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_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 = "&"; need = 5; break; |
|
29 |
|
case '<': new = "<"; need = 4; break; |
|
30 |
|
case '>': new = ">"; need = 4; break; |
|
31 |
|
case '"': new = """; need = 6; break; |
|
32 |
|
case '\'': new = ""; need = 5; break; |
|
33 |
|
case '/': new = "f;"; need = 5; break; |
|
34 |
|
case '`': new = "`"; 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 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 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 |
} |
} |