[MEDIUM] separate protocol-level accept() from the frontend's

For a long time we had two large accept() functions, one for TCP
sockets instanciating proxies, and another one for UNIX sockets
instanciating the stats interface.

A lot of code was duplicated and both did not work exactly the same way.

Now we have a stream_sock layer accept() called for either TCP or UNIX
sockets, and this function calls the frontend-specific accept() function
which does the rest of the frontend-specific initialisation.

Some code is still duplicated (session & task allocation, stream interface
initialization), and might benefit from having an intermediate session-level
accept() callback to perform such initializations. Still there are some
minor differences that need to be addressed first. For instance, the monitor
nets should only be checked for proxies and not for other connection templates.

Last, we renamed l->private as l->frontend. The "private" pointer in
the listener is only used to store a frontend, so let's rename it to
eliminate this ambiguity. When we later support detached listeners
(eg: FTP), we'll add another field to avoid the confusion.
diff --git a/src/proto_uxst.c b/src/proto_uxst.c
index 177c5a3..98c9555 100644
--- a/src/proto_uxst.c
+++ b/src/proto_uxst.c
@@ -1,7 +1,7 @@
 /*
  * UNIX SOCK_STREAM protocol layer (uxst)
  *
- * Copyright 2000-2009 Willy Tarreau <w@1wt.eu>
+ * Copyright 2000-2010 Willy Tarreau <w@1wt.eu>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -29,26 +29,17 @@
 #include <common/config.h>
 #include <common/debug.h>
 #include <common/errors.h>
-#include <common/memory.h>
 #include <common/mini-clist.h>
 #include <common/standard.h>
-#include <common/ticks.h>
 #include <common/time.h>
 #include <common/version.h>
 
 #include <types/global.h>
 
-#include <proto/acl.h>
-#include <proto/backend.h>
-#include <proto/buffers.h>
-#include <proto/dumpstats.h>
 #include <proto/fd.h>
 #include <proto/log.h>
 #include <proto/protocols.h>
 #include <proto/proto_uxst.h>
-#include <proto/queue.h>
-#include <proto/session.h>
-#include <proto/stream_interface.h>
 #include <proto/stream_sock.h>
 #include <proto/task.h>
 
@@ -68,6 +59,7 @@
 	.sock_family = AF_UNIX,
 	.sock_addrlen = sizeof(struct sockaddr_un),
 	.l3_addrlen = sizeof(((struct sockaddr_un*)0)->sun_path),/* path len */
+	.accept = &stream_sock_accept,
 	.read = &stream_sock_read,
 	.write = &stream_sock_write,
 	.bind_all = uxst_bind_listeners,
@@ -262,7 +254,7 @@
 
 	/* the function for the accept() event */
 	fd_insert(fd);
-	fdtab[fd].cb[DIR_RD].f = listener->accept;
+	fdtab[fd].cb[DIR_RD].f = listener->proto->accept;
 	fdtab[fd].cb[DIR_WR].f = NULL; /* never called */
 	fdtab[fd].cb[DIR_RD].b = fdtab[fd].cb[DIR_WR].b = NULL;
 	fdtab[fd].owner = listener; /* reference the listener instead of a task */
@@ -347,229 +339,6 @@
  * 4) high-level functions
  ********************************/
 
