/// <summary> /// Create a connection to a remote endpoint /// </summary> public virtual NetConnection Connect(NetEndPoint remoteEndPoint, NetOutgoingMessage hailMessage) { if (remoteEndPoint == null) { throw new ArgumentNullException("remoteEndPoint"); } if (m_configuration.DualStack) { remoteEndPoint = NetUtility.MapToIPv6(remoteEndPoint); } lock (m_connections) { if (m_status == NetPeerStatus.NotRunning) { throw new NetException("Must call Start() first"); } if (m_connectionLookup.ContainsKey(remoteEndPoint)) { throw new NetException("Already connected to that endpoint!"); } NetConnection hs; if (m_handshakes.TryGetValue(remoteEndPoint, out hs)) { // already trying to connect to that endpoint; make another try switch (hs.m_status) { case NetConnectionStatus.InitiatedConnect: // send another connect hs.m_connectRequested = true; break; case NetConnectionStatus.RespondedConnect: // send another response hs.SendConnectResponse(NetTime.Now, false); break; default: // weird LogWarning("Weird situation; Connect() already in progress to remote endpoint; but hs status is " + hs.m_status); break; } return(hs); } NetConnection conn = new NetConnection(this, remoteEndPoint); conn.SetStatus(NetConnectionStatus.InitiatedConnect, "user called connect"); conn.m_localHailMessage = hailMessage; // handle on network thread conn.m_connectRequested = true; conn.m_connectionInitiator = true; m_handshakes.Add(remoteEndPoint, conn); return(conn); } }
internal bool ActuallySendPacket(byte[] data, int numBytes, NetEndPoint target, out bool connectionReset) { connectionReset = false; target = NetUtility.MapToIPv6(target); IPAddress ba = default(IPAddress); try { ba = NetUtility.GetCachedBroadcastAddress(); // TODO: refactor this check outta here if (target.Address == ba) { // Some networks do not allow // a global broadcast so we use the BroadcastAddress from the configuration // this can be resolved to a local broadcast addresss e.g 192.168.x.255 target.Address = m_configuration.BroadcastAddress; m_socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, true); } int bytesSent = m_socket.SendTo(data, 0, numBytes, SocketFlags.None, target); if (numBytes != bytesSent) { LogWarning("Failed to send the full " + numBytes + "; only " + bytesSent + " bytes sent in packet!"); } // LogDebug("Sent " + numBytes + " bytes"); } catch (SocketException sx) { if (sx.SocketErrorCode == SocketError.WouldBlock) { // send buffer full? LogWarning("Socket threw exception; would block - send buffer full? Increase in NetPeerConfiguration"); return(false); } if (sx.SocketErrorCode == SocketError.ConnectionReset) { // connection reset by peer, aka connection forcibly closed aka "ICMP port unreachable" connectionReset = true; return(false); } LogError("Failed to send packet: " + sx); } catch (Exception ex) { LogError("Failed to send packet: " + ex); } finally { if (target.Address == ba) { m_socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, false); } } return(true); }
/// <summary> /// Create a connection to a remote endpoint. /// </summary> public virtual NetConnection Connect(IPEndPoint remoteEndPoint, NetOutgoingMessage?hailMessage) { if (remoteEndPoint == null) { throw new ArgumentNullException(nameof(remoteEndPoint)); } if (Configuration.DualStack) { remoteEndPoint = NetUtility.MapToIPv6(remoteEndPoint); } if (Status == NetPeerStatus.NotRunning) { throw new LidgrenException("Must call Start() first."); } if (ConnectionLookup.ContainsKey(remoteEndPoint)) { throw new LidgrenException("Already connected to that endpoint!"); } if (Handshakes.TryGetValue(remoteEndPoint, out NetConnection? hs)) { // already trying to connect to that endpoint; make another try switch (hs.Status) { case NetConnectionStatus.InitiatedConnect: // send another connect hs._connectRequested = true; break; case NetConnectionStatus.RespondedConnect: // send another response hs.SendConnectResponse(NetTime.Now, false); break; default: // weird LogWarning(NetLogMessage.FromValues(NetLogCode.UnexpectedHandshakeStatus, value: (int)hs.Status)); break; } return(hs); } var conn = new NetConnection(this, remoteEndPoint); conn.Status = NetConnectionStatus.InitiatedConnect; conn.LocalHailMessage = hailMessage; // handle on network thread conn._connectRequested = true; conn._connectionInitiator = true; Handshakes.TryAdd(remoteEndPoint, conn); return(conn); }
// TODO: replace byte[] with Memory<byte> in the future (held back by Socket.SendTo) // https://github.com/dotnet/runtime/issues/33418 internal NetSocketResult ActuallySendPacket(byte[] data, int byteCount, IPEndPoint target) { Socket?socket = Socket; Debug.Assert(socket != null); bool broadcasting = false; try { IPAddress?ba = NetUtility.GetBroadcastAddress(); // TODO: refactor this check outta here if (target.Address.Equals(ba)) { // Some networks do not allow // a global broadcast so we use the BroadcastAddress from the configuration // this can be resolved to a local broadcast addresss e.g 192.168.x.255 _targetCopy.Address = Configuration.BroadcastAddress; _targetCopy.Port = target.Port; socket.EnableBroadcast = true; broadcasting = true; } else if ( Configuration.DualStack && Configuration.LocalAddress.AddressFamily == AddressFamily.InterNetworkV6) { // Maps to IPv6 for Dual Mode NetUtility.MapToIPv6(target, _targetCopy); } else { _targetCopy.Port = target.Port; _targetCopy.Address = target.Address; } int bytesSent = socket.SendTo(data, 0, byteCount, SocketFlags.None, _targetCopy); if (byteCount != bytesSent) { LogWarning(NetLogMessage.FromValues(NetLogCode.FullSendFailure, endPoint: target, value: bytesSent, maxValue: byteCount)); } //LogDebug("Sent " + numBytes + " bytes"); } catch (SocketException sx) { switch (sx.SocketErrorCode) { case SocketError.WouldBlock: // send buffer full? LogDebug(new NetLogMessage(NetLogCode.SocketWouldBlock, sx)); return(new NetSocketResult(false, false)); case SocketError.ConnectionReset: // connection reset by peer, aka connection forcibly closed aka "ICMP port unreachable" return(new NetSocketResult(false, true)); default: LogError(new NetLogMessage(NetLogCode.SendFailure, sx, target)); break; } } catch (Exception ex) { LogError(new NetLogMessage(NetLogCode.SendFailure, ex, target)); } finally { if (broadcasting) { socket.EnableBroadcast = false; } } return(new NetSocketResult(true, false)); }