~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Minix Cross Reference
Minix/Solaris/relay.c


  1 static char *rcsid =  "$Id: relay.c,v 1.2 1996/08/01 02:21:08 paul Exp $";
  2 
  3 /*
  4  * relay
  5  * =====
  6  *
  7  * The relay program serves as a packet switch and simulates an ethernet
  8  * segment.  When it starts up it opens a UDP/IP socket, and publishes its
  9  * addresses in a file (whose name is specified as the single command
 10  * line argument).  It then waits for incoming ethernet packets.  Each
 11  * of the two "ethernet addresses" in the ethernet header is actually
 12  * a UDP/IP address (both are 6 bytes!).  Incoming packets fall into the
 13  * following categories:
 14  *
 15  *    1. Destination address is our address.  A packet from a new smx instance
 16  *       registering itself (its address is the source address).
 17  *    2. A broadcast, that is forwarded to all registered parties.
 18  *    3. A packet sent to some other destination.  It is forwarded to that
 19  *       destination.
 20  *
 21  * It may seem inefficient to route all traffic through the relay (when
 22  * traffic of type 3 can potentially be sent direct from one smx instance
 23  * to another), but the fact that the SunOS library calls to enable direct
 24  * sending are not available means that everything is done via relay.
 25  *
 26  * XXX Currently there is no way for an smx instance to "de-register",
 27  * so if "relay" runs for a long time it may send up forwarding broadcasts
 28  * to a lot of smx instances, many of which are long deceased.
 29  */
 30 
 31 #include <stdio.h>
 32 #include <stdlib.h>
 33 #include <unistd.h>
 34 #include <errno.h>
 35 #include <assert.h>
 36 
 37 #include <sys/types.h>
 38 #include <sys/socket.h>
 39 #include <netinet/in.h>
 40 #include <netdb.h>
 41 
 42 #include "lib.h"
 43 
 44 #define MIN_PKT_SIZE 12     /* packets must have at least dest and src addrs */
 45 
 46 /*
 47  * Local functions.
 48  */
 49 static void usage(void);
 50 
 51 static int open_socket(u_short *port);
 52 static int write_address_file(const char *file_name, u_short port);
 53 static char *get_ourhostname(void);
 54 
 55 static int relay_messages(int sock, u_short port);
 56 static int is_our_machine(u_int host);
 57 static unsigned int *our_ip_nums(void);
 58 static void forward_mesg(int sock, u_int host, u_short port, char *buffer,
 59                          int buff_len);
 60 
 61 static char *progname;
 62 
 63 
 64 /*
 65  * Function: main
 66  * Parameters: argc, argv - the name of the address file must be the only
 67  *             command line argument.
 68  *
 69  * This function coordinates everthing by opening a socket, writing
 70  * its address to a file, and the calling relay_messages to perform
 71  * the relaying.
 72  */
 73 int main(int argc, char *argv[])
 74 {
 75     int sock;
 76     u_short port;
 77 
 78     progname = argv[0];
 79 
 80     if (argc != 2) {
 81         usage();
 82     }
 83 
 84     if ((sock = open_socket(&port)) == -1) {
 85         fprintf(stderr, "%s: failed to open socket\n", progname);
 86         exit(1);
 87     }
 88 
 89     if (write_address_file(argv[1], port) == -1) {
 90         fprintf(stderr, "%s: failed to write address file\n", progname);
 91         exit(1);
 92     }
 93 
 94     relay_messages(sock, port);
 95 
 96     return 0;
 97 }
 98 
 99 
