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