Back to index

lightning-sunbird  0.9+nobinonly
macsockotpt.c
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is the Netscape Portable Runtime (NSPR).
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998-2000
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 /* This turns on UNIX style errors in OT 1.1 headers */
00039 #define OTUNIXERRORS 1
00040 
00041 #include <string.h>
00042 
00043 #include <Gestalt.h>
00044 #include <Files.h>
00045 #include <OpenTransport.h>
00046 #include <OSUtils.h>
00047 
00048 #define GESTALT_OPEN_TPT_PRESENT        gestaltOpenTptPresentMask
00049 #define GESTALT_OPEN_TPT_TCP_PRESENT    gestaltOpenTptTCPPresentMask
00050 
00051 #include <OpenTptInternet.h>    // All the internet typedefs
00052 
00053 #if (UNIVERSAL_INTERFACES_VERSION >= 0x0330)
00054 // for some reason Apple removed this typedef.
00055 typedef struct OTConfiguration     OTConfiguration;
00056 #endif
00057 
00058 #include "primpl.h"
00059 
00060 typedef enum SndRcvOpCode {
00061     kSTREAM_SEND,
00062     kSTREAM_RECEIVE,
00063     kDGRAM_SEND,
00064     kDGRAM_RECEIVE
00065 } SndRcvOpCode;
00066 
00067 static struct {
00068        PRLock *    lock;
00069        InetSvcRef  serviceRef;
00070        PRThread *  thread;
00071        void *      cookie;
00072 } dnsContext;
00073 
00074 
00075 static pascal void  DNSNotifierRoutine(void * contextPtr, OTEventCode code, OTResult result, void * cookie);
00076 static pascal void  NotifierRoutine(void * contextPtr, OTEventCode code, OTResult result, void * cookie);
00077 static pascal void  RawEndpointNotifierRoutine(void * contextPtr, OTEventCode code, OTResult result, void * cookie);
00078 
00079 static PRBool GetState(PRFileDesc *fd, PRBool *readReady, PRBool *writeReady, PRBool *exceptReady);
00080 
00081 void
00082 WakeUpNotifiedThread(PRThread *thread, OTResult result);
00083 
00084 extern void WaitOnThisThread(PRThread *thread, PRIntervalTime timeout);
00085 extern void DoneWaitingOnThisThread(PRThread *thread);
00086 
00087 #if TARGET_CARBON
00088 OTClientContextPtr  clientContext = NULL;
00089 
00090 #define INIT_OPEN_TRANSPORT()      InitOpenTransportInContext(kInitOTForExtensionMask, &clientContext)
00091 #define OT_OPEN_INTERNET_SERVICES(config, flags, err)   OTOpenInternetServicesInContext(config, flags, err, clientContext)
00092 #define OT_OPEN_ENDPOINT(config, flags, info, err)             OTOpenEndpointInContext(config, flags, info, err, clientContext)
00093 
00094 #else
00095 
00096 #define INIT_OPEN_TRANSPORT()      InitOpenTransport()
00097 #define OT_OPEN_INTERNET_SERVICES(config, flags, err)   OTOpenInternetServices(config, flags, err)
00098 #define OT_OPEN_ENDPOINT(config, flags, info, err)             OTOpenEndpoint(config, flags, info, err)
00099 #endif /* TARGET_CARBON */
00100 
00101 static OTNotifyUPP   DNSNotifierRoutineUPP;
00102 static OTNotifyUPP NotifierRoutineUPP;
00103 static OTNotifyUPP RawEndpointNotifierRoutineUPP;
00104 
00105 void _MD_InitNetAccess()
00106 {
00107     OSErr       err;
00108     OSStatus    errOT;
00109     PRBool      hasOTTCPIP = PR_FALSE;
00110     PRBool      hasOT = PR_FALSE;
00111     long        gestaltResult;
00112 
00113     err = Gestalt(gestaltOpenTpt, &gestaltResult);
00114     if (err == noErr)
00115         if (gestaltResult & GESTALT_OPEN_TPT_PRESENT)
00116             hasOT = PR_TRUE;
00117     
00118     if (hasOT)
00119         if (gestaltResult & GESTALT_OPEN_TPT_TCP_PRESENT)
00120             hasOTTCPIP = PR_TRUE;
00121         
00122     PR_ASSERT(hasOTTCPIP == PR_TRUE);
00123 
00124     DNSNotifierRoutineUPP   =  NewOTNotifyUPP(DNSNotifierRoutine);
00125     NotifierRoutineUPP             =  NewOTNotifyUPP(NotifierRoutine);
00126     RawEndpointNotifierRoutineUPP = NewOTNotifyUPP(RawEndpointNotifierRoutine);
00127 
00128     errOT = INIT_OPEN_TRANSPORT();
00129     PR_ASSERT(err == kOTNoError);
00130 
00131        dnsContext.serviceRef = NULL;
00132        dnsContext.lock = PR_NewLock();
00133        PR_ASSERT(dnsContext.lock != NULL);
00134 
00135        dnsContext.thread = _PR_MD_CURRENT_THREAD();
00136        dnsContext.cookie = NULL;
00137        
00138 /* XXX Does not handle absence of open tpt and tcp yet! */
00139 }
00140 
00141 static void _MD_FinishInitNetAccess()
00142 {
00143     OSStatus    errOT;
00144 
00145        if (dnsContext.serviceRef)
00146               return;
00147               
00148     dnsContext.serviceRef = OT_OPEN_INTERNET_SERVICES(kDefaultInternetServicesPath, NULL, &errOT);
00149     if (errOT != kOTNoError) {
00150         dnsContext.serviceRef = NULL;
00151         return;    /* no network -- oh well */
00152     }
00153     
00154     PR_ASSERT((dnsContext.serviceRef != NULL) && (errOT == kOTNoError));
00155 
00156     /* Install notify function for DNR Address To String completion */
00157     errOT = OTInstallNotifier(dnsContext.serviceRef, DNSNotifierRoutineUPP, &dnsContext);
00158     PR_ASSERT(errOT == kOTNoError);
00159 
00160     /* Put us into async mode */
00161     errOT = OTSetAsynchronous(dnsContext.serviceRef);
00162     PR_ASSERT(errOT == kOTNoError);
00163 }
00164 
00165 
00166 static pascal void  DNSNotifierRoutine(void * contextPtr, OTEventCode otEvent, OTResult result, void * cookie)
00167 {
00168 #pragma unused(contextPtr)
00169     _PRCPU *    cpu    = _PR_MD_CURRENT_CPU(); 
00170        OSStatus    errOT;
00171 
00172               dnsContext.thread->md.osErrCode = result;
00173               dnsContext.cookie = cookie;
00174        
00175        switch (otEvent) {
00176               case T_DNRSTRINGTOADDRCOMPLETE:
00177                             if (_PR_MD_GET_INTSOFF()) {
00178                                    dnsContext.thread->md.missedIONotify = PR_TRUE;
00179                                    cpu->u.missed[cpu->where] |= _PR_MISSED_IO;
00180                             } else {
00181                                    DoneWaitingOnThisThread(dnsContext.thread);
00182                             }
00183                             break;
00184               
00185         case kOTProviderWillClose:
00186                 errOT = OTSetSynchronous(dnsContext.serviceRef);
00187                 // fall through to kOTProviderIsClosed case
00188               
00189         case kOTProviderIsClosed:
00190                 errOT = OTCloseProvider((ProviderRef)dnsContext.serviceRef);
00191                 dnsContext.serviceRef = nil;
00192 
00193                             if (_PR_MD_GET_INTSOFF()) {
00194                                    dnsContext.thread->md.missedIONotify = PR_TRUE;
00195                                    cpu->u.missed[cpu->where] |= _PR_MISSED_IO;
00196                             } else {
00197                                    DoneWaitingOnThisThread(dnsContext.thread);
00198                             }
00199                 break;
00200 
00201         default: // or else we don't handle the event
00202                    PR_ASSERT(otEvent==NULL);
00203               
00204        }
00205        // or else we don't handle the event
00206        
00207        SignalIdleSemaphore();
00208 }
00209 
00210 
00211 static void macsock_map_error(OSStatus err)
00212 {
00213     _PR_MD_CURRENT_THREAD()->md.osErrCode = err;
00214 
00215     if (IsEError(err) || (err >= EPERM && err <= ELASTERRNO)) {
00216     switch (IsEError(err) ? OSStatus2E(err) : err) {
00217         case EBADF:
00218             PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err);
00219             break;
00220         case EADDRNOTAVAIL:
00221             PR_SetError(PR_ADDRESS_NOT_AVAILABLE_ERROR, err);
00222             break;
00223         case EINPROGRESS:
00224             PR_SetError(PR_IN_PROGRESS_ERROR, err);
00225             break;
00226         case EWOULDBLOCK:
00227         case EAGAIN:
00228             PR_SetError(PR_WOULD_BLOCK_ERROR, err);
00229             break;
00230         case ENOTSOCK:
00231             PR_SetError(PR_NOT_SOCKET_ERROR, err);
00232             break;
00233         case ETIMEDOUT:
00234             PR_SetError(PR_IO_TIMEOUT_ERROR, err);
00235             break;
00236         case ECONNREFUSED:
00237             PR_SetError(PR_CONNECT_REFUSED_ERROR, err);
00238             break;
00239         case ENETUNREACH:
00240             PR_SetError(PR_NETWORK_UNREACHABLE_ERROR, err);
00241             break;
00242         case EADDRINUSE:
00243             PR_SetError(PR_ADDRESS_IN_USE_ERROR, err);
00244             break;
00245         case EFAULT:
00246             PR_SetError(PR_ACCESS_FAULT_ERROR, err);
00247             break;
00248         case EINTR:
00249             PR_SetError(PR_PENDING_INTERRUPT_ERROR, err);
00250             break;
00251         case EINVAL:
00252             PR_SetError(PR_INVALID_ARGUMENT_ERROR, err);
00253             break;
00254         case EIO:
00255             PR_SetError(PR_IO_ERROR, err);
00256             break;
00257         case ENOENT:
00258             PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, err);
00259             break;
00260         case ENXIO:
00261             PR_SetError(PR_IO_ERROR, err);
00262             break;
00263         case EPROTOTYPE:
00264             PR_SetError(PR_PROTOCOL_NOT_SUPPORTED_ERROR, err);
00265             break;
00266         case EOPNOTSUPP:
00267             PR_SetError(PR_OPERATION_NOT_SUPPORTED_ERROR, err);
00268             break;
00269         default:
00270             PR_SetError(PR_UNKNOWN_ERROR, err);
00271             break;
00272         }
00273     } else {
00274     PR_ASSERT(IsXTIError(err));
00275     switch (err) {
00276         case kOTNoDataErr:
00277         case kOTFlowErr:
00278             PR_SetError(PR_WOULD_BLOCK_ERROR, err);
00279             break;
00280         default:
00281             PR_SetError(PR_UNKNOWN_ERROR, err);
00282             break;
00283         }
00284     }
00285 }
00286 
00287 static void PrepareForAsyncCompletion(PRThread * thread, PRInt32 osfd)
00288 {
00289     thread->io_pending       = PR_TRUE;
00290     thread->io_fd            = osfd;
00291     thread->md.osErrCode     = noErr;
00292 }
00293 
00294 
00295 void
00296 WakeUpNotifiedThread(PRThread *thread, OTResult result)
00297 {
00298     _PRCPU *      cpu      = _PR_MD_CURRENT_CPU(); 
00299 
00300        if (thread) {
00301               thread->md.osErrCode = result;
00302               if (_PR_MD_GET_INTSOFF()) {
00303                      thread->md.missedIONotify = PR_TRUE;
00304                      cpu->u.missed[cpu->where] |= _PR_MISSED_IO;
00305               } else {
00306                      DoneWaitingOnThisThread(thread);
00307               }
00308        }
00309        
00310        SignalIdleSemaphore();
00311 }
00312 
00313 // Notification routine
00314 // Async callback routine.
00315 // A5 is OK. Cannot allocate memory here
00316 // Ref: http://gemma.apple.com/techpubs/mac/NetworkingOT/NetworkingWOT-100.html
00317 //
00318 static pascal void  NotifierRoutine(void * contextPtr, OTEventCode code, OTResult result, void * cookie)
00319 {
00320     PRFilePrivate *secret  = (PRFilePrivate *) contextPtr;
00321     _MDFileDesc * md       = &(secret->md);
00322     EndpointRef   endpoint = (EndpointRef)secret->md.osfd;
00323     PRThread *    readThread   = NULL;          // also used for 'misc'
00324     PRThread *    writeThread  = NULL;
00325     OSStatus      err;
00326     OTResult      resultOT;
00327     TDiscon       discon;
00328 
00329     switch (code)
00330     {
00331 // OTLook Events - 
00332         case T_LISTEN:        // A connection request is available
00333             // If md->doListen is true, then PR_Listen has been
00334             // called on this endpoint; therefore, we're ready to
00335             // accept connections. But we'll do that with PR_Accept
00336             // (which calls OTListen, OTAccept, etc) instead of 
00337             // doing it here. 
00338             if (md->doListen) {
00339                 readThread = secret->md.misc.thread;
00340                 secret->md.misc.thread    = NULL;
00341                 secret->md.misc.cookie    = cookie;
00342                 break;
00343             } else {
00344                 // Reject the connection, we're not listening
00345                 OTSndDisconnect(endpoint, NULL);
00346             }
00347             break;
00348 
00349         case T_CONNECT:      // Confirmation of a connect request
00350             // cookie = sndCall parameter from OTConnect()
00351             err = OTRcvConnect(endpoint, NULL);
00352             PR_ASSERT(err == kOTNoError);
00353 
00354             // wake up waiting thread, if any.
00355             writeThread = secret->md.write.thread;
00356             secret->md.write.thread    = NULL;
00357             secret->md.write.cookie    = cookie;            
00358             break;
00359 
00360         case T_DATA:        // Standard data is available
00361             // Mark this socket as readable.
00362             secret->md.readReady = PR_TRUE;
00363 
00364             // wake up waiting thread, if any
00365             readThread = secret->md.read.thread;
00366             secret->md.read.thread    = NULL;
00367             secret->md.read.cookie    = cookie;
00368             break;
00369 
00370         case T_EXDATA:      // Expedited data is available
00371             PR_ASSERT(!"T_EXDATA Not implemented");
00372             return;
00373 
00374         case T_DISCONNECT:  // A disconnect is available
00375             discon.udata.len = 0;
00376             err = OTRcvDisconnect(endpoint, &discon);
00377             PR_ASSERT(err == kOTNoError);
00378             secret->md.exceptReady = PR_TRUE;       // XXX Check this
00379 
00380             md->disconnectError = discon.reason;    // save for _MD_mac_get_nonblocking_connect_error
00381 
00382             // wake up waiting threads, if any
00383             result = -3199 - discon.reason; // obtain the negative error code
00384             if ((readThread = secret->md.read.thread) != NULL) {
00385                 secret->md.read.thread    = NULL;
00386                 secret->md.read.cookie    = cookie;
00387             }
00388 
00389             if ((writeThread = secret->md.write.thread) != NULL) {
00390                 secret->md.write.thread    = NULL;
00391                 secret->md.write.cookie    = cookie;
00392             }
00393             break;
00394 
00395         case T_ERROR:       // obsolete/unused in library
00396             PR_ASSERT(!"T_ERROR Not implemented");
00397             return;
00398 
00399         case T_UDERR:       // UDP Send error; clear the error
00400             (void) OTRcvUDErr((EndpointRef) cookie, NULL);
00401             break;
00402 
00403         case T_ORDREL:      // An orderly release is available
00404             err = OTRcvOrderlyDisconnect(endpoint);
00405             PR_ASSERT(err == kOTNoError);
00406             secret->md.readReady      = PR_TRUE;   // mark readable (to emulate bsd sockets)
00407             // remember connection is closed, so we can return 0 on read or receive
00408             secret->md.orderlyDisconnect = PR_TRUE;
00409             
00410             readThread = secret->md.read.thread;
00411             secret->md.read.thread    = NULL;
00412             secret->md.read.cookie    = cookie;
00413             break;          
00414 
00415         case T_GODATA:   // Flow control lifted on standard data
00416             secret->md.writeReady = PR_TRUE;
00417             resultOT = OTLook(endpoint);        // clear T_GODATA event
00418             PR_ASSERT(resultOT == T_GODATA);
00419             
00420             // wake up waiting thread, if any
00421             writeThread = secret->md.write.thread;
00422             secret->md.write.thread    = NULL;
00423             secret->md.write.cookie    = cookie;
00424             break;
00425 
00426         case T_GOEXDATA: // Flow control lifted on expedited data
00427             PR_ASSERT(!"T_GOEXDATA Not implemented");
00428             return;
00429 
00430         case T_REQUEST:  // An Incoming request is available
00431             PR_ASSERT(!"T_REQUEST Not implemented");
00432             return;
00433 
00434         case T_REPLY:    // An Incoming reply is available
00435             PR_ASSERT(!"T_REPLY Not implemented");
00436             return;
00437 
00438         case T_PASSCON:  // State is now T_DATAXFER
00439             // OTAccept() complete, receiving endpoint in T_DATAXFER state
00440             // cookie = OTAccept() resRef parameter
00441             break;
00442 
00443         case T_RESET:    // Protocol has been reset
00444             PR_ASSERT(!"T_RESET Not implemented");
00445             return;
00446             
00447 // Async Completion Events
00448         case T_BINDCOMPLETE:
00449         case T_UNBINDCOMPLETE:
00450         case T_ACCEPTCOMPLETE:
00451         case T_OPTMGMTCOMPLETE:
00452         case T_GETPROTADDRCOMPLETE:
00453             readThread = secret->md.misc.thread;
00454             secret->md.misc.thread    = NULL;
00455             secret->md.misc.cookie    = cookie;
00456             break;
00457 
00458 //      case T_OPENCOMPLETE:            // we open endpoints in synchronous mode
00459 //      case T_REPLYCOMPLETE:
00460 //      case T_DISCONNECTCOMPLETE:      // we don't call OTSndDisconnect()
00461 //      case T_RESOLVEADDRCOMPLETE:
00462 //      case T_GETINFOCOMPLETE:
00463 //      case T_SYNCCOMPLETE:
00464 //      case T_MEMORYRELEASED:          // only if OTAckSends() called on endpoint
00465 //      case T_REGNAMECOMPLETE:
00466 //      case T_DELNAMECOMPLETE:
00467 //      case T_LKUPNAMECOMPLETE:
00468 //      case T_LKUPNAMERESULT:
00469         // OpenTptInternet.h
00470 //      case T_DNRSTRINGTOADDRCOMPLETE: // DNS is handled by dnsContext in DNSNotifierRoutine()
00471 //      case T_DNRADDRTONAMECOMPLETE:
00472 //      case T_DNRSYSINFOCOMPLETE:
00473 //      case T_DNRMAILEXCHANGECOMPLETE:
00474 //      case T_DNRQUERYCOMPLETE:
00475         default:
00476             // we should probably have a bit more sophisticated handling of kOTSystemSleep, etc.
00477             // PR_ASSERT(code != 0);
00478             return;
00479     }
00480 
00481     if (readThread)
00482         WakeUpNotifiedThread(readThread, result);
00483 
00484     if (writeThread && (writeThread != readThread))
00485         WakeUpNotifiedThread(writeThread, result);
00486 }
00487 
00488 
00489 static OSErr CreateSocket(int type, EndpointRef *endpoint)
00490 {
00491     OSStatus err;
00492     PRThread *me = _PR_MD_CURRENT_THREAD();
00493     char *  configName;
00494     OTConfiguration *config;
00495     EndpointRef ep;
00496 
00497     // for now we just create the endpoint
00498     // we'll make it asynchronous and give it a notifier routine in _MD_makenonblock()
00499 
00500     switch (type){
00501         case SOCK_STREAM:   configName = kTCPName;  break;
00502         case SOCK_DGRAM:    configName = kUDPName;  break;
00503     }
00504     config = OTCreateConfiguration(configName);
00505     ep = OT_OPEN_ENDPOINT(config, 0, NULL, &err);
00506     if (err != kOTNoError)
00507         goto ErrorExit;
00508 
00509     *endpoint = ep;
00510     PR_ASSERT(*endpoint != NULL);
00511 
00512     return kOTNoError;
00513 
00514 ErrorExit:
00515     return err;
00516 }
00517 
00518 
00519 // Errors returned:
00520 // kOTXXXX - OT returned error
00521 // EPROTONOSUPPORT - bad socket type/protocol
00522 // ENOBUFS - not enough space for another socket, or failure in socket creation routine
00523 PRInt32 _MD_socket(int domain, int type, int protocol)
00524 {
00525     OSStatus    err;
00526     EndpointRef endpoint;
00527     
00528     _MD_FinishInitNetAccess();
00529 
00530     // We only deal with internet domain
00531     if (domain != AF_INET) {
00532         err = kEPROTONOSUPPORTErr;
00533         goto ErrorExit;
00534     }
00535     
00536     // We only know about tcp & udp
00537     if ((type != SOCK_STREAM) && (type != SOCK_DGRAM)) {
00538         err = kEPROTONOSUPPORTErr;
00539         goto ErrorExit;
00540     }
00541     
00542     // Convert default types to specific types.
00543     if (protocol == 0)  {
00544         if (type == SOCK_DGRAM)
00545             protocol = IPPROTO_UDP;
00546         else if (type == SOCK_STREAM)
00547             protocol = IPPROTO_TCP;
00548     }
00549     
00550     // Only support default protocol for tcp
00551     if ((type == SOCK_STREAM)  && (protocol != IPPROTO_TCP)) {
00552         err = kEPROTONOSUPPORTErr;
00553         goto ErrorExit;
00554     }
00555                 
00556     // Only support default protocol for udp
00557     if ((type == SOCK_DGRAM)  && (protocol != IPPROTO_UDP)) {
00558         err = kEPROTONOSUPPORTErr;
00559         goto ErrorExit;
00560     }
00561         
00562     // Create a socket, we might run out of memory
00563     err = CreateSocket(type, &endpoint);
00564     if (err != kOTNoError)
00565         goto ErrorExit;
00566 
00567     PR_ASSERT((PRInt32)endpoint != -1);
00568 
00569     return ((PRInt32)endpoint);
00570 
00571 ErrorExit:
00572     macsock_map_error(err);
00573     return -1;
00574 }
00575 
00576 
00577 // Errors:
00578 // EBADF  -- bad socket id
00579 // EFAULT -- bad address format
00580 PRInt32 _MD_bind(PRFileDesc *fd, PRNetAddr *addr, PRUint32 addrlen)
00581 {
00582     OSStatus err;
00583     EndpointRef endpoint = (EndpointRef) fd->secret->md.osfd;
00584     TBind bindReq;
00585     PRThread *me = _PR_MD_CURRENT_THREAD();
00586     PRUint32 retryCount = 0;
00587 
00588     if (endpoint == NULL) {
00589         err = kEBADFErr;
00590         goto ErrorExit;
00591     }
00592         
00593     if (addr == NULL) {
00594         err = kEFAULTErr;
00595         goto ErrorExit;
00596     }
00597         
00598 /*
00599  * There seems to be a bug with OT related to OTBind failing with kOTNoAddressErr even though
00600  * a proper legal address was supplied.  This happens very rarely and just retrying the
00601  * operation after a certain time (less than 1 sec. does not work) seems to succeed.
00602  */
00603 
00604 TryAgain:
00605     // setup our request
00606     bindReq.addr.len = addrlen;
00607         
00608     bindReq.addr.maxlen = addrlen;
00609     bindReq.addr.buf = (UInt8*) addr;
00610     bindReq.qlen = 1;
00611 
00612        PR_Lock(fd->secret->md.miscLock);
00613     PrepareForAsyncCompletion(me, fd->secret->md.osfd);
00614        fd->secret->md.misc.thread = me;
00615 
00616     err = OTBind(endpoint, &bindReq, NULL);
00617     if (err != kOTNoError) {
00618            me->io_pending = PR_FALSE;
00619            PR_Unlock(fd->secret->md.miscLock);
00620         goto ErrorExit;
00621        }
00622 
00623     WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT);
00624        PR_Unlock(fd->secret->md.miscLock);
00625 
00626     err = me->md.osErrCode;
00627     if (err != kOTNoError)
00628         goto ErrorExit;
00629 
00630     return kOTNoError;
00631 
00632 ErrorExit:
00633     if ((err == kOTNoAddressErr) && (++retryCount <= 4)) {
00634         unsigned long finalTicks;
00635     
00636         Delay(100,&finalTicks);
00637         goto TryAgain;
00638     }
00639     macsock_map_error(err);
00640     return -1;
00641 }
00642 
00643 
00644 // Errors:
00645 // EBADF -- bad socket id
00646 PRInt32 _MD_listen(PRFileDesc *fd, PRIntn backlog)
00647 {
00648     PRInt32 osfd = fd->secret->md.osfd;
00649     OSStatus err = 0;
00650     EndpointRef endpoint = (EndpointRef) osfd;
00651     TBind bindReq;
00652     PRNetAddr addr;
00653     PRThread *me = _PR_MD_CURRENT_THREAD();
00654 
00655        if ((fd == NULL) || (endpoint == NULL)) {
00656               err = EBADF;
00657               goto ErrorExit;
00658        }
00659 
00660     if (backlog == 0)
00661         backlog = 1;
00662 
00663     if (endpoint == NULL) {
00664         err = EBADF;
00665         goto ErrorExit;
00666     }
00667         
00668     addr.inet.family = AF_INET;
00669     addr.inet.port = addr.inet.ip = 0;
00670 
00671     bindReq.addr.maxlen = PR_NETADDR_SIZE (&addr);
00672     bindReq.addr.len = 0;
00673     bindReq.addr.buf = (UInt8*) &addr;
00674     bindReq.qlen = 0;
00675     
00676     PrepareForAsyncCompletion(me, fd->secret->md.osfd);    
00677        fd->secret->md.misc.thread = me; // tell notifier routine what to wake up
00678 
00679     err = OTGetProtAddress(endpoint, &bindReq, NULL);
00680     if (err != kOTNoError)
00681         goto ErrorExit;
00682 
00683     WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT);
00684 
00685     err = me->md.osErrCode;
00686     if (err != kOTNoError)
00687         goto ErrorExit;
00688 
00689     PrepareForAsyncCompletion(me, fd->secret->md.osfd);    
00690        fd->secret->md.misc.thread = me; // tell notifier routine what to wake up
00691 
00692     err = OTUnbind(endpoint);
00693     if (err != kOTNoError)
00694         goto ErrorExit;
00695 
00696     WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT);
00697 
00698     err = me->md.osErrCode;
00699     if (err != kOTNoError)
00700         goto ErrorExit;
00701 
00702        /* tell the notifier func that we are interested in pending connections */
00703        fd->secret->md.doListen = PR_TRUE;
00704        /* accept up to (backlog) pending connections at any one time */
00705     bindReq.qlen = backlog;
00706     
00707     PrepareForAsyncCompletion(me, fd->secret->md.osfd);    
00708        fd->secret->md.misc.thread = me; // tell notifier routine what to wake up
00709 
00710     err = OTBind(endpoint, &bindReq, NULL);
00711     if (err != kOTNoError)
00712         goto ErrorExit;
00713 
00714     WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT);
00715 
00716     err = me->md.osErrCode;
00717     if (err != kOTNoError)
00718     {
00719        // If OTBind failed, we're really not ready to listen after all.
00720               fd->secret->md.doListen = PR_FALSE;
00721         goto ErrorExit;
00722     }
00723 
00724     return kOTNoError;
00725 
00726 ErrorExit:
00727        me->io_pending = PR_FALSE; // clear pending wait state if any
00728     macsock_map_error(err);
00729     return -1;
00730 }
00731 
00732 
00733 // Errors:
00734 // EBADF -- bad socket id
00735 PRInt32 _MD_getsockname(PRFileDesc *fd, PRNetAddr *addr, PRUint32 *addrlen)
00736 {
00737     OSStatus err;
00738     EndpointRef endpoint = (EndpointRef) fd->secret->md.osfd;
00739     TBind bindReq;
00740     PRThread *me = _PR_MD_CURRENT_THREAD();
00741 
00742     if (endpoint == NULL) {
00743         err = kEBADFErr;
00744         goto ErrorExit;
00745     }
00746         
00747     if (addr == NULL) {
00748         err = kEFAULTErr;
00749         goto ErrorExit;
00750     }
00751 
00752     bindReq.addr.len = *addrlen;
00753     bindReq.addr.maxlen = *addrlen;
00754     bindReq.addr.buf = (UInt8*) addr;
00755     bindReq.qlen = 0;
00756     
00757        PR_Lock(fd->secret->md.miscLock);
00758     PrepareForAsyncCompletion(me, fd->secret->md.osfd);    
00759        fd->secret->md.misc.thread = me;
00760 
00761     err = OTGetProtAddress(endpoint, &bindReq, NULL);
00762     if (err != kOTNoError) {
00763            me->io_pending = PR_FALSE;
00764            PR_Unlock(fd->secret->md.miscLock);
00765         goto ErrorExit;
00766        }
00767 
00768     WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT);
00769        PR_Unlock(fd->secret->md.miscLock);
00770 
00771     err = me->md.osErrCode;
00772     if (err != kOTNoError)
00773         goto ErrorExit;
00774 
00775     *addrlen = PR_NETADDR_SIZE(addr);
00776     return kOTNoError;
00777 
00778 ErrorExit:
00779     macsock_map_error(err);
00780     return -1;
00781 }
00782 
00783 
00784 PRStatus _MD_getsockopt(PRFileDesc *fd, PRInt32 level, PRInt32 optname, char* optval, PRInt32* optlen)
00785 {
00786     OSStatus err;
00787     EndpointRef endpoint = (EndpointRef) fd->secret->md.osfd;
00788     TOptMgmt cmd;
00789     TOption *opt;
00790     PRThread *me = _PR_MD_CURRENT_THREAD();
00791     unsigned char optionBuffer[kOTOptionHeaderSize + sizeof(PRSocketOptionData)];
00792     
00793     if (endpoint == NULL) {
00794         err = kEBADFErr;
00795         goto ErrorExit;
00796     }
00797     
00798     /* 
00799     OT wants IPPROTO_IP for level and not XTI_GENERIC.  SO_REUSEADDR and SO_KEEPALIVE 
00800     are equated to IP level and TCP level options respectively and hence we need to set 
00801     the level correctly.
00802     */
00803     if (level == SOL_SOCKET) {
00804         if (optname == SO_REUSEADDR)
00805             level = IPPROTO_IP;
00806         else if (optname == SO_KEEPALIVE)
00807             level = INET_TCP;
00808     }
00809 
00810     opt = (TOption *)&optionBuffer[0];
00811     opt->len = sizeof(TOption);
00812     opt->level = level;
00813     opt->name = optname;
00814     opt->status = 0;
00815     
00816     cmd.opt.len = sizeof(TOption);
00817     cmd.opt.maxlen = sizeof(optionBuffer);
00818     cmd.opt.buf = (UInt8*)optionBuffer;
00819     cmd.flags = T_CURRENT;
00820 
00821        PR_Lock(fd->secret->md.miscLock);
00822     PrepareForAsyncCompletion(me, fd->secret->md.osfd);    
00823        fd->secret->md.misc.thread = me;
00824 
00825     err = OTOptionManagement(endpoint, &cmd, &cmd);
00826     if (err != kOTNoError) {
00827            me->io_pending = PR_FALSE;
00828            PR_Unlock(fd->secret->md.miscLock);
00829         goto ErrorExit;
00830        }
00831 
00832     WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT);
00833        PR_Unlock(fd->secret->md.miscLock);
00834 
00835     err = me->md.osErrCode;
00836     if (err != kOTNoError)
00837         goto ErrorExit;
00838 
00839     if (opt->status == T_FAILURE || opt->status == T_NOTSUPPORT){
00840         err = kEOPNOTSUPPErr;
00841         goto ErrorExit;
00842     }
00843 
00844     PR_ASSERT(opt->status == T_SUCCESS);
00845 
00846     switch (optname) {
00847         case SO_LINGER:
00848             *((t_linger*)optval) = *((t_linger*)&opt->value);
00849             *optlen = sizeof(t_linger);
00850             break;
00851         case SO_REUSEADDR:
00852         case TCP_NODELAY:
00853         case SO_KEEPALIVE:
00854         case SO_RCVBUF:
00855         case SO_SNDBUF:
00856             *((PRIntn*)optval) = *((PRIntn*)&opt->value);
00857             *optlen = sizeof(PRIntn);
00858             break;
00859         case IP_MULTICAST_LOOP:
00860             *((PRUint8*)optval) = *((PRIntn*)&opt->value);
00861             *optlen = sizeof(PRUint8);
00862             break;
00863         case IP_TTL:
00864             *((PRUintn*)optval) = *((PRUint8*)&opt->value);
00865             *optlen = sizeof(PRUintn);
00866             break;
00867         case IP_MULTICAST_TTL:
00868             *((PRUint8*)optval) = *((PRUint8*)&opt->value);
00869             *optlen = sizeof(PRUint8);
00870             break;
00871         case IP_ADD_MEMBERSHIP:
00872         case IP_DROP_MEMBERSHIP:
00873             {
00874             /* struct ip_mreq and TIPAddMulticast are the same size and optval 
00875                is pointing to struct ip_mreq */
00876             *((struct ip_mreq *)optval) = *((struct ip_mreq *)&opt->value);
00877             *optlen = sizeof(struct ip_mreq);
00878             break;
00879             }
00880         case IP_MULTICAST_IF:
00881             {
00882             *((PRUint32*)optval) = *((PRUint32*)&opt->value);
00883             *optlen = sizeof(PRUint32);
00884             break;
00885             }
00886         /*case IP_TOS:*/ /*IP_TOS has same value as TCP_MAXSEG */
00887         case TCP_MAXSEG:
00888             if (level == IPPROTO_TCP) { /* it is TCP_MAXSEG */
00889                 *((PRIntn*)optval) = *((PRIntn*)&opt->value);
00890                 *optlen = sizeof(PRIntn);
00891             } else { /* it is IP_TOS */
00892                 *((PRUintn*)optval) = *((PRUint8*)&opt->value);
00893                 *optlen = sizeof(PRUintn);
00894             }
00895             break;
00896         default:
00897             PR_ASSERT(0);
00898             break;    
00899     }
00900     
00901     return PR_SUCCESS;
00902 
00903 ErrorExit:
00904     macsock_map_error(err);
00905     return PR_FAILURE;
00906 }
00907 
00908 
00909 PRStatus _MD_setsockopt(PRFileDesc *fd, PRInt32 level, PRInt32 optname, const char* optval, PRInt32 optlen)
00910 {
00911     OSStatus err;
00912     EndpointRef endpoint = (EndpointRef) fd->secret->md.osfd;
00913     TOptMgmt cmd;
00914     TOption *opt;
00915     PRThread *me = _PR_MD_CURRENT_THREAD();
00916     unsigned char optionBuffer[kOTOptionHeaderSize + sizeof(PRSocketOptionData) + 1];
00917     
00918     if (endpoint == NULL) {
00919         err = kEBADFErr;
00920         goto ErrorExit;
00921     }
00922     
00923     /* 
00924     OT wants IPPROTO_IP for level and not XTI_GENERIC.  SO_REUSEADDR and SO_KEEPALIVE 
00925     are equated to IP level and TCP level options respectively and hence we need to set 
00926     the level correctly.
00927     */
00928     if (level == SOL_SOCKET) {
00929         if (optname == SO_REUSEADDR)
00930             level = IPPROTO_IP;
00931         else if (optname == SO_KEEPALIVE)
00932             level = INET_TCP;
00933     }
00934 
00935     opt = (TOption *)&optionBuffer[0];
00936     opt->len = kOTOptionHeaderSize + optlen;
00937 
00938     /* special case adjustments for length follow */
00939     if (optname == SO_KEEPALIVE) /* we need to pass the timeout value for OT */
00940         opt->len = kOTOptionHeaderSize + sizeof(t_kpalive);
00941     if (optname == IP_MULTICAST_TTL || optname == IP_TTL) /* it is an unsigned char value */
00942         opt->len = kOTOneByteOptionSize;
00943     if (optname == IP_TOS && level == IPPROTO_IP)
00944         opt->len = kOTOneByteOptionSize;
00945 
00946     opt->level = level;
00947     opt->name = optname;
00948     opt->status = 0;
00949     
00950     cmd.opt.len = opt->len;
00951     cmd.opt.maxlen = sizeof(optionBuffer);
00952     cmd.opt.buf = (UInt8*)optionBuffer;
00953     
00954     optionBuffer[opt->len] = 0;
00955     
00956     cmd.flags = T_NEGOTIATE;
00957 
00958     switch (optname) {
00959         case SO_LINGER:
00960             *((t_linger*)&opt->value) = *((t_linger*)optval);
00961             break;
00962         case SO_REUSEADDR:
00963         case TCP_NODELAY:
00964         case SO_RCVBUF:
00965         case SO_SNDBUF:
00966             *((PRIntn*)&opt->value) = *((PRIntn*)optval);
00967             break;
00968         case IP_MULTICAST_LOOP:
00969             if (*optval != 0)
00970                 opt->value[0] = T_YES;
00971             else
00972                 opt->value[0] = T_NO;
00973             break;
00974         case SO_KEEPALIVE:
00975             {
00976             t_kpalive *kpalive = (t_kpalive *)&opt->value;
00977             
00978             kpalive->kp_onoff = *((long*)optval);
00979             kpalive->kp_timeout = 10; /* timeout in minutes */
00980             break;
00981             }
00982         case IP_TTL:
00983             *((unsigned char*)&opt->value) = *((PRUintn*)optval);
00984             break;
00985         case IP_MULTICAST_TTL:
00986             *((unsigned char*)&opt->value) = *optval;
00987             break;
00988         case IP_ADD_MEMBERSHIP:
00989         case IP_DROP_MEMBERSHIP:
00990             {
00991             /* struct ip_mreq and TIPAddMulticast are the same size and optval 
00992                is pointing to struct ip_mreq */
00993             *((TIPAddMulticast *)&opt->value) = *((TIPAddMulticast *)optval);
00994             break;
00995             }
00996         case IP_MULTICAST_IF:
00997             {
00998             *((PRUint32*)&opt->value) = *((PRUint32*)optval);
00999             break;
01000             }
01001         /*case IP_TOS:*/ /*IP_TOS has same value as TCP_MAXSEG */
01002         case TCP_MAXSEG:
01003             if (level == IPPROTO_TCP) { /* it is TCP_MAXSEG */
01004                 *((PRIntn*)&opt->value) = *((PRIntn*)optval);
01005             } else { /* it is IP_TOS */
01006                 *((unsigned char*)&opt->value) = *((PRUintn*)optval);
01007             }
01008             break;
01009         default:
01010             PR_ASSERT(0);
01011             break;    
01012     }
01013     
01014        PR_Lock(fd->secret->md.miscLock);
01015     PrepareForAsyncCompletion(me, fd->secret->md.osfd);    
01016        fd->secret->md.misc.thread = me;
01017 
01018     err = OTOptionManagement(endpoint, &cmd, &cmd);
01019     if (err != kOTNoError) {
01020            me->io_pending = PR_FALSE;
01021            PR_Unlock(fd->secret->md.miscLock);
01022         goto ErrorExit;
01023        }
01024 
01025     WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT);
01026        PR_Unlock(fd->secret->md.miscLock);
01027 
01028     err = me->md.osErrCode;
01029     if (err != kOTNoError)
01030         goto ErrorExit;
01031 
01032     if (opt->status == T_FAILURE || opt->status == T_NOTSUPPORT){
01033         err = kEOPNOTSUPPErr;
01034         goto ErrorExit;
01035     }
01036     
01037     if (level == IPPROTO_TCP && optname == TCP_MAXSEG && opt->status == T_READONLY) {
01038         err = kEOPNOTSUPPErr;
01039         goto ErrorExit;
01040     }
01041 
01042     PR_ASSERT(opt->status == T_SUCCESS);
01043 
01044     return PR_SUCCESS;
01045 
01046 ErrorExit:
01047     macsock_map_error(err);
01048     return PR_FAILURE;
01049 }
01050 
01051 
01052 PRInt32 _MD_socketavailable(PRFileDesc *fd)
01053 {
01054     PRInt32 osfd = fd->secret->md.osfd;
01055     OSStatus err;
01056     EndpointRef endpoint = (EndpointRef) osfd;
01057     size_t bytes;
01058 
01059     if (endpoint == NULL) {
01060         err = kEBADFErr;
01061         goto ErrorExit;
01062     }
01063     
01064     bytes = 0;
01065     
01066     err = OTCountDataBytes(endpoint, &bytes);
01067     if ((err == kOTLookErr) ||         // Not really errors, we just need to do a read,
01068         (err == kOTNoDataErr))        // or there's nothing there.
01069         err = kOTNoError;
01070         
01071     if (err != kOTNoError)
01072         goto ErrorExit;
01073         
01074     return bytes;
01075 
01076 ErrorExit:
01077     macsock_map_error(err);
01078     return -1;
01079 }
01080 
01081 
01082 typedef struct RawEndpointAndThread
01083 {
01084        PRThread *  thread;
01085        EndpointRef endpoint;
01086 } RawEndpointAndThread;
01087 
01088 // Notification routine for raw endpoints not yet attached to a PRFileDesc.
01089 // Async callback routine.
01090 // A5 is OK. Cannot allocate memory here
01091 static pascal void  RawEndpointNotifierRoutine(void * contextPtr, OTEventCode code, OTResult result, void * cookie)
01092 {
01093     RawEndpointAndThread *endthr = (RawEndpointAndThread *) contextPtr;
01094     PRThread *    thread   = endthr->thread;
01095     EndpointRef * endpoint = endthr->endpoint;
01096     _PRCPU *      cpu      = _PR_MD_CURRENT_CPU(); 
01097     OSStatus      err;
01098     OTResult    resultOT;
01099 
01100     switch (code)
01101     {
01102 // OTLook Events - 
01103         case T_LISTEN:        // A connection request is available
01104             PR_ASSERT(!"T_EXDATA not implemented for raw endpoints");
01105             break;
01106                      
01107         case T_CONNECT:      // Confirmation of a connect request
01108                      // cookie = sndCall parameter from OTConnect()
01109             err = OTRcvConnect(endpoint, NULL);
01110             PR_ASSERT(err == kOTNoError);
01111 
01112                      // wake up waiting thread
01113             break;
01114 
01115         case T_DATA:        // Standard data is available
01116                      break;
01117 
01118         case T_EXDATA:      // Expedited data is available
01119             PR_ASSERT(!"T_EXDATA Not implemented for raw endpoints");
01120                      return;
01121 
01122         case T_DISCONNECT:  // A disconnect is available
01123             err = OTRcvDisconnect(endpoint, NULL);
01124             PR_ASSERT(err == kOTNoError);
01125             break;
01126               
01127         case T_ERROR:       // obsolete/unused in library
01128             PR_ASSERT(!"T_ERROR Not implemented for raw endpoints");
01129                      return;              
01130               
01131         case T_UDERR:       // UDP Send error; clear the error
01132                      (void) OTRcvUDErr((EndpointRef) cookie, NULL);
01133             break;
01134 
01135         case T_ORDREL:      // An orderly release is available
01136             err = OTRcvOrderlyDisconnect(endpoint);
01137             PR_ASSERT(err == kOTNoError);
01138             break;          
01139 
01140         case T_GODATA:   // Flow control lifted on standard data
01141                      resultOT = OTLook(endpoint);              // clear T_GODATA event
01142                      PR_ASSERT(resultOT == T_GODATA);
01143                      
01144                      // wake up waiting thread, if any
01145             break;
01146 
01147         case T_GOEXDATA: // Flow control lifted on expedited data
01148             PR_ASSERT(!"T_GOEXDATA Not implemented");
01149                      return;
01150 
01151         case T_REQUEST:  // An Incoming request is available
01152             PR_ASSERT(!"T_REQUEST Not implemented");
01153             return;
01154 
01155         case T_REPLY:    // An Incoming reply is available
01156             PR_ASSERT(!"T_REPLY Not implemented");
01157             return;
01158 
01159         case T_PASSCON:  // State is now T_DATAXFER
01160                      // OTAccept() complete, receiving endpoint in T_DATAXFER state
01161                      // cookie = OTAccept() resRef parameter
01162                      break;
01163             
01164 // Async Completion Events
01165         case T_BINDCOMPLETE:
01166         case T_UNBINDCOMPLETE:
01167         case T_ACCEPTCOMPLETE:
01168         case T_OPTMGMTCOMPLETE:
01169         case T_GETPROTADDRCOMPLETE:
01170             break;
01171 
01172               // for other OT events, see NotifierRoutine above
01173         default:
01174             return;
01175     }
01176 
01177        if (thread) {
01178               thread->md.osErrCode = result;
01179               if (_PR_MD_GET_INTSOFF()) {
01180                      thread->md.asyncNotifyPending = PR_TRUE;
01181                      cpu->u.missed[cpu->where] |= _PR_MISSED_IO;
01182               } else {
01183                      DoneWaitingOnThisThread(thread);
01184               }
01185        }
01186 
01187        SignalIdleSemaphore();
01188 }
01189 
01190 PRInt32 _MD_accept(PRFileDesc *fd, PRNetAddr *addr, PRUint32 *addrlen, PRIntervalTime timeout)
01191 {
01192     OSStatus err;
01193     EndpointRef endpoint = (EndpointRef) fd->secret->md.osfd;
01194     PRThread *me = _PR_MD_CURRENT_THREAD();
01195     TBind bindReq;
01196     PRNetAddr bindAddr;
01197     PRInt32 newosfd = -1;
01198     TCall call;
01199     PRNetAddr callAddr;
01200     RawEndpointAndThread *endthr = NULL;
01201 
01202     if (endpoint == NULL) {
01203         err = kEBADFErr;
01204         goto ErrorExit;
01205     }
01206         
01207     memset(&call, 0 , sizeof(call));
01208 
01209     if (addr != NULL) {
01210         call.addr.maxlen = *addrlen;
01211         call.addr.len = *addrlen;
01212         call.addr.buf = (UInt8*) addr;
01213     } else {
01214         call.addr.maxlen = sizeof(callAddr);
01215         call.addr.len = sizeof(callAddr);
01216         call.addr.buf = (UInt8*) &callAddr;
01217     }
01218 
01219        do {
01220            PrepareForAsyncCompletion(me, fd->secret->md.osfd);
01221            fd->secret->md.misc.thread = me;
01222            
01223            // Perform the listen. 
01224            err = OTListen (endpoint, &call);
01225            if (err == kOTNoError)
01226               break; // got the call information
01227            else if ((!fd->secret->nonblocking) && (err == kOTNoDataErr)) {
01228                WaitOnThisThread(me, timeout);
01229                err = me->md.osErrCode;
01230                if ((err != kOTNoError) && (err != kOTNoDataErr))
01231                      goto ErrorExit;
01232                      // we can get kOTNoError here, but still need
01233                      // to loop back to call OTListen, in order
01234                      // to get call info for OTAccept
01235            } else {
01236               goto ErrorExit; // we're nonblocking, and/or we got an error
01237            }   
01238        }
01239        while(1);
01240 
01241     newosfd = _MD_socket(AF_INET, SOCK_STREAM, 0);
01242     if (newosfd == -1)
01243         return -1;
01244             
01245        // Attach the raw endpoint handler to this endpoint for now.
01246        endthr = (RawEndpointAndThread *) PR_Malloc(sizeof(RawEndpointAndThread));
01247        endthr->thread = me;
01248        endthr->endpoint = (EndpointRef) newosfd;
01249        
01250        err = OTInstallNotifier((ProviderRef) newosfd, RawEndpointNotifierRoutineUPP, endthr);
01251     PR_ASSERT(err == kOTNoError);
01252     
01253        err = OTSetAsynchronous((EndpointRef) newosfd);
01254        PR_ASSERT(err == kOTNoError);
01255 
01256     // Bind to a local port; let the system assign it.
01257     bindAddr.inet.family = AF_INET;
01258     bindAddr.inet.port = bindAddr.inet.ip = 0;
01259 
01260     bindReq.addr.maxlen = PR_NETADDR_SIZE (&bindAddr);
01261     bindReq.addr.len = 0;
01262     bindReq.addr.buf = (UInt8*) &bindAddr;
01263     bindReq.qlen = 0;
01264 
01265     PrepareForAsyncCompletion(me, newosfd);    
01266     err = OTBind((EndpointRef) newosfd, &bindReq, NULL);
01267     if (err != kOTNoError)
01268         goto ErrorExit;
01269 
01270     WaitOnThisThread(me, timeout);
01271 
01272     err = me->md.osErrCode;
01273     if (err != kOTNoError)
01274         goto ErrorExit;
01275 
01276     PrepareForAsyncCompletion(me, newosfd);    
01277 
01278     err = OTAccept (endpoint, (EndpointRef) newosfd, &call);
01279        if ((err != kOTNoError) && (err != kOTNoDataErr))
01280         goto ErrorExit;
01281 
01282     WaitOnThisThread(me, timeout);
01283 
01284     err = me->md.osErrCode;
01285     if (err != kOTNoError)
01286         goto ErrorExit;
01287 
01288     if (addrlen != NULL)
01289         *addrlen = call.addr.len;
01290 
01291        // Remove the temporary notifier we installed to set up the new endpoint.
01292        OTRemoveNotifier((EndpointRef) newosfd);
01293        PR_Free(endthr); // free the temporary context we set up for this endpoint
01294 
01295     return newosfd;
01296 
01297 ErrorExit:
01298        me->io_pending = PR_FALSE; // clear pending wait state if any
01299     if (newosfd != -1)
01300         _MD_closesocket(newosfd);
01301     macsock_map_error(err);
01302     return -1;
01303 }
01304 
01305 
01306 PRInt32 _MD_connect(PRFileDesc *fd, PRNetAddr *addr, PRUint32 addrlen, PRIntervalTime timeout)
01307 {
01308     OSStatus err;
01309     EndpointRef endpoint = (EndpointRef) fd->secret->md.osfd;
01310     PRThread *me = _PR_MD_CURRENT_THREAD();
01311     TCall sndCall;
01312     TBind bindReq;
01313     PRNetAddr bindAddr;
01314 
01315     if (endpoint == NULL) {
01316         err = kEBADFErr;
01317         goto ErrorExit;
01318     }
01319         
01320     if (addr == NULL) {
01321         err = kEFAULTErr;
01322         goto ErrorExit;
01323     }
01324     
01325     // Bind to a local port; let the system assign it.
01326 
01327     bindAddr.inet.family = AF_INET;
01328     bindAddr.inet.port = bindAddr.inet.ip = 0;
01329 
01330     bindReq.addr.maxlen = PR_NETADDR_SIZE (&bindAddr);
01331     bindReq.addr.len = 0;
01332     bindReq.addr.buf = (UInt8*) &bindAddr;
01333     bindReq.qlen = 0;
01334     
01335     PR_Lock(fd->secret->md.miscLock);
01336     PrepareForAsyncCompletion(me, fd->secret->md.osfd);    
01337     fd->secret->md.misc.thread = me;
01338 
01339     err = OTBind(endpoint, &bindReq, NULL);
01340     if (err != kOTNoError) {
01341       me->io_pending = PR_FALSE;
01342       PR_Unlock(fd->secret->md.miscLock);
01343       goto ErrorExit;
01344     }
01345 
01346     WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT);
01347     PR_Unlock(fd->secret->md.miscLock);
01348 
01349     err = me->md.osErrCode;
01350     if (err != kOTNoError)
01351         goto ErrorExit;
01352 
01353     memset(&sndCall, 0 , sizeof(sndCall));
01354 
01355     sndCall.addr.maxlen = addrlen;
01356     sndCall.addr.len = addrlen;
01357     sndCall.addr.buf = (UInt8*) addr;
01358 
01359     if (!fd->secret->nonblocking) {    
01360       PrepareForAsyncCompletion(me, fd->secret->md.osfd);
01361       PR_ASSERT(fd->secret->md.write.thread == NULL);
01362       fd->secret->md.write.thread = me;
01363     }
01364 
01365     err = OTConnect (endpoint, &sndCall, NULL);
01366     if (err == kOTNoError) {
01367       PR_ASSERT(!"OTConnect returned kOTNoError in async mode!?!");   
01368     }
01369     if (fd->secret->nonblocking) {
01370       if (err == kOTNoDataErr)
01371       err = EINPROGRESS;
01372       goto ErrorExit;
01373     } else {
01374       if (err != kOTNoError && err != kOTNoDataErr) {
01375         me->io_pending = PR_FALSE;
01376         goto ErrorExit;
01377       }
01378     }
01379        
01380     WaitOnThisThread(me, timeout);
01381 
01382     err = me->md.osErrCode;
01383     if (err != kOTNoError)
01384         goto ErrorExit;
01385 
01386     return kOTNoError;
01387 
01388 ErrorExit:
01389     macsock_map_error(err);
01390     return -1;
01391 }
01392 
01393 
01394 // Errors:
01395 // EBADF -- bad socket id
01396 // EFAULT -- bad buffer
01397 static PRInt32 SendReceiveStream(PRFileDesc *fd, void *buf, PRInt32 amount, 
01398                                PRIntn flags, PRIntervalTime timeout, SndRcvOpCode opCode)
01399 {
01400     OSStatus err;
01401     OTResult result;
01402     EndpointRef endpoint = (EndpointRef) fd->secret->md.osfd;
01403     PRThread *me = _PR_MD_CURRENT_THREAD();
01404     PRInt32 bytesLeft = amount;
01405 
01406     PR_ASSERT(flags == 0 ||
01407         (opCode == kSTREAM_RECEIVE && flags == PR_MSG_PEEK));
01408     PR_ASSERT(opCode == kSTREAM_SEND || opCode == kSTREAM_RECEIVE);
01409     
01410     if (endpoint == NULL) {
01411         err = kEBADFErr;
01412         goto ErrorExit;
01413     }
01414         
01415     if (buf == NULL) {
01416         err = kEFAULTErr;
01417         goto ErrorExit;
01418     }
01419 
01420     PR_ASSERT(opCode == kSTREAM_SEND ? fd->secret->md.write.thread == NULL :
01421                                        fd->secret->md.read.thread  == NULL);
01422 
01423     while (bytesLeft > 0)
01424     {
01425         Boolean disabledNotifications = OTEnterNotifier(endpoint);
01426     
01427         PrepareForAsyncCompletion(me, fd->secret->md.osfd);    
01428 
01429         if (opCode == kSTREAM_SEND) {
01430               do {
01431                             fd->secret->md.write.thread = me;
01432                             fd->secret->md.writeReady = PR_FALSE;                          // expect the worst
01433                    result = OTSnd(endpoint, buf, bytesLeft, NULL);
01434                             fd->secret->md.writeReady = (result != kOTFlowErr);
01435                             if (fd->secret->nonblocking)                                                 // hope for the best
01436                                    break;
01437                             else {
01438 
01439                                    // We drop through on anything other than a blocking write.
01440                                    if (result != kOTFlowErr)
01441                                           break;
01442 
01443                                    // Blocking write, but the pipe is full. Turn notifications on and
01444                                    // wait for an event, hoping that it's a T_GODATA event.
01445                     if (disabledNotifications) {
01446                         OTLeaveNotifier(endpoint);
01447                         disabledNotifications = false;
01448                     }
01449                                    WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT);
01450                                    result = me->md.osErrCode;
01451                                    if (result != kOTNoError) // got interrupted, or some other error
01452                                           break;
01453 
01454                                    // Prepare to loop back and try again
01455                                    disabledNotifications = OTEnterNotifier(endpoint);
01456                                    PrepareForAsyncCompletion(me, fd->secret->md.osfd);  
01457                             }
01458                      }
01459                      while(1);
01460         } else {
01461               do {
01462                             fd->secret->md.read.thread = me;
01463                             fd->secret->md.readReady = PR_FALSE;                           // expect the worst                
01464                    result = OTRcv(endpoint, buf, bytesLeft, NULL);
01465                    if (fd->secret->nonblocking) {
01466                                    fd->secret->md.readReady = (result != kOTNoDataErr);
01467                                    break;
01468                             } else {
01469                                    if (result != kOTNoDataErr) {
01470                                    // If we successfully read a blocking socket, check for more data.
01471                                    // According to IM:OT, we should be able to rely on OTCountDataBytes
01472                                    // to tell us whether there is a nonzero amount of data pending.
01473                                    size_t count;
01474                                    OSErr tmpResult;
01475                                    tmpResult = OTCountDataBytes(endpoint, &count);
01476                                     fd->secret->md.readReady = ((tmpResult == kOTNoError) && (count > 0));
01477                                           break;
01478                                 }
01479 
01480                                    // Blocking read, but no data available. Turn notifications on and
01481                                    // wait for an event on this endpoint, and hope that we get a T_DATA event.
01482                     if (disabledNotifications) {
01483                         OTLeaveNotifier(endpoint);
01484                         disabledNotifications = false;
01485                     }
01486                                    WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT);
01487                                    result = me->md.osErrCode;
01488                                    if (result != kOTNoError) // interrupted thread, etc.
01489                                           break;
01490 
01491                                    // Prepare to loop back and try again
01492                                    disabledNotifications = OTEnterNotifier(endpoint);
01493                                    PrepareForAsyncCompletion(me, fd->secret->md.osfd);  
01494                             }
01495                      }
01496                      // Retry read if we had to wait for data to show up.
01497                      while(1);
01498         }
01499 
01500               me->io_pending = PR_FALSE;
01501               
01502         if (opCode == kSTREAM_SEND)
01503             fd->secret->md.write.thread = NULL;
01504         else
01505             fd->secret->md.read.thread  = NULL;
01506 
01507         // turn notifications back on
01508         if (disabledNotifications)
01509             OTLeaveNotifier(endpoint);
01510 
01511         if (result > 0) {
01512             buf = (void *) ( (UInt32) buf + (UInt32)result );
01513             bytesLeft -= result;
01514             if (opCode == kSTREAM_RECEIVE) {
01515                 amount = result;
01516                 goto NormalExit;
01517             }
01518         } else {
01519                      switch (result) {
01520                             case kOTLookErr:
01521                                 PR_ASSERT(!"call to OTLook() required after all.");
01522                                    break;
01523                             
01524                             case kOTFlowErr:
01525                             case kOTNoDataErr:
01526                             case kEAGAINErr:
01527                             case kEWOULDBLOCKErr:
01528                                    if (fd->secret->nonblocking) {
01529                                    
01530                                        if (bytesLeft == amount) {  // no data was sent
01531                                               err = result;
01532                                               goto ErrorExit;
01533                                           }
01534                                           
01535                                           // some data was sent
01536                                           amount -= bytesLeft;
01537                                           goto NormalExit;
01538                                    }
01539 
01540                                    WaitOnThisThread(me, timeout);
01541                                    err = me->md.osErrCode;
01542                                    if (err != kOTNoError)
01543                                           goto ErrorExit;                           
01544                                    break;
01545                                    
01546                             case kOTOutStateErr: // if provider already closed, fall through to handle error
01547                                    if (fd->secret->md.orderlyDisconnect) {
01548                                           amount = 0;
01549                                           goto NormalExit;
01550                                    }
01551                                    // else fall through
01552                             default:
01553                                    err = result;
01554                                    goto ErrorExit;
01555                      }
01556               }
01557     }
01558 
01559 NormalExit:
01560     PR_ASSERT(opCode == kSTREAM_SEND ? fd->secret->md.write.thread == NULL :
01561                                        fd->secret->md.read.thread  == NULL);
01562     return amount;
01563 
01564 ErrorExit:
01565     PR_ASSERT(opCode == kSTREAM_SEND ? fd->secret->md.write.thread == NULL :
01566                                        fd->secret->md.read.thread  == NULL);
01567     macsock_map_error(err);
01568     return -1;
01569 }
01570 
01571 
01572 PRInt32 _MD_recv(PRFileDesc *fd, void *buf, PRInt32 amount, 
01573                                PRIntn flags, PRIntervalTime timeout)
01574 {
01575     return (SendReceiveStream(fd, buf, amount, flags, timeout, kSTREAM_RECEIVE));
01576 }
01577 
01578 
01579 PRInt32 _MD_send(PRFileDesc *fd,const void *buf, PRInt32 amount, 
01580                                PRIntn flags, PRIntervalTime timeout)
01581 {
01582     return (SendReceiveStream(fd, (void *)buf, amount, flags, timeout, kSTREAM_SEND));
01583 }
01584 
01585 
01586 // Errors:
01587 // EBADF -- bad socket id
01588 // EFAULT -- bad buffer
01589 static PRInt32 SendReceiveDgram(PRFileDesc *fd, void *buf, PRInt32 amount, 
01590                                PRIntn flags, PRNetAddr *addr, PRUint32 *addrlen, 
01591                                PRIntervalTime timeout, SndRcvOpCode opCode)
01592 {
01593     OSStatus err;
01594     EndpointRef endpoint = (EndpointRef) fd->secret->md.osfd;
01595     PRThread *me = _PR_MD_CURRENT_THREAD();
01596     PRInt32 bytesLeft = amount;
01597     TUnitData dgram;
01598 
01599     PR_ASSERT(flags == 0);
01600     
01601     if (endpoint == NULL) {
01602         err = kEBADFErr;
01603         goto ErrorExit;
01604     }
01605         
01606     if (buf == NULL || addr == NULL) {
01607         err = kEFAULTErr;
01608         goto ErrorExit;
01609     }
01610     
01611     if (opCode != kDGRAM_SEND && opCode != kDGRAM_RECEIVE) {
01612         err = kEINVALErr;
01613         goto ErrorExit;
01614     }
01615         
01616     memset(&dgram, 0 , sizeof(dgram));
01617     dgram.addr.maxlen = *addrlen;
01618     dgram.addr.len = *addrlen;
01619     dgram.addr.buf = (UInt8*) addr;
01620     dgram.udata.maxlen = amount;
01621     dgram.udata.len = amount;
01622     dgram.udata.buf = (UInt8*) buf;    
01623 
01624     while (bytesLeft > 0) {
01625     
01626         PrepareForAsyncCompletion(me, fd->secret->md.osfd);    
01627 
01628         if (opCode == kDGRAM_SEND) {
01629                      fd->secret->md.write.thread = me;
01630                      fd->secret->md.writeReady = PR_FALSE;                          // expect the worst
01631             err = OTSndUData(endpoint, &dgram);
01632                      if (err != kOTFlowErr)                                                // hope for the best
01633                             fd->secret->md.writeReady = PR_TRUE;
01634               } else {
01635                      fd->secret->md.read.thread = me;
01636                      fd->secret->md.readReady = PR_FALSE;                           // expect the worst                
01637             err = OTRcvUData(endpoint, &dgram, NULL);
01638                      if (err != kOTNoDataErr)                                              // hope for the best
01639                             fd->secret->md.readReady = PR_TRUE;
01640               }
01641 
01642         if (err == kOTNoError) {
01643             buf = (void *) ( (UInt32) buf + (UInt32)dgram.udata.len );
01644             bytesLeft -= dgram.udata.len;
01645             dgram.udata.buf = (UInt8*) buf;    
01646             me->io_pending = PR_FALSE;
01647         } else {
01648             PR_ASSERT(err == kOTNoDataErr || err == kOTOutStateErr);
01649             WaitOnThisThread(me, timeout);
01650             err = me->md.osErrCode;
01651             if (err != kOTNoError)
01652                 goto ErrorExit;
01653         }
01654     }
01655 
01656     if (opCode == kDGRAM_RECEIVE)
01657         *addrlen = dgram.addr.len;
01658 
01659     return amount;
01660 
01661 ErrorExit:
01662     macsock_map_error(err);
01663     return -1;
01664 }
01665 
01666 
01667 PRInt32 _MD_recvfrom(PRFileDesc *fd, void *buf, PRInt32 amount, 
01668                                PRIntn flags, PRNetAddr *addr, PRUint32 *addrlen,
01669                                PRIntervalTime timeout)
01670 {
01671     return (SendReceiveDgram(fd, buf, amount, flags, addr, addrlen,
01672                             timeout, kDGRAM_RECEIVE));
01673 }
01674 
01675 
01676 PRInt32 _MD_sendto(PRFileDesc *fd,const void *buf, PRInt32 amount, 
01677                                PRIntn flags, PRNetAddr *addr, PRUint32 addrlen,
01678                                PRIntervalTime timeout)
01679 {
01680     return (SendReceiveDgram(fd, (void *)buf, amount, flags, addr, &addrlen,
01681                             timeout, kDGRAM_SEND));
01682 }
01683 
01684 
01685 PRInt32 _MD_closesocket(PRInt32 osfd)
01686 {
01687     OSStatus err;
01688     EndpointRef endpoint = (EndpointRef) osfd;
01689     PRThread *me = _PR_MD_CURRENT_THREAD();
01690 
01691     if (endpoint == NULL) {
01692         err = kEBADFErr;
01693         goto ErrorExit;
01694     }
01695         
01696     if (me->io_pending && me->io_fd == osfd)
01697         me->io_pending = PR_FALSE;
01698 
01699     (void) OTSndOrderlyDisconnect(endpoint);
01700     err = OTCloseProvider(endpoint);
01701     if (err != kOTNoError)
01702         goto ErrorExit;
01703 
01704     return kOTNoError;
01705 
01706 ErrorExit:
01707     macsock_map_error(err);
01708     return -1;
01709 }
01710 
01711 
01712 PRInt32 _MD_writev(PRFileDesc *fd, const struct PRIOVec *iov, PRInt32 iov_size, PRIntervalTime timeout)
01713 {
01714 #pragma unused (fd, iov, iov_size, timeout)
01715 
01716     PR_ASSERT(0);
01717     _PR_MD_CURRENT_THREAD()->md.osErrCode = unimpErr;
01718     return -1;
01719 }
01720 
01721 // OT endpoint states are documented here:
01722 // http://gemma.apple.com/techpubs/mac/NetworkingOT/NetworkingWOT-27.html#MARKER-9-65
01723 //
01724 static PRBool GetState(PRFileDesc *fd, PRBool *readReady, PRBool *writeReady, PRBool *exceptReady)
01725 {
01726     OTResult resultOT;
01727     // hack to emulate BSD sockets; say that a socket that has disconnected
01728     // is still readable.
01729     size_t   availableData = 1;
01730     if (!fd->secret->md.orderlyDisconnect)
01731         OTCountDataBytes((EndpointRef)fd->secret->md.osfd, &availableData);
01732 
01733     *readReady = fd->secret->md.readReady && (availableData > 0);
01734     *exceptReady = fd->secret->md.exceptReady;
01735 
01736     resultOT = OTGetEndpointState((EndpointRef)fd->secret->md.osfd);
01737     switch (resultOT) {
01738         case T_IDLE:
01739         case T_UNBND:
01740             // the socket is not connected. Emulating BSD sockets,
01741             // we mark it readable and writable. The next PR_Read
01742             // or PR_Write will then fail. Usually, in this situation,
01743             // fd->secret->md.exceptReady is also set, and returned if
01744             // anyone is polling for it.
01745             *readReady = PR_FALSE;
01746             *writeReady = PR_FALSE;
01747             break;
01748 
01749         case T_DATAXFER:        // data transfer
01750             *writeReady = fd->secret->md.writeReady;
01751             break;
01752 
01753         case T_INREL:           // incoming orderly release
01754             *writeReady = fd->secret->md.writeReady;
01755             break;
01756 
01757         case T_OUTCON:          // outgoing connection pending  
01758         case T_INCON:           // incoming connection pending
01759         case T_OUTREL:          // outgoing orderly release
01760         default:
01761             *writeReady = PR_FALSE;
01762     }
01763     
01764     return  *readReady || *writeReady || *exceptReady;
01765 }
01766 
01767 // check to see if any of the poll descriptors have data available
01768 // for reading or writing, by calling their poll methods (layered IO).
01769 static PRInt32 CheckPollDescMethods(PRPollDesc *pds, PRIntn npds, PRInt16 *outReadFlags, PRInt16 *outWriteFlags)
01770 {
01771     PRInt32     ready = 0;
01772     PRPollDesc  *pd, *epd;
01773     PRInt16     *readFlag, *writeFlag;
01774     
01775     for (pd = pds, epd = pd + npds, readFlag = outReadFlags, writeFlag = outWriteFlags;
01776         pd < epd;
01777         pd++, readFlag++, writeFlag++)
01778     {
01779         PRInt16  in_flags_read = 0,  in_flags_write = 0;
01780         PRInt16 out_flags_read = 0, out_flags_write = 0;
01781 
01782         pd->out_flags = 0;
01783 
01784         if (NULL == pd->fd || pd->in_flags == 0) continue;
01785 
01786         if (pd->in_flags & PR_POLL_READ)
01787         {
01788             in_flags_read = (pd->fd->methods->poll)(
01789                 pd->fd, pd->in_flags & ~PR_POLL_WRITE, &out_flags_read);
01790         }
01791 
01792         if (pd->in_flags & PR_POLL_WRITE)
01793         {
01794             in_flags_write = (pd->fd->methods->poll)(
01795                 pd->fd, pd->in_flags & ~PR_POLL_READ, &out_flags_write);
01796         }
01797 
01798         if ((0 != (in_flags_read & out_flags_read)) ||
01799             (0 != (in_flags_write & out_flags_write)))
01800         {
01801             ready += 1;  /* some layer has buffer input */
01802             pd->out_flags = out_flags_read | out_flags_write;
01803         }
01804         
01805         *readFlag = in_flags_read;
01806         *writeFlag = in_flags_write;
01807     }
01808 
01809     return ready;
01810 }
01811 
01812 // check to see if any of OT endpoints of the poll descriptors have data available
01813 // for reading or writing.
01814 static PRInt32 CheckPollDescEndpoints(PRPollDesc *pds, PRIntn npds, const PRInt16 *inReadFlags, const PRInt16 *inWriteFlags)
01815 {
01816     PRInt32 ready = 0;
01817     PRPollDesc *pd, *epd;
01818     const PRInt16   *readFlag, *writeFlag;
01819     
01820     for (pd = pds, epd = pd + npds, readFlag = inReadFlags, writeFlag = inWriteFlags;
01821          pd < epd;
01822         pd++, readFlag++, writeFlag++)
01823     {
01824         PRFileDesc *bottomFD;
01825         PRBool      readReady, writeReady, exceptReady;
01826         PRInt16     in_flags_read = *readFlag;
01827         PRInt16     in_flags_write = *writeFlag;
01828 
01829         if (NULL == pd->fd || pd->in_flags == 0) continue;
01830 
01831         if ((pd->in_flags & ~pd->out_flags) == 0) {
01832             ready++;
01833             continue;
01834         }
01835 
01836         bottomFD = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER);
01837         /* bottomFD can be NULL for pollable sockets */
01838         if (bottomFD)
01839         {
01840             if (_PR_FILEDESC_OPEN == bottomFD->secret->state)
01841             {
01842                 if (GetState(bottomFD, &readReady, &writeReady, &exceptReady))
01843                 {
01844                     if (readReady)
01845                     {
01846                         if (in_flags_read & PR_POLL_READ)
01847                             pd->out_flags |= PR_POLL_READ;
01848                         if (in_flags_write & PR_POLL_READ)
01849                             pd->out_flags |= PR_POLL_WRITE;
01850                     }
01851                     if (writeReady)
01852                     {
01853                         if (in_flags_read & PR_POLL_WRITE)
01854                             pd->out_flags |= PR_POLL_READ;
01855                         if (in_flags_write & PR_POLL_WRITE)
01856                             pd->out_flags |= PR_POLL_WRITE;
01857                     }
01858                     if (exceptReady && (pd->in_flags & PR_POLL_EXCEPT))
01859                     {
01860                         pd->out_flags |= PR_POLL_EXCEPT;
01861                     }
01862                 }
01863                 if (0 != pd->out_flags) ready++;
01864             }
01865             else    /* bad state */
01866             {
01867                 ready += 1;  /* this will cause an abrupt return */
01868                 pd->out_flags = PR_POLL_NVAL;  /* bogii */
01869             }
01870         }
01871     }
01872 
01873     return ready;
01874 }
01875 
01876 
01877 // see how many of the poll descriptors are ready
01878 static PRInt32 CountReadyPollDescs(PRPollDesc *pds, PRIntn npds)
01879 {
01880     PRInt32 ready = 0;
01881     PRPollDesc *pd, *epd;
01882     
01883     for (pd = pds, epd = pd + npds; pd < epd; pd++)
01884     {
01885         if (pd->out_flags)
01886             ready ++;
01887     }
01888 
01889     return ready;
01890 }
01891 
01892 // set or clear the poll thread on the poll descriptors
01893 static void SetDescPollThread(PRPollDesc *pds, PRIntn npds, PRThread* thread)
01894 {
01895     PRInt32     ready = 0;
01896     PRPollDesc *pd, *epd;
01897 
01898     for (pd = pds, epd = pd + npds; pd < epd; pd++)
01899     {   
01900         if (pd->fd)
01901         { 
01902             PRFileDesc *bottomFD = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER);
01903             if (bottomFD && (_PR_FILEDESC_OPEN == bottomFD->secret->state))
01904             {
01905                 if (pd->in_flags & PR_POLL_READ) {
01906                     PR_ASSERT(thread == NULL || bottomFD->secret->md.read.thread == NULL);
01907                     bottomFD->secret->md.read.thread = thread;
01908                 }
01909 
01910                 if (pd->in_flags & PR_POLL_WRITE) {
01911                     // it's possible for the writing thread to be non-null during
01912                     // a non-blocking connect, so we assert that we're on
01913                     // the same thread, or the thread is null.
01914                     // Note that it's strictly possible for the connect and poll
01915                     // to be on different threads, so ideally we need to assert
01916                     // that if md.write.thread is non-null, there is a non-blocking
01917                     // connect in progress.
01918                     PR_ASSERT(thread == NULL ||
01919                         (bottomFD->secret->md.write.thread == NULL ||
01920                          bottomFD->secret->md.write.thread == thread));
01921                     bottomFD->secret->md.write.thread = thread;
01922                 }
01923             }
01924         }
01925     }
01926 }
01927 
01928 
01929 #define DESCRIPTOR_FLAGS_ARRAY_SIZE     32
01930 
01931 PRInt32 _MD_poll(PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout)
01932 {
01933     PRInt16     readFlagsArray[DESCRIPTOR_FLAGS_ARRAY_SIZE];
01934     PRInt16     writeFlagsArray[DESCRIPTOR_FLAGS_ARRAY_SIZE];
01935     
01936     PRInt16     *readFlags  = readFlagsArray;
01937     PRInt16     *writeFlags = writeFlagsArray;
01938 
01939     PRInt16     *ioFlags = NULL;
01940     
01941     PRThread    *thread = _PR_MD_CURRENT_THREAD();
01942     PRInt32     ready;
01943     
01944     if (npds > DESCRIPTOR_FLAGS_ARRAY_SIZE)
01945     {
01946         // we allocate a single double-size array. The first half is used
01947         // for read flags, and the second half for write flags.
01948         ioFlags = (PRInt16*)PR_Malloc(sizeof(PRInt16) * npds * 2);
01949         if (!ioFlags)
01950         {
01951             PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
01952             return -1;
01953         }
01954         
01955         readFlags = ioFlags;
01956         writeFlags = &ioFlags[npds];
01957     }
01958 
01959     // we have to be outside the lock when calling this, since
01960     // it can call arbitrary user code (including other socket
01961     // entry points)
01962     ready = CheckPollDescMethods(pds, npds, readFlags, writeFlags);
01963 
01964     if (!ready && timeout != PR_INTERVAL_NO_WAIT) {
01965         intn        is;
01966         
01967 
01968         _PR_INTSOFF(is);
01969         PR_Lock(thread->md.asyncIOLock);
01970         PrepareForAsyncCompletion(thread, 0);
01971 
01972         SetDescPollThread(pds, npds, thread);
01973 
01974         (void)CheckPollDescEndpoints(pds, npds, readFlags, writeFlags);
01975 
01976         PR_Unlock(thread->md.asyncIOLock);
01977         _PR_FAST_INTSON(is);
01978 
01979         ready = CountReadyPollDescs(pds, npds);
01980 
01981         if (ready == 0) {
01982             WaitOnThisThread(thread, timeout);
01983 
01984             // since we may have been woken by a pollable event firing,
01985             // we have to check both poll methods and endpoints.
01986             (void)CheckPollDescMethods(pds, npds, readFlags, writeFlags);
01987             ready = CheckPollDescEndpoints(pds, npds, readFlags, writeFlags);
01988         }
01989         
01990         thread->io_pending = PR_FALSE;
01991         SetDescPollThread(pds, npds, NULL);
01992     }
01993     else {
01994         ready = CheckPollDescEndpoints(pds, npds, readFlags, writeFlags);
01995     }
01996 
01997     if (readFlags != readFlagsArray)
01998         PR_Free(ioFlags);
01999     
02000     return ready;
02001 }
02002 
02003 
02004 void _MD_initfiledesc(PRFileDesc *fd)
02005 {
02006        // Allocate a PR_Lock to arbitrate miscellaneous OT calls for this endpoint between threads
02007        // We presume that only one thread will be making Read calls (Recv/Accept) and that only
02008        // one thread will be making Write calls (Send/Connect) on the endpoint at a time.
02009        if (fd->methods->file_type == PR_DESC_SOCKET_TCP ||
02010               fd->methods->file_type == PR_DESC_SOCKET_UDP )
02011        {
02012               PR_ASSERT(fd->secret->md.miscLock == NULL);
02013               fd->secret->md.miscLock = PR_NewLock();
02014               PR_ASSERT(fd->secret->md.miscLock != NULL);
02015               fd->secret->md.orderlyDisconnect = PR_FALSE;
02016               fd->secret->md.readReady = PR_FALSE;             // let's not presume we have data ready to read
02017               fd->secret->md.writeReady = PR_TRUE;             // let's presume we can write unless we hear otherwise
02018               fd->secret->md.exceptReady = PR_FALSE;
02019        }
02020 }
02021 
02022 
02023 void _MD_freefiledesc(PRFileDesc *fd)
02024 {
02025        if (fd->secret->md.miscLock)
02026        {
02027               PR_ASSERT(fd->methods->file_type == PR_DESC_SOCKET_TCP || fd->methods->file_type == PR_DESC_SOCKET_UDP);
02028               PR_DestroyLock(fd->secret->md.miscLock);
02029               fd->secret->md.miscLock = NULL;
02030        } else {
02031               PR_ASSERT(fd->methods->file_type != PR_DESC_SOCKET_TCP && PR_DESC_SOCKET_TCP != PR_DESC_SOCKET_UDP);
02032        }
02033 }
02034 
02035 // _MD_makenonblock is also used for sockets meant to be used for blocking I/O,
02036 // in order to install the notifier routine for async completion.
02037 void _MD_makenonblock(PRFileDesc *fd)
02038 {
02039        // We simulate non-blocking mode using async mode rather
02040        // than put the endpoint in non-blocking mode.
02041        // We need to install the PRFileDesc as the contextPtr for the NotifierRoutine, but it
02042        // didn't exist at the time the endpoint was created.  It does now though...
02043        ProviderRef   endpointRef = (ProviderRef)fd->secret->md.osfd;
02044        OSStatus      err;
02045        
02046        // Install fd->secret as the contextPtr for the Notifier function associated with this 
02047        // endpoint. We use this instead of the fd itself because:
02048        //            (a) in cases where you import I/O layers, the containing 
02049        //                fd changes, but the secret structure does not;
02050        //            (b) the notifier func refers only to the secret data structure
02051        //                anyway.
02052        err = OTInstallNotifier(endpointRef, NotifierRoutineUPP, fd->secret);
02053        PR_ASSERT(err == kOTNoError);
02054        
02055        // Now that we have a NotifierRoutine installed, we can make the endpoint asynchronous
02056        err = OTSetAsynchronous(endpointRef);
02057        PR_ASSERT(err == kOTNoError);
02058 }
02059 
02060 
02061 void _MD_initfdinheritable(PRFileDesc *fd, PRBool imported)
02062 {
02063        /* XXX this function needs to be implemented */
02064        fd->secret->inheritable = _PR_TRI_UNKNOWN;
02065 }
02066 
02067 
02068 void _MD_queryfdinheritable(PRFileDesc *fd)
02069 {
02070        /* XXX this function needs to be implemented */
02071        PR_ASSERT(0);
02072 }
02073 
02074 
02075 PR_IMPLEMENT(PRInt32) _MD_shutdown(PRFileDesc *fd, PRIntn how)
02076 {
02077 #pragma unused (fd, how)
02078 
02079 /* Just succeed silently!!! */
02080 return (0);
02081 }
02082 
02083 
02084 PR_IMPLEMENT(PRStatus) 
02085 _MD_getpeername(PRFileDesc *fd, PRNetAddr *addr, PRUint32 *addrlen)
02086 {
02087     PRThread *me = _PR_MD_CURRENT_THREAD();
02088        EndpointRef ep = (EndpointRef) fd->secret->md.osfd;
02089        InetAddress inetAddr;
02090        TBind peerAddr;
02091        OSErr err;
02092        
02093        if (*addrlen < sizeof(InetAddress)) {
02094 
02095               err = (OSErr) kEINVALErr;
02096               goto ErrorExit;
02097        }
02098 
02099     peerAddr.addr.maxlen = sizeof(InetAddress);
02100     peerAddr.addr.len = 0;
02101     peerAddr.addr.buf = (UInt8*) &inetAddr;
02102     peerAddr.qlen = 0;
02103 
02104     PrepareForAsyncCompletion(me, fd->secret->md.osfd);    
02105        fd->secret->md.misc.thread = me; // tell notifier routine what to wake up
02106 
02107        err = OTGetProtAddress(ep, NULL, &peerAddr);
02108        
02109     if (err != kOTNoError)
02110         goto ErrorExit;
02111 
02112     WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT);
02113 
02114     err = me->md.osErrCode;
02115     if ((err == kOTNoError) && (peerAddr.addr.len < sizeof(InetAddress)))
02116        err = kEBADFErr; // we don't understand the address we got
02117     if (err != kOTNoError)
02118        goto ErrorExit;
02119        
02120     // Translate the OT peer information into an NSPR address.
02121     addr->inet.family = AF_INET;
02122     addr->inet.port = (PRUint16) inetAddr.fPort;
02123     addr->inet.ip = (PRUint32) inetAddr.fHost;
02124     
02125     *addrlen = PR_NETADDR_SIZE(addr); // return the amount of data obtained
02126        return PR_SUCCESS;
02127 
02128 ErrorExit:
02129     macsock_map_error(err);
02130     return PR_FAILURE;
02131 }
02132 
02133 
02134 PR_IMPLEMENT(unsigned long) inet_addr(const char *cp)
02135 {
02136     OSStatus err;
02137     InetHost host;    
02138 
02139     _MD_FinishInitNetAccess();
02140 
02141     err = OTInetStringToHost((char*) cp, &host);
02142     if (err != kOTNoError)
02143         return -1;
02144     
02145     return host;
02146 }
02147 
02148 
02149 static char *sAliases[1] = {NULL};
02150 static struct hostent sHostEnt = {NULL, &sAliases[0], AF_INET, sizeof (long), NULL};
02151 static InetHostInfo sHostInfo;
02152 static InetHost *sAddresses[kMaxHostAddrs+1];
02153 
02154 
02155 PR_IMPLEMENT(struct hostent *) gethostbyname(const char * name)
02156 {
02157     OSStatus err;
02158     PRUint32 index;
02159     PRThread *me = _PR_MD_CURRENT_THREAD();
02160 
02161        _MD_FinishInitNetAccess();
02162 
02163     me->io_pending       = PR_TRUE;
02164     me->io_fd            = NULL;
02165     me->md.osErrCode     = noErr;
02166        
02167        PR_Lock(dnsContext.lock);   // so we can safely store our thread ptr in dnsContext
02168        dnsContext.thread = me;            // so we know what thread to wake up when OTInetStringToAddress completes
02169 
02170     err = OTInetStringToAddress(dnsContext.serviceRef, (char *)name, &sHostInfo);
02171     if (err != kOTNoError) {
02172         me->io_pending = PR_FALSE;
02173         me->md.osErrCode = err;
02174         goto ErrorExit;
02175     }
02176 
02177     WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT);
02178        PR_Unlock(dnsContext.lock);
02179 
02180     if (me->md.osErrCode != kOTNoError)
02181         goto ErrorExit;
02182 
02183     sHostEnt.h_name = sHostInfo.name;
02184     for (index=0; index<kMaxHostAddrs && sHostInfo.addrs[index] != NULL; index++)
02185         sAddresses[index] = &sHostInfo.addrs[index];
02186     sAddresses[index] = NULL;    
02187     sHostEnt.h_addr_list = (char **)sAddresses;
02188 
02189     return (&sHostEnt);
02190 
02191 ErrorExit:
02192     return NULL;
02193 }
02194 
02195 
02196 PR_IMPLEMENT(struct hostent *) gethostbyaddr(const void *addr, int addrlen, int type)
02197 {
02198     PR_ASSERT(type == AF_INET);
02199     PR_ASSERT(addrlen == sizeof(struct in_addr));
02200 
02201        _MD_FinishInitNetAccess();
02202 
02203     OTInetHostToString((InetHost)addr, sHostInfo.name);
02204     
02205     return (gethostbyname(sHostInfo.name));
02206 }
02207 
02208 
02209 PR_IMPLEMENT(char *) inet_ntoa(struct in_addr addr)
02210 {
02211     _MD_FinishInitNetAccess();
02212 
02213     OTInetHostToString((InetHost)addr.s_addr, sHostInfo.name);
02214     
02215     return sHostInfo.name;
02216 }
02217 
02218 
02219 PRStatus _MD_gethostname(char *name, int namelen)
02220 {
02221     OSStatus err;
02222     InetInterfaceInfo info;
02223 
02224     _MD_FinishInitNetAccess();
02225 
02226     /*
02227      *    On a Macintosh, we don't have the concept of a local host name.
02228      *    We do though have an IP address & everyone should be happy with
02229      *     a string version of that for a name.
02230      *    The alternative here is to ping a local DNS for our name, they
02231      *    will often know it.  This is the cheap, easiest, and safest way out.
02232      */
02233 
02234     /* Make sure the string is as long as the longest possible address */
02235     if (namelen < strlen("123.123.123.123")) {
02236         err = kEINVALErr;
02237         goto ErrorExit;
02238     }
02239 
02240     err = OTInetGetInterfaceInfo(&info, kDefaultInetInterface);
02241     if (err != kOTNoError)
02242         goto ErrorExit;
02243     
02244     OTInetHostToString(info.fAddress, name);
02245     
02246     return PR_SUCCESS;
02247 
02248 ErrorExit:
02249     macsock_map_error(err);
02250     return PR_FAILURE;
02251 }
02252 
02253 
02254 #define kIPName        "ip"
02255 static struct protoent sIPProto = {kIPName, NULL, INET_IP};
02256 static struct protoent sTCPProto = {kTCPName, NULL, INET_TCP};
02257 static struct protoent sUDPProto = {kUDPName, NULL, INET_UDP};
02258 
02259 PR_IMPLEMENT(struct protoent *) getprotobyname(const char * name)
02260 {
02261     if (strcmp(name, kIPName) == 0)
02262         return (&sIPProto);
02263         
02264     if (strcmp(name, kTCPName) == 0)
02265         return (&sTCPProto);
02266         
02267     if (strcmp(name, kUDPName) == 0)
02268         return (&sUDPProto);
02269         
02270 ErrorExit:
02271     macsock_map_error(kEINVALErr);
02272     return NULL;
02273 }
02274 
02275 
02276 PR_IMPLEMENT(struct protoent *) getprotobynumber(int number)
02277 {
02278     if (number == INET_IP)
02279         return (&sIPProto);
02280         
02281     if (number == INET_TCP)
02282         return (&sTCPProto);
02283         
02284     if (number == INET_UDP)
02285         return (&sUDPProto);
02286         
02287 ErrorExit:
02288     macsock_map_error(kEINVALErr);
02289     return NULL;
02290 }
02291 
02292 
02293 int _MD_mac_get_nonblocking_connect_error(PRFileDesc* fd)
02294 {
02295     EndpointRef endpoint = (EndpointRef)fd->secret->md.osfd;
02296     OTResult    resultOT = OTGetEndpointState(endpoint);
02297 
02298     switch (resultOT)    {
02299         case T_OUTCON:
02300             macsock_map_error(EINPROGRESS);
02301             return -1;
02302             
02303         case T_DATAXFER:
02304             return 0;
02305             
02306         case T_IDLE:
02307             macsock_map_error(fd->secret->md.disconnectError);
02308             fd->secret->md.disconnectError = 0;
02309             return -1;
02310 
02311         case T_INREL:
02312             macsock_map_error(ENOTCONN);
02313             return -1;
02314 
02315         default:
02316             PR_ASSERT(0);
02317             return -1;
02318     }
02319 
02320     return -1;      // not reached
02321 }