|
|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T c
Length: 6606 (0x19ce)
Types: TextFile
Names: »client.c«
└─⟦a0efdde77⟧ Bits:30001252 EUUGD11 Tape, 1987 Spring Conference Helsinki
└─⟦this⟧ »EUUGD11/euug-87hel/sec8/inet/client.c«
#include <stdio.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <net/if.h>
extern void request_service();
/*
* These variables may be accessed externally in order to verify that
* further messages received on the socket are actually being sent by
* the same server. This may easily be done using the command:
*
* bcmp( (char *) &server_addr, (char *) &addr, server_addr_size )
*/
struct sockaddr_in server_addr;
int server_addr_size = sizeof(server_addr);
/*
* int obtain_service( char *name, int port, int timeout_sec,
* char *request, int request_size )
*
* Sends a broadcast message over the net asking for the existence
* of a server socket on the given port associated with the named
* service. The port argument is a default port number if the service
* is not found in the local net DB. If there is no response after
* timeout_sec seconds, then we return with -1. If a response is
* received, then the socket is connected to that address and the socket
* number is returned. The socket type used is SOCK_DGRAM.
*/
int
obtain_service( serv_name, serv_port, timeout_sec, request, request_size )
char *serv_name;
int serv_port;
int timeout_sec;
char *request;
int request_size;
{
int sock;
fd_set mask;
struct timeval timeout;
struct servent *serv, *getservbyname();
struct protoent *proto, *getprotobyname();
int serv_proto = 0;
static char tbuf[64];
/* Initialize the timeout structure */
timeout.tv_sec = timeout_sec;
timeout.tv_usec = 0;
/* Get service information */
serv_port = htons(serv_port);
if ( (serv = getservbyname( serv_name, (char *) 0 )) != NULL ) {
serv_port = serv->s_port;
#ifdef PROTO_SUPPORTED
if ( (proto = getprotobyname(serv->s_proto)) != NULL )
serv_proto = proto->p_proto;
#endif PROTO_SUPPORTED
}
#ifdef DEBUG
printf( "Access port %d and proto %d\n", ntohs(serv_port), serv_proto );
fflush(stdout);
#endif DEBUG
/* Initialize the socket */
if ( (sock = socket( AF_INET, SOCK_DGRAM, serv_proto )) < 0 ) {
perror( "creating socket to server" );
exit(1);
}
/* Make the request */
printf( "[Request service ..." ); fflush(stdout);
request_service( sock, serv_port, request, request_size );
/* Now, wait for some response */
FD_ZERO(&mask);
FD_SET(sock,&mask);
if ( select(FD_SETSIZE,&mask,(fd_set *)0,(fd_set *)0,&timeout) <= 0 ||
!FD_ISSET( sock, &mask ) ) {
printf( " timed out]\n" ); fflush(stdout);
return -1;
}
/* We got a response (YAY!) */
printf( " answered..." ); fflush(stdout);
/* So, peek at the response (to get address) */
if ( recvfrom( sock, tbuf, sizeof(tbuf), MSG_PEEK,
&server_addr, &server_addr_size ) < 0 ) {
perror( "receive initial response" );
exit(1);
}
#ifdef DEBUG
printf( "[by %s %d]...",
inet_ntoa(server_addr.sin_addr), ntohs(server_addr.sin_port) );
fflush(stdout);
#endif DEBUG
/* Connect socket to the address */
if ( connect( sock, &server_addr, server_addr_size ) < 0 ) {
perror( "connect to server" );
exit(1);
}
/* Return with a happy (:-) response */
printf( " connected]\n" ); fflush(stdout);
return sock;
}
\f
/*
* int get_ifc( int sock )
*
* Put the IFCONF data structure into the ifc structure and return
* the number of ifreq structures it contains.
*/
static struct ifconf ifc;
int
get_ifc( sock )
int sock;
{
static char ifc_buffer[BUFSIZ];
ifc.ifc_len = sizeof(ifc_buffer);
ifc.ifc_buf = ifc_buffer;
if ( (ioctl( sock, SIOCGIFCONF, (char *) &ifc )) < 0 ) {
perror( "get ifconf" );
exit(1);
}
return ifc.ifc_len / sizeof(struct ifreq);
}
\f
/*
* request_service( int sock, int port, char *data, int data_len )
*
* This function broadcasts a request for the given service using
* the socket sock. The request is directed at servers on the named
* port on all machines in the local INET network.
*/
void
request_service( sock, port, data, data_len )
int sock;
int port;
char *data;
int data_len;
{
struct sockaddr_in sin;
struct sockaddr dst;
int off = 0, on = 1;
int n;
struct ifreq *ifr;
/* Set socket for broadcast mode */
if ( (setsockopt( sock,SOL_SOCKET,SO_BROADCAST,&on,sizeof(on) )) < 0 ) {
perror( "set socket option for broadcast" );
exit(1);
}
/* Initialize broadcast address and bind socket to it */
sin.sin_family = AF_INET;
sin.sin_port = port;
sin.sin_addr.s_addr = htonl(INADDR_ANY);
bind( sock, (struct sockaddr *) &sin, sizeof(sin) );
for ( n = get_ifc(sock), ifr = ifc.ifc_req; n > 0; --n, ++ifr ) {
/* Only deal with AF_INET networks */
if ( ifr->ifr_addr.sa_family != AF_INET ) continue;
/* Use the current address by default */
bzero( (char *) &dst, sizeof(dst) );
bcopy( (char *)&ifr->ifr_addr, (char *)&dst, sizeof(ifr->ifr_addr) );
/* Get the flags */
if ( ioctl( sock, SIOCGIFFLAGS, (char *) ifr ) < 0 ) {
perror( "get ifr flags" );
exit(1);
}
/* Skip unusable cases */
if ( !(ifr->ifr_flags & IFF_UP) || /* If not up, OR */
(ifr->ifr_flags & IFF_LOOPBACK ) || /* if loopback, OR */
!(ifr->ifr_flags & (IFF_BROADCAST | IFF_POINTOPOINT)) )
continue;
/* Now, determine the address to send to */
if ( ifr->ifr_flags & IFF_POINTOPOINT ) {
if ( ioctl( sock, SIOCGIFDSTADDR, (char *) ifr ) < 0 ) {
perror( "get ifr destination address" );
exit(1);
}
bcopy( (char *) &ifr->ifr_dstaddr,
(char *) &dst,
sizeof(ifr->ifr_dstaddr) );
}
if ( ifr->ifr_flags & IFF_BROADCAST ) {
if ( ioctl( sock, SIOCGIFBRDADDR, (char *) ifr ) < 0 ) {
perror( "get ifr broadcast address" );
exit(1);
}
bcopy( (char *) &ifr->ifr_broadaddr,
(char *) &dst,
sizeof(ifr->ifr_broadaddr) );
}
/* ... make sure that the port number is OK */
if ( dst.sa_family == AF_INET ) {
struct sockaddr_in *sa_in = (struct sockaddr_in *) &dst;
sa_in->sin_port = port;
#ifdef DEBUG
printf( "Request address = %s (%d)\n",
inet_ntoa(sa_in->sin_addr), ntohs(port) );
fflush(stdout);
#endif DEBUG
}
/* ... and send the request */
if ( sendto( sock, data, data_len, 0,
(struct sockaddr *) &dst, sizeof(dst) ) < 0 ) {
perror( "sendto" );
exit(1);
}
}
/* Reset socket option to normal operation */
if ( (setsockopt( sock,SOL_SOCKET,SO_BROADCAST,&off,sizeof(off) )) < 0 ) {
perror( "reset socket option for no broadcast" );
exit(1);
}
}