diff options
Diffstat (limited to 'pr/src/md/mac/macsockotpt.c')
-rw-r--r-- | pr/src/md/mac/macsockotpt.c | 290 |
1 files changed, 186 insertions, 104 deletions
diff --git a/pr/src/md/mac/macsockotpt.c b/pr/src/md/mac/macsockotpt.c index 7b6e4441..159a0db2 100644 --- a/pr/src/md/mac/macsockotpt.c +++ b/pr/src/md/mac/macsockotpt.c @@ -29,6 +29,12 @@ #define GESTALT_OPEN_TPT_TCP_PRESENT gestaltOpenTptTCPPresentMask #include <OpenTptInternet.h> // All the internet typedefs + +#if (UNIVERSAL_INTERFACES_VERSION >= 0x0330) +// for some reason Apple removed this typedef. +typedef struct OTConfiguration OTConfiguration; +#endif + #include "primpl.h" typedef enum SndRcvOpCode { @@ -45,38 +51,36 @@ static struct { void * cookie; } dnsContext; -static PRBool gOTInitialized; 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 pascal void NotifierRoutine(void * contextPtr, OTEventCode code, OTResult result, void * cookie); +static pascal void RawEndpointNotifierRoutine(void * contextPtr, OTEventCode code, OTResult result, void * cookie); static PRBool GetState(PRFileDesc *fd, PRBool *readReady, PRBool *writeReady, PRBool *exceptReady); +void +WakeUpNotifiedThread(PRThread *thread, OTResult result); + extern void WaitOnThisThread(PRThread *thread, PRIntervalTime timeout); extern void DoneWaitingOnThisThread(PRThread *thread); #if TARGET_CARBON OTClientContextPtr clientContext = NULL; -OTNotifyUPP DNSNotifierRoutineUPP; -OTNotifyUPP notifierRoutineUPP; - -#define DNS_NOTIFIER_ROUTINE DNSNotifierRoutineUPP -#define NOTIFIER_ROUTINE notifierRoutineUPP -#define INIT_OPEN_TRANSPORT() InitOpenTransport(clientContext, kInitOTForExtensionMask) -#define OT_OPEN_INTERNET_SERVICES(config, flags, err) OTOpenInternetServices(config, flags, err, clientContext) -#define OT_OPEN_ENDPOINT(config, flags, info, err) OTOpenEndpoint(config, flags, info, err, clientContext) +#define INIT_OPEN_TRANSPORT() InitOpenTransportInContext(kInitOTForExtensionMask, &clientContext) +#define OT_OPEN_INTERNET_SERVICES(config, flags, err) OTOpenInternetServicesInContext(config, flags, err, clientContext) +#define OT_OPEN_ENDPOINT(config, flags, info, err) OTOpenEndpointInContext(config, flags, info, err, clientContext) #else -#define DNS_NOTIFIER_ROUTINE DNSNotifierRoutine -#define NOTIFIER_ROUTINE NotifierRoutine #define INIT_OPEN_TRANSPORT() InitOpenTransport() #define OT_OPEN_INTERNET_SERVICES(config, flags, err) OTOpenInternetServices(config, flags, err) #define OT_OPEN_ENDPOINT(config, flags, info, err) OTOpenEndpoint(config, flags, info, err) #endif /* TARGET_CARBON */ +static OTNotifyUPP DNSNotifierRoutineUPP; +static OTNotifyUPP NotifierRoutineUPP; +static OTNotifyUPP RawEndpointNotifierRoutineUPP; void _MD_InitNetAccess() { @@ -97,26 +101,20 @@ void _MD_InitNetAccess() PR_ASSERT(hasOTTCPIP == PR_TRUE); -#if TARGET_CARBON DNSNotifierRoutineUPP = NewOTNotifyUPP(DNSNotifierRoutine); - notifierRoutineUPP = NewOTNotifyUPP(NotifierRoutine); - - errOT = OTAllocClientContext((UInt32)0, &clientContext); - PR_ASSERT(err == kOTNoError); -#endif - + NotifierRoutineUPP = NewOTNotifyUPP(NotifierRoutine); + RawEndpointNotifierRoutineUPP = NewOTNotifyUPP(RawEndpointNotifierRoutine); errOT = INIT_OPEN_TRANSPORT(); PR_ASSERT(err == kOTNoError); + dnsContext.serviceRef = NULL; dnsContext.lock = PR_NewLock(); PR_ASSERT(dnsContext.lock != NULL); dnsContext.thread = _PR_MD_CURRENT_THREAD(); dnsContext.cookie = NULL; - gOTInitialized = PR_FALSE; - /* XXX Does not handle absence of open tpt and tcp yet! */ } @@ -124,36 +122,65 @@ static void _MD_FinishInitNetAccess() { OSStatus errOT; + if (dnsContext.serviceRef) + return; + dnsContext.serviceRef = OT_OPEN_INTERNET_SERVICES(kDefaultInternetServicesPath, NULL, &errOT); - if (errOT != kOTNoError) return; /* no network -- oh well */ + if (errOT != kOTNoError) { + dnsContext.serviceRef = NULL; + return; /* no network -- oh well */ + } + PR_ASSERT((dnsContext.serviceRef != NULL) && (errOT == kOTNoError)); /* Install notify function for DNR Address To String completion */ - errOT = OTInstallNotifier(dnsContext.serviceRef, DNS_NOTIFIER_ROUTINE, &dnsContext); + errOT = OTInstallNotifier(dnsContext.serviceRef, DNSNotifierRoutineUPP, &dnsContext); PR_ASSERT(errOT == kOTNoError); /* Put us into async mode */ errOT = OTSetAsynchronous(dnsContext.serviceRef); PR_ASSERT(errOT == kOTNoError); - - gOTInitialized = PR_TRUE; } -pascal void DNSNotifierRoutine(void * contextPtr, OTEventCode code, OTResult result, void * cookie) +static pascal void DNSNotifierRoutine(void * contextPtr, OTEventCode otEvent, OTResult result, void * cookie) { #pragma unused(contextPtr) _PRCPU * cpu = _PR_MD_CURRENT_CPU(); - - if (code == T_DNRSTRINGTOADDRCOMPLETE) { + OSStatus errOT; + dnsContext.thread->md.osErrCode = result; dnsContext.cookie = cookie; - if (_PR_MD_GET_INTSOFF()) { - cpu->u.missed[cpu->where] |= _PR_MISSED_IO; - dnsContext.thread->md.missedIONotify = PR_TRUE; - return; - } - DoneWaitingOnThisThread(dnsContext.thread); + + switch (otEvent) { + case T_DNRSTRINGTOADDRCOMPLETE: + if (_PR_MD_GET_INTSOFF()) { + cpu->u.missed[cpu->where] |= _PR_MISSED_IO; + dnsContext.thread->md.missedIONotify = PR_TRUE; + return; + } + DoneWaitingOnThisThread(dnsContext.thread); + break; + + case kOTProviderWillClose: + errOT = OTSetSynchronous(dnsContext.serviceRef); + // fall through to kOTProviderIsClosed case + + case kOTProviderIsClosed: + errOT = OTCloseProvider((ProviderRef)dnsContext.serviceRef); + dnsContext.serviceRef = nil; + + if (_PR_MD_GET_INTSOFF()) { + cpu->u.missed[cpu->where] |= _PR_MISSED_IO; + dnsContext.thread->md.missedIONotify = PR_TRUE; + return; + } + DoneWaitingOnThisThread(dnsContext.thread); + break; + + default: // or else we don't handle the event + PR_ASSERT(otEvent==NULL); + } // or else we don't handle the event } @@ -243,7 +270,7 @@ static void PrepareForAsyncCompletion(PRThread * thread, PRInt32 osfd) } -static void +void WakeUpNotifiedThread(PRThread *thread, OTResult result) { _PRCPU * cpu = _PR_MD_CURRENT_CPU(); @@ -262,12 +289,13 @@ WakeUpNotifiedThread(PRThread *thread, OTResult result) // Notification routine // Async callback routine. // A5 is OK. Cannot allocate memory here -pascal void NotifierRoutine(void * contextPtr, OTEventCode code, OTResult result, void * cookie) +static pascal void NotifierRoutine(void * contextPtr, OTEventCode code, OTResult result, void * cookie) { PRFilePrivate *secret = (PRFilePrivate *) contextPtr; _MDFileDesc * md = &(secret->md); EndpointRef endpoint = (EndpointRef)secret->md.osfd; PRThread * thread = NULL; + PRThread * pollThread = md->poll.thread; OSStatus err; OTResult resultOT; TDiscon discon; @@ -301,7 +329,6 @@ pascal void NotifierRoutine(void * contextPtr, OTEventCode code, OTResult resul thread = secret->md.write.thread; secret->md.write.thread = NULL; secret->md.write.cookie = cookie; - secret->md.connectionOpen = PR_TRUE; break; case T_DATA: // Standard data is available @@ -323,7 +350,6 @@ pascal void NotifierRoutine(void * contextPtr, OTEventCode code, OTResult resul err = OTRcvDisconnect(endpoint, &discon); PR_ASSERT(err == kOTNoError); secret->md.exceptReady = PR_TRUE; - secret->md.connectionOpen = PR_FALSE; // wake up waiting threads, if any result = -3199 - discon.reason; // obtain the negative error code @@ -356,7 +382,7 @@ pascal void NotifierRoutine(void * contextPtr, OTEventCode code, OTResult resul PR_ASSERT(err == kOTNoError); secret->md.readReady = PR_TRUE; // mark readable (to emulate bsd sockets) // remember connection is closed, so we can return 0 on read or receive - secret->md.connectionOpen = PR_FALSE; + secret->md.orderlyDisconnect = PR_TRUE; thread = secret->md.read.thread; secret->md.read.thread = NULL; @@ -430,7 +456,11 @@ pascal void NotifierRoutine(void * contextPtr, OTEventCode code, OTResult resul return; } - WakeUpNotifiedThread(thread, result); + if (pollThread) + WakeUpNotifiedThread(pollThread, kOTNoError); + + if (thread && (thread != pollThread)) + WakeUpNotifiedThread(thread, result); } @@ -473,7 +503,6 @@ PRInt32 _MD_socket(int domain, int type, int protocol) OSStatus err; EndpointRef endpoint; - if (!gOTInitialized) _MD_FinishInitNetAccess(); // We only deal with internet domain @@ -1037,7 +1066,7 @@ typedef struct RawEndpointAndThread // Notification routine for raw endpoints not yet attached to a PRFileDesc. // Async callback routine. // A5 is OK. Cannot allocate memory here -pascal void RawEndpointNotifierRoutine(void * contextPtr, OTEventCode code, OTResult result, void * cookie) +static pascal void RawEndpointNotifierRoutine(void * contextPtr, OTEventCode code, OTResult result, void * cookie) { RawEndpointAndThread *endthr = (RawEndpointAndThread *) contextPtr; PRThread * thread = endthr->thread; @@ -1194,7 +1223,7 @@ PRInt32 _MD_accept(PRFileDesc *fd, PRNetAddr *addr, PRUint32 *addrlen, PRInterva endthr->thread = me; endthr->endpoint = (EndpointRef) newosfd; - err = OTInstallNotifier((ProviderRef) newosfd, RawEndpointNotifierRoutine, endthr); + err = OTInstallNotifier((ProviderRef) newosfd, RawEndpointNotifierRoutineUPP, endthr); PR_ASSERT(err == kOTNoError); err = OTSetAsynchronous((EndpointRef) newosfd); @@ -1350,6 +1379,7 @@ static PRInt32 SendReceiveStream(PRFileDesc *fd, void *buf, PRInt32 amount, PRInt32 bytesLeft = amount; PR_ASSERT(flags == 0); + PR_ASSERT(opCode == kSTREAM_SEND || opCode == kSTREAM_RECEIVE); if (endpoint == NULL) { err = kEBADFErr; @@ -1361,11 +1391,6 @@ static PRInt32 SendReceiveStream(PRFileDesc *fd, void *buf, PRInt32 amount, goto ErrorExit; } - if (opCode != kSTREAM_SEND && opCode != kSTREAM_RECEIVE) { - err = kEINVALErr; - goto ErrorExit; - } - while (bytesLeft > 0) { PrepareForAsyncCompletion(me, fd->secret->md.osfd); @@ -1434,6 +1459,10 @@ static PRInt32 SendReceiveStream(PRFileDesc *fd, void *buf, PRInt32 amount, } me->io_pending = PR_FALSE; + if (opCode == kSTREAM_SEND) + fd->secret->md.write.thread = nil; + else + fd->secret->md.read.thread = nil; if (result > 0) { buf = (void *) ( (UInt32) buf + (UInt32)result ); @@ -1442,9 +1471,6 @@ static PRInt32 SendReceiveStream(PRFileDesc *fd, void *buf, PRInt32 amount, return result; } else { switch (result) { - case kOTOutStateErr: // it has been closed - return 0; - case kOTLookErr: PR_ASSERT(!"call to OTLook() required after all."); break; @@ -1464,6 +1490,9 @@ static PRInt32 SendReceiveStream(PRFileDesc *fd, void *buf, PRInt32 amount, goto ErrorExit; break; + case kOTOutStateErr: // if provider already closed, fall through to handle error + if (fd->secret->md.orderlyDisconnect) + return 0; default: err = result; goto ErrorExit; @@ -1471,9 +1500,13 @@ static PRInt32 SendReceiveStream(PRFileDesc *fd, void *buf, PRInt32 amount, } } + PR_ASSERT(opCode == kSTREAM_SEND ? fd->secret->md.write.thread == nil : + fd->secret->md.read.thread == nil); return amount; ErrorExit: + PR_ASSERT(opCode == kSTREAM_SEND ? fd->secret->md.write.thread == nil : + fd->secret->md.read.thread == nil); macsock_map_error(err); return -1; } @@ -1633,8 +1666,13 @@ PRInt32 _MD_writev(PRFileDesc *fd, const struct PRIOVec *iov, PRInt32 iov_size, static PRBool GetState(PRFileDesc *fd, PRBool *readReady, PRBool *writeReady, PRBool *exceptReady) { OTResult resultOT; - - *readReady = fd->secret->md.readReady; + // hack to emulate BSD sockets; say that a socket that has disconnected + // is still readable. + size_t availableData = 1; + if (!fd->secret->md.orderlyDisconnect) + OTCountDataBytes((EndpointRef)fd->secret->md.osfd, &availableData); + + *readReady = fd->secret->md.readReady && (availableData > 0); *exceptReady = fd->secret->md.exceptReady; resultOT = OTGetEndpointState((EndpointRef)fd->secret->md.osfd); @@ -1650,22 +1688,13 @@ static PRBool GetState(PRFileDesc *fd, PRBool *readReady, PRBool *writeReady, PR return *readReady || *writeReady || *exceptReady; } - -PRInt32 _MD_poll(PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout) +// check to see if any of the poll descriptors have data available +// for reading or writing. +static PRInt32 CheckPollDescs(PRPollDesc *pds, PRIntn npds) { PRInt32 ready = 0; PRPollDesc *pd, *epd; - PRIntervalTime sleepTime, timein; - sleepTime = PR_MillisecondsToInterval(5UL); - if (PR_INTERVAL_NO_TIMEOUT != timeout) - { - 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; @@ -1696,48 +1725,105 @@ PRInt32 _MD_poll(PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout) pd->out_flags = 0; /* pre-condition */ bottomFD = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER); - PR_ASSERT(NULL != bottomFD); - if ((NULL != bottomFD) && (_PR_FILEDESC_OPEN == bottomFD->secret->state)) + /* bottomFD can be NULL for pollable sockets */ + if (bottomFD) { - if (GetState(bottomFD, &readReady, &writeReady, &exceptReady)) + if (_PR_FILEDESC_OPEN == bottomFD->secret->state) { - 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; - } - if (writeReady) - { - if (in_flags_read & PR_POLL_WRITE) - pd->out_flags |= PR_POLL_READ; - if (in_flags_write & PR_POLL_WRITE) - pd->out_flags |= PR_POLL_WRITE; - } - if (exceptReady && (pd->in_flags & PR_POLL_EXCEPT)) + if (GetState(bottomFD, &readReady, &writeReady, &exceptReady)) { - pd->out_flags |= PR_POLL_EXCEPT; + 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; + } + if (writeReady) + { + if (in_flags_read & PR_POLL_WRITE) + pd->out_flags |= PR_POLL_READ; + if (in_flags_write & PR_POLL_WRITE) + pd->out_flags |= PR_POLL_WRITE; + } + if (exceptReady && (pd->in_flags & PR_POLL_EXCEPT)) + { + pd->out_flags |= PR_POLL_EXCEPT; + } + if (0 != pd->out_flags) ready++; } - if (0 != pd->out_flags) ready++; } - } - else - { - ready += 1; /* this will cause an abrupt return */ - pd->out_flags = PR_POLL_NVAL; /* bogii */ + else /* bad state */ + { + ready += 1; /* this will cause an abrupt return */ + pd->out_flags = PR_POLL_NVAL; /* bogii */ + } } } } - if (ready > 0) return ready; + return ready; +} - (void) PR_Sleep(sleepTime); +// set or clear md.poll.thread on the poll descriptors +static void SetDescPollThread(PRPollDesc *pds, PRIntn npds, PRThread* thread) +{ + PRInt32 ready = 0; + PRPollDesc *pd, *epd; - } while ((timeout == PR_INTERVAL_NO_TIMEOUT) || - (((PRIntervalTime)(PR_IntervalNow() - timein)) < timeout)); + for (pd = pds, epd = pd + npds; pd < epd; pd++) + { + if (pd->fd) + { + PRFileDesc *bottomFD = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER); + if (bottomFD && (_PR_FILEDESC_OPEN == bottomFD->secret->state)) + { + bottomFD->secret->md.poll.thread = thread; + } + } + } +} - return 0; /* timed out */ +PRInt32 _MD_poll(PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout) +{ + PRThread *thread = _PR_MD_CURRENT_THREAD(); + intn is; + PRInt32 ready; + OSErr result; + + if (timeout == PR_INTERVAL_NO_WAIT) { + return CheckPollDescs(pds, npds); + } + + _PR_INTSOFF(is); + PR_Lock(thread->md.asyncIOLock); + + // ensure that we don't miss the firing of the notifier while checking socket status + // need to set up the thread + PrepareForAsyncCompletion(thread, 0); + + SetDescPollThread(pds, npds, thread); + ready = CheckPollDescs(pds, npds); + + PR_Unlock(thread->md.asyncIOLock); + _PR_FAST_INTSON(is); + + if (ready == 0) { + WaitOnThisThread(thread, timeout); + result = thread->md.osErrCode; + if (result != noErr && result != kETIMEDOUTErr) { + PR_ASSERT(0); /* debug: catch unexpected errors */ + ready = -1; + } else { + ready = CheckPollDescs(pds, npds); + } + } else { + thread->io_pending = PR_FALSE; + } + + SetDescPollThread(pds, npds, NULL); + + return ready; } @@ -1752,7 +1838,7 @@ void _MD_initfiledesc(PRFileDesc *fd) 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.orderlyDisconnect = PR_FALSE; 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; @@ -1789,7 +1875,7 @@ void _MD_makenonblock(PRFileDesc *fd) // fd changes, but the secret structure does not; // (b) the notifier func refers only to the secret data structure // anyway. - err = OTInstallNotifier(endpointRef, NOTIFIER_ROUTINE, fd->secret); + err = OTInstallNotifier(endpointRef, NotifierRoutineUPP, fd->secret); PR_ASSERT(err == kOTNoError); // Now that we have a NotifierRoutine installed, we can make the endpoint asynchronous @@ -1862,11 +1948,11 @@ PR_IMPLEMENT(unsigned long) inet_addr(const char *cp) OSStatus err; InetHost host; - if (!gOTInitialized) _MD_FinishInitNetAccess(); err = OTInetStringToHost((char*) cp, &host); - PR_ASSERT(err == kOTNoError); + if (err != kOTNoError) + return -1; return host; } @@ -1884,7 +1970,6 @@ PR_IMPLEMENT(struct hostent *) gethostbyname(const char * name) PRUint32 index; PRThread *me = _PR_MD_CURRENT_THREAD(); - if (!gOTInitialized) _MD_FinishInitNetAccess(); me->io_pending = PR_TRUE; @@ -1925,7 +2010,6 @@ PR_IMPLEMENT(struct hostent *) gethostbyaddr(const void *addr, int addrlen, int PR_ASSERT(type == AF_INET); PR_ASSERT(addrlen == sizeof(struct in_addr)); - if (!gOTInitialized) _MD_FinishInitNetAccess(); OTInetHostToString((InetHost)addr, sHostInfo.name); @@ -1936,7 +2020,6 @@ PR_IMPLEMENT(struct hostent *) gethostbyaddr(const void *addr, int addrlen, int PR_IMPLEMENT(char *) inet_ntoa(struct in_addr addr) { - if (!gOTInitialized) _MD_FinishInitNetAccess(); OTInetHostToString((InetHost)addr.s_addr, sHostInfo.name); @@ -1950,7 +2033,6 @@ PRStatus _MD_gethostname(char *name, int namelen) OSStatus err; InetInterfaceInfo info; - if (!gOTInitialized) _MD_FinishInitNetAccess(); /* |