Skip to content

Commit

Permalink
Initial checkin for libevent book; mostly example code.
Browse files Browse the repository at this point in the history
  • Loading branch information
nmathewson committed Feb 7, 2009
0 parents commit 6c551c0
Show file tree
Hide file tree
Showing 9 changed files with 959 additions and 0 deletions.
20 changes: 20 additions & 0 deletions 00_about.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@

About this document
-------------------

This document will teach you how to use Libevent 2.0 to write fast
portable asynchronous network IO programs in C. We assume:

* That you already know C.
* That you already know the basic C networking calls (socket(),
connect(), and so on).


A note on examples
------------------

The examples here above should work all right on Linux, FreeBSD,
OpenBSD, NetBSD, Mac OS X, Solaris, Android,

You might notice that some of the examples above
don't compile so well on winows.
29 changes: 29 additions & 0 deletions 01_intro.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@

A tiny introduction to asynchronous I/O
----------------------------------------

Most beginning programmers start with synchronous, blocking I/O calls.
An I/O call is _synchronous_ if, when you call it, it does not return
unless and until the operation is completed. When you call
"connect()" on a TCP connection, for example, your operating system
queues a SYN packet to the host on the other side of the TCP
connection, and does not return control back to your application until
it receives a SYN ACK packet from the opposite host, or until enough
time has passed that it decides to give up.

Here's an example of a really simple syncronous client that writes

[source,C]
~~~~~~~
include::01_sync_webclient.c[]
~~~~~~~

As you'll see,




Windows digression: what about overlapped IO?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Oh gods no.
19 changes: 19 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@

GENERATED_HTML=01_intro.html

all: html examples

html: $(GENERATED_HTML)

examples:
cd examples_01 && $(MAKE)

01_intro.html: examples_01/01_sync_webclient.c

.txt.html:
asciidoc $<
clean:
rm -f *~
rm -f *.o
rm -f $(GENERATED_HTML)
cd examples_01 && $(MAKE) clean
129 changes: 129 additions & 0 deletions examples_01/01_rot13_server_bufferevent.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
/* For sockaddr_in */
#include <netinet/in.h>
/* For socket functions */
#include <sys/socket.h>
/* For fcntl */
#include <fcntl.h>

#include <event2/event.h>
#include <event2/buffer.h>
#include <event2/bufferevent.h>

#include <assert.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>

void do_read(evutil_socket_t fd, short events, void *arg);
void do_write(evutil_socket_t fd, short events, void *arg);

char
rot13_char(char c)
{
/* We don't want to use isalpha here; setting the locale would change
* which characters are considered alphabetical. */
if ((c >= 'a' && c <= 'm') || (c >= 'A' && c <= 'M'))
return c + 13;
else if ((c >= 'n' && c <= 'z') || (c >= 'N' && c <= 'Z'))
return c - 13;
else
return c;
}

void
readcb(struct bufferevent *bev, void *ctx)
{
struct evbuffer *input, *output;
char *line;
size_t n;
input = bufferevent_get_input(bev);
output = bufferevent_get_output(bev);

while ((line = evbuffer_readln(input, &n, EVBUFFER_EOL_LF))) {
int i;
for (i = 0; i < n; ++i)
line[i] = rot13_char(line[i]);
evbuffer_add(output, line, n);
evbuffer_add(output, "\n", 1);
}
}

void
errorcb(struct bufferevent *bev, short error, void *ctx)
{
bufferevent_free(bev);
}

void
do_accept(evutil_socket_t listener, short event, void *arg)
{
struct event_base *base = arg;
struct sockaddr_storage ss;
socklen_t slen = sizeof(ss);
int fd = accept(listener, (struct sockaddr*)&ss, &slen);
if (fd < 0) {
perror("accept");
} else if (fd > FD_SETSIZE) {
close(fd);
} else {
struct bufferevent *bev;
evutil_make_socket_nonblocking(fd);
bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);
bufferevent_setcb(bev, readcb, NULL, errorcb, NULL);
bufferevent_enable(bev, EV_READ|EV_WRITE);
}
}

void
run(void)
{
evutil_socket_t listener;
struct sockaddr_in sin;
struct event_base *base;
struct event *listener_event;

base = event_base_new();
if (!base)
return; /*XXXerr*/

sin.sin_family = AF_INET;
sin.sin_addr.s_addr = 0;
sin.sin_port = htons(40713);

listener = socket(AF_INET, SOCK_STREAM, 0);
evutil_make_socket_nonblocking(listener);

#ifndef WIN32
{
int one = 1;
setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
}
#endif

if (bind(listener, (struct sockaddr*)&sin, sizeof(sin)) < 0) {
perror("bind");
return;
}

if (listen(listener, 16)<0) {
perror("listen");
return;
}

listener_event = event_new(base, listener, EV_READ|EV_PERSIST, do_accept, (void*)base);
/*XXX check it */
event_add(listener_event, NULL);

event_base_dispatch(base);
}

int
main(int c, char **v)
{
setvbuf(stdout, NULL, _IONBF, 0);

run();
return 0;
}
121 changes: 121 additions & 0 deletions examples_01/01_rot13_server_forking.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
/* For sockaddr_in */
#include <netinet/in.h>
/* For socket functions */
#include <sys/socket.h>

#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>

char
rot13_char(char c)
{
/* We don't want to use isalpha here; setting the locale would change
* which characters are considered alphabetical. */
if ((c >= 'a' && c <= 'm') || (c >= 'A' && c <= 'M'))
return c + 13;
else if ((c >= 'n' && c <= 'z') || (c >= 'N' && c <= 'Z'))
return c - 13;
else
return c;
}

void
child(int fd)
{
char *outbuf;
size_t outbuf_len = 1024;
size_t outbuf_used = 0;
ssize_t result;

outbuf = malloc(outbuf_len);
if (!outbuf) {
perror("malloc");
exit(1);
}

while (1) {
char ch;
result = recv(fd, &ch, 1, 0);
if (result == 0) {
break;
} else if (result == -1) {
perror("read");
break;
}

if (outbuf_used == outbuf_len) {
char *outbuf2 = realloc(outbuf, outbuf_len*2);
if (outbuf2 == NULL) {
perror("realloc");
break;
}
outbuf = outbuf2;
outbuf_len *= 2;
}

outbuf[outbuf_used++] = rot13_char(ch);

if (ch == '\n') {
send(fd, outbuf, outbuf_used, 0);
outbuf_used = 0;
continue;
}
}

free(outbuf);
}

void
run(void)
{
int listener;
struct sockaddr_in sin;

sin.sin_family = AF_INET;
sin.sin_addr.s_addr = 0;
sin.sin_port = htons(40713);

listener = socket(AF_INET, SOCK_STREAM, 0);

#ifndef WIN32
{
int one = 1;
setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
}
#endif

if (bind(listener, (struct sockaddr*)&sin, sizeof(sin)) < 0) {
perror("bind");
return;
}

if (listen(listener, 16)<0) {
perror("listen");
return;
}



while (1) {
struct sockaddr_storage ss;
socklen_t slen = sizeof(ss);
int fd = accept(listener, (struct sockaddr*)&ss, &slen);
if (fd < 0) {
perror("accept");
} else {
if (fork() == 0) {
child(fd);
exit(0);
}
}
}
}

int
main(int c, char **v)
{
run();
return 0;
}
Loading

0 comments on commit 6c551c0

Please sign in to comment.