From 8654ce33b450ae7bb34c3907835000a0760c2931 Mon Sep 17 00:00:00 2001 From: Simone Piccardi Date: Sun, 5 Dec 2004 18:19:42 +0000 Subject: [PATCH] Completata la parte su getaddinfo con delle funzioni di ausilio per chiamare quest'ultima ed avere client e server echo capaci di eseguire la risoluzione degli indirizzi. --- gapil.tex | 1 + listati/TCP_echo_fifth.c | 18 +++ listati/TCP_echod_third.c | 20 +++ listati/sockbind.c | 32 +++++ sockctrl.tex | 154 +++++++++++++++++++++-- socket.tex | 2 +- sources/Gapil.h | 6 + sources/Makefile | 2 +- sources/TCP_echo.c | 22 +--- sources/TCP_echo_fifth.c | 175 ++++++++++++++++++++++++++ sources/TCP_echod.c | 24 ++-- sources/TCP_echod_second.c | 7 +- sources/TCP_echod_third.c | 243 +++++++++++++++++++++++++++++++++++++ sources/sockbind.c | 69 +++++++++++ sources/sockconn.c | 33 ++--- 15 files changed, 742 insertions(+), 66 deletions(-) create mode 100644 listati/TCP_echo_fifth.c create mode 100644 listati/TCP_echod_third.c create mode 100644 listati/sockbind.c create mode 100644 sources/TCP_echo_fifth.c create mode 100644 sources/TCP_echod_third.c create mode 100644 sources/sockbind.c diff --git a/gapil.tex b/gapil.tex index 2df2a81..7d96b48 100644 --- 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 index 0000000..2f21902 --- /dev/null +++ b/listati/TCP_echo_fifth.c @@ -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 index 0000000..c150ad4 --- /dev/null +++ b/listati/TCP_echod_third.c @@ -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 index 0000000..ddf48d8 --- /dev/null +++ b/listati/sockbind.c @@ -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; +} diff --git a/sockctrl.tex b/sockctrl.tex index b4b229e..872f7b7 100644 --- a/sockctrl.tex +++ b/sockctrl.tex @@ -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} diff --git a/socket.tex b/socket.tex index 9d86a3e..2cb5fe7 100644 --- a/socket.tex +++ b/socket.tex @@ -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 diff --git a/sources/Gapil.h b/sources/Gapil.h index c6cbfea..5647368 100644 --- a/sources/Gapil.h +++ b/sources/Gapil.h @@ -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 */ diff --git a/sources/Makefile b/sources/Makefile index 0b4b5a9..0a4fcf3 100644 --- a/sources/Makefile +++ b/sources/Makefile @@ -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 \ diff --git a/sources/TCP_echo.c b/sources/TCP_echo.c index 691911e..f60c518 100644 --- a/sources/TCP_echo.c +++ b/sources/TCP_echo.c @@ -40,6 +40,7 @@ #include /* include error codes */ #include /* 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 index 0000000..f60c518 --- /dev/null +++ b/sources/TCP_echo_fifth.c @@ -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 /* predefined types */ +#include /* include unix standard library */ +#include /* IP addresses conversion utiliites */ +#include /* socket library */ +#include /* include standard I/O library */ +#include /* include error codes */ +#include /* 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; + } + } + } +} diff --git a/sources/TCP_echod.c b/sources/TCP_echod.c index dd0a9f8..7062c3b 100644 --- a/sources/TCP_echod.c +++ b/sources/TCP_echod.c @@ -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"); diff --git a/sources/TCP_echod_second.c b/sources/TCP_echod_second.c index 617eaf1..0ac7c0e 100644 --- a/sources/TCP_echod_second.c +++ b/sources/TCP_echod_second.c @@ -1,4 +1,4 @@ -/* TCP_echod.c +/* TCP_echod_second.c * * Copyright (C) 2001-2003 Simone Piccardi * @@ -20,13 +20,14 @@ * * 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 index 0000000..86c154f --- /dev/null +++ b/sources/TCP_echod_third.c @@ -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 /* 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 /* error code */ +#include /* error strings */ +#include + +#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 index 0000000..3e31fe7 --- /dev/null +++ b/sources/sockbind.c @@ -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 +#include +#include +#include +#include +#include +#include + +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; +} diff --git a/sources/sockconn.c b/sources/sockconn.c index c162474..81c982d 100644 --- a/sources/sockconn.c +++ b/sources/sockconn.c @@ -30,36 +30,39 @@ #include #include #include +#include +#include +#include #include 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; } - -- 2.30.2