Skip to content

Commit c1ccece

Browse files
committed
WebSocket and HTTP server examples with TLS
1 parent a346fce commit c1ccece

File tree

6 files changed

+146
-76
lines changed

6 files changed

+146
-76
lines changed

examples/http-server.c

Lines changed: 107 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
/*!
2-
* @file libxutils/examples/events.c
2+
* @file libxutils/examples/http-server.c
33
*
44
* This source is part of "libxutils" project
55
* 2015-2020 Sun Dro (f4tb0y@protonmail.com)
66
*
7-
* @brief Implementation of high performance event based non-blocking HTTP server.
8-
* The xUtils library will use poll() or epoll() depending on the operating system.
7+
* @brief Implementation of high performance event based non-blocking HTTP/S server.
8+
* The library will use poll(), epoll() or WSAPoll() depending on the operating system.
99
*/
1010

1111
#include <xutils/xstd.h>
@@ -15,6 +15,16 @@
1515
#include <xutils/api.h>
1616

1717
static int g_nInterrupted = 0;
18+
extern char *optarg;
19+
20+
typedef struct {
21+
char sCaPath[XPATH_MAX];
22+
char sCertPath[XPATH_MAX];
23+
char sKeyPath[XPATH_MAX];
24+
char sAddr[XSOCK_ADDR_MAX];
25+
uint16_t nPort;
26+
xbool_t bSSL;
27+
} xhttps_args_t;
1828

1929
void signal_callback(int sig)
2030
{
@@ -49,7 +59,7 @@ int handle_request(xapi_ctx_t *pCtx, xapi_data_t *pData)
4959
free(pHeader);
5060
}
5161

52-
return XAPI_SetEvents(pData, XPOLLOUT);
62+
return XAPI_EnableEvent(pData, XPOLLOUT);
5363
}
5464

5565
int write_data(xapi_ctx_t *pCtx, xapi_data_t *pData)
@@ -123,6 +133,83 @@ int service_callback(xapi_ctx_t *pCtx, xapi_data_t *pData)
123133
return XSTDOK;
124134
}
125135

