private int _AddClient(BaseClient h) { lock (_chs_sync) for (int i = 0; i < _chs.Length; i++) // Even with 100,000 clients, this loop won't be an issue. if (_chs[i] == null) { h.Disconnected += h_Disconnected; h.ConnectionFailed += h_ConnectionFailed; // I gotta subscribe to the event here (unfortunately, inside a lock) so it won't get added twice. This is the only code block guaranteed to run just once when this function is called. if (_peering) for (int j = 0; j < _chs.Length; j++) if (_chs[j] != null) _chs[j].GivePeer(i); _chs[i] = h; return h._id = i; // I love assignment as expression! } // If a suitable position wasn't found... _DoubleClientContainer(); return _AddClient(h); }
private void _handleHandshakeRequest(BaseClient sender, RequestReceivedEventArgs e) { if (handshakeStep == 0) using (var br = new BinaryReader(e.Response.RequestPayloadStream, Encoding.UTF8)) { int vma = br.ReadInt32(); int vmi = br.ReadInt32(); if (ProtocolVersion.Major != vma || ProtocolVersion.Minor != vmi) _CheckIfStopped(new NotSupportedException("vProto Protocol Version mismatch.")); else { handshakeStep = 1; using (var str = new MemoryStream()) using (BinaryWriter bw = new BinaryWriter(str, Encoding.UTF8)) { bw.Write(ProtocolVersion.Major); bw.Write(ProtocolVersion.Minor); bw.Flush(); e.Response.SetPayload(str, SeekOrigin.Begin).Send(); } } } else if (handshakeStep == 1) using (var br = new BinaryReader(e.Response.RequestPayloadStream, Encoding.UTF8)) { this._id = br.ReadInt32(); int peers_cnt = br.ReadInt32(); int[] peers = null; if (peers_cnt != -1) { peers = new int[peers_cnt]; for (int i = peers_cnt - 1; i >= 0; i--) peers[i] = br.ReadInt32(); } lock (_peers_lock) { _peers = new List<int>(peers); if (peers != null) for (int i = 0; i < _peers_queued_temp.Count; i++) if (!_peers.Contains(_peers_queued_temp[i])) _peers.Add(_peers_queued_temp[i]); _peers_queued_temp = null; } _FinishHandhake(); e.Response.Send(); } }
private void _DoubleClientContainer() { lock (_chs_sync) { BaseClient[] n = new BaseClient[_chs.Length * 2]; _chs.CopyTo(n, 0); // Indices need to be preserved... _chs = n; } }
private void _RemoveClient(BaseClient h) { lock (_chs_sync) if (h._id > -1 && h._id < _chs.Length) { _chs[h._id] = null; if (_peering) for (int j = 0; j < _chs.Length; j++) if (_chs[j] != null) _chs[j].TakePeer(h._id); } // else what the heck is going on? }
// Only internally... internal Request(BaseClient cl, short id) { client = cl; this.id = id; Disposed = Sent = Aborted = TimedOut = Failed = Responded = false; }
void h_ConnectionFailed(BaseClient sender, ClientConnectionFailedEventArgs e) { _RemoveClient(sender); OnClientConnectionFailed(new ServerClientConnectionFailedEventArgs(e.Exception)); }
/* Events from clients... */ void h_Disconnected(BaseClient sender, ClientDisconnectedEventArgs e) { _RemoveClient(sender); OnClientDisconnected(new ServerClientDisconnectedEventArgs(sender, e.Exception)); }
/// <summary> /// Integrates a new client into the server and raises appropriate events. /// </summary> /// <param name="client">The client to integrate.</param> protected void ClientReceived(BaseClient client) { _AddClient(client); OnClientConnected(new ServerClientConnectedEventArgs(client)); }
// Only internally... internal Response(BaseClient cl, short id, short type, byte[] reqpayload, TimeSpan timeout, DateTime receivalTime) { client = cl; this.id = id; this.Type = type; Timeout = timeout; TimeRquested = receivalTime; TimeDue = receivalTime + timeout; reqarr = reqpayload; reqstr = new MemoryStream(reqpayload); Disposed = Sent = Aborted = TimedOut = Failed = false; }