1 /*
2 
3 $Header: socket.c[1.17] Wed Sep  9 16:23:14 1992 nickel@cs.tu-berlin.de proposed $
4 This file is part of socket(1).
5 Copyright (C) 1992 by Juergen Nickelsen <nickel@cs.tu-berlin.de>
6 Please read the file COPYRIGHT for further details.
7 
8 */
9 
10 #include <sys/types.h>
11 #include <sys/socket.h>
12 #ifdef USE_INET6
13 #include <sys/time.h>
14 #endif /* USE_INET6 */
15 #include <netinet/in.h>
16 #include <netdb.h>
17 #include <errno.h>
18 #include <stdio.h>
19 #ifdef SEQUENT
20 #include <strings.h>
21 #else
22 #include <string.h>
23 #endif
24 #include <stdlib.h>
25 #include <unistd.h>
26 #include "globals.h"
27 
28 /* global variables */
29 int forkflag = 0 ;		/* server forks on connection */
30 int serverflag = 0 ;		/* create server socket */
31 int loopflag = 0 ;		/* loop server */
32 int verboseflag = 0 ;		/* give messages */
33 int readonlyflag = 0 ;		/* only read from socket */
34 int writeonlyflag = 0 ;		/* only write to socket */
35 int quitflag = 0 ;		/* quit connection on EOF */
36 int crlfflag = 0 ;		/* socket expects and delivers CRLF */
37 int backgflag = 0 ;		/* put yourself in background */
38 int active_socket ;		/* socket with connection */
39 char *progname ;		/* name of the game */
40 char *pipe_program = NULL ;	/* program to execute in two-way pipe */
41 
42 #ifndef USE_INET6
43 void server A((int port, char *service_name)) ;
44 void client A((char *host, int port, char *service_name)) ;
45 #else /* USE_INET6 */
46 void server A((char *port)) ;
47 void client A((char *host, char *port)) ;
48 #endif /* USE_INET6 */
49 
50 void handle_server_connection A((void)) ;
51 extern void init_signals A((void)) ;
52 extern void do_io A((void)) ;
53 
main(argc,argv)54 int main(argc, argv)
55 int argc ;
56 char **argv ;
57 {
58     char *cp ;			/* to point to '/' in argv[0] */
59     int opt ;			/* option character */
60     int error = 0 ;		/* usage error occurred */
61     extern int optind ;		/* from getopt() */
62     /* char *host ; */		/* name of remote host */
63 #ifndef USE_INET6
64     int port ;			/* port number for socket */
65     char *service_name ;	/* name of service for port */
66 #endif /* USE_INET6 */
67 
68     /* print version ID if requested */
69     if (argv[1] && !strcmp(argv[1], "-version")) {
70 	puts(so_release()) ;
71 	exit(0) ;
72     }
73 
74     /* set up progname for later use */
75     progname = argv[0] ;
76     cp = strrchr(progname, '/');
77     if (cp) progname = cp + 1 ;
78 
79     /* parse options */
80     while ((opt = getopt(argc, argv, "bcflp:qrsvw?")) != -1) {
81 	switch (opt) {
82 	  case 'f':
83 	    forkflag = 1 ;
84 	    break ;
85 	  case 'c':
86 	    crlfflag = 1 ;
87 	    break ;
88 	  case 'w':
89 	    writeonlyflag = 1 ;
90 	    break ;
91 	  case 'p':
92 	    pipe_program = argv[optind - 1] ;
93 	    break ;
94 	  case 'q':
95 	    quitflag = 1 ;
96 	    break ;
97 	  case 'r':
98 	    readonlyflag = 1 ;
99 	    break ;
100 	  case 's':
101 	    serverflag = 1 ;
102 	    break ;
103 	  case 'v':
104 	    verboseflag = 1 ;
105 	    break ;
106 	  case 'l':
107 	    loopflag = 1 ;
108 	    break ;
109 	  case 'b':
110 	    backgflag = 1 ;
111 	    break ;
112 	  default:
113 	    error++ ;
114 	}
115     }
116     if (error ||		/* usage error? */
117 	argc - optind + serverflag != 2) { /* number of args ok? */
118 	usage() ;
119 	exit(15) ;
120     }
121 
122     /* check some option combinations */
123 #define senseless(s1, s2) \
124     fprintf(stderr, "It does not make sense to set %s and %s.\n", (s1), (s2))
125 
126     if (writeonlyflag && readonlyflag) {
127 	senseless("-r", "-w") ;
128 	exit(15) ;
129     }
130     if (loopflag && !serverflag) {
131 	senseless("-l", "not -s") ;
132 	exit(15) ;
133     }
134     if (backgflag && !serverflag) {
135  	senseless("-b", "not -s") ;
136  	exit(15) ;
137     }
138     if (forkflag && !serverflag) {
139 	senseless("-f", "not -s") ;
140     }
141 
142     /* set up signal handling */
143     init_signals() ;
144 
145 #ifndef USE_INET6
146     /* get port number */
147     port = resolve_service(argv[optind + 1 - serverflag],
148 			   "tcp", &service_name) ;
149     if (port < 0) {
150 	fprintf(stderr, "%s: unknown service\n", progname) ;
151 	exit(5) ;
152     }
153 
154 #endif /* not USE_INET6 */
155     /* and go */
156     if (serverflag) {
157 	if (backgflag) {
158 	    background() ;
159 	}
160 #ifndef USE_INET6
161 	server(port, service_name) ;
162 #else /* USE_INET6 */
163 	server(argv[optind]) ;
164 #endif /* USE_INET6 */
165     } else {
166 #ifndef USE_INET6
167 	client(argv[optind], port, service_name) ;
168 #else /* USE_INET6 */
169 	client(argv[optind], argv[optind + 1]) ;
170 #endif /* USE_INET6 */
171     }
172     exit(0) ;
173 }
174 
175 
176 #ifndef USE_INET6
server(port,service_name)177 void server(port, service_name)
178 int port ;
179 char *service_name ;
180 #else /* USE_INET6 */
181 void server(port)
182 char *port ;
183 #endif /* USE_INET6 */
184 {
185 #ifndef USE_INET6
186     int socket_handle, alen ;
187 #else /* USE_INET6 */
188     int *socket_handle_list ;
189 #endif /* USE_INET6 */
190 
191     /* allocate server socket */
192 #ifndef USE_INET6
193     socket_handle = create_server_socket(port, 1) ;
194     if (socket_handle < 0) {
195 #else /* USE_INET6 */
196     socket_handle_list = create_server_sockets(&port, 1) ;
197     if (!socket_handle_list) {
198 #endif /* USE_INET6 */
199 	perror2("server socket") ;
200 	exit(1) ;
201     }
202 #ifdef USE_INET6
203 
204 #endif /* USE_INET6 */
205     if (verboseflag) {
206 #ifndef USE_INET6
207 	fprintf(stderr, "listening on port %d", port) ;
208 	if (service_name) {
209 	    fprintf(stderr, " (%s)", service_name) ;
210 	}
211 	fprintf(stderr, "\n") ;
212 #else /* USE_INET6 */
213 	char *ip, *port;
214 	int fd, i;
215 
216 	fd = socket_handle_list[1];
217 	for (i = 1; i <= socket_handle_list[0]; i++) {
218     	    if (!fd || fd < socket_handle_list[i])
219        	        fd = socket_handle_list[i];
220 	    socket_local_name (fd, NULL, &ip, &port);
221 	    fprintf(stderr, "listening at address %s on port %s\n", ip, port) ;
222     	}
223 #endif /* USE_INET6 */
224     }
225 
226     /* server loop */
227     do {
228 #ifndef USE_INET6
229 	struct sockaddr_in sa ;
230 
231 	alen = sizeof(sa) ;
232 
233 	/* accept a connection */
234 	if ((active_socket = accept(socket_handle,
235 			  (struct sockaddr *) &sa,
236 			  &alen)) == -1) {
237 	    perror2("accept") ;
238 	} else {
239 	    /* if verbose, get name of peer and give message */
240 	    if (verboseflag) {
241 		struct hostent *he ;
242 		long norder ;
243 		char dotted[20] ;
244 
245 		he = gethostbyaddr((const char *)&sa.sin_addr.s_addr,
246 				   sizeof(sa.sin_addr.s_addr), AF_INET) ;
247 		if (!he) {
248 		    norder = htonl(sa.sin_addr.s_addr) ;
249 		    sprintf(dotted, "%d.%d.%d.%d",
250                            (int)((norder >> 24) & 0xff),
251                            (int)((norder >> 16) & 0xff),
252                            (int)((norder >>  8) & 0xff),
253                            (int)(norder & 0xff)) ;
254 #else /* USE_INET6 */
255 	struct timeval tv;
256 	fd_set readfd;
257     	int fd, i, nfds, retval;
258 
259 	fd = socket_handle_list[1];
260 	for (i = 1; i <= socket_handle_list[0]; i++) {
261     	    if (!fd || fd < socket_handle_list[i])
262        	        fd = socket_handle_list[i];
263     	}
264 	nfds=fd+1;
265 
266 	FD_ZERO(&readfd);
267 	for (i = 1; i <= socket_handle_list[0]; i++)
268 	    FD_SET(socket_handle_list[i],&readfd);
269 
270     	tv.tv_sec  = 10;
271     	tv.tv_usec = 0;
272 
273     	retval = select(nfds, &readfd, NULL, NULL, &tv);
274 
275     	if(retval!=-1) {
276             for (i = 1; i <= socket_handle_list[0]; i++) {
277 		fd = socket_handle_list[i];
278 		if (FD_ISSET(fd, &readfd)) {
279 
280 		    /* accept a connection */
281 		    active_socket = accept(fd, (struct sockaddr *) 0, (int *)0);
282 		    if (active_socket == -1) {
283 			perror2("accept") ;
284 		    } else {
285 			/* if verbose, get name of peer and give message */
286 			if (verboseflag) {
287 			    char *host, *ip, *port;
288 
289 			    if(!socket_remote_name(active_socket,&host, &ip, &port)) {
290 				fprintf(stderr, "connection from %s at %s to %s\n", host, ip, port);
291 			    }
292 			    else
293 				fprintf(stderr, "cannot get name or address of peer") ;
294 			}
295 
296 			if (forkflag) {
297 			    switch (fork()) {
298 			    case 0:
299 				handle_server_connection() ;
300 				exit(0) ;
301 			    case -1:
302 				perror2("fork") ;
303 				break ;
304 			    default:
305 				close(active_socket) ;
306 				wait_for_children() ;
307 			    }
308 			} else {
309 			    handle_server_connection() ;
310 			}
311 		    }
312 #endif /* USE_INET6 */
313 		}
314 #ifndef USE_INET6
315 		fprintf(stderr, "connection from %s\n",
316 			(he ? he->h_name : dotted)) ;
317 	    }
318 	    if (forkflag) {
319 		switch (fork()) {
320 		  case 0:
321 		    handle_server_connection() ;
322 		    exit(0) ;
323 		  case -1:
324 		    perror2("fork") ;
325 		    break ;
326 		  default:
327 		    close(active_socket) ;
328 		    wait_for_children() ;
329 		}
330 	    } else {
331 		handle_server_connection() ;
332 #endif /* not USE_INET6 */
333 	    }
334 	}
335     } while (loopflag) ;
336 #ifdef USE_INET6
337 
338     free (socket_handle_list);
339 #endif /* USE_INET6 */
340 }
341 
342 
handle_server_connection()343 void handle_server_connection()
344 {
345     /* open pipes to program, if requested */
346     if (pipe_program != NULL) {
347 	open_pipes(pipe_program) ;
348     }
349     /* enter IO loop */
350     do_io() ;
351     /* connection is closed now */
352     close(active_socket) ;
353     if (pipe_program) {
354 	/* remove zombies */
355 	wait_for_children() ;
356     }
357 }
358 
359 
360 #ifndef USE_INET6
client(host,port,service_name)361 void client(host, port, service_name)
362 #else /* USE_INET6 */
363 void client(host, port)
364 #endif /* USE_INET6 */
365 char *host ;
366 #ifndef USE_INET6
367 int port ;
368 char *service_name ;
369 #else /* USE_INET6 */
370 char *port ;
371 #endif /* USE_INET6 */
372 {
373     /* get connection */
374 #ifndef USE_INET6
375     active_socket = create_client_socket(&host, port) ;
376 #else /* USE_INET6 */
377     active_socket = create_client_socket(&host, &port) ;
378 #endif /* USE_INET6 */
379     if (active_socket == -1) {
380 	perror2("client socket") ;
381 	exit(errno) ;
382     } else if (active_socket == -2) {
383 	fprintf(stderr, "%s: unknown host %s\n", progname, host) ;
384 	exit(13) ;
385     }
386     if (verboseflag) {
387 #ifndef USE_INET6
388 	fprintf(stderr, "connected to %s port %d", host, port) ;
389 	if (service_name) {
390 	    fprintf(stderr, " (%s)", service_name) ;
391 	}
392 	fprintf(stderr, "\n") ;
393 #else /* USE_INET6 */
394 	char *host, *ip, *port;
395 
396 	socket_local_name (active_socket, &host, &ip, &port);
397 	fprintf(stderr, "connected to %s with address %s at port %s\n", host, ip, port) ;
398 #endif /* USE_INET6 */
399     }
400 
401     /* open pipes to program if requested */
402     if (pipe_program != NULL) {
403 	open_pipes(pipe_program) ;
404     }
405     /* enter IO loop */
406     do_io() ;
407     /* connection is closed now */
408     close(active_socket) ;
409 }
410 
411 /*EOF*/
412