private async Task HandlePeripheralMessage(JsonApiObject message, CancellationToken token) { PeripheralRequestCode msgCode; try { msgCode = Enum.Parse <PeripheralRequestCode>(message.message_code); } catch (Exception) { await _socket.SendJson(SharedJsonApiObjectFactory.CreateError($"{message.message_code} is not a valid message code (or I forgot it)."), token); return; } switch (msgCode) { case PeripheralRequestCode.get_pairing_code: string pairingCode; ActivePairingCode dbCode = _db.ActivePairingCodes.SingleOrDefault(c => c.PeripheralId == Device.Id); if (dbCode != null) { pairingCode = dbCode.Code; } else { pairingCode = Cryptography.CreatePairingCode(); var codeEntry = new ActivePairingCode { Code = pairingCode, PeripheralId = Device.Id }; _db.ActivePairingCodes.Add(codeEntry); _db.SaveChanges(); } await _socket.SendJson(PeripheralJsonApiObjectFactory.CreateGetPairingCodeResponse(pairingCode), token); break; default: await _socket.SendJson(SharedJsonApiObjectFactory.CreateError($"Function {msgCode.ToString()} not implemented yet."), token); _logger.LogWarning($"PeripheralRequestCode.{msgCode.ToString()} not implemented."); break; } }
private async Task <bool> HandleSharedMessage(JsonApiObject message, CancellationToken token) { SharedJsonRequestCode msgCode; try { msgCode = Enum.Parse <SharedJsonRequestCode>(message.message_code); } catch (Exception) { return(false); } switch (msgCode) { case SharedJsonRequestCode.login: case SharedJsonRequestCode.register: await _socket.SendJson( SharedJsonApiObjectFactory.CreateError("You can't login while you're logged in ..."), token); break; case SharedJsonRequestCode.set_own_name: if (message.data.TryGetValue("name", out string newName)) { if (string.IsNullOrWhiteSpace(newName)) { await _socket.SendJson( SharedJsonApiObjectFactory.CreateChangeOwnNameResponse(false, _device.Name)); } else { _db.Hosts.Find(_device.Id).Name = newName; _db.SaveChanges(); await _socket.SendJson(SharedJsonApiObjectFactory.CreateChangeOwnNameResponse(true, newName)); } } else { await _socket.SendJson(SharedJsonApiObjectFactory.CreateError("name not defined")); } break; default: throw new ArgumentOutOfRangeException(); } return(true); }
private async Task <WebSocketCloseStatus> LoginDevice(HttpContext context, WebSocket socket, byte[] buffer, RegisteredDevice device, AnperiDbContext dbContext) { await socket.SendJson(SharedJsonApiObjectFactory.CreateLoginResponse(true, device.Name)); List <AuthenticatedWebSocketConnection> connectedPairedDevices = await GetOnlinePairedDevices(device, dbContext); var connection = new AuthenticatedWebSocketConnection(context, socket, buffer, device, dbContext, _logger, this, connectedPairedDevices); lock (_syncRootActiveConnections) { _activeConnections.Add(connection.Device.Id, connection); } WebSocketCloseStatus closeStatus; try { await OnDeviceLoggedIn(connection, dbContext); closeStatus = await connection.Run(_options.Value.RequestCancelToken); } catch (WebSocketException se) { if (!(se.InnerException is BadHttpRequestException)) { throw; } closeStatus = WebSocketCloseStatus.Empty; _logger.LogWarning( $"BadHttpRequestException occured while handling a websocket: {se.Message} -> {se.InnerException.Message}"); } finally { if (!connection.IsAborted) { await RemoveLoggedInDevice(connection, dbContext); } } return(closeStatus); }
private async Task HandleHostMessage(JsonApiObject message, CancellationToken token) { HostRequestCode msgCode; try { msgCode = Enum.Parse <HostRequestCode>(message.message_code); } catch (Exception) { await _socket.SendJson(SharedJsonApiObjectFactory.CreateError($"{message.message_code} is not a valid message code (or I forgot it)."), token); return; } switch (msgCode) { case HostRequestCode.pair: if (!message.data.TryGetValue("code", out string code)) { await _socket.SendJson( SharedJsonApiObjectFactory.CreateError("Parameter code not set or null."), token); return; } try { ActivePairingCode pairingCode = _db.ActivePairingCodes.SingleOrDefault(p => p.Code.Equals(code)); if (pairingCode == null) { await _socket.SendJson( SharedJsonApiObjectFactory.CreateError("Pairing code was not valid."), token); return; } Peripheral deviceToPair = _db.Peripherals.Find(pairingCode.PeripheralId); if (deviceToPair != null) { if (deviceToPair.PairedDevices.All(hp => hp.PeripheralId != deviceToPair.Id)) { deviceToPair.PairedDevices.Add(new HostPeripheral { HostId = Device.Id, PeripheralId = deviceToPair.Id }); _db.ActivePairingCodes.Remove(pairingCode); } } else { await _socket.SendJson( SharedJsonApiObjectFactory.CreateError( "The device you want to pair isn't known to me :(")); return; } _db.Remove(pairingCode); _db.SaveChanges(); AuthenticatedWebSocketConnection conn = _anperiManager.GetConnectionForId(deviceToPair.Id); if (conn != null) { OnPairedDeviceLogin(null, new AuthenticatedWebSocketEventArgs(conn)); } await _socket.SendJson(HostJsonApiObjectFactory.CreatePairingResponse(true, deviceToPair.Id)); } catch (Exception e) { await _socket.SendJson( SharedJsonApiObjectFactory.CreateError($"Internal error handling this request: {e.GetType()} - {e.Message}"), token); } break; case HostRequestCode.unpair: if (message.data.TryGetValue("id", out int peripheralId)) { HostPeripheral connection = _db.HostPeripherals.SingleOrDefault(hp => hp.HostId == _device.Id && hp.PeripheralId == peripheralId); if (connection != null) { try { _db.HostPeripherals.Remove(connection); (_device as Host)?.PairedDevices.Remove(connection); _db.SaveChanges(); AuthenticatedWebSocketConnection loggedInPeripheral; lock (_syncRootLoggedInPairedDevices) { loggedInPeripheral = _loggedInPairedDevices.SingleOrDefault(c => c.Device.Id == peripheralId); } if (loggedInPeripheral != null) { OnPairedDeviceLogoff(null, new AuthenticatedWebSocketEventArgs(loggedInPeripheral)); } await _socket.SendJson( HostJsonApiObjectFactory.CreateUnpairFromPeripheralResponse(true)); } catch (Exception ex) { _logger.LogError(ex, "Error unpairing devices."); await _socket.SendJson( HostJsonApiObjectFactory.CreateUnpairFromPeripheralResponse(false)); } } } else { await _socket.SendJson(SharedJsonApiObjectFactory.CreateError("id not defined")); } break; case HostRequestCode.get_available_peripherals: IEnumerable <Peripheral> peripherals = _db.HostPeripherals.Where(hp => hp.HostId == _device.Id).Select(p => p.Peripheral); IEnumerable <HostJsonApiObjectFactory.ApiPeripheral> apiPeris = peripherals.Select( p => new HostJsonApiObjectFactory.ApiPeripheral { id = p.Id, name = p.Name }).ToList(); lock (_syncRootLoggedInPairedDevices) { _loggedInPairedDevices.ForEach(d => { apiPeris.Single(p => p.id == d.Device.Id).online = true; }); } await _socket.SendJson( HostJsonApiObjectFactory.CreateAvailablePeripheralResponse(apiPeris), token); break; case HostRequestCode.connect_to_peripheral: if (message.data.TryGetValue("id", out int id)) { if (!_db.HostPeripherals.Any(hp => hp.HostId == _device.Id && hp.PeripheralId == id)) { await _socket.SendJson( HostJsonApiObjectFactory.CreateConnectToPeripheralResponse(false, -1)); return; } AuthenticatedWebSocketConnection conn = _anperiManager.GetConnectionForId(id); if (conn != null) { if (await conn.PartnerConnect(this)) { lock (_syncRootPartner) { _partner = conn; } await _socket.SendJson( HostJsonApiObjectFactory.CreateConnectToPeripheralResponse(true, id)); } else { await _socket.SendJson(HostJsonApiObjectFactory.CreateConnectToPeripheralResponse(false, -1)); } } else { await _socket.SendJson(HostJsonApiObjectFactory.CreateConnectToPeripheralResponse(false, -1)); } } else { await _socket.SendJson(HostJsonApiObjectFactory.CreateConnectToPeripheralResponse(false, -1)); } break; case HostRequestCode.disconnect_from_peripheral: lock (_syncRootPartner) { _partner?.PartnerCloseConnection(); _partner = null; } await _socket.SendJson(HostJsonApiObjectFactory.CreateDisconnectFromPeripheralResponse(true), token); break; case HostRequestCode.change_peripheral_name: if (message.data.TryGetValue("name", out string newName) && message.data.TryGetValue("id", out int periId)) { HostPeripheral hp = _db.HostPeripherals.SingleOrDefault(e => e.HostId == _device.Id && e.PeripheralId == periId); if (hp == null) { await _socket.SendJson( HostJsonApiObjectFactory.CreateChangeNameResponse(false, null, periId)); return; } if (string.IsNullOrWhiteSpace(newName)) { await _socket.SendJson( HostJsonApiObjectFactory.CreateChangeNameResponse(false, hp.Peripheral.Name, periId)); return; } Peripheral p = hp.Peripheral; p.Name = newName; _db.SaveChanges(); await _socket.SendJson( HostJsonApiObjectFactory.CreateChangeNameResponse(true, newName, periId)); } else { await _socket.SendJson(SharedJsonApiObjectFactory.CreateError("name or id not defined")); } break; default: await _socket.SendJson(SharedJsonApiObjectFactory.CreateError($"Function {msgCode.ToString()} not implemented yet."), token); _logger.LogWarning($"HostRequestCode.{msgCode.ToString()} not implemented."); break; } }
public async Task <WebSocketCloseStatus> Run(CancellationToken token) { WebSocketApiResult apiObjectResult = await _socket.ReceiveApiMessage(_buffer, token); while (!apiObjectResult.SocketResult.CloseStatus.HasValue && !token.IsCancellationRequested) { if (apiObjectResult.Obj == null) { await _socket.SendJson( SharedJsonApiObjectFactory.CreateError(apiObjectResult.JsonException.Message), token); } else { switch (apiObjectResult.Obj.context) { case JsonApiContextTypes.server: if (!(await HandleSharedMessage(apiObjectResult.Obj, token))) { switch (Device) { case Host _: await HandleHostMessage(apiObjectResult.Obj, token); break; case Peripheral _: await HandlePeripheralMessage(apiObjectResult.Obj, token); break; } } break; case JsonApiContextTypes.device: if (_partner != null) { _partner?.PartnerSendMessage(apiObjectResult.Obj); } else { await _socket.SendJson( SharedJsonApiObjectFactory.CreateError( "You don't have a partner, annoy somebody else >.>")); } break; } } try { apiObjectResult = await _socket.ReceiveApiMessage(_buffer, token); } catch (WebSocketException wse) { _logger.LogWarning(wse, "WebSocketException occured while receiving message."); apiObjectResult = new WebSocketApiResult(); apiObjectResult.SocketResult = new WebSocketReceiveResult(0, WebSocketMessageType.Binary, true, WebSocketCloseStatus.Empty, "WebSocketException thrown while receiving message."); } catch (Exception ex) { _logger.LogError(ex, "Error handling request."); apiObjectResult = new WebSocketApiResult(); apiObjectResult.SocketResult = new WebSocketReceiveResult(0, WebSocketMessageType.Binary, true, WebSocketCloseStatus.InternalServerError, "Exception thrown while receiving message."); } } return(apiObjectResult.SocketResult.CloseStatus ?? WebSocketCloseStatus.NormalClosure); }
private async Task HandleWebSocket(HttpContext ctx, AnperiDbContext dbContext) { WebSocket socket = await ctx.WebSockets.AcceptWebSocketAsync(); var buffer = new byte[_options.Value.WsBufferSize]; WebSocketApiResult apiObjectResult = await socket.ReceiveApiMessage(buffer, _options.Value.RequestCancelToken); bool authFailed = true; WebSocketCloseStatus closeStatus = WebSocketCloseStatus.Empty; if (apiObjectResult.Obj == null) { await socket.SendJson( SharedJsonApiObjectFactory.CreateError(apiObjectResult.JsonException.Message), _options.Value.RequestCancelToken); } else { if (apiObjectResult.Obj.context == JsonApiContextTypes.server && apiObjectResult.Obj.message_type == JsonApiMessageTypes.request) { apiObjectResult.Obj.data.TryGetValue(nameof(JsonLoginData.device_type), out string typeString); if (Enum.TryParse(typeString, out SharedJsonDeviceType type) && Enum.TryParse(apiObjectResult.Obj.message_code, out SharedJsonRequestCode code)) { RegisteredDevice device = null; switch (code) { case SharedJsonRequestCode.login: if (!apiObjectResult.Obj.data.TryGetValue("token", out string token)) { await socket.SendJson( SharedJsonApiObjectFactory.CreateError("Error retrieving token from request.")); } else { switch (type) { case SharedJsonDeviceType.host: device = dbContext.Hosts.SingleOrDefault(d => d.Token == token); break; case SharedJsonDeviceType.peripheral: device = dbContext.Peripherals.SingleOrDefault(d => d.Token == token); break; default: await socket.SendJson( SharedJsonApiObjectFactory.CreateError( "You need to be a host or peripheral.")); break; } if (device != null) { AuthenticatedWebSocketConnection activeConn; lock (_activeConnections) { _activeConnections.TryGetValue(device.Id, out activeConn); } if (activeConn != null) { activeConn.Abort(); await RemoveLoggedInDevice(activeConn, dbContext); } closeStatus = await LoginDevice(ctx, socket, buffer, device, dbContext); authFailed = false; } } break; case SharedJsonRequestCode.register: switch (type) { case SharedJsonDeviceType.host: device = new Host(); break; case SharedJsonDeviceType.peripheral: device = new Peripheral(); break; default: await socket.SendJson( SharedJsonApiObjectFactory.CreateError( "You need to be a host or peripheral.")); break; } if (device != null) { device.Token = Cryptography.CreateAuthToken(); if (apiObjectResult.Obj.data.TryGetValue("name", out string name)) { device.Name = name; } else { await socket.SendJson( SharedJsonApiObjectFactory.CreateError( "A device registration requires a name!")); } if (string.IsNullOrWhiteSpace(device.Name)) { device.Name = "devices want a name :("; } dbContext.RegisteredDevices.Add(device); await dbContext.SaveChangesAsync(); await socket.SendJson( SharedJsonApiObjectFactory.CreateRegisterResponse(device.Token, device.Name)); closeStatus = await LoginDevice(ctx, socket, buffer, device, dbContext); authFailed = false; } break; default: await socket.SendJson( SharedJsonApiObjectFactory.CreateError("Only login and register are valid here.")); break; } } else { await socket.SendJson( SharedJsonApiObjectFactory.CreateError( "Error parsing correct login or register parameters.")); } } } if (authFailed) { await socket.SendJson(SharedJsonApiObjectFactory.CreateLoginResponse(false, null)); CancellationTokenSource cts = new CancellationTokenSource(TimeSpan.FromMilliseconds(1000)); await socket.CloseAsync(WebSocketCloseStatus.PolicyViolation, "Authentication failed.", cts.Token); } else if (_options.Value.RequestCancelToken.IsCancellationRequested) { CancellationTokenSource cts = new CancellationTokenSource(TimeSpan.FromMilliseconds(1000)); await socket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Server is shutting down.", cts.Token); } else { await socket.CloseAsync(closeStatus, apiObjectResult.SocketResult.CloseStatusDescription, CancellationToken.None); } }