linux-um archives
 help / color / mirror / Atom feed
From: Michael Richardson <Michael.Richardson@seawaynetworks.com>
To: user-mode-linux-devel@lists.sourceforge.net
Subject: [uml-devel] switch->netjig patch 4
Date: Thu, 03 Jun 2004 17:20:54 -0400	[thread overview]
Message-ID: <27783.1086297654@camelot-054> (raw)


Jeff, this patch (also http://www.sandelman.ca/tmp/jig4.patch ) adds
contextualization to the switch functions.  I hope that this patch is
small enough to chew.

for hash.[ch], this is relatively simple, as it just adds struct nethub
* to all functions, and gets rid of the global "h[]" array.

for nethub.c's cleanup_nh(), it cleans up some additional items that
may get created, such as per-switch directories.

add_fd() gets context argument, and changes its allocation technique to
grow the array, doubling in size each time.

A new function, init_nethub() gathers all initialization stuff that was
done by uml_switch's main() into one place.

In port.c, the linked list is replaced with one from queue.h, which has
nice macros to cope.

nethub.h grows the new nethub and netjig_state structures.

for uml_switch, we don't need multiple netjig_state's, but we will
later.

in port.c, some printf()'s are changed to fprintf(stderr,). Also some of
the code is just unwrapped to be more readable. 
new_port becomes handle_new_port(), and gets made more readable.
A new function handle_port() takes over logic from uml_switch.

This is probably the biggest patch that there is.


diff -x CVS -x '*~' -u -N -r uml_tools.jig3/uml_router/hash.c uml_tools.jig4/uml_router/hash.c
--- uml_tools.jig3/uml_router/hash.c	Thu Jun  3 15:24:04 2004
+++ uml_tools.jig4/uml_router/hash.c	Thu Jun  3 17:09:33 2004
@@ -12,12 +12,11 @@
 #include <sys/types.h>
 #include <sys/time.h>
 #include <sys/signal.h>
+
+#include "nethub.h"
 #include "switch.h"
 #include "hash.h"
 
-#define HASH_SIZE 128
-#define HASH_MOD 11
-
 struct hash_entry {
   struct hash_entry *next;
   struct hash_entry *prev;
@@ -26,37 +25,38 @@
   unsigned char dst[ETH_ALEN];
 };
 
-static struct hash_entry *h[HASH_SIZE];
-
 static int calc_hash(char *src)
 {
   return ((*(u_int32_t *) &src[0] % HASH_MOD) ^ src[4] ^ src[5] ) % HASH_SIZE ;
 }
 
-static struct hash_entry *find_entry(char *dst)
+static struct hash_entry *find_entry(struct nethub *nh,
+				     char *dst)
 {
   struct hash_entry *e;
   int k = calc_hash(dst);
 
-  for(e = h[k]; e; e = e->next){
+  for(e = nh->h[k]; e; e = e->next){
     if(!memcmp(&e->dst, dst, ETH_ALEN)) return(e);
   }
   return(NULL);  
 }
 
-void *find_in_hash(char *dst)
+void *find_in_hash(struct nethub *nh,
+		   char *dst)
 {
-  struct hash_entry *e = find_entry(dst);
+  struct hash_entry *e = find_entry(nh, dst);
   if(e == NULL) return(NULL);
   return(e->port);
 }
 
-void insert_into_hash(char *src, void *port)
+void insert_into_hash(struct nethub *nh,
+		      char *src, void *port)
 {
   struct hash_entry *new;
   int k = calc_hash(src);
 
-  new = find_in_hash(src);
+  new = find_in_hash(nh, src);
   if(new != NULL) return;
 
   new = malloc(sizeof(*new));
@@ -66,50 +66,57 @@
   }
 
   memcpy(&new->dst, src, ETH_ALEN );
-  if(h[k] != NULL) h[k]->prev = new;
-  new->next = h[k];
+  if(nh->h[k] != NULL) nh->h[k]->prev = new;
+  new->next = nh->h[k];
   new->prev = NULL;
   new->port = port;
   new->last_seen = 0;
-  h[k] = new;
+  nh->h[k] = new;
 }
 
-void update_entry_time(char *src)
+void update_entry_time(struct nethub *nh,
+		       char *src)
 {
   struct hash_entry *e;
 
-  e = find_entry(src);
+  e = find_entry(nh, src);
   if(e == NULL) return;
   e->last_seen = time(NULL);
 }
 
-static void delete_hash_entry(struct hash_entry *old)
+static void delete_hash_entry(struct nethub *nh,
+			      struct hash_entry *old)
 {
   int k = calc_hash(old->dst);
 
   if(old->prev != NULL) old->prev->next = old->next;
   if(old->next != NULL) old->next->prev = old->prev;
-  if(h[k] == old) h[k] = old->next;
+  if(nh->h[k] == old) nh->h[k] = old->next;
   free(old);
 }
 
-void delete_hash(char *dst)
+void delete_hash(struct nethub *nh,
+		 char *dst)
 {
-  struct hash_entry *old = find_entry(dst);
+  struct hash_entry *old = find_entry(nh, dst);
 
   if(old == NULL) return;
-  delete_hash_entry(old);
+  delete_hash_entry(nh, old);
 }
 
-static void for_all_hash(void (*f)(struct hash_entry *, void *), void *arg)
+static void for_all_hash(struct nethub *nh,
+			 void (*f)(struct nethub *nh,
+				   struct hash_entry *,
+				   void *),
+			 void *arg)
 {
   int i;
   struct hash_entry *e, *next;
 
   for(i = 0; i < HASH_SIZE; i++){
-    for(e = h[i]; e; e = next){
+    for(e = nh->h[i]; e; e = next){
       next = e->next;
-      (*f)(e, arg);
+      (*f)(nh, e, arg);
     }
   }
 }
@@ -119,57 +126,43 @@
   char *(*port_id)(void *);
 };
 
-static void print_hash_entry(struct hash_entry *e, void *arg)
+static void print_hash_entry(struct nethub *nh,
+			     struct hash_entry *e, void *arg)
 {
   struct printer *p = arg;
 
-  printf("Hash: %d Addr: %02x:%02x:%02x:%02x:%02x:%02x to port: %s  " 
-	 "age %ld secs\n", calc_hash(e->dst),
-	 e->dst[0], e->dst[1], e->dst[2], e->dst[3], e->dst[4], e->dst[5],
-	 (*p->port_id)(e->port), (int) p->now - e->last_seen);
+  fprintf(stderr, "Hash: %d Addr: %02x:%02x:%02x:%02x:%02x:%02x to port: %s  " 
+	  "age %ld secs\n", calc_hash(e->dst),
+	  e->dst[0], e->dst[1], e->dst[2], e->dst[3], e->dst[4], e->dst[5],
+	  (*p->port_id)(e->port), (int) p->now - e->last_seen);
 }
 
-void print_hash(char *(*port_id)(void *))
+void print_hash(struct nethub *nh,
+		char *(*port_id)(void *))
 {
   struct printer p = ((struct printer) { now : 		time(NULL),
 					 port_id :	port_id });
 
-  for_all_hash(print_hash_entry, &p);
+  for_all_hash(nh, print_hash_entry, &p);
 }
 
-#define GC_INTERVAL 2
-#define GC_EXPIRE 100
-
-static void gc(struct hash_entry *e, void *now)
+static void gc(struct nethub *nh,
+	       struct hash_entry *e,
+	       void *now)
 {
   time_t t = *(time_t *) now;
 
   if(e->last_seen + GC_EXPIRE < t)
-    delete_hash_entry(e);
+    delete_hash_entry(nh, e);
 }
 
-static void sig_alarm(int sig)
+void hash_periodic(struct nethub *nh)
 {
-  struct itimerval it;
   time_t t = time(NULL);
-  for_all_hash(&gc, &t);
-
-  it.it_value.tv_sec = GC_INTERVAL;
-  it.it_value.tv_usec = 0 ;
-  it.it_interval.tv_sec = 0;
-  it.it_interval.tv_usec = 0 ;
-  setitimer(ITIMER_REAL, &it, NULL);
+  for_all_hash(nh, &gc, &t);
 }
-
-void hash_init(void)
+  
+void hash_init(struct nethub *nh)
 {
-  struct sigaction sa;
-
-  sa.sa_handler = sig_alarm;
-  sa.sa_flags = SA_RESTART;
-  if(sigaction(SIGALRM, &sa, NULL) < 0){
-    perror("Setting handler for SIGALRM");
-    return;
-  }
-  kill(getpid(), SIGALRM);
+  /* nothing right now */
 }
diff -x CVS -x '*~' -u -N -r uml_tools.jig3/uml_router/hash.h uml_tools.jig4/uml_router/hash.h
--- uml_tools.jig3/uml_router/hash.h	Thu Jun  3 15:24:04 2004
+++ uml_tools.jig4/uml_router/hash.h	Thu Jun  3 17:09:33 2004
@@ -5,11 +5,18 @@
 #ifndef __HASH_H__
 #define __HASH_H__
 
-extern void *find_in_hash(char *dst);
-extern void insert_into_hash(char *src, void *port);
-extern void delete_hash(char *dst);
-extern void print_hash(char *(*port_id)(void *));
-extern void update_entry_time(char *src);
-extern void hash_init(void);
+struct nethub;
+
+extern void *find_in_hash(struct nethub *nh, char *dst);
+extern void insert_into_hash(struct nethub *nh, char *src, void *port);
+extern void delete_hash(struct nethub *nh, char *dst);
+extern void print_hash(struct nethub *nh,
+		       char *(*port_id)(void *));
+extern void update_entry_time(struct nethub *nh, char *src);
+extern void hash_init(struct nethub *nh);
+extern void hash_periodic(struct nethub *nh);
+
+#define GC_INTERVAL 2
+#define GC_EXPIRE 100
 
 #endif
Binary files uml_tools.jig3/uml_router/hash.o and uml_tools.jig4/uml_router/hash.o differ
diff -x CVS -x '*~' -u -N -r uml_tools.jig3/uml_router/nethub.c uml_tools.jig4/uml_router/nethub.c
--- uml_tools.jig3/uml_router/nethub.c	Thu Jun  3 15:24:04 2004
+++ uml_tools.jig4/uml_router/nethub.c	Thu Jun  3 17:09:34 2004
@@ -1,74 +1,154 @@
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/time.h>
 #include <stdio.h>
+#include <stddef.h>
 #include <stdlib.h>
-#include <unistd.h>
 #include <fcntl.h>
+#include <unistd.h>
 #include <errno.h>
+#include <signal.h>
+#include <assert.h>
+#include <setjmp.h>
 #include <sys/socket.h>
-#include <sys/time.h>
+#include <poll.h>
 #include <sys/un.h>
-#include <sys/queue.h>
 #include <netinet/in.h>
+#include <net/ethernet.h>
+#include <net/if_arp.h>
+#define _GNU_SOURCE 1
+#include <getopt.h>
 
-#include <poll.h>
+#include <sys/queue.h>
 
-#include "nethub.h"
-#include "switch.h"
-#include "hash.h"
 #include "port.h"
+#include "hash.h"
 
-struct pollfd *fds = NULL;
-
-int maxfds = 0;
-int nfds = 0;
+#include "nethub.h"
+#include "netjig.h"
 
-void cleanup(void)
+void cleanup_nh(struct nethub *nh)
 {
-  if(unlink(ctl_socket) < 0){
-    printf("Couldn't remove control socket '%s' : ", ctl_socket);
-    perror("");
+  if(nh->pid_file_name) {
+    if(unlink(nh->pid_file_name) < 0 && errno!=ENOENT) {
+      fprintf(stderr, "Could not remove pid file '%s' : %s\n",
+	      nh->ctl_socket_name, strerror(errno));
+    }
+    free(nh->pid_file_name);
+    nh->pid_file_name = NULL;
   }
-  if((data_socket != NULL) && (unlink(data_socket) < 0)){
-    printf("Couldn't remove data socket '%s' : ", data_socket);
-    perror("");
+
+  if(nh->ctl_socket_name) {
+    if(unlink(nh->ctl_socket_name) < 0){
+      fprintf(stderr, "Couldn't remove control socket '%s' : %s\n",
+	      nh->ctl_socket_name, strerror(errno));
+    }
+    free(nh->ctl_socket_name);
+    nh->ctl_socket_name=NULL;
   }
+  if(nh->ctl_listen_fd > 0) {
+    close(nh->ctl_listen_fd);
+    nh->ctl_listen_fd = -1;
+  }
+
+  if(nh->data_socket_name) {
+    if(nh->data_socket_name!=NULL && unlink(nh->data_socket_name) < 0){
+      fprintf(stderr, "Couldn't remove data socket '%s' : %s\n",
+	      nh->data_socket_name, strerror(errno));
+    }
+    free(nh->data_socket_name);
+    nh->data_socket_name=NULL;
+  }
+
+  if(nh->data_fd > 0) {
+    close(nh->data_fd);
+    nh->data_fd = -1;
+  }
+    
+  if(nh->socket_dir != NULL && rmdir(nh->socket_dir) < 0) {
+    fprintf(stderr, "Couldn't remove socket dir '%s' : %s\n",
+	    nh->socket_dir, strerror(errno));
+  }
+
+  /* XXX should free up hash entries and ports */
+  free(nh);
 }
 
-void add_fd(int fd)
+void add_fd(struct netjig_state *ns,
+	    int fd)
 {
   struct pollfd *p;
+  int i;
+
+  /*  fprintf(stderr, "Adding fd %d\n", fd); */
 
-  if(nfds == maxfds){
-    maxfds = maxfds ? 2 * maxfds : 4;
-    if((fds = realloc(fds, maxfds * sizeof(struct pollfd))) == NULL){
+  if(ns->nfds == ns->max_fds){
+    ns->max_fds = ns->max_fds ? 2 * ns->max_fds : 4;
+    if((ns->fds = realloc(ns->fds, ns->max_fds * sizeof(struct pollfd))) == NULL){
       perror("realloc");
-      cleanup();
+      /* XXX need a better cleanup function ! */
       exit(1);
     }
   }
-  p = &fds[nfds++];
+  p = &ns->fds[ns->nfds++];
   p->fd = fd;
   p->events = POLLIN;
+  p->revents=0;
+
+  /*
+   * assuming that FD's are small integers is very Unix.
+   * If you port this to WinBLOWs, well, sorry, figure out someone else.
+   */
+  while(fd >= ns->fd_array_size) {
+    ns->fd_array_size = ns->fd_array_size ? 2*ns->fd_array_size : 4;
+    if((ns->fd_array = realloc(ns->fd_array,
+			       ns->fd_array_size * sizeof(int))) ==NULL) {
+      perror("realloc fd_array");
+      /* XXX need a better cleanup function ! */
+      exit(1);
+    }
+  }
+
+  /* we rebuild the fd->pollfd mapping here because we might have reallocated
+   * it above, and recalculating it is pretty easy.
+   */
+  for(i=0; i < ns->fd_array_size; i++) {
+    ns->fd_array[i]=-1;
+  }
+
+  for(i=0, p=ns->fds; i < ns->nfds; i++, p++) {
+    /* fprintf(stderr, "Mapping fd:%d to item %d\n", p->fd, i); */
+
+    ns->fd_array[p->fd]=i;
+  }
 }
 
-static void remove_fd(int fd)
+void remove_fd(struct netjig_state *ns,
+		      int fd)
 {
   int i;
 
-  for(i = 0; i < nfds; i++){
-    if(fds[i].fd == fd) break;
+  for(i = 0; i < ns->nfds; i++){
+    if(ns->fds[i].fd == fd) break;
   }
-  if(i == nfds){
+  if(i == ns->nfds){
     fprintf(stderr, "remove_fd : Couldn't find descriptor %d\n", fd);
   }
-  memmove(&fds[i], &fds[i + 1], (maxfds - i - 1) * sizeof(struct pollfd));
-  nfds--;
+  memmove(&ns->fds[i], &ns->fds[i + 1], (ns->max_fds - i - 1) * sizeof(struct pollfd));
+  ns->nfds--;
+
+  if(fd < ns->fd_array_size) {
+    ns->fd_array[fd]=-1;
+  }
 }
 
-void close_descriptor(int fd)
+void close_descriptor(struct netjig_state *ns,
+		      struct nethub       *nh,
+		      int fd)
 {
-  remove_fd(fd);
+  remove_fd(ns, fd);
   close(fd);
-  close_port(fd);
+  close_port(ns, nh, fd);
 }
 
 int still_used(struct sockaddr_un *sun)
@@ -79,6 +159,7 @@
     perror("socket");
     exit(1);
   }
+
   if(connect(test_fd, (struct sockaddr *) sun, sizeof(*sun)) < 0){
     if(errno == ECONNREFUSED){
       if(unlink(sun->sun_path) < 0){
@@ -94,12 +175,15 @@
   return(ret);
 }
 
+
 int bind_socket(int fd, const char *name, struct sockaddr_un *sock_out)
 {
   struct sockaddr_un sun;
 
+  memset(&sun, 0, sizeof(sun));
+
   sun.sun_family = AF_UNIX;
-  strncpy(sun.sun_path, name, sizeof(sun.sun_path));
+  strcpy(sun.sun_path, name);
   
   if(bind(fd, (struct sockaddr *) &sun, sizeof(sun)) < 0){
     if((errno == EADDRINUSE) && still_used(&sun)) return(EADDRINUSE);
@@ -112,53 +196,55 @@
   return(0);
 }
 
-void bind_sockets_v0(int ctl_fd, const char *ctl_name, 
-		     int data_fd, const char *data_name)
+
+void bind_sockets_v0(struct nethub *nh)
 {
   int ctl_err, ctl_present = 0, ctl_used = 0;
   int data_err, data_present = 0, data_used = 0;
   int try_remove_ctl, try_remove_data;
 
-  ctl_err = bind_socket(ctl_fd, ctl_name, NULL);
+  ctl_err = bind_socket(nh->ctl_listen_fd, nh->ctl_socket_name, NULL);
   if(ctl_err != 0) ctl_present = 1;
   if(ctl_err == EADDRINUSE) ctl_used = 1;
 
-  data_err = bind_socket(data_fd, data_name, &data_sun);
+  data_err = bind_socket(nh->data_fd, nh->data_socket_name, &nh->data_sun);
   if(data_err != 0) data_present = 1;
   if(data_err == EADDRINUSE) data_used = 1;
 
-  if(!ctl_err && !data_err){
-    return;
-  }
+  if(!ctl_err && !data_err) return;
+
+  unlink(nh->ctl_socket_name);
+  unlink(nh->data_socket_name);
 
   try_remove_ctl = ctl_present;
   try_remove_data = data_present;
   if(ctl_present && ctl_used){
     fprintf(stderr, "The control socket '%s' has another server "
-	    "attached to it\n", ctl_name);
+	    "attached to it\n", nh->ctl_socket_name);
     try_remove_ctl = 0;
   }
   else if(ctl_present && !ctl_used)
     fprintf(stderr, "The control socket '%s' exists, isn't used, but couldn't "
-	    "be removed\n", ctl_name);
+	    "be removed\n", nh->ctl_socket_name);
   if(data_present && data_used){
     fprintf(stderr, "The data socket '%s' has another server "
-	    "attached to it\n", data_name);
+	    "attached to it\n", nh->data_socket_name);
     try_remove_data = 0;
   }
   else if(data_present && !data_used)
     fprintf(stderr, "The data socket '%s' exists, isn't used, but couldn't "
-	    "be removed\n", data_name);
+	    "be removed\n", nh->data_socket_name);
   if(try_remove_ctl || try_remove_data){
     fprintf(stderr, "You can either\n");
     if(try_remove_ctl && !try_remove_data) 
-      fprintf(stderr, "\tremove '%s'\n", ctl_socket);
+      fprintf(stderr, "\tremove '%s'\n", nh->ctl_socket_name);
     else if(!try_remove_ctl && try_remove_data) 
-      fprintf(stderr, "\tremove '%s'\n", data_socket);
-    else fprintf(stderr, "\tremove '%s' and '%s'\n", ctl_socket, data_socket);
+      fprintf(stderr, "\tremove '%s'\n", nh->data_socket_name);
+    else fprintf(stderr, "\tremove '%s' and '%s'\n",
+		 nh->ctl_socket_name, nh->data_socket_name);
     fprintf(stderr, "\tor rerun with different, unused filenames for "
 	    "sockets:\n");
-    fprintf(stderr, "\t\t%s -unix <control> <data>\n", prog);
+    fprintf(stderr, "\t\t%s -unix <control> <data>\n", progname);
     fprintf(stderr, "\t\tand run the UMLs with "
 	    "'eth0=daemon,,unix,<control>,<data>\n");
     exit(1);
@@ -166,7 +252,7 @@
   else {
     fprintf(stderr, "You should rerun with different, unused filenames for "
 	    "sockets:\n");
-    fprintf(stderr, "\t%s -unix <control> <data>\n", prog);
+    fprintf(stderr, "\t%s -unix <control> <data>\n", progname);
     fprintf(stderr, "\tand run the UMLs with "
 	    "'eth0=daemon,,unix,<control>,<data>'\n");
     exit(1);
@@ -194,28 +280,221 @@
   }
 }
 
-void bind_sockets(int ctl_fd, const char *ctl_name, int data_fd)
+void bind_sockets(struct nethub *nh)
 {
   int err, used;
 
-  err = bind_socket(ctl_fd, ctl_name, NULL);
+  err = bind_socket(nh->ctl_listen_fd, nh->ctl_socket_name, NULL);
   if(err == 0){
-    bind_data_socket(data_fd, &data_sun);
+    bind_data_socket(nh->data_fd, &nh->data_sun);
     return;
   }
   else if(err == EADDRINUSE) used = 1;
   
   if(used){
     fprintf(stderr, "The control socket '%s' has another server "
-	    "attached to it\n", ctl_name);
+	    "attached to it\n", nh->ctl_socket_name);
     fprintf(stderr, "You can either\n");
-    fprintf(stderr, "\tremove '%s'\n", ctl_name);
+    fprintf(stderr, "\tremove '%s'\n", nh->ctl_socket_name);
     fprintf(stderr, "\tor rerun with a different, unused filename for a "
 	    "socket\n");
   }
   else
     fprintf(stderr, "The control socket '%s' exists, isn't used, but couldn't "
-	    "be removed\n", ctl_name);
+	    "be removed\n", nh->ctl_socket_name);
   exit(1);
 }
 
+
+struct nethub *init_nethub(struct netjig_state *ns,
+			   char *switchname,
+			   char *data_socket,
+			   char *ctl_socket,
+			   int compat_v0)
+{
+	int one;
+	char *env;
+	char *newdir, *p;
+	struct nethub *nh;
+	int used_base_dir;
+
+	one = 1;
+	used_base_dir = 0;
+
+	nh=xmalloc(sizeof(*nh));
+	memset(nh, 0, sizeof(*nh));
+
+	TAILQ_INIT(&nh->nh_ports);
+
+	nh->nh_name = strdup(switchname);
+
+	/* setup ARP stuff */
+	nh->nh_allarp = 0;
+	
+	nh->nh_defaultgate.s_addr = 0;
+	
+	nh->nh_defaultether[0]=0x10;
+	nh->nh_defaultether[1]=0x00;
+	nh->nh_defaultether[2]=0x00;
+	nh->nh_defaultether[3]=switchname[0];
+	nh->nh_defaultether[4]=switchname[1];
+	nh->nh_defaultether[5]=switchname[2];
+
+	if(ctl_socket == NULL) {
+	  /* cons up the names, and stick them in the environment */
+	  env = xmalloc(sizeof("UML_")+2*strlen(switchname)+sizeof("CTL=")+
+			strlen(ns->socketbasedir)+sizeof("/ctl")+4);
+	  
+	  sprintf(env, "UML_%s_CTL=%s/%s/ctl", switchname,
+		  ns->socketbasedir, switchname);
+	  putenv(env);
+	  nh->ctl_socket_name_env = env;
+	  nh->ctl_socket_name = strdup(strchr(env, '=')+1);
+	  used_base_dir = 1;
+	} else {
+	  nh->ctl_socket_name_env = NULL;
+	  nh->ctl_socket_name = strdup(ctl_socket);
+	}
+
+	if(data_socket == NULL) {
+	  env = xmalloc(sizeof("UML_")+2*strlen(switchname)+sizeof("DATA=")+
+			strlen(ns->socketbasedir)+sizeof("/data")+4);
+	  
+	  sprintf(env, "UML_%s_DATA=%s/%s/data", switchname,
+		  ns->socketbasedir, switchname);
+	  putenv(env);
+	  nh->data_socket_name_env = env;
+	  nh->data_socket_name = strdup(strchr(env, '=')+1);
+	  used_base_dir = 1;
+	} else {
+	  nh->data_socket_name_env = NULL;
+	  nh->data_socket_name = strdup(data_socket);
+	}
+	  
+
+	/* now make the directory, if we need it */
+ 	if(used_base_dir ) {
+		FILE *pidfile;
+
+		if(mkdir(ns->socketbasedir,0700) < 0 &&
+		   errno != EEXIST) {
+			perror(ns->socketbasedir);
+			exit(1);
+		}
+
+		newdir=strdup(nh->ctl_socket_name);
+		if((p=strrchr(newdir, '/'))!=NULL) {
+			*p='\0';
+			if(mkdir(newdir, 0700) < 0 &&
+			   errno != EEXIST) {
+				perror(newdir);
+				exit(1);
+			}
+		}
+		nh->socket_dir=newdir;
+
+		nh->pid_file_name=xmalloc(strlen(nh->socket_dir)+sizeof("pid")+2);
+		sprintf(nh->pid_file_name, "%s/pid", nh->socket_dir);
+		if((pidfile=fopen(nh->pid_file_name, "w"))==NULL) {
+			perror(nh->pid_file_name);
+		} else {
+			fprintf(pidfile, "%d", getpid());
+			fclose(pidfile);
+		}
+	} 
+
+	if((nh->ctl_listen_fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0){
+		perror("socket");
+		exit(1);
+	}
+	if(setsockopt(nh->ctl_listen_fd,
+		      SOL_SOCKET, SO_REUSEADDR, (char *) &one, 
+		      sizeof(one)) < 0){
+		perror("setsockopt");
+		exit(1);
+	}
+
+	if(fcntl(nh->ctl_listen_fd, F_SETFL, O_NONBLOCK) < 0){
+		perror("Setting O_NONBLOCK on connection fd");
+		exit(1);
+	}
+	
+	if((nh->data_fd = socket(PF_UNIX, SOCK_DGRAM, 0)) < 0){
+		perror("socket");
+		exit(1);
+	}
+
+#if 0
+	if(fcntl(nh->data_fd, F_SETFL, O_NONBLOCK) < 0){
+		perror("Setting O_NONBLOCK on data fd");
+		exit(1);
+	}
+#endif
+
+	if(compat_v0) bind_sockets_v0(nh);
+	else bind_sockets(nh);
+
+	if(listen(nh->ctl_listen_fd, 15) < 0){
+		perror("listen");
+		exit(1);
+	}
+	 
+
+	add_fd(ns, nh->ctl_listen_fd);
+	add_fd(ns, nh->data_fd);
+
+	hash_init(nh);
+
+	TAILQ_INSERT_TAIL(&ns->switches, nh, nh_link);
+	return nh;
+}
+
+
+struct nethub *find_nethubbyname(struct netjig_state *ns,
+				 char *name)
+{
+  struct nethub *nh;
+
+  for(nh=ns->switches.tqh_first;
+      nh;
+      nh=nh->nh_link.tqe_next) {
+
+    if(strcasecmp(nh->nh_name, name)==0) {
+      break;
+    }
+  }
+  return nh;
+}
+
+void create_socket_dir(struct netjig_state *ns)
+{
+	char tmpbuf[1024];
+
+	if(ns->socketbasedir == NULL) {
+		char *tmpdir_env;
+		int   fd_file;
+
+		tmpdir_env = getenv("TMPDIR");
+		if(tmpdir_env == NULL) {
+			tmpdir_env = P_tmpdir;
+		}
+
+		snprintf(tmpbuf, sizeof(tmpbuf)-4, "%s/umlXXXXXX", tmpdir_env);
+		fd_file = mkstemp(tmpbuf);
+		
+		if(fd_file == -1) {
+			fprintf(stderr, "failed to make tmpdir (last=%s)\n", tmpbuf);
+			exit(1);
+		}
+
+		strcat(tmpbuf,".d");
+
+		if(mkdir(tmpbuf, 0700) != 0) {
+			fprintf(stderr, "failed to mkdir(%s): %s\n",
+				tmpbuf, strerror(errno));
+			exit(2);
+		}
+		ns->socketbasedir=strdup(tmpbuf);
+		close(fd_file);
+	}
+}
diff -x CVS -x '*~' -u -N -r uml_tools.jig3/uml_router/nethub.h uml_tools.jig4/uml_router/nethub.h
--- uml_tools.jig3/uml_router/nethub.h	Thu Jun  3 15:24:04 2004
+++ uml_tools.jig4/uml_router/nethub.h	Thu Jun  3 17:09:34 2004
@@ -83,6 +83,78 @@
 
 struct port;
 
+struct nethub {
+	TAILQ_ENTRY(nethub)     nh_link;
+	TAILQ_HEAD(,port)  nh_ports;
+	char              *nh_name;
+	unsigned char      nh_defaultether[ETH_ALEN];
+	struct in_addr     nh_defaultgate;
+	int                nh_allarp;
+	char              *nh_outputFile;
+	int                nh_rate;
+	char              *nh_inputFile;
+	int                nh_hub;
+	int                nh_compat_v0;
+	char              *socket_dir;
+	char              *pid_file_name;
+	char              *ctl_socket_name_env;   /* do not free this one */
+	char              *ctl_socket_name;
+	int                ctl_listen_fd;
+	char              *data_socket_name_env;  /* do not free this one */
+	char              *data_socket_name;
+	struct sockaddr_un data_sun;
+	int                data_fd;
+	int                tap_fd;
+	struct hash_entry *h[HASH_SIZE];
+
+};
+
+#define CMDBUF_LEN 256
+struct netjig_state {
+	int   done;
+	int   debug;
+	int   verbose;
+        int   waitplay;
+	char *socketbasedir;
+	char *startup;
+	char *playprivatefile;
+	char *recordprivatefile;
+	char *playpublicfile;
+	char *recordpublicfile;
+	int arpreply;
+	int cmdproto;
+	int forcetick;   /* if set to 1, then a packet will be sent out */
+	int packetrate;  /* how many miliseconds between packets */
+	FILE *cmdproto_out;
+	int exitonempty;
+	TAILQ_HEAD(,nethub) switches;
+
+	/* stuff to keep track of the sources of input */
+	struct pollfd *fds;        /* array of input sources */
+	int            nfds;       /* number of relevant entries */
+	int            max_fds;    /* current size of the array */
+
+	/* poll(2) doesn't provide a very useful interface to figure out what
+	 * fd belongs to what event, and searching through stuff sucks, we
+	 * we keep a mapping of fd# -> poll descriptor entry. We then walk through
+	 * the set of possible inputs, (in the appropriate priority order) and
+	 * use this array to map to an entry in fds[] to see if this input has
+	 * activity.
+	 */
+	int            *fd_array;
+	int             fd_array_size;  /* so we can grow it in add_fd() */
+
+
+	/* keep track of curtent input buffer, since we predict that eventuallyu
+	 * command sizes will grow such that they do not always fit into a single
+	 * read(2), or that multiple commands may get coalesced into a single buffer.
+	 */
+	char cmdbuf[CMDBUF_LEN];
+	int  cmdloc;
+	int  cmdskip;
+	int  cmdlaststat;         /* 0= success */
+};
+
 struct packet {
   struct {
     unsigned char dest[6];
@@ -92,24 +164,30 @@
   unsigned char data[1500];
 };
 
+/* in nethub.c */
+extern struct nethub *init_nethub(struct netjig_state *ns,
+				  char *switchname,
+				  char *data_socket, char *ctl_socket,
+				  int compat_v0);
+extern void bind_sockets(struct nethub *nh);
+extern void cleanup_nh(struct nethub *nh);
+extern struct nethub *find_nethubbyname(struct netjig_state *ns, char *name);
+extern void add_fd(struct netjig_state *ns, int fd);
+extern void remove_fd(struct netjig_state *ns, int fd);
+
+extern void close_descriptor(struct netjig_state *ns,
+			     struct nethub       *nh,
+			     int fd);
+
 #define xmalloc(X) xmalloc1((X), __FILE__, __LINE__)
 
-extern char *ctl_socket;
-extern char *data_socket;
-extern char *prog;
-extern struct pollfd *fds;
-extern int maxfds;
-extern int nfds;
-
-extern struct sockaddr_un data_sun;
-extern void cleanup(void);
-extern void bind_sockets(int ctl_fd, const char *ctl_name, int data_fd);
-void bind_sockets_v0(int ctl_fd, const char *ctl_name, 
-		     int data_fd, const char *data_name);
-void add_fd(int fd);
-void accept_connection(int fd);
-void close_descriptor(int fd);
+#ifdef NETDISSECT
+#include "netdissect.h"
 
+extern struct netdissect_options gndo;
+extern int tcpdump_print;
+
+#endif
 
 #define _NETHUB_H_
 
@@ -124,3 +202,4 @@
  * End:
  *
  */
+
Binary files uml_tools.jig3/uml_router/nethub.o and uml_tools.jig4/uml_router/nethub.o differ
diff -x CVS -x '*~' -u -N -r uml_tools.jig3/uml_router/netjig.h uml_tools.jig4/uml_router/netjig.h
--- uml_tools.jig3/uml_router/netjig.h	Wed Dec 31 19:00:00 1969
+++ uml_tools.jig4/uml_router/netjig.h	Thu Jun  3 17:09:34 2004
@@ -0,0 +1,29 @@
+extern char *progname;
+extern jmp_buf getMeOut;
+
+#define ETH_ALEN 6
+
+#define MAX(x,y) ((x) > (y) ? (x) : (y))
+
+/* prototypes */
+extern void sig_handler(int sig);
+extern void create_socket_dir(struct netjig_state *ns);
+extern void cmdprompt(struct netjig_state *ns);
+extern void forward_data(struct nethub *nh, struct packet *p, int    len);
+extern int cmdread(struct netjig_state *ns, char  *buf, int    len);
+extern void *xmalloc1(size_t size, char *file, int linenum);
+
+/* from cmdmode.c */
+
+extern void finish_waitplay(struct netjig_state *ns);
+extern int cmdread(struct netjig_state *ns, char  *buf, int    len);
+
+/*
+ * $Log: netjig.h,v $
+ *
+ * Local variables:
+ * c-file-style: "linux"
+ * c-basic-offset: 8
+ * End:
+ *
+ */
diff -x CVS -x '*~' -u -N -r uml_tools.jig3/uml_router/port.c uml_tools.jig4/uml_router/port.c
--- uml_tools.jig3/uml_router/port.c	Thu Jun  3 15:24:04 2004
+++ uml_tools.jig4/uml_router/port.c	Thu Jun  3 17:09:33 2004
@@ -4,104 +4,126 @@
 #include <fcntl.h>
 #include <errno.h>
 #include <sys/socket.h>
-#include <sys/time.h>
 #include <sys/un.h>
 #include <sys/queue.h>
+#include <net/if_arp.h>
 #include <netinet/in.h>
-
 #include <poll.h>
 
-#include "nethub.h"
-#include "switch.h"
 #include "hash.h"
 #include "port.h"
 
+#include "nethub.h"
+
 struct port {
-  struct port *next;
-  struct port *prev;
-  int control;
-  void *data;
-  int data_len;
-  unsigned char src[ETH_ALEN];
-  void (*sender)(int fd, void *packet, int len, void *data);
+	TAILQ_ENTRY(port) link;
+	int control;
+	void *data;
+	int data_len;
+	packet_sender sender;
+        unsigned char most_recent_ethernet[ETH_ALEN];
 };
 
-static struct port *head = NULL;
-
 #define IS_BROADCAST(addr) ((addr[0] & 1) == 1)
 
-static void free_port(struct port *port)
+static void free_port(struct netjig_state *ns,
+		      struct nethub *nh,
+		      struct port *port)
 {
-  if(port->prev) port->prev->next = port->next;
-  else head = port->next;
-  if(port->next) port->next->prev = port->prev;
+  TAILQ_REMOVE(&nh->nh_ports,port,link);
   free(port);
 }
 
-void close_port(int fd)
+void close_port(struct netjig_state *ns,
+		struct nethub *nh,
+		int fd)
 {
   struct port *port;
 
-  for(port = head; port != NULL; port = port->next){
+  for(port = nh->nh_ports.tqh_first;
+      port != NULL;
+      port = port->link.tqe_next){
     if(port->control == fd) break;
   }
+
   if(port == NULL){
     fprintf(stderr, "No port associated with descriptor %d\n", fd);
     return;
   }
-  delete_hash(port->src);
-  free_port(port);
+  free_port(ns, nh, port);
 }
 
-static void update_src(struct port *port, struct packet *p)
+static void update_src(struct netjig_state *ns,
+		       struct nethub       *nh,
+		       struct port *port,
+		       struct packet *p)
 {
   struct port *last;
 
   /* We don't like broadcast source addresses */
   if(IS_BROADCAST(p->header.src)) return;  
 
-  last = find_in_hash(p->header.src);
+  last = find_in_hash(nh, p->header.src);
 
   if(port != last){
     /* old value differs from actual input port */
 
-    printf(" Addr: %02x:%02x:%02x:%02x:%02x:%02x New port %d",
-	   p->header.src[0], p->header.src[1], p->header.src[2],
-	   p->header.src[3], p->header.src[4], p->header.src[5],
-	   port->control);
+    if(ns->verbose) {
+      fprintf(stderr,
+	      " Addr: %02x:%02x:%02x:%02x:%02x:%02x "
+	      " New port %d",
+	      p->header.src[0], p->header.src[1], p->header.src[2],
+	      p->header.src[3], p->header.src[4], p->header.src[5],
+	      port->control);
+    }
 
     if(last != NULL){
-      printf(" old port %d", last->control);
-      delete_hash(p->header.src);
+      if(ns->verbose) {
+	fprintf(stderr, "old port %d", last->control);
+      }
+      delete_hash(nh, p->header.src);
+    }
+    if(ns->verbose) {
+      fprintf(stderr, "\n");
     }
-    printf("\n");
 
-    memcpy(port->src, p->header.src, sizeof(port->src));
-    insert_into_hash(p->header.src, port);
+    memcpy(port->most_recent_ethernet, p->header.src, ETH_ALEN);
+    insert_into_hash(nh, p->header.src, port);
   }
-  update_entry_time(p->header.src);
+  update_entry_time(nh, p->header.src);
 }
 
-static void send_dst(struct port *port, struct packet *packet, int len, 
+static void send_dst(struct netjig_state *ns,
+		     struct nethub       *nh,
+		     struct port *srcport,
+		     struct packet *packet, int len, 
 		     int hub)
 {
   struct port *target, *p;
 
-  target = find_in_hash(packet->header.dest);
+  target = find_in_hash(nh, packet->header.dest);
   if((target == NULL) || IS_BROADCAST(packet->header.dest) || hub){
     if((target == NULL) && !IS_BROADCAST(packet->header.dest)){
-      printf("unknown Addr: %02x:%02x:%02x:%02x:%02x:%02x from port ",
-	     packet->header.src[0], packet->header.src[1], 
-	     packet->header.src[2], packet->header.src[3], 
-	     packet->header.src[4], packet->header.src[5]);
-      if(port == NULL) printf("UNKNOWN\n");
-      else printf("%d\n", port->control);
+      if(ns->verbose) {
+	fprintf(stderr,
+		"hub %s unknown Addr: %02x:%02x:%02x:%02x:%02x:%02x from port %d\n",
+		nh->nh_name,
+		packet->header.src[0], packet->header.src[1], 
+		packet->header.src[2], packet->header.src[3], 
+		packet->header.src[4], packet->header.src[5],
+		(srcport == NULL) ? -1 : srcport->control);
+      }
     } 
 
     /* no cache or broadcast/multicast == all ports */
-    for(p = head; p != NULL; p = p->next){
+    for(p = nh->nh_ports.tqh_first;
+	p != NULL;
+	p = p->link.tqe_next){
       /* don't send it back the port it came in */
-      if(p == port) continue;
+      if(p == srcport) continue;
+
+      /* don't send to ports that aren't initalized yet */
+      if(!p->sender) continue;
 
       (*p->sender)(p->control, packet, len, p->data);
     }
@@ -109,23 +131,37 @@
   else (*target->sender)(target->control, packet, len, target->data);
 }
 
-static void handle_data(int fd, int hub, struct packet *packet, int len, 
-			void *data, int (*matcher)(int port_fd, int data_fd, 
-						   void *port_data,
-						   int port_data_len, 
-						   void *data))
+void insert_data(struct netjig_state *ns,
+		 struct nethub *nh,
+		 struct packet *packet, int len)
+{
+  send_dst(ns, nh, NULL, packet, len, nh->nh_hub);
+}
+
+
+void handle_data(struct netjig_state *ns,
+		 struct nethub *nh,
+		 struct packet *packet, int len,
+		 int   fd,
+		 void *data, int (*matcher)(int port_fd, int data_fd, 
+					    void *port_data,
+					    int port_data_len, 
+					    void *data))
 {
   struct port *p;
 
-  for(p = head; p != NULL; p = p->next){
-    if((*matcher)(p->control, fd, p->data, p->data_len, data)) break;
-  }
+  if(matcher) {
+	  for(p = nh->nh_ports.tqh_first;
+	      p != NULL;
+	      p = p->link.tqe_next){
+		  if((*matcher)(p->control, fd, p->data, p->data_len, data)) break;
+	  }
   
-  /* if we have an incoming port (we should) */
-  if(p != NULL) update_src(p, packet);
-  else printf("Unknown connection for packet, shouldn't happen.\n");
+	  /* if we have an incoming port (we will unless the packet is inserted) */
+	  if(p != NULL) update_src(ns, nh, p, packet);
+  }
 
-  send_dst(p, packet, len, hub);  
+  send_dst(ns, nh, p, packet, len, nh->nh_hub);  
 }
 
 static int match_tap(int port_fd, int data_fd, void *port_data, 
@@ -134,39 +170,34 @@
   return(port_fd == data_fd);
 }
 
-void handle_tap_data(int fd, int hub)
+void handle_tap_data(struct netjig_state *ns,
+		     struct nethub       *nh)
 {
   struct packet packet;
   int len;
 
-  len = read(fd, &packet, sizeof(packet));
+  len = read(nh->tap_fd, &packet, sizeof(packet));
   if(len < 0){
     if(errno != EAGAIN) perror("Reading tap data");
     return;
   }
-  handle_data(fd, hub, &packet, len, NULL, match_tap);
+  handle_data(ns, nh, &packet, len, nh->tap_fd, NULL, match_tap);
 }
 
-int setup_port(int fd, void (*sender)(int fd, void *packet, int len, 
-				      void *data), void *data, int data_len)
+struct port *alloc_port(struct netjig_state *ns,
+			struct nethub       *nh)
 {
   struct port *port;
 
   port = malloc(sizeof(struct port));
   if(port == NULL){
     perror("malloc");
-    return(-1);
+    return(NULL);
   }
-  port->next = head;
-  if(head) head->prev = port;
-  port->prev = NULL;
-  port->control = fd;
-  port->data = data;
-  port->data_len = data_len;
-  port->sender = sender;
-  head = port;
-  printf("New connection\n");
-  return(0);
+  memset(port, 0, sizeof(struct port));
+
+  TAILQ_INSERT_TAIL(&nh->nh_ports, port, link);
+  return port;
 }
 
 struct sock_data {
@@ -181,10 +212,7 @@
   
   err = sendto(mine->fd, packet, len, 0, (struct sockaddr *) &mine->sock,
 	       sizeof(mine->sock));
-  if(err != len){
-    fprintf(stderr, "send_sock sending to fd %d ", mine->fd);
-    perror("");
-  }
+  if(err != len) perror("send_sock");
 }
 
 static int match_sock(int port_fd, int data_fd, void *port_data, 
@@ -197,24 +225,32 @@
   return(!memcmp(&port->sock, &mine->sock, sizeof(mine->sock)));
 }
 
-void handle_sock_data(int fd, int hub)
+
+void handle_sock_data(struct netjig_state *ns,
+		      struct nethub *nh)
 {
   struct packet packet;
   struct sock_data data;
   int len, socklen = sizeof(data.sock);
 
-  len = recvfrom(fd, &packet, sizeof(packet), 0, 
+  len = recvfrom(nh->data_fd,
+		 &packet, sizeof(packet), 0, 
 		 (struct sockaddr *) &data.sock, &socklen);
+
   if(len < 0){
     if(errno != EAGAIN) perror("handle_sock_data");
     return;
   }
-  data.fd = fd;
 
-  handle_data(fd, hub, &packet, len, &data, match_sock);
+  data.fd = nh->data_fd;
+  handle_data(ns, nh, &packet, len, nh->data_fd, &data, match_sock);
 }
 
-int setup_sock_port(int fd, struct sockaddr_un *name, int data_fd)
+
+int setup_sock_port(struct netjig_state *ns,
+		    struct nethub       *nh,
+		    struct port         *port,
+		    struct sockaddr_un  *name)
 {
   struct sock_data *data;
 
@@ -223,120 +259,244 @@
     perror("setup_sock_port");
     return(-1);
   }
-  *data = ((struct sock_data) { fd : 	data_fd,
-				sock :	*name });
-  return(setup_port(fd, send_sock, data, sizeof(*data)));
-}
+  data->fd   = nh->data_fd;
+  data->sock = *name;
+  
+  port->sender = send_sock;
+  port->data   = data;
+  port->data_len=sizeof(*data);
 
-static void service_port(struct port *port)
-{
-  int n;
-  char c;
 
-  n = read(port->control, &c, sizeof(c));
-  if(n < 0) perror("Reading request");
-  else if(n == 0) printf("Disconnect\n");
-  else printf("Bad request\n");  
+  return(0);
 }
 
-int handle_port(int fd)
+int setup_sock_tap(struct netjig_state *ns,
+		   struct nethub       *nh,
+		   int    fd,
+		   packet_sender        tap_sender)
 {
-  struct port *p;
+  struct sock_data *data;
+  struct port *np;
 
-  for(p = head; p != NULL; p = p->next){
-    if(p->control == fd){
-      service_port(p);
-      return(0);
-    }
+  np = alloc_port(ns, nh);
+
+  data = malloc(sizeof(*data));
+  if(data == NULL){
+    perror("setup_sock_port");
+    return(-1);
+  }
+  data->fd   = nh->data_fd;
+  
+  np->sender = tap_sender;
+  np->data   = data;
+  np->data_len=sizeof(*data);
+
+  if(ns->verbose) {
+    fprintf(stderr, "New tap connection\n");
   }
-  return(1);
+  return(0);
 }
 
-static void new_port_v0(int fd, struct request_v0 *req, int data_fd)
+void new_port_v0(struct netjig_state *ns,
+		 struct nethub *nh,
+		 struct port *p,
+		 struct request_v0 *req)
 {
   switch(req->type){
   case REQ_NEW_CONTROL:
-    setup_sock_port(fd, &req->u.new_control.name, data_fd);
-    break;
+	  setup_sock_port(ns, nh, p, &req->u.new_control.name);
+	  break;
+    
   default:
-    printf("Bad request type : %d\n", req->type);
-    close_descriptor(fd);
+	  fprintf(stderr, "Bad request type : %d\n", req->type);
+	  close_descriptor(ns, nh, nh->data_fd);
   }
 }
 
-static void new_port_v1_v3(int fd, enum request_type type, 
-			   struct sockaddr_un *sock, int data_fd)
+void new_port_v1_v3(struct netjig_state *ns,
+		    struct nethub *nh,
+		    struct port   *port,
+		    enum request_type type, 
+		    struct sockaddr_un *sock)
 {
   int n, err;
 
   switch(type){
   case REQ_NEW_CONTROL:
-    err = setup_sock_port(fd, sock, data_fd);
+    err = setup_sock_port(ns, nh, port, sock);
     if(err) return;
-    n = write(fd, &data_sun, sizeof(data_sun));
-    if(n != sizeof(data_sun)){
-      perror("Sending data socket name");
-      close_descriptor(fd);
+    n = write(port->control, &nh->data_sun, sizeof(nh->data_sun));
+    if(n != sizeof(nh->data_sun)){
+      fprintf(stderr, "Sending data socket name: %s\n", strerror(errno));
+      close_descriptor(ns, nh, port->control);
     }
     break;
   default:
-    printf("Bad request type : %d\n", type);
-    close_descriptor(fd);
+    fprintf(stderr, "Bad request type : %d\n", type);
+    close_descriptor(ns, nh, port->control);
   }
 }
 
-static void new_port_v2(int fd, struct request_v2 *req, int data_fd)
+void new_port_v2(struct netjig_state *ns,
+		 struct nethub       *nh,
+		 struct port         *p,
+		 struct request_v2 *req)
 {
   fprintf(stderr, "Version 2 is not supported\n");
-  close_descriptor(fd);
+  close_descriptor(ns, nh, p->control);
 }
 
-void new_port(int fd, int data_fd)
+/*
+ * called when data is ready on a new port
+ */
+void handle_new_port(struct netjig_state *ns,
+		     struct nethub *nh,
+		     struct port   *p) 
 {
   union request req;
   int len;
 
-  len = read(fd, &req, sizeof(req));
+  len = read(p->control, &req, sizeof(req));
   if(len < 0){
     if(errno != EAGAIN){
       perror("Reading request");
-      close_descriptor(fd);
+      close_descriptor(ns,nh,p->control);
     }
     return;
   }
   else if(len == 0){
-    printf("EOF from new port\n");
-    close_descriptor(fd);
+    fprintf(stderr, "EOF from new port\n");
+    close_descriptor(ns,nh,p->control);
     return;
   }
-  if(req.v1.magic == SWITCH_MAGIC){
-    if(req.v2.version == 2) new_port_v2(fd, &req.v2, data_fd);
-    if(req.v3.version == 3) 
-      new_port_v1_v3(fd, req.v3.type, &req.v3.sock, data_fd);
-    else if(req.v2.version > 2) 
-      fprintf(stderr, "Request for a version %d port, which this "
-	      "uml_switch doesn't support\n", req.v2.version);
-    else new_port_v1_v3(fd, req.v1.type, &req.v1.u.new_control.name, data_fd);
+
+  if(req.v1.magic == SWITCH_MAGIC) {
+          if(ns->verbose) {
+	    fprintf(stderr,
+		    "switch %s: new connection using daemon v.%d on port %d\n",
+		    nh->nh_name, req.v2.version, p->control);
+	  }
+	  switch(req.v2.version) {
+	  case 2:
+		  new_port_v2(ns, nh, p, &req.v2);
+		  break;
+		  
+	  case 3:
+		  new_port_v1_v3(ns, nh, p, req.v3.type, &req.v3.sock);
+		  break;
+		  
+	  case 1:
+		  new_port_v1_v3(ns, nh, p, req.v1.type, &req.v1.u.new_control.name);
+		  break;
+		  
+	  default:
+		  fprintf(stderr, "Request for a version %d port, which this "
+			  "uml_switch doesn't support\n", req.v2.version);
+		  break;
+	  }
+  } else {
+	  new_port_v0(ns, nh, p, &req.v0);
   }
-  else new_port_v0(fd, &req.v0, data_fd);
 }
 
-void accept_connection(int fd)
+static void service_port(struct netjig_state *ns,
+			 struct nethub *nh,
+			 struct port *port)
+{
+  int n;
+  char c;
+
+  if(ns->debug > 2) {
+    fprintf(stderr, "servicing port %d\n", port->control);
+  }
+
+  n = read(port->control, &c, sizeof(c));
+  if(n < 0) {
+    fprintf(stderr, "while serving port %d of switch %s reading request: %s",
+	    port->control, nh->nh_name, strerror(errno));
+  }
+  else if(n == 0) {
+    if(ns->verbose) {
+      fprintf(stderr, "Disconnect on switch (%s) from %d addr: %02x:%02x:%02x:%02x:%02x:%02x\n",
+	      nh->nh_name,
+	      port->control,
+	      port->most_recent_ethernet[0], port->most_recent_ethernet[1],
+	      port->most_recent_ethernet[2], port->most_recent_ethernet[3],
+	      port->most_recent_ethernet[4], port->most_recent_ethernet[5]);
+    }
+
+    remove_fd(ns, port->control);
+    free_port(ns, nh, port);
+  }
+  else {
+    if(ns->verbose) {
+      fprintf(stderr,
+	      "Bad request on switch (%s) from %d addr: %02x:%02x:%02x:%02x:%02x:%02x\n",
+	      nh->nh_name,
+	      port->control,
+	      port->most_recent_ethernet[0], port->most_recent_ethernet[1],
+	      port->most_recent_ethernet[2], port->most_recent_ethernet[3],
+	      port->most_recent_ethernet[4], port->most_recent_ethernet[5]);
+    }
+  }
+}
+
+void accept_connection(struct netjig_state *ns,
+		       struct nethub       *nh)
 {
   struct sockaddr addr;
+  struct port *new_port;
   int len, new;
 
   len = sizeof(addr);
-  new = accept(fd, &addr, &len);
+  new = accept(nh->ctl_listen_fd, &addr, &len);
   if(new < 0){
     perror("accept");
     return;
   }
+
+#if 0
   if(fcntl(new, F_SETFL, O_NONBLOCK) < 0){
     perror("fcntl - setting O_NONBLOCK");
     close(new);
     return;
   }
-  add_fd(new);
+#endif
+  
+  new_port = alloc_port(ns, nh);
+  new_port->control = new;
+  add_fd(ns, new);
 }
 
+void handle_port(struct netjig_state *ns,
+		 struct nethub       *nh,
+		 struct pollfd  *l_fds,
+		 int             l_nfds,
+		 int            *l_fd_array,
+		 int             l_fd_array_size)
+{
+  struct port *p;
+  struct port *next_port;
+  
+  for(p = nh->nh_ports.tqh_first;
+      p != NULL;
+      p = next_port)
+    {
+      next_port = p->link.tqe_next;
+
+      if(p->control < l_fd_array_size &&
+	 l_fd_array[p->control]!=-1) {
+
+	if(l_fds[l_fd_array[p->control]].revents & POLLIN) {
+	  if(p->sender) {
+	    service_port(ns, nh, p);
+	  } else {
+	    handle_new_port(ns, nh, p);
+	  }
+	} else if(l_fds[l_fd_array[p->control]].revents & (POLLHUP|POLLERR)) {
+	  remove_fd(ns, p->control);
+	  free_port(ns, nh, p);
+	}
+      }
+    }
+}  
diff -x CVS -x '*~' -u -N -r uml_tools.jig3/uml_router/port.h uml_tools.jig4/uml_router/port.h
--- uml_tools.jig3/uml_router/port.h	Thu Jun  3 15:24:04 2004
+++ uml_tools.jig4/uml_router/port.h	Thu Jun  3 17:09:33 2004
@@ -8,15 +8,65 @@
 #include <sys/socket.h>
 #include <sys/un.h>
 
-extern int handle_port(int fd);
-extern void close_port(int fd);
-extern int setup_sock_port(int fd, struct sockaddr_un *name, int data_fd);
-extern int setup_port(int fd, void (*sender)(int fd, void *packet, int len, 
-					     void *data), void *data, 
-		      int data_len);
-extern void handle_tap_data(int fd, int hub);
-extern void handle_sock_data(int fd, int hub);
-extern void new_port(int fd, int data_fd);
+struct netjig_state;
+struct nethub;
+struct port;
+struct packet;
 
+typedef void (*packet_sender)(int fd, void *packet, int len, void *data);
+
+/* in port.c */
+extern void handle_sock_data(struct netjig_state *ns,
+			     struct nethub *nh);
+extern void handle_tap_data(struct netjig_state *ns,
+			    struct nethub  *nh);
+
+extern void handle_port(struct netjig_state *ns,
+			struct nethub       *nh,
+			struct pollfd  *l_fds,
+			int             l_nfds,
+			int            *l_fd_array,
+			int             l_fd_array_size);
+
+extern void handle_data(struct netjig_state *ns,
+			struct nethub *nh,
+			struct packet *packet, int len,
+			int   fd,
+			void *data, int (*matcher)(int port_fd, int data_fd, 
+						   void *port_data,
+						   int port_data_len, 
+						   void *data));
+
+void insert_data(struct netjig_state *ns,
+		 struct nethub *nh,
+		 struct packet *packet, int len);
+
+
+extern void close_port(struct netjig_state *ns,
+		       struct nethub       *nh,
+		       int fd);
+extern int setup_sock_port(struct netjig_state *ns,
+			   struct nethub       *nh,
+			   struct port        *port,
+			   struct sockaddr_un *name);
+
+extern void setup_port(struct netjig_state *ns,
+		       struct nethub       *nh,
+		       struct port         *port,
+		       int fd,
+		       void (*sender)(int fd, void *packet, int len, 
+				      void *data),
+		       void *data, int data_len);
+
+extern struct port *alloc_port(struct netjig_state *ns,
+			       struct nethub       *nh);
+
+
+extern int setup_sock_tap(struct netjig_state *ns,
+			  struct nethub       *nh,
+			  int    fd,
+			  packet_sender        tap_sender);
+
+extern void accept_connection(struct netjig_state *ns, struct nethub *nh);
 
 #endif
Binary files uml_tools.jig3/uml_router/port.o and uml_tools.jig4/uml_router/port.o differ
diff -x CVS -x '*~' -u -N -r uml_tools.jig3/uml_router/tuntap.c uml_tools.jig4/uml_router/tuntap.c
--- uml_tools.jig3/uml_router/tuntap.c	Thu Jun  3 15:24:04 2004
+++ uml_tools.jig4/uml_router/tuntap.c	Thu Jun  3 17:09:34 2004
@@ -6,6 +6,8 @@
 #include <sys/ioctl.h>
 #include <net/if.h>
 #include <linux/if_tun.h>
+
+#include "nethub.h"
 #include "port.h"
 
 static void send_tap(int fd, void *packet, int len, void *unused)
@@ -18,7 +20,9 @@
   }
 }
 
-int open_tap(char *dev)
+int open_tap(struct netjig_state *ns,
+	     struct nethub *nh,
+	     char *dev)
 {
   struct ifreq ifr;
   int fd, err;
@@ -35,8 +39,12 @@
     close(fd);
     return(-1);
   }
-  err = setup_port(fd, send_tap, NULL, 0);
+
+  err = setup_sock_tap(ns, nh, fd, send_tap);
   if(err) return(err);
+
+  add_fd(ns, fd);
+
   return(fd);
 }
 
diff -x CVS -x '*~' -u -N -r uml_tools.jig3/uml_router/tuntap.h uml_tools.jig4/uml_router/tuntap.h
--- uml_tools.jig3/uml_router/tuntap.h	Thu Jun  3 15:24:04 2004
+++ uml_tools.jig4/uml_router/tuntap.h	Thu Jun  3 17:09:34 2004
@@ -5,7 +5,10 @@
 #ifndef __TUNTAP_H__
 #define __TUNTAP_H__
 
-extern int open_tap(char *dev);
+extern int open_tap(struct netjig_state *ns,
+		    struct nethub *nh,
+		    char *dev);
+
 extern void handle_tap(int fd, int hub);
 
 #endif
Binary files uml_tools.jig3/uml_router/tuntap.o and uml_tools.jig4/uml_router/tuntap.o differ
Binary files uml_tools.jig3/uml_router/uml_switch and uml_tools.jig4/uml_router/uml_switch differ
diff -x CVS -x '*~' -u -N -r uml_tools.jig3/uml_router/uml_switch.c uml_tools.jig4/uml_router/uml_switch.c
--- uml_tools.jig3/uml_router/uml_switch.c	Thu Jun  3 15:24:04 2004
+++ uml_tools.jig4/uml_router/uml_switch.c	Thu Jun  3 17:09:34 2004
@@ -7,12 +7,14 @@
 #include <stdlib.h>
 #include <signal.h>
 #include <fcntl.h>
-#include <stdint.h>
+#include <unistd.h>
 #include <sys/socket.h>
 #include <sys/un.h>
 #include <sys/poll.h>
 #include <sys/time.h>
 #include <unistd.h>
+
+#include "nethub.h"
 #include "switch.h"
 #include "port.h"
 #include "hash.h"
@@ -20,74 +22,128 @@
 #include "tuntap.h"
 #endif
 
-#include "nethub.h"
 
 #ifdef notdef
 #include <stddef.h>
 #endif
 
-static int hub = 0;
-static int compat_v0 = 0;
-char *prog;
+static char *ctl_socket = "/tmp/uml.ctl";
+static char *data_socket = NULL;
 
-char *ctl_socket = "/tmp/uml.ctl";
+char *progname;
 
-char *data_socket = NULL;
-struct sockaddr_un data_sun;
+static struct nethub *global_nh = NULL;
+static struct netjig_state *global_ns=NULL;
+
+static void cleanup(void)
+{
+  if(global_nh) {
+    cleanup_nh(global_nh);
+  }
+}
 
 static void sig_handler(int sig)
 {
-  printf("Caught signal %d, cleaning up and exiting\n", sig);
+  fprintf(stderr, "Caught signal %d, cleaning up and exiting\n", sig);
   cleanup();
   signal(sig, SIG_DFL);
   kill(getpid(), sig);
 }
 
-static void Usage(void)
+void *xmalloc1(size_t size, char *file, int linenum)
 {
-  char *tap_str = "";
+	void *space;
 
-#ifdef TUNTAP
-  tap_str = "[ -tap tap-device ]";
-#endif
+	space = malloc(size);
+	if(space == NULL) {
+		fprintf(stderr, "no memory allocating %d bytes at %s:%d\n",
+			size, file, linenum);
+		exit(1);
+	}
+	return space;
+}
 
-  fprintf(stderr, "Usage : %s [ -unix control-socket ] [ -hub ] %s\n"
-	  "or : %s -compat-v0 [ -unix control-socket data-socket ] "
-	  "[ -hub ] %s\n", prog, tap_str, prog, tap_str);
 
+static void Usage(void)
+{
+  fprintf(stderr, "Usage : %s [ -unix control-socket ] [ -hub ]\n"
+	  "or : %s -compat-v0 [ -unix control-socket data-socket ] [ -hub ]\n"
+	  "or : %s -name switch [ -hub ]\n",
+	  progname, progname, progname);
   exit(1);
 }
 
+static void sig_alarm(int sig)
+{
+  struct itimerval it;
+
+  hash_periodic(global_nh);
+
+  it.it_value.tv_sec = GC_INTERVAL;
+  it.it_value.tv_usec = 0 ;
+  it.it_interval.tv_sec = 0;
+  it.it_interval.tv_usec = 0 ;
+  setitimer(ITIMER_REAL, &it, NULL);
+}
+
+void hash_timer_init()
+{
+  struct sigaction sa;
+
+  sa.sa_handler = sig_alarm;
+  sa.sa_flags = SA_RESTART;
+  if(sigaction(SIGALRM, &sa, NULL) < 0){
+    perror("Setting handler for SIGALRM");
+    return;
+  }
+  kill(getpid(), SIGALRM);
+}
+
 int main(int argc, char **argv)
 {
-  int connect_fd, data_fd, n, i, new, one = 1, daemonize = 0;
+  int hub, compat_v0;
+  int n, i;
   char *tap_dev = NULL;
-#ifdef TUNTAP
-  int tap_fd  = -1;
-#endif
+  char *home;
+  char *switchname;
+  int            *l_fd_array;
+  int             l_fd_array_size;  /* so we can grow it in add_fd() */
+  struct pollfd  *l_fds;        /* array of input sources */
+  int             l_nfds;       /* number of relevant entries */
+
+  hub = 0;
+  compat_v0=0;
+  switchname="switch";
+
+  global_ns = malloc(sizeof(*global_ns));
+  memset(global_ns, 0, sizeof(*global_ns));
+  TAILQ_INIT(&global_ns->switches);
 
-  prog = argv[0];
+  progname = argv[0];
   argv++;
   argc--;
   while(argc > 0){
     if(!strcmp(argv[0], "-unix")){
-      if(argc < 2) 
-	Usage();
+      if(argc < 2) Usage();
       ctl_socket = argv[1];
       argc -= 2;
       argv += 2;
-      if(!compat_v0) 
-	continue;
-      if(argc < 1) 
-	Usage();
+      if(!compat_v0) break;
+      if(argc < 1) Usage();
       data_socket = argv[0];
       argc--;
       argv++;
     }
+    else if(!strcmp(argv[0], "-name")){
+      if(argc < 2) Usage();
+      switchname = argv[1];
+      ctl_socket=NULL;
+      data_socket=NULL;
+      argc -= 2;
+      argv += 2;
+    }
     else if(!strcmp(argv[0], "-tap")){
 #ifdef TUNTAP
-      if(argc < 2) 
-	Usage();
       tap_dev = argv[1];
       argv += 2;
       argc -= 2;
@@ -97,7 +153,7 @@
 #endif      
     }
     else if(!strcmp(argv[0], "-hub")){
-      printf("%s will be a hub instead of a switch\n", prog);
+      printf("%s will be a hub instead of a switch\n", progname);
       hub = 1;
       argc--;
       argv++;
@@ -109,91 +165,85 @@
       argc--;
       argv++;
     }
-    else if(!strcmp(argv[0], "-daemon")){
-      daemonize = 1;
-      argc--;
-      argv++;
-    }
     else Usage();
   }
 
-  if((connect_fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0){
-    perror("socket");
-    exit(1);
-  }
-  if(setsockopt(connect_fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, 
-		sizeof(one)) < 0){
-    perror("setsockopt");
-    exit(1);
-  }
-  if(fcntl(connect_fd, F_SETFL, O_NONBLOCK) < 0){
-    perror("Setting O_NONBLOCK on connection fd");
-    exit(1);
-  }
-  if((data_fd = socket(PF_UNIX, SOCK_DGRAM, 0)) < 0){
-    perror("socket");
-    exit(1);
-  }
-  if(fcntl(data_fd, F_SETFL, O_NONBLOCK) < 0){
-    perror("Setting O_NONBLOCK on data fd");
-    exit(1);
-  }
-
-  if(compat_v0) bind_sockets_v0(connect_fd, ctl_socket, data_fd, data_socket);
-  else bind_sockets(connect_fd, ctl_socket, data_fd);
-
-  if(listen(connect_fd, 15) < 0){
-    perror("listen");
-    exit(1);
+  /* set socket base dir to $HOME/.uml, defaulting back to /tmp/uml,
+   * if $HOME is not set.
+   */
+  if((home=getenv("HOME"))==NULL) {
+    global_ns->socketbasedir="/tmp/uml";
+  } else {
+    global_ns->socketbasedir=xmalloc(strlen(home)+1+sizeof(".umlnet")+1);
+    sprintf(global_ns->socketbasedir,
+	    "%s/.umlnet", home);
   }
 
+  global_nh = init_nethub(global_ns,
+			  switchname,
+			  ctl_socket,
+			  data_socket,
+			  compat_v0);
+  global_nh->nh_hub = hub;
+  
   if(signal(SIGINT, sig_handler) < 0)
     perror("Setting handler for SIGINT");
-  hash_init();
+  hash_timer_init();
 
   if(compat_v0) 
-    printf("%s attached to unix sockets '%s' and '%s'", prog, ctl_socket,
-	   data_socket);
-  else printf("%s attached to unix socket '%s'", prog, ctl_socket);
+    printf("%s attached to unix sockets '%s' and '%s'\n",
+ 	   progname,
+	   global_nh->ctl_socket_name,
+	   (global_nh->data_socket_name ?
+	    global_nh->data_socket_name : "-abstract-named-"));
+  else printf("%s attached to unix socket '%s'\n",
+	      progname,
+	      global_nh->ctl_socket_name);
 
-#ifdef TUNTAP
-  if(tap_dev != NULL)
-    printf(" tap device '%s'", tap_dev);
-#endif
-  printf("\n");
-
-  if(isatty(0))
-    add_fd(0);
-  add_fd(connect_fd);
-  add_fd(data_fd);
+  if(isatty(0)) add_fd(global_ns, 0);
 
 #ifdef TUNTAP
-  if(tap_dev != NULL) tap_fd = open_tap(tap_dev);
-  if(tap_fd > -1) add_fd(tap_fd);
+  if(tap_dev != NULL) {
+    global_nh->tap_fd = open_tap(global_ns, global_nh, tap_dev);
+  }
 #endif
 
-  if (daemonize && daemon(0, 1)) {
-    perror("daemon");
-    exit(1);
-  }
+  l_fd_array = NULL;
+  l_fd_array_size = 0;
+  l_fds = NULL;
+  l_nfds= 0;
 
   while(1){
     char buf[128];
 
-    n = poll(fds, nfds, -1);
+    /*
+     * we need to allocate a local copy of the arrays to use!
+     * since we are going to modify the arrays based upon I/O
+     */
+    if(l_nfds != global_ns->nfds) {
+	    l_nfds = global_ns->nfds;
+	    l_fds = realloc(l_fds, l_nfds * sizeof(struct pollfd));
+    }
+    memcpy(l_fds,      global_ns->fds,      l_nfds * sizeof(struct pollfd));
+    if(l_fd_array_size != global_ns->fd_array_size) {
+	    l_fd_array_size = global_ns->fd_array_size;
+	    l_fd_array = realloc(l_fd_array, l_fd_array_size*sizeof(int));
+    }
+    memcpy(l_fd_array, global_ns->fd_array, l_fd_array_size * sizeof(int));
+    
+    n = poll(l_fds, l_nfds, -1);
     if(n < 0){
       if(errno == EINTR) continue;
       perror("poll");
       break;
     }
-    for(i = 0; i < nfds; i++){
-      if(fds[i].revents == 0) continue;
-      if(fds[i].fd == 0){
-	if(fds[i].revents & POLLHUP){
+    for(i = 0; i < l_nfds; i++){
+      if(l_fds[i].revents == 0) continue;
+      if(l_fds[i].fd == 0){
+	if(l_fds[i].revents & POLLHUP){
 	  printf("EOF on stdin, cleaning up and exiting\n");
 	  goto out;
 	}
-
 	n = read(0, buf, sizeof(buf));
 	if(n < 0){
 	  perror("Reading from stdin");
@@ -204,21 +254,25 @@
 	  goto out;
 	}
       }
-      else if(fds[i].fd == connect_fd){
-	if(fds[i].revents & POLLHUP){
+      else if(l_fds[i].fd == global_nh->ctl_listen_fd){
+	if(l_fds[i].revents & POLLHUP){
 	  printf("Error on connection fd\n");
 	  continue;
 	}
-	accept_connection(connect_fd);
+	accept_connection(global_ns, global_nh);
+      }
+      else if(l_fds[i].fd == global_nh->data_fd) {
+	handle_sock_data(global_ns, global_nh);
       }
-      else if(fds[i].fd == data_fd) handle_sock_data(data_fd, hub);
 #ifdef TUNTAP
-      else if(fds[i].fd == tap_fd) handle_tap_data(tap_fd, hub);
+      else if(l_fds[i].fd == global_nh->tap_fd) {
+	handle_tap_data(global_ns, global_nh);
+      }
 #endif
       else {
-	new = handle_port(fds[i].fd);
-	if(new) new_port(fds[i].fd, data_fd);
-	else close_descriptor(fds[i].fd);
+	handle_port(global_ns, global_nh,
+		    l_fds, l_nfds,
+		    l_fd_array, l_fd_array_size);
       }
     }
   }
Binary files uml_tools.jig3/uml_router/uml_switch.o and uml_tools.jig4/uml_router/uml_switch.o differ


-------------------------------------------------------
This SF.Net email is sponsored by the new InstallShield X.
From Windows to Linux, servers to mobile, InstallShield X is the one
installation-authoring solution that does it all. Learn more and
evaluate today! http://www.installshield.com/Dev2Dev/0504
_______________________________________________
User-mode-linux-devel mailing list
User-mode-linux-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/user-mode-linux-devel

                 reply	other threads:[~2004-06-03 21:21 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=27783.1086297654@camelot-054 \
    --to=michael.richardson@seawaynetworks.com \
    --cc=user-mode-linux-devel@lists.sourceforge.net \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox