/* * Establish a UDP socket and optionally call connect() to set up * the server's address for future I/O. */ #include "netdefs.h" #include #include #ifndef INADDR_NONE #define INADDR_NONE 0xffffffff /* should be in */ #endif /* * The following globals are available to the caller, if desired. */ struct sockaddr_in udp_srv_addr; /* server's Internet socket addr */ struct sockaddr_in udp_cli_addr; /* client's Internet socket addr */ struct servent udp_serv_info; /* from getservbyname() */ struct hostent udp_host_info; /* from gethostbyname() */ int /* return socket descriptor if OK, else -1 on error */ udp_open(host, service, port, dontconn) char *host; /* name of other system to communicate with */ char *service; /* name of service being requested */ /* can be NULL, iff port > 0 */ int port; /* if == 0, nothing special - use port# of service */ /* if < 0, bind a local reserved port */ /* if > 0, it's the port# of server (host-byte-order) */ int dontconn; /* if == 0, call connect(), else don't */ { int fd; unsigned long inaddr; char *host_err_str(); struct servent *sp; struct hostent *hp; /* * Initialize the server's Internet address structure. * We'll store the actual 4-byte Internet address and the * 2-byte port# below. */ bzero((char *) &udp_srv_addr, sizeof(udp_srv_addr)); udp_srv_addr.sin_family = AF_INET; if (service != NULL) { if ( (sp = getservbyname(service, "udp")) == NULL) { err_ret("udp_open: unknown service: %s/udp", service); return(-1); } udp_serv_info = *sp; /* structure copy */ if (port > 0) udp_srv_addr.sin_port = htons(port); /* caller's value */ else udp_srv_addr.sin_port = sp->s_port; /* service's value */ } else { if (port <= 0) { err_ret("udp_open: must specify either service or port"); return(-1); } udp_srv_addr.sin_port = htons(port); } /* * First try to convert the host name as a dotted-decimal number. * Only if that fails do we call gethostbyname(). */ if ( (inaddr = inet_addr(host)) != INADDR_NONE) { /* it's dotted-decimal */ bcopy((char *) &inaddr, (char *) &udp_srv_addr.sin_addr, sizeof(inaddr)); udp_host_info.h_name = NULL; } else { if ( (hp = gethostbyname(host)) == NULL) { err_ret("udp_open: host name error: %s %s", host, host_err_str()); return(-1); } udp_host_info = *hp; /* found it by name, structure copy */ bcopy(hp->h_addr, (char *) &udp_srv_addr.sin_addr, hp->h_length); } if (port < 0) err_quit("udp_open: reserved ports not implemeneted yet"); if ( (fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { err_ret("udp_open: can't create UDP socket"); return(-1); } /* * Bind any local address for us. */ bzero((char *) &udp_cli_addr, sizeof(udp_cli_addr)); udp_cli_addr.sin_family = AF_INET; udp_cli_addr.sin_addr.s_addr = htonl(INADDR_ANY); udp_cli_addr.sin_port = htons(0); if (bind(fd, (struct sockaddr *) &udp_cli_addr, sizeof(udp_cli_addr)) < 0) { err_ret("udp_open: bind error"); close(fd); return(-1); } /* * Call connect, if desired. This is used by most caller's, * as the peer shouldn't change. (TFTP is an exception.) * By calling connect, the caller can call send() and recv(). */ if (dontconn == 0) { if (connect(fd, (struct sockaddr *) &udp_srv_addr, sizeof(udp_srv_addr)) < 0) { err_ret("udp_open: connect error"); return(-1); } } return(fd); }