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), ";", &parameters)) {
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]), "=", &param_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]), "=", &param_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), ";", &parameters)) {
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]), "=", &param_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]), "=", &param_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