📄 util_sock.c
字号:
/* Set initial timeout */ timeout.tv_sec = (time_t)(time_out / 1000); timeout.tv_usec = (long)(1000 * (time_out % 1000)); for (nread=0; nread < mincnt; ) { FD_ZERO(&fds); FD_SET(fd,&fds); selrtn = sys_select_intr(fd+1,&fds,NULL,NULL,&timeout); /* Check if error */ if (selrtn == -1) { /* something is wrong. Maybe the socket is dead? */ if (fd == client_fd) { /* Try and give an error message saying what client failed. */ DEBUG(0,("read_socket_with_timeout: timeout read for client %s. select error = %s.\n", client_ip_string, strerror(errno) )); } else { DEBUG(0,("read_socket_with_timeout: timeout read. select error = %s.\n", strerror(errno) )); } smb_read_error = READ_ERROR; return -1; } /* Did we timeout ? */ if (selrtn == 0) { DEBUG(10,("read_socket_with_timeout: timeout read. select timed out.\n")); smb_read_error = READ_TIMEOUT; return -1; } readret = sys_read(fd, buf+nread, maxcnt-nread); if (readret == 0) { /* we got EOF on the file descriptor */ DEBUG(5,("read_socket_with_timeout: timeout read. EOF from client.\n")); smb_read_error = READ_EOF; return -1; } if (readret == -1) { /* the descriptor is probably dead */ if (fd == client_fd) { /* Try and give an error message saying what client failed. */ DEBUG(0,("read_socket_with_timeout: timeout read to client %s. read error = %s.\n", client_ip_string, strerror(errno) )); } else { DEBUG(0,("read_socket_with_timeout: timeout read. read error = %s.\n", strerror(errno) )); } smb_read_error = READ_ERROR; return -1; } nread += readret; } /* Return the number we got */ return (ssize_t)nread;}/**************************************************************************** Read data from the client, reading exactly N bytes. ****************************************************************************/ssize_t read_data(int fd,char *buffer,size_t N){ ssize_t ret; size_t total=0; smb_read_error = 0; while (total < N) { ret = sys_read(fd,buffer + total,N - total); if (ret == 0) { DEBUG(10,("read_data: read of %d returned 0. Error = %s\n", (int)(N - total), strerror(errno) )); smb_read_error = READ_EOF; return 0; } if (ret == -1) { if (fd == client_fd) { /* Try and give an error message saying what client failed. */ DEBUG(0,("read_data: read failure for %d bytes to client %s. Error = %s\n", (int)(N - total), client_ip_string, strerror(errno) )); } else { DEBUG(0,("read_data: read failure for %d. Error = %s\n", (int)(N - total), strerror(errno) )); } smb_read_error = READ_ERROR; return -1; } total += ret; } return (ssize_t)total;}/**************************************************************************** Write data to a fd.****************************************************************************/ssize_t write_data(int fd, const char *buffer, size_t N){ size_t total=0; ssize_t ret; while (total < N) { ret = sys_write(fd,buffer + total,N - total); if (ret == -1) { if (fd == client_fd) { /* Try and give an error message saying what client failed. */ DEBUG(0,("write_data: write failure in writing to client %s. Error %s\n", client_ip_string, strerror(errno) )); } else { DEBUG(0,("write_data: write failure. Error = %s\n", strerror(errno) )); } return -1; } if (ret == 0) { return total; } total += ret; } return (ssize_t)total;}/**************************************************************************** Send a keepalive packet (rfc1002).****************************************************************************/BOOL send_keepalive(int client){ unsigned char buf[4]; buf[0] = SMBkeepalive; buf[1] = buf[2] = buf[3] = 0; return(write_data(client,(char *)buf,4) == 4);}/**************************************************************************** Read 4 bytes of a smb packet and return the smb length of the packet. Store the result in the buffer. This version of the function will return a length of zero on receiving a keepalive packet. Timeout is in milliseconds.****************************************************************************/static ssize_t read_smb_length_return_keepalive(int fd, char *inbuf, unsigned int timeout){ ssize_t len=0; int msg_type; BOOL ok = False; while (!ok) { if (timeout > 0) ok = (read_socket_with_timeout(fd,inbuf,4,4,timeout) == 4); else ok = (read_data(fd,inbuf,4) == 4); if (!ok) return(-1); len = smb_len(inbuf); msg_type = CVAL(inbuf,0); if (msg_type == SMBkeepalive) DEBUG(5,("Got keepalive packet\n")); } DEBUG(10,("got smb length of %lu\n",(unsigned long)len)); return(len);}/**************************************************************************** Read 4 bytes of a smb packet and return the smb length of the packet. Store the result in the buffer. This version of the function will never return a session keepalive (length of zero). Timeout is in milliseconds.****************************************************************************/ssize_t read_smb_length(int fd, char *inbuf, unsigned int timeout){ ssize_t len; for(;;) { len = read_smb_length_return_keepalive(fd, inbuf, timeout); if(len < 0) return len; /* Ignore session keepalives. */ if(CVAL(inbuf,0) != SMBkeepalive) break; } DEBUG(10,("read_smb_length: got smb length of %lu\n", (unsigned long)len)); return len;}/**************************************************************************** Read an smb from a fd. Note that the buffer *MUST* be of size BUFFER_SIZE+SAFETY_MARGIN. The timeout is in milliseconds. This function will return on receipt of a session keepalive packet. Doesn't check the MAC on signed packets.****************************************************************************/BOOL receive_smb_raw(int fd, char *buffer, unsigned int timeout){ ssize_t len,ret; smb_read_error = 0; memset(buffer,'\0',smb_size + 100); len = read_smb_length_return_keepalive(fd,buffer,timeout); if (len < 0) { DEBUG(10,("receive_smb_raw: length < 0!\n")); /* * Correct fix. smb_read_error may have already been * set. Only set it here if not already set. Global * variables still suck :-). JRA. */ if (smb_read_error == 0) smb_read_error = READ_ERROR; return False; } /* * A WRITEX with CAP_LARGE_WRITEX can be 64k worth of data plus 65 bytes * of header. Don't print the error if this fits.... JRA. */ if (len > (BUFFER_SIZE + LARGE_WRITEX_HDR_SIZE)) { DEBUG(0,("Invalid packet length! (%lu bytes).\n",(unsigned long)len)); if (len > BUFFER_SIZE + (SAFETY_MARGIN/2)) { /* * Correct fix. smb_read_error may have already been * set. Only set it here if not already set. Global * variables still suck :-). JRA. */ if (smb_read_error == 0) smb_read_error = READ_ERROR; return False; } } if(len > 0) { if (timeout > 0) { ret = read_socket_with_timeout(fd,buffer+4,len,len,timeout); } else { ret = read_data(fd,buffer+4,len); } if (ret != len) { if (smb_read_error == 0) smb_read_error = READ_ERROR; return False; } /* not all of samba3 properly checks for packet-termination of strings. This ensures that we don't run off into empty space. */ SSVAL(buffer+4,len, 0); } return True;}/**************************************************************************** Wrapper for receive_smb_raw(). Checks the MAC on signed packets.****************************************************************************/BOOL receive_smb(int fd, char *buffer, unsigned int timeout){ if (!receive_smb_raw(fd, buffer, timeout)) { return False; } /* Check the incoming SMB signature. */ if (!srv_check_sign_mac(buffer, True)) { DEBUG(0, ("receive_smb: SMB Signature verification failed on incoming packet!\n")); if (smb_read_error == 0) smb_read_error = READ_BAD_SIG; return False; }; return(True);}/**************************************************************************** Send an smb to a fd.****************************************************************************/BOOL send_smb(int fd, char *buffer){ size_t len; size_t nwritten=0; ssize_t ret; /* Sign the outgoing packet if required. */ srv_calculate_sign_mac(buffer); len = smb_len(buffer) + 4; while (nwritten < len) { ret = write_data(fd,buffer+nwritten,len - nwritten); if (ret <= 0) { DEBUG(0,("Error writing %d bytes to client. %d. (%s)\n", (int)len,(int)ret, strerror(errno) )); return False; } nwritten += ret; } return True;}/**************************************************************************** Open a socket of the specified type, port, and address for incoming data.****************************************************************************/int open_socket_in( int type, int port, int dlevel, uint32 socket_addr, BOOL rebind ){ struct sockaddr_in sock; int res; memset( (char *)&sock, '\0', sizeof(sock) );#ifdef HAVE_SOCK_SIN_LEN sock.sin_len = sizeof(sock);#endif sock.sin_port = htons( port ); sock.sin_family = AF_INET; sock.sin_addr.s_addr = socket_addr; res = socket( AF_INET, type, 0 ); if( res == -1 ) { if( DEBUGLVL(0) ) { dbgtext( "open_socket_in(): socket() call failed: " ); dbgtext( "%s\n", strerror( errno ) ); } return -1; } /* This block sets/clears the SO_REUSEADDR and possibly SO_REUSEPORT. */ { int val = rebind ? 1 : 0; if( setsockopt(res,SOL_SOCKET,SO_REUSEADDR,(char *)&val,sizeof(val)) == -1 ) { if( DEBUGLVL( dlevel ) ) { dbgtext( "open_socket_in(): setsockopt: " ); dbgtext( "SO_REUSEADDR = %s ", val?"True":"False" ); dbgtext( "on port %d failed ", port ); dbgtext( "with error = %s\n", strerror(errno) ); } }#ifdef SO_REUSEPORT if( setsockopt(res,SOL_SOCKET,SO_REUSEPORT,(char *)&val,sizeof(val)) == -1 ) { if( DEBUGLVL( dlevel ) ) { dbgtext( "open_socket_in(): setsockopt: "); dbgtext( "SO_REUSEPORT = %s ", val?"True":"False" ); dbgtext( "on port %d failed ", port ); dbgtext( "with error = %s\n", strerror(errno) ); } }#endif /* SO_REUSEPORT */ } /* now we've got a socket - we need to bind it */ if( bind( res, (struct sockaddr *)&sock, sizeof(sock) ) == -1 ) { if( DEBUGLVL(dlevel) && (port == SMB_PORT1 || port == SMB_PORT2 || port == NMB_PORT) ) { dbgtext( "bind failed on port %d ", port ); dbgtext( "socket_addr = %s.\n", inet_ntoa( sock.sin_addr ) ); dbgtext( "Error = %s\n", strerror(errno) ); } close( res ); return( -1 ); } DEBUG( 10, ( "bind succeeded on port %d\n", port ) ); return( res ); }/**************************************************************************** Create an outgoing socket. timeout is in milliseconds.**************************************************************************/int open_socket_out(int type, struct in_addr *addr, int port ,int timeout){ struct sockaddr_in sock_out; int res,ret; int connect_loop = 10; int increment = 10; /* create a socket to write to */ res = socket(PF_INET, type, 0); if (res == -1) { DEBUG(0,("socket error (%s)\n", strerror(errno))); return -1; } if (type != SOCK_STREAM) return(res); memset((char *)&sock_out,'\0',sizeof(sock_out)); putip((char *)&sock_out.sin_addr,(char *)addr); sock_out.sin_port = htons( port ); sock_out.sin_family = PF_INET; /* set it non-blocking */ set_blocking(res,False); DEBUG(3,("Connecting to %s at port %d\n",inet_ntoa(*addr),port)); /* and connect it to the destination */ connect_again: ret = connect(res,(struct sockaddr *)&sock_out,sizeof(sock_out)); /* Some systems return EAGAIN when they mean EINPROGRESS */ if (ret < 0 && (errno == EINPROGRESS || errno == EALREADY || errno == EAGAIN) && (connect_loop < timeout) ) { smb_msleep(connect_loop); timeout -= connect_loop; connect_loop += increment; if (increment < 250) { /* After 8 rounds we end up at a max of 255 msec */ increment *= 1.5; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -