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 pss->pss_list = vhd->pss_list; 87 vhd->pss_list = pss; 88 pss->wsi = wsi; 89 pss->last = vhd->current; 90 break; 91 92 case LWS_CALLBACK_CLOSED: 93 /* remove our closing pss from the list of live pss */ 94 lws_start_foreach_llp(struct per_session_data__minimal **, 95 ppss, vhd->pss_list) { 96 if (*ppss == pss) { 97 *ppss = pss->pss_list; 98 break; 99 } 100 } lws_end_foreach_llp(ppss, pss_list); 101 break; 102 103 case LWS_CALLBACK_SERVER_WRITEABLE: 104 if (!vhd->amsg.payload) 105 break; 106 107 if (pss->last == vhd->current) 108 break; 109 110 /* notice we allowed for LWS_PRE in the payload already */ 111 m = lws_write(wsi, ((unsigned char *)vhd->amsg.payload) + 112 LWS_PRE, vhd->amsg.len, LWS_WRITE_TEXT); 113 if (m < (int)vhd->amsg.len) { 114 lwsl_err("ERROR %d writing to ws socket\n", m); 115 return -1; 116 } 117 118 pss->last = vhd->current; 119 break; 120 121 case LWS_CALLBACK_RECEIVE: 122 if (vhd->amsg.payload) 123 __minimal_destroy_message(&vhd->amsg); 124 125 vhd->amsg.len = len; 126 /* notice we over-allocate by LWS_PRE */ 127 vhd->amsg.payload = malloc(LWS_PRE + len); 128 if (!vhd->amsg.payload) { 129 lwsl_user("OOM: dropping\n"); 130 break; 131 } 132 133 memcpy((char *)vhd->amsg.payload + LWS_PRE, in, len); 134 vhd->current++; 135 136 /* 137 * let everybody know we want to write something on them 138 * as soon as they are ready 139 */ 140 lws_start_foreach_llp(struct per_session_data__minimal **, 141 ppss, vhd->pss_list) { 142 lws_callback_on_writable((*ppss)->wsi); 143 } lws_end_foreach_llp(ppss, pss_list); 144 break; 145 146 default: 147 break; 148 } 149 150 return 0; 151} 152 153#define LWS_PLUGIN_PROTOCOL_MINIMAL \ 154 { \ 155 "lws-minimal", \ 156 callback_minimal, \ 157 sizeof(struct per_session_data__minimal), \ 158 128, \ 159 0, NULL, 0 \ 160 } 161