Skip to content
Snippets Groups Projects
mongoose.c 160 KiB
Newer Older
Sergey Lyubka's avatar
Sergey Lyubka committed
    conn->ns_conn = nc;

    // Initialize the rest of connection attributes
    conn->server = server;
    conn->mg_conn.server_param = nc->mgr->user_data;
    set_ips(nc, 1);
    set_ips(nc, 0);
Sergey Lyubka's avatar
Sergey Lyubka committed
static void process_udp(struct ns_connection *nc) {
  struct iobuf *io = &nc->recv_iobuf;
  struct connection conn;

  memset(&conn, 0, sizeof(conn));
  conn.ns_conn = nc;
  conn.server = (struct mg_server *) nc->mgr;
  conn.request_len = parse_http_message(io->buf, io->len, &conn.mg_conn);
  on_recv_data(&conn);
  //ns_printf(nc, "%s", "HTTP/1.0 200 OK\r\n\r\n");
}

Sergey Lyubka's avatar
Sergey Lyubka committed
static void mg_ev_handler(struct ns_connection *nc, enum ns_event ev, void *p) {
Ake Hedman's avatar
Ake Hedman committed
  struct connection *conn = (struct connection *) nc->user_data;
  // Send NS event to the handler. Note that call_user won't send an event
  // if conn == NULL. Therefore, repeat this for NS_ACCEPT event as well.
#ifdef MONGOOSE_SEND_NS_EVENTS
  {
Ake Hedman's avatar
Ake Hedman committed
    struct connection *conn = (struct connection *) nc->user_data;
    void *param[2] = { nc, p };
    if (conn != NULL) conn->mg_conn.callback_param = param;
Sergey Lyubka's avatar
Sergey Lyubka committed
  switch (ev) {
    case NS_ACCEPT:
      on_accept(nc, (union socket_address *) p);
Ake Hedman's avatar
Ake Hedman committed
        struct connection *conn = (struct connection *) nc->user_data;
        void *param[2] = { nc, p };
        if (conn != NULL) conn->mg_conn.callback_param = param;
Sergey Lyubka's avatar
Sergey Lyubka committed
      break;

    case NS_CONNECT:
Ake Hedman's avatar
Ake Hedman committed
      if (nc->user_data != NULL) {
Daniel O'Connell's avatar
Daniel O'Connell committed
        set_ips(nc, 1);
        set_ips(nc, 0);
      }
Sergey Lyubka's avatar
Sergey Lyubka committed
      conn->mg_conn.status_code = * (int *) p;
      if (conn->mg_conn.status_code != 0 ||
          (!(nc->flags & MG_PROXY_CONN) &&
           call_user(conn, MG_CONNECT) == MG_FALSE)) {
Sergey Lyubka's avatar
Sergey Lyubka committed
        nc->flags |= NSF_CLOSE_IMMEDIATELY;
Sergey Lyubka's avatar
Sergey Lyubka committed
      }
      break;

    case NS_RECV:
      if (conn != NULL) {
        conn->num_bytes_recv += * (int *) p;
      }
Sergey Lyubka's avatar
Sergey Lyubka committed

      if (nc->flags & NSF_UDP) {
        process_udp(nc);
      } else if (nc->listener != NULL) {
        on_recv_data(conn);
Sergey Lyubka's avatar
Sergey Lyubka committed
      } else if (nc->flags & MG_CGI_CONN) {
        on_cgi_data(nc);
      } else if (nc->flags & MG_PROXY_CONN) {
        if (conn != NULL) {
          ns_forward(nc, conn->ns_conn);
        }
Sergey Lyubka's avatar
Sergey Lyubka committed
      } else {
        process_response(conn);
      }
      break;

    case NS_SEND:
      break;

    case NS_CLOSE:
Ake Hedman's avatar
Ake Hedman committed
      nc->user_data = NULL;
      if (nc->flags & (MG_CGI_CONN | MG_PROXY_CONN)) {
        DBG(("%p %p closing cgi/proxy conn", conn, nc));
        if (conn && conn->ns_conn) {
          conn->ns_conn->flags &= ~NSF_BUFFER_BUT_DONT_SEND;
          conn->ns_conn->flags |= conn->ns_conn->send_iobuf.len > 0 ?
            NSF_FINISHED_SENDING_DATA : NSF_CLOSE_IMMEDIATELY;
          conn->endpoint.nc = NULL;
        }
Sergey Lyubka's avatar
Sergey Lyubka committed
      } else if (conn != NULL) {
        DBG(("%p %p %d closing", conn, nc, conn->endpoint_type));
Sergey Lyubka's avatar
Sergey Lyubka committed

        if (conn->endpoint_type == EP_CLIENT && nc->recv_iobuf.len > 0) {
          call_http_client_handler(conn);
        call_user(conn, MG_CLOSE);
Sergey Lyubka's avatar
Sergey Lyubka committed
        close_local_endpoint(conn);
        conn->ns_conn = NULL;
Sergey Lyubka's avatar
Sergey Lyubka committed
        free(conn);
      }
      break;

    case NS_POLL:
      if (conn != NULL) {
        if (call_user(conn, MG_POLL) == MG_TRUE) {
          if (conn->ns_conn->flags & MG_HEADERS_SENT) {
            write_terminating_chunk(conn);
          }
          close_local_endpoint(conn);
Sergey Lyubka's avatar
Sergey Lyubka committed

        if (conn->endpoint_type == EP_FILE) {
          transfer_file_data(conn);
        }
Sergey Lyubka's avatar
Sergey Lyubka committed
      }

      // Expire idle connections
      {
        time_t current_time = * (time_t *) p;

        if (conn != NULL && conn->mg_conn.is_websocket) {
Sergey Lyubka's avatar
Sergey Lyubka committed
          ping_idle_websocket_connection(conn, current_time);
        }

        if (nc->listener != NULL &&
            nc->last_io_time + MONGOOSE_IDLE_TIMEOUT_SECONDS < current_time) {
          mg_ev_handler(nc, NS_CLOSE, NULL);
Sergey Lyubka's avatar
Sergey Lyubka committed
          nc->flags |= NSF_CLOSE_IMMEDIATELY;
        }
      }
      break;

    default:
      break;
  }
}

static void iter2(struct ns_connection *nc, enum ns_event ev, void *param) {
  mg_handler_t func = NULL;
Ake Hedman's avatar
Ake Hedman committed
  struct connection *conn = (struct connection *) nc->user_data;
  const char *msg = (const char *) param;
  int n;
  (void) ev;

  //DBG(("%p [%s]", conn, msg));
  if (sscanf(msg, "%p %n", &func, &n) && func != NULL) {
    conn->mg_conn.callback_param = (void *) (msg + n);
    func(&conn->mg_conn, MG_POLL);
  }
}

void mg_wakeup_server_ex(struct mg_server *server, mg_handler_t cb,
                         const char *fmt, ...) {
  va_list ap;
  char buf[8 * 1024];
  int len;

  // Encode callback (cb) into a buffer
  len = snprintf(buf, sizeof(buf), "%p ", cb);
  va_start(ap, fmt);
  len += vsnprintf(buf + len, sizeof(buf) - len, fmt, ap);
  va_end(ap);

  // "len + 1" is to include terminating \0 in the message
  ns_broadcast(&server->ns_mgr, iter2, buf, len + 1);
Sergey Lyubka's avatar
Sergey Lyubka committed
void mg_wakeup_server(struct mg_server *server) {
  ns_broadcast(&server->ns_mgr, NULL, (void *) "", 0);
void mg_set_listening_socket(struct mg_server *server, int sock) {
  if (server->ns_mgr.listening_sock != INVALID_SOCKET) {
    closesocket(server->ns_mgr.listening_sock);
  server->ns_mgr.listening_sock = (sock_t) sock;
  return server->ns_mgr.listening_sock;
const char *mg_get_option(const struct mg_server *server, const char *name) {
  const char **opts = (const char **) server->config_options;
  int i = get_option_index(name);
  return i == -1 ? NULL : opts[i] == NULL ? "" : opts[i];
}

struct mg_server *mg_create_server(void *server_data, mg_handler_t handler) {
  struct mg_server *server = (struct mg_server *) calloc(1, sizeof(*server));
  ns_mgr_init(&server->ns_mgr, server_data, mg_ev_handler);
  set_default_option_values(server->config_options);
  server->event_handler = handler;
  return server;