Joshua Moerman
12 years ago
4 changed files with 248 additions and 216 deletions
@ -0,0 +1,216 @@ |
|||||
|
|
||||
|
#include <string> |
||||
|
#include <memory> |
||||
|
#include <functional> |
||||
|
#include <stdexcept> |
||||
|
|
||||
|
#include <syslog.h> |
||||
|
#include <getopt.h> |
||||
|
#include <signal.h> |
||||
|
#include <string.h> |
||||
|
|
||||
|
#include <lib/libwebsockets.h> |
||||
|
|
||||
|
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 <typename... T>\ |
||||
|
void nice_name(std::string const & format, T... args){\ |
||||
|
lwsl_name(format.c_str(), std::forward(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<libwebsocket_context, decltype(libwebsocket_context_destroy)*> 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 <typename T> |
||||
|
struct Protocol { |
||||
|
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<T*>(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 <typename T> |
||||
|
struct TestProtocol : public Protocol<T> { |
||||
|
std::function<int(T&)> establish_func; |
||||
|
std::function<int(T&)> close_func; |
||||
|
std::function<std::string(T&)> write_func; |
||||
|
std::function<int(T&, std::string)> 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){ |
||||
|
int n = 0; |
||||
|
std::string string_to_send; |
||||
|
switch (reason) { |
||||
|
case LWS_CALLBACK_ESTABLISHED: |
||||
|
establish_func(user); |
||||
|
break; |
||||
|
case LWS_CALLBACK_CLOSED: |
||||
|
close_func(user); |
||||
|
break; |
||||
|
case LWS_CALLBACK_SERVER_WRITEABLE: |
||||
|
string_to_send = write_func(user); |
||||
|
n = libwebsocket_write(&wsi, (unsigned char *)string_to_send.c_str(), 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, user)\ |
||||
|
{ name, WSprotocol_callback(protocol), sizeof(user) } |
||||
|
|
||||
|
|
||||
|
static struct 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; |
||||
|
struct 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=<p>] " |
||||
|
"[-d <log bitfield>]\n"); |
||||
|
exit(1); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
websockets::Log log("lwsts", syslog_options, debug_level); |
||||
|
|
||||
|
log.notice("libwebsockets echo test - " |
||||
|
"(C) Copyright 2010-2013 Andy Green <andy@warmcat.com> - " |
||||
|
"licensed under LGPL2.1\n"); |
||||
|
|
||||
|
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
|
Reference in new issue