+ * Loop through the available servers, and serve them. Never returns.
+ **/
+int serveloop(GArray* servers) G_GNUC_NORETURN {
+ struct sockaddr_in addrin;
+ socklen_t addrinlen=sizeof(addrin);
+ SERVER *serve;
+ int i;
+ int max;
+ int sock;
+ fd_set mset;
+ fd_set rset;
+ struct timeval tv;
+
+ /*
+ * Set up the master fd_set. The set of descriptors we need
+ * to select() for never changes anyway and it buys us a *lot*
+ * of time to only build this once. However, if we ever choose
+ * to not fork() for clients anymore, we may have to revisit
+ * this.
+ */
+ max=0;
+ FD_ZERO(&mset);
+ for(i=0;i<servers->len;i++) {
+ sock=(g_array_index(servers, SERVER, i)).socket;
+ FD_SET(sock, &mset);
+ max=sock>max?sock:max;
+ }
+ for(;;) {
+ CLIENT *client;
+ int net;
+ pid_t *pid;
+
+ memcpy(&rset, &mset, sizeof(fd_set));
+ tv.tv_sec=0;
+ tv.tv_usec=500;
+ if(select(max+1, &rset, NULL, NULL, &tv)>0) {
+ DEBUG("accept, ");
+ for(i=0;i<servers->len;i++) {
+ serve=&(g_array_index(servers, SERVER, i));
+ if(FD_ISSET(serve->socket, &rset)) {
+ if ((net=accept(serve->socket, (struct sockaddr *) &addrin, &addrinlen)) < 0)
+ err("accept: %m");
+
+ client = g_malloc(sizeof(CLIENT));
+ client->server=serve;
+ client->exportsize=OFFT_MAX;
+ client->net=net;
+ set_peername(net, client);
+ if (!authorized_client(client)) {
+ msg2(LOG_INFO,"Unauthorized client") ;
+ close(net);
+ continue;
+ }
+ msg2(LOG_INFO,"Authorized client") ;
+ pid=g_malloc(sizeof(pid_t));
+#ifndef NOFORK
+ if ((*pid=fork())<0) {
+ msg3(LOG_INFO,"Could not fork (%s)",strerror(errno)) ;
+ close(net);
+ continue;
+ }
+ if (*pid>0) { /* parent */
+ close(net);
+ g_hash_table_insert(children, pid, pid);
+ continue;
+ }
+ /* child */
+ g_hash_table_destroy(children);
+ for(i=0;i<servers->len;i++) {
+ serve=g_array_index(servers, SERVER*, i);
+ close(serve->socket);
+ }
+ /* FALSE does not free the
+ actual data. This is required,
+ because the client has a
+ direct reference into that
+ data, and otherwise we get a
+ segfault... */
+ g_array_free(servers, FALSE);
+#endif // NOFORK
+ msg2(LOG_INFO,"Starting to serve");
+ serveconnection(client);
+ exit(EXIT_SUCCESS);
+ }
+ }
+ }
+ }
+}
+
+/**