123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236 |
- #include <errno.h>
- #include <stdio.h>
- #include <string.h>
- #include <sys/stat.h>
- #include <unistd.h>
- #include <fcntl.h>
- #include <netinet/in.h>
- #include <sys/socket.h>
- #include <stdlib.h>
- #include <sys/wait.h>
- #include "sinetd.h"
- int unixProgramResult( pid_t programPid, const char* programName ){
-
- int wstatus;
- pid_t waitres;
-
- //wait while programs works
- waitres = waitpid( programPid, &wstatus, 0 );
- if( waitres < 0 ) {
- perror( "waitpid" );
- return -2;
- }
-
- //print result
- if( WIFSIGNALED(wstatus) ) {
- printf( "%s was killed by signal %d\n", programName, WTERMSIG(wstatus) );
- return -1;
- }
-
- if( WIFEXITED(wstatus) ){
- if( WEXITSTATUS(wstatus) ){
- printf( "%s return code %d\n", programName, WEXITSTATUS(wstatus) );
- return -1;
- }
- return 0;
- }
-
- printf( "FATAL: waitpid return unknown status.\n" );
- return -2;
- }
- static pid_t startUnixProgram( struct instance* this ){
-
- int res1;
- int res2;
- int res3;
- pid_t forkRes;
-
- //after fork main thread return
- //and child be works in this function
- forkRes = fork();
- if( forkRes ){
- close( this->clientSocket );
- if( forkRes < 0 ) perror( "startUnixProgram fork" );
- return forkRes;
- }
-
- //close stdio
- res1 = close( fileno(stdin) );
- res2 = close( fileno(stdout) );
- res3 = close( fileno(stderr) );
- if( res1 < 0 || res2 < 0 || res3 < 0 ) exit( 60 );
-
- //replace stdio with socket
- res1 = dup2( this->clientSocket, 0 );
- res2 = dup2( this->clientSocket, 1 );
- res3 = dup2( this->clientSocket, 2 );
- if( res1 < 0 || res2 < 0 || res3 < 0 ) exit( 63 );
-
- //close original socket fd
- close( this->clientSocket );
-
- //exec
- execve( this->argv[0], this->argv, this->envp );
- exit( 66 );
- }
- static int launchSocketHandler( struct instance* this ){
-
- pid_t handlerPid;
-
- //run programm
- handlerPid = startUnixProgram( this );
- if( handlerPid < 0 ) return -1;
-
- //check status
- unixProgramResult( handlerPid, "Handler" );
-
- return 0;
- }
- static int openAndListenPort( struct instance* this ){
-
- const int reuseAddrEnable = 1;
-
- int res;
- int serverSocket;
- struct sockaddr_in addr;
-
- //TODO: SIGPIPE
-
- //socket
- serverSocket = socket( AF_INET, SOCK_STREAM, 0 );
- if( serverSocket < 0 ){
- perror("socket");
- return -1;
- }
-
- //set SO_REUSEADDR option for server socket
- res = setsockopt( serverSocket, SOL_SOCKET, SO_REUSEADDR, &reuseAddrEnable, sizeof(reuseAddrEnable) );
- if( res ){
- perror( "server sock set SO_REUSEADDR" );
- goto l_closeServer;
- }
-
- //set close-on-exec flag on server socket
- res = fcntl( serverSocket, F_SETFD, FD_CLOEXEC );
- if( res ){
- perror( "set close-on-exec flag on server socket" );
- goto l_closeServer;
- }
-
- addr.sin_family = AF_INET;
- addr.sin_port = htons( this->portNo );
- addr.sin_addr.s_addr = htonl( INADDR_ANY );
-
- //bind
- res = bind( serverSocket, (struct sockaddr *)&addr, sizeof(addr) );
- if( res ){
- perror( "bind" );
- goto l_closeServer;
- }
-
- //listen
- res = listen( serverSocket, 10 );
- if( res ){
- perror( "listen" );
- goto l_closeServer;
- }
-
- printf( "Listening %i TCP...\n", this->portNo );
-
- do{
- //accept
- this->clientSocket = accept( serverSocket, NULL, NULL );
-
- if( this->clientSocket < 0 ){
- perror( "accept" );
- goto l_closeServer;
- }
-
- //handle request
- res = launchSocketHandler( this );
-
- //close client socket
- close( this->clientSocket );
-
- //accept next
- }while( res > -2 );
-
-
- l_closeServer:
- close( serverSocket );
- return res;
- }
- int main( int argc, char* argv[], char* envp[] ){
-
- int i;
- int res;
-
- struct instance this = {
- .envp = envp,
- .portNo = 0
- };
-
- //parse arguments
- for( i = 1; i < argc; i++ ){
-
- //port
- if( !strcmp(argv[i], "-p") ){
- i++;
- if( i == argc || this.portNo ) goto l_help;
- res = sscanf( argv[i], "%hu", &this.portNo );
- if( res != 1 ) goto l_help;
- if( !this.portNo || this.portNo > 65535 ){
- printf( "TCP port must be in range 1-65535.\n" );
- return 2;
- }
-
- //options end marker
- }else if( !strcmp(argv[i], "--" ) ){
- i++;
- break;
- }
- }
-
- //check args exists
- if( i == argc ) goto l_help;
-
- //set argv for execve
- this.argv = &argv[i];
-
- //argv terminator check
- if( argv[argc] ){
- printf( "FATAL: argv[argc] != NULL\n" );
- return 1;
- }
-
- //check port is set
- if( !this.portNo ) goto l_help;
-
- //listen port
- res = openAndListenPort( &this );
- if( res ) return 1;
-
- return 0;
-
- l_help:
- printf(
- "Usage:\n"
- " %s -p <port> -- <exec> [exec args]\n\n"
- " <port> TCP port that server will listen.\n"
- " <exec> Path to program which will be run.\n"
- " [exec args] Parameters that will be passed to the program."
- "\n"
- , argv[0]
- );
-
- return 2;
- }
|