├── README.md
├── Source
└── HTML5Networking
│ ├── Classes
│ ├── WebSocketConnection.h
│ └── WebSocketNetDriver.h
│ ├── HTML5Networking.Build.cs
│ └── Private
│ ├── HTML5NetworkingPCH.h
│ ├── HTML5NetworkingPlugin.cpp
│ ├── WebSocket.cpp
│ ├── WebSocket.h
│ ├── WebSocketNetDriver.cpp
│ ├── WebSocketServer.cpp
│ ├── WebSocketServer.h
│ └── WebsocketConnection.cpp
└── html5networking.uplugin
/README.md:
--------------------------------------------------------------------------------
1 | ### Unreal Engine 4 Networking over Websockets Plugin
2 |
3 | - Provides websocket transport layer for unreal engine 4.
4 | - Uses [libwebsockets](http://libwebsocket.org) for the server side and client side for non HTML5 clients.
5 | - HTML5 clients use emscripten's sockets abstraction.
6 |
7 | #### How to
8 |
9 | - Clone this in Engine\Plugins\Experimental directory.
10 | - Add the following section in `BaseEngine.ini`
11 | ```
12 | [/Script/HTML5Networking.WebSocketNetDriver]
13 | AllowPeerConnections=False
14 | AllowPeerVoice=False
15 | ConnectionTimeout=6000.0
16 | InitialConnectTimeout=6000.0
17 | AckTimeout=10.0
18 | KeepAliveTime=20.2
19 | MaxClientRate=15000
20 | MaxInternetClientRate=10000
21 | RelevantTimeout=5.0
22 | SpawnPrioritySeconds=1.0
23 | ServerTravelPause=4.0
24 | NetServerMaxTickRate=30
25 | LanServerMaxTickRate=35
26 | WebSocketPort=8889
27 | NetConnectionClassName="/Script/HTML5Networking.WebSocketConnection"
28 | MaxPortCountToTry=512
29 | ```
30 | In section [/Script/Engine.Engine] disable comment out NetDriverDefinitions and add
31 | ```
32 | NetDriverDefinitions=(DefName="GameNetDriver",DriverClassName="/Script/HTML5Networking.WebSocketNetDriver",DriverClassNameFallback="/Script/HTML5Networking.IpNetDriver")
33 | ```
34 | To enable this Net Driver.
35 |
36 | Build! and follow existing Unreal Networking documentation to setup servers/clients.
37 |
38 | #### Issues/Todo
39 |
40 | Disconnect events on client or server side are not handled properly yet
41 |
42 | Copyright 2015 Epic Games.
43 |
--------------------------------------------------------------------------------
/Source/HTML5Networking/Classes/WebSocketConnection.h:
--------------------------------------------------------------------------------
1 | // Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
2 |
3 | #pragma once
4 |
5 | #include "WebSocketConnection.generated.h"
6 |
7 |
8 | UCLASS(transient, config = Engine)
9 | class HTML5NETWORKING_API UWebSocketConnection : public UNetConnection
10 | {
11 | GENERATED_UCLASS_BODY()
12 |
13 | class FWebSocket* WebSocket;
14 |
15 | // Begin NetConnection Interface
16 | virtual void InitBase(UNetDriver* InDriver, class FSocket* InSocket, const FURL& InURL, EConnectionState InState, int32 InMaxPacket = 0, int32 InPacketOverhead = 0) override;
17 | virtual void InitRemoteConnection(UNetDriver* InDriver, class FSocket* InSocket, const FURL& InURL, const class FInternetAddr& InRemoteAddr, EConnectionState InState, int32 InMaxPacket = 0, int32 InPacketOverhead = 0) override;
18 | virtual void InitLocalConnection(UNetDriver* InDriver, class FSocket* InSocket, const FURL& InURL, EConnectionState InState, int32 InMaxPacket = 0, int32 InPacketOverhead = 0) override;
19 | virtual void LowLevelSend(void* Data, int32 Count) override;
20 | FString LowLevelGetRemoteAddress(bool bAppendPort = false) override;
21 | FString LowLevelDescribe() override;
22 | virtual void Tick();
23 | virtual void FinishDestroy();
24 | // End NetConnection Interface
25 |
26 |
27 | void SetWebSocket(FWebSocket* InWebSocket);
28 | FWebSocket* GetWebSocket();
29 | };
30 |
--------------------------------------------------------------------------------
/Source/HTML5Networking/Classes/WebSocketNetDriver.h:
--------------------------------------------------------------------------------
1 | // Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
2 | //
3 | // websocket based implementation of the net driver
4 | //
5 |
6 | #pragma once
7 | #include "WebSocketNetDriver.generated.h"
8 |
9 | UCLASS(transient, config = Engine)
10 | class HTML5NETWORKING_API UWebSocketNetDriver : public UNetDriver
11 | {
12 | GENERATED_UCLASS_BODY()
13 |
14 | /** Websocket server port*/
15 | UPROPERTY(Config)
16 | int32 WebSocketPort;
17 |
18 | // Begin UNetDriver interface.
19 | virtual bool IsAvailable() const override;
20 | virtual bool InitBase(bool bInitAsClient, FNetworkNotify* InNotify, const FURL& URL, bool bReuseAddressAndPort, FString& Error) override;
21 | virtual bool InitConnect(FNetworkNotify* InNotify, const FURL& ConnectURL, FString& Error) override;
22 | virtual bool InitListen(FNetworkNotify* InNotify, FURL& LocalURL, bool bReuseAddressAndPort, FString& Error) override;
23 | virtual void ProcessRemoteFunction(class AActor* Actor, class UFunction* Function, void* Parameters, struct FOutParmRec* OutParms, struct FFrame* Stack, class UObject* SubObject = NULL) override;
24 | virtual void TickDispatch(float DeltaTime) override;
25 | virtual FString LowLevelGetNetworkNumber() override;
26 | virtual void LowLevelDestroy() override;
27 | virtual bool IsNetResourceValid(void) override;
28 |
29 | // stub implementation because for websockets we don't use any underlying socket sub system.
30 | virtual class ISocketSubsystem* GetSocketSubsystem() override;
31 | virtual FSocket * CreateSocket();
32 |
33 | // End UNetDriver interface.
34 |
35 | // Begin FExec Interface
36 | virtual bool Exec(UWorld* InWorld, const TCHAR* Cmd, FOutputDevice& Ar = *GLog) override;
37 | // End FExec Interface
38 |
39 | /**
40 | * Exec command handlers
41 | */
42 | bool HandleSocketsCommand(const TCHAR* Cmd, FOutputDevice& Ar, UWorld* InWorld);
43 |
44 | /** @return connection to server */
45 | class UWebSocketConnection* GetServerConnection();
46 |
47 | /************************************************************************/
48 | /* FWebSocketServer */
49 | /************************************************************************/
50 |
51 | FWebSocketServer* WebSocketServer;
52 |
53 | /******************************************************************************/
54 | /* Callback Function for New Connection from a client is accepted by this server */
55 | /******************************************************************************/
56 |
57 | void OnWebSocketClientConnected(FWebSocket*); // to the server.
58 |
59 |
60 | /************************************************************************/
61 | /* Callback Function for when this client Connects to the server */
62 | /************************************************************************/
63 |
64 | void OnWebSocketServerConnected(); // to the client.
65 |
66 |
67 | };
68 |
--------------------------------------------------------------------------------
/Source/HTML5Networking/HTML5Networking.Build.cs:
--------------------------------------------------------------------------------
1 | // Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
2 |
3 | namespace UnrealBuildTool.Rules
4 | {
5 | public class HTML5Networking : ModuleRules
6 | {
7 | public HTML5Networking(TargetInfo Target)
8 | {
9 | PrivateDependencyModuleNames.AddRange(
10 | new string[] {
11 | "Core",
12 | "CoreUObject",
13 | "Engine",
14 | "ImageCore",
15 | "Sockets",
16 | "OnlineSubSystemUtils",
17 | "WebSockets"
18 | }
19 | );
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Source/HTML5Networking/Private/HTML5NetworkingPCH.h:
--------------------------------------------------------------------------------
1 | // Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
2 | #pragma once
3 |
4 | #include "Core.h"
5 | #include "Engine.h"
6 | #include "Sockets.h"
7 | #include "SocketSubsystem.h"
8 | #include "ModuleManager.h"
9 |
10 | class FWebSocket;
11 | class FWebSocketServer;
12 |
13 | typedef struct libwebsocket_context WebSocketInternalContext;
14 | typedef struct libwebsocket WebSocketInternal;
15 | typedef struct libwebsocket_protocols WebSocketInternalProtocol;
16 |
17 | DECLARE_DELEGATE_TwoParams(FWebsocketPacketRecievedCallBack, void* /*Data*/, int32 /*Data Size*/);
18 | DECLARE_DELEGATE_OneParam(FWebsocketClientConnectedCallBack, FWebSocket* /*Socket*/);
19 | DECLARE_DELEGATE(FWebsocketInfoCallBack);
20 |
21 | DECLARE_LOG_CATEGORY_EXTERN(LogHTML5Networking, Warning, All);
--------------------------------------------------------------------------------
/Source/HTML5Networking/Private/HTML5NetworkingPlugin.cpp:
--------------------------------------------------------------------------------
1 | // Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
2 |
3 | #include "HTML5NetworkingPCH.h"
4 |
5 |
6 | class FHTML5NetworkingPlugin : public IModuleInterface
7 | {
8 | /** IModuleInterface implementation */
9 | virtual void StartupModule() override;
10 | virtual void ShutdownModule() override;
11 | };
12 |
13 | IMPLEMENT_MODULE(FHTML5NetworkingPlugin, HTML5Networking)
14 |
15 | void FHTML5NetworkingPlugin::StartupModule()
16 | {
17 | }
18 |
19 |
20 | void FHTML5NetworkingPlugin::ShutdownModule()
21 | {
22 | }
23 |
24 | DEFINE_LOG_CATEGORY(LogHTML5Networking);
25 |
26 |
27 |
--------------------------------------------------------------------------------
/Source/HTML5Networking/Private/WebSocket.cpp:
--------------------------------------------------------------------------------
1 | // Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
2 | #include "HTML5NetworkingPCH.h"
3 | #include "WebSocket.h"
4 |
5 | #if PLATFORM_HTML5
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include
15 | #include
16 | #include
17 | #include
18 | #include
19 | #endif
20 |
21 | #if PLATFORM_WINDOWS
22 | #include "AllowWindowsPlatformTypes.h"
23 | #endif
24 |
25 |
26 | #if !PLATFORM_HTML5
27 | #include "libwebsockets.h"
28 | #include "private-libwebsockets.h"
29 | #endif
30 |
31 | #if PLATFORM_WINDOWS
32 | #include "HideWindowsPlatformTypes.h"
33 | #endif
34 |
35 |
36 | #if !PLATFORM_HTML5
37 | uint8 PREPADDING[LWS_SEND_BUFFER_PRE_PADDING];
38 | uint8 POSTPADDING[LWS_SEND_BUFFER_POST_PADDING];
39 | #endif
40 |
41 |
42 | #if !PLATFORM_HTML5
43 | static void libwebsocket_debugLogS(int level, const char *line)
44 | {
45 | UE_LOG(LogHTML5Networking, Log, TEXT("client: %s"), ANSI_TO_TCHAR(line));
46 | }
47 | #endif
48 |
49 | FWebSocket::FWebSocket(
50 | const FInternetAddr& ServerAddress
51 | )
52 | :IsServerSide(false)
53 | {
54 |
55 | #if !PLATFORM_HTML5_BROWSER
56 |
57 | #if !UE_BUILD_SHIPPING
58 | lws_set_log_level(LLL_ERR | LLL_WARN | LLL_NOTICE | LLL_DEBUG | LLL_INFO, libwebsocket_debugLogS);
59 | #endif
60 |
61 | Protocols = new libwebsocket_protocols[3];
62 | FMemory::Memzero(Protocols, sizeof(libwebsocket_protocols) * 3);
63 |
64 | Protocols[0].name = "binary";
65 | Protocols[0].callback = FWebSocket::unreal_networking_client;
66 | Protocols[0].per_session_data_size = 0;
67 | Protocols[0].rx_buffer_size = 10 * 1024 * 1024;
68 |
69 | Protocols[1].name = nullptr;
70 | Protocols[1].callback = nullptr;
71 | Protocols[1].per_session_data_size = 0;
72 |
73 | struct lws_context_creation_info Info;
74 | memset(&Info, 0, sizeof Info);
75 |
76 | Info.port = CONTEXT_PORT_NO_LISTEN;
77 | Info.protocols = &Protocols[0];
78 | Info.gid = -1;
79 | Info.uid = -1;
80 | Info.user = this;
81 |
82 | Context = libwebsocket_create_context(&Info);
83 |
84 | check(Context);
85 |
86 |
87 | Wsi = libwebsocket_client_connect_extended
88 | (Context,
89 | TCHAR_TO_ANSI(*ServerAddress.ToString(false)),
90 | ServerAddress.GetPort(),
91 | false, "/", TCHAR_TO_ANSI(*ServerAddress.ToString(false)), TCHAR_TO_ANSI(*ServerAddress.ToString(false)), Protocols[1].name, -1,this);
92 |
93 | check(Wsi);
94 |
95 | #endif
96 |
97 | #if PLATFORM_HTML5_BROWSER
98 |
99 | struct sockaddr_in addr;
100 | int res;
101 |
102 | SockFd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
103 | if (SockFd == -1) {
104 | UE_LOG(LogHTML5Networking, Error, TEXT("Socket creationg failed "));
105 | }
106 | else
107 | {
108 | UE_LOG(LogHTML5Networking, Warning, TEXT(" Socked %d created "), SockFd);
109 | }
110 |
111 | fcntl(SockFd, F_SETFL, O_NONBLOCK);
112 |
113 | memset(&addr, 0, sizeof(addr));
114 | addr.sin_family = AF_INET;
115 | addr.sin_port = htons(ServerAddress.GetPort());
116 |
117 | if (inet_pton(AF_INET, TCHAR_TO_ANSI(*ServerAddress.ToString(false)), &addr.sin_addr) != 1) {
118 | UE_LOG(LogHTML5Networking, Warning, TEXT("inet_pton failed "));
119 | return;
120 | }
121 |
122 | int Ret = connect(SockFd, (struct sockaddr *)&addr, sizeof(addr));
123 | UE_LOG(LogHTML5Networking, Warning, TEXT(" Connect socket returned %d"), Ret);
124 |
125 | #endif
126 | }
127 |
128 | FWebSocket::FWebSocket(WebSocketInternalContext* InContext, WebSocketInternal* InWsi)
129 | : Context(InContext),
130 | Wsi(InWsi),
131 | IsServerSide(true)
132 | {
133 | }
134 |
135 |
136 | bool FWebSocket::Send(uint8* Data, uint32 Size)
137 | {
138 | TArray Buffer;
139 | // insert size.
140 |
141 | #if !PLATFORM_HTML5
142 | Buffer.Append((uint8*)&PREPADDING, sizeof(PREPADDING));
143 | #endif
144 |
145 | Buffer.Append((uint8*)&Size, sizeof (uint32));
146 | Buffer.Append((uint8*)Data, Size);
147 |
148 | #if !PLATFORM_HTML5
149 | Buffer.Append((uint8*)&POSTPADDING, sizeof(POSTPADDING));
150 | #endif
151 |
152 | OutgoingBuffer.Add(Buffer);
153 |
154 | return true;
155 | }
156 |
157 | void FWebSocket::SetRecieveCallBack(FWebsocketPacketRecievedCallBack CallBack)
158 | {
159 | RecievedCallBack = CallBack;
160 | }
161 |
162 | FString FWebSocket::RemoteEndPoint()
163 | {
164 | #if !PLATFORM_HTML5
165 | ANSICHAR Peer_Name[128];
166 | ANSICHAR Peer_Ip[128];
167 | libwebsockets_get_peer_addresses(Context, Wsi, libwebsocket_get_socket_fd(Wsi), Peer_Name, sizeof Peer_Name, Peer_Ip, sizeof Peer_Ip);
168 | return FString(Peer_Name);
169 | #endif
170 |
171 | #if PLATFORM_HTML5
172 | return FString(TEXT("TODO:REMOTEENDPOINT"));
173 | #endif
174 | }
175 |
176 |
177 | FString FWebSocket::LocalEndPoint()
178 | {
179 | #if !PLATFORM_HTML5
180 | return FString(ANSI_TO_TCHAR(libwebsocket_canonical_hostname(Context)));
181 | #endif
182 |
183 | #if PLATFORM_HTML5
184 | return FString(TEXT("TODO:LOCALENDPOINT"));
185 | #endif
186 |
187 | }
188 |
189 | void FWebSocket::Tick()
190 | {
191 |
192 | #if !PLATFORM_HTML5
193 | {
194 | libwebsocket_service(Context, 0);
195 | if (!IsServerSide)
196 | libwebsocket_callback_on_writable_all_protocol(&Protocols[0]);
197 | }
198 | #endif
199 |
200 | #if PLATFORM_HTML5
201 |
202 | fd_set Fdr;
203 | fd_set Fdw;
204 | int Res;
205 |
206 | // make sure that server.fd is ready to read / write
207 | FD_ZERO(&Fdr);
208 | FD_ZERO(&Fdw);
209 | FD_SET(SockFd, &Fdr);
210 | FD_SET(SockFd, &Fdw);
211 | Res = select(64, &Fdr, &Fdw, NULL, NULL);
212 |
213 | if (Res == -1) {
214 | UE_LOG(LogHTML5Networking, Warning, TEXT("Select Failed!"));
215 | return;
216 | }
217 |
218 | if (FD_ISSET(SockFd, &Fdr)) {
219 | // we can read!
220 | OnRawRecieve(NULL, NULL);
221 | }
222 |
223 | if (FD_ISSET(SockFd, &Fdw)) {
224 | // we can write
225 | OnRawWebSocketWritable(NULL);
226 | }
227 | #endif
228 | }
229 |
230 | void FWebSocket::SetConnectedCallBack(FWebsocketInfoCallBack CallBack)
231 | {
232 | ConnectedCallBack = CallBack;
233 | }
234 |
235 | void FWebSocket::SetErrorCallBack(FWebsocketInfoCallBack CallBack)
236 | {
237 | ErrorCallBack = CallBack;
238 | }
239 |
240 | void FWebSocket::OnRawRecieve(void* Data, uint32 Size)
241 | {
242 | #if !PLATFORM_HTML5
243 | RecievedBuffer.Append((uint8*)Data, Size);
244 |
245 | while (RecievedBuffer.Num())
246 | {
247 | uint32 BytesToBeRead = *(uint32*)RecievedBuffer.GetData();
248 | if (BytesToBeRead <= ((uint32)RecievedBuffer.Num() - sizeof(uint32)))
249 | {
250 | RecievedCallBack.Execute((void*)((uint8*)RecievedBuffer.GetData() + sizeof(uint32)), BytesToBeRead);
251 | RecievedBuffer.RemoveAt(0, sizeof(uint32) + BytesToBeRead );
252 | }
253 | else
254 | {
255 | break;
256 | }
257 | }
258 | #endif
259 |
260 | #if PLATFORM_HTML5
261 |
262 | uint8 Buffer[1024]; // should be at MAX PACKET SIZE.
263 | int Result = recv(SockFd, Buffer, sizeof(uint32), 0);
264 |
265 | uint32 DataToBeRead = 0;*(uint32*)Buffer;
266 |
267 | if (Result == -1)
268 | {
269 | UE_LOG(LogHTML5Networking, Log, TEXT("Read message size failed!"));
270 | this->ErrorCallBack.ExecuteIfBound();
271 | }
272 | else
273 | {
274 | DataToBeRead = *(uint32*)Buffer;
275 | UE_LOG(LogHTML5Networking, Log, TEXT("Read 4 bytes showing the size"), DataToBeRead);
276 | }
277 |
278 | check(Result == sizeof(uint32));
279 |
280 | // read rest of the data.
281 | Result = recv(SockFd, Buffer, DataToBeRead, 0);
282 |
283 | if(Result < 0 )
284 | {
285 | UE_LOG(LogHTML5Networking, Log, TEXT("Read message failed!"));
286 | this->ErrorCallBack.ExecuteIfBound();
287 | }
288 | else
289 | {
290 | UE_LOG(LogHTML5Networking, Log, TEXT("Read %d bytes and Executing."), DataToBeRead);
291 | check(DataToBeRead == Result);
292 | RecievedCallBack.Execute(Buffer, DataToBeRead);
293 | }
294 |
295 | #endif
296 |
297 | }
298 |
299 | void FWebSocket::OnRawWebSocketWritable(WebSocketInternal* wsi)
300 | {
301 | if (OutgoingBuffer.Num() == 0)
302 | return;
303 |
304 | TArray & Packet = OutgoingBuffer[0];
305 |
306 | #if !PLATFORM_HTML5_BROWSER
307 |
308 | uint32 TotalDataSize = Packet.Num() - LWS_SEND_BUFFER_PRE_PADDING - LWS_SEND_BUFFER_POST_PADDING;
309 |
310 | int Sent = libwebsocket_write(Wsi, Packet.GetData() + LWS_SEND_BUFFER_PRE_PADDING, TotalDataSize, (libwebsocket_write_protocol)LWS_WRITE_BINARY);
311 |
312 | check(Sent == TotalDataSize); // if this fires we need a slightly more complicated buffering mechanism.
313 | check(Wsi == wsi);
314 |
315 | #endif
316 |
317 | #if PLATFORM_HTML5_BROWSER
318 |
319 | // send actual data in one go.
320 | int Result = send(SockFd, (uint32*)Packet.GetData(),Packet.Num(), 0);
321 |
322 | if (Result == -1)
323 | {
324 | // we are caught with our pants down. fail.
325 | UE_LOG(LogHTML5Networking, Error, TEXT("Could not write %d bytes"), Packet.Num());
326 | ErrorCallBack.ExecuteIfBound();
327 | }
328 | else
329 | {
330 | check(Result == Packet.Num());
331 | UE_LOG(LogHTML5Networking, Log, TEXT("Wrote %d bytes"), Packet.Num());
332 | }
333 |
334 | #endif
335 |
336 | // this is very inefficient we need a constant size circular buffer to efficiently not do unnecessary allocations/deallocations.
337 | OutgoingBuffer.RemoveAt(0);
338 |
339 | }
340 |
341 | FWebSocket::~FWebSocket()
342 | {
343 | #if !PLATFORM_HTML5
344 | if ( !IsServerSide)
345 | {
346 | libwebsocket_context_destroy(Context);
347 | Context = NULL;
348 | delete Protocols;
349 | Protocols = NULL;
350 | }
351 | #endif
352 |
353 | #if PLATFORM_HTML5
354 | close(SockFd);
355 | #endif
356 |
357 | }
358 |
359 | #if !PLATFORM_HTML5
360 | int FWebSocket::unreal_networking_client(
361 | struct libwebsocket_context *Context,
362 | struct libwebsocket *Wsi,
363 | enum libwebsocket_callback_reasons Reason,
364 | void *User,
365 | void *In,
366 | size_t Len)
367 | {
368 | FWebSocket* Socket = (FWebSocket*)libwebsocket_context_user(Context);;
369 | switch (Reason)
370 | {
371 | case LWS_CALLBACK_CLIENT_ESTABLISHED:
372 | {
373 | Socket->ConnectedCallBack.ExecuteIfBound();
374 | libwebsocket_set_timeout(Wsi, NO_PENDING_TIMEOUT, 0);
375 | check(Socket->Wsi == Wsi);
376 | }
377 | break;
378 | case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
379 | {
380 | Socket->ErrorCallBack.ExecuteIfBound();
381 | return -1;
382 | }
383 | break;
384 | case LWS_CALLBACK_CLIENT_RECEIVE:
385 | {
386 | // push it on the socket.
387 | Socket->OnRawRecieve(In, (uint32)Len);
388 | check(Socket->Wsi == Wsi);
389 | libwebsocket_set_timeout(Wsi, NO_PENDING_TIMEOUT, 0);
390 | break;
391 | }
392 | case LWS_CALLBACK_CLIENT_WRITEABLE:
393 | {
394 | check(Socket->Wsi == Wsi);
395 | Socket->OnRawWebSocketWritable(Wsi);
396 | libwebsocket_callback_on_writable(Context, Wsi);
397 | libwebsocket_set_timeout(Wsi, NO_PENDING_TIMEOUT, 0);
398 | break;
399 | }
400 | case LWS_CALLBACK_CLOSED:
401 | {
402 | Socket->ErrorCallBack.ExecuteIfBound();
403 | return -1;
404 | }
405 | }
406 |
407 | return 0;
408 | }
409 | #endif
410 |
411 |
--------------------------------------------------------------------------------
/Source/HTML5Networking/Private/WebSocket.h:
--------------------------------------------------------------------------------
1 | // Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
2 | //
3 | // libwebsocket client wrapper.
4 | //
5 | #pragma once
6 | #include "HTML5NetworkingPCH.h"
7 |
8 | class FWebSocket
9 | {
10 |
11 | public:
12 |
13 | // Initialize as client side socket.
14 | FWebSocket(const FInternetAddr& ServerAddress);
15 |
16 | // Initialize as server side socket.
17 | FWebSocket(WebSocketInternalContext* InContext, WebSocketInternal* Wsi);
18 |
19 | // clean up.
20 | ~FWebSocket();
21 |
22 | /************************************************************************/
23 | /* Set various callbacks for Socket Events */
24 | /************************************************************************/
25 | void SetConnectedCallBack(FWebsocketInfoCallBack CallBack);
26 | void SetErrorCallBack(FWebsocketInfoCallBack CallBack);
27 | void SetRecieveCallBack(FWebsocketPacketRecievedCallBack CallBack);
28 |
29 | /** Send raw data to remote end point. */
30 | bool Send(uint8* Data, uint32 Size);
31 |
32 | /** service libwebsocket. */
33 | void Tick();
34 |
35 | /** Helper functions to describe end points. */
36 | FString RemoteEndPoint();
37 | FString LocalEndPoint();
38 |
39 | private:
40 |
41 | void OnRawRecieve(void* Data, uint32 Size);
42 | void OnRawWebSocketWritable(WebSocketInternal* wsi);
43 |
44 | /************************************************************************/
45 | /* Various Socket callbacks */
46 | /************************************************************************/
47 | FWebsocketPacketRecievedCallBack RecievedCallBack;
48 | FWebsocketInfoCallBack ConnectedCallBack;
49 | FWebsocketInfoCallBack ErrorCallBack;
50 |
51 | /** Recv and Send Buffers, serviced during the Tick */
52 | TArray RecievedBuffer;
53 | TArray> OutgoingBuffer;
54 |
55 | /** libwebsocket internal context*/
56 | WebSocketInternalContext* Context;
57 |
58 | /** libwebsocket web socket */
59 | WebSocketInternal* Wsi;
60 |
61 | /** libwebsocket Protocols that can be serviced by this implemenation*/
62 | WebSocketInternalProtocol* Protocols;
63 |
64 | /** Server side socket or client side*/
65 | bool IsServerSide;
66 |
67 | #if !PLATFORM_HTML5
68 | /* libwebsocket service functions */
69 | static int unreal_networking_server(struct libwebsocket_context *, struct libwebsocket *wsi, enum libwebsocket_callback_reasons reason, void *user, void *in, size_t len);
70 | static int unreal_networking_client(struct libwebsocket_context *, struct libwebsocket *wsi, enum libwebsocket_callback_reasons reason, void *user, void *in, size_t len);
71 | #endif
72 |
73 | friend class FWebSocketServer;
74 | int SockFd;
75 | };
76 |
77 |
78 |
--------------------------------------------------------------------------------
/Source/HTML5Networking/Private/WebSocketNetDriver.cpp:
--------------------------------------------------------------------------------
1 | // Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
2 |
3 | /*=============================================================================
4 | Unreal Websocket network driver.
5 | =============================================================================*/
6 |
7 | #include "HTML5NetworkingPCH.h"
8 | #include "Engine/Channel.h"
9 |
10 | #include "IPAddress.h"
11 | #include "Sockets.h"
12 |
13 | #include "WebSocketConnection.h"
14 | #include "WebSocketNetDriver.h"
15 | #include "WebSocketServer.h"
16 | #include "WebSocket.h"
17 |
18 |
19 | /*-----------------------------------------------------------------------------
20 | Declarations.
21 | -----------------------------------------------------------------------------*/
22 |
23 | /** Size of the network recv buffer */
24 | #define NETWORK_MAX_PACKET (576)
25 |
26 | UWebSocketNetDriver::UWebSocketNetDriver(const FObjectInitializer& ObjectInitializer)
27 | : Super(ObjectInitializer)
28 | {
29 | }
30 |
31 | bool UWebSocketNetDriver::IsAvailable() const
32 | {
33 | // Websocket driver always valid for now
34 | return true;
35 | }
36 |
37 |
38 |
39 | ISocketSubsystem* UWebSocketNetDriver::GetSocketSubsystem()
40 | {
41 | return ISocketSubsystem::Get();
42 | }
43 |
44 | FSocket * UWebSocketNetDriver::CreateSocket()
45 | {
46 | return NULL;
47 | }
48 |
49 | bool UWebSocketNetDriver::InitBase(bool bInitAsClient, FNetworkNotify* InNotify, const FURL& URL, bool bReuseAddressAndPort, FString& Error)
50 | {
51 | if (!Super::InitBase(bInitAsClient, InNotify, URL, bReuseAddressAndPort, Error))
52 | {
53 | return false;
54 | }
55 |
56 | return true;
57 | }
58 |
59 | bool UWebSocketNetDriver::InitConnect(FNetworkNotify* InNotify, const FURL& ConnectURL, FString& Error)
60 | {
61 | if (!InitBase(true, InNotify, ConnectURL, false, Error))
62 | {
63 | return false;
64 | }
65 |
66 | // Create new connection.
67 | ServerConnection = NewObject(NetConnectionClass);
68 |
69 | TSharedRef InternetAddr = GetSocketSubsystem()->CreateInternetAddr();
70 | bool Ok;
71 | InternetAddr->SetIp(*ConnectURL.Host, Ok);
72 | InternetAddr->SetPort(WebSocketPort);
73 |
74 | FWebSocket* WebSocket = new FWebSocket(*InternetAddr);
75 | UWebSocketConnection* Connection = (UWebSocketConnection*)ServerConnection;
76 | Connection->SetWebSocket(WebSocket);
77 |
78 | FWebsocketPacketRecievedCallBack CallBack;
79 | CallBack.BindUObject(Connection, &UWebSocketConnection::ReceivedRawPacket);
80 | WebSocket->SetRecieveCallBack(CallBack);
81 |
82 | FWebsocketInfoCallBack ConnectedCallBack;
83 | ConnectedCallBack.BindUObject(this, &UWebSocketNetDriver::OnWebSocketServerConnected);
84 | WebSocket->SetConnectedCallBack(ConnectedCallBack);
85 |
86 | ServerConnection->InitLocalConnection(this, NULL, ConnectURL, USOCK_Pending);
87 |
88 | // Create channel zero.
89 | GetServerConnection()->CreateChannel(CHTYPE_Control, 1, 0);
90 |
91 | return true;
92 | }
93 |
94 | bool UWebSocketNetDriver::InitListen(FNetworkNotify* InNotify, FURL& LocalURL, bool bReuseAddressAndPort, FString& Error)
95 | {
96 | if (!InitBase(false, InNotify, LocalURL, bReuseAddressAndPort, Error))
97 | {
98 | return false;
99 | }
100 |
101 | WebSocketServer = new class FWebSocketServer();
102 |
103 | FWebsocketClientConnectedCallBack CallBack;
104 | CallBack.BindUObject(this, &UWebSocketNetDriver::OnWebSocketClientConnected);
105 |
106 | if(!WebSocketServer->Init(WebSocketPort, CallBack))
107 | return false;
108 |
109 | WebSocketServer->Tick();
110 | LocalURL.Port = WebSocketPort;
111 | UE_LOG(LogHTML5Networking, Log, TEXT("%s WebSocketNetDriver listening on port %i"), *GetDescription(), LocalURL.Port);
112 |
113 | // server has no server connection.
114 | ServerConnection = NULL;
115 | return true;
116 | }
117 |
118 | void UWebSocketNetDriver::TickDispatch(float DeltaTime)
119 | {
120 | Super::TickDispatch(DeltaTime);
121 |
122 | if (WebSocketServer)
123 | WebSocketServer->Tick();
124 | }
125 |
126 | void UWebSocketNetDriver::ProcessRemoteFunction(class AActor* Actor, UFunction* Function, void* Parameters, FOutParmRec* OutParms, FFrame* Stack, class UObject* SubObject)
127 | {
128 | bool bIsServer = IsServer();
129 |
130 | UNetConnection* Connection = NULL;
131 | if (bIsServer)
132 | {
133 | if ((Function->FunctionFlags & FUNC_NetMulticast))
134 | {
135 | // Multicast functions go to every client
136 | TArray UniqueRealConnections;
137 | for (int32 i = 0; iFunctionFlags & FUNC_NetReliable) == 0)
151 | {
152 | if (Connection->ViewTarget)
153 | {
154 | FNetViewer Viewer(Connection, 0.f);
155 | IsRelevant = Actor->IsNetRelevantFor(Viewer.InViewer, Viewer.ViewTarget, Viewer.ViewLocation);
156 | }
157 | else
158 | {
159 | // No viewer for this connection(?), just let it go through.
160 | UE_LOG(LogHTML5Networking, Log, TEXT("Multicast function %s called on actor %s when a connection has no Viewer"), *Function->GetName(), *Actor->GetName());
161 | }
162 | }
163 |
164 | if (IsRelevant)
165 | {
166 | if (Connection->GetUChildConnection() != NULL)
167 | {
168 | Connection = ((UChildConnection*)Connection)->Parent;
169 | }
170 |
171 | InternalProcessRemoteFunction(Actor, SubObject, Connection, Function, Parameters, OutParms, Stack, bIsServer);
172 | }
173 | }
174 | }
175 |
176 | // Return here so we don't call InternalProcessRemoteFunction again at the bottom of this function
177 | return;
178 | }
179 | }
180 |
181 | // Send function data to remote.
182 | Connection = Actor->GetNetConnection();
183 | if (Connection)
184 | {
185 | InternalProcessRemoteFunction(Actor, SubObject, Connection, Function, Parameters, OutParms, Stack, bIsServer);
186 | }
187 | }
188 |
189 | FString UWebSocketNetDriver::LowLevelGetNetworkNumber()
190 | {
191 | return WebSocketServer->Info();
192 | }
193 |
194 | void UWebSocketNetDriver::LowLevelDestroy()
195 | {
196 | Super::LowLevelDestroy();
197 | delete WebSocketServer;
198 | }
199 |
200 | bool UWebSocketNetDriver::HandleSocketsCommand(const TCHAR* Cmd, FOutputDevice& Ar, UWorld* InWorld)
201 | {
202 | Ar.Logf(TEXT(""));
203 | if (WebSocketServer != NULL)
204 | {
205 | Ar.Logf(TEXT("Running WebSocket Server %s"), *WebSocketServer->Info());
206 | }
207 | else
208 | {
209 | check(GetServerConnection());
210 | Ar.Logf(TEXT("WebSocket client's EndPoint %s"), *(GetServerConnection()->WebSocket->RemoteEndPoint()));
211 | }
212 | return UNetDriver::Exec(InWorld, TEXT("SOCKETS"), Ar);
213 | }
214 |
215 | bool UWebSocketNetDriver::Exec(UWorld* InWorld, const TCHAR* Cmd, FOutputDevice& Ar)
216 | {
217 | if (FParse::Command(&Cmd, TEXT("SOCKETS")))
218 | {
219 | return HandleSocketsCommand(Cmd, Ar, InWorld);
220 | }
221 | return UNetDriver::Exec(InWorld, Cmd, Ar);
222 | }
223 |
224 | UWebSocketConnection* UWebSocketNetDriver::GetServerConnection()
225 | {
226 | return (UWebSocketConnection*)ServerConnection;
227 | }
228 |
229 | void UWebSocketNetDriver::OnWebSocketClientConnected(FWebSocket* ClientWebSocket)
230 | {
231 | // Determine if allowing for client/server connections
232 | const bool bAcceptingConnection = Notify->NotifyAcceptingConnection() == EAcceptConnection::Accept;
233 | if (bAcceptingConnection)
234 | {
235 |
236 | UWebSocketConnection* Connection = NewObject(NetConnectionClass);
237 | check(Connection);
238 |
239 | TSharedRef InternetAddr = GetSocketSubsystem()->CreateInternetAddr();
240 | bool Ok;
241 |
242 | InternetAddr->SetIp(*(ClientWebSocket->RemoteEndPoint()),Ok);
243 | InternetAddr->SetPort(0);
244 | Connection->SetWebSocket(ClientWebSocket);
245 | Connection->InitRemoteConnection(this, NULL, FURL(), *InternetAddr, USOCK_Open);
246 |
247 | Notify->NotifyAcceptedConnection(Connection);
248 |
249 | AddClientConnection(Connection);
250 |
251 | FWebsocketPacketRecievedCallBack CallBack;
252 | CallBack.BindUObject(Connection, &UWebSocketConnection::ReceivedRawPacket);
253 | ClientWebSocket->SetRecieveCallBack(CallBack);
254 |
255 | UE_LOG(LogHTML5Networking, Log, TEXT(" Websocket server running on %s Accepted Connection from %s "), *WebSocketServer->Info(),*ClientWebSocket->RemoteEndPoint());
256 | }
257 | }
258 |
259 | bool UWebSocketNetDriver::IsNetResourceValid(void)
260 | {
261 | if ( (WebSocketServer && !ServerConnection)// Server
262 | || (!WebSocketServer && ServerConnection) // client
263 | )
264 | {
265 | return true;
266 | }
267 |
268 | return false;
269 | }
270 |
271 | // Just logging, not yet attached to html5 clients.
272 | void UWebSocketNetDriver::OnWebSocketServerConnected()
273 | {
274 | check(GetServerConnection());
275 | UE_LOG(LogHTML5Networking, Log, TEXT(" %s Websocket Client connected to server %s "), *GetDescription(), *GetServerConnection()->WebSocket->RemoteEndPoint());
276 | }
277 |
278 |
--------------------------------------------------------------------------------
/Source/HTML5Networking/Private/WebSocketServer.cpp:
--------------------------------------------------------------------------------
1 | // Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
2 |
3 | #include "HTML5NetworkingPCH.h"
4 | #include "WebSocketServer.h"
5 | #include "WebSocket.h"
6 |
7 | #if PLATFORM_WINDOWS
8 | #include "AllowWindowsPlatformTypes.h"
9 | #endif
10 |
11 | #if !PLATFORM_HTML5
12 | #include "libwebsockets.h"
13 | #endif
14 |
15 | #if PLATFORM_WINDOWS
16 | #include "HideWindowsPlatformTypes.h"
17 | #endif
18 |
19 | // a object of this type is associated by libwebsocket to every connected session.
20 | struct PerSessionDataServer
21 | {
22 | FWebSocket *Socket; // each session is actually a socket to a client
23 | };
24 |
25 |
26 | #if !PLATFORM_HTML5
27 | // real networking handler.
28 | static int unreal_networking_server(
29 | struct libwebsocket_context *,
30 | struct libwebsocket *wsi,
31 | enum libwebsocket_callback_reasons reason,
32 | void *user,
33 | void *in,
34 | size_t
35 | len
36 | );
37 |
38 | #if !UE_BUILD_SHIPPING
39 | void libwebsocket_debugLog(int level, const char *line)
40 | {
41 | UE_LOG(LogHTML5Networking, Log, TEXT("websocket server: %s"), ANSI_TO_TCHAR(line));
42 | }
43 | #endif
44 | #endif
45 |
46 | bool FWebSocketServer::Init(uint32 Port, FWebsocketClientConnectedCallBack CallBack)
47 | {
48 | #if !PLATFORM_HTML5
49 | // setup log level.
50 | #if !UE_BUILD_SHIPPING
51 | lws_set_log_level(LLL_ERR | LLL_WARN | LLL_NOTICE | LLL_DEBUG | LLL_INFO, libwebsocket_debugLog);
52 | #endif
53 |
54 | Protocols = new libwebsocket_protocols[3];
55 | FMemory::Memzero(Protocols, sizeof(libwebsocket_protocols) * 3);
56 |
57 | Protocols[0].name = "binary";
58 | Protocols[0].callback = FWebSocket::unreal_networking_server;
59 | Protocols[0].per_session_data_size = sizeof(PerSessionDataServer);
60 | Protocols[0].rx_buffer_size = 10 * 1024 * 1024;
61 |
62 | Protocols[1].name = nullptr;
63 | Protocols[1].callback = nullptr;
64 | Protocols[1].per_session_data_size = 0;
65 |
66 | struct lws_context_creation_info Info;
67 | memset(&Info, 0, sizeof(lws_context_creation_info));
68 | // look up libwebsockets.h for details.
69 | Info.port = Port;
70 | // we listen on all available interfaces.
71 | Info.iface = NULL;
72 | Info.protocols = &Protocols[0];
73 | // no extensions
74 | Info.extensions = NULL;
75 | Info.gid = -1;
76 | Info.uid = -1;
77 | Info.options = 0;
78 | // tack on this object.
79 | Info.user = this;
80 | Info.port = Port;
81 | Context = libwebsocket_create_context(&Info);
82 |
83 | if (Context == NULL)
84 | {
85 | return false; // couldn't create a server.
86 | }
87 |
88 | ConnectedCallBack = CallBack;
89 |
90 | #endif
91 | return true;
92 | }
93 |
94 | bool FWebSocketServer::Tick()
95 | {
96 | #if !PLATFORM_HTML5
97 | {
98 | libwebsocket_service(Context, 0);
99 | libwebsocket_callback_on_writable_all_protocol(&Protocols[0]);
100 | }
101 | #endif
102 | return true;
103 | }
104 |
105 | FWebSocketServer::FWebSocketServer()
106 | {}
107 |
108 | FWebSocketServer::~FWebSocketServer()
109 | {
110 | #if !PLATFORM_HTML5
111 | if (Context)
112 | {
113 |
114 | libwebsocket_context_destroy(Context);
115 | Context = NULL;
116 | }
117 |
118 | delete Protocols;
119 | Protocols = NULL;
120 | #endif
121 | }
122 |
123 | FString FWebSocketServer::Info()
124 | {
125 |
126 | #if !PLATFORM_HTML5
127 | return FString(ANSI_TO_TCHAR(libwebsocket_canonical_hostname(Context)));
128 | #else
129 | return FString(TEXT("NOT SUPPORTED"));
130 | #endif
131 |
132 | }
133 |
134 | // callback.
135 | #if !PLATFORM_HTML5
136 | int FWebSocket::unreal_networking_server
137 | (
138 | struct libwebsocket_context *Context,
139 | struct libwebsocket *Wsi,
140 | enum libwebsocket_callback_reasons Reason,
141 | void *User,
142 | void *In,
143 | size_t Len
144 | )
145 | {
146 | PerSessionDataServer* BufferInfo = (PerSessionDataServer*)User;
147 | FWebSocketServer* Server = (FWebSocketServer*)libwebsocket_context_user(Context);
148 |
149 | switch (Reason)
150 | {
151 | case LWS_CALLBACK_ESTABLISHED:
152 | {
153 | BufferInfo->Socket = new FWebSocket(Context, Wsi);
154 | Server->ConnectedCallBack.ExecuteIfBound(BufferInfo->Socket);
155 | libwebsocket_set_timeout(Wsi, NO_PENDING_TIMEOUT, 0);
156 | }
157 | break;
158 |
159 | case LWS_CALLBACK_RECEIVE:
160 | {
161 | BufferInfo->Socket->OnRawRecieve(In, Len);
162 | libwebsocket_set_timeout(Wsi, NO_PENDING_TIMEOUT, 0);
163 | }
164 | break;
165 |
166 | case LWS_CALLBACK_SERVER_WRITEABLE:
167 | {
168 | BufferInfo->Socket->OnRawWebSocketWritable(Wsi);
169 | libwebsocket_set_timeout(Wsi, NO_PENDING_TIMEOUT, 0);
170 | }
171 | break;
172 | case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
173 | {
174 | BufferInfo->Socket->ErrorCallBack.ExecuteIfBound();
175 | }
176 | break;
177 | }
178 |
179 | return 0;
180 | }
181 | #endif
--------------------------------------------------------------------------------
/Source/HTML5Networking/Private/WebSocketServer.h:
--------------------------------------------------------------------------------
1 | // Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
2 | //
3 | // Read http://lucumr.pocoo.org/2012/9/24/websockets-101/ for a nice intro to web sockets.
4 | // This uses https://libwebsockets.org/trac/libwebsockets
5 | #pragma once
6 | #include "HTML5NetworkingPCH.h"
7 |
8 | class FWebSocketServer
9 | {
10 | public:
11 |
12 | FWebSocketServer();
13 | ~FWebSocketServer();
14 |
15 | /** Create a web socket server*/
16 | bool Init(uint32 Port, FWebsocketClientConnectedCallBack);
17 |
18 | /** Service libwebsocket */
19 | bool Tick();
20 |
21 | /** Describe this libwebsocket server */
22 | FString Info();
23 |
24 | private:
25 |
26 | /** Callback for a new websocket connection to the server */
27 | FWebsocketClientConnectedCallBack ConnectedCallBack;
28 |
29 | /** Internal libwebsocket context */
30 | WebSocketInternalContext* Context;
31 |
32 | /** Protocols serviced by this implementation */
33 | WebSocketInternalProtocol* Protocols;
34 |
35 | friend class FWebSocket;
36 | };
37 |
38 |
39 |
--------------------------------------------------------------------------------
/Source/HTML5Networking/Private/WebsocketConnection.cpp:
--------------------------------------------------------------------------------
1 | // Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
2 |
3 | #include "HTML5NetworkingPCH.h"
4 |
5 | #include "IPAddress.h"
6 | #include "Sockets.h"
7 | #include "Net/NetworkProfiler.h"
8 | #include "Net/DataChannel.h"
9 |
10 | #include "WebSocketConnection.h"
11 | #include "WebSocketNetDriver.h"
12 | #include "WebSocket.h"
13 | /*-----------------------------------------------------------------------------
14 | Declarations.
15 | -----------------------------------------------------------------------------*/
16 |
17 | // Size of a UDP header.
18 | #define IP_HEADER_SIZE (20)
19 | #define UDP_HEADER_SIZE (IP_HEADER_SIZE+8)
20 | #define SLIP_HEADER_SIZE (UDP_HEADER_SIZE+4)
21 | #define WINSOCK_MAX_PACKET (512)
22 |
23 | UWebSocketConnection::UWebSocketConnection(const FObjectInitializer& ObjectInitializer) :
24 | Super(ObjectInitializer),
25 | WebSocket(NULL)
26 | {
27 | }
28 |
29 | void UWebSocketConnection::InitBase(UNetDriver* InDriver, class FSocket* InSocket, const FURL& InURL, EConnectionState InState, int32 InMaxPacket, int32 InPacketOverhead)
30 | {
31 | // Pass the call up the chain
32 | Super::InitBase(InDriver, InSocket, InURL, InState,
33 | // Use the default packet size/overhead unless overridden by a child class
34 | InMaxPacket == 0 ? WINSOCK_MAX_PACKET : InMaxPacket,
35 | InPacketOverhead == 0 ? SLIP_HEADER_SIZE : InPacketOverhead);
36 |
37 | }
38 |
39 | void UWebSocketConnection::InitLocalConnection(UNetDriver* InDriver, class FSocket* InSocket, const FURL& InURL, EConnectionState InState, int32 InMaxPacket, int32 InPacketOverhead)
40 | {
41 | InitBase(InDriver, InSocket, InURL, InState,
42 | // Use the default packet size/overhead unless overridden by a child class
43 | InMaxPacket == 0 ? WINSOCK_MAX_PACKET : InMaxPacket,
44 | InPacketOverhead == 0 ? SLIP_HEADER_SIZE : InPacketOverhead);
45 |
46 | // Figure out IP address from the host URL
47 |
48 | // Initialize our send bunch
49 | InitSendBuffer();
50 | }
51 |
52 | void UWebSocketConnection::InitRemoteConnection(UNetDriver* InDriver, class FSocket* InSocket, const FURL& InURL, const class FInternetAddr& InRemoteAddr, EConnectionState InState, int32 InMaxPacket, int32 InPacketOverhead)
53 | {
54 | InitBase(InDriver, InSocket, InURL, InState,
55 | // Use the default packet size/overhead unless overridden by a child class
56 | InMaxPacket == 0 ? WINSOCK_MAX_PACKET : InMaxPacket,
57 | InPacketOverhead == 0 ? SLIP_HEADER_SIZE : InPacketOverhead);
58 |
59 | // Initialize our send bunch
60 | InitSendBuffer();
61 |
62 | // This is for a client that needs to log in, setup ClientLoginState and ExpectedClientLoginMsgType to reflect that
63 | SetClientLoginState(EClientLoginState::LoggingIn);
64 | SetExpectedClientLoginMsgType(NMT_Hello);
65 | }
66 |
67 | void UWebSocketConnection::LowLevelSend(void* Data, int32 Count)
68 | {
69 | int32 BytesSent = 0;
70 | WebSocket->Send((uint8*)Data, Count);
71 | }
72 |
73 | FString UWebSocketConnection::LowLevelGetRemoteAddress(bool bAppendPort)
74 | {
75 | return WebSocket->RemoteEndPoint();
76 | }
77 |
78 | FString UWebSocketConnection::LowLevelDescribe()
79 | {
80 | return FString::Printf
81 | (
82 | TEXT(" remote=%s local=%s state: %s"),
83 | *WebSocket->RemoteEndPoint(),
84 | *WebSocket->LocalEndPoint(),
85 | State == USOCK_Pending ? TEXT("Pending")
86 | : State == USOCK_Open ? TEXT("Open")
87 | : State == USOCK_Closed ? TEXT("Closed")
88 | : TEXT("Invalid")
89 | );
90 | }
91 |
92 |
93 | void UWebSocketConnection::SetWebSocket(FWebSocket* InWebSocket)
94 | {
95 | WebSocket = InWebSocket;
96 | }
97 |
98 | FWebSocket* UWebSocketConnection::GetWebSocket()
99 | {
100 | return WebSocket;
101 | }
102 |
103 |
104 | void UWebSocketConnection::Tick()
105 | {
106 | UNetConnection::Tick();
107 | WebSocket->Tick();
108 | }
109 |
110 | void UWebSocketConnection::FinishDestroy()
111 | {
112 | Super::FinishDestroy();
113 | delete WebSocket;
114 | WebSocket = NULL;
115 |
116 | }
117 |
118 |
--------------------------------------------------------------------------------
/html5networking.uplugin:
--------------------------------------------------------------------------------
1 | {
2 | "FileVersion" : 3,
3 |
4 | "FriendlyName" : "Experimental HTML5 Networking Plugin",
5 | "Version" : 1,
6 | "VersionName" : "1.0",
7 | "CreatedBy" : "Epic Games, Inc.",
8 | "CreatedByURL" : "http://epicgames.com",
9 | "EngineVersion" : "4.8.0",
10 | "Description" : "HTML5 Networking",
11 | "Category" : "Networking",
12 | "EnabledByDefault" : false,
13 |
14 | "Modules" :
15 | [
16 | {
17 | "Name" : "HTML5Networking",
18 | "Type" : "Runtime",
19 | "WhitelistPlatforms" : [ "Win64", "HTML5" ]
20 | }
21 | ]
22 | }
23 |
--------------------------------------------------------------------------------