*** apache_base:[src.main]http_main.c;1 Mon Aug 23 11:38:21 1999 --- apache_cur:[src.main]http_main.c;32 Mon Aug 23 19:48:48 1999 *************** *** 76,81 **** --- 76,86 ---- * * April-July '95 rst * Extensive rework for Apache. + * + * January 99 PV + * Porting to OpenVMS + * June 1999 DLJ + * Porting to OpenVMS. */ #ifndef SHARED_CORE_BOOTSTRAP *************** *** 123,128 **** --- 128,140 ---- #ifdef HAVE_BSTRING_H #include /* for IRIX, FD_SET calls bzero() */ #endif + #if defined(VMS) && !defined(UCX$C_AUXS) + /* + * We can not include ucx$inetdef.h because it redefines already included + * constants. + */ + #define UCX$C_AUXS 127 + #endif #ifdef MULTITHREAD /* special debug stuff -- PCS */ *************** *** 312,317 **** --- 324,342 ---- */ static int one_process = 0; + #ifdef VMS + /* + * Since VMS doesn't have a fork, server processes identify themselves as + * children by the -w (worker) option on the command line, with optarg being the + * scoreboard slot number allocated by the caretaker process. The child_id + * global is set to this slot number or -1 for the caretaker. + * + * The children have to do all the initialization done by the caretaker + * before calling child_main. + */ + int vms_child_id = -1; + #define child_id vms_child_id + #endif /* set if timeouts are to be handled by the children and not by the parent. * i.e. child_timeouts = !standalone || one_process. *************** *** 994,999 **** --- 1019,1131 ---- ap_check_signals(); } + #elif defined(USE_VMSDLM_SERIALIZED_ACCEPT) + + #include /* VMS lock manager defs */ + #include /* VMS string descriptors */ + #include + int SYS$ENQW(), SYS$DEQ(), LIB$GETJPI(), LIB$GET_EF(); + + static int accept_lock_ef; + static long accept_lock_id; /* Lock ID for lock */ + static struct lock_status_block { long status, id; long value[4]; }; + + static void accept_mutex_cleanup(void *foo) + { + SYS$DEQ ( accept_lock_id, 0, 0, 0 ); + } + + /* + * Initialize mutex lock. + * Done by each child at it's birth + */ + static void accept_mutex_child_init(pool *p) + { + /* + * Assume all children have the same parent, incorporate the + * parent's PID into the lock name so we have a separate lock + * for each running server. + */ + int code, status; + long owner; + struct lock_status_block lksb; + static char lock_name[32]; + static $DESCRIPTOR(lock_name_dx,lock_name); + + code = JPI$_OWNER; + status = LIB$GETJPI ( &code, 0, 0, &owner, 0, 0 ); + if ( (status&1) == 0 ) { + fprintf ( stderr, "Error getting parent ID; %d\n", status); + owner = 0; + } + if ( !owner ) owner = getpid(); /* fallback to our own PID */ + + sprintf ( lock_name, "APACHE_ACCEPT_%08x", owner ); + lock_name_dx.dsc$w_length = strlen(lock_name); + /* + * Get null mode lock. + */ + accept_lock_ef = 0; + LIB$GET_EF ( &accept_lock_ef ); /* no really needed */ + + status = SYS$ENQW ( accept_lock_ef, LCK$K_NLMODE, &lksb, + LCK$M_EXPEDITE, &lock_name_dx, 0, 0, 0, 0, 0, 0 ); + if ( (status&1) == 1 ) status = lksb.status; + if ( (status&1) == 0 ) { + ap_log_error(APLOG_MARK, APLOG_EMERG, server_conf, + "VMSDLM: Error %d creating accept lock. Exiting!", status ); + clean_child_exit(APEXIT_CHILDINIT); + } + /* + * Save the returned lock ID for use by mutext_on/off + */ + accept_lock_id = lksb.id; + } + + /* + * Initialize mutex lock. + * Must be safe to call this on a restart. + */ + static void accept_mutex_init(pool *p) + { + /* No action by parent needed */ + } + + /* Convert to EXclusive mode to lock mutex and convert back to NulL mode + * to unlock. + */ + static void accept_mutex_on(void) + { + int status; + struct lock_status_block lksb; + + lksb.id = accept_lock_id; + status = SYS$ENQW ( accept_lock_ef, LCK$K_EXMODE, &lksb, LCK$M_CONVERT, + 0, 0, 0, 0, 0, 0, 0 ); + if ( (status&1) == 1 ) status = lksb.status; + if ( (status&1) == 0 ) { + ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_EMERG, server_conf, + "VMSDLM: Error %d getting accept lock. Exiting!", status ); + clean_child_exit(APEXIT_CHILDFATAL); + } + } + + static void accept_mutex_off(void) + { + int status; + struct lock_status_block lksb; + + lksb.id = accept_lock_id; + status = SYS$ENQW ( accept_lock_ef, LCK$K_NLMODE, &lksb, LCK$M_CONVERT, + 0, 0, 0, 0, 0, 0, 0 ); + if ( (status&1) == 1 ) status = lksb.status; + if ( (status&1) == 0 ) { + ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_EMERG, server_conf, + "VMSDLM: Error %d freeing accept lock. Exiting!", status ); + clean_child_exit(APEXIT_CHILDFATAL); + } + } + #else /* Default --- no serialization. Other methods *could* go here, * as #elifs... *************** *** 1055,1060 **** --- 1187,1195 ---- fprintf(stderr, " -S : show parsed settings (currently only vhost settings)\n"); fprintf(stderr, " -t : run syntax check for config files (with docroot check)\n"); fprintf(stderr, " -T : run syntax check for config files (without docroot check)\n"); + #ifdef VMS + fprintf(stderr, " -w number : Assign slot number to child.\n"); + #endif #ifdef WIN32 fprintf(stderr, " -n name : set service name and use its ServerConfigFile\n"); fprintf(stderr, " -k shutdown : tell running Apache to shutdown\n"); *************** *** 1821,1826 **** --- 1956,1964 ---- close(fd); unlink(mfile); } + #elif defined(VMS) + /* Create global section */ + m = vms_create_scoreboard ( SCOREBOARD_SIZE, (child_id < 0) ? 1 : 0 ); #else m = mmap((caddr_t) 0, SCOREBOARD_SIZE, PROT_READ | PROT_WRITE, MAP_ANON | MAP_SHARED, -1, 0); *************** *** 2051,2056 **** --- 2189,2197 ---- if (ap_scoreboard_image == NULL) { setup_shared_mem(p); } + #ifdef VMS + if ( child_id >= 0 ) return; /* children don't init the section */ + #endif memset(ap_scoreboard_image, 0, SCOREBOARD_SIZE); ap_scoreboard_image->global.running_generation = running_gen; #else *************** *** 2649,2660 **** --- 2790,2815 ---- static int volatile usr1_just_die = 1; static int volatile deferred_die; + #ifdef VMS + static int volatile accept_fd = -1; + #include /* sys. serv. return codes: SS$_CANCEL */ + #endif static void usr1_handler(int sig) { if (usr1_just_die) { just_die(sig); } + #ifdef VMS + else if ( accept_fd >= 0 ) { + /* + * Issue cancel on accept in progress. + */ + int vms_chan, SYS$CANCEL(); + vms_chan = vaxc$get_sdc ( accept_fd ); + if ( vms_chan >= 0 ) SYS$CANCEL ( vms_chan ); + } + #endif deferred_die = 1; } *************** *** 2910,2916 **** int x; chdir("/"); ! #if !defined(MPE) && !defined(OS2) && !defined(TPF) /* Don't detach for MPE because child processes can't survive the death of the parent. */ if ((x = fork()) > 0) --- 3065,3071 ---- int x; chdir("/"); ! #if !defined(MPE) && !defined(OS2) && !defined(TPF) && !defined(VMS) /* Don't detach for MPE because child processes can't survive the death of the parent. */ if ((x = fork()) > 0) *************** *** 2934,2940 **** fprintf(stderr, "%s: setpgrp or getpgrp failed\n", ap_server_argv0); exit(1); } ! #elif defined(OS2) || defined(TPF) /* OS/2 and TPF don't support process group IDs */ pgrp = getpid(); #elif defined(MPE) --- 3089,3095 ---- fprintf(stderr, "%s: setpgrp or getpgrp failed\n", ap_server_argv0); exit(1); } ! #elif defined(OS2) || defined(TPF) || defined(VMS) /* OS/2 and TPF don't support process group IDs */ pgrp = getpid(); #elif defined(MPE) *************** *** 2949,2954 **** --- 3104,3110 ---- #endif /* close out the standard file descriptors */ + #ifndef VMS if (freopen("/dev/null", "r", stdin) == NULL) { fprintf(stderr, "%s: unable to replace stdin with /dev/null: %s\n", ap_server_argv0, strerror(errno)); *************** *** 2962,2967 **** --- 3118,3124 ---- fprintf(stderr, "%s: unable to replace stdout with /dev/null: %s\n", ap_server_argv0, strerror(errno)); } + #endif /* stderr is a tricky one, we really want it to be the error_log, * but we haven't opened that yet. So leave it alone for now and it'll * be reopened moments later. *************** *** 3125,3136 **** --- 3282,3309 ---- /* note that because we're about to slack we don't use psocket */ ap_block_alarms(); + #ifndef VMS if ((s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) { ap_log_error(APLOG_MARK, APLOG_CRIT, server_conf, "make_sock: failed to get a socket for %s", addr); ap_unblock_alarms(); exit(1); } + #else + /* + * Must set special attribute on socket to allow driver to share + * listen socket among several processes. Also if port number will + * be less than 1024, create_shared_socket marks the port privileged + * via a special user system service call. + */ + if ( (s=vms_create_shared_socket(AF_INET, SOCK_STREAM, IPPROTO_TCP, + ntohs(server->sin_port) )) < 0 ) { + ap_log_error(APLOG_MARK, APLOG_CRIT, server_conf, + "make_sock: failed to get a (shared) socket for %s", addr); + ap_unblock_alarms(); + exit(1); + } + #endif /* Solaris (probably versions 2.4, 2.5, and 2.5.1 with various levels * of tcp patches) has some really weird bugs where if you dup the *************** *** 3366,3377 **** --- 3539,3589 ---- { listen_rec *lr; int fd; + #ifdef VMS + struct vms_shared_socket *list, *ss; int status; + + if ( child_id >= 0 ) { + /* + * We are a child process, get the list of shared listen sockets + * and initialize their names. + */ + list = (struct vms_shared_socket *) 0; + status = vms_import_shared_socket ( "APACHE_SHARED_SOCKET", &list ); + if ( (status&1) == 1 ) { + for ( ss = list; ss; ss = ss->next ) { + char *p; unsigned char *nbyte; int i, octet; + ss->name = malloc ( sizeof(struct sockaddr) ); + ss->namelen = sizeof(struct sockaddr); + memset ( ss->name, 0, ss->namelen ); + status = getsockname ( ss->fd, (struct sockaddr *) ss->name, + (size_t *) &ss->namelen ); + } + } + else fprintf(stderr,"import of shared socket failed: %d\n", status ); + ss = list; + } + #endif listenmaxfd = -1; FD_ZERO(&listenfds); lr = ap_listeners; for (;;) { fd = find_listener(lr); + #ifdef VMS + if ( (child_id >= 0) && (fd < 0) && ss ) { + /* Locate matching address (to be done later) */ + for ( ss = list; ss; ss = ss->next ) { + if ( memcmp(&lr->local_addr, ss->name, ss->namelen ) == 0 ) { + fd = ss->fd; + break; + } + } + if ( !ss ) { + printf("Failed to find matching shared socket\n"); + fd = list->fd; + } + } + #endif if (fd < 0) { fd = make_sock(p, &lr->local_addr); } *************** *** 3393,3398 **** --- 3605,3624 ---- head_listener = ap_listeners; close_unused_listeners(); + #ifdef VMS + if ( child_id < 0 ) { + /* + * We are caretaker process, build logical name that lists + * the names of the shared socket devices. + */ + int status; + status = vms_export_shared_sockets ( "APACHE_SHARED_SOCKET" ); + if ( (status&1) == 0 ) { + fprintf(stderr,"Error exporting shared listen socket names: %d\n", + status ); + } + } + #endif #ifdef NO_SERIALIZED_ACCEPT /* warn them about the starvation problem if they're using multiple * sockets *************** *** 3529,3534 **** --- 3755,3763 ---- #ifdef USE_PTHREAD_SERIALIZED_ACCEPT printf(" -D USE_PTHREAD_SERIALIZED_ACCEPT\n"); #endif + #ifdef USE_VMSDLM_SERIALIZED_ACCEPT + printf(" -D USE_VMSDLM_SERIALIZED_ACCEPT\n"); + #endif #ifdef SINGLE_LISTEN_UNSERIALIZED_ACCEPT printf(" -D SINGLE_LISTEN_UNSERIALIZED_ACCEPT\n"); #endif *************** *** 3817,3823 **** usr1_just_die = 0; for (;;) { clen = sizeof(sa_client); ! csd = ap_accept(sd, &sa_client, &clen); if (csd >= 0 || errno != EINTR) break; if (deferred_die) { --- 4046,4064 ---- usr1_just_die = 0; for (;;) { clen = sizeof(sa_client); ! #ifdef VMS ! errno = 0; ! accept_fd = sd; ! csd = accept(sd, &sa_client, &clen); ! accept_fd = -1; ! if ( csd < 0 ) { ! /* Convert cancel to EINTR errno */ ! if ( (errno == EVMSERR) && (vaxc$errno == SS$_CANCEL) ) ! errno = EINTR; ! } ! #else ! csd = accept(sd, &sa_client, &clen); ! #endif if (csd >= 0 || errno != EINTR) break; if (deferred_die) { *************** *** 4130,4135 **** --- 4371,4384 ---- } if (one_process) { + #ifdef VMS + /* + * mimic the rotation of the ring 'start' + */ + int i; + for ( i = 0; i < slot; i++ ) head_listener = head_listener->next; + if ( (child_id >= 0) ) slot = child_id; + #endif signal(SIGHUP, just_die); signal(SIGINT, just_die); #ifdef SIGQUIT *************** *** 4145,4151 **** --- 4394,4427 ---- Explain1("Starting new child in slot %d", slot); (void) ap_update_child_status(slot, SERVER_STARTING, (request_rec *) NULL); + #ifdef VMS + pid = 0; + if ( !one_process ) { + /* + * Rather than fork, create a sub-process running a script. + * If symbol httpc defined, spawn command "httpc n", otherwise + * spawn command "httpd -w n". + */ + static char *val, command[256]; + static int command_init = 0; + int status; + if ( 0 == command_init ) { + command_init = 1; /* only call getenv once */ + val = getenv ( "httpc" ); + } + sprintf ( command, "%s %d", val ? "httpc" : "httpd -w", slot ); + status = vms_create_child ( command, (long *) &pid ); + if ( (status&1) == 0 ) pid = 0; + } else { + pid = getpid(); /* use ourselves */ + } + if ( (pid == 0) ) { + /* + * Spawn didn't succeed, fix the scoreboard or else it will + * say SERVER_STARTING forever. + */ + #else #ifdef _OSD_POSIX /* BS2000 requires a "special" version of fork() before a setuid() call */ if ((pid = os_fork(ap_user_name)) == -1) { *************** *** 4159,4164 **** --- 4435,4441 ---- /* fork didn't succeed. Fix the scoreboard or else * it will say SERVER_STARTING forever and ever */ + #endif /* VMS */ (void) ap_update_child_status(slot, SERVER_DEAD, (request_rec *) NULL); /* In case system resources are maxxed out, we don't want *************** *** 4411,4417 **** --- 4688,4698 ---- #endif ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, server_conf, + #ifdef VMS + "child pid %x exit signal %s (%d)", pid, + #else "child pid %d exit signal %s (%d)", pid, + #endif SYS_SIGLIST[WTERMSIG(status)], WTERMSIG(status)); #ifdef WCOREDUMP } *************** *** 4473,4478 **** --- 4754,4765 ---- setup_listeners(pconf); ap_clear_pool(plog); ap_open_logs(server_conf, plog); + #ifdef VMS + /* + * Have only the master process create a .pid file. + */ + if ( child_id < 0 ) + #endif ap_log_pid(pconf, ap_pid_fname); ap_set_version(); /* create our server_version string */ ap_init_modules(pconf, server_conf); *************** *** 4489,4494 **** --- 4776,4794 ---- #endif set_signals(); + #ifdef VMS + /* + * If we are really a child process, skip all the make_child stuff + */ + if ( child_id >= 0 ) { + signal(SIGHUP, just_die); + signal(SIGINT, just_die); + signal(SIGQUIT, SIG_DFL); + signal(SIGTERM, just_die); + child_main(child_id); + return; + } + #endif if (ap_daemons_max_free < ap_daemons_min_free + 1) /* Don't thrash... */ ap_daemons_max_free = ap_daemons_min_free + 1; *************** *** 4727,4733 **** ap_setup_prelinked_modules(); while ((c = getopt(argc, argv, ! "D:C:c:xXd:f:vVlLR:StTh" #ifdef DEBUG_SIGSTOP "Z:" #endif --- 5027,5033 ---- ap_setup_prelinked_modules(); while ((c = getopt(argc, argv, ! "D:C:c:xXd:f:w:vVlLR:StTh" #ifdef DEBUG_SIGSTOP "Z:" #endif *************** *** 4790,4795 **** --- 5090,5100 ---- */ break; #endif + #ifdef VMS + case 'w': + child_id = atoi ( optarg ); + break; + #endif case 'S': ap_dump_settings = 1; break; *************** *** 4902,4907 **** --- 5207,5226 ---- sock_out = * (int*)(&(ecbptr()->ebw000)); /* TPF also needs a signal set for alarm in inetd mode */ signal(SIGALRM, alrm_handler); + + #elif defined(VMS) + + /* TCP/IP Services for OpenVMS defines the Auxiliary server which accepts the + * connection. Howver, remember that Apache.Org depricates ServerType inetd + */ + + if ((sock_in = socket(UCX$C_AUXS, SOCK_STREAM, IPPROTO_TCP)) < 0) { + fprintf(stderr, "Error getting network socket\n"); + perror("socket"); + exit(1); + } + sock_out = sock_in; + #elif defined(MPE) /* HP MPE 5.5 inetd only passes the incoming socket as stdin (fd 0), whereas HPUX inetd passes the incoming socket as stdin (fd 0) and stdout (fd 1).