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)
Wpools work now\! f875d6bea1777c3a290bf9bb1aa047f26c935a63 Catalin(ux) M. BOIE 2013-11-13 20:51:13
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
Commit f875d6bea1777c3a290bf9bb1aa047f26c935a63 - Wpools work now\!
Author: Catalin(ux) M. BOIE
Author date (UTC): 2013-11-13 20:51
Committer name: Catalin(ux) M. BOIE
Committer date (UTC): 2013-11-13 20:51
Parent(s): 1d246f2130d4acf8c267e82051b250a623da6870
Signer:
Signing key:
Signing status: N
Tree: 220e8085985f25dc44ea16b28eb4358b8a237825
File Lines added Lines deleted
Conn.c 3103 482
Conn.h 114 17
Conn_config.h.in 22 1
Conn_core.c 0 1958
Conn_core.h 0 373
Conn_wpool.c 0 257
Conn_wpool.h 0 37
Makefile.in 3 10
TODO 46 27
examples/Makefile 9 4
examples/s.c 1 1
examples/wpool1.c 56 10
examples/wpool2.c 36 14
File Conn.c changed (mode: 100644) (index 1e342ee..2a7b800)
9 9 #include "Conn_config.h" #include "Conn_config.h"
10 10 #include "Conn.h" #include "Conn.h"
11 11
12 int Conn_init(const unsigned int max)
12 #include <sys/epoll.h>
13 #include <stdarg.h>
14 #include <string.h>
15 #include <unistd.h>
16 #include <ctype.h>
17 #include <sys/types.h>
18 #include <sys/socket.h>
19 #include <netinet/in.h>
20 #include <arpa/inet.h>
21 #include <netdb.h>
22 #include <sys/time.h>
23 #include <netinet/tcp.h>
24 #include <errno.h>
25 #include <pthread.h>
26
27
28 /* Stuff that is not needed outside */
29
30 /* type */
31 enum CONN_TYPE {
32 CONN_TYPE_UNK = 0,
33 CONN_TYPE_MASTER,
34 CONN_TYPE_P2P
35 };
36
37 /* state */
38 enum CONN_STATE {
39 CONN_STATE_FREE = 0,
40 CONN_STATE_EMPTY,
41 CONN_STATE_OPEN,
42 CONN_STATE_LISTEN,
43 CONN_STATE_CONNECT_0,
44 CONN_STATE_CONNECT_a,
45 CONN_STATE_CONNECT_b,
46 CONN_STATE_ERROR
47 };
48
49 /* error kind */
50 enum CONN_ERROR {
51 CONN_ERROR_NO_ERROR = 0,
52 CONN_ERROR_USERREQ, /* user requested the close */
53 CONN_ERROR_POLL,
54 CONN_ERROR_RECV,
55 CONN_ERROR_SEND,
56 CONN_ERROR_SOCKET,
57 CONN_ERROR_HANGUP,
58 CONN_ERROR_GETADDRINFO,
59 CONN_ERROR_EXPIRED,
60 CONN_ERROR_ACCEPT, /* This is free. TODO: check! */
61 CONN_ERROR_MEM,
62 CONN_ERROR_CONNECT,
63 CONN_ERROR_READ_TIMEOUT,
64 CONN_ERROR_CONN_TIMEOUT,
65 CONN_ERROR_INTERNAL
66 };
67
68 struct Conn_wpool_worker
69 {
70 int epoll_fd;
71 struct epoll_event events[CONN_EVENTS_SLOTS];
72 unsigned char inited:1;
73 int pipe[2];
74 pthread_t tid;
75 struct Conn *conns_head, *conns_tail;
76 unsigned short id; /* Used for logging */
77
78 /* Keep track of free structures */
79 struct Conn *free_head, *free_tail;
80 unsigned int free_count;
81
82 /* stats */
83 unsigned long mem_structs; /* How much bytes are used for conns */
84 };
85
86 struct Conn_wpool
87 {
88 int epoll_fd;
89 unsigned short workers;
90 struct Conn_wpool_worker *ws;
91 unsigned short next; /* next worker to be choosed */
92 unsigned short refs;
93 };
94
95 /*
96 * Used to define callbacks
97 */
98 struct Conn_cbs
99 {
100 void (*accept)(struct Conn *C);
101 void (*recv)(struct Conn *C);
102 void (*send)(struct Conn *C);
103 void (*data)(struct Conn *C);
104 void (*close)(struct Conn *C);
105 void (*trigger)(struct Conn *C);
106 void (*error)(struct Conn *C);
107 void (*connected)(struct Conn *C);
108 void (*accept_error)(struct Conn *C);
109 };
110
111 struct Conn
112 {
113 struct Conn *next;
114
115 int fd;
116 unsigned int revents; /* I/O events */ /* TODO: really needed? */
117
118 unsigned char type;
119
120 unsigned char state;
121 unsigned char error_state;
122
123 char *ibuf;
124 unsigned int ibuf_size, ibuf_head, ibuf_tail;
125
126 char *obuf;
127 unsigned int obuf_size, obuf_head, obuf_tail;
128
129 struct timeval trecv, tsend; /* last time we saw an receive/send */
130 time_t idle; /* idle time allowed */
131 unsigned int read_timeout; /* Max timeout for receiving an answer (milliseconds) */
132
133 struct timeval conn_syn; /* Time when a connection was initiated */
134 unsigned int conn_timeout; /* Timeout for connection (milliseconds) */
135
136 time_t last_trigger; /* last trigger was at */
137 time_t trigger; /* Frequency of wakeup a connection */
138
139 int sock_domain;
140 int sock_type;
141 int sock_protocol;
142
143 char addr[40], bind_addr[40];
144 int port, bind_port;
145 unsigned long long via; /* "via" is the connection id via a client was accepted */
146
147 unsigned long long bi, bo;
148
149 void *private; /* private use by user */
150
151 /* reconnect stuff */
152 unsigned int retries;
153 unsigned int delay; /* delay between reconnects */
154 time_t tryat; /* when we go to CONNECT_a state */
155
156 int xerrno;
157
158 time_t start;
159
160 /* Flags - TODO: remove 'flags' field */
161 unsigned char auto_reconnect:1;
162 unsigned char close_after_send:1;
163 unsigned char shutdown_after_send:1;
164 unsigned char local_dirty:1;
165 unsigned char remote_dirty:1;
166 unsigned char accept_pending:1;
167 unsigned char is_freed:1; /* 1 is is freed */
168
169 /* bandwidth stuff */
170 struct timeval band_lasttime; /* last time tokens were added */
171 unsigned int band_tokens; /* 1 token -> 1000 bytes */
172 unsigned int band_factor; /* tokens cannot go past f * w */
173 unsigned int band_width; /* in 1000b increments */
174
175 unsigned long long id; /* the id of a connection */
176
177 struct Conn_cbs cbs; /* Specific callbacks */
178
179 struct timeval time_open; /* When a connect succeded */ /* TODO: why not use start? */
180
181 /* wpool */
182 struct Conn_wpool *wp; /* Worker pool associated with this conn */
183 struct Conn_wpool_worker *ww; /* used to link C in active list of a worker */
184 };
185
186 struct Conn_pool
187 {
188 pthread_spinlock_t lock;
189 struct Conn *head, *tail;
190 unsigned int allocated;
191 unsigned short next_block;
192 void *blocks[4096]; /* TODO: make it dynamic */
193 };
194
195
196 /* For parsing */
197 struct Conn_split_cell
198 {
199 struct Conn_split_cell *next;
200 char *left;
201 char *right;
202 unsigned int right_len;
203 };
204
205 struct Conn_split
206 {
207 struct Conn_split_cell *head, *tail;
208 char *line;
209 };
210
211
212 /* ############## static ########### */
213 static int Conn_epoll_fd;
214 static struct epoll_event Conn_epoll_events[CONN_EVENTS_SLOTS];
215
216 static unsigned int Conn_max_reached = 0;
217 static unsigned int Conn_default_ibuf = 256;
218 static unsigned int Conn_default_obuf = 256;
219 static unsigned int Conn_max_ibuf = 4096000;
220 static unsigned int Conn_max_obuf = 4096000;
221
222 /* Max bytes to enqueue on one send/recv call */
223 static unsigned int Conn_max_send = 32 * 1024;
224 static unsigned int Conn_max_recv = 32 * 1024;
225
226 static unsigned int Conn_no = 0;
227 static unsigned int Conn_work_to_do = 0;
228 static unsigned int Conn_max = 0;
229 static unsigned long Conn_total = 0;
230 static unsigned int Conn_start = 0;
231 static unsigned int Conn_pending = 0;
232 static struct timeval Conn_now;
233 static unsigned short Conn_debug_level = 0; /* debug level */
234 /* memory stuff */
235 static unsigned long long Conn_mem_buffers_in = 0;
236 static unsigned long long Conn_mem_buffers_out = 0;
237 #if 0
238 static unsigned long long Conn_mem_structs = 0;
239 #endif
240
241 static struct Conn *Conns = NULL;
242 static unsigned int Conn_inited = 0;
243 static unsigned int Conn_allocated = 0;
244 static unsigned long long Conn_id = 1;
245 static unsigned int Conn_must_stop = 0;
246
247 static __thread char Conn_error[512];
248 static __thread char log_info[32];
249
250 static int Conn_log_fd = 2;
251 static int debug_band = 11;
252 static struct Conn_pool Conn_masters; /* Keeps track of listening sockets */
253 static struct Conn_pool Conn_free; /* Keeps track of free Conns */
254 static pthread_spinlock_t Log_lock;
255
256
257 /* Prototypes */
258 static void Conn_default_cbs_accept(struct Conn *C);
259 static void Conn_default_cbs_recv(struct Conn *C);
260 static void Conn_default_cbs_send(struct Conn *C);
261 static void Conn_default_cbs_data(struct Conn *C);
262 static void Conn_default_cbs_close(struct Conn *C);
263 static void Conn_default_cbs_trigger(struct Conn *C);
264 static void Conn_default_cbs_error(struct Conn *C);
265 static void Conn_default_cbs_connected(struct Conn *C);
266 static void Conn_default_cbs_accept_error(struct Conn *C);
267 int Conn_wpool_enqueue(struct Conn_wpool *wp, struct Conn *C);
268
269 static struct Conn_cbs Conn_default_cbs =
270 {
271 .accept = Conn_default_cbs_accept,
272 .recv = Conn_default_cbs_recv,
273 .send = Conn_default_cbs_send,
274 .data = Conn_default_cbs_data,
275 .close = Conn_default_cbs_close,
276 .trigger = Conn_default_cbs_trigger,
277 .error = Conn_default_cbs_error,
278 .connected = Conn_default_cbs_connected,
279 .accept_error = Conn_default_cbs_accept_error
280 };
281
282
283 /* ############## misc ############# */
284 #if 0
285 __cold void Log(const unsigned short level, char *format, ...)
286 {
287 va_list ap;
288 int len;
289 char line[512];
290
291 if (likely(level > Conn_debug_level))
292 return;
293
294 snprintf(line, sizeof(line), "%ld.%06ld %s ",
295 Conn_now.tv_sec, Conn_now.tv_usec, log_info);
296 len = strlen(line);
297
298 va_start(ap, format);
299 vsnprintf(line + len, sizeof(line) - len, format, ap);
300 va_end(ap);
301
302 //pthread_spin_lock(&Log_lock);
303 write(Conn_log_fd, line, strlen(line));
304 //pthread_spin_unlock(&Log_lock);
305 }
306 #else
307 __cold inline void Log(const unsigned short level, char *format, ...)
308 {
309 return;
310 }
311 #endif
312
313 __hot static inline void my_pthread_spin_lock(pthread_spinlock_t *lock)
314 {
315 int r;
316
317 r = pthread_spin_lock(lock);
318 if (unlikely(r != 0)) {
319 fprintf(stderr, "Cannot lock %p (%s)!\n",
320 lock, strerror(errno));
321 abort();
322 }
323 }
324
325 __hot static inline void my_pthread_spin_unlock(pthread_spinlock_t *lock)
326 {
327 int r;
328
329 r = pthread_spin_unlock(lock);
330 if (unlikely(r != 0)) {
331 fprintf(stderr, "Cannot unlock %p (%s)!\n",
332 lock, strerror(errno));
333 abort();
334 }
335 }
336
337 /*
338 * Set extra log info to distinguish between threads
339 */
340 static void Conn_log_set_info(const char *info)
341 {
342 snprintf(log_info, sizeof(log_info), "%s", info);
343 }
344
345 char *Conn_dump(const void *buf_src0, const int len_src)
346 {
347 int i, j;
348 char tmp[3];
349 char *buf_dst;
350 unsigned char c;
351 const unsigned char *buf_src = buf_src0;
352
353 if (len_src < 0)
354 return strdup("[Error: len < 0]");
355
356 Log(30, "\tConn_dump(%p, len=%d)\n",
357 buf_src, len_src);
358
359 buf_dst = malloc(len_src * 4 + 1);
360 if (buf_dst == NULL)
361 return strdup("Memory allocation error1!");
362
363 j = 0;
364 for (i = 0; i < len_src; i++) {
365 c = buf_src[i];
366 if ((c < 32) || (c > 127)) {
367 buf_dst[j++] = '[';
368 snprintf(tmp, sizeof(tmp), "%02x", c);
369 buf_dst[j++] = tmp[0];
370 buf_dst[j++] = tmp[1];
371 buf_dst[j++] = ']';
372 } else {
373 buf_dst[j++] = c;
374 }
375 }
376
377 buf_dst[j] = '\0';
378
379 return buf_dst;
380 }
381
382 char *Conn_dumphex(const void *buf_src0, const int len_src)
383 {
384 int i, j;
385 char tmp[3];
386 char *buf_dst;
387 unsigned char c;
388 const unsigned char *buf_src = buf_src0;
389
390 if (len_src < 0)
391 return strdup("[Error: len < 0]");
392
393 Log(30, "\tConn_dumphex(%p, len=%d)\n",
394 buf_src, len_src);
395
396 buf_dst = malloc(len_src * 2 + 1);
397 if (buf_dst == NULL)
398 return strdup("Memory allocation error1!");
399
400 j = 0;
401 for (i = 0; i < len_src; i++) {
402 c = buf_src[i];
403 snprintf(tmp, sizeof(tmp), "%02x", c);
404 buf_dst[j++] = tmp[0];
405 buf_dst[j++] = tmp[1];
406 }
407
408 buf_dst[j] = '\0';
409
410 return buf_dst;
411 }
412
413 void Conn_debug(int fd, const unsigned short debug)
414 {
415 Conn_log_fd = fd;
416 Conn_debug_level = debug;
417 }
418
419 static char *Conn_state(const struct Conn *C)
420 {
421 switch (C->state) {
422 case CONN_STATE_FREE: return "FREE";
423 case CONN_STATE_EMPTY: return "EMPTY";
424 case CONN_STATE_OPEN: return "OPEN";
425 case CONN_STATE_LISTEN: return "LISTEN";
426 case CONN_STATE_CONNECT_0: return "CONN0";
427 case CONN_STATE_CONNECT_a: return "CONNa";
428 case CONN_STATE_CONNECT_b: return "CONNb";
429 case CONN_STATE_ERROR: return "ERROR";
430 default: return "BUG?";
431 }
432 }
433
434 /*
435 * Reads a value from proc
436 */
437 static void Conn_read_proc(char *buf, const size_t buf_size, const char *file)
438 {
439 int fd;
440 ssize_t n;
441
442 fd = open(file, O_RDONLY);
443 if (fd == -1) {
444 snprintf(buf, buf_size, "ERROR_OPEN!");
445 return;
446 }
447
448 n = read(fd, buf, buf_size - 1);
449 if (n == -1) {
450 snprintf(buf, buf_size, "ERROR_READ!");
451 } else if (n == 0) {
452 strcpy(buf, "");
453 } else {
454 buf[n - 1] = '\0';
455 n--;
456
457 while ((n >= 0) && (buf[n - 1] == '\n')) {
458 buf[n - 1] = '\0';
459 n--;
460 }
461 }
462
463 close(fd);
464 }
465
466 /*
467 * Returns some important system values
468 */
469 static void Conn_sys(void)
470 {
471 char somaxconn[16];
472 char tcp_max_tw_buckets[16];
473 char tcp_fin_timeout[16];
474
475 Conn_read_proc(somaxconn, sizeof(somaxconn),
476 "/proc/sys/net/core/somaxconn");
477 Conn_read_proc(tcp_max_tw_buckets, sizeof(tcp_max_tw_buckets),
478 "/proc/sys/net/ipv4/tcp_max_tw_buckets");
479 Conn_read_proc(tcp_fin_timeout, sizeof(tcp_fin_timeout),
480 "/proc/sys/net/ipv4/tcp_fin_timeout");
481
482 Log(1, "net.core.somaxconn=%s"
483 " net.ipv4.tcp_max_tw_buckets=%s"
484 " net.ipv4.tcp_fin_timeout=%s\n",
485 somaxconn, tcp_max_tw_buckets, tcp_fin_timeout);
486 }
487
488 /* ############## split ############ */
489 /*
490 * Cut from right, in place, the chars specified in @chars.
491 */
492 static void Conn_rtrim(char *s, const char *chars)
493 {
494 char *e;
495
496 if (!s || (*s == '\0'))
497 return;
498
499 e = s + strlen(s) - 1;
500 while ((e >= s) && (strchr(chars, *e))) {
501 *e = '\0';
502 e--;
503 }
504 }
505
506 /*
507 * Free a prealocated structure
508 */
509 void Conn_split_free(struct Conn_split **s)
510 {
511 struct Conn_split *p;
512 struct Conn_split_cell *q, *next;
513
514 if (!s)
515 return;
516
517 p = *s;
518 if (!p)
519 return;
520
521 q = p->head;
522 while (q) {
523 next = q->next;
524 free(q);
525 q = next;
526 }
527
528 if (p->line)
529 free(p->line);
530
531 free(p);
532 }
533
534 /*
535 * Split a buffer pointed by C to var,value pairs.
536 */
537 struct Conn_split *Conn_split(const char *line0)
538 {
539 char *p;
540 struct Conn_split *ret = NULL;
541 struct Conn_split_cell *q;
542 char search_for;
543 char *left, *right;
544 unsigned int right_len;
545
546 ret = (struct Conn_split *) calloc(1, sizeof(struct Conn_split));
547 if (!ret) {
548 snprintf(Conn_error, sizeof(Conn_error),
549 "cannot alloc memory for Conn_split!\n");
550 return NULL;
551 }
552
553 ret->line = strdup(line0);
554 if (!ret->line) {
555 snprintf(Conn_error, sizeof(Conn_error),
556 "cannot alloc memory for line duplication!\n");
557 goto free;
558 }
559
560 Conn_rtrim(ret->line, "\r\n \t");
561
562 /* do the spliting */
563 p = ret->line;
564 while (*p != '\0') {
565 /* skip empty space */
566 while ((*p == ' ') || (*p == '\t'))
567 p++;
568
569 if (*p == '\0')
570 break;
571
572 /* Init */
573 right = "";
574 right_len = 0;
575
576 /* Building left */
577 left = p;
578 while ((*p != '\0') && (*p != '='))
579 p++;
580 if (*p != '\0') {
581 *p = '\0';
582
583 /* skip '=' */
584 p++;
585
586 /* Building right */
587 right = p;
588
589 search_for = ' ';
590 if (*p == '"') {
591 search_for = '"';
592 p++;
593 }
594
595 while ((*p != '\0') && (*p != search_for)) {
596 right_len++;
597 p++;
598 }
599
600 if (*p != '\0') {
601 *p = '\0';
602 p++;
603 }
604 }
605
606 /* alloc data and fill it */
607 q = (struct Conn_split_cell *) calloc(1, sizeof(struct Conn_split_cell));
608 if (!q) {
609 snprintf(Conn_error, sizeof(Conn_error),
610 "cannot alloc memory!\n");
611 goto free;
612 }
613 q->left = left;
614 q->right = right;
615 q->right_len = right_len;
616
617 if (ret->head == NULL)
618 ret->head = q;
619 else
620 ret->tail->next = q;
621
622 ret->tail = q;
623 }
624
625 return ret;
626
627 free:
628 Conn_split_free(&ret);
629
630 return NULL;
631 }
632
633 /*
634 * Search for a string and return the value
635 */
636 char *Conn_split_get_size(const struct Conn_split *s, const char *left,
637 unsigned int *size)
638 {
639 struct Conn_split_cell *p;
640
641 p = s->head;
642 while (p) {
643 if (strcmp(left, p->left) == 0) {
644 if (size != NULL)
645 *size = p->right_len;
646 return p->right;
647 }
648 p = p->next;
649 }
650
651 return NULL;
652 }
653
654 /*
655 * Search for a string and return the value
656 */
657 char *Conn_split_get_e(const struct Conn_split *s, const char *l)
658 {
659 return Conn_split_get_size(s, l, NULL);
660 }
661
662 /*
663 * Search for a string and return the value or "" if not found
664 */
665 char *Conn_split_get(const struct Conn_split *s, const char *l)
666 {
667 char *r;
668
669 r = Conn_split_get_size(s, l, NULL);
670 if (!r)
671 r = "";
672
673 return r;
674 }
675
676 /*
677 * Return a value as unsigned long
678 */
679 unsigned long Conn_split_get_ul(const struct Conn_split *s, const char *l,
680 unsigned int base)
681 {
682 char *r;
683 unsigned long ret = 0;
684
685 r = Conn_split_get_e(s, l);
686 if (r)
687 ret = strtoul(r, NULL, base);
688
689 return ret;
690 }
691
692 /*
693 * Return a value as unsigned long long
694 */
695 unsigned long long Conn_split_get_ull(const struct Conn_split *s, const char *l,
696 unsigned int base)
697 {
698 char *r;
699 unsigned long long ret = 0;
700
701 r = Conn_split_get_e(s, l);
702 if (r)
703 ret = strtoull(r, NULL, base);
704
705 return ret;
706 }
707
708 /*
709 * Return a value as double
710 */
711 double Conn_split_get_d(const struct Conn_split *s, const char *l)
712 {
713 char *r;
714 double ret = 0;
715
716 r = Conn_split_get_e(s, l);
717 if (r)
718 ret = strtod(r, NULL);
719
720 return ret;
721 }
722
723 #if 0
724 /*
725 * Returns 1 if the string contains only 0-9a-zA-Z. Else 0
726 */
727 static int Conn_alphanum(const char *s)
728 {
729 size_t i, len;
730
731 len = strlen(s);
732 for (i = 0; i < len; i++)
733 if (isalnum(s[i]) == 0)
734 return 0;
735
736 return 1;
737 }
738 #endif
739
740
741 /* ############## wpool ############ */
742
743 /*
744 * Gets a reference to a wpool structure
745 */
746 void Conn_wpool_get(struct Conn_wpool *wp)
747 {
748 wp->refs++;
749 }
750
751 /*
752 * Decrements usage
753 */
754 void Conn_wpool_put(struct Conn_wpool *wp)
755 {
756 wp->refs--;
757 if (wp->refs == 0)
758 Conn_wpool_destroy(wp);
759 }
760
761 /*
762 * Associate a Conn with a workers pool
763 */
764 void Conn_set_wp(struct Conn *C, struct Conn_wpool *wp)
765 {
766 Conn_wpool_get(wp);
767 C->wp = wp;
768 }
769
770 /*
771 * Disassociate a Conn with a workers pool
772 */
773 void Conn_del_wp(struct Conn *C, struct Conn_wpool *wp)
774 {
775 C->wp = NULL;
776 Conn_wpool_put(wp);
777 }
778
779
780 /* ########### conn ############## */
781 /*
782 * Inits a conn pool
783 */
784 static void pool_init(struct Conn_pool *x)
785 {
786 x->head = NULL;
787 x->allocated = 0;
788 x->next_block = 0;
789 pthread_spin_init(&x->lock, PTHREAD_PROCESS_PRIVATE);
790 }
791
792 /*
793 * Returns the lifetime of a connection
794 */
795 unsigned long long Conn_lifetime(struct Conn *C)
796 {
797 return Conn_time_diff(&Conn_now, &C->time_open);
798 }
799
800 char *Conn_strerror(void)
801 {
802 return Conn_error;
803 }
804
805 /*
806 * Difference between two timeval strutures, in milliseconds
807 */
808 long long Conn_time_diff(const struct timeval *t1, const struct timeval *t2)
809 {
810 return (t1->tv_sec - t2->tv_sec) * 1000
811 + (t1->tv_usec - t2->tv_usec) / 1000;
812 }
813
814 /*
815 * Returns string representation of errno code
816 */
817 char *Conn_errno(const struct Conn *C)
818 {
819 static char buf[256];
820 char *is;
821
822 switch (C->error_state) {
823 case CONN_ERROR_USERREQ: is = "user"; break;
824 case CONN_ERROR_POLL: is = "poll"; break;
825 case CONN_ERROR_RECV: is = "recv"; break;
826 case CONN_ERROR_SEND: is = "send"; break;
827 case CONN_ERROR_SOCKET: is = "socket"; break;
828 case CONN_ERROR_HANGUP: is = "hangup"; break;
829 case CONN_ERROR_GETADDRINFO: is = "lookup error"; break;
830 case CONN_ERROR_EXPIRED: is = "expired"; break;
831 case CONN_ERROR_ACCEPT: is = "accept"; break;
832 case CONN_ERROR_MEM: is = "allocation failed"; break;
833 case CONN_ERROR_CONNECT: is = "connect"; break;
834 case CONN_ERROR_READ_TIMEOUT: is = "read timeout"; break;
835 case CONN_ERROR_CONN_TIMEOUT: is = "conn timeout"; break;
836 case CONN_ERROR_INTERNAL: is = "internal error"; break;
837 default: is = "?"; break;
838 }
839
840 snprintf(buf, sizeof(buf), "%s (%s)",
841 is, (C->xerrno > 0) ? strerror(C->xerrno) : "-");
842
843 return buf;
844 }
845
846 /*
847 * Raise an error. It is just a little helper.
848 */
849 static void Conn_error_raise(struct Conn *C, const int err)
850 {
851 if (err != 0)
852 C->xerrno = err;
853
854 if (C->cbs.error)
855 C->cbs.error(C);
856 }
857
858 /* set noblocking */
859 static int Conn_setnonblock(const int fd)
860 {
861 return fcntl(fd, F_SETFL, O_NONBLOCK | O_RDWR);
862 }
863
864 /*
865 * Expand the requested buffer
866 * what = 0 for out buffer, what = 1 for input buffer
867 * returns 0 if OK, -1 on error
868 */
869 __cold static int Conn_try_expand_buf(struct Conn *C, const char what,
870 const unsigned int needed)
871 {
872 char *p;
873 unsigned int hm;
874 unsigned int old_size, amount, head, tail;
875 unsigned int max_buf;
876 char *pbuf;
877
878 if (what == 0) {
879 head = C->obuf_head;
880 tail = C->obuf_tail;
881 old_size = C->obuf_size;
882 max_buf = Conn_max_obuf;
883 pbuf = C->obuf;
884 } else {
885 head = C->ibuf_head;
886 tail = C->ibuf_tail;
887 old_size = C->ibuf_size;
888 max_buf = Conn_max_ibuf;
889 pbuf = C->ibuf;
890 }
891
892 /* Do we have enough room? */
893 if (old_size - tail >= needed)
894 return 0;
895
896 Log(10, "\tTry to expand buffer for [%s] have=%d needed=%d"
897 " head=%u tail=%u.\n",
898 what == 0 ? "O" : "I", old_size, old_size + needed, head, tail);
899
900 amount = needed - (old_size - tail);
901
902 /* Do not alloc less than 128 bytes */
903 if (amount < 128)
904 amount = 128;
905
906 hm = old_size + amount;
907 if ((max_buf > 0) && (hm > max_buf))
908 hm = max_buf;
909
910 /* Seems we are not allowed to grow larger */
911 if (hm <= old_size) {
912 Log(1, "Cannot obtain needed bytes:"
913 " hm(%u) <= old_size(%u)!\n",
914 hm, old_size);
915 return -1;
916 }
917
918 p = realloc(pbuf, hm);
919 if (p == NULL) {
920 Log(1, "Cannot realloc pbuf to %u bytes!\n", hm);
921 return -1;
922 }
923
924 if (what == 0) {
925 C->obuf = p;
926 C->obuf_size = hm;
927 Conn_mem_buffers_out += hm - old_size;
928 } else {
929 C->ibuf = p;
930 C->ibuf_size = hm;
931 Conn_mem_buffers_in += hm - old_size;
932 }
933
934 return 0;
935 }
936
937 /*
938 * Do not use it yet, it sucks (the paras)
939 */
940 static void Conn_poll_status(const short ev, char *ret)
941 {
942 int i = 0;
943
944 strcpy(ret, "");
945
946 if (ev & EPOLLIN) ret[i++] = 'I';
947 if (ev & EPOLLPRI) ret[i++] = 'P';
948 if (ev & EPOLLOUT) ret[i++] = 'O';
949 if (ev & EPOLLERR) ret[i++] = 'E';
950 if (ev & EPOLLHUP) ret[i++] = 'H';
951 if (ev & EPOLLRDHUP) ret[i++] = 'h';
952 ret[i++] = '\0';
953 }
954
955 static char *Conn_domain(const struct Conn *C)
956 {
957 switch (C->sock_domain) {
958 case PF_INET: return "IPv4";
959 case PF_INET6: return "IPv6";
960 case PF_PACKET: return "PACKET";
961 default: return "?";
962 }
963 }
964
965 static char *Conn_type(const struct Conn *C)
966 {
967 switch (C->sock_type) {
968 case SOCK_STREAM: return "stream";
969 case SOCK_DGRAM: return "dgram";
970 case SOCK_RAW: return "raw";
971 default: return "?";
972 }
973 }
974
975 static char *Conn_get_socket_protocol(const struct Conn *C)
976 {
977 switch (C->sock_protocol) {
978 case IPPROTO_IP: return "IP";
979 default: return "?";
980 }
981 }
982
983 static char *Conn_socktype(const struct Conn *C)
984 {
985 switch (C->type) {
986 case CONN_TYPE_UNK: return "unk";
987 case CONN_TYPE_MASTER: return "master";
988 case CONN_TYPE_P2P: return "p2p";
989 default: return "?";
990 }
991 }
992
993 /*
994 * Returns the string representation of an socket address
995 * @flags: bit0==0 => local address, bit0==1 => peer address
996 */
997 static int Conn_set_address(struct Conn *C, const int flags)
998 {
999 int err;
1000 struct sockaddr *psa;
1001 struct sockaddr_in sa4;
1002 struct sockaddr_in6 sa6;
1003 socklen_t sa_len;
1004 char *paddr;
1005 size_t addr_size;
1006 int *pport;
1007
1008 /* Test if we need to regenerate. */
1009 if (flags & 1) {
1010 if (C->remote_dirty == 0)
1011 return 0;
1012 } else {
1013 if (C->local_dirty == 0)
1014 return 0;
1015 }
1016
1017 if (C->state == CONN_STATE_FREE)
1018 return 0;
1019
1020 switch (C->sock_domain) {
1021 case PF_INET:
1022 psa = (struct sockaddr *) &sa4;
1023 sa_len = sizeof(struct sockaddr_in);
1024 break;
1025 case PF_INET6:
1026 psa = (struct sockaddr *) &sa6;
1027 sa_len = sizeof(struct sockaddr_in6);
1028 break;
1029 default:
1030 return -1;
1031 }
1032
1033 if (flags & 1) {
1034 /* peer */
1035 paddr = C->addr;
1036 addr_size = sizeof(C->addr);
1037 pport = &C->port;
1038 err = getpeername(C->fd, psa, &sa_len);
1039 } else {
1040 /* local */
1041 paddr = C->bind_addr;
1042 addr_size = sizeof(C->bind_addr);
1043 pport = &C->bind_port;
1044 err = getsockname(C->fd, psa, &sa_len);
1045 }
1046
1047 if (err != 0) {
1048 snprintf(paddr, addr_size, "?");
1049 return -1;
1050 }
1051
1052 switch (C->sock_domain) {
1053 case PF_INET:
1054 inet_ntop(C->sock_domain, &sa4.sin_addr,
1055 paddr, addr_size);
1056 *pport = ntohs(sa4.sin_port);
1057 break;
1058 case PF_INET6:
1059 inet_ntop(C->sock_domain, &sa6.sin6_addr,
1060 paddr, addr_size);
1061 *pport = ntohs(sa6.sin6_port);
1062 break;
1063 default:
1064 return -1;
1065 }
1066
1067 /* Remove dirty flag */
1068 if (flags & 1) {
1069 C->remote_dirty = 0;
1070 } else {
1071 C->local_dirty = 0;
1072 }
1073
1074 return 0;
1075 }
1076
1077 /*
1078 * Returns local address
1079 */
1080 char *Conn_addr_local(struct Conn *C)
1081 {
1082 Conn_set_address(C, 0);
1083
1084 return C->bind_addr;
1085 }
1086
1087 /*
1088 * Returns remote address
1089 */
1090 char *Conn_addr_remote(struct Conn *C)
1091 {
1092 Conn_set_address(C, 1);
1093
1094 return C->addr;
1095 }
1096
1097 /*
1098 * Returns local port
1099 */
1100 int Conn_port_local(struct Conn *C)
1101 {
1102 Conn_set_address(C, 0);
1103
1104 return C->bind_port;
1105 }
1106
1107 /*
1108 * Returns remote port
1109 */
1110 int Conn_port_remote(struct Conn *C)
1111 {
1112 Conn_set_address(C, 1);
1113
1114 return C->port;
1115 }
1116
1117 #if 0
1118 /*
1119 * Returns the address family for address stored in @addr.
1120 */
1121 static int Conn_addr_family(const char *addr)
1122 {
1123 struct addrinfo hints, *results = NULL;
1124 int ret;
1125
1126 memset(&hints, 0, sizeof(struct addrinfo));
1127 hints.ai_family = AF_UNSPEC;
1128 hints.ai_socktype = 0;
1129 hints.ai_flags = AI_NUMERICHOST;
1130 hints.ai_protocol = 0;
1131 hints.ai_canonname = NULL;
1132 hints.ai_addr = NULL;
1133 hints.ai_next = NULL;
1134
1135 ret = getaddrinfo(addr, NULL, &hints, &results);
1136 if (ret != 0) {
1137 snprintf(Conn_error, sizeof(Conn_error),
1138 "getaddrinfo error on %s (%s)",
1139 addr, gai_strerror(ret));
1140 if (results)
1141 freeaddrinfo(results);
1142 return -1;
1143 }
1144
1145 ret = results->ai_family;
1146
1147 freeaddrinfo(results);
1148
1149 return ret;
1150 }
1151 #endif
1152
1153 /*
1154 * Returns a nice speed
1155 */
1156 static void Conn_speed(char *dst, const unsigned int dst_len,
1157 const unsigned int speed)
1158 {
1159 float sp;
1160
1161 sp = speed;
1162
1163 if (speed < 1000)
1164 snprintf(dst, dst_len, "%.2fBps", sp);
1165 else if (speed < 1000 * 1000)
1166 snprintf(dst, dst_len, "%.2fKBps", sp / 1000);
1167 else
1168 snprintf(dst, dst_len, "%.2fMBps", sp / 1000 / 1000);
1169 }
1170
1171 static char *Conn_status_slot(struct Conn *C)
1172 {
1173 static char tmp[1024];
1174 char pollr[16];
1175 char speedi[32], speedo[32];
1176 unsigned int dT, si, so;
1177 char flags[128], flags_prefix[3], flags_postfix[2];
1178 char *local_addr, *remote_addr;
1179 int local_port, remote_port;
1180 char flags_tmp[64];
1181
1182 /* flags */
1183 strcpy(flags, "");
1184 strcpy(flags_prefix, " [");
1185 strcpy(flags_postfix, "");
1186
1187 if (C->auto_reconnect) {
1188 strcat(flags, flags_prefix);
1189 snprintf(flags_tmp, sizeof(flags_tmp), "autoreconnect_in_%ld/%u",
1190 (C->tryat == 0) ? 0 : C->tryat - Conn_now.tv_sec,
1191 C->delay);
1192 strcat(flags, flags_tmp);
1193 strcpy(flags_prefix, " ");
1194 strcpy(flags_postfix, "]");
1195 }
1196 if (C->close_after_send) {
1197 strcat(flags, flags_prefix);
1198 strcat(flags, "close_after_send");
1199 strcpy(flags_prefix, " ");
1200 strcpy(flags_postfix, "]");
1201 }
1202 if (C->shutdown_after_send) {
1203 strcat(flags, flags_prefix);
1204 strcat(flags, "shutdown_after_send");
1205 strcpy(flags_prefix, " ");
1206 strcpy(flags_postfix, "]");
1207 }
1208
1209 strcat(flags, flags_postfix);
1210
1211 Conn_poll_status(C->revents, pollr);
1212
1213 dT = Conn_now.tv_sec - C->start;
1214 if (dT == 0)
1215 dT = 1;
1216 si = C->bi / dT;
1217 so = C->bo / dT;
1218
1219 Conn_speed(speedi, sizeof(speedi), si);
1220 Conn_speed(speedo, sizeof(speedo), so);
1221
1222 Conn_set_address(C, 0);
1223 Conn_set_address(C, 1);
1224
1225 local_addr = "-";
1226 local_port = 0;
1227 remote_addr = "-";
1228 remote_port = 0;
1229 if (C->type == CONN_TYPE_MASTER) {
1230 local_addr = C->bind_addr;
1231 local_port = C->bind_port;
1232 } else if (C->type == CONN_TYPE_P2P) {
1233 if (C->bind_addr[0] != '\0') {
1234 local_addr = C->bind_addr;
1235 local_port = C->bind_port;
1236 }
1237 remote_addr = C->addr;
1238 remote_port = C->port;
1239 }
1240
1241 snprintf(tmp, sizeof(tmp), "%p id=%llu fd=%d"
1242 " %s/%s/%s"
1243 " %s %s"
1244 " %s/%d <-> %s/%d"
1245 " via=%llu [%s] IO=%llu/%llu"
1246 " BS=%u/%u S=%s/%s"
1247 " T=%ld bw=%u f=%u tk=%u next=%p"
1248 "%s",
1249 C, C->id, C->fd,
1250 Conn_domain(C), Conn_type(C),
1251 Conn_get_socket_protocol(C),
1252 Conn_socktype(C), Conn_state(C),
1253 local_addr, local_port, remote_addr, remote_port,
1254 C->via, pollr, C->bi, C->bo,
1255 C->ibuf_size, C->obuf_size, speedi, speedo,
1256 Conn_now.tv_sec - C->start,
1257 C->band_width, C->band_factor, C->band_tokens,
1258 C->next, flags);
1259
1260 return tmp;
1261 }
1262
1263 #if 0
1264 static char *Conn_status_slot_html(struct Conn *C)
1265 {
1266 static char tmp[1024];
1267 char pollr[16], *ext = "";
1268 char speedi[32], speedo[32];
1269 unsigned int dT, si, so;
1270
1271 Conn_poll_status(C->revents, pollr);
1272
1273 dT = Conn_now.tv_sec - C->start;
1274 if (dT == 0)
1275 dT = 1;
1276 si = C->bi / dT;
1277 so = C->bo / dT;
1278
1279 Conn_speed(speedi, sizeof(speedi), si);
1280 Conn_speed(speedo, sizeof(speedo), so);
1281
1282 #if 0
1283 TODO
1284 if (Conn_status_slot_html_cb)
1285 ext = Conn_status_slot_html_cb(C);
1286 #endif
1287
1288 snprintf(tmp, sizeof(tmp), "<td>%llu</td><td>%d</td>"
1289 "<td>%s</td><td>%s</td><td>%s</td>"
1290 "<td>%s</td><td>%s</td>"
1291 "<td>%s/%d</td>"
1292 "<td>%llu</td><td>%s</td><td>%llu / %llu</td>"
1293 "<td>%u / %u</td><td>%s / %s</td><td>%ld</td>"
1294 "<td>%u</td><td>%u</td><td>%u</td>"
1295 "%s",
1296 C->id, C->fd,
1297 Conn_domain(C), Conn_type(C), Conn_get_socket_protocol(C),
1298 Conn_socktype(C), Conn_state(C),
1299 C->addr, C->port, C->via, pollr, C->bi, C->bo,
1300 C->ibuf_size, C->obuf_size,
1301 speedi, speedo, Conn_now.tv_sec - C->start,
1302 C->band_width, C->band_factor, C->band_tokens,
1303 ext);
1304
1305 return tmp;
1306 }
1307 #endif
1308
1309 #if 0
1310 /* flags: bit 1 = 1 - html */
1311 char *Conn_status(const unsigned int flags)
1312 {
1313 unsigned int len = 0, max, tmp_len;
1314 char tmp[512];
1315 char pollr[16];
1316 char *buf, *per_slot, *ext = "";
1317 char speedi[32], speedo[32];
1318 unsigned long long bi, bo, dT;
1319
1320 max = (Conn_no + 1) * 512 - 1;
1321 buf = malloc(max + 1);
1322 if (!buf)
1323 return strdup("No enough memory!");
1324
1325 strcpy(buf, "");
1326
1327 gettimeofday(&Conn_now, NULL);
1328 /* TODO: "len += " is incorrect */
1329 tmp_len = snprintf(tmp, sizeof(tmp),
1330 "Conn_pending=%d Conn_no/Conn_max=%d/%d Conn_total=%lu"
1331 " Conn_uptime=%lus Conn_allocated=%d Conn_work_to_do=%u"
1332 " Conn_mem_structs=%llu Conn_mem_buffers_in/out=%llu/%llu\n",
1333 Conn_pending, Conn_no, Conn_max, Conn_total,
1334 Conn_now.tv_sec - Conn_start, Conn_allocated, Conn_work_to_do,
1335 Conn_mem_structs, Conn_mem_buffers_in, Conn_mem_buffers_out);
1336 if ((tmp_len > 0) && (len + tmp_len < max)) {
1337 strcat(buf, tmp);
1338 len += tmp_len;
1339 }
1340
1341 #if 0
1342 TODO
1343 if (flags & 1)
1344 if (Conn_status_cb)
1345 ext = Conn_status_cb();
1346 #endif
1347
1348 if (flags & 1) {
1349 strcat(buf, "<table border=\"0\" cellspacing=\"1\" cellpadding=\"3\" bgcolor=\"#aaaaaa\">\n");
1350 strcat(buf, "<tr bgcolor=\"ffffff\">\n");
1351 strcat(buf, "<td>ID</td>");
1352 strcat(buf, "<td>FD</td>");
1353 strcat(buf, "<td>Dom</td>");
1354 strcat(buf, "<td>Type</td>");
1355 strcat(buf, "<td>Protocol</td>");
1356 strcat(buf, "<td>SType</td>");
1357 strcat(buf, "<td>State</td>");
1358 strcat(buf, "<td>Addr/port</td>");
1359 strcat(buf, "<td>Via</td>");
1360 strcat(buf, "<td>Pollr</td>");
1361 strcat(buf, "<td>BI/BO</td>");
1362 strcat(buf, "<td>BUF I/O</td>");
1363 strcat(buf, "<td>Speed I/O</td>");
1364 strcat(buf, "<td>Elap (s)</td>");
1365 strcat(buf, "<td>Band</td>");
1366 strcat(buf, "<td>F</td>");
1367 strcat(buf, "<td>Tks</td>");
1368 strcat(buf, ext);
1369 strcat(buf, "</tr>\n");
1370 } else {
1371 strcat(buf, ext);
1372 }
1373
1374 #if 0
1375 TODO
1376 bi = 0; bo = 0; dT = 0;
1377 for (slot = 0; slot < Conn_no; slot++) {
1378 if (C->state == CONN_STATE_FREE)
1379 continue;
1380
1381 if (C->type == CONN_TYPE_P2P) {
1382 bi += C->bi;
1383 bo += C->bo;
1384 dT += Conn_now.tv_sec - C->start;
1385 }
1386
1387 if (flags & 1)
1388 strcat(buf, "<tr bgcolor=\"ffffff\">\n");
1389
1390 Conn_poll_status(C->revents, pollr);
1391
1392 if ((flags & 1) == 0)
1393 per_slot = Conn_status_slot(slot);
1394 else
1395 per_slot = Conn_status_slot_html(slot);
1396 len += snprintf(tmp, sizeof(tmp), "%s\n", per_slot);
1397 if (len < max)
1398 strcat(buf, tmp);
1399
1400 if (flags & 1)
1401 strcat(buf, "</tr>\n");
1402 }
1403 #endif
1404
1405 if (flags & 1)
1406 strcat(buf, "</table>\n");
1407
1408 if (dT == 0)
1409 dT = 1;
1410
1411 Conn_speed(speedi, sizeof(speedi), bi / dT);
1412 Conn_speed(speedo, sizeof(speedo), bo / dT);
1413
1414 tmp_len = snprintf(tmp, sizeof(tmp), "Total speed I/O: %s/%s."
1415 " Total bytes I/O: %llu/%llu\n",
1416 speedi, speedo, bi, bo);
1417 if (len + tmp_len < max) {
1418 strcat(buf, tmp);
1419 len += tmp_len;
1420 }
1421
1422 return buf;
1423 }
1424 #endif
1425
1426 /*
1427 * Returns the number of bytes in 'in' buffer
1428 */
1429 unsigned int Conn_iqlen(const struct Conn *C)
1430 {
1431 return C->ibuf_tail - C->ibuf_head;
1432 }
1433
1434 /*
1435 * Returns the number of bytes in 'out' buffer
1436 */
1437 unsigned int Conn_oqlen(const struct Conn *C)
1438 {
1439 return C->obuf_tail - C->obuf_head;
1440 }
1441
1442 /*
1443 * Returns the number of bytes in 'in' buffer (obsolete)
1444 */
1445 unsigned int Conn_qlen(const struct Conn *C)
1446 {
1447 return Conn_iqlen(C);
1448 }
1449
1450 #if 0
1451 TODO - really needed?
1452 /*
1453 * Returns 1 if we can ignore this connection
1454 */
1455 static int Conn_ignore(struct Conn *C)
1456 {
1457 if (C->error_state > 0)
1458 return 1;
1459
1460 if (C->is_freed == 1)
1461 return 1;
1462
1463 return 0;
1464 }
1465 #endif
1466
1467 #if 0
1468 /*
1469 * Close a connection if it exceeded maximum idle time or got a timeout
1470 */
1471 static void Conn_expire(struct Conn *C)
1472 {
1473 long long diff_ms;
1474
1475 if (C->trigger > 0) {
1476 /* We do not trigger first time */
1477 if (C->last_trigger == 0)
1478 C->last_trigger = Conn_now.tv_sec;
1479
1480 if ((C->last_trigger > 0)
1481 && (C->last_trigger + C->trigger < Conn_now.tv_sec)) {
1482 if (C->cbs.trigger)
1483 C->cbs.trigger(C);
1484 C->last_trigger = C->last_trigger + C->trigger;
1485 }
1486 }
1487
1488 if ((C->idle > 0) && (C->trecv.tv_sec + C->idle < Conn_now.tv_sec)) {
1489 C->error_state = CONN_ERROR_EXPIRED;
1490 } else if ((C->read_timeout > 0) && (C->tsend.tv_sec > 0)
1491 && (C->tsend.tv_sec > C->trecv.tv_sec)) {
1492 diff_ms = Conn_time_diff(&Conn_now, &C->tsend);
1493 if (diff_ms > C->read_timeout) {
1494 C->error_state = CONN_ERROR_READ_TIMEOUT;
1495 }
1496 } else if ((C->conn_timeout > 0) && (C->state == CONN_STATE_CONNECT_b)) {
1497 diff_ms = Conn_time_diff(&Conn_now, &C->conn_syn);
1498 if (diff_ms > C->conn_timeout) {
1499 /* connection attempt expired */
1500 C->error_state = CONN_ERROR_CONN_TIMEOUT;
1501 }
1502 }
1503 }
1504 #endif
1505
1506 /*
1507 * Set NODELAY on socket
1508 */
1509 int Conn_nodelay(const struct Conn *C)
1510 {
1511 int i = 1;
1512
1513 return setsockopt(C->fd, SOL_TCP, TCP_NODELAY, &i, sizeof(i));
1514 }
1515
1516 void Conn_rollback(struct Conn *C, const unsigned int bytes)
1517 {
1518 if (C->obuf_tail - C->obuf_head <= bytes)
1519 C->obuf_tail -= bytes;
1520 }
1521
1522 /*
1523 * Returns a pointer to current in buffer
1524 */
1525 char *Conn_ibuf(const struct Conn *C)
1526 {
1527 return C->ibuf + C->ibuf_head;
1528 }
1529
1530 /*
1531 * Returns a pointer to current out buffer
1532 */
1533 char *Conn_obuf(const struct Conn *C)
1534 {
1535 return C->obuf + C->obuf_head;
1536 }
1537
1538 /*
1539 * Returns the id of a connection
1540 */
1541 unsigned long long Conn_getid(const struct Conn *C)
1542 {
1543 return C->id;
1544 }
1545
1546 /*
1547 * Returns a Conn* searching by id
1548 */
1549 struct Conn *Conn_get(const unsigned long long id)
1550 {
1551 struct Conn *R = NULL;
1552 int i;
1553
1554 for (i = Conn_no - 1; i >= 0; i--) {
1555 if (Conns[i].id == id) {
1556 R = &Conns[i];
1557 break;
1558 }
1559 }
1560
1561 return R;
1562 }
1563
1564 /*
1565 * Returns the fd associated with C
1566 */
1567 static int Conn_get_fd(const struct Conn *C)
1568 {
1569 return C->fd;
1570 }
1571
1572 /*
1573 * Returns the timeval of the last packet
1574 */
1575 void Conn_last_time(const struct Conn *C, struct timeval *tv)
1576 {
1577 *tv = C->trecv;
1578 }
1579
1580 /*
1581 * Set a callback
1582 */
1583 int Conn_set_cb(struct Conn *C, const unsigned int cb_type,
1584 void (*f)(struct Conn *))
1585 {
1586 Log(12, "%s %u %p\n", __func__, cb_type, f);
1587 switch (cb_type) {
1588 case CONN_CB_ACCEPT: C->cbs.accept = f; break;
1589 case CONN_CB_RECV: C->cbs.recv = f; break;
1590 case CONN_CB_SEND: C->cbs.send = f; break;
1591 case CONN_CB_DATA: C->cbs.data = f; break;
1592 case CONN_CB_CLOSE: C->cbs.close = f; break;
1593 case CONN_CB_TRIGGER: C->cbs.trigger = f; break;
1594 case CONN_CB_ERROR: C->cbs.error = f; break;
1595 case CONN_CB_CONNECTED: C->cbs.connected = f; break;
1596 case CONN_CB_ACCEPT_ERROR: C->cbs.accept_error = f; break;
1597 default: return -1;
1598 }
1599
1600 return 0;
1601 }
1602
1603 /*
1604 * Search for str in active buffer from a given offset
1605 * Returns pointer to string if match or NULL if doesn't.
1606 * @flags: bit 0 == 1 => case insensitive
1607 */
1608 char *Conn_ostrstr(struct Conn *C, const unsigned int off, const char *str,
1609 const unsigned int flags)
1610 {
1611 unsigned int len, str_len, i;
1612 char *buf, *ret = NULL;
1613 int err;
1614
1615 len = C->ibuf_tail - C->ibuf_head - off;
1616 buf = C->ibuf + C->ibuf_head + off;
1617 str_len = strlen(str);
1618
1619 if (len < str_len)
1620 return NULL;
1621
1622 i = 0;
1623 while (i <= len - str_len) {
1624 if (flags & 1)
1625 err = strncasecmp(buf + i, str, str_len);
1626 else
1627 err = strncmp(buf + i, str, str_len);
1628 if (err == 0) {
1629 ret = buf + i;
1630 break;
1631 }
1632
1633 i++;
1634 }
1635
1636 return ret;
1637 }
1638
1639 /*
1640 * Search for str in active buffer
1641 * Returns pointer to string if match or NUll if doesn't.
1642 */
1643 char *Conn_strstr(struct Conn *C, const char *str)
1644 {
1645 return Conn_ostrstr(C, 0, str, 0);
1646 }
1647
1648 /*
1649 * Search for str in active buffer (case insensitive)
1650 * Returns pointer to string if match or NUll if doesn't.
1651 */
1652 char *Conn_strcasestr(struct Conn *C, const char *str)
1653 {
1654 return Conn_ostrstr(C, 0, str, 1);
1655 }
1656
1657 /*
1658 * Returns a '\0' terminated line, modifying received buffer
1659 */
1660 char *Conn_get_line(struct Conn *C)
1661 {
1662 char *cr;
1663
1664 cr = Conn_ostrstr(C, 0, "\n", 1);
1665 if (!cr)
1666 return NULL;
1667
1668 *cr = '\0';
1669
1670 return Conn_ibuf(C);
1671 }
1672
1673 /*
1674 * Helper help building text line daemons
1675 */
1676 void Conn_for_every_line(struct Conn *C, void (*cb)(struct Conn *C, char *line))
1677 {
1678 char *line;
1679 unsigned int line_size;
1680
1681 if (cb == NULL)
1682 return;
1683
1684 while (1) {
1685 /* TODO: Conn_get_line may also return the size */
1686 line = Conn_get_line(C);
1687 if (line == NULL)
1688 break;
1689
1690 line_size = strlen(line) + 1;
1691
1692 Conn_rtrim(line, "\r");
1693
1694 cb(C, line);
1695
1696 Conn_eat(C, line_size);
1697 }
1698 }
1699
1700 /*
1701 * Formats a line and puts it in the queue
1702 * Returns -1 on error.
1703 */
1704 int Conn_printf(struct Conn *C, const char *format, ...)
1705 {
1706 va_list ap;
1707 char *s;
1708 int d, len, r;
1709 char tmp[64];
1710
1711 va_start(ap, format);
1712 while (likely(*format)) {
1713 /* Find first formatting char */
1714 s = strchr(format, '%');
1715 if (unlikely(!s)) {
1716 r = Conn_enqueue_wait(C, format, strlen(format));
1717 return r == -1 ? -1 : 0;
1718 }
1719
1720 len = s - format;
1721 r = Conn_enqueue_wait(C, format, len);
1722 /* TODO: Should we call error callback and close the connection? */
1723 if (unlikely(r == -1))
1724 return -1;
1725
1726 format = s + 1;
1727 s = tmp;
1728 switch (*format) {
1729 case '%': tmp[0] = '%'; len = 1; break;
1730 case 's': s = va_arg(ap, char *); len = strlen(s); break;
1731
1732 case 'd':
1733 d = va_arg(ap, int);
1734 /* TODO: replace this with another function. Doh! */
1735 len = snprintf(tmp, sizeof(tmp), "%d", d);
1736 break;
1737
1738 case 'c':
1739 tmp[0] = (char) va_arg(ap, int);
1740 len = 1;
1741 break;
1742
1743 case '\0': s = NULL; break;
1744
1745 default:
1746 Log(0, "Unknown format [%c]!\n", *format);
1747 abort();
1748 }
1749
1750 if (likely(s)) {
1751 r = Conn_enqueue_wait(C, s, len);
1752 if (unlikely(r == -1))
1753 return - 1;
1754 format++;
1755 }
1756 }
1757
1758 return 0;
1759 }
1760
1761 /*
1762 * Eat @bytes from head of input buffer
1763 */
1764 void Conn_eat(struct Conn *C, const unsigned int bytes)
1765 {
1766 /* advance head */
1767 C->ibuf_head += bytes;
1768 if (C->ibuf_head >= C->ibuf_tail) {
1769 C->ibuf_head = 0;
1770 C->ibuf_tail = 0;
1771 }
1772
1773 Log(10, "%p %s(%u) head=%u tail=%u qlen=%u\n",
1774 C, bytes, C->ibuf_head, C->ibuf_tail,
1775 Conn_qlen(C));
1776 }
1777
1778 /*
1779 * Eat all input buffer
1780 */
1781 void Conn_eatall(struct Conn *C)
1782 {
1783 C->ibuf_head = 0;
1784 C->ibuf_tail = 0;
1785 }
1786
1787 __hot static void Conn_free_intern(struct Conn *C)
1788 {
1789 struct Conn *p, *prev;
1790
1791 if (unlikely(Conn_debug_level > 9)) {
1792 Log(0, "%p %s Cleaning-up id %llu fd=%d in state %s [%s]...\n",
1793 C, __func__, C->id, C->fd,
1794 Conn_state(C), Conn_errno(C));
1795 }
1796
1797 if (C->error_state != CONN_ERROR_USERREQ)
1798 Conn_error_raise(C, 0);
1799
1800 if ((C->state == CONN_STATE_OPEN)
1801 || (C->state == CONN_STATE_LISTEN)
1802 || (C->state == CONN_STATE_ERROR)) {
1803 if (C->cbs.close)
1804 C->cbs.close(C);
1805 }
1806
1807 if (likely(C->fd > -1)) {
1808 Log(10, "%p Closing fd %d\n", C, C->fd);
1809 close(C->fd);
1810 C->fd = -1;
1811 }
1812
1813 if (unlikely(C->type == CONN_TYPE_MASTER))
1814 Conn_wpool_put(C->wp);
1815
1816 /* Reset tsend, else we enter in a timeout error loop */
1817 C->tsend.tv_sec = 0;
1818 C->tsend.tv_usec = 0;
1819
1820 /* Reset the connection attempt time */
1821 C->conn_syn.tv_sec = 0;
1822 C->conn_syn.tv_usec = 0;
1823
1824 /* Misc */
1825 C->error_state = 0;
1826 C->revents = 0;
1827
1828 if (unlikely(C->auto_reconnect == 1)) {
1829 C->tryat = Conn_now.tv_sec + C->delay;
1830 C->state = CONN_STATE_CONNECT_0;
1831
1832 C->ibuf_head = 0;
1833 C->ibuf_tail = 0;
1834
1835 C->obuf_head = 0;
1836 C->obuf_tail = 0;
1837
1838 Conn_pending++;
1839 } else {
1840 C->is_freed = 1;
1841 C->type = CONN_TYPE_UNK;
1842 C->state = CONN_STATE_FREE;
1843
1844 /* Decrement the number of busy connections */
1845 Conn_no--;
1846 Conn_work_to_do--;
1847
1848 /* Remove from masters list */
1849 if (unlikely(C->type == CONN_TYPE_MASTER)) {
1850 Log(0, "%p ### Remove from Conn_masters\n", C);
1851 prev = NULL;
1852 p = Conn_masters.head;
1853 while (p) {
1854 if (p != C) {
1855 prev = p;
1856 p = p -> next;
1857 continue;
1858 }
1859
1860 if (prev == NULL)
1861 Conn_masters.head = p->next;
1862 else
1863 prev->next = p->next;
1864
1865 if (Conn_masters.tail == C)
1866 Conn_masters.tail = prev;
1867 break;
1868 }
1869
1870 C->next = NULL;
1871 }
1872
1873 /* Add it to free list of the worker pool */
1874 if (likely(C->ww)) {
1875 struct Conn_wpool_worker *ww = C->ww;
1876
1877 //Log(0, "%p: ww->free before: %p/%p\n",
1878 // C, ww->free_head, ww->free_tail);
1879 C->next = NULL;
1880 C->ww = NULL;
1881 if (unlikely(ww->free_head == NULL))
1882 ww->free_head = C;
1883 else
1884 ww->free_tail->next = C;
1885 ww->free_tail = C;
1886 //Log(0, "%p: ww->free after: %p/%p ww->free->next=%p\n",
1887 // C, ww->free_head, ww->free_tail, ww->free_head->next);
1888 //if ((ww->free_head == ww->free_tail) && (ww->free_head->next != NULL)) {
1889 // Log(0, "### List is corrupted!\n");
1890 // abort();
1891 //}
1892 ww->free_count++;
1893 }
1894 }
1895 }
1896
1897 /*
1898 * If we have data, set the flag to do the closing after send.
1899 */
1900 __hot void Conn_close(struct Conn *C)
13 1901 { {
14 if (Conn_inited == 1)
15 return 0;
1902 Log(10, "%p %s Mark id %llu for closing (head=%u tail=%u)\n",
1903 C, __func__, C->id, C->obuf_head, C->obuf_tail);
1904
1905 if (C->obuf_head == C->obuf_tail) {
1906 Log(15, "%p %s Nothing to send, call free_intern\n", C, __func__);
1907 C->error_state = CONN_ERROR_USERREQ;
1908 Conn_free_intern(C);
1909 } else {
1910 C->shutdown_after_send = 1;
1911 Log(9, "%p %s Set SHUTDOWN_AFTER_SEND;"
1912 " We have data in out buffer; kick sending.\n", C, __func__);
1913 if (likely(C->cbs.send))
1914 C->cbs.send(C);
1915 }
1916 }
1917
1918 /*
1919 * Instructs Conn to stop
1920 */
1921 void Conn_stop(void)
1922 {
1923 Conn_must_stop = 1;
1924 }
1925
1926 /*
1927 * Set some internal parameters
1928 */
1929 void Conn_set(struct Conn *C, const unsigned int var, const int val)
1930 {
1931 int fd;
1932
1933 fd = Conn_get_fd(C);
1934
1935 switch (var) {
1936 case CONN_PARA_AUTO_RECONNECT:
1937 C->auto_reconnect = (val == 0) ? 0 : 1;
1938 break;
1939 case CONN_PARA_RECONNECT_DELAY:
1940 C->delay = val;
1941 break;
1942 case CONN_PARA_IDLE_TIME:
1943 C->idle = val;
1944 break;
1945 case CONN_PARA_READ_TIMEOUT:
1946 C->read_timeout = val;
1947 break;
1948 case CONN_PARA_CONN_TIMEOUT:
1949 C->conn_timeout = val;
1950 break;
1951 case CONN_PARA_TRIGGER:
1952 C->trigger = val;
1953 C->last_trigger = 0;
1954 break;
1955 case CONN_PARA_IBUF:
1956 setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &val, sizeof(val));
1957 break;
1958 case CONN_PARA_OBUF:
1959 setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &val, sizeof(val));
1960 break;
1961 }
1962 }
1963
1964 /*
1965 * Adds an fd to poll system
1966 */
1967 static int Conn_add_obj(int epoll_fd, struct Conn *C)
1968 {
1969 int ret;
1970 struct epoll_event ev;
1971
1972 memset(&ev, 0, sizeof(struct epoll_event));
1973 ev.data.ptr = C;
1974 ev.events = EPOLLIN | EPOLLRDHUP | EPOLLOUT | EPOLLET;
1975 ret = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, C->fd, &ev);
1976 if (ret == -1) {
1977 C->xerrno = errno;
1978 snprintf(Conn_error, sizeof(Conn_error),
1979 strerror(C->xerrno));
1980 return C->xerrno;
1981 }
1982
1983 return 0;
1984 }
1985
1986 /*
1987 * Dispatch events to a callback
1988 * Returns: -1 on error, 0 nothing to do, n (>0) if some work was done
1989 * timeout is in miliseconds.
1990 */
1991 __hot static int Conn_dispatch_events(int epoll_fd, struct epoll_event *e,
1992 const unsigned short e_size, const int timeout,
1993 void (*cb)(struct Conn *C, unsigned int revents))
1994 {
1995 int i, events;
1996 struct Conn *C;
1997
1998 Log(10, "%s timeout2=%ums...\n", __func__, timeout);
1999 while (1) {
2000 events = epoll_wait(epoll_fd, e, e_size, timeout);
2001 if (unlikely((events == -1) && (errno == EINTR)))
2002 continue;
2003 break;
2004 };
2005
2006 if (unlikely(events < 0)) {
2007 Log(1, "%s e_size=%d [%s]\n",
2008 __func__, e_size, strerror(errno));
2009 snprintf(Conn_error, sizeof(Conn_error), "epoll error (%d/%d) (%s)",
2010 events, errno, strerror(errno));
2011 return -1;
2012 }
2013
2014 /* TODO: this must be protected by a lock or force per thread */
2015 /* Or just call gettimeofday when needed */
2016 gettimeofday(&Conn_now, NULL);
2017
2018 if (unlikely(Conn_debug_level > 8)) {
2019 Log(0, "Processing %d event(s)...\n", events);
2020 for (i = 0; i < events; i++) {
2021 C = e[i].data.ptr;
2022 Log(0, "%p ### ev %d %x\n", C, i, e[i].events);
2023 }
2024 }
2025 for (i = 0; i < events; i++) {
2026 C = e[i].data.ptr;
2027 cb(C, e[i].events);
2028 }
2029
2030 return events;
2031 }
2032
2033 /*
2034 * Grow Conn structures (cells)
2035 * Caller must have x->lock taken.
2036 */
2037 __cold static int pool_grow(struct Conn_pool *x, const unsigned int increment)
2038 {
2039 unsigned int i;
2040 struct Conn *p, *prev;
2041
2042 Log(1, "%s Try to grow pool from %d to %d.\n",
2043 __func__, x->allocated, x->allocated + increment);
2044
2045 p = (struct Conn *) malloc(increment * sizeof(struct Conn));
2046 if (unlikely(p == NULL))
2047 return -1;
2048
2049 i = x->next_block;
2050 x->blocks[i] = p;
2051 x->next_block++;
2052
2053 /* Add them to free pool */
2054 prev = NULL;
2055 for (i = 0; i < increment; i++) {
2056 //Log(1, "%s: ### Allocated %p.\n", __func__, &p[i]);
2057
2058 /* We are forced to do some inits here */
2059 p[i].obuf_size = 0;
2060 p[i].ibuf_size = 0;
2061 p[i].obuf = NULL;
2062 p[i].ibuf = NULL;
2063
2064 if (likely(prev))
2065 prev->next = &p[i];
2066
2067 prev = &p[i];
2068 }
2069 /* Now, 'prev' contain last element; we will reuse it. */
2070 prev->next = NULL;
2071
2072 if (likely(x->head == NULL))
2073 x->head = &p[0];
2074 else
2075 x->tail->next = &p[0];
2076 x->tail = prev;
2077
2078 x->allocated += increment;
2079
2080 return 0;
2081 }
2082
2083 /*
2084 * Allocs a Conn structure
2085 */
2086 __hot struct Conn *Conn_alloc(void)
2087 {
2088 struct Conn *C;
2089 unsigned int growok;
2090 void *p;
2091
2092 Log(10, "%s Conn_no=%d Conn_max=%d\n",
2093 __func__, Conn_no, Conn_max);
2094
2095 if (unlikely((Conn_max > 0) && (Conn_no >= Conn_max))) {
2096 snprintf(Conn_error, sizeof(Conn_error),
2097 "Limit reached! Consider a raise of max connection number or put 0 for no limit.");
2098 return NULL;
2099 }
2100
2101 my_pthread_spin_lock(&Conn_free.lock);
2102 if (unlikely(Conn_free.head == NULL)) {
2103 growok = pool_grow(&Conn_free, CONN_BULK_ALLOC);
2104 if (unlikely(growok != 0)) {
2105 snprintf(Conn_error, sizeof(Conn_error),
2106 "Cannot grow anymore. Probably memory shortage.");
2107 return NULL;
2108 }
2109 }
2110
2111 /* Steal from free list */
2112 C = Conn_free.head;
2113 Conn_free.head = C->next;
2114 C->next = NULL;
2115
2116 my_pthread_spin_unlock(&Conn_free.lock);
2117
2118 if (unlikely(Conn_no > Conn_max_reached))
2119 Conn_max_reached = Conn_no;
2120
2121 C->type = CONN_TYPE_UNK;
2122 C->state = CONN_STATE_EMPTY;
2123
2124 if (unlikely(C->ibuf_size < Conn_default_ibuf)) {
2125 p = realloc(C->ibuf, Conn_default_ibuf);
2126 if (unlikely(p == NULL)) {
2127 snprintf(Conn_error, sizeof(Conn_error),
2128 "Memory allocation error2!");
2129 return NULL;
2130 }
2131 Conn_mem_buffers_in += Conn_default_ibuf - C->ibuf_size;
2132 C->ibuf = p;
2133 C->ibuf_size = Conn_default_ibuf;
2134 }
2135 C->ibuf_head = 0;
2136 C->ibuf_tail = 0;
2137
2138 if (unlikely(C->obuf_size < Conn_default_obuf)) {
2139 p = realloc(C->obuf, Conn_default_obuf);
2140 if (unlikely(p == NULL)) {
2141 snprintf(Conn_error, sizeof(Conn_error),
2142 "Memory allocation error3!");
2143 return NULL;
2144 }
2145 Conn_mem_buffers_out += Conn_default_obuf - C->obuf_size;
2146 C->obuf = p;
2147 C->obuf_size = Conn_default_obuf;
2148 }
2149 C->obuf_head = 0;
2150 C->obuf_tail = 0;
2151
2152 C->trecv = Conn_now;
2153
2154 C->bi = 0;
2155 C->bo = 0;
2156 C->private = NULL;
2157
2158 /* Reset syn time */
2159 C->conn_syn.tv_sec = 0;
2160 C->conn_syn.tv_usec = 0;
2161
2162 /* flags */
2163 C->auto_reconnect = 0;
2164 C->close_after_send = 0;
2165 C->shutdown_after_send = 0;
2166 C->local_dirty = 1;
2167 C->remote_dirty = 1;
2168 C->accept_pending = 1;
2169 C->is_freed = 0;
2170
2171 /* bandwidth */
2172 C->band_width = 0;
2173 C->band_factor = 0;
2174 C->band_tokens = 0;
2175 C->band_lasttime = Conn_now;
2176
2177 C->fd = -1;
2178 C->revents = 0;
2179
2180 C->start = Conn_now.tv_sec;
2181
2182 C->id = Conn_id++;
2183
2184 /* TODO: really? Don't we borrow them from master listent conn?! */
2185 C->cbs = Conn_default_cbs;
2186
2187 Conn_no++;
2188 /* Conn_work_to_do will not be incremented here, only in commit! */
2189
2190 Log(10, "%p Allocated id %llu. Now Conn_no=%d.\n",
2191 C, C->id, Conn_no);
2192
2193 return C;
2194 }
2195
2196 /*
2197 * Accepting a connection
2198 */
2199 __hot static void Conn_accept(struct Conn *C)
2200 {
2201 int fd, err;
2202 struct sockaddr *pca;
2203 struct sockaddr_in ca4;
2204 struct sockaddr_in6 ca6;
2205 socklen_t cax_len;
2206 struct Conn *X;
2207
2208 if (unlikely(Conn_debug_level > 9)) {
2209 Log(0, "Accepting a connection via %s/%d, type %s, domain %s"
2210 ", protocol %s.\n",
2211 C->bind_addr, C->bind_port, Conn_type(C),
2212 Conn_domain(C), Conn_get_socket_protocol(C));
2213 }
2214
2215 switch(C->sock_domain) {
2216 case PF_INET:
2217 pca = (struct sockaddr *) &ca4;
2218 cax_len = sizeof(ca4);
2219 break;
2220
2221 case PF_INET6:
2222 pca = (struct sockaddr *) &ca6;
2223 cax_len = sizeof(ca6);
2224 break;
2225
2226 default:
2227 snprintf(Conn_error, sizeof(Conn_error),
2228 "Cannot deal with domain %d.",
2229 C->sock_domain);
2230 Conn_error_raise(C, EAFNOSUPPORT);
2231 return;
2232 }
2233
2234 again:
2235 fd = accept4(C->fd, pca, &cax_len, SOCK_NONBLOCK | SOCK_CLOEXEC);
2236 if (fd == -1) {
2237 if (unlikely(errno == EINTR))
2238 goto again;
2239
2240 if (unlikely(errno == EAGAIN)) {
2241 Log(10, "accept returned EAGAIN. Return\n");
2242 C->revents &= ~EPOLLIN;
2243 return;
2244 }
2245
2246 /* TODO: ratelimit */
2247 Log(2, "WARN: Cannot accept on fd %d [%s].\n",
2248 C->fd, strerror(errno));
2249 /*
2250 * We must not raise an error here because we will close the
2251 * master socket!
2252 * TODO: We should signal it as a warning.
2253 */
2254 /* Conn_error_raise(C, errno); */
2255 return;
2256 }
2257
2258 X = Conn_alloc();
2259 if (unlikely(!X)) {
2260 Conn_error_raise(C, ENOMEM);
2261 close(fd);
2262 return;
2263 }
16 2264
17 Conn_max = max;
2265 X->cbs = C->cbs;
2266 X->fd = fd;
2267 X->type = CONN_TYPE_P2P;
2268 X->state = CONN_STATE_OPEN;
2269 X->time_open = Conn_now;
2270 X->via = C->id;
18 2271
19 Conn_no = 0;
20 Conn_work_to_do = 0;
21 Conn_total = 0;
22 Conn_max_reached = 0;
23 gettimeofday(&Conn_now, NULL);
24 Conn_start = Conn_now.tv_sec;
25 Conn_accept_is_allowed = 1;
26 Conn_accept_is_allowed_last = 1;
27 Conn_allocated = 0;
2272 Conn_set_socket_domain(X, C->sock_domain);
2273 Conn_set_socket_type(X, C->sock_type);
2274 Conn_set_socket_protocol(X, C->sock_protocol);
28 2275
29 snprintf(Conn_error, sizeof(Conn_error), "%s", "");
2276 X->local_dirty = 1;
2277 X->remote_dirty = 1;
2278 X->accept_pending = 1;
30 2279
31 /*
32 Conn_queue_init(&Conn_queue_free);
33 */
2280 Conn_nodelay(X);
34 2281
35 Conn_epoll_fd = epoll_create(32);
36 if (Conn_epoll_fd == -1) {
37 Log(0, "Cannot create epoll fd (%s)\n", strerror(errno));
38 return -1;
2282 err = Conn_wpool_enqueue(C->wp, X);
2283 if (unlikely(err != 0)) {
2284 /* TODO: add a specific callback for enqueue errors? */
2285 Conn_error_raise(C, CONN_ERROR_INTERNAL);
2286 Conn_free_intern(X);
2287 return;
39 2288 } }
40 2289
41 Conn_inited = 1;
2290 Conn_work_to_do++;
42 2291
43 return 0;
2292 Conn_total++;
2293
2294 /* We must call accept till we get EAGAIN */
2295 goto again;
44 2296 } }
45 2297
46 2298 /* /*
47 * Shutdown Conn
2299 * Callback that is called for every connection
48 2300 */ */
49 int Conn_shutdown(void)
2301 __hot static void Conn_poll_cb(struct Conn *C, unsigned int revents)
50 2302 { {
51 unsigned int slot;
2303 char poll_status1[16], poll_status2[16];
52 2304
53 Conn_inited = 0;
2305 if (unlikely(Conn_debug_level > 5)) {
2306 Conn_poll_status(C->revents, poll_status1);
2307 Conn_poll_status(revents, poll_status2);
2308 Log(0, "%p %s id %llu, revents=prev=%s/new=%s\n",
2309 C, __func__, C->id, poll_status1, poll_status2);
54 2310
55 close(Conn_epoll_fd);
2311 Log(12, "%s\n", Conn_status_slot(C));
2312 }
56 2313
57 /* Free all buffers */
58 Log(5, "Freeing %u slots...\n", Conn_allocated);
59 for (slot = 0; slot < Conn_allocated - 1; slot++) {
60 if (Conns[slot].ibuf)
61 free(Conns[slot].ibuf);
62 if (Conns[slot].obuf)
63 free(Conns[slot].obuf);
2314 C->revents |= revents;
64 2315
65 if (Conns[slot].fd != -1) {
66 Log(6, "Closing slot %u, fd %d...\n",
67 slot, Conns[slot].fd);
68 close(Conns[slot].fd);
2316 /* We may receive several events on the same conn */
2317 if (unlikely(C->state == CONN_STATE_FREE))
2318 return;
2319
2320 if (unlikely(C->accept_pending == 1)) {
2321 /* Add it to active connections - only if is a worker */
2322 if (likely(C->ww)) {
2323 #if 0
2324 TODO: seems we have a problem with the list management. Try to isolate it.
2325 Log(0, "%p ### conns=%p/%p\n", C, C->ww->conns_head,
2326 C->ww->conns_tail);
2327 if (C->ww->conns_head == NULL)
2328 C->ww->conns_head = C;
2329 else
2330 C->ww->conns_tail->next = C;
2331 C->ww->conns_tail = C;
2332 C->next = NULL;
2333 Log(0, "%p: ### after adding C. conns=%p/%p\n",
2334 C->ww->conns_head, C->ww->conns_tail);
2335 #endif
2336
2337 if (C->cbs.accept) {
2338 Log(12, "%p Accept cb was not called, call now\n", C);
2339 C->cbs.accept(C);
2340 }
2341 C->accept_pending = 0;
69 2342 } }
70 2343 } }
71 2344
72 free(Conns);
2345 if (unlikely(C->revents & EPOLLERR)) {
2346 Log(0, "%p EPOLLERR!\n", C);
2347 C->error_state = CONN_ERROR_POLL;
2348 C->xerrno = 0; /* TODO: unknown error? */
2349 Conn_free_intern(C);
2350 /* TODO: CONN_ERROR_POLL is correct here? */
2351 return;
2352 }
73 2353
74 return 0;
75 }
2354 if (unlikely(C->revents & EPOLLHUP)) {
2355 Log(9, "%p EPOLLHUP!\n", C);
2356 C->error_state = CONN_ERROR_HANGUP;
2357 Conn_free_intern(C);
2358 return;
2359 }
76 2360
77 int Conn_enqueue(struct Conn *C, void *buf, const size_t count)
78 {
79 unsigned int r, slot;
80 char *dump;
2361 /* First, test we have a new connection */
2362 if (C->revents & EPOLLOUT) {
2363 if (C->state == CONN_STATE_CONNECT_b) {
2364 Log(9, "%p We just established a connection.\n", C);
81 2365
82 if (C == NULL) {
83 Log(0, "ERROR: Somebody try to enqueue something to a NULL conn.\n");
84 return -1;
2366 C->state = CONN_STATE_OPEN;
2367 C->local_dirty = 1;
2368 C->time_open = Conn_now;
2369
2370 if (likely(C->cbs.connected))
2371 C->cbs.connected(C);
2372 }
2373 }
2374 //if (Conn_ignore(C))
2375 // return;
2376
2377 /* Second, test for hangup or input */
2378 if (likely(C->revents & EPOLLIN)) {
2379 Log(9, "%p We have input...\n", C);
2380 if (unlikely(C->type == CONN_TYPE_MASTER)) {
2381 Conn_accept(C);
2382 } else {
2383 if (likely(C->cbs.recv))
2384 C->cbs.recv(C);
2385 }
85 2386 } }
2387 //if (Conn_ignore(C))
2388 // return;
86 2389
87 if (Conn_level >= 10) {
88 dump = Conn_dump(buf, count);
89 Log(0, "\tTry to enqueue %d bytes to id=%llu [%s]...\n",
90 count, C->id, dump);
91 free(dump);
2390 /* RDHUP may come with POLLIN, so it must be called after */
2391 if (unlikely(C->revents & EPOLLRDHUP)) {
2392 Log(9, "%p EPOLLRDHUP!\n", C);
2393 C->revents &= ~EPOLLIN;
92 2394 } }
93 2395
94 if (C->obuf_size - C->obuf_tail < count) {
95 r = Conn_try_expand_buf(C, 0, count);
96 if (r != 0)
97 return -1;
2396 if (likely(C->revents & EPOLLOUT)) {
2397 Log(9, "%p We can send data...\n", C);
2398 if (likely(C->state == CONN_STATE_OPEN)) {
2399 if (likely(C->cbs.send))
2400 C->cbs.send(C);
2401 }
98 2402 } }
2403 //if (Conn_ignore(C))
2404 // return;
2405 }
99 2406
100 memcpy(C->obuf + C->obuf_tail, buf, count);
101 C->obuf_tail += count;
102 2407
103 Conns->events |= EPOLLOUT;
104 Conn_change_obj(C);
2408 /* ########### wpool ########### */
2409 /* TODO: Seems we have two wpool sections! */
2410 /*
2411 * Function that is executed by a worker.
2412 * It accepts connections, receives and sends commands.
2413 */
2414 void *Conn_wpool_worker_func(void *arg)
2415 {
2416 struct Conn_wpool_worker *w = arg;
2417 char tmp[32];
2418
2419 snprintf(tmp, sizeof(tmp), "worker %hu", w->id);
2420 Conn_log_set_info(tmp);
105 2421
106 return count;
2422 Log(5, "Started work...\n");
2423
2424 while (1) {
2425 Conn_dispatch_events(w->epoll_fd, w->events,
2426 CONN_EVENTS_SLOTS, 60000, Conn_poll_cb);
2427
2428 /* Send back to master the free connections */
2429 if (unlikely(w->free_count >= CONN_GIVE_BACK_LIMIT)) {
2430 if ((w->free_head == w->free_tail) & (w->free_head->next != NULL)) {
2431 Log(0, "### List is wrong! TODO\n");
2432 abort();
2433 }
2434
2435 my_pthread_spin_lock(&Conn_free.lock);
2436 if (Conn_free.head == NULL)
2437 Conn_free.head = w->free_head;
2438 else
2439 Conn_free.tail->next = w->free_head;
2440 Conn_free.tail = w->free_tail;
2441 my_pthread_spin_unlock(&Conn_free.lock);
2442
2443 w->free_head = NULL;
2444 w->free_count = 0;
2445 }
2446 }
2447
2448 return NULL;
107 2449 } }
108 2450
109 static void Conn_free_intern(struct Conn *C)
2451 /*
2452 * Destroy a worker
2453 */
2454 void Conn_wpool_stop_worker(struct Conn_wpool_worker *w)
110 2455 { {
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));
2456 int r;
114 2457
115 if (C->error_state != CONN_ERROR_USERREQ)
116 Conn_error_raise(slot, 0);
2458 if (w->inited == 0)
2459 return;
117 2460
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);
123 else if (Conn_close_cb)
124 Conn_close_cb(C);
2461 close(w->epoll_fd);
2462
2463 close(w->pipe[0]);
2464 close(w->pipe[1]);
2465
2466 r = pthread_cancel(w->tid);
2467 if (r != 0) {
2468 Log(0, "Cannot cancel worker %p.\n", w);
125 2469 } }
2470 }
126 2471
127 if (C->fd > -1) {
128 close(C->fd);
129 C->fd = -1;
2472 /*
2473 * Start a worker
2474 */
2475 int Conn_wpool_start_worker(struct Conn_wpool_worker *w)
2476 {
2477 int r, cpus;
2478 struct epoll_event ev;
2479 cpu_set_t cpuset;
2480 pthread_attr_t attr;
2481
2482 Log(10, "Creating worker %p (%hu)...\n", w, w->id);
2483
2484 w->conns_head = NULL;
2485 w->free_head = NULL;
2486 w->free_tail = NULL; /* TODO: not needed */
2487 w->free_count = 0;
2488 w->mem_structs = 0; /* TODO: really used? */
2489
2490 w->epoll_fd = epoll_create1(EPOLL_CLOEXEC);
2491 if (w->epoll_fd == -1) {
2492 Log(0, "Cannot create worker epoll (%s).\n", strerror(errno));
2493 goto out;
130 2494 } }
131 2495
132 /* Reset tsend, else we enter in a timeout error loop */
133 C->tsend.tv_sec = 0;
134 C->tsend.tv_usec = 0;
2496 r = socketpair(AF_LOCAL, SOCK_STREAM, 0, w->pipe);
2497 if (r != 0) {
2498 Log(0, "Cannot call socketpair (%s)\n", strerror(errno));
2499 goto close_epoll;
2500 }
135 2501
136 /* Reset the connection attempt time */
137 C->conn_syn.tv_sec = 0;
138 C->conn_syn.tv_usec = 0;
2502 /* Register our end of the pipe to receive signaling from 'accept' thread */
2503 memset(&ev, 0, sizeof(struct epoll_event));
2504 ev.events = EPOLLIN;
2505 ev.data.u32 = 1; /* TODO: Found a better id */
2506 r = epoll_ctl(w->epoll_fd, EPOLL_CTL_ADD, w->pipe[1], &ev);
139 2507
140 /* Misc */
141 C->error_state = 0;
2508 r = pthread_attr_init(&attr);
2509 if (r != 0) {
2510 Log(0, "Cannot init attributes.\n");
2511 goto close_pipe;
2512 }
142 2513
143 if (C->flags & CONN_FLAGS_AUTO_RECONNECT) {
144 C->tryat = Conn_now.tv_sec + C->delay;
145 C->state = CONN_STATE_CONNECT_0;
2514 r = pthread_attr_setstacksize(&attr, 1 * 1024 * 1024);
2515 if (r != 0) {
2516 Log(0, "Cannot set stack size!\n");
2517 goto destroy_attr;
2518 }
146 2519
147 C->ibuf_head = 0;
148 C->ibuf_tail = 0;
2520 cpus = sysconf(_SC_NPROCESSORS_ONLN);
2521 Log(1, "%u cpus found.\n", cpus);
2522 CPU_ZERO(&cpuset);
2523 CPU_SET(w->id % cpus, &cpuset);
2524 r = pthread_attr_setaffinity_np(&attr, sizeof(cpu_set_t), &cpuset);
2525 if (r != 0) {
2526 Log(0, "Cannot set affinity\n");
2527 } else {
2528 Log(1, "Affinity for worker %hu: %u\n", w->id, w->id % cpus);
2529 }
149 2530
150 C->obuf_head = 0;
151 C->obuf_tail = 0;
2531 r = pthread_create(&w->tid, &attr, Conn_wpool_worker_func, w);
2532 if (r != 0) {
2533 Log(0, "Could not start thread (%s)\n", strerror(errno));
2534 goto destroy_attr;
2535 }
2536 w->inited = 1;
152 2537
153 Conn_pending++;
154 } else {
155 C->type = CONN_TYPE_UNK;
156 C->state = CONN_STATE_FREE;
2538 /* Everything is OK */
2539 pthread_attr_destroy(&attr);
157 2540
158 /* Allow connections */
159 Conn_accept_is_allowed = 1;
2541 Log(10, "Started worker %p (%hu), epoll=%d pipe=%d/%d\n",
2542 w, w->id, w->epoll_fd, w->pipe[0], w->pipe[1]);
2543 return 0;
160 2544
161 /* Decrement the number of busy connections */
162 Conn_no--;
163 Conn_work_to_do--;
164 }
2545 close_pipe:
2546 close(w->pipe[0]);
2547 close(w->pipe[1]);
2548
2549 destroy_attr:
2550 pthread_attr_destroy(&attr);
2551
2552 close_epoll:
2553 close(w->epoll_fd);
2554
2555 out:
2556 return -1;
165 2557 } }
166 2558
167 2559 /* /*
168 * Grow Conn structures (cells)
2560 * Creates a workers pool
169 2561 */ */
170 static int Conn_grow(void)
2562 struct Conn_wpool *Conn_wpool_create(const unsigned short workers)
171 2563 { {
172 unsigned int alloc, increment = 128, i;
173 struct Conn *p, *set;
2564 struct Conn_wpool *ret;
2565 int i, r;
2566 struct Conn_wpool_worker *w;
2567
2568 ret = malloc(sizeof(struct Conn_wpool));
2569 if (ret == NULL) {
2570 Log(0, "Cannot alloc memory for wpool!\n");
2571 goto out;
2572 }
2573
2574 /* TODO: switch to malloc */
2575 ret->ws = malloc(workers * sizeof(struct Conn_wpool_worker));
2576 if (ret->ws == NULL) {
2577 Log(0, "Cannot alloc memory for workers!\n");
2578 goto free_ret;
2579 }
174 2580
175 Log(10, "%s() Try to grow cells from %d to %d.\n",
176 __func__,
177 Conn_allocated, Conn_allocated + 128);
2581 ret->epoll_fd = epoll_create1(EPOLL_CLOEXEC);
2582 if (ret->epoll_fd == -1) {
2583 Log(0, "Cannot create epoll fd (%s)\n", strerror(errno));
2584 goto free_ws;
2585 }
2586
2587 /* Start threads */
2588 for (i = 0; i < workers; i++) {
2589 w = &ret->ws[i];
2590 w->id = i;
2591 r = Conn_wpool_start_worker(w);
2592 if (r != 0)
2593 goto destroy_workers;
2594 }
178 2595
179 alloc = Conn_allocated + increment;
2596 ret->workers = workers;
2597 ret->next = 0;
2598 ret->refs = 0;
2599 Log(10, "%s pool created with success.\n", __func__);
2600 return ret;
180 2601
181 p = (struct Conn *) realloc(Conns, alloc * sizeof(struct Conn));
182 if (p == NULL)
183 return -1;
2602 destroy_workers:
2603 for (i = 0; i < workers; i++) {
2604 w = &ret->ws[i];
2605 Conn_wpool_stop_worker(w);
2606 }
2607 close(ret->epoll_fd);
184 2608
185 Conn_mem_structs += increment * sizeof(struct Conn);
2609 free_ws:
2610 free(ret->ws);
186 2611
187 set = p + Conn_allocated;
188 memset(set, 0, increment * sizeof(struct Conn));
189 /* Some inits */
190 for (i = 0; i < 128; i++)
191 set[i].fd = -1;
2612 free_ret:
2613 free(ret);
192 2614
193 Conns = p;
194 Conn_allocated = alloc;
2615 out:
2616 Log(5, "%s Failed to create wpool.\n", __func__);
2617 return NULL;
2618 }
2619
2620 /*
2621 * Destroys a worker pool
2622 */
2623 int Conn_wpool_destroy(struct Conn_wpool *wp)
2624 {
2625 int i;
2626 struct Conn_wpool_worker *w;
2627
2628 for (i = 0; i < wp->workers; i++) {
2629 w = &wp->ws[i];
2630 Conn_wpool_stop_worker(w);
2631 }
2632
2633 close(wp->epoll_fd);
2634
2635 free(wp->ws);
2636
2637 free(wp);
195 2638
196 2639 return 0; return 0;
197 2640 } }
198 2641
199 2642 /* /*
200 * Allocs a Conn structure
2643 * Enqueues a connection to a workers pool
201 2644 */ */
202 struct Conn *Conn_alloc(void)
2645 int Conn_wpool_enqueue(struct Conn_wpool *wp, struct Conn *C)
203 2646 { {
204 unsigned int growok;
205 void *p;
206 unsigned int slot;
2647 short i;
2648 int r;
207 2649
208 Log(10, "%s() Conn_no=%d Conn_max=%d\n",
209 __func__,
210 Conn_no, Conn_max);
2650 /* Round robin algo */
2651 i = wp->next;
2652 wp->next = (wp->next + 1) % wp->workers;
211 2653
212 if ((Conn_max > 0) && (Conn_no >= Conn_max)) {
213 snprintf(Conn_error, sizeof(Conn_error),
214 "Limit reached! Consider a raise of max connection number or put 0 for no limit.");
215 return NULL;
216 }
2654 /* We need it later to add C to active conns */
2655 C->ww = &wp->ws[i];
217 2656
218 if (Conn_allocated == Conn_no) {
219 growok = Conn_grow();
220 if (growok != 0) {
221 snprintf(Conn_error, sizeof(Conn_error),
222 "Cannot grow anymore. Probably memory shortage.");
223 return NULL;
224 }
2657 Log(10, "%p %s Enqueue C to worker %u\n", C, __func__, C->ww->id);
2658
2659 r = Conn_add_obj(C->ww->epoll_fd, C);
2660 if (unlikely(r != 0)) {
2661 Log(0, "Cannot enqueue fd %d to epoll_fd %d (%s)\n",
2662 C->fd, C->ww->epoll_fd, strerror(errno));
2663 return -1;
225 2664 } }
226 2665
227 if (Conn_no > Conn_max_reached)
228 Conn_max_reached = Conn_no;
2666 return 0;
2667 }
229 2668
230 slot = Conn_no;
231 C->slot = slot;
232 2669
233 C->type = CONN_TYPE_UNK;
234 C->state = CONN_STATE_EMPTY;
2670 /* ############## conn 2 ############# */
2671 int Conn_init(const unsigned int max)
2672 {
2673 if (Conn_inited == 1)
2674 return 0;
235 2675
236 if (C->ibuf_size < Conn_default_ibuf) {
237 p = realloc(C->ibuf, Conn_default_ibuf);
238 if (p == NULL) {
239 snprintf(Conn_error, sizeof(Conn_error),
240 "Memory allocation error2!");
241 return NULL;
242 }
243 Conn_mem_buffers_in += Conn_default_ibuf - C->ibuf_size;
244 C->ibuf = p;
245 C->ibuf_size = Conn_default_ibuf;
246 }
247 C->ibuf_head = 0;
248 C->ibuf_tail = 0;
2676 pthread_spin_init(&Log_lock, PTHREAD_PROCESS_PRIVATE);
2677 Conn_log_set_info("main");
249 2678
250 if (C->obuf_size < Conn_default_obuf) {
251 p = realloc(C->obuf, Conn_default_obuf);
252 if (p == NULL) {
253 snprintf(Conn_error, sizeof(Conn_error),
254 "Memory allocation error3!");
255 return NULL;
256 }
257 Conn_mem_buffers_out += Conn_default_obuf - C->obuf_size;
258 C->obuf = p;
259 C->obuf_size = Conn_default_obuf;
2679 /* TODO: masters does not need a full pool implementation */
2680 pool_init(&Conn_masters);
2681 pool_init(&Conn_free);
2682
2683 Conn_max = max;
2684
2685 Conn_no = 0;
2686 Conn_work_to_do = 0;
2687 Conn_total = 0;
2688 Conn_max_reached = 0;
2689 gettimeofday(&Conn_now, NULL);
2690 Conn_start = Conn_now.tv_sec;
2691 Conn_allocated = 0;
2692
2693 snprintf(Conn_error, sizeof(Conn_error), "%s", "");
2694
2695 Conn_epoll_fd = epoll_create(32);
2696 if (Conn_epoll_fd == -1) {
2697 Log(0, "Cannot create epoll fd (%s)\n", strerror(errno));
2698 return -1;
260 2699 } }
261 C->obuf_head = 0;
262 C->obuf_tail = 0;
263 2700
264 C->trecv = Conn_now;
2701 Conn_inited = 1;
265 2702
266 C->bi = 0;
267 C->bo = 0;
268 C->private = NULL;
2703 /* Log some info about this system */
2704 Conn_sys();
269 2705
270 /* Reset syn time */
271 C->conn_syn.tv_sec = 0;
272 C->conn_syn.tv_usec = 0;
2706 return 0;
2707 }
273 2708
274 /* bandwidth */
275 C->band_width = 0;
276 C->band_factor = 0;
277 C->band_tokens = 0;
278 C->band_lasttime = Conn_now;
2709 /*
2710 * Shutdown Conn
2711 */
2712 int Conn_shutdown(void)
2713 {
2714 Conn_inited = 0;
2715
2716 close(Conn_epoll_fd);
2717
2718 /* Free all buffers */
2719 #if 0
2720 TODO
2721 Log(5, "Freeing %u slots...\n", Conn_allocated);
2722 for (slot = 0; slot < Conn_allocated - 1; slot++) {
2723 if (Conns[slot].ibuf)
2724 free(Conns[slot].ibuf);
2725 if (Conns[slot].obuf)
2726 free(Conns[slot].obuf);
2727
2728 if (Conns[slot].fd != -1) {
2729 Log(6, "Closing slot %u, fd %d...\n",
2730 slot, Conns[slot].fd);
2731 close(Conns[slot].fd);
2732 }
2733 }
2734 #endif
2735
2736 free(Conns);
2737
2738 return 0;
2739 }
279 2740
280 C->fd = -1;
281 C->events = 0;
282 C->revents = 0;
2741 /*
2742 * Enqueues data but do not kick the sending
2743 */
2744 __hot int Conn_enqueue_wait(struct Conn *C, const void *buf, const size_t count)
2745 {
2746 unsigned int r;
2747 char *dump;
283 2748
284 C->flags = 0;
2749 if (unlikely(Conn_debug_level >= 10)) {
2750 dump = Conn_dump(buf, count);
2751 Log(0, "%p %s Try to enqueue %d bytes to id %llu [%s]...\n",
2752 C, __func__, count, C->id, dump);
2753 free(dump);
2754 }
285 2755
286 C->start = Conn_now.tv_sec;
2756 if (unlikely(C->obuf_size - C->obuf_tail < count)) {
2757 r = Conn_try_expand_buf(C, 0, count);
2758 if (unlikely(r != 0))
2759 return -1;
2760 }
287 2761
288 C->id = Conn_id++;
2762 memcpy(C->obuf + C->obuf_tail, buf, count);
2763 C->obuf_tail += count;
289 2764
290 C->cbs = Conn_default_cbs;
2765 return count;
2766 }
291 2767
292 Conn_no++;
293 /* Conn_work_to_do will not be incremented here, only in commit! */
2768 /*
2769 * Enqueues data and kick the sending
2770 */
2771 __hot int Conn_enqueue(struct Conn *C, const void *buf, const size_t count)
2772 {
2773 int ret;
294 2774
295 Log(10, "\tFound free slot=%u, id=%llu. Now Conn_no=%d\n",
296 slot, C->id, Conn_no);
2775 ret = Conn_enqueue_wait(C, buf, count);
297 2776
298 if (Conn_no == Conn_max)
299 Conn_accept_is_allowed = 0;
2777 if (likely((ret > 0) && (C->cbs.send)))
2778 C->cbs.send(C);
300 2779
301 return C;
2780 return ret;
302 2781 } }
303 2782
304 2783 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)
350 2829 } }
351 2830
352 2831 /* /*
353 * Allocates socket and bind if necesary
2832 * Allocates socket and bind if asked
354 2833 * TODO: We should return -1 or free connection and call calbacks?! * TODO: We should return -1 or free connection and call calbacks?!
355 2834 */ */
356 2835 int Conn_commit(struct Conn *C) int Conn_commit(struct Conn *C)
 
