static void stream_chargen( const struct server *serp ) { char line_buf[ LINE_LENGTH+2 ] ; int descriptor = SERVER_FD( serp ) ; struct service *svc = SERVER_SERVICE( serp ); if( SVC_WAITS( svc ) ) { descriptor = accept(descriptor, NULL, NULL); if ( descriptor == -1 ) { if ((errno == EMFILE) || (errno == ENFILE)) cps_service_stop(svc, "no available descriptors"); return; } } (void) shutdown( descriptor, 0 ) ; close_all_svc_descriptors(); for ( ;; ) { if ( generate_line( line_buf, sizeof( line_buf ) ) == NULL ) break ; if ( write_buf( descriptor, line_buf, sizeof( line_buf ) ) == FAILED ) break ; } if( SVC_WAITS( svc ) ) /* Service forks, so close it */ Sclose(descriptor); }
static void stream_discard( const struct server *serp ) { char buf[ BUFFER_SIZE ] ; int cc ; int descriptor = SERVER_FD( serp ) ; struct service *svc = SERVER_SERVICE( serp ) ;; if( SVC_WAITS( svc ) ) { descriptor = accept(descriptor, NULL, NULL); if ( descriptor == -1 ) { if ((errno == EMFILE) || (errno == ENFILE)) cps_service_stop(svc, "no available descriptors"); return; } } close_all_svc_descriptors(); for ( ;; ) { cc = read( descriptor, buf, sizeof( buf ) ) ; if ( (cc == 0) || ((cc == -1) && (errno != EINTR)) ) break ; } if( SVC_WAITS( svc ) ) /* Service forks, so close it */ Sclose(descriptor); }
/* * Get a connection for the specified service and return a pointer * to a new connection_s */ connection_s *conn_new( struct service *sp ) { connection_s new_conn ; connection_s *cp ; const char *func = "conn_new" ; CLEAR( new_conn ) ; /* * The reason we first get the connection and then allocate a * 'connection_s' is because we want to always consume some input. */ if ( get_connection( sp, &new_conn ) == FAILED ) return( NULL ) ; new_conn.co_sp = sp ; SVC_HOLD( sp ) ; if ( SVC_WAITS( sp ) ) svc_suspend( sp ) ; cp = NEW_CONN() ; if ( cp == CONN_NULL ) { out_of_memory( func ) ; conn_free( &new_conn, 0 ) ; CLEAR( new_conn ) ; return( CONN_NULL ) ; } memcpy(cp, &new_conn, sizeof(connection_s)); return( cp ) ; }
static void stream_echo( const struct server *serp ) { char buf[ BUFFER_SIZE ] ; ssize_t cc ; int descriptor = SERVER_FD( serp ) ; struct service *svc = SERVER_SERVICE( serp ) ;; if( SVC_WAITS( svc ) ) { descriptor = accept(descriptor, NULL, NULL); if ( descriptor == -1 ) { if ((errno == EMFILE) || (errno == ENFILE)) cps_service_stop(svc, "no available descriptors"); return; } } close_all_svc_descriptors(); for ( ;; ) { cc = read( descriptor, buf, sizeof( buf ) ) ; if ( cc == 0 ) break ; if ( cc == (ssize_t)-1 ) { if ( errno == EINTR ) continue ; else break ; } if ( write_buf( descriptor, buf, cc ) == FAILED ) break ; } if( SVC_WAITS( svc ) ) /* Service forks, so close it */ Sclose(descriptor); }
/* * Invoked when a server of the specified service dies */ void svc_postmortem( struct service *sp, struct server *serp ) { struct service *co_sp = SERVER_CONNSERVICE( serp ) ; connection_s *cp = SERVER_CONNECTION( serp ) ; const char *func = "svc_postmortem" ; SVC_DEC_RUNNING_SERVERS( sp ) ; /* * Log information about the server that died */ if ( SVC_IS_LOGGING( sp ) ) { if ( SERVER_WRITES_TO_LOG(serp) ) { if ( debug.on ) msg( LOG_DEBUG, func, "Checking log size of %s service", SVC_ID( sp ) ) ; xlog_control( SVC_LOG( sp ), XLOG_SIZECHECK ) ; } svc_log_exit( sp, serp ) ; } /* * Now check if we have to check the log size of the service that owns * the connection */ if ( co_sp != sp && SVC_IS_LOGGING( co_sp ) ) xlog_control( SVC_LOG( co_sp ), XLOG_SIZECHECK ) ; if (!SVC_WAITS(sp)) { conn_free( cp, 1 ) ; cp = NULL; } else { if (cp) { if ( SVC_SOCKET_TYPE( sp ) == SOCK_DGRAM ) drain( cp->co_descriptor ) ; free(cp); cp = NULL; if( SVC_RELE( sp ) == 0 ) svc_release( sp ); /* shouldn't be 0, but should remove from * pset if it is... */ } svc_resume(sp); } }
static void stream_daytime( const struct server *serp ) { char time_buf[ BUFFER_SIZE ] ; unsigned int buflen = sizeof( time_buf ) ; int descriptor = SERVER_FD( serp ) ; struct service *svc = SERVER_SERVICE( serp ) ;; if( SVC_WAITS( svc ) ) { descriptor = accept(descriptor, NULL, NULL); if ( descriptor == -1 ) { if ((errno == EMFILE) || (errno == ENFILE)) cps_service_stop(svc, "no available descriptors"); return; } } daytime_protocol( time_buf, &buflen ) ; (void) write_buf( descriptor, time_buf, buflen ) ; Sclose(descriptor); }
static void stream_time( const struct server *serp ) { unsigned char time_buf[4]; int descriptor = SERVER_FD( serp ); struct service *svc = SERVER_SERVICE( serp ); if( SVC_WAITS( svc ) ) { descriptor = accept(descriptor, NULL, NULL); if ( descriptor == -1 ) { if ((errno == EMFILE) || (errno == ENFILE)) cps_service_stop(svc, "no available descriptors"); return; } } time_protocol( time_buf ) ; (void) write_buf( descriptor, (char *) time_buf, 4 ) ; Sclose(descriptor); }
/* * If the service is single-threaded: * if the descriptor is set in the socket mask, there must * be a server running (or to be retried) * If the service is multi-threaded: * the descriptor must be always set */ static unsigned thread_check( struct service *sp, unsigned running_servers, unsigned retry_servers ) { unsigned error_count = 0 ; int sd = SVC_FD( sp ) ; char *sid = SVC_ID( sp ) ; const char *func = "thread_check" ; if ( SVC_WAITS( sp ) ) { bool_int has_servers = ( running_servers + retry_servers != 0 ) ; if ( has_servers && FD_ISSET( sd, &ps.rws.socket_mask ) ) { msg( LOG_ERR, func, "Active single-threaded service %s: server running, descriptor set", sid ) ; error_count++ ; } if ( !has_servers && !FD_ISSET( sd, &ps.rws.socket_mask ) ) { msg( LOG_ERR, func, "Active single-threaded service %s: no server running, descriptor not set", sid ) ; error_count++ ; } } else if ( ! FD_ISSET( sd, &ps.rws.socket_mask ) ) { msg( LOG_ERR, func, "Active multi-threaded service %s: descriptor not set", sid ) ; error_count++ ; } if ( error_count && debug.on ) msg( LOG_DEBUG, func, "%s: %d errors detected", sid, error_count ) ; return( error_count ) ; }
static void tcpmux_handler( const struct server *serp ) { char svc_name[ BUFFER_SIZE ] ; int cc ; int descriptor = SERVER_FD( serp ) ; const struct service *svc = SERVER_SERVICE( serp ) ; unsigned u; struct service *sp = NULL; struct server server, *nserp; struct service_config *scp = NULL; close_all_svc_descriptors(); /* Read in the name of the service in the format "svc_name\r\n". * * XXX: should loop on partial reads (could probably use Sread() if * it wasn't thrown out of xinetd source code a few revisions back). */ do { cc = read( descriptor, svc_name, sizeof( svc_name ) ) ; } while (cc == -1 && errno == EINTR); if ( cc <= 0 ) { msg(LOG_ERR, "tcpmux_handler", "read failed"); exit(0); } if ( ( cc <= 2 ) || ( ( svc_name[cc - 1] != '\n' ) || ( svc_name[cc - 2] != '\r' ) ) ) { if ( debug.on ) msg(LOG_DEBUG, "tcpmux_handler", "Invalid service name format."); exit(0); } svc_name[cc - 2] = '\0'; /* Remove \r\n for compare */ if ( debug.on ) { msg(LOG_DEBUG, "tcpmux_handler", "Input (%d bytes) %s as service name.", cc, svc_name); } /* Search the services for the a match on name. */ for ( u = 0 ; u < pset_count( SERVICES( ps ) ) ; u++ ) { sp = SP( pset_pointer( SERVICES( ps ), u ) ) ; if ( strcasecmp( svc_name, SC_NAME( SVC_CONF( sp ) ) ) == 0 ) { /* Found the pointer. Validate its type. */ scp = SVC_CONF( sp ); /* if ( ! SVC_IS_MUXCLIENT( sp ) ) { if ( debug.on ) { msg(LOG_DEBUG, "tcpmux_handler", "Non-tcpmux service name: %s.", svc_name); } exit(0); } */ /* Send the accept string if we're a PLUS (+) client. */ if ( SVC_IS_MUXPLUSCLIENT( sp ) ) { if ( Swrite( descriptor, TCPMUX_ACK, sizeof( TCPMUX_ACK ) ) != sizeof( TCPMUX_ACK ) ) { msg(LOG_ERR, "tcpmux_handler", "Ack write failed for %s.", svc_name); exit(0); } } break; /* Time to get on with the service */ } continue; /* Keep looking */ } if ( u >= pset_count( SERVICES( ps ) ) ) { if ( debug.on ) { msg(LOG_DEBUG, "tcpmux_handler", "Service name %s not found.", svc_name); } exit(0); } if( SVC_WAITS( svc ) ) /* Service forks, so close it */ Sclose(descriptor); server.svr_sp = sp; server.svr_conn = SERVER_CONNECTION(serp); nserp = server_alloc(&server); if( SC_IS_INTERNAL( scp ) ) { SC_INTERNAL(scp, nserp); } else { exec_server(nserp); } }