📄 util_sock.c
字号:
/* Unix SMB/CIFS implementation. Samba utility functions Copyright (C) Andrew Tridgell 1992-1998 Copyright (C) Tim Potter 2000-2001 Copyright (C) Jeremy Allison 1992-2005 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.*/#include "includes.h"/* the following 3 client_*() functions are nasty ways of allowing some generic functions to get info that really should be hidden in particular modules */static int client_fd = -1;/* What to print out on a client disconnect error. */static char client_ip_string[16];void client_setfd(int fd){ client_fd = fd; safe_strcpy(client_ip_string, get_peer_addr(client_fd), sizeof(client_ip_string)-1);}static char *get_socket_addr(int fd){ struct sockaddr sa; struct sockaddr_in *sockin = (struct sockaddr_in *) (&sa); socklen_t length = sizeof(sa); static fstring addr_buf; fstrcpy(addr_buf,"0.0.0.0"); if (fd == -1) { return addr_buf; } if (getsockname(fd, &sa, &length) < 0) { DEBUG(0,("getsockname failed. Error was %s\n", strerror(errno) )); return addr_buf; } fstrcpy(addr_buf,(char *)inet_ntoa(sockin->sin_addr)); return addr_buf;}static int get_socket_port(int fd){ struct sockaddr sa; struct sockaddr_in *sockin = (struct sockaddr_in *) (&sa); socklen_t length = sizeof(sa); if (fd == -1) return -1; if (getsockname(fd, &sa, &length) < 0) { DEBUG(0,("getpeername failed. Error was %s\n", strerror(errno) )); return -1; } return ntohs(sockin->sin_port);}char *client_name(void){ return get_peer_name(client_fd,False);}char *client_addr(void){ return get_peer_addr(client_fd);}char *client_socket_addr(void){ return get_socket_addr(client_fd);}int client_socket_port(void){ return get_socket_port(client_fd);}struct in_addr *client_inaddr(struct sockaddr *sa){ struct sockaddr_in *sockin = (struct sockaddr_in *) (sa); socklen_t length = sizeof(*sa); if (getpeername(client_fd, sa, &length) < 0) { DEBUG(0,("getpeername failed. Error was %s\n", strerror(errno) )); return NULL; } return &sockin->sin_addr;}/* the last IP received from */struct in_addr lastip;/* the last port received from */int lastport=0;int smb_read_error = 0;/**************************************************************************** Determine if a file descriptor is in fact a socket.****************************************************************************/BOOL is_a_socket(int fd){ int v; socklen_t l; l = sizeof(int); return(getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&v, &l) == 0);}enum SOCK_OPT_TYPES {OPT_BOOL,OPT_INT,OPT_ON};typedef struct smb_socket_option { const char *name; int level; int option; int value; int opttype;} smb_socket_option;static const smb_socket_option socket_options[] = { {"SO_KEEPALIVE", SOL_SOCKET, SO_KEEPALIVE, 0, OPT_BOOL}, {"SO_REUSEADDR", SOL_SOCKET, SO_REUSEADDR, 0, OPT_BOOL}, {"SO_BROADCAST", SOL_SOCKET, SO_BROADCAST, 0, OPT_BOOL},#ifdef TCP_NODELAY {"TCP_NODELAY", IPPROTO_TCP, TCP_NODELAY, 0, OPT_BOOL},#endif#ifdef TCP_KEEPCNT {"TCP_KEEPCNT", IPPROTO_TCP, TCP_KEEPCNT, 0, OPT_INT},#endif#ifdef TCP_KEEPIDLE {"TCP_KEEPIDLE", IPPROTO_TCP, TCP_KEEPIDLE, 0, OPT_INT},#endif#ifdef TCP_KEEPINTVL {"TCP_KEEPINTVL", IPPROTO_TCP, TCP_KEEPINTVL, 0, OPT_INT},#endif#ifdef IPTOS_LOWDELAY {"IPTOS_LOWDELAY", IPPROTO_IP, IP_TOS, IPTOS_LOWDELAY, OPT_ON},#endif#ifdef IPTOS_THROUGHPUT {"IPTOS_THROUGHPUT", IPPROTO_IP, IP_TOS, IPTOS_THROUGHPUT, OPT_ON},#endif#ifdef SO_REUSEPORT {"SO_REUSEPORT", SOL_SOCKET, SO_REUSEPORT, 0, OPT_BOOL},#endif#ifdef SO_SNDBUF {"SO_SNDBUF", SOL_SOCKET, SO_SNDBUF, 0, OPT_INT},#endif#ifdef SO_RCVBUF {"SO_RCVBUF", SOL_SOCKET, SO_RCVBUF, 0, OPT_INT},#endif#ifdef SO_SNDLOWAT {"SO_SNDLOWAT", SOL_SOCKET, SO_SNDLOWAT, 0, OPT_INT},#endif#ifdef SO_RCVLOWAT {"SO_RCVLOWAT", SOL_SOCKET, SO_RCVLOWAT, 0, OPT_INT},#endif#ifdef SO_SNDTIMEO {"SO_SNDTIMEO", SOL_SOCKET, SO_SNDTIMEO, 0, OPT_INT},#endif#ifdef SO_RCVTIMEO {"SO_RCVTIMEO", SOL_SOCKET, SO_RCVTIMEO, 0, OPT_INT},#endif#ifdef TCP_FASTACK {"TCP_FASTACK", IPPROTO_TCP, TCP_FASTACK, 0, OPT_INT},#endif {NULL,0,0,0,0}};/**************************************************************************** Print socket options.****************************************************************************/static void print_socket_options(int s){ int value; socklen_t vlen = 4; const smb_socket_option *p = &socket_options[0]; /* wrapped in if statement to prevent streams leak in SCO Openserver 5.0 */ /* reported on samba-technical --jerry */ if ( DEBUGLEVEL >= 5 ) { for (; p->name != NULL; p++) { if (getsockopt(s, p->level, p->option, (void *)&value, &vlen) == -1) { DEBUG(5,("Could not test socket option %s.\n", p->name)); } else { DEBUG(5,("socket option %s = %d\n",p->name,value)); } } } }/**************************************************************************** Set user socket options.****************************************************************************/void set_socket_options(int fd, const char *options){ fstring tok; while (next_token(&options,tok," \t,", sizeof(tok))) { int ret=0,i; int value = 1; char *p; BOOL got_value = False; if ((p = strchr_m(tok,'='))) { *p = 0; value = atoi(p+1); got_value = True; } for (i=0;socket_options[i].name;i++) if (strequal(socket_options[i].name,tok)) break; if (!socket_options[i].name) { DEBUG(0,("Unknown socket option %s\n",tok)); continue; } switch (socket_options[i].opttype) { case OPT_BOOL: case OPT_INT: ret = setsockopt(fd,socket_options[i].level, socket_options[i].option,(char *)&value,sizeof(int)); break; case OPT_ON: if (got_value) DEBUG(0,("syntax error - %s does not take a value\n",tok)); { int on = socket_options[i].value; ret = setsockopt(fd,socket_options[i].level, socket_options[i].option,(char *)&on,sizeof(int)); } break; } if (ret != 0) DEBUG(0,("Failed to set socket option %s (Error %s)\n",tok, strerror(errno) )); } print_socket_options(fd);}/**************************************************************************** Read from a socket.****************************************************************************/ssize_t read_udp_socket(int fd,char *buf,size_t len){ ssize_t ret; struct sockaddr_in sock; socklen_t socklen = sizeof(sock); memset((char *)&sock,'\0',socklen); memset((char *)&lastip,'\0',sizeof(lastip)); ret = (ssize_t)sys_recvfrom(fd,buf,len,0,(struct sockaddr *)&sock,&socklen); if (ret <= 0) { DEBUG(2,("read socket failed. ERRNO=%s\n",strerror(errno))); return(0); } lastip = sock.sin_addr; lastport = ntohs(sock.sin_port); DEBUG(10,("read_udp_socket: lastip %s lastport %d read: %lu\n", inet_ntoa(lastip), lastport, (unsigned long)ret)); return(ret);}#if 0Socket routines from HEAD - maybe re-enable in future. JRA./**************************************************************************** Work out if we've timed out.****************************************************************************/static BOOL timeout_until(struct timeval *timeout, const struct timeval *endtime){ struct timeval now; SMB_BIG_INT t_dif; GetTimeOfDay(&now); t_dif = usec_time_diff(endtime, &now); if (t_dif <= 0) { return False; } timeout->tv_sec = (t_dif / (SMB_BIG_INT)1000000); timeout->tv_usec = (t_dif % (SMB_BIG_INT)1000000); return True;}/**************************************************************************** Read data from the client, reading exactly N bytes, or until endtime timeout. Use with a non-blocking socket if endtime != NULL.****************************************************************************/ssize_t read_data_until(int fd,char *buffer,size_t N, const struct timeval *endtime){ ssize_t ret; size_t total=0; smb_read_error = 0; while (total < N) { if (endtime != NULL) { fd_set r_fds; struct timeval timeout; int selrtn; if (!timeout_until(&timeout, endtime)) { DEBUG(10,("read_data_until: read timed out\n")); smb_read_error = READ_TIMEOUT; return -1; } FD_ZERO(&r_fds); FD_SET(fd, &r_fds); /* Select but ignore EINTR. */ selrtn = sys_select_intr(fd+1, &r_fds, NULL, NULL, &timeout); if (selrtn == -1) { /* something is wrong. Maybe the socket is dead? */ DEBUG(0,("read_data_until: select error = %s.\n", strerror(errno) )); smb_read_error = READ_ERROR; return -1; } /* Did we timeout ? */ if (selrtn == 0) { DEBUG(10,("read_data_until: select timed out.\n")); smb_read_error = READ_TIMEOUT; return -1; } } ret = sys_read(fd,buffer + total,N - total); if (ret == 0) { DEBUG(10,("read_data_until: read of %d returned 0. Error = %s\n", (int)(N - total), strerror(errno) )); smb_read_error = READ_EOF; return 0; } if (ret == -1) { if (errno == EAGAIN) { /* Non-blocking socket with no data available. Try select again. */ continue; } DEBUG(0,("read_data_until: 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;}#endif/**************************************************************************** Read data from a socket with a timout in msec. mincount = if timeout, minimum to read before returning maxcount = number to be read. time_out = timeout in milliseconds****************************************************************************/ssize_t read_socket_with_timeout(int fd,char *buf,size_t mincnt,size_t maxcnt,unsigned int time_out){ fd_set fds; int selrtn; ssize_t readret; size_t nread = 0; struct timeval timeout; /* just checking .... */ if (maxcnt <= 0) return(0); smb_read_error = 0; /* Blocking read */ if (time_out == 0) { if (mincnt == 0) { mincnt = maxcnt; } while (nread < mincnt) { readret = sys_read(fd, buf + nread, maxcnt - nread); if (readret == 0) { DEBUG(5,("read_socket_with_timeout: blocking read. EOF from client.\n")); smb_read_error = READ_EOF; return -1; } if (readret == -1) { if (fd == client_fd) { /* Try and give an error message saying what client failed. */ DEBUG(0,("read_socket_with_timeout: client %s read error = %s.\n", client_ip_string, strerror(errno) )); } else { DEBUG(0,("read_socket_with_timeout: read error = %s.\n", strerror(errno) )); } smb_read_error = READ_ERROR; return -1; } nread += readret; } return((ssize_t)nread); } /* Most difficult - timeout read */ /* If this is ever called on a disk file and mincnt is greater then the filesize then system performance will suffer severely as select always returns true on disk files */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -