Пример #1
0
/** 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
}
Пример #2
0
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;
}
Пример #3
0
/** 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;
}
Пример #4
0
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);
}
Пример #5
0
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;
}
Пример #6
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);
    }
}
Пример #7
0
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;
}