/** * New inbound connection for httpd. * * @param[in] fd socket file descriptor * @param[in] id I/O ID */ void hio_connection(iosrc_t fd, ioid_t id) { socket_t t; union { struct sockaddr sa; struct sockaddr_in sin; #if defined(X3270_IPV6) /*[*/ struct sockaddr_in6 sin6; #endif /*]*/ } sa; socklen_t len; char hostbuf[128]; session_t *session; len = sizeof(sa); t = accept(listen_s, &sa.sa, &len); if (t == INVALID_SOCKET) { vtrace("httpd accept error: %s%s\n", socket_errtext(), (socket_errno() == SE_EWOULDBLOCK)? " (harmless)": ""); return; } if (n_sessions >= N_SESSIONS) { vtrace("Too many connections.\n"); SOCK_CLOSE(t); return; } session = Malloc(sizeof(session_t)); memset(session, 0, sizeof(session_t)); vb_init(&session->pending.result); session->s = t; #if defined(_WIN32) /*[*/ session->event = CreateEvent(NULL, FALSE, FALSE, NULL); if (session->event == NULL) { vtrace("httpd: can't create socket handle\n"); SOCK_CLOSE(t); Free(session); return; } if (WSAEventSelect(session->s, session->event, FD_READ | FD_CLOSE) != 0) { vtrace("httpd: Can't set socket handle events\n"); CloseHandle(session->event); SOCK_CLOSE(t); Free(session); return; } #endif /*]*/ if (sa.sa.sa_family == AF_INET) { session->dhandle = httpd_new(session, lazyaf("%s:%u", inet_ntop(AF_INET, &sa.sin.sin_addr, hostbuf, sizeof(hostbuf)), ntohs(sa.sin.sin_port))); } #if defined(X3270_IPV6) /*[*/ else if (sa.sa.sa_family == AF_INET6) { session->dhandle = httpd_new(session, lazyaf("%s:%u", inet_ntop(AF_INET6, &sa.sin6.sin6_addr, hostbuf, sizeof(hostbuf)), ntohs(sa.sin6.sin6_port))); } #endif /*]*/ else { session->dhandle = httpd_new(session, "???"); } #if !defined(_WIN32) /*[*/ session->ioid = AddInput(t, hio_socket_input); #else /*][*/ session->ioid = AddInput(session->event, hio_socket_input); #endif /*]*/ /* Set the timeout for the first line of input. */ session->toid = AddTimeOut(IDLE_MAX * 1000, hio_timeout); llist_insert_before(&session->link, sessions.next); n_sessions++; }
static void * httpd_session_main(void *data) #endif { struct hrequest_t *req; conndata_t *conn; httpd_conn_t *rconn; hservice_t *service; herror_t status; struct timeval start, end, duration; int done; if (gettimeofday(&start, NULL) == -1) log_error("gettimeofday failed (%s)", strerror(errno)); conn = (conndata_t *) data; log_verbose("starting new httpd session on socket %d", conn->sock); rconn = httpd_new(&(conn->sock)); done = 0; while (!done) { log_verbose("starting HTTP request on socket %d (%p)", conn->sock, conn->sock.sock); if ((status = hrequest_new_from_socket(&(conn->sock), &req)) != H_OK) { int code; switch ((code = herror_code(status))) { case HSSL_ERROR_SSLCLOSE: case HSOCKET_ERROR_RECEIVE: log_error("hrequest_new_from_socket failed (%s)", herror_message(status)); break; default: httpd_send_bad_request(rconn, herror_message(status)); break; } herror_release(status); done = 1; } else { char *conn_str; _httpd_request_print(req); conn_str = hpairnode_get_ignore_case(req->header, HEADER_CONNECTION); if (conn_str && strncasecmp(conn_str, "close", 6) == 0) done = 1; if (!done) done = req->version == HTTP_1_0 ? 1 : 0; if ((service = httpd_find_service(req->path))) { log_verbose("service '%s' for '%s' found", service->context, req->path); if (service->status == NHTTPD_SERVICE_UP) { pthread_rwlock_wrlock(&(service->statistics->lock)); service->statistics->requests++; pthread_rwlock_unlock(&(service->statistics->lock)); if (_httpd_authenticate_request(req, service->auth)) { if (service->func != NULL) { service->func(rconn, req); if (gettimeofday(&end, NULL) == -1) log_error("gettimeofday failed (%s)", strerror(errno)); timersub(&end, &start, &duration); pthread_rwlock_wrlock(&(service->statistics->lock)); service->statistics->bytes_received += rconn->sock->bytes_received; service->statistics->bytes_transmitted += rconn->sock->bytes_transmitted; timeradd(&(service->statistics->time), &duration, &(service->statistics->time)); pthread_rwlock_unlock(&(service->statistics->lock)); if (rconn->out && rconn->out->type == HTTP_TRANSFER_CONNECTION_CLOSE) { log_verbose("Connection close requested"); done = 1; } } else { char buffer[256]; snprintf(buffer, 256, "service '%s' is not registered properly (service function is NULL)", req->path); log_verbose("%s", buffer); httpd_send_not_implemented(rconn, buffer); } } else { httpd_send_unauthorized(rconn, req->path); done = 1; } } else { char buffer[256]; sprintf(buffer, "service for '%s' is disabled", req->path); log_verbose("%s", buffer); httpd_send_internal_error(rconn, buffer); } } else { char buffer[256]; sprintf(buffer, "no service for '%s' found", req->path); log_verbose("%s", buffer); httpd_send_not_implemented(rconn, buffer); done = 1; } hrequest_free(req); } } httpd_free(rconn); hsocket_close(&(conn->sock)); #ifdef WIN32 CloseHandle((HANDLE) conn->tid); #else pthread_attr_destroy(&(conn->attr)); #endif conn->flag = CONNECTION_FREE; #ifdef WIN32 _endthread(); return 0; #else /* pthread_exits automagically */ return NULL; #endif }