static PRStatus PR_CALLBACK SocketConnect( PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime timeout) { PRInt32 rv; /* Return value of _PR_MD_CONNECT */ const PRNetAddr *addrp = addr; #if defined(_PR_INET6) PRNetAddr addrCopy; #endif PRThread *me = _PR_MD_CURRENT_THREAD(); if (_PR_PENDING_INTERRUPT(me)) { me->flags &= ~_PR_INTERRUPT; PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); return PR_FAILURE; } #if defined(_PR_INET6) if (addr->raw.family == PR_AF_INET6) { addrCopy = *addr; addrCopy.raw.family = AF_INET6; addrp = &addrCopy; } #endif rv = _PR_MD_CONNECT(fd, addrp, PR_NETADDR_SIZE(addr), timeout); PR_LOG(_pr_io_lm, PR_LOG_MAX, ("connect -> %d", rv)); if (rv == 0) return PR_SUCCESS; else return PR_FAILURE; }
static PRInt32 PR_CALLBACK SocketRecvFrom(PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags, PRNetAddr *addr, PRIntervalTime timeout) { PRInt32 rv; PRUint32 al; PRThread *me = _PR_MD_CURRENT_THREAD(); if (_PR_PENDING_INTERRUPT(me)) { me->flags &= ~_PR_INTERRUPT; PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); return -1; } if (_PR_IO_PENDING(me)) { PR_SetError(PR_IO_PENDING_ERROR, 0); return -1; } al = sizeof(PRNetAddr); rv = _PR_MD_RECVFROM(fd, buf, amount, flags, addr, &al, timeout); #ifdef _PR_INET6 if (addr && (AF_INET6 == addr->raw.family)) addr->raw.family = PR_AF_INET6; #endif return rv; }
static PRInt32 PR_CALLBACK FileWrite(PRFileDesc *fd, const void *buf, PRInt32 amount) { PRInt32 rv = 0; PRInt32 temp, count; PRThread *me = _PR_MD_CURRENT_THREAD(); if (_PR_PENDING_INTERRUPT(me)) { me->flags &= ~_PR_INTERRUPT; PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); rv = -1; } if (_PR_IO_PENDING(me)) { PR_SetError(PR_IO_PENDING_ERROR, 0); rv = -1; } if (rv != 0) return rv; count = 0; while (amount > 0) { temp = _PR_MD_WRITE(fd, buf, amount); if (temp < 0) { count = -1; break; } count += temp; if (fd->secret->nonblocking) { break; } buf = (const void*) ((const char*)buf + temp); amount -= temp; } PR_LOG(_pr_io_lm, PR_LOG_MAX, ("write -> %d", count)); return count; }
static PRInt32 PR_CALLBACK SocketAcceptRead(PRFileDesc *sd, PRFileDesc **nd, PRNetAddr **raddr, void *buf, PRInt32 amount, PRIntervalTime timeout) { PRInt32 rv; PRThread *me = _PR_MD_CURRENT_THREAD(); if (_PR_PENDING_INTERRUPT(me)) { me->flags &= ~_PR_INTERRUPT; PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); return -1; } if (_PR_IO_PENDING(me)) { PR_SetError(PR_IO_PENDING_ERROR, 0); return -1; } /* The socket must be in blocking mode. */ if (sd->secret->nonblocking) { PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); return -1; } *nd = NULL; #if defined(WINNT) { PROsfd newSock; PRNetAddr *raddrCopy; if (raddr == NULL) { raddr = &raddrCopy; } rv = _PR_MD_ACCEPT_READ(sd, &newSock, raddr, buf, amount, timeout); if (rv < 0) { rv = -1; } else { /* Successfully accepted and read; create the new PRFileDesc */ *nd = PR_AllocFileDesc(newSock, PR_GetTCPMethods()); if (*nd == 0) { _PR_MD_CLOSE_SOCKET(newSock); /* PR_AllocFileDesc() has invoked PR_SetError(). */ rv = -1; } else { (*nd)->secret->md.io_model_committed = PR_TRUE; (*nd)->secret->md.accepted_socket = PR_TRUE; memcpy(&(*nd)->secret->md.peer_addr, *raddr, PR_NETADDR_SIZE(*raddr)); #ifdef _PR_INET6 if (AF_INET6 == *raddr->raw.family) *raddr->raw.family = PR_AF_INET6; #endif } } } #else rv = PR_EmulateAcceptRead(sd, nd, raddr, buf, amount, timeout); #endif return rv; }
PR_IMPLEMENT(PRInt32) PR_NTFast_AcceptRead_WithTimeoutCallback( PRFileDesc *sd, PRFileDesc **nd, PRNetAddr **raddr, void *buf, PRInt32 amount, PRIntervalTime timeout, _PR_AcceptTimeoutCallback callback, void *callbackArg) { PRInt32 rv; PROsfd newSock; PRThread *me = _PR_MD_CURRENT_THREAD(); PRNetAddr *raddrCopy; if (_PR_PENDING_INTERRUPT(me)) { me->flags &= ~_PR_INTERRUPT; PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); return -1; } if (_PR_IO_PENDING(me)) { PR_SetError(PR_IO_PENDING_ERROR, 0); return -1; } *nd = NULL; if (raddr == NULL) { raddr = &raddrCopy; } rv = _PR_MD_FAST_ACCEPT_READ(sd, &newSock, raddr, buf, amount, timeout, PR_TRUE, callback, callbackArg); if (rv < 0) { rv = -1; } else { /* Successfully accepted and read; create the new PRFileDesc */ *nd = PR_AllocFileDesc(newSock, PR_GetTCPMethods()); if (*nd == 0) { _PR_MD_CLOSE_SOCKET(newSock); /* PR_AllocFileDesc() has invoked PR_SetError(). */ rv = -1; } else { (*nd)->secret->md.io_model_committed = PR_TRUE; (*nd)->secret->md.accepted_socket = PR_TRUE; memcpy(&(*nd)->secret->md.peer_addr, *raddr, PR_NETADDR_SIZE(*raddr)); #ifdef _PR_INET6 if (AF_INET6 == *raddr->raw.family) *raddr->raw.family = PR_AF_INET6; #endif #ifdef _PR_NEED_SECRET_AF (*nd)->secret->af = sd->secret->af; #endif } } return rv; }
static PRInt32 PR_CALLBACK SocketSendTo( PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags, const PRNetAddr *addr, PRIntervalTime timeout) { PRInt32 temp, count; const PRNetAddr *addrp = addr; #if defined(_PR_INET6) PRNetAddr addrCopy; #endif PRThread *me = _PR_MD_CURRENT_THREAD(); if (_PR_PENDING_INTERRUPT(me)) { me->flags &= ~_PR_INTERRUPT; PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); return -1; } if (_PR_IO_PENDING(me)) { PR_SetError(PR_IO_PENDING_ERROR, 0); return -1; } PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE); #if defined(_PR_INET6) if (addr->raw.family == PR_AF_INET6) { addrCopy = *addr; addrCopy.raw.family = AF_INET6; addrp = &addrCopy; } #endif count = 0; while (amount > 0) { temp = _PR_MD_SENDTO(fd, buf, amount, flags, addrp, PR_NETADDR_SIZE(addr), timeout); if (temp < 0) { count = -1; break; } count += temp; if (fd->secret->nonblocking) { break; } buf = (const void*) ((const char*)buf + temp); amount -= temp; } return count; }
static PRInt32 PR_CALLBACK SocketTransmitFile(PRFileDesc *sd, PRFileDesc *fd, const void *headers, PRInt32 hlen, PRTransmitFileFlags flags, PRIntervalTime timeout) { PRInt32 rv; PRThread *me = _PR_MD_CURRENT_THREAD(); if (_PR_PENDING_INTERRUPT(me)) { me->flags &= ~_PR_INTERRUPT; PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); return -1; } if (_PR_IO_PENDING(me)) { PR_SetError(PR_IO_PENDING_ERROR, 0); return -1; } #if defined(WINNT) rv = _PR_MD_TRANSMITFILE( sd, fd, headers, hlen, flags, timeout); if (rv < 0) { rv = -1; } if (flags & PR_TRANSMITFILE_CLOSE_SOCKET) { /* * This should be kept the same as SocketClose, except * that _PR_MD_CLOSE_SOCKET(sd->secret->md.osfd) should * not be called because the socket will be recycled. */ sd->secret->state = _PR_FILEDESC_CLOSED; PR_FreeFileDesc(sd); } #else #if defined(XP_UNIX) /* * On HPUX11, we could call _PR_HPUXTransmitFile(), but that * would require that we not override the malloc() functions. */ rv = _PR_UnixTransmitFile(sd, fd, headers, hlen, flags, timeout); #else /* XP_UNIX */ rv = _PR_EmulateTransmitFile(sd, fd, headers, hlen, flags, timeout); #endif /* XP_UNIX */ #endif /* WINNT */ return rv; }
PR_IMPLEMENT(PRFileDesc*) PR_NTFast_Accept(PRFileDesc *fd, PRNetAddr *addr, PRIntervalTime timeout) { PROsfd osfd; PRFileDesc *fd2; PRIntn al; PRThread *me = _PR_MD_CURRENT_THREAD(); PRNetAddr addrCopy; if (_PR_PENDING_INTERRUPT(me)) { me->flags &= ~_PR_INTERRUPT; PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); return 0; } if (_PR_IO_PENDING(me)) { PR_SetError(PR_IO_PENDING_ERROR, 0); return 0; } if (addr == NULL) { addr = &addrCopy; } al = PR_NETADDR_SIZE(addr); osfd = _PR_MD_FAST_ACCEPT(fd, addr, &al, timeout, PR_TRUE, NULL, NULL); if (osfd == -1) { return 0; } fd2 = PR_AllocFileDesc(osfd, PR_GetTCPMethods()); if (!fd2) { _PR_MD_CLOSE_SOCKET(osfd); } else { fd2->secret->nonblocking = fd->secret->nonblocking; fd2->secret->md.io_model_committed = PR_TRUE; PR_ASSERT(al == PR_NETADDR_SIZE(addr)); fd2->secret->md.accepted_socket = PR_TRUE; memcpy(&fd2->secret->md.peer_addr, addr, al); #ifdef _PR_INET6 if (AF_INET6 == addr->raw.family) addr->raw.family = PR_AF_INET6; #endif #ifdef _PR_NEED_SECRET_AF fd2->secret->af = fd->secret->af; #endif } return fd2; }
PRInt32 _MD_pr_poll(PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout) { PRInt32 rv = 0; PRThread *me = _PR_MD_CURRENT_THREAD(); if (_PR_PENDING_INTERRUPT(me)) { me->flags &= ~_PR_INTERRUPT; PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); return -1; } if (0 == npds) PR_Sleep(timeout); else if (_PR_IS_NATIVE_THREAD(me)) rv = NativeThreads(pds, npds, timeout); else rv = LocalThreads(pds, npds, timeout); return rv; } /* _MD_pr_poll */
static PRStatus PR_CALLBACK SocketConnect( PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime timeout) { PRInt32 rv; /* Return value of _PR_MD_CONNECT */ PRThread *me = _PR_MD_CURRENT_THREAD(); if (_PR_PENDING_INTERRUPT(me)) { me->flags &= ~_PR_INTERRUPT; PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); return PR_FAILURE; } rv = _PR_MD_CONNECT(fd, addr, PR_NETADDR_SIZE(addr), timeout); PR_LOG(_pr_io_lm, PR_LOG_MAX, ("connect -> %d", rv)); if (rv == 0) return PR_SUCCESS; else return PR_FAILURE; }
static PRInt32 PR_CALLBACK SocketSend(PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags, PRIntervalTime timeout) { PRInt32 temp, count; PRThread *me = _PR_MD_CURRENT_THREAD(); if (_PR_PENDING_INTERRUPT(me)) { me->flags &= ~_PR_INTERRUPT; PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); return -1; } if (_PR_IO_PENDING(me)) { PR_SetError(PR_IO_PENDING_ERROR, 0); return -1; } count = 0; while (amount > 0) { PR_LOG(_pr_io_lm, PR_LOG_MAX, ("send: fd=%p osfd=%" PR_PRIdOSFD " buf=%p amount=%d", fd, fd->secret->md.osfd, buf, amount)); temp = _PR_MD_SEND(fd, buf, amount, flags, timeout); if (temp < 0) { count = -1; break; } count += temp; if (fd->secret->nonblocking) { break; } buf = (const void*) ((const char*)buf + temp); amount -= temp; } PR_LOG(_pr_io_lm, PR_LOG_MAX, ("send -> %d", count)); return count; }
static PRInt32 PR_CALLBACK SocketRecv(PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags, PRIntervalTime timeout) { PRInt32 rv; PRThread *me = _PR_MD_CURRENT_THREAD(); if (_PR_PENDING_INTERRUPT(me)) { me->flags &= ~_PR_INTERRUPT; PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); return -1; } if (_PR_IO_PENDING(me)) { PR_SetError(PR_IO_PENDING_ERROR, 0); return -1; } PR_LOG(_pr_io_lm, PR_LOG_MAX, ("recv: fd=%p osfd=%d buf=%p amount=%d", fd, fd->secret->md.osfd, buf, amount)); rv = _PR_MD_RECV(fd, buf, amount, flags, timeout); PR_LOG(_pr_io_lm, PR_LOG_MAX, ("recv -> %d, error = %d, os error = %d", rv, PR_GetError(), PR_GetOSError())); return rv; }
static PRInt32 PR_CALLBACK SocketSendFile( PRFileDesc *sd, PRSendFileData *sfd, PRTransmitFileFlags flags, PRIntervalTime timeout) { PRInt32 rv; PRThread *me = _PR_MD_CURRENT_THREAD(); if (_PR_PENDING_INTERRUPT(me)) { me->flags &= ~_PR_INTERRUPT; PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); return -1; } if (_PR_IO_PENDING(me)) { PR_SetError(PR_IO_PENDING_ERROR, 0); return -1; } /* The socket must be in blocking mode. */ if (sd->secret->nonblocking) { PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); return -1; } #if defined(WINNT) rv = _PR_MD_SENDFILE(sd, sfd, flags, timeout); if ((rv >= 0) && (flags == PR_TRANSMITFILE_CLOSE_SOCKET)) { /* * This should be kept the same as SocketClose, except * that _PR_MD_CLOSE_SOCKET(sd->secret->md.osfd) should * not be called because the socket will be recycled. */ PR_FreeFileDesc(sd); } #else rv = PR_EmulateSendFile(sd, sfd, flags, timeout); #endif /* WINNT */ return rv; }
static PRInt32 PR_CALLBACK FileRead(PRFileDesc *fd, void *buf, PRInt32 amount) { PRInt32 rv = 0; PRThread *me = _PR_MD_CURRENT_THREAD(); if (_PR_PENDING_INTERRUPT(me)) { me->flags &= ~_PR_INTERRUPT; PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); rv = -1; } if (_PR_IO_PENDING(me)) { PR_SetError(PR_IO_PENDING_ERROR, 0); rv = -1; } if (rv == -1) return rv; rv = _PR_MD_READ(fd, buf, amount); if (rv < 0) { PR_ASSERT(rv == -1); } PR_LOG(_pr_io_lm, PR_LOG_MAX, ("read -> %d", rv)); return rv; }
PR_IMPLEMENT(PRRecvWait*) PR_WaitRecvReady(PRWaitGroup *group) { PRCList *io_ready = NULL; #ifdef WINNT PRThread *me = _PR_MD_CURRENT_THREAD(); _MDOverlapped *overlapped; #endif if (!_pr_initialized) _PR_ImplicitInitialization(); if ((NULL == group) && (NULL == (group = MW_Init2()))) goto failed_init; PR_Lock(group->ml); if (_prmw_running != group->state) { PR_SetError(PR_INVALID_STATE_ERROR, 0); goto invalid_state; } group->waiting_threads += 1; /* the polling thread is counted */ #ifdef WINNT _PR_MD_LOCK(&group->mdlock); while (PR_CLIST_IS_EMPTY(&group->io_ready)) { _PR_THREAD_LOCK(me); me->state = _PR_IO_WAIT; PR_APPEND_LINK(&me->waitQLinks, &group->wait_list); if (!_PR_IS_NATIVE_THREAD(me)) { _PR_SLEEPQ_LOCK(me->cpu); _PR_ADD_SLEEPQ(me, PR_INTERVAL_NO_TIMEOUT); _PR_SLEEPQ_UNLOCK(me->cpu); } _PR_THREAD_UNLOCK(me); _PR_MD_UNLOCK(&group->mdlock); PR_Unlock(group->ml); _PR_MD_WAIT(me, PR_INTERVAL_NO_TIMEOUT); me->state = _PR_RUNNING; PR_Lock(group->ml); _PR_MD_LOCK(&group->mdlock); if (_PR_PENDING_INTERRUPT(me)) { PR_REMOVE_LINK(&me->waitQLinks); _PR_MD_UNLOCK(&group->mdlock); me->flags &= ~_PR_INTERRUPT; me->io_suspended = PR_FALSE; PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); goto aborted; } } io_ready = PR_LIST_HEAD(&group->io_ready); PR_ASSERT(io_ready != NULL); PR_REMOVE_LINK(io_ready); _PR_MD_UNLOCK(&group->mdlock); overlapped = (_MDOverlapped *) ((char *)io_ready - offsetof(_MDOverlapped, data)); io_ready = &overlapped->data.mw.desc->internal; #else do { /* ** If the I/O ready list isn't empty, have this thread ** return with the first receive wait object that's available. */ if (PR_CLIST_IS_EMPTY(&group->io_ready)) { /* ** Is there a polling thread yet? If not, grab this thread ** and use it. */ if (NULL == group->poller) { /* ** This thread will stay do polling until it becomes the only one ** left to service a completion. Then it will return and there will ** be none left to actually poll or to run completions. ** ** The polling function should only return w/ failure or ** with some I/O ready. */ if (PR_FAILURE == _MW_PollInternal(group)) goto failed_poll; } else { /* ** There are four reasons a thread can be awakened from ** a wait on the io_complete condition variable. ** 1. Some I/O has completed, i.e., the io_ready list ** is nonempty. ** 2. The wait group is canceled. ** 3. The thread is interrupted. ** 4. The current polling thread has to leave and needs ** a replacement. ** The logic to find a new polling thread is made more ** complicated by all the other possible events. ** I tried my best to write the logic clearly, but ** it is still full of if's with continue and goto. */ PRStatus st; do { st = PR_WaitCondVar(group->io_complete, PR_INTERVAL_NO_TIMEOUT); if (_prmw_running != group->state) { PR_SetError(PR_INVALID_STATE_ERROR, 0); goto aborted; } if (_MW_ABORTED(st) || (NULL == group->poller)) break; } while (PR_CLIST_IS_EMPTY(&group->io_ready)); /* ** The thread is interrupted and has to leave. It might ** have also been awakened to process ready i/o or be the ** new poller. To be safe, if either condition is true, ** we awaken another thread to take its place. */ if (_MW_ABORTED(st)) { if ((NULL == group->poller || !PR_CLIST_IS_EMPTY(&group->io_ready)) && group->waiting_threads > 1) PR_NotifyCondVar(group->io_complete); goto aborted; } /* ** A new poller is needed, but can I be the new poller? ** If there is no i/o ready, sure. But if there is any ** i/o ready, it has a higher priority. I want to ** process the ready i/o first and wake up another ** thread to be the new poller. */ if (NULL == group->poller) { if (PR_CLIST_IS_EMPTY(&group->io_ready)) continue; if (group->waiting_threads > 1) PR_NotifyCondVar(group->io_complete); } } PR_ASSERT(!PR_CLIST_IS_EMPTY(&group->io_ready)); } io_ready = PR_LIST_HEAD(&group->io_ready); PR_NotifyCondVar(group->io_taken); PR_ASSERT(io_ready != NULL); PR_REMOVE_LINK(io_ready); } while (NULL == io_ready); failed_poll: #endif aborted: group->waiting_threads -= 1; invalid_state: (void)MW_TestForShutdownInternal(group); PR_Unlock(group->ml); failed_init: if (NULL != io_ready) { /* If the operation failed, record the reason why */ switch (((PRRecvWait*)io_ready)->outcome) { case PR_MW_PENDING: PR_ASSERT(0); break; case PR_MW_SUCCESS: #ifndef WINNT _MW_InitialRecv(io_ready); #endif break; #ifdef WINNT case PR_MW_FAILURE: _PR_MD_MAP_READ_ERROR(overlapped->data.mw.error); break; #endif case PR_MW_TIMEOUT: PR_SetError(PR_IO_TIMEOUT_ERROR, 0); break; case PR_MW_INTERRUPT: PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); break; default: break; } #ifdef WINNT if (NULL != overlapped->data.mw.timer) { PR_ASSERT(PR_INTERVAL_NO_TIMEOUT != overlapped->data.mw.desc->timeout); CancelTimer(overlapped->data.mw.timer); } else { PR_ASSERT(PR_INTERVAL_NO_TIMEOUT == overlapped->data.mw.desc->timeout); } PR_DELETE(overlapped); #endif } return (PRRecvWait*)io_ready; } /* PR_WaitRecvReady */
/* ** Make the given thread wait for the given condition variable */ PRStatus _PR_WaitCondVar( PRThread *thread, PRCondVar *cvar, PRLock *lock, PRIntervalTime timeout) { PRIntn is; PRStatus rv = PR_SUCCESS; PR_ASSERT(thread == _PR_MD_CURRENT_THREAD()); PR_ASSERT(!(thread->flags & _PR_IDLE_THREAD)); #ifdef _PR_GLOBAL_THREADS_ONLY if (_PR_PENDING_INTERRUPT(thread)) { PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); thread->flags &= ~_PR_INTERRUPT; return PR_FAILURE; } thread->wait.cvar = cvar; lock->owner = NULL; _PR_MD_WAIT_CV(&cvar->md,&lock->ilock, timeout); thread->wait.cvar = NULL; lock->owner = thread; if (_PR_PENDING_INTERRUPT(thread)) { PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); thread->flags &= ~_PR_INTERRUPT; return PR_FAILURE; } return PR_SUCCESS; #else /* _PR_GLOBAL_THREADS_ONLY */ if ( !_PR_IS_NATIVE_THREAD(thread)) _PR_INTSOFF(is); _PR_CVAR_LOCK(cvar); _PR_THREAD_LOCK(thread); if (_PR_PENDING_INTERRUPT(thread)) { PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); thread->flags &= ~_PR_INTERRUPT; _PR_CVAR_UNLOCK(cvar); _PR_THREAD_UNLOCK(thread); if ( !_PR_IS_NATIVE_THREAD(thread)) _PR_INTSON(is); return PR_FAILURE; } thread->state = _PR_COND_WAIT; thread->wait.cvar = cvar; /* ** Put the caller thread on the condition variable's wait Q */ PR_APPEND_LINK(&thread->waitQLinks, &cvar->condQ); /* Note- for global scope threads, we don't put them on the * global sleepQ, so each global thread must put itself * to sleep only for the time it wants to. */ if ( !_PR_IS_NATIVE_THREAD(thread) ) { _PR_SLEEPQ_LOCK(thread->cpu); _PR_ADD_SLEEPQ(thread, timeout); _PR_SLEEPQ_UNLOCK(thread->cpu); } _PR_CVAR_UNLOCK(cvar); _PR_THREAD_UNLOCK(thread); /* ** Release lock protecting the condition variable and thereby giving time ** to the next thread which can potentially notify on the condition variable */ PR_Unlock(lock); PR_LOG(_pr_cvar_lm, PR_LOG_MIN, ("PR_Wait: cvar=%p waiting for %d", cvar, timeout)); rv = _PR_MD_WAIT(thread, timeout); _PR_CVAR_LOCK(cvar); PR_REMOVE_LINK(&thread->waitQLinks); _PR_CVAR_UNLOCK(cvar); PR_LOG(_pr_cvar_lm, PR_LOG_MIN, ("PR_Wait: cvar=%p done waiting", cvar)); if ( !_PR_IS_NATIVE_THREAD(thread)) _PR_INTSON(is); /* Acquire lock again that we had just relinquished */ PR_Lock(lock); if (_PR_PENDING_INTERRUPT(thread)) { PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); thread->flags &= ~_PR_INTERRUPT; return PR_FAILURE; } return rv; #endif /* _PR_GLOBAL_THREADS_ONLY */ }
PRInt32 _PR_EmulateTransmitFile(PRFileDesc *sd, PRFileDesc *fd, const void *headers, PRInt32 hlen, PRTransmitFileFlags flags, PRIntervalTime timeout) { PRInt32 rv, count = 0; PRInt32 rlen; PRThread *me = _PR_MD_CURRENT_THREAD(); char *buf = NULL; #define _TRANSMITFILE_BUFSIZE (16 * 1024) if (_PR_PENDING_INTERRUPT(me)) { me->flags &= ~_PR_INTERRUPT; PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); return -1; } buf = PR_MALLOC(_TRANSMITFILE_BUFSIZE); if (buf == NULL) { PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); return -1; } /* * send headers, first */ while (hlen) { rv = PR_Send(sd, headers, hlen, 0, timeout); if (rv < 0) { /* PR_Send() has invoked PR_SetError(). */ rv = -1; goto done; } else { count += rv; headers = (const void*) ((const char*)headers + rv); hlen -= rv; } } /* * send file, next */ while ((rlen = PR_Read(fd, buf, _TRANSMITFILE_BUFSIZE)) > 0) { while (rlen) { char *bufptr = buf; rv = PR_Send(sd, bufptr, rlen,0,PR_INTERVAL_NO_TIMEOUT); if (rv < 0) { /* PR_Send() has invoked PR_SetError(). */ rv = -1; goto done; } else { count += rv; bufptr = ((char*)bufptr + rv); rlen -= rv; } } } if (rlen == 0) { /* * end-of-file */ if (flags & PR_TRANSMITFILE_CLOSE_SOCKET) PR_Close(sd); rv = count; } else { PR_ASSERT(rlen < 0); /* PR_Read() has invoked PR_SetError(). */ rv = -1; } done: if (buf) PR_DELETE(buf); return rv; }
static PRInt32 PR_CALLBACK SocketWritev(PRFileDesc *fd, PRIOVec *iov, PRInt32 iov_size, PRIntervalTime timeout) { PRThread *me = _PR_MD_CURRENT_THREAD(); int w = 0; PRIOVec *tmp_iov = NULL; int tmp_out; int index, iov_cnt; int count=0, sz = 0; /* 'count' is the return value. */ #if defined(XP_UNIX) struct timeval tv, *tvp; fd_set wd; FD_ZERO(&wd); if (timeout == PR_INTERVAL_NO_TIMEOUT) tvp = NULL; else if (timeout != PR_INTERVAL_NO_WAIT) { tv.tv_sec = PR_IntervalToSeconds(timeout); tv.tv_usec = PR_IntervalToMicroseconds( timeout - PR_SecondsToInterval(tv.tv_sec)); tvp = &tv; } #endif if (_PR_PENDING_INTERRUPT(me)) { me->flags &= ~_PR_INTERRUPT; PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); return -1; } if (_PR_IO_PENDING(me)) { PR_SetError(PR_IO_PENDING_ERROR, 0); return -1; } tmp_iov = (PRIOVec *)PR_CALLOC(iov_size * sizeof(PRIOVec)); if (!tmp_iov) { PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); return -1; } for (index=0; index<iov_size; index++) { sz += iov[index].iov_len; tmp_iov[index].iov_base = iov[index].iov_base; tmp_iov[index].iov_len = iov[index].iov_len; } iov_cnt = iov_size; while (sz > 0) { w = _PR_MD_WRITEV(fd, tmp_iov, iov_cnt, timeout); if (w < 0) { count = -1; break; } count += w; if (fd->secret->nonblocking) { break; } sz -= w; if (sz > 0) { /* find the next unwritten vector */ for ( index = 0, tmp_out = count; tmp_out >= iov[index].iov_len; tmp_out -= iov[index].iov_len, index++){;} /* nothing to execute */ /* fill in the first partial read */ tmp_iov[0].iov_base = &(((char *)iov[index].iov_base)[tmp_out]); tmp_iov[0].iov_len = iov[index].iov_len - tmp_out; index++; /* copy the remaining vectors */ for (iov_cnt=1; index<iov_size; iov_cnt++, index++) { tmp_iov[iov_cnt].iov_base = iov[index].iov_base; tmp_iov[iov_cnt].iov_len = iov[index].iov_len; } } } if (tmp_iov) PR_DELETE(tmp_iov); return count; }
static PRInt32 PR_CALLBACK SocketWritev(PRFileDesc *fd, const PRIOVec *iov, PRInt32 iov_size, PRIntervalTime timeout) { PRThread *me = _PR_MD_CURRENT_THREAD(); int w = 0; const PRIOVec *tmp_iov; #define LOCAL_MAXIOV 8 PRIOVec local_iov[LOCAL_MAXIOV]; PRIOVec *iov_copy = NULL; int tmp_out; int index, iov_cnt; int count=0, sz = 0; /* 'count' is the return value. */ if (_PR_PENDING_INTERRUPT(me)) { me->flags &= ~_PR_INTERRUPT; PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); return -1; } if (_PR_IO_PENDING(me)) { PR_SetError(PR_IO_PENDING_ERROR, 0); return -1; } /* * Assume the first writev will succeed. Copy iov's only on * failure. */ tmp_iov = iov; for (index = 0; index < iov_size; index++) sz += iov[index].iov_len; iov_cnt = iov_size; while (sz > 0) { w = _PR_MD_WRITEV(fd, tmp_iov, iov_cnt, timeout); if (w < 0) { count = -1; break; } count += w; if (fd->secret->nonblocking) { break; } sz -= w; if (sz > 0) { /* find the next unwritten vector */ for ( index = 0, tmp_out = count; tmp_out >= iov[index].iov_len; tmp_out -= iov[index].iov_len, index++){;} /* nothing to execute */ if (tmp_iov == iov) { /* * The first writev failed so we * must copy iov's around. * Avoid calloc/free if there * are few enough iov's. */ if (iov_size - index <= LOCAL_MAXIOV) iov_copy = local_iov; else if ((iov_copy = (PRIOVec *) PR_CALLOC((iov_size - index) * sizeof *iov_copy)) == NULL) { PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); return -1; } tmp_iov = iov_copy; } PR_ASSERT(tmp_iov == iov_copy); /* fill in the first partial read */ iov_copy[0].iov_base = &(((char *)iov[index].iov_base)[tmp_out]); iov_copy[0].iov_len = iov[index].iov_len - tmp_out; index++; /* copy the remaining vectors */ for (iov_cnt=1; index<iov_size; iov_cnt++, index++) { iov_copy[iov_cnt].iov_base = iov[index].iov_base; iov_copy[iov_cnt].iov_len = iov[index].iov_len; } } } if (iov_copy != local_iov) PR_DELETE(iov_copy); return count; }
static PRInt32 PR_CALLBACK SocketRecv(PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags, PRIntervalTime timeout) { PRInt32 rv; PRThread *me = _PR_MD_CURRENT_THREAD(); if ((flags != 0) && (flags != PR_MSG_PEEK)) { PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); return -1; } if (_PR_PENDING_INTERRUPT(me)) { me->flags &= ~_PR_INTERRUPT; PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); return -1; } if (_PR_IO_PENDING(me)) { PR_SetError(PR_IO_PENDING_ERROR, 0); return -1; } PR_LOG(_pr_io_lm, PR_LOG_MAX, ("recv: fd=%p osfd=%" PR_PRIdOSFD " buf=%p amount=%d flags=%d", fd, fd->secret->md.osfd, buf, amount, flags)); #ifdef _PR_HAVE_PEEK_BUFFER if (fd->secret->peekBytes != 0) { rv = (amount < fd->secret->peekBytes) ? amount : fd->secret->peekBytes; memcpy(buf, fd->secret->peekBuffer, rv); if (flags == 0) { /* consume the bytes in the peek buffer */ fd->secret->peekBytes -= rv; if (fd->secret->peekBytes != 0) { memmove(fd->secret->peekBuffer, fd->secret->peekBuffer + rv, fd->secret->peekBytes); } } return rv; } /* allocate peek buffer, if necessary */ if ((PR_MSG_PEEK == flags) && _PR_FD_NEED_EMULATE_MSG_PEEK(fd)) { PR_ASSERT(0 == fd->secret->peekBytes); /* impose a max size on the peek buffer */ if (amount > _PR_PEEK_BUFFER_MAX) { amount = _PR_PEEK_BUFFER_MAX; } if (fd->secret->peekBufSize < amount) { if (fd->secret->peekBuffer) { PR_Free(fd->secret->peekBuffer); } fd->secret->peekBufSize = amount; fd->secret->peekBuffer = PR_Malloc(amount); if (NULL == fd->secret->peekBuffer) { fd->secret->peekBufSize = 0; PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); return -1; } } } #endif rv = _PR_MD_RECV(fd, buf, amount, flags, timeout); PR_LOG(_pr_io_lm, PR_LOG_MAX, ("recv -> %d, error = %d, os error = %d", rv, PR_GetError(), PR_GetOSError())); #ifdef _PR_HAVE_PEEK_BUFFER if ((PR_MSG_PEEK == flags) && _PR_FD_NEED_EMULATE_MSG_PEEK(fd)) { if (rv > 0) { memcpy(fd->secret->peekBuffer, buf, rv); fd->secret->peekBytes = rv; } } #endif return rv; }
static PRInt32 socket_io_wait( PROsfd osfd, PRInt32 fd_type, PRIntervalTime timeout) { PRInt32 rv = -1; struct timeval tv; PRThread *me = _PR_MD_CURRENT_THREAD(); PRIntervalTime elapsed, remaining; PRBool wait_for_remaining; fd_set rd_wr, ex; int err, len; switch (timeout) { case PR_INTERVAL_NO_WAIT: PR_SetError(PR_IO_TIMEOUT_ERROR, 0); break; case PR_INTERVAL_NO_TIMEOUT: /* * This is a special case of the 'default' case below. * Please see the comments there. */ tv.tv_sec = _PR_INTERRUPT_CHECK_INTERVAL_SECS; tv.tv_usec = 0; FD_ZERO(&rd_wr); FD_ZERO(&ex); do { FD_SET(osfd, &rd_wr); FD_SET(osfd, &ex); switch( fd_type ) { case READ_FD: rv = _MD_SELECT(0, &rd_wr, NULL, NULL, &tv); break; case WRITE_FD: rv = _MD_SELECT(0, NULL, &rd_wr, NULL, &tv); break; case CONNECT_FD: rv = _MD_SELECT(0, NULL, &rd_wr, &ex, &tv); break; default: PR_ASSERT(0); break; } /* end switch() */ if (rv == -1 ) { _PR_MD_MAP_SELECT_ERROR(WSAGetLastError()); break; } if ( rv > 0 && fd_type == CONNECT_FD ) { /* * Call Sleep(0) to work around a Winsock timing bug. */ Sleep(0); if (FD_ISSET((SOCKET)osfd, &ex)) { len = sizeof(err); if (getsockopt(osfd, SOL_SOCKET, SO_ERROR, (char *) &err, &len) == SOCKET_ERROR) { _PR_MD_MAP_GETSOCKOPT_ERROR(WSAGetLastError()); return -1; } if (err != 0) _PR_MD_MAP_CONNECT_ERROR(err); else PR_SetError(PR_UNKNOWN_ERROR, 0); return -1; } if (FD_ISSET((SOCKET)osfd, &rd_wr)) { /* it's connected */ return 1; } PR_ASSERT(0); } if (_PR_PENDING_INTERRUPT(me)) { me->flags &= ~_PR_INTERRUPT; PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); rv = -1; break; } } while (rv == 0); break; default: remaining = timeout; FD_ZERO(&rd_wr); FD_ZERO(&ex); do { /* * We block in _MD_SELECT for at most * _PR_INTERRUPT_CHECK_INTERVAL_SECS seconds, * so that there is an upper limit on the delay * before the interrupt bit is checked. */ wait_for_remaining = PR_TRUE; tv.tv_sec = PR_IntervalToSeconds(remaining); if (tv.tv_sec > _PR_INTERRUPT_CHECK_INTERVAL_SECS) { wait_for_remaining = PR_FALSE; tv.tv_sec = _PR_INTERRUPT_CHECK_INTERVAL_SECS; tv.tv_usec = 0; } else { tv.tv_usec = PR_IntervalToMicroseconds( remaining - PR_SecondsToInterval(tv.tv_sec)); } FD_SET(osfd, &rd_wr); FD_SET(osfd, &ex); switch( fd_type ) { case READ_FD: rv = _MD_SELECT(0, &rd_wr, NULL, NULL, &tv); break; case WRITE_FD: rv = _MD_SELECT(0, NULL, &rd_wr, NULL, &tv); break; case CONNECT_FD: rv = _MD_SELECT(0, NULL, &rd_wr, &ex, &tv); break; default: PR_ASSERT(0); break; } /* end switch() */ if (rv == -1) { _PR_MD_MAP_SELECT_ERROR(WSAGetLastError()); break; } if ( rv > 0 && fd_type == CONNECT_FD ) { /* * Call Sleep(0) to work around a Winsock timing bug. */ Sleep(0); if (FD_ISSET((SOCKET)osfd, &ex)) { len = sizeof(err); if (getsockopt(osfd, SOL_SOCKET, SO_ERROR, (char *) &err, &len) == SOCKET_ERROR) { _PR_MD_MAP_GETSOCKOPT_ERROR(WSAGetLastError()); return -1; } if (err != 0) _PR_MD_MAP_CONNECT_ERROR(err); else PR_SetError(PR_UNKNOWN_ERROR, 0); return -1; } if (FD_ISSET((SOCKET)osfd, &rd_wr)) { /* it's connected */ return 1; } PR_ASSERT(0); } if (_PR_PENDING_INTERRUPT(me)) { me->flags &= ~_PR_INTERRUPT; PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); rv = -1; break; } /* * We loop again if _MD_SELECT timed out and the * timeout deadline has not passed yet. */ if (rv == 0 ) { if (wait_for_remaining) { elapsed = remaining; } else { elapsed = PR_SecondsToInterval(tv.tv_sec) + PR_MicrosecondsToInterval(tv.tv_usec); } if (elapsed >= remaining) { PR_SetError(PR_IO_TIMEOUT_ERROR, 0); rv = -1; break; } else { remaining = remaining - elapsed; } } } while (rv == 0 ); break; } return(rv); } /* end socket_io_wait() */
static PRFileDesc* PR_CALLBACK SocketAccept(PRFileDesc *fd, PRNetAddr *addr, PRIntervalTime timeout) { PROsfd osfd; PRFileDesc *fd2; PRUint32 al; PRThread *me = _PR_MD_CURRENT_THREAD(); #ifdef WINNT PRNetAddr addrCopy; #endif if (_PR_PENDING_INTERRUPT(me)) { me->flags &= ~_PR_INTERRUPT; PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); return 0; } if (_PR_IO_PENDING(me)) { PR_SetError(PR_IO_PENDING_ERROR, 0); return 0; } #ifdef WINNT if (addr == NULL) { addr = &addrCopy; } #endif al = sizeof(PRNetAddr); osfd = _PR_MD_ACCEPT(fd, addr, &al, timeout); if (osfd == -1) return 0; fd2 = PR_AllocFileDesc(osfd, PR_GetTCPMethods()); if (!fd2) { _PR_MD_CLOSE_SOCKET(osfd); return NULL; } fd2->secret->nonblocking = fd->secret->nonblocking; fd2->secret->inheritable = fd->secret->inheritable; #ifdef WINNT if (!fd2->secret->nonblocking && fd2->secret->inheritable != _PR_TRI_TRUE) { /* * The new socket has been associated with an I/O * completion port. There is no going back. */ fd2->secret->md.io_model_committed = PR_TRUE; } PR_ASSERT(al == PR_NETADDR_SIZE(addr)); fd2->secret->md.accepted_socket = PR_TRUE; memcpy(&fd2->secret->md.peer_addr, addr, al); #endif /* * On some platforms, the new socket created by accept() * inherits the nonblocking (or overlapped io) attribute * of the listening socket. As an optimization, these * platforms can skip the following _PR_MD_MAKE_NONBLOCK * call. */ #if !defined(SOLARIS) && !defined(IRIX) && !defined(WINNT) _PR_MD_MAKE_NONBLOCK(fd2); #endif #ifdef _PR_INET6 if (addr && (AF_INET6 == addr->raw.family)) addr->raw.family = PR_AF_INET6; #endif PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE); PR_ASSERT(IsValidNetAddrLen(addr, al) == PR_TRUE); return fd2; }