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)
Websocket changes + cosmetic 7438b1adf4a62d1fc5625224318a4b8922abf8c4 Catalin(ux) M. BOIE 2022-10-21 16:21:59
Fix a gcc warning a85c2219114d8b23a40901364db06580d6a40fce Catalin(ux) M. BOIE 2018-08-18 04:40:25
Notes goes under the title; title is nicer 8acce1da5bc4866b6a4bf7fb2af53750e6749a9a Catalin(ux) M. BOIE 2018-08-18 04:40:08
CSS fixes for showing source 1b96ffce7e3744972be0be246cd33d0b107a8553 Catalin(ux) M. BOIE 2018-08-17 03:42:45
Bump version to 1.0.39 9b34e52482191606aa7f92a781d5b5e33a5543c8 Catalin(ux) M. BOIE 2018-05-20 19:14:39
CSS fixes for wsdemo 7fed15a4b4a7ebc154f68a99eb413fea4726ec26 Catalin(ux) M. BOIE 2018-05-20 19:13:44
More compiler flags for security d33f9fdb57826353c755b86493c72993635b1053 Catalin(ux) M. BOIE 2018-05-20 18:56:42
grid1 is working now 0370e6808f8b89fb9ae43fc139195e76247ad6c5 Catalin(ux) M. BOIE 2018-05-12 15:31:00
Added pie2 demo (svg) e8df18b15deafdd0a810a09a251593ecd5fc608f Catalin(ux) M. BOIE 2018-04-17 21:46:02
wsdemo: added Source button 010d08897f99736b9a3f5440af71c2dc40544e68 Catalin(ux) M. BOIE 2018-04-17 17:54:53
More tweaks to wsdemo 56173807662daf36b36907d98bde751749c91075 Catalin(ux) M. BOIE 2018-04-16 18:08:18
Added a callback for worker start 32a05f401d5258f06af9db15a00a615859961cc2 Catalin(ux) M. BOIE 2018-04-16 18:07:55
wsdemo improvements 3eb3efd007fc9240ea39fabcdb4729d1367ebad2 Catalin(ux) M. BOIE 2018-04-13 22:47:24
wsdemo added 2baae01f2409496f990b6d673013b66286f0a5af Catalin(ux) M. BOIE 2018-04-02 21:41:40
Various small stuff 0c551268be734dd68a59426315abfc6ef776c60a Catalin(ux) M. BOIE 2018-04-02 21:40:49
More debugging for websocket parsing 66ccde632b280f1aa450610e6b671464b7e56451 Catalin(ux) M. BOIE 2018-04-02 21:39:23
Raise to 4096 to buffer for logging a59dee1fdfe087ff13e4c7012fe29f8da99ad75c Catalin(ux) M. BOIE 2018-04-02 21:38:11
Bump version 9b635cebfffdd6971eefef0ebad395e21684bb8a Catalin(ux) M. BOIE 2018-01-13 18:07:12
Added some more compile flags and websocket1 helper files. fce47295946106956fb70da77244d77ffca09423 Catalin(ux) M. BOIE 2018-01-13 18:03:46
Lots of changes everywhere 91b9113e8f92db07c079c005273683f2e868910c Catalin(ux) M. BOIE 2018-01-12 19:06:04
Commit 7438b1adf4a62d1fc5625224318a4b8922abf8c4 - Websocket changes + cosmetic
Author: Catalin(ux) M. BOIE
Author date (UTC): 2022-10-21 16:21
Committer name: Catalin(ux) M. BOIE
Committer date (UTC): 2022-10-21 16:21
Parent(s): a85c2219114d8b23a40901364db06580d6a40fce
Signing key:
Tree: 2abe84a8289f8f2f0dc3ddd729017609f9eccefd
File Lines added Lines deleted
Conn.c 108 58
Conn.h 3 0
Conn.spec.in 2 2
Conn_web.c 134 56
Makefile.in 2 2
TODO 10 1
duilder 48 27
duilder.conf 3 2
examples/c.c 23 23
examples/reconnect.c 39 28
examples/websocket1.c 0 3
examples/websocket1.data/main.js 1 1
examples/websocket1.txt 21 0
examples/wsdemo.c 233 47
examples/wsdemo.data/index.html 2 1
examples/wsdemo.data/main.css 0 3
examples/wsdemo.data/main.js 62 9
examples/wsdemo.data/wsdemo.nginx 9 2
File Conn.c changed (mode: 100644) (index 8e7bed6..d6754c4)
27 27 #include "Conn_web.h" #include "Conn_web.h"
28 28
29 29
30 #define CONN_OUT 0
31 #define CONN_IN 1
32
30 33 /* ############## static ########### */ /* ############## static ########### */
31 34 static int Conn_epoll_fd; static int Conn_epoll_fd;
32 35 static struct epoll_event Conn_epoll_events[CONN_EVENTS_SLOTS]; static struct epoll_event Conn_epoll_events[CONN_EVENTS_SLOTS];
 
... ... static int Conn_log_fd = 2;
69 72 static unsigned short debug_band = 11; static unsigned short debug_band = 11;
70 73 static struct Conn_pool Conn_masters; /* Keeps track of listening sockets */ static struct Conn_pool Conn_masters; /* Keeps track of listening sockets */
71 74 static struct Conn_pool Conn_free; /* Keeps track of free Conns */ static struct Conn_pool Conn_free; /* Keeps track of free Conns */
75 static struct Conn_pool Conn_connect_list; /* Keeps track of connecting sockets */
72 76
73 77 static unsigned char Conn_reuseport_available; static unsigned char Conn_reuseport_available;
74 78
 
... ... static void Conn_wpool_get(struct Conn_wpool *wp)
113 117 */ */
114 118 static void Conn_wpool_put(struct Conn_wpool *wp) static void Conn_wpool_put(struct Conn_wpool *wp)
115 119 { {
120 if (!wp)
121 return;
122
116 123 wp->refs--; wp->refs--;
117 124 if (wp->refs == 0) if (wp->refs == 0)
118 125 Conn_wpool_destroy(wp); Conn_wpool_destroy(wp);
 
... ... char *Conn_dumphex(const void *buf_src0, const size_t len_src)
472 479 char *buf_dst; char *buf_dst;
473 480 const unsigned char *buf_src = buf_src0; const unsigned char *buf_src = buf_src0;
474 481
475 Log(30, "\tConn_dumphex(%p, len=%zu)\n",
476 buf_src, len_src);
477
478 482 buf_dst = malloc(len_src * 2 + 1); buf_dst = malloc(len_src * 2 + 1);
479 483 if (buf_dst == NULL) if (buf_dst == NULL)
480 484 return strdup("Memory allocation error1!"); return strdup("Memory allocation error1!");
 
... ... char *Conn_dumphex(const void *buf_src0, const size_t len_src)
494 498 return buf_dst; return buf_dst;
495 499 } }
496 500
501 /*
502 * Hex digit to value
503 */
504 static unsigned char hex_digit(const char x)
505 {
506 if ((x >= 'A') && (x <= 'F'))
507 return 10 + x - 'A';
508 if ((x >= 'a') && (x <= 'f'))
509 return 10 + x - 'a';
510 return x - '0';
511 }
512
513 /*
514 * Converts a hexa string into binary form
515 * Returns -1 on error, else the number of bytes.
516 */
517 int Conn_hex2bin(unsigned char *out, const size_t out_size, const char *hex)
518 {
519 unsigned int i = 0;
520
521 while (*hex != '\0') {
522 if (i == out_size) {
523 snprintf(Conn_error, sizeof(Conn_error),
524 "out buffer too small (%zu)", out_size);
525 return -1;
526 }
527
528 if (hex[1] == '\0') {
529 snprintf(Conn_error, sizeof(Conn_error),
530 "odd number of hexa chars");
531 return -1;
532 }
533 out[i++] = hex_digit(hex[0]) * 16 + hex_digit(hex[1]);
534 hex += 2;
535 }
536
537 return i;
538 }
539
497 540 void Conn_debug(int fd, const unsigned short debug) void Conn_debug(int fd, const unsigned short debug)
498 541 { {
499 542 Conn_log_fd = fd; Conn_log_fd = fd;
 
... ... __cold static int Conn_try_expand_buf(struct Conn *C, const char what,
577 620 unsigned int max_buf; unsigned int max_buf;
578 621 char *pbuf; char *pbuf;
579 622
580 if (what == 0) {
623 if (what == CONN_OUT) {
581 624 head = C->obuf_head; head = C->obuf_head;
582 625 tail = C->obuf_tail; tail = C->obuf_tail;
583 626 old_size = C->obuf_size; old_size = C->obuf_size;
 
... ... __cold static int Conn_try_expand_buf(struct Conn *C, const char what,
597 640
598 641 Log(10, "\tTry to expand buffer for [%s] have=%d needed=%d" Log(10, "\tTry to expand buffer for [%s] have=%d needed=%d"
599 642 " head=%u tail=%u.\n", " head=%u tail=%u.\n",
600 what == 0 ? "O" : "I", old_size, old_size + needed, head, tail);
643 what == CONN_OUT ? "O" : "I", old_size, old_size + needed, head, tail);
601 644
602 645 amount = needed - (old_size - tail); amount = needed - (old_size - tail);
603 646
 
... ... __cold static int Conn_try_expand_buf(struct Conn *C, const char what,
623 666 return -1; return -1;
624 667 } }
625 668
626 if (what == 0) {
669 if (what == CONN_OUT) {
627 670 C->obuf = p; C->obuf = p;
628 671 C->obuf_size = hm; C->obuf_size = hm;
629 672 Conn_mem_buffers_out += hm - old_size; Conn_mem_buffers_out += hm - old_size;
 
... ... __hot static void Conn_free_intern(struct Conn *C)
724 767 Conn_wpool_put(C->wp); Conn_wpool_put(C->wp);
725 768
726 769 if (unlikely(C->auto_reconnect == 1)) { if (unlikely(C->auto_reconnect == 1)) {
770 Log(20, "Preparing for re-connect\n");
771
727 772 /* Reset tsend, else we enter in a timeout error loop */ /* Reset tsend, else we enter in a timeout error loop */
728 773 C->tsend.tv_sec = 0; C->tsend.tv_sec = 0;
729 774 C->tsend.tv_usec = 0; C->tsend.tv_usec = 0;
 
... ... __hot static void Conn_default_cbs_recv(struct Conn *C)
969 1014 break; break;
970 1015 } }
971 1016
972 if (unlikely(C->ibuf_tail == C->ibuf_size)) {
973 r = Conn_try_expand_buf(C, 1, Conn_default_ibuf);
1017 /* 1 is for a final \0 */
1018 if (unlikely(C->ibuf_tail + 1 >= C->ibuf_size)) {
1019 r = Conn_try_expand_buf(C, CONN_IN, Conn_default_ibuf);
974 1020 if (unlikely(r != 0)) { if (unlikely(r != 0)) {
975 1021 C->error_state = CONN_ERROR_MEM; C->error_state = CONN_ERROR_MEM;
976 1022 return; return;
977 1023 } }
978 1024 } }
979 1025
980 max = C->ibuf_size - C->ibuf_tail;
1026 max = C->ibuf_size - C->ibuf_tail - 1;
981 1027 if ((Conn_max_recv > 0) && (max > Conn_max_recv)) if ((Conn_max_recv > 0) && (max > Conn_max_recv))
982 1028 max = Conn_max_recv; max = Conn_max_recv;
983 1029
 
... ... __hot static void Conn_default_cbs_recv(struct Conn *C)
1036 1082 C->bi += (unsigned int) n; C->bi += (unsigned int) n;
1037 1083 xfer_in_this_call += (unsigned int) n; xfer_in_this_call += (unsigned int) n;
1038 1084
1085 C->ibuf[C->ibuf_tail] = '\0';
1086
1039 1087 if (n < max) { if (n < max) {
1040 Log(3, "\tReaded less(%d < %d) than what we requested\n",
1088 Log(23, "\tReaded less(%d < %d) than what we requested\n",
1041 1089 n, max); n, max);
1042 1090 break; break;
1043 1091 } }
 
... ... __hot static void Conn_default_cbs_send(struct Conn *C)
1058 1106 int xerrno, r; int xerrno, r;
1059 1107 char *dump; char *dump;
1060 1108
1061 Log(5, "%llu %s C=%p next=%p fd=%d head=%u tail=%u size=%u\n",
1109 Log(9, "%llu %s C=%p next=%p fd=%d head=%u tail=%u size=%u\n",
1062 1110 C->id, __func__, C, C->next, C->fd, C->obuf_head, C->id, __func__, C, C->next, C->fd, C->obuf_head,
1063 1111 C->obuf_tail, C->obuf_size); C->obuf_tail, C->obuf_size);
1064 1112
 
... ... __hot static void Conn_default_cbs_send(struct Conn *C)
1066 1114 unsigned int max, count; unsigned int max, count;
1067 1115 char *buf; char *buf;
1068 1116
1069 buf = C->obuf + C->obuf_head;
1070 1117 count = Conn_oqlen(C); count = Conn_oqlen(C);
1071 1118 if (unlikely(count == 0)) { if (unlikely(count == 0)) {
1072 Log(5, "\tEmpty output buffer.\n");
1119 Log(10, "\tEmpty output buffer.\n");
1073 1120 if (unlikely(C->close_after_send == 1)) { if (unlikely(C->close_after_send == 1)) {
1074 1121 Log(9, "\tCLOSE_AFTER_SEND is set" Log(9, "\tCLOSE_AFTER_SEND is set"
1075 1122 ", close connection\n"); ", close connection\n");
 
... ... __hot static void Conn_default_cbs_send(struct Conn *C)
1099 1146 return; return;
1100 1147 } }
1101 1148
1149 Conn_change_obj(C->worker->epoll_fd, C, EPOLLIN);
1102 1150 return; /* TODO: not clear if we could be here. */ return; /* TODO: not clear if we could be here. */
1103 1151 } }
1104 1152
 
... ... __hot static void Conn_default_cbs_send(struct Conn *C)
1111 1159 if (max > C->band_tokens) if (max > C->band_tokens)
1112 1160 max = C->band_tokens; max = C->band_tokens;
1113 1161 if (max == 0) { if (max == 0) {
1114 Log(debug_band, "\tBAND: Suspend 100ms"
1115 " the C (no tokens)!\n");
1162 Log(debug_band, "\tBAND: Suspend for 100ms"
1163 " (no tokens)!\n");
1116 1164 break; break;
1117 1165 } }
1118 1166 } }
 
... ... __hot static void Conn_default_cbs_send(struct Conn *C)
1121 1169 ", max=%d (count=%d), 0)...\n", ", max=%d (count=%d), 0)...\n",
1122 1170 C->fd, C->obuf_head, C->fd, C->obuf_head,
1123 1171 C->obuf_tail, max, count); C->obuf_tail, max, count);
1172 buf = C->obuf + C->obuf_head;
1124 1173 while (1) { while (1) {
1125 n = send(C->fd, buf, max, 0);
1174 n = send(C->fd, buf, max, MSG_NOSIGNAL);
1126 1175 xerrno = errno; xerrno = errno;
1127 1176 if (unlikely((n == -1) && (errno == EINTR))) if (unlikely((n == -1) && (errno == EINTR)))
1128 1177 continue; continue;
 
... ... __hot static struct Conn *Conn_alloc_prepare(struct Conn *C)
2109 2158
2110 2159 C->id = Conn_id++; C->id = Conn_id++;
2111 2160
2112 /* TODO: really? Don't we borrow them from master listent conn?! */
2161 /* TODO: really? Don't we borrow them from master listen conn?! */
2113 2162 C->cbs = Conn_default_cbs; C->cbs = Conn_default_cbs;
2114 2163
2115 2164 C->web = NULL; C->web = NULL;
 
... ... static inline void Conn_poll_cb(struct Conn *C, const unsigned int revents)
2357 2406 C->local_dirty = 1; C->local_dirty = 1;
2358 2407 C->time_open = Conn_now; C->time_open = Conn_now;
2359 2408
2360 /* TODO: indirect call costs a lot. Hm.
2409 /* TODO: indirect call costs a lot. Hm. */
2361 2410 if (likely(C->cbs.connected)) if (likely(C->cbs.connected))
2362 2411 C->cbs.connected(C); C->cbs.connected(C);
2363 */
2364 Conn_default_cbs_connected(C);
2412 else
2413 Conn_default_cbs_connected(C);
2365 2414 } }
2366 2415 } }
2367 2416 //if (Conn_ignore(C)) //if (Conn_ignore(C))
 
... ... static inline int Conn_dispatch_events(struct Conn_wpool_worker *w,
2426 2475 struct Conn *C; struct Conn *C;
2427 2476 ssize_t r; ssize_t r;
2428 2477
2429 Log(10, "%s timeout2=%dms e_size=%hu...\n", __func__,
2430 timeout, e_size);
2478 Log(10, "%s epoll_fd=%d timeout=%dms e_size=%hu...\n", __func__,
2479 epoll_fd, timeout, e_size);
2431 2480 while (1) { while (1) {
2432 2481 events = epoll_wait(epoll_fd, e, e_size, timeout); events = epoll_wait(epoll_fd, e, e_size, timeout);
2433 2482 if (unlikely(events < 0)) { if (unlikely(events < 0)) {
 
... ... int Conn_init(const unsigned int max)
3000 3049 /* TODO: masters does not need a full pool implementation */ /* TODO: masters does not need a full pool implementation */
3001 3050 pool_init(&Conn_masters); pool_init(&Conn_masters);
3002 3051 pool_init(&Conn_free); pool_init(&Conn_free);
3052 pool_init(&Conn_connect_list);
3003 3053
3004 3054 Conn_max = max; Conn_max = max;
3005 3055
 
... ... __hot int Conn_enqueue_wait(struct Conn *C, const void *buf, const unsigned int
3092 3142 if (unlikely(C->obuf_size - C->obuf_tail < count)) { if (unlikely(C->obuf_size - C->obuf_tail < count)) {
3093 3143 int r; int r;
3094 3144
3095 r = Conn_try_expand_buf(C, 0, count);
3145 r = Conn_try_expand_buf(C, CONN_OUT, count);
3096 3146 if (unlikely(r != 0)) if (unlikely(r != 0))
3097 3147 return -1; return -1;
3098 3148 } }
 
... ... int Conn_commit(struct Conn *C)
3264 3314 struct sockaddr_in bind_sa; struct sockaddr_in bind_sa;
3265 3315 struct sockaddr_in6 bind_sa6; struct sockaddr_in6 bind_sa6;
3266 3316 socklen_t bind_sock_len = 0; socklen_t bind_sock_len = 0;
3267 int do_connect = 0;
3268 3317 unsigned char first_state = 0xff; unsigned char first_state = 0xff;
3269 3318 struct Conn_wpool_worker *w; struct Conn_wpool_worker *w;
3270 3319
 
... ... int Conn_commit(struct Conn *C)
3282 3331 } }
3283 3332
3284 3333 if (C->type == CONN_TYPE_P2P) { if (C->type == CONN_TYPE_P2P) {
3285 do_connect = 1;
3286 } else {
3287 if (C->bind_addr[0] == '\0') {
3288 /* Choose defaults because IP was not specified */
3289 switch (C->sock_domain) {
3290 case PF_INET:
3291 snprintf(C->bind_addr, sizeof(C->bind_addr),
3292 "0.0.0.0"); break;
3293 case PF_INET6:
3294 snprintf(C->bind_addr, sizeof(C->bind_addr),
3295 "::"); break;
3296 }
3334 if (Conn_connect_list.head == NULL)
3335 Conn_connect_list.head = C;
3336 else
3337 Conn_connect_list.tail->next = C;
3338 Conn_connect_list.tail = C;
3339
3340 /* TODO:replace connect_a with OPEN?! */
3341 C->state = CONN_STATE_CONNECT_a;
3342 Conn_pending++;
3343 return 0;
3344 }
3345
3346 /* TODO: we may want to bind even if we connect */
3347 if (C->bind_addr[0] == '\0') {
3348 /* Choose defaults because IP was not specified */
3349 switch (C->sock_domain) {
3350 case PF_INET:
3351 snprintf(C->bind_addr, sizeof(C->bind_addr),
3352 "0.0.0.0"); break;
3353 case PF_INET6:
3354 snprintf(C->bind_addr, sizeof(C->bind_addr),
3355 "::"); break;
3297 3356 } }
3298 3357 } }
3299 3358
 
... ... int Conn_commit(struct Conn *C)
3357 3416 return -1; return -1;
3358 3417 } }
3359 3418
3360 // TODO: If we have workers, why would need to create a socket for master?!
3419 // TODO: If we have workers, why would need to create a socket
3420 // for master?!
3361 3421 #if 1 #if 1
3362 3422 ret = Conn_prepare_socket(C, bind_psa, bind_sock_len); ret = Conn_prepare_socket(C, bind_psa, bind_sock_len);
3363 3423 if (ret == -1) if (ret == -1)
 
... ... int Conn_commit(struct Conn *C)
3376 3436 Conn_masters.tail = C; Conn_masters.tail = C;
3377 3437 } }
3378 3438
3379 if (do_connect == 1) {
3380 /* TODO:replace connect_a with OPEN?! */
3381 first_state = CONN_STATE_CONNECT_a;
3382 }
3383
3384 3439 C->state = first_state; C->state = first_state;
3385 3440
3386 3441 if (!C->wp) { if (!C->wp) {
 
... ... int Conn_commit(struct Conn *C)
3400 3455 Log(1, "%s: reuseport is available, create a new socket.\n", Log(1, "%s: reuseport is available, create a new socket.\n",
3401 3456 __func__); __func__);
3402 3457 listen_fd = Conn_prepare_socket(C, bind_psa, bind_sock_len); listen_fd = Conn_prepare_socket(C, bind_psa, bind_sock_len);
3403 // TODO: why we do not do listen in prepare? Because we do not know if we should listen
3458 // TODO: why we do not do listen in prepare?
3459 // Because we do not know if we should listen.
3404 3460 } else { } else {
3405 3461 Log(1, "%s: reuseport is NOT available, use master socket.\n", Log(1, "%s: reuseport is NOT available, use master socket.\n",
3406 3462 __func__); __func__);
 
... ... int Conn_commit(struct Conn *C)
3415 3471 close(listen_fd); close(listen_fd);
3416 3472 } }
3417 3473
3418 if (do_connect == 1)
3419 Conn_pending++;
3420
3421 3474 return 0; return 0;
3422 3475
3423 3476 out_free: out_free:
 
... ... int Conn_band(struct Conn *C, const unsigned int width,
3552 3605 return 0; return 0;
3553 3606 } }
3554 3607
3555 #if 0
3556 TODO
3557 3608 static void Conn_trytoconnect(void) static void Conn_trytoconnect(void)
3558 3609 { {
3559 3610 struct addrinfo hints; struct addrinfo hints;
3560 3611 struct addrinfo *res; struct addrinfo *res;
3561 int i, ret;
3612 int ret;
3562 3613 char port[8]; char port[8];
3563 3614 struct Conn *C; struct Conn *C;
3564 3615
3565 3616 Log(8, "%s Conn_pending=%d\n", Log(8, "%s Conn_pending=%d\n",
3566 3617 __func__, Conn_pending); __func__, Conn_pending);
3567 3618
3619 gettimeofday(&Conn_now, NULL);
3620
3568 3621 C = Conn_connect_list.head; C = Conn_connect_list.head;
3569 3622 while (C) { while (C) {
3623 Log(20, "%s id=%llu state=%s\n",
3624 __func__, C->id, Conn_state(C));
3625
3570 3626 if ((C->state == CONN_STATE_CONNECT_0) if ((C->state == CONN_STATE_CONNECT_0)
3571 3627 && (C->tryat <= Conn_now.tv_sec)) && (C->tryat <= Conn_now.tv_sec))
3572 3628 C->state = CONN_STATE_CONNECT_a; C->state = CONN_STATE_CONNECT_a;
 
... ... static void Conn_trytoconnect(void)
3599 3655 } }
3600 3656
3601 3657 if (C->fd == -1) { if (C->fd == -1) {
3602 C->fd = socket(res->ai_family, res->ai_socktype, 0);
3658 C->fd = socket(res->ai_family, res->ai_socktype | SOCK_NONBLOCK | SOCK_CLOEXEC, 0);
3603 3659 if (C->fd == -1) { if (C->fd == -1) {
3604 3660 C->state = CONN_STATE_ERROR; C->state = CONN_STATE_ERROR;
3605 3661 C->error_state = CONN_ERROR_SOCKET; C->error_state = CONN_ERROR_SOCKET;
 
... ... static void Conn_trytoconnect(void)
3610 3666 } }
3611 3667 Log(10, "\tAllocated socket on fd %d\n", C->fd); Log(10, "\tAllocated socket on fd %d\n", C->fd);
3612 3668
3613 Conn_setnonblock(C->fd);
3614
3615 3669 /* Need POLLOUT to signal when the connection was done. */ /* Need POLLOUT to signal when the connection was done. */
3616 3670 /*TODO ret = Conn_add_obj(Conn_epoll_fd, C, EPOLLIN | EPOLLRDHUP);*/ /*TODO ret = Conn_add_obj(Conn_epoll_fd, C, EPOLLIN | EPOLLRDHUP);*/
3617 ret = Conn_add_obj(Conn_epoll_fd, C, EPOLLIN);
3671 ret = Conn_add_obj(Conn_epoll_fd, C, EPOLLIN | EPOLLOUT);
3618 3672 if (ret != 0) { if (ret != 0) {
3619 3673 C->state = CONN_STATE_ERROR; C->state = CONN_STATE_ERROR;
3620 3674 C->error_state = CONN_ERROR_SOCKET; C->error_state = CONN_ERROR_SOCKET;
 
... ... static void Conn_trytoconnect(void)
3650 3704
3651 3705 Log(8, "%s After, Conn_pending=%d\n", __func__, Conn_pending); Log(8, "%s After, Conn_pending=%d\n", __func__, Conn_pending);
3652 3706 } }
3653 #endif
3654 3707
3655 3708 #if 0 #if 0
3656 3709 /* /*
 
... ... int Conn_poll(const int timeout)
3710 3763 return 0; return 0;
3711 3764 } }
3712 3765
3713 #if 0
3714 TODO
3715 3766 if (Conn_pending > 0) if (Conn_pending > 0)
3716 3767 Conn_trytoconnect(); Conn_trytoconnect();
3717 #endif
3718 3768
3719 3769 ret = Conn_dispatch_events(NULL, Conn_epoll_fd, Conn_epoll_events, ret = Conn_dispatch_events(NULL, Conn_epoll_fd, Conn_epoll_events,
3720 3770 CONN_EVENTS_SLOTS, timeout2); CONN_EVENTS_SLOTS, timeout2);
 
... ... int Conn_poll(const int timeout)
3722 3772 return -1; return -1;
3723 3773
3724 3774 #if 1 #if 1
3725 Log(9, "Do compacting, expiration and band stuff...\n");
3775 Log(30, "Do compacting, expiration and band stuff...\n");
3726 3776 slot = 0; slot = 0;
3727 3777 while (slot < Conn_no) { while (slot < Conn_no) {
3728 3778 /* /*
File Conn.h changed (mode: 100644) (index a9199c1..f3e90d8)
... ... enum CONN_CB {
44 44 void Log(const unsigned short level, char *format, ...); void Log(const unsigned short level, char *format, ...);
45 45 char *Conn_dump(const void *buf_src0, const size_t len_src); char *Conn_dump(const void *buf_src0, const size_t len_src);
46 46 char *Conn_dumphex(const void *buf_src0, const size_t len_src); char *Conn_dumphex(const void *buf_src0, const size_t len_src);
47 int Conn_hex2bin(unsigned char *out, const size_t out_size,
48 const char *hex);
47 49 void Conn_debug(int fd, const unsigned short debug); void Conn_debug(int fd, const unsigned short debug);
48 50
49 51
 
... ... int Conn_band(struct Conn *C, const unsigned int width,
142 144 int Conn_poll(const int timeout); int Conn_poll(const int timeout);
143 145
144 146 /* web server */ /* web server */
147 char *Conn_web_escape(const char *s);
145 148 int Conn_web_create(struct Conn *C); int Conn_web_create(struct Conn *C);
146 149 int Conn_web_script(struct Conn *C, const char *url, int Conn_web_script(struct Conn *C, const char *url,
147 150 void(*cb)(struct Conn *C)); void(*cb)(struct Conn *C));
File Conn.spec.in changed (mode: 100644) (index 5423bbc..2f4a188)
... ... Group: Applications/Internet
7 7 Source: http://kernel.embedromix.ro/us/Conn/%{name}-%{version}.tar.gz Source: http://kernel.embedromix.ro/us/Conn/%{name}-%{version}.tar.gz
8 8 URL: http://kernel.embedromix.ro/us/ URL: http://kernel.embedromix.ro/us/
9 9 BuildRoot: %{_tmppath}/%{name}-%{version}-buildroot BuildRoot: %{_tmppath}/%{name}-%{version}-buildroot
10 BuildRequires: make, gcc, openssl-devel
11 Requires: openssl
10 BuildRequires: make, gcc, gnutls-devel
11 Requires: gnutls
12 12
13 13 %global _hardened_build 1 %global _hardened_build 1
14 14
File Conn_web.c changed (mode: 100644) (index 71f6810..7c769db)
2 2
3 3 #include "Conn_config.h" #include "Conn_config.h"
4 4
5 #include <openssl/sha.h>
6 #include <openssl/evp.h>
5 #include <gnutls/crypto.h>
7 6
8 7 #include "Conn_intern.h" #include "Conn_intern.h"
9 8 #include "Conn_web.h" #include "Conn_web.h"
10 9
11 10
11 /*
12 * HTML escape
13 */
14 char *Conn_web_escape(const char *s)
15 {
16 const char *new;
17 char *r, *r2;
18 size_t len, need, off;
19
20 r = malloc(64);
21 if (!r)
22 return NULL;
23
24 off = 0;
25 len = 64;
26 while (*s) {
27 switch (*s) {
28 case '&': new = "&amp;"; need = 5; break;
29 case '<': new = "&lt;"; need = 4; break;
30 case '>': new = "&gt;"; need = 4; break;
31 case '"': new = "&quot;"; need = 6; break;
32 case '\'': new = "&#27;"; need = 5; break;
33 case '/': new = "&#2f;"; need = 5; break;
34 case '`': new = "&grave;"; need = 7; break;
35 default: new = s; need = 1; break;
36 }
37
38 if (off + need + 1 > len) {
39 r2 = realloc(r, len + 64);
40 if (!r2) {
41 free(r);
42 return NULL;
43 }
44
45 r = r2;
46 len += 64;
47 }
48
49 strncpy(r + off, new, need);
50 off += need;
51 s++;
52 }
53
54 r[off] = '\0';
55
56 return r;
57 }
58
12 59 /* /*
13 60 * Allocates a web server structure (Conn_web) * Allocates a web server structure (Conn_web)
14 61 */ */
 
... ... void Conn_web_ws_negociate(struct Conn *C)
406 453 int r; int r;
407 454 char key[128], accept[64]; char key[128], accept[64];
408 455 unsigned char sha1[20]; unsigned char sha1[20];
456 gnutls_datum_t d1, d2;
409 457
410 458 Log(20, "%llu %s\n", C->id, __func__); Log(20, "%llu %s\n", C->id, __func__);
411 459
 
... ... void Conn_web_ws_negociate(struct Conn *C)
420 468 Log(21, "\treceived key=[%s]\n", key); Log(21, "\treceived key=[%s]\n", key);
421 469 strcat(key, "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"); strcat(key, "258EAFA5-E914-47DA-95CA-C5AB0DC85B11");
422 470 Log(21, "\tfinal key=%s\n", key); Log(21, "\tfinal key=%s\n", key);
471
423 472 /* Compute base64(sha1(key)) */ /* Compute base64(sha1(key)) */
424 SHA1((unsigned char *) key, strlen(key), sha1);
425 EVP_EncodeBlock((unsigned char *) accept, sha1, sizeof(sha1));
473 r = gnutls_hash_fast(GNUTLS_MAC_SHA1, key, strlen(key), sha1);
474 if (r != 0) {
475 Log(20, "\tCannot compute sha1!\n");
476 Conn_close(C);
477 return;
478 }
479 d1.data = sha1;
480 d1.size = 20;
481 r = gnutls_base64_encode2(&d1, &d2);
482 if (r != 0) {
483 Log(20, "\tCannot compute base64!\n");
484 Conn_close(C);
485 return;
486 }
487 memcpy(accept, d2.data, d2.size);
488 accept[d2.size] = '\0';
489 gnutls_free(d2.data);
426 490
427 491 Conn_eatall(C); Conn_eatall(C);
428 492
 
... ... void Conn_web_ws_negociate(struct Conn *C)
441 505
442 506 void Conn_web_ws_log(const struct Conn_web_ws *w) void Conn_web_ws_log(const struct Conn_web_ws *w)
443 507 { {
444 Log(0, "fin=%hhu opcode=%hhu mask=%hhu"
508 Log(10, "fin=%hhu opcode=%hhu mask=%hhu"
445 509 " len=%llu maskkey=0x%hhx%hhx%hhx%hhx\n", " len=%llu maskkey=0x%hhx%hhx%hhx%hhx\n",
446 510 w->fin, w->opcode, w->mask, w->len, w->fin, w->opcode, w->mask, w->len,
447 511 w->maskkey[0], w->maskkey[1], w->maskkey[2], w->maskkey[3]); w->maskkey[0], w->maskkey[1], w->maskkey[2], w->maskkey[3]);
448 512 } }
449 513
514 /*
515 * Send bytes respecting the websocket protocol
516 * @opcode (1 = text)
517 * @final: 0 (more data will follow) or 1 (final data)
518 */
519 void Conn_web_ws_enqueue(struct Conn *C, const unsigned char opcode,
520 const unsigned char final, const char *s, const unsigned int len)
521 {
522 unsigned char buf[10], i;
523
524 i = 0;
525 buf[i++] = (!!final << 7) | opcode; // FIN | opcode (1 = text)
526 if (len <= 125) {
527 buf[i++] = len;
528 } else if (len <= 65535) {
529 buf[i++] = 126;
530 buf[i++] = len >> 8;
531 buf[i++] = len;
532 } else {
533 buf[i++] = 0;
534 buf[i++] = 0;
535 buf[i++] = 0;
536 buf[i++] = 0;
537 buf[i++] = len >> 24;
538 buf[i++] = len >> 16;
539 buf[i++] = len >> 8;
540 buf[i++] = len;
541 }
542 Conn_enqueue_wait(C, buf, i);
543 Conn_enqueue(C, s, len);
544 }
545
450 546 /* /*
451 547 * Parses a buffer for a websocket packet * Parses a buffer for a websocket packet
452 548 * Example: 88 82 5c c7 68 b9 5f 2e * Example: 88 82 5c c7 68 b9 5f 2e
 
... ... void Conn_web_ws_log(const struct Conn_web_ws *w)
455 551 int Conn_web_ws_parse(struct Conn_web_ws *w, struct Conn *C) int Conn_web_ws_parse(struct Conn_web_ws *w, struct Conn *C)
456 552 { {
457 553 unsigned char len_bytes = 0; unsigned char len_bytes = 0;
458 char *buf;
459 unsigned int i, len;
554 unsigned char *buf;
555 unsigned int i;
460 556
461 557 Log(20, "%llu %s\n", C->id, __func__); Log(20, "%llu %s\n", C->id, __func__);
462 558
463 559 if (Conn_iqlen(C) < 2) if (Conn_iqlen(C) < 2)
464 560 return 0; return 0;
465 561
466 buf = Conn_ibuf(C);
562 buf = (unsigned char *) Conn_ibuf(C);
467 563 w->fin = buf[0] >> 7; w->fin = buf[0] >> 7;
468 w->opcode = buf[0];
564 w->opcode = buf[0] & 0x0F;
469 565 w->mask = buf[1] >> 7; w->mask = buf[1] >> 7;
470 566 w->len = buf[1] & 0x7F; w->len = buf[1] & 0x7F;
471 Conn_eat(C, 2);
567 buf += 2;
472 568 Log(20, "%s: fin=%hhu opcode=%hhu mask=%hhu len=%hhu\n", Log(20, "%s: fin=%hhu opcode=%hhu mask=%hhu len=%hhu\n",
473 569 __func__, w->fin, w->opcode, w->mask, w->len); __func__, w->fin, w->opcode, w->mask, w->len);
474 570
 
... ... int Conn_web_ws_parse(struct Conn_web_ws *w, struct Conn *C)
490 586 len_bytes = 8; len_bytes = 8;
491 587 } }
492 588
493 if (Conn_iqlen(C) < (unsigned int)(len_bytes + 4))
589 if (Conn_iqlen(C) < (unsigned int)(2 + len_bytes + 4)) {
590 Log(9, "What is in buffer [%u] is less than needed [%hhu] (header)\n",
591 Conn_iqlen(C), 2 + len_bytes + 4);
494 592 return 0; return 0;
593 }
495 594
496 buf = Conn_ibuf(C);
497 595 if (w->len == 126) { if (w->len == 126) {
498 596 w->len = (buf[0] << 8) | buf[1]; w->len = (buf[0] << 8) | buf[1];
499 597 } else if (w->len == 127) { } else if (w->len == 127) {
500 598 w->len = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; w->len = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
501 buf += 4;
502 599 w->len <<= 32; w->len <<= 32;
503 w->len |= (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
600 w->len |= (buf[4] << 24) | (buf[5] << 16) | (buf[6] << 8) | buf[7];
504 601 } }
505 Conn_eat(C, len_bytes);
602 buf += len_bytes;
506 603 Log(20, "\tw->len=%llu\n", w->len); Log(20, "\tw->len=%llu\n", w->len);
507 604
508 buf = Conn_ibuf(C);
509 605 w->maskkey[0] = buf[0]; w->maskkey[0] = buf[0];
510 606 w->maskkey[1] = buf[1]; w->maskkey[1] = buf[1];
511 607 w->maskkey[2] = buf[2]; w->maskkey[2] = buf[2];
512 608 w->maskkey[3] = buf[3]; w->maskkey[3] = buf[3];
513 Conn_eat(C, 4);
514 609
515 if (Conn_iqlen(C) < w->len)
610 if (Conn_iqlen(C) < 2 + len_bytes + 4 + w->len) {
611 Log(9, "What is in buffer [%u] is less than needed [%llu] (body)\n",
612 Conn_iqlen(C), 2 + len_bytes + 4 + w->len);
516 613 return 0; return 0;
614 }
615
616 Conn_web_ws_log(w);
517 617
518 buf = Conn_ibuf(C);
519 len = w->len;
520 for (i = 0; i < len; i++)
618 // Now (we have the whole packet) we are safe to eat bytes.
619 Conn_eat(C, 2 + len_bytes + 4);
620
621 buf = (unsigned char *) Conn_ibuf(C);
622 for (i = 0; i < w->len; i++)
521 623 buf[i] ^= w->maskkey[i % 4]; buf[i] ^= w->maskkey[i % 4];
522 624
625 if (unlikely(w->opcode == 0x09)) { // ping
626 Log(20, "We have a ping, respond with pong!\n");
627 Conn_eat(C, w->len);
628 Conn_web_ws_enqueue(C, 0x0A, 1, NULL, 0);
629 Conn_kick(C);
630 return 0;
631 }
523 632 if (unlikely(w->opcode != 0x1)) { if (unlikely(w->opcode != 0x1)) {
524 Conn_set_error("opcode is not 'text' (%hhu)", w->opcode);
525 Conn_dump(buf, len);
633 Conn_set_error("opcode is not 'text' (%hhu); w->len=%u",
634 w->opcode, w->len);
635 Conn_dump(buf, w->len);
526 636 return -1; return -1;
527 637 } }
528 638
529 return len;
530 }
531
532 /*
533 * Send bytes respecting the websocket protocol
534 * @opcode (1 = text)
535 * @final: 0 (more data will follow) or 1 (final data)
536 */
537 void Conn_web_ws_enqueue(struct Conn *C, const unsigned char opcode,
538 const unsigned char final, const char *s, const unsigned int len)
539 {
540 unsigned char buf[10], i;
541
542 i = 0;
543 buf[i++] = (!!final << 7) | opcode; // FIN | opcode (1 = text)
544 if (len <= 125) {
545 buf[i++] = len;
546 } else if (len <= 65535) {
547 buf[i++] = 126;
548 buf[i++] = len >> 8;
549 buf[i++] = len;
550 } else {
551 buf[i++] = 0;
552 buf[i++] = 0;
553 buf[i++] = 0;
554 buf[i++] = 0;
555 buf[i++] = len >> 24;
556 buf[i++] = len >> 16;
557 buf[i++] = len >> 8;
558 buf[i++] = len;
559 }
560 Conn_enqueue_wait(C, buf, i);
561 Conn_enqueue(C, s, len);
639 return w->len;
562 640 } }
563 641
File Makefile.in changed (mode: 100644) (index 19522a9..aa9a4eb)
... ... include Makefile.include
2 2
3 3 export CC := gcc export CC := gcc
4 4 export INCS += -I. export INCS += -I.
5 export LIBS += -lcrypto -lssl #-lpthread
5 export LIBS += -lgnutls #-lpthread
6 6 export OBJS += Conn.o Conn_web.o export OBJS += Conn.o Conn_web.o
7 7
8 export CFLAGS := -Wall -Wextra -pipe -g $(CC_SWITCHES) $(CFLAGS)
8 export CFLAGS := -Wall -Wextra -pipe -g $(CC_SWITCHES) $(CFLAGS) -D _FORTIFY_SOURCES=2
9 9
10 10
11 11 .PHONY: all .PHONY: all
File TODO changed (mode: 100644) (index 5fbc10d..bf0f191)
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 [ ] On Debian (amd64), we need to instal in /usr/lib, not /usr/lib64.
4 What about other distros?
5 [ ] Conn_ignore has to be marked with 'unlikely'.
3 6 [ ] Not clear what happens with CFLAGS passed by rpmbuild (for example). [ ] Not clear what happens with CFLAGS passed by rpmbuild (for example).
4 7 [ ] Do not set affinity if we have a single worker? [ ] Do not set affinity if we have a single worker?
5 8 [ ] 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
6 9 common stuff? For example C->web. Or the callbacks. common stuff? For example C->web. Or the callbacks.
7 10 [ ] We share C->web between connections! [ ] We share C->web between connections!
8 So struct Conn_web must contail only 'urls' (for now), to be able to
11 So struct Conn_web must contain only 'urls' (for now), to be able to
9 12 dispatch requests, but the rest of the fields must be per C. dispatch requests, but the rest of the fields must be per C.
10 13 Check Conn_web_dispatch for the logic. Check Conn_web_dispatch for the logic.
11 14 [ ] Shouldn't Conn_web_script receive a *web parameter instead of C?! [ ] Shouldn't Conn_web_script receive a *web parameter instead of C?!
 
... ... Pentru a reduce numarul de conexiuni in TIME-WAIT:
411 414 [ ] Bandwidth part should have a separate pointer, to not load too much Conn structure. [ ] Bandwidth part should have a separate pointer, to not load too much Conn structure.
412 415 [ ] Maybe we should have Bandwidth classes so we can group connections. [ ] Maybe we should have Bandwidth classes so we can group connections.
413 416 [ ] http://www.erlang-solutions.com/thesis/tcp_optimisation/tcp_optimisation.html [ ] http://www.erlang-solutions.com/thesis/tcp_optimisation/tcp_optimisation.html
417 [ ] We need a trigger also for worker_exit. For example, see wsu2f, when a
418 global exit function is needed.
414 419 [ ] [ ]
415 420
416 421 === When we switch to Conn version 2 library === === When we switch to Conn version 2 library ===
 
... ... Pentru a reduce numarul de conexiuni in TIME-WAIT:
418 423 [ ] use enums! [ ] use enums!
419 424 [ ] http://urbanairship.com/blog/2010/09/29/linux-kernel-tuning-for-c500k/ [ ] http://urbanairship.com/blog/2010/09/29/linux-kernel-tuning-for-c500k/
420 425 [ ] [ ]
426
427 === Debian
428 libjson-c-dev
429 libssl-dev
File duilder changed (mode: 100755) (index 274273c..e243861)
... ... function duilder_docs()
34 34
35 35 echo "[*] Copying docs to [${EXPORT_PATH}]..." echo "[*] Copying docs to [${EXPORT_PATH}]..."
36 36 for f in README License LICENSE Changelog Changelog-last TODO FAQ INSTALL AUTHORS samples; do for f in README License LICENSE Changelog Changelog-last TODO FAQ INSTALL AUTHORS samples; do
37 if [ -r "${f}" ]; then
38 cp -avp "${f}" "${EXPORT_PATH}/"
39 if [ "${BUILD_SDEB}" = "1" ]; then
40 # No need to install the license file
41 if [ "${f}" = "LICENSE" ]; then
42 continue
43 fi
44 echo "${f}" >> debian/docs
37 [ ! -r "${f}" ] && continue
38
39 cp -avp "${f}" "${EXPORT_PATH}/"
40 if [ "${BUILD_SDEB}" = "1" ]; then
41 # No need to install the license file
42 if [ "${f}" = "LICENSE" ]; then
43 continue
45 44 fi fi
45 echo "${f}" >> debian/docs
46 46 fi fi
47 47 done done
48 48 echo echo
 
... ... function duilder_docs()
57 57
58 58 function duilder_git() function duilder_git()
59 59 { {
60 PRJ="${1}"
61 GIT_DEST="${2}"
62 EXPORT_GIT="${3}"
63 GIT_CHANGELOG="${4}"
64 GIT_PUSH="${5}"
60 PRJ="${1}"; shift
61 GIT_DEST="${1}"; shift
62 EXPORT_GIT="${1}"; shift
63 EXPORT_PATH="${1}"; shift
64 GIT_CHANGELOG="${1}"; shift
65 GIT_PUSH="${1}"; shift
65 66
66 67 if [ ! -x /usr/bin/git ]; then if [ ! -x /usr/bin/git ]; then
67 68 echo "[*] Warning: Git not found!" echo "[*] Warning: Git not found!"
 
... ... function duilder_srpm()
205 206 fi fi
206 207
207 208 if [ ! -z "${SRPM_DEST}" ]; then if [ ! -z "${SRPM_DEST}" ]; then
209 if [ -r "${SRPM_DEST}/${PKG}" ]; then
210 mv "${SRPM_DEST}/${PKG}" "${SRPM_DEST}/${PKG}.old"
211 fi
208 212 echo "[*] Copying [${PKG}] to [${SRPM_DEST}]..." echo "[*] Copying [${PKG}] to [${SRPM_DEST}]..."
209 213 cp -vp "${PKG}" "${SRPM_DEST}/" cp -vp "${PKG}" "${SRPM_DEST}/"
210 214 fi fi
 
... ... function duilder_tar()
274 278
275 279 echo "[*] Generating tarball [${P}.tar.gz]..." echo "[*] Generating tarball [${P}.tar.gz]..."
276 280 ADD_EXCLUDE="" ADD_EXCLUDE=""
277 if [ ! -z "${EXCLUDE}" ]; then
281 if [ -r "${EXCLUDE}" ]; then
278 282 ADD_EXCLUDE="--exclude-from ${P}/${EXCLUDE}" ADD_EXCLUDE="--exclude-from ${P}/${EXCLUDE}"
279 283 echo "[*] ADD_EXCLUDE=${ADD_EXCLUDE}" echo "[*] ADD_EXCLUDE=${ADD_EXCLUDE}"
280 284 fi fi
 
... ... fi
307 311
308 312
309 313 if [ ! -r duilder.conf ]; then if [ ! -r duilder.conf ]; then
310 echo "[*] You must build a duilder.conf file!"
311 exit 1
314 echo "[*] You do not have a duilder.conf file. Trying to continue."
315 else
316 source ${PWD}/duilder.conf 2>/dev/null
312 317 fi fi
313 318
314 source ${PWD}/duilder.conf
315 319
316 320 # fixes # fixes
317 321 if [ -z "${GIT_DEST}" ]; then if [ -z "${GIT_DEST}" ]; then
 
... ... if [ -z "${GIT_DEST}" ]; then
319 323 fi fi
320 324
321 325 if [ -z "${PRJ}" ]; then if [ -z "${PRJ}" ]; then
322 echo "ERROR: PRJ= parameter is missing."
323 exit 1
326 echo "WARN: PRJ= parameter is missing."
324 327 fi fi
325 328
326 329 if [ -z "${VER}" ]; then if [ -z "${VER}" ]; then
327 echo "ERROR: VER= parameter is missing."
328 exit 1
330 echo "WARN: VER= parameter is missing."
329 331 fi fi
330 332
331 333 if [ -z "${REV}" ]; then if [ -z "${REV}" ]; then
332 echo "ERROR: REV= parameter is missing."
333 exit 1
334 echo "WARN: REV= parameter is missing."
334 335 fi fi
335 336
336 337 # export variables - just in case a script cares # export variables - just in case a script cares
 
... ... done
445 446 # Last fixes # Last fixes
446 447 VAR_LOG="${VAR}/log" VAR_LOG="${VAR}/log"
447 448 VAR_RUN="${VAR}/run" VAR_RUN="${VAR}/run"
449 DUILDER_SYSTEMD="${USR}/lib/systemd"
448 450
449 for i in ETC BIN USR USR_BIN USR_SBIN USR_INCLUDE USR_LIB USR_SHARE USR_SHARE_DOC SBIN VAR VAR_LIB MAN VAR_LOG VAR_RUN; do
451 for i in ETC BIN USR USR_BIN USR_SBIN USR_INCLUDE USR_LIB USR_SHARE USR_SHARE_DOC SBIN VAR VAR_LIB MAN VAR_LOG VAR_RUN DUILDER_SYSTEMD; do
450 452 eval value=\$$i eval value=\$$i
451 453 echo "[*] Var ${i}=${value}" echo "[*] Var ${i}=${value}"
452 454 done done
 
... ... else
540 542 echo "s#@NCURSES_FOUND@#1#g" >> tmp.sed echo "s#@NCURSES_FOUND@#1#g" >> tmp.sed
541 543 fi fi
542 544
543 if [ -n "${CC_SWITCHES}" ]; then
545 if [ "${CC_SWITCHES}" = "" ]; then
546 CC_SWITCHES="-O3 -fstack-reuse=all -flto -Wtrampolines -Wl,-z,noexecstack -Wl,-z,now -Wl,-z,relro -Wl,-O1 -Wl,-z,noexecstack -fPIE -pie -fstack-protector-all -Wcast-align -Wformat=2 -Wformat-security -fno-common -Wmissing-prototypes -Wmissing-declarations -Wstrict-overflow -Wstrict-prototypes -fno-guess-branch-probability -fbounds-check -Wl,-O3 -Wpadded -ftree-loop-distribution -ftree-vectorize -ftree-loop-if-convert -ftree-loop-im -ftree-parallelize-loops=4 -fcf-protection -fstack-clash-protection -Wimplicit-fallthrough -fanalyzer"
547 fi
548
549 if [ "1" = "1" ]; then
544 550 _CC_SWITCHES="" _CC_SWITCHES=""
545 551 echo "[*] Search for valid compiler flags..." echo "[*] Search for valid compiler flags..."
546 552 add="" add=""
547 553 for s in ${CC_SWITCHES}; do for s in ${CC_SWITCHES}; do
548 554 echo -n " [*] Testing switch [${s}]..." echo -n " [*] Testing switch [${s}]..."
555 case ${s} in
556 -Wformat-security) extra=" -Wformat" ;;
557 *) extra="" ;;
558 esac
549 559 set +e set +e
550 echo "int main(void) { return 0; }" | gcc ${s} -x c -pipe - -o /dev/null 2>/dev/null
560 echo "int main(void) { return 0; }" \
561 | gcc ${extra} ${s} -x c -pipe - -o /dev/null 2>>duilder.log
551 562 E=${?} E=${?}
552 563 set -e set -e
553 564 if [ "${E}" != "0" ]; then if [ "${E}" != "0" ]; then
 
... ... echo "s#@USR_LIB@#${USR_LIB}#g" >> tmp.sed
580 591 echo "s#@USR_SHARE@#${USR_SHARE}#g" >> tmp.sed echo "s#@USR_SHARE@#${USR_SHARE}#g" >> tmp.sed
581 592 echo "s#@USR_SHARE_DOC@#${USR_SHARE_DOC}#g" >> tmp.sed echo "s#@USR_SHARE_DOC@#${USR_SHARE_DOC}#g" >> tmp.sed
582 593 echo "s#@MAN@#${MAN}#g" >> tmp.sed echo "s#@MAN@#${MAN}#g" >> tmp.sed
594 echo "s#@DUILDER_SYSTEMD@#${DUILDER_SYSTEMD}#g" >> tmp.sed
583 595 # Export stuff # Export stuff
584 596 echo "s#@EXPORT_PATH@#${EXPORT_PATH}#g" >> tmp.sed echo "s#@EXPORT_PATH@#${EXPORT_PATH}#g" >> tmp.sed
585 597 # cc_switches # cc_switches
 
... ... if [ -r Makefile.in ]; then
617 629 echo "export I_VAR_LOG := \$(DESTDIR)${VAR_LOG}" >> Makefile echo "export I_VAR_LOG := \$(DESTDIR)${VAR_LOG}" >> Makefile
618 630 echo "export I_VAR_RUN := \$(DESTDIR)${VAR_RUN}" >> Makefile echo "export I_VAR_RUN := \$(DESTDIR)${VAR_RUN}" >> Makefile
619 631 echo "export I_MAN := \$(DESTDIR)${MAN}" >> Makefile echo "export I_MAN := \$(DESTDIR)${MAN}" >> Makefile
632 echo "export I_DUILDER_SYSTEMD := \$(DESTDIR)${DUILDER_SYSTEMD}" >> Makefile
620 633 echo >> Makefile echo >> Makefile
621 634 echo "# DB stuff" >> Makefile echo "# DB stuff" >> Makefile
622 635 echo "export DB_SUPPORT := ${DB_SUPPORT}" >> Makefile echo "export DB_SUPPORT := ${DB_SUPPORT}" >> Makefile
 
... ... if [ -r Makefile.in ]; then
639 652 echo >> Makefile echo >> Makefile
640 653 echo "# This is to allow exporting only the git tree" >> Makefile echo "# This is to allow exporting only the git tree" >> Makefile
641 654 echo "dist_git:" >> Makefile echo "dist_git:" >> Makefile
642 echo " @./duilder git \"\$(PRJ)\" \"${GIT_DEST}\" \"${EXPORT_GIT}\" \"${EXPORT_PATH}\" \"${GIT_CHANGELOG}\"" >> Makefile
655 echo " @./duilder git \"\$(PRJ)\" \"${GIT_DEST}\" \"${EXPORT_GIT}\" \"${EXPORT_PATH}\" \"${GIT_CHANGELOG}\" \"${GIT_PUSH}\"" >> Makefile
656 echo >> Makefile
657 echo "# This is to allow making the tar" >> Makefile
658 echo "dist_tar:" >> Makefile
659 echo " @./duilder tar \"\$(PRJ)\" \"\$(VER)\" \"${EXPORT_PATH}\" \"${EXCLUDE}\"" >> Makefile
660 echo >> Makefile
661 echo "# This is to allow making rpm" >> Makefile
662 echo "dist_srpm: dist_tar" >> Makefile
663 echo " @./duilder srpm \"\$(PRJ)\" \"\$(VER)\" \"${EXPORT_PATH}\" \"${BUILD_SRPM}\" \"${SRPM_DEST}\" \"${SRPM_POST_RUN}\"" >> Makefile
643 664 echo >> Makefile echo >> Makefile
644 665 echo ".PHONY: dist" >> Makefile echo ".PHONY: dist" >> Makefile
645 666 echo "dist: clean" >> Makefile echo "dist: clean" >> Makefile
File duilder.conf changed (mode: 100644) (index ad09fb7..e672a35)
1 1 PRJ="Conn" PRJ="Conn"
2 VER="1.0.39"
2 VER="1.0.40"
3 3 REV="1" REV="1"
4 4 EXCLUDE=".exclude" EXCLUDE=".exclude"
5 5 EXPORT_PATH="/data/www/umbrella/kernel/us/Conn" EXPORT_PATH="/data/www/umbrella/kernel/us/Conn"
 
... ... CC_SWITCHES="${CC_SWITCHES} -Wcast-align -Wformat=2"
24 24 CC_SWITCHES="${CC_SWITCHES} -Wformat-security -fno-common" CC_SWITCHES="${CC_SWITCHES} -Wformat-security -fno-common"
25 25 CC_SWITCHES="${CC_SWITCHES} -Wmissing-prototypes -Wmissing-declarations" 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 CC_SWITCHES="${CC_SWITCHES} -D _FORTIFY_SOURCES=2"
28 27 CC_SWITCHES="${CC_SWITCHES} -fno-guess-branch-probability -fbounds-check" CC_SWITCHES="${CC_SWITCHES} -fno-guess-branch-probability -fbounds-check"
29 28 CC_SWITCHES="${CC_SWITCHES} -Wl,-O3 -Wpadded" CC_SWITCHES="${CC_SWITCHES} -Wl,-O3 -Wpadded"
30 29 CC_SWITCHES="${CC_SWITCHES} -ftree-loop-distribution -ftree-vectorize -ftree-loop-if-convert" CC_SWITCHES="${CC_SWITCHES} -ftree-loop-distribution -ftree-vectorize -ftree-loop-if-convert"
31 30 CC_SWITCHES="${CC_SWITCHES} -ftree-loop-im -ftree-parallelize-loops=4" CC_SWITCHES="${CC_SWITCHES} -ftree-loop-im -ftree-parallelize-loops=4"
32 31 CC_SWITCHES="${CC_SWITCHES} -fcf-protection -fstack-clash-protection" CC_SWITCHES="${CC_SWITCHES} -fcf-protection -fstack-clash-protection"
32 CC_SWITCHES="${CC_SWITCHES} -Wimplicit-fallthrough -mbranch-protection=standard"
33 CC_SWITCHES="${CC_SWITCHES} -fanalyzer"
33 34
34 35 # TODO # TODO
35 36 #CC_SWITCHES="${CC_SWITCHES} -Wconversion" #CC_SWITCHES="${CC_SWITCHES} -Wconversion"
File examples/c.c changed (mode: 100644) (index ae4ce8c..f3e601b)
1 1 #define _GNU_SOURCE #define _GNU_SOURCE
2 2
3 #include <string.h>
4 #include <errno.h>
5 #include <sys/time.h>
6
3 7 #include <Conn.h> #include <Conn.h>
4 8
5 9 /* Global variables */ /* Global variables */
 
... ... struct priv
19 23
20 24 static void c_connected(struct Conn *C) static void c_connected(struct Conn *C)
21 25 { {
22 struct priv *p;
26 struct priv *p;
23 27
24 Log(4, "%s(A connection was estabilished on slot %d)\n",
25 __func__, C->slot);
28 Log(4, "%s: id=%llu: A connection was estabilished\n",
29 __func__, Conn_get_id(C));
26 30
27 C->private = malloc(sizeof(struct priv));
28 if (C->private == NULL) {
31 p = malloc(sizeof(struct priv));
32 if (p == NULL) {
29 33 Log(0, "cannot alloc memory!\n"); Log(0, "cannot alloc memory!\n");
30 34 exit(1); exit(1);
31 35 } }
36 Conn_set_private(C, p);
32 37
33 p = (struct priv *) C->private;
34 38 p->dummy = 0; p->dummy = 0;
35 39 } }
36 40
 
... ... static void c_close(struct Conn *C)
38 42 { {
39 43 Log(5, "%s: id=%llu will close...\n", Log(5, "%s: id=%llu will close...\n",
40 44 __func__, Conn_get_id(C)); __func__, Conn_get_id(C));
41 free(C->private);
42 45 } }
43 46
44 static int c_data_cb(struct Conn *C, char *line)
47 static void c_data_cb(struct Conn *C, char *line)
45 48 { {
46 49 struct priv *p; struct priv *p;
47 50 char *dump; char *dump;
48 51
49 p = (struct priv *) C->private;
52 p = Conn_get_private(C);
50 53
51 54 if (debug >= 8) { if (debug >= 8) {
52 55 dump = Conn_dump(line, strlen(line)); dump = Conn_dump(line, strlen(line));
53 Log(8, "data: recv: %s\n", dump);
56 Log(8, "id=%llu: data: recv: %s\n",
57 Conn_get_id(C), dump);
54 58 free(dump); free(dump);
55 59 } }
56 60
57 61 p->dummy++; p->dummy++;
58 62
59 63 answers++; answers++;
60
61 return 0;
62 64 } }
63 65
64 66 static void c_data(struct Conn *C) static void c_data(struct Conn *C)
 
... ... static void c_error(struct Conn *C)
76 78
77 79 int main(void) int main(void)
78 80 { {
79 int ret;
81 int ret, fd;
80 82 struct timeval start, end; struct timeval start, end;
81 83 unsigned int elap; unsigned int elap;
82 84 unsigned int i; unsigned int i;
83 85 struct Conn *C4, *C6; struct Conn *C4, *C6;
84 86
85 Logf = fopen(log_file, "a+");
86 if (!Logf) {
87 fd = open(log_file, O_RDWR | O_CREAT | O_TRUNC, 0600);
88 if (fd == -1) {
87 89 fprintf(stderr, "Cannot open log file [%s] [%s]\n", fprintf(stderr, "Cannot open log file [%s] [%s]\n",
88 90 log_file, strerror(errno)); log_file, strerror(errno));
89 91 return 1; return 1;
90 92 } }
91 if (debug > 0)
92 setlinebuf(Logf);
93 93
94 Conn_debug(Logf, debug);
94 Conn_debug(fd, debug);
95 95
96 96 Log(0, "Starting...\n"); Log(0, "Starting...\n");
97 97 Log(0, "\tPort=%d\n", port); Log(0, "\tPort=%d\n", port);
 
... ... int main(void)
103 103 return 1; return 1;
104 104 } }
105 105
106 Conn_connected_cb = c_connected;
107 Conn_data_cb = c_data;
108 Conn_close_cb = c_close;
109 Conn_error_cb = c_error;
110
111 106 gettimeofday(&start, NULL); gettimeofday(&start, NULL);
112 107
113 108 answers = 0; answers = 0;
 
... ... int main(void)
120 115 Conn_strerror()); Conn_strerror());
121 116 return 1; return 1;
122 117 } }
118 Conn_set_cb(C4, CONN_CB_CLOSE, c_close);
119 Conn_set_cb(C4, CONN_CB_CONNECTED, c_connected);
120 Conn_set_cb(C4, CONN_CB_DATA, c_data);
121 Conn_set_cb(C4, CONN_CB_CLOSE, c_close);
122 Conn_set_cb(C4, CONN_CB_ERROR, c_error);
123 123 } }
124 124
125 125 /* ipv6 */ /* ipv6 */
File examples/reconnect.c changed (mode: 100644) (index 79fd58e..e10257d)
5 5
6 6 #define _GNU_SOURCE #define _GNU_SOURCE
7 7
8 #include <unistd.h>
9 #include <errno.h>
10 #include <string.h>
11
8 12 #include <Conn.h> #include <Conn.h>
9 13
10 14 /* Global variables */ /* Global variables */
11 static unsigned short debug = 20;
12 static FILE *Logf = NULL;
15 static unsigned short debug = 100;
13 16 static char *log_file = "reconnect.log"; static char *log_file = "reconnect.log";
14 17
15 18
16 19 static void c_connected(struct Conn *C) static void c_connected(struct Conn *C)
17 20 { {
21 const char *buf =
22 "GET / HTTP/1.1\r\n"
23 "Host: www.google.com\r\n"
24 "\r\n";
25
18 26 Log(4, "%s: A connection was estabilished with id %llu)\n", Log(4, "%s: A connection was estabilished with id %llu)\n",
19 27 __func__, Conn_get_id(C)); __func__, Conn_get_id(C));
28
29 Conn_enqueue(C, buf, strlen(buf));
20 30 } }
21 31
22 32 static void c_close(struct Conn *C) static void c_close(struct Conn *C)
 
... ... static void c_close(struct Conn *C)
25 35 __func__, Conn_get_id(C)); __func__, Conn_get_id(C));
26 36 } }
27 37
28 static int c_data_cb(struct Conn *C, char *line)
38 static void c_data_cb(struct Conn *C, char *line)
29 39 { {
30 40 char *dump; char *dump;
31 41
 
... ... static int c_data_cb(struct Conn *C, char *line)
35 45 free(dump); free(dump);
36 46 } }
37 47
38 return 0;
48 Conn_close(C); // to force the reconnection
39 49 } }
40 50
41 51 static void c_data(struct Conn *C) static void c_data(struct Conn *C)
 
... ... static void c_error(struct Conn *C)
51 61
52 62 int main(void) int main(void)
53 63 { {
54 int ret;
64 int ret, fd;
55 65 struct Conn *C; struct Conn *C;
56 66
57 Logf = fopen(log_file, "a+");
58 if (!Logf) {
67 fd = open(log_file, O_RDWR | O_CREAT | O_TRUNC, 0600);
68 if (fd == -1) {
59 69 fprintf(stderr, "Cannot open log file [%s] [%s]\n", fprintf(stderr, "Cannot open log file [%s] [%s]\n",
60 70 log_file, strerror(errno)); log_file, strerror(errno));
61 71 return 1; return 1;
62 72 } }
63 if (debug > 0)
64 setlinebuf(Logf);
65 73
66 Conn_debug(Logf, debug);
74 Conn_debug(fd, debug);
67 75
68 76 ret = Conn_init(0); ret = Conn_init(0);
69 77 if (ret == -1) { if (ret == -1) {
 
... ... int main(void)
71 79 return 1; return 1;
72 80 } }
73 81
74 Conn_connected_cb = c_connected;
75 Conn_data_cb = c_data;
76 Conn_close_cb = c_close;
77 Conn_error_cb = c_error;
78
79 82 C = Conn_alloc(); C = Conn_alloc();
80 83 if (!C) { if (!C) {
81 printf("Cannot alloc socket [%s].\n", Conn_strerror());
82 } else {
83 Conn_set_socket_domain(C, PF_INET);
84 Conn_set_socket_type(C, SOCK_STREAM);
85 Conn_set_socket_addr(C, "www.google.com");
86 Conn_set_socket_port(C, 80);
87 ret = Conn_commit(C);
88 if (ret != 0) {
89 printf("Cannot commit socket [%s].\n",
90 Conn_strerror());
91 }
84 fprintf(stderr, "Cannot alloc socket [%s].\n", Conn_strerror());
85 return 1;
86 }
87
88 Conn_set_socket_domain(C, PF_INET);
89 Conn_set_socket_type(C, SOCK_STREAM);
90 Conn_set_socket_addr(C, "www.google.com");
91 Conn_set_socket_port(C, 80);
92
93 Conn_set_cb(C, CONN_CB_CONNECTED, c_connected);
94 Conn_set_cb(C, CONN_CB_DATA, c_data);
95 Conn_set_cb(C, CONN_CB_CLOSE, c_close);
96 Conn_set_cb(C, CONN_CB_ERROR, c_error);
97
98 ret = Conn_commit(C);
99 if (ret != 0) {
100 printf("Cannot commit socket [%s].\n",
101 Conn_strerror());
102 return 1;
92 103 } }
93 104
94 105 Conn_set(C, CONN_PARA_AUTO_RECONNECT, 1); Conn_set(C, CONN_PARA_AUTO_RECONNECT, 1);
95 Conn_set(C, CONN_PARA_RECONNECT_DELAY, 10);
106 Conn_set(C, CONN_PARA_RECONNECT_DELAY, 5);
96 107
97 108 while (1) { while (1) {
98 109 ret = Conn_poll(-1); ret = Conn_poll(-1);
 
... ... int main(void)
106 117
107 118 Conn_shutdown(); Conn_shutdown();
108 119
109 fclose(Logf);
120 close(fd);
110 121
111 122 return 0; return 0;
112 123 } }
File examples/websocket1.c changed (mode: 100644) (index 8a1f5b5..9f8fec5)
... ... static void ws1(struct Conn *C)
246 246 return; return;
247 247 } }
248 248
249 if (debug > 10)
250 Conn_web_ws_log(&w);
251
252 249 dump = Conn_dump(Conn_ibuf(C), Conn_iqlen(C)); dump = Conn_dump(Conn_ibuf(C), Conn_iqlen(C));
253 250 Log(5, "\tReceived: %s\n", dump); Log(5, "\tReceived: %s\n", dump);
254 251 free(dump); free(dump);
File examples/websocket1.data/main.js changed (mode: 100644) (index 5c6ea44..b468745)
... ... function reconnect()
101 101 { {
102 102 var j; var j;
103 103
104 //console.log('onmessage: data: ' + ev.data);
104 console.log('onmessage: data: ' + ev.data);
105 105 j = JSON.parse(ev.data); j = JSON.parse(ev.data);
106 106
107 107 if (j.op == 'ka') { if (j.op == 'ka') {
File examples/websocket1.txt added (mode: 100644) (index 0000000..b6b103c)
1 Request from Firefox:
2
3 GET /ws HTTP/1.1
4 Upgrade: websocket
5 Connection: upgrade
6 Host: websocket
7 User-Agent: Mozilla/5.0 (X11; Fedora; Linux i686; rv:57.0) Gecko/20100101 Firefox/57.0
8 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
9 Accept-Language: en-US,en;q=0.5
10 Accept-Encoding: gzip, deflate, br
11 Sec-WebSocket-Version: 13
12 Origin: https://cloud.embedromix.ro:9020
13 Sec-WebSocket-Extensions: permessage-deflate
14 Sec-WebSocket-Key: /v4q2f9C2hQvOa8y3yBH1A==
15
16 Possible answer:
17 HTTP/1.1 101 Switching Protocols
18 Upgrade: websocket
19 Connection: Upgrade
20 Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo= # base64(sha1(Sec-WebSocket-Key + 258EAFA5-E914-47DA-95CA-C5AB0DC85B11))
21 Sec-WebSocket-Protocol: chat # optional
File examples/wsdemo.c changed (mode: 100644) (index 0144c04..ae590b6)
... ... static unsigned short debug = 10; // recommended 1 for production
25 25 // Private data per client // Private data per client
26 26 struct priv { struct priv {
27 27 unsigned int x, y; // screen size unsigned int x, y; // screen size
28 char version[8];
29 char ua[128];
30 unsigned int visibility:1;
28 31
29 32 unsigned int main_init:1; unsigned int main_init:1;
30 33 unsigned int per1_init:1; unsigned int per1_init:1;
 
... ... struct priv {
37 40 unsigned int pie2_init:1; unsigned int pie2_init:1;
38 41 unsigned int bar1_init:1; unsigned int bar1_init:1;
39 42 unsigned int grid1_init:1; unsigned int grid1_init:1;
43 unsigned int users_init:1;
40 44
41 45 unsigned char per1_percent; unsigned char per1_percent;
42 46 unsigned char per2_percent; unsigned char per2_percent;
 
... ... static time_t band_last; // when the last value was updated
61 65 static int band_up = 30, band_down = 30; // fake start values static int band_up = 30, band_down = 30; // fake start values
62 66
63 67 /* grid1 is global */ /* grid1 is global */
64 static char grid1_data[3][3][64];
68 #define GRID1_CELL_SIZE 64
69 static char grid1_data1[3][3][GRID1_CELL_SIZE];
70 static char grid1_data2[3][3][GRID1_CELL_SIZE];
65 71
66 72
67 73 struct Clients struct Clients
 
... ... static void push_code(struct Conn *C, const char *code)
142 148 */ */
143 149 static void push_code_broadcast(struct Conn *source, const char *code) static void push_code_broadcast(struct Conn *source, const char *code)
144 150 { {
145 struct Clients *q;
151 struct Clients *q;
146 152
147 153 q = Clients_head; q = Clients_head;
148 154 while (q) { while (q) {
 
... ... static void arc1(struct Conn *C)
407 413 " c.x = (50 - last_x) + 40 * Math.cos(last_angle + angle);\n" " c.x = (50 - last_x) + 40 * Math.cos(last_angle + angle);\n"
408 414 " c.y = (50 - last_y) + 40 * Math.sin(last_angle + angle);\n" " c.y = (50 - last_y) + 40 * Math.sin(last_angle + angle);\n"
409 415 " last_x += c.x; last_y += c.y; last_angle += angle;\n" " last_x += c.x; last_y += c.y; last_angle += angle;\n"
410 " t.children[i].innerHTML = a[i].name + ': ' + parseInt(a[i].value * 100 / sum) + '%%';\n"
416 " t.children[i].innerHTML = a[i].name + ': ' + parseInt(a[i].value * 100 / sum) + '%';\n"
411 417 " }\n" " }\n"
412 418 " for (; i < 5; i++) {\n" " for (; i < 5; i++) {\n"
413 419 " var c = d.children[i].pathSegList[1];\n" " var c = d.children[i].pathSegList[1];\n"
 
... ... static void pie1(struct Conn *C)
640 646 "\n" "\n"
641 647 " ctx.shadowColor = '#444';\n" " ctx.shadowColor = '#444';\n"
642 648 " ctx.shadowBlur = 3;\n" " ctx.shadowBlur = 3;\n"
643 " ctx.shadowOffsetX = 2;\n"
644 " ctx.shadowOffsetY = 2;\n"
649 " ctx.shadowOffsetX = 1;\n"
650 " ctx.shadowOffsetY = 1;\n"
645 651 " for (i = 0; i < a.length; i++) {\n" " for (i = 0; i < a.length; i++) {\n"
646 652 " angle = a[i].value * 2 * Math.PI / sum;\n" " angle = a[i].value * 2 * Math.PI / sum;\n"
647 653 " ctx.fillStyle = a[i].color;\n" " ctx.fillStyle = a[i].color;\n"
 
... ... static void grid1(struct Conn *C)
803 809 const char *u = const char *u =
804 810 "window.wsdemo.grid1_oninput = function(id, i, j) {\n" "window.wsdemo.grid1_oninput = function(id, i, j) {\n"
805 811 " var d = document.getElementById(id);\n" " var d = document.getElementById(id);\n"
806 " var data = { op: 'grid1_oninput', i: i, j: j, value: d.innerHTML };\n"
812 " var rows = d.getElementsByTagName('tr');\n"
813 " var row = rows[i];\n"
814 " var cells = row.getElementsByTagName('td');\n"
815 " var cell = cells[j];\n"
816 " if (cell.innerHTML == '<br>')\n" // Strnge thing. If I am deleting the content of a cell it is set to '<br>'!
817 " cell.innerHTML = '';\n"
818 " var data = { op: 'grid1_oninput', id: id, i: i, j: j, value: cell.innerHTML };\n"
807 819 " ws.send(JSON.stringify(data));\n" " ws.send(JSON.stringify(data));\n"
808 " console.log('grid1_oninput: id=' + id + ' i=' + i + ' j=' + j);\n"
809 820 "}\n" "}\n"
810 821 "\n" "\n"
811 "window.wsdemo.grid1_update = function(i, j, value) {\n"
812 " var d = document.getElementById('grid1-' + i + '-' + j);\n"
813 " d.innerHTML = value;\n"
822 "window.wsdemo.grid1_update = function(id, i, j, value) {\n"
823 " var d = document.getElementById(id);\n"
824 " var rows = d.getElementsByTagName('tr');\n"
825 " var row = rows[i];\n"
826 " var cells = row.getElementsByTagName('td');\n"
827 " var cell = cells[j];\n"
828 " cell.innerHTML = value;\n"
814 829 "}\n" "}\n"
815 830 "\n" "\n"
816 "window.wsdemo.grid1_init = function(a) {\n"
831 "window.wsdemo.grid1_init = function(id, rows, cols) {\n"
817 832 " var i;\n" " var i;\n"
818 " var d;\n"
819 "\n"
820 " d = document.getElementById('grid1');\n"
833 " var d = document.getElementById(id);\n"
821 834 " if (d.children[0] != null)\n" " if (d.children[0] != null)\n"
822 835 " return;\n" " return;\n"
823 836 "\n" "\n"
824 837 " var t = document.createElement('table');\n" " var t = document.createElement('table');\n"
825 "\n"
826 838 " t.style.border = '1px solid black';\n" " t.style.border = '1px solid black';\n"
827 839 " t.style.borderCollapse = 'collapse';\n" " t.style.borderCollapse = 'collapse';\n"
828 840 " t.style.margin = '3px';\n" " t.style.margin = '3px';\n"
829 841 " t.style.padding = '5px';\n" " t.style.padding = '5px';\n"
830 " for (i = 0; i < 3; i++) {\n"
842 " for (i = 0; i < rows; i++) {\n"
831 843 " var tr = t.insertRow();\n" " var tr = t.insertRow();\n"
832 " for (j = 0; j < 3; j++) {\n"
844 " for (j = 0; j < cols; j++) {\n"
833 845 " var td = tr.insertCell();\n" " var td = tr.insertCell();\n"
834 846 " var v = '?';\n" " var v = '?';\n"
835 847 " td.style.border = '1px solid black';\n" " td.style.border = '1px solid black';\n"
836 848 " td.contentEditable = true;\n" " td.contentEditable = true;\n"
837 " td.id = 'grid1-' + i + '-' + j;\n"
849 " //td.id = id + '-' + i + '-' + j;\n"
838 850 " var tn = document.createTextNode(v);\n" " var tn = document.createTextNode(v);\n"
839 851 " td.appendChild(tn);\n" " td.appendChild(tn);\n"
840 " td.setAttribute('oninput', 'window.wsdemo.grid1_oninput(this.id,' + i + ',' + j + ');');\n"
852 " td.setAttribute('oninput', 'window.wsdemo.grid1_oninput(\\'' + id + '\\', ' + i + ', ' + j + ');');\n"
841 853 " }\n" " }\n"
842 854 " }\n" " }\n"
843 855 " d.appendChild(t);\n" " d.appendChild(t);\n"
844 856 "}\n" "}\n"
845 857 "\n" "\n"
846 "window.wsdemo.grid1_init();";
858 "window.wsdemo.grid1_init('grid1', 3, 3);\n"
859 "window.wsdemo.grid1_init('grid2', 3, 3);";
847 860 push_code(C, u); push_code(C, u);
848 861
849 862 for (i = 0; i < 3; i++) { for (i = 0; i < 3; i++) {
850 863 for (j = 0; j < 3; j++) { for (j = 0; j < 3; j++) {
851 864 snprintf(code, sizeof(code), snprintf(code, sizeof(code),
852 "window.wsdemo.grid1_update(%hhu, %hhu, '%s');",
853 i, j, grid1_data[i][j]);
865 "window.wsdemo.grid1_update('grid1', %hhu, %hhu, '%s');",
866 i, j, grid1_data1[i][j]);
867 push_code(C, code);
868
869 snprintf(code, sizeof(code),
870 "window.wsdemo.grid1_update('grid2', %hhu, %hhu, '%s');",
871 i, j, grid1_data2[i][j]);
854 872 push_code(C, code); push_code(C, code);
855 873 } }
856 874 } }
 
... ... static void grid1(struct Conn *C)
859 877 } }
860 878 } }
861 879
880 /*
881 * Prepare the 'users' table and send the current list
882 */
883 static void users(struct Conn *C)
884 {
885 struct priv *p, *p2;
886 char code[4096];
887 struct Clients *q;
888
889 p = Conn_get_private(C);
890 if (!p->users_init) {
891 const char *u =
892 "window.wsdemo.users_update = function(operation, id, ua, visibility) {\n"
893 " console.log('users_update: operation=' + operation + ' id=' + id + ' ua=' + ua + ' visibility=' + visibility);\n"
894 " var d, t, tr, td, tn, i, rows, row, cells;\n"
895 " d = document.getElementById('users');\n"
896 " t = d.getElementsByTagName('table');\n"
897 " t = t[0];\n"
898 " if (operation == 'add') {\n"
899 " tr = t.insertRow();\n"
900 " // id\n"
901 " td = tr.insertCell();\n"
902 " td.style.border = '1px solid black';\n"
903 " tn = document.createTextNode(id);\n"
904 " td.appendChild(tn);\n"
905 " // ua\n"
906 " td = tr.insertCell();\n"
907 " td.style.border = '1px solid black';\n"
908 " tn = document.createTextNode(ua);\n"
909 " td.appendChild(tn);\n"
910 " // visibility\n"
911 " td = tr.insertCell();\n"
912 " td.style.border = '1px solid black';\n"
913 " tn = document.createTextNode(visibility);\n"
914 " td.appendChild(tn);\n"
915 " return;\n"
916 " }\n"
917 "\n"
918 " rows = t.getElementsByTagName('tr');\n"
919 " for (i = 1; i < rows.length; i++) {\n"
920 " row = rows[i];\n"
921 " cells = row.getElementsByTagName('td');\n"
922 " if (cells[0].innerHTML != id)\n"
923 " continue;\n"
924 " if (operation == 'del') {\n"
925 " t.deleteRow(i);\n"
926 " return;\n"
927 " }\n"
928 " // update\n"
929 " cells[2].innerHTML = visibility;\n"
930 " }\n"
931 "}\n"
932 "\n"
933 "window.wsdemo.users_init = function() {\n"
934 " var t, t, tr, td, tn;\n"
935 " var d = document.getElementById('users');\n"
936 " if (d.children[0] != null)\n"
937 " return;\n"
938 "\n"
939 " t = document.createElement('table');\n"
940 " t.style.border = '1px solid black';\n"
941 " t.style.borderCollapse = 'collapse';\n"
942 " t.style.margin = '3px';\n"
943 " t.style.padding = '5px';\n"
944 " tr = t.insertRow();\n"
945 " // id\n"
946 " td = tr.insertCell();\n"
947 " td.style.border = '1px solid black';\n"
948 " tn = document.createTextNode('ID');\n"
949 " td.appendChild(tn);\n"
950 " // ua\n"
951 " td = tr.insertCell();\n"
952 " td.style.border = '1px solid black';\n"
953 " tn = document.createTextNode('User agent');\n"
954 " td.appendChild(tn);\n"
955 " // visibility\n"
956 " td = tr.insertCell();\n"
957 " td.style.border = '1px solid black';\n"
958 " tn = document.createTextNode('Visibility');\n"
959 " td.appendChild(tn);\n"
960 "\n"
961 " d.appendChild(t);\n"
962 "}\n"
963 "\n"
964 "window.wsdemo.users_init();";
965 push_code(C, u);
966
967 // Send current list of the users
968 q = Clients_head;
969 while (q) {
970 if (q->C != C) {
971 p2 = Conn_get_private(q->C);
972 snprintf(code, sizeof(code),
973 "window.wsdemo.users_update('add', '%lld', '%s', '%s');",
974 Conn_get_id(q->C), p2->ua, p2->visibility ? "Yes" : "No");
975 push_code(C, code);
976 }
977 q = q->next;
978 }
979
980 p->users_init = 1;
981 }
982 }
983
862 984 static void trigger(struct Conn *C) static void trigger(struct Conn *C)
863 985 { {
864 986 struct priv *p; struct priv *p;
 
... ... static void trigger(struct Conn *C)
906 1028 " }\n" " }\n"
907 1029 "\n" "\n"
908 1030 " // Toggle visibility\n" " // Toggle visibility\n"
909 " console.log('display=' + d.style.display);\n"
910 1031 " if (d.style.display == 'block')\n" " if (d.style.display == 'block')\n"
911 1032 " d.style.display = 'none';\n" " d.style.display = 'none';\n"
912 1033 " else\n" " else\n"
913 1034 " d.style.display = 'block';\n" " d.style.display = 'block';\n"
1035 "}\n"
1036 "\n"
1037 "window.wsdemo.fix_canvas = function(canvas)\n" // TODO: must be called when user zooms!
1038 "{\n"
1039 " var dpi = window.devicePixelRatio;\n"
1040 " var h = +getComputedStyle(canvas).getPropertyValue('height').slice(0, -2);\n"
1041 " var w = +getComputedStyle(canvas).getPropertyValue('width').slice(0, -2);\n"
1042 " console.log('dpi=' + dpi + ' h=' + h + ' w=' + w);\n"
1043 " canvas.setAttribute('height', h * dpi);\n"
1044 " canvas.setAttribute('width', w * dpi);\n"
914 1045 "}\n"; "}\n";
915 1046 push_code(C, code); push_code(C, code);
916 1047
 
... ... static void trigger(struct Conn *C)
936 1067 pie1(C); pie1(C);
937 1068 pie2(C); pie2(C);
938 1069 grid1(C); grid1(C);
1070 users(C);
939 1071 } }
940 1072
941 1073 static const char main_screen[] = static const char main_screen[] =
 
... ... static const char main_screen[] =
980 1112 "<div class=\"gem\">\n" "<div class=\"gem\">\n"
981 1113 "<div class=\"title\">Bandwidth (SVG)</div>\n" "<div class=\"title\">Bandwidth (SVG)</div>\n"
982 1114 "<div class=\"note\" width=\"200px\">Note: the width of the SVG is" "<div class=\"note\" width=\"200px\">Note: the width of the SVG is"
983 " scaled based on available width, but no more than 200px.</div>\n"
1115 " scaled based on available width, but no more than 200px. The old data is streamed from the server.</div>\n"
984 1116 "<svg id=\"band1_container\" height=\"102\" width=\"100\" style=\"border: 1px solid green\">\n" "<svg id=\"band1_container\" height=\"102\" width=\"100\" style=\"border: 1px solid green\">\n"
985 1117 " <g id=\"band1\"></g>\n" " <g id=\"band1\"></g>\n"
986 1118 " <line id=\"band1_line\" x1=\"0\" x2=\"100\" y1=\"50\" y2=\"50\" style=\"stroke: blue\" />\n" " <line id=\"band1_line\" x1=\"0\" x2=\"100\" y1=\"50\" y2=\"50\" style=\"stroke: blue\" />\n"
 
... ... static const char main_screen[] =
992 1124 "</div>\n" "</div>\n"
993 1125 "\n" "\n"
994 1126 "<div class=\"gem\" width=\"420px\">\n" "<div class=\"gem\" width=\"420px\">\n"
995 "<div class=\"title\">Arc 1 (SVG arcs + div text)</div>\n"
1127 "<div class=\"title\">Arc 1 (SVG arcs and text)</div>\n"
996 1128 "<svg height=\"100\" width=\"100\" style=\"border: 1px solid green\">\n" "<svg height=\"100\" width=\"100\" style=\"border: 1px solid green\">\n"
997 1129 "<defs>\n" "<defs>\n"
998 1130 " <filter id=\"ds1\" x=\"-50%\" y=\"-50%\" width=\"200%\" height=\"200%\">\n" " <filter id=\"ds1\" x=\"-50%\" y=\"-50%\" width=\"200%\" height=\"200%\">\n"
 
... ... static const char main_screen[] =
1068 1200 "</div>\n" "</div>\n"
1069 1201 "\n" "\n"
1070 1202 "<div class=\"gem\">\n" "<div class=\"gem\">\n"
1071 " <div class=\"title\">Editable grid (HTML5 content editable)</div>\n"
1203 " <div class=\"title\">Editable grids (HTML5 content editable)</div>\n"
1072 1204 " <div class=\"note\" width=\"200px\">" " <div class=\"note\" width=\"200px\">"
1073 1205 " Note: please load this page on two different devices, then try" " Note: please load this page on two different devices, then try"
1074 1206 " to change the content of a cell and watch the other device to" " to change the content of a cell and watch the other device to"
1075 1207 " see how the value changes." " see how the value changes."
1076 1208 " </div>\n" " </div>\n"
1077 " <div id=\"grid1\"></div>\n"
1078 " <input type=\"button\" onclick=\"window.wsdemo.source('grid1', ['grid1_update', 'grid1_oninput', 'grid1_init']);\" value=\"Source\" />\n"
1209 " Grid1: <div id=\"grid1\"></div>\n"
1210 " Grid2: <div id=\"grid2\"></div>\n"
1211 " <input type=\"button\" onclick=\"window.wsdemo.source('grid1', ['grid1_update', 'grid1_oninput', 'grid1_init']);\" value=\"Source\" />\n"
1079 1212 " <div class=\"source\" id=\"grid1_source\"></div>\n" " <div class=\"source\" id=\"grid1_source\"></div>\n"
1080 1213 "</div>\n" "</div>\n"
1081 1214 "\n" "\n"
1082 1215 "<div class=\"gem\">\n" "<div class=\"gem\">\n"
1083 "Buttons<br />\n"
1084 "<input type=\"button\" onclick=\"window.wsdemo.button('notify');\""
1085 " value=\"trigger notification\" />\n"
1216 " <div class=\"title\">Connected users</div>\n"
1217 " <div id=\"users\"></div>\n"
1218 " <input type=\"button\" onclick=\"window.wsdemo.source('users', ['users_update', 'users_init']);\" value=\"Source\" />\n"
1219 " <div class=\"source\" id=\"users_source\"></div>\n"
1220 "</div>\n"
1221 "\n"
1222 "<div class=\"gem\">\n"
1223 " <div class=\"title\">Notifications</div>\n"
1224 " <input type=\"button\" onclick=\"dispatch_notifications();\" value=\"trigger notification\" />\n"
1086 1225 "</div>\n" "</div>\n"
1087 1226 "\n"; "\n";
1088 1227
 
... ... static void accept_cb(struct Conn *C)
1127 1266 static void close_cb(struct Conn *C) static void close_cb(struct Conn *C)
1128 1267 { {
1129 1268 struct Clients *q, *p; struct Clients *q, *p;
1269 char code[4096];
1130 1270
1131 1271 Log(0, "%llu %s Closing...\n", Conn_get_id(C), __func__); Log(0, "%llu %s Closing...\n", Conn_get_id(C), __func__);
1132 1272
1273 snprintf(code, sizeof(code),
1274 "window.wsdemo.users_update('del', '%lld', '', '');",
1275 Conn_get_id(C));
1276 push_code_broadcast(C, code);
1277
1133 1278 if (C == Clients_head->C) { if (C == Clients_head->C) {
1134 1279 p = Clients_head; p = Clients_head;
1135 1280 Clients_head = Clients_head->next; Clients_head = Clients_head->next;
 
... ... static void close_cb(struct Conn *C)
1152 1297 } }
1153 1298 } }
1154 1299
1300 static void force_alpha_num(char *s)
1301 {
1302 char *p = s;
1303
1304 while (*s) {
1305 if (isalnum(*s)) {
1306 *p = *s;
1307 p++;
1308 }
1309 s++;
1310 }
1311 *p = '\0';
1312 }
1313
1155 1314 static void process_json(struct Conn *C, struct json_object *j) static void process_json(struct Conn *C, struct json_object *j)
1156 1315 { {
1157 1316 const char *s_op, *s_answer, *s_text; const char *s_op, *s_answer, *s_text;
 
... ... static void process_json(struct Conn *C, struct json_object *j)
1181 1340 return; return;
1182 1341 } }
1183 1342
1343 if (strcmp(s_op, "visibility") == 0) {
1344 json_object_object_get_ex(j, "v", &text);
1345 priv->visibility = json_object_get_int(text);
1346 Log(0, "\tSet visibility to %u\n", priv->visibility);
1347 snprintf(code, sizeof(code),
1348 "window.wsdemo.users_update('update', '%lld', '%s', '%s');",
1349 Conn_get_id(C), priv->ua, priv->visibility ? "Yes" : "No");
1350 push_code_broadcast(C, code);
1351 return;
1352 }
1353
1184 1354 if (strcmp(s_op, "init") == 0) { if (strcmp(s_op, "init") == 0) {
1185 1355 json_object_object_get_ex(j, "version", &text); json_object_object_get_ex(j, "version", &text);
1186 1356 s_text = json_object_get_string(text); s_text = json_object_get_string(text);
1357 snprintf(priv->version, sizeof(priv->version), "%s", s_text);
1358
1359 json_object_object_get_ex(j, "ua", &text);
1360 s_text = json_object_get_string(text);
1361 snprintf(priv->ua, sizeof(priv->ua), "%s", s_text);
1187 1362
1188 Log(10, "\tWe have an init command [version=%s]!\n", s_text);
1363 Log(10, "\tWe have an init command [version=%s] [ua=%s]!\n",
1364 priv->version, priv->ua);
1189 1365 json_object_object_add(answer, "op", json_object_object_add(answer, "op",
1190 1366 json_object_new_string("init")); json_object_new_string("init"));
1191 1367 json_object_object_add(answer, "id", json_object_object_add(answer, "id",
 
... ... static void process_json(struct Conn *C, struct json_object *j)
1195 1371 s_answer = json_object_to_json_string(answer); s_answer = json_object_to_json_string(answer);
1196 1372 Conn_web_ws_enqueue(C, 1, 1, s_answer, strlen(s_answer)); Conn_web_ws_enqueue(C, 1, 1, s_answer, strlen(s_answer));
1197 1373 json_object_put(answer); json_object_put(answer);
1374
1375 snprintf(code, sizeof(code),
1376 "window.wsdemo.users_update('add', '%lld', '%s', 'Yes');",
1377 Conn_get_id(C), priv->ua);
1378 push_code_broadcast(C, code);
1198 1379 return; return;
1199 1380 } }
1200 1381
 
... ... static void process_json(struct Conn *C, struct json_object *j)
1240 1421 if (strcmp(s_op, "grid1_oninput") == 0) { if (strcmp(s_op, "grid1_oninput") == 0) {
1241 1422 unsigned char i, k; unsigned char i, k;
1242 1423 char *q; char *q;
1424 const char *id;
1425
1426 json_object_object_get_ex(j, "id", &text);
1427 id = json_object_get_string(text);
1243 1428
1244 1429 json_object_object_get_ex(j, "i", &text); json_object_object_get_ex(j, "i", &text);
1245 1430 i = json_object_get_int(text); i = json_object_get_int(text);
 
... ... static void process_json(struct Conn *C, struct json_object *j)
1250 1435 json_object_object_get_ex(j, "value", &text); json_object_object_get_ex(j, "value", &text);
1251 1436 s_text = json_object_get_string(text); s_text = json_object_get_string(text);
1252 1437
1253 Log(10, "\tWe have a grid1 event [i=%hhu j=%hhu value=[%s]]!\n",
1254 i, k, s_text);
1438 Log(10, "\tWe have a grid1 event [id=%s i=%hhu j=%hhu value=%s]!\n",
1439 id, i, k, s_text);
1255 1440
1256 1441 if ((i < 3) && (k < 3)) { if ((i < 3) && (k < 3)) {
1257 snprintf(grid1_data[i][k], sizeof(grid1_data[i][k]),
1258 "%s", s_text);
1442 if (strcmp(id, "grid1") == 0)
1443 q = grid1_data1[i][k];
1444 else
1445 q = grid1_data2[i][k];
1259 1446
1260 q = grid1_data[i][k];
1261 while (isalnum(*q))
1262 q++;
1263 *q = '\0';
1447 snprintf(q, GRID1_CELL_SIZE, "%s", s_text);
1448 Log(10, "\tq=%s!\n", q);
1449 force_alpha_num(q);
1450 Log(10, "\tq=%s!\n", q);
1264 1451
1265 1452 snprintf(code, sizeof(code), snprintf(code, sizeof(code),
1266 "window.wsdemo.grid1_update(%hhu, %hhu, '%s');",
1267 i, k, s_text);
1453 "window.wsdemo.grid1_update('%s', %hhu, %hhu, '%s');",
1454 id, i, k, q);
1268 1455 push_code_broadcast(C, code); push_code_broadcast(C, code);
1269 1456 } }
1270 1457
 
... ... static void ws1(struct Conn *C)
1306 1493 return; return;
1307 1494 } }
1308 1495
1309 if (debug > 10)
1310 Conn_web_ws_log(&w);
1311
1312 1496 dump = Conn_dump(Conn_ibuf(C), Conn_iqlen(C)); dump = Conn_dump(Conn_ibuf(C), Conn_iqlen(C));
1313 1497 Log(5, "\tReceived: %s\n", dump); Log(5, "\tReceived: %s\n", dump);
1314 1498 free(dump); free(dump);
 
... ... static void ws1(struct Conn *C)
1333 1517 static void drop_privileges(struct Conn *C) static void drop_privileges(struct Conn *C)
1334 1518 { {
1335 1519 int ret, err; int ret, err;
1336 cap_t caps;
1520 cap_t caps = NULL;
1337 1521
1338 1522 chdir("/"); chdir("/");
1339 1523
 
... ... int main(void)
1381 1565 // Init grid1 data // Init grid1 data
1382 1566 for (i = 0; i < 3; i++) { for (i = 0; i < 3; i++) {
1383 1567 for (j = 0; j < 3; j++) { for (j = 0; j < 3; j++) {
1384 snprintf(grid1_data[i][j], sizeof(grid1_data[i][j]),
1568 snprintf(grid1_data1[i][j], sizeof(grid1_data1[i][j]),
1569 "%ld", random() % 1000);
1570 snprintf(grid1_data2[i][j], sizeof(grid1_data2[i][j]),
1385 1571 "%ld", random() % 1000); "%ld", random() % 1000);
1386 1572 } }
1387 1573 } }
File examples/wsdemo.data/index.html changed (mode: 100644) (index c1b5661..51c54ff)
22 22 Welcome to <a href="https://rocketgit.com/user/catalinux/Conn/source/tree/branch/master/blob/examples/wsdemo.c" target="_blank">wsdemo!</a><br /> Welcome to <a href="https://rocketgit.com/user/catalinux/Conn/source/tree/branch/master/blob/examples/wsdemo.c" target="_blank">wsdemo!</a><br />
23 23 It is using <a href="https://rocketgit.com/user/catalinux/Conn" target="_blank">Conn</a> library for the web part.<br /> It is using <a href="https://rocketgit.com/user/catalinux/Conn" target="_blank">Conn</a> library for the web part.<br />
24 24 Author: Catalin(ux) M. BOIE<br /> Author: Catalin(ux) M. BOIE<br />
25 <br />
25 26 This demo tries to prove that you can build websites without insane (more than 100KiB) This demo tries to prove that you can build websites without insane (more than 100KiB)
26 27 amount of JavaScript code. I am very disappointed by today websites. Disgusting crap. amount of JavaScript code. I am very disappointed by today websites. Disgusting crap.
27 28 The sad thing is that this crap becomes standard.<br /> The sad thing is that this crap becomes standard.<br />
28 29 The server side is a C application dealing with the data push.<br /> The server side is a C application dealing with the data push.<br />
29 30 On the client side, there is the JS code dealing with websocket and a very small part On the client side, there is the JS code dealing with websocket and a very small part
30 to dispatch the data pushed. The whole JS code used here is around than 5KiB.<br />
31 to dispatch the data pushed. The whole JS code used here is around 5KiB.<br />
31 32 If you did not paid attention above: no jQuery or any other framework was used to create this demo!<br /> If you did not paid attention above: no jQuery or any other framework was used to create this demo!<br />
32 33 Enjoy the demo and do not forget to send feedback to wsdemo@embedromix.ro!<br /> Enjoy the demo and do not forget to send feedback to wsdemo@embedromix.ro!<br />
33 34 </div> </div>
File examples/wsdemo.data/main.css changed (mode: 100644) (index ac11f53..058d3f2)
... ... pre {
44 44 padding: 3px; padding: 3px;
45 45 border: 1px solid blue; border: 1px solid blue;
46 46 margin: 3px; margin: 3px;
47
48 todo-display: flex;
49 todo-flex-direction: column;
50 47 } }
51 48
52 49 .title { .title {
File examples/wsdemo.data/main.js changed (mode: 100644) (index 9b2a23d..48db4e8)
3 3 // License: LGPLv3+ // License: LGPLv3+
4 4 // Copyright: Catalin(ux) M. BOIE // Copyright: Catalin(ux) M. BOIE
5 5
6 var my_ws_url = 'ws://' + window.location.host + '/ws';
6 console.log('main.js running...');
7
8 var my_ws_url = 'wss://' + window.location.host + '/ws';
7 9 var timer, ka; var timer, ka;
8 10 var ws; var ws;
9 11 var div_status, div_big; var div_status, div_big;
 
... ... function keep_alive()
35 37
36 38 function reconnect() function reconnect()
37 39 { {
40 console.log('reconnect...');
41
38 42 div_status.innerHTML = 'Status: connecting...'; div_status.innerHTML = 'Status: connecting...';
39 43
40 44 // We do not want the re-connect timer to trigger now, when // We do not want the re-connect timer to trigger now, when
 
... ... function reconnect()
45 49 if (ka != undefined) // TODO: check if this is correct if (ka != undefined) // TODO: check if this is correct
46 50 clearInterval(ka); clearInterval(ka);
47 51
48 console.log('connecting...');
52 console.log('connecting [' + my_ws_url + ']...');
49 53 ws = new WebSocket(my_ws_url); ws = new WebSocket(my_ws_url);
54 console.log('ws.readyState (0=conn, 1=open, 2=closing, 3=closed)=' + ws.readyState);
50 55
51 56 ws.onopen = function(ev) ws.onopen = function(ev)
52 57 { {
53 58 var data = { var data = {
54 59 op: 'init', op: 'init',
55 version: 1
60 version: 1,
61 ua: window.navigator.userAgent
56 62 }; };
57 63
58 64 console.log('onopen: sending init...'); console.log('onopen: sending init...');
 
... ... function reconnect()
72 78
73 79 ws.onclose = function(ev) ws.onclose = function(ev)
74 80 { {
81 console.log('onclose: [' + ev.reason + '] ' + ev.code);
82
75 83 clearInterval(ka); clearInterval(ka);
76 84
77 console.log('onclose: [' + ev.reason + '] ' + ev.code);
85 clearInterval(timer);
78 86 timer = setInterval(reconnect, reconnect_time_ms); timer = setInterval(reconnect, reconnect_time_ms);
79 87
80 88 div_status.innerHTML = 'Status: connection closed: [' div_status.innerHTML = 'Status: connection closed: ['
 
... ... function reconnect()
97 105 div_big.innerHTML = j.html; div_big.innerHTML = j.html;
98 106 } else if (j.op == 'push') { } else if (j.op == 'push') {
99 107 if (j.obj == 'exec') { if (j.obj == 'exec') {
100 eval(j.code);
108 //console.log('onmessage: eval: ' + j.code);
109 try {
110 eval(j.code);
111 } catch (e) {
112 console.log('onmessage: exception eval [' + e + ']: ' + j.code);
113 }
101 114 } else { } else {
102 115 console.log('Unknown object!'); console.log('Unknown object!');
103 116 } }
 
... ... function reconnect()
108 121 var not = new Notification( var not = new Notification(
109 122 'New message from ' + j.from, 'New message from ' + j.from,
110 123 { body: j.msg }); { body: j.msg });
124 } else if (notify_perm == 'denied') {
125 console.log('Notifications were denied!');
126 } else {
127 console.log('Notifications were not granted!');
111 128 } }
112 129 } else { } else {
113 130 console.log('invalid op [' + j.op + '] [' + ev.data + ']'); console.log('invalid op [' + j.op + '] [' + ev.data + ']');
 
... ... function my_start()
141 158 div_status = document.getElementById('my_status'); div_status = document.getElementById('my_status');
142 159 div_big = document.getElementById('big'); div_big = document.getElementById('big');
143 160
144 // Ask permission for notifications (if not already granted)
145 Notification.requestPermission().then(function(r) { notify_perm = r; });
146
147 161 // Add a listener for msg div // Add a listener for msg div
148 162 //div_msg.addEventListener('keydown', msg_key_event, false); //div_msg.addEventListener('keydown', msg_key_event, false);
149 163
150 164 reconnect(); reconnect();
151 165 } }
152 166
153 //ws.close();
167 function dispatch_notifications()
168 {
169 if (!("Notification" in window)) {
170 console.log('Notifications are not supported!');
171 return;
172 }
173
174 console.log('Requesting permission...');
175 Notification.requestPermission().then(
176 function(r) {
177 notify_perm = r;
178 console.log('Notifications set to [' + notify_perm + ']');
179 if (notify_perm == 'granted')
180 window.wsdemo.button('notify');
181 }
182 );
183 }
184
185 // TODO: move this in the C code, init section
186 window.wsdemo_visibility = function(v)
187 {
188 var v2 = v == 'visible' ? 1 : 0;
189 console.log('visibility = ' + v + ' v2=' + v2);
190 var data = { op: 'visibility', v: v2 };
191 ws.send(JSON.stringify(data));
192
193 }
194
195 document.addEventListener('visibilitychange', function() {
196 window.wsdemo_visibility(document.visibilityState);
197 });
198
199 //window.onbeforeunload = function()
200 //{
201 // console.log('user closing the page');
202 // ws.close();
203 // return true; // return 'false' => browser askes if you want to leave the page
204 //}
205
206 console.log('main.js ended');
File examples/wsdemo.data/wsdemo.nginx changed (mode: 100644) (index 595a30f..8ef0db5)
... ... upstream wsdemo {
3 3 } }
4 4
5 5 server { server {
6 listen 9051;
7 listen [::]:9051;
6 listen 9051 ssl http2;
7 listen [::]:9051 ssl http2;
8 8
9 9 root /usr/share/wsdemo/root; root /usr/share/wsdemo/root;
10 10
11 ssl_certificate /etc/letsencrypt/live/r1.embedromix.ro/fullchain.pem;
12 ssl_certificate_key /etc/letsencrypt/live/r1.embedromix.ro/privkey.pem;
13 ssl_prefer_server_ciphers off;
14 ssl_protocols TLSv1.2 TLSv1.3;
15
11 16 access_log /var/log/nginx/wsdemo-access.log; access_log /var/log/nginx/wsdemo-access.log;
12 17 error_log /var/log/nginx/wsdemo-error.log; error_log /var/log/nginx/wsdemo-error.log;
13 18
 
... ... server {
19 24 proxy_set_header Connection "upgrade"; proxy_set_header Connection "upgrade";
20 25 proxy_read_timeout 120; proxy_read_timeout 120;
21 26 proxy_buffering off; proxy_buffering off;
27
28 tcp_nodelay on;
22 29 } }
23 30 } }
Date/time (UTC) Type Misc Labels
2022-10-21 16:27 build fedora-rawhide-x86_64 worker/r1 builder/color=fff worker_elap/129s wait_time/141s date/2022-10-21 time/16:22
2022-10-22 04:27 build fedora-36-x86_64 worker/r1 builder/color=fff worker_elap/112s wait_time/43344s date/2022-10-21 time/16:22
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