1717// #define PROXY_DEEP_DEBUG
1818
1919static const unsigned char b64[] = " ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" ;
20- static void base64_encode (void *dst, const void *src, size_t len) // thread-safe, re-entrant
21- {
20+ static void base64_encode (void *dst, const void *src, size_t len) { // thread-safe, re-entrant
2221 assert (dst != src);
2322 unsigned int *d = (unsigned int *)dst;
2423 const unsigned char *s = (const unsigned char *)src;
2524 const unsigned char *end = s + len;
26- while (s < end)
27- {
25+ while (s < end) {
2826 uint32_t e = *s++ << 16 ;
2927 if (s < end) e |= *s++ << 8 ;
3028 if (s < end) e |= *s++;
@@ -37,23 +35,22 @@ static void base64_encode(void *dst, const void *src, size_t len) // thread-safe
3735#define on_error (...) { fprintf (stderr, __VA_ARGS__); fflush (stderr); exit (1 ); }
3836#define MIN (a, b ) ((a) <= (b) ? (a) : (b))
3937
40- // Given a multiline string of HTTP headers, returns a pointer to the beginning of the value of given header inside the string that was passed in.
41- static int GetHttpHeader ( const char *headers, const char * header, char *out, int maxBytesOut) // thread-safe, re-entrant
42- {
38+ // Given a multiline string of HTTP headers, returns a pointer to the beginning
39+ // of the value of given header inside the string that was passed in.
40+ static int GetHttpHeader ( const char *headers, const char *header, char *out, int maxBytesOut) { // thread-safe, re-entrant
4341 const char *pos = strstr (headers, header);
4442 if (!pos) return 0 ;
4543 pos += strlen (header);
4644 const char *end = pos;
47- while (*end != ' \r ' && *end != ' \n ' && *end != ' \0 ' ) ++end;
45+ while (*end != ' \r ' && *end != ' \n ' && *end != ' \0 ' ) ++end;
4846 int numBytesToWrite = MIN ((int )(end-pos), maxBytesOut-1 );
4947 memcpy (out, pos, numBytesToWrite);
5048 out[numBytesToWrite] = ' \0 ' ;
5149 return (int )(end-pos);
5250}
5351
5452// Sends WebSocket handshake back to the given WebSocket connection.
55- void SendHandshake (int fd, const char *request)
56- {
53+ void SendHandshake (int fd, const char *request) {
5754 const char webSocketGlobalGuid[] = " 258EAFA5-E914-47DA-95CA-C5AB0DC85B11" ; // 36 characters long
5855 char key[128 +sizeof (webSocketGlobalGuid)];
5956 GetHttpHeader (request, " Sec-WebSocket-Key: " , key, sizeof (key)/2 );
@@ -77,32 +74,30 @@ void SendHandshake(int fd, const char *request)
7774 printf (" Sent handshake:\n %s\n " , handshakeMsg);
7875}
7976
80- // Validates if the given, possibly partially received WebSocket message has enough bytes to contain a full WebSocket header.
81- static bool WebSocketHasFullHeader ( uint8_t *data, uint64_t obtainedNumBytes)
82- {
77+ // Validates if the given, possibly partially received WebSocket message has
78+ // enough bytes to contain a full WebSocket header.
79+ static bool WebSocketHasFullHeader ( uint8_t *data, uint64_t obtainedNumBytes) {
8380 if (obtainedNumBytes < 2 ) return false ;
8481 uint64_t expectedNumBytes = 2 ;
8582 WebSocketMessageHeader *header = (WebSocketMessageHeader *)data;
8683 if (header->mask ) expectedNumBytes += 4 ;
87- switch (header->payloadLength )
88- {
84+ switch (header->payloadLength ) {
8985 case 127 : return expectedNumBytes += 8 ; break ;
9086 case 126 : return expectedNumBytes += 2 ; break ;
9187 default : break ;
9288 }
9389 return obtainedNumBytes >= expectedNumBytes;
9490}
9591
96- // Computes the total number of bytes that the given WebSocket message will take up.
97- uint64_t WebSocketFullMessageSize ( uint8_t *data, uint64_t obtainedNumBytes)
98- {
92+ // Computes the total number of bytes that the given WebSocket message will take
93+ // up.
94+ uint64_t WebSocketFullMessageSize ( uint8_t *data, uint64_t obtainedNumBytes) {
9995 assert (WebSocketHasFullHeader (data, obtainedNumBytes));
10096
10197 uint64_t expectedNumBytes = 2 ;
10298 WebSocketMessageHeader *header = (WebSocketMessageHeader *)data;
10399 if (header->mask ) expectedNumBytes += 4 ;
104- switch (header->payloadLength )
105- {
100+ switch (header->payloadLength ) {
106101 case 127 : return expectedNumBytes += 8 + ntoh64 (*(uint64_t *)(data+2 )); break ;
107102 case 126 : return expectedNumBytes += 2 + ntohs (*(uint16_t *)(data+2 )); break ;
108103 default : expectedNumBytes += header->payloadLength ; break ;
@@ -111,74 +106,79 @@ uint64_t WebSocketFullMessageSize(uint8_t *data, uint64_t obtainedNumBytes)
111106}
112107
113108// Tests the structure integrity of the websocket message length.
114- bool WebSocketValidateMessageSize (uint8_t *data, uint64_t obtainedNumBytes)
115- {
109+ bool WebSocketValidateMessageSize (uint8_t *data, uint64_t obtainedNumBytes) {
116110 uint64_t expectedNumBytes = WebSocketFullMessageSize (data, obtainedNumBytes);
117111
118- if (expectedNumBytes != obtainedNumBytes)
119- {
112+ if (expectedNumBytes != obtainedNumBytes) {
120113 printf (" Corrupt WebSocket message size! (got %llu bytes, expected %llu bytes)\n " , obtainedNumBytes, expectedNumBytes);
121114 printf (" Received data:" );
122- for (size_t i = 0 ; i < obtainedNumBytes; ++i)
115+ for (size_t i = 0 ; i < obtainedNumBytes; ++i)
123116 printf (" %02X" , data[i]);
124117 printf (" \n " );
125118 }
126119 return expectedNumBytes == obtainedNumBytes;
127120}
128121
129- uint64_t WebSocketMessagePayloadLength (uint8_t *data, uint64_t numBytes)
130- {
122+ uint64_t WebSocketMessagePayloadLength (uint8_t *data, uint64_t numBytes) {
131123 WebSocketMessageHeader *header = (WebSocketMessageHeader *)data;
132- switch (header->payloadLength )
133- {
124+ switch (header->payloadLength ) {
134125 case 127 : return ntoh64 (*(uint64_t *)(data+2 ));
135126 case 126 : return ntohs (*(uint16_t *)(data+2 ));
136127 default : return header->payloadLength ;
137128 }
138129}
139130
140- uint32_t WebSocketMessageMaskingKey (uint8_t *data, uint64_t numBytes)
141- {
131+ uint32_t WebSocketMessageMaskingKey (uint8_t *data, uint64_t numBytes) {
142132 WebSocketMessageHeader *header = (WebSocketMessageHeader *)data;
143133 if (!header->mask ) return 0 ;
144- switch (header->payloadLength )
145- {
134+ switch (header->payloadLength ) {
146135 case 127 : return *(uint32_t *)(data+10 );
147136 case 126 : return *(uint32_t *)(data+4 );
148137 default : return *(uint32_t *)(data+2 );
149138 }
150139}
151140
152- uint8_t *WebSocketMessageData (uint8_t *data, uint64_t numBytes)
153- {
141+ uint8_t *WebSocketMessageData (uint8_t *data, uint64_t numBytes) {
154142 WebSocketMessageHeader *header = (WebSocketMessageHeader *)data;
155143 data += 2 ; // Two bytes of fixed size header
156144 if (header->mask ) data += 4 ; // If there is a masking key present in the header, that takes up 4 bytes
157- switch (header->payloadLength )
158- {
145+ switch (header->payloadLength ) {
159146 case 127 : return data + 8 ; // 64-bit length
160147 case 126 : return data + 2 ; // 16-bit length
161148 default : return data; // 7-bit length that was embedded in fixed size header.
162149 }
163150}
164151
165- void CloseWebSocket (int client_fd)
166- {
152+ void CloseWebSocket (int client_fd) {
167153 printf (" Closing WebSocket connection %d\n " , client_fd);
168154 CloseAllSocketsByConnection (client_fd);
169155 shutdown (client_fd, SHUTDOWN_BIDIRECTIONAL);
170156 CLOSE_SOCKET (client_fd);
171157}
172158
173- const char *WebSocketOpcodeToString (int opcode)
174- {
175- static const char *opcodes[] = { " continuation frame (0x0)" , " text frame (0x1)" , " binary frame (0x2)" , " reserved(0x3)" , " reserved(0x4)" , " reserved(0x5)" ,
176- " reserved(0x6)" , " reserved(0x7)" , " connection close (0x8)" , " ping (0x9)" , " pong (0xA)" , " reserved(0xB)" , " reserved(0xC)" , " reserved(0xD)" , " reserved(0xE)" , " reserved(0xF)" };
159+ const char *WebSocketOpcodeToString (int opcode) {
160+ static const char *opcodes[] = {
161+ " continuation frame (0x0)" ,
162+ " text frame (0x1)" ,
163+ " binary frame (0x2)" ,
164+ " reserved(0x3)" ,
165+ " reserved(0x4)" ,
166+ " reserved(0x5)" ,
167+ " reserved(0x6)" ,
168+ " reserved(0x7)" ,
169+ " connection close (0x8)" ,
170+ " ping (0x9)" ,
171+ " pong (0xA)" ,
172+ " reserved(0xB)" ,
173+ " reserved(0xC)" ,
174+ " reserved(0xD)" ,
175+ " reserved(0xE)" ,
176+ " reserved(0xF)"
177+ };
177178 return opcodes[opcode];
178179}
179180
180- void DumpWebSocketMessage (uint8_t *data, uint64_t numBytes)
181- {
181+ void DumpWebSocketMessage (uint8_t *data, uint64_t numBytes) {
182182 bool goodMessageSize = WebSocketValidateMessageSize (data, numBytes);
183183 if (!goodMessageSize)
184184 return ;
@@ -189,13 +189,11 @@ void DumpWebSocketMessage(uint8_t *data, uint64_t numBytes)
189189
190190 printf (" Received: FIN: %d, opcode: %s, mask: 0x%08X, payload length: %llu bytes, unmasked payload:" , header->fin , WebSocketOpcodeToString (header->opcode ),
191191 WebSocketMessageMaskingKey (data, numBytes), payloadLength);
192- for (uint64_t i = 0 ; i < payloadLength; ++i)
193- {
192+ for (uint64_t i = 0 ; i < payloadLength; ++i) {
194193 if (i%16 == 0 ) printf (" \n " );
195194 if (i%8 ==0 ) printf (" " );
196195 printf (" %02X" , payload[i]);
197- if (i >= 63 && payloadLength > 64 )
198- {
196+ if (i >= 63 && payloadLength > 64 ) {
199197 printf (" \n ... (%llu more bytes)" , payloadLength-i);
200198 break ;
201199 }
@@ -204,36 +202,33 @@ void DumpWebSocketMessage(uint8_t *data, uint64_t numBytes)
204202}
205203
206204// connection thread manages a single active proxy connection.
207- THREAD_RETURN_T connection_thread (void *arg)
208- {
205+ THREAD_RETURN_T connection_thread (void *arg) {
209206 int client_fd = (int )(uintptr_t )arg;
210- printf (" Established new proxy connection handler thread for incoming connection, at fd=%d\n " , client_fd); // TODO: print out getpeername()+getsockname() for more info
207+ // TODO: print out getpeername()+getsockname() for more info
208+ printf (" Established new proxy connection handler thread for incoming connection, at fd=%d\n " , client_fd);
211209
212210 // Waiting for connection upgrade handshake
213211 char buf[BUFFER_SIZE];
214212 int read = recv (client_fd, buf, BUFFER_SIZE, 0 );
215213
216- if (!read)
217- {
214+ if (!read) {
218215 CloseWebSocket (client_fd);
219216 EXIT_THREAD (0 );
220217 }
221218
222- if (read < 0 )
223- {
219+ if (read < 0 ) {
224220 fprintf (stderr, " Client read failed\n " );
225221 CloseWebSocket (client_fd);
226222 EXIT_THREAD (0 );
227223 }
228224
229225#ifdef PROXY_DEEP_DEBUG
230226 printf (" Received:" );
231- for (int i = 0 ; i < read; ++i)
232- {
227+ for (int i = 0 ; i < read; ++i) {
233228 printf (" %02X" , buf[i]);
234229 }
235230 printf (" \n " );
236- // printf("In text:\n%s\n", buf);
231+ // printf("In text:\n%s\n", buf);
237232#endif
238233 SendHandshake (client_fd, buf);
239234
@@ -244,21 +239,18 @@ THREAD_RETURN_T connection_thread(void *arg)
244239 std::vector<uint8_t > fragmentData;
245240
246241 bool connectionAlive = true ;
247- while (connectionAlive)
248- {
242+ while (connectionAlive) {
249243 int read = recv (client_fd, buf, BUFFER_SIZE, 0 );
250244
251245 if (!read) break ; // done reading
252- if (read < 0 )
253- {
246+ if (read < 0 ) {
254247 fprintf (stderr, " Client read failed\n " );
255248 EXIT_THREAD (0 );
256249 }
257250
258251#ifdef PROXY_DEEP_DEBUG
259252 printf (" Received:" );
260- for (int i = 0 ; i < read; ++i)
261- {
253+ for (int i = 0 ; i < read; ++i) {
262254 printf (" %02X" , ((unsigned char *)buf)[i]);
263255 }
264256 printf (" \n " );
@@ -271,19 +263,16 @@ THREAD_RETURN_T connection_thread(void *arg)
271263 fragmentData.insert (fragmentData.end (), buf, buf+read);
272264
273265 // Process received fragments until there is not enough data for a full message
274- while (!fragmentData.empty ())
275- {
266+ while (!fragmentData.empty ()) {
276267 bool hasFullHeader = WebSocketHasFullHeader (&fragmentData[0 ], fragmentData.size ());
277- if (!hasFullHeader)
278- {
268+ if (!hasFullHeader) {
279269#ifdef PROXY_DEEP_DEBUG
280270 printf (" (not enough for a full WebSocket header)\n " );
281271#endif
282272 break ;
283273 }
284274 uint64_t neededBytes = WebSocketFullMessageSize (&fragmentData[0 ], fragmentData.size ());
285- if (fragmentData.size () < neededBytes)
286- {
275+ if (fragmentData.size () < neededBytes) {
287276#ifdef PROXY_DEEP_DEBUG
288277 printf (" (not enough for a full WebSocket message, needed %d bytes)\n " , (int )neededBytes);
289278#endif
@@ -302,8 +291,7 @@ THREAD_RETURN_T connection_thread(void *arg)
302291 DumpWebSocketMessage (&fragmentData[0 ], neededBytes);
303292#endif
304293
305- switch (header->opcode )
306- {
294+ switch (header->opcode ) {
307295 case 0x02 : /* binary message*/ ProcessWebSocketMessage (client_fd, payload, payloadLength); break ;
308296 case 0x08 : connectionAlive = false ; break ;
309297 default :
@@ -323,22 +311,22 @@ THREAD_RETURN_T connection_thread(void *arg)
323311 EXIT_THREAD (0 );
324312}
325313
326- // Technically only would need one lock per connection, but this is now one lock per all connections, which would be
327- // slightly inefficient if we were handling multiple proxied connections at the same time. (currently that is a rare
328- // use case, expected to only be proxying one connection at a time - if this proxy bridge is expected to be used
329- // for hundreds of connections simultaneously, this mutex should be refactored to be per-connection)
314+ // Technically only would need one lock per connection, but this is now one lock
315+ // per all connections, which would be slightly inefficient if we were handling
316+ // multiple proxied connections at the same time. (currently that is a rare use
317+ // case, expected to only be proxying one connection at a time - if this proxy
318+ // bridge is expected to be used for hundreds of connections simultaneously,
319+ // this mutex should be refactored to be per-connection)
330320MUTEX_T webSocketSendLock;
331321MUTEX_T socketRegistryLock;
332322
333- int main (int argc, char *argv[])
334- {
323+ int main (int argc, char *argv[]) {
335324 if (argc < 2 ) on_error (" websocket_to_posix_proxy creates a bridge that allows WebSocket connections on a web page to proxy out to perform TCP/UDP connections.\n Usage: %s [port]\n " , argv[0 ]);
336325
337326#ifdef _WIN32
338327 WSADATA wsaData;
339328 int failed = WSAStartup (MAKEWORD (2 ,2 ), &wsaData);
340- if (failed)
341- {
329+ if (failed) {
342330 printf (" WSAStartup failed: %d\n " , failed);
343331 return 1 ;
344332 }
@@ -369,19 +357,16 @@ int main(int argc, char *argv[])
369357 CREATE_MUTEX (&webSocketSendLock);
370358 CREATE_MUTEX (&socketRegistryLock);
371359
372- while (1 )
373- {
360+ while (1 ) {
374361 SOCKET_T client_fd = accept (server_fd, 0 , 0 );
375- if (client_fd < 0 )
376- {
362+ if (client_fd < 0 ) {
377363 fprintf (stderr, " Could not establish new incoming proxy connection\n " );
378364 continue ; // Do not quit here, but keep serving any existing proxy connections.
379365 }
380366
381367 THREAD_T connection;
382368 CREATE_THREAD_RETURN_T ret = CREATE_THREAD (connection, connection_thread, (void *)(uintptr_t )client_fd);
383- if (!CREATE_THREAD_SUCCEEDED (ret))
384- {
369+ if (!CREATE_THREAD_SUCCEEDED (ret)) {
385370 fprintf (stderr, " Failed to create a connection handler thread for incoming proxy connection!\n " );
386371 continue ; // Do not quit here, but keep program alive to manage other existing proxy connections.
387372 }
0 commit comments