/// <summary> /// Called when a new web socket connection has been established. /// </summary> /// <param name="webSocketContext">The web socket context.</param> public async override Task WebSocketContext(AspNetWebSocketContext webSocketContext) { byte[] store = null; byte[] receiveBuffer = null; WebSocket webSocket = null; WebSocketClient wsClient = null; TimeoutModel tmConnection = null; TimeoutModel tmExpiry = null; try { // Get the web socket ref. webSocket = webSocketContext.WebSocket; // Random GUID string clientGUID = Guid.NewGuid().ToString(); wsClient = new WebSocketClient() { UniqueID = clientGUID, ApplicationID = clientGUID, Available = false, Broadcast = false, BroadcastAppID = false, HasAccess = false, AccessToken = null }; // Set the buffer. store = new byte[0]; CancellationTokenSource receiveCancelToken = new CancellationTokenSource(); // Connection timeout. tmConnection = new TimeoutModel() { Client = wsClient, Socket = webSocket, Start = DateTime.Now, Timeout = new TimeSpan(0, 0, (int)Global.ClientTimeoutConnect), ReceiveCancelToken = receiveCancelToken }; // Add the client to the collection. bool itemAdded = Global.Clients.TryAdd(wsClient, webSocket); // If a connect timeout exists. if ((int)Global.ClientTimeoutConnect > 0) { // Add timeout connect handler. Global.Timeout.Register(tmConnection, (c, w) => ConnectTimeoutActionHandler(c, w)); } // While the WebSocket connection remains open run a // simple loop that receives data and sends it back. while (webSocket.State == WebSocketState.Open) { receiveBuffer = null; receiveBuffer = new byte[16384]; // Receive the next set of data. ArraySegment <byte> arrayBuffer = new ArraySegment <byte>(receiveBuffer); WebSocketReceiveResult receiveResult = await webSocket.ReceiveAsync(arrayBuffer, receiveCancelToken.Token); // If the connection has been closed. if (receiveResult.MessageType == WebSocketMessageType.Close) { // Exit the loop break; } else { // If a message exists. if (receiveResult.Count > 0) { // If text. if (receiveResult.MessageType == WebSocketMessageType.Text) { // If this is the end of the message. if (receiveResult.EndOfMessage) { // Get the number of bytes sent. byte[] received = receiveBuffer.Take(receiveResult.Count).ToArray(); // Get the complete message. byte[] completeMessage = null; completeMessage = store.CombineParallel(received); string message = System.Text.Encoding.ASCII.GetString(completeMessage); // If requesting application IDs. if (message == "applicationids") { // If no access. if (!wsClient.HasAccess) { // Send a message back. byte[] sendBuffer = System.Text.Encoding.ASCII.GetBytes("{\"response\":\"error\",\"error\":\"Access Denied\"}"); await webSocket.SendAsync(new ArraySegment <byte>(sendBuffer), WebSocketMessageType.Text, true, CancellationToken.None); continue; } // If requesting application IDs. string listText = ""; // For each client. try { // Get a copy of all clients. var copyAllClients = Global.Clients.ToArray(); for (int i = 0; i < copyAllClients.Length; i++) { var u = copyAllClients[i]; // If can braodcast. if (u.Key.BroadcastAppID) { // Add each client. listText += "{\"application\":\"" + u.Key.ApplicationID + "\"},"; } } // Trim end. string listTextTrimed = listText.TrimEnd(new char[] { ',' }); // Send to client byte[] sendBuffer = System.Text.Encoding.ASCII.GetBytes("{\"response\":\"ok\",\"applications\":[" + listTextTrimed + "]}"); await webSocket.SendAsync(new ArraySegment <byte>(sendBuffer), WebSocketMessageType.Text, true, CancellationToken.None); } catch { } } else if (message == "uniqueids") { // If no access. if (!wsClient.HasAccess) { // Send a message back. byte[] sendBuffer = System.Text.Encoding.ASCII.GetBytes("{\"response\":\"error\",\"error\":\"Access Denied\"}"); await webSocket.SendAsync(new ArraySegment <byte>(sendBuffer), WebSocketMessageType.Text, true, CancellationToken.None); continue; } // If requesting unique IDs. string listText = ""; // For each client. try { // Get a copy of all clients. var copyAllClients = Global.Clients.ToArray(); for (int i = 0; i < copyAllClients.Length; i++) { var u = copyAllClients[i]; // If can braodcast. if (u.Key.Broadcast) { // Add each client. listText += "{\"unique\":\"" + u.Key.UniqueID + "\"},"; } } // Trim end. string listTextTrimed = listText.TrimEnd(new char[] { ',' }); // Send to client byte[] sendBuffer = System.Text.Encoding.ASCII.GetBytes("{\"response\":\"ok\",\"uniques\":[" + listTextTrimed + "]}"); await webSocket.SendAsync(new ArraySegment <byte>(sendBuffer), WebSocketMessageType.Text, true, CancellationToken.None); } catch { } } else if (message == "uniqueapplication") { // If no access. if (!wsClient.HasAccess) { // Send a message back. byte[] sendBuffer = System.Text.Encoding.ASCII.GetBytes("{\"response\":\"error\",\"error\":\"Access Denied\"}"); await webSocket.SendAsync(new ArraySegment <byte>(sendBuffer), WebSocketMessageType.Text, true, CancellationToken.None); continue; } // If requesting unique and application group pair. string listText = ""; // For each client. try { // Get a copy of all clients. var copyAllClients = Global.Clients.ToArray(); for (int i = 0; i < copyAllClients.Length; i++) { var u = copyAllClients[i]; // If can braodcast. if (u.Key.BroadcastAppID && u.Key.Broadcast) { // Add each client. listText += "{\"unique\":\"" + u.Key.UniqueID + "\",\"application\":\"" + u.Key.ApplicationID + "\"},"; } } // Trim end. string listTextTrimed = listText.TrimEnd(new char[] { ',' }); // Send to client byte[] sendBuffer = System.Text.Encoding.ASCII.GetBytes("{\"response\":\"ok\",\"groups\":[" + listTextTrimed + "]}"); await webSocket.SendAsync(new ArraySegment <byte>(sendBuffer), WebSocketMessageType.Text, true, CancellationToken.None); } catch { } } else { try { // Get the JSON data. JsonGenerator gen = new JsonGenerator(message); gen.Namespace = "Lake.WebSocketServer"; gen.RootClassName = "RootWebSocketData"; var extract = gen.Extract(); // Search for the contact. bool foundContact = false; var contact = gen.GetContactData(out foundContact); // Search for the client. bool foundClient = false; var client = gen.GetClientData(out foundClient); // Then change the client details. if (foundClient) { // Change. wsClient.UniqueID = client.UniqueID; wsClient.ApplicationID = client.ApplicationID; wsClient.Available = client.Available; wsClient.Broadcast = client.Broadcast; wsClient.BroadcastAppID = client.BroadcastAppID; wsClient.AccessToken = client.AccessToken; // If nothing has been sent. if (String.IsNullOrEmpty(client.UniqueID) || String.IsNullOrEmpty(client.ApplicationID)) { // Send to client byte[] sendBufferNoData = System.Text.Encoding.ASCII.GetBytes("{\"response\":\"ok\",\"settings\":false}"); await webSocket.SendAsync(new ArraySegment <byte>(sendBufferNoData), WebSocketMessageType.Text, true, CancellationToken.None); continue; } // Send to client byte[] sendBuffer = System.Text.Encoding.ASCII.GetBytes("{\"response\":\"ok\",\"settings\":true}"); await webSocket.SendAsync(new ArraySegment <byte>(sendBuffer), WebSocketMessageType.Text, true, CancellationToken.None); // If no access. if (!wsClient.HasAccess) { try { // Make a connection to the access token verification service. using (HttpClient httpClient = new HttpClient()) { // Add header with access token. string authValueBearer = "Bearer "; string authValueToken = wsClient.AccessToken; string authValue = authValueBearer + authValueToken; httpClient.DefaultRequestHeaders.Add("Authorization", authValue); httpClient.DefaultRequestHeaders.Add("UniqueID", wsClient.UniqueID); httpClient.DefaultRequestHeaders.Add("ApplicationID", wsClient.ApplicationID); // Verify the access token for the client. HttpResponseMessage response = await httpClient.GetAsync(new Uri(Global.AccessTokenVerifyURL)); if (response.IsSuccessStatusCode) { // Get the json response. string jsonData = await response.Content.ReadAsStringAsync(); // Get the JSON data. JsonGenerator genAccess = new JsonGenerator(jsonData); genAccess.Namespace = "Lake.WebSocketServer"; genAccess.RootClassName = "RootWebSocketData"; var extractAccess = genAccess.Extract(); // Search for the access token. bool foundAccessToken = false; var accessToken = genAccess.GetAccessTokenData(out foundAccessToken); // If the access token has been found. if (foundAccessToken) { // Has access. bool hasAccess = accessToken.Grant; if (hasAccess) { // Should the uniqueid be matched with what is in the returned token // and what was entered by the user. if (accessToken.UniqueIDMatch) { // If not the same. if (accessToken.UniqueID != wsClient.UniqueID) { // No access is allowed. hasAccess = false; } } } // Grant or not. wsClient.HasAccess = hasAccess; if (hasAccess) { try { // Expiry timeout. tmExpiry = new TimeoutModel() { Client = wsClient, Socket = webSocket, Start = DateTime.Now, Timeout = new TimeSpan(0, (int)accessToken.Expiry, 0), ReceiveCancelToken = receiveCancelToken }; // If an expiry exists. if (accessToken.Expiry > 0) { // Add timeout connect handler. Global.Timeout.Register(tmExpiry, (c, w) => ExpiryTimeoutActionHandler(c, w)); } // Remove connection timeout. // The client has access. Global.Timeout.Unregister(tmConnection); } catch { } } } } } } catch (Exception) { // Send a message back. byte[] sendBufferNoAccess = System.Text.Encoding.ASCII.GetBytes("{\"response\":\"error\",\"error\":\"Unable to grant access\"}"); await webSocket.SendAsync(new ArraySegment <byte>(sendBufferNoAccess), WebSocketMessageType.Text, true, CancellationToken.None); try { // Send close the connection. await webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Unable to grant access", CancellationToken.None); } catch { } } } } else { // If no access. if (!wsClient.HasAccess) { // Send a message back. byte[] sendBuffer = System.Text.Encoding.ASCII.GetBytes("{\"response\":\"error\",\"error\":\"Access Denied\"}"); await webSocket.SendAsync(new ArraySegment <byte>(sendBuffer), WebSocketMessageType.Text, true, CancellationToken.None); continue; } // If contact details have been sent. if (foundContact) { try { // Contact; bool contactMatchFound = false; bool contactAvailable = false; KeyValuePair <WebRTCSocket.WebSocketClient, WebSocket> contactMatch = new KeyValuePair <WebSocketClient, WebSocket>(); try { // Get a copy of all clients. var copyAllClients = Global.Clients.ToArray(); for (int i = 0; i < copyAllClients.Length; i++) { var u = copyAllClients[i]; if ((u.Key.UniqueID == contact.UniqueID) && (u.Key.ApplicationID == contact.ApplicationID)) { // Found, contact is also found is available. contactMatchFound = true; contactAvailable = u.Key.Available; contactMatch = u; break; } } } catch (Exception) { // No match. contactMatchFound = false; } // If the contact has been found and is available. if (contactMatchFound && contactAvailable) { // Send to client byte[] sendBuffer = System.Text.Encoding.ASCII.GetBytes("{\"response\":\"ok\",\"available\":true}"); await webSocket.SendAsync(new ArraySegment <byte>(sendBuffer), WebSocketMessageType.Text, true, CancellationToken.None); // Replace the contact properties. gen.Replace(new JsonNameValue[] { new WebRTCSocket.JsonNameValue() { Name = "contactUniqueID", Value = wsClient.UniqueID }, new WebRTCSocket.JsonNameValue() { Name = "contactApplicationID", Value = wsClient.ApplicationID } }); // Add the response. gen.Create(new JsonNameValue[] { new WebRTCSocket.JsonNameValue() { Name = "response", Value = "ok" }, new WebRTCSocket.JsonNameValue() { Name = "available", Value = true } }); extract = gen.Extract(); var jsonDataNew = gen.GetJson(); byte[] sendBufferContact = System.Text.Encoding.ASCII.GetBytes(jsonDataNew); // Send the client data to the contact. await contactMatch.Value.SendAsync(new ArraySegment <byte>(sendBufferContact), WebSocketMessageType.Text, true, CancellationToken.None); } else { // If the contact has been found and is not available. if (contactMatchFound && !contactAvailable) { // Send to client byte[] sendBuffer = System.Text.Encoding.ASCII.GetBytes("{\"response\":\"ok\",\"available\":false}"); await webSocket.SendAsync(new ArraySegment <byte>(sendBuffer), WebSocketMessageType.Text, true, CancellationToken.None); } else { // Indicate to the client that we are searching. byte[] sendBuffer = System.Text.Encoding.ASCII.GetBytes("{\"response\":\"error\",\"error\":\"No contacts, searching\"}"); await webSocket.SendAsync(new ArraySegment <byte>(sendBuffer), WebSocketMessageType.Text, true, CancellationToken.None); // If broadcast enabled. if (Global.UdpBroadcastEnabled) { // The contact has not been found. // Broadcast to servers asking where // this contact is located. // Add the response. gen.Create(new JsonNameValue[] { new WebRTCSocket.JsonNameValue() { Name = "response", Value = "ok" }, new WebRTCSocket.JsonNameValue() { Name = "available", Value = false }, new WebRTCSocket.JsonNameValue() { Name = "error", Value = "" }, new WebRTCSocket.JsonNameValue() { Name = "serverID", Value = Global.ServerID }, new WebRTCSocket.JsonNameValue() { Name = "uniqueID", Value = wsClient.UniqueID }, new WebRTCSocket.JsonNameValue() { Name = "applicationID", Value = wsClient.ApplicationID } }); // Get the new JSON data. extract = gen.Extract(); var jsonDataNew = gen.GetJson(); // Broadcast. Global.UdpSocket.Broadcast(jsonDataNew, Global.UdpBroadcastAddress, Global.UdpBroadcastMask, wsClient, contact); } } } } catch { // Send to client byte[] sendBuffer = System.Text.Encoding.ASCII.GetBytes("{\"response\":\"error\",\"error\":\"No contacts, searching\"}"); await webSocket.SendAsync(new ArraySegment <byte>(sendBuffer), WebSocketMessageType.Text, true, CancellationToken.None); } } } } catch { // Send to client byte[] sendBuffer = System.Text.Encoding.ASCII.GetBytes("{\"response\":\"error\",\"error\":\"Unable to read request\"}"); await webSocket.SendAsync(new ArraySegment <byte>(sendBuffer), WebSocketMessageType.Text, true, CancellationToken.None); } } store = null; received = null; store = new byte[0]; completeMessage = null; } else { // Get the number of bytes sent. byte[] received = receiveBuffer.Take(receiveResult.Count).ToArray(); // Store the data until the // end of the message. byte[] temp = null; temp = store.CombineParallel(received); // Store the data until the end. store = temp; temp = null; received = null; } } else { // Exit the loop break; } } } } // Cancel the receive request. if (webSocket.State != WebSocketState.Open) { // Cancel the receive request. receiveCancelToken.Cancel(); } } catch (Exception) { } finally { // Clean-up connection timeout. if (tmConnection != null) { try { // Remove connection timeout. Global.Timeout.Unregister(tmConnection); } catch { } } // Clean-up expiry timeout. if (tmExpiry != null) { try { // Remove connection timeout. Global.Timeout.Unregister(tmExpiry); } catch { } } // Clean up by disposing the WebSocket client. if (wsClient != null) { try { // Remove the client from the list. Global.Clients.TryRemove(wsClient, out webSocket); } catch { } } // Clean up by disposing the WebSocket. if (webSocket != null) { try { // Abort the operation. webSocket.Abort(); } catch { } } store = null; receiveBuffer = null; webSocket = null; wsClient = null; tmConnection = null; tmExpiry = null; } }
/// <summary> /// Broadcast to subnet (e.g. IPAddress 192.168.1.10 with SubnetMask 255.255.0.0 will result /// in sending to all hosts with IPAddress 192.168.0.1 to 192.168.254.254). /// </summary> /// <param name="data">The data to send.</param> /// <param name="baseIPAddress">The base IP address (e.g. 192.168.1.10)</param> /// <param name="IPSubnetMask">The subnet-mask to apply on the IP address (e.g. 255.255.0.0)</param> /// <param name="wsClient">The WebSocket client.</param> /// <param name="wsContact">The WebSocket contact.</param> public async void Broadcast(string data, string baseIPAddress, string IPSubnetMask, WebSocketClient wsClient, WebSocketContact wsContact) { // If started. if (_started && _enabled) { string udpAddress = baseIPAddress; string udpMask = IPSubnetMask; // If client location request enabled. if (Global.ClientLocationRequestEnabled) { try { // Make a connection to the access token verification service. using (HttpClient httpClient = new HttpClient()) { // Add header with access token. string authValueBearer = "Bearer "; string authValueToken = wsClient.AccessToken; string authValue = authValueBearer + authValueToken; httpClient.DefaultRequestHeaders.Add("Authorization", authValue); httpClient.DefaultRequestHeaders.Add("UniqueID", wsClient.UniqueID); httpClient.DefaultRequestHeaders.Add("ApplicationID", wsClient.ApplicationID); httpClient.DefaultRequestHeaders.Add("ContactUniqueID", wsContact.UniqueID); httpClient.DefaultRequestHeaders.Add("ContactApplicationID", wsContact.ApplicationID); // Verify the access token for the client. HttpResponseMessage response = await httpClient.GetAsync(new Uri(Global.ClientLocationRequestURL)); if (response.IsSuccessStatusCode) { // Get the json response. string jsonData = await response.Content.ReadAsStringAsync(); // Get the JSON data. JsonGenerator genAccess = new JsonGenerator(jsonData); genAccess.Namespace = "Lake.WebSocketServer"; genAccess.RootClassName = "RootWebSocketData"; var extractAccess = genAccess.Extract(); // Search for the client loaction. bool foundClientLocation = false; var clientLocation = genAccess.GetClientLocation(out foundClientLocation); // If the client location has been found. if (foundClientLocation) { udpAddress = clientLocation.Address; udpMask = clientLocation.Mask; } } } } catch { } } // Open the client. using (UdpClient client = new UdpClient()) { // Enable broadcasting. client.EnableBroadcast = true; // If either is empty. if (String.IsNullOrEmpty(udpAddress) || String.IsNullOrEmpty(udpMask)) { // If data exists. if (!String.IsNullOrEmpty(data)) { // Broadcast to all. byte[] toSent = System.Text.Encoding.ASCII.GetBytes(data); try { // Sent the message. IPEndPoint endPointAll = new IPEndPoint(IPAddress.Broadcast, _broadcastListenerPort); int sent = await client.SendAsync(toSent, toSent.Length, endPointAll); } catch { } } } else { // Get the IP address. IPAddress address = null; bool isIP = IPAddress.TryParse(udpAddress, out address); // Get the subnet mask. IPAddress mask = null; bool isIPMask = IPAddress.TryParse(udpMask, out mask); // If both are valid. if (isIP && isIPMask) { // If data exists. if (!String.IsNullOrEmpty(data)) { // Broadcast to all. byte[] toSent = System.Text.Encoding.ASCII.GetBytes(data); try { // Broadcast to subnet. IPAddress broadcast = GetBroadcastAddress(address, mask); IPEndPoint endPointSub = new IPEndPoint(broadcast, _broadcastListenerPort); int sent = await client.SendAsync(toSent, toSent.Length, endPointSub); } catch { } } } } } } }
/// <summary> /// Get the client data. /// </summary> /// <param name="found">True if found; else false.</param> /// <returns>The client data.</returns> public WebSocketClient GetClientData(out bool found) { found = false; WebSocketClient client = new WebSocketClient(); try { // Get the list. foreach (JsonType item in _types) { // For each field. foreach (JsonFieldInfo field in item.Fields) { // If found contact unique id. if (field.JsonMemberName == "uniqueID") { found = true; client.UniqueID = field.Jobjects[0].ToString(); } // If found contact application id. if (field.JsonMemberName == "applicationID") { found = true; client.ApplicationID = field.Jobjects[0].ToString(); } // If found contact available. if (field.JsonMemberName == "available") { found = true; bool available = false; if (Boolean.TryParse(field.Jobjects[0].ToString(), out available)) { client.Available = available; } } // If found contact broadcast. if (field.JsonMemberName == "broadcast") { found = true; bool broadcast = false; if (Boolean.TryParse(field.Jobjects[0].ToString(), out broadcast)) { client.Broadcast = broadcast; } } // If found contact broadcastAppID. if (field.JsonMemberName == "broadcastAppID") { found = true; bool broadcastAppID = false; if (Boolean.TryParse(field.Jobjects[0].ToString(), out broadcastAppID)) { client.BroadcastAppID = broadcastAppID; } } // If found access token. if (field.JsonMemberName == "accessToken") { found = true; client.AccessToken = field.Jobjects[0].ToString(); } } } } catch { } // Return the client. return(client); }