100 /*
101  * Function: usage
102  *
103  * Prints a usage message then calls exit. 
104  */
105 static void usage(void)
106 {
107     fprintf(stderr, "Usage: %s socket_address_file\n", progname);
108     exit(1);
109 }
110 
111 
112 /*
113  * Function: open_socket
114  * Parameter: port - used to return the port number of the UDP address
115  *                   assigned to the socket.
116  * Returns: the descriptor of the open socket on success, -1 on error
117  *
118  * Creates a UDP/IP socket, binds an address to it, and returns the port
119  * number for that address.
120  */
121 static int open_socket(u_short *port)
122 {
123     struct sockaddr_in dsock;
124     int addrlen;
125     int ds;
126 
127     if ((ds = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
128         return -1;
129     }
130 
131     dsock.sin_family = AF_INET;
132     dsock.sin_port = htons(0);
133     dsock.sin_addr.s_addr = htonl(INADDR_ANY);
134     if (bind(ds, (struct sockaddr *) &dsock, sizeof(dsock)) < 0) {
135         return -1;
136     }
137 
138     addrlen = sizeof(dsock);
139     if (getsockname(ds, (struct sockaddr *) &dsock, &addrlen) == -1) {
140         return -1;
141     }
142 
143     *port = ntohs(dsock.sin_port);
144     return ds;
145 }
146 
147 
148 /*
149  * Function: write_address_file
150  * Parameters: file_name - name of file to write to
151  *             port - port number to write to file
152  * Returns: 0 on success, -1 on error
153  *
154  * Writes the host name of the current machine and the specified
155  * port number to the specified file.
156  */
157 static int write_address_file(const char *file_name, u_short port)
158 {
159     FILE *addr_file;
160 
161     addr_file = fopen(file_name, "w");
162     if (addr_file == 0) {
163         return -1;
164     }
165     fprintf(addr_file, "%s %d\n", get_ourhostname(), port);
166     if (fflush(addr_file) == EOF || ferror(addr_file)) {
167         return -1;
168     }
169     if (fclose(addr_file) == EOF) {
170         return -1;
171     }
172 
173     return 0;
174 }
175 
176 
177 /*
178  * Function: get_ourhostname
179  * Returns: a pointer to a static array containing the name of this
180  *          (SunOS) machine.
181  */
182 static char *get_ourhostname(void)
183 {
184     static char our_name[MAXHOSTNAMELEN + 1];
185     static int first_time = 1;
186     int gethostname(char *name, int namelen);    /* not in any .h file */
187 
188     if (first_time) {
189         if (gethostname(our_name, sizeof(our_name)) == -1) {
190             fprintf(stderr, "%s: gethostname error %d\n", progname, errno);
191             exit(1);
192         }
193         first_time = 0;
194     }
195     return our_name;
196 }
197 
198 
199 /*
200  * Function: relay_messages
201  * Parameters: sock - socket on which to receive messages
202  *             port - UDP port number bound to sock
203  * Returns: -1 on error, doesn't return otherwise
204  *
205  * Sits in an infinite loop receiving and processing messages.  Any messages
206  * addressed to relay itself cause a new smx instance to be added to the
207  * list.  Any broadcasts are forwarded to all registered smx instances.
208  * All other messages are forwarded to their specified destinations.
209  * The list of addresses of smx instances is held on the contacts array,
210  * which is dynamically increased in size (REALLOC_CHUNK elements at a time)
211  * as needed.
212  */
213 #define REALLOC_CHUNK 20
214 
215 static int relay_messages(int sock, u_short port)
216 {
217     struct contact_list {
218         u_int ip;
219         u_short port;
220     } *contacts;
221     int array_size, num_contacts;
222 
223     u_int to_host, from_host;
224     u_short to_port, from_port;
225     char buffer[2000];
226     int chars_read;
227 
228     array_size = REALLOC_CHUNK;
229     num_contacts = 0;
230     if ((contacts = malloc(array_size * sizeof(*contacts))) == 0) {
231         return -1;
232     }
233 
234     for (;;) {
235         chars_read = read(sock, buffer, sizeof(buffer));
236 #ifdef DEBUG
237         printf("Got message of %d chars\n", chars_read); fflush(stdout);
238 #endif
239         if (chars_read <= 0) {
240             fprintf(stderr, "%s: %d returned by read on socket; exiting\n",
241                     progname, errno);
242             exit(1);
243         }
244         if (chars_read < MIN_PKT_SIZE) {
245             continue;
246         }
247         to_host = atohost(buffer + DEST_HOST);
248         to_port = atoport(buffer + DEST_PORT);
249         from_host = atohost(buffer + SRC_HOST);
250         from_port = atoport(buffer + SRC_PORT);
251 #ifdef DEBUG
252         printf("to: host 0x%x, port %d; ", to_host, to_port);
253         printf("from: host 0x%x, port = %d; our port = %d\n",
254                from_host, from_port, port);
255         fflush(stdout);
256 #endif
257 
258         if (is_our_machine(to_host) && to_port == port) {
259             /*
260              * This message is directed to the relay server from an smx
261              * bootstrap---the UDP address of the new smx is in the source
262              * field.
263              */
264             if (num_contacts == array_size) {
265                 array_size += REALLOC_CHUNK;
266                 if ((contacts = realloc(contacts, array_size *
267                                         sizeof(*contacts))) == 0) {
268                     return -1;
269                 }
270             }
271             contacts[num_contacts].ip = from_host;
272             contacts[num_contacts].port = from_port;
273 #ifdef DEBUG
274             printf("relay: Adding host 0x%x/%d\n", from_host, from_port);
275             fflush(stdout);
276 #endif
277             num_contacts++;
278             continue;
279         }
280 
281         if (to_host == 0xffffffff && to_port == 0xffff) {
282             int i;
283 
284             /*
285              * Broacdast to everyone
286              */
287             for (i = 0; i < num_contacts; i++) {
288                 if (contacts[i].ip == from_host &&
289                     contacts[i].port == from_port) {
290                     /* Hosts don't get their own broadcasts */
291                     continue;
292                 }
293                 forward_mesg(sock, contacts[i].ip, contacts[i].port, buffer,
294                              chars_read);
295             }
296         } else {
297             forward_mesg(sock, to_host, to_port, buffer, chars_read);
298         }
299     }
300 }
301 
302 
303 /*
304  * Function: is_our_machine
305  * Parameter: host - ip address to be checked
306  * Returns: true if host is an IP address of this machine, false otherwise.
307  */
308 static int is_our_machine(u_int host)
309 {
310     static u_int *our_nums = 0;
311     u_int *np;
312 
313     if (our_nums == 0) {
314         if ((our_nums = our_ip_nums()) == 0) {
315             fprintf(stderr, "%s: falied to get local IP numbers\n", progname);
316             exit(1);
317         }
318     }
319 
320     for (np = our_nums; *np; np++) {
321         if (*np == host) {
322             return 1;
323         }
324     }
325     return 0;
326 }
327 
328 
329 /*
330  * Function: our_ip_nums
331  * Returns: a pointer to a malloc'ed arrat containing all of the ip addresses
332  *          for this machine returned by gethostname.  The list is terminated
333  *          by an ip address of 0.
334  */
335 static unsigned int *our_ip_nums(void)
336 {
337     struct hostent *hp;
338     u_int *nums;
339     u_int **ip;
340     int cnt;
341 
342     if ((hp = gethostbyname(get_ourhostname())) == 0) {
343         return 0;
344     }
345 
346     assert(sizeof(*nums) == hp->h_length);
347     ip = (unsigned int **) hp->h_addr_list;
348     for (cnt = 0; *ip; ip++, cnt++) {
349         ;
350     }
351     if ((nums = malloc((cnt + 1) * sizeof(*nums))) == 0) {
352         return 0;
353     }
354     ip = (unsigned int **) hp->h_addr_list;
355     for (cnt = 0; *ip; ip++, cnt++) {
356         nums[cnt] = **ip;
357     }
358     nums[cnt] = 0;
359     return nums;
360 }
361 
362 
363 /*
364  * Function: forward_mesg
365  * Parameters: sock - socket to send message on.
366  *             host, port - UDP/IP address to send to
367  *             buffer - packet to send
368  *             buff_len - length of packet to send
369  *
370  * Sends the specified packet to the specified UDP/IP address on the specified
371  * socket.
372  */
373 static void forward_mesg(int sock, u_int host, u_short port, char *buffer,
374                          int buff_len)
375 {
376     struct sockaddr_in addr;
377 
378     addr.sin_family = AF_INET;
379     addr.sin_addr.s_addr = htonl(host);
380     addr.sin_port = htons(port);
381     if (sendto(sock, buffer, buff_len, 0, (struct sockaddr *) &addr,
382                sizeof(addr)) != buff_len) {
383         fprintf(stderr, "%s: send failed to %d/%d; errno %d\n", progname,
384                 host, port, errno);
385     }
386 }
387 
388 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.