1/* 2 * lws-minimal-ws-client 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 demonstrates the a minimal ws client using lws. 10 * 11 * It connects to https://libwebsockets.org/ and makes a 12 * wss connection to the dumb-increment protocol there. While 13 * connected, it prints the numbers it is being sent by 14 * dumb-increment protocol. 15 */ 16 17#include <libwebsockets.h> 18#include <string.h> 19#include <signal.h> 20 21static int interrupted, rx_seen, test; 22static struct lws *client_wsi; 23 24static int 25callback_dumb_increment(struct lws *wsi, enum lws_callback_reasons reason, 26 void *user, void *in, size_t len) 27{ 28 switch (reason) { 29 30 /* because we are protocols[0] ... */ 31 case LWS_CALLBACK_CLIENT_CONNECTION_ERROR: 32 lwsl_err("CLIENT_CONNECTION_ERROR: %s\n", 33 in ? (char *)in : "(null)"); 34 client_wsi = NULL; 35 break; 36 37 case LWS_CALLBACK_CLIENT_ESTABLISHED: 38 lwsl_user("%s: established\n", __func__); 39 break; 40 41 case LWS_CALLBACK_CLIENT_RECEIVE: 42 lwsl_user("RX: %s\n", (const char *)in); 43 rx_seen++; 44 if (test && rx_seen == 10) 45 interrupted = 1; 46 break; 47 48 case LWS_CALLBACK_CLIENT_CLOSED: 49 client_wsi = NULL; 50 break; 51 52 default: 53 break; 54 } 55 56 return lws_callback_http_dummy(wsi, reason, user, in, len); 57} 58 59static const struct lws_protocols protocols[] = { 60 { 61 "dumb-increment-protocol", 62 callback_dumb_increment, 63 0, 0, 0, NULL, 0 64 }, 65 LWS_PROTOCOL_LIST_TERM 66}; 67 68static void 69sigint_handler(int sig) 70{ 71 interrupted = 1; 72} 73 74int main(int argc, const char **argv) 75{ 76 struct lws_context_creation_info info; 77 struct lws_client_connect_info i; 78 struct lws_context *context; 79 const char *p; 80 int n = 0, logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE 81 /* for LLL_ verbosity above NOTICE to be built into lws, lws 82 * must have been configured with -DCMAKE_BUILD_TYPE=DEBUG 83 * instead of =RELEASE */ 84 /* | LLL_INFO */ /* | LLL_PARSER */ /* | LLL_HEADER */ 85 /* | LLL_EXT */ /* | LLL_CLIENT */ /* | LLL_LATENCY */ 86 /* | LLL_DEBUG */; 87 88 signal(SIGINT, sigint_handler); 89 if ((p = lws_cmdline_option(argc, argv, "-d"))) 90 logs = atoi(p); 91 92 test = !!lws_cmdline_option(argc, argv, "-t"); 93 94 lws_set_log_level(logs, NULL); 95 lwsl_user("LWS minimal ws client rx [-d <logs>] [--h2] [-t (test)]\n"); 96 97 memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */ 98 info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT; 99 info.port = CONTEXT_PORT_NO_LISTEN; /* we do not run any server */ 100 info.protocols = protocols; 101 info.timeout_secs = 10; 102 info.connect_timeout_secs = 30; 103#if defined(LWS_WITH_MBEDTLS) || defined(USE_WOLFSSL) 104 /* 105 * OpenSSL uses the system trust store. mbedTLS has to be told which 106 * CA to trust explicitly. 107 */ 108 info.client_ssl_ca_filepath = "./libwebsockets.org.cer"; 109#endif 110 111 /* 112 * since we know this lws context is only ever going to be used with 113 * one client wsis / fds / sockets at a time, let lws know it doesn't 114 * have to use the default allocations for fd tables up to ulimit -n. 115 * It will just allocate for 1 internal and 1 (+ 1 http2 nwsi) that we 116 * will use. 117 */ 118 info.fd_limit_per_thread = 1 + 1 + 1; 119 120 context = lws_create_context(&info); 121 if (!context) { 122 lwsl_err("lws init failed\n"); 123 return 1; 124 } 125 126 memset(&i, 0, sizeof i); /* otherwise uninitialized garbage */ 127 i.context = context; 128 i.port = 443; 129 i.address = "libwebsockets.org"; 130 i.path = "/"; 131 i.host = i.address; 132 i.origin = i.address; 133 i.ssl_connection = LCCSCF_USE_SSL; 134 i.protocol = protocols[0].name; /* "dumb-increment-protocol" */ 135 i.pwsi = &client_wsi; 136 137 if (lws_cmdline_option(argc, argv, "--h2")) 138 i.alpn = "h2"; 139 140 lws_client_connect_via_info(&i); 141 142 while (n >= 0 && client_wsi && !interrupted) 143 n = lws_service(context, 0); 144 145 lws_context_destroy(context); 146 147 lwsl_user("Completed %s\n", rx_seen > 10 ? "OK" : "Failed"); 148 149 return rx_seen > 10; 150} 151