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