Exemplo n.º 1
0
char const *
endpoint_presentation(struct endpoint const *e)
{
    static char name[INET6_ADDRSTRLEN];

    switch (e->addr.ss_family)
    {
        case AF_INET:
            {
                struct sockaddr_in *sin = (struct sockaddr_in *)&e->addr;
                char tmp[INET_ADDRSTRLEN];

                evutil_inet_ntop(AF_INET, &sin->sin_addr, tmp, sizeof tmp);
                evutil_snprintf(name, INET6_ADDRSTRLEN, "%s:%d", tmp, ntohs(sin->sin_port));
                break;
            }
        case AF_INET6:
            {
                struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&e->addr;
                char tmp[INET6_ADDRSTRLEN];

                evutil_inet_ntop(AF_INET6, &sin6->sin6_addr, tmp, sizeof tmp);
                evutil_snprintf(name, INET6_ADDRSTRLEN, "%s:%d", tmp, ntohs(sin6->sin6_port));
                break;
            }
        default:
            {
                log_warnx("[ENDPOINT] presentation doesn't handle protocol", e->addr.ss_family);
            }
    }
    return name;
}
Exemplo n.º 2
0
static void
test_evutil_snprintf(void *ptr)
{
	char buf[16];
	int r;
	ev_uint64_t u64 = ((ev_uint64_t)1000000000)*200;
	ev_int64_t i64 = -1 * (ev_int64_t) u64;
	size_t size = 8000;
	ev_ssize_t ssize = -9000;

	r = evutil_snprintf(buf, sizeof(buf), "%d %d", 50, 100);
	tt_str_op(buf, ==, "50 100");
	tt_int_op(r, ==, 6);

	r = evutil_snprintf(buf, sizeof(buf), "longish %d", 1234567890);
	tt_str_op(buf, ==, "longish 1234567");
	tt_int_op(r, ==, 18);

	r = evutil_snprintf(buf, sizeof(buf), EV_U64_FMT, EV_U64_ARG(u64));
	tt_str_op(buf, ==, "200000000000");
	tt_int_op(r, ==, 12);

	r = evutil_snprintf(buf, sizeof(buf), EV_I64_FMT, EV_I64_ARG(i64));
	tt_str_op(buf, ==, "-200000000000");
	tt_int_op(r, ==, 13);

	r = evutil_snprintf(buf, sizeof(buf), EV_SIZE_FMT" "EV_SSIZE_FMT,
	    EV_SIZE_ARG(size), EV_SSIZE_ARG(ssize));
	tt_str_op(buf, ==, "8000 -9000");
	tt_int_op(r, ==, 10);

      end:
	;
}
Exemplo n.º 3
0
static void
dns_reissue_test(void *arg)
{
	struct basic_test_data *data = arg;
	struct event_base *base = data->base;
	struct evdns_server_port *port1 = NULL, *port2 = NULL;
	struct evdns_base *dns = NULL;
	struct generic_dns_callback_result r1;
	ev_uint16_t portnum1 = 0, portnum2=0;
	char buf1[64], buf2[64];

	port1 = regress_get_dnsserver(base, &portnum1, NULL,
	    regress_dns_server_cb, internal_error_table);
	tt_assert(port1);
	port2 = regress_get_dnsserver(base, &portnum2, NULL,
	    regress_dns_server_cb, reissue_table);
	tt_assert(port2);
	evutil_snprintf(buf1, sizeof(buf1), "127.0.0.1:%d", (int)portnum1);
	evutil_snprintf(buf2, sizeof(buf2), "127.0.0.1:%d", (int)portnum2);

	dns = evdns_base_new(base, 0);
	tt_assert(!evdns_base_nameserver_ip_add(dns, buf1));
	tt_assert(! evdns_base_set_option(dns, "timeout:", "0.3"));
	tt_assert(! evdns_base_set_option(dns, "max-timeouts:", "2"));
	tt_assert(! evdns_base_set_option(dns, "attempts:", "5"));

	memset(&r1, 0, sizeof(r1));
	evdns_base_resolve_ipv4(dns, "foof.example.com", 0,
	    generic_dns_callback, &r1);

	/* Add this after, so that we are sure to get a reissue. */
	tt_assert(!evdns_base_nameserver_ip_add(dns, buf2));

	n_replies_left = 1;
	exit_base = base;

	event_base_dispatch(base);
	tt_int_op(r1.result, ==, DNS_ERR_NONE);
	tt_int_op(r1.type, ==, DNS_IPv4_A);
	tt_int_op(r1.count, ==, 1);
	tt_int_op(((ev_uint32_t*)r1.addrs)[0], ==, htonl(0xf00ff00f));

	/* Make sure we dropped at least once. */
	tt_int_op(internal_error_table[0].seen, >, 0);

end:
	if (dns)
		evdns_base_free(dns, 0);
	if (port1)
		evdns_close_server_port(port1);
	if (port2)
		evdns_close_server_port(port2);
}
Exemplo n.º 4
0
evutil_addrinfo* make_addrinfo_(const char* address, ev_uint16_t port) {
    struct evutil_addrinfo *ai = NULL;

    struct evutil_addrinfo hints;
    char strport[NI_MAXSERV];
    int ai_result;

    memset(&hints, 0, sizeof(hints));
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    /* turn NULL hostname into INADDR_ANY, and skip looking up any address
     * types we don't have an interface to connect to. */
    hints.ai_flags = EVUTIL_AI_PASSIVE|EVUTIL_AI_ADDRCONFIG;
    evutil_snprintf(strport, sizeof(strport), "%d", port);
    if ((ai_result = evutil_getaddrinfo(address, strport, &hints, &ai))
            != 0) {
        /*
           if (ai_result == EVUTIL_EAI_SYSTEM) {
           event_warn("getaddrinfo");
           } else {
           event_warnx("getaddrinfo: %s",
           evutil_gai_strerror(ai_result));
           }
           */
        return (NULL);
    }

    return (ai);
}
Exemplo n.º 5
0
void diplay_socket_information(struct evhttp_bound_socket *handle) {
	struct sockaddr_storage ss;
	evutil_socket_t fd;
	ev_socklen_t socklen = sizeof(ss);
	char addrbuf[128];
	void *inaddr;
	const char *addr;
	int got_port = -1;

	fd = evhttp_bound_socket_get_fd(handle);
	memset(&ss, 0, sizeof(ss));
	if (getsockname(fd, (struct sockaddr *)&ss, &socklen)) {
		perror("getsockname() failed");
		exit(1);
	}
	if (ss.ss_family == AF_INET) {
		got_port = ntohs(((struct sockaddr_in*)&ss)->sin_port);
		inaddr = &((struct sockaddr_in*)&ss)->sin_addr;
	} else {
		fprintf(stderr, "Weird address family %d\n", ss.ss_family);
		exit(1);
	}
	addr = evutil_inet_ntop(ss.ss_family, inaddr, addrbuf, sizeof(addrbuf));
	if (addr) {
		printf("Listening on %s:%d\n", addr, got_port);
		evutil_snprintf(uri_root, sizeof(uri_root),
			"http://%s:%d",addr,got_port);
	} else {
		fprintf(stderr, "evutil_inet_ntop failed\n");
		exit(1);
	}
}
Exemplo n.º 6
0
int
bufferevent_socket_connect_hostname(struct bufferevent *bev,
    struct evdns_base *evdns_base, int family, const char *hostname, int port)
{
	char portbuf[10];
	struct evutil_addrinfo hint;
	int err;

