/** * @short Internal accept of just one request. * * It might be called straight from listen, or from the epoller. * * @returns 0 if ok, <0 if error. */ static int onion_accept_request(onion *o){ struct sockaddr_storage cli_addr; socklen_t cli_len; int clientfd=onion_accept(o, &cli_addr, &cli_len); if (clientfd<0) return -1; if (o->flags&O_POLL){ onion_request *req=onion_connection_start(o, clientfd, &cli_addr, cli_len); if (!req){ shutdown(clientfd,SHUT_RDWR); // Socket must be destroyed. close(clientfd); return 0; } onion_poller_slot *slot=onion_poller_slot_new(clientfd, (void*)onion_connection_read, req); onion_poller_slot_set_shutdown(slot, (void*)onion_connection_shutdown, req); onion_poller_slot_set_timeout(slot, o->timeout); onion_poller_add(o->poller, slot); } else{ onion_process_request(o, clientfd, &cli_addr, cli_len); } return 0; }
/** * @short Called when a new connection appears on the listenfd * @memberof onion_listen_point_t * * When the new connection appears, creates the request and adds it to the pollers. * * It returns always 1 as any <0 would detach from the poller and close the listen point, * and not accepting a request does not mean the connection point is corrupted. If a * connection point may become corrupted should be the connection point itself who detaches * from the poller. * * @param op The listen point from where the request must be built * @returns 1 always. */ int onion_listen_point_accept(onion_listen_point *op){ onion_request *req=onion_request_new(op); if (req){ if (req->connection.fd>0){ onion_poller_slot *slot=onion_poller_slot_new(req->connection.fd, (void*)onion_listen_point_read_ready, req); if (!slot) return 1; onion_poller_slot_set_timeout(slot, req->connection.listen_point->server->timeout); onion_poller_slot_set_shutdown(slot, (void*)onion_request_free, req); onion_poller_add(req->connection.listen_point->server->poller, slot); return 1; } if (req->connection.fd<0) ONION_ERROR("Error creating connection"); // else, no need for fd... no use case yet. } return 1; }
/** * @short Called when a new connection appears on the listenfd * @memberof onion_listen_point_t * * When the new connection appears, creates the request and adds it to the pollers. * * It returns always 1 as any <0 would detach from the poller and close the listen point, * and not accepting a request does not mean the connection point is corrupted. If a * connection point may become corrupted should be the connection point itself who detaches * from the poller. * * @param op The listen point from where the request must be built * @returns 1 always. The poller needs one to keep listening for connections. */ int onion_listen_point_accept(onion_listen_point *op){ onion_request *req=onion_request_new(op); if (req){ if (req->connection.fd>0){ onion_poller_slot *slot=onion_poller_slot_new(req->connection.fd, (void*)onion_listen_point_read_ready, req); if (!slot) return 1; onion_poller_slot_set_timeout(slot, req->connection.listen_point->server->timeout); onion_poller_slot_set_shutdown(slot, (void*)onion_request_free, req); onion_poller_add(req->connection.listen_point->server->poller, slot); return 1; } // No fd. This could mean error, or not fd based. Normally error would not return a req. onion_request_free(req); ONION_ERROR("Error creating connection"); return 1; } return 1; }
/** * @short Launches one handler for the given request * @ingroup request * * Once the request is ready, launch it. * * @returns The connection status: if it should be closed, error codes... */ onion_connection_status onion_request_process(onion_request *req){ onion_response *res=onion_response_new(req); if (!req->path){ onion_request_polish(req); } // Call the main handler. onion_connection_status hs=onion_handler_handle(req->connection.listen_point->server->root_handler, req, res); if (hs==OCS_INTERNAL_ERROR || hs==OCS_NOT_IMPLEMENTED || hs==OCS_NOT_PROCESSED){ if (hs==OCS_INTERNAL_ERROR) req->flags|=OR_INTERNAL_ERROR; if (hs==OCS_NOT_IMPLEMENTED) req->flags|=OR_NOT_IMPLEMENTED; if (hs==OCS_NOT_PROCESSED) req->flags|=OR_NOT_FOUND; if (hs==OCS_FORBIDDEN) req->flags|=OR_FORBIDDEN; hs=onion_handler_handle(req->connection.listen_point->server->internal_error_handler, req, res); } if (hs==OCS_YIELD){ // Remove from the poller, and yield thread to poller. From now on it will be processed somewhere else (longpoll thread). onion_poller *poller=onion_get_poller(req->connection.listen_point->server); onion_poller_slot *slot=onion_poller_get(poller, req->connection.fd); onion_poller_slot_set_shutdown(slot, NULL, NULL); return hs; } int rs=onion_response_free(res); if (hs>=0 && rs==OCS_KEEP_ALIVE) // if keep alive, reset struct to get the new petition. onion_request_clean(req); return hs>0 ? rs : hs; }