/* * Jeff Polk * Second Protocol Programming Project * CS 522 * 12-13-92 */ #include #include #include #include #include #include #include #include "msg.h" char *progname; extern int errno; extern int debug; /* * Create a datagram socket. Either choose the port * selected in the args, or let the system choose a port number. * Enable broadcast messages if requested */ int create_sock (addr, port, broadcast) struct sockaddr_in *addr; int port; int broadcast; { int sock; int on=1; int length; char hostname[BUFSIZ]; /* create the new socket */ z((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0, "opening datagram socket"); /* re-use addresses if port is non-zero */ if (port != 0) z(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0, "setsockopt: SO_REUSEADDR"); /* bind the name to the socket */ addr->sin_family = AF_INET; addr->sin_addr.s_addr = INADDR_ANY; addr->sin_port = htons(port); z(bind(sock, addr, sizeof(struct sockaddr_in)) < 0, "binding name to socket"); /* get the assigned name/port */ length = sizeof(struct sockaddr_in); z(getsockname(sock, addr, &length) < 0, "getting socket name"); /* set broadcast if requested */ if (broadcast) z(setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)), "setsockopt: SO_BROADCAST"); /* fill in missing primary address */ gethostname(hostname, BUFSIZ); filladdr(addr, hostname, addr->sin_port); return (sock); } /* * z checks assertions and prints appropriate messages * before aborting. */ #include z(va_alist) va_dcl { va_list pvar; /* var args traverser */ int checkz; /* whether we should quit or not */ char *format; /* printf message */ int i; va_start(pvar); checkz = va_arg(pvar, int); if (!checkz) return; format = va_arg(pvar, char *); (void) fprintf(stdout, "%s Fatal Error: ", progname); (void) vfprintf(stdout, format, pvar); (void) fprintf(stdout, "\n"); va_end(pvar); (void) printf("\n"); exit(1); } /* * Fill in an internet sockaddr structure * given the host name and port number */ int filladdr(addrp, name, port) struct sockaddr_in *addrp; char *name; short port; { struct hostent *hp; extern struct hostent *gethostbyname(); hp = gethostbyname(name); if (hp == NULL) { fprintf(stderr, "%s: unknown host", name); return(-1); } bcopy(hp->h_addr, &addrp->sin_addr, hp->h_length); addrp->sin_family = AF_INET; addrp->sin_port = port; return(0); } /* * Convert appropriate fields of a record from host * to network byte ordering */ htonr(rp) union Record *rp; { switch(rp->rr.msgType) { case REG: break; case PEN: rp->pr.X = htons(rp->pr.X); rp->pr.Y = htons(rp->pr.Y); break; case ERASER: rp->er.X = htons(rp->er.X); rp->er.Y = htons(rp->er.Y); break; case CURSOR: rp->cr.X = htons(rp->cr.X); rp->cr.Y = htons(rp->cr.Y); break; case TEXT: rp->tr.X = htons(rp->tr.X); rp->tr.Y = htons(rp->tr.Y); break; case CLEAN: case DISC: case CONN: case QUIT: /* No conversion required */ break; case BOB: rp->bbr.W = htons(rp->bbr.W); rp->bbr.H = htons(rp->bbr.H); rp->bbr.Length = htons(rp->bbr.Length); break; case NOB: rp->nbr.LineNo = htons(rp->nbr.LineNo); rp->nbr.Length = htons(rp->nbr.Length); break; case ACK: case NAK: case IS: /* No conversion required */ break; default: z(1, "ntohr: Unknown record type (%d)\n", rp->rr.msgType); } } /* * Convert appropriate fields of a record from network * to host byte ordering */ ntohr(rp) union Record *rp; { switch(rp->rr.msgType) { case REG: break; case PEN: rp->pr.X = ntohs(rp->pr.X); rp->pr.Y = ntohs(rp->pr.Y); break; case ERASER: rp->er.X = ntohs(rp->er.X); rp->er.Y = ntohs(rp->er.Y); break; case CURSOR: rp->cr.X = ntohs(rp->cr.X); rp->cr.Y = ntohs(rp->cr.Y); break; case TEXT: rp->tr.X = ntohs(rp->tr.X); rp->tr.Y = ntohs(rp->tr.Y); break; case CLEAN: case DISC: case CONN: case QUIT: /* No conversion required */ break; case BOB: rp->bbr.W = ntohs(rp->bbr.W); rp->bbr.H = ntohs(rp->bbr.H); rp->bbr.Length = ntohs(rp->bbr.Length); break; case NOB: rp->nbr.LineNo = ntohs(rp->nbr.LineNo); rp->nbr.Length = ntohs(rp->nbr.Length); break; case ACK: case NAK: case IS: /* No conversion required */ break; default: z(1, "ntohr: Unknown record type (%d)\n", rp->rr.msgType); } } /* * Find the broadcast interfaces available on this system * and broadcast the message to the specified port via * each interface. */ broadcast(r, sock, port) union Record *r; int sock; int port; { int n; struct ifconf ifc; struct ifreq *ifr, ifreq; char buf[10240]; char *cp, *cplim; struct sockaddr_in to; ifc.ifc_len = sizeof(buf); ifc.ifc_buf = buf; n = ioctl(sock, SIOCGIFCONF, (char *)&ifc); z(n<0, "ioctl SIOCGIFCONF failed: %d", errno); #ifdef AF_LINK #define max(a, b) (a > b ? a : b) #define size(p) max((p).sa_len, sizeof(p)) #else #define size(p) (sizeof (p)) #endif cplim = buf + ifc.ifc_len; for (cp = buf; cp < cplim; cp += sizeof (ifr->ifr_name) + size(ifr->ifr_addr)) { ifr = (struct ifreq *)cp; if (ifr->ifr_addr.sa_family != AF_INET) continue; ifreq = *ifr; n = ioctl(sock, SIOCGIFFLAGS, (char *)&ifreq); z(n<0, "ioctl SIOCGIFFLAGS failed: %d", errno); if ((ifreq.ifr_flags & IFF_UP) == 0 || (ifreq.ifr_flags & IFF_BROADCAST) == 0) continue; n = ioctl(sock, SIOCGIFBRDADDR, (char *)&ifreq); z(n<0, "ioctl SIOCGIFBRDADDR: %d", errno); /* if (debug) printf("BROADCAST: sending packet out interface: %s\n", ifreq.ifr_name); */ bcopy(&ifreq.ifr_broadaddr, &to, sizeof(ifreq.ifr_broadaddr)); to.sin_port = ntohs(port); sendto(sock, r, sizeof(union Record), 0, &to, sizeof(to)); } }