2 * Copyright (c) 2007 Ry Dahl <ry.d4hl@gmail.com>
6 /* TODO: add timeouts for clients */
10 #include <arpa/inet.h>
23 #include "tcp_server.h"
25 #define TCP_CHUNKSIZE (16*1024)
27 int misc_lookup_host(char *address
, struct in_addr
*addr
)
30 host
= gethostbyname(address
);
31 if (host
&& host
->h_addr_list
[0]) {
32 memmove(addr
, host
->h_addr_list
[0], sizeof(struct in_addr
));
38 /* Returns the number of bytes remaining to write */
39 int tcp_client_write(tcp_client
*client
, const char *data
, int length
)
41 int sent
= send(client
->fd
, data
, length
, 0);
43 client
->error_cb(ERROR_CB_ERROR
, strerror(errno
));
44 tcp_client_close(client
);
50 void tcp_client_on_readable( struct ev_loop
*loop
51 , struct ev_io
*watcher
55 tcp_client
*client
= (tcp_client
*)(watcher
->data
);
56 char buffer
[TCP_CHUNKSIZE
];
59 if(client
->read_cb
== NULL
) return;
61 length
= recv(client
->fd
, buffer
, TCP_CHUNKSIZE
, 0);
64 client
->error_cb(ERROR_CB_ERROR
, strerror(errno
));
65 tcp_client_close(client
);
69 /* User needs to copy the data out of the buffer or process it before
70 * leaving this function.
72 client
->read_cb(buffer
, length
, client
->read_cb_data
);
75 tcp_client
* tcp_client_new(tcp_server
*server
)
80 client
= g_new0(tcp_client
, 1);
81 client
->error_cb
= server
->error_cb
;
82 client
->parent
= server
;
83 client
->fd
= accept(server
->fd
, (struct sockaddr
*)&(client
->sockaddr
), &len
);
85 client
->error_cb(ERROR_CB_ERROR
, "Could not get client socket");
86 tcp_client_free(client
);
90 int r
= fcntl(client
->fd
, F_SETFL
, O_NONBLOCK
);
92 server
->error_cb(ERROR_CB_WARNING
, "setting nonblock mode failed");
95 client
->read_watcher
= g_new0(struct ev_io
, 1);
96 client
->read_watcher
->data
= client
;
97 ev_init (client
->read_watcher
, tcp_client_on_readable
);
98 ev_io_set (client
->read_watcher
, client
->fd
, EV_READ
);
99 ev_io_start (server
->loop
, client
->read_watcher
);
104 void tcp_client_free(tcp_client
*client
)
106 tcp_client_close(client
);
110 void tcp_client_close(tcp_client
*client
)
112 if(client
->read_watcher
) {
113 printf("killing read watcher\n");
114 ev_io_stop(client
->parent
->loop
, client
->read_watcher
);
115 free(client
->read_watcher
);
116 client
->read_watcher
= NULL
;
121 tcp_server
* tcp_server_new(error_cb_t error_cb
)
124 tcp_server
*server
= g_new0(tcp_server
, 1);
126 server
->fd
= socket(PF_INET
, SOCK_STREAM
, 0);
127 server
->error_cb
= error_cb
;
128 r
= fcntl(server
->fd
, F_SETFL
, O_NONBLOCK
);
130 server
->error_cb(ERROR_CB_WARNING
, "setting nonblock mode failed");
134 server
->loop
= ev_default_loop(0);
139 void tcp_server_free(tcp_server
*server
)
141 tcp_server_close(server
);
145 void tcp_server_close(tcp_server
*server
)
147 if(server
->accept_watcher
) {
148 printf("killing accept watcher\n");
149 ev_io_stop(server
->loop
, server
->accept_watcher
);
150 free(server
->accept_watcher
);
151 server
->accept_watcher
= NULL
;
156 void tcp_server_accept( struct ev_loop
*loop
157 , struct ev_io
*watcher
161 tcp_server
*server
= (tcp_server
*)(watcher
->data
);
164 assert(server
->loop
== loop
);
166 client
= tcp_client_new(server
);
167 //g_queue_push_head(server->children, (gpointer)client);
169 if(server
->accept_cb
!= NULL
)
170 server
->accept_cb(server
, client
, server
->accept_cb_data
);
175 void tcp_server_listen ( tcp_server
*server
179 , tcp_server_accept_cb_t accept_cb
180 , void *accept_cb_data
185 server
->sockaddr
.sin_family
= AF_INET
;
186 server
->sockaddr
.sin_port
= htons(port
);
187 //inet_aton(address, server->sockaddr.sin_addr);
188 misc_lookup_host(address
, &(server
->sockaddr
.sin_addr
));
190 /* Other socket options. This could probably be fine tuned.
191 * SO_SNDBUF set buffer size for output
192 * SO_RCVBUF set buffer size for input
193 * SO_SNDLOWAT set minimum count for output
194 * SO_RCVLOWAT set minimum count for input
195 * SO_SNDTIMEO set timeout value for output
196 * SO_RCVTIMEO set timeout value for input
198 r
= bind(server
->fd
, (struct sockaddr
*)&(server
->sockaddr
), sizeof(server
->sockaddr
));
200 server
->error_cb(ERROR_CB_ERROR
, "bind failed");
205 r
= listen(server
->fd
, backlog
);
207 server
->error_cb(ERROR_CB_ERROR
, "listen failed");
211 server
->accept_watcher
= g_new0(struct ev_io
, 1);
212 server
->accept_watcher
->data
= server
;
213 server
->accept_cb
= accept_cb
;
214 server
->accept_cb_data
= accept_cb_data
;
216 ev_init (server
->accept_watcher
, tcp_server_accept
);
217 ev_io_set (server
->accept_watcher
, server
->fd
, EV_READ
);
218 ev_io_start (server
->loop
, server
->accept_watcher
);
219 ev_loop (server
->loop
, 0);