1 /**
2 *
3 * Ulfius Framework
4 *
5 * REST framework library
6 *
7 * u_websocket.c: websocket implementation
8 *
9 * Copyright 2017-2020 Nicolas Mora <mail@babelouest.org>
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public License
13 * as published by the Free Software Foundation;
14 * version 2.1 of the License.
15 *
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU GENERAL PUBLIC LICENSE for more details.
20 *
21 * You should have received a copy of the GNU General Public
22 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
23 *
24 */
25
26 #include "u_private.h"
27 #include "ulfius.h"
28
29 #if defined(__APPLE__) && !defined (MSG_NOSIGNAL)
30 #define MSG_NOSIGNAL 0
31 #endif
32
33 #ifndef U_DISABLE_WEBSOCKET
34 #include "yuarel.h"
35 #include <string.h>
36 #include <stdio.h>
37 #include <unistd.h>
38 #include <fcntl.h>
39 #include <pthread.h>
40 #include <errno.h>
41 #include <unistd.h>
42 #include <sys/socket.h>
43 #include <netinet/in.h>
44 #include <netdb.h>
45 #include <stdlib.h>
46 #include <gnutls/crypto.h>
47 #include <zlib.h>
48 #include <errno.h>
49
50 #define STR_HELPER(x) #x
51 #define STR(x) STR_HELPER(x)
52
53 #define U_WEBSOCKET_DEFAULT_MEMORY_LEVEL 4
54 #define U_WEBSOCKET_DEFAULT_WINDOWS_BITS 15
55
56 /**********************************/
57 /** Internal websocket functions **/
58 /**********************************/
59
ulfius_free_websocket_extension_pointer_list(void * extension)60 void ulfius_free_websocket_extension_pointer_list(void * extension) {
61 ulfius_free_websocket_extension((struct _websocket_extension *)extension);
62 }
63
ulfius_free_websocket_extension(struct _websocket_extension * websocket_extension)64 void ulfius_free_websocket_extension(struct _websocket_extension * websocket_extension) {
65 if (websocket_extension != NULL) {
66 o_free(websocket_extension->extension_server);
67 o_free(websocket_extension->extension_client);
68 o_free(websocket_extension);
69 }
70 }
71
ulfius_init_websocket_extension(struct _websocket_extension * websocket_extension)72 int ulfius_init_websocket_extension(struct _websocket_extension * websocket_extension) {
73 if (websocket_extension != NULL) {
74 websocket_extension->extension_server = NULL;
75 websocket_extension->extension_client = NULL;
76 websocket_extension->websocket_extension_message_out_perform = NULL;
77 websocket_extension->websocket_extension_message_out_perform_user_data = NULL;
78 websocket_extension->websocket_extension_message_in_perform = NULL;
79 websocket_extension->websocket_extension_message_in_perform_user_data = NULL;
80 websocket_extension->websocket_extension_server_match = NULL;
81 websocket_extension->websocket_extension_server_match_user_data = NULL;
82 websocket_extension->websocket_extension_client_match = NULL;
83 websocket_extension->websocket_extension_client_match_user_data = NULL;
84 websocket_extension->enabled = 0;
85 return U_OK;
86 } else {
87 return U_ERROR_PARAMS;
88 }
89 }
90
is_websocket_data_available(struct _websocket_manager * websocket_manager)91 static int is_websocket_data_available(struct _websocket_manager * websocket_manager) {
92 int ret = 0, poll_ret = 0;
93
94 if (websocket_manager->tls) {
95 ret = gnutls_record_check_pending(websocket_manager->gnutls_session);
96 if (ret)
97 return ret;
98 }
99 poll_ret = poll(&websocket_manager->fds_in, 1, U_WEBSOCKET_USEC_WAIT);
100 if (poll_ret == -1) {
101 y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error poll websocket read");
102 websocket_manager->connected = 0;
103 } else if (websocket_manager->fds_in.revents & (POLLRDHUP|POLLERR|POLLHUP|POLLNVAL)) {
104 websocket_manager->connected = 0;
105 } else if (poll_ret > 0) {
106 ret = 1;
107 }
108 return ret;
109 }
110
is_websocket_write_available(struct _websocket_manager * websocket_manager)111 static int is_websocket_write_available(struct _websocket_manager * websocket_manager) {
112 int ret = 0, poll_ret = 0;
113
114 if (websocket_manager->tls) {
115 ret = gnutls_record_check_pending(websocket_manager->gnutls_session);
116 if (ret)
117 return ret;
118 }
119 poll_ret = poll(&websocket_manager->fds_out, 1, U_WEBSOCKET_USEC_WAIT);
120 if (poll_ret == -1) {
121 y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error poll websocket write");
122 websocket_manager->connected = 0;
123 } else if (websocket_manager->fds_out.revents & (POLLRDHUP|POLLERR|POLLHUP|POLLNVAL)) {
124 websocket_manager->connected = 0;
125 } else if (poll_ret > 0) {
126 ret = 1;
127 }
128 return ret;
129 }
130
read_data_from_socket(struct _websocket_manager * websocket_manager,uint8_t * data,size_t len)131 static ssize_t read_data_from_socket(struct _websocket_manager * websocket_manager, uint8_t * data, size_t len) {
132 ssize_t ret = 0, data_len;
133
134 if (len > 0) {
135 do {
136 if (is_websocket_data_available(websocket_manager)) {
137 if (websocket_manager->tls) {
138 data_len = gnutls_record_recv(websocket_manager->gnutls_session, &data[ret], (len - ret));
139 } else if (websocket_manager->type == U_WEBSOCKET_SERVER) {
140 data_len = read(websocket_manager->mhd_sock, &data[ret], (len - ret));
141 } else {
142 data_len = read(websocket_manager->tcp_sock, &data[ret], (len - ret));
143 }
144 if (data_len > 0) {
145 ret += data_len;
146 } else if (data_len < 0) {
147 ret = -1;
148 break;
149 }
150 }
151 } while (websocket_manager->connected && ret < (ssize_t)len);
152 }
153 return ret;
154 }
155
156 /**
157 * Workaround to make sure a message, as long as it can be is complete sent
158 */
ulfius_websocket_send_frame(struct _websocket_manager * websocket_manager,const uint8_t * data,size_t len)159 static void ulfius_websocket_send_frame(struct _websocket_manager * websocket_manager, const uint8_t * data, size_t len) {
160 ssize_t ret = 0, off;
161 if (data != NULL && len > 0) {
162 for (off = 0; (size_t)off < len; off += ret) {
163 if (websocket_manager->type == U_WEBSOCKET_SERVER) {
164 if (is_websocket_write_available(websocket_manager)) {
165 ret = send(websocket_manager->mhd_sock, &data[off], len - off, MSG_NOSIGNAL);
166 if (ret < 0) {
167 break;
168 }
169 } else {
170 break;
171 }
172 } else {
173 if (websocket_manager->tls) {
174 ret = gnutls_record_send(websocket_manager->gnutls_session, &data[off], len - off);
175 } else {
176 ret = send(websocket_manager->tcp_sock, &data[off], len - off, MSG_NOSIGNAL);
177 }
178 if (ret < 0) {
179 break;
180 }
181 }
182 }
183 }
184 }
185
186 /**
187 * Builds a websocket frame from the given struct _websocket_message
188 * returns U_OK on success
189 * frame must be free'd after use
190 */
ulfius_build_frame(const struct _websocket_message * message,const uint64_t data_offset,const uint64_t data_len,uint8_t ** frame,size_t * frame_len)191 static int ulfius_build_frame (const struct _websocket_message * message,
192 const uint64_t data_offset,
193 const uint64_t data_len,
194 uint8_t ** frame,
195 size_t * frame_len) {
196 int ret, has_fin = 0;
197 unsigned int i;
198 uint64_t off, frame_data_len;
199 if (message != NULL && frame != NULL && frame_len != NULL) {
200 *frame_len = 2;
201 if (message->data_len >= 65536) {
202 *frame_len += 8;
203 } else if (message->data_len > 125) {
204 *frame_len += 2;
205 }
206 if (message->has_mask) {
207 *frame_len += 4;
208 }
209 if (data_offset + data_len >= message->data_len) {
210 frame_data_len = message->data_len - data_offset;
211 has_fin = 1;
212 } else {
213 frame_data_len = data_len;
214 }
215 *frame_len += frame_data_len;
216 *frame = o_malloc(*frame_len);
217 if (*frame != NULL) {
218 if (has_fin) {
219 (*frame)[0] = (message->opcode | message->rsv | U_WEBSOCKET_BIT_FIN);
220 } else {
221 (*frame)[0] = message->rsv;
222 }
223 if (message->data_len >= 65536) {
224 (*frame)[1] = 127;
225 (*frame)[2] = (uint8_t)(frame_data_len >> 54);
226 (*frame)[3] = (uint8_t)(frame_data_len >> 48);
227 (*frame)[4] = (uint8_t)(frame_data_len >> 40);
228 (*frame)[5] = (uint8_t)(frame_data_len >> 32);
229 (*frame)[6] = (uint8_t)(frame_data_len >> 24);
230 (*frame)[7] = (uint8_t)(frame_data_len >> 16);
231 (*frame)[8] = (uint8_t)(frame_data_len >> 8);
232 (*frame)[9] = (uint8_t)(frame_data_len);
233 off = 10;
234 } else if (data_len > 125) {
235 (*frame)[1] = 126;
236 (*frame)[2] = (uint8_t)(frame_data_len >> 8);
237 (*frame)[3] = (uint8_t)(frame_data_len);
238 off = 4;
239 } else {
240 (*frame)[1] = (uint8_t)frame_data_len;
241 off = 2;
242 }
243 if (message->has_mask) {
244 (*frame)[1] |= U_WEBSOCKET_MASK;
245 // Append mask
246 memcpy(*frame + off, message->mask, 4);
247 off += 4;
248 for (i=0; i < frame_data_len; i++) {
249 (*frame)[off + i] = message->data[data_offset + i] ^ message->mask[i%4];
250 }
251 } else {
252 memcpy((*frame) + off, message->data + data_offset, frame_data_len);
253 }
254 ret = U_OK;
255 } else {
256 y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error allocating resources for *frame");
257 ret = U_ERROR_MEMORY;
258 }
259 } else {
260 ret = U_ERROR_PARAMS;
261 }
262 return ret;
263 }
264
265 /**
266 * Builds a struct _websocket_message using the given parameters
267 * returns a newly allocated struct _websocket_message
268 * returned value must be free'd after use
269 */
ulfius_build_message(const uint8_t opcode,const uint8_t rsv,const short int has_mask,const char * data,const uint64_t data_len)270 static struct _websocket_message * ulfius_build_message (const uint8_t opcode,
271 const uint8_t rsv,
272 const short int has_mask,
273 const char * data,
274 const uint64_t data_len) {
275 struct _websocket_message * new_message = NULL;
276 if (
277 opcode == U_WEBSOCKET_OPCODE_TEXT ||
278 opcode == U_WEBSOCKET_OPCODE_BINARY ||
279 opcode == U_WEBSOCKET_OPCODE_CLOSE ||
280 opcode == U_WEBSOCKET_OPCODE_PING ||
281 opcode == U_WEBSOCKET_OPCODE_PONG
282 ) {
283 new_message = o_malloc(sizeof(struct _websocket_message));
284 if (new_message != NULL) {
285 if (data_len) {
286 new_message->data = o_malloc(data_len*sizeof(char));
287 } else {
288 new_message->data = NULL;
289 }
290 if (!data_len || new_message->data != NULL) {
291 new_message->opcode = opcode;
292 new_message->rsv = rsv;
293 new_message->data_len = data_len;
294 if (!has_mask) {
295 new_message->has_mask = 0;
296 memset(new_message->mask, 0, 4);
297 } else {
298 gnutls_rnd(GNUTLS_RND_NONCE, &new_message->mask, 4*sizeof(uint8_t));
299 new_message->has_mask = 1;
300 }
301 if (data_len > 0) {
302 memcpy(new_message->data, data, data_len);
303 }
304 time(&new_message->datestamp);
305 } else {
306 y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error allocating resources for new_message->data");
307 o_free(new_message);
308 new_message = NULL;
309 }
310 } else {
311 y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error allocating resources for new_message");
312 }
313 } else {
314 y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Send invalid opcode error");
315 }
316 return new_message;
317 }
318
319 /**
320 * Builds a struct _websocket_message using the given parameters
321 * Sends message to the websocket recipient in fragment if required
322 * Then pushes the message in the outcoming message list
323 * returns U_OK on success
324 */
ulfius_send_websocket_message_managed(struct _websocket_manager * websocket_manager,const uint8_t opcode,const uint8_t rsv,const uint64_t data_len,const char * data,const uint64_t fragment_len)325 static int ulfius_send_websocket_message_managed(struct _websocket_manager * websocket_manager,
326 const uint8_t opcode,
327 const uint8_t rsv,
328 const uint64_t data_len,
329 const char * data,
330 const uint64_t fragment_len) {
331 size_t offset = 0, cur_len;
332 struct _websocket_message * message;
333 uint8_t * frame = NULL;
334 size_t frame_len = 0;
335 int ret = U_OK;
336
337 if (pthread_mutex_lock(&websocket_manager->write_lock)) {
338 y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error locking write lock");
339 } else {
340 message = ulfius_build_message(opcode, rsv, (websocket_manager->type == U_WEBSOCKET_CLIENT), data, data_len);
341 if (message != NULL) {
342 if ((websocket_manager->keep_messages&U_WEBSOCKET_KEEP_OUTCOMING) && ulfius_push_websocket_message(websocket_manager->message_list_outcoming, message) != U_OK) {
343 y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error pushing new websocket message in list");
344 }
345 if (data_len) {
346 while (offset < data_len) {
347 if (!fragment_len) {
348 cur_len = data_len<(data_len - offset)?data_len:(data_len - offset);
349 } else {
350 cur_len = fragment_len<(data_len - offset)?fragment_len:(data_len - offset);
351 }
352 if ((ret = ulfius_build_frame(message, offset, cur_len, &frame, &frame_len)) != U_OK) {
353 y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error ulfius_build_frame");
354 break;
355 } else {
356 ulfius_websocket_send_frame(websocket_manager, frame, frame_len);
357 offset += cur_len;
358 o_free(frame);
359 frame = NULL;
360 frame_len = 0;
361 }
362 message->opcode = U_WEBSOCKET_OPCODE_CONTINUE;
363 }
364 } else {
365 if (ulfius_build_frame(message, 0, 0, &frame, &frame_len) == U_OK) {
366 ulfius_websocket_send_frame(websocket_manager, frame, frame_len);
367 }
368 o_free(frame);
369 }
370 if (!(websocket_manager->keep_messages&U_WEBSOCKET_KEEP_OUTCOMING)) {
371 ulfius_clear_websocket_message(message);
372 message = NULL;
373 }
374 } else {
375 y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error ulfius_build_message");
376 ret = U_ERROR;
377 }
378 pthread_mutex_unlock(&websocket_manager->write_lock);
379 }
380 return ret;
381 }
382
ulfius_merge_fragmented_message(struct _websocket_message * message_orig,struct _websocket_message * message_next_fragment)383 static int ulfius_merge_fragmented_message(struct _websocket_message * message_orig, struct _websocket_message * message_next_fragment) {
384 int ret;
385 if (message_orig != NULL && message_next_fragment != NULL && !message_orig->fin) {
386 if ((message_orig->opcode == U_WEBSOCKET_OPCODE_TEXT || message_orig->opcode == U_WEBSOCKET_OPCODE_BINARY) && message_next_fragment->opcode == U_WEBSOCKET_OPCODE_CONTINUE) {
387 if (!message_orig->fragment_len) {
388 message_orig->fragment_len = message_orig->data_len;
389 }
390 if (message_next_fragment->fin) {
391 message_orig->fin = message_next_fragment->fin;
392 }
393 if (message_next_fragment->data_len) {
394 if ((message_orig->data = o_realloc(message_orig->data, message_orig->data_len+message_next_fragment->data_len)) != NULL) {
395 memcpy(message_orig->data+message_orig->data_len, message_next_fragment->data, message_next_fragment->data_len);
396 message_orig->data_len += message_next_fragment->data_len;
397 ret = U_OK;
398 } else {
399 y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error reallocating resources for data");
400 ret = U_ERROR_PARAMS;
401 }
402 } else {
403 ret = U_OK;
404 }
405 } else {
406 ret = U_ERROR_PARAMS;
407 }
408 } else {
409 ret = U_ERROR_PARAMS;
410 }
411 return ret;
412 }
413
414 /**
415 * Read and parse a new message from the websocket
416 * Return the opcode of the new websocket, U_WEBSOCKET_OPCODE_NONE if no message arrived, or U_WEBSOCKET_OPCODE_ERROR on error
417 * Sets the new message in the message variable
418 */
ulfius_read_incoming_message(struct _websocket_manager * websocket_manager,struct _websocket_message ** message)419 static int ulfius_read_incoming_message(struct _websocket_manager * websocket_manager, struct _websocket_message ** message) {
420 int ret = U_OK, i;
421 uint8_t header[2] = {0}, payload_len[8] = {0}, masking_key[4] = {0};
422 uint8_t * payload_data = NULL;
423 size_t msg_len = 0;
424 ssize_t len = 0;
425
426 if (pthread_mutex_lock(&websocket_manager->read_lock)) {
427 y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error locking websocket read lock messages");
428 websocket_manager->connected = 0;
429 } else {
430 *message = o_malloc(sizeof(struct _websocket_message));
431 if (*message != NULL) {
432 (*message)->data_len = 0;
433 (*message)->has_mask = 0;
434 (*message)->data = NULL;
435 (*message)->fragment_len = 0;
436 (*message)->opcode = 0;
437 (*message)->rsv = 0;
438 (*message)->fin = 0;
439 time(&(*message)->datestamp);
440
441 // Read header
442 if ((len = read_data_from_socket(websocket_manager, header, 2)) == 2) {
443 (*message)->opcode = header[0] & 0x0F;
444 (*message)->rsv = header[0] & 0x70;
445 (*message)->fin = (header[0] & U_WEBSOCKET_BIT_FIN);
446 if ((header[1] & U_WEBSOCKET_LEN_MASK) <= 125) {
447 msg_len = (header[1] & U_WEBSOCKET_LEN_MASK);
448 } else if ((header[1] & U_WEBSOCKET_LEN_MASK) == 126) {
449 len = read_data_from_socket(websocket_manager, payload_len, 2);
450 if (len == 2) {
451 msg_len = payload_len[1] | ((uint64_t)payload_len[0] << 8);
452 } else if (len >= 0) {
453 ret = U_ERROR;
454 y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error reading websocket message length");
455 } else {
456 ret = U_ERROR_DISCONNECTED;
457 }
458 } else if ((header[1] & U_WEBSOCKET_LEN_MASK) == 127) {
459 len = read_data_from_socket(websocket_manager, payload_len, 8);
460 if (len == 8) {
461 msg_len = payload_len[7] |
462 ((uint64_t)payload_len[6] << 8) |
463 ((uint64_t)payload_len[5] << 16) |
464 ((uint64_t)payload_len[4] << 24) |
465 ((uint64_t)payload_len[3] << 32) |
466 ((uint64_t)payload_len[2] << 40) |
467 ((uint64_t)payload_len[1] << 48) |
468 ((uint64_t)payload_len[0] << 54);
469 } else if (len >= 0) {
470 ret = U_ERROR;
471 y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error reading websocket message length");
472 } else {
473 ret = U_ERROR_DISCONNECTED;
474 }
475 }
476 } else if (len == 0) {
477 y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error reading websocket");
478 ret = U_ERROR;
479 } else {
480 ret = U_ERROR_DISCONNECTED;
481 }
482 if (!(*message)->fin) {
483 if (!(*message)->fragment_len) {
484 (*message)->fragment_len = msg_len;
485 }
486 }
487
488 if (ret == U_OK) {
489 if (websocket_manager->type == U_WEBSOCKET_SERVER) {
490 // Read mask
491 if (header[1] & U_WEBSOCKET_MASK) {
492 (*message)->has_mask = 1;
493 len = read_data_from_socket(websocket_manager, masking_key, 4);
494 if (len != 4 && len >= 0) {
495 y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error reading websocket for mask");
496 ret = U_ERROR;
497 } else if (len < 0) {
498 ret = U_ERROR_DISCONNECTED;
499 }
500 } else {
501 y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Incoming message has no MASK flag, exiting");
502 ret = U_ERROR;
503 }
504 } else {
505 if ((header[1] & U_WEBSOCKET_MASK)) {
506 y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Incoming message has MASK flag while it should not, exiting");
507 ret = U_ERROR;
508 }
509 }
510 }
511 if (ret == U_OK && msg_len) {
512 payload_data = o_malloc(msg_len*sizeof(uint8_t));
513 if (payload_data != NULL) {
514 len = read_data_from_socket(websocket_manager, payload_data, msg_len);
515 if (len < 0) {
516 ret = U_ERROR_DISCONNECTED;
517 } else if ((unsigned int)len != msg_len) {
518 y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error reading websocket for payload_data");
519 ret = U_ERROR;
520 } else {
521 // If mask, decode message
522 (*message)->data = o_malloc((msg_len+(*message)->data_len)*sizeof(uint8_t));
523 if ((*message)->has_mask) {
524 for (i = (*message)->data_len; (unsigned int)i < (*message)->data_len + msg_len; i++) {
525 (*message)->data[i] = payload_data[i-(*message)->data_len] ^ masking_key[(i-(*message)->data_len)%4];
526 }
527 } else {
528 memcpy((*message)->data+(*message)->data_len, payload_data, msg_len);
529 }
530 (*message)->data_len += msg_len;
531 }
532 o_free(payload_data);
533 } else {
534 y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error allocating resources for payload_data, exiting");
535 ret = U_ERROR;
536 }
537 }
538 } else {
539 y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error allocating resources for *message");
540 }
541 pthread_mutex_unlock(&websocket_manager->read_lock);
542 }
543 if (ret != U_OK) {
544 ulfius_clear_websocket_message(*message);
545 *message = NULL;
546 }
547 return ret;
548 }
549
550 /**
551 * Run the websocket manager in a separated detached thread
552 */
ulfius_thread_websocket_manager_run(void * args)553 static void * ulfius_thread_websocket_manager_run(void * args) {
554 struct _websocket * websocket = (struct _websocket *)args;
555 if (websocket != NULL) {
556 websocket->websocket_manager_callback(websocket->request, websocket->websocket_manager, websocket->websocket_manager_user_data);
557
558 // Send close message if the websocket is still open
559 if (websocket->websocket_manager->connected) {
560 if (pthread_mutex_lock(&websocket->websocket_manager->read_lock)) {
561 y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error locking websocket read lock messages");
562 } else {
563 websocket->websocket_manager->close_flag = 1;
564 pthread_mutex_unlock(&websocket->websocket_manager->read_lock);
565 }
566 }
567 }
568 return NULL;
569 }
570
ulfius_websocket_extension_message_in_perform_apply(struct _websocket * websocket,struct _websocket_message * message)571 static int ulfius_websocket_extension_message_in_perform_apply(struct _websocket * websocket, struct _websocket_message * message) {
572 uint64_t data_out_len = 0, data_in_len = 0;
573 char * data_out = NULL, * data_in = NULL;
574 int ret = U_OK;
575 size_t len, i;
576 struct _websocket_extension * extension;
577
578 if ((len = pointer_list_size(websocket->websocket_manager->websocket_extension_list))) {
579 data_in = NULL;
580 if (!message->data_len || (message->data_len && (data_in = o_malloc(message->data_len*sizeof(char))) != NULL)) {
581 if (message->data_len) {
582 memcpy(data_in, message->data, message->data_len);
583 }
584 data_in_len = message->data_len;
585 for (i=0; i<len && ret == U_OK; i++) {
586 extension = pointer_list_get_at(websocket->websocket_manager->websocket_extension_list, (len-i-1));
587 if (extension != NULL &&
588 extension->enabled &&
589 extension->websocket_extension_message_in_perform != NULL &&
590 (message->rsv & extension->rsv)) {
591 if (extension->websocket_extension_message_in_perform(message->opcode,
592 data_in_len,
593 data_in,
594 &data_out_len,
595 &data_out,
596 0,
597 extension->websocket_extension_message_out_perform_user_data,
598 extension->context) != U_OK) {
599 y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error performing websocket_extension_message_in_perform at index %zu", i);
600 ret = U_ERROR;
601 } else {
602 o_free(data_in);
603 data_in = NULL;
604 data_in_len = 0;
605 if (data_out_len) {
606 if ((data_in = o_malloc(data_out_len*sizeof(char))) != NULL) {
607 memcpy(data_in, data_out, data_out_len);
608 data_in_len = data_out_len;
609 } else {
610 y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error allocating resources for data_in (%zu) (incoming)", i);
611 ret = U_ERROR_MEMORY;
612 }
613 }
614 o_free(data_out);
615 data_out = NULL;
616 data_out_len = 0;
617 }
618 }
619 }
620 o_free(message->data);
621 message->data = data_in;
622 message->data_len = data_in_len;
623 } else {
624 y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error allocating resources for data_in (incoming) %zu", message->data_len);
625 ret = U_ERROR_MEMORY;
626 }
627 }
628 return ret;
629 }
630
631 /**
632 * Run websocket in a separate thread
633 * then sets a listening message loop
634 * Complete the callback when the websocket is closed
635 * The websocket can be closed by the client, the manager, the program, or on network disconnect
636 */
ulfius_thread_websocket(void * data)637 static void * ulfius_thread_websocket(void * data) {
638 struct _websocket * websocket = (struct _websocket*)data;
639 struct _websocket_message * message = NULL, * message_previous = NULL;
640 pthread_t thread_websocket_manager;
641 int thread_ret_websocket_manager = 1, ret = U_OK;
642
643 if (websocket != NULL && websocket->websocket_manager != NULL) {
644 if (websocket->websocket_manager_callback != NULL) {
645 thread_ret_websocket_manager = pthread_create(&thread_websocket_manager, NULL, ulfius_thread_websocket_manager_run, (void *)websocket);
646 if (thread_ret_websocket_manager) {
647 y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error creating websocket manager thread, return code: %d", thread_ret_websocket_manager);
648 websocket->websocket_manager->connected = 0;
649 }
650 }
651 while (websocket->websocket_manager->connected && ret == U_OK) {
652 if (websocket->websocket_manager->close_flag) {
653 if (ulfius_websocket_send_message(websocket->websocket_manager, U_WEBSOCKET_OPCODE_CLOSE, 0, NULL) != U_OK) {
654 y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error sending close message on close_flag");
655 }
656 websocket->websocket_manager->connected = 0;
657 } else {
658 if (is_websocket_data_available(websocket->websocket_manager)) {
659 message = NULL;
660 if (ulfius_read_incoming_message(websocket->websocket_manager, &message) == U_OK) {
661 if (message->opcode == U_WEBSOCKET_OPCODE_CLOSE && message->fin) {
662 // Send close command back, then close the socket
663 if (message->data_len <= 125) {
664 if (ulfius_send_websocket_message_managed(websocket->websocket_manager, U_WEBSOCKET_OPCODE_CLOSE, 0, 0, NULL, 0) != U_OK) {
665 y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error sending close command");
666 }
667 }
668 websocket->websocket_manager->connected = 0;
669 } else if (message->opcode == U_WEBSOCKET_OPCODE_PING && message->fin) {
670 if (pthread_mutex_lock(&websocket->websocket_manager->write_lock)) {
671 y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error locking write lock");
672 } else {
673 // Send pong command
674 if (message->data_len <= 125) {
675 if (ulfius_websocket_send_message(websocket->websocket_manager, U_WEBSOCKET_OPCODE_PONG, message->data_len, message->data) != U_OK) {
676 y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error sending pong command");
677 websocket->websocket_manager->connected = 0;
678 }
679 } else {
680 websocket->websocket_manager->connected = 0;
681 }
682 pthread_mutex_unlock(&websocket->websocket_manager->write_lock);
683 }
684 } else if (message->opcode == U_WEBSOCKET_OPCODE_PONG && message->fin) {
685 if (websocket->websocket_manager->ping_sent) {
686 websocket->websocket_manager->ping_sent = 0;
687 }
688 } else if (message->opcode == U_WEBSOCKET_OPCODE_TEXT || message->opcode == U_WEBSOCKET_OPCODE_BINARY || message->opcode == U_WEBSOCKET_OPCODE_CONTINUE) {
689 if (message->fin && message->opcode == U_WEBSOCKET_OPCODE_CONTINUE && message_previous == NULL) {
690 y_log_message(Y_LOG_LEVEL_DEBUG, "Ulfius - Invalid fragmented message");
691 websocket->websocket_manager->connected = 0;
692 } else if (message->fin) {
693 if (message_previous != NULL) {
694 if (ulfius_merge_fragmented_message(message_previous, message) != U_OK) {
695 y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error merging final fragmented messages");
696 ret = U_ERROR;
697 } else {
698 ulfius_clear_websocket_message(message);
699 message = message_previous;
700 message_previous = NULL;
701 }
702 }
703 if (ret == U_OK) {
704 if (ulfius_websocket_extension_message_in_perform_apply(websocket, message) == U_OK) {
705 if (!message->rsv || (websocket->websocket_manager->rsv_expected & message->rsv)) {
706 if (message->opcode != U_WEBSOCKET_OPCODE_TEXT || !message->data_len || utf8_check(message->data, message->data_len) == NULL) {
707 if (websocket->websocket_incoming_message_callback != NULL) {
708 websocket->websocket_incoming_message_callback(websocket->request, websocket->websocket_manager, message, websocket->websocket_incoming_user_data);
709 }
710 if (websocket->websocket_manager->keep_messages&U_WEBSOCKET_KEEP_INCOMING) {
711 if (ulfius_push_websocket_message(websocket->websocket_manager->message_list_incoming, message) != U_OK) {
712 y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error pushing new websocket message in list");
713 websocket->websocket_manager->connected = 0;
714 } else {
715 message = NULL;
716 }
717 } else {
718 ulfius_clear_websocket_message(message);
719 message = NULL;
720 }
721 } else {
722 y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Invalid UTF8 text message");
723 websocket->websocket_manager->connected = 0;
724 }
725 } else {
726 y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Unexpected rsv message");
727 websocket->websocket_manager->connected = 0;
728 }
729 } else {
730 y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error ulfius_websocket_extension_message_in_perform_apply");
731 websocket->websocket_manager->connected = 0;
732 }
733 }
734 } else if (message->opcode == U_WEBSOCKET_OPCODE_TEXT || message->opcode == U_WEBSOCKET_OPCODE_BINARY || message->opcode == U_WEBSOCKET_OPCODE_CONTINUE) {
735 if (message->opcode != U_WEBSOCKET_OPCODE_CONTINUE || message_previous != NULL) {
736 if (message_previous == NULL) {
737 message_previous = message;
738 message = NULL;
739 } else {
740 if (ulfius_merge_fragmented_message(message_previous, message) != U_OK) {
741 y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error merging fragmented messages");
742 websocket->websocket_manager->connected = 0;
743 }
744 }
745 } else {
746 y_log_message(Y_LOG_LEVEL_DEBUG, "Ulfius - Invalid continue message");
747 websocket->websocket_manager->connected = 0;
748 }
749 } else {
750 y_log_message(Y_LOG_LEVEL_DEBUG, "Ulfius - Invalid fragmented message");
751 websocket->websocket_manager->connected = 0;
752 }
753 } else {
754 // Invalid opcode
755 y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error invalid opcode");
756 websocket->websocket_manager->connected = 0;
757 }
758 } else {
759 y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error ulfius_read_incoming_message");
760 websocket->websocket_manager->connected = 0;
761 }
762 ulfius_clear_websocket_message(message);
763 }
764 }
765 }
766 ulfius_clear_websocket_message(message_previous);
767 // Wait for thread manager to close if exists
768 if (!thread_ret_websocket_manager) {
769 pthread_join(thread_websocket_manager, NULL);
770 }
771 // Call websocket_onclose_callback if set
772 if (websocket->websocket_onclose_callback != NULL) {
773 websocket->websocket_onclose_callback(websocket->request, websocket->websocket_manager, websocket->websocket_onclose_user_data);
774 }
775 if (ulfius_close_websocket(websocket) != U_OK) {
776 y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error closing websocket");
777 }
778 // Broadcast end signal
779 if (websocket->websocket_manager->type == U_WEBSOCKET_CLIENT) {
780 pthread_mutex_lock(&websocket->websocket_manager->status_lock);
781 pthread_cond_broadcast(&websocket->websocket_manager->status_cond);
782 pthread_mutex_unlock(&websocket->websocket_manager->status_lock);
783 } else if (websocket->websocket_manager->type == U_WEBSOCKET_SERVER) {
784 ulfius_clear_websocket(websocket);
785 }
786 } else {
787 y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error websocket parameters");
788 }
789 pthread_exit(NULL);
790 }
791
792 /**
793 * Read the next line in http response
794 * Fill buffer until \r\n is read or buffer_len is reached
795 * return U_OK on success
796 */
ulfius_get_next_line_from_http_response(struct _websocket * websocket,char * buffer,size_t buffer_len,size_t * line_len)797 static int ulfius_get_next_line_from_http_response(struct _websocket * websocket, char * buffer, size_t buffer_len, size_t * line_len) {
798 size_t offset = 0;
799 int eol = 0, ret = U_ERROR;
800 uint8_t car;
801
802 *line_len = 0;
803 do {
804 if (read_data_from_socket(websocket->websocket_manager, &car, 1) == 1) {
805 buffer[offset] = car;
806 }
807
808 if (offset > 0 && buffer[offset-1] == '\r' && buffer[offset] == '\n') {
809 eol = 1;
810 buffer[offset-1] = '\0';
811 *line_len = offset - 1;
812 ret = U_OK;
813 }
814
815 offset++;
816 } while (websocket->websocket_manager->connected && !eol && offset < buffer_len);
817
818 if (!websocket->websocket_manager->connected && !eol && offset < buffer_len) {
819 read_data_from_socket(websocket->websocket_manager, (uint8_t *)buffer+offset, (buffer_len-offset-1));
820 buffer[buffer_len-1] = '\0';
821 *line_len = buffer_len;
822 }
823 return ret;
824 }
825
826 /**
827 * Sends the HTTP request and read the HTTP response
828 * Verify if the response has the expexted paramters to open the
829 * websocket
830 * Return U_OK on success
831 */
ulfius_websocket_connection_handshake(struct _u_request * request,struct yuarel * y_url,struct _websocket * websocket,struct _u_response * response)832 static int ulfius_websocket_connection_handshake(struct _u_request * request, struct yuarel * y_url, struct _websocket * websocket, struct _u_response * response) {
833 int websocket_response_http = 0, ret, check_websocket = WEBSOCKET_RESPONSE_UPGRADE | WEBSOCKET_RESPONSE_CONNECTION | WEBSOCKET_RESPONSE_ACCEPT, extension_enabled;
834 unsigned int websocket_response = 0;
835 char * http_line, ** split_line = NULL, * key, * value, * separator, ** extension_list = NULL;
836 char buffer[4096] = {0};
837 const char ** keys;
838 size_t buffer_len = 4096, line_len, extension_len, i, j;
839 struct _websocket_extension * w_extension;
840
841 // Send HTTP Request
842 http_line = msprintf("%s /%s%s%s HTTP/%s\r\n", request->http_verb, o_strlen(y_url->path)?y_url->path:"", y_url->query!=NULL?"?":"", y_url->query!=NULL?y_url->query:"", request->http_protocol);
843 ulfius_websocket_send_frame(websocket->websocket_manager, (uint8_t *)http_line, o_strlen(http_line));
844 o_free(http_line);
845
846 if (y_url->port) {
847 http_line = msprintf("Host: %s:%d\r\n", y_url->host, y_url->port);
848 } else {
849 http_line = msprintf("Host: %s\r\n", y_url->host);
850 }
851 ulfius_websocket_send_frame(websocket->websocket_manager, (uint8_t *)http_line, o_strlen(http_line));
852 o_free(http_line);
853
854 http_line = msprintf("Upgrade: websocket\r\n");
855 ulfius_websocket_send_frame(websocket->websocket_manager, (uint8_t *)http_line, o_strlen(http_line));
856 o_free(http_line);
857
858 http_line = msprintf("Connection: Upgrade\r\n");
859 ulfius_websocket_send_frame(websocket->websocket_manager, (uint8_t *)http_line, o_strlen(http_line));
860 o_free(http_line);
861
862 http_line = msprintf("Origin: %s://%s\r\n", y_url->scheme, y_url->host);
863 ulfius_websocket_send_frame(websocket->websocket_manager, (uint8_t *)http_line, o_strlen(http_line));
864 o_free(http_line);
865
866 keys = u_map_enum_keys(request->map_header);
867 for (i=0; keys[i] != NULL; i++) {
868 http_line = msprintf("%s: %s\r\n", keys[i], u_map_get_case(request->map_header, keys[i]));
869 ulfius_websocket_send_frame(websocket->websocket_manager, (uint8_t *)http_line, o_strlen(http_line));
870 o_free(http_line);
871 if (0 == o_strcmp("Sec-WebSocket-Protocol", keys[i])) {
872 check_websocket |= WEBSOCKET_RESPONSE_PROTCOL;
873 } else if (0 == o_strcmp("Sec-WebSocket-Extension", keys[i])) {
874 check_websocket |= WEBSOCKET_RESPONSE_EXTENSION;
875 }
876 }
877
878 if (websocket->websocket_manager->tcp_sock >= 0) {
879 // Send empty line
880 const char * empty = "\r\n";
881 ulfius_websocket_send_frame(websocket->websocket_manager, (uint8_t *)empty, o_strlen(empty));
882 }
883
884 // Read and parse response
885 if (ulfius_get_next_line_from_http_response(websocket, buffer, buffer_len, &line_len) == U_OK) {
886 if (split_string(buffer, " ", &split_line) >= 2 && 0 == o_strcmp(split_line[0], "HTTP/1.1")) {
887 websocket_response_http = 1;
888 response->status = strtol(split_line[1], NULL, 10);
889 response->protocol = o_strdup("1.1");
890 }
891 free_string_array(split_line);
892 }
893 if (websocket_response_http && response->status == 101) {
894 do {
895 if (ulfius_get_next_line_from_http_response(websocket, buffer, buffer_len, &line_len) == U_OK) {
896 if (o_strlen(buffer) && (separator = o_strchr(buffer, ':')) != NULL) {
897 key = o_strndup(buffer, (separator - buffer));
898 value = o_strdup(separator + 1);
899 if (u_map_put(response->map_header, key, value) != U_OK) {
900 y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error adding header %s:%s to the response structure", key, value);
901 }
902 if (0 == o_strcasecmp(buffer, "Upgrade: websocket")) {
903 websocket_response |= WEBSOCKET_RESPONSE_UPGRADE;
904 } else if (0 == o_strcasecmp(buffer, "Connection: Upgrade")) {
905 websocket_response |= WEBSOCKET_RESPONSE_CONNECTION;
906 } else if (0 == o_strcasecmp(key, "Sec-WebSocket-Protocol")) {
907 websocket->websocket_manager->protocol = o_strdup(value);
908 websocket_response |= WEBSOCKET_RESPONSE_PROTCOL;
909 } else if (0 == o_strcasecmp(key, "Sec-WebSocket-Extensions")) {
910 websocket->websocket_manager->extensions = o_strdup(value);
911 websocket_response |= WEBSOCKET_RESPONSE_EXTENSION;
912 } else if (0 == o_strcasecmp(buffer, "Sec-WebSocket-Accept") && ulfius_check_handshake_response(u_map_get_case(request->map_header, "Sec-WebSocket-Key"), value) == U_OK) {
913 websocket_response |= WEBSOCKET_RESPONSE_ACCEPT;
914 }
915 o_free(key);
916 o_free(value);
917 } else if (0 == o_strcmp(buffer, "")) {
918 // Websocket HTTP response header complete
919 break;
920 }
921 } else {
922 y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error ulfius_get_next_line_from_http_response, abort parsing response");
923 close(websocket->websocket_manager->tcp_sock);
924 websocket->websocket_manager->tcp_sock = -1;
925 break;
926 }
927 } while (1);
928 }
929
930 if (!websocket_response_http || !(websocket_response & check_websocket) || response->status != 101) {
931 if (u_map_has_key(response->map_header, "Content-Length")) {
932 response->binary_body_length = strtol(u_map_get(response->map_header, "Content-Length"), NULL, 10);
933 response->binary_body = o_malloc(response->binary_body_length);
934 if (response->binary_body != NULL) {
935 if (read_data_from_socket(websocket->websocket_manager, response->binary_body, response->binary_body_length) != (ssize_t)response->binary_body_length) {
936 y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error read_data_from_socket for response->binary_body");
937 }
938 } else {
939 y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error allocating resources for response->binary_body");
940 }
941 }
942 close(websocket->websocket_manager->tcp_sock);
943 websocket->websocket_manager->tcp_sock = -1;
944 ret = U_ERROR;
945 } else {
946 ret = U_OK;
947 if (o_strlen(websocket->websocket_manager->extensions)) {
948 extension_len = pointer_list_size(websocket->websocket_manager->websocket_extension_list);
949 if (extension_len) {
950 if (split_string(websocket->websocket_manager->extensions, ",", &extension_list)) {
951 for (i=0; extension_list[i]!=NULL; i++) {
952 extension_enabled = 0;
953 for (j=0; j<extension_len; j++) {
954 w_extension = pointer_list_get_at(websocket->websocket_manager->websocket_extension_list, j);
955 if (w_extension != NULL && !w_extension->enabled) {
956 if (w_extension->websocket_extension_client_match != NULL) {
957 if (w_extension->websocket_extension_client_match(trimwhitespace(extension_list[i]), w_extension->websocket_extension_client_match_user_data, &w_extension->context) == U_OK) {
958 if (!(w_extension->rsv & websocket->websocket_manager->rsv_expected)) {
959 websocket->websocket_manager->rsv_expected |= w_extension->rsv;
960 w_extension->extension_server = o_strdup(extension_list[i]);
961 w_extension->enabled = 1;
962 extension_enabled = 1;
963 }
964 break;
965 }
966 } else {
967 if (0 == o_strcmp(trimwhitespace(extension_list[i]), w_extension->extension_client)) {
968 if (!(w_extension->rsv & websocket->websocket_manager->rsv_expected)) {
969 websocket->websocket_manager->rsv_expected |= w_extension->rsv;
970 w_extension->extension_server = o_strdup(extension_list[i]);
971 w_extension->enabled = 1;
972 extension_enabled = 1;
973 }
974 break;
975 }
976 }
977 } else if (w_extension == NULL) {
978 y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error pointer_list_get_at %zu", j);
979 ret = U_ERROR;
980 }
981 }
982 if (!extension_enabled) {
983 y_log_message(Y_LOG_LEVEL_DEBUG, "Extension '%s' not enabled, aborting", extension_list[i]);
984 ret = U_ERROR;
985 break;
986 }
987 }
988 } else {
989 y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error split_string extensions");
990 ret = U_ERROR;
991 }
992 free_string_array(extension_list);
993 }
994 }
995 }
996
997 return ret;
998 }
999
1000 /**
1001 * Opens a websocket connection to the specified server
1002 * Returns U_OK on success
1003 */
ulfius_open_websocket(struct _u_request * request,struct yuarel * y_url,struct _websocket * websocket,struct _u_response * response)1004 static int ulfius_open_websocket(struct _u_request * request, struct yuarel * y_url, struct _websocket * websocket, struct _u_response * response) {
1005 int ret;
1006 struct sockaddr_in server;
1007 struct hostent * he;
1008
1009 websocket->websocket_manager->tcp_sock = socket(AF_INET, SOCK_STREAM, 0);
1010 if (websocket->websocket_manager->tcp_sock != -1) {
1011 if ((he = gethostbyname(y_url->host)) != NULL) {
1012 memcpy(&server.sin_addr, he->h_addr_list[0], he->h_length);
1013 server.sin_family = AF_INET;
1014 server.sin_port = htons(y_url->port);
1015
1016 if (connect(websocket->websocket_manager->tcp_sock, (struct sockaddr *)&server , sizeof(server)) >= 0) {
1017 websocket->websocket_manager->fds_in.fd = websocket->websocket_manager->tcp_sock;
1018 websocket->websocket_manager->fds_out.fd = websocket->websocket_manager->tcp_sock;
1019 websocket->websocket_manager->connected = 1;
1020 websocket->websocket_manager->close_flag = 0;
1021 websocket->urh = NULL;
1022 websocket->instance = NULL;
1023
1024 ret = ulfius_websocket_connection_handshake(request, y_url, websocket, response);
1025 } else {
1026 y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error connecting socket");
1027 close(websocket->websocket_manager->tcp_sock);
1028 websocket->websocket_manager->tcp_sock = -1;
1029 ret = U_ERROR;
1030 }
1031 } else {
1032 y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error gethostbyname");
1033 ret = U_ERROR;
1034 }
1035 } else {
1036 y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error opening socket");
1037 ret = U_ERROR;
1038 }
1039 return ret;
1040 }
1041
1042 /**
1043 * Opens a websocket connection to the specified server using a tls socket
1044 * Returns U_OK on success
1045 */
ulfius_open_websocket_tls(struct _u_request * request,struct yuarel * y_url,struct _websocket * websocket,struct _u_response * response)1046 static int ulfius_open_websocket_tls(struct _u_request * request, struct yuarel * y_url, struct _websocket * websocket, struct _u_response * response) {
1047 int ret;
1048 struct sockaddr_in server;
1049 struct hostent * he;
1050 gnutls_datum_t out;
1051 int type;
1052 unsigned status;
1053
1054 if (gnutls_global_init() >= 0) {
1055 if (gnutls_certificate_allocate_credentials(&websocket->websocket_manager->xcred) >= 0 &&
1056 gnutls_certificate_set_x509_system_trust(websocket->websocket_manager->xcred) >= 0 &&
1057 gnutls_init(&websocket->websocket_manager->gnutls_session, GNUTLS_CLIENT) >= 0 &&
1058 gnutls_server_name_set(websocket->websocket_manager->gnutls_session, GNUTLS_NAME_DNS, y_url->host, o_strlen(y_url->host)) >= 0 &&
1059 gnutls_set_default_priority(websocket->websocket_manager->gnutls_session) >= 0 &&
1060 gnutls_credentials_set(websocket->websocket_manager->gnutls_session, GNUTLS_CRD_CERTIFICATE, websocket->websocket_manager->xcred) >= 0) {
1061
1062 if (request->check_server_certificate) {
1063 gnutls_session_set_verify_cert(websocket->websocket_manager->gnutls_session, y_url->host, 0);
1064 }
1065 websocket->websocket_manager->tcp_sock = socket(AF_INET, SOCK_STREAM, 0);
1066 if (websocket->websocket_manager->tcp_sock != -1) {
1067 if ((he = gethostbyname(y_url->host)) != NULL) {
1068 memset(&server, '\0', sizeof(server));
1069 memcpy(&server.sin_addr, he->h_addr_list[0], he->h_length);
1070 server.sin_family = AF_INET;
1071 server.sin_port = htons(y_url->port);
1072 if (connect(websocket->websocket_manager->tcp_sock, (struct sockaddr *)&server , sizeof(server)) >= 0) {
1073 websocket->websocket_manager->fds_in.fd = websocket->websocket_manager->tcp_sock;
1074 websocket->websocket_manager->fds_out.fd = websocket->websocket_manager->tcp_sock;
1075 websocket->websocket_manager->connected = 1;
1076 websocket->websocket_manager->close_flag = 0;
1077 websocket->urh = NULL;
1078 websocket->instance = NULL;
1079
1080 gnutls_transport_set_int(websocket->websocket_manager->gnutls_session, websocket->websocket_manager->tcp_sock);
1081 gnutls_handshake_set_timeout(websocket->websocket_manager->gnutls_session, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
1082
1083 do {
1084 ret = gnutls_handshake(websocket->websocket_manager->gnutls_session);
1085 }
1086 while (ret < 0 && gnutls_error_is_fatal(ret) == 0);
1087
1088 if (ret < 0) {
1089 if (ret == GNUTLS_E_CERTIFICATE_VERIFICATION_ERROR) {
1090 /* check certificate verification status */
1091 type = gnutls_certificate_type_get(websocket->websocket_manager->gnutls_session);
1092 status = gnutls_session_get_verify_cert_status(websocket->websocket_manager->gnutls_session);
1093 if (gnutls_certificate_verification_status_print(status, type, &out, 0) >= 0) {
1094 y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Certificate verify output: %s\n", out.data);
1095 gnutls_free(out.data);
1096 } else {
1097 y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error gnutls_certificate_verification_status_print");
1098 }
1099 }
1100 y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Handshake failed: %s\n", gnutls_strerror(ret));
1101 ret = U_ERROR;
1102 } else {
1103 char * desc = gnutls_session_get_desc(websocket->websocket_manager->gnutls_session);
1104 gnutls_free(desc);
1105
1106 ret = ulfius_websocket_connection_handshake(request, y_url, websocket, response);
1107 }
1108 } else {
1109 y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error connecting socket");
1110 close(websocket->websocket_manager->tcp_sock);
1111 websocket->websocket_manager->tcp_sock = -1;
1112 ret = U_ERROR;
1113 }
1114
1115 } else {
1116 y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error gethostbyname");
1117 ret = U_ERROR;
1118 }
1119 } else {
1120 y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error opening socket");
1121 ret = U_ERROR;
1122 }
1123 } else {
1124 y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error initialize gnutls routines");
1125 ret = U_ERROR;
1126 }
1127 } else {
1128 y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error gnutls_global_init");
1129 ret = U_ERROR;
1130 }
1131 return ret;
1132 }
1133
u_zalloc(void * q,unsigned n,unsigned m)1134 static void * u_zalloc(void * q, unsigned n, unsigned m) {
1135 (void)q;
1136 return o_malloc((size_t) n * m);
1137 }
1138
u_zfree(void * q,void * p)1139 static void u_zfree(void *q, void *p) {
1140 (void)q;
1141 o_free(p);
1142 }
1143
1144 /**
1145 * Websocket callback function for MHD
1146 * Starts the websocket manager if set,
1147 */
ulfius_start_websocket_cb(void * cls,struct MHD_Connection * connection,void * con_cls,const char * extra_in,size_t extra_in_size,MHD_socket sock,struct MHD_UpgradeResponseHandle * urh)1148 void ulfius_start_websocket_cb (void * cls,
1149 struct MHD_Connection * connection,
1150 void * con_cls,
1151 const char * extra_in,
1152 size_t extra_in_size,
1153 MHD_socket sock,
1154 struct MHD_UpgradeResponseHandle * urh) {
1155 struct _websocket * websocket = (struct _websocket *)cls;
1156 pthread_t thread_websocket;
1157 int thread_ret_websocket = 0, thread_detach_websocket = 0;
1158 UNUSED(connection);
1159 UNUSED(con_cls);
1160 UNUSED(extra_in);
1161 UNUSED(extra_in_size);
1162
1163 if (websocket != NULL) {
1164 websocket->urh = urh;
1165 // Run websocket manager in a thread
1166 websocket->websocket_manager->type = U_WEBSOCKET_SERVER;
1167 websocket->websocket_manager->mhd_sock = sock;
1168 websocket->websocket_manager->fds_in.fd = sock;
1169 websocket->websocket_manager->fds_in.events = POLLIN | POLLRDHUP;
1170 websocket->websocket_manager->fds_out.fd = sock;
1171 websocket->websocket_manager->fds_out.events = POLLOUT | POLLRDHUP;
1172 websocket->websocket_manager->connected = 1;
1173 websocket->websocket_manager->close_flag = 0;
1174 thread_ret_websocket = pthread_create(&thread_websocket, NULL, ulfius_thread_websocket, (void *)websocket);
1175 thread_detach_websocket = pthread_detach(thread_websocket);
1176 if (thread_ret_websocket || thread_detach_websocket) {
1177 y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error creating or detaching websocket manager thread, return code: %d, detach code: %d",
1178 thread_ret_websocket, thread_detach_websocket);
1179 if (websocket->websocket_onclose_callback != NULL) {
1180 websocket->websocket_onclose_callback(websocket->request, websocket->websocket_manager, websocket->websocket_onclose_user_data);
1181 }
1182 ulfius_clear_websocket(websocket);
1183 }
1184 } else {
1185 y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error websocket is NULL");
1186 ulfius_clear_websocket(websocket);
1187 }
1188 return;
1189 }
1190
1191 /**
1192 * Check if the response corresponds to the transformation of the key with the magic string
1193 */
ulfius_check_handshake_response(const char * key,const char * response)1194 int ulfius_check_handshake_response(const char * key, const char * response) {
1195 char websocket_accept[32] = {0};
1196
1197 if (key != NULL && response != NULL) {
1198 if (ulfius_generate_handshake_answer(key, websocket_accept) && 0 == o_strcmp(websocket_accept, response)) {
1199 return U_OK;
1200 } else {
1201 return U_ERROR;
1202 }
1203 } else {
1204 return U_ERROR_PARAMS;
1205 }
1206 }
1207
1208 /**
1209 * Generates a handhshake answer from the key given in parameter
1210 */
ulfius_generate_handshake_answer(const char * key,char * out_digest)1211 int ulfius_generate_handshake_answer(const char * key, char * out_digest) {
1212 gnutls_datum_t key_data;
1213 unsigned char encoded_key[32] = {0};
1214 size_t encoded_key_size = 32, encoded_key_size_base64;
1215 int res, to_return = 0;
1216
1217 key_data.data = (unsigned char*)msprintf("%s%s", key, U_WEBSOCKET_MAGIC_STRING);
1218 key_data.size = o_strlen((const char *)key_data.data);
1219
1220 if (key_data.data != NULL && out_digest != NULL && (res = gnutls_fingerprint(GNUTLS_DIG_SHA1, &key_data, encoded_key, &encoded_key_size)) == GNUTLS_E_SUCCESS) {
1221 if (o_base64_encode(encoded_key, encoded_key_size, (unsigned char *)out_digest, &encoded_key_size_base64)) {
1222 to_return = 1;
1223 } else {
1224 y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error base64 encoding hashed key");
1225 }
1226 } else {
1227 y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error getting sha1 signature for key");
1228 }
1229 o_free(key_data.data);
1230 return to_return;
1231 }
1232
1233 /**
1234 * Initialize a websocket message list
1235 * Return U_OK on success
1236 */
ulfius_init_websocket_message_list(struct _websocket_message_list * message_list)1237 int ulfius_init_websocket_message_list(struct _websocket_message_list * message_list) {
1238 if (message_list != NULL) {
1239 message_list->len = 0;
1240 message_list->list = NULL;
1241 return U_OK;
1242 } else {
1243 return U_ERROR_PARAMS;
1244 }
1245 }
1246
1247 /**
1248 * Append a message in a message list
1249 * Return U_OK on success
1250 */
ulfius_push_websocket_message(struct _websocket_message_list * message_list,struct _websocket_message * message)1251 int ulfius_push_websocket_message(struct _websocket_message_list * message_list, struct _websocket_message * message) {
1252 if (message_list != NULL && message != NULL) {
1253 message_list->list = o_realloc(message_list->list, (message_list->len+1)*sizeof(struct _websocket_message *));
1254 if (message_list->list != NULL) {
1255 message_list->list[message_list->len] = message;
1256 message_list->len++;
1257 return U_OK;
1258 } else {
1259 return U_ERROR_MEMORY;
1260 }
1261 } else {
1262 return U_ERROR_PARAMS;
1263 }
1264 }
1265
1266 /**
1267 * Return a match list between two list of items
1268 * If match is NULL, then result will be NULL and returned value will be U_OK
1269 * *result value must be u_free'd after use
1270 */
ulfius_check_list_match(const char * source,const char * match,const char * separator,char ** result)1271 int ulfius_check_list_match(const char * source, const char * match, const char * separator, char ** result) {
1272 char ** source_list = NULL, ** match_list = NULL;
1273 int i, ret = U_OK;
1274
1275 if (result != NULL) {
1276 *result = NULL;
1277 if (match != NULL && source != NULL) {
1278 if (split_string(source, separator, &source_list) > 0 && split_string(match, separator, &match_list) > 0) {
1279 for (i=0; source_list[i] != NULL; i++) {
1280 if (string_array_has_trimmed_value((const char **)match_list, source_list[i])) {
1281 if (*result == NULL) {
1282 *result = o_strdup(trimwhitespace(source_list[i]));
1283 } else {
1284 char * tmp = msprintf("%s%s%s", *result, separator, trimwhitespace(source_list[i]));
1285 o_free(*result);
1286 *result = tmp;
1287 }
1288 }
1289 }
1290 free_string_array(source_list);
1291 free_string_array(match_list);
1292 }
1293 if (*result == NULL) {
1294 ret = U_ERROR;
1295 }
1296 }
1297 } else {
1298 ret = U_ERROR_PARAMS;
1299 }
1300 return ret;
1301 }
1302
1303 /**
1304 * Return the first match between two list of items
1305 * If match is NULL, then return the first element of source
1306 * Returned value must be u_free'd after use
1307 */
ulfius_check_first_match(const char * source,const char * match,const char * separator,char ** result)1308 int ulfius_check_first_match(const char * source, const char * match, const char * separator, char ** result) {
1309 char ** source_list = NULL, ** match_list = NULL;
1310 int i, ret = U_OK;
1311
1312 if (result != NULL) {
1313 *result = NULL;
1314 if (match == NULL) {
1315 if (source != NULL) {
1316 if (split_string(source, separator, &source_list) > 0) {
1317 *result = o_strdup(trimwhitespace(source_list[0]));
1318 }
1319 free_string_array(source_list);
1320 }
1321 } else {
1322 if (source != NULL) {
1323 if (split_string(source, separator, &source_list) > 0 && split_string(match, separator, &match_list) > 0) {
1324 for (i=0; source_list[i] != NULL && *result == NULL; i++) {
1325 if (string_array_has_trimmed_value((const char **)match_list, source_list[i])) {
1326 if (*result == NULL) {
1327 *result = o_strdup(trimwhitespace(source_list[i]));
1328 }
1329 }
1330 }
1331 free_string_array(source_list);
1332 free_string_array(match_list);
1333 }
1334 }
1335 if (*result == NULL) {
1336 ret = U_ERROR;
1337 }
1338 }
1339 } else {
1340 ret = U_ERROR_PARAMS;
1341 }
1342 return ret;
1343 }
1344
1345 /**
1346 * Close the websocket
1347 */
ulfius_close_websocket(struct _websocket * websocket)1348 int ulfius_close_websocket(struct _websocket * websocket) {
1349 if (websocket != NULL && websocket->websocket_manager != NULL) {
1350 if (websocket->websocket_manager->type == U_WEBSOCKET_CLIENT && websocket->websocket_manager->tls) {
1351 gnutls_bye(websocket->websocket_manager->gnutls_session, GNUTLS_SHUT_RDWR);
1352 gnutls_deinit(websocket->websocket_manager->gnutls_session);
1353 gnutls_certificate_free_credentials(websocket->websocket_manager->xcred);
1354 gnutls_global_deinit();
1355 }
1356 if (websocket->websocket_manager->type == U_WEBSOCKET_CLIENT) {
1357 shutdown(websocket->websocket_manager->tcp_sock, SHUT_RDWR);
1358 close(websocket->websocket_manager->tcp_sock);
1359 }
1360 websocket->websocket_manager->connected = 0;
1361 return U_OK;
1362 } else {
1363 return U_ERROR_PARAMS;
1364 }
1365 }
1366
1367 /**
1368 * Add a websocket in the list of active websockets of the instance
1369 */
ulfius_instance_add_websocket_active(struct _u_instance * instance,struct _websocket * websocket)1370 int ulfius_instance_add_websocket_active(struct _u_instance * instance, struct _websocket * websocket) {
1371 if (instance != NULL && websocket != NULL) {
1372 ((struct _websocket_handler *)instance->websocket_handler)->websocket_active = o_realloc(((struct _websocket_handler *)instance->websocket_handler)->websocket_active, (((struct _websocket_handler *)instance->websocket_handler)->nb_websocket_active+1)*sizeof(struct _websocket *));
1373 if (((struct _websocket_handler *)instance->websocket_handler)->websocket_active != NULL) {
1374 if (pthread_mutex_lock(&((struct _websocket_handler *)instance->websocket_handler)->websocket_active_lock)) {
1375 y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error locking websocket_active_lock");
1376 return U_ERROR;
1377 } else {
1378 ((struct _websocket_handler *)instance->websocket_handler)->websocket_active[((struct _websocket_handler *)instance->websocket_handler)->nb_websocket_active] = websocket;
1379 ((struct _websocket_handler *)instance->websocket_handler)->nb_websocket_active++;
1380 pthread_mutex_unlock(&((struct _websocket_handler *)instance->websocket_handler)->websocket_active_lock);
1381 return U_OK;
1382 }
1383 } else {
1384 y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error allocating resources for instance->websocket_handler->websocket_active");
1385 return U_ERROR_MEMORY;
1386 }
1387 } else {
1388 return U_ERROR_PARAMS;
1389 }
1390 }
1391
1392 /**
1393 * Remove a websocket from the list of active websockets of the instance
1394 */
ulfius_instance_remove_websocket_active(struct _u_instance * instance,struct _websocket * websocket)1395 int ulfius_instance_remove_websocket_active(struct _u_instance * instance, struct _websocket * websocket) {
1396 size_t i, j;
1397 int ret;
1398 if (instance != NULL && instance->websocket_handler != NULL && ((struct _websocket_handler *)instance->websocket_handler)->websocket_active != NULL && websocket != NULL) {
1399 if (pthread_mutex_lock(&((struct _websocket_handler *)instance->websocket_handler)->websocket_active_lock)) {
1400 y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error locking websocket_active_lock");
1401 ret = U_ERROR;
1402 } else {
1403 ret = U_ERROR_NOT_FOUND;
1404 for (i=0; i<((struct _websocket_handler *)instance->websocket_handler)->nb_websocket_active && ret == U_ERROR_NOT_FOUND; i++) {
1405 if (((struct _websocket_handler *)instance->websocket_handler)->websocket_active[i] == websocket) {
1406 if (((struct _websocket_handler *)instance->websocket_handler)->nb_websocket_active > 1) {
1407 for (j=i; j<((struct _websocket_handler *)instance->websocket_handler)->nb_websocket_active-1; j++) {
1408 ((struct _websocket_handler *)instance->websocket_handler)->websocket_active[j] = ((struct _websocket_handler *)instance->websocket_handler)->websocket_active[j+1];
1409 }
1410 ((struct _websocket_handler *)instance->websocket_handler)->websocket_active = o_realloc(((struct _websocket_handler *)instance->websocket_handler)->websocket_active, (((struct _websocket_handler *)instance->websocket_handler)->nb_websocket_active-1)*sizeof(struct _websocket *));
1411 if (((struct _websocket_handler *)instance->websocket_handler)->websocket_active == NULL) {
1412 y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error allocating resources for instance->websocket_active");
1413 ret = U_ERROR_MEMORY;
1414 }
1415 } else {
1416 o_free(((struct _websocket_handler *)instance->websocket_handler)->websocket_active);
1417 ((struct _websocket_handler *)instance->websocket_handler)->websocket_active = NULL;
1418 }
1419 ((struct _websocket_handler *)instance->websocket_handler)->nb_websocket_active--;
1420 pthread_mutex_lock(&((struct _websocket_handler *)instance->websocket_handler)->websocket_close_lock);
1421 pthread_cond_broadcast(&((struct _websocket_handler *)instance->websocket_handler)->websocket_close_cond);
1422 pthread_mutex_unlock(&((struct _websocket_handler *)instance->websocket_handler)->websocket_close_lock);
1423 ret = U_OK;
1424 }
1425 }
1426 pthread_mutex_unlock(&((struct _websocket_handler *)instance->websocket_handler)->websocket_active_lock);
1427 }
1428 } else {
1429 ret = U_ERROR_PARAMS;
1430 }
1431 return ret;
1432 }
1433
1434 /********************************/
1435 /** Common websocket functions **/
1436 /********************************/
1437
1438 /**
1439 * Send a fragmented message in the websocket
1440 * each fragment size will be at most fragment_len
1441 * Return U_OK on success
1442 */
ulfius_websocket_send_fragmented_message(struct _websocket_manager * websocket_manager,const uint8_t opcode,const uint64_t data_len,const char * data,const uint64_t fragment_len)1443 int ulfius_websocket_send_fragmented_message(struct _websocket_manager * websocket_manager,
1444 const uint8_t opcode,
1445 const uint64_t data_len,
1446 const char * data,
1447 const uint64_t fragment_len) {
1448 int ret = U_OK, ret_message, count = WEBSOCKET_MAX_CLOSE_TRY;
1449 struct _websocket_message * message;
1450 uint8_t rsv = 0;
1451 size_t i, len;
1452 uint64_t data_out_len = 0, data_in_len = 0;
1453 char * data_out = NULL, * data_in = NULL;
1454 struct _websocket_extension * extension;
1455
1456 if (websocket_manager != NULL && websocket_manager->connected) {
1457 if (opcode == U_WEBSOCKET_OPCODE_CLOSE) {
1458 if (ulfius_send_websocket_message_managed(websocket_manager, U_WEBSOCKET_OPCODE_CLOSE, 0, 0, NULL, 0) == U_OK) {
1459 // If message sent is U_WEBSOCKET_OPCODE_CLOSE, wait for the close response for WEBSOCKET_MAX_CLOSE_TRY messages max, then close the connection
1460 do {
1461 if (is_websocket_data_available(websocket_manager)) {
1462 message = NULL;
1463 ret_message = ulfius_read_incoming_message(websocket_manager, &message);
1464 if (ret_message == U_OK && message != NULL) {
1465 if (message->opcode == U_WEBSOCKET_OPCODE_CLOSE) {
1466 websocket_manager->connected = 0;
1467 }
1468 if ((websocket_manager->keep_messages&U_WEBSOCKET_KEEP_INCOMING) && ulfius_push_websocket_message(websocket_manager->message_list_incoming, message) != U_OK) {
1469 y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error pushing new websocket message in list");
1470 }
1471 } else {
1472 websocket_manager->connected = 0;
1473 }
1474 if (!(websocket_manager->keep_messages&U_WEBSOCKET_KEEP_INCOMING)) {
1475 ulfius_clear_websocket_message(message);
1476 message = NULL;
1477 }
1478 }
1479 } while (websocket_manager->connected && (count-- > 0));
1480 } else {
1481 y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error sending U_WEBSOCKET_OPCODE_CLOSE message");
1482 }
1483 websocket_manager->connected = 0;
1484 } else if (opcode == U_WEBSOCKET_OPCODE_PING && websocket_manager->ping_sent) {
1485 // Ignore sending a second ping before the pong has arrived
1486 ret = U_OK;
1487 } else {
1488 ret = U_OK;
1489 if ((data_len && (data_in = o_malloc(data_len*sizeof(char))) != NULL) || !data_len) {
1490 if (data != NULL) {
1491 memcpy(data_in, data, data_len);
1492 } else {
1493 memset(data_in, 0, data_len);
1494 }
1495 data_in_len = data_len;
1496 if ((len = pointer_list_size(websocket_manager->websocket_extension_list)) && (opcode == U_WEBSOCKET_OPCODE_BINARY || opcode == U_WEBSOCKET_OPCODE_TEXT)) {
1497 for (i=0; ret == U_OK && i<len && (extension = (struct _websocket_extension *)pointer_list_get_at(websocket_manager->websocket_extension_list, i)) != NULL; i++) {
1498 if (extension->enabled && extension->websocket_extension_message_out_perform != NULL) {
1499 if ((ret = extension->websocket_extension_message_out_perform(opcode, data_in_len, data_in, &data_out_len, &data_out, fragment_len, extension->websocket_extension_message_out_perform_user_data, extension->context)) != U_OK) {
1500 y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error performing websocket_extension_message_out_perform at index %zu", i);
1501 } else {
1502 rsv |= extension->rsv;
1503 o_free(data_in);
1504 if ((data_in = o_malloc(data_out_len*sizeof(char))) != NULL) {
1505 memcpy(data_in, data_out, data_out_len);
1506 data_in_len = data_out_len;
1507 } else {
1508 y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error allocating resources for data_in (%zu) (outcoming)", i);
1509 ret = U_ERROR_MEMORY;
1510 }
1511 o_free(data_out);
1512 data_out = NULL;
1513 data_out_len = 0;
1514 }
1515 }
1516 }
1517 }
1518 if (ret == U_OK) {
1519 ret = ulfius_send_websocket_message_managed(websocket_manager, opcode, rsv, data_in_len, data_in, fragment_len);
1520 }
1521 } else {
1522 y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error allocating resources for data_in (outcoming)");
1523 ret = U_ERROR_MEMORY;
1524 }
1525 o_free(data_in);
1526 }
1527 } else {
1528 ret = U_ERROR_PARAMS;
1529 }
1530 return ret;
1531 }
1532
1533 /**
1534 * Send a message in the websocket
1535 * Return U_OK on success
1536 */
ulfius_websocket_send_message(struct _websocket_manager * websocket_manager,const uint8_t opcode,const uint64_t data_len,const char * data)1537 int ulfius_websocket_send_message(struct _websocket_manager * websocket_manager,
1538 const uint8_t opcode,
1539 const uint64_t data_len,
1540 const char * data) {
1541 return ulfius_websocket_send_fragmented_message(websocket_manager, opcode, data_len, data, 0);
1542 }
1543
1544 /**
1545 * Send a JSON message in the websocket
1546 * Return U_OK on success
1547 */
1548 #ifndef U_DISABLE_JANSSON
ulfius_websocket_send_json_message(struct _websocket_manager * websocket_manager,json_t * message)1549 int ulfius_websocket_send_json_message(struct _websocket_manager * websocket_manager,
1550 json_t *message) {
1551 char * json = json_dumps(message, JSON_COMPACT);
1552 int ret = ulfius_websocket_send_message(websocket_manager, U_WEBSOCKET_OPCODE_TEXT, strlen(json), json);
1553 o_free(json);
1554 return ret;
1555 }
1556 #endif
1557
1558 /**
1559 * Return the first message of the message list
1560 * Return NULL if message_list has no message
1561 * Returned value must be cleared after use
1562 */
ulfius_websocket_pop_first_message(struct _websocket_message_list * message_list)1563 struct _websocket_message * ulfius_websocket_pop_first_message(struct _websocket_message_list * message_list) {
1564 size_t len;
1565 struct _websocket_message * message = NULL;
1566 if (message_list != NULL && message_list->len > 0) {
1567 message = message_list->list[0];
1568 for (len=0; len < message_list->len-1; len++) {
1569 message_list->list[len] = message_list->list[len+1];
1570 }
1571 if (message_list->len > 1) {
1572 message_list->list = o_realloc(message_list->list, (message_list->len-1));
1573 } else {
1574 o_free(message_list->list);
1575 message_list->list = NULL;
1576 }
1577 message_list->len--;
1578 }
1579 return message;
1580 }
1581
1582 /**
1583 * Clear data of a websocket message
1584 */
ulfius_clear_websocket_message(struct _websocket_message * message)1585 void ulfius_clear_websocket_message(struct _websocket_message * message) {
1586 if (message != NULL) {
1587 o_free(message->data);
1588 message->data = NULL;
1589 o_free(message);
1590 }
1591 }
1592
1593 /************************************/
1594 /** Init/clear websocket functions **/
1595 /************************************/
1596
1597 /**
1598 * Clear all data related to the websocket
1599 */
ulfius_clear_websocket(struct _websocket * websocket)1600 int ulfius_clear_websocket(struct _websocket * websocket) {
1601 if (websocket != NULL) {
1602 if (websocket->websocket_manager != NULL &&
1603 websocket->urh != NULL &&
1604 websocket->websocket_manager->type == U_WEBSOCKET_SERVER &&
1605 MHD_upgrade_action (websocket->urh, MHD_UPGRADE_ACTION_CLOSE) != MHD_YES) {
1606 y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error sending MHD_UPGRADE_ACTION_CLOSE frame to urh");
1607 }
1608 if (websocket->instance != NULL) {
1609 ulfius_instance_remove_websocket_active(websocket->instance, websocket);
1610 }
1611 ulfius_clean_request_full(websocket->request);
1612 websocket->request = NULL;
1613 ulfius_clear_websocket_manager(websocket->websocket_manager);
1614 o_free(websocket->websocket_manager);
1615 websocket->websocket_manager = NULL;
1616 o_free(websocket);
1617 return U_OK;
1618 } else {
1619 return U_ERROR_PARAMS;
1620 }
1621 }
1622
1623 /**
1624 * Clear data of a websocket message list
1625 */
ulfius_clear_websocket_message_list(struct _websocket_message_list * message_list)1626 void ulfius_clear_websocket_message_list(struct _websocket_message_list * message_list) {
1627 size_t i;
1628 if (message_list != NULL) {
1629 for (i=0; i < message_list->len; i++) {
1630 ulfius_clear_websocket_message(message_list->list[i]);
1631 message_list->list[i] = NULL;
1632 }
1633 o_free(message_list->list);
1634 message_list->list = NULL;
1635 }
1636 }
1637
1638 /**
1639 * Initialize a struct _websocket
1640 * return U_OK on success
1641 */
ulfius_init_websocket(struct _websocket * websocket)1642 int ulfius_init_websocket(struct _websocket * websocket) {
1643 if (websocket != NULL) {
1644 websocket->instance = NULL;
1645 websocket->request = NULL;
1646 websocket->websocket_manager_callback = NULL;
1647 websocket->websocket_manager_user_data = NULL;
1648 websocket->websocket_incoming_message_callback = NULL;
1649 websocket->websocket_incoming_user_data = NULL;
1650 websocket->websocket_onclose_callback = NULL;
1651 websocket->websocket_onclose_user_data = NULL;
1652 websocket->websocket_manager = o_malloc(sizeof(struct _websocket_manager));
1653 websocket->urh = NULL;
1654 if (websocket->websocket_manager == NULL) {
1655 y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error allocating resources for websocket_manager");
1656 return U_ERROR_MEMORY;
1657 } else {
1658 websocket->websocket_manager->tls = 0;
1659 if (ulfius_init_websocket_manager(websocket->websocket_manager) != U_OK) {
1660 o_free(websocket->websocket_manager);
1661 y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error ulfius_init_websocket_manager");
1662 return U_ERROR;
1663 } else {
1664 return U_OK;
1665 }
1666 }
1667 } else {
1668 return U_ERROR_PARAMS;
1669 }
1670 }
1671
1672 /**
1673 * Initialize a struct _websocket_manager
1674 * return U_OK on success
1675 */
ulfius_init_websocket_manager(struct _websocket_manager * websocket_manager)1676 int ulfius_init_websocket_manager(struct _websocket_manager * websocket_manager) {
1677 pthread_mutexattr_t mutexattr;
1678 int ret = U_OK;
1679
1680 if (websocket_manager != NULL) {
1681 websocket_manager->connected = 0;
1682 websocket_manager->close_flag = 0;
1683 websocket_manager->ping_sent = 0;
1684 websocket_manager->mhd_sock = 0;
1685 websocket_manager->tcp_sock = 0;
1686 websocket_manager->protocol = NULL;
1687 websocket_manager->extensions = NULL;
1688 websocket_manager->rsv_expected = 0;
1689 websocket_manager->keep_messages = U_WEBSOCKET_KEEP_INCOMING|U_WEBSOCKET_KEEP_OUTCOMING;
1690 pthread_mutexattr_init ( &mutexattr );
1691 pthread_mutexattr_settype( &mutexattr, PTHREAD_MUTEX_RECURSIVE );
1692 if (pthread_mutex_init(&(websocket_manager->read_lock), &mutexattr) != 0 || pthread_mutex_init(&(websocket_manager->write_lock), &mutexattr) != 0) {
1693 y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Impossible to initialize Mutex Lock for websocket");
1694 ret = U_ERROR;
1695 } else if (pthread_mutex_init(&websocket_manager->status_lock, NULL) || pthread_cond_init(&websocket_manager->status_cond, NULL)) {
1696 y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error initializing status_lock or status_cond");
1697 ret = U_ERROR;
1698 } else if ((websocket_manager->message_list_incoming = o_malloc(sizeof(struct _websocket_message_list))) == NULL ||
1699 ulfius_init_websocket_message_list(websocket_manager->message_list_incoming) != U_OK ||
1700 (websocket_manager->message_list_outcoming = o_malloc(sizeof(struct _websocket_message_list))) == NULL ||
1701 ulfius_init_websocket_message_list(websocket_manager->message_list_outcoming) != U_OK) {
1702 y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error initializing message_list_incoming or message_list_outcoming");
1703 ret = U_ERROR_MEMORY;
1704 }
1705 websocket_manager->fds_in.events = POLLIN | POLLRDHUP;
1706 websocket_manager->fds_out.events = POLLOUT | POLLRDHUP;
1707 websocket_manager->type = U_WEBSOCKET_NONE;
1708
1709 if (ret != U_OK) {
1710 o_free(websocket_manager->message_list_incoming);
1711 o_free(websocket_manager->message_list_outcoming);
1712 }
1713 websocket_manager->websocket_extension_list = NULL;
1714 pthread_mutexattr_destroy(&mutexattr);
1715 } else {
1716 ret = U_ERROR_PARAMS;
1717 }
1718 return ret;
1719 }
1720
1721 /**
1722 * Clear data of a websocket_manager
1723 */
ulfius_clear_websocket_manager(struct _websocket_manager * websocket_manager)1724 void ulfius_clear_websocket_manager(struct _websocket_manager * websocket_manager) {
1725 size_t len, i;
1726 struct _websocket_extension * extension;
1727
1728 if (websocket_manager != NULL) {
1729 pthread_mutex_destroy(&websocket_manager->read_lock);
1730 pthread_mutex_destroy(&websocket_manager->write_lock);
1731 ulfius_clear_websocket_message_list(websocket_manager->message_list_incoming);
1732 o_free(websocket_manager->message_list_incoming);
1733 websocket_manager->message_list_incoming = NULL;
1734 ulfius_clear_websocket_message_list(websocket_manager->message_list_outcoming);
1735 o_free(websocket_manager->message_list_outcoming);
1736 websocket_manager->message_list_outcoming = NULL;
1737 o_free(websocket_manager->protocol);
1738 o_free(websocket_manager->extensions);
1739 if ((len = pointer_list_size(websocket_manager->websocket_extension_list))) {
1740 for (i=0; i<len; i++) {
1741 extension = pointer_list_get_at(websocket_manager->websocket_extension_list, i);
1742 if (extension != NULL && extension->enabled && extension->websocket_extension_free_context != NULL) {
1743 extension->websocket_extension_free_context(extension->websocket_extension_free_context_user_data, extension->context);
1744 }
1745 }
1746 }
1747 pointer_list_clean_free(websocket_manager->websocket_extension_list, &ulfius_free_websocket_extension_pointer_list);
1748 o_free(websocket_manager->websocket_extension_list);
1749 }
1750 }
1751
1752 /********************************/
1753 /** Server websocket functions **/
1754 /********************************/
1755
ulfius_set_websocket_response(struct _u_response * response,const char * websocket_protocol,const char * websocket_extensions,void (* websocket_manager_callback)(const struct _u_request * request,struct _websocket_manager * websocket_manager,void * websocket_manager_user_data),void * websocket_manager_user_data,void (* websocket_incoming_message_callback)(const struct _u_request * request,struct _websocket_manager * websocket_manager,const struct _websocket_message * message,void * websocket_incoming_user_data),void * websocket_incoming_user_data,void (* websocket_onclose_callback)(const struct _u_request * request,struct _websocket_manager * websocket_manager,void * websocket_onclose_user_data),void * websocket_onclose_user_data)1756 int ulfius_set_websocket_response(struct _u_response * response,
1757 const char * websocket_protocol,
1758 const char * websocket_extensions,
1759 void (* websocket_manager_callback) (const struct _u_request * request,
1760 struct _websocket_manager * websocket_manager,
1761 void * websocket_manager_user_data),
1762 void * websocket_manager_user_data,
1763 void (* websocket_incoming_message_callback) (const struct _u_request * request,
1764 struct _websocket_manager * websocket_manager,
1765 const struct _websocket_message * message,
1766 void * websocket_incoming_user_data),
1767 void * websocket_incoming_user_data,
1768 void (* websocket_onclose_callback) (const struct _u_request * request,
1769 struct _websocket_manager * websocket_manager,
1770 void * websocket_onclose_user_data),
1771 void * websocket_onclose_user_data) {
1772 if (response != NULL && (websocket_manager_callback != NULL || websocket_incoming_message_callback)) {
1773 if (((struct _websocket_handle *)response->websocket_handle)->websocket_protocol != NULL) {
1774 o_free(((struct _websocket_handle *)response->websocket_handle)->websocket_protocol);
1775 }
1776 ((struct _websocket_handle *)response->websocket_handle)->websocket_protocol = o_strdup(websocket_protocol);
1777 if (((struct _websocket_handle *)response->websocket_handle)->websocket_protocol == NULL && websocket_protocol != NULL) {
1778 y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error allocating resources for response->websocket_protocol");
1779 return U_ERROR_MEMORY;
1780 }
1781 if (((struct _websocket_handle *)response->websocket_handle)->websocket_extensions != NULL) {
1782 o_free(((struct _websocket_handle *)response->websocket_handle)->websocket_extensions);
1783 }
1784 ((struct _websocket_handle *)response->websocket_handle)->websocket_extensions = o_strdup(websocket_extensions);
1785 if (((struct _websocket_handle *)response->websocket_handle)->websocket_extensions == NULL && websocket_extensions != NULL) {
1786 y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error allocating resources for response->websocket_extensions");
1787 o_free(((struct _websocket_handle *)response->websocket_handle)->websocket_protocol);
1788 return U_ERROR_MEMORY;
1789 }
1790 ((struct _websocket_handle *)response->websocket_handle)->websocket_manager_callback = websocket_manager_callback;
1791 ((struct _websocket_handle *)response->websocket_handle)->websocket_manager_user_data = websocket_manager_user_data;
1792 ((struct _websocket_handle *)response->websocket_handle)->websocket_incoming_message_callback = websocket_incoming_message_callback;
1793 ((struct _websocket_handle *)response->websocket_handle)->websocket_incoming_user_data = websocket_incoming_user_data;
1794 ((struct _websocket_handle *)response->websocket_handle)->websocket_onclose_callback = websocket_onclose_callback;
1795 ((struct _websocket_handle *)response->websocket_handle)->websocket_onclose_user_data = websocket_onclose_user_data;
1796 ((struct _websocket_handle *)response->websocket_handle)->rsv_expected = 0;
1797 return U_OK;
1798 } else {
1799 return U_ERROR_PARAMS;
1800 }
1801 }
1802
ulfius_add_websocket_extension_message_perform(struct _u_response * response,const char * extension_server,uint8_t rsv,int (* websocket_extension_message_out_perform)(const uint8_t opcode,const uint64_t data_len_in,const char * data_in,uint64_t * data_len_out,char ** data_out,const uint64_t fragment_len,void * user_data,void * context),void * websocket_extension_message_out_perform_user_data,int (* websocket_extension_message_in_perform)(const uint8_t opcode,const uint64_t data_len_in,const char * data_in,uint64_t * data_len_out,char ** data_out,const uint64_t fragment_len,void * user_data,void * context),void * websocket_extension_message_in_perform_user_data,int (* websocket_extension_server_match)(const char * extension_client,const char ** extension_client_list,char ** extension_server,void * user_data,void ** context),void * websocket_extension_server_match_user_data,void (* websocket_extension_free_context)(void * user_data,void * context),void * websocket_extension_free_context_user_data)1803 int ulfius_add_websocket_extension_message_perform(struct _u_response * response,
1804 const char * extension_server,
1805 uint8_t rsv,
1806 int (* websocket_extension_message_out_perform)(const uint8_t opcode,
1807 const uint64_t data_len_in,
1808 const char * data_in,
1809 uint64_t * data_len_out,
1810 char ** data_out,
1811 const uint64_t fragment_len,
1812 void * user_data,
1813 void * context),
1814 void * websocket_extension_message_out_perform_user_data,
1815 int (* websocket_extension_message_in_perform)(const uint8_t opcode,
1816 const uint64_t data_len_in,
1817 const char * data_in,
1818 uint64_t * data_len_out,
1819 char ** data_out,
1820 const uint64_t fragment_len,
1821 void * user_data,
1822 void * context),
1823 void * websocket_extension_message_in_perform_user_data,
1824 int (* websocket_extension_server_match)(const char * extension_client,
1825 const char ** extension_client_list,
1826 char ** extension_server,
1827 void * user_data,
1828 void ** context),
1829 void * websocket_extension_server_match_user_data,
1830 void (* websocket_extension_free_context)(void * user_data,
1831 void * context),
1832 void * websocket_extension_free_context_user_data) {
1833 int ret;
1834 struct _websocket_extension * extension;
1835
1836 if (response != NULL && o_strlen(extension_server) &&
1837 (websocket_extension_message_out_perform != NULL || websocket_extension_message_in_perform != NULL) &&
1838 (rsv == U_WEBSOCKET_RSV1 || rsv == U_WEBSOCKET_RSV2 || rsv == U_WEBSOCKET_RSV3)) {
1839 if ((extension = o_malloc(sizeof(struct _websocket_extension))) != NULL) {
1840 if (ulfius_init_websocket_extension(extension) == U_OK) {
1841 extension->extension_server = o_strdup(extension_server);
1842 extension->rsv = rsv;
1843 extension->websocket_extension_message_out_perform = websocket_extension_message_out_perform;
1844 extension->websocket_extension_message_out_perform_user_data = websocket_extension_message_out_perform_user_data;
1845 extension->websocket_extension_message_in_perform = websocket_extension_message_in_perform;
1846 extension->websocket_extension_message_in_perform_user_data = websocket_extension_message_in_perform_user_data;
1847 extension->websocket_extension_server_match = websocket_extension_server_match;
1848 extension->websocket_extension_server_match_user_data = websocket_extension_server_match_user_data;
1849 extension->websocket_extension_free_context = websocket_extension_free_context;
1850 extension->websocket_extension_free_context_user_data = websocket_extension_free_context_user_data;
1851 extension->context = NULL;
1852 if (pointer_list_append(((struct _websocket_handle *)response->websocket_handle)->websocket_extension_list, extension)) {
1853 ret = U_OK;
1854 } else {
1855 y_log_message(Y_LOG_LEVEL_ERROR, "ulfius_add_websocket_extension_message_perform - Error pointer_list_append");
1856 ret = U_ERROR;
1857 }
1858 } else {
1859 y_log_message(Y_LOG_LEVEL_ERROR, "ulfius_add_websocket_extension_message_perform - Error ulfius_init_websocket_extension");
1860 ret = U_ERROR;
1861 }
1862 } else {
1863 y_log_message(Y_LOG_LEVEL_ERROR, "ulfius_add_websocket_extension_message_perform - Error allocating resources for struct _websocket_extension");
1864 ret = U_ERROR_MEMORY;
1865 }
1866 } else {
1867 ret = U_ERROR_PARAMS;
1868 }
1869 return ret;
1870 }
1871
websocket_extension_message_out_deflate(const uint8_t opcode,const uint64_t data_len_in,const char * data_in,uint64_t * data_len_out,char ** data_out,const uint64_t fragment_len,void * user_data,void * context)1872 int websocket_extension_message_out_deflate(const uint8_t opcode,
1873 const uint64_t data_len_in,
1874 const char * data_in,
1875 uint64_t * data_len_out,
1876 char ** data_out,
1877 const uint64_t fragment_len,
1878 void * user_data,
1879 void * context) {
1880 struct _websocket_deflate_context * deflate_context = (struct _websocket_deflate_context *)context;
1881 int ret;
1882 (void)opcode;
1883 (void)fragment_len;
1884 (void)user_data;
1885
1886 if (data_len_in) {
1887 if (deflate_context != NULL) {
1888 *data_out = NULL;
1889 *data_len_out = 0;
1890
1891 deflate_context->defstream.avail_in = (uInt)data_len_in;
1892 deflate_context->defstream.next_in = (Bytef *)data_in;
1893
1894 ret = U_OK;
1895 do {
1896 if ((*data_out = o_realloc(*data_out, (*data_len_out)+_U_W_BUFF_LEN)) != NULL) {
1897 deflate_context->defstream.avail_out = _U_W_BUFF_LEN;
1898 deflate_context->defstream.next_out = ((Bytef *)*data_out)+(*data_len_out);
1899 int res;
1900 switch ((res = deflate(&deflate_context->defstream, deflate_context->deflate_mask))) {
1901 case Z_OK:
1902 case Z_STREAM_END:
1903 case Z_BUF_ERROR:
1904 break;
1905 default:
1906 y_log_message(Y_LOG_LEVEL_ERROR, "websocket_extension_message_out_deflate - Error deflate");
1907 ret = U_ERROR;
1908 break;
1909 }
1910 (*data_len_out) += _U_W_BUFF_LEN - deflate_context->defstream.avail_out;
1911 } else {
1912 y_log_message(Y_LOG_LEVEL_ERROR, "websocket_extension_message_out_deflate - Error allocating resources for data_in_suffix");
1913 ret = U_ERROR;
1914 }
1915 } while (U_OK == ret && deflate_context->defstream.avail_out == 0);
1916
1917 // https://github.com/madler/zlib/issues/149
1918 if (U_OK == ret && Z_BLOCK == deflate_context->deflate_mask) {
1919 if ((*data_out = o_realloc(*data_out, (*data_len_out)+_U_W_BUFF_LEN)) != NULL) {
1920 deflate_context->defstream.avail_out = _U_W_BUFF_LEN;
1921 deflate_context->defstream.next_out = ((Bytef *)*data_out)+(*data_len_out);
1922 switch (deflate(&deflate_context->defstream, Z_FULL_FLUSH)) {
1923 case Z_OK:
1924 case Z_STREAM_END:
1925 case Z_BUF_ERROR:
1926 break;
1927 default:
1928 y_log_message(Y_LOG_LEVEL_ERROR, "websocket_extension_message_out_deflate - Error inflate (2)");
1929 ret = U_ERROR;
1930 break;
1931 }
1932 (*data_len_out) += _U_W_BUFF_LEN - deflate_context->defstream.avail_out;
1933 } else {
1934 y_log_message(Y_LOG_LEVEL_ERROR, "websocket_extension_message_out_deflate - Error allocating resources for data_in_suffix (2)");
1935 ret = U_ERROR;
1936 }
1937 }
1938
1939 if (U_OK != ret) {
1940 o_free(*data_out);
1941 *data_out = NULL;
1942 *data_len_out = 0;
1943 } else {
1944 if ((*(unsigned char **)data_out)[*data_len_out-1] == 0xff && (*(unsigned char **)data_out)[*data_len_out-2] == 0xff && (*(unsigned char **)data_out)[*data_len_out-3] == 0x00 && (*(unsigned char **)data_out)[*data_len_out-4] == 0x00) {
1945 *data_len_out -= 4;
1946 } else {
1947 (*(unsigned char **)data_out)[*data_len_out] = '\0';
1948 (*data_len_out)++;
1949 }
1950 }
1951 } else {
1952 y_log_message(Y_LOG_LEVEL_ERROR, "websocket_extension_message_out_deflate - Error context is NULL");
1953 ret = U_ERROR;
1954 }
1955 } else {
1956 *data_len_out = 0;
1957 ret = U_OK;
1958 }
1959 return ret;
1960 }
1961
websocket_extension_message_in_inflate(const uint8_t opcode,const uint64_t data_len_in,const char * data_in,uint64_t * data_len_out,char ** data_out,const uint64_t fragment_len,void * user_data,void * context)1962 int websocket_extension_message_in_inflate(const uint8_t opcode,
1963 const uint64_t data_len_in,
1964 const char * data_in,
1965 uint64_t * data_len_out,
1966 char ** data_out,
1967 const uint64_t fragment_len,
1968 void * user_data,
1969 void * context) {
1970 struct _websocket_deflate_context * deflate_context = (struct _websocket_deflate_context *)context;
1971 unsigned char * data_in_suffix;
1972 unsigned char suffix[4] = {0x00, 0x00, 0xff, 0xff};
1973 int ret;
1974 (void)opcode;
1975 (void)fragment_len;
1976 (void)user_data;
1977
1978 if (data_len_in) {
1979 if (deflate_context != NULL) {
1980 *data_out = NULL;
1981 *data_len_out = 0;
1982 if ((data_in_suffix = o_malloc(data_len_in+4)) != NULL) {
1983 memcpy(data_in_suffix, data_in, data_len_in);
1984 memcpy(data_in_suffix+data_len_in, suffix, 4);
1985
1986 deflate_context->infstream.avail_in = (uInt)data_len_in+4;
1987 deflate_context->infstream.next_in = (Bytef *)data_in_suffix;
1988
1989 ret = U_OK;
1990 do {
1991 if ((*data_out = o_realloc(*data_out, (*data_len_out)+_U_W_BUFF_LEN)) != NULL) {
1992 deflate_context->infstream.avail_out = _U_W_BUFF_LEN;
1993 deflate_context->infstream.next_out = ((Bytef *)*data_out)+(*data_len_out);
1994 switch (inflate(&deflate_context->infstream, deflate_context->inflate_mask)) {
1995 case Z_OK:
1996 case Z_STREAM_END:
1997 case Z_BUF_ERROR:
1998 break;
1999 default:
2000 y_log_message(Y_LOG_LEVEL_ERROR, "websocket_extension_message_in_inflate - Error inflate");
2001 ret = U_ERROR;
2002 break;
2003 }
2004 (*data_len_out) += _U_W_BUFF_LEN - deflate_context->infstream.avail_out;
2005 } else {
2006 y_log_message(Y_LOG_LEVEL_ERROR, "websocket_extension_message_in_inflate - Error allocating resources for data_in_suffix");
2007 ret = U_ERROR;
2008 }
2009 } while (U_OK == ret && deflate_context->infstream.avail_out == 0);
2010
2011 o_free(data_in_suffix);
2012 if (U_OK != ret) {
2013 o_free(*data_out);
2014 *data_out = NULL;
2015 *data_len_out = 0;
2016 }
2017 } else {
2018 y_log_message(Y_LOG_LEVEL_ERROR, "websocket_extension_message_in_inflate - Error allocating resources for data_in_suffix");
2019 ret = U_ERROR;
2020 }
2021 } else {
2022 y_log_message(Y_LOG_LEVEL_ERROR, "websocket_extension_message_in_inflate - Error context is NULL");
2023 ret = U_ERROR;
2024 }
2025 } else {
2026 // If RSV1 flag isn't set, copy data as is (as seen in firefox)
2027 *data_len_out = data_len_in;
2028 *data_out = o_malloc(data_len_in);
2029 if (*data_out != NULL) {
2030 memcpy(*data_out, data_in, data_len_in);
2031 ret = U_OK;
2032 } else {
2033 y_log_message(Y_LOG_LEVEL_ERROR, "websocket_extension_message_in_inflate - Error allocating resources for data_out");
2034 ret = U_ERROR;
2035 }
2036 }
2037 return ret;
2038 }
2039
websocket_extension_server_match_deflate(const char * extension_client,const char ** extension_client_list,char ** extension_server,void * user_data,void ** context)2040 int websocket_extension_server_match_deflate(const char * extension_client, const char ** extension_client_list, char ** extension_server, void * user_data, void ** context) {
2041 (void)user_data;
2042 size_t i;
2043 int first_param = 0, ret, server_bits_changed = 0, client_bits_changed = 0;
2044 char ** parameters = NULL, ** param_value = NULL;
2045 long int window_bits;
2046
2047 if (0 == o_strncmp(extension_client, _U_W_EXT_DEFLATE, o_strlen(_U_W_EXT_DEFLATE))) {
2048 // Check if the current extension is the first extension permessage-deflate
2049 for (i=0; extension_client_list[i] != NULL; i++) {
2050 if (0 == o_strncmp(extension_client_list[i], _U_W_EXT_DEFLATE, o_strlen(_U_W_EXT_DEFLATE))) {
2051 if (0 == o_strcmp(extension_client, extension_client_list[i])) {
2052 first_param = 1;
2053 }
2054 break;
2055 }
2056 }
2057 if (first_param) {
2058 if ((*context = o_malloc(sizeof(struct _websocket_deflate_context))) != NULL) {
2059 ((struct _websocket_deflate_context *)*context)->server_no_context_takeover = 0;
2060 ((struct _websocket_deflate_context *)*context)->client_no_context_takeover = 0;
2061 ((struct _websocket_deflate_context *)*context)->server_max_window_bits = WEBSOCKET_DEFLATE_WINDOWS_BITS;
2062 ((struct _websocket_deflate_context *)*context)->client_max_window_bits = WEBSOCKET_DEFLATE_WINDOWS_BITS;
2063 ((struct _websocket_deflate_context *)*context)->deflate_mask = Z_SYNC_FLUSH;
2064 ((struct _websocket_deflate_context *)*context)->inflate_mask = Z_SYNC_FLUSH;
2065 // Parse extension parameters
2066 ret = U_OK;
2067 if (o_strlen(extension_client) > o_strlen(_U_W_EXT_DEFLATE)) {
2068 if (split_string(extension_client+o_strlen(_U_W_EXT_DEFLATE), ";", ¶meters)) {
2069 for (i=0; parameters[i] != NULL; i++) {
2070 if (0 == o_strcmp("server_no_context_takeover", trimwhitespace(parameters[i]))) {
2071 ((struct _websocket_deflate_context *)*context)->server_no_context_takeover = 1;
2072 ((struct _websocket_deflate_context *)*context)->deflate_mask = Z_FULL_FLUSH;
2073 } else if (0 == o_strcmp("client_no_context_takeover", trimwhitespace(parameters[i]))) {
2074 ((struct _websocket_deflate_context *)*context)->client_no_context_takeover = 1;
2075 ((struct _websocket_deflate_context *)*context)->inflate_mask = Z_FULL_FLUSH;
2076 } else if (0 == o_strncmp("server_max_window_bits", trimwhitespace(parameters[i]), o_strlen("server_max_window_bits"))) {
2077 if (split_string(trimwhitespace(parameters[i]), "=", ¶m_value) == 2) {
2078 window_bits = strtol(param_value[1], NULL, 10);
2079 if (window_bits >= 8 && window_bits <= 15) {
2080 if (window_bits == 8) {
2081 window_bits = 9; // Is really 8, but zlib does not support value 8 so increase to 9 - Morten Houmøller Nygaard
2082 }
2083 ((struct _websocket_deflate_context *)*context)->server_max_window_bits = (uint)window_bits;
2084 server_bits_changed = 1;
2085 } else {
2086 y_log_message(Y_LOG_LEVEL_DEBUG, "websocket_extension_server_match_deflate - Error server_max_window_bits value");
2087 ret = U_ERROR;
2088 }
2089 free_string_array(param_value);
2090 } else {
2091 y_log_message(Y_LOG_LEVEL_ERROR, "websocket_extension_server_match_deflate - Error split_string param_value server_max_window_bits");
2092 ret = U_ERROR;
2093 }
2094 } else if (0 == o_strncmp("client_max_window_bits", trimwhitespace(parameters[i]), o_strlen("client_max_window_bits"))) {
2095 if (split_string(trimwhitespace(parameters[i]), "=", ¶m_value)) {
2096 if (o_strlen(trimwhitespace(param_value[1]))) {
2097 window_bits = strtol(trimwhitespace(param_value[1]), NULL, 10);
2098 } else {
2099 window_bits = WEBSOCKET_DEFLATE_WINDOWS_BITS;
2100 }
2101 if (window_bits >= 8 && window_bits <= 15) {
2102 if (window_bits == 8) {
2103 window_bits = 9; // Is really 8, but zlib does not support value 8 so increase to 9 - Morten Houmøller Nygaard
2104 }
2105 ((struct _websocket_deflate_context *)*context)->client_max_window_bits = (uint)window_bits;
2106 client_bits_changed = 1;
2107 } else {
2108 y_log_message(Y_LOG_LEVEL_DEBUG, "websocket_extension_server_match_deflate - Error client_max_window_bits value");
2109 ret = U_ERROR;
2110 }
2111 free_string_array(param_value);
2112 } else {
2113 y_log_message(Y_LOG_LEVEL_ERROR, "websocket_extension_server_match_deflate - Error split_string param_value client_max_window_bits");
2114 ret = U_ERROR;
2115 }
2116 } else if (o_strlen(trimwhitespace(parameters[i]))) {
2117 y_log_message(Y_LOG_LEVEL_ERROR, "websocket_extension_server_match_deflate - Invalid parameter");
2118 ret = U_ERROR;
2119 }
2120 }
2121 } else {
2122 y_log_message(Y_LOG_LEVEL_ERROR, "websocket_extension_server_match_deflate - Error split_string parameters");
2123 ret = U_ERROR;
2124 }
2125 free_string_array(parameters);
2126 }
2127 if (ret == U_OK) {
2128 ((struct _websocket_deflate_context *)*context)->defstream.zalloc = u_zalloc;
2129 ((struct _websocket_deflate_context *)*context)->defstream.zfree = u_zfree;
2130 ((struct _websocket_deflate_context *)*context)->defstream.opaque = Z_NULL;
2131 ((struct _websocket_deflate_context *)*context)->infstream.zalloc = u_zalloc;
2132 ((struct _websocket_deflate_context *)*context)->infstream.zfree = u_zfree;
2133 ((struct _websocket_deflate_context *)*context)->infstream.opaque = Z_NULL;
2134
2135 if (deflateInit2(&((struct _websocket_deflate_context *)*context)->defstream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, -((struct _websocket_deflate_context *)*context)->server_max_window_bits, U_WEBSOCKET_DEFAULT_MEMORY_LEVEL, Z_DEFAULT_STRATEGY) != Z_OK) {
2136 y_log_message(Y_LOG_LEVEL_ERROR, "websocket_extension_server_match_deflate - Error deflateInit2");
2137 deflateEnd(&((struct _websocket_deflate_context *)*context)->defstream);
2138 o_free(*context);
2139 *context = NULL;
2140 ret = U_ERROR;
2141 } else if (inflateInit2(&((struct _websocket_deflate_context *)*context)->infstream, -((struct _websocket_deflate_context *)*context)->client_max_window_bits) != Z_OK) {
2142 y_log_message(Y_LOG_LEVEL_ERROR, "websocket_extension_server_match_deflate - Error inflateInit2");
2143 inflateEnd(&((struct _websocket_deflate_context *)*context)->infstream);
2144 deflateEnd(&((struct _websocket_deflate_context *)*context)->defstream);
2145 o_free(*context);
2146 *context = NULL;
2147 ret = U_ERROR;
2148 }
2149 if (ret == U_OK) {
2150 *extension_server = o_strdup(_U_W_EXT_DEFLATE);
2151 if (((struct _websocket_deflate_context *)*context)->server_no_context_takeover) {
2152 *extension_server = mstrcatf(*extension_server, "; server_no_context_takeover");
2153 }
2154 if (((struct _websocket_deflate_context *)*context)->client_no_context_takeover) {
2155 *extension_server = mstrcatf(*extension_server, "; client_no_context_takeover");
2156 }
2157 if (server_bits_changed) {
2158 *extension_server = mstrcatf(*extension_server, "; server_max_window_bits=%u", ((struct _websocket_deflate_context *)*context)->server_max_window_bits);
2159 }
2160 if (client_bits_changed) {
2161 *extension_server = mstrcatf(*extension_server, "; client_max_window_bits=%u", ((struct _websocket_deflate_context *)*context)->client_max_window_bits);
2162 }
2163 }
2164 } else {
2165 o_free(*context);
2166 *context = NULL;
2167 }
2168 } else {
2169 y_log_message(Y_LOG_LEVEL_ERROR, "websocket_extension_server_match_deflate - Error allocating resources for context");
2170 ret = U_ERROR;
2171 }
2172 } else {
2173 ret = U_ERROR;
2174 }
2175 } else {
2176 ret = U_ERROR;
2177 }
2178 return ret;
2179 }
2180
websocket_extension_deflate_free_context(void * user_data,void * context)2181 void websocket_extension_deflate_free_context(void * user_data, void * context) {
2182 (void)user_data;
2183 inflateEnd(&((struct _websocket_deflate_context *)context)->infstream);
2184 deflateEnd(&((struct _websocket_deflate_context *)context)->defstream);
2185 o_free(context);
2186 }
2187
ulfius_add_websocket_deflate_extension(struct _u_response * response)2188 int ulfius_add_websocket_deflate_extension(struct _u_response * response) {
2189 return ulfius_add_websocket_extension_message_perform(response, _U_W_EXT_DEFLATE, U_WEBSOCKET_RSV1, websocket_extension_message_out_deflate, NULL, websocket_extension_message_in_inflate, NULL, &websocket_extension_server_match_deflate, NULL, websocket_extension_deflate_free_context, NULL);
2190 }
2191
2192 /**
2193 * Sets the websocket in closing mode
2194 * The websocket will not necessarily be closed at the return of this function,
2195 * it will process through the end of the `websocket_manager_callback`
2196 * and the `websocket_onclose_callback` calls first.
2197 * return U_OK on success
2198 * or U_ERROR on error
2199 */
ulfius_websocket_send_close_signal(struct _websocket_manager * websocket_manager)2200 int ulfius_websocket_send_close_signal(struct _websocket_manager * websocket_manager) {
2201 if (websocket_manager != NULL) {
2202
2203 websocket_manager->close_flag = 1;
2204 return U_OK;
2205 } else {
2206 return U_ERROR_PARAMS;
2207 }
2208 }
2209
2210 /**
2211 * Returns the status of the websocket connection
2212 * Returned values can be U_WEBSOCKET_STATUS_OPEN or U_WEBSOCKET_STATUS_CLOSE
2213 * wether the websocket is open or closed, or U_WEBSOCKET_STATUS_ERROR on error
2214 */
ulfius_websocket_status(struct _websocket_manager * websocket_manager)2215 int ulfius_websocket_status(struct _websocket_manager * websocket_manager) {
2216 if (websocket_manager != NULL) {
2217 return websocket_manager->connected?U_WEBSOCKET_STATUS_OPEN:U_WEBSOCKET_STATUS_CLOSE;
2218 } else {
2219 return U_WEBSOCKET_STATUS_ERROR;
2220 }
2221 }
2222
2223 /**
2224 * Wait until the websocket connection is closed or the timeout in milliseconds is reached
2225 * if timeout is 0, no timeout is set
2226 * Returned values can be U_WEBSOCKET_STATUS_OPEN or U_WEBSOCKET_STATUS_CLOSE
2227 * wether the websocket is open or closed, or U_WEBSOCKET_STATUS_ERROR on error
2228 */
ulfius_websocket_wait_close(struct _websocket_manager * websocket_manager,unsigned int timeout)2229 int ulfius_websocket_wait_close(struct _websocket_manager * websocket_manager, unsigned int timeout) {
2230 struct timespec abstime;
2231 int ret;
2232
2233 if (websocket_manager != NULL) {
2234 if (websocket_manager->connected) {
2235 if (timeout) {
2236 clock_gettime(CLOCK_REALTIME, &abstime);
2237 abstime.tv_nsec += ((timeout%1000) * 1000000);
2238 abstime.tv_sec += (timeout / 1000);
2239 pthread_mutex_lock(&websocket_manager->status_lock);
2240 ret = pthread_cond_timedwait(&websocket_manager->status_cond, &websocket_manager->status_lock, &abstime);
2241 pthread_mutex_unlock(&websocket_manager->status_lock);
2242 return ((ret == ETIMEDOUT && websocket_manager->connected)?U_WEBSOCKET_STATUS_OPEN:U_WEBSOCKET_STATUS_CLOSE);
2243 } else {
2244 pthread_mutex_lock(&websocket_manager->status_lock);
2245 pthread_cond_wait(&websocket_manager->status_cond, &websocket_manager->status_lock);
2246 pthread_mutex_unlock(&websocket_manager->status_lock);
2247 return U_WEBSOCKET_STATUS_CLOSE;
2248 }
2249 } else {
2250 return U_WEBSOCKET_STATUS_CLOSE;
2251 }
2252 } else {
2253 return U_WEBSOCKET_STATUS_ERROR;
2254 }
2255 }
2256
2257 /********************************/
2258 /** Client websocket functions **/
2259 /********************************/
2260
random_at_most(long max)2261 static long random_at_most(long max) {
2262 unsigned char
2263 num_bins = (unsigned char) max + 1,
2264 num_rand = (unsigned char) 0xff,
2265 bin_size = num_rand / num_bins,
2266 defect = num_rand % num_bins;
2267
2268 unsigned char x[1];
2269 do {
2270 gnutls_rnd(GNUTLS_RND_KEY, x, sizeof(x));
2271 }
2272 // This is carefully written not to overflow
2273 while (num_rand - defect <= (unsigned char)x[0]);
2274
2275 // Truncated division is intentional
2276 return x[0]/bin_size;
2277 }
2278
2279 /**
2280 * Generates a random string and store it in str
2281 */
rand_string(char * str,size_t str_size)2282 static char * rand_string(char * str, size_t str_size) {
2283 const char charset[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
2284 size_t n;
2285
2286 if (str_size > 0 && str != NULL) {
2287 for (n = 0; n < str_size; n++) {
2288 long key = random_at_most((sizeof(charset)) - 2);
2289 str[n] = charset[key];
2290 }
2291 str[str_size] = '\0';
2292 return str;
2293 } else {
2294 return NULL;
2295 }
2296 }
2297
2298 /**
2299 * Set values for a struct _u_request to open a websocket
2300 * request must be previously initialized
2301 * Return U_OK on success
2302 */
ulfius_set_websocket_request(struct _u_request * request,const char * url,const char * websocket_protocol,const char * websocket_extensions)2303 int ulfius_set_websocket_request(struct _u_request * request,
2304 const char * url,
2305 const char * websocket_protocol,
2306 const char * websocket_extensions) {
2307 int ret;
2308 char rand_str[17] = {0}, rand_str_base64[25] = {0};
2309 size_t out_len;
2310
2311 if (request != NULL && url != NULL) {
2312 o_free(request->http_protocol);
2313 o_free(request->http_verb);
2314 o_free(request->http_url);
2315 request->http_protocol = o_strdup("1.1");
2316 request->http_verb = o_strdup("GET");
2317 request->http_url = o_strdup(url);
2318 if (websocket_protocol != NULL) {
2319 u_map_put(request->map_header, "Sec-WebSocket-Protocol", websocket_protocol);
2320 }
2321 if (websocket_extensions != NULL) {
2322 u_map_put(request->map_header, "Sec-WebSocket-Extensions", websocket_extensions);
2323 }
2324 u_map_put(request->map_header, "Sec-WebSocket-Version", "13");
2325 u_map_put(request->map_header, "Upgrade", "websocket");
2326 u_map_put(request->map_header, "Connection", "Upgrade");
2327 u_map_put(request->map_header, "Content-Length", "0");
2328 u_map_put(request->map_header, "User-Agent", U_WEBSOCKET_USER_AGENT "/" STR(ULFIUS_VERSION));
2329 rand_string(rand_str, 16);
2330 if (!o_base64_encode((unsigned char *)rand_str, 16, (unsigned char *)rand_str_base64, &out_len)) {
2331 y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error o_base64_encode with the input string %s", rand_str);
2332 ret = U_ERROR;
2333 } else {
2334 u_map_put(request->map_header, "Sec-WebSocket-Key", rand_str_base64);
2335 ret = U_OK;
2336 }
2337 } else {
2338 y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error ulfius_set_websocket_request input parameters");
2339 ret = U_ERROR;
2340 }
2341 return ret;
2342 }
2343
ulfius_add_websocket_client_extension_message_perform(struct _websocket_client_handler * websocket_client_handler,const char * extension,uint8_t rsv,int (* websocket_extension_message_out_perform)(const uint8_t opcode,const uint64_t data_len_in,const char * data_in,uint64_t * data_len_out,char ** data_out,const uint64_t fragment_len,void * user_data,void * context),void * websocket_extension_message_out_perform_user_data,int (* websocket_extension_message_in_perform)(const uint8_t opcode,const uint64_t data_len_in,const char * data_in,uint64_t * data_len_out,char ** data_out,const uint64_t fragment_len,void * user_data,void * context),void * websocket_extension_message_in_perform_user_data,int (* websocket_extension_client_match)(const char * extension_server,void * user_data,void ** context),void * websocket_extension_client_match_user_data,void (* websocket_extension_free_context)(void * user_data,void * context),void * websocket_extension_free_context_user_data)2344 int ulfius_add_websocket_client_extension_message_perform(struct _websocket_client_handler * websocket_client_handler,
2345 const char * extension,
2346 uint8_t rsv,
2347 int (* websocket_extension_message_out_perform)(const uint8_t opcode,
2348 const uint64_t data_len_in,
2349 const char * data_in,
2350 uint64_t * data_len_out,
2351 char ** data_out,
2352 const uint64_t fragment_len,
2353 void * user_data,
2354 void * context),
2355 void * websocket_extension_message_out_perform_user_data,
2356 int (* websocket_extension_message_in_perform)(const uint8_t opcode,
2357 const uint64_t data_len_in,
2358 const char * data_in,
2359 uint64_t * data_len_out,
2360 char ** data_out,
2361 const uint64_t fragment_len,
2362 void * user_data,
2363 void * context),
2364 void * websocket_extension_message_in_perform_user_data,
2365 int (* websocket_extension_client_match)(const char * extension_server,
2366 void * user_data,
2367 void ** context),
2368 void * websocket_extension_client_match_user_data,
2369 void (* websocket_extension_free_context)(void * user_data,
2370 void * context),
2371 void * websocket_extension_free_context_user_data) {
2372 int ret;
2373 struct _websocket_extension * w_extension;
2374
2375 if (websocket_client_handler != NULL && o_strlen(extension) &&
2376 (websocket_extension_message_out_perform != NULL || websocket_extension_message_in_perform != NULL) &&
2377 (rsv == U_WEBSOCKET_RSV1 || rsv == U_WEBSOCKET_RSV2 || rsv == U_WEBSOCKET_RSV3)) {
2378 if (websocket_client_handler->websocket == NULL) {
2379 websocket_client_handler->websocket = o_malloc(sizeof(struct _websocket));
2380 if (websocket_client_handler->websocket == NULL || ulfius_init_websocket(websocket_client_handler->websocket) != U_OK) {
2381 y_log_message(Y_LOG_LEVEL_ERROR, "ulfius_add_websocket_client_extension_message_perform - Error ulfius_init_websocket");
2382 return U_ERROR;
2383 }
2384 }
2385 if ((w_extension = o_malloc(sizeof(struct _websocket_extension))) != NULL) {
2386 if (ulfius_init_websocket_extension(w_extension) == U_OK) {
2387 w_extension->extension_client = o_strdup(extension);
2388 w_extension->rsv = rsv;
2389 w_extension->websocket_extension_message_out_perform = websocket_extension_message_out_perform;
2390 w_extension->websocket_extension_message_out_perform_user_data = websocket_extension_message_out_perform_user_data;
2391 w_extension->websocket_extension_message_in_perform = websocket_extension_message_in_perform;
2392 w_extension->websocket_extension_message_in_perform_user_data = websocket_extension_message_in_perform_user_data;
2393 w_extension->websocket_extension_client_match = websocket_extension_client_match;
2394 w_extension->websocket_extension_client_match_user_data = websocket_extension_client_match_user_data;
2395 w_extension->websocket_extension_free_context = websocket_extension_free_context;
2396 w_extension->websocket_extension_free_context_user_data = websocket_extension_free_context_user_data;
2397 if (websocket_client_handler->websocket->websocket_manager->websocket_extension_list == NULL) {
2398 websocket_client_handler->websocket->websocket_manager->websocket_extension_list = o_malloc(sizeof(struct _pointer_list));
2399 if (websocket_client_handler->websocket->websocket_manager->websocket_extension_list != NULL) {
2400 pointer_list_init(websocket_client_handler->websocket->websocket_manager->websocket_extension_list);
2401 } else {
2402 y_log_message(Y_LOG_LEVEL_ERROR, "ulfius_add_websocket_client_extension_message_perform - Error allocating resources for struct websocket_extension_list");
2403 return U_ERROR_MEMORY;
2404 }
2405 }
2406 if (pointer_list_append(websocket_client_handler->websocket->websocket_manager->websocket_extension_list, w_extension)) {
2407 ret = U_OK;
2408 } else {
2409 y_log_message(Y_LOG_LEVEL_ERROR, "ulfius_add_websocket_client_extension_message_perform - Error pointer_list_append");
2410 ret = U_ERROR;
2411 }
2412 } else {
2413 y_log_message(Y_LOG_LEVEL_ERROR, "ulfius_add_websocket_client_extension_message_perform - Error ulfius_init_websocket_extension");
2414 ret = U_ERROR;
2415 }
2416 } else {
2417 y_log_message(Y_LOG_LEVEL_ERROR, "ulfius_add_websocket_client_extension_message_perform - Error allocating resources for struct _websocket_extension");
2418 ret = U_ERROR_MEMORY;
2419 }
2420 } else {
2421 ret = U_ERROR_PARAMS;
2422 }
2423 return ret;
2424 }
2425
2426 /**
2427 * Open a websocket client connection
2428 * Return U_OK on success
2429 */
ulfius_open_websocket_client_connection(struct _u_request * request,void (* websocket_manager_callback)(const struct _u_request * request,struct _websocket_manager * websocket_manager,void * websocket_manager_user_data),void * websocket_manager_user_data,void (* websocket_incoming_message_callback)(const struct _u_request * request,struct _websocket_manager * websocket_manager,const struct _websocket_message * message,void * websocket_incoming_user_data),void * websocket_incoming_user_data,void (* websocket_onclose_callback)(const struct _u_request * request,struct _websocket_manager * websocket_manager,void * websocket_onclose_user_data),void * websocket_onclose_user_data,struct _websocket_client_handler * websocket_client_handler,struct _u_response * response)2430 int ulfius_open_websocket_client_connection(struct _u_request * request,
2431 void (* websocket_manager_callback) (const struct _u_request * request,
2432 struct _websocket_manager * websocket_manager,
2433 void * websocket_manager_user_data),
2434 void * websocket_manager_user_data,
2435 void (* websocket_incoming_message_callback) (const struct _u_request * request,
2436 struct _websocket_manager * websocket_manager,
2437 const struct _websocket_message * message,
2438 void * websocket_incoming_user_data),
2439 void * websocket_incoming_user_data,
2440 void (* websocket_onclose_callback) (const struct _u_request * request,
2441 struct _websocket_manager * websocket_manager,
2442 void * websocket_onclose_user_data),
2443 void * websocket_onclose_user_data,
2444 struct _websocket_client_handler * websocket_client_handler,
2445 struct _u_response * response) {
2446 int ret;
2447 struct yuarel y_url;
2448 char * url, * basic_auth_encoded_header, * basic_auth, * basic_auth_encoded;
2449 size_t basic_auth_encoded_len;
2450 struct _websocket * websocket = NULL;
2451 pthread_t thread_websocket;
2452 int thread_ret_websocket = 0, thread_detach_websocket = 0;
2453
2454 if (request != NULL && response != NULL && (websocket_manager_callback != NULL || websocket_incoming_message_callback != NULL)) {
2455 url = o_strdup(request->http_url);
2456 if (!yuarel_parse(&y_url, url)) {
2457 if (0 == o_strcasecmp("http", y_url.scheme) || 0 == o_strcasecmp("https", y_url.scheme) || 0 == o_strcasecmp("ws", y_url.scheme) || 0 == o_strcasecmp("wss", y_url.scheme)) {
2458 if (!y_url.port) {
2459 if (0 == o_strcasecmp("http", y_url.scheme) || 0 == o_strcasecmp("ws", y_url.scheme)) {
2460 y_url.port = 80;
2461 } else {
2462 y_url.port = 443;
2463 }
2464 }
2465 if (y_url.username != NULL && y_url.password != NULL) {
2466 basic_auth = msprintf("%s:%s", y_url.username, y_url.password);
2467 basic_auth_encoded = o_malloc((o_strlen(basic_auth)*4/3)+1);
2468 memset(basic_auth_encoded, 0, (o_strlen(basic_auth)*4/3)+1);
2469 if (o_base64_encode((const unsigned char *)basic_auth, o_strlen(basic_auth), (unsigned char *)basic_auth_encoded, &basic_auth_encoded_len)) {
2470 basic_auth_encoded_header = msprintf("Basic: %s", basic_auth_encoded);
2471 u_map_remove_from_key(request->map_header, "Authorization");
2472 u_map_put(request->map_header, "Authorization", basic_auth_encoded_header);
2473 o_free(basic_auth_encoded_header);
2474 o_free(basic_auth_encoded);
2475 } else {
2476 y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error o_base64_encode");
2477 }
2478 o_free(basic_auth);
2479 }
2480
2481 if (websocket_client_handler->websocket == NULL) {
2482 websocket = o_malloc(sizeof(struct _websocket));
2483 if (ulfius_init_websocket(websocket) != U_OK) {
2484 o_free(websocket);
2485 websocket = NULL;
2486 y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error allocating resources for websocket");
2487 ret = U_ERROR_MEMORY;
2488 } else {
2489 websocket_client_handler->websocket = websocket;
2490 }
2491 } else {
2492 websocket = websocket_client_handler->websocket;
2493 }
2494 if (websocket != NULL) {
2495 websocket->request = ulfius_duplicate_request(request);
2496 websocket->websocket_manager->type = U_WEBSOCKET_CLIENT;
2497 websocket->websocket_manager_callback = websocket_manager_callback;
2498 websocket->websocket_manager_user_data = websocket_manager_user_data;
2499 websocket->websocket_incoming_message_callback = websocket_incoming_message_callback;
2500 websocket->websocket_incoming_user_data = websocket_incoming_user_data;
2501 websocket->websocket_onclose_callback = websocket_onclose_callback;
2502 websocket->websocket_onclose_user_data = websocket_onclose_user_data;
2503 // Open connection
2504 if (0 == o_strcasecmp("http", y_url.scheme) || 0 == o_strcasecmp("ws", y_url.scheme)) {
2505 websocket->websocket_manager->tls = 0;
2506 if (ulfius_open_websocket(request, &y_url, websocket, response) != U_OK) {
2507 y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error ulfius_open_websocket");
2508 ulfius_clear_websocket(websocket);
2509 ret = U_ERROR;
2510 } else {
2511 ret = U_OK;
2512 }
2513 } else {
2514 websocket->websocket_manager->tls = 1;
2515 if (ulfius_open_websocket_tls(request, &y_url, websocket, response) != U_OK) {
2516 y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error ulfius_open_websocket_tls");
2517 ulfius_clear_websocket(websocket);
2518 ret = U_ERROR;
2519 } else {
2520 ret = U_OK;
2521 }
2522 }
2523 if (ret == U_OK) {
2524 thread_ret_websocket = pthread_create(&thread_websocket, NULL, ulfius_thread_websocket, (void *)websocket);
2525 thread_detach_websocket = pthread_detach(thread_websocket);
2526 if (thread_ret_websocket || thread_detach_websocket) {
2527 y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error creating or detaching websocket manager thread, return code: %d, detach code: %d",
2528 thread_ret_websocket, thread_detach_websocket);
2529 ulfius_clear_websocket(websocket);
2530 ret = U_ERROR;
2531 }
2532 }
2533 } else {
2534 ret = U_ERROR_MEMORY;
2535 }
2536 } else {
2537 y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Unknown scheme, please use one of the following: 'http', 'https', 'ws', 'wss'");
2538 ret = U_ERROR_PARAMS;
2539 }
2540 } else {
2541 y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error parsing url");
2542 ret = U_ERROR_PARAMS;
2543 }
2544 o_free(url);
2545 } else {
2546 ret = U_ERROR_PARAMS;
2547 }
2548 return ret;
2549 }
2550
websocket_extension_client_match_deflate(const char * extension_server,void * user_data,void ** context)2551 int websocket_extension_client_match_deflate(const char * extension_server, void * user_data, void ** context) {
2552 (void)user_data;
2553 size_t i;
2554 int ret;
2555 char ** parameters = NULL, ** param_value = NULL;
2556 long int window_bits;
2557
2558 if (0 == o_strncmp(extension_server, _U_W_EXT_DEFLATE, o_strlen(_U_W_EXT_DEFLATE))) {
2559 if ((*context = o_malloc(sizeof(struct _websocket_deflate_context))) != NULL) {
2560 ((struct _websocket_deflate_context *)*context)->server_no_context_takeover = 0;
2561 ((struct _websocket_deflate_context *)*context)->client_no_context_takeover = 0;
2562 ((struct _websocket_deflate_context *)*context)->server_max_window_bits = WEBSOCKET_DEFLATE_WINDOWS_BITS;
2563 ((struct _websocket_deflate_context *)*context)->client_max_window_bits = WEBSOCKET_DEFLATE_WINDOWS_BITS;
2564 ((struct _websocket_deflate_context *)*context)->deflate_mask = Z_SYNC_FLUSH;
2565 ((struct _websocket_deflate_context *)*context)->inflate_mask = Z_SYNC_FLUSH;
2566 // Parse extension parameters
2567 ret = U_OK;
2568 if (o_strlen(extension_server) > o_strlen(_U_W_EXT_DEFLATE)) {
2569 if (split_string(extension_server+o_strlen(_U_W_EXT_DEFLATE), ";", ¶meters)) {
2570 for (i=0; parameters[i] != NULL; i++) {
2571 if (0 == o_strcmp("server_no_context_takeover", trimwhitespace(parameters[i]))) {
2572 ((struct _websocket_deflate_context *)*context)->server_no_context_takeover = 1;
2573 ((struct _websocket_deflate_context *)*context)->inflate_mask = Z_FULL_FLUSH;
2574 } else if (0 == o_strcmp("client_no_context_takeover", trimwhitespace(parameters[i]))) {
2575 ((struct _websocket_deflate_context *)*context)->client_no_context_takeover = 1;
2576 ((struct _websocket_deflate_context *)*context)->deflate_mask = Z_FULL_FLUSH;
2577 } else if (0 == o_strncmp("server_max_window_bits", trimwhitespace(parameters[i]), o_strlen("server_max_window_bits"))) {
2578 if (split_string(trimwhitespace(parameters[i]), "=", ¶m_value) == 2) {
2579 window_bits = strtol(param_value[1], NULL, 10);
2580 if (window_bits >= 8 && window_bits <= 15) {
2581 if (window_bits == 8) {
2582 window_bits = 9; // Is really 8, but zlib does not support value 8 so increase to 9 - Morten Houmøller Nygaard
2583 }
2584 ((struct _websocket_deflate_context *)*context)->server_max_window_bits = (uint)window_bits;
2585 } else {
2586 y_log_message(Y_LOG_LEVEL_DEBUG, "websocket_extension_client_match_deflate - Error server_max_window_bits value");
2587 ret = U_ERROR;
2588 }
2589 free_string_array(param_value);
2590 } else {
2591 y_log_message(Y_LOG_LEVEL_ERROR, "websocket_extension_client_match_deflate - Error split_string param_value server_max_window_bits");
2592 ret = U_ERROR;
2593 }
2594 } else if (0 == o_strncmp("client_max_window_bits", trimwhitespace(parameters[i]), o_strlen("client_max_window_bits"))) {
2595 if (split_string(trimwhitespace(parameters[i]), "=", ¶m_value)) {
2596 if (o_strlen(trimwhitespace(param_value[1]))) {
2597 window_bits = strtol(trimwhitespace(param_value[1]), NULL, 10);
2598 } else {
2599 window_bits = WEBSOCKET_DEFLATE_WINDOWS_BITS;
2600 }
2601 if (window_bits >= 8 && window_bits <= 15) {
2602 if (window_bits == 8) {
2603 window_bits = 9; // Is really 8, but zlib does not support value 8 so increase to 9 - Morten Houmøller Nygaard
2604 }
2605 ((struct _websocket_deflate_context *)*context)->client_max_window_bits = (uint)window_bits;
2606 } else {
2607 y_log_message(Y_LOG_LEVEL_DEBUG, "websocket_extension_client_match_deflate - Error client_max_window_bits value");
2608 ret = U_ERROR;
2609 }
2610 free_string_array(param_value);
2611 } else {
2612 y_log_message(Y_LOG_LEVEL_ERROR, "websocket_extension_client_match_deflate - Error split_string param_value client_max_window_bits");
2613 ret = U_ERROR;
2614 }
2615 } else if (o_strlen(trimwhitespace(parameters[i]))) {
2616 y_log_message(Y_LOG_LEVEL_ERROR, "websocket_extension_client_match_deflate - Invalid parameter");
2617 ret = U_ERROR;
2618 }
2619 }
2620 } else {
2621 y_log_message(Y_LOG_LEVEL_ERROR, "websocket_extension_client_match_deflate - Error split_string parameters");
2622 ret = U_ERROR;
2623 }
2624 free_string_array(parameters);
2625 }
2626 if (ret == U_OK) {
2627 ((struct _websocket_deflate_context *)*context)->defstream.zalloc = u_zalloc;
2628 ((struct _websocket_deflate_context *)*context)->defstream.zfree = u_zfree;
2629 ((struct _websocket_deflate_context *)*context)->defstream.opaque = Z_NULL;
2630 ((struct _websocket_deflate_context *)*context)->infstream.zalloc = u_zalloc;
2631 ((struct _websocket_deflate_context *)*context)->infstream.zfree = u_zfree;
2632 ((struct _websocket_deflate_context *)*context)->infstream.opaque = Z_NULL;
2633
2634 if (deflateInit2(&((struct _websocket_deflate_context *)*context)->defstream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, -((struct _websocket_deflate_context *)*context)->client_max_window_bits, U_WEBSOCKET_DEFAULT_MEMORY_LEVEL, Z_DEFAULT_STRATEGY) != Z_OK) {
2635 y_log_message(Y_LOG_LEVEL_ERROR, "websocket_extension_client_match_deflate - Error deflateInit2");
2636 deflateEnd(&((struct _websocket_deflate_context *)*context)->defstream);
2637 o_free(*context);
2638 *context = NULL;
2639 ret = U_ERROR;
2640 } else if (inflateInit2(&((struct _websocket_deflate_context *)*context)->infstream, -((struct _websocket_deflate_context *)*context)->server_max_window_bits) != Z_OK) {
2641 y_log_message(Y_LOG_LEVEL_ERROR, "websocket_extension_client_match_deflate - Error inflateInit2");
2642 inflateEnd(&((struct _websocket_deflate_context *)*context)->infstream);
2643 deflateEnd(&((struct _websocket_deflate_context *)*context)->defstream);
2644 o_free(*context);
2645 *context = NULL;
2646 ret = U_ERROR;
2647 }
2648 } else {
2649 o_free(*context);
2650 *context = NULL;
2651 }
2652 } else {
2653 y_log_message(Y_LOG_LEVEL_ERROR, "websocket_extension_client_match_deflate - Error allocating resources for context");
2654 ret = U_ERROR;
2655 }
2656 } else {
2657 ret = U_ERROR;
2658 }
2659 return ret;
2660 }
2661
ulfius_add_websocket_client_deflate_extension(struct _websocket_client_handler * websocket_client_handler)2662 int ulfius_add_websocket_client_deflate_extension(struct _websocket_client_handler * websocket_client_handler) {
2663 return ulfius_add_websocket_client_extension_message_perform(websocket_client_handler, _U_W_EXT_DEFLATE, U_WEBSOCKET_RSV1, websocket_extension_message_out_deflate, NULL, websocket_extension_message_in_inflate, NULL, websocket_extension_client_match_deflate, NULL, websocket_extension_deflate_free_context, NULL);
2664 }
2665
2666 /**
2667 * Send a close signal to the websocket
2668 * return U_OK when the signal is sent
2669 * or U_ERROR on error
2670 */
ulfius_websocket_client_connection_send_close_signal(struct _websocket_client_handler * websocket_client_handler)2671 int ulfius_websocket_client_connection_send_close_signal(struct _websocket_client_handler * websocket_client_handler) {
2672 if (websocket_client_handler != NULL) {
2673 return ulfius_websocket_send_close_signal(websocket_client_handler->websocket->websocket_manager);
2674 } else {
2675 return U_ERROR_PARAMS;
2676 }
2677 }
2678
2679 /**
2680 * Closes a websocket client connection
2681 * return U_OK when the websocket is closed
2682 * or U_ERROR on error
2683 */
ulfius_websocket_client_connection_close(struct _websocket_client_handler * websocket_client_handler)2684 int ulfius_websocket_client_connection_close(struct _websocket_client_handler * websocket_client_handler) {
2685 if (websocket_client_handler != NULL) {
2686 if (websocket_client_handler->websocket != NULL) {
2687 if (ulfius_websocket_send_close_signal(websocket_client_handler->websocket->websocket_manager) == U_OK) {
2688 if (ulfius_websocket_wait_close(websocket_client_handler->websocket->websocket_manager, 0) != U_WEBSOCKET_STATUS_CLOSE) {
2689 y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error ulfius_websocket_send_close_signal");
2690 return U_ERROR;
2691 }
2692 ulfius_clear_websocket(websocket_client_handler->websocket);
2693 return U_OK;
2694 } else {
2695 y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error ulfius_websocket_send_close_signal");
2696 return U_ERROR;
2697 }
2698 } else {
2699 return U_OK;
2700 }
2701 } else {
2702 return U_ERROR_PARAMS;
2703 }
2704 }
2705
2706 /**
2707 * Returns the status of the websocket client connection
2708 * Returned values can be U_WEBSOCKET_STATUS_OPEN or U_WEBSOCKET_STATUS_CLOSE
2709 * wether the websocket is open or closed, or U_WEBSOCKET_STATUS_ERROR on error
2710 */
ulfius_websocket_client_connection_status(struct _websocket_client_handler * websocket_client_handler)2711 int ulfius_websocket_client_connection_status(struct _websocket_client_handler * websocket_client_handler) {
2712 if (websocket_client_handler != NULL) {
2713 return ulfius_websocket_status(websocket_client_handler->websocket->websocket_manager);
2714 } else {
2715 return U_WEBSOCKET_STATUS_ERROR;
2716 }
2717 }
2718
2719 /**
2720 * Wait until the websocket client connection is closed or the timeout in milliseconds is reached
2721 * if timeout is 0, no timeout is set
2722 * Returned values can be U_WEBSOCKET_STATUS_OPEN or U_WEBSOCKET_STATUS_CLOSE
2723 * wether the websocket is open or closed, or U_WEBSOCKET_STATUS_ERROR on error
2724 */
ulfius_websocket_client_connection_wait_close(struct _websocket_client_handler * websocket_client_handler,unsigned int timeout)2725 int ulfius_websocket_client_connection_wait_close(struct _websocket_client_handler * websocket_client_handler, unsigned int timeout) {
2726 int ret;
2727
2728 if (websocket_client_handler != NULL) {
2729 ret = ulfius_websocket_wait_close(websocket_client_handler->websocket->websocket_manager, timeout);
2730 if (ret == U_WEBSOCKET_STATUS_CLOSE && websocket_client_handler->websocket != NULL) {
2731 ulfius_clear_websocket(websocket_client_handler->websocket);
2732 websocket_client_handler->websocket = NULL;
2733 }
2734 return ret;
2735 } else {
2736 return U_WEBSOCKET_STATUS_ERROR;
2737 }
2738 }
2739
2740 #endif
2741