%\usepackage{footnote}
%\usepackage{mdwtab}
\usepackage{geometry}
+\usepackage{fancyvrb}
\def\tild{\char'176}
--- /dev/null
+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;
+}
--- /dev/null
+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;
+ }
+ ...
+}
--- /dev/null
+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;
+}
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}
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
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
*/
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 \
#include <errno.h> /* include error codes */
#include <string.h> /* include erroro strings definitions */
+#include "Gapil.h"
#include "macros.h"
#define MAXLINE 256
*/
int sock, i;
int reset = 0;
- struct sockaddr_in serv_add;
struct linger ling;
/*
* Input section: decode parameters passed in the calling
* 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 */
--- /dev/null
+/* 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;
+ }
+ }
+ }
+}
/* 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
*
* Usage: echod -h give all info
*
- * $Id: TCP_echod.c,v 1.13 2003/12/25 17:31:09 piccardi Exp $
+ * $Id$
*
****************************************************************/
/*
} 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");
-/* 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$
*
****************************************************************/
/*
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);
}
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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;
+}
#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;
}
-