ttcpd

Trivial tcp daemon
git clone git://git.finwo.net/app/ttcpd
Log | Files | Refs | LICENSE

ttcpd.c (3882B)


      1 #ifdef __cplusplus
      2 extern "C" {
      3 #endif
      4 
      5 #include <arpa/inet.h>
      6 #include <netinet/in.h>
      7 #include <stdint.h>
      8 #include <stdio.h>
      9 #include <stdlib.h>
     10 #include <string.h>
     11 #include <sys/socket.h>
     12 #include <sys/types.h>
     13 #include <sys/wait.h>
     14 #include <unistd.h>
     15 
     16 #ifdef GNU_SOURCE
     17 #include <fcntl.h>
     18 #endif
     19 
     20 void usage( char *cmd ) {
     21   fprintf(stderr, "\n");
     22   fprintf(stderr, "Usage:\n");
     23   fprintf(stderr, "  %s -h\n", cmd);
     24   fprintf(stderr, "  %s [-p port] [-c command] [-- arg arg ...]\n", cmd);
     25   fprintf(stderr, "\n");
     26   fprintf(stderr, "Options:\n");
     27   fprintf(stderr, "  -h          Show this help\n");
     28   fprintf(stderr, "  -a address  Address to listen on (default: any)\n");
     29   fprintf(stderr, "  -p port     Set the port to listen on (default: 8080)\n");
     30   fprintf(stderr, "  -c command  The command to run\n");
     31   fprintf(stderr, "\n");
     32   fprintf(stderr, "About:\n");
     33   fprintf(stderr, "%s handles network communications for basic commands, attaching\n", cmd);
     34   fprintf(stderr, "a connection's i/o to the command's stdin and stdout.\n");
     35   fprintf(stderr, "\n");
     36 }
     37 
     38 int main( int argc, char *argv[] ) {
     39   char * inaddr = "any";
     40 
     41   // Initialize
     42   int opt=0,port = 8080;
     43   char *cmd = 0;
     44   char **args = calloc(argc,sizeof(void*));
     45 
     46   // Detect port by environment variables
     47   if(getenv("PORT")) {
     48     port = atoi(getenv("PORT"));
     49   }
     50 
     51   // Parse arguments
     52   while((opt = getopt(argc, argv, "a:c:p:")) != -1) {
     53     switch(opt) {
     54       case 'a':
     55         inaddr = optarg;
     56         break;
     57       case 'c':
     58         cmd = optarg;
     59         break;
     60       case 'p':
     61         port = atoi(optarg);
     62         break;
     63       case 'h':
     64         usage(argv[0]);
     65         exit(EXIT_SUCCESS);
     66       default:
     67         usage(argv[0]);
     68         exit(EXIT_FAILURE);
     69     }
     70   }
     71 
     72   // Arguments to child
     73   args[0] = cmd;
     74   if(strcmp(argv[optind-1],"--")==0) {
     75     for(opt=0; argv[optind+opt]; opt++) {
     76       args[opt+1] = argv[optind+opt];
     77     }
     78   }
     79 
     80   // Make sure we have a command set
     81   if(!cmd) {
     82     fprintf( stderr, "Required argument not given: command\n" );
     83     exit(EXIT_FAILURE);
     84   };
     85 
     86   // Start listening socket
     87   int sockfd = socket( AF_INET, SOCK_STREAM, 0 );
     88   if(sockfd<0) {
     89     fprintf( stderr, "Could not initialize socket\n" );
     90     exit(EXIT_FAILURE);
     91   }
     92 
     93   // Setup server address
     94   struct sockaddr_in saddr, caddr;
     95   bzero((char *) &saddr, sizeof(saddr));
     96   saddr.sin_family      = AF_INET;
     97   saddr.sin_addr.s_addr = INADDR_ANY;
     98   saddr.sin_port        = htons(port);
     99 
    100   inet_aton(inaddr, &saddr.sin_addr);
    101 
    102   // Allow socket re-use
    103   int optval = 1;
    104   setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT, &optval, sizeof(optval));
    105 
    106   // Bind socket to port
    107   if(bind(sockfd,(struct sockaddr *) &saddr, sizeof(saddr))<0) {
    108     fprintf( stderr, "Could not bind to %s:%d\n", inet_ntoa(saddr.sin_addr), port );
    109     exit(EXIT_FAILURE);
    110   }
    111 
    112   // Start listening
    113   if(listen(sockfd,5)) {
    114     fprintf( stderr, "Could not start listening\n" );
    115     exit(EXIT_FAILURE);
    116   } else {
    117     printf( "Listening on %s:%d\n", inet_ntoa(saddr.sin_addr), port );
    118   }
    119 
    120   // Prepare for the client
    121   socklen_t clen = sizeof(caddr);
    122   int nsock;
    123 
    124   // Start accepting connections
    125   while( (nsock=accept(sockfd,(struct sockaddr *) &caddr,&clen)) >= 0 ) {
    126 
    127     // Spawn a clone
    128     if(fork()) {
    129 
    130       // We're the parent, we don't need the socket anymore
    131       close(nsock);
    132 
    133       // Don't wait for childs, ever
    134       waitpid(-1,NULL,WNOHANG);
    135     } else {
    136 
    137       // We're the child, bind the socket to stdio
    138       close(0);
    139       close(1);
    140       dup2(nsock,0);
    141       dup2(nsock,1);
    142 
    143       // Close the old reference
    144       close(nsock);
    145 
    146       // Start the given command
    147       execvp( cmd, args );
    148 
    149       // Being here is a major failure
    150       // Simply exit with an error code
    151       return 3;
    152     }
    153   }
    154 
    155   // We should never reach this
    156   // Maybe a SIGHUP received?
    157   return 0;
    158 }
    159 
    160 #ifdef __cplusplus
    161 } //extern "C"
    162 #endif