136+
void display_usage(const char *pName)
137+
{
138+
printf("============================================================\n");
139+
printf(" HTTP/S server example - xUtils: %s\n", XUtils_Version());
140+
printf("============================================================\n");
141+
printf("Usage: %s [options]\n\n", pName);
142+
printf("Options are:\n");
143+
printf(" -a <addr> # Listener address (%s*%s)\n", XSTR_CLR_RED, XSTR_FMT_RESET);
144+
printf(" -p <port> # Listener port (%s*%s)\n", XSTR_CLR_RED, XSTR_FMT_RESET);
145+
printf(" -c <path> # SSL Cert file path\n");
146+
printf(" -k <path> # SSL Key file path\n");
147+
printf(" -r <path> # SSL CA file path\n");
148+
printf(" -s # SSL (WSS) mode\n");
149+
printf(" -h # Version and usage\n\n");
150+
}
151+
152+
xbool_t parse_args(xhttps_args_t *pArgs, int argc, char *argv[])
153+
{
154+
pArgs->sCertPath[0] = XSTR_NUL;
155+
pArgs->sKeyPath[0] = XSTR_NUL;
156+
pArgs->sCaPath[0] = XSTR_NUL;
157+
pArgs->sAddr[0] = XSTR_NUL;
158+
pArgs->nPort = XSTDNON;
159+
pArgs->bSSL = XFALSE;
160+
int nChar = XSTDNON;
161+
162+
while ((nChar = getopt(argc, argv, "a:p:c:k:r:s1:h1")) != -1)
163+
{
164+
switch (nChar)
165+
{
166+
case 'a':
167+
xstrncpy(pArgs->sAddr, sizeof(pArgs->sAddr), optarg);
168+
break;
169+
case 'c':
170+
xstrncpy(pArgs->sCertPath, sizeof(pArgs->sCertPath), optarg);
171+
break;
172+
case 'k':
173+
xstrncpy(pArgs->sKeyPath, sizeof(pArgs->sKeyPath), optarg);
174+
break;
175+
case 'r':
176+
xstrncpy(pArgs->sCaPath, sizeof(pArgs->sCaPath), optarg);
177+
break;
178+
case 'p':
179+
pArgs->nPort = atoi(optarg);
180+
break;
181+
case 's':
182+
pArgs->bSSL = XTRUE;
183+
break;
184+
case 'h':
185+
default:
186+
return XFALSE;
187+
}
188+
}
189+
190+
if (!xstrused(pArgs->sAddr))
191+
{
192+
xloge("Missing listener addr");
193+
return XFALSE;
194+
}
195+
196+
if (!pArgs->nPort)
197+
{
198+
xloge("Missing listener port");
199+
return XFALSE;
200+
}
201+
202+
if (pArgs->bSSL &&
203+
(!xstrused(pArgs->sCertPath) ||
204+
!xstrused(pArgs->sKeyPath)))
205+
{
206+
xloge("Missing SSL cert or key path");
207+
return XFALSE;
208+
}
209+
210+
return XTRUE;
211+
}
212+
126213
int main(int argc, char* argv[])
127214
{
128215
xlog_defaults();
@@ -135,21 +222,31 @@ int main(int argc, char* argv[])
135222
nSignals[1] = SIGINT;
136223
XSig_Register(nSignals, 2, signal_callback);
137224

138-
if (argc < 2)
225+
xhttps_args_t args;
226+
if (!parse_args(&args, argc, argv))
139227
{
140-
xlog("Usage: %s [address] [port]", argv[0]);
141-
xlog("Example: %s 127.0.0.1 6969", argv[0]);
142-
return 1;
228+
display_usage(argv[0]);
229+
return XSTDERR;
143230
}
144231

145232
xapi_t api;
146233
XAPI_Init(&api, service_callback, &api, XSTDNON);
147234

148235
xapi_endpoint_t endpt;
149236
XAPI_InitEndpoint(&endpt);
237+
150238
endpt.eType = XAPI_HTTP;
151-
endpt.pAddr = argv[1];
152-
endpt.nPort = atoi(argv[2]);
239+
endpt.pAddr = args.sAddr;
240+
endpt.nPort = args.nPort;
241+
endpt.bTLS = args.bSSL;
242+
243+
if (endpt.bTLS)
244+
{
245+
endpt.certs.pCaPath = args.sCaPath;
246+
endpt.certs.pKeyPath = args.sKeyPath;
247+
endpt.certs.pCertPath = args.sCertPath;
248+
endpt.certs.nVerifyFlags = SSL_VERIFY_PEER;
249+
}
153250

154251
if (XAPI_Listen(&api, &endpt) < 0)
155252
{

examples/ws-client.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* This source is part of "libxutils" project
55
* 2015-2023 Sun Dro (f4tb0y@protonmail.com)
66
*
7-
* @brief Implementation of high performance event based non-blocking Web Socket client.
7+
* @brief Implementation of high performance event based non-blocking WebSocket/TLS client.
88
* The library will use poll(), WSAPoll(), or epoll() depending on the operating system.
99
*/
1010

examples/ws-server.c

Lines changed: 21 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* This source is part of "libxutils" project
55
* 2015-2023 Sun Dro (f4tb0y@protonmail.com)
66
*
7-
* @brief Implementation of high performance event based non-blocking Web Socket server.
7+
* @brief Implementation of high performance event based non-blocking WS/WSS echo server.
88
* The library will use poll(), WSAPoll(), or epoll() depending on the operating system.
99
*/
1010

@@ -106,6 +106,7 @@ int handshake_answer(xapi_ctx_t *pCtx, xapi_data_t *pData)
106106

107107
int send_pong(xapi_data_t *pData)
108108
{
109+
session_data_t *pSession = (session_data_t*)pData->pSessionData;
109110
xws_status_t status;
110111
xws_frame_t frame;
111112

@@ -124,16 +125,17 @@ int send_pong(xapi_data_t *pData)
124125
XAPI_PutTxBuff(pData, &frame.buffer);
125126
XWebFrame_Clear(&frame);
126127

128+
pSession->nTxCount++;
127129
return XAPI_EnableEvent(pData, XPOLLOUT);
128130
}
129131

130-
int send_response(xapi_data_t *pData, const char *pPayload, size_t nLength)
132+
int send_response(xapi_data_t *pData, const uint8_t *pPayload, size_t nLength)
131133
{
132134
session_data_t *pSession = (session_data_t*)pData->pSessionData;
133135
xws_status_t status;
134136
xws_frame_t frame;
135137

136-
status = XWebFrame_Create(&frame, (uint8_t*)pPayload, nLength, XWS_TEXT, XTRUE);
138+
status = XWebFrame_Create(&frame, pPayload, nLength, XWS_TEXT, XTRUE);
137139
if (status != XWS_ERR_NONE)
138140
{
139141
xloge("Failed to create WS frame: %s",
@@ -145,8 +147,6 @@ int send_response(xapi_data_t *pData, const char *pPayload, size_t nLength)
145147
xlogn("Sending response: fd(%d), buff(%zu)",
146148
(int)pData->sock.nFD, frame.buffer.nUsed);
147149

148-
xlogn("Response payload: %s", pPayload);
149-
150150
XAPI_PutTxBuff(pData, &frame.buffer);
151151
XWebFrame_Clear(&frame);
152152

@@ -158,50 +158,24 @@ int handle_frame(xapi_ctx_t *pCtx, xapi_data_t *pData)
158158
{
159159
xws_frame_t *pFrame = (xws_frame_t*)pData->pPacket;
160160
session_data_t *pSession = (session_data_t*)pData->pSessionData;
161+
pSession->nRxCount++;
161162

162163
xlogn("Received WS frame: fd(%d), type(%s), fin(%s), hdr(%zu), pl(%zu), buff(%zu)",
163164
(int)pData->sock.nFD, XWS_FrameTypeStr(pFrame->eType), pFrame->bFin?"true":"false",
164165
pFrame->nHeaderSize, pFrame->nPayloadLength, pFrame->buffer.nUsed);
165166

166-
if (pFrame->eType == XWS_CLOSE)
167-
{
168-
xlogd("Received CLOSE frame");
169-
return XSTDERR;
170-
}
171-
else if (pFrame->eType == XWS_PING)
172-
{
173-
pSession->nRxCount++;
174-
pSession->nTxCount++;
175-
return send_pong(pData);
176-
}
177-
else if (pFrame->eType != XWS_TEXT)
178-
{
179-
char sPayload[XSTR_MIN];
167+
if (pFrame->eType == XWS_PING) return send_pong(pData);
168+
else if (pFrame->eType == XWS_CLOSE) return XSTDERR;
180169

181-
size_t nLength = xstrncpyf(
182-
sPayload, sizeof(sPayload),
183-
"{\"error\":\"unsupported type\"}");
184-
185-
return send_response(pData, sPayload, nLength);
186-
}
187-
188-
/* Received close request, we should destroy this session */
189-
const char* pPayload = (const char*)XWebFrame_GetPayload(pFrame);
190-
if (xstrused(pPayload)) xlogn("WS frame payload: %s", pPayload);
191-
192-
pSession->nRxCount++;
193-
return XAPI_EnableEvent(pData, XPOLLOUT);
194-
}
195-
196-
int send_answer(xapi_ctx_t *pCtx, xapi_data_t *pData)
197-
{
198-
char sPayload[XSTR_MIN];
170+
const uint8_t *pPayload = XWebFrame_GetPayload(pFrame);
171+
size_t nLength = XWebFrame_GetPayloadLength(pFrame);
172+
XASSERT_RET((pPayload != NULL && nLength), XSTDOK);
199173

200-
size_t nLength = xstrncpyf(
201-
sPayload, sizeof(sPayload),
202-
"{\"message\":\"here is your response\"}");
174+
if (pFrame->eType == XWS_TEXT && xstrused((const char*)pPayload))
175+
xlogn("Payload (%zu bytes): %s", nLength, (const char*)pPayload);
203176

204-
return send_response(pData, sPayload, nLength);
177+
/* Send payload back to the client (echo) */
178+
return send_response(pData, pPayload, nLength);
205179
}
206180

207181
int init_session(xapi_ctx_t *pCtx, xapi_data_t *pData)
@@ -243,8 +217,6 @@ int service_callback(xapi_ctx_t *pCtx, xapi_data_t *pData)
243217
return destroy_session(pCtx, pData);
244218
case XAPI_CB_READ:
245219
return handle_frame(pCtx, pData);
246-
case XAPI_CB_WRITE:
247-
return send_answer(pCtx, pData);
248220
case XAPI_CB_ERROR:
249221
return print_error(pCtx, pData);
250222
case XAPI_CB_STATUS:
@@ -272,11 +244,11 @@ void display_usage(const char *pName)
272244
printf("============================================================\n");
273245
printf("Usage: %s [options]\n\n", pName);
274246
printf("Options are:\n");
275-
printf(" -a <path> # Listener address (%s*%s)\n", XSTR_CLR_RED, XSTR_FMT_RESET);
276-
printf(" -p <path> # Listener port (%s*%s)\n", XSTR_CLR_RED, XSTR_FMT_RESET);
277-
printf(" -c <format> # SSL Cert file path\n");
278-
printf(" -k <format> # SSL Key file path\n");
279-
printf(" -r <format> # SSL CA file path\n");
247+
printf(" -a <addr> # Listener address (%s*%s)\n", XSTR_CLR_RED, XSTR_FMT_RESET);
248+
printf(" -p <port> # Listener port (%s*%s)\n", XSTR_CLR_RED, XSTR_FMT_RESET);
249+
printf(" -c <path> # SSL Cert file path\n");
250+
printf(" -k <path> # SSL Key file path\n");
251+
printf(" -r <path> # SSL CA file path\n");
280252
printf(" -s # SSL (WSS) mode\n");
281253
printf(" -h # Version and usage\n\n");
282254
}
@@ -377,7 +349,7 @@ int main(int argc, char* argv[])
377349
endpt.certs.pCaPath = args.sCaPath;
378350
endpt.certs.pKeyPath = args.sKeyPath;
379351
endpt.certs.pCertPath = args.sCertPath;
380-
endpt.certs.nVerifyFlags = SSL_VERIFY_NONE;
352+
endpt.certs.nVerifyFlags = SSL_VERIFY_PEER;
381353
}
382354

383355
if (XAPI_Listen(&api, &endpt) < 0)

src/net/ws.c

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ uint8_t XWS_OpCode(xws_frame_type_t eType)
139139
return 0;
140140
}
141141

142-
uint8_t* XWS_CreateFrame(uint8_t *pPayload, size_t nLength, uint8_t nOpCode, xbool_t bFin, size_t *pFrameSize)
142+
uint8_t* XWS_CreateFrame(const uint8_t *pPayload, size_t nLength, uint8_t nOpCode, xbool_t bFin, size_t *pFrameSize)
143143
{
144144
if (pFrameSize != NULL) *pFrameSize = 0;
145145
uint8_t nFIN = bFin ? XSTDOK : XSTDNON;
@@ -235,7 +235,7 @@ void XWebFrame_Free(xws_frame_t **pFrame)
235235
}
236236
}
237237

238-
xws_status_t XWebFrame_Create(xws_frame_t *pFrame, uint8_t *pPayload, size_t nLength, xws_frame_type_t eType, xbool_t bFin)
238+
xws_status_t XWebFrame_Create(xws_frame_t *pFrame, const uint8_t *pPayload, size_t nLength, xws_frame_type_t eType, xbool_t bFin)
239239
{
240240
XASSERT(pFrame, XWS_INVALID_ARGS);
241241
XASSERT((pPayload || !nLength), XWS_INVALID_ARGS);
@@ -278,7 +278,7 @@ xws_frame_t* XWebFrame_Alloc(xws_frame_type_t eType, size_t nBuffSize)
278278
return pFrame;
279279
}
280280

281-
xws_frame_t* XWebFrame_New(uint8_t *pPayload, size_t nLength, xws_frame_type_t eType, xbool_t bFin)
281+
xws_frame_t* XWebFrame_New(const uint8_t *pPayload, size_t nLength, xws_frame_type_t eType, xbool_t bFin)
282282
{
283283
xws_frame_t *pFrame = XWebFrame_Alloc(eType, XSTDNON);
284284
XASSERT((pFrame != NULL), NULL);
@@ -313,10 +313,19 @@ const uint8_t* XWebFrame_GetPayload(xws_frame_t *pFrame)
313313
return pFrame->buffer.pData + pFrame->nHeaderSize;
314314
}
315315

316+
size_t XWebFrame_GetExtraLength(xws_frame_t *pFrame)
317+
{
318+
size_t nFrameSize = XWebFrame_GetFrameLength(pFrame);
319+
XASSERT_RET((nFrameSize && pFrame->bComplete), XSTDNON);
320+
XASSERT_RET((nFrameSize > pFrame->buffer.nUsed), XSTDNON);
321+
return pFrame->buffer.nUsed - nFrameSize;
322+
}
323+
316324
size_t XWebFrame_GetPayloadLength(xws_frame_t *pFrame)
317325
{
318326
XASSERT_RET(XWebFrame_CheckPayload(pFrame), XSTDNON);
319-
return pFrame->buffer.nUsed - pFrame->nHeaderSize;
327+
size_t nExtra = XWebFrame_GetExtraLength(pFrame);
328+
return pFrame->buffer.nUsed - pFrame->nHeaderSize - nExtra;
320329
}
321330

322331
size_t XWebFrame_GetFrameLength(xws_frame_t *pFrame)
@@ -333,14 +342,6 @@ size_t XWebFrame_GetFrameLength(xws_frame_t *pFrame)
333342
return nFrameSize;
334343
}
335344

