home *** CD-ROM | disk | FTP | other *** search
- /*
- c_udp.c
- */
- /* Copyright (c) 1994 Christian F. Tschudin. All rights reserved.
-
- Distributed under the terms of the GNU General Public License
- version 2 of june 1991 as published by the Free Software
- Foundation, Inc.
-
- This file is part of M0.
-
- M0 is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY. No author or distributor accepts responsibility to anyone for
- the consequences of using it or for whether it serves any particular
- purpose or works at all, unless he says so in writing. Refer to the GNU
- General Public License for full details.
-
- Everyone is granted permission to copy, modify and redistribute M0, but
- only under the conditions described in the GNU General Public License.
- A copy of this license is supposed to have been given to you along with
- M0 so you can know your rights and responsibilities. It should be in a
- file named LICENSE. Among other things, the copyright notice and this
- notice must be preserved on all copies. */
-
- #include "c_proto.h"
-
-
- #ifdef CHANNEL_UDP
-
- #include <stdlib.h>
- #include <string.h>
- #include <malloc.h>
-
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <sys/time.h>
- #include <sys/ioctl.h>
- #include <signal.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
- #include <fcntl.h>
- #include <errno.h>
- #include <netdb.h>
-
- #ifndef MAXHOSTNAMELEN
- # define MAXHOSTNAMELEN 64
- #endif
-
- struct udp_data {
- eindex chankey;
- ushort chan;
- uint host;
- ushort port;
- };
-
- eindex udp_addr;
- eindex udp_name;
-
- #define MAXUDPPORTS 5
- static int send_socket[MAXUDPPORTS];
-
-
- int
- udp_listen(uint host, int port)
- {
- struct sockaddr_in host_addr;
- int s;
-
- if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
- return -1;
-
- bzero( &host_addr, sizeof(host_addr) );
- host_addr.sin_family = AF_INET;
- host_addr.sin_addr.s_addr = htonl(host ? host : INADDR_ANY);
- host_addr.sin_port = htons((ushort) port);
-
- if (bind(s, &host_addr, sizeof(struct sockaddr)) < 0)
- return -1;
-
- return s;
- }
-
-
- uint*
- get_ip_addresses()
- {
- static uint* my_addresses;
-
- if (!my_addresses) {
- char myname[MAXHOSTNAMELEN];
- struct hostent *hentry;
- int i;
- uint **ipp;
-
- gethostname(myname, sizeof(myname));
- hentry = gethostbyname(myname);
-
- for (i = 0, ipp = (uint**)(hentry->h_addr_list);
- *ipp ; i++, ipp++);
-
- my_addresses = calloc(i+1, sizeof(uint));
- for (i = 0, ipp = (uint**)(hentry->h_addr_list);
- *ipp ; i++, ipp++)
- my_addresses[i] = ntohl(**ipp);
- my_addresses[i] = 0;
- }
- return my_addresses;
- }
-
-
- int
- udp_init(uint *ip, int port)
- {
- uint *p2;
- int s, i;
- eindex p;
- eptr pp;
-
- for (p2 = ip, i = 0; p2 && *p2; p2++, i++);
- if (!i)
- return -1;
-
- if (i > MAXUDPPORTS)
- i = MAXUDPPORTS;
- udp_addr = new_array(0, i);
- udp_name = name_add((byteptr)"udpip", 5, A_EXECUTABLE);
-
- p = new_element(0, T_INT);
- pp = gaddr(p);
- pp->V.i = port;
-
- for (p2 = ip, i = 0; *p2 && i < MAXUDPPORTS; p2++) {
- eindex a, e;
-
- s = udp_listen(*p2, port);
- if (s > 0) {
- add_incoming(s, udp_recv, udp_name, i);
- send_socket[i] = s;
- a = new_array(0, 2);
- e = new_element(0, T_INT);
- gaddr(e)->V.i = (sint) *p2;
- array_put(0, a, 0, e);
- array_put(0, a, 1, p);
- increfp(pp);
- epattr(gaddr(a)) &= ~A_WRITE;
- array_put(0, udp_addr, i++, a);
- }
- }
-
- decrefp(0, p, pp);
- if (!i) {
- decref(0, udp_addr);
- udp_addr = 0;
- decref(0, udp_name);
- udp_name = 0;
- return -1;
- }
- eplen(gaddr(udp_addr)) = i;
-
- return 0;
- }
-
-
- void
- udp_recv(int s, eindex *msgr, eindex *src)
- {
- #define UDPFRAMESIZE 8092
- struct sockaddr_in from;
- int len, cnt, fromlen = sizeof(from);
- eindex a, h, p;
- byteptr buf;
-
- *msgr = 0;
- if (ioctl(s, FIONREAD, &len) < 0) {
- perror("udp_recv, FIONREAD");
- return;
- }
- if (len > UDPFRAMESIZE)
- len = UDPFRAMESIZE;
- buf = malloc(len);
-
- cnt = recvfrom(s, buf, len, 0, &from, &fromlen);
- if (cnt < 0) {
- perror("recvfrom");
- free(buf);
- return;
- }
-
- *msgr = str_import(0, buf, cnt, len);
- if (!*msgr) {
- free(buf);
- return;
- }
- h = new_element(0, T_INT);
- gaddr(h)->V.i = ntohl(from.sin_addr.s_addr);
- p = new_element(0, T_INT);
- gaddr(p)->V.i = ntohs(from.sin_port);
- a = new_array(0, 2);
- array_put(0, a, 0, h);
- array_put(0, a, 1, p);
- *src = a;
- }
-
-
- int udp_send(int s, uint host, int port, byteptr packet, int len)
- {
- static struct sockaddr_in sockaddr;
-
- TRACE(5, printf("udp send: %u %d (%d bytes)\n", host, port, len))
-
- bzero(&sockaddr, sizeof(struct sockaddr_in));
- sockaddr.sin_family = AF_INET;
- sockaddr.sin_addr.s_addr = htonl(host);
- sockaddr.sin_port = htons(port);
-
- return sendto(s, packet, len, 0,
- (struct sockaddr *)&sockaddr, sizeof (struct sockaddr));
- }
-
-
- char*
- iptoa(uint i)
- {
- static char str[30];
- byteptr ip = (byteptr)&i;
-
- i = htonl(i);
- sprintf(str, "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
- return str;
- }
-
-
- static void
- udp_submit(mproc p, void *data, eindex m)
- {
- struct udp_data *d = (struct udp_data*) data;
- uint len = elen(p,m);
- byteptr s;
-
- len = len > 8000 ? 8000 : len;
- s = malloc(len);
- str_export(p, s, m, 0, len);
-
- if (udp_send(send_socket[d->chan], d->host, d->port, s, len) < 0)
- perror("udp_submit");
-
- dict_undef(0, channeldict, d->chankey);
- free(d);
- free(s);
- return;
- }
-
-
- eindex
- add_udp_channel(sint chan, uint host, ushort port)
- {
- eindex key;
- byte bits[8];
- struct udp_data *d;
-
- random64(bits);
- key = key_add(bits);
- d = (struct udp_data*) malloc(sizeof(struct udp_data));
- d->chankey = key;
- d->chan = chan;
- d->host = host;
- d->port = port;
- new_channel(key, d, udp_submit);
-
- return key;
- }
-
- #endif /* CHANNEL_UDP */
-