Last active
December 16, 2015 05:49
-
-
Save bodgit/5387076 to your computer and use it in GitHub Desktop.
libevent 2.0.21 / OS X 10.8.3 test case
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
events = 80 | |
Connected to 127.0.0.1:2003 | |
events = 21 | |
Error connecting to 127.0.0.1:2003 | |
events = 80 | |
Connected to 192.168.255.128:2003 | |
events = 20 | |
Error connecting to 127.0.0.1:2003 | |
<5 second pause> | |
events = 20 | |
Error connecting to 127.0.0.1:2003 | |
<5 second pause> | |
events = 20 | |
Error connecting to 127.0.0.1:2003 | |
^C |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <sys/time.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <event2/event.h> | |
#include <event2/dns.h> | |
#include <event2/buffer.h> | |
#include <event2/bufferevent.h> | |
struct graphite_connection { | |
struct evdns_base *dns; | |
struct bufferevent *bev; | |
char *host; | |
unsigned short port; | |
/* (Re)connect */ | |
struct event *connect_ev; | |
struct timeval connect_tv[2]; | |
int connect_index; | |
}; | |
void graphite_init(struct event_base *); | |
struct graphite_connection *graphite_connection_new(char *, | |
unsigned short, struct timeval); | |
void graphite_connect(struct graphite_connection *); | |
void graphite_disconnect(struct graphite_connection *); | |
void graphite_connection_free(struct graphite_connection *); | |
struct event_base *base; | |
void | |
graphite_init(struct event_base *b) | |
{ | |
base = b; | |
} | |
void | |
graphite_read(struct bufferevent *bev, void *arg) | |
{ | |
struct graphite_connection *c = (struct graphite_connection *)arg; | |
struct evbuffer *input = bufferevent_get_input(bev); | |
/* Just drain any input away */ | |
evbuffer_drain(input, evbuffer_get_length(input)); | |
} | |
void | |
graphite_event(struct bufferevent *bev, short events, void *arg) | |
{ | |
struct graphite_connection *c = (struct graphite_connection *)arg; | |
fprintf(stderr, "events = %x\n", events); | |
if (events & BEV_EVENT_CONNECTED) { | |
fprintf(stderr, "Connected to %s:%hu\n", c->host, c->port); | |
/* Reset backoff to immediate */ | |
c->connect_index = 0; | |
evdns_base_free(c->dns, 1); | |
} else if (events & (BEV_EVENT_ERROR|BEV_EVENT_EOF)) { | |
if (events & BEV_EVENT_ERROR) { | |
int err = bufferevent_socket_get_dns_error(bev); | |
if (err) | |
fprintf(stderr, "DNS error: %s\n", | |
evutil_gai_strerror(err)); | |
fprintf(stderr, "Error connecting to %s:%hu\n", | |
c->host, c->port); | |
} | |
/* Tear down connection */ | |
bufferevent_free(c->bev); | |
c->bev = NULL; | |
/* Schedule a reconnect attempt */ | |
evtimer_add(c->connect_ev, | |
&c->connect_tv[c->connect_index]); | |
/* If this attempt is after no delay, set the next attempt (and | |
* all subsequent ones) to be after a delay | |
*/ | |
if (c->connect_index == 0) | |
c->connect_index++; | |
} | |
} | |
void | |
graphite_reconnect(int fd, short event, void *arg) | |
{ | |
struct graphite_connection *c = (struct graphite_connection *)arg; | |
c->dns = evdns_base_new(base, 1); | |
c->bev = bufferevent_socket_new(base, -1, | |
BEV_OPT_CLOSE_ON_FREE|BEV_OPT_DEFER_CALLBACKS); | |
if (bufferevent_socket_connect_hostname(c->bev, c->dns, AF_UNSPEC, | |
c->host, c->port) < 0) { | |
/* Error starting connection */ | |
bufferevent_free(c->bev); | |
return; | |
} | |
bufferevent_setcb(c->bev, graphite_read, NULL, graphite_event, | |
(void *)c); | |
bufferevent_enable(c->bev, EV_READ|EV_WRITE); | |
} | |
struct graphite_connection * | |
graphite_connection_new(char *host, unsigned short port, struct timeval tv) | |
{ | |
struct graphite_connection *c; | |
if ((c = calloc(1, sizeof(struct graphite_connection))) != NULL) { | |
/* Set up timer to (re)connect */ | |
c->connect_ev = evtimer_new(base, graphite_reconnect, | |
(void *)c); | |
c->connect_tv[1] = tv; | |
/* Hostname */ | |
c->host = strdup(host); | |
/* TCP port */ | |
c->port = port; | |
} | |
return (c); | |
} | |
void | |
graphite_connect(struct graphite_connection *c) | |
{ | |
evtimer_add(c->connect_ev, &c->connect_tv[0]); | |
c->connect_index = 1; | |
} | |
void | |
graphite_disconnect(struct graphite_connection *c) | |
{ | |
bufferevent_free(c->bev); | |
c->bev = NULL; | |
} | |
void | |
graphite_connection_free(struct graphite_connection *c) | |
{ | |
free(c->host); | |
free(c); | |
} | |
int | |
main(int argc, char *argv[]) | |
{ | |
struct event_base *b; | |
struct graphite_connection *c1, *c2; | |
struct timeval tv = { 5, 0 }; /* 5 seconds */ | |
if ((b = event_base_new()) == NULL) | |
return (-1); | |
graphite_init(b); | |
/* Host that won't connect */ | |
if ((c1 = graphite_connection_new("127.0.0.1", 2003, tv)) == NULL) | |
return (-1); | |
/* Host that will connect */ | |
if ((c2 = graphite_connection_new("192.168.255.128", 2003, tv)) == NULL) | |
return (-1); | |
graphite_connect(c1); | |
graphite_connect(c2); | |
event_base_dispatch(b); | |
graphite_connection_free(c1); | |
graphite_connection_free(c2); | |
return (0); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment