1/* 2 * ws protocol handler plugin for "lws-minimal" 3 * 4 * Written in 2010-2019 by Andy Green <andy@warmcat.com> 5 * 6 * This file is made available under the Creative Commons CC0 1.0 7 * Universal Public Domain Dedication. 8 * 9 * This version holds a single message at a time, which may be lost if a new 10 * message comes. See the minimal-ws-server-ring sample for the same thing 11 * but using an lws_ring ringbuffer to hold up to 8 messages at a time. 12 */ 13 14#if !defined (LWS_PLUGIN_STATIC) 15#define LWS_DLL 16#define LWS_INTERNAL 17#include <libwebsockets.h> 18#endif 19 20#include <string.h> 21 22/* one of these created for each message */ 23 24struct msg { 25 void *payload; /* is malloc'd */ 26 size_t len; 27}; 28 29/* one of these is created for each client connecting to us */ 30 31struct per_session_data__minimal { 32 struct per_session_data__minimal *pss_list; 33 struct lws *wsi; 34 int last; /* the last message number we sent */ 35}; 36 37/* one of these is created for each vhost our protocol is used with */ 38 39struct per_vhost_data__minimal { 40 struct lws_context *context; 41 struct lws_vhost *vhost; 42 const struct lws_protocols *protocol; 43 44 struct per_session_data__minimal *pss_list; /* linked-list of live pss*/ 45 46 struct msg amsg; /* the one pending message... */ 47 int current; /* the current message number we are caching */ 48}; 49 50/* destroys the message when everyone has had a copy of it */ 51 52static void 53__minimal_destroy_message(void *_msg) 54{ 55 struct msg *msg = _msg; 56 57 free(msg->payload); 58 msg->payload = NULL; 59 msg->len = 0; 60} 61 62static int 63callback_minimal(struct lws *wsi, enum lws_callback_reasons reason, 64 void *user, void *in, size_t len) 65{ 66 struct per_session_data__minimal *pss = 67 (struct per_session_data__minimal *)user; 68 struct per_vhost_data__minimal *vhd = 69 (struct per_vhost_data__minimal *) 70 lws_protocol_vh_priv_get(lws_get_vhost(wsi), 71 lws_get_protocol(wsi)); 72 int m; 73 74 switch (reason) { 75 case LWS_CALLBACK_PROTOCOL_INIT: 76 vhd = lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi), 77 lws_get_protocol(wsi), 78 sizeof(struct per_vhost_data__minimal)); 79 vhd->context = lws_get_context(wsi); 80 vhd->protocol = lws_get_protocol(wsi); 81 vhd->vhost = lws_get_vhost(wsi); 82 break; 83 84 case LWS_CALLBACK_ESTABLISHED: 85 /* add ourselves to the list of live pss held in the vhd */ 86 lws_ll_fwd_insert(pss, pss_list, vhd->pss_list); 87 pss->wsi = wsi; 88 pss->last = vhd->current; 89 break; 90 91 case LWS_CALLBACK_CLOSED: 92 /* remove our closing pss from the list of live pss */ 93 lws_ll_fwd_remove(struct per_session_data__minimal, pss_list, 94 pss, vhd->pss_list); 95 break; 96 97 case LWS_CALLBACK_SERVER_WRITEABLE: 98 if (!vhd->amsg.payload) 99 break; 100 101 if (pss->last == vhd->current) 102 break; 103 104 /* notice we allowed for LWS_PRE in the payload already */ 105 m = lws_write(wsi, ((unsigned char *)vhd->amsg.payload) + 106 LWS_PRE, vhd->amsg.len, LWS_WRITE_TEXT); 107 if (m < (int)vhd->amsg.len) { 108 lwsl_err("ERROR %d writing to ws\n", m); 109 return -1; 110 } 111 112 pss->last = vhd->current; 113 break; 114 115 case LWS_CALLBACK_RECEIVE: 116 if (vhd->amsg.payload) 117 __minimal_destroy_message(&vhd->amsg); 118 119 vhd->amsg.len = len; 120 /* notice we over-allocate by LWS_PRE */ 121 vhd->amsg.payload = malloc(LWS_PRE + len); 122 if (!vhd->amsg.payload) { 123 lwsl_user("OOM: dropping\n"); 124 break; 125 } 126 127 memcpy((char *)vhd->amsg.payload + LWS_PRE, in, len); 128 vhd->current++; 129 130 /* 131 * let everybody know we want to write something on them 132 * as soon as they are ready 133 */ 134 lws_start_foreach_llp(struct per_session_data__minimal **, 135 ppss, vhd->pss_list) { 136 lws_callback_on_writable((*ppss)->wsi); 137 } lws_end_foreach_llp(ppss, pss_list); 138 break; 139 140 default: 141 break; 142 } 143 144 return 0; 145} 146 147#define LWS_PLUGIN_PROTOCOL_MINIMAL \ 148 { \ 149 "lws-minimal", \ 150 callback_minimal, \ 151 sizeof(struct per_session_data__minimal), \ 152 128, \ 153 0, NULL, 0 \ 154 } 155