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