static OSErr CreateSocket(int type, EndpointRef *endpoint) { OSStatus err; PRThread *me = _PR_MD_CURRENT_THREAD(); 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; } if (err != kOTNoError) goto ErrorExit; WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT); err = me->md.osErrCode; if (err != kOTNoError) goto ErrorExit; *endpoint = me->md.cookie; PR_ASSERT(*endpoint != NULL); return kOTNoError; ErrorExit: return err; }
PR_IMPLEMENT(struct hostent *) gethostbyname(const char * name) { OSStatus err; PRUint32 index; PRThread *me = _PR_MD_CURRENT_THREAD(); PrepareThreadForAsyncIO(me, sSvcRef, NULL); err = OTInetStringToAddress(sSvcRef, (char *)name, &sHostInfo); if (err != kOTNoError) goto ErrorExit; WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT); err = me->md.osErrCode; if (err != 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; sHostEnt.h_addr_list = (char **)sAddresses; return (&sHostEnt); ErrorExit: macsock_map_error(err); return NULL; }
// 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; TBind bindReq; PRThread *me = _PR_MD_CURRENT_THREAD(); if (endpoint == NULL) { err = kEBADFErr; goto ErrorExit; } if (addr == NULL) { err = kEFAULTErr; goto ErrorExit; } #if !defined(_PR_INET6) addr->inet.family = AF_INET; #endif 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); 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; PR_ASSERT(me->md.cookie == &bindReq); return kOTNoError; ErrorExit: macsock_map_error(err); return -1; }
PRInt32 _MD_connect(PRFileDesc *fd, PRNetAddr *addr, PRUint32 addrlen, PRIntervalTime timeout) { PRInt32 osfd = fd->secret->md.osfd; OSStatus err; EndpointRef endpoint = (EndpointRef) osfd; PRThread *me = _PR_MD_CURRENT_THREAD(); TCall sndCall; TBind bindReq; PRNetAddr bindAddr; if (endpoint == NULL) { err = kEBADFErr; goto ErrorExit; } if (addr == NULL) { err = kEFAULTErr; goto ErrorExit; } // Bind to a local port; let the system assign it. 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); err = OTBind(endpoint, &bindReq, NULL); if (err != kOTNoError) goto ErrorExit; WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT); 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); 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; } 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; }
PRInt32 _MD_accept(PRFileDesc *fd, PRNetAddr *addr, PRUint32 *addrlen, PRIntervalTime timeout) { PRInt32 osfd = fd->secret->md.osfd; OSStatus err; EndpointRef endpoint = (EndpointRef) osfd; PRThread *me = _PR_MD_CURRENT_THREAD(); TBind bindReq; PRNetAddr bindAddr; PRInt32 newosfd = -1; EndpointRef newEndpoint; TCall call; PRNetAddr callAddr; if (endpoint == NULL) { err = kEBADFErr; goto ErrorExit; } 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); 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); err = OTListen (endpoint, &call); if (err == kOTNoError) break; PR_ASSERT(err == kOTNoDataErr); } newosfd = _MD_socket(AF_INET, SOCK_STREAM, 0); if (newosfd == -1) return -1; newEndpoint = (EndpointRef)newosfd; // Bind to a local port; let the system assign it. 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); 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); 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; }
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; TOptMgmt cmd; TOption *opt; PRThread *me = _PR_MD_CURRENT_THREAD(); unsigned char optionBuffer[kOTOptionHeaderSize + sizeof(PRSocketOptionData) + 1]; if (endpoint == NULL) { err = kEBADFErr; goto ErrorExit; } /* OT wants IPPROTO_IP for level and not XTI_GENERIC. SO_REUSEADDR and SO_KEEPALIVE are equated to IP level and TCP level options respectively and hence we need to set the level correctly. */ if (level == SOL_SOCKET) { if (optname == SO_REUSEADDR) level = IPPROTO_IP; else if (optname == SO_KEEPALIVE) level = INET_TCP; } opt = (TOption *)&optionBuffer[0]; opt->len = kOTOptionHeaderSize + optlen; /* special case adjustments for length follow */ if (optname == SO_KEEPALIVE) /* we need to pass the timeout value for OT */ opt->len = kOTOptionHeaderSize + sizeof(t_kpalive); if (optname == IP_MULTICAST_TTL || optname == IP_TTL) /* it is an unsigned char value */ opt->len = kOTOneByteOptionSize; if (optname == IP_TOS && level == IPPROTO_IP) opt->len = kOTOneByteOptionSize; opt->level = level; opt->name = optname; opt->status = 0; cmd.opt.len = opt->len; cmd.opt.maxlen = sizeof(optionBuffer); cmd.opt.buf = (UInt8*)optionBuffer; optionBuffer[opt->len] = 0; cmd.flags = T_NEGOTIATE; switch (optname) { case SO_LINGER: *((t_linger*)&opt->value) = *((t_linger*)optval); break; case SO_REUSEADDR: case TCP_NODELAY: case SO_RCVBUF: case SO_SNDBUF: *((PRIntn*)&opt->value) = *((PRIntn*)optval); break; case IP_MULTICAST_LOOP: if (*optval != 0) opt->value[0] = T_YES; else opt->value[0] = T_NO; break; case SO_KEEPALIVE: { t_kpalive *kpalive = (t_kpalive *)&opt->value; kpalive->kp_onoff = *((long*)optval); kpalive->kp_timeout = 10; /* timeout in minutes */ break; } case IP_TTL: *((unsigned char*)&opt->value) = *((PRUintn*)optval); break; case IP_MULTICAST_TTL: *((unsigned char*)&opt->value) = *optval; break; case IP_ADD_MEMBERSHIP: case IP_DROP_MEMBERSHIP: { /* struct ip_mreq and TIPAddMulticast are the same size and optval is pointing to struct ip_mreq */ *((TIPAddMulticast *)&opt->value) = *((TIPAddMulticast *)optval); break; } case IP_MULTICAST_IF: { *((PRUint32*)&opt->value) = *((PRUint32*)optval); break; } /*case IP_TOS:*/ /*IP_TOS has same value as TCP_MAXSEG */ case TCP_MAXSEG: if (level == IPPROTO_TCP) { /* it is TCP_MAXSEG */ *((PRIntn*)&opt->value) = *((PRIntn*)optval); } else { /* it is IP_TOS */ *((unsigned char*)&opt->value) = *((PRUintn*)optval); } break; default: PR_ASSERT(0); break; } PrepareThreadForAsyncIO(me, endpoint, osfd); err = OTOptionManagement(endpoint, &cmd, &cmd); if (err != kOTNoError) goto ErrorExit; WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT); err = me->md.osErrCode; if (err != kOTNoError) goto ErrorExit; if (opt->status == T_FAILURE || opt->status == T_NOTSUPPORT){ err = kEOPNOTSUPPErr; goto ErrorExit; } if (level == IPPROTO_TCP && optname == TCP_MAXSEG && opt->status == T_READONLY) { err = kEOPNOTSUPPErr; goto ErrorExit; } PR_ASSERT(opt->status == T_SUCCESS); return PR_SUCCESS; ErrorExit: macsock_map_error(err); return PR_FAILURE; }
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; TOptMgmt cmd; TOption *opt; PRThread *me = _PR_MD_CURRENT_THREAD(); unsigned char optionBuffer[kOTOptionHeaderSize + sizeof(PRSocketOptionData)]; if (endpoint == NULL) { err = kEBADFErr; goto ErrorExit; } /* OT wants IPPROTO_IP for level and not XTI_GENERIC. SO_REUSEADDR and SO_KEEPALIVE are equated to IP level and TCP level options respectively and hence we need to set the level correctly. */ if (level == SOL_SOCKET) { if (optname == SO_REUSEADDR) level = IPPROTO_IP; else if (optname == SO_KEEPALIVE) level = INET_TCP; } opt = (TOption *)&optionBuffer[0]; opt->len = sizeof(TOption); opt->level = level; 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); err = OTOptionManagement(endpoint, &cmd, &cmd); if (err != kOTNoError) goto ErrorExit; WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT); err = me->md.osErrCode; if (err != kOTNoError) goto ErrorExit; if (opt->status == T_FAILURE || opt->status == T_NOTSUPPORT){ err = kEOPNOTSUPPErr; goto ErrorExit; } PR_ASSERT(opt->status == T_SUCCESS); switch (optname) { case SO_LINGER: *((t_linger*)optval) = *((t_linger*)&opt->value); *optlen = sizeof(t_linger); break; case SO_REUSEADDR: case TCP_NODELAY: case SO_KEEPALIVE: case SO_RCVBUF: case SO_SNDBUF: *((PRIntn*)optval) = *((PRIntn*)&opt->value); *optlen = sizeof(PRIntn); break; case IP_MULTICAST_LOOP: *((PRUint8*)optval) = *((PRIntn*)&opt->value); *optlen = sizeof(PRUint8); break; case IP_TTL: *((PRUintn*)optval) = *((PRUint8*)&opt->value); *optlen = sizeof(PRUintn); break; case IP_MULTICAST_TTL: *((PRUint8*)optval) = *((PRUint8*)&opt->value); *optlen = sizeof(PRUint8); break; case IP_ADD_MEMBERSHIP: case IP_DROP_MEMBERSHIP: { /* struct ip_mreq and TIPAddMulticast are the same size and optval is pointing to struct ip_mreq */ *((struct ip_mreq *)optval) = *((struct ip_mreq *)&opt->value); *optlen = sizeof(struct ip_mreq); break; } case IP_MULTICAST_IF: { *((PRUint32*)optval) = *((PRUint32*)&opt->value); *optlen = sizeof(PRUint32); break; } /*case IP_TOS:*/ /*IP_TOS has same value as TCP_MAXSEG */ case TCP_MAXSEG: if (level == IPPROTO_TCP) { /* it is TCP_MAXSEG */ *((PRIntn*)optval) = *((PRIntn*)&opt->value); *optlen = sizeof(PRIntn); } else { /* it is IP_TOS */ *((PRUintn*)optval) = *((PRUint8*)&opt->value); *optlen = sizeof(PRUintn); } break; default: PR_ASSERT(0); break; } return PR_SUCCESS; ErrorExit: macsock_map_error(err); return PR_FAILURE; }
// 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; TBind bindReq; PRNetAddr addr; PRThread *me = _PR_MD_CURRENT_THREAD(); if (backlog == 0) backlog = 1; if (endpoint == NULL) { err = EBADF; goto ErrorExit; } 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); 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); 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); err = OTBind(endpoint, &bindReq, NULL); if (err != kOTNoError) goto ErrorExit; WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT); err = me->md.osErrCode; if (err != kOTNoError) goto ErrorExit; PR_ASSERT(me->md.cookie == NULL); return kOTNoError; ErrorExit: macsock_map_error(err); return -1; #endif #pragma unused (fd, backlog) return kOTNoError; }
// Errors: // 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; 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 * 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: bindReq.addr.len = addrlen; bindReq.addr.maxlen = addrlen; bindReq.addr.buf = (UInt8*) addr; bindReq.qlen = 1; PrepareThreadForAsyncIO(me, endpoint, osfd); err = OTBind(endpoint, &bindReq, NULL); if (err != kOTNoError) goto ErrorExit; WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT); 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 // 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; PRThread *me = _PR_MD_CURRENT_THREAD(); PRInt32 bytesLeft = amount; TUnitData dgram; PR_ASSERT(flags == 0); if (endpoint == NULL) { err = kEBADFErr; goto ErrorExit; } if (buf == NULL || addr == NULL) { err = kEFAULTErr; goto ErrorExit; } memset(&dgram, 0 , sizeof(dgram)); dgram.addr.maxlen = *addrlen; 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); if (opCode == kDGRAM_SEND) err = OTSndUData(endpoint, &dgram); else if (opCode == kDGRAM_RECEIVE) err = OTRcvUData(endpoint, &dgram, NULL); else { err = kEINVALErr; goto ErrorExit; } 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 { PR_ASSERT(err == kOTNoDataErr || err == kOTOutStateErr); WaitOnThisThread(me, timeout); 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; }
// 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; PRThread *me = _PR_MD_CURRENT_THREAD(); PRInt32 bytesLeft = amount; PR_ASSERT(flags == 0); if (endpoint == NULL) { err = kEBADFErr; goto ErrorExit; } if (buf == NULL) { err = kEFAULTErr; goto ErrorExit; } while (bytesLeft > 0) { PrepareThreadForAsyncIO(me, endpoint, osfd); if (opCode == kSTREAM_SEND) result = OTSnd(endpoint, buf, bytesLeft, NULL); else if (opCode == kSTREAM_RECEIVE) result = OTRcv(endpoint, buf, bytesLeft, NULL); else { err = kEINVALErr; goto ErrorExit; } 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 */ 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) { err = result; goto ErrorExit; } else if (fd->secret->nonblocking) { me->io_pending = PR_FALSE; err = result; goto ErrorExit; } WaitOnThisThread(me, timeout); err = me->md.osErrCode; if (err != kOTNoError) goto ErrorExit; PR_ASSERT(me->md.cookie != NULL); } } return amount; ErrorExit: macsock_map_error(err); return -1; }
// ====================== 1st thread PRInt32 readWriteProc(PRFileDesc fd, void buf, PRUint32 bytes, IOOperation op) { PRInt32 refNum; OSErr err; int pbAsync_pb; int me_io_pending; // quick hack to allow PR_fprintf, etc to work with stderr, stdin, stdout // note, if a user chooses "seek" or the like as an operation in another function // this will not work if (refNum >= 0 && refNum < 3) { switch (refNum) { case 0: //stdin - not on a Mac for now err = paramErr; goto ErrorExit; break; case 1: // stdout case 2: // stderr puts(); break; } return (bytes); } else { PRBool doingAsync = PR_FALSE; // // Issue the async read call and wait for the io semaphore associated // with this thread. // Async file system calls *never* return error values, so ignore their // results (see <http://developer.apple.com/technotes/fl/fl_515.html>); // the completion routine is always called. // if (op == READ_ASYNC) { // // Skanky optimization so that reads < 20K are actually done synchronously // to optimize performance on small reads (e.g. registry reads on startup) // if ( bytes > 20480L ) { doingAsync = PR_TRUE; { __ESBMC_atomic_begin(); if (__COUNT__ == 0) { me_io_pending = PR_TRUE; // check for order violation __COUNT__ = __COUNT__ + 1; } else { assert(0); } __ESBMC_atomic_end(); } __START_ASYNC__ = True; // second thread can start (void)PBReadAsync(pbAsync_pb); } else { me_io_pending = PR_FALSE; err = PBReadSync(pbAsync_pb); if (err != noErr && err != eofErr) goto ErrorExit; } } else { doingAsync = PR_TRUE; me_io_pending = PR_TRUE; // writes are currently always async (void)PBWriteAsync(pbAsync_pb); } if (doingAsync) { WaitOnThisThread(PR_INTERVAL_NO_TIMEOUT); } } if (err != noErr) goto ErrorExit; if (err != noErr && err != eofErr) goto ErrorExit; return; ErrorExit: _MD_SetError(err); return -1; }