blob: bfc3c857571086c7d48ffb20846a419ed1b508fc [file] [log] [blame]
Andy Greena0da8a82010-11-08 17:12:19 +00001/*
2 * libwebsockets-test-server - libwebsockets test implementation
3 *
4 * Copyright (C) 2010 Andy Green <andy@warmcat.com>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation:
9 * version 2.1 of the License.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 * MA 02110-1301 USA
20 */
21
Andy Green775c0dd2010-10-29 14:15:22 +010022#include <stdio.h>
23#include <stdlib.h>
24#include <unistd.h>
Andy Greenea71ed12010-10-31 07:40:33 +000025#include <getopt.h>
Andy Green5fd8a5e2010-10-31 11:57:17 +000026#include <string.h>
27
Andy Green7310e9c2010-11-01 09:12:17 +000028#include "../lib/libwebsockets.h"
Andy Green775c0dd2010-10-29 14:15:22 +010029
Andy Green3138e442010-11-01 09:20:48 +000030#define LOCAL_RESOURCE_PATH "/usr/share/libwebsockets-test-server"
Andy Greenea71ed12010-10-31 07:40:33 +000031static int port = 7681;
32static int ws_protocol = 76;
Andy Green3faa9c72010-11-08 17:03:03 +000033static int use_ssl = 0;
Andy Green775c0dd2010-10-29 14:15:22 +010034
Andy Green251f6fa2010-11-03 11:13:06 +000035struct per_session_data {
36 int number;
37};
38
Andy Green05a0a7b2010-10-31 17:51:39 +000039 /**
40 * libwebsocket_callback() - User server actions
41 * @wsi: Opaque websocket instance pointer
42 * @reason: The reason for the call
Andy Green251f6fa2010-11-03 11:13:06 +000043 * @user: Pointer to per-session user data allocated by library
Andy Green05a0a7b2010-10-31 17:51:39 +000044 * @in: Pointer used for some callback reasons
45 * @len: Length set for some callback reasons
Andy Greenab990e42010-10-31 12:42:52 +000046 *
Andy Green05a0a7b2010-10-31 17:51:39 +000047 * This callback is the way the user controls what is served. All the
48 * protocol detail is hidden and handled by the library.
49 *
Andy Green251f6fa2010-11-03 11:13:06 +000050 * For each connection / session there is user data allocated that is
51 * pointed to by "user". You set the size of this user data area when
52 * the library is initialized with libwebsocket_create_server.
53 *
54 * You get an opportunity to initialize user data when called back with
55 * LWS_CALLBACK_ESTABLISHED reason.
56 *
Andy Green05a0a7b2010-10-31 17:51:39 +000057 * LWS_CALLBACK_ESTABLISHED: after successful websocket handshake
Andy Greena2b0ab02010-11-11 12:28:29 +000058 *
Andy Green05a0a7b2010-10-31 17:51:39 +000059 * LWS_CALLBACK_CLOSED: when the websocket session ends
Andy Greena2b0ab02010-11-11 12:28:29 +000060 *
Andy Green05a0a7b2010-10-31 17:51:39 +000061 * LWS_CALLBACK_SEND: opportunity to send to client (you would use
62 * libwebsocket_write() taking care about the
63 * special buffer requirements
64 * LWS_CALLBACK_RECEIVE: data has appeared for the server, it can be
Andy Greena2b0ab02010-11-11 12:28:29 +000065 * found at *in and is len bytes long
66 *
67 * LWS_CALLBACK_HTTP: an http request has come from a client that is not
Andy Green05a0a7b2010-10-31 17:51:39 +000068 * asking to upgrade the connection to a websocket
69 * one. This is a chance to serve http content,
70 * for example, to send a script to the client
71 * which will then open the websockets connection.
Andy Greena2b0ab02010-11-11 12:28:29 +000072 * @in points to the URI path requested and
Andy Green05a0a7b2010-10-31 17:51:39 +000073 * libwebsockets_serve_http_file() makes it very
74 * simple to send back a file to the client.
Andy Greena2b0ab02010-11-11 12:28:29 +000075 *
76 * LWS_CALLBACK_PROTOCOL_FILTER: before the confirmation handshake is sent
77 * the user callback is given a chance to confirm
78 * it's OK with the protocol that was requested
79 * from the client. The protocol string (which
80 * may be NULL if no protocol header was sent)
81 * can be found at parameter @in. Return 0 from
82 * the callback to allow the connection or nonzero
83 * to abort the connection.
Andy Greenab990e42010-10-31 12:42:52 +000084 */
85
Andy Green4ea60062010-10-30 12:15:07 +010086static int websocket_callback(struct libwebsocket * wsi,
Andy Green251f6fa2010-11-03 11:13:06 +000087 enum libwebsocket_callback_reasons reason, void * user,
88 void *in, size_t len)
Andy Green775c0dd2010-10-29 14:15:22 +010089{
90 int n;
Andy Greenab990e42010-10-31 12:42:52 +000091 char buf[LWS_SEND_BUFFER_PRE_PADDING + 512 +
92 LWS_SEND_BUFFER_POST_PADDING];
Andy Green5fd8a5e2010-10-31 11:57:17 +000093 char *p = &buf[LWS_SEND_BUFFER_PRE_PADDING];
Andy Green251f6fa2010-11-03 11:13:06 +000094 struct per_session_data * pss = user;
Andy Green775c0dd2010-10-29 14:15:22 +010095
96 switch (reason) {
Andy Greenab990e42010-10-31 12:42:52 +000097 /*
98 * Websockets session handshake completed and is established
99 */
Andy Green775c0dd2010-10-29 14:15:22 +0100100 case LWS_CALLBACK_ESTABLISHED:
101 fprintf(stderr, "Websocket connection established\n");
Andy Green251f6fa2010-11-03 11:13:06 +0000102 pss->number = 0;
Andy Green775c0dd2010-10-29 14:15:22 +0100103 break;
104
Andy Greenab990e42010-10-31 12:42:52 +0000105 /*
106 * Websockets session is closed
107 */
Andy Green775c0dd2010-10-29 14:15:22 +0100108 case LWS_CALLBACK_CLOSED:
109 fprintf(stderr, "Websocket connection closed\n");
110 break;
111
Andy Greenab990e42010-10-31 12:42:52 +0000112 /*
113 * Opportunity for us to send something on the connection
114 */
Andy Green775c0dd2010-10-29 14:15:22 +0100115 case LWS_CALLBACK_SEND:
Andy Green251f6fa2010-11-03 11:13:06 +0000116 n = sprintf(p, "%d", pss->number++);
Andy Green7c212cc2010-11-08 20:20:42 +0000117 n = libwebsocket_write(wsi, (unsigned char *)p, n,
118 LWS_WRITE_TEXT);
Andy Green775c0dd2010-10-29 14:15:22 +0100119 if (n < 0) {
120 fprintf(stderr, "ERROR writing to socket");
121 exit(1);
122 }
123 break;
Andy Greenab990e42010-10-31 12:42:52 +0000124 /*
125 * Something has arrived for us on the connection, it's len bytes long
126 * and is available at *in
127 */
Andy Green775c0dd2010-10-29 14:15:22 +0100128 case LWS_CALLBACK_RECEIVE:
Andy Green4ea60062010-10-30 12:15:07 +0100129 fprintf(stderr, "Received %d bytes payload\n", (int)len);
Andy Green775c0dd2010-10-29 14:15:22 +0100130 break;
Andy Greenab990e42010-10-31 12:42:52 +0000131
132 /*
133 * The client has asked us for something in normal HTTP mode,
134 * not websockets mode. Normally it means we want to send
135 * our script / html to the client, and when that script runs
136 * it will start up separate websocket connections.
137 *
138 * Interpret the URI string to figure out what is needed to send
139 */
140
Andy Green5fd8a5e2010-10-31 11:57:17 +0000141 case LWS_CALLBACK_HTTP:
Andy Greenab990e42010-10-31 12:42:52 +0000142
Andy Greena2b0ab02010-11-11 12:28:29 +0000143 fprintf(stderr, "serving HTTP URI %s\n", in);
Andy Green3faa9c72010-11-08 17:03:03 +0000144
Andy Greena2b0ab02010-11-11 12:28:29 +0000145 if (in && strcmp(in, "/favicon.ico") == 0) {
Andy Green3138e442010-11-01 09:20:48 +0000146 if (libwebsockets_serve_http_file(wsi,
147 LOCAL_RESOURCE_PATH"/favicon.ico", "image/x-icon"))
Andy Greenab990e42010-10-31 12:42:52 +0000148 fprintf(stderr, "Failed to send favicon\n");
Andy Green5fd8a5e2010-10-31 11:57:17 +0000149 break;
150 }
151
152 /* send the script... when it runs it'll start websockets */
153
Andy Green3138e442010-11-01 09:20:48 +0000154 if (libwebsockets_serve_http_file(wsi,
155 LOCAL_RESOURCE_PATH"/test.html", "text/html"))
Andy Green5fd8a5e2010-10-31 11:57:17 +0000156 fprintf(stderr, "Failed to send HTTP file\n");
Andy Green5fd8a5e2010-10-31 11:57:17 +0000157 break;
Andy Greena2b0ab02010-11-11 12:28:29 +0000158
159 /*
160 * This is our chance to choose if we support one of the requested
161 * protocols or not. in points to the protocol string. Nonzero return
162 * aborts the connection handshake
163 */
164
165 case LWS_CALLBACK_PROTOCOL_FILTER:
166 if (in == NULL) {
167 fprintf(stderr, "Client did not request protocol\n");
168 /* accept it */
169 return 0;
170 }
171 fprintf(stderr, "Client requested protocol '%s'\n", in);
172 /* accept it */
173 return 0;
Andy Green775c0dd2010-10-29 14:15:22 +0100174 }
Andy Greenab990e42010-10-31 12:42:52 +0000175
Andy Green775c0dd2010-10-29 14:15:22 +0100176 return 0;
177}
178
Andy Greenea71ed12010-10-31 07:40:33 +0000179static struct option options[] = {
180 { "help", no_argument, NULL, 'h' },
181 { "port", required_argument, NULL, 'p' },
182 { "protocol", required_argument, NULL, 'r' },
Andy Green3faa9c72010-11-08 17:03:03 +0000183 { "ssl", no_argument, NULL, 's' },
Andy Greenea71ed12010-10-31 07:40:33 +0000184 { NULL, 0, 0, 0 }
185};
Andy Green775c0dd2010-10-29 14:15:22 +0100186
Andy Greenea71ed12010-10-31 07:40:33 +0000187int main(int argc, char **argv)
Andy Green775c0dd2010-10-29 14:15:22 +0100188{
Andy Greenea71ed12010-10-31 07:40:33 +0000189 int n = 0;
Andy Green7c212cc2010-11-08 20:20:42 +0000190 const char * cert_path =
191 LOCAL_RESOURCE_PATH"/libwebsockets-test-server.pem";
192 const char * key_path =
193 LOCAL_RESOURCE_PATH"/libwebsockets-test-server.key.pem";
Andy Greenea71ed12010-10-31 07:40:33 +0000194
Andy Greenab990e42010-10-31 12:42:52 +0000195 fprintf(stderr, "libwebsockets test server\n"
Andy Green6452f1e2010-11-11 09:22:22 +0000196 "(C) Copyright 2010 Andy Green <andy@warmcat.com> "
197 "licensed under LGPL2.1\n");
Andy Greenea71ed12010-10-31 07:40:33 +0000198
199 while (n >= 0) {
200 n = getopt_long(argc, argv, "hp:r:", options, NULL);
201 if (n < 0)
202 continue;
203 switch (n) {
Andy Green3faa9c72010-11-08 17:03:03 +0000204 case 's':
205 use_ssl = 1;
206 break;
Andy Greenea71ed12010-10-31 07:40:33 +0000207 case 'p':
208 port = atoi(optarg);
209 break;
210 case 'r':
211 ws_protocol = atoi(optarg);
212 break;
213 case 'h':
Andy Greenab990e42010-10-31 12:42:52 +0000214 fprintf(stderr, "Usage: test-server "
215 "[--port=<p>] [--protocol=<v>]\n");
Andy Greenea71ed12010-10-31 07:40:33 +0000216 exit(1);
217 }
Andy Greenea71ed12010-10-31 07:40:33 +0000218 }
Andy Green3faa9c72010-11-08 17:03:03 +0000219
220 if (!use_ssl)
221 cert_path = key_path = NULL;
Andy Greenea71ed12010-10-31 07:40:33 +0000222
Andy Green251f6fa2010-11-03 11:13:06 +0000223 if (libwebsocket_create_server(port, websocket_callback, ws_protocol,
Andy Green3faa9c72010-11-08 17:03:03 +0000224 sizeof(struct per_session_data),
225 cert_path, key_path, -1, -1) < 0) {
Andy Green775c0dd2010-10-29 14:15:22 +0100226 fprintf(stderr, "libwebsocket init failed\n");
227 return -1;
228 }
Andy Greenab990e42010-10-31 12:42:52 +0000229
230 /* just sit there until killed */
Andy Greenea71ed12010-10-31 07:40:33 +0000231
Andy Green775c0dd2010-10-29 14:15:22 +0100232 while (1)
Andy Greenab990e42010-10-31 12:42:52 +0000233 sleep(10);
Andy Green775c0dd2010-10-29 14:15:22 +0100234
235 return 0;
236}