r294: Delay daemon() call as long as possible, and modify error handling slightly to
[nbd.git] / nbd-server.c
index f9691df..044e6d9 100644 (file)
@@ -139,7 +139,7 @@ gchar* rungroup=NULL;
  **/
 #define OFFT_MAX ~((off_t)1<<(sizeof(off_t)*8-1))
 #define LINELEN 256      /**< Size of static buffer used to read the
-                           authorization file (yuck) */
+                              authorization file (yuck) */
 #define BUFSIZE (1024*1024) /**< Size of buffer that can hold requests */
 #define DIFFPAGESIZE 4096 /**< diff file uses those chunks */
 #define F_READONLY 1      /**< flag to tell us a file is readonly */
@@ -1365,6 +1365,96 @@ void destroy_pid_t(gpointer data) {
 }
 
 /**
+ * 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);
+                               }
+                       }
+               }
+       }
+}
+
+/**
  * Go daemon (unless we specified at compile time that we didn't want this)
  * @param serve the first server of our configuration. If its port is zero,
  *     then do not daemonize, because we're doing inetd then. This parameter
@@ -1402,6 +1492,17 @@ void daemonize(SERVER* serve) {
 #define daemonize(serve)
 #endif /* !defined(NODAEMON) && !defined(NOFORK) */
 
+/*
+ * Everything beyond this point (in the file) is run in non-daemon mode.
+ * The stuff above daemonize() isn't.
+ */
+
+void serve_err(SERVER* serve, const char* msg) G_GNUC_NORETURN {
+       g_message("Export of %s on port %d failed:", serve->exportname,
+                       serve->port);
+       err(msg);
+}
+
 /**
  * Connect a server's socket.
  *
@@ -1483,96 +1584,6 @@ void setup_servers(GArray* servers) {
 }
 
 /**
- * Loop through the available servers, and serve them.
- **/
-int serveloop(GArray* servers) {
-       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);
-                               }
-                       }
-               }
-       }
-}
-
-/**
  * Set up user-ID and/or group-ID
  **/
 void dousers(void) {