1 #include <libwebsockets.h>
2 #include <string.h>
3 #include <signal.h>
4 #if defined(WIN32)
5 #define HAVE_STRUCT_TIMESPEC
6 #if defined(pid_t)
7 #undef pid_t
8 #endif
9 #endif
10
11 static int nclients = 11;
12 unsigned char msg[LWS_PRE+128];
13 static int message_delay = 500000; // microseconds
14 static int connection_delay = 100000; // microseconds
15 static struct lws_context *context;
16 static const char *server_address = "localhost", *pro = "lws-minimal";
17 static int interrupted = 0, port = 7681, ssl_connection = 0;
18
connect_client()19 static int connect_client()
20 {
21 struct lws_client_connect_info i;
22
23 memset(&i, 0, sizeof(i));
24
25 i.context = context;
26 i.port = port;
27 i.address = server_address;
28 i.path = "/";
29 i.host = i.address;
30 i.origin = i.address;
31 i.ssl_connection = ssl_connection;
32 i.protocol = pro;
33 i.local_protocol_name = pro;
34
35 //usleep(connection_delay);
36 lwsl_notice("%s: connection %s:%d\n", __func__, i.address, i.port);
37 if (!lws_client_connect_via_info(&i)) return 1;
38
39 return 0;
40 }
41
42 static int
callback(struct lws * wsi,enum lws_callback_reasons reason,void * user,void * in,size_t len)43 callback(struct lws *wsi, enum lws_callback_reasons reason,
44 void *user, void *in, size_t len)
45 {
46 int m= 0, n = 0;
47 short r;
48 #if defined(_DEBUG) && !defined(LWS_WITH_NO_LOGS)
49 size_t remain;
50 int first = 0, final = 0;
51 #endif
52
53 //lwsl_notice("callback called with reason %d\n", reason);
54 switch (reason) {
55
56 case LWS_CALLBACK_PROTOCOL_INIT:
57 for (n = 0; n < nclients; n++)
58 connect_client();
59 break;
60
61 case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
62 lwsl_err("CLIENT_CONNECTION_ERROR: %s\n", in ? (char *)in :
63 "(null)");
64 if(--nclients == 0) interrupted = 1;
65 break;
66
67 /* --- client callbacks --- */
68
69 case LWS_CALLBACK_CLIENT_ESTABLISHED:
70 lws_callback_on_writable(wsi);
71 lwsl_user("%s: established connection, wsi = %p\n",
72 __func__, wsi);
73 break;
74
75 case LWS_CALLBACK_CLIENT_CLOSED:
76 lwsl_user("%s: CLOSED\n", __func__);
77 if(--nclients == 0) interrupted = 1;
78 break;
79
80 case LWS_CALLBACK_CLIENT_WRITEABLE:
81
82 m = lws_write(wsi, msg + LWS_PRE, 128, LWS_WRITE_TEXT);
83 if (m < 128) {
84 lwsl_err("sending message failed: %d < %d\n", m, n);
85 return -1;
86 }
87
88 /*
89 * Schedule the timer after minimum message delay plus the
90 * random number of centiseconds.
91 */
92 if (lws_get_random(lws_get_context(wsi), &r, 2) == 2) {
93 n = message_delay + 10000*(r % 100);
94 lwsl_debug("set timer on %d usecs\n", n);
95 lws_set_timer_usecs(wsi, n);
96 }
97 break;
98
99 case LWS_CALLBACK_TIMER:
100 // Let the main loop know we want to send another message to the
101 // server
102 lws_callback_on_writable(wsi);
103 break;
104
105 case LWS_CALLBACK_CLIENT_RECEIVE:
106 #if defined(_DEBUG) && !defined(LWS_WITH_NO_LOGS)
107 first = lws_is_first_fragment(wsi);
108 final = lws_is_final_fragment(wsi);
109 remain = lws_remaining_packet_payload(wsi);
110 lwsl_debug("LWS_CALLBACK_RECEIVE: len = %lu, first = %d, "
111 "final = %d, remains = %lu\n",
112 (unsigned long)len, first, final,
113 (unsigned long)remain);
114 #endif
115 break;
116
117 case LWS_CALLBACK_WS_PEER_INITIATED_CLOSE:
118 lwsl_notice("server initiated connection close: len = %lu, "
119 "in = %s\n", (unsigned long)len, (char*)in);
120 return 0;
121
122 default:
123 break;
124 }
125
126 return lws_callback_http_dummy(wsi, reason, user, in, len);
127 }
128
129 static const struct lws_protocols protocols[] = {
130 { "spam-rx-tx", callback, 4096, 4096, 0, NULL, 0 },
131 { NULL, NULL, 0, 0 }
132 };
133
134 static void
sigint_handler(int sig)135 sigint_handler(int sig)
136 {
137 interrupted = 1;
138 }
139
main(int argc,const char ** argv)140 int main(int argc, const char **argv)
141 {
142 struct lws_context_creation_info info;
143 const char *p;
144 int n = 0, logs =
145 LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE;
146 #ifndef WIN32
147 srandom((unsigned int)time(0));
148 #endif
149
150 memset(msg, 'x', sizeof(msg));
151
152 signal(SIGINT, sigint_handler);
153
154 if (lws_cmdline_option(argc, argv, "-d"))
155 logs |= LLL_INFO | LLL_DEBUG;
156
157 lws_set_log_level(logs, NULL);
158
159 memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
160 info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
161 info.port = CONTEXT_PORT_NO_LISTEN; /* we do not run any server */
162 info.protocols = protocols;
163 #if defined(LWS_WITH_MBEDTLS) || defined(USE_WOLFSSL)
164 /*
165 * OpenSSL uses the system trust store. mbedTLS has to be told which
166 * CA to trust explicitly.
167 */
168 info.client_ssl_ca_filepath = "./libwebsockets.org.cer";
169 #endif
170
171 if ((p = lws_cmdline_option(argc, argv, "-h"))) {
172 server_address = p;
173 }
174
175 if ((p = lws_cmdline_option(argc, argv, "-s"))) {
176 ssl_connection |=
177 LCCSCF_USE_SSL |
178 LCCSCF_ALLOW_SELFSIGNED |
179 LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK;
180 }
181
182 if ((p = lws_cmdline_option(argc, argv, "-p")))
183 port = atoi(p);
184
185 if ((p = lws_cmdline_option(argc, argv, "-n"))) {
186 n = atoi(p);
187 if (n < 1)
188 n = 1;
189 if (n < nclients)
190 nclients = n;
191 lwsl_notice("Start test clients: %d\n", nclients);
192 }
193
194 if ((p = lws_cmdline_option(argc, argv, "-c"))) {
195 connection_delay = atoi(p);
196 lwsl_notice("Connection delay: %d\n", connection_delay);
197 }
198
199 if ((p = lws_cmdline_option(argc, argv, "-m"))) {
200 message_delay = atoi(p);
201 lwsl_notice("Message delay: %d\n", connection_delay);
202 }
203
204 info.fd_limit_per_thread = (unsigned int)(1 + nclients + 1);
205
206 context = lws_create_context(&info);
207 if (!context) {
208 lwsl_err("lws init failed\n");
209 return 1;
210 }
211
212 while (n >= 0 && !interrupted)
213 n = lws_service(context, 0);
214
215 lwsl_notice("%s: exiting service loop. n = %d, interrupted = %d\n",
216 __func__, n, interrupted);
217
218 lws_context_destroy(context);
219
220 return 0;
221 }
222