336-
size_t XWebFrame_GetExtraLength(xws_frame_t *pFrame)
337-
{
338-
size_t nFrameSize = XWebFrame_GetFrameLength(pFrame);
339-
XASSERT_RET((nFrameSize && pFrame->bComplete), XSTDNON);
340-
XASSERT_RET((nFrameSize > pFrame->buffer.nUsed), XSTDNON);
341-
return pFrame->buffer.nUsed - nFrameSize;
342-
}
343-
344345
XSTATUS XWebFrame_CutExtraData(xws_frame_t *pFrame)
345346
{
346347
size_t nExtraLength = XWebFrame_GetExtraLength(pFrame);

src/net/ws.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,11 +87,11 @@ void XWebFrame_Free(xws_frame_t **pFrame);
8787
void XWebFrame_Clear(xws_frame_t *pFrame);
8888
void XWebFrame_Reset(xws_frame_t *pFrame);
8989

90-
uint8_t* XWS_CreateFrame(uint8_t *pPayload, size_t nLength, uint8_t nOpCode, xbool_t bFin, size_t *pFrameSize);
91-
xws_frame_t* XWebFrame_New(uint8_t *pPayload, size_t nLength, xws_frame_type_t eType, xbool_t bFin);
90+
uint8_t* XWS_CreateFrame(const uint8_t *pPayload, size_t nLength, uint8_t nOpCode, xbool_t bFin, size_t *pFrameSize);
91+
xws_frame_t* XWebFrame_New(const uint8_t *pPayload, size_t nLength, xws_frame_type_t eType, xbool_t bFin);
9292
xws_frame_t* XWebFrame_Alloc(xws_frame_type_t eType, size_t nBuffSize);
9393

94-
xws_status_t XWebFrame_Create(xws_frame_t *pFrame, uint8_t *pPayload, size_t nLength, xws_frame_type_t eType, xbool_t bFin);
94+
xws_status_t XWebFrame_Create(xws_frame_t *pFrame, const uint8_t *pPayload, size_t nLength, xws_frame_type_t eType, xbool_t bFin);
9595
xws_status_t XWebFrame_AppendData(xws_frame_t *pFrame, uint8_t* pData, size_t nSize);
9696
xws_status_t XWebFrame_ParseData(xws_frame_t *pFrame, uint8_t* pData, size_t nSize);
9797
xws_status_t XWebFrame_TryParse(xws_frame_t *pFrame, uint8_t* pData, size_t nSize);

0 commit comments

Comments
 (0)