Rinominato la prima versione del server.
authorSimone Piccardi <piccardi@gnulinux.it>
Tue, 6 May 2003 14:05:12 +0000 (14:05 +0000)
committerSimone Piccardi <piccardi@gnulinux.it>
Tue, 6 May 2003 14:05:12 +0000 (14:05 +0000)
elemtcp.tex
listati/TCP_echod_first.c [new file with mode: 0644]
sources/SigHand.c
sources/TCP_echod_first.c [new file with mode: 0644]

index 766974f..90fcfb9 100644 (file)
@@ -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 (file)
index 0000000..81085a7
--- /dev/null
@@ -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 */
+}
index 3fb588a..6112700 100644 (file)
@@ -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 <errno.h>                               /* 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 (file)
index 0000000..55fd5c6
--- /dev/null
@@ -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 <sys/types.h>   /* predefined types */
+#include <unistd.h>      /* include unix standard library */
+#include <arpa/inet.h>   /* IP addresses conversion utiliites */
+#include <sys/socket.h>  /* socket library */
+#include <stdio.h>      /* include standard I/O library */
+#include <time.h>
+#include <syslog.h>      /* syslog system functions */
+#include <signal.h>      /* 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;
+}