/* 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.5 2003/06/19 11:43:13 piccardi Exp $
- *
****************************************************************/
/*
* Include needed headers
*/
-#include <sys/types.h> /* predefined types */
-#include <unistd.h> /* include unix standard library */
-#include <arpa/inet.h> /* IP addresses conversion utiliites */
-#include <sys/socket.h> /* socket library */
-#include <stdio.h> /* include standard I/O library */
-#include <time.h>
+#include <sys/types.h> /* primitive system data types */
+#include <unistd.h> /* unix standard library */
+#include <arpa/inet.h> /* IP addresses conversion utilities */
+#include <sys/socket.h> /* socket constants, types and functions */
+#include <stdio.h> /* standard I/O library */
+#include <time.h> /* date and time constants, types and functions */
#include <syslog.h> /* syslog system functions */
-#include <signal.h> /* signal functions */
-#include <errno.h> /* error code */
+#include <signal.h> /* signal constants, types and functions */
+#include <errno.h> /* error definitions and routines */
+#include <string.h> /* C strings library */
+#include <stdlib.h> /* C standard library */
+
#include "Gapil.h"
#define BACKLOG 10
* Variables definition
*/
int list_fd, conn_fd;
- int waiting;
+ int waiting = 0;
+ int keepalive = 0;
+ int reuse = 0;
+ int compat = 0;
pid_t pid;
- struct sockaddr_in serv_add, cli_add;
+ struct sockaddr_in cli_add;
socklen_t len;
char debug[MAXLINE], ipaddr[20];
/*
*/
int i;
opterr = 0; /* don't want writing to stderr */
- while ( (i = getopt(argc, argv, "hdiw:")) != -1) {
+ while ( (i = getopt(argc, argv, "hkrdicw:")) != -1) {
switch (i) {
/*
* Handling options
case 'i':
demonize = 0;
break;
+ case 'k':
+ keepalive = 1;
+ break;
+ case 'r':
+ reuse = 1;
+ break;
+ case 'c':
+ compat = 1;
+ break;
case 'd':
debugging = 1;
break;
* Main code beginning
*
* ***********************************************************/
- /* install SIGCHLD handler */
- Signal(SIGCHLD, HandSigCHLD); /* establish handler */
- /* create socket */
- if ( (list_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
- perror("Socket creation error");
- exit(1);
- }
- /* initialize address */
- memset((void *)&serv_add, 0, sizeof(serv_add)); /* clear server address */
- serv_add.sin_family = AF_INET; /* address type is INET */
- serv_add.sin_port = htons(7); /* echo port is 7 */
- serv_add.sin_addr.s_addr = htonl(INADDR_ANY); /* connect from anywhere */
- /* bind socket */
- if (bind(list_fd, (struct sockaddr *)&serv_add, sizeof(serv_add)) < 0) {
- perror("bind error");
- exit(1);
+ /* 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 = sockbindopt(argv[optind], "echo", 6,
+ SOCK_STREAM, reuse)) < 0) {
+ return 1;
+ }
/* release privileges and go daemon */
if (setgid(65534) !=0) { /* first give away group privileges */
perror("cannot give away group privileges");
/* 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) {
+ if (conn_fd < 0) {
PrintErr("accept error");
exit(1);
}
}
if (pid == 0) { /* child */
close(list_fd); /* close listening socket */
+ if (keepalive) { /* enable keepalive ? */
+ setsockopt(conn_fd, SOL_SOCKET, SO_KEEPALIVE,
+ &keepalive, sizeof(keepalive));
+ }
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 */
printf("Usage:\n");
printf(" echod [-h] \n");
printf(" -h print this help\n");
- printf(" -d print debug info\n");
+ printf(" -d write debug info\n");
+ printf(" -k enable SO_KEEPALIVE\n");
+ printf(" -r enable SO_REUSEADDR\n");
printf(" -i use interactively\n");
+ printf(" -c disable BSD semantics\n");
+ printf(" -w N wait N sec. before calling accept\n");
exit(1);
}
/*
char buffer[MAXLINE];
int nread, nwrite;
char debug[MAXLINE+20];
- int size;
/* main loop, reading 0 char means client close connection */
while ( (nread = read(sockfd, buffer, MAXLINE)) != 0) {
+ 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);
* routine to print error on stout or syslog
*/
void PrintErr(char * error) {
- if (demonize) { /* daemon mode */
- syslog(LOG_ERR, error);
+ if (demonize) { /* daemon mode */
+ syslog(LOG_ERR, "%s: %m", error); /* log string and error message */
} else {
perror(error);
}