* macsock.c: Add Mac socket support file, verbatim from K4 release
authorJohn Gilmore <gnu@toad.com>
Mon, 27 Mar 1995 22:17:24 +0000 (22:17 +0000)
committerJohn Gilmore <gnu@toad.com>
Mon, 27 Mar 1995 22:17:24 +0000 (22:17 +0000)
git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@5274 dc483132-0cff-0310-8789-dd5450dbe970

src/lib/krb5/os/ChangeLog
src/lib/krb5/os/macsock.c [new file with mode: 0644]

index 556a7b318ffcd960dd50ee92636888e95503ee79..4adea7499ae67229291cee60c3affdc7b870341f 100644 (file)
@@ -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 (file)
index 0000000..e62e663
--- /dev/null
@@ -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 <stddef.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+/* Mac includes */
+#include <Memory.h>
+#include <Devices.h>
+#include <errno.h>             /* For ENOMEM */
+
+#ifndef ENOMEM                 /* Think C <errno.h> 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);
+
+\f
+/* 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;
+}
+
+
+\f
+/*
+       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