From: Simone Piccardi Date: Tue, 6 May 2003 14:05:12 +0000 (+0000) Subject: Rinominato la prima versione del server. X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=commitdiff_plain;h=3e8003adb1396080659ef5d34896eb2f573be6cd Rinominato la prima versione del server. --- diff --git a/elemtcp.tex b/elemtcp.tex index 766974f..90fcfb9 100644 --- a/elemtcp.tex +++ b/elemtcp.tex @@ -1711,23 +1711,23 @@ illustriamo immediatamente. \subsection{Il server: prima versione} \label{sec:TCPsimp_server_main} -La prima versione del server, contenuta nel file \file{TCP\_echod.c}, è -riportata in \figref{fig:TCP_echo_server_code}. Come abbiamo fatto per il -client anche il server è stato diviso in un corpo principale, costituito dalla -funzione \code{main}, che è molto simile a quello visto nel precedente esempio -per il server del servizio \textit{daytime} di +La prima versione del server, contenuta nel file \file{TCP\_echod_first.c}, è +riportata in \figref{fig:TCP_echo_server_first_code}. Come abbiamo fatto per +il client anche il server è stato diviso in un corpo principale, costituito +dalla funzione \code{main}, che è molto simile a quello visto nel precedente +esempio per il server del servizio \textit{daytime} di \secref{sec:TCP_daytime_cunc_server}, e da una funzione ausiliaria \code{ServEcho} che si cura della gestione del servizio. \begin{figure}[!htbp] \footnotesize \centering \begin{minipage}[c]{15.6cm} - \includecodesample{listati/TCP_echod.c} + \includecodesample{listati/TCP_echod_first.c} \end{minipage} \normalsize \caption{Codice del corpo principale della prima versione del server per il servizio \textit{echo}.} - \label{fig:TCP_echo_server_code} + \label{fig:TCP_echo_server_first_code} \end{figure} In questo caso però, rispetto a quanto visto nell'esempio di @@ -2003,7 +2003,7 @@ dei processi figli terminati gi Basterà allora aggiungere il seguente codice: \includecodesnip{listati/sigchildhand.c} \noindent -all'esempio illustrato in \figref{fig:TCP_echo_server_code}. +all'esempio illustrato in \figref{fig:TCP_echo_server_first_code}. In questo modo però si introduce un altro problema, il fatto che, come spiegato in \secref{sec:sig_gen_beha}, quando un programma si trova in stato @@ -2018,9 +2018,9 @@ ritorner arriva durante l'esecuzione del programma in risposta ad una connessione) con un errore di \errcode{EINTR}, terminando a sua volta con un errore del tipo: \begin{verbatim} - -\end{verbatim} - +[root@gont sources]# ./echod -i +accept error: Interrupted system call +\end{verbatim}%# Come accennato in \secref{sec:sig_gen_beha} questo ci mette di fronte a due @@ -2038,19 +2038,33 @@ definiremo allora la nuova funzione \func{SignalRestart} come mostrato in \end{minipage} \normalsize \caption{La funzione \funcd{SignalRestart}, che installa un gestore di - segnali in semantica BSD.} + segnali in semantica BSD per il riavvio delle system call interrotte.} \label{fig:sig_SignalRestart_code} \end{figure} Come si può notare questa funzione è identica a \func{Signal}, solo che in questo caso invece di inizializzare a zero il campo \var{sa\_flags} di -\struct{sigaction} lo si inizializza (\texttt{\small 5}) al valore -\const{SA\_RESTART}. +\struct{sigaction}, lo si inizializza (\texttt{\small 5}) al valore +\const{SA\_RESTART}. Usando questa funzione al posto di \func{Signal} nel +server non è necessaria nessuna altra modifica: le system call interrotte +saranno automaticamente riavviate, e l'errore \errcode{EINTR} non si +manifesterà più. -Usando questa funzione al posto di \func{Signal} nel server non è necessaria -nessuna altra modifica, le system call interrotte saranno automaticamente -riavviate, e l'errore \errcode{EINTR} non si manifesterà più. +La seconda soluzione è più invasiva e richiede di controllare tutte le volte +l'errore restituito dalle varie system call, ripetendo la chiamata qualora +questo corrisponda ad \errcode{EINTR}, questo comporta una riscrittura +parziale del server secondo quanto mostrato in +\begin{figure}[!htbp] + \footnotesize \centering + \begin{minipage}[c]{15.6cm} + \includecodesample{listati/TCP_echod.c} + \end{minipage} + \normalsize + \caption{Codice del corpo principale della seconda versione del server + per il servizio \textit{echo}.} + \label{fig:TCP_echo_server_code} +\end{figure} \section{I vari scenari critici} diff --git a/listati/TCP_echod_first.c b/listati/TCP_echod_first.c new file mode 100644 index 0000000..81085a7 --- /dev/null +++ b/listati/TCP_echod_first.c @@ -0,0 +1,60 @@ +int main(int argc, char *argv[]) +{ + int list_fd, conn_fd; + pid_t pid; + struct sockaddr_in serv_add; + ... + /* create socket */ + if ( (list_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + perror("Socket creation error"); + exit(1); + } + /* initialize address and bind socket */ + memset((void *)&serv_add, 0, sizeof(serv_add)); /* clear server address */ + serv_add.sin_family = AF_INET; /* address type is INET */ + serv_add.sin_port = htons(7); /* echo port is 7 */ + serv_add.sin_addr.s_addr = htonl(INADDR_ANY); /* connect from anywhere */ + if (bind(list_fd, (struct sockaddr *)&serv_add, sizeof(serv_add)) < 0) { + perror("bind error"); + exit(1); + } + /* give away privileges and go daemon */ + if (setgid(65534) !=0) { /* first give away group privileges */ + perror("cannot give away group privileges"); + exit(1); + } + if (setuid(65534) !=0) { /* and only after user ... */ + perror("cannot give away user privileges"); + exit(1); + } + if (demonize) { /* go daemon */ + openlog(argv[0], 0, LOG_DAEMON); /* open logging */ + if (daemon(0, 0) != 0) { + perror("cannot start as daemon"); + exit(1); + } + } + /* main body */ + if (listen(list_fd, BACKLOG) < 0 ) { /* listen on socket */ + PrintErr("listen error"); + exit(1); + } + while (1) { /* handle echo to client */ + if ( (conn_fd = accept(list_fd, NULL, NULL)) < 0) { + PrintErr("accept error"); + exit(1); + } + if ( (pid = fork()) < 0 ) { /* fork to handle connection */ + PrintErr("fork error"); + exit(1); + } + if (pid == 0) { /* child */ + close(list_fd); /* close listening socket */ + ServEcho(conn_fd); /* handle echo */ + exit(0); + } else { /* parent */ + close(conn_fd); /* close connected socket */ + } + } + exit(0); /* normal exit, never reached */ +} diff --git a/sources/SigHand.c b/sources/SigHand.c index 3fb588a..6112700 100644 --- a/sources/SigHand.c +++ b/sources/SigHand.c @@ -22,7 +22,7 @@ * * Author: S. Piccardi Dec. 2002 * - * $Id: SigHand.c,v 1.6 2003/05/06 11:29:16 piccardi Exp $ + * $Id: SigHand.c,v 1.7 2003/05/06 14:05:12 piccardi Exp $ * *****************************************************************************/ #include /* error simbol definitions */ @@ -97,7 +97,7 @@ inline SigFunc * SignalRestart(int signo, SigFunc *func) * Generic handler for SIGCHLD signal * * Simone Piccardi Dec. 2002 - * $Id: SigHand.c,v 1.6 2003/05/06 11:29:16 piccardi Exp $ + * $Id: SigHand.c,v 1.7 2003/05/06 14:05:12 piccardi Exp $ */ void HandSigCHLD(int sig) { @@ -110,9 +110,9 @@ void HandSigCHLD(int sig) do { errno = 0; pid = waitpid(WAIT_ANY, &status, WNOHANG); - if (pid > 0) { - debug("child %d terminated with status %x\n", pid, status); - } +// if (pid > 0) { +// debug("child %d terminated with status %x\n", pid, status); +// } } while ((pid > 0) && (errno == EINTR)); /* restore errno value*/ errno = errno_save; diff --git a/sources/TCP_echod_first.c b/sources/TCP_echod_first.c new file mode 100644 index 0000000..55fd5c6 --- /dev/null +++ b/sources/TCP_echod_first.c @@ -0,0 +1,204 @@ +/* TCP_echod.c + * + * Copyright (C) 2001-2003 Simone Piccardi + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +/**************************************************************** + * + * Program echod + * Elementary TCP server for echo service (port 7) + * + * Author: Simone Piccardi + * Jun. 2001 + * + * Usage: echod -h give all info + * + * $Id: TCP_echod_first.c,v 1.1 2003/05/06 14:05:12 piccardi Exp $ + * + ****************************************************************/ +/* + * Include needed headers + */ +#include /* predefined types */ +#include /* include unix standard library */ +#include /* IP addresses conversion utiliites */ +#include /* socket library */ +#include /* include standard I/O library */ +#include +#include /* syslog system functions */ +#include /* signal functions */ +#include "Gapil.h" + +#define BACKLOG 10 +#define MAXLINE 256 +int demonize = 1; /* daemon use option */ +int debugging = 0; /* debug info printing option */ +/* Subroutines declaration */ +void usage(void); +void ServEcho(int sockfd); +void PrintErr(char * error); +/* Program beginning */ +int main(int argc, char *argv[]) +{ +/* + * Variables definition + */ + int list_fd, conn_fd; + pid_t pid; + struct sockaddr_in serv_add; + /* + * Input section: decode parameters passed in the calling + * Use getopt function + */ + int i; + opterr = 0; /* don't want writing to stderr */ + while ( (i = getopt(argc, argv, "hdi")) != -1) { + switch (i) { + /* + * Handling options + */ + case 'h': + printf("Wrong -h option use\n"); + usage(); + return(0); + break; + case 'i': + demonize = 0; + break; + case 'd': + debugging = 1; + break; + case '?': /* unrecognized options */ + printf("Unrecognized options -%c\n",optopt); + usage(); + default: /* should not reached */ + usage(); + } + } + /* *********************************************************** + * + * Options processing completed + * + * Main code beginning + * + * ***********************************************************/ + /* install SIGCHLD handler */ + Signal(SIGCHLD, HandSigCHLD); /* establish handler */ + /* create socket */ + if ( (list_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + perror("Socket creation error"); + exit(1); + } + /* initialize address */ + memset((void *)&serv_add, 0, sizeof(serv_add)); /* clear server address */ + serv_add.sin_family = AF_INET; /* address type is INET */ + serv_add.sin_port = htons(7); /* echo port is 7 */ + serv_add.sin_addr.s_addr = htonl(INADDR_ANY); /* connect from anywhere */ + /* bind socket */ + if (bind(list_fd, (struct sockaddr *)&serv_add, sizeof(serv_add)) < 0) { + perror("bind error"); + exit(1); + } + /* release privileges and go daemon */ + if (setgid(65534) !=0) { /* first give away group privileges */ + perror("cannot give away group privileges"); + exit(1); + } + if (setuid(65534) !=0) { /* and only after user ... */ + perror("cannot give away user privileges"); + exit(1); + } + if (demonize) { /* go daemon */ + openlog(argv[0], 0, LOG_DAEMON); /* open logging */ + if (daemon(0, 0) != 0) { + perror("cannot start as daemon"); + exit(1); + } + } + /* main body */ + if (listen(list_fd, BACKLOG) < 0 ) { + PrintErr("listen error"); + exit(1); + } + /* handle echo to client */ + while (1) { + /* accept connection */ + if ( (conn_fd = accept(list_fd, NULL, NULL)) < 0) { + PrintErr("accept error"); + exit(1); + } + /* fork to handle connection */ + if ( (pid = fork()) < 0 ){ + PrintErr("fork error"); + exit(1); + } + if (pid == 0) { /* child */ + close(list_fd); /* close listening socket */ + ServEcho(conn_fd); /* handle echo */ + exit(0); + } else { /* parent */ + close(conn_fd); /* close connected socket */ + } + } + /* normal exit, never reached */ + exit(0); +} +/* + * routine to print usage info and exit + */ +void usage(void) { + printf("Elementary echo server\n"); + printf("Usage:\n"); + printf(" echod [-h] \n"); + printf(" -h print this help\n"); + printf(" -d print debug info\n"); + printf(" -i use interactively\n"); + exit(1); +} +/* + * routine to handle echo for connection + */ +void ServEcho(int sockfd) { + char buffer[MAXLINE]; + int nread, nwrite; + char debug[MAXLINE+20]; + int size; + /* main loop, reading 0 char means client close connection */ + while ( (nread = read(sockfd, buffer, MAXLINE)) != 0) { + nwrite = FullWrite(sockfd, buffer, nread); + if (debugging) { + buffer[nread] = 0; + snprintf(debug, MAXLINE+20, "Letti %d byte, %s", nread, buffer); + if (demonize) { /* go daemon */ + syslog(LOG_DEBUG, debug); + } else { + printf("%s", debug); + } + } + } + return; +} +/* + * routine to print error on stout or syslog + */ +void PrintErr(char * error) { + if (demonize) { /* go daemon */ + syslog(LOG_ERR, error); + } else { + perror(error); + } + return; +}