Nearly everyone that I know enjoys reading the little messages that are enclosed in fortune cookies. Fortune cookies are so popular that the computer equivalent, the fortune program, has become a standard feature of nearly every variant of UNIX.
Most variants of UNIX have a small but entertaining fortune cookie database pre-installed. Additional fortune cookie files have been posted to USENET over the years, and a large collection is on-line at UUNET. As a result, a dedicated fortune cookie fan can accumulate a rather large amount of fortune cookie data. This can become a real problem when your site has a large number of UNIX machines. It is a time sink to have to update a lot of machines, and it also consumes a great deal of disk space to have a cookie database replicated on a number of different machines.
The obvious solution to the fortune cookie problem is to have a centralized fortune cookie repository, and a tool that can access this cookie warehouse from across the network. The remainder of this document describes the implementation of just such a system.
The cookie protocol is very simple—the client sends a single one character message to the server, and the server sends back a single message up to 64K in length. The cookie service runs from the Internet Super-daemon (inetd) on UDP port #17.
/* *** ------------------------------------------------------------ *** */
/* *** File: cookied.c *** */
/* *** ------------------------------------------------------------ *** */
/* *** Written by Bart Massey *** */
/* *** Bug fix by Chris McNeil *** */
#include <stdio.h>
#include <syslog.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define FORTUNEBUFSIZE (64 * 1024)
char fbp[ FORTUNEBUFSIZE ];
/* *** Change this definition to match your local system *** */
#define FORTUNEPROG "/usr/games/fortune -a"
/* *** ------------------------------------------------------------ *** */
/* *** Main Procedure: respond to cookie requests from the network *** */
/* *** ------------------------------------------------------------ *** */
main( argc, argv )
int argc;
char **argv;
{
int i;
FILE *pfile;
int fromlen;
struct sockaddr_in from;
fromlen = sizeof( from );
/* *** Read the one character request from the client *** */
/* *** Specific content is ignored *** */
if ( recvfrom( 0, fbp, FORTUNEBUFSIZE, 0, (struct sockaddr *) &from,
&fromlen ) == -1 )
{
exit( 1 );
}
/* *** Connect with the local fortune cookie program *** */
/* *** via a pipe connection. *** */
pfile = popen( FORTUNEPROG, "r" );
if ( !pfile )
{
exit( 1 );
}
/* *** Read the fortune from the pipe char by char and save in a buffer *** */
for ( i = 0; FORTUNEBUFSIZE; )
{
fbp[i] = getc( pfile );
if ( fbp[i] == EOF )
{
fbp[i] = '\0';
break;
}
i++;
}
pclose( pfile );
/* *** Send the cookie buffer back to the client in one shot *** */
sendto( 0, fbp, i + 1, 0, &from, fromlen );
exit( 0 );
}
/* *** ------------------------------------------------------------ *** */
/* *** End Of File: cookied.c *** */
/* *** ------------------------------------------------------------ *** */
/* *** ------------------------------------------------------------ *** */
/* *** File: rcookie.c *** */
/* *** ------------------------------------------------------------ *** */
/* *** Written by John Weeks *** */
/* *** Based on UCB "rdate" command *** */
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#define FORTUNEBUFSIZE (64 * 1024)
char buf[ FORTUNEBUFSIZE ];
/* *** Change this to be your local cookie server *** */
#define DEFAULTHOST "abc.yourhost.com"
/* *** ------------------------------------------------------------ *** */
/* *** Main Procedure: check args and locate host name *** */
/* *** ------------------------------------------------------------ *** */
main ( argc, argv )
int argc;
char *argv[];
{
if ( argc == 1 )
DoRemoteCookie( DEFAULTHOST );
else
DoRemoteCookie( argv[1] );
}
/* *** ------------------------------------------------------------ *** */
/* *** DoRemoteCookie: contact remote cookie server & get fortune *** */
/* *** ------------------------------------------------------------ *** */
int DoRemoteCookie( host )
char *host;
{
struct hostent *hname; /* /etc/hosts table entry */
struct servent *sname; /* /etc/service file entry */
struct sockaddr_in socaddr; /* socket address */
int soc; /* network file descriptor */
/* *** Look up the host name in /etc/hosts or via DNS *** */
if ( ( hname = gethostbyname( host ) ) == NULL )
{
fprintf( stderr, "rcookie: Unknown host %s\n", host );
return( -1 );
}
/* *** Look up the cookie service in /etc/services *** */
if ( ( sname = getservbyname( "cookie", "udp" ) ) == NULL )
{
fprintf( stderr, "rcookie: cookie/udp: unknown service\n" );
return( -1 );
}
/* *** Open a network socket, type DGRAM since service is UDP *** */
if ( ( soc = socket( AF_INET, SOCK_DGRAM, 0, 0 ) ) < 0 )
{
perror( "rcookie" );
return( -1 );
}
/* *** Set up network structures in preparation for connect call *** */
socaddr.sin_family = hname->h_addrtype;
bcopy( hname->h_addr, (caddr_t) &socaddr.sin_addr, hname->h_length );
socaddr.sin_port = sname->s_port;
/* *** Connect to the cookie daemon on remote host *** */
if ( connect( soc, (caddr_t) &socaddr, sizeof( socaddr ), 0 ) < 0 )
{
perror( "cookie" );
close( soc );
return( -1 );
}
/* *** Write anything to the cookie daemon to wake it up *** */
if ( write( soc, "x", 1 ) != 1 )
{
perror( "rcookie" );
close( soc );
return( -1 );
}
/* *** Read the returned fortune cookie into a buffer *** */
if ( read( soc, &buf[ 0 ], FORTUNEBUFSIZE ) < 1 )
{
perror( "rcookie" );
close( soc );
return( -1);
}
/* *** Send the fortune cookie in buffer out to screen *** */
printf( "%s", buf );
/* *** Close socket before exiting, then return good completion code *** */
close( soc );
return( 0 );
}
/* *** ------------------------------------------------------------ *** */
/* *** End Of File: rcookie.c *** */
/* *** ------------------------------------------------------------ *** */
Return To John Weeks Hobby Page
Return To John Weeks Home Page
Authored by John A. Weeks III, Copyright © 1997, all rights reserved.
For further information, contact:
john@johnweeks.com