/** Closure sent to main thread to request a reply to be sent to * a HTTP request. * Replies must be sent in the main loop in the main http thread, * this cannot be done from worker threads. */ void HTTPRequest::WriteReply(int nStatus, const std::string& strReply) { assert(!replySent && req); // Send event to main http thread to send reply message struct evbuffer* evb = evhttp_request_get_output_buffer(req); assert(evb); evbuffer_add(evb, strReply.data(), strReply.size()); auto req_copy = req; HTTPEvent* ev = new HTTPEvent(eventBase, true, [req_copy, nStatus]{ evhttp_send_reply(req_copy, nStatus, nullptr, nullptr); // Re-enable reading from the socket. This is the second part of the libevent // workaround above. if (event_get_version_number() >= 0x02010600 && event_get_version_number() < 0x02020001) { evhttp_connection* conn = evhttp_request_get_connection(req_copy); if (conn) { bufferevent* bev = evhttp_connection_get_bufferevent(conn); if (bev) { bufferevent_enable(bev, EV_READ | EV_WRITE); } } } }); ev->trigger(nullptr); replySent = true; req = nullptr; // transferred back to main thread }
int libevent_version_ok(void) { ev_uint32_t v_compile_maj; ev_uint32_t v_run_maj; v_compile_maj = LIBEVENT_VERSION_NUMBER & 0xffff0000; v_run_maj = event_get_version_number() & 0xffff0000; if (v_compile_maj != v_run_maj) { fprintf(stderr, "Incompatible libevent versions: have %s, built with %s\n", event_get_version(), LIBEVENT_VERSION); return 0; } return 1; }
/** Return the version number of the currently running version of Libevent. * See le_version_t for info on the format. */ static le_version_t tor_get_libevent_version(const char **v_out) { const char *v; le_version_t r; #if defined(HAVE_EVENT_GET_VERSION_NUMBER) v = event_get_version(); r = event_get_version_number(); #elif defined (HAVE_EVENT_GET_VERSION) v = event_get_version(); r = tor_decode_libevent_version(v); #else v = "pre-1.0c"; r = LE_OLD; #endif if (v_out) *v_out = v; return r; }
void internal_parc_initializeLibevent(void) { if (_libeventInitialized) { return; } _libeventInitialized = 1; // 0x AA BB CC XX // AA = major // BB = minor // CC = patchlevel // uint32_t version = event_get_version_number(); trapIllegalValueIf(version < 0x02001000UL, "Libevent version must be at least 2.0.16, got %s", event_get_version()); // Make sure libevent uses our memory allocator. // Libevent allocates an internal object the first time a base is allocated // that it never releases. In order to ensure our outstanding memory counters // start at zero we trigger this allocation before interposing our memory allocator. // // Create a scheduler event base, an event, then free both of them. // struct event_base *evbase = event_base_new(); assertNotNull(evbase, "Libevent event_base_new returned NULL"); struct event *event = event_new(evbase, -1, 0, NULL, NULL); assertNotNull(event, "Libevent event_new returned NULL"); event_del(event); event_base_free(evbase); event_set_mem_functions(internal_parc_alloc, internal_parc_realloc, internal_parc_free); }
int main(int argc, char * * argv) { struct sigaction sa; upnpc_t upnp; char * multicast_if = NULL; if(argc > 1) { multicast_if = argv[1]; } memset(&sa, 0, sizeof(struct sigaction)); sa.sa_handler = sighandler; if(sigaction(SIGINT, &sa, NULL) < 0) { perror("sigaction"); } if(find_local_address() < 0) { fprintf(stderr, "failed to get local address\n"); return 1; } #ifdef DEBUG event_enable_debug_mode(); #if LIBEVENT_VERSION_NUMBER >= 0x02010100 event_enable_debug_logging(EVENT_DBG_ALL); /* Libevent 2.1.1 */ #endif /* LIBEVENT_VERSION_NUMBER >= 0x02010100 */ #endif /* DEBUG */ printf("Using libevent %s\n", event_get_version()); if(LIBEVENT_VERSION_NUMBER != event_get_version_number()) { fprintf(stderr, "WARNING build using libevent %s", LIBEVENT_VERSION); } base = event_base_new(); if(base == NULL) { fprintf(stderr, "event_base_new() failed\n"); return 1; } #ifdef DEBUG printf("Using Libevent with backend method %s.\n", event_base_get_method(base)); #endif /* DEBUG */ if(upnpc_init(&upnp, base, multicast_if, ready, soap, &upnp) != UPNPC_OK) { fprintf(stderr, "upnpc_init() failed\n"); return 1; } upnpc_set_local_address(&upnp, local_address, 50000); #ifdef ENABLE_UPNP_EVENTS upnpc_set_event_callback(&upnp, event_callback); #endif /* ENABLE_UPNP_EVENTS */ if(upnpc_start(&upnp) != UPNPC_OK) { fprintf(stderr, "upnp_start() failed\n"); return 1; } event_base_dispatch(base); /* TODO : check return value */ printf("finishing...\n"); upnpc_finalize(&upnp); event_base_free(base); #if LIBEVENT_VERSION_NUMBER >= 0x02010100 libevent_global_shutdown(); /* Libevent 2.1.1 */ #endif return 0; }
/** HTTP request callback */ static void http_request_cb(struct evhttp_request* req, void* arg) { // Disable reading to work around a libevent bug, fixed in 2.2.0. if (event_get_version_number() >= 0x02010600 && event_get_version_number() < 0x02020001) { evhttp_connection* conn = evhttp_request_get_connection(req); if (conn) { bufferevent* bev = evhttp_connection_get_bufferevent(conn); if (bev) { bufferevent_disable(bev, EV_READ); } } } std::unique_ptr<HTTPRequest> hreq(new HTTPRequest(req)); // Early address-based allow check if (!ClientAllowed(hreq->GetPeer())) { LogPrint(BCLog::HTTP, "HTTP request from %s rejected: Client network is not allowed RPC access\n", hreq->GetPeer().ToString()); hreq->WriteReply(HTTP_FORBIDDEN); return; } // Early reject unknown HTTP methods if (hreq->GetRequestMethod() == HTTPRequest::UNKNOWN) { LogPrint(BCLog::HTTP, "HTTP request from %s rejected: Unknown HTTP request method\n", hreq->GetPeer().ToString()); hreq->WriteReply(HTTP_BADMETHOD); return; } LogPrint(BCLog::HTTP, "Received a %s request for %s from %s\n", RequestMethodString(hreq->GetRequestMethod()), SanitizeString(hreq->GetURI(), SAFE_CHARS_URI).substr(0, 100), hreq->GetPeer().ToString()); // Find registered handler for prefix std::string strURI = hreq->GetURI(); std::string path; std::vector<HTTPPathHandler>::const_iterator i = pathHandlers.begin(); std::vector<HTTPPathHandler>::const_iterator iend = pathHandlers.end(); for (; i != iend; ++i) { bool match = false; if (i->exactMatch) match = (strURI == i->prefix); else match = (strURI.substr(0, i->prefix.size()) == i->prefix); if (match) { path = strURI.substr(i->prefix.size()); break; } } // Dispatch to worker thread if (i != iend) { std::unique_ptr<HTTPWorkItem> item(new HTTPWorkItem(std::move(hreq), path, i->handler)); assert(workQueue); if (workQueue->Enqueue(item.get())) item.release(); /* if true, queue took ownership */ else { LogPrintf("WARNING: request rejected because http work queue depth exceeded, it can be increased with the -rpcworkqueue= setting\n"); item->req->WriteReply(HTTP_INTERNAL, "Work queue depth exceeded"); } } else { hreq->WriteReply(HTTP_NOTFOUND); } }
int main(int argc, char **argv) { int error; app_subsys **ss; int exit_signals[2] = {SIGTERM, SIGINT}; struct event terminators[2]; bool conftest = false; int opt; int i; evutil_secure_rng_init(); while ((opt = getopt(argc, argv, "h?vtc:p:")) != -1) { switch (opt) { case 't': conftest = true; break; case 'c': confname = optarg; break; case 'p': pidfile = optarg; break; case 'v': puts(redsocks_version); printf("Built with libevent-%s\n", LIBEVENT_VERSION); printf("Runs with libevent-%s\n", event_get_version()); if (LIBEVENT_VERSION_NUMBER != event_get_version_number()) { printf("Warning: libevent version number mismatch.\n" " Headers: %8x\n" " Runtime: %8x\n", LIBEVENT_VERSION_NUMBER, event_get_version_number()); } return EXIT_SUCCESS; default: printf( "Usage: %s [-?hvt] [-c config] [-p pidfile]\n" " -h, -? this message\n" " -v print version\n" " -t test config syntax\n" " -p write pid to pidfile\n", argv[0]); return (opt == '?' || opt == 'h') ? EXIT_SUCCESS : EXIT_FAILURE; } } if (event_get_struct_event_size() != sizeof(struct event)) { puts("libevent event_get_struct_event_size() != sizeof(struct event)! Check `redsocks -v` and recompile redsocks"); return EXIT_FAILURE; } FILE *f = fopen(confname, "r"); if (!f) { perror("Unable to open config file"); return EXIT_FAILURE; } parser_context* parser = parser_start(f); if (!parser) { perror("Not enough memory for parser"); return EXIT_FAILURE; } FOREACH(ss, subsystems) if ((*ss)->conf_section) parser_add_section(parser, (*ss)->conf_section); error = parser_run(parser); parser_stop(parser); fclose(f); if (error) return EXIT_FAILURE; if (conftest) return EXIT_SUCCESS; struct event_base* evbase = event_init(); memset(terminators, 0, sizeof(terminators)); FOREACH(ss, subsystems) { if ((*ss)->init) { error = (*ss)->init(evbase); if (error) goto shutdown; } } if (pidfile) { f = fopen(pidfile, "w"); if (!f) { perror("Unable to open pidfile for write"); return EXIT_FAILURE; } fprintf(f, "%d\n", getpid()); fclose(f); } assert(SIZEOF_ARRAY(exit_signals) == SIZEOF_ARRAY(terminators)); for (i = 0; i < SIZEOF_ARRAY(exit_signals); i++) { signal_set(&terminators[i], exit_signals[i], terminate, NULL); if (signal_add(&terminators[i], NULL) != 0) { log_errno(LOG_ERR, "signal_add"); goto shutdown; } } if (LIBEVENT_VERSION_NUMBER != event_get_version_number()) { log_error(LOG_WARNING, "libevent version mismatch! headers %8x, runtime %8x\n", LIBEVENT_VERSION_NUMBER, event_get_version_number()); } log_error(LOG_NOTICE, "redsocks started, conn_max=%u", redsocks_conn_max()); event_dispatch(); log_error(LOG_NOTICE, "redsocks goes down"); shutdown: for (i = 0; i < SIZEOF_ARRAY(exit_signals); i++) { if (signal_initialized(&terminators[i])) { if (signal_del(&terminators[i]) != 0) log_errno(LOG_WARNING, "signal_del"); memset(&terminators[i], 0, sizeof(terminators[i])); } } for (--ss; ss >= subsystems; ss--) if ((*ss)->fini) (*ss)->fini(); event_base_free(evbase); return !error ? EXIT_SUCCESS : EXIT_FAILURE; }