... ... int Conn_commit(struct Conn *C)
361 2840 struct sockaddr_in6 bind_sa6; struct sockaddr_in6 bind_sa6;
362 2841 int bind_sock_len = 0; int bind_sock_len = 0;
363 2842 int do_listen = 1, do_connect = 0; int do_listen = 1, do_connect = 0;
364 int first_state;
365 unsigned int slot;
2843 int first_state = -1;
2844 struct Conn_wpool *wp;
366 2845
367 slot = C->slot;
368
369 Log(10, "%s: slot=%u...\n", __func__, slot);
2846 Log(10, "%p %s\n", C, __func__);
370 2847
371 2848 /* Be optimistical and increment here, in 'free' we will decrement. */ /* Be optimistical and increment here, in 'free' we will decrement. */
372 2849 /* So, in error case, we will only decrement this thing! */ /* So, in error case, we will only decrement this thing! */
 
... ... int Conn_commit(struct Conn *C)
380 2857 do_connect = 1; do_connect = 1;
381 2858 } else { } else {
382 2859 C->type = CONN_TYPE_MASTER; C->type = CONN_TYPE_MASTER;
383 if (strlen(C->bind_addr) == 0) {
2860 if (C->bind_addr[0] == '\0') {
2861 /* Choose defaults because IP was not specified */
384 2862 switch (C->sock_domain) { switch (C->sock_domain) {
385 2863 case PF_INET: case PF_INET:
386 2864 snprintf(C->bind_addr, sizeof(C->bind_addr), snprintf(C->bind_addr, sizeof(C->bind_addr),
 
... ... int Conn_commit(struct Conn *C)
394 2872 } }
395 2873
396 2874 switch (C->sock_domain) { switch (C->sock_domain) {
397 case PF_INET:
398 /* for binding socket */
399 if (C->bind_addr[0] != '\0') {
400 memset(&bind_sa, 0, sizeof(bind_sa));
401 bind_sa.sin_family = AF_INET;
402 ret = inet_pton(AF_INET, C->bind_addr, &bind_sa.sin_addr);
403 if (ret < 0) {
404 snprintf(Conn_error, sizeof(Conn_error),
405 "inet_pton(%s) failed", C->bind_addr);
406 return -1;
407 }
408 bind_sa.sin_port = htons(C->bind_port);
409 bind_psa = (struct sockaddr *) &bind_sa;
410 bind_sock_len = sizeof(bind_sa);
411 }
412
413 if (C->sock_type == SOCK_STREAM) {
414 first_state = CONN_STATE_LISTEN;
415 } else if (C->sock_type == SOCK_DGRAM) {
416 do_listen = 0;
417 first_state = CONN_STATE_OPEN;
418 }
419 break;
420
421 case PF_INET6:
422 /* for binding socket */
423 if (C->bind_addr[0] != '\0') {
424 memset(&bind_sa6, 0, sizeof(bind_sa6));
425 bind_sa6.sin6_family = AF_INET6;
426 ret = inet_pton(AF_INET6, C->bind_addr, &bind_sa6.sin6_addr);
427 if (ret < 0) {
428 snprintf(Conn_error, sizeof(Conn_error),
2875 case PF_INET:
2876 /* for binding socket */
2877 if (C->bind_addr[0] != '\0') {
2878 memset(&bind_sa, 0, sizeof(bind_sa));
2879 bind_sa.sin_family = AF_INET;
2880 ret = inet_pton(AF_INET, C->bind_addr, &bind_sa.sin_addr);
2881 if (ret < 0) {
2882 snprintf(Conn_error, sizeof(Conn_error),
429 2883 "inet_pton(%s) failed", C->bind_addr); "inet_pton(%s) failed", C->bind_addr);
430 return -1;
431 }
432 bind_sa6.sin6_port = htons(C->bind_port);
433 bind_psa = (struct sockaddr *) &bind_sa6;
434 bind_sock_len = sizeof(bind_sa6);
2884 return -1;
435 2885 } }
2886 bind_sa.sin_port = htons(C->bind_port);
2887 bind_psa = (struct sockaddr *) &bind_sa;
2888 bind_sock_len = sizeof(bind_sa);
2889 }
436 2890
437 if (C->sock_type == SOCK_STREAM) {
438 first_state = CONN_STATE_LISTEN;
439 } else if (C->sock_type == SOCK_DGRAM) {
440 do_listen = 0;
441 first_state = CONN_STATE_OPEN;
2891 if (C->sock_type == SOCK_STREAM) {
2892 first_state = CONN_STATE_LISTEN;
2893 } else if (C->sock_type == SOCK_DGRAM) {
2894 do_listen = 0;
2895 first_state = CONN_STATE_OPEN;
2896 }
2897 break;
2898
2899 case PF_INET6:
2900 /* for binding socket */
2901 if (C->bind_addr[0] != '\0') {
2902 memset(&bind_sa6, 0, sizeof(bind_sa6));
2903 bind_sa6.sin6_family = AF_INET6;
2904 ret = inet_pton(AF_INET6, C->bind_addr, &bind_sa6.sin6_addr);
2905 if (ret < 0) {
2906 snprintf(Conn_error, sizeof(Conn_error),
2907 "inet_pton(%s) failed", C->bind_addr);
2908 return -1;
442 2909 } }
443 break;
2910 bind_sa6.sin6_port = htons(C->bind_port);
2911 bind_psa = (struct sockaddr *) &bind_sa6;
2912 bind_sock_len = sizeof(bind_sa6);
2913 }
444 2914
445 case PF_PACKET:
446 /*do_bind = 0; TODO? */
447 do_listen = 0; /*TODO:check this!*/
2915 if (C->sock_type == SOCK_STREAM) {
2916 first_state = CONN_STATE_LISTEN;
2917 } else if (C->sock_type == SOCK_DGRAM) {
2918 do_listen = 0;
448 2919 first_state = CONN_STATE_OPEN; first_state = CONN_STATE_OPEN;
449 break;
2920 }
2921 break;
450 2922
451 default:
452 snprintf(Conn_error, sizeof(Conn_error),
453 "Invalid domain [%d]!", C->sock_domain);
454 return -1;
2923 case PF_PACKET:
2924 /*do_bind = 0; TODO? */
2925 do_listen = 0; /*TODO:check this!*/
2926 first_state = CONN_STATE_OPEN;
2927 break;
2928
2929 default:
2930 snprintf(Conn_error, sizeof(Conn_error),
2931 "Invalid domain [%d]!", C->sock_domain);
2932 return -1;
455 2933 } }
456 2934
457 C->fd = socket(C->sock_domain, C->sock_type,
458 C->sock_protocol);
2935 C->fd = socket(C->sock_domain, C->sock_type, C->sock_protocol);
459 2936 if (C->fd == -1) { if (C->fd == -1) {
460 2937 snprintf(Conn_error, sizeof(Conn_error), snprintf(Conn_error, sizeof(Conn_error),
461 2938 "Cannot create socket (%s, %s, %s) [%s]", "Cannot create socket (%s, %s, %s) [%s]",
 
... ... int Conn_commit(struct Conn *C)
466 2943 } }
467 2944
468 2945 Conn_setnonblock(C->fd); Conn_setnonblock(C->fd);
2946 Conn_nodelay(C);
469 2947
470 2948 if (C->sock_domain == PF_INET6) { if (C->sock_domain == PF_INET6) {
471 2949 #ifndef IPV6_V6ONLY #ifndef IPV6_V6ONLY
 
... ... int Conn_commit(struct Conn *C)
475 2953 setsockopt(C->fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&i, sizeof(i)); setsockopt(C->fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&i, sizeof(i));
476 2954 } }
477 2955
478 if (strlen(C->bind_addr) > 0) {
2956 if (C->type == CONN_TYPE_MASTER) {
479 2957 i = 1; i = 1;
480 2958 setsockopt(C->fd, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i)); setsockopt(C->fd, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i));
481 2959
 
... ... int Conn_commit(struct Conn *C)
484 2962 snprintf(Conn_error, sizeof(Conn_error), snprintf(Conn_error, sizeof(Conn_error),
485 2963 "Cannot bind on %s/%d [%s]", "Cannot bind on %s/%d [%s]",
486 2964 C->bind_addr, C->bind_port, strerror(errno)); C->bind_addr, C->bind_port, strerror(errno));
487 goto out_free_fd;
2965 goto out_free;
488 2966 } }
2967
2968 if (Conn_masters.head == NULL)
2969 Conn_masters.head = C;
2970 else
2971 Conn_masters.tail->next = C;
2972 Conn_masters.tail = C;
489 2973 } }
490 2974
491 C->events = EPOLLIN;
492 2975 C->revents = 0; C->revents = 0;
493 2976
494 2977 if (do_listen == 1) if (do_listen == 1)
495 2978 listen(C->fd, 4096); listen(C->fd, 4096);
496 2979
497 2980 if (do_connect == 1) { if (do_connect == 1) {
498 /*TODO:replace connect_a with OPEN?! */
2981 /* TODO:replace connect_a with OPEN?! */
499 2982 first_state = CONN_STATE_CONNECT_a; first_state = CONN_STATE_CONNECT_a;
500 C->events |= EPOLLOUT;
501 2983 } }
502 2984
503 ret = Conn_add_obj(C);
2985 if (C->wp == NULL) {
2986 wp = Conn_wpool_create(2);
2987 if (!wp)
2988 goto out_free;
2989 Conn_set_wp(C, wp);
2990 }
2991
2992 ret = Conn_add_obj(Conn_epoll_fd, C);
504 2993 if (ret != 0) if (ret != 0)
505 goto out_free_fd;
2994 goto out_free;
506 2995
507 2996 if (do_connect == 1) if (do_connect == 1)
508 2997 Conn_pending++; Conn_pending++;
 
... ... int Conn_commit(struct Conn *C)
511 3000
512 3001 return 0; return 0;
513 3002
514 out_free_fd:
515 Conn_free_intern(slot);
3003 out_free:
3004 Conn_free_intern(C);
516 3005
517 3006 return -1; return -1;
518 3007 } }
 
... ... struct Conn *Conn_connect(const int domain, const int type, const char *addr,
586 3075 return X; return X;
587 3076 } }
588 3077
589 static void Conn_accept(const unsigned int slot)
590 {
591 int fd, err;
592 struct sockaddr *pca;
593 struct sockaddr_in ca4;
594 struct sockaddr_in6 ca6;
595 socklen_t cax_len;
596 struct Conn *X;
597
598 Log(10, "Accepting a connection on slot=%u via %s/%d, type %s, domain %s"
599 ", protocol %s.\n",
600 slot, C->bind_addr, C->bind_port, Conn_type(C),
601 Conn_domain(C), Conn_get_socket_protocol(C));
602
603 switch(C->sock_domain) {
604 case PF_INET:
605 pca = (struct sockaddr *) &ca4;
606 cax_len = sizeof(ca4);
607 break;
608
609 case PF_INET6:
610 pca = (struct sockaddr *) &ca6;
611 cax_len = sizeof(ca6);
612 break;
613
614 default:
615 snprintf(Conn_error, sizeof(Conn_error),
616 "Cannot deal with domain %d.",
617 C->sock_domain);
618 Conn_error_raise(slot, EAFNOSUPPORT);
619 return;
620 }
621
622 fd = accept4(C->fd, pca, &cax_len,
623 SOCK_NONBLOCK | SOCK_CLOEXEC);
624 if (fd == -1) {
625 if (errno == EAGAIN)
626 return;
627
628 /* TODO: ratelimit */
629 Log(2, "WARN: Cannot accept on fd %d [%s].\n",
630 C->fd, strerror(errno));
631 /*
632 * We must not raise an error here because we will close the
633 * master socket!
634 * TODO: We should signal it as a warning.
635 */
636 /* Conn_error_raise(slot, errno); */
637 return;
638 }
639
640 /* After calling Conn_alloc, pointer to slot can change, so C is not valid */
641 X = Conn_alloc();
642 if (!X) {
643 Conn_error_raise(slot, ENOMEM);
644 close(fd);
645 return;
646 }
647
648 X->fd = fd;
649 X->type = CONN_TYPE_P2P;
650 X->state = CONN_STATE_OPEN;
651 X->time_open = Conn_now;
652 X->via = C->id;
653 X->events = EPOLLIN | EPOLLOUT;
654
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);
658
659 X->flags |= CONN_ADDR_LOCAL_DIRTY | CONN_ADDR_REMOTE_DIRTY;
660
661 if (C->wp != NULL) {
662 err = Conn_wpool_enqueue(C->wp, X);
663 if (err != 0) {
664 Conn_error_raise(slot, CONN_ERROR_INTERNAL);
665 Conn_free_intern(X->slot);
666 return;
667 }
668 /* TODO: send signaling to thread to call accept callback */
669 /* TODO: maybe we want to pass the fd also by signaling channel */
670 } else {
671 err = Conn_add_obj(X);
672 if (err != 0) {
673 Conn_error_raise(slot, err);
674 Conn_free_intern(X->slot);
675 return;
676 }
677
678 if (C->cb_accept)
679 C->cb_accept(X);
680 else if (Conn_accept_cb != NULL)
681 Conn_accept_cb(X);
682 }
683
684 Conn_work_to_do++;
685
686 Conn_total++;
687 }
688
689 static void Conn_accept_allow(void)
690 {
691 unsigned int slot;
692
693 if (Conn_accept_is_allowed == Conn_accept_is_allowed_last)
694 return;
695
696 Log(10, "%s: Turning accept allow from %d to %d...\n",
697 __func__, Conn_accept_is_allowed_last,
698 Conn_accept_is_allowed);
699
700 for (slot = 0; slot < Conn_no; slot++) {
701 if (C->type != CONN_TYPE_MASTER)
702 continue;
703
704 if (Conn_accept_is_allowed == 0)
705 C->events &= ~EPOLLIN;
706 else
707 C->events |= EPOLLIN;
708
709 Conn_change_obj(C);
710 }
711
712 Conn_accept_is_allowed_last = Conn_accept_is_allowed;
713 }
714
3078 #if 0
715 3079 /* /*
716 3080 * Add tokens to connection * Add tokens to connection
717 3081 */ */
718 static void Conn_band_update(const unsigned int slot)
3082 static void Conn_band_update(struct Conn *C)
719 3083 { {
720 3084 long diff; long diff;
721 3085
 
... ... static void Conn_band_update(const unsigned int slot)
740 3104 if (C->band_tokens > C->band_factor * C->band_width) if (C->band_tokens > C->band_factor * C->band_width)
741 3105 C->band_tokens = C->band_factor * C->band_width; C->band_tokens = C->band_factor * C->band_width;
742 3106
743 C->events |= EPOLLOUT;
744 Conn_change_obj(C);
3107 if (C->cbs.send)
3108 C->cbs.send(C);
745 3109
746 Log(debug_band, "\t\tBAND: slot=%u, id=%llu, added tokens -> %u.\n",
747 slot, C->id, C->band_tokens);
3110 Log(debug_band, "%p BAND: id %llu added tokens -> %u.\n",
3111 C, C->id, C->band_tokens);
748 3112 } }
749 3113
750 3114 /* /*
 
... ... static void Conn_band_update(const unsigned int slot)
754 3118 int Conn_band(struct Conn *C, const unsigned int width, int Conn_band(struct Conn *C, const unsigned int width,
755 3119 const unsigned int factor) const unsigned int factor)
756 3120 { {
757 unsigned int slot;
758
759 slot = C->slot;
760
761 Log(11, "\tConn_band: slot=%u, id=%llu, width=%u, factor=%u.\n",
762 slot, C->id, width, factor);
3121 Log(11, "%p %s id %llu width=%u factor=%u.\n",
3122 C, __func__, C->id, width, factor);
763 3123
764 3124 C->band_lasttime = Conn_now; C->band_lasttime = Conn_now;
765 3125 C->band_width = width; C->band_width = width;
 
... ... int Conn_band(struct Conn *C, const unsigned int width,
772 3132
773 3133 return 0; return 0;
774 3134 } }
3135 #endif
775 3136
3137 #if 0
3138 TODO
776 3139 static void Conn_trytoconnect(void) static void Conn_trytoconnect(void)
777 3140 { {
778 3141 struct addrinfo hints; struct addrinfo hints;
779 3142 struct addrinfo *res; struct addrinfo *res;
780 3143 int i, ret; int i, ret;
781 3144 char port[8]; char port[8];
3145 struct Conn *C;
782 3146
783 Log(8, "%s: Conn_pending=%d\n",
784 __func__, Conn_pending);
785
786 for (i = Conn_no - 1; i >= 0; i--) {
787 if (Conns[i].type != CONN_TYPE_P2P)
788 continue;
3147 Log(8, "%p %s Conn_pending=%d\n",
3148 C, __func__, Conn_pending);
789 3149
790 if ((Conns[i].state == CONN_STATE_CONNECT_0)
791 && (Conns[i].tryat <= Conn_now.tv_sec)) {
792 Conns[i].state = CONN_STATE_CONNECT_a;
793 }
3150 C = Conn_connect_list.head;
3151 while (C) {
3152 if ((C->state == CONN_STATE_CONNECT_0)
3153 && (C->tryat <= Conn_now.tv_sec))
3154 C->state = CONN_STATE_CONNECT_a;
794 3155
795 if (Conns[i].state != CONN_STATE_CONNECT_a)
3156 if (C->state != CONN_STATE_CONNECT_a) {
3157 C = C->next;
796 3158 continue; continue;
3159 }
797 3160
798 Log(9, "\tTrying to connect slot=%u, id=%llu, to %s/%d...\n",
799 Conns[i].slot, Conns[i].id, Conns[i].addr, Conns[i].port);
3161 Log(9, "%p Trying to connect id %llu, to %s/%d...\n",
3162 C, C->id, C->addr, C->port);
800 3163
801 3164 memset(&hints, 0, sizeof(hints)); memset(&hints, 0, sizeof(hints));
802 if (Conns[i].sock_domain == 0)
3165 if (C->sock_domain == 0)
803 3166 hints.ai_family = PF_UNSPEC; hints.ai_family = PF_UNSPEC;
804 3167 else else
805 hints.ai_family = Conns[i].sock_domain;
806 hints.ai_socktype = Conns[i].sock_type;
807 /*hints.ai_flags = AI_NUMERICHOST;*/
3168 hints.ai_family = C->sock_domain;
3169 hints.ai_socktype = C->sock_type;
808 3170 hints.ai_flags = AI_ADDRCONFIG; hints.ai_flags = AI_ADDRCONFIG;
809 snprintf(port, sizeof(port), "%d", Conns[i].port);
3171 snprintf(port, sizeof(port), "%d", C->port);
810 3172 res = NULL; res = NULL;
811 ret = getaddrinfo(Conns[i].addr, port, &hints, &res);
3173 ret = getaddrinfo(C->addr, port, &hints, &res);
812 3174 if (ret != 0) { if (ret != 0) {
813 Conns[i].state = CONN_STATE_ERROR;
814 Conns[i].error_state = CONN_ERROR_GETADDRINFO;
3175 C->state = CONN_STATE_ERROR;
3176 C->error_state = CONN_ERROR_GETADDRINFO;
815 3177 if (res) if (res)
816 3178 freeaddrinfo(res); freeaddrinfo(res);
3179 C = C->next;
817 3180 continue; continue;
818 3181 } }
819 3182
820 if (Conns[i].fd == -1) {
821 Conns[i].fd = socket(res->ai_family, res->ai_socktype, 0);
822 if (Conns[i].fd == -1) {
823 Conns[i].state = CONN_STATE_ERROR;
824 Conns[i].error_state = CONN_ERROR_SOCKET;
825 Conns[i].xerrno = errno;
3183 if (C->fd == -1) {
3184 C->fd = socket(res->ai_family, res->ai_socktype, 0);
3185 if (C->fd == -1) {
3186 C->state = CONN_STATE_ERROR;
3187 C->error_state = CONN_ERROR_SOCKET;
3188 C->xerrno = errno;
826 3189 freeaddrinfo(res); freeaddrinfo(res);
3190 C = C->next;
827 3191 continue; continue;
828 3192 } }
829 Log(10, "\tAllocated socket on fd %d\n",
830 Conns[i].fd);
3193 Log(10, "\tAllocated socket on fd %d\n", C->fd);
831 3194
832 Conn_setnonblock(Conns[i].fd);
3195 Conn_setnonblock(C->fd);
833 3196
834 3197 /* Need POLLOUT to signal when the connection was done. */ /* Need POLLOUT to signal when the connection was done. */
835 Conns[i].events |= (EPOLLIN | EPOLLOUT);
836 ret = Conn_add_obj(&Conns[i]);
3198 C->events |= EPOLLIN | EPOLLRDHUP | EPOLLOUT | EPOLLET;
3199 ret = Conn_add_obj(Conn_epoll_fd, C);
837 3200 if (ret != 0) { if (ret != 0) {
838 Conns[i].state = CONN_STATE_ERROR;
839 Conns[i].error_state = CONN_ERROR_SOCKET;
3201 C->state = CONN_STATE_ERROR;
3202 C->error_state = CONN_ERROR_SOCKET;
840 3203 freeaddrinfo(res); freeaddrinfo(res);
3204 C = C->next;
841 3205 continue; continue;
842 3206 } }
843 3207 } }
844 3208
845 3209 /* Set syn time */ /* Set syn time */
846 Conns[i].conn_syn = Conn_now;
3210 C->conn_syn = Conn_now;
847 3211
848 3212 Log(11, "\tConnecting...\n"); Log(11, "\tConnecting...\n");
849 ret = connect(Conns[i].fd, res->ai_addr, res->ai_addrlen);
3213 ret = connect(C->fd, res->ai_addr, res->ai_addrlen);
850 3214 if ((ret != 0) && (errno != EINPROGRESS)) { if ((ret != 0) && (errno != EINPROGRESS)) {
851 Conns[i].state = CONN_STATE_ERROR;
852 Conns[i].error_state = CONN_ERROR_CONNECT;
853 Conns[i].xerrno = errno;
3215 C->state = CONN_STATE_ERROR;
3216 C->error_state = CONN_ERROR_CONNECT;
3217 C->xerrno = errno;
854 3218 freeaddrinfo(res); freeaddrinfo(res);
3219 C = C->next;
855 3220 continue; continue;
856 3221 } }
857 3222
858 Conns[i].state = CONN_STATE_CONNECT_b;
3223 C->state = CONN_STATE_CONNECT_b;
859 3224
860 3225 Conn_pending--; Conn_pending--;
861 3226 Conn_total++; Conn_total++;
862 3227
863 3228 freeaddrinfo(res); freeaddrinfo(res);
3229
3230 C = C->next;
864 3231 } }
865 3232
866 Log(8, "%s: After, Conn_pending=%d\n",
867 __func__, Conn_pending);
3233 Log(8, "%p %s After, Conn_pending=%d\n", C, __func__, Conn_pending);
868 3234 } }
3235 #endif
869 3236
3237 #if 0
870 3238 /* /*
871 3239 * Moving an in-use slot over a free one for compacting reason. * Moving an in-use slot over a free one for compacting reason.
872 3240 */ */
 
