Fix for Mac OT bugs #2133, #2405, #2451, #2623, #3580 among others. Steve Dagley served as buddy for my changes. This is basically the first half of the redesign for Mac NSPR Sockets. Blocking mode or Server sockets remain to be implemented. RDF_SCRIPTABLE_19990317_BASE SeaMonkey_M3_BASE
authorgordon%netscape.com
Sun, 14 Mar 1999 00:15:39 +0000
changeset 492 e495e4c00fb468c029b48acd87c9d14986fee0ec
parent 491 91c3f3b19cc4e1184fee1afc1306847cd39c039f
child 493 b84183455629e3ef9e47a937696173fc47097cd7
child 494 88b0ae6a12c731df2fe013cefaafe5dc1ca56517
child 495 ea776f3d0d2549007ebc65f546eeeba6340e2134
push idunknown
push userunknown
push dateunknown
Fix for Mac OT bugs #2133, #2405, #2451, #2623, #3580 among others. Steve Dagley served as buddy for my changes. This is basically the first half of the redesign for Mac NSPR Sockets. Blocking mode or Server sockets remain to be implemented.
pr/include/md/_macos.h
pr/include/private/primpl.h
pr/src/io/prio.c
pr/src/md/mac/macsockotpt.c
--- a/pr/include/md/_macos.h
+++ b/pr/include/md/_macos.h
@@ -46,22 +46,21 @@
 #include <setjmp.h>
 #include <Errors.h>
 
 struct _MDProcess {
     PRInt8 notused;
 };
 
 struct _MDThread {
-    jmp_buf jb;
-    int osErrCode;
-	PRLock		*asyncIOLock;
-	PRCondVar	*asyncIOCVar;
-    void *cookie;
-    PRBool notifyPending;
+    jmp_buf      jb;
+    int          osErrCode;
+	PRLock *     asyncIOLock;
+	PRCondVar *  asyncIOCVar;
+    PRBool       notifyPending;
 };
 
 struct _MDThreadStack {
     PRInt8 notused;
 };
 
 struct _MDLock {
     PRInt8 notused;
@@ -78,18 +77,31 @@ struct _MDSemaphore {
 struct _MDSegment {
     PRInt8 notused;
 };
 
 struct _MDCPU {
     PRInt8 notused;
 };
 
+typedef struct _MDSocketCallerInfo {
+	PRThread *	thread;
+	void *		cookie;
+} _MDSocketCallerInfo;
+
 struct _MDFileDesc {
-    PRInt32 osfd;
+    PRInt32     osfd;
+	PRBool      connectionOpen;
+	PRBool      readReady;
+	PRBool      writeReady;
+	PRBool      exceptReady;
+	PRLock *    miscLock;
+	_MDSocketCallerInfo  misc;
+	_MDSocketCallerInfo  read;
+	_MDSocketCallerInfo  write;
 };
 
 /*
 ** Iinitialization Related definitions
 */
 
 #define _MD_EARLY_INIT		_MD_EarlyInit
 #define _MD_FINAL_INIT		_MD_FinalInit
@@ -372,17 +384,18 @@ extern PRStatus _MD_setsockopt(PRFileDes
 #define _MD_ACCEPT			_MD_accept
 #define _MD_CONNECT			_MD_connect
 #define _MD_SEND			_MD_send
 #define _MD_RECV			_MD_recv
 #define _MD_CLOSE_SOCKET	_MD_closesocket
 #define _MD_SENDTO			_MD_sendto
 #define _MD_RECVFROM		_MD_recvfrom
 #define _MD_PR_POLL			_MD_poll
-#define _MD_INIT_FILEDESC(fd)
+#define _MD_INIT_FILEDESC	_MD_initfiledesc
+#define _MD_FREE_FILEDESC	_MD_freefiledesc
 #define _MD_MAKE_NONBLOCK	_MD_makenonblock
 
 #define _MD_GET_SOCKET_ERROR() 		_PR_MD_CURRENT_THREAD()->md.osErrCode
 
 #define _PR_MD_MAP_SELECT_ERROR(x) 	(x)
 /*
 ** Netdb Related definitions
 */
--- a/pr/include/private/primpl.h
+++ b/pr/include/private/primpl.h
@@ -972,16 +972,21 @@ extern char * _PR_MD_READ_DIR(_MDDir *md
 
 extern PRInt32 _PR_MD_CLOSE_DIR(_MDDir *md);
 #define    _PR_MD_CLOSE_DIR _MD_CLOSE_DIR
 
 /* I/O related */
 extern void _PR_MD_INIT_FILEDESC(PRFileDesc *fd);
 #define    _PR_MD_INIT_FILEDESC _MD_INIT_FILEDESC
 
+#ifdef XP_MAC
+extern void _PR_MD_FREE_FILEDESC(PRFileDesc *fd);
+#define    _PR_MD_FREE_FILEDESC _MD_FREE_FILEDESC
+#endif
+
 extern void _PR_MD_MAKE_NONBLOCK(PRFileDesc *fd);
 #define    _PR_MD_MAKE_NONBLOCK _MD_MAKE_NONBLOCK
 
 /* File I/O related */
 extern PRInt32 _PR_MD_OPEN(const char *name, PRIntn osflags, PRIntn mode);
 #define    _PR_MD_OPEN _MD_OPEN
 
 extern PRInt32 _PR_MD_CLOSE_FILE(PRInt32 osfd);
--- a/pr/src/io/prio.c
+++ b/pr/src/io/prio.c
@@ -96,16 +96,19 @@ PR_IMPLEMENT(PRFileDesc*) PR_AllocFileDe
     }
 
     return fd;
 }
 
 PR_IMPLEMENT(void) PR_FreeFileDesc(PRFileDesc *fd)
 {
     PR_ASSERT(fd);
+#ifdef XP_MAC
+	_PR_MD_FREE_FILEDESC(fd);
+#endif
     _PR_Putfd(fd);
 }
 
 /*
 ** Wait for some i/o to finish on one or more more poll descriptors.
 */
 PR_IMPLEMENT(PRInt32) PR_Poll(PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout)
 {
--- a/pr/src/md/mac/macsockotpt.c
+++ b/pr/src/md/mac/macsockotpt.c
@@ -15,92 +15,112 @@
  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  * Reserved.
  */
 
 /* This turns on UNIX style errors in OT 1.1 headers */
 #define OTUNIXERRORS 1
 
 #include <Gestalt.h>
+#include <OpenTransport.h>
 
-/*
-    Since Apple put out new headers without
-    putting in a way to test for them, we found some random symbol which
-    isn't defined in the "1.1" headers.
-*/
-#include <OpenTransport.h>
-#ifdef kOTInvalidStreamRef
-/* old */
-#define GESTALT_OPEN_TPT_PRESENT        gestaltOpenTptPresent
-#define GESTALT_OPEN_TPT_TCP_PRESENT    gestaltOpenTptTCPPresent
-#else
-/* new */
 #define GESTALT_OPEN_TPT_PRESENT        gestaltOpenTptPresentMask
 #define GESTALT_OPEN_TPT_TCP_PRESENT    gestaltOpenTptTCPPresentMask
-#endif
 
 #include <OpenTptInternet.h>    // All the internet typedefs
 #include "primpl.h"
 
 typedef enum SndRcvOpCode {
     kSTREAM_SEND,
-    kSTREAM_RECEIVE    ,
+    kSTREAM_RECEIVE,
     kDGRAM_SEND,
     kDGRAM_RECEIVE
 } SndRcvOpCode;
 
+static struct {
+	PRLock *    lock;
+	InetSvcRef  serviceRef;
+	PRThread *  thread;
+	void *      cookie;
+} dnsContext;
 
-static InetSvcRef sSvcRef;
 
+static pascal void  DNSNotifierRoutine(void * contextPtr, OTEventCode code, OTResult result, void * cookie);
 static pascal void  NotifierRoutine(void * contextPtr, OTEventCode code, 
             OTResult result, void * cookie);
 
-static PRBool GetState(EndpointRef endpoint, PRBool *readReady, PRBool *writeReady, PRBool *exceptReady);
+static PRBool GetState(PRFileDesc *fd, PRBool *readReady, PRBool *writeReady, PRBool *exceptReady);
 
 extern void WaitOnThisThread(PRThread *thread, PRIntervalTime timeout);
 extern void DoneWaitingOnThisThread(PRThread *thread);
 
+
 void _MD_InitNetAccess()
 {
-    OSErr        err;
+    OSErr       err;
     OSStatus    errOT;
-    PRBool         hasOTTCPIP = PR_FALSE;
-    PRBool         hasOT = PR_FALSE;
-    long         gestaltResult;
-    PRThread *me = _PR_MD_CURRENT_THREAD();
+    PRBool      hasOTTCPIP = PR_FALSE;
+    PRBool      hasOT = PR_FALSE;
+    long        gestaltResult;
     
     err = Gestalt(gestaltOpenTpt, &gestaltResult);
     if (err == noErr)
         if (gestaltResult & GESTALT_OPEN_TPT_PRESENT)
             hasOT = PR_TRUE;
     
     if (hasOT)
         if (gestaltResult & GESTALT_OPEN_TPT_TCP_PRESENT)
             hasOTTCPIP = PR_TRUE;
         
     PR_ASSERT(hasOTTCPIP == PR_TRUE);
 
     errOT = InitOpenTransport();
     PR_ASSERT(err == kOTNoError);
+	
+	dnsContext.lock = PR_NewLock();
+	PR_ASSERT(dnsContext.lock != NULL);
 
-    sSvcRef = OTOpenInternetServices(kDefaultInternetServicesPath, NULL, &errOT);
+	dnsContext.thread = _PR_MD_CURRENT_THREAD();
+	dnsContext.cookie = NULL;
+	
+    dnsContext.serviceRef = OTOpenInternetServices(kDefaultInternetServicesPath, NULL, &errOT);
     if (errOT != kOTNoError) return;    /* no network -- oh well */
-    PR_ASSERT((sSvcRef != NULL) && (errOT == kOTNoError));
+    PR_ASSERT((dnsContext.serviceRef != NULL) && (errOT == kOTNoError));
 
     /* Install notify function for DNR Address To String completion */
-    errOT = OTInstallNotifier(sSvcRef, NotifierRoutine, me);
+    errOT = OTInstallNotifier(dnsContext.serviceRef, DNSNotifierRoutine, &dnsContext);
     PR_ASSERT(errOT == kOTNoError);
 
     /* Put us into async mode */
-    errOT = OTSetAsynchronous(sSvcRef);
+    errOT = OTSetAsynchronous(dnsContext.serviceRef);
     PR_ASSERT(errOT == kOTNoError);
 
 /* XXX Does not handle absence of open tpt and tcp yet! */
 }
 
+
+pascal void  DNSNotifierRoutine(void * contextPtr, OTEventCode code, OTResult result, void * cookie)
+{
+#pragma unused(contextPtr)
+    _PRCPU *    cpu    = _PR_MD_CURRENT_CPU(); 
+	
+	if (code == T_DNRSTRINGTOADDRCOMPLETE) {
+		dnsContext.thread->md.osErrCode = result;
+		dnsContext.cookie = cookie;
+		if (_PR_MD_GET_INTSOFF()) {
+			cpu->u.missed[cpu->where] |= _PR_MISSED_IO;
+			dnsContext.thread->md.notifyPending = PR_TRUE;
+			return;
+		}
+		DoneWaitingOnThisThread(dnsContext.thread);
+	}
+	// or else we don't handle the event
+}
+
+
 static void macsock_map_error(OSStatus err)
 {
     _PR_MD_CURRENT_THREAD()->md.osErrCode = err;
 
     if (IsEError(err) || (err >= EPERM && err <= ELASTERRNO)) {
     switch (IsEError(err) ? OSStatus2E(err) : err) {
         case EBADF:
             PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err);
@@ -168,118 +188,195 @@ static void macsock_map_error(OSStatus e
         default:
             PR_ASSERT(0);
             PR_SetError(PR_UNKNOWN_ERROR, err);
             break;
         }
     }
 }
 
-static void PrepareThreadForAsyncIO(PRThread *thread, EndpointRef endpoint, PRInt32 osfd)
-{
-    OSStatus err;
+
 
-    thread->io_pending = PR_TRUE;
-    thread->io_fd = osfd;
-    thread->md.osErrCode = noErr;
+static void PrepareForAsyncCompletion(PRThread * thread, PRFileDesc * fd)
+{
+    thread->io_pending       = PR_TRUE;
+    thread->io_fd            = fd->secret->md.osfd;
+    thread->md.osErrCode     = noErr;
+}
 
-    OTRemoveNotifier(endpoint);
-    err = OTInstallNotifier(endpoint, NotifierRoutine, thread);
-    PR_ASSERT(err == kOTNoError);
-}
 
 // Notification routine
 // Async callback routine.
 // A5 is OK. Cannot allocate memory here
 pascal void  NotifierRoutine(void * contextPtr, OTEventCode code, OTResult result, void * cookie)
 {
-    PRThread * thread = (PRThread *) contextPtr;
-    _PRCPU *cpu = _PR_MD_CURRENT_CPU();    
-    
+	PRFileDesc *  fd       = (PRFileDesc *) contextPtr;
+	EndpointRef   endpoint = (EndpointRef)fd->secret->md.osfd;
+    PRThread *    thread   = NULL;
+    _PRCPU *      cpu      = _PR_MD_CURRENT_CPU(); 
+	OSStatus      err;
+    TDiscon       discon;
+	OTResult	  resultOT;
+
     switch (code)
     {
-// Async Completion Event
-        case T_OPENCOMPLETE:
+// OTLook Events - 
+        case T_LISTEN:        // A connection request is available
+            PR_ASSERT(!"T_LISTEN Not implemented");  // listen or reject?
+            break;
+			
+        case T_CONNECT:      // Confirmation of a connect request
+			// cookie = sndCall parameter from OTConnect()
+            err = OTRcvConnect(endpoint, NULL);
+            PR_ASSERT(err == kOTNoError);
+
+			// wake up waiting thread, if any
+            thread = fd->secret->md.write.thread;
+            fd->secret->md.write.thread    = NULL;
+            fd->secret->md.write.cookie    = cookie;
+            fd->secret->md.connectionOpen  = PR_TRUE;
+            break;
+
+        case T_DATA:        // Standard data is available
+			fd->secret->md.readReady = PR_TRUE;
+
+			// wake up waiting thread, if any
+            thread = fd->secret->md.read.thread;
+            fd->secret->md.read.thread    = NULL;
+            fd->secret->md.read.cookie    = cookie;
+			break;
+
+        case T_EXDATA:      // Expedited data is available
+            PR_ASSERT(!"T_EXDATA Not implemented");
+			return;
+
+        case T_DISCONNECT:  // A disconnect is available
+            memset(&discon, 0 , sizeof(discon));
+            err = OTRcvDisconnect(endpoint, &discon);
+            PR_ASSERT(err == kOTNoError);
+            macsock_map_error(discon.reason);
+            fd->secret->md.exceptReady     = PR_TRUE;
+            fd->secret->md.connectionOpen  = PR_FALSE;
+            break;
+		
+        case T_ERROR:       // obsolete/unused in library
+            PR_ASSERT(!"T_ERROR Not implemented");
+			return;		
+		
+        case T_UDERR:       // UDP Send error; clear the error
+			(void) OTRcvUDErr((EndpointRef) cookie, NULL);
+            break;
+
+        case T_ORDREL:      // An orderly release is available
+            err = OTRcvOrderlyDisconnect(endpoint);
+            PR_ASSERT(err == kOTNoError);
+            fd->secret->md.readReady      = PR_TRUE;   // mark readable (to emulate bsd sockets)
+            // remember connection is closed, so we can return 0 on read or receive
+			fd->secret->md.connectionOpen = PR_FALSE;
+            break;		
+
+        case T_GODATA:   // Flow control lifted on standard data
+            fd->secret->md.writeReady = PR_TRUE;
+			resultOT = OTLook(endpoint);		// clear T_GODATA event
+			PR_ASSERT(resultOT == T_GODATA);
+			
+			// wake up waiting thread, if any
+            thread = fd->secret->md.write.thread;
+            fd->secret->md.write.thread    = NULL;
+            fd->secret->md.write.cookie    = cookie;
+            break;
+
+        case T_GOEXDATA: // Flow control lifted on expedited data
+            PR_ASSERT(!"T_GOEXDATA Not implemented");
+			return;
+
+        case T_REQUEST:  // An Incoming request is available
+            PR_ASSERT(!"T_REQUEST Not implemented");
+            return;
+
+        case T_REPLY:    // An Incoming reply is available
+            PR_ASSERT(!"T_REPLY Not implemented");
+            return;
+
+        case T_PASSCON:  // State is now T_DATAXFER
+			// OTAccept() complete, receiving endpoint in T_DATAXFER state
+			// cookie = OTAccept() resRef parameter
+			break;
+
+        case T_RESET:    // Protocol has been reset
+            PR_ASSERT(!"T_RESET Not implemented");
+			return;
+            
+// Async Completion Events
         case T_BINDCOMPLETE:
         case T_UNBINDCOMPLETE:
+        case T_ACCEPTCOMPLETE:
+        case T_OPTMGMTCOMPLETE:
         case T_GETPROTADDRCOMPLETE:
-        case T_ACCEPTCOMPLETE:
-// Connect callback
-        case T_CONNECT:
-// Standard or expedited data is available
-        case T_DATA:
-        case T_EXDATA:
-// Standard or expedited data Flow control lifted
-        case T_GODATA:
-        case T_GOEXDATA:
-// Asynchronous Listen Event
-        case T_LISTEN:
-// DNR String To Address Complete Event
-        case T_DNRSTRINGTOADDRCOMPLETE:
-// Option Management Request Complete Event
-        case T_OPTMGMTCOMPLETE:
-            thread->md.osErrCode = result;
-            thread->md.cookie = cookie;
-            if (_PR_MD_GET_INTSOFF()) {
-                cpu->u.missed[cpu->where] |= _PR_MISSED_IO;
-                thread->md.notifyPending = PR_TRUE;
-                return;
-            }
-            DoneWaitingOnThisThread(thread);
+			thread = fd->secret->md.misc.thread;
+            fd->secret->md.misc.thread    = NULL;
+            fd->secret->md.misc.cookie    = cookie;
             break;
 
-// T_ORDREL orderly release is available;  nothing to do
-        case T_ORDREL:
-            break;
-
-// T_PASSCON; nothing to do
-        case T_PASSCON:
-            break;
+//      case T_OPENCOMPLETE:			// we open endpoints in synchronous mode
+//      case T_REPLYCOMPLETE:
+//      case T_DISCONNECTCOMPLETE:		// we don't call OTSndDisconnect()
+//      case T_RESOLVEADDRCOMPLETE:
+//      case T_GETINFOCOMPLETE:
+//      case T_SYNCCOMPLETE:
+//      case T_MEMORYRELEASED:			// only if OTAckSends() called on endpoint
+//      case T_REGNAMECOMPLETE:
+//      case T_DELNAMECOMPLETE:
+//      case T_LKUPNAMECOMPLETE:
+//      case T_LKUPNAMERESULT:
+		// OpenTptInternet.h
+//      case T_DNRSTRINGTOADDRCOMPLETE:	// DNS is handled by dnsContext in DNSNotifierRoutine()
+//      case T_DNRADDRTONAMECOMPLETE:
+//      case T_DNRSYSINFOCOMPLETE:
+//      case T_DNRMAILEXCHANGECOMPLETE:
+//      case T_DNRQUERYCOMPLETE:
+        default:
+        	// we should probably have a bit more sophisticated handling of kOTSystemSleep, etc.
+			// PR_ASSERT(code != 0);
+            return;
+    }
 
-// T_DISCONNECT; disconnect is available; nothing to do
-        case T_DISCONNECT:
-            break;
-
-// UDP Send error; clear the error
-        case T_UDERR:
-            (void) OTRcvUDErr((EndpointRef) cookie, NULL);
-            break;
-            
-        default:
-            PR_ASSERT(0);
-            break;
-    }
+	if (thread) {
+		thread->md.osErrCode = result;
+		if (_PR_MD_GET_INTSOFF()) {
+			cpu->u.missed[cpu->where] |= _PR_MISSED_IO;
+			thread->md.notifyPending = PR_TRUE;
+			return;
+		}
+		DoneWaitingOnThisThread(thread);
+	}
 }
 
 
 static OSErr CreateSocket(int type, EndpointRef *endpoint)
 {
     OSStatus err;
     PRThread *me = _PR_MD_CURRENT_THREAD();
+    char *  configName;
+    OTConfiguration *config;
+    EndpointRef ep;
+
+	// for now we just create the endpoint
+	// we'll make it asynchronous and give it a notifier routine in _MD_makenonblock()
 
     switch (type){
-        case SOCK_STREAM:
-            err = OTAsyncOpenEndpoint(OTCreateConfiguration(kTCPName), 0, NULL, 
-                    NotifierRoutine, me);
-            break;
-        case SOCK_DGRAM:
-            err = OTAsyncOpenEndpoint(OTCreateConfiguration(kUDPName), 0, NULL,
-                    NotifierRoutine, me);
-            break;
+        case SOCK_STREAM:   configName = kTCPName;  break;
+        case SOCK_DGRAM:    configName = kUDPName;  break;
     }
+    config = OTCreateConfiguration(configName);
+    ep = OTOpenEndpoint(config, 0, NULL, &err);
     if (err != kOTNoError)
         goto ErrorExit;
 
-    WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT);
-
-    err = me->md.osErrCode;
-    if (err != kOTNoError)
-        goto ErrorExit;
-
-    *endpoint = me->md.cookie;
+    *endpoint = ep;
     PR_ASSERT(*endpoint != NULL);
 
     return kOTNoError;
 
 ErrorExit:
     return err;
 }
 
@@ -334,84 +431,84 @@ PRInt32 _MD_socket(int domain, int type,
 
     return ((PRInt32)endpoint);
 
 ErrorExit:
     macsock_map_error(err);
     return -1;
 }
 
+
 // Errors:
-// EBADF -- bad socket id
+// EBADF  -- bad socket id
 // EFAULT -- bad address format
 PRInt32 _MD_bind(PRFileDesc *fd, PRNetAddr *addr, PRUint32 addrlen)
 {
-    PRInt32 osfd = fd->secret->md.osfd;
     OSStatus err;
-    EndpointRef endpoint = (EndpointRef) osfd;
+    EndpointRef endpoint = (EndpointRef) fd->secret->md.osfd;
     TBind bindReq;
     PRThread *me = _PR_MD_CURRENT_THREAD();
     PRUint32 retryCount = 0;
 
     if (endpoint == NULL) {
         err = kEBADFErr;
         goto ErrorExit;
     }
         
     if (addr == NULL) {
         err = kEFAULTErr;
         goto ErrorExit;
     }
         
-    // setup our request
-#if 0
-    if ((addr->inet.port == 0) || (addr->inet.ip == 0))
-        bindReq.addr.len = 0;
-    else
-#endif
 /*
- * There seems to be a bug with OT ralted to OTBind failing with kOTNoAddressErr eventhough
+ * There seems to be a bug with OT related to OTBind failing with kOTNoAddressErr even though
  * a proper legal address was supplied.  This happens very rarely and just retrying the
  * operation after a certain time (less than 1 sec. does not work) seems to succeed.
  */
 
 TryAgain:
+    // setup our request
     bindReq.addr.len = addrlen;
         
     bindReq.addr.maxlen = addrlen;
     bindReq.addr.buf = (UInt8*) addr;
     bindReq.qlen = 1;
-    
-    PrepareThreadForAsyncIO(me, endpoint, osfd);    
+
+	PR_Lock(fd->secret->md.miscLock);
+    PrepareForAsyncCompletion(me, fd);
+	fd->secret->md.misc.thread = me;
 
     err = OTBind(endpoint, &bindReq, NULL);
-    if (err != kOTNoError)
+    if (err != kOTNoError) {
+	    me->io_pending = PR_FALSE;
+	    PR_Unlock(fd->secret->md.miscLock);
         goto ErrorExit;
+	}
 
     WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT);
+	PR_Unlock(fd->secret->md.miscLock);
 
     err = me->md.osErrCode;
     if (err != kOTNoError)
         goto ErrorExit;
 
-    PR_ASSERT(me->md.cookie == NULL);
-
     return kOTNoError;
 
 ErrorExit:
     if ((err == kOTNoAddressErr) && (++retryCount <= 4)) {
         long finalTicks;
     
         Delay(100,&finalTicks);
         goto TryAgain;
     }
     macsock_map_error(err);
     return -1;
 }
 
