summaryrefslogtreecommitdiff
path: root/pr/src/md/mac/macsockotpt.c
diff options
context:
space:
mode:
Diffstat (limited to 'pr/src/md/mac/macsockotpt.c')
-rw-r--r--pr/src/md/mac/macsockotpt.c290
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();
/*