catalinux / Conn (public) (License: LGPLv2) (since 2016-03-01) (hash sha1)
Net library for easy building ipv4/ipv6 network daemons/clients
List of commits:
Subject Hash Author Date (UTC)
WIP 1d246f2130d4acf8c267e82051b250a623da6870 Catalin(ux) M. BOIE 2013-10-16 19:57:04
WIP 6387026db3ce7983e610887565a282f4124d4092 Catalin(ux) M. BOIE 2013-10-14 20:06:49
WIP 15f063f9d34d3f7b7ae9d9e83f59b4077515122b Catalin(ux) M. BOIE 2010-09-30 22:01:30
Switch licence to LGPLv3+; Do not stupidly close master socket. d3b1c4ccd591627e7faa0eeaaa3b2bc1ee20709e Catalin(ux) M. BOIE 2013-08-14 04:09:36
Duilder fixes. Removed -O0. Fixed spec file. d8a03dced52e918b6f66a05dfd64a3c75c07c91b Catalin(ux) M. BOIE 2011-12-14 09:12:55
Fixed a stupid logging bug (invalid number of parameters). e7d4c38d0130a142ac6c409c63d63201d2af08e2 Catalin(ux) M. BOIE 2010-12-22 16:46:47
Ignore all Changelog files. fa45b63d3db958228f44bcb3d6431d60f94d1147 Catalin(ux) M. BOIE 2010-12-22 16:46:16
Added mailmap file. a57dcfd6bdf6c8c86161cf7ce3fff942a714a2b9 Catalin(ux) M. BOIE 2010-12-22 16:46:04
WIP a69db41578de7ded49d656b7ea7cfae76c6695d9 Catalin(ux) M. BOIE 2010-09-30 22:01:30
Be more verbose in try_expand_buf and error out connection when cannot expand. e95ac8d7e5015958d3594862c6183b63bab80d4a Catalin(ux) M. BOIE 2010-09-30 20:58:08
Ignore xbind1 compiled example. 089b68cf9fc5c16ee7d8136b28a52ec4dd139c78 Catalin(ux) M. BOIE 2010-08-23 19:42:01
Removed direct access to Conn structure in s.c example. f6215273602571ef2c98479bdba930ebe312cbc9 Catalin(ux) M. BOIE 2010-08-23 19:38:33
Bumped the version to 1.0.32. f158fca2cf9f3285ae761cd4ce30b01911b84385 Catalin(ux) M. BOIE 2010-06-23 21:30:47
The cache for epoll_ctl, has to take also the slot in consideration. ed378c16927c707feee481b2cd0ea7fbdf257d9d Catalin(ux) M. BOIE 2010-06-09 19:18:03
After calling getsockname, set cache as clean. 199f0fd96b064fd1e63f5773b1e7ab58e7d91303 Catalin(ux) M. BOIE 2010-06-08 18:30:20
Do not try to call getsockname if connection is not opened. e9853b5b5a01df3c5e07f6fe4607a68fd7181b39 Catalin(ux) M. BOIE 2010-06-08 18:28:49
Supports kernels below 2.6.9 (epoll_ctl). 97919a022fae39bdefc3f7e4c50526fb473dfd34 Catalin(ux) M. BOIE 2010-06-08 18:06:35
Cosmetic logging. ad806920255f8ca5f9281b6b6a3a53edf2d5088f Catalin(ux) M. BOIE 2010-06-08 17:35:45
When generating one line of slot status, do not append \n. 20ed77b4bf5909ded12cd225753a8858d8941792 Catalin(ux) M. BOIE 2010-06-08 15:57:16
Indented Conn_poll_cb to better watch logs. 58d734a8895b03eb17724eefe37e862c9665fb2c Catalin(ux) M. BOIE 2010-06-08 15:52:44
Commit 1d246f2130d4acf8c267e82051b250a623da6870 - WIP
Author: Catalin(ux) M. BOIE
Author date (UTC): 2013-10-16 19:57
Committer name: Catalin(ux) M. BOIE
Committer date (UTC): 2013-10-16 19:57
Parent(s): e04dd2581ae50957f34c84be7337b742d72dafba
Signing key:
Tree: 13347d09ad9beab1b16120989da46cb00947b9d6
File Lines added Lines deleted
Conn.c 192 568
Conn.h 2 4
Conn_config.h.in 13 0
Conn_core.c 708 290
Conn_core.h 53 34
Conn_engine_epoll.c 0 211
Conn_engine_epoll.h 0 22
Conn_wpool.c 257 0
Conn_wpool.h 37 0
Makefile.in 6 9
TODO 14 0
duilder.conf 1 1
examples/blackhole_c.c 1 1
examples/blackhole_s.c 1 1
examples/c.c 3 3
examples/ma.c 90 0
examples/raw.c 3 3
examples/raw2.c 3 3
examples/reconnect.c 3 3
examples/s.c 5 5
examples/timeout.c 3 3
examples/udp_s.c 5 5
examples/wpool1.c 25 24
examples/xbind.c 1 1
File Conn.c changed (mode: 100644) (index 02dd3f5..1e342ee)
6 6 * Licence: LGPL * Licence: LGPL
7 7 */ */
8 8
9 #include "Conn_config.h"
9 10 #include "Conn.h" #include "Conn.h"
10 #include "Conn_engine_epoll.h"
11
12
13 /* Internal variables */
14
15 /* Engine functions */
16 static int (*Conn_engine_init)(void);
17 static int (*Conn_engine_shutdown)(void);
18 static int (*Conn_engine_grow)(unsigned int);
19 static int (*Conn_engine_add_obj)(struct Conn *);
20 static int (*Conn_engine_del_obj)(struct Conn *);
21 static int (*Conn_engine_chg_obj)(struct Conn *);
22 static int (*Conn_engine_poll)(int, void (*cb)(const unsigned int slot, const int revents));
23 static int (*Conn_engine_move_slot)(const unsigned int dst,
24 const unsigned int src);
25
26
27 /* Functions */
28
29 /*
30 * Reads a value from proc
31 */
32 static void Conn_read_proc(char *buf, const size_t buf_size, const char *file)
33 {
34 int fd;
35 ssize_t n;
36
37 fd = open(file, O_RDONLY);
38 if (fd == -1) {
39 snprintf(buf, buf_size, "ERROR_OPEN!");
40 return;
41 }
42
43 n = read(fd, buf, buf_size - 1);
44 if (n == -1) {
45 snprintf(buf, buf_size, "ERROR_READ!");
46 } else if (n == 0) {
47 strcpy(buf, "");
48 } else {
49 buf[n - 1] = '\0';
50 n--;
51
52 while ((n >= 0) && (buf[n - 1] == '\n')) {
53 buf[n - 1] = '\0';
54 n--;
55 }
56 }
57
58 close(fd);
59 }
60
61 /*
62 * Returns some important system values
63 */
64 char *Conn_sys(void)
65 {
66 static char ret[512];
67 char somaxconn[16];
68 char tcp_max_tw_buckets[16];
69 char tcp_fin_timeout[16];
70
71 Conn_read_proc(somaxconn, sizeof(somaxconn),
72 "/proc/sys/net/core/somaxconn");
73 Conn_read_proc(tcp_max_tw_buckets, sizeof(tcp_max_tw_buckets),
74 "/proc/sys/net/ipv4/tcp_max_tw_buckets");
75 Conn_read_proc(tcp_fin_timeout, sizeof(tcp_fin_timeout),
76 "/proc/sys/net/ipv4/tcp_fin_timeout");
77
78 snprintf(ret, sizeof(ret), "net.core.somaxconn=%s"
79 " net.ipv4.tcp_max_tw_buckets=%s"
80 " net.ipv4.tcp_fin_timeout=%s",
81 somaxconn, tcp_max_tw_buckets, tcp_fin_timeout);
82
83 return ret;
84 }
85 11
86 12 int Conn_init(const unsigned int max) int Conn_init(const unsigned int max)
87 13 { {
88 unsigned int ret;
89 unsigned int engine;
90
91 14 if (Conn_inited == 1) if (Conn_inited == 1)
92 15 return 0; return 0;
93 16
 
... ... int Conn_init(const unsigned int max)
109 32 Conn_queue_init(&Conn_queue_free); Conn_queue_init(&Conn_queue_free);
110 33 */ */
111 34
112 ret = Conn_engine_set(engine);
113 if (ret != 0)
114 return -1;
115
116 ret = Conn_engine_epoll_init();
117 if (ret != 0)
35 Conn_epoll_fd = epoll_create(32);
36 if (Conn_epoll_fd == -1) {
37 Log(0, "Cannot create epoll fd (%s)\n", strerror(errno));
118 38 return -1; return -1;
39 }
119 40
120 41 Conn_inited = 1; Conn_inited = 1;
121 42
 
... ... int Conn_init(const unsigned int max)
127 48 */ */
128 49 int Conn_shutdown(void) int Conn_shutdown(void)
129 50 { {
130 int ret;
131 51 unsigned int slot; unsigned int slot;
132 52
133 53 Conn_inited = 0; Conn_inited = 0;
134 54
135 ret = Conn_engine_shutdown();
136 if (ret < 0)
137 return ret;
55 close(Conn_epoll_fd);
138 56
139 57 /* Free all buffers */ /* Free all buffers */
140 58 Log(5, "Freeing %u slots...\n", Conn_allocated); Log(5, "Freeing %u slots...\n", Conn_allocated);
 
... ... int Conn_enqueue(struct Conn *C, void *buf, const size_t count)
166 84 return -1; return -1;
167 85 } }
168 86
169 slot = C->slot;
170
171 87 if (Conn_level >= 10) { if (Conn_level >= 10) {
172 88 dump = Conn_dump(buf, count); dump = Conn_dump(buf, count);
173 Log(0, "\tTry to enqueue %d bytes to slot=%u, id=%llu [%s]...\n",
174 count, slot, Conns[slot].id, dump);
89 Log(0, "\tTry to enqueue %d bytes to id=%llu [%s]...\n",
90 count, C->id, dump);
175 91 free(dump); free(dump);
176 92 } }
177 93
178 if (Conns[slot].obuf_size - Conns[slot].obuf_tail < count) {
179 r = Conn_try_expand_buf(slot, 0, count);
94 if (C->obuf_size - C->obuf_tail < count) {
95 r = Conn_try_expand_buf(C, 0, count);
180 96 if (r != 0) if (r != 0)
181 97 return -1; return -1;
182 98 } }
183 99
184 memcpy(Conns[slot].obuf + Conns[slot].obuf_tail, buf, count);
185 Conns[slot].obuf_tail += count;
100 memcpy(C->obuf + C->obuf_tail, buf, count);
101 C->obuf_tail += count;
186 102
187 Conns[slot].events |= CONN_POLLOUT;
188 Conn_engine_chg_obj(&Conns[slot]);
103 Conns->events |= EPOLLOUT;
104 Conn_change_obj(C);
189 105
190 106 return count; return count;
191 107 } }
192 108
193 static void Conn_free_intern(const unsigned int slot)
109 static void Conn_free_intern(struct Conn *C)
194 110 { {
195 Log(11, "%s: Cleaning-up id %llu (slot=%u, fd=%d) in state %s [%s]...\n",
196 __FUNCTION__, Conns[slot].id, slot, Conns[slot].fd,
197 Conn_state(&Conns[slot]), Conn_errno(&Conns[slot]));
111 Log(11, "%s: Cleaning-up id %llu fd=%d in state %s [%s]...\n",
112 __func__, C->id, C->fd,
113 Conn_state(C), Conn_errno(C));
198 114
199 if (Conns[slot].error_state != CONN_ERROR_USERREQ)
115 if (C->error_state != CONN_ERROR_USERREQ)
200 116 Conn_error_raise(slot, 0); Conn_error_raise(slot, 0);
201 117
202 if ((Conns[slot].state == CONN_STATE_OPEN)
203 || (Conns[slot].state == CONN_STATE_LISTEN)
204 || (Conns[slot].state == CONN_STATE_ERROR)) {
205 if (Conns[slot].cb_close)
206 Conns[slot].cb_close(&Conns[slot]);
118 if ((C->state == CONN_STATE_OPEN)
119 || (C->state == CONN_STATE_LISTEN)
120 || (C->state == CONN_STATE_ERROR)) {
121 if (C->cb_close)
122 C->cb_close(C);
207 123 else if (Conn_close_cb) else if (Conn_close_cb)
208 Conn_close_cb(&Conns[slot]);
124 Conn_close_cb(C);
209 125 } }
210 126
211 if (Conns[slot].fd > -1) {
212 close(Conns[slot].fd);
213 Conns[slot].fd = -1;
127 if (C->fd > -1) {
128 close(C->fd);
129 C->fd = -1;
214 130 } }
215 131
216 132 /* Reset tsend, else we enter in a timeout error loop */ /* Reset tsend, else we enter in a timeout error loop */
217 Conns[slot].tsend.tv_sec = 0;
218 Conns[slot].tsend.tv_usec = 0;
133 C->tsend.tv_sec = 0;
134 C->tsend.tv_usec = 0;
219 135
220 136 /* Reset the connection attempt time */ /* Reset the connection attempt time */
221 Conns[slot].conn_syn.tv_sec = 0;
222 Conns[slot].conn_syn.tv_usec = 0;
137 C->conn_syn.tv_sec = 0;
138 C->conn_syn.tv_usec = 0;
223 139
224 140 /* Misc */ /* Misc */
225 Conns[slot].error_state = 0;
141 C->error_state = 0;
226 142
227 if (Conns[slot].flags & CONN_FLAGS_AUTO_RECONNECT) {
228 Conns[slot].tryat = Conn_now.tv_sec + Conns[slot].delay;
229 Conns[slot].state = CONN_STATE_CONNECT_0;
143 if (C->flags & CONN_FLAGS_AUTO_RECONNECT) {
144 C->tryat = Conn_now.tv_sec + C->delay;
145 C->state = CONN_STATE_CONNECT_0;
230 146
231 Conns[slot].ibuf_head = 0;
232 Conns[slot].ibuf_tail = 0;
147 C->ibuf_head = 0;
148 C->ibuf_tail = 0;
233 149
234 Conns[slot].obuf_head = 0;
235 Conns[slot].obuf_tail = 0;
150 C->obuf_head = 0;
151 C->obuf_tail = 0;
236 152
237 153 Conn_pending++; Conn_pending++;
238 154 } else { } else {
239 Conns[slot].type = CONN_TYPE_UNK;
240 Conns[slot].state = CONN_STATE_FREE;
155 C->type = CONN_TYPE_UNK;
156 C->state = CONN_STATE_FREE;
241 157
242 158 /* Allow connections */ /* Allow connections */
243 159 Conn_accept_is_allowed = 1; Conn_accept_is_allowed = 1;
 
... ... static void Conn_free_intern(const unsigned int slot)
253 169 */ */
254 170 static int Conn_grow(void) static int Conn_grow(void)
255 171 { {
256 int ret;
257 172 unsigned int alloc, increment = 128, i; unsigned int alloc, increment = 128, i;
258 173 struct Conn *p, *set; struct Conn *p, *set;
259 174
260 175 Log(10, "%s() Try to grow cells from %d to %d.\n", Log(10, "%s() Try to grow cells from %d to %d.\n",
261 __FUNCTION__,
176 __func__,
262 177 Conn_allocated, Conn_allocated + 128); Conn_allocated, Conn_allocated + 128);
263 178
264 179 alloc = Conn_allocated + increment; alloc = Conn_allocated + increment;
265 180
266 ret = Conn_engine_grow(alloc);
267 if (ret != 0)
268 return -1;
269
270 181 p = (struct Conn *) realloc(Conns, alloc * sizeof(struct Conn)); p = (struct Conn *) realloc(Conns, alloc * sizeof(struct Conn));
271 182 if (p == NULL) if (p == NULL)
272 183 return -1; return -1;
 
... ... struct Conn *Conn_alloc(void)
295 206 unsigned int slot; unsigned int slot;
296 207
297 208 Log(10, "%s() Conn_no=%d Conn_max=%d\n", Log(10, "%s() Conn_no=%d Conn_max=%d\n",
298 __FUNCTION__,
209 __func__,
299 210 Conn_no, Conn_max); Conn_no, Conn_max);
300 211
301 212 if ((Conn_max > 0) && (Conn_no >= Conn_max)) { if ((Conn_max > 0) && (Conn_no >= Conn_max)) {
 
... ... struct Conn *Conn_alloc(void)
317 228 Conn_max_reached = Conn_no; Conn_max_reached = Conn_no;
318 229
319 230 slot = Conn_no; slot = Conn_no;
320 Conns[slot].slot = slot;
231 C->slot = slot;
321 232
322 Conns[slot].type = CONN_TYPE_UNK;
323 Conns[slot].state = CONN_STATE_EMPTY;
233 C->type = CONN_TYPE_UNK;
234 C->state = CONN_STATE_EMPTY;
324 235
325 if (Conns[slot].ibuf_size < Conn_default_ibuf) {
326 p = realloc(Conns[slot].ibuf, Conn_default_ibuf);
236 if (C->ibuf_size < Conn_default_ibuf) {
237 p = realloc(C->ibuf, Conn_default_ibuf);
327 238 if (p == NULL) { if (p == NULL) {
328 239 snprintf(Conn_error, sizeof(Conn_error), snprintf(Conn_error, sizeof(Conn_error),
329 240 "Memory allocation error2!"); "Memory allocation error2!");
330 241 return NULL; return NULL;
331 242 } }
332 Conn_mem_buffers_in += Conn_default_ibuf - Conns[slot].ibuf_size;
333 Conns[slot].ibuf = p;
334 Conns[slot].ibuf_size = Conn_default_ibuf;
243 Conn_mem_buffers_in += Conn_default_ibuf - C->ibuf_size;
244 C->ibuf = p;
245 C->ibuf_size = Conn_default_ibuf;
335 246 } }
336 Conns[slot].ibuf_head = 0;
337 Conns[slot].ibuf_tail = 0;
247 C->ibuf_head = 0;
248 C->ibuf_tail = 0;
338 249
339 if (Conns[slot].obuf_size < Conn_default_obuf) {
340 p = realloc(Conns[slot].obuf, Conn_default_obuf);
250 if (C->obuf_size < Conn_default_obuf) {
251 p = realloc(C->obuf, Conn_default_obuf);
341 252 if (p == NULL) { if (p == NULL) {
342 253 snprintf(Conn_error, sizeof(Conn_error), snprintf(Conn_error, sizeof(Conn_error),
343 254 "Memory allocation error3!"); "Memory allocation error3!");
344 255 return NULL; return NULL;
345 256 } }
346 Conn_mem_buffers_out += Conn_default_obuf - Conns[slot].obuf_size;
347 Conns[slot].obuf = p;
348 Conns[slot].obuf_size = Conn_default_obuf;
257 Conn_mem_buffers_out += Conn_default_obuf - C->obuf_size;
258 C->obuf = p;
259 C->obuf_size = Conn_default_obuf;
349 260 } }
350 Conns[slot].obuf_head = 0;
351 Conns[slot].obuf_tail = 0;
261 C->obuf_head = 0;
262 C->obuf_tail = 0;
352 263
353 Conns[slot].trecv = Conn_now;
264 C->trecv = Conn_now;
354 265
355 Conns[slot].bi = 0;
356 Conns[slot].bo = 0;
357 Conns[slot].private = NULL;
266 C->bi = 0;
267 C->bo = 0;
268 C->private = NULL;
358 269
359 270 /* Reset syn time */ /* Reset syn time */
360 Conns[slot].conn_syn.tv_sec = 0;
361 Conns[slot].conn_syn.tv_usec = 0;
271 C->conn_syn.tv_sec = 0;
272 C->conn_syn.tv_usec = 0;
362 273
363 274 /* bandwidth */ /* bandwidth */
364 Conns[slot].band_width = 0;
365 Conns[slot].band_factor = 0;
366 Conns[slot].band_tokens = 0;
367 Conns[slot].band_lasttime = Conn_now;
275 C->band_width = 0;
276 C->band_factor = 0;
277 C->band_tokens = 0;
278 C->band_lasttime = Conn_now;
279
280 C->fd = -1;
281 C->events = 0;
282 C->revents = 0;
368 283
369 Conns[slot].fd = -1;
370 Conns[slot].events = 0;
371 Conns[slot].revents = 0;
284 C->flags = 0;
372 285
373 Conns[slot].flags = 0;
286 C->start = Conn_now.tv_sec;
374 287
375 Conns[slot].start = Conn_now.tv_sec;
288 C->id = Conn_id++;
376 289
377 Conns[slot].id = Conn_id++;
290 C->cbs = Conn_default_cbs;
378 291
379 292 Conn_no++; Conn_no++;
380 293 /* Conn_work_to_do will not be incremented here, only in commit! */ /* Conn_work_to_do will not be incremented here, only in commit! */
381 294
382 295 Log(10, "\tFound free slot=%u, id=%llu. Now Conn_no=%d\n", Log(10, "\tFound free slot=%u, id=%llu. Now Conn_no=%d\n",
383 slot, Conns[slot].id, Conn_no);
296 slot, C->id, Conn_no);
384 297
385 298 if (Conn_no == Conn_max) if (Conn_no == Conn_max)
386 299 Conn_accept_is_allowed = 0; Conn_accept_is_allowed = 0;
387 300
388 return &Conns[slot];
301 return C;
389 302 } }
390 303
391 304 int Conn_set_socket_domain(struct Conn *C, const int domain) int Conn_set_socket_domain(struct Conn *C, const int domain)
 
... ... int Conn_set_socket_port(struct Conn *C, const int port)
443 356 int Conn_commit(struct Conn *C) int Conn_commit(struct Conn *C)
444 357 { {
445 358 int i, ret; int i, ret;
446 struct sockaddr *psa = NULL, *bind_psa = NULL;
447 struct sockaddr_in sa, bind_sa;
448 struct sockaddr_in6 sa6, bind_sa6;
449 int sock_len = 0, bind_sock_len = 0;
450 int do_bind = 1, do_listen = 1, do_connect = 0;
359 struct sockaddr *bind_psa = NULL;
360 struct sockaddr_in bind_sa;
361 struct sockaddr_in6 bind_sa6;
362 int bind_sock_len = 0;
363 int do_listen = 1, do_connect = 0;
451 364 int first_state; int first_state;
452 365 unsigned int slot; unsigned int slot;
453 366
454 367 slot = C->slot; slot = C->slot;
455 368
456 Log(10, "%s: slot=%u...\n", __FUNCTION__, slot);
369 Log(10, "%s: slot=%u...\n", __func__, slot);
457 370
458 371 /* Be optimistical and increment here, in 'free' we will decrement. */ /* Be optimistical and increment here, in 'free' we will decrement. */
459 372 /* So, in error case, we will only decrement this thing! */ /* So, in error case, we will only decrement this thing! */
460 373 Conn_work_to_do++; Conn_work_to_do++;
461 374
462 375 /* Try to figure what kind of socket is: client or master */ /* Try to figure what kind of socket is: client or master */
463 if (Conns[slot].type == CONN_TYPE_UNK) {
464 if (strlen(Conns[slot].addr) > 0) {
465 Conns[slot].type = CONN_TYPE_P2P;
376 if (C->type == CONN_TYPE_UNK) {
377 if (C->addr[0] != '\0') {
378 C->type = CONN_TYPE_P2P;
466 379 do_listen = 0; do_listen = 0;
467 380 do_connect = 1; do_connect = 1;
468 381 } else { } else {
469 Conns[slot].type = CONN_TYPE_MASTER;
470 if (strlen(Conns[slot].bind_addr) == 0) {
471 switch (Conns[slot].sock_domain) {
382 C->type = CONN_TYPE_MASTER;
383 if (strlen(C->bind_addr) == 0) {
384 switch (C->sock_domain) {
472 385 case PF_INET: case PF_INET:
473 snprintf(Conns[slot].bind_addr, sizeof(Conns[slot].bind_addr),
386 snprintf(C->bind_addr, sizeof(C->bind_addr),
474 387 "0.0.0.0"); break; "0.0.0.0"); break;
475 388 case PF_INET6: case PF_INET6:
476 snprintf(Conns[slot].bind_addr, sizeof(Conns[slot].bind_addr),
389 snprintf(C->bind_addr, sizeof(C->bind_addr),
477 390 "::"); break; "::"); break;
478 391 } }
479 392 } }
480 393 } }
481 394 } }
482 395
483 switch (Conns[slot].sock_domain) {
396 switch (C->sock_domain) {
484 397 case PF_INET: case PF_INET:
485 /* for connection socket */
486 if (strlen(Conns[slot].addr) > 0) {
487 memset(&sa, 0, sizeof(sa));
488 sa.sin_family = AF_INET;
489 ret = inet_pton(AF_INET, Conns[slot].addr, &sa.sin_addr);
490 if (ret < 0) {
491 snprintf(Conn_error, sizeof(Conn_error),
492 "inet_pton(%s) failed", Conns[slot].addr);
493 return -1;
494 }
495 sa.sin_port = htons(Conns[slot].port);
496 psa = (struct sockaddr *) &sa;
497 sock_len = sizeof(sa);
498 }
499
500 398 /* for binding socket */ /* for binding socket */
501 if (strlen(Conns[slot].bind_addr) > 0) {
399 if (C->bind_addr[0] != '\0') {
502 400 memset(&bind_sa, 0, sizeof(bind_sa)); memset(&bind_sa, 0, sizeof(bind_sa));
503 401 bind_sa.sin_family = AF_INET; bind_sa.sin_family = AF_INET;
504 ret = inet_pton(AF_INET, Conns[slot].bind_addr, &bind_sa.sin_addr);
402 ret = inet_pton(AF_INET, C->bind_addr, &bind_sa.sin_addr);
505 403 if (ret < 0) { if (ret < 0) {
506 404 snprintf(Conn_error, sizeof(Conn_error), snprintf(Conn_error, sizeof(Conn_error),
507 "inet_pton(%s) failed", Conns[slot].bind_addr);
405 "inet_pton(%s) failed", C->bind_addr);
508 406 return -1; return -1;
509 407 } }
510 bind_sa.sin_port = htons(Conns[slot].bind_port);
408 bind_sa.sin_port = htons(C->bind_port);
511 409 bind_psa = (struct sockaddr *) &bind_sa; bind_psa = (struct sockaddr *) &bind_sa;
512 410 bind_sock_len = sizeof(bind_sa); bind_sock_len = sizeof(bind_sa);
513 411 } }
514 412
515 if (Conns[slot].sock_type == SOCK_STREAM) {
413 if (C->sock_type == SOCK_STREAM) {
516 414 first_state = CONN_STATE_LISTEN; first_state = CONN_STATE_LISTEN;
517 } else if (Conns[slot].sock_type == SOCK_DGRAM) {
415 } else if (C->sock_type == SOCK_DGRAM) {
518 416 do_listen = 0; do_listen = 0;
519 417 first_state = CONN_STATE_OPEN; first_state = CONN_STATE_OPEN;
520 418 } }
521 419 break; break;
522 420
523 421 case PF_INET6: case PF_INET6:
524 /* for connection socket */
525 if (strlen(Conns[slot].addr) > 0) {
526 memset(&sa6, 0, sizeof(sa6));
527 sa6.sin6_family = AF_INET6;
528 ret = inet_pton(AF_INET6, Conns[slot].addr, &sa6.sin6_addr);
529 if (ret < 0) {
530 snprintf(Conn_error, sizeof(Conn_error),
531 "inet_pton(%s) failed", Conns[slot].addr);
532 return -1;
533 }
534 sa6.sin6_port = htons(Conns[slot].port);
535 psa = (struct sockaddr *) &sa6;
536 sock_len = sizeof(sa6);
537 }
538
539 422 /* for binding socket */ /* for binding socket */
540 if (strlen(Conns[slot].bind_addr) > 0) {
423 if (C->bind_addr[0] != '\0') {
541 424 memset(&bind_sa6, 0, sizeof(bind_sa6)); memset(&bind_sa6, 0, sizeof(bind_sa6));
542 425 bind_sa6.sin6_family = AF_INET6; bind_sa6.sin6_family = AF_INET6;
543 ret = inet_pton(AF_INET6, Conns[slot].bind_addr, &bind_sa6.sin6_addr);
426 ret = inet_pton(AF_INET6, C->bind_addr, &bind_sa6.sin6_addr);
544 427 if (ret < 0) { if (ret < 0) {
545 428 snprintf(Conn_error, sizeof(Conn_error), snprintf(Conn_error, sizeof(Conn_error),
546 "inet_pton(%s) failed", Conns[slot].bind_addr);
429 "inet_pton(%s) failed", C->bind_addr);
547 430 return -1; return -1;
548 431 } }
549 bind_sa6.sin6_port = htons(Conns[slot].bind_port);
432 bind_sa6.sin6_port = htons(C->bind_port);
550 433 bind_psa = (struct sockaddr *) &bind_sa6; bind_psa = (struct sockaddr *) &bind_sa6;
551 434 bind_sock_len = sizeof(bind_sa6); bind_sock_len = sizeof(bind_sa6);
552 435 } }
553 436
554 if (Conns[slot].sock_type == SOCK_STREAM) {
437 if (C->sock_type == SOCK_STREAM) {
555 438 first_state = CONN_STATE_LISTEN; first_state = CONN_STATE_LISTEN;
556 } else if (Conns[slot].sock_type == SOCK_DGRAM) {
439 } else if (C->sock_type == SOCK_DGRAM) {
557 440 do_listen = 0; do_listen = 0;
558 441 first_state = CONN_STATE_OPEN; first_state = CONN_STATE_OPEN;
559 442 } }
560 443 break; break;
561 444
562 445 case PF_PACKET: case PF_PACKET:
563 do_bind = 0;
446 /*do_bind = 0; TODO? */
564 447 do_listen = 0; /*TODO:check this!*/ do_listen = 0; /*TODO:check this!*/
565 448 first_state = CONN_STATE_OPEN; first_state = CONN_STATE_OPEN;
566 449 break; break;
567 450
568 451 default: default:
569 452 snprintf(Conn_error, sizeof(Conn_error), snprintf(Conn_error, sizeof(Conn_error),
570 "Invalid domain [%d]!", Conns[slot].sock_domain);
453 "Invalid domain [%d]!", C->sock_domain);
571 454 return -1; return -1;
572 455 } }
573 456
574 Conns[slot].fd = socket(Conns[slot].sock_domain, Conns[slot].sock_type, Conns[slot].sock_protocol);
575 if (Conns[slot].fd == -1) {
457 C->fd = socket(C->sock_domain, C->sock_type,
458 C->sock_protocol);
459 if (C->fd == -1) {
576 460 snprintf(Conn_error, sizeof(Conn_error), snprintf(Conn_error, sizeof(Conn_error),
577 461 "Cannot create socket (%s, %s, %s) [%s]", "Cannot create socket (%s, %s, %s) [%s]",
578 Conn_domain(&Conns[slot]), Conn_type(&Conns[slot]),
579 Conn_get_socket_protocol(&Conns[slot]),
462 Conn_domain(C), Conn_type(C),
463 Conn_get_socket_protocol(C),
580 464 strerror(errno)); strerror(errno));
581 465 return -1; return -1;
582 466 } }
583 467
584 Conn_setnonblock(Conns[slot].fd);
468 Conn_setnonblock(C->fd);
585 469
586 if (Conns[slot].sock_domain == PF_INET6) {
470 if (C->sock_domain == PF_INET6) {
587 471 #ifndef IPV6_V6ONLY #ifndef IPV6_V6ONLY
588 472 #define IPV6_V6ONLY 26 #define IPV6_V6ONLY 26
589 473 #endif #endif
590 474 i = 1; i = 1;
591 setsockopt(Conns[slot].fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&i, sizeof(i));
475 setsockopt(C->fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&i, sizeof(i));
592 476 } }
593 477
594 if (strlen(Conns[slot].bind_addr) > 0) {
478 if (strlen(C->bind_addr) > 0) {
595 479 i = 1; i = 1;
596 setsockopt(Conns[slot].fd, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i));
480 setsockopt(C->fd, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i));
597 481
598 ret = bind(Conns[slot].fd, bind_psa, bind_sock_len);
482 ret = bind(C->fd, bind_psa, bind_sock_len);
599 483 if (ret < 0) { if (ret < 0) {
600 484 snprintf(Conn_error, sizeof(Conn_error), snprintf(Conn_error, sizeof(Conn_error),
601 485 "Cannot bind on %s/%d [%s]", "Cannot bind on %s/%d [%s]",
602 Conns[slot].bind_addr, Conns[slot].bind_port, strerror(errno));
486 C->bind_addr, C->bind_port, strerror(errno));
603 487 goto out_free_fd; goto out_free_fd;
604 488 } }
605 489 } }
606 490
607 Conns[slot].events = CONN_POLLIN;
608 Conns[slot].revents = 0;
491 C->events = EPOLLIN;
492 C->revents = 0;
609 493
610 494 if (do_listen == 1) if (do_listen == 1)
611 listen(Conns[slot].fd, 4096);
495 listen(C->fd, 4096);
612 496
613 497 if (do_connect == 1) { if (do_connect == 1) {
614 498 /*TODO:replace connect_a with OPEN?! */ /*TODO:replace connect_a with OPEN?! */
615 499 first_state = CONN_STATE_CONNECT_a; first_state = CONN_STATE_CONNECT_a;
616 Conns[slot].events |= CONN_POLLOUT;
500 C->events |= EPOLLOUT;
617 501 } }
618 502
619 ret = Conn_engine_add_obj(&Conns[slot]);
503 ret = Conn_add_obj(C);
620 504 if (ret != 0) if (ret != 0)
621 505 goto out_free_fd; goto out_free_fd;
622 506
623 507 if (do_connect == 1) if (do_connect == 1)
624 508 Conn_pending++; Conn_pending++;
625 509
626 Conns[slot].state = first_state;
510 C->state = first_state;
627 511
628 512 return 0; return 0;
629 513
 
... ... struct Conn *Conn_connect(const int domain, const int type, const char *addr,
685 569 int ret; int ret;
686 570
687 571 Log(8, "%s(%s, %d)\n", Log(8, "%s(%s, %d)\n",
688 __FUNCTION__, addr, port);
572 __func__, addr, port);
689 573
690 574 X = Conn_alloc(); X = Conn_alloc();
691 575 if (!X) if (!X)
 
... ... struct Conn *Conn_connect(const int domain, const int type, const char *addr,
705 589 static void Conn_accept(const unsigned int slot) static void Conn_accept(const unsigned int slot)
706 590 { {
707 591 int fd, err; int fd, err;
708 struct sockaddr *pca, *psa;
709 struct sockaddr_in ca4, sa4;
710 struct sockaddr_in6 ca6, sa6;
711 socklen_t cax_len, sax_len;
592 struct sockaddr *pca;
593 struct sockaddr_in ca4;
594 struct sockaddr_in6 ca6;
595 socklen_t cax_len;
712 596 struct Conn *X; struct Conn *X;
713 597
714 598 Log(10, "Accepting a connection on slot=%u via %s/%d, type %s, domain %s" Log(10, "Accepting a connection on slot=%u via %s/%d, type %s, domain %s"
715 599 ", protocol %s.\n", ", protocol %s.\n",
716 slot, Conns[slot].bind_addr, Conns[slot].bind_port, Conn_type(&Conns[slot]),
717 Conn_domain(&Conns[slot]), Conn_get_socket_protocol(&Conns[slot]));
600 slot, C->bind_addr, C->bind_port, Conn_type(C),
601 Conn_domain(C), Conn_get_socket_protocol(C));
718 602
719 switch(Conns[slot].sock_domain) {
603 switch(C->sock_domain) {
720 604 case PF_INET: case PF_INET:
721 605 pca = (struct sockaddr *) &ca4; pca = (struct sockaddr *) &ca4;
722 606 cax_len = sizeof(ca4); cax_len = sizeof(ca4);
723 psa = (struct sockaddr *) &sa4;
724 sax_len = sizeof(sa4);
725 break;
607 break;
726 608
727 609 case PF_INET6: case PF_INET6:
728 610 pca = (struct sockaddr *) &ca6; pca = (struct sockaddr *) &ca6;
729 611 cax_len = sizeof(ca6); cax_len = sizeof(ca6);
730 psa = (struct sockaddr *) &sa6;
731 sax_len = sizeof(sa6);
732 break;
612 break;
733 613
734 614 default: default:
735 615 snprintf(Conn_error, sizeof(Conn_error), snprintf(Conn_error, sizeof(Conn_error),
736 616 "Cannot deal with domain %d.", "Cannot deal with domain %d.",
737 Conns[slot].sock_domain);
617 C->sock_domain);
738 618 Conn_error_raise(slot, EAFNOSUPPORT); Conn_error_raise(slot, EAFNOSUPPORT);
739 619 return; return;
740 620 } }
741 621
742 fd = accept4(Conns[slot].fd, pca, &cax_len, SOCK_NONBLOCK | SOCK_CLOEXEC);
622 fd = accept4(C->fd, pca, &cax_len,
623 SOCK_NONBLOCK | SOCK_CLOEXEC);
743 624 if (fd == -1) { if (fd == -1) {
744 625 if (errno == EAGAIN) if (errno == EAGAIN)
745 626 return; return;
746 627
747 628 /* TODO: ratelimit */ /* TODO: ratelimit */
748 Log(9, "WARN: Cannot accept on fd %d [%s].\n",
749 Conns[slot].fd, strerror(errno));
629 Log(2, "WARN: Cannot accept on fd %d [%s].\n",
630 C->fd, strerror(errno));
750 631 /* /*
751 632 * We must not raise an error here because we will close the * We must not raise an error here because we will close the
752 633 * master socket! * master socket!
 
... ... static void Conn_accept(const unsigned int slot)
768 649 X->type = CONN_TYPE_P2P; X->type = CONN_TYPE_P2P;
769 650 X->state = CONN_STATE_OPEN; X->state = CONN_STATE_OPEN;
770 651 X->time_open = Conn_now; X->time_open = Conn_now;
771 X->via = Conns[slot].id;
772 X->events = CONN_POLLIN | CONN_POLLOUT;
652 X->via = C->id;
653 X->events = EPOLLIN | EPOLLOUT;
773 654
774 Conn_set_socket_domain(X, Conns[slot].sock_domain);
775 Conn_set_socket_type(X, Conns[slot].sock_type);
776 Conn_set_socket_protocol(X, Conns[slot].sock_protocol);
655 Conn_set_socket_domain(X, C->sock_domain);
656 Conn_set_socket_type(X, C->sock_type);
657 Conn_set_socket_protocol(X, C->sock_protocol);
777 658
778 659 X->flags |= CONN_ADDR_LOCAL_DIRTY | CONN_ADDR_REMOTE_DIRTY; X->flags |= CONN_ADDR_LOCAL_DIRTY | CONN_ADDR_REMOTE_DIRTY;
779 660
780 if (Conns[slot].wp != NULL) {
781 struct Conn_wpool *wp = Conns[slot].wp;
782 struct Conn_wpool_worker *w = &wp->wi[0];
783 struct epoll_event ev;
784
785 memset(&ev, 0, sizeof(struct epoll_event));
786 ev.events = X->events;
787 ev.data.u32 = X->slot;
788 err = epoll_ctl(w->epoll_fd, EPOLL_CTL_ADD, X->fd, &ev);
661 if (C->wp != NULL) {
662 err = Conn_wpool_enqueue(C->wp, X);
789 663 if (err != 0) { if (err != 0) {
790 Conn_error_raise(slot, err);
664 Conn_error_raise(slot, CONN_ERROR_INTERNAL);
791 665 Conn_free_intern(X->slot); Conn_free_intern(X->slot);
792 666 return; return;
793 667 } }
794 668 /* TODO: send signaling to thread to call accept callback */ /* TODO: send signaling to thread to call accept callback */
795 669 /* TODO: maybe we want to pass the fd also by signaling channel */ /* TODO: maybe we want to pass the fd also by signaling channel */
796 670 } else { } else {
797 err = Conn_engine_add_obj(X);
671 err = Conn_add_obj(X);
798 672 if (err != 0) { if (err != 0) {
799 673 Conn_error_raise(slot, err); Conn_error_raise(slot, err);
800 674 Conn_free_intern(X->slot); Conn_free_intern(X->slot);
801 675 return; return;
802 676 } }
803 677
804 if (Conns[slot].cb_accept)
805 Conns[slot].cb_accept(X);
678 if (C->cb_accept)
679 C->cb_accept(X);
806 680 else if (Conn_accept_cb != NULL) else if (Conn_accept_cb != NULL)
807 681 Conn_accept_cb(X); Conn_accept_cb(X);
808 682 } }
 
... ... static void Conn_accept_allow(void)
820 694 return; return;
821 695
822 696 Log(10, "%s: Turning accept allow from %d to %d...\n", Log(10, "%s: Turning accept allow from %d to %d...\n",
823 __FUNCTION__, Conn_accept_is_allowed_last,
697 __func__, Conn_accept_is_allowed_last,
824 698 Conn_accept_is_allowed); Conn_accept_is_allowed);
825 699
826 700 for (slot = 0; slot < Conn_no; slot++) { for (slot = 0; slot < Conn_no; slot++) {
827 if (Conns[slot].type != CONN_TYPE_MASTER)
701 if (C->type != CONN_TYPE_MASTER)
828 702 continue; continue;
829 703
830 704 if (Conn_accept_is_allowed == 0) if (Conn_accept_is_allowed == 0)
831 Conns[slot].events &= ~CONN_POLLIN;
705 C->events &= ~EPOLLIN;
832 706 else else
833 Conns[slot].events |= CONN_POLLIN;
707 C->events |= EPOLLIN;
834 708
835 Conn_engine_chg_obj(&Conns[slot]);
709 Conn_change_obj(C);
836 710 } }
837 711
838 712 Conn_accept_is_allowed_last = Conn_accept_is_allowed; Conn_accept_is_allowed_last = Conn_accept_is_allowed;
 
... ... static void Conn_band_update(const unsigned int slot)
846 720 long diff; long diff;
847 721
848 722 /* no need */ /* no need */
849 if (Conns[slot].band_width == 0)
723 if (C->band_width == 0)
850 724 return; return;
851 725
852 diff = (Conn_now.tv_sec - Conns[slot].band_lasttime.tv_sec) * 1000000;
853 diff += Conn_now.tv_usec - Conns[slot].band_lasttime.tv_usec;
726 diff = (Conn_now.tv_sec - C->band_lasttime.tv_sec) * 1000000;
727 diff += Conn_now.tv_usec - C->band_lasttime.tv_usec;
854 728 diff /= 100000; diff /= 100000;
855 729
856 730 /* already added in this hundred of milisecond? */ /* already added in this hundred of milisecond? */
 
... ... static void Conn_band_update(const unsigned int slot)
861 735 if (diff < 0) if (diff < 0)
862 736 diff = 1; diff = 1;
863 737
864 Conns[slot].band_lasttime = Conn_now;
865 Conns[slot].band_tokens += diff * Conns[slot].band_width / 10;
866 if (Conns[slot].band_tokens > Conns[slot].band_factor * Conns[slot].band_width)
867 Conns[slot].band_tokens = Conns[slot].band_factor * Conns[slot].band_width;
738 C->band_lasttime = Conn_now;
739 C->band_tokens += diff * C->band_width / 10;
740 if (C->band_tokens > C->band_factor * C->band_width)
741 C->band_tokens = C->band_factor * C->band_width;
868 742
869 Conns[slot].events |= CONN_POLLOUT;
870 Conn_engine_chg_obj(&Conns[slot]);
743 C->events |= EPOLLOUT;
744 Conn_change_obj(C);
871 745
872 746 Log(debug_band, "\t\tBAND: slot=%u, id=%llu, added tokens -> %u.\n", Log(debug_band, "\t\tBAND: slot=%u, id=%llu, added tokens -> %u.\n",
873 slot, Conns[slot].id, Conns[slot].band_tokens);
747 slot, C->id, C->band_tokens);
874 748 } }
875 749
876 750 /* /*
 
... ... int Conn_band(struct Conn *C, const unsigned int width,
885 759 slot = C->slot; slot = C->slot;
886 760
887 761 Log(11, "\tConn_band: slot=%u, id=%llu, width=%u, factor=%u.\n", Log(11, "\tConn_band: slot=%u, id=%llu, width=%u, factor=%u.\n",
888 slot, Conns[slot].id, width, factor);
762 slot, C->id, width, factor);
889 763
890 Conns[slot].band_lasttime = Conn_now;
891 Conns[slot].band_width = width;
892 Conns[slot].band_factor = factor;
893 Conns[slot].band_tokens = factor * width;
764 C->band_lasttime = Conn_now;
765 C->band_width = width;
766 C->band_factor = factor;
767 C->band_tokens = factor * width;
894 768
895 769 Log(debug_band, "\t\tBAND: lasttime=%d.%06d, width=%u, factor=%u, tokens=%u\n", Log(debug_band, "\t\tBAND: lasttime=%d.%06d, width=%u, factor=%u, tokens=%u\n",
896 Conns[slot].band_lasttime.tv_sec, Conns[slot].band_lasttime.tv_usec,
897 Conns[slot].band_width, Conns[slot].band_factor, Conns[slot].band_tokens);
770 C->band_lasttime.tv_sec, C->band_lasttime.tv_usec,
771 C->band_width, C->band_factor, C->band_tokens);
898 772
899 773 return 0; return 0;
900 774 } }
 
... ... static void Conn_trytoconnect(void)
907 781 char port[8]; char port[8];
908 782
909 783 Log(8, "%s: Conn_pending=%d\n", Log(8, "%s: Conn_pending=%d\n",
910 __FUNCTION__, Conn_pending);
784 __func__, Conn_pending);
911 785
912 786 for (i = Conn_no - 1; i >= 0; i--) { for (i = Conn_no - 1; i >= 0; i--) {
913 787 if (Conns[i].type != CONN_TYPE_P2P) if (Conns[i].type != CONN_TYPE_P2P)
 
... ... static void Conn_trytoconnect(void)
958 832 Conn_setnonblock(Conns[i].fd); Conn_setnonblock(Conns[i].fd);
959 833
960 834 /* Need POLLOUT to signal when the connection was done. */ /* Need POLLOUT to signal when the connection was done. */
961 Conns[i].events |= (CONN_POLLIN | CONN_POLLOUT);
962 ret = Conn_engine_add_obj(&Conns[i]);
835 Conns[i].events |= (EPOLLIN | EPOLLOUT);
836 ret = Conn_add_obj(&Conns[i]);
963 837 if (ret != 0) { if (ret != 0) {
964 838 Conns[i].state = CONN_STATE_ERROR; Conns[i].state = CONN_STATE_ERROR;
965 839 Conns[i].error_state = CONN_ERROR_SOCKET; Conns[i].error_state = CONN_ERROR_SOCKET;
 
... ... static void Conn_trytoconnect(void)
990 864 } }
991 865
992 866 Log(8, "%s: After, Conn_pending=%d\n", Log(8, "%s: After, Conn_pending=%d\n",
993 __FUNCTION__, Conn_pending);
994 }
995
996 static void Conn_send_cb_i(const unsigned int slot)
997 {
998 ssize_t n;
999 unsigned int max;
1000 int count;
1001 char *buf;
1002 int xerrno;
1003 char *dump;
1004
1005 Log(10, "Conn_send_cb_i slot=%u, id=%llu, fd=%d"
1006 ", head=%u, tail=%u, size=%u...\n",
1007 slot, Conns[slot].id, Conns[slot].fd,
1008 Conns[slot].obuf_head, Conns[slot].obuf_tail,
1009 Conns[slot].obuf_size);
1010
1011 if (Conns[slot].obuf == NULL)
1012 abort();
1013
1014 buf = Conns[slot].obuf + Conns[slot].obuf_head;
1015 count = Conns[slot].obuf_tail - Conns[slot].obuf_head;
1016 if (count == 0) {
1017 Log(13, "\tEmpty output buffer!\n");
1018 return;
1019 }
1020
1021 max = count;
1022 if ((Conn_max_send > 0) && (max > Conn_max_send))
1023 max = Conn_max_send;
1024
1025 /* bandwidth */
1026 if (Conns[slot].band_width > 0) {
1027 if (max > Conns[slot].band_tokens)
1028 max = Conns[slot].band_tokens;
1029 if (max == 0) {
1030 Log(debug_band, "\tBAND: Suspend 100ms the C (no tokens)!\n");
1031 Conns[slot].events &= ~CONN_POLLOUT;
1032 Conn_engine_chg_obj(&Conns[slot]);
1033 return;
1034 }
1035 }
1036
1037 again:
1038 Log(10, "\tsend(fd=%d, buf (head=%u, tail=%u), max=%d (count=%d), 0)...\n",
1039 Conns[slot].fd, Conns[slot].obuf_head,
1040 Conns[slot].obuf_tail, max, count);
1041 n = send(Conns[slot].fd, buf, max, 0);
1042 xerrno = errno;
1043 if ((n == -1) && (errno == EINTR))
1044 goto again;
1045
1046 if ((n == -1) && (errno == EAGAIN))
1047 return;
1048
1049 Log(10, "\tSent %d bytes [head=%d tail=%d]\n",
1050 n, Conns[slot].obuf_head, Conns[slot].obuf_tail);
1051 if (Conn_level >= 10) {
1052 dump = Conn_dump(buf, n);
1053 Log(0, "\t%s\n", dump);
1054 free(dump);
1055 }
1056
1057 if (n > 0) {
1058 Conns[slot].tsend = Conn_now;
1059 if (n < count) {
1060 Conns[slot].obuf_head += n;
1061 } else {
1062 Conns[slot].obuf_head = 0;
1063 Conns[slot].obuf_tail = 0;
1064 }
1065
1066 Conns[slot].bo += n;
1067 if (Conns[slot].band_width > 0) {
1068 Conns[slot].band_tokens -= n;
1069 Log(debug_band, "\t%s: BAND: Remove %d tokens -> %u...\n",
1070 __FUNCTION__,
1071 n, Conns[slot].band_tokens);
1072 }
1073 } else {
1074 Log(0, "\tError in sending [%s]\n",
1075 strerror(errno));
1076 Conns[slot].error_state = CONN_ERROR_SEND;
1077 Conns[slot].xerrno = xerrno;
1078 }
1079 }
1080
1081 static void Conn_recv_cb_i(const unsigned int slot)
1082 {
1083 ssize_t n;
1084 unsigned int max;
1085 int r, xerrno;
1086 char *dump;
1087
1088 Log(10, "Conn_recv_cb_i: slot=%u, id=%llu, fd=%d"
1089 ", head=%u, tail=%u, size=%u...\n",
1090 slot, Conns[slot].id, Conns[slot].fd,
1091 Conns[slot].ibuf_head, Conns[slot].ibuf_tail, Conns[slot].ibuf_size);
1092
1093 if (Conns[slot].ibuf_tail == Conns[slot].ibuf_size) {
1094 r = Conn_try_expand_buf(slot, 1, Conn_default_ibuf);
1095 if (r != 0) {
1096 Conns[slot].error_state = CONN_ERROR_MEM;
1097 /* TODO: Just suspend connection for 1 second instead */
1098 return;
1099 }
1100 }
1101
1102 max = Conns[slot].ibuf_size - Conns[slot].ibuf_tail;
1103 if ((Conn_max_recv > 0) && (max > Conn_max_recv))
1104 max = Conn_max_recv;
1105
1106 while (1) {
1107 n = recv(Conns[slot].fd, Conns[slot].ibuf + Conns[slot].ibuf_tail, max, 0);
1108 if ((n == -1) && (errno == EINTR))
1109 continue;
1110
1111 xerrno = errno;
1112
1113 break;
1114 }
1115
1116 Log(10, "\tReceived %d bytes.\n", n);
1117
1118 if (n > 0) {
1119 if (Conn_level >= 10) {
1120 dump = Conn_dump(Conns[slot].ibuf + Conns[slot].ibuf_tail, n);
1121 Log(0, "\t%s\n", dump);
1122 free(dump);
1123 }
1124
1125 Conns[slot].ibuf_tail += n;
1126
1127 Conns[slot].bi += n;
1128 Conns[slot].trecv = Conn_now;
1129
1130 if (Conns[slot].cb_data)
1131 Conns[slot].cb_data(&Conns[slot]);
1132 else if (Conn_data_cb)
1133 Conn_data_cb(&Conns[slot]);
1134 } else if (n == 0) {
1135 Log(10, "\tRemote closed sending side.\n");
1136 Conns[slot].error_state = CONN_ERROR_HANGUP;
1137 /* TODO: Maybe we should just cut INPUT and do not hangup */
1138 } else {
1139 Log(0, "\tError receiving [%s]\n",
1140 strerror(errno));
1141 Conns[slot].error_state = CONN_ERROR_RECV;
1142 Conns[slot].xerrno = xerrno;
1143 }
1144 }
1145
1146 /*
1147 * Callback that is called for every connection
1148 */
1149 static void Conn_poll_cb(const unsigned int slot, int revents)
1150 {
1151 char poll_status[16];
1152
1153 Conn_poll_status(revents, poll_status);
1154 Log(12, "\t%s: slot=%u, id=%llu, revents=%s.\n",
1155 __FUNCTION__, slot, Conns[slot].id, poll_status);
1156 Conns[slot].revents = revents;
1157
1158 if (Conn_level >= 12)
1159 Log(12, "\t\t%s\n", Conn_status_slot(slot));
1160
1161 /* We should not have events on a free cell */
1162 if (Conns[slot].state == CONN_STATE_FREE) {
1163 Log(12, "\t\tBUG! Events on a FREE slot!\n");
1164 return;
1165 }
1166
1167 if (revents & CONN_POLLHUP) {
1168 Conns[slot].error_state = CONN_ERROR_HANGUP;
1169 /* TODO: Add it to the close list to speed it up */
1170 }
1171
1172 if (revents & CONN_POLLERR) {
1173 Conns[slot].error_state = CONN_ERROR_POLL;
1174 Conns[slot].xerrno = 0; /* TODO: unknown error? */
1175 /* TODO: CONN_ERROR_POLL is correct here? */
1176 }
1177
1178 /* First, test we have a new connection */
1179 if ((revents & CONN_POLLOUT)
1180 && (Conn_ignore(slot) == 0)) {
1181
1182 if (Conn_oqlen(&Conns[slot]) == 0) {
1183 /* Nothing to send */
1184 revents &= ~CONN_POLLOUT;
1185 Conns[slot].events &= ~CONN_POLLOUT;
1186 Conn_engine_chg_obj(&Conns[slot]);
1187 }
1188
1189 if (Conns[slot].state == CONN_STATE_CONNECT_b) {
1190 Log(12, "\t\tWe just established a connection.\n");
1191
1192 Conns[slot].state = CONN_STATE_OPEN;
1193
1194 Conns[slot].flags |= CONN_ADDR_LOCAL_DIRTY;
1195
1196 Conns[slot].time_open = Conn_now;
1197
1198 if (Conns[slot].cb_connected != NULL)
1199 Conns[slot].cb_connected(&Conns[slot]);
1200 else if (Conn_connected_cb)
1201 Conn_connected_cb(&Conns[slot]);
1202 }
1203 }
1204
1205 /* Second, test for hangup or input */
1206 if ((revents & CONN_POLLIN)
1207 && (Conn_ignore(slot) == 0)) {
1208 Log(12, "\t\tWe have input...\n");
1209 if (Conns[slot].type == CONN_TYPE_MASTER) {
1210 /* C pointer can change under us in Conn_accept->Conn_grow */
1211 Conn_accept(slot);
1212 } else {
1213 if (Conns[slot].cb_recv)
1214 Conns[slot].cb_recv(&Conns[slot]);
1215 else if (Conn_recv_cb != NULL)
1216 Conn_recv_cb(&Conns[slot]);
1217 else
1218 Conn_recv_cb_i(slot);
1219 }
1220 }
1221
1222 if ((revents & CONN_POLLOUT)
1223 && (Conn_ignore(slot) == 0)) {
1224 Log(12, "\t\tWe can send data...\n");
1225 if (Conns[slot].state == CONN_STATE_OPEN) {
1226 if (Conns[slot].cb_send)
1227 Conns[slot].cb_send(&Conns[slot]);
1228 else if (Conn_send_cb != NULL)
1229 Conn_send_cb(&Conns[slot]);
1230 else
1231 Conn_send_cb_i(slot);
1232
1233 if (Conn_oqlen(&Conns[slot]) == 0) {
1234 if (Conns[slot].flags & CONN_FLAGS_CLOSE_AFTER_SEND) {
1235 Conns[slot].state = CONN_STATE_ERROR;
1236 Conns[slot].error_state = CONN_ERROR_USERREQ;
1237 } else {
1238 Conns[slot].events &= ~CONN_POLLOUT;
1239 Conn_epoll_chg_obj(&Conns[slot]);
1240 }
1241 }
1242 }
1243 }
867 __func__, Conn_pending);
1244 868 } }
1245 869
1246 870 /* /*
 
... ... static void Conn_move_slot(const unsigned int dst, const unsigned int src)
1254 878 return; return;
1255 879
1256 880 Log(10, "\t\t%s: Moving id %llu from slot=%u to slot=%d...\n", Log(10, "\t\t%s: Moving id %llu from slot=%u to slot=%d...\n",
1257 __FUNCTION__, Conns[src].id, src, dst);
881 __func__, Conns[src].id, src, dst);
1258 882
1259 883 /* We need to save old location because of usefull pointers. */ /* We need to save old location because of usefull pointers. */
1260 884 tmp = Conns[dst]; tmp = Conns[dst];
 
... ... static void Conn_move_slot(const unsigned int dst, const unsigned int src)
1264 888 Conns[dst].slot = dst; Conns[dst].slot = dst;
1265 889 Conns[src].slot = src; Conns[src].slot = src;
1266 890
1267 Conn_engine_move_slot(dst, src);
891 Conn_change_obj(&Conns[dst]);
1268 892 } }
1269 893
1270 894 /* /*
 
... ... int Conn_poll(const int timeout)
1279 903 unsigned int slot, last; unsigned int slot, last;
1280 904
1281 905 Log(9, "%s: timeout=%d Conn_no=%d, Conn_work_to_do=%u)\n", Log(9, "%s: timeout=%d Conn_no=%d, Conn_work_to_do=%u)\n",
1282 __FUNCTION__, timeout, Conn_no, Conn_work_to_do);
906 __func__, timeout, Conn_no, Conn_work_to_do);
1283 907
1284 908 if (timeout > 1000) if (timeout > 1000)
1285 909 timeout2 = 1000; timeout2 = 1000;
 
... ... int Conn_poll(const int timeout)
1294 918
1295 919 if (Conn_work_to_do == 0) { if (Conn_work_to_do == 0) {
1296 920 Log(9, "%s: work_to_do is 0, so return 0!\n", Log(9, "%s: work_to_do is 0, so return 0!\n",
1297 __FUNCTION__);
921 __func__);
1298 922 return 0; return 0;
1299 923 } }
1300 924
1301 925 if (Conn_pending > 0) if (Conn_pending > 0)
1302 926 Conn_trytoconnect(); Conn_trytoconnect();
1303 927
1304 ret = Conn_engine_epoll_poll(timeout2, Conn_poll_cb);
928 ret = Conn_dispatch_events(timeout2, Conn_poll_cb);
1305 929 if (ret < 0) if (ret < 0)
1306 930 return -1; return -1;
1307 931
 
... ... int Conn_poll(const int timeout)
1315 939 last = Conn_no - 1; last = Conn_no - 1;
1316 940
1317 941 /* Closing connection if it is in error state. */ /* Closing connection if it is in error state. */
1318 if (Conns[slot].error_state > 0) {
942 if (C->error_state > 0) {
1319 943 Log(11, "\tSlot=%u in error [%s], move and free it.\n", Log(11, "\tSlot=%u in error [%s], move and free it.\n",
1320 slot, Conn_errno(&Conns[slot]));
944 slot, Conn_errno(C));
1321 945 Conn_move_slot(slot, last); Conn_move_slot(slot, last);
1322 946 Conn_free_intern(last); Conn_free_intern(last);
1323 947 continue; continue;
1324 948 } }
1325 949
1326 950 /* No commit done yet */ /* No commit done yet */
1327 if (Conns[slot].state == CONN_STATE_EMPTY) {
951 if (C->state == CONN_STATE_EMPTY) {
1328 952 slot++; slot++;
1329 953 continue; continue;
1330 954 } }
1331 955
1332 if (Conns[slot].state == CONN_STATE_FREE) {
956 if (C->state == CONN_STATE_FREE) {
1333 957 /* Must not happen! Probably stale events. */ /* Must not happen! Probably stale events. */
1334 958 Log(9, "\tBUG! Slot is in FREE state and has events!\n"); Log(9, "\tBUG! Slot is in FREE state and has events!\n");
1335 959 slot++; slot++;
 
... ... unsigned long long Conn_lifetime(struct Conn *C)
1370 994
1371 995 slot = C->slot; slot = C->slot;
1372 996
1373 return Conn_time_diff(&Conn_now, &Conns[slot].time_open);
997 return Conn_time_diff(&Conn_now, C.time_open);
1374 998 } }
1375 999
1376 1000 /* /*
 
... ... unsigned long long Conn_lifetime(struct Conn *C)
1378 1002 */ */
1379 1003 void Conn_add_wp(struct Conn *C, struct Conn_wpool *wp) void Conn_add_wp(struct Conn *C, struct Conn_wpool *wp)
1380 1004 { {
1381 wp->users++;
1005 Conn_wpool_get(wp);
1382 1006 C->wp = wp; C->wp = wp;
1383 1007 } }
1384 1008
 
... ... void Conn_add_wp(struct Conn *C, struct Conn_wpool *wp)
1387 1011 */ */
1388 1012 void Conn_del_wp(struct Conn *C, struct Conn_wpool *wp) void Conn_del_wp(struct Conn *C, struct Conn_wpool *wp)
1389 1013 { {
1390 Conn_wpool_destroy(wp);
1391 1014 C->wp = NULL; C->wp = NULL;
1015 Conn_wpool_put(wp);
1392 1016 } }
File Conn.h changed (mode: 100644) (index 9823f64..fd37073)
1 1 #ifndef _Conn_h #ifndef _Conn_h
2 2 #define _Conn_h 1 #define _Conn_h 1
3 3
4 #include <Conn_engine_core.h>
4 #include <Conn_core.h>
5 5 #include <Conn_wpool.h> #include <Conn_wpool.h>
6 6
7 extern int Conn_engine_set(const unsigned int engine);
8 7 extern int Conn_init(const unsigned int max); extern int Conn_init(const unsigned int max);
9 8 extern int Conn_shutdown(void); extern int Conn_shutdown(void);
10 9 extern ssize_t Conn_send(struct Conn *C, void *buf, const size_t count); extern ssize_t Conn_send(struct Conn *C, void *buf, const size_t count);
 
... ... extern int Conn_band(struct Conn *C, const unsigned int width,
29 28 const unsigned int factor); const unsigned int factor);
30 29 extern struct Conn *Conn_alloc(void); extern struct Conn *Conn_alloc(void);
31 30 extern int Conn_commit(struct Conn *C); extern int Conn_commit(struct Conn *C);
32 extern char *Conn_sys(void);
33 31 extern unsigned long long Conn_lifetime(struct Conn *C); extern unsigned long long Conn_lifetime(struct Conn *C);
34 32
35 /* wpool */
33 /* wpool - TODO: move to Conn_wpool.c */
36 34 extern void Conn_add_wp(struct Conn *C, struct Conn_wpool *wp); extern void Conn_add_wp(struct Conn *C, struct Conn_wpool *wp);
37 35 extern void Conn_del_wp(struct Conn *C, struct Conn_wpool *wp); extern void Conn_del_wp(struct Conn *C, struct Conn_wpool *wp);
38 36 #endif #endif
File Conn_config.h.in changed (mode: 100644) (index ff7ee33..6367f3c)
1 /*
2 *
3 * Atention! Conn_config.h file is not editable! Edit Conn_config.h.in instead!
4 *
5 */
6
1 7 #define CONN_VERSION "@VER@" #define CONN_VERSION "@VER@"
2 8 #define POLL_FOUND @POLL_FOUND@ #define POLL_FOUND @POLL_FOUND@
3 9 #define EPOLL_FOUND @EPOLL_FOUND@ #define EPOLL_FOUND @EPOLL_FOUND@
4 10
5 11 #define _GNU_SOURCE #define _GNU_SOURCE
12
13
14 /*
15 * How many events slots to pass to kernel in one epoll_wait call
16 */
17 #define CONN_EVENTS_SLOTS 128
18
File Conn_core.c renamed from Conn_engine_core.c (similarity 56%) (mode: 100644) (index f8c3b9f..8a43a5b)
6 6 * Licence: LGPL * Licence: LGPL
7 7 */ */
8 8
9 #include "Conn_engine_core.h"
10
11 #include <sys/epoll.h>
9 #include "Conn_core.h"
12 10
13 11 /* Visible variables */ /* Visible variables */
14 void (*Conn_accept_cb)(struct Conn *C) = NULL;
15 void (*Conn_recv_cb)(struct Conn *C) = NULL;
16 void (*Conn_send_cb)(struct Conn *C) = NULL;
17 void (*Conn_data_cb)(struct Conn *C) = NULL;
18 void (*Conn_close_cb)(struct Conn *C) = NULL;
19 void (*Conn_trigger_cb)(struct Conn *C) = NULL;
20 void (*Conn_error_cb)(struct Conn *C) = NULL;
21 void (*Conn_connected_cb)(struct Conn *C) = NULL;
22 void (*Conn_accept_error_cb)(struct Conn *C) = NULL;
23
24 12 char *(*Conn_status_slot_html_cb)(const struct Conn *C); char *(*Conn_status_slot_html_cb)(const struct Conn *C);
25 13 char *(*Conn_status_cb)(void); char *(*Conn_status_cb)(void);
26 14
15 int Conn_epoll_fd;
16 static struct epoll_event Conn_epoll_events[CONN_EVENTS_SLOTS];
27 17
28 18 unsigned int Conn_max_reached = 0; unsigned int Conn_max_reached = 0;
29 19 unsigned int Conn_default_ibuf = 128; unsigned int Conn_default_ibuf = 128;
 
... ... unsigned int Conn_allocated = 0;
56 46 unsigned long long Conn_id = 1; unsigned long long Conn_id = 1;
57 47 unsigned int Conn_must_stop = 0; unsigned int Conn_must_stop = 0;
58 48
59 char Conn_error[512];
49 static __thread char Conn_error[512];
60 50
61 51 FILE *Conn_Log = NULL; FILE *Conn_Log = NULL;
62 52 int debug_band = 11; int debug_band = 11;
 
... ... int debug_band = 11;
64 54 /* queues */ /* queues */
65 55 struct Conn_queue Conn_queue_free; struct Conn_queue Conn_queue_free;
66 56
57 static struct Conn_cbs Conn_default_cbs =
58 {
59 .accept = Conn_default_cbs_accept,
60 .recv = Conn_default_cbs_recv,
61 .send = Conn_default_cbs_send,
62 .data = NULL,
63 .close = NULL,
64 .trigger = NULL,
65 .error = Conn_default_cbs_error
66 .connected = Conn_default_cbs_connected,
67 .accept_error = NULL
68 };
67 69
68 70 /* Functions */ /* Functions */
69 71
 
... ... char *Conn_errno(const struct Conn *C)
88 90 { {
89 91 static char buf[256]; static char buf[256];
90 92 char *is; char *is;
91 unsigned int slot;
92
93 slot = C->slot;
94 93
95 switch (Conns[slot].error_state) {
94 switch (C->error_state) {
96 95 case CONN_ERROR_USERREQ: is = "user"; break; case CONN_ERROR_USERREQ: is = "user"; break;
97 96 case CONN_ERROR_POLL: is = "poll"; break; case CONN_ERROR_POLL: is = "poll"; break;
98 97 case CONN_ERROR_RECV: is = "recv"; break; case CONN_ERROR_RECV: is = "recv"; break;
 
... ... char *Conn_errno(const struct Conn *C)
111 110 } }
112 111
113 112 snprintf(buf, sizeof(buf), "%s (%s)", snprintf(buf, sizeof(buf), "%s (%s)",
114 is, (Conns[slot].xerrno > 0) ? strerror(Conns[slot].xerrno) : "-");
113 is, (C->xerrno > 0) ? strerror(C->xerrno) : "-");
115 114
116 115 return buf; return buf;
117 116 } }
 
... ... char *Conn_errno(const struct Conn *C)
119 118 /* /*
120 119 * Raise an error. It is just a little helper. * Raise an error. It is just a little helper.
121 120 */ */
122 void Conn_error_raise(const unsigned int slot, const int err)
121 void Conn_error_raise(struct Conn *C, const int err)
123 122 { {
124 123 if (err != 0) if (err != 0)
125 Conns[slot].xerrno = err;
124 C->xerrno = err;
126 125
127 if (Conns[slot].cb_error)
128 Conns[slot].cb_error(&Conns[slot]);
129 else if (Conn_error_cb)
130 Conn_error_cb(&Conns[slot]);
126 if (C->cbs.error)
127 C->cbs.error(C);
131 128 } }
132 129
133 130 /* set noblocking */ /* set noblocking */
 
... ... void Log(const unsigned short level, char *format, ...)
156 153 va_end(ap); va_end(ap);
157 154 } }
158 155
159 char *Conn_dump(const char *buf_src, const int len_src)
156 char *Conn_dump(const void *buf_src0, const int len_src)
160 157 { {
161 158 int i, j; int i, j;
162 159 char tmp[3]; char tmp[3];
163 160 char *buf_dst; char *buf_dst;
164 161 unsigned char c; unsigned char c;
162 const unsigned char *buf_src = buf_src0;
165 163
166 164 if (len_src < 0) if (len_src < 0)
167 165 return strdup("[Error: len < 0]"); return strdup("[Error: len < 0]");
 
... ... char *Conn_dump(const char *buf_src, const int len_src)
191 189
192 190 /* /*
193 191 Log(0, "%s ([%s], %d, [%s], %d\n", Log(0, "%s ([%s], %d, [%s], %d\n",
194 __FUNCTION__, buf_src, len_src, buf_dst, len_dst);
192 __func__, buf_src, len_src, buf_dst, len_dst);
195 193 */ */
196 194
197 195 return buf_dst; return buf_dst;
198 196 } }
199 197
200 char *Conn_dumphex(const char *buf_src, const int len_src)
198 char *Conn_dumphex(const void *buf_src0, const int len_src)
201 199 { {
202 200 int i, j; int i, j;
203 201 char tmp[3]; char tmp[3];
204 202 char *buf_dst; char *buf_dst;
205 203 unsigned char c; unsigned char c;
204 const unsigned char *buf_src = buf_src0;
206 205
207 206 if (len_src < 0) if (len_src < 0)
208 207 return strdup("[Error: len < 0]"); return strdup("[Error: len < 0]");
 
... ... void Conn_debug(FILE *f, const unsigned short debug)
235 234
236 235 char *Conn_state(const struct Conn *C) char *Conn_state(const struct Conn *C)
237 236 { {
238 unsigned int slot;
239
240 slot = C->slot;
241
242 switch (Conns[slot].state) {
237 switch (C->state) {
243 238 case CONN_STATE_FREE: return "FREE"; case CONN_STATE_FREE: return "FREE";
244 239 case CONN_STATE_EMPTY: return "EMPTY"; case CONN_STATE_EMPTY: return "EMPTY";
245 240 case CONN_STATE_OPEN: return "OPEN"; case CONN_STATE_OPEN: return "OPEN";
 
... ... char *Conn_state(const struct Conn *C)
257 252 * what = 0 for out buffer, what = 1 for input buffer * what = 0 for out buffer, what = 1 for input buffer
258 253 * returns 0 if OK, -1 on error * returns 0 if OK, -1 on error
259 254 */ */
260 int Conn_try_expand_buf(const unsigned int slot, const int what,
255 int Conn_try_expand_buf(struct Conn *C, const int what,
261 256 const unsigned int needed) const unsigned int needed)
262 257 { {
263 258 char *p; char *p;
 
... ... int Conn_try_expand_buf(const unsigned int slot, const int what,
267 262 char *pbuf; char *pbuf;
268 263
269 264 if (what == 0) { if (what == 0) {
270 head = Conns[slot].obuf_head;
271 tail = Conns[slot].obuf_tail;
272 old_size = Conns[slot].obuf_size;
273 buf_size = Conns[slot].obuf_size;
265 head = C->obuf_head;
266 tail = C->obuf_tail;
267 old_size = C->obuf_size;
268 buf_size = C->obuf_size;
274 269 max_buf = Conn_max_obuf; max_buf = Conn_max_obuf;
275 pbuf = Conns[slot].obuf;
270 pbuf = C->obuf;
276 271 } else { } else {
277 head = Conns[slot].ibuf_head;
278 tail = Conns[slot].ibuf_tail;
279 old_size = Conns[slot].ibuf_size;
280 buf_size = Conns[slot].ibuf_size;
272 head = C->ibuf_head;
273 tail = C->ibuf_tail;
274 old_size = C->ibuf_size;
275 buf_size = C->ibuf_size;
281 276 max_buf = Conn_max_ibuf; max_buf = Conn_max_ibuf;
282 pbuf = Conns[slot].ibuf;
277 pbuf = C->ibuf;
283 278 } }
284 279
285 280 /* Do we have enough room? */ /* Do we have enough room? */
286 281 if (buf_size - tail >= needed) if (buf_size - tail >= needed)
287 282 return 0; return 0;
288 283
289 Log(10, "\tTry to expand buffer on slot=%u for [%s] needed=%d head=%u tail=%u.\n",
290 slot, what == 0 ? "o" : "i", needed,
291 head, tail);
284 Log(10, "\tTry to expand buffer for [%s] needed=%d head=%u tail=%u.\n",
285 what == 0 ? "o" : "i", needed, head, tail);
292 286
293 287 amount = needed - (buf_size - tail); amount = needed - (buf_size - tail);
294 288
 
... ... int Conn_try_expand_buf(const unsigned int slot, const int what,
315 309 } }
316 310
317 311 if (what == 0) { if (what == 0) {
318 Conns[slot].obuf = p;
319 Conns[slot].obuf_size = hm;
312 C->obuf = p;
313 C->obuf_size = hm;
320 314 Conn_mem_buffers_out += hm - old_size; Conn_mem_buffers_out += hm - old_size;
321 315 } else { } else {
322 Conns[slot].ibuf = p;
323 Conns[slot].ibuf_size = hm;
316 C->ibuf = p;
317 C->ibuf_size = hm;
324 318 Conn_mem_buffers_in += hm - old_size; Conn_mem_buffers_in += hm - old_size;
325 319 } }
326 320
 
... ... void Conn_poll_status(const short ev, char *ret)
344 338 if (ev & EPOLLOUT) ret[i++] = 'O'; if (ev & EPOLLOUT) ret[i++] = 'O';
345 339 if (ev & EPOLLERR) ret[i++] = 'E'; if (ev & EPOLLERR) ret[i++] = 'E';
346 340 if (ev & EPOLLHUP) ret[i++] = 'H'; if (ev & EPOLLHUP) ret[i++] = 'H';
347 if (ev & EPOLLNVAL) ret[i++] = 'V';
348 if (ev & EPOLLRDNORM) ret[i++] = 'N';
349 if (ev & EPOLLRDBAND) ret[i++] = 'B';
350 if (ev & EPOLLWRNORM) ret[i++] = 'n';
351 if (ev & EPOLLWRBAND) ret[i++] = 'b';
352 341 if (ev & EPOLLRDHUP) ret[i++] = 'h'; if (ev & EPOLLRDHUP) ret[i++] = 'h';
353 342 ret[i++] = '\0'; ret[i++] = '\0';
354 343 } }
355 344
356 345 char *Conn_domain(const struct Conn *C) char *Conn_domain(const struct Conn *C)
357 346 { {
358 unsigned int slot;
359
360 slot = C->slot;
361
362 switch (Conns[slot].sock_domain) {
363 case PF_INET: return "IPv4";
364 case PF_INET6: return "IPv6";
365 case PF_PACKET: return "PACKET";
366
367 default: return "?";
347 switch (C->sock_domain) {
348 case PF_INET: return "IPv4";
349 case PF_INET6: return "IPv6";
350 case PF_PACKET: return "PACKET";
351 default: return "?";
368 352 } }
369 353 } }
370 354
371 355 char *Conn_type(const struct Conn *C) char *Conn_type(const struct Conn *C)
372 356 { {
373 unsigned int slot;
374
375 slot = C->slot;
376
377 switch (Conns[slot].sock_type) {
378 case SOCK_STREAM: return "stream";
379 case SOCK_DGRAM: return "dgram";
380 case SOCK_RAW: return "raw";
381
382 default: return "?";
357 switch (C->sock_type) {
358 case SOCK_STREAM: return "stream";
359 case SOCK_DGRAM: return "dgram";
360 case SOCK_RAW: return "raw";
361 default: return "?";
383 362 } }
384 363 } }
385 364
386 365 char *Conn_get_socket_protocol(const struct Conn *C) char *Conn_get_socket_protocol(const struct Conn *C)
387 366 { {
388 unsigned int slot;
389
390 slot = C->slot;
391
392 switch (Conns[slot].sock_protocol) {
393 case IPPROTO_IP: return "IP";
394
395 default: return "?";
367 switch (C->sock_protocol) {
368 case IPPROTO_IP: return "IP";
369 default: return "?";
396 370 } }
397 371 } }
398 372
399 373 static char *Conn_socktype(const struct Conn *C) static char *Conn_socktype(const struct Conn *C)
400 374 { {
401 unsigned int slot;
402
403 slot = C->slot;
404
405 switch (Conns[slot].type) {
406 case CONN_TYPE_UNK: return "unk";
407 case CONN_TYPE_MASTER: return "master";
408 case CONN_TYPE_P2P: return "p2p";
409 default: return "?";
375 switch (C->type) {
376 case CONN_TYPE_UNK: return "unk";
377 case CONN_TYPE_MASTER: return "master";
378 case CONN_TYPE_P2P: return "p2p";
379 default: return "?";
410 380 } }
411 381 } }
412 382
 
... ... void Conn_speed(char *dst, const unsigned int dst_len, const unsigned int speed)
427 397 snprintf(dst, dst_len, "%.2fMBps", sp / 1000 / 1000); snprintf(dst, dst_len, "%.2fMBps", sp / 1000 / 1000);
428 398 } }
429 399
430 char *Conn_status_slot(const unsigned int slot)
400 char *Conn_status_slot(struct Conn *C)
431 401 { {
432 402 static char tmp[1024]; static char tmp[1024];
433 403 char polle[16], pollr[16]; char polle[16], pollr[16];
 
... ... char *Conn_status_slot(const unsigned int slot)
443 413 strcpy(flags_prefix, " ["); strcpy(flags_prefix, " [");
444 414 strcpy(flags_postfix, ""); strcpy(flags_postfix, "");
445 415
446 if (Conns[slot].flags & CONN_FLAGS_AUTO_RECONNECT) {
416 if (C->flags & CONN_FLAGS_AUTO_RECONNECT) {
447 417 strcat(flags, flags_prefix); strcat(flags, flags_prefix);
448 418 snprintf(flags_tmp, sizeof(flags_tmp), "autoreconnect_in_%ld/%u", snprintf(flags_tmp, sizeof(flags_tmp), "autoreconnect_in_%ld/%u",
449 (Conns[slot].tryat == 0) ? 0 : Conns[slot].tryat - Conn_now.tv_sec,
450 Conns[slot].delay);
419 (C->tryat == 0) ? 0 : C->tryat - Conn_now.tv_sec,
420 C->delay);
451 421 strcat(flags, flags_tmp); strcat(flags, flags_tmp);
452 422 strcpy(flags_prefix, " "); strcpy(flags_prefix, " ");
453 423 strcpy(flags_postfix, "]"); strcpy(flags_postfix, "]");
454 424 } }
455 if (Conns[slot].flags & CONN_FLAGS_CLOSE_AFTER_SEND) {
425 if (C->flags & CONN_FLAGS_CLOSE_AFTER_SEND) {
456 426 strcat(flags, flags_prefix); strcat(flags, flags_prefix);
457 427 strcat(flags, "close_after_send"); strcat(flags, "close_after_send");
458 428 strcpy(flags_prefix, " "); strcpy(flags_prefix, " ");
 
... ... char *Conn_status_slot(const unsigned int slot)
461 431
462 432 strcat(flags, flags_postfix); strcat(flags, flags_postfix);
463 433
464 Conn_poll_status(Conns[slot].events, polle);
465 Conn_poll_status(Conns[slot].revents, pollr);
434 Conn_poll_status(C->events, polle);
435 Conn_poll_status(C->revents, pollr);
466 436
467 dT = Conn_now.tv_sec - Conns[slot].start;
437 dT = Conn_now.tv_sec - C->start;
468 438 if (dT == 0) if (dT == 0)
469 439 dT = 1; dT = 1;
470 si = Conns[slot].bi / dT;
471 so = Conns[slot].bo / dT;
440 si = C->bi / dT;
441 so = C->bo / dT;
472 442
473 443 Conn_speed(speedi, sizeof(speedi), si); Conn_speed(speedi, sizeof(speedi), si);
474 444 Conn_speed(speedo, sizeof(speedo), so); Conn_speed(speedo, sizeof(speedo), so);
475 445
476 Conn_set_address(&Conns[slot], 0);
477 Conn_set_address(&Conns[slot], 1);
446 Conn_set_address(C, 0);
447 Conn_set_address(C, 1);
478 448
479 449 local_addr = "-"; local_addr = "-";
480 450 local_port = 0; local_port = 0;
481 451 remote_addr = "-"; remote_addr = "-";
482 452 remote_port = 0; remote_port = 0;
483 if (Conns[slot].type == CONN_TYPE_MASTER) {
484 local_addr = Conns[slot].bind_addr;
485 local_port = Conns[slot].bind_port;
486 } else if (Conns[slot].type == CONN_TYPE_P2P) {
487 if (strlen(Conns[slot].bind_addr) > 0) {
488 local_addr = Conns[slot].bind_addr;
489 local_port = Conns[slot].bind_port;
453 if (C->type == CONN_TYPE_MASTER) {
454 local_addr = C->bind_addr;
455 local_port = C->bind_port;
456 } else if (C->type == CONN_TYPE_P2P) {
457 if (strlen(C->bind_addr) > 0) {
458 local_addr = C->bind_addr;
459 local_port = C->bind_port;
490 460 } }
491 remote_addr = Conns[slot].addr;
492 remote_port = Conns[slot].port;
461 remote_addr = C->addr;
462 remote_port = C->port;
493 463 } }
494 464
495 snprintf(tmp, sizeof(tmp), "id=%llu slot=%d fd=%d"
465 snprintf(tmp, sizeof(tmp), "id=%llu fd=%d"
496 466 " %s/%s/%s" " %s/%s/%s"
497 467 " %s %s" " %s %s"
498 468 " %s/%d <-> %s/%d" " %s/%d <-> %s/%d"
 
... ... char *Conn_status_slot(const unsigned int slot)
500 470 " BS=%u/%u S=%s/%s" " BS=%u/%u S=%s/%s"
501 471 " T=%ld bw=%u f=%u tk=%u" " T=%ld bw=%u f=%u tk=%u"
502 472 "%s", "%s",
503 Conns[slot].id, slot, Conns[slot].fd,
504 Conn_domain(&Conns[slot]), Conn_type(&Conns[slot]),
505 Conn_get_socket_protocol(&Conns[slot]),
506 Conn_socktype(&Conns[slot]), Conn_state(&Conns[slot]),
473 C->id, C->fd,
474 Conn_domain(C), Conn_type(C),
475 Conn_get_socket_protocol(C),
476 Conn_socktype(C), Conn_state(C),
507 477 local_addr, local_port, remote_addr, remote_port, local_addr, local_port, remote_addr, remote_port,
508 Conns[slot].via, polle, pollr, Conns[slot].bi, Conns[slot].bo,
509 Conns[slot].ibuf_size, Conns[slot].obuf_size, speedi, speedo,
510 Conn_now.tv_sec - Conns[slot].start,
511 Conns[slot].band_width, Conns[slot].band_factor, Conns[slot].band_tokens,
478 C->via, polle, pollr, C->bi, C->bo,
479 C->ibuf_size, C->obuf_size, speedi, speedo,
480 Conn_now.tv_sec - C->start,
481 C->band_width, C->band_factor, C->band_tokens,
512 482 flags); flags);
513 483
514 484 return tmp; return tmp;
515 485 } }
516 486
517 char *Conn_status_slot_html(const unsigned int slot)
487 char *Conn_status_slot_html(struct Conn *C)
518 488 { {
519 489 static char tmp[1024]; static char tmp[1024];
520 490 char polle[16], pollr[16], *ext = ""; char polle[16], pollr[16], *ext = "";
521 491 char speedi[32], speedo[32]; char speedi[32], speedo[32];
522 492 unsigned int dT, si, so; unsigned int dT, si, so;
523 493
524 Conn_poll_status(Conns[slot].events, polle);
525 Conn_poll_status(Conns[slot].revents, pollr);
494 Conn_poll_status(C->events, polle);
495 Conn_poll_status(C->revents, pollr);
526 496
527 dT = Conn_now.tv_sec - Conns[slot].start;
497 dT = Conn_now.tv_sec - C->start;
528 498 if (dT == 0) if (dT == 0)
529 499 dT = 1; dT = 1;
530 si = Conns[slot].bi / dT;
531 so = Conns[slot].bo / dT;
500 si = C->bi / dT;
501 so = C->bo / dT;
532 502
533 503 Conn_speed(speedi, sizeof(speedi), si); Conn_speed(speedi, sizeof(speedi), si);
534 504 Conn_speed(speedo, sizeof(speedo), so); Conn_speed(speedo, sizeof(speedo), so);
535 505
536 506 if (Conn_status_slot_html_cb) if (Conn_status_slot_html_cb)
537 ext = Conn_status_slot_html_cb(&Conns[slot]);
507 ext = Conn_status_slot_html_cb(C);
538 508
539 snprintf(tmp, sizeof(tmp), "<td>%llu</td><td>%d</td><td>%d</td>"
509 snprintf(tmp, sizeof(tmp), "<td>%llu</td><td>%d</td>"
540 510 "<td>%s</td><td>%s</td><td>%s</td>" "<td>%s</td><td>%s</td><td>%s</td>"
541 511 "<td>%s</td><td>%s</td>" "<td>%s</td><td>%s</td>"
542 512 "<td>%s/%d</td>" "<td>%s/%d</td>"
 
... ... char *Conn_status_slot_html(const unsigned int slot)
544 514 "<td>%u / %u</td><td>%s / %s</td><td>%ld</td>" "<td>%u / %u</td><td>%s / %s</td><td>%ld</td>"
545 515 "<td>%u</td><td>%u</td><td>%u</td>" "<td>%u</td><td>%u</td><td>%u</td>"
546 516 "%s", "%s",
547 Conns[slot].id, slot, Conns[slot].fd,
548 Conn_domain(&Conns[slot]), Conn_type(&Conns[slot]),
549 Conn_get_socket_protocol(&Conns[slot]),
550 Conn_socktype(&Conns[slot]), Conn_state(&Conns[slot]),
551 Conns[slot].addr, Conns[slot].port, Conns[slot].via, polle, pollr, Conns[slot].bi, Conns[slot].bo,
552 Conns[slot].ibuf_size, Conns[slot].obuf_size,
553 speedi, speedo, Conn_now.tv_sec - Conns[slot].start,
554 Conns[slot].band_width, Conns[slot].band_factor, Conns[slot].band_tokens,
517 C->id, C->fd,
518 Conn_domain(C), Conn_type(C),
519 Conn_get_socket_protocol(C),
520 Conn_socktype(C), Conn_state(C),
521 C->addr, C->port, C->via, polle, pollr, C->bi, C->bo,
522 C->ibuf_size, C->obuf_size,
523 speedi, speedo, Conn_now.tv_sec - C->start,
524 C->band_width, C->band_factor, C->band_tokens,
555 525 ext); ext);
556 526
557 527 return tmp; return tmp;
 
... ... char *Conn_status_slot_html(const unsigned int slot)
560 530 /* flags: bit 1 = 1 - html */ /* flags: bit 1 = 1 - html */
561 531 char *Conn_status(const unsigned int flags) char *Conn_status(const unsigned int flags)
562 532 { {
563 unsigned int len = 0, slot, max, tmp_len;
533 unsigned int len = 0, max, tmp_len;
564 534 char tmp[512]; char tmp[512];
565 535 char polle[16], pollr[16]; char polle[16], pollr[16];
566 536 char *buf, *per_slot, *ext = ""; char *buf, *per_slot, *ext = "";
 
... ... char *Conn_status(const unsigned int flags)
596 566 strcat(buf, "<table border=\"0\" cellspacing=\"1\" cellpadding=\"3\" bgcolor=\"#aaaaaa\">\n"); strcat(buf, "<table border=\"0\" cellspacing=\"1\" cellpadding=\"3\" bgcolor=\"#aaaaaa\">\n");
597 567 strcat(buf, "<tr bgcolor=\"ffffff\">\n"); strcat(buf, "<tr bgcolor=\"ffffff\">\n");
598 568 strcat(buf, "<td>ID</td>"); strcat(buf, "<td>ID</td>");
599 strcat(buf, "<td>Slot</td>");
600 569 strcat(buf, "<td>FD</td>"); strcat(buf, "<td>FD</td>");
601 570 strcat(buf, "<td>Dom</td>"); strcat(buf, "<td>Dom</td>");
602 571 strcat(buf, "<td>Type</td>"); strcat(buf, "<td>Type</td>");
 
... ... char *Conn_status(const unsigned int flags)
622 591
623 592 bi = 0; bo = 0; dT = 0; bi = 0; bo = 0; dT = 0;
624 593 for (slot = 0; slot < Conn_no; slot++) { for (slot = 0; slot < Conn_no; slot++) {
625 if (Conns[slot].state == CONN_STATE_FREE)
594 if (C->state == CONN_STATE_FREE)
626 595 continue; continue;
627 596
628 if (Conns[slot].type == CONN_TYPE_P2P) {
629 bi += Conns[slot].bi;
630 bo += Conns[slot].bo;
631 dT += Conn_now.tv_sec - Conns[slot].start;
597 if (C->type == CONN_TYPE_P2P) {
598 bi += C->bi;
599 bo += C->bo;
600 dT += Conn_now.tv_sec - C->start;
632 601 } }
633 602
634 603 if (flags & 1) if (flags & 1)
635 604 strcat(buf, "<tr bgcolor=\"ffffff\">\n"); strcat(buf, "<tr bgcolor=\"ffffff\">\n");
636 605
637 Conn_poll_status(Conns[slot].events, polle);
638 Conn_poll_status(Conns[slot].revents, pollr);
606 Conn_poll_status(C->events, polle);
607 Conn_poll_status(C->revents, pollr);
639 608
640 609 if ((flags & 1) == 0) if ((flags & 1) == 0)
641 610 per_slot = Conn_status_slot(slot); per_slot = Conn_status_slot(slot);
 
... ... unsigned int Conn_qlen(const struct Conn *C)
696 665 /* /*
697 666 * Returns 1 if we can ignore this connection * Returns 1 if we can ignore this connection
698 667 */ */
699 int Conn_ignore(const unsigned int slot)
668 int Conn_ignore(struct Conn *C)
700 669 { {
701 if (Conns[slot].error_state > 0)
670 if (C->error_state > 0)
702 671 return 1; return 1;
703 672
704 673 return 0; return 0;
 
... ... int Conn_ignore(const unsigned int slot)
707 676 /* /*
708 677 * Close a connection if it exceeded maximum idle time or got a timeout * Close a connection if it exceeded maximum idle time or got a timeout
709 678 */ */
710 void Conn_expire(const unsigned int slot)
679 void Conn_expire(struct Conn *C)
711 680 { {
712 681 long long diff_ms; long long diff_ms;
713 682
714 if (Conns[slot].trigger > 0) {
683 if (C->trigger > 0) {
715 684 /* We do not trigger first time */ /* We do not trigger first time */
716 if (Conns[slot].last_trigger == 0)
717 Conns[slot].last_trigger = Conn_now.tv_sec;
718
719 if ((Conns[slot].last_trigger > 0)
720 && (Conns[slot].last_trigger + Conns[slot].trigger < Conn_now.tv_sec)) {
721 if (Conns[slot].cb_trigger)
722 Conns[slot].cb_trigger(&Conns[slot]);
723 else if (Conn_trigger_cb)
724 Conn_trigger_cb(&Conns[slot]);
725 Conns[slot].last_trigger = Conns[slot].last_trigger + Conns[slot].trigger;
685 if (C->last_trigger == 0)
686 C->last_trigger = Conn_now.tv_sec;
687
688 if ((C->last_trigger > 0)
689 && (C->last_trigger + C->trigger < Conn_now.tv_sec)) {
690 if (C->cbs.trigger)
691 C->cbs.trigger(C);
692 C->last_trigger = C->last_trigger + C->trigger;
726 693 } }
727 694 } }
728 695
729 if ((Conns[slot].idle > 0) && (Conns[slot].trecv.tv_sec + Conns[slot].idle < Conn_now.tv_sec)) {
730 Conns[slot].error_state = CONN_ERROR_EXPIRED;
731 } else if ((Conns[slot].read_timeout > 0) && (Conns[slot].tsend.tv_sec > 0)
732 && (Conns[slot].tsend.tv_sec > Conns[slot].trecv.tv_sec)) {
733 diff_ms = Conn_time_diff(&Conn_now, &Conns[slot].tsend);
734 if (diff_ms > Conns[slot].read_timeout) {
735 Conns[slot].error_state = CONN_ERROR_READ_TIMEOUT;
696 if ((C->idle > 0) && (C->trecv.tv_sec + C->idle < Conn_now.tv_sec)) {
697 C->error_state = CONN_ERROR_EXPIRED;
698 } else if ((C->read_timeout > 0) && (C->tsend.tv_sec > 0)
699 && (C->tsend.tv_sec > C->trecv.tv_sec)) {
700 diff_ms = Conn_time_diff(&Conn_now, &C->tsend);
701 if (diff_ms > C->read_timeout) {
702 C->error_state = CONN_ERROR_READ_TIMEOUT;
736 703 } }
737 } else if ((Conns[slot].conn_timeout > 0) && (Conns[slot].state == CONN_STATE_CONNECT_b)) {
738 diff_ms = Conn_time_diff(&Conn_now, &Conns[slot].conn_syn);
739 if (diff_ms > Conns[slot].conn_timeout) {
704 } else if ((C->conn_timeout > 0) && (C->state == CONN_STATE_CONNECT_b)) {
705 diff_ms = Conn_time_diff(&Conn_now, &C->conn_syn);
706 if (diff_ms > C->conn_timeout) {
740 707 /* connection attempt expired */ /* connection attempt expired */
741 Conns[slot].error_state = CONN_ERROR_CONN_TIMEOUT;
708 C->error_state = CONN_ERROR_CONN_TIMEOUT;
742 709 } }
743 710 } }
744 711 } }
 
... ... void Conn_expire(const unsigned int slot)
749 716 int Conn_nodelay(const struct Conn *C) int Conn_nodelay(const struct Conn *C)
750 717 { {
751 718 int i = 1; int i = 1;
752 unsigned int slot;
753 719
754 slot = C->slot;
755
756 return setsockopt(Conns[slot].fd, SOL_TCP, TCP_NODELAY, &i, sizeof(i));
720 return setsockopt(C->fd, SOL_TCP, TCP_NODELAY, &i, sizeof(i));
757 721 } }
758 722
759 723 void Conn_rollback(struct Conn *C, const unsigned int bytes) void Conn_rollback(struct Conn *C, const unsigned int bytes)
760 724 { {
761 unsigned int slot;
762
763 slot = C->slot;
764
765 if (Conns[slot].obuf_tail - Conns[slot].obuf_head <= bytes)
766 Conns[slot].obuf_tail -= bytes;
725 if (C->obuf_tail - C->obuf_head <= bytes)
726 C->obuf_tail -= bytes;
767 727 } }
768 728
769 729 /* /*
 
... ... void Conn_rollback(struct Conn *C, const unsigned int bytes)
771 731 */ */
772 732 char *Conn_ibuf(const struct Conn *C) char *Conn_ibuf(const struct Conn *C)
773 733 { {
774 unsigned int slot;
775
776 slot = C->slot;
777
778 return Conns[slot].ibuf + Conns[slot].ibuf_head;
734 return C->ibuf + C->ibuf_head;
779 735 } }
780 736
781 737 /* /*
 
... ... char *Conn_ibuf(const struct Conn *C)
783 739 */ */
784 740 char *Conn_obuf(const struct Conn *C) char *Conn_obuf(const struct Conn *C)
785 741 { {
786 unsigned int slot;
787
788 slot = C->slot;
789
790 return Conns[slot].obuf + Conns[slot].obuf_head;
742 return C->obuf + C->obuf_head;
791 743 } }
792 744
793 745 /* /*
 
... ... char *Conn_obuf(const struct Conn *C)
795 747 */ */
796 748 unsigned long long Conn_getid(const struct Conn *C) unsigned long long Conn_getid(const struct Conn *C)
797 749 { {
798 unsigned int slot;
799
800 slot = C->slot;
801
802 return Conns[slot].id;
750 return C->id;
803 751 } }
804 752
805 753 /* /*
 
... ... struct Conn *Conn_get(const unsigned long long id)
825 773 */ */
826 774 int Conn_get_fd(const struct Conn *C) int Conn_get_fd(const struct Conn *C)
827 775 { {
828 unsigned int slot;
829
830 slot = C->slot;
831
832 return Conns[slot].fd;
776 return C->fd;
833 777 } }
834 778
835 779 /* /*
 
... ... int Conn_get_fd(const struct Conn *C)
837 781 */ */
838 782 void Conn_last_time(const struct Conn *C, struct timeval *tv) void Conn_last_time(const struct Conn *C, struct timeval *tv)
839 783 { {
840 unsigned int slot;
841
842 slot = C->slot;
843
844 *tv = Conns[slot].trecv;
784 *tv = C->trecv;
845 785 } }
846 786
847 787 /* /*
 
... ... void Conn_last_time(const struct Conn *C, struct timeval *tv)
849 789 */ */
850 790 int Conn_set_cb(struct Conn *C, const unsigned int cb_type, void (*f)(struct Conn *)) int Conn_set_cb(struct Conn *C, const unsigned int cb_type, void (*f)(struct Conn *))
851 791 { {
852 unsigned int slot;
853
854 slot = C->slot;
855
856 792 switch (cb_type) { switch (cb_type) {
857 case CONN_CB_ACCEPT: Conns[slot].cb_accept = f; break;
858 case CONN_CB_RECV: Conns[slot].cb_recv = f; break;
859 case CONN_CB_SEND: Conns[slot].cb_send = f; break;
860 case CONN_CB_DATA: Conns[slot].cb_data = f; break;
861 case CONN_CB_CLOSE: Conns[slot].cb_close = f; break;
862 case CONN_CB_TRIGGER: Conns[slot].cb_trigger = f; break;
863 case CONN_CB_ERROR: Conns[slot].cb_error = f; break;
864 case CONN_CB_CONNECTED: Conns[slot].cb_connected = f; break;
865 case CONN_CB_ACCEPT_ERROR: Conns[slot].cb_accept_error = f; break;
866
867 default:
868 return -1;
793 case CONN_CB_ACCEPT: C->cbs.accept = f; break;
794 case CONN_CB_RECV: C->cbs.recv = f; break;
795 case CONN_CB_SEND: C->cbs.send = f; break;
796 case CONN_CB_DATA: C->cbs.data = f; break;
797 case CONN_CB_CLOSE: C->cbs.close = f; break;
798 case CONN_CB_TRIGGER: C->cbs.trigger = f; break;
799 case CONN_CB_ERROR: C->cbs.error = f; break;
800 case CONN_CB_CONNECTED: C->cbs.connected = f; break;
801 case CONN_CB_ACCEPT_ERROR: C->cbs.accept_error = f; break;
802 default: return -1;
869 803 } }
870 804
871 805 return 0; return 0;
 
... ... char *Conn_ostrstr(struct Conn *C, const unsigned int off, const char *str,
882 816 unsigned int len, str_len, i; unsigned int len, str_len, i;
883 817 char *buf, *ret = NULL; char *buf, *ret = NULL;
884 818 int err; int err;
885 unsigned int slot;
886
887 slot = C->slot;
888 819
889 len = Conns[slot].ibuf_tail - Conns[slot].ibuf_head - off;
890 buf = Conns[slot].ibuf + Conns[slot].ibuf_head + off;
820 len = C->ibuf_tail - C->ibuf_head - off;
821 buf = C->ibuf + C->ibuf_head + off;
891 822 str_len = strlen(str); str_len = strlen(str);
892 823
893 824 if (len < str_len) if (len < str_len)
 
... ... void Conn_for_every_line(struct Conn *C, int (*cb)(struct Conn *C, char *line))
952 883 int ret = 0; int ret = 0;
953 884 char *line; char *line;
954 885 unsigned int line_size; unsigned int line_size;
955 unsigned int slot;
956
957 slot = C->slot;
958 886
959 887 if (cb == NULL) if (cb == NULL)
960 888 return; return;
961 889
962 890 while (1) { while (1) {
963 line = Conn_get_line(&Conns[slot]);
891 line = Conn_get_line(C);
964 892 if (line == NULL) if (line == NULL)
965 893 break; break;
966 894
 
... ... void Conn_for_every_line(struct Conn *C, int (*cb)(struct Conn *C, char *line))
968 896
969 897 Conn_rtrim(line, "\r"); Conn_rtrim(line, "\r");
970 898
971 ret = cb(&Conns[slot], line);
899 ret = cb(C, line);
972 900 if (ret != 0) if (ret != 0)
973 901 break; break;
974 902
975 Conn_eat(&Conns[slot], line_size);
903 Conn_eat(C, line_size);
976 904 } }
977 905 } }
978 906
 
... ... void Conn_for_every_line(struct Conn *C, int (*cb)(struct Conn *C, char *line))
981 909 */ */
982 910 void Conn_eat(struct Conn *C, const unsigned int bytes) void Conn_eat(struct Conn *C, const unsigned int bytes)
983 911 { {
984 unsigned int slot;
985
986 slot = C->slot;
987
988 912 /* advance head */ /* advance head */
989 Conns[slot].ibuf_head += bytes;
990 if (Conns[slot].ibuf_head >= Conns[slot].ibuf_tail) {
991 Conns[slot].ibuf_head = 0;
992 Conns[slot].ibuf_tail = 0;
913 C->ibuf_head += bytes;
914 if (C->ibuf_head >= C->ibuf_tail) {
915 C->ibuf_head = 0;
916 C->ibuf_tail = 0;
993 917 } }
994 918
995 Log(10, "Conn_eat(slot=%u, %u) head=%u tail=%u qlen=%u\n",
996 slot, bytes, Conns[slot].ibuf_head, Conns[slot].ibuf_tail,
997 Conn_qlen(&Conns[slot]));
919 Log(10, "Conn_eat(%u) head=%u tail=%u qlen=%u\n",
920 bytes, C->ibuf_head, C->ibuf_tail,
921 Conn_qlen(C));
998 922 } }
999 923
1000 924 /* /*
 
... ... void Conn_eat(struct Conn *C, const unsigned int bytes)
1002 926 */ */
1003 927 void Conn_eatall(struct Conn *C) void Conn_eatall(struct Conn *C)
1004 928 { {
1005 unsigned int slot;
1006
1007 slot = C->slot;
1008
1009 Conns[slot].ibuf_head = 0;
1010 Conns[slot].ibuf_tail = 0;
929 C->ibuf_head = 0;
930 C->ibuf_tail = 0;
1011 931 } }
1012 932
1013 933 /* /*
 
... ... void Conn_eatall(struct Conn *C)
1016 936 */ */
1017 937 void Conn_close(struct Conn *C) void Conn_close(struct Conn *C)
1018 938 { {
1019 unsigned int slot;
939 Log(10, "%s: Mark id=%llu for closing...\n",
940 __func__, C->id);
1020 941
1021 slot = C->slot;
1022
1023 Log(10, "%s: Mark slot=%u, id=%llu for closing...\n",
1024 __FUNCTION__, slot, Conns[slot].id);
1025
1026 if (Conns[slot].obuf_head == Conns[slot].obuf_tail)
1027 Conns[slot].error_state = CONN_ERROR_USERREQ;
942 if (C->obuf_head == C->obuf_tail)
943 C->error_state = CONN_ERROR_USERREQ;
1028 944 else else
1029 Conns[slot].flags |= CONN_FLAGS_CLOSE_AFTER_SEND;
945 C->flags |= CONN_FLAGS_CLOSE_AFTER_SEND;
1030 946 } }
1031 947
1032 948 /* /*
 
... ... void Conn_stop(void)
1043 959 void Conn_set(struct Conn *C, const unsigned int var, const int val) void Conn_set(struct Conn *C, const unsigned int var, const int val)
1044 960 { {
1045 961 int fd; int fd;
1046 unsigned int slot;
1047 962
1048 slot = C->slot;
1049
1050 fd = Conn_get_fd(&Conns[slot]);
963 fd = Conn_get_fd(C);
1051 964
1052 965 switch (var) { switch (var) {
1053 966 case CONN_PARA_AUTO_RECONNECT: case CONN_PARA_AUTO_RECONNECT:
1054 Conns[slot].flags |= (val == 0) ? 0 : CONN_FLAGS_AUTO_RECONNECT;
967 C->flags |= (val == 0) ? 0 : CONN_FLAGS_AUTO_RECONNECT;
1055 968 break; break;
1056 969 case CONN_PARA_RECONNECT_DELAY: case CONN_PARA_RECONNECT_DELAY:
1057 Conns[slot].delay = val;
970 C->delay = val;
1058 971 break; break;
1059 972 case CONN_PARA_IDLE_TIME: case CONN_PARA_IDLE_TIME:
1060 Conns[slot].idle = val;
973 C->idle = val;
1061 974 break; break;
1062 975 case CONN_PARA_READ_TIMEOUT: case CONN_PARA_READ_TIMEOUT:
1063 Conns[slot].read_timeout = val;
976 C->read_timeout = val;
1064 977 break; break;
1065 978 case CONN_PARA_CONN_TIMEOUT: case CONN_PARA_CONN_TIMEOUT:
1066 Conns[slot].conn_timeout = val;
979 C->conn_timeout = val;
1067 980 break; break;
1068 981 case CONN_PARA_TRIGGER: case CONN_PARA_TRIGGER:
1069 Conns[slot].trigger = val;
1070 Conns[slot].last_trigger = 0;
982 C->trigger = val;
983 C->last_trigger = 0;
1071 984 break; break;
1072 985 case CONN_PARA_IBUF: case CONN_PARA_IBUF:
1073 986 setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &val, sizeof(val)); setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &val, sizeof(val));
 
... ... void Conn_queue_init(struct Conn_queue *q)
1089 1002 /* /*
1090 1003 * Add a slot in a queue * Add a slot in a queue
1091 1004 */ */
1092 int Conn_queue_add(struct Conn_queue *q, const unsigned int slot)
1005 int Conn_queue_add(struct Conn_queue *q, struct Conn *C)
1093 1006 { {
1094 1007 struct Conn_queue_entry *p; struct Conn_queue_entry *p;
1095 1008
 
... ... int Conn_queue_add(struct Conn_queue *q, const unsigned int slot)
1097 1010 if (!p) if (!p)
1098 1011 return -1; return -1;
1099 1012
1100 p->slot = slot;
1013 p->C = C;
1101 1014 p->next = NULL; p->next = NULL;
1102 1015
1103 1016 if (q->head == NULL) { if (q->head == NULL) {
 
... ... int Conn_queue_add(struct Conn_queue *q, const unsigned int slot)
1105 1018 } else { } else {
1106 1019 q->tail->next = p; q->tail->next = p;
1107 1020 } }
1108
1109 1021 q->tail = p; q->tail = p;
1110 1022
1111 1023 return 0; return 0;
 
... ... int Conn_set_address(struct Conn *C, const int flags)
1143 1055 char *paddr; char *paddr;
1144 1056 size_t addr_size; size_t addr_size;
1145 1057 int *pport; int *pport;
1146 unsigned int slot;
1147 1058
1148 1059 /* Test if we need to regenerate. */ /* Test if we need to regenerate. */
1149 1060 if (flags & 1) { if (flags & 1) {
 
... ... int Conn_set_address(struct Conn *C, const int flags)
1157 1068 if (C->state == CONN_STATE_FREE) if (C->state == CONN_STATE_FREE)
1158 1069 return 0; return 0;
1159 1070
1160 slot = C->slot;
1161
1162 switch (Conns[slot].sock_domain) {
1071 switch (C->sock_domain) {
1163 1072 case PF_INET: case PF_INET:
1164 1073 psa = (struct sockaddr *) &sa4; psa = (struct sockaddr *) &sa4;
1165 1074 sa_len = sizeof(struct sockaddr_in); sa_len = sizeof(struct sockaddr_in);
 
... ... int Conn_set_address(struct Conn *C, const int flags)
1174 1083
1175 1084 if (flags & 1) { if (flags & 1) {
1176 1085 /* peer */ /* peer */
1177 paddr = Conns[slot].addr;
1178 addr_size = sizeof(Conns[slot].addr);
1179 pport = &Conns[slot].port;
1180 err = getpeername(Conns[slot].fd, psa, &sa_len);
1086 paddr = C->addr;
1087 addr_size = sizeof(C->addr);
1088 pport = &C->port;
1089 err = getpeername(C->fd, psa, &sa_len);
1181 1090 } else { } else {
1182 1091 /* local */ /* local */
1183 paddr = Conns[slot].bind_addr;
1184 addr_size = sizeof(Conns[slot].bind_addr);
1185 pport = &Conns[slot].bind_port;
1186 err = getsockname(Conns[slot].fd, psa, &sa_len);
1092 paddr = C->bind_addr;
1093 addr_size = sizeof(C->bind_addr);
1094 pport = &C->bind_port;
1095 err = getsockname(C->fd, psa, &sa_len);
1187 1096 } }
1188 1097
1189 1098 if (err != 0) if (err != 0)
1190 1099 return -1; return -1;
1191 1100
1192 switch (Conns[slot].sock_domain) {
1101 switch (C->sock_domain) {
1193 1102 case PF_INET: case PF_INET:
1194 inet_ntop(Conns[slot].sock_domain, &sa4.sin_addr,
1103 inet_ntop(C->sock_domain, &sa4.sin_addr,
1195 1104 paddr, addr_size); paddr, addr_size);
1196 1105 *pport = ntohs(sa4.sin_port); *pport = ntohs(sa4.sin_port);
1197 1106 break; break;
1198 1107 case PF_INET6: case PF_INET6:
1199 inet_ntop(Conns[slot].sock_domain, &sa6.sin6_addr,
1108 inet_ntop(C->sock_domain, &sa6.sin6_addr,
1200 1109 paddr, addr_size); paddr, addr_size);
1201 1110 *pport = ntohs(sa6.sin6_port); *pport = ntohs(sa6.sin6_port);
1202 1111 break; break;
 
... ... int Conn_alphanum(const char *s)
1538 1447
1539 1448 return 1; return 1;
1540 1449 } }
1450
1451 /*
1452 * Reads a value from proc
1453 */
1454 static void Conn_read_proc(char *buf, const size_t buf_size, const char *file)
1455 {
1456 int fd;
1457 ssize_t n;
1458
1459 fd = open(file, O_RDONLY);
1460 if (fd == -1) {
1461 snprintf(buf, buf_size, "ERROR_OPEN!");
1462 return;
1463 }
1464
1465 n = read(fd, buf, buf_size - 1);
1466 if (n == -1) {
1467 snprintf(buf, buf_size, "ERROR_READ!");
1468 } else if (n == 0) {
1469 strcpy(buf, "");
1470 } else {
1471 buf[n - 1] = '\0';
1472 n--;
1473
1474 while ((n >= 0) && (buf[n - 1] == '\n')) {
1475 buf[n - 1] = '\0';
1476 n--;
1477 }
1478 }
1479
1480 close(fd);
1481 }
1482
1483 /*
1484 * Returns some important system values
1485 */
1486 char *Conn_sys(void)
1487 {
1488 static char ret[512];
1489 char somaxconn[16];
1490 char tcp_max_tw_buckets[16];
1491 char tcp_fin_timeout[16];
1492
1493 Conn_read_proc(somaxconn, sizeof(somaxconn),
1494 "/proc/sys/net/core/somaxconn");
1495 Conn_read_proc(tcp_max_tw_buckets, sizeof(tcp_max_tw_buckets),
1496 "/proc/sys/net/ipv4/tcp_max_tw_buckets");
1497 Conn_read_proc(tcp_fin_timeout, sizeof(tcp_fin_timeout),
1498 "/proc/sys/net/ipv4/tcp_fin_timeout");
1499
1500 snprintf(ret, sizeof(ret), "net.core.somaxconn=%s"
1501 " net.ipv4.tcp_max_tw_buckets=%s"
1502 " net.ipv4.tcp_fin_timeout=%s",
1503 somaxconn, tcp_max_tw_buckets, tcp_fin_timeout);
1504
1505 return ret;
1506 }
1507
1508 /*
1509 * Adds an fd to poll system
1510 */
1511 int Conn_add_obj(struct Conn *C)
1512 {
1513 int ret;
1514 struct epoll_event ev;
1515
1516 memset(&ev, 0, sizeof(struct epoll_event));
1517 ev.data.ptr = C;
1518 ev.events = C->events;
1519 ret = epoll_ctl(Conn_epoll_fd, EPOLL_CTL_ADD, C->fd, &ev);
1520 if (ret == -1) {
1521 C->xerrno = errno;
1522 snprintf(Conn_error, sizeof(Conn_error),
1523 strerror(C->xerrno));
1524 return C->xerrno;
1525 }
1526
1527 C->events_cache = C->events;
1528
1529 return 0;
1530 }
1531
1532 /*
1533 * Remove a target from list
1534 */
1535 int Conn_del_obj(struct Conn *C)
1536 {
1537 struct epoll_event ev; /* Dummy, for kernels below 2.6.9. */
1538 int ret;
1539
1540 ret = epoll_ctl(Conn_epoll_fd, EPOLL_CTL_DEL, C->fd, &ev);
1541 if (ret == -1) {
1542 Log(0, "del_obj: Could not delete fd %d (%s). Bug?\n",
1543 C->fd, strerror(errno));
1544 }
1545
1546 return 0;
1547 }
1548
1549 /*
1550 * Change event mask
1551 */
1552 int Conn_change_obj(struct Conn *C)
1553 {
1554 struct epoll_event ev;
1555 int ret;
1556
1557 if (C->events == C->events_cache)
1558 return 0;
1559
1560 /* We may move a slot already in error state */
1561 if (C->fd == -1)
1562 return 0;
1563
1564 memset(&ev, 0, sizeof(ev));
1565 ev.events = C->events;
1566 ev.data.ptr = C;
1567 ret = epoll_ctl(Conn_epoll_fd, EPOLL_CTL_MOD, C->fd, &ev);
1568 if (ret != 0) {
1569 /* Could not happen! */
1570 Log(0, "chg_obj: Could not change fd %d (%s). Bug?\n",
1571 C->fd, strerror(errno));
1572 abort();
1573 }
1574
1575 C->events_cache = C->events;
1576
1577 return 0;
1578 }
1579
1580 /*
1581 * Dispatch events to a callback
1582 * Returns: -1 on error, 0 nothing to do, n (>0) if some work was done
1583 * timeout is in miliseconds.
1584 */
1585 int Conn_dispatch_events_core(int epoll_fd, struct epoll_event *e,
1586 const unsigned short e_size, const int timeout,
1587 void (*cb)(struct Conn *C, unsigned int revents))
1588 {
1589 int i, events;
1590 struct Conn *C;
1591
1592 Log(10, "%s: timeout2=%ums...\n", __func__, timeout);
1593 again:
1594 events = epoll_wait(epoll_fd, e, e_size, timeout);
1595 if ((events == -1) && (errno == EINTR))
1596 goto again;
1597
1598 if (events < 0) {
1599 snprintf(Conn_error, sizeof(Conn_error),
1600 "%s: e_size=%d [%s]",
1601 __func__, e_size, strerror(errno));
1602 return -1;
1603 }
1604
1605 gettimeofday(&Conn_now, NULL);
1606
1607 if (events == 0)
1608 return 0;
1609
1610 Log(11, "\tProcessing %d event(s)...\n", events);
1611 i = events - 1;
1612 do {
1613 C = e[i].data.ptr;
1614 cb(C, e[i].events);
1615
1616 i--;
1617 } while (i >= 0);
1618
1619 return events;
1620 }
1621
1622 int Conn_dispatch_events(const int timeout,
1623 void (*cb)(struct Conn *C, unsigned int revents))
1624 {
1625 return Conn_dispatch_events_core(Conn_epoll_fd, Conn_epoll_events,
1626 CONN_EVENTS_SLOTS, timeout, cb);
1627 }
1628
1629 /*
1630 * Callback that is called for every connection
1631 */
1632 void Conn_poll_cb(struct Conn *C, unsigned int revents)
1633 {
1634 char poll_status[16];
1635
1636 Conn_poll_status(revents, poll_status);
1637 Log(12, "\t%s: id=%llu, revents=%s.\n",
1638 __func__, C->id, poll_status);
1639 C->revents = revents;
1640
1641 if (Conn_level >= 12)
1642 Log(12, "\t\t%s\n", Conn_status_slot(C));
1643
1644 /* We should not have events on a free cell */
1645 if (C->state == CONN_STATE_FREE) {
1646 Log(12, "\t\tBUG! Events on a FREE slot!\n");
1647 return;
1648 }
1649
1650 if (revents & EPOLLHUP) {
1651 C->error_state = CONN_ERROR_HANGUP;
1652 /* TODO: Add it to the close list to speed it up */
1653 }
1654
1655 if (revents & EPOLLERR) {
1656 C->error_state = CONN_ERROR_POLL;
1657 C->xerrno = 0; /* TODO: unknown error? */
1658 /* TODO: CONN_ERROR_POLL is correct here? */
1659 }
1660
1661 /* First, test we have a new connection */
1662 if ((revents & EPOLLOUT) && (Conn_ignore(C) == 0)) {
1663 if (Conn_oqlen(C) == 0) {
1664 /* Nothing to send */
1665 revents &= ~EPOLLOUT;
1666 C->events &= ~EPOLLOUT;
1667 Conn_change_obj(C);
1668 }
1669
1670 if (C->state == CONN_STATE_CONNECT_b) {
1671 Log(12, "\t\tWe just established a connection.\n");
1672
1673 C->state = CONN_STATE_OPEN;
1674
1675 C->flags |= CONN_ADDR_LOCAL_DIRTY;
1676
1677 C->time_open = Conn_now;
1678
1679 if (C->cbs.connected != NULL)
1680 C->cbs.connected(C);
1681 }
1682 }
1683
1684 /* Second, test for hangup or input */
1685 if ((revents & EPOLLIN) && (Conn_ignore(C) == 0)) {
1686 Log(12, "\t\tWe have input...\n");
1687 if (C->type == CONN_TYPE_MASTER) {
1688 Conn_accept(C);
1689 } else {
1690 if (C->cbs.recv)
1691 C->cbs.recv(C);
1692 }
1693 }
1694
1695 if ((revents & EPOLLOUT) && (Conn_ignore(C) == 0)) {
1696 Log(12, "\t\tWe can send data...\n");
1697 if (C->state == CONN_STATE_OPEN) {
1698 if (C->cbs.send)
1699 C->cbs.send(C);
1700
1701 if (Conn_oqlen(C) == 0) {
1702 if (C->flags & CONN_FLAGS_CLOSE_AFTER_SEND) {
1703 C->state = CONN_STATE_ERROR;
1704 C->error_state = CONN_ERROR_USERREQ;
1705 } else {
1706 C->events &= ~EPOLLOUT;
1707 Conn_change_obj(C);
1708 }
1709 }
1710 }
1711 }
1712 }
1713
1714 /* ############ Callbacks ########### */
1715
1716 void Conn_default_cbs_accept(struct Conn *C)
1717 {
1718 int fd, err;
1719 struct sockaddr *pca;
1720 struct sockaddr_in ca4;
1721 struct sockaddr_in6 ca6;
1722 socklen_t cax_len;
1723 struct Conn *X;
1724
1725 Log(10, "Accepting a connection via %s/%d, type %s, domain %s"
1726 ", protocol %s.\n",
1727 C->bind_addr, C->bind_port, Conn_type(C),
1728 Conn_domain(C), Conn_get_socket_protocol(C));
1729
1730 switch(C->sock_domain) {
1731 case PF_INET:
1732 pca = (struct sockaddr *) &ca4;
1733 cax_len = sizeof(ca4);
1734 break;
1735
1736 case PF_INET6:
1737 pca = (struct sockaddr *) &ca6;
1738 cax_len = sizeof(ca6);
1739 break;
1740
1741 default:
1742 snprintf(Conn_error, sizeof(Conn_error),
1743 "Cannot deal with domain %d.",
1744 C->sock_domain);
1745 Conn_error_raise(C, EAFNOSUPPORT);
1746 return;
1747 }
1748
1749 fd = accept4(C->fd, pca, &cax_len, SOCK_NONBLOCK | SOCK_CLOEXEC);
1750 if (fd == -1) {
1751 if (errno == EAGAIN)
1752 return;
1753
1754 /* TODO: ratelimit */
1755 Log(2, "WARN: Cannot accept on fd %d [%s].\n",
1756 C->fd, strerror(errno));
1757 /*
1758 * We must not raise an error here because we will close the
1759 * master socket!
1760 * TODO: We should signal it as a warning.
1761 */
1762 /* Conn_error_raise(C, errno); */
1763 return;
1764 }
1765
1766 X = Conn_alloc();
1767 if (!X) {
1768 Conn_error_raise(C, ENOMEM);
1769 close(fd);
1770 return;
1771 }
1772
1773 X->fd = fd;
1774 X->type = CONN_TYPE_P2P;
1775 X->state = CONN_STATE_OPEN;
1776 X->time_open = Conn_now;
1777 X->via = C->id;
1778 X->events = EPOLLIN | EPOLLOUT;
1779
1780 Conn_set_socket_domain(X, C->sock_domain);
1781 Conn_set_socket_type(X, C->sock_type);
1782 Conn_set_socket_protocol(X, C->sock_protocol);
1783
1784 X->flags |= CONN_ADDR_LOCAL_DIRTY | CONN_ADDR_REMOTE_DIRTY;
1785
1786 if (C->wp != NULL) {
1787 err = Conn_wpool_enqueue(C->wp, X);
1788 if (err != 0) {
1789 Conn_error_raise(C, CONN_ERROR_INTERNAL);
1790 Conn_free_intern(X);
1791 return;
1792 }
1793 /* TODO: send signaling to thread to call accept callback */
1794 /* TODO: maybe we want to pass the fd also by signaling channel */
1795 } else {
1796 err = Conn_add_obj(X);
1797 if (err != 0) {
1798 Conn_error_raise(C, err);
1799 Conn_free_intern(X);
1800 return;
1801 }
1802
1803 if (C->cb_accept)
1804 C->cb_accept(X);
1805 else if (Conn_accept_cb != NULL)
1806 Conn_accept_cb(X);
1807 }
1808
1809 Conn_work_to_do++;
1810
1811 Conn_total++;
1812 }
1813
1814 void Conn_default_cbs_recv(struct Conn *C)
1815 {
1816 ssize_t n;
1817 unsigned int max;
1818 int r, xerrno;
1819 char *dump;
1820
1821 Log(10, "%s: id=%llu fd=%d head=%u tail=%u size=%u...\n",
1822 __func__, C->id, C->fd,
1823 C->ibuf_head, C->ibuf_tail, C->ibuf_size);
1824
1825 if (C->ibuf_tail == C->ibuf_size) {
1826 r = Conn_try_expand_buf(C, 1, Conn_default_ibuf);
1827 if (r != 0) {
1828 C->error_state = CONN_ERROR_MEM;
1829 /* TODO: Just suspend connection for 1 second instead */
1830 return;
1831 }
1832 }
1833
1834 max = C->ibuf_size - C->ibuf_tail;
1835 if ((Conn_max_recv > 0) && (max > Conn_max_recv))
1836 max = Conn_max_recv;
1837
1838 while (1) {
1839 n = recv(C->fd, C->ibuf + C->ibuf_tail, max, 0);
1840 if ((n == -1) && (errno == EINTR))
1841 continue;
1842
1843 xerrno = errno;
1844
1845 break;
1846 }
1847
1848 Log(10, "\tReceived %d bytes.\n", n);
1849
1850 if (n > 0) {
1851 if (Conn_level >= 10) {
1852 dump = Conn_dump(C->ibuf + C->ibuf_tail, n);
1853 Log(0, "\t%s\n", dump);
1854 free(dump);
1855 }
1856
1857 C->ibuf_tail += n;
1858
1859 C->bi += n;
1860 C->trecv = Conn_now;
1861
1862 if (C->cb_data)
1863 C->cb_data(C);
1864 } else if (n == 0) {
1865 Log(10, "\tRemote closed sending side.\n");
1866 C->error_state = CONN_ERROR_HANGUP;
1867 /* TODO: Maybe we should just cut INPUT and do not hangup */
1868 } else {
1869 Log(0, "\tError receiving [%s]\n",
1870 strerror(errno));
1871 C->error_state = CONN_ERROR_RECV;
1872 C->xerrno = xerrno;
1873 }
1874 }
1875
1876 void Conn_default_cbs_send(struct Conn *C)
1877 {
1878 ssize_t n;
1879 unsigned int max;
1880 int count;
1881 char *buf;
1882 int xerrno;
1883 char *dump;
1884
1885 Log(10, "%s id=%llu fd=%d head=%u, tail=%u, size=%u\n",
1886 __func__, C->id, C->fd, C->obuf_head, C->obuf_tail,
1887 C->obuf_size);
1888
1889 if (C->obuf == NULL)
1890 abort();
1891
1892 buf = C->obuf + C->obuf_head;
1893 count = C->obuf_tail - C->obuf_head;
1894 if (count == 0) {
1895 Log(13, "\tEmpty output buffer!\n");
1896 return;
1897 }
1898
1899 max = count;
1900 if ((Conn_max_send > 0) && (max > Conn_max_send))
1901 max = Conn_max_send;
1902
1903 /* bandwidth */
1904 if (C->band_width > 0) {
1905 if (max > C->band_tokens)
1906 max = C->band_tokens;
1907 if (max == 0) {
1908 Log(debug_band, "\tBAND: Suspend 100ms the C (no tokens)!\n");
1909 C->events &= ~EPOLLOUT;
1910 Conn_change_obj(C);
1911 return;
1912 }
1913 }
1914
1915 again:
1916 Log(10, "\tsend(fd=%d, buf (head=%u, tail=%u), max=%d (count=%d), 0)...\n",
1917 C->fd, C->obuf_head,
1918 C->obuf_tail, max, count);
1919 n = send(C->fd, buf, max, 0);
1920 xerrno = errno;
1921 if ((n == -1) && (errno == EINTR))
1922 goto again;
1923
1924 if ((n == -1) && (errno == EAGAIN))
1925 return;
1926
1927 Log(10, "\tSent %d bytes [head=%d tail=%d]\n",
1928 n, C->obuf_head, C->obuf_tail);
1929 if (Conn_level >= 10) {
1930 dump = Conn_dump(buf, n);
1931 Log(0, "\t%s\n", dump);
1932 free(dump);
1933 }
1934
1935 if (n > 0) {
1936 C->tsend = Conn_now;
1937 if (n < count) {
1938 C->obuf_head += n;
1939 } else {
1940 C->obuf_head = 0;
1941 C->obuf_tail = 0;
1942 }
1943
1944 C->bo += n;
1945 if (C->band_width > 0) {
1946 C->band_tokens -= n;
1947 Log(debug_band, "\t%s: BAND: Remove %d tokens -> %u...\n",
1948 __func__,
1949 n, C->band_tokens);
1950 }
1951 } else {
1952 Log(0, "\tError in sending [%s]\n",
1953 strerror(errno));
1954 C->error_state = CONN_ERROR_SEND;
1955 C->xerrno = xerrno;
1956 }
1957 }
1958
File Conn_core.h renamed from Conn_engine_core.h (similarity 83%) (mode: 100644) (index f91828e..0a0b0f8)
1 #ifndef CONN_ENGINE_CORE_H
2 #define CONN_ENGINE_CORE_H
1 #ifndef CONN_CORE_H
2 #define CONN_CORE_H
3 3
4 4 #include <Conn_config.h> #include <Conn_config.h>
5 5
 
13 13 #include <sys/time.h> #include <sys/time.h>
14 14 #include <sys/stat.h> #include <sys/stat.h>
15 15 #include <sys/socket.h> #include <sys/socket.h>
16 #include <sys/epoll.h>
16 17 #include <unistd.h> #include <unistd.h>
17 18 #include <time.h> #include <time.h>
18 19 #include <stdio.h> #include <stdio.h>
 
... ... enum CONN_CB {
95 96 CONN_CB_ACCEPT_ERROR CONN_CB_ACCEPT_ERROR
96 97 }; };
97 98
99 struct Conn;
100
101 /*
102 * Used to define callbacks
103 */
104 struct Conn_cbs
105 {
106 void (*accept)(struct Conn *C);
107 void (*recv)(struct Conn *C);
108 void (*send)(struct Conn *C);
109 void (*data)(struct Conn *C);
110 void (*close)(struct Conn *C);
111 void (*trigger)(struct Conn *C);
112 void (*error)(struct Conn *C);
113 void (*connected)(struct Conn *C);
114 void (*accept_error)(struct Conn *C);
115 };
116
98 117 struct Conn struct Conn
99 118 { {
100 119 int fd; int fd;
 
... ... struct Conn
154 173
155 174 unsigned long long id; /* the id of a connection */ unsigned long long id; /* the id of a connection */
156 175
157 /* Specific callbacks */
158 void (*cb_accept)(struct Conn *C);
159 void (*cb_recv)(struct Conn *C);
160 void (*cb_send)(struct Conn *C);
161 void (*cb_data)(struct Conn *C);
162 void (*cb_close)(struct Conn *C);
163 void (*cb_trigger)(struct Conn *C);
164 void (*cb_error)(struct Conn *C);
165 void (*cb_connected)(struct Conn *C);
166 void (*cb_accept_error)(struct Conn *C);
176 struct Conn_cbs cbs; /* Specific callbacks */
167 177
168 178 struct timeval time_open; /* When a connect succeded */ struct timeval time_open; /* When a connect succeded */
169 179
 
... ... struct Conn
173 183
174 184 struct Conn_queue_entry struct Conn_queue_entry
175 185 { {
176 unsigned int slot;
186 struct Conn *C;
177 187 struct Conn_queue_entry *next; struct Conn_queue_entry *next;
178 188 }; };
179 189
 
... ... struct Conn_split
198 208 char *line; char *line;
199 209 }; };
200 210
201
202 211 /* Variables */ /* Variables */
203 extern void (*Conn_accept_cb)(struct Conn *C);
204 extern void (*Conn_recv_cb)(struct Conn *C);
205 extern void (*Conn_send_cb)(struct Conn *C);
206 extern void (*Conn_data_cb)(struct Conn *C);
207 extern void (*Conn_close_cb)(struct Conn *C);
208 extern void (*Conn_trigger_cb)(struct Conn *C);
209 extern void (*Conn_error_cb)(struct Conn *C);
210 extern void (*Conn_connected_cb)(struct Conn *C);
211 extern void (*Conn_accept_error_cb)(struct Conn *C);
212
213 212 extern char *(*Conn_status_slot_html_cb)(const struct Conn *C); extern char *(*Conn_status_slot_html_cb)(const struct Conn *C);
214 213 extern char *(*Conn_status_cb)(void); extern char *(*Conn_status_cb)(void);
215 214
215 extern int Conn_epoll_fd;
216
216 217 extern unsigned int Conn_max_reached; extern unsigned int Conn_max_reached;
217 218 extern unsigned int Conn_default_ibuf; extern unsigned int Conn_default_ibuf;
218 219 extern unsigned int Conn_default_obuf; extern unsigned int Conn_default_obuf;
 
... ... extern unsigned int Conn_allocated;
242 243 extern unsigned long long Conn_id; extern unsigned long long Conn_id;
243 244 extern unsigned int Conn_must_stop; extern unsigned int Conn_must_stop;
244 245
245 extern char Conn_error[512];
246
247 246 extern FILE *Conn_Log; extern FILE *Conn_Log;
248 247 extern int debug_band; extern int debug_band;
249 248
 
... ... extern struct Conn_queue Conn_queue_free;
254 253 extern char *Conn_strerror(void); extern char *Conn_strerror(void);
255 254 extern void Log(const unsigned short level, char *format, ...); extern void Log(const unsigned short level, char *format, ...);
256 255 extern char *Conn_errno(const struct Conn *C); extern char *Conn_errno(const struct Conn *C);
257 extern char *Conn_status_slot(const unsigned int slot);
256 extern char *Conn_status_slot(struct Conn *C);
258 257 extern char *Conn_status(const unsigned int flags); extern char *Conn_status(const unsigned int flags);
259 extern int Conn_try_expand_buf(const unsigned int slot, const int what,
258 extern int Conn_try_expand_buf(struct Conn *C, const int what,
260 259 const unsigned int needed); const unsigned int needed);
261 260 extern char *Conn_state(const struct Conn *C); extern char *Conn_state(const struct Conn *C);
262 261
 
... ... extern void Conn_last_time(const struct Conn *C, struct timeval *tv);
266 265
267 266 extern int Conn_setnonblock(const int fd); extern int Conn_setnonblock(const int fd);
268 267
269 extern char *Conn_dump(const char *buf_src, const int len_src);
270 extern char *Conn_dumphex(const char *buf_src, const int len_src);
268 extern char *Conn_dump(const void *buf_src, const int len_src);
269 extern char *Conn_dumphex(const void *buf_src, const int len_src);
271 270 extern void Conn_debug(FILE *f, const unsigned short debug); extern void Conn_debug(FILE *f, const unsigned short debug);
272 271
273 272 extern void Conn_close(struct Conn *C); extern void Conn_close(struct Conn *C);
274 273
275 extern int Conn_ignore(const unsigned int slot);
274 extern int Conn_ignore(struct Conn *C);
276 275
277 extern void Conn_expire(const unsigned int slot);
276 extern void Conn_expire(struct Conn *C);
278 277
279 278 extern int Conn_set_cb(struct Conn *C, const unsigned int cb_type, extern int Conn_set_cb(struct Conn *C, const unsigned int cb_type,
280 279 void (*f)(struct Conn *)); void (*f)(struct Conn *));
 
... ... extern char *Conn_get_socket_protocol(const struct Conn *C);
309 308
310 309 extern int Conn_addr_family(const char *addr); extern int Conn_addr_family(const char *addr);
311 310
312 extern void Conn_error_raise(const unsigned int slot, const int err);
311 extern void Conn_error_raise(struct Conn *C, const int err);
313 312
314 313 extern void Conn_stop(void); extern void Conn_stop(void);
315 314
 
... ... extern int Conn_port_remote(struct Conn *C);
323 322 /* queue stuff */ /* queue stuff */
324 323 extern void Conn_queue_init(struct Conn_queue *q); extern void Conn_queue_init(struct Conn_queue *q);
325 324 extern int Conn_queue_add(struct Conn_queue *q, extern int Conn_queue_add(struct Conn_queue *q,
326 const unsigned int slot);
325 struct Conn *C);
327 326 extern void Conn_queue_destroy(struct Conn_queue *q); extern void Conn_queue_destroy(struct Conn_queue *q);
328 327
329 328 /* String stuff */ /* String stuff */
 
... ... extern void Conn_split_free(struct Conn_split **s);
350 349 /* Misc stuff */ /* Misc stuff */
351 350 extern int Conn_alphanum(const char *s); extern int Conn_alphanum(const char *s);
352 351
352 extern char *Conn_sys(void);
353
354 extern int Conn_add_obj(struct Conn *C);
355 extern int Conn_del_obj(struct Conn *C);
356 extern int Conn_change_obj(struct Conn *C);
357
358 extern int Conn_dispatch_events_core(int epoll_fd,
359 struct epoll_event *e,
360 const unsigned short e_size, const int timeout,
361 void (*cb)(struct Conn *C, unsigned int revents));
362 extern int Conn_dispatch_events(const int timeout,
363 void (*cb)(struct Conn *C, unsigned int revents));
364
365 extern void Conn_poll_cb(struct Conn *C, unsigned int revents);
366
367 /* Default callbacks */
368 extern void Conn_default_cbs_accept(struct Conn *C);
369 extern void Conn_default_cbs_recv(struct Conn *C);
370 extern void Conn_default_cbs_send(struct Conn *C);
371
353 372 #endif #endif
354 373
File Conn_engine_epoll.c deleted (index 183b8d4..0000000)
1 #include <Conn_config.h>
2
3 #include <Conn_engine_epoll.h>
4
5 /*
6 * Variables
7 */
8 static unsigned long Conn_epoll_allocated_slots = 0;
9 static int Conn_epoll_fd;
10 static struct epoll_event *Conn_epoll_events = NULL;
11
12 /*
13 * Functions
14 */
15
16 /*
17 * Init the engine
18 */
19 int Conn_epoll_init(void)
20 {
21 Conn_epoll_fd = epoll_create(256);
22 if (Conn_epoll_fd == -1) {
23 snprintf(Conn_error, sizeof(Conn_error),
24 "Cannot open epoll socket (%s).", strerror(errno));
25 return -1;
26 }
27
28 return 0;
29 }
30
31 int Conn_epoll_shutdown(void)
32 {
33 int ret;
34
35 free(Conn_epoll_events);
36 ret = close(Conn_epoll_fd);
37 if (ret != 0)
38 return -1;
39
40 return 0;
41 }
42
43 /*
44 * Grow the number of slots needed for epoll
45 */
46 int Conn_epoll_grow(unsigned int alloc)
47 {
48 struct epoll_event *p, *set;
49 unsigned int diff;
50
51 Log(10, "%s: Try to grow pollfds from %d to %d.\n",
52 __FUNCTION__,
53 Conn_epoll_allocated_slots, alloc);
54
55 if (alloc <= Conn_epoll_allocated_slots)
56 return 0;
57
58 diff = alloc - Conn_epoll_allocated_slots;
59
60 p = (struct epoll_event *) realloc(Conn_epoll_events, alloc
61 * sizeof(struct epoll_event));
62 if (p == NULL) {
63 snprintf(Conn_error, sizeof(Conn_error),
64 "Cannot alloc memory for epoll_events.");
65 return -1;
66 }
67
68 set = p + Conn_epoll_allocated_slots;
69 memset(set, 0, diff * sizeof(struct epoll_event));
70 Conn_epoll_events = p;
71
72 return 0;
73 }
74
75 /*
76 * Add a target to the list
77 */
78 int Conn_epoll_add_obj(struct Conn *C)
79 {
80 int ret;
81 struct epoll_event ev;
82
83 memset(&ev, 0, sizeof(ev));
84 ev.data.u32 = C->slot;
85 ev.events = C->events;
86 ret = epoll_ctl(Conn_epoll_fd, EPOLL_CTL_ADD, C->fd, &ev);
87 if (ret == -1) {
88 C->xerrno = errno;
89 snprintf(Conn_error, sizeof(Conn_error),
90 "Cannot add obj to list (%s).",
91 strerror(C->xerrno));
92 return C->xerrno;
93 }
94
95 C->events_cache = C->events;
96 C->slot_cache = C->slot;
97
98 return 0;
99 }
100
101 /*
102 * Remove a target from list
103 */
104 int Conn_epoll_del_obj(struct Conn *C)
105 {
106 struct epoll_event ev; /* Dummy, for kernels below 2.6.9. */
107 int ret;
108
109 ret = epoll_ctl(Conn_epoll_fd, EPOLL_CTL_DEL, C->fd, &ev);
110 if (ret == -1) {
111 Log(0, "del_obj: Could not delete fd %d (%s). Bug?\n",
112 C->fd, strerror(errno));
113 }
114
115 return 0;
116 }
117
118 /*
119 * Change event mask
120 */
121 int Conn_epoll_chg_obj(struct Conn *C)
122 {
123 struct epoll_event ev;
124 int ret;
125
126 if ((C->events == C->events_cache) && (C->slot == C->slot_cache))
127 return 0;
128
129 /* We may move a slot already in error state */
130 if (C->fd == -1)
131 return 0;
132
133 memset(&ev, 0, sizeof(ev));
134 ev.events = C->events;
135 ev.data.u32 = C->slot;
136 ret = epoll_ctl(Conn_epoll_fd, EPOLL_CTL_MOD, C->fd, &ev);
137 if (ret != 0) {
138 /* Could not happen! */
139 Log(0, "chg_obj: Could not change fd %d (%s). Bug?\n",
140 C->fd, strerror(errno));
141 abort();
142 }
143
144 C->events_cache = C->events;
145 C->slot_cache = C->slot;
146
147 return 0;
148 }
149
150 /*
151 * Calls a callback for fds with activity
152 * Returns: -1 on error, 0 nothing to do, n (>0) if some work was done
153 * timeout is in 1/1000 seconds increments.
154 */
155 int Conn_epoll_poll_core(int fd, struct epoll_event *ee,
156 const unsigned int max, const int timeout2,
157 void (*cb)(const unsigned int slot, const unsigned int revents))
158 {
159 int i, events;
160 unsigned int slot;
161
162 Log(10, "%s: timeout2=%ums...\n", __FUNCTION__, timeout2);
163 again:
164 events = epoll_wait(fd, ee, max, timeout2);
165 if ((events == -1) && (errno == EINTR))
166 goto again;
167
168 if (events < 0) {
169 snprintf(Conn_error, sizeof(Conn_error),
170 "%s: max=%d [%s]",
171 __FUNCTION__, max, strerror(errno));
172 return -1;
173 }
174
175 gettimeofday(&Conn_now, NULL);
176
177 if (events == 0)
178 return 0;
179
180 Log(11, "\tProcessing %d event(s)...\n", events);
181 i = events - 1;
182 do {
183 slot = ee[i].data.u32;
184 cb(slot, ee[i].events);
185
186 i--;
187 } while (i >= 0);
188
189 return events;
190 }
191
192 int Conn_epoll_poll(const int timeout2,
193 void (*cb)(const unsigned int slot, const unsigned int events))
194 {
195 return Conn_epoll_poll_core(Conn_epoll_fd, Conn_epoll_events, Conn_no, timeout2, cb);
196 }
197
198 /*
199 * Move a slot over an other.
200 */
201 int Conn_epoll_move_slot(const unsigned int dst, const unsigned int src)
202 {
203 unsigned int tmp;
204
205 tmp = src; /* gcc silencer */
206
207 /* Because slot was changed, update epoll info */
208 Conn_epoll_chg_obj(&Conns[dst]);
209
210 return 0;
211 }
File Conn_engine_epoll.h deleted (index 2a42b3a..0000000)
1 #ifndef CONN_ENGINE_EPOLL_H
2 #define CONN_ENGINE_EPOLL_H
3
4 #include <sys/epoll.h>
5
6 #include <Conn_engine_core.h>
7
8 extern int Conn_epoll_init(void);
9 extern int Conn_epoll_shutdown(void);
10 extern int Conn_epoll_grow(unsigned int alloc);
11 extern int Conn_epoll_add_obj(struct Conn *C);
12 extern int Conn_epoll_del_obj(struct Conn *C);
13 extern int Conn_epoll_chg_obj(struct Conn *C);
14 extern int Conn_epoll_poll_core(const int fd, struct epoll_event *ee,
15 const unsigned int max, const int timeout2,
16 void (*cb)(const unsigned int slot, const unsigned int revents));
17 extern int Conn_epoll_poll(const int timeout2,
18 void (*cb)(const unsigned int slot, const unsigned int revents));
19 extern int Conn_epoll_move_slot(const unsigned int dst,
20 const unsigned int src);
21
22 #endif
File Conn_wpool.c added (mode: 100644) (index 0000000..e8bcfbb)
1 /*
2 * Several function work workers pool
3 */
4
5 #include <Conn_config.h>
6
7 #include <stdlib.h>
8 #include <sys/epoll.h>
9 #include <sys/types.h>
10 #include <sys/socket.h>
11 #include <fcntl.h>
12 #include <unistd.h>
13 #include <string.h>
14 #include <errno.h>
15 #include <pthread.h>
16
17 #include <Conn_core.h>
18 #include <Conn_wpool.h>
19
20
21 /*
22 * Function that is executed by a worker.
23 * It accepts connections, receives nad sends commands.
24 */
25 void *Conn_wpool_worker_func(void *arg)
26 {
27 struct Conn_wpool_worker *w = arg;
28 int r;
29
30 Log(10, "Worker %p started work...\n", w);
31
32 while (1) {
33 r = Conn_dispatch_events_core(w->epoll_fd, w->events,
34 CONN_EVENTS_SLOTS, 0, Conn_poll_cb);
35 if (r != 0)
36 Log(0, "Cannot dispatch events.\n");
37 }
38
39 return NULL;
40 }
41
42 /*
43 * Destroy a worker
44 */
45 void Conn_wpool_stop_worker(struct Conn_wpool_worker *w)
46 {
47 int r;
48
49 if (w->inited == 0)
50 return;
51
52 close(w->epoll_fd);
53
54 close(w->pipe[0]);
55 close(w->pipe[1]);
56
57 r = pthread_cancel(w->tid);
58 if (r != 0)
59 Log(0, "Cannot cancel worker %p.\n", w);
60 }
61
62 /*
63 * Start a worker
64 */
65 int Conn_wpool_start_worker(struct Conn_wpool_worker *w)
66 {
67 int r;
68 struct epoll_event ev;
69
70 Log(10, "Creating worker %p...\n", w);
71
72 w->epoll_fd = epoll_create1(EPOLL_CLOEXEC);
73 if (w->epoll_fd == -1) {
74 Log(0, "Cannot create worker epoll (%s).\n", strerror(errno));
75 goto out;
76 }
77
78 r = socketpair(AF_LOCAL, SOCK_STREAM, 0, w->pipe);
79 if (r != 0) {
80 Log(0, "Cannot call socketpair (%s)\n", strerror(errno));
81 goto close_epoll;
82 }
83
84 /* Register our end of the pipe to receive signaling from 'accept' thread */
85 memset(&ev, 0, sizeof(struct epoll_event));
86 ev.events = EPOLLIN;
87 ev.data.u32 = 1; /* TODO: Found a better id */
88 r = epoll_ctl(w->epoll_fd, EPOLL_CTL_ADD, w->pipe[1], &ev);
89 r = pthread_create(&w->tid, NULL, Conn_wpool_worker_func, w);
90 if (r != 0) {
91 Log(0, "Could not start thread (%s)\n", strerror(errno));
92 goto close_pipe;
93 }
94 w->inited = 1;
95
96 Log(10, "Started worker %p, epoll=%d pipe=%d/%d\n",
97 w, w->epoll_fd, w->pipe[0], w->pipe[1]);
98 return 0;
99
100 close_pipe:
101 close(w->pipe[0]);
102 close(w->pipe[1]);
103
104 close_epoll:
105 close(w->epoll_fd);
106
107 out:
108 return -1;
109 }
110
111 /*
112 * Creates a workers pool
113 */
114 struct Conn_wpool *Conn_wpool_create(const short workers)
115 {
116 struct Conn_wpool *ret;
117 int i, r;
118 pthread_attr_t attr;
119 struct Conn_wpool_worker *w;
120
121 ret = malloc(sizeof(struct Conn_wpool));
122 if (ret == NULL) {
123 Log(0, "Cannot alloc memory for wpool!\n");
124 goto out;
125 }
126
127 ret->ws = calloc(workers, sizeof(struct Conn_wpool_worker));
128 if (ret->ws == NULL) {
129 Log(0, "Cannot alloc memory for workers!\n");
130 goto free_ret;
131 }
132
133 ret->epoll_fd = epoll_create1(EPOLL_CLOEXEC);
134 if (ret->epoll_fd == -1) {
135 Log(0, "Cannot create epoll fd (%s)\n", strerror(errno));
136 goto free_ws;
137 }
138
139 /* Start threads */
140 r = pthread_attr_init(&attr);
141 if (r != 0) {
142 Log(0, "Cannot init attributes.\n");
143 goto close_epoll;
144 }
145
146 r = pthread_attr_setstacksize(&attr, 1 * 1024 * 1024);
147 if (r != 0) {
148 Log(0, "Cannot set stack size!\n");
149 goto close_epoll;
150 }
151
152 for ( i = 0; i < workers; i++) {
153 w = &ret->ws[i];
154 r = Conn_wpool_start_worker(w);
155 if (r != 0)
156 goto destroy_workers;
157 }
158
159 /* Everything is OK */
160 pthread_attr_destroy(&attr);
161
162 ret->workers = workers;
163 ret->next = 0;
164 ret->refs = 0;
165 return ret;
166
167 destroy_workers:
168 for (i = 0; i < workers; i++) {
169 w = &ret->ws[i];
170 Conn_wpool_stop_worker(w);
171 }
172
173 close_epoll:
174 close(ret->epoll_fd);
175
176 free_ws:
177 free(ret->ws);
178
179 free_ret:
180 free(ret);
181
182 out:
183 return NULL;
184 }
185
186 /*
187 * Destroys a worker pool
188 */
189 int Conn_wpool_destroy(struct Conn_wpool *wp)
190 {
191 int i;
192 struct Conn_wpool_worker *w;
193
194 for (i = 0; i < wp->workers; i++) {
195 w = &wp->ws[i];
196 Conn_wpool_stop_worker(w);
197 }
198
199 close(wp->epoll_fd);
200
201 free(wp->ws);
202
203 free(wp);
204
205 return 0;
206 }
207
208 /*
209 * Gets a reference to a wpool structure
210 */
211 void Conn_wpool_get(struct Conn_wpool *wp)
212 {
213 wp->refs++;
214 }
215
216 /*
217 * Decrements usage
218 */
219 void Conn_wpool_put(struct Conn_wpool *wp)
220 {
221 wp->refs--;
222 if (wp->refs == 0)
223 Conn_wpool_destroy(wp);
224 }
225
226 /*
227 * Enqueues a connection to a workers pool
228 */
229 int Conn_wpool_enqueue(struct Conn_wpool *wp, struct Conn *C)
230 {
231 short i;
232 struct Conn_wpool_worker *w;
233 int r;
234 struct epoll_event ev;
235
236 Log(10, "Enqueue C %p to wp %p\n", wp, C);
237
238 /* Round robil algo */
239 i = wp->next;
240 wp->next = (wp->next + 1) % wp->workers;
241
242 w = &wp->ws[i];
243
244 C->flags |= CONN_ACCEPT_PENDING;
245
246 memset(&ev, 0, sizeof(struct epoll_event));
247 ev.events = C->events;
248 ev.data.u32 = C->slot;
249 r = epoll_ctl(w->epoll_fd, EPOLL_CTL_ADD, C->fd, &ev);
250 if (r != 0) {
251 Log(0, "Cannot enqueue fd %d to epoll_fd %d (%s)\n",
252 C->fd, w->epoll_fd, strerror(errno));
253 return -1;
254 }
255
256 return 0;
257 }
File Conn_wpool.h added (mode: 100644) (index 0000000..076e0f4)
1 #ifndef CONN_WPOOL_H
2 #define CONN_WPOOL_H
3
4 #include <Conn_config.h>
5
6 #include <sys/epoll.h>
7
8 #include <Conn_core.h>
9
10 struct Conn_wpool_worker
11 {
12 int epoll_fd;
13 struct epoll_event events[CONN_EVENTS_SLOTS];
14 unsigned char inited:1;
15 int pipe[2];
16 pthread_t tid;
17 };
18
19 struct Conn_wpool
20 {
21 int epoll_fd;
22 unsigned short workers;
23 struct Conn_wpool_worker *ws;
24 unsigned short next; /* next worker to be choosed */
25 unsigned short refs;
26 };
27
28 struct Conn_wpool *Conn_wpool_create(const short workers);
29 int Conn_wpool_destroy(struct Conn_wpool *wp);
30 void Conn_wpool_get(struct Conn_wpool *wp);
31 void Conn_wpool_put(struct Conn_wpool *wp);
32
33 int Conn_wpool_enqueue(struct Conn_wpool *wp,
34 struct Conn *C);
35
36
37 #endif
File Makefile.in changed (mode: 100644) (index c62a877..96a7eb0)
1 1 export CC := gcc export CC := gcc
2 2 export INCS += -I. export INCS += -I.
3 3 export LIBS += -lpthread export LIBS += -lpthread
4 export CFLAGS += -ggdb3 -Wall -Wextra -pedantic -Wno-long-long -pipe -fpic
5 export OBJS += Conn_engine_core.o Conn_engine_epoll.o Conn.o \
4 export CFLAGS += -ggdb3 -Wall -Wextra -pipe -fpic
5 export OBJS += Conn_core.o Conn.o \
6 6 Conn_wpool.o Conn_wpool.o
7 7
8 8 .PHONY: all .PHONY: all
9 9 all: libConn.so.@VER@ all: libConn.so.@VER@
10 10
11 11
12 Conn_engine_core.o: Conn_engine_core.c Conn_engine_core.h Conn_config.h
13 $(CC) $(CFLAGS) $(INCS) -c Conn_engine_core.c
12 Conn_core.o: Conn_core.c Conn_core.h Conn_config.h
13 $(CC) $(CFLAGS) $(INCS) -c Conn_core.c
14 14
15 Conn_engine_epoll.o: Conn_engine_epoll.c Conn_config.h Conn_engine_core.h
16 $(CC) $(CFLAGS) $(INCS) -c Conn_engine_epoll.c
17
18 Conn_wpool.o: Conn_wpool.c Conn_wpool.h Conn_engine_core.o Conn_config.h
15 Conn_wpool.o: Conn_wpool.c Conn_wpool.h Conn_core.o Conn_config.h
19 16 $(CC) $(CFLAGS) $(INCS) -c Conn_wpool.c $(CC) $(CFLAGS) $(INCS) -c Conn_wpool.c
20 17
21 Conn.o: Conn.c Conn.h Conn_engine_core.o Conn_engine_epoll.o Conn_wpool.o
18 Conn.o: Conn.c Conn.h Conn_core.o Conn_wpool.o
22 19 $(CC) $(CFLAGS) $(INCS) -c Conn.c $(CC) $(CFLAGS) $(INCS) -c Conn.c
23 20
24 21 %.o: %.c %.o: %.c
File TODO changed (mode: 100644) (index 76d81cb..f865b30)
10 10 [ ] [ ]
11 11
12 12 == LOW PRIORITY == == LOW PRIORITY ==
13 [ ] How should wpool will be used?
14 C = Conn_alloc();
15 Conn_set_socket_domain(C, PF_INET);
16 Conn_set_socket_type(C, SOCK_STREAM);
17 Conn_set_socket_bind_addr(C, "127.0.0.1");
18 Conn_set_socket_bind_port(C, 60000);
19 Conn_commit(C);
20 Conn_poll();
21 epoll_wait
22 accept
23 w = choose a worker
24 epoll_ctl(w->epoll_fd, new_fd);
25 somehow enqueue 'accept' trigger
26
13 27 [ ] See http://highscalability.com/blog/2012/9/10/russ-10-ingredient-recipe-for-making-1-million-tps-on-5k-har.html [ ] See http://highscalability.com/blog/2012/9/10/russ-10-ingredient-recipe-for-making-1-million-tps-on-5k-har.html
14 28 [ ] Dump all memory statistics [ ] Dump all memory statistics
15 29 [ ] SCTP [ ] SCTP
File duilder.conf changed (mode: 100644) (index 0397e6b..809c9f3)
1 1 PRJ="Conn" PRJ="Conn"
2 VER="1.0.32"
2 VER="1.0.33"
3 3 REV="1" REV="1"
4 4 EXCLUDE="" EXCLUDE=""
5 5 EXPORT_PATH="/data/www/umbrella/kernel/us/Conn" EXPORT_PATH="/data/www/umbrella/kernel/us/Conn"
File examples/blackhole_c.c changed (mode: 100644) (index 306c0b4..69253b1)
... ... static void c_connected(struct Conn *C)
40 40 static void c_error(struct Conn *C) static void c_error(struct Conn *C)
41 41 { {
42 42 printf("%s id=%llu [%s]\n", printf("%s id=%llu [%s]\n",
43 __FUNCTION__, Conn_getid(C), Conn_strerror());
43 __func__, Conn_getid(C), Conn_strerror());
44 44 conn_errors++; conn_errors++;
45 45 } }
46 46
File examples/blackhole_s.c changed (mode: 100644) (index 6cdc100..1a23dc8)
... ... static void s_data(struct Conn *C)
38 38 static void s_error(struct Conn *C) static void s_error(struct Conn *C)
39 39 { {
40 40 printf("%s id=%llu (%s)\n", printf("%s id=%llu (%s)\n",
41 __FUNCTION__, Conn_getid(C), Conn_strerror());
41 __func__, Conn_getid(C), Conn_strerror());
42 42 errors++; errors++;
43 43 } }
44 44
File examples/c.c changed (mode: 100644) (index 6ed591e..d730a68)
... ... static void c_connected(struct Conn *C)
22 22 struct priv *p; struct priv *p;
23 23
24 24 Log(4, "%s(A connection was estabilished on slot %d)\n", Log(4, "%s(A connection was estabilished on slot %d)\n",
25 __FUNCTION__, C->slot);
25 __func__, C->slot);
26 26
27 27 C->private = malloc(sizeof(struct priv)); C->private = malloc(sizeof(struct priv));
28 28 if (C->private == NULL) { if (C->private == NULL) {
 
... ... static void c_connected(struct Conn *C)
37 37 static void c_close(struct Conn *C) static void c_close(struct Conn *C)
38 38 { {
39 39 Log(5, "%s: id=%llu will close...\n", Log(5, "%s: id=%llu will close...\n",
40 __FUNCTION__, Conn_getid(C));
40 __func__, Conn_getid(C));
41 41 free(C->private); free(C->private);
42 42 } }
43 43
 
... ... static void c_data(struct Conn *C)
71 71 static void c_error(struct Conn *C) static void c_error(struct Conn *C)
72 72 { {
73 73 Log(0, "%s id=%llu [%s]\n", Log(0, "%s id=%llu [%s]\n",
74 __FUNCTION__, Conn_getid(C), Conn_strerror());
74 __func__, Conn_getid(C), Conn_strerror());
75 75 } }
76 76
77 77 int main(void) int main(void)
File examples/ma.c added (mode: 100644) (index 0000000..72fa4bc)
1 /*
2 * Test example to see what happends when multiple threads are doing accept
3 */
4
5 #define _GNU_SOURCE
6
7 #include <pthread.h>
8 #include <sys/socket.h>
9 #include <sys/types.h>
10 #include <netinet/ip.h>
11 #include <stdlib.h>
12 #include <stdio.h>
13 #include <string.h>
14 #include <sys/epoll.h>
15
16 struct priv
17 {
18 int master_fd;
19 };
20
21 void *func(void *a)
22 {
23 int r, epollfd;
24 struct sockaddr_in peer;
25 struct priv *p = a;
26 socklen_t size;
27 struct epoll_event e;
28
29 epollfd = epoll_create(32);
30 memset(&e, 0, sizeof(struct epoll_event));
31 e.events = EPOLLIN;
32
33 epoll_ctl(epollfd, EPOLL_CTL_ADD, p->master_fd, &e);
34
35 size = sizeof(struct sockaddr_in);
36 while (1) {
37 r = epoll_wait(epollfd, &e, 1, -1);
38 printf("epoll_wait returned %d\n", r);
39 r = accept(p->master_fd, (struct sockaddr *) &peer, &size);
40 if (r == -1) {
41 perror("accept");
42 }
43 printf("Accept returned %d\n", r);
44 }
45
46 return NULL;
47 }
48
49 int main(void)
50 {
51 pthread_t t[2];
52 int i, r, master_fd;
53 struct sockaddr_in my;
54 struct priv p;
55
56 master_fd = socket(AF_INET, SOCK_STREAM, 0);
57 if (master_fd == -1) {
58 perror("socket");
59 abort();
60 }
61
62 memset(&my, 0, sizeof(struct sockaddr_in));
63 my.sin_port = htons(3000);
64 my.sin_addr.s_addr = INADDR_ANY;
65
66 i = 1;
67 setsockopt(master_fd, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i));
68
69 r = bind(master_fd, (struct sockaddr *) &my, sizeof(struct sockaddr_in));
70 if (r !=0) {
71 perror("bind");
72 abort();
73 }
74
75 listen(master_fd, 32);
76
77 p.master_fd = master_fd;
78
79 for (i = 0; i < 2; i++) {
80 r = pthread_create(&t[i], NULL, func, &p);
81 if (r != 0) {
82 perror("pthread_create");
83 abort();
84 }
85 }
86
87 func(&p);
88
89 return 0;
90 }
File examples/raw.c changed (mode: 100644) (index e5ac141..30c6bb2)
... ... static int maxconn = 0;
31 31 static void s_close(struct Conn *C) static void s_close(struct Conn *C)
32 32 { {
33 33 Log(5, "%s (A connection will be closed [%s] on slot %d)\n", Log(5, "%s (A connection will be closed [%s] on slot %d)\n",
34 __FUNCTION__, C->addr, C->slot);
34 __func__, C->addr, C->slot);
35 35 } }
36 36
37 37 static void s_data(struct Conn *C) static void s_data(struct Conn *C)
 
... ... static void s_data(struct Conn *C)
48 48
49 49 dump = Conn_dumphex(p, len); dump = Conn_dumphex(p, len);
50 50 Log(8, "%s: recv %d bytes at %d.%06d on slot %d: [%s]\n", Log(8, "%s: recv %d bytes at %d.%06d on slot %d: [%s]\n",
51 __FUNCTION__, len, tv.tv_sec, tv.tv_usec, C->slot, dump);
51 __func__, len, tv.tv_sec, tv.tv_usec, C->slot, dump);
52 52 free(dump); free(dump);
53 53
54 54 Conn_eatall(C); Conn_eatall(C);
 
... ... static void s_data(struct Conn *C)
57 57 static void s_error(struct Conn *C) static void s_error(struct Conn *C)
58 58 { {
59 59 Log(1, "%s id=%llu [%s]\n", Log(1, "%s id=%llu [%s]\n",
60 __FUNCTION__, Conn_getid(C), Conn_strerror());
60 __func__, Conn_getid(C), Conn_strerror());
61 61 } }
62 62
63 63 int main(void) int main(void)
File examples/raw2.c changed (mode: 100644) (index bf71e2b..5f19d07)
... ... static int maxconn = 0;
31 31 static void s_close(struct Conn *C) static void s_close(struct Conn *C)
32 32 { {
33 33 Log(5, "%s (A connection will be closed [%s] on slot %d)\n", Log(5, "%s (A connection will be closed [%s] on slot %d)\n",
34 __FUNCTION__, C->addr, C->slot);
34 __func__, C->addr, C->slot);
35 35 } }
36 36
37 37 static void s_data(struct Conn *C) static void s_data(struct Conn *C)
 
... ... static void s_data(struct Conn *C)
48 48
49 49 dump = Conn_dumphex(p, len); dump = Conn_dumphex(p, len);
50 50 Log(8, "%s: recv %d bytes at %d.%06d on slot %d: [%s]\n", Log(8, "%s: recv %d bytes at %d.%06d on slot %d: [%s]\n",
51 __FUNCTION__, len, tv.tv_sec, tv.tv_usec, C->slot, dump);
51 __func__, len, tv.tv_sec, tv.tv_usec, C->slot, dump);
52 52 free(dump); free(dump);
53 53
54 54 Conn_eatall(C); Conn_eatall(C);
 
... ... static void s_data(struct Conn *C)
57 57 static void s_error(struct Conn *C) static void s_error(struct Conn *C)
58 58 { {
59 59 Log(1, "%s slot=%d C=%p [%s]\n", Log(1, "%s slot=%d C=%p [%s]\n",
60 __FUNCTION__, C == NULL ? -1 : C->slot, (void *) C,
60 __func__, C == NULL ? -1 : C->slot, (void *) C,
61 61 Conn_strerror()); Conn_strerror());
62 62 } }
63 63
File examples/reconnect.c changed (mode: 100644) (index 6139a72..74b6d23)
... ... static char *log_file = "reconnect.log";
16 16 static void c_connected(struct Conn *C) static void c_connected(struct Conn *C)
17 17 { {
18 18 Log(4, "%s: A connection was estabilished with id %llu)\n", Log(4, "%s: A connection was estabilished with id %llu)\n",
19 __FUNCTION__, Conn_getid(C));
19 __func__, Conn_getid(C));
20 20 } }
21 21
22 22 static void c_close(struct Conn *C) static void c_close(struct Conn *C)
23 23 { {
24 24 Log(5, "%s: id=%llu will close...\n", Log(5, "%s: id=%llu will close...\n",
25 __FUNCTION__, Conn_getid(C));
25 __func__, Conn_getid(C));
26 26 } }
27 27
28 28 static int c_data_cb(struct Conn *C, char *line) static int c_data_cb(struct Conn *C, char *line)
 
... ... static void c_data(struct Conn *C)
46 46 static void c_error(struct Conn *C) static void c_error(struct Conn *C)
47 47 { {
48 48 Log(0, "%s id=%llu [%s]\n", Log(0, "%s id=%llu [%s]\n",
49 __FUNCTION__, Conn_getid(C), Conn_strerror());
49 __func__, Conn_getid(C), Conn_strerror());
50 50 } }
51 51
52 52 int main(void) int main(void)
File examples/s.c changed (mode: 100644) (index d060697..3345af5)
... ... static int maxconn = 0;
30 30 static void s_accept_error(struct Conn *C) static void s_accept_error(struct Conn *C)
31 31 { {
32 32 Log(0, "%s: Cannot accept a new connection with id %llu!\n", Log(0, "%s: Cannot accept a new connection with id %llu!\n",
33 __FUNCTION__, Conn_getid(C));
33 __func__, Conn_getid(C));
34 34 } }
35 35
36 36 static void s_accept(struct Conn *C) static void s_accept(struct Conn *C)
 
... ... static void s_accept(struct Conn *C)
39 39 char *s; char *s;
40 40
41 41 Log(4, "%s (A connection was accepted from [%s/%d]. Enqueue greeting...\n", Log(4, "%s (A connection was accepted from [%s/%d]. Enqueue greeting...\n",
42 __FUNCTION__, Conn_addr_remote(C), Conn_port_remote(C));
42 __func__, Conn_addr_remote(C), Conn_port_remote(C));
43 43
44 44 s = "Hello!\r\n"; s = "Hello!\r\n";
45 45 err = Conn_enqueue(C, s, strlen(s)); err = Conn_enqueue(C, s, strlen(s));
 
... ... static void s_accept(struct Conn *C)
52 52 static void s_close(struct Conn *C) static void s_close(struct Conn *C)
53 53 { {
54 54 Log(5, "%s (A connection will be closed [%s/%d] id=%lld)\n", Log(5, "%s (A connection will be closed [%s/%d] id=%lld)\n",
55 __FUNCTION__, Conn_addr_remote(C), Conn_addr_remote(C), Conn_getid(C));
55 __func__, Conn_addr_remote(C), Conn_addr_remote(C), Conn_getid(C));
56 56 } }
57 57
58 58 static int s_data_cb(struct Conn *C, char *line) static int s_data_cb(struct Conn *C, char *line)
 
... ... static int s_data_cb(struct Conn *C, char *line)
63 63 if (debug >= 8) { if (debug >= 8) {
64 64 dump = Conn_dump(line, strlen(line)); dump = Conn_dump(line, strlen(line));
65 65 Log(8, "%s: recv: [%s]\n", Log(8, "%s: recv: [%s]\n",
66 __FUNCTION__,
66 __func__,
67 67 dump); dump);
68 68 free(dump); free(dump);
69 69 } }
 
... ... static void s_data(struct Conn *C)
90 90 static void s_error(struct Conn *C) static void s_error(struct Conn *C)
91 91 { {
92 92 Log(1, "%s id=%llu (%s)\n", Log(1, "%s id=%llu (%s)\n",
93 __FUNCTION__, Conn_getid(C), Conn_strerror());
93 __func__, Conn_getid(C), Conn_strerror());
94 94 } }
95 95
96 96 int main(void) int main(void)
File examples/timeout.c changed (mode: 100644) (index a53af91..c8c9474)
... ... static char *log_file = "timeout.log";
12 12 static void c_connected(struct Conn *C) static void c_connected(struct Conn *C)
13 13 { {
14 14 Log(4, "%s(A connection was estabilished on slot %d)\n", Log(4, "%s(A connection was estabilished on slot %d)\n",
15 __FUNCTION__, C->slot);
15 __func__, C->slot);
16 16
17 17
18 18 Conn_close(C); Conn_close(C);
 
... ... static void c_connected(struct Conn *C)
21 21 static void c_close(struct Conn *C) static void c_close(struct Conn *C)
22 22 { {
23 23 Log(5, "%s(Slot %d will close)\n", Log(5, "%s(Slot %d will close)\n",
24 __FUNCTION__, C->slot);
24 __func__, C->slot);
25 25 free(C->private); free(C->private);
26 26 } }
27 27
 
... ... static void c_data(struct Conn *C)
43 43 static void c_error(struct Conn *C) static void c_error(struct Conn *C)
44 44 { {
45 45 Log(0, "%s Slot=%u [%s]\n", Log(0, "%s Slot=%u [%s]\n",
46 __FUNCTION__, C->slot, Conn_strerror());
46 __func__, C->slot, Conn_strerror());
47 47 } }
48 48
49 49 int main(void) int main(void)
File examples/udp_s.c changed (mode: 100644) (index bd450e8..3b26612)
... ... static void s_send(struct Conn *C)
35 35 int fd; int fd;
36 36 ssize_t ret; ssize_t ret;
37 37
38 Log(0, "%s\n", __FUNCTION__);
38 Log(0, "%s\n", __func__);
39 39
40 40 fd = Conn_get_fd(C); fd = Conn_get_fd(C);
41 41 from_len = sizeof(from); from_len = sizeof(from);
42 42 ret = sendto(fd, "xxx\n", 4, 0, (struct sockaddr_in *) &from, from_len); ret = sendto(fd, "xxx\n", 4, 0, (struct sockaddr_in *) &from, from_len);
43 Log(0, "%s: ret = %d\n", __FUNCTION__, ret);
43 Log(0, "%s: ret = %d\n", __func__, ret);
44 44 } }
45 45
46 46 static void s_recv(struct Conn *C) static void s_recv(struct Conn *C)
 
... ... static void s_recv(struct Conn *C)
50 50 char *dump; char *dump;
51 51 ssize_t ret; ssize_t ret;
52 52
53 Log(0, "%s...\n", __FUNCTION__);
53 Log(0, "%s...\n", __func__);
54 54
55 55 fd = Conn_get_fd(C); fd = Conn_get_fd(C);
56 56 from_len = sizeof(from); from_len = sizeof(from);
 
... ... static void s_recv(struct Conn *C)
65 65 if (debug >= 8) { if (debug >= 8) {
66 66 dump = Conn_dump(buf, len); dump = Conn_dump(buf, len);
67 67 Log(8, "%s: recv head=%d tail=%d bytes on slot %d: [%s]\n", Log(8, "%s: recv head=%d tail=%d bytes on slot %d: [%s]\n",
68 __FUNCTION__, C->ibuf_head, C->ibuf_tail,
68 __func__, C->ibuf_head, C->ibuf_tail,
69 69 C->slot, dump); C->slot, dump);
70 70 free(dump); free(dump);
71 71 } }
 
... ... static void s_recv(struct Conn *C)
77 77 static void s_error(struct Conn *C) static void s_error(struct Conn *C)
78 78 { {
79 79 Log(1, "%s: slot=%d, id=%llu\n", Log(1, "%s: slot=%d, id=%llu\n",
80 __FUNCTION__, C->slot, Conn_getid(C));
80 __func__, C->slot, Conn_getid(C));
81 81 } }
82 82
83 83 int main(void) int main(void)
File examples/wpool1.c copied from file examples/trigger.c (similarity 61%) (mode: 100644) (index 43e6bc5..bd07f00)
1 /*
2 * Test workers pool
3 */
4
1 5 #define _GNU_SOURCE #define _GNU_SOURCE
2 6
3 7 #include <errno.h> #include <errno.h>
 
22 26 static unsigned short debug = 1; static unsigned short debug = 1;
23 27
24 28
25 static void trigger(struct Conn *C)
26 {
27 printf("Trigger is running on %llu!\n", Conn_getid(C));
28 }
29
30 29 int main(void) int main(void)
31 30 { {
32 31 char *stat; char *stat;
33 32 int ret; int ret;
34 33 struct Conn *C; struct Conn *C;
34 struct Conn_wpool *wp;
35 35
36 36 Conn_debug(NULL, debug); Conn_debug(NULL, debug);
37 37
 
... ... int main(void)
45 45 C = Conn_alloc(); C = Conn_alloc();
46 46 if (!C) { if (!C) {
47 47 printf("Cannot alloc socket [%s].\n", Conn_strerror()); printf("Cannot alloc socket [%s].\n", Conn_strerror());
48 } else {
49 Conn_set_socket_domain(C, PF_INET);
50 Conn_set_socket_type(C, SOCK_STREAM);
51 Conn_set_socket_bind_addr(C, "127.0.0.1");
52 Conn_set_socket_bind_port(C, 60000);
53 ret = Conn_commit(C);
54 if (ret != 0) {
55 printf("Cannot bind on ipv4 socket [%s].\n",
56 Conn_strerror());
57 }
48 return 1;
49 }
50
51 Conn_set_socket_domain(C, PF_INET);
52 Conn_set_socket_type(C, SOCK_STREAM);
53 Conn_set_socket_bind_addr(C, "127.0.0.1");
54 Conn_set_socket_bind_port(C, 60000);
55 ret = Conn_commit(C);
56 if (ret != 0) {
57 printf("Cannot bind on ipv4 socket [%s].\n",
58 Conn_strerror());
59 return 1;
58 60 } }
59 61
60 /* Install connection specific trigger */
61 Conn_set_cb(C, CONN_CB_TRIGGER, trigger);
62 wp = Conn_wpool_create(3);
63 if (wp == NULL) {
64 printf("Cannot create wpool!\n");
65 return 1;
66 }
62 67
63 /* Force a timeout for connect (in seconds) */
64 Conn_set(C, CONN_PARA_TRIGGER, 3);
68 Conn_add_wp(C, wp);
65 69
66 70 while (1) { while (1) {
67 71 ret = Conn_poll(1000); ret = Conn_poll(1000);
 
... ... int main(void)
71 75 break; break;
72 76 } }
73 77
74 if (ret == 0) {
75 printf("Finish work!\n");
76 break;
77 }
78
79 78 if (debug >= 9) { if (debug >= 9) {
80 79 stat = Conn_status(0); stat = Conn_status(0);
81 80 printf("%s\n", stat); printf("%s\n", stat);
 
... ... int main(void)
83 82 } }
84 83 } }
85 84
85 Conn_del_wp(C, wp);
86
86 87 Conn_shutdown(); Conn_shutdown();
87 88
88 89 return 0; return 0;
File examples/xbind.c changed (mode: 100644) (index de66da2..437be6f)
... ... static char *log_file = "xbind.log";
27 27 static void s_error(struct Conn *C) static void s_error(struct Conn *C)
28 28 { {
29 29 Log(1, "%s id=%llu (%s)\n", Log(1, "%s id=%llu (%s)\n",
30 __FUNCTION__, Conn_getid(C), Conn_strerror());
30 __func__, Conn_getid(C), Conn_strerror());
31 31 } }
32 32
33 33 int main(void) int main(void)
Hints:
Before first commit, do not forget to setup your git environment:
git config --global user.name "your_name_here"
git config --global user.email "your@email_here"

Clone this repository using HTTP(S):
git clone https://rocketgit.com/user/catalinux/Conn

Clone this repository using ssh (do not forget to upload a key first):
git clone ssh://rocketgit@ssh.rocketgit.com/user/catalinux/Conn

Clone this repository using git:
git clone git://git.rocketgit.com/user/catalinux/Conn

You are allowed to anonymously push to this repository.
This means that your pushed commits will automatically be transformed into a merge request:
... clone the repository ...
... make some changes and some commits ...
git push origin main