mirror of
				https://github.com/apache/httpd.git
				synced 2025-10-31 19:10:37 +03:00 
			
		
		
		
	with old connections in TIME_WAIT. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1515050 13f79535-47bb-0310-9956-ffa450edef68
		
			
				
	
	
		
			221 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			221 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* Licensed to the Apache Software Foundation (ASF) under one or more
 | |
|  * contributor license agreements.  See the NOTICE file distributed with
 | |
|  * this work for additional information regarding copyright ownership.
 | |
|  * The ASF licenses this file to You under the Apache License, Version 2.0
 | |
|  * (the "License"); you may not use this file except in compliance with
 | |
|  * the License.  You may obtain a copy of the License at
 | |
|  *
 | |
|  *     http://www.apache.org/licenses/LICENSE-2.0
 | |
|  *
 | |
|  * Unless required by applicable law or agreed to in writing, software
 | |
|  * distributed under the License is distributed on an "AS IS" BASIS,
 | |
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | |
|  * See the License for the specific language governing permissions and
 | |
|  * limitations under the License.
 | |
|  */
 | |
| 
 | |
| #include <apr.h>
 | |
| #include <apr_pools.h>
 | |
| #include <apr_network_io.h>
 | |
| #include <apr_thread_proc.h>
 | |
| #include <apr_getopt.h>
 | |
| #include <apr_portable.h>
 | |
| 
 | |
| #if APR_HAVE_STDLIB_H
 | |
| #include <stdlib.h> /* For EXIT_SUCCESS, EXIT_FAILURE */
 | |
| #endif
 | |
| 
 | |
| #if APR_HAVE_UNISTD_H
 | |
| #include <unistd.h> /* For execl */
 | |
| #endif
 | |
| 
 | |
| static const char *usage_message =
 | |
|     "usage: fcgistarter -c <command> -p <port> [-i <interface> -N <num>]\n"
 | |
|     "\n"
 | |
|     "If an interface is not specified, any available will be used.\n";
 | |
| 
 | |
| static void usage(void)
 | |
| {
 | |
|     fprintf(stderr, "%s", usage_message);
 | |
| 
 | |
|     exit(EXIT_FAILURE);
 | |
| }
 | |
| 
 | |
| static void exit_error(apr_status_t rv, const char *func)
 | |
| {
 | |
|     char buffer[1024];
 | |
| 
 | |
|     fprintf(stderr,
 | |
|             "%s: %s\n",
 | |
|             func,
 | |
|             apr_strerror(rv, buffer, sizeof(buffer)));
 | |
| 
 | |
|     exit(EXIT_FAILURE);
 | |
| }
 | |
| 
 | |
| int main(int argc, const char * const argv[])
 | |
