public virtual void SendPCPHelo() { Logger.Debug("Handshake Started"); var helo = new AtomCollection(); helo.SetHeloAgent(PeerCast.AgentName); helo.SetHeloSessionID(PeerCast.SessionID); if (PeerCast.IsFirewalled.HasValue) { if (PeerCast.IsFirewalled.Value) { //Do nothing } else { var listener = PeerCast.FindListener( RemoteEndPoint.Address, OutputStreamType.Relay | OutputStreamType.Metadata); helo.SetHeloPort(listener.LocalEndPoint.Port); } } else { var listener = PeerCast.FindListener( RemoteEndPoint.Address, OutputStreamType.Relay | OutputStreamType.Metadata); if (listener != null) { helo.SetHeloPing(listener.LocalEndPoint.Port); } } helo.SetHeloVersion(PCP_VERSION); Send(new Atom(Atom.PCP_HELO, helo)); }
private void AnnounceThreadProc() { Logger.Debug("Thread started"); var host = Uri.DnsSafeHost; var port = Uri.Port; if (port < 0) { port = DefaultPort; } while (!IsStopped) { int next_update = Environment.TickCount; posts.Clear(); try { Logger.Debug("Connecting to YP"); AnnouncingStatus = AnnouncingStatus.Connecting; using (var client = new TcpClient(host, port)) { using (var stream = client.GetStream()) { AtomWriter.Write(stream, new Atom(new ID4("pcp\n"), (int)1)); var helo = new AtomCollection(); Logger.Debug("Sending Handshake"); helo.SetHeloAgent(PeerCast.AgentName); helo.SetHeloVersion(1218); helo.SetHeloSessionID(PeerCast.SessionID); helo.SetHeloBCID(PeerCast.BroadcastID); if (PeerCast.IsFirewalled.HasValue) { if (PeerCast.IsFirewalled.Value) { //Do nothing } else { var listener = PeerCast.FindListener( ((IPEndPoint)client.Client.RemoteEndPoint).Address, OutputStreamType.Relay | OutputStreamType.Metadata); if (listener != null) { helo.SetHeloPort(listener.LocalEndPoint.Port); } } } else { var listener = PeerCast.FindListener( ((IPEndPoint)client.Client.RemoteEndPoint).Address, OutputStreamType.Relay | OutputStreamType.Metadata); if (listener != null) { helo.SetHeloPing(listener.LocalEndPoint.Port); } } AtomWriter.Write(stream, new Atom(Atom.PCP_HELO, helo)); while (!IsStopped) { var atom = AtomReader.Read(stream); if (atom.Name == Atom.PCP_OLEH) { OnPCPOleh(atom); break; } else if (atom.Name == Atom.PCP_QUIT) { Logger.Debug("Handshake aborted by PCP_QUIT ({0})", atom.GetInt32()); throw new QuitException(); } if (restartEvent.WaitOne(10)) { throw new RestartException(); } } Logger.Debug("Handshake succeeded"); AnnouncingStatus = AnnouncingStatus.Connected; while (!IsStopped) { if (next_update - Environment.TickCount <= 0) { Logger.Debug("Sending channel info"); lock (announcingChannels) { foreach (var announcing in announcingChannels) { PostChannelBcst(announcing.Channel, true); } } next_update = Environment.TickCount + 30000; } if (stream.DataAvailable) { Atom atom = AtomReader.Read(stream); ProcessAtom(atom); } lock (posts) { foreach (var atom in posts) { AtomWriter.Write(stream, atom); } posts.Clear(); } if (restartEvent.WaitOne(10)) { throw new RestartException(); } } lock (posts) { foreach (var atom in posts) { AtomWriter.Write(stream, atom); } posts.Clear(); } Logger.Debug("Closing connection"); AtomWriter.Write(stream, new Atom(Atom.PCP_QUIT, Atom.PCP_ERROR_QUIT)); } } } catch (RestartException) { Logger.Debug("Connection retrying"); AnnouncingStatus = AnnouncingStatus.Connecting; } catch (BannedException) { AnnouncingStatus = AnnouncingStatus.Error; Logger.Error("Your BCID is banned"); break; } catch (QuitException) { AnnouncingStatus = AnnouncingStatus.Error; } catch (SocketException e) { AnnouncingStatus = AnnouncingStatus.Error; Logger.Info(e); } catch (IOException e) { AnnouncingStatus = AnnouncingStatus.Error; Logger.Info(e); } Logger.Debug("Connection closed"); if (!IsStopped) { restartEvent.WaitOne(10000); } else { AnnouncingStatus = AnnouncingStatus.Idle; } } Logger.Debug("Thread finished"); }
public Uri FindTracker(Guid channel_id) { Logger.Debug("Finding tracker {0} from {1}", channel_id.ToString("N"), Uri); var host = Uri.DnsSafeHost; var port = Uri.Port; Uri res = null; if (port < 0) { port = DefaultPort; } try { var client = new TcpClient(host, port); var stream = client.GetStream(); var request = System.Text.Encoding.UTF8.GetBytes( String.Format("GET /channel/{0} HTTP/1.0\r\n", channel_id.ToString("N")) + "x-peercast-pcp:1\r\n" + "\r\n"); stream.Write(request, 0, request.Length); var response = ReadResponse(stream); var md = System.Text.RegularExpressions.Regex.Match(response, @"^HTTP/1.\d (\d+) "); if (md.Success) { var status = md.Groups[1].Value; switch (status) { case "503": var helo = new AtomCollection(); helo.SetHeloAgent(PeerCast.AgentName); helo.SetHeloVersion(1218); helo.SetHeloSessionID(PeerCast.SessionID); helo.SetHeloPort(0); AtomWriter.Write(stream, new Atom(Atom.PCP_HELO, helo)); var hosts = ReadHosts(stream, channel_id); res = HostToUri(hosts.FirstOrDefault(h => h.IsTracker), channel_id); break; case "200": //なぜかリレー可能だったのでYP自体をトラッカーとみなしてしまうことにする AtomWriter.Write(stream, new Atom(Atom.PCP_QUIT, Atom.PCP_ERROR_QUIT)); res = Uri; break; default: //エラーだったのでトラッカーのアドレスを貰えず終了 break; } } AtomWriter.Write(stream, new Atom(Atom.PCP_QUIT, Atom.PCP_ERROR_QUIT)); client.Close(); } catch (SocketException) { } catch (IOException) { } if (res != null) { Logger.Debug("Tracker found: {0}", res); } else { Logger.Debug("Tracker no found"); } return(res); }
protected virtual void OnPCPHelo(Atom atom) { if (Downhost!=null) return; Logger.Debug("Helo received"); var session_id = atom.Children.GetHeloSessionID(); int remote_port = 0; if (session_id!=null) { var host = new HostBuilder(); host.SessionID = session_id.Value; var port = atom.Children.GetHeloPort(); var ping = atom.Children.GetHeloPing(); if (port!=null) { remote_port = port.Value; } else if (ping!=null) { if (IsPingTarget(((IPEndPoint)RemoteEndPoint).Address) && PingHost(new IPEndPoint(((IPEndPoint)RemoteEndPoint).Address, ping.Value), session_id.Value)) { remote_port = ping.Value; } else { remote_port = 0; } } else { remote_port = 0; } if (remote_port!=0) { var ip = new IPEndPoint(((IPEndPoint)RemoteEndPoint).Address, remote_port); if (host.GlobalEndPoint==null || !host.GlobalEndPoint.Equals(ip)) { host.GlobalEndPoint = ip; } } host.IsFirewalled = remote_port==0; host.Extra.Update(atom.Children); Downhost = host.ToHost(); } var oleh = new AtomCollection(); if (RemoteEndPoint!=null && RemoteEndPoint.AddressFamily==System.Net.Sockets.AddressFamily.InterNetwork) { oleh.SetHeloRemoteIP(((IPEndPoint)RemoteEndPoint).Address); } oleh.SetHeloAgent(PeerCast.AgentName); oleh.SetHeloSessionID(PeerCast.SessionID); oleh.SetHeloRemotePort(remote_port); oleh.SetHeloVersion(PCP_VERSION); Send(new Atom(Atom.PCP_OLEH, oleh)); if (Downhost==null) { Logger.Info("Helo has no SessionID"); //セッションIDが無かった Stop(StopReason.NotIdentifiedError); } else if ((Downhost.Extra.GetHeloVersion() ?? 0)<1200) { Logger.Info("Helo version {0} is too old", Downhost.Extra.GetHeloVersion() ?? 0); //クライアントバージョンが無かった、もしくは古すぎ Stop(StopReason.BadAgentError); } else if (IsRelayFull) { Logger.Debug("Handshake succeeded {0}({1}) but relay is full", Downhost.GlobalEndPoint, Downhost.SessionID.ToString("N")); //次に接続するホストを送ってQUIT foreach (var node in SelectSourceHosts((IPEndPoint)RemoteEndPoint)) { var host_atom = new AtomCollection(node.Extra); Atom ip = host_atom.FindByName(Atom.PCP_HOST_IP); while (ip!=null) { host_atom.Remove(ip); ip = host_atom.FindByName(Atom.PCP_HOST_IP); } Atom port = host_atom.FindByName(Atom.PCP_HOST_PORT); while (port!=null) { host_atom.Remove(port); port = host_atom.FindByName(Atom.PCP_HOST_PORT); } host_atom.SetHostSessionID(node.SessionID); var globalendpoint = node.GlobalEndPoint ?? new IPEndPoint(IPAddress.Any, 0); host_atom.AddHostIP(globalendpoint.Address); host_atom.AddHostPort(globalendpoint.Port); var localendpoint = node.LocalEndPoint ?? new IPEndPoint(IPAddress.Any, 0); host_atom.AddHostIP(localendpoint.Address); host_atom.AddHostPort(localendpoint.Port); host_atom.SetHostNumRelays(node.RelayCount); host_atom.SetHostNumListeners(node.DirectCount); host_atom.SetHostChannelID(Channel.ChannelID); host_atom.SetHostFlags1( (node.IsFirewalled ? PCPHostFlags1.Firewalled : PCPHostFlags1.None) | (node.IsTracker ? PCPHostFlags1.Tracker : PCPHostFlags1.None) | (node.IsRelayFull ? PCPHostFlags1.None : PCPHostFlags1.Relay) | (node.IsDirectFull ? PCPHostFlags1.None : PCPHostFlags1.Direct) | (node.IsReceiving ? PCPHostFlags1.Receiving : PCPHostFlags1.None) | (node.IsControlFull ? PCPHostFlags1.None : PCPHostFlags1.ControlIn)); Send(new Atom(Atom.PCP_HOST, host_atom)); Logger.Debug("Sending Node: {0}({1})", globalendpoint, node.SessionID.ToString("N")); } Stop(StopReason.UnavailableError); } else { Logger.Debug("Handshake succeeded {0}({1})", Downhost.GlobalEndPoint, Downhost.SessionID.ToString("N")); Send(new Atom(Atom.PCP_OK, (int)1)); } }
private void AnnounceThreadProc() { Logger.Debug("Thread started"); var host = Uri.DnsSafeHost; var port = Uri.Port; if (port<0) port = PCPVersion.DefaultPort; while (!IsStopped) { int next_update = Environment.TickCount; posts.Clear(); try { Logger.Debug("Connecting to YP"); AnnouncingStatus = AnnouncingStatus.Connecting; using (var client = new TcpClient(host, port)) { remoteEndPoint = (IPEndPoint)client.Client.RemoteEndPoint; using (var stream = client.GetStream()) { AtomWriter.Write(stream, new Atom(new ID4("pcp\n"), (int)1)); var helo = new AtomCollection(); Logger.Debug("Sending Handshake"); helo.SetHeloAgent(PeerCast.AgentName); helo.SetHeloVersion(1218); helo.SetHeloSessionID(PeerCast.SessionID); helo.SetHeloBCID(PeerCast.BroadcastID); if (PeerCast.IsFirewalled.HasValue) { if (PeerCast.IsFirewalled.Value) { //Do nothing } else { var listener = PeerCast.FindListener( ((IPEndPoint)client.Client.RemoteEndPoint).Address, OutputStreamType.Relay | OutputStreamType.Metadata); if (listener!=null) { helo.SetHeloPort(listener.LocalEndPoint.Port); } } } else { var listener = PeerCast.FindListener( ((IPEndPoint)client.Client.RemoteEndPoint).Address, OutputStreamType.Relay | OutputStreamType.Metadata); if (listener!=null) { helo.SetHeloPing(listener.LocalEndPoint.Port); } } AtomWriter.Write(stream, new Atom(Atom.PCP_HELO, helo)); while (!IsStopped) { var atom = AtomReader.Read(stream); if (atom.Name==Atom.PCP_OLEH) { OnPCPOleh(atom); break; } else if (atom.Name==Atom.PCP_QUIT) { Logger.Debug("Handshake aborted by PCP_QUIT ({0})", atom.GetInt32()); throw new QuitException(); } if (restartEvent.WaitOne(10)) throw new RestartException(); } Logger.Debug("Handshake succeeded"); AnnouncingStatus = AnnouncingStatus.Connected; while (!IsStopped) { if (next_update-Environment.TickCount<=0) { Logger.Debug("Sending channel info"); lock (announcingChannels) { foreach (var announcing in announcingChannels) { PostChannelBcst(announcing.Channel, true); } } next_update = Environment.TickCount+30000; } if (stream.DataAvailable) { Atom atom = AtomReader.Read(stream); ProcessAtom(atom); } lock (posts) { foreach (var atom in posts) { AtomWriter.Write(stream, atom); } posts.Clear(); } if (restartEvent.WaitOne(10)) throw new RestartException(); } lock (posts) { foreach (var atom in posts) { AtomWriter.Write(stream, atom); } posts.Clear(); } Logger.Debug("Closing connection"); AtomWriter.Write(stream, new Atom(Atom.PCP_QUIT, Atom.PCP_ERROR_QUIT)); } } } catch (RestartException) { Logger.Debug("Connection retrying"); AnnouncingStatus = AnnouncingStatus.Connecting; } catch (BannedException) { AnnouncingStatus = AnnouncingStatus.Error; Logger.Error("Your BCID is banned"); break; } catch (QuitException) { AnnouncingStatus = AnnouncingStatus.Error; } catch (SocketException e) { AnnouncingStatus = AnnouncingStatus.Error; Logger.Info(e); } catch (IOException e) { AnnouncingStatus = AnnouncingStatus.Error; Logger.Info(e); } finally { remoteEndPoint = null; } Logger.Debug("Connection closed"); if (!IsStopped) { restartEvent.WaitOne(10000); } else { AnnouncingStatus = AnnouncingStatus.Idle; } } Logger.Debug("Thread finished"); }
public Uri FindTracker(Guid channel_id) { Logger.Debug("Finding tracker {0} from {1}", channel_id.ToString("N"), Uri); var host = Uri.DnsSafeHost; var port = Uri.Port; Uri res = null; if (port<0) port = PCPVersion.DefaultPort; try { var client = new TcpClient(host, port); var stream = client.GetStream(); var request = System.Text.Encoding.UTF8.GetBytes( String.Format("GET /channel/{0} HTTP/1.0\r\n", channel_id.ToString("N")) + "x-peercast-pcp:1\r\n" + "\r\n"); stream.Write(request, 0, request.Length); var response = ReadResponse(stream); var md = System.Text.RegularExpressions.Regex.Match(response, @"^HTTP/1.\d (\d+) "); if (md.Success) { var status = md.Groups[1].Value; switch (status) { case "503": var helo = new AtomCollection(); helo.SetHeloAgent(PeerCast.AgentName); helo.SetHeloVersion(1218); helo.SetHeloSessionID(PeerCast.SessionID); helo.SetHeloPort(0); AtomWriter.Write(stream, new Atom(Atom.PCP_HELO, helo)); var hosts = ReadHosts(stream, channel_id); res = HostToUri(hosts.FirstOrDefault(h => h.IsTracker), channel_id); break; case "200": //なぜかリレー可能だったのでYP自体をトラッカーとみなしてしまうことにする AtomWriter.Write(stream, new Atom(Atom.PCP_QUIT, Atom.PCP_ERROR_QUIT)); res = Uri; break; default: //エラーだったのでトラッカーのアドレスを貰えず終了 break; } } AtomWriter.Write(stream, new Atom(Atom.PCP_QUIT, Atom.PCP_ERROR_QUIT)); client.Close(); } catch (SocketException) { } catch (IOException) { } if (res!=null) { Logger.Debug("Tracker found: {0}", res); } else { Logger.Debug("Tracker no found"); } return res; }
protected virtual void OnPCPHelo(Atom atom) { if (Downhost != null) { return; } Logger.Debug("Helo received"); var session_id = atom.Children.GetHeloSessionID(); int remote_port = 0; if (session_id != null) { var host = new HostBuilder(); host.SessionID = session_id.Value; var port = atom.Children.GetHeloPort(); var ping = atom.Children.GetHeloPing(); if (port != null) { remote_port = port.Value; } else if (ping != null) { if (IsPingTarget(((IPEndPoint)RemoteEndPoint).Address) && PingHost(new IPEndPoint(((IPEndPoint)RemoteEndPoint).Address, ping.Value), session_id.Value)) { remote_port = ping.Value; } else { remote_port = 0; } } else { remote_port = 0; } if (remote_port != 0) { var ip = new IPEndPoint(((IPEndPoint)RemoteEndPoint).Address, remote_port); if (host.GlobalEndPoint == null || !host.GlobalEndPoint.Equals(ip)) { host.GlobalEndPoint = ip; } } host.IsFirewalled = remote_port == 0; host.Extra.Update(atom.Children); Downhost = host.ToHost(); } var oleh = new AtomCollection(); if (RemoteEndPoint != null && RemoteEndPoint.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork) { oleh.SetHeloRemoteIP(((IPEndPoint)RemoteEndPoint).Address); } oleh.SetHeloAgent(PeerCast.AgentName); oleh.SetHeloSessionID(PeerCast.SessionID); oleh.SetHeloRemotePort(remote_port); oleh.SetHeloVersion(PCP_VERSION); Send(new Atom(Atom.PCP_OLEH, oleh)); if (Downhost == null) { Logger.Info("Helo has no SessionID"); //セッションIDが無かった Stop(StopReason.NotIdentifiedError); } else if ((Downhost.Extra.GetHeloVersion() ?? 0) < 1200) { Logger.Info("Helo version {0} is too old", Downhost.Extra.GetHeloVersion() ?? 0); //クライアントバージョンが無かった、もしくは古すぎ Stop(StopReason.BadAgentError); } else if (IsRelayFull) { Logger.Debug("Handshake succeeded {0}({1}) but relay is full", Downhost.GlobalEndPoint, Downhost.SessionID.ToString("N")); //次に接続するホストを送ってQUIT foreach (var node in SelectSourceHosts((IPEndPoint)RemoteEndPoint)) { var host_atom = new AtomCollection(node.Extra); Atom ip = host_atom.FindByName(Atom.PCP_HOST_IP); while (ip != null) { host_atom.Remove(ip); ip = host_atom.FindByName(Atom.PCP_HOST_IP); } Atom port = host_atom.FindByName(Atom.PCP_HOST_PORT); while (port != null) { host_atom.Remove(port); port = host_atom.FindByName(Atom.PCP_HOST_PORT); } host_atom.SetHostSessionID(node.SessionID); var globalendpoint = node.GlobalEndPoint ?? new IPEndPoint(IPAddress.Any, 0); host_atom.AddHostIP(globalendpoint.Address); host_atom.AddHostPort(globalendpoint.Port); var localendpoint = node.LocalEndPoint ?? new IPEndPoint(IPAddress.Any, 0); host_atom.AddHostIP(localendpoint.Address); host_atom.AddHostPort(localendpoint.Port); host_atom.SetHostNumRelays(node.RelayCount); host_atom.SetHostNumListeners(node.DirectCount); host_atom.SetHostChannelID(Channel.ChannelID); host_atom.SetHostFlags1( (node.IsFirewalled ? PCPHostFlags1.Firewalled : PCPHostFlags1.None) | (node.IsTracker ? PCPHostFlags1.Tracker : PCPHostFlags1.None) | (node.IsRelayFull ? PCPHostFlags1.None : PCPHostFlags1.Relay) | (node.IsDirectFull ? PCPHostFlags1.None : PCPHostFlags1.Direct) | (node.IsReceiving ? PCPHostFlags1.Receiving : PCPHostFlags1.None) | (node.IsControlFull ? PCPHostFlags1.None : PCPHostFlags1.ControlIn)); Send(new Atom(Atom.PCP_HOST, host_atom)); Logger.Debug("Sending Node: {0}({1})", globalendpoint, node.SessionID.ToString("N")); } Stop(StopReason.UnavailableError); } else { Logger.Debug("Handshake succeeded {0}({1})", Downhost.GlobalEndPoint, Downhost.SessionID.ToString("N")); Send(new Atom(Atom.PCP_OK, (int)1)); } }