	if (family != AF_INET && family != AF_INET6 && family != AF_UNSPEC)
		return -1;
	if (port < 1 || port > 65535)
		return -1;

	evutil_snprintf(portbuf, sizeof(portbuf), "%d", port);

	memset(&hint, 0, sizeof(hint));
	hint.ai_family = family;
	hint.ai_protocol = IPPROTO_TCP;
	hint.ai_socktype = SOCK_STREAM;

	bufferevent_suspend_write(bev, BEV_SUSPEND_LOOKUP);
	bufferevent_suspend_read(bev, BEV_SUSPEND_LOOKUP);

	bufferevent_incref(bev);
	err = evutil_getaddrinfo_async(evdns_base, hostname, portbuf,
	    &hint, bufferevent_connect_getaddrinfo_cb, bev);

	if (err == 0) {
		return 0;
	} else {
		bufferevent_unsuspend_write(bev, BEV_SUSPEND_LOOKUP);
		bufferevent_unsuspend_read(bev, BEV_SUSPEND_LOOKUP);
		return -1;
	}
}
Exemplo n.º 7
0
static void
test_evutil_snprintf(void *ptr)
{
	char buf[16];
	int r;
	r = evutil_snprintf(buf, sizeof(buf), "%d %d", 50, 100);
	tt_str_op(buf, ==, "50 100");
	tt_int_op(r, ==, 6);

	r = evutil_snprintf(buf, sizeof(buf), "longish %d", 1234567890);
	tt_str_op(buf, ==, "longish 1234567");
	tt_int_op(r, ==, 18);

      end:
	;
}
Exemplo n.º 8
0
static int
sockaddr_from_ip_and_port(struct sockaddr_storage * const sockaddr,
                          ev_socklen_t * const sockaddr_len_p,
                          const char * const ip, const char * const port,
                          const char * const error_msg)
{
    char   sockaddr_port[INET6_ADDRSTRLEN + sizeof "[]:65535"];
    int    sockaddr_len_int;
    char  *pnt;
    _Bool  has_column = 0;
    _Bool  has_columns = 0;
    _Bool  has_brackets = *ip == '[';

    if ((pnt = strchr(ip, ':')) != NULL) {
        has_column = 1;
        if (strchr(pnt + 1, ':') != NULL) {
            has_columns = 1;
        }
    }
    sockaddr_len_int = (int) sizeof *sockaddr;
    if ((has_brackets != 0 || has_column != has_columns) &&
        evutil_parse_sockaddr_port(ip, (struct sockaddr *) sockaddr,
                                   &sockaddr_len_int) == 0) {
        *sockaddr_len_p = (ev_socklen_t) sockaddr_len_int;
        return 0;
    }
    if (has_columns != 0 && has_brackets == 0) {
        evutil_snprintf(sockaddr_port, sizeof sockaddr_port, "[%s]:%s",
                        ip, port);
    } else {
        evutil_snprintf(sockaddr_port, sizeof sockaddr_port, "%s:%s",
                        ip, port);
    }
    sockaddr_len_int = (int) sizeof *sockaddr;
    if (evutil_parse_sockaddr_port(sockaddr_port, (struct sockaddr *) sockaddr,
                                   &sockaddr_len_int) != 0) {
        logger(NULL, LOG_ERR, "%s: %s", error_msg, sockaddr_port);
        *sockaddr_len_p = (ev_socklen_t) 0U;

        return -1;
    }
    *sockaddr_len_p = (ev_socklen_t) sockaddr_len_int;

    return 0;
}
Exemplo n.º 9
0
static void
dns_search_test(void *arg)
{
	struct basic_test_data *data = arg;
	struct event_base *base = data->base;
	struct evdns_base *dns = NULL;
	ev_uint16_t portnum = 0;
	char buf[64];

	struct generic_dns_callback_result r[8];

	tt_assert(regress_dnsserver(base, &portnum, search_table));
	evutil_snprintf(buf, sizeof(buf), "127.0.0.1:%d", (int)portnum);

	dns = evdns_base_new(base, 0);
	tt_assert(!evdns_base_nameserver_ip_add(dns, buf));

	evdns_base_search_add(dns, "a.example.com");
	evdns_base_search_add(dns, "b.example.com");
	evdns_base_search_add(dns, "c.example.com");

	n_replies_left = sizeof(r)/sizeof(r[0]);
	exit_base = base;

	evdns_base_resolve_ipv4(dns, "host", 0, generic_dns_callback, &r[0]);
	evdns_base_resolve_ipv4(dns, "host2", 0, generic_dns_callback, &r[1]);
	evdns_base_resolve_ipv4(dns, "host", DNS_NO_SEARCH, generic_dns_callback, &r[2]);
	evdns_base_resolve_ipv4(dns, "host2", DNS_NO_SEARCH, generic_dns_callback, &r[3]);
	evdns_base_resolve_ipv4(dns, "host3", 0, generic_dns_callback, &r[4]);
	evdns_base_resolve_ipv4(dns, "hostn.a.example.com", DNS_NO_SEARCH, generic_dns_callback, &r[5]);
	evdns_base_resolve_ipv4(dns, "hostn.b.example.com", DNS_NO_SEARCH, generic_dns_callback, &r[6]);
	evdns_base_resolve_ipv4(dns, "hostn.c.example.com", DNS_NO_SEARCH, generic_dns_callback, &r[7]);

	event_base_dispatch(base);

	tt_int_op(r[0].type, ==, DNS_IPv4_A);
	tt_int_op(r[0].count, ==, 1);
	tt_int_op(((ev_uint32_t*)r[0].addrs)[0], ==, htonl(0x0b16212c));
	tt_int_op(r[1].type, ==, DNS_IPv4_A);
	tt_int_op(r[1].count, ==, 1);
	tt_int_op(((ev_uint32_t*)r[1].addrs)[0], ==, htonl(0xc8640064));
	tt_int_op(r[2].result, ==, DNS_ERR_NOTEXIST);
	tt_int_op(r[3].result, ==, DNS_ERR_NOTEXIST);
	tt_int_op(r[4].result, ==, DNS_ERR_NOTEXIST);
	tt_int_op(r[5].result, ==, DNS_ERR_NODATA);
	tt_int_op(r[5].ttl, ==, 42);
	tt_int_op(r[6].result, ==, DNS_ERR_NOTEXIST);
	tt_int_op(r[6].ttl, ==, 42);
	tt_int_op(r[7].result, ==, DNS_ERR_NODATA);
	tt_int_op(r[7].ttl, ==, 0);

end:
	if (dns)
		evdns_base_free(dns, 0);

	regress_clean_dnsserver();
}
Exemplo n.º 10
0
Arquivo: conn.c Projeto: 0xffea/shim
int
conn_connect_bufferevent(struct bufferevent *bev, struct evdns_base *dns,
			 int family, const char *name, int port,
			 conn_connectcb conncb, void *arg)
{
	struct conninfo *info;
	int rv = -1;
	

	info = mem_calloc(1, sizeof(*info));
	info->bev = bev;
	info->on_connect = conncb;
	info->cbarg = arg;
	info->connecting = 1;
	info->socks = use_socks;

	bufferevent_setcb(bev, conn_readcb, NULL, conn_errorcb, info);
	if (use_socks != SOCKS_NONE) {
		info->host = mem_strdup(name);
		info->port = port;
		if (use_socks == SOCKS_4a) {
			rv = bufferevent_socket_connect(bev,
					(struct sockaddr*)&socks_addr,
					socks_addr_len);
			return rv;
		}
#ifndef DISABLE_DIRECT_CONNECTIONS
		else {
			struct evutil_addrinfo hint;
			char portstr[NI_MAXSERV];

			evutil_snprintf(portstr, sizeof(portstr), "%d", port);
			memset(&hint, 0, sizeof(hint));
			hint.ai_family = AF_INET;
			hint.ai_protocol = IPPROTO_TCP;
			hint.ai_socktype = SOCK_STREAM;

			evdns_getaddrinfo(dns, name, portstr, &hint,
				          socks_resolvecb, info);
			return 0;
		}
#endif
	}
#ifdef DISABLE_DIRECT_CONNECTIONS
	{
		const char *msg;
		msg = "Direct connections disabled, but I have no SOCKS 4a "
		      "proxy to connect to!";
		log_error("conn: %s", msg);
		finish_connection(info, 0, msg);
	}
#else
	rv =  bufferevent_socket_connect_hostname(bev, dns, family, name, port);
#endif

	return rv;
}
Exemplo n.º 11
0
Arquivo: hub.c Projeto: nizox/hub
void
hub_add_peer(struct hub *hub, char const *address)
{
  int e;
  char *hostname, *ptr, port[6];
  struct evutil_addrinfo hints, *answer = NULL;
  struct peer *peer;

  if ((ptr = strchr(address, ':')))
  {
    hostname = calloc(ptr - address + 1, sizeof(*hostname));
    if (!hostname) err(1, NULL);
    strncpy(hostname, address, ptr - address);
    strncpy(port, ptr + 1, sizeof(port));
  }
  else
  {
    hostname = (char *) address;
    evutil_snprintf(port, sizeof(port), "%hi", hub->port);
  }

  memset(&hints, 0, sizeof(hints));
  hints.ai_family = AF_INET;
  hints.ai_socktype = SOCK_DGRAM;
  hints.ai_flags = EVUTIL_AI_ADDRCONFIG;

  if ((e = evutil_getaddrinfo(hostname, port, &hints, &answer)) < 0)
  {
    fprintf(stderr, "Error while resolving '%s': %s", hostname,
        evutil_gai_strerror(e));
    return;
  }

  if (!answer)
    return;

  peer = calloc(1, sizeof(*peer));
  if (!peer) err(1, NULL);
  peer->name = address;

  peer->addrlen = answer->ai_addrlen;
  peer->addr = malloc(peer->addrlen);
  if (!peer->addr) err(1, NULL);
  memcpy(peer->addr, answer->ai_addr, peer->addrlen);

  peer->next = hub->peers;
  hub->peers = peer;

  evutil_freeaddrinfo(answer);
}
Exemplo n.º 12
0
Arquivo: util.c Projeto: Phoul/shim
const char *
format_addr(const struct sockaddr *addr)
{
	const char *r = NULL;
	static char buf[256];
	char tmp[256];

	if (addr->sa_family == AF_INET) {	
		struct sockaddr_in *sin = (struct sockaddr_in *)addr;
		r = evutil_inet_ntop(AF_INET, &sin->sin_addr, tmp,
		            	     sizeof(tmp));
		if (r) {
			if (sin->sin_port)
				evutil_snprintf(buf, sizeof(buf), "%s:%hu",
						tmp, ntohs(sin->sin_port));
			else
				strcpy(buf, tmp);
		}
	} else if (addr->sa_family == AF_INET6) {
		struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)addr;
		r = evutil_inet_ntop(AF_INET6, &sin6->sin6_addr, tmp,
				     sizeof(tmp));
		if (r) {
			if (sin6->sin6_port)
				evutil_snprintf(buf, sizeof(buf), "[%s]:%hu",
						tmp, ntohs(sin6->sin6_port));
			else
				strcpy(buf, tmp);
		}
	}

	if (!r)
		strcpy(buf, "???"); // XXX: Is this really a reasonable thing to return?
	
	return buf;
}
Exemplo n.º 13
0
static int http_get_address(struct evhttp_bound_socket *handle, char *buffer, int buflen)
{
    /* Extract and display the address we're listening on. */
    struct sockaddr_storage ss;
    evutil_socket_t fd;
    ev_socklen_t socklen = sizeof(ss);
    char addrbuf[128];
    void *inaddr;
    const char *addr;
    int got_port = -1;

    memset(&ss, 0, sizeof(ss));

    fd = evhttp_bound_socket_get_fd(handle);
    if (getsockname(fd, (struct sockaddr *)&ss, &socklen))
    {
        return ERROR_FAIL;
    }

    if (ss.ss_family == AF_INET)
    {
        got_port = ntohs(((struct sockaddr_in*)&ss)->sin_port);
        inaddr = &((struct sockaddr_in*)&ss)->sin_addr;
    }
    else if (ss.ss_family == AF_INET6)
    {
        got_port = ntohs(((struct sockaddr_in6*)&ss)->sin6_port);
        inaddr = &((struct sockaddr_in6*)&ss)->sin6_addr;
    }
    else
    {
        fprintf(stderr, "Unexpected address family %d\n", ss.ss_family);
        return ERROR_FAIL;
    }

    addr = evutil_inet_ntop(ss.ss_family, inaddr, addrbuf, sizeof(addrbuf));
    if (addr)
    {
        evutil_snprintf(buffer, buflen, "http://%s:%d", addr,got_port);
    }
    else
    {
        fprintf(stderr, "evutil_inet_ntop failed\n");
        return ERROR_FAIL;
    }

    return S_OK;
}
Exemplo n.º 14
0
static void
dns_search_test(void *arg)
{
	struct basic_test_data *data = arg;
	struct event_base *base = data->base;
	struct evdns_base *dns = NULL;
	ev_uint16_t portnum = 0;
	char buf[64];

	struct generic_dns_callback_result r1, r2, r3, r4, r5;

	tt_assert(regress_dnsserver(base, &portnum, search_table));
	evutil_snprintf(buf, sizeof(buf), "127.0.0.1:%d", (int)portnum);

	dns = evdns_base_new(base, 0);
	tt_assert(!evdns_base_nameserver_ip_add(dns, buf));

	evdns_base_search_add(dns, "a.example.com");
	evdns_base_search_add(dns, "b.example.com");
	evdns_base_search_add(dns, "c.example.com");

	n_replies_left = 5;
	exit_base = base;

	evdns_base_resolve_ipv4(dns, "host", 0, generic_dns_callback, &r1);
	evdns_base_resolve_ipv4(dns, "host2", 0, generic_dns_callback, &r2);
	evdns_base_resolve_ipv4(dns, "host", DNS_NO_SEARCH, generic_dns_callback, &r3);
	evdns_base_resolve_ipv4(dns, "host2", DNS_NO_SEARCH, generic_dns_callback, &r4);
	evdns_base_resolve_ipv4(dns, "host3", 0, generic_dns_callback, &r5);

	event_base_dispatch(base);

	tt_int_op(r1.type, ==, DNS_IPv4_A);
	tt_int_op(r1.count, ==, 1);
	tt_int_op(((ev_uint32_t*)r1.addrs)[0], ==, htonl(0x0b16212c));
	tt_int_op(r2.type, ==, DNS_IPv4_A);
	tt_int_op(r2.count, ==, 1);
	tt_int_op(((ev_uint32_t*)r2.addrs)[0], ==, htonl(0xc8640064));
	tt_int_op(r3.result, ==, DNS_ERR_NOTEXIST);
	tt_int_op(r4.result, ==, DNS_ERR_NOTEXIST);
	tt_int_op(r5.result, ==, DNS_ERR_NOTEXIST);

end:
	if (dns)
		evdns_base_free(dns, 0);

	regress_clean_dnsserver();
}
Exemplo n.º 15
0
static void ts_conn_host(const char *hostname, unsigned short port, struct ts_session *session) {
    struct evutil_addrinfo hints;
    memset(&hints, 0, sizeof(hints));
    hints.ai_family = AF_UNSPEC;
    /* Unless we specify a socktype, we'll get at least two entries for
     * each address: one for TCP and one for UDP. That's not what we
     * want. */
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;
    char port_buf[6];
    evutil_snprintf(port_buf, sizeof(port_buf), "%d", (int)port);
    /* We will run a non-blocking dns resolve */
    struct ts_server_ctx *ctx = session->ctx;
    ts_log_d("start to resolve host %s", hostname);
    evdns_getaddrinfo(ctx->dnsbase, hostname, port_buf,
        &hints, ts_dns_resolved, session);
}
Exemplo n.º 16
0
char *
path_from_app_folder(const char *file_name)
{
    WCHAR       utf16_buf[16383 + 1];
    char        utf8_buf[65535 + 1];
    char       *utf8_buf_copy;
    char       *chr_revpathsep;
    const char *chr_column;
    const char *chr_pathsep;
    size_t      utf8_buf_copy_len;
    DWORD       utf16_buf_len = (DWORD) sizeof utf16_buf;
    int         utf8_buf_len = (int) sizeof utf8_buf;

    assert(file_name != NULL);
    if (((chr_pathsep = strchr(file_name, '/')) != NULL ||
         (chr_pathsep = strchr(file_name, '\\')) != NULL) &&
        (chr_pathsep == file_name ||
         ((chr_column = strchr(file_name, ':')) != NULL &&
           chr_column - file_name < chr_pathsep - file_name))) {
        return strdup(file_name);
    }
    if ((utf16_buf_len =
         GetModuleFileNameW(NULL, utf16_buf, utf16_buf_len - 1)) <= (DWORD) 0) {
        return NULL;
    }
    utf16_buf[utf16_buf_len] = (WCHAR) 0;
    utf8_buf_len = WideCharToMultiByte(CP_UTF8, 0, utf16_buf, -1, utf8_buf,
                                       utf8_buf_len, NULL, NULL);
    if (utf8_buf_len <= 0) {
        return NULL;
    }
    assert(utf8_buf[utf8_buf_len - 1] == 0);
    if ((chr_revpathsep = strrchr(utf8_buf, '/')) == NULL &&
        (chr_revpathsep = strrchr(utf8_buf, '\\')) == NULL) {
        return strdup(file_name);
    }
    *(chr_revpathsep + 1U) = 0;
    utf8_buf_copy_len = strlen(utf8_buf) + strlen(file_name) + (size_t) 1U;
    if ((utf8_buf_copy = malloc(utf8_buf_copy_len)) == NULL) {
        return NULL;
    }
    evutil_snprintf(utf8_buf_copy, utf8_buf_copy_len, "%s%s",
                    utf8_buf, file_name);

    return utf8_buf_copy;
}
Exemplo n.º 17
0
Arquivo: log.c Projeto: Henauxg/minix
static void
_warn_helper(int severity, const char *errstr, const char *fmt, va_list ap)
{
	char buf[1024];
	size_t len;

	if (fmt != NULL)
		evutil_vsnprintf(buf, sizeof(buf), fmt, ap);
	else
		buf[0] = '\0';

	if (errstr) {
		len = strlen(buf);
		if (len < sizeof(buf) - 3) {
			evutil_snprintf(buf + len, sizeof(buf) - len, ": %s", errstr);
		}
	}

	event_log(severity, buf);
}
Exemplo n.º 18
0
static void
dns_search_cancel_test(void *arg)
{
	struct basic_test_data *data = arg;
	struct event_base *base = data->base;
	struct evdns_base *dns = NULL;
	struct evdns_server_port *port = NULL;
	ev_uint16_t portnum = 0;
	struct generic_dns_callback_result r1;
	char buf[64];

	port = regress_get_dnsserver(base, &portnum, NULL,
	    search_cancel_server_cb, NULL);
	tt_assert(port);
	evutil_snprintf(buf, sizeof(buf), "127.0.0.1:%d", (int)portnum);

	dns = evdns_base_new(base, 0);
	tt_assert(!evdns_base_nameserver_ip_add(dns, buf));

	evdns_base_search_add(dns, "a.example.com");
	evdns_base_search_add(dns, "b.example.com");
	evdns_base_search_add(dns, "c.example.com");
	evdns_base_search_add(dns, "d.example.com");

	exit_base = base;
	request_count = 3;
	n_replies_left = 1;

	current_req = evdns_base_resolve_ipv4(dns, "host", 0,
					generic_dns_callback, &r1);
	event_base_dispatch(base);

	tt_int_op(r1.result, ==, DNS_ERR_CANCEL);

end:
	if (port)
		evdns_close_server_port(port);
	if (dns)
		evdns_base_free(dns, 0);
}
Exemplo n.º 19
0
static int
init_tz(void)
{
    static char  default_tz_for_putenv[] = "TZ=UTC+00:00";
    char         stbuf[10U];
    struct tm   *tm;
    time_t       now;

    tzset();
    time(&now);
    if ((tm = localtime(&now)) != NULL &&
        strftime(stbuf, sizeof stbuf, "%z", tm) == (size_t) 5U) {
        evutil_snprintf(default_tz_for_putenv, sizeof default_tz_for_putenv,
                        "TZ=UTC%c%c%c:%c%c", (*stbuf == '-' ? '+' : '-'),
                        stbuf[1], stbuf[2], stbuf[3], stbuf[4]);
    }
    putenv(default_tz_for_putenv);
    (void) localtime(&now);
    (void) gmtime(&now);

    return 0;
}
Exemplo n.º 20
0
static void
dns_inflight_test(void *arg)
{
	struct basic_test_data *data = arg;
	struct event_base *base = data->base;
	struct evdns_base *dns = NULL;
	ev_uint16_t portnum = 0;
	char buf[64];

	struct generic_dns_callback_result r[20];
	int i;

	tt_assert(regress_dnsserver(base, &portnum, reissue_table));
	evutil_snprintf(buf, sizeof(buf), "127.0.0.1:%d", (int)portnum);

	dns = evdns_base_new(base, 0);
	tt_assert(!evdns_base_nameserver_ip_add(dns, buf));
	tt_assert(! evdns_base_set_option(dns, "max-inflight:", "3"));
	tt_assert(! evdns_base_set_option(dns, "randomize-case:", "0"));

	for (i=0;i<20;++i)
		evdns_base_resolve_ipv4(dns, "foof.example.com", 0, generic_dns_callback, &r[i]);

	n_replies_left = 20;
	exit_base = base;

	event_base_dispatch(base);

	for (i=0;i<20;++i) {
		tt_int_op(r[i].type, ==, DNS_IPv4_A);
		tt_int_op(r[i].count, ==, 1);
		tt_int_op(((ev_uint32_t*)r[i].addrs)[0], ==, htonl(0xf00ff00f));
	}

end:
	if (dns)
		evdns_base_free(dns, 0);
	regress_clean_dnsserver();
}
Exemplo n.º 21
0
void
dnscrypt_key_to_fingerprint(char fingerprint[80U], const uint8_t * const key)
{
    const size_t fingerprint_size = 80U;
    size_t       fingerprint_pos = (size_t) 0U;
    size_t       key_pos = (size_t) 0U;

    COMPILER_ASSERT(crypto_box_PUBLICKEYBYTES == 32U);
    COMPILER_ASSERT(crypto_box_SECRETKEYBYTES == 32U);
    for (;;) {
        assert(fingerprint_size > fingerprint_pos);
        evutil_snprintf(&fingerprint[fingerprint_pos],
                        fingerprint_size - fingerprint_pos, "%02X%02X",
                        key[key_pos], key[key_pos + 1U]);
        key_pos += 2U;
        if (key_pos >= crypto_box_PUBLICKEYBYTES) {
            break;
        }
        fingerprint[fingerprint_pos + 4U] = ':';
        fingerprint_pos += 5U;
    }
}
Exemplo n.º 22
0
Arquivo: log.c Projeto: TomCN7/Event
void
event_logv_(int severity, const char *errstr, const char *fmt, va_list ap)
{
	char buf[1024];
	size_t len;

	if (severity == EVENT_LOG_DEBUG && !event_debug_get_logging_mask_())
		return;

	if (fmt != NULL)
		evutil_vsnprintf(buf, sizeof(buf), fmt, ap);
	else
		buf[0] = '\0';

	if (errstr) {
		len = strlen(buf);
		if (len < sizeof(buf) - 3) {
			evutil_snprintf(buf + len, sizeof(buf) - len, ": %s", errstr);
		}
	}

	event_log(severity, buf);
}
Exemplo n.º 23
0
Arquivo: conn.c Projeto: ioerror/shim
void socks_resolvecb(int result, struct evutil_addrinfo *ai, void *arg)
{
	struct conninfo *info = arg;

	if (result) {
		char buf[256];
		evutil_snprintf(buf, sizeof(buf), "DNS Failure: %s",
				evutil_gai_strerror(result));
		finish_connection(info, 0, buf);
	} else {
		log_debug("conn: socks resolve %s",
			  format_addr(ai->ai_addr));
		assert(ai->ai_addrlen <= sizeof(info->addr));
		memcpy(&info->addr, ai->ai_addr, ai->ai_addrlen);
		info->addr_len = ai->ai_addrlen;
		bufferevent_socket_connect(info->bev,
					   (struct sockaddr*)&socks_addr,
					   socks_addr_len);
	}

	if (ai)
		evutil_freeaddrinfo(ai);
}
Exemplo n.º 24
0
static char * evdns_get_default_hosts_filename(void)
{
#ifdef WIN32
	/* Windows is a little coy about where it puts its configuration
	 * files.  Sure, they're _usually_ in C:\windows\system32, but
	 * there's no reason in principle they couldn't be in
	 * W:\hoboken chicken emergency\
	 */
	char path[MAX_PATH+1];
	static const char hostfile[] = "\\drivers\\etc\\hosts";
	char *path_out;
	size_t len_out;

	if (! SHGetSpecialFolderPathA(NULL, path, CSIDL_SYSTEM, 0))
		return NULL;
	len_out = strlen(path)+strlen(hostfile);
	path_out = (char *)malloc(len_out+1);
	evutil_snprintf(path_out, len_out+1, "%s%s", path, hostfile);
	return path_out;
#else
	return mm_strdup("/etc/hosts");
#endif
}
Exemplo n.º 25
0
/* Create the headers needed for an outgoing HTTP request, adds them to
 * the request's header list, and writes the request line to the
 * connection's output buffer.
 */