| {
 | |
|     apr_file_t *infd, *skwrapper;
 | |
|     apr_sockaddr_t *skaddr;
 | |
|     apr_getopt_t *gopt;
 | |
|     apr_socket_t *skt;
 | |
|     apr_pool_t *pool;
 | |
|     apr_status_t rv;
 | |
|     apr_proc_t proc;
 | |
| 
 | |
| 
 | |
|     /* Command line arguments */
 | |
|     int num_to_start = 1, port = 0;
 | |
|     const char *interface = NULL;
 | |
|     const char *command = NULL;
 | |
| 
 | |
|     apr_app_initialize(&argc, &argv, NULL);
 | |
| 
 | |
|     atexit(apr_terminate);
 | |
| 
 | |
|     apr_pool_create(&pool, NULL);
 | |
| 
 | |
|     rv = apr_getopt_init(&gopt, pool, argc, argv);
 | |
|     if (rv) {
 | |
|         return EXIT_FAILURE;
 | |
|     }
 | |
| 
 | |
|     for (;;) {
 | |
|         const char *arg;
 | |
|         char opt;
 | |
| 
 | |
|         rv = apr_getopt(gopt, "c:p:i:N:", &opt, &arg);
 | |
|         if (APR_STATUS_IS_EOF(rv)) {
 | |
|             break;
 | |
|         } else if (rv) {
 | |
|             usage();
 | |
|         } else {
 | |
|             switch (opt) {
 | |
|             case 'c':
 | |
|                 command = arg;
 | |
|                 break;
 | |
| 
 | |
|             case 'p':
 | |
|                 port = atoi(arg);
 | |
|                 if (! port) {
 | |
|                     usage();
 | |
|                 }
 | |
|                 break;
 | |
| 
 | |
|             case 'i':
 | |
|                 interface = arg;
 | |
|                 break;
 | |
| 
 | |
|             case 'N':
 | |
|                 num_to_start = atoi(arg);
 | |
|                 if (! num_to_start) {
 | |
|                     usage();
 | |
|                 }
 | |
|                 break;
 | |
| 
 | |
|             default:
 | |
|                 break;
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     if (! command || ! port) {
 | |
|         usage();
 | |
|     }
 | |
| 
 | |
|     rv = apr_sockaddr_info_get(&skaddr, interface, APR_UNSPEC, port, 0, pool);
 | |
|     if (rv) {
 | |
|         exit_error(rv, "apr_sockaddr_info_get");
 | |
|     }
 | |
| 
 | |
|     rv = apr_socket_create(&skt, skaddr->family, SOCK_STREAM, APR_PROTO_TCP, pool);
 | |
|     if (rv) {
 | |
|         exit_error(rv, "apr_socket_create");
 | |
|     }
 | |
| 
 | |
|     rv = apr_socket_opt_set(skt, APR_SO_REUSEADDR, 1);
 | |
|     if (rv) {
 | |
|         exit_error(rv, "apr_socket_opt_set(APR_SO_REUSEADDR)");
 | |
|     }
 | |
| 
 | |
|     rv = apr_socket_bind(skt, skaddr);
 | |
|     if (rv) {
 | |
|         exit_error(rv, "apr_socket_bind");
 | |
|     }
 | |
| 
 | |
|     rv = apr_socket_listen(skt, 1024);
 | |
|     if (rv) {
 | |
|         exit_error(rv, "apr_socket_listen");
 | |
|     }
 | |
| 
 | |
|     rv = apr_proc_detach(APR_PROC_DETACH_DAEMONIZE);
 | |
|     if (rv) {
 | |
|         exit_error(rv, "apr_proc_detach");
 | |
|     }
 | |
| 
 | |
| #if defined(WIN32) || defined(OS2) || defined(NETWARE)
 | |
| 
 | |
| #error "Please implement me."
 | |
| 
 | |
| #else
 | |
| 
 | |
|     while (--num_to_start >= 0) {
 | |
|         rv = apr_proc_fork(&proc, pool);
 | |
|         if (rv == APR_INCHILD) {
 | |
|             apr_os_file_t oft = 0;
 | |
|             apr_os_sock_t oskt;
 | |
| 
 | |
|             /* Ok, so we need a file that has file descriptor 0 (which
 | |
|              * FastCGI wants), but points to our socket.  This isn't really
 | |
|              * possible in APR, so we cheat a bit.  I have no idea how to
 | |
|              * do this on a non-unix platform, so for now this is platform
 | |
|              * specific.  Ick.
 | |
|              *
 | |
|              * Note that this has to happen post-detach, otherwise fd 0
 | |
|              * gets closed during apr_proc_detach and it's all for nothing.
 | |
|              *
 | |
|              * Unfortunately, doing this post detach means we have no way
 | |
|              * to let anyone know if there's a problem at this point :( */
 | |
| 
 | |
|             rv = apr_os_file_put(&infd, &oft, APR_READ | APR_WRITE, pool);
 | |
|             if (rv) {
 | |
|                 exit(EXIT_FAILURE);
 | |
|             }
 | |
| 
 | |
|             rv = apr_os_sock_get(&oskt, skt);
 | |
|             if (rv) {
 | |
|                 exit(EXIT_FAILURE);
 | |
|             }
 | |
| 
 | |
|             rv = apr_os_file_put(&skwrapper, &oskt, APR_READ | APR_WRITE,
 | |
|                                  pool);
 | |
|             if (rv) {
 | |
|                 exit(EXIT_FAILURE);
 | |
|             }
 | |
| 
 | |
|             rv = apr_file_dup2(infd, skwrapper, pool);
 | |
|             if (rv) {
 | |
|                 exit(EXIT_FAILURE);
 | |
|             }
 | |
| 
 | |
|             /* XXX Can't use apr_proc_create because there's no way to get
 | |
|              *     infd into the procattr without going through another dup2,
 | |
|              *     which means by the time it gets to the fastcgi process it
 | |
|              *     is no longer fd 0, so it doesn't work.  Sigh. */
 | |
| 
 | |
|             execl(command, command, NULL);
 | |
| 
 | |
|         } else if (rv == APR_INPARENT) {
 | |
|             if (num_to_start == 0) {
 | |
|                 apr_socket_close(skt);
 | |
|             }
 | |
|         } else {
 | |
|             exit_error(rv, "apr_proc_fork");
 | |
|         }
 | |
|     }
 | |
| 
 | |
| #endif
 | |
| 
 | |
|     return EXIT_SUCCESS;
 | |
| }
 |