/* locbrok - location broker * vix 13sep91 [written] */ #ifndef LINT static char RCSid[] = "$Id: locbrok.c,v 1.9 2001/03/24 21:14:26 vixie Exp $"; #endif /* Copyright (c) 1996 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS * SOFTWARE. */ #ifdef DEBUG int Debug = 0; #endif #ifdef WANT_TCPIP #include #include #include #include #include #include #include #include #include "rtty.h" #include "misc.h" #include "locbrok.h" #define USAGE_STR "[-s service] [-x debuglev]" /* misc.c */ #ifndef isnumber extern int isnumber(char *); #endif typedef struct reg_db { char *name; u_short port; u_short client; struct reg_db *next; } reg_db; static reg_db *find_byname(char *name), *find_byport(u_int port); static int add(char *name, u_int port, u_int client); static void server(void), client_input(int fd), rm_byclient(u_int client), print(void); static char *ProgName = "amnesia", *Service = LB_SERVNAME; static int Port, MaxFD; static fd_set Clients; static reg_db *RegDB = NULL; main(int argc, char *argv[]) { struct servent *serv; char ch; ProgName = argv[0]; while ((ch = getopt(argc, argv, "s:x:")) != EOF) { switch (ch) { case 's': Service = optarg; break; case 'x': Debug = atoi(optarg); break; default: USAGE((stderr, "%s: getopt=%c ?\n", ProgName, ch)); } } if (isnumber(Service) && (Port = atoi(Service))) { /* numeric service; we're ok */ ; } else if (NULL != (serv = getservbyname(Service, "tcp"))) { /* found the service name; we're ok */ Port = ntohs(serv->s_port); } else { /* nothing worked; use default */ Port = LB_SERVPORT; fprintf(stderr, "%s: service `%s' not found, using port %d\n", ProgName, Service, Port); } server(); } static void server(void) { int serv, on = 1; struct sockaddr_in name; serv = socket(PF_INET, SOCK_STREAM, 0); ASSERT(serv>=0, "socket") setsockopt(serv, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof on); name.sin_family = AF_INET; #ifndef NO_SOCKADDR_LEN name.sin_len = sizeof(struct sockaddr_in); #endif name.sin_addr.s_addr = INADDR_ANY; name.sin_port = htons(Port); ASSERT(bind(serv, (struct sockaddr *)&name, sizeof name)>=0, "bind") FD_ZERO(&Clients); MaxFD = serv; listen(serv, 5); for (;;) { fd_set readfds; int nset, fd; readfds = Clients; FD_SET(serv, &readfds); nset = select(MaxFD+1, &readfds, NULL, NULL, NULL); if (nset < 0 && errno == EINTR) continue; ASSERT(nset>=0, "assert") for (fd = 0; fd <= MaxFD; fd++) { if (!FD_ISSET(fd, &readfds)) continue; if (fd == serv) { int namesize = sizeof name; int addr, local, cl; ASSERT((cl=accept(serv, (struct sockaddr *)&name, &namesize))>=0, "accept") addr = ntohl(name.sin_addr.s_addr); local = (addr == INADDR_ANY) || ((IN_CLASSA(addr) && (addr & IN_CLASSA_NET) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET); fprintf(stderr, "accept from %08x (%slocal)\n", addr, local?"":"not "); FD_SET(cl, &Clients); if (cl > MaxFD) MaxFD = cl; continue; } if (FD_ISSET(fd, &Clients)) { client_input(fd); } } } } static void client_input(int fd) { locbrok lb; reg_db *db; int keepalive = 0; if (0 >= read(fd, &lb, sizeof lb)) { fputs("locbrok.client_input: ", stderr); perror("read"); goto death; } lb.lb_port = ntohs(lb.lb_port); lb.lb_nlen = ntohs(lb.lb_nlen); if (lb.lb_nlen >= LB_MAXNAMELEN) { fprintf(stderr, "client_input: fd%d sent oversize req\n", fd); goto death; } lb.lb_name[lb.lb_nlen] = '\0'; fprintf(stderr, "client_input(fd %d, port %d, %d:`%s')\n", fd, lb.lb_port, lb.lb_nlen, lb.lb_name); if (lb.lb_port && !lb.lb_nlen) { if (NULL != (db = find_byport(lb.lb_port))) { lb.lb_nlen = min(strlen(db->name), LB_MAXNAMELEN); strncpy(lb.lb_name, db->name, lb.lb_nlen); } } else if (!lb.lb_port && lb.lb_nlen) { if (NULL != (db = find_byname(lb.lb_name))) { lb.lb_port = db->port; } } else if (lb.lb_port && lb.lb_nlen) { if (add(lb.lb_name, lb.lb_port, fd) == -1) { lb.lb_nlen = 0; } else { keepalive++; print(); } } else { fprintf(stderr, "bogus client_input (port,nlen both 0)\n"); goto death; } lb.lb_port = htons(lb.lb_port); lb.lb_nlen = htons(lb.lb_nlen); write(fd, &lb, sizeof lb); if (keepalive) return; death: close(fd); FD_CLR(fd, &Clients); rm_byclient(fd); print(); } static reg_db * find_byname(const char *name) { reg_db *db; for (db = RegDB; db; db = db->next) if (!strcmp(name, db->name)) return (db); return (NULL); } static reg_db * find_byport(u_int port) { reg_db *db; for (db = RegDB; db; db = db->next) if (port == db->port) return (db); return (NULL); } static int add(const char *name, u_int port, u_int client) { reg_db *db; if (find_byname(name) || find_byport(port)) return (-1); db = (reg_db *) safe_malloc(sizeof(reg_db)); db->name = safe_malloc(strlen(name)+1); strcpy(db->name, name); db->port = port; db->client = client; db->next = RegDB; RegDB = db; return (0); } static void rm_byclient(u_int client) { reg_db *cur = RegDB, *prev = NULL; while (cur) { if (cur->client == client) { reg_db *tmp = cur; if (prev) prev->next = cur->next; else RegDB = cur->next; cur = cur->next; free(tmp->name); free(tmp); } else { prev = cur; cur = cur->next; } } } static void print(void) { reg_db *db; fprintf(stderr, "db:\n"); for (db = RegDB; db; db = db->next) fprintf(stderr, "(%s %d %d)\n", db->name, db->port, db->client); fprintf(stderr, "---\n"); } #else /*WANT_TCPIP*/ #include int main(int argc, char *argv[]) { fprintf(stderr, "There is no location broker for this system.\n"); exit(1); } #endif /*WANT_TCPIP*/