static void
evhttp_make_header_request(struct evhttp_connection *evcon,
    struct evhttp_request *req)
{
	const char *method;

	evhttp_remove_header(req->output_headers, "Proxy-Connection");

	/* Generate request line */
	method = evhttp_method(req->type);
	evbuffer_add_printf(bufferevent_get_output(evcon->bufev),
	    "%s %s HTTP/%d.%d\r\n",
	    method, req->uri, req->major, req->minor);

	/* Add the content length on a post or put request if missing */
	if ((req->type == EVHTTP_REQ_POST || req->type == EVHTTP_REQ_PUT) &&
	    evhttp_find_header(req->output_headers, "Content-Length") == NULL){
		char size[22];
		evutil_snprintf(size, sizeof(size), EV_SIZE_FMT,
		    EV_SIZE_ARG(evbuffer_get_length(req->output_buffer)));
		evhttp_add_header(req->output_headers, "Content-Length", size);
	}
}
Exemplo n.º 26
0
Arquivo: conn.c Projeto: 0xffea/shim
int
conn_set_socks_server(const char *name, int port, enum socks_ver ver)
{
	int ret;
	int rv = -1;	
	struct evutil_addrinfo *ai = NULL;
	struct evutil_addrinfo hint;
	char portstr[NI_MAXSERV];

	assert(ver != SOCKS_NONE);

	evutil_snprintf(portstr, sizeof(portstr), "%d", port);
	memset(&hint, 0, sizeof(hint));
	hint.ai_family = AF_UNSPEC;
	hint.ai_protocol = IPPROTO_TCP;
	hint.ai_socktype = SOCK_STREAM;
	hint.ai_flags = EVUTIL_AI_ADDRCONFIG;

	ret = evutil_getaddrinfo(name, portstr, &hint, &ai);
	if (!ret) {
		rv = 0;
		memset(&socks_addr, 0, sizeof(socks_addr));
		memcpy(&socks_addr, ai->ai_addr, ai->ai_addrlen);
		socks_addr_len = ai->ai_addrlen;
		use_socks = ver;
		log_notice("conn: socks server set to %s",
			   format_addr((struct sockaddr*)&socks_addr));
	} else {
		log_error("conn: can't resolve socks server %s: %s",
			  name, evutil_gai_strerror(ret));
	}
	
	if (ai)
		evutil_freeaddrinfo(ai);

	return rv;
}
Exemplo n.º 27
0
static int
fake_getnameinfo(const struct sockaddr *sa, size_t salen, char *host,
	size_t hostlen, char *serv, size_t servlen, int flags)
{
	struct sockaddr_in *sin = (struct sockaddr_in *)sa;

	if (serv != NULL) {
		char tmpserv[16];
		evutil_snprintf(tmpserv, sizeof(tmpserv),
		    "%d", ntohs(sin->sin_port));
		if (strlcpy(serv, tmpserv, servlen) >= servlen)
			return (-1);
	}

	if (host != NULL) {
		if (flags & NI_NUMERICHOST) {
			if (strlcpy(host, inet_ntoa(sin->sin_addr),
			    hostlen) >= hostlen)
				return (-1);
			else
				return (0);
		} else {
			struct hostent *hp;
			hp = gethostbyaddr((char *)&sin->sin_addr,
			    sizeof(struct in_addr), AF_INET);
			if (hp == NULL)
				return (-2);

			if (strlcpy(host, hp->h_name, hostlen) >= hostlen)
				return (-1);
			else
				return (0);
		}
	}
	return (0);
}
Exemplo n.º 28
0
static void
test_bufferevent_connect_hostname(void *arg)
{
	struct basic_test_data *data = arg;
	struct evconnlistener *listener = NULL;
	struct bufferevent *be1=NULL, *be2=NULL, *be3=NULL, *be4=NULL, *be5=NULL;
	int be1_outcome=0, be2_outcome=0, be3_outcome=0, be4_outcome=0,
	    be5_outcome=0;
	struct evdns_base *dns=NULL;
	struct evdns_server_port *port=NULL;
	evutil_socket_t server_fd=-1;
	struct sockaddr_in sin;
	int listener_port=-1;
	ev_uint16_t dns_port=0;
	int n_accept=0, n_dns=0;
	char buf[128];

	be_connect_hostname_base = data->base;

	/* Bind an address and figure out what port it's on. */
	memset(&sin, 0, sizeof(sin));
	sin.sin_family = AF_INET;
	sin.sin_addr.s_addr = htonl(0x7f000001); /* 127.0.0.1 */
	sin.sin_port = 0;
	listener = evconnlistener_new_bind(data->base, nil_accept_cb,
	    &n_accept,
	    LEV_OPT_REUSEABLE|LEV_OPT_CLOSE_ON_EXEC,
	    -1, (struct sockaddr *)&sin, sizeof(sin));
	listener_port = regress_get_socket_port(
		evconnlistener_get_fd(listener));

	port = regress_get_dnsserver(data->base, &dns_port, NULL,
	    be_getaddrinfo_server_cb, &n_dns);
	tt_assert(port);
	tt_int_op(dns_port, >=, 0);

	/* Start an evdns_base that uses the server as its resolver. */
	dns = evdns_base_new(data->base, 0);
	evutil_snprintf(buf, sizeof(buf), "127.0.0.1:%d", dns_port);
	evdns_base_nameserver_ip_add(dns, buf);

	/* Now, finally, at long last, launch the bufferevents.  One should do
	 * a failing lookup IP, one should do a successful lookup by IP,
	 * and one should do a successful lookup by hostname. */
	be1 = bufferevent_socket_new(data->base, -1, BEV_OPT_CLOSE_ON_FREE);
	be2 = bufferevent_socket_new(data->base, -1, BEV_OPT_CLOSE_ON_FREE);
	be3 = bufferevent_socket_new(data->base, -1, BEV_OPT_CLOSE_ON_FREE);
	be4 = bufferevent_socket_new(data->base, -1, BEV_OPT_CLOSE_ON_FREE);
	be5 = bufferevent_socket_new(data->base, -1, BEV_OPT_CLOSE_ON_FREE);

	bufferevent_setcb(be1, NULL, NULL, be_connect_hostname_event_cb,
	    &be1_outcome);
	bufferevent_setcb(be2, NULL, NULL, be_connect_hostname_event_cb,
	    &be2_outcome);
	bufferevent_setcb(be3, NULL, NULL, be_connect_hostname_event_cb,
	    &be3_outcome);
	bufferevent_setcb(be4, NULL, NULL, be_connect_hostname_event_cb,
	    &be4_outcome);
	bufferevent_setcb(be5, NULL, NULL, be_connect_hostname_event_cb,
	    &be5_outcome);

	/* Launch an async resolve that will fail. */
	tt_assert(!bufferevent_socket_connect_hostname(be1, dns, AF_INET,
		"nosuchplace.example.com", listener_port));
	/* Connect to the IP without resolving. */
	tt_assert(!bufferevent_socket_connect_hostname(be2, dns, AF_INET,
		"127.0.0.1", listener_port));
	/* Launch an async resolve that will succeed. */
	tt_assert(!bufferevent_socket_connect_hostname(be3, dns, AF_INET,
		"nobodaddy.example.com", listener_port));
	/* Use the blocking resolver.  This one will fail if your resolver
	 * can't resolve localhost to 127.0.0.1 */
	tt_assert(!bufferevent_socket_connect_hostname(be4, NULL, AF_INET,
		"localhost", listener_port));
	/* Use the blocking resolver with a nonexistent hostname. */
	tt_assert(!bufferevent_socket_connect_hostname(be5, NULL, AF_INET,
		"nonesuch.nowhere.example.com", 80));

	event_base_dispatch(data->base);

	tt_int_op(be1_outcome, ==, BEV_EVENT_ERROR);
	tt_int_op(be2_outcome, ==, BEV_EVENT_CONNECTED);
	tt_int_op(be3_outcome, ==, BEV_EVENT_CONNECTED);
	tt_int_op(be4_outcome, ==, BEV_EVENT_CONNECTED);
	tt_int_op(be5_outcome, ==, BEV_EVENT_ERROR);

	tt_int_op(n_accept, ==, 3);
	tt_int_op(n_dns, ==, 2);

end:
	if (listener)
		evconnlistener_free(listener);
	if (server_fd>=0)
		EVUTIL_CLOSESOCKET(server_fd);
	if (port)
                evdns_close_server_port(port);
	if (dns)
		evdns_base_free(dns, 0);
	if (be1)
		bufferevent_free(be1);
	if (be2)
		bufferevent_free(be2);
	if (be3)
		bufferevent_free(be3);
	if (be4)
		bufferevent_free(be4);
	if (be5)
		bufferevent_free(be5);
}
Exemplo n.º 29
0
static void
test_evutil_log(void *ptr)
{
	evutil_socket_t fd = -1;
	char buf[128];

	event_set_log_callback(logfn);
	event_set_fatal_callback(fatalfn);
#define RESET() do {				\
		logsev = 0;	\
		if (logmsg) free(logmsg);	\
		logmsg = NULL;			\
	} while (0)
