📄 macsockotpt.c
字号:
_MD_closesocket(newosfd); macsock_map_error(err); return -1;}PRInt32 _MD_connect(PRFileDesc *fd, PRNetAddr *addr, PRUint32 addrlen, PRIntervalTime timeout){ OSStatus err; 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; } if (addr == NULL) { err = kEFAULTErr; goto ErrorExit; } // Bind to a local port; let the system assign it. bindAddr.inet.family = AF_INET; 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; PR_Lock(fd->secret->md.miscLock); PrepareForAsyncCompletion(me, fd->secret->md.osfd); fd->secret->md.misc.thread = me; err = OTBind(endpoint, &bindReq, NULL); 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; if (!fd->secret->nonblocking) { PrepareForAsyncCompletion(me, fd->secret->md.osfd); PR_ASSERT(fd->secret->md.write.thread == NULL); fd->secret->md.write.thread = me; } err = OTConnect (endpoint, &sndCall, NULL); 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; return kOTNoError;ErrorExit: macsock_map_error(err); return -1;}// Errors:// EBADF -- bad socket id// EFAULT -- bad bufferstatic PRInt32 SendReceiveStream(PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags, PRIntervalTime timeout, SndRcvOpCode opCode){ OSStatus err; OTResult result; EndpointRef endpoint = (EndpointRef) fd->secret->md.osfd; PRThread *me = _PR_MD_CURRENT_THREAD(); PRInt32 bytesLeft = amount; PR_ASSERT(flags == 0 || (opCode == kSTREAM_RECEIVE && flags == PR_MSG_PEEK)); PR_ASSERT(opCode == kSTREAM_SEND || opCode == kSTREAM_RECEIVE); if (endpoint == NULL) { err = kEBADFErr; goto ErrorExit; } if (buf == NULL) { err = kEFAULTErr; goto ErrorExit; } PR_ASSERT(opCode == kSTREAM_SEND ? fd->secret->md.write.thread == NULL : fd->secret->md.read.thread == NULL); while (bytesLeft > 0) { Boolean disabledNotifications = OTEnterNotifier(endpoint); PrepareForAsyncCompletion(me, fd->secret->md.osfd); if (opCode == kSTREAM_SEND) { do { fd->secret->md.write.thread = me; fd->secret->md.writeReady = PR_FALSE; // expect the worst result = OTSnd(endpoint, buf, bytesLeft, NULL); fd->secret->md.writeReady = (result != kOTFlowErr); if (fd->secret->nonblocking) // hope for the best break; else { // We drop through on anything other than a blocking write. if (result != kOTFlowErr) break; // Blocking write, but the pipe is full. Turn notifications on and // wait for an event, hoping that it's a T_GODATA event. if (disabledNotifications) { OTLeaveNotifier(endpoint); disabledNotifications = false; } WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT); result = me->md.osErrCode; if (result != kOTNoError) // got interrupted, or some other error break; // Prepare to loop back and try again disabledNotifications = OTEnterNotifier(endpoint); PrepareForAsyncCompletion(me, fd->secret->md.osfd); } } while(1); } else { do { fd->secret->md.read.thread = me; fd->secret->md.readReady = PR_FALSE; // expect the worst result = OTRcv(endpoint, buf, bytesLeft, NULL); if (fd->secret->nonblocking) { fd->secret->md.readReady = (result != kOTNoDataErr); break; } else { if (result != kOTNoDataErr) { // If we successfully read a blocking socket, check for more data. // According to IM:OT, we should be able to rely on OTCountDataBytes // to tell us whether there is a nonzero amount of data pending. size_t count; OSErr tmpResult; tmpResult = OTCountDataBytes(endpoint, &count); fd->secret->md.readReady = ((tmpResult == kOTNoError) && (count > 0)); break; } // Blocking read, but no data available. Turn notifications on and // wait for an event on this endpoint, and hope that we get a T_DATA event. if (disabledNotifications) { OTLeaveNotifier(endpoint); disabledNotifications = false; } WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT); result = me->md.osErrCode; if (result != kOTNoError) // interrupted thread, etc. break; // Prepare to loop back and try again disabledNotifications = OTEnterNotifier(endpoint); PrepareForAsyncCompletion(me, fd->secret->md.osfd); } } // Retry read if we had to wait for data to show up. while(1); } me->io_pending = PR_FALSE; if (opCode == kSTREAM_SEND) fd->secret->md.write.thread = NULL; else fd->secret->md.read.thread = NULL; // turn notifications back on if (disabledNotifications) OTLeaveNotifier(endpoint); if (result > 0) { buf = (void *) ( (UInt32) buf + (UInt32)result ); bytesLeft -= result; if (opCode == kSTREAM_RECEIVE) { amount = result; goto NormalExit; } } else { switch (result) { case kOTLookErr: PR_ASSERT(!"call to OTLook() required after all."); break; case kOTFlowErr: case kOTNoDataErr: case kEAGAINErr: case kEWOULDBLOCKErr: if (fd->secret->nonblocking) { if (bytesLeft == amount) { // no data was sent err = result; goto ErrorExit; } // some data was sent amount -= bytesLeft; goto NormalExit; } WaitOnThisThread(me, timeout); err = me->md.osErrCode; if (err != kOTNoError) goto ErrorExit; break; case kOTOutStateErr: // if provider already closed, fall through to handle error if (fd->secret->md.orderlyDisconnect) { amount = 0; goto NormalExit; } // else fall through default: err = result; goto ErrorExit; } } }NormalExit: PR_ASSERT(opCode == kSTREAM_SEND ? fd->secret->md.write.thread == NULL : fd->secret->md.read.thread == NULL); return amount;ErrorExit: PR_ASSERT(opCode == kSTREAM_SEND ? fd->secret->md.write.thread == NULL : fd->secret->md.read.thread == NULL); 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 bufferstatic PRInt32 SendReceiveDgram(PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags, PRNetAddr *addr, PRUint32 *addrlen, PRIntervalTime timeout, SndRcvOpCode opCode){ OSStatus err; EndpointRef endpoint = (EndpointRef) fd->secret->md.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; } if (opCode != kDGRAM_SEND && opCode != kDGRAM_RECEIVE) { err = kEINVALErr; 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) { PrepareForAsyncCompletion(me, fd->secret->md.osfd); if (opCode == kDGRAM_SEND) { fd->secret->md.write.thread = me; fd->secret->md.writeReady = PR_FALSE; // expect the worst err = OTSndUData(endpoint, &dgram); if (err != 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 (err != 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 { PR_ASSERT(err == kOTNoDataErr || err == kOTOutStateErr); WaitOnThisThread(me, timeout); err = me->md.osErrCode; if (err != kOTNoError) goto ErrorExit; } } 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; (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;}// OT endpoint states are documented here:// http://gemma.apple.com/techpubs/mac/NetworkingOT/NetworkingWOT-27.html#MARKER-9-65//static PRBool GetState(PRFileDesc *fd, PRBool *readReady, PRBool *writeReady, PRBool *exceptReady){ OTResult resultOT; // 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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -