PR_ASSERT(flags == 0);
PR_ASSERT(flags == 0 || (opCode == kSTREAM_RECEIVE && flags == PR_MSG_PEEK));
static 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);    PR_ASSERT(opCode == kSTREAM_SEND || opCode == kSTREAM_RECEIVE);        if (endpoint == NULL) {        err = kEBADFErr;        goto ErrorExit;    }            if (buf == NULL) {        err = kEFAULTErr;        goto ErrorExit;    }        while (bytesLeft > 0) {            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. Wait for an event,					// hoping that it's a T_GODATA event.					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  			   		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. Wait for an event					// on this endpoint, and hope that we get a T_DATA event.					WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT);					result = me->md.osErrCode;					if (result != kOTNoError) // interrupted thread, etc.						break;					// Prepare to loop back and try again  			   		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 = nil;        else            fd->secret->md.read.thread  = nil;        if (result > 0) {            buf = (void *) ( (UInt32) buf + (UInt32)result );            bytesLeft -= result;            if (opCode == kSTREAM_RECEIVE)                return result;        } else {			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;					}					WaitOnThisThread(me, timeout);					err = me->md.osErrCode;					if (err != kOTNoError)						goto ErrorExit;									break;									default:					err = result;					goto ErrorExit;			}		}    }    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;}                               