Index: memcached.c =================================================================== --- memcached.c (revision 608) +++ memcached.c (working copy) @@ -64,7 +64,7 @@ */ static void drive_machine(conn *c); static int new_socket(const bool is_udp); -static int server_socket(const int port, const bool is_udp); +static int server_socket(struct in_addr interf, const int port, const bool is_udp); static int try_read_command(conn *c); static int try_read_network(conn *c); static int try_read_udp(conn *c); @@ -105,7 +105,8 @@ static item **todelete = NULL; static int delcurr; static int deltotal; -static conn *listen_conn; +static conn *listen_conn[MAX_LISTEN_CONNS+1]; /* one for unix socket*/ +static int listen_conn_num=0; static struct event_base *main_base; #define TRANSMIT_COMPLETE 0 @@ -166,7 +167,7 @@ static void settings_init(void) { settings.port = 11211; settings.udpport = 0; - settings.interf.s_addr = htonl(INADDR_ANY); + settings.interf_num = 0; settings.maxbytes = 64 * 1024 * 1024; /* default is 64MB */ settings.maxconns = 1024; /* to limit connections-related memory to about 5MB */ settings.verbose = 0; @@ -183,6 +184,7 @@ #endif settings.prefix_delimiter = ':'; settings.detail_enabled = 0; + settings.network_disabled = false; } /* returns true if a deleted item's delete-locked-time is over, and it @@ -916,16 +918,16 @@ char *pos = temp; info = mallinfo(); - pos += sprintf(pos, "STAT arena_size %d\r\n", info.arena); - pos += sprintf(pos, "STAT free_chunks %d\r\n", info.ordblks); - pos += sprintf(pos, "STAT fastbin_blocks %d\r\n", info.smblks); - pos += sprintf(pos, "STAT mmapped_regions %d\r\n", info.hblks); - pos += sprintf(pos, "STAT mmapped_space %d\r\n", info.hblkhd); - pos += sprintf(pos, "STAT max_total_alloc %d\r\n", info.usmblks); - pos += sprintf(pos, "STAT fastbin_space %d\r\n", info.fsmblks); - pos += sprintf(pos, "STAT total_alloc %d\r\n", info.uordblks); - pos += sprintf(pos, "STAT total_free %d\r\n", info.fordblks); - pos += sprintf(pos, "STAT releasable_space %d\r\nEND", info.keepcost); + pos += sprintf(pos, "STAT arena_size %lu\r\n", info.arena); + pos += sprintf(pos, "STAT free_chunks %lu\r\n", info.ordblks); + pos += sprintf(pos, "STAT fastbin_blocks %lu\r\n", info.smblks); + pos += sprintf(pos, "STAT mmapped_regions %lu\r\n", info.hblks); + pos += sprintf(pos, "STAT mmapped_space %lu\r\n", info.hblkhd); + pos += sprintf(pos, "STAT max_total_alloc %lu\r\n", info.usmblks); + pos += sprintf(pos, "STAT fastbin_space %lu\r\n", info.fsmblks); + pos += sprintf(pos, "STAT total_alloc %lu\r\n", info.uordblks); + pos += sprintf(pos, "STAT total_free %lu\r\n", info.fordblks); + pos += sprintf(pos, "STAT releasable_space %lu\r\nEND", info.keepcost); out_string(c, temp); return; } @@ -1731,20 +1733,15 @@ * Sets whether we are listening for new connections or not. */ void accept_new_conns(const bool do_accept) { + int i; if (! is_listen_thread()) return; - if (do_accept) { - update_event(listen_conn, EV_READ | EV_PERSIST); - if (listen(listen_conn->sfd, 1024) != 0) { - perror("listen"); - } + for (i=0; isfd, (do_accept) ? 1024 : 0 ) != 0) { + perror("listen"); + } } - else { - update_event(listen_conn, 0); - if (listen(listen_conn->sfd, 0) != 0) { - perror("listen"); - } - } } @@ -2105,7 +2102,7 @@ } -static int server_socket(const int port, const bool is_udp) { +static int server_socket(struct in_addr interf, const int port, const bool is_udp) { int sfd; struct linger ling = {0, 0}; struct sockaddr_in addr; @@ -2132,7 +2129,7 @@ addr.sin_family = AF_INET; addr.sin_port = htons(port); - addr.sin_addr = settings.interf; + addr.sin_addr = interf; if (bind(sfd, (struct sockaddr *)&addr, sizeof(addr)) == -1) { perror("bind()"); close(sfd); @@ -2213,7 +2210,8 @@ } /* listening socket */ -static int l_socket = 0; +static int l_socket[MAX_LISTEN_CONNS+1]; /* one for unix socket */ +static int l_socket_num=0; /* udp socket */ static int u_socket = -1; @@ -2221,7 +2219,9 @@ /* invoke right before gdb is called, on assert */ void pre_gdb(void) { int i; - if (l_socket > -1) close(l_socket); + for (i=0;i -1) close(l_socket[i]); + } if (u_socket > -1) close(u_socket); for (i = 3; i <= 500; i++) close(i); /* so lame */ kill(getpid(), SIGABRT); @@ -2304,7 +2304,7 @@ printf(PACKAGE " " VERSION "\n"); printf("-p TCP port number to listen on (default: 11211)\n" "-U UDP port number to listen on (default: 0, off)\n" - "-s unix socket path to listen on (disables network support)\n" + "-s unix socket path to listen on\n" "-l interface to listen on, default is INDRR_ANY\n" "-d run as a daemon\n" "-r maximize core file limit\n" @@ -2320,7 +2320,8 @@ "-b run a managed instanced (mnemonic: buckets)\n" "-P save PID in , only used with -d option\n" "-f chunk size growth factor, default 1.25\n" - "-n minimum space allocated for key+value+flags, default 48\n"); + "-n minimum space allocated for key+value+flags, default 48\n" + "-N disable network support\n"); #ifdef USE_THREADS printf("-t number of threads to use, default 4\n"); #endif @@ -2432,7 +2433,7 @@ } int main (int argc, char **argv) { - int c; + int c,i; struct in_addr addr; bool lock_memory = false; bool daemonize = false; @@ -2453,7 +2454,7 @@ setbuf(stderr, NULL); /* process arguments */ - while ((c = getopt(argc, argv, "bp:s:U:m:Mc:khirvdl:u:P:f:s:n:t:D:")) != -1) { + while ((c = getopt(argc, argv, "bp:s:U:m:Mc:khirvdl:u:P:f:s:n:t:D:N")) != -1) { switch (c) { case 'U': settings.udpport = atoi(optarg); @@ -2489,12 +2490,23 @@ settings.verbose++; break; case 'l': - if (inet_pton(AF_INET, optarg, &addr) <= 0) { - fprintf(stderr, "Illegal address: %s\n", optarg); - return 1; - } else { - settings.interf = addr; - } + { + char *port_cp = strchr(optarg,PORT_DELIMITER); + if (settings.interf_num==MAX_LISTEN_CONNS) { + fprintf(stderr, "Maximum number of listen socket reached\n"); + return 1; + } + if (port_cp) { /* cut ip on delimiter and move to port */ + *(port_cp++)=0; + } + if (inet_pton(AF_INET, optarg, &addr) <= 0) { + fprintf(stderr, "Illegal address: %s\n", optarg); + return 1; + } else { + settings.ports[settings.interf_num] = (port_cp) ? atoi(port_cp) : 0; + settings.interf[settings.interf_num++] = addr; + } + } break; case 'd': daemonize = true; @@ -2537,12 +2549,19 @@ settings.prefix_delimiter = optarg[0]; settings.detail_enabled = 1; break; + case 'N': + settings.network_disabled = true; default: fprintf(stderr, "Illegal argument \"%c\"\n", c); return 1; } } + if (settings.network_disabled && NULL==settings.socketpath) { + fprintf(stderr,"both unix socket and network disabled - memcache not operational - use -s or don't use -N option"); + return 1; + } + if (maxcore != 0) { struct rlimit rlim_new; /* @@ -2597,21 +2616,30 @@ */ /* create the listening socket and bind it */ - if (settings.socketpath == NULL) { - l_socket = server_socket(settings.port, 0); - if (l_socket == -1) { - fprintf(stderr, "failed to listen\n"); - exit(EXIT_FAILURE); - } - } + if (!settings.network_disabled) { + struct in_addr any_interf; + any_interf.s_addr = htonl(INADDR_ANY); + if (settings.interf_num==0) { /*if no interfaces defined listen on INADDR_ANY*/ + settings.ports[settings.interf_num]=0; + settings.interf[settings.interf_num++] = any_interf; + } + for (i=0;i 0 && settings.socketpath == NULL) { - /* create the UDP listening socket and bind it */ - u_socket = server_socket(settings.udpport, 1); - if (u_socket == -1) { - fprintf(stderr, "failed to listen on UDP port %d\n", settings.udpport); - exit(EXIT_FAILURE); - } + if (settings.udpport > 0) { + /* create the UDP listening socket and bind it */ + u_socket = server_socket(any_interf,settings.udpport, 1); + if (u_socket == -1) { + fprintf(stderr, "failed to listen on UDP port %d\n", settings.udpport); + exit(EXIT_FAILURE); + } + } } /* lose root privileges if we have them */ @@ -2632,9 +2660,8 @@ /* create unix mode sockets after dropping privileges */ if (settings.socketpath != NULL) { - l_socket = server_socket_unix(settings.socketpath); - if (l_socket == -1) { - fprintf(stderr, "failed to listen\n"); + if ((l_socket[l_socket_num++] = server_socket_unix(settings.socketpath))==-1) { + fprintf(stderr, "failed to listen on %s\n",settings.socketpath); exit(EXIT_FAILURE); } } @@ -2692,10 +2719,12 @@ exit(EXIT_FAILURE); } /* create the initial listening connection */ - if (!(listen_conn = conn_new(l_socket, conn_listening, - EV_READ | EV_PERSIST, 1, false, main_base))) { - fprintf(stderr, "failed to create listening connection"); - exit(EXIT_FAILURE); + for (i=0; i #include +#define MAX_LISTEN_CONNS 10 +#define PORT_DELIMITER ':' #define DATA_BUFFER_SIZE 2048 #define UDP_READ_BUFFER_SIZE 65536 #define UDP_MAX_PAYLOAD_SIZE 1400 @@ -77,7 +79,9 @@ int maxconns; int port; int udpport; - struct in_addr interf; + struct in_addr interf[MAX_LISTEN_CONNS]; + int ports[MAX_LISTEN_CONNS]; + int interf_num; int verbose; rel_time_t oldest_live; /* ignore existing items older than this */ bool managed; /* if 1, a tracker manages virtual buckets */ @@ -88,6 +92,7 @@ int num_threads; /* number of libevent threads to run */ char prefix_delimiter; /* character that marks a key prefix (for stats) */ int detail_enabled; /* nonzero if we're collecting detailed stats */ + bool network_disabled; /* if true network support is disabled (usefull with unix sockets) */ }; extern struct stats stats; Index: doc/memcached.1 =================================================================== --- doc/memcached.1 (revision 608) +++ doc/memcached.1 (working copy) @@ -23,10 +23,12 @@ .B \-s Unix socket path to listen on (disables network support). .TP -.B \-l +.B \-l Listen on ; default to INDRR_ANY. This is an important option to consider as there is no other way to secure the installation. Binding to an internal or firewalled network interface is suggested. +You can add multiple -l options to commandline if you wish to listen on multiple interfaces. +If port number ommited, default or given with -p option will be used. .TP .B \-d Run memcached as a daemon. @@ -102,6 +104,10 @@ per-prefix stats reporting. The default is ":" (colon). If this option is specified, stats collection is turned on automatically; if not, then it may be turned on by sending the "stats detail on" command to the server. +.TP +.B \-N +Disable network support. Memcache won't listen on any network inferface for +incomming connections. .br .SH LICENSE The memcached daemon is copyright Danga Interactive and is distributed under Index: TODO =================================================================== --- TODO (revision 608) +++ TODO (working copy) @@ -25,5 +25,3 @@ out other objects with infinite expirations. * curr_items never decreases? mailing list report. - -* memcached to listen on more than one IP. mailing list request.