void http_session_destroy(struct http_session *s) { int must_destroy = 0; http_sessions_t http_sessions = s->http_sessions; yaz_log(http_sessions->log_level, "Session %u destroy", s->session_id); yaz_mutex_enter(http_sessions->mutex); /* only if http_session has no active http sessions on it can be destroyed */ if (s->destroy_counter == s->activity_counter) { struct http_session **p = 0; must_destroy = 1; for (p = &http_sessions->session_list; *p; p = &(*p)->next) if (*p == s) { *p = (*p)->next; break; } } yaz_mutex_leave(http_sessions->mutex); if (must_destroy) { /* destroying for real */ yaz_log(http_sessions->log_level, "Session %u destroyed", s->session_id); iochan_destroy(s->timeout_iochan); session_destroy(s->psession); http_session_use(-1); nmem_destroy(s->nmem); } else { yaz_log(http_sessions->log_level, "Session %u destroying delayed. Active clients (%d-%d). Waiting for new timeout.", s->session_id, s->activity_counter, s->destroy_counter); } }
static void statserv_closedown(void) { IOCHAN p; xml_config_bend_stop(); for (p = pListener; p; p = p->next) { iochan_destroy(p); } xml_config_close(); }
// Cleanup channel static void http_channel_destroy(IOCHAN i) { struct http_channel *s = iochan_getdata(i); http_server_t http_server; if (s->proxy) { if (s->proxy->iochan) { #ifdef WIN32 closesocket(iochan_getfd(s->proxy->iochan)); #else close(iochan_getfd(s->proxy->iochan)); #endif iochan_destroy(s->proxy->iochan); } http_buf_destroy_queue(s->http_server, s->proxy->oqueue); xfree(s->proxy); } http_buf_destroy_queue(s->http_server, s->iqueue); http_buf_destroy_queue(s->http_server, s->oqueue); http_fire_observers(s); http_destroy_observers(s); http_server = s->http_server; /* save it for destroy (decref) */ http_server_destroy(http_server); #ifdef WIN32 closesocket(iochan_getfd(i)); #else close(iochan_getfd(i)); #endif iochan_destroy(i); nmem_destroy(s->nmem); wrbuf_destroy(s->wrbuf); xfree(s); }
void http_sessions_destroy(http_sessions_t hs) { if (hs) { struct http_session *s = hs->session_list; while (s) { struct http_session *s_next = s->next; iochan_destroy(s->timeout_iochan); session_destroy(s->psession); nmem_destroy(s->nmem); s = s_next; } yaz_mutex_destroy(&hs->mutex); xfree(hs); } }
// Close connection and recycle structure static void connection_destroy(struct connection *co) { if (co->link) { ZOOM_connection_destroy(co->link); iochan_destroy(co->iochan); } yaz_log(YLOG_DEBUG, "%p Connection destroy %s", co, co->host->url); if (co->client) { client_disconnect(co->client); } xfree(co->zproxy); xfree(co); connection_use(-1); }
void iochan_handler(struct iochan *i, int event) { static int number = 0; sel_thread_t p = iochan_getdata(i); if (event & EVENT_INPUT) { struct my_work_data *work; work = sel_thread_result(p); YAZ_CHECK(work); if (work) { YAZ_CHECK_EQ(work->x * 2, work->y); /* stop work after a couple of iterations */ if (work->x > 10) iochan_destroy(i); xfree(work); } } if (event & EVENT_TIMEOUT) { struct my_work_data *work; work = xmalloc(sizeof(*work)); work->x = number; sel_thread_add(p, work); work = xmalloc(sizeof(*work)); work->x = number+1; sel_thread_add(p, work); number += 10; } }
// Handles I/O on a client connection to a backend web server (proxy mode) static void proxy_io(IOCHAN pi, int event) { struct http_proxy *pc = iochan_getdata(pi); struct http_channel *hc = pc->channel; switch (event) { int res; struct http_buf *htbuf; case EVENT_INPUT: htbuf = http_buf_create(hc->http_server); res = recv(iochan_getfd(pi), htbuf->buf, HTTP_BUF_SIZE -1, 0); if (res == 0 || (res < 0 && !is_inprogress())) { if (hc->oqueue) { yaz_log(YLOG_WARN, "Proxy read came up short"); // Close channel and alert client HTTP channel that we're gone http_buf_destroy(hc->http_server, htbuf); #ifdef WIN32 closesocket(iochan_getfd(pi)); #else close(iochan_getfd(pi)); #endif iochan_destroy(pi); pc->iochan = 0; } else { http_channel_destroy(hc->iochan); return; } } else { htbuf->buf[res] = '\0'; htbuf->offset = 0; htbuf->len = res; // Write any remaining payload if (htbuf->len - htbuf->offset > 0) http_buf_enqueue(&hc->oqueue, htbuf); } iochan_setflag(hc->iochan, EVENT_OUTPUT); break; case EVENT_OUTPUT: if (!(htbuf = pc->oqueue)) { iochan_clearflag(pi, EVENT_OUTPUT); return; } res = send(iochan_getfd(pi), htbuf->buf + htbuf->offset, htbuf->len, 0); if (res <= 0) { yaz_log(YLOG_WARN|YLOG_ERRNO, "write"); http_channel_destroy(hc->iochan); return; } if (res == htbuf->len) { struct http_buf *np = htbuf->next; http_buf_destroy(hc->http_server, htbuf); pc->oqueue = np; } else { htbuf->len -= res; htbuf->offset += res; } if (!pc->oqueue) { iochan_setflags(pi, EVENT_INPUT); // Turns off output flag } break; default: yaz_log(YLOG_WARN, "Unexpected event on connection"); http_channel_destroy(hc->iochan); } }
/* UNIX listener */ static void listener(IOCHAN h, int event) { COMSTACK line = (COMSTACK) iochan_getdata(h); int res; if (event == EVENT_INPUT) { COMSTACK new_line; if ((res = cs_listen_check(line, 0, 0, control_block.check_ip, control_block.daemon_name)) < 0) { yaz_log(YLOG_WARN|YLOG_ERRNO, "cs_listen failed"); return; } else if (res == 1) { yaz_log(YLOG_WARN, "cs_listen incomplete"); return; } new_line = cs_accept(line); if (!new_line) { yaz_log(YLOG_FATAL, "Accept failed."); iochan_setflags(h, EVENT_INPUT | EVENT_EXCEPT); /* reset listener */ return; } yaz_log(log_sessiondetail, "Connect from %s", cs_addrstr(new_line)); no_sessions++; if (control_block.dynamic) { if ((res = fork()) < 0) { yaz_log(YLOG_FATAL|YLOG_ERRNO, "fork"); iochan_destroy(h); return; } else if (res == 0) /* child */ { char nbuf[100]; IOCHAN pp; for (pp = pListener; pp; pp = iochan_getnext(pp)) { COMSTACK l = (COMSTACK)iochan_getdata(pp); cs_close(l); iochan_destroy(pp); } sprintf(nbuf, "%s(%d)", me, no_sessions); yaz_log_init_prefix(nbuf); /* ensure that bend_stop is not called when each child exits - only for the main process .. */ control_block.bend_stop = 0; } else /* parent */ { cs_close(new_line); return; } } if (control_block.threads) { #if YAZ_POSIX_THREADS pthread_t child_thread; pthread_create(&child_thread, 0, new_session, new_line); pthread_detach(child_thread); #elif YAZ_GNU_THREADS pth_attr_t attr; pth_t child_thread; attr = pth_attr_new(); pth_attr_set(attr, PTH_ATTR_JOINABLE, FALSE); pth_attr_set(attr, PTH_ATTR_STACK_SIZE, 32*1024); pth_attr_set(attr, PTH_ATTR_NAME, "session"); yaz_log(YLOG_DEBUG, "pth_spawn begin"); child_thread = pth_spawn(attr, new_session, new_line); yaz_log(YLOG_DEBUG, "pth_spawn finish"); pth_attr_destroy(attr); #else new_session(new_line); #endif } else new_session(new_line); } else if (event == EVENT_TIMEOUT) { yaz_log(log_server, "Shutting down listener."); iochan_destroy(h); } else { yaz_log(YLOG_FATAL, "Bad event on listener."); iochan_destroy(h); } }
/* WIN32 listener */ static void listener(IOCHAN h, int event) { COMSTACK line = (COMSTACK) iochan_getdata(h); IOCHAN parent_chan = line->user; association *newas; int res; HANDLE newHandle; if (event == EVENT_INPUT) { COMSTACK new_line; IOCHAN new_chan; if ((res = cs_listen(line, 0, 0)) < 0) { yaz_log(YLOG_FATAL|YLOG_ERRNO, "cs_listen failed"); return; } else if (res == 1) return; /* incomplete */ yaz_log(YLOG_DEBUG, "listen ok"); new_line = cs_accept(line); if (!new_line) { yaz_log(YLOG_FATAL, "Accept failed."); return; } yaz_log(YLOG_DEBUG, "Accept ok"); if (!(new_chan = iochan_create(cs_fileno(new_line), ir_session, EVENT_INPUT, parent_chan->chan_id))) { yaz_log(YLOG_FATAL, "Failed to create iochan"); iochan_destroy(h); return; } yaz_log(YLOG_DEBUG, "Creating association"); if (!(newas = create_association(new_chan, new_line, control_block.apdufile))) { yaz_log(YLOG_FATAL, "Failed to create new assoc."); iochan_destroy(h); return; } newas->cs_get_mask = EVENT_INPUT; newas->cs_put_mask = 0; newas->cs_accept_mask = 0; yaz_log(YLOG_DEBUG, "Setting timeout %d", control_block.idle_timeout); iochan_setdata(new_chan, newas); iochan_settimeout(new_chan, 60); /* Now what we need todo is create a new thread with this iochan as the parameter */ newHandle = (HANDLE) _beginthread(event_loop_thread, 0, new_chan); if (newHandle == (HANDLE) -1) { yaz_log(YLOG_FATAL|YLOG_ERRNO, "Failed to create new thread."); iochan_destroy(h); return; } /* We successfully created the thread, so add it to the list */ statserv_add(newHandle, new_chan); yaz_log(YLOG_DEBUG, "Created new thread, id = %ld iochan %p",(long) newHandle, new_chan); iochan_setflags(h, EVENT_INPUT | EVENT_EXCEPT); /* reset listener */ } else { yaz_log(YLOG_FATAL, "Bad event on listener."); iochan_destroy(h); return; } }
/* WIN32 statserv_closedown */ static void statserv_closedown() { /* Shouldn't do anything if we are not initialized */ if (bInitialized) { int iHandles = 0; HANDLE *pThreadHandles = NULL; /* We need to stop threads adding and removing while we */ /* start the closedown process */ EnterCriticalSection(&Thread_CritSect); { /* We have exclusive access to the thread stuff now */ /* Y didn't i use a semaphore - Oh well never mind */ ThreadList *pCurrentThread = pFirstThread; /* Before we do anything else, we need to shutdown the listener */ if (pListener != NULL) iochan_destroy(pListener); for (; pCurrentThread != NULL; pCurrentThread = pCurrentThread->pNext) { /* Just destroy the IOCHAN, that should do the trick */ iochan_destroy(pCurrentThread->pIOChannel); closesocket(pCurrentThread->pIOChannel->fd); /* Keep a running count of our handles */ iHandles++; } if (iHandles > 0) { HANDLE *pCurrentHandle ; /* Allocate the thread handle array */ pThreadHandles = (HANDLE *)malloc(sizeof(HANDLE) * iHandles); pCurrentHandle = pThreadHandles; for (pCurrentThread = pFirstThread; pCurrentThread != NULL; pCurrentThread = pCurrentThread->pNext, pCurrentHandle++) { /* Just the handle */ *pCurrentHandle = pCurrentThread->hThread; } } /* We can now leave the critical section */ LeaveCriticalSection(&Thread_CritSect); } /* Now we can really do something */ if (iHandles > 0) { yaz_log(log_server, "waiting for %d to die", iHandles); /* This will now wait, until all the threads close */ WaitForMultipleObjects(iHandles, pThreadHandles, TRUE, INFINITE); /* Free the memory we allocated for the handle array */ free(pThreadHandles); } xml_config_bend_stop(); /* No longer require the critical section, since all threads are dead */ DeleteCriticalSection(&Thread_CritSect); } xml_config_close(); }