Thursday, September 27, 2007

Richard Stevens My Hero

In my earlier days, I was a struggling programmer. Not married and had plenty of time to learn things. What struck me in those days was the beauty of Unix and the ugliness of Windows (things have not changed even today). What helped me the most in my quest for knowledge was the book "Unix Network Programming" by Richard Stevens. Stevens died in 1999, at the age of 48. In 2000, he was posthumously awarded the Usenix Lifetime Achievement Award. May his soul rest in peace and may god give happiness to all his loved ones. If I have a hero other than Dr Abdul Kalam, it is Richard Stevens and D.J Bernstein who has written the world's first flawless software called qmail all written in the C Programming Language. When I wrote my first socket program way back in 1995 I used Richard Steven's tcp_open(). All aspiring C Programmers and Unix enthusiasts should read each and every book by Richard Stevens. Since the time I read this function in his book, it is being used even today in all my programs involving TCP connections. Here it is

/*
* $Log: tcpopen.c,v $
* Revision 2.2 2002-12-11 10:28:57+05:30 Cprogrammer
* added ERESTART check for errno
*
* Revision 2.1 2002-12-02 21:48:45+05:30 Cprogrammer
* added check for in_addr_t
*
* Revision 1.5 2002-03-03 15:40:47+05:30 Cprogrammer
* changed strncpy to scopy
*
* Revision 1.4 2001-12-19 16:29:10+05:30 Cprogrammer
* added code to bind on unix domain sockets
*
* Revision 1.3 2001-12-13 11:52:27+05:30 Cprogrammer
* variable for inaddr changed to in_addr_t
*
* Revision 1.2 2001-12-11 11:32:53+05:30 Cprogrammer
* inclusion of systeminfo.h for solaris
*
* Revision 1.1 2001-12-07 22:29:09+05:30 Cprogrammer
* Initial revision
*
*/

#ifndef lint
static char sccsid[] = "$Id: tcpopen.c,v 2.2 2002-12-11 10:28:57+05:30 Cprogrammer Stab root $";
#endif

#include "stdlib.h"
#include "netdb.h"
#include "unistd.h"
#include "netinet/in.h"
#include "arpa/inet.h"
#include "string.h"
#include "errno.h"
#include "sys/param.h"
#include "sys/types.h"
#include "sys/socket.h"
#include "sys/un.h"
#ifdef sun
#include "sys/systeminfo.h"
#endif


static unsigned sleeptime = MAXSLEEP + 1; /*- 0 for infinite connect */

int
tcpopen(host, service, port) /*- Thanks to Richard's Steven */
char *host;
char *service;
int port;
/*-
* host - Name or dotted decimal address of the
* other system / Pathname for a unix domain socket
* service - Name of the service being requested.
* Can be NULL, if port > 0.
* port - if == 0, nothin special, use port# of the service.
* if <> 0, it is the port# of server (host-byte-order)
*/
{
int resvport, fd, optval, retval;
char *ptr, *hostptr;
#ifdef HAVE_IN_ADDR_T
in_addr_t inaddr;
#else
unsigned long inaddr;
#endif
struct servent *sp;
struct hostent *hp;
struct sockaddr_in tcp_srv_addr;/*- server's Internet socket address */
struct sockaddr_un unixaddr; /*- server's local unix socket address */
struct servent tcp_serv_info; /*- from getservbyname */
struct hostent tcp_host_info; /*- from gethostbyname */
struct linger linger;
char *dir;
char localhost[MAXHOSTNAMELEN];

if(host && *host && ((strchr(host, '/') || ((dir = Dirname(host)) && !access(dir, F_OK)))))
{
if ((fd = socket (AF_UNIX, SOCK_STREAM, 0)) == -1)
return -1;
unixaddr.sun_family = AF_UNIX;
scopy (unixaddr.sun_path, host, sizeof(unixaddr.sun_path));
if (connect (fd, (struct sockaddr *) &unixaddr, sizeof(struct sockaddr_un) ) == -1)
return -1;
return(fd);
}
/*
* Initialize the server's Internet address structure. We'll store
* the actual 4-byte Internet address and the 2-byte port # below.
*/
(void) memset((char *) &tcp_srv_addr, 0, sizeof(tcp_srv_addr));
tcp_srv_addr.sin_family = AF_INET;
if (service != (char *) NULL)
{
if ((sp = getservbyname(service, "tcp")) == NULL)
{
errno = EINVAL;
return (-1);
}
tcp_serv_info = *sp;
if (port > 0)
tcp_srv_addr.sin_port = htons(port); /*- caller's value */
else
tcp_srv_addr.sin_port = sp->s_port; /*- service's value */
} else
if (port <= 0) { errno = EINVAL; return (-1); } else tcp_srv_addr.sin_port = htons(port); #ifdef sun if (sysinfo(SI_HOSTNAME, localhost, MAXHOSTNAMELEN) > MAXHOSTNAMELEN)
#else
if (gethostname(localhost, MAXHOSTNAMELEN))
#endif
return (-1);
if (!strcmp(host, localhost) || !strcmp(host, "localhost"))
hostptr = "localhost";
else
hostptr = host;
/*
* First try to convert the hostname as the dotted decimal number.
* Only if that fails, call gethostbyname.
*/
if ((inaddr = inet_addr(hostptr)) != INADDR_NONE)
{ /*- It's a dotted decimal */
(void) memcpy((char *) &tcp_srv_addr.sin_addr, (char *) &inaddr, sizeof(inaddr));
tcp_host_info.h_name = NULL;
} else
if ((hp = gethostbyname(hostptr)) == NULL)
{
errno = EINVAL;
return (-1);
} else
{
tcp_host_info = *hp; /*- found it by name, structure copy */
(void) memcpy((char *) &tcp_srv_addr.sin_addr, hp->h_addr, hp->h_length);
}
if ((ptr = (char *) getenv("SLEEPTIME")) != (char *) 0)
{
if (isnum(ptr))
sleeptime = atoi(ptr);
else
{
errno = EINVAL;
return (-1);
}
}
for (;;)
{
if (port >= 0)
{
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < resvport =" IPPORT_RESERVED" fd =" rresvport(&resvport))" optval =" 1;" errno =" 0;;)" retval =" connect(fd," errno ="="" errno ="="" errno ="="" errno =" ECONNREFUSED;" errno =" ECONNREFUSED;" errno ="="" optval =" errno;" errno =" optval;" errno =" 0;;)" l_onoff =" 1;" l_linger =" 1;">
#include
#include
#include

/* set the socket buffer sizes */
int
setsockbuf(fd, option, size)
int fd, option, size;
{
int len, retrycount;

len = size;
for (retrycount = 0; retrycount < MAXNOBUFRETRY; retrycount++)
{
if (setsockopt(fd, SOL_SOCKET, option, (void *) &len, sizeof(int)) == -1)
{
if (errno == ENOBUFS)
{
usleep(1000);
continue;
}
close(fd);
return (-1);
}
break;
}
return (errno = 0);
}

#include "ctype.h"

int
isnum(str)
char *str;
{
char *ptr;

for (ptr = str; *ptr; ptr++)
if (!isdigit((int) *ptr))
return (0);
return (1);
}

No comments: