| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409 | 
							- #include <time.h>
 
- #include <stdio.h>
 
- #include <stdlib.h>
 
- #include <string.h>
 
- #include "civetweb.h"
 
- /* Get an OS independent definition for sleep() */
 
- #ifdef _WIN32
 
- #include <windows.h>
 
- #define sleep(x) Sleep((x)*1000)
 
- #else
 
- #include <unistd.h>
 
- #endif
 
- /* User defined client data structure */
 
- struct tclient_data {
 
- 	time_t started;
 
- 	time_t closed;
 
- 	struct tmsg_list_elem *msgs;
 
- };
 
- struct tmsg_list_elem {
 
- 	time_t timestamp;
 
- 	void *data;
 
- 	size_t len;
 
- 	struct tmsg_list_elem *next;
 
- };
 
- /* Helper function to get a printable name for websocket opcodes */
 
- static const char *
 
- msgtypename(int flags)
 
- {
 
- 	unsigned f = (unsigned)flags & 0xFu;
 
- 	switch (f) {
 
- 	case MG_WEBSOCKET_OPCODE_CONTINUATION:
 
- 		return "continuation";
 
- 	case MG_WEBSOCKET_OPCODE_TEXT:
 
- 		return "text";
 
- 	case MG_WEBSOCKET_OPCODE_BINARY:
 
- 		return "binary";
 
- 	case MG_WEBSOCKET_OPCODE_CONNECTION_CLOSE:
 
- 		return "connection close";
 
- 	case MG_WEBSOCKET_OPCODE_PING:
 
- 		return "PING";
 
- 	case MG_WEBSOCKET_OPCODE_PONG:
 
- 		return "PONG";
 
- 	}
 
- 	return "unknown";
 
- }
 
- /* Callback for handling data received from the server */
 
- static int
 
- websocket_client_data_handler(struct mg_connection *conn,
 
-                               int flags,
 
-                               char *data,
 
-                               size_t data_len,
 
-                               void *user_data)
 
- {
 
- 	struct tclient_data *pclient_data = (struct tclient_data *)user_data;
 
- 	time_t now = time(NULL);
 
- 	/* We may get some different message types (websocket opcodes).
 
- 	 * We will handle these messages differently. */
 
- 	int is_text = ((flags & 0xf) == MG_WEBSOCKET_OPCODE_TEXT);
 
- 	int is_bin = ((flags & 0xf) == MG_WEBSOCKET_OPCODE_BINARY);
 
- 	int is_ping = ((flags & 0xf) == MG_WEBSOCKET_OPCODE_PING);
 
- 	int is_pong = ((flags & 0xf) == MG_WEBSOCKET_OPCODE_PONG);
 
- 	int is_close = ((flags & 0xf) == MG_WEBSOCKET_OPCODE_CONNECTION_CLOSE);
 
- 	/* Log output: We got some data */
 
- 	printf("%10.0f - Client received %lu bytes of %s data from server%s",
 
- 	       difftime(now, pclient_data->started),
 
- 	       (long unsigned)data_len,
 
- 	       msgtypename(flags),
 
- 	       (is_text ? ": " : ".\n"));
 
- 	/* Check if we got a websocket PING request */
 
- 	if (is_ping) {
 
- 		/* PING requests are to check if the connection is broken.
 
- 		 * They should be replied with a PONG with the same data.
 
- 		 */
 
- 		mg_websocket_client_write(conn,
 
- 		                          MG_WEBSOCKET_OPCODE_PONG,
 
- 		                          data,
 
- 		                          data_len);
 
- 		return 1;
 
- 	}
 
- 	/* Check if we got a websocket PONG message */
 
- 	if (is_pong) {
 
- 		/* A PONG message may be a response to our PING, but
 
- 		 * it is also allowed to send unsolicited PONG messages
 
- 		 * send by the server to check some lower level TCP
 
- 		 * connections. Just ignore all kinds of PONGs. */
 
- 		return 1;
 
- 	}
 
- 	/* It we got a websocket TEXT message, handle it ... */
 
- 	if (is_text) {
 
- 		struct tmsg_list_elem *p;
 
- 		struct tmsg_list_elem **where = &(pclient_data->msgs);
 
- 		/* ... by printing it to the log ... */
 
- 		fwrite(data, 1, data_len, stdout);
 
- 		printf("\n");
 
- 		/* ... and storing it (OOM ignored for simplicity). */
 
- 		p = (struct tmsg_list_elem *)malloc(sizeof(struct tmsg_list_elem));
 
- 		p->timestamp = now;
 
- 		p->data = malloc(data_len);
 
- 		memcpy(p->data, data, data_len);
 
- 		p->len = data_len;
 
- 		p->next = NULL;
 
- 		while (*where != NULL) {
 
- 			where = &((*where)->next);
 
- 		}
 
- 		*where = p;
 
- 	}
 
- 	/* Another option would be BINARY data. */
 
- 	if (is_bin) {
 
- 		/* In this example, we just ignore binary data.
 
- 		 * According to some blogs, discriminating TEXT and
 
- 		 * BINARY may be some remains from earlier drafts
 
- 		 * of the WebSocket protocol.
 
- 		 * Anyway, a real application will usually use
 
- 		 * either TEXT or BINARY. */
 
- 	}
 
- 	/* It could be a CLOSE message as well. */
 
- 	if (is_close) {
 
- 		printf("%10.0f - Goodbye\n", difftime(now, pclient_data->started));
 
- 		return 0;
 
- 	}
 
- 	/* Return 1 to keep the connection open */
 
- 	return 1;
 
- }
 
