struct http_session *http_session_create(struct conf_service *service, http_sessions_t http_sessions, unsigned int sesid) { NMEM nmem = nmem_create(); struct http_session *r = nmem_malloc(nmem, sizeof(*r)); char tmp_str[50]; sprintf(tmp_str, "session#%u", sesid); r->psession = new_session(nmem, service, sesid); r->session_id = sesid; r->timestamp = 0; r->nmem = nmem; r->destroy_counter = r->activity_counter = 0; r->http_sessions = http_sessions; yaz_mutex_enter(http_sessions->mutex); r->next = http_sessions->session_list; http_sessions->session_list = r; yaz_mutex_leave(http_sessions->mutex); r->timeout_iochan = iochan_create(-1, session_timeout, 0, "http_session_timeout"); iochan_setdata(r->timeout_iochan, r); yaz_log(http_sessions->log_level, "Session %u created. timeout chan=%p timeout=%d", sesid, r->timeout_iochan, service->session_timeout); iochan_settimeout(r->timeout_iochan, service->session_timeout); iochan_add(service->server->iochan_man, r->timeout_iochan); http_session_use(1); return r; }
/* Accept a new command connection */ static void http_accept(IOCHAN i, int event) { struct sockaddr_in addr; int fd = iochan_getfd(i); socklen_t len; int s; IOCHAN c; struct http_channel *ch; struct conf_server *server = iochan_getdata(i); len = sizeof addr; if ((s = accept(fd, (struct sockaddr *) &addr, &len)) < 0) { yaz_log(YLOG_WARN|YLOG_ERRNO, "accept"); return; } enable_nonblock(s); yaz_log(YLOG_DEBUG, "New command connection"); c = iochan_create(s, http_io, EVENT_INPUT | EVENT_EXCEPT, "http_session_socket"); ch = http_channel_create(server->http_server, inet_ntoa(addr.sin_addr), server); ch->iochan = c; iochan_setdata(c, ch); iochan_add(server->iochan_man, c); }
/* * Set up a listening endpoint, and give it to the event-handler. */ static int add_listener(char *where, int listen_id) { COMSTACK l; void *ap; IOCHAN lst = NULL; const char *mode; if (control_block.dynamic) mode = "dynamic"; else if (control_block.threads) mode = "threaded"; else mode = "static"; yaz_log(log_server, "Adding %s listener on %s id=%d", mode, where, listen_id); l = cs_create_host(where, 2, &ap); if (!l) { yaz_log(YLOG_FATAL, "Failed to listen on %s", where); return -1; } if (*control_block.cert_fname) cs_set_ssl_certificate_file(l, control_block.cert_fname); if (cs_bind(l, ap, CS_SERVER) < 0) { if (cs_errno(l) == CSYSERR) yaz_log(YLOG_FATAL|YLOG_ERRNO, "Failed to bind to %s", where); else yaz_log(YLOG_FATAL, "Failed to bind to %s: %s", where, cs_strerror(l)); cs_close(l); return -1; } if (!(lst = iochan_create(cs_fileno(l), listener, EVENT_INPUT | EVENT_EXCEPT, listen_id))) { yaz_log(YLOG_FATAL|YLOG_ERRNO, "Failed to create IOCHAN-type"); cs_close(l); return -1; } iochan_setdata(lst, l); /* user-defined data for listener is COMSTACK */ l->user = lst; /* user-defined data for COMSTACK is listener chan */ /* Add listener to chain */ lst->next = pListener; pListener = lst; return 0; /* OK */ }
/** brief use the fd for something */ static void test_for_real_work(int no_threads) { int thread_fd; sel_thread_t p = sel_thread_create(work_handler, work_destroy, &thread_fd, no_threads); YAZ_CHECK(p); if (p) { iochan_man_t chan_man = iochan_man_create(10); IOCHAN chan = iochan_create(thread_fd, iochan_handler, EVENT_INPUT|EVENT_TIMEOUT, "test_chan"); iochan_settimeout(chan, 1); iochan_setdata(chan, p); iochan_add(chan_man, chan); iochan_man_events(chan_man); sel_thread_destroy(p); iochan_man_destroy(&chan_man); } }
static void getaddrinfo_start(iochan_man_t iochan_man) { int fd; sel_thread_t p = resolver_thread = sel_thread_create(work_handler, 0 /* work_destroy */, &fd, 3 /* no of resolver threads */); if (!p) { yaz_log(YLOG_FATAL|YLOG_ERRNO, "sel_create_create failed"); exit(1); } else { IOCHAN chan = iochan_create(fd, iochan_handler, EVENT_INPUT, "getaddrinfo_socket"); iochan_setdata(chan, p); iochan_add(iochan_man, chan); } yaz_log(log_level, "resolver start"); resolver_thread = p; }
static void inetd_connection(int what) { COMSTACK line; IOCHAN chan; association *assoc; char *addr; if ((line = cs_createbysocket(0, tcpip_type, 0, what))) { if ((chan = iochan_create(cs_fileno(line), ir_session, EVENT_INPUT, 0))) { if ((assoc = create_association(chan, line, control_block.apdufile))) { iochan_setdata(chan, assoc); iochan_settimeout(chan, 60); addr = cs_addrstr(line); yaz_log(log_sessiondetail, "Inetd association from %s", addr ? addr : "[UNKNOWN]"); assoc->cs_get_mask = EVENT_INPUT; } else { yaz_log(YLOG_FATAL, "Failed to create association structure"); } chan->next = pListener; pListener = chan; } else { yaz_log(YLOG_FATAL, "Failed to create iochan"); } } else { yaz_log(YLOG_ERRNO|YLOG_FATAL, "Failed to create comstack on socket 0"); } }
static int http_proxy(struct http_request *rq) { struct http_channel *c = rq->channel; struct http_proxy *p = c->proxy; struct http_header *hp; struct http_buf *requestbuf; char server_port[16] = ""; struct conf_server *ser = c->server; if (!p) // This is a new connection. Create a proxy channel { int sock; struct protoent *pe; int one = 1; if (!(pe = getprotobyname("tcp"))) { abort(); } if ((sock = socket(PF_INET, SOCK_STREAM, pe->p_proto)) < 0) { yaz_log(YLOG_WARN|YLOG_ERRNO, "socket"); return -1; } if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*) &one, sizeof(one)) < 0) abort(); enable_nonblock(sock); if (connect(sock, (struct sockaddr *) c->server->http_server->proxy_addr, sizeof(*c->server->http_server->proxy_addr)) < 0) { if (!is_inprogress()) { yaz_log(YLOG_WARN|YLOG_ERRNO, "Proxy connect"); return -1; } } p = xmalloc(sizeof(struct http_proxy)); p->oqueue = 0; p->channel = c; p->first_response = 1; c->proxy = p; // We will add EVENT_OUTPUT below p->iochan = iochan_create(sock, proxy_io, EVENT_INPUT, "http_proxy"); iochan_setdata(p->iochan, p); iochan_add(ser->iochan_man, p->iochan); } // Do _not_ modify Host: header, just checking it's existence if (!http_lookup_header(rq->headers, "Host")) { yaz_log(YLOG_WARN, "Failed to find Host header in proxy"); return -1; } // Add new header about paraz2 version, host, remote client address, etc. { char server_via[128]; hp = rq->headers; hp = http_header_append(c, hp, "X-Pazpar2-Version", PACKAGE_VERSION); hp = http_header_append(c, hp, "X-Pazpar2-Server-Host", ser->host); sprintf(server_port, "%d", ser->port); hp = http_header_append(c, hp, "X-Pazpar2-Server-Port", server_port); yaz_snprintf(server_via, sizeof(server_via), "1.1 %s:%s (%s/%s)", ser->host ? ser->host : "@", server_port, PACKAGE_NAME, PACKAGE_VERSION); hp = http_header_append(c, hp, "Via" , server_via); hp = http_header_append(c, hp, "X-Forwarded-For", c->addr); } requestbuf = http_serialize_request(rq); http_buf_enqueue(&p->oqueue, requestbuf); iochan_setflag(p->iochan, EVENT_OUTPUT); return 0; }
/* Create a http-channel listener, syntax [host:]port */ int http_init(const char *addr, struct conf_server *server, const char *record_fname) { IOCHAN c; int l; struct protoent *p; struct sockaddr_in myaddr; int one = 1; const char *pp; short port; FILE *record_file = 0; yaz_log(YLOG_LOG, "HTTP listener %s", addr); if (record_fname) { record_file = fopen(record_fname, "wb"); if (!record_file) { yaz_log(YLOG_FATAL|YLOG_ERRNO, "fopen %s", record_fname); return 1; } } memset(&myaddr, 0, sizeof myaddr); myaddr.sin_family = AF_INET; pp = strchr(addr, ':'); if (pp) { WRBUF w = wrbuf_alloc(); struct hostent *he; wrbuf_write(w, addr, pp - addr); wrbuf_puts(w, ""); he = gethostbyname(wrbuf_cstr(w)); wrbuf_destroy(w); if (!he) { yaz_log(YLOG_FATAL, "Unable to resolve '%s'", addr); return 1; } memcpy(&myaddr.sin_addr.s_addr, he->h_addr_list[0], he->h_length); port = atoi(pp + 1); } else { port = atoi(addr); myaddr.sin_addr.s_addr = INADDR_ANY; } myaddr.sin_port = htons(port); if (!(p = getprotobyname("tcp"))) { return 1; } if ((l = socket(PF_INET, SOCK_STREAM, p->p_proto)) < 0) yaz_log(YLOG_FATAL|YLOG_ERRNO, "socket"); if (setsockopt(l, SOL_SOCKET, SO_REUSEADDR, (char*) &one, sizeof(one)) < 0) return 1; if (bind(l, (struct sockaddr *) &myaddr, sizeof myaddr) < 0) { yaz_log(YLOG_FATAL|YLOG_ERRNO, "bind"); return 1; } if (listen(l, SOMAXCONN) < 0) { yaz_log(YLOG_FATAL|YLOG_ERRNO, "listen"); return 1; } server->http_server = http_server_create(); server->http_server->record_file = record_file; server->http_server->listener_socket = l; c = iochan_create(l, http_accept, EVENT_INPUT | EVENT_EXCEPT, "http_server"); iochan_setdata(c, server); iochan_add(server->iochan_man, c); return 0; }
static int connection_connect(struct connection *con, iochan_man_t iochan_man) { struct host *host = connection_get_host(con); ZOOM_options zoptions = ZOOM_options_create(); const char *auth; const char *charset; const char *sru; const char *sru_version = 0; struct session_database *sdb = client_get_database(con->client); const char *apdulog = session_setting_oneval(sdb, PZ_APDULOG); assert(con); ZOOM_options_set(zoptions, "async", "1"); ZOOM_options_set(zoptions, "implementationName", PACKAGE_NAME); ZOOM_options_set(zoptions, "implementationVersion", VERSION); if ((charset = session_setting_oneval(sdb, PZ_NEGOTIATION_CHARSET))) ZOOM_options_set(zoptions, "charset", charset); assert(host->ipport); if (host->proxy) { yaz_log(YLOG_LOG, "proxy=%s", host->ipport); ZOOM_options_set(zoptions, "proxy", host->ipport); } else { assert(host->tproxy); yaz_log(YLOG_LOG, "tproxy=%s", host->ipport); ZOOM_options_set(zoptions, "tproxy", host->ipport); } if (apdulog && *apdulog) ZOOM_options_set(zoptions, "apdulog", apdulog); if ((auth = session_setting_oneval(sdb, PZ_AUTHENTICATION))) ZOOM_options_set(zoptions, "user", auth); if ((sru = session_setting_oneval(sdb, PZ_SRU)) && *sru) ZOOM_options_set(zoptions, "sru", sru); if ((sru_version = session_setting_oneval(sdb, PZ_SRU_VERSION)) && *sru_version) ZOOM_options_set(zoptions, "sru_version", sru_version); if (!(con->link = ZOOM_connection_create(zoptions))) { yaz_log(YLOG_FATAL|YLOG_ERRNO, "Failed to create ZOOM Connection"); ZOOM_options_destroy(zoptions); return -1; } if (sru && *sru) { char http_hostport[512]; strcpy(http_hostport, "http://"); strcat(http_hostport, host->url); yaz_log(YLOG_LOG, "SRU connect to : %s", http_hostport); ZOOM_connection_connect(con->link, http_hostport, 0); } else { ZOOM_connection_connect(con->link, host->url, 0); } con->iochan = iochan_create(-1, connection_handler, 0, "connection_socket"); con->state = Conn_Connecting; iochan_settimeout(con->iochan, con->operation_timeout); iochan_setdata(con->iochan, con); iochan_add(iochan_man, con->iochan); client_set_state(con->client, Client_Connecting); ZOOM_options_destroy(zoptions); return 0; }
static void *new_session(void *vp) { char *a; association *newas; IOCHAN new_chan; COMSTACK new_line = (COMSTACK) vp; IOCHAN parent_chan = (IOCHAN) new_line->user; unsigned cs_get_mask, cs_accept_mask, mask = ((new_line->io_pending & CS_WANT_WRITE) ? EVENT_OUTPUT : 0) | ((new_line->io_pending & CS_WANT_READ) ? EVENT_INPUT : 0); if (mask) { cs_accept_mask = mask; /* accept didn't complete */ cs_get_mask = 0; } else { cs_accept_mask = 0; /* accept completed. */ cs_get_mask = mask = EVENT_INPUT; } if (!(new_chan = iochan_create(cs_fileno(new_line), ir_session, mask, parent_chan->chan_id))) { yaz_log(YLOG_FATAL, "Failed to create iochan"); return 0; } if (!(newas = create_association(new_chan, new_line, control_block.apdufile))) { yaz_log(YLOG_FATAL, "Failed to create new assoc."); return 0; } newas->cs_accept_mask = cs_accept_mask; newas->cs_get_mask = cs_get_mask; iochan_setdata(new_chan, newas); iochan_settimeout(new_chan, 60); #if 1 a = cs_addrstr(new_line); #else a = 0; #endif yaz_log_xml_errors(0, YLOG_WARN); yaz_log(log_session, "Session - OK %d %s %ld", no_sessions, a ? a : "[Unknown]", (long) getpid()); if (max_sessions && no_sessions >= max_sessions) control_block.one_shot = 1; if (control_block.threads) { iochan_event_loop(&new_chan); } else { new_chan->next = pListener; pListener = new_chan; } return 0; }
/* 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; } }