1cd30c339dae692a3eb5c5fc55f70726457f4756bmridge/******************************************************************************/
2cd30c339dae692a3eb5c5fc55f70726457f4756bmridge/*                                                                            */
3cd30c339dae692a3eb5c5fc55f70726457f4756bmridge/*   Copyright (c) International Business Machines  Corp., 2005               */
4cd30c339dae692a3eb5c5fc55f70726457f4756bmridge/*                                                                            */
5cd30c339dae692a3eb5c5fc55f70726457f4756bmridge/*   This program is free software;  you can redistribute it and/or modify    */
6cd30c339dae692a3eb5c5fc55f70726457f4756bmridge/*   it under the terms of the GNU General Public License as published by     */
7cd30c339dae692a3eb5c5fc55f70726457f4756bmridge/*   the Free Software Foundation; either version 2 of the License, or        */
8cd30c339dae692a3eb5c5fc55f70726457f4756bmridge/*   (at your option) any later version.                                      */
9cd30c339dae692a3eb5c5fc55f70726457f4756bmridge/*                                                                            */
10cd30c339dae692a3eb5c5fc55f70726457f4756bmridge/*   This program is distributed in the hope that it will be useful,          */
11cd30c339dae692a3eb5c5fc55f70726457f4756bmridge/*   but WITHOUT ANY WARRANTY;  without even the implied warranty of          */
12cd30c339dae692a3eb5c5fc55f70726457f4756bmridge/*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See                */
13cd30c339dae692a3eb5c5fc55f70726457f4756bmridge/*   the GNU General Public License for more details.                         */
14cd30c339dae692a3eb5c5fc55f70726457f4756bmridge/*                                                                            */
15cd30c339dae692a3eb5c5fc55f70726457f4756bmridge/*   You should have received a copy of the GNU General Public License        */
16cd30c339dae692a3eb5c5fc55f70726457f4756bmridge/*   along with this program;  if not, write to the Free Software             */
174548c6cf9bcdd96d8303caa4130ab638b61f8a30Wanlong Gao/*   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA  */
18cd30c339dae692a3eb5c5fc55f70726457f4756bmridge/*                                                                            */
19cd30c339dae692a3eb5c5fc55f70726457f4756bmridge/******************************************************************************/
20cd30c339dae692a3eb5c5fc55f70726457f4756bmridge
21cd30c339dae692a3eb5c5fc55f70726457f4756bmridge/*
22cd30c339dae692a3eb5c5fc55f70726457f4756bmridge * File:
23cd30c339dae692a3eb5c5fc55f70726457f4756bmridge *	ns-tcpserver.c
24cd30c339dae692a3eb5c5fc55f70726457f4756bmridge *
25cd30c339dae692a3eb5c5fc55f70726457f4756bmridge * Description:
26cd30c339dae692a3eb5c5fc55f70726457f4756bmridge *      This is TCP traffic server.
27cd30c339dae692a3eb5c5fc55f70726457f4756bmridge *	Accept connections from the clients, then send tcp segments to clients
28cd30c339dae692a3eb5c5fc55f70726457f4756bmridge *
29cd30c339dae692a3eb5c5fc55f70726457f4756bmridge * Author:
30cd30c339dae692a3eb5c5fc55f70726457f4756bmridge *	Mitsuru Chinen <mitch@jp.ibm.com>
31cd30c339dae692a3eb5c5fc55f70726457f4756bmridge *
32cd30c339dae692a3eb5c5fc55f70726457f4756bmridge * History:
33cd30c339dae692a3eb5c5fc55f70726457f4756bmridge *	Oct 19 2005 - Created (Mitsuru Chinen)
34cd30c339dae692a3eb5c5fc55f70726457f4756bmridge *---------------------------------------------------------------------------*/
35cd30c339dae692a3eb5c5fc55f70726457f4756bmridge
36cd30c339dae692a3eb5c5fc55f70726457f4756bmridge#include "ns-traffic.h"
37cd30c339dae692a3eb5c5fc55f70726457f4756bmridge
38cd30c339dae692a3eb5c5fc55f70726457f4756bmridge/*
39cd30c339dae692a3eb5c5fc55f70726457f4756bmridge * Standard Include Files
40cd30c339dae692a3eb5c5fc55f70726457f4756bmridge */
41cd30c339dae692a3eb5c5fc55f70726457f4756bmridge#include <stdio.h>
42cd30c339dae692a3eb5c5fc55f70726457f4756bmridge#include <stdlib.h>
43cd30c339dae692a3eb5c5fc55f70726457f4756bmridge#include <string.h>
44cd30c339dae692a3eb5c5fc55f70726457f4756bmridge#include <errno.h>
45cd30c339dae692a3eb5c5fc55f70726457f4756bmridge#include <fcntl.h>
46cd30c339dae692a3eb5c5fc55f70726457f4756bmridge#include <netdb.h>
47cd30c339dae692a3eb5c5fc55f70726457f4756bmridge#include <time.h>
48cd30c339dae692a3eb5c5fc55f70726457f4756bmridge#include <unistd.h>
49cd30c339dae692a3eb5c5fc55f70726457f4756bmridge#include <sys/select.h>
50cd30c339dae692a3eb5c5fc55f70726457f4756bmridge#include <sys/socket.h>
51cd30c339dae692a3eb5c5fc55f70726457f4756bmridge#include <sys/stat.h>
52cd30c339dae692a3eb5c5fc55f70726457f4756bmridge#include <sys/types.h>
53cd30c339dae692a3eb5c5fc55f70726457f4756bmridge#include <sys/wait.h>
54cd30c339dae692a3eb5c5fc55f70726457f4756bmridge#include <netinet/in.h>
55cd30c339dae692a3eb5c5fc55f70726457f4756bmridge#include <netinet/tcp.h>
56cd30c339dae692a3eb5c5fc55f70726457f4756bmridge
57cd30c339dae692a3eb5c5fc55f70726457f4756bmridge/*
58cd30c339dae692a3eb5c5fc55f70726457f4756bmridge * Gloval variables
59cd30c339dae692a3eb5c5fc55f70726457f4756bmridge */
60354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gaostruct sigaction handler;	/* Behavior for a signal */
61354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gaoint catch_sighup;		/* When catch the SIGHUP, set to non-zero */
62354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gaoint catch_sigpipe;		/* When catch the SIGPIPE, set to non-zero */
63cd30c339dae692a3eb5c5fc55f70726457f4756bmridge
64cd30c339dae692a3eb5c5fc55f70726457f4756bmridge/*
65cd30c339dae692a3eb5c5fc55f70726457f4756bmridge * Structure: server_info
66cd30c339dae692a3eb5c5fc55f70726457f4756bmridge *
67cd30c339dae692a3eb5c5fc55f70726457f4756bmridge * Description:
68cd30c339dae692a3eb5c5fc55f70726457f4756bmridge *  This structure stores the information of a server
69cd30c339dae692a3eb5c5fc55f70726457f4756bmridge */
70cd30c339dae692a3eb5c5fc55f70726457f4756bmridgestruct server_info {
71354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	sa_family_t family;	/* protocol family */
72354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	char *portnum;		/* port number */
73354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	int listen_sd;		/* socket descriptor for listening */
74354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	int concurrent;		/* if non-zero, act as a concurrent server */
75354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	size_t current_connection;	/* number of the current connection */
76354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	size_t max_connection;	/* maximum connection number */
77354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	size_t lost_connection;	/* number of lost connection */
78354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	size_t small_sending;	/* if non-zero, in the small sending mode */
79354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	size_t window_scaling;	/* if non-zero, in the window scaling mode */
80cd30c339dae692a3eb5c5fc55f70726457f4756bmridge};
81cd30c339dae692a3eb5c5fc55f70726457f4756bmridge
82cd30c339dae692a3eb5c5fc55f70726457f4756bmridge/*
83cd30c339dae692a3eb5c5fc55f70726457f4756bmridge * Function: usage()
842c28215423293e443469a07ae7011135d058b671Garrett Cooper *
85cd30c339dae692a3eb5c5fc55f70726457f4756bmridge * Descripton:
86cd30c339dae692a3eb5c5fc55f70726457f4756bmridge *  Print the usage of this program. Then, terminate this program with
87cd30c339dae692a3eb5c5fc55f70726457f4756bmridge *  the specified exit value.
88cd30c339dae692a3eb5c5fc55f70726457f4756bmridge *
89cd30c339dae692a3eb5c5fc55f70726457f4756bmridge * Argument:
90cd30c339dae692a3eb5c5fc55f70726457f4756bmridge *  exit_value:	exit value
91cd30c339dae692a3eb5c5fc55f70726457f4756bmridge *
92cd30c339dae692a3eb5c5fc55f70726457f4756bmridge * Return value:
93cd30c339dae692a3eb5c5fc55f70726457f4756bmridge *  This function does not return.
94cd30c339dae692a3eb5c5fc55f70726457f4756bmridge */
95354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gaovoid usage(char *program_name, int exit_value)
96cd30c339dae692a3eb5c5fc55f70726457f4756bmridge{
97354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	FILE *stream = stdout;	/* stream where the usage is output */
98354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
99354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (exit_value == EXIT_FAILURE)
100354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		stream = stderr;
101354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
102354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	fprintf(stream, "%s [OPTION]\n"
103354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		"\t-f\tprotocol family\n"
104354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		"\t\t  4 : IPv4\n"
105354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		"\t\t  6 : IPv6\n"
106354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		"\t-p\tport number\n"
107354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		"\t-b\twork in the background\n"
108354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		"\t-c\twork in the concurrent server mode\n"
109354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		"\t-s\twork in the small sending mode\n"
110354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		"\t-w\twork in the window scaling mode\n"
111354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		"\t-o\tfilename where the server infomation is outputted\n"
112354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		"\t-d\twork in the debug mode\n"
113354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		"\t-h\tdisplay this usage\n"
114354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		"" "*) Server works till it receives SIGHUP\n", program_name);
115354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	exit(exit_value);
116cd30c339dae692a3eb5c5fc55f70726457f4756bmridge}
117cd30c339dae692a3eb5c5fc55f70726457f4756bmridge
118cd30c339dae692a3eb5c5fc55f70726457f4756bmridge/*
119cd30c339dae692a3eb5c5fc55f70726457f4756bmridge * Function: set_signal_flag()
120cd30c339dae692a3eb5c5fc55f70726457f4756bmridge *
121cd30c339dae692a3eb5c5fc55f70726457f4756bmridge * Description:
122cd30c339dae692a3eb5c5fc55f70726457f4756bmridge *  This function sets global variable according to the signal.
123cd30c339dae692a3eb5c5fc55f70726457f4756bmridge *  Once a signal is caught, the signal is ignored after that.
124cd30c339dae692a3eb5c5fc55f70726457f4756bmridge *
125cd30c339dae692a3eb5c5fc55f70726457f4756bmridge * Argument:
126cd30c339dae692a3eb5c5fc55f70726457f4756bmridge *  type: type of signal
127cd30c339dae692a3eb5c5fc55f70726457f4756bmridge *
128cd30c339dae692a3eb5c5fc55f70726457f4756bmridge * Return value:
129cd30c339dae692a3eb5c5fc55f70726457f4756bmridge *  None
130cd30c339dae692a3eb5c5fc55f70726457f4756bmridge */
131354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gaovoid set_signal_flag(int type)
132cd30c339dae692a3eb5c5fc55f70726457f4756bmridge{
133354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	/* Set SIG_IGN against the caught signal */
134354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	handler.sa_handler = SIG_IGN;
135354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (sigaction(type, &handler, NULL) < 0)
136354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		fatal_error("sigaction()");
137cd30c339dae692a3eb5c5fc55f70726457f4756bmridge
138354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (debug)
139354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		fprintf(stderr, "Catch signal. type is %d\n", type);
140cd30c339dae692a3eb5c5fc55f70726457f4756bmridge
141354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	switch (type) {
142cd30c339dae692a3eb5c5fc55f70726457f4756bmridge	case SIGHUP:
143354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		catch_sighup = 1;
144354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		break;
145cd30c339dae692a3eb5c5fc55f70726457f4756bmridge	case SIGPIPE:
146354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		catch_sigpipe = 1;
147354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		break;
148cd30c339dae692a3eb5c5fc55f70726457f4756bmridge	default:
149354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		fprintf(stderr, "Unexpected signal (%d) is caught\n", type);
150354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		exit(EXIT_FAILURE);
151354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	}
152cd30c339dae692a3eb5c5fc55f70726457f4756bmridge}
153cd30c339dae692a3eb5c5fc55f70726457f4756bmridge
154cd30c339dae692a3eb5c5fc55f70726457f4756bmridge/*
155cd30c339dae692a3eb5c5fc55f70726457f4756bmridge * Function: delete_zombies()
1562c28215423293e443469a07ae7011135d058b671Garrett Cooper *
157cd30c339dae692a3eb5c5fc55f70726457f4756bmridge * Descripton:
158cd30c339dae692a3eb5c5fc55f70726457f4756bmridge *  Delete the zombies
159cd30c339dae692a3eb5c5fc55f70726457f4756bmridge *
160cd30c339dae692a3eb5c5fc55f70726457f4756bmridge * Argument:
161cd30c339dae692a3eb5c5fc55f70726457f4756bmridge *  info_p:	pointer to a server infomation
162cd30c339dae692a3eb5c5fc55f70726457f4756bmridge *
163cd30c339dae692a3eb5c5fc55f70726457f4756bmridge * Return value:
164cd30c339dae692a3eb5c5fc55f70726457f4756bmridge *  None
165cd30c339dae692a3eb5c5fc55f70726457f4756bmridge */
166354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gaovoid delete_zombies(struct server_info *info_p)
167cd30c339dae692a3eb5c5fc55f70726457f4756bmridge{
168354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	int status;		/* exit value of a child */
169354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	pid_t zombie_pid;	/* process id of a zombie */
170354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
171354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	while (info_p->current_connection) {
172354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		zombie_pid = waitpid((pid_t) - 1, &status, WNOHANG);
173354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		if (zombie_pid == (pid_t) - 1)
174354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			fatal_error("waitpid()");
175354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		else if (zombie_pid == (pid_t) 0)
176354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			break;
177354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		else {
178354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			--info_p->current_connection;
179354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			if (status != EXIT_SUCCESS) {
180354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				++info_p->lost_connection;
181354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				if (debug)
182354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao					fprintf(stderr,
183354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao						"The number of lost conncections is %zu\n",
184354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao						info_p->lost_connection);
185354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			}
186354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		}
187cd30c339dae692a3eb5c5fc55f70726457f4756bmridge	}
188cd30c339dae692a3eb5c5fc55f70726457f4756bmridge}
189cd30c339dae692a3eb5c5fc55f70726457f4756bmridge
190cd30c339dae692a3eb5c5fc55f70726457f4756bmridge/*
191cd30c339dae692a3eb5c5fc55f70726457f4756bmridge * Function: create_listen_socket()
1922c28215423293e443469a07ae7011135d058b671Garrett Cooper *
193cd30c339dae692a3eb5c5fc55f70726457f4756bmridge * Descripton:
194cd30c339dae692a3eb5c5fc55f70726457f4756bmridge *  Create a socket to listen for connections on a socket.
195cd30c339dae692a3eb5c5fc55f70726457f4756bmridge *  The socket discripter is stored info_p->listen_sd.
196cd30c339dae692a3eb5c5fc55f70726457f4756bmridge *
197cd30c339dae692a3eb5c5fc55f70726457f4756bmridge * Argument:
198cd30c339dae692a3eb5c5fc55f70726457f4756bmridge *  info_p:	pointer to a server infomation
199cd30c339dae692a3eb5c5fc55f70726457f4756bmridge *
200cd30c339dae692a3eb5c5fc55f70726457f4756bmridge * Return value:
201cd30c339dae692a3eb5c5fc55f70726457f4756bmridge *  None
202cd30c339dae692a3eb5c5fc55f70726457f4756bmridge */
203354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gaovoid create_listen_socket(struct server_info *info_p)
204cd30c339dae692a3eb5c5fc55f70726457f4756bmridge{
205354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	int on;			/* on/off at an socket option */
206354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	int err;		/* return value of getaddrinfo */
207354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	struct addrinfo hints;	/* hints for getaddrinfo() */
208354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	struct addrinfo *res;	/* pointer to addrinfo */
209354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
210354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	/* Set the hints to addrinfo() */
211354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	memset(&hints, '\0', sizeof(struct addrinfo));
212354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	hints.ai_family = info_p->family;
213354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	hints.ai_socktype = SOCK_STREAM;
214354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	hints.ai_protocol = IPPROTO_TCP;
215354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	hints.ai_flags = AI_PASSIVE;
216354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
217354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	/* Translate the network and service information of the server */
218354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	err = getaddrinfo(NULL, info_p->portnum, &hints, &res);
219354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (err) {
220354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		fprintf(stderr, "getaddrinfo(): %s\n", gai_strerror(err));
221354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		exit(EXIT_FAILURE);
222354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	}
223354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (res->ai_next) {
224354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		fprintf(stderr, "getaddrinfo(): multiple address is found.");
225354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		exit(EXIT_FAILURE);
226354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	}
227354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
228354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	/* Create a socket for listening. */
229354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	info_p->listen_sd = socket(res->ai_family,
230354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				   res->ai_socktype, res->ai_protocol);
231354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (info_p->listen_sd < 0)
232354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		fatal_error("socket()");
233cd30c339dae692a3eb5c5fc55f70726457f4756bmridge
234cd30c339dae692a3eb5c5fc55f70726457f4756bmridge#ifdef IPV6_V6ONLY
235354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	/* Don't accept IPv4 mapped address if the protocol family is IPv6 */
236354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (res->ai_family == PF_INET6) {
237354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		on = 1;
238354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		if (setsockopt(info_p->listen_sd,
239354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			       IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(int)))
240354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			fatal_error("setsockopt()");
241354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	}
242cd30c339dae692a3eb5c5fc55f70726457f4756bmridge#endif
243cd30c339dae692a3eb5c5fc55f70726457f4756bmridge
244354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	/* Enable to reuse the socket */
245cd30c339dae692a3eb5c5fc55f70726457f4756bmridge	on = 1;
246cd30c339dae692a3eb5c5fc55f70726457f4756bmridge	if (setsockopt(info_p->listen_sd,
247354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		       SOL_SOCKET, SO_REUSEADDR, &on, sizeof(int)))
248354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		fatal_error("setsockopt()");
249354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
250354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	/* Disable the Nagle algorithm, when small sending mode */
251354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (info_p->small_sending) {
252354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		on = 1;
253354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		if (setsockopt(info_p->listen_sd,
254354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			       IPPROTO_TCP, TCP_NODELAY, &on, sizeof(int)))
255354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			fatal_error("setsockopt()");
256354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		if (debug) {
257354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			fprintf(stderr, "small sending[on]\n");
258354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		}
259cd30c339dae692a3eb5c5fc55f70726457f4756bmridge	}
260cd30c339dae692a3eb5c5fc55f70726457f4756bmridge
261354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	/* Maximize socket buffer, when window scaling mode */
262354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (info_p->window_scaling)
263354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		maximize_sockbuf(info_p->listen_sd);
264cd30c339dae692a3eb5c5fc55f70726457f4756bmridge
265354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	/* Bind to the local address */
266354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (bind(info_p->listen_sd, res->ai_addr, res->ai_addrlen) < 0)
267354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		fatal_error("bind()");
268354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	freeaddrinfo(res);
269cd30c339dae692a3eb5c5fc55f70726457f4756bmridge
270354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	/* Start to listen for connections */
271354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (listen(info_p->listen_sd, 5) < 0)
272354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		fatal_error("listen()");
273cd30c339dae692a3eb5c5fc55f70726457f4756bmridge}
274cd30c339dae692a3eb5c5fc55f70726457f4756bmridge
275cd30c339dae692a3eb5c5fc55f70726457f4756bmridge/*
276cd30c339dae692a3eb5c5fc55f70726457f4756bmridge * Function: communicate_client()
2772c28215423293e443469a07ae7011135d058b671Garrett Cooper *
278cd30c339dae692a3eb5c5fc55f70726457f4756bmridge * Descripton:
279cd30c339dae692a3eb5c5fc55f70726457f4756bmridge *  Communicate with the connectted client.
280cd30c339dae692a3eb5c5fc55f70726457f4756bmridge *  Currently, this function sends tcp segment in the specified second
281cd30c339dae692a3eb5c5fc55f70726457f4756bmridge *  or recevie SIGHUP
282cd30c339dae692a3eb5c5fc55f70726457f4756bmridge *
283cd30c339dae692a3eb5c5fc55f70726457f4756bmridge * Argument:
284cd30c339dae692a3eb5c5fc55f70726457f4756bmridge *  sock_fd: socket descriptor to communicate with client
285cd30c339dae692a3eb5c5fc55f70726457f4756bmridge *  info_p:  pointer to a server infomation
286cd30c339dae692a3eb5c5fc55f70726457f4756bmridge *
287cd30c339dae692a3eb5c5fc55f70726457f4756bmridge * Return value:
288cd30c339dae692a3eb5c5fc55f70726457f4756bmridge *  0:	    success
289cd30c339dae692a3eb5c5fc55f70726457f4756bmridge *  other:  fail
290cd30c339dae692a3eb5c5fc55f70726457f4756bmridge */
291354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gaoint communicate_client(struct server_info *info_p, int sock_fd)
292cd30c339dae692a3eb5c5fc55f70726457f4756bmridge{
293354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	char *sendmsg;		/* pointer to the message to send */
294354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	int sndbuf_size;	/* size of the send buffer */
295354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	socklen_t sock_optlen;	/* size of the result parameter */
296354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	ssize_t sntbyte_size;	/* size of the sent byte */
297354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	int ret = EXIT_SUCCESS;	/* The return value of this function */
298354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
299354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (info_p->small_sending) {	/* small sending mode */
300354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		sndbuf_size = 1;
301354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	} else {
302354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		sock_optlen = sizeof(sndbuf_size);
303354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		if (getsockopt
304354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		    (sock_fd, SOL_SOCKET, SO_SNDBUF, &sndbuf_size,
305354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		     &sock_optlen) < 0) {
306354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			perror("getsockopt()");
307354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			if (close(sock_fd))
308354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				fatal_error("close()");
309354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			return EXIT_FAILURE;
310354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		}
311cd30c339dae692a3eb5c5fc55f70726457f4756bmridge	}
312354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (debug)
313354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		fprintf(stderr, "sndbuf size is %d\n", sndbuf_size);
314354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
315354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	/* Define the message */
316d218f348c12b42a78fa0306d9a033bfa4f67238bCyril Hrubis	sendmsg = malloc(sndbuf_size);
317354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (sendmsg == NULL) {
318354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		fprintf(stderr, "malloc() is failed.\n");
319354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		if (close(sock_fd))
320354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			fatal_error("close()");
321354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		return EXIT_FAILURE;
322cd30c339dae692a3eb5c5fc55f70726457f4756bmridge	}
323cd30c339dae692a3eb5c5fc55f70726457f4756bmridge
324354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	/* Set a signal handler against SIGHUP and SIGPIPE */
325354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	handler.sa_handler = set_signal_flag;
326354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (sigaction(SIGHUP, &handler, NULL) < 0)
327354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		fatal_error("sigaction()");
328354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (sigaction(SIGPIPE, &handler, NULL) < 0)
329354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		fatal_error("sigaction()");
330354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
331354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	/* Send the message */
332354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	for (;;) {
333354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		sntbyte_size = send(sock_fd, sendmsg, sndbuf_size, 0);
334354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
335354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		/* Catch SIGPIPE */
336354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		if (catch_sigpipe) {
337354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			if (debug)
338354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				fprintf(stderr,
339354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao					"The client closed the connection.\n");
340354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			break;
341354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		}
342354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
343354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		/* Catch SIGHUP */
344354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		if (catch_sighup)
345354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			break;
346354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
347354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		if (sntbyte_size < (ssize_t) 0) {
348354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			if (errno == EPIPE) {
349354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				if (debug)
350354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao					fprintf(stderr,
351354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao						"The client closed the connection.\n");
352354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			} else {
353354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				printf("errno=%d\n", errno);
354354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				perror("send()");
355354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				ret = EXIT_FAILURE;
356354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			}
357354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			break;
358354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		}
359cd30c339dae692a3eb5c5fc55f70726457f4756bmridge	}
360cd30c339dae692a3eb5c5fc55f70726457f4756bmridge
361354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	free(sendmsg);
362354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (close(sock_fd))
363354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		fatal_error("close()");
364354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	return ret;
365cd30c339dae692a3eb5c5fc55f70726457f4756bmridge}
366cd30c339dae692a3eb5c5fc55f70726457f4756bmridge
367cd30c339dae692a3eb5c5fc55f70726457f4756bmridge/*
368cd30c339dae692a3eb5c5fc55f70726457f4756bmridge * Function: handle_client()
3692c28215423293e443469a07ae7011135d058b671Garrett Cooper *
370cd30c339dae692a3eb5c5fc55f70726457f4756bmridge * Descripton:
371cd30c339dae692a3eb5c5fc55f70726457f4756bmridge *  Accept a connection from a client, then fork to communicate the client
372cd30c339dae692a3eb5c5fc55f70726457f4756bmridge *
373cd30c339dae692a3eb5c5fc55f70726457f4756bmridge * Argument:
374cd30c339dae692a3eb5c5fc55f70726457f4756bmridge *  info_p:	pointer to a server infomation
375cd30c339dae692a3eb5c5fc55f70726457f4756bmridge *
376cd30c339dae692a3eb5c5fc55f70726457f4756bmridge * Return value:
377cd30c339dae692a3eb5c5fc55f70726457f4756bmridge *  0:	    success
378cd30c339dae692a3eb5c5fc55f70726457f4756bmridge *  other:  fail
379cd30c339dae692a3eb5c5fc55f70726457f4756bmridge */
380354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gaoint handle_client(struct server_info *info_p)
381cd30c339dae692a3eb5c5fc55f70726457f4756bmridge{
382354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	int ret = EXIT_SUCCESS;	/* return value of this function */
383354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	int do_accept = 1;	/* if non-zero, accept connection */
384354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	fd_set read_fds;	/* list of file descriptor for reading */
385354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	int max_read_fd = 0;	/* maximum number in the read fds */
386354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
387354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	info_p->current_connection = 0;
388354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	FD_ZERO(&read_fds);
389354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	FD_SET(info_p->listen_sd, &read_fds);
390354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	max_read_fd = info_p->listen_sd;
391354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
392354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	/* Catch SIGHUP */
393354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	handler.sa_handler = set_signal_flag;
394354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (sigaction(SIGHUP, &handler, NULL) < 0)
395354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		fatal_error("sigaction()");
396354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
397354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	/* Loop to wait a new connection */
398354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	for (;;) {
399354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		if (do_accept) {
400354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			int data_sd;	/* socket descriptor for send/recv data */
401354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			socklen_t client_addr_len;	/* length of `client_addr' */
402354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			struct sockaddr_storage client_addr;	/* address of a client */
403354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			int select_ret;	/* return value of select() */
404354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			fd_set active_fds;	/* list of the active file descriptor */
405354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			struct timeval select_timeout;	/* timeout for select() */
406354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
407354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			/* When catch SIGHUP, no more connection is acceptted. */
408354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			if (catch_sighup) {
409354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				do_accept = 0;
410354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				if (close(info_p->listen_sd))
411354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao					fatal_error("close()");
412354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				continue;
413cd30c339dae692a3eb5c5fc55f70726457f4756bmridge			}
414354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
415354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			/* Check a connection is requested */
416354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			active_fds = read_fds;
417354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			select_timeout.tv_sec = 0;	/* 0.5 sec */
418354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			select_timeout.tv_usec = 500000;
419354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
420354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			select_ret = select(max_read_fd + 1,
421354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao					    &active_fds, NULL, NULL,
422354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao					    &select_timeout);
423354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			if (select_ret < 0) {
424354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				do_accept = 0;
425354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				if (!catch_sighup) {
426354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao					perror("select()");
427354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao					ret = EXIT_FAILURE;
428354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				}
429354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				if (close(info_p->listen_sd))
430354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao					fatal_error("close()");
431354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				continue;
432354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			} else if (select_ret == 0) {	/* select() is timeout */
433354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				if (info_p->concurrent)
434354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao					delete_zombies(info_p);
435354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				continue;
436354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			}
437354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
438354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			/* Accetpt a client connection */
439354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			if (FD_ISSET(info_p->listen_sd, &active_fds)) {
440354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				client_addr_len =
441354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				    sizeof(struct sockaddr_storage);
442354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				data_sd =
443354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				    accept(info_p->listen_sd,
444354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao					   (struct sockaddr *)&client_addr,
445354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao					   &client_addr_len);
446354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				if (data_sd < 0) {
447354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao					do_accept = 0;
448354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao					if (!catch_sighup) {
449354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao						perror("accept()");
450354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao						ret = EXIT_FAILURE;
451354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao					}
452354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao					if (close(info_p->listen_sd))
453354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao						fatal_error("close()");
454354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao					continue;
455354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				}
456354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				if (debug)
457354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao					fprintf(stderr,
458354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao						"called accept(). data_sd=%d\n",
459354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao						data_sd);
460354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
461354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				/* Handle clients */
462354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				if (info_p->concurrent) {	/* concurrent server. */
463354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao					pid_t child_pid;
464354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao					child_pid = fork();
465354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao					if (child_pid < 0) {	/* fork() is failed. */
466354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao						perror("fork()");
467354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao						if (close(data_sd))
468354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao							fatal_error("close()");
469354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao						if (close(info_p->listen_sd))
470354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao							fatal_error("close()");
471354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao						do_accept = 0;
472354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao						continue;
473354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao					} else if (child_pid == 0) {	/* case of a child */
474354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao						int exit_value;
475354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao						if (close(info_p->listen_sd))
476354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao							fatal_error("close()");
477354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao						exit_value =
478354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao						    communicate_client(info_p,
479354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao								       data_sd);
480354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao						if (debug)
481354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao							fprintf(stderr,
482354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao								"child(%d) exits. value is %d\n",
483354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao								getpid(),
484354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao								exit_value);
485354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao						exit(exit_value);
486354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao					} else {	/* case of the parent */
487354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao						if (close(data_sd))
488354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao							fatal_error("close()");
489354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
490354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao						++info_p->current_connection;
491354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao						if (info_p->max_connection <
492354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao						    info_p->
493354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao						    current_connection) {
494354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao							info_p->max_connection =
495354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao							    info_p->
496354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao							    current_connection;
497354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao							if (debug)
498354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao								fprintf(stderr,
499354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao									"The maximum connection is updated. The number is %zu.\n",
500354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao									info_p->
501354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao									max_connection);
502354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao						}
503354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao						delete_zombies(info_p);
504354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao					}
505354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				} else {	/* repeat server */
506354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao					ret =
507354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao					    communicate_client(info_p, data_sd);
508354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao					if (ret != EXIT_SUCCESS)
509354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao						if (close(info_p->listen_sd))
510354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao							fatal_error("close()");
511354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao					break;
512354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				}
513354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			}
514354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		} else {
515354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			/* case where new connection isn't accepted. */
516354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			if (info_p->concurrent)
517354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				delete_zombies(info_p);
518354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			if (info_p->current_connection == 0)
519354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				break;
520cd30c339dae692a3eb5c5fc55f70726457f4756bmridge		}
521cd30c339dae692a3eb5c5fc55f70726457f4756bmridge	}
522354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	return ret;
523cd30c339dae692a3eb5c5fc55f70726457f4756bmridge}
524cd30c339dae692a3eb5c5fc55f70726457f4756bmridge
525cd30c339dae692a3eb5c5fc55f70726457f4756bmridge/*
526cd30c339dae692a3eb5c5fc55f70726457f4756bmridge *
527cd30c339dae692a3eb5c5fc55f70726457f4756bmridge *  Function: main()
528cd30c339dae692a3eb5c5fc55f70726457f4756bmridge *
529cd30c339dae692a3eb5c5fc55f70726457f4756bmridge */
530354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gaoint main(int argc, char *argv[])
531cd30c339dae692a3eb5c5fc55f70726457f4756bmridge{
532354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	char *program_name = argv[0];
533354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	int optc;		/* option */
534354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	struct server_info server;	/* server information */
535354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	int ret = EXIT_SUCCESS;	/* exit value */
536354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	int background = 0;	/* If non-zero work in the background */
537354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	FILE *info_fp = stdout;	/* FILE pointer to a information file */
538354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
539354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	debug = 0;
540354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
541354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	/* Initilalize the server information */
542354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	memset(&server, '\0', sizeof(struct server_info));
543354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	server.family = PF_UNSPEC;
544354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	server.portnum = NULL;
545354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
546354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	/* Retrieve the options */
547354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	while ((optc = getopt(argc, argv, "f:p:bcswo:dh")) != EOF) {
548354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		switch (optc) {
549354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		case 'f':
550354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			if (strncmp(optarg, "4", 1) == 0)
551354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				server.family = PF_INET;	/* IPv4 */
552354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			else if (strncmp(optarg, "6", 1) == 0)
553354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				server.family = PF_INET6;	/* IPv6 */
554354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			else {
555354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				fprintf(stderr,
556354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao					"protocol family should be 4 or 6.\n");
557354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				usage(program_name, EXIT_FAILURE);
558354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			}
559354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			break;
560354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
561354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		case 'p':
562354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			{
563354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				unsigned long int num;
564354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				num = strtoul(optarg, NULL, 0);
565354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				if (num < PORTNUMMIN || PORTNUMMAX < num) {
566354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao					fprintf(stderr,
567354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao						"The range of port is from %u to %u\n",
568354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao						PORTNUMMIN, PORTNUMMAX);
569354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao					usage(program_name, EXIT_FAILURE);
570354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				}
571354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				server.portnum = strdup(optarg);
572354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			}
573354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			break;
574cd30c339dae692a3eb5c5fc55f70726457f4756bmridge
575354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		case 'b':
576354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			background = 1;
577354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			break;
578cd30c339dae692a3eb5c5fc55f70726457f4756bmridge
579354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		case 'c':
580354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			server.concurrent = 1;
581354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			break;
582cd30c339dae692a3eb5c5fc55f70726457f4756bmridge
583354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		case 's':
584354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			server.small_sending = 1;
585354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			break;
586cd30c339dae692a3eb5c5fc55f70726457f4756bmridge
587354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		case 'w':
588354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			server.window_scaling = 1;
589354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			break;
590cd30c339dae692a3eb5c5fc55f70726457f4756bmridge
591354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		case 'o':
592354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			if ((info_fp = fopen(optarg, "w")) == NULL) {
593354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				fprintf(stderr, "Cannot open %s\n", optarg);
594354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				exit(EXIT_FAILURE);
595354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			}
596354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			break;
597cd30c339dae692a3eb5c5fc55f70726457f4756bmridge
598354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		case 'd':
599354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			debug = 1;
600354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			break;
601cd30c339dae692a3eb5c5fc55f70726457f4756bmridge
602354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		case 'h':
603354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			usage(program_name, EXIT_SUCCESS);
604354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			break;
605cd30c339dae692a3eb5c5fc55f70726457f4756bmridge
606354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		default:
607354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			usage(program_name, EXIT_FAILURE);
608354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		}
609354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	}
610cd30c339dae692a3eb5c5fc55f70726457f4756bmridge
611354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	/* Check the family is spefied. */
612354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (server.family == PF_UNSPEC) {
613354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		fprintf(stderr, "protocol family should be specified.\n");
614cd30c339dae692a3eb5c5fc55f70726457f4756bmridge		usage(program_name, EXIT_FAILURE);
615cd30c339dae692a3eb5c5fc55f70726457f4756bmridge	}
616354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
617354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	/* Check the port number is specfied. */
618354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (server.portnum == NULL) {
619354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		server.portnum = (char *)calloc(6, sizeof(char));
620354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		sprintf(server.portnum, "%u", PORTNUMMIN);
621354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	}
622354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
623354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	/* If -b option is specified, work as a daemon */
624354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (background)
625354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		if (daemon(0, 0) < 0)
626354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			fatal_error("daemon()");
627354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
628354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	/* At first, SIGHUP is ignored. default with SIGPIPE */
629354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	handler.sa_handler = SIG_IGN;
630354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (sigfillset(&handler.sa_mask) < 0)
631354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		fatal_error("sigfillset()");
632354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	handler.sa_flags = 0;
633354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
634354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (sigaction(SIGHUP, &handler, NULL) < 0)
635354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		fatal_error("sigaction()");
636354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
637354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	/* Create a listen socket */
638354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	create_listen_socket(&server);
639354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
640354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	/* Output any server information to the information file */
641354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	fprintf(info_fp, "PID: %u\n", getpid());
642354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	fflush(info_fp);
643354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (info_fp != stdout)
644354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		if (fclose(info_fp))
645354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			fatal_error("fclose()");
646354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
647354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	/* Handle one or more tcp clients. */
648354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	ret = handle_client(&server);
649354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	exit(ret);
650ec6edca7aa42b6affd989ef91b5897f96795e40fChris Dearman}
651