#define LOGEQ(sev,msg) do {			\
		tt_int_op(logsev,==,sev);	\
		tt_assert(logmsg != NULL);	\
		tt_str_op(logmsg,==,msg);	\
	} while (0)

#ifdef CAN_CHECK_ERR
	/* We need to disable these tests for now.  Previously, the logging
	 * module didn't enforce the requirement that a fatal callback
	 * actually exit.  Now, it exits no matter what, so if we wan to
	 * reinstate these tests, we'll need to fork for each one. */
	check_error_logging(errx_fn, 2, EVENT_LOG_ERR,
	    "Fatal error; too many kumquats (5)");
	RESET();
#endif

	event_warnx("Far too many %s (%d)", "wombats", 99);
	LOGEQ(EVENT_LOG_WARN, "Far too many wombats (99)");
	RESET();

	event_msgx("Connecting lime to coconut");
	LOGEQ(EVENT_LOG_MSG, "Connecting lime to coconut");
	RESET();

	event_debug(("A millisecond passed! We should log that!"));
#ifdef USE_DEBUG
	LOGEQ(EVENT_LOG_DEBUG, "A millisecond passed! We should log that!");
#else
	tt_int_op(logsev,==,0);
	tt_ptr_op(logmsg,==,NULL);
#endif
	RESET();

	/* Try with an errno. */
	errno = ENOENT;
	event_warn("Couldn't open %s", "/bad/file");
	evutil_snprintf(buf, sizeof(buf),
	    "Couldn't open /bad/file: %s",strerror(ENOENT));
	LOGEQ(EVENT_LOG_WARN,buf);
	RESET();

