/// <summary> /// Pushes a single packet onto the wire /// </summary> /// <returns>True if the packet was sent or dropped (i.e. "completed"), false if non-blocking return.</returns> internal bool SendPacket(byte[] data, int length, NetworkEndPoint remoteEP, NetConnection connection) { if (length <= 0 || length > m_config.SendBufferSize) { string str = "Invalid packet size " + length + "; Must be between 1 and NetConfiguration.SendBufferSize - Invalid value: " + length; LogWrite(str); throw new NetException(str); } if (!m_isBound) { Start(); } #if DEBUG || USE_RELEASE_SIMULATION if (!m_suppressSimulatedLag) { bool send = SimulatedSendPacket(data, length, remoteEP); if (!send) { m_statistics.CountPacketSent(length); return(true); } } #endif int orgLength = length; // TODO: cleanup fulhaacks: packets below 60 or 64 are padded, if too low sometimes even dropped! if (length < 18 && data.Length - length >= 18) // 18 udp payload + 42 udp header = 60 bytes { for (int i = length; i < 18; i++) { data[i] = 0; } length = 18; } try { //m_socket.SendTo(data, 0, length, SocketFlags.None, remoteEP); //the original CPU busy polling loop wasn't very acceptable in PikkoServer ^^ int bytesSent; //do //{ bytesSent = m_socket.SendPacket(data, 0, length, remoteEP); //} while (bytesSent == 0); if (bytesSent > 0 && bytesSent < orgLength) { Log.Warning(LogFlags.Socket, NetTime.Now, " (", DateTime.Now, "): Socket sent fewer bytes of the packet (", bytesSent, ") than requested (", orgLength, ")"); } else if (bytesSent > length) { Log.Warning(LogFlags.Socket, NetTime.Now, " (", DateTime.Now, "): Socket sent more bytes of the packet (", bytesSent, ") than requested and padding (", length, ")"); } //LogVerbose("Sent " + bytesSent + " bytes"); #if DEBUG || USE_RELEASE_STATISTICS if (!m_suppressSimulatedLag && bytesSent > 0) { m_statistics.CountPacketSent(orgLength); } #endif return(bytesSent > 0); } catch (SocketException sex) { if (sex.ErrorCode == 10035 || sex.SocketErrorCode == SocketError.WouldBlock) { // NOTE: add independent ability to log warnings instead of this hack. Log.Warning(LogFlags.Socket, "Send buffer is full, if you see this too often it might be a sign that you need to increase the send buffer size: ", sex.Message); #if PIKKO_BUILD PikkoServer.PikkoStats.IncrementSendBufferDrops(); #endif return(true); //drop packet instead of trying to resend it } if (sex.ErrorCode == 10065 || sex.SocketErrorCode == SocketError.HostUnreachable) { if (connection != null) { Log.Warning(LogFlags.Socket, "Disconnecting from ", remoteEP, " because it's not reachable or internet/network connection is unstable: ", sex.Message); connection.Disconnect("Host Unreachable", 0, false, true); } else { Log.Warning(LogFlags.Socket, "Packet has been dropped because either ", remoteEP, " is unreachable or internet/network connection is unstable: ", sex.Message); } return(true); } /* * if (sex.SocketErrorCode == SocketError.ConnectionReset || * sex.SocketErrorCode == SocketError.ConnectionRefused || * sex.SocketErrorCode == SocketError.ConnectionAborted) * { * LogWrite("Remote socket forcefully closed: " + sex.SocketErrorCode); * // TODO: notify connection somehow? * return; * } */ throw new NetException(NetTime.Now + " (" + DateTime.Now + "): Could not send packet (" + length + " bytes) to " + remoteEP, sex); } catch (Exception ex) { throw new NetException(NetTime.Now + " (" + DateTime.Now + "): Could not send packet (" + length + " bytes) to " + remoteEP, ex); } }