1997-05-03 19:18:21 +00:00
|
|
|
/* This is a simple name server for GNUstep Distributed Objects
|
1998-03-10 19:01:24 +00:00
|
|
|
Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
|
1997-05-03 19:18:21 +00:00
|
|
|
|
|
|
|
Written by: Richard Frith-Macdonald <richard@brainstorm.co.uk>
|
|
|
|
Created: October 1996
|
|
|
|
|
|
|
|
This file is part of the GNUstep Base Library.
|
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
|
|
modify it under the terms of the GNU Library General Public
|
|
|
|
License as published by the Free Software Foundation; either
|
|
|
|
version 2 of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
This library 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
|
|
|
|
Library General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU Library General Public
|
|
|
|
License along with this library; if not, write to the Free
|
1999-09-09 02:56:20 +00:00
|
|
|
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA.
|
1997-05-03 19:18:21 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#ifndef __WIN32__
|
|
|
|
#include <unistd.h> /* for gethostname() */
|
|
|
|
#include <sys/param.h> /* for MAXHOSTNAMELEN */
|
|
|
|
#include <sys/types.h>
|
1997-09-01 21:59:51 +00:00
|
|
|
#include <netinet/in.h>
|
1997-05-03 19:18:21 +00:00
|
|
|
#include <arpa/inet.h> /* for inet_ntoa() */
|
|
|
|
#endif /* !__WIN32__ */
|
|
|
|
#include <errno.h>
|
|
|
|
#include <limits.h>
|
|
|
|
#include <string.h> /* for strchr() */
|
1999-06-24 19:30:29 +00:00
|
|
|
#include <ctype.h> /* for strchr() */
|
1997-05-03 19:18:21 +00:00
|
|
|
#ifndef __WIN32__
|
|
|
|
#include <sys/time.h>
|
|
|
|
#include <sys/resource.h>
|
|
|
|
#include <netdb.h>
|
|
|
|
#include <signal.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <sys/socket.h>
|
1997-09-01 21:59:51 +00:00
|
|
|
#include <sys/file.h>
|
1997-05-03 19:18:21 +00:00
|
|
|
/*
|
|
|
|
* Stuff for setting the sockets into non-blocking mode.
|
|
|
|
*/
|
|
|
|
#ifdef __POSIX_SOURCE
|
|
|
|
#define NBLK_OPT O_NONBLOCK
|
|
|
|
#else
|
|
|
|
#define NBLK_OPT FNDELAY
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <netinet/in.h>
|
|
|
|
#include <net/if.h>
|
|
|
|
#ifndef SIOCGIFCONF
|
|
|
|
#include <sys/ioctl.h>
|
|
|
|
#ifndef SIOCGIFCONF
|
|
|
|
#include <sys/sockio.h>
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
1998-05-29 15:25:41 +00:00
|
|
|
#if defined(__svr4__)
|
|
|
|
#include <sys/stropts.h>
|
|
|
|
#endif
|
1997-05-03 19:18:21 +00:00
|
|
|
#endif /* !__WIN32__ */
|
|
|
|
|
|
|
|
#include "gdomap.h"
|
|
|
|
/*
|
|
|
|
* ABOUT THIS PROGRAM
|
|
|
|
*
|
|
|
|
* This is a simple name server for GNUstep Distributed Objects
|
|
|
|
* The server program listens on a well known port (service name 'gdomap')
|
|
|
|
*
|
|
|
|
* The officially assigned port is 538. On most systems port numbers
|
|
|
|
* under 1024 can only be used by root (for security). So this program
|
|
|
|
* needs to be run as root.
|
|
|
|
*
|
|
|
|
* This is UNIX code - I have no idea how portable to other OSs it may be.
|
|
|
|
*
|
|
|
|
* For detailed information about the communication protocol used - see
|
|
|
|
* the include file.
|
|
|
|
*/
|
|
|
|
|
1998-02-03 14:20:00 +00:00
|
|
|
/* For IRIX machines, which don't define this */
|
|
|
|
#ifndef IPPORT_USERRESERVED
|
|
|
|
#define IPPORT_USERRESERVED 5000
|
|
|
|
#endif /* IPPORT_USERRESERVED */
|
|
|
|
|
1997-05-03 19:18:21 +00:00
|
|
|
#define QUEBACKLOG (16) /* How many coonections to queue. */
|
|
|
|
#define MAX_IFACE (256) /* How many network interfaces. */
|
|
|
|
#define IASIZE (sizeof(struct in_addr))
|
|
|
|
|
1998-02-26 17:55:42 +00:00
|
|
|
#define MAX_EXTRA ((GDO_NAME_MAX_LEN - 2 * IASIZE)/IASIZE)
|
|
|
|
|
1998-10-27 20:58:22 +00:00
|
|
|
typedef unsigned char *uptr;
|
1997-05-03 19:18:21 +00:00
|
|
|
int debug = 0; /* Extra debug logging. */
|
2000-02-22 08:32:04 +00:00
|
|
|
int nobcst = 0; /* turn off broadcast probing. */
|
1997-05-03 19:18:21 +00:00
|
|
|
int nofork = 0; /* turn off fork() for debugging. */
|
1997-09-01 21:59:51 +00:00
|
|
|
int noprobe = 0; /* turn off probe for unknown servers. */
|
1999-08-21 05:29:10 +00:00
|
|
|
int interval = 600; /* Minimum time (sec) between probes. */
|
2000-02-21 22:01:08 +00:00
|
|
|
char *pidfile = NULL; /* file to write PID to */
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
|
|
int udp_sent = 0;
|
|
|
|
int tcp_sent = 0;
|
|
|
|
int udp_read = 0;
|
|
|
|
int tcp_read = 0;
|
1997-05-03 19:18:21 +00:00
|
|
|
|
1998-02-26 17:55:42 +00:00
|
|
|
long last_probe;
|
|
|
|
struct in_addr loopback;
|
|
|
|
|
1997-05-03 19:18:21 +00:00
|
|
|
unsigned short my_port; /* Set in init_iface() */
|
|
|
|
|
1998-02-26 17:55:42 +00:00
|
|
|
unsigned long class_a_net;
|
|
|
|
struct in_addr class_a_mask;
|
|
|
|
unsigned long class_b_net;
|
|
|
|
struct in_addr class_b_mask;
|
|
|
|
unsigned long class_c_net;
|
|
|
|
struct in_addr class_c_mask;
|
|
|
|
|
1997-05-03 19:18:21 +00:00
|
|
|
/*
|
|
|
|
* Predeclare some of the functions used.
|
|
|
|
*/
|
1997-09-01 21:59:51 +00:00
|
|
|
static void dump_stats();
|
1997-05-03 19:18:21 +00:00
|
|
|
static void handle_accept();
|
|
|
|
static void handle_io();
|
|
|
|
static void handle_read(int);
|
|
|
|
static void handle_recv();
|
|
|
|
static void handle_request(int);
|
1997-09-01 21:59:51 +00:00
|
|
|
static void handle_send();
|
1997-05-03 19:18:21 +00:00
|
|
|
static void handle_write(int);
|
|
|
|
static void init_iface();
|
1998-05-29 15:25:41 +00:00
|
|
|
static void load_iface(const char* from);
|
1997-05-03 19:18:21 +00:00
|
|
|
static void init_ports();
|
|
|
|
static void init_probe();
|
1998-10-27 20:58:22 +00:00
|
|
|
static void queue_msg(struct sockaddr_in* a, uptr d, int l);
|
1997-09-01 21:59:51 +00:00
|
|
|
static void queue_pop();
|
1998-02-26 17:55:42 +00:00
|
|
|
static void queue_probe(struct in_addr* to, struct in_addr *from, int num_extras, struct in_addr* extra, int is_reply);
|
1997-05-03 19:18:21 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* I have simple mcopy() and mzero() implementations here for the
|
|
|
|
* present because there seems to be a bug in the gcc 2.7.2.1
|
|
|
|
* memcpy() and memset() on SunOS 4.1.3 for sparc!
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
mcopy(void* p0, void* p1, int l)
|
|
|
|
{
|
1998-10-29 16:20:53 +00:00
|
|
|
uptr b0 = (uptr)p0;
|
|
|
|
uptr b1 = (uptr)p1;
|
|
|
|
int i;
|
1997-05-03 19:18:21 +00:00
|
|
|
|
1998-10-29 16:20:53 +00:00
|
|
|
for (i = 0; i < l; i++)
|
|
|
|
{
|
|
|
|
b0[i] = b1[i];
|
1997-05-03 19:18:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
mzero(void* p, int l)
|
|
|
|
{
|
1998-10-29 16:20:53 +00:00
|
|
|
uptr b = (uptr)p;
|
1997-05-03 19:18:21 +00:00
|
|
|
|
1998-10-29 16:20:53 +00:00
|
|
|
while (l > 0)
|
|
|
|
{
|
|
|
|
*b++ = '\0';
|
|
|
|
l--;
|
1997-05-03 19:18:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1998-03-10 19:01:24 +00:00
|
|
|
/*
|
|
|
|
* Structure for linked list of addresses to probe rather than
|
|
|
|
* probing entire network.
|
|
|
|
*/
|
|
|
|
typedef struct plstruct {
|
1998-10-29 16:20:53 +00:00
|
|
|
struct plstruct *next;
|
|
|
|
int direct;
|
|
|
|
struct in_addr addr;
|
1998-03-10 19:01:24 +00:00
|
|
|
} plentry;
|
|
|
|
|
|
|
|
static plentry *plist = 0;
|
|
|
|
|
1997-05-03 19:18:21 +00:00
|
|
|
/*
|
|
|
|
* Variables used for determining if a connection is from a process
|
|
|
|
* on the local host.
|
|
|
|
*/
|
1998-02-26 17:55:42 +00:00
|
|
|
int interfaces = 0; /* Number of interfaces. */
|
|
|
|
struct in_addr *addr; /* Address of each interface. */
|
2000-02-22 08:32:04 +00:00
|
|
|
unsigned char *bcok; /* Broadcast OK for interface? */
|
|
|
|
struct in_addr *bcst; /* Broadcast for interface. */
|
1998-02-26 17:55:42 +00:00
|
|
|
struct in_addr *mask; /* Netmask of each interface. */
|
1997-05-03 19:18:21 +00:00
|
|
|
|
|
|
|
static int
|
|
|
|
is_local_host(struct in_addr a)
|
|
|
|
{
|
1998-10-29 16:20:53 +00:00
|
|
|
int i;
|
1997-05-03 19:18:21 +00:00
|
|
|
|
1998-10-29 16:20:53 +00:00
|
|
|
for (i = 0; i < interfaces; i++)
|
|
|
|
{
|
|
|
|
if (a.s_addr == addr[i].s_addr)
|
|
|
|
{
|
1998-12-05 06:50:15 +00:00
|
|
|
return 1;
|
1997-05-03 19:18:21 +00:00
|
|
|
}
|
|
|
|
}
|
1998-12-05 06:50:15 +00:00
|
|
|
return 0;
|
1997-05-03 19:18:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
is_local_net(struct in_addr a)
|
|
|
|
{
|
1998-10-29 16:20:53 +00:00
|
|
|
int i;
|
1997-05-03 19:18:21 +00:00
|
|
|
|
1998-10-29 16:20:53 +00:00
|
|
|
for (i = 0; i < interfaces; i++)
|
|
|
|
{
|
2000-02-22 08:32:04 +00:00
|
|
|
if ((mask[i].s_addr && addr[i].s_addr) == (mask[i].s_addr && a.s_addr))
|
1998-10-29 16:20:53 +00:00
|
|
|
{
|
1998-12-05 06:50:15 +00:00
|
|
|
return 1;
|
1997-05-03 19:18:21 +00:00
|
|
|
}
|
|
|
|
}
|
1998-12-05 06:50:15 +00:00
|
|
|
return 0;
|
1997-05-03 19:18:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Variables used for handling non-blocking I/O on channels.
|
|
|
|
*/
|
|
|
|
int tcp_desc = -1; /* Socket for incoming TCP connections. */
|
|
|
|
int udp_desc = -1; /* Socket for UDP communications. */
|
|
|
|
fd_set read_fds; /* Descriptors which are readable. */
|
|
|
|
fd_set write_fds; /* Descriptors which are writable. */
|
|
|
|
|
|
|
|
struct {
|
1998-10-29 16:20:53 +00:00
|
|
|
struct sockaddr_in addr; /* Address of process making request. */
|
|
|
|
int pos; /* Position reading data. */
|
|
|
|
union {
|
|
|
|
gdo_req r;
|
|
|
|
unsigned char b[GDO_REQ_SIZE];
|
|
|
|
} buf;
|
1997-05-03 19:18:21 +00:00
|
|
|
} r_info[FD_SETSIZE]; /* State of reading each request. */
|
|
|
|
|
|
|
|
struct {
|
1998-10-29 16:20:53 +00:00
|
|
|
int len; /* Length of data to be written. */
|
|
|
|
int pos; /* Amount of data already written. */
|
|
|
|
char* buf; /* Buffer for data. */
|
1997-05-03 19:18:21 +00:00
|
|
|
} w_info[FD_SETSIZE];
|
|
|
|
|
1997-09-01 21:59:51 +00:00
|
|
|
struct u_data {
|
1998-10-29 16:20:53 +00:00
|
|
|
struct sockaddr_in addr; /* Address to send to. */
|
|
|
|
int pos; /* Number of bytes already sent. */
|
|
|
|
int len; /* Length of data to send. */
|
|
|
|
uptr dat; /* Data to be sent. */
|
|
|
|
struct u_data *next; /* Next message to send. */
|
1997-09-01 21:59:51 +00:00
|
|
|
} *u_queue = 0;
|
|
|
|
int udp_pending = 0;
|
1997-05-03 19:18:21 +00:00
|
|
|
|
|
|
|
/*
|
1997-09-01 21:59:51 +00:00
|
|
|
* Name - queue_msg()
|
|
|
|
* Purpose - Add a message to the queue of those to be sent
|
|
|
|
* on the UDP socket.
|
1997-05-03 19:18:21 +00:00
|
|
|
*/
|
1997-09-01 21:59:51 +00:00
|
|
|
void
|
1998-10-27 20:58:22 +00:00
|
|
|
queue_msg(struct sockaddr_in* a, uptr d, int l)
|
1997-05-03 19:18:21 +00:00
|
|
|
{
|
1998-10-29 16:20:53 +00:00
|
|
|
struct u_data* entry = (struct u_data*)malloc(sizeof(struct u_data));
|
|
|
|
|
|
|
|
memcpy(&entry->addr, a, sizeof(*a));
|
|
|
|
entry->pos = 0;
|
|
|
|
entry->len = l;
|
|
|
|
entry->dat = malloc(l);
|
|
|
|
memcpy(entry->dat, d, l);
|
|
|
|
entry->next = 0;
|
|
|
|
if (u_queue)
|
|
|
|
{
|
|
|
|
struct u_data* tmp = u_queue;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
1998-10-29 16:20:53 +00:00
|
|
|
while (tmp->next)
|
|
|
|
{
|
|
|
|
tmp = tmp->next;
|
|
|
|
}
|
|
|
|
tmp->next = entry;
|
1997-09-01 21:59:51 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
u_queue = entry;
|
1997-05-03 19:18:21 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
udp_pending++;
|
1997-05-03 19:18:21 +00:00
|
|
|
}
|
|
|
|
|
1997-09-01 21:59:51 +00:00
|
|
|
void
|
|
|
|
queue_pop()
|
|
|
|
{
|
1998-10-29 16:20:53 +00:00
|
|
|
struct u_data* tmp = u_queue;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
1998-10-29 16:20:53 +00:00
|
|
|
if (tmp)
|
|
|
|
{
|
|
|
|
u_queue = tmp->next;
|
|
|
|
free(tmp->dat);
|
|
|
|
free(tmp);
|
|
|
|
udp_pending--;
|
1997-09-01 21:59:51 +00:00
|
|
|
}
|
|
|
|
}
|
1997-05-03 19:18:21 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Primitive mapping stuff.
|
|
|
|
*/
|
|
|
|
unsigned short next_port = IPPORT_USERRESERVED;
|
|
|
|
|
|
|
|
typedef struct {
|
1998-10-29 16:20:53 +00:00
|
|
|
uptr name; /* Service name registered. */
|
|
|
|
unsigned int port; /* Port it was mapped to. */
|
|
|
|
unsigned short size; /* Number of bytes in name. */
|
|
|
|
unsigned char net; /* Type of port registered. */
|
|
|
|
unsigned char svc; /* Type of port registered. */
|
1997-05-03 19:18:21 +00:00
|
|
|
} map_ent;
|
|
|
|
|
|
|
|
int map_used = 0;
|
|
|
|
int map_size = 0;
|
|
|
|
map_ent **map = 0;
|
|
|
|
|
|
|
|
static int
|
1998-10-27 20:58:22 +00:00
|
|
|
compare(uptr n0, int l0, uptr n1, int l1)
|
1997-05-03 19:18:21 +00:00
|
|
|
{
|
1998-10-29 16:20:53 +00:00
|
|
|
if (l0 == l1)
|
|
|
|
{
|
1998-12-05 06:50:15 +00:00
|
|
|
return memcmp(n0, n1, l0);
|
1997-05-03 19:18:21 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
else if (l0 < l1)
|
|
|
|
{
|
1998-12-05 06:50:15 +00:00
|
|
|
return -1;
|
1997-05-03 19:18:21 +00:00
|
|
|
}
|
1998-12-05 06:50:15 +00:00
|
|
|
return 1;
|
1997-05-03 19:18:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Name - map_add()
|
|
|
|
* Purpose - Create a new map entry structure and insert it
|
|
|
|
* into the map in the appropriate position.
|
|
|
|
*/
|
|
|
|
static map_ent*
|
1998-10-27 20:58:22 +00:00
|
|
|
map_add(uptr n, unsigned char l, unsigned int p, unsigned char t)
|
1997-05-03 19:18:21 +00:00
|
|
|
{
|
1998-10-29 16:20:53 +00:00
|
|
|
map_ent *m = (map_ent*)malloc(sizeof(map_ent));
|
|
|
|
int i;
|
1997-05-03 19:18:21 +00:00
|
|
|
|
1998-10-29 16:20:53 +00:00
|
|
|
m->port = p;
|
|
|
|
m->name = (char*)malloc(l);
|
|
|
|
m->size = l;
|
|
|
|
m->net = (t & GDO_NET_MASK);
|
|
|
|
m->svc = (t & GDO_SVC_MASK);
|
|
|
|
mcopy(m->name, n, l);
|
1997-05-03 19:18:21 +00:00
|
|
|
|
1998-10-29 16:20:53 +00:00
|
|
|
if (map_used >= map_size)
|
|
|
|
{
|
|
|
|
if (map_size)
|
|
|
|
{
|
|
|
|
map = (map_ent**)realloc(map, (map_size + 16)*sizeof(map_ent*));
|
|
|
|
map_size += 16;
|
1997-05-03 19:18:21 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
map = (map_ent**)calloc(16,sizeof(map_ent*));
|
|
|
|
map_size = 16;
|
1997-05-03 19:18:21 +00:00
|
|
|
}
|
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
for (i = 0; i < map_used; i++)
|
|
|
|
{
|
|
|
|
if (compare(map[i]->name, map[i]->size, m->name, m->size) > 0)
|
|
|
|
{
|
|
|
|
int j;
|
1997-05-03 19:18:21 +00:00
|
|
|
|
1998-10-29 16:20:53 +00:00
|
|
|
for (j = map_used+1; j > i; j--)
|
|
|
|
{
|
|
|
|
map[j] = map[j-1];
|
1997-05-03 19:18:21 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
break;
|
1997-05-03 19:18:21 +00:00
|
|
|
}
|
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
map[i] = m;
|
|
|
|
map_used++;
|
|
|
|
if (debug > 2)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "Added port %d to map for %.*s\n",
|
1997-09-01 21:59:51 +00:00
|
|
|
m->port, m->size, m->name);
|
|
|
|
}
|
1998-12-05 06:50:15 +00:00
|
|
|
return m;
|
1997-05-03 19:18:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Name - map_by_name()
|
|
|
|
* Purpose - Search the map for an entry for a particular name
|
|
|
|
*/
|
|
|
|
static map_ent*
|
1998-10-27 20:58:22 +00:00
|
|
|
map_by_name(uptr n, int s)
|
1997-05-03 19:18:21 +00:00
|
|
|
{
|
1998-10-29 16:20:53 +00:00
|
|
|
int lower = 0;
|
|
|
|
int upper = map_used;
|
|
|
|
int index;
|
|
|
|
|
|
|
|
if (debug > 2)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "Searching map for %.*s\n", s, n);
|
|
|
|
}
|
|
|
|
for (index = upper/2; upper != lower; index = lower + (upper - lower)/2)
|
|
|
|
{
|
|
|
|
int i = compare(map[index]->name, map[index]->size, n, s);
|
|
|
|
|
|
|
|
if (i < 0)
|
|
|
|
{
|
|
|
|
lower = index + 1;
|
|
|
|
}
|
|
|
|
else if (i > 0)
|
|
|
|
{
|
|
|
|
upper = index;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
break;
|
1997-05-03 19:18:21 +00:00
|
|
|
}
|
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
if (index<map_used && compare(map[index]->name,map[index]->size,n,s) == 0)
|
|
|
|
{
|
|
|
|
if (debug > 2)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "Found port %d for %.*s\n", map[index]->port, s, n);
|
1997-09-01 21:59:51 +00:00
|
|
|
}
|
1998-12-05 06:50:15 +00:00
|
|
|
return map[index];
|
1997-05-03 19:18:21 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
if (debug > 2)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "Failed to find map entry for %.*s\n", s, n);
|
1997-09-01 21:59:51 +00:00
|
|
|
}
|
1998-12-05 06:50:15 +00:00
|
|
|
return 0;
|
1997-05-03 19:18:21 +00:00
|
|
|
}
|
|
|
|
|
1998-11-02 11:48:42 +00:00
|
|
|
/*
|
|
|
|
* Name - map_by_port()
|
|
|
|
* Purpose - Search the map for an entry for a particular port
|
|
|
|
*/
|
|
|
|
static map_ent*
|
|
|
|
map_by_port(unsigned p, unsigned char t)
|
|
|
|
{
|
|
|
|
int index;
|
|
|
|
|
|
|
|
if (debug > 2)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "Searching map for %u:%x\n", p, t);
|
|
|
|
}
|
|
|
|
for (index = 0; index < map_used; index++)
|
|
|
|
{
|
|
|
|
map_ent *e = map[index];
|
|
|
|
|
|
|
|
if (e->port == p && (e->net | e->svc) == t)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (index < map_used)
|
|
|
|
{
|
|
|
|
if (debug > 2)
|
|
|
|
{
|
1999-06-24 19:30:29 +00:00
|
|
|
fprintf(stderr, "Found port %d with name %s\n",
|
1998-11-02 11:48:42 +00:00
|
|
|
map[index]->port, map[index]->name);
|
|
|
|
}
|
1998-12-05 06:50:15 +00:00
|
|
|
return map[index];
|
1998-11-02 11:48:42 +00:00
|
|
|
}
|
|
|
|
if (debug > 2)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "Failed to find map entry for %u:%x\n", p, t);
|
|
|
|
}
|
1998-12-05 06:50:15 +00:00
|
|
|
return 0;
|
1998-11-02 11:48:42 +00:00
|
|
|
}
|
|
|
|
|
1997-05-03 19:18:21 +00:00
|
|
|
/*
|
|
|
|
* Name - map_del()
|
|
|
|
* Purpose - Remove a mapping entry from the map and release
|
|
|
|
* the memory it uses.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
map_del(map_ent* e)
|
|
|
|
{
|
1998-10-29 16:20:53 +00:00
|
|
|
int i;
|
1997-05-03 19:18:21 +00:00
|
|
|
|
1998-10-29 16:20:53 +00:00
|
|
|
if (debug > 2)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "Removing port %d from map for %.*s\n",
|
1997-09-01 21:59:51 +00:00
|
|
|
e->port, e->size, e->name);
|
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
for (i = 0; i < map_used; i++)
|
|
|
|
{
|
|
|
|
if (map[i] == e)
|
|
|
|
{
|
|
|
|
int j;
|
|
|
|
|
|
|
|
free(e->name);
|
|
|
|
free(e);
|
|
|
|
for (j = i + 1; j < map_used; j++)
|
|
|
|
{
|
|
|
|
map[j-1] = map[j];
|
1997-05-03 19:18:21 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
map_used--;
|
|
|
|
return;
|
1997-05-03 19:18:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Variables and functions for keeping track of the IP addresses of
|
|
|
|
* hosts which are running the name server.
|
|
|
|
*/
|
1997-09-01 21:59:51 +00:00
|
|
|
unsigned long prb_used = 0;
|
|
|
|
unsigned long prb_size = 0;
|
1998-02-26 17:55:42 +00:00
|
|
|
typedef struct {
|
1998-10-29 16:20:53 +00:00
|
|
|
struct in_addr sin;
|
|
|
|
long when;
|
1998-02-26 17:55:42 +00:00
|
|
|
} prb_type;
|
|
|
|
prb_type **prb = 0;
|
|
|
|
|
1997-05-03 19:18:21 +00:00
|
|
|
/*
|
|
|
|
* Name - prb_add()
|
1999-08-21 05:29:10 +00:00
|
|
|
* Purpose - Create a new probe entry in the list.
|
|
|
|
* The new entry is always placed at the end of the list
|
|
|
|
* so that the list remains in the order in which hosts
|
|
|
|
* have been contancted.
|
1997-05-03 19:18:21 +00:00
|
|
|
*/
|
1998-02-26 17:55:42 +00:00
|
|
|
static void
|
1997-05-03 19:18:21 +00:00
|
|
|
prb_add(struct in_addr *p)
|
|
|
|
{
|
1999-08-21 05:29:10 +00:00
|
|
|
prb_type *n = 0;
|
1998-10-29 16:20:53 +00:00
|
|
|
int i;
|
1997-05-03 19:18:21 +00:00
|
|
|
|
1998-10-29 16:20:53 +00:00
|
|
|
if (is_local_host(*p) != 0)
|
|
|
|
{
|
|
|
|
return;
|
1998-02-26 17:55:42 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
if (is_local_net(*p) == 0)
|
|
|
|
{
|
|
|
|
return;
|
1998-02-26 17:55:42 +00:00
|
|
|
}
|
|
|
|
|
1999-08-21 05:29:10 +00:00
|
|
|
/*
|
|
|
|
* If we already have an entry for this address, remove it from the list
|
|
|
|
* ready for re-insertion in the correct place.
|
|
|
|
*/
|
|
|
|
for (i = 0; i < prb_used; i++)
|
1998-10-29 16:20:53 +00:00
|
|
|
{
|
1999-08-21 05:29:10 +00:00
|
|
|
if (memcmp(&prb[i]->sin, p, IASIZE) == 0)
|
|
|
|
{
|
|
|
|
n = prb[i];
|
|
|
|
for (i++; i < prb_used; i++)
|
|
|
|
{
|
|
|
|
prb[i-1] = prb[i];
|
|
|
|
}
|
|
|
|
prb_used--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Create a new entry structure if necessary.
|
|
|
|
* Set the current time in the structure, so we know when we last had contact.
|
|
|
|
*/
|
|
|
|
if (n == 0)
|
|
|
|
{
|
|
|
|
n = (prb_type*)malloc(sizeof(prb_type));
|
|
|
|
n->sin = *p;
|
1998-02-26 17:55:42 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
n->when = time(0);
|
1997-05-03 19:18:21 +00:00
|
|
|
|
1999-08-21 05:29:10 +00:00
|
|
|
/*
|
|
|
|
* Grow the list if we need more space.
|
|
|
|
*/
|
1998-10-29 16:20:53 +00:00
|
|
|
if (prb_used >= prb_size)
|
|
|
|
{
|
|
|
|
int size = (prb_size + 16) * sizeof(prb_type*);
|
1997-05-03 19:18:21 +00:00
|
|
|
|
1998-10-29 16:20:53 +00:00
|
|
|
if (prb_size)
|
|
|
|
{
|
|
|
|
prb = (prb_type**)realloc(prb, size);
|
|
|
|
prb_size += 16;
|
1997-05-03 19:18:21 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
prb = (prb_type**)malloc(size);
|
|
|
|
prb_size = 16;
|
1997-05-03 19:18:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-08-21 05:29:10 +00:00
|
|
|
/*
|
|
|
|
* Append the new item at the end of the list.
|
|
|
|
*/
|
|
|
|
prb[prb_used] = n;
|
1998-10-29 16:20:53 +00:00
|
|
|
prb_used++;
|
1997-05-03 19:18:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Name - prb_del()
|
|
|
|
* Purpose - Remove an entry from the list.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
prb_del(struct in_addr *p)
|
|
|
|
{
|
1998-10-29 16:20:53 +00:00
|
|
|
int i;
|
1997-05-03 19:18:21 +00:00
|
|
|
|
1998-10-29 16:20:53 +00:00
|
|
|
for (i = 0; i < prb_used; i++)
|
|
|
|
{
|
|
|
|
if (memcmp(&prb[i]->sin, p, IASIZE) == 0)
|
|
|
|
{
|
|
|
|
int j;
|
|
|
|
|
|
|
|
free(prb[i]);
|
|
|
|
for (j = i + 1; j < prb_used; j++)
|
|
|
|
{
|
|
|
|
prb[j-1] = prb[j];
|
1997-05-03 19:18:21 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
prb_used--;
|
|
|
|
return;
|
1997-05-03 19:18:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1998-02-26 17:55:42 +00:00
|
|
|
/*
|
1998-04-02 14:27:40 +00:00
|
|
|
* Remove any server from which we have had no messages in the last
|
|
|
|
* thirty minutes (as long as we have sent as probe in that time).
|
1998-02-26 17:55:42 +00:00
|
|
|
*/
|
|
|
|
static void
|
|
|
|
prb_tim(long when)
|
|
|
|
{
|
1998-10-29 16:20:53 +00:00
|
|
|
int i;
|
1998-02-26 17:55:42 +00:00
|
|
|
|
1998-10-29 16:20:53 +00:00
|
|
|
when -= 1800;
|
|
|
|
for (i = prb_used - 1; i >= 0; i--)
|
|
|
|
{
|
2000-02-22 08:32:04 +00:00
|
|
|
if (noprobe == 0 && prb[i]->when < when && prb[i]->when < last_probe)
|
1998-10-29 16:20:53 +00:00
|
|
|
{
|
|
|
|
prb_del(&prb[i]->sin);
|
1998-02-26 17:55:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
1997-05-03 19:18:21 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Name - clear_chan()
|
|
|
|
* Purpose - Release all resources associated with a channel
|
|
|
|
* and remove it from the list of requests being
|
|
|
|
* serviced.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
clear_chan(int desc)
|
|
|
|
{
|
1998-10-29 16:20:53 +00:00
|
|
|
if (desc >= 0 && desc < FD_SETSIZE)
|
|
|
|
{
|
|
|
|
FD_CLR(desc, &write_fds);
|
|
|
|
if (desc == tcp_desc || desc == udp_desc)
|
|
|
|
{
|
|
|
|
FD_SET(desc, &read_fds);
|
1997-05-03 19:18:21 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
FD_CLR(desc, &read_fds);
|
|
|
|
close(desc);
|
1997-05-03 19:18:21 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
if (w_info[desc].buf)
|
|
|
|
{
|
|
|
|
free(w_info[desc].buf);
|
|
|
|
w_info[desc].buf = 0;
|
1997-05-03 19:18:21 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
w_info[desc].len = 0;
|
|
|
|
w_info[desc].pos = 0;
|
|
|
|
mzero(&r_info[desc], sizeof(r_info[desc]));
|
1997-05-03 19:18:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1997-09-01 21:59:51 +00:00
|
|
|
static void
|
|
|
|
dump_stats()
|
|
|
|
{
|
1998-10-29 16:20:53 +00:00
|
|
|
int tcp_pending = 0;
|
|
|
|
int i;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
1998-10-29 16:20:53 +00:00
|
|
|
for (i = 0; i < FD_SETSIZE; i++)
|
|
|
|
{
|
|
|
|
if (w_info[i].len > 0)
|
|
|
|
{
|
|
|
|
tcp_pending++;
|
1997-09-01 21:59:51 +00:00
|
|
|
}
|
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
fprintf(stderr, "tcp messages waiting for send - %d\n", tcp_pending);
|
|
|
|
fprintf(stderr, "udp messages waiting for send - %d\n", udp_pending);
|
|
|
|
fprintf(stderr, "size of name-to-port map - %d\n", map_used);
|
1999-06-24 19:30:29 +00:00
|
|
|
fprintf(stderr, "number of known name servers - %ld\n", prb_used);
|
1998-10-29 16:20:53 +00:00
|
|
|
fprintf(stderr, "TCP %d read, %d sent\n", tcp_read, tcp_sent);
|
|
|
|
fprintf(stderr, "UDP %d read, %d sent\n", udp_read, udp_sent);
|
1997-09-01 21:59:51 +00:00
|
|
|
}
|
|
|
|
|
1997-05-03 19:18:21 +00:00
|
|
|
/*
|
|
|
|
* Name - init_iface()
|
1998-05-29 15:25:41 +00:00
|
|
|
* Purpose - Build up an array of the IP addresses supported on
|
|
|
|
* the network interfaces of this machine.
|
1997-05-03 19:18:21 +00:00
|
|
|
*/
|
|
|
|
static void
|
|
|
|
init_iface()
|
|
|
|
{
|
1998-05-29 15:25:41 +00:00
|
|
|
#ifdef SIOCGIFCONF
|
1998-10-29 16:20:53 +00:00
|
|
|
struct ifconf ifc;
|
|
|
|
struct ifreq ifreq;
|
|
|
|
struct ifreq *ifr;
|
|
|
|
struct ifreq *final;
|
|
|
|
char buf[MAX_IFACE * sizeof(struct ifreq)];
|
|
|
|
int desc;
|
|
|
|
int num_iface;
|
|
|
|
|
|
|
|
if ((desc = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
|
|
|
|
{
|
|
|
|
perror("socket for init_iface");
|
|
|
|
exit(1);
|
1997-05-03 19:18:21 +00:00
|
|
|
}
|
1998-05-29 15:25:41 +00:00
|
|
|
#if defined(__svr4__)
|
|
|
|
{
|
1998-10-29 16:20:53 +00:00
|
|
|
struct strioctl ioc;
|
1997-05-03 19:18:21 +00:00
|
|
|
|
1998-10-29 16:20:53 +00:00
|
|
|
ioc.ic_cmd = SIOCGIFCONF;
|
|
|
|
ioc.ic_timout = 0;
|
|
|
|
ioc.ic_len = sizeof(buf);
|
|
|
|
ioc.ic_dp = buf;
|
|
|
|
if (ioctl(desc, I_STR, (char*)&ioc) < 0)
|
|
|
|
{
|
|
|
|
ioc.ic_len = 0;
|
1997-05-03 19:18:21 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
ifc.ifc_len = ioc.ic_len;
|
|
|
|
ifc.ifc_buf = ioc.ic_dp;
|
1997-05-03 19:18:21 +00:00
|
|
|
}
|
1998-05-29 15:25:41 +00:00
|
|
|
#else
|
1998-10-29 16:20:53 +00:00
|
|
|
ifc.ifc_len = sizeof(buf);
|
|
|
|
ifc.ifc_buf = buf;
|
|
|
|
if (ioctl(desc, SIOCGIFCONF, (char*)&ifc) < 0)
|
|
|
|
{
|
|
|
|
ifc.ifc_len = 0;
|
1997-05-03 19:18:21 +00:00
|
|
|
}
|
1998-05-29 15:25:41 +00:00
|
|
|
#endif
|
1997-05-03 19:18:21 +00:00
|
|
|
|
1998-10-29 16:20:53 +00:00
|
|
|
/*
|
|
|
|
* Find the IP address of each active network interface.
|
|
|
|
*/
|
|
|
|
num_iface = ifc.ifc_len / sizeof(struct ifreq);
|
|
|
|
if (num_iface == 0)
|
|
|
|
{
|
|
|
|
int res = errno;
|
1998-05-29 15:25:41 +00:00
|
|
|
|
1998-10-29 16:20:53 +00:00
|
|
|
perror("SIOCGIFCONF for init_iface found no active interfaces");
|
|
|
|
if (res == EINVAL)
|
|
|
|
{
|
|
|
|
fprintf(stderr,
|
1998-05-29 15:25:41 +00:00
|
|
|
"Either you have too many network interfaces on your machine (in which case\n"
|
|
|
|
"you need to change the 'MAX_IFACE' constant in gdomap.c and rebuild it), or\n"
|
|
|
|
"your system is buggy, and you need to use the '-a' command line flag for\n"
|
|
|
|
"gdomap to manually set the interface addresses and masks to be used.\n");
|
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
close(desc);
|
|
|
|
exit(1);
|
|
|
|
}
|
2000-02-22 08:32:04 +00:00
|
|
|
if (addr != 0) free(addr);
|
1998-10-29 16:20:53 +00:00
|
|
|
addr = (struct in_addr*)malloc(num_iface*IASIZE);
|
2000-02-22 08:32:04 +00:00
|
|
|
if (bcok != 0) free(bcok);
|
|
|
|
bcok = (char*)malloc(num_iface*sizeof(char));
|
|
|
|
if (bcst != 0) free(bcst);
|
|
|
|
bcst = (struct in_addr*)malloc(num_iface*IASIZE);
|
|
|
|
if (mask != 0) free(mask);
|
1998-10-29 16:20:53 +00:00
|
|
|
mask = (struct in_addr*)malloc(num_iface*IASIZE);
|
|
|
|
|
|
|
|
final = (struct ifreq*)&ifc.ifc_buf[ifc.ifc_len];
|
|
|
|
for (ifr = ifc.ifc_req; ifr < final; ifr++)
|
|
|
|
{
|
2000-02-19 00:40:47 +00:00
|
|
|
ifreq = *ifr;
|
|
|
|
if (ioctl(desc, SIOCGIFFLAGS, (char *)&ifreq) < 0)
|
|
|
|
{
|
|
|
|
perror("SIOCGIFFLAGS");
|
|
|
|
}
|
|
|
|
else if (ifreq.ifr_flags & IFF_UP)
|
|
|
|
{ /* interface is up */
|
2000-02-22 08:32:04 +00:00
|
|
|
int broadcast = 0;
|
|
|
|
int pointopoint = 0;
|
|
|
|
|
|
|
|
if (ifreq.ifr_flags & IFF_BROADCAST)
|
|
|
|
{
|
|
|
|
broadcast = 1;
|
|
|
|
}
|
|
|
|
if (ifreq.ifr_flags & IFF_POINTOPOINT)
|
|
|
|
{
|
|
|
|
pointopoint = 1;
|
|
|
|
}
|
2000-02-19 00:40:47 +00:00
|
|
|
if (ioctl(desc, SIOCGIFADDR, (char *)&ifreq) < 0)
|
|
|
|
{
|
|
|
|
perror("SIOCGIFADDR");
|
|
|
|
}
|
|
|
|
else if (ifreq.ifr_addr.sa_family == AF_INET)
|
|
|
|
{ /* IP interface */
|
|
|
|
if (interfaces >= MAX_IFACE)
|
|
|
|
{
|
|
|
|
fprintf(stderr,
|
1998-12-05 06:50:15 +00:00
|
|
|
"You have too many network interfaces on your machine (in which case you need\n"
|
|
|
|
"to change the 'MAX_IFACE' constant in gdomap.c and rebuild it), or your\n"
|
|
|
|
"system is buggy, and you need to use the '-a' command line flag for\n"
|
|
|
|
"gdomap to manually set the interface addresses and masks to be used.\n");
|
2000-02-19 00:40:47 +00:00
|
|
|
close(desc);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
addr[interfaces] =
|
|
|
|
((struct sockaddr_in *)&ifreq.ifr_addr)->sin_addr;
|
2000-02-22 08:32:04 +00:00
|
|
|
bcok[interfaces] = (broadcast | pointopoint);
|
|
|
|
if (pointopoint)
|
|
|
|
{
|
|
|
|
if (ioctl(desc, SIOCGIFDSTADDR, (char*)&ifreq) < 0)
|
|
|
|
{
|
|
|
|
perror("SIOCGIFDSTADDR");
|
|
|
|
bcok[interfaces] = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
bcst[interfaces]
|
|
|
|
= ((struct sockaddr_in *)&ifreq.ifr_dstaddr)->sin_addr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (ioctl(desc, SIOCGIFBRDADDR, (char*)&ifreq) < 0)
|
|
|
|
{
|
|
|
|
perror("SIOCGIFBRDADDR");
|
|
|
|
bcok[interfaces] = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
bcst[interfaces]
|
|
|
|
= ((struct sockaddr_in*)&ifreq.ifr_broadaddr)->sin_addr;
|
|
|
|
}
|
|
|
|
}
|
2000-02-19 00:40:47 +00:00
|
|
|
if (ioctl(desc, SIOCGIFNETMASK, (char *)&ifreq) < 0)
|
|
|
|
{
|
|
|
|
perror("SIOCGIFNETMASK");
|
|
|
|
/*
|
|
|
|
* If we can't get a netmask - assume a class-c
|
|
|
|
* network.
|
|
|
|
*/
|
|
|
|
mask[interfaces] = class_c_mask;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
1998-02-26 17:55:42 +00:00
|
|
|
/*
|
|
|
|
* Some systems don't have ifr_netmask
|
|
|
|
*/
|
|
|
|
#ifdef ifr_netmask
|
2000-02-19 00:40:47 +00:00
|
|
|
mask[interfaces] =
|
|
|
|
((struct sockaddr_in *)&ifreq.ifr_netmask)->sin_addr;
|
1998-02-26 17:55:42 +00:00
|
|
|
#else
|
2000-02-19 00:40:47 +00:00
|
|
|
mask[interfaces] =
|
|
|
|
((struct sockaddr_in *)&ifreq.ifr_addr)->sin_addr;
|
1998-02-26 17:55:42 +00:00
|
|
|
#endif
|
2000-02-19 00:40:47 +00:00
|
|
|
}
|
|
|
|
interfaces++;
|
1997-05-03 19:18:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
close(desc);
|
1998-05-29 15:25:41 +00:00
|
|
|
#else
|
1998-10-29 16:20:53 +00:00
|
|
|
fprintf(stderr, "I can't find the SIOCGIFCONF ioctl on this platform -\r\nuse the '-a' flag to load interface details from a file instead.\r\n");
|
|
|
|
exit(1);
|
1998-05-29 15:25:41 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Name - load_iface()
|
|
|
|
* Purpose - Read addresses and netmasks for interfaces on this
|
|
|
|
* machine from a file.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
load_iface(const char* from)
|
|
|
|
{
|
1998-10-29 16:20:53 +00:00
|
|
|
FILE *fptr = fopen(from, "r");
|
|
|
|
char buf[128];
|
|
|
|
int num_iface = 0;
|
1998-05-29 15:25:41 +00:00
|
|
|
|
1998-10-29 16:20:53 +00:00
|
|
|
if (fptr == 0)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "Unable to open address config - '%s'\n", from);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
while (fgets(buf, sizeof(buf), fptr) != 0)
|
|
|
|
{
|
|
|
|
char *ptr = buf;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Strip leading white space.
|
|
|
|
*/
|
|
|
|
while (isspace(*ptr))
|
|
|
|
{
|
|
|
|
ptr++;
|
1998-05-29 15:25:41 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
if (ptr != buf)
|
|
|
|
{
|
|
|
|
strcpy(buf, ptr);
|
1998-05-29 15:25:41 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
/*
|
|
|
|
* Strip comments.
|
|
|
|
*/
|
|
|
|
ptr = strchr(buf, '#');
|
|
|
|
if (ptr)
|
|
|
|
{
|
|
|
|
*ptr = '\0';
|
1998-05-29 15:25:41 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
/*
|
|
|
|
* Strip trailing white space.
|
|
|
|
*/
|
|
|
|
ptr = buf;
|
|
|
|
while (*ptr)
|
|
|
|
{
|
|
|
|
ptr++;
|
1998-05-29 15:25:41 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
while (ptr > buf && isspace(ptr[-1]))
|
|
|
|
{
|
|
|
|
ptr--;
|
1998-05-29 15:25:41 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
*ptr = '\0';
|
|
|
|
/*
|
|
|
|
* Ignore blank lines.
|
|
|
|
*/
|
|
|
|
if (*buf == '\0')
|
|
|
|
{
|
|
|
|
continue;
|
1998-05-29 15:25:41 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
num_iface++;
|
1998-05-29 15:25:41 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
fseek(fptr, 0, 0);
|
1998-05-29 15:25:41 +00:00
|
|
|
|
1998-10-29 16:20:53 +00:00
|
|
|
if (num_iface == 0)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "No address mask pairs found in file.\n");
|
|
|
|
exit(1);
|
1998-05-29 15:25:41 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
addr = (struct in_addr*)malloc(num_iface*IASIZE);
|
|
|
|
mask = (struct in_addr*)malloc(num_iface*IASIZE);
|
1998-05-29 15:25:41 +00:00
|
|
|
|
1998-10-29 16:20:53 +00:00
|
|
|
while (fgets(buf, sizeof(buf), fptr) != 0)
|
|
|
|
{
|
|
|
|
char *ptr = buf;
|
1998-05-29 15:25:41 +00:00
|
|
|
|
1998-10-29 16:20:53 +00:00
|
|
|
/*
|
|
|
|
* Strip leading white space.
|
|
|
|
*/
|
|
|
|
while (isspace(*ptr))
|
|
|
|
{
|
|
|
|
ptr++;
|
1998-05-29 15:25:41 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
if (ptr != buf)
|
|
|
|
{
|
|
|
|
strcpy(buf, ptr);
|
1998-05-29 15:25:41 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
/*
|
|
|
|
* Strip comments.
|
|
|
|
*/
|
|
|
|
ptr = strchr(buf, '#');
|
|
|
|
if (ptr)
|
|
|
|
{
|
|
|
|
*ptr = '\0';
|
1998-05-29 15:25:41 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
/*
|
|
|
|
* Strip trailing white space.
|
|
|
|
*/
|
|
|
|
ptr = buf;
|
|
|
|
while (*ptr)
|
|
|
|
{
|
|
|
|
ptr++;
|
1998-05-29 15:25:41 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
while (ptr > buf && isspace(ptr[-1]))
|
|
|
|
{
|
|
|
|
ptr--;
|
1998-05-29 15:25:41 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
*ptr = '\0';
|
|
|
|
/*
|
|
|
|
* Ignore blank lines.
|
|
|
|
*/
|
|
|
|
if (*buf == '\0')
|
|
|
|
{
|
|
|
|
continue;
|
1998-05-29 15:25:41 +00:00
|
|
|
}
|
|
|
|
|
1998-10-29 16:20:53 +00:00
|
|
|
ptr = buf;
|
|
|
|
while (*ptr && (isdigit(*ptr) || (*ptr == '.')))
|
|
|
|
{
|
|
|
|
ptr++;
|
1998-05-29 15:25:41 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
while (isspace(*ptr))
|
|
|
|
{
|
|
|
|
*ptr++ = '\0';
|
1998-05-29 15:25:41 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
addr[interfaces].s_addr = inet_addr(buf);
|
|
|
|
mask[interfaces].s_addr = inet_addr(ptr);
|
|
|
|
if (addr[interfaces].s_addr == -1)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "'%s' is not as valid address\n", buf);
|
1998-05-29 15:25:41 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
else if (mask[interfaces].s_addr == -1)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "'%s' is not as valid netmask\n", ptr);
|
1998-05-29 15:25:41 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
interfaces++;
|
1998-05-29 15:25:41 +00:00
|
|
|
}
|
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
fclose(fptr);
|
1998-05-29 15:25:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Name - init_my_port()
|
|
|
|
* Purpose - Establish our well-known port (my_port).
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
init_my_port()
|
|
|
|
{
|
1998-10-29 16:20:53 +00:00
|
|
|
struct servent *sp;
|
1998-05-29 15:25:41 +00:00
|
|
|
|
1998-10-29 16:20:53 +00:00
|
|
|
/*
|
|
|
|
* First we determine the port for the 'gdomap' service - ideally
|
|
|
|
* this should be the default port, since we should have registered
|
|
|
|
* this with the appropriate authority and have it reserved for us.
|
|
|
|
*/
|
1998-05-29 15:25:41 +00:00
|
|
|
#ifdef GDOMAP_PORT_OVERRIDE
|
1998-10-29 16:20:53 +00:00
|
|
|
my_port = htons(GDOMAP_PORT_OVERRIDE);
|
1998-05-29 15:25:41 +00:00
|
|
|
#else
|
1998-10-29 16:20:53 +00:00
|
|
|
my_port = htons(GDOMAP_PORT);
|
|
|
|
if ((sp = getservbyname("gdomap", "tcp")) == 0)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "Warning - unable to find service 'gdomap'\n");
|
|
|
|
fprintf(stderr, "on a unix host it should be in /etc/services\n");
|
|
|
|
fprintf(stderr, "as 'gdomap %d/tcp' and 'gdomap %d/udp'\n",
|
|
|
|
GDOMAP_PORT, GDOMAP_PORT);
|
1998-05-29 15:25:41 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
unsigned short tcp_port = sp->s_port;
|
1998-05-29 15:25:41 +00:00
|
|
|
|
1998-10-29 16:20:53 +00:00
|
|
|
if ((sp = getservbyname("gdomap", "udp")) == 0)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "Warning - unable to find service 'gdomap'\n");
|
|
|
|
fprintf(stderr, "on a unix host it should be in /etc/services\n");
|
|
|
|
fprintf(stderr, "as 'gdomap %d/tcp' and 'gdomap %d/udp'\n",
|
|
|
|
GDOMAP_PORT, GDOMAP_PORT);
|
1998-05-29 15:25:41 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
else if (sp->s_port != tcp_port)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "Warning - UDP and TCP service entries differ\n");
|
|
|
|
fprintf(stderr, "Warning - I will use the TCP entry for both!\n");
|
1998-05-29 15:25:41 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
if (tcp_port != my_port)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "Warning - gdomap not running on normal port\n");
|
1998-05-29 15:25:41 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
my_port = tcp_port;
|
1998-05-29 15:25:41 +00:00
|
|
|
}
|
|
|
|
#endif
|
1997-05-03 19:18:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Name - init_ports()
|
|
|
|
* Purpose - Set up the ports for accepting incoming requests.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
init_ports()
|
|
|
|
{
|
1998-10-29 16:20:53 +00:00
|
|
|
int r;
|
|
|
|
struct sockaddr_in sa;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Now we set up the sockets to accept incoming connections and set
|
|
|
|
* options on it so that if this program is killed, we can restart
|
|
|
|
* immediately and not find the socket addresses hung.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if ((udp_desc = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "Unable to create UDP socket\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
r = 1;
|
|
|
|
if ((setsockopt(udp_desc,SOL_SOCKET,SO_REUSEADDR,(char*)&r,sizeof(r)))<0)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "Warning - unable to set 're-use' on UDP socket\n");
|
|
|
|
}
|
2000-02-22 08:32:04 +00:00
|
|
|
if (nobcst == 0)
|
|
|
|
{
|
|
|
|
r = 1;
|
|
|
|
if ((setsockopt(udp_desc,SOL_SOCKET,SO_BROADCAST,(char*)&r,sizeof(r)))<0)
|
|
|
|
{
|
|
|
|
nobcst++;
|
|
|
|
fprintf(stderr, "Warning - unable to use 'broadcast' for probes\n");
|
|
|
|
}
|
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
if ((r = fcntl(udp_desc, F_GETFL, 0)) >= 0)
|
|
|
|
{
|
|
|
|
r |= NBLK_OPT;
|
|
|
|
if (fcntl(udp_desc, F_SETFL, r) < 0)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "Unable to set UDP socket non-blocking\n");
|
|
|
|
exit(1);
|
1997-05-03 19:18:21 +00:00
|
|
|
}
|
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
fprintf(stderr, "Unable to handle UDP socket non-blocking\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* Now we bind our address to the socket and prepare to accept incoming
|
|
|
|
* connections by listening on it.
|
|
|
|
*/
|
|
|
|
mzero(&sa, sizeof(sa));
|
|
|
|
sa.sin_family = AF_INET;
|
|
|
|
sa.sin_addr.s_addr = htonl(INADDR_ANY);
|
|
|
|
sa.sin_port = my_port;
|
|
|
|
if (bind(udp_desc, (void*)&sa, sizeof(sa)) < 0)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "Unable to bind address to UDP socket\n");
|
1999-10-04 10:35:57 +00:00
|
|
|
if (errno == EACCES)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "You probably need to run gdomap as root,\n");
|
|
|
|
fprintf(stderr, "or run the nameserver on a non-standard\n");
|
|
|
|
fprintf(stderr, "port that does not require root privilege.\n");
|
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Now we do the TCP socket.
|
|
|
|
*/
|
|
|
|
if ((tcp_desc = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "Unable to create TCP socket\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
r = 1;
|
|
|
|
if ((setsockopt(tcp_desc,SOL_SOCKET,SO_REUSEADDR,(char*)&r,sizeof(r)))<0)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "Warning - unable to set 're-use' on TCP socket\n");
|
|
|
|
}
|
|
|
|
if ((r = fcntl(tcp_desc, F_GETFL, 0)) >= 0)
|
|
|
|
{
|
|
|
|
r |= NBLK_OPT;
|
|
|
|
if (fcntl(tcp_desc, F_SETFL, r) < 0)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "Unable to set TCP socket non-blocking\n");
|
|
|
|
exit(1);
|
1997-05-03 19:18:21 +00:00
|
|
|
}
|
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
fprintf(stderr, "Unable to handle TCP socket non-blocking\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
mzero(&sa, sizeof(sa));
|
|
|
|
sa.sin_family = AF_INET;
|
|
|
|
sa.sin_addr.s_addr = htonl(INADDR_ANY);
|
|
|
|
sa.sin_port = my_port;
|
|
|
|
if (bind(tcp_desc, (void*)&sa, sizeof(sa)) < 0)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "Unable to bind address to TCP socket\n");
|
1999-10-04 10:35:57 +00:00
|
|
|
if (errno == EACCES)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "You probably need to run gdomap as root,\n");
|
|
|
|
fprintf(stderr, "or run the nameserver on a non-standard\n");
|
|
|
|
fprintf(stderr, "port that does not require root privilege.\n");
|
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
if (listen(tcp_desc, QUEBACKLOG) < 0)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "Unable to listen for connections on TCP socket\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Set up masks to say we are interested in these descriptors.
|
|
|
|
*/
|
1999-02-17 14:35:49 +00:00
|
|
|
memset(&read_fds, '\0', sizeof(read_fds));
|
|
|
|
memset(&write_fds, '\0', sizeof(write_fds));
|
1998-10-29 16:20:53 +00:00
|
|
|
FD_SET(tcp_desc, &read_fds);
|
|
|
|
FD_SET(udp_desc, &read_fds);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Turn off pipe signals so we don't get interrupted if we attempt
|
|
|
|
* to write a response to a process which has died.
|
|
|
|
*/
|
|
|
|
signal(SIGPIPE, SIG_IGN);
|
1997-05-03 19:18:21 +00:00
|
|
|
}
|
|
|
|
|
1998-02-26 17:55:42 +00:00
|
|
|
|
|
|
|
static int
|
|
|
|
other_addresses_on_net(struct in_addr old, struct in_addr **extra)
|
|
|
|
{
|
1998-10-29 16:20:53 +00:00
|
|
|
int numExtra = 0;
|
|
|
|
int iface;
|
1998-02-26 17:55:42 +00:00
|
|
|
|
1998-10-29 16:20:53 +00:00
|
|
|
for (iface = 0; iface < interfaces; iface++)
|
|
|
|
{
|
|
|
|
if (addr[iface].s_addr == old.s_addr)
|
|
|
|
{
|
|
|
|
continue;
|
1998-02-26 17:55:42 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
if ((addr[iface].s_addr & mask[iface].s_addr) ==
|
|
|
|
(old.s_addr & mask[iface].s_addr))
|
|
|
|
{
|
|
|
|
numExtra++;
|
1998-02-26 17:55:42 +00:00
|
|
|
}
|
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
if (numExtra > 0)
|
|
|
|
{
|
|
|
|
struct in_addr *addrs;
|
1998-02-26 17:55:42 +00:00
|
|
|
|
1998-10-29 16:20:53 +00:00
|
|
|
addrs = (struct in_addr*)malloc(sizeof(struct in_addr)*numExtra);
|
|
|
|
*extra = addrs;
|
|
|
|
numExtra = 0;
|
1998-02-26 17:55:42 +00:00
|
|
|
|
1998-10-29 16:20:53 +00:00
|
|
|
for (iface = 0; iface < interfaces; iface++)
|
|
|
|
{
|
|
|
|
if (addr[iface].s_addr == old.s_addr)
|
|
|
|
{
|
|
|
|
continue;
|
1998-02-26 17:55:42 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
if ((addr[iface].s_addr & mask[iface].s_addr) ==
|
|
|
|
(old.s_addr & mask[iface].s_addr))
|
|
|
|
{
|
|
|
|
addrs[numExtra].s_addr = addr[iface].s_addr;
|
|
|
|
numExtra++;
|
1998-02-26 17:55:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
return numExtra;
|
1998-02-26 17:55:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1997-05-03 19:18:21 +00:00
|
|
|
/*
|
|
|
|
* Name - init_probe()
|
|
|
|
* Purpose - Send a request to all hosts on the local network
|
|
|
|
* to see if there is a name server running on them.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
init_probe()
|
|
|
|
{
|
1998-10-29 16:20:53 +00:00
|
|
|
unsigned long nlist[interfaces];
|
|
|
|
int nlist_size = 0;
|
|
|
|
int iface;
|
|
|
|
int i;
|
1997-05-03 19:18:21 +00:00
|
|
|
|
2000-02-22 08:32:04 +00:00
|
|
|
if (noprobe > 0)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
if (debug > 2)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "Initiating probe requests.\n");
|
1997-09-01 21:59:51 +00:00
|
|
|
}
|
1997-05-03 19:18:21 +00:00
|
|
|
|
1998-10-29 16:20:53 +00:00
|
|
|
/*
|
|
|
|
* Make a list of the different networks to which we must send.
|
|
|
|
*/
|
|
|
|
for (iface = 0; iface < interfaces; iface++)
|
|
|
|
{
|
|
|
|
unsigned long net = (addr[iface].s_addr & mask[iface].s_addr);
|
1997-05-03 19:18:21 +00:00
|
|
|
|
1998-10-29 16:20:53 +00:00
|
|
|
if (addr[iface].s_addr == loopback.s_addr)
|
|
|
|
{
|
|
|
|
continue; /* Skip loopback */
|
1997-09-01 21:59:51 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
for (i = 0; i < nlist_size; i++)
|
|
|
|
{
|
|
|
|
if (net == nlist[i])
|
|
|
|
{
|
|
|
|
break;
|
1998-02-26 17:55:42 +00:00
|
|
|
}
|
1997-05-03 19:18:21 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
if (i == nlist_size)
|
|
|
|
{
|
|
|
|
nlist[i] = net;
|
|
|
|
nlist_size++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < nlist_size; i++)
|
|
|
|
{
|
2000-02-22 08:32:04 +00:00
|
|
|
int broadcast = 0;
|
|
|
|
int elen = 0;
|
1998-10-29 16:20:53 +00:00
|
|
|
struct in_addr *other;
|
|
|
|
struct in_addr sin;
|
|
|
|
int high;
|
|
|
|
int low;
|
|
|
|
unsigned long net;
|
|
|
|
int j;
|
2000-02-22 08:32:04 +00:00
|
|
|
struct in_addr b;
|
1998-10-29 16:20:53 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Build up a list of addresses that we serve on this network.
|
|
|
|
*/
|
|
|
|
for (iface = 0; iface < interfaces; iface++)
|
|
|
|
{
|
|
|
|
if ((addr[iface].s_addr & mask[iface].s_addr) == nlist[i])
|
|
|
|
{
|
2000-02-22 08:32:04 +00:00
|
|
|
if (bcok[iface])
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Simple broadcast for this address.
|
|
|
|
*/
|
|
|
|
b.s_addr = bcst[iface].s_addr;
|
|
|
|
broadcast = 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
unsigned long ha; /* full host address. */
|
|
|
|
unsigned long hm; /* full netmask. */
|
1998-10-29 16:20:53 +00:00
|
|
|
|
2000-02-22 08:32:04 +00:00
|
|
|
ha = ntohl(addr[iface].s_addr);
|
|
|
|
hm = ntohl(mask[iface].s_addr);
|
1998-10-29 16:20:53 +00:00
|
|
|
|
2000-02-22 08:32:04 +00:00
|
|
|
/*
|
|
|
|
* Make sure that our netmasks are restricted
|
|
|
|
* to class-c networks and subnets of those
|
|
|
|
* networks - we don't want to be probing
|
|
|
|
* more than a couple of hundred hosts!
|
|
|
|
*/
|
|
|
|
if ((mask[iface].s_addr | class_c_mask.s_addr)
|
|
|
|
!= mask[iface].s_addr)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "gdomap - warning - netmask %s will be "
|
|
|
|
"treated as 255.255.255.0 for %s\n",
|
|
|
|
inet_ntoa(mask[iface]), inet_ntoa(addr[iface]));
|
|
|
|
hm |= ~255;
|
|
|
|
}
|
|
|
|
sin = addr[iface];
|
|
|
|
net = ha & hm & ~255; /* class-c net number. */
|
|
|
|
low = ha & hm & 255; /* low end of subnet. */
|
|
|
|
high = low | (255 & ~hm); /* high end of subnet. */
|
|
|
|
elen = other_addresses_on_net(sin, &other);
|
1997-09-01 21:59:51 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
break;
|
1997-05-03 19:18:21 +00:00
|
|
|
}
|
1997-09-01 21:59:51 +00:00
|
|
|
}
|
|
|
|
|
1998-10-29 16:20:53 +00:00
|
|
|
if (plist)
|
|
|
|
{
|
|
|
|
plentry *p;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
1998-10-29 16:20:53 +00:00
|
|
|
/*
|
|
|
|
* Now start probes for servers on machines in our probe config
|
|
|
|
* list for which we have a direct connection.
|
|
|
|
*/
|
|
|
|
for (p = plist; p != 0; p = p->next)
|
|
|
|
{
|
|
|
|
if ((p->addr.s_addr & mask[iface].s_addr) ==
|
|
|
|
(addr[iface].s_addr & mask[iface].s_addr))
|
|
|
|
{
|
|
|
|
int len = elen;
|
|
|
|
|
|
|
|
p->direct = 1;
|
|
|
|
/* Kick off probe. */
|
|
|
|
if (is_local_host(p->addr))
|
|
|
|
{
|
|
|
|
continue; /* Don't probe self. */
|
1998-03-10 19:01:24 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
while (len > MAX_EXTRA)
|
|
|
|
{
|
|
|
|
len -= MAX_EXTRA;
|
|
|
|
queue_probe(&p->addr, &sin, MAX_EXTRA, &other[len], 0);
|
1998-03-10 19:01:24 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
queue_probe(&p->addr, &sin, len, other, 0);
|
1998-03-10 19:01:24 +00:00
|
|
|
}
|
1997-05-03 19:18:21 +00:00
|
|
|
}
|
1998-03-10 19:01:24 +00:00
|
|
|
}
|
2000-02-22 08:32:04 +00:00
|
|
|
else if (broadcast)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Now broadcast probe on this network.
|
|
|
|
*/
|
|
|
|
queue_probe(&b, &sin, 0, 0, 0);
|
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Now start probes for servers on machines which may be on
|
|
|
|
* any network for which we have an interface.
|
|
|
|
*
|
|
|
|
* Assume 'low' and 'high' are not valid host addresses as 'low'
|
|
|
|
* is the network address and 'high' is the broadcast address.
|
|
|
|
*/
|
|
|
|
for (j = low + 1; j < high; j++)
|
|
|
|
{
|
|
|
|
struct in_addr a;
|
|
|
|
int len = elen;
|
|
|
|
|
|
|
|
a.s_addr = htonl(net + j);
|
|
|
|
if (is_local_host(a))
|
|
|
|
{
|
|
|
|
continue; /* Don't probe self - that's silly. */
|
1998-03-10 19:01:24 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
/* Kick off probe. */
|
|
|
|
while (len > MAX_EXTRA)
|
|
|
|
{
|
|
|
|
len -= MAX_EXTRA;
|
|
|
|
queue_probe(&a, &sin, MAX_EXTRA, &other[len], 0);
|
1998-03-10 19:01:24 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
queue_probe(&a, &sin, len, other, 0);
|
1998-02-26 17:55:42 +00:00
|
|
|
}
|
|
|
|
}
|
1998-03-10 19:01:24 +00:00
|
|
|
|
1998-10-29 16:20:53 +00:00
|
|
|
if (elen > 0)
|
|
|
|
{
|
|
|
|
free(other);
|
1997-05-03 19:18:21 +00:00
|
|
|
}
|
|
|
|
}
|
1998-03-10 19:01:24 +00:00
|
|
|
|
1998-10-29 16:20:53 +00:00
|
|
|
if (plist)
|
|
|
|
{
|
|
|
|
plentry *p;
|
|
|
|
int indirect = 0;
|
1998-03-10 19:01:24 +00:00
|
|
|
|
1998-10-29 16:20:53 +00:00
|
|
|
/*
|
|
|
|
* Are there any hosts for which we do not have a direct
|
|
|
|
* network connection, and to which we have therefore not
|
|
|
|
* queued a probe?
|
|
|
|
*/
|
|
|
|
for (p = plist; p != 0; p = p->next)
|
|
|
|
{
|
|
|
|
if (p->direct == 0)
|
|
|
|
{
|
|
|
|
indirect = 1;
|
1998-03-10 19:01:24 +00:00
|
|
|
}
|
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
if (indirect)
|
|
|
|
{
|
|
|
|
struct in_addr *other;
|
|
|
|
int elen;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Queue probes for indirect connections to hosts from our
|
|
|
|
* primary interface and let the routing system handle it.
|
|
|
|
*/
|
|
|
|
elen = other_addresses_on_net(addr[0], &other);
|
|
|
|
for (p = plist; p != 0; p = p->next)
|
|
|
|
{
|
|
|
|
if (p->direct == 0)
|
|
|
|
{
|
|
|
|
int len = elen;
|
1998-03-10 19:01:24 +00:00
|
|
|
|
1998-10-29 16:20:53 +00:00
|
|
|
if (is_local_host(p->addr))
|
|
|
|
{
|
|
|
|
continue; /* Don't probe self. */
|
1998-03-10 19:01:24 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
/* Kick off probe. */
|
|
|
|
while (len > MAX_EXTRA)
|
|
|
|
{
|
|
|
|
len -= MAX_EXTRA;
|
|
|
|
queue_probe(&p->addr, addr, MAX_EXTRA, &other[len], 0);
|
1998-03-10 19:01:24 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
queue_probe(&p->addr, addr, len, other, 0);
|
1998-03-10 19:01:24 +00:00
|
|
|
}
|
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
if (elen > 0)
|
|
|
|
{
|
|
|
|
free(other);
|
1998-03-10 19:01:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1998-10-29 16:20:53 +00:00
|
|
|
if (debug > 2)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "Probe requests initiated.\n");
|
1997-09-01 21:59:51 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
last_probe = time(0);
|
1997-05-03 19:18:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Name - handle_accept()
|
|
|
|
* Purpose - Handle an incoming connection, setting up resources
|
|
|
|
* for the request. Ensure that the channel is in
|
|
|
|
* non-blocking mode so that we can't hang.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
handle_accept()
|
|
|
|
{
|
1998-10-29 16:20:53 +00:00
|
|
|
struct sockaddr_in sa;
|
|
|
|
int len = sizeof(sa);
|
|
|
|
int desc;
|
1997-05-03 19:18:21 +00:00
|
|
|
|
1998-10-29 16:20:53 +00:00
|
|
|
desc = accept(tcp_desc, (void*)&sa, &len);
|
|
|
|
if (desc >= 0)
|
|
|
|
{
|
|
|
|
int r;
|
1997-05-03 19:18:21 +00:00
|
|
|
|
1998-10-29 16:20:53 +00:00
|
|
|
FD_SET(desc, &read_fds);
|
|
|
|
r_info[desc].pos = 0;
|
|
|
|
mcopy((char*)&r_info[desc].addr, (char*)&sa, sizeof(sa));
|
1997-05-03 19:18:21 +00:00
|
|
|
|
1998-10-29 16:20:53 +00:00
|
|
|
if (debug)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "accept from %s(%d) to chan %d\n",
|
1997-10-28 14:34:49 +00:00
|
|
|
inet_ntoa(sa.sin_addr), ntohs(sa.sin_port), desc);
|
1997-09-01 21:59:51 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
/*
|
|
|
|
* Ensure that the connection is non-blocking.
|
|
|
|
*/
|
|
|
|
if ((r = fcntl(desc, F_GETFL, 0)) >= 0)
|
|
|
|
{
|
|
|
|
r |= NBLK_OPT;
|
|
|
|
if (fcntl(desc, F_SETFL, r) < 0)
|
|
|
|
{
|
|
|
|
if (debug)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "failed to set chan %d non-blocking\n", desc);
|
1997-09-01 21:59:51 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
clear_chan(desc);
|
1997-05-03 19:18:21 +00:00
|
|
|
}
|
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
if (debug)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "failed to set chan %d non-blocking\n", desc);
|
1997-09-01 21:59:51 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
clear_chan(desc);
|
1997-09-01 21:59:51 +00:00
|
|
|
}
|
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
else if (debug)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "accept failed - errno %d\n", errno);
|
1997-05-03 19:18:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Name - handle_io()
|
|
|
|
* Purpose - Main loop to handle I/O on multiple simultaneous
|
|
|
|
* connections. All non-blocking stuff.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
handle_io()
|
|
|
|
{
|
1998-10-29 16:20:53 +00:00
|
|
|
struct timeval timeout;
|
|
|
|
void *to;
|
|
|
|
int rval = 0;
|
|
|
|
int i;
|
|
|
|
fd_set rfds;
|
|
|
|
fd_set wfds;
|
|
|
|
|
|
|
|
while (rval >= 0)
|
|
|
|
{
|
|
|
|
rfds = read_fds;
|
|
|
|
wfds = write_fds;
|
|
|
|
to = 0;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If there is anything waiting to be sent on the UDP socket
|
|
|
|
* we must check to see if it is writable.
|
|
|
|
*/
|
|
|
|
if (u_queue != 0)
|
|
|
|
{
|
|
|
|
FD_SET(udp_desc, &wfds);
|
|
|
|
}
|
|
|
|
|
|
|
|
timeout.tv_sec = 10;
|
|
|
|
timeout.tv_usec = 0;
|
|
|
|
to = &timeout;
|
|
|
|
rval = select(FD_SETSIZE, &rfds, &wfds, 0, to);
|
|
|
|
|
|
|
|
if (rval < 0)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Let's handle any error return.
|
|
|
|
*/
|
|
|
|
if (errno == EBADF)
|
|
|
|
{
|
|
|
|
fd_set efds;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Almost certainly lost a connection - try each
|
|
|
|
* descriptor in turn to see which one it is.
|
|
|
|
* Remove descriptor from bitmask and close it.
|
|
|
|
* If the error is on the listener socket we die.
|
|
|
|
*/
|
1999-02-17 14:35:49 +00:00
|
|
|
memset(&efds, '\0', sizeof(efds));
|
1998-10-29 16:20:53 +00:00
|
|
|
for (i = 0; i < FD_SETSIZE; i++)
|
|
|
|
{
|
|
|
|
if (FD_ISSET(i, &rfds) || FD_ISSET(i, &wfds))
|
|
|
|
{
|
|
|
|
FD_SET(i, &efds);
|
|
|
|
timeout.tv_sec = 0;
|
|
|
|
timeout.tv_usec = 0;
|
|
|
|
to = &timeout;
|
|
|
|
rval = select(FD_SETSIZE, &efds, 0, 0, to);
|
|
|
|
FD_CLR(i, &efds);
|
|
|
|
if (rval < 0 && errno == EBADF)
|
|
|
|
{
|
|
|
|
clear_chan(i);
|
|
|
|
if (i == tcp_desc)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "Fatal error on socket.\n");
|
|
|
|
exit(1);
|
1997-05-03 19:18:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
rval = 0;
|
1997-05-03 19:18:21 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
fprintf(stderr, "Interrupted in select.\n");
|
|
|
|
exit(1);
|
1997-05-03 19:18:21 +00:00
|
|
|
}
|
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
else if (rval == 0)
|
|
|
|
{
|
|
|
|
long now = time(0);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Let's handle a timeout.
|
|
|
|
*/
|
|
|
|
prb_tim(now); /* Remove dead servers */
|
|
|
|
if (udp_pending == 0 && (now - last_probe) >= interval)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* If there is no output pending on the udp channel and
|
|
|
|
* it is at least five minutes since we sent out a probe
|
|
|
|
* we can re-probe the network for other name servers.
|
|
|
|
*/
|
|
|
|
init_probe();
|
1997-05-03 19:18:21 +00:00
|
|
|
}
|
1998-02-26 17:55:42 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Got some descriptor activity - deal with it.
|
|
|
|
*/
|
|
|
|
for (i = 0; i < FD_SETSIZE; i++)
|
|
|
|
{
|
|
|
|
if (FD_ISSET(i, &rfds))
|
|
|
|
{
|
|
|
|
if (i == tcp_desc)
|
|
|
|
{
|
|
|
|
handle_accept();
|
1998-02-26 17:55:42 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
else if (i == udp_desc)
|
|
|
|
{
|
|
|
|
handle_recv();
|
1998-02-26 17:55:42 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
handle_read(i);
|
1998-02-26 17:55:42 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
if (debug > 2)
|
|
|
|
{
|
|
|
|
dump_stats();
|
1998-02-26 17:55:42 +00:00
|
|
|
}
|
1997-09-01 21:59:51 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
if (FD_ISSET(i, &wfds))
|
|
|
|
{
|
|
|
|
if (i == udp_desc)
|
|
|
|
{
|
|
|
|
handle_send();
|
1998-02-26 17:55:42 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
handle_write(i);
|
1998-02-26 17:55:42 +00:00
|
|
|
}
|
1997-09-01 21:59:51 +00:00
|
|
|
}
|
1997-05-03 19:18:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Name - handle_read()
|
|
|
|
* Purpose - Read a request from a channel. This may be called in
|
|
|
|
* many stages if the read is blocking.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
handle_read(int desc)
|
|
|
|
{
|
1998-10-29 16:20:53 +00:00
|
|
|
uptr ptr = r_info[desc].buf.b;
|
|
|
|
int nothingRead = 1;
|
|
|
|
int done = 0;
|
|
|
|
int r;
|
1997-05-03 19:18:21 +00:00
|
|
|
|
1998-10-29 16:20:53 +00:00
|
|
|
while (r_info[desc].pos < GDO_REQ_SIZE && done == 0)
|
|
|
|
{
|
|
|
|
r = read(desc, &ptr[r_info[desc].pos], GDO_REQ_SIZE - r_info[desc].pos);
|
|
|
|
if (r > 0)
|
|
|
|
{
|
|
|
|
nothingRead = 0;
|
|
|
|
r_info[desc].pos += r;
|
1997-05-03 19:18:21 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
done = 1;
|
1997-05-03 19:18:21 +00:00
|
|
|
}
|
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
if (r_info[desc].pos == GDO_REQ_SIZE)
|
|
|
|
{
|
|
|
|
tcp_read++;
|
|
|
|
handle_request(desc);
|
1997-05-03 19:18:21 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
else if (errno != EWOULDBLOCK || nothingRead == 1)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* If there is an error or end-of-file on the descriptor then
|
|
|
|
* we must close it down.
|
|
|
|
*/
|
|
|
|
clear_chan(desc);
|
1997-05-03 19:18:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Name - handle_recv()
|
|
|
|
* Purpose - Read a request from the UDP socket.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
handle_recv()
|
|
|
|
{
|
1998-10-29 16:20:53 +00:00
|
|
|
uptr ptr = r_info[udp_desc].buf.b;
|
|
|
|
struct sockaddr_in* addr = &r_info[udp_desc].addr;
|
|
|
|
int len = sizeof(struct sockaddr_in);
|
|
|
|
int r;
|
1997-05-03 19:18:21 +00:00
|
|
|
|
1998-10-29 16:20:53 +00:00
|
|
|
r = recvfrom(udp_desc, ptr, GDO_REQ_SIZE, 0, (void*)addr, &len);
|
|
|
|
if (r == GDO_REQ_SIZE)
|
|
|
|
{
|
|
|
|
udp_read++;
|
|
|
|
r_info[udp_desc].pos = GDO_REQ_SIZE;
|
|
|
|
if (debug)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "recvfrom %s\n", inet_ntoa(addr->sin_addr));
|
1997-05-03 19:18:21 +00:00
|
|
|
}
|
2000-02-22 08:32:04 +00:00
|
|
|
if (is_local_host(addr->sin_addr) == 1)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "recvfrom packet from self discarded\n");
|
|
|
|
return;
|
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
handle_request(udp_desc);
|
1997-05-03 19:18:21 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
if (debug)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "recvfrom returned %d - ", r);
|
|
|
|
perror("");
|
1997-05-03 19:18:21 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
clear_chan(udp_desc);
|
1997-05-03 19:18:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Name - handle_request()
|
|
|
|
* Purpose - Once we have read a full request, we come here
|
|
|
|
* to take action depending on the request type.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
handle_request(int desc)
|
|
|
|
{
|
1998-10-29 16:20:53 +00:00
|
|
|
unsigned char type = r_info[desc].buf.r.rtype;
|
|
|
|
unsigned char size = r_info[desc].buf.r.nsize;
|
|
|
|
unsigned char ptype = r_info[desc].buf.r.ptype;
|
|
|
|
unsigned long port = ntohl(r_info[desc].buf.r.port);
|
|
|
|
unsigned char *buf = r_info[desc].buf.r.name;
|
|
|
|
map_ent* m;
|
|
|
|
|
|
|
|
FD_CLR(desc, &read_fds);
|
|
|
|
FD_SET(desc, &write_fds);
|
|
|
|
w_info[desc].pos = 0;
|
|
|
|
|
|
|
|
if (debug > 1)
|
|
|
|
{
|
|
|
|
if (desc == udp_desc)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "request type '%c' on UDP chan", type);
|
1997-09-01 21:59:51 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
fprintf(stderr, "request type '%c' from chan %d", type, desc);
|
1997-09-01 21:59:51 +00:00
|
|
|
}
|
1999-06-24 19:30:29 +00:00
|
|
|
fprintf(stderr, " - name: '%.*s' port: %ld\n", size, buf, port);
|
1997-09-01 21:59:51 +00:00
|
|
|
}
|
|
|
|
|
1998-10-29 16:20:53 +00:00
|
|
|
if (ptype != GDO_TCP_GDO && ptype != GDO_TCP_FOREIGN &&
|
|
|
|
ptype != GDO_UDP_GDO && ptype != GDO_UDP_FOREIGN)
|
|
|
|
{
|
|
|
|
if (ptype != 0 || (type != GDO_PROBE && type != GDO_PREPLY &&
|
|
|
|
type != GDO_SERVERS))
|
|
|
|
{
|
|
|
|
if (debug)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "Illegal port type in request\n");
|
1997-09-01 21:59:51 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
clear_chan(desc);
|
|
|
|
return;
|
1997-09-01 21:59:51 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1998-10-29 16:20:53 +00:00
|
|
|
/*
|
|
|
|
* The default return value is a four byte number set to zero.
|
|
|
|
* We assume that malloc returns data aligned on a 4 byte boundary.
|
|
|
|
*/
|
|
|
|
w_info[desc].len = 4;
|
|
|
|
w_info[desc].buf = (char*)malloc(4);
|
|
|
|
w_info[desc].buf[0] = 0;
|
|
|
|
w_info[desc].buf[1] = 0;
|
|
|
|
w_info[desc].buf[2] = 0;
|
|
|
|
w_info[desc].buf[3] = 0;
|
|
|
|
|
|
|
|
if (type == GDO_REGISTER)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* See if this is a request from a local process.
|
|
|
|
*/
|
|
|
|
if (is_local_host(r_info[desc].addr.sin_addr) == 0)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "Illegal attempt to register!\n");
|
|
|
|
clear_chan(desc); /* Only local progs may register. */
|
|
|
|
return;
|
1997-05-03 19:18:21 +00:00
|
|
|
}
|
1997-10-28 14:34:49 +00:00
|
|
|
|
1998-10-29 16:20:53 +00:00
|
|
|
/*
|
|
|
|
* What should we do if we already have the name registered?
|
|
|
|
* Simple algorithm -
|
|
|
|
* We check to see if we can bind to the old port,
|
|
|
|
* and if we can we assume that the original process
|
|
|
|
* has gone away and permit a new registration for the
|
|
|
|
* same name.
|
|
|
|
* This is not foolproof - if the machine has more
|
|
|
|
* than one IP address, we could bind to the port on
|
|
|
|
* one address even though the server is using it on
|
|
|
|
* another.
|
|
|
|
* Also - the operating system is not guaranteed to
|
|
|
|
* let us bind to the port if another process has only
|
|
|
|
* recently stopped using it.
|
|
|
|
* Also - what if an old server used the port that the
|
|
|
|
* new one is using? In this case the registration
|
|
|
|
* attempt will be refused even though it shouldn't be!
|
|
|
|
* On the other hand - the occasional registration
|
|
|
|
* failure MUST be better than permitting a process to
|
|
|
|
* grab a name already in use! If a server fails to
|
|
|
|
* register a name/port combination, it can always be
|
|
|
|
* coded to retry on a different port.
|
|
|
|
*/
|
|
|
|
m = map_by_name(buf, size);
|
|
|
|
if (m != 0 && port == m->port)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Special case - we already have this name registered for this
|
|
|
|
* port - so everything is already ok.
|
|
|
|
*/
|
|
|
|
*(unsigned long*)w_info[desc].buf = htonl(port);
|
|
|
|
}
|
|
|
|
else if (m != 0)
|
|
|
|
{
|
|
|
|
int sock = -1;
|
|
|
|
|
|
|
|
if ((ptype & GDO_NET_MASK) == GDO_NET_TCP)
|
|
|
|
{
|
|
|
|
sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
1997-09-01 21:59:51 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
else if ((ptype & GDO_NET_MASK) == GDO_NET_UDP)
|
|
|
|
{
|
|
|
|
sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
1997-09-01 21:59:51 +00:00
|
|
|
}
|
1997-05-03 19:18:21 +00:00
|
|
|
|
1998-10-29 16:20:53 +00:00
|
|
|
if (sock < 0)
|
|
|
|
{
|
|
|
|
perror("unable to create new socket");
|
1997-09-01 21:59:51 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
int r = 1;
|
|
|
|
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
|
|
|
|
(char*)&r, sizeof(r)) < 0)
|
|
|
|
{
|
|
|
|
perror("unable to set socket options");
|
1997-05-03 19:18:21 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
struct sockaddr_in sa;
|
|
|
|
int result;
|
|
|
|
short p = m->port;
|
|
|
|
|
|
|
|
mzero(&sa, sizeof(sa));
|
|
|
|
sa.sin_family = AF_INET;
|
|
|
|
sa.sin_addr.s_addr = htonl(INADDR_ANY);
|
|
|
|
sa.sin_port = htons(p);
|
|
|
|
result = bind(sock, (void*)&sa, sizeof(sa));
|
|
|
|
if (result == 0)
|
|
|
|
{
|
|
|
|
if (debug > 1)
|
|
|
|
{
|
1999-06-24 19:30:29 +00:00
|
|
|
fprintf(stderr, "re-register from %d to %ld\n",
|
1997-09-01 21:59:51 +00:00
|
|
|
m->port, port);
|
1997-05-03 19:18:21 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
m->port = port;
|
|
|
|
m->net = (ptype & GDO_NET_MASK);
|
|
|
|
m->svc = (ptype & GDO_SVC_MASK);
|
|
|
|
port = htonl(m->port);
|
|
|
|
*(unsigned long*)w_info[desc].buf = port;
|
1997-05-03 19:18:21 +00:00
|
|
|
}
|
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
close(sock);
|
1997-05-03 19:18:21 +00:00
|
|
|
}
|
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
else if (port == 0)
|
|
|
|
{ /* Port not provided! */
|
|
|
|
fprintf(stderr, "port not provided in request\n");
|
1997-09-01 21:59:51 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
else
|
|
|
|
{ /* Use port provided in request. */
|
|
|
|
m = map_add(buf, size, port, ptype);
|
|
|
|
port = htonl(m->port);
|
|
|
|
*(unsigned long*)w_info[desc].buf = port;
|
1997-09-01 21:59:51 +00:00
|
|
|
}
|
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
else if (type == GDO_LOOKUP)
|
|
|
|
{
|
|
|
|
m = map_by_name(buf, size);
|
|
|
|
if (m != 0 && (m->net | m->svc) != ptype)
|
|
|
|
{
|
|
|
|
if (debug > 1)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "requested service is of wrong type\n");
|
1997-09-01 21:59:51 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
m = 0; /* Name exists but is of wrong type. */
|
|
|
|
}
|
|
|
|
if (m)
|
|
|
|
{
|
|
|
|
int sock = -1;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We check to see if we can bind to the old port, and if we can
|
|
|
|
* we assume that the process has gone away and remove it from
|
|
|
|
* the map.
|
|
|
|
* This is not foolproof - if the machine has more
|
|
|
|
* than one IP address, we could bind to the port on
|
|
|
|
* one address even though the server is using it on
|
|
|
|
* another.
|
|
|
|
*/
|
|
|
|
if ((ptype & GDO_NET_MASK) == GDO_NET_TCP)
|
|
|
|
{
|
|
|
|
sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
1997-09-01 21:59:51 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
else if ((ptype & GDO_NET_MASK) == GDO_NET_UDP)
|
|
|
|
{
|
|
|
|
sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
1997-09-01 21:59:51 +00:00
|
|
|
}
|
1997-05-03 19:18:21 +00:00
|
|
|
|
1998-10-29 16:20:53 +00:00
|
|
|
if (sock < 0)
|
|
|
|
{
|
|
|
|
perror("unable to create new socket");
|
1997-09-01 21:59:51 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
int r = 1;
|
|
|
|
|
|
|
|
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
|
|
|
|
(char*)&r, sizeof(r)) < 0)
|
|
|
|
{
|
|
|
|
perror("unable to set socket options");
|
1997-05-03 19:18:21 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
struct sockaddr_in sa;
|
|
|
|
int result;
|
|
|
|
unsigned short p = (unsigned short)m->port;
|
|
|
|
|
|
|
|
mzero(&sa, sizeof(sa));
|
|
|
|
sa.sin_family = AF_INET;
|
|
|
|
sa.sin_addr.s_addr = htonl(INADDR_ANY);
|
|
|
|
sa.sin_port = htons(p);
|
|
|
|
result = bind(sock, (void*)&sa, sizeof(sa));
|
|
|
|
if (result == 0)
|
|
|
|
{
|
|
|
|
map_del(m);
|
|
|
|
m = 0;
|
1997-05-03 19:18:21 +00:00
|
|
|
}
|
1997-09-01 21:59:51 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
close(sock);
|
1997-05-03 19:18:21 +00:00
|
|
|
}
|
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
if (m)
|
|
|
|
{ /* Lookup found live server. */
|
|
|
|
*(unsigned long*)w_info[desc].buf = htonl(m->port);
|
1997-05-03 19:18:21 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
else
|
|
|
|
{ /* Not found. */
|
|
|
|
if (debug > 1)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "requested service not found\n");
|
1997-09-01 21:59:51 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
*(unsigned short*)w_info[desc].buf = 0;
|
1997-05-03 19:18:21 +00:00
|
|
|
}
|
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
else if (type == GDO_UNREG)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* See if this is a request from a local process.
|
|
|
|
*/
|
|
|
|
if (is_local_host(r_info[desc].addr.sin_addr) == 0)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "Illegal attempt to un-register!\n");
|
|
|
|
clear_chan(desc);
|
|
|
|
return;
|
|
|
|
}
|
1998-11-02 11:48:42 +00:00
|
|
|
if (port == 0 || size > 0)
|
1998-10-29 16:20:53 +00:00
|
|
|
{
|
1998-11-02 11:48:42 +00:00
|
|
|
m = map_by_name(buf, size);
|
|
|
|
if (m)
|
1998-10-29 16:20:53 +00:00
|
|
|
{
|
1998-11-02 11:48:42 +00:00
|
|
|
if ((m->net | m->svc) != ptype)
|
1998-10-29 16:20:53 +00:00
|
|
|
{
|
1998-11-02 11:48:42 +00:00
|
|
|
if (debug)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "Attempted unregister with wrong type\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
*(unsigned long*)w_info[desc].buf = htonl(m->port);
|
|
|
|
map_del(m);
|
1997-09-01 21:59:51 +00:00
|
|
|
}
|
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
else
|
|
|
|
{
|
1998-11-02 11:48:42 +00:00
|
|
|
if (debug > 1)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "requested service not found\n");
|
|
|
|
}
|
1997-05-03 19:18:21 +00:00
|
|
|
}
|
1997-09-01 21:59:51 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
else
|
|
|
|
{
|
1998-11-02 11:48:42 +00:00
|
|
|
*(unsigned long*)w_info[desc].buf = 0;
|
|
|
|
while ((m = map_by_port(port, ptype)) != 0)
|
1998-10-29 16:20:53 +00:00
|
|
|
{
|
1998-11-02 11:48:42 +00:00
|
|
|
*(unsigned long*)w_info[desc].buf = htonl(m->port);
|
|
|
|
map_del(m);
|
1997-05-03 19:18:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
else if (type == GDO_SERVERS)
|
|
|
|
{
|
|
|
|
int i;
|
1999-08-21 05:29:10 +00:00
|
|
|
int j;
|
1997-05-03 19:18:21 +00:00
|
|
|
|
1998-10-29 16:20:53 +00:00
|
|
|
free(w_info[desc].buf);
|
|
|
|
w_info[desc].buf = (char*)malloc(sizeof(unsigned long) +
|
1998-02-26 17:55:42 +00:00
|
|
|
(prb_used+1)*IASIZE);
|
1998-10-29 16:20:53 +00:00
|
|
|
*(unsigned long*)w_info[desc].buf = htonl(prb_used+1);
|
|
|
|
mcopy(&w_info[desc].buf[4], &r_info[desc].addr.sin_addr, IASIZE);
|
1999-08-21 05:29:10 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Copy the addresses of the hosts we have probed into the buffer.
|
|
|
|
* During the copy, reverse the order of the addresses so that the
|
|
|
|
* address we have contacted most recently is first. This should
|
|
|
|
* ensure that the client process will attempt to contact live
|
|
|
|
* hosts before dead ones.
|
|
|
|
*/
|
|
|
|
for (i = 0, j = prb_used; i < prb_used; i++)
|
1998-10-29 16:20:53 +00:00
|
|
|
{
|
1999-08-21 05:29:10 +00:00
|
|
|
mcopy(&w_info[desc].buf[4+(i+1)*IASIZE], &prb[--j]->sin, IASIZE);
|
1998-10-29 16:20:53 +00:00
|
|
|
}
|
|
|
|
w_info[desc].len = 4 + (prb_used+1)*IASIZE;
|
|
|
|
}
|
|
|
|
else if (type == GDO_PROBE)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* If the client is a name server, we add it to the list.
|
|
|
|
*/
|
|
|
|
if (r_info[desc].addr.sin_port == my_port)
|
|
|
|
{
|
|
|
|
struct in_addr *ptr;
|
|
|
|
struct in_addr sin;
|
|
|
|
unsigned long net;
|
|
|
|
int c;
|
|
|
|
|
|
|
|
memcpy(&sin, r_info[desc].buf.r.name, IASIZE);
|
|
|
|
if (debug > 2)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "Probe from '%s'\n", inet_ntoa(sin));
|
1998-02-26 17:55:42 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
net = inet_netof(sin);
|
|
|
|
ptr = (struct in_addr*)&r_info[desc].buf.r.name[2*IASIZE];
|
|
|
|
c = (r_info[desc].buf.r.nsize - 2*IASIZE)/IASIZE;
|
|
|
|
prb_add(&sin);
|
|
|
|
while (c-- > 0)
|
|
|
|
{
|
|
|
|
if (debug > 2)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "Delete server '%s'\n", inet_ntoa(*ptr));
|
1997-05-03 19:18:21 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
prb_del(ptr);
|
|
|
|
ptr++;
|
1997-05-03 19:18:21 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
/*
|
|
|
|
* Irrespective of what we are told to do - we also add the
|
|
|
|
* interface from which this packet arrived so we have a
|
|
|
|
* route we KNOW we can use.
|
|
|
|
*/
|
|
|
|
prb_add(&r_info[desc].addr.sin_addr);
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* For a UDP request from another name server, we send a reply
|
|
|
|
* packet. We shouldn't be getting probes from anywhere else,
|
|
|
|
* but just to be nice, we send back our port number anyway.
|
|
|
|
*/
|
|
|
|
if (desc == udp_desc && r_info[desc].addr.sin_port == my_port)
|
|
|
|
{
|
|
|
|
struct in_addr laddr;
|
|
|
|
struct in_addr raddr;
|
|
|
|
struct in_addr *other;
|
|
|
|
int elen;
|
|
|
|
void *rbuf = r_info[desc].buf.r.name;
|
|
|
|
void *wbuf;
|
|
|
|
int i;
|
|
|
|
gdo_req *r;
|
|
|
|
|
|
|
|
free(w_info[desc].buf);
|
|
|
|
w_info[desc].buf = (char*)calloc(GDO_REQ_SIZE,1);
|
|
|
|
r = (gdo_req*)w_info[desc].buf;
|
|
|
|
wbuf = r->name;
|
|
|
|
r->rtype = GDO_PREPLY;
|
|
|
|
r->nsize = IASIZE*2;
|
|
|
|
|
|
|
|
mcopy(&raddr, rbuf, IASIZE);
|
|
|
|
mcopy(&laddr, rbuf+IASIZE, IASIZE);
|
1998-02-26 17:55:42 +00:00
|
|
|
|
1998-10-29 16:20:53 +00:00
|
|
|
mcopy(wbuf+IASIZE, &raddr, IASIZE);
|
|
|
|
/*
|
|
|
|
* If the other end did not tell us which of our addresses it was
|
|
|
|
* probing, try to select one on the same network to send back.
|
|
|
|
* otherwise, respond with the address it was probing.
|
|
|
|
*/
|
|
|
|
if (is_local_host(laddr) == 0)
|
|
|
|
{
|
|
|
|
for (i = 0; i < interfaces; i++)
|
|
|
|
{
|
|
|
|
if ((mask[i].s_addr && addr[i].s_addr) ==
|
|
|
|
(mask[i].s_addr && r_info[desc].addr.sin_addr.s_addr))
|
|
|
|
{
|
|
|
|
laddr = addr[i];
|
|
|
|
mcopy(wbuf, &laddr, IASIZE);
|
|
|
|
break;
|
1998-02-26 17:55:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
mcopy(wbuf, &laddr, IASIZE);
|
1998-02-26 17:55:42 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
w_info[desc].len = GDO_REQ_SIZE;
|
1998-02-26 17:55:42 +00:00
|
|
|
|
1998-10-29 16:20:53 +00:00
|
|
|
elen = other_addresses_on_net(laddr, &other);
|
|
|
|
if (elen > 0)
|
|
|
|
{
|
|
|
|
while (elen > MAX_EXTRA)
|
|
|
|
{
|
|
|
|
elen -= MAX_EXTRA;
|
|
|
|
queue_probe(&raddr, &laddr, MAX_EXTRA, &other[elen], 1);
|
1998-02-26 17:55:42 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
queue_probe(&raddr, &laddr, elen, other, 1);
|
1998-02-26 17:55:42 +00:00
|
|
|
}
|
1997-05-03 19:18:21 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
port = my_port;
|
|
|
|
*(unsigned long*)w_info[desc].buf = htonl(port);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (type == GDO_PREPLY)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* This should really be a reply by UDP to a probe we sent
|
|
|
|
* out earlier. We should add the name server to our list.
|
|
|
|
*/
|
|
|
|
if (r_info[desc].addr.sin_port == my_port)
|
|
|
|
{
|
|
|
|
struct in_addr sin;
|
|
|
|
unsigned long net;
|
|
|
|
struct in_addr *ptr;
|
|
|
|
int c;
|
|
|
|
|
|
|
|
memcpy(&sin, &r_info[desc].buf.r.name, IASIZE);
|
|
|
|
if (debug > 2)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "Probe reply from '%s'\n", inet_ntoa(sin));
|
1998-02-26 17:55:42 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
net = inet_netof(sin);
|
|
|
|
ptr = (struct in_addr*)&r_info[desc].buf.r.name[2*IASIZE];
|
|
|
|
c = (r_info[desc].buf.r.nsize - 2*IASIZE)/IASIZE;
|
|
|
|
prb_add(&sin);
|
|
|
|
while (c-- > 0)
|
|
|
|
{
|
|
|
|
if (debug > 2)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "Delete server '%s'\n", inet_ntoa(*ptr));
|
1997-05-03 19:18:21 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
prb_del(ptr);
|
|
|
|
ptr++;
|
1997-05-03 19:18:21 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
/*
|
|
|
|
* Irrespective of what we are told to do - we also add the
|
|
|
|
* interface from which this packet arrived so we have a
|
|
|
|
* route we KNOW we can use.
|
|
|
|
*/
|
|
|
|
prb_add(&r_info[desc].addr.sin_addr);
|
1997-05-03 19:18:21 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
/*
|
|
|
|
* Because this is really a reply to us, we don't want to reply
|
|
|
|
* to it or we would get a feedback loop.
|
|
|
|
*/
|
|
|
|
clear_chan(desc);
|
|
|
|
return;
|
1997-05-03 19:18:21 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
fprintf(stderr, "Illegal operation code received!\n");
|
|
|
|
clear_chan(desc);
|
|
|
|
return;
|
1997-05-03 19:18:21 +00:00
|
|
|
}
|
|
|
|
|
1998-10-29 16:20:53 +00:00
|
|
|
/*
|
|
|
|
* If the request was via UDP, we send a response back by queuing
|
|
|
|
* rather than letting the normal 'write_handler()' function do it.
|
|
|
|
*/
|
|
|
|
if (desc == udp_desc)
|
|
|
|
{
|
|
|
|
queue_msg(&r_info[desc].addr, w_info[desc].buf, w_info[desc].len);
|
|
|
|
clear_chan(desc);
|
1997-05-03 19:18:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1997-09-01 21:59:51 +00:00
|
|
|
/*
|
|
|
|
* Name - handle_send()
|
|
|
|
* Purpose - Send any pending message on UDP socket.
|
|
|
|
* The code is designed to send the message in parts if
|
|
|
|
* the 'sendto()' function returns a positive integer
|
|
|
|
* indicating that only part of the message has been
|
|
|
|
* written. This should never happen - but I coded it
|
|
|
|
* this way in case we have to run on a system which
|
|
|
|
* implements sendto() badly (I used such a system
|
|
|
|
* many years ago).
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
handle_send()
|
|
|
|
{
|
1998-10-29 16:20:53 +00:00
|
|
|
struct u_data* entry = u_queue;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
1998-10-29 16:20:53 +00:00
|
|
|
if (entry)
|
|
|
|
{
|
|
|
|
int r;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
1998-10-29 16:20:53 +00:00
|
|
|
r = sendto(udp_desc, &entry->dat[entry->pos], entry->len - entry->pos,
|
1997-09-01 21:59:51 +00:00
|
|
|
0, (void*)&entry->addr, sizeof(entry->addr));
|
1998-10-29 16:20:53 +00:00
|
|
|
/*
|
|
|
|
* 'r' is the number of bytes sent. This should be the number
|
|
|
|
* of bytes we asked to send, or -1 to indicate failure.
|
|
|
|
*/
|
|
|
|
if (r > 0)
|
|
|
|
{
|
|
|
|
entry->pos += r;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If we haven't written all the data, it should have been
|
|
|
|
* because we blocked. Anything else is a major problem
|
|
|
|
* so we remove the message from the queue.
|
|
|
|
*/
|
|
|
|
if (entry->pos != entry->len)
|
|
|
|
{
|
|
|
|
if (errno != EWOULDBLOCK)
|
|
|
|
{
|
|
|
|
if (debug)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "failed sendto for %s\n",
|
1997-09-01 21:59:51 +00:00
|
|
|
inet_ntoa(entry->addr.sin_addr));
|
|
|
|
}
|
1999-08-21 05:29:10 +00:00
|
|
|
queue_pop();
|
1997-09-01 21:59:51 +00:00
|
|
|
}
|
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
udp_sent++;
|
|
|
|
if (debug > 1)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "performed sendto for %s\n",
|
1997-09-01 21:59:51 +00:00
|
|
|
inet_ntoa(entry->addr.sin_addr));
|
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
/*
|
|
|
|
* If we have sent the entire message - remove it from queue.
|
|
|
|
*/
|
|
|
|
if (entry->pos == entry->len)
|
|
|
|
{
|
|
|
|
queue_pop();
|
1997-09-01 21:59:51 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1997-05-03 19:18:21 +00:00
|
|
|
/*
|
|
|
|
* Name - handle_write()
|
|
|
|
* Purpose - Write data to a channel. When all writing for the
|
|
|
|
* channel is complete, close the channel down.
|
|
|
|
*
|
|
|
|
* This is all probably totally paranoid - the reply
|
|
|
|
* to any request is so short that the write operation
|
|
|
|
* should not block so there shouldn't be any need to
|
|
|
|
* handle non-blocking I/O.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
handle_write(int desc)
|
|
|
|
{
|
1998-10-29 16:20:53 +00:00
|
|
|
char *ptr = w_info[desc].buf;
|
|
|
|
int len = w_info[desc].len;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
r = write(desc, &ptr[w_info[desc].pos], len - w_info[desc].pos);
|
|
|
|
if (r < 0)
|
|
|
|
{
|
|
|
|
if (debug > 1)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "Failed write on chan %d - closing\n", desc);
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* Failure - close connection silently.
|
|
|
|
*/
|
|
|
|
clear_chan(desc);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
w_info[desc].pos += r;
|
|
|
|
if (w_info[desc].pos >= len)
|
|
|
|
{
|
|
|
|
tcp_sent++;
|
|
|
|
if (debug > 1)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "Completed write on chan %d - closing\n", desc);
|
1997-09-01 21:59:51 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
/*
|
|
|
|
* Success - written all information.
|
|
|
|
*/
|
|
|
|
clear_chan(desc);
|
1997-05-03 19:18:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1998-10-27 20:58:22 +00:00
|
|
|
/*
|
|
|
|
* Name - tryRead()
|
|
|
|
* Purpose - Attempt to read from a non blocking channel.
|
|
|
|
* Time out in specified time.
|
|
|
|
* If length of data is zero then just wait for
|
|
|
|
* descriptor to be readable.
|
|
|
|
* If the length is negative then attempt to
|
|
|
|
* read the absolute value of length but return
|
|
|
|
* as soon as anything is read.
|
|
|
|
*
|
|
|
|
* Return -1 on failure
|
|
|
|
* Return -2 on timeout
|
|
|
|
* Return number of bytes read
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
tryRead(int desc, int tim, unsigned char* dat, int len)
|
|
|
|
{
|
|
|
|
struct timeval timeout;
|
|
|
|
fd_set fds;
|
|
|
|
void *to;
|
|
|
|
int rval;
|
|
|
|
int pos = 0;
|
|
|
|
time_t when = 0;
|
|
|
|
int neg = 0;
|
|
|
|
|
1998-10-29 16:20:53 +00:00
|
|
|
if (len < 0)
|
|
|
|
{
|
|
|
|
neg = 1;
|
|
|
|
len = -len;
|
|
|
|
}
|
1998-10-27 20:58:22 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* First time round we do a select with an instant timeout to see
|
|
|
|
* if the descriptor is already readable.
|
|
|
|
*/
|
|
|
|
timeout.tv_sec = 0;
|
|
|
|
timeout.tv_usec = 0;
|
|
|
|
|
1998-10-29 16:20:53 +00:00
|
|
|
for (;;)
|
|
|
|
{
|
|
|
|
to = &timeout;
|
1999-02-17 14:35:49 +00:00
|
|
|
memset(&fds, '\0', sizeof(fds));
|
1998-10-29 16:20:53 +00:00
|
|
|
FD_SET(desc, &fds);
|
|
|
|
|
|
|
|
rval = select(FD_SETSIZE, &fds, 0, 0, to);
|
|
|
|
if (rval == 0)
|
|
|
|
{
|
|
|
|
time_t now = time(0);
|
|
|
|
|
|
|
|
if (when == 0)
|
|
|
|
{
|
|
|
|
when = now;
|
|
|
|
}
|
|
|
|
else if (now - when >= tim)
|
|
|
|
{
|
1998-12-05 06:50:15 +00:00
|
|
|
return -2; /* Timed out. */
|
1998-10-29 16:20:53 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Set the timeout for a new call to select next time
|
|
|
|
* round the loop.
|
|
|
|
*/
|
|
|
|
timeout.tv_sec = tim - (now - when);
|
|
|
|
timeout.tv_usec = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (rval < 0)
|
|
|
|
{
|
1998-12-05 06:50:15 +00:00
|
|
|
return -1; /* Error in select. */
|
1998-10-29 16:20:53 +00:00
|
|
|
}
|
|
|
|
else if (len > 0)
|
|
|
|
{
|
|
|
|
rval = read(desc, &dat[pos], len - pos);
|
|
|
|
if (rval < 0)
|
|
|
|
{
|
|
|
|
if (errno != EWOULDBLOCK)
|
|
|
|
{
|
1998-12-05 06:50:15 +00:00
|
|
|
return -1; /* Error in read. */
|
1998-10-29 16:20:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (rval == 0)
|
|
|
|
{
|
1998-12-05 06:50:15 +00:00
|
|
|
return -1; /* End of file. */
|
1998-10-29 16:20:53 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
pos += rval;
|
|
|
|
if (pos == len || neg == 1)
|
|
|
|
{
|
1998-12-05 06:50:15 +00:00
|
|
|
return pos; /* Read as needed. */
|
1998-10-29 16:20:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
1998-12-05 06:50:15 +00:00
|
|
|
return 0; /* Not actually asked to read. */
|
1998-10-27 20:58:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Name - tryWrite()
|
|
|
|
* Purpose - Attempt to write to a non blocking channel.
|
|
|
|
* Time out in specified time.
|
|
|
|
* If length of data is zero then just wait for
|
|
|
|
* descriptor to be writable.
|
|
|
|
* If the length is negative then attempt to
|
|
|
|
* write the absolute value of length but return
|
|
|
|
* as soon as anything is written.
|
|
|
|
*
|
|
|
|
* Return -1 on failure
|
|
|
|
* Return -2 on timeout
|
|
|
|
* Return number of bytes written
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
tryWrite(int desc, int tim, unsigned char* dat, int len)
|
|
|
|
{
|
|
|
|
struct timeval timeout;
|
|
|
|
fd_set fds;
|
|
|
|
void *to;
|
|
|
|
int rval;
|
|
|
|
int pos = 0;
|
|
|
|
time_t when = 0;
|
|
|
|
int neg = 0;
|
|
|
|
|
|
|
|
if (len < 0) {
|
|
|
|
neg = 1;
|
|
|
|
len = -len;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* First time round we do a select with an instant timeout to see
|
|
|
|
* if the descriptor is already writable.
|
|
|
|
*/
|
|
|
|
timeout.tv_sec = 0;
|
|
|
|
timeout.tv_usec = 0;
|
|
|
|
|
1998-10-29 16:20:53 +00:00
|
|
|
for (;;)
|
|
|
|
{
|
|
|
|
to = &timeout;
|
1999-02-17 14:35:49 +00:00
|
|
|
memset(&fds, '\0', sizeof(fds));
|
1998-10-29 16:20:53 +00:00
|
|
|
FD_SET(desc, &fds);
|
|
|
|
|
|
|
|
rval = select(FD_SETSIZE, 0, &fds, 0, to);
|
|
|
|
if (rval == 0)
|
|
|
|
{
|
|
|
|
time_t now = time(0);
|
|
|
|
|
|
|
|
if (when == 0)
|
|
|
|
{
|
|
|
|
when = now;
|
|
|
|
}
|
|
|
|
else if (now - when >= tim)
|
|
|
|
{
|
1998-12-05 06:50:15 +00:00
|
|
|
return -2; /* Timed out. */
|
1998-10-29 16:20:53 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Set the timeout for a new call to select next time round
|
|
|
|
* the loop. */
|
|
|
|
timeout.tv_sec = tim - (now - when);
|
|
|
|
timeout.tv_usec = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (rval < 0)
|
|
|
|
{
|
1998-12-05 06:50:15 +00:00
|
|
|
return -1; /* Error in select. */
|
1998-10-29 16:20:53 +00:00
|
|
|
}
|
|
|
|
else if (len > 0)
|
|
|
|
{
|
|
|
|
void (*ifun)();
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Should be able to write this short a message immediately, but
|
|
|
|
* if the connection is lost we will get a signal we must trap.
|
|
|
|
*/
|
|
|
|
ifun = signal(SIGPIPE, (void(*)(int))SIG_IGN);
|
|
|
|
rval = write(desc, &dat[pos], len - pos);
|
|
|
|
signal(SIGPIPE, ifun);
|
|
|
|
|
|
|
|
if (rval <= 0)
|
|
|
|
{
|
|
|
|
if (errno != EWOULDBLOCK)
|
|
|
|
{
|
1998-12-05 06:50:15 +00:00
|
|
|
return -1; /* Error in write. */
|
1998-10-29 16:20:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
pos += rval;
|
|
|
|
if (pos == len || neg == 1)
|
|
|
|
{
|
1998-12-05 06:50:15 +00:00
|
|
|
return pos; /* Written as needed. */
|
1998-10-29 16:20:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
1998-12-05 06:50:15 +00:00
|
|
|
return 0; /* Not actually asked to write. */
|
1998-10-27 20:58:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Name - tryHost()
|
|
|
|
* Purpose - Perform a name server operation with a given
|
|
|
|
* request packet to a server at specified address.
|
|
|
|
* On error - return non-zero with reason in 'errno'
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
tryHost(unsigned char op, unsigned char len, const unsigned char* name,
|
|
|
|
int ptype, struct sockaddr_in* addr, unsigned short* p, uptr*v)
|
|
|
|
{
|
1998-10-29 16:20:53 +00:00
|
|
|
int desc = socket(AF_INET, SOCK_STREAM, 0);
|
|
|
|
int e = 0;
|
|
|
|
unsigned long port = *p;
|
|
|
|
gdo_req msg;
|
|
|
|
struct sockaddr_in sin;
|
|
|
|
|
|
|
|
*p = 0;
|
|
|
|
if (desc < 0)
|
|
|
|
{
|
1998-12-05 06:50:15 +00:00
|
|
|
return 1; /* Couldn't create socket. */
|
1998-10-27 20:58:22 +00:00
|
|
|
}
|
|
|
|
|
1998-10-29 16:20:53 +00:00
|
|
|
if ((e = fcntl(desc, F_GETFL, 0)) >= 0)
|
|
|
|
{
|
|
|
|
e |= NBLK_OPT;
|
|
|
|
if (fcntl(desc, F_SETFL, e) < 0)
|
|
|
|
{
|
|
|
|
e = errno;
|
|
|
|
close(desc);
|
|
|
|
errno = e;
|
1998-12-05 06:50:15 +00:00
|
|
|
return 2; /* Couldn't set non-blocking. */
|
1998-10-27 20:58:22 +00:00
|
|
|
}
|
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
e = errno;
|
|
|
|
close(desc);
|
|
|
|
errno = e;
|
1998-12-05 06:50:15 +00:00
|
|
|
return 2; /* Couldn't set non-blocking. */
|
1998-10-27 20:58:22 +00:00
|
|
|
}
|
|
|
|
|
1998-10-29 16:20:53 +00:00
|
|
|
memcpy(&sin, addr, sizeof(sin));
|
|
|
|
if (connect(desc, (struct sockaddr*)&sin, sizeof(sin)) != 0)
|
|
|
|
{
|
|
|
|
if (errno == EINPROGRESS)
|
|
|
|
{
|
|
|
|
e = tryWrite(desc, 10, 0, 0);
|
|
|
|
if (e == -2)
|
|
|
|
{
|
|
|
|
e = errno;
|
|
|
|
close(desc);
|
|
|
|
errno = e;
|
1998-12-05 06:50:15 +00:00
|
|
|
return 3; /* Connect timed out. */
|
1998-10-27 20:58:22 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
else if (e == -1)
|
|
|
|
{
|
|
|
|
e = errno;
|
|
|
|
close(desc);
|
|
|
|
errno = e;
|
1998-12-05 06:50:15 +00:00
|
|
|
return 3; /* Select failed. */
|
1998-10-27 20:58:22 +00:00
|
|
|
}
|
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
e = errno;
|
|
|
|
close(desc);
|
|
|
|
errno = e;
|
1998-12-05 06:50:15 +00:00
|
|
|
return 3; /* Failed connect. */
|
1998-10-27 20:58:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1998-10-29 16:20:53 +00:00
|
|
|
memset((char*)&msg, '\0', GDO_REQ_SIZE);
|
|
|
|
msg.rtype = op;
|
|
|
|
msg.nsize = len;
|
|
|
|
msg.ptype = ptype;
|
|
|
|
if (op != GDO_REGISTER)
|
|
|
|
{
|
|
|
|
port = 0;
|
1998-10-27 20:58:22 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
msg.port = htonl(port);
|
|
|
|
memcpy(msg.name, name, len);
|
1998-10-27 20:58:22 +00:00
|
|
|
|
1998-10-29 16:20:53 +00:00
|
|
|
e = tryWrite(desc, 10, (uptr)&msg, GDO_REQ_SIZE);
|
|
|
|
if (e != GDO_REQ_SIZE)
|
|
|
|
{
|
|
|
|
e = errno;
|
|
|
|
close(desc);
|
|
|
|
errno = e;
|
1998-12-05 06:50:15 +00:00
|
|
|
return 4;
|
1998-10-27 20:58:22 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
e = tryRead(desc, 3, (uptr)&port, 4);
|
|
|
|
if (e != 4)
|
|
|
|
{
|
|
|
|
e = errno;
|
|
|
|
close(desc);
|
|
|
|
errno = e;
|
1998-12-05 06:50:15 +00:00
|
|
|
return 5; /* Read timed out. */
|
1998-10-27 20:58:22 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
port = ntohl(port);
|
1998-10-27 20:58:22 +00:00
|
|
|
|
1998-10-29 16:20:53 +00:00
|
|
|
/*
|
|
|
|
* Special case for GDO_SERVERS - allocate buffer and read list.
|
|
|
|
*/
|
|
|
|
if (op == GDO_SERVERS)
|
|
|
|
{
|
|
|
|
int len = port * sizeof(struct in_addr);
|
|
|
|
uptr b;
|
1998-10-27 20:58:22 +00:00
|
|
|
|
1998-10-29 16:20:53 +00:00
|
|
|
b = (uptr)malloc(len);
|
|
|
|
if (tryRead(desc, 3, b, len) != len)
|
|
|
|
{
|
|
|
|
free(b);
|
|
|
|
e = errno;
|
|
|
|
close(desc);
|
|
|
|
errno = e;
|
1998-12-05 06:50:15 +00:00
|
|
|
return 5;
|
1998-10-27 20:58:22 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
*v = b;
|
1998-10-27 20:58:22 +00:00
|
|
|
}
|
|
|
|
|
1998-10-29 16:20:53 +00:00
|
|
|
*p = (unsigned short)port;
|
|
|
|
close(desc);
|
|
|
|
errno = 0;
|
1998-12-05 06:50:15 +00:00
|
|
|
return 0;
|
1998-10-27 20:58:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Name - nameFail()
|
|
|
|
* Purpose - If given a failure status from tryHost()
|
|
|
|
* raise an appropriate exception.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
nameFail(int why)
|
|
|
|
{
|
1998-10-29 16:20:53 +00:00
|
|
|
switch (why)
|
|
|
|
{
|
|
|
|
case 0: break;
|
|
|
|
case 1:
|
|
|
|
fprintf(stderr, "failed to contact name server - socket - %s",
|
|
|
|
strerror(errno));
|
|
|
|
case 2:
|
|
|
|
fprintf(stderr, "failed to contact name server - socket - %s",
|
|
|
|
strerror(errno));
|
|
|
|
case 3:
|
|
|
|
fprintf(stderr, "failed to contact name server - socket - %s",
|
|
|
|
strerror(errno));
|
|
|
|
case 4:
|
|
|
|
fprintf(stderr, "failed to contact name server - socket - %s",
|
|
|
|
strerror(errno));
|
1998-10-27 20:58:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Name - nameServer()
|
|
|
|
* Purpose - Perform name server lookup or registration.
|
|
|
|
* Return success/failure status and set up an
|
|
|
|
* address structure for use in bind or connect.
|
|
|
|
* Restrictions - 0xffff byte name limit
|
|
|
|
* Uses old style host lookup - only handles the
|
|
|
|
* primary network interface for each host!
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
nameServer(const char* name, const char* host, int op, int ptype, struct sockaddr_in* addr, int pnum, int max)
|
|
|
|
{
|
1998-10-29 16:20:53 +00:00
|
|
|
struct sockaddr_in sin;
|
|
|
|
struct servent* sp;
|
|
|
|
struct hostent* hp;
|
|
|
|
unsigned short p = htons(GDOMAP_PORT);
|
|
|
|
unsigned short port = 0;
|
|
|
|
int len = strlen(name);
|
|
|
|
int multi = 0;
|
|
|
|
int found = 0;
|
|
|
|
int rval;
|
|
|
|
char local_hostname[MAXHOSTNAMELEN];
|
|
|
|
|
|
|
|
if (len == 0)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "no name specified.\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (len > 0xffff)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "name length to large.\n");
|
|
|
|
return -1;
|
1998-10-27 20:58:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#if GDOMAP_PORT_OVERRIDE
|
1998-10-29 16:20:53 +00:00
|
|
|
p = htons(GDOMAP_PORT_OVERRIDE);
|
1998-10-27 20:58:22 +00:00
|
|
|
#else
|
1998-10-29 16:20:53 +00:00
|
|
|
/*
|
|
|
|
* Ensure we have port number to connect to name server.
|
|
|
|
* The TCP service name 'gdomap' overrides the default port.
|
|
|
|
*/
|
|
|
|
if ((sp = getservbyname("gdomap", "tcp")) != 0)
|
|
|
|
{
|
|
|
|
p = sp->s_port; /* Network byte order. */
|
1998-10-27 20:58:22 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
1998-10-29 16:20:53 +00:00
|
|
|
/*
|
|
|
|
* The host name '*' matches any host on the local network.
|
|
|
|
*/
|
|
|
|
if (host && host[0] == '*' && host[1] == '\0')
|
|
|
|
{
|
1998-10-27 20:58:22 +00:00
|
|
|
multi = 1;
|
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
/*
|
|
|
|
* If no host name is given, we use the name of the local host.
|
|
|
|
* NB. This should always be the case for operations other than lookup.
|
|
|
|
*/
|
|
|
|
if (multi || host == 0 || *host == '\0')
|
|
|
|
{
|
|
|
|
char *first_dot;
|
|
|
|
|
|
|
|
if (gethostname(local_hostname, sizeof(local_hostname)) < 0)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "gethostname() failed: %s", strerror(errno));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
first_dot = strchr(local_hostname, '.');
|
|
|
|
if (first_dot)
|
|
|
|
{
|
|
|
|
*first_dot = '\0';
|
|
|
|
}
|
|
|
|
host = local_hostname;
|
|
|
|
}
|
|
|
|
if ((hp = gethostbyname(host)) == 0)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "gethostbyname() failed: %s", strerror(errno));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (hp->h_addrtype != AF_INET)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "non-internet network not supported for %s\n", host);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
memset((char*)&sin, '\0', sizeof(sin));
|
|
|
|
sin.sin_family = AF_INET;
|
|
|
|
sin.sin_port = p;
|
|
|
|
memcpy((caddr_t)&sin.sin_addr, hp->h_addr, hp->h_length);
|
|
|
|
|
|
|
|
if (multi)
|
|
|
|
{
|
|
|
|
unsigned short num;
|
|
|
|
struct in_addr* b;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* A host name of '*' is a special case which should do lookup on
|
|
|
|
* all machines on the local network until one is found which has
|
|
|
|
* the specified server on it.
|
|
|
|
*/
|
|
|
|
rval = tryHost(GDO_SERVERS, 0, 0, ptype, &sin, &num, (uptr*)&b);
|
|
|
|
if (rval != 0 && host == local_hostname)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "failed to contact gdomap\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (rval == 0)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; found == 0 && i < num; i++)
|
|
|
|
{
|
|
|
|
memset((char*)&sin, '\0', sizeof(sin));
|
|
|
|
sin.sin_family = AF_INET;
|
|
|
|
sin.sin_port = p;
|
|
|
|
memcpy((caddr_t)&sin.sin_addr, &b[i], sizeof(struct in_addr));
|
|
|
|
if (sin.sin_addr.s_addr == 0)
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tryHost(GDO_LOOKUP, len, name, ptype, &sin, &port, 0)==0)
|
|
|
|
{
|
|
|
|
if (port != 0)
|
|
|
|
{
|
|
|
|
memset((char*)&addr[found], '\0', sizeof(*addr));
|
|
|
|
memcpy((caddr_t)&addr[found].sin_addr, &sin.sin_addr,
|
1998-10-27 20:58:22 +00:00
|
|
|
sizeof(sin.sin_addr));
|
1998-10-29 16:20:53 +00:00
|
|
|
addr[found].sin_family = AF_INET;
|
|
|
|
addr[found].sin_port = htons(port);
|
|
|
|
found++;
|
|
|
|
if (found == max)
|
|
|
|
{
|
|
|
|
break;
|
1998-10-27 20:58:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
free(b);
|
1998-12-05 06:50:15 +00:00
|
|
|
return found;
|
1998-10-27 20:58:22 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
nameFail(rval);
|
1998-10-27 20:58:22 +00:00
|
|
|
}
|
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
if (op == GDO_REGISTER)
|
|
|
|
{
|
|
|
|
port = (unsigned short)pnum;
|
1998-10-27 20:58:22 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
rval = tryHost(op, len, name, ptype, &sin, &port, 0);
|
|
|
|
if (rval != 0 && host == local_hostname)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "failed to contact gdomap\n");
|
|
|
|
return -1;
|
1998-10-27 20:58:22 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
nameFail(rval);
|
1998-10-27 20:58:22 +00:00
|
|
|
}
|
|
|
|
|
1998-10-29 16:20:53 +00:00
|
|
|
if (op == GDO_REGISTER)
|
|
|
|
{
|
|
|
|
if (port == 0 || (pnum != 0 && port != pnum))
|
|
|
|
{
|
|
|
|
fprintf(stderr, "service already registered.\n");
|
|
|
|
return -1;
|
1998-10-27 20:58:22 +00:00
|
|
|
}
|
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
if (port == 0)
|
|
|
|
{
|
|
|
|
return 0;
|
1998-10-27 20:58:22 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
memset((char*)addr, '\0', sizeof(*addr));
|
|
|
|
memcpy((caddr_t)&addr->sin_addr, &sin.sin_addr, sizeof(sin.sin_addr));
|
|
|
|
addr->sin_family = AF_INET;
|
|
|
|
addr->sin_port = htons(port);
|
|
|
|
return 1;
|
1998-10-27 20:58:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
lookup(const char *name, const char *host, int ptype)
|
|
|
|
{
|
|
|
|
struct sockaddr_in sin[100];
|
|
|
|
int found;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
found = nameServer(name, host, GDO_LOOKUP, ptype, sin, 0, 100);
|
|
|
|
for (i = 0; i < found; i++)
|
|
|
|
{
|
|
|
|
printf("Found %s on '%s' port %d\n", name,
|
|
|
|
inet_ntoa(sin[i].sin_addr), ntohs(sin[i].sin_port));
|
|
|
|
}
|
|
|
|
if (found == 0)
|
|
|
|
{
|
|
|
|
printf("Unable to find %s.\n", name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
doregister(const char *name, int port, int ptype)
|
|
|
|
{
|
|
|
|
struct sockaddr_in sin;
|
|
|
|
int found;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
found = nameServer(name, 0, GDO_REGISTER, ptype, &sin, port, 1);
|
|
|
|
for (i = 0; i < found; i++)
|
|
|
|
{
|
|
|
|
printf("Registered %s on '%s' port %d\n", name,
|
|
|
|
inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
|
|
|
|
}
|
|
|
|
if (found == 0)
|
|
|
|
{
|
|
|
|
printf("Unable to register %s on port %d.\n", name, port);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
1998-11-02 11:48:42 +00:00
|
|
|
unregister(const char *name, int port, int ptype)
|
1998-10-27 20:58:22 +00:00
|
|
|
{
|
|
|
|
struct sockaddr_in sin;
|
|
|
|
int found;
|
|
|
|
int i;
|
|
|
|
|
1998-11-02 11:48:42 +00:00
|
|
|
found = nameServer(name, 0, GDO_UNREG, ptype, &sin, port, 1);
|
1998-10-27 20:58:22 +00:00
|
|
|
for (i = 0; i < found; i++)
|
|
|
|
{
|
|
|
|
printf("Unregistered %s on '%s' port %d\n", name,
|
|
|
|
inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
|
|
|
|
}
|
|
|
|
if (found == 0)
|
|
|
|
{
|
|
|
|
printf("Unable to unregister %s.\n", name);
|
|
|
|
}
|
|
|
|
}
|
1997-05-03 19:18:21 +00:00
|
|
|
|
|
|
|
int
|
|
|
|
main(int argc, char** argv)
|
|
|
|
{
|
1998-10-29 16:20:53 +00:00
|
|
|
extern char *optarg;
|
2000-02-22 08:32:04 +00:00
|
|
|
char *options = "CHI:L:M:P:R:T:U:a:bc:dfi:p";
|
1998-10-29 16:20:53 +00:00
|
|
|
int c;
|
|
|
|
int ptype = GDO_TCP_GDO;
|
|
|
|
int port = 0;
|
|
|
|
const char *machine = 0;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Would use inet_aton(), but older systems don't have it.
|
|
|
|
*/
|
|
|
|
loopback.s_addr = inet_addr("127.0.0.1");
|
|
|
|
class_a_net = inet_network("255.0.0.0");
|
|
|
|
class_a_mask = inet_makeaddr(class_a_net, 0);
|
|
|
|
class_b_net = inet_network("255.255.0.0");
|
|
|
|
class_b_mask = inet_makeaddr(class_b_net, 0);
|
|
|
|
class_c_net = inet_network("255.255.255.0");
|
|
|
|
class_c_mask = inet_makeaddr(class_c_net, 0);
|
|
|
|
|
|
|
|
while ((c = getopt(argc, argv, options)) != -1)
|
|
|
|
{
|
|
|
|
switch(c)
|
|
|
|
{
|
|
|
|
case 'H':
|
|
|
|
printf("%s -[%s]\n", argv[0], options);
|
|
|
|
printf("GNU Distributed Objects name server\n");
|
|
|
|
printf("-C help about configuration\n");
|
|
|
|
printf("-H general help\n");
|
2000-02-22 08:32:04 +00:00
|
|
|
printf("-I pid file to write pid\n");
|
1998-10-29 16:20:53 +00:00
|
|
|
printf("-L name perform lookup for name then quit.\n");
|
|
|
|
printf("-M name machine name for L (default local)\n");
|
|
|
|
printf("-P number port number required for R option.\n");
|
|
|
|
printf("-R name register name locally then quit.\n");
|
|
|
|
printf("-T type port type for L, R and U options -\n");
|
|
|
|
printf(" tcp_gdo, udp_gdo,\n");
|
|
|
|
printf(" tcp_foreign, udp_foreign.\n");
|
|
|
|
printf("-U name unregister name locally then quit.\n");
|
|
|
|
printf("-a file use config file for interface list.\n");
|
2000-02-22 08:32:04 +00:00
|
|
|
printf("-p disable udp broadcast for probe\n");
|
1998-10-29 16:20:53 +00:00
|
|
|
printf("-c file use config file for probe.\n");
|
|
|
|
printf("-d extra debug logging.\n");
|
|
|
|
printf("-f avoid fork() to make debugging easy\n");
|
1999-08-21 05:29:10 +00:00
|
|
|
printf("-i seconds re-probe at this interval (roughly), min 60\n");
|
2000-02-22 08:32:04 +00:00
|
|
|
printf("-p disable probing for other servers\n");
|
1998-10-29 16:20:53 +00:00
|
|
|
printf("\n");
|
|
|
|
exit(0);
|
|
|
|
|
|
|
|
case 'C':
|
|
|
|
printf("\n");
|
|
|
|
printf(
|
1998-03-10 19:01:24 +00:00
|
|
|
"Gdomap normally probes every machine on the local network to see if there\n"
|
|
|
|
"is a copy of gdomap running on it. This is done for class-C networks and\n"
|
|
|
|
"subnets of class-C networks. If your host is on a class-B or class-A net\n"
|
|
|
|
"then the default behaviour is to treat it as a class-C net and probe only\n"
|
|
|
|
"the hosts that would be expected on a class-C network of the same number.\n");
|
1998-10-29 16:20:53 +00:00
|
|
|
printf("\n");
|
|
|
|
printf(
|
1998-03-10 19:01:24 +00:00
|
|
|
"If you are running on a class-A or class-B network, or if your net has a\n"
|
|
|
|
"large number of hosts which will not have gdomap on them - you may want to\n"
|
|
|
|
"supply a configuration file listing the hosts to be probed explicitly,\n"
|
|
|
|
"rather than getting gdomap to probe all hosts on the local net.\n");
|
1998-10-29 16:20:53 +00:00
|
|
|
printf("\n");
|
|
|
|
printf(
|
1998-03-10 19:01:24 +00:00
|
|
|
"You may also want to supply the configuration file so that hosts which are\n"
|
|
|
|
"not actually on your local network can still be found when your code tries\n"
|
|
|
|
"to connect to a host using @\"*\" as the host name. NB. this functionality\n"
|
|
|
|
"does not exist in OpenStep.\n");
|
1998-10-29 16:20:53 +00:00
|
|
|
printf("\n");
|
|
|
|
printf(
|
1998-03-10 19:01:24 +00:00
|
|
|
"A configuration file consists of a list of IP addresses to be probed.\n"
|
2000-02-21 22:01:08 +00:00
|
|
|
"The IP addresses should be in standard 'dot' notation, one per line.\n"
|
1998-03-10 19:01:24 +00:00
|
|
|
"Empty lines are permitted in the configuration file.\n"
|
|
|
|
"Anything on a line after a hash ('#') is ignored.\n"
|
|
|
|
"You tell gdomap about the config file with the '-c' command line option.\n");
|
1998-10-29 16:20:53 +00:00
|
|
|
printf("\n");
|
|
|
|
printf("\n");
|
1998-05-29 15:25:41 +00:00
|
|
|
printf(
|
|
|
|
"gdomap uses the SIOCGIFCONF ioctl to build a list of IP addresses and\n"
|
|
|
|
"netmasks for the network interface cards on your machine. On some operating\n"
|
|
|
|
"systems, this facility is not available (or is broken), so you must tell\n"
|
|
|
|
"gdomap the addresses and masks of the interfaces using the '-a' command line\n"
|
|
|
|
"option. The file named with '-a' should contain a series of lines with\n"
|
|
|
|
"space separated pairs of addresses and masks in 'dot' notation.\n"
|
|
|
|
"You must NOT include loopback interfaces in this list.\n"
|
|
|
|
"If your operating system has some other method of giving you a list of\n"
|
|
|
|
"network interfaces and masks, please send me example code so that I can\n"
|
|
|
|
"implement it in gdomap.\n");
|
1998-10-29 16:20:53 +00:00
|
|
|
printf("\n");
|
|
|
|
exit(0);
|
|
|
|
|
|
|
|
case 'L':
|
|
|
|
lookup(optarg, machine, ptype);
|
|
|
|
exit(0);
|
|
|
|
|
|
|
|
case 'M':
|
|
|
|
machine = optarg;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'P':
|
|
|
|
port = atoi(optarg);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'R':
|
|
|
|
if (machine && *machine)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "-M flag is ignored for registration.\n");
|
|
|
|
fprintf(stderr, "Registration will take place locally.\n");
|
|
|
|
}
|
|
|
|
doregister(optarg, port, ptype);
|
1999-06-24 19:30:29 +00:00
|
|
|
return 0;
|
1998-10-29 16:20:53 +00:00
|
|
|
|
|
|
|
case 'T':
|
|
|
|
if (strcmp(optarg, "tcp_gdo") == 0)
|
|
|
|
{
|
|
|
|
ptype = GDO_TCP_GDO;
|
|
|
|
}
|
|
|
|
else if (strcmp(optarg, "udp_gdo") == 0)
|
|
|
|
{
|
|
|
|
ptype = GDO_UDP_GDO;
|
|
|
|
}
|
|
|
|
else if (strcmp(optarg, "tcp_foreign") == 0)
|
|
|
|
{
|
|
|
|
ptype = GDO_TCP_FOREIGN;
|
|
|
|
}
|
|
|
|
else if (strcmp(optarg, "udp_foreign") == 0)
|
|
|
|
{
|
|
|
|
ptype = GDO_UDP_FOREIGN;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
fprintf(stderr, "Warning - -P selected unknown type -");
|
|
|
|
fprintf(stderr, " using tcp_gdo.\n");
|
|
|
|
ptype = GDO_TCP_GDO;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'U':
|
|
|
|
if (machine && *machine)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "-M flag is ignored for unregistration.\n");
|
|
|
|
fprintf(stderr, "Operation will take place locally.\n");
|
|
|
|
}
|
1998-11-02 11:48:42 +00:00
|
|
|
unregister(optarg, port, ptype);
|
1998-10-29 16:20:53 +00:00
|
|
|
exit(0);
|
|
|
|
|
|
|
|
case 'a':
|
|
|
|
load_iface(optarg);
|
|
|
|
break;
|
|
|
|
|
2000-02-22 08:32:04 +00:00
|
|
|
case 'b':
|
|
|
|
nobcst++;
|
|
|
|
break;
|
|
|
|
|
1998-10-29 16:20:53 +00:00
|
|
|
case 'c':
|
|
|
|
{
|
|
|
|
FILE *fptr = fopen(optarg, "r");
|
|
|
|
char buf[128];
|
|
|
|
|
|
|
|
if (fptr == 0)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "Unable to open probe config - '%s'\n",
|
|
|
|
optarg);
|
|
|
|
exit(1);
|
1998-10-27 20:58:22 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
while (fgets(buf, sizeof(buf), fptr) != 0)
|
1998-03-10 19:01:24 +00:00
|
|
|
{
|
1998-10-29 16:20:53 +00:00
|
|
|
char *ptr = buf;
|
|
|
|
plentry *prb;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Strip leading white space.
|
|
|
|
*/
|
|
|
|
while (isspace(*ptr))
|
|
|
|
{
|
|
|
|
ptr++;
|
|
|
|
}
|
|
|
|
if (ptr != buf)
|
|
|
|
{
|
|
|
|
strcpy(buf, ptr);
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* Strip comments.
|
|
|
|
*/
|
|
|
|
ptr = strchr(buf, '#');
|
|
|
|
if (ptr)
|
|
|
|
{
|
|
|
|
*ptr = '\0';
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* Strip trailing white space.
|
|
|
|
*/
|
|
|
|
ptr = buf;
|
|
|
|
while (*ptr)
|
|
|
|
{
|
|
|
|
ptr++;
|
|
|
|
}
|
|
|
|
while (ptr > buf && isspace(ptr[-1]))
|
|
|
|
{
|
|
|
|
ptr--;
|
|
|
|
}
|
|
|
|
*ptr = '\0';
|
|
|
|
/*
|
|
|
|
* Ignore blank lines.
|
|
|
|
*/
|
|
|
|
if (*buf == '\0')
|
|
|
|
{
|
|
|
|
continue;
|
1998-03-10 19:01:24 +00:00
|
|
|
}
|
|
|
|
|
1998-10-29 16:20:53 +00:00
|
|
|
prb = (plentry*)malloc(sizeof(plentry));
|
|
|
|
memset((char*)prb, '\0', sizeof(plentry));
|
|
|
|
prb->addr.s_addr = inet_addr(buf);
|
|
|
|
if (prb->addr.s_addr == -1)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "'%s' is not as valid address\n", buf);
|
|
|
|
free(prb);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Add this address at the end of the list.
|
|
|
|
*/
|
|
|
|
if (plist == 0)
|
|
|
|
{
|
|
|
|
plist = prb;
|
1998-03-10 19:01:24 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
plentry *tmp = plist;
|
|
|
|
|
|
|
|
while (tmp->next)
|
|
|
|
{
|
|
|
|
if (tmp->addr.s_addr == prb->addr.s_addr)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "'%s' repeat in '%s'\n",
|
|
|
|
buf, optarg);
|
|
|
|
free(prb);
|
|
|
|
break;
|
1998-03-10 19:01:24 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
tmp = tmp->next;
|
|
|
|
}
|
|
|
|
if (tmp->next == 0)
|
|
|
|
{
|
|
|
|
tmp->next = prb;
|
1998-03-10 19:01:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
fclose(fptr);
|
|
|
|
}
|
|
|
|
break;
|
2000-02-21 22:01:08 +00:00
|
|
|
|
|
|
|
case 'I':
|
|
|
|
pidfile = optarg;
|
|
|
|
break;
|
|
|
|
|
1998-10-29 16:20:53 +00:00
|
|
|
case 'd':
|
|
|
|
debug++;
|
|
|
|
break;
|
1998-02-26 17:55:42 +00:00
|
|
|
|
1998-10-29 16:20:53 +00:00
|
|
|
case 'f':
|
|
|
|
nofork++;
|
|
|
|
break;
|
1997-05-03 19:18:21 +00:00
|
|
|
|
1998-10-29 16:20:53 +00:00
|
|
|
case 'i':
|
|
|
|
interval = atoi(optarg);
|
|
|
|
if (interval < 60)
|
|
|
|
{
|
|
|
|
interval = 60;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'p':
|
|
|
|
noprobe++;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
printf("%s - GNU Distributed Objects name server\n", argv[0]);
|
|
|
|
printf("-H for help\n");
|
|
|
|
exit(0);
|
1997-05-03 19:18:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1998-10-29 16:20:53 +00:00
|
|
|
if (nofork == 0)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Now fork off child process to run in background.
|
|
|
|
*/
|
|
|
|
switch (fork())
|
|
|
|
{
|
|
|
|
case -1:
|
|
|
|
fprintf(stderr, "gdomap - fork failed - bye.\n");
|
|
|
|
exit(1);
|
1997-05-03 19:18:21 +00:00
|
|
|
|
1998-10-29 16:20:53 +00:00
|
|
|
case 0:
|
|
|
|
/*
|
|
|
|
* Try to run in background.
|
|
|
|
*/
|
1997-05-03 19:18:21 +00:00
|
|
|
#ifdef NeXT
|
1998-10-29 16:20:53 +00:00
|
|
|
setpgrp(0, getpid());
|
1997-05-03 19:18:21 +00:00
|
|
|
#else
|
1998-10-29 16:20:53 +00:00
|
|
|
setsid();
|
1997-05-03 19:18:21 +00:00
|
|
|
#endif
|
1998-10-29 16:20:53 +00:00
|
|
|
break;
|
1997-05-03 19:18:21 +00:00
|
|
|
|
1998-10-29 16:20:53 +00:00
|
|
|
default:
|
|
|
|
if (debug)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "gdomap - initialisation complete.\n");
|
|
|
|
}
|
|
|
|
exit(0);
|
1997-05-03 19:18:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2000-02-21 22:01:08 +00:00
|
|
|
if (pidfile) {
|
|
|
|
{
|
|
|
|
FILE *fptr = fopen(pidfile, "a");
|
|
|
|
|
|
|
|
if (fptr == 0)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "Unable to open pid file - '%s'\n", pidfile);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
fprintf(fptr, "%d\n", (int) getpid());
|
|
|
|
fclose(fptr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1998-10-29 16:20:53 +00:00
|
|
|
/*
|
|
|
|
* Ensure we don't have any open file descriptors which may refer
|
|
|
|
* to sockets bound to ports we may try to use.
|
|
|
|
*
|
1999-10-04 09:48:57 +00:00
|
|
|
* Use '/dev/null' for stdin and stdout. Assume stderr is ok.
|
1998-10-29 16:20:53 +00:00
|
|
|
*/
|
|
|
|
for (c = 0; c < FD_SETSIZE; c++)
|
|
|
|
{
|
1999-10-04 09:48:57 +00:00
|
|
|
if (c != 2)
|
|
|
|
(void)close(c);
|
1997-09-01 21:59:51 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
(void)open("/dev/null", O_RDONLY); /* Stdin. */
|
|
|
|
(void)open("/dev/null", O_WRONLY); /* Stdout. */
|
1997-09-01 21:59:51 +00:00
|
|
|
|
1998-10-29 16:20:53 +00:00
|
|
|
init_my_port(); /* Determine port to listen on. */
|
|
|
|
if (interfaces == 0)
|
|
|
|
{
|
|
|
|
init_iface(); /* Build up list of network interfaces. */
|
1998-05-29 15:25:41 +00:00
|
|
|
}
|
1998-12-05 06:50:15 +00:00
|
|
|
|
|
|
|
if (!is_local_host(loopback))
|
|
|
|
{
|
|
|
|
fprintf(stderr, "I can't find the loopback interface on this machine.\n");
|
|
|
|
fprintf(stderr,
|
|
|
|
"Perhaps you should correct your machine configuration or use the -a flag.\n");
|
|
|
|
if (interfaces < MAX_IFACE)
|
|
|
|
{
|
|
|
|
addr[interfaces].s_addr = loopback.s_addr;
|
|
|
|
mask[interfaces] = class_c_mask;
|
|
|
|
interfaces++;
|
|
|
|
fprintf(stderr, "I am assuming loopback interface on 127.0.0.1\n");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
fprintf(stderr,
|
|
|
|
"You have too many network interfaces to add the loopback interface on\n"
|
|
|
|
"127.0.0.1 - you need to change the 'MAX_IFACE' constant in gdomap.c and\n"
|
|
|
|
"rebuild it.\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
init_ports(); /* Create ports to handle requests. */
|
|
|
|
init_probe(); /* Probe other name servers on net. */
|
1997-05-03 19:18:21 +00:00
|
|
|
|
1998-10-29 16:20:53 +00:00
|
|
|
if (debug)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "gdomap - entering main loop.\n");
|
1997-09-01 21:59:51 +00:00
|
|
|
}
|
1998-10-29 16:20:53 +00:00
|
|
|
handle_io();
|
1998-12-05 06:50:15 +00:00
|
|
|
return 0;
|
1997-05-03 19:18:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
1997-09-01 21:59:51 +00:00
|
|
|
* Name - queue_probe()
|
1997-05-03 19:18:21 +00:00
|
|
|
* Purpose - Send a probe request to a specified host so we
|
|
|
|
* can see if a name server is running on it.
|
|
|
|
* We don't bother to check to see if it worked.
|
|
|
|
*/
|
|
|
|
static void
|
1998-02-26 17:55:42 +00:00
|
|
|
queue_probe(struct in_addr* to, struct in_addr* from, int l, struct in_addr* e, int f)
|
1997-05-03 19:18:21 +00:00
|
|
|
{
|
1998-10-29 16:20:53 +00:00
|
|
|
struct sockaddr_in sin;
|
|
|
|
gdo_req msg;
|
|
|
|
|
|
|
|
if (debug > 2)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "Probing for server on '%s'", inet_ntoa(*to));
|
|
|
|
fprintf(stderr, " from '%s'\n", inet_ntoa(*from));
|
|
|
|
}
|
|
|
|
mzero(&sin, sizeof(sin));
|
|
|
|
sin.sin_family = AF_INET;
|
|
|
|
mcopy(&sin.sin_addr, to, sizeof(*to));
|
|
|
|
sin.sin_port = my_port;
|
|
|
|
|
|
|
|
mzero((char*)&msg, GDO_REQ_SIZE);
|
|
|
|
if (f)
|
|
|
|
{
|
|
|
|
msg.rtype = GDO_PREPLY;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
msg.rtype = GDO_PROBE;
|
|
|
|
}
|
|
|
|
msg.nsize = 2*IASIZE;
|
|
|
|
msg.ptype = 0;
|
|
|
|
msg.dummy = 0;
|
|
|
|
msg.port = 0;
|
|
|
|
mcopy(msg.name, from, IASIZE);
|
|
|
|
mcopy(&msg.name[IASIZE], to, IASIZE);
|
|
|
|
if (l > 0)
|
|
|
|
{
|
|
|
|
memcpy(&msg.name[msg.nsize], e, l*IASIZE);
|
|
|
|
msg.nsize += l*IASIZE;
|
1998-02-26 17:55:42 +00:00
|
|
|
}
|
1997-09-01 21:59:51 +00:00
|
|
|
|
1998-10-29 16:20:53 +00:00
|
|
|
queue_msg(&sin, (uptr)&msg, GDO_REQ_SIZE);
|
1997-05-03 19:18:21 +00:00
|
|
|
}
|
|
|
|
|