/// <summary> /// reads a message from connection /// </summary> /// <param name="buffer">buffer where the message will be written</param> /// <returns>true if we got a message, false if we got disconnected</returns> public void Receive() { if (!open) { OnDisconnected?.Invoke(); Debug.LogWarning("DISCO a"); return; } // read as long as we have things to read int msgSize; while ((msgSize = kcp.PeekSize()) > 0) { kcp.Receive(buffer, 0, msgSize); ArraySegment <byte> dataSegment = new ArraySegment <byte>(buffer, 0, msgSize); // handshake message? if (SegmentsEqual(dataSegment, Hello)) { // we are only connected if we received the handshake. // not just after receiving any first data. Debug.LogWarning("Kcp recv handshake"); OnConnected?.Invoke(); } // disconnect message? else if (SegmentsEqual(dataSegment, Goodby)) { // if we receive a disconnect message, then close everything Debug.LogWarning("Kcp recv disconnected"); open = false; OnDisconnected?.Invoke(); } // otherwise regular message else { //Debug.LogWarning($"Kcp recv msg: {BitConverter.ToString(buffer, 0, msgSize)}"); OnData?.Invoke(dataSegment); } } }
// reads the next message from connection. bool ReceiveNext(out ArraySegment <byte> message) { // read only one message int msgSize = kcp.PeekSize(); if (msgSize > 0) { // only allow receiving up to MaxMessageSize sized messages. // otherwise we would get BlockCopy ArgumentException anyway. if (msgSize <= Kcp.MTU_DEF) { int received = kcp.Receive(buffer, msgSize); if (received >= 0) { message = new ArraySegment <byte>(buffer, 0, msgSize); lastReceiveTime = (uint)refTime.ElapsedMilliseconds; // return false if it was a ping message. true otherwise. if (Utils.SegmentsEqual(message, Ping)) { //Debug.Log("KCP: received ping."); return(false); } return(true); } else { // if receive failed, close everything Debug.LogWarning($"Receive failed with error={received}. closing connection."); Disconnect(); } } // we don't allow sending messages > Max, so this must be an // attacker. let's disconnect to avoid allocation attacks etc. else { Debug.LogWarning($"KCP: possible allocation attack for msgSize {msgSize} > max {Kcp.MTU_DEF}. Disconnecting the connection."); Disconnect(); } } return(false); }
// reads the next reliable message type & content from kcp. // -> to avoid buffering, unreliable messages call OnData directly. bool ReceiveNextReliable(out KcpHeader header, out ArraySegment <byte> message) { int msgSize = kcp.PeekSize(); if (msgSize > 0) { // only allow receiving up to buffer sized messages. // otherwise we would get BlockCopy ArgumentException anyway. if (msgSize <= kcpMessageBuffer.Length) { // receive from kcp int received = kcp.Receive(kcpMessageBuffer, msgSize); if (received >= 0) { // extract header & content without header header = (KcpHeader)kcpMessageBuffer[0]; message = new ArraySegment <byte>(kcpMessageBuffer, 1, msgSize - 1); lastReceiveTime = (uint)refTime.ElapsedMilliseconds; return(true); } else { // if receive failed, close everything // pass error to user callback. no need to log it manually. OnError(ErrorCode.InvalidReceive, $"Receive failed with error={received}. closing connection."); Disconnect(); } } // we don't allow sending messages > Max, so this must be an // attacker. let's disconnect to avoid allocation attacks etc. else { // pass error to user callback. no need to log it manually. OnError(ErrorCode.InvalidReceive, $"KCP: possible allocation attack for msgSize {msgSize} > buffer {kcpMessageBuffer.Length}. Disconnecting the connection."); Disconnect(); } } message = default; header = KcpHeader.Disconnect; return(false); }