Skip to content

Instantly share code, notes, and snippets.

@bodgit
Last active December 16, 2015 05:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bodgit/5387076 to your computer and use it in GitHub Desktop.
Save bodgit/5387076 to your computer and use it in GitHub Desktop.
libevent 2.0.21 / OS X 10.8.3 test case
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
#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