#ifdef CAN_CHECK_ERR
	evutil_snprintf(buf, sizeof(buf),
	    "Couldn't open /very/bad/file: %s",strerror(ENOENT));
	check_error_logging(err_fn, 5, EVENT_LOG_ERR, buf);
	RESET();
#endif

	/* Try with a socket errno. */
	fd = socket(AF_INET, SOCK_STREAM, 0);
#ifdef _WIN32
	evutil_snprintf(buf, sizeof(buf),
	    "Unhappy socket: %s",
	    evutil_socket_error_to_string(WSAEWOULDBLOCK));
	EVUTIL_SET_SOCKET_ERROR(WSAEWOULDBLOCK);
#else
	evutil_snprintf(buf, sizeof(buf),
	    "Unhappy socket: %s", strerror(EAGAIN));
	errno = EAGAIN;
#endif
	event_sock_warn(fd, "Unhappy socket");
	LOGEQ(EVENT_LOG_WARN, buf);
	RESET();

#ifdef CAN_CHECK_ERR
	check_error_logging(sock_err_fn, 20, EVENT_LOG_ERR, buf);
	RESET();
#endif

#undef RESET
#undef LOGEQ
end:
	if (logmsg)
		free(logmsg);
	if (fd >= 0)
		evutil_closesocket(fd);
}
Exemplo n.º 30
0
int
main(int argc, char **argv)
{
	int r;

	struct evhttp_uri *http_uri = NULL;
	const char *url = NULL, *data_file = NULL;
	const char *crt = "/etc/ssl/certs/ca-certificates.crt";
	const char *scheme, *host, *path, *query;
	char uri[256];
	int port;
	int retries = 0;
	int timeout = -1;

	SSL_CTX *ssl_ctx = NULL;
	SSL *ssl = NULL;
	struct bufferevent *bev;
	struct evhttp_connection *evcon = NULL;
	struct evhttp_request *req;
	struct evkeyvalq *output_headers;
	struct evbuffer *output_buffer;

	int i;
	int ret = 0;
	enum { HTTP, HTTPS } type = HTTP;

	for (i = 1; i < argc; i++) {
		if (!strcmp("-url", argv[i])) {
			if (i < argc - 1) {
				url = argv[i + 1];
			} else {
				syntax();
				goto error;
			}
		} else if (!strcmp("-crt", argv[i])) {
			if (i < argc - 1) {
				crt = argv[i + 1];
			} else {
				syntax();
				goto error;
			}
		} else if (!strcmp("-ignore-cert", argv[i])) {
			ignore_cert = 1;
		} else if (!strcmp("-data", argv[i])) {
			if (i < argc - 1) {
				data_file = argv[i + 1];
			} else {
				syntax();
				goto error;
			}
		} else if (!strcmp("-retries", argv[i])) {
			if (i < argc - 1) {
				retries = atoi(argv[i + 1]);
			} else {
				syntax();
				goto error;
			}
		} else if (!strcmp("-timeout", argv[i])) {
			if (i < argc - 1) {
				timeout = atoi(argv[i + 1]);
			} else {
				syntax();
				goto error;
			}
		} else if (!strcmp("-help", argv[i])) {
			syntax();
			goto error;
		}
	}

	if (!url) {
		syntax();
		goto error;
	}

#ifdef _WIN32
	{
		WORD wVersionRequested;
		WSADATA wsaData;
		int err;

		wVersionRequested = MAKEWORD(2, 2);

		err = WSAStartup(wVersionRequested, &wsaData);
		if (err != 0) {
			printf("WSAStartup failed with error: %d\n", err);
			goto error;
		}
	}
#endif // _WIN32

	http_uri = evhttp_uri_parse(url);
	if (http_uri == NULL) {
		err("malformed url");
		goto error;
	}

	scheme = evhttp_uri_get_scheme(http_uri);
	if (scheme == NULL || (strcasecmp(scheme, "https") != 0 &&
	                       strcasecmp(scheme, "http") != 0)) {
		err("url must be http or https");
		goto error;
	}

	host = evhttp_uri_get_host(http_uri);
	if (host == NULL) {
		err("url must have a host");
		goto error;
	}

	port = evhttp_uri_get_port(http_uri);
	if (port == -1) {
		port = (strcasecmp(scheme, "http") == 0) ? 80 : 443;
	}

	path = evhttp_uri_get_path(http_uri);
	if (strlen(path) == 0) {
		path = "/";
	}

	query = evhttp_uri_get_query(http_uri);
	if (query == NULL) {
		snprintf(uri, sizeof(uri) - 1, "%s", path);
	} else {
		snprintf(uri, sizeof(uri) - 1, "%s?%s", path, query);
	}
	uri[sizeof(uri) - 1] = '\0';

#if OPENSSL_VERSION_NUMBER < 0x10100000L
	// Initialize OpenSSL
	SSL_library_init();
	ERR_load_crypto_strings();
	SSL_load_error_strings();
	OpenSSL_add_all_algorithms();
#endif

	/* This isn't strictly necessary... OpenSSL performs RAND_poll
	 * automatically on first use of random number generator. */
	r = RAND_poll();
	if (r == 0) {
		err_openssl("RAND_poll");
		goto error;
	}

	/* Create a new OpenSSL context */
	ssl_ctx = SSL_CTX_new(SSLv23_method());
	if (!ssl_ctx) {
		err_openssl("SSL_CTX_new");
		goto error;
	}

#ifndef _WIN32
	/* TODO: Add certificate loading on Windows as well */

	/* Attempt to use the system's trusted root certificates.
	 * (This path is only valid for Debian-based systems.) */
	if (1 != SSL_CTX_load_verify_locations(ssl_ctx, crt, NULL)) {
		err_openssl("SSL_CTX_load_verify_locations");
		goto error;
	}
	/* Ask OpenSSL to verify the server certificate.  Note that this
	 * does NOT include verifying that the hostname is correct.
	 * So, by itself, this means anyone with any legitimate
	 * CA-issued certificate for any website, can impersonate any
	 * other website in the world.  This is not good.  See "The
	 * Most Dangerous Code in the World" article at
	 * https://crypto.stanford.edu/~dabo/pubs/abstracts/ssl-client-bugs.html
	 */
	SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_PEER, NULL);
	/* This is how we solve the problem mentioned in the previous
	 * comment.  We "wrap" OpenSSL's validation routine in our
	 * own routine, which also validates the hostname by calling
	 * the code provided by iSECPartners.  Note that even though
	 * the "Everything You've Always Wanted to Know About
	 * Certificate Validation With OpenSSL (But Were Afraid to
	 * Ask)" paper from iSECPartners says very explicitly not to
	 * call SSL_CTX_set_cert_verify_callback (at the bottom of
	 * page 2), what we're doing here is safe because our
	 * cert_verify_callback() calls X509_verify_cert(), which is
	 * OpenSSL's built-in routine which would have been called if
	 * we hadn't set the callback.  Therefore, we're just
	 * "wrapping" OpenSSL's routine, not replacing it. */
	SSL_CTX_set_cert_verify_callback(ssl_ctx, cert_verify_callback,
					  (void *) host);