+
 // Errors:
 // EBADF -- bad socket id
 PRInt32 _MD_listen(PRFileDesc *fd, PRIntn backlog)
 {
 #if 0
     PRInt32 osfd = fd->secret->md.osfd;
     OSStatus err;
     EndpointRef endpoint = (EndpointRef) osfd;
@@ -429,43 +526,43 @@ PRInt32 _MD_listen(PRFileDesc *fd, PRInt
         
     addr.inet.port = addr.inet.ip = 0;
 
     bindReq.addr.maxlen = PR_NETADDR_SIZE (&addr);
     bindReq.addr.len = 0;
     bindReq.addr.buf = (UInt8*) &addr;
     bindReq.qlen = 0;
     
-    PrepareThreadForAsyncIO(me, endpoint, osfd);    
+    PrepareForAsyncCompletion(me, osfd);    
 
     err = OTGetProtAddress(endpoint, &bindReq, NULL);
     if (err != kOTNoError)
         goto ErrorExit;
 
     WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT);
 
     err = me->md.osErrCode;
     if (err != kOTNoError)
         goto ErrorExit;
 
-    PrepareThreadForAsyncIO(me, endpoint, osfd);    
+    PrepareForAsyncCompletion(me, osfd);    
 
     err = OTUnbind(endpoint);
     if (err != kOTNoError)
         goto ErrorExit;
 
     WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT);
 
     err = me->md.osErrCode;
     if (err != kOTNoError)
         goto ErrorExit;
 
     bindReq.qlen = backlog;
     
