Risistemato tutto il primo esempio di server echo e le funzioni FullWrite e
[gapil.git] / sources / TCP_echod.c
1 /* TCP_echod.c
2  * 
3  * Copyright (C) 2001-2003 Simone Piccardi
4  * 
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.
9  * 
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.
14  * 
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.
18  */
19 /****************************************************************
20  *
21  * Program echod 
22  * Elementary TCP server for echo service (port 7)
23  *
24  * Author: Simone Piccardi
25  * Jun. 2001
26  *
27  * Usage: echod -h give all info
28  *
29  * $Id: TCP_echod.c,v 1.9 2003/07/27 23:41:04 piccardi Exp $ 
30  *
31  ****************************************************************/
32 /* 
33  * Include needed headers
34  */
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 */
40 #include <time.h>
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 */
45 #include "Gapil.h"
46
47 #define BACKLOG 10
48 #define MAXLINE 256
49 int demonize  = 1;  /* daemon use option: default is daemon */
50 int debugging = 0;  /* debug info printing option: default is no debug */
51 /* Subroutines declaration */
52 void usage(void);
53 void ServEcho(int sockfd);
54 void PrintErr(char * error);
55 /* Program beginning */
56 int main(int argc, char *argv[])
57 {
58 /* 
59  * Variables definition  
60  */
61     int list_fd, conn_fd;
62     int waiting = 0;
63     pid_t pid;
64     struct sockaddr_in serv_add, cli_add;
65     socklen_t len;
66     char debug[MAXLINE], ipaddr[20];
67     /*
68      * Input section: decode parameters passed in the calling 
69      * Use getopt function
70      */
71     int i;
72     opterr = 0;  /* don't want writing to stderr */
73     while ( (i = getopt(argc, argv, "hdiw:")) != -1) {
74         switch (i) {
75         /* 
76          * Handling options 
77          */ 
78         case 'h':  
79             printf("Wrong -h option use\n");
80             usage();
81             return(0);
82             break;
83         case 'i':
84             demonize = 0;
85             break;
86         case 'd':
87             debugging = 1;
88             break;
89         case 'w':
90             waiting = strtol(optarg, NULL, 10);
91             break;
92         case '?':   /* unrecognized options */
93             printf("Unrecognized options -%c\n",optopt);
94             usage();
95         default:    /* should not reached */
96             usage();
97         }
98     }
99     /* ***********************************************************
100      * 
101      *           Options processing completed
102      *
103      *                Main code beginning
104      * 
105      * ***********************************************************/
106     /* install SIGCHLD handler */
107     Signal(SIGCHLD, HandSigCHLD);  /* establish handler */
108     /* create socket */
109     if ( (list_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
110         perror("Socket creation error");
111         exit(1);
112     }
113     /* initialize address */
114     memset((void *)&serv_add, 0, sizeof(serv_add)); /* clear server address */
115     serv_add.sin_family = AF_INET;                  /* address type is INET */
116     serv_add.sin_port = htons(7);                   /* echo port is 7 */
117     serv_add.sin_addr.s_addr = htonl(INADDR_ANY);   /* connect from anywhere */
118     /* bind socket */
119     if (bind(list_fd, (struct sockaddr *)&serv_add, sizeof(serv_add)) < 0) {
120         perror("bind error");
121         exit(1);
122     }
123     /* release privileges and go daemon */
124     if (setgid(65534) !=0) { /* first give away group privileges */
125         perror("cannot give away group privileges");
126         exit(1);
127     }
128     if (setuid(65534) !=0) { /* and only after user ... */
129         perror("cannot give away user privileges");
130         exit(1);
131     }
132     if (demonize) {          /* go daemon */
133         openlog(argv[0], 0, LOG_DAEMON); /* open logging */
134         if (daemon(0, 0) != 0) {
135             perror("cannot start as daemon");
136             exit(1);
137         }
138     }
139     /* main body */
140     if (listen(list_fd, BACKLOG) < 0 ) {
141         PrintErr("listen error");
142         exit(1);
143     }
144     if (waiting) sleep(waiting);
145     /* handle echo to client */
146     while (1) {
147         /* accept connection */
148         while (((conn_fd = accept(list_fd, (struct sockaddr *)&cli_add, &len)) 
149                 < 0) && (errno == EINTR)); 
150         if ( conn_fd < 0) {
151             PrintErr("accept error");
152             exit(1);
153         }
154         if (debugging) {
155             inet_ntop(AF_INET, &cli_add.sin_addr, ipaddr, sizeof(ipaddr));
156             snprintf(debug, MAXLINE, "Accepted connection form %s\n", ipaddr);
157             if (demonize) {
158                 syslog(LOG_DEBUG, debug);
159             } else {
160                 printf("%s", debug);
161             }
162         }
163         /* fork to handle connection */
164         if ( (pid = fork()) < 0 ){
165             PrintErr("fork error");
166             exit(1);
167         }
168         if (pid == 0) {      /* child */
169             close(list_fd);          /* close listening socket */   
170             ServEcho(conn_fd);       /* handle echo */
171             exit(0);
172         } else {             /* parent */
173             close(conn_fd);          /* close connected socket */
174         }
175     }
176     /* normal exit, never reached */
177     exit(0);
178 }
179 /*
180  * routine to print usage info and exit
181  */
182 void usage(void) {
183     printf("Elementary echo server\n");
184     printf("Usage:\n");
185     printf("  echod [-h] \n");
186     printf("  -h           print this help\n");
187     printf("  -d           write debug info\n");
188     printf("  -i           use interactively\n");
189     printf("  -w N         wait N sec. before calling accept\n");
190     exit(1);
191 }
192 /*
193  * routine to handle echo for connection
194  */
195 void ServEcho(int sockfd) {
196     char buffer[MAXLINE];
197     int nread, nwrite;
198     char debug[MAXLINE+20];
199     int size;
200     /* main loop, reading 0 char means client close connection */
201     while ( (nread = read(sockfd, buffer, MAXLINE)) != 0) {
202         if (nread < 0) {
203             snprintf(debug, MAXLINE+20, "Errore in lettura: %s \n", 
204                      strerror(errno));
205             if (demonize) {          /* daemon mode */
206                 syslog(LOG_DEBUG, debug);
207             } else {
208                 printf("%s", debug);
209             }
210         }
211         nwrite = FullWrite(sockfd, buffer, nread);
212         if (nwrite) {
213             snprintf(debug, MAXLINE+20, "Errore in scrittura: %s \n", 
214                      strerror(errno));
215             if (demonize) {          /* daemon mode */
216                 syslog(LOG_DEBUG, debug);
217             } else {
218                 printf("%s", debug);
219             }       
220         }
221         if (debugging) {
222             buffer[nread] = 0;
223             snprintf(debug, MAXLINE+20, "Letti %d byte, %s", nread, buffer);
224             if (demonize) {          /* daemon mode */
225                 syslog(LOG_DEBUG, debug);
226             } else {
227                 printf("%s", debug);
228             }
229         }
230     }
231     return;
232 }
233 /*
234  * routine to print error on stout or syslog
235  */
236 void PrintErr(char * error) {
237     if (demonize) {                       /* daemon mode */
238         syslog(LOG_ERR, "%s: %m", error); /* log string and error message */
239     } else {
240         perror(error);
241     }
242     return;
243 }