Completata la parte su getaddinfo con delle funzioni di ausilio per chiamare
authorSimone Piccardi <piccardi@gnulinux.it>
Sun, 5 Dec 2004 18:19:42 +0000 (18:19 +0000)
committerSimone Piccardi <piccardi@gnulinux.it>
Sun, 5 Dec 2004 18:19:42 +0000 (18:19 +0000)
quest'ultima ed avere client e server echo capaci di eseguire la risoluzione
degli indirizzi.

15 files changed:
gapil.tex
listati/TCP_echo_fifth.c [new file with mode: 0644]
listati/TCP_echod_third.c [new file with mode: 0644]
listati/sockbind.c [new file with mode: 0644]
sockctrl.tex
socket.tex
sources/Gapil.h
sources/Makefile
sources/TCP_echo.c
sources/TCP_echo_fifth.c [new file with mode: 0644]
sources/TCP_echod.c
sources/TCP_echod_second.c
sources/TCP_echod_third.c [new file with mode: 0644]
sources/sockbind.c [new file with mode: 0644]
sources/sockconn.c

index 2df2a81..7d96b48 100644 (file)
--- a/gapil.tex
+++ b/gapil.tex
@@ -43,6 +43,7 @@
 %\usepackage{footnote} 
 %\usepackage{mdwtab} 
 \usepackage{geometry}
