Permalink
Browse files

Initial checkin for libevent book; mostly example code.

  • Loading branch information...
Nick Mathewson
Nick Mathewson committed Feb 7, 2009
0 parents commit 6c551c01695582cd967bea167c305af65f62b206
@@ -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.
@@ -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.
@@ -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
@@ -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;
+}
@@ -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;
+}
Oops, something went wrong.

0 comments on commit 6c551c0

Please sign in to comment.