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)
First import. 5ad0e7b8aa527aaebab52c53b45c36257fce5d0a Catalin(ux) M. BOIE 2007-10-03 20:20:26
Commit 5ad0e7b8aa527aaebab52c53b45c36257fce5d0a - First import.
Author: Catalin(ux) M. BOIE
Author date (UTC): 2007-10-03 20:20
Committer name: Catalin(ux) M. BOIE
Committer date (UTC): 2007-10-03 20:20
Parent(s):
Signing key:
Tree: 55ebc0795bb808823937d3efbbfbb14ec2e7d8e2
File Lines added Lines deleted
Changelog 53 0
Conn.c 1811 0
Conn.h 222 0
Conn.spec.in 39 0
INSTALL 3 0
LICENSE 481 0
Makefile.head 26 0
Makefile.in 38 0
Makefile.tail 16 0
PROJECT 1 0
PROJECT_EXCLUDE 0 0
PROJECT_REV 1 0
PROJECT_TARGETS 1 0
PROJECT_VER 1 0
README 7 0
TODO 43 0
configure 118 0
docs/LINKS 3 0
examples/Makefile 30 0
examples/c.c 196 0
examples/c.run 4 0
examples/raw.c 159 0
examples/raw2.c 142 0
examples/s.c 167 0
examples/s.run 4 0
examples/timeout.c 141 0
examples/trigger.c 80 0
examples/udp_s.c 172 0
File Changelog added (mode: 100644) (index 0000000..b259242)
1 1.0.8:
2 - Added "ldconfig" to %post and %postun.
3 - Fixed a trigger problem: now it triggers in more states.
4 - Fixed wrong freeaddrinfo.
5 - Separated timeout in two: for read and for connect.
6 - Improved UDP support.
7 - Correcting a problem if no log file was specified.
8 - Fixed a bug in connection closing if no buffer to send.
9
10 1.0.7:
11 - Get rid of Conn_com.h.
12 - Added first support for PF_PACKET.
13 - Switch tsend/trecv to timeval from time_t. This way we can easily
14 retrieve the last timestamp of the last recv packet.
15 - Added a parameter to resize receiving buffer.
16 - Added possibility to add calbacks per connection.
17 - Removed typedef. Now yo must replace "Conn..." with "struct Conn...".
18 - If user close the connection, wait till output buffer is gone.
19 - Fixed a big bug regarding the order we called callbacks. Now it
20 always call connected before recv.
21 - Fixed another important bug because of the grow and a pointer to a
22 variable instead of the value.
23
24 1.0.6:
25 - Fix timeout logic; now it should works good.
26 - gai_strerror received wrong parameter.
27 - Added triggers.
28 - Corrected a timeout bug.
29 - Bug testing for id (going negative).
30 - For in connections, port was in network order.
31
32 1.0.5:
33 - Corrected a bug preventing sending to take place. Hm.
34 - Clean now removes package leftovers.
35
36 1.0.4:
37 - Now it supports auto-reconnection.
38 - You can output a custom connections' status using Conn_status_cb hook.
39 - The log function doesn't call gettimeofday for performance reasons.
40 - Conn_dumphex added.
41 - Bandwidth control.
42 - Conn_status outputs more info.
43 - Conn_connect now returns a pointer to the new created connection.
44 - You can set a expiration timer on a connection.
45 - A lot of small functions added.
46 - Corrected a lot of minor bugs.
47
48 1.0.3:
49 - Improve responsivness by limiting amount of data passed to recv/send.
50 - Corrected some bugs in buffer management
51
52 1.0.2:
53 ?
File Conn.c added (mode: 100644) (index 0000000..3101607)
1 /*
2 * Author: Catalin(ux aka Dino) BOIE <catab at umbrella.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.h"
10
11
12 /* Visible variables */
13 void (*Conn_accept_cb)(struct Conn *C) = NULL;
14 void (*Conn_recv_cb)(struct Conn *C) = NULL;
15 void (*Conn_send_cb)(struct Conn *C) = NULL;
16 void (*Conn_data_cb)(struct Conn *C) = NULL;
17 void (*Conn_close_cb)(struct Conn *C) = NULL;
18 void (*Conn_trigger_cb)(struct Conn *C) = NULL;
19 void (*Conn_error_cb)(struct Conn *C) = NULL;
20 void (*Conn_connected_cb)(struct Conn *C) = NULL;
21
22 char *(*Conn_status_slot_html_cb)(struct Conn *C);
23 char *(*Conn_status_cb)(void);
24
25
26 unsigned int Conn_max_reached = 0;
27 unsigned int Conn_default_ibuf = 128;
28 unsigned int Conn_default_obuf = 128;
29 unsigned int Conn_max_ibuf = 4096000;
30 unsigned int Conn_max_obuf = 4096000;
31
32 /* Max bytes enqueued on one send/recv call */
33 unsigned int Conn_max_send = 32 * 1024;
34 unsigned int Conn_max_recv = 32 * 1024;
35
36 unsigned int Conn_no = 0;
37 unsigned int Conn_max = 0;
38 unsigned long Conn_total = 0;
39 unsigned int Conn_start = 0;
40 unsigned int Conn_pending = 0;
41 struct timeval Conn_now;
42 unsigned short Conn_level = 0; /* debug level */
43
44 /* Internal variables */
45 static char Conn_error[512];
46 static struct pollfd *Conn_pfds = NULL;
47 static struct Conn *Conns = NULL;
48 static unsigned int Conn_inited = 0;
49 static unsigned int Conn_accept_is_allowed;
50 static unsigned int Conn_allocated = 0;
51 static unsigned long long Conn_id = 1;
52
53 static FILE *Conn_Log = NULL;
54 static int debug_band = 11;
55
56 /* Functions */
57
58 /*
59 * Difference between two timeval strutures, in milliseconds
60 */
61 long long Conn_time_diff(const struct timeval *t1, const struct timeval *t2)
62 {
63 return (t1->tv_sec - t2->tv_sec) * 1000
64 + (t1->tv_usec - t2->tv_usec) / 1000;
65 }
66
67 char *Conn_strerror(void)
68 {
69 return Conn_error;
70 }
71
72 /* set noblocking */
73 static int Conn_setnonblock(int fd)
74 {
75 int ret;
76 long flags;
77
78 flags = fcntl(fd, F_GETFL, 0);
79 if (flags == -1)
80 return -1;
81
82 flags |= O_NONBLOCK;
83
84 ret = fcntl(fd, F_SETFL, flags);
85
86 return ret;
87 }
88
89 static void Log(unsigned short level, char *format, ...)
90 {
91 va_list ap;
92 FILE *out;
93
94 if (level > Conn_level)
95 return;
96
97 if (Conn_Log == NULL)
98 out = stderr;
99 else
100 out = Conn_Log;
101 fprintf(out, "%ld.%06ld ",
102 Conn_now.tv_sec, Conn_now.tv_usec);
103
104 va_start(ap, format);
105 vfprintf(out, format, ap);
106 va_end(ap);
107 }
108
109 char *Conn_dump(char *buf_src, int len_src)
110 {
111 int i, j;
112 char tmp[3];
113 char *buf_dst;
114 unsigned char c;
115
116 if (len_src < 0)
117 return strdup("[Error: len < 0]");
118
119 Log(30, "\tConn_dump(%p, len=%d)\n",
120 buf_src, len_src);
121
122 buf_dst = malloc(len_src * 4 + 1);
123 if (buf_dst == NULL)
124 return strdup("Memory allocation error1!");
125
126 j = 0;
127 for (i = 0; i < len_src; i++) {
128 c = buf_src[i];
129 if ((c < 32) || (c > 127)) {
130 buf_dst[j++] = '[';
131 snprintf(tmp, sizeof(tmp), "%02x", c);
132 buf_dst[j++] = tmp[0];
133 buf_dst[j++] = tmp[1];
134 buf_dst[j++] = ']';
135 } else {
136 buf_dst[j++] = c;
137 }
138 }
139
140 buf_dst[j] = '\0';
141
142 /*
143 Log(0, "%s ([%s], %d, [%s], %d\n",
144 __FUNCTION__, buf_src, len_src, buf_dst, len_dst);
145 */
146
147 return buf_dst;
148 }
149
150 char *Conn_dumphex(char *buf_src, int len_src)
151 {
152 int i, j;
153 char tmp[3];
154 char *buf_dst;
155 unsigned char c;
156
157 if (len_src < 0)
158 return strdup("[Error: len < 0]");
159
160 Log(30, "\tConn_dumphex(%p, len=%d)\n",
161 buf_src, len_src);
162
163 buf_dst = malloc(len_src * 2 + 1);
164 if (buf_dst == NULL)
165 return strdup("Memory allocation error1!");
166
167 j = 0;
168 for (i = 0; i < len_src; i++) {
169 c = buf_src[i];
170 snprintf(tmp, sizeof(tmp), "%02x", c);
171 buf_dst[j++] = tmp[0];
172 buf_dst[j++] = tmp[1];
173 }
174
175 buf_dst[j] = '\0';
176
177 return buf_dst;
178 }
179
180 void Conn_debug(FILE *f, unsigned short debug)
181 {
182 Conn_Log = f;
183 Conn_level = debug;
184 }
185
186 /* Grow Conn structures */
187 static unsigned int Conn_grow(void)
188 {
189 unsigned int alloc;
190 struct pollfd *p, *set;
191 struct Conn *q, *set2;
192
193 Log(10, "%s() Try to grow from %d to %d.\n",
194 __FUNCTION__,
195 Conn_allocated, Conn_allocated + 128);
196
197 alloc = Conn_allocated + 128;
198
199 p = (struct pollfd *) realloc(Conn_pfds, alloc * sizeof(struct pollfd));
200 if (p == NULL)
201 return 0;
202
203 q = (struct Conn *) realloc(Conns, alloc * sizeof(struct Conn));
204 if (q == NULL) {
205 free(p);
206 return 0;
207 }
208
209 set = p + Conn_allocated;
210 memset(set, 0, 128 * sizeof(struct pollfd));
211 Conn_pfds = p;
212
213 set2 = q + Conn_allocated;
214 memset(set2, 0, 128 * sizeof(struct Conn));
215 Conns = q;
216
217 Conn_allocated = alloc;
218
219 return 1;
220 }
221
222 int Conn_init(unsigned int max)
223 {
224 unsigned int ret;
225
226 if (Conn_inited == 1)
227 return 0;
228
229 Conn_max = max;
230
231 Conn_no = 0;
232 Conn_total = 0;
233 Conn_max_reached = 0;
234 gettimeofday(&Conn_now, NULL);
235 Conn_start = Conn_now.tv_sec;
236 Conn_accept_is_allowed = 1;
237 Conn_allocated = 0;
238
239 snprintf(Conn_error, sizeof(Conn_error), "%s", "");
240
241 ret = Conn_grow();
242 if (ret == 0) {
243 snprintf(Conn_error, sizeof(Conn_error),
244 "Cannot grow anymore. Probably memory shortage.");
245 return -1;
246 }
247
248 Conn_inited = 1;
249
250 return 0;
251 }
252
253 static void Conn_accept_allow(unsigned short val)
254 {
255 unsigned int i;
256
257 if (Conn_accept_is_allowed == val)
258 return;
259
260 Log(10, "%s: Turn accept allow to %d (%s)\n",
261 __FUNCTION__, val, val == 0 ? "off" : "on");
262
263 for (i = 0; i < Conn_no; i++) {
264 if (Conns[i].type != Conn_type_MASTER)
265 continue;
266
267 if (val == 0)
268 Conn_pfds[i].events &= ~POLLIN;
269 else
270 Conn_pfds[i].events |= POLLIN;
271 }
272
273 Conn_accept_is_allowed = val;
274 }
275
276 /* Alloc a Conn structure */
277 static struct Conn *Conn_alloc(void)
278 {
279 unsigned int slot, growok;
280 void *p;
281
282 Log(10, "%s() Conn_no=%d Conn_max=%d\n",
283 __FUNCTION__,
284 Conn_no, Conn_max);
285
286 if ((Conn_max > 0) && (Conn_no >= Conn_max)) {
287 snprintf(Conn_error, sizeof(Conn_error),
288 "Limit reached! Consider a raise of max connection number or put 0 for no limit.");
289 return NULL;
290 }
291
292 if (Conn_allocated == Conn_no) {
293 growok = Conn_grow();
294 if (growok == 0) {
295 snprintf(Conn_error, sizeof(Conn_error),
296 "Cannot grow anymore. Probably memory shortage.");
297 return NULL;
298 }
299 }
300
301 if (Conn_no > Conn_max_reached)
302 Conn_max_reached = Conn_no;
303
304 slot = Conn_no;
305
306 Conns[slot].type = Conn_type_UNK;
307 Conns[slot].state = CONN_STATE_FREE;
308 Conns[slot].slot = slot;
309
310 if (Conns[slot].ibuf_size < Conn_default_ibuf) {
311 p = realloc(Conns[slot].ibuf, Conn_default_ibuf);
312 if (p == NULL) {
313 snprintf(Conn_error, sizeof(Conn_error),
314 "Memory allocation error2!");
315 return NULL;
316 }
317 Conns[slot].ibuf = p;
318 Conns[slot].ibuf_size = Conn_default_ibuf;
319 }
320 Conns[slot].ibuf_head = 0;
321 Conns[slot].ibuf_tail = 0;
322
323 if (Conns[slot].obuf_size < Conn_default_obuf) {
324 p = realloc(Conns[slot].obuf, Conn_default_obuf);
325 if (p == NULL) {
326 snprintf(Conn_error, sizeof(Conn_error),
327 "Memory allocation error3!");
328 return NULL;
329 }
330 Conns[slot].obuf = p;
331 Conns[slot].obuf_size = Conn_default_obuf;
332 }
333 Conns[slot].obuf_head = 0;
334 Conns[slot].obuf_tail = 0;
335
336 Conns[slot].trecv = Conn_now;
337
338 Conns[slot].bi = 0;
339 Conns[slot].bo = 0;
340 Conns[slot].private = NULL;
341
342 /* bandwidth */
343 Conns[slot].band_width = 0;
344 Conns[slot].band_factor = 0;
345 Conns[slot].band_tokens = 0;
346 Conns[slot].band_lasttime = Conn_now;
347
348 Conn_pfds[slot].fd = -1;
349 Conn_pfds[slot].events = 0;
350 Conn_pfds[slot].revents = 0;
351 Conns[slot].state = CONN_STATE_EMPTY;
352
353 Conns[slot].flags = 0;
354
355 Conn_no++;
356
357 Log(10, "\tFound free slot %u. Now Conn_no=%d\n",
358 slot, Conn_no);
359
360 if (Conn_no == Conn_max)
361 Conn_accept_allow(0);
362
363 return &Conns[slot];
364 }
365
366 /*
367 * If put buffer is empty, just mark for closing.
368 * If we have data, set the flag to do the closing after send.
369 */
370 void Conn_close(struct Conn *C)
371 {
372 if (C->obuf_head == C->obuf_tail)
373 C->error_state = CONN_ERROR_USERREQ;
374 else
375 C->flags |= CONN_FLAGS_CLOSE_AFTER_SEND;
376 }
377
378 /*
379 * Returns string representation of errno code
380 */
381 static char *Conn_errno(struct Conn *C)
382 {
383 static char buf[256];
384 char *is;
385
386 switch (C->error_state) {
387 case CONN_ERROR_USERREQ: is = "user"; break;
388 case CONN_ERROR_POLL: is = "poll"; break;
389 case CONN_ERROR_RECV: is = "recv"; break;
390 case CONN_ERROR_SEND: is = "send"; break;
391 case CONN_ERROR_SOCKET: is = "socket"; break;
392 case CONN_ERROR_HANGUP: is = "hangup"; break;
393 case CONN_ERROR_GETADDRINFO: is = "lookup error"; break;
394 case CONN_ERROR_EXPIRED: is = "expired"; break;
395 case CONN_ERROR_ACCEPT: is = "accept"; break;
396 case CONN_ERROR_MEM: is = "allocation failed"; break;
397 case CONN_ERROR_CONNECT: is = "connect"; break;
398 case CONN_ERROR_READ_TIMEOUT: is = "read timeout"; break;
399 case CONN_ERROR_CONN_TIMEOUT: is = "conn timeout"; break;
400
401 default: is = "?";
402 }
403
404 snprintf(buf, sizeof(buf), "%s (%s)",
405 is, strerror(C->xerrno));
406
407 return buf;
408 }
409
410 static char *Conn_state(struct Conn *C)
411 {
412 switch (C->state) {
413 case CONN_STATE_FREE: return "FREE";
414 case CONN_STATE_EMPTY: return "EMPTY";
415 case CONN_STATE_OPEN: return "OPEN";
416 case CONN_STATE_LISTEN: return "LISTEN";
417 case CONN_STATE_CONNECT_0: return "CONN0";
418 case CONN_STATE_CONNECT_a: return "CONNa";
419 case CONN_STATE_CONNECT_b: return "CONNb";
420
421 default: return "BUG?";
422 }
423 }
424
425 static void Conn_free_intern(struct Conn *C)
426 {
427 unsigned int slot;
428
429 slot = C->slot;
430
431 Log(7, "Cleaning-up slot in %s state id %llu [%s]...\n",
432 Conn_state(C), C->id, Conn_errno(C));
433
434 snprintf(Conn_error, sizeof(Conn_error),
435 "%s", Conn_errno(C));
436
437 if (C->error_state != CONN_ERROR_USERREQ) {
438 if (Conns[slot].cb_error)
439 Conns[slot].cb_error(C);
440 else if (Conn_error_cb)
441 Conn_error_cb(C);
442 }
443
444 if (Conns[slot].state == CONN_STATE_OPEN) {
445 if (Conns[slot].cb_close)
446 Conns[slot].cb_close(C);
447 else if (Conn_close_cb)
448 Conn_close_cb(&Conns[slot]);
449 }
450
451 if (Conn_pfds[slot].fd > -1) {
452 close(Conn_pfds[slot].fd);
453 Conn_pfds[slot].fd = -1;
454 }
455
456 /* Reset tsend, else we enter in a timeout error loop */
457 Conns[slot].tsend.tv_sec = 0;
458 Conns[slot].tsend.tv_usec = 0;
459
460 Conn_pfds[slot].events = 0;
461 Conn_pfds[slot].revents = 0;
462
463 /* Reset the connection attempt time */
464 Conns[slot].conn_syn.tv_sec = 0;
465 Conns[slot].conn_syn.tv_usec = 0;
466
467 if (Conns[slot].flags & CONN_FLAGS_AUTO_RECONNECT) {
468 Conns[slot].tryat = Conn_now.tv_sec + Conns[slot].delay;
469 Conns[slot].error_state = 0;
470 Conns[slot].state = CONN_STATE_CONNECT_0;
471
472 Conns[slot].ibuf_head = 0;
473 Conns[slot].ibuf_tail = 0;
474
475 Conns[slot].obuf_head = 0;
476 Conns[slot].obuf_tail = 0;
477
478 Conn_pending++;
479 } else {
480 Conns[slot].type = Conn_type_UNK;
481 Conns[slot].state = CONN_STATE_FREE;
482
483 if (slot < Conn_no - 1) {
484 Log(10, "Move last pfd/Conn entry %d -> %d...\n",
485 Conn_no - 1, slot);
486
487 /* free old mem */
488 if (Conns[slot].ibuf)
489 free(Conns[slot].ibuf);
490 if (Conns[slot].obuf)
491 free(Conns[slot].obuf);
492
493 Conn_pfds[slot] = Conn_pfds[Conn_no - 1];
494 Conns[slot] = Conns[Conn_no - 1];
495 Conns[slot].slot = slot;
496
497 /* fix */
498 Conns[Conn_no - 1].ibuf = NULL;
499 Conns[Conn_no - 1].ibuf_size = 0;
500 Conns[Conn_no - 1].obuf = NULL;
501 Conns[Conn_no - 1].obuf_size = 0;
502 }
503
504 Conn_no--;
505
506 Conn_accept_allow(1);
507 }
508 }
509
510 /*
511 * Expand the requested buffer
512 * what = 0 for out buffer, what = 1 for input buffer
513 * returns 0 if OK, -1 on error
514 */
515 int Conn_try_expand_buf(struct Conn *C, int what, int needed)
516 {
517 char *p;
518 unsigned int hm;
519 unsigned int slot, old_size, amount, head, tail;
520
521 slot = C->slot;
522
523 if (what == 0) {
524 head = C->obuf_head;
525 tail = C->obuf_tail;
526 } else {
527 head = C->ibuf_head;
528 tail = C->ibuf_tail;
529 }
530
531 Log(10, "\tTry to expand buffer on slot %u for [%s] needed=%d head=%u tail=%u.\n",
532 slot, what == 0 ? "o" : "i", needed,
533 head, tail);
534
535 amount = needed;
536
537 if (what == 0) {
538 if (amount < Conn_default_obuf)
539 amount = Conn_default_obuf;
540 old_size = Conns[slot].obuf_size;
541 hm = Conns[slot].obuf_size + amount;
542 if (hm > Conn_max_obuf)
543 hm = Conn_max_obuf;
544 p = realloc(Conns[slot].obuf, hm);
545 if (p == NULL) {
546 Log(3, "Cannot realloc obuf!\n");
547 return -1;
548 }
549 Conns[slot].obuf = p;
550 Conns[slot].obuf_size = hm;
551 Log(10, "\tSucces. Old/new size = %u/%u.\n",
552 old_size, Conns[slot].obuf_size);
553 } else {
554 if (amount < Conn_default_ibuf)
555 amount = Conn_default_ibuf;
556 old_size = Conns[slot].ibuf_size;
557 hm = Conns[slot].ibuf_size + amount;
558 if (hm > Conn_max_ibuf)
559 hm = Conn_max_ibuf;
560 p = realloc(Conns[slot].ibuf, hm);
561 if (p == NULL) {
562 Log(3, "Cannot realloc ibuf!\n");
563 return -1;
564 }
565 Conns[slot].ibuf = p;
566 Conns[slot].ibuf_size = hm;
567 Log(10, "\tSucces. Old/new size = %u/%u.\n",
568 old_size, Conns[slot].ibuf_size);
569 }
570
571 return 0;
572 }
573
574 int Conn_enqueue(struct Conn *C, void *buf, size_t count)
575 {
576 unsigned int slot, r;
577 char *dump;
578
579 if (C == NULL) {
580 Log(0, "ERROR: Somebody try to enqueue something to a NULL conn.\n");
581 return -1;
582 }
583
584 if (Conn_level >= 10) {
585 dump = Conn_dump(buf, count);
586 Log(0, "\tTry to enqueue %d bytes to id %llu [%s]...\n",
587 count, C->id, dump);
588 free(dump);
589 }
590
591 /* we cannot use pointers directly because they can change under us */
592 slot = C->slot;
593
594 if (Conns[slot].obuf_size - Conns[slot].obuf_tail < count) {
595 r = Conn_try_expand_buf(&Conns[slot], 0, count);
596 if (r != 0)
597 return -1;
598 }
599
600 memcpy(Conns[slot].obuf + Conns[slot].obuf_tail, buf, count);
601 Conns[slot].obuf_tail += count;
602
603 Conn_pfds[slot].events |= POLLOUT;
604
605 return 0;
606 }
607
608 struct Conn *Conn_socket(int domain, int type, int port)
609 {
610 struct Conn *C;
611 int i, ret;
612 struct sockaddr *psa = NULL;
613 struct sockaddr_in sa;
614 struct sockaddr_in6 sa6;
615 int sock_len = 0;
616 char *addr = "?";
617 unsigned int slot;
618 int do_bind = 1, do_listen = 1;
619 int protocol = 0;
620 int first_state;
621
622 switch (domain) {
623 case PF_INET:
624 memset(&sa, 0, sizeof(sa));
625 sa.sin_family = AF_INET;
626 sa.sin_addr.s_addr = htonl(INADDR_ANY);
627 sa.sin_port = htons(port);
628 psa = (struct sockaddr *) &sa;
629 sock_len = sizeof(sa);
630 addr = "0.0.0.0";
631 if (type == SOCK_STREAM) {
632 first_state = CONN_STATE_LISTEN;
633 } else if (type == SOCK_DGRAM) {
634 do_listen = 0;
635 first_state = CONN_STATE_OPEN;
636 }
637 break;
638
639 case PF_INET6:
640 memset(&sa6, 0, sizeof(sa6));
641 sa6.sin6_family = AF_INET6;
642 ret = inet_pton(AF_INET6, "::", &sa6.sin6_addr);
643 if (ret < 0) {
644 snprintf(Conn_error, sizeof(Conn_error),
645 "inet_pton(::) failed");
646 return NULL;
647 }
648 sa6.sin6_port = htons(port);
649 psa = (struct sockaddr *) &sa6;
650 sock_len = sizeof(sa6);
651 addr = "::";
652 if (type == SOCK_STREAM) {
653 first_state = CONN_STATE_LISTEN;
654 } else if (type == SOCK_DGRAM) {
655 do_listen = 0;
656 first_state = CONN_STATE_OPEN;
657 }
658 break;
659
660 case PF_PACKET:
661 do_bind = 0;
662 protocol = htons(port);
663 first_state = CONN_STATE_OPEN;
664 break;
665
666 default:
667 snprintf(Conn_error, sizeof(Conn_error),
668 "Invalid domain [%d]!", domain);
669 return NULL;
670 }
671
672 C = Conn_alloc();
673 if (!C)
674 return NULL;
675
676 slot = C->slot;
677
678 Conn_pfds[slot].fd = socket(domain, type, protocol);
679 if (Conn_pfds[slot].fd == -1) {
680 snprintf(Conn_error, sizeof(Conn_error),
681 "Cannot create socket (%d, %d, %d) [%s]",
682 domain, type, protocol, strerror(errno));
683 Conns[slot].xerrno = errno;
684 goto out;
685 }
686 Conn_pfds[slot].events = POLLIN;
687
688 Conn_setnonblock(Conn_pfds[slot].fd);
689
690 if (domain == PF_INET6) {
691 #ifndef IPV6_V6ONLY
692 #define IPV6_V6ONLY 26
693 #endif
694 i = 1;
695 setsockopt(Conn_pfds[slot].fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&i, sizeof(i));
696 }
697
698 /* Default, client */
699 C->type = Conn_type_CLIENT;
700
701 if (do_bind == 1) {
702 i = 1;
703 setsockopt(Conn_pfds[slot].fd, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i));
704
705 ret = bind(Conn_pfds[slot].fd, psa, sock_len);
706 if (ret < 0) {
707 snprintf(Conn_error, sizeof(Conn_error),
708 "Cannot bind [%s]", strerror(errno));
709 Conns[slot].xerrno = errno;
710 goto out;
711 }
712
713 if (do_listen == 1) {
714 listen(Conn_pfds[slot].fd, 128);
715 C->type = Conn_type_MASTER;
716 }
717 }
718
719 C->state = first_state;
720
721 C->start = Conn_now.tv_sec;
722
723 /* Reset syn time */
724 C->conn_syn.tv_sec = 0;
725 C->conn_syn.tv_usec = 0;
726
727 C->id = Conn_id++;
728
729 snprintf(Conns[slot].addr, sizeof(Conns[slot].addr), "%s", addr);
730 Conns[slot].port = port;
731
732 Conns[slot].sock_domain = domain;
733 Conns[slot].sock_type = type;
734
735 return &Conns[slot];
736
737 out:
738 Conns[slot].error_state = CONN_ERROR_SOCKET;
739 Conn_free_intern(&Conns[slot]);
740
741 return NULL;
742 }
743
744 void Conn_new(struct Conn *C)
745 {
746 }
747
748 void Conn_accept(struct Conn *C)
749 {
750 int fd;
751 struct sockaddr *pca;
752 struct sockaddr_in ca4;
753 struct sockaddr_in6 ca6;
754 socklen_t cax_len;
755 struct Conn *X;
756 unsigned int slot, Xslot;
757
758 slot = C->slot;
759 switch(Conns[slot].sock_domain) {
760 case PF_INET:
761 pca = (struct sockaddr *) &ca4;
762 cax_len = sizeof(ca4);
763 break;
764
765 case PF_INET6:
766 pca = (struct sockaddr *) &ca6;
767 cax_len = sizeof(ca6);
768 break;
769
770 default:
771 snprintf(Conn_error, sizeof(Conn_error),
772 "Cannot deal with domain %d.",
773 Conns[slot].sock_domain);
774 Conns[slot].error_state = CONN_ERROR_SOCKET;
775 if (Conns[slot].cb_error)
776 Conns[slot].cb_error(&Conns[slot]);
777 else if (Conn_error_cb)
778 Conn_error_cb(&Conns[slot]);
779 return;
780 }
781
782 fd = accept(Conn_pfds[slot].fd, pca, &cax_len);
783 if (fd == -1) {
784 if (errno == EAGAIN)
785 return;
786
787 snprintf(Conn_error, sizeof(Conn_error),
788 "Cannot accept: %s",
789 strerror(errno));
790 Conns[slot].error_state = CONN_ERROR_ACCEPT;
791 if (Conns[slot].cb_error)
792 Conns[slot].cb_error(&Conns[slot]);
793 else if (Conn_error_cb)
794 Conn_error_cb(&Conns[slot]);
795 return;
796 }
797
798 X = Conn_alloc();
799 if (!X) {
800 Log(0, "ERROR: Cannot alloc a slot!\n");
801 Conns[slot].error_state = CONN_ERROR_MEM;
802 if (Conns[slot].cb_error)
803 Conns[slot].cb_error(&Conns[slot]);
804 else if (Conn_error_cb)
805 Conn_error_cb(&Conns[slot]);
806 close(fd);
807 return;
808 }
809
810 Xslot = X->slot;
811
812 switch (Conns[slot].sock_domain) {
813 case PF_INET:
814 inet_ntop(Conns[slot].sock_domain, &ca4.sin_addr, Conns[Xslot].addr, sizeof(Conns[Xslot].addr));
815 Conns[Xslot].port = ntohs(ca4.sin_port);
816 break;
817
818 case PF_INET6:
819 inet_ntop(Conns[slot].sock_domain, &ca6.sin6_addr, Conns[Xslot].addr, sizeof(Conns[Xslot].addr));
820 Conns[Xslot].port = ntohs(ca6.sin6_port);
821 break;
822 }
823
824 Conns[Xslot].type = Conn_type_CLIENT;
825 Conns[Xslot].error_state = 0;
826 Conns[Xslot].state = CONN_STATE_OPEN;
827 Conns[Xslot].via = Conns[slot].port;
828 Conn_pfds[Xslot].fd = fd;
829 Conn_pfds[Xslot].events = POLLIN;
830 Conns[Xslot].sock_domain = Conns[slot].sock_domain;
831 Conns[Xslot].sock_type = Conns[slot].sock_type;
832 Conns[Xslot].start = Conn_now.tv_sec;
833 Conns[Xslot].id = Conn_id++;
834
835 Conn_setnonblock(Conn_pfds[Xslot].fd);
836
837 if (Conns[slot].cb_accept)
838 Conns[slot].cb_accept(&Conns[slot]);
839 else if (Conn_accept_cb != NULL)
840 Conn_accept_cb(&Conns[Xslot]);
841
842 Conn_total++;
843 }
844
845 static void Conn_poll_status(short ev, char *ret)
846 {
847 strcpy(ret, "________");
848
849 if (ev & POLLIN) ret[0] = 'I';
850 if (ev & POLLPRI) ret[1] = 'P';
851 if (ev & POLLOUT) ret[2] = 'O';
852 if (ev & POLLERR) ret[3] = 'E';
853 if (ev & POLLHUP) ret[4] = 'H';
854 if (ev & POLLNVAL) ret[5] = 'V';
855 if (ev & POLLRDNORM) ret[6] = 'r';
856 if (ev & POLLRDBAND) ret[7] = 'R';
857 }
858
859 static char *Conn_domain(struct Conn *C)
860 {
861 switch (C->sock_domain) {
862 case PF_INET: return "IPv4";
863 case PF_INET6: return "IPv6";
864 case PF_PACKET: return "PACKET";
865
866 default: return "?";
867 }
868 }
869
870 static char *Conn_type(struct Conn *C)
871 {
872 switch (C->sock_type) {
873 case SOCK_STREAM: return "stream";
874 case SOCK_DGRAM: return "dgram";
875 case SOCK_RAW: return "raw";
876
877 default: return "?";
878 }
879 }
880
881 static char *Conn_socktype(struct Conn *C)
882 {
883 switch (C->type) {
884 case Conn_type_MASTER: return "master";
885 case Conn_type_CLIENT: return "client";
886 case Conn_type_UNK: return "unk";
887
888 default:
889 return "?";
890 }
891 }
892
893 /*
894 * Returns a nice speed
895 */
896 void Conn_speed(char *dst, unsigned int dst_len, unsigned int speed)
897 {
898 float sp;
899
900 sp = speed;
901
902 if (speed < 1000)
903 snprintf(dst, dst_len, "%.2fBps", sp);
904 else if (speed < 1000 * 1000)
905 snprintf(dst, dst_len, "%.2fKBps", sp / 1000);
906 else
907 snprintf(dst, dst_len, "%.2fMBps", sp / 1000 / 1000);
908 }
909
910 char *Conn_status_slot(struct Conn *C)
911 {
912 static char tmp[1024];
913 char polle[16], pollr[16];
914 char speedi[32], speedo[32];
915 unsigned int dT, si, so;
916
917 Conn_poll_status(Conn_pfds[C->slot].events, polle);
918 Conn_poll_status(Conn_pfds[C->slot].revents, pollr);
919
920 dT = Conn_now.tv_sec - C->start;
921 if (dT == 0)
922 dT = 1;
923 si = C->bi / dT;
924 so = C->bo / dT;
925
926 Conn_speed(speedi, sizeof(speedi), si);
927 Conn_speed(speedo, sizeof(speedo), so);
928
929 snprintf(tmp, sizeof(tmp), "%4d fd%4d"
930 " %4s %6s %5s %6s"
931 " %39s/%-5d\n"
932 " Via%-5d [%s][%s] IO=%llu/%llu"
933 " BS=%u/%u S=%s/%s"
934 " T=%ld bw=%u f=%u tk=%u id=%llu\n",
935 C->slot, Conn_pfds[C->slot].fd,
936 Conn_domain(C), Conn_type(C), Conn_socktype(C), Conn_state(C),
937 C->addr, C->port, C->via, polle, pollr, C->bi, C->bo,
938 C->ibuf_size, C->obuf_size, speedi, speedo,
939 Conn_now.tv_sec - C->start,
940 C->band_width, C->band_factor, C->band_tokens,
941 C->id);
942
943 return tmp;
944 }
945
946 char *Conn_status_slot_html(struct Conn *C)
947 {
948 static char tmp[1024];
949 char polle[16], pollr[16], *ext = "";
950 char speedi[32], speedo[32];
951 unsigned int dT, si, so;
952
953 Conn_poll_status(Conn_pfds[C->slot].events, polle);
954 Conn_poll_status(Conn_pfds[C->slot].revents, pollr);
955
956 dT = Conn_now.tv_sec - C->start;
957 if (dT == 0)
958 dT = 1;
959 si = C->bi / dT;
960 so = C->bo / dT;
961
962 Conn_speed(speedi, sizeof(speedi), si);
963 Conn_speed(speedo, sizeof(speedo), so);
964
965 if (Conn_status_slot_html_cb)
966 ext = Conn_status_slot_html_cb(C);
967
968 snprintf(tmp, sizeof(tmp), "<td>%llu</td><td>%d</td><td>%d</td>"
969 "<td>%s</td><td>%s</td><td>%s</td><td>%s</td>"
970 "<td>%s/%d</td>"
971 "<td>%d</td><td>%s</td><td>%s</td><td>%llu / %llu</td>"
972 "<td>%u / %u</td><td>%s / %s</td><td>%ld</td>"
973 "<td>%u</td><td>%u</td><td>%u</td>"
974 "%s\n",
975 C->id, C->slot, Conn_pfds[C->slot].fd,
976 Conn_domain(C), Conn_type(C), Conn_socktype(C), Conn_state(C),
977 C->addr, C->port, C->via, polle, pollr, C->bi, C->bo,
978 C->ibuf_size, C->obuf_size,
979 speedi, speedo, Conn_now.tv_sec - C->start,
980 C->band_width, C->band_factor, C->band_tokens,
981 ext);
982
983 return tmp;
984 }
985
986 /* flags: bit 1 = 1 - html */
987 char *Conn_status(unsigned int flags)
988 {
989 unsigned int len = 0, i, max;
990 struct Conn *C;
991 char tmp[512], tmp_len;
992 char polle[16], pollr[16];
993 char *buf, *slot, *ext = "";
994 char speedi[32], speedo[32];
995 unsigned long long bi, bo, dT;
996
997 max = (Conn_no + 1) * 512 - 1;
998 buf = malloc(max + 1);
999 if (!buf)
1000 return strdup("No enough memory!");
1001
1002 strcpy(buf, "");
1003
1004 gettimeofday(&Conn_now, NULL);
1005 /* TODO: "len += " is incorrect */
1006 tmp_len = snprintf(tmp, sizeof(tmp), "Conn_pending=%d Conn_no/Conn_max=%d/%d Conn_total=%lu Conn_uptime=%lus Conn_allocated=%d\n",
1007 Conn_pending, Conn_no, Conn_max, Conn_total, Conn_now.tv_sec - Conn_start, Conn_allocated);
1008 if (len + tmp_len < max) {
1009 strcat(buf, tmp);
1010 len += tmp_len;
1011 }
1012
1013 if (flags & 1)
1014 if (Conn_status_cb)
1015 ext = Conn_status_cb();
1016
1017 if (flags & 1) {
1018 strcat(buf, "<table border=\"0\" cellspacing=\"1\" cellpadding=\"3\" bgcolor=\"#aaaaaa\">\n");
1019 strcat(buf, "<tr bgcolor=\"ffffff\">\n");
1020 strcat(buf, "<td>ID</td>");
1021 strcat(buf, "<td>Slot</td>");
1022 strcat(buf, "<td>FD</td>");
1023 strcat(buf, "<td>Dom</td>");
1024 strcat(buf, "<td>Type</td>");
1025 strcat(buf, "<td>SType</td>");
1026 strcat(buf, "<td>State</td>");
1027 strcat(buf, "<td>Addr/port</td>");
1028 strcat(buf, "<td>Via</td>");
1029 strcat(buf, "<td>Polle</td>");
1030 strcat(buf, "<td>Pollr</td>");
1031 strcat(buf, "<td>BI/BO</td>");
1032 strcat(buf, "<td>BUF I/O</td>");
1033 strcat(buf, "<td>Speed I/O</td>");
1034 strcat(buf, "<td>Elap (s)</td>");
1035 strcat(buf, "<td>Band</td>");
1036 strcat(buf, "<td>F</td>");
1037 strcat(buf, "<td>Tks</td>");
1038 strcat(buf, ext);
1039 strcat(buf, "</tr>\n");
1040 } else {
1041 strcat(buf, ext);
1042 }
1043
1044 bi = 0; bo = 0; dT = 0;
1045 for (i = 0; i < Conn_no; i++) {
1046 C = &Conns[i];
1047 if (C->state == CONN_STATE_FREE)
1048 continue;
1049
1050 if (C->type == Conn_type_CLIENT) {
1051 bi += C->bi;
1052 bo += C->bo;
1053 dT += Conn_now.tv_sec - C->start;
1054 }
1055
1056 if (flags & 1)
1057 strcat(buf, "<tr bgcolor=\"ffffff\">\n");
1058
1059 Conn_poll_status(Conn_pfds[C->slot].events, polle);
1060 Conn_poll_status(Conn_pfds[C->slot].revents, pollr);
1061
1062 if ((flags & 1) == 0)
1063 slot = Conn_status_slot(C);
1064 else
1065 slot = Conn_status_slot_html(C);
1066 len += snprintf(tmp, sizeof(tmp), "%s", slot);
1067 if (len < max)
1068 strcat(buf, tmp);
1069
1070 if (flags & 1)
1071 strcat(buf, "</tr>\n");
1072 }
1073
1074 if (flags & 1)
1075 strcat(buf, "</table>\n");
1076
1077 if (dT == 0)
1078 dT = 1;
1079
1080 Conn_speed(speedi, sizeof(speedi), bi / dT);
1081 Conn_speed(speedo, sizeof(speedo), bo / dT);
1082
1083 tmp_len = snprintf(tmp, sizeof(tmp), "Total speed I/O: %s / %s."
1084 " Total bytes I/O: %llu / %llu\n",
1085 speedi, speedo, bi, bo);
1086 if (len + tmp_len < max) {
1087 strcat(buf, tmp);
1088 len += tmp_len;
1089 }
1090
1091 return buf;
1092 }
1093
1094 /*
1095 * Returns the number of bytes in 'in' buffer
1096 */
1097 unsigned int Conn_qlen(struct Conn *C)
1098 {
1099 return C->ibuf_tail - C->ibuf_head;
1100 }
1101
1102 /*
1103 * Eat @bytes from head of input buffer
1104 */
1105 void Conn_eat(struct Conn *C, unsigned int bytes)
1106 {
1107 unsigned int slot;
1108
1109 slot = C->slot;
1110
1111 /* advance head */
1112 Conns[slot].ibuf_head += bytes;
1113 if (Conns[slot].ibuf_head >= Conns[slot].ibuf_tail) {
1114 Conns[slot].ibuf_head = 0;
1115 Conns[slot].ibuf_tail = 0;
1116 }
1117
1118 Log(10, "Conn_eat(C, %u) head=%u tail=%u qlen=%u\n",
1119 bytes, C->ibuf_head, C->ibuf_tail,
1120 Conn_qlen(C));
1121 }
1122
1123 /*
1124 * Eat all input buffer
1125 */
1126 void Conn_eatall(struct Conn *C)
1127 {
1128 Conn_eat(C, Conn_qlen(C));
1129 }
1130
1131 /*
1132 * Add tokens to connection
1133 */
1134 void Conn_band_update(struct Conn *C)
1135 {
1136 unsigned int slot;
1137 long diff;
1138
1139 /* no need */
1140 if (C->band_width == 0)
1141 return;
1142
1143 diff = (Conn_now.tv_sec - C->band_lasttime.tv_sec) * 1000000;
1144 diff += Conn_now.tv_usec - C->band_lasttime.tv_usec;
1145 diff /= 100000;
1146
1147 /* already added in this hundred of milisecond? */
1148 if (diff == 0)
1149 return;
1150
1151 /* take care of time skew */
1152 if (diff < 0)
1153 diff = 1;
1154
1155 C->band_lasttime = Conn_now;
1156 C->band_tokens += diff * C->band_width / 10;
1157 if (C->band_tokens > C->band_factor * C->band_width)
1158 C->band_tokens = C->band_factor * C->band_width;
1159
1160 slot = C->slot;
1161 Conn_pfds[slot].events |= POLLOUT;
1162
1163 Log(debug_band, "\t\tBAND: Added tokens -> %u.\n",
1164 C->band_tokens);
1165 }
1166
1167 /*
1168 * Set the bandwidth for a connection
1169 * width is in 1b increments
1170 */
1171 int Conn_band(struct Conn *C, unsigned int width, unsigned int factor)
1172 {
1173 Log(11, "\tConn_band(C, width=%u, factor=%u)\n",
1174 width, factor);
1175
1176 C->band_lasttime = Conn_now;
1177 C->band_width = width;
1178 C->band_factor = factor;
1179 C->band_tokens = factor * width;
1180
1181 Log(debug_band, "\t\tBAND: lasttime=%d.%06d, width=%u, factor=%u, tokens=%u\n",
1182 C->band_lasttime.tv_sec, C->band_lasttime.tv_usec,
1183 C->band_width, C->band_factor, C->band_tokens);
1184
1185 return 0;
1186 }
1187
1188 static void Conn_send_cb_i(struct Conn *C)
1189 {
1190 ssize_t n;
1191 unsigned int max;
1192 int count;
1193 unsigned int slot;
1194 char *buf;
1195 int xerrno;
1196 char *dump;
1197
1198 Log(10, "Conn_send_cb_i id=%llu, slot=%u...\n",
1199 C->id, C->slot);
1200
1201 slot = C->slot;
1202
1203 buf = Conns[slot].obuf + Conns[slot].obuf_head;
1204 count = Conns[slot].obuf_tail - Conns[slot].obuf_head;
1205 if (count == 0) {
1206 Log(13, "\tConn_send_cb_i: Empty buffer! Strange!\n");
1207 return;
1208 }
1209
1210 max = count;
1211 if ((Conn_max_send > 0) && (max > Conn_max_send))
1212 max = Conn_max_send;
1213
1214 /* bandwidth */
1215 if (Conns[slot].band_width > 0) {
1216 if (max > Conns[slot].band_tokens)
1217 max = Conns[slot].band_tokens;
1218 if (max == 0) {
1219 Log(debug_band, "\tBAND: Suspend 100ms the C (no tokens)!\n");
1220 Conn_pfds[slot].events &= ~POLLOUT;
1221 return;
1222 }
1223 }
1224
1225 again:
1226 Log(10, "\tsend(fd%d, buf=%p (head=%u), max=%d (count=%d), 0)...\n",
1227 Conn_pfds[slot].fd, buf, Conns[slot].obuf_head, max, count);
1228 n = send(Conn_pfds[slot].fd, buf, max, 0);
1229 xerrno = errno;
1230 if ((n == -1) && (errno == EINTR))
1231 goto again;
1232
1233 if ((n == -1) && (errno == EAGAIN))
1234 return;
1235
1236 Log(10, "%s: Slot %u: FD%d Sent %d bytes [head=%d tail=%d]\n",
1237 __FUNCTION__, slot, Conn_pfds[slot].fd,
1238 n, Conns[slot].obuf_head, Conns[slot].obuf_tail);
1239 if (Conn_level >= 10) {
1240 dump = Conn_dump(buf, n);
1241 Log(0, "\t%s\n", dump);
1242 free(dump);
1243 }
1244
1245 if (n > 0) {
1246 Conns[slot].tsend = Conn_now;
1247 if (n < count) {
1248 Conns[slot].obuf_head += n;
1249 } else {
1250 Conns[slot].obuf_head = 0;
1251 Conns[slot].obuf_tail = 0;
1252 }
1253
1254 Conns[slot].bo += n;
1255 if (C->band_width > 0) {
1256 Conns[slot].band_tokens -= n;
1257 Log(debug_band, "\t%s: BAND: Remove %d tokens -> %u...\n",
1258 __FUNCTION__,
1259 n, Conns[slot].band_tokens);
1260 }
1261 } else {
1262 Log(0, "%s: Error in send [id %llu] [slot %u] [%s]\n",
1263 __FUNCTION__,
1264 Conns[slot].id, slot, strerror(errno));
1265 Conns[slot].error_state = CONN_ERROR_SEND;
1266 Conns[slot].xerrno = xerrno;
1267 }
1268 }
1269
1270 static void Conn_recv_cb_i(struct Conn *C)
1271 {
1272 ssize_t n;
1273 unsigned int max;
1274 unsigned int slot;
1275 int r, xerrno;
1276 char *dump;
1277
1278 Log(10, "Conn_recv_cb_i id=%llu, slot=%u...\n",
1279 C->id, C->slot);
1280
1281 slot = C->slot;
1282
1283 if (Conns[slot].ibuf_tail == Conns[slot].ibuf_size) {
1284 r = Conn_try_expand_buf(&Conns[slot], 1, 0);
1285 if (r != 0) {
1286 Log(1, "MEM: Cannot expand ibuf!\n");
1287 return;
1288 }
1289 }
1290
1291 max = Conns[slot].ibuf_size - Conns[slot].ibuf_tail;
1292 if ((Conn_max_recv > 0) && (max > Conn_max_recv))
1293 max = Conn_max_recv;
1294
1295 while (1) {
1296 n = recv(Conn_pfds[slot].fd, Conns[slot].ibuf + Conns[slot].ibuf_tail, max, 0);
1297 if ((n == -1) && (errno == EINTR))
1298 continue;
1299
1300 xerrno = errno;
1301
1302 break;
1303 }
1304
1305 Log(10, "%s: Slot %u: FD%d Received %d bytes.\n",
1306 __FUNCTION__, slot, Conn_pfds[slot].fd, n);
1307
1308 if (n > 0) {
1309 if (Conn_level >= 10) {
1310 dump = Conn_dump(Conns[slot].ibuf
1311 + Conns[slot].ibuf_tail, n);
1312 Log(0, "\t%s\n", dump);
1313 free(dump);
1314 }
1315
1316 Conns[slot].ibuf_tail += n;
1317
1318 Conns[slot].bi += n;
1319 Conns[slot].trecv = Conn_now;
1320
1321 if (Conns[slot].cb_data)
1322 Conns[slot].cb_data(&Conns[slot]);
1323 else if (Conn_data_cb)
1324 Conn_data_cb(&Conns[slot]);
1325 } else if (n == 0) {
1326 Conns[slot].error_state = CONN_ERROR_HANGUP;
1327 } else {
1328 Log(4, "Error in recv id %llu slot %u [%s]\n",
1329 Conns[slot].id, slot, strerror(errno));
1330 Conns[slot].error_state = CONN_ERROR_RECV;
1331 Conns[slot].xerrno = xerrno;
1332 }
1333 }
1334
1335 /*
1336 * Set some internal parameters
1337 */
1338 void Conn_set(struct Conn *C, int var, unsigned int val)
1339 {
1340 unsigned int slot;
1341 int fd;
1342
1343 slot = C->slot;
1344 fd = Conn_pfds[slot].fd;
1345
1346 switch (var) {
1347 case CONN_PARA_AUTO_RECONNECT:
1348 C->flags |= (val == 0) ? 0 : CONN_FLAGS_AUTO_RECONNECT;
1349 break;
1350 case CONN_PARA_RECONNECT_DELAY:
1351 C->delay = val;
1352 break;
1353 case CONN_PARA_IDLE_TIME:
1354 C->idle = val;
1355 break;
1356 case CONN_PARA_READ_TIMEOUT:
1357 C->read_timeout = val;
1358 break;
1359 case CONN_PARA_CONN_TIMEOUT:
1360 C->conn_timeout = val;
1361 break;
1362 case CONN_PARA_TRIGGER:
1363 C->trigger = val;
1364 break;
1365 case CONN_PARA_IBUF:
1366 setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &val, sizeof(val));
1367 break;
1368 case CONN_PARA_OBUF:
1369 setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &val, sizeof(val));
1370 break;
1371 }
1372 }
1373
1374 struct Conn *Conn_connect(int domain, int type, char *addr, int port)
1375 {
1376 struct Conn *X;
1377 unsigned int Xslot;
1378
1379 Log(8, "%s(%s, %d)\n",
1380 __FUNCTION__, addr, port);
1381
1382 X = Conn_alloc();
1383 if (!X)
1384 return NULL;
1385
1386 Xslot = X->slot;
1387
1388 Conns[Xslot].type = Conn_type_CLIENT;
1389 Conns[Xslot].error_state = 0;
1390 Conns[Xslot].state = CONN_STATE_CONNECT_a;
1391 snprintf(Conns[Xslot].addr, sizeof(Conns[Xslot].addr), "%s", addr);
1392 Conns[Xslot].port = port;
1393 Conns[Xslot].sock_domain = domain;
1394 Conns[Xslot].sock_type = type;
1395 Conns[Xslot].id = Conn_id++;
1396 Conns[Xslot].start = Conn_now.tv_sec;
1397
1398 Conn_pending++;
1399
1400 return &Conns[Xslot];
1401 }
1402
1403 static void Conn_trytoconnect(void)
1404 {
1405 struct addrinfo hints;
1406 struct addrinfo *res;
1407 int i, ret;
1408 char port[8];
1409
1410 Log(8, "%s() Conn_no=%d Conn_pending=%d\n",
1411 __FUNCTION__, Conn_no, Conn_pending);
1412
1413 for (i = Conn_no - 1; i >= 0; i--) {
1414 if (Conns[i].type != Conn_type_CLIENT)
1415 continue;
1416
1417 if ((Conns[i].state == CONN_STATE_CONNECT_0)
1418 && (Conns[i].tryat <= Conn_now.tv_sec)) {
1419 Conns[i].state = CONN_STATE_CONNECT_a;
1420 }
1421
1422 if (Conns[i].state != CONN_STATE_CONNECT_a)
1423 continue;
1424
1425 Log(9, "\tTry to connect to %s/%d...\n",
1426 Conns[i].addr, Conns[i].port);
1427
1428 memset(&hints, 0, sizeof(hints));
1429 if (Conns[i].sock_domain == 0)
1430 hints.ai_family = PF_UNSPEC;
1431 else
1432 hints.ai_family = Conns[i].sock_domain;
1433 hints.ai_socktype = Conns[i].sock_type;
1434 /*hints.ai_flags = AI_NUMERICHOST;*/
1435 hints.ai_flags = 0;
1436 snprintf(port, sizeof(port), "%d", Conns[i].port);
1437 res = NULL;
1438 ret = getaddrinfo(Conns[i].addr, port, &hints, &res);
1439 if (ret != 0) {
1440 snprintf(Conn_error, sizeof(Conn_error),
1441 "Cannot call getaddrinfo [%s]", gai_strerror(ret));
1442 Log(9, "\t%s\n", Conn_error);
1443 Conns[i].error_state = CONN_ERROR_GETADDRINFO;
1444 Conn_free_intern(&Conns[i]);
1445 if (res)
1446 freeaddrinfo(res);
1447 continue;
1448 }
1449
1450 if (Conn_pfds[i].fd == -1) {
1451 Conn_pfds[i].fd = socket(res->ai_family, res->ai_socktype, 0);
1452 if (Conn_pfds[i].fd == -1) {
1453 snprintf(Conn_error, sizeof(Conn_error),
1454 "Cannot create socket [%s]", strerror(errno));
1455 Log(9, "\t%s\n", Conn_error);
1456 Conns[i].error_state = CONN_ERROR_SOCKET;
1457 Conn_free_intern(&Conns[i]);
1458 freeaddrinfo(res);
1459 continue;
1460 }
1461 Log(10, " Allocated socket %d\n",
1462 Conn_pfds[i].fd);
1463 Conn_pfds[i].events |= POLLIN | POLLOUT;
1464
1465 Conn_setnonblock(Conn_pfds[i].fd);
1466 }
1467
1468 Log(9, "\tconnecting...\n");
1469 /* Set syn time */
1470 Conns[i].conn_syn = Conn_now;
1471 ret = connect(Conn_pfds[i].fd, res->ai_addr, res->ai_addrlen);
1472 if ((ret != 0) && (errno != EINPROGRESS)) {
1473 snprintf(Conn_error, sizeof(Conn_error),
1474 "Cannot connect [%d] [%s]", errno, strerror(errno));
1475 Log(9, "\t%s\n", Conn_error);
1476 Conns[i].error_state = CONN_ERROR_CONNECT;
1477 Conn_free_intern(&Conns[i]);
1478 freeaddrinfo(res);
1479 continue;
1480 }
1481
1482 Conns[i].state = CONN_STATE_CONNECT_b;
1483 Conn_pending--;
1484 Conn_total++;
1485
1486 freeaddrinfo(res);
1487 }
1488
1489 Log(10, "%s() FINISH\n",
1490 __FUNCTION__);
1491 }
1492
1493 /*
1494 * Returns 1 if we can ignore this connection */
1495 static int Conn_ignore(struct Conn *C)
1496 {
1497 if (C->error_state > 0)
1498 return 1;
1499
1500 return 0;
1501 }
1502
1503 /*
1504 * Close a connection if it exceeded maximum idle time or got a timeout
1505 */
1506 static void Conn_expire(struct Conn *C)
1507 {
1508 long long diff_ms;
1509
1510 if ((C->trigger > 0)
1511 && (C->last_trigger + C->trigger < Conn_now.tv_sec)) {
1512 C->last_trigger = Conn_now.tv_sec;
1513 if (C->cb_trigger)
1514 C->cb_trigger(C);
1515 else if (Conn_trigger_cb)
1516 Conn_trigger_cb(C);
1517 }
1518
1519 if ((C->idle > 0) && (C->trecv.tv_sec + C->idle < Conn_now.tv_sec)) {
1520 C->error_state = CONN_ERROR_EXPIRED;
1521 } else if ((C->read_timeout > 0) && (C->tsend.tv_sec > 0)
1522 && (C->tsend.tv_sec > C->trecv.tv_sec)) {
1523 diff_ms = Conn_time_diff(&Conn_now, &C->tsend);
1524 if (diff_ms > C->read_timeout) {
1525 C->error_state = CONN_ERROR_READ_TIMEOUT;
1526 }
1527 } else if ((C->conn_timeout > 0) && (C->state == CONN_STATE_CONNECT_b)) {
1528 diff_ms = Conn_time_diff(&Conn_now, &C->conn_syn);
1529 if (diff_ms > C->conn_timeout) {
1530 /* connection attempt expired */
1531 C->error_state = CONN_ERROR_CONN_TIMEOUT;
1532 }
1533 }
1534 }
1535
1536 /*
1537 * Returns: -1 on error, 0 nothing to do, 1 if some work was done
1538 * timeout is in 1/1000 seconds increments.
1539 */
1540 int Conn_poll(int timeout)
1541 {
1542 int i;
1543 short rev;
1544 char *stats;
1545 int timeout2;
1546 int events;
1547
1548 Log(11, "Conn_poll(timeout=%d Conn_no=%d)\n",
1549 timeout, Conn_no);
1550
1551 if (Conn_no == 0)
1552 return 0;
1553
1554 if (timeout == -1)
1555 timeout2 = 500;
1556 else
1557 timeout2 = timeout;
1558
1559 loop:
1560 if (Conn_pending > 0)
1561 Conn_trytoconnect();
1562
1563 again:
1564 events = poll(&Conn_pfds[0], Conn_no, timeout2);
1565 if ((events == -1) && (errno == EINTR))
1566 goto again;
1567
1568 if (events < 0) {
1569 snprintf(Conn_error, sizeof(Conn_error),
1570 "poll(%p, %d): %s",
1571 (void *)Conn_pfds, Conn_no, strerror(errno));
1572 return -1;
1573 }
1574
1575 gettimeofday(&Conn_now, NULL);
1576
1577 if (Conn_level >= 11) {
1578 stats = Conn_status(0);
1579 Log(0, "%s\n", stats);
1580 free(stats);
1581 }
1582
1583 /* We do revers scan because of moving Conn objects */
1584 Log(11, "Process %d events...\n",
1585 events);
1586 for (i = Conn_no - 1; i >= 0; i--) {
1587 if (events > 0) {
1588 rev = Conn_pfds[i].revents;
1589
1590 if (rev == 0)
1591 continue;
1592
1593 events--;
1594
1595 if (rev & POLLHUP) {
1596 Conns[i].error_state = CONN_ERROR_HANGUP;
1597 }
1598
1599 if (rev & POLLERR) {
1600 Conns[i].error_state = CONN_ERROR_POLL;
1601 Conns[i].xerrno = 0;
1602 }
1603
1604 if (rev & POLLNVAL) {
1605 Log(0, "BUG NVAL!\n");
1606 exit(1);
1607 }
1608
1609 /* First, test we have a new connection */
1610 if ((rev & POLLOUT) && (Conn_ignore(&Conns[i]) == 0)) {
1611 /* We just established a connection */
1612 if (Conns[i].state == CONN_STATE_CONNECT_b) {
1613 if (Conns[i].cb_connected)
1614 Conns[i].cb_connected(&Conns[i]);
1615 else if (Conn_connected_cb)
1616 Conn_connected_cb(&Conns[i]);
1617 Conns[i].state = CONN_STATE_OPEN;
1618 }
1619 }
1620
1621 /* Second, test for error or input */
1622 if ((rev & POLLIN) && (Conn_ignore(&Conns[i]) == 0)) {
1623 if (Conns[i].type == Conn_type_MASTER) {
1624 Conn_accept(&Conns[i]);
1625 } else {
1626 if (Conns[i].cb_recv)
1627 Conns[i].cb_recv(&Conns[i]);
1628 else if (Conn_recv_cb != NULL)
1629 Conn_recv_cb(&Conns[i]);
1630 else
1631 Conn_recv_cb_i(&Conns[i]);
1632 }
1633 }
1634
1635 if ((rev & POLLOUT) && (Conn_ignore(&Conns[i]) == 0)) {
1636 /* We can send data */
1637 if (Conns[i].state == CONN_STATE_OPEN) {
1638 if (Conns[i].cb_send)
1639 Conns[i].cb_send(&Conns[i]);
1640 else if (Conn_send_cb != NULL)
1641 Conn_send_cb(&Conns[i]);
1642 else
1643 Conn_send_cb_i(&Conns[i]);
1644
1645 if (Conns[i].obuf_head == Conns[i].obuf_tail) {
1646 Conn_pfds[i].events &= ~POLLOUT;
1647 if (Conns[i].flags & CONN_FLAGS_CLOSE_AFTER_SEND)
1648 Conns[i].error_state = CONN_ERROR_USERREQ;
1649 }
1650 }
1651 }
1652 }
1653
1654 /* test if it expired/timout */
1655 Conn_expire(&Conns[i]);
1656
1657 if (Conns[i].error_state > 0) {
1658 Conn_free_intern(&Conns[i]);
1659 } else {
1660 /* add tokens */
1661 Conn_band_update(&Conns[i]);
1662 }
1663 }
1664
1665 if (timeout == -1)
1666 goto loop;
1667 else
1668 return 1;
1669
1670 return 1;
1671 }
1672
1673 /*
1674 * Set NODELAY on socket
1675 */
1676 int Conn_nodelay(struct Conn *C)
1677 {
1678 int i, fd;
1679
1680 fd = Conn_pfds[C->slot] . fd;
1681 i = 1;
1682 return setsockopt(fd, SOL_TCP, TCP_NODELAY, &i, sizeof(i));
1683 }
1684
1685 void Conn_rollback(struct Conn *C, unsigned int bytes)
1686 {
1687 if (C->obuf_tail - C->obuf_head <= bytes)
1688 C->obuf_tail -= bytes;
1689 }
1690
1691 /*
1692 * Search for str in active buffer from a given offset
1693 * Returns pointer to string if match or NUll if doesn't.
1694 */
1695 char *Conn_ostrstr(struct Conn *C, unsigned int off, char *str)
1696 {
1697 unsigned int len, str_len, i;
1698 char *buf, *ret = NULL;
1699
1700 len = C->ibuf_tail - C->ibuf_head - off;
1701 buf = C->ibuf + C->ibuf_head + off;
1702 str_len = strlen(str);
1703
1704 if (len < str_len)
1705 return NULL;
1706
1707 i = 0;
1708 while (i <= len - str_len) {
1709 if (strncmp(buf + i, str, str_len) == 0) {
1710 ret = buf + i;
1711 break;
1712 }
1713
1714 i++;
1715 }
1716
1717 return ret;
1718 }
1719
1720 /*
1721 * Search for str in active buffer
1722 * Returns pointer to string if match or NUll if doesn't.
1723 */
1724 char *Conn_strstr(struct Conn *C, char *str)
1725 {
1726 return Conn_ostrstr(C, 0, str);
1727 }
1728
1729 /*
1730 * Returns a pointer to current in buffer
1731 */
1732 char *Conn_ibuf(struct Conn *C)
1733 {
1734 return C->ibuf + C->ibuf_head;
1735 }
1736
1737 /*
1738 * Returns a pointer to current out buffer
1739 */
1740 char *Conn_obuf(struct Conn *C)
1741 {
1742 return C->obuf + C->obuf_head;
1743 }
1744
1745 /*
1746 * Returns the id of a connection
1747 */
1748 unsigned long long Conn_getid(struct Conn *C)
1749 {
1750 return C->id;
1751 }
1752
1753 /*
1754 * Returns a Conn* searching for id
1755 */
1756 struct Conn *Conn_get(unsigned long long id)
1757 {
1758 struct Conn *R = NULL;
1759 int i;
1760
1761 for (i = Conn_no - 1; i >= 0; i--) {
1762 if (Conns[i].id == id) {
1763 R = &Conns[i];
1764 break;
1765 }
1766 }
1767
1768 return R;
1769 }
1770
1771
1772 /*
1773 * Returns the fd associated with C
1774 */
1775 int Conn_get_fd(struct Conn *C)
1776 {
1777 if (C == NULL)
1778 return -1;
1779
1780 return Conn_pfds[C->slot].fd;
1781 }
1782
1783 /*
1784 * Returns the timeval of the last packet
1785 */
1786 void Conn_last_time(struct Conn *C, struct timeval *tv)
1787 {
1788 *tv = C->trecv;
1789 }
1790
1791 /*
1792 * Set a callback
1793 */
1794 int Conn_set_cb(struct Conn *C, unsigned int type, void (*f)(struct Conn *))
1795 {
1796 switch (type) {
1797 case CONN_CB_ACCEPT: C->cb_accept = f; break;
1798 case CONN_CB_RECV: C->cb_recv = f; break;
1799 case CONN_CB_SEND: C->cb_send = f; break;
1800 case CONN_CB_DATA: C->cb_data = f; break;
1801 case CONN_CB_CLOSE: C->cb_close = f; break;
1802 case CONN_CB_TRIGGER: C->cb_trigger = f; break;
1803 case CONN_CB_ERROR: C->cb_error = f; break;
1804 case CONN_CB_CONNECTED: C->cb_connected = f; break;
1805
1806 default:
1807 return -1;
1808 }
1809
1810 return 0;
1811 }
File Conn.h added (mode: 100644) (index 0000000..e2302f4)
1 #ifndef _Conn_h
2 #define _Conn_h 1
3
4 #define _GNU_SOURCE
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 <unistd.h>
17 #include <time.h>
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <unistd.h>
21 #include <string.h>
22 #include <fcntl.h>
23 #include <sys/poll.h>
24 #include <arpa/inet.h>
25 #include <netinet/tcp.h>
26
27
28
29 /* type */
30 #define Conn_type_MASTER 1
31 #define Conn_type_CLIENT 2
32 #define Conn_type_UNK 3
33
34
35 /* state */
36 #define CONN_STATE_START 0
37 #define CONN_STATE_FREE CONN_STATE_START + 1
38 #define CONN_STATE_EMPTY CONN_STATE_START + 2
39 #define CONN_STATE_OPEN CONN_STATE_START + 3
40 #define CONN_STATE_LISTEN CONN_STATE_START + 4
41 #define CONN_STATE_CONNECT_0 CONN_STATE_START + 5
42 #define CONN_STATE_CONNECT_a CONN_STATE_START + 6
43 #define CONN_STATE_CONNECT_b CONN_STATE_START + 7
44
45
46 /* error kind */
47 #define CONN_ERROR_START 0
48 #define CONN_ERROR_USERREQ CONN_ERROR_START + 1 /* user requested the close */
49 #define CONN_ERROR_POLL CONN_ERROR_START + 2
50 #define CONN_ERROR_RECV CONN_ERROR_START + 3
51 #define CONN_ERROR_SEND CONN_ERROR_START + 4
52 #define CONN_ERROR_SOCKET CONN_ERROR_START + 5
53 #define CONN_ERROR_HANGUP CONN_ERROR_START + 6
54 #define CONN_ERROR_GETADDRINFO CONN_ERROR_START + 7
55 #define CONN_ERROR_EXPIRED CONN_ERROR_START + 8
56 #define CONN_ERROR_ACCEPT CONN_ERROR_START + 9
57 #define CONN_ERROR_MEM CONN_ERROR_START + 10
58 #define CONN_ERROR_CONNECT CONN_ERROR_START + 11
59 #define CONN_ERROR_READ_TIMEOUT CONN_ERROR_START + 12
60 #define CONN_ERROR_CONN_TIMEOUT CONN_ERROR_START + 13
61
62
63 /* FLAGS */
64 #define CONN_FLAGS_AUTO_RECONNECT 0x01 << 0
65 #define CONN_FLAGS_CLOSE_AFTER_SEND 0x01 << 1
66
67
68 /* Parameters */
69 #define CONN_PARA_START 0
70 #define CONN_PARA_AUTO_RECONNECT CONN_PARA_START + 1
71 #define CONN_PARA_RECONNECT_DELAY CONN_PARA_START + 2
72 #define CONN_PARA_IDLE_TIME CONN_PARA_START + 3
73 #define CONN_PARA_READ_TIMEOUT CONN_PARA_START + 4
74 #define CONN_PARA_CONN_TIMEOUT CONN_PARA_START + 5
75 #define CONN_PARA_TRIGGER CONN_PARA_START + 6
76 #define CONN_PARA_IBUF CONN_PARA_START + 7
77 #define CONN_PARA_OBUF CONN_PARA_START + 8
78
79 /* Callbacks */
80 #define CONN_CB_START 0
81 #define CONN_CB_ACCEPT CONN_CB_START + 1
82 #define CONN_CB_RECV CONN_CB_START + 2
83 #define CONN_CB_SEND CONN_CB_START + 3
84 #define CONN_CB_DATA CONN_CB_START + 4
85 #define CONN_CB_CLOSE CONN_CB_START + 5
86 #define CONN_CB_TRIGGER CONN_CB_START + 6
87 #define CONN_CB_ERROR CONN_CB_START + 7
88 #define CONN_CB_CONNECTED CONN_CB_START + 8
89
90
91 struct Conn
92 {
93 unsigned char type;
94
95 unsigned char state;
96 unsigned char error_state;
97
98 unsigned int slot;
99
100 char *ibuf;
101 unsigned int ibuf_size, ibuf_head, ibuf_tail;
102
103 char *obuf;
104 unsigned int obuf_size, obuf_head, obuf_tail;
105
106 struct timeval trecv, tsend; /* last time we saw an receive/send */
107 unsigned int idle; /* idle time allowed */
108 unsigned int read_timeout; /* Max timeout for receiving an answer (milliseconds) */
109
110 struct timeval conn_syn; /* Time when a connection was initiated */
111 unsigned int conn_timeout; /* Timeout for connection (milliseconds) */
112
113 time_t last_trigger; /* last trigger was at */
114 unsigned int trigger; /* Frequency of wakeup a connection */
115
116 int sock_domain;
117 int sock_type;
118
119 char addr[64];
120 int port, via; /* "via" is the port via a client was accepted */
121
122 unsigned long long bi, bo;
123
124 void *private; /* private use by user */
125
126 /* reconnect stuff */
127 unsigned int retries;
128 unsigned int delay; /* delay between reconnects */
129 time_t tryat; /* when we go to CONNECT_a state */
130
131 int xerrno;
132
133 time_t start;
134
135 unsigned int flags;
136
137 /* bandwidth stuff */
138 struct timeval band_lasttime; /* last time tokens were added */
139 unsigned int band_tokens; /* 1 token -> 1000 bytes */
140 unsigned int band_factor; /* tokens cannot go past f * w */
141 unsigned int band_width; /* in 1000b increments */
142
143 unsigned long long id; /* the id of a connection */
144
145 /* Specific callbacks */
146 void (*cb_accept)(struct Conn *C);
147 void (*cb_recv)(struct Conn *C);
148 void (*cb_send)(struct Conn *C);
149 void (*cb_data)(struct Conn *C);
150 void (*cb_close)(struct Conn *C);
151 void (*cb_trigger)(struct Conn *C);
152 void (*cb_error)(struct Conn *C);
153 void (*cb_connected)(struct Conn *C);
154 };
155
156
157
158 /* Variables */
159 extern void (*Conn_accept_cb)(struct Conn *C);
160 extern void (*Conn_recv_cb)(struct Conn *C);
161 extern void (*Conn_send_cb)(struct Conn *C);
162 extern void (*Conn_data_cb)(struct Conn *C);
163 extern void (*Conn_close_cb)(struct Conn *C);
164 extern void (*Conn_trigger_cb)(struct Conn *C);
165 extern void (*Conn_error_cb)(struct Conn *C);
166 extern void (*Conn_connected_cb)(struct Conn *C);
167
168 extern char *(*Conn_status_slot_html_cb)(struct Conn *C);
169 extern char *(*Conn_status_cb)(void);
170
171 extern unsigned int Conn_max_reached;
172 extern unsigned int Conn_default_ibuf;
173 extern unsigned int Conn_default_obuf;
174 extern unsigned int Conn_max_ibuf;
175 extern unsigned int Conn_max_obuf;
176 extern unsigned int Conn_no;
177 extern unsigned int Conn_max;
178 extern unsigned long Conn_total;
179 extern unsigned int Conn_start;
180 extern unsigned int Conn_pending;
181 extern struct timeval Conn_now;
182
183 extern unsigned int Conn_max_send;
184 extern unsigned int Conn_max_recv;
185
186 extern unsigned short Conn_level;
187
188
189 /* Functions */
190 extern char *Conn_strerror(void);
191 extern int Conn_init(unsigned int max);
192 extern void Conn_close(struct Conn *C);
193 extern ssize_t Conn_send(struct Conn *C, void *buf, size_t count);
194 extern ssize_t Conn_recv(struct Conn *C, void *buf, size_t count);
195 extern struct Conn *Conn_socket(int domain, int type, int port);
196 extern char *Conn_status(unsigned int flags);
197 extern int Conn_poll(int timeout);
198 extern int Conn_enqueue(struct Conn *C, void *buf, size_t count);
199 extern void Conn_debug(FILE *f, unsigned short debug);
200 extern struct Conn *Conn_connect(int domain, int type, char *addr, int port);
201 extern char *Conn_dump(char *buf_src, int len_src);
202 extern char *Conn_dumphex(char *buf_src, int len_src);
203 extern int Conn_nodelay(struct Conn *C);
204 extern void Conn_rollback(struct Conn *C, unsigned int bytes);
205 extern char *Conn_strstr(struct Conn *C, char *str);
206 extern unsigned int Conn_qlen(struct Conn *C);
207 extern void Conn_eat(struct Conn *C, unsigned int bytes);
208 extern void Conn_eatall(struct Conn *C);
209 extern char *Conn_ibuf(struct Conn *C);
210 extern char *Conn_obuf(struct Conn *C);
211 extern int Conn_try_expand_buf(struct Conn *C, int what, int needed);
212 extern int Conn_band(struct Conn *C, unsigned int width, unsigned int factor);
213 extern void Conn_set(struct Conn *C, int var, unsigned int val);
214 extern char *Conn_ostrstr(struct Conn *C, unsigned int off, char *str);
215 extern unsigned long long Conn_getid(struct Conn *C);
216 extern struct Conn *Conn_get(unsigned long long id);
217 extern int Conn_get_fd(struct Conn *C);
218 extern void Conn_last_time(struct Conn *C, struct timeval *tv);
219 extern int Conn_set_cb(struct Conn *C, unsigned int type,
220 void (*f)(struct Conn *));
221
222 #endif
File Conn.spec.in added (mode: 100644) (index 0000000..1394784)
1 Summary: Connection manager
2 Name: @PRJ@
3 Version: @VER@
4 Release: @REV@
5 License: LGPL
6 Group: Applications/Network
7 Source: http://kernel.umbrella.ro/us/Conn/%{name}-%{version}.tar.gz
8 URL: http://kernel.umbrella.ro/us/
9 Packager: Catalin(uk aka Dino) BOIE <catab@umbrella.ro>
10 BuildRoot: %{_tmppath}/%{name}-%{version}-buildroot
11
12
13 %description
14 Small library for easy building client/server daemons.
15
16 %prep
17 %setup
18
19 %build
20 %configure
21 make
22
23 %install
24 rm -rf ${RPM_BUILD_ROOT}
25 mkdir -p ${RPM_BUILD_ROOT}
26 make install DESTDIR=${RPM_BUILD_ROOT}
27
28 %clean
29 rm -rf ${RPM_BUILD_ROOT}
30
31 %post -p /sbin/ldconfig
32
33 %postun -p /sbin/ldconfig
34
35 %files
36 %attr (-,root,root)
37 %dir /usr/include/*
38 %dir /usr/lib/*
39 %doc README Changelog examples
File INSTALL added (mode: 100644) (index 0000000..d987fa5)
1 ./configure
2 make
3 make install
File LICENSE added (mode: 100644) (index 0000000..92b8903)
1 GNU LIBRARY GENERAL PUBLIC LICENSE
2 Version 2, June 1991
3
4 Copyright (C) 1991 Free Software Foundation, Inc.
5 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
6 Everyone is permitted to copy and distribute verbatim copies
7 of this license document, but changing it is not allowed.
8
9 [This is the first released version of the library GPL. It is
10 numbered 2 because it goes with version 2 of the ordinary GPL.]
11
12 Preamble
13
14 The licenses for most software are designed to take away your
15 freedom to share and change it. By contrast, the GNU General Public
16 Licenses are intended to guarantee your freedom to share and change
17 free software--to make sure the software is free for all its users.
18
19 This license, the Library General Public License, applies to some
20 specially designated Free Software Foundation software, and to any
21 other libraries whose authors decide to use it. You can use it for
22 your libraries, too.
23
24 When we speak of free software, we are referring to freedom, not
25 price. Our General Public Licenses are designed to make sure that you
26 have the freedom to distribute copies of free software (and charge for
27 this service if you wish), that you receive source code or can get it
28 if you want it, that you can change the software or use pieces of it
29 in new free programs; and that you know you can do these things.
30
31 To protect your rights, we need to make restrictions that forbid
32 anyone to deny you these rights or to ask you to surrender the rights.
33 These restrictions translate to certain responsibilities for you if
34 you distribute copies of the library, or if you modify it.
35
36 For example, if you distribute copies of the library, whether gratis
37 or for a fee, you must give the recipients all the rights that we gave
38 you. You must make sure that they, too, receive or can get the source
39 code. If you link a program with the library, you must provide
40 complete object files to the recipients so that they can relink them
41 with the library, after making changes to the library and recompiling
42 it. And you must show them these terms so they know their rights.
43
44 Our method of protecting your rights has two steps: (1) copyright
45 the library, and (2) offer you this license which gives you legal
46 permission to copy, distribute and/or modify the library.
47
48 Also, for each distributor's protection, we want to make certain
49 that everyone understands that there is no warranty for this free
50 library. If the library is modified by someone else and passed on, we
51 want its recipients to know that what they have is not the original
52 version, so that any problems introduced by others will not reflect on
53 the original authors' reputations.
54
55 Finally, any free program is threatened constantly by software
56 patents. We wish to avoid the danger that companies distributing free
57 software will individually obtain patent licenses, thus in effect
58 transforming the program into proprietary software. To prevent this,
59 we have made it clear that any patent must be licensed for everyone's
60 free use or not licensed at all.
61
62 Most GNU software, including some libraries, is covered by the ordinary
63 GNU General Public License, which was designed for utility programs. This
64 license, the GNU Library General Public License, applies to certain
65 designated libraries. This license is quite different from the ordinary
66 one; be sure to read it in full, and don't assume that anything in it is
67 the same as in the ordinary license.
68
69 The reason we have a separate public license for some libraries is that
70 they blur the distinction we usually make between modifying or adding to a
71 program and simply using it. Linking a program with a library, without
72 changing the library, is in some sense simply using the library, and is
73 analogous to running a utility program or application program. However, in
74 a textual and legal sense, the linked executable is a combined work, a
75 derivative of the original library, and the ordinary General Public License
76 treats it as such.
77
78 Because of this blurred distinction, using the ordinary General
79 Public License for libraries did not effectively promote software
80 sharing, because most developers did not use the libraries. We
81 concluded that weaker conditions might promote sharing better.
82
83 However, unrestricted linking of non-free programs would deprive the
84 users of those programs of all benefit from the free status of the
85 libraries themselves. This Library General Public License is intended to
86 permit developers of non-free programs to use free libraries, while
87 preserving your freedom as a user of such programs to change the free
88 libraries that are incorporated in them. (We have not seen how to achieve
89 this as regards changes in header files, but we have achieved it as regards
90 changes in the actual functions of the Library.) The hope is that this
91 will lead to faster development of free libraries.
92
93 The precise terms and conditions for copying, distribution and
94 modification follow. Pay close attention to the difference between a
95 "work based on the library" and a "work that uses the library". The
96 former contains code derived from the library, while the latter only
97 works together with the library.
98
99 Note that it is possible for a library to be covered by the ordinary
100 General Public License rather than by this special one.
101
102 GNU LIBRARY GENERAL PUBLIC LICENSE
103 TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
104
105 0. This License Agreement applies to any software library which
106 contains a notice placed by the copyright holder or other authorized
107 party saying it may be distributed under the terms of this Library
108 General Public License (also called "this License"). Each licensee is
109 addressed as "you".
110
111 A "library" means a collection of software functions and/or data
112 prepared so as to be conveniently linked with application programs
113 (which use some of those functions and data) to form executables.
114
115 The "Library", below, refers to any such software library or work
116 which has been distributed under these terms. A "work based on the
117 Library" means either the Library or any derivative work under
118 copyright law: that is to say, a work containing the Library or a
119 portion of it, either verbatim or with modifications and/or translated
120 straightforwardly into another language. (Hereinafter, translation is
121 included without limitation in the term "modification".)
122
123 "Source code" for a work means the preferred form of the work for
124 making modifications to it. For a library, complete source code means
125 all the source code for all modules it contains, plus any associated
126 interface definition files, plus the scripts used to control compilation
127 and installation of the library.
128
129 Activities other than copying, distribution and modification are not
130 covered by this License; they are outside its scope. The act of
131 running a program using the Library is not restricted, and output from
132 such a program is covered only if its contents constitute a work based
133 on the Library (independent of the use of the Library in a tool for
134 writing it). Whether that is true depends on what the Library does
135 and what the program that uses the Library does.
136
137 1. You may copy and distribute verbatim copies of the Library's
138 complete source code as you receive it, in any medium, provided that
139 you conspicuously and appropriately publish on each copy an
140 appropriate copyright notice and disclaimer of warranty; keep intact
141 all the notices that refer to this License and to the absence of any
142 warranty; and distribute a copy of this License along with the
143 Library.
144
145 You may charge a fee for the physical act of transferring a copy,
146 and you may at your option offer warranty protection in exchange for a
147 fee.
148
149 2. You may modify your copy or copies of the Library or any portion
150 of it, thus forming a work based on the Library, and copy and
151 distribute such modifications or work under the terms of Section 1
152 above, provided that you also meet all of these conditions:
153
154 a) The modified work must itself be a software library.
155
156 b) You must cause the files modified to carry prominent notices
157 stating that you changed the files and the date of any change.
158
159 c) You must cause the whole of the work to be licensed at no
160 charge to all third parties under the terms of this License.
161
162 d) If a facility in the modified Library refers to a function or a
163 table of data to be supplied by an application program that uses
164 the facility, other than as an argument passed when the facility
165 is invoked, then you must make a good faith effort to ensure that,
166 in the event an application does not supply such function or
167 table, the facility still operates, and performs whatever part of
168 its purpose remains meaningful.
169
170 (For example, a function in a library to compute square roots has
171 a purpose that is entirely well-defined independent of the
172 application. Therefore, Subsection 2d requires that any
173 application-supplied function or table used by this function must
174 be optional: if the application does not supply it, the square
175 root function must still compute square roots.)
176
177 These requirements apply to the modified work as a whole. If
178 identifiable sections of that work are not derived from the Library,
179 and can be reasonably considered independent and separate works in
180 themselves, then this License, and its terms, do not apply to those
181 sections when you distribute them as separate works. But when you
182 distribute the same sections as part of a whole which is a work based
183 on the Library, the distribution of the whole must be on the terms of
184 this License, whose permissions for other licensees extend to the
185 entire whole, and thus to each and every part regardless of who wrote
186 it.
187
188 Thus, it is not the intent of this section to claim rights or contest
189 your rights to work written entirely by you; rather, the intent is to
190 exercise the right to control the distribution of derivative or
191 collective works based on the Library.
192
193 In addition, mere aggregation of another work not based on the Library
194 with the Library (or with a work based on the Library) on a volume of
195 a storage or distribution medium does not bring the other work under
196 the scope of this License.
197
198 3. You may opt to apply the terms of the ordinary GNU General Public
199 License instead of this License to a given copy of the Library. To do
200 this, you must alter all the notices that refer to this License, so
201 that they refer to the ordinary GNU General Public License, version 2,
202 instead of to this License. (If a newer version than version 2 of the
203 ordinary GNU General Public License has appeared, then you can specify
204 that version instead if you wish.) Do not make any other change in
205 these notices.
206
207 Once this change is made in a given copy, it is irreversible for
208 that copy, so the ordinary GNU General Public License applies to all
209 subsequent copies and derivative works made from that copy.
210
211 This option is useful when you wish to copy part of the code of
212 the Library into a program that is not a library.
213
214 4. You may copy and distribute the Library (or a portion or
215 derivative of it, under Section 2) in object code or executable form
216 under the terms of Sections 1 and 2 above provided that you accompany
217 it with the complete corresponding machine-readable source code, which
218 must be distributed under the terms of Sections 1 and 2 above on a
219 medium customarily used for software interchange.
220
221 If distribution of object code is made by offering access to copy
222 from a designated place, then offering equivalent access to copy the
223 source code from the same place satisfies the requirement to
224 distribute the source code, even though third parties are not
225 compelled to copy the source along with the object code.
226
227 5. A program that contains no derivative of any portion of the
228 Library, but is designed to work with the Library by being compiled or
229 linked with it, is called a "work that uses the Library". Such a
230 work, in isolation, is not a derivative work of the Library, and
231 therefore falls outside the scope of this License.
232
233 However, linking a "work that uses the Library" with the Library
234 creates an executable that is a derivative of the Library (because it
235 contains portions of the Library), rather than a "work that uses the
236 library". The executable is therefore covered by this License.
237 Section 6 states terms for distribution of such executables.
238
239 When a "work that uses the Library" uses material from a header file
240 that is part of the Library, the object code for the work may be a
241 derivative work of the Library even though the source code is not.
242 Whether this is true is especially significant if the work can be
243 linked without the Library, or if the work is itself a library. The
244 threshold for this to be true is not precisely defined by law.
245
246 If such an object file uses only numerical parameters, data
247 structure layouts and accessors, and small macros and small inline
248 functions (ten lines or less in length), then the use of the object
249 file is unrestricted, regardless of whether it is legally a derivative
250 work. (Executables containing this object code plus portions of the
251 Library will still fall under Section 6.)
252
253 Otherwise, if the work is a derivative of the Library, you may
254 distribute the object code for the work under the terms of Section 6.
255 Any executables containing that work also fall under Section 6,
256 whether or not they are linked directly with the Library itself.
257
258 6. As an exception to the Sections above, you may also compile or
259 link a "work that uses the Library" with the Library to produce a
260 work containing portions of the Library, and distribute that work
261 under terms of your choice, provided that the terms permit
262 modification of the work for the customer's own use and reverse
263 engineering for debugging such modifications.
264
265 You must give prominent notice with each copy of the work that the
266 Library is used in it and that the Library and its use are covered by
267 this License. You must supply a copy of this License. If the work
268 during execution displays copyright notices, you must include the
269 copyright notice for the Library among them, as well as a reference
270 directing the user to the copy of this License. Also, you must do one
271 of these things:
272
273 a) Accompany the work with the complete corresponding
274 machine-readable source code for the Library including whatever
275 changes were used in the work (which must be distributed under
276 Sections 1 and 2 above); and, if the work is an executable linked
277 with the Library, with the complete machine-readable "work that
278 uses the Library", as object code and/or source code, so that the
279 user can modify the Library and then relink to produce a modified
280 executable containing the modified Library. (It is understood
281 that the user who changes the contents of definitions files in the
282 Library will not necessarily be able to recompile the application
283 to use the modified definitions.)
284
285 b) Accompany the work with a written offer, valid for at
286 least three years, to give the same user the materials
287 specified in Subsection 6a, above, for a charge no more
288 than the cost of performing this distribution.
289
290 c) If distribution of the work is made by offering access to copy
291 from a designated place, offer equivalent access to copy the above
292 specified materials from the same place.
293
294 d) Verify that the user has already received a copy of these
295 materials or that you have already sent this user a copy.
296
297 For an executable, the required form of the "work that uses the
298 Library" must include any data and utility programs needed for
299 reproducing the executable from it. However, as a special exception,
300 the source code distributed need not include anything that is normally
301 distributed (in either source or binary form) with the major
302 components (compiler, kernel, and so on) of the operating system on
303 which the executable runs, unless that component itself accompanies
304 the executable.
305
306 It may happen that this requirement contradicts the license
307 restrictions of other proprietary libraries that do not normally
308 accompany the operating system. Such a contradiction means you cannot
309 use both them and the Library together in an executable that you
310 distribute.
311
312 7. You may place library facilities that are a work based on the
313 Library side-by-side in a single library together with other library
314 facilities not covered by this License, and distribute such a combined
315 library, provided that the separate distribution of the work based on
316 the Library and of the other library facilities is otherwise
317 permitted, and provided that you do these two things:
318
319 a) Accompany the combined library with a copy of the same work
320 based on the Library, uncombined with any other library
321 facilities. This must be distributed under the terms of the
322 Sections above.
323
324 b) Give prominent notice with the combined library of the fact
325 that part of it is a work based on the Library, and explaining
326 where to find the accompanying uncombined form of the same work.
327
328 8. You may not copy, modify, sublicense, link with, or distribute
329 the Library except as expressly provided under this License. Any
330 attempt otherwise to copy, modify, sublicense, link with, or
331 distribute the Library is void, and will automatically terminate your
332 rights under this License. However, parties who have received copies,
333 or rights, from you under this License will not have their licenses
334 terminated so long as such parties remain in full compliance.
335
336 9. You are not required to accept this License, since you have not
337 signed it. However, nothing else grants you permission to modify or
338 distribute the Library or its derivative works. These actions are
339 prohibited by law if you do not accept this License. Therefore, by
340 modifying or distributing the Library (or any work based on the
341 Library), you indicate your acceptance of this License to do so, and
342 all its terms and conditions for copying, distributing or modifying
343 the Library or works based on it.
344
345 10. Each time you redistribute the Library (or any work based on the
346 Library), the recipient automatically receives a license from the
347 original licensor to copy, distribute, link with or modify the Library
348 subject to these terms and conditions. You may not impose any further
349 restrictions on the recipients' exercise of the rights granted herein.
350 You are not responsible for enforcing compliance by third parties to
351 this License.
352
353 11. If, as a consequence of a court judgment or allegation of patent
354 infringement or for any other reason (not limited to patent issues),
355 conditions are imposed on you (whether by court order, agreement or
356 otherwise) that contradict the conditions of this License, they do not
357 excuse you from the conditions of this License. If you cannot
358 distribute so as to satisfy simultaneously your obligations under this
359 License and any other pertinent obligations, then as a consequence you
360 may not distribute the Library at all. For example, if a patent
361 license would not permit royalty-free redistribution of the Library by
362 all those who receive copies directly or indirectly through you, then
363 the only way you could satisfy both it and this License would be to
364 refrain entirely from distribution of the Library.
365
366 If any portion of this section is held invalid or unenforceable under any
367 particular circumstance, the balance of the section is intended to apply,
368 and the section as a whole is intended to apply in other circumstances.
369
370 It is not the purpose of this section to induce you to infringe any
371 patents or other property right claims or to contest validity of any
372 such claims; this section has the sole purpose of protecting the
373 integrity of the free software distribution system which is
374 implemented by public license practices. Many people have made
375 generous contributions to the wide range of software distributed
376 through that system in reliance on consistent application of that
377 system; it is up to the author/donor to decide if he or she is willing
378 to distribute software through any other system and a licensee cannot
379 impose that choice.
380
381 This section is intended to make thoroughly clear what is believed to
382 be a consequence of the rest of this License.
383
384 12. If the distribution and/or use of the Library is restricted in
385 certain countries either by patents or by copyrighted interfaces, the
386 original copyright holder who places the Library under this License may add
387 an explicit geographical distribution limitation excluding those countries,
388 so that distribution is permitted only in or among countries not thus
389 excluded. In such case, this License incorporates the limitation as if
390 written in the body of this License.
391
392 13. The Free Software Foundation may publish revised and/or new
393 versions of the Library General Public License from time to time.
394 Such new versions will be similar in spirit to the present version,
395 but may differ in detail to address new problems or concerns.
396
397 Each version is given a distinguishing version number. If the Library
398 specifies a version number of this License which applies to it and
399 "any later version", you have the option of following the terms and
400 conditions either of that version or of any later version published by
401 the Free Software Foundation. If the Library does not specify a
402 license version number, you may choose any version ever published by
403 the Free Software Foundation.
404
405 14. If you wish to incorporate parts of the Library into other free
406 programs whose distribution conditions are incompatible with these,
407 write to the author to ask for permission. For software which is
408 copyrighted by the Free Software Foundation, write to the Free
409 Software Foundation; we sometimes make exceptions for this. Our
410 decision will be guided by the two goals of preserving the free status
411 of all derivatives of our free software and of promoting the sharing
412 and reuse of software generally.
413
414 NO WARRANTY
415
416 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
417 WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
418 EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
419 OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
420 KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
421 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
422 PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
423 LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
424 THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
425
426 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
427 WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
428 AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
429 FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
430 CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
431 LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
432 RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
433 FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
434 SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
435 DAMAGES.
436
437 END OF TERMS AND CONDITIONS
438
439 How to Apply These Terms to Your New Libraries
440
441 If you develop a new library, and you want it to be of the greatest
442 possible use to the public, we recommend making it free software that
443 everyone can redistribute and change. You can do so by permitting
444 redistribution under these terms (or, alternatively, under the terms of the
445 ordinary General Public License).
446
447 To apply these terms, attach the following notices to the library. It is
448 safest to attach them to the start of each source file to most effectively
449 convey the exclusion of warranty; and each file should have at least the
450 "copyright" line and a pointer to where the full notice is found.
451
452 <one line to give the library's name and a brief idea of what it does.>
453 Copyright (C) <year> <name of author>
454
455 This library is free software; you can redistribute it and/or
456 modify it under the terms of the GNU Library General Public
457 License as published by the Free Software Foundation; either
458 version 2 of the License, or (at your option) any later version.
459
460 This library is distributed in the hope that it will be useful,
461 but WITHOUT ANY WARRANTY; without even the implied warranty of
462 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
463 Library General Public License for more details.
464
465 You should have received a copy of the GNU Library General Public
466 License along with this library; if not, write to the Free
467 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
468
469 Also add information on how to contact you by electronic and paper mail.
470
471 You should also get your employer (if you work as a programmer) or your
472 school, if any, to sign a "copyright disclaimer" for the library, if
473 necessary. Here is a sample; alter the names:
474
475 Yoyodyne, Inc., hereby disclaims all copyright interest in the
476 library `Frob' (a library for tweaking knobs) written by James Random Hacker.
477
478 <signature of Ty Coon>, 1 April 1990
479 Ty Coon, President of Vice
480
481 That's all there is to it!
File Makefile.head added (mode: 100644) (index 0000000..9b760aa)
1 export PRJ := @PRJ@
2 export VER := @VER@
3 export REV := @REV@
4 export DESTDIR
5
6 export ETC := @ETC@
7 export SBIN := @SBIN@
8
9 export I_ETC := $(DESTDIR)/$(ETC)
10 export I_SBIN := $(DESTDIR)/$(SBIN)
11 export I_LOG := $(DESTDIR)/var/log/$(PRJ)
12 export I_INC := $(DESTDIR)/usr/include
13 export I_LIB := $(DESTDIR)/usr/lib
14
15 # DB stuff
16 export DB_SUPPORT := @DB_SUPPORT@
17 # PG
18 export PG_FOUND := @PG_FOUND@
19 export PG_INC := @PG_INC@
20 export PG_LIB := @PG_LIB@
21
22 .PHONY: xxx_all
23 xxx_all: @MAKEFILE_TARGETS@
24
25 # HEAD END #
26
File Makefile.in added (mode: 100644) (index 0000000..570276f)
1 export CC := gcc
2 export INCS += -I.
3 export LIBS += -L/usr/local/lib
4 export CFLAGS += -ggdb3 -Wall -Wextra -pedantic -Wno-long-long -pipe -fpic -O0
5 export OBJS += Conn.o
6
7 .PHONY: all
8 all: libConn.so.@VER@ libConn.a examples
9
10
11 %.o: %.c
12 gcc $(CFLAGS) $(INCS) $< -c
13
14 libConn.so.@VER@: $(OBJS)
15 $(CC) $(CFLAGS) -shared -Wl,-soname,libConn.so \
16 -o $@ $(OBJS) -lc $(LIBS)
17 ln -sf $@ libConn.so
18
19 libConn.a: $(OBJS)
20 ar rcs libConn.a $(OBJS)
21
22
23 .PHONY: examples
24 examples:
25 $(MAKE) -C examples
26
27
28 .PHONY: clean
29 clean:
30 @-rm -f *.a *.o *.so* $(PRJ)-*.rpm $(PRJ)-*-*-*.tgz $(PRJ)-*.tar.gz
31 @$(MAKE) -C examples clean
32
33
34 install: all
35 @mkdir -p $(I_LIB)
36 @cp -vd libConn* $(I_LIB)
37 @mkdir -p $(I_INC)
38 @cp -vd *.h $(I_INC)
File Makefile.tail added (mode: 100644) (index 0000000..1b23184)
1
2 # TAIL START #
3
4 dist: clean
5 @echo "Generate tarball..."
6 cd .. && rm -f $(PRJ)-$(VER) && ln -s $(PRJ) $(PRJ)-$(VER)
7 tar czhvf $(PRJ)-$(VER).tar.gz \
8 --exclude $(PRJ)-$(VER).tar.gz \
9 --exclude-from PROJECT_EXCLUDE \
10 -C .. $(PRJ)-$(VER)
11 rm -f ../$(PRJ)-$(VER)
12 @echo "Build SRPM..."
13 rpmbuild -ts $(PRJ)-$(VER).tar.gz
14 @echo "Copy to my repository..."
15 mv /usr/src/redhat/SRPMS/$(PRJ)-$(VER)-$(REV)* ../dinorepo/fedora/SRPMS/
16 rm -f $(PRJ)-$(VER).tar.gz
File PROJECT added (mode: 100644) (index 0000000..c484660)
1 Conn
File PROJECT_EXCLUDE added (mode: 100644) (index 0000000..e69de29)
File PROJECT_REV added (mode: 100644) (index 0000000..a787364)
1 34
File PROJECT_TARGETS added (mode: 100644) (index 0000000..0702cb5)
1 all
File PROJECT_VER added (mode: 100644) (index 0000000..b0f3d96)
1 1.0.8
File README added (mode: 100644) (index 0000000..4e68e6a)
1 Author: Catalin(ux aka Dino) BOIE
2 Date: 2004 jul 01
3 Project page: http://kernel.umbrella.ro/us/
4 Description: Net library for easy building ipv4/ipv6 network daemons/clients.
5 License: LGPL
6
7
File TODO added (mode: 100644) (index 0000000..b9f9dab)
1 [ ] A la redir stuff
2
3 [ ] Bridge 2 connections together for proxy stuff.
4 [ ] Use a plugin arhitecture for select/poll/epoll/etc.
5 [ ] Check PACKET: can we send with "send" without knowing the MAC?
6 [ ] alloc nu functioneaza bine!
7 [ ] La status, input-ul nu se afiseaza corect. Sa fac un callback
8 care este apelat dupa poll.
9 [ ] UDP
10 [ ] Pe ipv6 asteapta sa apas o tasta inainte de a-mi da +OK!
11 [ ] Ce se intimpla daca se ajunge la ~ sfirsitul buffer-ului si nu pot inca sa
12 procesez datele?
13 [ ] Coada pentru stergerea intrarilor invalide.
14 [ ] Queue for delete/trytoconnect/etc.
15
16 Performance:
17 [ ] Take care for /proc/net/netstat
18 [ ] /proc/sys/net/ipv4/tcp_mem
19 Now (512M): 49152 65536 98304
20 Now (256M): 24576 32768 49152 - 55 conns/sec
21
22 Test with: 80000 120000 240000 - 92 conns/sec
23 Test with 160000 240000 480000 - 96 conns/sec
24
25 After:
26 echo "16000 64000 512000" > tcp_[rw]mem - 96
27
28 After echo 1 > /proc/sys/net/ipv4/tcp_low_latency - 156 conns/sec
29
30 Pentru a reduce numarul de conexiuni in TIME-WAIT:
31 echo 200 > /proc/sys/net/ipv4/tcp_max_tw_buckets
32
33
34
35 [ ] Conn_data_consume '==' -> '>='
36 [ ] Replace config.h with code
37 [ ] Seems that if we reconnect very fast, poll is hanging.
38 [ ] Add loadbalancing and failover in the base code.
39 [ ] Automaticaly put \0 at the end of receive data.
40 [ ] Add the possibility to wait for an char/string before calling recv callback
41 [ ] Change socket buffer accordingly with user settings to minimize
42 needed memory.
43
File configure added (mode: 100755) (index 0000000..11e05cc)
1 #!/bin/sh
2
3 if [ ! -r "PROJECT" ]; then
4 echo "ERRRO: You must have a PROJECT file in the current directory!"
5 exit 1
6 fi
7
8 PRJ="`cat PROJECT`"
9
10 if [ -r "PROJECT_VER" ]; then
11 VER="`cat PROJECT_VER`"
12 else
13 VER="0.1.0"
14 echo "${VER}" > PROJECT_VER
15 fi
16
17 if [ -r PROJECT_REV ]; then
18 REV=`cat PROJECT_REV`
19 else
20 REV="1"
21 echo ${REV} > PROJECT_REV
22 fi
23
24 echo "PRJ=${PRJ}, VER=${VER}, REV=${REV}"
25
26 ETC="/etc"
27 BIN="/usr/bin"
28 SBIN="/usr/sbin"
29 LOG="/var/log/${PRJ}"
30 INC="/usr/include"
31 LIB="/usr/lib"
32
33 while [ "${1}" != "" ]; do
34 VAR="`echo ${1} | cut -d'=' -f1`"
35 VAL="`echo ${1} | cut -d'=' -f2`"
36 case ${VAR} in
37 --sysconfdir)
38 ETC="${VAL}"
39 ;;
40 --bindir)
41 BIN="${VAL}"
42 ;;
43 --sbindir)
44 SBIN="${VAL}"
45 ;;
46 --includedir)
47 INC="${VAL}"
48 ;;
49 --libdir)
50 LIB="${VAL}"
51 ;;
52 esac
53 shift
54 done
55
56 DB_SUPPORT=0
57
58 echo -n "Search for PostgreSQL..."
59 PG_FOUND=0
60 PG_VERSION="`pg_config --version`"
61 if [ -z "${PG_VERSION}" ]; then
62 echo " not found!"
63 else
64 echo " found version ${PG_VERSION}!"
65 PG_FOUND=1
66 PG_INC="${DB_INC} -I`pg_config --includedir`"
67 PG_LIB="${DB_INC} -L`pg_config --libdir` -lpq"
68 DB_SUPPORT=1
69 fi
70
71 echo "Find out targets for Makefile..."
72 if [ -r PROJECT_TARGETS ]; then
73 MAKEFILE_TARGETS="`cat PROJECT_TARGETS`"
74 fi
75
76
77 # generic stuff
78 echo "s#@PRJ@#${PRJ}#g" >> tmp.sed
79 echo "s#@VER@#${VER}#g" >> tmp.sed
80 echo "s#@REV@#${REV}#g" >> tmp.sed
81 echo "s#@ETC@#${ETC}#g" >> tmp.sed
82 echo "s#@BIN@#${BIN}#g" >> tmp.sed
83 echo "s#@SBIN@#${SBIN}#g" >> tmp.sed
84 echo "s#@LOG@#${LOG}#g" >> tmp.sed
85 echo "s#@INC@#${INC}#g" >> tmp.sed
86 echo "s#@LIB@#${LIB}#g" >> tmp.sed
87 # PG stuff
88 echo "s#@PG_VERSION@#${PG_VERSION}#g" >> tmp.sed
89 echo "s#@PG_FOUND@#${PG_FOUND}#g" >> tmp.sed
90 echo "s#@PG_INC@#${PG_INC}#g" >> tmp.sed
91 echo "s#@PG_LIB@#${PG_LIB}#g" >> tmp.sed
92 # DB stuff
93 echo "s#@DB_SUPPORT@#${DB_SUPPORT}#g" >> tmp.sed
94 # makefile stuff
95 echo "s#@MAKEFILE_TARGETS@#${MAKEFILE_TARGETS}#g" >> tmp.sed
96
97
98 echo "Build Makefile..."
99 sed --file tmp.sed Makefile.head > Makefile
100 if [ -r Makefile.in ]; then
101 sed --file tmp.sed Makefile.in >> Makefile
102 fi
103 sed --file tmp.sed Makefile.tail >> Makefile
104
105
106 echo "Generate .spec file..."
107 sed --file tmp.sed ${PRJ}.spec.in > ${PRJ}.spec
108
109
110 if [ -r config.h.in ]; then
111 echo "Generate config.h file..."
112 sed --file tmp.sed config.h.in > config.h
113 fi
114
115
116 rm -f tmp.sed
117
118 echo "Done. Run make."
File docs/LINKS added (mode: 100644) (index 0000000..a9b398e)
1 http://www.uninet.edu/6fevu/text/afindependence.html
2 http://www.kame.net/newsletter/19980604/
3 http://www.ipv6style.jp/en/apps/20030829/index.shtml
File examples/Makefile added (mode: 100644) (index 0000000..6016348)
1 TARGETS := s c raw udp_s timeout trigger
2
3 all: $(TARGETS)
4
5 INCS += -I. -I..
6 LIBS += -L.. -lConn
7 OBJS :=
8
9 s: s.c $(OBJS)
10 gcc $(CFLAGS) $(INCS) s.c -o s $(LIBS)
11
12 c: c.c $(OBJS)
13 gcc $(CFLAGS) $(INCS) c.c -o c $(LIBS)
14
15 raw: raw.c $(OBJS)
16 gcc $(CFLAGS) $(INCS) raw.c -o raw $(LIBS)
17
18 udp_s: udp_s.c $(OBJS)
19 gcc $(CFLAGS) $(INCS) $@.c -o $@ $(LIBS)
20
21 timeout: timeout.c $(OBJS)
22 gcc $(CFLAGS) $(INCS) $@.c -o $@ $(LIBS)
23
24 %: %.c $(OBJS)
25 gcc $(CFLAGS) $(INCS) $@.c -o $@ $(LIBS)
26
27
28 .PHONY: clean
29 clean:
30 @-rm -f $(TARGETS) *.log core
File examples/c.c added (mode: 100644) (index 0000000..008f6c0)
1 #define _GNU_SOURCE
2
3 #include <errno.h>
4 #include <string.h>
5 #include <strings.h>
6 #include <stdlib.h>
7 #include <unistd.h>
8 #include <sys/poll.h>
9 #include <sys/types.h>
10 #include <sys/socket.h>
11 #include <stdio.h>
12 #include <fcntl.h>
13 #include <netinet/in.h>
14 #include <sys/time.h>
15 #include <sys/ioctl.h>
16 #include <time.h>
17 #include <arpa/inet.h>
18 #include <stdarg.h>
19
20 #include <Conn.h>
21
22 /* Global variables */
23 static unsigned short debug = 1;
24
25 static FILE *Logf = NULL;
26 static char *log_file = "c.log";
27 static int port = 9000;
28 static unsigned int answers = 0;
29
30 struct priv
31 {
32 unsigned int dummy;
33 };
34
35
36 static void Log(unsigned short level, char *format, ...)
37 {
38 va_list ap;
39
40 if (level > debug)
41 return;
42
43 va_start(ap, format);
44 vfprintf(Logf, format, ap);
45 va_end(ap);
46 }
47
48 static void c_connected(struct Conn *C)
49 {
50 struct priv *p;
51
52 Log(4, "%s(A connection was estabilished on slot %d)\n",
53 __FUNCTION__, C->slot);
54
55 C->private = malloc(sizeof(struct priv));
56 if (C->private == NULL) {
57 Log(0, "cannot alloc memory!\n");
58 exit(1);
59 }
60
61 p = (struct priv *) C->private;
62 p->dummy = 0;
63 }
64
65 static void c_close(struct Conn *C)
66 {
67 Log(5, "%s(Slot %d will close)\n",
68 __FUNCTION__, C->slot);
69 free(C->private);
70 }
71
72 static void c_data(struct Conn *C)
73 {
74 struct priv *p;
75 char *dump;
76
77 if (debug >= 8) {
78 dump = Conn_dump(C->ibuf + C->ibuf_head, C->ibuf_tail - C->ibuf_head);
79 Log(8, "data: recv: %s\n", dump);
80 free(dump);
81 }
82
83 p = (struct priv *) C->private;
84
85 p->dummy = 1;
86
87 answers++;
88
89 Conn_close(C);
90
91 Conn_eatall(C);
92 }
93
94 static void c_error(struct Conn *C)
95 {
96 Log(0, "%s Slot=%d C=%p [%s]\n",
97 __FUNCTION__, C ? C->slot : -1, (void *) C, Conn_strerror());
98 }
99
100 int main(void)
101 {
102 char *stat;
103 int i, ret;
104 struct timeval start, end;
105 unsigned int elap;
106 unsigned int ipv4conns = 10000, ipv6conns = 0;
107 struct Conn *C4, *C6;
108
109
110 Logf = fopen(log_file, "a+");
111 if (!Logf) {
112 fprintf(stderr, "Cannot open log file [%s] [%s]\n",
113 log_file, strerror(errno));
114 return 1;
115 }
116 if (debug > 0)
117 setlinebuf(Logf);
118
119 Log(0, "Starting...\n");
120 Log(0, "\tPort=%d\n", port);
121 Log(0, "\tLogFile=%s Debug=%d\n", log_file, debug);
122
123 Conn_debug(Logf, debug);
124
125 ret = Conn_init(0);
126 if (ret == -1) {
127 Log(0, "%s", Conn_strerror());
128 return 1;
129 }
130
131 Conn_connected_cb = c_connected;
132 Conn_data_cb = c_data;
133 Conn_close_cb = c_close;
134 Conn_error_cb = c_error;
135
136 gettimeofday(&start, NULL);
137
138 answers = 0;
139
140 /* ipv4 */
141 for (i = 0; i < ipv4conns; i++) {
142 C4 = Conn_connect(PF_INET, SOCK_STREAM, "82.79.23.14", port);
143 if (C4 == NULL) {
144 Log(0, "Error calling Conn_connect [%s]!\n",
145 Conn_strerror());
146 return 1;
147 }
148 }
149
150 /* ipv6 */
151 for (i = 0; i < ipv6conns; i++) {
152 C6 = Conn_connect(PF_INET6, SOCK_STREAM, "::1", port);
153 if (C6 == NULL) {
154 Log(0, "Error calling Conn_connect6 [%s]!\n",
155 Conn_strerror());
156 return 1;
157 }
158 }
159
160 while (1) {
161 ret = Conn_poll(1000);
162 if (ret == -1) {
163 Log(0, "Error in poll [%s]!\n",
164 Conn_strerror());
165 break;
166 }
167
168 if (ret == 0) {
169 Log(0, "Finish work!\n");
170 break;
171 }
172
173 if (debug >= 9) {
174 stat = Conn_status(0);
175 Log(9, "%s\n", stat);
176 free(stat);
177 }
178
179 if (answers % 10 == 0)
180 printf(".");
181
182 if (answers == ipv4conns + ipv6conns)
183 break;
184 }
185
186 gettimeofday(&end, NULL);
187
188 elap = 1000000 * (end.tv_sec - start.tv_sec) + end.tv_usec - start.tv_usec;
189 Log(0, "Finish in %ld.%06ld. ipv4conns=%d. ipv6conns=%d. Total=%d. answers=%d"
190 " Conns per sec = %d\n",
191 elap / 1000000, elap % 1000000,
192 ipv4conns, ipv6conns, ipv4conns + ipv6conns,
193 answers, (ipv4conns + ipv6conns) / (elap / 1000000 + 1));
194
195 return 0;
196 }
File examples/c.run added (mode: 100755) (index 0000000..03ef1bc)
1 #!/bin/bash
2
3 ulimit -n60000
4 ./c
File examples/raw.c added (mode: 100644) (index 0000000..e9ac471)
1 #define _GNU_SOURCE
2
3 #include <errno.h>
4 #include <string.h>
5 #include <strings.h>
6 #include <stdlib.h>
7 #include <unistd.h>
8 #include <sys/poll.h>
9 #include <sys/types.h>
10 #include <sys/socket.h>
11 #include <stdio.h>
12 #include <fcntl.h>
13 #include <netinet/in.h>
14 #include <sys/time.h>
15 #include <sys/ioctl.h>
16 #include <time.h>
17 #include <arpa/inet.h>
18 #include <stdarg.h>
19 #include <linux/if_ether.h>
20
21 #include <Conn.h>
22
23 /* Global variables */
24 static unsigned short debug = 9;
25
26 static FILE *Logf = NULL;
27 static char *log_file = "raw.log";
28 static int port = 9000;
29 static int maxconn = 0;
30
31
32 static void Log(unsigned short level, char *format, ...)
33 {
34 va_list ap;
35
36 if (level > debug)
37 return;
38
39 va_start(ap, format);
40 vfprintf(Logf, format, ap);
41 va_end(ap);
42 }
43
44 static void s_close(struct Conn *C)
45 {
46 Log(5, "%s (A connection will be closed [%s] on slot %d)\n",
47 __FUNCTION__, C->addr, C->slot);
48 }
49
50 static void s_data(struct Conn *C)
51 {
52 char *dump;
53 char *p;
54 int len;
55 struct timeval tv;
56
57 p = Conn_ibuf(C);
58 len = Conn_qlen(C);
59
60 Conn_last_time(C, &tv);
61
62 dump = Conn_dumphex(p, len);
63 Log(8, "%s: recv %d bytes at %d.%06d on slot %d: [%s]\n",
64 __FUNCTION__, len, tv.tv_sec, tv.tv_usec, C->slot, dump);
65 free(dump);
66
67 Conn_eatall(C);
68 }
69
70 static void s_error(struct Conn *C)
71 {
72 Log(1, "%s slot=%d C=%p [%s]\n",
73 __FUNCTION__, C == NULL ? -1 : C->slot, (void *) C,
74 Conn_strerror());
75 }
76
77 int main(void)
78 {
79 struct Conn *I4;
80 int ret;
81 struct timeval start;
82 int loops = 0;
83
84 Logf = fopen(log_file, "w");
85 if (!Logf) {
86 fprintf(stderr, "Cannot open log file [%s] [%s]\n",
87 log_file, strerror(errno));
88 return 1;
89 }
90 if (debug > 0)
91 setlinebuf(Logf);
92
93 daemon(0, 0);
94
95 gettimeofday(&start, NULL);
96 Log(0, "\nStarting at %ld...\n", start.tv_sec);
97 Log(0, "\tPort=%d\n", port);
98 Log(0, "\tLogFile=%s Debug=%d\n", log_file, debug);
99
100 /* set library output debug */
101 Conn_debug(Logf, debug);
102
103 Conn_default_ibuf = 10240;
104 Conn_default_obuf = 10240;
105
106 ret = Conn_init(maxconn);
107 if (ret == -1) {
108 Log(0, "%s", Conn_strerror());
109 return 1;
110 }
111
112 Log(9, "Try to register IPv4 socket...\n");
113 I4 = Conn_socket(PF_PACKET, SOCK_RAW, ETH_P_IP);
114 if (I4 == NULL) {
115 Log(0, "Cannot create socket (%s)!\n",
116 Conn_strerror());
117 return 1;
118 }
119
120 ret = Conn_set_cb(I4, CONN_CB_CLOSE, s_close);
121 if (ret != 0) {
122 Log(0, "ERROR: Cannot set cb for 'close'!\n");
123 return 1;
124 }
125
126 ret = Conn_set_cb(I4, CONN_CB_ERROR, s_error);
127 if (ret != 0) {
128 Log(0, "ERROR: Cannot set cb for 'error'!\n");
129 return 1;
130 }
131
132 ret = Conn_set_cb(I4, CONN_CB_DATA, s_data);
133 if (ret != 0) {
134 Log(0, "ERROR: Cannot set cb for 'data'!\n");
135 return 1;
136 }
137
138 while (1) {
139 ret = Conn_poll(10000);
140 if (ret == -1) {
141 Log(0, "Error calling Conn_poll [%s]!\n",
142 Conn_strerror());
143 return 1;
144 }
145
146 loops++;
147 if (ret == 0)
148 break;
149
150 /*
151 if (loops > 1000000)
152 break;
153 */
154 }
155
156 Log(0, "Finish!\n\n");
157
158 return 0;
159 }
File examples/raw2.c added (mode: 100644) (index 0000000..e8d73ae)
1 #define _GNU_SOURCE
2
3 #include <errno.h>
4 #include <string.h>
5 #include <strings.h>
6 #include <stdlib.h>
7 #include <unistd.h>
8 #include <sys/poll.h>
9 #include <sys/types.h>
10 #include <sys/socket.h>
11 #include <stdio.h>
12 #include <fcntl.h>
13 #include <netinet/in.h>
14 #include <sys/time.h>
15 #include <sys/ioctl.h>
16 #include <time.h>
17 #include <arpa/inet.h>
18 #include <stdarg.h>
19 #include <linux/if_ether.h>
20
21 #include <Conn.h>
22
23 /* Global variables */
24 static unsigned short debug = 9;
25
26 static FILE *Logf = NULL;
27 static char *log_file = "raw.log";
28 static int port = 9000;
29 static int maxconn = 0;
30
31
32 static void Log(unsigned short level, char *format, ...)
33 {
34 va_list ap;
35
36 if (level > debug)
37 return;
38
39 va_start(ap, format);
40 vfprintf(Logf, format, ap);
41 va_end(ap);
42 }
43
44 static void s_close(struct Conn *C)
45 {
46 Log(5, "%s (A connection will be closed [%s] on slot %d)\n",
47 __FUNCTION__, C->addr, C->slot);
48 }
49
50 static void s_data(struct Conn *C)
51 {
52 char *dump;
53 char *p;
54 int len;
55 struct timeval tv;
56
57 p = Conn_ibuf(C);
58 len = Conn_qlen(C);
59
60 Conn_last_time(C, &tv);
61
62 dump = Conn_dumphex(p, len);
63 Log(8, "%s: recv %d bytes at %d.%06d on slot %d: [%s]\n",
64 __FUNCTION__, len, tv.tv_sec, tv.tv_usec, C->slot, dump);
65 free(dump);
66
67 Conn_eatall(C);
68 }
69
70 static void s_error(struct Conn *C)
71 {
72 Log(1, "%s slot=%d C=%p [%s]\n",
73 __FUNCTION__, C == NULL ? -1 : C->slot, (void *) C,
74 Conn_strerror());
75 }
76
77 int main(void)
78 {
79 struct Conn *I4;
80 int ret;
81 struct timeval start;
82 int loops = 0;
83
84 Logf = fopen(log_file, "w");
85 if (!Logf) {
86 fprintf(stderr, "Cannot open log file [%s] [%s]\n",
87 log_file, strerror(errno));
88 return 1;
89 }
90 if (debug > 0)
91 setlinebuf(Logf);
92
93 daemon(0, 0);
94
95 gettimeofday(&start, NULL);
96 Log(0, "\nStarting at %ld...\n", start.tv_sec);
97 Log(0, "\tPort=%d\n", port);
98 Log(0, "\tLogFile=%s Debug=%d\n", log_file, debug);
99
100 /* set library output debug */
101 Conn_debug(Logf, debug);
102
103 ret = Conn_init(maxconn);
104 if (ret == -1) {
105 Log(0, "%s", Conn_strerror());
106 return 1;
107 }
108
109 Log(9, "Try to register IPv4 socket...\n");
110 I4 = Conn_socket(PF_PACKET, SOCK_RAW, ETH_P_IP);
111 if (I4 == NULL) {
112 Log(0, "Cannot create socket (%s)!\n",
113 Conn_strerror());
114 return 1;
115 }
116
117 Conn_close_cb = s_close;
118 Conn_error_cb = s_error;
119 Conn_read_cb = s_read;
120
121 while (1) {
122 ret = Conn_poll(10000);
123 if (ret == -1) {
124 Log(0, "Error calling Conn_poll [%s]!\n",
125 Conn_strerror());
126 return 1;
127 }
128
129 loops++;
130 if (ret == 0)
131 break;
132
133 /*
134 if (loops > 1000000)
135 break;
136 */
137 }
138
139 Log(0, "Finish!\n\n");
140
141 return 0;
142 }
File examples/s.c added (mode: 100644) (index 0000000..13143a0)
1 #define _GNU_SOURCE
2
3 #include <errno.h>
4 #include <string.h>
5 #include <strings.h>
6 #include <stdlib.h>
7 #include <unistd.h>
8 #include <sys/poll.h>
9 #include <sys/types.h>
10 #include <sys/socket.h>
11 #include <stdio.h>
12 #include <fcntl.h>
13 #include <netinet/in.h>
14 #include <sys/time.h>
15 #include <sys/ioctl.h>
16 #include <time.h>
17 #include <arpa/inet.h>
18 #include <stdarg.h>
19
20 #include <Conn.h>
21
22 /* Global variables */
23 static unsigned short debug = 1;
24
25 static FILE *Logf = NULL;
26 static char *log_file = "s.log";
27 static int port = 9000;
28 static short ipv4 = 1, ipv6 = 1;
29 static int maxconn = 0;
30
31 static void Log(unsigned short level, char *format, ...)
32 {
33 va_list ap;
34
35 if (level > debug)
36 return;
37
38 va_start(ap, format);
39 vfprintf(Logf, format, ap);
40 va_end(ap);
41 }
42
43 static void s_accept(struct Conn *C)
44 {
45 char *s;
46
47 Log(4, "%s (A connection was accepted from [%s] on slot %d. Set POLLIN and enq greeting...\n",
48 __FUNCTION__, C->addr, C->slot);
49
50 s = "Hello!\r\n";
51 Conn_enqueue(C, s, strlen(s));
52 Conn_close(C);
53 }
54
55 static void s_close(struct Conn *C)
56 {
57 Log(5, "%s (A connection will be closed [%s] on slot %d)\n",
58 __FUNCTION__, C->addr, C->slot);
59 }
60
61 static void s_data(struct Conn *C)
62 {
63 int len;
64 char *buf;
65 char *dump;
66
67 len = C->ibuf_tail - C->ibuf_head;
68 buf = C->ibuf + C->ibuf_head;
69
70 if (debug >= 8) {
71 dump = Conn_dump(buf, len);
72 Log(8, "%s: recv head=%d tail=%d bytes on slot %d: [%s]\n",
73 __FUNCTION__, C->ibuf_head, C->ibuf_tail,
74 C->slot, dump);
75 free(dump);
76 }
77
78 Log(8, " Send back: %s", buf);
79 Conn_enqueue(C, buf, len);
80
81 Conn_eatall(C);
82 }
83
84 static void s_error(struct Conn *C)
85 {
86 Log(1, "%s slot=%d C=%p\n",
87 __FUNCTION__, C == NULL ? -1 : C->slot, (void *) C);
88 }
89
90 int main(void)
91 {
92 struct Conn *I4 = NULL, *I6 = NULL;
93 int ret;
94 struct timeval start;
95 int loops = 0;
96
97 Logf = fopen(log_file, "w");
98 if (!Logf) {
99 fprintf(stderr, "Cannot open log file [%s] [%s]\n",
100 log_file, strerror(errno));
101 return 1;
102 }
103 if (debug > 0)
104 setlinebuf(Logf);
105
106 /*daemon(0, 0);*/
107
108 gettimeofday(&start, NULL);
109 Log(0, "\nStarting at %ld...\n", start.tv_sec);
110 Log(0, "\tPort=%d\n", port);
111 Log(0, "\tLogFile=%s Debug=%d\n", log_file, debug);
112 Log(0, "\tipv4=%s ipv6=%s\n", (ipv4 == 1) ? "on" : "off", (ipv6 == 1) ? "on" : "off");
113
114 /* set library output debug */
115 Conn_debug(Logf, debug);
116
117 ret = Conn_init(maxconn);
118 if (ret == -1) {
119 Log(0, "%s", Conn_strerror());
120 return 1;
121 }
122
123 if (ipv4 == 1) {
124 Log(9, "Try to register IPv4 socket...\n");
125 I4 = Conn_socket(PF_INET, SOCK_STREAM, port);
126 if (!I4)
127 Log(1, "Cannot bind on ipv4 socket [%s].\n", Conn_strerror());
128 }
129
130 if (ipv6 == 1) {
131 Log(9, "Try to register IPv6 socket...\n");
132 I6 = Conn_socket(PF_INET6, SOCK_STREAM, port);
133 if (!I6)
134 Log(1, "Cannot bind on ipv6 socket [%s].\n", Conn_strerror());
135 }
136
137 if ((I6 == NULL) && (I4 == NULL)) {
138 Log(0, "Cannot bind!\n");
139 return 1;
140 }
141
142 Conn_accept_cb = s_accept;
143 Conn_data_cb = s_data;
144 Conn_close_cb = s_close;
145 Conn_error_cb = s_error;
146
147 while (1) {
148 ret = Conn_poll(10000);
149 if (ret == -1) {
150 Log(0, "Error calling Conn_poll [%s]!\n", Conn_strerror());
151 return 1;
152 }
153
154 loops++;
155 if (ret == 0)
156 break;
157
158 /*
159 if (loops > 1000000)
160 break;
161 */
162 }
163
164 Log(0, "Finish!\n\n");
165
166 return 0;
167 }
File examples/s.run added (mode: 100755) (index 0000000..3b88a01)
1 #!/bin/bash
2
3 ulimit -n60000
4 ./s
File examples/timeout.c added (mode: 100644) (index 0000000..7b9b734)
1 #define _GNU_SOURCE
2
3 #include <errno.h>
4 #include <string.h>
5 #include <strings.h>
6 #include <stdlib.h>
7 #include <unistd.h>
8 #include <sys/poll.h>
9 #include <sys/types.h>
10 #include <sys/socket.h>
11 #include <stdio.h>
12 #include <fcntl.h>
13 #include <netinet/in.h>
14 #include <sys/time.h>
15 #include <sys/ioctl.h>
16 #include <time.h>
17 #include <arpa/inet.h>
18 #include <stdarg.h>
19
20 #include <Conn.h>
21
22 /* Global variables */
23 static unsigned short debug = 20;
24
25 static FILE *Logf = NULL;
26 static char *log_file = "timeout.log";
27
28
29 static void Log(unsigned short level, char *format, ...)
30 {
31 va_list ap;
32
33 if (level > debug)
34 return;
35
36 va_start(ap, format);
37 vfprintf(Logf, format, ap);
38 va_end(ap);
39 }
40
41 static void c_connected(struct Conn *C)
42 {
43 Log(4, "%s(A connection was estabilished on slot %d)\n",
44 __FUNCTION__, C->slot);
45
46
47 Conn_close(C);
48 }
49
50 static void c_close(struct Conn *C)
51 {
52 Log(5, "%s(Slot %d will close)\n",
53 __FUNCTION__, C->slot);
54 free(C->private);
55 }
56
57 static void c_data(struct Conn *C)
58 {
59 char *dump;
60
61 if (debug >= 8) {
62 dump = Conn_dump(C->ibuf + C->ibuf_head, Conn_qlen(C));
63 Log(8, "data: recv: %s\n", dump);
64 free(dump);
65 }
66
67 Conn_close(C);
68
69 Conn_eatall(C);
70 }
71
72 static void c_error(struct Conn *C)
73 {
74 Log(0, "%s Slot=%u [%s]\n",
75 __FUNCTION__, C->slot, Conn_strerror());
76 }
77
78 int main(void)
79 {
80 char *stat;
81 int ret;
82 struct Conn *C;
83
84 Logf = fopen(log_file, "a+");
85 if (!Logf) {
86 fprintf(stderr, "Cannot open log file [%s] [%s]\n",
87 log_file, strerror(errno));
88 return 1;
89 }
90 if (debug > 0)
91 setlinebuf(Logf);
92
93 Log(0, "Starting...\n");
94 Log(0, "\tLogFile=%s Debug=%d\n", log_file, debug);
95
96 Conn_debug(Logf, debug);
97
98 ret = Conn_init(0);
99 if (ret == -1) {
100 Log(0, "%s", Conn_strerror());
101 return 1;
102 }
103
104 Conn_connected_cb = c_connected;
105 Conn_data_cb = c_data;
106 Conn_close_cb = c_close;
107 Conn_error_cb = c_error;
108
109 /* Connect to google */
110 C = Conn_connect(PF_INET, SOCK_STREAM, "209.85.129.104", 80);
111 if (C == NULL) {
112 Log(0, "Error calling Conn_connect [%s]!\n",
113 Conn_strerror());
114 return 1;
115 }
116
117 /* Force a timeout for connect */
118 Conn_set(C, CONN_PARA_CONN_TIMEOUT, 1);
119
120 while (1) {
121 ret = Conn_poll(10);
122 if (ret == -1) {
123 Log(0, "Error in poll [%s]!\n",
124 Conn_strerror());
125 break;
126 }
127
128 if (ret == 0) {
129 Log(0, "Finish work!\n");
130 break;
131 }
132
133 if (debug >= 9) {
134 stat = Conn_status(0);
135 Log(9, "%s\n", stat);
136 free(stat);
137 }
138 }
139
140 return 0;
141 }
File examples/trigger.c added (mode: 100644) (index 0000000..8694363)
1 #define _GNU_SOURCE
2
3 #include <errno.h>
4 #include <string.h>
5 #include <strings.h>
6 #include <stdlib.h>
7 #include <unistd.h>
8 #include <sys/poll.h>
9 #include <sys/types.h>
10 #include <sys/socket.h>
11 #include <stdio.h>
12 #include <fcntl.h>
13 #include <netinet/in.h>
14 #include <sys/time.h>
15 #include <sys/ioctl.h>
16 #include <time.h>
17 #include <arpa/inet.h>
18 #include <stdarg.h>
19
20 #include <Conn.h>
21
22 /* Global variables */
23 static unsigned short debug = 1;
24
25
26 static void trigger(struct Conn *C)
27 {
28 printf("Trigger is running on %llu!\n", Conn_getid(C));
29 }
30
31 int main(void)
32 {
33 char *stat;
34 int ret;
35 struct Conn *C;
36
37 Conn_debug(NULL, debug);
38
39 ret = Conn_init(0);
40 if (ret == -1) {
41 printf("%s", Conn_strerror());
42 return 1;
43 }
44
45 /* Listen to a port */
46 C = Conn_socket(PF_INET, SOCK_STREAM, 60000);
47 if (C == NULL) {
48 printf("Error creating socket [%s]!\n",
49 Conn_strerror());
50 return 1;
51 }
52
53 /* Install connection specific trigger */
54 Conn_set_cb(C, CONN_CB_TRIGGER, trigger);
55
56 /* Force a timeout for connect (in seconds) */
57 Conn_set(C, CONN_PARA_TRIGGER, 3);
58
59 while (1) {
60 ret = Conn_poll(1000);
61 if (ret == -1) {
62 printf("Error in poll [%s]!\n",
63 Conn_strerror());
64 break;
65 }
66
67 if (ret == 0) {
68 printf("Finish work!\n");
69 break;
70 }
71
72 if (debug >= 9) {
73 stat = Conn_status(0);
74 printf("%s\n", stat);
75 free(stat);
76 }
77 }
78
79 return 0;
80 }
File examples/udp_s.c added (mode: 100644) (index 0000000..b7f10db)
1 #define _GNU_SOURCE
2
3 #include <errno.h>
4 #include <string.h>
5 #include <strings.h>
6 #include <stdlib.h>
7 #include <unistd.h>
8 #include <sys/poll.h>
9 #include <sys/types.h>
10 #include <sys/socket.h>
11 #include <stdio.h>
12 #include <fcntl.h>
13 #include <netinet/in.h>
14 #include <sys/time.h>
15 #include <sys/ioctl.h>
16 #include <time.h>
17 #include <arpa/inet.h>
18 #include <stdarg.h>
19
20 #include <Conn.h>
21
22 /* Global variables */
23 static unsigned short debug = 20;
24
25 static FILE *Logf = NULL;
26 static char *log_file = "udp_s.log";
27 static int port = 9000;
28 static short ipv4 = 1, ipv6 = 1;
29 static int maxconn = 0;
30 static struct sockaddr_in from;
31 static socklen_t from_len;
32
33
34 static void Log(unsigned short level, char *format, ...)
35 {
36 va_list ap;
37
38 if (level > debug)
39 return;
40
41 va_start(ap, format);
42 vfprintf(Logf, format, ap);
43 va_end(ap);
44 }
45
46 static void s_send(struct Conn *C)
47 {
48 int fd;
49 ssize_t ret;
50
51 Log(0, "%s\n", __FUNCTION__);
52
53 fd = Conn_get_fd(C);
54 from_len = sizeof(from);
55 ret = sendto(fd, "xxx\n", 4, 0, (struct sockaddr_in *) &from, from_len);
56 Log(0, "%s: ret = %d\n", __FUNCTION__, ret);
57 }
58
59 static void s_recv(struct Conn *C)
60 {
61 int fd, len;
62 unsigned char buf[10240];
63 char *dump;
64 ssize_t ret;
65
66 Log(0, "%s...\n", __FUNCTION__);
67
68 fd = Conn_get_fd(C);
69 from_len = sizeof(from);
70 ret = recvfrom(fd, buf, sizeof(buf), 0, (struct sockaddr *) &from,
71 &from_len);
72 if (ret == -1) {
73 Log(0, "Error %d!\n", ret);
74 return;
75 }
76 len = ret;
77
78 if (debug >= 8) {
79 dump = Conn_dump(buf, len);
80 Log(8, "%s: recv head=%d tail=%d bytes on slot %d: [%s]\n",
81 __FUNCTION__, C->ibuf_head, C->ibuf_tail,
82 C->slot, dump);
83 free(dump);
84 }
85
86 Log(8, "Send back: %s", buf);
87 Conn_enqueue(C, buf, len);
88 }
89
90 static void s_error(struct Conn *C)
91 {
92 Log(1, "%s slot=%d id=%llu\n",
93 __FUNCTION__, C->slot, Conn_getid(C));
94 }
95
96 int main(void)
97 {
98 struct Conn *I4 = NULL, *I6 = NULL;
99 int ret;
100 struct timeval start;
101 int loops = 0;
102
103 Logf = fopen(log_file, "w");
104 if (!Logf) {
105 fprintf(stderr, "Cannot open log file [%s] [%s]\n",
106 log_file, strerror(errno));
107 return 1;
108 }
109 if (debug > 0)
110 setlinebuf(Logf);
111
112 /*daemon(0, 0);*/
113
114 gettimeofday(&start, NULL);
115 Log(0, "\nStarting at %ld...\n", start.tv_sec);
116 Log(0, "\tPort=%d\n", port);
117 Log(0, "\tLogFile=%s Debug=%d\n", log_file, debug);
118 Log(0, "\tipv4=%s ipv6=%s\n", (ipv4 == 1) ? "on" : "off", (ipv6 == 1) ? "on" : "off");
119
120 /* set library output debug */
121 Conn_debug(Logf, debug);
122
123 ret = Conn_init(maxconn);
124 if (ret == -1) {
125 Log(0, "%s", Conn_strerror());
126 return 1;
127 }
128
129 if (ipv4 == 1) {
130 Log(9, "Try to register IPv4 socket...\n");
131 I4 = Conn_socket(PF_INET, SOCK_DGRAM, port);
132 if (!I4)
133 Log(1, "Cannot bind on ipv4 socket [%s].\n", Conn_strerror());
134 }
135
136 if (ipv6 == 1) {
137 Log(9, "Try to register IPv6 socket...\n");
138 I6 = Conn_socket(PF_INET6, SOCK_DGRAM, port);
139 if (!I6)
140 Log(1, "Cannot bind on ipv6 socket [%s].\n", Conn_strerror());
141 }
142
143 if ((I6 == NULL) && (I4 == NULL)) {
144 Log(0, "Cannot bind!\n");
145 return 1;
146 }
147
148 Conn_recv_cb = s_recv;
149 Conn_send_cb = s_send;
150 Conn_error_cb = s_error;
151
152 while (1) {
153 ret = Conn_poll(10000);
154 if (ret == -1) {
155 Log(0, "Error calling Conn_poll [%s]!\n", Conn_strerror());
156 return 1;
157 }
158
159 loops++;
160 if (ret == 0)
161 break;
162
163 /*
164 if (loops > 1000000)
165 break;
166 */
167 }
168
169 Log(0, "Finish!\n\n");
170
171 return 0;
172 }
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