#else // _WIN32
	(void)crt;
#endif // _WIN32

	// Create event base
	base = event_base_new();
	if (!base) {
		perror("event_base_new()");
		goto error;
	}

	// Create OpenSSL bufferevent and stack evhttp on top of it
	ssl = SSL_new(ssl_ctx);
	if (ssl == NULL) {
		err_openssl("SSL_new()");
		goto error;
	}

	#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
	// Set hostname for SNI extension
	SSL_set_tlsext_host_name(ssl, host);
	#endif

	if (strcasecmp(scheme, "http") == 0) {
		bev = bufferevent_socket_new(base, -1, BEV_OPT_CLOSE_ON_FREE);
	} else {
		type = HTTPS;
		bev = bufferevent_openssl_socket_new(base, -1, ssl,
			BUFFEREVENT_SSL_CONNECTING,
			BEV_OPT_CLOSE_ON_FREE|BEV_OPT_DEFER_CALLBACKS);
	}

	if (bev == NULL) {
		fprintf(stderr, "bufferevent_openssl_socket_new() failed\n");
		goto error;
	}

	bufferevent_openssl_set_allow_dirty_shutdown(bev, 1);

	// For simplicity, we let DNS resolution block. Everything else should be
	// asynchronous though.
	evcon = evhttp_connection_base_bufferevent_new(base, NULL, bev,
		host, port);
	if (evcon == NULL) {
		fprintf(stderr, "evhttp_connection_base_bufferevent_new() failed\n");
		goto error;
	}

	if (retries > 0) {
		evhttp_connection_set_retries(evcon, retries);
	}
	if (timeout >= 0) {
		evhttp_connection_set_timeout(evcon, timeout);
	}

	// Fire off the request
	req = evhttp_request_new(http_request_done, bev);
	if (req == NULL) {
		fprintf(stderr, "evhttp_request_new() failed\n");
		goto error;
	}

	output_headers = evhttp_request_get_output_headers(req);
	evhttp_add_header(output_headers, "Host", host);
	evhttp_add_header(output_headers, "Connection", "close");

	if (data_file) {
		/* NOTE: In production code, you'd probably want to use
		 * evbuffer_add_file() or evbuffer_add_file_segment(), to
		 * avoid needless copying. */
		FILE * f = fopen(data_file, "rb");
		char buf[1024];
		size_t s;
		size_t bytes = 0;

		if (!f) {
			syntax();
			goto error;
		}

		output_buffer = evhttp_request_get_output_buffer(req);
		while ((s = fread(buf, 1, sizeof(buf), f)) > 0) {
			evbuffer_add(output_buffer, buf, s);
			bytes += s;
		}
		evutil_snprintf(buf, sizeof(buf)-1, "%lu", (unsigned long)bytes);
		evhttp_add_header(output_headers, "Content-Length", buf);
		fclose(f);
	}

	r = evhttp_make_request(evcon, req, data_file ? EVHTTP_REQ_POST : EVHTTP_REQ_GET, uri);
	if (r != 0) {
		fprintf(stderr, "evhttp_make_request() failed\n");
		goto error;
	}

	event_base_dispatch(base);
	goto cleanup;

error:
	ret = 1;
cleanup:
	if (evcon)
		evhttp_connection_free(evcon);
	if (http_uri)
		evhttp_uri_free(http_uri);
	event_base_free(base);

	if (ssl_ctx)
		SSL_CTX_free(ssl_ctx);
	if (type == HTTP && ssl)
		SSL_free(ssl);
#if OPENSSL_VERSION_NUMBER < 0x10100000L
	EVP_cleanup();
	ERR_free_strings();

#ifdef EVENT__HAVE_ERR_REMOVE_THREAD_STATE
	ERR_remove_thread_state(NULL);
#else
	ERR_remove_state(0);
#endif
	CRYPTO_cleanup_all_ex_data();

	sk_SSL_COMP_free(SSL_COMP_get_compression_methods());
#endif /*OPENSSL_VERSION_NUMBER < 0x10100000L */

#ifdef _WIN32
	WSACleanup();
#endif

	return ret;
}