fix
[libjh.git] / netconn.c
1 #include <sys/types.h>
2 #include <stdlib.h>
3 #include <errno.h>
4 #include <unistd.h>
5 #include <stdbool.h>
6 #include <assert.h>
7 #include <ev.h>
8
9 static void connection_waiting_cb(struct ev_loop *loop, ev_io *w, int revents) {
10   bufio_connection *con = (bufio_connection *)w->data;
11   if (revents & EV_READ) {
12     assert(con->inbuf_used != con->inbuf_size);
13     int res = read(w->fd, con->inbuf+con->inbuf_used, con->inbuf_size-con->inbuf_used);
14     if (res == -1) {
15       if (errno != EAGAIN && errno != EWOULDBLOCK) {
16         con->err_cb(con);
17       }
18       return;
19     }
20     if (res == 0) {
21       con->err_cb(con);
22       return;
23     }
24     con->inbuf_used += res;
25     if (con->inbuf_size == con->inbuf_used) {
26       // The buffer is filled, so stop reading data until we have a new one.
27       ev_io_stop(loop, w);
28
29       // Call the callback AFTERWARDS (after it has finished executing, we might
30       // already have a new read buffer).
31       con->data_cb(con);
32     }
33   }
34
35   if (revents & EV_WRITE) {
36     if (bufio_chain_flush(&con->outbuf, w->fd) == 0) {
37       ev_io_stop(loop, w);
38     }
39   }
40 }
41
42 bufio_connection *bufio_connection_create(struct ev_loop *loop, int fd) {
43   bufio_connection *con = calloc(1, sizeof(*con));
44   if (con == NULL) return NULL;
45   con->loop = loop;
46   ev_io_init(&con->rw, connection_waiting_cb, fd, EV_READ);
47   ev_io_init(&con->ww, connection_waiting_cb, fd, EV_WRITE);
48   con->rw.data = con;
49   con->ww.data = con;
50   return con;
51 }
52
53 void bufio_connection_set_read_buffer(bufio_connection *con, void *buf, size_t size) {
54   assert(size > 0);
55   con->inbuf = buf;
56   con->inbuf_size = size;
57   con->inbuf_used = 0;
58
59   ev_io_start(con->loop, &con->rw);
60 }
61
62 void bufio_connection_destroy(bufio_connection *con) {
63   bufio_chain_clear(&con->outbuf);
64   ev_io_stop(con->loop, &con->rw);
65   ev_io_stop(con->loop, &con->ww);
66   free(con);
67 }
68
69 int bufio_connection_write(bufio_connection *con, void *buf, size_t len) {
70   int res;
71   bool chain_was_empty = (con->outbuf.head == NULL);
72   res = bufio_chain_append(&con->outbuf, buf, len);
73   if (res == -1) return -1;
74   if (chain_was_empty) {
75     if (bufio_chain_flush(&con->outbuf, con->ww.fd)) {
76       ev_io_start(con->loop, &con->ww);
77     }
78   }
79   return 0;
80 }