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)
Lots of changes everywhere 91b9113e8f92db07c079c005273683f2e868910c Catalin(ux) M. BOIE 2018-01-12 19:06:04
Require openssl (for websocket) b4b34eb88f38bfd421187da76611cc54476d7309 Catalin(ux) M. BOIE 2017-12-30 23:44:50
Very important fixes 01e33f06a5cdc52fb3795158fd838fcca7055dda Catalin(ux) M. BOIE 2017-12-30 23:39:17
Bump version to 1.0.37 54e8f3bcaf7f7e096c454563039a545a4abb1bf0 Catalin(ux) M. BOIE 2017-12-30 22:13:12
Lots of small fixes 4894de0472e571b8c78294de527bf70089096545 Catalin(ux) M. BOIE 2017-12-30 22:11:09
Checkpoint b6bf45330f046da40d762b6fd10d1bb97bc40036 Catalin(ux) M. BOIE 2017-12-28 00:13:09
Fixed libConn*.so instalation. df1bef9190d30dd11fcd150b41810ce18278b74f Catalin(ux) M. BOIE 2015-04-25 14:43:37
libConn1.so was not included in spec file. dd99625a7fb70d66fa5a91371fb4d2eaf7a4f23d Catalin(ux) M. BOIE 2015-04-25 14:39:32
Small fixes for build system. ab12cbbe149933cbf1b9a9900be1a45d63ee0b29 Catalin(ux) M. BOIE 2015-04-25 14:17:14
Build fixes e7521468199d4da53461fb0c1ffa08e1913c1e9f Catalin(ux) M. BOIE 2015-04-24 19:18:42
Checkpoint before switching to processes not threads de43b387557dde215ab1210838d396e7e7b22c4f Catalin(ux) M. BOIE 2015-01-14 04:13:00
Wpools work now\! f875d6bea1777c3a290bf9bb1aa047f26c935a63 Catalin(ux) M. BOIE 2013-11-13 20:51:13
WIP 1d246f2130d4acf8c267e82051b250a623da6870 Catalin(ux) M. BOIE 2013-10-16 19:57:04
WIP 6387026db3ce7983e610887565a282f4124d4092 Catalin(ux) M. BOIE 2013-10-14 20:06:49
WIP 15f063f9d34d3f7b7ae9d9e83f59b4077515122b Catalin(ux) M. BOIE 2010-09-30 22:01:30
Switch licence to LGPLv3+; Do not stupidly close master socket. d3b1c4ccd591627e7faa0eeaaa3b2bc1ee20709e Catalin(ux) M. BOIE 2013-08-14 04:09:36
Duilder fixes. Removed -O0. Fixed spec file. d8a03dced52e918b6f66a05dfd64a3c75c07c91b Catalin(ux) M. BOIE 2011-12-14 09:12:55
Fixed a stupid logging bug (invalid number of parameters). e7d4c38d0130a142ac6c409c63d63201d2af08e2 Catalin(ux) M. BOIE 2010-12-22 16:46:47
Ignore all Changelog files. fa45b63d3db958228f44bcb3d6431d60f94d1147 Catalin(ux) M. BOIE 2010-12-22 16:46:16
Added mailmap file. a57dcfd6bdf6c8c86161cf7ce3fff942a714a2b9 Catalin(ux) M. BOIE 2010-12-22 16:46:04
Commit 91b9113e8f92db07c079c005273683f2e868910c - Lots of changes everywhere
Author: Catalin(ux) M. BOIE
Author date (UTC): 2018-01-12 19:06
Committer name: Catalin(ux) M. BOIE
Committer date (UTC): 2018-01-13 06:15
Parent(s): b4b34eb88f38bfd421187da76611cc54476d7309
Signing key:
Tree: 5b4c55adcdb73a406340b720391848b9529de946
File Lines added Lines deleted
.exclude 1 0
.gitignore 1 1
Conn.c 65 31
Conn.h 5 3
Conn.spec.in 2 2
Conn_intern.h 37 25
Conn_web.c 21 15
Makefile.in 8 7
Makefile.include.in 1 0
TODO 2 1
duilder 1 1
duilder.conf 3 0
examples/.gitignore 3 0
examples/Makefile 6 10
examples/websocket1.c 72 32
examples/ws1.c 1 1
tests/Makefile 4 1
tests/t2.c 2 0
tests/t3.c 2 15
File .exclude changed (mode: 100644) (index 3a04894..38f2534)
1 1 *.gz *.gz
2 2 *.out *.out
3 3 Makefile Makefile
4 Makefile.include
4 5 *.strace *.strace
5 6 *.asm *.asm
6 7 examples/*.strace.* examples/*.strace.*
File .gitignore changed (mode: 100644) (index bd7f50c..807f4b3)
1 1 Changelog* Changelog*
2 2 /Makefile /Makefile
3 /Makefile.include
3 4 Conn.spec Conn.spec
4 5 Conn_config.h Conn_config.h
5 6 *.o *.o
 
... ... Conn_config.h
9 10 *.log *.log
10 11 duilder_release duilder_release
11 12 *.out *.out
12 cppcheck.out
13 13 *.asm *.asm
14 14 *.strace *.strace
15 15 *.pcap *.pcap
File Conn.c changed (mode: 100644) (index 6fdb2aa..b435807)
... ... struct Conn_wpool *Conn_wpool_create(const unsigned short workers)
202 202 int Conn_wpool_destroy(struct Conn_wpool *wp) int Conn_wpool_destroy(struct Conn_wpool *wp)
203 203 { {
204 204 int i; int i;
205 struct Conn_wpool_worker *w;
206 205
207 206 for (i = 0; i < wp->workers; i++) { for (i = 0; i < wp->workers; i++) {
207 struct Conn_wpool_worker *w;
208
208 209 w = &wp->ww[i]; w = &wp->ww[i];
209 210
210 211 if (w->inited == 0) if (w->inited == 0)
 
... ... char *Conn_dump(const void *buf_src0, const size_t len_src)
433 434 unsigned int i, j; unsigned int i, j;
434 435 char tmp[3]; char tmp[3];
435 436 char *buf_dst; char *buf_dst;
436 unsigned char c;
437 437 const unsigned char *buf_src = buf_src0; const unsigned char *buf_src = buf_src0;
438 438
439 439 Log(30, "\tConn_dump(%p, len=%zu)\n", Log(30, "\tConn_dump(%p, len=%zu)\n",
 
... ... char *Conn_dump(const void *buf_src0, const size_t len_src)
445 445
446 446 j = 0; j = 0;
447 447 for (i = 0; i < len_src; i++) { for (i = 0; i < len_src; i++) {
448 unsigned char c;
449
448 450 c = buf_src[i]; c = buf_src[i];
449 451 if ((c < 32) || (c > 127)) { if ((c < 32) || (c > 127)) {
450 452 buf_dst[j++] = '['; buf_dst[j++] = '[';
 
... ... char *Conn_dumphex(const void *buf_src0, const size_t len_src)
467 469 unsigned int i, j; unsigned int i, j;
468 470 char tmp[3]; char tmp[3];
469 471 char *buf_dst; char *buf_dst;
470 unsigned char c;
471 472 const unsigned char *buf_src = buf_src0; const unsigned char *buf_src = buf_src0;
472 473
473 474 Log(30, "\tConn_dumphex(%p, len=%zu)\n", Log(30, "\tConn_dumphex(%p, len=%zu)\n",
 
... ... char *Conn_dumphex(const void *buf_src0, const size_t len_src)
479 480
480 481 j = 0; j = 0;
481 482 for (i = 0; i < len_src; i++) { for (i = 0; i < len_src; i++) {
483 unsigned char c;
484
482 485 c = buf_src[i]; c = buf_src[i];
483 486 snprintf(tmp, sizeof(tmp), "%02x", c); snprintf(tmp, sizeof(tmp), "%02x", c);
484 487 buf_dst[j++] = tmp[0]; buf_dst[j++] = tmp[0];
 
... ... __hot static void Conn_free_intern(struct Conn *C)
774 777 C->next = NULL; C->next = NULL;
775 778 } }
776 779
780 if (C->private) {
781 free(C->private);
782 C->private = NULL;
783 }
784
777 785 /* Add it to free list of the worker pool */ /* Add it to free list of the worker pool */
778 786 if (likely(C->worker)) { if (likely(C->worker)) {
779 787 struct Conn_wpool_worker *worker = C->worker; struct Conn_wpool_worker *worker = C->worker;
 
... ... static inline int Conn_change_obj(int epoll_fd, struct Conn *C,
942 950 __hot static void Conn_default_cbs_recv(struct Conn *C) __hot static void Conn_default_cbs_recv(struct Conn *C)
943 951 { {
944 952 ssize_t n; ssize_t n;
945 unsigned int max, xfer_in_this_call;
953 unsigned int xfer_in_this_call;
946 954 int r, xerrno; int r, xerrno;
947 955 char *dump, call_callback; char *dump, call_callback;
948 956
 
... ... __hot static void Conn_default_cbs_recv(struct Conn *C)
953 961 call_callback = 0; call_callback = 0;
954 962 xfer_in_this_call = 0; xfer_in_this_call = 0;
955 963 while (1) { while (1) {
964 unsigned int max;
965
956 966 if ((Conn_max_recv > 0) && (xfer_in_this_call >= Conn_max_recv)) { if ((Conn_max_recv > 0) && (xfer_in_this_call >= Conn_max_recv)) {
957 967 Log(3, "\tRecv limit reached. Add to extra queue.\n"); Log(3, "\tRecv limit reached. Add to extra queue.\n");
958 968 break; break;
 
... ... __hot static void Conn_default_cbs_recv(struct Conn *C)
1044 1054 __hot static void Conn_default_cbs_send(struct Conn *C) __hot static void Conn_default_cbs_send(struct Conn *C)
1045 1055 { {
1046 1056 ssize_t n; ssize_t n;
1047 unsigned int max;
1048 1057 int xerrno, r; int xerrno, r;
1049 unsigned int count;
1050 char *buf;
1051 1058 char *dump; char *dump;
1052 1059
1053 1060 Log(5, "%llu %s C=%p next=%p fd=%d head=%u tail=%u size=%u\n", Log(5, "%llu %s C=%p next=%p fd=%d head=%u tail=%u size=%u\n",
 
... ... __hot static void Conn_default_cbs_send(struct Conn *C)
1055 1062 C->obuf_tail, C->obuf_size); C->obuf_tail, C->obuf_size);
1056 1063
1057 1064 while (1) { while (1) {
1065 unsigned int max, count;
1066 char *buf;
1067
1058 1068 buf = C->obuf + C->obuf_head; buf = C->obuf + C->obuf_head;
1059 1069 count = Conn_oqlen(C); count = Conn_oqlen(C);
1060 1070 if (unlikely(count == 0)) { if (unlikely(count == 0)) {
 
... ... static char *Conn_status_slot(struct Conn *C)
1391 1401 char flags[128], flags_prefix[3], flags_postfix[2]; char flags[128], flags_prefix[3], flags_postfix[2];
1392 1402 char *local_addr, *remote_addr; char *local_addr, *remote_addr;
1393 1403 int local_port, remote_port; int local_port, remote_port;
1394 char flags_tmp[64];
1395 1404
1396 1405 /* flags */ /* flags */
1397 1406 strcpy(flags, ""); strcpy(flags, "");
 
... ... static char *Conn_status_slot(struct Conn *C)
1399 1408 strcpy(flags_postfix, ""); strcpy(flags_postfix, "");
1400 1409
1401 1410 if (C->auto_reconnect) { if (C->auto_reconnect) {
1411 char flags_tmp[64];
1412
1402 1413 strcat(flags, flags_prefix); strcat(flags, flags_prefix);
1403 1414 snprintf(flags_tmp, sizeof(flags_tmp), "autoreconnect_in_%ld/%u", snprintf(flags_tmp, sizeof(flags_tmp), "autoreconnect_in_%ld/%u",
1404 1415 (C->tryat == 0) ? 0 : C->tryat - Conn_now.tv_sec, (C->tryat == 0) ? 0 : C->tryat - Conn_now.tv_sec,
 
... ... char *Conn_status(const unsigned int flags)
1538 1549 gettimeofday(&Conn_now, NULL); gettimeofday(&Conn_now, NULL);
1539 1550 /* TODO: "len += " is incorrect */ /* TODO: "len += " is incorrect */
1540 1551 tmp_len = snprintf(tmp, sizeof(tmp), tmp_len = snprintf(tmp, sizeof(tmp),
1541 "Conn_pending=%d Conn_no/Conn_max=%d/%d Conn_total=%lu"
1542 " Conn_uptime=%lus Conn_allocated=%d Conn_work_to_do=%u"
1552 "Conn_pending=%u Conn_no/Conn_max=%u/%u Conn_total=%lu"
1553 " Conn_uptime=%lus Conn_allocated=%u Conn_work_to_do=%u"
1543 1554 " Conn_mem_structs=%llu Conn_mem_buffers_in/out=%llu/%llu\n", " Conn_mem_structs=%llu Conn_mem_buffers_in/out=%llu/%llu\n",
1544 1555 Conn_pending, Conn_no, Conn_max, Conn_total, Conn_pending, Conn_no, Conn_max, Conn_total,
1545 1556 Conn_now.tv_sec - Conn_start, Conn_allocated, Conn_work_to_do, Conn_now.tv_sec - Conn_start, Conn_allocated, Conn_work_to_do,
1546 1557 Conn_mem_structs, Conn_mem_buffers_in, Conn_mem_buffers_out); Conn_mem_structs, Conn_mem_buffers_in, Conn_mem_buffers_out);
1547 if (tmp_len < 0)
1558 if (tmp_len < 0) {
1559 free(buf);
1548 1560 return strdup("snprintf error"); return strdup("snprintf error");
1561 }
1549 1562 if (len + (unsigned int) tmp_len < max) { if (len + (unsigned int) tmp_len < max) {
1550 1563 strcat(buf, tmp); strcat(buf, tmp);
1551 1564 len += (unsigned int) tmp_len; len += (unsigned int) tmp_len;
 
... ... char *Conn_status(const unsigned int flags)
1603 1616 else else
1604 1617 per_slot = Conn_status_slot_html(C); per_slot = Conn_status_slot_html(C);
1605 1618 tmp_len = snprintf(tmp, sizeof(tmp), "%s\n", per_slot); tmp_len = snprintf(tmp, sizeof(tmp), "%s\n", per_slot);
1606 if (tmp_len < 0)
1619 if (tmp_len < 0) {
1620 free(buf);
1607 1621 return strdup("snprintf error"); return strdup("snprintf error");
1622 }
1608 1623 len += (unsigned int) tmp_len; len += (unsigned int) tmp_len;
1609 1624 if (len < max) if (len < max)
1610 1625 strcat(buf, tmp); strcat(buf, tmp);
 
... ... char *Conn_status(const unsigned int flags)
1628 1643 tmp_len = snprintf(tmp, sizeof(tmp), "Total speed I/O: %s/%s" tmp_len = snprintf(tmp, sizeof(tmp), "Total speed I/O: %s/%s"
1629 1644 " Total bytes I/O: %llu/%llu\n", " Total bytes I/O: %llu/%llu\n",
1630 1645 speedi, speedo, bi, bo); speedi, speedo, bi, bo);
1631 if (tmp_len < 0)
1646 if (tmp_len < 0) {
1647 free(buf);
1632 1648 return strdup("snprintf error"); return strdup("snprintf error");
1649 }
1633 1650 if (len + (unsigned int) tmp_len < max) { if (len + (unsigned int) tmp_len < max) {
1634 1651 strcat(buf, tmp); strcat(buf, tmp);
1635 1652 len += (unsigned int) tmp_len; len += (unsigned int) tmp_len;
 
... ... static void Conn_rtrim(char *s, const char *chars)
1915 1932 */ */
1916 1933 void Conn_for_every_line(struct Conn *C, void (*cb)(struct Conn *C, char *line)) void Conn_for_every_line(struct Conn *C, void (*cb)(struct Conn *C, char *line))
1917 1934 { {
1918 char *line;
1919 size_t line_size;
1920
1921 1935 if (cb == NULL) if (cb == NULL)
1922 1936 return; return;
1923 1937
1924 1938 while (1) { while (1) {
1939 char *line;
1940 size_t line_size;
1941
1925 1942 /* TODO: Conn_get_line may also return the size */ /* TODO: Conn_get_line may also return the size */
1926 1943 line = Conn_get_line(C); line = Conn_get_line(C);
1927 1944 if (line == NULL) if (line == NULL)
 
... ... void Conn_for_every_line(struct Conn *C, void (*cb)(struct Conn *C, char *line))
1944 1961 int Conn_printf(struct Conn *C, const char *format, ...) int Conn_printf(struct Conn *C, const char *format, ...)
1945 1962 { {
1946 1963 va_list ap; va_list ap;
1947 char *s;
1948 int d, r, ret;
1949 ssize_t slen;
1950 unsigned long len;
1951 char tmp[64];
1964 int ret;
1952 1965
1953 1966 ret = 0; ret = 0;
1954 1967 va_start(ap, format); va_start(ap, format);
1955 1968 while (likely(*format)) { while (likely(*format)) {
1969 char *s;
1970 ssize_t slen;
1971 unsigned long len;
1972 char tmp[64];
1973 int d, r;
1974
1956 1975 /* Find first formatting char */ /* Find first formatting char */
1957 1976 s = strchr(format, '%'); s = strchr(format, '%');
1958 1977 if (unlikely(!s)) { if (unlikely(!s)) {
 
... ... __hot static struct Conn *Conn_alloc_prepare(struct Conn *C)
2113 2132 __hot struct Conn *Conn_alloc(void) __hot struct Conn *Conn_alloc(void)
2114 2133 { {
2115 2134 struct Conn *C; struct Conn *C;
2116 int r;
2117 2135
2118 2136 Log(10, "%s Conn_no=%d Conn_max=%d\n", Log(10, "%s Conn_no=%d Conn_max=%d\n",
2119 2137 __func__, Conn_no, Conn_max); __func__, Conn_no, Conn_max);
 
... ... __hot struct Conn *Conn_alloc(void)
2125 2143 } }
2126 2144
2127 2145 if (unlikely(Conn_free.head == NULL)) { if (unlikely(Conn_free.head == NULL)) {
2146 int r;
2147
2128 2148 r = pool_grow(&Conn_free, 4); r = pool_grow(&Conn_free, 4);
2129 2149 if (unlikely(r != 0)) { if (unlikely(r != 0)) {
2130 2150 snprintf(Conn_error, sizeof(Conn_error), snprintf(Conn_error, sizeof(Conn_error),
 
... ... __hot struct Conn *Conn_alloc(void)
2147 2167 __hot static struct Conn *Conn_alloc_worker(struct Conn_wpool_worker *w) __hot static struct Conn *Conn_alloc_worker(struct Conn_wpool_worker *w)
2148 2168 { {
2149 2169 struct Conn *C; struct Conn *C;
2150 int r;
2151 2170
2152 2171 if (unlikely(w->free.head == NULL)) { if (unlikely(w->free.head == NULL)) {
2172 int r;
2173
2153 2174 r = pool_grow(&w->free, CONN_BULK_ALLOC); r = pool_grow(&w->free, CONN_BULK_ALLOC);
2154 2175 if (unlikely(r != 0)) { if (unlikely(r != 0)) {
2155 2176 snprintf(Conn_error, sizeof(Conn_error), snprintf(Conn_error, sizeof(Conn_error),
 
... ... __hot static void Conn_accept(struct Conn *C)
2296 2317 */ */
2297 2318 static inline void Conn_poll_cb(struct Conn *C, const unsigned int revents) static inline void Conn_poll_cb(struct Conn *C, const unsigned int revents)
2298 2319 { {
2299 char poll_status[16];
2300
2301 2320 if (unlikely(Conn_debug_level > 5)) { if (unlikely(Conn_debug_level > 5)) {
2321 char poll_status[16];
2322
2302 2323 Conn_poll_status(revents, poll_status); Conn_poll_status(revents, poll_status);
2303 2324 Log(0, "%llu %s revents=%s\n", Log(0, "%llu %s revents=%s\n",
2304 2325 C->id, __func__, poll_status); C->id, __func__, poll_status);
 
... ... static inline int Conn_dispatch_events(struct Conn_wpool_worker *w,
2403 2424 { {
2404 2425 int i, events; int i, events;
2405 2426 struct Conn *C; struct Conn *C;
2406 char sevents[16];
2407 2427 ssize_t r; ssize_t r;
2408 2428
2409 2429 Log(10, "%s timeout2=%dms e_size=%hu...\n", __func__, Log(10, "%s timeout2=%dms e_size=%hu...\n", __func__,
 
... ... static inline int Conn_dispatch_events(struct Conn_wpool_worker *w,
2428 2448 return 0; return 0;
2429 2449
2430 2450 if (unlikely(Conn_debug_level > 8)) { if (unlikely(Conn_debug_level > 8)) {
2451 char sevents[16];
2452
2431 2453 Log(0, "\tProcessing %d event(s):\n", events); Log(0, "\tProcessing %d event(s):\n", events);
2432 2454 for (i = 0; i < events; i++) { for (i = 0; i < events; i++) {
2433 2455 C = e[i].data.ptr; C = e[i].data.ptr;
 
... ... void Conn_split_free(struct Conn_split **s)
2699 2721 struct Conn_split *Conn_split(const char *line0) struct Conn_split *Conn_split(const char *line0)
2700 2722 { {
2701 2723 char *p; char *p;
2702 struct Conn_split *ret = NULL;
2724 struct Conn_split *ret;
2703 2725 struct Conn_split_cell *q; struct Conn_split_cell *q;
2704 2726 char search_for; char search_for;
2705 2727 char *left, *right; char *left, *right;
 
... ... char *Conn_strerror(void)
2912 2934 return Conn_error; return Conn_error;
2913 2935 } }
2914 2936
2937 void Conn_set_error(const char *format, ...)
2938 {
2939 va_list ap;
2940
2941 va_start(ap, format);
2942 vsnprintf(Conn_error, sizeof(Conn_error), format, ap);
2943 va_end(ap);
2944 }
2945
2915 2946 /* /*
2916 2947 * Difference between two timeval strutures, in milliseconds * Difference between two timeval strutures, in milliseconds
2917 2948 */ */
 
... ... int Conn_shutdown(void)
3045 3076 */ */
3046 3077 __hot int Conn_enqueue_wait(struct Conn *C, const void *buf, const unsigned int count) __hot int Conn_enqueue_wait(struct Conn *C, const void *buf, const unsigned int count)
3047 3078 { {
3048 int r;
3049 char *dump;
3050
3051 3079 if (unlikely(Conn_debug_level >= 10)) { if (unlikely(Conn_debug_level >= 10)) {
3080 char *dump;
3081
3052 3082 dump = Conn_dump(buf, count); dump = Conn_dump(buf, count);
3053 3083 Log(0, "%llu %s Try to enqueue %d byte(s) [%s]...\n", Log(0, "%llu %s Try to enqueue %d byte(s) [%s]...\n",
3054 3084 C->id, __func__, count, dump); C->id, __func__, count, dump);
 
... ... __hot int Conn_enqueue_wait(struct Conn *C, const void *buf, const unsigned int
3056 3086 } }
3057 3087
3058 3088 if (unlikely(C->obuf_size - C->obuf_tail < count)) { if (unlikely(C->obuf_size - C->obuf_tail < count)) {
3089 int r;
3090
3059 3091 r = Conn_try_expand_buf(C, 0, count); r = Conn_try_expand_buf(C, 0, count);
3060 3092 if (unlikely(r != 0)) if (unlikely(r != 0))
3061 3093 return -1; return -1;
 
... ... __cold static struct Conn *Conn_clone(struct Conn *C)
3166 3198 static int Conn_prepare_socket(struct Conn *C, struct sockaddr *bind_psa, static int Conn_prepare_socket(struct Conn *C, struct sockaddr *bind_psa,
3167 3199 socklen_t bind_sock_len) socklen_t bind_sock_len)
3168 3200 { {
3169 int fd, i, ret;
3201 int fd, i;
3170 3202
3171 3203 fd = socket(C->sock_domain, C->sock_type | SOCK_NONBLOCK | SOCK_CLOEXEC, fd = socket(C->sock_domain, C->sock_type | SOCK_NONBLOCK | SOCK_CLOEXEC,
3172 3204 C->sock_protocol); C->sock_protocol);
 
... ... static int Conn_prepare_socket(struct Conn *C, struct sockaddr *bind_psa,
3194 3226 } }
3195 3227
3196 3228 if (C->type == CONN_TYPE_MASTER) { if (C->type == CONN_TYPE_MASTER) {
3229 int ret;
3230
3197 3231 i = 1; i = 1;
3198 3232 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i)); setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i));
3199 3233
File Conn.h changed (mode: 100644) (index 6eeb574..c20cfbd)
... ... double Conn_split_get_d(const struct Conn_split *s,
64 64 /* conn */ /* conn */
65 65 unsigned long long Conn_lifetime(struct Conn *C); unsigned long long Conn_lifetime(struct Conn *C);
66 66 char *Conn_strerror(void); char *Conn_strerror(void);
67 void Conn_set_error(const char *format, ...);
67 68 long long Conn_time_diff(const struct timeval *t1, long long Conn_time_diff(const struct timeval *t1,
68 69 const struct timeval *t2); const struct timeval *t2);
69 70 char *Conn_errno(const struct Conn *C); char *Conn_errno(const struct Conn *C);
 
... ... int Conn_web_header_lookup(char *out, const size_t out_size,
152 153 /* web server - websocket */ /* web server - websocket */
153 154 struct Conn_web_ws struct Conn_web_ws
154 155 { {
155 unsigned char fin:1;
156 unsigned char opcode:4;
157 unsigned char mask:1;
156 unsigned int fin:1;
157 unsigned int opcode:4;
158 unsigned int mask:1;
159 unsigned int pad:26;
158 160 unsigned char maskkey[4]; unsigned char maskkey[4];
159 161 unsigned long long len; unsigned long long len;
160 162 }; };
File Conn.spec.in changed (mode: 100644) (index 81719e1..5423bbc)
... ... rm -rf ${RPM_BUILD_ROOT}
37 37 %files %files
38 38 %attr (-,root,root) %attr (-,root,root)
39 39 %{_includedir}/* %{_includedir}/*
40 %{_libdir}/libConn.so.1
41 40 %{_libdir}/libConn.so.@VER@ %{_libdir}/libConn.so.@VER@
42 %{_libdir}/libConn1.so
41 %{_libdir}/libConn.so.1
42 %{_libdir}/libConn.so
43 43 %doc README Changelog examples INSTALL %doc README Changelog examples INSTALL
44 44
45 45 %changelog %changelog
File Conn_intern.h changed (mode: 100644) (index 29ae224..9529479)
... ... struct Conn_pool
49 49 struct Conn *head, *tail; struct Conn *head, *tail;
50 50 unsigned int allocated; unsigned int allocated;
51 51 unsigned short next_block; unsigned short next_block;
52 unsigned short pad;
52 53 void *blocks[4096]; /* TODO: make it dynamic */ void *blocks[4096]; /* TODO: make it dynamic */
53 54 }; };
54 55
55 56 struct Conn_wpool_worker struct Conn_wpool_worker
56 57 { {
57 58 int epoll_fd; int epoll_fd;
59 int timer_fd;
58 60 struct epoll_event events[CONN_EVENTS_SLOTS]; struct epoll_event events[CONN_EVENTS_SLOTS];
59 unsigned char inited:1;
61 unsigned short inited:1;
62 unsigned short pad1:15;
63 unsigned short id; /* Used for logging */
60 64 int control; /* socket to communicate with parent */ int control; /* socket to communicate with parent */
61 65 pid_t pid; pid_t pid;
66 int pad2;
62 67 struct Conn *conns_head, *conns_tail; struct Conn *conns_head, *conns_tail;
63 unsigned short id; /* Used for logging */
64 int timer_fd;
65 68
66 69 /* Keep track of free structures */ /* Keep track of free structures */
67 70 struct Conn_pool free; struct Conn_pool free;
 
... ... struct Conn_wpool
75 78 { {
76 79 int epoll_fd; int epoll_fd;
77 80 unsigned short workers; unsigned short workers;
78 struct Conn_wpool_worker *ww;
79 81 unsigned short next; /* next worker to be choosen */ unsigned short next; /* next worker to be choosen */
80 82 unsigned short refs; unsigned short refs;
83 unsigned short pad1;
84 unsigned int pad2;
85 struct Conn_wpool_worker *ww;
81 86 }; };
82 87
83 88 /* /*
 
... ... struct Conn
107 112 unsigned char state; unsigned char state;
108 113 unsigned char error_state; unsigned char error_state;
109 114
110 char *ibuf;
111 unsigned int ibuf_size, ibuf_head, ibuf_tail;
115 /* Flags */
116 unsigned char auto_reconnect:1;
117 unsigned char close_after_send:1;
118 unsigned char shutdown_after_send:1;
119 unsigned char local_dirty:1;
120 unsigned char remote_dirty:1;
121 unsigned char pad1:3;
112 122
113 char *obuf;
123 unsigned int ibuf_size, ibuf_head, ibuf_tail;
114 124 unsigned int obuf_size, obuf_head, obuf_tail; unsigned int obuf_size, obuf_head, obuf_tail;
125 char *ibuf;
126 char *obuf;
115 127
116 128 struct timeval trecv, tsend; /* last time we saw an receive/send */ struct timeval trecv, tsend; /* last time we saw an receive/send */
117 129 unsigned int idle; /* idle time allowed TODO: ms? */ unsigned int idle; /* idle time allowed TODO: ms? */
 
... ... struct Conn
130 142 char addr[40], bind_addr[40]; char addr[40], bind_addr[40];
131 143 int port, bind_port; int port, bind_port;
132 144
145 struct Conn_cbs cbs; /* Specific callbacks */
146
133 147 unsigned long long bi, bo; unsigned long long bi, bo;
134 148
135 149 void *private; /* private use by user */ void *private; /* private use by user */
136 150
151 time_t start;
152
153 unsigned long long id; /* the id of a connection */
154
155 int xerrno;
156
137 157 /* reconnect stuff */ /* reconnect stuff */
138 158 unsigned int retries; unsigned int retries;
139 159 unsigned int delay; /* delay between reconnects */ unsigned int delay; /* delay between reconnects */
140 160 unsigned int tryat; /* when we go to CONNECT_a state */ unsigned int tryat; /* when we go to CONNECT_a state */
141 161
142 int xerrno;
143
144 time_t start;
145
146 /* Flags - TODO: remove 'flags' field */
147 unsigned char auto_reconnect:1;
148 unsigned char close_after_send:1;
149 unsigned char shutdown_after_send:1;
150 unsigned char local_dirty:1;
151 unsigned char remote_dirty:1;
152
153 162 /* bandwidth stuff */ /* bandwidth stuff */
154 struct timeval band_lasttime; /* last time tokens were added */
155 163 unsigned int band_tokens; /* 1 token -> 1000 bytes */ unsigned int band_tokens; /* 1 token -> 1000 bytes */
156 164 unsigned int band_factor; /* tokens cannot go past f * w */ unsigned int band_factor; /* tokens cannot go past f * w */
165 struct timeval band_lasttime; /* last time tokens were added */
157 166 unsigned int band_width; /* in 1000b increments */ unsigned int band_width; /* in 1000b increments */
158 167
159 unsigned long long id; /* the id of a connection */
160
161 struct Conn_cbs cbs; /* Specific callbacks */
162
168 unsigned int pad2;
163 169 struct timeval time_open; /* When a connect succeded */ /* TODO: why not use start? */ struct timeval time_open; /* When a connect succeded */ /* TODO: why not use start? */
164 170
165 171 /* wpool */ /* wpool */
166 172 struct Conn_wpool *wp; /* Worker pool associated with this conn */ struct Conn_wpool *wp; /* Worker pool associated with this conn */
167 struct Conn_wpool_worker *worker; /* used to link C in active list of a worker */
173 struct Conn_wpool_worker
174 *worker; /* used to link C in active list of a worker */
168 175
169 176 /* web server */ /* web server */
170 177 struct Conn_web *web; /* everything needed for web (urls etc.) - common for all childs */ struct Conn_web *web; /* everything needed for web (urls etc.) - common for all childs */
 
... ... struct Conn_web_url
190 197 char *path; char *path;
191 198 void (*cb)(struct Conn *); void (*cb)(struct Conn *);
192 199 unsigned char type:1; /* CONN_WEB_TYPE_* */ unsigned char type:1; /* CONN_WEB_TYPE_* */
200 unsigned char pad1:7;
201 unsigned char pad2[7];
193 202 }; };
194 203
195 204 struct Conn_web struct Conn_web
 
... ... struct Conn_web
200 209 struct Conn_web_request struct Conn_web_request
201 210 { {
202 211 unsigned char req_type:2; /* CONN_WEB_REQ_* */ /* TODO: replace with string representation to support more types? */ unsigned char req_type:2; /* CONN_WEB_REQ_* */ /* TODO: replace with string representation to support more types? */
212 unsigned char pad1:6;
213 unsigned char http_protocol; /* 10, 11, 20 etc. */
214 unsigned char pad2[6];
203 215 char *url; /* requested url */ char *url; /* requested url */
204 216 char *paras; /* parameters */ /* TODO: should be make NULL after first request? */ char *paras; /* parameters */ /* TODO: should be make NULL after first request? */
205 unsigned char http_protocol; /* 10, 11, 20 etc. */
206 217 char *header; char *header;
207 218 struct Conn_web_url *u; /* used for websocket */ /* TODO: really used? */ struct Conn_web_url *u; /* used for websocket */ /* TODO: really used? */
208 219 }; };
 
... ... struct Conn_split_cell
214 225 char *left; char *left;
215 226 char *right; char *right;
216 227 unsigned int right_len; unsigned int right_len;
228 unsigned int pad;
217 229 }; };
218 230
219 231 struct Conn_split struct Conn_split
File Conn_web.c changed (mode: 100644) (index 14e0d5b..95be3de)
... ... void Conn_web_dispatch(struct Conn *C)
200 200 struct Conn_web_url *u = NULL; struct Conn_web_url *u = NULL;
201 201 char *end_header, *start_header, *sep, *url, *paras = ""; char *end_header, *start_header, *sep, *url, *paras = "";
202 202 char tmp[128]; char tmp[128];
203 unsigned char http_protocol = 11, tmp8;
203 unsigned char http_protocol = 11;
204 204 unsigned char req_type = 0; unsigned char req_type = 0;
205 205
206 if (C->web_req->u) {
207 Log(2, "%llu %s We have C->web_req->u; just call the callback\n",
208 C->id, __func__);
206 Log(10, "%llu %s\n", C->id, __func__);
207
208 if (C->web_req->u) { // This is for websocket
209 Log(10, "\tWe have C->web_req->u; just call the callback\n");
209 210 C->web_req->u->cb(C); C->web_req->u->cb(C);
210 211 return; return;
211 212 } }
212 213
213 214 url = Conn_ibuf(C); url = Conn_ibuf(C);
214 Log(1, "\turl=%s\n", url);
215 215
216 216 end_header = Conn_strstr(C, "\r\n\r\n"); end_header = Conn_strstr(C, "\r\n\r\n");
217 217 if (end_header == NULL) if (end_header == NULL)
 
... ... void Conn_web_dispatch(struct Conn *C)
220 220 /* parsing first line */ /* parsing first line */
221 221 sep = Conn_strstr(C, "\r\n"); sep = Conn_strstr(C, "\r\n");
222 222 *sep = '\0'; *sep = '\0';
223 start_header = sep + 1;
223 start_header = sep + 2;
224
225 Log(20, "\turl=%s\n", url);
226 Log(20, "\theaders:\n%s\n", start_header);
224 227
225 228 if (strncmp(url, "GET ", 4) == 0) { if (strncmp(url, "GET ", 4) == 0) {
226 229 req_type = CONN_WEB_REQ_GET; req_type = CONN_WEB_REQ_GET;
 
... ... void Conn_web_dispatch(struct Conn *C)
242 245 sep = strchr(url, ' '); sep = strchr(url, ' ');
243 246 if (sep) if (sep)
244 247 *sep = '\0'; *sep = '\0';
245 Log(2, "\tRequest req_type=%s [%s]!\n",
248 Log(10, "\tRequest req_type=%s [%s]!\n",
246 249 Conn_web_req_type(req_type), url); Conn_web_req_type(req_type), url);
247 250
248 251 /* TODO: parse HTTP type */ /* TODO: parse HTTP type */
249 252 if (sep) { if (sep) {
250 253 sep = strstr(sep + 1, "HTTP/"); sep = strstr(sep + 1, "HTTP/");
251 254 if (sep) { if (sep) {
255 unsigned char tmp8;
256
252 257 sep += 5; sep += 5;
253 258 tmp8 = (unsigned char)(sep[0] - '0'); tmp8 = (unsigned char)(sep[0] - '0');
254 259 if ((sep[1] == '.') && (sep[2] != '\0')) if ((sep[1] == '.') && (sep[2] != '\0'))
 
... ... void Conn_web_dispatch(struct Conn *C)
267 272 char *dump; char *dump;
268 273 int match; int match;
269 274
270 Log(2, "\tComparing [%s] with [%s]...\n",
275 Log(10, "\tComparing [%s] with [%s]...\n",
271 276 url, u->url); url, u->url);
272 277
273 278 if (u->type == CONN_WEB_TYPE_PATH) if (u->type == CONN_WEB_TYPE_PATH)
 
... ... void Conn_web_dispatch(struct Conn *C)
287 292 C->web_req->header = start_header; C->web_req->header = start_header;
288 293 Conn_eat(C, end_header + 4 - Conn_ibuf(C)); Conn_eat(C, end_header + 4 - Conn_ibuf(C));
289 294 dump = Conn_dump(Conn_ibuf(C), Conn_iqlen(C)); dump = Conn_dump(Conn_ibuf(C), Conn_iqlen(C));
290 Log(0, "\tNOW ibuf (after eating header): [%s]\n", dump);
295 Log(20, "\tNOW ibuf (after eating header): [%s]\n", dump);
291 296 free(dump); free(dump);
292 297
293 298 if (u->type == CONN_WEB_TYPE_PATH) { if (u->type == CONN_WEB_TYPE_PATH) {
294 299 Conn_web_dispatch_path(C, u); Conn_web_dispatch_path(C, u);
295 300 } else { } else {
296 Log(0, "\tDEBUG: Set C->web->u!\n");
301 Log(20, "\tDEBUG: Set C->web->u!\n");
297 302 C->web_req->u = u; C->web_req->u = u;
298 303 u->cb(C); u->cb(C);
299 304 } }
 
... ... int Conn_web_header_lookup(char *out, const size_t out_size,
351 356
352 357 hlen = strlen(h); hlen = strlen(h);
353 358 while (1) { while (1) {
354 Log(20, "\tpos=%p: %s\n", pos, pos);
359 Log(20, "\tpos=%p [%c]\n", pos, pos[0]);
355 360 if (strncmp(pos, "\r\n", 2) == 0) if (strncmp(pos, "\r\n", 2) == 0)
356 361 return -1; return -1;
357 362
 
... ... int Conn_web_header_lookup(char *out, const size_t out_size,
375 380
376 381 i = 0; i = 0;
377 382 while (1) { while (1) {
378 if ((i == out_size - 1) || (*pos == '\r')) {
383 if ((i == out_size - 1) || (*pos == '\r')
384 || (*pos == '\n')) {
379 385 out[i] = '\0'; out[i] = '\0';
380 386 return 1; return 1;
381 387 } }
 
... ... int Conn_web_ws_parse(struct Conn_web_ws *w, struct Conn *C)
466 472 Conn_eat(C, 2); Conn_eat(C, 2);
467 473
468 474 if (w->opcode == 0x8) { if (w->opcode == 0x8) {
469 Log(20, "\tremote sent close opcode\n");
475 Conn_set_error("remote sent close opcode");
470 476 return -1; return -1;
471 477 } }
472 478
473 479 if (unlikely(w->opcode != 0x1)) { if (unlikely(w->opcode != 0x1)) {
474 Log(20, "\topcode is not 'text' (%hhu)\n", w->opcode);
480 Conn_set_error("opcode is not 'text' (%hhu)", w->opcode);
475 481 return -1; return -1;
476 482 } }
477 483
478 484 if (w->mask != 1) { if (w->mask != 1) {
479 Log(20, "\tinput is not masked!\n");
485 Conn_set_error("input is not masked");
480 486 return -1; return -1;
481 487 } }
482 488
File Makefile.in changed (mode: 100644) (index 2a1a14e..3ebb2ef)
1 include Makefile.include
2
1 3 export CC := gcc export CC := gcc
2 4 export INCS += -I. export INCS += -I.
3 5 export LIBS += -lcrypto -lssl #-lpthread export LIBS += -lcrypto -lssl #-lpthread
4 6 export OBJS += Conn.o Conn_web.o export OBJS += Conn.o Conn_web.o
5 7
6 export CFLAGS += -Wall -Wextra -pipe -O3 -g -ggdb
7 # TODO export CFLAGS += -Wconversion
8 export CFLAGS += @CC_SWITCHES@
8 export CFLAGS := -Wall -Wextra -pipe -O3 -g $(CC_SWITCHES) $(CFLAGS)
9
9 10
10 11 .PHONY: all .PHONY: all
11 12 all: libConn.so.@VER@ all: libConn.so.@VER@
 
... ... libConn.so.@VER@: $(OBJS)
24 25 $(CC) $(CFLAGS) -fPIC $(INCS) -shared -Wl,-soname,libConn.so.1 \ $(CC) $(CFLAGS) -fPIC $(INCS) -shared -Wl,-soname,libConn.so.1 \
25 26 -o $@ $(OBJS) -lc $(LIBS) -o $@ $(OBJS) -lc $(LIBS)
26 27 ln -sf $@ libConn.so.1 ln -sf $@ libConn.so.1
27 ln -sf $@ libConn1.so
28 ln -sf libConn.so.1 libConn.so
28 29
29 30 libConn.a: $(OBJS) libConn.a: $(OBJS)
30 31 ar rcs libConn.a $(OBJS) ar rcs libConn.a $(OBJS)
 
... ... libConn.a: $(OBJS)
32 33
33 34 .PHONY: tests .PHONY: tests
34 35 tests: tests:
35 cppcheck --include=all . 2>cppcheck.out
36 cppcheck --enable=all -I. .
36 37 $(MAKE) -C tests $(MAKE) -C tests
37 38
38 39 .PHONY: examples .PHONY: examples
 
... ... examples:
42 43
43 44 .PHONY: clean .PHONY: clean
44 45 clean: clean:
45 @-rm -f *.a *.o *.so* $(PRJ)-*.rpm $(PRJ)-*-*-*.tgz $(PRJ)-*.tar.gz
46 @-rm -f *.a *.o libConn.so.@VER@ *.so *.so.1
47 @-rm -f $(PRJ)-*.rpm $(PRJ)-*-*-*.tgz $(PRJ)-*.tar.gz
46 48 @$(MAKE) -C examples clean @$(MAKE) -C examples clean
47 49 @$(MAKE) -C tests clean @$(MAKE) -C tests clean
48 50
 
... ... clean:
50 52 install: all install: all
51 53 @mkdir -p $(I_USR_LIB) @mkdir -p $(I_USR_LIB)
52 54 @cp -vd libConn.so* $(I_USR_LIB) @cp -vd libConn.so* $(I_USR_LIB)
53 @cp -vd libConn*.so $(I_USR_LIB)
54 55 @mkdir -p $(I_USR_INC) @mkdir -p $(I_USR_INC)
55 56 @cp -vd Conn.h Conn_config.h $(I_USR_INC) @cp -vd Conn.h Conn_config.h $(I_USR_INC)
File Makefile.include.in added (mode: 100644) (index 0000000..e214257)
1 CC_SWITCHES := @CC_SWITCHES@
File TODO changed (mode: 100644) (index 1105b5e..5fbc10d)
1 1 Use 'set follow-fork-mode child' for gdb to follow childs. Use 'set follow-fork-mode child' for gdb to follow childs.
2 2
3 [ ] Not clear what happens with CFLAGS passed by rpmbuild (for example).
4 [ ] Do not set affinity if we have a single worker?
3 5 [ ] Should I have a link to the master, to remove a lot of pointers to [ ] Should I have a link to the master, to remove a lot of pointers to
4 6 common stuff? For example C->web. Or the callbacks. common stuff? For example C->web. Or the callbacks.
5 7 [ ] We share C->web between connections! [ ] We share C->web between connections!
 
... ... gwan:
308 310
309 311 == HIGH PRIORITY == == HIGH PRIORITY ==
310 312 [ ] Should we do Conn_now per thread? It is updated from all worker threads! [ ] Should we do Conn_now per thread? It is updated from all worker threads!
311 [ ] Switch to libConn.so.1 at compile time to be able tu bump the version sometime.
312 313 [ ] Verify likely/unlikely. I suspect are not working correctly. [ ] Verify likely/unlikely. I suspect are not working correctly.
313 314 [ ] http://lwn.net/Articles/257209/ [ ] http://lwn.net/Articles/257209/
314 315 [ ] http://highscalability.com/blog/2013/5/13/the-secret-to-10-million-concurrent-connections-the-kernel-i.html [ ] http://highscalability.com/blog/2013/5/13/the-secret-to-10-million-concurrent-connections-the-kernel-i.html
File duilder changed (mode: 100755) (index a321672..274273c)
... ... fi
671 671 echo "[*] Autogenerate files from .in..." echo "[*] Autogenerate files from .in..."
672 672 for f in ${AUTOGENERATE}; do for f in ${AUTOGENERATE}; do
673 673 if [ -r "${f}" ]; then if [ -r "${f}" ]; then
674 dst="${f//.in/}"
674 dst="${f%.in}"
675 675 echo " [*] Autogenerate ${dst} from ${f}..." echo " [*] Autogenerate ${dst} from ${f}..."
676 676 sed -f tmp.sed "${f}" > "${dst}" sed -f tmp.sed "${f}" > "${dst}"
677 677 # We need to have the same rights (maybe is executable...) # We need to have the same rights (maybe is executable...)
File duilder.conf changed (mode: 100644) (index 3729c7b..199f3a1)
... ... CC_SWITCHES="${CC_SWITCHES} -Wmissing-prototypes -Wmissing-declarations"
26 26 CC_SWITCHES="${CC_SWITCHES} -Wstrict-overflow -Wstrict-prototypes" CC_SWITCHES="${CC_SWITCHES} -Wstrict-overflow -Wstrict-prototypes"
27 27 CC_SWITCHES="${CC_SWITCHES} -D _FORTIFY_SOURCES=2" CC_SWITCHES="${CC_SWITCHES} -D _FORTIFY_SOURCES=2"
28 28 CC_SWITCHES="${CC_SWITCHES} -fno-guess-branch-probability -fbounds-check" CC_SWITCHES="${CC_SWITCHES} -fno-guess-branch-probability -fbounds-check"
29 CC_SWITCHES="${CC_SWITCHES} -Wl,-O2 -Wpadded"
29 30
30 31 # TODO # TODO
31 32 #CC_SWITCHES="${CC_SWITCHES} -Wconversion" #CC_SWITCHES="${CC_SWITCHES} -Wconversion"
33
34 AUTOGENERATE="Makefile.include.in"
File examples/.gitignore changed (mode: 100644) (index 04ef2d8..53998c2)
... ... rund
16 16 ntime ntime
17 17 xbind1 xbind1
18 18 wpool1 wpool1
19 websocket1
20 ws1
21 wpool2
File examples/Makefile changed (mode: 100644) (index 3c97015..165bab4)
1 include ../Makefile.include
2
1 3 TARGETS := wpool1 wpool2 \ TARGETS := wpool1 wpool2 \
2 4 s c raw udp_s timeout trigger reconnect ntime blackhole_s blackhole_c \ s c raw udp_s timeout trigger reconnect ntime blackhole_s blackhole_c \
3 5 xbind xbind
4 6 TARGETS := wpool2 ws1 websocket1 TARGETS := wpool2 ws1 websocket1
5 7
6 .PHONY: all
7 all:
8 make -C .. examples
9
8 all: $(TARGETS)
10 9 build: $(TARGETS) build: $(TARGETS)
11 10
12 11 INCS += -I.. INCS += -I..
13 LIBS += -L.. -l:libConn.so.1
12 LIBS += -L.. -lConn
14 13 OBJS := OBJS :=
15 14 DEPS := ../Conn.h $(OBJS) DEPS := ../Conn.h $(OBJS)
16 CFLAGS += -Wall -Wextra
17
18 #CFLAGS += $(shell pkg-config --cflags json-c)
19 #LDFLAGS += $(shell pkg-config --libs json-c)
15 CFLAGS := $(CC_SWITCHES) $(CFLAGS)
20 16
21 17 s: s.c $(DEPS) s: s.c $(DEPS)
22 18 gcc $(CFLAGS) $(INCS) s.c -o s $(LIBS) gcc $(CFLAGS) $(INCS) s.c -o s $(LIBS)
 
... ... wpool2: wpool2.c $(DEPS)
66 62 ws1: ws1.c $(DEPS) ws1: ws1.c $(DEPS)
67 63 gcc $(CFLAGS) $(INCS) $@.c -o $@ $(LIBS) gcc $(CFLAGS) $(INCS) $@.c -o $@ $(LIBS)
68 64
69 websocket1: websocket1.c $(DEPS)
65 websocket1: websocket1.c $(DEPS)
70 66 gcc $(CFLAGS) -I/usr/include/json-c $(INCS) $@.c -o $@ $(LIBS) -ljson-c gcc $(CFLAGS) -I/usr/include/json-c $(INCS) $@.c -o $@ $(LIBS) -ljson-c
71 67
72 68 ma: ma.c ma: ma.c
File examples/websocket1.c changed (mode: 100644) (index 422a5ed..38bdb13)
18 18 #include <json.h> #include <json.h>
19 19
20 20 /* Global variables */ /* Global variables */
21 static unsigned short debug = 20;
21 static unsigned short debug = 1; // recommended 1 for production
22
23 // Private data per client
24 struct priv {
25 char name[32];
26 };
22 27
23 28 struct Clients struct Clients
24 29 { {
 
... ... static struct Clients *Clients_head, *Clients_tail;
30 35 static void dump_Clients(void) static void dump_Clients(void)
31 36 { {
32 37 struct Clients *q; struct Clients *q;
38 struct priv *priv;
33 39
34 Log(0, "Dumping Clients:\n");
40 Log(10, "Dumping Clients:\n");
35 41
36 42 q = Clients_head; q = Clients_head;
37 43 while (q) { while (q) {
38 Log(0, "\tq=%p q->next=%p q->C->id=%llu\n", q, q->next, Conn_get_id(q->C));
44 priv = Conn_get_private(q->C);
45 Log(10, "\tq=%p q->next=%p q->C->id=%llu name=%s\n",
46 q, q->next, Conn_get_id(q->C), priv->name);
39 47 q = q->next; q = q->next;
40 48 } }
41 49 } }
 
... ... static void dump_Clients(void)
43 51 static void accept_cb(struct Conn *C) static void accept_cb(struct Conn *C)
44 52 { {
45 53 struct Clients *q; struct Clients *q;
54 struct priv *priv;
46 55
47 Log(0, "%llu %s\n", Conn_get_id(C), __func__);
56 Log(1, "%llu %s from %s/%d\n", Conn_get_id(C), __func__,
57 Conn_addr_remote(C), Conn_port_remote(C));
58
59 priv = malloc(sizeof(struct priv));
60 if (!priv) {
61 Log(0, "\tCannot alloc memory for private area!\n");
62 Conn_close(C);
63 return;
64 }
65 memset(priv, 0, sizeof(struct priv));
66 Conn_set_private(C, priv);
48 67
49 68 q = malloc(sizeof(struct Clients)); q = malloc(sizeof(struct Clients));
50 69 if (!q) { if (!q) {
 
... ... static void process_json(struct Conn *C, struct json_object *j)
100 119 const char *s_op, *s_answer, *s_text; const char *s_op, *s_answer, *s_text;
101 120 struct json_object *op, *answer, *text; struct json_object *op, *answer, *text;
102 121 struct Clients *q; struct Clients *q;
122 struct priv *priv;
103 123
104 Log(0, "%llu %s\n", Conn_get_id(C), __func__);
124 Log(10, "%llu %s\n", Conn_get_id(C), __func__);
105 125
106 Log(0, "json:\n%s\n", json_object_to_json_string_ext(j,
126 priv = Conn_get_private(C);
127
128 Log(10, "json:\n%s\n", json_object_to_json_string_ext(j,
107 129 JSON_C_TO_STRING_SPACED | JSON_C_TO_STRING_PRETTY)); JSON_C_TO_STRING_SPACED | JSON_C_TO_STRING_PRETTY));
108 130
109 131 json_object_object_get_ex(j, "op", &op); json_object_object_get_ex(j, "op", &op);
110 Log(0, "op=%p\n", op);
111 132 s_op = json_object_get_string(op); s_op = json_object_get_string(op);
112 133 if (!s_op) { if (!s_op) {
113 134 Log(0, "\tNo s_op! Ignore it!\n"); Log(0, "\tNo s_op! Ignore it!\n");
114 135 return; return;
115 136 } }
116 Log(0, "\ts_op=[%s]\n", s_op);
137 Log(10, "\ts_op=[%s]\n", s_op);
117 138
118 139 answer = json_object_new_object(); answer = json_object_new_object();
119 140 if (!answer) { if (!answer) {
 
... ... static void process_json(struct Conn *C, struct json_object *j)
122 143 return; return;
123 144 } }
124 145
125 if (strcmp(s_op, "ping") == 0) {
126 Log(0, "\tWe have a ping!\n");
127 json_object_object_add(answer, "answer",
128 json_object_new_string("answer value - ping"));
146 if (strcmp(s_op, "init") == 0) {
147 json_object_object_get_ex(j, "version", &text);
148 s_text = json_object_get_string(text);
149
150 Log(10, "\tWe have an init command [version=%s]!\n", s_text);
151 json_object_object_add(answer, "op",
152 json_object_new_string("init"));
153 json_object_object_add(answer, "id",
154 json_object_new_int64(Conn_get_id(C)));
129 155 s_answer = json_object_to_json_string(answer); s_answer = json_object_to_json_string(answer);
130 156 Conn_web_ws_enqueue(C, 1, 1, s_answer, strlen(s_answer)); Conn_web_ws_enqueue(C, 1, 1, s_answer, strlen(s_answer));
131 157 json_object_put(answer); json_object_put(answer);
132 158 return; return;
133 159 } }
134 160
135 if (strcmp(s_op, "click") == 0) {
136 Log(0, "\tWe have a click!\n");
137 json_object_object_add(answer, "answer",
138 json_object_new_string("answer value - click"));
161 if (strcmp(s_op, "ka") == 0) {
162 Log(10, "\tWe have a ka!\n");
163 json_object_object_add(answer, "op",
164 json_object_new_string("ka"));
139 165 s_answer = json_object_to_json_string(answer); s_answer = json_object_to_json_string(answer);
140 166 Conn_web_ws_enqueue(C, 1, 1, s_answer, strlen(s_answer)); Conn_web_ws_enqueue(C, 1, 1, s_answer, strlen(s_answer));
141 167 json_object_put(answer); json_object_put(answer);
142 168 return; return;
143 169 } }
144 170
145 if (strcmp(s_op, "status") == 0) {
146 Log(0, "\tWe have a status!\n");
147 json_object_object_add(answer, "answer",
148 json_object_new_string("answer value - status"));
149 s_answer = json_object_to_json_string(answer);
150 Conn_web_ws_enqueue(C, 1, 1, s_answer, strlen(s_answer));
151 json_object_put(answer);
171 if (strcmp(s_op, "set_name") == 0) {
172 json_object_object_get_ex(j, "name", &text);
173 s_text = json_object_get_string(text);
174 Log(10, "\tWe have a set_name [%s]!\n", s_text);
175 snprintf(priv->name, sizeof(priv->name), "%s", s_text);
176 // TODO: notify everybody?
177 // We do not answer
152 178 return; return;
153 179 } }
154 180
155 181 if (strcmp(s_op, "msg") == 0) { if (strcmp(s_op, "msg") == 0) {
182 char name[64];
156 183
157 184 json_object_object_get_ex(j, "text", &text); json_object_object_get_ex(j, "text", &text);
158 185 s_text = json_object_get_string(text); s_text = json_object_get_string(text);
159 Log(0, "\tWe have a msg [%s]!\n", s_text);
160
161 json_object_object_add(answer, "answer",
186 Log(10, "\tWe have a msg [%s]!\n", s_text);
187
188 json_object_object_add(answer, "op",
189 json_object_new_string("msg"));
190 if (priv->name[0] == '\0')
191 snprintf(name, sizeof(name), "%llu", Conn_get_id(C));
192 else
193 snprintf(name, sizeof(name), "%s[%llu]", priv->name, Conn_get_id(C));
194 json_object_object_add(answer, "from",
195 json_object_new_string(name));
196 json_object_object_add(answer, "msg",
162 197 json_object_new_string(s_text)); json_object_new_string(s_text));
163 198 s_answer = json_object_to_json_string(answer); s_answer = json_object_to_json_string(answer);
164 199
 
... ... static void process_json(struct Conn *C, struct json_object *j)
182 217
183 218 static void ws1(struct Conn *C) static void ws1(struct Conn *C)
184 219 { {
185 char *dump;
220 char *dump, ip[64];
186 221 int r; int r;
187 222 struct Conn_web_ws w; struct Conn_web_ws w;
188 223 struct json_object *json; struct json_object *json;
189 224
190 Log(0, "%llu %s\n", Conn_get_id(C), __func__);
225 Log(5, "%llu %s\n", Conn_get_id(C), __func__);
191 226
192 227 if (!Conn_web_is_ws(C)) { if (!Conn_web_is_ws(C)) {
228 // Last chanse to extract something from header
229 Conn_web_header_lookup(ip, sizeof(ip), C, "X-Original-IP");
230 Log(0, "IP=%s\n", ip);
231
193 232 Conn_web_ws_negociate(C); Conn_web_ws_negociate(C);
194 233 return; return;
195 234 } }
196 235
197 Log(2, "We already have an established ws connection\n");
236 Log(5, "\tWe already have an established ws connection\n");
198 237 r = Conn_web_ws_parse(&w, C); r = Conn_web_ws_parse(&w, C);
199 238 if (r == -1) { if (r == -1) {
200 Log(0, "\tProtocol erorr!\n");
239 Log(0, "\tProtocol error: %s!\n", Conn_strerror());
201 240 Conn_close(C); Conn_close(C);
202 241 return; return;
203 242 } }
 
... ... static void ws1(struct Conn *C)
206 245 return; return;
207 246 } }
208 247
209 Conn_web_ws_log(&w);
248 if (debug > 10)
249 Conn_web_ws_log(&w);
210 250
211 251 dump = Conn_dump(Conn_ibuf(C), Conn_iqlen(C)); dump = Conn_dump(Conn_ibuf(C), Conn_iqlen(C));
212 Log(0, "\tReceived: %s\n", dump);
252 Log(5, "\tReceived: %s\n", dump);
213 253 free(dump); free(dump);
214 254
215 255 json = json_tokener_parse(Conn_ibuf(C)); json = json_tokener_parse(Conn_ibuf(C));
File examples/ws1.c changed (mode: 100644) (index 3314a4e..0de9b3f)
... ... static void data_cb(struct Conn *C)
40 40 Conn_close(C); Conn_close(C);
41 41 } }
42 42
43 void cgi1(struct Conn *C)
43 static void cgi1(struct Conn *C)
44 44 { {
45 45 char body[4096]; char body[4096];
46 46
File tests/Makefile changed (mode: 100644) (index f2a8de6..8cb138f)
1 include ../Makefile.include
2
1 3 TARGETS := t1.run t2.run t3.run TARGETS := t1.run t2.run t3.run
2 4
3 5 all: $(TARGETS) all: $(TARGETS)
 
... ... all: $(TARGETS)
5 7 INCS += -I.. INCS += -I..
6 8 LIBS += -L.. -lConn LIBS += -L.. -lConn
7 9 OBJS := OBJS :=
8 DEPS := ../libConn.so.$(VER) $(OBJS)
10 DEPS := ../Conn.h $(OBJS)
11 CFLAGS := $(CC_SWITCHES) $(CFLAGS)
9 12
10 13 t1.run: t1.c $(DEPS) t1.run: t1.c $(DEPS)
11 14 gcc $(CFLAGS) $(INCS) t1.c -o $@ $(LIBS) gcc $(CFLAGS) $(INCS) t1.c -o $@ $(LIBS)
File tests/t2.c changed (mode: 100644) (index 4ec1f81..4b4983b)
4 4
5 5 #include <Conn.h> #include <Conn.h>
6 6
7 #include <string.h>
8
7 9 int main(void) int main(void)
8 10 { {
9 11 char *x; char *x;
File tests/t3.c changed (mode: 100644) (index 9832afc..3d2378a)
4 4
5 5 #include <Conn.h> #include <Conn.h>
6 6
7 #include <string.h>
8
7 9 int main(void) int main(void)
8 10 { {
9 11 char x[128]; char x[128];
10 12
11 strcpy(x, "\n");
12 Conn_rtrim(x, "\n\t \r");
13 if (strcmp(x, "LOAD") != 0)
14 return 1;
15
16 strcpy(x, "PORT addr=213.206.96.100 port=443\n");
17 Conn_rtrim(x, "\n\t \r");
18 if (strcmp(x, "PORT addr=213.206.96.100 port=443") != 0)
19 return 1;
20
21 strcpy(x, "");
22 Conn_rtrim(x, "\n\t \r");
23 if (strcmp(x, "") != 0)
24 return 1;
25
26 13 return 0; return 0;
27 14 } }
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