├── .gitignore ├── LICENSE ├── Source └── UEWebSocket │ ├── Private │ ├── UEWebSocket.cpp │ ├── UEWebSocketBlueprintFunctionLibrary.cpp │ ├── UEWebSocketPrivatePCH.h │ ├── WebSocket.cpp │ ├── WebSocket.h │ ├── WebSocketServer.cpp │ ├── WebSocketServer.h │ └── WebSocketWrap.cpp │ ├── Public │ ├── IUEWebSocket.h │ ├── UEWebSocketBlueprintFunctionLibrary.h │ ├── WebSocketServerWrap.h │ └── WebSocketWrap.h │ └── UEWebSocket.Build.cs └── UEWebSocket.uplugin /.gitignore: -------------------------------------------------------------------------------- 1 | # Visual Studio 2015 user specific files 2 | .vs/ 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | 22 | # Compiled Static libraries 23 | *.lai 24 | *.la 25 | *.a 26 | *.lib 27 | 28 | # Executables 29 | *.exe 30 | *.out 31 | *.app 32 | *.ipa 33 | 34 | # These project files can be generated by the engine 35 | *.xcodeproj 36 | *.sln 37 | *.suo 38 | *.opensdf 39 | *.sdf 40 | *.VC.opendb 41 | 42 | # Precompiled Assets 43 | SourceArt/**/*.png 44 | SourceArt/**/*.tga 45 | 46 | # Binary Files 47 | Binaries/* 48 | 49 | # Builds 50 | Build/* 51 | 52 | # Don't ignore icon files in Build 53 | !Build/**/*.ico 54 | 55 | # Configuration files generated by the Editor 56 | Saved/* 57 | 58 | # Compiled source files for the engine to use 59 | Intermediate/* 60 | 61 | # Cache files for the editor to use 62 | DerivedDataCache/* 63 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 flufy3d 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Source/UEWebSocket/Private/UEWebSocket.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 1998-2016 Epic Games, Inc. All Rights Reserved. 2 | 3 | #include "UEWebSocketPrivatePCH.h" 4 | 5 | 6 | class FUEWebSocket : public IUEWebSocket 7 | { 8 | /** IModuleInterface implementation */ 9 | virtual void StartupModule() override; 10 | virtual void ShutdownModule() override; 11 | }; 12 | 13 | IMPLEMENT_MODULE( FUEWebSocket, UEWebSocket ) 14 | 15 | 16 | 17 | void FUEWebSocket::StartupModule() 18 | { 19 | // This code will execute after your module is loaded into memory (but after global variables are initialized, of course.) 20 | } 21 | 22 | 23 | void FUEWebSocket::ShutdownModule() 24 | { 25 | // This function may be called during shutdown to clean up your module. For modules that support dynamic reloading, 26 | // we call this function before unloading the module. 27 | } 28 | 29 | 30 | DEFINE_LOG_CATEGORY(LogUEWebSocket); 31 | -------------------------------------------------------------------------------- /Source/UEWebSocket/Private/UEWebSocketBlueprintFunctionLibrary.cpp: -------------------------------------------------------------------------------- 1 | #include "UEWebSocketPrivatePCH.h" 2 | 3 | 4 | UUEWebSocketBlueprintFunctionLibrary::UUEWebSocketBlueprintFunctionLibrary(const class FObjectInitializer& PCIP) 5 | : Super(PCIP) 6 | { 7 | 8 | } 9 | 10 | UWebSocketWrap* UUEWebSocketBlueprintFunctionLibrary::NewWebSocket(UObject* WorldContextObject) 11 | { 12 | 13 | UWorld* World = GEngine->GetWorldFromContextObject(WorldContextObject); 14 | UWebSocketWrap* tempObject = Cast(StaticConstructObject_Internal(UWebSocketWrap::StaticClass())); 15 | 16 | return tempObject; 17 | 18 | } 19 | -------------------------------------------------------------------------------- /Source/UEWebSocket/Private/UEWebSocketPrivatePCH.h: -------------------------------------------------------------------------------- 1 | // Copyright 1998-2016 Epic Games, Inc. All Rights Reserved. 2 | #pragma once 3 | #include "IUEWebSocket.h" 4 | 5 | // You should place include statements to your module's private header files here. You only need to 6 | // add includes for headers that are used in most of your module's source files though. 7 | 8 | #include "Core.h" 9 | #include "Engine.h" 10 | 11 | 12 | #include "UEWebSocketBlueprintFunctionLibrary.h" 13 | #include "WebSocketWrap.h" 14 | 15 | 16 | class FMyWebSocket; 17 | class FWebSocketServer; 18 | 19 | typedef struct libwebsocket_context WebSocketInternalContext; 20 | typedef struct libwebsocket WebSocketInternal; 21 | typedef struct libwebsocket_protocols WebSocketInternalProtocol; 22 | 23 | DECLARE_DELEGATE_TwoParams(FWebsocketPacketRecievedCallBack, void* /*Data*/, int32 /*Data Size*/); 24 | DECLARE_DELEGATE_OneParam(FWebsocketClientConnectedCallBack, FMyWebSocket* /*Socket*/); 25 | DECLARE_DELEGATE(FWebsocketInfoCallBack); 26 | 27 | DECLARE_LOG_CATEGORY_EXTERN(LogUEWebSocket, Warning, All); 28 | 29 | -------------------------------------------------------------------------------- /Source/UEWebSocket/Private/WebSocket.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 1998-2016 Epic Games, Inc. All Rights Reserved. 2 | #include "UEWebSocketPrivatePCH.h" 3 | #include "WebSocket.h" 4 | 5 | 6 | #if PLATFORM_WINDOWS 7 | #include "AllowWindowsPlatformTypes.h" 8 | #endif 9 | 10 | 11 | 12 | #include "libwebsockets.h" 13 | //#include "private-libwebsockets.h" 14 | 15 | 16 | #if PLATFORM_WINDOWS 17 | #include "HideWindowsPlatformTypes.h" 18 | #endif 19 | 20 | 21 | 22 | uint8 MYPREPADDING[LWS_SEND_BUFFER_PRE_PADDING]; 23 | uint8 MYPOSTPADDING[LWS_SEND_BUFFER_POST_PADDING]; 24 | 25 | 26 | 27 | static void libwebsocket_debugLogS(int level, const char *line) 28 | { 29 | UE_LOG(LogUEWebSocket, Log, TEXT("client: %s"), ANSI_TO_TCHAR(line)); 30 | } 31 | 32 | 33 | FMyWebSocket::FMyWebSocket(const FString& url, int port) 34 | :IsServerSide(false) 35 | { 36 | 37 | 38 | 39 | #if !UE_BUILD_SHIPPING 40 | lws_set_log_level(LLL_ERR | LLL_WARN | LLL_NOTICE | LLL_DEBUG | LLL_INFO, libwebsocket_debugLogS); 41 | #endif 42 | 43 | Protocols = new libwebsocket_protocols[3]; 44 | FMemory::Memzero(Protocols, sizeof(libwebsocket_protocols) * 3); 45 | 46 | Protocols[0].name = "binary"; 47 | Protocols[0].callback = FMyWebSocket::unreal_networking_client; 48 | Protocols[0].per_session_data_size = 0; 49 | Protocols[0].rx_buffer_size = 10 * 1024 * 1024; 50 | 51 | Protocols[1].name = nullptr; 52 | Protocols[1].callback = nullptr; 53 | Protocols[1].per_session_data_size = 0; 54 | 55 | struct lws_context_creation_info Info; 56 | memset(&Info, 0, sizeof Info); 57 | 58 | Info.port = CONTEXT_PORT_NO_LISTEN; 59 | Info.protocols = &Protocols[0]; 60 | Info.gid = -1; 61 | Info.uid = -1; 62 | Info.user = this; 63 | 64 | Context = libwebsocket_create_context(&Info); 65 | 66 | check(Context); 67 | 68 | Wsi = libwebsocket_client_connect_extended 69 | (Context, 70 | TCHAR_TO_ANSI(*url), 71 | port, 72 | false, "/", TCHAR_TO_ANSI(*url), TCHAR_TO_ANSI(*url), Protocols[1].name, -1,this); 73 | 74 | check(Wsi); 75 | 76 | 77 | 78 | } 79 | 80 | FMyWebSocket::FMyWebSocket(WebSocketInternalContext* InContext, WebSocketInternal* InWsi) 81 | : Context(InContext) 82 | , Wsi(InWsi) 83 | , IsServerSide(true) 84 | , Protocols(nullptr) 85 | { 86 | } 87 | 88 | 89 | bool FMyWebSocket::Send(uint8* Data, uint32 Size) 90 | { 91 | TArray Buffer; 92 | // insert size. 93 | 94 | 95 | //Buffer.Append((uint8*)&MYPREPADDING, sizeof(MYPREPADDING)); 96 | 97 | //this is for continue get data.the data is big ,so need write length in first int32. 98 | //Buffer.Append((uint8*)&Size, sizeof (uint32)); 99 | 100 | 101 | Buffer.Append((uint8*)Data, Size); 102 | 103 | 104 | 105 | //Buffer.Append((uint8*)&MYPOSTPADDING, sizeof(MYPOSTPADDING)); 106 | 107 | 108 | OutgoingBuffer.Add(Buffer); 109 | 110 | return true; 111 | } 112 | 113 | void FMyWebSocket::SetRecieveCallBack(FWebsocketPacketRecievedCallBack CallBack) 114 | { 115 | RecievedCallBack = CallBack; 116 | } 117 | 118 | FString FMyWebSocket::RemoteEndPoint() 119 | { 120 | ANSICHAR Peer_Name[128]; 121 | ANSICHAR Peer_Ip[128]; 122 | libwebsockets_get_peer_addresses(Context, Wsi, libwebsocket_get_socket_fd(Wsi), Peer_Name, sizeof Peer_Name, Peer_Ip, sizeof Peer_Ip); 123 | return FString(Peer_Name); 124 | 125 | } 126 | 127 | 128 | FString FMyWebSocket::LocalEndPoint() 129 | { 130 | return FString(ANSI_TO_TCHAR(libwebsocket_canonical_hostname(Context))); 131 | } 132 | 133 | void FMyWebSocket::Tick() 134 | { 135 | HandlePacket(); 136 | } 137 | 138 | void FMyWebSocket::HandlePacket() 139 | { 140 | 141 | { 142 | libwebsocket_service(Context, 0); 143 | if (!IsServerSide) 144 | libwebsocket_callback_on_writable_all_protocol(&Protocols[0]); 145 | } 146 | 147 | 148 | } 149 | 150 | void FMyWebSocket::Flush() 151 | { 152 | auto PendingMesssages = OutgoingBuffer.Num(); 153 | while (OutgoingBuffer.Num() > 0 && !IsServerSide) 154 | { 155 | 156 | if (Protocols) 157 | libwebsocket_callback_on_writable_all_protocol(&Protocols[0]); 158 | else 159 | libwebsocket_callback_on_writable(Context, Wsi); 160 | 161 | HandlePacket(); 162 | if (PendingMesssages >= OutgoingBuffer.Num()) 163 | { 164 | UE_LOG(LogUEWebSocket, Warning, TEXT("Unable to flush all of OutgoingBuffer in FWebSocket.")); 165 | break; 166 | } 167 | }; 168 | } 169 | 170 | void FMyWebSocket::SetConnectedCallBack(FWebsocketInfoCallBack CallBack) 171 | { 172 | ConnectedCallBack = CallBack; 173 | } 174 | 175 | void FMyWebSocket::SetErrorCallBack(FWebsocketInfoCallBack CallBack) 176 | { 177 | ErrorCallBack = CallBack; 178 | } 179 | 180 | void FMyWebSocket::OnRawRecieve(void* Data, uint32 Size) 181 | { 182 | RecievedCallBack.ExecuteIfBound(Data, Size); 183 | /* this is for continue get data.the data is big ,so need write length in first int32. 184 | 185 | RecievedBuffer.Append((uint8*)Data, Size); // consumes all of Data 186 | while (RecievedBuffer.Num()) 187 | { 188 | uint32 BytesToBeRead = Size; 189 | if (BytesToBeRead <= ((uint32)RecievedBuffer.Num() - sizeof(uint32))) 190 | { 191 | RecievedCallBack.ExecuteIfBound((void*)((uint8*)RecievedBuffer.GetData() + sizeof(uint32)), BytesToBeRead); 192 | RecievedBuffer.RemoveAt(0, sizeof(uint32) + BytesToBeRead ); 193 | } 194 | else 195 | { 196 | break; 197 | } 198 | } 199 | */ 200 | 201 | } 202 | 203 | void FMyWebSocket::OnRawWebSocketWritable(WebSocketInternal* wsi) 204 | { 205 | 206 | if (OutgoingBuffer.Num() == 0) 207 | return; 208 | 209 | TArray & Packet = OutgoingBuffer[0]; 210 | 211 | 212 | uint32 TotalDataSize = Packet.Num(); 213 | 214 | if (TotalDataSize > 2048) 215 | { 216 | UE_LOG(LogUEWebSocket, Error, TEXT("send data size exceed 2048")); 217 | ErrorCallBack.ExecuteIfBound(); 218 | return; 219 | } 220 | 221 | uint8 buf[2048]; 222 | memcpy(buf, Packet.GetData(), TotalDataSize); 223 | 224 | int Sent = libwebsocket_write(Wsi, buf, TotalDataSize, (libwebsocket_write_protocol)LWS_WRITE_TEXT); 225 | if (Sent < 0) 226 | { 227 | ErrorCallBack.ExecuteIfBound(); 228 | return; 229 | } 230 | 231 | 232 | check(Wsi == wsi); 233 | 234 | // this is very inefficient we need a constant size circular buffer to efficiently not do unnecessary allocations/deallocations. 235 | OutgoingBuffer.RemoveAt(0); 236 | 237 | } 238 | 239 | FMyWebSocket::~FMyWebSocket() 240 | { 241 | RecievedCallBack.Unbind(); 242 | Flush(); 243 | if ( !IsServerSide) 244 | { 245 | libwebsocket_context_destroy(Context); 246 | Context = NULL; 247 | delete Protocols; 248 | Protocols = NULL; 249 | } 250 | } 251 | 252 | int FMyWebSocket::unreal_networking_client( 253 | struct libwebsocket_context *Context, 254 | struct libwebsocket *Wsi, 255 | enum libwebsocket_callback_reasons Reason, 256 | void *User, 257 | void *In, 258 | size_t Len) 259 | { 260 | FMyWebSocket* Socket = (FMyWebSocket*)libwebsocket_context_user(Context);; 261 | switch (Reason) 262 | { 263 | case LWS_CALLBACK_CLIENT_ESTABLISHED: 264 | { 265 | Socket->ConnectedCallBack.ExecuteIfBound(); 266 | libwebsocket_set_timeout(Wsi, NO_PENDING_TIMEOUT, 0); 267 | check(Socket->Wsi == Wsi); 268 | } 269 | break; 270 | case LWS_CALLBACK_CLIENT_CONNECTION_ERROR: 271 | { 272 | Socket->ErrorCallBack.ExecuteIfBound(); 273 | return -1; 274 | } 275 | break; 276 | case LWS_CALLBACK_CLIENT_RECEIVE: 277 | { 278 | // push it on the socket. 279 | Socket->OnRawRecieve(In, (uint32)Len); 280 | check(Socket->Wsi == Wsi); 281 | libwebsocket_set_timeout(Wsi, NO_PENDING_TIMEOUT, 0); 282 | break; 283 | } 284 | case LWS_CALLBACK_CLIENT_WRITEABLE: 285 | { 286 | check(Socket->Wsi == Wsi); 287 | Socket->OnRawWebSocketWritable(Wsi); 288 | libwebsocket_callback_on_writable(Context, Wsi); 289 | libwebsocket_set_timeout(Wsi, NO_PENDING_TIMEOUT, 0); 290 | break; 291 | } 292 | case LWS_CALLBACK_CLOSED: 293 | { 294 | Socket->ErrorCallBack.ExecuteIfBound(); 295 | return -1; 296 | } 297 | } 298 | 299 | return 0; 300 | } 301 | 302 | 303 | -------------------------------------------------------------------------------- /Source/UEWebSocket/Private/WebSocket.h: -------------------------------------------------------------------------------- 1 | // Copyright 1998-2016 Epic Games, Inc. All Rights Reserved. 2 | // 3 | // libwebsocket client wrapper. 4 | // 5 | #pragma once 6 | #include "UEWebSocketPrivatePCH.h" 7 | 8 | class FMyWebSocket 9 | { 10 | 11 | public: 12 | 13 | // Initialize as client side socket. 14 | FMyWebSocket(const FString& url,int port); 15 | 16 | // Initialize as server side socket. 17 | FMyWebSocket(WebSocketInternalContext* InContext, WebSocketInternal* Wsi); 18 | 19 | // clean up. 20 | ~FMyWebSocket(); 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 | /** service libwebsocket until outgoing buffer is empty */ 35 | void Flush(); 36 | 37 | /** Helper functions to describe end points. */ 38 | FString RemoteEndPoint(); 39 | FString LocalEndPoint(); 40 | 41 | /* libwebsocket service functions */ 42 | static int unreal_networking_server(struct libwebsocket_context *, struct libwebsocket *wsi, enum libwebsocket_callback_reasons reason, void *user, void *in, size_t len); 43 | static int unreal_networking_client(struct libwebsocket_context *, struct libwebsocket *wsi, enum libwebsocket_callback_reasons reason, void *user, void *in, size_t len); 44 | 45 | private: 46 | 47 | void HandlePacket(); 48 | void OnRawRecieve(void* Data, uint32 Size); 49 | void OnRawWebSocketWritable(WebSocketInternal* wsi); 50 | 51 | /************************************************************************/ 52 | /* Various Socket callbacks */ 53 | /************************************************************************/ 54 | FWebsocketPacketRecievedCallBack RecievedCallBack; 55 | FWebsocketInfoCallBack ConnectedCallBack; 56 | FWebsocketInfoCallBack ErrorCallBack; 57 | 58 | /** Recv and Send Buffers, serviced during the Tick */ 59 | TArray RecievedBuffer; 60 | TArray> OutgoingBuffer; 61 | 62 | /** libwebsocket internal context*/ 63 | WebSocketInternalContext* Context; 64 | 65 | /** libwebsocket web socket */ 66 | WebSocketInternal* Wsi; 67 | 68 | /** libwebsocket Protocols that can be serviced by this implemenation*/ 69 | WebSocketInternalProtocol* Protocols; 70 | 71 | /** Server side socket or client side*/ 72 | bool IsServerSide; 73 | 74 | 75 | friend class FWebSocketServer; 76 | int SockFd; 77 | }; 78 | 79 | 80 | -------------------------------------------------------------------------------- /Source/UEWebSocket/Private/WebSocketServer.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 1998-2016 Epic Games, Inc. All Rights Reserved. 2 | 3 | #include "UEWebSocketPrivatePCH.h" 4 | #include "WebSocketServer.h" 5 | #include "WebSocket.h" 6 | 7 | #if PLATFORM_WINDOWS 8 | #include "AllowWindowsPlatformTypes.h" 9 | #endif 10 | 11 | 12 | #include "libwebsockets.h" 13 | 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 | FMyWebSocket *Socket; // each session is actually a socket to a client 23 | }; 24 | 25 | 26 | // real networking handler. 27 | static int unreal_networking_server( 28 | struct libwebsocket_context *, 29 | struct libwebsocket *wsi, 30 | enum libwebsocket_callback_reasons reason, 31 | void *user, 32 | void *in, 33 | size_t 34 | len 35 | ); 36 | 37 | #if !UE_BUILD_SHIPPING 38 | void libwebsocket_debugLogSS(int level, const char *line) 39 | { 40 | UE_LOG(LogUEWebSocket, Log, TEXT("websocket server: %s"), ANSI_TO_TCHAR(line)); 41 | } 42 | #endif 43 | 44 | 45 | bool FMyWebSocketServer::Init(uint32 Port, FWebsocketClientConnectedCallBack CallBack) 46 | { 47 | 48 | // setup log level. 49 | #if !UE_BUILD_SHIPPING 50 | lws_set_log_level(LLL_ERR | LLL_WARN | LLL_NOTICE | LLL_DEBUG | LLL_INFO, libwebsocket_debugLogSS); 51 | #endif 52 | 53 | Protocols = new libwebsocket_protocols[3]; 54 | FMemory::Memzero(Protocols, sizeof(libwebsocket_protocols) * 3); 55 | 56 | Protocols[0].name = "binary"; 57 | Protocols[0].callback = FMyWebSocket::unreal_networking_server; 58 | Protocols[0].per_session_data_size = sizeof(PerSessionDataServer); 59 | Protocols[0].rx_buffer_size = 10 * 1024 * 1024; 60 | 61 | Protocols[1].name = nullptr; 62 | Protocols[1].callback = nullptr; 63 | Protocols[1].per_session_data_size = 0; 64 | 65 | struct lws_context_creation_info Info; 66 | memset(&Info, 0, sizeof(lws_context_creation_info)); 67 | // look up libwebsockets.h for details. 68 | Info.port = Port; 69 | // we listen on all available interfaces. 70 | Info.iface = NULL; 71 | Info.protocols = &Protocols[0]; 72 | // no extensions 73 | Info.extensions = NULL; 74 | Info.gid = -1; 75 | Info.uid = -1; 76 | Info.options = 0; 77 | // tack on this object. 78 | Info.user = this; 79 | Info.port = Port; 80 | Context = libwebsocket_create_context(&Info); 81 | 82 | if (Context == NULL) 83 | { 84 | return false; // couldn't create a server. 85 | } 86 | 87 | ConnectedCallBack = CallBack; 88 | 89 | 90 | return true; 91 | } 92 | 93 | bool FMyWebSocketServer::Tick() 94 | { 95 | 96 | { 97 | libwebsocket_service(Context, 0); 98 | libwebsocket_callback_on_writable_all_protocol(&Protocols[0]); 99 | } 100 | 101 | return true; 102 | } 103 | 104 | FMyWebSocketServer::FMyWebSocketServer() 105 | {} 106 | 107 | FMyWebSocketServer::~FMyWebSocketServer() 108 | { 109 | 110 | if (Context) 111 | { 112 | 113 | libwebsocket_context_destroy(Context); 114 | Context = NULL; 115 | } 116 | 117 | delete Protocols; 118 | Protocols = NULL; 119 | 120 | } 121 | 122 | FString FMyWebSocketServer::Info() 123 | { 124 | return FString(ANSI_TO_TCHAR(libwebsocket_canonical_hostname(Context))); 125 | 126 | } 127 | 128 | // callback. 129 | 130 | int FMyWebSocket::unreal_networking_server 131 | ( 132 | struct libwebsocket_context *Context, 133 | struct libwebsocket *Wsi, 134 | enum libwebsocket_callback_reasons Reason, 135 | void *User, 136 | void *In, 137 | size_t Len 138 | ) 139 | { 140 | PerSessionDataServer* BufferInfo = (PerSessionDataServer*)User; 141 | FMyWebSocketServer* Server = (FMyWebSocketServer*)libwebsocket_context_user(Context); 142 | 143 | switch (Reason) 144 | { 145 | case LWS_CALLBACK_ESTABLISHED: 146 | { 147 | BufferInfo->Socket = new FMyWebSocket(Context, Wsi); 148 | Server->ConnectedCallBack.ExecuteIfBound(BufferInfo->Socket); 149 | libwebsocket_set_timeout(Wsi, NO_PENDING_TIMEOUT, 0); 150 | } 151 | break; 152 | 153 | case LWS_CALLBACK_RECEIVE: 154 | { 155 | BufferInfo->Socket->OnRawRecieve(In, Len); 156 | libwebsocket_set_timeout(Wsi, NO_PENDING_TIMEOUT, 0); 157 | } 158 | break; 159 | 160 | case LWS_CALLBACK_SERVER_WRITEABLE: 161 | { 162 | BufferInfo->Socket->OnRawWebSocketWritable(Wsi); 163 | libwebsocket_set_timeout(Wsi, NO_PENDING_TIMEOUT, 0); 164 | } 165 | break; 166 | case LWS_CALLBACK_CLIENT_CONNECTION_ERROR: 167 | { 168 | BufferInfo->Socket->ErrorCallBack.ExecuteIfBound(); 169 | } 170 | break; 171 | } 172 | 173 | return 0; 174 | } 175 | 176 | -------------------------------------------------------------------------------- /Source/UEWebSocket/Private/WebSocketServer.h: -------------------------------------------------------------------------------- 1 | // Copyright 1998-2016 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 "UEWebSocketPrivatePCH.h" 7 | 8 | class FMyWebSocketServer 9 | { 10 | public: 11 | 12 | FMyWebSocketServer(); 13 | ~FMyWebSocketServer(); 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 FMyWebSocket; 36 | }; 37 | 38 | 39 | -------------------------------------------------------------------------------- /Source/UEWebSocket/Private/WebSocketWrap.cpp: -------------------------------------------------------------------------------- 1 | #include "UEWebSocketPrivatePCH.h" 2 | 3 | #include "WebSocket.h" 4 | 5 | UWebSocketWrap::UWebSocketWrap(const class FObjectInitializer& PCIP) 6 | : Super(PCIP), websocket(nullptr) 7 | { 8 | 9 | 10 | } 11 | void UWebSocketWrap::OnPacketRecieved(void* Data, int32 Count) 12 | { 13 | FString _tmp = FString(Count,ANSI_TO_TCHAR((char*)Data)); 14 | PacketRecievedCallBack.Broadcast(_tmp); 15 | 16 | } 17 | 18 | void UWebSocketWrap::OnPacketRecievedCPP(void* Data, int32 Count) 19 | { 20 | FString _tmp = FString(Count, ANSI_TO_TCHAR((char*)Data)); 21 | PacketRecievedCallBackCPP.ExecuteIfBound(_tmp); 22 | 23 | } 24 | 25 | void UWebSocketWrap::OnConnected() 26 | { 27 | ConnectedCallBack.Broadcast(); 28 | } 29 | 30 | void UWebSocketWrap::OnError() 31 | { 32 | ErrorCallBack.Broadcast(); 33 | } 34 | 35 | void UWebSocketWrap::Init(UObject* WorldContextObject) 36 | { 37 | websocket = new FMyWebSocket(URL,Port); 38 | 39 | FWebsocketPacketRecievedCallBack CallBack; 40 | CallBack.BindUObject(this, &UWebSocketWrap::OnPacketRecieved); 41 | websocket->SetRecieveCallBack(CallBack); 42 | 43 | FWebsocketInfoCallBack connectedCallBack; 44 | connectedCallBack.BindUObject(this, &UWebSocketWrap::OnConnected); 45 | websocket->SetConnectedCallBack(connectedCallBack); 46 | 47 | FWebsocketInfoCallBack errorCallBack; 48 | errorCallBack.BindUObject(this, &UWebSocketWrap::OnError); 49 | websocket->SetErrorCallBack(errorCallBack); 50 | 51 | } 52 | void UWebSocketWrap::Init() 53 | { 54 | websocket = new FMyWebSocket(URL, Port); 55 | 56 | FWebsocketPacketRecievedCallBack CallBack; 57 | CallBack.BindUObject(this, &UWebSocketWrap::OnPacketRecievedCPP); 58 | websocket->SetRecieveCallBack(CallBack); 59 | 60 | FWebsocketInfoCallBack connectedCallBack; 61 | connectedCallBack.BindUObject(this, &UWebSocketWrap::OnConnected); 62 | websocket->SetConnectedCallBack(connectedCallBack); 63 | 64 | FWebsocketInfoCallBack errorCallBack; 65 | errorCallBack.BindUObject(this, &UWebSocketWrap::OnError); 66 | websocket->SetErrorCallBack(errorCallBack); 67 | } 68 | 69 | 70 | void UWebSocketWrap::Send(const FString& data) 71 | { 72 | if (websocket) websocket->Send((uint8*)TCHAR_TO_ANSI(*data), data.Len()); 73 | } 74 | 75 | void UWebSocketWrap::FinishDestroy() 76 | { 77 | Super::FinishDestroy(); 78 | delete websocket; 79 | websocket = nullptr; 80 | } 81 | void UWebSocketWrap::Tick(float DeltaTime) 82 | { 83 | if (websocket) websocket->Tick(); 84 | } 85 | 86 | bool UWebSocketWrap::IsTickable() const 87 | { 88 | return true; 89 | } 90 | 91 | bool UWebSocketWrap::IsTickableInEditor() const 92 | { 93 | return false; 94 | } 95 | 96 | bool UWebSocketWrap::IsTickableWhenPaused() const 97 | { 98 | return false; 99 | } 100 | 101 | TStatId UWebSocketWrap::GetStatId() const 102 | { 103 | return TStatId(); 104 | } 105 | 106 | UWorld* UWebSocketWrap::GetWorld() const 107 | { 108 | return GetOuter()->GetWorld(); 109 | } -------------------------------------------------------------------------------- /Source/UEWebSocket/Public/IUEWebSocket.h: -------------------------------------------------------------------------------- 1 | // Copyright 1998-2016 Epic Games, Inc. All Rights Reserved. 2 | 3 | #pragma once 4 | 5 | #include "ModuleManager.h" 6 | 7 | 8 | /** 9 | * The public interface to this module. In most cases, this interface is only public to sibling modules 10 | * within this plugin. 11 | */ 12 | class IUEWebSocket : public IModuleInterface 13 | { 14 | 15 | public: 16 | 17 | /** 18 | * Singleton-like access to this module's interface. This is just for convenience! 19 | * Beware of calling this during the shutdown phase, though. Your module might have been unloaded already. 20 | * 21 | * @return Returns singleton instance, loading the module on demand if needed 22 | */ 23 | static inline IUEWebSocket& Get() 24 | { 25 | return FModuleManager::LoadModuleChecked< IUEWebSocket >( "UEWebSocket" ); 26 | } 27 | 28 | /** 29 | * Checks to see if this module is loaded and ready. It is only valid to call Get() if IsAvailable() returns true. 30 | * 31 | * @return True if the module is loaded and ready to use 32 | */ 33 | static inline bool IsAvailable() 34 | { 35 | return FModuleManager::Get().IsModuleLoaded( "UEWebSocket" ); 36 | } 37 | }; 38 | 39 | -------------------------------------------------------------------------------- /Source/UEWebSocket/Public/UEWebSocketBlueprintFunctionLibrary.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | #include "UEWebSocketBlueprintFunctionLibrary.generated.h" 5 | 6 | UCLASS(ClassGroup = UEWebSocket, Blueprintable) 7 | class UUEWebSocketBlueprintFunctionLibrary : public UBlueprintFunctionLibrary 8 | { 9 | 10 | GENERATED_UCLASS_BODY() 11 | 12 | UFUNCTION(BlueprintPure, meta = (HidePin = "WorldContextObject", DefaultToSelf = "WorldContextObject", DisplayName = "Create WebSocket", CompactNodeTitle = "WebSocket", Keywords = "new create WebSocket"), Category = UEWebSocket) 13 | static UWebSocketWrap* NewWebSocket(UObject* WorldContextObject); 14 | 15 | 16 | 17 | }; 18 | 19 | -------------------------------------------------------------------------------- /Source/UEWebSocket/Public/WebSocketServerWrap.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flufy3d/UEWebSocket/b6b147568093d92b091571bc2a9b9b428c0ed99f/Source/UEWebSocket/Public/WebSocketServerWrap.h -------------------------------------------------------------------------------- /Source/UEWebSocket/Public/WebSocketWrap.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "WebSocketWrap.generated.h" 3 | 4 | class FMyWebSocket; 5 | 6 | DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FWebsocketPacketRecievedCallBackBP,const FString&, Data); 7 | DECLARE_DELEGATE_OneParam(FWebsocketPacketRecievedCallBackCPP, const FString&); 8 | 9 | DECLARE_DYNAMIC_MULTICAST_DELEGATE(FWebsocketInfoCallBackBP); 10 | 11 | 12 | UCLASS(ClassGroup = UEWebSocket, Blueprintable) 13 | class UEWEBSOCKET_API UWebSocketWrap : public UObject, public FTickableGameObject 14 | { 15 | GENERATED_BODY() 16 | 17 | UWebSocketWrap(const class FObjectInitializer& PCIP); 18 | 19 | public: 20 | 21 | 22 | // Initialize function, should be called after properties are set 23 | UFUNCTION(BlueprintCallable, Category = "UEWebSocket", meta = (WorldContext = "WorldContextObject")) 24 | void Init(UObject* WorldContextObject); 25 | 26 | 27 | //this is call from CPP 28 | void Init(); 29 | 30 | UFUNCTION(BlueprintCallable, Category = "UEWebSocket") 31 | void Send(const FString& data); 32 | 33 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "UEWebSocket") 34 | FString URL; 35 | 36 | 37 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "UEWebSocket") 38 | int32 Port; 39 | 40 | UPROPERTY(BlueprintAssignable) 41 | FWebsocketInfoCallBackBP ConnectedCallBack; 42 | 43 | UPROPERTY(BlueprintAssignable) 44 | FWebsocketInfoCallBackBP ErrorCallBack; 45 | 46 | UPROPERTY(BlueprintAssignable) 47 | FWebsocketPacketRecievedCallBackBP PacketRecievedCallBack; 48 | 49 | FWebsocketPacketRecievedCallBackCPP PacketRecievedCallBackCPP; 50 | 51 | 52 | 53 | private: 54 | 55 | void OnPacketRecieved(void* Data, int32 Count); 56 | void OnPacketRecievedCPP(void* Data, int32 Count); 57 | 58 | void OnConnected(); 59 | 60 | void OnError(); 61 | 62 | FMyWebSocket* websocket; 63 | 64 | void Tick(float DeltaTime) override; 65 | bool IsTickable() const override; 66 | bool IsTickableInEditor() const override; 67 | bool IsTickableWhenPaused() const override; 68 | TStatId GetStatId() const override; 69 | UWorld* GetWorld() const override; 70 | void FinishDestroy() override; 71 | 72 | }; 73 | -------------------------------------------------------------------------------- /Source/UEWebSocket/UEWebSocket.Build.cs: -------------------------------------------------------------------------------- 1 | // Copyright 1998-2016 Epic Games, Inc. All Rights Reserved. 2 | 3 | namespace UnrealBuildTool.Rules 4 | { 5 | public class UEWebSocket : ModuleRules 6 | { 7 | public UEWebSocket(TargetInfo Target) 8 | { 9 | PublicIncludePaths.AddRange( 10 | new string[] { 11 | // ... add public include paths required here ... 12 | } 13 | ); 14 | 15 | PrivateIncludePaths.AddRange( 16 | new string[] { 17 | "Private", 18 | // ... add other private include paths required here ... 19 | } 20 | ); 21 | 22 | PublicDependencyModuleNames.AddRange( 23 | new string[] 24 | { 25 | "Core", 26 | "CoreUObject", 27 | "Engine" 28 | // ... add other public dependencies that you statically link with here ... 29 | } 30 | ); 31 | 32 | PrivateDependencyModuleNames.AddRange( 33 | new string[] 34 | { 35 | // ... add private dependencies that you statically link with here ... 36 | "libWebSockets" 37 | } 38 | ); 39 | 40 | DynamicallyLoadedModuleNames.AddRange( 41 | new string[] 42 | { 43 | // ... add any modules that your module loads dynamically here ... 44 | } 45 | ); 46 | } 47 | } 48 | } -------------------------------------------------------------------------------- /UEWebSocket.uplugin: -------------------------------------------------------------------------------- 1 | { 2 | "FileVersion" : 3, 3 | "Version" : 1, 4 | "VersionName" : "1.0", 5 | "FriendlyName" : "UE4 WebSocket Plugin", 6 | "Description" : "Websocket plugin for Unreal Engine 4 ", 7 | "Category" : "Network", 8 | "CreatedBy" : "flufy3d", 9 | "CreatedByURL" : "https://github.com/flufy3d/UEWebSocket", 10 | "DocsURL" : "", 11 | "MarketplaceURL" : "", 12 | "SupportURL" : "", 13 | "EnabledByDefault" : false, 14 | "CanContainContent" : false, 15 | "IsBetaVersion" : false, 16 | "Installed" : false, 17 | "Modules" : 18 | [ 19 | { 20 | "Name" : "UEWebSocket", 21 | "Type" : "Runtime", 22 | "LoadingPhase" : "Default" 23 | } 24 | ] 25 | } --------------------------------------------------------------------------------