-    PrepareThreadForAsyncIO(me, endpoint, osfd);    
+    PrepareForAsyncCompletion(me, osfd);    
 
     err = OTBind(endpoint, &bindReq, NULL);
     if (err != kOTNoError)
         goto ErrorExit;
 
     WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT);
 
     err = me->md.osErrCode;
@@ -481,23 +578,23 @@ ErrorExit:
     return -1;
 #endif
 
 #pragma unused (fd, backlog)    
     return kOTNoError;
 
 }
 
+
 // Errors:
 // EBADF -- bad socket id
 PRInt32 _MD_getsockname(PRFileDesc *fd, PRNetAddr *addr, PRUint32 *addrlen)
 {
-    PRInt32 osfd = fd->secret->md.osfd;
     OSStatus err;
-    EndpointRef endpoint = (EndpointRef) osfd;
+    EndpointRef endpoint = (EndpointRef) fd->secret->md.osfd;
     TBind bindReq;
     PRThread *me = _PR_MD_CURRENT_THREAD();
 
     if (endpoint == NULL) {
         err = kEBADFErr;
         goto ErrorExit;
     }
         
@@ -512,42 +609,46 @@ PRInt32 _MD_getsockname(PRFileDesc *fd, 
     
     PR_ASSERT(PR_NETADDR_SIZE(addr) >= (*addrlen));
 
     bindReq.addr.len = *addrlen;
     bindReq.addr.maxlen = *addrlen;
     bindReq.addr.buf = (UInt8*) addr;
     bindReq.qlen = 0;
     
-    PrepareThreadForAsyncIO(me, endpoint, osfd);    
+	PR_Lock(fd->secret->md.miscLock);
+    PrepareForAsyncCompletion(me, fd);    
+	fd->secret->md.misc.thread = me;
 
     err = OTGetProtAddress(endpoint, &bindReq, NULL);
-    if (err != kOTNoError)
+    if (err != kOTNoError) {
+	    me->io_pending = PR_FALSE;
+	    PR_Unlock(fd->secret->md.miscLock);
         goto ErrorExit;
+	}
 
     WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT);
+	PR_Unlock(fd->secret->md.miscLock);
 
     err = me->md.osErrCode;
     if (err != kOTNoError)
         goto ErrorExit;
 
-    PR_ASSERT(me->md.cookie == &bindReq);
-
     return kOTNoError;
 
 ErrorExit:
     macsock_map_error(err);
     return -1;
 }
 
