From eea783e04cca45b1d3d9e5bb10556a2c8dc79b86 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Mon, 2 May 2011 16:23:40 +1000 Subject: lib/util Move set_socket_options() into common code. --- lib/util/util_net.c | 161 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 161 insertions(+) (limited to 'lib/util/util_net.c') diff --git a/lib/util/util_net.c b/lib/util/util_net.c index e80447128f..a8a05da138 100644 --- a/lib/util/util_net.c +++ b/lib/util/util_net.c @@ -695,3 +695,164 @@ const char *client_socket_addr(int fd, char *addr, size_t addr_len) { return get_socket_addr(fd, addr, addr_len); } + + +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 +#ifdef TCP_QUICKACK + {"TCP_QUICKACK", IPPROTO_TCP, TCP_QUICKACK, 0, OPT_BOOL}, +#endif +#ifdef TCP_KEEPALIVE_THRESHOLD + {"TCP_KEEPALIVE_THRESHOLD", IPPROTO_TCP, TCP_KEEPALIVE_THRESHOLD, 0, OPT_INT}, +#endif +#ifdef TCP_KEEPALIVE_ABORT_THRESHOLD + {"TCP_KEEPALIVE_ABORT_THRESHOLD", IPPROTO_TCP, TCP_KEEPALIVE_ABORT_THRESHOLD, 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 ) { + DEBUG(5,("Socket options:\n")); + for (; p->name != NULL; p++) { + if (getsockopt(s, p->level, p->option, + (void *)&value, &vlen) == -1) { + DEBUGADD(5,("\tCould not test socket option %s.\n", + p->name)); + } else { + DEBUGADD(5,("\t%s = %d\n", + p->name,value)); + } + } + } + } + +/**************************************************************************** + Set user socket options. +****************************************************************************/ + +void set_socket_options(int fd, const char *options) +{ + TALLOC_CTX *ctx = talloc_new(NULL); + char *tok; + + while (next_token_talloc(ctx, &options, &tok," \t,")) { + 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) { + /* be aware that some systems like Solaris return + * EINVAL to a setsockopt() call when the client + * sent a RST previously - no need to worry */ + DEBUG(2,("Failed to set socket option %s (Error %s)\n", + tok, strerror(errno) )); + } + } + + TALLOC_FREE(ctx); + print_socket_options(fd); +} -- cgit