Beispiel #1
0
/**
 * 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++;
}
Beispiel #2
0
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
}