#include #include #include #include #include #include #include #include #include namespace websockets { struct Log { Log(std::string const & name, int syslog_options, int debug_level){ setlogmask(LOG_UPTO (LOG_DEBUG)); openlog(name.c_str(), syslog_options, LOG_DAEMON); lws_set_log_level(debug_level, lwsl_emit_syslog); } #define log_function(nice_name, lwsl_name)\ template \ void nice_name(std::string const & format, T... args){\ lwsl_name(format.c_str(), args...);\ } log_function(notice, lwsl_notice) log_function(error, lwsl_err) log_function(warning, lwsl_warn) log_function(debug, lwsl_debug) #undef log_function ~Log(){ closelog(); } }; struct Context { std::unique_ptr context; Context(lws_context_creation_info& info) : context(libwebsocket_create_context(&info), &libwebsocket_context_destroy) { if(context == nullptr){ lwsl_err("libwebsocket init failed\n"); throw std::runtime_error("libwebsocket init failed"); } } libwebsocket_context const * get_raw() const { return context.get(); } libwebsocket_context * get_raw() { return context.get(); } }; template struct Protocol { typedef T user_type; int callback(libwebsocket_context *context, libwebsocket *wsi, libwebsocket_callback_reasons reason, void *user, void *in, size_t len){ return call(*context, *wsi, reason, *static_cast(user), in, len); } virtual int call(libwebsocket_context& context, libwebsocket& wsi, libwebsocket_callback_reasons reason, T& user, void *in, size_t len){ return 0; }; }; template struct TestProtocol : public Protocol { std::function establish_func; std::function close_func; std::function write_func; std::function receive_func; TestProtocol(decltype(establish_func) establish_func, decltype(close_func) close_func, decltype(write_func) write_func, decltype(receive_func) receive_func) : establish_func(establish_func) , close_func(close_func) , write_func(write_func) , receive_func(receive_func) {} virtual int call(libwebsocket_context& context, libwebsocket& wsi, libwebsocket_callback_reasons reason, T& user, void *in, size_t len){ switch (reason) { case LWS_CALLBACK_ESTABLISHED: establish_func(user); break; case LWS_CALLBACK_CLOSED: close_func(user); break; case LWS_CALLBACK_SERVER_WRITEABLE:{ std::string string_to_send = write_func(user); // we need the extra bytes padding on both sides :( unsigned char * buf = new unsigned char [LWS_SEND_BUFFER_PRE_PADDING + string_to_send.size() + LWS_SEND_BUFFER_POST_PADDING]; memcpy(&buf[LWS_SEND_BUFFER_PRE_PADDING], string_to_send.c_str(), string_to_send.size()); int n = libwebsocket_write(&wsi, &buf[LWS_SEND_BUFFER_PRE_PADDING], string_to_send.size(), LWS_WRITE_TEXT); if (n < 0) { lwsl_err("ERROR %d writing to socket, hanging up\n", n); return 1; } if (n < string_to_send.size()) { lwsl_err("Partial write\n"); return -1; } break; } case LWS_CALLBACK_RECEIVE: receive_func(user, std::string((char*)in, len)); libwebsocket_callback_on_writable(&context, &wsi); break; default: break; } return 0; } }; #define WSprotocol_callback(protocol)\ [](libwebsocket_context *context, libwebsocket *wsi, libwebsocket_callback_reasons reason, void *user, void *in, size_t len)\ {return protocol.callback(context, wsi, reason, user, in, len);} #define WSstandard_protocol(name, protocol)\ { name, WSprotocol_callback(protocol), sizeof(decltype(protocol)::user_type) } static option options[] = { { "help", no_argument, NULL, 'h' }, { "debug", required_argument, NULL, 'd' }, { "port", required_argument, NULL, 'p' }, { "ssl", no_argument, NULL, 's' }, { "interface", required_argument, NULL, 'i' }, { NULL, 0, 0, 0 } }; inline int default_main(int argc, char **argv, libwebsocket_protocols* protocols){ int n = 0; int port = 7681; int use_ssl = 0; int opts = 0; char interface_name[128] = ""; const char *interface = NULL; int syslog_options = LOG_PID | LOG_PERROR; int listen_port; lws_context_creation_info info; int debug_level = 7; memset(&info, 0, sizeof info); while (n >= 0) { n = getopt_long(argc, argv, "i:hsp:d:D" , options, NULL); if (n < 0) continue; switch (n) { case 'd': debug_level = atoi(optarg); break; case 's': use_ssl = 1; /* 1 = take care about cert verification, 2 = allow anything */ break; case 'p': port = atoi(optarg); break; case 'i': strncpy(interface_name, optarg, sizeof interface_name); interface_name[(sizeof interface_name) - 1] = '\0'; interface = interface_name; break; case '?': case 'h': fprintf(stderr, "Usage: libwebsockets-test-echo " "[--ssl] " "[--port=

] " "[-d ]\n"); exit(1); } } websockets::Log log("lwsts", syslog_options, debug_level); log.notice("Running in server mode\n"); listen_port = port; info.port = listen_port; info.iface = interface; info.protocols = protocols; if (use_ssl) { info.ssl_cert_filepath = "libwebsockets-test-server.pem"; info.ssl_private_key_filepath = "libwebsockets-test-server.key.pem"; } info.gid = -1; info.uid = -1; info.options = opts; static bool force_exit = false; signal(SIGINT, [](int){ force_exit = true; }); websockets::Context context(info); while (!force_exit) { auto ret = libwebsocket_service(context.get_raw(), 10); if(ret < 0) break; } log.notice("libwebsockets-test-echo exited cleanly\n"); return 0; } } // namespace websockets