PRInt32 tls13_ServerSendKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append, PRUint32 maxBytes) { PRUint32 extension_length; PRUint32 entry_length; SECStatus rv; sslEphemeralKeyPair *keyPair; /* There should be exactly one key share. */ PORT_Assert(!PR_CLIST_IS_EMPTY(&ss->ephemeralKeyPairs)); PORT_Assert(PR_PREV_LINK(&ss->ephemeralKeyPairs) == PR_NEXT_LINK(&ss->ephemeralKeyPairs)); keyPair = (sslEphemeralKeyPair *)PR_NEXT_LINK(&ss->ephemeralKeyPairs); entry_length = tls13_SizeOfKeyShareEntry(keyPair->keys->pubKey); extension_length = 2 + 2 + entry_length; /* Type + length + entry_length */ if (maxBytes < extension_length) { PORT_Assert(0); return 0; } if (append) { rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_tls13_key_share_xtn, 2); if (rv != SECSuccess) goto loser; rv = ssl3_ExtAppendHandshakeNumber(ss, entry_length, 2); if (rv != SECSuccess) goto loser; rv = tls13_EncodeKeyShareEntry(ss, keyPair); if (rv != SECSuccess) goto loser; } return extension_length; loser: return -1; }
PR_FindNextTraceQname( PRTraceHandle handle ) { QName *qnp = (QName *)handle; if ( PR_CLIST_IS_EMPTY( &qNameList )) qnp = NULL; else if ( qnp == NULL ) qnp = (QName *)PR_LIST_HEAD( &qNameList ); else if ( PR_NEXT_LINK( &qnp->link ) == &qNameList ) qnp = NULL; else qnp = (QName *)PR_NEXT_LINK( &qnp->link ); PR_LOG( lm, PR_LOG_DEBUG, ("PRTrace: FindNextQname: Handle: %p, Returns: %p", handle, qnp )); return((PRTraceHandle)qnp); } /* end PR_FindNextTraceQname() */
PR_DestroyTrace( PRTraceHandle handle /* Handle to be destroyed */ ) { RName *rnp = (RName *)handle; QName *qnp = rnp->qName; PR_LOG( lm, PR_LOG_DEBUG, ("PRTrace: Deleting: QName: %s, RName: %s", qnp->name, rnp->name)); /* Lock the Facility */ PR_Lock( traceLock ); /* ** Remove RName from the list of RNames in QName ** and free RName */ PR_LOG( lm, PR_LOG_DEBUG, ("PRTrace: Deleting RName: %s, %p", rnp->name, rnp)); PR_REMOVE_LINK( &rnp->link ); PR_Free( rnp->lock ); PR_DELETE( rnp ); /* ** If this is the last RName within QName ** remove QName from the qNameList and free it */ if ( PR_CLIST_IS_EMPTY( &qnp->rNameList ) ) { PR_LOG( lm, PR_LOG_DEBUG, ("PRTrace: Deleting unused QName: %s, %p", qnp->name, qnp)); PR_REMOVE_LINK( &qnp->link ); PR_DELETE( qnp ); } /* Unlock the Facility */ PR_Unlock( traceLock ); return; } /* end PR_DestroyTrace() */
void terminateWorkerThreads(void) { VLOG(("selfserv: server_thead: waiting on stopping")); PZ_Lock(qLock); PZ_NotifyAllCondVar(jobQNotEmptyCv); while (threadCount > 0) { PZ_WaitCondVar(threadCountChangeCv, PR_INTERVAL_NO_TIMEOUT); } /* The worker threads empty the jobQ before they terminate. */ PORT_Assert(PR_CLIST_IS_EMPTY(&jobQ)); PZ_Unlock(qLock); DESTROY_CONDVAR(jobQNotEmptyCv); DESTROY_CONDVAR(freeListNotEmptyCv); DESTROY_CONDVAR(threadCountChangeCv); PR_DestroyLock(lastLoadedCrlLock); DESTROY_LOCK(qLock); PR_Free(jobTable); PR_Free(threads); }
PR_FindNextTraceRname( PRTraceHandle rhandle, PRTraceHandle qhandle ) { RName *rnp = (RName *)rhandle; QName *qnp = (QName *)qhandle; if ( PR_CLIST_IS_EMPTY( &qnp->rNameList )) rnp = NULL; else if ( rnp == NULL ) rnp = (RName *)PR_LIST_HEAD( &qnp->rNameList ); else if ( PR_NEXT_LINK( &rnp->link ) == &qnp->rNameList ) rnp = NULL; else rnp = (RName *)PR_NEXT_LINK( &rnp->link ); PR_LOG( lm, PR_LOG_DEBUG, ("PRTrace: FindNextRname: Rhandle: %p, QHandle: %p, Returns: %p", rhandle, qhandle, rnp )); return((PRTraceHandle)rnp); } /* end PR_FindNextTraceRname() */
static PRAlarmID *pr_getNextAlarm(PRAlarm *alarm, PRAlarmID *id) { /* * Puts 'id' back into the sorted list iff it's not NULL. * Removes the first element from the list and returns it (or NULL). * List is "assumed" to be short. * * NB: Caller is providing locking */ PRCList *timer; PRAlarmID *result = id; PRIntervalTime now = PR_IntervalNow(); if (!PR_CLIST_IS_EMPTY(&alarm->timers)) { if (id != NULL) /* have to put this id back in */ { PRIntervalTime idDelta = now - id->nextNotify; timer = alarm->timers.next; do { result = (PRAlarmID*)timer; if ((PRIntervalTime)(now - result->nextNotify) > idDelta) { PR_INSERT_BEFORE(&id->list, &alarm->timers); break; } timer = timer->next; } while (timer != &alarm->timers); } result = (PRAlarmID*)(timer = PR_LIST_HEAD(&alarm->timers)); PR_REMOVE_LINK(timer); /* remove it from the list */ } return result; } /* pr_getNextAlarm */
/* * worker thread function */ static void wstart(void *arg) { PRThreadPool *tp = (PRThreadPool *) arg; PRCList *head; /* * execute jobs until shutdown */ while (!tp->shutdown) { PRJob *jobp; #ifdef OPT_WINNT BOOL rv; DWORD unused, shutdown; LPOVERLAPPED olp; PR_Lock(tp->jobq.lock); tp->idle_threads++; PR_Unlock(tp->jobq.lock); rv = GetQueuedCompletionStatus(tp->jobq.nt_completion_port, &unused, &shutdown, &olp, INFINITE); PR_ASSERT(rv); if (shutdown) break; jobp = ((NT_notifier *) olp)->jobp; PR_Lock(tp->jobq.lock); tp->idle_threads--; tp->jobq.cnt--; PR_Unlock(tp->jobq.lock); #else PR_Lock(tp->jobq.lock); while (PR_CLIST_IS_EMPTY(&tp->jobq.list) && (!tp->shutdown)) { tp->idle_threads++; PR_WaitCondVar(tp->jobq.cv, PR_INTERVAL_NO_TIMEOUT); tp->idle_threads--; } if (tp->shutdown) { PR_Unlock(tp->jobq.lock); break; } head = PR_LIST_HEAD(&tp->jobq.list); /* * remove job from queue */ PR_REMOVE_AND_INIT_LINK(head); tp->jobq.cnt--; jobp = JOB_LINKS_PTR(head); PR_Unlock(tp->jobq.lock); #endif jobp->job_func(jobp->job_arg); if (!JOINABLE_JOB(jobp)) { delete_job(jobp); } else { JOIN_NOTIFY(jobp); } } PR_Lock(tp->jobq.lock); tp->current_threads--; PR_Unlock(tp->jobq.lock); }
PR_JoinThreadPool(PRThreadPool *tpool) { PRStatus rval = PR_SUCCESS; PRCList *head; PRStatus rval_status; PR_Lock(tpool->jobq.lock); while (!tpool->shutdown) PR_WaitCondVar(tpool->shutdown_cv, PR_INTERVAL_NO_TIMEOUT); /* * wakeup worker threads */ #ifdef OPT_WINNT /* * post shutdown notification for all threads */ { int i; for(i=0; i < tpool->current_threads; i++) { PostQueuedCompletionStatus(tpool->jobq.nt_completion_port, 0, TRUE, NULL); } } #else PR_NotifyAllCondVar(tpool->jobq.cv); #endif /* * wakeup io thread(s) */ notify_ioq(tpool); /* * wakeup timer thread(s) */ PR_Lock(tpool->timerq.lock); notify_timerq(tpool); PR_Unlock(tpool->timerq.lock); while (!PR_CLIST_IS_EMPTY(&tpool->jobq.wthreads)) { wthread *wthrp; head = PR_LIST_HEAD(&tpool->jobq.wthreads); PR_REMOVE_AND_INIT_LINK(head); PR_Unlock(tpool->jobq.lock); wthrp = WTHREAD_LINKS_PTR(head); rval_status = PR_JoinThread(wthrp->thread); PR_ASSERT(PR_SUCCESS == rval_status); PR_DELETE(wthrp); PR_Lock(tpool->jobq.lock); } PR_Unlock(tpool->jobq.lock); while (!PR_CLIST_IS_EMPTY(&tpool->ioq.wthreads)) { wthread *wthrp; head = PR_LIST_HEAD(&tpool->ioq.wthreads); PR_REMOVE_AND_INIT_LINK(head); wthrp = WTHREAD_LINKS_PTR(head); rval_status = PR_JoinThread(wthrp->thread); PR_ASSERT(PR_SUCCESS == rval_status); PR_DELETE(wthrp); } while (!PR_CLIST_IS_EMPTY(&tpool->timerq.wthreads)) { wthread *wthrp; head = PR_LIST_HEAD(&tpool->timerq.wthreads); PR_REMOVE_AND_INIT_LINK(head); wthrp = WTHREAD_LINKS_PTR(head); rval_status = PR_JoinThread(wthrp->thread); PR_ASSERT(PR_SUCCESS == rval_status); PR_DELETE(wthrp); } /* * Delete queued jobs */ while (!PR_CLIST_IS_EMPTY(&tpool->jobq.list)) { PRJob *jobp; head = PR_LIST_HEAD(&tpool->jobq.list); PR_REMOVE_AND_INIT_LINK(head); jobp = JOB_LINKS_PTR(head); tpool->jobq.cnt--; delete_job(jobp); } /* delete io jobs */ while (!PR_CLIST_IS_EMPTY(&tpool->ioq.list)) { PRJob *jobp; head = PR_LIST_HEAD(&tpool->ioq.list); PR_REMOVE_AND_INIT_LINK(head); tpool->ioq.cnt--; jobp = JOB_LINKS_PTR(head); delete_job(jobp); } /* delete timer jobs */ while (!PR_CLIST_IS_EMPTY(&tpool->timerq.list)) { PRJob *jobp; head = PR_LIST_HEAD(&tpool->timerq.list); PR_REMOVE_AND_INIT_LINK(head); tpool->timerq.cnt--; jobp = JOB_LINKS_PTR(head); delete_job(jobp); } PR_ASSERT(0 == tpool->jobq.cnt); PR_ASSERT(0 == tpool->ioq.cnt); PR_ASSERT(0 == tpool->timerq.cnt); delete_threadpool(tpool); return rval; }
PR_IMPLEMENT(PRRecvWait*) PR_CancelWaitGroup(PRWaitGroup *group) { PRRecvWait **desc; PRRecvWait *recv_wait = NULL; #ifdef WINNT _MDOverlapped *overlapped; PRRecvWait **end; PRThread *me = _PR_MD_CURRENT_THREAD(); #endif if (NULL == group) group = mw_state->group; PR_ASSERT(NULL != group); if (NULL == group) { PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); return NULL; } PR_Lock(group->ml); if (_prmw_stopped != group->state) { if (_prmw_running == group->state) group->state = _prmw_stopping; /* so nothing new comes in */ if (0 == group->waiting_threads) /* is there anybody else? */ group->state = _prmw_stopped; /* we can stop right now */ else { PR_NotifyAllCondVar(group->new_business); PR_NotifyAllCondVar(group->io_complete); } while (_prmw_stopped != group->state) (void)PR_WaitCondVar(group->mw_manage, PR_INTERVAL_NO_TIMEOUT); } #ifdef WINNT _PR_MD_LOCK(&group->mdlock); #endif /* make all the existing descriptors look done/interrupted */ #ifdef WINNT end = &group->waiter->recv_wait + group->waiter->length; for (desc = &group->waiter->recv_wait; desc < end; ++desc) { if (NULL != *desc) { if (InterlockedCompareExchange((LONG *)&(*desc)->outcome, (LONG)PR_MW_INTERRUPT, (LONG)PR_MW_PENDING) == (LONG)PR_MW_PENDING) { PRFileDesc *bottom = PR_GetIdentitiesLayer( (*desc)->fd, PR_NSPR_IO_LAYER); PR_ASSERT(NULL != bottom); if (NULL == bottom) { PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); goto invalid_arg; } bottom->secret->state = _PR_FILEDESC_CLOSED; #if 0 fprintf(stderr, "cancel wait group: closing socket\n"); #endif if (closesocket(bottom->secret->md.osfd) == SOCKET_ERROR) { fprintf(stderr, "closesocket failed: %d\n", WSAGetLastError()); exit(1); } } } } while (group->waiter->count > 0) { _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); } #else for (desc = &group->waiter->recv_wait; group->waiter->count > 0; ++desc) { PR_ASSERT(desc < &group->waiter->recv_wait + group->waiter->length); if (NULL != *desc) _MW_DoneInternal(group, desc, PR_MW_INTERRUPT); } #endif /* take first element of finished list and return it or NULL */ if (PR_CLIST_IS_EMPTY(&group->io_ready)) PR_SetError(PR_GROUP_EMPTY_ERROR, 0); else { PRCList *head = PR_LIST_HEAD(&group->io_ready); PR_REMOVE_AND_INIT_LINK(head); #ifdef WINNT overlapped = (_MDOverlapped *) ((char *)head - offsetof(_MDOverlapped, data)); head = &overlapped->data.mw.desc->internal; 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 recv_wait = (PRRecvWait*)head; } #ifdef WINNT invalid_arg: _PR_MD_UNLOCK(&group->mdlock); #endif PR_Unlock(group->ml); return recv_wait; } /* PR_CancelWaitGroup */
PR_QueueJob_Timer(PRThreadPool *tpool, PRIntervalTime timeout, PRJobFn fn, void * arg, PRBool joinable) { PRIntervalTime now; PRJob *jobp; if (PR_INTERVAL_NO_TIMEOUT == timeout) { PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); return NULL; } if (PR_INTERVAL_NO_WAIT == timeout) { /* * no waiting; add to jobq right away */ return(PR_QueueJob(tpool, fn, arg, joinable)); } jobp = alloc_job(joinable, tpool); if (NULL == jobp) { return NULL; } /* * Add a new job to timer_jobq * wakeup timer worker thread */ jobp->job_func = fn; jobp->job_arg = arg; jobp->tpool = tpool; jobp->timeout = timeout; now = PR_IntervalNow(); jobp->absolute = now + timeout; PR_Lock(tpool->timerq.lock); jobp->on_timerq = PR_TRUE; if (PR_CLIST_IS_EMPTY(&tpool->timerq.list)) PR_APPEND_LINK(&jobp->links,&tpool->timerq.list); else { PRCList *qp; PRJob *tmp_jobp; /* * insert into the sorted timer jobq */ for (qp = tpool->timerq.list.prev; qp != &tpool->timerq.list; qp = qp->prev) { tmp_jobp = JOB_LINKS_PTR(qp); if ((PRInt32)(jobp->absolute - tmp_jobp->absolute) >= 0) { break; } } PR_INSERT_AFTER(&jobp->links,qp); } tpool->timerq.cnt++; /* * notify timer worker thread(s) */ notify_timerq(tpool); PR_Unlock(tpool->timerq.lock); return jobp; }
SECStatus do_accepts( PRFileDesc *listen_sock, PRFileDesc *model_sock, int requestCert ) { PRNetAddr addr; PRErrorCode perr; #ifdef XP_UNIX struct sigaction act; #endif VLOG(("selfserv: do_accepts: starting")); PR_SetThreadPriority( PR_GetCurrentThread(), PR_PRIORITY_HIGH); acceptorThread = PR_GetCurrentThread(); #ifdef XP_UNIX /* set up the signal handler */ act.sa_handler = sigusr1_handler; sigemptyset(&act.sa_mask); act.sa_flags = 0; if (sigaction(SIGUSR1, &act, NULL)) { fprintf(stderr, "Error installing signal handler.\n"); exit(1); } #endif while (!stopping) { PRFileDesc *tcp_sock; PRCList *myLink; FPRINTF(stderr, "\n\n\nselfserv: About to call accept.\n"); tcp_sock = PR_Accept(listen_sock, &addr, PR_INTERVAL_NO_TIMEOUT); if (tcp_sock == NULL) { perr = PR_GetError(); if ((perr != PR_CONNECT_RESET_ERROR && perr != PR_PENDING_INTERRUPT_ERROR) || verbose) { errWarn("PR_Accept"); } if (perr == PR_CONNECT_RESET_ERROR) { FPRINTF(stderr, "Ignoring PR_CONNECT_RESET_ERROR error - continue\n"); continue; } stopping = 1; break; } VLOG(("selfserv: do_accept: Got connection\n")); PZ_Lock(qLock); while (PR_CLIST_IS_EMPTY(&freeJobs) && !stopping) { PZ_WaitCondVar(freeListNotEmptyCv, PR_INTERVAL_NO_TIMEOUT); } if (stopping) { PZ_Unlock(qLock); if (tcp_sock) { PR_Close(tcp_sock); } break; } myLink = PR_LIST_HEAD(&freeJobs); PR_REMOVE_AND_INIT_LINK(myLink); /* could release qLock here and reacquire it 7 lines below, but ** why bother for 4 assignment statements? */ { JOB * myJob = (JOB *)myLink; myJob->tcp_sock = tcp_sock; myJob->model_sock = model_sock; myJob->requestCert = requestCert; } PR_APPEND_LINK(myLink, &jobQ); PZ_NotifyCondVar(jobQNotEmptyCv); PZ_Unlock(qLock); } FPRINTF(stderr, "selfserv: Closing listen socket.\n"); VLOG(("selfserv: do_accepts: exiting")); if (listen_sock) { PR_Close(listen_sock); } return SECSuccess; }
NSFC_NewFilenameEntry(NSFCCache cip, const char *filename, PRUint32 hvalue, NSFCStatus &rfc) { PRUint32 bucket = hvalue % cip->hsize; PR_ASSERT(cip); if (cip->state != NSFCCache_Active) { rfc = NSFC_DEADCACHE; return NULL; } rfc = NSFC_OK; /* Replace file cache entries once the cache fills up */ if (_NSFC_IsTimeToReplace(cip)) { PR_Lock(cip->hitLock); if (!PR_CLIST_IS_EMPTY(&cip->hit_list)) { NSFCEntryImpl* nepDelete; PRUint32 bucketDelete; /* Get the LRU entry from the hit list and remember its bucket */ PRCList *lru = PR_LIST_TAIL(&cip->hit_list); PR_ASSERT(lru); nepDelete = (NSFCEntryImpl*)((char*)lru - offsetof(NSFCEntryImpl, hit_list)); bucketDelete = nepDelete->hash % cip->hsize; PR_Unlock(cip->hitLock); /* Get access to the LRU entry's bucket */ if (bucket != bucketDelete) { NSFC_RELEASEBUCKET(cip, bucket); NSFC_ACQUIREBUCKET(cip, bucketDelete); } /* Look for the LRU entry in the bucket */ NSFCEntryImpl *nep; for (nep = cip->hname[bucketDelete]; nep; nep = nep->next) { if (nep == nepDelete) break; } if (nep == nepDelete) { /* The LRU entry is still around, mark it for deletion */ NSFC_DeleteEntry(cip, nep, PR_TRUE); /* Increment count of replaced entries */ PR_AtomicIncrement((PRInt32*)&cip->rplcCnt); } /* Get access to the new entry's bucket */ if (bucket != bucketDelete) { NSFC_RELEASEBUCKET(cip, bucketDelete); NSFC_ACQUIREBUCKET(cip, bucket); } } else { PR_Unlock(cip->hitLock); } } /* Respect limit on number of cache entries */ if (cip->curFiles >= cip->cfg.maxFiles) { cip->cacheFull = PR_TRUE; rfc = NSFC_NOSPACE; return NULL; } /* Get a file name entry */ PR_Lock(cip->namefLock); NSFCEntryImpl *nep = cip->namefl; if (nep != NULL) { /* Found a file name entry on the free list */ PR_ASSERT(nep->refcnt == 0); PR_ASSERT(!nep->fHashed); cip->namefl = nep->next; } PR_Unlock(cip->namefLock); if (nep == NULL) { /* Allocate a new file name entry */ nep = (NSFCEntryImpl *)NSFC_Calloc(1, sizeof(*nep), cip); if (nep) { nep->seqno = 1; } } if (nep) { nep->filename = NSFC_Strdup(filename, cip); if (nep->filename) { /* Initialize entry */ nep->next = NULL; nep->pdLock = PR_NewLock(); nep->pdlist = NULL; nep->finfo.pr.type = PR_FILE_OTHER; nep->finfo.pr.size = 0; nep->finfo.pr.creationTime = 0; nep->finfo.pr.modifyTime = 0; PRIntervalTime now = ft_timeIntervalNow(); nep->finfo.lastUpdate = now; nep->finfo.fileid[0] = hvalue; nep->finfo.fileid[1] = nep->seqno; nep->finfo.prerr = 0; nep->finfo.oserr = 0; nep->hash = hvalue; nep->hitcnt = 0; nep->refcnt = 1; nep->flags = 0; nep->fHashed = 1; nep->fDelete = 0; nep->fWriting = 0; /* Add entry to cache instance hash table */ NSFC_ASSERTBUCKETHELD(cip, bucket); nep->next = cip->hname[bucket]; cip->hname[bucket] = nep; PR_AtomicIncrement((PRInt32*)&cip->curFiles); /* Add entry to the hit list */ PR_Lock(cip->hitLock); PR_INIT_CLIST(&nep->hit_list); if (cip->cfg.hitOrder == PR_TRUE) { /* * Add this entry towards the end of the hit list, * but ahead of other entries with a zero hit count. */ PRCList *prev; NSFCEntryImpl *pnep; for (prev = PR_LIST_TAIL(&cip->hit_list); prev != &cip->hit_list; prev = PR_PREV_LINK(prev)) { pnep = NSFCENTRYIMPL(prev); if (pnep->hitcnt > nep->hitcnt) { break; /* Our spot in the list */ } } PR_INSERT_AFTER(&nep->hit_list, prev); } else { /* Put new entry at head of hit list */ PR_INSERT_LINK(&nep->hit_list, &cip->hit_list); } PR_Unlock(cip->hitLock); PR_ASSERT(!nep->fDelete); } else { /* Failed, so return the entry to the free list */ PR_Lock(cip->namefLock); nep->next = cip->namefl; cip->namefl = nep; nep = NULL; PR_Unlock(cip->namefLock); cip->cacheFull = PR_TRUE; /* file cache is full */ rfc = NSFC_NOSPACE; } } else { cip->cacheFull = PR_TRUE; /* file cache is full */ rfc = NSFC_NOSPACE; } /* Cache contents have been modified */ cip->sig++; return nep; }
static void linked_attrs_fixup_task_thread(void *arg) { int rc = 0; Slapi_Task *task = (Slapi_Task *)arg; task_data *td = NULL; PRCList *main_config = NULL; int found_config = 0; /* Fetch our task data from the task */ td = (task_data *)slapi_task_get_data(task); /* init and set the bind dn in the thread data */ slapi_td_set_dn(slapi_ch_strdup(td->bind_dn)); /* Log started message. */ slapi_task_begin(task, 1); slapi_task_log_notice(task, "Linked attributes fixup task starting (link dn: \"%s\") ...\n", td->linkdn ? td->linkdn : ""); slapi_log_error(SLAPI_LOG_FATAL, LINK_PLUGIN_SUBSYSTEM, "Syntax validate task starting (link dn: \"%s\") ...\n", td->linkdn ? td->linkdn : ""); linked_attrs_read_lock(); main_config = linked_attrs_get_config(); if (!PR_CLIST_IS_EMPTY(main_config)) { struct configEntry *config_entry = NULL; PRCList *list = PR_LIST_HEAD(main_config); while (list != main_config) { config_entry = (struct configEntry *) list; /* See if this is the requested config and fix up if so. */ if (td->linkdn) { if (strcasecmp(td->linkdn, config_entry->dn) == 0) { found_config = 1; slapi_task_log_notice(task, "Fixing up linked attribute pair (%s)\n", config_entry->dn); slapi_log_error(SLAPI_LOG_FATAL, LINK_PLUGIN_SUBSYSTEM, "Fixing up linked attribute pair (%s)\n", config_entry->dn); linked_attrs_fixup_links(config_entry); break; } } else { /* No config DN was supplied, so fix up all configured links. */ slapi_task_log_notice(task, "Fixing up linked attribute pair (%s)\n", config_entry->dn); slapi_log_error(SLAPI_LOG_FATAL, LINK_PLUGIN_SUBSYSTEM, "Fixing up linked attribute pair (%s)\n", config_entry->dn); linked_attrs_fixup_links(config_entry); } list = PR_NEXT_LINK(list); } } /* Log a message if we didn't find the requested attribute pair. */ if (td->linkdn && !found_config) { slapi_task_log_notice(task, "Requested link config DN not found (%s)\n", td->linkdn); slapi_log_error(SLAPI_LOG_FATAL, LINK_PLUGIN_SUBSYSTEM, "Requested link config DN not found (%s)\n", td->linkdn); } linked_attrs_unlock(); /* Log finished message. */ slapi_task_log_notice(task, "Linked attributes fixup task complete.\n"); slapi_task_log_status(task, "Linked attributes fixup task complete.\n"); slapi_log_error(SLAPI_LOG_FATAL, LINK_PLUGIN_SUBSYSTEM, "Linked attributes fixup task complete.\n"); slapi_task_inc_progress(task); /* this will queue the destruction of the task */ slapi_task_finish(task, rc); }
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 */
static PRStatus _MW_PollInternal(PRWaitGroup *group) { PRRecvWait **waiter; PRStatus rv = PR_FAILURE; PRInt32 count, count_ready; PRIntervalTime polling_interval; group->poller = PR_GetCurrentThread(); while (PR_TRUE) { PRIntervalTime now, since_last_poll; PRPollDesc *poll_list; while (0 == group->waiter->count) { PRStatus st; st = PR_WaitCondVar(group->new_business, PR_INTERVAL_NO_TIMEOUT); if (_prmw_running != group->state) { PR_SetError(PR_INVALID_STATE_ERROR, 0); goto aborted; } if (_MW_ABORTED(st)) goto aborted; } /* ** There's something to do. See if our existing polling list ** is large enough for what we have to do? */ while (group->polling_count < group->waiter->count) { PRUint32 old_count = group->waiter->count; PRUint32 new_count = PR_ROUNDUP(old_count, _PR_POLL_COUNT_FUDGE); PRSize new_size = sizeof(PRPollDesc) * new_count; PRPollDesc *old_polling_list = group->polling_list; PR_Unlock(group->ml); poll_list = (PRPollDesc*)PR_CALLOC(new_size); if (NULL == poll_list) { PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); PR_Lock(group->ml); goto failed_alloc; } if (NULL != old_polling_list) PR_DELETE(old_polling_list); PR_Lock(group->ml); if (_prmw_running != group->state) { PR_SetError(PR_INVALID_STATE_ERROR, 0); goto aborted; } group->polling_list = poll_list; group->polling_count = new_count; } now = PR_IntervalNow(); polling_interval = max_polling_interval; since_last_poll = now - group->last_poll; waiter = &group->waiter->recv_wait; poll_list = group->polling_list; for (count = 0; count < group->waiter->count; ++waiter) { PR_ASSERT(waiter < &group->waiter->recv_wait + group->waiter->length); if (NULL != *waiter) /* a live one! */ { if ((PR_INTERVAL_NO_TIMEOUT != (*waiter)->timeout) && (since_last_poll >= (*waiter)->timeout)) _MW_DoneInternal(group, waiter, PR_MW_TIMEOUT); else { if (PR_INTERVAL_NO_TIMEOUT != (*waiter)->timeout) { (*waiter)->timeout -= since_last_poll; if ((*waiter)->timeout < polling_interval) polling_interval = (*waiter)->timeout; } PR_ASSERT(poll_list < group->polling_list + group->polling_count); poll_list->fd = (*waiter)->fd; poll_list->in_flags = PR_POLL_READ; poll_list->out_flags = 0; #if 0 printf( "Polling 0x%x[%d]: [fd: 0x%x, tmo: %u]\n", poll_list, count, poll_list->fd, (*waiter)->timeout); #endif poll_list += 1; count += 1; } } } PR_ASSERT(count == group->waiter->count); /* ** If there are no more threads waiting for completion, ** we need to return. */ if ((!PR_CLIST_IS_EMPTY(&group->io_ready)) && (1 == group->waiting_threads)) break; if (0 == count) continue; /* wait for new business */ group->last_poll = now; PR_Unlock(group->ml); count_ready = PR_Poll(group->polling_list, count, polling_interval); PR_Lock(group->ml); if (_prmw_running != group->state) { PR_SetError(PR_INVALID_STATE_ERROR, 0); goto aborted; } if (-1 == count_ready) { goto failed_poll; /* that's a shame */ } else if (0 < count_ready) { for (poll_list = group->polling_list; count > 0; poll_list++, count--) { PR_ASSERT( poll_list < group->polling_list + group->polling_count); if (poll_list->out_flags != 0) { waiter = _MW_LookupInternal(group, poll_list->fd); /* ** If 'waiter' is NULL, that means the wait receive ** descriptor has been canceled. */ if (NULL != waiter) _MW_DoneInternal(group, waiter, PR_MW_SUCCESS); } } } /* ** If there are no more threads waiting for completion, ** we need to return. ** This thread was "borrowed" to do the polling, but it really ** belongs to the client. */ if ((!PR_CLIST_IS_EMPTY(&group->io_ready)) && (1 == group->waiting_threads)) break; } rv = PR_SUCCESS; aborted: failed_poll: failed_alloc: group->poller = NULL; /* we were that, not we ain't */ if ((_prmw_running == group->state) && (group->waiting_threads > 1)) { /* Wake up one thread to become the new poller. */ PR_NotifyCondVar(group->io_complete); } return rv; /* we return with the lock held */ } /* _MW_PollInternal */
/* * io worker thread function */ static void io_wstart(void *arg) { PRThreadPool *tp = (PRThreadPool *) arg; int pollfd_cnt, pollfds_used; int rv; PRCList *qp, *nextqp; PRPollDesc *pollfds; PRJob **polljobs; int poll_timeout; PRIntervalTime now; /* * scan io_jobq * construct poll list * call PR_Poll * for all fds, for which poll returns true, move the job to * jobq and wakeup worker thread. */ while (!tp->shutdown) { PRJob *jobp; pollfd_cnt = tp->ioq.cnt + 10; if (pollfd_cnt > tp->ioq.npollfds) { /* * re-allocate pollfd array if the current one is not large * enough */ if (NULL != tp->ioq.pollfds) PR_Free(tp->ioq.pollfds); tp->ioq.pollfds = (PRPollDesc *) PR_Malloc(pollfd_cnt * (sizeof(PRPollDesc) + sizeof(PRJob *))); PR_ASSERT(NULL != tp->ioq.pollfds); /* * array of pollfds */ pollfds = tp->ioq.pollfds; tp->ioq.polljobs = (PRJob **) (&tp->ioq.pollfds[pollfd_cnt]); /* * parallel array of jobs */ polljobs = tp->ioq.polljobs; tp->ioq.npollfds = pollfd_cnt; } pollfds_used = 0; /* * add the notify fd; used for unblocking io thread(s) */ pollfds[pollfds_used].fd = tp->ioq.notify_fd; pollfds[pollfds_used].in_flags = PR_POLL_READ; pollfds[pollfds_used].out_flags = 0; polljobs[pollfds_used] = NULL; pollfds_used++; /* * fill in the pollfd array */ PR_Lock(tp->ioq.lock); for (qp = tp->ioq.list.next; qp != &tp->ioq.list; qp = nextqp) { nextqp = qp->next; jobp = JOB_LINKS_PTR(qp); if (jobp->cancel_io) { CANCEL_IO_JOB(jobp); continue; } if (pollfds_used == (pollfd_cnt)) break; pollfds[pollfds_used].fd = jobp->iod->socket; pollfds[pollfds_used].in_flags = jobp->io_poll_flags; pollfds[pollfds_used].out_flags = 0; polljobs[pollfds_used] = jobp; pollfds_used++; } if (!PR_CLIST_IS_EMPTY(&tp->ioq.list)) { qp = tp->ioq.list.next; jobp = JOB_LINKS_PTR(qp); if (PR_INTERVAL_NO_TIMEOUT == jobp->timeout) poll_timeout = PR_INTERVAL_NO_TIMEOUT; else if (PR_INTERVAL_NO_WAIT == jobp->timeout) poll_timeout = PR_INTERVAL_NO_WAIT; else { poll_timeout = jobp->absolute - PR_IntervalNow(); if (poll_timeout <= 0) /* already timed out */ poll_timeout = PR_INTERVAL_NO_WAIT; } } else { poll_timeout = PR_INTERVAL_NO_TIMEOUT; } PR_Unlock(tp->ioq.lock); /* * XXXX * should retry if more jobs have been added to the queue? * */ PR_ASSERT(pollfds_used <= pollfd_cnt); rv = PR_Poll(tp->ioq.pollfds, pollfds_used, poll_timeout); if (tp->shutdown) { break; } if (rv > 0) { /* * at least one io event is set */ PRStatus rval_status; PRInt32 index; PR_ASSERT(pollfds[0].fd == tp->ioq.notify_fd); /* * reset the pollable event, if notified */ if (pollfds[0].out_flags & PR_POLL_READ) { rval_status = PR_WaitForPollableEvent(tp->ioq.notify_fd); PR_ASSERT(PR_SUCCESS == rval_status); } for(index = 1; index < (pollfds_used); index++) { PRInt16 events = pollfds[index].in_flags; PRInt16 revents = pollfds[index].out_flags; jobp = polljobs[index]; if ((revents & PR_POLL_NVAL) || /* busted in all cases */ (revents & PR_POLL_ERR) || ((events & PR_POLL_WRITE) && (revents & PR_POLL_HUP))) { /* write op & hup */ PR_Lock(tp->ioq.lock); if (jobp->cancel_io) { CANCEL_IO_JOB(jobp); PR_Unlock(tp->ioq.lock); continue; } PR_REMOVE_AND_INIT_LINK(&jobp->links); tp->ioq.cnt--; jobp->on_ioq = PR_FALSE; PR_Unlock(tp->ioq.lock); /* set error */ if (PR_POLL_NVAL & revents) jobp->iod->error = PR_BAD_DESCRIPTOR_ERROR; else if (PR_POLL_HUP & revents) jobp->iod->error = PR_CONNECT_RESET_ERROR; else jobp->iod->error = PR_IO_ERROR; /* * add to jobq */ add_to_jobq(tp, jobp); } else if (revents) { /* * add to jobq */ PR_Lock(tp->ioq.lock); if (jobp->cancel_io) { CANCEL_IO_JOB(jobp); PR_Unlock(tp->ioq.lock); continue; } PR_REMOVE_AND_INIT_LINK(&jobp->links); tp->ioq.cnt--; jobp->on_ioq = PR_FALSE; PR_Unlock(tp->ioq.lock); if (jobp->io_op == JOB_IO_CONNECT) { if (PR_GetConnectStatus(&pollfds[index]) == PR_SUCCESS) jobp->iod->error = 0; else jobp->iod->error = PR_GetError(); } else jobp->iod->error = 0; add_to_jobq(tp, jobp); } } } /* * timeout processing */ now = PR_IntervalNow(); PR_Lock(tp->ioq.lock); for (qp = tp->ioq.list.next; qp != &tp->ioq.list; qp = nextqp) { nextqp = qp->next; jobp = JOB_LINKS_PTR(qp); if (jobp->cancel_io) { CANCEL_IO_JOB(jobp); continue; } if (PR_INTERVAL_NO_TIMEOUT == jobp->timeout) break; if ((PR_INTERVAL_NO_WAIT != jobp->timeout) && ((PRInt32)(jobp->absolute - now) > 0)) break; PR_REMOVE_AND_INIT_LINK(&jobp->links); tp->ioq.cnt--; jobp->on_ioq = PR_FALSE; jobp->iod->error = PR_IO_TIMEOUT_ERROR; add_to_jobq(tp, jobp); } PR_Unlock(tp->ioq.lock); } }
/* queue a job, when a socket is readable or writeable */ static PRJob * queue_io_job(PRThreadPool *tpool, PRJobIoDesc *iod, PRJobFn fn, void * arg, PRBool joinable, io_op_type op) { PRJob *jobp; PRIntervalTime now; jobp = alloc_job(joinable, tpool); if (NULL == jobp) { return NULL; } /* * Add a new job to io_jobq * wakeup io worker thread */ jobp->job_func = fn; jobp->job_arg = arg; jobp->tpool = tpool; jobp->iod = iod; if (JOB_IO_READ == op) { jobp->io_op = JOB_IO_READ; jobp->io_poll_flags = PR_POLL_READ; } else if (JOB_IO_WRITE == op) { jobp->io_op = JOB_IO_WRITE; jobp->io_poll_flags = PR_POLL_WRITE; } else if (JOB_IO_ACCEPT == op) { jobp->io_op = JOB_IO_ACCEPT; jobp->io_poll_flags = PR_POLL_READ; } else if (JOB_IO_CONNECT == op) { jobp->io_op = JOB_IO_CONNECT; jobp->io_poll_flags = PR_POLL_WRITE|PR_POLL_EXCEPT; } else { delete_job(jobp); PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); return NULL; } jobp->timeout = iod->timeout; if ((PR_INTERVAL_NO_TIMEOUT == iod->timeout) || (PR_INTERVAL_NO_WAIT == iod->timeout)) { jobp->absolute = iod->timeout; } else { now = PR_IntervalNow(); jobp->absolute = now + iod->timeout; } PR_Lock(tpool->ioq.lock); if (PR_CLIST_IS_EMPTY(&tpool->ioq.list) || (PR_INTERVAL_NO_TIMEOUT == iod->timeout)) { PR_APPEND_LINK(&jobp->links,&tpool->ioq.list); } else if (PR_INTERVAL_NO_WAIT == iod->timeout) { PR_INSERT_LINK(&jobp->links,&tpool->ioq.list); } else { PRCList *qp; PRJob *tmp_jobp; /* * insert into the timeout-sorted ioq */ for (qp = tpool->ioq.list.prev; qp != &tpool->ioq.list; qp = qp->prev) { tmp_jobp = JOB_LINKS_PTR(qp); if ((PRInt32)(jobp->absolute - tmp_jobp->absolute) >= 0) { break; } } PR_INSERT_AFTER(&jobp->links,qp); } jobp->on_ioq = PR_TRUE; tpool->ioq.cnt++; /* * notify io worker thread(s) */ PR_Unlock(tpool->ioq.lock); notify_ioq(tpool); return jobp; }
void nsIOThreadPool::ThreadFunc(void *arg) { nsIOThreadPool *pool = (nsIOThreadPool *) arg; LOG(("entering ThreadFunc\n")); { nsAutoLock lock(pool->mLock); for (;;) { PRIntervalTime start = PR_IntervalNow(), timeout = IDLE_TIMEOUT; // // wait for one or more of the following to occur: // (1) the event queue has an event to process // (2) the shutdown flag has been set // (3) the thread has been idle for too long // // PR_WaitCondVar will return when any of these conditions is true. // while (PR_CLIST_IS_EMPTY(&pool->mEventQ) && !pool->mShutdown) { pool->mNumIdleThreads++; PR_WaitCondVar(pool->mIdleThreadCV, timeout); pool->mNumIdleThreads--; PRIntervalTime delta = PR_IntervalNow() - start; if (delta >= timeout) break; timeout -= delta; start += delta; } // if the queue is still empty, then kill this thread (either we // are shutting down or the thread exceeded the idle timeout)... if (PR_CLIST_IS_EMPTY(&pool->mEventQ)) break; // handle one event at a time: we don't want this one thread to hog // all the events while other threads may be able to help out ;-) do { PLEvent *event = PLEVENT_FROM_LINK(PR_LIST_HEAD(&pool->mEventQ)); PR_REMOVE_AND_INIT_LINK(&event->link); LOG(("event:%p\n", event)); // release lock! lock.unlock(); PL_HandleEvent(event); lock.lock(); } while (!PR_CLIST_IS_EMPTY(&pool->mEventQ)); } // thread is going away... pool->mNumThreads--; PR_NotifyCondVar(pool->mExitThreadCV); } // release our reference to the pool NS_RELEASE(pool); LOG(("leaving ThreadFunc\n")); }
nsPACMan::~nsPACMan() { NS_ASSERTION(mLoader == nsnull, "pac man not shutdown properly"); NS_ASSERTION(mPAC == nsnull, "pac man not shutdown properly"); NS_ASSERTION(PR_CLIST_IS_EMPTY(&mPendingQ), "pac man not shutdown properly"); }
/* Apply the pending changes in the e entry to our config struct. validate must have already been called */ static int pam_passthru_apply_config (Slapi_Entry* e) { int rc = PAM_PASSTHRU_SUCCESS; char **excludes = NULL; char **includes = NULL; char *new_service = NULL; char *pam_ident_attr = NULL; char *map_method = NULL; char *dn = NULL; PRBool fallback; PRBool secure; Pam_PassthruConfig *entry = NULL; PRCList *list; Slapi_Attr *a = NULL; char *filter_str = NULL; int inserted = 0; pam_ident_attr = slapi_entry_attr_get_charptr(e, PAMPT_PAM_IDENT_ATTR); map_method = slapi_entry_attr_get_charptr(e, PAMPT_MAP_METHOD_ATTR); new_service = slapi_entry_attr_get_charptr(e, PAMPT_SERVICE_ATTR); excludes = slapi_entry_attr_get_charray(e, PAMPT_EXCLUDES_ATTR); includes = slapi_entry_attr_get_charray(e, PAMPT_INCLUDES_ATTR); fallback = slapi_entry_attr_get_bool(e, PAMPT_FALLBACK_ATTR); filter_str = slapi_entry_attr_get_charptr(e, PAMPT_FILTER_ATTR); /* Require SSL/TLS if the secure attr is not specified. We * need to check if the attribute is present to make this * determiniation. */ if (slapi_entry_attr_find(e, PAMPT_SECURE_ATTR, &a) == 0) { secure = slapi_entry_attr_get_bool(e, PAMPT_SECURE_ATTR); } else { secure = PR_TRUE; } /* Allocate a config struct. */ entry = (Pam_PassthruConfig *) slapi_ch_calloc(1, sizeof(Pam_PassthruConfig)); if (NULL == entry) { rc = PAM_PASSTHRU_FAILURE; goto bail; } /* use the RDN method to derive the PAM identity by default*/ entry->pamptconfig_map_method1 = PAMPT_MAP_METHOD_RDN; entry->pamptconfig_map_method2 = PAMPT_MAP_METHOD_NONE; entry->pamptconfig_map_method3 = PAMPT_MAP_METHOD_NONE; /* Fill in the struct. */ dn = slapi_entry_get_ndn(e); if (dn) { entry->dn = slapi_ch_strdup(dn); } entry->pamptconfig_fallback = fallback; entry->pamptconfig_secure = secure; if (!entry->pamptconfig_service || (new_service && PL_strcmp(entry->pamptconfig_service, new_service))) { slapi_ch_free_string(&entry->pamptconfig_service); entry->pamptconfig_service = new_service; new_service = NULL; /* config now owns memory */ } /* get the list of excluded suffixes */ pam_ptconfig_free_suffixes(entry->pamptconfig_excludes); entry->pamptconfig_excludes = pam_ptconfig_add_suffixes(excludes); /* get the list of included suffixes */ pam_ptconfig_free_suffixes(entry->pamptconfig_includes); entry->pamptconfig_includes = pam_ptconfig_add_suffixes(includes); if (!entry->pamptconfig_pam_ident_attr || (pam_ident_attr && PL_strcmp(entry->pamptconfig_pam_ident_attr, pam_ident_attr))) { slapi_ch_free_string(&entry->pamptconfig_pam_ident_attr); entry->pamptconfig_pam_ident_attr = pam_ident_attr; pam_ident_attr = NULL; /* config now owns memory */ } if (map_method) { parse_map_method(map_method, &entry->pamptconfig_map_method1, &entry->pamptconfig_map_method2, &entry->pamptconfig_map_method3, NULL); } if (filter_str) { entry->filter_str = filter_str; filter_str = NULL; /* config now owns memory */ entry->slapi_filter = slapi_str2filter(entry->filter_str); } /* Add config to list. We just store at the tail. */ if (!PR_CLIST_IS_EMPTY(pam_passthru_global_config)) { list = PR_LIST_HEAD(pam_passthru_global_config); while (list != pam_passthru_global_config) { list = PR_NEXT_LINK(list); if (pam_passthru_global_config == list) { /* add to tail */ PR_INSERT_BEFORE(&(entry->list), list); slapi_log_err(SLAPI_LOG_CONFIG, PAM_PASSTHRU_PLUGIN_SUBSYSTEM, "pam_passthru_apply_config - store [%s] at tail\n", entry->dn); inserted = 1; break; } } } else { /* first entry */ PR_INSERT_LINK(&(entry->list), pam_passthru_global_config); slapi_log_err(SLAPI_LOG_CONFIG, PAM_PASSTHRU_PLUGIN_SUBSYSTEM, "pam_passthru_apply_config - store [%s] at head \n", entry->dn); inserted = 1; } bail: if(!inserted){ pam_passthru_free_config_entry(&entry); } slapi_ch_free_string(&new_service); slapi_ch_free_string(&map_method); slapi_ch_free_string(&pam_ident_attr); slapi_ch_free_string(&filter_str); slapi_ch_array_free(excludes); slapi_ch_array_free(includes); return rc; }
PR_CreateTrace( const char *qName, /* QName for this trace handle */ const char *rName, /* RName for this trace handle */ const char *description /* description for this trace handle */ ) { QName *qnp; RName *rnp; PRBool matchQname = PR_FALSE; /* Self initialize, if necessary */ if ( traceLock == NULL ) _PR_InitializeTrace(); /* Validate input arguments */ PR_ASSERT( strlen(qName) <= PRTRACE_NAME_MAX ); PR_ASSERT( strlen(rName) <= PRTRACE_NAME_MAX ); PR_ASSERT( strlen(description) <= PRTRACE_DESC_MAX ); PR_LOG( lm, PR_LOG_DEBUG, ("PRTRACE: CreateTrace: Qname: %s, RName: %s", qName, rName)); /* Lock the Facility */ PR_Lock( traceLock ); /* Do we already have a matching QName? */ if (!PR_CLIST_IS_EMPTY( &qNameList )) { qnp = (QName *) PR_LIST_HEAD( &qNameList ); do { if ( strcmp(qnp->name, qName) == 0) { matchQname = PR_TRUE; break; } qnp = (QName *)PR_NEXT_LINK( &qnp->link ); } while( qnp != (QName *)PR_LIST_HEAD( &qNameList )); } /* ** If we did not find a matching QName, ** allocate one and initialize it. ** link it onto the qNameList. ** */ if ( matchQname != PR_TRUE ) { qnp = PR_NEWZAP( QName ); PR_ASSERT( qnp != NULL ); PR_INIT_CLIST( &qnp->link ); PR_INIT_CLIST( &qnp->rNameList ); strcpy( qnp->name, qName ); PR_APPEND_LINK( &qnp->link, &qNameList ); } /* Do we already have a matching RName? */ if (!PR_CLIST_IS_EMPTY( &qnp->rNameList )) { rnp = (RName *) PR_LIST_HEAD( &qnp->rNameList ); do { /* ** No duplicate RNames are allowed within a QName ** */ PR_ASSERT( strcmp(rnp->name, rName)); rnp = (RName *)PR_NEXT_LINK( &rnp->link ); } while( rnp != (RName *)PR_LIST_HEAD( &qnp->rNameList )); } /* Get a new RName structure; initialize its members */ rnp = PR_NEWZAP( RName ); PR_ASSERT( rnp != NULL ); PR_INIT_CLIST( &rnp->link ); strcpy( rnp->name, rName ); strcpy( rnp->desc, description ); rnp->lock = PR_NewLock(); rnp->state = Running; if ( rnp->lock == NULL ) { PR_ASSERT(0); } PR_APPEND_LINK( &rnp->link, &qnp->rNameList ); /* add RName to QName's rnList */ rnp->qName = qnp; /* point the RName to the QName */ /* Unlock the Facility */ PR_Unlock( traceLock ); PR_LOG( lm, PR_LOG_DEBUG, ("PRTrace: Create: QName: %s %p, RName: %s %p\n\t", qName, qnp, rName, rnp )); return((PRTraceHandle)rnp); } /* end PR_CreateTrace() */
/* Call extension handlers for the given message. */ SECStatus ssl_ConstructExtensions(sslSocket *ss, sslBuffer *buf, SSLHandshakeType message) { const sslExtensionBuilder *sender; SECStatus rv; PORT_Assert(buf->len == 0); switch (message) { case ssl_hs_client_hello: if (ss->vrange.max > SSL_LIBRARY_VERSION_3_0) { sender = clientHelloSendersTLS; } else { sender = clientHelloSendersSSL3; } break; case ssl_hs_server_hello: sender = ss->xtnData.serverHelloSenders; break; case ssl_hs_certificate_request: PORT_Assert(ss->version >= SSL_LIBRARY_VERSION_TLS_1_3); sender = tls13_cert_req_senders; break; case ssl_hs_certificate: PORT_Assert(ss->version >= SSL_LIBRARY_VERSION_TLS_1_3); sender = ss->xtnData.certificateSenders; break; case ssl_hs_encrypted_extensions: PORT_Assert(ss->version >= SSL_LIBRARY_VERSION_TLS_1_3); sender = ss->xtnData.encryptedExtensionsSenders; break; case ssl_hs_hello_retry_request: PORT_Assert(ss->version >= SSL_LIBRARY_VERSION_TLS_1_3); sender = tls13_hrr_senders; break; default: PORT_Assert(0); PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); return SECFailure; } for (; sender->ex_sender != NULL; ++sender) { PRBool append = PR_FALSE; unsigned int start = buf->len; unsigned int length; if (ssl_FindCustomExtensionHooks(ss, sender->ex_type)) { continue; } /* Save space for the extension type and length. Note that we don't grow * the buffer now; rely on sslBuffer_Append* to do that. */ buf->len += 4; rv = (*sender->ex_sender)(ss, &ss->xtnData, buf, &append); if (rv != SECSuccess) { goto loser; } /* Save the length and go back to the start. */ length = buf->len - start - 4; buf->len = start; if (!append) { continue; } buf->len = start; rv = sslBuffer_AppendNumber(buf, sender->ex_type, 2); if (rv != SECSuccess) { goto loser; /* Code already set. */ } rv = sslBuffer_AppendNumber(buf, length, 2); if (rv != SECSuccess) { goto loser; /* Code already set. */ } /* Skip over the extension body. */ buf->len += length; if (message == ssl_hs_client_hello || message == ssl_hs_certificate_request) { ss->xtnData.advertised[ss->xtnData.numAdvertised++] = sender->ex_type; } } if (!PR_CLIST_IS_EMPTY(&ss->extensionHooks)) { rv = ssl_CallCustomExtensionSenders(ss, buf, message); if (rv != SECSuccess) { goto loser; } } if (buf->len > 0xffff) { PORT_SetError(SSL_ERROR_TX_RECORD_TOO_LONG); goto loser; } return SECSuccess; loser: sslBuffer_Clear(buf); return SECFailure; }
PR_IMPLEMENT(PRRecvWait*) PR_WaitRecvReady(PRWaitGroup *group) { PRStatus rv = PR_SUCCESS; PRCList *io_ready = NULL; if (PR_FAILURE == MW_Init()) goto failed_init; 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 */ 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)) { while ((NULL == group->waiter) || (0 == group->waiter->count)) { if (_prmw_running != group->state) goto aborted; rv = PR_WaitCondVar(group->new_business, PR_INTERVAL_NO_TIMEOUT); if (_MW_ABORTED(rv)) goto aborted; } /* ** 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; if (PR_CLIST_IS_EMPTY(&group->io_ready)) continue; /* timeout */ } else { while (PR_CLIST_IS_EMPTY(&group->io_ready)) { rv = PR_WaitCondVar(group->io_complete, PR_INTERVAL_NO_TIMEOUT); if (_MW_ABORTED(rv)) goto aborted; } } } io_ready = PR_LIST_HEAD(&group->io_ready); PR_NotifyCondVar(group->io_taken); PR_ASSERT(io_ready != NULL); PR_REMOVE_LINK(io_ready); /* If the operation failed, record the reason why */ switch (((PRRecvWait*)io_ready)->outcome) { case PR_MW_PENDING: PR_ASSERT(PR_MW_PENDING != ((PRRecvWait*)io_ready)->outcome); break; case PR_MW_SUCCESS: _MW_InitialRecv(io_ready); break; 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; } } while (NULL == io_ready); aborted: failed_poll: group->waiting_threads -= 1; invalid_state: (void)MW_TestForShutdownInternal(group); PR_Unlock(group->ml); failed_init: return (PRRecvWait*)io_ready; } /* PR_WaitRecvReady */
static void PR_CALLBACK Server(void *arg) { PRStatus rv; PRNetAddr serverAddress; PRThread *me = PR_GetCurrentThread(); CSServer_t *server = (CSServer_t*)arg; PRSocketOptionData sockOpt; server->listener = PR_Socket(domain, SOCK_STREAM, protocol); sockOpt.option = PR_SockOpt_Reuseaddr; sockOpt.value.reuse_addr = PR_TRUE; rv = PR_SetSocketOption(server->listener, &sockOpt); TEST_ASSERT(PR_SUCCESS == rv); memset(&serverAddress, 0, sizeof(serverAddress)); if (PR_AF_INET6 != domain) rv = PR_InitializeNetAddr(PR_IpAddrAny, DEFAULT_PORT, &serverAddress); else rv = PR_SetNetAddr(PR_IpAddrAny, PR_AF_INET6, DEFAULT_PORT, &serverAddress); rv = PR_Bind(server->listener, &serverAddress); TEST_ASSERT(PR_SUCCESS == rv); rv = PR_Listen(server->listener, server->backlog); TEST_ASSERT(PR_SUCCESS == rv); server->started = PR_IntervalNow(); TimeOfDayMessage("Server started at", me); PR_Lock(server->ml); server->state = cs_run; PR_NotifyCondVar(server->stateChange); PR_Unlock(server->ml); /* ** Create the first worker (actually, a thread that accepts ** connections and then processes the work load as needed). ** From this point on, additional worker threads are created ** as they are needed by existing worker threads. */ rv = CreateWorker(server, &server->pool); TEST_ASSERT(PR_SUCCESS == rv); /* ** From here on this thread is merely hanging around as the contact ** point for the main test driver. It's just waiting for the driver ** to declare the test complete. */ TEST_LOG( cltsrv_log_file, TEST_LOG_VERBOSE, ("\tServer(0x%p): waiting for state change\n", me)); PR_Lock(server->ml); while ((cs_run == server->state) && !Aborted(rv)) { rv = PR_WaitCondVar(server->stateChange, PR_INTERVAL_NO_TIMEOUT); } PR_Unlock(server->ml); PR_ClearInterrupt(); TEST_LOG( cltsrv_log_file, TEST_LOG_INFO, ("\tServer(0x%p): shutting down workers\n", me)); /* ** Get all the worker threads to exit. They know how to ** clean up after themselves, so this is just a matter of ** waiting for clorine in the pool to take effect. During ** this stage we're ignoring interrupts. */ server->workers.minimum = server->workers.maximum = 0; PR_Lock(server->ml); while (!PR_CLIST_IS_EMPTY(&server->list)) { PRCList *head = PR_LIST_HEAD(&server->list); CSWorker_t *worker = (CSWorker_t*)head; TEST_LOG( cltsrv_log_file, TEST_LOG_VERBOSE, ("\tServer(0x%p): interrupting worker(0x%p)\n", me, worker)); rv = PR_Interrupt(worker->thread); TEST_ASSERT(PR_SUCCESS == rv); PR_REMOVE_AND_INIT_LINK(head); } while (server->pool.workers > 0) { TEST_LOG( cltsrv_log_file, TEST_LOG_NOTICE, ("\tServer(0x%p): waiting for %u workers to exit\n", me, server->pool.workers)); (void)PR_WaitCondVar(server->pool.exiting, PR_INTERVAL_NO_TIMEOUT); } server->state = cs_exit; PR_NotifyCondVar(server->stateChange); PR_Unlock(server->ml); TEST_LOG( cltsrv_log_file, TEST_LOG_ALWAYS, ("\tServer(0x%p): stopped after %u operations and %u bytes\n", me, server->operations, server->bytesTransferred)); if (NULL != server->listener) PR_Close(server->listener); server->stopped = PR_IntervalNow(); } /* Server */
SECStatus ssl3_SendECDHServerKeyExchange( sslSocket *ss, const SSLSignatureAndHashAlg *sigAndHash) { SECStatus rv = SECFailure; int length; PRBool isTLS, isTLS12; SECItem signed_hash = { siBuffer, NULL, 0 }; SSL3Hashes hashes; SECItem ec_params = { siBuffer, NULL, 0 }; unsigned char paramBuf[3]; const namedGroupDef *ecGroup; sslEphemeralKeyPair *keyPair; SECKEYPublicKey *pubKey; /* Generate ephemeral ECDH key pair and send the public key */ ecGroup = ssl_GetECGroupForServerSocket(ss); if (!ecGroup) { goto loser; } PORT_Assert(PR_CLIST_IS_EMPTY(&ss->ephemeralKeyPairs)); if (ss->opt.reuseServerECDHEKey) { rv = ssl_CreateECDHEphemeralKeys(ss, ecGroup); if (rv != SECSuccess) { goto loser; } keyPair = (sslEphemeralKeyPair *)PR_NEXT_LINK(&ss->ephemeralKeyPairs); } else { rv = ssl_CreateECDHEphemeralKeyPair(ecGroup, &keyPair); if (rv != SECSuccess) { goto loser; } PR_APPEND_LINK(&keyPair->link, &ss->ephemeralKeyPairs); } PORT_Assert(keyPair); if (!keyPair) { PORT_SetError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE); return SECFailure; } ec_params.len = sizeof(paramBuf); ec_params.data = paramBuf; PORT_Assert(keyPair->group); PORT_Assert(keyPair->group->type == group_type_ec); ec_params.data[0] = ec_type_named; ec_params.data[1] = keyPair->group->name >> 8; ec_params.data[2] = keyPair->group->name & 0xff; pubKey = keyPair->keys->pubKey; rv = ssl3_ComputeECDHKeyHash(sigAndHash->hashAlg, ec_params, pubKey->u.ec.publicValue, &ss->ssl3.hs.client_random, &ss->ssl3.hs.server_random, &hashes, ss->opt.bypassPKCS11); if (rv != SECSuccess) { ssl_MapLowLevelError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE); goto loser; } isTLS = (PRBool)(ss->ssl3.pwSpec->version > SSL_LIBRARY_VERSION_3_0); isTLS12 = (PRBool)(ss->ssl3.pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2); rv = ssl3_SignHashes(&hashes, ss->sec.serverCert->serverKeyPair->privKey, &signed_hash, isTLS); if (rv != SECSuccess) { goto loser; /* ssl3_SignHashes has set err. */ } if (signed_hash.data == NULL) { /* how can this happen and rv == SECSuccess ?? */ PORT_SetError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE); goto loser; } length = ec_params.len + 1 + pubKey->u.ec.publicValue.len + (isTLS12 ? 2 : 0) + 2 + signed_hash.len; rv = ssl3_AppendHandshakeHeader(ss, server_key_exchange, length); if (rv != SECSuccess) { goto loser; /* err set by AppendHandshake. */ } rv = ssl3_AppendHandshake(ss, ec_params.data, ec_params.len); if (rv != SECSuccess) { goto loser; /* err set by AppendHandshake. */ } rv = ssl3_AppendHandshakeVariable(ss, pubKey->u.ec.publicValue.data, pubKey->u.ec.publicValue.len, 1); if (rv != SECSuccess) { goto loser; /* err set by AppendHandshake. */ } if (isTLS12) { rv = ssl3_AppendSignatureAndHashAlgorithm(ss, sigAndHash); if (rv != SECSuccess) { goto loser; /* err set by AppendHandshake. */ } } rv = ssl3_AppendHandshakeVariable(ss, signed_hash.data, signed_hash.len, 2); if (rv != SECSuccess) { goto loser; /* err set by AppendHandshake. */ } PORT_Free(signed_hash.data); return SECSuccess; loser: if (signed_hash.data != NULL) PORT_Free(signed_hash.data); return SECFailure; }
PR_IMPLEMENT(PRStatus) PR_CancelWaitFileDesc(PRWaitGroup *group, PRRecvWait *desc) { #if !defined(WINNT) PRRecvWait **recv_wait; #endif PRStatus rv = PR_SUCCESS; if (NULL == group) group = mw_state->group; PR_ASSERT(NULL != group); if (NULL == group) { PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); return PR_FAILURE; } PR_Lock(group->ml); if (_prmw_running != group->state) { PR_SetError(PR_INVALID_STATE_ERROR, 0); rv = PR_FAILURE; goto unlock; } #ifdef WINNT if (InterlockedCompareExchange((LONG *)&desc->outcome, (LONG)PR_MW_INTERRUPT, (LONG)PR_MW_PENDING) == (LONG)PR_MW_PENDING) { PRFileDesc *bottom = PR_GetIdentitiesLayer(desc->fd, PR_NSPR_IO_LAYER); PR_ASSERT(NULL != bottom); if (NULL == bottom) { PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); goto unlock; } bottom->secret->state = _PR_FILEDESC_CLOSED; #if 0 fprintf(stderr, "cancel wait recv: closing socket\n"); #endif if (closesocket(bottom->secret->md.osfd) == SOCKET_ERROR) { fprintf(stderr, "closesocket failed: %d\n", WSAGetLastError()); exit(1); } } #else if (NULL != (recv_wait = _MW_LookupInternal(group, desc->fd))) { /* it was in the wait table */ _MW_DoneInternal(group, recv_wait, PR_MW_INTERRUPT); goto unlock; } if (!PR_CLIST_IS_EMPTY(&group->io_ready)) { /* is it already complete? */ PRCList *head = PR_LIST_HEAD(&group->io_ready); do { PRRecvWait *done = (PRRecvWait*)head; if (done == desc) goto unlock; head = PR_NEXT_LINK(head); } while (head != &group->io_ready); } PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); rv = PR_FAILURE; #endif unlock: PR_Unlock(group->ml); return rv; } /* PR_CancelWaitFileDesc */