2 * FILE: $Header: /home/egg/src/RCS/network.c,v 1.7 1999/02/28 20:14:20 ghn Exp $
3 * PURPOSE: Network communication functions
9 * Revision 1.7 1999/02/28 20:14:20 ghn
10 * Version 5.1: Modified InitNetwork to take interface (addr) argument as
11 * well as port, and handle various cases of interface (NULL, IP,
12 * hostname) gracefully. Modified NetUp to call this new version.
14 * Revision 1.6 1999/01/02 00:01:01 ghn
15 * Socket and sockaddr_in corrections suggested by Mike Cheponis
17 * perror() turned off for ENETUNREACH/EHOSTUNREACH unless app specifies
18 * "gripe" argument to NetTalk.
20 * Revision 1.5 1998/12/31 22:07:56 ghn
21 * Rev 5 code: includes multi-reg support, HTML, etc.
23 * Revision 1.4 1998/08/03 20:39:03 kelvin
24 * inet_ntoa warning fix, bad packet diagnostics.
26 * Revision 1.3 1998/08/01 18:51:25 ghn
27 * Added John's byte-order-independence changes.
29 * Revision 1.2 1998/08/01 17:16:39 ghn
30 * Added DND support and John's typecasts.
32 * Revision 1.1 1998/07/21 11:36:45 ghn
35 * Copyright 1998 - Greg Nelson
36 * Redistributable under the terms of the GNU Public Licence (GPL)
45 #include <sys/types.h>
46 #include <sys/socket.h>
47 #include <netinet/in.h>
48 #include <arpa/inet.h>
50 #include <sys/ioctl.h>
51 #include <sys/utsname.h>
58 #define MAXBUFSIZE 512
59 char buffer[MAXBUFSIZE];
61 /* Eventually, these might deal with encryption and decryption or
62 validation processes, but until such time as we actually do
63 something with these, they are no-ops. */
64 #define PktEncrypt(buf, len) ERR_NONE
65 #define PktDecrypt(buf, len) ERR_NONE
68 extern void xd(FILE *out, void *bub, int bufl, int dochar);
71 int32 InitNetwork(char *addr, int32 port) {
74 struct sockaddr_in sin;
79 if ((pp = getprotobyname("udp")) == NULL) {
80 perror("getprotobyname");
85 memset(&sin, 0, sizeof(struct sockaddr_in));
86 sin.sin_port = htons(port);
87 sin.sin_family = AF_INET;
89 /* Try to convert dotted quad. Hope this is okay for null addr? */
90 if (!addr || !inet_aton(addr, &(sin.sin_addr))) {
91 /* Nope, so try to gethostbyname */
93 /* No addr at all, use host name from uname */
94 if (uname(&uts) < 0) {
99 strcpy(uts.nodename, addr);
102 if ((hp = gethostbyname(uts.nodename)) == NULL) {
103 fprintf(stderr, "gethostbyname(%s): %s", uts.nodename, strerror(errno));
107 if (hp->h_addrtype != AF_INET) {
108 fprintf(stderr, "Host is not on the internet!\n");
112 memcpy(&(sin.sin_addr), hp->h_addr, hp->h_length);
115 if ((sd = socket(PF_INET, SOCK_DGRAM, 0)) <= 0) {
116 printf("Could not make socket\n");
120 if (bind(sd, (struct sockaddr *)(&sin), sizeof(sin)) != 0) {
121 if (errno == EADDRNOTAVAIL) {
122 /* Network probably not up yet. */
123 close(sd); /* Error pointed out my Mike Cheponis */
132 if (ioctl(sd, FIONBIO, (char *)&argp) != 0) {
133 perror("ioctl FIONBIO");
141 /* Bring net up with command */
142 int32 NetUp(char *cmd, char *addr, int32 port) {
146 /* 0x7e00 = perm denied
147 0x7f00 = command not found
148 256 * cmd if command runs */
149 if (res != 0) return ERR_OTHER;
151 return InitNetwork(addr, port);
154 /* Bring net down with command */
155 int NetDown(char *cmd, int32 oldsd) {
158 /* Close existing connection */
159 if (oldsd >= 0) close(oldsd);
162 if (res != 0) return ERR_OTHER;
167 int NetGetAddr(struct sockaddr_in *sin, char *host, uint16 port) {
170 if ((hp = gethostbyname(host)) == NULL) {
171 fprintf(stderr, "gethostbyname(%s): %s", host, strerror(errno));
175 if (hp->h_addrtype != AF_INET) {
176 fprintf(stderr, "Host is not on the internet!\n");
180 memset(sin, 0, sizeof(struct sockaddr_in));
181 sin->sin_port = htons(port);
182 sin->sin_family = AF_INET;
183 memcpy(&(sin->sin_addr), hp->h_addr, hp->h_length);
188 /* Listen for a data request.
190 Listen on specified socket sd. When one is received, validate the
191 checksum, and, if successful, allocate memory and stuff it as a
192 character array. Return the remote sockaddr_in, if the sin pointer
193 is not null, and block until something interesting happens if block
195 int NetListen(int sd, char **pktbuf,
196 struct sockaddr_in *sin,
199 struct timeval timeout, *top;
205 uint16 pkttype, cksumt, cksumc;
207 if (sd < 0) return ERR_INRANGE;
211 timeout.tv_sec = timeout.tv_usec = 0;
213 /* Wait for an incoming connection.
214 If block is true, we wait indefinitely; otherwise, we
215 return immediately because of zero timeout. */
217 if (block) top = NULL; else top = &timeout;
218 nfound = select(FD_SETSIZE, &fdset, 0, 0, top);
221 if (errno == EWOULDBLOCK) return ERR_COMM_TMOUT;
226 /* No connections, go back to main loop. */
227 if (nfound == 0) return ERR_COMM_TMOUT;
230 fprintf(stderr, "Net port got a request!\n");
233 if (!FD_ISSET(sd, &fdset)) {
234 fprintf(stderr, "Confused condition -- FD not part of set.\n");
239 count = recvfrom(sd, buffer, MAXBUFSIZE, 0,
240 (struct sockaddr *)sin, (int *)&size);
242 /* Don't wait for it. */
243 if (errno == EWOULDBLOCK) return ERR_COMM_TMOUT;
249 fprintf(stderr, "Received %ld bytes from %s\n", count,
250 inet_ntoa(sin->sin_addr));
251 xd(stderr, buffer, count, FALSE);
254 /* Mangle buffer as needed */
255 if ((res = PktDecrypt(buffer, count)) < 0) {
256 fprintf(stderr, "Packet decryption failed with %d.\n", (int)res);
260 /* Verify length and CRC of packet. In making these
261 protocol-level sanity checks, we transform the relevant
262 fields in the packet from network to host byte order
263 as required. Note, however, that the packet returned
264 to the caller remains, in its entirety, in network
265 byte order and even references to protocol-common
266 fields, if made, must be converted by the code which
267 invokes this function. */
269 { uint16 rpkttype, rpktsize, rcrc;
271 memcpy(&rpkttype, buffer, sizeof rpkttype);
272 memcpy(&rpktsize, buffer + 2, sizeof rpktsize);
273 memcpy(&rcrc, buffer + (count - 2), sizeof rcrc);
274 pktsize = ntohs(rpktsize);
275 if (pktsize != count) {
277 fprintf(stderr, "** Bad packet length: pktsize = %d, count = %ld.\n",
280 return ERR_PKT_BADLEN;
282 cksumt = ntohs(rcrc);
283 cksumc = BlockCRC16((byte *) buffer, count - 2);
284 if (cksumc != cksumt) {
286 fprintf(stderr, "** Bad packet CRC: packet = %04X, computed = %04X.\n",
289 return ERR_PKT_CKSUM;
291 pkttype = ntohs(rpkttype);
295 fprintf(stderr, "Recv packet type %04x, %d bytes (hdr), cks = %04x\n",
296 pkttype, pktsize, cksumt);
299 /* Hand back the packet */
300 *pktbuf = (char *)malloc(count);
301 memcpy(*pktbuf, buffer, count);
306 /* Send a data packet.
308 Checksum the packet, create a socket, and send it to the specified
309 port of the specified host. Length of packet to be extracted from
312 /* The entire contents of the packet passed to NetTalk must
313 be in network byte order. Fields within the packet used
314 to append the CRC, determine the number of bytes to send,
315 etc. are converted to host byte order as needed. */
317 int NetTalk(struct sockaddr_in *sin, char *pkt, int gripe) {
318 uint16 pktsize, cksum;
319 static struct protoent *pp = NULL;
322 memcpy(&pktsize, pkt + 2, 2);
323 pktsize = ntohs(pktsize);
325 if (pktsize > 1500) {
326 fprintf(stderr, "Bogus packet size of %ud bytes. Suspect byte alignment bug.\n", pktsize);
330 cksum = htons(BlockCRC16((byte *) pkt, pktsize - sizeof(uint16)));
331 memcpy(pkt+pktsize-sizeof(uint16), &cksum, sizeof(uint16));
333 if (pp == NULL) { /* Only get protocol code the first time */
334 if ((pp = getprotobyname("udp")) == NULL) {
335 perror("getprotobyname");
340 if ((out_sock = socket(AF_INET, SOCK_DGRAM, pp->p_proto)) < 0) {
345 i = sendto(out_sock, pkt, pktsize,
346 0, (struct sockaddr *)sin,
347 sizeof(struct sockaddr));
349 /* We only report on certain errors if told to "gripe", because
350 it is a normal occurence if in PERM mode with a variably
351 available net connection. */
352 if ((errno != ENETUNREACH && errno != EHOSTUNREACH) || gripe) perror("sendto");
358 fprintf(stderr, "Sent %d bytes to %s\n", pktsize, inet_ntoa(sin->sin_addr));
359 xd(stderr, pkt, pktsize, FALSE);