Changeset 2106

Show
Ignore:
Timestamp:
02/28/2008 12:19:34 PM (2 months ago)
Author:
stbuehler
Message:

Fix #1575: spawn-fcgi: only try to connect to unix socket (not tcp) before spawning

  • we do not need to check for a tcp socket this way as bind will fail if the socket is in use;
    this does not apply to unix sockets as they are not bound to a filename but to the file, which
    we delete before spawning.
Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • branches/lighttpd-1.4.x/NEWS

    r2105 r2106  
    4545  * remove compress cache file if compression or write failed (#1150) 
    4646  * fixed body handling of status 300 requests  
     47  * spawn-fcgi: only try to connect to unix socket (not tcp) before spawning (#1575) 
    4748 
    4849- 1.4.18 - 2007-09-09 
  • branches/lighttpd-1.4.x/src/spawn-fcgi.c

    r2023 r2106  
    4949        socklen_t servlen; 
    5050 
     51        pid_t child; 
     52        int val; 
     53 
    5154        if (child_count < 2) { 
    5255                child_count = 5; 
     
    7275                socket_type = AF_UNIX; 
    7376                fcgi_addr = (struct sockaddr *) &fcgi_addr_un; 
     77 
     78                /* check if some backend is listening on the socket 
     79                 * as if we delete the socket-file and rebind there will be no "socket already in use" error 
     80                 */ 
     81                if (-1 == (fcgi_fd = socket(socket_type, SOCK_STREAM, 0))) { 
     82                        fprintf(stderr, "%s.%d\n", 
     83                                __FILE__, __LINE__); 
     84                        return -1; 
     85                } 
     86 
     87                if (-1 != connect(fcgi_fd, fcgi_addr, servlen)) { 
     88                        fprintf(stderr, "%s.%d: socket is already used, can't spawn\n", 
     89                                __FILE__, __LINE__); 
     90                        return -1; 
     91                } 
     92 
     93                /* cleanup previous socket if it exists */ 
     94                unlink(unixsocket); 
     95                close(fcgi_fd); 
    7496        } else { 
    7597                fcgi_addr_in.sin_family = AF_INET; 
     
    86108        } 
    87109 
     110        /* open socket */ 
    88111        if (-1 == (fcgi_fd = socket(socket_type, SOCK_STREAM, 0))) { 
    89112                fprintf(stderr, "%s.%d\n", 
     
    92115        } 
    93116 
    94         if (-1 == connect(fcgi_fd, fcgi_addr, servlen)) { 
    95                 /* server is not up, spawn in  */ 
    96                 pid_t child; 
    97                 int val; 
    98  
    99                 if (unixsocket) unlink(unixsocket); 
    100  
    101                 close(fcgi_fd); 
    102  
    103                 /* reopen socket */ 
    104                 if (-1 == (fcgi_fd = socket(socket_type, SOCK_STREAM, 0))) { 
    105                         fprintf(stderr, "%s.%d\n", 
    106                                 __FILE__, __LINE__); 
    107                         return -1; 
    108                 } 
    109  
    110                 val = 1; 
    111                 if (setsockopt(fcgi_fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) { 
    112                         fprintf(stderr, "%s.%d\n", 
    113                                 __FILE__, __LINE__); 
    114                         return -1; 
    115                 } 
    116  
    117                 /* create socket */ 
    118                 if (-1 == bind(fcgi_fd, fcgi_addr, servlen)) { 
    119                         fprintf(stderr, "%s.%d: bind failed: %s\n", 
     117        val = 1; 
     118        if (setsockopt(fcgi_fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) { 
     119                fprintf(stderr, "%s.%d\n", 
     120                        __FILE__, __LINE__); 
     121                return -1; 
     122        } 
     123 
     124        /* create socket */ 
     125        if (-1 == bind(fcgi_fd, fcgi_addr, servlen)) { 
     126                fprintf(stderr, "%s.%d: bind failed: %s\n", 
     127                        __FILE__, __LINE__, 
     128                        strerror(errno)); 
     129                return -1; 
     130        } 
     131 
     132        if (-1 == listen(fcgi_fd, 1024)) { 
     133                fprintf(stderr, "%s.%d: fd = -1\n", 
     134                        __FILE__, __LINE__); 
     135                return -1; 
     136        } 
     137 
     138        if (!nofork) { 
     139                child = fork(); 
     140        } else { 
     141                child = 0; 
     142        } 
     143 
     144        switch (child) { 
     145        case 0: { 
     146                char cgi_childs[64]; 
     147 
     148                int i = 0; 
     149 
     150                /* is safe as we limit to 256 childs */ 
     151                sprintf(cgi_childs, "PHP_FCGI_CHILDREN=%d", child_count); 
     152 
     153                if(fcgi_fd != FCGI_LISTENSOCK_FILENO) { 
     154                        close(FCGI_LISTENSOCK_FILENO); 
     155                        dup2(fcgi_fd, FCGI_LISTENSOCK_FILENO); 
     156                        close(fcgi_fd); 
     157                } 
     158 
     159                /* we don't need the client socket */ 
     160                for (i = 3; i < 256; i++) { 
     161                        close(i); 
     162                } 
     163 
     164                /* create environment */ 
     165 
     166                putenv(cgi_childs); 
     167 
     168                /* fork and replace shell */ 
     169                if (appArgv) { 
     170                        execv(appArgv[0], appArgv); 
     171 
     172                } else { 
     173                        char *b = malloc(strlen("exec ") + strlen(appPath) + 1); 
     174                        strcpy(b, "exec "); 
     175                        strcat(b, appPath); 
     176 
     177                        /* exec the cgi */ 
     178                        execl("/bin/sh", "sh", "-c", b, (char *)NULL); 
     179                } 
     180 
     181                exit(errno); 
     182 
     183                break; 
     184        } 
     185        case -1: 
     186                /* error */ 
     187                break; 
     188        default: 
     189                /* father */ 
     190 
     191                /* wait */ 
     192                select(0, NULL, NULL, NULL, &tv); 
     193 
     194                switch (waitpid(child, &status, WNOHANG)) { 
     195                case 0: 
     196                        fprintf(stderr, "%s.%d: child spawned successfully: PID: %d\n", 
    120197                                __FILE__, __LINE__, 
    121                                 strerror(errno)); 
    122                         return -1; 
    123                 } 
    124  
    125                 if (-1 == listen(fcgi_fd, 1024)) { 
    126                         fprintf(stderr, "%s.%d: fd = -1\n", 
    127                                 __FILE__, __LINE__); 
    128                         return -1; 
    129                 } 
    130  
    131                 if (!nofork) { 
    132                         child = fork(); 
    133                 } else { 
    134                         child = 0; 
    135                 } 
    136  
    137                 switch (child) { 
    138                 case 0: { 
    139                         char cgi_childs[64]; 
    140  
    141                         int i = 0; 
    142  
    143                         /* is safe as we limit to 256 childs */ 
    144                         sprintf(cgi_childs, "PHP_FCGI_CHILDREN=%d", child_count); 
    145  
    146                         if(fcgi_fd != FCGI_LISTENSOCK_FILENO) { 
    147                                 close(FCGI_LISTENSOCK_FILENO); 
    148                                 dup2(fcgi_fd, FCGI_LISTENSOCK_FILENO); 
    149                                 close(fcgi_fd); 
    150                         } 
    151  
    152                         /* we don't need the client socket */ 
    153                         for (i = 3; i < 256; i++) { 
    154                                 close(i); 
    155                         } 
    156  
    157                         /* create environment */ 
    158  
    159                         putenv(cgi_childs); 
    160  
    161                         /* fork and replace shell */ 
    162                         if (appArgv) { 
    163                                 execv(appArgv[0], appArgv); 
    164  
    165                         } else { 
    166                                 char *b = malloc(strlen("exec ") + strlen(appPath) + 1); 
    167                                 strcpy(b, "exec "); 
    168                                 strcat(b, appPath); 
    169  
    170                                 /* exec the cgi */ 
    171                                 execl("/bin/sh", "sh", "-c", b, (char *)NULL); 
    172                         } 
    173  
    174                         exit(errno); 
     198                                child); 
     199 
     200                        /* write pid file */ 
     201                        if (pid_fd != -1) { 
     202                                /* assume a 32bit pid_t */ 
     203                                char pidbuf[12]; 
     204 
     205                                snprintf(pidbuf, sizeof(pidbuf) - 1, "%d", child); 
     206 
     207                                write(pid_fd, pidbuf, strlen(pidbuf)); 
     208                                close(pid_fd); 
     209                                pid_fd = -1; 
     210                        } 
    175211 
    176212                        break; 
    177                 } 
    178213                case -1: 
    179                         /* error */ 
    180214                        break; 
    181215                default: 
    182                         /* father */ 
    183  
    184                         /* wait */ 
    185                         select(0, NULL, NULL, NULL, &tv); 
    186  
    187                         switch (waitpid(child, &status, WNOHANG)) { 
    188                         case 0: 
    189                                 fprintf(stderr, "%s.%d: child spawned successfully: PID: %d\n", 
    190                                         __FILE__, __LINE__, 
    191                                         child); 
    192  
    193                                 /* write pid file */ 
    194                                 if (pid_fd != -1) { 
    195                                         /* assume a 32bit pid_t */ 
    196                                         char pidbuf[12]; 
    197  
    198                                         snprintf(pidbuf, sizeof(pidbuf) - 1, "%d", child); 
    199  
    200                                         write(pid_fd, pidbuf, strlen(pidbuf)); 
    201                                         close(pid_fd); 
    202                                         pid_fd = -1; 
    203                                 } 
    204  
    205                                 break; 
    206                         case -1: 
    207                                 break; 
    208                         default: 
    209                                 if (WIFEXITED(status)) { 
    210                                         fprintf(stderr, "%s.%d: child exited with: %d, %s\n", 
    211                                                 __FILE__, __LINE__, 
    212                                                 WEXITSTATUS(status), strerror(WEXITSTATUS(status))); 
    213                                 } else if (WIFSIGNALED(status)) { 
    214                                         fprintf(stderr, "%s.%d: child signaled: %d\n", 
    215                                                 __FILE__, __LINE__, 
    216                                                 WTERMSIG(status)); 
    217                                 } else { 
    218                                         fprintf(stderr, "%s.%d: child died somehow: %d\n", 
    219                                                 __FILE__, __LINE__, 
    220                                                 status); 
    221                                 } 
    222                         } 
    223  
    224                         break; 
    225                 } 
    226         } else { 
    227                 fprintf(stderr, "%s.%d: socket is already used, can't spawn\n", 
    228                         __FILE__, __LINE__); 
    229                 return -1; 
     216                        if (WIFEXITED(status)) { 
     217                                fprintf(stderr, "%s.%d: child exited with: %d, %s\n", 
     218                                        __FILE__, __LINE__, 
     219                                        WEXITSTATUS(status), strerror(WEXITSTATUS(status))); 
     220                        } else if (WIFSIGNALED(status)) { 
     221                                fprintf(stderr, "%s.%d: child signaled: %d\n", 
     222                                        __FILE__, __LINE__, 
     223                                        WTERMSIG(status)); 
     224                        } else { 
     225                                fprintf(stderr, "%s.%d: child died somehow: %d\n", 
     226                                        __FILE__, __LINE__, 
     227                                        status); 
     228                        } 
     229                } 
     230 
     231                break; 
    230232        } 
    231233 
     
    286288                switch(o) { 
    287289                case 'f': fcgi_app = optarg; break; 
    288                case 'a': addr = optarg;/* ip addr */ break; 
     290               case 'a': addr = optarg;/* ip addr */ break; 
    289291                case 'p': port = strtol(optarg, NULL, 10);/* port */ break; 
    290292                case 'C': child_count = strtol(optarg, NULL, 10);/*  */ break;