... ... static void Conn_move_slot(const unsigned int dst, const unsigned int src)
877 3245 if (dst == src) if (dst == src)
878 3246 return; return;
879 3247
880 Log(10, "\t\t%s: Moving id %llu from slot=%u to slot=%d...\n",
3248 Log(10, "%s Moving id %llu from slot=%u to slot=%d...\n",
881 3249 __func__, Conns[src].id, src, dst); __func__, Conns[src].id, src, dst);
882 3250
883 3251 /* We need to save old location because of usefull pointers. */ /* We need to save old location because of usefull pointers. */
 
... ... static void Conn_move_slot(const unsigned int dst, const unsigned int src)
890 3258
891 3259 Conn_change_obj(&Conns[dst]); Conn_change_obj(&Conns[dst]);
892 3260 } }
3261 #endif
893 3262
894 3263 /* /*
895 3264 * Does the polling of file descriptors. * Does the polling of file descriptors.
 
... ... int Conn_poll(const int timeout)
900 3269 { {
901 3270 int ret; int ret;
902 3271 int timeout2; int timeout2;
903 unsigned int slot, last;
904 3272
905 Log(9, "%s: timeout=%d Conn_no=%d, Conn_work_to_do=%u)\n",
3273 Log(9, "%s timeout=%d Conn_no=%d Conn_work_to_do=%u\n",
906 3274 __func__, timeout, Conn_no, Conn_work_to_do); __func__, timeout, Conn_no, Conn_work_to_do);
907 3275
908 if (timeout > 1000)
909 timeout2 = 1000;
3276 if (timeout > 5000)
3277 timeout2 = 5000;
910 3278 else if (timeout == -1) else if (timeout == -1)
911 timeout2 = 1000;
3279 timeout2 = 5000;
912 3280 else else
913 3281 timeout2 = timeout; timeout2 = timeout;
914 3282
915 3283 loop: loop:
916 if (Conn_must_stop == 1)
3284 if (unlikely(Conn_must_stop == 1))
917 3285 return 0; return 0;
918 3286
919 if (Conn_work_to_do == 0) {
920 Log(9, "%s: work_to_do is 0, so return 0!\n",
3287 if (unlikely(Conn_work_to_do == 0)) {
3288 Log(9, "%s work_to_do is 0, so return 0!\n",
921 3289 __func__); __func__);
922 3290 return 0; return 0;
923 3291 } }
924 3292
3293 #if 0
3294 TODO
925 3295 if (Conn_pending > 0) if (Conn_pending > 0)
926 3296 Conn_trytoconnect(); Conn_trytoconnect();
3297 #endif
927 3298
928 ret = Conn_dispatch_events(timeout2, Conn_poll_cb);
929 if (ret < 0)
3299 ret = Conn_dispatch_events(Conn_epoll_fd, Conn_epoll_events,
3300 CONN_EVENTS_SLOTS, timeout2, Conn_poll_cb);
3301 if (unlikely(ret < 0))
930 3302 return -1; return -1;
931 3303
3304 #if 0
932 3305 Log(9, "Do compacting, expiration and band stuff...\n"); Log(9, "Do compacting, expiration and band stuff...\n");
3306 TODO
933 3307 slot = 0; slot = 0;
934 3308 while (slot < Conn_no) { while (slot < Conn_no) {
935 3309 /* /*
 
... ... int Conn_poll(const int timeout)
968 3342
969 3343 slot++; slot++;
970 3344 } }
971
972 /* Blocking accept if full queue or unblock if not */
973 Conn_accept_allow();
3345 #endif
974 3346
975 3347 /* Any work left to do? */ /* Any work left to do? */
976 3348 if (Conn_no == 0) { if (Conn_no == 0) {
 
... ... int Conn_poll(const int timeout)
984 3356 return ret; return ret;
985 3357 } }
986 3358
987 /*
988 * Returns the lifetime of a connection
989 * TODO: To be moved in 'core'?
990 */
991 unsigned long long Conn_lifetime(struct Conn *C)
3359
3360 /* ############ Callbacks ########### */
3361 static void Conn_default_cbs_accept(struct Conn *C)
3362 {
3363 if (Conn_debug_level > 10) {
3364 Log(0, "%p A conn was accepted from %s/%d (id %llu)\n",
3365 C, Conn_addr_remote(C), Conn_port_remote(C), Conn_getid(C));
3366 }
3367 }
3368
3369 __hot static void Conn_default_cbs_recv(struct Conn *C)
992 3370 { {
993 unsigned int slot;
3371 ssize_t n;
3372 unsigned int max, xfer_in_this_call;
3373 int r, xerrno;
3374 char *dump, call_callback;
3375 unsigned char add_to_extra_queue;
3376
3377 Log(10, "%p %s id %llu fd=%d head=%u tail=%u size=%u...\n",
3378 C, __func__, C->id, C->fd,
3379 C->ibuf_head, C->ibuf_tail, C->ibuf_size);
3380
3381 add_to_extra_queue = 0;
3382 call_callback = 0;
3383 xfer_in_this_call = 0;
3384 while (1) {
3385 if ((Conn_max_recv > 0) && (xfer_in_this_call >= Conn_max_recv)) {
3386 Log(3, "%p Recv limit reached. Add to extra queue.\n", C);
3387 add_to_extra_queue = 1;
3388 break;
3389 }
3390
3391 if (unlikely(C->ibuf_tail == C->ibuf_size)) {
3392 r = Conn_try_expand_buf(C, 1, Conn_default_ibuf);
3393 if (unlikely(r != 0)) {
3394 C->error_state = CONN_ERROR_MEM;
3395 /* TODO: Just suspend connection for 1 second instead;
3396 add to extra queue? */
3397 return;
3398 }
3399 }
3400
3401 max = C->ibuf_size - C->ibuf_tail;
3402 if ((Conn_max_recv > 0) && (max > Conn_max_recv))
3403 max = Conn_max_recv;
3404
3405 while (1) {
3406 n = recv(C->fd, C->ibuf + C->ibuf_tail, max, 0);
3407 xerrno = errno;
3408 if (unlikely((n == -1) && (errno == EINTR)))
3409 continue;
3410 break;
3411 };
3412
3413 if ((n == -1) && (errno == EAGAIN)) {
3414 Log(10, "%p EAGAIN received. Wait next round.\n", C);
3415 C->revents &= ~EPOLLIN;
3416 break;
3417 }
3418
3419 if (unlikely(n < 0)) {
3420 Log(0, "%p Error receiving [%s]\n", C, strerror(errno));
3421 C->error_state = CONN_ERROR_RECV;
3422 C->xerrno = xerrno;
3423 Conn_free_intern(C);
3424 break;
3425 }
994 3426
995 slot = C->slot;
3427 if (unlikely(n == 0)) {
3428 Log(10, "%p Remote closed sending side. Set CLOSE_AFTER_SEND\n", C);
3429 C->close_after_send = 1;
3430 break;
3431 }
3432
3433 Log(10, "%p Received %d bytes.\n", C, n);
3434 call_callback = 1;
3435
3436 if (unlikely(Conn_debug_level >= 10)) {
3437 dump = Conn_dump(C->ibuf + C->ibuf_tail, n);
3438 Log(0, "%p %s\n", C, dump);
3439 free(dump);
3440 }
3441
3442 C->trecv = Conn_now;
3443 C->ibuf_tail += n;
3444 C->bi += n;
3445 xfer_in_this_call += n;
3446
3447 if (n < max) {
3448 Log(3, "%p Readed less(%d < %d) than what we requested."
3449 " Drop EPOLLIN and wait the signal.\n", C, n, max);
3450 C->revents &= ~EPOLLIN;
3451 break;
3452 }
3453 }
996 3454
997 return Conn_time_diff(&Conn_now, C.time_open);
3455 if (likely((call_callback == 1) && (C->cbs.data)))
3456 C->cbs.data(C);
3457
3458 if (unlikely(add_to_extra_queue)) {
3459 Log(1, "%p Add to extra processing queue. TODO\n", C);
3460 }
998 3461 } }
999 3462
1000 /*
1001 * Associate a Conn with a workers pool
1002 */
1003 void Conn_add_wp(struct Conn *C, struct Conn_wpool *wp)
3463 __hot static void Conn_default_cbs_send(struct Conn *C)
1004 3464 { {
1005 Conn_wpool_get(wp);
1006 C->wp = wp;
3465 ssize_t n;
3466 unsigned int max, xfer_in_this_call;
3467 int count, xerrno, r;
3468 char *buf;
3469 char *dump;
3470 unsigned char add_to_extra_queue;
3471
3472 Log(10, "%p %p %s id %llu fd=%d head=%u tail=%u size=%u\n",
3473 C, C->next, __func__, C->id, C->fd, C->obuf_head, C->obuf_tail,
3474 C->obuf_size);
3475
3476 add_to_extra_queue = 0;
3477 xfer_in_this_call = 0;
3478 while (1) {
3479 buf = C->obuf + C->obuf_head;
3480 count = Conn_oqlen(C);
3481 if (unlikely(count == 0)) {
3482 Log(5, "%p Empty output buffer.\n", C);
3483 C->revents &= ~EPOLLOUT;
3484 if (unlikely(C->close_after_send == 1)) {
3485 Log(9, "%p CLOSE_AFTER_SEND is set, close connection\n", C);
3486 /* TODO: this is not really an error; switch to other code */
3487 C->state = CONN_STATE_ERROR;
3488 C->error_state = CONN_ERROR_USERREQ;
3489 Conn_free_intern(C);
3490 }
3491
3492 if (C->shutdown_after_send == 1) {
3493 Log(9, "%p SHUTDOWN_AFTER_SEND is set, shutdown write\n", C);
3494 C->state = CONN_STATE_ERROR;
3495 r = shutdown(C->fd, SHUT_WR);
3496 if (unlikely(r != 0)) {
3497 Log(1, "%p: shutdown returned error [%s]!\n",
3498 C, strerror(errno));
3499 /* TODO: We must set a proper C->state */
3500 C->error_state = CONN_ERROR_HANGUP;
3501 Conn_free_intern(C);
3502 } else {
3503 /* TODO: this is not really an error; switch to other code */
3504 C->error_state = CONN_ERROR_USERREQ;
3505 }
3506 }
3507
3508 return;
3509 }
3510
3511 if ((Conn_max_send > 0) && (xfer_in_this_call >= Conn_max_send)) {
3512 Log(1, "%p Send limit reached. Add to extra queue.", C);
3513 add_to_extra_queue = 1;
3514 break;
3515 }
3516
3517 max = count;
3518 if ((Conn_max_send > 0) && (max > Conn_max_send))
3519 max = Conn_max_send;
3520
3521 /* bandwidth */
3522 if (unlikely(C->band_width > 0)) {
3523 if (max > C->band_tokens)
3524 max = C->band_tokens;
3525 if (max == 0) {
3526 Log(debug_band, "%p BAND: Suspend 100ms the C (no tokens)!\n", C);
3527 break;
3528 }
3529 }
3530
3531 Log(10, "%p send(fd=%d, buf (head=%u, tail=%u), max=%d (count=%d), 0)...\n",
3532 C, C->fd, C->obuf_head,
3533 C->obuf_tail, max, count);
3534 while (1) {
3535 n = send(C->fd, buf, max, 0);
3536 xerrno = errno;
3537 if (unlikely((n == -1) && (errno == EINTR)))
3538 continue;
3539 break;
3540 }
3541
3542 if ((n == -1) && (errno == EAGAIN)) {
3543 Log(10, "%p EAGAIN received. Wait next round.\n", C);
3544 C->revents &= ~EPOLLOUT;
3545 break;
3546 }
3547
3548 Log(10, "%p Sent %d bytes [head=%d tail=%d]\n",
3549 C, n, C->obuf_head, C->obuf_tail);
3550
3551 if (unlikely(n <= 0)) {
3552 Log(0, "%p Error in sending [%s]\n",
3553 C, strerror(errno));
3554 C->error_state = CONN_ERROR_SEND;
3555 C->xerrno = xerrno;
3556 Conn_free_intern(C);
3557 break;
3558 }
3559
3560 if (unlikely(Conn_debug_level >= 10)) {
3561 dump = Conn_dump(buf, n);
3562 Log(0, "%p %s\n", C, dump);
3563 free(dump);
3564 }
3565
3566 C->tsend = Conn_now;
3567 if (n < count) {
3568 C->obuf_head += n;
3569 } else {
3570 C->obuf_head = 0;
3571 C->obuf_tail = 0;
3572 }
3573 C->bo += n;
3574 xfer_in_this_call += n;
3575
3576 if (C->band_width > 0) {
3577 /* What if band_tokens < n?! */
3578 C->band_tokens -= n;
3579 Log(debug_band, "%p BAND: Remove %d tokens -> %u...\n",
3580 C, n, C->band_tokens);
3581 }
3582
3583 if (n < max) {
3584 Log(1, "%p Sent less than what we requested."
3585 " Drop EPOLLOUT and wait for signal."
3586 " Break loop.\n", C);
3587 C->revents &= ~EPOLLOUT;
3588 break;
3589 }
3590
3591 /*
3592 if (n == max) {
3593 Log(0, "%p n == max (%d == %d). Break the loop.\n",
3594 C, n, max);
3595 break;
3596 }
3597 */
3598 }
3599
3600 if (add_to_extra_queue) {
3601 Log(1, "%p Add to extra processing queue. TODO\n", C);
3602 }
1007 3603 } }
1008 3604
1009 /*
1010 * Disassociate a Conn with a workers pool
1011 */
1012 void Conn_del_wp(struct Conn *C, struct Conn_wpool *wp)
3605 static void Conn_default_cbs_data(struct Conn *C)
1013 3606 { {
1014 C->wp = NULL;
1015 Conn_wpool_put(wp);
3607 Log(10, "%p Data on conn id %llu\n", C, Conn_getid(C));
1016 3608 } }
3609
3610 __hot static void Conn_default_cbs_close(struct Conn *C)
3611 {
3612 Log(9, "%p Closing conn id %llu\n", C, Conn_getid(C));
3613 }
3614
3615 static void Conn_default_cbs_trigger(struct Conn *C)
3616 {
3617 Log(10, "%p Trigger on conn id %llu\n", C, Conn_getid(C));
3618 }
3619
3620 static void Conn_default_cbs_error(struct Conn *C)
3621 {
3622 /* TODO: put 0 */
3623 Log(10, "%p Error on conn id %llu (%s)\n",
3624 C, Conn_getid(C), Conn_strerror());
3625 }
3626
3627 static void Conn_default_cbs_connected(struct Conn *C)
3628 {
3629 Log(10, "%p We are connected (id %llu)\n", C, Conn_getid(C));
3630 }
3631
3632 static void Conn_default_cbs_accept_error(struct Conn *C)
3633 {
3634 Log(10, "%p Error accepting conn (id %llu) (%s)\n",
3635 C, Conn_getid(C), Conn_strerror());
3636 }
3637
File Conn.h changed (mode: 100644) (index fd37073..90f29fb)
1 1 #ifndef _Conn_h #ifndef _Conn_h
2 2 #define _Conn_h 1 #define _Conn_h 1
3 3
4 #include <Conn_core.h>
5 #include <Conn_wpool.h>
4 #include "Conn_config.h"
6 5
6 #include <stdlib.h>
7 #include <sys/types.h>
8 #include <fcntl.h>
9 #include <stdio.h>
10
11 struct Conn;
12 struct Conn_wpool;
13 struct Conn_split;
14
15 /* Parameters */
16 enum CONN_PARA {
17 CONN_PARA_AUTO_RECONNECT = 0,
18 CONN_PARA_RECONNECT_DELAY,
19 CONN_PARA_IDLE_TIME,
20 CONN_PARA_READ_TIMEOUT,
21 CONN_PARA_CONN_TIMEOUT,
22 CONN_PARA_TRIGGER,
23 CONN_PARA_IBUF,
24 CONN_PARA_OBUF
25 };
26
27 /* Callbacks */
28 enum CONN_CB {
29 CONN_CB_ACCEPT = 0,
30 CONN_CB_RECV,
31 CONN_CB_SEND,
32 CONN_CB_DATA,
33 CONN_CB_CLOSE,
34 CONN_CB_TRIGGER,
35 CONN_CB_ERROR,
36 CONN_CB_CONNECTED,
37 CONN_CB_ACCEPT_ERROR
38 };
39
40 /* misc */
41 extern void Log(const unsigned short level, char *format, ...);
42 extern char *Conn_dump(const void *buf_src0, const int len_src);
43 extern char *Conn_dumphex(const void *buf_src0, const int len_src);
44 extern void Conn_debug(int fd, const unsigned short debug);
45
46 /* split */
47 extern void Conn_split_free(struct Conn_split **s);
48 extern struct Conn_split *Conn_split(const char *line0);
49 extern char *Conn_split_get_size(const struct Conn_split *s,
50 const char *left, unsigned int *size);
51 extern char *Conn_split_get_e(const struct Conn_split *s,
52 const char *l);
53 extern char *Conn_split_get(const struct Conn_split *s,
54 const char *l);
55 extern unsigned long Conn_split_get_ul(const struct Conn_split *s,
56 const char *l, unsigned int base);
57 extern unsigned long long Conn_split_get_ull(const struct Conn_split *s,
58 const char *l, unsigned int base);
59 extern double Conn_split_get_d(const struct Conn_split *s,
60 const char *l);
61
62 /* conn */
63 extern unsigned long long Conn_lifetime(struct Conn *C);
64 extern char *Conn_strerror(void);
65 extern long long Conn_time_diff(const struct timeval *t1,
66 const struct timeval *t2);
67 extern char *Conn_status(const unsigned int flags);
68
69 extern unsigned int Conn_iqlen(const struct Conn *C);
70 extern unsigned int Conn_oqlen(const struct Conn *C);
71 extern unsigned int Conn_qlen(const struct Conn *C);
72 extern int Conn_nodelay(const struct Conn *C);
73 extern void Conn_rollback(struct Conn *C, const unsigned int bytes);
74 extern char *Conn_ibuf(const struct Conn *C);
75 extern char *Conn_obuf(const struct Conn *C);
76 extern unsigned long long Conn_getid(const struct Conn *C);
77 extern struct Conn *Conn_get(const unsigned long long id);
78 extern void Conn_last_time(const struct Conn *C, struct timeval *tv);
79 extern int Conn_set_cb(struct Conn *C, const unsigned int cb_type,
80 void (*f)(struct Conn *));
81 extern char *Conn_ostrstr(struct Conn *C, const unsigned int off,
82 const char *str, const unsigned int flags);
83 extern char *Conn_strstr(struct Conn *C, const char *str);
84 extern char *Conn_strcasestr(struct Conn *C, const char *str);
85 extern char *Conn_get_line(struct Conn *C);
86 extern void Conn_for_every_line(struct Conn *C,
87 void (*cb)(struct Conn *C, char *line));
88 extern int Conn_printf(struct Conn *C, const char *format, ...);
89 extern void Conn_eat(struct Conn *C, const unsigned int bytes);
90 extern void Conn_eatall(struct Conn *C);
91 extern void Conn_send_done(struct Conn *C);
92 extern void Conn_close(struct Conn *C);
93 extern void Conn_stop(void);
94 extern void Conn_set(struct Conn *C, const unsigned int var,
95 const int val);
96 extern char *Conn_addr_local(struct Conn *C);
97 extern char *Conn_addr_remote(struct Conn *C);
98 extern int Conn_port_local(struct Conn *C);
99 extern int Conn_port_remote(struct Conn *C);
100
101 /* wpool */
102 extern struct Conn_wpool *Conn_wpool_create(const unsigned short workers);
103 extern int Conn_wpool_destroy(struct Conn_wpool *wp);
104 extern void Conn_set_wp(struct Conn *C, struct Conn_wpool *wp);
105 extern void Conn_del_wp(struct Conn *C, struct Conn_wpool *wp);
106
107 /* conn 2 */
7 108 extern int Conn_init(const unsigned int max); extern int Conn_init(const unsigned int max);
8 109 extern int Conn_shutdown(void); extern int Conn_shutdown(void);
9 extern ssize_t Conn_send(struct Conn *C, void *buf, const size_t count);
10 extern ssize_t Conn_recv(struct Conn *C, void *buf, const size_t count);
11 extern struct Conn *Conn_socket_addr(const int domain, const int type,
12 const char *addr, const int port);
13 extern struct Conn *Conn_socket(const int domain, const int type,
14 const int port);
110 extern int Conn_enqueue_wait(struct Conn *C, const void *buf,
111 const size_t count);
112 extern int Conn_enqueue(struct Conn *C, const void *buf,
113 const size_t count);
114 extern struct Conn *Conn_alloc(void);
15 115 extern int Conn_set_socket_domain(struct Conn *C, const int domain); extern int Conn_set_socket_domain(struct Conn *C, const int domain);
16 116 extern int Conn_set_socket_type(struct Conn *C, const int type); extern int Conn_set_socket_type(struct Conn *C, const int type);
17 117 extern int Conn_set_socket_protocol(struct Conn *C, const int proto); extern int Conn_set_socket_protocol(struct Conn *C, const int proto);
 
