3 * Copyright (C) 2003 Simone Piccardi
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or (at
8 * your option) any later version.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 /****************************************************************
21 * Program select_echod
22 * Elementary TCP server for echo service (port 7) using select
24 * Author: Simone Piccardi
27 * Usage: echod -h give all info
29 * $Id: select_echod.c,v 1.1 2003/12/25 17:31:09 piccardi Exp $
31 ****************************************************************/
33 * Include needed headers
35 #include <sys/types.h> /* predefined types */
36 #include <unistd.h> /* include unix standard library */
37 #include <arpa/inet.h> /* IP addresses conversion utiliites */
38 #include <sys/socket.h> /* socket library */
39 #include <stdio.h> /* include standard I/O library */
41 #include <syslog.h> /* syslog system functions */
42 #include <signal.h> /* signal functions */
43 #include <errno.h> /* error code */
44 #include <string.h> /* error strings */
51 int demonize = 1; /* daemon use option: default is daemon */
52 int debugging = 0; /* debug info printing option: default is no debug */
53 /* Subroutines declaration */
55 void PrintErr(char * error);
56 /* Program beginning */
57 int main(int argc, char *argv[])
60 * Variables definition
64 struct sockaddr_in serv_add, cli_add;
67 char fd_open[FD_SETSIZE];
70 int max_fd, nread, nwrite;
73 * Input section: decode parameters passed in the calling
76 opterr = 0; /* don't want writing to stderr */
77 while ( (i = getopt(argc, argv, "hdicw:")) != -1) {
83 printf("Wrong -h option use\n");
97 waiting = strtol(optarg, NULL, 10);
99 case '?': /* unrecognized options */
100 printf("Unrecognized options -%c\n",optopt);
102 default: /* should not reached */
106 /* ***********************************************************
108 * Options processing completed
110 * Main code beginning
112 * ***********************************************************/
113 /* Main code begin here */
114 if (compat) { /* install signal handler */
115 Signal(SIGCHLD, HandSigCHLD); /* non restarting handler */
117 SignalRestart(SIGCHLD, HandSigCHLD); /* restarting handler */
120 if ( (list_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
121 perror("Socket creation error");
124 /* initialize address */
125 memset((void *)&serv_add, 0, sizeof(serv_add)); /* clear server address */
126 serv_add.sin_family = AF_INET; /* address type is INET */
127 serv_add.sin_port = htons(7); /* echo port is 7 */
128 serv_add.sin_addr.s_addr = htonl(INADDR_ANY); /* connect from anywhere */
130 if (bind(list_fd, (struct sockaddr *)&serv_add, sizeof(serv_add)) < 0) {
131 perror("bind error");
134 /* release privileges and go daemon */
135 if (setgid(65534) !=0) { /* first give away group privileges */
136 perror("cannot give away group privileges");
139 if (setuid(65534) !=0) { /* and only after user ... */
140 perror("cannot give away user privileges");
143 if (demonize) { /* go daemon */
144 openlog(argv[0], 0, LOG_DAEMON); /* open logging */
145 if (daemon(0, 0) != 0) {
146 perror("cannot start as daemon");
151 if (listen(list_fd, BACKLOG) < 0 ) {
152 PrintErr("listen error");
155 if (waiting) sleep(waiting);
156 /* initialize all needed variables */
157 memset(fd_open, 0, FD_SETSIZE); /* clear array of open files */
158 max_fd = list_fd; /* set maximum fd to look */
160 /* main loop, wait for connection and data inside a select */
162 FD_ZERO(&fset); /* clear fd_set */
163 for (i = list_fd; i <= max_fd; i++) {
164 if (fd_open[i]) FD_SET(i, &fset); /* initialize open sockets */
166 while ( ((n = select(max_fd + 1, &fset, NULL, NULL, NULL)) < 0)
167 && (errno == EINTR));
170 PrintErr("select error");
173 if (FD_ISSET(list_fd, &fset)) { /* if data on listening socket */
174 len = sizeof(cli_add);
175 fd = accept(list_fd, (struct sockaddr *)&cli_add, &len);
177 PrintErr("accept error");
181 if (max_fd < fd) max_fd = fd;
185 for (i = list_fd + 1; i <= max_fd; i++) {
186 if (fd_open[i] == 0) continue;
187 if (FD_ISSET(i, &fset)) {
189 nread = read(fd, buffer, MAXLINE);
191 PrintErr("Errore in lettura");
197 while (fd_open[i] == 0) {
205 nwrite = FullWrite(fd, buffer, nread);
207 PrintErr("Errore in scrittura");
213 PrintErr("Errore nella gestione dei file descriptor");
216 /* normal exit, never reached */
220 * routine to print usage info and exit
223 printf("Elementary echo server\n");
225 printf(" echod [-h] \n");
226 printf(" -h print this help\n");
227 printf(" -d write debug info\n");
228 printf(" -i use interactively\n");
229 printf(" -c disable BSD semantics\n");
230 printf(" -w N wait N sec. before calling accept\n");
234 * routine to print error on stout or syslog
236 void PrintErr(char * error) {
237 if (demonize) { /* daemon mode */
238 syslog(LOG_ERR, "%s: %m", error); /* log string and error message */