sinetd.c 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. #include <errno.h>
  2. #include <stdio.h>
  3. #include <string.h>
  4. #include <sys/stat.h>
  5. #include <unistd.h>
  6. #include <fcntl.h>
  7. #include <netinet/in.h>
  8. #include <sys/socket.h>
  9. #include <stdlib.h>
  10. #include <sys/wait.h>
  11. #include "sinetd.h"
  12. int unixProgramResult( pid_t programPid, const char* programName ){
  13. int wstatus;
  14. pid_t waitres;
  15. //wait while programs works
  16. waitres = waitpid( programPid, &wstatus, 0 );
  17. if( waitres < 0 ) {
  18. perror( "waitpid" );
  19. return -2;
  20. }
  21. //print result
  22. if( WIFSIGNALED(wstatus) ) {
  23. printf( "%s was killed by signal %d\n", programName, WTERMSIG(wstatus) );
  24. return -1;
  25. }
  26. if( WIFEXITED(wstatus) ){
  27. if( WEXITSTATUS(wstatus) ){
  28. printf( "%s return code %d\n", programName, WEXITSTATUS(wstatus) );
  29. return -1;
  30. }
  31. return 0;
  32. }
  33. printf( "FATAL: waitpid return unknown status.\n" );
  34. return -2;
  35. }
  36. static pid_t startUnixProgram( struct instance* this ){
  37. int res1;
  38. int res2;
  39. int res3;
  40. pid_t forkRes;
  41. //after fork main thread return
  42. //and child be works in this function
  43. forkRes = fork();
  44. if( forkRes ){
  45. close( this->clientSocket );
  46. if( forkRes < 0 ) perror( "startUnixProgram fork" );
  47. return forkRes;
  48. }
  49. //close stdio
  50. res1 = close( fileno(stdin) );
  51. res2 = close( fileno(stdout) );
  52. res3 = close( fileno(stderr) );
  53. if( res1 < 0 || res2 < 0 || res3 < 0 ) exit( 60 );
  54. //replace stdio with socket
  55. res1 = dup2( this->clientSocket, 0 );
  56. res2 = dup2( this->clientSocket, 1 );
  57. res3 = dup2( this->clientSocket, 2 );
  58. if( res1 < 0 || res2 < 0 || res3 < 0 ) exit( 63 );
  59. //close original socket fd
  60. close( this->clientSocket );
  61. //exec
  62. execve( this->argv[0], this->argv, this->envp );
  63. exit( 66 );
  64. }
  65. static int launchSocketHandler( struct instance* this ){
  66. pid_t handlerPid;
  67. //run programm
  68. handlerPid = startUnixProgram( this );
  69. if( handlerPid < 0 ) return -1;
  70. //check status
  71. unixProgramResult( handlerPid, "Handler" );
  72. return 0;
  73. }
  74. static int openAndListenPort( struct instance* this ){
  75. const int reuseAddrEnable = 1;
  76. int res;
  77. int serverSocket;
  78. struct sockaddr_in addr;
  79. //TODO: SIGPIPE
  80. //socket
  81. serverSocket = socket( AF_INET, SOCK_STREAM, 0 );
  82. if( serverSocket < 0 ){
  83. perror("socket");
  84. return -1;
  85. }
  86. //set SO_REUSEADDR option for server socket
  87. res = setsockopt( serverSocket, SOL_SOCKET, SO_REUSEADDR, &reuseAddrEnable, sizeof(reuseAddrEnable) );
  88. if( res ){
  89. perror( "server sock set SO_REUSEADDR" );
  90. goto l_closeServer;
  91. }
  92. //set close-on-exec flag on server socket
  93. res = fcntl( serverSocket, F_SETFD, FD_CLOEXEC );
  94. if( res ){
  95. perror( "set close-on-exec flag on server socket" );
  96. goto l_closeServer;
  97. }
  98. addr.sin_family = AF_INET;
  99. addr.sin_port = htons( this->portNo );
  100. addr.sin_addr.s_addr = htonl( INADDR_ANY );
  101. //bind
  102. res = bind( serverSocket, (struct sockaddr *)&addr, sizeof(addr) );
  103. if( res ){
  104. perror( "bind" );
  105. goto l_closeServer;
  106. }
  107. //listen
  108. res = listen( serverSocket, 10 );
  109. if( res ){
  110. perror( "listen" );
  111. goto l_closeServer;
  112. }
  113. printf( "Listening %i TCP...\n", this->portNo );
  114. do{
  115. //accept
  116. this->clientSocket = accept( serverSocket, NULL, NULL );
  117. if( this->clientSocket < 0 ){
  118. perror( "accept" );
  119. goto l_closeServer;
  120. }
  121. //handle request
  122. res = launchSocketHandler( this );
  123. //close client socket
  124. close( this->clientSocket );
  125. //accept next
  126. }while( res > -2 );
  127. l_closeServer:
  128. close( serverSocket );
  129. return res;
  130. }
  131. int main( int argc, char* argv[], char* envp[] ){
  132. int i;
  133. int res;
  134. struct instance this = {
  135. .envp = envp,
  136. .portNo = 0
  137. };
  138. //parse arguments
  139. for( i = 1; i < argc; i++ ){
  140. //port
  141. if( !strcmp(argv[i], "-p") ){
  142. i++;
  143. if( i == argc || this.portNo ) goto l_help;
  144. res = sscanf( argv[i], "%hu", &this.portNo );
  145. if( res != 1 ) goto l_help;
  146. if( !this.portNo || this.portNo > 65535 ){
  147. printf( "TCP port must be in range 1-65535.\n" );
  148. return 2;
  149. }
  150. //options end marker
  151. }else if( !strcmp(argv[i], "--" ) ){
  152. i++;
  153. break;
  154. }
  155. }
  156. //check args exists
  157. if( i == argc ) goto l_help;
  158. //set argv for execve
  159. this.argv = &argv[i];
  160. //argv terminator check
  161. if( argv[argc] ){
  162. printf( "FATAL: argv[argc] != NULL\n" );
  163. return 1;
  164. }
  165. //check port is set
  166. if( !this.portNo ) goto l_help;
  167. //listen port
  168. res = openAndListenPort( &this );
  169. if( res ) return 1;
  170. return 0;
  171. l_help:
  172. printf(
  173. "Usage:\n"
  174. " %s -p <port> -- <exec> [exec args]\n\n"
  175. " <port> TCP port that server will listen.\n"
  176. " <exec> Path to program which will be run.\n"
  177. " [exec args] Parameters that will be passed to the program."
  178. "\n"
  179. , argv[0]
  180. );
  181. return 2;
  182. }