#include #include #include int max_poll_elements; struct lws_pollfd *pollfds; int *fd_lookup; int count_pollfds; static int callback_http(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len) { int n; struct lws_pollargs *pa = (struct lws_pollargs *)in; switch (reason) { case LWS_CALLBACK_ADD_POLL_FD: if (count_pollfds >= max_poll_elements) { lwsl_err("LWS_CALLBACK_ADD_POLL_FD: too many sockets to track\n"); return 1; } fd_lookup[pa->fd] = count_pollfds; pollfds[count_pollfds].fd = pa->fd; pollfds[count_pollfds].events = pa->events; pollfds[count_pollfds].revents = 0; count_pollfds++; break; case LWS_CALLBACK_DEL_POLL_FD: if (!--count_pollfds) break; n = fd_lookup[pa->fd]; /* have the last guy take up the vacant slot */ pollfds[n] = pollfds[count_pollfds]; fd_lookup[pollfds[count_pollfds].fd] = n; break; case LWS_CALLBACK_CHANGE_MODE_POLL_FD: pollfds[fd_lookup[pa->fd]].events = pa->events; break; default: break; } return 0; } static int callback_dumb_increment(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len) { switch (reason) { case LWS_CALLBACK_ESTABLISHED: // just log message that someone is connecting printf("connection established\n"); break; case LWS_CALLBACK_RECEIVE: { // the funny part // create a buffer to hold our response // it has to have some pre and post padding. You don't need to care // what comes there, lwss will do everything for you. For more info see // http://git.warmcat.com/cgi-bin/cgit/lwss/tree/lib/lwss.h#n597 unsigned char *buf = (unsigned char*) malloc(LWS_SEND_BUFFER_PRE_PADDING + len + LWS_SEND_BUFFER_POST_PADDING); int i; // pointer to `void *in` holds the incomming request // we're just going to put it in reverse order and put it in `buf` with // correct offset. `len` holds length of the request. for (i=0; i < len; i++) { buf[LWS_SEND_BUFFER_PRE_PADDING + (len - 1) - i ] = ((char *) in)[i]; } // log what we recieved and what we're going to send as a response. // that disco syntax `%.*s` is used to print just a part of our buffer // http://stackoverflow.com/questions/5189071/print-part-of-char-array printf("received data: %s, replying: %.*s\n", (char *) in, (int) len, buf + LWS_SEND_BUFFER_PRE_PADDING); // send response // just notice that we have to tell where exactly our response starts. That's // why there's `buf[LWS_SEND_BUFFER_PRE_PADDING]` and how long it is. // we know that our response has the same length as request because // it's the same message in reverse order. lws_write(wsi, &buf[LWS_SEND_BUFFER_PRE_PADDING], len, LWS_WRITE_TEXT); // release memory back into the wild free(buf); break; } case LWS_CALLBACK_CLOSED: printf("connection closed\n"); break; default: break; } return 0; } static struct lws_protocols protocols[] = { /* first protocol must always be HTTP handler */ { "http-only", // name callback_http, // callback 0, // per_session_data_size 0 /* max frame size / rx buffer */ }, { "dumb-increment-protocol", // protocol name - very important! callback_dumb_increment, // callback 0, // we don't use any per session data 0 }, { NULL, NULL, 0, 0 /* End of list */ } }; int main(void) { unsigned int ms, ms_1sec = 0; int n = 0; max_poll_elements = getdtablesize(); count_pollfds = 0; pollfds = malloc(max_poll_elements * sizeof (struct lws_pollfd)); fd_lookup = malloc(max_poll_elements * sizeof (int)); if (pollfds == NULL || fd_lookup == NULL) { lwsl_err("Out of memory pollfds=%d\n", max_poll_elements); return -1; } // server url will be http://localhost:9000 int port = 9000; struct lws_context *context; struct lws_context_creation_info context_info = { .port = port, .iface = NULL, .protocols = protocols, .extensions = NULL, .ssl_cert_filepath = "cert.pem", .ssl_private_key_filepath = "key.pem", .ssl_ca_filepath = NULL, .options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT, .gid = -1, .uid = -1, .ka_time = 0, .ka_probes = 0, .ka_interval = 0 }; // create lws context representing this server context = lws_create_context(&context_info); if (context == NULL) { fprintf(stderr, "lws init failed\n"); return -1; } printf("starting server...\n"); /* * this represents an existing server's single poll action * which also includes libwebsocket sockets */ while (!0) { struct timeval tv; gettimeofday(&tv, NULL); ms = (tv.tv_sec * 1000) + (tv.tv_usec / 1000); n = poll(pollfds, count_pollfds, 50); if (n < 0) { continue; } if (n) { for (n = 0; n < count_pollfds; n++) { if (pollfds[n].revents) { /* returns immediately if the fd does not match anything under libwebsocketscontrol */ if (lws_service_fd(context, &pollfds[n]) < 0) goto done; } } /* if needed, force-service wsis that may not have read all input */ /* NOTE: lws_service_adjust_timeout() is not available in v2.0 (version of package in debian) */ /* while (!lws_service_adjust_timeout(context, 1, 0)) { lwsl_notice("extpoll doing forced service!\n"); lws_service_tsi(context, -1, 0); } */ } else { /* no revents, but before polling again, make lws check for any timeouts */ if (ms - ms_1sec > 1000) { //lwsl_notice("1 per sec\n"); lws_service_fd(context, NULL); ms_1sec = ms; } } } done: lws_context_destroy(context); return 0; }