... ... extern int Conn_set_socket_bind_addr(struct Conn *C, const char *addr);
19 119 extern int Conn_set_socket_addr(struct Conn *C, const char *addr); extern int Conn_set_socket_addr(struct Conn *C, const char *addr);
20 120 extern int Conn_set_socket_bind_port(struct Conn *C, const int port); extern int Conn_set_socket_bind_port(struct Conn *C, const int port);
21 121 extern int Conn_set_socket_port(struct Conn *C, const int port); extern int Conn_set_socket_port(struct Conn *C, const int port);
22 extern int Conn_poll(const int timeout);
23 extern int Conn_enqueue(struct Conn *C, void *buf,
24 const size_t count);
122 extern int Conn_commit(struct Conn *C);
123 extern struct Conn *Conn_socket_addr(const int domain, const int type,
124 const char *addr, const int port);
125 extern struct Conn *Conn_socket(const int domain, const int type,
126 const int port);
25 127 extern struct Conn *Conn_connect(const int domain, const int type, extern struct Conn *Conn_connect(const int domain, const int type,
26 128 const char *addr, const int port); const char *addr, const int port);
27 129 extern int Conn_band(struct Conn *C, const unsigned int width, extern int Conn_band(struct Conn *C, const unsigned int width,
28 130 const unsigned int factor); const unsigned int factor);
29 extern struct Conn *Conn_alloc(void);
30 extern int Conn_commit(struct Conn *C);
31 extern unsigned long long Conn_lifetime(struct Conn *C);
131 extern int Conn_poll(const int timeout);
32 132
33 /* wpool - TODO: move to Conn_wpool.c */
34 extern void Conn_add_wp(struct Conn *C, struct Conn_wpool *wp);
35 extern void Conn_del_wp(struct Conn *C, struct Conn_wpool *wp);
36 133 #endif #endif
File Conn_config.h.in changed (mode: 100644) (index 6367f3c..6a704fe)
12 12
13 13
14 14 /* /*
15 * How many events slots to pass to kernel in one epoll_wait call
15 * How many events slots to expect from kernel in one epoll_wait call
16 16 */ */
17 17 #define CONN_EVENTS_SLOTS 128 #define CONN_EVENTS_SLOTS 128
18 18
19 /*
20 * How many free structures to give back in one locked section
21 */
22 #define CONN_GIVE_BACK_LIMIT 128
23
24 /*
25 * How many Conn structures to allocate once
26 */
27 #define CONN_BULK_ALLOC 128
28
29 #if GCC_VERSION >= 40300
30 #define __hot __attribute__((__hot__))
31 #define __cold __attribute__((__cold__))
32 #else
33 #define __hot
34 #define __cold
35 #endif
36
37 /* Stolen from Linux kernel */
38 #define likely(x) (__builtin_constant_p(x) ? !!(x) : __builtin_expect(!!(x), 1))
39 #define unlikely(x) (__builtin_constant_p(x) ? !!(x) : __builtin_expect(!!(x), 0))
File Conn_core.c deleted (index 8a43a5b..0000000)
1 /*
2 * Author: Catalin(ux) M BOIE <catab at embedromix.ro>
3 * Date: 2004
4 * Description: Some functions to help writing network servers and clients,
5 * both ipv4 and ipv6.
6 * Licence: LGPL
7 */
8
9 #include "Conn_core.h"
10
11 /* Visible variables */
12 char *(*Conn_status_slot_html_cb)(const struct Conn *C);
13 char *(*Conn_status_cb)(void);
14
15 int Conn_epoll_fd;
16 static struct epoll_event Conn_epoll_events[CONN_EVENTS_SLOTS];
17
18 unsigned int Conn_max_reached = 0;
19 unsigned int Conn_default_ibuf = 128;
20 unsigned int Conn_default_obuf = 128;
21 unsigned int Conn_max_ibuf = 4096000;
22 unsigned int Conn_max_obuf = 4096000;
23
24 /* Max bytes to enqueue on one send/recv call */
25 unsigned int Conn_max_send = 32 * 1024;
26 unsigned int Conn_max_recv = 32 * 1024;
27
28 unsigned int Conn_no = 0;
29 unsigned int Conn_work_to_do = 0;
30 unsigned int Conn_max = 0;
31 unsigned long Conn_total = 0;
32 unsigned int Conn_start = 0;
33 unsigned int Conn_pending = 0;
34 struct timeval Conn_now;
35 unsigned short Conn_level = 0; /* debug level */
36 unsigned int Conn_accept_is_allowed;
37 unsigned int Conn_accept_is_allowed_last;
38 /* memory stuff */
39 unsigned long long Conn_mem_buffers_in = 0;
40 unsigned long long Conn_mem_buffers_out = 0;
41 unsigned long long Conn_mem_structs = 0;
42
43 struct Conn *Conns = NULL;
44 unsigned int Conn_inited = 0;
45 unsigned int Conn_allocated = 0;
46 unsigned long long Conn_id = 1;
47 unsigned int Conn_must_stop = 0;
48
49 static __thread char Conn_error[512];
50
51 FILE *Conn_Log = NULL;
52 int debug_band = 11;
53
54 /* queues */
55 struct Conn_queue Conn_queue_free;
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 };
69
70 /* Functions */
71
72 char *Conn_strerror(void)
73 {
74 return Conn_error;
75 }
76
77 /*
78 * Difference between two timeval strutures, in milliseconds
79 */
80 long long Conn_time_diff(const struct timeval *t1, const struct timeval *t2)
81 {
82 return (t1->tv_sec - t2->tv_sec) * 1000
83 + (t1->tv_usec - t2->tv_usec) / 1000;
84 }
85
86 /*
87 * Returns string representation of errno code
88 */
89 char *Conn_errno(const struct Conn *C)
90 {
91 static char buf[256];
92 char *is;
93
94 switch (C->error_state) {
95 case CONN_ERROR_USERREQ: is = "user"; break;
96 case CONN_ERROR_POLL: is = "poll"; break;
97 case CONN_ERROR_RECV: is = "recv"; break;
98 case CONN_ERROR_SEND: is = "send"; break;
99 case CONN_ERROR_SOCKET: is = "socket"; break;
100 case CONN_ERROR_HANGUP: is = "hangup"; break;
101 case CONN_ERROR_GETADDRINFO: is = "lookup error"; break;
102 case CONN_ERROR_EXPIRED: is = "expired"; break;
103 case CONN_ERROR_ACCEPT: is = "accept"; break;
104 case CONN_ERROR_MEM: is = "allocation failed"; break;
105 case CONN_ERROR_CONNECT: is = "connect"; break;
106 case CONN_ERROR_READ_TIMEOUT: is = "read timeout"; break;
107 case CONN_ERROR_CONN_TIMEOUT: is = "conn timeout"; break;
108 case CONN_ERROR_INTERNAL: is = "internal error"; break;
109 default: is = "?"; break;
110 }
111
112 snprintf(buf, sizeof(buf), "%s (%s)",
113 is, (C->xerrno > 0) ? strerror(C->xerrno) : "-");
114
115 return buf;
116 }
117
118 /*
119 * Raise an error. It is just a little helper.
120 */
121 void Conn_error_raise(struct Conn *C, const int err)
122 {
123 if (err != 0)
124 C->xerrno = err;
125
126 if (C->cbs.error)
127 C->cbs.error(C);
128 }
129
130 /* set noblocking */
131 int Conn_setnonblock(const int fd)
132 {
133 return fcntl(fd, F_SETFL, O_NONBLOCK | O_RDWR);
134 }
135
136 void Log(const unsigned short level, char *format, ...)
137 {
138 va_list ap;
139 FILE *out;
140
141 if (level > Conn_level)
142 return;
143
144 if (Conn_Log == NULL)
145 out = stderr;
146 else
147 out = Conn_Log;
148 fprintf(out, "%ld.%06ld ",
149 Conn_now.tv_sec, Conn_now.tv_usec);
150
151 va_start(ap, format);
152 vfprintf(out, format, ap);
153 va_end(ap);
154 }
155
156 char *Conn_dump(const void *buf_src0, const int len_src)
157 {
158 int i, j;
159 char tmp[3];
160 char *buf_dst;
161 unsigned char c;
162 const unsigned char *buf_src = buf_src0;
163
164 if (len_src < 0)
165 return strdup("[Error: len < 0]");
166
167 Log(30, "\tConn_dump(%p, len=%d)\n",
168 buf_src, len_src);
169
170 buf_dst = malloc(len_src * 4 + 1);
171 if (buf_dst == NULL)
172 return strdup("Memory allocation error1!");
173
174 j = 0;
175 for (i = 0; i < len_src; i++) {
176 c = buf_src[i];
177 if ((c < 32) || (c > 127)) {
178 buf_dst[j++] = '[';
179 snprintf(tmp, sizeof(tmp), "%02x", c);
180 buf_dst[j++] = tmp[0];
181 buf_dst[j++] = tmp[1];
182 buf_dst[j++] = ']';
183 } else {
184 buf_dst[j++] = c;
185 }
186 }
187
188 buf_dst[j] = '\0';
189
190 /*
191 Log(0, "%s ([%s], %d, [%s], %d\n",
192 __func__, buf_src, len_src, buf_dst, len_dst);
193 */
194
195 return buf_dst;
196 }
197
198 char *Conn_dumphex(const void *buf_src0, const int len_src)
199 {
200 int i, j;
201 char tmp[3];
202 char *buf_dst;
203 unsigned char c;
204 const unsigned char *buf_src = buf_src0;
205
206 if (len_src < 0)
207 return strdup("[Error: len < 0]");
208
209 Log(30, "\tConn_dumphex(%p, len=%d)\n",
210 buf_src, len_src);
211
212 buf_dst = malloc(len_src * 2 + 1);
213 if (buf_dst == NULL)
214 return strdup("Memory allocation error1!");
215
216 j = 0;
217 for (i = 0; i < len_src; i++) {
218 c = buf_src[i];
219 snprintf(tmp, sizeof(tmp), "%02x", c);
220 buf_dst[j++] = tmp[0];
221 buf_dst[j++] = tmp[1];
222 }
223
224 buf_dst[j] = '\0';
225
226 return buf_dst;
227 }
228
229 void Conn_debug(FILE *f, const unsigned short debug)
230 {
231 Conn_Log = f;
232 Conn_level = debug;
233 }
234
235 char *Conn_state(const struct Conn *C)
236 {
237 switch (C->state) {
238 case CONN_STATE_FREE: return "FREE";
239 case CONN_STATE_EMPTY: return "EMPTY";
240 case CONN_STATE_OPEN: return "OPEN";
241 case CONN_STATE_LISTEN: return "LISTEN";
242 case CONN_STATE_CONNECT_0: return "CONN0";
243 case CONN_STATE_CONNECT_a: return "CONNa";
244 case CONN_STATE_CONNECT_b: return "CONNb";
245 case CONN_STATE_ERROR: return "ERROR";
246 default: return "BUG?";
247 }
248 }
249
250 /*
251 * Expand the requested buffer
252 * what = 0 for out buffer, what = 1 for input buffer
253 * returns 0 if OK, -1 on error
254 */
255 int Conn_try_expand_buf(struct Conn *C, const int what,
256 const unsigned int needed)
257 {
258 char *p;
259 unsigned int hm;
260 unsigned int old_size, amount, head, tail;
261 unsigned int buf_size, max_buf;
262 char *pbuf;
263
264 if (what == 0) {
265 head = C->obuf_head;
266 tail = C->obuf_tail;
267 old_size = C->obuf_size;
268 buf_size = C->obuf_size;
269 max_buf = Conn_max_obuf;
270 pbuf = C->obuf;
271 } else {
272 head = C->ibuf_head;
273 tail = C->ibuf_tail;
274 old_size = C->ibuf_size;
275 buf_size = C->ibuf_size;
276 max_buf = Conn_max_ibuf;
277 pbuf = C->ibuf;
278 }
279
280 /* Do we have enough room? */
281 if (buf_size - tail >= needed)
282 return 0;
283
284 Log(10, "\tTry to expand buffer for [%s] needed=%d head=%u tail=%u.\n",
285 what == 0 ? "o" : "i", needed, head, tail);
286
287 amount = needed - (buf_size - tail);
288
289 /* Do not alloc less than 128 bytes */
290 if (amount < 128)
291 amount = 128;
292
293 hm = buf_size + amount;
294 if ((max_buf > 0) && (hm > max_buf))
295 hm = max_buf;
296
297 /* Seems we are not allowed to grow larger */
298 if (hm <= buf_size) {
299 Log(1, "Cannot obtain needed bytes:"
300 " hm(%u) <= buf_size(%u)!\n",
301 hm, buf_size);
302 return -1;
303 }
304
305 p = realloc(pbuf, hm);
306 if (p == NULL) {
307 Log(1, "Cannot realloc pbuf to %u bytes!\n", hm);
308 return -1;
309 }
310
311 if (what == 0) {
312 C->obuf = p;
313 C->obuf_size = hm;
314 Conn_mem_buffers_out += hm - old_size;
315 } else {
316 C->ibuf = p;
317 C->ibuf_size = hm;
318 Conn_mem_buffers_in += hm - old_size;
319 }
320
321 Log(10, "\tSucces. Old/new size = %u/%u.\n",
322 old_size, hm);
323
324 return 0;
325 }
326
327 /*
328 * Do not use it yet, it sucks (the paras)
329 */
330 void Conn_poll_status(const short ev, char *ret)
331 {
332 int i = 0;
333
334 strcpy(ret, "");
335
336 if (ev & EPOLLIN) ret[i++] = 'I';
337 if (ev & EPOLLPRI) ret[i++] = 'P';
338 if (ev & EPOLLOUT) ret[i++] = 'O';
339 if (ev & EPOLLERR) ret[i++] = 'E';
340 if (ev & EPOLLHUP) ret[i++] = 'H';
341 if (ev & EPOLLRDHUP) ret[i++] = 'h';
342 ret[i++] = '\0';
343 }
344
345 char *Conn_domain(const struct Conn *C)
346 {
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 "?";
352 }
353 }
354
355 char *Conn_type(const struct Conn *C)
356 {
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 "?";
362 }
363 }
364
365 char *Conn_get_socket_protocol(const struct Conn *C)
366 {
367 switch (C->sock_protocol) {
368 case IPPROTO_IP: return "IP";
369 default: return "?";
370 }
371 }
372
373 static char *Conn_socktype(const struct Conn *C)
374 {
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 "?";
380 }
381 }
382
383 /*
384 * Returns a nice speed
385 */
386 void Conn_speed(char *dst, const unsigned int dst_len, const unsigned int speed)
387 {
388 float sp;
389
390 sp = speed;
391
392 if (speed < 1000)
393 snprintf(dst, dst_len, "%.2fBps", sp);
394 else if (speed < 1000 * 1000)
395 snprintf(dst, dst_len, "%.2fKBps", sp / 1000);
396 else
397 snprintf(dst, dst_len, "%.2fMBps", sp / 1000 / 1000);
398 }
399
400 char *Conn_status_slot(struct Conn *C)
401 {
402 static char tmp[1024];
403 char polle[16], pollr[16];
404 char speedi[32], speedo[32];
405 unsigned int dT, si, so;
406 char flags[128], flags_prefix[3], flags_postfix[2];
407 char *local_addr, *remote_addr;
408 int local_port, remote_port;
409 char flags_tmp[64];
410
411 /* flags */
412 strcpy(flags, "");
413 strcpy(flags_prefix, " [");
414 strcpy(flags_postfix, "");
415
416 if (C->flags & CONN_FLAGS_AUTO_RECONNECT) {
417 strcat(flags, flags_prefix);
418 snprintf(flags_tmp, sizeof(flags_tmp), "autoreconnect_in_%ld/%u",
419 (C->tryat == 0) ? 0 : C->tryat - Conn_now.tv_sec,
420 C->delay);
421 strcat(flags, flags_tmp);
422 strcpy(flags_prefix, " ");
423 strcpy(flags_postfix, "]");
424 }
425 if (C->flags & CONN_FLAGS_CLOSE_AFTER_SEND) {
426 strcat(flags, flags_prefix);
427 strcat(flags, "close_after_send");
428 strcpy(flags_prefix, " ");
429 strcpy(flags_postfix, "]");
430 }
431
432 strcat(flags, flags_postfix);
433
434 Conn_poll_status(C->events, polle);
435 Conn_poll_status(C->revents, pollr);
436
437 dT = Conn_now.tv_sec - C->start;
438 if (dT == 0)
439 dT = 1;
440 si = C->bi / dT;
441 so = C->bo / dT;
442
443 Conn_speed(speedi, sizeof(speedi), si);
444 Conn_speed(speedo, sizeof(speedo), so);
445
446 Conn_set_address(C, 0);
447 Conn_set_address(C, 1);
448
449 local_addr = "-";
450 local_port = 0;
451 remote_addr = "-";
452 remote_port = 0;
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;
460 }
461 remote_addr = C->addr;
462 remote_port = C->port;
463 }
464
465 snprintf(tmp, sizeof(tmp), "id=%llu fd=%d"
466 " %s/%s/%s"
467 " %s %s"
468 " %s/%d <-> %s/%d"
469 " via=%llu [%s][%s] IO=%llu/%llu"
470 " BS=%u/%u S=%s/%s"
471 " T=%ld bw=%u f=%u tk=%u"
472 "%s",
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),
477 local_addr, local_port, remote_addr, remote_port,
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,
482 flags);
483
484 return tmp;
485 }
486
487 char *Conn_status_slot_html(struct Conn *C)
488 {
489 static char tmp[1024];
490 char polle[16], pollr[16], *ext = "";
491 char speedi[32], speedo[32];
492 unsigned int dT, si, so;
493
494 Conn_poll_status(C->events, polle);
495 Conn_poll_status(C->revents, pollr);
496
497 dT = Conn_now.tv_sec - C->start;
498 if (dT == 0)
499 dT = 1;
500 si = C->bi / dT;
501 so = C->bo / dT;
502
503 Conn_speed(speedi, sizeof(speedi), si);
504 Conn_speed(speedo, sizeof(speedo), so);
505
506 if (Conn_status_slot_html_cb)
507 ext = Conn_status_slot_html_cb(C);
508
509 snprintf(tmp, sizeof(tmp), "<td>%llu</td><td>%d</td>"
510 "<td>%s</td><td>%s</td><td>%s</td>"
511 "<td>%s</td><td>%s</td>"
512 "<td>%s/%d</td>"
513 "<td>%llu</td><td>%s</td><td>%s</td><td>%llu / %llu</td>"
514 "<td>%u / %u</td><td>%s / %s</td><td>%ld</td>"
515 "<td>%u</td><td>%u</td><td>%u</td>"
516 "%s",
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,
525 ext);
526
527 return tmp;
528 }
529
530 /* flags: bit 1 = 1 - html */
531 char *Conn_status(const unsigned int flags)
532 {
533 unsigned int len = 0, max, tmp_len;
534 char tmp[512];
535 char polle[16], pollr[16];
536 char *buf, *per_slot, *ext = "";
537 char speedi[32], speedo[32];
538 unsigned long long bi, bo, dT;
539
540 max = (Conn_no + 1) * 512 - 1;
541 buf = malloc(max + 1);
542 if (!buf)
543 return strdup("No enough memory!");
544
545 strcpy(buf, "");
546
547 gettimeofday(&Conn_now, NULL);
548 /* TODO: "len += " is incorrect */
549 tmp_len = snprintf(tmp, sizeof(tmp),
550 "Conn_pending=%d Conn_no/Conn_max=%d/%d Conn_total=%lu"
551 " Conn_uptime=%lus Conn_allocated=%d Conn_work_to_do=%u"
552 " Conn_mem_structs=%llu Conn_mem_buffers_in/out=%llu/%llu\n",
553 Conn_pending, Conn_no, Conn_max, Conn_total,
554 Conn_now.tv_sec - Conn_start, Conn_allocated, Conn_work_to_do,
555 Conn_mem_structs, Conn_mem_buffers_in, Conn_mem_buffers_out);
556 if ((tmp_len > 0) && (len + tmp_len < max)) {
557 strcat(buf, tmp);
558 len += tmp_len;
559 }
560
561 if (flags & 1)
562 if (Conn_status_cb)
563 ext = Conn_status_cb();
564
565 if (flags & 1) {
566 strcat(buf, "<table border=\"0\" cellspacing=\"1\" cellpadding=\"3\" bgcolor=\"#aaaaaa\">\n");
567 strcat(buf, "<tr bgcolor=\"ffffff\">\n");
568 strcat(buf, "<td>ID</td>");
569 strcat(buf, "<td>FD</td>");
570 strcat(buf, "<td>Dom</td>");
571 strcat(buf, "<td>Type</td>");
572 strcat(buf, "<td>Protocol</td>");
573 strcat(buf, "<td>SType</td>");
574 strcat(buf, "<td>State</td>");
575 strcat(buf, "<td>Addr/port</td>");
576 strcat(buf, "<td>Via</td>");
577 strcat(buf, "<td>Polle</td>");
578 strcat(buf, "<td>Pollr</td>");
579 strcat(buf, "<td>BI/BO</td>");
580 strcat(buf, "<td>BUF I/O</td>");
581 strcat(buf, "<td>Speed I/O</td>");
582 strcat(buf, "<td>Elap (s)</td>");
583 strcat(buf, "<td>Band</td>");
584 strcat(buf, "<td>F</td>");
585 strcat(buf, "<td>Tks</td>");
586 strcat(buf, ext);
587 strcat(buf, "</tr>\n");
588 } else {
589 strcat(buf, ext);
590 }
591
592 bi = 0; bo = 0; dT = 0;
593 for (slot = 0; slot < Conn_no; slot++) {
594 if (C->state == CONN_STATE_FREE)
595 continue;
596
597 if (C->type == CONN_TYPE_P2P) {
598 bi += C->bi;
599 bo += C->bo;
600 dT += Conn_now.tv_sec - C->start;
601 }
602
603 if (flags & 1)
604 strcat(buf, "<tr bgcolor=\"ffffff\">\n");
605
606 Conn_poll_status(C->events, polle);
607 Conn_poll_status(C->revents, pollr);
608
609 if ((flags & 1) == 0)
610 per_slot = Conn_status_slot(slot);
611 else
612 per_slot = Conn_status_slot_html(slot);
613 len += snprintf(tmp, sizeof(tmp), "%s\n", per_slot);
614 if (len < max)
615 strcat(buf, tmp);
616
617 if (flags & 1)
618 strcat(buf, "</tr>\n");
619 }
620
621 if (flags & 1)
622 strcat(buf, "</table>\n");
623
624 if (dT == 0)
625 dT = 1;
626
627 Conn_speed(speedi, sizeof(speedi), bi / dT);
628 Conn_speed(speedo, sizeof(speedo), bo / dT);
629
630 tmp_len = snprintf(tmp, sizeof(tmp), "Total speed I/O: %s/%s."
631 " Total bytes I/O: %llu/%llu\n",
632 speedi, speedo, bi, bo);
633 if (len + tmp_len < max) {
634 strcat(buf, tmp);
635 len += tmp_len;
636 }
637
638 return buf;
639 }
640
641 /*
642 * Returns the number of bytes in 'in' buffer
643 */
644 unsigned int Conn_iqlen(const struct Conn *C)
645 {
646 return C->ibuf_tail - C->ibuf_head;
647 }
648
649 /*
650 * Returns the number of bytes in 'out' buffer
651 */
652 unsigned int Conn_oqlen(const struct Conn *C)
653 {
654 return C->obuf_tail - C->obuf_head;
655 }
656
657 /*
658 * Returns the number of bytes in 'in' buffer (obsolete)
659 */
660 unsigned int Conn_qlen(const struct Conn *C)
661 {
662 return Conn_iqlen(C);
663 }
664
665 /*
666 * Returns 1 if we can ignore this connection
667 */
668 int Conn_ignore(struct Conn *C)
669 {
670 if (C->error_state > 0)
671 return 1;
672
673 return 0;
674 }
675
676 /*
677 * Close a connection if it exceeded maximum idle time or got a timeout
678 */
679 void Conn_expire(struct Conn *C)
680 {
681 long long diff_ms;
682
683 if (C->trigger > 0) {
684 /* We do not trigger first time */
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;
693 }
694 }
695
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;
703 }
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) {
707 /* connection attempt expired */
708 C->error_state = CONN_ERROR_CONN_TIMEOUT;
709 }
710 }
711 }
712
713 /*
714 * Set NODELAY on socket
715 */
716 int Conn_nodelay(const struct Conn *C)
717 {
718 int i = 1;
719
720 return setsockopt(C->fd, SOL_TCP, TCP_NODELAY, &i, sizeof(i));
721 }
722
723 void Conn_rollback(struct Conn *C, const unsigned int bytes)
724 {
725 if (C->obuf_tail - C->obuf_head <= bytes)
726 C->obuf_tail -= bytes;
727 }
728
729 /*
730 * Returns a pointer to current in buffer
731 */
732 char *Conn_ibuf(const struct Conn *C)
733 {
734 return C->ibuf + C->ibuf_head;
735 }
736
737 /*
738 * Returns a pointer to current out buffer
739 */
740 char *Conn_obuf(const struct Conn *C)
741 {
742 return C->obuf + C->obuf_head;
743 }
744
745 /*
746 * Returns the id of a connection
747 */
748 unsigned long long Conn_getid(const struct Conn *C)
749 {
750 return C->id;
751 }
752
753 /*
754 * Returns a Conn* searching by id
755 */
756 struct Conn *Conn_get(const unsigned long long id)
757 {
758 struct Conn *R = NULL;
759 int i;
760
761 for (i = Conn_no - 1; i >= 0; i--) {
762 if (Conns[i].id == id) {
763 R = &Conns[i];
764 break;
765 }
766 }
767
768 return R;
769 }
770
771 /*
772 * Returns the fd associated with C
773 */
774 int Conn_get_fd(const struct Conn *C)
775 {
776 return C->fd;
777 }
778
779 /*
780 * Returns the timeval of the last packet
781 */
782 void Conn_last_time(const struct Conn *C, struct timeval *tv)
783 {
784 *tv = C->trecv;
785 }
786
787 /*
788 * Set a callback
789 */
790 int Conn_set_cb(struct Conn *C, const unsigned int cb_type, void (*f)(struct Conn *))
791 {
792 switch (cb_type) {
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;
803 }
804
805 return 0;
806 }
807
808 /*
809 * Search for str in active buffer from a given offset
810 * Returns pointer to string if match or NULL if doesn't.
811 * @flags: bit 0 == 1 => case insensitive
812 */
813 char *Conn_ostrstr(struct Conn *C, const unsigned int off, const char *str,
814 const unsigned int flags)
815 {
816 unsigned int len, str_len, i;
817 char *buf, *ret = NULL;
818 int err;
819
820 len = C->ibuf_tail - C->ibuf_head - off;
821 buf = C->ibuf + C->ibuf_head + off;
822 str_len = strlen(str);
823
824 if (len < str_len)
825 return NULL;
826
827 i = 0;
828 while (i <= len - str_len) {
829 if (flags & 1)
830 err = strncasecmp(buf + i, str, str_len);
831 else
832 err = strncmp(buf + i, str, str_len);
833 if (err == 0) {
834 ret = buf + i;
835 break;
836 }
837
838 i++;
839 }
840
841 return ret;
842 }
843
844 /*
845 * Search for str in active buffer
846 * Returns pointer to string if match or NUll if doesn't.
847 */
848 char *Conn_strstr(struct Conn *C, const char *str)
849 {
850 return Conn_ostrstr(C, 0, str, 0);
851 }
852
853 /*
854 * Search for str in active buffer (case insensitive)
855 * Returns pointer to string if match or NUll if doesn't.
856 */
857 char *Conn_strcasestr(struct Conn *C, const char *str)
858 {
859 return Conn_ostrstr(C, 0, str, 1);
860 }
861
862 /*
863 * Returns a '\0' terminated line, modifying received buffer
864 */
865 char *Conn_get_line(struct Conn *C)
866 {
867 char *cr;
868
869 cr = Conn_ostrstr(C, 0, "\n", 1);
870 if (!cr)
871 return NULL;
872
873 *cr = '\0';
874
875 return Conn_ibuf(C);
876 }
877
878 /*
879 * Helper help building text line daemons
880 */
881 void Conn_for_every_line(struct Conn *C, int (*cb)(struct Conn *C, char *line))
882 {
883 int ret = 0;
884 char *line;
885 unsigned int line_size;
886
887 if (cb == NULL)
888 return;
889
890 while (1) {
891 line = Conn_get_line(C);
892 if (line == NULL)
893 break;
894
895 line_size = strlen(line) + 1;
896
897 Conn_rtrim(line, "\r");
898
899 ret = cb(C, line);
900 if (ret != 0)
901 break;
902
903 Conn_eat(C, line_size);
904 }
905 }
906
907 /*
908 * Eat @bytes from head of input buffer
909 */
910 void Conn_eat(struct Conn *C, const unsigned int bytes)
911 {
912 /* advance head */
913 C->ibuf_head += bytes;
914 if (C->ibuf_head >= C->ibuf_tail) {
915 C->ibuf_head = 0;
916 C->ibuf_tail = 0;
917 }
918
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));
922 }
923
924 /*
925 * Eat all input buffer
926 */
927 void Conn_eatall(struct Conn *C)
928 {
929 C->ibuf_head = 0;
930 C->ibuf_tail = 0;
931 }
932
933 /*
934 * If put buffer is empty, just mark for closing.
935 * If we have data, set the flag to do the closing after send.
936 */
937 void Conn_close(struct Conn *C)
938 {
939 Log(10, "%s: Mark id=%llu for closing...\n",
940 __func__, C->id);
941
942 if (C->obuf_head == C->obuf_tail)
943 C->error_state = CONN_ERROR_USERREQ;
944 else
945 C->flags |= CONN_FLAGS_CLOSE_AFTER_SEND;
946 }
947
948 /*
949 * Instructs Conn to stop
950 */
951 void Conn_stop(void)
952 {
953 Conn_must_stop = 1;
954 }
955
956 /*
957 * Set some internal parameters
958 */
959 void Conn_set(struct Conn *C, const unsigned int var, const int val)
960 {
961 int fd;
962
963 fd = Conn_get_fd(C);
964
965 switch (var) {
966 case CONN_PARA_AUTO_RECONNECT:
967 C->flags |= (val == 0) ? 0 : CONN_FLAGS_AUTO_RECONNECT;
968 break;
969 case CONN_PARA_RECONNECT_DELAY:
970 C->delay = val;
971 break;
972 case CONN_PARA_IDLE_TIME:
973 C->idle = val;
974 break;
975 case CONN_PARA_READ_TIMEOUT:
976 C->read_timeout = val;
977 break;
978 case CONN_PARA_CONN_TIMEOUT:
979 C->conn_timeout = val;
980 break;
981 case CONN_PARA_TRIGGER:
982 C->trigger = val;
983 C->last_trigger = 0;
984 break;
985 case CONN_PARA_IBUF:
986 setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &val, sizeof(val));
987 break;
988 case CONN_PARA_OBUF:
989 setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &val, sizeof(val));
990 break;
991 }
992 }
993
994 /*
995 * Init a queue
996 */
997 void Conn_queue_init(struct Conn_queue *q)
998 {
999 q->head = q->tail = NULL;
1000 }
1001
1002 /*
1003 * Add a slot in a queue
1004 */
1005 int Conn_queue_add(struct Conn_queue *q, struct Conn *C)
1006 {
1007 struct Conn_queue_entry *p;
1008
1009 p = (struct Conn_queue_entry *) calloc(1, sizeof(struct Conn_queue_entry));
1010 if (!p)
1011 return -1;
1012
1013 p->C = C;
1014 p->next = NULL;
1015
1016 if (q->head == NULL) {
1017 q->head = p;
1018 } else {
1019 q->tail->next = p;
1020 }
1021 q->tail = p;
1022
1023 return 0;
1024 }
1025
1026 /*
1027 * Destroys a queue
1028 */
1029 void Conn_queue_destroy(struct Conn_queue *q)
1030 {
1031 struct Conn_queue_entry *p, *next;
1032
1033 p = q->head;
1034 while (p) {
1035 next = p->next;
1036 free(p);
1037 p = next;
1038 }
1039
1040 q->head = q->tail = NULL;
1041 }
1042
1043 /* Misc */
1044 /*
1045 * Returns the string representation of an socket address
1046 * @flags: bit0==0 => local address, bit0==1 => peer address
1047 */
1048 int Conn_set_address(struct Conn *C, const int flags)
1049 {
1050 int err;
1051 struct sockaddr *psa;
1052 struct sockaddr_in sa4;
1053 struct sockaddr_in6 sa6;
1054 socklen_t sa_len;
1055 char *paddr;
1056 size_t addr_size;
1057 int *pport;
1058
1059 /* Test if we need to regenerate. */
1060 if (flags & 1) {
1061 if (!(C->flags & CONN_ADDR_REMOTE_DIRTY))
1062 return 0;
1063 } else {
1064 if (!(C->flags & CONN_ADDR_LOCAL_DIRTY))
1065 return 0;
1066 }
1067
1068 if (C->state == CONN_STATE_FREE)
1069 return 0;
1070
1071 switch (C->sock_domain) {
1072 case PF_INET:
1073 psa = (struct sockaddr *) &sa4;
1074 sa_len = sizeof(struct sockaddr_in);
1075 break;
1076 case PF_INET6:
1077 psa = (struct sockaddr *) &sa6;
1078 sa_len = sizeof(struct sockaddr_in6);
1079 break;
1080 default:
1081 return -1;
1082 }
1083
1084 if (flags & 1) {
1085 /* peer */
1086 paddr = C->addr;
1087 addr_size = sizeof(C->addr);
1088 pport = &C->port;
1089 err = getpeername(C->fd, psa, &sa_len);
1090 } else {
1091 /* local */
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);
1096 }
1097
1098 if (err != 0)
1099 return -1;
1100
1101 switch (C->sock_domain) {
1102 case PF_INET:
1103 inet_ntop(C->sock_domain, &sa4.sin_addr,
1104 paddr, addr_size);
1105 *pport = ntohs(sa4.sin_port);
1106 break;
1107 case PF_INET6:
1108 inet_ntop(C->sock_domain, &sa6.sin6_addr,
1109 paddr, addr_size);
1110 *pport = ntohs(sa6.sin6_port);
1111 break;
1112 default:
1113 return -1;
1114 }
1115
1116 /* Remove dirty flag */
1117 if (flags & 1) {
1118 C->flags &= ~CONN_ADDR_REMOTE_DIRTY;
1119 } else {
1120 C->flags &= ~CONN_ADDR_LOCAL_DIRTY;
1121 }
1122
1123 return 0;
1124 }
1125
1126 /*
1127 * Returns local address
1128 */
1129 char *Conn_addr_local(struct Conn *C)
1130 {
1131 Conn_set_address(C, 0);
1132
1133 return C->bind_addr;
1134 }
1135
1136 /*
1137 * Returns remote address
1138 */
1139 char *Conn_addr_remote(struct Conn *C)
1140 {
1141 Conn_set_address(C, 1);
1142
1143 return C->addr;
1144 }
1145
1146 /*
1147 * Returns local port
1148 */
1149 int Conn_port_local(struct Conn *C)
1150 {
1151 Conn_set_address(C, 0);
1152
1153 return C->bind_port;
1154 }
1155
1156 /*
1157 * Returns remote port
1158 */
1159 int Conn_port_remote(struct Conn *C)
1160 {
1161 Conn_set_address(C, 1);
1162
1163 return C->port;
1164 }
1165
1166 /*
1167 * Returns the address family for address stored in @addr.
1168 */
1169 int Conn_addr_family(const char *addr)
1170 {
1171 struct addrinfo hints, *results = NULL;
1172 int ret;
1173
1174 memset(&hints, 0, sizeof(struct addrinfo));
1175 hints.ai_family = AF_UNSPEC;
1176 hints.ai_socktype = 0;
1177 hints.ai_flags = AI_NUMERICHOST;
1178 hints.ai_protocol = 0;
1179 hints.ai_canonname = NULL;
1180 hints.ai_addr = NULL;
1181 hints.ai_next = NULL;
1182
1183 ret = getaddrinfo(addr, NULL, &hints, &results);
1184 if (ret != 0) {
1185 snprintf(Conn_error, sizeof(Conn_error),
1186 "getaddrinfo error on %s (%s)",
1187 addr, gai_strerror(ret));
1188 if (results)
1189 freeaddrinfo(results);
1190 return -1;
1191 }
1192
1193 ret = results->ai_family;
1194
1195 freeaddrinfo(results);
1196
1197 return ret;
1198 }
1199
1200 /* Splitting stuff */
1201
1202 /*
1203 * Cut from right, in place, the chars specified in @chars.
1204 */
1205 void Conn_rtrim(char *s, const char *chars)
1206 {
1207 char *e;
1208
1209 if (!s || (*s == '\0'))
1210 return;
1211
1212 e = s + strlen(s) - 1;
1213 while ((e >= s) && (strchr(chars, *e))) {
1214 *e = '\0';
1215 e--;
1216 }
1217 }
1218
1219 /*
1220 * Free a prealocated structure
1221 */
1222 void Conn_split_free(struct Conn_split **s)
1223 {
1224 struct Conn_split *p;
1225 struct Conn_split_cell *q, *next;
1226
1227 if (!s)
1228 return;
1229
1230 p = *s;
1231 if (!p)
1232 return;
1233
1234 q = p->head;
1235 while (q) {
1236 next = q->next;
1237 free(q);
1238 q = next;
1239 }
1240
1241 if (p->line)
1242 free(p->line);
1243
1244 free(p);
1245 }
1246
1247 /*
1248 * Split a buffer pointed by C to var,value pairs.
1249 */
1250 struct Conn_split *Conn_split(const char *line0)
1251 {
1252 char *p;
1253 struct Conn_split *ret = NULL;
1254 struct Conn_split_cell *q;
1255 char search_for;
1256 char *left, *right;
1257 unsigned int right_len;
1258
1259 ret = (struct Conn_split *) calloc(1, sizeof(struct Conn_split));
1260 if (!ret) {
1261 snprintf(Conn_error, sizeof(Conn_error),
1262 "cannot alloc memory for Conn_split!\n");
1263 return NULL;
1264 }
1265
1266 ret->line = strdup(line0);
1267 if (!ret->line) {
1268 snprintf(Conn_error, sizeof(Conn_error),
1269 "cannot alloc memory for line duplication!\n");
1270 goto free;
1271 }
1272
1273 Conn_rtrim(ret->line, "\r\n \t");
1274
1275 /* do the spliting */
1276 p = ret->line;
1277 while (*p != '\0') {
1278 /* skip empty space */
1279 while ((*p == ' ') || (*p == '\t'))
1280 p++;
1281
1282 if (*p == '\0')
1283 break;
1284
1285 /* Init */
1286 right = "";
1287 right_len = 0;
1288
1289 /* Building left */
1290 left = p;
1291 while ((*p != '\0') && (*p != '='))
1292 p++;
1293 if (*p != '\0') {
1294 *p = '\0';
1295
1296 /* skip '=' */
1297 p++;
1298
1299 /* Building right */
1300 right = p;
1301
1302 search_for = ' ';
1303 if (*p == '"') {
1304 search_for = '"';
1305 p++;
1306 }
1307
1308 while ((*p != '\0') && (*p != search_for)) {
1309 right_len++;
1310 p++;
1311 }
1312
1313 if (*p != '\0') {
1314 *p = '\0';
1315 p++;
1316 }
1317 }
1318
1319 /* alloc data and fill it */
1320 q = (struct Conn_split_cell *) calloc(1, sizeof(struct Conn_split_cell));
1321 if (!q) {
1322 snprintf(Conn_error, sizeof(Conn_error),
1323 "cannot alloc memory!\n");
1324 goto free;
1325 }
1326 q->left = left;
1327 q->right = right;
1328 q->right_len = right_len;
1329
1330 if (ret->head == NULL)
1331 ret->head = q;
1332 else
1333 ret->tail->next = q;
1334
1335 ret->tail = q;
1336 }
1337
1338 return ret;
1339
1340 free:
1341 Conn_split_free(&ret);
1342
1343 return NULL;
1344 }
1345
1346 /*
1347 * Search for a string and return the value
1348 */
1349 char *Conn_split_get_size(const struct Conn_split *s, const char *left,
1350 unsigned int *size)
1351 {
1352 struct Conn_split_cell *p;
1353
1354 p = s->head;
1355 while (p) {
1356 if (strcmp(left, p->left) == 0) {
1357 if (size != NULL)
1358 *size = p->right_len;
1359 return p->right;
1360 }
1361 p = p->next;
1362 }
1363
1364 return NULL;
1365 }
1366
1367 /*
1368 * Search for a string and return the value
1369 */
1370 char *Conn_split_get_e(const struct Conn_split *s, const char *l)
1371 {
1372 return Conn_split_get_size(s, l, NULL);
1373 }
1374
1375 /*
1376 * Search for a string and return the value or "" if not found
1377 */
1378 char *Conn_split_get(const struct Conn_split *s, const char *l)
1379 {
1380 char *r;
1381
1382 r = Conn_split_get_size(s, l, NULL);
1383 if (!r)
1384 r = "";
1385
1386 return r;
1387 }
1388
1389 /*
1390 * Return a value as unsigned long
1391 */
1392 unsigned long Conn_split_get_ul(const struct Conn_split *s, const char *l,
1393 unsigned int base)
1394 {
1395 char *r;
1396 unsigned long ret = 0;
1397
1398 r = Conn_split_get_e(s, l);
1399 if (r)
1400 ret = strtoul(r, NULL, base);
1401
1402 return ret;
1403 }
1404
1405 /*
1406 * Return a value as unsigned long long
1407 */
1408 unsigned long long Conn_split_get_ull(const struct Conn_split *s, const char *l,
1409 unsigned int base)
1410 {
1411 char *r;
1412 unsigned long long ret = 0;
1413
1414 r = Conn_split_get_e(s, l);
1415 if (r)
1416 ret = strtoull(r, NULL, base);
1417
1418 return ret;
1419 }
1420
1421 /*
1422 * Return a value as double
1423 */
1424 double Conn_split_get_d(const struct Conn_split *s, const char *l)
1425 {
1426 char *r;
1427 double ret = 0;
1428
1429 r = Conn_split_get_e(s, l);
1430 if (r)
1431 ret = strtod(r, NULL);
1432
1433 return ret;
1434 }
1435
1436 /*
1437 * Returns 1 if the string contains only 0-9a-zA-Z. Else 0
1438 */
1439 int Conn_alphanum(const char *s)
1440 {
1441 size_t i, len;
1442
1443 len = strlen(s);
1444 for (i = 0; i < len; i++)
1445 if (isalnum(s[i]) == 0)
1446 return 0;
1447
1448 return 1;
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 deleted (index 0a0b0f8..0000000)
1 #ifndef CONN_CORE_H
2 #define CONN_CORE_H
3
4 #include <Conn_config.h>
5
6 #include <stdarg.h>
7 #include <resolv.h>
8 #include <errno.h>
9 #include <signal.h>
10 #include <netinet/in.h>
11 #include <netdb.h>
12 #include <sys/types.h>
13 #include <sys/time.h>
14 #include <sys/stat.h>
15 #include <sys/socket.h>
16 #include <sys/epoll.h>
17 #include <unistd.h>
18 #include <time.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <unistd.h>
22 #include <string.h>
23 #include <fcntl.h>
24 #include <arpa/inet.h>
25 #include <netinet/tcp.h>
26 #include <ctype.h>
27
28
29 /* type */
30 enum CONN_TYPE {
31 CONN_TYPE_UNK = 0,
32 CONN_TYPE_MASTER,
33 CONN_TYPE_P2P
34 };
35
36 /* state */
37 enum CONN_STATE {
38 CONN_STATE_FREE = 0,
39 CONN_STATE_EMPTY,
40 CONN_STATE_OPEN,
41 CONN_STATE_LISTEN,
42 CONN_STATE_CONNECT_0,
43 CONN_STATE_CONNECT_a,
44 CONN_STATE_CONNECT_b,
45 CONN_STATE_ERROR
46 };
47
48 /* error kind */
49 enum CONN_ERROR {
50 CONN_ERROR_NO_ERROR = 0,
51 CONN_ERROR_USERREQ, /* user requested the close */
52 CONN_ERROR_POLL,
53 CONN_ERROR_RECV,
54 CONN_ERROR_SEND,
55 CONN_ERROR_SOCKET,
56 CONN_ERROR_HANGUP,
57 CONN_ERROR_GETADDRINFO,
58 CONN_ERROR_EXPIRED,
59 CONN_ERROR_ACCEPT, /* This is free. TODO: check! */
60 CONN_ERROR_MEM,
61 CONN_ERROR_CONNECT,
62 CONN_ERROR_READ_TIMEOUT,
63 CONN_ERROR_CONN_TIMEOUT,
64 CONN_ERROR_INTERNAL
65 };
66
67 /* FLAGS */
68 #define CONN_FLAGS_AUTO_RECONNECT 1 << 0
69 #define CONN_FLAGS_CLOSE_AFTER_SEND 1 << 1
70 #define CONN_ADDR_LOCAL_DIRTY 1 << 2
71 #define CONN_ADDR_REMOTE_DIRTY 1 << 3
72 #define CONN_ACCEPT_PENDING 1 << 4
73
74 /* Parameters */
75 enum CONN_PARA {
76 CONN_PARA_AUTO_RECONNECT = 0,
77 CONN_PARA_RECONNECT_DELAY,
78 CONN_PARA_IDLE_TIME,
79 CONN_PARA_READ_TIMEOUT,
80 CONN_PARA_CONN_TIMEOUT,
81 CONN_PARA_TRIGGER,
82 CONN_PARA_IBUF,
83 CONN_PARA_OBUF
84 };
85
86 /* Callbacks */
87 enum CONN_CB {
88 CONN_CB_ACCEPT = 0,
89 CONN_CB_RECV,
90 CONN_CB_SEND,
91 CONN_CB_DATA,
92 CONN_CB_CLOSE,
93 CONN_CB_TRIGGER,
94 CONN_CB_ERROR,
95 CONN_CB_CONNECTED,
96 CONN_CB_ACCEPT_ERROR
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
117 struct Conn
118 {
119 int fd;
120 unsigned int events, revents, events_cache; /* I/O events */
121
122 unsigned char type;
123
124 unsigned char state;
125 unsigned char error_state;
126
127 unsigned int slot, slot_cache;
128
129 char *ibuf;
130 unsigned int ibuf_size, ibuf_head, ibuf_tail;
131
132 char *obuf;
133 unsigned int obuf_size, obuf_head, obuf_tail;
134
135 struct timeval trecv, tsend; /* last time we saw an receive/send */
136 time_t idle; /* idle time allowed */
137 unsigned int read_timeout; /* Max timeout for receiving an answer (milliseconds) */
138
139 struct timeval conn_syn; /* Time when a connection was initiated */
140 unsigned int conn_timeout; /* Timeout for connection (milliseconds) */
141
142 time_t last_trigger; /* last trigger was at */
143 time_t trigger; /* Frequency of wakeup a connection */
144
145 int sock_domain;
146 int sock_type;
147 int sock_protocol;
148
149 char addr[64], bind_addr[64];
150 int port, bind_port;
151 unsigned long long via; /* "via" is the connection id via a client was accepted */
152
153 unsigned long long bi, bo;
154
155 void *private; /* private use by user */
156
157 /* reconnect stuff */
158 unsigned int retries;
159 unsigned int delay; /* delay between reconnects */
160 time_t tryat; /* when we go to CONNECT_a state */
161
162 int xerrno;
163
164 time_t start;
165
166 unsigned int flags;
167
168 /* bandwidth stuff */
169 struct timeval band_lasttime; /* last time tokens were added */
170 unsigned int band_tokens; /* 1 token -> 1000 bytes */
171 unsigned int band_factor; /* tokens cannot go past f * w */
172 unsigned int band_width; /* in 1000b increments */
173
174 unsigned long long id; /* the id of a connection */
175
176 struct Conn_cbs cbs; /* Specific callbacks */
177
178 struct timeval time_open; /* When a connect succeded */
179
180 /* wpool */
181 struct Conn_wpool *wp;
182 };
183
184 struct Conn_queue_entry
185 {
186 struct Conn *C;
187 struct Conn_queue_entry *next;
188 };
189
190 struct Conn_queue
191 {
192 struct Conn_queue_entry *head, *tail;
193 };
194
195
196 /* For parsing */
197 struct Conn_split_cell
198 {
199 struct Conn_split_cell *next;
200 char *left;
201 char *right;
202 unsigned int right_len;
203 };
204
205 struct Conn_split
206 {
207 struct Conn_split_cell *head, *tail;
208 char *line;
209 };
210
211 /* Variables */
212 extern char *(*Conn_status_slot_html_cb)(const struct Conn *C);
213 extern char *(*Conn_status_cb)(void);
214
215 extern int Conn_epoll_fd;
216
217 extern unsigned int Conn_max_reached;
218 extern unsigned int Conn_default_ibuf;
219 extern unsigned int Conn_default_obuf;
220 extern unsigned int Conn_max_ibuf;
221 extern unsigned int Conn_max_obuf;
222 extern unsigned int Conn_no;
223 extern unsigned int Conn_work_to_do;
224 extern unsigned int Conn_max;
225 extern unsigned long Conn_total;
226 extern unsigned int Conn_start;
227 extern unsigned int Conn_pending;
228 extern struct timeval Conn_now;
229 extern unsigned long long Conn_mem_buffers_in;
230 extern unsigned long long Conn_mem_buffers_out;
231 extern unsigned long long Conn_mem_structs;
232
233 extern unsigned int Conn_max_send;
234 extern unsigned int Conn_max_recv;
235
236 extern unsigned short Conn_level;
237 extern unsigned int Conn_accept_is_allowed;
238 extern unsigned int Conn_accept_is_allowed_last;
239
240 extern struct Conn *Conns;
241 extern unsigned int Conn_inited;
242 extern unsigned int Conn_allocated;
243 extern unsigned long long Conn_id;
244 extern unsigned int Conn_must_stop;
245
246 extern FILE *Conn_Log;
247 extern int debug_band;
248
249 /* queues */
250 extern struct Conn_queue Conn_queue_free;
251
252 /* Functions */
253 extern char *Conn_strerror(void);
254 extern void Log(const unsigned short level, char *format, ...);
255 extern char *Conn_errno(const struct Conn *C);
256 extern char *Conn_status_slot(struct Conn *C);
257 extern char *Conn_status(const unsigned int flags);
258 extern int Conn_try_expand_buf(struct Conn *C, const int what,
259 const unsigned int needed);
260 extern char *Conn_state(const struct Conn *C);
261
262 extern long long Conn_time_diff(const struct timeval *t1,
263 const struct timeval *t2);
264 extern void Conn_last_time(const struct Conn *C, struct timeval *tv);
265
266 extern int Conn_setnonblock(const int fd);
267
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);
270 extern void Conn_debug(FILE *f, const unsigned short debug);
271
272 extern void Conn_close(struct Conn *C);
273
274 extern int Conn_ignore(struct Conn *C);
275
276 extern void Conn_expire(struct Conn *C);
277
278 extern int Conn_set_cb(struct Conn *C, const unsigned int cb_type,
279 void (*f)(struct Conn *));
280 extern char *Conn_get_line(struct Conn *C);
281 extern void Conn_for_every_line(struct Conn *C,
282 int (*cb)(struct Conn *C, char *line));
283
284 extern void Conn_eat(struct Conn *C, const unsigned int bytes);
285 extern void Conn_eatall(struct Conn *C);
286
287 extern unsigned int Conn_iqlen(const struct Conn *C);
288 extern unsigned int Conn_oqlen(const struct Conn *C);
289 extern unsigned int Conn_qlen(const struct Conn *C); /* obsolete */
290
291 extern void Conn_set(struct Conn *C, const unsigned int var,
292 const int val);
293
294 extern int Conn_get_fd(const struct Conn *C);
295
296 extern unsigned long long Conn_getid(const struct Conn *C);
297
298 extern struct Conn *Conn_get(const unsigned long long id);
299
300 extern char *Conn_ibuf(const struct Conn *C);
301 extern char *Conn_obuf(const struct Conn *C);
302
303 extern void Conn_poll_status(const short ev, char *ret);
304
305 extern char *Conn_domain(const struct Conn *C);
306 extern char *Conn_type(const struct Conn *C);
307 extern char *Conn_get_socket_protocol(const struct Conn *C);
308
309 extern int Conn_addr_family(const char *addr);
310
311 extern void Conn_error_raise(struct Conn *C, const int err);
312
313 extern void Conn_stop(void);
314
315 extern int Conn_set_address(struct Conn *C, const int flags);
316
317 extern char *Conn_addr_local(struct Conn *C);
318 extern char *Conn_addr_remote(struct Conn *C);
319 extern int Conn_port_local(struct Conn *C);
320 extern int Conn_port_remote(struct Conn *C);
321
322 /* queue stuff */
323 extern void Conn_queue_init(struct Conn_queue *q);
324 extern int Conn_queue_add(struct Conn_queue *q,
325 struct Conn *C);
326 extern void Conn_queue_destroy(struct Conn_queue *q);
327
328 /* String stuff */
329 extern char *Conn_strstr(struct Conn *C, const char *str);
330 extern char *Conn_strcasestr(struct Conn *C, const char *str);
331
332 /* splitting stuff */
333 extern void Conn_rtrim(char *s, const char *chars);
334 extern struct Conn_split *Conn_split(const char *line);
335 extern char *Conn_split_get_size(const struct Conn_split *s,
336 const char *l, unsigned int *len);
337 extern char *Conn_split_get_e(const struct Conn_split *s,
338 const char *l);
339 extern char *Conn_split_get(const struct Conn_split *s,
340 const char *l);
341 extern unsigned long Conn_split_get_ul(const struct Conn_split *s,
342 const char *l, unsigned int base);
343 extern unsigned long long Conn_split_get_ull(const struct Conn_split *s,
344 const char *l, unsigned int base);
345 extern double Conn_split_get_d(const struct Conn_split *s,
346 const char *l);
347 extern void Conn_split_free(struct Conn_split **s);
348
349 /* Misc stuff */
350 extern int Conn_alphanum(const char *s);
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
372 #endif
373
File Conn_wpool.c deleted (index e8bcfbb..0000000)
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 deleted (index 076e0f4..0000000)
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 96a7eb0..9da6a61)
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 -pipe -fpic
5 export OBJS += Conn_core.o Conn.o \
6 Conn_wpool.o
4 export CFLAGS += -g -Wall -Wextra -pipe -fpic -O2
5 export OBJS += Conn.o
7 6
8 7 .PHONY: all .PHONY: all
9 8 all: libConn.so.@VER@ all: libConn.so.@VER@
10 9
11 10
12 Conn_core.o: Conn_core.c Conn_core.h Conn_config.h
13 $(CC) $(CFLAGS) $(INCS) -c Conn_core.c
14
15 Conn_wpool.o: Conn_wpool.c Conn_wpool.h Conn_core.o Conn_config.h
16 $(CC) $(CFLAGS) $(INCS) -c Conn_wpool.c
17
18 Conn.o: Conn.c Conn.h Conn_core.o Conn_wpool.o
11 Conn.o: Conn.c Conn.h Conn_config.h
19 12 $(CC) $(CFLAGS) $(INCS) -c Conn.c $(CC) $(CFLAGS) $(INCS) -c Conn.c
20 13
21 14 %.o: %.c %.o: %.c
File TODO changed (mode: 100644) (index f865b30..e3ddaa3)
1 == Some history ==
2 2013-11-12: on r1: ~3850 req/s (-n50000 -c2 + taskset + nice) branch mispredict: 9% K:3.11.4-201
3
1 4 == SHOWSTOPPERS == == SHOWSTOPPERS ==
5 [ ] Check with gdb why we get a segmentation fault in line 2267.
6 [ ]
2 7
3 8 == HIGH PRIORITY == == HIGH PRIORITY ==
9 [ ] When init Conn, preallocate a 1 worker wp and set it and when user requests
10 another wp, just put(wp) and set the new one? Or at commit time?
11 Use cases: want to alloc 1 core for a listen port and for other
12 many cores.
13 [ ] Split Conn_poll_cb into MASTER/NON_MASTER and do not make it callback
14 but inline.
15 [ ] ->next pointer can be remove from struct Conn.
16 This way I can save a lot of space.
17 [ ] Do not make the fd -1, is pointless.
18 [ ] At start, dump also the size of Conn structure.
4 19 [ ] Cache getaddrinfo responses [ ] Cache getaddrinfo responses
5 20 [ ] Replace Conn_X with Conn_get_socket_X! [ ] Replace Conn_X with Conn_get_socket_X!
6 [ ] Use shutdown(2) before closing connection (http://www.developerweb.net/forum/archive/index.php/t-2940.html).
21 [ ] Use shutdown(2) before closing connection
22 http://www.developerweb.net/forum/archive/index.php/t-2940.html.
7 23 [ ] Switch all pointers to callbacks to a single callback with paramenters + [ ] Switch all pointers to callbacks to a single callback with paramenters +
8 24 a flag that will say for what type of callbacks to call the callback. a flag that will say for what type of callbacks to call the callback.
9 [ ] Conn.c:532:19: warning: variable 'psa' set but not used [-Wunused-but-set-variable] & Co.
25 What happends when I want to change one callback?
26 [ ] Nu pare ca inchid conexiunea: fac shutdown, dar atit.
27 [ ] Conn_free_intern is not called. Because of callbacks?
28 [ ] Try to alloc bigger chunks for wpool and maybe other stuff.
29 [ ] Alloc private area just after Conn structure. Add a function to set private
30 size.
31 [ ] Set on master socket the needed in/out buffer sizes and inherit to accepted
32 ones. This is becuase we may need different buffers for different masters.
33 [ ] Daca am luat HUP, nu mai trebuie sa permit parsarea in continuare!
34 [ ] Ar trebui sa-l scoatem din lista de active C-ul caruia ii facem free.
35 [ ]
36 1383337000.648931 main Affinity for worker 1: 1
37 1383337003.109904 main pool_grow: Try to grow cells from 1024 to 2048.
38 1383337003.621690 main pool_grow: Try to grow cells from 2048 to 3072.
39 1383337004.153547 main pool_grow: Try to grow cells from 3072 to 4096.
40 1383337004.667851 main pool_grow: Try to grow cells from 4096 to 5120.
41 [ ] Align Conn structures to 8 bytes in allocations blocks.
42 [ ] Investigate the idea to put free buffers in front of the queue because
43 they are hot.
44 [ ] Investigate the idea to keep the free list per thread to avoid cache trashing.
45 [ ] Seems that I do not call close on a C that already received HUP.
46 Seems I must not call shutdown(SHUT_WR).
47 [ ] Trebuie sa fac tcpdump -w.
10 48 [ ] [ ]
11 49
12 == 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 50
51 == LOW PRIORITY ==
52 [ ] Investigate moving TCP stack in userspace.
53 [ ] Conn_join(C1, C2) (Bridge 2 connections together for proxy stuff.)
27 54 [ ] 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
28 55 [ ] Dump all memory statistics [ ] Dump all memory statistics
29 56 [ ] SCTP [ ] SCTP
 
35 62 [ ] Put callbacks in a structure to free some space from struct Conn. [ ] Put callbacks in a structure to free some space from struct Conn.
36 63 [ ] wpool: When we free a Conn structure, we have to Conn_del_wp! [ ] wpool: When we free a Conn structure, we have to Conn_del_wp!
37 64 [ ] wpool: What if we add master sockets also to workers and do nothing in main [ ] wpool: What if we add master sockets also to workers and do nothing in main
38 thread? Check ma.c example. Verified: accept waks in only one thread.
65 thread? Check ma.c example. Verified: accept wakes up only one thread.
39 66 Still to check if epoll wakes in all threads! Seems it wakes all threads! Still to check if epoll wakes in all threads! Seems it wakes all threads!
40 67 Not very good. Not very good.
41 68 [ ] Investigate splice. [ ] Investigate splice.
42 69 [ ] Investigate MSG_MORE as an alternative to CORK or writev. [ ] Investigate MSG_MORE as an alternative to CORK or writev.
43 [ ]
44
45 70 [ ] Check if we are swapping and warn. [ ] Check if we are swapping and warn.
46 71 [ ] Log faults and io. [ ] Log faults and io.
47 [ ] We must have a single set of pointers to callback, not many. At Conn creation,
48 we copy the default set and than replace, on request, some members.
49 This will simplify the code.
50 72 [ ] Add access control [ ] Add access control
51 73 Conn_ac_set_default(C, CONN_AC_DENY) - default deny (or CONN_AC_ALLOW) Conn_ac_set_default(C, CONN_AC_DENY) - default deny (or CONN_AC_ALLOW)
52 74 Conn_ac_add(C, CONN_AC_ALLOW, "2001::1/64"); - for ipv6 Conn_ac_add(C, CONN_AC_ALLOW, "2001::1/64"); - for ipv6
53 75 Conn_ac_add(C, CONN_AC_ALLOW, "192.168.0.0/25"); - for ipv4 Conn_ac_add(C, CONN_AC_ALLOW, "192.168.0.0/25"); - for ipv4
54 76 [ ] A la redir stuff [ ] A la redir stuff
55
56 [ ] Bridge 2 connections together for proxy stuff.
57 77 [ ] Check PACKET: can we send with "send" without knowing the MAC? [ ] Check PACKET: can we send with "send" without knowing the MAC?
58 78 [ ] UDP [ ] UDP
59 79 [ ] Ce se intimpla daca se ajunge la ~ sfirsitul buffer-ului si nu pot inca sa [ ] Ce se intimpla daca se ajunge la ~ sfirsitul buffer-ului si nu pot inca sa
 
... ... Pentru a reduce numarul de conexiuni in TIME-WAIT:
81 101
82 102 [ ] Add loadbalancing and failover in the base code. [ ] Add loadbalancing and failover in the base code.
83 103 [ ] Automaticaly put \0 at the end of receive data. What for?! [ ] Automaticaly put \0 at the end of receive data. What for?!
84 [ ] Add the possibility to wait for an char/string before calling recv callback.
104 [ ] Add the possibility to wait for an char/string before calling recv/data callback.
85 105 Maybe do this with socket filtering or in kernel? Maybe do this with socket filtering or in kernel?
86 106 [ ] Change socket buffer accordingly with user settings to minimize [ ] Change socket buffer accordingly with user settings to minimize
87 107 needed memory. needed memory.
88
89 108 [ ] Dump how many memory is in use vor various parts of the internal data. [ ] Dump how many memory is in use vor various parts of the internal data.
90 109 [ ] Do not mix slot and id and fd in examples. [ ] Do not mix slot and id and fd in examples.
91 110 [ ] Test suite [ ] Test suite
 
... ... Pentru a reduce numarul de conexiuni in TIME-WAIT:
96 115 [ ] [ ]
97 116
98 117 === When we switch to Conn version 2 library === === When we switch to Conn version 2 library ===
99 [ ] Conn_socket will cann Conn_socket_proto
118 [ ] Conn_socket will call Conn_socket_proto
100 119 [ ] use enums! [ ] use enums!
101 120 [ ] All internal variables of Conn structure must not be exposed directly. [ ] All internal variables of Conn structure must not be exposed directly.
102 121 [ ] http://urbanairship.com/blog/2010/09/29/linux-kernel-tuning-for-c500k/ [ ] http://urbanairship.com/blog/2010/09/29/linux-kernel-tuning-for-c500k/
File examples/Makefile changed (mode: 100644) (index 851c908..d7b0c60)
1 TARGETS := s c raw udp_s timeout trigger reconnect ntime blackhole_s blackhole_c \
2 xbind \
3 wpool1
1 TARGETS := wpool1 wpool2 \
2 s c raw udp_s timeout trigger reconnect ntime blackhole_s blackhole_c \
3 xbind
4
5 TARGETS := wpool2
4 6
5 7 all: $(TARGETS) all: $(TARGETS)
6 8
7 9 INCS += -I.. INCS += -I..
8 10 LIBS += -L.. -lConn LIBS += -L.. -lConn
9 11 OBJS := OBJS :=
10 DEPS := ../libConn.so.$(VER) $(OBJS)
12 DEPS := ../libConn.so $(OBJS)
11 13
12 14 s: s.c $(DEPS) s: s.c $(DEPS)
13 15 gcc $(CFLAGS) $(INCS) s.c -o s $(LIBS) gcc $(CFLAGS) $(INCS) s.c -o s $(LIBS)
 
... ... xbind: xbind.c $(DEPS)
51 53 wpool1: wpool1.c $(DEPS) wpool1: wpool1.c $(DEPS)
52 54 gcc $(CFLAGS) $(INCS) $@.c -o $@ $(LIBS) gcc $(CFLAGS) $(INCS) $@.c -o $@ $(LIBS)
53 55
56 wpool2: wpool2.c $(DEPS)
57 gcc $(CFLAGS) $(INCS) $@.c -o $@ $(LIBS)
58
54 59 ma: ma.c ma: ma.c
55 60 gcc $(CFLAGS) $(INCS) $@.c -o $@ -lpthread gcc $(CFLAGS) $(INCS) $@.c -o $@ -lpthread
56 61
File examples/s.c changed (mode: 100644) (index 3345af5..3f48e64)
... ... 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 __func__, Conn_addr_remote(C), Conn_addr_remote(C), Conn_getid(C));
55 __func__, Conn_addr_remote(C), Conn_port_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)
File examples/wpool1.c changed (mode: 100644) (index bd07f00..e1bc1bd)
23 23 #include <Conn.h> #include <Conn.h>
24 24
25 25 /* Global variables */ /* Global variables */
26 static unsigned short debug = 1;
26 static unsigned short debug = 100;
27 27
28 static void accept_cb(struct Conn *C)
29 {
30 int err;
31 char *s = "Hello!\n";
32
33 Log(0, "%s: sending hello!\n", __func__);
34
35 err = Conn_enqueue(C, s, strlen(s));
36 if (err == -1) {
37 Log(4, "\tCannot enqueue [%s]!\n", Conn_strerror());
38 Conn_close(C);
39 }
40 }
41
42 static void close_cb(struct Conn *C)
43 {
44 Log(5, "%s: Closing connection with %s/%d id=%llu\n",
45 __func__, Conn_addr_remote(C), Conn_port_remote(C),
46 Conn_getid(C));
47 }
48
49 static void data_cb_line(struct Conn *C, char *line)
50 {
51 int r;
52
53 if (strncmp(line, "shutdown", 8) == 0)
54 exit(1);
55
56 r = Conn_enqueue(C, line, strlen(line));
57 if (r == -1)
58 Log(0, "Cannot enqueue (%s)!\n", strerror(errno));
59 }
60
61 static void data_cb(struct Conn *C)
62 {
63 Conn_for_every_line(C, data_cb_line);
64 }
28 65
29 66 int main(void) int main(void)
30 67 { {
 
... ... int main(void)
33 70 struct Conn *C; struct Conn *C;
34 71 struct Conn_wpool *wp; struct Conn_wpool *wp;
35 72
36 Conn_debug(NULL, debug);
73 Conn_debug(stderr, debug);
37 74
38 75 ret = Conn_init(0); ret = Conn_init(0);
39 76 if (ret == -1) { if (ret == -1) {
 
... ... int main(void)
52 89 Conn_set_socket_type(C, SOCK_STREAM); Conn_set_socket_type(C, SOCK_STREAM);
53 90 Conn_set_socket_bind_addr(C, "127.0.0.1"); Conn_set_socket_bind_addr(C, "127.0.0.1");
54 91 Conn_set_socket_bind_port(C, 60000); 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;
60 }
61 92
93 /* Create a pool with 3 workers */
62 94 wp = Conn_wpool_create(3); wp = Conn_wpool_create(3);
63 95 if (wp == NULL) { if (wp == NULL) {
64 96 printf("Cannot create wpool!\n"); printf("Cannot create wpool!\n");
65 97 return 1; return 1;
66 98 } }
67 99
68 Conn_add_wp(C, wp);
100 Conn_set_wp(C, wp);
101
102 Conn_set_cb(C, CONN_CB_ACCEPT, accept_cb);
103 Conn_set_cb(C, CONN_CB_CLOSE, close_cb);
104 Conn_set_cb(C, CONN_CB_DATA, data_cb);
105
106 ret = Conn_commit(C);
107 if (ret != 0) {
108 printf("Cannot bind on ipv4 socket [%s].\n",
109 Conn_strerror());
110 return 1;
111 }
69 112
113 Log(12, "Waiting...\n");
70 114 while (1) { while (1) {
71 ret = Conn_poll(1000);
115 ret = Conn_poll(-1);
72 116 if (ret == -1) { if (ret == -1) {
73 117 printf("Error in poll [%s]!\n", printf("Error in poll [%s]!\n",
74 118 Conn_strerror()); Conn_strerror());
75 119 break; break;
76 120 } }
77 121
122 #if 0
78 123 if (debug >= 9) { if (debug >= 9) {
79 124 stat = Conn_status(0); stat = Conn_status(0);
80 125 printf("%s\n", stat); printf("%s\n", stat);
81 126 free(stat); free(stat);
82 127 } }
128 #endif
83 129 } }
84 130
85 131 Conn_del_wp(C, wp); Conn_del_wp(C, wp);
File examples/wpool2.c copied from file examples/wpool1.c (similarity 66%) (mode: 100644) (index bd07f00..7929424)
1 1 /* /*
2 * Test workers pool
2 * Test workers pool - web server
3 3 */ */
4 4
5 5 #define _GNU_SOURCE #define _GNU_SOURCE
 
23 23 #include <Conn.h> #include <Conn.h>
24 24
25 25 /* Global variables */ /* Global variables */
26 static unsigned short debug = 1;
26 static unsigned short debug = 2;
27 27
28 static void data_cb(struct Conn *C)
29 {
30 char body[4096];
31
32 memset(body, 'X', 100);
33 body[100] = '\0';
34
35 Conn_printf(C, "HTTP/1.0 200 OK\r\n"
36 "Server: wpool2\r\n"
37 "Content-Length: 100\r\n"
38 "\r\n"
39 "%s", body);
40 Conn_close(C);
41 }
28 42
29 43 int main(void) int main(void)
30 44 { {
31 char *stat;
32 45 int ret; int ret;
33 46 struct Conn *C; struct Conn *C;
34 47 struct Conn_wpool *wp; struct Conn_wpool *wp;
35 48
36 Conn_debug(NULL, debug);
49 Conn_debug(2, debug);
37 50
38 51 ret = Conn_init(0); ret = Conn_init(0);
39 52 if (ret == -1) { if (ret == -1) {
 
... ... int main(void)
50 63
51 64 Conn_set_socket_domain(C, PF_INET); Conn_set_socket_domain(C, PF_INET);
52 65 Conn_set_socket_type(C, SOCK_STREAM); Conn_set_socket_type(C, SOCK_STREAM);
53 Conn_set_socket_bind_addr(C, "127.0.0.1");
66 Conn_set_socket_bind_addr(C, "0.0.0.0");
54 67 Conn_set_socket_bind_port(C, 60000); 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;
60 }
61 68
62 wp = Conn_wpool_create(3);
69 /* Create a pool with 2 workers */
70 wp = Conn_wpool_create(2);
63 71 if (wp == NULL) { if (wp == NULL) {
64 72 printf("Cannot create wpool!\n"); printf("Cannot create wpool!\n");
65 73 return 1; return 1;
66 74 } }
67 75
68 Conn_add_wp(C, wp);
76 Conn_set_wp(C, wp);
77
78 Conn_set_cb(C, CONN_CB_DATA, data_cb);
79 Conn_set_cb(C, CONN_CB_ACCEPT, NULL);
80 Conn_set_cb(C, CONN_CB_CLOSE, NULL);
81
82 ret = Conn_commit(C);
83 if (ret != 0) {
84 printf("Cannot bind on ipv4 socket [%s].\n",
85 Conn_strerror());
86 return 1;
87 }
69 88
89 Log(12, "Waiting...\n");
70 90 while (1) { while (1) {
71 ret = Conn_poll(1000);
91 ret = Conn_poll(-1);
72 92 if (ret == -1) { if (ret == -1) {
73 93 printf("Error in poll [%s]!\n", printf("Error in poll [%s]!\n",
74 94 Conn_strerror()); Conn_strerror());
75 95 break; break;
76 96 } }
77 97
98 #if 0
78 99 if (debug >= 9) { if (debug >= 9) {
79 100 stat = Conn_status(0); stat = Conn_status(0);
80 101 printf("%s\n", stat); printf("%s\n", stat);
81 102 free(stat); free(stat);
82 103 } }
104 #endif
83 105 } }
84 106
85 107 Conn_del_wp(C, wp); Conn_del_wp(C, wp);
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