+\usepackage{fancyvrb}
 
 \def\tild{\char'176}
 
diff --git a/listati/TCP_echo_fifth.c b/listati/TCP_echo_fifth.c
new file mode 100644 (file)
index 0000000..2f21902
--- /dev/null
@@ -0,0 +1,18 @@
+int main(int argc, char *argv[])
+{
+/* 
+ * Variables definition  
+ */
+    int sock, i;
+    int reset = 0;
+    ...
+    /* call sockaddr to get a connected socket */
+    if ( (sock = sockconn(argv[optind], "echo", 6, SOCK_STREAM)) < 0) {
+       if (errno) perror("Socket creation error");
+       return 1;
+    }
+    /* do read/write operations */
+    ClientEcho(stdin, sock);
+    /* normal exit */
+    return 0;
+}
diff --git a/listati/TCP_echod_third.c b/listati/TCP_echod_third.c
new file mode 100644 (file)
index 0000000..c150ad4
--- /dev/null
@@ -0,0 +1,20 @@
+int main(int argc, char *argv[])
+{
+/* 
+ * Variables definition  
+ */
+    int list_fd, conn_fd;
+    ...
+    /* Main code begin here */
+    if (compat) {                             /* install signal handler */
+       Signal(SIGCHLD, HandSigCHLD);         /* non restarting handler */
+    } else {
+       SignalRestart(SIGCHLD, HandSigCHLD);  /* restarting handler */
+    }
+    /* create and bind socket */
+    if ( (list_fd = sockbind(argv[optind], "echo", 6, SOCK_STREAM)) < 0) {
+       if (errno) perror("Socket creation error");
+       return 1;
+    }   
+    ...
+}
diff --git a/listati/sockbind.c b/listati/sockbind.c
new file mode 100644 (file)
index 0000000..ddf48d8
--- /dev/null
@@ -0,0 +1,32 @@
+int sockbind(char *host, char *serv, int prot, int type) 
+{
+    struct addrinfo hint, *addr;
+    int res;
+    int sock;
+    /* initialize hint structure */
+    memset(&hint, 0, sizeof(struct addrinfo)); 
+    hint.ai_flags = AI_PASSIVE;          /* address for binding */
+    hint.ai_family = PF_UNSPEC;          /* generic address (IPv4 or IPv6) */
+    hint.ai_protocol = prot;             /* protocol */
+    hint.ai_socktype = type;             /* socket type */
+    res = getaddrinfo(host, serv, &hint, &addr);   /* calling getaddrinfo */
+    if (res != 0) {                                /* on error exit */
+       printf("sockbind cannot resolve host %s, service %s, ", host, serv);
+       printf("protocol %d: %s\n", prot, gai_strerror(res));
+       return -1;
+    }
+    /* get a socket */
+    sock = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
+    if (sock < 0) {
+       printf("sockconn cannot create socket\n");
+       return sock;
+    }
+    /* connect the socket */
+    res = bind(sock, addr->ai_addr, addr->ai_addrlen);
+    if (res < 0) {
+       printf("sockconn cannot bind socket\n");
+       return res;
+    }
+    freeaddrinfo(addr);         /* done, release memory */
+    return sock;
+}
index b4b229e..872f7b7 100644 (file)
@@ -1656,18 +1656,150 @@ qualora la loro dimensione ecceda quelle specificate dagli argomenti
 viene restituito invece un codice che assume gli stessi valori illustrati in
 tab.~\ref{tab:addrinfo_error_code}.
 
-A questo punto possiamo fornire degli esempi di utilizzo diretto della nuova
+A questo punto possiamo fornire degli esempi di utilizzo della nuova
 interfaccia, adottandola per le precedenti implementazioni del client e del
-server per il servizio \textit{echo}; dato che l'uso delle funzioni (in
-particolare di \func{getaddrinfo} è piuttosto complesso, prevedendo una
-impostazione manuale dell'argomento \param{hints}, provvederemo una
-interfaccia semplificata per i due casi visti finora, quello in cui si
-specifica nel client un indirizzo remoto per la connessione al server, e
-quello in cui si specifica nel server un indirizzo locale su cui porsi in
-ascolto.
-
-La prima funzione è allora \func{sockconn}, che richiede la risoluzione di un
-indirizzo e di un servizio per connettere un socket allo stesso. 
+server per il servizio \textit{echo}; dato che l'uso delle funzioni appena
+illustrate (in particolare di \func{getaddrinfo}) è piuttosto complesso,
+essendo necessaria anche una impostazione diretta dei campi dell'argomento
+\param{hints}, provvederemo una interfaccia semplificata per i due casi visti
+finora, quello in cui si specifica nel client un indirizzo remoto per la
+connessione al server, e quello in cui si specifica nel server un indirizzo
+locale su cui porsi in ascolto.
+
+La prima funzione è allora \func{sockconn} che restituisce un socket connesso
+all'indirizzo ed al servizio specificati come argomenti; la funzione prende
+poi altri due argomenti aggiuntivi per indicare il protocollo da usare ed il
+tipo di socket. Il corpo della funzione è riportato in
+fig.~\ref{fig:sockconn_code}, ed il codice completo è nel file
+\file{sockconn.c} nei sorgenti allegati alla guida.
+
+\begin{figure}[!htb]
+  \footnotesize \centering
+  \begin{minipage}[c]{15cm}
+    \includecodesample{listati/sockconn.c}
+  \end{minipage}
+  \normalsize
+  \caption{Il codice della funzione \func{sockconn}.}
+  \label{fig:sockconn_code}
+\end{figure}
+
+La funzione prende quattro argomenti, i primi due sono le stringhe che
+indicano il nome della macchina a cui collegarsi ed il relativo servizio;
+seguono il protocollo da usare (in forma numerica) ed il tipo di socket (al
+solito specificato con i valori illustrati in sez.~\ref{sec:sock_type}). La
+funzione ritorna il filde descriptor associato al socket in caso di successo,
+o -1 in caso di errore. Come si vede la funzione prevede anche ad alcune
+stampe in maniera diretta (il che la rende non utilizzabile all'interno di un
+demone).
+
+Una volta definite le variabili necessarie (\texttt{\small 3--5}) la funzione
+prima (\texttt{\small 7}) azzera il contenuto della struttura \var{hint} e poi
+provvede (\texttt{\small 8--10}) ad inizializzarne i valori necessari per la
+chiamata (\texttt{\small 11}) a \func{getaddrinfo}. Di quest'ultima si
+controlla (\texttt{\small 12}) il codice di ritorno, in modo da stampare
+(\texttt{\small 13--15}) un avviso di errore ed uscire in caso di errore.  Se
+la risoluzioen del nome ha successo si provvede (\texttt{\small 18--22}) ad
+aprire il socket, ed a connettersi ad esso (\texttt{\small 24--28}); in
+entrambi casi si gestisce il caso di errore. Infine prima di ritornare
+(\texttt{\small 30}) il file descriptor del socket si provvede (\texttt{\small
+  29}) a liberare le strutture \struct{addrinfo} allocate da
+\func{getaddrinfo}.
+
+Si noti come la funzione si limiti ad usare i valori contenuti nella prima
+struttura \struct{addrinfo} ritornata da \func{getaddrinfo}, non eseguendo
+ulteriori tentativi sulle successive in caso di errore. Un'altra
+caratteristica della funzione è che è del tutto irrilevante se la struttura
+ritornata usa indirizzi IPv6 o IPv4, in quanto si fa uso direttamente dei dati
+relativi alle strutture degli indirizzi di \struct{addrinfo} che sono
+\textsl{opachi} rispetto all'uso della funzione \func{connect}.
+
+Per usare questa funzione possiamo allora modificare ulteriormente il nostro
+programma client per il servizio \textit{echo}; in questo caso rispetto al
+codice usato finora per collegarsi (vedi fig.~\ref{fig:TCP_echo_client_1})
+avremo una semplificazione per cui il corpo principale del nostro client
+diventerà quello illustrato in fig.~\ref{fig:TCP_echo_fifth}, in cui le
+chiamate a \func{socket}, \func{inet\_pton} e \func{connect} sono sostituite
+da una singola chiamata a \func{sockconn}. Inoltre il nuovo client (il cui
+codice completo è nel file \file{TCP\_echo\_fifth.c} dei sorgenti allegati)
+consente di utilizzare come argomento del programma un nome a dominio al posto
+dell'indirizzo numerico, e può utilizzare sia indirizzi IPv4 che IPv6.
+
+\begin{figure}[!htb]
+  \footnotesize \centering
+  \begin{minipage}[c]{15cm}
+    \includecodesample{listati/TCP_echo_fifth.c}
+  \end{minipage}
+  \normalsize
+  \caption{Il nuovo codice per la connessione del client \textit{echo}.}
+  \label{fig:TCP_echo_fifth}
+\end{figure}
+
+La seconda funzione di ausilio è \func{sockbind}, il cui corpo principale è
+riportato in fig.~\ref{fig:sockbind_code} (al solito il sorgente completo è
+nel file \file{sockbind.c} dei sorgenti allegati alla guida). Come si può
+notare la funzione è del tutto analoga alla precedente \func{sockconn}, e
+prende gli stessi argomenti, però invece di eseguire una connessione con
+\func{connect} si limita a chiamare \func{bind} per collegare il socket ad una
+porta. 
+
+Dato che la funzione è pensata per utilizzata da un server ci si può chiedere
+a quale scopo mantenere l'argomento \param{host} quando l'indirizzo di questo
+è usualmente noto. Si ricordi però quanto detto in
+sez.~\ref{sec:TCP_func_bind}, relativamente al significato della scelta di un
+indirizzo specifico come argomento di \func{bind}, che consente di porre il
+server in ascolto su uno solo dei possibili diversi indirizzi presenti su di
+una macchina. 
+
+Se non si vuole che la funzione esegua \func{bind} su un indirizzo specifico,
+ma utilizzi l'indirizzo generico, occorrerà avere cura di passare un valore
+\const{NULL} come valore per l'argomento \var{host}, l'uso del valore
+\const{AI\_PASSIVE} serve ad ottenere il valore generico nella rispettiva
+struttura degli indirizzi.
+
+\begin{figure}[!htb]
+  \footnotesize \centering
+  \begin{minipage}[c]{15cm}
+    \includecodesample{listati/sockbind.c}
+  \end{minipage}
+  \normalsize
+  \caption{Il codice della funzione \func{sockbind}.}
+  \label{fig:sockbind_code}
+\end{figure}
+
+
+Come già detto la funzione è analoga a \func{sockconn} ed inizia azzerando ed
+inizializzando (\texttt{\small 6-11}) opportunamente la struttura \var{hint}
+con i valori ricevuti come argomenti, soltanto che in questo caso si è usata
+(\texttt{\small 8}) una impostazione specifica dei flag di \var{hint} usando
+\const{AI\_PASSIVE} per indicare che il socket sarà usato per una apertura
+passiva. Per il resto la chiamata a \func{getaddrinfo} (\texttt{\small 12-17})
+e quella a \func{socket} (\texttt{\small 19--23}) sono identiche, mentre si è
+sostituita (\texttt{\small 25--29}) la chiamata a \func{connect} con una
+chiamata a \func{bind}. La conclusione (\texttt{\small 30--31}) della funzione
+è identica. Si noti come anche in questo caso si siano inserite le stampe
+degli errori sullo standard output, nonostante la funzione possa essere
+invocata da un demone. In realtà questo non è un problema in quanto se la
+funzione non ha successo il programma deve uscire immediatamente prima di
+essere posto in background, e può quindi scrivere gli errori direttamente
+sullo standard output.
+
+Con l'uso di questa funzione si può modificare anche il codice del nostro
+server \textit{echo}, che rispetto a quanto illustrato nella versione iniziale
+di fig.~\ref{fig:TCP_echo_server_first_code} viene modificato nella forma
+riportata in fig.~\ref{fig:TCP_echod_third}. In questo caso il socket su cui
+porsi in ascolto viene ottenuto (\texttt{\small 15--18}) da \func{sockbind}
+che si cura anche della eventuale risoluzione di un indirizzo specifico sul
+quale si voglia far ascoltare il server.
+
+\begin{figure}[!htb]
+  \footnotesize \centering
+  \begin{minipage}[c]{15cm}
+    \includecodesample{listati/TCP_echod_third.c}
+  \end{minipage}
+  \normalsize
+  \caption{Nuovo codice per l'apertura passiva del server \textit{echo}.}
+  \label{fig:TCP_echod_third}
+\end{figure}
 
 
 
index 9d86a3e..2cb5fe7 100644 (file)
@@ -255,7 +255,7 @@ disposizione vari tipi di socket (che corrispondono a quelli che il manuale
 della \acr{glibc} \cite{glibc} chiama \textit{styles}) identificati dalle
 seguenti costanti:
 
-\begin{basedescript}{\desclabelwidth{2.8cm}\desclabelstyle{\nextlinelabel}}
+\begin{basedescript}{\desclabelwidth{2.9cm}\desclabelstyle{\nextlinelabel}}
 \item[\const{SOCK\_STREAM}] Provvede un canale di trasmissione dati
   bidirezionale, sequenziale e affidabile. Opera su una connessione con un
   altro socket. I dati vengono ricevuti e trasmessi come un flusso continuo di
index c6cbfea..5647368 100644 (file)
@@ -122,6 +122,12 @@ void * CreateShm(char * shm_name, off_t shm_size, int perm, int fill);
 void * FindShm(char * shm_name, off_t shm_size);
 /* Function RemoveShm: remove a POSIX shared memory */
 int RemoveShm(char * shm_name);
+/*
+ * Socket creation functions. See corresponding .c
+ */
+int sockconn(char *host, char *serv, int prot, int type);
+int sockbind(char *host, char *serv, int prot, int type);
+
 /*
  * General purpose functions. See corresponding .c
  */
index 0b4b5a9..0a4fcf3 100644 (file)
@@ -9,7 +9,7 @@ CFLAGJ= -L./ -lgapil
 LIB = libgapil.so
 
 OBJ = FullRead.o FullWrite.o SigHand.o Mutex.o SharedMem.o LockFile.o \
-      DirScan.o endian.o
+      DirScan.o endian.o sockconn.o sockbind.o
 
 FINAL = forktest errcode echo echod daytimed iterdaytimed daytime testfopen \
        testren fortune fortuned mqfortune mqfortuned flock myls dirmonitor \
index 691911e..f60c518 100644 (file)
@@ -40,6 +40,7 @@
 #include <errno.h>      /* include error codes */
 #include <string.h>     /* include erroro strings definitions */
 
+#include "Gapil.h"
 #include "macros.h"
 
 #define MAXLINE 256
@@ -55,7 +56,6 @@ int main(int argc, char *argv[])
  */
     int sock, i;
     int reset = 0;
-    struct sockaddr_in serv_add;
     struct linger ling;
     /*
      * Input section: decode parameters passed in the calling 
@@ -89,23 +89,9 @@ int main(int argc, char *argv[])
      *               Main code beginning
      * 
      * ***********************************************************/
-    /* create socket */
-    if ( (sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
-       perror("Socket creation error");
-       return 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 */
-    /* build address using inet_pton */
-    if ( (inet_pton(AF_INET, argv[optind], &serv_add.sin_addr)) <= 0) {
-       perror("Address creation error");
-       return 1;
-    }
-    /* extablish connection */
-    if (connect(sock, (struct sockaddr *)&serv_add, sizeof(serv_add)) < 0) {
-       perror("Connection error");
+    /* call sockaddr to get a connected socket */
+    if ( (sock = sockconn(argv[optind], "echo", 6, SOCK_STREAM)) < 0) {
+       if (errno) perror("Socket creation error");
        return 1;
     }
     /* check if resetting on close is required */
diff --git a/sources/TCP_echo_fifth.c b/sources/TCP_echo_fifth.c
new file mode 100644 (file)
index 0000000..f60c518
--- /dev/null
@@ -0,0 +1,175 @@
+/* TCP_echo.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 TCP_echo.c
+ * Simple TCP client for echo service (port 7)
+ *
+ * Author: Simone Piccardi
+ * Jun. 2001
+ *
+ * Usage: echo -h give all info's
+ *
+ * $Id: TCP_echo.c,v 1.11 2003/10/20 22:44:16 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 <errno.h>      /* include error codes */
+#include <string.h>     /* include erroro strings definitions */
+
+#include "Gapil.h"
+#include "macros.h"
+
+#define MAXLINE 256
+void usage(void);
+void ClientEcho(FILE * filein, int socket);
+void SigTERM_hand(int sig);
+
+/* Program begin */
+int main(int argc, char *argv[])
+{
+/* 
+ * Variables definition  
+ */
+    int sock, i;
+    int reset = 0;
+    struct linger ling;
+    /*
+     * Input section: decode parameters passed in the calling 
+     * Use getopt function
+     */
+    opterr = 0;         /* don't want writing to stderr */
+    while ( (i = getopt(argc, argv, "hr")) != -1) {
+       switch (i) {
+       /* 
+        * Handling options 
+        */ 
+       case 'h':  
+           printf("Wrong -h option use\n");
+           usage();
+           return(1);
+           break;
+       case 'r':
+           reset = 1;
+           break;
+       case '?':   /* unrecognized options */
+           printf("Unrecognized options -%c\n",optopt);
+           usage();
+       default:    /* should not reached */
+           usage();
+       }
+    }
+    /* ***********************************************************
+     * 
+     *          Options processing completed
+     *
+     *               Main code beginning
+     * 
+     * ***********************************************************/
+    /* call sockaddr to get a connected socket */
+    if ( (sock = sockconn(argv[optind], "echo", 6, SOCK_STREAM)) < 0) {
+       if (errno) perror("Socket creation error");
+       return 1;
+    }
+    /* check if resetting on close is required */
+    if (reset) {
+       printf("Setting reset on close \n");
+       ling.l_onoff = 1;
+       ling.l_linger = 0;      
+       if (setsockopt(sock, SOL_SOCKET, SO_LINGER, &ling, sizeof(ling))) {
+           perror("Cannot set linger");
+           exit(1);
+       }
+    }
+    /* do read/write operations */
+    ClientEcho(stdin, sock);
+    /* normal exit */
+    return 0;
+}
+/*
+ * routine to print usage info and exit 
+ */
+void usage(void) {
+    printf("Take daytime from a remote host \n");
+    printf("Usage:\n");
+    printf("  daytime [-h] [-v] [host in dotted decimal form] \n");
+//    printf("  -v        set verbosity on\n");
+    printf("  -r          require reset on closing\n");
+    printf("  -h          print this help\n");
+    exit(1);
+}
+
+void ClientEcho(FILE * filein, int socket) 
+{
+    char sendbuff[MAXLINE+1], recvbuff[MAXLINE+1];
+    int nread, nwrite; 
+    int maxfd;
+    fd_set fset;
+    int eof = 0;
+    /* initialize file descriptor set */
+    FD_ZERO(&fset);
+    maxfd = max(fileno(filein), socket) + 1;
+    while (1) {
+       FD_SET(socket, &fset);         /* set for the socket */
+       if (eof == 0) {
+           FD_SET(fileno(filein), &fset); /* set for the standard input */
+       }
+       select(maxfd, &fset, NULL, NULL, NULL); /* wait for read ready */
+       if (FD_ISSET(fileno(filein), &fset)) {  /* if ready on stdin */
+           if (fgets(sendbuff, MAXLINE, filein) == NULL) { /* if no input */
+               eof = 1;               /* EOF on input */
+               shutdown(socket, SHUT_WR);      /* close write half */
+               FD_CLR(fileno(filein), &fset);  /* no more interest on stdin */
+           } else {                   /* else we have to write to socket */
+               nwrite = FullWrite(socket, sendbuff, strlen(sendbuff)); 
+               if (nwrite < 0) {      /* on error stop */
+                   printf("Errore in scrittura: %s", strerror(errno));
+                   return;
+               }
+           }
+       }
+       if (FD_ISSET(socket, &fset)) { /* if ready on socket */ 
+           nread = read(socket, recvbuff, strlen(sendbuff)); /* do read */
+           if (nread < 0) {  /* error condition, stop client */
+               printf("Errore in lettura: %s\n", strerror(errno));
+               return;
+           }
+           if (nread == 0) { /* server closed connection, stop */
+               if (eof == 1) {
+                   return;
+               } else {
+                   printf("EOF prematuro sul socket\n");
+                   return;
+               }
+           }
+           recvbuff[nread] = 0;   /* else read is ok, write on stdout */
+           if (fputs(recvbuff, stdout) == EOF) {
+               perror("Errore in scrittura su terminale");
+               return;
+           }
+       }
+    }
+}
index dd0a9f8..7062c3b 100644 (file)
@@ -1,6 +1,6 @@
 /* TCP_echod.c
  * 
- * Copyright (C) 2001-2003 Simone Piccardi
+ * Copyright (C) 2001-2004 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
@@ -26,7 +26,7 @@
  *
  * Usage: echod -h give all info
  *
- * $Id: TCP_echod.c,v 1.13 2003/12/25 17:31:09 piccardi Exp 
+ * $Id$ 
  *
  ****************************************************************/
 /* 
@@ -115,21 +115,11 @@ int main(int argc, char *argv[])
     } else {
        SignalRestart(SIGCHLD, HandSigCHLD);  /* restarting 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);
-    }
+    /* create and bind socket */
+    if ( (list_fd = sockbind(argv[optind], "echo", 6, SOCK_STREAM)) < 0) {
+       if (errno) perror("Socket creation error");
+       return 1;
+    }   
     /* release privileges and go daemon */
     if (setgid(65534) !=0) { /* first give away group privileges */
        perror("cannot give away group privileges");
index 617eaf1..0ac7c0e 100644 (file)
@@ -1,4 +1,4 @@
-/* TCP_echod.c
+/* TCP_echod_second.c
  * 
  * Copyright (C) 2001-2003 Simone Piccardi
  * 
  *
  * Program echod 
  * Elementary TCP server for echo service (port 7)
+ * Second version
  *
  * Author: Simone Piccardi
  * Jun. 2001
  *
  * Usage: echod -h give all info
  *
- * $Id: TCP_echod_second.c,v 1.2 2003/12/25 17:31:09 piccardi Exp 
+ * $Id$ 
  *
  ****************************************************************/
 /* 
@@ -158,7 +159,7 @@ int main(int argc, char *argv[])
        len = sizeof(cli_add);
        while (((conn_fd = accept(list_fd, (struct sockaddr *)&cli_add, &len)) 
                < 0) && (errno == EINTR)); 
-       if ( conn_fd < 0) {
+       if (conn_fd < 0) {
            PrintErr("accept error");
            exit(1);
        }
diff --git a/sources/TCP_echod_third.c b/sources/TCP_echod_third.c
new file mode 100644 (file)
index 0000000..86c154f
--- /dev/null
@@ -0,0 +1,243 @@
+/* TCP_echod_third.c
+ * 
+ * Copyright (C) 2001-2004 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)
+ * Third version, use sockbind
+ *
+ * Author: Simone Piccardi
+ * Jun. 2001
+ *
+ * Usage: echod -h give all info
+ *
+ * $Id$ 
+ *
+ ****************************************************************/
+/* 
+ * 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 <errno.h>       /* error code */
+#include <string.h>      /* error strings */
+#include <stdlib.h>
+
+#include "Gapil.h"
+
+#define BACKLOG 10
+#define MAXLINE 256
+int demonize  = 1;  /* daemon use option: default is daemon */
+int debugging = 0;  /* debug info printing option: default is no debug */
+/* 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;
+    int waiting = 0;
+    int compat = 0;
+    pid_t pid;
+    struct sockaddr_in serv_add, cli_add;
+    socklen_t len;
+    char debug[MAXLINE], ipaddr[20];
+    /*
+     * 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, "hdicw:")) != -1) {
+       switch (i) {
+       /* 
+        * Handling options 
+        */ 
+       case 'h':  
+           printf("Wrong -h option use\n");
+           usage();
+           return(0);
+           break;
+       case 'i':
+           demonize = 0;
+           break;
+       case 'c':
+           compat = 1;
+           break;
+       case 'd':
+           debugging = 1;
+           break;
+       case 'w':
+           waiting = strtol(optarg, NULL, 10);
+           break;
+       case '?':   /* unrecognized options */
+           printf("Unrecognized options -%c\n",optopt);
+           usage();
+       default:    /* should not reached */
+           usage();
+       }
+    }
+    /* ***********************************************************
+     * 
+     *          Options processing completed
+     *
+     *               Main code beginning
+     * 
+     * ***********************************************************/
+    /* Main code begin here */
+    if (compat) {                             /* install signal handler */
+       Signal(SIGCHLD, HandSigCHLD);         /* non restarting handler */
+    } else {
+       SignalRestart(SIGCHLD, HandSigCHLD);  /* restarting handler */
+    }
+    /* create and bind socket */
+    if ( (list_fd = sockbind(argv[optind], "echo", 6, SOCK_STREAM)) < 0) {
+       if (errno) perror("Socket creation error");
+       return 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);
+    }
+    if (waiting) sleep(waiting);
+    /* handle echo to client */
+    while (1) {
+       /* accept connection */
+       len = sizeof(cli_add);
+       while (((conn_fd = accept(list_fd, (struct sockaddr *)&cli_add, &len)) 
+               < 0) && (errno == EINTR)); 
+       if (conn_fd < 0) {
+           PrintErr("accept error");
+           exit(1);
+       }
+       if (debugging) {
+           inet_ntop(AF_INET, &cli_add.sin_addr, ipaddr, sizeof(ipaddr));
+           snprintf(debug, MAXLINE, "Accepted connection form %s\n", ipaddr);
+           if (demonize) {
+               syslog(LOG_DEBUG, debug);
+           } else {
+               printf("%s", debug);
+           }
+       }
+       /* 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 */
+           if (debugging) {
+               snprintf(debug, MAXLINE, "Closed connection %s\n", ipaddr);
+               if (demonize) {
+                   syslog(LOG_DEBUG, debug);
+               } else {
+                   printf("%s", debug);
+               }
+           }
+           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          write debug info\n");
+    printf("  -i          use interactively\n");
+    printf("  -c          disable BSD semantics\n");
+    printf("  -w N        wait N sec. before calling accept\n");
+    exit(1);
+}
+/*
+ * routine to handle echo for connection
+ */
+void ServEcho(int sockfd) {
+    char buffer[MAXLINE];
+    int nread, nwrite;
+    char debug[MAXLINE+20];
+    /* main loop, reading 0 char means client close connection */
+    while ( (nread = read(sockfd, buffer, MAXLINE)) != 0) {
+       if (nread < 0) {
+           PrintErr("Errore in lettura");
+           return;
+       }
+       nwrite = FullWrite(sockfd, buffer, nread);
+       if (nwrite) {
+           PrintErr("Errore in scrittura");
+           return;
+       }
+       if (debugging) {
+           buffer[nread] = 0;
+           snprintf(debug, MAXLINE+20, "Letti %d byte, %s", nread, buffer);
+           if (demonize) {          /* daemon mode */
+               syslog(LOG_DEBUG, debug);
+           } else {
+               printf("%s", debug);
+           }
+       }
+    }
+    return;
+}
+/*
+ * routine to print error on stout or syslog
+ */
+void PrintErr(char * error) {
+    if (demonize) {                       /* daemon mode */
+       syslog(LOG_ERR, "%s: %m", error); /* log string and error message */
+    } else {
+       perror(error);
+    }
+    return;
+}
diff --git a/sources/sockbind.c b/sources/sockbind.c
new file mode 100644 (file)
index 0000000..3e31fe7
--- /dev/null
@@ -0,0 +1,69 @@
+/* sockbind.c
+ * 
+ * Copyright (C) 2004 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.
+ */
+/****************************************************************
+ *
+ * Routine sockbind
+ * Return a binded socket given hostname, service, and socket type
+ *
+ * Author: Simone Piccardi
+ * Dec. 2004
+ *
+ * $Id$ 
+ *
+ ****************************************************************/
+#include <arpa/inet.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+
+int sockbind(char *host, char *serv, int prot, int type) 
+{
+    struct addrinfo hint, *addr;
+    int res;
+    int sock;
+    /* initialize hint structure */
+    memset(&hint, 0, sizeof(struct addrinfo)); 
+    hint.ai_flags = AI_PASSIVE;          /* address for binding */
+    hint.ai_family = PF_UNSPEC;          /* generic address (IPv4 or IPv6) */
+    hint.ai_protocol = prot;             /* protocol */
+    hint.ai_socktype = type;             /* socket type */
+    res = getaddrinfo(host, serv, &hint, &addr);   /* calling getaddrinfo */
+    if (res != 0) {                                /* on error exit */
+       printf("sockbind cannot resolve host %s, service %s, ", host, serv);
+       printf("protocol %d: %s\n", prot, gai_strerror(res));
+       return -1;
+    }
+    /* get a socket */
+    sock = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
+    if (sock < 0) {
+       printf("sockconn cannot create socket\n");
+       return sock;
+    }
+    /* connect the socket */
+    res = bind(sock, addr->ai_addr, addr->ai_addrlen);
+    if (res < 0) {
+       printf("sockconn cannot bind socket\n");
+       return res;
+    }
+    freeaddrinfo(addr);         /* done, release memory */
+    return sock;
+}
index c162474..81c982d 100644 (file)
 #include <arpa/inet.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdio.h>
 #include <errno.h>
 
 int sockconn(char *host, char *serv, int prot, int type) 
 {
     struct addrinfo hint, *addr;
     int res;
-    int sock
-    /* initialize hint */
-    memset(&hint, 0, sizeof(hint)); 
-    hint.ai_family = PF_UNSPEC;
-    hint.ai_protocol = prot;
-    hint.ai_socktype = type;
-    res = getaddrinfo(host, serv, &hint, &addr);
-    if (res != 0) {
-       printf("sockconn cannot resolve host %s, service %s,
-                protocol %d: %s\n", host, serv, prot, gai_strerror(res));
-       errno = 0;
+    int sock;
+    /* initialize hint structure */
+    memset(&hint, 0, sizeof(struct addrinfo)); 
+    hint.ai_family = PF_UNSPEC;          /* generic address (IPv4 or IPv6) */
+    hint.ai_protocol = prot;             /* protocol */
+    hint.ai_socktype = type;             /* socket type */
+    res = getaddrinfo(host, serv, &hint, &addr);   /* calling getaddrinfo */
+    if (res != 0) {                                /* on error exit */
+       printf("sockconn cannot resolve host %s, service %s, ", host, serv);
+       printf("protocol %d: %s\n", prot, gai_strerror(res));
        return -1;
     }
+    /* get a socket */
     sock = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
     if (sock < 0) {
-       perror("sockconn cannot create socket\n");
+       printf("sockconn cannot create socket\n");
        return sock;
     }
+    /* connect the socket */
     res = connect(sock, addr->ai_addr, addr->ai_addrlen);
     if (res < 0) {
-       perror("sockconn cannot connect socket\n");
+       printf("sockconn cannot connect socket\n");
        return res;
     }
-    freeaddrinfo(addr);
+    freeaddrinfo(addr);         /* done, release memory */
     return sock;
 }
-