-
-/*
- * This function is called on a read event from a listen socket, corresponding
- * to an accept. It tries to accept as many connections as possible.
- * It returns 0. Since we use UNIX sockets on the local system for monitoring
- * purposes and other related things, we do not need to output as many messages
- * as with TCP which can fall under attack.
- */
-int uxst_event_accept(int fd) {
-	struct listener *l = fdtab[fd].owner;
-	struct session *s;
-	struct task *t;
-	int cfd;
-	int max_accept;
-
-	if (global.nbproc > 1)
-		max_accept = 8; /* let other processes catch some connections too */
-	else
-		max_accept = -1;
-
-	while (max_accept--) {
-		struct sockaddr_storage addr;
-		socklen_t laddr = sizeof(addr);
-
-		if ((cfd = accept(fd, (struct sockaddr *)&addr, &laddr)) == -1) {
-			switch (errno) {
-			case EAGAIN:
-			case EINTR:
-			case ECONNABORTED:
-				return 0;	    /* nothing more to accept */
-			case ENFILE:
-				/* Process reached system FD limit. Check system tunables. */
-				return 0;
-			case EMFILE:
-				/* Process reached process FD limit. Check 'ulimit-n'. */
-				return 0;
-			case ENOBUFS:
-			case ENOMEM:
-				/* Process reached system memory limit. Check system tunables. */
-				return 0;
-			default:
-				return 0;
-			}
-		}
-
-		if (l->nbconn >= l->maxconn || actconn >= global.maxconn) {
-			/* too many connections, we shoot this one and return.
-			 * FIXME: it would be better to simply switch the listener's
-			 * state to LI_FULL and disable the FD. We could re-enable
-			 * it upon fd_delete(), but this requires all protocols to
-			 * be switched.
-			 */
-			goto out_close;
-		}
-
-		if ((s = pool_alloc2(pool2_session)) == NULL) {
-			Alert("out of memory in uxst_event_accept().\n");
-			goto out_close;
-		}
-
-		LIST_ADDQ(&sessions, &s->list);
-		LIST_INIT(&s->back_refs);
-
-		s->flags = 0;
-		s->term_trace = 0;
-
-		if ((t = task_new()) == NULL) {
-			Alert("out of memory in uxst_event_accept().\n");
-			goto out_free_session;
-		}
-
-		s->cli_addr = addr;
-
-		/* FIXME: should be checked earlier */
-		if (cfd >= global.maxsock) {
-			Alert("accept(): not enough free sockets. Raise -n argument. Giving up.\n");
-			goto out_free_task;
-		}
-
-		if (fcntl(cfd, F_SETFL, O_NONBLOCK) == -1) {
-			Alert("accept(): cannot set the socket in non blocking mode. Giving up.\n");
-			goto out_free_task;
-		}
-
-		t->process = l->handler;
-		t->context = s;
-		t->nice = l->nice;
-
-		s->task = t;
-		s->listener = l;
-		s->fe = s->be = l->private;
-
-		s->req = s->rep = NULL; /* will be allocated later */
-
-		s->si[0].state = s->si[0].prev_state = SI_ST_EST;
-		s->si[0].err_type = SI_ET_NONE;
-		s->si[0].err_loc = NULL;
-		s->si[0].owner = t;
-		s->si[0].update = stream_sock_data_finish;
-		s->si[0].shutr = stream_sock_shutr;
-		s->si[0].shutw = stream_sock_shutw;
-		s->si[0].chk_rcv = stream_sock_chk_rcv;
-		s->si[0].chk_snd = stream_sock_chk_snd;
-		s->si[0].connect = NULL;
-		s->si[0].iohandler = NULL;
-		s->si[0].fd = cfd;
-		s->si[0].flags = SI_FL_NONE;
-		if (s->fe->options2 & PR_O2_INDEPSTR)
-			s->si[0].flags |= SI_FL_INDEP_STR;
-		s->si[0].exp = TICK_ETERNITY;
-
-		s->si[1].state = s->si[1].prev_state = SI_ST_INI;
-		s->si[1].err_type = SI_ET_NONE;
-		s->si[1].err_loc = NULL;
-		s->si[1].owner = t;
-		s->si[1].exp = TICK_ETERNITY;
-		s->si[1].fd = -1; /* just to help with debugging */
-		s->si[1].flags = SI_FL_NONE;
-		if (s->be->options2 & PR_O2_INDEPSTR)
-			s->si[1].flags |= SI_FL_INDEP_STR;
-
-		stream_int_register_handler(&s->si[1], stats_io_handler);
-		s->si[1].private = s;
-		s->si[1].st1 = 0;
-		s->si[1].st0 = STAT_CLI_INIT;
-
-		s->srv = s->prev_srv = s->srv_conn = NULL;
-		s->pend_pos = NULL;
-
-		s->store_count = 0;
-
-		memset(&s->logs, 0, sizeof(s->logs));
-		memset(&s->txn, 0, sizeof(s->txn));
-
-		s->logs.accept_date = date; /* user-visible date for logging */
-		s->logs.tv_accept = now;  /* corrected date for internal use */
-
-		s->data_state = DATA_ST_INIT;
-		s->data_source = DATA_SRC_NONE;
-		s->uniq_id = totalconn;
-		totalconn++;
-
-		if ((s->req = pool_alloc2(pool2_buffer)) == NULL)
-			goto out_free_task;
-
-		s->req->size = global.tune.bufsize;
-		buffer_init(s->req);
-		s->req->prod = &s->si[0];
-		s->req->cons = &s->si[1];
-		s->si[0].ib = s->si[1].ob = s->req;
-		s->req->flags |= BF_READ_ATTACHED; /* the producer is already connected */
-		s->req->flags |= BF_READ_DONTWAIT; /* we plan to read small requests */
-
-		s->req->analysers = l->analysers;
-
-		s->req->wto = TICK_ETERNITY;
-		s->req->cto = TICK_ETERNITY;
-		s->req->rto = TICK_ETERNITY;
-
-		if ((s->rep = pool_alloc2(pool2_buffer)) == NULL)
-			goto out_free_req;
-
-		s->rep->size = global.tune.bufsize;
-		buffer_init(s->rep);
-
-		s->rep->prod = &s->si[1];
-		s->rep->cons = &s->si[0];
-		s->si[0].ob = s->si[1].ib = s->rep;
-		s->rep->analysers = 0;
-
-		s->rep->rto = TICK_ETERNITY;
-		s->rep->cto = TICK_ETERNITY;
-		s->rep->wto = TICK_ETERNITY;
-
-		s->req->rex = TICK_ETERNITY;
-		s->req->wex = TICK_ETERNITY;
-		s->req->analyse_exp = TICK_ETERNITY;
-		s->rep->rex = TICK_ETERNITY;
-		s->rep->wex = TICK_ETERNITY;
-		s->rep->analyse_exp = TICK_ETERNITY;
-
-		t->expire = TICK_ETERNITY;
-
-		if (l->timeout) {
-			s->req->rto = *l->timeout;
-			s->rep->wto = *l->timeout;
-		}
-
-		fd_insert(cfd);
-		fdtab[cfd].owner = &s->si[0];
-		fdtab[cfd].state = FD_STREADY;
-		fdtab[cfd].cb[DIR_RD].f = l->proto->read;
-		fdtab[cfd].cb[DIR_RD].b = s->req;
-		fdtab[cfd].cb[DIR_WR].f = l->proto->write;
-		fdtab[cfd].cb[DIR_WR].b = s->rep;
-		fdinfo[cfd].peeraddr = (struct sockaddr *)&s->cli_addr;
-		fdinfo[cfd].peerlen = sizeof(s->cli_addr);
-
-		EV_FD_SET(cfd, DIR_RD);
-
-		task_wakeup(t, TASK_WOKEN_INIT);
-
-		l->nbconn++; /* warning! right now, it's up to the handler to decrease this */
-		if (l->nbconn >= l->maxconn) {
-			EV_FD_CLR(l->fd, DIR_RD);
-			l->state = LI_FULL;
-		}
-		actconn++;
-	}
-	return 0;
-
- out_free_req:
-	pool_free2(pool2_buffer, s->req);
- out_free_task:
-	task_free(t);
- out_free_session:
-	LIST_DEL(&s->list);
-	pool_free2(pool2_session, s);
- out_close:
-	close(cfd);
-	return 0;
-}
-
 __attribute__((constructor))
 static void __uxst_protocol_init(void)
 {