+
 PRStatus _MD_getsockopt(PRFileDesc *fd, PRInt32 level, PRInt32 optname, char* optval, PRInt32* optlen)
 {
     OSStatus err;
-    PRInt32 osfd = fd->secret->md.osfd;
-    EndpointRef endpoint = (EndpointRef) osfd;
+    EndpointRef endpoint = (EndpointRef) fd->secret->md.osfd;
     TOptMgmt cmd;
     TOption *opt;
     PRThread *me = _PR_MD_CURRENT_THREAD();
     unsigned char optionBuffer[kOTOptionHeaderSize + sizeof(PRSocketOptionData)];
     
     if (endpoint == NULL) {
         err = kEBADFErr;
         goto ErrorExit;
@@ -571,23 +672,29 @@ PRStatus _MD_getsockopt(PRFileDesc *fd, 
     opt->name = optname;
     opt->status = 0;
     
     cmd.opt.len = sizeof(TOption);
     cmd.opt.maxlen = sizeof(optionBuffer);
     cmd.opt.buf = (UInt8*)optionBuffer;
     cmd.flags = T_CURRENT;
 
-    PrepareThreadForAsyncIO(me, endpoint, osfd);    
+	PR_Lock(fd->secret->md.miscLock);
+    PrepareForAsyncCompletion(me, fd);    
+	fd->secret->md.misc.thread = me;
 
     err = OTOptionManagement(endpoint, &cmd, &cmd);
-    if (err != kOTNoError)
+    if (err != kOTNoError) {
+	    me->io_pending = PR_FALSE;
+	    PR_Unlock(fd->secret->md.miscLock);
         goto ErrorExit;
+	}
 
     WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT);
+	PR_Unlock(fd->secret->md.miscLock);
 
     err = me->md.osErrCode;
     if (err != kOTNoError)
         goto ErrorExit;
 
     if (opt->status == T_FAILURE || opt->status == T_NOTSUPPORT){
         err = kEOPNOTSUPPErr;
         goto ErrorExit;
@@ -652,21 +759,21 @@ PRStatus _MD_getsockopt(PRFileDesc *fd, 
     
     return PR_SUCCESS;
 
 ErrorExit:
     macsock_map_error(err);
     return PR_FAILURE;
 }
 
+
 PRStatus _MD_setsockopt(PRFileDesc *fd, PRInt32 level, PRInt32 optname, const char* optval, PRInt32 optlen)
 {
     OSStatus err;
-    PRInt32 osfd = fd->secret->md.osfd;
-    EndpointRef endpoint = (EndpointRef) osfd;
+    EndpointRef endpoint = (EndpointRef) fd->secret->md.osfd;
     TOptMgmt cmd;
     TOption *opt;
     PRThread *me = _PR_MD_CURRENT_THREAD();
     unsigned char optionBuffer[kOTOptionHeaderSize + sizeof(PRSocketOptionData) + 1];
     
     if (endpoint == NULL) {
         err = kEBADFErr;
         goto ErrorExit;
@@ -758,23 +865,29 @@ PRStatus _MD_setsockopt(PRFileDesc *fd, 
                 *((unsigned char*)&opt->value) = *((PRUintn*)optval);
             }
             break;
         default:
             PR_ASSERT(0);
             break;    
     }
     
-    PrepareThreadForAsyncIO(me, endpoint, osfd);    
+	PR_Lock(fd->secret->md.miscLock);
+    PrepareForAsyncCompletion(me, fd);    
+	fd->secret->md.misc.thread = me;
 
     err = OTOptionManagement(endpoint, &cmd, &cmd);
-    if (err != kOTNoError)
+    if (err != kOTNoError) {
+	    me->io_pending = PR_FALSE;
+	    PR_Unlock(fd->secret->md.miscLock);
         goto ErrorExit;
+	}
 
     WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT);
+	PR_Unlock(fd->secret->md.miscLock);
 
     err = me->md.osErrCode;
     if (err != kOTNoError)
         goto ErrorExit;
 
     if (opt->status == T_FAILURE || opt->status == T_NOTSUPPORT){
         err = kEOPNOTSUPPErr;
         goto ErrorExit;
@@ -789,16 +902,17 @@ PRStatus _MD_setsockopt(PRFileDesc *fd, 
 
     return PR_SUCCESS;
 
 ErrorExit:
     macsock_map_error(err);
     return PR_FAILURE;
 }
 
+
 PRInt32 _MD_socketavailable(PRFileDesc *fd)
 {
     PRInt32 osfd = fd->secret->md.osfd;
     OSStatus err;
     EndpointRef endpoint = (EndpointRef) osfd;
     size_t bytes;
 
     if (endpoint == NULL) {
@@ -818,21 +932,27 @@ PRInt32 _MD_socketavailable(PRFileDesc *
         
     return bytes;
 
 ErrorExit:
     macsock_map_error(err);
     return -1;
 }
 
+
 PRInt32 _MD_accept(PRFileDesc *fd, PRNetAddr *addr, PRUint32 *addrlen, PRIntervalTime timeout)
 {
-    PRInt32 osfd = fd->secret->md.osfd;
+#pragma unused (fd, addr, addrlen, timeout)
+
+    PR_ASSERT(!"_MD_accept Not implemented");
+	return -1;
+
+#if 0
     OSStatus err;
-    EndpointRef endpoint = (EndpointRef) osfd;
+    EndpointRef endpoint = (EndpointRef) fd->secret->md.osfd;
     PRThread *me = _PR_MD_CURRENT_THREAD();
     TBind bindReq;
     PRNetAddr bindAddr;
     PRInt32 newosfd = -1;
     EndpointRef newEndpoint;
     TCall call;
     PRNetAddr callAddr;
 
@@ -842,31 +962,31 @@ PRInt32 _MD_accept(PRFileDesc *fd, PRNet
     }
         
     memset(&call, 0 , sizeof(call));
 
     call.addr.maxlen = PR_NETADDR_SIZE(&callAddr);
     call.addr.len = PR_NETADDR_SIZE(&callAddr);
     call.addr.buf = (UInt8*) &callAddr;
     
-    PrepareThreadForAsyncIO(me, endpoint, osfd);    
+    PrepareForAsyncCompletion(me, fd);    
 
     err = OTListen (endpoint, &call);
     if (err != kOTNoError && (err != kOTNoDataErr || fd->secret->nonblocking)) {
         me->io_pending = PR_FALSE;
         goto ErrorExit;
     }
 
     while (err == kOTNoDataErr) {
         WaitOnThisThread(me, timeout);
         err = me->md.osErrCode;
         if (err != kOTNoError)
             goto ErrorExit;
 
-        PrepareThreadForAsyncIO(me, endpoint, osfd);    
+        PrepareForAsyncCompletion(me, fd);    
 
         err = OTListen (endpoint, &call);
         if (err == kOTNoError)
             break;
 
         PR_ASSERT(err == kOTNoDataErr);
     }        
 
@@ -880,61 +1000,60 @@ PRInt32 _MD_accept(PRFileDesc *fd, PRNet
 
     bindAddr.inet.port = bindAddr.inet.ip = 0;
 
     bindReq.addr.maxlen = PR_NETADDR_SIZE (&bindAddr);
     bindReq.addr.len = 0;
     bindReq.addr.buf = (UInt8*) &bindAddr;
     bindReq.qlen = 0;
     
-    PrepareThreadForAsyncIO(me, newEndpoint, newosfd);    
+    PrepareThreadForAsyncIO(me, newosfd);    
 
     err = OTBind(newEndpoint, &bindReq, NULL);
     if (err != kOTNoError)
         goto ErrorExit;
 
     WaitOnThisThread(me, timeout);
 
     err = me->md.osErrCode;
     if (err != kOTNoError)
         goto ErrorExit;
 
-    PrepareThreadForAsyncIO(me, endpoint, newosfd);    
+    PrepareThreadForAsyncIO(me, newosfd);    
 
     err = OTAccept (endpoint, newEndpoint, &call);
     if (err != kOTNoError)
         goto ErrorExit;
 
     WaitOnThisThread(me, timeout);
 
     err = me->md.osErrCode;
     if (err != kOTNoError)
         goto ErrorExit;
 
-    PR_ASSERT(me->md.cookie != NULL);
-
     if (addr != NULL)
         *addr = callAddr;
     if (addrlen != NULL)
         *addrlen = call.addr.len;
 
     return newosfd;
 
 ErrorExit:
     if (newosfd != -1)
         _MD_closesocket(newosfd);
     macsock_map_error(err);
     return -1;
+#endif
 }
 
+
 PRInt32 _MD_connect(PRFileDesc *fd, PRNetAddr *addr, PRUint32 addrlen, PRIntervalTime timeout)
 {
-    PRInt32 osfd = fd->secret->md.osfd;
     OSStatus err;
-    EndpointRef endpoint = (EndpointRef) osfd;
+    EndpointRef endpoint = (EndpointRef) fd->secret->md.osfd;
     PRThread *me = _PR_MD_CURRENT_THREAD();
     TCall sndCall;
     TBind bindReq;
     PRNetAddr bindAddr;
 
     if (endpoint == NULL) {
         err = kEBADFErr;
         goto ErrorExit;
@@ -949,73 +1068,83 @@ PRInt32 _MD_connect(PRFileDesc *fd, PRNe
 
     bindAddr.inet.port = bindAddr.inet.ip = 0;
 
     bindReq.addr.maxlen = PR_NETADDR_SIZE (&bindAddr);
     bindReq.addr.len = 0;
     bindReq.addr.buf = (UInt8*) &bindAddr;
     bindReq.qlen = 0;
     
-    PrepareThreadForAsyncIO(me, endpoint, osfd);    
+	PR_Lock(fd->secret->md.miscLock);
+    PrepareForAsyncCompletion(me, fd);    
+	fd->secret->md.misc.thread = me;
 
     err = OTBind(endpoint, &bindReq, NULL);
-    if (err != kOTNoError)
+    if (err != kOTNoError) {
+	    me->io_pending = PR_FALSE;
+	    PR_Unlock(fd->secret->md.miscLock);
         goto ErrorExit;
+	}
 
     WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT);
+	PR_Unlock(fd->secret->md.miscLock);
 
     err = me->md.osErrCode;
     if (err != kOTNoError)
         goto ErrorExit;
 
     memset(&sndCall, 0 , sizeof(sndCall));
 
     sndCall.addr.maxlen = addrlen;
     sndCall.addr.len = addrlen;
     sndCall.addr.buf = (UInt8*) addr;
-    
-    PrepareThreadForAsyncIO(me, endpoint, osfd);    
 
+	if (!fd->secret->nonblocking) {    
+        PrepareForAsyncCompletion(me, fd);    
+	    fd->secret->md.write.thread = me;
+    }
+	
     err = OTConnect (endpoint, &sndCall, NULL);
-    if (err != kOTNoError && err != kOTNoDataErr)
-        goto ErrorExit;
-    if (err == kOTNoDataErr && fd->secret->nonblocking) {
-        err = kEINPROGRESSErr;
-        me->io_pending = PR_FALSE;
-        goto ErrorExit;
-    }
-
+	if (err == kOTNoError) {
+        PR_ASSERT(!"OTConnect returned kOTNoError in async mode!?!");	
+	}
+	if (fd->secret->nonblocking) {
+		if (err == kOTNoDataErr)
+			err = EINPROGRESS;
+		goto ErrorExit;
+	} else {
+		if (err != kOTNoError && err != kOTNoDataErr) {
+            me->io_pending = PR_FALSE;
+            goto ErrorExit;
+		}
+	}
+	
     WaitOnThisThread(me, timeout);
 
     err = me->md.osErrCode;
     if (err != kOTNoError)
         goto ErrorExit;
 
-    PR_ASSERT(me->md.cookie != NULL);
-
-    err = OTRcvConnect(endpoint, NULL);
-    PR_ASSERT(err == kOTNoError);
-
     return kOTNoError;
 
 ErrorExit:
     macsock_map_error(err);
     return -1;
 }
 
+
 // Errors:
 // EBADF -- bad socket id
 // EFAULT -- bad buffer
 static PRInt32 SendReceiveStream(PRFileDesc *fd, void *buf, PRInt32 amount, 
                                PRIntn flags, PRIntervalTime timeout, SndRcvOpCode opCode)
 {
     OSStatus err;
     OTResult result;
-    PRInt32 osfd = fd->secret->md.osfd;
-    EndpointRef endpoint = (EndpointRef) osfd;
+    EndpointRef endpoint = (EndpointRef) fd->secret->md.osfd;
     PRThread *me = _PR_MD_CURRENT_THREAD();
     PRInt32 bytesLeft = amount;
 
     PR_ASSERT(flags == 0);
     
     if (endpoint == NULL) {
         err = kEBADFErr;
         goto ErrorExit;
@@ -1028,93 +1157,104 @@ static PRInt32 SendReceiveStream(PRFileD
     
     if (opCode != kSTREAM_SEND && opCode != kSTREAM_RECEIVE) {
         err = kEINVALErr;
         goto ErrorExit;
     }
         
     while (bytesLeft > 0) {
     
-        PrepareThreadForAsyncIO(me, endpoint, osfd);    
+        PrepareForAsyncCompletion(me, fd);    
 
-        if (opCode == kSTREAM_SEND)
+        if (opCode == kSTREAM_SEND) {
+			fd->secret->md.write.thread = me;
+			fd->secret->md.writeReady = PR_FALSE;				// expect the worst
             result = OTSnd(endpoint, buf, bytesLeft, NULL);
-        else
+			if (result != kOTFlowErr)							// hope for the best
+				fd->secret->md.writeReady = PR_TRUE;
+        } else {
+			fd->secret->md.read.thread = me;
+			fd->secret->md.readReady = PR_FALSE;				// expect the worst			
             result = OTRcv(endpoint, buf, bytesLeft, NULL);
+			if (result != kOTNoDataErr)							// hope for the best
+				fd->secret->md.readReady = PR_TRUE;
+        }
+		me->io_pending = PR_FALSE;
 
         if (result > 0) {
             buf = (void *) ( (UInt32) buf + (UInt32)result );
             bytesLeft -= result;
-            me->io_pending = PR_FALSE;
             if (opCode == kSTREAM_RECEIVE)
                 return result;
         } else {
-            if (result == kOTOutStateErr) { /* it has been closed */
-                me->io_pending = PR_FALSE;
-                return 0;
-            }
-            if (result == kOTLookErr) {
-                PRBool readReady,writeReady,exceptReady;
-                /* process the event and then continue the operation */
-                (void) GetState(endpoint, &readReady, &writeReady, &exceptReady);
-                continue;
-            }
-            if (result != kOTNoDataErr && result != kOTFlowErr && 
-                result != kEAGAINErr && result != kEWOULDBLOCKErr) {
-                me->io_pending = PR_FALSE;
-                err = result;
-                goto ErrorExit;
-            } else if (fd->secret->nonblocking) {
-                me->io_pending = PR_FALSE;
-                err = result;
-                goto ErrorExit;
-            }
-            WaitOnThisThread(me, timeout);
-            me->io_pending = PR_FALSE;
-            err = me->md.osErrCode;
-            if (err != kOTNoError)
-                goto ErrorExit;
+			switch (result) {
+				case kOTOutStateErr:			// it has been closed
+                    return 0;
+				
+				case kOTLookErr:
+				    PR_ASSERT(!"call to OTLook() required after all.");
+					break;
+				
+				case kOTFlowErr:
+				case kOTNoDataErr:
+				case kEAGAINErr:
+				case kEWOULDBLOCKErr:
+					if (fd->secret->nonblocking) {
+						err = result;
+						goto ErrorExit;
+					}
 
-            PR_ASSERT(me->md.cookie != NULL);
-        }
+					WaitOnThisThread(me, timeout);
+					err = me->md.osErrCode;
+					if (err != kOTNoError)
+						goto ErrorExit;				
+					break;
+					
+				default:
+					err = result;
+					goto ErrorExit;
+			}
+		}
     }
 
     return amount;
 
 ErrorExit:
     macsock_map_error(err);
     return -1;
 }                               
 
+
 PRInt32 _MD_recv(PRFileDesc *fd, void *buf, PRInt32 amount, 
                                PRIntn flags, PRIntervalTime timeout)
 {
     return (SendReceiveStream(fd, buf, amount, flags, timeout, kSTREAM_RECEIVE));
 }                               
 
+
 PRInt32 _MD_send(PRFileDesc *fd,const void *buf, PRInt32 amount, 
                                PRIntn flags, PRIntervalTime timeout)
 {
     return (SendReceiveStream(fd, (void *)buf, amount, flags, timeout, kSTREAM_SEND));
 }                               
 
 
 // Errors:
 // EBADF -- bad socket id
 // EFAULT -- bad buffer
 static PRInt32 SendReceiveDgram(PRFileDesc *fd, void *buf, PRInt32 amount, 
                                PRIntn flags, PRNetAddr *addr, PRUint32 *addrlen, 
                                PRIntervalTime timeout, SndRcvOpCode opCode)
 {
     OSStatus err;
-    PRInt32 osfd = fd->secret->md.osfd;
-    EndpointRef endpoint = (EndpointRef) osfd;
+    EndpointRef endpoint = (EndpointRef) fd->secret->md.osfd;
     PRThread *me = _PR_MD_CURRENT_THREAD();
     PRInt32 bytesLeft = amount;
     TUnitData dgram;
+    OTResult	result;
 
     PR_ASSERT(flags == 0);
     
     if (endpoint == NULL) {
         err = kEBADFErr;
         goto ErrorExit;
     }
         
@@ -1133,177 +1273,132 @@ static PRInt32 SendReceiveDgram(PRFileDe
     dgram.addr.len = *addrlen;
     dgram.addr.buf = (UInt8*) addr;
     dgram.udata.maxlen = amount;
     dgram.udata.len = amount;
     dgram.udata.buf = (UInt8*) buf;    
 
     while (bytesLeft > 0) {
     
-        PrepareThreadForAsyncIO(me, endpoint, osfd);    
+        PrepareForAsyncCompletion(me, fd);    
 
-        if (opCode == kDGRAM_SEND)
+        if (opCode == kDGRAM_SEND) {
+			fd->secret->md.write.thread = me;
+			fd->secret->md.writeReady = PR_FALSE;				// expect the worst
             err = OTSndUData(endpoint, &dgram);
-        else
+			if (result != kOTFlowErr)							// hope for the best
+				fd->secret->md.writeReady = PR_TRUE;
+		} else {
+			fd->secret->md.read.thread = me;
+			fd->secret->md.readReady = PR_FALSE;				// expect the worst			
             err = OTRcvUData(endpoint, &dgram, NULL);
+			if (result != kOTNoDataErr)							// hope for the best
+				fd->secret->md.readReady = PR_TRUE;
+		}
 
         if (err == kOTNoError) {
             buf = (void *) ( (UInt32) buf + (UInt32)dgram.udata.len );
             bytesLeft -= dgram.udata.len;
             dgram.udata.buf = (UInt8*) buf;    
             me->io_pending = PR_FALSE;
-        }
-        else {
+        } else {
             PR_ASSERT(err == kOTNoDataErr || err == kOTOutStateErr);
             WaitOnThisThread(me, timeout);
-            me->io_pending = PR_FALSE;
             err = me->md.osErrCode;
             if (err != kOTNoError)
                 goto ErrorExit;
-
-            PR_ASSERT(me->md.cookie != NULL);
         }
     }
 
     if (opCode == kDGRAM_RECEIVE)
         *addrlen = dgram.addr.len;
 
     return amount;
 
 ErrorExit:
     macsock_map_error(err);
     return -1;
 }                               
 
+
 PRInt32 _MD_recvfrom(PRFileDesc *fd, void *buf, PRInt32 amount, 
                                PRIntn flags, PRNetAddr *addr, PRUint32 *addrlen,
                                PRIntervalTime timeout)
 {
     return (SendReceiveDgram(fd, buf, amount, flags, addr, addrlen,
                             timeout, kDGRAM_RECEIVE));
 }                               
 
+
 PRInt32 _MD_sendto(PRFileDesc *fd,const void *buf, PRInt32 amount, 
                                PRIntn flags, PRNetAddr *addr, PRUint32 addrlen,
                                PRIntervalTime timeout)
 {
     return (SendReceiveDgram(fd, (void *)buf, amount, flags, addr, &addrlen,
                             timeout, kDGRAM_SEND));
 }                               
 
+
 PRInt32 _MD_closesocket(PRInt32 osfd)
 {
     OSStatus err;
     EndpointRef endpoint = (EndpointRef) osfd;
     PRThread *me = _PR_MD_CURRENT_THREAD();
 
     if (endpoint == NULL) {
         err = kEBADFErr;
         goto ErrorExit;
     }
         
     if (me->io_pending && me->io_fd == osfd)
         me->io_pending = PR_FALSE;
 
-#if 0
-    {
-    OTResult state;
-    state = OTGetEndpointState(endpoint);
-    
-    err = OTSndOrderlyDisconnect(endpoint);
-    if (err != kOTNoError && err != kOTOutStateErr)
-        goto ErrorExit;
-
-    state = OTGetEndpointState(endpoint);
-    
-    err = OTUnbind(endpoint);
-    if (err != kOTNoError && err != kOTOutStateErr)
-        goto ErrorExit;
-
-    state = OTGetEndpointState(endpoint);
-
-    err = OTSetSynchronous(endpoint);
-    if (err != kOTNoError)
-        goto ErrorExit;
-
-    err = OTSetBlocking(endpoint);
-    if (err != kOTNoError)
-        goto ErrorExit;
-    }
-#endif
-
     (void) OTSndOrderlyDisconnect(endpoint);
-
     err = OTCloseProvider(endpoint);
     if (err != kOTNoError)
         goto ErrorExit;
 
     return kOTNoError;
 
 ErrorExit:
     macsock_map_error(err);
     return -1;
 }                               
 
+
 PRInt32 _MD_writev(PRFileDesc *fd, const struct PRIOVec *iov, PRInt32 iov_size, PRIntervalTime timeout)
 {
 #pragma unused (fd, iov, iov_size, timeout)
 
     PR_ASSERT(0);
     _PR_MD_CURRENT_THREAD()->md.osErrCode = unimpErr;
     return -1;
 }                               
 
-static PRBool GetState(EndpointRef endpoint, PRBool *readReady, PRBool *writeReady, PRBool *exceptReady)
-{
-    OSStatus err;
-    OTResult resultOT;
-    TDiscon discon;
-    PRBool result = PR_FALSE;
-    
-    *readReady = *writeReady = *exceptReady = PR_FALSE;
 
-    resultOT = OTLook(endpoint);
-    switch (resultOT) {
-        case T_DATA:
-        case T_LISTEN:
-            *readReady = PR_TRUE;
-            break;
-        case T_CONNECT:
-            err = OTRcvConnect(endpoint, NULL);
-            PR_ASSERT(err == kOTNoError);
-            break;        
-        case T_DISCONNECT:
-            memset(&discon, 0 , sizeof(discon));
-            err = OTRcvDisconnect(endpoint, &discon);
-            PR_ASSERT(err == kOTNoError);
-            macsock_map_error(discon.reason);
-            *exceptReady = PR_TRUE;
-            break;        
-        case T_ORDREL:
-            *readReady = PR_TRUE;
-            err = OTRcvOrderlyDisconnect(endpoint);
-            PR_ASSERT(err == kOTNoError);
-            break;
-    }
-    resultOT = OTGetEndpointState(endpoint);
+static PRBool GetState(PRFileDesc *fd, PRBool *readReady, PRBool *writeReady, PRBool *exceptReady)
+{
+    OTResult resultOT;
+    
+	*readReady = fd->secret->md.readReady;
+	*exceptReady = fd->secret->md.exceptReady;
+
+    resultOT = OTGetEndpointState((EndpointRef)fd->secret->md.osfd);
     switch (resultOT)    {
         case T_DATAXFER:
         case T_INREL:
             *writeReady = PR_TRUE;
             break;
         default:
             *writeReady = PR_FALSE;
     }
     
-    if ((*readReady == PR_TRUE) || (*writeReady==PR_TRUE) || (*exceptReady==PR_TRUE))
-        result = PR_TRUE;
+    return  *readReady || *writeReady || *exceptReady;
+}
 
-    return result;
-}
 
 PRInt32 _MD_poll(PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout)
 {
     PRInt32 ready = 0;
     PRPollDesc *pd, *epd;
     PRIntervalTime sleepTime, timein;
     
     sleepTime = PR_MillisecondsToInterval(5UL);
@@ -1312,17 +1407,17 @@ PRInt32 _MD_poll(PRPollDesc *pds, PRIntn
         if (sleepTime > timeout) sleepTime = timeout;
         timein = PR_IntervalNow();
     }
 
     do
     {
         for (pd = pds, epd = pd + npds; pd < epd; pd++)
         {
-            PRInt16 in_flags_read = 0, in_flags_write = 0;
+            PRInt16  in_flags_read = 0,  in_flags_write = 0;
             PRInt16 out_flags_read = 0, out_flags_write = 0;
 
             if (NULL == pd->fd || pd->in_flags == 0) continue;
 
             if (pd->in_flags & PR_POLL_READ)
             {
                 in_flags_read = (pd->fd->methods->poll)(
                     pd->fd, pd->in_flags & ~PR_POLL_WRITE, &out_flags_read);
@@ -1335,30 +1430,25 @@ PRInt32 _MD_poll(PRPollDesc *pds, PRIntn
             if ((0 != (in_flags_read & out_flags_read))
             || (0 != (in_flags_write & out_flags_write)))
             {
                 ready += 1;  /* some layer has buffer input */
                 pd->out_flags = out_flags_read | out_flags_write;
             }
             else
             {
-                PRFileDesc *bottom;
-                EndpointRef endpoint;
+                PRFileDesc *bottomFD;
                 PRBool readReady, writeReady, exceptReady;
 
                 pd->out_flags = 0;  /* pre-condition */
-                bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER);
-                PR_ASSERT(NULL != bottom);
-                if ((NULL != bottom)
-                && (_PR_FILEDESC_OPEN == bottom->secret->state))
+                bottomFD = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER);
+                PR_ASSERT(NULL != bottomFD);
+                if ((NULL != bottomFD) && (_PR_FILEDESC_OPEN == bottomFD->secret->state))
                 {
-                    endpoint = (EndpointRef)bottom->secret->md.osfd;
-
-                    if (GetState(endpoint,
-                    &readReady, &writeReady, &exceptReady))
+                    if (GetState(bottomFD, &readReady, &writeReady, &exceptReady))
                     {
                         if (readReady)
                         {
                             if (in_flags_read & PR_POLL_READ)
                                 pd->out_flags |= PR_POLL_READ;
                             if (in_flags_write & PR_POLL_READ)
                                 pd->out_flags |= PR_POLL_WRITE;
                         }
@@ -1389,34 +1479,76 @@ PRInt32 _MD_poll(PRPollDesc *pds, PRIntn
         (void) PR_Sleep(sleepTime);
 
     } while ((timeout == PR_INTERVAL_NO_TIMEOUT) ||
            (((PRIntervalTime)(PR_IntervalNow() - timein)) < timeout));
 
     return 0; /* timed out */
 }
 
+
+void _MD_initfiledesc(PRFileDesc *fd)
+{
+	// Allocate a PR_Lock to arbitrate miscellaneous OT calls for this endpoint between threads
+	// We presume that only one thread will be making Read calls (Recv/Accept) and that only
+	// one thread will be making Write calls (Send/Connect) on the endpoint at a time.
+	if (fd->methods->file_type == PR_DESC_SOCKET_TCP ||
+		fd->methods->file_type == PR_DESC_SOCKET_UDP )
+	{
+		PR_ASSERT(fd->secret->md.miscLock == NULL);
+		fd->secret->md.miscLock = PR_NewLock();
+		PR_ASSERT(fd->secret->md.miscLock != NULL);
+		fd->secret->md.connectionOpen = PR_FALSE;	// starts out closed
+		fd->secret->md.readReady = PR_FALSE;		// let's not presume we have data ready to read
+		fd->secret->md.writeReady = PR_TRUE;		// let's presume we can write unless we hear otherwise
+		fd->secret->md.exceptReady = PR_FALSE;
+	}
+}
+
+
+void _MD_freefiledesc(PRFileDesc *fd)
+{
+	if (fd->secret->md.miscLock)
+	{
+		PR_ASSERT(fd->methods->file_type == PR_DESC_SOCKET_TCP || fd->methods->file_type == PR_DESC_SOCKET_UDP);
+		PR_DestroyLock(fd->secret->md.miscLock);
+		fd->secret->md.miscLock = NULL;
+	} else {
+		PR_ASSERT(fd->methods->file_type != PR_DESC_SOCKET_TCP && PR_DESC_SOCKET_TCP != PR_DESC_SOCKET_UDP);
+	}
+}
+
 void _MD_makenonblock(PRFileDesc *fd)
 {
-    OSStatus err;
-    PRInt32 osfd = fd->secret->md.osfd;
-    EndpointRef endpoint = (EndpointRef) osfd;
+	// We simulate non-blocking mode using async mode rather
+	// than put the endpoint in non-blocking mode.
+	// We need to install the PRFileDesc as the contextPtr for the NotifierRoutine, but it
+	// didn't exist at the time the endpoint was created.  It does now though...
+	ProviderRef	endpointRef = (ProviderRef)fd->secret->md.osfd;
+	OSStatus	err;
+	
+	// Install the PRFileDesc as the contextPtr for the Notifier function associated with this Endpoint.
+	err = OTInstallNotifier(endpointRef, NotifierRoutine, fd);
+	PR_ASSERT(err == kOTNoError);
+	
+	// Now that we have a NotifierRoutine installed, we can make the endpoint asynchronous
+	err = OTSetAsynchronous(endpointRef);
+	PR_ASSERT(err == kOTNoError);
+}
 
-    err = OTSetNonBlocking(endpoint);
-    PR_ASSERT(err == kOTNoError || err == kOTOutStateErr);
-}
 
 PR_IMPLEMENT(PRInt32) _MD_shutdown(PRFileDesc *fd, PRIntn how)
 {
 #pragma unused (fd, how)
 
 /* Just succeed silently!!! */
 return (0);
 }                               
 
+
 PR_IMPLEMENT(PRStatus) _MD_getpeername(PRFileDesc *fd, PRNetAddr *addr, PRUint32 *addrlen)
 {
 #pragma unused (fd, addr, addrlen)
 
     PR_ASSERT(0);
     _PR_MD_CURRENT_THREAD()->md.osErrCode = unimpErr;
     return PR_FAILURE;
 }                               
@@ -1434,32 +1566,39 @@ PR_IMPLEMENT(unsigned long) inet_addr(co
 }
 
 
 static char *sAliases[1] = {NULL};
 static struct hostent sHostEnt = {NULL, &sAliases[0], AF_INET, sizeof (long), NULL};
 static InetHostInfo sHostInfo;
 static InetHost *sAddresses[kMaxHostAddrs+1];
 
+
 PR_IMPLEMENT(struct hostent *) gethostbyname(const char * name)
 {
     OSStatus err;
     PRUint32 index;
     PRThread *me = _PR_MD_CURRENT_THREAD();
 
-    PrepareThreadForAsyncIO(me, sSvcRef, NULL);    
+    me->io_pending       = PR_TRUE;
+    me->io_fd            = NULL;
+    me->md.osErrCode     = noErr;
+	
+	PR_Lock(dnsContext.lock);	// so we can safely store our thread ptr in dnsContext
+	dnsContext.thread = me;		// so we know what thread to wake up when OTInetStringToAddress completes
 
-    err = OTInetStringToAddress(sSvcRef, (char *)name, &sHostInfo);
+    err = OTInetStringToAddress(dnsContext.serviceRef, (char *)name, &sHostInfo);
     if (err != kOTNoError) {
         me->io_pending = PR_FALSE;
         me->md.osErrCode = err;
         goto ErrorExit;
     }
 
     WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT);
+	PR_Unlock(dnsContext.lock);
 
     if (me->md.osErrCode != kOTNoError)
         goto ErrorExit;
 
     sHostEnt.h_name = sHostInfo.name;
     for (index=0; index<kMaxHostAddrs && sHostInfo.addrs[index] != NULL; index++)
         sAddresses[index] = &sHostInfo.addrs[index];
     sAddresses[index] = NULL;    
@@ -1492,17 +1631,17 @@ PR_IMPLEMENT(char *) inet_ntoa(struct in
 
 
 PRStatus _MD_gethostname(char *name, int namelen)
 {
     OSStatus err;
     InetInterfaceInfo info;
 
     /*
-     *    On a Macintosh, we donŐt have the concept of a local host name.
+     *    On a Macintosh, we don't have the concept of a local host name.
      *    We do though have an IP address & everyone should be happy with
      *     a string version of that for a name.
      *    The alternative here is to ping a local DNS for our name, they
      *    will often know it.  This is the cheap, easiest, and safest way out.
      */
 
     /* Make sure the string is as long as the longest possible address */
     if (namelen < strlen("123.123.123.123")) {
@@ -1566,17 +1705,17 @@ ErrorExit:
 int _MD_mac_get_nonblocking_connect_error(PRInt32 osfd)
 {
     OTResult resultOT;
     EndpointRef endpoint = (EndpointRef) osfd;
 
     resultOT = OTGetEndpointState(endpoint);
     switch (resultOT)    {
         case T_OUTCON:
-            macsock_map_error(kEINPROGRESSErr);
+            macsock_map_error(EINPROGRESS);
             return -1;
         case T_DATAXFER:
             return 0;
         case T_IDLE:
             return -1;
         default:
             PR_ASSERT(0);
             return -1;