- /* Callback for handling a close message received from the server */
 
- static void
 
- websocket_client_close_handler(const struct mg_connection *conn,
 
-                                void *user_data)
 
- {
 
- 	struct tclient_data *pclient_data = (struct tclient_data *)user_data;
 
- 	pclient_data->closed = time(NULL);
 
- 	printf("%10.0f - Client: Close handler\n",
 
- 	       difftime(pclient_data->closed, pclient_data->started));
 
- }
 
- /* Websocket client test function */
 
- void
 
- run_websocket_client(const char *host,
 
-                      int port,
 
-                      int secure,
 
-                      const char *path,
 
-                      const char *greetings)
 
- {
 
- 	char err_buf[100] = {0};
 
- 	struct mg_connection *client_conn;
 
- 	struct tclient_data *pclient_data;
 
- 	int i;
 
- 	/* Allocate some memory for callback specific data.
 
- 	 * For simplicity, we ignore OOM handling in this example. */
 
- 	pclient_data = (struct tclient_data *)malloc(sizeof(struct tclient_data));
 
- 	/* Store start time in the private structure */
 
- 	pclient_data->started = time(NULL);
 
- 	pclient_data->closed = 0;
 
- 	pclient_data->msgs = NULL;
 
- 	/* Log first action (time = 0.0) */
 
- 	printf("%10.0f - Connecting to %s:%i\n", 0.0, host, port);
 
- 	/* Connect to the given WS or WSS (WS secure) server */
 
- 	client_conn = mg_connect_websocket_client(host,
 
- 	                                          port,
 
- 	                                          secure,
 
- 	                                          err_buf,
 
- 	                                          sizeof(err_buf),
 
- 	                                          path,
 
- 	                                          NULL,
 
- 	                                          websocket_client_data_handler,
 
- 	                                          websocket_client_close_handler,
 
- 	                                          pclient_data);
 
- 	/* Check if connection is possible */
 
- 	if (client_conn == NULL) {
 
- 		printf("mg_connect_websocket_client error: %s\n", err_buf);
 
- 		return;
 
- 	}
 
- 	/* Connection established */
 
- 	printf("%10.0f - Connected\n", difftime(time(NULL), pclient_data->started));
 
- 	/* If there are greetings to send, do it now */
 
- 	if (greetings) {
 
- 		printf("%10.0f - Sending greetings\n",
 
- 		       difftime(time(NULL), pclient_data->started));
 
- 		mg_websocket_client_write(client_conn,
 
- 		                          MG_WEBSOCKET_OPCODE_TEXT,
 
- 		                          greetings,
 
- 		                          strlen(greetings));
 
- 	}
 
- 	/* Wait for some seconds */
 
- 	sleep(5);
 
- 	/* Does the server play "ping pong" ? */
 
- 	for (i = 0; i < 5; i++) {
 
- 		/* Send a PING message every 5 seconds. */
 
- 		printf("%10.0f - Sending PING\n",
 
- 		       difftime(time(NULL), pclient_data->started));
 
- 		mg_websocket_client_write(client_conn,
 
- 		                          MG_WEBSOCKET_OPCODE_PING,
 
- 		                          (const char *)&i,
 
- 		                          sizeof(int));
 
- 		sleep(5);
 
- 	}
 
- 	/* Wait a while */
 
- 	/* If we do not use "ping pong", the server will probably
 
- 	 * close the connection with a timeout earlier. */
 
- 	sleep(150);
 
- 	/* Send greetings again */
 
- 	if (greetings) {
 
- 		printf("%10.0f - Sending greetings again\n",
 
- 		       difftime(time(NULL), pclient_data->started));
 
- 		mg_websocket_client_write(client_conn,
 
- 		                          MG_WEBSOCKET_OPCODE_TEXT,
 
- 		                          greetings,
 
- 		                          strlen(greetings));
 
- 	}
 
- 	/* Wait for some seconds */
 
- 	sleep(5);
 
- 	/* Send some "song text": http://www.99-bottles-of-beer.net/ */
 
- 	{
 
- 		char txt[128];
 
- 		int b = 99; /* start with 99 bottles */
 
- 		while (b > 0) {
 
- 			/* Send "b bottles" text line. */
 
- 			sprintf(txt,
 
- 			        "%i bottle%s of beer on the wall, "
 
- 			        "%i bottle%s of beer.",
 
- 			        b,
 
- 			        ((b != 1) ? "s" : ""),
 
- 			        b,
 
- 			        ((b != 1) ? "s" : ""));
 
- 			mg_websocket_client_write(client_conn,
 
- 			                          MG_WEBSOCKET_OPCODE_TEXT,
 
- 			                          txt,
 
- 			                          strlen(txt));
 
- 			/* Take a breath. */
 
- 			sleep(1);
 
- 			/* Drink a bottle */
 
- 			b--;
 
- 			/* Send "remaining bottles" text line. */
 
- 			if (b) {
 
- 				sprintf(txt,
 
- 				        "Take one down and pass it around, "
 
- 				        "%i bottle%s of beer on the wall.",
 
- 				        b,
 
- 				        ((b != 1) ? "s" : ""));
 
- 			} else {
 
- 				strcpy(txt,
 
- 				       "Take one down and pass it around, "
 
- 				       "no more bottles of beer on the wall.");
 
- 			}
 
- 			mg_websocket_client_write(client_conn,
 
- 			                          MG_WEBSOCKET_OPCODE_TEXT,
 
- 			                          txt,
 
- 			                          strlen(txt));
 
- 			/* Take a breath. */
 
- 			sleep(2);
 
- 		}
 
- 		/* Send "no more bottles" text line. */
 
- 		strcpy(txt,
 
- 		       "No more bottles of beer on the wall, "
 
- 		       "no more bottles of beer.");
 
- 		mg_websocket_client_write(client_conn,
 
- 		                          MG_WEBSOCKET_OPCODE_TEXT,
 
- 		                          txt,
 
- 		                          strlen(txt));
 
- 		/* Take a breath. */
 
- 		sleep(1);
 
- 		/* Buy new bottles. */
 
- 		b = 99;
 
- 		/* Send "buy some more" text line. */
 
- 		sprintf(txt,
 
- 		        "Go to the store and buy some more, "
 
- 		        "%i bottle%s of beer on the wall.",
 
- 		        b,
 
- 		        ((b != 1) ? "s" : ""));
 
- 		mg_websocket_client_write(client_conn,
 
- 		                          MG_WEBSOCKET_OPCODE_TEXT,
 
- 		                          txt,
 
- 		                          strlen(txt));
 
- 	}
 
- 	/* Wait for some seconds */
 
- 	sleep(5);
 
- 	/* Somewhat boring conversation, isn't it?
 
- 	 * Tell the server we have to leave. */
 
- 	printf("%10.0f - Sending close message\n",
 
- 	       difftime(time(NULL), pclient_data->started));
 
- 	mg_websocket_client_write(client_conn,
 
- 	                          MG_WEBSOCKET_OPCODE_CONNECTION_CLOSE,
 
- 	                          NULL,
 
- 	                          0);
 
- 	/* We don't need to wait, this is just to have the log timestamp
 
- 	 * a second later, and to not log from the handlers and from
 
- 	 * here the same time (printf to stdout is not thread-safe, but
 
- 	 * adding flock or mutex or an explicit logging function makes
 
- 	 * this example unnecessarily complex). */
 
- 	sleep(5);
 
- 	/* Connection should be closed by now. */
 
- 	printf("%10.0f - Connection state: %s\n",
 
- 	       difftime(time(NULL), pclient_data->started),
 
- 	       ((pclient_data->closed == 0) ? "open" : "closed"));
 
- 	/* Close client connection */
 
- 	mg_close_connection(client_conn);
 
- 	printf("%10.0f - End of test\n",
 
- 	       difftime(time(NULL), pclient_data->started));
 
- 	/* Print collected data */
 
- 	printf("\n\nPrint all text messages from server again:\n");
 
- 	{
 
- 		struct tmsg_list_elem **where = &(pclient_data->msgs);
 
- 		while (*where != NULL) {
 
- 			printf("%10.0f - [%5lu] ",
 
- 			       difftime((*where)->timestamp, pclient_data->started),
 
- 			       (unsigned long)(*where)->len);
 
- 			fwrite((const char *)(*where)->data, 1, (*where)->len, stdout);
 
- 			printf("\n");
 
- 			where = &((*where)->next);
 
- 		}
 
- 	}
 
- 	/* Free collected data */
 
- 	{
 
- 		struct tmsg_list_elem **where = &(pclient_data->msgs);
 
- 		void *p1 = 0;
 
- 		void *p2 = 0;
 
- 		while (*where != NULL) {
 
- 			free((*where)->data);
 
- 			free(p2);
 
- 			p2 = p1;
 
- 			p1 = *where;
 
- 			where = &((*where)->next);
 
- 		}
 
- 		free(p2);
 
- 		free(p1);
 
- 	}
 
- 	free(pclient_data);
 
- }
 
- /* main will initialize the CivetWeb library
 
-  * and start the WebSocket client test function */
 
- int
 
- main(int argc, char *argv[])
 
- {
 
- 	const char *greetings = "Hello World!";
 
- 	const char *host = "echo.websocket.org";
 
- 	const char *path = "/";
 
- #if defined(NO_SSL)
 
- 	const int port = 80;
 
- 	const int secure = 0;
 
- 	mg_init_library(0);
 
- #else
 
- 	const int port = 443;
 
- 	const int secure = 1;
 
- 	mg_init_library(MG_FEATURES_SSL);
 
- #endif
 
- 	run_websocket_client(host, port, secure, path, greetings);
 
- }
 
 
  |