home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / nsprpub / pr / src / md / mac / macsockotpt.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  36.8 KB  |  1,543 lines

  1. /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /*
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  * 
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  * 
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18.  
  19. /* This turns on UNIX style errors in OT 1.1 headers */
  20. #define OTUNIXERRORS 1
  21.  
  22. #include <Gestalt.h>
  23.  
  24. /*
  25.     Since Apple put out new headers without
  26.     putting in a way to test for them, we found some random symbol which
  27.     isn't defined in the "1.1" headers.
  28. */
  29. #include <OpenTransport.h>
  30. #ifdef kOTInvalidStreamRef
  31. /* old */
  32. #define GESTALT_OPEN_TPT_PRESENT        gestaltOpenTptPresent
  33. #define GESTALT_OPEN_TPT_TCP_PRESENT    gestaltOpenTptTCPPresent
  34. #else
  35. /* new */
  36. #define GESTALT_OPEN_TPT_PRESENT        gestaltOpenTptPresentMask
  37. #define GESTALT_OPEN_TPT_TCP_PRESENT    gestaltOpenTptTCPPresentMask
  38. #endif
  39.  
  40. #include <OpenTptInternet.h>    // All the internet typedefs
  41. #include "macsocket.h"
  42. #include "primpl.h"
  43.  
  44. typedef enum SndRcvOpCode {
  45.     kSTREAM_SEND,
  46.     kSTREAM_RECEIVE    ,
  47.     kDGRAM_SEND,
  48.     kDGRAM_RECEIVE
  49. } SndRcvOpCode;
  50.  
  51.  
  52. static InetSvcRef sSvcRef;
  53.  
  54. static pascal void  NotifierRoutine(void * contextPtr, OTEventCode code, 
  55.             OTResult result, void * cookie);
  56.  
  57. static PRBool GetState(EndpointRef endpoint, PRBool *readReady, PRBool *writeReady, PRBool *exceptReady);
  58.  
  59. extern void WaitOnThisThread(PRThread *thread, PRIntervalTime timeout);
  60. extern void DoneWaitingOnThisThread(PRThread *thread);
  61.  
  62. void _MD_InitNetAccess()
  63. {
  64.     OSErr        err;
  65.     OSStatus    errOT;
  66.     PRBool         hasOTTCPIP = PR_FALSE;
  67.     PRBool         hasOT = PR_FALSE;
  68.     long         gestaltResult;
  69.     PRThread *me = _PR_MD_CURRENT_THREAD();
  70.     
  71.     err = Gestalt(gestaltOpenTpt, &gestaltResult);
  72.     if (err == noErr)
  73.         if (gestaltResult & GESTALT_OPEN_TPT_PRESENT)
  74.             hasOT = PR_TRUE;
  75.     
  76.     if (hasOT)
  77.         if (gestaltResult & GESTALT_OPEN_TPT_TCP_PRESENT)
  78.             hasOTTCPIP = PR_TRUE;
  79.         
  80.     PR_ASSERT(hasOTTCPIP == PR_TRUE);
  81.  
  82.     errOT = InitOpenTransport();
  83.     PR_ASSERT(err == kOTNoError);
  84.  
  85.     sSvcRef = OTOpenInternetServices(kDefaultInternetServicesPath, NULL, &errOT);
  86.     if (errOT != kOTNoError) return;    /* no network -- oh well */
  87.     PR_ASSERT((sSvcRef != NULL) && (errOT == kOTNoError));
  88.  
  89.     /* Install notify function for DNR Address To String completion */
  90.     errOT = OTInstallNotifier(sSvcRef, NotifierRoutine, me);
  91.     PR_ASSERT(errOT == kOTNoError);
  92.  
  93.     /* Put us into async mode */
  94.     errOT = OTSetAsynchronous(sSvcRef);
  95.     PR_ASSERT(errOT == kOTNoError);
  96.  
  97. /* XXX Does not handle absence of open tpt and tcp yet! */
  98. }
  99.  
  100. static void macsock_map_error(OSStatus err)
  101. {
  102.     _PR_MD_CURRENT_THREAD()->md.osErrCode = err;
  103.  
  104.     if (IsEError(err) || (err >= EPERM && err <= ELASTERRNO)) {
  105.     switch (IsEError(err) ? OSStatus2E(err) : err) {
  106.         case EBADF:
  107.             PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err);
  108.             break;
  109.         case EADDRNOTAVAIL:
  110.             PR_SetError(PR_ADDRESS_NOT_AVAILABLE_ERROR, err);
  111.             break;
  112.         case EINPROGRESS:
  113.             PR_SetError(PR_IN_PROGRESS_ERROR, err);
  114.             break;
  115.         case EWOULDBLOCK:
  116.         case EAGAIN:
  117.             PR_SetError(PR_WOULD_BLOCK_ERROR, err);
  118.             break;
  119.         case ENOTSOCK:
  120.             PR_SetError(PR_NOT_SOCKET_ERROR, err);
  121.             break;
  122.         case ETIMEDOUT:
  123.             PR_SetError(PR_IO_TIMEOUT_ERROR, err);
  124.             break;
  125.         case ECONNREFUSED:
  126.             PR_SetError(PR_CONNECT_REFUSED_ERROR, err);
  127.             break;
  128.         case ENETUNREACH:
  129.             PR_SetError(PR_NETWORK_UNREACHABLE_ERROR, err);
  130.             break;
  131.         case EADDRINUSE:
  132.             PR_SetError(PR_ADDRESS_IN_USE_ERROR, err);
  133.             break;
  134.         case EFAULT:
  135.             PR_SetError(PR_ACCESS_FAULT_ERROR, err);
  136.             break;
  137.         case EINTR:
  138.             PR_SetError(PR_PENDING_INTERRUPT_ERROR, err);
  139.             break;
  140.         case EINVAL:
  141.             PR_SetError(PR_INVALID_ARGUMENT_ERROR, err);
  142.             break;
  143.         case EIO:
  144.             PR_SetError(PR_IO_ERROR, err);
  145.             break;
  146.         case ENOENT:
  147.             PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, err);
  148.             break;
  149.         case ENXIO:
  150.             PR_SetError(PR_IO_ERROR, err);
  151.             break;
  152.         case EPROTOTYPE:
  153.             PR_SetError(PR_PROTOCOL_NOT_SUPPORTED_ERROR, err);
  154.             break;
  155.         case EOPNOTSUPP:
  156.             PR_SetError(PR_OPERATION_NOT_SUPPORTED_ERROR, err);
  157.             break;
  158.         default:
  159.             PR_SetError(PR_UNKNOWN_ERROR, err);
  160.             break;
  161.         }
  162.     } else {
  163.     PR_ASSERT(IsXTIError(err));
  164.     switch (err) {
  165.         case kOTNoDataErr:
  166.         case kOTFlowErr:
  167.             PR_SetError(PR_WOULD_BLOCK_ERROR, err);
  168.             break;
  169.         default:
  170.             PR_ASSERT(0);
  171.             PR_SetError(PR_UNKNOWN_ERROR, err);
  172.             break;
  173.         }
  174.     }
  175. }
  176.  
  177. static void PrepareThreadForAsyncIO(PRThread *thread, EndpointRef endpoint, PRInt32 osfd)
  178. {
  179.     OSStatus err;
  180.  
  181.     thread->io_pending = PR_TRUE;
  182.     thread->io_fd = osfd;
  183.     thread->md.osErrCode = noErr;
  184.  
  185.     OTRemoveNotifier(endpoint);
  186.     err = OTInstallNotifier(endpoint, NotifierRoutine, thread);
  187.     PR_ASSERT(err == kOTNoError);
  188. }
  189.  
  190. // Notification routine
  191. // Async callback routine.
  192. // A5 is OK. Cannot allocate memory here
  193. pascal void  NotifierRoutine(void * contextPtr, OTEventCode code, OTResult result, void * cookie)
  194. {
  195.     PRThread * thread = (PRThread *) contextPtr;
  196.     _PRCPU *cpu = _PR_MD_CURRENT_CPU();    
  197.     
  198.     switch (code)
  199.     {
  200. // Async Completion Event
  201.         case T_OPENCOMPLETE:
  202.         case T_BINDCOMPLETE:
  203.         case T_UNBINDCOMPLETE:
  204.         case T_GETPROTADDRCOMPLETE:
  205.         case T_ACCEPTCOMPLETE:
  206. // Connect callback
  207.         case T_CONNECT:
  208. // Standard or expedited data is available
  209.         case T_DATA:
  210.         case T_EXDATA:
  211. // Standard or expedited data Flow control lifted
  212.         case T_GODATA:
  213.         case T_GOEXDATA:
  214. // Asynchronous Listen Event
  215.         case T_LISTEN:
  216. // DNR String To Address Complete Event
  217.         case T_DNRSTRINGTOADDRCOMPLETE:
  218. // Option Management Request Complete Event
  219.         case T_OPTMGMTCOMPLETE:
  220.             thread->md.osErrCode = result;
  221.             thread->md.cookie = cookie;
  222.             if (_PR_MD_GET_INTSOFF()) {
  223.                 cpu->u.missed[cpu->where] |= _PR_MISSED_IO;
  224.                 thread->md.notifyPending = PR_TRUE;
  225.                 return;
  226.             }
  227.             DoneWaitingOnThisThread(thread);
  228.             break;
  229.  
  230. // T_ORDREL orderly release is available;  nothing to do
  231.         case T_ORDREL:
  232.             break;
  233.  
  234. // T_PASSCON; nothing to do
  235.         case T_PASSCON:
  236.             break;
  237.  
  238. // T_DISCONNECT; disconnect is available; nothing to do
  239.         case T_DISCONNECT:
  240.             break;
  241.  
  242. // UDP Send error; clear the error
  243.         case T_UDERR:
  244.             (void) OTRcvUDErr((EndpointRef) cookie, NULL);
  245.         default:
  246.             PR_ASSERT(0);
  247.     }
  248. }
  249.  
  250.  
  251. static OSErr CreateSocket(int type, EndpointRef *endpoint)
  252. {
  253.     OSStatus err;
  254.     PRThread *me = _PR_MD_CURRENT_THREAD();
  255.  
  256.     switch (type){
  257.         case SOCK_STREAM:
  258.             err = OTAsyncOpenEndpoint(OTCreateConfiguration(kTCPName), 0, NULL, 
  259.                     NotifierRoutine, me);
  260.             break;
  261.         case SOCK_DGRAM:
  262.             err = OTAsyncOpenEndpoint(OTCreateConfiguration(kUDPName), 0, NULL,
  263.                     NotifierRoutine, me);
  264.             break;
  265.     }
  266.     if (err != kOTNoError)
  267.         goto ErrorExit;
  268.  
  269.     WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT);
  270.  
  271.     err = me->md.osErrCode;
  272.     if (err != kOTNoError)
  273.         goto ErrorExit;
  274.  
  275.     *endpoint = me->md.cookie;
  276.     PR_ASSERT(*endpoint != NULL);
  277.  
  278.     return kOTNoError;
  279.  
  280. ErrorExit:
  281.     return err;
  282. }
  283.  
  284.  
  285. // Errors returned:
  286. // kOTXXXX - OT returned error
  287. // EPROTONOSUPPORT - bad socket type/protocol
  288. // ENOBUFS - not enough space for another socket, or failure in socket creation routine
  289. PRInt32 _MD_socket(int domain, int type, int protocol)
  290. {
  291.     OSStatus    err;
  292.     EndpointRef endpoint;
  293.  
  294.     // We only deal with internet domain
  295.     if (domain != AF_INET) {
  296.         err = kEPROTONOSUPPORTErr;
  297.         goto ErrorExit;
  298.     }
  299.     
  300.     // We only know about tcp & udp
  301.     if ((type != SOCK_STREAM) && (type != SOCK_DGRAM)) {
  302.         err = kEPROTONOSUPPORTErr;
  303.         goto ErrorExit;
  304.     }
  305.     
  306.     // Convert default types to specific types.
  307.     if (protocol == 0)  {
  308.         if (type == SOCK_DGRAM)
  309.             protocol = IPPROTO_UDP;
  310.         else if (type == SOCK_STREAM)
  311.             protocol = IPPROTO_TCP;
  312.     }
  313.     
  314.     // Only support default protocol for tcp
  315.     if ((type == SOCK_STREAM)  && (protocol != IPPROTO_TCP)) {
  316.         err = kEPROTONOSUPPORTErr;
  317.         goto ErrorExit;
  318.     }
  319.                 
  320.     // Only support default protocol for udp
  321.     if ((type == SOCK_DGRAM)  && (protocol != IPPROTO_UDP)) {
  322.         err = kEPROTONOSUPPORTErr;
  323.         goto ErrorExit;
  324.     }
  325.         
  326.     // Create a socket, we might run out of memory
  327.     err = CreateSocket(type, &endpoint);
  328.     if (err != kOTNoError)
  329.         goto ErrorExit;
  330.  
  331.     PR_ASSERT((PRInt32)endpoint != -1);
  332.  
  333.     return ((PRInt32)endpoint);
  334.  
  335. ErrorExit:
  336.     macsock_map_error(err);
  337.     return -1;
  338. }
  339.  
  340. // Errors:
  341. // EBADF -- bad socket id
  342. // EFAULT -- bad address format
  343. PRInt32 _MD_bind(PRFileDesc *fd, PRNetAddr *addr, PRUint32 addrlen)
  344. {
  345.     PRInt32 osfd = fd->secret->md.osfd;
  346.     OSStatus err;
  347.     EndpointRef endpoint = (EndpointRef) osfd;
  348.     TBind bindReq;
  349.     PRThread *me = _PR_MD_CURRENT_THREAD();
  350.     PRUint32 retryCount = 0;
  351.  
  352.     if (endpoint == NULL) {
  353.         err = kEBADFErr;
  354.         goto ErrorExit;
  355.     }
  356.         
  357.     if (addr == NULL) {
  358.         err = kEFAULTErr;
  359.         goto ErrorExit;
  360.     }
  361.         
  362.     // setup our request
  363. #if 0
  364.     if ((addr->inet.port == 0) || (addr->inet.ip == 0))
  365.         bindReq.addr.len = 0;
  366.     else
  367. #endif
  368. /*
  369.  * There seems to be a bug with OT ralted to OTBind failing with kOTNoAddressErr eventhough
  370.  * a proper legal address was supplied.  This happens very rarely and just retrying the
  371.  * operation after a certain time (less than 1 sec. does not work) seems to succeed.
  372.  */
  373.  
  374. TryAgain:
  375.     bindReq.addr.len = addrlen;
  376.         
  377.     bindReq.addr.maxlen = addrlen;
  378.     bindReq.addr.buf = (UInt8*) addr;
  379.     bindReq.qlen = 1;
  380.     
  381.     PrepareThreadForAsyncIO(me, endpoint, osfd);    
  382.  
  383.     err = OTBind(endpoint, &bindReq, NULL);
  384.     if (err != kOTNoError)
  385.         goto ErrorExit;
  386.  
  387.     WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT);
  388.  
  389.     err = me->md.osErrCode;
  390.     if (err != kOTNoError)
  391.         goto ErrorExit;
  392.  
  393.     PR_ASSERT(me->md.cookie == NULL);
  394.  
  395.     return kOTNoError;
  396.  
  397. ErrorExit:
  398.     if ((err == kOTNoAddressErr) && (++retryCount <= 4)) {
  399.         long finalTicks;
  400.     
  401.         Delay(100,&finalTicks);
  402.         goto TryAgain;
  403.     }
  404.     macsock_map_error(err);
  405.     return -1;
  406. }
  407.  
  408. // Errors:
  409. // EBADF -- bad socket id
  410. PRInt32 _MD_listen(PRFileDesc *fd, PRIntn backlog)
  411. {
  412. #if 0
  413.     PRInt32 osfd = fd->secret->md.osfd;
  414.     OSStatus err;
  415.     EndpointRef endpoint = (EndpointRef) osfd;
  416.     TBind bindReq;
  417.     PRNetAddr addr;
  418.     PRThread *me = _PR_MD_CURRENT_THREAD();
  419.  
  420.     if (backlog == 0)
  421.         backlog = 1;
  422.  
  423.     if (endpoint == NULL) {
  424.         err = EBADF;
  425.         goto ErrorExit;
  426.     }
  427.         
  428.     addr.inet.port = addr.inet.ip = 0;
  429.  
  430.     bindReq.addr.maxlen = PR_NETADDR_SIZE (&addr);
  431.     bindReq.addr.len = 0;
  432.     bindReq.addr.buf = (UInt8*) &addr;
  433.     bindReq.qlen = 0;
  434.     
  435.     PrepareThreadForAsyncIO(me, endpoint, osfd);    
  436.  
  437.     err = OTGetProtAddress(endpoint, &bindReq, NULL);
  438.     if (err != kOTNoError)
  439.         goto ErrorExit;
  440.  
  441.     WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT);
  442.  
  443.     err = me->md.osErrCode;
  444.     if (err != kOTNoError)
  445.         goto ErrorExit;
  446.  
  447.     PrepareThreadForAsyncIO(me, endpoint, osfd);    
  448.  
  449.     err = OTUnbind(endpoint);
  450.     if (err != kOTNoError)
  451.         goto ErrorExit;
  452.  
  453.     WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT);
  454.  
  455.     err = me->md.osErrCode;
  456.     if (err != kOTNoError)
  457.         goto ErrorExit;
  458.  
  459.     bindReq.qlen = backlog;
  460.     
  461.     PrepareThreadForAsyncIO(me, endpoint, osfd);    
  462.  
  463.     err = OTBind(endpoint, &bindReq, NULL);
  464.     if (err != kOTNoError)
  465.         goto ErrorExit;
  466.  
  467.     WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT);
  468.  
  469.     err = me->md.osErrCode;
  470.     if (err != kOTNoError)
  471.         goto ErrorExit;
  472.  
  473.     PR_ASSERT(me->md.cookie == NULL);
  474.  
  475.     return kOTNoError;
  476.  
  477. ErrorExit:
  478.     macsock_map_error(err);
  479.     return -1;
  480. #endif
  481.  
  482. #pragma unused (fd, backlog)    
  483.     return kOTNoError;
  484.  
  485. }
  486.  
  487. // Errors:
  488. // EBADF -- bad socket id
  489. PRInt32 _MD_getsockname(PRFileDesc *fd, PRNetAddr *addr, PRUint32 *addrlen)
  490. {
  491.     PRInt32 osfd = fd->secret->md.osfd;
  492.     OSStatus err;
  493.     EndpointRef endpoint = (EndpointRef) osfd;
  494.     TBind bindReq;
  495.     PRThread *me = _PR_MD_CURRENT_THREAD();
  496.  
  497.     if (endpoint == NULL) {
  498.         err = kEBADFErr;
  499.         goto ErrorExit;
  500.     }
  501.         
  502.     if (addr == NULL) {
  503.         err = kEFAULTErr;
  504.         goto ErrorExit;
  505.     }
  506.  
  507. #if !defined(_PR_INET6)        
  508.     addr->inet.family = AF_INET;
  509. #endif
  510.     
  511.     PR_ASSERT(PR_NETADDR_SIZE(addr) >= (*addrlen));
  512.  
  513.     bindReq.addr.len = *addrlen;
  514.     bindReq.addr.maxlen = *addrlen;
  515.     bindReq.addr.buf = (UInt8*) addr;
  516.     bindReq.qlen = 0;
  517.     
  518.     PrepareThreadForAsyncIO(me, endpoint, osfd);    
  519.  
  520.     err = OTGetProtAddress(endpoint, &bindReq, NULL);
  521.     if (err != kOTNoError)
  522.         goto ErrorExit;
  523.  
  524.     WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT);
  525.  
  526.     err = me->md.osErrCode;
  527.     if (err != kOTNoError)
  528.         goto ErrorExit;
  529.  
  530.     PR_ASSERT(me->md.cookie == &bindReq);
  531.  
  532.     return kOTNoError;
  533.  
  534. ErrorExit:
  535.     macsock_map_error(err);
  536.     return -1;
  537. }
  538.  
  539. PRStatus _MD_getsockopt(PRFileDesc *fd, PRInt32 level, PRInt32 optname, char* optval, PRInt32* optlen)
  540. {
  541.     OSStatus err;
  542.     PRInt32 osfd = fd->secret->md.osfd;
  543.     EndpointRef endpoint = (EndpointRef) osfd;
  544.     TOptMgmt cmd;
  545.     TOption *opt;
  546.     PRThread *me = _PR_MD_CURRENT_THREAD();
  547.     unsigned char optionBuffer[kOTOptionHeaderSize + sizeof(PRSocketOptionData)];
  548.     
  549.     if (endpoint == NULL) {
  550.         err = kEBADFErr;
  551.         goto ErrorExit;
  552.     }
  553.     
  554.     /* 
  555.     OT wants IPPROTO_IP for level and not XTI_GENERIC.  SO_REUSEADDR and SO_KEEPALIVE 
  556.     are equated to IP level and TCP level options respectively and hence we need to set 
  557.     the level correctly.
  558.     */
  559.     if (level == SOL_SOCKET) {
  560.         if (optname == SO_REUSEADDR)
  561.             level = IPPROTO_IP;
  562.         else if (optname == SO_KEEPALIVE)
  563.             level = INET_TCP;
  564.     }
  565.  
  566.     opt = (TOption *)&optionBuffer[0];
  567.     opt->len = sizeof(TOption);
  568.     opt->level = level;
  569.     opt->name = optname;
  570.     opt->status = 0;
  571.     
  572.     cmd.opt.len = sizeof(TOption);
  573.     cmd.opt.maxlen = sizeof(optionBuffer);
  574.     cmd.opt.buf = (UInt8*)optionBuffer;
  575.     cmd.flags = T_CURRENT;
  576.  
  577.     PrepareThreadForAsyncIO(me, endpoint, osfd);    
  578.  
  579.     err = OTOptionManagement(endpoint, &cmd, &cmd);
  580.     if (err != kOTNoError)
  581.         goto ErrorExit;
  582.  
  583.     WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT);
  584.  
  585.     err = me->md.osErrCode;
  586.     if (err != kOTNoError)
  587.         goto ErrorExit;
  588.  
  589.     if (opt->status == T_FAILURE || opt->status == T_NOTSUPPORT){
  590.         err = kEOPNOTSUPPErr;
  591.         goto ErrorExit;
  592.     }
  593.  
  594.     PR_ASSERT(opt->status == T_SUCCESS);
  595.  
  596.     switch (optname) {
  597.         case SO_LINGER:
  598.             *((t_linger*)optval) = *((t_linger*)&opt->value);
  599.             *optlen = sizeof(t_linger);
  600.             break;
  601.         case SO_REUSEADDR:
  602.         case TCP_NODELAY:
  603.         case SO_KEEPALIVE:
  604.         case SO_RCVBUF:
  605.         case SO_SNDBUF:
  606.             *((PRIntn*)optval) = *((PRIntn*)&opt->value);
  607.             *optlen = sizeof(PRIntn);
  608.             break;
  609.         case IP_MULTICAST_LOOP:
  610.             *((PRUint8*)optval) = *((PRIntn*)&opt->value);
  611.             *optlen = sizeof(PRUint8);
  612.             break;
  613.         case IP_TTL:
  614.             *((PRUintn*)optval) = *((PRUint8*)&opt->value);
  615.             *optlen = sizeof(PRUintn);
  616.             break;
  617.         case IP_MULTICAST_TTL:
  618.             *((PRUint8*)optval) = *((PRUint8*)&opt->value);
  619.             *optlen = sizeof(PRUint8);
  620.             break;
  621.         case IP_ADD_MEMBERSHIP:
  622.         case IP_DROP_MEMBERSHIP:
  623.             {
  624.             /* struct ip_mreq and TIPAddMulticast are the same size and optval 
  625.                is pointing to struct ip_mreq */
  626.             *((struct ip_mreq *)optval) = *((struct ip_mreq *)&opt->value);
  627.             *optlen = sizeof(struct ip_mreq);
  628.             break;
  629.             }
  630.         case IP_MULTICAST_IF:
  631.             {
  632.             *((PRUint32*)optval) = *((PRUint32*)&opt->value);
  633.             *optlen = sizeof(PRUint32);
  634.             break;
  635.             }
  636.         /*case IP_TOS:*/ /*IP_TOS has same value as TCP_MAXSEG */
  637.         case TCP_MAXSEG:
  638.             if (level == IPPROTO_TCP) { /* it is TCP_MAXSEG */
  639.                 *((PRIntn*)optval) = *((PRIntn*)&opt->value);
  640.                 *optlen = sizeof(PRIntn);
  641.             } else { /* it is IP_TOS */
  642.                 *((PRUintn*)optval) = *((PRUint8*)&opt->value);
  643.                 *optlen = sizeof(PRUintn);
  644.             }
  645.             break;
  646.         default:
  647.             PR_ASSERT(0);
  648.             break;    
  649.     }
  650.     
  651.     return PR_SUCCESS;
  652.  
  653. ErrorExit:
  654.     macsock_map_error(err);
  655.     return PR_FAILURE;
  656. }
  657.  
  658. PRStatus _MD_setsockopt(PRFileDesc *fd, PRInt32 level, PRInt32 optname, const char* optval, PRInt32 optlen)
  659. {
  660.     OSStatus err;
  661.     PRInt32 osfd = fd->secret->md.osfd;
  662.     EndpointRef endpoint = (EndpointRef) osfd;
  663.     TOptMgmt cmd;
  664.     TOption *opt;
  665.     PRThread *me = _PR_MD_CURRENT_THREAD();
  666.     unsigned char optionBuffer[kOTOptionHeaderSize + sizeof(PRSocketOptionData) + 1];
  667.     
  668.     if (endpoint == NULL) {
  669.         err = kEBADFErr;
  670.         goto ErrorExit;
  671.     }
  672.     
  673.     /* 
  674.     OT wants IPPROTO_IP for level and not XTI_GENERIC.  SO_REUSEADDR and SO_KEEPALIVE 
  675.     are equated to IP level and TCP level options respectively and hence we need to set 
  676.     the level correctly.
  677.     */
  678.     if (level == SOL_SOCKET) {
  679.         if (optname == SO_REUSEADDR)
  680.             level = IPPROTO_IP;
  681.         else if (optname == SO_KEEPALIVE)
  682.             level = INET_TCP;
  683.     }
  684.  
  685.     opt = (TOption *)&optionBuffer[0];
  686.     opt->len = kOTOptionHeaderSize + optlen;
  687.  
  688.     /* special case adjustments for length follow */
  689.     if (optname == SO_KEEPALIVE) /* we need to pass the timeout value for OT */
  690.         opt->len = kOTOptionHeaderSize + sizeof(t_kpalive);
  691.     if (optname == IP_MULTICAST_TTL || optname == IP_TTL) /* it is an unsigned char value */
  692.         opt->len = kOTOneByteOptionSize;
  693.     if (optname == IP_TOS && level == IPPROTO_IP)
  694.         opt->len = kOTOneByteOptionSize;
  695.  
  696.     opt->level = level;
  697.     opt->name = optname;
  698.     opt->status = 0;
  699.     
  700.     cmd.opt.len = opt->len;
  701.     cmd.opt.maxlen = sizeof(optionBuffer);
  702.     cmd.opt.buf = (UInt8*)optionBuffer;
  703.     
  704.     optionBuffer[opt->len] = 0;
  705.     
  706.     cmd.flags = T_NEGOTIATE;
  707.  
  708.     switch (optname) {
  709.         case SO_LINGER:
  710.             *((t_linger*)&opt->value) = *((t_linger*)optval);
  711.             break;
  712.         case SO_REUSEADDR:
  713.         case TCP_NODELAY:
  714.         case SO_RCVBUF:
  715.         case SO_SNDBUF:
  716.             *((PRIntn*)&opt->value) = *((PRIntn*)optval);
  717.             break;
  718.         case IP_MULTICAST_LOOP:
  719.             if (*optval != 0)
  720.                 opt->value[0] = T_YES;
  721.             else
  722.                 opt->value[0] = T_NO;
  723.             break;
  724.         case SO_KEEPALIVE:
  725.             {
  726.             t_kpalive *kpalive = (t_kpalive *)&opt->value;
  727.             
  728.             kpalive->kp_onoff = *((long*)optval);
  729.             kpalive->kp_timeout = 10; /* timeout in minutes */
  730.             break;
  731.             }
  732.         case IP_TTL:
  733.             *((unsigned char*)&opt->value) = *((PRUintn*)optval);
  734.             break;
  735.         case IP_MULTICAST_TTL:
  736.             *((unsigned char*)&opt->value) = *optval;
  737.             break;
  738.         case IP_ADD_MEMBERSHIP:
  739.         case IP_DROP_MEMBERSHIP:
  740.             {
  741.             /* struct ip_mreq and TIPAddMulticast are the same size and optval 
  742.                is pointing to struct ip_mreq */
  743.             *((TIPAddMulticast *)&opt->value) = *((TIPAddMulticast *)optval);
  744.             break;
  745.             }
  746.         case IP_MULTICAST_IF:
  747.             {
  748.             *((PRUint32*)&opt->value) = *((PRUint32*)optval);
  749.             break;
  750.             }
  751.         /*case IP_TOS:*/ /*IP_TOS has same value as TCP_MAXSEG */
  752.         case TCP_MAXSEG:
  753.             if (level == IPPROTO_TCP) { /* it is TCP_MAXSEG */
  754.                 *((PRIntn*)&opt->value) = *((PRIntn*)optval);
  755.             } else { /* it is IP_TOS */
  756.                 *((unsigned char*)&opt->value) = *((PRUintn*)optval);
  757.             }
  758.             break;
  759.         default:
  760.             PR_ASSERT(0);
  761.             break;    
  762.     }
  763.     
  764.     PrepareThreadForAsyncIO(me, endpoint, osfd);    
  765.  
  766.     err = OTOptionManagement(endpoint, &cmd, &cmd);
  767.     if (err != kOTNoError)
  768.         goto ErrorExit;
  769.  
  770.     WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT);
  771.  
  772.     err = me->md.osErrCode;
  773.     if (err != kOTNoError)
  774.         goto ErrorExit;
  775.  
  776.     if (opt->status == T_FAILURE || opt->status == T_NOTSUPPORT){
  777.         err = kEOPNOTSUPPErr;
  778.         goto ErrorExit;
  779.     }
  780.     
  781.     if (level == IPPROTO_TCP && optname == TCP_MAXSEG && opt->status == T_READONLY) {
  782.         err = kEOPNOTSUPPErr;
  783.         goto ErrorExit;
  784.     }
  785.  
  786.     PR_ASSERT(opt->status == T_SUCCESS);
  787.  
  788.     return PR_SUCCESS;
  789.  
  790. ErrorExit:
  791.     macsock_map_error(err);
  792.     return PR_FAILURE;
  793. }
  794.  
  795. PRInt32 _MD_socketavailable(PRFileDesc *fd)
  796. {
  797.     PRInt32 osfd = fd->secret->md.osfd;
  798.     OSStatus err;
  799.     EndpointRef endpoint = (EndpointRef) osfd;
  800.     size_t bytes;
  801.  
  802.     if (endpoint == NULL) {
  803.         err = kEBADFErr;
  804.         goto ErrorExit;
  805.     }
  806.     
  807.     bytes = 0;
  808.     
  809.     err = OTCountDataBytes(endpoint, &bytes);
  810.     if ((err == kOTLookErr) ||         // Not really errors, we just need to do a read,
  811.         (err == kOTNoDataErr))        // or there╒s nothing there.
  812.         err = kOTNoError;
  813.         
  814.     if (err != kOTNoError)
  815.         goto ErrorExit;
  816.         
  817.     return bytes;
  818.  
  819. ErrorExit:
  820.     macsock_map_error(err);
  821.     return -1;
  822. }
  823.  
  824. PRInt32 _MD_accept(PRFileDesc *fd, PRNetAddr *addr, PRUint32 *addrlen, PRIntervalTime timeout)
  825. {
  826.     PRInt32 osfd = fd->secret->md.osfd;
  827.     OSStatus err;
  828.     EndpointRef endpoint = (EndpointRef) osfd;
  829.     PRThread *me = _PR_MD_CURRENT_THREAD();
  830.     TBind bindReq;
  831.     PRNetAddr bindAddr;
  832.     PRInt32 newosfd = -1;
  833.     EndpointRef newEndpoint;
  834.     TCall call;
  835.     PRNetAddr callAddr;
  836.  
  837.     if (endpoint == NULL) {
  838.         err = kEBADFErr;
  839.         goto ErrorExit;
  840.     }
  841.         
  842.     memset(&call, 0 , sizeof(call));
  843.  
  844.     call.addr.maxlen = PR_NETADDR_SIZE(&callAddr);
  845.     call.addr.len = PR_NETADDR_SIZE(&callAddr);
  846.     call.addr.buf = (UInt8*) &callAddr;
  847.     
  848.     PrepareThreadForAsyncIO(me, endpoint, osfd);    
  849.  
  850.     err = OTListen (endpoint, &call);
  851.     if (err != kOTNoError && (err != kOTNoDataErr || fd->secret->nonblocking)) {
  852.         me->io_pending = PR_FALSE;
  853.         goto ErrorExit;
  854.     }
  855.  
  856.     while (err == kOTNoDataErr) {
  857.         WaitOnThisThread(me, timeout);
  858.         err = me->md.osErrCode;
  859.         if (err != kOTNoError)
  860.             goto ErrorExit;
  861.  
  862.         PrepareThreadForAsyncIO(me, endpoint, osfd);    
  863.  
  864.         err = OTListen (endpoint, &call);
  865.         if (err == kOTNoError)
  866.             break;
  867.  
  868.         PR_ASSERT(err == kOTNoDataErr);
  869.     }        
  870.  
  871.     newosfd = _MD_socket(AF_INET, SOCK_STREAM, 0);
  872.     if (newosfd == -1)
  873.         return -1;
  874.  
  875.     newEndpoint = (EndpointRef)newosfd;
  876.     
  877.     // Bind to a local port; let the system assign it.
  878.  
  879.     bindAddr.inet.port = bindAddr.inet.ip = 0;
  880.  
  881.     bindReq.addr.maxlen = PR_NETADDR_SIZE (&bindAddr);
  882.     bindReq.addr.len = 0;
  883.     bindReq.addr.buf = (UInt8*) &bindAddr;
  884.     bindReq.qlen = 0;
  885.     
  886.     PrepareThreadForAsyncIO(me, newEndpoint, newosfd);    
  887.  
  888.     err = OTBind(newEndpoint, &bindReq, NULL);
  889.     if (err != kOTNoError)
  890.         goto ErrorExit;
  891.  
  892.     WaitOnThisThread(me, timeout);
  893.  
  894.     err = me->md.osErrCode;
  895.     if (err != kOTNoError)
  896.         goto ErrorExit;
  897.  
  898.     PrepareThreadForAsyncIO(me, endpoint, newosfd);    
  899.  
  900.     err = OTAccept (endpoint, newEndpoint, &call);
  901.     if (err != kOTNoError)
  902.         goto ErrorExit;
  903.  
  904.     WaitOnThisThread(me, timeout);
  905.  
  906.     err = me->md.osErrCode;
  907.     if (err != kOTNoError)
  908.         goto ErrorExit;
  909.  
  910.     PR_ASSERT(me->md.cookie != NULL);
  911.  
  912.     if (addr != NULL)
  913.         *addr = callAddr;
  914.     if (addrlen != NULL)
  915.         *addrlen = call.addr.len;
  916.  
  917.     return newosfd;
  918.  
  919. ErrorExit:
  920.     if (newosfd != -1)
  921.         _MD_closesocket(newosfd);
  922.     macsock_map_error(err);
  923.     return -1;
  924. }
  925.  
  926. PRInt32 _MD_connect(PRFileDesc *fd, PRNetAddr *addr, PRUint32 addrlen, PRIntervalTime timeout)
  927. {
  928.     PRInt32 osfd = fd->secret->md.osfd;
  929.     OSStatus err;
  930.     EndpointRef endpoint = (EndpointRef) osfd;
  931.     PRThread *me = _PR_MD_CURRENT_THREAD();
  932.     TCall sndCall;
  933.     TBind bindReq;
  934.     PRNetAddr bindAddr;
  935.  
  936.     if (endpoint == NULL) {
  937.         err = kEBADFErr;
  938.         goto ErrorExit;
  939.     }
  940.         
  941.     if (addr == NULL) {
  942.         err = kEFAULTErr;
  943.         goto ErrorExit;
  944.     }
  945.         
  946.     // Bind to a local port; let the system assign it.
  947.  
  948.     bindAddr.inet.port = bindAddr.inet.ip = 0;
  949.  
  950.     bindReq.addr.maxlen = PR_NETADDR_SIZE (&bindAddr);
  951.     bindReq.addr.len = 0;
  952.     bindReq.addr.buf = (UInt8*) &bindAddr;
  953.     bindReq.qlen = 0;
  954.     
  955.     PrepareThreadForAsyncIO(me, endpoint, osfd);    
  956.  
  957.     err = OTBind(endpoint, &bindReq, NULL);
  958.     if (err != kOTNoError)
  959.         goto ErrorExit;
  960.  
  961.     WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT);
  962.  
  963.     err = me->md.osErrCode;
  964.     if (err != kOTNoError)
  965.         goto ErrorExit;
  966.  
  967.     memset(&sndCall, 0 , sizeof(sndCall));
  968.  
  969.     sndCall.addr.maxlen = addrlen;
  970.     sndCall.addr.len = addrlen;
  971.     sndCall.addr.buf = (UInt8*) addr;
  972.     
  973.     PrepareThreadForAsyncIO(me, endpoint, osfd);    
  974.  
  975.     err = OTConnect (endpoint, &sndCall, NULL);
  976.     if (err != kOTNoError && err != kOTNoDataErr)
  977.         goto ErrorExit;
  978.     if (err == kOTNoDataErr && fd->secret->nonblocking) {
  979.         err = kEINPROGRESSErr;
  980.         me->io_pending = PR_FALSE;
  981.         goto ErrorExit;
  982.     }
  983.  
  984.     WaitOnThisThread(me, timeout);
  985.  
  986.     err = me->md.osErrCode;
  987.     if (err != kOTNoError)
  988.         goto ErrorExit;
  989.  
  990.     PR_ASSERT(me->md.cookie != NULL);
  991.  
  992.     err = OTRcvConnect(endpoint, NULL);
  993.     PR_ASSERT(err == kOTNoError);
  994.  
  995.     return kOTNoError;
  996.  
  997. ErrorExit:
  998.     macsock_map_error(err);
  999.     return -1;
  1000. }
  1001.  
  1002. // Errors:
  1003. // EBADF -- bad socket id
  1004. // EFAULT -- bad buffer
  1005. static PRInt32 SendReceiveStream(PRFileDesc *fd, void *buf, PRInt32 amount, 
  1006.                                PRIntn flags, PRIntervalTime timeout, SndRcvOpCode opCode)
  1007. {
  1008.     OSStatus err;
  1009.     OTResult result;
  1010.     PRInt32 osfd = fd->secret->md.osfd;
  1011.     EndpointRef endpoint = (EndpointRef) osfd;
  1012.     PRThread *me = _PR_MD_CURRENT_THREAD();
  1013.     PRInt32 bytesLeft = amount;
  1014.  
  1015.     PR_ASSERT(flags == 0);
  1016.     
  1017.     if (endpoint == NULL) {
  1018.         err = kEBADFErr;
  1019.         goto ErrorExit;
  1020.     }
  1021.         
  1022.     if (buf == NULL) {
  1023.         err = kEFAULTErr;
  1024.         goto ErrorExit;
  1025.     }
  1026.         
  1027.     while (bytesLeft > 0) {
  1028.     
  1029.         PrepareThreadForAsyncIO(me, endpoint, osfd);    
  1030.  
  1031.         if (opCode == kSTREAM_SEND)
  1032.             result = OTSnd(endpoint, buf, bytesLeft, NULL);
  1033.         else if (opCode == kSTREAM_RECEIVE)
  1034.             result = OTRcv(endpoint, buf, bytesLeft, NULL);
  1035.         else {
  1036.             err = kEINVALErr;
  1037.             goto ErrorExit;
  1038.         }
  1039.  
  1040.         if (result > 0) {
  1041.             buf = (void *) ( (UInt32) buf + (UInt32)result );
  1042.             bytesLeft -= result;
  1043.             me->io_pending = PR_FALSE;
  1044.             if (opCode == kSTREAM_RECEIVE)
  1045.                 return result;
  1046.         } else {
  1047.             if (result == kOTOutStateErr) { /* it has been closed */
  1048.                 return 0;
  1049.             }
  1050.             if (result == kOTLookErr) {
  1051.                 PRBool readReady,writeReady,exceptReady;
  1052.                 /* process the event and then continue the operation */
  1053.                 (void) GetState(endpoint, &readReady, &writeReady, &exceptReady);
  1054.                 continue;
  1055.             }
  1056.             if (result != kOTNoDataErr && result != kOTFlowErr && 
  1057.                 result != kEAGAINErr && result != kEWOULDBLOCKErr) {
  1058.                 err = result;
  1059.                 goto ErrorExit;
  1060.             } else if (fd->secret->nonblocking) {
  1061.                 me->io_pending = PR_FALSE;
  1062.                 err = result;
  1063.                 goto ErrorExit;
  1064.             }
  1065.             WaitOnThisThread(me, timeout);
  1066.             err = me->md.osErrCode;
  1067.             if (err != kOTNoError)
  1068.                 goto ErrorExit;
  1069.  
  1070.             PR_ASSERT(me->md.cookie != NULL);
  1071.         }
  1072.     }
  1073.  
  1074.     return amount;
  1075.  
  1076. ErrorExit:
  1077.     macsock_map_error(err);
  1078.     return -1;
  1079. }                               
  1080.  
  1081. PRInt32 _MD_recv(PRFileDesc *fd, void *buf, PRInt32 amount, 
  1082.                                PRIntn flags, PRIntervalTime timeout)
  1083. {
  1084.     return (SendReceiveStream(fd, buf, amount, flags, timeout, kSTREAM_RECEIVE));
  1085. }                               
  1086.  
  1087. PRInt32 _MD_send(PRFileDesc *fd,const void *buf, PRInt32 amount, 
  1088.                                PRIntn flags, PRIntervalTime timeout)
  1089. {
  1090.     return (SendReceiveStream(fd, (void *)buf, amount, flags, timeout, kSTREAM_SEND));
  1091. }                               
  1092.  
  1093.  
  1094. // Errors:
  1095. // EBADF -- bad socket id
  1096. // EFAULT -- bad buffer
  1097. static PRInt32 SendReceiveDgram(PRFileDesc *fd, void *buf, PRInt32 amount, 
  1098.                                PRIntn flags, PRNetAddr *addr, PRUint32 *addrlen, 
  1099.                                PRIntervalTime timeout, SndRcvOpCode opCode)
  1100. {
  1101.     OSStatus err;
  1102.     PRInt32 osfd = fd->secret->md.osfd;
  1103.     EndpointRef endpoint = (EndpointRef) osfd;
  1104.     PRThread *me = _PR_MD_CURRENT_THREAD();
  1105.     PRInt32 bytesLeft = amount;
  1106.     TUnitData dgram;
  1107.  
  1108.     PR_ASSERT(flags == 0);
  1109.     
  1110.     if (endpoint == NULL) {
  1111.         err = kEBADFErr;
  1112.         goto ErrorExit;
  1113.     }
  1114.         
  1115.     if (buf == NULL || addr == NULL) {
  1116.         err = kEFAULTErr;
  1117.         goto ErrorExit;
  1118.     }
  1119.         
  1120.     memset(&dgram, 0 , sizeof(dgram));
  1121.     dgram.addr.maxlen = *addrlen;
  1122.     dgram.addr.len = *addrlen;
  1123.     dgram.addr.buf = (UInt8*) addr;
  1124.     dgram.udata.maxlen = amount;
  1125.     dgram.udata.len = amount;
  1126.     dgram.udata.buf = (UInt8*) buf;    
  1127.  
  1128.     while (bytesLeft > 0) {
  1129.     
  1130.         PrepareThreadForAsyncIO(me, endpoint, osfd);    
  1131.  
  1132.         if (opCode == kDGRAM_SEND)
  1133.             err = OTSndUData(endpoint, &dgram);
  1134.         else if (opCode == kDGRAM_RECEIVE)
  1135.             err = OTRcvUData(endpoint, &dgram, NULL);
  1136.         else {
  1137.             err = kEINVALErr;
  1138.             goto ErrorExit;
  1139.         }
  1140.  
  1141.         if (err == kOTNoError) {
  1142.             buf = (void *) ( (UInt32) buf + (UInt32)dgram.udata.len );
  1143.             bytesLeft -= dgram.udata.len;
  1144.             dgram.udata.buf = (UInt8*) buf;    
  1145.             me->io_pending = PR_FALSE;
  1146.         }
  1147.         else {
  1148.             PR_ASSERT(err == kOTNoDataErr || err == kOTOutStateErr);
  1149.             WaitOnThisThread(me, timeout);
  1150.             err = me->md.osErrCode;
  1151.             if (err != kOTNoError)
  1152.                 goto ErrorExit;
  1153.  
  1154.             PR_ASSERT(me->md.cookie != NULL);
  1155.         }
  1156.     }
  1157.  
  1158.     if (opCode == kDGRAM_RECEIVE)
  1159.         *addrlen = dgram.addr.len;
  1160.  
  1161.     return amount;
  1162.  
  1163. ErrorExit:
  1164.     macsock_map_error(err);
  1165.     return -1;
  1166. }                               
  1167.  
  1168. PRInt32 _MD_recvfrom(PRFileDesc *fd, void *buf, PRInt32 amount, 
  1169.                                PRIntn flags, PRNetAddr *addr, PRUint32 *addrlen,
  1170.                                PRIntervalTime timeout)
  1171. {
  1172.     return (SendReceiveDgram(fd, buf, amount, flags, addr, addrlen,
  1173.                             timeout, kDGRAM_RECEIVE));
  1174. }                               
  1175.  
  1176. PRInt32 _MD_sendto(PRFileDesc *fd,const void *buf, PRInt32 amount, 
  1177.                                PRIntn flags, PRNetAddr *addr, PRUint32 addrlen,
  1178.                                PRIntervalTime timeout)
  1179. {
  1180.     return (SendReceiveDgram(fd, (void *)buf, amount, flags, addr, &addrlen,
  1181.                             timeout, kDGRAM_SEND));
  1182. }                               
  1183.  
  1184. PRInt32 _MD_closesocket(PRInt32 osfd)
  1185. {
  1186.     OSStatus err;
  1187.     EndpointRef endpoint = (EndpointRef) osfd;
  1188.     PRThread *me = _PR_MD_CURRENT_THREAD();
  1189.  
  1190.     if (endpoint == NULL) {
  1191.         err = kEBADFErr;
  1192.         goto ErrorExit;
  1193.     }
  1194.         
  1195.     if (me->io_pending && me->io_fd == osfd)
  1196.         me->io_pending = PR_FALSE;
  1197.  
  1198. #if 0
  1199.     {
  1200.     OTResult state;
  1201.     state = OTGetEndpointState(endpoint);
  1202.     
  1203.     err = OTSndOrderlyDisconnect(endpoint);
  1204.     if (err != kOTNoError && err != kOTOutStateErr)
  1205.         goto ErrorExit;
  1206.  
  1207.     state = OTGetEndpointState(endpoint);
  1208.     
  1209.     err = OTUnbind(endpoint);
  1210.     if (err != kOTNoError && err != kOTOutStateErr)
  1211.         goto ErrorExit;
  1212.  
  1213.     state = OTGetEndpointState(endpoint);
  1214.  
  1215.     err = OTSetSynchronous(endpoint);
  1216.     if (err != kOTNoError)
  1217.         goto ErrorExit;
  1218.  
  1219.     err = OTSetBlocking(endpoint);
  1220.     if (err != kOTNoError)
  1221.         goto ErrorExit;
  1222.     }
  1223. #endif
  1224.  
  1225.     (void) OTSndOrderlyDisconnect(endpoint);
  1226.  
  1227.     err = OTCloseProvider(endpoint);
  1228.     if (err != kOTNoError)
  1229.         goto ErrorExit;
  1230.  
  1231.     return kOTNoError;
  1232.  
  1233. ErrorExit:
  1234.     macsock_map_error(err);
  1235.     return -1;
  1236. }                               
  1237.  
  1238. PRInt32 _MD_writev(PRFileDesc *fd, struct PRIOVec *iov, PRInt32 iov_size, PRIntervalTime timeout)
  1239. {
  1240. #pragma unused (fd, iov, iov_size, timeout)
  1241.  
  1242.     PR_ASSERT(0);
  1243.     _PR_MD_CURRENT_THREAD()->md.osErrCode = unimpErr;
  1244.     return -1;
  1245. }                               
  1246.  
  1247. static PRBool GetState(EndpointRef endpoint, PRBool *readReady, PRBool *writeReady, PRBool *exceptReady)
  1248. {
  1249.     OSStatus err;
  1250.     OTResult resultOT;
  1251.     TDiscon discon;
  1252.     PRBool result = PR_FALSE;
  1253.     
  1254.     *readReady = *writeReady = *exceptReady = PR_FALSE;
  1255.  
  1256.     resultOT = OTLook(endpoint);
  1257.     switch (resultOT) {
  1258.         case T_DATA:
  1259.         case T_LISTEN:
  1260.             *readReady = PR_TRUE;
  1261.             break;
  1262.         case T_CONNECT:
  1263.             err = OTRcvConnect(endpoint, NULL);
  1264.             PR_ASSERT(err == kOTNoError);
  1265.             break;        
  1266.         case T_DISCONNECT:
  1267.             memset(&discon, 0 , sizeof(discon));
  1268.             err = OTRcvDisconnect(endpoint, &discon);
  1269.             PR_ASSERT(err == kOTNoError);
  1270.             macsock_map_error(discon.reason);
  1271.             *exceptReady = PR_TRUE;
  1272.             break;        
  1273.         case T_ORDREL:
  1274.             *readReady = PR_TRUE;
  1275.             err = OTRcvOrderlyDisconnect(endpoint);
  1276.             PR_ASSERT(err == kOTNoError);
  1277.             break;
  1278.     }
  1279.     resultOT = OTGetEndpointState(endpoint);
  1280.     switch (resultOT)    {
  1281.         case T_DATAXFER:
  1282.         case T_INREL:
  1283.             *writeReady = PR_TRUE;
  1284.             break;
  1285.         default:
  1286.             *writeReady = PR_FALSE;
  1287.     }
  1288.     
  1289.     if ((*readReady == PR_TRUE) || (*writeReady==PR_TRUE) || (*exceptReady==PR_TRUE))
  1290.         result = PR_TRUE;
  1291.  
  1292.     return result;
  1293. }
  1294.  
  1295. PRInt32 _MD_poll(PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout)
  1296. {
  1297.     PRPollDesc *pd, *epd;
  1298.     PRInt32 n = 0;
  1299.     PRThread *me = _PR_MD_CURRENT_THREAD();
  1300.     PRIntervalTime sleepTime;
  1301.     PRIntervalTime timein = PR_IntervalNow();
  1302.     
  1303.     sleepTime = PR_MillisecondsToInterval(5UL);
  1304.     if (sleepTime > timeout)
  1305.         sleepTime = timeout;
  1306.  
  1307.     do {
  1308.  
  1309.     for (pd = pds, epd = pd + npds; pd < epd; pd++) {
  1310.         PRInt32 osfd;
  1311.         PRInt16 in_flags = pd->in_flags;
  1312.         PRFileDesc *bottom = pd->fd;
  1313.         EndpointRef endpoint;
  1314.         PRInt16 out_flags = 0;
  1315.         PRBool readReady, writeReady, exceptReady;
  1316.  
  1317.         pd->out_flags = 0;
  1318.         if (NULL == bottom || in_flags == 0) {
  1319.             continue;
  1320.         }
  1321.         while (bottom->lower != NULL) {
  1322.             bottom = bottom->lower;
  1323.         }
  1324.         osfd = bottom->secret->md.osfd;
  1325.         endpoint = (EndpointRef) osfd;
  1326.  
  1327.         if (GetState(endpoint, &readReady, &writeReady, &exceptReady)) {
  1328.         
  1329.             if ((in_flags & PR_POLL_READ) && (readReady))  {
  1330.                 out_flags |= PR_POLL_READ;
  1331.             }
  1332.             if ((in_flags & PR_POLL_WRITE) && (writeReady)) {
  1333.                 out_flags |= PR_POLL_WRITE;
  1334.             }
  1335.             if ((in_flags & PR_POLL_EXCEPT) && (exceptReady)) {
  1336.                 out_flags |= PR_POLL_EXCEPT;
  1337.             }
  1338.             pd->out_flags = out_flags;
  1339.             if (out_flags) {
  1340.                 n++;
  1341.             }
  1342.         }
  1343.     }
  1344.  
  1345.     if (n > 0)
  1346.         return n;
  1347.  
  1348.     (void) PR_Sleep(sleepTime);
  1349.  
  1350.     } while ((timeout == PR_INTERVAL_NO_TIMEOUT) ||
  1351.            (((PRIntervalTime)(PR_IntervalNow() - timein)) < timeout));
  1352.  
  1353.     return 0; /* timed out */
  1354. }
  1355.  
  1356. void _MD_makenonblock(PRFileDesc *fd)
  1357. {
  1358.     OSStatus err;
  1359.     PRInt32 osfd = fd->secret->md.osfd;
  1360.     EndpointRef endpoint = (EndpointRef) osfd;
  1361.  
  1362.     err = OTSetNonBlocking(endpoint);
  1363.     PR_ASSERT(err == kOTNoError || err == kOTOutStateErr);
  1364. }
  1365.  
  1366. PR_IMPLEMENT(PRInt32) _MD_shutdown(PRFileDesc *fd, PRIntn how)
  1367. {
  1368. #pragma unused (fd, how)
  1369.  
  1370. /* Just succeed silently!!! */
  1371. return (0);
  1372. }                               
  1373.  
  1374. PR_IMPLEMENT(PRStatus) _MD_getpeername(PRFileDesc *fd, PRNetAddr *addr, PRUint32 *addrlen)
  1375. {
  1376. #pragma unused (fd, addr, addrlen)
  1377.  
  1378.     PR_ASSERT(0);
  1379.     _PR_MD_CURRENT_THREAD()->md.osErrCode = unimpErr;
  1380.     return PR_FAILURE;
  1381. }                               
  1382.  
  1383.  
  1384. PR_IMPLEMENT(unsigned long) inet_addr(const char *cp)
  1385. {
  1386.     OSStatus err;
  1387.     InetHost host;    
  1388.  
  1389.     err = OTInetStringToHost((char*) cp, &host);
  1390.     PR_ASSERT(err == kOTNoError);
  1391.     
  1392.     return host;
  1393. }
  1394.  
  1395.  
  1396. static char *sAliases[1] = {NULL};
  1397. static struct hostent sHostEnt = {NULL, &sAliases[0], AF_INET, sizeof (long), NULL};
  1398. static InetHostInfo sHostInfo;
  1399. static InetHost *sAddresses[kMaxHostAddrs+1];
  1400.  
  1401. PR_IMPLEMENT(struct hostent *) gethostbyname(const char * name)
  1402. {
  1403.     OSStatus err;
  1404.     PRUint32 index;
  1405.     PRThread *me = _PR_MD_CURRENT_THREAD();
  1406.  
  1407.     PrepareThreadForAsyncIO(me, sSvcRef, NULL);    
  1408.  
  1409.     err = OTInetStringToAddress(sSvcRef, (char *)name, &sHostInfo);
  1410.     if (err != kOTNoError)
  1411.         goto ErrorExit;
  1412.  
  1413.     WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT);
  1414.  
  1415.     err = me->md.osErrCode;
  1416.     if (err != kOTNoError)
  1417.         goto ErrorExit;
  1418.  
  1419.     sHostEnt.h_name = sHostInfo.name;
  1420.     for (index=0; index<kMaxHostAddrs && sHostInfo.addrs[index] != NULL; index++)
  1421.         sAddresses[index] = &sHostInfo.addrs[index];
  1422.     sAddresses[index] = NULL;    
  1423.     sHostEnt.h_addr_list = (char **)sAddresses;
  1424.  
  1425.     return (&sHostEnt);
  1426.  
  1427. ErrorExit:
  1428.     macsock_map_error(err);
  1429.     return NULL;
  1430. }
  1431.  
  1432.  
  1433. PR_IMPLEMENT(struct hostent *) gethostbyaddr(const void *addr, int addrlen, int type)
  1434. {
  1435.     PR_ASSERT(type == AF_INET);
  1436.     PR_ASSERT(addrlen == sizeof(struct in_addr));
  1437.  
  1438.     OTInetHostToString((InetHost)addr, sHostInfo.name);
  1439.     
  1440.     return (gethostbyname(sHostInfo.name));
  1441. }
  1442.  
  1443.  
  1444. PR_IMPLEMENT(char *) inet_ntoa(struct in_addr addr)
  1445. {
  1446.     OTInetHostToString((InetHost)addr.s_addr, sHostInfo.name);
  1447.     
  1448.     return sHostInfo.name;
  1449. }
  1450.  
  1451.  
  1452. PR_IMPLEMENT(PRStatus) _MD_gethostname(char *name, int namelen)
  1453. {
  1454.     OSStatus err;
  1455.     InetInterfaceInfo info;
  1456.  
  1457.     /*
  1458.      *    On a Macintosh, we don╒t have the concept of a local host name.
  1459.      *    We do though have an IP address & everyone should be happy with
  1460.      *     a string version of that for a name.
  1461.      *    The alternative here is to ping a local DNS for our name, they
  1462.      *    will often know it.  This is the cheap, easiest, and safest way out.
  1463.      */
  1464.  
  1465.     /* Make sure the string is as long as the longest possible address */
  1466.     if (namelen < strlen("123.123.123.123")) {
  1467.         err = kEINVALErr;
  1468.         goto ErrorExit;
  1469.     }
  1470.  
  1471.     err = OTInetGetInterfaceInfo(&info, kDefaultInetInterface);
  1472.     if (err != kOTNoError)
  1473.         goto ErrorExit;
  1474.     
  1475.     OTInetHostToString(info.fAddress, name);
  1476.     
  1477.     return PR_SUCCESS;
  1478.  
  1479. ErrorExit:
  1480.     macsock_map_error(err);
  1481.     return PR_FAILURE;
  1482. }
  1483.  
  1484.  
  1485. #define kIPName        "ip"
  1486. static struct protoent sIPProto = {kIPName, NULL, INET_IP};
  1487. static struct protoent sTCPProto = {kTCPName, NULL, INET_TCP};
  1488. static struct protoent sUDPProto = {kUDPName, NULL, INET_UDP};
  1489.  
  1490. PR_IMPLEMENT(struct protoent *) getprotobyname(const char * name)
  1491. {
  1492.     if (strcmp(name, kIPName) == 0)
  1493.         return (&sIPProto);
  1494.         
  1495.     if (strcmp(name, kTCPName) == 0)
  1496.         return (&sTCPProto);
  1497.         
  1498.     if (strcmp(name, kUDPName) == 0)
  1499.         return (&sUDPProto);
  1500.         
  1501. ErrorExit:
  1502.     macsock_map_error(kEINVALErr);
  1503.     return NULL;
  1504. }
  1505.  
  1506.  
  1507. PR_IMPLEMENT(struct protoent *) getprotobynumber(int number)
  1508. {
  1509.     if (number == INET_IP)
  1510.         return (&sIPProto);
  1511.         
  1512.     if (number == INET_TCP)
  1513.         return (&sTCPProto);
  1514.         
  1515.     if (number == INET_UDP)
  1516.         return (&sUDPProto);
  1517.         
  1518. ErrorExit:
  1519.     macsock_map_error(kEINVALErr);
  1520.     return NULL;
  1521. }
  1522.  
  1523.  
  1524. int _MD_mac_get_nonblocking_connect_error(PRInt32 osfd)
  1525. {
  1526.     OTResult resultOT;
  1527.     EndpointRef endpoint = (EndpointRef) osfd;
  1528.  
  1529.     resultOT = OTGetEndpointState(endpoint);
  1530.     switch (resultOT)    {
  1531.         case T_OUTCON:
  1532.             macsock_map_error(kEINPROGRESSErr);
  1533.             return -1;
  1534.         case T_DATAXFER:
  1535.             return 0;
  1536.         case T_IDLE:
  1537.             return -1;
  1538.         default:
  1539.             PR_ASSERT(0);
  1540.             return -1;
  1541.     }
  1542. }
  1543.