From: John Gilmore Date: Mon, 27 Mar 1995 22:17:24 +0000 (+0000) Subject: * macsock.c: Add Mac socket support file, verbatim from K4 release X-Git-Tag: krb5-1.0-beta5~442 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=eef8cca3aa9381c5f7aaa61d579ad1027b091bdb;p=krb5.git * macsock.c: Add Mac socket support file, verbatim from K4 release git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@5274 dc483132-0cff-0310-8789-dd5450dbe970 --- diff --git a/src/lib/krb5/os/ChangeLog b/src/lib/krb5/os/ChangeLog index 556a7b318..4adea7499 100644 --- a/src/lib/krb5/os/ChangeLog +++ b/src/lib/krb5/os/ChangeLog @@ -1,3 +1,7 @@ +Mon Mar 27 14:16:39 1995 John Gilmore (gnu at toad.com) + + * macsock.c: Add Mac socket support file, verbatim from K4 release. + Fri Mar 24 17:58:15 1995 Theodore Y. Ts'o (tytso@rt-11) * locate_kdc.c: Don't include sys/socket.h, netdb.h, netinet/in.h, diff --git a/src/lib/krb5/os/macsock.c b/src/lib/krb5/os/macsock.c new file mode 100644 index 000000000..e62e66347 --- /dev/null +++ b/src/lib/krb5/os/macsock.c @@ -0,0 +1,484 @@ +/* + * macsock.c + * + * Macintosh socket implementation using MacTCP. + * + * This only implements what's needed for Cygnus Kerberos -- a warped + * subset of UDP. + * + * Written by John Gilmore, Cygnus Support, June 1994. + * Adapted from: + Interface into the UDP class. + Written by Timothy Miller for Brown University. + */ + +/* C includes */ +#include +#include +#include +#include + +/* Mac includes */ +#include +#include +#include /* For ENOMEM */ + +#ifndef ENOMEM /* Think C doesn't have ENOMEM */ +#define ENOMEM ENOSPC +#endif + +/* Our own include file */ +#include "macsock.h" + +/* Kerberos:source:lib:kerb - MacTCP headers from KClient */ +#include "MacTCPCommonTypes.h" +#include "UDPPB.h" +#include "AddressXlation.h" /* MacTCP Domain name resolver decls */ + +/* This WinSock-ism is just too ugly to use everywhere. */ +#define SOCKET_SET_ERRNO WSASetLastError + +/* Description of our WinSock implementation... */ +struct WSAData macsock_data = { + 0x0101, /* wVersion = 1.1 */ + 0x0101, /* wHighVersion = 1.1 */ + "Mac Sockets implemented on top of MacTCP, by John Gilmore of\ +Cygnus Support (email info@cygnus.com).", + "It only implements a small subset of UDP for now.", + 107, /* iMaxSockets, arbitrary number */ + UDPbuflen, /* iMaxUDPDg, max datagram size */ + 0 /* lpVendorInfo, nonexistent */ +}; + +/* This variable implements a kludge in which select() always says that + sockets are ready for I/O, but recvfrom() actually implements the + timeout that select() had requested. This hack happens to work + for Kerberos, which is all that we care about right now. */ +static struct timeval last_timeout; + + +/* Forward declarations of static functions */ + +static pascal void DNRresultproc(struct hostInfo *hinfo, char *userdata); + + +/* Start using sockets */ +int +WSAStartup(WORD wVersionRequested, WSADATA *data) +{ + if (LOBYTE (wVersionRequested) < 1 || + (LOBYTE (wVersionRequested) == 1 && HIBYTE (wVersionRequested) < 1)) + return WSAVERNOTSUPPORTED; + if (data) + *data = macsock_data; + return 0; +} + +/* Finish using sockets */ +int +WSACleanup() +{ + return 0; +} + +/* Get a particular socket */ +SOCKET +socket(af, type, protocol) + int af; + int type; + int protocol; +{ + SOCKET theUDP; + short refNum; + UDPiopb pb; + OSErr err; + + if (af != AF_INET) { + SOCKET_SET_ERRNO (EINVAL); + return INVALID_SOCKET; + } + if (type != SOCK_DGRAM) { + SOCKET_SET_ERRNO (EINVAL); + return INVALID_SOCKET; + } + if (protocol != 0) { + SOCKET_SET_ERRNO (EINVAL); + return INVALID_SOCKET; + } + + theUDP = malloc (sizeof (*theUDP)); + if (theUDP == 0) { + SOCKET_SET_ERRNO (ENOMEM); + return INVALID_SOCKET; + } + + err = OpenDriver( "\p.IPP", &refNum ); + if (err) { + free (theUDP); + SOCKET_SET_ERRNO (EIO); + return INVALID_SOCKET; + } + theUDP->fMacTCPRef = refNum; + + /* Set up param blocks and create the socket (called a + stream by MacTCP). */ + pb.ioCRefNum = theUDP->fMacTCPRef; + pb.csCode = UDPCreate; + pb.csParam.create.rcvBuff = theUDP->fRecvBuf; + pb.csParam.create.rcvBuffLen = UDPbuflen; + pb.csParam.create.notifyProc = NULL; + pb.csParam.create.localPort = 0; + + err = PBControl( (ParamBlockRec *) &pb, false ); + if (err) { + free (theUDP); + SOCKET_SET_ERRNO (EIO); + return INVALID_SOCKET; + } + theUDP->fStream = (unsigned long)pb.udpStream; + + return theUDP; +} + +/* Finish using a particular socket. */ +int +closesocket (theUDP) + SOCKET theUDP; +{ + UDPiopb pb; + + if (theUDP->fStream) { + pb.ioCRefNum = theUDP->fMacTCPRef; + pb.csCode = UDPRelease; + pb.udpStream = (StreamPtr) theUDP->fStream; + + (void) PBControl( (ParamBlockRec *) &pb, false ); + } + + free(theUDP); + return 0; +} + + +/* Bind a socket to a particular address. + In our case, this is just a no-op for bug-compatability with + the FTP Software WINSOCK library. */ +int +bind (s, name, namelen) + SOCKET s; + const struct sockaddr *name; + int namelen; +{ + if (name->sin_family != AF_INET) { + SOCKET_SET_ERRNO (EINVAL); + return SOCKET_ERROR; + } +#if 0 + if (namelen != sizeof (struct sockaddr_in)) { + SOCKET_SET_ERRNO (EINVAL); + return SOCKET_ERROR; + } + if (name->sin_addr.s_addr != INADDR_ANY) { + SOCKET_SET_ERRNO (EINVAL); + return SOCKET_ERROR; + } +#endif + /* OK, then, it's a no-op. */ + s - s; /* lint */ + return 0; +} + + +/* Send a packet to a UDP peer. */ +int +sendto (theUDP, buf, len, flags, to_param, tolen) + SOCKET theUDP; + const char *buf; + const int len; + int flags; + const struct sockaddr *to_param; + int tolen; +{ + OSErr err; + /* really 1 wds + extra space for terminating null */ + wdsEntry wds[2]; + UDPiopb pb; + struct sockaddr_in *to = (struct sockaddr_in *)to_param; + + if (tolen != sizeof (struct sockaddr_in)) { + SOCKET_SET_ERRNO (EINVAL); + return SOCKET_ERROR; + } + if (to->sin_family != AF_INET) { + SOCKET_SET_ERRNO (EINVAL); + return SOCKET_ERROR; + } + + wds[0].length = len; + wds[0].ptr = (char *) buf; + wds[1].length = 0; + + pb.ioCRefNum = theUDP->fMacTCPRef; + pb.csCode = UDPWrite; + pb.udpStream = (StreamPtr) theUDP->fStream; + pb.csParam.send.remotePort = to->sin_port; + pb.csParam.send.wdsPtr = (Ptr) wds; + pb.csParam.send.checkSum = 1; // TRUE + pb.csParam.send.sendLength = 0; // reserved + pb.csParam.send.remoteHost = to->sin_addr.s_addr; + + err = PBControl( (ParamBlockRec *) &pb, false ); + if (err != noErr) { + SOCKET_SET_ERRNO (EIO); + return SOCKET_ERROR; + } + return len; +} + +/* Select for sockets that are ready for I/O. + This version just remembers the timeout for a future receive... + It always reports that one socket is ready for I/O. + */ +int +select (nfds, readfds, writefds, exceptfds, timeout) + int nfds; + fd_set *readfds; + fd_set *writefds; + fd_set *exceptfds; + const struct timeval *timeout; +{ + if (timeout) + last_timeout = *timeout; + return 1; /* Claim that a single FD is ready */ + /* Note that readfd, writefds, and exceptfds still have all + of their current values, indicating that they're all ready + for I/O. */ +} + + +/* Receive a packet from a UDP peer. */ +int +recvfrom (theUDP, buf, len, flags, from_param, fromlen) + SOCKET theUDP; + char *buf; + int len; + int flags; + struct sockaddr *from_param; + int *fromlen; +{ + OSErr err; + UDPiopb pb; + int packet_len; + struct sockaddr_in *from = (struct sockaddr_in *)from_param; + + if (*fromlen < sizeof (*from)) { + SOCKET_SET_ERRNO (EINVAL); + return SOCKET_ERROR; + } + + pb.ioCRefNum = theUDP->fMacTCPRef; + pb.csCode = UDPRead; + pb.udpStream = (StreamPtr) theUDP->fStream; + pb.csParam.receive.timeOut = last_timeout.tv_sec; + pb.csParam.receive.secondTimeStamp = 0; // reserved + + err = PBControl( (ParamBlockRec *) &pb, false ); + if( err ) { + SOCKET_SET_ERRNO (EIO); + return SOCKET_ERROR; + } + + packet_len = pb.csParam.receive.rcvBuffLen; + if( len > packet_len ) + len = packet_len; /* only move as much as we got */ + BlockMove( pb.csParam.receive.rcvBuff, buf, len ); + *fromlen = sizeof (*from); + from->sin_family = AF_INET; + from->sin_port = pb.csParam.receive.remotePort; + from->sin_addr.s_addr = pb.csParam.receive.remoteHost; + + if( pb.csParam.receive.rcvBuffLen ) { + pb.csCode = UDPBfrReturn; + err = PBControl( (ParamBlockRec *) &pb, false ); + } + + if (len < packet_len) { + /* Only got first part of packet, rest was dropped. */ + SOCKET_SET_ERRNO (EMSGSIZE); + return SOCKET_ERROR; + } + return len; +} + + + +/* + Interface UNIX routine inet_ntoa with mac equivalent. + + The input argument is a struct containing the internet address. + struct type defined in config-mac.h + + The routine inet_ntoa() returns a pointer to a string in the + base 256 notation ``d.d.d.d'' +*/ + + +char* +inet_ntoa(struct in_addr ina) { + OSErr err; +#define max_addr_str 16 + char addrStr[max_addr_str]; + + err = AddrToStr(ina.s_addr, addrStr); + return addrStr; + +} + +/* Static variables which provide space for the last result from getXbyY. */ + +static struct hostInfo host; +static char * ipaddr_ptrs[NUM_ALT_ADDRS+1]; +static struct hostent result; + +/* + Performs a domain name resolution of host, returning an IP address for it, + or 0 if any error occurred. + + FIXME -- this routine has the potential to go asynchronous, but it + loops until the asynchronous call to MacTCP finishes. + */ + +struct hostent * +gethostbyname (char *hostname) +{ + OSErr err; + char done = false; + int i; + + if (err = OpenResolver(NULL)) + return(0); // make sure resolver is open + err = StrToAddr(hostname, &host, DNRresultproc, &done); + + if (err == cacheFault) { + while(!done) ; /* LOOP UNTIL CALLBACK IS RUN */ + err = host.rtnCode; /* Pick up final result code */ + } + + if (err != noErr) { + return 0; + } + + /* Build result in hostent structure, which we will return to caller. */ + + result.h_name = host.cname; + result.h_aliases = 0; /* We don't know about aliases. */ + result.h_addrtype = AF_INET; + result.h_length = sizeof (host.addr[0]); /* Length of each address */ + result.h_addr_list = ipaddr_ptrs; + for (i = 0; i < NUM_ALT_ADDRS; i++) + if (host.addr[i] != 0) /* Assume addrs terminated with 0 addr */ + ipaddr_ptrs[i] = (char*) &host.addr[i]; /* Point at good IP addresses */ + else + break; /* Quit when we see first zero address */ + ipaddr_ptrs[i] = 0; + + return &result; +} + +/* Does a reverse DNS lookup of addr, to find the canonical name of its host. + FIXME, set errno for failures. */ + +struct hostent * +gethostbyaddr (char *addr, int len, int type) +{ + OSErr err; + char done = false; + ip_addr macaddr; + + if (type != AF_INET) + return 0; /* We only do Internet addresses */ + if (len != sizeof (ip_addr)) + return 0; /* We only handle IP addrs *this* long... */ + memcpy ((void *)&macaddr, (void *)addr, (size_t)len); + + if (err = OpenResolver(NULL)) + return 0; // make sure resolver is open + err = AddrToName(macaddr, &host, DNRresultproc, &done); + + if (err == cacheFault) { + while(!done) ; /* LOOP UNTIL CALLBACK IS RUN */ + err = host.rtnCode; /* Pick up final result code */ + } + + if (err != noErr) { + /* Set errno? FIXME. */ + return 0; + } + + /* Build result in hostent structure, which we will return to caller. */ + + result.h_name = host.cname; + result.h_aliases = 0; /* We don't know about aliases. */ + result.h_addrtype = AF_INET; + result.h_length = sizeof (host.addr[0]); /* Length of each address */ + result.h_addr_list = 0; /* MacTCP doesn't give us this info on addr->name */ + + return &result; +} + +/* Tell calling program that the asynchronous operation has finished. + FIXME, this will require significant work if we support async calls to + Kerberos in the future. */ +static pascal void +DNRresultproc(struct hostInfo *hinfo, char *userdata) +{ + *userdata = true; +} + +#if 0 +/* FIXME: THIS WAS A STAB AT GETHOSTNAME, which I abandoned for lack of need, + and since the required header files didn't seem to be handy. + -- gnu@cygnus.com june94 */ +/* + * gethostname + * + * Gets our own host name, by getting our IP address and asking what name + * corresponds. There seems to be no better way in MacTCP to do this. + */ + int + gethostname(name, namelen) + char *name; + int namelen; +{ + ip_addr ourAddress; + SOCKET sock; + struct IPParamBlock pb; + struct hostent *host; + struct sockaddr_in hostaddr; + + sock = socket (AF_INET, SOCK_DGRAM, 0); + if (!sock) + return -1; + pb.ioCRefNum = sock->fMacTCPRef; + pb.csCode = ipctlGetAddr; + err = PBControl( (ParamBlockRec *) &pb, false ); + if (err) { + free (theUDP); + SOCKET_SET_ERRNO (EIO); + return -1; + } + + + pb.csParam.xxxx + + host = gethostbyaddr (&hostaddr, sizeof (hostaddr), AF_INET); + if (!host) + return -1; + len = strlen (host->h_name); + if (len > namelen) + return -1; + memcpy (name, host->h_name, len+1); + return 0; +} + +#endif