From 9bd7680bf29446538cbc13806ae976d8e8ba1a88 Mon Sep 17 00:00:00 2001 From: eru Date: Wed, 12 Dec 2007 05:03:54 +0000 Subject: [PATCH] =?utf8?q?GUI=E7=B5=82=E4=BA=86=E6=99=82=E3=81=AE=E3=82=A8?= =?utf8?q?=E3=83=A9=E3=83=BC=E8=90=BD=E3=81=A1=E3=82=92=E4=BF=AE=E6=AD=A3(?= =?utf8?q?=EF=BC=9F)?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit 原因: backImageがNULLなのにGUIDataUpdateが更新を試みる事があった 対策: backImageの破棄タイミングを調整 --- PeerCast.root/PeerCast/core/common/asf.h | 290 ++ PeerCast.root/PeerCast/core/common/atom.h | 208 + PeerCast.root/PeerCast/core/common/channel.cpp | 4608 ++++++++++++++++++++ PeerCast.root/PeerCast/core/common/channel.h | 731 ++++ PeerCast.root/PeerCast/core/common/common.h | 293 ++ PeerCast.root/PeerCast/core/common/cstream.h | 241 + PeerCast.root/PeerCast/core/common/gnutella.cpp | 751 ++++ PeerCast.root/PeerCast/core/common/gnutella.h | 295 ++ PeerCast.root/PeerCast/core/common/html-xml.h | 28 + PeerCast.root/PeerCast/core/common/html.cpp | 558 +++ PeerCast.root/PeerCast/core/common/html.h | 91 + PeerCast.root/PeerCast/core/common/http.cpp | 192 + PeerCast.root/PeerCast/core/common/http.h | 185 + PeerCast.root/PeerCast/core/common/icy.cpp | 43 + PeerCast.root/PeerCast/core/common/icy.h | 35 + PeerCast.root/PeerCast/core/common/id.h | 101 + .../PeerCast/core/common/identify_encoding.c | 280 ++ .../PeerCast/core/common/identify_encoding.h | 42 + PeerCast.root/PeerCast/core/common/inifile.cpp | 168 + PeerCast.root/PeerCast/core/common/inifile.h | 53 + PeerCast.root/PeerCast/core/common/jis.cpp | 755 ++++ PeerCast.root/PeerCast/core/common/jis.h | 35 + PeerCast.root/PeerCast/core/common/mms.cpp | 194 + PeerCast.root/PeerCast/core/common/mms.h | 37 + PeerCast.root/PeerCast/core/common/mp3.cpp | 82 + PeerCast.root/PeerCast/core/common/mp3.h | 35 + PeerCast.root/PeerCast/core/common/nsv.cpp | 80 + PeerCast.root/PeerCast/core/common/nsv.h | 35 + PeerCast.root/PeerCast/core/common/ogg.cpp | 494 +++ PeerCast.root/PeerCast/core/common/ogg.h | 169 + PeerCast.root/PeerCast/core/common/pcp.cpp | 886 ++++ PeerCast.root/PeerCast/core/common/pcp.h | 268 ++ PeerCast.root/PeerCast/core/common/peercast.cpp | 242 + PeerCast.root/PeerCast/core/common/peercast.h | 102 + PeerCast.root/PeerCast/core/common/rtsp.cpp | 26 + PeerCast.root/PeerCast/core/common/rtsp.h | 32 + PeerCast.root/PeerCast/core/common/servent.cpp | 3163 ++++++++++++++ PeerCast.root/PeerCast/core/common/servent.h | 298 ++ PeerCast.root/PeerCast/core/common/servhs.cpp | 1954 +++++++++ PeerCast.root/PeerCast/core/common/servmgr.cpp | 2608 +++++++++++ PeerCast.root/PeerCast/core/common/servmgr.h | 428 ++ PeerCast.root/PeerCast/core/common/socket.cpp | 32 + PeerCast.root/PeerCast/core/common/socket.h | 185 + PeerCast.root/PeerCast/core/common/stats.cpp | 102 + PeerCast.root/PeerCast/core/common/stats.h | 87 + PeerCast.root/PeerCast/core/common/stream.cpp | 367 ++ PeerCast.root/PeerCast/core/common/stream.h | 541 +++ PeerCast.root/PeerCast/core/common/sys.cpp | 1041 +++++ PeerCast.root/PeerCast/core/common/sys.h | 534 +++ PeerCast.root/PeerCast/core/common/url.cpp | 355 ++ PeerCast.root/PeerCast/core/common/url.h | 49 + PeerCast.root/PeerCast/core/common/utf8.c | 343 ++ PeerCast.root/PeerCast/core/common/utf8.h | 36 + PeerCast.root/PeerCast/core/common/version2.h | 53 + PeerCast.root/PeerCast/core/common/xml.cpp | 491 +++ PeerCast.root/PeerCast/core/common/xml.h | 92 + .../PeerCast/core/win32/lib/corelib.vcproj | 1573 +++++++ .../PeerCast/core/win32/lib/corelib.vcproj.vspscc | 10 + PeerCast.root/PeerCast/core/win32/wsocket.cpp | 675 +++ PeerCast.root/PeerCast/core/win32/wsocket.h | 86 + PeerCast.root/PeerCast/core/win32/wsys.cpp | 150 + PeerCast.root/PeerCast/core/win32/wsys.h | 61 + PeerCast.root/PeerCast/ui/win32/PeerCast.sln | 49 + PeerCast.root/PeerCast/ui/win32/PeerCast.vsscc | Bin 0 -> 26 bytes PeerCast.root/PeerCast/ui/win32/PeerCast.vssscc | 10 + PeerCast.root/PeerCast/ui/win32/simple/SMALL.ICO | Bin 0 -> 318 bytes PeerCast.root/PeerCast/ui/win32/simple/Simple.ICO | Bin 0 -> 1078 bytes PeerCast.root/PeerCast/ui/win32/simple/Simple.cpp | 1437 ++++++ PeerCast.root/PeerCast/ui/win32/simple/Simple.h | 65 + PeerCast.root/PeerCast/ui/win32/simple/Simple.rc | 379 ++ .../PeerCast/ui/win32/simple/Simple.vcproj | 906 ++++ .../PeerCast/ui/win32/simple/Simple.vcproj.vspscc | 10 + PeerCast.root/PeerCast/ui/win32/simple/StdAfx.cpp | 9 + PeerCast.root/PeerCast/ui/win32/simple/StdAfx.h | 32 + .../PeerCast/ui/win32/simple/chkMemoryLeak.cpp | 21 + .../PeerCast/ui/win32/simple/chkMemoryLeak.h | 25 + PeerCast.root/PeerCast/ui/win32/simple/gui.cpp | 1853 ++++++++ PeerCast.root/PeerCast/ui/win32/simple/gui.h | 228 + PeerCast.root/PeerCast/ui/win32/simple/resource.h | 110 + PeerCast.root/PeerCast/ui/win32/simple/small1.ico | Bin 0 -> 318 bytes PeerCast.root/PeerCast/ui/win32/simple/small3.ico | Bin 0 -> 318 bytes c:/Git/PeerCast.root/PeerCast/core/common/asf.h | 290 ++ c:/Git/PeerCast.root/PeerCast/core/common/atom.h | 208 + .../PeerCast.root/PeerCast/core/common/channel.cpp | 4608 ++++++++++++++++++++ .../PeerCast.root/PeerCast/core/common/channel.h | 731 ++++ c:/Git/PeerCast.root/PeerCast/core/common/common.h | 293 ++ .../PeerCast.root/PeerCast/core/common/cstream.h | 241 + .../PeerCast/core/common/gnutella.cpp | 751 ++++ .../PeerCast.root/PeerCast/core/common/gnutella.h | 295 ++ .../PeerCast.root/PeerCast/core/common/html-xml.h | 28 + c:/Git/PeerCast.root/PeerCast/core/common/html.cpp | 558 +++ c:/Git/PeerCast.root/PeerCast/core/common/html.h | 91 + c:/Git/PeerCast.root/PeerCast/core/common/http.cpp | 192 + c:/Git/PeerCast.root/PeerCast/core/common/http.h | 185 + c:/Git/PeerCast.root/PeerCast/core/common/icy.cpp | 43 + c:/Git/PeerCast.root/PeerCast/core/common/icy.h | 35 + c:/Git/PeerCast.root/PeerCast/core/common/id.h | 101 + .../PeerCast/core/common/identify_encoding.c | 280 ++ .../PeerCast/core/common/identify_encoding.h | 42 + .../PeerCast.root/PeerCast/core/common/inifile.cpp | 168 + .../PeerCast.root/PeerCast/core/common/inifile.h | 53 + c:/Git/PeerCast.root/PeerCast/core/common/jis.cpp | 755 ++++ c:/Git/PeerCast.root/PeerCast/core/common/jis.h | 35 + c:/Git/PeerCast.root/PeerCast/core/common/mms.cpp | 194 + c:/Git/PeerCast.root/PeerCast/core/common/mms.h | 37 + c:/Git/PeerCast.root/PeerCast/core/common/mp3.cpp | 82 + c:/Git/PeerCast.root/PeerCast/core/common/mp3.h | 35 + c:/Git/PeerCast.root/PeerCast/core/common/nsv.cpp | 80 + c:/Git/PeerCast.root/PeerCast/core/common/nsv.h | 35 + c:/Git/PeerCast.root/PeerCast/core/common/ogg.cpp | 494 +++ c:/Git/PeerCast.root/PeerCast/core/common/ogg.h | 169 + c:/Git/PeerCast.root/PeerCast/core/common/pcp.cpp | 886 ++++ c:/Git/PeerCast.root/PeerCast/core/common/pcp.h | 268 ++ .../PeerCast/core/common/peercast.cpp | 242 + .../PeerCast.root/PeerCast/core/common/peercast.h | 102 + c:/Git/PeerCast.root/PeerCast/core/common/rtsp.cpp | 26 + c:/Git/PeerCast.root/PeerCast/core/common/rtsp.h | 32 + .../PeerCast.root/PeerCast/core/common/servent.cpp | 3163 ++++++++++++++ .../PeerCast.root/PeerCast/core/common/servent.h | 298 ++ .../PeerCast.root/PeerCast/core/common/servhs.cpp | 1954 +++++++++ .../PeerCast.root/PeerCast/core/common/servmgr.cpp | 2608 +++++++++++ .../PeerCast.root/PeerCast/core/common/servmgr.h | 428 ++ .../PeerCast.root/PeerCast/core/common/socket.cpp | 32 + c:/Git/PeerCast.root/PeerCast/core/common/socket.h | 185 + .../PeerCast.root/PeerCast/core/common/stats.cpp | 102 + c:/Git/PeerCast.root/PeerCast/core/common/stats.h | 87 + .../PeerCast.root/PeerCast/core/common/stream.cpp | 367 ++ c:/Git/PeerCast.root/PeerCast/core/common/stream.h | 541 +++ c:/Git/PeerCast.root/PeerCast/core/common/sys.cpp | 1041 +++++ c:/Git/PeerCast.root/PeerCast/core/common/sys.h | 534 +++ c:/Git/PeerCast.root/PeerCast/core/common/url.cpp | 355 ++ c:/Git/PeerCast.root/PeerCast/core/common/url.h | 49 + c:/Git/PeerCast.root/PeerCast/core/common/utf8.c | 343 ++ c:/Git/PeerCast.root/PeerCast/core/common/utf8.h | 36 + .../PeerCast.root/PeerCast/core/common/version2.h | 53 + c:/Git/PeerCast.root/PeerCast/core/common/xml.cpp | 491 +++ c:/Git/PeerCast.root/PeerCast/core/common/xml.h | 92 + .../PeerCast/core/win32/lib/corelib.vcproj | 1573 +++++++ .../PeerCast/core/win32/lib/corelib.vcproj.vspscc | 10 + .../PeerCast.root/PeerCast/core/win32/wsocket.cpp | 675 +++ c:/Git/PeerCast.root/PeerCast/core/win32/wsocket.h | 86 + c:/Git/PeerCast.root/PeerCast/core/win32/wsys.cpp | 150 + c:/Git/PeerCast.root/PeerCast/core/win32/wsys.h | 61 + .../PeerCast.root/PeerCast/ui/win32/PeerCast.sln | 49 + .../PeerCast.root/PeerCast/ui/win32/PeerCast.vsscc | Bin 0 -> 26 bytes .../PeerCast/ui/win32/PeerCast.vssscc | 10 + .../PeerCast/ui/win32/simple/SMALL.ICO | Bin 0 -> 318 bytes .../PeerCast/ui/win32/simple/Simple.ICO | Bin 0 -> 1078 bytes .../PeerCast/ui/win32/simple/Simple.cpp | 1437 ++++++ .../PeerCast/ui/win32/simple/Simple.h | 65 + .../PeerCast/ui/win32/simple/Simple.rc | 379 ++ .../PeerCast/ui/win32/simple/Simple.vcproj | 906 ++++ .../PeerCast/ui/win32/simple/Simple.vcproj.vspscc | 10 + .../PeerCast/ui/win32/simple/StdAfx.cpp | 9 + .../PeerCast/ui/win32/simple/StdAfx.h | 32 + .../PeerCast/ui/win32/simple/chkMemoryLeak.cpp | 21 + .../PeerCast/ui/win32/simple/chkMemoryLeak.h | 25 + .../PeerCast.root/PeerCast/ui/win32/simple/gui.cpp | 1853 ++++++++ .../PeerCast.root/PeerCast/ui/win32/simple/gui.h | 228 + .../PeerCast/ui/win32/simple/resource.h | 110 + .../PeerCast/ui/win32/simple/small1.ico | Bin 0 -> 318 bytes .../PeerCast/ui/win32/simple/small3.ico | Bin 0 -> 318 bytes 162 files changed, 66226 insertions(+) create mode 100644 PeerCast.root/PeerCast/core/common/asf.h create mode 100644 PeerCast.root/PeerCast/core/common/atom.h create mode 100644 PeerCast.root/PeerCast/core/common/channel.cpp create mode 100644 PeerCast.root/PeerCast/core/common/channel.h create mode 100644 PeerCast.root/PeerCast/core/common/common.h create mode 100644 PeerCast.root/PeerCast/core/common/cstream.h create mode 100644 PeerCast.root/PeerCast/core/common/gnutella.cpp create mode 100644 PeerCast.root/PeerCast/core/common/gnutella.h create mode 100644 PeerCast.root/PeerCast/core/common/html-xml.h create mode 100644 PeerCast.root/PeerCast/core/common/html.cpp create mode 100644 PeerCast.root/PeerCast/core/common/html.h create mode 100644 PeerCast.root/PeerCast/core/common/http.cpp create mode 100644 PeerCast.root/PeerCast/core/common/http.h create mode 100644 PeerCast.root/PeerCast/core/common/icy.cpp create mode 100644 PeerCast.root/PeerCast/core/common/icy.h create mode 100644 PeerCast.root/PeerCast/core/common/id.h create mode 100644 PeerCast.root/PeerCast/core/common/identify_encoding.c create mode 100644 PeerCast.root/PeerCast/core/common/identify_encoding.h create mode 100644 PeerCast.root/PeerCast/core/common/inifile.cpp create mode 100644 PeerCast.root/PeerCast/core/common/inifile.h create mode 100644 PeerCast.root/PeerCast/core/common/jis.cpp create mode 100644 PeerCast.root/PeerCast/core/common/jis.h create mode 100644 PeerCast.root/PeerCast/core/common/mms.cpp create mode 100644 PeerCast.root/PeerCast/core/common/mms.h create mode 100644 PeerCast.root/PeerCast/core/common/mp3.cpp create mode 100644 PeerCast.root/PeerCast/core/common/mp3.h create mode 100644 PeerCast.root/PeerCast/core/common/nsv.cpp create mode 100644 PeerCast.root/PeerCast/core/common/nsv.h create mode 100644 PeerCast.root/PeerCast/core/common/ogg.cpp create mode 100644 PeerCast.root/PeerCast/core/common/ogg.h create mode 100644 PeerCast.root/PeerCast/core/common/pcp.cpp create mode 100644 PeerCast.root/PeerCast/core/common/pcp.h create mode 100644 PeerCast.root/PeerCast/core/common/peercast.cpp create mode 100644 PeerCast.root/PeerCast/core/common/peercast.h create mode 100644 PeerCast.root/PeerCast/core/common/rtsp.cpp create mode 100644 PeerCast.root/PeerCast/core/common/rtsp.h create mode 100644 PeerCast.root/PeerCast/core/common/servent.cpp create mode 100644 PeerCast.root/PeerCast/core/common/servent.h create mode 100644 PeerCast.root/PeerCast/core/common/servhs.cpp create mode 100644 PeerCast.root/PeerCast/core/common/servmgr.cpp create mode 100644 PeerCast.root/PeerCast/core/common/servmgr.h create mode 100644 PeerCast.root/PeerCast/core/common/socket.cpp create mode 100644 PeerCast.root/PeerCast/core/common/socket.h create mode 100644 PeerCast.root/PeerCast/core/common/stats.cpp create mode 100644 PeerCast.root/PeerCast/core/common/stats.h create mode 100644 PeerCast.root/PeerCast/core/common/stream.cpp create mode 100644 PeerCast.root/PeerCast/core/common/stream.h create mode 100644 PeerCast.root/PeerCast/core/common/sys.cpp create mode 100644 PeerCast.root/PeerCast/core/common/sys.h create mode 100644 PeerCast.root/PeerCast/core/common/url.cpp create mode 100644 PeerCast.root/PeerCast/core/common/url.h create mode 100644 PeerCast.root/PeerCast/core/common/utf8.c create mode 100644 PeerCast.root/PeerCast/core/common/utf8.h create mode 100644 PeerCast.root/PeerCast/core/common/version2.h create mode 100644 PeerCast.root/PeerCast/core/common/xml.cpp create mode 100644 PeerCast.root/PeerCast/core/common/xml.h create mode 100644 PeerCast.root/PeerCast/core/win32/lib/corelib.vcproj create mode 100644 PeerCast.root/PeerCast/core/win32/lib/corelib.vcproj.vspscc create mode 100644 PeerCast.root/PeerCast/core/win32/wsocket.cpp create mode 100644 PeerCast.root/PeerCast/core/win32/wsocket.h create mode 100644 PeerCast.root/PeerCast/core/win32/wsys.cpp create mode 100644 PeerCast.root/PeerCast/core/win32/wsys.h create mode 100644 PeerCast.root/PeerCast/ui/win32/PeerCast.sln create mode 100644 PeerCast.root/PeerCast/ui/win32/PeerCast.vsscc create mode 100644 PeerCast.root/PeerCast/ui/win32/PeerCast.vssscc create mode 100644 PeerCast.root/PeerCast/ui/win32/simple/SMALL.ICO create mode 100644 PeerCast.root/PeerCast/ui/win32/simple/Simple.ICO create mode 100644 PeerCast.root/PeerCast/ui/win32/simple/Simple.cpp create mode 100644 PeerCast.root/PeerCast/ui/win32/simple/Simple.h create mode 100644 PeerCast.root/PeerCast/ui/win32/simple/Simple.rc create mode 100644 PeerCast.root/PeerCast/ui/win32/simple/Simple.vcproj create mode 100644 PeerCast.root/PeerCast/ui/win32/simple/Simple.vcproj.vspscc create mode 100644 PeerCast.root/PeerCast/ui/win32/simple/StdAfx.cpp create mode 100644 PeerCast.root/PeerCast/ui/win32/simple/StdAfx.h create mode 100644 PeerCast.root/PeerCast/ui/win32/simple/chkMemoryLeak.cpp create mode 100644 PeerCast.root/PeerCast/ui/win32/simple/chkMemoryLeak.h create mode 100644 PeerCast.root/PeerCast/ui/win32/simple/gui.cpp create mode 100644 PeerCast.root/PeerCast/ui/win32/simple/gui.h create mode 100644 PeerCast.root/PeerCast/ui/win32/simple/resource.h create mode 100644 PeerCast.root/PeerCast/ui/win32/simple/small1.ico create mode 100644 PeerCast.root/PeerCast/ui/win32/simple/small3.ico create mode 100644 c:/Git/PeerCast.root/PeerCast/core/common/asf.h create mode 100644 c:/Git/PeerCast.root/PeerCast/core/common/atom.h create mode 100644 c:/Git/PeerCast.root/PeerCast/core/common/channel.cpp create mode 100644 c:/Git/PeerCast.root/PeerCast/core/common/channel.h create mode 100644 c:/Git/PeerCast.root/PeerCast/core/common/common.h create mode 100644 c:/Git/PeerCast.root/PeerCast/core/common/cstream.h create mode 100644 c:/Git/PeerCast.root/PeerCast/core/common/gnutella.cpp create mode 100644 c:/Git/PeerCast.root/PeerCast/core/common/gnutella.h create mode 100644 c:/Git/PeerCast.root/PeerCast/core/common/html-xml.h create mode 100644 c:/Git/PeerCast.root/PeerCast/core/common/html.cpp create mode 100644 c:/Git/PeerCast.root/PeerCast/core/common/html.h create mode 100644 c:/Git/PeerCast.root/PeerCast/core/common/http.cpp create mode 100644 c:/Git/PeerCast.root/PeerCast/core/common/http.h create mode 100644 c:/Git/PeerCast.root/PeerCast/core/common/icy.cpp create mode 100644 c:/Git/PeerCast.root/PeerCast/core/common/icy.h create mode 100644 c:/Git/PeerCast.root/PeerCast/core/common/id.h create mode 100644 c:/Git/PeerCast.root/PeerCast/core/common/identify_encoding.c create mode 100644 c:/Git/PeerCast.root/PeerCast/core/common/identify_encoding.h create mode 100644 c:/Git/PeerCast.root/PeerCast/core/common/inifile.cpp create mode 100644 c:/Git/PeerCast.root/PeerCast/core/common/inifile.h create mode 100644 c:/Git/PeerCast.root/PeerCast/core/common/jis.cpp create mode 100644 c:/Git/PeerCast.root/PeerCast/core/common/jis.h create mode 100644 c:/Git/PeerCast.root/PeerCast/core/common/mms.cpp create mode 100644 c:/Git/PeerCast.root/PeerCast/core/common/mms.h create mode 100644 c:/Git/PeerCast.root/PeerCast/core/common/mp3.cpp create mode 100644 c:/Git/PeerCast.root/PeerCast/core/common/mp3.h create mode 100644 c:/Git/PeerCast.root/PeerCast/core/common/nsv.cpp create mode 100644 c:/Git/PeerCast.root/PeerCast/core/common/nsv.h create mode 100644 c:/Git/PeerCast.root/PeerCast/core/common/ogg.cpp create mode 100644 c:/Git/PeerCast.root/PeerCast/core/common/ogg.h create mode 100644 c:/Git/PeerCast.root/PeerCast/core/common/pcp.cpp create mode 100644 c:/Git/PeerCast.root/PeerCast/core/common/pcp.h create mode 100644 c:/Git/PeerCast.root/PeerCast/core/common/peercast.cpp create mode 100644 c:/Git/PeerCast.root/PeerCast/core/common/peercast.h create mode 100644 c:/Git/PeerCast.root/PeerCast/core/common/rtsp.cpp create mode 100644 c:/Git/PeerCast.root/PeerCast/core/common/rtsp.h create mode 100644 c:/Git/PeerCast.root/PeerCast/core/common/servent.cpp create mode 100644 c:/Git/PeerCast.root/PeerCast/core/common/servent.h create mode 100644 c:/Git/PeerCast.root/PeerCast/core/common/servhs.cpp create mode 100644 c:/Git/PeerCast.root/PeerCast/core/common/servmgr.cpp create mode 100644 c:/Git/PeerCast.root/PeerCast/core/common/servmgr.h create mode 100644 c:/Git/PeerCast.root/PeerCast/core/common/socket.cpp create mode 100644 c:/Git/PeerCast.root/PeerCast/core/common/socket.h create mode 100644 c:/Git/PeerCast.root/PeerCast/core/common/stats.cpp create mode 100644 c:/Git/PeerCast.root/PeerCast/core/common/stats.h create mode 100644 c:/Git/PeerCast.root/PeerCast/core/common/stream.cpp create mode 100644 c:/Git/PeerCast.root/PeerCast/core/common/stream.h create mode 100644 c:/Git/PeerCast.root/PeerCast/core/common/sys.cpp create mode 100644 c:/Git/PeerCast.root/PeerCast/core/common/sys.h create mode 100644 c:/Git/PeerCast.root/PeerCast/core/common/url.cpp create mode 100644 c:/Git/PeerCast.root/PeerCast/core/common/url.h create mode 100644 c:/Git/PeerCast.root/PeerCast/core/common/utf8.c create mode 100644 c:/Git/PeerCast.root/PeerCast/core/common/utf8.h create mode 100644 c:/Git/PeerCast.root/PeerCast/core/common/version2.h create mode 100644 c:/Git/PeerCast.root/PeerCast/core/common/xml.cpp create mode 100644 c:/Git/PeerCast.root/PeerCast/core/common/xml.h create mode 100644 c:/Git/PeerCast.root/PeerCast/core/win32/lib/corelib.vcproj create mode 100644 c:/Git/PeerCast.root/PeerCast/core/win32/lib/corelib.vcproj.vspscc create mode 100644 c:/Git/PeerCast.root/PeerCast/core/win32/wsocket.cpp create mode 100644 c:/Git/PeerCast.root/PeerCast/core/win32/wsocket.h create mode 100644 c:/Git/PeerCast.root/PeerCast/core/win32/wsys.cpp create mode 100644 c:/Git/PeerCast.root/PeerCast/core/win32/wsys.h create mode 100644 c:/Git/PeerCast.root/PeerCast/ui/win32/PeerCast.sln create mode 100644 c:/Git/PeerCast.root/PeerCast/ui/win32/PeerCast.vsscc create mode 100644 c:/Git/PeerCast.root/PeerCast/ui/win32/PeerCast.vssscc create mode 100644 c:/Git/PeerCast.root/PeerCast/ui/win32/simple/SMALL.ICO create mode 100644 c:/Git/PeerCast.root/PeerCast/ui/win32/simple/Simple.ICO create mode 100644 c:/Git/PeerCast.root/PeerCast/ui/win32/simple/Simple.cpp create mode 100644 c:/Git/PeerCast.root/PeerCast/ui/win32/simple/Simple.h create mode 100644 c:/Git/PeerCast.root/PeerCast/ui/win32/simple/Simple.rc create mode 100644 c:/Git/PeerCast.root/PeerCast/ui/win32/simple/Simple.vcproj create mode 100644 c:/Git/PeerCast.root/PeerCast/ui/win32/simple/Simple.vcproj.vspscc create mode 100644 c:/Git/PeerCast.root/PeerCast/ui/win32/simple/StdAfx.cpp create mode 100644 c:/Git/PeerCast.root/PeerCast/ui/win32/simple/StdAfx.h create mode 100644 c:/Git/PeerCast.root/PeerCast/ui/win32/simple/chkMemoryLeak.cpp create mode 100644 c:/Git/PeerCast.root/PeerCast/ui/win32/simple/chkMemoryLeak.h create mode 100644 c:/Git/PeerCast.root/PeerCast/ui/win32/simple/gui.cpp create mode 100644 c:/Git/PeerCast.root/PeerCast/ui/win32/simple/gui.h create mode 100644 c:/Git/PeerCast.root/PeerCast/ui/win32/simple/resource.h create mode 100644 c:/Git/PeerCast.root/PeerCast/ui/win32/simple/small1.ico create mode 100644 c:/Git/PeerCast.root/PeerCast/ui/win32/simple/small3.ico diff --git a/PeerCast.root/PeerCast/core/common/asf.h b/PeerCast.root/PeerCast/core/common/asf.h new file mode 100644 index 0000000..fcd1e3d --- /dev/null +++ b/PeerCast.root/PeerCast/core/common/asf.h @@ -0,0 +1,290 @@ +// ------------------------------------------------ +// File : asf.h +// Date: 10-apr-2003 +// Author: giles +// +// (c) 2002-3 peercast.org +// ------------------------------------------------ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// ------------------------------------------------ + +#ifndef _ASF_H +#define _ASF_H + + +#include "stream.h" + +// ----------------------------------- +class MSID +{ +public: + + void read(Stream &in) + { + data1 = in.readLong(); + data2 = in.readShort(); + data3 = in.readShort(); + in.read(data4,8); + } + + void write(Stream &out) + { + out.writeLong(data1); + out.writeShort(data2); + out.writeShort(data3); + out.write(data4,8); + } + + + void toString(String &s) + { + sprintf(s.data,"%X-%X-%X-%02X%02X%02X%02X%02X%02X%02X%02X", + data1,data2,data3, + data4[0],data4[1],data4[2],data4[3], + data4[4],data4[5],data4[6],data4[7]); + } + + int operator==(const MSID& msid) const{return !memcmp(this, &msid, sizeof(MSID));} + + unsigned int data1; + unsigned short data2,data3; + unsigned char data4[8]; + +}; + + + + +// ----------------------------------- +const MSID headObjID= + {0x75B22630, 0x668E, 0x11CF, 0xA6,0xD9,0x00,0xAA,0x00,0x62,0xCE,0x6C}; +const MSID dataObjID= + {0x75B22636, 0x668E, 0x11CF, 0xA6,0xD9,0x00,0xAA,0x00,0x62,0xCE,0x6C}; +const MSID filePropObjID= + {0x8CABDCA1, 0xA947, 0x11CF, 0x8E,0xE4,0x00,0xC0,0x0C,0x20,0x53,0x65}; +const MSID streamPropObjID= + {0xB7DC0791, 0xA9B7, 0x11CF, 0x8E,0xE6,0x00,0xC0,0x0C,0x20,0x53,0x65}; + +const MSID audioStreamObjID= + {0xF8699E40, 0x5B4D, 0x11CF, 0xA8,0xFD,0x00,0x80,0x5F,0x5C,0x44,0x2B}; +const MSID videoStreamObjID= + {0xBC19EFC0, 0x5B4D, 0x11CF, 0xA8,0xFD,0x00,0x80,0x5F,0x5C,0x44,0x2B}; + +const MSID streamBitrateObjID= + {0x7BF875CE, 0x468D, 0x11D1, 0x8D,0x82,0x00,0x60,0x97,0xC9,0xA2,0xB2}; + + +// ----------------------------------- +class ASFObject +{ +public: + + enum TYPE + { + T_UNKNOWN, + T_HEAD_OBJECT, + T_DATA_OBJECT, + T_FILE_PROP, + T_STREAM_PROP, + T_STREAM_BITRATE + }; + + int getTotalLen() + { + return 24+dataLen; + } + + unsigned int readHead(Stream &in) + { + id.read(in); + + lenLo = in.readLong(); + lenHi = in.readLong(); + + type = T_UNKNOWN; + if (id == headObjID) + type = T_HEAD_OBJECT; + else if (id == dataObjID) + type = T_DATA_OBJECT; + else if (id == filePropObjID) + type = T_FILE_PROP; + else if (id == streamPropObjID) + type = T_STREAM_PROP; + else if (id == streamBitrateObjID) + type = T_STREAM_BITRATE; + + String str; + id.toString(str); + LOG_DEBUG("ASF: %s (%s)= %d : %d\n",str.data,getTypeName(),lenLo,lenHi); + + + dataLen = 0; + + return lenLo-24; + } + + void readData(Stream &in,int len) + { + dataLen = len; + + if ((dataLen > sizeof(data)) || (lenHi)) + throw StreamException("ASF object too big"); + + in.read(data,dataLen); + } + + + void write(Stream &out) + { + id.write(out); + out.writeLong(lenLo); + out.writeLong(lenHi); + if (dataLen) + out.write(data,dataLen); + } + + const char *getTypeName() + { + switch(type) + { + case T_HEAD_OBJECT: + return "ASF_Header_Object"; + case T_DATA_OBJECT: + return "ASF_Data_Object"; + case T_FILE_PROP: + return "ASF_File_Properties_Object"; + case T_STREAM_PROP: + return "ASF_Stream_Properties_Object"; + case T_STREAM_BITRATE: + return "ASF_Stream_Bitrate_Properties_Object"; + default: + return "Unknown_Object"; + } + } + + char data[8192]; + MSID id; + unsigned int lenLo,lenHi,dataLen; + TYPE type; +}; +// ----------------------------------- +class ASFStream +{ +public: + enum TYPE + { + T_UNKNOWN, + T_AUDIO, + T_VIDEO + }; + + void read(Stream &in) + { + MSID sid; + sid.read(in); + + if (sid == videoStreamObjID) + type = T_VIDEO; + else if (sid == audioStreamObjID) + type = T_AUDIO; + else + type = T_UNKNOWN; + + in.skip(32); + id = in.readShort()&0x7f; + } + + + const char *getTypeName() + { + switch(type) + { + case T_VIDEO: + return "Video"; + case T_AUDIO: + return "Audio"; + } + return "Unknown"; + } + + void reset() + { + id = 0; + bitrate = 0; + type = T_UNKNOWN; + } + + unsigned int id; + int bitrate; + TYPE type; +}; + +// ----------------------------------- +class ASFInfo +{ +public: + enum + { + MAX_STREAMS = 128 + }; + + ASFInfo() + { + numPackets = 0; + packetSize = 0; + flags = 0; + bitrate=0; + for(int i=0; i sizeof(data)) + throw StreamException("ASF chunk too big"); + in.read(data,dataLen); + } + + void write(Stream &out) + { + out.writeShort(type); + out.writeShort(len); + out.writeLong(seq); + out.writeShort(v1); + out.writeShort(v2); + out.write(data,dataLen); + } + + unsigned int seq,dataLen; + unsigned short type,len,v1,v2; + unsigned char data[8192]; +}; + + +#endif + diff --git a/PeerCast.root/PeerCast/core/common/atom.h b/PeerCast.root/PeerCast/core/common/atom.h new file mode 100644 index 0000000..94d8e46 --- /dev/null +++ b/PeerCast.root/PeerCast/core/common/atom.h @@ -0,0 +1,208 @@ +// ------------------------------------------------ +// File : atom.h +// Date: 1-mar-2004 +// Author: giles +// +// (c) 2002-4 peercast.org +// ------------------------------------------------ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// ------------------------------------------------ + +#ifndef _ATOM_H +#define _ATOM_H + +#include "stream.h" + +#include "id.h" + +// ------------------------------------------------ +class AtomStream +{ +public: + AtomStream(Stream &s) : io(s),numChildren(0),numData(0) + {} + + void checkData(int d) + { + if (numData != d) + throw StreamException("Bad atom data"); + } + + void writeParent(ID4 id,int nc) + { + io.writeID4(id); + io.writeInt(nc|0x80000000); + } + + void writeInt(ID4 id,int d) + { + io.writeID4(id); + io.writeInt(4); + io.writeInt(d); + } + + void writeID4(ID4 id,ID4 d) + { + io.writeID4(id); + io.writeInt(4); + io.writeID4(d); + } + + void writeShort(ID4 id,short d) + { + io.writeID4(id); + io.writeInt(2); + io.writeShort(d); + } + + void writeChar(ID4 id,char d) + { + io.writeID4(id); + io.writeInt(1); + io.writeChar(d); + } + + void writeBytes(ID4 id,const void *p,int l) + { + io.writeID4(id); + io.writeInt(l); + io.write(p,l); + } + + + int writeStream(ID4 id,Stream &in,int l) + { + io.writeID4(id); + io.writeInt(l); + in.writeTo(io,l); + return (sizeof(int)*2)+l; + + } + + void writeString(ID4 id,const char *p) + { + writeBytes(id,p,strlen(p)+1); + } + + ID4 read(int &numc,int &dlen) + { + ID4 id = io.readID4(); + + unsigned int v = io.readInt(); + if (v & 0x80000000) + { + numc = v&0x7fffffff; + dlen = 0; + }else + { + numc = 0; + dlen = v; + } + + numChildren = numc; + numData = dlen; + + return id; + } + + void skip(int c, int d) + { + if (d) + io.skip(d); + + for(int i=0; i dlen) + readBytes(s,dlen); + else + { + readBytes(s,max); + io.skip(dlen-max); + } + } + + int writeAtoms(ID4 id, Stream &in, int cnt, int data) + { + int total=0; + + if (cnt) + { + writeParent(id,cnt); + total+=sizeof(int)*2; + + for(int i=0; i +#include +#include "common.h" +#include "socket.h" +#include "channel.h" +#include "gnutella.h" +#include "servent.h" +#include "servmgr.h" +#include "sys.h" +#include "xml.h" +#include "http.h" +#include "peercast.h" +#include "atom.h" +#include "pcp.h" + +#include "mp3.h" +#include "ogg.h" +#include "mms.h" +#include "nsv.h" + +#include "icy.h" +#include "url.h" + +#include "version2.h" +#ifdef _DEBUG +#include "chkMemoryLeak.h" +#define DEBUG_NEW new(__FILE__, __LINE__) +#define new DEBUG_NEW +#endif + +// ----------------------------------- +char *Channel::srcTypes[]= +{ + "NONE", + "PEERCAST", + "SHOUTCAST", + "ICECAST", + "URL" +}; +// ----------------------------------- +char *Channel::statusMsgs[]= +{ + "NONE", + "WAIT", + "CONNECT", + "REQUEST", + "CLOSE", + "RECEIVE", + "BROADCAST", + "ABORT", + "SEARCH", + "NOHOSTS", + "IDLE", + "ERROR", + "NOTFOUND" +}; + + +// for PCRaw start. +bool isIndexTxt(ChanInfo *info) +{ + int len; + + if( info && + info->contentType == ChanInfo::T_RAW && + info->bitrate <= 32 && + (len = strlen(info->name.cstr())) >= 9 && + !memcmp(info->name.cstr(), "index", 5) && + !memcmp(info->name.cstr()+len-4, ".txt", 4)) + { + return true; + } + else + { + return false; + } +} + +bool isIndexTxt(Channel *ch) +{ + if(ch && !ch->isBroadcasting() && isIndexTxt(&ch->info)) + return true; + else + return false; +} + +int numMaxRelaysIndexTxt(Channel *ch) +{ + return ((servMgr->maxRelaysIndexTxt < 1) ? 1 : servMgr->maxRelaysIndexTxt); +} + +int canStreamIndexTxt(Channel *ch) +{ + int ret; + + // Ž©•ª‚ª”zM‚µ‚Ä‚¢‚éê‡‚ÍŠÖŒW‚È‚¢ + if(!ch || ch->isBroadcasting()) + return -1; + + ret = numMaxRelaysIndexTxt(ch) - ch->localRelays(); + if(ret < 0) + ret = 0; + + return ret; +} +// for PCRaw end. + +// ----------------------------------- +void readXMLString(String &str, XML::Node *n, const char *arg) +{ + char *p; + p = n->findAttr(arg); + if (p) + { + str.set(p,String::T_HTML); + str.convertTo(String::T_ASCII); + } +} + +int channel_count=1; +// ----------------------------------------------------------------------------- +// Initialise the channel to its default settings of unallocated and reset. +// ----------------------------------------------------------------------------- +Channel::Channel() +{ + next = NULL; + reset(); + channel_id = channel_count++; +} +// ----------------------------------------------------------------------------- +void Channel::endThread(bool flg) +{ + if (pushSock) + { + pushSock->close(); + delete pushSock; + pushSock = NULL; + } + + if (sock) + { + sock->close(); + sock = NULL; + } + + if (sourceData) + { + delete sourceData; + sourceData = NULL; + } + + if (flg == true){ + reset(); + + chanMgr->channellock.on(); + chanMgr->deleteChannel(this); + chanMgr->channellock.off(); + + sys->endThread(&thread); + } +} +// ----------------------------------------------------------------------------- +void Channel::resetPlayTime() +{ + info.lastPlayStart = sys->getTime(); +} +// ----------------------------------------------------------------------------- +void Channel::setStatus(STATUS s) +{ + if (s != status) + { + bool wasPlaying = isPlaying(); + + status = s; + + if (isPlaying()) + { + info.status = ChanInfo::S_PLAY; + resetPlayTime(); + }else + { + if (wasPlaying) + info.lastPlayEnd = sys->getTime(); + info.status = ChanInfo::S_UNKNOWN; + } + + if (isBroadcasting()) + { + ChanHitList *chl = chanMgr->findHitListByID(info.id); + if (!chl) + chanMgr->addHitList(info); + } + + peercastApp->channelUpdate(&info); + + } +} + +// ----------------------------------------------------------------------------- +// Reset channel and make it available +// ----------------------------------------------------------------------------- +void Channel::reset() +{ + sourceHost.init(); + remoteID.clear(); + + streamIndex = 0; + + lastIdleTime = 0; + + info.init(); + + mount.clear(); + bump = false; + stayConnected = false; + + icyMetaInterval = 0; + streamPos = 0; + skipCount = 0; //JP-EX + lastSkipTime = 0; + + insertMeta.init(); + + headPack.init(); + + sourceStream = NULL; + + rawData.init(); + rawData.accept = ChanPacket::T_HEAD|ChanPacket::T_DATA; + + setStatus(S_NONE); + type = T_NONE; + + readDelay = false; + sock = NULL; + pushSock = NULL; + + sourceURL.clear(); + sourceData = NULL; + + lastTrackerUpdate = 0; + lastMetaUpdate = 0; + + srcType = SRC_NONE; + + + startTime = 0; + syncTime = 0; + + channel_id = 0; + finthread = NULL; + + trackerHit.init(); +} + +// ----------------------------------- +void Channel::newPacket(ChanPacket &pack) +{ + if (pack.type != ChanPacket::T_PCP) + { + rawData.writePacket(pack,true); + } +} + + +// ----------------------------------- +bool Channel::checkIdle() +{ + return ( (info.getUptime() > chanMgr->prefetchTime) && (localListeners() == 0) && (!stayConnected) && (status != S_BROADCASTING)); +} + +// ----------------------------------- +bool Channel::isFull() +{ + // for PCRaw (relay) start. + if(isIndexTxt(this)) + { + int ret = canStreamIndexTxt(this); + + if(ret > 0) + return false; + else if(ret == 0) + return true; + } + // for PCRaw (relay) end. + + return chanMgr->maxRelaysPerChannel ? localRelays() >= chanMgr->maxRelaysPerChannel : false; +} +// ----------------------------------- +int Channel::localRelays() +{ + return servMgr->numStreams(info.id,Servent::T_RELAY,true); +} +// ----------------------------------- +int Channel::localListeners() +{ + return servMgr->numStreams(info.id,Servent::T_DIRECT,true); +} + +// ----------------------------------- +int Channel::totalRelays() +{ + int tot = 0; + ChanHitList *chl = chanMgr->findHitListByID(info.id); + if (chl) + tot += chl->numHits(); + return tot; +} +// ----------------------------------- +int Channel::totalListeners() +{ + int tot = localListeners(); + ChanHitList *chl = chanMgr->findHitListByID(info.id); + if (chl) + tot += chl->numListeners(); + return tot; +} + + + + +// ----------------------------------- +void Channel::startGet() +{ + srcType = SRC_PEERCAST; + type = T_RELAY; + info.srcProtocol = ChanInfo::SP_PCP; + + + sourceData = new PeercastSource(); + + startStream(); +} +// ----------------------------------- +void Channel::startURL(const char *u) +{ + sourceURL.set(u); + + srcType = SRC_URL; + type = T_BROADCAST; + stayConnected = true; + + resetPlayTime(); + + sourceData = new URLSource(u); + + startStream(); + +} +// ----------------------------------- +void Channel::startStream() +{ + thread.data = this; + thread.func = stream; + if (!sys->startThread(&thread)) + reset(); +} + +// ----------------------------------- +void Channel::sleepUntil(double time) +{ + double sleepTime = time - (sys->getDTime()-startTime); + +// LOG("sleep %g",sleepTime); + if (sleepTime > 0) + { + if (sleepTime > 60) sleepTime = 60; + + double sleepMS = sleepTime*1000; + + sys->sleep((int)sleepMS); + } +} + + +// ----------------------------------- +void Channel::checkReadDelay(unsigned int len) +{ + if (readDelay) + { + unsigned int time = (len*1000)/((info.bitrate*1024)/8); + sys->sleep(time); + } + + +} + + +// ----------------------------------- +THREAD_PROC Channel::stream(ThreadInfo *thread) +{ +// thread->lock(); + + Channel *ch = (Channel *)thread->data; + + LOG_CHANNEL("Channel started"); + + while (thread->active && !peercastInst->isQuitting && !thread->finish) + { + ChanHitList *chl = chanMgr->findHitList(ch->info); + if (!chl) + chanMgr->addHitList(ch->info); + + ch->sourceData->stream(ch); + + LOG_CHANNEL("Channel stopped"); + ch->rawData.init(); + + if (!ch->stayConnected) + { + thread->active = false; + break; + }else + { + if (!ch->info.lastPlayEnd) + ch->info.lastPlayEnd = sys->getTime(); + + unsigned int diff = (sys->getTime()-ch->info.lastPlayEnd) + 5; + + LOG_DEBUG("Channel sleeping for %d seconds",diff); + for(unsigned int i=0; iactive || peercastInst->isQuitting){ + thread->active = false; + break; + } + sys->sleep(1000); + } + } + } + + LOG_DEBUG("thread.active = %d, thread.finish = %d", + ch->thread.active, ch->thread.finish); + + if (!thread->finish){ + ch->endThread(false); + + if (!ch->finthread){ + ch->finthread = new ThreadInfo(); + ch->finthread->func = waitFinish; + ch->finthread->data = ch; + sys->startThread(ch->finthread); + } + } else { + ch->endThread(true); + } + return 0; +} + +// ----------------------------------- +THREAD_PROC Channel::waitFinish(ThreadInfo *thread) +{ + Channel *ch = (Channel*)thread->data; + LOG_DEBUG("Wait channel finish"); + + while(!(ch->thread.finish) && !thread->finish){ + sys->sleep(1000); + } + + if (ch->thread.finish){ + LOG_DEBUG("channel finish"); + ch->endThread(true); + } else { + LOG_DEBUG("channel restart"); + } + + delete thread; + return 0; +} + +// ----------------------------------- +bool Channel::acceptGIV(ClientSocket *givSock) +{ + if (!pushSock) + { + pushSock = givSock; + return true; + }else + return false; +} +// ----------------------------------- +void Channel::connectFetch() +{ + sock = sys->createSocket(); + + if (!sock) + throw StreamException("Can`t create socket"); + + if (sourceHost.tracker || sourceHost.yp) + { + sock->setReadTimeout(30000); + sock->setWriteTimeout(30000); + LOG_CHANNEL("Channel using longer timeouts"); + } else { + sock->setReadTimeout(5000); + sock->setWriteTimeout(5000); + } + + sock->open(sourceHost.host); + + sock->connect(); +} + +// ----------------------------------- +int Channel::handshakeFetch() +{ + char idStr[64]; + info.id.toStr(idStr); + + char sidStr[64]; + servMgr->sessionID.toStr(sidStr); + + sock->writeLineF("GET /channel/%s HTTP/1.0",idStr); + sock->writeLineF("%s %d",PCX_HS_POS,streamPos); + sock->writeLineF("%s %d",PCX_HS_PCP,1); + + sock->writeLine(""); + + HTTP http(*sock); + + int r = http.readResponse(); + + LOG_CHANNEL("Got response: %d",r); + + while (http.nextHeader()) + { + char *arg = http.getArgStr(); + if (!arg) + continue; + + if (http.isHeader(PCX_HS_POS)) + streamPos = atoi(arg); + else + Servent::readICYHeader(http, info, NULL); + + LOG_CHANNEL("Channel fetch: %s",http.cmdLine); + } + + if ((r != 200) && (r != 503)) + return r; + + if (!servMgr->keepDownstreams) { + if (rawData.getLatestPos() > streamPos) + rawData.init(); + } + + AtomStream atom(*sock); + + String agent; + + Host rhost = sock->host; + + if (info.srcProtocol == ChanInfo::SP_PCP) + { + // don`t need PCP_CONNECT here + Servent::handshakeOutgoingPCP(atom,rhost,remoteID,agent,sourceHost.yp|sourceHost.tracker); + } + + if (r == 503) return 503; + return 0; + +} + +// ----------------------------------- +void PeercastSource::stream(Channel *ch) +{ + int numYPTries=0; + int numYPTries2=0; + bool next_yp = false; + bool tracker_check = (ch->trackerHit.host.ip != 0); + int connFailCnt = 0; + + ch->lastStopTime = 0; + ch->bumped = false; + + while (ch->thread.active) + { + ch->skipCount = 0; //JP-EX + ch->lastSkipTime = 0; + + ChanHitList *chl = NULL; + + ch->sourceHost.init(); + + if (connFailCnt >= 3 && (ch->localListeners() == 0) && (!ch->stayConnected) && !ch->isBroadcasting()) { + ch->lastIdleTime = sys->getTime(); + ch->setStatus(Channel::S_IDLE); + ch->skipCount = 0; + ch->lastSkipTime = 0; + break; + } + + if (!servMgr->keepDownstreams && !ch->bumped) { + ch->trackerHit.lastContact = sys->getTime() - 30 + (rand() % 30); + } + + ch->setStatus(Channel::S_SEARCHING); + LOG_CHANNEL("Channel searching for hit.."); + do + { + + if (ch->pushSock) + { + ch->sock = ch->pushSock; + ch->pushSock = NULL; + ch->sourceHost.host = ch->sock->host; + break; + } + + chanMgr->hitlistlock.on(); + + chl = chanMgr->findHitList(ch->info); + if (chl) + { + ChanHitSearch chs; + + // find local hit + if (!ch->sourceHost.host.ip){ + chs.init(); + chs.matchHost = servMgr->serverHost; + chs.waitDelay = MIN_RELAY_RETRY; + chs.excludeID = servMgr->sessionID; + if (chl->pickSourceHits(chs)){ + ch->sourceHost = chs.best[0]; + LOG_DEBUG("use local hit"); + } + } + + // else find global hit + if (!ch->sourceHost.host.ip) + { + chs.init(); + chs.waitDelay = MIN_RELAY_RETRY; + chs.excludeID = servMgr->sessionID; + if (chl->pickSourceHits(chs)){ + ch->sourceHost = chs.best[0]; + LOG_DEBUG("use global hit"); + } + } + + + // else find local tracker + if (!ch->sourceHost.host.ip) + { + chs.init(); + chs.matchHost = servMgr->serverHost; + chs.waitDelay = MIN_TRACKER_RETRY; + chs.excludeID = servMgr->sessionID; + chs.trackersOnly = true; + if (chl->pickSourceHits(chs)){ + ch->sourceHost = chs.best[0]; + LOG_DEBUG("use local tracker"); + } + } + + // find tracker + unsigned int ctime = sys->getTime(); + if (!ch->sourceHost.host.ip && tracker_check && ch->trackerHit.host.ip){ + if (ch->trackerHit.lastContact + 30 < ctime){ + ch->sourceHost = ch->trackerHit; + ch->trackerHit.lastContact = ctime; + LOG_DEBUG("use saved tracker"); + } + } + + // else find global tracker + if (!ch->sourceHost.host.ip) + { + chs.init(); + chs.waitDelay = MIN_TRACKER_RETRY; + chs.excludeID = servMgr->sessionID; + chs.trackersOnly = true; + if (chl->pickSourceHits(chs)){ + ch->sourceHost = chs.best[0]; + tracker_check = true; + ch->trackerHit = chs.best[0]; + LOG_DEBUG("use global tracker"); + } + } + } + + chanMgr->hitlistlock.off(); + + if (servMgr->keepDownstreams && ch->lastStopTime && ch->lastStopTime < sys->getTime() - 7) { + ch->lastStopTime = 0; + LOG_DEBUG("------------ disconnect all downstreams"); + ChanPacket pack; + MemoryStream mem(pack.data,sizeof(pack.data)); + AtomStream atom(mem); + atom.writeInt(PCP_QUIT,PCP_ERROR_QUIT+PCP_ERROR_OFFAIR); + pack.len = mem.pos; + pack.type = ChanPacket::T_PCP; + GnuID noID; + noID.clear(); + servMgr->broadcastPacket(pack,ch->info.id,ch->remoteID,noID,Servent::T_RELAY); + + chanMgr->hitlistlock.on(); + ChanHitList *hl = chanMgr->findHitList(ch->info); + if (hl){ + hl->clearHits(false); + } + chanMgr->hitlistlock.off(); + } + + // no trackers found so contact YP + if (!tracker_check && !ch->sourceHost.host.ip) + { + next_yp = false; + if (servMgr->rootHost.isEmpty()) + goto yp2; + + if (numYPTries >= 3) + goto yp2; + + if ((!servMgr->rootHost2.isEmpty()) && (numYPTries > numYPTries2)) + goto yp2; + + unsigned int ctime=sys->getTime(); + if ((ctime-chanMgr->lastYPConnect) > MIN_YP_RETRY) + { + ch->sourceHost.host.fromStrName(servMgr->rootHost.cstr(),DEFAULT_PORT); + ch->sourceHost.yp = true; + chanMgr->lastYPConnect=ctime; + numYPTries++; + } + if (numYPTries < 3) + next_yp = true; + } + +yp2: + // no trackers found so contact YP2 + if (!tracker_check && !ch->sourceHost.host.ip) + { +// next_yp = false; + if (servMgr->rootHost2.isEmpty()) + goto yp0; + + if (numYPTries2 >= 3) + goto yp0; + + unsigned int ctime=sys->getTime(); + if ((ctime-chanMgr->lastYPConnect2) > MIN_YP_RETRY) + { + ch->sourceHost.host.fromStrName(servMgr->rootHost2.cstr(),DEFAULT_PORT); + ch->sourceHost.yp = true; + chanMgr->lastYPConnect2=ctime; + numYPTries2++; + } + if (numYPTries2 < 3) + next_yp = true; + } +yp0: + if (!tracker_check && !ch->sourceHost.host.ip && !next_yp) break; + + sys->sleepIdle(); + + }while((ch->sourceHost.host.ip==0) && (ch->thread.active)); + + if (!ch->sourceHost.host.ip) + { + LOG_ERROR("Channel giving up"); + ch->setStatus(Channel::S_ERROR); + break; + } + + if (ch->sourceHost.yp) + { + LOG_CHANNEL("Channel contacting YP, try %d",numYPTries); + }else + { + LOG_CHANNEL("Channel found hit"); + numYPTries=0; + numYPTries2=0; + } + + if (ch->sourceHost.host.ip) + { + bool isTrusted = ch->sourceHost.tracker | ch->sourceHost.yp; + + + //if (ch->sourceHost.tracker) + // peercastApp->notifyMessage(ServMgr::NT_PEERCAST,"Contacting tracker, please wait..."); + + char ipstr[64]; + ch->sourceHost.host.toStr(ipstr); + + char *type = ""; + if (ch->sourceHost.tracker) + type = "(tracker)"; + else if (ch->sourceHost.yp) + type = "(YP)"; + + int error=-1; + int got503 = 0; + try + { + ch->setStatus(Channel::S_CONNECTING); + ch->sourceHost.lastContact = sys->getTime(); + + if (!ch->sock) + { + LOG_CHANNEL("Channel connecting to %s %s",ipstr,type); + ch->connectFetch(); + } + + error = ch->handshakeFetch(); + if (error == 503) { + got503 = 1; + error = 0; + } + if (error) + throw StreamException("Handshake error"); + if (ch->sourceHost.tracker) connFailCnt = 0; + + if (servMgr->autoMaxRelaySetting) //JP-EX + { + double setMaxRelays = ch->info.bitrate?servMgr->maxBitrateOut/(ch->info.bitrate*1.3):0; + if ((unsigned int)setMaxRelays == 0) + servMgr->maxRelays = 1; + else if ((unsigned int)setMaxRelays > servMgr->autoMaxRelaySetting) + servMgr->maxRelays = servMgr->autoMaxRelaySetting; + else + servMgr->maxRelays = (unsigned int)setMaxRelays; + } + + ch->sourceStream = ch->createSource(); + + error = ch->readStream(*ch->sock,ch->sourceStream); + if (error) + throw StreamException("Stream error"); + + error = 0; // no errors, closing normally. +// ch->setStatus(Channel::S_CLOSING); + ch->setStatus(Channel::S_IDLE); + + LOG_CHANNEL("Channel closed normally"); + }catch(StreamException &e) + { + ch->setStatus(Channel::S_ERROR); + LOG_ERROR("Channel to %s %s : %s",ipstr,type,e.msg); + if (!servMgr->allowConnectPCST) //JP-EX + { + if (ch->info.srcProtocol == ChanInfo::SP_PEERCAST) + ch->thread.active = false; + } + //if (!ch->sourceHost.tracker || ((error != 503) && ch->sourceHost.tracker)) + if (!ch->sourceHost.tracker || (!got503 && ch->sourceHost.tracker)) + chanMgr->deadHit(ch->sourceHost); + if (ch->sourceHost.tracker && error == -1) { + LOG_ERROR("can't connect to tracker"); + connFailCnt++; + } + } + + unsigned int ctime = sys->getTime(); + if (ch->rawData.lastWriteTime) { + ch->lastStopTime = ch->rawData.lastWriteTime; + if (isIndexTxt(ch) && ctime - ch->lastStopTime < 60) + ch->lastStopTime = ctime; + } + + if (tracker_check && ch->sourceHost.tracker) + ch->trackerHit.lastContact = ctime - 30 + (rand() % 30); + + // broadcast source host + if (!error && ch->sourceHost.host.ip) { // if closed normally + ChanPacket pack; + MemoryStream mem(pack.data,sizeof(pack.data)); + AtomStream atom(mem); + ch->sourceHost.writeAtoms(atom, ch->info.id); + pack.len = mem.pos; + pack.type = ChanPacket::T_PCP; + GnuID noID; + noID.clear(); + servMgr->broadcastPacket(pack,ch->info.id,ch->remoteID,noID,Servent::T_RELAY); + LOG_DEBUG("stream: broadcast sourceHost"); + } + + // broadcast quit to any connected downstream servents + if (!servMgr->keepDownstreams || (ch->sourceHost.tracker && !got503) || !error) { + ChanPacket pack; + MemoryStream mem(pack.data,sizeof(pack.data)); + AtomStream atom(mem); + atom.writeInt(PCP_QUIT,PCP_ERROR_QUIT+PCP_ERROR_OFFAIR); + pack.len = mem.pos; + pack.type = ChanPacket::T_PCP; + GnuID noID; + noID.clear(); + servMgr->broadcastPacket(pack,ch->info.id,ch->remoteID,noID,Servent::T_RELAY); + LOG_DEBUG("------------ broadcast quit to all downstreams"); + + chanMgr->hitlistlock.on(); + ChanHitList *hl = chanMgr->findHitList(ch->info); + if (hl){ + hl->clearHits(false); + } + chanMgr->hitlistlock.off(); + } + + + if (ch->sourceStream) + { + try + { + if (!error) + { + ch->sourceStream->updateStatus(ch); + ch->sourceStream->flush(*ch->sock); + } + }catch(StreamException &) + {} + ChannelStream *cs = ch->sourceStream; + ch->sourceStream = NULL; + cs->kill(); + delete cs; + } + + if (ch->sock) + { + ch->sock->close(); + delete ch->sock; + ch->sock = NULL; + } + + if (error == 404) + { + LOG_ERROR("Channel not found"); + //if (!next_yp){ + if ((ch->sourceHost.yp && !next_yp) || ch->sourceHost.tracker) { + chanMgr->hitlistlock.on(); + ChanHitList *hl = chanMgr->findHitList(ch->info); + if (hl){ + hl->clearHits(true); + } + chanMgr->hitlistlock.off(); + + if(!isIndexTxt(&ch->info)) // for PCRaw (popup) + peercastApp->notifyMessage(ServMgr::NT_PEERCAST,"Channel not found"); + return; + } + } + + + } + + ch->lastIdleTime = sys->getTime(); + ch->setStatus(Channel::S_IDLE); + ch->skipCount = 0; //JP-EX + ch->lastSkipTime = 0; + while ((ch->checkIdle()) && (ch->thread.active)) + { + sys->sleepIdle(); + } + + sys->sleepIdle(); + } + +} +// ----------------------------------- +void Channel::startICY(ClientSocket *cs, SRC_TYPE st) +{ + srcType = st; + type = T_BROADCAST; + cs->setReadTimeout(0); // stay connected even when theres no data coming through + sock = cs; + info.srcProtocol = ChanInfo::SP_HTTP; + + streamIndex = ++chanMgr->icyIndex; + + sourceData = new ICYSource(); + startStream(); +} + +// ----------------------------------- +static char *nextMetaPart(char *str,char delim) +{ + while (*str) + { + if (*str == delim) + { + *str++ = 0; + return str; + } + str++; + } + return NULL; +} +// ----------------------------------- +static void copyStr(char *to,char *from,int max) +{ + char c; + while ((c=*from++) && (--max)) + if (c != '\'') + *to++ = c; + + *to = 0; +} + +// ----------------------------------- +void Channel::processMp3Metadata(char *str) +{ + ChanInfo newInfo = info; + + char *cmd=str; + while (cmd) + { + char *arg = nextMetaPart(cmd,'='); + if (!arg) + break; + + char *next = nextMetaPart(arg,';'); + + if (strcmp(cmd,"StreamTitle")==0) + { + newInfo.track.title.setUnquote(arg,String::T_ASCII); + newInfo.track.title.convertTo(String::T_UNICODE); + + }else if (strcmp(cmd,"StreamUrl")==0) + { + newInfo.track.contact.setUnquote(arg,String::T_ASCII); + newInfo.track.contact.convertTo(String::T_UNICODE); + } + + + cmd = next; + } + + updateInfo(newInfo); +} + +// ----------------------------------- +XML::Node *ChanHit::createXML() +{ + // IP + char ipStr[64]; + host.toStr(ipStr); + + return new XML::Node("host ip=\"%s\" hops=\"%d\" listeners=\"%d\" relays=\"%d\" uptime=\"%d\" push=\"%d\" relay=\"%d\" direct=\"%d\" cin=\"%d\" stable=\"%d\" version=\"%d\" update=\"%d\" tracker=\"%d\"", + ipStr, + numHops, + numListeners, + numRelays, + upTime, + firewalled?1:0, + relay?1:0, + direct?1:0, + cin?1:0, + stable?1:0, + version, + sys->getTime()-time, + tracker + ); + +} + +// ----------------------------------- +XML::Node *ChanHitList::createXML(bool addHits) +{ + XML::Node *hn = new XML::Node("hits hosts=\"%d\" listeners=\"%d\" relays=\"%d\" firewalled=\"%d\" closest=\"%d\" furthest=\"%d\" newest=\"%d\"", + numHits(), + numListeners(), + numRelays(), + numFirewalled(), + closestHit(), + furthestHit(), + sys->getTime()-newestHit() + ); + + if (addHits) + { + ChanHit *h = hit; + while (h) + { + if (h->host.ip) + hn->add(h->createXML()); + h = h->next; + } + } + + return hn; +} + +// ----------------------------------- +XML::Node *Channel::createRelayXML(bool showStat) +{ + const char *ststr; + ststr = getStatusStr(); + if (!showStat) + if ((status == S_RECEIVING) || (status == S_BROADCASTING)) + ststr = "OK"; + + ChanHitList *chl = chanMgr->findHitList(info); + + return new XML::Node("relay listeners=\"%d\" relays=\"%d\" hosts=\"%d\" status=\"%s\"", + localListeners(), + localRelays(), + (chl!=NULL)?chl->numHits():0, + ststr + ); +} + +// ----------------------------------- +void ChanMeta::fromXML(XML &xml) +{ + MemoryStream tout(data,MAX_DATALEN); + xml.write(tout); + + len = tout.pos; +} +// ----------------------------------- +void ChanMeta::fromMem(void *p, int l) +{ + len = l; + memcpy(data,p,len); +} +// ----------------------------------- +void ChanMeta::addMem(void *p, int l) +{ + if ((len+l) <= MAX_DATALEN) + { + memcpy(data+len,p,l); + len += l; + } +} +// ----------------------------------- +void Channel::broadcastTrackerUpdate(GnuID &svID, bool force) +{ + unsigned int ctime = sys->getTime(); + + if (((ctime-lastTrackerUpdate) > 30) || (force)) + { + ChanPacket pack; + + MemoryStream mem(pack.data,sizeof(pack)); + + AtomStream atom(mem); + + ChanHit hit; + + ChanHitList *chl = chanMgr->findHitListByID(info.id); + if (!chl) + throw StreamException("Broadcast channel has no hitlist"); + + int numListeners = totalListeners(); + int numRelays = totalRelays(); + + unsigned int oldp = rawData.getOldestPos(); + unsigned int newp = rawData.getLatestPos(); + + hit.initLocal(numListeners,numRelays,info.numSkips,info.getUptime(),isPlaying(), false, 0, this, oldp,newp); + hit.tracker = true; + +#ifndef VERSION_EX + atom.writeParent(PCP_BCST,8); +#else + atom.writeParent(PCP_BCST,10); +#endif + atom.writeChar(PCP_BCST_GROUP,PCP_BCST_GROUP_ROOT); + atom.writeChar(PCP_BCST_HOPS,0); + atom.writeChar(PCP_BCST_TTL,11); + atom.writeBytes(PCP_BCST_FROM,servMgr->sessionID.id,16); + atom.writeInt(PCP_BCST_VERSION,PCP_CLIENT_VERSION); + atom.writeInt(PCP_BCST_VERSION_VP,PCP_CLIENT_VERSION_VP); +#ifdef VERSION_EX + atom.writeBytes(PCP_BCST_VERSION_EX_PREFIX,PCP_CLIENT_VERSION_EX_PREFIX,2); + atom.writeShort(PCP_BCST_VERSION_EX_NUMBER,PCP_CLIENT_VERSION_EX_NUMBER); +#endif + atom.writeParent(PCP_CHAN,4); + atom.writeBytes(PCP_CHAN_ID,info.id.id,16); + atom.writeBytes(PCP_CHAN_BCID,chanMgr->broadcastID.id,16); + info.writeInfoAtoms(atom); + info.writeTrackAtoms(atom); + hit.writeAtoms(atom,info.id); + + + pack.len = mem.pos; + pack.type = ChanPacket::T_PCP; + + GnuID noID; + noID.clear(); + int cnt = servMgr->broadcastPacket(pack,noID,servMgr->sessionID,svID,Servent::T_COUT); + + if (cnt) + { + LOG_DEBUG("Sent tracker update for %s to %d client(s)",info.name.cstr(),cnt); + lastTrackerUpdate = ctime; + } + } +} + +// ----------------------------------- +bool Channel::sendPacketUp(ChanPacket &pack,GnuID &cid,GnuID &sid,GnuID &did) +{ + if ( isActive() + && (!cid.isSet() || info.id.isSame(cid)) + && (!sid.isSet() || !remoteID.isSame(sid)) + && sourceStream + ) + return sourceStream->sendPacket(pack,did); + + return false; +} + +// ----------------------------------- +void Channel::updateInfo(ChanInfo &newInfo) +{ + if (info.update(newInfo)) + { + if (isBroadcasting()) + { + unsigned int ctime = sys->getTime(); + if ((ctime-lastMetaUpdate) > 30) + { + lastMetaUpdate = ctime; + + ChanPacket pack; + + MemoryStream mem(pack.data,sizeof(pack)); + + AtomStream atom(mem); + +#ifndef VERSION_EX + atom.writeParent(PCP_BCST,8); +#else + atom.writeParent(PCP_BCST,10); +#endif + atom.writeChar(PCP_BCST_HOPS,0); + atom.writeChar(PCP_BCST_TTL,7); + atom.writeChar(PCP_BCST_GROUP,PCP_BCST_GROUP_RELAYS); + atom.writeBytes(PCP_BCST_FROM,servMgr->sessionID.id,16); + atom.writeInt(PCP_BCST_VERSION,PCP_CLIENT_VERSION); + atom.writeInt(PCP_BCST_VERSION_VP,PCP_CLIENT_VERSION_VP); +#ifdef VERSION_EX + atom.writeBytes(PCP_BCST_VERSION_EX_PREFIX,PCP_CLIENT_VERSION_EX_PREFIX,2); + atom.writeShort(PCP_BCST_VERSION_EX_NUMBER,PCP_CLIENT_VERSION_EX_NUMBER); +#endif + atom.writeBytes(PCP_BCST_CHANID,info.id.id,16); + atom.writeParent(PCP_CHAN,3); + atom.writeBytes(PCP_CHAN_ID,info.id.id,16); + info.writeInfoAtoms(atom); + info.writeTrackAtoms(atom); + + pack.len = mem.pos; + pack.type = ChanPacket::T_PCP; + GnuID noID; + noID.clear(); + servMgr->broadcastPacket(pack,info.id,servMgr->sessionID,noID,Servent::T_RELAY); + + broadcastTrackerUpdate(noID); + } + } + + ChanHitList *chl = chanMgr->findHitList(info); + if (chl) + chl->info = info; + + peercastApp->channelUpdate(&info); + + } + +} +// ----------------------------------- +ChannelStream *Channel::createSource() +{ +// if (servMgr->relayBroadcast) +// chanMgr->broadcastRelays(NULL,chanMgr->minBroadcastTTL,chanMgr->maxBroadcastTTL); + + + ChannelStream *source=NULL; + + if (info.srcProtocol == ChanInfo::SP_PEERCAST) + { + LOG_CHANNEL("Channel is Peercast"); + if (servMgr->allowConnectPCST) //JP-EX + source = new PeercastStream(); + else + throw StreamException("Channel is not allowed"); + } + else if (info.srcProtocol == ChanInfo::SP_PCP) + { + LOG_CHANNEL("Channel is PCP"); + PCPStream *pcp = new PCPStream(remoteID); + source = pcp; + } + else if (info.srcProtocol == ChanInfo::SP_MMS) + { + LOG_CHANNEL("Channel is MMS"); + source = new MMSStream(); + }else + { + switch(info.contentType) + { + case ChanInfo::T_MP3: + LOG_CHANNEL("Channel is MP3 - meta: %d",icyMetaInterval); + source = new MP3Stream(); + break; + case ChanInfo::T_NSV: + LOG_CHANNEL("Channel is NSV"); + source = new NSVStream(); + break; + case ChanInfo::T_WMA: + case ChanInfo::T_WMV: + throw StreamException("Channel is WMA/WMV - but not MMS"); + break; + case ChanInfo::T_OGG: + case ChanInfo::T_OGM: + LOG_CHANNEL("Channel is OGG"); + source = new OGGStream(); + break; + default: + LOG_CHANNEL("Channel is Raw"); + source = new RawStream(); + break; + } + } + + source->parent = this; + + return source; +} +// ------------------------------------------ +void ChannelStream::updateStatus(Channel *ch) +{ + ChanPacket pack; + if (getStatus(ch,pack)) + { + if (!ch->isBroadcasting()) + { + GnuID noID; + noID.clear(); + int cnt = chanMgr->broadcastPacketUp(pack,ch->info.id,servMgr->sessionID,noID); + LOG_CHANNEL("Sent channel status update to %d clients",cnt); + } + } +} + +// ------------------------------------------ +bool ChannelStream::getStatus(Channel *ch,ChanPacket &pack) +{ + unsigned int ctime = sys->getTime(); + + ChanHitList *chl = chanMgr->findHitListByID(ch->info.id); + + if (!chl) + return false; + +/* int newLocalListeners = ch->localListeners(); + int newLocalRelays = ch->localRelays(); + + if ( + ( + (numListeners != newLocalListeners) + || (numRelays != newLocalRelays) + || (ch->isPlaying() != isPlaying) + || (servMgr->getFirewall() != fwState) + || (((ctime-lastUpdate)>chanMgr->hostUpdateInterval) && chanMgr->hostUpdateInterval) + ) + && ((ctime-lastUpdate) > 10) + ) + { + + numListeners = newLocalListeners; + numRelays = newLocalRelays; + isPlaying = ch->isPlaying(); + fwState = servMgr->getFirewall(); + lastUpdate = ctime; + + ChanHit hit; + + hit.initLocal(ch->localListeners(),ch->localRelays(),ch->info.numSkips,ch->info.getUptime(),isPlaying, ch->isFull(), ch->info.bitrate, ch); + hit.tracker = ch->isBroadcasting();*/ + + int newLocalListeners = ch->localListeners(); + int newLocalRelays = ch->localRelays(); + + if ((ch->isPlaying() == isPlaying)){ + if ((ctime-lastUpdate) < 10){ + return false; + } + + if ((ctime-lastCheckTime) < 10){ + return false; + } + lastCheckTime = ctime; + } + + unsigned int oldp = ch->rawData.getOldestPos(); + unsigned int newp = ch->rawData.getLatestPos(); + + ChanHit hit; + +// LOG_DEBUG("isPlaying-------------------------------------- %d %d", ch->isPlaying(), isPlaying); + + hit.initLocal(newLocalListeners,newLocalRelays,ch->info.numSkips,ch->info.getUptime(),ch->isPlaying(), ch->isFull(), ch->info.bitrate, ch, oldp, newp); + hit.tracker = ch->isBroadcasting(); + + if ( (((ctime-lastUpdate)>chanMgr->hostUpdateInterval) && chanMgr->hostUpdateInterval) + || (newLocalListeners != numListeners) + || (newLocalRelays != numRelays) + || (ch->isPlaying() != isPlaying) + || (servMgr->getFirewall() != fwState) + || (ch->chDisp.relay != hit.relay) + || (ch->chDisp.relayfull != hit.relayfull) + || (ch->chDisp.chfull != hit.chfull) + || (ch->chDisp.ratefull != hit.ratefull) + ){ + numListeners = newLocalListeners; + numRelays = newLocalRelays; + isPlaying = ch->isPlaying(); + fwState = servMgr->getFirewall(); + lastUpdate = ctime; + + ch->chDisp = hit; + + if ((numRelays) && ((servMgr->getFirewall() == ServMgr::FW_OFF) && (servMgr->autoRelayKeep!=0))) //JP-EX + ch->stayConnected = true; + + if ((!numRelays && !numListeners) && (servMgr->autoRelayKeep==2)) //JP-EX + ch->stayConnected = false; + + MemoryStream pmem(pack.data,sizeof(pack.data)); + AtomStream atom(pmem); + + GnuID noID; + noID.clear(); + +#ifndef VERSION_EX + atom.writeParent(PCP_BCST,8); +#else + atom.writeParent(PCP_BCST,10); +#endif + atom.writeChar(PCP_BCST_GROUP,PCP_BCST_GROUP_TRACKERS); + atom.writeChar(PCP_BCST_HOPS,0); + atom.writeChar(PCP_BCST_TTL,11); + atom.writeBytes(PCP_BCST_FROM,servMgr->sessionID.id,16); + atom.writeInt(PCP_BCST_VERSION,PCP_CLIENT_VERSION); + atom.writeInt(PCP_BCST_VERSION_VP,PCP_CLIENT_VERSION_VP); +#ifdef VERSION_EX + atom.writeBytes(PCP_BCST_VERSION_EX_PREFIX,PCP_CLIENT_VERSION_EX_PREFIX,2); + atom.writeShort(PCP_BCST_VERSION_EX_NUMBER,PCP_CLIENT_VERSION_EX_NUMBER); +#endif + atom.writeBytes(PCP_BCST_CHANID,ch->info.id.id,16); + hit.writeAtoms(atom,noID); + + pack.len = pmem.pos; + pack.type = ChanPacket::T_PCP; + return true; + }else + return false; +} +// ----------------------------------- +bool Channel::checkBump() +{ + if (!isBroadcasting() && (!sourceHost.tracker)) + if (rawData.lastWriteTime && ((sys->getTime() - rawData.lastWriteTime) > 30)) + { + LOG_ERROR("Channel Auto bumped"); + bump = true; + } + + if (bump) + { + bump = false; + return true; + }else + return false; +} + +// ----------------------------------- +int Channel::readStream(Stream &in,ChannelStream *source) +{ + //sys->sleep(300); + + int error = 0; + + info.numSkips = 0; + + source->readHeader(in,this); + + peercastApp->channelStart(&info); + + rawData.lastWriteTime = 0; + + bool wasBroadcasting=false; + + unsigned int receiveStartTime = 0; + + try + { + while (thread.active && !peercastInst->isQuitting) + { + if (checkIdle()) + { + LOG_DEBUG("Channel idle"); + break; + } + + if (checkBump()) + { + LOG_DEBUG("Channel bumped"); + error = -1; + bumped = true; + break; + } + + if (in.eof()) + { + LOG_DEBUG("Channel eof"); + break; + } + + if (in.readReady()) + { + error = source->readPacket(in,this); + + if (error) + break; + + //if (rawData.writePos > 0) + if (rawData.lastWriteTime > 0) + { + if (isBroadcasting()) + { + if ((sys->getTime()-lastTrackerUpdate) >= chanMgr->hostUpdateInterval) + { + GnuID noID; + noID.clear(); + broadcastTrackerUpdate(noID); + } + wasBroadcasting = true; + + }else + { +/* if (status != Channel::S_RECEIVING){ + receiveStartTime = sys->getTime(); + } else if (receiveStartTime && receiveStartTime + 10 > sys->getTime()){ + chanMgr->hitlistlock.on(); + ChanHitList *hl = chanMgr->findHitList(info); + if (hl){ + hl->clearHits(true); + } + chanMgr->hitlistlock.off(); + receiveStartTime = 0; + }*/ + setStatus(Channel::S_RECEIVING); + bumped = false; + } + source->updateStatus(this); + } + } + + source->flush(in); + + sys->sleepIdle(); + } + }catch(StreamException &e) + { + LOG_ERROR("readStream: %s",e.msg); + error = -1; + } + + if (!servMgr->keepDownstreams) { + if (status == Channel::S_RECEIVING){ + chanMgr->hitlistlock.on(); + ChanHitList *hl = chanMgr->findHitList(info); + if (hl){ + hl->clearHits(false); + } + chanMgr->hitlistlock.off(); + } + } + +// setStatus(S_CLOSING); + setStatus(S_IDLE); + + if (wasBroadcasting) + { + GnuID noID; + noID.clear(); + broadcastTrackerUpdate(noID,true); + } + + peercastApp->channelStop(&info); + + source->readEnd(in,this); + + return error; +} + +// ----------------------------------- +void PeercastStream::readHeader(Stream &in,Channel *ch) +{ + if (in.readTag() != 'PCST') + throw StreamException("Not PeerCast stream"); + +} +// ----------------------------------- +void PeercastStream::readEnd(Stream &,Channel *) +{ + +} +// ----------------------------------- +int PeercastStream::readPacket(Stream &in,Channel *ch) +{ + ChanPacket pack; + + { + + pack.readPeercast(in); + + MemoryStream mem(pack.data,pack.len); + + switch(pack.type) + { + case ChanPacket::T_HEAD: + // update sync pos + ch->headPack = pack; + pack.pos = ch->streamPos; + ch->newPacket(pack); + ch->streamPos+=pack.len; + break; + case ChanPacket::T_DATA: + pack.pos = ch->streamPos; + ch->newPacket(pack); + ch->streamPos+=pack.len; + break; + case ChanPacket::T_META: + ch->insertMeta.fromMem(pack.data,pack.len); + { + if (pack.len) + { + XML xml; + xml.read(mem); + XML::Node *n = xml.findNode("channel"); + if (n) + { + ChanInfo newInfo = ch->info; + newInfo.updateFromXML(n); + ChanHitList *chl = chanMgr->findHitList(ch->info); + if (chl) + newInfo.updateFromXML(n); + ch->updateInfo(newInfo); + } + } + } + break; +#if 0 + case ChanPacket::T_SYNC: + { + unsigned int s = mem.readLong(); + if ((s-ch->syncPos) != 1) + { + LOG_CHANNEL("Ch.%d SKIP: %d to %d (%d)",ch->index,ch->syncPos,s,ch->info.numSkips); + if (ch->syncPos) + { + ch->info.numSkips++; + if (ch->info.numSkips>50) + throw StreamException("Bumped - Too many skips"); + } + } + + ch->syncPos = s; + } + break; +#endif + + } + + } + return 0; +} + +// ----------------------------------- +void ChannelStream::readRaw(Stream &in, Channel *ch) +{ + ChanPacket pack; + + const int readLen = 8192; + + pack.init(ChanPacket::T_DATA,pack.data,readLen,ch->streamPos); + in.read(pack.data,pack.len); + ch->newPacket(pack); + ch->checkReadDelay(pack.len); + + ch->streamPos+=pack.len; + +} +// ------------------------------------------ +void RawStream::readHeader(Stream &,Channel *) +{ +} + +// ------------------------------------------ +int RawStream::readPacket(Stream &in,Channel *ch) +{ + readRaw(in,ch); + return 0; +} + +// ------------------------------------------ +void RawStream::readEnd(Stream &,Channel *) +{ +} + + + +// ----------------------------------- +void ChanPacket::init(ChanPacketv &p) +{ + type = p.type; + len = p.len; + pos = p.pos; + sync = p.sync; + skip = p.skip; + memcpy(data, p.data, len); +} +// ----------------------------------- +void ChanPacket::init(TYPE t, const void *p, unsigned int l,unsigned int _pos) +{ + type = t; + if (l > MAX_DATALEN) + throw StreamException("Packet data too large"); + len = l; + memcpy(data,p,len); + pos = _pos; + skip = false; +} +// ----------------------------------- +void ChanPacket::writeRaw(Stream &out) +{ + out.write(data,len); +} +// ----------------------------------- +void ChanPacket::writePeercast(Stream &out) +{ + unsigned int tp = 0; + switch (type) + { + case T_HEAD: tp = 'HEAD'; break; + case T_META: tp = 'META'; break; + case T_DATA: tp = 'DATA'; break; + } + + if (type != T_UNKNOWN) + { + out.writeTag(tp); + out.writeShort(len); + out.writeShort(0); + out.write(data,len); + } +} +// ----------------------------------- +void ChanPacket::readPeercast(Stream &in) +{ + unsigned int tp = in.readTag(); + + switch (tp) + { + case 'HEAD': type = T_HEAD; break; + case 'DATA': type = T_DATA; break; + case 'META': type = T_META; break; + default: type = T_UNKNOWN; + } + len = in.readShort(); + in.readShort(); + if (len > MAX_DATALEN) + throw StreamException("Bad ChanPacket"); + in.read(data,len); +} +// ----------------------------------- +int ChanPacketBuffer::copyFrom(ChanPacketBuffer &buf, unsigned int reqPos) +{ + lock.on(); + buf.lock.on(); + + firstPos = 0; + lastPos = 0; + safePos = 0; + readPos = 0; + + for(unsigned int i=buf.firstPos; i<=buf.lastPos; i++) + { + //ChanPacket *src = &buf.packets[i%MAX_PACKETS]; + ChanPacketv *src = &buf.packets[i%MAX_PACKETS]; + if (src->type & accept) + { + if (src->pos >= reqPos) + { + lastPos = writePos; + //packets[writePos++] = *src; + packets[writePos++].init(*src); + } + } + + } + + + buf.lock.off(); + lock.off(); + return lastPos-firstPos; +} + +// ----------------------------------- +bool ChanPacketBuffer::findPacket(unsigned int spos, ChanPacket &pack) +{ + if (writePos == 0) + return false; + + lock.on(); + + unsigned int fpos = getStreamPos(firstPos); + if (spos < fpos) + spos = fpos; + + + for(unsigned int i=firstPos; i<=lastPos; i++) + { + //ChanPacket &p = packets[i%MAX_PACKETS]; + ChanPacketv &p = packets[i%MAX_PACKETS]; + if (p.pos >= spos) + { + pack.init(p); + lock.off(); + return true; + } + } + + lock.off(); + return false; +} +// ----------------------------------- +unsigned int ChanPacketBuffer::getLatestPos() +{ + if (!writePos) + return 0; + else + return getStreamPos(lastPos); + +} +// ----------------------------------- +unsigned int ChanPacketBuffer::getOldestPos() +{ + if (!writePos) + return 0; + else + return getStreamPos(firstPos); +} + +// ----------------------------------- +unsigned int ChanPacketBuffer::findOldestPos(unsigned int spos) +{ + unsigned int min = getStreamPos(safePos); + unsigned int max = getStreamPos(lastPos); + + if (min > spos) + return min; + + if (max < spos) + return max; + + return spos; +} + +// ----------------------------------- +unsigned int ChanPacketBuffer::getStreamPos(unsigned int index) +{ + return packets[index%MAX_PACKETS].pos; +} +// ----------------------------------- +unsigned int ChanPacketBuffer::getStreamPosEnd(unsigned int index) +{ + return packets[index%MAX_PACKETS].pos+packets[index%MAX_PACKETS].len; +} +// ----------------------------------- +bool ChanPacketBuffer::writePacket(ChanPacket &pack, bool updateReadPos) +{ + if (pack.len) + { + if (servMgr->keepDownstreams) { + unsigned int lpos = getLatestPos(); + unsigned int diff = pack.pos - lpos; + if (packets[lastPos%MAX_PACKETS].type == ChanPacket::T_HEAD) lpos = 0; + if (lpos && (diff == 0 || diff > 0xfff00000)) { + LOG_DEBUG("* latest pos=%d, pack pos=%d", getLatestPos(), pack.pos); + return false; + } + } + + if (willSkip()) // too far behind + { + lastSkipTime = sys->getTime(); + return false; + } + + lock.on(); + + pack.sync = writePos; + packets[writePos%MAX_PACKETS].init(pack); + +// LOG_DEBUG("packet.len = %d",pack.len); + + + lastPos = writePos; + writePos++; + + if (writePos >= MAX_PACKETS) + firstPos = writePos-MAX_PACKETS; + else + firstPos = 0; + + if (writePos >= NUM_SAFEPACKETS) + safePos = writePos - NUM_SAFEPACKETS; + else + safePos = 0; + + if (updateReadPos) + readPos = writePos; + + lastWriteTime = sys->getTime(); + + lock.off(); + return true; + } + + return false; +} +// ----------------------------------- +void ChanPacketBuffer::readPacket(ChanPacket &pack) +{ + + unsigned int tim = sys->getTime(); + + if (readPos < firstPos) + throw StreamException("Read too far behind"); + + while (readPos >= writePos) + { + sys->sleepIdle(); + if ((sys->getTime() - tim) > 30) + throw TimeoutException(); + } + lock.on(); + pack.init(packets[readPos%MAX_PACKETS]); + readPos++; + lock.off(); + + sys->sleepIdle(); + +} +// ----------------------------------- +bool ChanPacketBuffer::willSkip() +{ + return ((writePos-readPos) >= MAX_PACKETS); +} + +// ----------------------------------- +void Channel::getStreamPath(char *str) +{ + char idStr[64]; + + getIDStr(idStr); + + sprintf(str,"/stream/%s%s",idStr,info.getTypeExt(info.contentType)); +} + + + +// ----------------------------------- +void ChanMgr::startSearch(ChanInfo &info) +{ + searchInfo = info; + clearHitLists(); + numFinds = 0; + lastHit = 0; +// lastSearch = 0; + searchActive = true; +} +// ----------------------------------- +void ChanMgr::quit() +{ + LOG_DEBUG("ChanMgr is quitting.."); + closeAll(); +} +// ----------------------------------- +int ChanMgr::numIdleChannels() +{ + int cnt=0; + Channel *ch = channel; + while (ch) + { + if (ch->isActive()) + if (ch->thread.active) + if (ch->status == Channel::S_IDLE) + cnt++; + ch=ch->next; + } + return cnt; +} +// ----------------------------------- +void ChanMgr::closeOldestIdle() +{ + unsigned int idleTime = (unsigned int)-1; + Channel *ch = channel,*oldest=NULL; + while (ch) + { + if (ch->isActive()) + if (ch->thread.active) + if (ch->status == Channel::S_IDLE) + if (ch->lastIdleTime < idleTime) + { + oldest = ch; + idleTime = ch->lastIdleTime; + } + ch=ch->next; + } + + if (oldest) + oldest->thread.active = false; +} + +// ----------------------------------- +void ChanMgr::closeAll() +{ + Channel *ch = channel; + while (ch) + { + if (ch->thread.active) + ch->thread.shutdown(); + ch=ch->next; + } +} +// ----------------------------------- +Channel *ChanMgr::findChannelByNameID(ChanInfo &info) +{ + Channel *ch = channel; + while (ch) + { + if (ch->isActive()) + if (ch->info.matchNameID(info)) + return ch; + ch=ch->next; + } + return NULL; +} + +// ----------------------------------- +Channel *ChanMgr::findChannelByName(const char *n) +{ + Channel *ch = channel; + while (ch) + { + if (ch->isActive()) + if (stricmp(ch->info.name,n)==0) + return ch; + ch=ch->next; + } + + return NULL; +} +// ----------------------------------- +Channel *ChanMgr::findChannelByIndex(int index) +{ + int cnt=0; + Channel *ch = channel; + while (ch) + { + if (ch->isActive()) + { + if (cnt == index) + return ch; + cnt++; + } + ch=ch->next; + } + return NULL; +} +// ----------------------------------- +Channel *ChanMgr::findChannelByMount(const char *str) +{ + Channel *ch = channel; + while (ch) + { + if (ch->isActive()) + if (strcmp(ch->mount,str)==0) + return ch; + ch=ch->next; + } + + return NULL; +} +// ----------------------------------- +Channel *ChanMgr::findChannelByID(GnuID &id) +{ + Channel *ch = channel; + while (ch) + { + if (ch->isActive()) + if (ch->info.id.isSame(id)) + return ch; + ch=ch->next; + } + return NULL; +} +// ----------------------------------- +Channel *ChanMgr::findChannelByChannelID(int id) +{ + int cnt=0; + Channel *ch = channel; + while (ch) + { + if (ch->isActive()){ + if (ch->channel_id == id){ + return ch; + } + } + ch = ch->next; + } + return NULL; +} +// ----------------------------------- +int ChanMgr::findChannels(ChanInfo &info, Channel **chlist, int max) +{ + int cnt=0; + Channel *ch = channel; + while (ch) + { + if (ch->isActive()) + if (ch->info.match(info)) + { + chlist[cnt++] = ch; + if (cnt >= max) + break; + } + ch=ch->next; + } + return cnt; +} +// ----------------------------------- +int ChanMgr::findChannelsByStatus(Channel **chlist, int max, Channel::STATUS status) +{ + int cnt=0; + Channel *ch = channel; + while (ch) + { + if (ch->isActive()) + if (ch->status == status) + { + chlist[cnt++] = ch; + if (cnt >= max) + break; + } + ch=ch->next; + } + return cnt; +} +// ----------------------------------- +Channel *ChanMgr::createRelay(ChanInfo &info, bool stayConnected) +{ + Channel *c = chanMgr->createChannel(info,NULL); + if (c) + { + c->stayConnected = stayConnected; + c->startGet(); + return c; + } + return NULL; +} +// ----------------------------------- +Channel *ChanMgr::findAndRelay(ChanInfo &info) +{ + char idStr[64]; + info.id.toStr(idStr); + LOG_CHANNEL("Searching for: %s (%s)",idStr,info.name.cstr()); + + if(!isIndexTxt(&info)) // for PCRaw (popup) + peercastApp->notifyMessage(ServMgr::NT_PEERCAST,"Finding channel..."); + + + Channel *c = NULL; + + WLockBlock wb(&(chanMgr->channellock)); + + wb.on(); + + c = findChannelByNameID(info); + + if (!c) + { + c = chanMgr->createChannel(info,NULL); + if (c) + { + c->setStatus(Channel::S_SEARCHING); + c->startGet(); + } + } else if (!(c->thread.active)){ + c->thread.active = true; + c->thread.finish = false; + if (c->finthread){ + c->finthread->finish = true; + c->finthread = NULL; + } + if (c->status != Channel::S_CONNECTING && c->status != Channel::S_SEARCHING){ + c->setStatus(Channel::S_SEARCHING); + c->startGet(); + } + } + + wb.off(); + + for(int i=0; i<600; i++) // search for 1 minute. + { + + + wb.on(); + c = findChannelByNameID(info); + + if (!c) + { +// peercastApp->notifyMessage(ServMgr::NT_PEERCAST,"Channel not found"); + return NULL; + } + + + if (c->isPlaying() && (c->info.contentType!=ChanInfo::T_UNKNOWN)) + break; + + wb.off(); + + sys->sleep(100); + } + + return c; +} +// ----------------------------------- +ChanMgr::ChanMgr() +{ + channel = NULL; + + hitlist = NULL; + + currFindAndPlayChannel.clear(); + + broadcastMsg.clear(); + broadcastMsgInterval=10; + + broadcastID.generate(PCP_BROADCAST_FLAGS); + + deadHitAge = 600; + + icyIndex = 0; + icyMetaInterval = 8192; + maxRelaysPerChannel = 1; + + searchInfo.init(); + + minBroadcastTTL = 1; + maxBroadcastTTL = 7; + + pushTimeout = 60; // 1 minute + pushTries = 5; // 5 times + maxPushHops = 8; // max 8 hops away + maxUptime = 0; // 0 = none + + prefetchTime = 10; // n seconds + + hostUpdateInterval = 120; // 2 minutes + + bufferTime = 5; + + autoQuery = 0; + lastQuery = 0; + + lastYPConnect = 0; + lastYPConnect2 = 0; + +} + +// ----------------------------------- +bool ChanMgr::writeVariable(Stream &out, const String &var, int index) +{ + char buf[1024]; + if (var == "numHitLists") + sprintf(buf,"%d",numHitLists()); + + else if (var == "numChannels") + sprintf(buf,"%d",numChannels()); + else if (var == "djMessage") + strcpy(buf,broadcastMsg.cstr()); + else if (var == "icyMetaInterval") + sprintf(buf,"%d",icyMetaInterval); + else if (var == "maxRelaysPerChannel") + sprintf(buf,"%d",maxRelaysPerChannel); + else if (var == "hostUpdateInterval") + sprintf(buf,"%d",hostUpdateInterval); + else if (var == "broadcastID") + broadcastID.toStr(buf); + else + return false; + + + + out.writeString(buf); + return true; +} + +// ----------------------------------- +bool Channel::writeVariable(Stream &out, const String &var, int index) +{ + char buf[1024]; + + buf[0]=0; + + String utf8; + + if (var == "name") + { + utf8 = info.name; + utf8.convertTo(String::T_UNICODESAFE); + strcpy(buf,utf8.cstr()); + + }else if (var == "bitrate") + { + sprintf(buf,"%d",info.bitrate); + + }else if (var == "srcrate") + { + if (sourceData) + { + unsigned int tot = sourceData->getSourceRate(); + sprintf(buf,"%.1f",BYTES_TO_KBPS(tot)); + }else + strcpy(buf,"0"); + + }else if (var == "genre") + { + utf8 = info.genre; + utf8.convertTo(String::T_UNICODESAFE); + strcpy(buf,utf8.cstr()); + }else if (var == "desc") + { + utf8 = info.desc; + utf8.convertTo(String::T_UNICODESAFE); + strcpy(buf,utf8.cstr()); + }else if (var == "comment") + { + utf8 = info.comment; + utf8.convertTo(String::T_UNICODESAFE); + strcpy(buf,utf8.cstr()); + }else if (var == "uptime") + { + String uptime; + if (info.lastPlayStart) + uptime.setFromStopwatch(sys->getTime()-info.lastPlayStart); + else + uptime.set("-"); + strcpy(buf,uptime.cstr()); + } + else if (var == "type") + sprintf(buf,"%s",ChanInfo::getTypeStr(info.contentType)); + else if (var == "ext") + sprintf(buf,"%s",ChanInfo::getTypeExt(info.contentType)); + else if (var == "proto") { + switch(info.contentType) { + case ChanInfo::T_WMA: + case ChanInfo::T_WMV: + sprintf(buf, "mms://"); + break; + default: + sprintf(buf, "http://"); + } + } + else if (var == "localRelays") + sprintf(buf,"%d",localRelays()); + else if (var == "localListeners") + sprintf(buf,"%d",localListeners()); + + else if (var == "totalRelays") + sprintf(buf,"%d",totalRelays()); + else if (var == "totalListeners") + sprintf(buf,"%d",totalListeners()); + + else if (var == "status") + sprintf(buf,"%s",getStatusStr()); + else if (var == "keep") + sprintf(buf,"%s",stayConnected?"Yes":"No"); + else if (var == "id") + info.id.toStr(buf); + else if (var.startsWith("track.")) + { + + if (var == "track.title") + utf8 = info.track.title; + else if (var == "track.artist") + utf8 = info.track.artist; + else if (var == "track.album") + utf8 = info.track.album; + else if (var == "track.genre") + utf8 = info.track.genre; + else if (var == "track.contactURL") + utf8 = info.track.contact; + + utf8.convertTo(String::T_UNICODESAFE); + strcpy(buf,utf8.cstr()); + + }else if (var == "contactURL") + sprintf(buf,"%s",info.url.cstr()); + else if (var == "streamPos") + sprintf(buf,"%d",streamPos); + else if (var == "sourceType") + strcpy(buf,getSrcTypeStr()); + else if (var == "sourceProtocol") + strcpy(buf,ChanInfo::getProtocolStr(info.srcProtocol)); + else if (var == "sourceURL") + { + if (sourceURL.isEmpty()) + sourceHost.host.toStr(buf); + else + strcpy(buf,sourceURL.cstr()); + } + else if (var == "headPos") + sprintf(buf,"%d",headPack.pos); + else if (var == "headLen") + sprintf(buf,"%d",headPack.len); + else if (var == "numHits") + { + ChanHitList *chl = chanMgr->findHitListByID(info.id); + int numHits = 0; + if (chl){ +// numHits = chl->numHits(); + ChanHit *hit; + hit = chl->hit; + while(hit){ + numHits++; + hit = hit->next; + } + } + sprintf(buf,"%d",numHits); + } else if (var == "isBroadcast") + strcpy(buf, (type == T_BROADCAST) ? "1":"0"); + else + return false; + + out.writeString(buf); + return true; +} + +// ----------------------------------- +void ChanMgr::broadcastTrackerUpdate(GnuID &svID, bool force) +{ + Channel *c = channel; + while(c) + { + if ( c->isActive() && c->isBroadcasting() ) + c->broadcastTrackerUpdate(svID,force); + c=c->next; + } +} + + +// ----------------------------------- +int ChanMgr::broadcastPacketUp(ChanPacket &pack,GnuID &chanID, GnuID &srcID, GnuID &destID) +{ + int cnt=0; + + Channel *c = channel; + while(c) + { + if (c->sendPacketUp(pack,chanID,srcID,destID)) + cnt++; + c=c->next; + } + + return cnt; +} + +// ----------------------------------- +void ChanMgr::broadcastRelays(Servent *serv, int minTTL, int maxTTL) +{ + //if ((servMgr->getFirewall() == ServMgr::FW_OFF) || servMgr->serverHost.localIP()) + { + + Host sh = servMgr->serverHost; + bool push = (servMgr->getFirewall()!=ServMgr::FW_OFF); + bool busy = (servMgr->pubInFull() && servMgr->outFull()) || servMgr->relaysFull(); + bool stable = servMgr->totalStreams>0; + + + GnuPacket hit; + + int numChans=0; + + Channel *c = channel; + while(c) + { + if (c->isPlaying()) + { + + bool tracker = c->isBroadcasting(); + + int ttl = (c->info.getUptime() / servMgr->relayBroadcast); // 1 hop per N seconds + + if (ttl < minTTL) + ttl = minTTL; + + if (ttl > maxTTL) + ttl = maxTTL; + + if (hit.initHit(sh,c,NULL,push,busy,stable,tracker,ttl)) + { + int numOut=0; + numChans++; + if (serv) + { + serv->outputPacket(hit,false); + numOut++; + } + + LOG_NETWORK("Sent channel to %d servents, TTL %d",numOut,ttl); + + } + } + c=c->next; + } + //if (numChans) + // LOG_NETWORK("Sent %d channels to %d servents",numChans,numOut); + } +} +// ----------------------------------- +void ChanMgr::setUpdateInterval(unsigned int v) +{ + hostUpdateInterval = v; +} + + +// ----------------------------------- +// message check +#if 0 + ChanPacket pack; + MemoryStream mem(pack.data,sizeof(pack.data)); + AtomStream atom(mem); + atom.writeParent(PCP_BCST,3); + atom.writeChar(PCP_BCST_GROUP,PCP_BCST_GROUP_ALL); + atom.writeBytes(PCP_BCST_FROM,servMgr->sessionID.id,16); + atom.writeParent(PCP_MESG,1); + atom.writeString(PCP_MESG_DATA,msg.cstr()); + + mem.len = mem.pos; + mem.rewind(); + pack.len = mem.len; + + GnuID noID; + noID.clear(); + + BroadcastState bcs; + PCPStream::readAtom(atom,bcs); + //int cnt = servMgr->broadcastPacketUp(pack,noID,servMgr->sessionID); + //int cnt = servMgr->broadcastPacketDown(pack,noID,servMgr->sessionID); + //int cnt = chanMgr->broadcastPacketUp(pack,noID,servMgr->sessionID); + //LOG_DEBUG("Sent message to %d clients",cnt); +#endif +// ----------------------------------- +void ChanMgr::setBroadcastMsg(String &msg) +{ + if (!msg.isSame(broadcastMsg)) + { + broadcastMsg = msg; + + Channel *c = channel; + while(c) + { + if (c->isActive() && c->isBroadcasting()) + { + ChanInfo newInfo = c->info; + newInfo.comment = broadcastMsg; + c->updateInfo(newInfo); + } + c=c->next; + } + + } +} + + +// ----------------------------------- +void ChanMgr::clearHitLists() +{ + +// LOG_DEBUG("clearHitLists HITLISTLOCK ON-------------"); + chanMgr->hitlistlock.on(); + while (hitlist) + { + peercastApp->delChannel(&hitlist->info); + + ChanHitList *next = hitlist->next; + + delete hitlist; + + hitlist = next; + } +// LOG_DEBUG("clearHitLists HITLISTLOCK OFF-------------"); + chanMgr->hitlistlock.off(); +} +// ----------------------------------- +Channel *ChanMgr::deleteChannel(Channel *delchan) +{ + lock.on(); + + Channel *ch = channel,*prev=NULL,*next=NULL; + + while (ch) + { + if (ch == delchan) + { + Channel *next = ch->next; + if (prev) + prev->next = next; + else + channel = next; + + if (delchan->sourceStream){ + delchan->sourceStream->parent = NULL; + } + + delete delchan; + + break; + } + prev = ch; + ch=ch->next; + } + + + lock.off(); + return next; +} + +// ----------------------------------- +Channel *ChanMgr::createChannel(ChanInfo &info, const char *mount) +{ + lock.on(); + + Channel *nc=NULL; + + nc = new Channel(); + + nc->next = channel; + channel = nc; + + + nc->info = info; + nc->info.lastPlayStart = 0; + nc->info.lastPlayEnd = 0; + nc->info.status = ChanInfo::S_UNKNOWN; + if (mount) + nc->mount.set(mount); + nc->setStatus(Channel::S_WAIT); + nc->type = Channel::T_ALLOCATED; + nc->info.createdTime = sys->getTime(); + + LOG_CHANNEL("New channel created"); + + lock.off(); + return nc; +} +// ----------------------------------- +int ChanMgr::pickHits(ChanHitSearch &chs) +{ + ChanHitList *chl = hitlist; + while(chl) + { + if (chl->isUsed()) + if (chl->pickHits(chs)) + { + chl->info.id; + return 1; + } + chl = chl->next; + } + return 0; +} + +// ----------------------------------- +ChanHitList *ChanMgr::findHitList(ChanInfo &info) +{ + ChanHitList *chl = hitlist; + while(chl) + { + if (chl->isUsed()) + if (chl->info.matchNameID(info)) + return chl; + + chl = chl->next; + } + return NULL; +} +// ----------------------------------- +ChanHitList *ChanMgr::findHitListByID(GnuID &id) +{ + ChanHitList *chl = hitlist; + while(chl) + { + if (chl->isUsed()) + if (chl->info.id.isSame(id)) + return chl; + chl = chl->next; + } + return NULL; +} +// ----------------------------------- +int ChanMgr::numHitLists() +{ + int num=0; + ChanHitList *chl = hitlist; + while(chl) + { + if (chl->isUsed()) + num++; + chl = chl->next; + } + return num; +} +// ----------------------------------- +ChanHitList *ChanMgr::addHitList(ChanInfo &info) +{ + ChanHitList *chl = new ChanHitList(); + + + chl->next = hitlist; + hitlist = chl; + + chl->used = true; + chl->info = info; + chl->info.createdTime = sys->getTime(); + peercastApp->addChannel(&chl->info); + + + return chl; +} +// ----------------------------------- +void ChanMgr::clearDeadHits(bool clearTrackers) +{ + unsigned int interval; + + if (servMgr->isRoot) + interval = 1200; // mainly for old 0.119 clients + else + interval = hostUpdateInterval+120; + + chanMgr->hitlistlock.on(); + ChanHitList *chl = hitlist,*prev = NULL; + while (chl) + { + if (chl->isUsed()) + { + if (chl->clearDeadHits(interval,clearTrackers) == 0) + { + if (!isBroadcasting(chl->info.id)) + { + if (!chanMgr->findChannelByID(chl->info.id)) + { + peercastApp->delChannel(&chl->info); + + ChanHitList *next = chl->next; + if (prev) + prev->next = next; + else + hitlist = next; + + delete chl; + chl = next; + continue; + } + } + } + } + prev = chl; + chl = chl->next; + } + chanMgr->hitlistlock.off(); +} +// ----------------------------------- +bool ChanMgr::isBroadcasting(GnuID &id) +{ + Channel *ch = findChannelByID(id); + if (ch) + return ch->isBroadcasting(); + + return false; +} +// ----------------------------------- +bool ChanMgr::isBroadcasting() +{ + Channel *ch = channel; + while (ch) + { + if (ch->isActive()) + if (ch->isBroadcasting()) + return true; + + ch = ch->next; + } + return false; +} + +// ----------------------------------- +int ChanMgr::numChannels() +{ + int tot = 0; + Channel *ch = channel; + while (ch) + { + if (ch->isActive()) + tot++; + ch = ch->next; + } + return tot; +} + +// ----------------------------------- +void ChanMgr::deadHit(ChanHit &hit) +{ + ChanHitList *chl = findHitListByID(hit.chanID); + if (chl) + chl->deadHit(hit); +} +// ----------------------------------- +void ChanMgr::delHit(ChanHit &hit) +{ + ChanHitList *chl = findHitListByID(hit.chanID); + if (chl) + chl->delHit(hit); +} + +// ----------------------------------- +void ChanMgr::addHit(Host &h,GnuID &id,bool tracker) +{ + ChanHit hit; + hit.init(); + hit.host = h; + hit.rhost[0] = h; + hit.rhost[1].init(); + hit.tracker = tracker; + hit.recv = true; + hit.chanID = id; + addHit(hit); +} +// ----------------------------------- +ChanHit *ChanMgr::addHit(ChanHit &h) +{ + if (searchActive) + lastHit = sys->getTime(); + + ChanHitList *hl=NULL; + + hl = findHitListByID(h.chanID); + + if (!hl) + { + ChanInfo info; + info.id = h.chanID; + hl = addHitList(info); + } + + if (hl) + { + return hl->addHit(h); + }else + return NULL; +} + +// ----------------------------------- +class ChanFindInfo : public ThreadInfo +{ +public: + ChanInfo info; + bool keep; +}; +// ----------------------------------- +THREAD_PROC findAndPlayChannelProc(ThreadInfo *th) +{ + ChanFindInfo *cfi = (ChanFindInfo *)th; + + ChanInfo info; + info = cfi->info; + + + Channel *ch = chanMgr->findChannelByNameID(info); + + chanMgr->currFindAndPlayChannel = info.id; + + if (!ch) + ch = chanMgr->findAndRelay(info); + + if (ch) + { + // check that a different channel hasn`t be selected already. + if (chanMgr->currFindAndPlayChannel.isSame(ch->info.id)) + chanMgr->playChannel(ch->info); + + if (cfi->keep) + ch->stayConnected = cfi->keep; + } + + delete cfi; + return 0; +} +// ----------------------------------- +void ChanMgr::findAndPlayChannel(ChanInfo &info, bool keep) +{ + ChanFindInfo *cfi = new ChanFindInfo; + cfi->info = info; + cfi->keep = keep; + cfi->func = findAndPlayChannelProc; + + + sys->startThread(cfi); +} +// ----------------------------------- +void ChanMgr::playChannel(ChanInfo &info) +{ + + char str[128],fname[256],idStr[128]; + + sprintf(str,"http://localhost:%d",servMgr->serverHost.port); + info.id.toStr(idStr); + + PlayList::TYPE type; + + + if ((info.contentType == ChanInfo::T_WMA) || (info.contentType == ChanInfo::T_WMV)) + { + type = PlayList::T_ASX; + // WMP seems to have a bug where it doesn`t re-read asx files if they have the same name + // so we prepend the channel id to make it unique - NOTE: should be deleted afterwards. + if (servMgr->getModulePath) //JP-EX + { + peercastApp->getDirectory(); + sprintf(fname,"%s/%s.asx",servMgr->modulePath,idStr); + }else + sprintf(fname,"%s/%s.asx",peercastApp->getPath(),idStr); + }else if (info.contentType == ChanInfo::T_OGM) + { + type = PlayList::T_RAM; + if (servMgr->getModulePath) //JP-EX + { + peercastApp->getDirectory(); + sprintf(fname,"%s/play.ram",servMgr->modulePath); + }else + sprintf(fname,"%s/play.ram",peercastApp->getPath()); + + }else + { + type = PlayList::T_SCPLS; + if (servMgr->getModulePath) //JP-EX + { + peercastApp->getDirectory(); + sprintf(fname,"%s/play.pls",servMgr->modulePath); + }else + sprintf(fname,"%s/play.pls",peercastApp->getPath()); + } + + + PlayList *pls = new PlayList(type,1); + pls->addChannel(str,info); + + + LOG_DEBUG("Writing %s",fname); + FileStream file; + file.openWriteReplace(fname); + pls->write(file); + file.close(); + + + LOG_DEBUG("Executing: %s",fname); + sys->executeFile(fname); + delete pls; + +} + +// ----------------------------------- +ChanHitList::ChanHitList() +{ + info.init(); + lastHitTime = 0; + used = false; + hit = NULL; +} +// ----------------------------------- +ChanHitList::~ChanHitList() +{ + chanMgr->hitlistlock.on(); + while (hit) + hit = deleteHit(hit); + chanMgr->hitlistlock.off(); +} +// ----------------------------------- +void ChanHit::pickNearestIP(Host &h) +{ + for(int i=0; i<2; i++) + { + if (h.classType() == rhost[i].classType()) + { + host = rhost[i]; + break; + } + } +} + +// ----------------------------------- +void ChanHit::init() +{ + host.init(); + + rhost[0].init(); + rhost[1].init(); + + next = NULL; + + numListeners = 0; + numRelays = 0; + + dead = tracker = firewalled = stable = yp = false; + recv = cin = direct = relay = true; + relayfull = chfull = ratefull = false; + direct = 0; + numHops = 0; + time = upTime = 0; + lastContact = 0; + + version = 0; + version_vp = 0; + + version_ex_prefix[0] = ' '; + version_ex_prefix[1] = ' '; + version_ex_number = 0; + + status = 0; + + sessionID.clear(); + chanID.clear(); + + + oldestPos = newestPos = 0; + uphost.init(); + uphostHops = 0; +} + +// ----------------------------------- +void ChanHit::initLocal(int numl,int numr,int,int uptm,bool connected,bool isFull,unsigned int bitrate, Channel* ch, unsigned int oldp,unsigned int newp) +{ + init(); + firewalled = (servMgr->getFirewall() != ServMgr::FW_OFF); + numListeners = numl; + numRelays = numr; + upTime = uptm; + stable = servMgr->totalStreams>0; + sessionID = servMgr->sessionID; + recv = connected; + + direct = !servMgr->directFull(); +// relay = !servMgr->relaysFull(); + cin = !servMgr->controlInFull(); + + relayfull = servMgr->relaysFull(); + chfull = isFull; + + Channel *c = chanMgr->channel; + int noRelay = 0; + unsigned int needRate = 0; + unsigned int allRate = 0; + while(c){ + if (c->isPlaying()){ + allRate += c->info.bitrate * c->localRelays(); + if ((c != ch) && (c->localRelays() == 0)){ + if(!isIndexTxt(c)) // for PCRaw (relay) + noRelay++; + needRate+=c->info.bitrate; + } + } + c = c->next; + } + int diff = servMgr->maxRelays - servMgr->numStreams(Servent::T_RELAY,false); + if (ch->localRelays()){ + if (noRelay > diff){ + noRelay = diff; + } + } else { + noRelay = 0; + needRate = 0; + } + + // for PCRaw (relay) start. + bool force_off = false; + + if(isIndexTxt(ch)) + force_off = true; + // for PCRaw (relay) end. + +// ratefull = servMgr->bitrateFull(needRate+bitrate); + ratefull = (servMgr->maxBitrateOut < allRate + needRate + ch->info.bitrate); + + //relay = (!relayfull) && (!chfull) && (!ratefull) && ((servMgr->numStreams(Servent::T_RELAY,false) + noRelay) < servMgr->maxRelays); + relay = (!relayfull || force_off) && (!chfull) && (!ratefull) + && (((servMgr->numStreams(Servent::T_RELAY,false) + noRelay) < servMgr->maxRelays) || force_off); // for PCRaw (relay) (force_off) + +/* if (relayfull){ + LOG_DEBUG("Reject by relay full"); + } + if (chfull){ + LOG_DEBUG("Reject by channel full"); + } + if (ratefull){ + LOG_DEBUG("Reject by rate: Max=%d Now=%d Need=%d ch=%d", servMgr->maxBitrateOut, allRate, needRate, ch->info.bitrate); + }*/ + + host = servMgr->serverHost; + + version = PCP_CLIENT_VERSION; + version_vp = PCP_CLIENT_VERSION_VP; +#ifdef VERSION_EX + strncpy(version_ex_prefix, PCP_CLIENT_VERSION_EX_PREFIX,2); + version_ex_number = PCP_CLIENT_VERSION_EX_NUMBER; +#else + version_ex_prefix[0] = ' '; + version_ex_prefix[1] = ' '; + version_ex_number = 0; +#endif + + status = ch->status; + + rhost[0] = Host(host.ip,host.port); + rhost[1] = Host(ClientSocket::getIP(NULL),host.port); + + if (firewalled) + rhost[0].port = 0; + + oldestPos = oldp; + newestPos = newp; + + uphost.ip = ch->sourceHost.host.ip; + uphost.port = ch->sourceHost.host.port; + uphostHops = 1; +} + +// ----------------------------------- +void ChanHit::writeAtoms(AtomStream &atom,GnuID &chanID) +{ + bool addChan=chanID.isSet(); + bool uphostdata=(uphost.ip != 0); + + int fl1 = 0; + if (recv) fl1 |= PCP_HOST_FLAGS1_RECV; + if (relay) fl1 |= PCP_HOST_FLAGS1_RELAY; + if (direct) fl1 |= PCP_HOST_FLAGS1_DIRECT; + if (cin) fl1 |= PCP_HOST_FLAGS1_CIN; + if (tracker) fl1 |= PCP_HOST_FLAGS1_TRACKER; + if (firewalled) fl1 |= PCP_HOST_FLAGS1_PUSH; + + atom.writeParent(PCP_HOST,13 + (addChan?1:0) + (uphostdata?3:0) + (version_ex_number?2:0)); + + if (addChan) + atom.writeBytes(PCP_HOST_CHANID,chanID.id,16); + atom.writeBytes(PCP_HOST_ID,sessionID.id,16); + atom.writeInt(PCP_HOST_IP,rhost[0].ip); + atom.writeShort(PCP_HOST_PORT,rhost[0].port); + atom.writeInt(PCP_HOST_IP,rhost[1].ip); + atom.writeShort(PCP_HOST_PORT,rhost[1].port); + atom.writeInt(PCP_HOST_NUML,numListeners); + atom.writeInt(PCP_HOST_NUMR,numRelays); + atom.writeInt(PCP_HOST_UPTIME,upTime); + atom.writeInt(PCP_HOST_VERSION,version); + atom.writeInt(PCP_HOST_VERSION_VP,version_vp); + if (version_ex_number){ + atom.writeBytes(PCP_HOST_VERSION_EX_PREFIX,version_ex_prefix,2); + atom.writeShort(PCP_HOST_VERSION_EX_NUMBER,version_ex_number); + } + atom.writeChar(PCP_HOST_FLAGS1,fl1); + atom.writeInt(PCP_HOST_OLDPOS,oldestPos); + atom.writeInt(PCP_HOST_NEWPOS,newestPos); + if (uphostdata){ + atom.writeInt(PCP_HOST_UPHOST_IP,uphost.ip); + atom.writeInt(PCP_HOST_UPHOST_PORT,uphost.port); + atom.writeInt(PCP_HOST_UPHOST_HOPS,uphostHops); + } +} +// ----------------------------------- +bool ChanHit::writeVariable(Stream &out, const String &var) +{ + char buf[1024]; + + if (var == "rhost0") + { + if (servMgr->enableGetName) //JP-EX s + { + char buf2[256]; + if (firewalled) + { + if (numRelays==0) + strcpy(buf,""); + else + strcpy(buf,""); + } + else { + if (!relay){ + if (numRelays==0){ + strcpy(buf,""); + } else { + strcpy(buf,""); + } + } else { + strcpy(buf,""); + } + } + + rhost[0].toStr(buf2); + strcat(buf,buf2); + + char h_name[128]; + if (ClientSocket::getHostname(h_name,rhost[0].ip)) + { + strcat(buf,"["); + strcat(buf,h_name); + strcat(buf,"]"); + } + strcat(buf,""); + } //JP-EX e + else + rhost[0].toStr(buf); + } + else if (var == "rhost1") + rhost[1].toStr(buf); + else if (var == "numHops") + sprintf(buf,"%d",numHops); + else if (var == "numListeners") + sprintf(buf,"%d",numListeners); + else if (var == "numRelays") + sprintf(buf,"%d",numRelays); + else if (var == "uptime") + { + String timeStr; + timeStr.setFromStopwatch(upTime); + strcpy(buf,timeStr.cstr()); + }else if (var == "update") + { + String timeStr; + if (timeStr) + timeStr.setFromStopwatch(sys->getTime()-time); + else + timeStr.set("-"); + strcpy(buf,timeStr.cstr()); + }else if (var == "isFirewalled"){ + sprintf(buf,"%d",firewalled?1:0); + }else if (var == "version"){ + sprintf(buf,"%d",version); + }else if (var == "agent"){ + if (version){ + if (version_ex_number){ + sprintf(buf, "v0.%d(%c%c%04d)", version, version_ex_prefix[0], version_ex_prefix[1], version_ex_number); + } else if (version_vp){ + sprintf(buf,"v0.%d(VP%04d)", version, version_vp); + } else { + sprintf(buf,"v0.%d", version); + } + } else { + strcpy(buf, "0"); + } + } + else if (var == "check") + { + char buf2[256]; + strcpy(buf, "_"); + } + else if (var == "uphost") // tree + uphost.toStr(buf); + else if (var == "uphostHops") // tree + sprintf(buf,"%d",uphostHops); + else if (var == "canRelay") // tree + sprintf(buf, "%d",relay); + else + return false; + + out.writeString(buf); + return true; +} + +// ----------------------------------- +int ChanHitList::getTotalListeners() +{ + int cnt=0; + ChanHit *h = hit; + while (h) + { + if (h->host.ip) + cnt+=h->numListeners; + h=h->next; + } + return cnt; +} +// ----------------------------------- +int ChanHitList::getTotalRelays() +{ + int cnt=0; + ChanHit *h = hit; + while (h) + { + if (h->host.ip) + cnt+=h->numRelays; + h=h->next; + } + return cnt; +} +// ----------------------------------- +int ChanHitList::getTotalFirewalled() +{ + int cnt=0; + ChanHit *h = hit; + while (h) + { + if (h->host.ip) + if (h->firewalled) + cnt++; + h=h->next; + } + return cnt; +} + +// ----------------------------------- +int ChanHitList::contactTrackers(bool connected, int numl, int nums, int uptm) +{ + return 0; +} + +void ChanHitList::clearHits(bool flg) +{ + ChanHit *c = hit, *prev = NULL; + + while(c){ + if (flg || (c->numHops != 0)){ + ChanHit *next = c->next; + if (prev) + prev->next = next; + else + hit = next; + + delete c; + c = next; + } else { + prev = c; + c = c->next; + } + } +} + +// ----------------------------------- +ChanHit *ChanHitList::deleteHit(ChanHit *ch) +{ + ChanHit *c = hit,*prev=NULL; + while (c) + { + if (c == ch) + { + ChanHit *next = c->next; + if (prev) + prev->next = next; + else + hit = next; + + delete c; + + return next; + } + prev=c; + c=c->next; + } + + return NULL; +} +// ----------------------------------- +ChanHit *ChanHitList::addHit(ChanHit &h) +{ + char ip0str[64],ip1str[64]; + h.rhost[0].toStr(ip0str); + h.rhost[1].toStr(ip1str); + char uphostStr[64]; + h.uphost.toStr(uphostStr); + if (h.uphost.ip){ + LOG_DEBUG("Add hit: F%dT%dR%d %s/%s <- %s(%d)",h.firewalled,h.tracker,h.relay,ip0str,ip1str,uphostStr, h.uphostHops); + } else { + LOG_DEBUG("Add hit: F%dT%dR%d %s/%s",h.firewalled,h.tracker,h.relay,ip0str,ip1str); + } + + // dont add our own hits + if (servMgr->sessionID.isSame(h.sessionID)) + return NULL; + + + lastHitTime = sys->getTime(); + h.time = lastHitTime; + + ChanHit *ch = hit; + while (ch) + { + if ((ch->rhost[0].ip == h.rhost[0].ip) && (ch->rhost[0].port == h.rhost[0].port)) + if (((ch->rhost[1].ip == h.rhost[1].ip) && (ch->rhost[1].port == h.rhost[1].port)) || (!ch->rhost[1].isValid())) + { + if (!ch->dead) + { + if (ch->numHops > 0 && h.numHops == 0) + // downstream hit recieved as RelayHost + return ch; + ChanHit *next = ch->next; + *ch = h; + ch->next = next; + return ch; + } + } + ch=ch->next; + } + + // clear hits with same session ID (IP may have changed) + if (h.sessionID.isSet()) + { + ChanHit *ch = hit; + while (ch) + { + if (ch->host.ip) + if (ch->sessionID.isSame(h.sessionID)) + { + ch = deleteHit(ch); + continue; + } + ch=ch->next; + } + } + + + // else add new hit + { + ChanHit *ch = new ChanHit(); + *ch = h; + ch->chanID = info.id; + ch->next = hit; + hit = ch; + return ch; + } + + return NULL; +} + + +// ----------------------------------- +int ChanHitList::clearDeadHits(unsigned int timeout, bool clearTrackers) +{ + int cnt=0; + unsigned int ctime = sys->getTime(); + +// LOG_DEBUG("clearDeadHits HITLISTLOCK ON-------------"); + chanMgr->hitlistlock.on(); + ChanHit *ch = hit; + while (ch) + { + if (ch->host.ip) + { + if (ch->dead || ((ctime-ch->time) > timeout) && (clearTrackers || (!clearTrackers & !ch->tracker))) + { +// ch = deleteHit(ch); + + if (ch->firewalled){ +// LOG_DEBUG("kickKeepTime = %d, %d", servMgr->kickKeepTime, ctime-ch->time); + if ( (servMgr->kickKeepTime == 0) || ((ctime-ch->time) > servMgr->kickKeepTime) ){ + ch = deleteHit(ch); + } else { + ch->numHops = 0; + ch->numListeners = 0; + ch = ch->next; + } + } else { + ch = deleteHit(ch); + } + + continue; + }else + cnt++; + } + ch = ch->next; + } +// LOG_DEBUG("clearDeadHits HITLISTLOCK OFF-------------"); + chanMgr->hitlistlock.off(); + return cnt; +} + + +// ----------------------------------- +void ChanHitList::deadHit(ChanHit &h) +{ + char ip0str[64],ip1str[64]; + h.rhost[0].toStr(ip0str); + h.rhost[1].toStr(ip1str); + LOG_DEBUG("Dead hit: %s/%s",ip0str,ip1str); + + ChanHit *ch = hit; + while (ch) + { + if (ch->host.ip) + if (ch->rhost[0].isSame(h.rhost[0]) && ch->rhost[1].isSame(h.rhost[1])) + { + ch->dead = true; + } + ch = ch->next; + } +} +// ----------------------------------- +void ChanHitList::delHit(ChanHit &h) +{ + char ip0str[64],ip1str[64]; + h.rhost[0].toStr(ip0str); + h.rhost[1].toStr(ip1str); + LOG_DEBUG("Del hit: %s/%s",ip0str,ip1str); + + ChanHit *ch = hit; + while (ch) + { + if (ch->host.ip) + if (ch->rhost[0].isSame(h.rhost[0]) && ch->rhost[1].isSame(h.rhost[1])) + { + ch=deleteHit(ch); + continue; + } + ch = ch->next; + } +} +// ----------------------------------- +int ChanHitList::numHits() +{ + int cnt=0; + ChanHit *ch = hit; + while (ch) + { + if (ch->host.ip && !ch->dead && ch->numHops) + cnt++; + ch = ch->next; + } + + return cnt; +} +// ----------------------------------- +int ChanHitList::numListeners() +{ + int cnt=0; + ChanHit *ch = hit; + while (ch) + { + if (ch->host.ip && !ch->dead && ch->numHops) + cnt += ch->numListeners; + ch=ch->next; + } + + return cnt; +} +// ----------------------------------- +int ChanHitList::numRelays() +{ + int cnt=0; + ChanHit *ch = hit; + while (ch) + { + if (ch->host.ip && !ch->dead) + cnt += ch->numRelays; + ch=ch->next; + } + + return cnt; +} + +// ----------------------------------- +int ChanHitList::numTrackers() +{ + int cnt=0; + ChanHit *ch = hit; + while (ch) + { + if ((ch->host.ip && !ch->dead) && (ch->tracker)) + cnt++; + ch=ch->next; + } + return cnt; +} +// ----------------------------------- +int ChanHitList::numFirewalled() +{ + int cnt=0; + ChanHit *ch = hit; + while (ch) + { + if (ch->host.ip && !ch->dead) + cnt += ch->firewalled?1:0; + ch=ch->next; + } + return cnt; +} +// ----------------------------------- +int ChanHitList::closestHit() +{ + unsigned int hop=10000; + ChanHit *ch = hit; + while (ch) + { + if (ch->host.ip && !ch->dead) + if (ch->numHops < hop) + hop = ch->numHops; + ch=ch->next; + } + + return hop; +} +// ----------------------------------- +int ChanHitList::furthestHit() +{ + unsigned int hop=0; + ChanHit *ch = hit; + while (ch) + { + if (ch->host.ip && !ch->dead) + if (ch->numHops > hop) + hop = ch->numHops; + ch=ch->next; + } + + return hop; +} +// ----------------------------------- +unsigned int ChanHitList::newestHit() +{ + unsigned int time=0; + ChanHit *ch = hit; + while (ch) + { + if (ch->host.ip && !ch->dead) + if (ch->time > time) + time = ch->time; + ch=ch->next; + } + + return time; +} +// ----------------------------------- +int ChanHitList::pickHits(ChanHitSearch &chs) +{ + ChanHit best,*bestP=NULL; + best.init(); + best.numHops = 255; + best.time = 0; + + unsigned int ctime = sys->getTime(); + + ChanHit *c = hit; + while (c) + { + if (c->host.ip && !c->dead) + { + if (!chs.excludeID.isSame(c->sessionID)) + if ((chs.waitDelay==0) || ((ctime-c->lastContact) >= chs.waitDelay)) + if ((c->numHops<=best.numHops)) // (c->time>=best.time)) + if (c->relay || (!c->relay && chs.useBusyRelays)) + if (c->cin || (!c->cin && chs.useBusyControls)) + { + + if (chs.trackersOnly && c->tracker) + { + if (chs.matchHost.ip) + { + if ((c->rhost[0].ip == chs.matchHost.ip) && c->rhost[1].isValid()) + { + bestP = c; + best = *c; + best.host = best.rhost[1]; // use lan ip + } + }else if (c->firewalled == chs.useFirewalled) + { + bestP = c; + best = *c; + best.host = best.rhost[0]; // use wan ip + } + }else if (!chs.trackersOnly && !c->tracker) + { + if (chs.matchHost.ip) + { + if ((c->rhost[0].ip == chs.matchHost.ip) && c->rhost[1].isValid()) + { + bestP = c; + best = *c; + best.host = best.rhost[1]; // use lan ip + } + }else if (c->firewalled == chs.useFirewalled && (!bestP || !bestP->relay)) + { + bestP = c; + best = *c; + best.host = best.rhost[0]; // use wan ip + } + } + } + } + c=c->next; + } + + if (bestP) + { + if (chs.numResults < ChanHitSearch::MAX_RESULTS) + { + if (chs.waitDelay) + bestP->lastContact = ctime; + chs.best[chs.numResults++] = best; + return 1; + } + + } + + return 0; +} + + +// ----------------------------------- +int ChanHitList::pickSourceHits(ChanHitSearch &chs) +{ + if (pickHits(chs) && chs.best[0].numHops == 0) return 1; + return 0; +} + + +// ----------------------------------- +const char *ChanInfo::getTypeStr(TYPE t) +{ + switch (t) + { + case T_RAW: return "RAW"; + + case T_MP3: return "MP3"; + case T_OGG: return "OGG"; + case T_OGM: return "OGM"; + case T_WMA: return "WMA"; + + case T_MOV: return "MOV"; + case T_MPG: return "MPG"; + case T_NSV: return "NSV"; + case T_WMV: return "WMV"; + + case T_PLS: return "PLS"; + case T_ASX: return "ASX"; + + default: return "UNKNOWN"; + } +} +// ----------------------------------- +const char *ChanInfo::getProtocolStr(PROTOCOL t) +{ + switch (t) + { + case SP_PEERCAST: return "PEERCAST"; + case SP_HTTP: return "HTTP"; + case SP_FILE: return "FILE"; + case SP_MMS: return "MMS"; + case SP_PCP: return "PCP"; + default: return "UNKNOWN"; + } +} +// ----------------------------------- +ChanInfo::PROTOCOL ChanInfo::getProtocolFromStr(const char *str) +{ + if (stricmp(str,"PEERCAST")==0) + return SP_PEERCAST; + else if (stricmp(str,"HTTP")==0) + return SP_HTTP; + else if (stricmp(str,"FILE")==0) + return SP_FILE; + else if (stricmp(str,"MMS")==0) + return SP_MMS; + else if (stricmp(str,"PCP")==0) + return SP_PCP; + else + return SP_UNKNOWN; +} + +// ----------------------------------- +const char *ChanInfo::getTypeExt(TYPE t) +{ + switch(t) + { + case ChanInfo::T_OGM: + case ChanInfo::T_OGG: + return ".ogg"; + case ChanInfo::T_MP3: + return ".mp3"; + case ChanInfo::T_MOV: + return ".mov"; + case ChanInfo::T_NSV: + return ".nsv"; + case ChanInfo::T_WMV: + return ".wmv"; + case ChanInfo::T_WMA: + return ".wma"; + default: + return ""; + } +} +// ----------------------------------- +ChanInfo::TYPE ChanInfo::getTypeFromStr(const char *str) +{ + if (stricmp(str,"MP3")==0) + return T_MP3; + else if (stricmp(str,"OGG")==0) + return T_OGG; + else if (stricmp(str,"OGM")==0) + return T_OGM; + else if (stricmp(str,"RAW")==0) + return T_RAW; + else if (stricmp(str,"NSV")==0) + return T_NSV; + else if (stricmp(str,"WMA")==0) + return T_WMA; + else if (stricmp(str,"WMV")==0) + return T_WMV; + else if (stricmp(str,"PLS")==0) + return T_PLS; + else if (stricmp(str,"M3U")==0) + return T_PLS; + else if (stricmp(str,"ASX")==0) + return T_ASX; + else + return T_UNKNOWN; +} +// ----------------------------------- +bool ChanInfo::matchNameID(ChanInfo &inf) +{ + if (inf.id.isSet()) + if (id.isSame(inf.id)) + return true; + + if (!inf.name.isEmpty()) + if (name.contains(inf.name)) + return true; + + return false; +} +// ----------------------------------- +bool ChanInfo::match(ChanInfo &inf) +{ + bool matchAny=true; + + if (inf.status != S_UNKNOWN) + { + if (status != inf.status) + return false; + } + + if (inf.bitrate != 0) + { + if (bitrate == inf.bitrate) + return true; + matchAny = false; + } + + if (inf.id.isSet()) + { + if (id.isSame(inf.id)) + return true; + matchAny = false; + } + + if (inf.contentType != T_UNKNOWN) + { + if (contentType == inf.contentType) + return true; + matchAny = false; + } + + if (!inf.name.isEmpty()) + { + if (name.contains(inf.name)) + return true; + matchAny = false; + } + + if (!inf.genre.isEmpty()) + { + if (genre.contains(inf.genre)) + return true; + matchAny = false; + } + + return matchAny; +} +// ----------------------------------- +bool TrackInfo::update(TrackInfo &inf) +{ + bool changed = false; + + if (!contact.isSame(inf.contact)) + { + contact = inf.contact; + changed = true; + } + + if (!title.isSame(inf.title)) + { + title = inf.title; + changed = true; + } + + if (!artist.isSame(inf.artist)) + { + artist = inf.artist; + changed = true; + } + + if (!album.isSame(inf.album)) + { + album = inf.album; + changed = true; + } + + if (!genre.isSame(inf.genre)) + { + genre = inf.genre; + changed = true; + } + + + return changed; +} + + +// ----------------------------------- +bool ChanInfo::update(ChanInfo &info) +{ + bool changed = false; + + + + // check valid id + if (!info.id.isSet()) + return false; + + // only update from chaninfo that has full name etc.. + if (info.name.isEmpty()) + return false; + + // check valid broadcaster key + if (bcID.isSet()) + { + if (!bcID.isSame(info.bcID)) + { + LOG_ERROR("ChanInfo BC key not valid"); + return false; + } + }else + { + bcID = info.bcID; + } + + + + if (bitrate != info.bitrate) + { + bitrate = info.bitrate; + changed = true; + } + + if (contentType != info.contentType) + { + contentType = info.contentType; + changed = true; + } + + if (!desc.isSame(info.desc)) //JP-EX + { + desc = info.desc; + changed = true; + } + + if (!name.isSame(info.name)) + { + name = info.name; + changed = true; + } + + if (!comment.isSame(info.comment)) + { + comment = info.comment; + changed = true; + } + + if (!genre.isSame(info.genre)) + { + genre = info.genre; + changed = true; + } + + if (!url.isSame(info.url)) + { + url = info.url; + changed = true; + } + + if (track.update(info.track)) + changed = true; + + + return changed; +} +// ----------------------------------- +void ChanInfo::initNameID(const char *n) +{ + init(); + id.fromStr(n); + if (!id.isSet()) + name.set(n); +} + +// ----------------------------------- +void ChanInfo::init() +{ + status = S_UNKNOWN; + name.clear(); + bitrate = 0; + contentType = T_UNKNOWN; + srcProtocol = SP_UNKNOWN; + id.clear(); + url.clear(); + genre.clear(); + comment.clear(); + track.clear(); + lastPlayStart = 0; + lastPlayEnd = 0; + numSkips = 0; + bcID.clear(); + createdTime = 0; +} +// ----------------------------------- +void ChanInfo::readTrackXML(XML::Node *n) +{ + track.clear(); + readXMLString(track.title,n,"title"); + readXMLString(track.contact,n,"contact"); + readXMLString(track.artist,n,"artist"); + readXMLString(track.album,n,"album"); + readXMLString(track.genre,n,"genre"); +} +// ----------------------------------- +unsigned int ChanInfo::getUptime() +{ + // calculate uptime and cap if requested by settings. + unsigned int upt; + upt = lastPlayStart?(sys->getTime()-lastPlayStart):0; + if (chanMgr->maxUptime) + if (upt > chanMgr->maxUptime) + upt = chanMgr->maxUptime; + return upt; +} +// ----------------------------------- +unsigned int ChanInfo::getAge() +{ + return sys->getTime()-createdTime; +} + +// ------------------------------------------ +void ChanInfo::readTrackAtoms(AtomStream &atom,int numc) +{ + for(int i=0; ifindAttrInt("bitrate"); + if (br) + bitrate = br; + + readXMLString(typeStr,n,"type"); + if (!typeStr.isEmpty()) + contentType = getTypeFromStr(typeStr.cstr()); + + + readXMLString(idStr,n,"id"); + if (!idStr.isEmpty()) + id.fromStr(idStr.cstr()); + + readXMLString(comment,n,"comment"); + + XML::Node *tn = n->findNode("track"); + if (tn) + readTrackXML(tn); + +} + +// ----------------------------------- +void ChanInfo::init(const char *n, GnuID &cid, TYPE tp, int br) +{ + init(); + + name.set(n); + bitrate = br; + contentType = tp; + id = cid; +} + +// ----------------------------------- +void ChanInfo::init(const char *fn) +{ + init(); + + if (fn) + name.set(fn); +} +// ----------------------------------- +void PlayList::readASX(Stream &in) +{ + LOG_DEBUG("Reading ASX"); + XML xml; + + try + { + xml.read(in); + }catch(StreamException &) {} // TODO: eof is NOT handled properly in sockets - always get error at end + + if (xml.root) + { + XML::Node *n = xml.root->child; + while (n) + { + if (stricmp("entry",n->getName())==0) + { + XML::Node *rf = n->findNode("ref"); + if (rf) + { + char *hr = rf->findAttr("href"); + if (hr) + { + addURL(hr,""); + //LOG("asx url %s",hr); + } + + } + } + n=n->sibling; + } + } +} +// ----------------------------------- +void PlayList::readSCPLS(Stream &in) +{ + char tmp[256]; + while (in.readLine(tmp,sizeof(tmp))) + { + if (strnicmp(tmp,"file",4)==0) + { + char *p = strstr(tmp,"="); + if (p) + addURL(p+1,""); + } + } +} +// ----------------------------------- +void PlayList::readPLS(Stream &in) +{ + char tmp[256]; + while (in.readLine(tmp,sizeof(tmp))) + { + if (tmp[0] != '#') + addURL(tmp,""); + } +} +// ----------------------------------- +void PlayList::writeSCPLS(Stream &out) +{ + out.writeLine("[playlist]"); + out.writeLine(""); + out.writeLineF("NumberOfEntries=%d",numURLs); + + for(int i=0; i"); + for(int i=0; i"); + out.writeLineF("",urls[i].cstr()); + out.writeLine(""); + } + out.writeLine(""); +} + + +// ----------------------------------- +void PlayList::addChannel(const char *path, ChanInfo &info) +{ + String url; + + char idStr[64]; + + info.id.toStr(idStr); + char *nid = info.id.isSet()?idStr:info.name.cstr(); + + sprintf(url.cstr(),"%s/stream/%s%s",path,nid,ChanInfo::getTypeExt(info.contentType)); + addURL(url.cstr(),info.name); +} + +// ----------------------------------- +void ChanHitSearch::init() +{ + matchHost.init(); + waitDelay = 0; + useFirewalled = false; + trackersOnly = false; + useBusyRelays = true; + useBusyControls = true; + excludeID.clear(); + numResults = 0; + + //seed = sys->getTime(); + //srand(seed); +} + +int ChanHitSearch::getRelayHost(Host host1, Host host2, GnuID exID, ChanHitList *chl) +{ + int cnt = 0; + int loop = 1; + int index = 0; + int prob; + int rnd; + static int base = 0x400; + ChanHit tmpHit[MAX_RESULTS]; + static WLock seqLock; + static unsigned int riSequence = 0; + + //srand(seed); + //seed += 11; + + unsigned int seq; + seqLock.on(); + seq = riSequence++; + riSequence &= 0xffffff; + seqLock.off(); + + ChanHit *hit = chl->hit; + + while(hit){ + if (hit->host.ip && !hit->dead){ + if ( + (!exID.isSame(hit->sessionID)) +// && (hit->relay) + && (!hit->tracker) + && (!hit->firewalled) + && (hit->numHops != 0) + ){ + if ( (hit->rhost[0].ip == host1.ip) + && hit->rhost[1].isValid() + && (host2.ip != hit->rhost[1].ip) + ){ + best[0] = *hit; + best[0].host = hit->rhost[1]; + index++; + } + if ((hit->rhost[0].ip == host2.ip) && hit->rhost[1].isValid()){ + best[0] = *hit; + best[0].host = hit->rhost[1]; + index++; + } + + loop = (index / MAX_RESULTS) + 1; + //prob = (float)1 / (float)loop; + prob = base / loop; + //rnd = (float)rand() / (float)RAND_MAX; + rnd = rand() % base; + if (hit->numHops == 1){ + if (tmpHit[index % MAX_RESULTS].numHops == 1){ + if (rnd < prob){ + tmpHit[index % MAX_RESULTS] = *hit; + tmpHit[index % MAX_RESULTS].host = hit->rhost[0]; + index++; + } + } else { + tmpHit[index % MAX_RESULTS] = *hit; + tmpHit[index % MAX_RESULTS].host = hit->rhost[0]; + index++; + } + } else { + if ((tmpHit[index % MAX_RESULTS].numHops != 1) && (rnd < prob)){ + tmpHit[index % MAX_RESULTS] = *hit; + tmpHit[index % MAX_RESULTS].host = hit->rhost[0]; + index++; + } + } + +// char tmp[50]; +// hit->host.toStr(tmp); +// LOG_DEBUG("TEST %s: %f %f", tmp, rnd, prob); + } + } + hit = hit->next; + } + + if (index > MAX_RESULTS){ + cnt = MAX_RESULTS; + } else { + cnt = index; + } + +/* int use[MAX_RESULTS]; + memset(use, 0, sizeof(use)); + int i; + for (i = 0; i < cnt; i++){ + use[i] = -1; + } + int r; + for (i = 0; i < cnt; i++){ + do { + r = rand(); +// LOG_DEBUG("%d",r); + r = r % cnt; + if (use[r] == -1){ + use[r] = i; + break; + } + } while(1); + } + for (i = 0; i < cnt; i++){ +// LOG_DEBUG("%d", use[i]); + best[use[i]] = tmpHit[i]; + }*/ + + int use[MAX_RESULTS]; + int i; + for (i = 0; i < cnt; i++) { + use[i] = (i + seq) % cnt; + } + + for (i = 0; i < cnt; i++){ +// LOG_DEBUG("%d", use[i]); + best[use[i]] = tmpHit[i]; + } +// for (i = 0; i < cnt; i++){ +// char tmp[50]; +// best[i].host.toStr(tmp); +// LOG_DEBUG("Relay info: Hops = %d, %s", best[i].numHops, tmp); +// } + + return cnt; +} diff --git a/PeerCast.root/PeerCast/core/common/channel.h b/PeerCast.root/PeerCast/core/common/channel.h new file mode 100644 index 0000000..d1d00fb --- /dev/null +++ b/PeerCast.root/PeerCast/core/common/channel.h @@ -0,0 +1,731 @@ +// ------------------------------------------------ +// File : channel.h +// Date: 4-apr-2002 +// Author: giles +// +// (c) 2002 peercast.org +// ------------------------------------------------ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// ------------------------------------------------ + +#ifndef _CHANNEL_H +#define _CHANNEL_H + +#include "sys.h" +#include "stream.h" +#include "gnutella.h" +#include "xml.h" +#include "asf.h" +#include "cstream.h" + +class AtomStream; +class ChanHitSearch; + +// -------------------------------------------------- +struct MP3Header +{ + int lay; + int version; + int error_protection; + int bitrate_index; + int sampling_frequency; + int padding; + int extension; + int mode; + int mode_ext; + int copyright; + int original; + int emphasis; + int stereo; +}; + +// ---------------------------------- +class TrackInfo +{ +public: + void clear() + { + contact.clear(); + title.clear(); + artist.clear(); + album.clear(); + genre.clear(); + } + + void convertTo(String::TYPE t) + { + contact.convertTo(t); + title.convertTo(t); + artist.convertTo(t); + album.convertTo(t); + genre.convertTo(t); + } + + bool update(TrackInfo &); + + ::String contact,title,artist,album,genre; +}; + + + +// ---------------------------------- +class ChanInfo +{ +public: + enum TYPE + { + T_UNKNOWN, + + T_RAW, + T_MP3, + T_OGG, + T_OGM, + T_MOV, + T_MPG, + T_NSV, + + T_WMA, + T_WMV, + + T_PLS, + T_ASX + }; + + + enum PROTOCOL + { + SP_UNKNOWN, + SP_PEERCAST, + SP_HTTP, + SP_FILE, + SP_MMS, + SP_PCP + }; + + + enum STATUS + { + S_UNKNOWN, + S_PLAY + }; + + ChanInfo() {init();} + + void init(); + void init(const char *); + void init(const char *, GnuID &, TYPE, int); + void init(XML::Node *); + void initNameID(const char *); + + void updateFromXML(XML::Node *); + + void readTrackXML(XML::Node *); + void readServentXML(XML::Node *); + bool update(ChanInfo &); + XML::Node *createQueryXML(); + XML::Node *createChannelXML(); + XML::Node *createRelayChannelXML(); + XML::Node *createTrackXML(); + bool match(XML::Node *); + bool match(ChanInfo &); + bool matchNameID(ChanInfo &); + + void writeInfoAtoms(AtomStream &atom); + void writeTrackAtoms(AtomStream &atom); + + void readInfoAtoms(AtomStream &,int); + void readTrackAtoms(AtomStream &,int); + + unsigned int getUptime(); + unsigned int getAge(); + bool isActive() {return id.isSet();} + bool isPrivate() {return bcID.getFlags() & 1;} + static const char *getTypeStr(TYPE); + static const char *getProtocolStr(PROTOCOL); + static const char *getTypeExt(TYPE); + static TYPE getTypeFromStr(const char *str); + static PROTOCOL getProtocolFromStr(const char *str); + + ::String name; + GnuID id,bcID; + int bitrate; + TYPE contentType; + PROTOCOL srcProtocol; + unsigned int lastPlayStart,lastPlayEnd; + unsigned int numSkips; + unsigned int createdTime; + + STATUS status; + + TrackInfo track; + ::String desc,genre,url,comment; + +}; + + +// ---------------------------------- +class ChanHit +{ +public: + void init(); + void initLocal(int numl,int numr,int nums,int uptm,bool,bool,unsigned int,Channel*,unsigned int,unsigned int); + XML::Node *createXML(); + + void writeAtoms(AtomStream &,GnuID &); + bool writeVariable(Stream &, const String &); + + void pickNearestIP(Host &); + + Host host; + Host rhost[2]; + unsigned int numListeners,numRelays,numHops; + unsigned int time,upTime,lastContact; + unsigned int hitID; + GnuID sessionID,chanID; + unsigned int version; + unsigned int version_vp; + + bool firewalled:1,stable:1,tracker:1,recv:1,yp:1,dead:1,direct:1,relay:1,cin:1; + bool relayfull:1,chfull:1,ratefull:1; + + ChanHit *next; + + int status; + int servent_id; + + unsigned int oldestPos,newestPos; + Host uphost; + unsigned int uphostHops; + + char version_ex_prefix[2]; + unsigned int version_ex_number; +}; +// ---------------------------------- +class ChanHitList +{ +public: + ChanHitList(); + ~ChanHitList(); + + int contactTrackers(bool,int,int,int); + + ChanHit *addHit(ChanHit &); + void delHit(ChanHit &); + void deadHit(ChanHit &); + void clearHits(bool); + int numHits(); + int numListeners(); + int numRelays(); + int numFirewalled(); + int numTrackers(); + int closestHit(); + int furthestHit(); + unsigned int newestHit(); + + int pickHits(ChanHitSearch &); + int pickSourceHits(ChanHitSearch &); + + bool isUsed() {return used;} + int clearDeadHits(unsigned int,bool); + XML::Node *createXML(bool addHits = true); + + ChanHit *deleteHit(ChanHit *); + + int getTotalListeners(); + int getTotalRelays(); + int getTotalFirewalled(); + + bool used; + ChanInfo info; + ChanHit *hit; + unsigned int lastHitTime; + ChanHitList *next; + + +}; +// ---------------------------------- +class ChanHitSearch +{ +public: + enum + { + MAX_RESULTS = 8 + }; + + ChanHitSearch() { init(); } + void init(); + + ChanHit best[MAX_RESULTS]; + Host matchHost; + unsigned int waitDelay; + bool useFirewalled; + bool trackersOnly; + bool useBusyRelays,useBusyControls; + GnuID excludeID; + int numResults; + unsigned int seed; + + int getRelayHost(Host host1, Host host2, GnuID exID, ChanHitList *chl); +}; + +// ---------------------------------- +class ChanMeta +{ +public: + enum { + MAX_DATALEN = 65536 + }; + + void init() + { + len = 0; + cnt = 0; + startPos = 0; + } + + void fromXML(XML &); + void fromMem(void *,int); + void addMem(void *,int); + + unsigned int len,cnt,startPos; + char data[MAX_DATALEN]; +}; + + + +// ------------------------------------------ +class RawStream : public ChannelStream +{ +public: + virtual void readHeader(Stream &,Channel *); + virtual int readPacket(Stream &,Channel *); + virtual void readEnd(Stream &,Channel *); + +}; + +// ------------------------------------------ +class PeercastStream : public ChannelStream +{ +public: + virtual void readHeader(Stream &,Channel *); + virtual int readPacket(Stream &,Channel *); + virtual void readEnd(Stream &,Channel *); +}; + +// ------------------------------------------ +class ChannelSource +{ +public: + virtual ~ChannelSource() {} + virtual void stream(Channel *) = 0; + + virtual int getSourceRate() {return 0;} + +}; +// ------------------------------------------ +class PeercastSource : public ChannelSource +{ +public: + + + virtual void stream(Channel *); + +}; + + +// ---------------------------------- +class Channel +{ +public: + + enum STATUS + { + S_NONE, + S_WAIT, + S_CONNECTING, + S_REQUESTING, + S_CLOSING, + S_RECEIVING, + S_BROADCASTING, + S_ABORT, + S_SEARCHING, + S_NOHOSTS, + S_IDLE, + S_ERROR, + S_NOTFOUND + }; + + enum TYPE + { + T_NONE, + T_ALLOCATED, + T_BROADCAST, + T_RELAY + }; + + enum SRC_TYPE + { + SRC_NONE, + SRC_PEERCAST, + SRC_SHOUTCAST, + SRC_ICECAST, + SRC_URL + }; + + + Channel(); + void reset(); + void endThread(bool flg); + + void startMP3File(char *); + void startGet(); + void startICY(ClientSocket *,SRC_TYPE); + void startURL(const char *); + + + ChannelStream *createSource(); + + void resetPlayTime(); + + bool notFound() + { + return (status == S_NOTFOUND); + } + + bool isPlaying() + { + return (status == S_RECEIVING) || (status == S_BROADCASTING); + } + + bool isReceiving() + { + return (status == S_RECEIVING); + } + + bool isBroadcasting() + { + return (status == S_BROADCASTING); + } + + bool isFull(); + + bool checkBump(); + + bool checkIdle(); + void sleepUntil(double); + + bool isActive() + { + return type != T_NONE; + } + + + void connectFetch(); + int handshakeFetch(); + + bool isIdle() {return isActive() && (status==S_IDLE);} + + static THREAD_PROC stream(ThreadInfo *); + + static THREAD_PROC waitFinish(ThreadInfo *); + + void setStatus(STATUS s); + const char *getSrcTypeStr() {return srcTypes[srcType];} + const char *getStatusStr() {return statusMsgs[status];} + const char *getName() {return info.name.cstr();} + GnuID getID() {return info.id;} + int getBitrate() {return info.bitrate; } + void getIDStr(char *s) {info.id.toStr(s);} + void getStreamPath(char *); + + void broadcastTrackerUpdate(GnuID &,bool = false); + bool sendPacketUp(ChanPacket &,GnuID &,GnuID &,GnuID &); + + bool writeVariable(Stream &, const String &,int); + + bool acceptGIV(ClientSocket *); + + void updateInfo(ChanInfo &); + + int readStream(Stream &,ChannelStream *); + + void checkReadDelay(unsigned int); + + void processMp3Metadata(char *); + + void readHeader(); + + void startStream(); + + XML::Node *createRelayXML(bool); + + void newPacket(ChanPacket &); + + int localListeners(); + int localRelays(); + + int totalListeners(); + int totalRelays(); + + ::String mount; + ChanMeta insertMeta; + ChanPacket headPack; + + ChanPacketBuffer rawData; + + ChannelStream *sourceStream; + unsigned int streamIndex; + + + ChanInfo info; + ChanHit sourceHost; + + GnuID remoteID; + + + ::String sourceURL; + + bool bump,stayConnected; + int icyMetaInterval; + unsigned int streamPos; + unsigned int skipCount; //JP-EX + bool readDelay; + + TYPE type; + ChannelSource *sourceData; + + SRC_TYPE srcType; + + MP3Header mp3Head; + ThreadInfo thread; + ThreadInfo *finthread; + + unsigned int lastIdleTime; + int status; + static char *statusMsgs[],*srcTypes[]; + + ClientSocket *sock; + ClientSocket *pushSock; + + unsigned int lastTrackerUpdate; + unsigned int lastMetaUpdate; + + double startTime,syncTime; + + WEvent syncEvent; + + Channel *next; + + int channel_id; + ChanHit chDisp; + ChanHit trackerHit; + bool bumped; + unsigned int lastSkipTime; + unsigned int lastStopTime; +}; + +// ---------------------------------- +class ChanMgr +{ +public: + enum { + MAX_IDLE_CHANNELS = 8, // max. number of channels that can be left idle + MAX_METAINT = 8192 // must be at least smaller than ChanPacket data len (ie. about half) + + }; + + + ChanMgr(); + + Channel *deleteChannel(Channel *); + + Channel *createChannel(ChanInfo &,const char *); + Channel *findChannelByName(const char *); + Channel *findChannelByIndex(int); + Channel *findChannelByMount(const char *); + Channel *findChannelByID(GnuID &); + Channel *findChannelByNameID(ChanInfo &); + Channel *findPushChannel(int); + Channel *findChannelByChannelID(int id); + + void broadcastTrackerSettings(); + void setUpdateInterval(unsigned int v); + void broadcastRelays(Servent *,int,int); + + int broadcastPacketUp(ChanPacket &,GnuID &,GnuID &,GnuID &); + void broadcastTrackerUpdate(GnuID &,bool = false); + + bool writeVariable(Stream &, const String &,int); + + int findChannels(ChanInfo &,Channel **,int); + int findChannelsByStatus(Channel **,int,Channel::STATUS); + + int numIdleChannels(); + int numChannels(); + + void closeOldestIdle(); + void closeAll(); + void quit(); + + void addHit(Host &,GnuID &,bool); + ChanHit *addHit(ChanHit &); + void delHit(ChanHit &); + void deadHit(ChanHit &); + void setFirewalled(Host &); + + ChanHitList *findHitList(ChanInfo &); + ChanHitList *findHitListByID(GnuID &); + ChanHitList *addHitList(ChanInfo &); + + void clearHitLists(); + void clearDeadHits(bool); + int numHitLists(); + + void setBroadcastMsg(::String &); + + Channel *createRelay(ChanInfo &,bool); + Channel *findAndRelay(ChanInfo &); + void startSearch(ChanInfo &); + + void playChannel(ChanInfo &); + void findAndPlayChannel(ChanInfo &,bool); + + bool isBroadcasting(GnuID &); + bool isBroadcasting(); + + int pickHits(ChanHitSearch &); + + + + Channel *channel; + ChanHitList *hitlist; + + GnuID broadcastID; + + ChanInfo searchInfo; + + int numFinds; + ::String broadcastMsg; + unsigned int broadcastMsgInterval; + unsigned int lastHit,lastQuery; + unsigned int maxUptime; + bool searchActive; + unsigned int deadHitAge; + int icyMetaInterval; + int maxRelaysPerChannel; + WLock lock; + int minBroadcastTTL,maxBroadcastTTL; + int pushTimeout,pushTries,maxPushHops; + unsigned int autoQuery; + unsigned int prefetchTime; + unsigned int lastYPConnect; + unsigned int lastYPConnect2; + unsigned int icyIndex; + + unsigned int hostUpdateInterval; + unsigned int bufferTime; + + GnuID currFindAndPlayChannel; + + WLock channellock; + WLock hitlistlock; +}; +// ---------------------------------- +class PlayList +{ +public: + + enum TYPE + { + T_NONE, + T_SCPLS, + T_PLS, + T_ASX, + T_RAM, + }; + + PlayList(TYPE t, int max) + { + maxURLs = max; + numURLs = 0; + type = t; + urls = new ::String[max]; + titles = new ::String[max]; + } + + ~PlayList() + { + delete [] urls; + delete [] titles; + } + + void addURL(const char *url, const char *tit) + { + if (numURLs < maxURLs) + { + urls[numURLs].set(url); + titles[numURLs].set(tit); + numURLs++; + } + } + void addChannels(const char *,Channel **,int); + void addChannel(const char *,ChanInfo &); + + void writeSCPLS(Stream &); + void writePLS(Stream &); + void writeASX(Stream &); + void writeRAM(Stream &); + + void readSCPLS(Stream &); + void readPLS(Stream &); + void readASX(Stream &); + + void read(Stream &s) + { + try + { + switch (type) + { + case T_SCPLS: readSCPLS(s); break; + case T_PLS: readPLS(s); break; + case T_ASX: readASX(s); break; + } + }catch(StreamException &) {} // keep pls regardless of errors (eof isn`t handled properly in sockets) + } + + void write(Stream &s) + { + switch (type) + { + case T_SCPLS: writeSCPLS(s); break; + case T_PLS: writePLS(s); break; + case T_ASX: writeASX(s); break; + case T_RAM: writeRAM(s); break; + } + } + + TYPE type; + int numURLs,maxURLs; + ::String *urls,*titles; +}; + +// ---------------------------------- + +extern ChanMgr *chanMgr; + +// for PCRaw start. +bool isIndexTxt(ChanInfo *info); +bool isIndexTxt(Channel *ch); +int numMaxRelaysIndexTxt(Channel *ch); +int canStreamIndexTxt(Channel *ch); +// for PCRaw end + +#endif diff --git a/PeerCast.root/PeerCast/core/common/common.h b/PeerCast.root/PeerCast/core/common/common.h new file mode 100644 index 0000000..99a1c9b --- /dev/null +++ b/PeerCast.root/PeerCast/core/common/common.h @@ -0,0 +1,293 @@ +// ------------------------------------------------ +// File : common.h +// Date: 4-apr-2002 +// Author: giles +// +// (c) 2002 peercast.org +// ------------------------------------------------ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// ------------------------------------------------ + +#ifndef _COMMON_H +#define _COMMON_H + +#pragma warning (disable: 4996) + +#include +#include + +#ifndef NULL +#define NULL 0 +#endif + +// ---------------------------------- +class GeneralException +{ +public: + GeneralException(const char *m, int e = 0) + { + strcpy(msg,m); + err=e; + } + char msg[128]; + int err; +}; + +// ------------------------------------- +class StreamException : public GeneralException +{ +public: + StreamException(const char *m) : GeneralException(m) {} + StreamException(const char *m,int e) : GeneralException(m,e) {} +}; + +// ---------------------------------- +class SockException : public StreamException +{ +public: + SockException(const char *m="Socket") : StreamException(m) {} + SockException(const char *m, int e) : StreamException(m,e) {} +}; +// ---------------------------------- +class EOFException : public StreamException +{ +public: + EOFException(const char *m="EOF") : StreamException(m) {} + EOFException(const char *m, int e) : StreamException(m,e) {} +}; + +// ---------------------------------- +class CryptException : public StreamException +{ +public: + CryptException(const char *m="Crypt") : StreamException(m) {} + CryptException(const char *m, int e) : StreamException(m,e) {} +}; + + +// ---------------------------------- +class TimeoutException : public StreamException +{ +public: + TimeoutException(const char *m="Timeout") : StreamException(m) {} +}; +// -------------------------------- +class GnuID +{ +public: + bool isSame(GnuID &gid) + { + for(int i=0; i<16; i++) + if (gid.id[i] != id[i]) + return false; + return true; + } + + + bool isSet() + { + for(int i=0; i<16; i++) + if (id[i] != 0) + return true; + return false; + } + + void clear() + { + for(int i=0; i<16; i++) + id[i] = 0; + storeTime = 0; + } + + + void generate(unsigned char = 0); + void encode(class Host *, const char *,const char *,unsigned char); + + void toStr(char *); + void fromStr(const char *); + + unsigned char getFlags(); + + unsigned char id[16]; + unsigned int storeTime; +}; +// -------------------------------- +class GnuIDList +{ +public: + GnuIDList(int); + ~GnuIDList(); + void clear(); + void add(GnuID &); + bool contains(GnuID &); + int numUsed(); + unsigned int getOldest(); + + GnuID *ids; + int maxID; +}; + + +// ---------------------------------- +class Host +{ + inline unsigned int ip3() + { + return (ip>>24); + } + inline unsigned int ip2() + { + return (ip>>16)&0xff; + } + inline unsigned int ip1() + { + return (ip>>8)&0xff; + } + inline unsigned int ip0() + { + return ip&0xff; + } + +public: + Host(){init();} + Host(unsigned int i, unsigned short p) + { + ip = i; + port = p; + value = 0; + } + + void init() + { + ip = 0; + port = 0; + value = 0; + } + + + bool isMemberOf(Host &); + + bool isSame(Host &h) + { + return (h.ip == ip) && (h.port == port); + } + + bool classType() {return globalIP();} + + bool globalIP() + { + // local host + if ((ip3() == 127) && (ip2() == 0) && (ip1() == 0) && (ip0() == 1)) + return false; + + // class A + if (ip3() == 10) + return false; + + // class B + if ((ip3() == 172) && (ip2() >= 16) && (ip2() <= 31)) + return false; + + // class C + if ((ip3() == 192) && (ip2() == 168)) + return false; + + return true; + } + bool localIP() + { + return !globalIP(); + } + + bool loopbackIP() + { +// return ((ipByte[3] == 127) && (ipByte[2] == 0) && (ipByte[1] == 0) && (ipByte[0] == 1)); + return ((ip3() == 127) && (ip2() == 0) && (ip1() == 0) && (ip0() == 1)); + } + + bool isValid() + { + return (ip != 0); + } + + + bool isSameType(Host &h) + { + return ( (globalIP() && h.globalIP()) || + (!globalIP() && !h.globalIP()) ); + } + + void IPtoStr(char *str) + { + sprintf(str,"%d.%d.%d.%d",(ip>>24)&0xff,(ip>>16)&0xff,(ip>>8)&0xff,(ip)&0xff); + } + + void toStr(char *str) + { + sprintf(str,"%d.%d.%d.%d:%d",(ip>>24)&0xff,(ip>>16)&0xff,(ip>>8)&0xff,(ip)&0xff,port); + } + + void fromStrIP(const char *,int); + void fromStrName(const char *,int); + + bool isLocalhost(); + + + union + { + unsigned int ip; +// unsigned char ipByte[4]; + }; + + unsigned short port; + unsigned int value; +}; +// ---------------------------------- +#define SWAP2(v) ( ((v&0xff)<<8) | ((v&0xff00)>>8) ) +#define SWAP3(v) (((v&0xff)<<16) | ((v&0xff00)) | ((v&0xff0000)>>16) ) +#define SWAP4(v) (((v&0xff)<<24) | ((v&0xff00)<<8) | ((v&0xff0000)>>8) | ((v&0xff000000)>>24)) +#define TOUPPER(c) ((((c) >= 'a') && ((c) <= 'z')) ? (c)+'A'-'a' : (c)) +#define TONIBBLE(c) ((((c) >= 'A')&&((c) <= 'F')) ? (((c)-'A')+10) : ((c)-'0')) +#define BYTES_TO_KBPS(n) (float)(((((float)n)*8.0f)/1024.0f)) + +// ---------------------------------- +inline bool isWhiteSpace(char c) +{ + return (c == ' ') || (c == '\r') || (c == '\n') || (c == '\t'); +} + +// ---------------------------------- +inline int strToID(char *str) +{ + union { + int i; + char s[8]; + }; + strncpy(s,str,4); + return i; +} + +// ----------------------------------- +char *getCGIarg(const char *str, const char *arg); +bool cmpCGIarg(char *str, char *arg, char *value); +bool hasCGIarg(char *str, char *arg); + +// ---------------------------------- +extern void LOG(const char *fmt,...); + +extern void LOG_ERROR(const char *fmt,...); +extern void LOG_DEBUG(const char *fmt,...); +extern void LOG_NETWORK(const char *fmt,...); +extern void LOG_CHANNEL(const char *fmt,...); + + +#endif + diff --git a/PeerCast.root/PeerCast/core/common/cstream.h b/PeerCast.root/PeerCast/core/common/cstream.h new file mode 100644 index 0000000..f1a228b --- /dev/null +++ b/PeerCast.root/PeerCast/core/common/cstream.h @@ -0,0 +1,241 @@ +// ------------------------------------------------ +// File : cstream.h +// Date: 12-mar-2004 +// Author: giles +// +// (c) 2002-4 peercast.org +// ------------------------------------------------ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// ------------------------------------------------ + +#ifndef _CSTREAM_H +#define _CSTREAM_H + +// ---------------------------------- + +class Channel; +class ChanPacket; +class ChanPacketv; +class Stream; + + +// ---------------------------------- +class ChanPacket +{ +public: + enum + { + MAX_DATALEN = 16384 + }; + + enum TYPE + { + T_UNKNOWN = 0, + T_HEAD = 1, + T_DATA = 2, + T_META = 4, + T_PCP = 16, + T_ALL = 0xff + }; + + ChanPacket() + { + init(); + } + + void init() + { + type = T_UNKNOWN; + len = 0; + pos = 0; + sync = 0; + skip = false; + } + void init(ChanPacketv &p); + void init(TYPE t, const void *, unsigned int , unsigned int ); + + void writeRaw(Stream &); + void writePeercast(Stream &); + void readPeercast(Stream &); + + + unsigned int sync; + unsigned int pos; + TYPE type; + unsigned int len; + char data[MAX_DATALEN]; + bool skip; + +}; +// ---------------------------------- +class ChanPacketv +{ +public: + enum {BSIZE = 0x100}; + ChanPacketv() + { + init(); + } + ~ChanPacketv() + { + free(); + } + + void free() + { + if (data) { + delete [] data; + data = NULL; + datasize = 0; + } + } + void reset() + { + free(); + init(); + } + void init() + { + type = ChanPacket::T_UNKNOWN; + len = 0; + pos = 0; + sync = 0; + skip = false; + data = NULL; + datasize = 0; + } + void init(ChanPacket &p) + { + if (data && (datasize < p.len || datasize > p.len + BSIZE * 4)) { + free(); + data = NULL; + datasize = 0; + } + type = p.type; + len = p.len; + pos = p.pos; + sync = p.sync; + skip = p.skip; + if (!data) { + datasize = (len & ~(BSIZE - 1)) + BSIZE; + data = new char[datasize]; + } + memcpy(data, p.data, len); + } + void init(ChanPacketv &p) + { + ChanPacket tp; + tp.init(p); + init(tp); + } + + void writeRaw(Stream &); + void writePeercast(Stream &); + void readPeercast(Stream &); + + unsigned int sync; + unsigned int pos; + ChanPacket::TYPE type; + unsigned int len; + char *data; + unsigned int datasize; + bool skip; + +}; +// ---------------------------------- +class ChanPacketBuffer +{ +public: + enum { + MAX_PACKETS = 64, + NUM_SAFEPACKETS = 60 + }; + + void init() + { + lock.on(); + lastPos = firstPos = safePos = 0; + readPos = writePos = 0; + accept = 0; + lastWriteTime = 0; + for (int i = 0; i < MAX_PACKETS; i++) packets[i].reset(); + lock.off(); + + lastSkipTime = 0; + } + + int copyFrom(ChanPacketBuffer &,unsigned in); + + bool writePacket(ChanPacket &,bool = false); + void readPacket(ChanPacket &); + + bool willSkip(); + + int numPending() {return writePos-readPos;} + + unsigned int getLatestPos(); + unsigned int getOldestPos(); + unsigned int findOldestPos(unsigned int); + bool findPacket(unsigned int,ChanPacket &); + unsigned int getStreamPos(unsigned int); + unsigned int getStreamPosEnd(unsigned int); + unsigned int getLastSync(); + + //ChanPacket packets[MAX_PACKETS]; + ChanPacketv packets[MAX_PACKETS]; + volatile unsigned int lastPos,firstPos,safePos; + volatile unsigned int readPos,writePos; + unsigned int accept; + unsigned int lastWriteTime; + WLock lock; + + unsigned int lastSkipTime; +}; + +// ---------------------------------- +class ChannelStream +{ +public: + ChannelStream() + :numListeners(0) + ,numRelays(0) + ,isPlaying(false) + ,fwState(0) + ,lastUpdate(0) + ,lastCheckTime(0) + ,parent(NULL) + {} + virtual ~ChannelStream() {} + + void updateStatus(Channel *); + bool getStatus(Channel *,ChanPacket &); + + virtual void kill() {} + virtual bool sendPacket(ChanPacket &,GnuID &) {return false;} + virtual void flush(Stream &) {} + virtual void readHeader(Stream &,Channel *)=0; + virtual int readPacket(Stream &,Channel *)=0; + virtual void readEnd(Stream &,Channel *)=0; + + void readRaw(Stream &,Channel *); + + int numRelays; + int numListeners; + bool isPlaying; + int fwState; + unsigned int lastUpdate; + unsigned int lastCheckTime; + + Channel *parent; +}; + +#endif + diff --git a/PeerCast.root/PeerCast/core/common/gnutella.cpp b/PeerCast.root/PeerCast/core/common/gnutella.cpp new file mode 100644 index 0000000..bff67fd --- /dev/null +++ b/PeerCast.root/PeerCast/core/common/gnutella.cpp @@ -0,0 +1,751 @@ +// ------------------------------------------------ +// File : gnutella.cpp +// Date: 4-apr-2002 +// Author: giles +// Desc: +// GnuPacket is a Gnutella protocol packet. +// GnuStream is a Stream that reads/writes GnuPackets +// +// +// (c) 2002 peercast.org +// +// ------------------------------------------------ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// ------------------------------------------------ + +#include "gnutella.h" +#include "stream.h" +#include "common.h" +#include "servent.h" +#include "servmgr.h" +#include "stats.h" +#include +#ifdef _DEBUG +#include "chkMemoryLeak.h" +#define DEBUG_NEW new(__FILE__, __LINE__) +#define new DEBUG_NEW +#endif + +// --------------------------- +const char *GNU_FUNC_STR(int func) +{ + switch (func) + { + case GNU_FUNC_PING: return "PING"; break; + case GNU_FUNC_PONG: return "PONG"; break; + case GNU_FUNC_QUERY: return "QUERY"; break; + case GNU_FUNC_HIT: return "HIT"; break; + case GNU_FUNC_PUSH: return "PUSH"; break; + default: return "UNKNOWN"; break; + } +} + +// --------------------------- +const char *GnuStream::getRouteStr(R_TYPE r) +{ + switch(r) + { + case R_PROCESS: return "PROCESS"; break; + case R_DEAD: return "DEAD"; break; + case R_DISCARD: return "DISCARD"; break; + case R_ACCEPTED: return "ACCEPTED"; break; + case R_BROADCAST: return "BROADCAST"; break; + case R_ROUTE: return "ROUTE"; break; + case R_DUPLICATE: return "DUPLICATE"; break; + case R_BADVERSION: return "BADVERSION"; break; + case R_DROP: return "DROP"; break; + default: return "UNKNOWN"; break; + } +} +// --------------------------- +void GnuPacket::makeChecksumID() +{ + for(unsigned int i=0; inumChannels()); // cnt + pk.writeLong(servMgr->totalOutput(false)); // total + }else{ + pk.writeLong(0); // cnt + pk.writeLong(0); // total + } + + +} +// --------------------------- +void GnuPacket::initPush(ChanHit &ch, Host &sh) +{ +#if 0 + func = GNU_FUNC_PUSH; + ttl = ch.numHops; + hops = 0; + len = 26; + id.generate(); + + MemoryStream data(data,len); + + // ID of Hit packet + data.write(ch.packetID.id,16); + + // index of channel + data.writeLong(ch.index); + + data.writeLong(SWAP4(sh.ip)); // ip + data.writeShort(sh.port); // port +#endif +} + + +// --------------------------- +bool GnuPacket::initHit(Host &h, Channel *ch, GnuPacket *query, bool push, bool busy, bool stable, bool tracker, int maxttl) +{ + if (!ch) + return false; + + func = GNU_FUNC_HIT; + hops = 0; + id.generate(); + + ttl = maxttl; + + + MemoryStream mem(data,MAX_DATA); + + mem.writeChar(1); // num hits + mem.writeShort(h.port); // port + mem.writeLong(SWAP4(h.ip)); // ip + + if (query) + mem.writeLong(0); // speed - route + else + mem.writeLong(1); // broadcast + + + //mem.writeLong(ch->index); // index + mem.writeLong(0); // index + mem.writeShort(ch->getBitrate()); // bitrate + mem.writeShort(ch->localListeners()); // num listeners + + mem.writeChar(0); // no name + + XML xml; + XML::Node *cn = ch->info.createChannelXML(); + cn->add(ch->info.createTrackXML()); + xml.setRoot(cn); + xml.writeCompact(mem); + + mem.writeChar(0); // extra null + + + // QHD + mem.writeLong('PCST'); // vendor ID + mem.writeChar(2); // public sector length + + int f1 = 0, f2 = 0; + + f1 = 1 | 4 | 8 | 32 | 64; // use push | busy | stable | broadcast | tracker + + if (push) f2 |= 1; + if (busy) f2 |= 4; + if (stable) f2 |= 8; + if (!query) f2 |= 32; + if (tracker) f2 |= 64; + + mem.writeChar(f1); + mem.writeChar(f2); + + { + // write private sector + char pbuf[256]; + MemoryStream pmem(pbuf,sizeof(pbuf)); + XML xml; + XML::Node *pn = servMgr->createServentXML(); + xml.setRoot(pn); + xml.writeCompact(pmem); + pmem.writeChar(0); // add null terminator + if (pmem.pos <= 255) + { + mem.writeChar(pmem.pos); + mem.write(pmem.buf,pmem.pos); + }else + mem.writeChar(0); + } + + + // queryID/not used + if (query) + mem.write(query->id.id,16); + else + mem.write(id.id,16); + + len = mem.pos; + + LOG_NETWORK("Created Hit packet: %d bytes",len); + + if (len >= MAX_DATA) + return false; + +// servMgr->addReplyID(id); + return true; +} + + +// --------------------------- +void GnuPacket::initFind(const char *str, XML *xml, int maxTTL) +{ + + func = GNU_FUNC_QUERY; + ttl = maxTTL; + hops = 0; + id.generate(); + + MemoryStream mem(data,MAX_DATA); + + mem.writeShort(0); // min speed + + if (str) + { + int slen = strlen(str); + mem.write((void *)str,slen+1); // string + }else + mem.writeChar(0); // null string + + + if (xml) + xml->writeCompact(mem); + + len = mem.pos; +} + +// --------------------------- +void GnuStream::ping(int ttl) +{ + GnuPacket ping; + ping.initPing(ttl); +// servMgr->addReplyID(ping.id); + sendPacket(ping); + LOG_NETWORK("ping out %02x%02x%02x%02x",ping.id.id[0],ping.id.id[1],ping.id.id[2],ping.id.id[3]); +} + +// --------------------------- +void GnuStream::sendPacket(GnuPacket &p) +{ + try + { + lock.on(); + packetsOut++; + stats.add(Stats::NUMPACKETSOUT); + + switch(p.func) + { + case GNU_FUNC_PING: stats.add(Stats::NUMPINGOUT); break; + case GNU_FUNC_PONG: stats.add(Stats::NUMPONGOUT); break; + case GNU_FUNC_QUERY: stats.add(Stats::NUMQUERYOUT); break; + case GNU_FUNC_HIT: stats.add(Stats::NUMHITOUT); break; + case GNU_FUNC_PUSH: stats.add(Stats::NUMPUSHOUT); break; + default: stats.add(Stats::NUMOTHEROUT); break; + } + + + write(p.id.id,16); + writeChar(p.func); // ping func + writeChar(p.ttl); // ttl + writeChar(p.hops); // hops + writeLong(p.len); // len + + if (p.len) + write(p.data,p.len); + + stats.add(Stats::PACKETDATAOUT,23+p.len); + + lock.off(); + }catch(StreamException &e) + { + lock.off(); + throw e; + } +} +// --------------------------- +bool GnuStream::readPacket(GnuPacket &p) +{ + try + { + lock.on(); + packetsIn++; + stats.add(Stats::NUMPACKETSIN); + + read(p.id.id,16); + p.func = readChar(); + p.ttl = readChar(); + p.hops = readChar(); + p.len = readLong(); + + + if ((p.hops >= 1) && (p.hops <= 10)) + stats.add((Stats::STAT)((int)Stats::NUMHOPS1+p.hops-1)); + + stats.add(Stats::PACKETDATAIN,23+p.len); + + switch(p.func) + { + case GNU_FUNC_PING: stats.add(Stats::NUMPINGIN); break; + case GNU_FUNC_PONG: stats.add(Stats::NUMPONGIN); break; + case GNU_FUNC_QUERY: stats.add(Stats::NUMQUERYIN); break; + case GNU_FUNC_HIT: stats.add(Stats::NUMHITIN); break; + case GNU_FUNC_PUSH: stats.add(Stats::NUMPUSHIN); break; + default: stats.add(Stats::NUMOTHERIN); break; + } + + + if (p.len) + { + if (p.len > GnuPacket::MAX_DATA) + { + while (p.len--) + readChar(); + lock.off(); + return false; + } + read(p.data,p.len); + } + + lock.off(); + return true; + }catch(StreamException &e) + { + lock.off(); + throw e; + } +} + +// --------------------------- +GnuStream::R_TYPE GnuStream::processPacket(GnuPacket &in, Servent *serv, GnuID &routeID) +{ + + R_TYPE ret = R_DISCARD; + + MemoryStream data(in.data,in.len); + + Host remoteHost = serv->getHost(); + + in.ttl--; + in.hops++; + + routeID = in.id; + + + + switch(in.func) + { + case GNU_FUNC_PING: // ping + { + LOG_NETWORK("ping: from %d.%d.%d.%d : %02x%02x%02x%02x", + remoteHost.ip>>24&0xff,remoteHost.ip>>16&0xff,remoteHost.ip>>8&0xff,remoteHost.ip&0xff, + in.id.id[0],in.id.id[1],in.id.id[2],in.id.id[3] + ); + Host sh = servMgr->serverHost; + if (sh.isValid()) + { + if ((servMgr->getFirewall() != ServMgr::FW_ON) && (!servMgr->pubInFull())) + { + GnuPacket pong; + pong.initPong(sh,true,in); + if (serv->outputPacket(pong,true)) + LOG_NETWORK("pong out"); + } + ret = R_BROADCAST; + } + } + break; + case GNU_FUNC_PONG: // pong + { + { + int ip,port,cnt,total; + port = data.readShort(); + ip = data.readLong(); + cnt = data.readLong(); + total = data.readLong(); + + ip = SWAP4(ip); + + + Host h; + h.ip = ip; + h.port = port; + + char sIP[64],rIP[64]; + h.toStr(sIP); + remoteHost.toStr(rIP); + + LOG_NETWORK("pong: %s via %s : %02x%02x%02x%02x",sIP,ip,rIP,in.id.id[0],in.id.id[1],in.id.id[2],in.id.id[3]); + + + ret = R_DISCARD; + + if (h.isValid()) + { + + #if 0 + // accept if this pong is a reply from one of our own pings, otherwise route back + if (servMgr->isReplyID(in.id)) + { + servMgr->addHost(h,ServHost::T_SERVENT,sys->getTime()); + ret = R_ACCEPTED; + }else + ret = R_ROUTE; + #endif + } + + } + } + break; + case GNU_FUNC_QUERY: // query + ret = R_BROADCAST; + + { + Host sh = servMgr->serverHost; + if (!sh.isValid()) + sh.ip = 127<<24|1; + + char words[256]; + short spd = data.readShort(); + data.readString(words,sizeof(words)); + words[sizeof(words)-1] = 0; + + MemoryStream xm(&data.buf[data.pos],data.len-data.pos); + xm.buf[xm.len] = 0; + + Channel *hits[16]; + int numHits=0; + + if (strncmp(xm.buf,"findChannels(info,hits,16); + } + LOG_NETWORK("query XML: %s : found %d",xm.buf,numHits); + }else{ + ChanInfo info; + info.name.set(words); + info.genre.set(words); + info.id.fromStr(words); + info.status = ChanInfo::S_PLAY; + numHits = chanMgr->findChannels(info,hits,16); + LOG_NETWORK("query STR: %s : found %d",words,numHits); + } + + + + for(int i=0; igetFirewall()!=ServMgr::FW_OFF); + bool busy = (servMgr->pubInFull() && servMgr->outFull()) || servMgr->relaysFull(); + bool stable = servMgr->totalStreams>0; + bool tracker = hits[i]->isBroadcasting(); + + GnuPacket hit; + if (hit.initHit(sh,hits[i],&in,push,busy,stable,tracker,in.hops)) + serv->outputPacket(hit,true); + } + } + break; + case GNU_FUNC_PUSH: // push + { + + GnuID pid; + data.read(pid.id,16); + + //LOG("push serv= %02x%02x%02x%02x",servMgr->id[0],servMgr->id[1],servMgr->id[2],servMgr->id[3]); + //LOG("pack = %02x%02x%02x%02x",id[0],id[1],id[2],id[3]); + + + int index = data.readLong(); + int ip = data.readLong(); + int port = data.readShort(); + + + ip = SWAP4(ip); + + Host h(ip,port); + char hostName[64]; + h.toStr(hostName); + +#if 0 + if (servMgr->isReplyID(pid)) + { +#if 0 + Channel *c = chanMgr->findChannelByIndex(index); + + if (!c) + { + LOG_NETWORK("push 0x%x to %s: Not found",index,hostName); + }else + { + if (!c->isFull() && !servMgr->streamFull()) + { + LOG_NETWORK("push: 0x%x to %s: OK",index,hostName); + + Servent *s = servMgr->allocServent(); + if (s) + s->initGIV(h,c->info.id); + }else + LOG_NETWORK("push: 0x%x to %s: FULL",index,hostName); + } +#endif + ret = R_ACCEPTED; + }else{ + LOG_NETWORK("push: 0x%x to %s: ROUTE",index,hostName); + routeID = pid; + ret = R_ROUTE; + } +#endif + } + break; + case GNU_FUNC_HIT: // hit + { + ret = R_DISCARD; + + ChanHit hit; + if (readHit(data,hit,in.hops,in.id)) + { + + char flstr[64]; + flstr[0]=0; + if (hit.firewalled) strcat(flstr,"Push,"); + if (hit.tracker) strcat(flstr,"Tracker,"); + +#if 0 + if ((spd == 0) && (!isBroadcastHit)) + { + if (servMgr->isReplyID(queryID)) + { + ret = R_ACCEPTED; + LOG_NETWORK("self-hit: %s 0x%02x %s %d chan",hostName,f2,flstr,num); + }else + { + routeID = queryID; + ret = R_ROUTE; + LOG_NETWORK("route-hit: %s 0x%02x %s %d chan",hostName,f2,flstr,num); + } + }else + { + ret = R_BROADCAST; + LOG_NETWORK("broadcast-hit: %s 0x%02x %s %d chan",hostName,f2,flstr,num); + } +#else + ret = R_BROADCAST; + LOG_NETWORK("broadcast-hit: %s",flstr); +#endif + } + } + break; + default: + LOG_NETWORK("packet: %d",in.func); + break; + } + + + if ((in.ttl > 10) || (in.hops > 10) || (in.ttl==0)) + if ((ret == R_BROADCAST) || (ret == R_ROUTE)) + ret = R_DEAD; + + return ret; +} + +// --------------------------- +bool GnuStream::readHit(Stream &data, ChanHit &ch,int hops,GnuID &id) +{ + int i; + int num = data.readChar(); // hits + int port = data.readShort(); // port + int ip = data.readLong(); // ip + ip = SWAP4(ip); + int spd = data.readLong(); // speed/broadcast + + Host h(ip,port); + char hostName[64]; + + h.IPtoStr(hostName); + + bool dataValid=true; + + ChanHit *hits[100]; + int numHits=0; + + for(i=0; ifindAttrInt("uptime"); + + }else + LOG_NETWORK("Missing Channel node"); + }else + { + LOG_NETWORK("Missing XML data"); + //LOG_NETWORK("%s",xmlData); + dataValid = false; + } + } + + if (info.id.isSet()) + { + if (!chanMgr->findHitList(info)) + chanMgr->addHitList(info); + + ch.recv = true; + ch.chanID = info.id; + ChanHit *chp = chanMgr->addHit(ch); + + if ((chp) && (numHits<100)) + hits[numHits++] = chp; + } + + } + + + int vendor = data.readLong(); // vendor ID + + int pubLen = data.readChar(); // public sec length - should be 2 + + int f1 = data.readChar() & 0xff; // flags 1 + int f2 = data.readChar() & 0xff; // flags 2 + + pubLen -= 2; + while (pubLen-->0) + data.readChar(); + + + char agentStr[16]; + agentStr[0]=0; + int maxPreviewTime=0; + + // read private sector with peercast servant specific info + int privLen = data.readChar(); + + if (privLen) + { + char privData[256]; + data.read(privData,privLen); + if (strncmp(privData,"findAttr("agent"); + if (ag) + { + strncpy(agentStr,ag,16); + agentStr[15]=0; + } + maxPreviewTime = sn->findAttrInt("preview"); + } + + } + } + + + // not used anymore + GnuID queryID; + data.read(queryID.id,16); + + bool isBroadcastHit=false; + if (f1 & 32) + isBroadcastHit = (f2 & 32)!=0; + + for(i=0; ifirewalled = (f2 & 1)!=0; + + if (f1 & 64) + hits[i]->tracker = (f2 & 64)!=0; + + } + + return dataValid; +} + diff --git a/PeerCast.root/PeerCast/core/common/gnutella.h b/PeerCast.root/PeerCast/core/common/gnutella.h new file mode 100644 index 0000000..d31c580 --- /dev/null +++ b/PeerCast.root/PeerCast/core/common/gnutella.h @@ -0,0 +1,295 @@ +// ------------------------------------------------ +// File : gnutella.h +// Date: 4-apr-2002 +// Author: giles +// Desc: +// +// (c) 2002 peercast.org +// ------------------------------------------------ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// ------------------------------------------------ + +#ifndef _GNUTELLA_H +#define _GNUTELLA_H + +// -------------------------------- +#include "stream.h" +#include "sys.h" + + + +#define GNUTELLA_SETUP 0 + + +// -------------------------------- +static const int GNU_FUNC_PING = 0; +static const int GNU_FUNC_PONG = 1; +static const int GNU_FUNC_QUERY = 128; +static const int GNU_FUNC_HIT = 129; +static const int GNU_FUNC_PUSH = 64; + +extern const char *GNU_FUNC_STR(int); + +// -------------------------------- +static const char *GNU_PEERCONN = "PEERCAST CONNECT/0.1"; +static const char *GNU_CONNECT = "GNUTELLA CONNECT/0.6"; +static const char *GNU_OK = "GNUTELLA/0.6 200 OK"; +static const char *PCX_PCP_CONNECT = "pcp"; + +static const char *PCX_HS_OS = "x-peercast-os:"; +static const char *PCX_HS_DL = "x-peercast-download:"; +static const char *PCX_HS_ID = "x-peercast-id:"; +static const char *PCX_HS_CHANNELID = "x-peercast-channelid:"; +static const char *PCX_HS_NETWORKID = "x-peercast-networkid:"; +static const char *PCX_HS_MSG = "x-peercast-msg:"; +static const char *PCX_HS_SUBNET = "x-peercast-subnet:"; +static const char *PCX_HS_FULLHIT = "x-peercast-fullhit:"; +static const char *PCX_HS_MINBCTTL = "x-peercast-minbcttl:"; +static const char *PCX_HS_MAXBCTTL = "x-peercast-maxbcttl:"; +static const char *PCX_HS_RELAYBC = "x-peercast-relaybc:"; +static const char *PCX_HS_PRIORITY = "x-peercast-priority:"; +static const char *PCX_HS_FLOWCTL = "x-peercast-flowctl:"; +static const char *PCX_HS_PCP = "x-peercast-pcp:"; +static const char *PCX_HS_PINGME = "x-peercast-pingme:"; +static const char *PCX_HS_PORT = "x-peercast-port:"; +static const char *PCX_HS_REMOTEIP = "x-peercast-remoteip:"; +static const char *PCX_HS_POS = "x-peercast-pos:"; +static const char *PCX_HS_SESSIONID = "x-peercast-sessionid:"; + +// official version number sent to relay to check for updates +static const char *PCX_OS_WIN32 = "Win32"; +static const char *PCX_OS_LINUX = "Linux"; +static const char *PCX_OS_MACOSX = "Apple-OSX"; +static const char *PCX_OS_WINAMP2 = "Win32-WinAmp2"; +static const char *PCX_OS_ACTIVEX = "Win32-ActiveX"; + +static const char *PCX_DL_URL = "http://www.peercast.org/download.php"; + +// version number sent to other clients +static const char *PCX_OLDAGENT = "PeerCast/0.119E"; + + + + + +// version number used inside packets GUIDs +static const int PEERCAST_PACKETID = 0x0000119E; + +static const char *MIN_ROOTVER = "0.119E"; + +static const char *MIN_CONNECTVER = "0.119D"; +static const int MIN_PACKETVER = 0x0000119D; + +static const char *ICY_OK = "ICY 200 OK"; + +// -------------------------------- + +static const int DEFAULT_PORT = 7144; + +// -------------------------------- + +class Servent; +class Channel; +class ChanHit; + + +// -------------------------------- +class GnuPacket +{ +public: + + + // -------------------------------- + class Hash + { + public: + + bool isSame(Hash &h) + { + return (idChecksum == h.idChecksum) && (dataChecksum == h.dataChecksum); + } + + bool isSameID(Hash &h) + { + return (idChecksum == h.idChecksum); + } + + unsigned int idChecksum; + unsigned int dataChecksum; + + }; + // -------------------------------- + + enum { + MAX_DATA = 2000 + }; + + void initPing(int); + void initPong(Host &, bool, GnuPacket &); + void initFind(const char *, class XML *,int); + bool initHit(Host &, Channel *, GnuPacket *,bool,bool,bool,bool,int); + void initPush(ChanHit &, Host &); + + + void makeChecksumID(); + + unsigned char func; + unsigned char ttl; + unsigned char hops; + unsigned int len; + Hash hash; + GnuID id; + + char data[MAX_DATA]; +}; +// -------------------------------- +class GnuPacketBuffer +{ +public: + GnuPacketBuffer(int s) + :size(s) + ,packets(new GnuPacket[size]) + { + reset(); + } + ~GnuPacketBuffer() + { + delete [] packets; + } + + void reset() + { + readPtr = writePtr = 0; + } + + GnuPacket *curr() + { + if (numPending()) + return &packets[readPtr%size]; + else + return NULL; + + } + void next() + { + readPtr++; + } + + int findMinHop() + { + int min=100; + int n = numPending(); + for(int i=0; i max) + max = packets[idx].hops; + } + return max; + } + + int percentFull() + { + return (numPending()*100) / size; + } + + + int sizeOfPending() + { + int tot=0; + int n = numPending(); + for(int i=0; i= size) + return false; + else + { + packets[writePtr%size] = p; + writePtr++; + return true; + } + } + + int size; + GnuPacket *packets; + int readPtr,writePtr; +}; + + + +// -------------------------------- +class GnuStream : public IndirectStream +{ +public: + + enum R_TYPE + { + R_PROCESS, + R_DEAD, + R_DISCARD, + R_ACCEPTED, + R_BROADCAST, + R_ROUTE, + R_DUPLICATE, + R_BADVERSION, + R_DROP + }; + + GnuStream() + { + init(NULL); + } + + void init(Stream *s) + { + IndirectStream::init(s); + packetsIn = packetsOut = 0; + } + + bool readPacket(GnuPacket &); + void sendPacket(GnuPacket &); + R_TYPE processPacket(GnuPacket &, Servent *, GnuID &); + + static const char *getRouteStr(R_TYPE); + bool readHit(Stream &data, ChanHit &ch,int,GnuID &); + + + + void ping(int); + + int packetsIn,packetsOut; + WLock lock; +}; + + +#endif diff --git a/PeerCast.root/PeerCast/core/common/html-xml.h b/PeerCast.root/PeerCast/core/common/html-xml.h new file mode 100644 index 0000000..ae1d93a --- /dev/null +++ b/PeerCast.root/PeerCast/core/common/html-xml.h @@ -0,0 +1,28 @@ +#ifndef _HTML_H +#define _HTML_H + +// --------------------------------------- +#include "xml.h" + +// --------------------------------------- +class HTML : public XML +{ +public: + HTML(const char *); + + + void startNode(XML::Node *, const char * = NULL); + void addLink(const char *, const char *); + void addArgLink(const char *, const char *); + XML::Node *startTag(const char *, const char * = NULL,...); + XML::Node *startTagEnd(const char *, const char * = NULL,...); + void startSingleTagEnd(const char *,...); + void startTableRow(int); + void end(); + void addRefresh(int); + + char defArgs[128]; + XML::Node *currNode,*headNode,*htmlNode; +}; + +#endif diff --git a/PeerCast.root/PeerCast/core/common/html.cpp b/PeerCast.root/PeerCast/core/common/html.cpp new file mode 100644 index 0000000..ff659ac --- /dev/null +++ b/PeerCast.root/PeerCast/core/common/html.cpp @@ -0,0 +1,558 @@ +// ------------------------------------------------ +// File : html.cpp +// Date: 4-apr-2002 +// Author: giles +// Desc: +// HTML protocol handling +// +// (c) 2002 peercast.org +// ------------------------------------------------ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// ------------------------------------------------ + + +#include +#include +#include "html.h" +#include "http.h" +#include "stream.h" +#include "gnutella.h" +#include "servmgr.h" +#include "channel.h" +#include "stats.h" +#include "version2.h" +#ifdef _DEBUG +#include "chkMemoryLeak.h" +#define DEBUG_NEW new(__FILE__, __LINE__) +#define new DEBUG_NEW +#endif + + +// -------------------------------------- +HTML::HTML(const char *t, Stream &o) +{ + o.writeCRLF = false; + out = new WriteBufferStream(8192, &o); + out->writeCRLF = false; + + title.set(t); + tagLevel = 0; + refresh = 0; +} + +HTML::~HTML() +{ + try { + out->flush(); + } catch (StreamException &) {} + delete out; +} + +// -------------------------------------- +void HTML::writeOK(const char *content) +{ + out->writeLine(HTTP_SC_OK); + out->writeLineF("%s %s",HTTP_HS_SERVER,PCX_AGENT); + //out->writeLine("%s %s",HTTP_HS_CACHE,"no-cache"); + out->writeLineF("%s %s",HTTP_HS_CONNECTION,"close"); + out->writeLineF("%s %s",HTTP_HS_CONTENT,content); + out->writeLine(""); +} +// -------------------------------------- +void HTML::writeVariable(Stream &s,const String &varName, int loop) +{ + bool r=false; + if (varName.startsWith("servMgr.")) + r=servMgr->writeVariable(s,varName+8); + else if (varName.startsWith("chanMgr.")) + r=chanMgr->writeVariable(s,varName+8,loop); + else if (varName.startsWith("stats.")) + r=stats.writeVariable(s,varName+6); + else if (varName.startsWith("sys.")) + { + if (varName == "sys.log.dumpHTML") + { + sys->logBuf->dumpHTML(s); + r=true; + } + } + else if (varName.startsWith("loop.")) + { + if (varName.startsWith("loop.channel.")) + { + Channel *ch = chanMgr->findChannelByIndex(loop); + if (ch) + r = ch->writeVariable(s,varName+13,loop); + }else if (varName.startsWith("loop.servent.")) + { + Servent *sv = servMgr->findServentByIndex(loop); + if (sv) + r = sv->writeVariable(s,varName+13); + }else if (varName.startsWith("loop.filter.")) + { + ServFilter *sf = &servMgr->filters[loop]; + r = sf->writeVariable(s,varName+12); + + }else if (varName.startsWith("loop.bcid.")) + { + BCID *bcid = servMgr->findValidBCID(loop); + if (bcid) + r = bcid->writeVariable(s,varName+10); + + }else if (varName == "loop.indexEven") + { + s.writeStringF("%d",(loop&1)==0); + r = true; + }else if (varName == "loop.index") + { + s.writeStringF("%d",loop); + r = true; + }else if (varName.startsWith("loop.hit.")) + { + char *idstr = getCGIarg(tmplArgs,"id="); + if (idstr) + { + GnuID id; + id.fromStr(idstr); + ChanHitList *chl = chanMgr->findHitListByID(id); + if (chl) + { + int cnt=0; + ChanHit *ch = chl->hit; + while (ch) + { + if (ch->host.ip && !ch->dead) + { + if (cnt == loop) + { + r = ch->writeVariable(s,varName+9); + break; + } + cnt++; + } + ch=ch->next; + } + + } + } + } + + } + else if (varName.startsWith("page.")) + { + if (varName.startsWith("page.channel.")) + { + char *idstr = getCGIarg(tmplArgs,"id="); + if (idstr) + { + GnuID id; + id.fromStr(idstr); + Channel *ch = chanMgr->findChannelByID(id); + if (ch) + r = ch->writeVariable(s,varName+13,loop); + } + }else + { + + String v = varName+5; + v.append('='); + char *a = getCGIarg(tmplArgs,v); + if (a) + { + s.writeString(a); + r=true; + } + } + } + + + if (!r) + s.writeString(varName); +} +// -------------------------------------- +int HTML::getIntVariable(const String &varName,int loop) +{ + String val; + MemoryStream mem(val.cstr(),String::MAX_LEN); + + writeVariable(mem,varName,loop); + + return atoi(val.cstr()); +} +// -------------------------------------- +bool HTML::getBoolVariable(const String &varName,int loop) +{ + String val; + MemoryStream mem(val.cstr(),String::MAX_LEN); + + writeVariable(mem,varName,loop); + + // integer + if ((val[0] >= '0') && (val[0] <= '9')) + return atoi(val.cstr()) != 0; + + // string + if (val[0]!=0) + return true; + + return false; +} + +// -------------------------------------- +void HTML::readIf(Stream &in,Stream *outp,int loop) +{ + String var; + bool varCond=true; + + while (!in.eof()) + { + char c = in.readChar(); + + if (c == '}') + { + if (getBoolVariable(var,loop)==varCond) + { + if (readTemplate(in,outp,loop)) + readTemplate(in,NULL,loop); + }else{ + if (readTemplate(in,NULL,loop)) + readTemplate(in,outp,loop); + } + return; + }else if (c == '!') + { + varCond = !varCond; + }else + { + var.append(c); + } + } + +} + +// -------------------------------------- +void HTML::readLoop(Stream &in,Stream *outp,int loop) +{ + String var; + while (!in.eof()) + { + char c = in.readChar(); + + if (c == '}') + { + int cnt = getIntVariable(var,loop); + + if (cnt) + { + int spos = in.getPosition(); + for(int i=0; iwriteChar(c); + } + else + throw StreamException("Unknown template escape"); + }else + { + if (outp) + outp->writeChar(c); + } + } + return false; +} + +// -------------------------------------- +void HTML::writeTemplate(const char *fileName, const char *args) +{ + FileStream file; + MemoryStream mm; + try + { + file.openReadOnly(fileName); + mm.readFromFile(file); + + tmplArgs = args; + readTemplate(mm,out,0); + + }catch(StreamException &e) + { + out->writeString(e.msg); + out->writeString(" : "); + out->writeString(fileName); + } + + mm.free2(); + file.close(); +} +// -------------------------------------- +void HTML::writeRawFile(const char *fileName) +{ + FileStream file; + try + { + file.openReadOnly(fileName); + + file.writeTo(*out,file.length()); + + }catch(StreamException &) + { + } + + file.close(); +} + +// -------------------------------------- +void HTML::locateTo(const char *url) +{ + out->writeLine(HTTP_SC_FOUND); + out->writeLineF("Location: %s",url); + out->writeLine(""); +} +// -------------------------------------- +void HTML::startHTML() +{ + startNode("html"); +} +// -------------------------------------- +void HTML::startBody() +{ + startNode("body"); +} +// -------------------------------------- +void HTML::addHead() +{ + char buf[512]; + startNode("head"); + startTagEnd("title",title.cstr()); + startTagEnd("meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\""); + + if (!refreshURL.isEmpty()) + { + sprintf(buf,"meta http-equiv=\"refresh\" content=\"%d;URL=%s\"",refresh,refreshURL.cstr()); + startTagEnd(buf); + }else if (refresh) + { + sprintf(buf,"meta http-equiv=\"refresh\" content=\"%d\"",refresh); + startTagEnd(buf); + } + + + end(); +} +// -------------------------------------- +void HTML::addContent(const char *s) +{ + out->writeString(s); +} +// -------------------------------------- +void HTML::startNode(const char *tag, const char *data) +{ + const char *p = tag; + char *o = &currTag[tagLevel][0]; + + int i; + for(i=0; iwriteString("<"); + out->writeString(tag); + out->writeString(">"); + if (data) + out->writeString(data); + + tagLevel++; + if (tagLevel >= MAX_TAGLEVEL) + throw StreamException("HTML too deep!"); +} +// -------------------------------------- +void HTML::end() +{ + tagLevel--; + if (tagLevel < 0) + throw StreamException("HTML premature end!"); + + out->writeString("writeString(&currTag[tagLevel][0]); + out->writeString(">"); +} +// -------------------------------------- +void HTML::addLink(const char *url, const char *text, bool toblank) +{ + char buf[1024]; + + sprintf(buf,"a href=\"%s\" %s",url,toblank?"target=\"_blank\"":""); + startNode(buf,text); + end(); +} +// -------------------------------------- +void HTML::startTag(const char *tag, const char *fmt,...) +{ + if (fmt) + { + + va_list ap; + va_start(ap, fmt); + + char tmp[512]; + vsprintf(tmp,fmt,ap); + startNode(tag,tmp); + + va_end(ap); + }else{ + startNode(tag,NULL); + } +} +// -------------------------------------- +void HTML::startTagEnd(const char *tag, const char *fmt,...) +{ + if (fmt) + { + + va_list ap; + va_start(ap, fmt); + + char tmp[512]; + vsprintf(tmp,fmt,ap); + startNode(tag,tmp); + + va_end(ap); + }else{ + startNode(tag,NULL); + } + end(); +} +// -------------------------------------- +void HTML::startSingleTagEnd(const char *fmt,...) +{ + va_list ap; + va_start(ap, fmt); + + char tmp[512]; + vsprintf(tmp,fmt,ap); + startNode(tmp); + + va_end(ap); + end(); +} + +// -------------------------------------- +void HTML::startTableRow(int i) +{ + if (i & 1) + startTag("tr bgcolor=\"#dddddd\" align=\"left\""); + else + startTag("tr bgcolor=\"#eeeeee\" align=\"left\""); +} diff --git a/PeerCast.root/PeerCast/core/common/html.h b/PeerCast.root/PeerCast/core/common/html.h new file mode 100644 index 0000000..7f05c43 --- /dev/null +++ b/PeerCast.root/PeerCast/core/common/html.h @@ -0,0 +1,91 @@ +// ------------------------------------------------ +// File : html.h +// Date: 4-apr-2002 +// Author: giles +// Desc: +// +// (c) 2002 peercast.org +// ------------------------------------------------ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// ------------------------------------------------ + +#ifndef _HTML_H +#define _HTML_H + +// --------------------------------------- +#include "xml.h" +#include "sys.h" + +class FileStream; +class WriteBufferStream; + +// --------------------------------------- +class HTML +{ +public: + enum + { + MAX_TAGLEVEL = 64, + MAX_TAGLEN = 64 + }; + + enum + { + TMPL_UNKNOWN, + TMPL_LOOP, + TMPL_IF, + TMPL_ELSE, + TMPL_END + }; + + HTML(const char *,Stream &); + ~HTML(); + + void startNode(const char *, const char * = NULL); + void addLink(const char *, const char *, bool = false); + void startTag(const char *, const char * = NULL,...); + void startTagEnd(const char *, const char * = NULL,...); + void startSingleTagEnd(const char *,...); + void startTableRow(int); + void end(); + void setRefresh(int sec) {refresh = sec;} + void setRefreshURL(const char *u){refreshURL.set(u);} + void addHead(); + void startHTML(); + void startBody(); + + void locateTo(const char *); + void addContent(const char *); + + void writeOK(const char *); + void writeTemplate(const char *, const char *); + void writeRawFile(const char *); + void writeVariable(Stream &,const String &,int); + int getIntVariable(const String &,int); + bool getBoolVariable(const String &,int); + + + void readIf(Stream &,Stream *,int); + void readLoop(Stream &,Stream *,int); + void readVariable(Stream &,Stream *,int); + bool readTemplate(Stream &,Stream *,int); + int readCmd(Stream &,Stream *,int); + + + const char *tmplArgs; + String title,refreshURL; + char currTag[MAX_TAGLEVEL][MAX_TAGLEN]; + int tagLevel; + int refresh; + WriteBufferStream *out; +}; + +#endif diff --git a/PeerCast.root/PeerCast/core/common/http.cpp b/PeerCast.root/PeerCast/core/common/http.cpp new file mode 100644 index 0000000..95f4df4 --- /dev/null +++ b/PeerCast.root/PeerCast/core/common/http.cpp @@ -0,0 +1,192 @@ +// ------------------------------------------------ +// File : http.cpp +// Date: 4-apr-2002 +// Author: giles +// Desc: +// HTTP protocol handling +// +// (c) 2002 peercast.org +// ------------------------------------------------ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// ------------------------------------------------ + + +#include +#include "http.h" +#include "sys.h" +#include "common.h" +#ifdef _DEBUG +#include "chkMemoryLeak.h" +#define DEBUG_NEW new(__FILE__, __LINE__) +#define new DEBUG_NEW +#endif + +//----------------------------------------- +bool HTTP::checkResponse(int r) +{ + if (readResponse()!=r) + { + LOG_ERROR("Unexpected HTTP: %s",cmdLine); + throw StreamException("Unexpected HTTP response"); + return false; + } + + return true; +} +//----------------------------------------- +void HTTP::readRequest() +{ + readLine(cmdLine,sizeof(cmdLine)); +} +//----------------------------------------- +int HTTP::readResponse() +{ + readLine(cmdLine,sizeof(cmdLine)); + + char *cp = cmdLine; + + while (*cp) if (*++cp == ' ') break; + while (*cp) if (*++cp != ' ') break; + + char *scp = cp; + + while (*cp) if (*++cp == ' ') break; + *cp = 0; + + return atoi(scp); +} + +//----------------------------------------- +bool HTTP::nextHeader() +{ + if (readLine(cmdLine,sizeof(cmdLine))) + { + char *ap = strstr(cmdLine,":"); + if (ap) + while (*++ap) + if (*ap!=' ') + break; + arg = ap; + return true; + }else + { + arg = NULL; + return false; + } + +} +//----------------------------------------- +bool HTTP::isHeader(const char *hs) +{ + return stristr(cmdLine,hs) != NULL; +} +//----------------------------------------- +bool HTTP::isRequest(const char *rq) +{ + return strncmp(cmdLine,rq,strlen(rq)) == 0; +} +//----------------------------------------- +char *HTTP::getArgStr() +{ + return arg; +} +//----------------------------------------- +int HTTP::getArgInt() +{ + if (arg) + return atoi(arg); + else + return 0; +} +//----------------------------------------- +void HTTP::getAuthUserPass(char *user, char *pass) +{ + if (arg) + { + char *s = stristr(arg,"Basic"); + if (s) + { + while (*s) + if (*s++ == ' ') + break; + String str; + str.set(s,String::T_BASE64); + str.convertTo(String::T_ASCII); + s = strstr(str.cstr(),":"); + if (s) + { + *s = 0; + if (user) + strcpy(user,str.cstr()); + if (pass) + strcpy(pass,s+1); + } + } + } +} +// ----------------------------------- +void CookieList::init() +{ + for(int i=0; igetTime(); + list[oldestIndex]=c; + return true; +} +// ----------------------------------- +void CookieList::remove(Cookie &c) +{ + for(int i=0; isock) + throw StreamException("ICY channel has no socket"); + + ch->resetPlayTime(); + + ch->setStatus(Channel::S_BROADCASTING); + source = ch->createSource(); + ch->readStream(*ch->sock,source); + + }catch(StreamException &e) + { + LOG_ERROR("Channel aborted: %s",e.msg); + } + + + ch->setStatus(Channel::S_CLOSING); + + if (ch->sock) + { + ch->sock->close(); + delete ch->sock; + ch->sock = NULL; + } + + if (source) + delete source; + +} diff --git a/PeerCast.root/PeerCast/core/common/icy.h b/PeerCast.root/PeerCast/core/common/icy.h new file mode 100644 index 0000000..aec507d --- /dev/null +++ b/PeerCast.root/PeerCast/core/common/icy.h @@ -0,0 +1,35 @@ +// ------------------------------------------------ +// File : icy.h +// Date: 20-feb-2004 +// Author: giles +// +// (c) 2002-4 peercast.org +// ------------------------------------------------ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// ------------------------------------------------ + +#ifndef _ICY_H +#define _ICY_H + +#include "channel.h" + +// ------------------------------------------------ +class ICYSource : public ChannelSource +{ +public: + virtual void stream(Channel *); + +}; + + + + +#endif diff --git a/PeerCast.root/PeerCast/core/common/id.h b/PeerCast.root/PeerCast/core/common/id.h new file mode 100644 index 0000000..8052820 --- /dev/null +++ b/PeerCast.root/PeerCast/core/common/id.h @@ -0,0 +1,101 @@ +#ifndef _ID_H +#define _ID_H + +#include + +// --------------------------------------------------- +class IDString +{ +private: + enum + { + LENGTH = 31 + }; + + char data[LENGTH+1]; +public: + IDString(const char *id,int cnt) + { + if (cnt >= LENGTH) + cnt=LENGTH; + int i; + for(i=0; i + * 2001/10/14 First version + * Kazuhiko Iwama + * + */ + +#include +#include +#include +#include +#include "identify_encoding.h" + +enum encoding_id +{ + eid_KNOWN = 0, + eid_ASCII = 1, + eid_JIS = 2, + eid_SJIS = 3, + eid_EUCJP = 4, + eid_UTF8 = 5 +}; + +const char *encoding_str[] = +{ + "KNOWN", "ASCII", "ISO-2022-JP", "SJIS", "EUC-JP", "UTF-8" +}; + +static int +is_ascii(ie_state_t *st, const unsigned char *p) +{ + if (!(isprint(*p) || isspace(*p)) || *p >= 0x80) + st->flag = 0; + return st->flag; +} + +static int +is_jis(ie_state_t *st, const unsigned char *p) +{ + if (*p >= 0x80) + st->flag = 0; + return st->flag; +} + +static int +is_sjis(ie_state_t *st, const unsigned char *p) +{ + switch (st->state) + { + case 0: + st->c_type = 0; + if (*p >= 0x80) + { + st->state = 1; + if (*p >= 0x81 && *p <= 0x9f) st->c_type = 1; + else if (*p >= 0xe0 && *p <= 0xef) st->c_type = 1; + else if (*p >= 0xa1 && *p <= 0xdf) st->state = 0; + else st->flag = 1; + } + break; + case 1: + if (*p >= 0x40 && *p <= 0x7e) st->state = 0; + else if (*p >= 0x80 && *p <= 0xfc) st->state = 0; + else st->flag = 0; + break; + default: + st->flag = 0; + break; + } + + return st->flag; +} + +static int +is_eucjp(ie_state_t *st, const unsigned char *p) +{ + switch (st->state) + { + case 0: + st->c_type = 0; + if (*p >= 0x80) + { + st->state = 1; + if (*p >= 0xa1 && *p <= 0xfe) st->c_type = 1; + else if (*p == 0x8e ) st->c_type = 2; + else if (*p == 0x8f ) st->c_type = 3; + else st->flag = 0; + } + break; + case 1: + switch (st->c_type) + { + case 1: + if (*p >= 0xa1 && *p <= 0xfe) st->state = 0; + else st->flag = 0; + break; + case 2: + if (*p >= 0x81 && *p <= 0xff) st->state = 0; + else st->flag = 0; + break; + case 3: + if (*p >= 0x81 && *p <= 0xff) st->state = 2; + else st->flag = 0; + break; + default: + st->flag = 0; + break; + } + break; + case 2: + if (*p >= 0x81 && *p <= 0xff) st->state = 0; + else st->flag = 0; + default: + st->flag = 0; + break; + } + + return st->flag; +} + +static int +is_utf8(ie_state_t *st, const unsigned char *p) +{ + switch (st->state) + { + case 0: + st->c_type = 0; + if (*p >= 0x80) + { + st->state = 1; + if (*p >= 0xc2 && *p <= 0xdf) st->c_type = 1; + else if (*p == 0xe0 ) st->c_type = 2; + else if (*p >= 0xe1 && *p <= 0xef) st->c_type = 3; + else if (*p == 0xf0 ) st->c_type = 4; + else if (*p >= 0xf1 && *p <= 0xf3) st->c_type = 5; + else if (*p == 0xf4 ) st->c_type = 6; + else st->flag = 0; + } + break; + case 1: + switch (st->c_type) + { + case 1: + if (*p >= 0x80 && *p <= 0xbf) st->state = 0; + else st->flag = 0; + break; + case 2: + if (*p >= 0xa0 && *p <= 0xbf) st->state = 2; + else st->flag = 0; + break; + case 3: + if (*p >= 0x80 && *p <= 0xbf) st->state = 2; + else st->flag = 0; + break; + case 4: + if (*p >= 0x90 && *p <= 0xbf) st->state = 2; + else st->flag = 0; + break; + case 5: + if (*p >= 0x80 && *p <= 0xbf) st->state = 2; + else st->flag = 0; + break; + case 6: + if (*p >= 0x80 && *p <= 0x8f) st->state = 2; + else st->flag = 0; + break; + default: + st->flag = 0; + break; + } + break; + case 2: + if (st->c_type >= 2 && st->c_type <= 3) + { + if (*p >= 0x80 && *p <= 0xbf) st->state = 0; + else st->flag = 0; + }else if (st->c_type >= 4 && st->c_type <= 6) + { + if (*p >= 0x80 && *p <= 0xbf) st->state = 3; + else st->flag = 0; + }else{ + st->flag = 0; + } + break; + case 3: + if (st->c_type >= 4 && st->c_type <= 6) + { + if (*p >= 0x80 && *p <= 0xbf) st->state = 0; + else st->flag = 0; + }else{ + st->flag = 0; + } + break; + default: + st->flag = 0; + break; + } + + return st->flag; +} + +identify_encoding_t* +identify_encoding_open(enum identify_encoding_order order) +{ + identify_encoding_t* cd; + cd = (identify_encoding_t*)malloc(sizeof(identify_encoding_t)); + + if (cd == NULL) + { + cd = (identify_encoding_t*)(-1); + }else{ + cd->order = order; + identify_encoding_reset(cd); + } + return cd; +} + +void +identify_encoding_close(identify_encoding_t* cd) +{ + if (cd != (identify_encoding_t*)(-1) || cd != NULL) + { + free(cd); + } +} + +static void +identify_encoding_reset_state(ie_state_t* st) +{ + st->flag = 1; + st->state = 0; + st->c_type = 0; +} + +void +identify_encoding_reset(identify_encoding_t* cd) +{ + identify_encoding_reset_state(&(cd->st_ascii)); + identify_encoding_reset_state(&(cd->st_jis)); + identify_encoding_reset_state(&(cd->st_sjis)); + identify_encoding_reset_state(&(cd->st_eucjp)); + identify_encoding_reset_state(&(cd->st_utf8)); +} + +const char* +identify_encoding(identify_encoding_t *cd, char* instr) +{ + int n; + unsigned char *p; + enum encoding_id eid = eid_KNOWN; + + identify_encoding_reset(cd); + + for (n = 0, p = (unsigned char *)instr; *p != '\0' && n < IDENTIFY_MAX_LENGTH; p++, n++) + { + if (cd->st_ascii.flag == 1) is_ascii(&(cd->st_ascii), p); + if (cd->st_jis.flag == 1) is_jis(&(cd->st_jis), p); + if (cd->st_sjis.flag == 1) is_sjis(&(cd->st_sjis), p); + if (cd->st_eucjp.flag == 1) is_eucjp(&(cd->st_eucjp), p); + if (cd->st_utf8.flag == 1) is_utf8(&(cd->st_utf8), p); + } + + if (cd->st_ascii.flag == 1) eid = eid_ASCII; + else if (cd->st_jis.flag == 1) eid = eid_JIS; + else if (cd->st_utf8.flag == 1) eid = eid_UTF8; + else if (cd->order == ieo_EUCJP) + { + if (cd->st_eucjp.flag == 1) eid = eid_EUCJP; + else if (cd->st_sjis.flag == 1) eid = eid_SJIS; + }else{ + if (cd->st_sjis.flag == 1) eid = eid_SJIS; + else if (cd->st_eucjp.flag == 1) eid = eid_EUCJP; + } + + return encoding_str[ eid ]; +} diff --git a/PeerCast.root/PeerCast/core/common/identify_encoding.h b/PeerCast.root/PeerCast/core/common/identify_encoding.h new file mode 100644 index 0000000..5ccaf72 --- /dev/null +++ b/PeerCast.root/PeerCast/core/common/identify_encoding.h @@ -0,0 +1,42 @@ +/* + * + * Š¿ŽšƒR[ƒh‚Ì”»•Ê‚µAiconv —p‚Ì•¶ŽšƒGƒ“ƒR[ƒfƒBƒ“ƒO•¶Žš—ñ‚ð•Ô‚· + * + * 2001/10/24 Remove static variables + * Kazuhiko Iwama + * 2001/10/14 First version + * Kazuhiko Iwama + * + */ + +#ifndef IDENTIFY_ENCODING_H +#define IDENTIFY_ENCODING_H + +#define IDENTIFY_MAX_LENGTH 256 + +enum identify_encoding_order { + ieo_EUCJP = 0, + ieo_SJIS = 1 +}; + +typedef struct { + int flag; + int state; + int c_type; +} ie_state_t; + +typedef struct { + enum identify_encoding_order order; + ie_state_t st_ascii; + ie_state_t st_jis; + ie_state_t st_sjis; + ie_state_t st_eucjp; + ie_state_t st_utf8; +} identify_encoding_t; + +identify_encoding_t* identify_encoding_open(enum identify_encoding_order order); +void identify_encoding_close(identify_encoding_t* cd); +void identify_encoding_reset(identify_encoding_t* cd); +const char *identify_encoding(identify_encoding_t *cd, char* instr); + +#endif diff --git a/PeerCast.root/PeerCast/core/common/inifile.cpp b/PeerCast.root/PeerCast/core/common/inifile.cpp new file mode 100644 index 0000000..965f2a9 --- /dev/null +++ b/PeerCast.root/PeerCast/core/common/inifile.cpp @@ -0,0 +1,168 @@ +// ------------------------------------------------ +// File : inifile.cpp +// Date: 4-apr-2002 +// Author: giles +// Desc: +// .INI file reading/writing class +// +// (c) 2002 peercast.org +// ------------------------------------------------ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// ------------------------------------------------ + +#include +#include "inifile.h" +#include "sys.h" +#ifdef _DEBUG +#include "chkMemoryLeak.h" +#define DEBUG_NEW new(__FILE__, __LINE__) +#define new DEBUG_NEW +#endif + + + void openReadOnly(const char *); + void openWriteReplace(const char *); +// ----------------------------------------- +bool IniFile::openReadOnly(const char *fn) +{ + try + { + fStream.openReadOnly(fn); + }catch(StreamException &) + { + return false; + } + return true; +} +// ----------------------------------------- +bool IniFile::openWriteReplace(const char *fn) +{ + try + { + fStream.openWriteReplace(fn); +#if defined(_LINUX) || defined(__APPLE__) + fStream.writeCRLF = false; +#endif + + }catch(StreamException &) + { + return false; + } + return true; +} +// ----------------------------------------- +void IniFile::close() +{ + fStream.close(); +} + + +// ----------------------------------------- +bool IniFile::readNext() +{ + if (fStream.eof()) + return false; + + try + { + fStream.readLine(currLine,256); + }catch(StreamException &) + { + return false; + } + + + // find end of value name and null terminate + char *nend = strstr(currLine,"="); + + if (nend) + { + *nend = 0; + valueStr = trimstr(nend+1); + }else + valueStr = NULL; + + nameStr = trimstr(currLine); + + return true; +} +// ----------------------------------------- +bool IniFile::isName(const char *str) +{ + return stricmp(getName(),str)==0; +} + +// ----------------------------------------- +char * IniFile::getName() +{ + return nameStr; +} +// ----------------------------------------- +int IniFile::getIntValue() +{ + if (valueStr) + return atoi(valueStr); + else + return 0; +} +// ----------------------------------------- +char * IniFile::getStrValue() +{ + if (valueStr) + return valueStr; + else + return ""; +} +// ----------------------------------------- +bool IniFile::getBoolValue() +{ + if (!valueStr) + return false; + + + if ( (stricmp(valueStr,"yes")==0) || + (stricmp(valueStr,"y")==0) || + (stricmp(valueStr,"1")==0) ) + return true; + + return false; +} + +// ----------------------------------------- +void IniFile::writeIntValue(const char *name, int iv) +{ + sprintf(currLine,"%s = %d",name,iv); + fStream.writeLine(currLine); +} +// ----------------------------------------- +void IniFile::writeStrValue(const char *name, const char *sv) +{ + sprintf(currLine,"%s = %s",name,sv); + fStream.writeLine(currLine); +} +// ----------------------------------------- +void IniFile::writeSection(const char *name) +{ + fStream.writeLine(""); + sprintf(currLine,"[%s]",name); + fStream.writeLine(currLine); +} +// ----------------------------------------- +void IniFile::writeBoolValue(const char *name, int v) +{ + sprintf(currLine,"%s = %s",name,(v!=0)?"Yes":"No"); + fStream.writeLine(currLine); +} +// ----------------------------------------- +void IniFile::writeLine(const char *str) +{ + fStream.writeLine(str); +} diff --git a/PeerCast.root/PeerCast/core/common/inifile.h b/PeerCast.root/PeerCast/core/common/inifile.h new file mode 100644 index 0000000..2b75cca --- /dev/null +++ b/PeerCast.root/PeerCast/core/common/inifile.h @@ -0,0 +1,53 @@ +// ------------------------------------------------ +// File : inifile.h +// Date: 4-apr-2002 +// Author: giles +// Desc: +// +// (c) 2002 peercast.org +// ------------------------------------------------ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// ------------------------------------------------ + +#ifndef _INIFILE +#define _INIFILE + +#include "stream.h" + +// ----------------------------------------- +class IniFile +{ +public: + bool openReadOnly(const char *); + bool openWriteReplace(const char *); + void close(); + + bool readNext(); + + bool isName(const char *); + char * getName(); + int getIntValue(); + char * getStrValue(); + bool getBoolValue(); + + void writeSection(const char *); + void writeIntValue(const char *, int); + void writeStrValue(const char *, const char *); + void writeBoolValue(const char *, int); + void writeLine(const char *); + + + FileStream fStream; + char currLine[256]; + char *nameStr,*valueStr; +}; + +#endif diff --git a/PeerCast.root/PeerCast/core/common/jis.cpp b/PeerCast.root/PeerCast/core/common/jis.cpp new file mode 100644 index 0000000..1ce75f2 --- /dev/null +++ b/PeerCast.root/PeerCast/core/common/jis.cpp @@ -0,0 +1,755 @@ +// ------------------------------------------------ +// File : jis.cpp +// Date: 1-april-2004 +// Author: giles +// +// ShiftJIS/EUC to Unicode conversions +// (modified version of program by Y. Kuno, see below) +// +// +// (c) 2002-4 peercast.org +// ------------------------------------------------ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// ------------------------------------------------ + + + +/* J2Uc.c --- written by Y. Kuno, July 1996. */ +/* Compile with -DSJIS if you want to convert from SJIS; otherwise */ +/* EUC-JP is assumed. */ +/* We are thankful to following people for permitting us free use */ +/* of the following materials. */ +/* * Itaru Ichikawa (Fujitsu) --- nkf 1.4 source code. */ +/* * Glenn Adams (Unicode Inc.) --- JISx0208 to Unicode mapping table. */ +/* This source code can freely be used, distributed, modified provided */ +/* that this credit is also included in the source code. */ + +// ----------------------------------- + +#include "jis.h" +#ifdef _DEBUG +#include "chkMemoryLeak.h" +#define DEBUG_NEW new(__FILE__, __LINE__) +#define new DEBUG_NEW +#endif + + +// ----------------------------------- + +#define SJ0162 0x00e1 /* 01 - 62 ku offset */ +#define SJ6394 0x0161 /* 63 - 94 ku offset */ + + +// ----------------------------------- +static unsigned short uniTable[94][94] = { +{12288,12289,12290,65292,65294,12539,65306,65307,65311,65281,12443,12444, + 180,65344,168,65342,65507,65343,12541,12542,12445,12446,12291,20189, + 12293,12294,12295,12540,8213,8208,65295,92,12316,8214,65372,8230, + 8229,8216,8217,8220,8221,65288,65289,12308,12309,65339,65341,65371, + 65373,12296,12297,12298,12299,12300,12301,12302,12303,12304,12305,65291, + 8722,177,215,247,65309,8800,65308,65310,8806,8807,8734,8756, + 9794,9792,176,8242,8243,8451,65509,65284,162,163,65285,65283, + 65286,65290,65312,167,9734,9733,9675,9679,9678,9671,}, +{9670,9633,9632,9651,9650,9661,9660,8251,12306,8594,8592,8593, + 8595,12307,0,0,0,0,0,0,0,0,0,0,0,8712,8715,8838,8839,8834,8835, + 8746,8745,0,0,0,0,0,0,0,0,8743,8744,172,8658,8660,8704,8707,0,0, + 0,0,0,0,0,0,0,0,0,8736,8869,8978,8706,8711,8801,8786,8810,8811, + 8730,8765,8733,8757,8747,8748,0,0,0,0,0,0,0,8491,8240,9839,9837, + 9834,8224,8225,182,0,0,0,0,9711,}, +{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,65296,65297,65298,65299,65300,65301,65302, + 65303,65304,65305,0,0,0,0,0,0,0,65313,65314,65315,65316,65317,65318,65319, + 65320,65321,65322,65323,65324,65325,65326,65327,65328,65329,65330,65331, + 65332,65333,65334,65335,65336,65337,65338,0,0,0,0,0,0,65345,65346,65347, + 65348,65349,65350,65351,65352,65353,65354,65355,65356,65357,65358,65359, + 65360,65361,65362,65363,65364,65365,65366,65367,65368,65369,65370,0,0,0,0,}, +{12353,12354,12355,12356,12357,12358,12359,12360,12361,12362,12363,12364, + 12365,12366,12367,12368,12369,12370,12371,12372,12373,12374,12375,12376, + 12377,12378,12379,12380,12381,12382,12383,12384,12385,12386,12387,12388, + 12389,12390,12391,12392,12393,12394,12395,12396,12397,12398,12399,12400, + 12401,12402,12403,12404,12405,12406,12407,12408,12409,12410,12411,12412, + 12413,12414,12415,12416,12417,12418,12419,12420,12421,12422,12423,12424, + 12425,12426,12427,12428,12429,12430,12431,12432,12433,12434,12435,0,0,0,0, + 0,0,0,0,0,0,0,}, +{12449,12450,12451,12452,12453,12454,12455,12456,12457,12458,12459,12460, + 12461,12462,12463,12464,12465,12466,12467,12468,12469,12470,12471,12472, + 12473,12474,12475,12476,12477,12478,12479,12480,12481,12482,12483,12484, + 12485,12486,12487,12488,12489,12490,12491,12492,12493,12494,12495,12496, + 12497,12498,12499,12500,12501,12502,12503,12504,12505,12506,12507,12508, + 12509,12510,12511,12512,12513,12514,12515,12516,12517,12518,12519,12520, + 12521,12522,12523,12524,12525,12526,12527,12528,12529,12530,12531,12532, + 12533,12534,0,0,0,0,0,0,0,0,}, +{913,914,915,916,917,918,919,920,921,922,923,924, + 925,926,927,928,929,931,932,933,934,935,936,937,0, + 0,0,0,0,0,0,0,945,946,947,948,949,950,951,952,953,954, + 955,956,957,958,959,960,961,963,964,965,966,967, + 968,969,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,}, +{1040,1041,1042,1043,1044,1045,1025,1046,1047,1048,1049,1050, + 1051,1052,1053,1054,1055,1056,1057,1058,1059,1060,1061,1062, + 1063,1064,1065,1066,1067,1068,1069,1070,1071,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,1072,1073,1074,1075,1076,1077,1105,1078,1079,1080, + 1081,1082,1083,1084,1085,1086,1087,1088,1089,1090,1091,1092, + 1093,1094,1095,1096,1097,1098,1099,1100,1101,1102,1103,0,0,0,0, + 0,0,0,0,0,0,0,0,0,}, +{9472,9474,9484,9488,9496,9492,9500,9516,9508,9524,9532,9473, + 9475,9487,9491,9499,9495,9507,9523,9515,9531,9547,9504,9519, + 9512,9527,9535,9501,9520,9509,9528,9538,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,}, +{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,}, +{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,}, +{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,}, +{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,}, +{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,}, +{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,}, +{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,}, +{20124,21782,23043,38463,21696,24859,25384,23030,36898,33909,33564,31312, + 24746,25569,28197,26093,33894,33446,39925,26771,22311,26017,25201,23451, + 22992,34427,39156,32098,32190,39822,25110,31903,34999,23433,24245,25353, + 26263,26696,38343,38797,26447,20197,20234,20301,20381,20553,22258,22839, + 22996,23041,23561,24799,24847,24944,26131,26885,28858,30031,30064,31227, + 32173,32239,32963,33806,34915,35586,36949,36986,21307,20117,20133,22495, + 32946,37057,30959,19968,22769,28322,36920,31282,33576,33419,39983,20801, + 21360,21693,21729,22240,23035,24341,39154,28139,32996,34093,}, +{38498,38512,38560,38907,21515,21491,23431,28879,32701,36802,38632,21359, + 40284,31418,19985,30867,33276,28198,22040,21764,27421,34074,39995,23013, + 21417,28006,29916,38287,22082,20113,36939,38642,33615,39180,21473,21942, + 23344,24433,26144,26355,26628,27704,27891,27945,29787,30408,31310,38964, + 33521,34907,35424,37613,28082,30123,30410,39365,24742,35585,36234,38322, + 27022,21421,20870,22290,22576,22852,23476,24310,24616,25513,25588,27839, + 28436,28814,28948,29017,29141,29503,32257,33398,33489,34199,36960,37467, + 40219,22633,26044,27738,29989,20985,22830,22885,24448,24540,}, +{25276,26106,27178,27431,27572,29579,32705,35158,40236,40206,40644,23713, + 27798,33659,20740,23627,25014,33222,26742,29281,20057,20474,21368,24681, + 28201,31311,38899,19979,21270,20206,20309,20285,20385,20339,21152,21487, + 22025,22799,23233,23478,23521,31185,26247,26524,26550,27468,27827,28779, + 29634,31117,31166,31292,31623,33457,33499,33540,33655,33775,33747,34662, + 35506,22057,36008,36838,36942,38686,34442,20420,23784,25105,29273,30011, + 33253,33469,34558,36032,38597,39187,39381,20171,20250,35299,22238,22602, + 22730,24315,24555,24618,24724,24674,25040,25106,25296,25913,}, +{39745,26214,26800,28023,28784,30028,30342,32117,33445,34809,38283,38542, + 35997,20977,21182,22806,21683,23475,23830,24936,27010,28079,30861,33995, + 34903,35442,37799,39608,28012,39336,34521,22435,26623,34510,37390,21123, + 22151,21508,24275,25313,25785,26684,26680,27579,29554,30906,31339,35226, + 35282,36203,36611,37101,38307,38548,38761,23398,23731,27005,38989,38990, + 25499,31520,27179,27263,26806,39949,28511,21106,21917,24688,25324,27963, + 28167,28369,33883,35088,36676,19988,39993,21494,26907,27194,38788,26666, + 20828,31427,33970,37340,37772,22107,40232,26658,33541,33841,}, +{31909,21000,33477,29926,20094,20355,20896,23506,21002,21208,21223,24059, + 21914,22570,23014,23436,23448,23515,24178,24185,24739,24863,24931,25022, + 25563,25954,26577,26707,26874,27454,27475,27735,28450,28567,28485,29872, + 29976,30435,30475,31487,31649,31777,32233,32566,32752,32925,33382,33694, + 35251,35532,36011,36996,37969,38291,38289,38306,38501,38867,39208,33304, + 20024,21547,23736,24012,29609,30284,30524,23721,32747,36107,38593,38929, + 38996,39000,20225,20238,21361,21916,22120,22522,22855,23305,23492,23696, + 24076,24190,24524,25582,26426,26071,26082,26399,26827,26820,}, +{27231,24112,27589,27671,27773,30079,31048,23395,31232,32000,24509,35215, + 35352,36020,36215,36556,36637,39138,39438,39740,20096,20605,20736,22931, + 23452,25135,25216,25836,27450,29344,30097,31047,32681,34811,35516,35696, + 25516,33738,38816,21513,21507,21931,26708,27224,35440,30759,26485,40653, + 21364,23458,33050,34384,36870,19992,20037,20167,20241,21450,21560,23470, + 24339,24613,25937,26429,27714,27762,27875,28792,29699,31350,31406,31496, + 32026,31998,32102,26087,29275,21435,23621,24040,25298,25312,25369,28192, + 34394,35377,36317,37624,28417,31142,39770,20136,20139,20140,}, +{20379,20384,20689,20807,31478,20849,20982,21332,21281,21375,21483,21932, + 22659,23777,24375,24394,24623,24656,24685,25375,25945,27211,27841,29378, + 29421,30703,33016,33029,33288,34126,37111,37857,38911,39255,39514,20208, + 20957,23597,26241,26989,23616,26354,26997,29577,26704,31873,20677,21220, + 22343,24062,37670,26020,27427,27453,29748,31105,31165,31563,32202,33465, + 33740,34943,35167,35641,36817,37329,21535,37504,20061,20534,21477,21306, + 29399,29590,30697,33510,36527,39366,39368,39378,20855,24858,34398,21936, + 31354,20598,23507,36935,38533,20018,27355,37351,23633,23624,}, +{25496,31391,27795,38772,36705,31402,29066,38536,31874,26647,32368,26705, + 37740,21234,21531,34219,35347,32676,36557,37089,21350,34952,31041,20418, + 20670,21009,20804,21843,22317,29674,22411,22865,24418,24452,24693,24950, + 24935,25001,25522,25658,25964,26223,26690,28179,30054,31293,31995,32076, + 32153,32331,32619,33550,33610,34509,35336,35427,35686,36605,38938,40335, + 33464,36814,39912,21127,25119,25731,28608,38553,26689,20625,27424,27770, + 28500,31348,32080,34880,35363,26376,20214,20537,20518,20581,20860,21048, + 21091,21927,22287,22533,23244,24314,25010,25080,25331,25458,}, +{26908,27177,29309,29356,29486,30740,30831,32121,30476,32937,35211,35609, + 36066,36562,36963,37749,38522,38997,39443,40568,20803,21407,21427,24187, + 24358,28187,28304,29572,29694,32067,33335,35328,35578,38480,20046,20491, + 21476,21628,22266,22993,23396,24049,24235,24359,25144,25925,26543,28246, + 29392,31946,34996,32929,32993,33776,34382,35463,36328,37431,38599,39015, + 40723,20116,20114,20237,21320,21577,21566,23087,24460,24481,24735,26791, + 27278,29786,30849,35486,35492,35703,37264,20062,39881,20132,20348,20399, + 20505,20502,20809,20844,21151,21177,21246,21402,21475,21521,}, +{21518,21897,22353,22434,22909,23380,23389,23439,24037,24039,24055,24184, + 24195,24218,24247,24344,24658,24908,25239,25304,25511,25915,26114,26179, + 26356,26477,26657,26775,27083,27743,27946,28009,28207,28317,30002,30343, + 30828,31295,31968,32005,32024,32094,32177,32789,32771,32943,32945,33108, + 33167,33322,33618,34892,34913,35611,36002,36092,37066,37237,37489,30783, + 37628,38308,38477,38917,39321,39640,40251,21083,21163,21495,21512,22741, + 25335,28640,35946,36703,40633,20811,21051,21578,22269,31296,37239,40288, + 40658,29508,28425,33136,29969,24573,24794,39592,29403,36796,}, +{27492,38915,20170,22256,22372,22718,23130,24680,25031,26127,26118,26681, + 26801,28151,30165,32058,33390,39746,20123,20304,21449,21766,23919,24038, + 24046,26619,27801,29811,30722,35408,37782,35039,22352,24231,25387,20661, + 20652,20877,26368,21705,22622,22971,23472,24425,25165,25505,26685,27507, + 28168,28797,37319,29312,30741,30758,31085,25998,32048,33756,35009,36617, + 38555,21092,22312,26448,32618,36001,20916,22338,38442,22586,27018,32948, + 21682,23822,22524,30869,40442,20316,21066,21643,25662,26152,26388,26613, + 31364,31574,32034,37679,26716,39853,31545,21273,20874,21047,}, +{23519,25334,25774,25830,26413,27578,34217,38609,30352,39894,25420,37638, + 39851,30399,26194,19977,20632,21442,23665,24808,25746,25955,26719,29158, + 29642,29987,31639,32386,34453,35715,36059,37240,39184,26028,26283,27531, + 20181,20180,20282,20351,21050,21496,21490,21987,22235,22763,22987,22985, + 23039,23376,23629,24066,24107,24535,24605,25351,25903,23388,26031,26045, + 26088,26525,27490,27515,27663,29509,31049,31169,31992,32025,32043,32930, + 33026,33267,35222,35422,35433,35430,35468,35566,36039,36060,38604,39164, + 27503,20107,20284,20365,20816,23383,23546,24904,25345,26178,}, +{27425,28363,27835,29246,29885,30164,30913,31034,32780,32819,33258,33940, + 36766,27728,40575,24335,35672,40235,31482,36600,23437,38635,19971,21489, + 22519,22833,23241,23460,24713,28287,28422,30142,36074,23455,34048,31712, + 20594,26612,33437,23649,34122,32286,33294,20889,23556,25448,36198,26012, + 29038,31038,32023,32773,35613,36554,36974,34503,37034,20511,21242,23610, + 26451,28796,29237,37196,37320,37675,33509,23490,24369,24825,20027,21462, + 23432,25163,26417,27530,29417,29664,31278,33131,36259,37202,39318,20754, + 21463,21610,23551,25480,27193,32172,38656,22234,21454,21608,}, +{23447,23601,24030,20462,24833,25342,27954,31168,31179,32066,32333,32722, + 33261,33311,33936,34886,35186,35728,36468,36655,36913,37195,37228,38598, + 37276,20160,20303,20805,21313,24467,25102,26580,27713,28171,29539,32294, + 37325,37507,21460,22809,23487,28113,31069,32302,31899,22654,29087,20986, + 34899,36848,20426,23803,26149,30636,31459,33308,39423,20934,24490,26092, + 26991,27529,28147,28310,28516,30462,32020,24033,36981,37255,38918,20966, + 21021,25152,26257,26329,28186,24246,32210,32626,26360,34223,34295,35576, + 21161,21465,22899,24207,24464,24661,37604,38500,20663,20767,}, +{21213,21280,21319,21484,21736,21830,21809,22039,22888,22974,23100,23477, + 23558,23567,23569,23578,24196,24202,24288,24432,25215,25220,25307,25484, + 25463,26119,26124,26157,26230,26494,26786,27167,27189,27836,28040,28169, + 28248,28988,28966,29031,30151,30465,30813,30977,31077,31216,31456,31505, + 31911,32057,32918,33750,33931,34121,34909,35059,35359,35388,35412,35443, + 35937,36062,37284,37478,37758,37912,38556,38808,19978,19976,19998,20055, + 20887,21104,22478,22580,22732,23330,24120,24773,25854,26465,26454,27972, + 29366,30067,31331,33976,35698,37304,37664,22065,22516,39166,}, +{25325,26893,27542,29165,32340,32887,33394,35302,39135,34645,36785,23611, + 20280,20449,20405,21767,23072,23517,23529,24515,24910,25391,26032,26187, + 26862,27035,28024,28145,30003,30137,30495,31070,31206,32051,33251,33455, + 34218,35242,35386,36523,36763,36914,37341,38663,20154,20161,20995,22645, + 22764,23563,29978,23613,33102,35338,36805,38499,38765,31525,35535,38920, + 37218,22259,21416,36887,21561,22402,24101,25512,27700,28810,30561,31883, + 32736,34928,36930,37204,37648,37656,38543,29790,39620,23815,23913,25968, + 26530,36264,38619,25454,26441,26905,33733,38935,38592,35070,}, +{28548,25722,23544,19990,28716,30045,26159,20932,21046,21218,22995,24449, + 24615,25104,25919,25972,26143,26228,26866,26646,27491,28165,29298,29983, + 30427,31934,32854,22768,35069,35199,35488,35475,35531,36893,37266,38738, + 38745,25993,31246,33030,38587,24109,24796,25114,26021,26132,26512,30707, + 31309,31821,32318,33034,36012,36196,36321,36447,30889,20999,25305,25509, + 25666,25240,35373,31363,31680,35500,38634,32118,33292,34633,20185,20808, + 21315,21344,23459,23554,23574,24029,25126,25159,25776,26643,26676,27849, + 27973,27927,26579,28508,29006,29053,26059,31359,31661,32218,}, +{32330,32680,33146,33307,33337,34214,35438,36046,36341,36984,36983,37549, + 37521,38275,39854,21069,21892,28472,28982,20840,31109,32341,33203,31950, + 22092,22609,23720,25514,26366,26365,26970,29401,30095,30094,30990,31062, + 31199,31895,32032,32068,34311,35380,38459,36961,40736,20711,21109,21452, + 21474,20489,21930,22766,22863,29245,23435,23652,21277,24803,24819,25436, + 25475,25407,25531,25805,26089,26361,24035,27085,27133,28437,29157,20105, + 30185,30456,31379,31967,32207,32156,32865,33609,33624,33900,33980,34299, + 35013,36208,36865,36973,37783,38684,39442,20687,22679,24974,}, +{33235,34101,36104,36896,20419,20596,21063,21363,24687,25417,26463,28204, + 36275,36895,20439,23646,36042,26063,32154,21330,34966,20854,25539,23384, + 23403,23562,25613,26449,36956,20182,22810,22826,27760,35409,21822,22549, + 22949,24816,25171,26561,33333,26965,38464,39364,39464,20307,22534,23550, + 32784,23729,24111,24453,24608,24907,25140,26367,27888,28382,32974,33151, + 33492,34955,36024,36864,36910,38538,40667,39899,20195,21488,22823,31532, + 37261,38988,40441,28381,28711,21331,21828,23429,25176,25246,25299,27810, + 28655,29730,35351,37944,28609,35582,33592,20967,34552,21482,}, +{21481,20294,36948,36784,22890,33073,24061,31466,36799,26842,35895,29432, + 40008,27197,35504,20025,21336,22022,22374,25285,25506,26086,27470,28129, + 28251,28845,30701,31471,31658,32187,32829,32966,34507,35477,37723,22243, + 22727,24382,26029,26262,27264,27573,30007,35527,20516,30693,22320,24347, + 24677,26234,27744,30196,31258,32622,33268,34584,36933,39347,31689,30044, + 31481,31569,33988,36880,31209,31378,33590,23265,30528,20013,20210,23449, + 24544,25277,26172,26609,27880,34411,34935,35387,37198,37619,39376,27159, + 28710,29482,33511,33879,36015,19969,20806,20939,21899,23541,}, +{24086,24115,24193,24340,24373,24427,24500,25074,25361,26274,26397,28526, + 29266,30010,30522,32884,33081,33144,34678,35519,35548,36229,36339,37530, + 38263,38914,40165,21189,25431,30452,26389,27784,29645,36035,37806,38515, + 27941,22684,26894,27084,36861,37786,30171,36890,22618,26626,25524,27131, + 20291,28460,26584,36795,34086,32180,37716,26943,28528,22378,22775,23340, + 32044,29226,21514,37347,40372,20141,20302,20572,20597,21059,35998,21576, + 22564,23450,24093,24213,24237,24311,24351,24716,25269,25402,25552,26799, + 27712,30855,31118,31243,32224,33351,35330,35558,36420,36883,}, +{37048,37165,37336,40718,27877,25688,25826,25973,28404,30340,31515,36969, + 37841,28346,21746,24505,25764,36685,36845,37444,20856,22635,22825,23637, + 24215,28155,32399,29980,36028,36578,39003,28857,20253,27583,28593,30000, + 38651,20814,21520,22581,22615,22956,23648,24466,26007,26460,28193,30331, + 33759,36077,36884,37117,37709,30757,30778,21162,24230,22303,22900,24594, + 20498,20826,20908,20941,20992,21776,22612,22616,22871,23445,23798,23947, + 24764,25237,25645,26481,26691,26812,26847,30423,28120,28271,28059,28783, + 29128,24403,30168,31095,31561,31572,31570,31958,32113,21040,}, +{33891,34153,34276,35342,35588,35910,36367,36867,36879,37913,38518,38957, + 39472,38360,20685,21205,21516,22530,23566,24999,25758,27934,30643,31461, + 33012,33796,36947,37509,23776,40199,21311,24471,24499,28060,29305,30563, + 31167,31716,27602,29420,35501,26627,27233,20984,31361,26932,23626,40182, + 33515,23493,37193,28702,22136,23663,24775,25958,27788,35930,36929,38931, + 21585,26311,37389,22856,37027,20869,20045,20970,34201,35598,28760,25466, + 37707,26978,39348,32260,30071,21335,26976,36575,38627,27741,20108,23612, + 24336,36841,21250,36049,32905,34425,24319,26085,20083,20837,}, +{22914,23615,38894,20219,22922,24525,35469,28641,31152,31074,23527,33905, + 29483,29105,24180,24565,25467,25754,29123,31896,20035,24316,20043,22492, + 22178,24745,28611,32013,33021,33075,33215,36786,35223,34468,24052,25226, + 25773,35207,26487,27874,27966,29750,30772,23110,32629,33453,39340,20467, + 24259,25309,25490,25943,26479,30403,29260,32972,32954,36649,37197,20493, + 22521,23186,26757,26995,29028,29437,36023,22770,36064,38506,36889,34687, + 31204,30695,33833,20271,21093,21338,25293,26575,27850,30333,31636,31893, + 33334,34180,36843,26333,28448,29190,32283,33707,39361,40614,}, +{20989,31665,30834,31672,32903,31560,27368,24161,32908,30033,30048,20843, + 37474,28300,30330,37271,39658,20240,32624,25244,31567,38309,40169,22138, + 22617,34532,38588,20276,21028,21322,21453,21467,24070,25644,26001,26495, + 27710,27726,29256,29359,29677,30036,32321,33324,34281,36009,31684,37318, + 29033,38930,39151,25405,26217,30058,30436,30928,34115,34542,21290,21329, + 21542,22915,24199,24444,24754,25161,25209,25259,26000,27604,27852,30130, + 30382,30865,31192,32203,32631,32933,34987,35513,36027,36991,38750,39131, + 27147,31800,20633,23614,24494,26503,27608,29749,30473,32654,}, +{40763,26570,31255,21305,30091,39661,24422,33181,33777,32920,24380,24517, + 30050,31558,36924,26727,23019,23195,32016,30334,35628,20469,24426,27161, + 27703,28418,29922,31080,34920,35413,35961,24287,25551,30149,31186,33495, + 37672,37618,33948,34541,39981,21697,24428,25996,27996,28693,36007,36051, + 38971,25935,29942,19981,20184,22496,22827,23142,23500,20904,24067,24220, + 24598,25206,25975,26023,26222,28014,29238,31526,33104,33178,33433,35676, + 36000,36070,36212,38428,38468,20398,25771,27494,33310,33889,34154,37096, + 23553,26963,39080,33914,34135,20239,21103,24489,24133,26381,}, +{31119,33145,35079,35206,28149,24343,25173,27832,20175,29289,39826,20998, + 21563,22132,22707,24996,25198,28954,22894,31881,31966,32027,38640,25991, + 32862,19993,20341,20853,22592,24163,24179,24330,26564,20006,34109,38281, + 38491,31859,38913,20731,22721,30294,30887,21029,30629,34065,31622,20559, + 22793,29255,31687,32232,36794,36820,36941,20415,21193,23081,24321,38829, + 20445,33303,37610,22275,25429,27497,29995,35036,36628,31298,21215,22675, + 24917,25098,26286,27597,31807,33769,20515,20472,21253,21574,22577,22857, + 23453,23792,23791,23849,24214,25265,25447,25918,26041,26379,}, +{27861,27873,28921,30770,32299,32990,33459,33804,34028,34562,35090,35370, + 35914,37030,37586,39165,40179,40300,20047,20129,20621,21078,22346,22952, + 24125,24536,24537,25151,26292,26395,26576,26834,20882,32033,32938,33192, + 35584,35980,36031,37502,38450,21536,38956,21271,20693,21340,22696,25778, + 26420,29287,30566,31302,37350,21187,27809,27526,22528,24140,22868,26412, + 32763,20961,30406,25705,30952,39764,40635,22475,22969,26151,26522,27598, + 21737,27097,24149,33180,26517,39850,26622,40018,26717,20134,20451,21448, + 25273,26411,27819,36804,20397,32365,40639,19975,24930,28288,}, +{28459,34067,21619,26410,39749,24051,31637,23724,23494,34588,28234,34001, + 31252,33032,22937,31885,27665,30496,21209,22818,28961,29279,30683,38695, + 40289,26891,23167,23064,20901,21517,21629,26126,30431,36855,37528,40180, + 23018,29277,28357,20813,26825,32191,32236,38754,40634,25720,27169,33538, + 22916,23391,27611,29467,30450,32178,32791,33945,20786,26408,40665,30446, + 26466,21247,39173,23588,25147,31870,36016,21839,24758,32011,38272,21249, + 20063,20918,22812,29242,32822,37326,24357,30690,21380,24441,32004,34220, + 35379,36493,38742,26611,34222,37971,24841,24840,27833,30290,}, +{35565,36664,21807,20305,20778,21191,21451,23461,24189,24736,24962,25558, + 26377,26586,28263,28044,29494,29495,30001,31056,35029,35480,36938,37009, + 37109,38596,34701,22805,20104,20313,19982,35465,36671,38928,20653,24188, + 22934,23481,24248,25562,25594,25793,26332,26954,27096,27915,28342,29076, + 29992,31407,32650,32768,33865,33993,35201,35617,36362,36965,38525,39178, + 24958,25233,27442,27779,28020,32716,32764,28096,32645,34746,35064,26469, + 33713,38972,38647,27931,32097,33853,37226,20081,21365,23888,27396,28651, + 34253,34349,35239,21033,21519,23653,26446,26792,29702,29827,}, +{30178,35023,35041,37324,38626,38520,24459,29575,31435,33870,25504,30053, + 21129,27969,28316,29705,30041,30827,31890,38534,31452,40845,20406,24942, + 26053,34396,20102,20142,20698,20001,20940,23534,26009,26753,28092,29471, + 30274,30637,31260,31975,33391,35538,36988,37327,38517,38936,21147,32209, + 20523,21400,26519,28107,29136,29747,33256,36650,38563,40023,40607,29792, + 22593,28057,32047,39006,20196,20278,20363,20919,21169,23994,24604,29618, + 31036,33491,37428,38583,38646,38666,40599,40802,26278,27508,21015,21155, + 28872,35010,24265,24651,24976,28451,29001,31806,32244,32879,}, +{34030,36899,37676,21570,39791,27347,28809,36034,36335,38706,21172,23105, + 24266,24324,26391,27004,27028,28010,28431,29282,29436,31725,32769,32894, + 34635,37070,20845,40595,31108,32907,37682,35542,20525,21644,35441,27498, + 36036,33031,24785,26528,40434,20121,20120,39952,35435,34241,34152,26880, + 28286,30871,33109,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,}, +{24332,19984,19989,20010,20017,20022,20028,20031,20034,20054,20056,20098, + 20101,35947,20106,33298,24333,20110,20126,20127,20128,20130,20144,20147, + 20150,20174,20173,20164,20166,20162,20183,20190,20205,20191,20215,20233, + 20314,20272,20315,20317,20311,20295,20342,20360,20367,20376,20347,20329, + 20336,20369,20335,20358,20374,20760,20436,20447,20430,20440,20443,20433, + 20442,20432,20452,20453,20506,20520,20500,20522,20517,20485,20252,20470, + 20513,20521,20524,20478,20463,20497,20486,20547,20551,26371,20565,20560, + 20552,20570,20566,20588,20600,20608,20634,20613,20660,20658,}, +{20681,20682,20659,20674,20694,20702,20709,20717,20707,20718,20729,20725, + 20745,20737,20738,20758,20757,20756,20762,20769,20794,20791,20796,20795, + 20799,20800,20818,20812,20820,20834,31480,20841,20842,20846,20864,20866, + 22232,20876,20873,20879,20881,20883,20885,20886,20900,20902,20898,20905, + 20906,20907,20915,20913,20914,20912,20917,20925,20933,20937,20955,20960, + 34389,20969,20973,20976,20981,20990,20996,21003,21012,21006,21031,21034, + 21038,21043,21049,21071,21060,21067,21068,21086,21076,21098,21108,21097, + 21107,21119,21117,21133,21140,21138,21105,21128,21137,36776,}, +{36775,21164,21165,21180,21173,21185,21197,21207,21214,21219,21222,39149, + 21216,21235,21237,21240,21241,21254,21256,30008,21261,21264,21263,21269, + 21274,21283,21295,21297,21299,21304,21312,21318,21317,19991,21321,21325, + 20950,21342,21353,21358,22808,21371,21367,21378,21398,21408,21414,21413, + 21422,21424,21430,21443,31762,38617,21471,26364,29166,21486,21480,21485, + 21498,21505,21565,21568,21548,21549,21564,21550,21558,21545,21533,21582, + 21647,21621,21646,21599,21617,21623,21616,21650,21627,21632,21622,21636, + 21648,21638,21703,21666,21688,21669,21676,21700,21704,21672,}, +{21675,21698,21668,21694,21692,21720,21733,21734,21775,21780,21757,21742, + 21741,21754,21730,21817,21824,21859,21836,21806,21852,21829,21846,21847, + 21816,21811,21853,21913,21888,21679,21898,21919,21883,21886,21912,21918, + 21934,21884,21891,21929,21895,21928,21978,21957,21983,21956,21980,21988, + 21972,22036,22007,22038,22014,22013,22043,22009,22094,22096,29151,22068, + 22070,22066,22072,22123,22116,22063,22124,22122,22150,22144,22154,22176, + 22164,22159,22181,22190,22198,22196,22210,22204,22209,22211,22208,22216, + 22222,22225,22227,22231,22254,22265,22272,22271,22276,22281,}, +{22280,22283,22285,22291,22296,22294,21959,22300,22310,22327,22328,22350, + 22331,22336,22351,22377,22464,22408,22369,22399,22409,22419,22432,22451, + 22436,22442,22448,22467,22470,22484,22482,22483,22538,22486,22499,22539, + 22553,22557,22642,22561,22626,22603,22640,27584,22610,22589,22649,22661, + 22713,22687,22699,22714,22750,22715,22712,22702,22725,22739,22737,22743, + 22745,22744,22757,22748,22756,22751,22767,22778,22777,22779,22780,22781, + 22786,22794,22800,22811,26790,22821,22828,22829,22834,22840,22846,31442, + 22869,22864,22862,22874,22872,22882,22880,22887,22892,22889,}, +{22904,22913,22941,20318,20395,22947,22962,22982,23016,23004,22925,23001, + 23002,23077,23071,23057,23068,23049,23066,23104,23148,23113,23093,23094, + 23138,23146,23194,23228,23230,23243,23234,23229,23267,23255,23270,23273, + 23254,23290,23291,23308,23307,23318,23346,23248,23338,23350,23358,23363, + 23365,23360,23377,23381,23386,23387,23397,23401,23408,23411,23413,23416, + 25992,23418,23424,23427,23462,23480,23491,23495,23497,23508,23504,23524, + 23526,23522,23518,23525,23531,23536,23542,23539,23557,23559,23560,23565, + 23571,23584,23586,23592,23608,23609,23617,23622,23630,23635,}, +{23632,23631,23409,23660,23662,20066,23670,23673,23692,23697,23700,22939, + 23723,23739,23734,23740,23735,23749,23742,23751,23769,23785,23805,23802, + 23789,23948,23786,23819,23829,23831,23900,23839,23835,23825,23828,23842, + 23834,23833,23832,23884,23890,23886,23883,23916,23923,23926,23943,23940, + 23938,23970,23965,23980,23982,23997,23952,23991,23996,24009,24013,24019, + 24018,24022,24027,24043,24050,24053,24075,24090,24089,24081,24091,24118, + 24119,24132,24131,24128,24142,24151,24148,24159,24162,24164,24135,24181, + 24182,24186,40636,24191,24224,24257,24258,24264,24272,24271,}, +{24278,24291,24285,24282,24283,24290,24289,24296,24297,24300,24305,24307, + 24304,24308,24312,24318,24323,24329,24413,24412,24331,24337,24342,24361, + 24365,24376,24385,24392,24396,24398,24367,24401,24406,24407,24409,24417, + 24429,24435,24439,24451,24450,24447,24458,24456,24465,24455,24478,24473, + 24472,24480,24488,24493,24508,24534,24571,24548,24568,24561,24541,24755, + 24575,24609,24672,24601,24592,24617,24590,24625,24603,24597,24619,24614, + 24591,24634,24666,24641,24682,24695,24671,24650,24646,24653,24675,24643, + 24676,24642,24684,24683,24665,24705,24717,24807,24707,24730,}, +{24708,24731,24726,24727,24722,24743,24715,24801,24760,24800,24787,24756, + 24560,24765,24774,24757,24792,24909,24853,24838,24822,24823,24832,24820, + 24826,24835,24865,24827,24817,24845,24846,24903,24894,24872,24871,24906, + 24895,24892,24876,24884,24893,24898,24900,24947,24951,24920,24921,24922, + 24939,24948,24943,24933,24945,24927,24925,24915,24949,24985,24982,24967, + 25004,24980,24986,24970,24977,25003,25006,25036,25034,25033,25079,25032, + 25027,25030,25018,25035,32633,25037,25062,25059,25078,25082,25076,25087, + 25085,25084,25086,25088,25096,25097,25101,25100,25108,25115,}, +{25118,25121,25130,25134,25136,25138,25139,25153,25166,25182,25187,25179, + 25184,25192,25212,25218,25225,25214,25234,25235,25238,25300,25219,25236, + 25303,25297,25275,25295,25343,25286,25812,25288,25308,25292,25290,25282, + 25287,25243,25289,25356,25326,25329,25383,25346,25352,25327,25333,25424, + 25406,25421,25628,25423,25494,25486,25472,25515,25462,25507,25487,25481, + 25503,25525,25451,25449,25534,25577,25536,25542,25571,25545,25554,25590, + 25540,25622,25652,25606,25619,25638,25654,25885,25623,25640,25615,25703, + 25711,25718,25678,25898,25749,25747,25765,25769,25736,25788,}, +{25818,25810,25797,25799,25787,25816,25794,25841,25831,33289,25824,25825, + 25260,25827,25839,25900,25846,25844,25842,25850,25856,25853,25880,25884, + 25861,25892,25891,25899,25908,25909,25911,25910,25912,30027,25928,25942, + 25941,25933,25944,25950,25949,25970,25976,25986,25987,35722,26011,26015, + 26027,26039,26051,26054,26049,26052,26060,26066,26075,26073,26080,26081, + 26097,26482,26122,26115,26107,26483,26165,26166,26164,26140,26191,26180, + 26185,26177,26206,26205,26212,26215,26216,26207,26210,26224,26243,26248, + 26254,26249,26244,26264,26269,26305,26297,26313,26302,26300,}, +{26308,26296,26326,26330,26336,26175,26342,26345,26352,26357,26359,26383, + 26390,26398,26406,26407,38712,26414,26431,26422,26433,26424,26423,26438, + 26462,26464,26457,26467,26468,26505,26480,26537,26492,26474,26508,26507, + 26534,26529,26501,26551,26607,26548,26604,26547,26601,26552,26596,26590, + 26589,26594,26606,26553,26574,26566,26599,27292,26654,26694,26665,26688, + 26701,26674,26702,26803,26667,26713,26723,26743,26751,26783,26767,26797, + 26772,26781,26779,26755,27310,26809,26740,26805,26784,26810,26895,26765, + 26750,26881,26826,26888,26840,26914,26918,26849,26892,26829,}, +{26836,26855,26837,26934,26898,26884,26839,26851,26917,26873,26848,26863, + 26920,26922,26906,26915,26913,26822,27001,26999,26972,27000,26987,26964, + 27006,26990,26937,26996,26941,26969,26928,26977,26974,26973,27009,26986, + 27058,27054,27088,27071,27073,27091,27070,27086,23528,27082,27101,27067, + 27075,27047,27182,27025,27040,27036,27029,27060,27102,27112,27138,27163, + 27135,27402,27129,27122,27111,27141,27057,27166,27117,27156,27115,27146, + 27154,27329,27171,27155,27204,27148,27250,27190,27256,27207,27234,27225, + 27238,27208,27192,27170,27280,27277,27296,27268,27298,27299,}, +{27287,34327,27323,27331,27330,27320,27315,27308,27358,27345,27359,27306, + 27354,27370,27387,27397,34326,27386,27410,27414,39729,27423,27448,27447, + 30428,27449,39150,27463,27459,27465,27472,27481,27476,27483,27487,27489, + 27512,27513,27519,27520,27524,27523,27533,27544,27541,27550,27556,27562, + 27563,27567,27570,27569,27571,27575,27580,27590,27595,27603,27615,27628, + 27627,27635,27631,40638,27656,27667,27668,27675,27684,27683,27742,27733, + 27746,27754,27778,27789,27802,27777,27803,27774,27752,27763,27794,27792, + 27844,27889,27859,27837,27863,27845,27869,27822,27825,27838,}, +{27834,27867,27887,27865,27882,27935,34893,27958,27947,27965,27960,27929, + 27957,27955,27922,27916,28003,28051,28004,27994,28025,27993,28046,28053, + 28644,28037,28153,28181,28170,28085,28103,28134,28088,28102,28140,28126, + 28108,28136,28114,28101,28154,28121,28132,28117,28138,28142,28205,28270, + 28206,28185,28274,28255,28222,28195,28267,28203,28278,28237,28191,28227, + 28218,28238,28196,28415,28189,28216,28290,28330,28312,28361,28343,28371, + 28349,28335,28356,28338,28372,28373,28303,28325,28354,28319,28481,28433, + 28748,28396,28408,28414,28479,28402,28465,28399,28466,28364,}, +{28478,28435,28407,28550,28538,28536,28545,28544,28527,28507,28659,28525, + 28546,28540,28504,28558,28561,28610,28518,28595,28579,28577,28580,28601, + 28614,28586,28639,28629,28652,28628,28632,28657,28654,28635,28681,28683, + 28666,28689,28673,28687,28670,28699,28698,28532,28701,28696,28703,28720, + 28734,28722,28753,28771,28825,28818,28847,28913,28844,28856,28851,28846, + 28895,28875,28893,28889,28937,28925,28956,28953,29029,29013,29064,29030, + 29026,29004,29014,29036,29071,29179,29060,29077,29096,29100,29143,29113, + 29118,29138,29129,29140,29134,29152,29164,29159,29173,29180,}, +{29177,29183,29197,29200,29211,29224,29229,29228,29232,29234,29243,29244, + 29247,29248,29254,29259,29272,29300,29310,29314,29313,29319,29330,29334, + 29346,29351,29369,29362,29379,29382,29380,29390,29394,29410,29408,29409, + 29433,29431,20495,29463,29450,29468,29462,29469,29492,29487,29481,29477, + 29502,29518,29519,40664,29527,29546,29544,29552,29560,29557,29563,29562, + 29640,29619,29646,29627,29632,29669,29678,29662,29858,29701,29807,29733, + 29688,29746,29754,29781,29759,29791,29785,29761,29788,29801,29808,29795, + 29802,29814,29822,29835,29854,29863,29898,29903,29908,29681,}, +{29920,29923,29927,29929,29934,29938,29936,29937,29944,29943,29956,29955, + 29957,29964,29966,29965,29973,29971,29982,29990,29996,30012,30020,30029, + 30026,30025,30043,30022,30042,30057,30052,30055,30059,30061,30072,30070, + 30086,30087,30068,30090,30089,30082,30100,30106,30109,30117,30115,30146, + 30131,30147,30133,30141,30136,30140,30129,30157,30154,30162,30169,30179, + 30174,30206,30207,30204,30209,30192,30202,30194,30195,30219,30221,30217, + 30239,30247,30240,30241,30242,30244,30260,30256,30267,30279,30280,30278, + 30300,30296,30305,30306,30312,30313,30314,30311,30316,30320,}, +{30322,30326,30328,30332,30336,30339,30344,30347,30350,30358,30355,30361, + 30362,30384,30388,30392,30393,30394,30402,30413,30422,30418,30430,30433, + 30437,30439,30442,34351,30459,30472,30471,30468,30505,30500,30494,30501, + 30502,30491,30519,30520,30535,30554,30568,30571,30555,30565,30591,30590, + 30585,30606,30603,30609,30624,30622,30640,30646,30649,30655,30652,30653, + 30651,30663,30669,30679,30682,30684,30691,30702,30716,30732,30738,31014, + 30752,31018,30789,30862,30836,30854,30844,30874,30860,30883,30901,30890, + 30895,30929,30918,30923,30932,30910,30908,30917,30922,30956,}, +{30951,30938,30973,30964,30983,30994,30993,31001,31020,31019,31040,31072, + 31063,31071,31066,31061,31059,31098,31103,31114,31133,31143,40779,31146, + 31150,31155,31161,31162,31177,31189,31207,31212,31201,31203,31240,31245, + 31256,31257,31264,31263,31104,31281,31291,31294,31287,31299,31319,31305, + 31329,31330,31337,40861,31344,31353,31357,31368,31383,31381,31384,31382, + 31401,31432,31408,31414,31429,31428,31423,36995,31431,31434,31437,31439, + 31445,31443,31449,31450,31453,31457,31458,31462,31469,31472,31490,31503, + 31498,31494,31539,31512,31513,31518,31541,31528,31542,31568,}, +{31610,31492,31565,31499,31564,31557,31605,31589,31604,31591,31600,31601, + 31596,31598,31645,31640,31647,31629,31644,31642,31627,31634,31631,31581, + 31641,31691,31681,31692,31695,31668,31686,31709,31721,31761,31764,31718, + 31717,31840,31744,31751,31763,31731,31735,31767,31757,31734,31779,31783, + 31786,31775,31799,31787,31805,31820,31811,31828,31823,31808,31824,31832, + 31839,31844,31830,31845,31852,31861,31875,31888,31908,31917,31906,31915, + 31905,31912,31923,31922,31921,31918,31929,31933,31936,31941,31938,31960, + 31954,31964,31970,39739,31983,31986,31988,31990,31994,32006,}, +{32002,32028,32021,32010,32069,32075,32046,32050,32063,32053,32070,32115, + 32086,32078,32114,32104,32110,32079,32099,32147,32137,32091,32143,32125, + 32155,32186,32174,32163,32181,32199,32189,32171,32317,32162,32175,32220, + 32184,32159,32176,32216,32221,32228,32222,32251,32242,32225,32261,32266, + 32291,32289,32274,32305,32287,32265,32267,32290,32326,32358,32315,32309, + 32313,32323,32311,32306,32314,32359,32349,32342,32350,32345,32346,32377, + 32362,32361,32380,32379,32387,32213,32381,36782,32383,32392,32393,32396, + 32402,32400,32403,32404,32406,32398,32411,32412,32568,32570,}, +{32581,32588,32589,32590,32592,32593,32597,32596,32600,32607,32608,32616, + 32617,32615,32632,32642,32646,32643,32648,32647,32652,32660,32670,32669, + 32666,32675,32687,32690,32697,32686,32694,32696,35697,32709,32710,32714, + 32725,32724,32737,32742,32745,32755,32761,39132,32774,32772,32779,32786, + 32792,32793,32796,32801,32808,32831,32827,32842,32838,32850,32856,32858, + 32863,32866,32872,32883,32882,32880,32886,32889,32893,32895,32900,32902, + 32901,32923,32915,32922,32941,20880,32940,32987,32997,32985,32989,32964, + 32986,32982,33033,33007,33009,33051,33065,33059,33071,33099,}, +{38539,33094,33086,33107,33105,33020,33137,33134,33125,33126,33140,33155, + 33160,33162,33152,33154,33184,33173,33188,33187,33119,33171,33193,33200, + 33205,33214,33208,33213,33216,33218,33210,33225,33229,33233,33241,33240, + 33224,33242,33247,33248,33255,33274,33275,33278,33281,33282,33285,33287, + 33290,33293,33296,33302,33321,33323,33336,33331,33344,33369,33368,33373, + 33370,33375,33380,33378,33384,33386,33387,33326,33393,33399,33400,33406, + 33421,33426,33451,33439,33467,33452,33505,33507,33503,33490,33524,33523, + 33530,33683,33539,33531,33529,33502,33542,33500,33545,33497,}, +{33589,33588,33558,33586,33585,33600,33593,33616,33605,33583,33579,33559, + 33560,33669,33690,33706,33695,33698,33686,33571,33678,33671,33674,33660, + 33717,33651,33653,33696,33673,33704,33780,33811,33771,33742,33789,33795, + 33752,33803,33729,33783,33799,33760,33778,33805,33826,33824,33725,33848, + 34054,33787,33901,33834,33852,34138,33924,33911,33899,33965,33902,33922, + 33897,33862,33836,33903,33913,33845,33994,33890,33977,33983,33951,34009, + 33997,33979,34010,34000,33985,33990,34006,33953,34081,34047,34036,34071, + 34072,34092,34079,34069,34068,34044,34112,34147,34136,34120,}, +{34113,34306,34123,34133,34176,34212,34184,34193,34186,34216,34157,34196, + 34203,34282,34183,34204,34167,34174,34192,34249,34234,34255,34233,34256, + 34261,34269,34277,34268,34297,34314,34323,34315,34302,34298,34310,34338, + 34330,34352,34367,34381,20053,34388,34399,34407,34417,34451,34467,34473, + 34474,34443,34444,34486,34479,34500,34502,34480,34505,34851,34475,34516, + 34526,34537,34540,34527,34523,34543,34578,34566,34568,34560,34563,34555, + 34577,34569,34573,34553,34570,34612,34623,34615,34619,34597,34601,34586, + 34656,34655,34680,34636,34638,34676,34647,34664,34670,34649,}, +{34643,34659,34666,34821,34722,34719,34690,34735,34763,34749,34752,34768, + 38614,34731,34756,34739,34759,34758,34747,34799,34802,34784,34831,34829, + 34814,34806,34807,34830,34770,34833,34838,34837,34850,34849,34865,34870, + 34873,34855,34875,34884,34882,34898,34905,34910,34914,34923,34945,34942, + 34974,34933,34941,34997,34930,34946,34967,34962,34990,34969,34978,34957, + 34980,34992,35007,34993,35011,35012,35028,35032,35033,35037,35065,35074, + 35068,35060,35048,35058,35076,35084,35082,35091,35139,35102,35109,35114, + 35115,35137,35140,35131,35126,35128,35148,35101,35168,35166,}, +{35174,35172,35181,35178,35183,35188,35191,35198,35203,35208,35210,35219, + 35224,35233,35241,35238,35244,35247,35250,35258,35261,35263,35264,35290, + 35292,35293,35303,35316,35320,35331,35350,35344,35340,35355,35357,35365, + 35382,35393,35419,35410,35398,35400,35452,35437,35436,35426,35461,35458, + 35460,35496,35489,35473,35493,35494,35482,35491,35524,35533,35522,35546, + 35563,35571,35559,35556,35569,35604,35552,35554,35575,35550,35547,35596, + 35591,35610,35553,35606,35600,35607,35616,35635,38827,35622,35627,35646, + 35624,35649,35660,35663,35662,35657,35670,35675,35674,35691,}, +{35679,35692,35695,35700,35709,35712,35724,35726,35730,35731,35734,35737, + 35738,35898,35905,35903,35912,35916,35918,35920,35925,35938,35948,35960, + 35962,35970,35977,35973,35978,35981,35982,35988,35964,35992,25117,36013, + 36010,36029,36018,36019,36014,36022,36040,36033,36068,36067,36058,36093, + 36090,36091,36100,36101,36106,36103,36111,36109,36112,40782,36115,36045, + 36116,36118,36199,36205,36209,36211,36225,36249,36290,36286,36282,36303, + 36314,36310,36300,36315,36299,36330,36331,36319,36323,36348,36360,36361, + 36351,36381,36382,36368,36383,36418,36405,36400,36404,36426,}, +{36423,36425,36428,36432,36424,36441,36452,36448,36394,36451,36437,36470, + 36466,36476,36481,36487,36485,36484,36491,36490,36499,36497,36500,36505, + 36522,36513,36524,36528,36550,36529,36542,36549,36552,36555,36571,36579, + 36604,36603,36587,36606,36618,36613,36629,36626,36633,36627,36636,36639, + 36635,36620,36646,36659,36667,36665,36677,36674,36670,36684,36681,36678, + 36686,36695,36700,36706,36707,36708,36764,36767,36771,36781,36783,36791, + 36826,36837,36834,36842,36847,36999,36852,36869,36857,36858,36881,36885, + 36897,36877,36894,36886,36875,36903,36918,36917,36921,36856,}, +{36943,36944,36945,36946,36878,36937,36926,36950,36952,36958,36968,36975, + 36982,38568,36978,36994,36989,36993,36992,37002,37001,37007,37032,37039, + 37041,37045,37090,37092,25160,37083,37122,37138,37145,37170,37168,37194, + 37206,37208,37219,37221,37225,37235,37234,37259,37257,37250,37282,37291, + 37295,37290,37301,37300,37306,37312,37313,37321,37323,37328,37334,37343, + 37345,37339,37372,37365,37366,37406,37375,37396,37420,37397,37393,37470, + 37463,37445,37449,37476,37448,37525,37439,37451,37456,37532,37526,37523, + 37531,37466,37583,37561,37559,37609,37647,37626,37700,37678,}, +{37657,37666,37658,37667,37690,37685,37691,37724,37728,37756,37742,37718, + 37808,37804,37805,37780,37817,37846,37847,37864,37861,37848,37827,37853, + 37840,37832,37860,37914,37908,37907,37891,37895,37904,37942,37931,37941, + 37921,37946,37953,37970,37956,37979,37984,37986,37982,37994,37417,38000, + 38005,38007,38013,37978,38012,38014,38017,38015,38274,38279,38282,38292, + 38294,38296,38297,38304,38312,38311,38317,38332,38331,38329,38334,38346, + 28662,38339,38349,38348,38357,38356,38358,38364,38369,38373,38370,38433, + 38440,38446,38447,38466,38476,38479,38475,38519,38492,38494,}, +{38493,38495,38502,38514,38508,38541,38552,38549,38551,38570,38567,38577, + 38578,38576,38580,38582,38584,38585,38606,38603,38601,38605,35149,38620, + 38669,38613,38649,38660,38662,38664,38675,38670,38673,38671,38678,38681, + 38692,38698,38704,38713,38717,38718,38724,38726,38728,38722,38729,38748, + 38752,38756,38758,38760,21202,38763,38769,38777,38789,38780,38785,38778, + 38790,38795,38799,38800,38812,38824,38822,38819,38835,38836,38851,38854, + 38856,38859,38876,38893,40783,38898,31455,38902,38901,38927,38924,38968, + 38948,38945,38967,38973,38982,38991,38987,39019,39023,39024,}, +{39025,39028,39027,39082,39087,39089,39094,39108,39107,39110,39145,39147, + 39171,39177,39186,39188,39192,39201,39197,39198,39204,39200,39212,39214, + 39229,39230,39234,39241,39237,39248,39243,39249,39250,39244,39253,39319, + 39320,39333,39341,39342,39356,39391,39387,39389,39384,39377,39405,39406, + 39409,39410,39419,39416,39425,39439,39429,39394,39449,39467,39479,39493, + 39490,39488,39491,39486,39509,39501,39515,39511,39519,39522,39525,39524, + 39529,39531,39530,39597,39600,39612,39616,39631,39633,39635,39636,39646, + 39647,39650,39651,39654,39663,39659,39662,39668,39665,39671,}, +{39675,39686,39704,39706,39711,39714,39715,39717,39719,39720,39721,39722, + 39726,39727,39730,39748,39747,39759,39757,39758,39761,39768,39796,39827, + 39811,39825,39830,39831,39839,39840,39848,39860,39872,39882,39865,39878, + 39887,39889,39890,39907,39906,39908,39892,39905,39994,39922,39921,39920, + 39957,39956,39945,39955,39948,39942,39944,39954,39946,39940,39982,39963, + 39973,39972,39969,39984,40007,39986,40006,39998,40026,40032,40039,40054, + 40056,40167,40172,40176,40201,40200,40171,40195,40198,40234,40230,40367, + 40227,40223,40260,40213,40210,40257,40255,40254,40262,40264,}, +{40285,40286,40292,40273,40272,40281,40306,40329,40327,40363,40303,40314, + 40346,40356,40361,40370,40388,40385,40379,40376,40378,40390,40399,40386, + 40409,40403,40440,40422,40429,40431,40445,40474,40475,40478,40565,40569, + 40573,40577,40584,40587,40588,40594,40597,40593,40605,40613,40617,40632, + 40618,40621,38753,40652,40654,40655,40656,40660,40668,40670,40669,40672, + 40677,40680,40687,40692,40694,40695,40697,40699,40700,40701,40711,40712, + 30391,40725,40737,40748,40766,40778,40786,40788,40803,40799,40800,40801, + 40806,40807,40812,40810,40823,40818,40822,40853,40860,40864,}, +{22575,27079,36953,29796,20956,29081,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,}, +{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,}, +{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,}, +{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,}, +{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,}, +{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,}, +{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,}, +{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,}, +{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,}, +{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,}, +{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,}, +}; + + +// ------------------------------------------------------------ +unsigned short JISConverter::sjisToUnicode(unsigned short sjis) +{ + unsigned short u; + unsigned int c = sjis>>8; + unsigned int c1 = sjis&0xff; + + c = c + c - ((c <= 0x9f) ? SJ0162 : SJ6394); + if(c1 < 0x9f) + { + c1 = c1 - ((c1 > 0x7f) ? 0x20 : 0x1f); + } + else + { + c1 = c1 - 0x7e; c++; + } + c -= 33; + c1 -= 33; + if(c < 0 || c1 < 0 || c > 93 || c1 > 93) + u = 0x3013; + else + { + u = uniTable[c][c1]; + if(!u) + u = 0x3013; + } + + return u; +} +// ------------------------------------------------------------ +unsigned short JISConverter::eucToUnicode(unsigned short euc) +{ + unsigned short u; + unsigned int c = euc>>8; + unsigned int c1 = euc&0xff; + + c &= 0x7f; + c -= 33; + c1 &= 0x7f; + c1 -= 33; + if(c < 0 || c1 < 0 || c > 93 || c1 > 93) + u = 0x3013; + else + { + u = uniTable[c][c1]; + if(!u) + u = 0x3013; + } + return u; +} diff --git a/PeerCast.root/PeerCast/core/common/jis.h b/PeerCast.root/PeerCast/core/common/jis.h new file mode 100644 index 0000000..da4df03 --- /dev/null +++ b/PeerCast.root/PeerCast/core/common/jis.h @@ -0,0 +1,35 @@ +// ------------------------------------------------ +// File : jis.h +// Date: 1-april-2004 +// Author: giles +// +// (c) 2002-4 peercast.org +// ------------------------------------------------ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// ------------------------------------------------ + +#ifndef _JIS_H +#define _JIS_H + +// ---------------------------------- +class JISConverter +{ +public: + + static unsigned short sjisToUnicode(unsigned short); + static unsigned short eucToUnicode(unsigned short); +}; + + + +#endif + + diff --git a/PeerCast.root/PeerCast/core/common/mms.cpp b/PeerCast.root/PeerCast/core/common/mms.cpp new file mode 100644 index 0000000..2ddafbc --- /dev/null +++ b/PeerCast.root/PeerCast/core/common/mms.cpp @@ -0,0 +1,194 @@ +// ------------------------------------------------ +// File : mms.cpp +// Date: 28-may-2003 +// Author: giles +// +// (c) 2002-3 peercast.org +// ------------------------------------------------ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// ------------------------------------------------ + +#include "channel.h" +#include "mms.h" +#include "asf.h" +#ifdef _DEBUG +#include "chkMemoryLeak.h" +#define DEBUG_NEW new(__FILE__, __LINE__) +#define new DEBUG_NEW +#endif + +// ------------------------------------------ +ASFInfo parseASFHeader(Stream &in); + + +// ------------------------------------------ +void MMSStream::readEnd(Stream &,Channel *) +{ +} + +// ------------------------------------------ +void MMSStream::readHeader(Stream &,Channel *) +{ +} +// ------------------------------------------ +int MMSStream::readPacket(Stream &in,Channel *ch) +{ + { + ASFChunk chunk; + + chunk.read(in); + + switch (chunk.type) + { + case 0x4824: // asf header + { + MemoryStream mem(ch->headPack.data,sizeof(ch->headPack.data)); + + chunk.write(mem); + + + + + MemoryStream asfm(chunk.data,chunk.dataLen); + ASFObject asfHead; + asfHead.readHead(asfm); + + ASFInfo asf = parseASFHeader(asfm); + LOG_DEBUG("ASF Info: pnum=%d, psize=%d, br=%d",asf.numPackets,asf.packetSize,asf.bitrate); + for(int i=0; iid) + LOG_DEBUG("ASF Stream %d : %s, br=%d",s->id,s->getTypeName(),s->bitrate); + } + + ch->info.bitrate = asf.bitrate/1000; + + ch->headPack.type = ChanPacket::T_HEAD; + ch->headPack.len = mem.pos; + ch->headPack.pos = ch->streamPos; + ch->newPacket(ch->headPack); + + ch->streamPos += ch->headPack.len; + + break; + } + case 0x4424: // asf data + { + + ChanPacket pack; + + MemoryStream mem(pack.data,sizeof(pack.data)); + + chunk.write(mem); + + pack.type = ChanPacket::T_DATA; + pack.len = mem.pos; + pack.pos = ch->streamPos; + + ch->newPacket(pack); + ch->streamPos += pack.len; + + break; + } + default: + throw StreamException("Unknown ASF chunk"); + + } + + } + return 0; +} + + +// ----------------------------------- +ASFInfo parseASFHeader(Stream &in) +{ + ASFInfo asf; + + try + { + int numHeaders = in.readLong(); + + in.readChar(); + in.readChar(); + + LOG_CHANNEL("ASF Headers: %d",numHeaders); + for(int i=0; iicyMetaInterval) + { + + int rlen = ch->icyMetaInterval; + + while (rlen) + { + int rl = rlen; + if (rl > ChanMgr::MAX_METAINT) + rl = ChanMgr::MAX_METAINT; + + pack.init(ChanPacket::T_DATA,pack.data,rl,ch->streamPos); + in.read(pack.data,pack.len); + ch->newPacket(pack); + ch->checkReadDelay(pack.len); + ch->streamPos+=pack.len; + + rlen-=rl; + } + + unsigned char len; + in.read(&len,1); + if (len) + { + if (len*16 > 1024) len = 1024/16; + char buf[1024]; + in.read(buf,len*16); + ch->processMp3Metadata(buf); + } + + }else{ + + pack.init(ChanPacket::T_DATA,pack.data,ChanMgr::MAX_METAINT,ch->streamPos); + in.read(pack.data,pack.len); + ch->newPacket(pack); + ch->checkReadDelay(pack.len); + + ch->streamPos += pack.len; + } + return 0; +} diff --git a/PeerCast.root/PeerCast/core/common/mp3.h b/PeerCast.root/PeerCast/core/common/mp3.h new file mode 100644 index 0000000..2297d10 --- /dev/null +++ b/PeerCast.root/PeerCast/core/common/mp3.h @@ -0,0 +1,35 @@ +// ------------------------------------------------ +// File : mp3.h +// Date: 28-may-2003 +// Author: giles +// +// (c) 2002-3 peercast.org +// ------------------------------------------------ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// ------------------------------------------------ + +#ifndef _MP3_H +#define _MP3_H + + +#include "channel.h" + +// ---------------------------------------------- +class MP3Stream : public ChannelStream +{ +public: + virtual void readHeader(Stream &,Channel *); + virtual int readPacket(Stream &,Channel *); + virtual void readEnd(Stream &,Channel *); +}; + + +#endif diff --git a/PeerCast.root/PeerCast/core/common/nsv.cpp b/PeerCast.root/PeerCast/core/common/nsv.cpp new file mode 100644 index 0000000..55cdb98 --- /dev/null +++ b/PeerCast.root/PeerCast/core/common/nsv.cpp @@ -0,0 +1,80 @@ +// ------------------------------------------------ +// File : nsv.cpp +// Date: 28-may-2003 +// Author: giles +// +// (c) 2002-3 peercast.org +// ------------------------------------------------ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// ------------------------------------------------ + +#include "nsv.h" +#ifdef _DEBUG +#include "chkMemoryLeak.h" +#define DEBUG_NEW new(__FILE__, __LINE__) +#define new DEBUG_NEW +#endif + +// ------------------------------------------ +void NSVStream::readEnd(Stream &,Channel *) +{ +} + +// ------------------------------------------ +void NSVStream::readHeader(Stream &,Channel *) +{ +} +// ------------------------------------------ +int NSVStream::readPacket(Stream &in,Channel *ch) +{ + ChanPacket pack; + + if (ch->icyMetaInterval) + { + + int rlen = ch->icyMetaInterval; + + while (rlen) + { + int rl = rlen; + if (rl > ChanMgr::MAX_METAINT) + rl = ChanMgr::MAX_METAINT; + + pack.init(ChanPacket::T_DATA,pack.data,rl,ch->streamPos); + in.read(pack.data,pack.len); + ch->newPacket(pack); + ch->checkReadDelay(pack.len); + ch->streamPos+=pack.len; + + rlen-=rl; + } + + unsigned char len; + in.read(&len,1); + if (len) + { + if (len*16 > 1024) len = 1024/16; + char buf[1024]; + in.read(buf,len*16); + ch->processMp3Metadata(buf); + } + + }else{ + + pack.init(ChanPacket::T_DATA,pack.data,ChanMgr::MAX_METAINT,ch->streamPos); + in.read(pack.data,pack.len); + ch->newPacket(pack); + ch->checkReadDelay(pack.len); + + ch->streamPos += pack.len; + } + return 0; +} diff --git a/PeerCast.root/PeerCast/core/common/nsv.h b/PeerCast.root/PeerCast/core/common/nsv.h new file mode 100644 index 0000000..cca0106 --- /dev/null +++ b/PeerCast.root/PeerCast/core/common/nsv.h @@ -0,0 +1,35 @@ +// ------------------------------------------------ +// File : nsv.h +// Date: 28-may-2003 +// Author: giles +// +// (c) 2002-3 peercast.org +// ------------------------------------------------ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// ------------------------------------------------ + +#ifndef _NSV_H +#define _NSV_H + + +#include "channel.h" + +// ---------------------------------------------- +class NSVStream : public ChannelStream +{ +public: + virtual void readHeader(Stream &,Channel *); + virtual int readPacket(Stream &,Channel *); + virtual void readEnd(Stream &,Channel *); +}; + + +#endif diff --git a/PeerCast.root/PeerCast/core/common/ogg.cpp b/PeerCast.root/PeerCast/core/common/ogg.cpp new file mode 100644 index 0000000..ed38bc7 --- /dev/null +++ b/PeerCast.root/PeerCast/core/common/ogg.cpp @@ -0,0 +1,494 @@ +// ------------------------------------------------ +// File : mp3.cpp +// Date: 28-may-2003 +// Author: giles +// +// (c) 2002-3 peercast.org +// ------------------------------------------------ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// ------------------------------------------------ + +#include "channel.h" +#include "ogg.h" +#ifdef _DEBUG +#include "chkMemoryLeak.h" +#define DEBUG_NEW new(__FILE__, __LINE__) +#define new DEBUG_NEW +#endif + + +static int test=0; +// ------------------------------------------ +void OGGStream::readHeader(Stream &,Channel *) +{ + test = 0; +} + +// ------------------------------------------ +void OGGStream::readEnd(Stream &,Channel *) +{ +} + +// ------------------------------------------ +int OGGStream::readPacket(Stream &in,Channel *ch) +{ + OggPage ogg; + ChanPacket pack; + + ogg.read(in); + + if (ogg.isBOS()) + { + if (!vorbis.needHeader() && !theora.needHeader()) + { + ch->headPack.len = 0; + } + + if (ogg.detectVorbis()) + vorbis.bos(ogg.getSerialNo()); + if (ogg.detectTheora()) + theora.bos(ogg.getSerialNo()); + } + + if (ogg.isEOS()) + { + + if (ogg.getSerialNo() == vorbis.serialNo) + { + LOG_CHANNEL("Vorbis stream: EOS"); + vorbis.eos(); + } + if (ogg.getSerialNo() == theora.serialNo) + { + LOG_CHANNEL("Theora stream: EOS"); + theora.eos(); + } + } + + if (vorbis.needHeader() || theora.needHeader()) + { + + if (ogg.getSerialNo() == vorbis.serialNo) + vorbis.readHeader(ch,ogg); + else if (ogg.getSerialNo() == theora.serialNo) + theora.readHeader(ch,ogg); + else + throw StreamException("Bad OGG serial no."); + + + if (!vorbis.needHeader() && !theora.needHeader()) + { + + ch->info.bitrate = 0; + + if (vorbis.isActive()) + ch->info.bitrate += vorbis.bitrate; + + if (theora.isActive()) + { + ch->info.bitrate += theora.bitrate; + ch->info.contentType = ChanInfo::T_OGM; + } + + + ch->headPack.type = ChanPacket::T_HEAD; + ch->headPack.pos = ch->streamPos; + + ch->startTime = sys->getDTime(); + + ch->streamPos += ch->headPack.len; + + ch->newPacket(ch->headPack); + LOG_CHANNEL("Got %d bytes of headers",ch->headPack.len); + } + + }else + { + + + pack.init(ChanPacket::T_DATA,ogg.data,ogg.headLen+ogg.bodyLen,ch->streamPos); + ch->newPacket(pack); + + ch->streamPos+=pack.len; + + if (theora.isActive()) + { + if (ogg.getSerialNo() == theora.serialNo) + { + ch->sleepUntil(theora.getTime(ogg)); + } + }else if (vorbis.isActive()) + { + if (ogg.getSerialNo() == vorbis.serialNo) + { + ch->sleepUntil(vorbis.getTime(ogg)); + } + } + + } + return 0; +} + +// ----------------------------------- +void OggSubStream::readHeader(Channel *ch,OggPage &ogg) +{ + if ((pack.bodyLen + ogg.bodyLen) >= OggPacket::MAX_BODYLEN) + throw StreamException("OGG packet too big"); + + if (ch->headPack.len+(ogg.bodyLen+ogg.headLen) >= ChanMeta::MAX_DATALEN) + throw StreamException("OGG packet too big for headMeta"); + +// copy complete packet into head packet + memcpy(&ch->headPack.data[ch->headPack.len],ogg.data,ogg.headLen+ogg.bodyLen); + ch->headPack.len += ogg.headLen+ogg.bodyLen; + + // add body to packet + memcpy(&pack.body[pack.bodyLen],&ogg.data[ogg.headLen],ogg.bodyLen); + pack.bodyLen += ogg.bodyLen; + + pack.addLacing(ogg); + + if (pack.numPackets >= maxHeaders) + procHeaders(ch); + +} +// ----------------------------------- +void OggVorbisSubStream::procHeaders(Channel *ch) +{ + unsigned int packPtr=0; + + for(int i=0; iinfo); + break; + case 3: // comment + { + LOG_CHANNEL("OGG Vorbis Header: Comment (%d bytes)",vin.len); + ChanInfo newInfo = ch->info; + readComment(vin,newInfo); + ch->updateInfo(newInfo); + } + break; + case 5: // setup + LOG_CHANNEL("OGG Vorbis Header: Setup (%d bytes)",vin.len); + //readSetup(vin); + break; + default: + throw StreamException("Unknown Vorbis packet header type"); + break; + } + } + +} +// ----------------------------------- +double OggTheoraSubStream::getTime(OggPage &ogg) +{ + int64_t iframe=ogg.granPos>>granposShift; + int64_t pframe=ogg.granPos-(iframe<info); + break; + default: + LOG_CHANNEL("OGG Theora Header: Unknown %d (%d bytes)",id[0] & 0xff,vin.len); + break; + } + + + + } + +} + +// ----------------------------------- +double OggVorbisSubStream::getTime(OggPage &ogg) +{ + return (double)ogg.granPos / (double)samplerate; + +} + +// ----------------------------------- +void OggVorbisSubStream::readIdent(Stream &in, ChanInfo &info) +{ + int ver = in.readLong(); + int chans = in.readChar(); + samplerate = in.readLong(); + int brMax = in.readLong(); + int brNom = in.readLong(); + int brLow = in.readLong(); + + + in.readChar(); // skip blocksize 0+1 + + LOG_CHANNEL("OGG Vorbis Ident: ver=%d, chans=%d, rate=%d, brMax=%d, brNom=%d, brLow=%d", + ver,chans,samplerate,brMax,brNom,brLow); + + + bitrate = brNom/1000; + + char frame = in.readChar(); // framing bit + if (!frame) + throw StreamException("Bad Indent frame"); + +} + + +// ----------------------------------- +void OggVorbisSubStream::readSetup(Stream &in) +{ + // skip everything in packet + int cnt=0; + while (!in.eof()) + { + cnt++; + in.readChar(); + } + + LOG_CHANNEL("Read %d bytes of Vorbis Setup",cnt); +} +// ----------------------------------- +void OggVorbisSubStream::readComment(Stream &in, ChanInfo &info) +{ + int vLen = in.readLong(); // vendor len + + in.skip(vLen); + + char argBuf[8192]; + + info.track.clear(); + + int cLen = in.readLong(); // comment len + for(int i=0; i sizeof(argBuf)) + throw StreamException("Comment string too long"); + in.read(argBuf,l); + argBuf[l] = 0; + LOG_CHANNEL("OGG Comment: %s",argBuf); + + char *arg; + if ((arg=stristr(argBuf,"ARTIST="))) + { + info.track.artist.set(arg+7,String::T_ASCII); + info.track.artist.convertTo(String::T_UNICODE); + + }else if ((arg=stristr(argBuf,"TITLE="))) + { + info.track.title.set(arg+6,String::T_ASCII); + info.track.title.convertTo(String::T_UNICODE); + + }else if ((arg=stristr(argBuf,"GENRE="))) + { + info.track.genre.set(arg+6,String::T_ASCII); + info.track.genre.convertTo(String::T_UNICODE); + + }else if ((arg=stristr(argBuf,"CONTACT="))) + { + info.track.contact.set(arg+8,String::T_ASCII); + info.track.contact.convertTo(String::T_UNICODE); + + }else if ((arg=stristr(argBuf,"ALBUM="))) + { + info.track.album.set(arg+6,String::T_ASCII); + info.track.album.convertTo(String::T_UNICODE); + } + } + + char frame = in.readChar(); // framing bit + if (!frame) + throw StreamException("Bad Comment frame"); + +// updateMeta(); + +} + +// ----------------------------------- +bool OggPage::isBOS() +{ + return (data[5] & 0x02) != 0; +} +// ----------------------------------- +bool OggPage::isEOS() +{ + return (data[5] & 0x04) != 0; +} +// ----------------------------------- +bool OggPage::isNewPacket() +{ + return (data[5] & 0x01) == 0; +} +// ----------------------------------- +bool OggPage::isHeader() +{ + return ((*(unsigned int *)&data[6]) || (*(unsigned int *)&data[10])) == 0; +} +// ----------------------------------- +unsigned int OggPage::getSerialNo() +{ + return *(unsigned int *)&data[14]; +} + +// ----------------------------------- +void OggPage::read(Stream &in) +{ + // skip until we get OGG capture pattern + bool gotOgg=false; + while (!gotOgg) + { + if (in.readChar() == 'O') + if (in.readChar() == 'g') + if (in.readChar() == 'g') + if (in.readChar() == 'S') + gotOgg = true; + if (!gotOgg) + LOG_CHANNEL("Skipping OGG packet"); + } + + + + memcpy(&data[0],"OggS",4); + + in.read(&data[4],27-4); + + int numSegs = data[26]; + bodyLen = 0; + + // read segment table + in.read(&data[27],numSegs); + for(int i=0; i= MAX_BODYLEN) + throw StreamException("OGG body too big"); + + headLen = 27+numSegs; + + if (headLen > MAX_HEADERLEN) + throw StreamException("OGG header too big"); + + in.read(&data[headLen],bodyLen); + + granPos = *(unsigned int *)&data[10]; + granPos <<= 32; + granPos |= *(unsigned int *)&data[6]; + + + #if 0 + LOG_DEBUG("OGG Packet - page %d, id = %x - %s %s %s - %d:%d - %d segs, %d bytes", + *(unsigned int *)&data[18], + *(unsigned int *)&data[14], + data[5]&0x1?"cont":"new", + data[5]&0x2?"bos":"", + data[5]&0x4?"eos":"", + (unsigned int)(granPos>>32), + (unsigned int)(granPos&0xffffffff), + numSegs, + headLen+bodyLen); + + #endif + +} +// ----------------------------------- +bool OggPage::detectVorbis() +{ + return memcmp(&data[headLen+1],"vorbis",6) == 0; +} +// ----------------------------------- +bool OggPage::detectTheora() +{ + return memcmp(&data[headLen+1],"theora",6) == 0; +} + +// ----------------------------------- +void OggPacket::addLacing(OggPage &ogg) +{ + + int numSegs = ogg.data[26]; + for(int i=0; i= MAX_PACKETS) + throw StreamException("Too many OGG packets"); + packetSizes[numPackets]=0; + } + } + +} diff --git a/PeerCast.root/PeerCast/core/common/ogg.h b/PeerCast.root/PeerCast/core/common/ogg.h new file mode 100644 index 0000000..67a228c --- /dev/null +++ b/PeerCast.root/PeerCast/core/common/ogg.h @@ -0,0 +1,169 @@ +// ------------------------------------------------ +// File : ogg.h +// Date: 28-may-2003 +// Author: giles +// +// (c) 2002-3 peercast.org +// ------------------------------------------------ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// ------------------------------------------------ + +#ifndef _OGG_H +#define _OGG_H + + +#include "channel.h" +// ---------------------------------------------- +class OggPage; + +// ---------------------------------- +class OggPacket +{ +public: + enum + { + MAX_BODYLEN = 65536, // probably too small + MAX_PACKETS = 256 // prolly too small too, but realloc?!?!?! + }; + + void addLacing(OggPage &); + + int bodyLen; + unsigned char body[MAX_BODYLEN]; + + + int numPackets; + unsigned int packetSizes[MAX_PACKETS]; +}; + +// ---------------------------------------------- +class OggSubStream +{ +public: + OggSubStream() + :maxHeaders(0),serialNo(0),bitrate(0) + {} + + bool needHeader() + { + return maxHeaders && (pack.numPackets < maxHeaders); + } + + void eos() + { + maxHeaders=0; + serialNo=0; + } + + void bos(unsigned int ser) + { + maxHeaders = 3; + pack.numPackets=0; + pack.packetSizes[0]=0; + pack.bodyLen = 0; + serialNo = ser; + bitrate = 0; + } + + bool isActive() {return serialNo!=0;} + + void readHeader(Channel *,OggPage &); + + virtual void procHeaders(Channel *) = 0; + + int bitrate; + + OggPacket pack; + int maxHeaders; + unsigned int serialNo; +}; +// ---------------------------------------------- +class OggVorbisSubStream : public OggSubStream +{ +public: + OggVorbisSubStream() + :samplerate(0) + {} + + virtual void procHeaders(Channel *); + + void readIdent(Stream &, ChanInfo &); + void readSetup(Stream &); + void readComment(Stream &, ChanInfo &); + + double getTime(OggPage &); + + int samplerate; + +}; +// ---------------------------------------------- +class OggTheoraSubStream : public OggSubStream +{ +public: + OggTheoraSubStream() : granposShift(0), frameTime(0) {} + + virtual void procHeaders(Channel *); + + void readInfo(Stream &, ChanInfo &); + + double getTime(OggPage &); + + int granposShift; + double frameTime; +}; + +// ---------------------------------------------- +class OGGStream : public ChannelStream +{ +public: + OGGStream() + {} + + + virtual void readHeader(Stream &,Channel *); + virtual int readPacket(Stream &,Channel *); + virtual void readEnd(Stream &,Channel *); + + + void readHeaders(Stream &,Channel *, OggPage &); + + OggVorbisSubStream vorbis; + OggTheoraSubStream theora; +}; + +// ---------------------------------- +class OggPage +{ +public: + enum + { + MAX_BODYLEN = 65536, + MAX_HEADERLEN = 27+256 + }; + + void read(Stream &); + bool isBOS(); + bool isEOS(); + bool isNewPacket(); + bool isHeader(); + unsigned int getSerialNo(); + + bool detectVorbis(); + bool detectTheora(); + + + int64_t granPos; + int headLen,bodyLen; + unsigned char data[MAX_HEADERLEN+MAX_BODYLEN]; +}; + + +#endif diff --git a/PeerCast.root/PeerCast/core/common/pcp.cpp b/PeerCast.root/PeerCast/core/common/pcp.cpp new file mode 100644 index 0000000..37514ed --- /dev/null +++ b/PeerCast.root/PeerCast/core/common/pcp.cpp @@ -0,0 +1,886 @@ +// ------------------------------------------------ +// File : pcp.cpp +// Date: 1-mar-2004 +// Author: giles +// +// (c) 2002-4 peercast.org +// ------------------------------------------------ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// ------------------------------------------------ + +#include "atom.h" +#include "pcp.h" +#include "peercast.h" +#include "version2.h" +#ifdef _DEBUG +#include "chkMemoryLeak.h" +#define DEBUG_NEW new(__FILE__, __LINE__) +#define new DEBUG_NEW +#endif + +// ------------------------------------------ +void PCPStream::init(GnuID &rid) +{ + remoteID = rid; + routeList.clear(); + + lastPacketTime = 0; + nextRootPacket = 0; // 0 seconds (never) + + inData.init(); + inData.accept = ChanPacket::T_PCP; + + outData.init(); + outData.accept = ChanPacket::T_PCP; +} +// ------------------------------------------ +void PCPStream::readVersion(Stream &in) +{ + int len = in.readInt(); + + if (len != 4) + throw StreamException("Invalid PCP"); + + int ver = in.readInt(); + + LOG_DEBUG("PCP ver: %d",ver); +} +// ------------------------------------------ +void PCPStream::readHeader(Stream &in,Channel *) +{ +// AtomStream atom(in); + +// if (in.readInt() != PCP_CONNECT) +// throw StreamException("Not PCP"); + +// readVersion(in); +} +// ------------------------------------------ +bool PCPStream::sendPacket(ChanPacket &pack,GnuID &destID) +{ + if (destID.isSet()) + if (!destID.isSame(remoteID)) + if (!routeList.contains(destID)) + return false; + + return outData.writePacket(pack); +} +// ------------------------------------------ +void PCPStream::flush(Stream &in) +{ + ChanPacket pack; + // send outward packets + while (outData.numPending()) + { + outData.readPacket(pack); + pack.writeRaw(in); + } +} +// ------------------------------------------ +int PCPStream::readPacket(Stream &in,Channel *) +{ + BroadcastState bcs; + return readPacket(in,bcs); +} +// ------------------------------------------ +int PCPStream::readPacket(Stream &in,BroadcastState &bcs) +{ + int error = PCP_ERROR_GENERAL; + try + { + AtomStream atom(in); + + ChanPacket pack; + MemoryStream mem(pack.data,sizeof(pack.data)); + AtomStream patom(mem); + + + // send outward packets + error = PCP_ERROR_WRITE; + if (outData.numPending()) + { + outData.readPacket(pack); + pack.writeRaw(in); + } + error = PCP_ERROR_GENERAL; + + if (outData.willSkip()) + { + error = PCP_ERROR_WRITE+PCP_ERROR_SKIP; + throw StreamException("Send too slow"); + } + + + error = PCP_ERROR_READ; + // poll for new downward packet + if (in.readReady()) + { + int numc,numd; + ID4 id; + + id = atom.read(numc,numd); + + mem.rewind(); + pack.len = patom.writeAtoms(id, in, numc, numd); + pack.type = ChanPacket::T_PCP; + + //inData.writePacket(pack); + //} + error = PCP_ERROR_GENERAL; + + // process downward packets + //if (inData.numPending()) + //{ + //inData.readPacket(pack); + + mem.rewind(); + + //int numc,numd; + id = patom.read(numc,numd); + + error = PCPStream::procAtom(patom,id,numc,numd,bcs); + + if (error) + throw StreamException("PCP exception"); + } + + error = 0; + + }catch(StreamException &e) + { + LOG_ERROR("PCP readPacket: %s (%d)",e.msg,error); + } + + return error; +} + +// ------------------------------------------ +void PCPStream::readEnd(Stream &,Channel *) +{ +} + + +// ------------------------------------------ +void PCPStream::readPushAtoms(AtomStream &atom, int numc,BroadcastState &bcs) +{ + Host host; + GnuID chanID; + + chanID.clear(); + + for(int i=0; ifindChannelByID(chanID); + if (ch) + if (ch->isBroadcasting() || !ch->isFull() && !servMgr->relaysFull() && ch->info.id.isSame(chanID)) + s = servMgr->allocServent(); + }else{ + s = servMgr->allocServent(); + } + + if (s) + { + LOG_DEBUG("GIVing to %s",ipstr); + s->initGIV(host,chanID); + } + } + +} +// ------------------------------------------ +void PCPStream::readRootAtoms(AtomStream &atom, int numc,BroadcastState &bcs) +{ + String url; + + for(int i=0; isetUpdateInterval(si); + LOG_DEBUG("PCP got new host update interval: %ds",si); + }else if (id == PCP_ROOT_URL) + { + url = "http://www.peercast.org/"; + String loc; + atom.readString(loc.data,sizeof(loc.data),d); + url.append(loc); + + }else if (id == PCP_ROOT_CHECKVER) + { + unsigned int newVer = atom.readInt(); + if (newVer > PCP_CLIENT_VERSION) + { + strcpy(servMgr->downloadURL,url.cstr()); + peercastApp->notifyMessage(ServMgr::NT_UPGRADE,"There is a new version available, please click here to upgrade your client."); + } + LOG_DEBUG("PCP got version check: %d / %d",newVer,PCP_CLIENT_VERSION); + + }else if (id == PCP_ROOT_NEXT) + { + unsigned int time = atom.readInt(); + + if (time) + { + unsigned int ctime = sys->getTime(); + nextRootPacket = ctime+time; + LOG_DEBUG("PCP expecting next root packet in %ds",time); + }else + { + nextRootPacket = 0; + } + + }else if (id == PCP_ROOT_UPDATE) + { + atom.skip(c,d); + + chanMgr->broadcastTrackerUpdate(remoteID,true); + + }else if ((id == PCP_MESG_ASCII) || (id == PCP_MESG)) // PCP_MESG_ASCII to be depreciated + { + String newMsg; + + atom.readString(newMsg.data,sizeof(newMsg.data),d); + if (!newMsg.isSame(servMgr->rootMsg.cstr())) + { + servMgr->rootMsg = newMsg; + LOG_DEBUG("PCP got new root mesg: %s",servMgr->rootMsg.cstr()); + peercastApp->notifyMessage(ServMgr::NT_PEERCAST,servMgr->rootMsg.cstr()); + } + }else + { + LOG_DEBUG("PCP skip: %s,%d,%d",id.getString().str(),c,d); + atom.skip(c,d); + } + } +} + +// ------------------------------------------ +void PCPStream::readPktAtoms(Channel *ch,AtomStream &atom,int numc,BroadcastState &bcs) +{ + ChanPacket pack; + ID4 type; + + + for(int i=0; istreamPos; + if (diff) + { + LOG_DEBUG("PCP skipping %s%8d (%10d -> %10d) count=%2d",(diff>0)?"+":"",diff,ch->streamPos,pack.pos, ch->skipCount); + if (ch->lastSkipTime + 120 < sys->getTime()){ + ch->skipCount = 0; + } + ch->lastSkipTime = sys->getTime(); + ch->skipCount++; //JP-EX + pack.skip = true; + } + + if (servMgr->autoBumpSkipCount) //JP-EX + { + if (ch->skipCount > servMgr->autoBumpSkipCount) + { + LOG_DEBUG("Auto bump"); + ch->bump = true; + } + } + + if (pack.type == ChanPacket::T_HEAD) + { + LOG_DEBUG("New head packet at %d",pack.pos); + bool renewhead; + if (servMgr->keepDownstreams) + renewhead = (memcmp(ch->headPack.data, pack.data, pack.len) != 0); + else + renewhead = true; + + /* + // check for stream restart + if (pack.pos == 0) + { + LOG_CHANNEL("PCP resetting stream"); + ch->streamIndex++; + ch->rawData.init(); + } + */ + if (renewhead || ch->lastStopTime + 30 < sys->getTime()) { + // check for stream restart + if (pack.pos == 0) + { + LOG_CHANNEL("PCP resetting stream"); + ch->streamIndex++; + ch->rawData.init(); + } + + ch->headPack = pack; + + ch->rawData.writePacket(pack,true); + ch->streamPos = pack.pos+pack.len; + } + + }else if (pack.type == ChanPacket::T_DATA) + { + ch->rawData.writePacket(pack,true); + ch->streamPos = pack.pos+pack.len; + } + + } + + // update this parent packet stream position + if ((pack.pos) && (!bcs.streamPos || (pack.pos < bcs.streamPos))) + bcs.streamPos = pack.pos; + +} +// ----------------------------------- +void PCPStream::readHostAtoms(AtomStream &atom, int numc, BroadcastState &bcs, ChanHit &hit, bool flg) +{ +// ChanHit hit; + hit.init(); + GnuID chanID = bcs.chanID; //use default + + bool busy=false; + + unsigned int ipNum=0; + + for(int i=0; i 1) + ipNum = 1; + } + else if (id == PCP_HOST_NUML) + hit.numListeners = atom.readInt(); + else if (id == PCP_HOST_NUMR) + hit.numRelays = atom.readInt(); + else if (id == PCP_HOST_UPTIME) + hit.upTime = atom.readInt(); + else if (id == PCP_HOST_OLDPOS) + hit.oldestPos = atom.readInt(); + else if (id == PCP_HOST_NEWPOS) + hit.newestPos = atom.readInt(); + else if (id == PCP_HOST_VERSION) + hit.version = atom.readInt(); + else if (id == PCP_HOST_VERSION_VP) + hit.version_vp = atom.readInt(); + else if (id == PCP_HOST_VERSION_EX_PREFIX) + atom.readBytes(hit.version_ex_prefix,2); + else if (id == PCP_HOST_VERSION_EX_NUMBER){ + hit.version_ex_number = atom.readShort(); + } + else if (id == PCP_HOST_FLAGS1) + { + int fl1 = atom.readChar(); + + hit.recv = (fl1 & PCP_HOST_FLAGS1_RECV) !=0; + hit.relay = (fl1 & PCP_HOST_FLAGS1_RELAY) !=0; + hit.direct = (fl1 & PCP_HOST_FLAGS1_DIRECT) !=0; + hit.cin = (fl1 & PCP_HOST_FLAGS1_CIN) !=0; + hit.tracker = (fl1 & PCP_HOST_FLAGS1_TRACKER) !=0; + hit.firewalled = (fl1 & PCP_HOST_FLAGS1_PUSH) !=0; + + + }else if (id == PCP_HOST_ID) + atom.readBytes(hit.sessionID.id,16); + else if (id == PCP_HOST_CHANID) + atom.readBytes(chanID.id,16); + else if (id == PCP_HOST_UPHOST_IP) + hit.uphost.ip = atom.readInt(); + else if (id == PCP_HOST_UPHOST_PORT) + hit.uphost.port = atom.readInt(); + else if (id == PCP_HOST_UPHOST_HOPS) + hit.uphostHops = atom.readInt(); + else + { + LOG_DEBUG("PCP skip: %s,%d,%d",id.getString().str(),c,d); + atom.skip(c,d); + } + } + + hit.host = hit.rhost[0]; + hit.chanID = chanID; + + hit.numHops = bcs.numHops; + + hit.servent_id = bcs.servent_id; + + if (flg){ +// LOG_DEBUG("readHostAtoms HITLISTLOCK ON-------------"); + chanMgr->hitlistlock.on(); + if (hit.recv) + chanMgr->addHit(hit); + else + chanMgr->delHit(hit); +// LOG_DEBUG("readHostAtoms HITLISTLOCK OFF-------------"); + chanMgr->hitlistlock.off(); + } + + if (hit.numHops == 1){ + Servent *sv = servMgr->findServentByServentID(hit.servent_id); + if (sv){ +// LOG_DEBUG("set servent's waitPort = %d", hit.host.port); + sv->waitPort = hit.host.port; + } + } +} + +// ------------------------------------------ +void PCPStream::readChanAtoms(AtomStream &atom,int numc,BroadcastState &bcs) +{ +/* Channel *ch=NULL; + ChanHitList *chl=NULL; + ChanInfo newInfo; + + ch = chanMgr->findChannelByID(bcs.chanID); + chl = chanMgr->findHitListByID(bcs.chanID); + + if (ch) + newInfo = ch->info; + else if (chl) + newInfo = chl->info;*/ + + Channel *ch=NULL; + ChanHitList *chl=NULL; + ChanInfo newInfo, chaInfo; + + ch = this->parent; + if (ch){ + newInfo = ch->info; + chaInfo = ch->info; + } + + for(int i=0; ifindChannelByID(newInfo.id); + chl = chanMgr->findHitListByID(newInfo.id); + + }else + { + LOG_DEBUG("PCP skip: %s,%d,%d",id.getString().str(),c,d); + atom.skip(c,d); + } + } + + chl = chanMgr->findHitList(newInfo); + + if (!chl) + chl = chanMgr->addHitList(newInfo); + + if (chl) + { + chl->info.update(newInfo); + + if (!servMgr->chanLog.isEmpty()) + { + //if (chl->numListeners()) + { + try + { + FileStream file; + file.openWriteAppend(servMgr->chanLog.cstr()); + + XML::Node *rn = new XML::Node("update time=\"%d\"",sys->getTime()); + XML::Node *n = chl->info.createChannelXML(); + n->add(chl->createXML(false)); + n->add(chl->info.createTrackXML()); + rn->add(n); + + rn->write(file,0); + delete rn; + file.close(); + }catch(StreamException &e) + { + LOG_ERROR("Unable to update channel log: %s",e.msg); + } + } + } + + } + + if (ch && !ch->isBroadcasting()) + ch->updateInfo(newInfo); + + +} +// ------------------------------------------ +int PCPStream::readBroadcastAtoms(AtomStream &atom,int numc,BroadcastState &bcs) +{ + ChanPacket pack; + int ttl=0; + int ver=0; + int ver_vp=0; + GnuID fromID,destID; + int r=0; + char ver_ex_prefix[2]; + int ver_ex_number = 0; + + fromID.clear(); + destID.clear(); + + bcs.initPacketSettings(); + + MemoryStream pmem(pack.data,sizeof(pack.data)); + AtomStream patom(pmem); + + patom.writeParent(PCP_BCST,numc); + + for(int i=0; isessionID); + + char idstr1[64]; + char idstr2[64]; + + destID.toStr(idstr1); + servMgr->sessionID.toStr(idstr2); + + }else if (id == PCP_BCST_CHANID) + { + atom.readBytes(bcs.chanID.id,16); + patom.writeBytes(id,bcs.chanID.id,16); + }else if (id == PCP_BCST_VERSION) + { + ver = atom.readInt(); + patom.writeInt(id,ver); + }else if (id == PCP_BCST_VERSION_VP) + { + ver_vp = atom.readInt(); + patom.writeInt(id,ver_vp); + }else if (id == PCP_BCST_VERSION_EX_PREFIX) + { + atom.readBytes(ver_ex_prefix,2); + patom.writeBytes(id,ver_ex_prefix,2); + }else if (id == PCP_BCST_VERSION_EX_NUMBER) + { + ver_ex_number = atom.readShort(); + patom.writeShort(id,ver_ex_number); + }else if (id == PCP_HOST) + { + ChanHit hit; + readHostAtoms(atom,c,bcs,hit,false); + if (hit.uphost.ip == 0){ +// LOG_DEBUG("bcs servent_id = %d", bcs.servent_id); + if (bcs.numHops == 1){ + hit.uphost.ip = servMgr->serverHost.ip; + hit.uphost.port = servMgr->serverHost.port; + hit.uphostHops = 1; + } else { + Servent *sv = servMgr->findServentByServentID(bcs.servent_id); + if (sv){ + hit.uphost.ip = sv->getHost().ip; + hit.uphost.port = sv->waitPort; + hit.uphostHops = bcs.numHops - 1; + } + } + } + int oldPos = pmem.pos; + hit.writeAtoms(patom, hit.chanID); + pmem.pos = oldPos; + r = readAtom(patom,bcs); + } else { + // copy and process atoms + int oldPos = pmem.pos; + patom.writeAtoms(id,atom.io,c,d); + pmem.pos = oldPos; + r = readAtom(patom,bcs); + } + } + + char fromStr[64]; + fromStr[0] = 0; + if (fromID.isSet()) + fromID.toStr(fromStr); + char destStr[64]; + destStr[0] = 0; + if (destID.isSet()) + destID.toStr(destStr); + char tmp[64]; + bcs.chanID.toStr(tmp); + +// LOG_DEBUG(tmp); + + if (ver_ex_number){ + LOG_DEBUG("PCP bcst: group=%d, hops=%d, ver=%d(%c%c%04d), from=%s, dest=%s ttl=%d", + bcs.group,bcs.numHops,ver,ver_ex_prefix[0],ver_ex_prefix[1],ver_ex_number,fromStr,destStr,ttl); + } else if (ver_vp){ + LOG_DEBUG("PCP bcst: group=%d, hops=%d, ver=%d(VP%04d), from=%s, dest=%s ttl=%d",bcs.group,bcs.numHops,ver,ver_vp,fromStr,destStr,ttl); + } else { + LOG_DEBUG("PCP bcst: group=%d, hops=%d, ver=%d, from=%s, dest=%s ttl=%d",bcs.group,bcs.numHops,ver,fromStr,destStr,ttl); + } + + if (fromID.isSet()) + if (fromID.isSame(servMgr->sessionID)) + { + LOG_ERROR("BCST loopback"); + return PCP_ERROR_BCST+PCP_ERROR_LOOPBACK; + } + + // broadcast back out if ttl > 0 + if ((ttl>0) && (!bcs.forMe)) + { + pack.len = pmem.pos; + pack.type = ChanPacket::T_PCP; + + if (bcs.group & (/*PCP_BCST_GROUP_ROOT|*/PCP_BCST_GROUP_TRACKERS|PCP_BCST_GROUP_RELAYS)) + { + chanMgr->broadcastPacketUp(pack,bcs.chanID,remoteID,destID); + } + + if (bcs.group & (/*PCP_BCST_GROUP_ROOT|*/PCP_BCST_GROUP_TRACKERS|PCP_BCST_GROUP_RELAYS)) + { + servMgr->broadcastPacket(pack,bcs.chanID,remoteID,destID,Servent::T_COUT); + } + + if (bcs.group & (PCP_BCST_GROUP_RELAYS|PCP_BCST_GROUP_TRACKERS)) + { + servMgr->broadcastPacket(pack,bcs.chanID,remoteID,destID,Servent::T_CIN); + } + + if (bcs.group & (PCP_BCST_GROUP_RELAYS)) + { + servMgr->broadcastPacket(pack,bcs.chanID,remoteID,destID,Servent::T_RELAY); + } + + +// LOG_DEBUG("ttl=%d",ttl); + + } else { +// LOG_DEBUG("ttl=%d",ttl); + } + return r; +} + + +// ------------------------------------------ +int PCPStream::procAtom(AtomStream &atom,ID4 id,int numc, int dlen,BroadcastState &bcs) +{ + int r=0; + ChanHit hit; + int rBan = 0; + + if (id == PCP_CHAN) + { + readChanAtoms(atom,numc,bcs); + }else if (id == PCP_ROOT) + { + if (servMgr->isRoot) + throw StreamException("Unauthorized root message"); + else + readRootAtoms(atom,numc,bcs); + + }else if (id == PCP_HOST) + { + readHostAtoms(atom,numc,bcs,hit); + Channel *ch = chanMgr->findChannelByID(hit.chanID); + if (ch && (ch->isBroadcasting() || servMgr->vpDebug)){ + if (servMgr->autoPort0Kick && (hit.numHops == 1) && (hit.firewalled || (!hit.relay && !hit.numRelays))){ + char tmp[32]; + hit.host.IPtoStr(tmp); + LOG_DEBUG("host that can't relay is disconnect: %s", tmp); + rBan = PCP_ERROR_BANNED; + } + if (servMgr->allowOnlyVP && (hit.numHops == 1) && !hit.version_vp){ + char tmp[32]; + hit.host.IPtoStr(tmp); + LOG_DEBUG("host that is not VP is disconnect: %s", tmp); + rBan = PCP_ERROR_BANNED; + } + } + + }else if ((id == PCP_MESG_ASCII) || (id == PCP_MESG)) // PCP_MESG_ASCII to be depreciated + { + String msg; + atom.readString(msg.data,sizeof(msg.data),dlen); + LOG_DEBUG("PCP got text: %s",msg.cstr()); + }else if (id == PCP_BCST) + { + r = readBroadcastAtoms(atom,numc,bcs); + }else if (id == PCP_HELO) + { + atom.skip(numc,dlen); + atom.writeParent(PCP_OLEH,1); + atom.writeBytes(PCP_HELO_SESSIONID,servMgr->sessionID.id,16); + }else if (id == PCP_PUSH) + { + + readPushAtoms(atom,numc,bcs); + }else if (id == PCP_OK) + { + atom.readInt(); + + }else if (id == PCP_QUIT) + { + r = atom.readInt(); + if (!r) + r = PCP_ERROR_QUIT; + + }else if (id == PCP_ATOM) + { + for(int i=0; igetIniFilename()) + servMgr->loadSettings(peercastApp->getIniFilename()); + + servMgr->start(); +} +// -------------------------------------------------- +void APICALL PeercastInstance::setNotifyMask(int mask) +{ + if (servMgr) + servMgr->notifyMask = mask; +} +// -------------------------------------------------- +int APICALL PeercastInstance::getNotifyMask() +{ + if (servMgr) + return servMgr->notifyMask; + else + return 0; +} + +// -------------------------------------------------- +void APICALL PeercastInstance::setAutoConnect(bool on) +{ + if (servMgr) + servMgr->autoConnect = on; +} +// -------------------------------------------------- +bool APICALL PeercastInstance::getAutoConnect() +{ + if (servMgr) + return servMgr->autoConnect; + else + return false; +} +// -------------------------------------------------- +void APICALL PeercastInstance::setMaxOutput(int kbps) +{ + if (servMgr) + servMgr->maxBitrateOut = kbps; +} +// -------------------------------------------------- +int APICALL PeercastInstance::getMaxOutput() +{ + if (servMgr) + return servMgr->maxBitrateOut; + else + return 0; +} +// -------------------------------------------------- +void APICALL PeercastInstance::setMaxRelays(int max) +{ + if (servMgr) + servMgr->setMaxRelays(max); +} +// -------------------------------------------------- +int APICALL PeercastInstance::getMaxRelays() +{ + if (servMgr) + return servMgr->maxRelays; + else + return 0; +} +// -------------------------------------------------- +void APICALL PeercastInstance::setActive(bool on) +{ + if (servMgr) + { + servMgr->autoConnect = on; + servMgr->autoServe = on; + } +} +// -------------------------------------------------- +bool APICALL PeercastInstance::getActive() +{ + if (servMgr) + return servMgr->autoConnect&&servMgr->autoServe; + else + return false; +} +// -------------------------------------------------- +void APICALL PeercastInstance::saveSettings() +{ + if (servMgr) + servMgr->saveSettings(peercastApp->getIniFilename()); +} +// -------------------------------------------------- +void APICALL PeercastInstance::quit() +{ + isQuitting = true; + if (chanMgr) + chanMgr->quit(); + if (servMgr) + servMgr->quit(); +} +// -------------------------------------------------- +void APICALL PeercastInstance::setServerPort(int port) +{ + if (servMgr) + { + servMgr->serverHost.port = port; + servMgr->restartServer = true; + } +} +// -------------------------------------------------- +int APICALL PeercastInstance::getServerPort() +{ + if (servMgr) + return servMgr->serverHost.port; + else + return 0; +} +// -------------------------------------------------- +void APICALL PeercastInstance::setServerPassword(const char *pwd) +{ + if (servMgr) + strcpy(servMgr->password,pwd); +} +// -------------------------------------------------- +const char *APICALL PeercastInstance::getServerPassword() +{ + return servMgr->password; +} +// -------------------------------------------------- +void APICALL PeercastInstance::callLocalURL(const char *url) +{ + if (sys && servMgr) + sys->callLocalURL(url,servMgr->serverHost.port); +} + + +// -------------------------------------------------- +void ADDLOG(const char *fmt,va_list ap,LogBuffer::TYPE type) +{ + if(sys) + { + const int MAX_LINELEN = 1024; + + char str[MAX_LINELEN+1]; + vsnprintf(str,MAX_LINELEN-1,fmt,ap); + str[MAX_LINELEN-1]=0; + + if (type != LogBuffer::T_NONE) + sys->logBuf->write(str,type); + + peercastApp->printLog(type,str); + } +} +// -------------------------------------------------- +void LOG(const char *fmt,...) +{ + va_list ap; + va_start(ap, fmt); + ADDLOG(fmt,ap,LogBuffer::T_DEBUG); + va_end(ap); +} + +// -------------------------------------------------- +void LOG_ERROR(const char *fmt,...) +{ + if (servMgr) + { + if ((servMgr->showLog & (1<pauseLog)) + { + va_list ap; + va_start(ap, fmt); + ADDLOG(fmt,ap,LogBuffer::T_ERROR); + va_end(ap); + } + } +} +// -------------------------------------------------- +void LOG_DEBUG(const char *fmt,...) +{ + if (servMgr) + { + if ((servMgr->showLog & (1<pauseLog)) + { + va_list ap; + va_start(ap, fmt); + ADDLOG(fmt,ap,LogBuffer::T_DEBUG); + va_end(ap); + } + } +} +// -------------------------------------------------- +void LOG_NETWORK(const char *fmt,...) +{ + if (servMgr) + { + if ((servMgr->showLog & (1<pauseLog)) + { + va_list ap; + va_start(ap, fmt); + ADDLOG(fmt,ap,LogBuffer::T_NETWORK); + va_end(ap); + } + } +} +// -------------------------------------------------- +void LOG_CHANNEL(const char *fmt,...) +{ + if (servMgr) + { + if ((servMgr->showLog & (1<pauseLog)) + { + va_list ap; + va_start(ap, fmt); + ADDLOG(fmt,ap,LogBuffer::T_CHANNEL); + va_end(ap); + } + } +} diff --git a/PeerCast.root/PeerCast/core/common/peercast.h b/PeerCast.root/PeerCast/core/common/peercast.h new file mode 100644 index 0000000..ef8732b --- /dev/null +++ b/PeerCast.root/PeerCast/core/common/peercast.h @@ -0,0 +1,102 @@ +#ifndef _PEERCAST_H +#define _PEERCAST_H + + +//#define APICALL _stdcall +#ifdef WIN32 +#define APICALL _cdecl +#else +#define APICALL +#endif + + +class ChanInfo; +class Sys; + +#include "servmgr.h" + + +// ------------------------------------------------------------ +// This is the interface from the application to the core. +class PeercastInstance +{ +public: + PeercastInstance() + :isQuitting(false) + {} + + virtual void APICALL init(); + + virtual void APICALL setAutoConnect(bool); + virtual bool APICALL getAutoConnect(); + + virtual void APICALL setActive(bool); + virtual bool APICALL getActive(); + + virtual int APICALL getMaxOutput(); + virtual void APICALL setMaxOutput(int); + + virtual int APICALL getMaxRelays(); + virtual void APICALL setMaxRelays(int); + + virtual void APICALL setServerPort(int); + virtual int APICALL getServerPort(); + virtual void APICALL setServerPassword(const char *); + virtual const char *APICALL getServerPassword(); + + virtual void APICALL saveSettings(); + + virtual void APICALL callLocalURL(const char *); + + virtual void APICALL setNotifyMask(int); + virtual int APICALL getNotifyMask(); + + virtual void APICALL quit(); + + virtual Sys * APICALL createSys()=0; + + bool isQuitting; + +}; +// ------------------------------------------------------------ +// This is the interface from the core to the application. +class PeercastApplication +{ +public: + + virtual const char * APICALL getPath() {return "./";} + virtual const char * APICALL getIniFilename() {return "peercast.ini";} + virtual bool APICALL clearTemp() { return false; } //JP-EX + virtual void APICALL openLogFile() {} //JP-EX + virtual void APICALL getDirectory() {} //JP-EX + virtual void APICALL printLog(LogBuffer::TYPE, const char *) {} + virtual void APICALL addChannel(ChanInfo *) {} + virtual void APICALL delChannel(ChanInfo *) {} + virtual void APICALL resetChannels() {} + virtual void APICALL test(char *) {} + virtual const char *APICALL getClientTypeOS() = 0; + virtual void APICALL updateSettings() {} + + virtual void APICALL notifyMessage(ServMgr::NOTIFY_TYPE, const char *) {} + virtual void APICALL channelStart(ChanInfo *) {} + virtual void APICALL channelStop(ChanInfo *) {} + virtual void APICALL channelUpdate(ChanInfo *) {} +}; + + +// ---------------------------------- +extern PeercastInstance *peercastInst; +extern PeercastApplication *peercastApp; + +// ---------------------------------- +#ifdef WIN32 +extern "C" +{ +__declspec( dllexport ) PeercastInstance * newPeercast(PeercastApplication *); +}; +#endif + +// ---------------------------------- + + +#endif diff --git a/PeerCast.root/PeerCast/core/common/rtsp.cpp b/PeerCast.root/PeerCast/core/common/rtsp.cpp new file mode 100644 index 0000000..4101852 --- /dev/null +++ b/PeerCast.root/PeerCast/core/common/rtsp.cpp @@ -0,0 +1,26 @@ +// ------------------------------------------------ +// File : rtsp.cpp +// Date: 4-apr-2002 +// Author: giles +// Desc: +// RTSP protocol handling (experimental) +// +// (c) 2002 peercast.org +// ------------------------------------------------ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// ------------------------------------------------ + +#include "rtsp.h" +#ifdef _DEBUG +#include "chkMemoryLeak.h" +#define DEBUG_NEW new(__FILE__, __LINE__) +#define new DEBUG_NEW +#endif diff --git a/PeerCast.root/PeerCast/core/common/rtsp.h b/PeerCast.root/PeerCast/core/common/rtsp.h new file mode 100644 index 0000000..60bb71d --- /dev/null +++ b/PeerCast.root/PeerCast/core/common/rtsp.h @@ -0,0 +1,32 @@ +// ------------------------------------------------ +// File : rtsp.h +// Date: 4-apr-2002 +// Author: giles +// Desc: +// +// (c) 2002 peercast.org +// ------------------------------------------------ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// ------------------------------------------------ + +#ifndef _RTSP_H +#define _RTSP_H + +#include "http.h" + +// --------------------------------------------- +class RTSP : public HTTP +{ +public: + RTSP(Stream &s):HTTP(s){} +}; + +#endif diff --git a/PeerCast.root/PeerCast/core/common/servent.cpp b/PeerCast.root/PeerCast/core/common/servent.cpp new file mode 100644 index 0000000..1ce8a26 --- /dev/null +++ b/PeerCast.root/PeerCast/core/common/servent.cpp @@ -0,0 +1,3163 @@ +// ------------------------------------------------ +// File : servent.cpp +// Date: 4-apr-2002 +// Author: giles +// Desc: +// Servents are the actual connections between clients. They do the handshaking, +// transfering of data and processing of GnuPackets. Each servent has one socket allocated +// to it on connect, it uses this to transfer all of its data. +// +// (c) 2002 peercast.org +// ------------------------------------------------ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// ------------------------------------------------ +// todo: make lan->yp not check firewall + +#include +#include "servent.h" +#include "sys.h" +#include "gnutella.h" +#include "xml.h" +#include "html.h" +#include "http.h" +#include "stats.h" +#include "servmgr.h" +#include "peercast.h" +#include "atom.h" +#include "pcp.h" +#include "version2.h" +#ifdef _DEBUG +#include "chkMemoryLeak.h" +#define DEBUG_NEW new(__FILE__, __LINE__) +#define new DEBUG_NEW +#endif + + +const int DIRECT_WRITE_TIMEOUT = 60; + +// ----------------------------------- +char *Servent::statusMsgs[]= +{ + "NONE", + "CONNECTING", + "PROTOCOL", + "HANDSHAKE", + "CONNECTED", + "CLOSING", + "LISTENING", + "TIMEOUT", + "REFUSED", + "VERIFIED", + "ERROR", + "WAIT", + "FREE" +}; + +// ----------------------------------- +char *Servent::typeMsgs[]= +{ + "NONE", + "INCOMING", + "SERVER", + "RELAY", + "DIRECT", + "COUT", + "CIN", + "PGNU" +}; +// ----------------------------------- +bool Servent::isPrivate() +{ + Host h = getHost(); + return servMgr->isFiltered(ServFilter::F_PRIVATE,h) || h.isLocalhost(); +} +// ----------------------------------- +bool Servent::isAllowed(int a) +{ + Host h = getHost(); + + if (servMgr->isFiltered(ServFilter::F_BAN,h)) + return false; + + return (allow&a)!=0; +} + +// ----------------------------------- +bool Servent::isFiltered(int f) +{ + Host h = getHost(); + return servMgr->isFiltered(f,h); +} + +int servent_count = 1; +// ----------------------------------- +Servent::Servent(int index) +:outPacketsPri(MAX_OUTPACKETS) +,outPacketsNorm(MAX_OUTPACKETS) +,seenIDs(MAX_HASH) +,serventIndex(index) +,sock(NULL) +,next(NULL) +{ + reset(); + servent_id = servent_count++; + lastSkipTime = 0; + lastSkipCount = 0; + waitPort = 0; +} + +// ----------------------------------- +Servent::~Servent() +{ + +} +// ----------------------------------- +void Servent::kill() +{ + thread.active = false; + + setStatus(S_CLOSING); + + if (pcpStream) + { + PCPStream *pcp = pcpStream; + pcpStream = NULL; + pcp->kill(); + delete pcp; + } + + chanMgr->hitlistlock.on(); + ChanHitList *chl = chanMgr->findHitListByID(chanID); + if (chl) { + ChanHit *chh = chl->hit; + ChanHit *prev = NULL; + while (chh) { + if (chh->servent_id == this->servent_id){ + if ((servMgr->kickKeepTime != 0) && (chh->firewalled == 1)){ + chh->numHops = 0; + chh->numListeners = 0; + chh->numRelays = 0; + prev = chh; + chh = chh->next; + } else { + ChanHit *next = chh->next; + if (prev) + prev->next = next; + else + chl->hit = next; + + char ip0str[64],ip1str[64]; + chh->rhost[0].toStr(ip0str); + chh->rhost[1].toStr(ip1str); + LOG_DEBUG("Delete hit (servent_id=%d): F%dT%dR%d %s/%s", + chh->servent_id,chh->firewalled,chh->tracker,chh->relay,ip0str,ip1str); + + delete chh; + chh = next; + } + } else { + prev = chh; + chh = chh->next; + } + } + } + chanMgr->hitlistlock.off(); + + if (sock) + { + sock->close(); + delete sock; + sock = NULL; + } + + if (pushSock) + { + pushSock->close(); + delete pushSock; + pushSock = NULL; + } + +// thread.unlock(); + + if (type != T_SERVER) + { + reset(); + setStatus(S_FREE); + } + +} +// ----------------------------------- +void Servent::abort() +{ + thread.active = false; + if (sock) + { + sock->close(); + } + +} + +// ----------------------------------- +void Servent::reset() +{ + + remoteID.clear(); + + servPort = 0; + + pcpStream = NULL; + + flowControl = false; + networkID.clear(); + + chanID.clear(); + + outputProtocol = ChanInfo::SP_UNKNOWN; + + agent.clear(); + sock = NULL; + allow = ALLOW_ALL; + syncPos = 0; + addMetadata = false; + nsSwitchNum = 0; + pack.func = 255; + lastConnect = lastPing = lastPacket = 0; + loginPassword[0] = 0; + loginMount[0] = 0; + bytesPerSecond = 0; + priorityConnect = false; + pushSock = NULL; + sendHeader = true; + + outPacketsNorm.reset(); + outPacketsPri.reset(); + + seenIDs.clear(); + + status = S_NONE; + type = T_NONE; + + channel_id = 0; +} +// ----------------------------------- +bool Servent::sendPacket(ChanPacket &pack,GnuID &cid,GnuID &sid,GnuID &did,Servent::TYPE t) +{ + + if ( (type == t) + && (isConnected()) + && (!cid.isSet() || chanID.isSame(cid)) + && (!sid.isSet() || !sid.isSame(remoteID)) + && (pcpStream != NULL) + ) + { + return pcpStream->sendPacket(pack,did); + } + return false; +} + + +// ----------------------------------- +bool Servent::acceptGIV(ClientSocket *givSock) +{ + if (!pushSock) + { + pushSock = givSock; + return true; + }else + return false; +} + +// ----------------------------------- +Host Servent::getHost() +{ + Host h(0,0); + + if (sock) + h = sock->host; + + return h; +} + +// ----------------------------------- +bool Servent::outputPacket(GnuPacket &p, bool pri) +{ + lock.on(); + + bool r=false; + if (pri) + r = outPacketsPri.write(p); + else + { + if (servMgr->useFlowControl) + { + int per = outPacketsNorm.percentFull(); + if (per > 50) + flowControl = true; + else if (per < 25) + flowControl = false; + } + + + bool send=true; + if (flowControl) + { + // if in flowcontrol, only allow packets with less of a hop count than already in queue + if (p.hops >= outPacketsNorm.findMinHop()) + send = false; + } + + if (send) + r = outPacketsNorm.write(p); + } + + lock.off(); + return r; +} + +// ----------------------------------- +bool Servent::initServer(Host &h) +{ + try + { + checkFree(); + + status = S_WAIT; + + createSocket(); + + sock->bind(h); + + thread.data = this; + + thread.func = serverProc; + + type = T_SERVER; + + if (!sys->startThread(&thread)) + throw StreamException("Can`t start thread"); + + }catch(StreamException &e) + { + LOG_ERROR("Bad server: %s",e.msg); + kill(); + return false; + } + + return true; +} +// ----------------------------------- +void Servent::checkFree() +{ + if (sock) + throw StreamException("Socket already set"); + if (thread.active) + throw StreamException("Thread already active"); +} +// ----------------------------------- +void Servent::initIncoming(ClientSocket *s, unsigned int a) +{ + + try{ + + checkFree(); + + type = T_INCOMING; + sock = s; + allow = a; + thread.data = this; + thread.func = incomingProc; + + setStatus(S_PROTOCOL); + + char ipStr[64]; + sock->host.toStr(ipStr); + LOG_DEBUG("Incoming from %s",ipStr); + + + if (!sys->startThread(&thread)) + throw StreamException("Can`t start thread"); + }catch(StreamException &e) + { + //LOG_ERROR("!!FATAL!! Incoming error: %s",e.msg); + //servMgr->shutdownTimer = 1; + kill(); + + LOG_ERROR("INCOMING FAILED: %s",e.msg); + + } +} + +// ----------------------------------- +void Servent::initOutgoing(TYPE ty) +{ + try + { + checkFree(); + + + type = ty; + + thread.data = this; + thread.func = outgoingProc; + + if (!sys->startThread(&thread)) + throw StreamException("Can`t start thread"); + + }catch(StreamException &e) + { + LOG_ERROR("Unable to start outgoing: %s",e.msg); + kill(); + } +} + +// ----------------------------------- +void Servent::initPCP(Host &rh) +{ + char ipStr[64]; + rh.toStr(ipStr); + try + { + checkFree(); + + createSocket(); + + type = T_COUT; + + sock->open(rh); + + if (!isAllowed(ALLOW_NETWORK)) + throw StreamException("Servent not allowed"); + + thread.data = this; + thread.func = outgoingProc; + + LOG_DEBUG("Outgoing to %s",ipStr); + + if (!sys->startThread(&thread)) + throw StreamException("Can`t start thread"); + + }catch(StreamException &e) + { + LOG_ERROR("Unable to open connection to %s - %s",ipStr,e.msg); + kill(); + } +} + +#if 0 +// ----------------------------------- +void Servent::initChannelFetch(Host &host) +{ + type = T_STREAM; + + char ipStr[64]; + host.toStr(ipStr); + + checkFree(); + + createSocket(); + + sock->open(host); + + + if (!isAllowed(ALLOW_DATA)) + throw StreamException("Servent not allowed"); + + sock->connect(); +} +#endif + +// ----------------------------------- +void Servent::initGIV(Host &h, GnuID &id) +{ + char ipStr[64]; + h.toStr(ipStr); + try + { + checkFree(); + + givID = id; + + createSocket(); + + sock->open(h); + + if (!isAllowed(ALLOW_NETWORK)) + throw StreamException("Servent not allowed"); + + sock->connect(); + + thread.data = this; + thread.func = givProc; + + type = T_RELAY; + + if (!sys->startThread(&thread)) + throw StreamException("Can`t start thread"); + + }catch(StreamException &e) + { + LOG_ERROR("GIV error to %s: %s",ipStr,e.msg); + kill(); + } +} +// ----------------------------------- +void Servent::createSocket() +{ + if (sock) + LOG_ERROR("Servent::createSocket attempt made while active"); + + sock = sys->createSocket(); +} +// ----------------------------------- +void Servent::setStatus(STATUS s) +{ + if (s != status) + { + status = s; + + if ((s == S_HANDSHAKE) || (s == S_CONNECTED) || (s == S_LISTENING)) + lastConnect = sys->getTime(); + } + +} + +// ----------------------------------- +void Servent::handshakeOut() +{ + sock->writeLine(GNU_PEERCONN); + + char str[64]; + + sock->writeLineF("%s %s",HTTP_HS_AGENT,PCX_AGENT); + sock->writeLineF("%s %d",PCX_HS_PCP,1); + + if (priorityConnect) + sock->writeLineF("%s %d",PCX_HS_PRIORITY,1); + + if (networkID.isSet()) + { + networkID.toStr(str); + sock->writeLineF("%s %s",PCX_HS_NETWORKID,str); + } + + servMgr->sessionID.toStr(str); + sock->writeLineF("%s %s",PCX_HS_ID,str); + + + sock->writeLineF("%s %s",PCX_HS_OS,peercastApp->getClientTypeOS()); + + sock->writeLine(""); + + HTTP http(*sock); + + int r = http.readResponse(); + + if (r != 200) + { + LOG_ERROR("Expected 200, got %d",r); + throw StreamException("Unexpected HTTP response"); + } + + + bool versionValid = false; + + GnuID clientID; + clientID.clear(); + + while (http.nextHeader()) + { + LOG_DEBUG(http.cmdLine); + + char *arg = http.getArgStr(); + if (!arg) + continue; + + if (http.isHeader(HTTP_HS_AGENT)) + { + agent.set(arg); + + if (strnicmp(arg,"PeerCast/",9)==0) + versionValid = (stricmp(arg+9,MIN_CONNECTVER)>=0); + }else if (http.isHeader(PCX_HS_NETWORKID)) + clientID.fromStr(arg); + } + + if (!clientID.isSame(networkID)) + throw HTTPException(HTTP_SC_UNAVAILABLE,503); + + if (!versionValid) + throw HTTPException(HTTP_SC_UNAUTHORIZED,401); + + + sock->writeLine(GNU_OK); + sock->writeLine(""); + +} + + +// ----------------------------------- +void Servent::processOutChannel() +{ +} + + +// ----------------------------------- +void Servent::handshakeIn() +{ + + int osType=0; + + HTTP http(*sock); + + + bool versionValid = false; + bool diffRootVer = false; + + GnuID clientID; + clientID.clear(); + + while (http.nextHeader()) + { + LOG_DEBUG("%s",http.cmdLine); + + char *arg = http.getArgStr(); + if (!arg) + continue; + + if (http.isHeader(HTTP_HS_AGENT)) + { + agent.set(arg); + + if (strnicmp(arg,"PeerCast/",9)==0) + { + versionValid = (stricmp(arg+9,MIN_CONNECTVER)>=0); + diffRootVer = stricmp(arg+9,MIN_ROOTVER)<0; + } + }else if (http.isHeader(PCX_HS_NETWORKID)) + { + clientID.fromStr(arg); + + }else if (http.isHeader(PCX_HS_PRIORITY)) + { + priorityConnect = atoi(arg)!=0; + + }else if (http.isHeader(PCX_HS_ID)) + { + GnuID id; + id.fromStr(arg); + if (id.isSame(servMgr->sessionID)) + throw StreamException("Servent loopback"); + + }else if (http.isHeader(PCX_HS_OS)) + { + if (stricmp(arg,PCX_OS_LINUX)==0) + osType = 1; + else if (stricmp(arg,PCX_OS_WIN32)==0) + osType = 2; + else if (stricmp(arg,PCX_OS_MACOSX)==0) + osType = 3; + else if (stricmp(arg,PCX_OS_WINAMP2)==0) + osType = 4; + } + + } + + if (!clientID.isSame(networkID)) + throw HTTPException(HTTP_SC_UNAVAILABLE,503); + + // if this is a priority connection and all incoming connections + // are full then kill an old connection to make room. Otherwise reject connection. + //if (!priorityConnect) + { + if (!isPrivate()) + if (servMgr->pubInFull()) + throw HTTPException(HTTP_SC_UNAVAILABLE,503); + } + + if (!versionValid) + throw HTTPException(HTTP_SC_FORBIDDEN,403); + + sock->writeLine(GNU_OK); + + sock->writeLineF("%s %s",HTTP_HS_AGENT,PCX_OLDAGENT); + + if (networkID.isSet()) + { + char idStr[64]; + networkID.toStr(idStr); + sock->writeLineF("%s %s",PCX_HS_NETWORKID,idStr); + } + + if (servMgr->isRoot) + { + sock->writeLineF("%s %d",PCX_HS_FLOWCTL,servMgr->useFlowControl?1:0); + sock->writeLineF("%s %d",PCX_HS_MINBCTTL,chanMgr->minBroadcastTTL); + sock->writeLineF("%s %d",PCX_HS_MAXBCTTL,chanMgr->maxBroadcastTTL); + sock->writeLineF("%s %d",PCX_HS_RELAYBC,servMgr->relayBroadcast); + //sock->writeLine("%s %d",PCX_HS_FULLHIT,2); + + + if (diffRootVer) + { + sock->writeString(PCX_HS_DL); + sock->writeLine(PCX_DL_URL); + } + + sock->writeLineF("%s %s",PCX_HS_MSG,servMgr->rootMsg.cstr()); + } + + + char hostIP[64]; + Host h = sock->host; + h.IPtoStr(hostIP); + sock->writeLineF("%s %s",PCX_HS_REMOTEIP,hostIP); + + + sock->writeLine(""); + + + while (http.nextHeader()); +} + +// ----------------------------------- +bool Servent::pingHost(Host &rhost,GnuID &rsid) +{ + char ipstr[64]; + rhost.toStr(ipstr); + LOG_DEBUG("Ping host %s: trying..",ipstr); + ClientSocket *s=NULL; + bool hostOK=false; + try + { + s = sys->createSocket(); + if (!s) + return false; + else + { + + s->setReadTimeout(15000); + s->setWriteTimeout(15000); + s->open(rhost); + s->connect(); + + AtomStream atom(*s); + + atom.writeInt(PCP_CONNECT,1); + atom.writeParent(PCP_HELO,1); + atom.writeBytes(PCP_HELO_SESSIONID,servMgr->sessionID.id,16); + + GnuID sid; + sid.clear(); + + int numc,numd; + ID4 id = atom.read(numc,numd); + if (id == PCP_OLEH) + { + for(int i=0; iclose(); + delete s; + } + + if (!hostOK) + rhost.port = 0; + + return true; +} + +WLock canStreamLock; + +// ----------------------------------- +bool Servent::handshakeStream(ChanInfo &chanInfo) +{ + + HTTP http(*sock); + + + bool gotPCP=false; + unsigned int reqPos=0; + + nsSwitchNum=0; + + while (http.nextHeader()) + { + char *arg = http.getArgStr(); + if (!arg) + continue; + + if (http.isHeader(PCX_HS_PCP)) + gotPCP = atoi(arg)!=0; + else if (http.isHeader(PCX_HS_POS)) + reqPos = atoi(arg); + else if (http.isHeader("icy-metadata")) + addMetadata = atoi(arg) > 0; + else if (http.isHeader(HTTP_HS_AGENT)) + agent = arg; + else if (http.isHeader("Pragma")) + { + char *ssc = stristr(arg,"stream-switch-count="); + char *so = stristr(arg,"stream-offset"); + + if (ssc || so) + { + nsSwitchNum=1; + //nsSwitchNum = atoi(ssc+20); + } + } + + LOG_DEBUG("Stream: %s",http.cmdLine); + } + + + if ((!gotPCP) && (outputProtocol == ChanInfo::SP_PCP)) + outputProtocol = ChanInfo::SP_PEERCAST; + + if (outputProtocol == ChanInfo::SP_HTTP) + { + if ( (chanInfo.srcProtocol == ChanInfo::SP_MMS) + || (chanInfo.contentType == ChanInfo::T_WMA) + || (chanInfo.contentType == ChanInfo::T_WMV) + || (chanInfo.contentType == ChanInfo::T_ASX) + ) + outputProtocol = ChanInfo::SP_MMS; + } + + + bool chanFound=false; + bool chanReady=false; + + Channel *ch = chanMgr->findChannelByID(chanInfo.id); + if (ch) + { + sendHeader = true; +// if (reqPos) +// { +// streamPos = ch->rawData.findOldestPos(reqPos); +// }else +// { + streamPos = ch->rawData.getLatestPos(); +// } + + chanID = chanInfo.id; + canStreamLock.on(); + chanReady = canStream(ch); + if (!chanReady) type = T_INCOMING; + thread.active = chanReady; + setStatus(S_CONNECTED); + canStreamLock.off(); + channel_id = ch->channel_id; + + //JP-Patch add-s + if (servMgr->isCheckPushStream()) + { + if (chanReady == true) + { + Host h = getHost(); + + if (!h.isLocalhost()) + { + do + { + if (strstr(agent.cstr(),"PeerCast/0.119") != NULL) + { + char strip[256]; + h.toStr(strip); + LOG_ERROR("Block v0.119 Servent : %s (%s)",strip,agent.cstr()); + chanReady = false; + break; + } + +/* ChanHitList *hits[ChanMgr::MAX_HITLISTS]; + int numHits=0; + for(int i=0; ihitlists[i]; + if (chl->isUsed()) + hits[numHits++] = chl; + } + bool isfw = false; + int numRelay = 0; + for(int i=0; iisUsed()) + { + for (int j=0; jhits[j]; + if (hit->host.isValid() && (h.ip == hit->host.ip)) + { + if (hit->firewalled) + isfw = true; + numRelay = hit->numRelays; + } + } + } + } + if ((isfw == true) && (numRelay == 0)) + { + char strip[256]; + h.toStr(strip); + LOG_ERROR("Block firewalled Servent : %s",strip); + chanReady = false; + }*/ + + ChanHitList *chl = chanMgr->findHitList(chanInfo); + ChanHit *hit = chl->hit; + while(hit){ + if (hit->host.isValid() && (h.ip == hit->host.ip)) + { + if ((hit->firewalled) && (hit->numRelays == 0)){ + char strip[256]; + h.toStr(strip); + LOG_ERROR("Block firewalled Servent : %s",strip); + chanReady = false; + } + } + hit = hit->next; + } + }while (0); + } + } + } + //JP-Patch add-e + } + +// LockBlock lockblock(chanMgr->hitlistlock); + +// lockblock.lockon(); + ChanHitList *chl = chanMgr->findHitList(chanInfo); + + if (chl) + { + chanFound = true; + } + + + bool result = false; + + char idStr[64]; + chanInfo.id.toStr(idStr); + + char sidStr[64]; + servMgr->sessionID.toStr(sidStr); + + Host rhost = sock->host; + + + + + AtomStream atom(*sock); + + + + if (!chanFound) + { + sock->writeLine(HTTP_SC_NOTFOUND); + sock->writeLine(""); + LOG_DEBUG("Sending channel not found"); + return false; + } + + + if (!chanReady) + { + if (outputProtocol == ChanInfo::SP_PCP) + { + + char tbuf[8196]; + MemoryStream mem(tbuf, sizeof(tbuf)); + mem.writeLine(HTTP_SC_UNAVAILABLE); + mem.writeLineF("%s %s",HTTP_HS_CONTENT,MIME_XPCP); + mem.writeLine(""); + sock->write(tbuf, mem.getPosition()); + + handshakeIncomingPCP(atom,rhost,remoteID,agent); + + char ripStr[64]; + rhost.toStr(ripStr); + + LOG_DEBUG("Sending channel unavailable"); + + ChanHitSearch chs; + + mem.rewind(); + AtomStream atom2(mem); + + int error = PCP_ERROR_QUIT+PCP_ERROR_UNAVAILABLE; + + chanMgr->hitlistlock.on(); + + chl = chanMgr->findHitList(chanInfo); + + if (chl) + { + ChanHit best; + + // search for up to 8 other hits + int cnt=0; + for(int i=0; i<8; i++) + { + best.init(); + + + // find best hit this network if local IP + if (!rhost.globalIP()) + { + chs.init(); + chs.matchHost = servMgr->serverHost; + chs.waitDelay = 2; + chs.excludeID = remoteID; + if (chl->pickHits(chs)){ + best = chs.best[0]; + LOG_DEBUG("find best hit this network if local IP"); + } + } + + // find best hit on same network + if (!best.host.ip) + { + chs.init(); + chs.matchHost = rhost; + chs.waitDelay = 2; + chs.excludeID = remoteID; + if (chl->pickHits(chs)){ + best = chs.best[0]; + LOG_DEBUG("find best hit on same network"); + } + + } + + // find best hit on other networks +/* if (!best.host.ip) + { + chs.init(); + chs.waitDelay = 2; + chs.excludeID = remoteID; + if (chl->pickHits(chs)){ + best = chs.best[0]; + LOG_DEBUG("find best hit on other networks"); + } + + }*/ + + if (!best.host.ip) + break; + + best.writeAtoms(atom2,chanInfo.id); + cnt++; + } + + if (!best.host.ip){ + char tmp[50]; +// chanMgr->hitlistlock.on(); + int cnt = chs.getRelayHost(servMgr->serverHost, rhost, remoteID, chl); +// chanMgr->hitlistlock.off(); + for (int i = 0; i < cnt; i++){ + chs.best[i].writeAtoms(atom2, chanInfo.id); + chs.best[i].host.toStr(tmp); + LOG_DEBUG("relay info: %s hops = %d", tmp, chs.best[i].numHops); + best.host.ip = chs.best[i].host.ip; + } + } + + if (cnt) + { + LOG_DEBUG("Sent %d channel hit(s) to %s",cnt,ripStr); + + } + else if (rhost.port) + { + // find firewalled host + chs.init(); + chs.waitDelay = 30; + chs.useFirewalled = true; + chs.excludeID = remoteID; + if (chl->pickHits(chs)) + { + best = chs.best[0]; + int cnt = servMgr->broadcastPushRequest(best,rhost,chl->info.id,Servent::T_RELAY); + LOG_DEBUG("Broadcasted channel push request to %d clients for %s",cnt,ripStr); + } + } + + // if all else fails, use tracker + if (!best.host.ip) + { + // find best tracker on this network if local IP + if (!rhost.globalIP()) + { + chs.init(); + chs.matchHost = servMgr->serverHost; + chs.trackersOnly = true; + chs.excludeID = remoteID; + if (chl->pickHits(chs)) + best = chs.best[0]; + + } + + // find local tracker + if (!best.host.ip) + { + chs.init(); + chs.matchHost = rhost; + chs.trackersOnly = true; + chs.excludeID = remoteID; + if (chl->pickHits(chs)) + best = chs.best[0]; + } + + // find global tracker + if (!best.host.ip) + { + chs.init(); + chs.trackersOnly = true; + chs.excludeID = remoteID; + if (chl->pickHits(chs)) + best = chs.best[0]; + } + + if (best.host.ip) + { + best.writeAtoms(atom2,chanInfo.id); + LOG_DEBUG("Sent 1 tracker hit to %s",ripStr); + }else if (rhost.port) + { + // find firewalled tracker + chs.init(); + chs.useFirewalled = true; + chs.trackersOnly = true; + chs.excludeID = remoteID; + chs.waitDelay = 30; + if (chl->pickHits(chs)) + { + best = chs.best[0]; + int cnt = servMgr->broadcastPushRequest(best,rhost,chl->info.id,Servent::T_CIN); + LOG_DEBUG("Broadcasted tracker push request to %d clients for %s",cnt,ripStr); + } + } + + } + + + } + + chanMgr->hitlistlock.off(); + + // return not available yet code + atom2.writeInt(PCP_QUIT,error); + sock->write(tbuf, mem.getPosition()); + result = false; + + /* + char c[512]; + // wait disconnect from other host + try{ + while(sock->read(c, sizeof(c))){ + sys->sleep(10); + } + }catch(StreamException &e){ + LOG_DEBUG("RelayInfoWait: %s",e.msg); + } + */ + }else + { + LOG_DEBUG("Sending channel unavailable"); + sock->writeLine(HTTP_SC_UNAVAILABLE); + sock->writeLine(""); + result = false; + } + + } else { + + if (chanInfo.contentType != ChanInfo::T_MP3) + addMetadata=false; + + if (addMetadata && (outputProtocol == ChanInfo::SP_HTTP)) // winamp mp3 metadata check + { + + sock->writeLine(ICY_OK); + + sock->writeLineF("%s %s",HTTP_HS_SERVER,PCX_AGENT); + sock->writeLineF("icy-name:%s",chanInfo.name.cstr()); + sock->writeLineF("icy-br:%d",chanInfo.bitrate); + sock->writeLineF("icy-genre:%s",chanInfo.genre.cstr()); + sock->writeLineF("icy-url:%s",chanInfo.url.cstr()); + sock->writeLineF("icy-metaint:%d",chanMgr->icyMetaInterval); + sock->writeLineF("%s %s",PCX_HS_CHANNELID,idStr); + + sock->writeLineF("%s %s",HTTP_HS_CONTENT,MIME_MP3); + + }else + { + + sock->writeLine(HTTP_SC_OK); + + if ((chanInfo.contentType != ChanInfo::T_ASX) && (chanInfo.contentType != ChanInfo::T_WMV) && (chanInfo.contentType != ChanInfo::T_WMA)) + { + sock->writeLineF("%s %s",HTTP_HS_SERVER,PCX_AGENT); + + sock->writeLine("Accept-Ranges: none"); + + sock->writeLineF("x-audiocast-name: %s",chanInfo.name.cstr()); + sock->writeLineF("x-audiocast-bitrate: %d",chanInfo.bitrate); + sock->writeLineF("x-audiocast-genre: %s",chanInfo.genre.cstr()); + sock->writeLineF("x-audiocast-description: %s",chanInfo.desc.cstr()); + sock->writeLineF("x-audiocast-url: %s",chanInfo.url.cstr()); + sock->writeLineF("%s %s",PCX_HS_CHANNELID,idStr); + } + + + if (outputProtocol == ChanInfo::SP_HTTP) + { + switch (chanInfo.contentType) + { + case ChanInfo::T_OGG: + sock->writeLineF("%s %s",HTTP_HS_CONTENT,MIME_XOGG); + break; + case ChanInfo::T_MP3: + sock->writeLineF("%s %s",HTTP_HS_CONTENT,MIME_MP3); + break; + case ChanInfo::T_MOV: + sock->writeLine("Connection: close"); + sock->writeLine("Content-Length: 10000000"); + sock->writeLineF("%s %s",HTTP_HS_CONTENT,MIME_MOV); + break; + case ChanInfo::T_MPG: + sock->writeLineF("%s %s",HTTP_HS_CONTENT,MIME_MPG); + break; + case ChanInfo::T_NSV: + sock->writeLineF("%s %s",HTTP_HS_CONTENT,MIME_NSV); + break; + case ChanInfo::T_ASX: + sock->writeLineF("%s %s",HTTP_HS_CONTENT,MIME_ASX); + break; + case ChanInfo::T_WMA: + sock->writeLineF("%s %s",HTTP_HS_CONTENT,MIME_WMA); + break; + case ChanInfo::T_WMV: + sock->writeLineF("%s %s",HTTP_HS_CONTENT,MIME_WMV); + break; + } + } else if (outputProtocol == ChanInfo::SP_MMS) + { + sock->writeLine("Server: Rex/9.0.0.2980"); + sock->writeLine("Cache-Control: no-cache"); + sock->writeLine("Pragma: no-cache"); + sock->writeLine("Pragma: client-id=3587303426"); + sock->writeLine("Pragma: features=\"broadcast,playlist\""); + + if (nsSwitchNum) + { + sock->writeLineF("%s %s",HTTP_HS_CONTENT,MIME_MMS); + }else + { + sock->writeLine("Content-Type: application/vnd.ms.wms-hdr.asfv1"); + if (ch) + sock->writeLineF("Content-Length: %d",ch->headPack.len); + sock->writeLine("Connection: Keep-Alive"); + } + + } else if (outputProtocol == ChanInfo::SP_PCP) + { + sock->writeLineF("%s %d",PCX_HS_POS,streamPos); + sock->writeLineF("%s %s",HTTP_HS_CONTENT,MIME_XPCP); + + }else if (outputProtocol == ChanInfo::SP_PEERCAST) + { + sock->writeLineF("%s %s",HTTP_HS_CONTENT,MIME_XPEERCAST); + } + } + sock->writeLine(""); + result = true; + + if (gotPCP) + { + handshakeIncomingPCP(atom,rhost,remoteID,agent); + atom.writeInt(PCP_OK,0); + } + + } + + + + return result; +} + +// ----------------------------------- +void Servent::handshakeGiv(GnuID &id) +{ + if (id.isSet()) + { + char idstr[64]; + id.toStr(idstr); + sock->writeLineF("GIV /%s",idstr); + }else + sock->writeLine("GIV"); + + sock->writeLine(""); +} + + +// ----------------------------------- +void Servent::processGnutella() +{ + type = T_PGNU; + + //if (servMgr->isRoot && !servMgr->needConnections()) + if (servMgr->isRoot) + { + processRoot(); + return; + } + + + + gnuStream.init(sock); + setStatus(S_CONNECTED); + + if (!servMgr->isRoot) + { + chanMgr->broadcastRelays(this, 1, 1); + GnuPacket *p; + + if ((p=outPacketsNorm.curr())) + gnuStream.sendPacket(*p); + return; + } + + gnuStream.ping(2); + +// if (type != T_LOOKUP) +// chanMgr->broadcastRelays(this,chanMgr->minBroadcastTTL,2); + + lastPacket = lastPing = sys->getTime(); + bool doneBigPing=false; + + const unsigned int abortTimeoutSecs = 60; // abort connection after 60 secs of no activitiy + const unsigned int packetTimeoutSecs = 30; // ping connection after 30 secs of no activity + + unsigned int currBytes=0; + unsigned int lastWait=0; + + unsigned int lastTotalIn=0,lastTotalOut=0; + + while (thread.active && sock->active()) + { + + if (sock->readReady()) + { + lastPacket = sys->getTime(); + + if (gnuStream.readPacket(pack)) + { + char ipstr[64]; + sock->host.toStr(ipstr); + + GnuID routeID; + GnuStream::R_TYPE ret = GnuStream::R_PROCESS; + + if (pack.func != GNU_FUNC_PONG) + if (servMgr->seenPacket(pack)) + ret = GnuStream::R_DUPLICATE; + + seenIDs.add(pack.id); + + + if (ret == GnuStream::R_PROCESS) + { + GnuID routeID; + ret = gnuStream.processPacket(pack,this,routeID); + + if (flowControl && (ret == GnuStream::R_BROADCAST)) + ret = GnuStream::R_DROP; + + } + + switch(ret) + { + case GnuStream::R_BROADCAST: + if (servMgr->broadcast(pack,this)) + stats.add(Stats::NUMBROADCASTED); + else + stats.add(Stats::NUMDROPPED); + break; + case GnuStream::R_ROUTE: + if (servMgr->route(pack,routeID,NULL)) + stats.add(Stats::NUMROUTED); + else + stats.add(Stats::NUMDROPPED); + break; + case GnuStream::R_ACCEPTED: + stats.add(Stats::NUMACCEPTED); + break; + case GnuStream::R_DUPLICATE: + stats.add(Stats::NUMDUP); + break; + case GnuStream::R_DEAD: + stats.add(Stats::NUMDEAD); + break; + case GnuStream::R_DISCARD: + stats.add(Stats::NUMDISCARDED); + break; + case GnuStream::R_BADVERSION: + stats.add(Stats::NUMOLD); + break; + case GnuStream::R_DROP: + stats.add(Stats::NUMDROPPED); + break; + } + + + LOG_NETWORK("packet in: %s-%s, %d bytes, %d hops, %d ttl, from %s",GNU_FUNC_STR(pack.func),GnuStream::getRouteStr(ret),pack.len,pack.hops,pack.ttl,ipstr); + + + + }else{ + LOG_ERROR("Bad packet"); + } + } + + + GnuPacket *p; + + if ((p=outPacketsPri.curr())) // priority packet + { + gnuStream.sendPacket(*p); + seenIDs.add(p->id); + outPacketsPri.next(); + } else if ((p=outPacketsNorm.curr())) // or.. normal packet + { + gnuStream.sendPacket(*p); + seenIDs.add(p->id); + outPacketsNorm.next(); + } + + int lpt = sys->getTime()-lastPacket; + + if (!doneBigPing) + { + if ((sys->getTime()-lastPing) > 15) + { + gnuStream.ping(7); + lastPing = sys->getTime(); + doneBigPing = true; + } + }else{ + if (lpt > packetTimeoutSecs) + { + + if ((sys->getTime()-lastPing) > packetTimeoutSecs) + { + gnuStream.ping(1); + lastPing = sys->getTime(); + } + + } + } + if (lpt > abortTimeoutSecs) + throw TimeoutException(); + + + unsigned int totIn = sock->totalBytesIn-lastTotalIn; + unsigned int totOut = sock->totalBytesOut-lastTotalOut; + + unsigned int bytes = totIn+totOut; + + lastTotalIn = sock->totalBytesIn; + lastTotalOut = sock->totalBytesOut; + + const int serventBandwidth = 1000; + + int delay = sys->idleSleepTime; + if ((bytes) && (serventBandwidth >= 8)) + delay = (bytes*1000)/(serventBandwidth/8); // set delay relative packetsize + + if (delay < (int)sys->idleSleepTime) + delay = sys->idleSleepTime; + //LOG("delay %d, in %d, out %d",delay,totIn,totOut); + + sys->sleep(delay); + } + +} + + +// ----------------------------------- +void Servent::processRoot() +{ + try + { + + gnuStream.init(sock); + setStatus(S_CONNECTED); + + gnuStream.ping(2); + + unsigned int lastConnect = sys->getTime(); + + while (thread.active && sock->active()) + { + if (gnuStream.readPacket(pack)) + { + char ipstr[64]; + sock->host.toStr(ipstr); + + LOG_NETWORK("packet in: %d from %s",pack.func,ipstr); + + + if (pack.func == GNU_FUNC_PING) // if ping then pong back some hosts and close + { + + Host hl[32]; + int cnt = servMgr->getNewestServents(hl,32,sock->host); + if (cnt) + { + int start = sys->rnd() % cnt; + int max = cnt>8?8:cnt; + + for(int i=0; ihost.toStr(str); + LOG_NETWORK("Sent %d pong(s) to %s",max,str); + }else + { + LOG_NETWORK("No Pongs to send"); + //return; + } + }else if (pack.func == GNU_FUNC_PONG) // pong? + { + MemoryStream pong(pack.data,pack.len); + + int ip,port; + port = pong.readShort(); + ip = pong.readLong(); + ip = SWAP4(ip); + + + Host h(ip,port); + if ((ip) && (port) && (h.globalIP())) + { + + LOG_NETWORK("added pong: %d.%d.%d.%d:%d",ip>>24&0xff,ip>>16&0xff,ip>>8&0xff,ip&0xff,port); + servMgr->addHost(h,ServHost::T_SERVENT,sys->getTime()); + } + //return; + } else if (pack.func == GNU_FUNC_HIT) + { + MemoryStream data(pack.data,pack.len); + ChanHit hit; + gnuStream.readHit(data,hit,pack.hops,pack.id); + } + + //if (gnuStream.packetsIn > 5) // die if we get too many packets + // return; + } + + if((sys->getTime()-lastConnect > 60)) + break; + } + + + }catch(StreamException &e) + { + LOG_ERROR("Relay: %s",e.msg); + } + + +} + +// ----------------------------------- +int Servent::givProc(ThreadInfo *thread) +{ +// thread->lock(); + Servent *sv = (Servent*)thread->data; + try + { + sv->handshakeGiv(sv->givID); + sv->handshakeIncoming(); + + }catch(StreamException &e) + { + LOG_ERROR("GIV: %s",e.msg); + } + + sv->kill(); + sys->endThread(thread); + return 0; +} + +// ----------------------------------- +void Servent::handshakeOutgoingPCP(AtomStream &atom, Host &rhost, GnuID &rid, String &agent, bool isTrusted) +{ + + bool nonFW = (servMgr->getFirewall() != ServMgr::FW_ON); + bool testFW = (servMgr->getFirewall() == ServMgr::FW_UNKNOWN); + + bool sendBCID = isTrusted && chanMgr->isBroadcasting(); + + char tbuf[1024]; + MemoryStream mem(tbuf, sizeof(tbuf)); + AtomStream atom2(mem); + atom2.writeParent(PCP_HELO,3 + (testFW?1:0) + (nonFW?1:0) + (sendBCID?1:0)); + atom2.writeString(PCP_HELO_AGENT,PCX_AGENT); + atom2.writeInt(PCP_HELO_VERSION,PCP_CLIENT_VERSION); + atom2.writeBytes(PCP_HELO_SESSIONID,servMgr->sessionID.id,16); + if (nonFW) + atom2.writeShort(PCP_HELO_PORT,servMgr->serverHost.port); + if (testFW) + atom2.writeShort(PCP_HELO_PING,servMgr->serverHost.port); + if (sendBCID) + atom2.writeBytes(PCP_HELO_BCID,chanMgr->broadcastID.id,16); + atom.io.write(tbuf, mem.getPosition()); + + + LOG_DEBUG("PCP outgoing waiting for OLEH.."); + + int numc,numd; + ID4 id = atom.read(numc,numd); + if (id != PCP_OLEH) + { + LOG_DEBUG("PCP outgoing reply: %s",id.getString().str()); + atom.writeInt(PCP_QUIT,PCP_ERROR_QUIT+PCP_ERROR_BADRESPONSE); + throw StreamException("Got unexpected PCP response"); + } + + + + char arg[64]; + + GnuID clientID; + clientID.clear(); + rid.clear(); + int version=0; + int disable=0; + + Host thisHost; + + // read OLEH response + for(int i=0; isessionID)) + throw StreamException("Servent loopback"); + + }else + { + LOG_DEBUG("PCP handshake skip: %s",id.getString().str()); + atom.skip(c,dlen); + } + + } + + + // update server ip/firewall status + if (isTrusted) + { + if (thisHost.isValid()) + { + if ((servMgr->serverHost.ip != thisHost.ip) && (servMgr->forceIP.isEmpty())) + { + char ipstr[64]; + thisHost.toStr(ipstr); + LOG_DEBUG("Got new ip: %s",ipstr); + servMgr->serverHost.ip = thisHost.ip; + } + + if (servMgr->getFirewall() == ServMgr::FW_UNKNOWN) + { + if (thisHost.port && thisHost.globalIP()) + servMgr->setFirewall(ServMgr::FW_OFF); + else + servMgr->setFirewall(ServMgr::FW_ON); + } + } + + if (disable == 1) + { + LOG_ERROR("client disabled: %d",disable); + servMgr->isDisabled = true; + }else + { + servMgr->isDisabled = false; + } + } + + + + if (!rid.isSet()) + { + atom.writeInt(PCP_QUIT,PCP_ERROR_QUIT+PCP_ERROR_NOTIDENTIFIED); + throw StreamException("Remote host not identified"); + } + + LOG_DEBUG("PCP Outgoing handshake complete."); + +} + +// ----------------------------------- +void Servent::handshakeIncomingPCP(AtomStream &atom, Host &rhost, GnuID &rid, String &agent) +{ + int numc,numd; + ID4 id = atom.read(numc,numd); + + + if (id != PCP_HELO) + { + LOG_DEBUG("PCP incoming reply: %s",id.getString().str()); + atom.writeInt(PCP_QUIT,PCP_ERROR_QUIT+PCP_ERROR_BADRESPONSE); + throw StreamException("Got unexpected PCP response"); + } + + char arg[64]; + + ID4 osType; + + int version=0; + + int pingPort=0; + + GnuID bcID; + GnuID clientID; + + bcID.clear(); + clientID.clear(); + + rhost.port = 0; + + for(int i=0; isessionID)) + throw StreamException("Servent loopback"); + + }else if (id == PCP_HELO_BCID) + { + atom.readBytes(bcID.id,16); + + }else if (id == PCP_HELO_OSTYPE) + { + osType = atom.readInt(); + }else if (id == PCP_HELO_PORT) + { + rhost.port = atom.readShort(); + }else if (id == PCP_HELO_PING) + { + pingPort = atom.readShort(); + }else + { + LOG_DEBUG("PCP handshake skip: %s",id.getString().str()); + atom.skip(c,dlen); + } + + } + + if (version) + LOG_DEBUG("Incoming PCP is %s : v%d", agent.cstr(),version); + + + if (!rhost.globalIP() && servMgr->serverHost.globalIP()) + rhost.ip = servMgr->serverHost.ip; + + if (pingPort) + { + char ripStr[64]; + rhost.toStr(ripStr); + LOG_DEBUG("Incoming firewalled test request: %s ", ripStr); + rhost.port = pingPort; + if (!rhost.globalIP() || !pingHost(rhost,rid)) + rhost.port = 0; + } + + if (servMgr->isRoot) + { + if (bcID.isSet()) + { + if (bcID.getFlags() & 1) // private + { + BCID *bcid = servMgr->findValidBCID(bcID); + if (!bcid || (bcid && !bcid->valid)) + { + atom.writeParent(PCP_OLEH,1); + atom.writeInt(PCP_HELO_DISABLE,1); + throw StreamException("Client is banned"); + } + } + } + } + + + char tbuf[1024]; + MemoryStream mem(tbuf, sizeof(tbuf)); + AtomStream atom2(mem); + atom2.writeParent(PCP_OLEH,5); + atom2.writeString(PCP_HELO_AGENT,PCX_AGENT); + atom2.writeBytes(PCP_HELO_SESSIONID,servMgr->sessionID.id,16); + atom2.writeInt(PCP_HELO_VERSION,PCP_CLIENT_VERSION); + atom2.writeInt(PCP_HELO_REMOTEIP,rhost.ip); + atom2.writeShort(PCP_HELO_PORT,rhost.port); + + if (version) + { + if (version < PCP_CLIENT_MINVERSION) + { + atom2.writeInt(PCP_QUIT,PCP_ERROR_QUIT+PCP_ERROR_BADAGENT); + atom.io.write(tbuf, mem.getPosition()); + throw StreamException("Agent is not valid"); + } + } + + if (!rid.isSet()) + { + atom2.writeInt(PCP_QUIT,PCP_ERROR_QUIT+PCP_ERROR_NOTIDENTIFIED); + atom.io.write(tbuf, mem.getPosition()); + throw StreamException("Remote host not identified"); + } + + + + if (servMgr->isRoot) + { + servMgr->writeRootAtoms(atom2,false); + } + + atom.io.write(tbuf, mem.getPosition()); + + LOG_DEBUG("PCP Incoming handshake complete."); + +} + +// ----------------------------------- +void Servent::processIncomingPCP(bool suggestOthers) +{ + PCPStream::readVersion(*sock); + + + AtomStream atom(*sock); + Host rhost = sock->host; + + handshakeIncomingPCP(atom,rhost,remoteID,agent); + + + bool alreadyConnected = (servMgr->findConnection(Servent::T_COUT,remoteID)!=NULL) + || (servMgr->findConnection(Servent::T_CIN,remoteID)!=NULL); + bool unavailable = servMgr->controlInFull(); + bool offair = !servMgr->isRoot && !chanMgr->isBroadcasting(); + + char rstr[64]; + rhost.toStr(rstr); + + if (unavailable || alreadyConnected || offair) + { + int error; + + if (alreadyConnected) + error = PCP_ERROR_QUIT+PCP_ERROR_ALREADYCONNECTED; + else if (unavailable) + error = PCP_ERROR_QUIT+PCP_ERROR_UNAVAILABLE; + else if (offair) + error = PCP_ERROR_QUIT+PCP_ERROR_OFFAIR; + else + error = PCP_ERROR_QUIT; + + + if (suggestOthers) + { + + ChanHit best; + ChanHitSearch chs; + + int cnt=0; + for(int i=0; i<8; i++) + { + best.init(); + + // find best hit on this network + if (!rhost.globalIP()) + { + chs.init(); + chs.matchHost = servMgr->serverHost; + chs.waitDelay = 2; + chs.excludeID = remoteID; + chs.trackersOnly = true; + chs.useBusyControls = false; + if (chanMgr->pickHits(chs)) + best = chs.best[0]; + } + + // find best hit on same network + if (!best.host.ip) + { + chs.init(); + chs.matchHost = rhost; + chs.waitDelay = 2; + chs.excludeID = remoteID; + chs.trackersOnly = true; + chs.useBusyControls = false; + if (chanMgr->pickHits(chs)) + best = chs.best[0]; + } + + // else find best hit on other networks + if (!best.host.ip) + { + chs.init(); + chs.waitDelay = 2; + chs.excludeID = remoteID; + chs.trackersOnly = true; + chs.useBusyControls = false; + if (chanMgr->pickHits(chs)) + best = chs.best[0]; + } + + if (!best.host.ip) + break; + + GnuID noID; + noID.clear(); + best.writeAtoms(atom,noID); + cnt++; + } + if (cnt) + { + LOG_DEBUG("Sent %d tracker(s) to %s",cnt,rstr); + } + else if (rhost.port) + { + // send push request to best firewalled tracker on other network + chs.init(); + chs.waitDelay = 30; + chs.excludeID = remoteID; + chs.trackersOnly = true; + chs.useFirewalled = true; + chs.useBusyControls = false; + if (chanMgr->pickHits(chs)) + { + best = chs.best[0]; + GnuID noID; + noID.clear(); + int cnt = servMgr->broadcastPushRequest(best,rhost,noID,Servent::T_CIN); + LOG_DEBUG("Broadcasted tracker push request to %d clients for %s",cnt,rstr); + } + }else + { + LOG_DEBUG("No available trackers"); + } + } + + + LOG_ERROR("Sending QUIT to incoming: %d",error); + + atom.writeInt(PCP_QUIT,error); + return; + } + + + type = T_CIN; + setStatus(S_CONNECTED); + + atom.writeInt(PCP_OK,0); + + // ask for update + atom.writeParent(PCP_ROOT,1); + atom.writeParent(PCP_ROOT_UPDATE,0); + + pcpStream = new PCPStream(remoteID); + + int error = 0; + BroadcastState bcs; + while (!error && thread.active && !sock->eof()) + { + error = pcpStream->readPacket(*sock,bcs); + sys->sleepIdle(); + + if (!servMgr->isRoot && !chanMgr->isBroadcasting()) + error = PCP_ERROR_OFFAIR; + if (peercastInst->isQuitting) + error = PCP_ERROR_SHUTDOWN; + } + + pcpStream->flush(*sock); + + error += PCP_ERROR_QUIT; + atom.writeInt(PCP_QUIT,error); + + LOG_DEBUG("PCP Incoming to %s closed: %d",rstr,error); + +} + +// ----------------------------------- +int Servent::outgoingProc(ThreadInfo *thread) +{ +// thread->lock(); + LOG_DEBUG("COUT started"); + + Servent *sv = (Servent*)thread->data; + + GnuID noID; + noID.clear(); + sv->pcpStream = new PCPStream(noID); + + while (sv->thread.active) + { + sv->setStatus(S_WAIT); + + if (chanMgr->isBroadcasting() && servMgr->autoServe) + { + ChanHit bestHit; + ChanHitSearch chs; + char ipStr[64]; + + do + { + bestHit.init(); + + if (servMgr->rootHost.isEmpty()) + break; + + if (sv->pushSock) + { + sv->sock = sv->pushSock; + sv->pushSock = NULL; + bestHit.host = sv->sock->host; + break; + } + + GnuID noID; + noID.clear(); + ChanHitList *chl = chanMgr->findHitListByID(noID); + if (chl) + { + // find local tracker + chs.init(); + chs.matchHost = servMgr->serverHost; + chs.waitDelay = MIN_TRACKER_RETRY; + chs.excludeID = servMgr->sessionID; + chs.trackersOnly = true; + if (!chl->pickHits(chs)) + { + // else find global tracker + chs.init(); + chs.waitDelay = MIN_TRACKER_RETRY; + chs.excludeID = servMgr->sessionID; + chs.trackersOnly = true; + chl->pickHits(chs); + } + + if (chs.numResults) + { + bestHit = chs.best[0]; + } + } + + + unsigned int ctime = sys->getTime(); + + if ((!bestHit.host.ip) && ((ctime-chanMgr->lastYPConnect) > MIN_YP_RETRY)) + { + bestHit.host.fromStrName(servMgr->rootHost.cstr(),DEFAULT_PORT); + bestHit.yp = true; + chanMgr->lastYPConnect = ctime; + } + sys->sleepIdle(); + + }while (!bestHit.host.ip && (sv->thread.active)); + + + if (!bestHit.host.ip) // give up + { + LOG_ERROR("COUT giving up"); + break; + } + + + bestHit.host.toStr(ipStr); + + int error=0; + try + { + + LOG_DEBUG("COUT to %s: Connecting..",ipStr); + + if (!sv->sock) + { + sv->setStatus(S_CONNECTING); + sv->sock = sys->createSocket(); + if (!sv->sock) + throw StreamException("Unable to create socket"); + sv->sock->open(bestHit.host); + sv->sock->connect(); + + } + + sv->sock->setReadTimeout(30000); + AtomStream atom(*sv->sock); + + sv->setStatus(S_HANDSHAKE); + + Host rhost = sv->sock->host; + atom.writeInt(PCP_CONNECT,1); + handshakeOutgoingPCP(atom,rhost,sv->remoteID,sv->agent,bestHit.yp); + + sv->setStatus(S_CONNECTED); + + LOG_DEBUG("COUT to %s: OK",ipStr); + + sv->pcpStream->init(sv->remoteID); + + BroadcastState bcs; + bcs.servent_id = sv->servent_id; + error = 0; + while (!error && sv->thread.active && !sv->sock->eof() && servMgr->autoServe) + { + error = sv->pcpStream->readPacket(*sv->sock,bcs); + + sys->sleepIdle(); + + if (!chanMgr->isBroadcasting()) + error = PCP_ERROR_OFFAIR; + if (peercastInst->isQuitting) + error = PCP_ERROR_SHUTDOWN; + + if (sv->pcpStream->nextRootPacket) + if (sys->getTime() > (sv->pcpStream->nextRootPacket+30)) + error = PCP_ERROR_NOROOT; + } + sv->setStatus(S_CLOSING); + + sv->pcpStream->flush(*sv->sock); + + error += PCP_ERROR_QUIT; + atom.writeInt(PCP_QUIT,error); + + LOG_ERROR("COUT to %s closed: %d",ipStr,error); + + }catch(TimeoutException &e) + { + LOG_ERROR("COUT to %s: timeout (%s)",ipStr,e.msg); + sv->setStatus(S_TIMEOUT); + }catch(StreamException &e) + { + LOG_ERROR("COUT to %s: %s",ipStr,e.msg); + sv->setStatus(S_ERROR); + } + + try + { + if (sv->sock) + { + sv->sock->close(); + delete sv->sock; + sv->sock = NULL; + } + + }catch(StreamException &) {} + + // don`t discard this hit if we caused the disconnect (stopped broadcasting) + if (error != (PCP_ERROR_QUIT+PCP_ERROR_OFFAIR)) + chanMgr->deadHit(bestHit); + + } + + sys->sleepIdle(); + } + + sv->kill(); + sys->endThread(thread); + LOG_DEBUG("COUT ended"); + return 0; +} +// ----------------------------------- +int Servent::incomingProc(ThreadInfo *thread) +{ +// thread->lock(); + + Servent *sv = (Servent*)thread->data; + + char ipStr[64]; + sv->sock->host.toStr(ipStr); + + try + { + sv->handshakeIncoming(); + }catch(HTTPException &e) + { + try + { + sv->sock->writeLine(e.msg); + if (e.code == 401) + sv->sock->writeLine("WWW-Authenticate: Basic realm=\"PeerCast\""); + sv->sock->writeLine(""); + }catch(StreamException &){} + LOG_ERROR("Incoming from %s: %s",ipStr,e.msg); + }catch(StreamException &e) + { + LOG_ERROR("Incoming from %s: %s",ipStr,e.msg); + } + + + sv->kill(); + sys->endThread(thread); + return 0; +} +// ----------------------------------- +void Servent::processServent() +{ + setStatus(S_HANDSHAKE); + + handshakeIn(); + + if (!sock) + throw StreamException("Servent has no socket"); + + processGnutella(); +} + +// ----------------------------------- +void Servent::processStream(bool doneHandshake,ChanInfo &chanInfo) +{ + if (!doneHandshake) + { + setStatus(S_HANDSHAKE); + + if (!handshakeStream(chanInfo)) + return; + } + + if (chanInfo.id.isSet()) + { + + chanID = chanInfo.id; + + LOG_CHANNEL("Sending channel: %s ",ChanInfo::getProtocolStr(outputProtocol)); + + if (!waitForChannelHeader(chanInfo)) + throw StreamException("Channel not ready"); + + servMgr->totalStreams++; + + Host host = sock->host; + host.port = 0; // force to 0 so we ignore the incoming port + + Channel *ch = chanMgr->findChannelByID(chanID); + if (!ch) + throw StreamException("Channel not found"); + + if (outputProtocol == ChanInfo::SP_HTTP) + { + if ((addMetadata) && (chanMgr->icyMetaInterval)) + sendRawMetaChannel(chanMgr->icyMetaInterval); + else + sendRawChannel(true,true); + + }else if (outputProtocol == ChanInfo::SP_MMS) + { + if (nsSwitchNum) + { + sendRawChannel(true,true); + }else + { + sendRawChannel(true,false); + } + + }else if (outputProtocol == ChanInfo::SP_PCP) + { + sendPCPChannel(); + + } else if (outputProtocol == ChanInfo::SP_PEERCAST) + { + sendPeercastChannel(); + } + } + + setStatus(S_CLOSING); +} + +// ----------------------------------------- +#if 0 +// debug + FileStream file; + file.openReadOnly("c://test.mp3"); + + LOG_DEBUG("raw file read"); + char buf[4000]; + int cnt=0; + while (!file.eof()) + { + LOG_DEBUG("send %d",cnt++); + file.read(buf,sizeof(buf)); + sock->write(buf,sizeof(buf)); + + } + file.close(); + LOG_DEBUG("raw file sent"); + + return; +// debug +#endif +// ----------------------------------- +bool Servent::waitForChannelHeader(ChanInfo &info) +{ + for(int i=0; i<30*10; i++) + { + Channel *ch = chanMgr->findChannelByID(info.id); + if (!ch) + return false; + + if (ch->isPlaying() && (ch->rawData.writePos>0)) + return true; + + if (!thread.active || !sock->active()) + break; + sys->sleep(100); + } + return false; +} +// ----------------------------------- +void Servent::sendRawChannel(bool sendHead, bool sendData) +{ + try + { + + sock->setWriteTimeout(DIRECT_WRITE_TIMEOUT*1000); + + Channel *ch = chanMgr->findChannelByID(chanID); + if (!ch) + throw StreamException("Channel not found"); + + setStatus(S_CONNECTED); + + LOG_DEBUG("Starting Raw stream of %s at %d",ch->info.name.cstr(),streamPos); + + if (sendHead) + { + ch->headPack.writeRaw(*sock); + streamPos = ch->headPack.pos + ch->headPack.len; + LOG_DEBUG("Sent %d bytes header ",ch->headPack.len); + } + + if (sendData) + { + + unsigned int streamIndex = ch->streamIndex; + unsigned int connectTime = sys->getTime(); + unsigned int lastWriteTime = connectTime; + + while ((thread.active) && sock->active()) + { + ch = chanMgr->findChannelByID(chanID); + + if (ch) + { + + if (streamIndex != ch->streamIndex) + { + streamIndex = ch->streamIndex; + streamPos = ch->headPack.pos; + LOG_DEBUG("sendRaw got new stream index"); + } + + ChanPacket rawPack; + if (ch->rawData.findPacket(streamPos,rawPack)) + { + if (syncPos != rawPack.sync) + LOG_ERROR("Send skip: %d",rawPack.sync-syncPos); + syncPos = rawPack.sync+1; + + if ((rawPack.type == ChanPacket::T_DATA) || (rawPack.type == ChanPacket::T_HEAD)) + { + rawPack.writeRaw(*sock); + lastWriteTime = sys->getTime(); + } + + if (rawPack.pos < streamPos) + LOG_DEBUG("raw: skip back %d",rawPack.pos-streamPos); + streamPos = rawPack.pos+rawPack.len; + } else if (sock->readReady()) { + char c; + int error = sock->readUpto(&c, 1); + if (error == 0) sock->close(); + } + } + + if ((sys->getTime()-lastWriteTime) > DIRECT_WRITE_TIMEOUT) + throw TimeoutException(); + + sys->sleepIdle(); + } + } + }catch(StreamException &e) + { + LOG_ERROR("Stream channel: %s",e.msg); + } +} + +#if 0 +// ----------------------------------- +void Servent::sendRawMultiChannel(bool sendHead, bool sendData) +{ + try + { + unsigned int chanStreamIndex[ChanMgr::MAX_CHANNELS]; + unsigned int chanStreamPos[ChanMgr::MAX_CHANNELS]; + GnuID chanIDs[ChanMgr::MAX_CHANNELS]; + int numChanIDs=0; + for(int i=0; ichannels[i]; + if (ch->isPlaying()) + chanIDs[numChanIDs++]=ch->info.id; + } + + + + setStatus(S_CONNECTED); + + + if (sendHead) + { + for(int i=0; ifindChannelByID(chanIDs[i]); + if (ch) + { + LOG_DEBUG("Starting RawMulti stream: %s",ch->info.name.cstr()); + ch->headPack.writeRaw(*sock); + chanStreamPos[i] = ch->headPack.pos + ch->headPack.len; + chanStreamIndex[i] = ch->streamIndex; + LOG_DEBUG("Sent %d bytes header",ch->headPack.len); + + } + } + } + + if (sendData) + { + + unsigned int connectTime=sys->getTime(); + + while ((thread.active) && sock->active()) + { + + for(int i=1; ifindChannelByID(chanIDs[i]); + if (ch) + { + if (chanStreamIndex[i] != ch->streamIndex) + { + chanStreamIndex[i] = ch->streamIndex; + chanStreamPos[i] = ch->headPack.pos; + LOG_DEBUG("sendRawMulti got new stream index for chan %d",i); + } + + ChanPacket rawPack; + if (ch->rawData.findPacket(chanStreamPos[i],rawPack)) + { + if ((rawPack.type == ChanPacket::T_DATA) || (rawPack.type == ChanPacket::T_HEAD)) + rawPack.writeRaw(*sock); + + + if (rawPack.pos < chanStreamPos[i]) + LOG_DEBUG("raw: skip back %d",rawPack.pos-chanStreamPos[i]); + chanStreamPos[i] = rawPack.pos+rawPack.len; + + + //LOG("raw at %d: %d %d",streamPos,ch->rawData.getStreamPos(ch->rawData.firstPos),ch->rawData.getStreamPos(ch->rawData.lastPos)); + } + } + break; + } + + + sys->sleepIdle(); + } + } + }catch(StreamException &e) + { + LOG_ERROR("Stream channel: %s",e.msg); + } +} +#endif + +// ----------------------------------- +void Servent::sendRawMetaChannel(int interval) +{ + + try + { + Channel *ch = chanMgr->findChannelByID(chanID); + if (!ch) + throw StreamException("Channel not found"); + + sock->setWriteTimeout(DIRECT_WRITE_TIMEOUT*1000); + + setStatus(S_CONNECTED); + + LOG_DEBUG("Starting Raw Meta stream of %s (metaint: %d) at %d",ch->info.name.cstr(),interval,streamPos); + + + String lastTitle,lastURL; + + int lastMsgTime=sys->getTime(); + bool showMsg=true; + + char buf[16384]; + int bufPos=0; + + if ((interval > sizeof(buf)) || (interval < 1)) + throw StreamException("Bad ICY Meta Interval value"); + + unsigned int connectTime = sys->getTime(); + unsigned int lastWriteTime = connectTime; + + streamPos = 0; // raw meta channel has no header (its MP3) + + while ((thread.active) && sock->active()) + { + ch = chanMgr->findChannelByID(chanID); + + if (ch) + { + + ChanPacket rawPack; + if (ch->rawData.findPacket(streamPos,rawPack)) + { + + if (syncPos != rawPack.sync) + LOG_ERROR("Send skip: %d",rawPack.sync-syncPos); + syncPos = rawPack.sync+1; + + MemoryStream mem(rawPack.data,rawPack.len); + + if (rawPack.type == ChanPacket::T_DATA) + { + + int len = rawPack.len; + char *p = rawPack.data; + while (len) + { + int rl = len; + if ((bufPos+rl) > interval) + rl = interval-bufPos; + memcpy(&buf[bufPos],p,rl); + bufPos+=rl; + p+=rl; + len-=rl; + + if (bufPos >= interval) + { + bufPos = 0; + sock->write(buf,interval); + lastWriteTime = sys->getTime(); + + if (chanMgr->broadcastMsgInterval) + if ((sys->getTime()-lastMsgTime) >= chanMgr->broadcastMsgInterval) + { + showMsg ^= true; + lastMsgTime = sys->getTime(); + } + + String *metaTitle = &ch->info.track.title; + if (!ch->info.comment.isEmpty() && (showMsg)) + metaTitle = &ch->info.comment; + + + if (!metaTitle->isSame(lastTitle) || !ch->info.url.isSame(lastURL)) + { + + char tmp[1024]; + String title,url; + + title = *metaTitle; + url = ch->info.url; + + title.convertTo(String::T_META); + url.convertTo(String::T_META); + + sprintf(tmp,"StreamTitle='%s';StreamUrl='%s';\0",title.cstr(),url.cstr()); + int len = ((strlen(tmp) + 15+1) / 16); + sock->writeChar(len); + sock->write(tmp,len*16); + + lastTitle = *metaTitle; + lastURL = ch->info.url; + + LOG_DEBUG("StreamTitle: %s, StreamURL: %s",lastTitle.cstr(),lastURL.cstr()); + + }else + { + sock->writeChar(0); + } + + } + } + } + streamPos = rawPack.pos + rawPack.len; + } + } + if ((sys->getTime()-lastWriteTime) > DIRECT_WRITE_TIMEOUT) + throw TimeoutException(); + + sys->sleepIdle(); + + } + }catch(StreamException &e) + { + LOG_ERROR("Stream channel: %s",e.msg); + } +} +// ----------------------------------- +void Servent::sendPeercastChannel() +{ + try + { + setStatus(S_CONNECTED); + + Channel *ch = chanMgr->findChannelByID(chanID); + if (!ch) + throw StreamException("Channel not found"); + + LOG_DEBUG("Starting PeerCast stream: %s",ch->info.name.cstr()); + + sock->writeTag("PCST"); + + ChanPacket pack; + + ch->headPack.writePeercast(*sock); + + pack.init(ChanPacket::T_META,ch->insertMeta.data,ch->insertMeta.len,ch->streamPos); + pack.writePeercast(*sock); + + streamPos = 0; + unsigned int syncPos=0; + while ((thread.active) && sock->active()) + { + ch = chanMgr->findChannelByID(chanID); + if (ch) + { + + ChanPacket rawPack; + if (ch->rawData.findPacket(streamPos,rawPack)) + { + if ((rawPack.type == ChanPacket::T_DATA) || (rawPack.type == ChanPacket::T_HEAD)) + { + sock->writeTag("SYNC"); + sock->writeShort(4); + sock->writeShort(0); + sock->write(&syncPos,4); + syncPos++; + + rawPack.writePeercast(*sock); + } + streamPos = rawPack.pos + rawPack.len; + } + } + sys->sleepIdle(); + } + + }catch(StreamException &e) + { + LOG_ERROR("Stream channel: %s",e.msg); + } +} + +//WLock canStreamLock; + +// ----------------------------------- +void Servent::sendPCPChannel() +{ + bool skipCheck = false; + + Channel *ch = chanMgr->findChannelByID(chanID); + if (!ch) + throw StreamException("Channel not found"); + + AtomStream atom(*sock); + + pcpStream = new PCPStream(remoteID); + int error=0; + + try + { + + LOG_DEBUG("Starting PCP stream of channel at %d",streamPos); + + +// setStatus(S_CONNECTED); + + //canStreamLock.on(); + //thread.active = canStream(ch); + //setStatus(S_CONNECTED); + //canStreamLock.off(); + + lastSkipTime = 0; + lastSkipCount = 0; + waitPort = 0; + + if (thread.active){ + atom.writeParent(PCP_CHAN,3 + ((sendHeader)?1:0)); + atom.writeBytes(PCP_CHAN_ID,chanID.id,16); + ch->info.writeInfoAtoms(atom); + ch->info.writeTrackAtoms(atom); + if (sendHeader) + { + atom.writeParent(PCP_CHAN_PKT,3); + atom.writeID4(PCP_CHAN_PKT_TYPE,PCP_CHAN_PKT_HEAD); + atom.writeInt(PCP_CHAN_PKT_POS,ch->headPack.pos); + atom.writeBytes(PCP_CHAN_PKT_DATA,ch->headPack.data,ch->headPack.len); + + streamPos = ch->headPack.pos+ch->headPack.len; + LOG_DEBUG("Sent %d bytes header",ch->headPack.len); + } + } + + unsigned int streamIndex = ch->streamIndex; + + ChanPacket rawPack; + char pbuf[ChanPacket::MAX_DATALEN*3]; + MemoryStream mems(pbuf,sizeof(pbuf)); + AtomStream atom2(mems); + + while (thread.active) + { + + Channel *ch = chanMgr->findChannelByID(chanID); + + if (ch) + { + + if (streamIndex != ch->streamIndex) + { + streamIndex = ch->streamIndex; + streamPos = ch->headPack.pos; + LOG_DEBUG("sendPCPStream got new stream index"); + } + + mems.rewind(); + + if (ch->rawData.findPacket(streamPos,rawPack)) + { + if ((streamPos < rawPack.pos) && !rawPack.skip){ + if (skipCheck){ + char tmp[32]; + getHost().IPtoStr(tmp); + LOG_NETWORK("##### send skipping ##### %d (%d, %d) -> %s", (rawPack.pos - streamPos), streamPos, rawPack.pos, tmp); + + if (sys->getTime() == lastSkipTime) { + LOG_DEBUG("##### skip all buffer"); + streamPos = ch->rawData.getLatestPos(); + continue; + } + + lastSkipTime = sys->getTime(); + lastSkipCount++; + } else { + skipCheck = true; + } + } + + if (rawPack.type == ChanPacket::T_HEAD) + { + atom2.writeParent(PCP_CHAN,2); + atom2.writeBytes(PCP_CHAN_ID,chanID.id,16); + atom2.writeParent(PCP_CHAN_PKT,3); + atom2.writeID4(PCP_CHAN_PKT_TYPE,PCP_CHAN_PKT_HEAD); + atom2.writeInt(PCP_CHAN_PKT_POS,rawPack.pos); + atom2.writeBytes(PCP_CHAN_PKT_DATA,rawPack.data,rawPack.len); + + sock->write(pbuf, mems.getPosition()); + }else if (rawPack.type == ChanPacket::T_DATA) + { + atom2.writeParent(PCP_CHAN,2); + atom2.writeBytes(PCP_CHAN_ID,chanID.id,16); + atom2.writeParent(PCP_CHAN_PKT,3); + atom2.writeID4(PCP_CHAN_PKT_TYPE,PCP_CHAN_PKT_DATA); + atom2.writeInt(PCP_CHAN_PKT_POS,rawPack.pos); + atom2.writeBytes(PCP_CHAN_PKT_DATA,rawPack.data,rawPack.len); + +#ifdef WIN32 + sock->bufferingWrite(pbuf, mems.getPosition()); + lastSkipTime = sock->bufList.lastSkipTime; + lastSkipCount = sock->bufList.skipCount; +#else + sock->write(pbuf, mems.getPosition()); +#endif + } + + if (rawPack.pos < streamPos) + LOG_DEBUG("pcp: skip back %d",rawPack.pos-streamPos); + + //LOG_DEBUG("Sending %d-%d (%d,%d,%d)",rawPack.pos,rawPack.pos+rawPack.len,ch->streamPos,ch->rawData.getLatestPos(),ch->rawData.getOldestPos()); + + streamPos = rawPack.pos+rawPack.len; + } + } else { + pcpStream->flush(*sock); + throw StreamException("Channel not found"); + } + +#ifdef WIN32 + sock->bufferingWrite(NULL, 0); + lastSkipTime = sock->bufList.lastSkipTime; + lastSkipCount = sock->bufList.skipCount; +#endif + BroadcastState bcs; + bcs.servent_id = servent_id; +// error = pcpStream->readPacket(*sock,bcs); + do { + error = pcpStream->readPacket(*sock,bcs); + if (error) + throw StreamException("PCP exception"); + } while (sock->readReady() || pcpStream->outData.numPending()); + + sys->sleepIdle(); + + } + + LOG_DEBUG("PCP channel stream closed normally."); + + }catch(StreamException &e) + { + LOG_ERROR("Stream channel: %s",e.msg); + } + + try + { + atom.writeInt(PCP_QUIT,error); + }catch(StreamException &) {} + +} + +// ----------------------------------- +int Servent::serverProc(ThreadInfo *thread) +{ +// thread->lock(); + + + Servent *sv = (Servent*)thread->data; + + try + { + if (!sv->sock) + throw StreamException("Server has no socket"); + + sv->setStatus(S_LISTENING); + + + char servIP[64]; + sv->sock->host.toStr(servIP); + + if (servMgr->isRoot) + LOG_DEBUG("Root Server started: %s",servIP); + else + LOG_DEBUG("Server started: %s",servIP); + + + while ((thread->active) && (sv->sock->active())) + { + if (servMgr->numActiveOnPort(sv->sock->host.port) < servMgr->maxServIn) + { + ClientSocket *cs = sv->sock->accept(); + if (cs) + { + LOG_DEBUG("accepted incoming"); + Servent *ns = servMgr->allocServent(); + if (ns) + { + servMgr->lastIncoming = sys->getTime(); + ns->servPort = sv->sock->host.port; + ns->networkID = servMgr->networkID; + ns->initIncoming(cs,sv->allow); + }else + LOG_ERROR("Out of servents"); + } + } + sys->sleep(100); + } + }catch(StreamException &e) + { + LOG_ERROR("Server Error: %s:%d",e.msg,e.err); + } + + + LOG_DEBUG("Server stopped"); + + sv->kill(); + sys->endThread(thread); + return 0; +} + +// ----------------------------------- +bool Servent::writeVariable(Stream &s, const String &var) +{ + char buf[1024]; + + if (var == "type") + strcpy(buf,getTypeStr()); + else if (var == "status") + strcpy(buf,getStatusStr()); + else if (var == "address") + { + if (servMgr->enableGetName) //JP-EX s + { + getHost().toStr(buf); + char h_ip[64]; + Host h = getHost(); + h.toStr(h_ip); + +/* ChanHitList *hits[ChanMgr::MAX_HITLISTS]; + int numHits=0; + for(int i=0; ihitlists[i]; + if (chl->isUsed()) + hits[numHits++] = chl; + } + bool ishit,isfw; + ishit = isfw = false; + int numRelay = 0; + if (numHits) + { + for(int k=0; kisUsed()) + { + for (int j=0; jhits[j]; + if (hit->host.isValid() && (h.ip == hit->host.ip)) + { + ishit = true; + if (hit->firewalled) + isfw = true; + numRelay += hit->numRelays; + } + } + } + } + } + strcpy(buf,""); + if (ishit == true) + { + if (isfw == true) + { + if (numRelay== 0) + strcat(buf,""); + else + strcat(buf,""); + } + else + strcat(buf,""); + } + strcat(buf,h_ip); + char h_name[128]; + if (ClientSocket::getHostname(h_name,h.ip)) + { + strcat(buf,"["); + strcat(buf,h_name); + strcat(buf,"]"); + } + if (ishit == true) + { + strcat(buf,""); + } + } //JP-EX e*/ + + + bool isfw = false; + bool isRelay = true; + int numRelay = 0; + ChanHitList *chl = chanMgr->findHitListByID(chanID); + if (chl){ + ChanHit *hit = chl->hit; + while(hit){ + if (hit->host.isValid() && (h.ip == hit->host.ip)){ + isfw = hit->firewalled; + isRelay = hit->relay; + numRelay = hit->numRelays; + break; + } + hit = hit->next; + } + } + strcpy(buf, ""); + if (isfw){ + if (numRelay == 0){ + strcat(buf,""); + } else { + strcat(buf,""); + } + } else { + if (!isRelay){ + if (numRelay==0){ + strcpy(buf,""); + } else { + strcpy(buf,""); + } + } else { + strcpy(buf,""); + } + } + strcat(buf,h_ip); + char h_name[128]; + if (ClientSocket::getHostname(h_name,h.ip)) + { + strcat(buf,"["); + strcat(buf,h_name); + strcat(buf,"]"); + } + strcat(buf,""); + } + else + getHost().toStr(buf); + } + else if (var == "agent") + strcpy(buf,agent.cstr()); + else if (var == "bitrate") + { + if (sock) + { + unsigned int tot = sock->bytesInPerSec+sock->bytesOutPerSec; + sprintf(buf,"%.1f",BYTES_TO_KBPS(tot)); + }else + strcpy(buf,"0"); + }else if (var == "uptime") + { + String uptime; + if (lastConnect) + uptime.setFromStopwatch(sys->getTime()-lastConnect); + else + uptime.set("-"); + strcpy(buf,uptime.cstr()); + }else if (var.startsWith("gnet.")) + { + + float ctime = (float)(sys->getTime()-lastConnect); + if (var == "gnet.packetsIn") + sprintf(buf,"%d",gnuStream.packetsIn); + else if (var == "gnet.packetsInPerSec") + sprintf(buf,"%.1f",ctime>0?((float)gnuStream.packetsIn)/ctime:0); + else if (var == "gnet.packetsOut") + sprintf(buf,"%d",gnuStream.packetsOut); + else if (var == "gnet.packetsOutPerSec") + sprintf(buf,"%.1f",ctime>0?((float)gnuStream.packetsOut)/ctime:0); + else if (var == "gnet.normQueue") + sprintf(buf,"%d",outPacketsNorm.numPending()); + else if (var == "gnet.priQueue") + sprintf(buf,"%d",outPacketsPri.numPending()); + else if (var == "gnet.flowControl") + sprintf(buf,"%d",flowControl?1:0); + else if (var == "gnet.routeTime") + { + int nr = seenIDs.numUsed(); + unsigned int tim = sys->getTime()-seenIDs.getOldest(); + + String tstr; + tstr.setFromStopwatch(tim); + + if (nr) + strcpy(buf,tstr.cstr()); + else + strcpy(buf,"-"); + } + else + return false; + + }else + return false; + + s.writeString(buf); + + return true; +} diff --git a/PeerCast.root/PeerCast/core/common/servent.h b/PeerCast.root/PeerCast/core/common/servent.h new file mode 100644 index 0000000..b1c2241 --- /dev/null +++ b/PeerCast.root/PeerCast/core/common/servent.h @@ -0,0 +1,298 @@ +// ------------------------------------------------ +// File : servent.h +// Date: 4-apr-2002 +// Author: giles +// Desc: +// +// (c) 2002 peercast.org +// ------------------------------------------------ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// ------------------------------------------------ + + +#ifndef _SERVENT_H +#define _SERVENT_H + +// ---------------------------------- +#include "socket.h" +#include "sys.h" +#include "gnutella.h" +#include "channel.h" +#include "http.h" +#include "rtsp.h" +#include "pcp.h" + +class HTML; + +class AtomStream; + +// ---------------------------------- +// Servent handles the actual connection between clients +class Servent +{ +public: + + enum + { + MAX_HASH = 500, // max. amount of packet hashes Servents can store + MAX_OUTPACKETS = 32 // max. output packets per queue (normal/priority) + }; + + enum TYPE + { + T_NONE, // Not allocated + T_INCOMING, // Unknown incoming + T_SERVER, // The main server + T_RELAY, // Outgoing relay + T_DIRECT, // Outgoing direct connection + T_COUT, // PCP out connection + T_CIN, // PCP in connection + T_PGNU // old protocol connection + }; + + enum STATUS + { + S_NONE, + S_CONNECTING, + S_PROTOCOL, + S_HANDSHAKE, + S_CONNECTED, + S_CLOSING, + S_LISTENING, + S_TIMEOUT, + S_REFUSED, + S_VERIFIED, + S_ERROR, + S_WAIT, + S_FREE + }; + + enum PROTOCOL + { + P_UNKNOWN, + P_GNUTELLA06, + P_PCP + }; + + + enum SORT + { + SORT_NAME = 0, + SORT_BITRATE, + SORT_LISTENERS, + SORT_HOSTS, + SORT_TYPE, + SORT_GENRE + }; + + enum ALLOW + { + ALLOW_HTML = 0x01, + ALLOW_BROADCAST = 0x02, + ALLOW_NETWORK = 0x04, + ALLOW_DIRECT = 0x08, + ALLOW_ALL = 0xff + }; + + Servent(int); + ~Servent(); + + void reset(); + bool initServer(Host &); + void initIncoming(ClientSocket *,unsigned int); + void initOutgoing(TYPE); + void initGIV(Host &, GnuID &); + void initPCP(Host &); + + void checkFree(); + + + + + // funcs for handling status/type + void setStatus(STATUS); + static char * getTypeStr(Servent::TYPE t) {return typeMsgs[t];} + char * getTypeStr() {return getTypeStr(type);} + char * getStatusStr() {return statusMsgs[status];} + int getOutput(); + void addBytes(unsigned int); + bool isOlderThan(Servent *s) + { + if (s) + { + unsigned int t = sys->getTime(); + return ((t-lastConnect) > (t-s->lastConnect)); + }else + return true; + } + + + + // static funcs that do the actual work in the servent thread + static THREAD_PROC serverProc(ThreadInfo *); + static THREAD_PROC outgoingProc(ThreadInfo *); + static THREAD_PROC incomingProc(ThreadInfo *); + static THREAD_PROC givProc(ThreadInfo *); + static THREAD_PROC pcpProc(ThreadInfo *); + static THREAD_PROC fetchProc(ThreadInfo *); + + static bool pingHost(Host &,GnuID &); + + bool getLocalURL(char *); + bool getLocalTypeURL(char *, ChanInfo::TYPE); + + // various types of handshaking are needed + void handshakePLS(ChanHitList **, int, bool); + void handshakePLS(ChanInfo &, bool); + + void handshakeHTML(char *); + void handshakeXML(); + void handshakeCMD(char *); + bool handshakeAuth(HTTP &,const char *,bool); + void handshakeIn(); + void handshakeOut(); + + + void processOutPCP(); + void processOutChannel(); + + bool handshakeStream(ChanInfo &); + void handshakeGiv(GnuID &); + + void handshakeICY(Channel::SRC_TYPE,bool); + void handshakeIncoming(); + void handshakePOST(); + void handshakeRTSP(RTSP &); + void handshakeHTTP(HTTP &,bool); + + void handshakeRemoteFile(const char *); + void handshakeLocalFile(const char *); + + static void handshakeOutgoingPCP(AtomStream &,Host &,GnuID &,String &,bool); + static void handshakeIncomingPCP(AtomStream &,Host &,GnuID &,String &); + + void processIncomingPCP(bool); + + bool waitForChannelHeader(ChanInfo &); + ChanInfo findChannel(char *str,ChanInfo &); + + bool writeVariable(Stream &, const String &); + + + // the "mainloop" of servents + void processGnutella(); + void processRoot(); + void processServent(); + void processStream(bool,ChanInfo &); + void processPCP(bool,bool); + + bool procAtoms(AtomStream &); + void procRootAtoms(AtomStream &,int); + void procHeloAtoms(AtomStream &,int,bool); + void procGetAtoms(AtomStream &,int); + + void triggerChannel(char *,ChanInfo::PROTOCOL,bool); + void sendPeercastChannel(); + void sendRawChannel(bool,bool); +// void sendRawMultiChannel(bool,bool); + void sendRawMetaChannel(int); + void sendPCPChannel(); + void checkPCPComms(Channel *, AtomStream &); + + static void readICYHeader(HTTP &, ChanInfo &, char *); + bool canStream(Channel *); + + bool isConnected() {return status == S_CONNECTED;} + bool isListening() {return status == S_LISTENING;} + + bool isAllowed(int); + bool isFiltered(int); + + // connection handling funcs + void createSocket(); + void kill(); + void abort(); + bool isPrivate(); + bool isLocal(); + + + Host getHost(); + + bool outputPacket(GnuPacket &,bool); + bool hasSeenPacket(GnuPacket &p) {return seenIDs.contains(p.id);} + bool acceptGIV(ClientSocket *); + bool sendPacket(ChanPacket &,GnuID &,GnuID &,GnuID &,Servent::TYPE); + + + TYPE type; + STATUS status; + + static char *statusMsgs[],*typeMsgs[]; + GnuStream gnuStream; + GnuPacket pack; + unsigned int lastConnect,lastPing,lastPacket; + String agent; + + GnuIDList seenIDs; + GnuID networkID; + int serventIndex; + + GnuID remoteID; + + GnuID chanID; + + GnuID givID; + + ThreadInfo thread; + + + char loginPassword[64]; + char loginMount[64]; + + bool priorityConnect; + bool addMetadata; + int nsSwitchNum; + + unsigned int allow; + + ClientSocket *sock,*pushSock; + + WLock lock; + + bool sendHeader; + unsigned int syncPos,streamPos; + int servPort; + + ChanInfo::PROTOCOL outputProtocol; + + GnuPacketBuffer outPacketsNorm,outPacketsPri; + + unsigned int bytesPerSecond; + bool flowControl; + + Servent *next; + + PCPStream *pcpStream; + Cookie cookie; + + int servent_id; + unsigned int lastSkipTime; + unsigned int lastSkipCount; + unsigned int waitPort; + + int channel_id; +}; + +extern char *nextCGIarg(char *cp, char *cmd, char *arg); + + +#endif + diff --git a/PeerCast.root/PeerCast/core/common/servhs.cpp b/PeerCast.root/PeerCast/core/common/servhs.cpp new file mode 100644 index 0000000..8e352bf --- /dev/null +++ b/PeerCast.root/PeerCast/core/common/servhs.cpp @@ -0,0 +1,1954 @@ +// ------------------------------------------------ +// File : servhs.cpp +// Date: 4-apr-2002 +// Author: giles +// Desc: +// Servent handshaking, TODO: should be in its own class +// +// (c) 2002 peercast.org +// ------------------------------------------------ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// ------------------------------------------------ + + +#include +#include "servent.h" +#include "servmgr.h" +#include "html.h" +#include "stats.h" +#include "peercast.h" +#include "pcp.h" +#include "version2.h" +#ifdef _DEBUG +#include "chkMemoryLeak.h" +#define DEBUG_NEW new(__FILE__, __LINE__) +#define new DEBUG_NEW +#endif + +// ----------------------------------- +static void termArgs(char *str) +{ + if (str) + { + int slen = strlen(str); + for(int i=0; i= (MAX_CGI_LEN-1)) + break; + } + *arg = 0; + + return cp; +} +// ----------------------------------- +bool getCGIargBOOL(char *a) +{ + return (strcmp(a,"1")==0); +} +// ----------------------------------- +int getCGIargINT(char *a) +{ + return atoi(a); +} + +// ----------------------------------- +void Servent::handshakeHTTP(HTTP &http, bool isHTTP) +{ + char *in = http.cmdLine; + + if (http.isRequest("GET /")) + { + char *fn = in+4; + + char *pt = strstr(fn,HTTP_PROTO1); + if (pt) + pt[-1] = 0; + + if (strncmp(fn,"/admin?",7)==0) + { + if (!isAllowed(ALLOW_HTML)) + throw HTTPException(HTTP_SC_UNAVAILABLE,503); + + + LOG_DEBUG("Admin client"); + handshakeCMD(fn+7); + + }else if (strncmp(fn,"/http/",6)==0) + { + String dirName = fn+6; + + if (!isAllowed(ALLOW_HTML)) + throw HTTPException(HTTP_SC_UNAVAILABLE,503); + + if (!handshakeAuth(http,fn,false)) + throw HTTPException(HTTP_SC_UNAUTHORIZED,401); + + + handshakeRemoteFile(dirName); + + + }else if (strncmp(fn,"/html/",6)==0) + { + String dirName = fn+1; + + if (!isAllowed(ALLOW_HTML)) + throw HTTPException(HTTP_SC_UNAVAILABLE,503); + + if (handshakeAuth(http,fn,true)) + handshakeLocalFile(dirName); + + + }else if (strncmp(fn,"/admin/?",8)==0) + { + if (!isAllowed(ALLOW_HTML)) + throw HTTPException(HTTP_SC_UNAVAILABLE,503); + + LOG_DEBUG("Admin client"); + handshakeCMD(fn+8); + + }else if (strncmp(fn,"/admin.cgi",10)==0) + { + if (!isAllowed(ALLOW_BROADCAST)) + throw HTTPException(HTTP_SC_UNAVAILABLE,503); + + char *pwdArg = getCGIarg(fn,"pass="); + char *songArg = getCGIarg(fn,"song="); + char *mountArg = getCGIarg(fn,"mount="); + char *urlArg = getCGIarg(fn,"url="); + + if (pwdArg && songArg) + { + int i; + int slen = strlen(fn); + for(i=0; ichannel; + while (c) + { + if ((c->status == Channel::S_BROADCASTING) && + (c->info.contentType == ChanInfo::T_MP3) ) + { + // if we have a mount point then check for it, otherwise update all channels. + bool match=true; + + if (mountArg) + match = strcmp(c->mount,mountArg)==0; + + if (match) + { + ChanInfo newInfo = c->info; + newInfo.track.title.set(songArg,String::T_ESC); + newInfo.track.title.convertTo(String::T_UNICODE); + + if (urlArg) + if (urlArg[0]) + newInfo.track.contact.set(urlArg,String::T_ESC); + LOG_CHANNEL("Channel Shoutcast update: %s",songArg); + c->updateInfo(newInfo); + } + } + c=c->next; + } + } + + }else if (strncmp(fn,"/pls/",5)==0) + { + + if (!sock->host.isLocalhost()) + if (!isAllowed(ALLOW_DIRECT) || !isFiltered(ServFilter::F_DIRECT)) + throw HTTPException(HTTP_SC_UNAVAILABLE,503); + + + ChanInfo info; + if (servMgr->getChannel(fn+5,info,isPrivate())) + handshakePLS(info,false); + else + throw HTTPException(HTTP_SC_NOTFOUND,404); + + }else if (strncmp(fn,"/stream/",8)==0) + { + + if (!sock->host.isLocalhost()) + if (!isAllowed(ALLOW_DIRECT) || !isFiltered(ServFilter::F_DIRECT)) + throw HTTPException(HTTP_SC_UNAVAILABLE,503); + + triggerChannel(fn+8,ChanInfo::SP_HTTP,isPrivate()); + + + }else if (strncmp(fn,"/channel/",9)==0) + { + + if (!sock->host.isLocalhost()) + if (!isAllowed(ALLOW_NETWORK) || !isFiltered(ServFilter::F_NETWORK)) + throw HTTPException(HTTP_SC_UNAVAILABLE,503); + + triggerChannel(fn+9,ChanInfo::SP_PCP,false); + + }else + { + while (http.nextHeader()); + http.writeLine(HTTP_SC_FOUND); + http.writeLineF("Location: /%s/index.html",servMgr->htmlPath); + http.writeLine(""); + } + } + else if (http.isRequest("POST /")) + { + char *fn = in+5; + + char *pt = strstr(fn,HTTP_PROTO1); + if (pt) + pt[-1] = 0; + + if (strncmp(fn,"/pls/",5)==0) + { + + if (!sock->host.isLocalhost()) + if (!isAllowed(ALLOW_DIRECT) || !isFiltered(ServFilter::F_DIRECT)) + throw HTTPException(HTTP_SC_UNAVAILABLE,503); + + + ChanInfo info; + if (servMgr->getChannel(fn+5,info,isPrivate())) + handshakePLS(info,false); + else + throw HTTPException(HTTP_SC_NOTFOUND,404); + + }else if (strncmp(fn,"/stream/",8)==0) + { + + if (!sock->host.isLocalhost()) + if (!isAllowed(ALLOW_DIRECT) || !isFiltered(ServFilter::F_DIRECT)) + throw HTTPException(HTTP_SC_UNAVAILABLE,503); + + triggerChannel(fn+8,ChanInfo::SP_HTTP,isPrivate()); + + }else if (strncmp(fn,"/admin",7)==0) + { + if (!isAllowed(ALLOW_HTML)) + throw HTTPException(HTTP_SC_UNAVAILABLE,503); + + + LOG_DEBUG("Admin client"); + while(http.nextHeader()){ + LOG_DEBUG("%s",http.cmdLine); + } + char buf[8192]; + if (sock->readLine(buf, sizeof(buf)) != 0){ + handshakeCMD(buf); + } + + }else + { + while (http.nextHeader()); + http.writeLine(HTTP_SC_FOUND); + http.writeLineF("Location: /%s/index.html",servMgr->htmlPath); + http.writeLine(""); + } + }else if (http.isRequest("GIV")) + { + HTTP http(*sock); + + while (http.nextHeader()) ; + + if (!isAllowed(ALLOW_NETWORK)) + throw HTTPException(HTTP_SC_UNAVAILABLE,503); + + GnuID id; + id.clear(); + + char *idstr = strstr(in,"/"); + if (idstr) + id.fromStr(idstr+1); + + char ipstr[64]; + sock->host.toStr(ipstr); + + if (id.isSet()) + { + // at the moment we don`t really care where the GIV came from, so just give to chan. no. if its waiting. + Channel *ch = chanMgr->findChannelByID(id); + + if (!ch) + throw HTTPException(HTTP_SC_NOTFOUND,404); + + if (!ch->acceptGIV(sock)) + throw HTTPException(HTTP_SC_UNAVAILABLE,503); + + + LOG_DEBUG("Accepted GIV channel %s from: %s",idstr,ipstr); + + sock=NULL; // release this servent but dont close socket. + }else + { + + if (!servMgr->acceptGIV(sock)) + throw HTTPException(HTTP_SC_UNAVAILABLE,503); + + LOG_DEBUG("Accepted GIV PCP from: %s",ipstr); + sock=NULL; // release this servent but dont close socket. + } + + }else if (http.isRequest(PCX_PCP_CONNECT)) + { + + if (!isAllowed(ALLOW_NETWORK) || !isFiltered(ServFilter::F_NETWORK)) + throw HTTPException(HTTP_SC_UNAVAILABLE,503); + + processIncomingPCP(true); + + }else if (http.isRequest("PEERCAST CONNECT")) + { + if (!isAllowed(ALLOW_NETWORK) || !isFiltered(ServFilter::F_NETWORK)) + throw HTTPException(HTTP_SC_UNAVAILABLE,503); + + LOG_DEBUG("PEERCAST client"); + processServent(); + + }else if (http.isRequest("SOURCE")) + { + if (!isAllowed(ALLOW_BROADCAST)) + throw HTTPException(HTTP_SC_UNAVAILABLE,503); + + char *mount = NULL; + + char *ps; + if (ps=strstr(in,"ICE/1.0")) + { + mount = in+7; + *ps = 0; + LOG_DEBUG("ICE 1.0 client to %s",mount?mount:"unknown"); + }else{ + mount = in+strlen(in); + while (*--mount) + if (*mount == '/') + { + mount[-1] = 0; // password preceeds + break; + } + strcpy(loginPassword,in+7); + + LOG_DEBUG("ICY client: %s %s",loginPassword,mount?mount:"unknown"); + } + + if (mount) + strcpy(loginMount,mount); + + handshakeICY(Channel::SRC_ICECAST,isHTTP); + sock = NULL; // socket is taken over by channel, so don`t close it + + }else if (http.isRequest(servMgr->password)) + { + if (!isAllowed(ALLOW_BROADCAST)) + throw HTTPException(HTTP_SC_UNAVAILABLE,503); + + strcpy(loginPassword,servMgr->password); // pwd already checked + + sock->writeLine("OK2"); + sock->writeLine("icy-caps:11"); + sock->writeLine(""); + LOG_DEBUG("ShoutCast client"); + + handshakeICY(Channel::SRC_SHOUTCAST,isHTTP); + sock = NULL; // socket is taken over by channel, so don`t close it + + }else + { + throw HTTPException(HTTP_SC_BADREQUEST,400); + } + +} +// ----------------------------------- +bool Servent::canStream(Channel *ch) +{ + if (ch==NULL) + return false; + + if (servMgr->isDisabled) + return false; + + if (!isPrivate()) + { + Channel *c = chanMgr->channel; + int noRelay = 0; + unsigned int needRate = 0; + unsigned int allRate = 0; + while(c){ + if (c->isPlaying()){ + allRate += c->info.bitrate * c->localRelays(); + if ((c != ch) && (c->localRelays() == 0)){ + if(!isIndexTxt(c)) // for PCRaw (relay) + noRelay++; + needRate+=c->info.bitrate; + } + } + c = c->next; + } + int diff = servMgr->maxRelays - servMgr->numStreams(Servent::T_RELAY,false); + if (ch->localRelays()){ + if (noRelay > diff){ + noRelay = diff; + } + } else { + noRelay = 0; + needRate = 0; + } + + // for PCRaw (relay) start. + bool force_off = true; + + if(isIndexTxt(ch)) + force_off = false; + // for PCRaw (relay) end. + + LOG_DEBUG("Relay check: Max=%d Now=%d Need=%d ch=%d", + servMgr->maxBitrateOut, allRate, needRate, ch->info.bitrate); + if ( !ch->isPlaying() + || ch->isFull() +// || servMgr->bitrateFull(needRate+ch->getBitrate()) + || (allRate + needRate + ch->info.bitrate > servMgr->maxBitrateOut) + || ((type == T_RELAY) && servMgr->relaysFull() && force_off) // for PCRaw (relay) (force_off) + || ((type == T_RELAY) && (((servMgr->numStreams(Servent::T_RELAY,false) + noRelay) >= servMgr->maxRelays)) && force_off) // for PCRaw (relay) (force_off) + || ((type == T_DIRECT) && servMgr->directFull()) + ){ + LOG_DEBUG("Relay check: NG"); + return false; + } + } + + LOG_DEBUG("Relay check: OK"); + return true; +} +// ----------------------------------- +void Servent::handshakeIncoming() +{ + + setStatus(S_HANDSHAKE); + + char buf[2048]; + sock->readLine(buf,sizeof(buf)); + + char sb[64]; + sock->host.toStr(sb); + + + if (stristr(buf,RTSP_PROTO1)) + { + LOG_DEBUG("RTSP from %s '%s'",sb,buf); + RTSP rtsp(*sock); + rtsp.initRequest(buf); + handshakeRTSP(rtsp); + }else if (stristr(buf,HTTP_PROTO1)) + { + LOG_DEBUG("HTTP from %s '%s'",sb,buf); + HTTP http(*sock); + http.initRequest(buf); + handshakeHTTP(http,true); + }else + { + LOG_DEBUG("Connect from %s '%s'",sb,buf); + HTTP http(*sock); + http.initRequest(buf); + handshakeHTTP(http,false); + } + +} +// ----------------------------------- +void Servent::triggerChannel(char *str, ChanInfo::PROTOCOL proto,bool relay) +{ + + ChanInfo info; +// WLockBlock lb(&(chanMgr->channellock)); + +// LOG_DEBUG("----------triggerChannel LOCK ON"); +// lb.on(); + servMgr->getChannel(str,info,relay); +// LOG_DEBUG("==========triggerChannel LOCK OFF"); +// lb.off(); + + if (proto == ChanInfo::SP_PCP) + type = T_RELAY; + else + type = T_DIRECT; + + outputProtocol = proto; + + processStream(false,info); + +} +// ----------------------------------- +void writePLSHeader(Stream &s, PlayList::TYPE type) +{ + s.writeLine(HTTP_SC_OK); + s.writeLineF("%s %s",HTTP_HS_SERVER,PCX_AGENT); + + const char *content; + switch(type) + { + case PlayList::T_PLS: + content = MIME_XM3U; + break; + case PlayList::T_ASX: + content = MIME_ASX; + break; + case PlayList::T_RAM: + content = MIME_RAM; + break; + default: + content = MIME_TEXT; + break; + } + s.writeLineF("%s %s",HTTP_HS_CONTENT,content); + s.writeLine("Content-Disposition: inline"); + s.writeLine("Cache-Control: private" ); + s.writeLineF("%s %s",HTTP_HS_CONNECTION,"close"); + + s.writeLine(""); +} + +// ----------------------------------- +void Servent::handshakePLS(ChanInfo &info, bool doneHandshake) +{ + char url[256]; + + char in[128]; + + if (!doneHandshake) + while (sock->readLine(in,128)); + + + if (getLocalTypeURL(url,info.contentType)) + { + + PlayList::TYPE type; + + if ((info.contentType == ChanInfo::T_WMA) || (info.contentType == ChanInfo::T_WMV)) + type = PlayList::T_ASX; + else if (info.contentType == ChanInfo::T_OGM) + type = PlayList::T_RAM; + else + type = PlayList::T_PLS; + + writePLSHeader(*sock,type); + + PlayList *pls; + + pls = new PlayList(type,1); + + pls->addChannel(url,info); + + pls->write(*sock); + + delete pls; + } +} +// ----------------------------------- +void Servent::handshakePLS(ChanHitList **cl, int num, bool doneHandshake) +{ + char url[256]; + char in[128]; + + if (!doneHandshake) + while (sock->readLine(in,128)); + + if (getLocalURL(url)) + { + writePLSHeader(*sock,PlayList::T_SCPLS); + + PlayList *pls; + + pls = new PlayList(PlayList::T_SCPLS,num); + + for(int i=0; iaddChannel(url,cl[i]->info); + + pls->write(*sock); + + delete pls; + } +} +// ----------------------------------- +bool Servent::getLocalURL(char *str) +{ + if (!sock) + throw StreamException("Not connected"); + + + char ipStr[64]; + + Host h; + + if (sock->host.localIP()) + h = sock->getLocalHost(); + else + h = servMgr->serverHost; + + h.port = servMgr->serverHost.port; + + h.toStr(ipStr); + + sprintf(str,"http://%s",ipStr); + return true; +} + +// ----------------------------------- +bool Servent::getLocalTypeURL(char *str, ChanInfo::TYPE type) +{ + if (!sock) + throw StreamException("Not connected"); + + + char ipStr[64]; + + Host h; + + if (sock->host.localIP()) + h = sock->getLocalHost(); + else + h = servMgr->serverHost; + + h.port = servMgr->serverHost.port; + + h.toStr(ipStr); + switch(type) { + case ChanInfo::T_WMA: + case ChanInfo::T_WMV: + sprintf(str,"mms://%s",ipStr); + break; + default: + sprintf(str,"http://%s",ipStr); + } + return true; +} +// ----------------------------------- +// Warning: testing RTSP/RTP stuff below. +// .. moved over to seperate app now. +// ----------------------------------- +void Servent::handshakePOST() +{ + char tmp[1024]; + while (sock->readLine(tmp,sizeof(tmp))) + LOG_DEBUG("POST: %s",tmp); + + throw HTTPException(HTTP_SC_BADREQUEST,400); +} + + +// ----------------------------------- +void Servent::handshakeRTSP(RTSP &rtsp) +{ + throw HTTPException(HTTP_SC_BADREQUEST,400); +} +// ----------------------------------- +bool Servent::handshakeAuth(HTTP &http,const char *args,bool local) +{ + char user[1024],pass[1024]; + user[0] = pass[0] = 0; + + char *pwd = getCGIarg(args, "pass="); + + if ((pwd) && strlen(servMgr->password)) + { + String tmp = pwd; + char *as = strstr(tmp.cstr(),"&"); + if (as) *as = 0; + if (strcmp(tmp,servMgr->password)==0) + { + while (http.nextHeader()); + return true; + } + } + + Cookie gotCookie; + cookie.clear(); + + while (http.nextHeader()) + { + char *arg = http.getArgStr(); + if (!arg) + continue; + + switch (servMgr->authType) + { + case ServMgr::AUTH_HTTPBASIC: + if (http.isHeader("Authorization")) + http.getAuthUserPass(user,pass); + break; + case ServMgr::AUTH_COOKIE: + if (http.isHeader("Cookie")) + { + LOG_DEBUG("Got cookie: %s",arg); + char *idp=arg; + while ((idp = strstr(idp,"id="))) + { + idp+=3; + gotCookie.set(idp,sock->host.ip); + if (servMgr->cookieList.contains(gotCookie)) + { + LOG_DEBUG("Cookie found"); + cookie = gotCookie; + break; + } + + } + } + break; + } + } + + if (sock->host.isLocalhost()) + return true; + + + switch (servMgr->authType) + { + case ServMgr::AUTH_HTTPBASIC: + + if ((strcmp(pass,servMgr->password)==0) && strlen(servMgr->password)) + return true; + break; + case ServMgr::AUTH_COOKIE: + if (servMgr->cookieList.contains(cookie)) + return true; + break; + } + + + + if (servMgr->authType == ServMgr::AUTH_HTTPBASIC) + { + http.writeLine(HTTP_SC_UNAUTHORIZED); + http.writeLine("WWW-Authenticate: Basic realm=\"PeerCast Admin\""); + }else if (servMgr->authType == ServMgr::AUTH_COOKIE) + { + String file = servMgr->htmlPath; + file.append("/login.html"); + if (local) + handshakeLocalFile(file); + else + handshakeRemoteFile(file); + } + + + return false; +} + +// ----------------------------------- +void Servent::handshakeCMD(char *cmd) +{ + char result[MAX_CGI_LEN]; + char arg[MAX_CGI_LEN]; + char curr[MAX_CGI_LEN]; + + char jumpStr[128]; + char *jumpArg=NULL; + bool retHTML=true; + strcpy(result,"OK"); + + HTTP http(*sock); + HTML html("",*sock); + + + if (!handshakeAuth(http,cmd,true)) + return; + + try + { + if (cmpCGIarg(cmd,"cmd=","redirect")) + { + char *j = getCGIarg(cmd,"url="); + if (j) + { + termArgs(cmd); + String url; + url.set(j,String::T_ESC); + url.convertTo(String::T_ASCII); + + if (!url.contains("http://")) + url.prepend("http://"); + + html.setRefreshURL(url.cstr()); + html.startHTML(); + html.addHead(); + html.startBody(); + html.startTagEnd("h3","Please wait..."); + html.end(); + html.end(); + + } + }else{ + + if (cmpCGIarg(cmd,"cmd=","viewxml")) + { + + handshakeXML(); + retHTML = false; + }else if (cmpCGIarg(cmd,"cmd=","clearlog")) + { + sys->logBuf->clear(); + sprintf(jumpStr,"/%s/viewlog.html",servMgr->htmlPath); + jumpArg = jumpStr; + + }else if (cmpCGIarg(cmd,"cmd=","save")) + { + + peercastInst->saveSettings(); + + sprintf(jumpStr,"/%s/settings.html",servMgr->htmlPath); + jumpArg = jumpStr; + }else if (cmpCGIarg(cmd,"cmd=","reg")) + { + char idstr[128]; + chanMgr->broadcastID.toStr(idstr); + sprintf(jumpStr,"http://www.peercast.org/register/?id=%s",idstr); + jumpArg = jumpStr; + }else if (cmpCGIarg(cmd,"cmd=","edit_bcid")) + { + char *cp = cmd; + GnuID id; + BCID *bcid; + while (cp=nextCGIarg(cp,curr,arg)) + { + if (strcmp(curr,"id")==0) + id.fromStr(arg); + else if (strcmp(curr,"del")==0) + servMgr->removeValidBCID(id); + else if (strcmp(curr,"valid")==0) + { + bcid = servMgr->findValidBCID(id); + if (bcid) + bcid->valid = getCGIargBOOL(arg); + } + } + peercastInst->saveSettings(); + sprintf(jumpStr,"/%s/bcid.html",servMgr->htmlPath); + jumpArg = jumpStr; + + }else if (cmpCGIarg(cmd,"cmd=","add_bcid")) + { + BCID *bcid = new BCID(); + + char *cp = cmd; + bool result=false; + while (cp=nextCGIarg(cp,curr,arg)) + { + if (strcmp(curr,"id")==0) + bcid->id.fromStr(arg); + else if (strcmp(curr,"name")==0) + bcid->name.set(arg); + else if (strcmp(curr,"email")==0) + bcid->email.set(arg); + else if (strcmp(curr,"url")==0) + bcid->url.set(arg); + else if (strcmp(curr,"valid")==0) + bcid->valid = getCGIargBOOL(arg); + else if (strcmp(curr,"result")==0) + result = true; + + } + + LOG_DEBUG("Adding BCID : %s",bcid->name.cstr()); + servMgr->addValidBCID(bcid); + peercastInst->saveSettings(); + if (result) + { + http.writeLine(HTTP_SC_OK); + http.writeLine(""); + http.writeString("OK"); + }else + { + sprintf(jumpStr,"/%s/bcid.html",servMgr->htmlPath); + jumpArg = jumpStr; + } + + + }else if (cmpCGIarg(cmd,"cmd=","apply")) + { + //servMgr->numFilters = 0; + ServFilter *currFilter=servMgr->filters; + bool beginfilt = false; + + bool brRoot=false; + bool getUpd=false; + int showLog=0; + int allowServer1=0; + int allowServer2=0; + int newPort=servMgr->serverHost.port; + int enableGetName = 0; + int allowConnectPCST = 0; + + char *cp = cmd; + while (cp=nextCGIarg(cp,curr,arg)) + { + // server + if (strcmp(curr,"serveractive")==0) + servMgr->autoServe = getCGIargBOOL(arg); + else if (strcmp(curr,"port")==0) + newPort = getCGIargINT(arg); + else if (strcmp(curr,"icymeta")==0) + { + int iv = getCGIargINT(arg); + if (iv < 0) iv = 0; + else if (iv > 16384) iv = 16384; + + chanMgr->icyMetaInterval = iv; + + }else if (strcmp(curr,"passnew")==0) + strcpy(servMgr->password,arg); + else if (strcmp(curr,"root")==0) + servMgr->isRoot = getCGIargBOOL(arg); + else if (strcmp(curr,"brroot")==0) + brRoot = getCGIargBOOL(arg); + else if (strcmp(curr,"getupd")==0) + getUpd = getCGIargBOOL(arg); + else if (strcmp(curr,"huint")==0) + chanMgr->setUpdateInterval(getCGIargINT(arg)); + else if (strcmp(curr,"forceip")==0) + servMgr->forceIP = arg; + else if (strcmp(curr,"htmlPath")==0) + { + strcpy(servMgr->htmlPath,"html/"); + strcat(servMgr->htmlPath,arg); + }else if (strcmp(curr,"djmsg")==0) + { + String msg; + msg.set(arg,String::T_ESC); + msg.convertTo(String::T_UNICODE); + chanMgr->setBroadcastMsg(msg); + } + else if (strcmp(curr,"pcmsg")==0) + { + servMgr->rootMsg.set(arg,String::T_ESC); + servMgr->rootMsg.convertTo(String::T_UNICODE); + }else if (strcmp(curr,"minpgnu")==0) + servMgr->minGnuIncoming = atoi(arg); + else if (strcmp(curr,"maxpgnu")==0) + servMgr->maxGnuIncoming = atoi(arg); + + + + // connections + else if (strcmp(curr,"maxcin")==0) + servMgr->maxControl = getCGIargINT(arg); + + else if (strcmp(curr,"maxup")==0) + servMgr->maxBitrateOut = getCGIargINT(arg); + else if (strcmp(curr,"maxrelays")==0) + servMgr->setMaxRelays(getCGIargINT(arg)); + else if (strcmp(curr,"maxdirect")==0) + servMgr->maxDirect = getCGIargINT(arg); + else if (strcmp(curr,"maxrelaypc")==0) + chanMgr->maxRelaysPerChannel = getCGIargINT(arg); + else if (strncmp(curr,"filt_",5)==0) + { + if (!beginfilt) { + servMgr->numFilters = 0; + beginfilt = true; + } + char *fs = curr+5; + { + if (strncmp(fs,"ip",2)==0) // ip must be first + { + currFilter = &servMgr->filters[servMgr->numFilters]; + currFilter->init(); + currFilter->host.fromStrIP(arg,DEFAULT_PORT); + if ((currFilter->host.ip) && (servMgr->numFilters < (ServMgr::MAX_FILTERS-1))) + { + servMgr->numFilters++; + servMgr->filters[servMgr->numFilters].init(); // clear new entry + } + + }else if (strncmp(fs,"bn",2)==0) + currFilter->flags |= ServFilter::F_BAN; + else if (strncmp(fs,"pr",2)==0) + currFilter->flags |= ServFilter::F_PRIVATE; + else if (strncmp(fs,"nw",2)==0) + currFilter->flags |= ServFilter::F_NETWORK; + else if (strncmp(fs,"di",2)==0) + currFilter->flags |= ServFilter::F_DIRECT; + } + } + + // client + else if (strcmp(curr,"clientactive")==0) + servMgr->autoConnect = getCGIargBOOL(arg); + else if (strcmp(curr,"yp")==0) + { + if (!PCP_FORCE_YP) + { + String str(arg,String::T_ESC); + str.convertTo(String::T_ASCII); + servMgr->rootHost = str; + } + } + else if (strcmp(curr,"yp2")==0) + { + if (!PCP_FORCE_YP) + { + String str(arg,String::T_ESC); + str.convertTo(String::T_ASCII); + servMgr->rootHost2 = str; + } + } + else if (strcmp(curr,"deadhitage")==0) + chanMgr->deadHitAge = getCGIargINT(arg); + else if (strcmp(curr,"refresh")==0) + servMgr->refreshHTML = getCGIargINT(arg); + else if (strcmp(curr,"auth")==0) + { + if (strcmp(arg,"cookie")==0) + servMgr->authType = ServMgr::AUTH_COOKIE; + else if (strcmp(arg,"http")==0) + servMgr->authType = ServMgr::AUTH_HTTPBASIC; + + }else if (strcmp(curr,"expire")==0) + { + if (strcmp(arg,"session")==0) + servMgr->cookieList.neverExpire = false; + else if (strcmp(arg,"never")==0) + servMgr->cookieList.neverExpire = true; + } + + else if (strcmp(curr,"logDebug")==0) + showLog |= atoi(arg)?(1<autoRelayKeep = getCGIargINT(arg); + else if (strcmp(curr, "autoMaxRelaySetting") ==0) + servMgr->autoMaxRelaySetting = getCGIargINT(arg); + else if (strcmp(curr, "autoBumpSkipCount") ==0) + servMgr->autoBumpSkipCount = getCGIargINT(arg); + else if (strcmp(curr, "kickPushStartRelays") ==0) + servMgr->kickPushStartRelays = getCGIargINT(arg); + else if (strcmp(curr, "kickPushInterval") ==0) + servMgr->kickPushInterval = getCGIargINT(arg); + else if (strcmp(curr, "allowConnectPCST") ==0) + allowConnectPCST = atoi(arg) ? 1 : 0; + else if (strcmp(curr, "enableGetName") ==0) + enableGetName = atoi(arg)? 1 : 0; + else if (strcmp(curr, "autoPort0Kick") ==0) + servMgr->autoPort0Kick = getCGIargBOOL(arg); + else if (strcmp(curr, "allowOnlyVP") ==0) + servMgr->allowOnlyVP = getCGIargBOOL(arg); + else if (strcmp(curr, "kickKeepTime") ==0) + servMgr->kickKeepTime = getCGIargINT(arg); + + else if (strcmp(curr, "maxRelaysIndexTxt") ==0) // for PCRaw (relay) + servMgr->maxRelaysIndexTxt = getCGIargINT(arg); + } + + + + servMgr->showLog = showLog; + servMgr->allowServer1 = allowServer1; + servMgr->allowServer2 = allowServer2; + servMgr->enableGetName = enableGetName; + servMgr->allowConnectPCST = allowConnectPCST; + if (!(servMgr->allowServer1 & ALLOW_HTML) && !(servMgr->allowServer2 & ALLOW_HTML)) + servMgr->allowServer1 |= ALLOW_HTML; + + if (servMgr->serverHost.port != newPort) + { + Host lh(ClientSocket::getIP(NULL),newPort); + char ipstr[64]; + lh.toStr(ipstr); + sprintf(jumpStr,"http://%s/%s/settings.html",ipstr,servMgr->htmlPath); + + servMgr->serverHost.port = newPort; + servMgr->restartServer=true; + //html.setRefresh(3); + //html.setRefreshURL(jumpStr); + //html.startHTML(); + //html.addHead(); + // html.startBody(); + // html.startTagEnd("h1","Please wait..."); + // html.end(); + //html.end(); + + + + //char ipstr[64]; + //servMgr->serverHost.toStr(ipstr); + //sprintf(jumpStr,"/%s/settings.html",ipstr,servMgr->htmlPath); + jumpArg = jumpStr; + + }else + { + sprintf(jumpStr,"/%s/settings.html",servMgr->htmlPath); + jumpArg = jumpStr; + } + + peercastInst->saveSettings(); + + peercastApp->updateSettings(); + + if ((servMgr->isRoot) && (brRoot)) + servMgr->broadcastRootSettings(getUpd); + + + + + + }else if (cmpCGIarg(cmd,"cmd=","fetch")) + { + + ChanInfo info; + String curl; + + char *cp = cmd; + while (cp=nextCGIarg(cp,curr,arg)) + { + if (strcmp(curr,"url")==0) + { + curl.set(arg,String::T_ESC); + curl.convertTo(String::T_UNICODE); + }else if (strcmp(curr,"name")==0) + { + info.name.set(arg,String::T_ESC); + info.name.convertTo(String::T_UNICODE); + }else if (strcmp(curr,"desc")==0) + { + info.desc.set(arg,String::T_ESC); + info.desc.convertTo(String::T_UNICODE); + }else if (strcmp(curr,"genre")==0) + { + info.genre.set(arg,String::T_ESC); + info.genre.convertTo(String::T_UNICODE); + }else if (strcmp(curr,"contact")==0) + { + info.url.set(arg,String::T_ESC); + info.url.convertTo(String::T_UNICODE); + }else if (strcmp(curr,"bitrate")==0) + { + info.bitrate = atoi(arg); + }else if (strcmp(curr,"type")==0) + { + info.contentType = ChanInfo::getTypeFromStr(arg); + } + + } + + info.bcID = chanMgr->broadcastID; + + Channel *c = chanMgr->createChannel(info,NULL); + if (c) + c->startURL(curl.cstr()); + + + sprintf(jumpStr,"/%s/relays.html",servMgr->htmlPath); + jumpArg = jumpStr; + + }else if (cmpCGIarg(cmd,"cmd=","stopserv")) + { + + char *cp = cmd; + while (cp=nextCGIarg(cp,curr,arg)) + { + if (strcmp(curr,"index")==0) + { + Servent *s = servMgr->findServentByIndex(atoi(arg)); + if (s) + s->abort(); + } + } + sprintf(jumpStr,"/%s/connections.html",servMgr->htmlPath); + jumpArg = jumpStr; + + + }else if (cmpCGIarg(cmd,"cmd=","hitlist")) + { + + bool stayConnected=hasCGIarg(cmd,"relay"); + + int index = 0; + ChanHitList *chl = chanMgr->hitlist; + while (chl) + { + if (chl->isUsed()) + { + char tmp[64]; + sprintf(tmp,"c%d=",index); + if (cmpCGIarg(cmd,tmp,"1")) + { + Channel *c; + if (!(c=chanMgr->findChannelByID(chl->info.id))) + { + c = chanMgr->createChannel(chl->info,NULL); + if (!c) + throw StreamException("out of channels"); + c->stayConnected = stayConnected; + c->startGet(); + } + } + } + chl = chl->next; + index++; + } + + char *findArg = getCGIarg(cmd,"keywords="); + + if (hasCGIarg(cmd,"relay")) + { + sys->sleep(500); + sprintf(jumpStr,"/%s/relays.html",servMgr->htmlPath); + jumpArg = jumpStr; + } + }else if (cmpCGIarg(cmd,"cmd=","clear")) + { + char *cp = cmd; + while (cp=nextCGIarg(cp,curr,arg)) + { + if (strcmp(curr,"hostcache")==0) + servMgr->clearHostCache(ServHost::T_SERVENT); + else if (strcmp(curr,"hitlists")==0) + chanMgr->clearHitLists(); + else if (strcmp(curr,"packets")==0) + { + stats.clearRange(Stats::PACKETSSTART,Stats::PACKETSEND); + servMgr->numVersions = 0; + } + } + + sprintf(jumpStr,"/%s/index.html",servMgr->htmlPath); + jumpArg = jumpStr; + + }else if (cmpCGIarg(cmd,"cmd=","upgrade")) + { + if (servMgr->downloadURL[0]) + { + sprintf(jumpStr,"/admin?cmd=redirect&url=%s",servMgr->downloadURL); + jumpArg = jumpStr; + } + + + + + }else if (cmpCGIarg(cmd,"cmd=","connect")) + { + + + Servent *s = servMgr->servents; + { + char tmp[64]; + sprintf(tmp,"c%d=",s->serventIndex); + if (cmpCGIarg(cmd,tmp,"1")) + { + if (hasCGIarg(cmd,"stop")) + s->thread.active = false; + } + s=s->next; + } + sprintf(jumpStr,"/%s/connections.html",servMgr->htmlPath); + jumpArg = jumpStr; + + }else if (cmpCGIarg(cmd,"cmd=","shutdown")) + { + servMgr->shutdownTimer = 1; + + }else if (cmpCGIarg(cmd,"cmd=","stop")) + { + GnuID id; + char *cp = cmd; + while (cp=nextCGIarg(cp,curr,arg)) + { + if (strcmp(curr,"id")==0) + id.fromStr(arg); + } + + Channel *c = chanMgr->findChannelByID(id); + if (c){ + c->thread.active = false; + c->thread.finish = true; + } + + sys->sleep(500); + sprintf(jumpStr,"/%s/relays.html",servMgr->htmlPath); + jumpArg = jumpStr; + + }else if (cmpCGIarg(cmd,"cmd=","bump")) + { + GnuID id; + char *cp = cmd; + while (cp=nextCGIarg(cp,curr,arg)) + { + if (strcmp(curr,"id")==0) + id.fromStr(arg); + } + + Channel *c = chanMgr->findChannelByID(id); + if (c) + c->bump = true; + + sprintf(jumpStr,"/%s/relays.html",servMgr->htmlPath); + jumpArg = jumpStr; + + }else if (cmpCGIarg(cmd,"cmd=","keep")) + { + GnuID id; + char *cp = cmd; + while (cp=nextCGIarg(cp,curr,arg)) + { + if (strcmp(curr,"id")==0) + id.fromStr(arg); + } + + Channel *c = chanMgr->findChannelByID(id); + if (c) + { //JP-Patch + //c->stayConnected = true; + if (!c->stayConnected) + { + //if (servMgr->getFirewall() == ServMgr::FW_OFF) + c->stayConnected = true; + } + else + c->stayConnected = false; + } //JP-Patch + + sprintf(jumpStr,"/%s/relays.html",servMgr->htmlPath); + jumpArg = jumpStr; + + }else if (cmpCGIarg(cmd,"cmd=","relay")) + { + ChanInfo info; + char *cp = cmd; + while (cp=nextCGIarg(cp,curr,arg)) + { + if (strcmp(curr,"id")==0) + info.id.fromStr(arg); + } + + + if (!chanMgr->findChannelByID(info.id)) + { + + ChanHitList *chl = chanMgr->findHitList(info); + if (!chl) + throw StreamException("channel not found"); + + + Channel *c = chanMgr->createChannel(chl->info,NULL); + if (!c) + throw StreamException("out of channels"); + + c->stayConnected = true; + c->startGet(); + } + + sprintf(jumpStr,"/%s/relays.html",servMgr->htmlPath); + jumpArg = jumpStr; + + + }else if (cmpCGIarg(cmd,"net=","add")) + { + + GnuID id; + id.clear(); + while (cmd=nextCGIarg(cmd,curr,arg)) + { + if (strcmp(curr,"ip")==0) + { + Host h; + h.fromStrIP(arg,DEFAULT_PORT); + if (servMgr->addOutgoing(h,id,true)) + LOG_NETWORK("Added connection: %s",arg); + + }else if (strcmp(curr,"id")==0) + { + id.fromStr(arg); + } + + } + + }else if (cmpCGIarg(cmd,"cmd=","logout")) + { + jumpArg = "/"; + servMgr->cookieList.remove(cookie); + + }else if (cmpCGIarg(cmd,"cmd=","login")) + { + GnuID id; + char idstr[64]; + id.generate(); + id.toStr(idstr); + + cookie.set(idstr,sock->host.ip); + servMgr->cookieList.add(cookie); + + http.writeLine(HTTP_SC_FOUND); + if (servMgr->cookieList.neverExpire) + http.writeLineF("%s id=%s; path=/; expires=\"Mon, 01-Jan-3000 00:00:00 GMT\";",HTTP_HS_SETCOOKIE,idstr); + else + http.writeLineF("%s id=%s; path=/;",HTTP_HS_SETCOOKIE,idstr); + http.writeLineF("Location: /%s/index.html",servMgr->htmlPath); + http.writeLine(""); + + }else if (cmpCGIarg(cmd,"cmd=","setmeta")) + { + char *cp = cmd; + while (cp=nextCGIarg(cp,curr,arg)) + { + if (strcmp(curr,"name")==0) + { +/* String chname; + chname.set(arg,String::T_ESC); + chname.convertTo(String::T_ASCII); + for(int i=0; ichannels[i]; + if ((c->isActive()) && (c->status == Channel::S_BROADCASTING) && (strcmp(c->info.name.cstr(),chname.cstr())==0)) + { + ChanInfo newInfo = c->info; + + while (cmd=nextCGIarg(cmd,curr,arg)) + { + String chmeta; + chmeta.set(arg,String::T_ESC); + chmeta.convertTo(String::T_ASCII); + if (strcmp(curr,"desc")==0) + newInfo.desc = chmeta.cstr(); + else if (strcmp(curr,"url")==0) + newInfo.url = chmeta.cstr(); + else if (strcmp(curr,"genre")==0) + newInfo.genre = chmeta.cstr(); + else if (strcmp(curr,"comment")==0) + newInfo.comment = chmeta.cstr(); + else if (strcmp(curr,"t_contact")==0) + newInfo.track.contact = chmeta.cstr(); + else if (strcmp(curr,"t_title")==0) + newInfo.track.title = chmeta.cstr(); + else if (strcmp(curr,"t_artist")==0) + newInfo.track.artist = chmeta.cstr(); + else if (strcmp(curr,"t_album")==0) + newInfo.track.album = chmeta.cstr(); + else if (strcmp(curr,"t_genre")==0) + newInfo.track.genre = chmeta.cstr(); + } + c->updateInfo(newInfo); + char idstr[64]; + newInfo.id.toStr(idstr); + sprintf(jumpStr,"/%s/relayinfo.html?id=%s",servMgr->htmlPath,idstr); + jumpArg = jumpStr; + break; + } + }*/ + String chname; + chname.set(arg,String::T_ESC); + chname.convertTo(String::T_ASCII); + + Channel *c = chanMgr->findChannelByName(chname.cstr()); + if (c && (c->isActive()) && (c->status == Channel::S_BROADCASTING)){ + ChanInfo newInfo = c->info; + while (cmd=nextCGIarg(cmd,curr,arg)) + { + String chmeta; + chmeta.set(arg,String::T_ESC); + chmeta.convertTo(String::T_ASCII); + if (strcmp(curr,"desc")==0) + newInfo.desc = chmeta.cstr(); + else if (strcmp(curr,"url")==0) + newInfo.url = chmeta.cstr(); + else if (strcmp(curr,"genre")==0) + newInfo.genre = chmeta.cstr(); + else if (strcmp(curr,"comment")==0) + newInfo.comment = chmeta.cstr(); + else if (strcmp(curr,"t_contact")==0) + newInfo.track.contact = chmeta.cstr(); + else if (strcmp(curr,"t_title")==0) + newInfo.track.title = chmeta.cstr(); + else if (strcmp(curr,"t_artist")==0) + newInfo.track.artist = chmeta.cstr(); + else if (strcmp(curr,"t_album")==0) + newInfo.track.album = chmeta.cstr(); + else if (strcmp(curr,"t_genre")==0) + newInfo.track.genre = chmeta.cstr(); + } + c->updateInfo(newInfo); + char idstr[64]; + newInfo.id.toStr(idstr); + sprintf(jumpStr,"/%s/relayinfo.html?id=%s",servMgr->htmlPath,idstr); + jumpArg = jumpStr; + } + } + } + if (!jumpArg) + { + jumpArg = "/"; + } + + }else{ + + sprintf(jumpStr,"/%s/index.html",servMgr->htmlPath); + jumpArg = jumpStr; + } + } + + }catch(StreamException &e) + { + html.startTagEnd("h1","ERROR - %s",e.msg); + LOG_ERROR("html: %s",e.msg); + } + + + if (retHTML) + { + if (jumpArg) + { + String jmp(jumpArg,String::T_HTML); + jmp.convertTo(String::T_ASCII); + html.locateTo(jmp.cstr()); + } + } + + +} +// ----------------------------------- +static XML::Node *createChannelXML(Channel *c) +{ + XML::Node *n = c->info.createChannelXML(); + n->add(c->createRelayXML(true)); + n->add(c->info.createTrackXML()); +// n->add(c->info.createServentXML()); + return n; +} +// ----------------------------------- +static XML::Node *createChannelXML(ChanHitList *chl) +{ + XML::Node *n = chl->info.createChannelXML(); + n->add(chl->createXML()); + n->add(chl->info.createTrackXML()); +// n->add(chl->info.createServentXML()); + return n; +} +// ----------------------------------- +void Servent::handshakeXML() +{ + int i; + + + + XML xml; + + XML::Node *rn = new XML::Node("peercast"); + xml.setRoot(rn); + + + rn->add(new XML::Node("servent uptime=\"%d\"",servMgr->getUptime())); + + rn->add(new XML::Node("bandwidth out=\"%d\" in=\"%d\"", + stats.getPerSecond(Stats::BYTESOUT)-stats.getPerSecond(Stats::LOCALBYTESOUT), + stats.getPerSecond(Stats::BYTESIN)-stats.getPerSecond(Stats::LOCALBYTESIN) + )); + + rn->add(new XML::Node("connections total=\"%d\" relays=\"%d\" direct=\"%d\"",servMgr->totalConnected(),servMgr->numStreams(Servent::T_RELAY,true),servMgr->numStreams(Servent::T_DIRECT,true))); + + XML::Node *an = new XML::Node("channels_relayed total=\"%d\"",chanMgr->numChannels()); + rn->add(an); + + Channel *c = chanMgr->channel; + while (c) + { + if (c->isActive()) + an->add(createChannelXML(c)); + c=c->next; + } + + + // add public channels + { + XML::Node *fn = new XML::Node("channels_found total=\"%d\"",chanMgr->numHitLists()); + rn->add(fn); + + ChanHitList *chl = chanMgr->hitlist; + while (chl) + { + if (chl->isUsed()) + fn->add(createChannelXML(chl)); + chl = chl->next; + } + } + + +#if 0 + if (servMgr->isRoot) + { + // add private channels + { + XML::Node *pn = new XML::Node("priv_channels"); + rn->add(pn); + + ChanHitList *chl = chanMgr->hitlist; + while (chl) + { + if (chl->isUsed()) + if (chl->info.isPrivate()) + pn->add(createChannelXML(chl)); + chl = chl->next; + } + } + } +#endif + + XML::Node *hc = new XML::Node("host_cache"); + for(i=0; ihostCache[i]; + if (sh->type != ServHost::T_NONE) + { + char ipstr[64]; + sh->host.toStr(ipstr); + + hc->add(new XML::Node("host ip=\"%s\" type=\"%s\" time=\"%d\"",ipstr,ServHost::getTypeStr(sh->type),sh->time)); + + } + } + rn->add(hc); + + + sock->writeLine(HTTP_SC_OK); + sock->writeLineF("%s %s",HTTP_HS_SERVER,PCX_AGENT); + sock->writeLineF("%s %s",HTTP_HS_CONTENT,MIME_XML); + sock->writeLine("Connection: close"); + + sock->writeLine(""); + + xml.write(*sock); + +} +// ----------------------------------- +void Servent::readICYHeader(HTTP &http, ChanInfo &info, char *pwd) +{ + char *arg = http.getArgStr(); + if (!arg) return; + + if (http.isHeader("x-audiocast-name") || http.isHeader("icy-name") || http.isHeader("ice-name")) + { + info.name.set(arg,String::T_ASCII); + info.name.convertTo(String::T_UNICODE); + + }else if (http.isHeader("x-audiocast-url") || http.isHeader("icy-url") || http.isHeader("ice-url")) + info.url.set(arg,String::T_ASCII); + else if (http.isHeader("x-audiocast-bitrate") || (http.isHeader("icy-br")) || http.isHeader("ice-bitrate") || http.isHeader("icy-bitrate")) + info.bitrate = atoi(arg); + else if (http.isHeader("x-audiocast-genre") || http.isHeader("ice-genre") || http.isHeader("icy-genre")) + { + info.genre.set(arg,String::T_ASCII); + info.genre.convertTo(String::T_UNICODE); + + }else if (http.isHeader("x-audiocast-description") || http.isHeader("ice-description")) + { + info.desc.set(arg,String::T_ASCII); + info.desc.convertTo(String::T_UNICODE); + + }else if (http.isHeader("Authorization")) + http.getAuthUserPass(NULL,pwd); + else if (http.isHeader(PCX_HS_CHANNELID)) + info.id.fromStr(arg); + else if (http.isHeader("ice-password")) + { + if (pwd) + if (strlen(arg) < 64) + strcpy(pwd,arg); + }else if (http.isHeader("content-type")) + { + if (stristr(arg,MIME_OGG)) + info.contentType = ChanInfo::T_OGG; + else if (stristr(arg,MIME_XOGG)) + info.contentType = ChanInfo::T_OGG; + + else if (stristr(arg,MIME_MP3)) + info.contentType = ChanInfo::T_MP3; + else if (stristr(arg,MIME_XMP3)) + info.contentType = ChanInfo::T_MP3; + + else if (stristr(arg,MIME_WMA)) + info.contentType = ChanInfo::T_WMA; + else if (stristr(arg,MIME_WMV)) + info.contentType = ChanInfo::T_WMV; + else if (stristr(arg,MIME_ASX)) + info.contentType = ChanInfo::T_ASX; + + else if (stristr(arg,MIME_NSV)) + info.contentType = ChanInfo::T_NSV; + else if (stristr(arg,MIME_RAW)) + info.contentType = ChanInfo::T_RAW; + + else if (stristr(arg,MIME_MMS)) + info.srcProtocol = ChanInfo::SP_MMS; + else if (stristr(arg,MIME_XPCP)) + info.srcProtocol = ChanInfo::SP_PCP; + else if (stristr(arg,MIME_XPEERCAST)) + info.srcProtocol = ChanInfo::SP_PEERCAST; + + else if (stristr(arg,MIME_XSCPLS)) + info.contentType = ChanInfo::T_PLS; + else if (stristr(arg,MIME_PLS)) + info.contentType = ChanInfo::T_PLS; + else if (stristr(arg,MIME_XPLS)) + info.contentType = ChanInfo::T_PLS; + else if (stristr(arg,MIME_M3U)) + info.contentType = ChanInfo::T_PLS; + else if (stristr(arg,MIME_MPEGURL)) + info.contentType = ChanInfo::T_PLS; + else if (stristr(arg,MIME_TEXT)) + info.contentType = ChanInfo::T_PLS; + + + } + +} + +// ----------------------------------- +void Servent::handshakeICY(Channel::SRC_TYPE type, bool isHTTP) +{ + ChanInfo info; + + HTTP http(*sock); + + // default to mp3 for shoutcast DSP (doesn`t send content-type) + if (type == Channel::SRC_SHOUTCAST) + info.contentType = ChanInfo::T_MP3; + + while (http.nextHeader()) + { + LOG_DEBUG("ICY %s",http.cmdLine); + readICYHeader(http,info,loginPassword); + } + + + + // check password before anything else, if needed + if (strcmp(servMgr->password,loginPassword)!=0) + { + if (!sock->host.isLocalhost() || strlen(loginPassword)) + throw HTTPException(HTTP_SC_UNAUTHORIZED,401); + } + + + // we need a valid IP address before we start + servMgr->checkFirewall(); + + + // attach channel ID to name, channel ID is also encoded with IP address + // to help prevent channel hijacking. + + + info.id = chanMgr->broadcastID; + info.id.encode(NULL,info.name.cstr(),loginMount,info.bitrate); + + LOG_DEBUG("Incoming source: %s : %s",info.name.cstr(),ChanInfo::getTypeStr(info.contentType)); + + + if (isHTTP) + sock->writeStringF("%s\n\n",HTTP_SC_OK); + else + sock->writeLine("OK"); + + Channel *c = chanMgr->findChannelByID(info.id); + if (c) + { + LOG_CHANNEL("ICY channel already active, closing old one"); + c->thread.shutdown(); + } + + + info.comment = chanMgr->broadcastMsg; + info.bcID = chanMgr->broadcastID; + + c = chanMgr->createChannel(info,loginMount); + if (!c) + throw HTTPException(HTTP_SC_UNAVAILABLE,503); + + c->startICY(sock,type); +} + + +// ----------------------------------- +void Servent::handshakeLocalFile(const char *fn) +{ + HTTP http(*sock); + String fileName; + + if (servMgr->getModulePath) //JP-EX + { + peercastApp->getDirectory(); + fileName = servMgr->modulePath; + }else + fileName = peercastApp->getPath(); + + fileName.append(fn); + + LOG_DEBUG("Writing HTML file: %s",fileName.cstr()); + + HTML html("",*sock); + + char *args = strstr(fileName.cstr(),"?"); + if (args) + *args++=0; + + if (fileName.contains(".htm")) + { + html.writeOK(MIME_HTML); + html.writeTemplate(fileName.cstr(),args); + + }else if (fileName.contains(".css")) + { + html.writeOK(MIME_CSS); + html.writeRawFile(fileName.cstr()); + }else if (fileName.contains(".jpg")) + { + html.writeOK(MIME_JPEG); + html.writeRawFile(fileName.cstr()); + }else if (fileName.contains(".gif")) + { + html.writeOK(MIME_GIF); + html.writeRawFile(fileName.cstr()); + }else if (fileName.contains(".png")) + { + html.writeOK(MIME_PNG); + html.writeRawFile(fileName.cstr()); + } +} + +// ----------------------------------- +void Servent::handshakeRemoteFile(const char *dirName) +{ + ClientSocket *rsock = sys->createSocket(); + if (!rsock) + throw HTTPException(HTTP_SC_UNAVAILABLE,503); + + + const char *hostName = "www.peercast.org"; // hardwired for "security" + + Host host; + host.fromStrName(hostName,80); + + + rsock->open(host); + rsock->connect(); + + HTTP rhttp(*rsock); + + rhttp.writeLineF("GET /%s HTTP/1.0",dirName); + rhttp.writeLineF("%s %s",HTTP_HS_HOST,hostName); + rhttp.writeLineF("%s %s",HTTP_HS_CONNECTION,"close"); + rhttp.writeLineF("%s %s",HTTP_HS_ACCEPT,"*/*"); + rhttp.writeLine(""); + + String contentType; + bool isTemplate = false; + while (rhttp.nextHeader()) + { + char *arg = rhttp.getArgStr(); + if (arg) + { + if (rhttp.isHeader("content-type")) + contentType = arg; + } + } + + MemoryStream mem(100*1024); + while (!rsock->eof()) + { + int len=0; + char buf[4096]; + len = rsock->readUpto(buf,sizeof(buf)); + if (len==0) + break; + else + mem.write(buf,len); + + } + rsock->close(); + + int fileLen = mem.getPosition(); + mem.len = fileLen; + mem.rewind(); + + + if (contentType.contains(MIME_HTML)) + isTemplate = true; + + sock->writeLine(HTTP_SC_OK); + sock->writeLineF("%s %s",HTTP_HS_SERVER,PCX_AGENT); + sock->writeLineF("%s %s",HTTP_HS_CACHE,"no-cache"); + sock->writeLineF("%s %s",HTTP_HS_CONNECTION,"close"); + sock->writeLineF("%s %s",HTTP_HS_CONTENT,contentType.cstr()); + + sock->writeLine(""); + + if (isTemplate) + { + HTML html("",*sock); + html.readTemplate(mem,sock,0); + }else + sock->write(mem.buf,fileLen); + + mem.free2(); +} diff --git a/PeerCast.root/PeerCast/core/common/servmgr.cpp b/PeerCast.root/PeerCast/core/common/servmgr.cpp new file mode 100644 index 0000000..7f72944 --- /dev/null +++ b/PeerCast.root/PeerCast/core/common/servmgr.cpp @@ -0,0 +1,2608 @@ +// ------------------------------------------------ +// File : servmgr.cpp +// Date: 4-apr-2002 +// Author: giles +// Desc: +// Management class for handling multiple servent connections. +// +// (c) 2002 peercast.org +// ------------------------------------------------ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// ------------------------------------------------ + +#include +#include "servent.h" +#include "servmgr.h" +#include "inifile.h" +#include "stats.h" +#include "peercast.h" +#include "pcp.h" +#include "atom.h" +#include "version2.h" +#ifdef _DEBUG +#include "chkMemoryLeak.h" +#define DEBUG_NEW new(__FILE__, __LINE__) +#define new DEBUG_NEW +#endif + +ThreadInfo ServMgr::serverThread,ServMgr::idleThread; + +// ----------------------------------- +ServMgr::ServMgr() +{ + validBCID = NULL; + + authType = AUTH_COOKIE; + cookieList.init(); + + serventNum = 0; + + startTime = sys->getTime(); + + allowServer1 = Servent::ALLOW_ALL; + allowServer2 = Servent::ALLOW_BROADCAST; + + clearHostCache(ServHost::T_NONE); + password[0]=0; + + allowGnutella = false; + useFlowControl = true; + + maxServIn = 50; + minGnuIncoming = 10; + maxGnuIncoming = 20; + + lastIncoming = 0; + + maxBitrateOut = 540; //JP-Patch 0-> 540 + maxRelays = MIN_RELAYS; + maxDirect = 0; + refreshHTML = 1800; + + networkID.clear(); + + notifyMask = 0xffff; + + tryoutDelay = 10; + numVersions = 0; + + sessionID.generate(); + + isDisabled = false; + isRoot = false; + + forceIP.clear(); + + strcpy(connectHost,"connect1.peercast.org"); + strcpy(htmlPath,"html/ja"); + + rootHost = "yp.peercast.org"; + rootHost2 = ""; + + serverHost.fromStrIP("127.0.0.1",DEFAULT_PORT); + + firewalled = FW_UNKNOWN; + allowDirect = true; + autoConnect = true; + forceLookup = true; + autoServe = true; + forceNormal = false; + + maxControl = 3; + + queryTTL = 7; + + totalStreams = 0; + firewallTimeout = 30; + pauseLog = false; + showLog = 0; + + shutdownTimer = 0; + + downloadURL[0] = 0; + rootMsg.clear(); + + + restartServer=false; + + setFilterDefaults(); + + servents = NULL; + + modulePath[0] = 0; //JP-EX + kickPushStartRelays = 1; //JP-EX + kickPushInterval = 60; //JP-EX + kickPushTime = 0; //JP-EX + autoRelayKeep = 2; //JP-EX + autoMaxRelaySetting = 0; //JP-EX + autoBumpSkipCount = 50; //JP-EX + enableGetName = 1; //JP-EX + allowConnectPCST = 0; //JP-EX + getModulePath = true; //JP-EX + clearPLS = false; //JP-EX + writeLogFile = false; //JP-EX + + autoPort0Kick = false; + allowOnlyVP = false; + kickKeepTime = 0; + vpDebug = false; + saveIniChannel = true; + saveGuiPos = false; + keepDownstreams = true; + + chanLog=""; + + maxRelaysIndexTxt = 1; // for PCRaw (relay) +} +// ----------------------------------- +BCID *ServMgr::findValidBCID(int index) +{ + int cnt = 0; + BCID *bcid = validBCID; + while (bcid) + { + if (cnt == index) + return bcid; + cnt++; + bcid=bcid->next; + } + return 0; +} +// ----------------------------------- +BCID *ServMgr::findValidBCID(GnuID &id) +{ + BCID *bcid = validBCID; + while (bcid) + { + if (bcid->id.isSame(id)) + return bcid; + bcid=bcid->next; + } + return 0; +} +// ----------------------------------- +void ServMgr::removeValidBCID(GnuID &id) +{ + BCID *bcid = validBCID,*prev=0; + while (bcid) + { + if (bcid->id.isSame(id)) + { + if (prev) + prev->next = bcid->next; + else + validBCID = bcid->next; + return; + } + prev = bcid; + bcid=bcid->next; + } +} +// ----------------------------------- +void ServMgr::addValidBCID(BCID *bcid) +{ + removeValidBCID(bcid->id); + + bcid->next = validBCID; + validBCID = bcid; +} + +// ----------------------------------- +void ServMgr::connectBroadcaster() +{ + if (!rootHost.isEmpty()) + { + if (!numUsed(Servent::T_COUT)) + { + Servent *sv = allocServent(); + if (sv) + { + sv->initOutgoing(Servent::T_COUT); + sys->sleep(3000); + } + } + } +} +// ----------------------------------- +void ServMgr::addVersion(unsigned int ver) +{ + for(int i=0; i 0) && (t < 60)) +// t = 60; +// passiveSearch = t; +} +// ----------------------------------- +bool ServMgr::seenHost(Host &h, ServHost::TYPE type,unsigned int time) +{ + time = sys->getTime()-time; + + for(int i=0; i= time) + return true; + return false; +} + +// ----------------------------------- +void ServMgr::addHost(Host &h, ServHost::TYPE type, unsigned int time) +{ + int i; + if (!h.isValid()) + return; + + ServHost *sh=NULL; + + for(i=0; itime) + sh = &hostCache[i]; + }else{ + sh = &hostCache[i]; + } + } + } + + if (sh) + sh->init(h,type,time); +} + +// ----------------------------------- +void ServMgr::deadHost(Host &h,ServHost::TYPE t) +{ + for(int i=0; i sh->time) + sh = &hostCache[j]; + } + } + } + } + + // add to list + if (sh) + hl[cnt++]=sh->host; + } + + return cnt; +} +// ----------------------------------- +ServHost ServMgr::getOutgoingServent(GnuID &netid) +{ + ServHost host; + + Host lh(ClientSocket::getIP(NULL),0); + + // find newest host not in list + ServHost *sh=NULL; + for(int j=0; jtype == ServHost::T_SERVENT) + { + if (!((lh.globalIP() && !hc->host.globalIP()) || lh.isSame(hc->host))) + { +#if 0 + if (!findServent(Servent::T_OUTGOING,hc->host,netid)) + { + if (!sh) + { + sh = hc; + }else{ + if (hc->time > sh->time) + sh = hc; + } + } +#endif + } + } + } + + if (sh) + host = *sh; + + return host; +} +// ----------------------------------- +Servent *ServMgr::findOldestServent(Servent::TYPE type, bool priv) +{ + Servent *oldest=NULL; + + Servent *s = servents; + while (s) + { + if (s->type == type) + if (s->thread.active) + if (s->isOlderThan(oldest)) + if (s->isPrivate() == priv) + oldest = s; + s=s->next; + } + return oldest; +} +// ----------------------------------- +Servent *ServMgr::findServent(Servent::TYPE type, Host &host, GnuID &netid) +{ + lock.on(); + Servent *s = servents; + while (s) + { + if (s->type == type) + { + Host h = s->getHost(); + if (h.isSame(host) && s->networkID.isSame(netid)) + { + lock.off(); + return s; + } + } + s=s->next; + } + lock.off(); + return NULL; + +} + +// ----------------------------------- +Servent *ServMgr::findServent(unsigned int ip, unsigned short port, GnuID &netid) +{ + lock.on(); + Servent *s = servents; + while (s) + { + if (s->type != Servent::T_NONE) + { + Host h = s->getHost(); + if ((h.ip == ip) && (h.port == port) && (s->networkID.isSame(netid))) + { + lock.off(); + return s; + } + } + s=s->next; + } + lock.off(); + return NULL; + +} + +// ----------------------------------- +Servent *ServMgr::findServent(Servent::TYPE t) +{ + Servent *s = servents; + while (s) + { + if (s->type == t) + return s; + s=s->next; + } + return NULL; +} +// ----------------------------------- +Servent *ServMgr::findServentByIndex(int id) +{ + Servent *s = servents; + int cnt=0; + while (s) + { + if (cnt == id) + return s; + cnt++; + s=s->next; + } + return NULL; +} + +// ----------------------------------- +Servent *ServMgr::findServentByServentID(int id) +{ + Servent *s = servents; + while (s) + { + if (id == s->servent_id){ + return s; + } + s=s->next; + } + return NULL; +} + +// ----------------------------------- +Servent *ServMgr::allocServent() +{ + lock.on(); + + Servent *s = servents; + while (s) + { + if (s->status == Servent::S_FREE) + break; + s=s->next; + } + + if (!s) + { + s = new Servent(++serventNum); + s->next = servents; + servents = s; + + LOG_DEBUG("allocated servent %d",serventNum); + }else + LOG_DEBUG("reused servent %d",s->serventIndex); + + + s->reset(); + + lock.off(); + + return s; +} +// -------------------------------------------------- +void ServMgr::closeConnections(Servent::TYPE type) +{ + Servent *sv = servents; + while (sv) + { + if (sv->isConnected()) + if (sv->type == type) + sv->thread.active = false; + sv=sv->next; + } +} + +// ----------------------------------- +unsigned int ServMgr::numConnected(int type,bool priv,unsigned int uptime) +{ + unsigned int cnt=0; + + unsigned int ctime=sys->getTime(); + Servent *s = servents; + while (s) + { + if (s->thread.active) + if (s->isConnected()) + if (s->type == type) + if (s->isPrivate()==priv) + if ((ctime-s->lastConnect) >= uptime) + cnt++; + + s=s->next; + } + return cnt; +} +// ----------------------------------- +unsigned int ServMgr::numConnected() +{ + unsigned int cnt=0; + + Servent *s = servents; + while (s) + { + if (s->thread.active) + if (s->isConnected()) + cnt++; + + s=s->next; + } + return cnt; +} +// ----------------------------------- +unsigned int ServMgr::numServents() +{ + unsigned int cnt=0; + + Servent *s = servents; + while (s) + { + cnt++; + s=s->next; + } + return cnt; +} + +// ----------------------------------- +unsigned int ServMgr::numUsed(int type) +{ + unsigned int cnt=0; + + Servent *s = servents; + while (s) + { + if (s->type == type) + cnt++; + s=s->next; + } + return cnt; +} +// ----------------------------------- +unsigned int ServMgr::numActiveOnPort(int port) +{ + unsigned int cnt=0; + + Servent *s = servents; + while (s) + { + if (s->thread.active && s->sock && (s->servPort == port)) + cnt++; + s=s->next; + } + return cnt; +} +// ----------------------------------- +unsigned int ServMgr::numActive(Servent::TYPE tp) +{ + unsigned int cnt=0; + + Servent *s = servents; + while (s) + { + if (s->thread.active && s->sock && (s->type == tp)) + cnt++; + s=s->next; + } + return cnt; +} + +// ----------------------------------- +unsigned int ServMgr::totalOutput(bool all) +{ + unsigned int tot = 0; + Servent *s = servents; + while (s) + { + if (s->isConnected()) + if (all || !s->isPrivate()) + if (s->sock) + tot += s->sock->bytesOutPerSec; + s=s->next; + } + + return tot; +} + +// ----------------------------------- +unsigned int ServMgr::totalInput(bool all) +{ + unsigned int tot = 0; + Servent *s = servents; + while (s) + { + if (s->isConnected()) + if (all || !s->isPrivate()) + if (s->sock) + tot += s->sock->bytesInPerSec; + s=s->next; + } + + return tot; +} + +// ----------------------------------- +unsigned int ServMgr::numOutgoing() +{ + int cnt=0; + + Servent *s = servents; + while (s) + { +// if ((s->type == Servent::T_INCOMING) || +// (s->type == Servent::T_OUTGOING)) +// cnt++; + s=s->next; + } + return cnt; +} + +// ----------------------------------- +bool ServMgr::seenPacket(GnuPacket &p) +{ + Servent *s = servents; + while (s) + { + if (s->isConnected()) + if (s->seenIDs.contains(p.id)) + return true; + s=s->next; + } + return false; +} + +// ----------------------------------- +void ServMgr::quit() +{ + LOG_DEBUG("ServMgr is quitting.."); + + serverThread.shutdown(); + + idleThread.shutdown(); + + Servent *s = servents; + while (s) + { + try + { + if (s->thread.active) + { + s->thread.shutdown(); + } + + }catch(StreamException &) + { + } + s=s->next; + } +} + +// ----------------------------------- +int ServMgr::broadcast(GnuPacket &pack,Servent *src) +{ + int cnt=0; + if (pack.ttl) + { + Servent *s = servents; + while (s) + { + + if (s != src) + if (s->isConnected()) + if (s->type == Servent::T_PGNU) + if (!s->seenIDs.contains(pack.id)) + { + + if (src) + if (!src->networkID.isSame(s->networkID)) + continue; + + if (s->outputPacket(pack,false)) + cnt++; + } + s=s->next; + } + } + + LOG_NETWORK("broadcast: %s (%d) to %d servents",GNU_FUNC_STR(pack.func),pack.ttl,cnt); + + return cnt; +} +// ----------------------------------- +int ServMgr::route(GnuPacket &pack, GnuID &routeID, Servent *src) +{ + int cnt=0; + if (pack.ttl) + { + Servent *s = servents; + while (s) + { + if (s != src) + if (s->isConnected()) + if (s->type == Servent::T_PGNU) + if (!s->seenIDs.contains(pack.id)) + if (s->seenIDs.contains(routeID)) + { + if (src) + if (!src->networkID.isSame(s->networkID)) + continue; + + if (s->outputPacket(pack,true)) + cnt++; + } + s=s->next; + } + + } + + LOG_NETWORK("route: %s (%d) to %d servents",GNU_FUNC_STR(pack.func),pack.ttl,cnt); + return cnt; +} +// ----------------------------------- +bool ServMgr::checkForceIP() +{ + if (!forceIP.isEmpty()) + { + unsigned int newIP = ClientSocket::getIP(forceIP.cstr()); + if (serverHost.ip != newIP) + { + serverHost.ip = newIP; + char ipstr[64]; + serverHost.IPtoStr(ipstr); + LOG_DEBUG("Server IP changed to %s",ipstr); + return true; + } + } + return false; +} + +// ----------------------------------- +void ServMgr::checkFirewall() +{ + if ((getFirewall() == FW_UNKNOWN) && !servMgr->rootHost.isEmpty()) + { + + LOG_DEBUG("Checking firewall.."); + Host host; + host.fromStrName(servMgr->rootHost.cstr(),DEFAULT_PORT); + + ClientSocket *sock = sys->createSocket(); + if (!sock) + throw StreamException("Unable to create socket"); + sock->setReadTimeout(30000); + sock->open(host); + sock->connect(); + + AtomStream atom(*sock); + + atom.writeInt(PCP_CONNECT,1); + + GnuID remoteID; + String agent; + Servent::handshakeOutgoingPCP(atom,sock->host,remoteID,agent,true); + + atom.writeInt(PCP_QUIT,PCP_ERROR_QUIT); + + sock->close(); + delete sock; + } +} + +// ----------------------------------- +void ServMgr::setFirewall(FW_STATE state) +{ + if (firewalled != state) + { + char *str; + switch (state) + { + case FW_ON: + str = "ON"; + break; + case FW_OFF: + str = "OFF"; + break; + case FW_UNKNOWN: + default: + str = "UNKNOWN"; + break; + } + + LOG_DEBUG("Firewall is set to %s",str); + firewalled = state; + } +} +// ----------------------------------- +bool ServMgr::isFiltered(int fl, Host &h) +{ + for(int i=0; igetHost(); + + if (sh.globalIP() || (sh.localIP() && h.localIP())) + return true; + } + return false; +} +#endif + +// -------------------------------------------------- +void writeServerSettings(IniFile &iniFile, unsigned int a) +{ + iniFile.writeBoolValue("allowHTML",a & Servent::ALLOW_HTML); + iniFile.writeBoolValue("allowBroadcast",a & Servent::ALLOW_BROADCAST); + iniFile.writeBoolValue("allowNetwork",a & Servent::ALLOW_NETWORK); + iniFile.writeBoolValue("allowDirect",a & Servent::ALLOW_DIRECT); +} +// -------------------------------------------------- +void writeFilterSettings(IniFile &iniFile, ServFilter &f) +{ + char ipstr[64]; + f.host.IPtoStr(ipstr); + iniFile.writeStrValue("ip",ipstr); + iniFile.writeBoolValue("private",f.flags & ServFilter::F_PRIVATE); + iniFile.writeBoolValue("ban",f.flags & ServFilter::F_BAN); + iniFile.writeBoolValue("network",f.flags & ServFilter::F_NETWORK); + iniFile.writeBoolValue("direct",f.flags & ServFilter::F_DIRECT); +} + +// -------------------------------------------------- +static void writeServHost(IniFile &iniFile, ServHost &sh) +{ + iniFile.writeSection("Host"); + + char ipStr[64]; + sh.host.toStr(ipStr); + iniFile.writeStrValue("type",ServHost::getTypeStr(sh.type)); + iniFile.writeStrValue("address",ipStr); + iniFile.writeIntValue("time",sh.time); + + iniFile.writeLine("[End]"); +} + +#ifdef WIN32 +extern bool guiFlg; +extern WINDOWPLACEMENT winPlace; +extern HWND guiWnd; +#endif + +// -------------------------------------------------- +void ServMgr::saveSettings(const char *fn) +{ + IniFile iniFile; + if (!iniFile.openWriteReplace(fn)) + { + LOG_ERROR("Unable to open ini file"); + }else{ + LOG_DEBUG("Saving settings to: %s",fn); + + char idStr[64]; + + iniFile.writeSection("Server"); + iniFile.writeIntValue("serverPort",servMgr->serverHost.port); + iniFile.writeBoolValue("autoServe",servMgr->autoServe); + iniFile.writeStrValue("forceIP",servMgr->forceIP); + iniFile.writeBoolValue("isRoot",servMgr->isRoot); + iniFile.writeIntValue("maxBitrateOut",servMgr->maxBitrateOut); + iniFile.writeIntValue("maxRelays",servMgr->maxRelays); + iniFile.writeIntValue("maxDirect",servMgr->maxDirect); + iniFile.writeIntValue("maxRelaysPerChannel",chanMgr->maxRelaysPerChannel); + iniFile.writeIntValue("firewallTimeout",firewallTimeout); + iniFile.writeBoolValue("forceNormal",forceNormal); + iniFile.writeStrValue("rootMsg",rootMsg.cstr()); + iniFile.writeStrValue("authType",servMgr->authType==ServMgr::AUTH_COOKIE?"cookie":"http-basic"); + iniFile.writeStrValue("cookiesExpire",servMgr->cookieList.neverExpire==true?"never":"session"); + iniFile.writeStrValue("htmlPath",servMgr->htmlPath); + iniFile.writeIntValue("minPGNUIncoming",servMgr->minGnuIncoming); + iniFile.writeIntValue("maxPGNUIncoming",servMgr->maxGnuIncoming); + iniFile.writeIntValue("maxServIn",servMgr->maxServIn); + iniFile.writeStrValue("chanLog",servMgr->chanLog.cstr()); + + networkID.toStr(idStr); + iniFile.writeStrValue("networkID",idStr); + + + iniFile.writeSection("Broadcast"); + iniFile.writeIntValue("broadcastMsgInterval",chanMgr->broadcastMsgInterval); + iniFile.writeStrValue("broadcastMsg",chanMgr->broadcastMsg.cstr()); + iniFile.writeIntValue("icyMetaInterval",chanMgr->icyMetaInterval); + chanMgr->broadcastID.toStr(idStr); + iniFile.writeStrValue("broadcastID",idStr); + iniFile.writeIntValue("hostUpdateInterval",chanMgr->hostUpdateInterval); + iniFile.writeIntValue("maxControlConnections",servMgr->maxControl); + iniFile.writeStrValue("rootHost",servMgr->rootHost.cstr()); + + iniFile.writeSection("Client"); + iniFile.writeIntValue("refreshHTML",refreshHTML); + iniFile.writeIntValue("relayBroadcast",servMgr->relayBroadcast); + iniFile.writeIntValue("minBroadcastTTL",chanMgr->minBroadcastTTL); + iniFile.writeIntValue("maxBroadcastTTL",chanMgr->maxBroadcastTTL); + iniFile.writeIntValue("pushTries",chanMgr->pushTries); + iniFile.writeIntValue("pushTimeout",chanMgr->pushTimeout); + iniFile.writeIntValue("maxPushHops",chanMgr->maxPushHops); + iniFile.writeIntValue("autoQuery",chanMgr->autoQuery); + iniFile.writeIntValue("queryTTL",servMgr->queryTTL); + + + iniFile.writeSection("Privacy"); + iniFile.writeStrValue("password",servMgr->password); + iniFile.writeIntValue("maxUptime",chanMgr->maxUptime); + + //JP-EX + iniFile.writeSection("Extend"); + iniFile.writeIntValue("autoRelayKeep",servMgr->autoRelayKeep); + iniFile.writeIntValue("autoMaxRelaySetting",servMgr->autoMaxRelaySetting); + iniFile.writeIntValue("autoBumpSkipCount",servMgr->autoBumpSkipCount); + iniFile.writeIntValue("kickPushStartRelays",servMgr->kickPushStartRelays); + iniFile.writeIntValue("kickPushInterval",servMgr->kickPushInterval); + iniFile.writeIntValue("allowConnectPCST",servMgr->allowConnectPCST); + iniFile.writeIntValue("enableGetName",servMgr->enableGetName); + + iniFile.writeIntValue("maxRelaysIndexTxt", servMgr->maxRelaysIndexTxt); // for PCRaw (relay) + + //JP-EX + iniFile.writeSection("Windows"); + iniFile.writeBoolValue("getModulePath",servMgr->getModulePath); + iniFile.writeBoolValue("clearPLS",servMgr->clearPLS); + iniFile.writeBoolValue("writeLogFile",servMgr->writeLogFile); + + //VP-EX + iniFile.writeStrValue("rootHost2",servMgr->rootHost2.cstr()); + iniFile.writeBoolValue("autoPort0Kick",servMgr->autoPort0Kick); + iniFile.writeBoolValue("allowOnlyVP",servMgr->allowOnlyVP); + iniFile.writeIntValue("kickKeepTime",servMgr->kickKeepTime); + iniFile.writeBoolValue("vpDebug", servMgr->vpDebug); + iniFile.writeBoolValue("saveIniChannel", servMgr->saveIniChannel); +#ifdef WIN32 + iniFile.writeBoolValue("saveGuiPos", servMgr->saveGuiPos); + if (guiFlg){ + GetWindowPlacement(guiWnd, &winPlace); + iniFile.writeIntValue("guiTop", winPlace.rcNormalPosition.top); + iniFile.writeIntValue("guiBottom", winPlace.rcNormalPosition.bottom); + iniFile.writeIntValue("guiLeft", winPlace.rcNormalPosition.left); + iniFile.writeIntValue("guiRight", winPlace.rcNormalPosition.right); + } +#endif + int i; + + for(i=0; inumFilters; i++) + { + iniFile.writeSection("Filter"); + writeFilterSettings(iniFile,servMgr->filters[i]); + iniFile.writeLine("[End]"); + } + + iniFile.writeSection("Notify"); + iniFile.writeBoolValue("PeerCast",notifyMask&NT_PEERCAST); + iniFile.writeBoolValue("Broadcasters",notifyMask&NT_BROADCASTERS); + iniFile.writeBoolValue("TrackInfo",notifyMask&NT_TRACKINFO); + iniFile.writeLine("[End]"); + + + iniFile.writeSection("Server1"); + writeServerSettings(iniFile,allowServer1); + iniFile.writeLine("[End]"); + + iniFile.writeSection("Server2"); + writeServerSettings(iniFile,allowServer2); + iniFile.writeLine("[End]"); + + + + iniFile.writeSection("Debug"); + iniFile.writeBoolValue("logDebug",(showLog&(1<idleSleepTime); + + + if (servMgr->validBCID) + { + BCID *bcid = servMgr->validBCID; + while (bcid) + { + iniFile.writeSection("ValidBCID"); + char idstr[128]; + bcid->id.toStr(idstr); + iniFile.writeStrValue("id",idstr); + iniFile.writeStrValue("name",bcid->name.cstr()); + iniFile.writeStrValue("email",bcid->email.cstr()); + iniFile.writeStrValue("url",bcid->url.cstr()); + iniFile.writeBoolValue("valid",bcid->valid); + iniFile.writeLine("[End]"); + + bcid=bcid->next; + } + } + + if (servMgr->saveIniChannel){ + Channel *c = chanMgr->channel; + while (c) + { + char idstr[64]; + if (c->isActive() && c->stayConnected) + { + c->getIDStr(idstr); + + iniFile.writeSection("RelayChannel"); + iniFile.writeStrValue("name",c->getName()); + iniFile.writeStrValue("genre",c->info.genre.cstr()); + if (!c->sourceURL.isEmpty()) + iniFile.writeStrValue("sourceURL",c->sourceURL.cstr()); + iniFile.writeStrValue("sourceProtocol",ChanInfo::getProtocolStr(c->info.srcProtocol)); + iniFile.writeStrValue("contentType",ChanInfo::getTypeStr(c->info.contentType)); + iniFile.writeIntValue("bitrate",c->info.bitrate); + iniFile.writeStrValue("contactURL",c->info.url.cstr()); + iniFile.writeStrValue("id",idstr); + iniFile.writeBoolValue("stayConnected",c->stayConnected); + + ChanHitList *chl = chanMgr->findHitListByID(c->info.id); + if (chl) + { + + ChanHitSearch chs; + chs.trackersOnly = true; + if (chl->pickHits(chs)) + { + char ipStr[64]; + chs.best[0].host.toStr(ipStr); + iniFile.writeStrValue("tracker",ipStr); + } + } + iniFile.writeLine("[End]"); + } + c=c->next; + } + } + + + +#if 0 + Servent *s = servents; + while (s) + { + if (s->type == Servent::T_OUTGOING) + if (s->isConnected()) + { + ServHost sh; + Host h = s->getHost(); + sh.init(h,ServHost::T_SERVENT,0,s->networkID); + writeServHost(iniFile,sh); + } + s=s->next; + } +#endif + + for(i=0; ihostCache[i]; + if (sh->type != ServHost::T_NONE) + writeServHost(iniFile,*sh); + } + + iniFile.close(); + } +} +// -------------------------------------------------- +unsigned int readServerSettings(IniFile &iniFile, unsigned int a) +{ + while (iniFile.readNext()) + { + if (iniFile.isName("[End]")) + break; + else if (iniFile.isName("allowHTML")) + a = iniFile.getBoolValue()?a|Servent::ALLOW_HTML:a&~Servent::ALLOW_HTML; + else if (iniFile.isName("allowDirect")) + a = iniFile.getBoolValue()?a|Servent::ALLOW_DIRECT:a&~Servent::ALLOW_DIRECT; + else if (iniFile.isName("allowNetwork")) + a = iniFile.getBoolValue()?a|Servent::ALLOW_NETWORK:a&~Servent::ALLOW_NETWORK; + else if (iniFile.isName("allowBroadcast")) + a = iniFile.getBoolValue()?a|Servent::ALLOW_BROADCAST:a&~Servent::ALLOW_BROADCAST; + } + return a; +} +// -------------------------------------------------- +void readFilterSettings(IniFile &iniFile, ServFilter &sv) +{ + sv.host.init(); + + while (iniFile.readNext()) + { + if (iniFile.isName("[End]")) + break; + else if (iniFile.isName("ip")) + sv.host.fromStrIP(iniFile.getStrValue(),0); + else if (iniFile.isName("private")) + sv.flags = (sv.flags & ~ServFilter::F_PRIVATE) | (iniFile.getBoolValue()?ServFilter::F_PRIVATE:0); + else if (iniFile.isName("ban")) + sv.flags = (sv.flags & ~ServFilter::F_BAN) | (iniFile.getBoolValue()?ServFilter::F_BAN:0); + else if (iniFile.isName("allow") || iniFile.isName("network")) + sv.flags = (sv.flags & ~ServFilter::F_NETWORK) | (iniFile.getBoolValue()?ServFilter::F_NETWORK:0); + else if (iniFile.isName("direct")) + sv.flags = (sv.flags & ~ServFilter::F_DIRECT) | (iniFile.getBoolValue()?ServFilter::F_DIRECT:0); + } + +} +// -------------------------------------------------- +void ServMgr::loadSettings(const char *fn) +{ + IniFile iniFile; + + if (!iniFile.openReadOnly(fn)) + saveSettings(fn); + + + servMgr->numFilters = 0; + showLog = 0; + + if (iniFile.openReadOnly(fn)) + { + while (iniFile.readNext()) + { + // server settings + if (iniFile.isName("serverPort")) + servMgr->serverHost.port = iniFile.getIntValue(); + else if (iniFile.isName("autoServe")) + servMgr->autoServe = iniFile.getBoolValue(); + else if (iniFile.isName("autoConnect")) + servMgr->autoConnect = iniFile.getBoolValue(); + else if (iniFile.isName("icyPassword")) // depreciated + strcpy(servMgr->password,iniFile.getStrValue()); + else if (iniFile.isName("forceIP")) + servMgr->forceIP = iniFile.getStrValue(); + else if (iniFile.isName("isRoot")) + servMgr->isRoot = iniFile.getBoolValue(); + else if (iniFile.isName("broadcastID")) + { + chanMgr->broadcastID.fromStr(iniFile.getStrValue()); + chanMgr->broadcastID.id[0] = PCP_BROADCAST_FLAGS; // hacky, but we need to fix old clients + + }else if (iniFile.isName("htmlPath")) + strcpy(servMgr->htmlPath,iniFile.getStrValue()); + else if (iniFile.isName("maxPGNUIncoming")) + servMgr->maxGnuIncoming = iniFile.getIntValue(); + else if (iniFile.isName("minPGNUIncoming")) + servMgr->minGnuIncoming = iniFile.getIntValue(); + + else if (iniFile.isName("maxControlConnections")) + { + servMgr->maxControl = iniFile.getIntValue(); + + } + else if (iniFile.isName("maxBitrateOut")) + servMgr->maxBitrateOut = iniFile.getIntValue(); + + else if (iniFile.isName("maxStreamsOut")) // depreciated + servMgr->setMaxRelays(iniFile.getIntValue()); + else if (iniFile.isName("maxRelays")) + servMgr->setMaxRelays(iniFile.getIntValue()); + else if (iniFile.isName("maxDirect")) + servMgr->maxDirect = iniFile.getIntValue(); + + else if (iniFile.isName("maxStreamsPerChannel")) // depreciated + chanMgr->maxRelaysPerChannel = iniFile.getIntValue(); + else if (iniFile.isName("maxRelaysPerChannel")) + chanMgr->maxRelaysPerChannel = iniFile.getIntValue(); + + else if (iniFile.isName("firewallTimeout")) + firewallTimeout = iniFile.getIntValue(); + else if (iniFile.isName("forceNormal")) + forceNormal = iniFile.getBoolValue(); + else if (iniFile.isName("broadcastMsgInterval")) + chanMgr->broadcastMsgInterval = iniFile.getIntValue(); + else if (iniFile.isName("broadcastMsg")) + chanMgr->broadcastMsg.set(iniFile.getStrValue(),String::T_ASCII); + else if (iniFile.isName("hostUpdateInterval")) + chanMgr->hostUpdateInterval = iniFile.getIntValue(); + else if (iniFile.isName("icyMetaInterval")) + chanMgr->icyMetaInterval = iniFile.getIntValue(); + else if (iniFile.isName("maxServIn")) + servMgr->maxServIn = iniFile.getIntValue(); + else if (iniFile.isName("chanLog")) + servMgr->chanLog.set(iniFile.getStrValue(),String::T_ASCII); + + else if (iniFile.isName("rootMsg")) + rootMsg.set(iniFile.getStrValue()); + else if (iniFile.isName("networkID")) + networkID.fromStr(iniFile.getStrValue()); + else if (iniFile.isName("authType")) + { + char *t = iniFile.getStrValue(); + if (stricmp(t,"cookie")==0) + servMgr->authType = ServMgr::AUTH_COOKIE; + else if (stricmp(t,"http-basic")==0) + servMgr->authType = ServMgr::AUTH_HTTPBASIC; + }else if (iniFile.isName("cookiesExpire")) + { + char *t = iniFile.getStrValue(); + if (stricmp(t,"never")==0) + servMgr->cookieList.neverExpire = true; + else if (stricmp(t,"session")==0) + servMgr->cookieList.neverExpire = false; + + + } + + // privacy settings + else if (iniFile.isName("password")) + strcpy(servMgr->password,iniFile.getStrValue()); + else if (iniFile.isName("maxUptime")) + chanMgr->maxUptime = iniFile.getIntValue(); + + // client settings + + else if (iniFile.isName("rootHost")) + { + if (!PCP_FORCE_YP) + servMgr->rootHost = iniFile.getStrValue(); + + }else if (iniFile.isName("deadHitAge")) + chanMgr->deadHitAge = iniFile.getIntValue(); + else if (iniFile.isName("tryoutDelay")) + servMgr->tryoutDelay = iniFile.getIntValue(); + else if (iniFile.isName("refreshHTML")) + refreshHTML = iniFile.getIntValue(); + else if (iniFile.isName("relayBroadcast")) + { + servMgr->relayBroadcast = iniFile.getIntValue(); + if (servMgr->relayBroadcast < 30) + servMgr->relayBroadcast = 30; + } + else if (iniFile.isName("minBroadcastTTL")) + chanMgr->minBroadcastTTL = iniFile.getIntValue(); + else if (iniFile.isName("maxBroadcastTTL")) + chanMgr->maxBroadcastTTL = iniFile.getIntValue(); + else if (iniFile.isName("pushTimeout")) + chanMgr->pushTimeout = iniFile.getIntValue(); + else if (iniFile.isName("pushTries")) + chanMgr->pushTries = iniFile.getIntValue(); + else if (iniFile.isName("maxPushHops")) + chanMgr->maxPushHops = iniFile.getIntValue(); + else if (iniFile.isName("autoQuery")) + { + chanMgr->autoQuery = iniFile.getIntValue(); + if ((chanMgr->autoQuery < 300) && (chanMgr->autoQuery > 0)) + chanMgr->autoQuery = 300; + } + else if (iniFile.isName("queryTTL")) + { + servMgr->queryTTL = iniFile.getIntValue(); + } + + //JP-Extend + else if (iniFile.isName("autoRelayKeep")) + servMgr->autoRelayKeep = iniFile.getIntValue(); + else if (iniFile.isName("autoMaxRelaySetting")) + servMgr->autoMaxRelaySetting = iniFile.getIntValue(); + else if (iniFile.isName("autoBumpSkipCount")) + servMgr->autoBumpSkipCount = iniFile.getIntValue(); + else if (iniFile.isName("kickPushStartRelays")) + servMgr->kickPushStartRelays = iniFile.getIntValue(); + else if (iniFile.isName("kickPushInterval")) + { + servMgr->kickPushInterval = iniFile.getIntValue(); + if (servMgr->kickPushInterval < 60) + servMgr->kickPushInterval = 0; + } + else if (iniFile.isName("allowConnectPCST")) + servMgr->allowConnectPCST = iniFile.getIntValue(); + else if (iniFile.isName("enableGetName")) + servMgr->enableGetName = iniFile.getIntValue(); + + else if (iniFile.isName("maxRelaysIndexTxt")) // for PCRaw (relay) + servMgr->maxRelaysIndexTxt = iniFile.getIntValue(); + + //JP-Windows + else if (iniFile.isName("getModulePath")) + servMgr->getModulePath = iniFile.getBoolValue(); + else if (iniFile.isName("clearPLS")) + servMgr->clearPLS = iniFile.getBoolValue(); + else if (iniFile.isName("writeLogFile")) + servMgr->writeLogFile = iniFile.getBoolValue(); + + //VP-EX + else if (iniFile.isName("rootHost2")) + { + if (!PCP_FORCE_YP) + servMgr->rootHost2 = iniFile.getStrValue(); + } + else if (iniFile.isName("autoPort0Kick")) + servMgr->autoPort0Kick = iniFile.getBoolValue(); + else if (iniFile.isName("allowOnlyVP")) + servMgr->allowOnlyVP = iniFile.getBoolValue(); + else if (iniFile.isName("kickKeepTime")) + servMgr->kickKeepTime = iniFile.getIntValue(); + else if (iniFile.isName("vpDebug")) + servMgr->vpDebug = iniFile.getBoolValue(); + else if (iniFile.isName("saveIniChannel")) + servMgr->saveIniChannel = iniFile.getBoolValue(); +#ifdef WIN32 + else if (iniFile.isName("saveGuiPos")) + servMgr->saveGuiPos = iniFile.getBoolValue(); + else if (iniFile.isName("guiTop")) + winPlace.rcNormalPosition.top = iniFile.getIntValue(); + else if (iniFile.isName("guiBottom")) + winPlace.rcNormalPosition.bottom = iniFile.getIntValue(); + else if (iniFile.isName("guiLeft")) + winPlace.rcNormalPosition.left = iniFile.getIntValue(); + else if (iniFile.isName("guiRight")){ + winPlace.rcNormalPosition.right = iniFile.getIntValue(); + winPlace.length = sizeof(winPlace); + winPlace.flags = 0; + winPlace.showCmd = 1; + winPlace.ptMinPosition.x = -1; + winPlace.ptMinPosition.y = -1; + winPlace.ptMaxPosition.x = -1; + winPlace.ptMaxPosition.y = -1; + if (servMgr->saveGuiPos){ + guiFlg = true; + } + } +#endif + + // debug + else if (iniFile.isName("logDebug")) + showLog |= iniFile.getBoolValue() ? 1<idleSleepTime = iniFile.getIntValue(); + else if (iniFile.isName("[Server1]")) + allowServer1 = readServerSettings(iniFile,allowServer1); + else if (iniFile.isName("[Server2]")) + allowServer2 = readServerSettings(iniFile,allowServer2); + else if (iniFile.isName("[Filter]")) + { + readFilterSettings(iniFile,filters[numFilters]); + + if (numFilters < (MAX_FILTERS-1)) + numFilters++; + } + else if (iniFile.isName("[Notify]")) + { + notifyMask = NT_UPGRADE; + while (iniFile.readNext()) + { + if (iniFile.isName("[End]")) + break; + else if (iniFile.isName("PeerCast")) + notifyMask |= iniFile.getBoolValue()?NT_PEERCAST:0; + else if (iniFile.isName("Broadcasters")) + notifyMask |= iniFile.getBoolValue()?NT_BROADCASTERS:0; + else if (iniFile.isName("TrackInfo")) + notifyMask |= iniFile.getBoolValue()?NT_TRACKINFO:0; + } + + } + else if (iniFile.isName("[RelayChannel]")) + { + ChanInfo info; + bool stayConnected=false; + String sourceURL; + while (iniFile.readNext()) + { + if (iniFile.isName("[End]")) + break; + else if (iniFile.isName("name")) + info.name.set(iniFile.getStrValue()); + else if (iniFile.isName("id")) + info.id.fromStr(iniFile.getStrValue()); + else if (iniFile.isName("sourceType")) + info.srcProtocol = ChanInfo::getProtocolFromStr(iniFile.getStrValue()); + else if (iniFile.isName("contentType")) + info.contentType = ChanInfo::getTypeFromStr(iniFile.getStrValue()); + else if (iniFile.isName("stayConnected")) + stayConnected = iniFile.getBoolValue(); + else if (iniFile.isName("sourceURL")) + sourceURL.set(iniFile.getStrValue()); + else if (iniFile.isName("genre")) + info.genre.set(iniFile.getStrValue()); + else if (iniFile.isName("contactURL")) + info.url.set(iniFile.getStrValue()); + else if (iniFile.isName("bitrate")) + info.bitrate = atoi(iniFile.getStrValue()); + else if (iniFile.isName("tracker")) + { + ChanHit hit; + hit.init(); + hit.tracker = true; + hit.host.fromStrName(iniFile.getStrValue(),DEFAULT_PORT); + hit.rhost[0] = hit.host; + hit.rhost[1] = hit.host; + hit.chanID = info.id; + hit.recv = true; + chanMgr->addHit(hit); + } + + } + if (sourceURL.isEmpty()) + { + chanMgr->createRelay(info,stayConnected); + }else + { + info.bcID = chanMgr->broadcastID; + Channel *c = chanMgr->createChannel(info,NULL); + if (c) + c->startURL(sourceURL.cstr()); + } + } else if (iniFile.isName("[Host]")) + { + Host h; + ServHost::TYPE type=ServHost::T_NONE; + bool firewalled=false; + unsigned int time=0; + while (iniFile.readNext()) + { + if (iniFile.isName("[End]")) + break; + else if (iniFile.isName("address")) + h.fromStrIP(iniFile.getStrValue(),DEFAULT_PORT); + else if (iniFile.isName("type")) + type = ServHost::getTypeFromStr(iniFile.getStrValue()); + else if (iniFile.isName("time")) + time = iniFile.getIntValue(); + } + servMgr->addHost(h,type,time); + + } else if (iniFile.isName("[ValidBCID]")) + { + BCID *bcid = new BCID(); + while (iniFile.readNext()) + { + if (iniFile.isName("[End]")) + break; + else if (iniFile.isName("id")) + bcid->id.fromStr(iniFile.getStrValue()); + else if (iniFile.isName("name")) + bcid->name.set(iniFile.getStrValue()); + else if (iniFile.isName("email")) + bcid->email.set(iniFile.getStrValue()); + else if (iniFile.isName("url")) + bcid->url.set(iniFile.getStrValue()); + else if (iniFile.isName("valid")) + bcid->valid = iniFile.getBoolValue(); + } + servMgr->addValidBCID(bcid); + } + } + } + + if (!numFilters) + setFilterDefaults(); + +} + +// -------------------------------------------------- +unsigned int ServMgr::numStreams(GnuID &cid, Servent::TYPE tp, bool all) +{ + int cnt = 0; + Servent *sv = servents; + while (sv) + { + if (sv->isConnected()) + if (sv->type == tp) + if (sv->chanID.isSame(cid)) + if (all || !sv->isPrivate()) + cnt++; + sv=sv->next; + } + return cnt; +} +// -------------------------------------------------- +unsigned int ServMgr::numStreams(Servent::TYPE tp, bool all) +{ + int cnt = 0; + Servent *sv = servents; + while (sv) + { + if (sv->isConnected()) + if (sv->type == tp) + if (all || !sv->isPrivate()) + { + // for PCRaw (relay) start. + if(tp == Servent::T_RELAY) + { + Channel *ch = chanMgr->findChannelByID(sv->chanID); + + // index.txt‚̓JƒEƒ“ƒg‚µ‚È‚¢ + if(!isIndexTxt(ch)) + cnt++; + } + else + // for PCRaw (relay) end. + { + cnt++; + } + } + sv=sv->next; + } + return cnt; +} + +// -------------------------------------------------- +bool ServMgr::getChannel(char *str,ChanInfo &info, bool relay) +{ + // remove file extension (only added for winamp) + //char *ext = strstr(str,"."); + //if (ext) *ext = 0; + + procConnectArgs(str,info); + + WLockBlock wb(&(chanMgr->channellock)); + + wb.on(); + Channel *ch; + + ch = chanMgr->findChannelByNameID(info); + if (ch && ch->thread.active) + { + + if (!ch->isPlaying()) + { + if (relay) + { + ch->info.lastPlayStart = 0; // force reconnect + ch->info.lastPlayEnd = 0; + }else + return false; + } + + info = ch->info; // get updated channel info + + return true; + }else + { + if (relay) + { + wb.off(); + ch = chanMgr->findAndRelay(info); + if (ch) + { + // «Exception point + info = ch->info; //get updated channel info + return true; + } + } + } + + return false; +} +// -------------------------------------------------- +int ServMgr::findChannel(ChanInfo &info) +{ +#if 0 + char idStr[64]; + info.id.toStr(idStr); + + + if (info.id.isSet()) + { + // if we have an ID then try and connect to known hosts carrying channel. + ServHost sh = getOutgoingServent(info.id); + addOutgoing(sh.host,info.id,true); + } + + GnuPacket pack; + + XML xml; + XML::Node *n = info.createQueryXML(); + xml.setRoot(n); + pack.initFind(NULL,&xml,servMgr->queryTTL); + + addReplyID(pack.id); + int cnt = broadcast(pack,NULL); + + LOG_NETWORK("Querying network: %s %s - %d servents",info.name.cstr(),idStr,cnt); + + return cnt; +#endif + return 0; +} +// -------------------------------------------------- +// add outgoing network connection from string (ip:port format) +bool ServMgr::addOutgoing(Host h, GnuID &netid, bool pri) +{ +#if 0 + if (h.ip) + { + if (!findServent(h.ip,h.port,netid)) + { + Servent *sv = allocServent(); + if (sv) + { + if (pri) + sv->priorityConnect = true; + sv->networkID = netid; + sv->initOutgoing(h,Servent::T_OUTGOING); + return true; + } + } + } +#endif + return false; +} +// -------------------------------------------------- +Servent *ServMgr::findConnection(Servent::TYPE t,GnuID &sid) +{ + Servent *sv = servents; + while (sv) + { + if (sv->isConnected()) + if (sv->type == t) + if (sv->remoteID.isSame(sid)) + return sv; + sv=sv->next; + } + return NULL; +} + +// -------------------------------------------------- +void ServMgr::procConnectArgs(char *str,ChanInfo &info) +{ + char arg[MAX_CGI_LEN]; + char curr[MAX_CGI_LEN]; + + char *args = strstr(str,"?"); + if (args) + *args++=0; + + info.initNameID(str); + + if (args) + { + + while (args=nextCGIarg(args,curr,arg)) + { + LOG_DEBUG("cmd: %s, arg: %s",curr,arg); + + if (strcmp(curr,"sip")==0) + // sip - add network connection to client with channel + { + Host h; + h.fromStrName(arg,DEFAULT_PORT); + if (addOutgoing(h,servMgr->networkID,true)) + LOG_NETWORK("Added connection: %s",arg); + + }else if (strcmp(curr,"pip")==0) + // pip - add private network connection to client with channel + { + Host h; + h.fromStrName(arg,DEFAULT_PORT); + if (addOutgoing(h,info.id,true)) + LOG_NETWORK("Added private connection: %s",arg); + }else if (strcmp(curr,"ip")==0) + // ip - add hit + { + Host h; + h.fromStrName(arg,DEFAULT_PORT); + ChanHit hit; + hit.init(); + hit.host = h; + hit.rhost[0] = h; + hit.rhost[1].init(); + hit.chanID = info.id; + hit.recv = true; + + chanMgr->addHit(hit); + }else if (strcmp(curr,"tip")==0) + // tip - add tracker hit + { + Host h; + h.fromStrName(arg,DEFAULT_PORT); + chanMgr->hitlistlock.on(); + chanMgr->addHit(h,info.id,true); + chanMgr->hitlistlock.off(); + + } + + + } + } +} + +// -------------------------------------------------- +bool ServMgr::start() +{ + char idStr[64]; + + + const char *priv; +#if PRIVATE_BROADCASTER + priv = "(private)"; +#else + priv = ""; +#endif +#ifdef VERSION_EX + LOG_DEBUG("Peercast %s, %s %s",PCX_VERSTRING_EX,peercastApp->getClientTypeOS(),priv); +#else + LOG_DEBUG("Peercast %s, %s %s",PCX_VERSTRING,peercastApp->getClientTypeOS(),priv); +#endif + + sessionID.toStr(idStr); + LOG_DEBUG("SessionID: %s",idStr); + + chanMgr->broadcastID.toStr(idStr); + LOG_DEBUG("BroadcastID: %s",idStr); + checkForceIP(); + + + serverThread.func = ServMgr::serverProc; + if (!sys->startThread(&serverThread)) + return false; + + idleThread.func = ServMgr::idleProc; + if (!sys->startThread(&idleThread)) + return false; + + return true; +} +// -------------------------------------------------- +int ServMgr::clientProc(ThreadInfo *thread) +{ +#if 0 + thread->lock(); + + GnuID netID; + netID = servMgr->networkID; + + while(thread->active) + { + if (servMgr->autoConnect) + { + if (servMgr->needConnections() || servMgr->forceLookup) + { + if (servMgr->needHosts() || servMgr->forceLookup) + { + // do lookup to find some hosts + + Host lh; + lh.fromStrName(servMgr->connectHost,DEFAULT_PORT); + + + if (!servMgr->findServent(lh.ip,lh.port,netID)) + { + Servent *sv = servMgr->allocServent(); + if (sv) + { + LOG_DEBUG("Lookup: %s",servMgr->connectHost); + sv->networkID = netID; + sv->initOutgoing(lh,Servent::T_LOOKUP); + servMgr->forceLookup = false; + } + } + } + + for(int i=0; ioutUsedFull()) + break; + if (servMgr->tryFull()) + break; + + + ServHost sh = servMgr->getOutgoingServent(netID); + + if (!servMgr->addOutgoing(sh.host,netID,false)) + servMgr->deadHost(sh.host,ServHost::T_SERVENT); + sys->sleep(servMgr->tryoutDelay); + break; + } + } + }else{ +#if 0 + Servent *s = servMgr->servents; + while (s) + { + + if (s->type == Servent::T_OUTGOING) + s->thread.active = false; + s=s->next; + } +#endif + } + sys->sleepIdle(); + } + thread->unlock(); +#endif + return 0; +} +// ----------------------------------- +bool ServMgr::acceptGIV(ClientSocket *sock) +{ + Servent *sv = servents; + while (sv) + { + if (sv->type == Servent::T_COUT) + { + if (sv->acceptGIV(sock)) + return true; + } + sv=sv->next; + } + return false; +} + +// ----------------------------------- +int ServMgr::broadcastPushRequest(ChanHit &hit, Host &to, GnuID &chanID, Servent::TYPE type) +{ + ChanPacket pack; + MemoryStream pmem(pack.data,sizeof(pack.data)); + AtomStream atom(pmem); + +#ifndef VERSION_EX + atom.writeParent(PCP_BCST,8); +#else + atom.writeParent(PCP_BCST,10); +#endif + atom.writeChar(PCP_BCST_GROUP,PCP_BCST_GROUP_ALL); + atom.writeChar(PCP_BCST_HOPS,0); + atom.writeChar(PCP_BCST_TTL,7); + atom.writeBytes(PCP_BCST_DEST,hit.sessionID.id,16); + atom.writeBytes(PCP_BCST_FROM,servMgr->sessionID.id,16); + atom.writeInt(PCP_BCST_VERSION,PCP_CLIENT_VERSION); + atom.writeInt(PCP_BCST_VERSION_VP,PCP_CLIENT_VERSION_VP); +#ifdef VERSION_EX + atom.writeBytes(PCP_BCST_VERSION_EX_PREFIX,PCP_CLIENT_VERSION_EX_PREFIX,2); + atom.writeShort(PCP_BCST_VERSION_EX_NUMBER,PCP_CLIENT_VERSION_EX_NUMBER); +#endif + atom.writeParent(PCP_PUSH,3); + atom.writeInt(PCP_PUSH_IP,to.ip); + atom.writeShort(PCP_PUSH_PORT,to.port); + atom.writeBytes(PCP_PUSH_CHANID,chanID.id,16); + + + pack.len = pmem.pos; + pack.type = ChanPacket::T_PCP; + + + GnuID noID; + noID.clear(); + + return servMgr->broadcastPacket(pack,noID,servMgr->sessionID,hit.sessionID,type); +} + +// -------------------------------------------------- +void ServMgr::writeRootAtoms(AtomStream &atom, bool getUpdate) +{ + atom.writeParent(PCP_ROOT,5 + (getUpdate?1:0)); + atom.writeInt(PCP_ROOT_UPDINT,chanMgr->hostUpdateInterval); + atom.writeString(PCP_ROOT_URL,"download.php"); + atom.writeInt(PCP_ROOT_CHECKVER,PCP_ROOT_VERSION); + atom.writeInt(PCP_ROOT_NEXT,chanMgr->hostUpdateInterval); + atom.writeString(PCP_MESG_ASCII,rootMsg.cstr()); + if (getUpdate) + atom.writeParent(PCP_ROOT_UPDATE,0); + +} +// -------------------------------------------------- +void ServMgr::broadcastRootSettings(bool getUpdate) +{ + if (isRoot) + { + + ChanPacket pack; + MemoryStream mem(pack.data,sizeof(pack.data)); + AtomStream atom(mem); +#ifndef VERSION_EX + atom.writeParent(PCP_BCST,7); +#else + atom.writeParent(PCP_BCST,9); +#endif + atom.writeChar(PCP_BCST_GROUP,PCP_BCST_GROUP_TRACKERS); + atom.writeChar(PCP_BCST_HOPS,0); + atom.writeChar(PCP_BCST_TTL,7); + atom.writeBytes(PCP_BCST_FROM,sessionID.id,16); + atom.writeInt(PCP_BCST_VERSION,PCP_CLIENT_VERSION); + atom.writeInt(PCP_BCST_VERSION_VP,PCP_CLIENT_VERSION_VP); +#ifdef VERSION_EX + atom.writeBytes(PCP_BCST_VERSION_EX_PREFIX,PCP_CLIENT_VERSION_EX_PREFIX,2); + atom.writeShort(PCP_BCST_VERSION_EX_NUMBER,PCP_CLIENT_VERSION_EX_NUMBER); +#endif + writeRootAtoms(atom,getUpdate); + + mem.len = mem.pos; + mem.rewind(); + pack.len = mem.len; + + GnuID noID; + noID.clear(); + + broadcastPacket(pack,noID,servMgr->sessionID,noID,Servent::T_CIN); + } +} +// -------------------------------------------------- +int ServMgr::broadcastPacket(ChanPacket &pack,GnuID &chanID,GnuID &srcID, GnuID &destID, Servent::TYPE type) +{ + int cnt=0; + + Servent *sv = servents; + while (sv) + { + if (sv->sendPacket(pack,chanID,srcID,destID,type)) + cnt++; + sv=sv->next; + } + return cnt; +} + +// -------------------------------------------------- +int ServMgr::idleProc(ThreadInfo *thread) +{ + +// thread->lock(); + + unsigned int lastPasvFind=0; + unsigned int lastBroadcast=0; + + + // nothing much to do for the first couple of seconds, so just hang around. + sys->sleep(2000); + + unsigned int lastBWcheck=0; + unsigned int bytesIn=0,bytesOut=0; + + unsigned int lastBroadcastConnect = 0; + unsigned int lastRootBroadcast = 0; + + unsigned int lastForceIPCheck = 0; + + while(thread->active) + { + stats.update(); + + + + unsigned int ctime = sys->getTime(); + + + if (!servMgr->forceIP.isEmpty()) + { + if ((ctime-lastForceIPCheck) > 60) + { + if (servMgr->checkForceIP()) + { + GnuID noID; + noID.clear(); + chanMgr->broadcastTrackerUpdate(noID,true); + } + lastForceIPCheck = ctime; + } + } + + + if (chanMgr->isBroadcasting()) + { + if ((ctime-lastBroadcastConnect) > 30) + { + servMgr->connectBroadcaster(); + lastBroadcastConnect = ctime; + } + } + + if (servMgr->isRoot) + { + if ((servMgr->lastIncoming) && ((ctime-servMgr->lastIncoming) > 60*60)) + { + peercastInst->saveSettings(); + sys->exit(); + } + + if ((ctime-lastRootBroadcast) > chanMgr->hostUpdateInterval) + { + servMgr->broadcastRootSettings(true); + lastRootBroadcast = ctime; + } + } + + + // clear dead hits + chanMgr->clearDeadHits(true); + + if (servMgr->kickPushStartRelays && servMgr->kickPushInterval) //JP-EX + { + servMgr->banFirewalledHost(); + } + + if (servMgr->shutdownTimer) + { + if (--servMgr->shutdownTimer <= 0) + { + peercastInst->saveSettings(); + sys->exit(); + } + } + + // shutdown idle channels + if (chanMgr->numIdleChannels() > ChanMgr::MAX_IDLE_CHANNELS) + chanMgr->closeOldestIdle(); + + + sys->sleep(500); + } + + sys->endThread(thread); +// thread->unlock(); + return 0; +} + +// -------------------------------------------------- +int ServMgr::serverProc(ThreadInfo *thread) +{ + +// thread->lock(); + + Servent *serv = servMgr->allocServent(); + Servent *serv2 = servMgr->allocServent(); + + unsigned int lastLookupTime=0; + + + while (thread->active) + { + + if (servMgr->restartServer) + { + serv->abort(); // force close + serv2->abort(); // force close + servMgr->quit(); + + servMgr->restartServer = false; + } + + if (servMgr->autoServe) + { + serv->allow = servMgr->allowServer1; + serv2->allow = servMgr->allowServer2; + + + if ((!serv->sock) || (!serv2->sock)) + { + LOG_DEBUG("Starting servers"); +// servMgr->forceLookup = true; + + //if (servMgr->serverHost.ip != 0) + { + + if (servMgr->forceNormal) + servMgr->setFirewall(ServMgr::FW_OFF); + else + servMgr->setFirewall(ServMgr::FW_UNKNOWN); + + Host h = servMgr->serverHost; + + if (!serv->sock) + serv->initServer(h); + + h.port++; + if (!serv2->sock) + serv2->initServer(h); + + + } + } + }else{ + // stop server + serv->abort(); // force close + serv2->abort(); // force close + + // cancel incoming connectuions + Servent *s = servMgr->servents; + while (s) + { + if (s->type == Servent::T_INCOMING) + s->thread.active = false; + s=s->next; + } + + servMgr->setFirewall(ServMgr::FW_ON); + } + + sys->sleepIdle(); + + } + + sys->endThread(thread); +// thread->unlock(); + return 0; +} + +// ----------------------------------- +void ServMgr::setMaxRelays(int max) +{ + if (max < MIN_RELAYS) + max = MIN_RELAYS; + maxRelays = max; +} + +// ----------------------------------- +XML::Node *ServMgr::createServentXML() +{ + + return new XML::Node("servent agent=\"%s\" ",PCX_AGENT); +} + +// -------------------------------------------------- +const char *ServHost::getTypeStr(TYPE t) +{ + switch(t) + { + case T_NONE: return "NONE"; + case T_STREAM: return "STREAM"; + case T_CHANNEL: return "CHANNEL"; + case T_SERVENT: return "SERVENT"; + case T_TRACKER: return "TRACKER"; + } + return "UNKNOWN"; +} +// -------------------------------------------------- +ServHost::TYPE ServHost::getTypeFromStr(const char *s) +{ + if (stricmp(s,"NONE")==0) + return T_NONE; + else if (stricmp(s,"SERVENT")==0) + return T_SERVENT; + else if (stricmp(s,"STREAM")==0) + return T_STREAM; + else if (stricmp(s,"CHANNEL")==0) + return T_CHANNEL; + else if (stricmp(s,"TRACKER")==0) + return T_TRACKER; + + return T_NONE; +} + + +// -------------------------------------------------- +bool ServFilter::writeVariable(Stream &out, const String &var) +{ + char buf[1024]; + + if (var == "network") + strcpy(buf,(flags & F_NETWORK)?"1":"0"); + else if (var == "private") + strcpy(buf,(flags & F_PRIVATE)?"1":"0"); + else if (var == "direct") + strcpy(buf,(flags & F_DIRECT)?"1":"0"); + else if (var == "banned") + strcpy(buf,(flags & F_BAN)?"1":"0"); + else if (var == "ip") + host.IPtoStr(buf); + else + return false; + + + out.writeString(buf); + return true; +} +// -------------------------------------------------- +bool BCID::writeVariable(Stream &out, const String &var) +{ + char buf[1024]; + + if (var == "id") + id.toStr(buf); + else if (var == "name") + strcpy(buf,name.cstr()); + else if (var == "email") + strcpy(buf,email.cstr()); + else if (var == "url") + strcpy(buf,url.cstr()); + else if (var == "valid") + strcpy(buf,valid?"Yes":"No"); + else + return false; + + + out.writeString(buf); + return true; +} + + +// -------------------------------------------------- +bool ServMgr::writeVariable(Stream &out, const String &var) +{ + char buf[1024]; + String str; + + if (var == "version") +#ifdef VERSION_EX + strcpy(buf,PCX_VERSTRING_EX); +#else + strcpy(buf,PCX_VERSTRING); +#endif + else if (var == "uptime") + { + str.setFromStopwatch(getUptime()); + str.convertTo(String::T_HTML); + strcpy(buf,str.cstr()); + }else if (var == "numRelays") + sprintf(buf,"%d",numStreams(Servent::T_RELAY,true)); + else if (var == "numDirect") + sprintf(buf,"%d",numStreams(Servent::T_DIRECT,true)); + else if (var == "totalConnected") + sprintf(buf,"%d",totalConnected()); + else if (var == "numServHosts") + sprintf(buf,"%d",numHosts(ServHost::T_SERVENT)); + else if (var == "numServents") + sprintf(buf,"%d",numServents()); + else if (var == "serverPort") + sprintf(buf,"%d",serverHost.port); + else if (var == "serverIP") + serverHost.IPtoStr(buf); + else if (var == "ypAddress") + strcpy(buf,rootHost.cstr()); + else if (var == "password") + strcpy(buf,password); + else if (var == "isFirewalled") + sprintf(buf,"%d",getFirewall()==FW_ON?1:0); + else if (var == "firewallKnown") + sprintf(buf,"%d",getFirewall()==FW_UNKNOWN?0:1); + else if (var == "rootMsg") + strcpy(buf,rootMsg); + else if (var == "isRoot") + sprintf(buf,"%d",isRoot?1:0); + else if (var == "isPrivate") + sprintf(buf,"%d",(PCP_BROADCAST_FLAGS&1)?1:0); + else if (var == "forceYP") + sprintf(buf,"%d",PCP_FORCE_YP?1:0); + else if (var == "refreshHTML") + sprintf(buf,"%d",refreshHTML?refreshHTML:0x0fffffff); + else if (var == "maxRelays") + sprintf(buf,"%d",maxRelays); + else if (var == "maxDirect") + sprintf(buf,"%d",maxDirect); + else if (var == "maxBitrateOut") + sprintf(buf,"%d",maxBitrateOut); + else if (var == "maxControlsIn") + sprintf(buf,"%d",maxControl); + else if (var == "numFilters") + sprintf(buf,"%d",numFilters+1); + else if (var == "maxPGNUIn") + sprintf(buf,"%d",maxGnuIncoming); + else if (var == "minPGNUIn") + sprintf(buf,"%d",minGnuIncoming); + else if (var == "numActive1") + sprintf(buf,"%d",numActiveOnPort(serverHost.port)); + else if (var == "numActive2") + sprintf(buf,"%d",numActiveOnPort(serverHost.port+1)); + else if (var == "numPGNU") + sprintf(buf,"%d",numConnected(Servent::T_PGNU)); + else if (var == "numCIN") + sprintf(buf,"%d",numConnected(Servent::T_CIN)); + else if (var == "numCOUT") + sprintf(buf,"%d",numConnected(Servent::T_COUT)); + else if (var == "numIncoming") + sprintf(buf,"%d",numActive(Servent::T_INCOMING)); + else if (var == "numValidBCID") + { + int cnt = 0; + BCID *bcid = validBCID; + while (bcid) + { + cnt++; + bcid=bcid->next; + } + sprintf(buf,"%d",cnt); + } + + else if (var == "disabled") + sprintf(buf,"%d",isDisabled); + + // JP-EX + else if (var.startsWith("autoRelayKeep")) { + if (var == "autoRelayKeep.0") + strcpy(buf, (autoRelayKeep == 0) ? "1":"0"); + else if (var == "autoRelayKeep.1") + strcpy(buf, (autoRelayKeep == 1) ? "1":"0"); + else if (var == "autoRelayKeep.2") + strcpy(buf, (autoRelayKeep == 2) ? "1":"0"); + } else if (var == "autoMaxRelaySetting") + sprintf(buf,"%d",autoMaxRelaySetting); + else if (var == "autoBumpSkipCount") + sprintf(buf,"%d",autoBumpSkipCount); + else if (var == "kickPushStartRelays") + sprintf(buf,"%d",kickPushStartRelays); + else if (var == "kickPushInterval") + sprintf(buf,"%d",kickPushInterval); + else if (var == "allowConnectPCST") + strcpy(buf, (allowConnectPCST == 1) ? "1":"0"); + else if (var == "enableGetName") + strcpy(buf, (enableGetName == 1)? "1":"0"); + + // VP-EX + else if (var == "ypAddress2") + strcpy(buf,rootHost2.cstr()); + else if (var.startsWith("autoPort0Kick")) { + if (var == "autoPort0Kick.0") + strcpy(buf, (autoPort0Kick == 0) ? "1":"0"); + else if (var == "autoPort0Kick.1") + strcpy(buf, (autoPort0Kick == 1) ? "1":"0"); + } + else if (var.startsWith("allowOnlyVP")) { + if (var == "allowOnlyVP.0") + strcpy(buf, (allowOnlyVP == 0) ? "1":"0"); + else if (var == "allowOnlyVP.1") + strcpy(buf, (allowOnlyVP == 1) ? "1":"0"); + } + else if (var == "kickKeepTime") + sprintf(buf, "%d",kickKeepTime); + + else if (var == "serverPort1") + sprintf(buf,"%d",serverHost.port); + else if (var == "serverLocalIP") + { + Host lh(ClientSocket::getIP(NULL),0); + char ipStr[64]; + lh.IPtoStr(ipStr); + strcpy(buf,ipStr); + }else if (var == "upgradeURL") + strcpy(buf,servMgr->downloadURL); + else if (var == "serverPort2") + sprintf(buf,"%d",serverHost.port+1); + else if (var.startsWith("allow.")) + { + if (var == "allow.HTML1") + strcpy(buf,(allowServer1&Servent::ALLOW_HTML)?"1":"0"); + else if (var == "allow.HTML2") + strcpy(buf,(allowServer2&Servent::ALLOW_HTML)?"1":"0"); + else if (var == "allow.broadcasting1") + strcpy(buf,(allowServer1&Servent::ALLOW_BROADCAST)?"1":"0"); + else if (var == "allow.broadcasting2") + strcpy(buf,(allowServer2&Servent::ALLOW_BROADCAST)?"1":"0"); + else if (var == "allow.network1") + strcpy(buf,(allowServer1&Servent::ALLOW_NETWORK)?"1":"0"); + else if (var == "allow.direct1") + strcpy(buf,(allowServer1&Servent::ALLOW_DIRECT)?"1":"0"); + }else if (var.startsWith("auth.")) + { + if (var == "auth.useCookies") + strcpy(buf,(authType==AUTH_COOKIE)?"1":"0"); + else if (var == "auth.useHTTP") + strcpy(buf,(authType==AUTH_HTTPBASIC)?"1":"0"); + else if (var == "auth.useSessionCookies") + strcpy(buf,(cookieList.neverExpire==false)?"1":"0"); + + }else if (var.startsWith("log.")) + { + if (var == "log.debug") + strcpy(buf,(showLog&(1<kickPushStartRelays) + if (servMgr->numStreams(Servent::T_RELAY,false)>=(servMgr->kickPushStartRelays-1)) + return true; + + return false; +} +// -------------------------------------------------- +//JP-EX +void ServMgr::banFirewalledHost() +{ + unsigned int kickpushtime = sys->getTime(); + if ((kickpushtime-servMgr->kickPushTime) > servMgr->kickPushInterval) + { + servMgr->kickPushTime = kickpushtime; + Servent *s = servMgr->servents; + LOG_DEBUG("Servent scan start."); + while (s) + { + if (s->type != Servent::T_NONE) + { + Host h = s->getHost(); + int ip = h.ip; + int port = h.port; + Host h2(ip,port); + unsigned int tnum = 0; + + if (s->lastConnect) + tnum = sys->getTime() - s->lastConnect; + if ((s->type==Servent::T_RELAY) && (s->status==Servent::S_CONNECTED) && (tnum>servMgr->kickPushInterval)) + { +/* ChanHitList *hits[ChanMgr::MAX_HITLISTS]; + int numHits=0; + for(int i=0; ihitlists[i]; + if (chl->isUsed()) + hits[numHits++] = chl; + } + + bool isfw = false; + int numRelay = 0; + if (numHits) + { + for(int k=0; kisUsed()) + { + for (int j=0; jhits[j]; + if (hit->host.isValid() && (h2.ip == hit->host.ip)) + { + if (hit->firewalled) + isfw = true; + numRelay = hit->numRelays; + } + } + } + } + } + if ((isfw==true) && (numRelay==0)) + { + char hostName[256]; + h2.toStr(hostName); + if (servMgr->isCheckPushStream()) + { + s->thread.active = false; + LOG_ERROR("Stop firewalled Servent : %s",hostName); + } + }*/ + + chanMgr->hitlistlock.on(); + ChanHitList *chl = chanMgr->findHitListByID(s->chanID); + if (chl){ + ChanHit *hit = chl->hit; + while(hit){ + if ((hit->numHops == 1) && hit->host.isValid() && (h2.ip == hit->host.ip) && hit->firewalled /*&& !hit->numRelays*/) + { + char hostName[256]; + h2.toStr(hostName); + if (servMgr->isCheckPushStream()) + { + s->thread.active = false; + LOG_ERROR("Stop firewalled Servent : %s",hostName); + } + } + hit = hit->next; + } + + } + chanMgr->hitlistlock.off(); + + + } + } + s=s->next; + } + LOG_DEBUG("Servent scan finished."); + } +} + diff --git a/PeerCast.root/PeerCast/core/common/servmgr.h b/PeerCast.root/PeerCast/core/common/servmgr.h new file mode 100644 index 0000000..492520e --- /dev/null +++ b/PeerCast.root/PeerCast/core/common/servmgr.h @@ -0,0 +1,428 @@ +// ------------------------------------------------ +// File : servmgr.h +// Date: 4-apr-2002 +// Author: giles +// Desc: +// +// (c) 2002 peercast.org +// ------------------------------------------------ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// ------------------------------------------------ + +#ifndef _SERVMGR_H +#define _SERVMGR_H + +#include "servent.h" + +// ---------------------------------- + +const int MIN_YP_RETRY = 20; +const int MIN_TRACKER_RETRY = 10; +const int MIN_RELAY_RETRY = 5; + +// ---------------------------------- +class BCID +{ +public: + BCID() + :next(0),valid(true) + {} + + bool writeVariable(Stream &, const String &); + + GnuID id; + String name,email,url; + bool valid; + BCID *next; +}; + + +// ---------------------------------- +class ServHost +{ +public: + enum TYPE + { + T_NONE, + T_STREAM, + T_CHANNEL, + T_SERVENT, + T_TRACKER + }; + + ServHost() {init();} + void init() + { + host.init(); + time = 0; + type = T_NONE; + } + void init(Host &h, TYPE tp, unsigned int tim) + { + init(); + host = h; + type = tp; + if (tim) + time = tim; + else + time = sys->getTime(); + } + + static const char *getTypeStr(TYPE); + static TYPE getTypeFromStr(const char *); + + TYPE type; + Host host; + unsigned int time; +}; +// ---------------------------------- +class ServFilter +{ +public: + enum + { + F_PRIVATE = 0x01, + F_BAN = 0x02, + F_NETWORK = 0x04, + F_DIRECT = 0x08 + }; + + ServFilter() {init();} + void init() + { + flags = 0; + host.init(); + } + + bool writeVariable(Stream &, const String &); + + Host host; + unsigned int flags; +}; + +// ---------------------------------- +// ServMgr keeps track of Servents +class ServMgr +{ + + + +public: + + enum NOTIFY_TYPE + { + NT_UPGRADE = 0x0001, + NT_PEERCAST = 0x0002, + NT_BROADCASTERS = 0x0004, + NT_TRACKINFO = 0x0008 + }; + + enum FW_STATE + { + FW_OFF, + FW_ON, + FW_UNKNOWN + }; + enum { + + MAX_HOSTCACHE = 100, // max. amount of hosts in cache + MIN_HOSTS = 3, // min. amount of hosts that should be kept in cache + + MAX_OUTGOING = 3, // max. number of outgoing servents to use + MAX_INCOMING = 6, // max. number of public incoming servents to use + MAX_TRYOUT = 10, // max. number of outgoing servents to try connect + MIN_CONNECTED = 3, // min. amount of connected hosts that should be kept + + MIN_RELAYS = 1, + + MAX_FILTERS = 50, + + MAX_VERSIONS = 16, + + MAX_PREVIEWTIME = 300, // max. seconds preview per channel available (direct connections) + MAX_PREVIEWWAIT = 300, // max. seconds wait between previews + + }; + + enum AUTH_TYPE + { + AUTH_COOKIE, + AUTH_HTTPBASIC + }; + + + + ServMgr(); + + bool start(); + + Servent *findServent(unsigned int,unsigned short,GnuID &); + Servent *findServent(Servent::TYPE); + Servent *findServent(Servent::TYPE,Host &,GnuID &); + Servent *findOldestServent(Servent::TYPE,bool); + Servent *findServentByIndex(int); + Servent *findServentByServentID(int); + + bool writeVariable(Stream &, const String &); + Servent *allocServent(); + unsigned int numUsed(int); + unsigned int numStreams(GnuID &, Servent::TYPE,bool); + unsigned int numStreams(Servent::TYPE,bool); + unsigned int numConnected(int,bool,unsigned int); + unsigned int numConnected(int t,int tim = 0) + { + return numConnected(t,false,tim)+numConnected(t,true,tim); + } + unsigned int numConnected(); + unsigned int numServents(); + + unsigned int totalConnected() + { + //return numConnected(Servent::T_OUTGOING) + numConnected(Servent::T_INCOMING); + return numConnected(); + } + unsigned int numOutgoing(); + bool isFiltered(int,Host &h); + bool addOutgoing(Host,GnuID &,bool); + Servent *findConnection(Servent::TYPE,GnuID &); + + + static THREAD_PROC serverProc(ThreadInfo *); + static THREAD_PROC clientProc(ThreadInfo *); + static THREAD_PROC trackerProc(ThreadInfo *); + static THREAD_PROC idleProc(ThreadInfo *); + + int broadcast(GnuPacket &,Servent * = NULL); + int route(GnuPacket &, GnuID &, Servent * = NULL); + + XML::Node *createServentXML(); + + void connectBroadcaster(); + void procConnectArgs(char *,ChanInfo &); + + void quit(); + void closeConnections(Servent::TYPE); + + void checkFirewall(); + + // host cache + void addHost(Host &,ServHost::TYPE,unsigned int); + int getNewestServents(Host *,int, Host &); + ServHost getOutgoingServent(GnuID &); + void deadHost(Host &,ServHost::TYPE); + unsigned int numHosts(ServHost::TYPE); + void clearHostCache(ServHost::TYPE); + bool seenHost(Host &,ServHost::TYPE,unsigned int); + + void setMaxRelays(int); + void setFirewall(FW_STATE); + bool checkForceIP(); + FW_STATE getFirewall() {return firewalled;} + void saveSettings(const char *); + void loadSettings(const char *); + void setPassiveSearch(unsigned int); + int findChannel(ChanInfo &); + bool getChannel(char *,ChanInfo &,bool); + void setFilterDefaults(); + + bool acceptGIV(ClientSocket *); + void addVersion(unsigned int); + + void broadcastRootSettings(bool); + int broadcastPushRequest(ChanHit &, Host &, GnuID &, Servent::TYPE); + void writeRootAtoms(AtomStream &,bool); + + int broadcastPacket(ChanPacket &,GnuID &,GnuID &,GnuID &,Servent::TYPE type); + + void addValidBCID(BCID *); + void removeValidBCID(GnuID &); + BCID *findValidBCID(GnuID &); + BCID *findValidBCID(int); + + unsigned int getUptime() + { + return sys->getTime()-startTime; + } + + bool seenPacket(GnuPacket &); + + + bool needHosts() + { + return false; + //return numHosts(ServHost::T_SERVENT) < maxTryout; + } + + unsigned int numActiveOnPort(int); + unsigned int numActive(Servent::TYPE); + + bool needConnections() + { + return numConnected(Servent::T_PGNU,60) < minGnuIncoming; + } + bool tryFull() + { + return false; + //return maxTryout ? numUsed(Servent::T_OUTGOING) > maxTryout: false; + } + + bool pubInOver() + { + return numConnected(Servent::T_PGNU) > maxGnuIncoming; +// return maxIncoming ? numConnected(Servent::T_INCOMING,false) > maxIncoming : false; + } + bool pubInFull() + { + return numConnected(Servent::T_PGNU) >= maxGnuIncoming; +// return maxIncoming ? numConnected(Servent::T_INCOMING,false) >= maxIncoming : false; + } + + bool outUsedFull() + { + return false; +// return maxOutgoing ? numUsed(Servent::T_OUTGOING) >= maxOutgoing: false; + } + bool outOver() + { + return false; +// return maxOutgoing ? numConnected(Servent::T_OUTGOING) > maxOutgoing : false; + } + + bool controlInFull() + { + return numConnected(Servent::T_CIN)>=maxControl; + } + + bool outFull() + { + return false; +// return maxOutgoing ? numConnected(Servent::T_OUTGOING) >= maxOutgoing : false; + } + + bool relaysFull() + { + return numStreams(Servent::T_RELAY,false) >= maxRelays; + } + bool directFull() + { + return numStreams(Servent::T_DIRECT,false) >= maxDirect; + } + + bool bitrateFull(unsigned int br) + { + return maxBitrateOut ? (BYTES_TO_KBPS(totalOutput(false))+br) > maxBitrateOut : false; + } + + unsigned int totalOutput(bool); + unsigned int totalInput(bool); + + static ThreadInfo serverThread,idleThread; + + + Servent *servents; + WLock lock; + + ServHost hostCache[MAX_HOSTCACHE]; + + char password[64]; + + bool allowGnutella; + + unsigned int maxBitrateOut,maxControl,maxRelays,maxDirect; + unsigned int minGnuIncoming,maxGnuIncoming; + unsigned int maxServIn; + + bool isDisabled; + bool isRoot; + int totalStreams; + + Host serverHost; + String rootHost; + String rootHost2; + + char downloadURL[128]; + String rootMsg; + String forceIP; + char connectHost[128]; + GnuID networkID; + unsigned int firewallTimeout; + int showLog; + int shutdownTimer; + bool pauseLog; + bool forceNormal; + bool useFlowControl; + unsigned int lastIncoming; + + bool restartServer; + bool allowDirect; + bool autoConnect,autoServe,forceLookup; + int queryTTL; + + unsigned int allowServer1,allowServer2; + unsigned int startTime; + unsigned int tryoutDelay; + unsigned int refreshHTML; + unsigned int relayBroadcast; + + unsigned int notifyMask; + + BCID *validBCID; + GnuID sessionID; + + ServFilter filters[MAX_FILTERS]; + int numFilters; + + + CookieList cookieList; + AUTH_TYPE authType; + + char htmlPath[128]; + unsigned int clientVersions[MAX_VERSIONS],clientCounts[MAX_VERSIONS]; + int numVersions; + + int serventNum; + String chanLog; + + char modulePath[256]; //JP-EX + int enableGetName; //JP-EX + int allowConnectPCST; //JP-EX + int autoRelayKeep; //JP-EX + unsigned int autoMaxRelaySetting; //JP-EX + unsigned int autoBumpSkipCount;//JP-EX + unsigned int kickPushStartRelays; //JP-EX + unsigned int kickPushInterval; //JP-EX + unsigned int kickPushTime; + bool isCheckPushStream(); //JP-EX + void banFirewalledHost(); //JP-EX + + bool getModulePath; //JP-EX + bool clearPLS; //JP-EX + bool writeLogFile; //JP-EX + + bool autoPort0Kick; + bool allowOnlyVP; + unsigned int kickKeepTime; + bool vpDebug; + bool saveIniChannel; + bool saveGuiPos; + bool keepDownstreams; + + int maxRelaysIndexTxt; // for PCRaw (relay) + +private: + FW_STATE firewalled; +}; + +// ---------------------------------- +extern ServMgr *servMgr; + + +#endif diff --git a/PeerCast.root/PeerCast/core/common/socket.cpp b/PeerCast.root/PeerCast/core/common/socket.cpp new file mode 100644 index 0000000..80ac2dd --- /dev/null +++ b/PeerCast.root/PeerCast/core/common/socket.cpp @@ -0,0 +1,32 @@ +// ------------------------------------------------ +// File : socket.cpp +// Date: 4-apr-2002 +// Author: giles +// Desc: +// ClientSocket is a generic socket interface, Non OS/HW dependant. +// +// (c) 2002 peercast.org +// ------------------------------------------------ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// ------------------------------------------------ + + +#include +#include +#include "socket.h" +#include "sys.h" +#ifdef _DEBUG +#include "chkMemoryLeak.h" +#define DEBUG_NEW new(__FILE__, __LINE__) +#define new DEBUG_NEW +#endif + + diff --git a/PeerCast.root/PeerCast/core/common/socket.h b/PeerCast.root/PeerCast/core/common/socket.h new file mode 100644 index 0000000..0e47e07 --- /dev/null +++ b/PeerCast.root/PeerCast/core/common/socket.h @@ -0,0 +1,185 @@ +// ------------------------------------------------ +// File : socket.h +// Date: 4-apr-2002 +// Author: giles +// Desc: +// +// (c) 2002 peercast.org +// ------------------------------------------------ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// ------------------------------------------------ + +#ifndef _SOCKET_H +#define _SOCKET_H + + +#include "common.h" +#include "stream.h" + +//#define DISABLE_NAGLE 1 + +class SocketBuffer { + +public: + SocketBuffer(const void *p, int l){ + buf = ::new char[l]; + len = l; + pos = 0; + next = NULL; + ctime = sys->getTime(); + memcpy((void*)buf, p, l); + } + + ~SocketBuffer(){ + if (buf){ + ::delete [] buf; + } + } + char *buf; + int len; + int pos; + unsigned int ctime; + SocketBuffer *next; +}; + +class SocketBufferList { + +public: + SocketBufferList(){ + top = NULL; + last = NULL; + skipCount = 0; + lastSkipTime = 0; + } + + bool isNull(){ return (top == NULL); } + void add(const void *p, int l){ + SocketBuffer *tmp = new SocketBuffer(p,l); + + if (!last){ + top = tmp; + last = tmp; + } else { + last->next = tmp; + last = tmp; + } + +// LOG_DEBUG("tmp = %d, top = %d, last = %d", tmp, top, last); + } + + SocketBuffer *getTop(){ + unsigned int ctime = sys->getTime(); + + while(top){ + if (top && (top->ctime + 10 >= ctime)){ + break; + } else { +// LOG_DEBUG("over 10sec(data skip)"); + skipCount++; + lastSkipTime = sys->getTime(); + deleteTop(); + } + } + return top; + } + + void deleteTop(){ +// LOG_DEBUG("oldtop = %d", top); + SocketBuffer *tmp = top; + top = tmp->next; + delete tmp; + if (!top){ + last = NULL; + } + +// LOG_DEBUG("newtop = %d",top); + } + + void clear(){ + while(top){ + SocketBuffer *tmp = top; + top = tmp->next; + delete tmp; + } + top = NULL; + last = NULL; + } + + SocketBuffer *top; + SocketBuffer *last; + unsigned int skipCount; + unsigned int lastSkipTime; + +}; + +// -------------------------------------------------- +class ClientSocket : public Stream +{ +public: + + ClientSocket() + { + readTimeout = 30000; + writeTimeout = 30000; +#ifdef WIN32 + skipCount = 0; + lastSkipTime = 0; +#endif + } + + ~ClientSocket(){ +#ifdef WIN32 + bufList.clear(); +#endif + } + + // required interface + virtual void open(Host &) = 0; + virtual void bind(Host &) = 0; + virtual void connect() = 0; + virtual bool active() = 0; + virtual ClientSocket *accept() = 0; + virtual Host getLocalHost() = 0; + + virtual void setReadTimeout(unsigned int t) + { + readTimeout = t; + } + virtual void setWriteTimeout(unsigned int t) + { + writeTimeout = t; + } + virtual void setBlocking(bool) {} + + + static unsigned int getIP(char *); + static bool getHostname(char *,unsigned int); + + virtual bool eof() + { + return active()==false; + } + + Host host; + +#ifdef WIN32 + SocketBufferList bufList; + virtual void bufferingWrite(const void *, int) = 0; + unsigned int skipCount; + unsigned int lastSkipTime; +#endif + + unsigned int readTimeout,writeTimeout; + +}; + + +#endif diff --git a/PeerCast.root/PeerCast/core/common/stats.cpp b/PeerCast.root/PeerCast/core/common/stats.cpp new file mode 100644 index 0000000..46e0a44 --- /dev/null +++ b/PeerCast.root/PeerCast/core/common/stats.cpp @@ -0,0 +1,102 @@ +// ------------------------------------------------ +// File : stats.cpp +// Date: 4-apr-2002 +// Author: giles +// Desc: +// Statistic logging +// +// (c) 2002 peercast.org +// ------------------------------------------------ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// ------------------------------------------------ + + +#include "stats.h" +#include "common.h" +#include "sys.h" +#include "stream.h" +#ifdef _DEBUG +#include "chkMemoryLeak.h" +#define DEBUG_NEW new(__FILE__, __LINE__) +#define new DEBUG_NEW +#endif + +Stats stats; +// ------------------------------------ +void Stats::clear() +{ + for(int i=0; igetTime(); + + unsigned int diff = ctime - lastUpdate; + if (diff >= /* 5 */ 1) + { + + for(int i=0; i= 4) + { + out += String::base64WordToChars(out,in); + in += 4; + rl -= 4; + } + *out = 0; + len = out-buf; +} +// ------------------------------------- +void FileStream::openReadOnly(const char *fn) +{ + file = fopen(fn,"rb"); + + if (!file) + throw StreamException("Unable to open file"); +} +// ------------------------------------- +void FileStream::openWriteReplace(const char *fn) +{ + file = fopen(fn,"wb"); + + if (!file) + throw StreamException("Unable to open file"); +} +// ------------------------------------- +void FileStream::openWriteAppend(const char *fn) +{ + file = fopen(fn,"ab"); + + if (!file) + throw StreamException("Unable to open file"); +} + +// ------------------------------------- +void FileStream::close() +{ + if (file) + { + fclose(file); + file = NULL; + } +} +// ------------------------------------- +void FileStream::rewind() +{ + if (file) + fseek(file,0,SEEK_SET); +} +// ------------------------------------- +int FileStream::length() +{ + int len = 0; + if (file) + { + int old = ftell(file); + fseek(file,0,SEEK_END); + len = ftell(file); + fseek(file,old,SEEK_SET); + + } + return len; +} + +// ------------------------------------- +bool FileStream::eof() +{ + if (file) + return (feof(file)!=0); + else + return true; +} +// ------------------------------------- +int FileStream::read(void *ptr, int len) +{ + if (!file) + return 0; + if (feof(file)) + throw StreamException("End of file"); + + int r = (int)fread(ptr,1,len,file); + + updateTotals(r, 0); + return r; +} + +// ------------------------------------- +void FileStream::write(const void *ptr, int len) +{ + if (!file) + return; + fwrite(ptr,1,len,file); + updateTotals(0, len); + +} +// ------------------------------------- +void FileStream::flush() +{ + if (!file) + return; + fflush(file); +} +// ------------------------------------- +int FileStream::pos() +{ + if (!file) + return 0; + return ftell(file); +} + +// ------------------------------------- +void FileStream::seekTo(int pos) +{ + if (!file) + return; + fseek(file,pos,SEEK_SET); +} + +// ------------------------------------- +void Stream::writeTo(Stream &out, int len) +{ + char tmp[4096]; + while (len) + { + int rlen = sizeof(tmp); + if (rlen > len) + rlen = len; + + read(tmp,rlen); + out.write(tmp,rlen); + + len-=rlen; + } +} +// ------------------------------------- +int Stream::writeUTF8(unsigned int code) +{ + if (code < 0x80) + { + writeChar(code); + return 1; + }else + if (code < 0x0800) + { + writeChar(code>>6 | 0xC0); + writeChar(code & 0x3F | 0x80); + return 2; + }else if (code < 0x10000) + { + writeChar(code>>12 | 0xE0); + writeChar(code>>6 & 0x3F | 0x80); + writeChar(code & 0x3F | 0x80); + return 3; + }else + { + writeChar(code>>18 | 0xF0); + writeChar(code>>12 & 0x3F | 0x80); + writeChar(code>>6 & 0x3F | 0x80); + writeChar(code & 0x3F | 0x80); + return 4; + } + +} + +// ------------------------------------- +void Stream::skip(int len) +{ + char tmp[4096]; + while (len) + { + int rlen = sizeof(tmp); + if (rlen > len) + rlen = len; + read(tmp,rlen); + len-=rlen; + } + +} + + +// ------------------------------------- +void Stream::updateTotals(unsigned int in, unsigned int out) +{ + totalBytesIn += in; + totalBytesOut += out; + + unsigned int tdiff = sys->getTime()-lastUpdate; + if (tdiff >= 5) + { + bytesInPerSec = (totalBytesIn-lastBytesIn)/tdiff; + bytesOutPerSec = (totalBytesOut-lastBytesOut)/tdiff; + lastBytesIn = totalBytesIn; + lastBytesOut = totalBytesOut; + lastUpdate = sys->getTime(); + } +} +// ------------------------------------- +int Stream::readLine(char *in, int max) +{ + int i=0; + max -= 2; + + while(max--) + { + char c; + read(&c,1); + if (c == '\n') + break; + if (c == '\r') + continue; + in[i++] = c; + } + in[i] = 0; + return i; +} +// ------------------------------------- +void Stream::write(const char *fmt,va_list ap) +{ + char tmp[4096]; + vsprintf(tmp,fmt,ap); + write(tmp,strlen(tmp)); +} +// ------------------------------------- +void Stream::writeStringF(const char *fmt,...) +{ + va_list ap; + va_start(ap, fmt); + write(fmt,ap); + va_end(ap); +} +// ------------------------------------- +void Stream::writeString(const char *str) +{ + write(str,strlen(str)); +} +// ------------------------------------- +void Stream::writeLineF(const char *fmt,...) +{ + va_list ap; + va_start(ap, fmt); + + write(fmt,ap); + + if (writeCRLF) + write("\r\n",2); + else + write("\n",1); + + va_end(ap); +} + +// ------------------------------------- +void Stream::writeLine(const char *str) +{ + writeString(str); + + if (writeCRLF) + write("\r\n",2); + else + write("\n",1); +} + +// ------------------------------------- +int Stream::readWord(char *in, int max) +{ + int i=0; + while (!eof()) + { + char c = readChar(); + + if ((c == ' ') || (c == '\t') || (c == '\r') || (c == '\n')) + { + if (i) + break; // stop reading + else + continue; // skip whitespace + } + + if (i >= (max-1)) + break; + + in[i++] = c; + } + + in[i]=0; + return i; +} + + +// -------------------------------------------------- +int Stream::readBase64(char *p, int max) +{ + char vals[4]; + + int cnt=0; + while (cnt < (max-4)) + { + read(vals,4); + int rl = String::base64WordToChars(p,vals); + if (!rl) + break; + + p+=rl; + cnt+=rl; + } + *p = 0; + return cnt; +} + + +// ------------------------------------- +int Stream::readBits(int cnt) +{ + int v = 0; + + while (cnt) + { + if (!bitsPos) + bitsBuffer = readChar(); + + cnt--; + + v |= (bitsBuffer&(1<<(7-bitsPos)))?(1< +#include +#include +#include "common.h" +#include "sys.h" +#include "id.h" + +// ------------------------------------- +class Stream +{ +public: + Stream() + :writeCRLF(true) + ,totalBytesIn(0) + ,totalBytesOut(0) + ,lastBytesIn(0) + ,lastBytesOut(0) + ,bytesInPerSec(0) + ,bytesOutPerSec(0) + ,lastUpdate(0) + ,bitsBuffer(0) + ,bitsPos(0) + { + } + virtual ~Stream() {} + + virtual int readUpto(void *,int) {return 0;} + virtual int read(void *,int)=0; + virtual void write(const void *,int) = 0; + virtual bool eof() + { + throw StreamException("Stream can`t eof"); + return false; + } + + virtual void rewind() + { + throw StreamException("Stream can`t rewind"); + } + + virtual void seekTo(int) + { + throw StreamException("Stream can`t seek"); + } + + void writeTo(Stream &out, int len); + virtual void skip(int i); + + virtual void close() + { + } + + virtual void setReadTimeout(unsigned int ) + { + } + virtual void setWriteTimeout(unsigned int ) + { + } + virtual void setPollRead(bool) + { + } + + virtual int getPosition() {return 0;} + + + // binary + char readChar() + { + char v; + read(&v,1); + return v; + } + short readShort() + { + short v; + read(&v,2); + CHECK_ENDIAN2(v); + return v; + } + long readLong() + { + long v; + read(&v,4); + CHECK_ENDIAN4(v); + return v; + } + int readInt() + { + return readLong(); + } + ID4 readID4() + { + ID4 id; + read(id.getData(),4); + return id; + } + int readInt24() + { + int v=0; + read(&v,3); + CHECK_ENDIAN3(v); + } + + + + long readTag() + { + long v = readLong(); + return SWAP4(v); + } + + int readString(char *s, int max) + { + int cnt=0; + while (max) + { + char c = readChar(); + *s++ = c; + cnt++; + max--; + if (!c) + break; + } + return cnt; + } + + virtual bool readReady() {return true;} + virtual int numPending() {return 0;} + + + void writeID4(ID4 id) + { + write(id.getData(),4); + } + + void writeChar(char v) + { + write(&v,1); + } + void writeShort(short v) + { + CHECK_ENDIAN2(v); + write(&v,2); + } + void writeLong(long v) + { + CHECK_ENDIAN4(v); + write(&v,4); + } + void writeInt(int v) {writeLong(v);} + + void writeTag(long v) + { + //CHECK_ENDIAN4(v); + writeLong(SWAP4(v)); + } + + void writeTag(char id[4]) + { + write(id,4); + } + + int writeUTF8(unsigned int); + + // text + int readLine(char *in, int max); + + int readWord(char *, int); + int readBase64(char *, int); + + void write(const char *,va_list); + void writeLine(const char *); + void writeLineF(const char *,...); + void writeString(const char *); + void writeStringF(const char *,...); + + bool writeCRLF; + + int readBits(int); + + void updateTotals(unsigned int,unsigned int); + + + unsigned char bitsBuffer; + unsigned int bitsPos; + + unsigned int totalBytesIn,totalBytesOut; + unsigned int lastBytesIn,lastBytesOut; + unsigned int bytesInPerSec,bytesOutPerSec; + unsigned int lastUpdate; + +}; + + +// ------------------------------------- +class FileStream : public Stream +{ +public: + FileStream() {file=NULL;} + + void openReadOnly(const char *); + void openWriteReplace(const char *); + void openWriteAppend(const char *); + bool isOpen(){return file!=NULL;} + int length(); + int pos(); + + virtual void seekTo(int); + virtual int getPosition() {return pos();} + virtual void flush(); + virtual int read(void *,int); + virtual void write(const void *,int); + virtual bool eof(); + virtual void rewind(); + virtual void close(); + + FILE *file; +}; +// ------------------------------------- +class MemoryStream : public Stream +{ +public: + MemoryStream() + :buf(NULL) + ,len(0) + ,pos(0) + ,own(false) + { + } + + MemoryStream(void *p, int l) + :buf((char *)p) + ,len(l) + ,pos(0) + ,own(false) + { + } + + MemoryStream(int l) + :buf(new char[l]) + ,len(l) + ,pos(0) + ,own(true) + { + } + + ~MemoryStream() {free2();} + + void readFromFile(FileStream &file) + { + len = file.length(); + buf = new char[len]; + own = true; + pos = 0; + file.read(buf,len); + } + + void free2() + { + if (own && buf) + { + delete buf; + buf = NULL; + own = false; + } + + } + + virtual int read(void *p,int l) + { + if (pos+l <= len) + { + memcpy(p,&buf[pos],l); + pos += l; + return l; + }else + { + memset(p,0,l); + return 0; + } + } + + virtual void write(const void *p,int l) + { + if ((pos+l) > len) + throw StreamException("Stream - premature end of write()"); + memcpy(&buf[pos],p,l); + pos += l; + } + + virtual bool eof() + { + return pos >= len; + } + + virtual void rewind() + { + pos = 0; + } + + virtual void seekTo(int p) + { + pos = p; + } + + virtual int getPosition() + { + return pos; + } + + void convertFromBase64(); + + + char *buf; + bool own; + int len,pos; +}; +// -------------------------------------------------- +class IndirectStream : public Stream +{ +public: + + void init(Stream *s) + { + stream = s; + } + + virtual int read(void *p,int l) + { + return stream->read(p,l); + } + + virtual void write(const void *p,int l) + { + stream->write(p,l); + } + + virtual bool eof() + { + return stream->eof(); + } + + virtual void close() + { + stream->close(); + } + + Stream *stream; +}; + +// ------------------------------------- + +class SockBufStream : public Stream +{ +public: + SockBufStream(Stream &sockStream, int bufsize=128*1024) + : sock(sockStream), mem(bufsize) + { + } + + ~SockBufStream() + { + flush(); + mem.free2(); + } + + virtual int read(void *p,int l) + { + return sock.read(p, l); + } + + virtual void write(const void *p, int len) + { + if ( mem.pos+len > mem.len ) + flush(); + + mem.write(p, len); + } + + void flush() + { + if ( mem.pos > 0 ) { + sock.write(mem.buf, mem.pos); + clearWriteBuffer(); + } + } + + void clearWriteBuffer() + { + mem.rewind(); + } + +private: + Stream &sock; + MemoryStream mem; +}; + +// ------------------------------------- +class WriteBufferStream : public Stream +{ +public: + WriteBufferStream(Stream *out_) + :buf(NULL) + ,own(false) + ,len(0) + ,pos(0) + ,out(out_) + { + } + + WriteBufferStream(void *p, int l, Stream *out_) + :buf((char *)p) + ,own(false) + ,len(l) + ,pos(0) + ,out(out_) + { + } + + WriteBufferStream(int l, Stream *out_) + :buf(new char[l]) + ,own(true) + ,len(l) + ,pos(0) + ,out(out_) + { + } + + virtual ~WriteBufferStream() + { + try { + flush(); + } catch (StreamException &) {} + free(); + } + + void readFromFile(FileStream &file) + { + len = file.length(); + buf = new char[len]; + own = true; + pos = 0; + file.read(buf,len); + } + + void flush() + { + if (!out || !buf) return; + out->write(buf, pos); + pos = 0; + } + + void free() + { + if (own && buf) + { + delete buf; + buf = NULL; + own = false; + } + + } + + virtual int read(void *p,int l) + { + return 0; + } + + virtual void write(const void *p,int l) + { + char *cp = (char *) p; + while ((pos + l) >= len) { + int n = len - pos; + memcpy(&buf[pos], cp, n); + l -= n; + cp += n; + pos = len; + flush(); + if (pos != 0) return; + } + if (l > 0) { + memcpy(&buf[pos], cp, l); + pos += l; + } + } + + virtual bool eof() + { + return true; + } + + virtual void rewind() + { + pos = 0; + } + + virtual void seekTo(int p) + { + pos = p; + } + + virtual int getPosition() + { + return pos; + } + + void convertFromBase64(); + + + char *buf; + bool own; + int len,pos; + Stream *out; +}; + +#endif + diff --git a/PeerCast.root/PeerCast/core/common/sys.cpp b/PeerCast.root/PeerCast/core/common/sys.cpp new file mode 100644 index 0000000..1e0704b --- /dev/null +++ b/PeerCast.root/PeerCast/core/common/sys.cpp @@ -0,0 +1,1041 @@ +// ------------------------------------------------ +// File : sys.cpp +// Date: 4-apr-2002 +// Author: giles +// Desc: +// Sys is a base class for all things systemy, like starting threads, creating sockets etc.. +// Lock is a very basic cross platform CriticalSection class +// SJIS-UTF8 conversion by ???? +// +// (c) 2002 peercast.org +// ------------------------------------------------ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// ------------------------------------------------ + +#include "common.h" +#include "sys.h" +#include "socket.h" +#include "gnutella.h" +#include "servmgr.h" //JP-EX +#ifdef WIN32 +#include "utf8.h" //JP-Patch +#endif +#include +#include +#include "jis.h" +#ifdef _DEBUG +#include "chkMemoryLeak.h" +#define DEBUG_NEW new(__FILE__, __LINE__) +#define new DEBUG_NEW +#endif + +// ----------------------------------- +#define isSJIS(a,b) ((a >= 0x81 && a <= 0x9f || a >= 0xe0 && a<=0xfc) && (b >= 0x40 && b <= 0x7e || b >= 0x80 && b<=0xfc)) +#define isEUC(a) (a >= 0xa1 && a <= 0xfe) +#define isASCII(a) (a <= 0x7f) +#define isPLAINASCII(a) (((a >= '0') && (a <= '9')) || ((a >= 'a') && (a <= 'z')) || ((a >= 'A') && (a <= 'Z'))) +#define isUTF8(a,b) ((a & 0xc0) == 0xc0 && (b & 0x80) == 0x80 ) +#define isESCAPE(a,b) ((a == '&') && (b == '#')) +#define isHTMLSPECIAL(a) ((a == '&') || (a == '\"') || (a == '\'') || (a == '<') || (a == '>')) + + + +// ----------------------------------- +const char *LogBuffer::logTypes[]= +{ + "", + "DBUG", + "EROR", + "GNET", + "CHAN", +}; + +// ----------------------------------- +// base64 encode/decode taken from ices2 source.. +static char base64table[64] = { + 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P', + 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f', + 'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v', + 'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/' +}; +#if 0 +// ----------------------------------- +static char *util_base64_encode(char *data) +{ + int len = strlen(data); + char *out = malloc(len*4/3 + 4); + char *result = out; + int chunk; + + while(len > 0) { + chunk = (len >3)?3:len; + *out++ = base64table[(*data & 0xFC)>>2]; + *out++ = base64table[((*data & 0x03)<<4) | ((*(data+1) & 0xF0) >> 4)]; + switch(chunk) { + case 3: + *out++ = base64table[((*(data+1) & 0x0F)<<2) | ((*(data+2) & 0xC0)>>6)]; + *out++ = base64table[(*(data+2)) & 0x3F]; + break; + case 2: + *out++ = base64table[((*(data+1) & 0x0F)<<2)]; + *out++ = '='; + break; + case 1: + *out++ = '='; + *out++ = '='; + break; + } + data += chunk; + len -= chunk; + } + + return result; +} +#endif + +// ----------------------------------- +static int base64chartoval(char input) +{ + if(input >= 'A' && input <= 'Z') + return input - 'A'; + else if(input >= 'a' && input <= 'z') + return input - 'a' + 26; + else if(input >= '0' && input <= '9') + return input - '0' + 52; + else if(input == '+') + return 62; + else if(input == '/') + return 63; + else if(input == '=') + return -1; + else + return -2; +} + +// ----------------------------------- +static char *util_base64_decode(char *input) +{ + return NULL; +} + + + + + +// ------------------------------------------ +Sys::Sys() +{ + idleSleepTime = 10; + logBuf = new LogBuffer(1000,100); + numThreads=0; +} + +// ------------------------------------------ +void Sys::sleepIdle() +{ + sleep(idleSleepTime); +} + +// ------------------------------------------ +bool Host::isLocalhost() +{ + return loopbackIP() || (ip == ClientSocket::getIP(NULL)); +} +// ------------------------------------------ +void Host::fromStrName(const char *str, int p) +{ + if (!strlen(str)) + { + port = 0; + ip = 0; + return; + } + + char name[128]; + strncpy(name,str,sizeof(name)-1); + name[127] = '\0'; + port = p; + char *pp = strstr(name,":"); + if (pp) + { + port = atoi(pp+1); + pp[0] = 0; + } + + ip = ClientSocket::getIP(name); +} +// ------------------------------------------ +void Host::fromStrIP(const char *str, int p) +{ + unsigned int ipb[4]; + unsigned int ipp; + + + if (strstr(str,":")) + { + if (sscanf(str,"%03d.%03d.%03d.%03d:%d",&ipb[0],&ipb[1],&ipb[2],&ipb[3],&ipp) == 5) + { + ip = ((ipb[0]&0xff) << 24) | ((ipb[1]&0xff) << 16) | ((ipb[2]&0xff) << 8) | ((ipb[3]&0xff)); + port = ipp; + }else + { + ip = 0; + port = 0; + } + }else{ + port = p; + if (sscanf(str,"%03d.%03d.%03d.%03d",&ipb[0],&ipb[1],&ipb[2],&ipb[3]) == 4) + ip = ((ipb[0]&0xff) << 24) | ((ipb[1]&0xff) << 16) | ((ipb[2]&0xff) << 8) | ((ipb[3]&0xff)); + else + ip = 0; + } +} +// ----------------------------------- +bool Host::isMemberOf(Host &h) +{ + if (h.ip==0) + return false; + + if( h.ip0() != 255 && ip0() != h.ip0() ) + return false; + if( h.ip1() != 255 && ip1() != h.ip1() ) + return false; + if( h.ip2() != 255 && ip2() != h.ip2() ) + return false; + if( h.ip3() != 255 && ip3() != h.ip3() ) + return false; + +/* removed for endieness compatibility + for(int i=0; i<4; i++) + if (h.ipByte[i] != 255) + if (ipByte[i] != h.ipByte[i]) + return false; +*/ + return true; +} + +// ----------------------------------- +char *trimstr(char *s1) +{ + while (*s1) + { + if ((*s1 == ' ') || (*s1 == '\t')) + s1++; + else + break; + + } + + char *s = s1; + + if(strlen(s1) > 0) { +/* s1 = s1+strlen(s1); + + while (*--s1) + if ((*s1 != ' ') && (*s1 != '\t')) + break;*/ + + s1 = s1+strlen(s1); + +// s1[1] = 0; + + while (*--s1) + if ((*s1 != ' ') && (*s1 != '\t')) + break; + + s1[1] = 0; + } + return s; +} + +// ----------------------------------- +char *stristr(const char *s1, const char *s2) +{ + while (*s1) + { + if (TOUPPER(*s1) == TOUPPER(*s2)) + { + const char *c1 = s1; + const char *c2 = s2; + + while (*c1 && *c2) + { + if (TOUPPER(*c1) != TOUPPER(*c2)) + break; + c1++; + c2++; + } + if (*c2==0) + return (char *)s1; + } + + s1++; + } + return NULL; +} +// ----------------------------------- +bool String::isValidURL() +{ + return (strnicmp(data,"http://",7)==0) || (strnicmp(data,"mailto:",7)==0); +} + +// ----------------------------------- +void String::setFromTime(unsigned int t) +{ +// char *p = ctime((time_t*)&t); + time_t tmp = t; + char *p = ctime(&tmp); + if (p) + strcpy(data,p); + else + strcpy(data,"-"); + type = T_ASCII; +} +// ----------------------------------- +void String::setFromStopwatch(unsigned int t) +{ + unsigned int sec,min,hour,day; + + sec = t%60; + min = (t/60)%60; + hour = (t/3600)%24; + day = (t/86400); + + if (day) + sprintf(data,"%d day, %d hour",day,hour); + else if (hour) + sprintf(data,"%d hour, %d min",hour,min); + else if (min) + sprintf(data,"%d min, %d sec",min,sec); + else if (sec) + sprintf(data,"%d sec",sec); + else + sprintf(data,"-"); + + type = T_ASCII; +} +// ----------------------------------- +void String::setFromString(const char *str, TYPE t) +{ + int cnt=0; + bool quote=false; + while (*str) + { + bool add=true; + if (*str == '\"') + { + if (quote) + break; + else + quote = true; + add = false; + }else if (*str == ' ') + { + if (!quote) + { + if (cnt) + break; + else + add = false; + } + } + + if (add) + { + data[cnt++] = *str++; + if (cnt >= (MAX_LEN-1)) + break; + }else + str++; + } + data[cnt] = 0; + type = t; +} + +// ----------------------------------- +int String::base64WordToChars(char *out,const char *input) +{ + char *start = out; + signed char vals[4]; + + vals[0] = base64chartoval(*input++); + vals[1] = base64chartoval(*input++); + vals[2] = base64chartoval(*input++); + vals[3] = base64chartoval(*input++); + + if(vals[0] < 0 || vals[1] < 0 || vals[2] < -1 || vals[3] < -1) + return 0; + + *out++ = vals[0]<<2 | vals[1]>>4; + if(vals[2] >= 0) + *out++ = ((vals[1]&0x0F)<<4) | (vals[2]>>2); + else + *out++ = 0; + + if(vals[3] >= 0) + *out++ = ((vals[2]&0x03)<<6) | (vals[3]); + else + *out++ = 0; + + return out-start; +} + +// ----------------------------------- +void String::BASE642ASCII(const char *input) +{ + char *out = data; + int len = strlen(input); + + while(len >= 4) + { + out += base64WordToChars(out,input); + input += 4; + len -= 4; + } + *out = 0; +} + + + +// ----------------------------------- +void String::UNKNOWN2UNICODE(const char *in,bool safe) +{ + MemoryStream utf8(data,MAX_LEN-1); + + unsigned char c; + unsigned char d; + + while (c = *in++) + { + d = *in; + + if (isUTF8(c,d)) // utf8 encoded + { + int numChars=0; + int i; + + for(i=0; i<6; i++) + { + if (c & (0x80>>i)) + numChars++; + else + break; + } + + utf8.writeChar(c); + for(i=0; i') str = ">"; + else str = "?"; + + utf8.writeString(str); + } + else + { + utf8.writeUTF8(c); + } + + if (utf8.pos >= (MAX_LEN-10)) + break; + + + } + + utf8.writeChar(0); // null terminate + +} + +// ----------------------------------- +void String::ASCII2HTML(const char *in) +{ + char *op = data; + char *oe = data+MAX_LEN-10; + unsigned char c; + const char *p = in; + while (c = *p++) + { + + if (((c >= '0') && (c <= '9')) || ((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z'))) + { + *op++ = c; + }else + { + sprintf(op,"&#x%02X;",(int)c); + op+=6; + } + if (op >= oe) + break; + } + *op = 0; +} +// ----------------------------------- +void String::ASCII2ESC(const char *in, bool safe) +{ + char *op = data; + char *oe = data+MAX_LEN-10; + const char *p = in; + unsigned char c; + while (c = *p++) + { + if (((c >= '0') && (c <= '9')) || ((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z'))) + *op++ = c; + else + { + *op++ = '%'; + if (safe) + *op++ = '%'; + *op=0; + sprintf(op,"%02X",(int)c); + op+=2; + } + if (op >= oe) + break; + } + *op=0; +} +// ----------------------------------- +void String::HTML2ASCII(const char *in) +{ + unsigned char c; + char *o = data; + char *oe = data+MAX_LEN-10; + const char *p = in; + while (c = *p++) + { + if ((c == '&') && (p[0] == '#')) + { + p++; + char code[8]; + char *cp = code; + char ec = *p++; // hex/dec + while (c=*p++) + { + if (c!=';') + *cp++ = c; + else + break; + } + *cp = 0; + c = (unsigned char)strtoul(code,NULL,ec=='x'?16:10); + } + *o++ = c; + if (o >= oe) + break; + } + + *o=0; +} +// ----------------------------------- +void String::HTML2UNICODE(const char *in) +{ + MemoryStream utf8(data,MAX_LEN-1); + + unsigned char c; + while (c = *in++) + { + if ((c == '&') && (*in == '#')) + { + in++; + char code[16]; + char *cp = code; + char ec = *in++; // hex/dec + while (c=*in++) + { + if (c!=';') + *cp++ = c; + else + break; + } + *cp = 0; + utf8.writeUTF8(strtoul(code,NULL,ec=='x'?16:10)); + }else + utf8.writeUTF8(c); + + if (utf8.pos >= (MAX_LEN-10)) + break; + } + + utf8.writeUTF8(0); +} + +// ----------------------------------- +void String::ESC2ASCII(const char *in) +{ + unsigned char c; + char *o = data; + char *oe = data+MAX_LEN-10; + const char *p = in; + while (c = *p++) + { + if (c == '+') + c = ' '; + else if (c == '%') + { + if (p[0] == '%') + p++; + + char hi = TOUPPER(p[0]); + char lo = TOUPPER(p[1]); + c = (TONIBBLE(hi)<<4) | TONIBBLE(lo); + p+=2; + } + *o++ = c; + if (o >= oe) + break; + } + + *o=0; +} +// ----------------------------------- +void String::ASCII2META(const char *in, bool safe) +{ + char *op = data; + char *oe = data+MAX_LEN-10; + const char *p = in; + unsigned char c; + while (c = *p++) + { + switch (c) + { + case '%': + if (safe) + *op++='%'; + break; + case ';': + c = ':'; + break; + } + + *op++=c; + if (op >= oe) + break; + } + *op=0; +} +#ifdef WIN32 +// ----------------------------------- +void String::ASCII2SJIS(const char *in) //JP-EX +{ + char *op = data; + char *p; + if (utf8_decode(in,&p)<0) + { + strcpy(op,in); + return; + } + strcpy(op,p); + free(p); +} +#endif +// ----------------------------------- +void String::convertTo(TYPE t) +{ + if (t != type) + { + String tmp = *this; + + // convert to ASCII + switch (type) + { + case T_UNKNOWN: + case T_ASCII: + break; + case T_HTML: + tmp.HTML2ASCII(data); + break; + case T_ESC: + case T_ESCSAFE: + tmp.ESC2ASCII(data); + break; + case T_META: + case T_METASAFE: + break; + case T_BASE64: + tmp.BASE642ASCII(data); + break; + } + + // convert to new format + switch (t) + { + case T_UNKNOWN: + case T_ASCII: + strcpy(data,tmp.data); + break; + case T_UNICODE: + UNKNOWN2UNICODE(tmp.data,false); + break; + case T_UNICODESAFE: + UNKNOWN2UNICODE(tmp.data,true); + break; + case T_HTML: + ASCII2HTML(tmp.data); + break; + case T_ESC: + ASCII2ESC(tmp.data,false); + break; + case T_ESCSAFE: + ASCII2ESC(tmp.data,true); + break; + case T_META: + ASCII2META(tmp.data,false); + break; + case T_METASAFE: + ASCII2META(tmp.data,true); + break; +#ifdef WIN32 + case T_SJIS: //JP-EX + ASCII2SJIS(tmp.data); + break; +#endif + } + + type = t; + } +} +// ----------------------------------- +void LogBuffer::write(const char *str, TYPE t) +{ + lock.on(); + + unsigned int len = strlen(str); + int cnt=0; + while (len) + { + unsigned int rlen = len; + if (rlen > (lineLen-1)) + rlen = lineLen-1; + + int i = currLine % maxLines; + int bp = i*lineLen; + strncpy(&buf[bp],str,rlen); + buf[bp+rlen] = 0; + if (cnt==0) + { + times[i] = sys->getTime(); + types[i] = t; + }else + { + times[i] = 0; + types[i] = T_NONE; + } + currLine++; + + str += rlen; + len -= rlen; + cnt++; + } + + lock.off(); +} + +// ----------------------------------- +char *getCGIarg(const char *str, const char *arg) +{ + if (!str) + return NULL; + +// char *s = strstr(str,arg); + char *s = (char*)strstr(str,arg); + + if (!s) + return NULL; + + s += strlen(arg); + + return s; +} + +// ----------------------------------- +bool cmpCGIarg(char *str, char *arg, char *value) +{ + if ((!str) || (!strlen(value))) + return false; + + if (strnicmp(str,arg,strlen(arg)) == 0) + { + + str += strlen(arg); + + return strncmp(str,value,strlen(value))==0; + }else + return false; +} +// ----------------------------------- +bool hasCGIarg(char *str, char *arg) +{ + if (!str) + return false; + + char *s = strstr(str,arg); + + if (!s) + return false; + + return true; +} + + +// --------------------------- +void GnuID::encode(Host *h, const char *salt1, const char *salt2, unsigned char salt3) +{ + int s1=0,s2=0; + for(int i=0; i<16; i++) + { + unsigned char ipb = id[i]; + + // encode with IP address + if (h) + ipb ^= ((unsigned char *)&h->ip)[i&3]; + + // add a bit of salt + if (salt1) + { + if (salt1[s1]) + ipb ^= salt1[s1++]; + else + s1=0; + } + + // and some more + if (salt2) + { + if (salt2[s2]) + ipb ^= salt2[s2++]; + else + s2=0; + } + + // plus some pepper + ipb ^= salt3; + + id[i] = ipb; + } + +} +// --------------------------- +void GnuID::toStr(char *str) +{ + + str[0] = 0; + for(int i=0; i<16; i++) + { + char tmp[8]; + unsigned char ipb = id[i]; + + sprintf(tmp,"%02X",ipb); + strcat(str,tmp); + } + +} +// --------------------------- +void GnuID::fromStr(const char *str) +{ + clear(); + + if (strlen(str) < 32) + return; + + char buf[8]; + + buf[2] = 0; + + for(int i=0; i<16; i++) + { + buf[0] = str[i*2]; + buf[1] = str[i*2+1]; + id[i] = (unsigned char)strtoul(buf,NULL,16); + } + +} + +// --------------------------- +void GnuID::generate(unsigned char flags) +{ + clear(); + + for(int i=0; i<16; i++) + id[i] = sys->rnd(); + + id[0] = flags; +} + +// --------------------------- +unsigned char GnuID::getFlags() +{ + return id[0]; +} + +// --------------------------- +GnuIDList::GnuIDList(int max) +:ids(new GnuID[max]) +{ + maxID = max; + for(int i=0; igetTime(); + return; + } + if (ids[i].storeTime <= minTime) + { + minTime = ids[i].storeTime; + minIndex = i; + } + } + + ids[minIndex] = id; + ids[minIndex].storeTime = sys->getTime(); +} +// --------------------------- +void GnuIDList::clear() +{ + for(int i=0; i maxLines) + { + nl = maxLines-1; + sp = (currLine+1)%maxLines; + } + + String tim,str; + if (nl) + { + for(unsigned int i=0; i["); + out.writeString(getTypeStr(types[sp])); + out.writeString("] "); + } + str.set(&buf[bp]); + str.convertTo(String::T_HTML); + + out.writeString(str.cstr()); + out.writeString("
"); + + sp++; + sp %= maxLines; + } + } + + lb.off(); + +} + +// --------------------------- +void ThreadInfo::shutdown() +{ + active = false; + //sys->waitThread(this); +} diff --git a/PeerCast.root/PeerCast/core/common/sys.h b/PeerCast.root/PeerCast/core/common/sys.h new file mode 100644 index 0000000..5583a9d --- /dev/null +++ b/PeerCast.root/PeerCast/core/common/sys.h @@ -0,0 +1,534 @@ +// ------------------------------------------------ +// File : sys.h +// Date: 4-apr-2002 +// Author: giles +// Desc: +// +// (c) 2002 peercast.org +// ------------------------------------------------ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// ------------------------------------------------ + +#ifndef _SYS_H +#define _SYS_H + +#include +#include "common.h" + +#define RAND(a,b) (((a = 36969 * (a & 65535) + (a >> 16)) << 16) + \ + (b = 18000 * (b & 65535) + (b >> 16)) ) +extern char *stristr(const char *s1, const char *s2); +extern char *trimstr(char *s); + + +#define MAX_CGI_LEN 1024 +// ------------------------------------ +class String +{ +public: + enum { + MAX_LEN = 256 + }; + + enum TYPE + { + T_UNKNOWN, + T_ASCII, + T_HTML, + T_ESC, + T_ESCSAFE, + T_META, + T_METASAFE, + T_BASE64, + T_UNICODE, + T_UNICODESAFE, +#ifdef WIN32 + T_SJIS, //JP-EX +#endif + }; + + String() {clear();} + String(const char *p, TYPE t=T_ASCII) + { + set(p,t); + } + + // set from straight null terminated string + void set(const char *p, TYPE t=T_ASCII) + { + strncpy(data,p,MAX_LEN-1); + data[MAX_LEN-1] = 0; + type = t; + } + + // set from quoted or unquoted null terminated string + void setFromString(const char *str, TYPE t=T_ASCII); + + // set from stopwatch + void setFromStopwatch(unsigned int t); + + // set from time + void setFromTime(unsigned int t); + + + // from single word (end at whitespace) + void setFromWord(const char *str) + { + int i; + for(i=0; i 2) + { + if (slen >= MAX_LEN) slen = MAX_LEN; + strncpy(data,p+1,slen-2); + data[slen-2]=0; + }else + clear(); + type = t; + } + + void clear() + { + data[0]=0; + type = T_UNKNOWN; + } + void ASCII2ESC(const char *,bool); + void ASCII2HTML(const char *); + void ASCII2META(const char *,bool); + void ESC2ASCII(const char *); + void HTML2ASCII(const char *); + void HTML2UNICODE(const char *); + void BASE642ASCII(const char *); + void UNKNOWN2UNICODE(const char *,bool); +#ifdef WIN32 + void ASCII2SJIS(const char *); //JP-EX +#endif + + static int base64WordToChars(char *,const char *); + + static bool isSame(const char *s1, const char *s2) {return strcmp(s1,s2)==0;} + + bool startsWith(const char *s) const {return strncmp(data,s,strlen(s))==0;} + bool isValidURL(); + bool isEmpty() {return data[0]==0;} + bool isSame(::String &s) const {return strcmp(data,s.data)==0;} + bool isSame(const char *s) const {return strcmp(data,s)==0;} + bool contains(::String &s) {return stristr(data,s.data)!=NULL;} + bool contains(const char *s) {return stristr(data,s)!=NULL;} + void append(const char *s) + { + if ((strlen(s)+strlen(data) < (MAX_LEN-1))) + strcat(data,s); + } + void append(char c) + { + char tmp[2]; + tmp[0]=c; + tmp[1]=0; + append(tmp); + } + + void prepend(const char *s) + { + ::String tmp; + tmp.set(s); + tmp.append(data); + tmp.type = type; + *this = tmp; + } + + bool operator == (const char *s) const {return isSame(s);} + + operator const char *() const {return data;} + + void convertTo(TYPE t); + + char *cstr() {return data;} + + static bool isWhitespace(char c) {return c==' ' || c=='\t';} + + TYPE type; + char data[MAX_LEN]; +}; + +// ------------------------------------ +namespace peercast { +class Random { +public: + Random(int s=0x14235465) + { + setSeed(s); + } + + unsigned int next() + { + return RAND(a[0],a[1]); + } + + void setSeed(int s) + { + a[0] = a[1] = s; + } + + unsigned long a[2]; +}; +} +// ------------------------------------ +class Sys +{ +public: + Sys(); + + + + virtual class ClientSocket *createSocket() = 0; + virtual bool startThread(class ThreadInfo *) = 0; + virtual void sleep(int) = 0; + virtual void appMsg(long,long = 0) = 0; + virtual unsigned int getTime() = 0; + virtual double getDTime() = 0; + virtual unsigned int rnd() = 0; + virtual void getURL(const char *) = 0; + virtual void exit() = 0; + virtual bool hasGUI() = 0; + virtual void callLocalURL(const char *,int)=0; + virtual void executeFile(const char *) = 0; + virtual void endThread(ThreadInfo *) {} + virtual void waitThread(ThreadInfo *, int timeout = 30000) {} + + + +#ifdef __BIG_ENDIAN__ + unsigned short convertEndian(unsigned short v) { return SWAP2(v); } + unsigned int convertEndian(unsigned int v) { return SWAP4(v); } +#else + unsigned short convertEndian(unsigned short v) { return v; } + unsigned int convertEndian(unsigned int v) { return v; } +#endif + + + void sleepIdle(); + + unsigned int idleSleepTime; + unsigned int rndSeed; + unsigned int numThreads; + + class LogBuffer *logBuf; +}; + + +#ifdef WIN32 +#include + +typedef __int64 int64_t; + + +// ------------------------------------ +class WEvent +{ +public: + WEvent() + { + event = ::CreateEvent(NULL, // no security attributes + TRUE, // manual-reset + FALSE,// initially non-signaled + NULL);// anonymous + } + + ~WEvent() + { + ::CloseHandle(event); + } + + void signal() + { + ::SetEvent(event); + } + + void wait(int timeout = 30000) + { + switch(::WaitForSingleObject(event, timeout)) + { + case WAIT_TIMEOUT: + throw TimeoutException(); + break; + //case WAIT_OBJECT_0: + //break; + } + } + + void reset() + { + ::ResetEvent(event); + } + + + + HANDLE event; +}; + + + +// ------------------------------------ +typedef int (WINAPI *THREAD_FUNC)(ThreadInfo *); +typedef unsigned int THREAD_HANDLE; +#define THREAD_PROC int WINAPI +#define vsnprintf _vsnprintf + +// ------------------------------------ +class WLock +{ +public: + WLock() + { + InitializeCriticalSection(&cs); + } + + + void on() + { + EnterCriticalSection(&cs); + } + + void off() + { + LeaveCriticalSection(&cs); + } + + CRITICAL_SECTION cs; +}; +#endif + + +#ifdef _UNIX +// ------------------------------------ +#include +#include + +#ifdef __APPLE__ +#include +#define _BIG_ENDIAN 1 +#endif + +typedef long long int64_t; + +typedef int (*THREAD_FUNC)(ThreadInfo *); +#define THREAD_PROC int +typedef pthread_t THREAD_HANDLE; + +// ------------------------------------ +#define stricmp strcasecmp +#define strnicmp strncasecmp + + +// ------------------------------------ +class WEvent +{ +public: + + WEvent() + { + } + + void signal() + { + } + + void wait(int timeout = 30000) + { + } + + void reset() + { + } + +}; + +// ------------------------------------ +class WLock +{ +private: + pthread_mutex_t mutex; +public: + WLock() + { + const pthread_mutexattr_t mattr = + { +#ifdef __APPLE__ + PTHREAD_MUTEX_RECURSIVE +#else + PTHREAD_MUTEX_RECURSIVE_NP +#endif + }; + + pthread_mutex_init( &mutex, &mattr ); + } + + ~WLock() + { + pthread_mutex_destroy( &mutex ); + } + + + void on() + { + pthread_mutex_lock(&mutex); + } + + void off() + { + pthread_mutex_unlock(&mutex); + } + +}; +#endif + +class WLockBlock +{ +private: + WLock *lock; + bool flg; +public: + WLockBlock(WLock *l){ + lock = l; + flg = false; + } + ~WLockBlock(){ + if (flg){ + lock->off(); + LOG_DEBUG("LOCK OFF by destructor"); + } + } + void on(){ + flg = true; + lock->on(); + } + void off(){ + flg = false; + lock->off(); + } +}; + +// ------------------------------------ +class ThreadInfo +{ +public: + //typedef int (__stdcall *THREAD_FUNC)(ThreadInfo *); + + ThreadInfo() + { + active = false; + finish = false; + id = 0; + func = NULL; + data = NULL; + } + + void shutdown(); + + volatile bool active; + volatile bool finish; + int id; + THREAD_FUNC func; + THREAD_HANDLE handle; + + + void *data; +}; + + +// ------------------------------------ +class LogBuffer +{ +public: + enum TYPE + { + T_NONE, + T_DEBUG, + T_ERROR, + T_NETWORK, + T_CHANNEL, + }; + + LogBuffer(int i, int l) + { + lineLen = l; + maxLines = i; + currLine = 0; + buf = new char[lineLen*maxLines]; + times = new unsigned int [maxLines]; + types = new TYPE [maxLines]; + } + + void clear() + { + currLine = 0; + } + void write(const char *, TYPE); + static const char *getTypeStr(TYPE t) {return logTypes[t];} + void dumpHTML(class Stream &); + + char *buf; + unsigned int *times; + unsigned int currLine,maxLines,lineLen; + TYPE *types; + WLock lock; + static const char *logTypes[]; + +}; + +#define RWLOCK_READ_MAX 32 + +class LockBlock +{ +public: + LockBlock(WLock &l){ flg = false; lock = l; } + ~LockBlock(){ if (flg) lock.off(); } + void lockon(){ flg = true; lock.on(); } + void lockoff(){ flg = false; lock.off(); } + +private: + WLock lock; + bool flg; +}; + +// ------------------------------------ +extern Sys *sys; + +// ------------------------------------ + + +#if _BIG_ENDIAN +#define CHECK_ENDIAN2(v) v=SWAP2(v) +#define CHECK_ENDIAN3(v) v=SWAP3(v) +#define CHECK_ENDIAN4(v) v=SWAP4(v) +#else +#define CHECK_ENDIAN2 +#define CHECK_ENDIAN3 +#define CHECK_ENDIAN4 +#endif + + +// ------------------------------------ +#endif + diff --git a/PeerCast.root/PeerCast/core/common/url.cpp b/PeerCast.root/PeerCast/core/common/url.cpp new file mode 100644 index 0000000..f98d195 --- /dev/null +++ b/PeerCast.root/PeerCast/core/common/url.cpp @@ -0,0 +1,355 @@ +// ------------------------------------------------ +// File : url.h +// Date: 20-feb-2004 +// Author: giles +// +// (c) 2002-4 peercast.org +// ------------------------------------------------ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// ------------------------------------------------ + +#include "url.h" +#include "socket.h" +#include "http.h" +#include "servent.h" +#include "servmgr.h" +#include "peercast.h" +#include "version2.h" +#ifdef _DEBUG +#include "chkMemoryLeak.h" +#define DEBUG_NEW new(__FILE__, __LINE__) +#define new DEBUG_NEW +#endif + +// ------------------------------------------------ +void URLSource::stream(Channel *ch) +{ + + String url,tmpUrl; + while (ch->thread.active && !peercastInst->isQuitting) + { + tmpUrl = url; + if (url.isEmpty()) + url = baseurl; + + url = streamURL(ch,url.cstr()); + if (url == tmpUrl){ + sys->sleep(2000); + } + } + +} +// ------------------------------------------------ +int URLSource::getSourceRate() +{ + if (inputStream) + return inputStream->bytesInPerSec; + else + return 0; +} + +// ------------------------------------------------ +::String URLSource::streamURL(Channel *ch, const char *url) +{ + String nextURL; + + if (peercastInst->isQuitting || !ch->thread.active) + return nextURL; + + + String urlTmp; + urlTmp.set(url); + + char *fileName = urlTmp.cstr(); + + PlayList *pls=NULL; + ChannelStream *source=NULL; + + LOG_CHANNEL("Fetch URL=%s",fileName); + + try + { + + // get the source protocol + if (strnicmp(fileName,"http://",7)==0) + { + ch->info.srcProtocol = ChanInfo::SP_HTTP; + fileName += 7; + } + else if (strnicmp(fileName,"mms://",6)==0) + { + ch->info.srcProtocol = ChanInfo::SP_MMS; + fileName += 6; + } + else if (strnicmp(fileName,"pcp://",6)==0) + { + ch->info.srcProtocol = ChanInfo::SP_PCP; + fileName += 6; + } + else if (strnicmp(fileName,"file://",7)==0) + { + ch->info.srcProtocol = ChanInfo::SP_FILE; + fileName += 7; + } + else + { + ch->info.srcProtocol = ChanInfo::SP_FILE; + } + + // default to mp3 for shoutcast servers + if (ch->info.contentType == ChanInfo::T_PLS) + ch->info.contentType = ChanInfo::T_MP3; + + + ch->setStatus(Channel::S_CONNECTING); + + if ((ch->info.srcProtocol == ChanInfo::SP_HTTP) || (ch->info.srcProtocol == ChanInfo::SP_PCP) || (ch->info.srcProtocol == ChanInfo::SP_MMS)) + { + + if ((ch->info.contentType == ChanInfo::T_WMA) || (ch->info.contentType == ChanInfo::T_WMV)) + ch->info.srcProtocol = ChanInfo::SP_MMS; + + + LOG_CHANNEL("Channel source is HTTP"); + + ClientSocket *inputSocket = sys->createSocket(); + if (!inputSocket) + throw StreamException("Channel cannot create socket"); + + + inputStream = inputSocket; + + + char *dir = strstr(fileName,"/"); + if (dir) + *dir++=0; + + + LOG_CHANNEL("Fetch Host=%s",fileName); + if (dir) + LOG_CHANNEL("Fetch Dir=%s",dir); + + + Host host; + host.fromStrName(fileName,80); + + inputSocket->open(host); + inputSocket->connect(); + + HTTP http(*inputSocket); + http.writeLineF("GET /%s HTTP/1.0",dir?dir:""); + + http.writeLineF("%s %s",HTTP_HS_HOST,fileName); + http.writeLineF("%s %s",HTTP_HS_CONNECTION,"close"); + http.writeLineF("%s %s",HTTP_HS_ACCEPT,"*/*"); + + if (ch->info.srcProtocol == ChanInfo::SP_MMS) + { + http.writeLineF("%s %s",HTTP_HS_AGENT,"NSPlayer/4.1.0.3856"); + http.writeLine("Pragma: no-cache,rate=1.000000,request-context=1"); + //http.writeLine("Pragma: no-cache,rate=1.000000,stream-time=0,stream-offset=4294967295:4294967295,request-context=22605256,max-duration=0"); + http.writeLine("Pragma: xPlayStrm=1"); + http.writeLine("Pragma: xClientGUID={c77e7400-738a-11d2-9add-0020af0a3278}"); + http.writeLine("Pragma: stream-switch-count=2"); + http.writeLine("Pragma: stream-switch-entry=ffff:1:0 ffff:2:0"); + }else + { + http.writeLineF("%s %s",HTTP_HS_AGENT,PCX_AGENT); + http.writeLineF("%s %d",PCX_HS_PCP,1); + http.writeLine("Icy-MetaData:1"); // fix by ravon + } + + http.writeLine(""); + + int res = http.readResponse(); + + + String name = ch->info.name; + + while (http.nextHeader()) + { + + LOG_CHANNEL("Fetch HTTP: %s",http.cmdLine); + + ChanInfo tmpInfo = ch->info; + Servent::readICYHeader(http,ch->info,NULL); + + if (!tmpInfo.name.isEmpty()) + ch->info.name = tmpInfo.name; + if (!tmpInfo.genre.isEmpty()) + ch->info.genre = tmpInfo.genre; + if (!tmpInfo.url.isEmpty()) + ch->info.url = tmpInfo.url; + + if (http.isHeader("icy-metaint")) + ch->icyMetaInterval = http.getArgInt(); + else if (http.isHeader("Location:")) + nextURL.set(http.getArgStr()); + + char *arg = http.getArgStr(); + if (arg) + { + if (http.isHeader("content-type")) + { + if (stristr(arg,MIME_XSCPLS)) + pls = new PlayList(PlayList::T_SCPLS, 1000); + else if (stristr(arg,MIME_PLS)) + pls = new PlayList(PlayList::T_PLS, 1000); + else if (stristr(arg,MIME_XPLS)) + pls = new PlayList(PlayList::T_PLS, 1000); + else if (stristr(arg,MIME_M3U)) + pls = new PlayList(PlayList::T_PLS, 1000); + else if (stristr(arg,MIME_TEXT)) + pls = new PlayList(PlayList::T_PLS, 1000); + else if (stristr(arg,MIME_ASX)) + pls = new PlayList(PlayList::T_ASX, 1000); + else if (stristr(arg,MIME_MMS)) + ch->info.srcProtocol = ChanInfo::SP_MMS; + } + } + + } + + if ((!nextURL.isEmpty()) && (res==302)) + { + LOG_CHANNEL("Channel redirect: %s",nextURL.cstr()); + inputSocket->close(); + delete inputSocket; + inputSocket = NULL; + return nextURL; + } + + if (res!=200) + { + LOG_ERROR("HTTP response: %d",res); + throw StreamException("Bad HTTP connect"); + } + + + }else if (ch->info.srcProtocol == ChanInfo::SP_FILE) + { + + LOG_CHANNEL("Channel source is FILE"); + + FileStream *fs = new FileStream(); + fs->openReadOnly(fileName); + inputStream = fs; + + ChanInfo::TYPE fileType = ChanInfo::T_UNKNOWN; + // if filetype is unknown, try and figure it out from file extension. + //if ((info.srcType == ChanInfo::T_UNKNOWN) || (info.srcType == ChanInfo::T_PLAYLIST)) + { + const char *ext = fileName+strlen(fileName); + while (*--ext) + if (*ext=='.') + { + ext++; + break; + } + + fileType = ChanInfo::getTypeFromStr(ext); + } + + + if (ch->info.bitrate) + ch->readDelay = true; + + + if (fileType == ChanInfo::T_PLS) + pls = new PlayList(PlayList::T_PLS, 1000); + else if (fileType == ChanInfo::T_ASX) + pls = new PlayList(PlayList::T_ASX, 1000); + else + ch->info.contentType = fileType; + + }else + { + throw StreamException("Unsupported URL"); + } + + + if (pls) + { + + LOG_CHANNEL("Channel is Playlist"); + + pls->read(*inputStream); + + inputStream->close(); + delete inputStream; + inputStream = NULL; + + int urlNum=0; + String url; + + LOG_CHANNEL("Playlist: %d URLs",pls->numURLs); + while ((ch->thread.active) && (pls->numURLs) && (!peercastInst->isQuitting)) + { + if (url.isEmpty()) + { + url = pls->urls[urlNum%pls->numURLs]; + urlNum++; + } + try + { + url = streamURL(ch,url.cstr()); + }catch(StreamException &) + {} + } + + delete pls; + + }else + { + + // if we didn`t get a channel id from the source, then create our own (its an original broadcast) + if (!ch->info.id.isSet()) + { + ch->info.id = chanMgr->broadcastID; + ch->info.id.encode(NULL,ch->info.name.cstr(),ch->info.genre,ch->info.bitrate); + } + + if (ch->info.contentType == ChanInfo::T_ASX) + ch->info.contentType = ChanInfo::T_WMV; + + ch->setStatus(Channel::S_BROADCASTING); + + inputStream->setReadTimeout(60); // use longer read timeout + + source = ch->createSource(); + + ch->readStream(*inputStream,source); + + inputStream->close(); + } + + }catch(StreamException &e) + { + ch->setStatus(Channel::S_ERROR); + LOG_ERROR("Channel error: %s",e.msg); + sys->sleep(1000); + } + + + ch->setStatus(Channel::S_CLOSING); + if (inputStream) + { + delete inputStream; + inputStream = NULL; + } + + if (source) + delete source; + + + return nextURL; + +} diff --git a/PeerCast.root/PeerCast/core/common/url.h b/PeerCast.root/PeerCast/core/common/url.h new file mode 100644 index 0000000..8d113c0 --- /dev/null +++ b/PeerCast.root/PeerCast/core/common/url.h @@ -0,0 +1,49 @@ +// ------------------------------------------------ +// File : url.h +// Date: 20-feb-2004 +// Author: giles +// +// (c) 2002-4 peercast.org +// ------------------------------------------------ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// ------------------------------------------------ + +#ifndef _URL_H +#define _URL_H + +#include "channel.h" + +// ------------------------------------------------ +class URLSource : public ChannelSource +{ +public: + URLSource(const char *url) + :inputStream(NULL) + { + baseurl.set(url); + } + + ::String streamURL(Channel *, const char *); + + virtual void stream(Channel *); + + virtual int getSourceRate(); + + + Stream *inputStream; + ::String baseurl; +}; + + + + +#endif + diff --git a/PeerCast.root/PeerCast/core/common/utf8.c b/PeerCast.root/PeerCast/core/common/utf8.c new file mode 100644 index 0000000..4747c3f --- /dev/null +++ b/PeerCast.root/PeerCast/core/common/utf8.c @@ -0,0 +1,343 @@ +/* + * Copyright (C) 2001 Peter Harris + * Copyright (C) 2001 Edmund Grimley Evans + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * Convert a string between UTF-8 and the locale's charset. + */ + +#include +#include + +#include "utf8.h" +#include "identify_encoding.h" +#ifdef _WIN32 + +/* Thanks to Peter Harris for this win32 + * code. + */ + +#include +#include + +static unsigned char *make_utf8_string(const wchar_t *unicode) +{ + int size = 0, index = 0, out_index = 0; + unsigned char *out; + unsigned short c; + + /* first calculate the size of the target string */ + c = unicode[index++]; + while (c) + { + if (c < 0x0080) + { + size += 1; + } + else if (c < 0x0800) + { + size += 2; + }else{ + size += 3; + } + c = unicode[index++]; + } + + out = (unsigned char *)malloc(size + 1); + if (out == NULL) + return NULL; + index = 0; + + c = unicode[index++]; + while (c) + { + if (c < 0x080) + { + out[out_index++] = (unsigned char)c; + }else if (c < 0x800) + { + out[out_index++] = 0xc0 | (c >> 6); + out[out_index++] = 0x80 | (c & 0x3f); + }else{ + out[out_index++] = 0xe0 | (c >> 12); + out[out_index++] = 0x80 | ((c >> 6) & 0x3f); + out[out_index++] = 0x80 | (c & 0x3f); + } + c = unicode[index++]; + } + out[out_index] = 0x00; + + return out; +} + +static wchar_t *make_unicode_string(const unsigned char *utf8) +{ + int size = 0, index = 0, out_index = 0; + wchar_t *out; + unsigned char c; + + /* first calculate the size of the target string */ + c = utf8[index++]; + while (c) + { + if ((c & 0x80) == 0) + { + index += 0; + }else if((c & 0xe0) == 0xe0) + { + index += 2; + }else{ + index += 1; + } + size += 1; + c = utf8[index++]; + } + + out = (wchar_t *)malloc((size + 1) * sizeof(wchar_t)); + if (out == NULL) + return NULL; + index = 0; + + c = utf8[index++]; + while (c) + { + if ((c & 0x80) == 0) + { + out[out_index++] = c; + }else if ((c & 0xe0) == 0xe0) + { + out[out_index] = (c & 0x1F) << 12; + c = utf8[index++]; + out[out_index] |= (c & 0x3F) << 6; + c = utf8[index++]; + out[out_index++] |= (c & 0x3F); + }else{ + out[out_index] = (c & 0x3F) << 6; + c = utf8[index++]; + out[out_index++] |= (c & 0x3F); + } + c = utf8[index++]; + } + out[out_index] = 0; + + return out; +} + +int utf8_encode(const char *from, char **to) +{ + wchar_t *unicode; + int wchars, err; + + + wchars = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, from, + strlen(from), NULL, 0); + + if(wchars == 0) + { +// fprintf(stderr, "Unicode translation error %d\n", GetLastError()); + return -1; + } + + unicode = (wchar_t *)calloc(wchars + 1, sizeof(unsigned short)); + if(unicode == NULL) + { +// fprintf(stderr, "Out of memory processing string to UTF8\n"); + return -1; + } + + err = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, from, strlen(from), unicode, wchars); + if (err != wchars) + { + free(unicode); +// fprintf(stderr, "Unicode translation error %d\n", GetLastError()); + return -1; + } + + /* On NT-based windows systems, we could use WideCharToMultiByte(), but + * MS doesn't actually have a consistent API across win32. + */ + *to = (char *)make_utf8_string(unicode); + + free(unicode); + return 0; +} + +int utf8_decode(const char *from, char **to) +{ + wchar_t *unicode; + int chars, err; + + const char *cds; + identify_encoding_t *cdt; + enum identify_encoding_order order; + order = ieo_SJIS; + cdt = identify_encoding_open(order); + cds = identify_encoding(cdt,(char *)from); + if (strcmp(cds,"UTF-8")!=0) + { + identify_encoding_close(cdt); + return -1; + } + identify_encoding_close(cdt); + + + /* On NT-based windows systems, we could use MultiByteToWideChar(CP_UTF8), but + * MS doesn't actually have a consistent API across win32. + */ + unicode = (wchar_t *)make_unicode_string((const unsigned char *)from); + if (unicode == NULL) + { +// fprintf(stderr, "Out of memory processing string from UTF8 to UNICODE16\n"); + return -1; + } + + chars = WideCharToMultiByte(GetConsoleCP(), WC_COMPOSITECHECK, unicode, -1, NULL, 0, NULL, NULL); + + if (chars == 0) + { +// fprintf(stderr, "Unicode translation error %d\n", GetLastError()); + free(unicode); + return -1; + } + + *to = (char *)calloc(chars + 1, sizeof(unsigned char)); + if (*to == NULL) + { +// fprintf(stderr, "Out of memory processing string to local charset\n"); + free(unicode); + return -1; + } + + err = WideCharToMultiByte(GetConsoleCP(), WC_COMPOSITECHECK, unicode, -1, *to, chars, NULL, NULL); + if (err != chars) + { +// fprintf(stderr, "Unicode translation error %d\n", GetLastError()); + free(unicode); + free(*to); + *to = NULL; + return -1; + } + + free(unicode); + return 0; +} + +#else /* End win32. Rest is for real operating systems */ + + +#ifdef HAVE_LANGINFO_CODESET +#include +#endif + +int iconvert(const char *fromcode, const char *tocode, + const char *from, size_t fromlen, + char **to, size_t *tolen); + +static char *current_charset = 0; /* means "US-ASCII" */ + +void convert_set_charset(const char *charset) +{ + + if (!charset) + charset = getenv("CHARSET"); + +#ifdef HAVE_LANGINFO_CODESET + if (!charset) + charset = nl_langinfo(CODESET); +#endif + + free(current_charset); + current_charset = 0; + if (charset && *charset) + current_charset = strdup(charset); +} + +static int convert_buffer(const char *fromcode, const char *tocode, + const char *from, size_t fromlen, + char **to, size_t *tolen) +{ + int ret = -1; + +#ifdef HAVE_ICONV + ret = iconvert(fromcode, tocode, from, fromlen, to, tolen); + if (ret != -1) + return ret; +#endif + +#ifndef HAVE_ICONV /* should be ifdef USE_CHARSET_CONVERT */ + ret = charset_convert(fromcode, tocode, from, fromlen, to, tolen); + if (ret != -1) + return ret; +#endif + + return ret; +} + +static int convert_string(const char *fromcode, const char *tocode, + const char *from, char **to, char replace) +{ + int ret; + size_t fromlen; + char *s; + + fromlen = strlen(from); + ret = convert_buffer(fromcode, tocode, from, fromlen, to, 0); + if (ret == -2) + return -1; + if (ret != -1) + return ret; + + s = malloc(fromlen + 1); + if (!s) + return -1; + strcpy(s, from); + *to = s; + for (; *s; s++) + if (*s & ~0x7f) + *s = replace; + return 3; +} + +int utf8_encode(const char *from, char **to) +{ + char *charset; + + if (!current_charset) + convert_set_charset(0); + charset = current_charset ? current_charset : "US-ASCII"; + return convert_string(charset, "UTF-8", from, to, '#'); +} + +int utf8_decode(const char *from, char **to) +{ + char *charset; + + if (*from == 0) + { + *to = malloc(1); + **to = 0; + return 1; + } + + if (!current_charset) + convert_set_charset(0); + charset = current_charset ? current_charset : "US-ASCII"; + return convert_string("UTF-8", charset, from, to, '?'); +} + +#endif diff --git a/PeerCast.root/PeerCast/core/common/utf8.h b/PeerCast.root/PeerCast/core/common/utf8.h new file mode 100644 index 0000000..f701319 --- /dev/null +++ b/PeerCast.root/PeerCast/core/common/utf8.h @@ -0,0 +1,36 @@ + +/* + * Convert a string between UTF-8 and the locale's charset. + * Invalid bytes are replaced by '#', and characters that are + * not available in the target encoding are replaced by '?'. + * + * If the locale's charset is not set explicitly then it is + * obtained using nl_langinfo(CODESET), where available, the + * environment variable CHARSET, or assumed to be US-ASCII. + * + * Return value of conversion functions: + * + * -1 : memory allocation failed + * 0 : data was converted exactly + * 1 : valid data was converted approximately (using '?') + * 2 : input was invalid (but still converted, using '#') + * 3 : unknown encoding (but still converted, using '?') + */ + +#ifndef __UTF8_H +#define __UTF8_H + +#ifdef __cplusplus +extern "C" { +#endif + +void convert_set_charset(const char *charset); + +int utf8_encode(const char *from, char **to); +int utf8_decode(const char *from, char **to); + +#ifdef __cplusplus +} +#endif + +#endif /* __UTF8_H */ diff --git a/PeerCast.root/PeerCast/core/common/version2.h b/PeerCast.root/PeerCast/core/common/version2.h new file mode 100644 index 0000000..24a45ce --- /dev/null +++ b/PeerCast.root/PeerCast/core/common/version2.h @@ -0,0 +1,53 @@ +// ------------------------------------------------ +// File : version2.h +// Date: 17-june-2005 +// Author: giles +// +// (c) 2005 peercast.org +// ------------------------------------------------ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// ------------------------------------------------ + +#ifndef _VERSION2_H +#define _VERSION2_H + +// ------------------------------------------------ +#ifdef PRIVATE_BROADCASTER +static const char PCP_BROADCAST_FLAGS = 0x01; +static bool PCP_FORCE_YP = true; +#else +static const char PCP_BROADCAST_FLAGS = 0x00; +static bool PCP_FORCE_YP = false; +#endif +// ------------------------------------------------ +static const int PCP_CLIENT_VERSION = 1217; +static const int PCP_CLIENT_VERSION_VP = 23; +static const int PCP_ROOT_VERSION = 1212; + +static const int PCP_CLIENT_MINVERSION = 1200; + +static const char *PCX_AGENT = "PeerCast/0.1217"; +static const char *PCX_AGENTJP = "PeerCast/0.1217-J"; +static const char *PCX_AGENTVP = "PeerCast/0.1217(VP0023)"; +static const char *PCX_VERSTRING = "v0.1217(VP0023)"; + +#if 1 /* for VP extend version */ +#define VERSION_EX 1 +static const char *PCP_CLIENT_VERSION_EX_PREFIX = "IM"; // 2bytes only +static const int PCP_CLIENT_VERSION_EX_NUMBER = 7651; +static const char *PCX_AGENTEX = "PeerCast/0.1217(IM7651)"; +static const char *PCX_VERSTRING_EX = "v0.1217(IM7651)"; +#endif + +// ------------------------------------------------ + + +#endif diff --git a/PeerCast.root/PeerCast/core/common/xml.cpp b/PeerCast.root/PeerCast/core/common/xml.cpp new file mode 100644 index 0000000..19c1035 --- /dev/null +++ b/PeerCast.root/PeerCast/core/common/xml.cpp @@ -0,0 +1,491 @@ +// ------------------------------------------------ +// File : xml.cpp +// Date: 4-apr-2002 +// Author: giles +// Desc: +// Basic XML parsing/creation +// +// (c) 2002 peercast.org +// ------------------------------------------------ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// ------------------------------------------------ + +#include "xml.h" +#include "stream.h" +#include +#include +#ifdef _DEBUG +#include "chkMemoryLeak.h" +#define DEBUG_NEW new(__FILE__, __LINE__) +#define new DEBUG_NEW +#endif + +// ---------------------------------- +void XML::Node::add(Node *n) +{ + if (!n) + return; + + n->parent = this; + + if (child) + { + // has children, add to last sibling + Node *s = child; + while (s->sibling) + s = s->sibling; + s->sibling = n; + + }else{ + // no children yet + child = n; + } +} +// --------------------------------- +inline char nibsToByte(char n1, char n2) +{ + if (n1 >= 'A') n1 = n1-'A'+10; + else n1 = n1-'0'; + if (n2 >= 'A') n2 = n2-'A'+10; + else n2 = n2-'0'; + + return ((n2&0xf)<<4)|(n1&0xf); +} + +// ---------------------------------- +int XML::Node::getBinaryContent(void *ptr, int size) +{ + char *in = contData; + char *out = (char *)ptr; + + int i=0; + while (*in) + { + if (isWhiteSpace(*in)) + { + in++; + }else + { + if (i >= size) + throw StreamException("Too much binary data"); + out[i++] = nibsToByte(in[0],in[1]); + in+=2; + } + } + return i; +} +// ---------------------------------- +void XML::Node::setBinaryContent(void *ptr, int size) +{ + const char hexTable[] = "0123456789ABCDEF"; + const int lineWidth = 1023; + + contData = new char[size*2+1+(size/lineWidth)]; + + char *bp = (char *)ptr; + register char *ap = contData; + + for(register int i=0; i>4)&0xf]; + if ((i&lineWidth)==lineWidth) + *ap++ = '\n'; + } + ap[0] = 0; +} + + +// ---------------------------------- +void XML::Node::setContent(const char *n) +{ + contData = strdup(n); +} +// ---------------------------------- +void XML::Node::setAttributes(const char *n) +{ + char c; + + attrData = strdup(n); + + // count maximum amount of attributes + int maxAttr = 1; // 1 for tag name + bool inQ = false; + int i=0; + while ((c=attrData[i++])!=0) + { + if (c=='\"') + inQ ^= true; + + if (!inQ) + if (c=='=') + maxAttr++; + } + + + attr = new Attribute[maxAttr]; + + attr[0].namePos = 0; + attr[0].valuePos = 0; + + numAttr=1; + + i=0; + + // skip until whitespace + while (c=attrData[i++]) + if (isWhiteSpace(c)) + break; + + if (!c) return; // no values + + attrData[i-1]=0; + + + while ((c=attrData[i])!=0) + { + if (!isWhiteSpace(c)) + { + if (numAttr>=maxAttr) + throw StreamException("Too many attributes"); + + // get start of tag name + attr[numAttr].namePos = i; + + + // skip whitespaces until next '=' + // terminate name on next whitespace or '=' + while (attrData[i]) + { + c = attrData[i++]; + + if ((c == '=') || isWhiteSpace(c)) + { + attrData[i-1] = 0; // null term. name + if (c == '=') + break; + } + } + + // skip whitespaces + while (attrData[i]) + { + if (isWhiteSpace(attrData[i])) + i++; + else + break; + } + + // check for valid start of attribute value - '"' + if (attrData[i++] != '\"') + throw StreamException("Bad tag value"); + + attr[numAttr++].valuePos = i; + + // terminate attribute value at next '"' + + while (attrData[i]) + if (attrData[i++] == '\"') + break; + + attrData[i-1] = 0; // null term. value + + + }else{ + i++; + } + } +} +// ---------------------------------- +XML::Node::Node(const char *fmt,...) +{ + va_list ap; + va_start(ap, fmt); + + char tmp[8192]; + vsprintf(tmp,fmt,ap); + setAttributes(tmp); + + va_end(ap); + init(); +} + +// ---------------------------------- +void XML::Node::init() +{ + parent = sibling = child = NULL; + contData = NULL; + userPtr = NULL; +} +// ---------------------------------- +int XML::Node::findAttrInt(const char *name) +{ + char *v = findAttr(name); + if (!v) return 0; + return atoi(v); +} +// ---------------------------------- +int XML::Node::findAttrID(const char *name) +{ + char *v = findAttr(name); + if (!v) return 0; + return strToID(v); +} +// ---------------------------------- +char *XML::Node::findAttr(const char *name) +{ + int nlen = strlen(name); + for(int i=1; i\n",3); + }else + { + out.write(">\n",2); + + if (contData) + out.write(contData,strlen(contData)); + + if (child) + child->write(out,level+1); +#if 0 + if (level) + out.write(tabs,strlen(tabs)); +#endif + out.write("\n",2); + } + + if (sibling) + sibling->write(out,level); +} +// ---------------------------------- +XML::Node::~Node() +{ +// LOG("delete %s",getName()); + + if (contData) + delete [] contData; + if (attrData) + delete [] attrData; + if (attr) + delete [] attr; + + Node *n = child; + while (n) + { + Node *nn = n->sibling; + delete n; + n = nn; + } +} + + +// ---------------------------------- +XML::~XML() +{ + if (root) + delete root; +} + +// ---------------------------------- +void XML::write(Stream &out) +{ + if (!root) + throw StreamException("No XML root"); + + out.writeLine(""); + root->write(out,1); + +} +// ---------------------------------- +void XML::writeCompact(Stream &out) +{ + if (!root) + throw StreamException("No XML root"); + + out.writeLine(""); + root->write(out,1); + +} +// ---------------------------------- +void XML::writeHTML(Stream &out) +{ + if (!root) + throw StreamException("No XML root"); + + root->write(out,1); +} + +// ---------------------------------- +void XML::setRoot(Node *n) +{ + root=n; +} + + +// ---------------------------------- +XML::Node *XML::findNode(const char *n) +{ + if (root) + return root->findNode(n); + else + return NULL; +} + + +// ---------------------------------- +XML::Node *XML::Node::findNode(const char *name) +{ + if (stricmp(getName(),name)==0) + return this; + + XML::Node *c = child; + + while (c) + { + XML::Node *fn = c->findNode(name); + if (fn) + return fn; + c=c->sibling; + } + + return NULL; +} + +// ---------------------------------- +void XML::read(Stream &in) +{ + const int BUFFER_LEN = 100*1024; + static char buf[BUFFER_LEN]; + + Node *currNode=NULL; + int tp=0; + + while (!in.eof()) + { + char c = in.readChar(); + + if (c == '<') + { + if (tp && currNode) // check for content + { + buf[tp] = 0; + currNode->setContent(buf); + } + tp = 0; + + // read to next '>' + while (!in.eof()) + { + c = in.readChar(); + if (c == '>') + break; + + if (tp >= BUFFER_LEN) + throw StreamException("Tag too long"); + + buf[tp++] = c; + } + buf[tp]=0; + + if (buf[0] == '!') // comment + { + // do nothing + }else if (buf[0] == '?') // doc type + { + if (strnicmp(&buf[1],"xml ",4)) + throw StreamException("Not XML document"); + }else if (buf[0] == '/') // end tag + { + if (!currNode) + throw StreamException("Unexpected end tag"); + currNode = currNode->parent; + }else // new tag + { + //LOG("tag: %s",buf); + + bool singleTag = false; + + if (buf[tp-1] == '/') // check for single tag + { + singleTag = true; + buf[tp-1] = 0; + } + + // only add valid tags + if (strlen(buf)) + { + Node *n = new Node(buf); + + if (currNode) + currNode->add(n); + else + setRoot(n); + + if (!singleTag) + currNode = n; + } + } + + tp = 0; + } else { + + if (tp >= BUFFER_LEN) + throw StreamException("Content too big"); + + buf[tp++] = c; + + } + } +} + diff --git a/PeerCast.root/PeerCast/core/common/xml.h b/PeerCast.root/PeerCast/core/common/xml.h new file mode 100644 index 0000000..df157a4 --- /dev/null +++ b/PeerCast.root/PeerCast/core/common/xml.h @@ -0,0 +1,92 @@ +// ------------------------------------------------ +// File : xml.h +// Date: 4-apr-2002 +// Author: giles +// Desc: +// +// (c) 2002 peercast.org +// ------------------------------------------------ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// ------------------------------------------------ + +#ifndef _XML_H +#define _XML_H + +//----------------------- +#include "common.h" +#include + +//----------------------- +class Stream; + +//----------------------- +class XML +{ +public: + class Node + { + public: + class Attribute + { + public: + int namePos,valuePos; + }; + + Node(const char *,...); + + void init(); + + ~Node(); + + void add(Node *); + void write(Stream &,int); // output, level + char *getName() {return getAttrName(0);} + + char *getAttrValue(int i) {return &attrData[attr[i].valuePos];} + char *getAttrName(int i) {return &attrData[attr[i].namePos];} + char *getContent() {return contData; } + int getBinaryContent(void *, int); + + void setAttributes(const char *); + void setContent(const char *); + void setBinaryContent(void *, int); + + Node *findNode(const char *); + char *findAttr(const char *); + int findAttrInt(const char *); + int findAttrID(const char *); + + char *contData,*attrData; + + Attribute *attr; + int numAttr; + + Node *child,*parent,*sibling; + void *userPtr; + }; + + XML() + { + root = NULL; + } + + ~XML(); + + void setRoot(Node *n); + void write(Stream &); + void writeCompact(Stream &); + void writeHTML(Stream &); + void read(Stream &); + Node *findNode(const char *n); + + Node *root; +}; +#endif diff --git a/PeerCast.root/PeerCast/core/win32/lib/corelib.vcproj b/PeerCast.root/PeerCast/core/win32/lib/corelib.vcproj new file mode 100644 index 0000000..6f7743e --- /dev/null +++ b/PeerCast.root/PeerCast/core/win32/lib/corelib.vcproj @@ -0,0 +1,1573 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/PeerCast.root/PeerCast/core/win32/lib/corelib.vcproj.vspscc b/PeerCast.root/PeerCast/core/win32/lib/corelib.vcproj.vspscc new file mode 100644 index 0000000..16d4a14 --- /dev/null +++ b/PeerCast.root/PeerCast/core/win32/lib/corelib.vcproj.vspscc @@ -0,0 +1,10 @@ +"" +{ +"FILE_VERSION" = "9237" +"ENLISTMENT_CHOICE" = "NEVER" +"PROJECT_FILE_RELATIVE_PATH" = "relative:core\\win32\\lib" +"NUMBER_OF_EXCLUDED_FILES" = "0" +"ORIGINAL_PROJECT_FILE_PATH" = "" +"NUMBER_OF_NESTED_PROJECTS" = "0" +"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROJECT" +} diff --git a/PeerCast.root/PeerCast/core/win32/wsocket.cpp b/PeerCast.root/PeerCast/core/win32/wsocket.cpp new file mode 100644 index 0000000..5b03e4c --- /dev/null +++ b/PeerCast.root/PeerCast/core/win32/wsocket.cpp @@ -0,0 +1,675 @@ +// ------------------------------------------------ +// File : wsocket.cpp +// Date: 4-apr-2002 +// Author: giles +// Desc: +// Windows version of ClientSocket. Handles the nitty gritty of actually +// reading and writing TCP +// +// (c) 2002 peercast.org +// ------------------------------------------------ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// ------------------------------------------------ + +// TODO: fix socket closing + + +//#include "stdafx.h" +//#include "winsock2.h" +#include +#include +#include "wsocket.h" +#include "stats.h" +#ifdef _DEBUG +#include "chkMemoryLeak.h" +#define DEBUG_NEW new(__FILE__, __LINE__) +#define new DEBUG_NEW +#endif + + +// -------------------------------------------------- +void WSAClientSocket::init() +{ + WORD wVersionRequested; + WSADATA wsaData; + int err; + + wVersionRequested = MAKEWORD( 2, 0 ); + err = WSAStartup( wVersionRequested, &wsaData ); + if ( err != 0 ) + throw SockException("Unable to init sockets"); + + //LOG4("WSAStartup: OK"); + +} +// -------------------------------------------------- +bool ClientSocket::getHostname(char *str,unsigned int ip) +{ + HOSTENT *he; + + ip = htonl(ip); + + he = gethostbyaddr((char *)&ip,sizeof(ip),AF_INET); + + if (he) + { + strcpy(str,he->h_name); + return true; + }else + return false; +} + +unsigned int cache_ip = 0; +unsigned int cache_time = 0; + +// -------------------------------------------------- +unsigned int ClientSocket::getIP(char *name) +{ + unsigned int ctime = sys->getTime(); + bool null_flg = (name == NULL); + + if (null_flg){ + if ((cache_time != 0) && (cache_time + 60 > ctime)){ + return cache_ip; + } else { + cache_time = 0; + cache_ip = 0; + } + } + + char szHostName[256]; + + if (!name) + { + if (gethostname(szHostName, sizeof(szHostName))==0) + name = szHostName; + else + return 0; + } + + HOSTENT *he = WSAClientSocket::resolveHost(name); + + if (!he) + return 0; + + + LPSTR lpAddr = he->h_addr_list[0]; + if (lpAddr) + { + unsigned int ret; + struct in_addr inAddr; + memmove (&inAddr, lpAddr, 4); + + ret = inAddr.S_un.S_un_b.s_b1<<24 | + inAddr.S_un.S_un_b.s_b2<<16 | + inAddr.S_un.S_un_b.s_b3<<8 | + inAddr.S_un.S_un_b.s_b4; + + if (null_flg){ + cache_ip = ret; + cache_time = ctime; + } + return ret; + } + return 0; +} +// -------------------------------------------------- +void WSAClientSocket::setLinger(int sec) +{ + linger linger; + linger.l_onoff = (sec>0)?1:0; + linger.l_linger = sec; + + if (setsockopt(sockNum, SOL_SOCKET, SO_LINGER, (const char *)&linger, sizeof (linger)) == -1) + throw SockException("Unable to set LINGER"); +} + +// -------------------------------------------------- +void WSAClientSocket::setBlocking(bool yes) +{ + unsigned long op = yes ? 0 : 1; + if (ioctlsocket(sockNum, FIONBIO, &op) == SOCKET_ERROR) + throw SockException("Can`t set blocking"); +} +// -------------------------------------------------- +void WSAClientSocket::setNagle(bool on) +{ + int nodelay = (on==false); + if (setsockopt(sockNum, SOL_SOCKET, TCP_NODELAY, (char *)&nodelay, sizeof nodelay) == -1) + throw SockException("Unable to set NODELAY"); + +} + +// -------------------------------------------------- +void WSAClientSocket::setReuse(bool yes) +{ + unsigned long op = yes ? 1 : 0; + if (setsockopt(sockNum,SOL_SOCKET,SO_REUSEADDR,(char *)&op,sizeof(unsigned long)) == -1) + throw SockException("Unable to set REUSE"); +} + +// -------------------------------------------------- +void WSAClientSocket::setBufSize(int size) +{ + int oldop; + int op = size; + int len = sizeof(op); + if (getsockopt(sockNum,SOL_SOCKET,SO_RCVBUF,(char *)&oldop,&len) == -1) { + LOG_DEBUG("Unable to get RCVBUF"); + } else if (oldop < size) { + if (setsockopt(sockNum,SOL_SOCKET,SO_RCVBUF,(char *)&op,len) == -1) + LOG_DEBUG("Unable to set RCVBUF"); + //else + // LOG_DEBUG("*** recvbufsize:%d -> %d", oldop, op); + } + + if (getsockopt(sockNum,SOL_SOCKET,SO_SNDBUF,(char *)&oldop,&len) == -1) { + LOG_DEBUG("Unable to get SNDBUF"); + } else if (oldop < size) { + if (setsockopt(sockNum,SOL_SOCKET,SO_SNDBUF,(char *)&op,len) == -1) + LOG_DEBUG("Unable to set SNDBUF"); + //else + // LOG_DEBUG("*** sendbufsize: %d -> %d", oldop, op); + } +} + +// -------------------------------------------------- +HOSTENT *WSAClientSocket::resolveHost(const char *hostName) +{ + HOSTENT *he; + + if ((he = gethostbyname(hostName)) == NULL) + { + // if failed, try using gethostbyaddr instead + + unsigned long ip = inet_addr(hostName); + + if (ip == INADDR_NONE) + return NULL; + + if ((he = gethostbyaddr((char *)&ip,sizeof(ip),AF_INET)) == NULL) + return NULL; + } + return he; +} + +// -------------------------------------------------- +void WSAClientSocket::open(Host &rh) +{ + sockNum = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); + + if (sockNum == INVALID_SOCKET) + throw SockException("Can`t open socket"); + + setBlocking(false); +#ifdef DISABLE_NAGLE + setNagle(false); +#endif + setBufSize(65535); + + host = rh; + + memset(&remoteAddr,0,sizeof(remoteAddr)); + + remoteAddr.sin_family = AF_INET; + remoteAddr.sin_port = htons(host.port); + remoteAddr.sin_addr.S_un.S_addr = htonl(host.ip); + +} +// -------------------------------------------------- +void WSAClientSocket::checkTimeout(bool r, bool w) +{ + int err = WSAGetLastError(); + if (err == WSAEWOULDBLOCK) + { + + timeval timeout; + fd_set read_fds; + fd_set write_fds; + + timeout.tv_sec = 0; + timeout.tv_usec = 0; + + FD_ZERO (&write_fds); + if (w) + { + timeout.tv_sec = (int)this->writeTimeout/1000; + FD_SET (sockNum, &write_fds); + } + + FD_ZERO (&read_fds); + if (r) + { + timeout.tv_sec = (int)this->readTimeout/1000; + FD_SET (sockNum, &read_fds); + } + + timeval *tp; + if (timeout.tv_sec) + tp = &timeout; + else + tp = NULL; + + + int r=select (NULL, &read_fds, &write_fds, NULL, tp); + + if (r == 0) + throw TimeoutException(); + else if (r == SOCKET_ERROR) + throw SockException("select failed."); + + }else{ + char str[32]; + sprintf(str,"%d",err); + throw SockException(str); + } +} + +// -------------------------------------------------- +void WSAClientSocket::checkTimeout2(bool r, bool w) +{ + { + + timeval timeout; + fd_set read_fds; + fd_set write_fds; + + timeout.tv_sec = 0; + timeout.tv_usec = 0; + + FD_ZERO (&write_fds); + if (w) + { + timeout.tv_sec = (int)this->writeTimeout/1000; + FD_SET (sockNum, &write_fds); + } + + FD_ZERO (&read_fds); + if (r) + { + timeout.tv_sec = (int)this->readTimeout/1000; + FD_SET (sockNum, &read_fds); + } + + timeval *tp; + if (timeout.tv_sec) + tp = &timeout; + else + tp = NULL; + + + int r=select (NULL, &read_fds, &write_fds, NULL, tp); + + if (r == 0) + throw TimeoutException(); + else if (r == SOCKET_ERROR) + throw SockException("select failed."); + } +} + +// -------------------------------------------------- +Host WSAClientSocket::getLocalHost() +{ + struct sockaddr_in localAddr; + + int len = sizeof(localAddr); + if (getsockname(sockNum, (sockaddr *)&localAddr, &len) == 0) + return Host(SWAP4(localAddr.sin_addr.s_addr),0); + else + return Host(0,0); +} + +// -------------------------------------------------- +void WSAClientSocket::connect() +{ + if (::connect(sockNum,(struct sockaddr *)&remoteAddr,sizeof(remoteAddr)) == SOCKET_ERROR) + checkTimeout(false,true); + +} +// -------------------------------------------------- +int WSAClientSocket::read(void *p, int l) +{ + int bytesRead=0; + + while (l) + { + if (rbDataSize >= l) { + memcpy(p, &apReadBuf[rbPos], l); + rbPos += l; + rbDataSize -= l; + return l; + } else if (rbDataSize > 0) { + memcpy(p, &apReadBuf[rbPos], rbDataSize); + p = (char *) p + rbDataSize; + l -= rbDataSize; + bytesRead += rbDataSize; + } + + rbPos = 0; + rbDataSize = 0; + //int r = recv(sockNum, (char *)p, l, 0); + int r = recv(sockNum, apReadBuf, RBSIZE, 0); + if (r == SOCKET_ERROR) + { + // non-blocking sockets always fall through to here + checkTimeout(true,false); + + }else if (r == 0) + { + throw EOFException("Closed on read"); + + }else + { + stats.add(Stats::BYTESIN,r); + if (host.localIP()) + stats.add(Stats::LOCALBYTESIN,r); + updateTotals(r,0); + //bytesRead += r; + //l -= r; + //p = (char *)p+r; + + rbDataSize += r; + } + } + return bytesRead; +} +// -------------------------------------------------- +int WSAClientSocket::readUpto(void *p, int l) +{ + int bytesRead=0; + while (l) + { + int r = recv(sockNum, (char *)p, l, 0); + if (r == SOCKET_ERROR) + { + // non-blocking sockets always fall through to here + //checkTimeout(true,false); + return r; + + }else if (r == 0) + { + break; + }else + { + stats.add(Stats::BYTESIN,r); + if (host.localIP()) + stats.add(Stats::LOCALBYTESIN,r); + updateTotals(r,0); + bytesRead += r; + l -= r; + p = (char *)p+r; + } + if (bytesRead) break; + } + return bytesRead; +} + + +// -------------------------------------------------- +void WSAClientSocket::write(const void *p, int l) +{ + while (l) + { + int r = send(sockNum, (char *)p, l, 0); + if (r == SOCKET_ERROR) + { + checkTimeout(false,true); + } + else if (r == 0) + { + throw SockException("Closed on write"); + } + else + if (r > 0) + { + stats.add(Stats::BYTESOUT,r); + if (host.localIP()) + stats.add(Stats::LOCALBYTESOUT,r); + + updateTotals(0,r); + l -= r; + p = (char *)p+r; + } + } +} + +// -------------------------------------------------- +void WSAClientSocket::bufferingWrite(const void *p, int l) +{ + if (bufList.isNull() && p != NULL){ + while(l){ + int r = send(sockNum, (char *)p, l, 0); + if (r == SOCKET_ERROR){ + int err = WSAGetLastError(); + if (err == WSAEWOULDBLOCK){ + bufList.add(p, l); +// LOG_DEBUG("normal add"); + break; + } else { + char str[32]; + sprintf(str,"%d",err); + throw SockException(str); + } + } else if (r == 0) { + throw SockException("Closed on write"); + } else if (r > 0){ + stats.add(Stats::BYTESOUT,r); + if (host.localIP()) + stats.add(Stats::LOCALBYTESOUT,r); + + updateTotals(0,r); + l -= r; + p = (char *)p+r; + } + } + } else { +// LOG_DEBUG("***************BufferingWrite"); + if (p) + bufList.add(p,l); + + bool flg = true; + + while(flg){ + SocketBuffer *tmp; + tmp = bufList.getTop(); + + if (tmp){ +// LOG_DEBUG("tmp->pos = %d, tmp->len = %d, %d", tmp->pos, tmp->len, tmp); + while(tmp->pos < tmp->len){ + int r = send(sockNum, (char*)(tmp->buf + tmp->pos), tmp->len - tmp->pos, 0); +// LOG_DEBUG("send = %d", r); + if (r == SOCKET_ERROR){ + int err = WSAGetLastError(); + if (err == WSAEWOULDBLOCK){ + flg = false; + break; + } else { + bufList.clear(); + char str[32]; + sprintf(str,"%d",err); + throw SockException(str); + } + } else if (r == 0){ + bufList.clear(); + throw SockException("Closed on write"); + } else if (r > 0){ + stats.add(Stats::BYTESOUT,r); + if (host.localIP()) + stats.add(Stats::LOCALBYTESOUT,r); + + updateTotals(0,r); + + tmp->pos += r; + if (tmp->pos >= tmp->len){ +// LOG_DEBUG("deleteTop"); + bufList.deleteTop(); + break; + } + } + } + } else { + flg = false; + } + } +// LOG_DEBUG("bufferingWrite end"); + } +} + +// -------------------------------------------------- +void WSAClientSocket::checkBuffering(bool r, bool w) +{ + int err = WSAGetLastError(); + if (err == WSAEWOULDBLOCK) + { + + timeval timeout; + fd_set read_fds; + fd_set write_fds; + + timeout.tv_sec = 0; + timeout.tv_usec = 0; + + FD_ZERO (&write_fds); + if (w) + { + timeout.tv_sec = (int)this->writeTimeout/1000; + FD_SET (sockNum, &write_fds); + } + + FD_ZERO (&read_fds); + if (r) + { + timeout.tv_sec = (int)this->readTimeout/1000; + FD_SET (sockNum, &read_fds); + } + + timeval *tp; + if (timeout.tv_sec) + tp = &timeout; + else + tp = NULL; + + + int r=select (NULL, &read_fds, &write_fds, NULL, tp); + + if (r == 0) + throw TimeoutException(); + else if (r == SOCKET_ERROR) + throw SockException("select failed."); + + }else{ + char str[32]; + sprintf(str,"%d",err); + throw SockException(str); + } +} + +// -------------------------------------------------- +void WSAClientSocket::bind(Host &h) +{ + struct sockaddr_in localAddr; + + if ((sockNum = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) + throw SockException("Can`t open socket"); + + setBlocking(false); + setReuse(true); + + memset(&localAddr,0,sizeof(localAddr)); + localAddr.sin_family = AF_INET; + localAddr.sin_port = htons(h.port); + localAddr.sin_addr.s_addr = INADDR_ANY; + + if( ::bind (sockNum, (sockaddr *)&localAddr, sizeof(localAddr)) == -1) + throw SockException("Can`t bind socket"); + + if (::listen(sockNum,SOMAXCONN)) + throw SockException("Can`t listen",WSAGetLastError()); + + host = h; +} +// -------------------------------------------------- +ClientSocket *WSAClientSocket::accept() +{ + + int fromSize = sizeof(sockaddr_in); + sockaddr_in from; + + int conSock = ::accept(sockNum,(sockaddr *)&from,&fromSize); + + + if (conSock == INVALID_SOCKET) + return NULL; + + + WSAClientSocket *cs = new WSAClientSocket(); + cs->sockNum = conSock; + + cs->host.port = from.sin_port; + cs->host.ip = from.sin_addr.S_un.S_un_b.s_b1<<24 | + from.sin_addr.S_un.S_un_b.s_b2<<16 | + from.sin_addr.S_un.S_un_b.s_b3<<8 | + from.sin_addr.S_un.S_un_b.s_b4; + + + cs->setBlocking(false); +#ifdef DISABLE_NAGLE + cs->setNagle(false); +#endif + cs->setBufSize(65535); + + return cs; +} + +// -------------------------------------------------- +void WSAClientSocket::close() +{ + sockLock.on(); + if (sockNum) + { +// shutdown(sockNum,SD_SEND); + + setReadTimeout(2000); + unsigned int stime = sys->getTime(); + try + { + char c[1024]; + while (readUpto(&c,1024) > 0) + if (sys->getTime() - stime > 5) break; + //readUpto(&c,1); + }catch(StreamException &) {} + + if (closesocket (sockNum)) + LOG_ERROR("closesocket() error"); + + + sockNum=0; + } + sockLock.off(); +} + +// -------------------------------------------------- +bool WSAClientSocket::readReady() +{ + if (rbDataSize) return true; + + timeval timeout; + fd_set read_fds; + + timeout.tv_sec = 0; + timeout.tv_usec = 0; + + FD_ZERO (&read_fds); + FD_SET (sockNum, &read_fds); + + return select (sockNum+1, &read_fds, NULL, NULL, &timeout) == 1; +} + diff --git a/PeerCast.root/PeerCast/core/win32/wsocket.h b/PeerCast.root/PeerCast/core/win32/wsocket.h new file mode 100644 index 0000000..fdf4055 --- /dev/null +++ b/PeerCast.root/PeerCast/core/win32/wsocket.h @@ -0,0 +1,86 @@ +// ------------------------------------------------ +// File : wsocket.h +// Date: 4-apr-2002 +// Author: giles +// Desc: +// see .cpp for details +// +// (c) 2002 peercast.org +// ------------------------------------------------ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// ------------------------------------------------ + +#ifndef _WSOCKET_H +#define _WSOCKET_H + +#include +#include "socket.h" +//#include "winsock2.h" + + +// -------------------------------------------------- +class WSAClientSocket : public ClientSocket +{ +public: + static void init(); + + WSAClientSocket() + :sockNum(0) + ,writeCnt(0) + ,rbPos(0) + ,rbDataSize(0) + { + } + + ~WSAClientSocket(){ + bufList.clear(); + } + + virtual void open(Host &); + virtual int read(void *, int); + virtual int readUpto(void *, int); + virtual void write(const void *, int); + virtual void bind(Host &); + virtual void connect(); + virtual void close(); + virtual ClientSocket * accept(); + virtual bool active() {return sockNum != 0;} + virtual bool readReady(); + virtual Host getLocalHost(); + virtual void setBlocking(bool); + void setReuse(bool); + void setNagle(bool); + void setLinger(int); + void setBufSize(int size); + +// static HOSTENT *resolveHost(const char *); + static hostent *resolveHost(const char *); + + void checkTimeout(bool,bool); + void checkTimeout2(bool,bool); + + virtual void bufferingWrite(const void*, int); + void checkBuffering(bool, bool); + + unsigned int writeCnt; + unsigned int sockNum; + struct sockaddr_in remoteAddr; + + enum {RBSIZE = 8192}; + char apReadBuf[RBSIZE]; + int rbPos; + int rbDataSize; + + WLock sockLock; +}; + +#endif + \ No newline at end of file diff --git a/PeerCast.root/PeerCast/core/win32/wsys.cpp b/PeerCast.root/PeerCast/core/win32/wsys.cpp new file mode 100644 index 0000000..9ed1fcf --- /dev/null +++ b/PeerCast.root/PeerCast/core/win32/wsys.cpp @@ -0,0 +1,150 @@ +// ------------------------------------------------ +// File : wsys.cpp +// Date: 4-apr-2002 +// Author: giles +// Desc: +// WSys derives from Sys to provide basic win32 functions such as starting threads. +// +// (c) 2002 peercast.org +// ------------------------------------------------ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// ------------------------------------------------ + + +//#include "stdafx.h" +#include +#include +#include +#include "win32/wsys.h" +#include "win32/wsocket.h" +#include "stats.h" +#include "peercast.h" +#include +#include +#include "shellapi.h" +#ifdef _DEBUG +#include "chkMemoryLeak.h" +#define DEBUG_NEW new(__FILE__, __LINE__) +#define new DEBUG_NEW +#endif + +// --------------------------------- +WSys::WSys(HWND w) +{ + stats.clear(); + + rndGen.setSeed(getTime()); + + mainWindow = w; + WSAClientSocket::init(); + + rndSeed = rnd(); +} +// --------------------------------- +double WSys::getDTime() +{ + struct _timeb timebuffer; + + _ftime( &timebuffer ); + + return (double)timebuffer.time+(((double)timebuffer.millitm)/1000); +} +// --------------------------------- +unsigned int WSys::getTime() +{ + time_t ltime; + time( <ime ); + return ltime; +} + +// --------------------------------- +ClientSocket *WSys::createSocket() +{ + return new WSAClientSocket(); +} +// --------------------------------- +void WSys::endThread(ThreadInfo *info) +{ +} +// --------------------------------- +void WSys::waitThread(ThreadInfo *info, int timeout) +{ + switch(WaitForSingleObject((void *)info->handle, timeout)) + { + case WAIT_TIMEOUT: + throw TimeoutException(); + break; + } +} + + +// --------------------------------- +bool WSys::startThread(ThreadInfo *info) +{ + info->active = true; + +/* typedef unsigned ( __stdcall *start_address )( void * ); + + unsigned int threadID; + info->handle = (unsigned int)_beginthreadex( NULL, 0, (start_address)info->func, info, 0, &threadID ); + + if(info->handle == 0) + return false;*/ + + typedef void (__cdecl *start_address)( void * ); + info->handle = _beginthread((start_address)info->func, 0,info); + + if(info->handle == -1) + return false; + + return true; + +} +// --------------------------------- +void WSys::sleep(int ms) +{ + Sleep(ms); +} + +// --------------------------------- +void WSys::appMsg(long msg, long arg) +{ + //SendMessage(mainWindow,WM_USER,(WPARAM)msg,(LPARAM)arg); +} + +// -------------------------------------------------- +void WSys::callLocalURL(const char *str,int port) +{ + char cmd[512]; + sprintf(cmd,"http://localhost:%d/%s",port,str); + ShellExecute(mainWindow, NULL, cmd, NULL, NULL, SW_SHOWNORMAL); +} + +// --------------------------------- +void WSys::getURL(const char *url) +{ + if (mainWindow) + if (strnicmp(url,"http://",7) || strnicmp(url,"mailto:",7)) + ShellExecute(mainWindow, NULL, url, NULL, NULL, SW_SHOWNORMAL); +} +// --------------------------------- +void WSys::exit() +{ + if (mainWindow) + PostMessage(mainWindow,WM_CLOSE,0,0); + else + ::exit(0); +} +// -------------------------------------------------- +void WSys::executeFile(const char *file) +{ + ShellExecute(NULL,"open",file,NULL,NULL,SW_SHOWNORMAL); +} diff --git a/PeerCast.root/PeerCast/core/win32/wsys.h b/PeerCast.root/PeerCast/core/win32/wsys.h new file mode 100644 index 0000000..95f479a --- /dev/null +++ b/PeerCast.root/PeerCast/core/win32/wsys.h @@ -0,0 +1,61 @@ +// ------------------------------------------------ +// File : wsys.h +// Date: 4-apr-2002 +// Author: giles +// Desc: +// WSys derives from Sys to provide basic win32 functions such as starting threads. +// +// (c) 2002 peercast.org +// ------------------------------------------------ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// ------------------------------------------------ + + + +#ifndef _WSYS_H +#define _WSYS_H +// ------------------------------------ +#include +#include "socket.h" +#include "sys.h" + +// ------------------------------------ +class WSys : public Sys +{ +public: + WSys(HWND); + + virtual ClientSocket *createSocket(); + virtual bool startThread(ThreadInfo *); + virtual void sleep(int ); + virtual void appMsg(long,long); + virtual unsigned int getTime(); + virtual double getDTime(); + virtual unsigned int rnd() {return rndGen.next();} + virtual void getURL(const char *); + virtual void exit(); + virtual bool hasGUI() {return mainWindow!=NULL;} + virtual void callLocalURL(const char *str,int port); + virtual void executeFile(const char *); + virtual void endThread(ThreadInfo *); + virtual void waitThread(ThreadInfo *, int timeout = 30000); + + + HWND mainWindow; + peercast::Random rndGen; +}; + + +// ------------------------------------ +#endif + + + \ No newline at end of file diff --git a/PeerCast.root/PeerCast/ui/win32/PeerCast.sln b/PeerCast.root/PeerCast/ui/win32/PeerCast.sln new file mode 100644 index 0000000..9768be1 --- /dev/null +++ b/PeerCast.root/PeerCast/ui/win32/PeerCast.sln @@ -0,0 +1,49 @@ + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "corelib", "..\..\core\win32\lib\corelib.vcproj", "{7BCFE65B-8757-45F3-8DFB-1E7D683950D1}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Simple", "simple\Simple.vcproj", "{7D4833CE-1286-4587-9470-52E098B29C12}" +EndProject +Global + GlobalSection(SourceCodeControl) = preSolution + SccNumberOfProjects = 3 + SccProjectName0 = \u0022$/PeerCast.root/PeerCast\u0022,\u0020JCAAAAAA + SccLocalPath0 = ..\\.. + SccProvider0 = MSSCCI:Microsoft\u0020Visual\u0020SourceSafe + SccProjectFilePathRelativizedFromConnection0 = ui\\win32\\ + SccProjectUniqueName1 = ..\\..\\core\\win32\\lib\\corelib.vcproj + SccLocalPath1 = ..\\.. + SccProjectFilePathRelativizedFromConnection1 = core\\win32\\lib\\ + SccProjectUniqueName2 = simple\\Simple.vcproj + SccLocalPath2 = ..\\.. + SccProjectFilePathRelativizedFromConnection2 = ui\\win32\\simple\\ + EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Private Debug|Win32 = Private Debug|Win32 + Private Release|Win32 = Private Release|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {7BCFE65B-8757-45F3-8DFB-1E7D683950D1}.Debug|Win32.ActiveCfg = Debug|Win32 + {7BCFE65B-8757-45F3-8DFB-1E7D683950D1}.Debug|Win32.Build.0 = Debug|Win32 + {7BCFE65B-8757-45F3-8DFB-1E7D683950D1}.Private Debug|Win32.ActiveCfg = Private Debug|Win32 + {7BCFE65B-8757-45F3-8DFB-1E7D683950D1}.Private Debug|Win32.Build.0 = Private Debug|Win32 + {7BCFE65B-8757-45F3-8DFB-1E7D683950D1}.Private Release|Win32.ActiveCfg = Private Release|Win32 + {7BCFE65B-8757-45F3-8DFB-1E7D683950D1}.Private Release|Win32.Build.0 = Private Release|Win32 + {7BCFE65B-8757-45F3-8DFB-1E7D683950D1}.Release|Win32.ActiveCfg = Release|Win32 + {7BCFE65B-8757-45F3-8DFB-1E7D683950D1}.Release|Win32.Build.0 = Release|Win32 + {7D4833CE-1286-4587-9470-52E098B29C12}.Debug|Win32.ActiveCfg = Debug|Win32 + {7D4833CE-1286-4587-9470-52E098B29C12}.Debug|Win32.Build.0 = Debug|Win32 + {7D4833CE-1286-4587-9470-52E098B29C12}.Private Debug|Win32.ActiveCfg = Private Debug|Win32 + {7D4833CE-1286-4587-9470-52E098B29C12}.Private Debug|Win32.Build.0 = Private Debug|Win32 + {7D4833CE-1286-4587-9470-52E098B29C12}.Private Release|Win32.ActiveCfg = Private Release|Win32 + {7D4833CE-1286-4587-9470-52E098B29C12}.Private Release|Win32.Build.0 = Private Release|Win32 + {7D4833CE-1286-4587-9470-52E098B29C12}.Release|Win32.ActiveCfg = Release|Win32 + {7D4833CE-1286-4587-9470-52E098B29C12}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/PeerCast.root/PeerCast/ui/win32/PeerCast.vsscc b/PeerCast.root/PeerCast/ui/win32/PeerCast.vsscc new file mode 100644 index 0000000000000000000000000000000000000000..51e2532bd4dcd18ab95de08486939f4f14bc5f60 GIT binary patch literal 26 gcmezW&x;|Ep_0LXp_Cz$A%>wGNaisZGZ--d0BiULKL7v# literal 0 HcmV?d00001 diff --git a/PeerCast.root/PeerCast/ui/win32/PeerCast.vssscc b/PeerCast.root/PeerCast/ui/win32/PeerCast.vssscc new file mode 100644 index 0000000..e957f02 --- /dev/null +++ b/PeerCast.root/PeerCast/ui/win32/PeerCast.vssscc @@ -0,0 +1,10 @@ +"" +{ +"FILE_VERSION" = "9237" +"ENLISTMENT_CHOICE" = "NEVER" +"PROJECT_FILE_RELATIVE_PATH" = "relative:ui\\win32" +"NUMBER_OF_EXCLUDED_FILES" = "0" +"ORIGINAL_PROJECT_FILE_PATH" = "" +"NUMBER_OF_NESTED_PROJECTS" = "0" +"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROJECT" +} diff --git a/PeerCast.root/PeerCast/ui/win32/simple/SMALL.ICO b/PeerCast.root/PeerCast/ui/win32/simple/SMALL.ICO new file mode 100644 index 0000000000000000000000000000000000000000..c7dee299bec9d38ea44c45432b48fd10214e226c GIT binary patch literal 318 zcmZvYF%H5o3`Kt>Br|qmX5@I;!bUd6UMbw95*I*XXpvCObJ}h=dH*|(6Gf3aM&I{} zxOCDf9HMfDP6t$~P5()em?~v8loX0;t!#Lka*qrcQ3{bPgh;8`zO*&5gd*>1DL6F1z|v;;aqRdUw9l6_GaIu9mVEp76a%Gaif|-c9RHB_Cmi1)Tr! J2Rz{|{Q%s#L@@vW literal 0 HcmV?d00001 diff --git a/PeerCast.root/PeerCast/ui/win32/simple/Simple.ICO b/PeerCast.root/PeerCast/ui/win32/simple/Simple.ICO new file mode 100644 index 0000000000000000000000000000000000000000..51811ea4819dbdb4726fbb0f5f4347425ca2a566 GIT binary patch literal 1078 zcma)6v2KGv41F|}%+&G+WvcQQ?I*Eaww%-}Ol7KSw$g}-y zpYJeMfDBJ4%L2B3o`84iqDXw30WTY1OJ7NR5*eN;fyms)D>BGPj7d?_BqG|jWkCH0 zRkH{_<}%?+!emUULbY@(xj+`-HLq6jb-61~$6mL)KZLYhs1f+s3L)(310e1N^180| z#`A{nqD-CQPKVu+_r_sW;qksUE-UU=_xNG3xZNS;hl#U9?#G={oYEa3Vs4XEtia=D z&N_|SK?Yxv8^3E~RWG^N#qQ#6U$c#M?IvU=1!iUXyL6pQi=Pm8WD^8c- zd^5phG#AA`=6vo(mAW=lNrqI^6am5swC?jGyKZz~tl}5!Pc|<}Lw4Fn+bd0Yi1o;Ujh literal 0 HcmV?d00001 diff --git a/PeerCast.root/PeerCast/ui/win32/simple/Simple.cpp b/PeerCast.root/PeerCast/ui/win32/simple/Simple.cpp new file mode 100644 index 0000000..928ceee --- /dev/null +++ b/PeerCast.root/PeerCast/ui/win32/simple/Simple.cpp @@ -0,0 +1,1437 @@ +// ------------------------------------------------ +// File : simple.cpp +// Date: 4-apr-2002 +// Author: giles +// Desc: +// Simple tray icon interface to PeerCast, mostly win32 related stuff. +// +// (c) 2002 peercast.org +// ------------------------------------------------ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// ------------------------------------------------ + +#include +#include +#include "stdafx.h" +#include "resource.h" +#include "gui.h" +#include "channel.h" +#include "servent.h" +#include "servmgr.h" +#include "win32/wsys.h" +#include "peercast.h" +#include "simple.h" +#include "version2.h" +#include "gdiplus.h" +#include "time.h" +#ifdef _DEBUG +#include "chkMemoryLeak.h" +#define DEBUG_NEW new(__FILE__, __LINE__) +#define new DEBUG_NEW +#endif + +#define MAX_LOADSTRING 100 + +#define PLAY_CMD 7000 +#define RELAY_CMD 8000 +#define INFO_CMD 9000 +#define URL_CMD 10000 + +#define MAX_CHANNELS 999 + + +extern "C" +{ + void loadIcons(HINSTANCE hInstance, HWND hWnd); +}; + +UINT g_iTaskbarCreated = ~0; // for PCRaw (tray icon) + +// PeerCast globals + +static int currNotify=0; +String iniFileName; +HWND guiWnd; +HWND mainWnd; +static HMENU trayMenu = NULL,ltrayMenu = NULL; // for PCRaw (tray icon) +bool showGUI=true; +bool allowMulti=false; +bool killMe=false; +bool allowTrayMenu=true; +static bool winDistinctionNT=false; +int seenNewVersionTime=0; +HICON icon1,icon2; +ChanInfo chanInfo; +bool chanInfoIsRelayed; +//GnuID lastPlayID; +String exePath; +ULONG_PTR gdiplusToken; + +// --------------------------------- +Sys * APICALL MyPeercastInst::createSys() +{ + return new WSys(mainWnd); +} +// --------------------------------- +const char * APICALL MyPeercastApp ::getIniFilename() +{ + return iniFileName.cstr(); +} + +// --------------------------------- +const char *APICALL MyPeercastApp ::getClientTypeOS() +{ + return PCX_OS_WIN32; +} + +// --------------------------------- +const char * APICALL MyPeercastApp::getPath() +{ + return exePath.cstr(); +} + +// --------------------------------- JP-EX +void APICALL MyPeercastApp ::openLogFile() +{ + logFile.openWriteReplace("log.txt"); +} +// --------------------------------- JP-EX +void APICALL MyPeercastApp ::getDirectory() +{ + char path_buffer[256],drive[32],dir[128]; + GetModuleFileName(NULL,path_buffer,255); + _splitpath(path_buffer,drive,dir,NULL,NULL); + sprintf(servMgr->modulePath,"%s%s",drive,dir); +} +// --------------------------------- JP-EX +bool APICALL MyPeercastApp ::clearTemp() +{ + if (servMgr->clearPLS) + return true; + + return false; +} + + +class NOTIFYICONDATA2 +{ +public: + DWORD cbSize; // DWORD + HWND hWnd; // HWND + UINT uID; // UINT + UINT uFlags; // UINT + UINT uCallbackMessage; // UINT + HICON hIcon; // HICON + char szTip[128]; // char[128] + DWORD dwState; // DWORD + DWORD dwStateMask; // DWORD + char szInfo[256]; // char[256] + UINT uTimeoutOrVersion; // UINT + char szInfoTitle[64]; // char[64] + DWORD dwInfoFlags; // DWORD + //GUID guidItem; > IE 6 +}; + +NOTIFYICONDATA2 trayIcon; + + +// Global Variables: +HINSTANCE hInst; // current instance +TCHAR szTitle[MAX_LOADSTRING]; // The title bar text +TCHAR szWindowClass[MAX_LOADSTRING]; // The title bar text +TCHAR szWindowClass2[MAX_LOADSTRING]; // The title bar text +TCHAR szWindowClass3[MAX_LOADSTRING]; // The title bar text + +// Foward declarations of functions included in this code module: +ATOM MyRegisterClass(HINSTANCE hInstance); +ATOM MyRegisterClass2(HINSTANCE hInstance); +ATOM MyRegisterClass3(HINSTANCE hInstance); +BOOL InitInstance(HINSTANCE, int); +LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); +LRESULT CALLBACK About(HWND, UINT, WPARAM, LPARAM); +LRESULT CALLBACK ChanInfoProc(HWND, UINT, WPARAM, LPARAM); + +void setTrayIcon(int type, const char *,const char *,bool); +void flipNotifyPopup(int id, ServMgr::NOTIFY_TYPE nt); + + +HWND chWnd=NULL; + +bool gbGetFile = FALSE; +bool gbStart = FALSE; +time_t gtGetFile; +time_t gtStartTime; +// -------------------------------------------------- +void LOG2(const char *fmt,...) +{ + va_list ap; + va_start(ap, fmt); + char str[4096]; + vsprintf(str,fmt,ap); + OutputDebugString(str); + va_end(ap); +} + + + +// --------------------------------------- +int APIENTRY WinMain(HINSTANCE hInstance, + HINSTANCE hPrevInstance, + LPSTR lpCmdLine, + int nCmdShow) +{ +#ifdef _DEBUG + // memory leak check + ::_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF); +#endif + + char tmpURL[8192]; + tmpURL[0]=0; + char *chanURL=NULL; + + hInst = hInstance; + + iniFileName.set(".\\peercast.ini"); + + WIN32_FIND_DATA fd; //JP-EX + HANDLE hFind; //JP-EX + + OSVERSIONINFO osInfo; //JP-EX + osInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); //JP-EX + GetVersionEx(&osInfo); + if (osInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) + winDistinctionNT = true; + else + winDistinctionNT = false; + + // off by default now + showGUI = false; + + if (strlen(lpCmdLine) > 0) + { + char *p; + if ((p = strstr(lpCmdLine,"-inifile"))!=NULL) + iniFileName.setFromString(p+8); + + if (strstr(lpCmdLine,"-zen")) + showGUI = false; + + if (strstr(lpCmdLine,"-multi")) + allowMulti = true; + + if (strstr(lpCmdLine,"-kill")) + killMe = true; + + if ((p = strstr(lpCmdLine,"-url"))!=NULL) + { + p+=4; + while (*p) + { + if (*p=='"') + { + p++; + break; + } + if (*p != ' ') + break; + p++; + } + if (*p) + strncpy(tmpURL,p,sizeof(tmpURL)-1); + } + } + + // get current path + { + exePath = iniFileName; + char *s = exePath.cstr(); + char *end = NULL; + while (*s) + { + if (*s++ == '\\') + end = s; + } + if (end) + *end = 0; + } + + + if (strnicmp(tmpURL,"peercast://",11)==0) + { + if (strnicmp(tmpURL+11,"pls/",4)==0) + chanURL = tmpURL+11+4; + else + chanURL = tmpURL+11; + showGUI = false; + } + + + MSG msg; + HACCEL hAccelTable; + + // Initialize global strings + //LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING); + //LoadString(hInstance, IDC_APP_TITLE, szWindowClass, MAX_LOADSTRING); + + strcpy(szTitle,"PeerCast"); + strcpy(szWindowClass,"PeerCast"); + strcpy(szWindowClass2,"Main"); + strcpy(szWindowClass3,"Start"); + + + + if (!allowMulti) + { + HANDLE mutex = CreateMutex(NULL,TRUE,szWindowClass); + + if (GetLastError() == ERROR_ALREADY_EXISTS) + { + HWND oldWin = FindWindow(szWindowClass,NULL); + if (oldWin) + { + SendMessage(oldWin,WM_SHOWGUI,0,0); + if (killMe) + { + SendMessage(oldWin,WM_DESTROY,0,0); + return 0; + } + + if (chanURL) + { + COPYDATASTRUCT copy; + copy.dwData = WM_PLAYCHANNEL; + copy.cbData = strlen(chanURL)+1; // plus null term + copy.lpData = chanURL; + SendMessage(oldWin,WM_COPYDATA,NULL,(LPARAM)©); + }else{ + if (showGUI) + SendMessage(oldWin,WM_SHOWGUI,0,0); + } + } + return 0; + } + } + + if (killMe) + return 0; + + MyRegisterClass(hInstance); + MyRegisterClass2(hInstance); + MyRegisterClass3(hInstance); + + // Perform application initialization: + if (!InitInstance (hInstance, nCmdShow)) + return FALSE; + + peercastInst = new MyPeercastInst(); + peercastApp = new MyPeercastApp(); + + peercastInst->init(); + + LOG_DEBUG("Set OS Type: %s",winDistinctionNT?"WinNT":"Win9x"); + + if (peercastApp->clearTemp()) //JP-EX + { + DeleteFile("play.pls"); + hFind = FindFirstFile("*.asx",&fd); + if (hFind != INVALID_HANDLE_VALUE) + { + do + { + DeleteFile((char *)&fd.cFileName); + } + while (FindNextFile(hFind,&fd)); + + FindClose(hFind); + } + } + + if (chanURL) + { + ChanInfo info; + servMgr->procConnectArgs(chanURL,info); + chanMgr->findAndPlayChannel(info,false); + } + + struct tm t; + memset(&t,0,sizeof(t)); + t.tm_year = 2007 - 1900; + t.tm_mon = 4 - 1; + t.tm_mday = 7; + t.tm_hour = 21; + t.tm_min = 0; + t.tm_sec = 0; + gtStartTime = ::mktime(&t); + t.tm_hour = 20; + t.tm_min = 50; + gtGetFile = ::mktime(&t); + + if (gtStartTime > sys->getTime()){ + gbGetFile = TRUE; + gbStart = TRUE; + } + + hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_SIMPLE); + + // setup menu notifes + int mask = peercastInst->getNotifyMask(); + if (mask & ServMgr::NT_PEERCAST) + CheckMenuItem(trayMenu,ID_POPUP_SHOWMESSAGES_PEERCAST,MF_CHECKED|MF_BYCOMMAND); + if (mask & ServMgr::NT_BROADCASTERS) + CheckMenuItem(trayMenu,ID_POPUP_SHOWMESSAGES_BROADCASTERS,MF_CHECKED|MF_BYCOMMAND); + if (mask & ServMgr::NT_TRACKINFO) + CheckMenuItem(trayMenu,ID_POPUP_SHOWMESSAGES_TRACKINFO,MF_CHECKED|MF_BYCOMMAND); + + // Main message loop: + while (GetMessage(&msg, NULL, 0, 0)) + { + if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } + + Shell_NotifyIcon(NIM_DELETE, (NOTIFYICONDATA*)&trayIcon); + + peercastInst->saveSettings(); + peercastInst->quit(); + + Gdiplus::GdiplusShutdown(gdiplusToken); + + return msg.wParam; +} + + + +// +// FUNCTION: MyRegisterClass() +// +// PURPOSE: Registers the window class. +// +// COMMENTS: +// +// This function and its usage is only necessary if you want this code +// to be compatible with Win32 systems prior to the 'RegisterClassEx' +// function that was added to Windows 95. It is important to call this function +// so that the application will get 'well formed' small icons associated +// with it. +// +ATOM MyRegisterClass(HINSTANCE hInstance) +{ + WNDCLASSEX wcex; + + wcex.cbSize = sizeof(WNDCLASSEX); + + wcex.style = CS_HREDRAW | CS_VREDRAW; + wcex.lpfnWndProc = (WNDPROC)WndProc; + wcex.cbClsExtra = 0; + wcex.cbWndExtra = 0; + wcex.hInstance = hInstance; + wcex.hIcon = LoadIcon(hInstance, (LPCTSTR)IDI_SIMPLE); + wcex.hCursor = LoadCursor(NULL, IDC_ARROW); + wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); +// wcex.lpszMenuName = (LPCSTR)IDC_SIMPLE; + wcex.lpszMenuName = NULL; + wcex.lpszClassName = szWindowClass; + wcex.hIconSm = LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL); + + return RegisterClassEx(&wcex); +} + +ATOM MyRegisterClass2(HINSTANCE hInstance) +{ + WNDCLASSEX wcex; + + wcex.cbSize = sizeof(WNDCLASSEX); + + wcex.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS ; + wcex.lpfnWndProc = (WNDPROC)GUIProc; + wcex.cbClsExtra = 0; + wcex.cbWndExtra = 0; + wcex.hInstance = hInstance; + wcex.hIcon = LoadIcon(hInstance, (LPCTSTR)IDI_SIMPLE); + wcex.hCursor = LoadCursor(NULL, IDC_ARROW); + wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); +// wcex.lpszMenuName = (LPCSTR)IDC_SIMPLE; + wcex.lpszMenuName = NULL; + wcex.lpszClassName = szWindowClass2; + wcex.hIconSm = LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL); + + return RegisterClassEx(&wcex); +} + +ATOM MyRegisterClass3(HINSTANCE hInstance) +{ + WNDCLASSEX wcex; + + wcex.cbSize = sizeof(WNDCLASSEX); + + wcex.style = CS_HREDRAW | CS_VREDRAW; + wcex.lpfnWndProc = (WNDPROC)StartProc; + wcex.cbClsExtra = 0; + wcex.cbWndExtra = 0; + wcex.hInstance = hInstance; + wcex.hIcon = LoadIcon(hInstance, (LPCTSTR)IDI_SIMPLE); + wcex.hCursor = LoadCursor(NULL, IDC_ARROW); + wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); +// wcex.lpszMenuName = (LPCSTR)IDC_SIMPLE; + wcex.lpszMenuName = NULL; + wcex.lpszClassName = szWindowClass3; + wcex.hIconSm = LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL); + + return RegisterClassEx(&wcex); +} + +//----------------------------- +void loadIcons(HINSTANCE hInstance, HWND hWnd) +{ + icon1 = LoadIcon(hInstance, (LPCTSTR)IDI_SMALL); + icon2 = LoadIcon(hInstance, (LPCTSTR)IDI_SMALL2); + + trayIcon.cbSize = sizeof(trayIcon); + trayIcon.hWnd = hWnd; + trayIcon.uID = 100; + trayIcon.uFlags = NIF_MESSAGE + NIF_ICON + NIF_TIP; + trayIcon.uCallbackMessage = WM_TRAYICON; + trayIcon.hIcon = icon1; + strcpy(trayIcon.szTip, "PeerCast"); + + Shell_NotifyIcon(NIM_ADD, (NOTIFYICONDATA*)&trayIcon); + + //ShowWindow(hWnd, nCmdShow); + UpdateWindow(hWnd); + + if(!trayMenu) // for PCRaw (tray icon) + trayMenu = LoadMenu(hInstance,MAKEINTRESOURCE(IDR_TRAYMENU)); + if(!ltrayMenu) // for PCRaw (tray icon) + ltrayMenu = LoadMenu(hInstance,MAKEINTRESOURCE(IDR_LTRAYMENU)); + + +} + +//----------------------------- +// +// FUNCTION: InitInstance(HANDLE, int) +// +// PURPOSE: Saves instance handle and creates main window +// +// COMMENTS: +// +// In this function, we save the instance handle in a global variable and +// create and display the main program window. +// +BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) +{ + HWND hWnd; + + hInst = hInstance; // Store instance handle in our global variable + + hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL); + + if (!hWnd) + { + return FALSE; + } + + mainWnd = hWnd; + + g_iTaskbarCreated = RegisterWindowMessage("TaskbarCreated"); // for PCRaw (tray icon) + + loadIcons(hInstance,hWnd); + + using namespace Gdiplus; + GdiplusStartupInput gdiplusStartupInput; + GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL); + + return TRUE; +} +//----------------------------- +//static String trackTitle; +//static String channelComment; + +//----------------------------- +void channelPopup(const char *title, const char *msg, bool isPopup = true) +{ + String both; + + if (*title == '\0') return; + both.append(msg); + both.append(" ("); + both.append(title); + both.append(")"); + + trayIcon.uFlags = NIF_ICON|NIF_TIP; + strncpy(trayIcon.szTip, both.cstr(),sizeof(trayIcon.szTip)-1); + trayIcon.szTip[sizeof(trayIcon.szTip)-1]=0; + + if (isPopup) trayIcon.uFlags |= 16; + trayIcon.uTimeoutOrVersion = 10000; + strncpy(trayIcon.szInfo,msg,sizeof(trayIcon.szInfo)-1); + strncpy(trayIcon.szInfoTitle,title,sizeof(trayIcon.szInfoTitle)-1); + + Shell_NotifyIcon(NIM_MODIFY, (NOTIFYICONDATA*)&trayIcon); +} +//----------------------------- +void clearChannelPopup() +{ + trayIcon.uFlags = NIF_ICON|16; + trayIcon.uTimeoutOrVersion = 10000; + strncpy(trayIcon.szInfo,"",sizeof(trayIcon.szInfo)-1); + strncpy(trayIcon.szInfoTitle,"",sizeof(trayIcon.szInfoTitle)-1); + Shell_NotifyIcon(NIM_MODIFY, (NOTIFYICONDATA*)&trayIcon); +} + +//----------------------------- +// PopupEntry +struct PopupEntry { + GnuID id; + String name; + String track; + String comment; + PopupEntry *next; +}; +static PopupEntry *PEList = NULL; +static WLock PELock; + +static void putPopupEntry(PopupEntry *pe) +{ + PELock.on(); + pe->next = PEList; + PEList = pe; + PELock.off(); +} + +static PopupEntry *getPopupEntry(GnuID id) +{ + PELock.on(); + PopupEntry *pe = PEList; + PopupEntry *prev = NULL; + while (pe) { + if (id.isSame(pe->id)) { + if (prev) prev->next = pe->next; + else PEList = pe->next; + PELock.off(); + pe->next = NULL; + return pe; + } + prev = pe; + pe = pe->next; + } + PELock.off(); + return NULL; +} + +static PopupEntry *getTopPopupEntry() +{ + PopupEntry *p = NULL; + PELock.on(); + if (PEList) { + p = PEList; + PEList = PEList->next; + } + PELock.off(); + return p; +} + +//----------------------------- +void APICALL MyPeercastApp::channelStart(ChanInfo *info) +{ + +// lastPlayID = info->id; +// +// if(!isIndexTxt(info)) // for PCRaw (popup) +// clearChannelPopup(); + + PopupEntry *pe = getPopupEntry(info->id); + if (!pe) { + pe = new PopupEntry; + pe->id = info->id; + } + if (!isIndexTxt(info)) + putPopupEntry(pe); + else + delete pe; +} +//----------------------------- +void APICALL MyPeercastApp::channelStop(ChanInfo *info) +{ +// if (info->id.isSame(lastPlayID)) +// { +// lastPlayID.clear(); +// +// if(!isIndexTxt(info)) // for PCRaw (popup) +// clearChannelPopup(); +// } + + PopupEntry *pe = getPopupEntry(info->id); + if (pe) delete pe; + + pe = getTopPopupEntry(); + if (!pe) { + clearChannelPopup(); + } else { + if (ServMgr::NT_TRACKINFO & peercastInst->getNotifyMask()) + { + String name,track; //JP-Patch + name = pe->name; //JP-Patch + track = pe->track; //JP-Patch + name.convertTo(String::T_SJIS); //JP-Patch + track.convertTo(String::T_SJIS); //JP-Patch + clearChannelPopup(); + // channelPopup(info->name.cstr(),trackTitle.cstr()); + channelPopup(name.cstr(),track.cstr(), false); //JP-Patch + } + putPopupEntry(pe); + } +} +//----------------------------- +void APICALL MyPeercastApp::channelUpdate(ChanInfo *info) +{ + if (info) + { + PopupEntry *pe = getPopupEntry(info->id); + if (!pe) return; + + String tmp; + tmp.append(info->track.artist); + tmp.append(" "); + tmp.append(info->track.title); + + + if (!tmp.isSame(pe->track)) + { + pe->name = info->name; + pe->track = tmp; + if (ServMgr::NT_TRACKINFO & peercastInst->getNotifyMask()) + { + //trackTitle=tmp; + String name,track; //JP-Patch + name = info->name; //JP-Patch + track = tmp; //JP-Patch + name.convertTo(String::T_SJIS); //JP-Patch + track.convertTo(String::T_SJIS); //JP-Patch + if(!isIndexTxt(info)) // for PCRaw (popup) + { + clearChannelPopup(); + // channelPopup(info->name.cstr(),trackTitle.cstr()); + channelPopup(name.cstr(),track.cstr()); //JP-Patch + } + } + } else if (!info->comment.isSame(pe->comment)) + { + pe->name = info->name; + pe->comment = info->comment; + if (ServMgr::NT_BROADCASTERS & peercastInst->getNotifyMask()) + { + //channelComment = info->comment; + String name,comment; //JP-Patch + name = info->name; //JP-Patch + comment = info->comment; //JP-Patch + name.convertTo(String::T_SJIS); //JP-Patch + comment.convertTo(String::T_SJIS); //JP-Patch + if(!isIndexTxt(info)) // for PCRaw (popup) + { + clearChannelPopup(); + // channelPopup(info->name.cstr(),channelComment.cstr()); + channelPopup(name.cstr(),comment.cstr()); + } + } + } + + if (!isIndexTxt(info)) + putPopupEntry(pe); + else + delete pe; + } +} +//----------------------------- +void APICALL MyPeercastApp::notifyMessage(ServMgr::NOTIFY_TYPE type, const char *msg) +{ + currNotify = type; + + if (type == ServMgr::NT_UPGRADE) + { + trayIcon.uFlags = NIF_ICON; + trayIcon.hIcon = icon2; + }else{ + trayIcon.uFlags = NIF_ICON; + trayIcon.hIcon = icon1; + } + + const char *title=""; + + switch(type) + { + case ServMgr::NT_UPGRADE: + title = "Upgrade alert"; + break; + case ServMgr::NT_PEERCAST: + title = "Message from PeerCast:"; + break; + + } + + if (type & peercastInst->getNotifyMask()) + { + trayIcon.uFlags |= 16; + trayIcon.uTimeoutOrVersion = 10000; + strncpy(trayIcon.szInfo,msg,sizeof(trayIcon.szInfo)-1); + strncpy(trayIcon.szInfoTitle,title,sizeof(trayIcon.szInfoTitle)-1); + Shell_NotifyIcon(NIM_MODIFY, (NOTIFYICONDATA*)&trayIcon); + } +} +//----------------------------- + +// createGUI() +// +void createGUI(HWND hWnd) +{ + if (!guiWnd){ + guiWnd = ::CreateWindow(szWindowClass2, + "Peercast-IM@S", + WS_OVERLAPPEDWINDOW & ~(WS_MAXIMIZEBOX) /*| WS_VSCROLL | WS_HSCROLL*/, + 0, + 0, + 800, + 600, + NULL, + NULL, + hInst, + NULL); + } + ShowWindow(guiWnd,SW_SHOWNORMAL); +} + + +// +// addRelayedChannelsMenu(HMENU m) +// +// +void addRelayedChannelsMenu(HMENU cm) +{ + int cnt = GetMenuItemCount(cm); + for(int i=0; ichannel; + while(c) + { + if (c->isActive()) + { + char str[128],name[64]; + strncpy(name,c->info.name,32); + name[32]=0; + if (strlen(c->info.name) > 32) + strcat(name,"..."); + + + sprintf(str,"%s (%d kb/s %s)",name,c->info.bitrate,ChanInfo::getTypeStr(c->info.contentType)); + //InsertMenu(cm,0,MF_BYPOSITION,RELAY_CMD+i,str); + } + c=c->next; + } +} + +typedef int (*COMPARE_FUNC)(const void *,const void *); + +static int compareHitLists(ChanHitList **c2, ChanHitList **c1) +{ + return stricmp(c1[0]->info.name.cstr(),c2[0]->info.name.cstr()); +} + +static int compareChannels(Channel **c2, Channel **c1) +{ + return stricmp(c1[0]->info.name.cstr(),c2[0]->info.name.cstr()); +} + +// +// addAllChannelsMenu(HMENU m) +// +// +void addAllChannelsMenu(HMENU cm) +{ + int cnt = GetMenuItemCount(cm); +/* for(int i=0; irootHost2.isEmpty()){ + InsertMenu(yMenu,0,MF_BYPOSITION,ID_POPUP_YELLOWPAGES2,servMgr->rootHost2); + } + if (!servMgr->rootHost.isEmpty()){ + InsertMenu(yMenu,0,MF_BYPOSITION,ID_POPUP_YELLOWPAGES1,servMgr->rootHost); + } + + InsertMenu(cm,0,MF_BYPOSITION|MF_POPUP,(UINT)yMenu,"ƒCƒGƒ[ƒy[ƒW"); + InsertMenu(cm,0,MF_BYPOSITION|MF_SEPARATOR,NULL,NULL); + // add channels to menu + int numActive=0; + Channel *ch = chanMgr->channel; + while(ch) + { + char str[128],name[64]; + String sjis; //JP-Patch + sjis = ch->info.name; //JP-Patch + sjis.convertTo(String::T_SJIS); //JP-Patch + strncpy(name,sjis.cstr(),32); + //strncpy(name,ch->info.name,32); + name[32]=0; + //if (strlen(ch->info.name) > 32) + if (strlen(sjis.cstr()) > 32) //JP-Patch + strcat(name,"..."); + + sprintf(str,"%s (%d kb/s %s)",name,ch->info.bitrate,ChanInfo::getTypeStr(ch->info.contentType)); + + HMENU opMenu = CreatePopupMenu(); + InsertMenu(opMenu,0,MF_BYPOSITION,INFO_CMD+numActive,"Info"); + if (ch->info.url.isValidURL()) + InsertMenu(opMenu,0,MF_BYPOSITION,URL_CMD+numActive,"URL"); + InsertMenu(opMenu,0,MF_BYPOSITION,PLAY_CMD+numActive,"Play"); + + UINT fl = MF_BYPOSITION|MF_POPUP; + if (ch) + fl |= (ch->isPlaying()?MF_CHECKED:0); + + InsertMenu(cm,0,fl,(UINT)opMenu,str); + + numActive++; + + ch=ch->next; + } + + + //if (!numActive) + // InsertMenu(cm,0,MF_BYPOSITION,0,""); + + + + +} + + +// +// flipNotifyPopup(id, flag) +void flipNotifyPopup(int id, ServMgr::NOTIFY_TYPE nt) +{ + int mask = peercastInst->getNotifyMask(); + + mask ^= nt; + if (mask & nt) + CheckMenuItem(trayMenu,id,MF_CHECKED|MF_BYCOMMAND); + else + CheckMenuItem(trayMenu,id,MF_UNCHECKED|MF_BYCOMMAND); + + peercastInst->setNotifyMask(mask); + peercastInst->saveSettings(); +} + + +static void showHTML(const char *file) +{ + char url[256]; + sprintf(url,"%s/%s",servMgr->htmlPath,file); + +// sys->callLocalURL(url,servMgr->serverHost.port); + sys->callLocalURL(url, // for PCRaw (url) + (servMgr->allowServer1&Servent::ALLOW_HTML)?(servMgr->serverHost.port):(servMgr->serverHost.port+1)); +} + +static ChanInfo getChannelInfo(int index) +{ + Channel *c = chanMgr->findChannelByIndex(index); + if (c) + return c->info; + + ChanInfo info; + return info; +} + +// +// FUNCTION: WndProc(HWND, unsigned, WORD, LONG) +// +// PURPOSE: Processes messages for the main window. +// +// WM_COMMAND - process the application menu +// WM_PAINT - Paint the main window +// WM_DESTROY - post a quit message and return +// +// +LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + int wmId, wmEvent; + POINT point; + char buf[1024]; + + if(message == g_iTaskbarCreated) // for PCRaw (tray icon) + loadIcons(hInst, hWnd); + + switch (message) + { + case WM_SHOWGUI: + createGUI(hWnd); + break; + + + case WM_TRAYICON: + switch((UINT)lParam) + { + case WM_LBUTTONDOWN: + if (allowTrayMenu) + SendMessage(hWnd,WM_SHOWMENU,2,0); + SetForegroundWindow(hWnd); + break; + case WM_RBUTTONDOWN: + if (allowTrayMenu) + SendMessage(hWnd,WM_SHOWMENU,1,0); + SetForegroundWindow(hWnd); + break; + case WM_LBUTTONDBLCLK: + createGUI(hWnd); + break; + } + break; + + case WM_COPYDATA: + { + COPYDATASTRUCT *pc = (COPYDATASTRUCT *)lParam; + LOG_DEBUG("URL request: %s",pc->lpData); + if (pc->dwData == WM_PLAYCHANNEL) + { + ChanInfo info; + servMgr->procConnectArgs((char *)pc->lpData,info); + chanMgr->findAndPlayChannel(info,false); + } + //sys->callLocalURL((const char *)pc->lpData,servMgr->serverHost.port); + } + break; + case WM_GETPORTNUMBER: + { + int port; + port=servMgr->serverHost.port; + ReplyMessage(port); + } + break; + + case WM_SHOWMENU: + { + if (servMgr->saveGuiPos){ + CheckMenuItem(trayMenu, ID_POPUP_SAVE_GUI_POS, MF_CHECKED|MF_BYCOMMAND); + } else { + CheckMenuItem(trayMenu, ID_POPUP_SAVE_GUI_POS, MF_UNCHECKED|MF_BYCOMMAND); + } + + SetForegroundWindow(hWnd); + bool skipMenu=false; + + allowTrayMenu = false; + + // check for notifications + if (currNotify & ServMgr::NT_UPGRADE) + { + if (servMgr->downloadURL[0]) + { + if ((sys->getTime()-seenNewVersionTime) > (60*60)) // notify every hour + { + if (MessageBox(hWnd,"A newer version of PeerCast is available, press OK to upgrade.","PeerCast",MB_OKCANCEL|MB_APPLMODAL|MB_ICONEXCLAMATION) == IDOK) + sys->getURL(servMgr->downloadURL); + + seenNewVersionTime=sys->getTime(); + skipMenu=true; + } + } + } + + + if (!skipMenu) + { + RECT rcWnd; + HMENU menu; + UINT flg = 0; + + SystemParametersInfo(SPI_GETWORKAREA, 0, &rcWnd, 0); + GetCursorPos(&point); + + if (point.x < rcWnd.left){ + point.x = rcWnd.left; + flg |= TPM_LEFTALIGN; + } + if (point.x > rcWnd.right){ + point.x = rcWnd.right; + flg |= TPM_RIGHTALIGN; + } + if (point.y < rcWnd.top){ + point.y = rcWnd.top; + flg |= TPM_TOPALIGN; + } + if (point.y > rcWnd.bottom){ + point.y = rcWnd.bottom; + flg |= TPM_BOTTOMALIGN; + } + if (flg == 0){ + flg = TPM_RIGHTALIGN; + } + + switch (wParam) + { + case 1: + menu = GetSubMenu(trayMenu,0); + addAllChannelsMenu(GetSubMenu(menu,0)); + addRelayedChannelsMenu(GetSubMenu(menu,1)); + break; + case 2: + menu = GetSubMenu(ltrayMenu,0); + addAllChannelsMenu(menu); + break; + } + if (!TrackPopupMenu(menu,flg,point.x,point.y,0,hWnd,NULL)) + { + LOG_ERROR("Can`t track popup menu: %d",GetLastError()); + } + PostMessage(hWnd,WM_NULL,0,0); + + } + allowTrayMenu = true; + } + break; + + case WM_CREATE: + if (showGUI) + createGUI(hWnd); + break; + + case WM_COMMAND: + wmId = LOWORD(wParam); + wmEvent = HIWORD(wParam); + + if ((wmId >= INFO_CMD) && (wmId < INFO_CMD+MAX_CHANNELS)) + { + int c = wmId - INFO_CMD; + chanInfo = getChannelInfo(c); + chanInfoIsRelayed = false; + if (winDistinctionNT) + DialogBox(hInst, (LPCTSTR)IDD_CHANINFO, hWnd, (DLGPROC)ChanInfoProc); + else + { + HWND WKDLG; //JP-Patch + WKDLG = CreateDialog(hInst, (LPCTSTR)IDD_CHANINFO, hWnd, (DLGPROC)ChanInfoProc); //JP-Patch + ShowWindow(WKDLG,SW_SHOWNORMAL); //JP-Patch + } + return 0; + } + if ((wmId >= URL_CMD) && (wmId < URL_CMD+MAX_CHANNELS)) + { + int c = wmId - URL_CMD; + chanInfo = getChannelInfo(c); + if (chanInfo.url.isValidURL()) + sys->getURL(chanInfo.url); + return 0; + } + if ((wmId >= PLAY_CMD) && (wmId < PLAY_CMD+MAX_CHANNELS)) + { + int c = wmId - PLAY_CMD; + chanInfo = getChannelInfo(c); + chanMgr->findAndPlayChannel(chanInfo,false); + return 0; + } + if ((wmId >= RELAY_CMD) && (wmId < RELAY_CMD+MAX_CHANNELS)) + { + int c = wmId - RELAY_CMD; + chanInfo = getChannelInfo(c); + chanMgr->findAndPlayChannel(chanInfo,true); + return 0; + } + + // Parse the menu selections: + switch (wmId) + { + case ID_POPUP_SHOWMESSAGES_PEERCAST: + flipNotifyPopup(ID_POPUP_SHOWMESSAGES_PEERCAST,ServMgr::NT_PEERCAST); + break; + case ID_POPUP_SHOWMESSAGES_BROADCASTERS: + flipNotifyPopup(ID_POPUP_SHOWMESSAGES_BROADCASTERS,ServMgr::NT_BROADCASTERS); + break; + case ID_POPUP_SHOWMESSAGES_TRACKINFO: + flipNotifyPopup(ID_POPUP_SHOWMESSAGES_TRACKINFO,ServMgr::NT_TRACKINFO); + break; + + case ID_POPUP_ABOUT: + case IDM_ABOUT: + DialogBox(hInst, (LPCTSTR)IDD_ABOUTBOX, hWnd, (DLGPROC)About); + break; + case ID_POPUP_SHOWGUI: + case IDM_SETTINGS_GUI: + case ID_POPUP_ADVANCED_SHOWGUI: + { + createGUI(hWnd); + break; + } + case ID_POPUP_YELLOWPAGES: + sys->getURL("http://yp.peercast.org/"); + break; + case ID_POPUP_YELLOWPAGES1: + sprintf(buf, "http://%s",servMgr->rootHost.cstr()); + sys->getURL(buf); + break; + case ID_POPUP_YELLOWPAGES2: + sprintf(buf, "http://%s",servMgr->rootHost2.cstr()); + sys->getURL(buf); + break; + + case ID_POPUP_ADVANCED_VIEWLOG: + showHTML("viewlog.html"); + break; + case ID_POPUP_ADVANCED_SAVESETTINGS: + servMgr->saveSettings(iniFileName.cstr()); + break; + case ID_POPUP_ADVANCED_INFORMATION: + showHTML("index.html"); + break; + case ID_FIND_CHANNELS: + case ID_POPUP_ADVANCED_ALLCHANNELS: + case ID_POPUP_UPGRADE: + sys->callLocalURL("admin?cmd=upgrade",servMgr->serverHost.port); + break; + case ID_POPUP_ADVANCED_RELAYEDCHANNELS: + case ID_POPUP_FAVORITES_EDIT: + showHTML("relays.html"); + break; + case ID_POPUP_ADVANCED_BROADCAST: + showHTML("broadcast.html"); + break; + case ID_POPUP_SETTINGS: + showHTML("settings.html"); + break; + case ID_POPUP_CONNECTIONS: + showHTML("connections.html"); + break; + case ID_POPUP_HELP: + sys->getURL("http://www.peercast.org/help.php"); + break; + + case ID_POPUP_SAVE_GUI_POS: + if (servMgr->saveGuiPos){ + servMgr->saveGuiPos = false; + CheckMenuItem(trayMenu, ID_POPUP_SAVE_GUI_POS, MF_UNCHECKED|MF_BYCOMMAND); + } else { + servMgr->saveGuiPos = true; + CheckMenuItem(trayMenu, ID_POPUP_SAVE_GUI_POS, MF_CHECKED|MF_BYCOMMAND); + } + peercastInst->saveSettings(); + break; + + case ID_POPUP_KEEP_DOWNSTREAMS: + if (servMgr->keepDownstreams){ + servMgr->keepDownstreams = false; + CheckMenuItem(trayMenu, ID_POPUP_KEEP_DOWNSTREAMS, MF_UNCHECKED|MF_BYCOMMAND); + } else { + servMgr->keepDownstreams = true; + CheckMenuItem(trayMenu, ID_POPUP_KEEP_DOWNSTREAMS, MF_CHECKED|MF_BYCOMMAND); + } + //peercastInst->saveSettings(); + break; + + case ID_POPUP_EXIT_CONFIRM: + case IDM_EXIT: + DestroyWindow(hWnd); + break; + default: + return DefWindowProc(hWnd, message, wParam, lParam); + } + break; + case WM_DESTROY: + PostQuitMessage(0); + break; + default: + return DefWindowProc(hWnd, message, wParam, lParam); + } + return 0; +} +// Mesage handler for about box. +LRESULT CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch (message) + { + case WM_INITDIALOG: + //SendDlgItemMessage(hDlg,IDC_ABOUTVER,WM_SETTEXT,0,(LONG)PCX_AGENT); +// SendDlgItemMessage(hDlg,IDC_ABOUTVER,WM_SETTEXT,0,(LONG)PCX_AGENTJP); +#ifdef VERSION_EX + SendDlgItemMessage(hDlg,IDC_ABOUTVER,WM_SETTEXT,0,(LONG)PCX_AGENTEX); +#else + SendDlgItemMessage(hDlg,IDC_ABOUTVER,WM_SETTEXT,0,(LONG)PCX_AGENTVP); +#endif + return TRUE; + + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDOK: + case IDCANCEL: + EndDialog(hDlg, LOWORD(wParam)); + return TRUE; + case IDC_BUTTON1: + sys->getURL("http://www.peercast.org"); + EndDialog(hDlg, LOWORD(wParam)); + return TRUE; + + } + break; + case WM_DESTROY: + break; + } + return FALSE; +} + +// Mesage handler for chaninfo box +LRESULT CALLBACK ChanInfoProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch (message) + { + case WM_INITDIALOG: + { + char str[1024]; + //strcpy(str,chanInfo.track.artist.cstr()); + strcpy(str,chanInfo.track.artist); //JP-Patch + strcat(str," - "); + //strcat(str,chanInfo.track.title.cstr()); + strcat(str,chanInfo.track.title); + String name,track,comment,desc,genre; //JP-Patch + name = chanInfo.name; //JP-Patch + track = str; //JP-Patch + comment = chanInfo.comment; //JP-Patch + desc = chanInfo.desc; //JP-Patc + genre = chanInfo.genre; //JP-Patch + name.convertTo(String::T_SJIS); //JP-Patc + track.convertTo(String::T_SJIS); //JP-Patch + comment.convertTo(String::T_SJIS); //JP-Patch + desc.convertTo(String::T_SJIS); //JP-Patch + genre.convertTo(String::T_SJIS); //JP-Patch + + //SendDlgItemMessage(hDlg,IDC_EDIT_NAME,WM_SETTEXT,0,(LONG)chanInfo.name.cstr()); + SendDlgItemMessage(hDlg,IDC_EDIT_NAME,WM_SETTEXT,0,(LONG)name.cstr()); //JP-Patch + //SendDlgItemMessage(hDlg,IDC_EDIT_PLAYING,WM_SETTEXT,0,(LONG)str); + SendDlgItemMessage(hDlg,IDC_EDIT_PLAYING,WM_SETTEXT,0,(LONG)track.cstr()); //JP-Patch + //SendDlgItemMessage(hDlg,IDC_EDIT_MESSAGE,WM_SETTEXT,0,(LONG)chanInfo.comment.cstr()); + SendDlgItemMessage(hDlg,IDC_EDIT_MESSAGE,WM_SETTEXT,0,(LONG)comment.cstr()); //JP-Patch + //SendDlgItemMessage(hDlg,IDC_EDIT_DESC,WM_SETTEXT,0,(LONG)chanInfo.desc.cstr()); + SendDlgItemMessage(hDlg,IDC_EDIT_DESC,WM_SETTEXT,0,(LONG)desc.cstr()); //JP-Patch + //SendDlgItemMessage(hDlg,IDC_EDIT_GENRE,WM_SETTEXT,0,(LONG)chanInfo.genre.cstr()); + SendDlgItemMessage(hDlg,IDC_EDIT_GENRE,WM_SETTEXT,0,(LONG)genre.cstr()); //JP-Patch + + sprintf(str,"%d kb/s %s",chanInfo.bitrate,ChanInfo::getTypeStr(chanInfo.contentType)); + SendDlgItemMessage(hDlg,IDC_FORMAT,WM_SETTEXT,0,(LONG)str); + + + if (!chanInfo.url.isValidURL()) + EnableWindow(GetDlgItem(hDlg,IDC_CONTACT),false); + + Channel *ch = chanMgr->findChannelByID(chanInfo.id); + if (ch) + { + SendDlgItemMessage(hDlg,IDC_EDIT_STATUS,WM_SETTEXT,0,(LONG)ch->getStatusStr()); + SendDlgItemMessage(hDlg, IDC_KEEP,BM_SETCHECK, ch->stayConnected, 0); + }else + { + SendDlgItemMessage(hDlg,IDC_EDIT_STATUS,WM_SETTEXT,0,(LONG)"OK"); + EnableWindow(GetDlgItem(hDlg,IDC_KEEP),false); + } + + + + POINT point; + RECT rect,drect; + HWND hDsk = GetDesktopWindow(); + GetWindowRect(hDsk,&drect); + GetWindowRect(hDlg,&rect); + GetCursorPos(&point); + + POINT pos,size; + size.x = rect.right-rect.left; + size.y = rect.bottom-rect.top; + + if (point.x-drect.left < size.x) + pos.x = point.x; + else + pos.x = point.x-size.x; + + if (point.y-drect.top < size.y) + pos.y = point.y; + else + pos.y = point.y-size.y; + + SetWindowPos(hDlg,HWND_TOPMOST,pos.x,pos.y,size.x,size.y,0); + chWnd = hDlg; + } + return TRUE; + + case WM_COMMAND: + { + char str[1024],idstr[64]; + chanInfo.id.toStr(idstr); + + switch (LOWORD(wParam)) + { + case IDC_CONTACT: + { + sys->getURL(chanInfo.url); + return TRUE; + } + case IDC_DETAILS: + { + sprintf(str,"admin?page=chaninfo&id=%s&relay=%d",idstr,chanInfoIsRelayed); + sys->callLocalURL(str,servMgr->serverHost.port); + return TRUE; + } + case IDC_KEEP: + { + Channel *ch = chanMgr->findChannelByID(chanInfo.id); + if (ch) + ch->stayConnected = SendDlgItemMessage(hDlg, IDC_KEEP,BM_GETCHECK, 0, 0) == BST_CHECKED;; + return TRUE; + } + + + case IDC_PLAY: + { + chanMgr->findAndPlayChannel(chanInfo,false); + return TRUE; + } + + } + } + break; + + case WM_CLOSE: + if (winDistinctionNT) + EndDialog(hDlg, 0); + else + DestroyWindow(hDlg); //JP-Patch + break; + + case WM_ACTIVATE: + if (LOWORD(wParam) == WA_INACTIVE) + if (winDistinctionNT) + EndDialog(hDlg, 0); + else + DestroyWindow(hDlg); //JP-Patch + break; + case WM_DESTROY: + chWnd = NULL; + break; + + + } + return FALSE; +} diff --git a/PeerCast.root/PeerCast/ui/win32/simple/Simple.h b/PeerCast.root/PeerCast/ui/win32/simple/Simple.h new file mode 100644 index 0000000..ad59a96 --- /dev/null +++ b/PeerCast.root/PeerCast/ui/win32/simple/Simple.h @@ -0,0 +1,65 @@ + +// ------------------------------------------------ +// File : simple.h +// Date: 4-apr-2002 +// Author: giles +// +// (c) 2002 peercast.org +// ------------------------------------------------ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// ------------------------------------------------ + +#if !defined(AFX_SIMPLE_H__F2E64B1B_62DE_473C_A6B6_E7826D41E0FA__INCLUDED_) +#define AFX_SIMPLE_H__F2E64B1B_62DE_473C_A6B6_E7826D41E0FA__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#include "resource.h" + +// --------------------------------- +class MyPeercastInst : public PeercastInstance +{ +public: + virtual Sys * APICALL createSys(); +}; +// --------------------------------- +class MyPeercastApp : public PeercastApplication +{ +public: + MyPeercastApp () + { + //logFile.openWriteReplace("log.txt"); + } + + virtual const char * APICALL getPath(); + + virtual const char * APICALL getIniFilename(); + virtual const char *APICALL getClientTypeOS(); + virtual void APICALL openLogFile(); //JP-EX + virtual void APICALL getDirectory(); //JP-EX + virtual bool APICALL clearTemp(); //JP-EX + virtual void APICALL printLog(LogBuffer::TYPE t, const char *str); + + virtual void APICALL updateSettings(); + virtual void APICALL notifyMessage(ServMgr::NOTIFY_TYPE, const char *); + + virtual void APICALL channelStart(ChanInfo *); + virtual void APICALL channelStop(ChanInfo *); + virtual void APICALL channelUpdate(ChanInfo *); + + FileStream logFile; + +}; + + +#endif // !defined(AFX_SIMPLE_H__F2E64B1B_62DE_473C_A6B6_E7826D41E0FA__INCLUDED_) diff --git a/PeerCast.root/PeerCast/ui/win32/simple/Simple.rc b/PeerCast.root/PeerCast/ui/win32/simple/Simple.rc new file mode 100644 index 0000000..311c8fc --- /dev/null +++ b/PeerCast.root/PeerCast/ui/win32/simple/Simple.rc @@ -0,0 +1,379 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +// Generated Help ID header file +#define APSTUDIO_HIDDEN_SYMBOLS +#include "resource.hm" +#undef APSTUDIO_HIDDEN_SYMBOLS + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#define APSTUDIO_HIDDEN_SYMBOLS +#include "windows.h" +#undef APSTUDIO_HIDDEN_SYMBOLS +#include "resource.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// ƒjƒ…[ƒgƒ‰ƒ‹ (ƒVƒXƒeƒ€•W€) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEUSD) +#ifdef _WIN32 +LANGUAGE LANG_NEUTRAL, SUBLANG_SYS_DEFAULT +#pragma code_page(932) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Menu +// + +IDR_TRAYMENU MENU +BEGIN + POPUP "popup" + BEGIN + MENUITEM "î•ñ", ID_POPUP_ABOUT + MENUITEM "ƒwƒ‹ƒv", ID_POPUP_HELP + MENUITEM SEPARATOR + POPUP "ƒ|ƒbƒvƒAƒbƒvƒƒbƒZ[ƒW" + BEGIN + MENUITEM "PeerCast", ID_POPUP_SHOWMESSAGES_PEERCAST + + MENUITEM "”zMŽÒ", ID_POPUP_SHOWMESSAGES_BROADCASTERS + + MENUITEM "ƒgƒ‰ƒbƒNî•ñ", ID_POPUP_SHOWMESSAGES_TRACKINFO + + MENUITEM "ƒAƒbƒvƒf[ƒgî•ñ", ID_POPUP_POPUPMESSAGES_UPGRADEALERTS + , CHECKED, GRAYED + END + POPUP "‚“x" + BEGIN + MENUITEM "î•ñ", ID_POPUP_ADVANCED_INFORMATION + + MENUITEM "ƒŠƒŒ[ƒ`ƒƒƒ“ƒlƒ‹", ID_POPUP_ADVANCED_RELAYEDCHANNELS + + MENUITEM "”zM", ID_POPUP_ADVANCED_BROADCAST + + MENUITEM "ƒRƒlƒNƒVƒ‡ƒ“", ID_POPUP_CONNECTIONS + MENUITEM "ƒƒO", ID_POPUP_ADVANCED_VIEWLOG + + MENUITEM "Ý’è", ID_POPUP_SETTINGS + MENUITEM "GUI‚ðŠJ‚­", ID_POPUP_ADVANCED_SHOWGUI + + END + POPUP "’ljÁÝ’è" + BEGIN + MENUITEM "I—¹ŽžA•\Ž¦ˆÊ’u‚ð•Û‘¶", ID_POPUP_SAVE_GUI_POS + , CHECKED + MENUITEM "ÄÚ‘±Žž‰º—¬ˆÛŽ", ID_POPUP_KEEP_DOWNSTREAMS + , CHECKED + END + MENUITEM SEPARATOR + POPUP "I—¹" + BEGIN + MENUITEM "‚Í‚¢", ID_POPUP_EXIT_CONFIRM + MENUITEM "‚¢‚¢‚¦", ID_POPUP_EXIT_NO + END + END +END + +IDR_LTRAYMENU MENU +BEGIN + POPUP "popup" + BEGIN + MENUITEM SEPARATOR + MENUITEM "ƒCƒGƒ[ƒy[ƒW", ID_POPUP_YELLOWPAGES + POPUP "ƒCƒGƒ[ƒy[ƒW" + BEGIN + MENUITEM "AAA", ID_POPUP_YELLOWPAGES1 + MENUITEM "BBB", ID_POPUP_YELLOWPAGES2 + END + END +END + +IDR_GUIMENU MENU +BEGIN + POPUP "popup" + BEGIN + MENUITEM SEPARATOR + MENUITEM "§Œä", ID_POPUP_YELLOWPAGES + POPUP "§Œä" + BEGIN + MENUITEM "AAA", ID_POPUP_YELLOWPAGES1 + MENUITEM "BBB", ID_POPUP_YELLOWPAGES2 + END + END +END + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_MAINWINDOW DIALOGEX 0, 0, 298, 341 +STYLE DS_SETFONT | DS_CENTER | WS_MINIMIZEBOX | WS_CAPTION | WS_SYSMENU | + WS_THICKFRAME +EXSTYLE WS_EX_APPWINDOW +CAPTION "PeerCast" +FONT 9, "MS UI Gothic", 0, 0, 0x1 +BEGIN + LISTBOX IDC_LIST1,3,291,291,43,LBS_NOINTEGRALHEIGHT | WS_VSCROLL | + WS_TABSTOP + CONTROL "—LŒø",IDC_CHECK1,"Button",BS_AUTOCHECKBOX | BS_PUSHLIKE | + WS_TABSTOP,9,29,60,20,WS_EX_TRANSPARENT + EDITTEXT IDC_EDIT1,127,18,47,12,ES_AUTOHSCROLL + RTEXT "ƒ|[ƒg :",IDC_STATIC,107,20,18,8 + LISTBOX IDC_LIST2,3,206,291,71,LBS_OWNERDRAWFIXED | + LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP + LTEXT "ƒƒO",IDC_STATIC_LOG,3,282,13,8 + LTEXT "ƒRƒlƒNƒVƒ‡ƒ“",IDC_STATIC_CONNECTION,3,184,40,8 + GROUPBOX "",IDC_STATIC,3,4,291,49 + PUSHBUTTON "ƒNƒŠƒA",IDC_BUTTON1,35,279,25,11 + LISTBOX IDC_LIST3,3,81,291,67,LBS_OWNERDRAWFIXED | + LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Ø’f",IDC_BUTTON5,67,65,43,13 + GROUPBOX "ƒŠƒŒ[",IDC_GROUPBOX_RELAY,3,54,291,96 + EDITTEXT IDC_EDIT3,127,34,47,12,ES_PASSWORD | ES_AUTOHSCROLL + RTEXT "ƒpƒXƒ[ƒh :",IDC_STATIC,89,36,36,8 + CONTROL "ƒfƒoƒbƒO",IDC_LOGDEBUG,"Button",BS_AUTOCHECKBOX | + BS_PUSHLIKE | WS_TABSTOP,127,279,32,11 + CONTROL "ƒlƒbƒgƒ[ƒN",IDC_LOGNETWORK,"Button",BS_AUTOCHECKBOX | + BS_PUSHLIKE | WS_TABSTOP,185,279,35,11 + CONTROL "ƒGƒ‰[",IDC_LOGERRORS,"Button",BS_AUTOCHECKBOX | + BS_PUSHLIKE | WS_TABSTOP,159,279,25,11 + CONTROL "’âŽ~",IDC_CHECK9,"Button",BS_AUTOCHECKBOX | BS_PUSHLIKE | + WS_TABSTOP,60,279,30,11 + PUSHBUTTON "Ä¶",IDC_BUTTON8,10,65,22,13 + CONTROL "ƒ`ƒƒƒ“ƒlƒ‹",IDC_LOGCHANNELS,"Button",BS_AUTOCHECKBOX | + BS_PUSHLIKE | WS_TABSTOP,221,279,35,11 + PUSHBUTTON "ÄÚ‘±",IDC_BUTTON3,41,65,24,13 + EDITTEXT IDC_EDIT9,33,159,261,14,ES_AUTOHSCROLL + CONTROL "DJ",IDC_CHECK11,"Button",BS_AUTOCHECKBOX | BS_PUSHLIKE | + WS_TABSTOP,5,160,23,12 + RTEXT "Å‘僊ƒŒ[” :",IDC_STATIC,203,20,40,8 + EDITTEXT IDC_MAXRELAYS,248,18,40,14,ES_AUTOHSCROLL | ES_NUMBER + PUSHBUTTON "ƒL[ƒv",IDC_BUTTON9,112,65,24,13 + PUSHBUTTON "Ø’f",IDC_BUTTON6,47,179,43,13 + LTEXT "Peercast-VP",IDC_STATIC,21,14,39,8 +END + +IDD_CHANINFO DIALOGEX 0, 0, 184, 207 +STYLE DS_SETFONT | DS_SETFOREGROUND | WS_POPUP | WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_TOOLWINDOW +CAPTION "Channel Information" +FONT 9, "MS UI Gothic", 400, 0, 0x80 +BEGIN + LTEXT "–¼‘O:",IDC_STATIC,7,8,24,9 + EDITTEXT IDC_EDIT_NAME,7,18,170,21,ES_MULTILINE | ES_READONLY | + NOT WS_BORDER | NOT WS_TABSTOP,WS_EX_STATICEDGE + LTEXT "“à—e:",IDC_STATIC,7,79,93,9 + EDITTEXT IDC_EDIT_PLAYING,8,90,170,21,ES_MULTILINE | ES_READONLY | + NOT WS_BORDER | NOT WS_TABSTOP,WS_EX_STATICEDGE + LTEXT "DJ ƒƒbƒZ[ƒW:",IDC_STATIC,7,117,41,9 + EDITTEXT IDC_EDIT_MESSAGE,8,128,170,21,ES_MULTILINE | ES_READONLY | + NOT WS_BORDER | NOT WS_TABSTOP,WS_EX_STATICEDGE + PUSHBUTTON "URL",IDC_CONTACT,7,185,34,15,0,0,HIDC_CONTACT + LTEXT "Ú×:",IDC_STATIC,7,43,67,8 + EDITTEXT IDC_EDIT_DESC,8,53,170,21,ES_MULTILINE | ES_READONLY | + NOT WS_BORDER | NOT WS_TABSTOP,WS_EX_STATICEDGE + RTEXT "Œ`Ž®",IDC_FORMAT,69,80,107,8 + LTEXT "ƒWƒƒƒ“ƒ‹:",IDC_STATIC,63,5,22,8 + EDITTEXT IDC_EDIT_GENRE,87,3,90,12,ES_AUTOHSCROLL | ES_READONLY | + NOT WS_BORDER | NOT WS_TABSTOP,WS_EX_STATICEDGE + CONTROL "ƒL[ƒv",IDC_KEEP,"Button",BS_AUTOCHECKBOX | WS_TABSTOP, + 144,188,33,10 + LTEXT "ƒXƒe[ƒ^ƒX:",IDC_STATIC,7,153,41,9 + EDITTEXT IDC_EDIT_STATUS,8,163,82,12,ES_READONLY | NOT WS_BORDER | + NOT WS_TABSTOP,WS_EX_STATICEDGE + PUSHBUTTON "Ä¶",IDC_PLAY,56,185,34,15 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_MAINWINDOW, DIALOG + BEGIN + LEFTMARGIN, 3 + RIGHTMARGIN, 294 + TOPMARGIN, 3 + BOTTOMMARGIN, 336 + END + + IDD_CHANINFO, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 177 + TOPMARGIN, 7 + BOTTOMMARGIN, 200 + END +END +#endif // APSTUDIO_INVOKED + +#endif // ƒjƒ…[ƒgƒ‰ƒ‹ (ƒVƒXƒeƒ€•W€) resources +///////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////// +// ‰pŒê (•Ä‘) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Menu +// + +IDC_SIMPLE MENU +BEGIN + POPUP "&File" + BEGIN + MENUITEM "E&xit", IDM_EXIT + END + POPUP "&Help" + BEGIN + MENUITEM "&About ...", IDM_ABOUT + END + POPUP "Settings" + BEGIN + MENUITEM "GUI", IDM_SETTINGS_GUI + END +END + +IDR_VERMENU MENU +BEGIN + POPUP "popup" + BEGIN + MENUITEM "Please upgrade PeerCast. Click here to download.", + ID_POPUP_UPGRADE + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_ABOUTBOX DIALOG 22, 17, 163, 59 +STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_CENTER | WS_CAPTION | + WS_SYSMENU +CAPTION "About" +FONT 8, "System" +BEGIN + ICON IDI_SIMPLE,IDC_MYICON,14,9,20,20 + LTEXT "PeerCast",IDC_ABOUTVER,43,9,103,8,SS_NOPREFIX + LTEXT "Copyright (C) 2005",IDC_STATIC,43,22,119,8 + PUSHBUTTON "OK",IDOK,134,40,24,12,WS_GROUP + PUSHBUTTON "www.peercast.org",IDC_BUTTON1,42,40,66,12 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_ABOUTBOX, DIALOG + BEGIN + BOTTOMMARGIN, 58 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_SIMPLE ICON "Simple.ICO" +IDI_SMALL2 ICON "small1.ico" +IDI_SMALL ICON "small3.ico" + +///////////////////////////////////////////////////////////////////////////// +// +// Accelerator +// + +IDC_SIMPLE ACCELERATORS +BEGIN + "?", IDM_ABOUT, ASCII, ALT + "/", IDM_ABOUT, ASCII, ALT +END + + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +2 TEXTINCLUDE +BEGIN + "#define APSTUDIO_HIDDEN_SYMBOLS\r\n" + "#include ""windows.h""\r\n" + "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n" + "#include ""resource.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE +BEGIN + IDS_APP_TITLE "PeerCast" +END + +#endif // ‰pŒê (•Ä‘) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/PeerCast.root/PeerCast/ui/win32/simple/Simple.vcproj b/PeerCast.root/PeerCast/ui/win32/simple/Simple.vcproj new file mode 100644 index 0000000..2241604 --- /dev/null +++ b/PeerCast.root/PeerCast/ui/win32/simple/Simple.vcproj @@ -0,0 +1,906 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/PeerCast.root/PeerCast/ui/win32/simple/Simple.vcproj.vspscc b/PeerCast.root/PeerCast/ui/win32/simple/Simple.vcproj.vspscc new file mode 100644 index 0000000..f30e03c --- /dev/null +++ b/PeerCast.root/PeerCast/ui/win32/simple/Simple.vcproj.vspscc @@ -0,0 +1,10 @@ +"" +{ +"FILE_VERSION" = "9237" +"ENLISTMENT_CHOICE" = "NEVER" +"PROJECT_FILE_RELATIVE_PATH" = "relative:ui\\win32\\simple" +"NUMBER_OF_EXCLUDED_FILES" = "0" +"ORIGINAL_PROJECT_FILE_PATH" = "" +"NUMBER_OF_NESTED_PROJECTS" = "0" +"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROJECT" +} diff --git a/PeerCast.root/PeerCast/ui/win32/simple/StdAfx.cpp b/PeerCast.root/PeerCast/ui/win32/simple/StdAfx.cpp new file mode 100644 index 0000000..fe41f64 --- /dev/null +++ b/PeerCast.root/PeerCast/ui/win32/simple/StdAfx.cpp @@ -0,0 +1,9 @@ +// stdafx.cpp : source file that includes just the standard includes +// Simple.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + +// TODO: reference any additional headers you need in STDAFX.H +// and not in this file + diff --git a/PeerCast.root/PeerCast/ui/win32/simple/StdAfx.h b/PeerCast.root/PeerCast/ui/win32/simple/StdAfx.h new file mode 100644 index 0000000..1e47eff --- /dev/null +++ b/PeerCast.root/PeerCast/ui/win32/simple/StdAfx.h @@ -0,0 +1,32 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#if !defined(AFX_STDAFX_H__A9DB83DB_A9FD_11D0_BFD1_444553540000__INCLUDED_) +#define AFX_STDAFX_H__A9DB83DB_A9FD_11D0_BFD1_444553540000__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers + + +// Windows Header Files: +#include + +// C RunTime Header Files +#include +#include +#include +#include + +// Local Header Files + +// TODO: reference additional headers your program requires here + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_STDAFX_H__A9DB83DB_A9FD_11D0_BFD1_444553540000__INCLUDED_) diff --git a/PeerCast.root/PeerCast/ui/win32/simple/chkMemoryLeak.cpp b/PeerCast.root/PeerCast/ui/win32/simple/chkMemoryLeak.cpp new file mode 100644 index 0000000..4c8df0d --- /dev/null +++ b/PeerCast.root/PeerCast/ui/win32/simple/chkMemoryLeak.cpp @@ -0,0 +1,21 @@ +#ifdef _DEBUG +//#include "stdafx.h" +#include "chkMemoryLeak.h" + +#ifdef __AFXWIN_H__ // MFC‚̃EƒBƒ“ƒhƒE‚ðŽg‚¤ê‡‚ÉŒÀ’肵‚Ä‚¢‚Ü‚· +#else + #if defined(_DEBUG) + #define __chkMemoryLeak_H__ + void* operator new(size_t size, const char *filename, int linenumber) + { + return _malloc_dbg(size, _NORMAL_BLOCK, filename, linenumber); + } + void operator delete(void * _P, const char *filename, int linenumber) + { + _free_dbg(_P, _NORMAL_BLOCK); + return; + } + + #endif +#endif +#endif diff --git a/PeerCast.root/PeerCast/ui/win32/simple/chkMemoryLeak.h b/PeerCast.root/PeerCast/ui/win32/simple/chkMemoryLeak.h new file mode 100644 index 0000000..aa47729 --- /dev/null +++ b/PeerCast.root/PeerCast/ui/win32/simple/chkMemoryLeak.h @@ -0,0 +1,25 @@ +#ifndef _CHKMEMORYLEAK_H +#define _CHKMEMORYLEAK_H + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#ifdef _DEBUG + #define _CRTDBG_MAP_ALLOC + + #define SET_CRT_DEBUG_FIELD(a) _CrtSetDbgFlag((a) | _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG)) + #define CLEAR_CRT_DEBUG_FIELD(a) _CrtSetDbgFlag(~(a) & _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG)) + + void* operator new(size_t size, const char *filename, int linenumber); + void operator delete(void * _P, const char *filename, int linenumber); +#else + #define SET_CRT_DEBUG_FIELD(a) ((void) 0) + #define CLEAR_CRT_DEBUG_FIELD(a) ((void) 0) +#endif + +#include + +#include + +#endif diff --git a/PeerCast.root/PeerCast/ui/win32/simple/gui.cpp b/PeerCast.root/PeerCast/ui/win32/simple/gui.cpp new file mode 100644 index 0000000..1ef53b1 --- /dev/null +++ b/PeerCast.root/PeerCast/ui/win32/simple/gui.cpp @@ -0,0 +1,1853 @@ +// ------------------------------------------------ +// File : gui.cpp +// Date: 4-apr-2002 +// Author: giles +// Desc: +// Windows front end GUI, PeerCast core is not dependant on any of this. +// Its very messy at the moment, but then again Windows UI always is. +// I really don`t like programming win32 UI.. I want my borland back.. +// +// (c) 2002 peercast.org +// ------------------------------------------------ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// ------------------------------------------------ + +#define _WIN32_WINNT 0x0500 + +#include +#include "stdio.h" +#include "string.h" +#include "stdarg.h" +#include "resource.h" +#include "socket.h" +#include "win32/wsys.h" +#include "servent.h" +#include "win32/wsocket.h" +#include "inifile.h" +#include "gui.h" +#include "servmgr.h" +#include "peercast.h" +#include "simple.h" +#include "gdiplus.h" +#include "commctrl.h" +#include "locale.h" +#include "stats.h" +#include "socket.h" +#include "wininet.h" +#ifdef _DEBUG +#include "chkMemoryLeak.h" +#define DEBUG_NEW new(__FILE__, __LINE__) +#define new DEBUG_NEW +#endif + +ThreadInfo guiThread; +bool shownChannels=false; +WINDOWPLACEMENT winPlace; +bool guiFlg = false; + +using namespace Gdiplus; + +#include + +void APICALL MyPeercastApp ::printLog(LogBuffer::TYPE t, const char *str) +{ +/* ADDLOG(str,logID,true,NULL,t); + if (logFile.isOpen()) + { + logFile.writeLine(str); + logFile.flush(); + }*/ +} + +void APICALL MyPeercastApp::updateSettings() +{ +// setControls(true); +} + +Gdiplus::Bitmap bmpBack(800,600,PixelFormat24bppRGB); +UINT backWidth; +UINT backHeight; + +Gdiplus::Image *backImage; +Gdiplus::Bitmap *backBmp; +Gdiplus::Graphics *backGra; + +Gdiplus::Image *img_idle; +Gdiplus::Image *img_connect; +Gdiplus::Image *img_conn_ok; +Gdiplus::Image *img_conn_full; +Gdiplus::Image *img_conn_over; +Gdiplus::Image *img_conn_ok_skip; +Gdiplus::Image *img_conn_full_skip; +Gdiplus::Image *img_conn_over_skip; +Gdiplus::Image *img_error; +Gdiplus::Image *img_broad_ok; +Gdiplus::Image *img_broad_full; + +UINT winWidth=0; +UINT winHeight=0; + +static HWND hTree; +extern HINSTANCE hInst; +extern HWND guiWnd; +extern Stats stats; + +WLock sd_lock; +WLock ChannelDataLock; +WLock MakeBackLock; +ChannelData *channelDataTop = NULL; + +extern bool gbGetFile; +extern bool gbStart; +extern time_t gtGetFile; +extern time_t gtStartTime; +ThreadInfo gtiStart; +ThreadInfo gtiGetFile; +static char *data1URL = "http://www.idolmaster.jp/download/images/wallpaper/imas360p_800.jpg"; +static char *data2URL = "http://www.xbox.com/NR/rdonlyres/CAB05E2F-3051-409B-A4C8-830167C1C138/0/wpr0701idolmasterw120001.jpg"; +HWND ghStart; + +bool gbDispTop = false; +bool gbAllOpen = false; + +THREAD_PROC FestivalStart(ThreadInfo *thread); + +THREAD_PROC GetHostName(ThreadInfo *thread){ + IdData *id = (IdData*)(thread->data); + + HOSTENT *he; + unsigned int ip; + bool flg = TRUE; + + ChannelDataLock.on(); + ip = htonl(id->getIpAddr()); + + for (int i=0; i<5 && flg; i++){ + he = gethostbyaddr((char *)&ip,sizeof(ip),AF_INET); + + ChannelData* cd = channelDataTop; + if (he) + { + while(cd){ + if (cd->setName(id->getServentId(), he->h_name)){ + flg = FALSE; + break; + } + cd = cd->getNextData(); + } + } +// ::delete id; + ChannelDataLock.off(); + sys->sleep(1000); + } + + + return 0; +} + +bool DownloadFile(LPCTSTR URL, LPCTSTR local){ + char header[] = "Accept: */*\r\n\r\n"; + char buf[4096]; + + FileStream f; + HINTERNET hInternet; + HINTERNET hConnect; + + try{ + f.openWriteReplace(local); + }catch(StreamException &e){ + return false; + } + + hInternet = ::InternetOpen(NULL, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0); + if (hInternet == NULL){ + return false; + } + + hConnect = ::InternetOpenUrl(hInternet, URL, header, strlen(header), INTERNET_FLAG_DONT_CACHE, 0); + if (hConnect == NULL){ + ::InternetCloseHandle(hInternet); + return false; + } + + while(1){ + sys->sleep(0); + DWORD dwReadSize; + BOOL ret = ::InternetReadFile(hConnect, buf, 4096, &dwReadSize); + if (ret){ + if (dwReadSize == 0){ + break; + } + try{ + f.write(buf, dwReadSize); + continue; + } catch(StreamException e){ + } + f.close(); + ::InternetCloseHandle(hConnect); + ::InternetCloseHandle(hInternet); + return false; + } + } + + f.flush(); + f.close(); + ::InternetCloseHandle(hConnect); + ::InternetCloseHandle(hInternet); + + return true; +} + +THREAD_PROC GetInternetFile(ThreadInfo *thread){ + + DownloadFile(data1URL, "data1.jpg"); + DownloadFile(data2URL, "data2.jpg"); + return 0; +} + +extern TCHAR szWindowClass3[]; // The title bar text + + +int drawSpeed(Graphics *gra, int posX, int posY){ + + // ‘¬“x•\Ž¦•”‚Ì”wŒi‚ð”’‚­‚·‚é + SolidBrush b(Color(180,255,255,255)); + backGra->FillRectangle(&b, posX, posY, 200, 14); + // ƒtƒHƒ“ƒgÝ’è + Font font(L"‚l‚r ‚oƒSƒVƒbƒN",10); + // •¶ŽšF + SolidBrush strBrush(Color::Black); + // •¶Žš—ñì¬ + char tmp[256]; + sprintf(tmp, "R:%.1fkbps S:%.1fkbps", + BYTES_TO_KBPS(stats.getPerSecond(Stats::BYTESIN)-stats.getPerSecond(Stats::LOCALBYTESIN)), + BYTES_TO_KBPS(stats.getPerSecond(Stats::BYTESOUT)-stats.getPerSecond(Stats::LOCALBYTESOUT))); + _bstr_t bstr(tmp); + // •¶Žš•\Ž¦”͈͎w’è + StringFormat format; + format.SetAlignment(StringAlignmentCenter); + RectF r((REAL)posX, (REAL)posY, (REAL)200, (REAL)14); + // •¶Žš•`‰æ + gra->DrawString(bstr, -1, &font, r, &format, &strBrush); + + + + return posY + 15; +} + +void MakeBack(HWND hwnd, UINT x, UINT y){ + MakeBackLock.on(); + + winWidth = x; + winHeight = y; + + if (backGra){ + ::delete backBmp; + ::delete backGra; + } + + backBmp = ::new Bitmap(x,y); + backGra = ::new Graphics(backBmp); + + // ‘S‚Ä”’‚Å“h‚è‚‚Ԃµ + SolidBrush b(Color(255,255,255,255)); + backGra->FillRectangle(&b, 0, 0, x, y); + + backWidth = backImage->GetWidth(); + backHeight = backImage->GetHeight(); + + // ”wŒi‰æ‘œ‚ð•`‰æ + for (UINT xx = 0; xx < x/backWidth + 1; xx++){ + for (UINT yy = 0; yy < y/backHeight + 1; yy++){ + UINT width,height; + if (backWidth*(xx+1) > x){ + width = x % backWidth; + } else { + width = backWidth; + } + if (backHeight*(yy+1) > y){ + height = y % backHeight; + } else { + height = backHeight; + } + Rect r((INT)backWidth*xx, (INT)backHeight*yy, width, height); + backGra->DrawImage(backImage, r, 0, 0, (INT)width, (INT)height, UnitPixel); + } + } + + INT posX = 20; + INT posY = 20; + + // ‘¬“x•`‰æ + drawSpeed(backGra, winWidth-205, 5); + + // ƒ`ƒƒƒ“ƒlƒ‹î•ñ‚ð•`‰æ + ChannelDataLock.on(); + ChannelData *cd = channelDataTop; + while(cd){ + posY = cd->drawChannel(backGra, 20, posY); + cd = cd->getNextData(); + } + ChannelDataLock.off(); + MakeBackLock.off(); +} + +void MakeBack(HWND hwnd){ + MakeBack(hwnd, winWidth, winHeight); + ::InvalidateRect(guiWnd, NULL, FALSE); +} + +void ChannelData::setData(Channel *c){ + String sjis; + sjis = c->getName(); + sjis.convertTo(String::T_SJIS); + + strncpy(name, sjis, 256); + name[256] = '\0'; + channel_id = c->channel_id; + bitRate = c->info.bitrate; + lastPlayStart = c->info.lastPlayStart; + status = c->status; + totalListeners = c->totalListeners(); + totalRelays = c->totalRelays(); + localListeners = c->localListeners(); + localRelays = c->localRelays(); + stayConnected = c->stayConnected; + chDisp = c->chDisp; + bTracker = c->sourceHost.tracker; + lastSkipTime = c->lastSkipTime; + skipCount = c->skipCount; +} + +int gW = 0; +int gWS = 0; + +int ChannelData::drawChannel(Graphics *g, int x, int y){ + REAL xx = x * 1.0f; + REAL yy = y * 1.0f; + ServentData* sd; + + // ˆÊ’u‚ð•Û‘¶ + posX = x; + posY = y; + + int w,h; + + if (getWidth() == 0){ + if (gW){ + w = gW; + } else { + w = 400; + } + } else { + w = getWidth(); + gW = w; + } + + // ƒ`ƒƒƒ“ƒlƒ‹•\Ž¦•”‚Ì”wŒi‚ð“h‚é + if (isSelected()){ + // ‘I‘ð’† + SolidBrush b(Color(160,49,106,197)); + g->FillRectangle(&b, x, y, w, 14); + } else { + // ”ñ‘I‘ð + SolidBrush b(Color(160,255,255,255)); + g->FillRectangle(&b, x, y, w, 14); + } + + // ƒXƒe[ƒ^ƒX•\Ž¦ + Gdiplus::Image *img = NULL; + unsigned int nowTime = sys->getTime(); + switch(this->getStatus()){ + case Channel::S_IDLE: + img = img_idle; + break; + case Channel::S_SEARCHING: + case Channel::S_CONNECTING: + img = img_connect; + break; + case Channel::S_RECEIVING: + if ((skipCount > 2) && (lastSkipTime + 120 > nowTime)){ + if (chDisp.relay){ + img = img_conn_ok_skip; + } else { + if (chDisp.numRelays){ + img = img_conn_full_skip; + } else { + img = img_conn_over_skip; + } + } + } else { + if (chDisp.relay){ + img = img_conn_ok; + } else { + if (chDisp.numRelays){ + img = img_conn_full; + } else { + img = img_conn_over; + } + } + } + break; + case Channel::S_BROADCASTING: + img = img_broad_ok; + break; + case Channel::S_ERROR: + img = img_error; + break; + default: + img = img_idle; + break; + } + // •`‰æŠî“_ + PointF origin(xx, yy); + // ƒXƒe[ƒ^ƒX•\Ž¦ˆÊ’u + Rect img_rect((INT)origin.X, (INT)origin.Y + 1, img ? img->GetWidth() : 12, 12); + // ƒXƒe[ƒ^ƒX•`‰æ + ImageAttributes att; +// att.SetColorKey(Color::White, Color::White, ColorAdjustTypeBitmap); + g->DrawImage(img, img_rect, 0, 0, img_rect.Width, 12, UnitPixel, &att); + // ŽŸ‚ÌŠî“_ + origin.X += img_rect.Width; + + // ƒtƒHƒ“ƒgÝ’è + Gdiplus::Font font(L"‚l‚r ‚oƒSƒVƒbƒN",10); + // •¶ŽšF + SolidBrush *strBrush; + if (servMgr->getFirewall() == ServMgr::FW_ON){ + strBrush = ::new SolidBrush(Color::Red); + } else if (isTracker() && (getStatus() == Channel::S_RECEIVING)){ + strBrush = ::new SolidBrush(Color::Green); + } else { + if (isSelected()){ + // ‘I‘ð’† + strBrush = ::new SolidBrush(Color::White); + } else { + // ”ñ‘I‘ð + strBrush = ::new SolidBrush(Color::Black); + } + } + // ƒ`ƒƒƒ“ƒlƒ‹–¼•\Ž¦ + g->SetTextRenderingHint(TextRenderingHintAntiAlias); + _bstr_t bstr1(getName()); + // •¶Žš•`‰æ”͈͎w’è + RectF r1(origin.X, origin.Y, 120.0f, 13.0f); + StringFormat format; + format.SetAlignment(StringAlignmentNear); + g->DrawString(bstr1, -1, &font, r1, &format, strBrush); + // ŽŸ‚ÌŠî“_ + origin.X += r1.Width; + + // ƒŠƒXƒi[”/ƒŠƒŒ[”•\Ž¦ + char tmp[256]; + sprintf(tmp, "%d/%d - [%d/%d]", getTotalListeners(), getTotalRelays(), getLocalListeners(), getLocalRelays()); + _bstr_t bstr2(tmp); + // •¶Žš•\Ž¦”͈͎w’è + RectF r2(origin.X, origin.Y, 100.0f, 13.0f); + format.SetAlignment(StringAlignmentCenter); + g->DrawString(bstr2, -1, &font, r2, &format, strBrush); + // ŽŸ‚ÌŠî“_ + origin.X += r2.Width; + + // bps•\Ž¦ + Font *f; + if (isStayConnected()){ + f = ::new Font(L"Arial", 9.0f, FontStyleItalic|FontStyleBold, UnitPoint); + } else { + f = ::new Font(L"Arial", 9.0f); + } + sprintf(tmp, "%dkbps", getBitRate()); + _bstr_t bstr3(tmp); + format.SetAlignment(StringAlignmentFar); + // •¶Žš•\Ž¦”͈͎w’è + RectF r3(origin.X, origin.Y, 80.0f, 13.0f); + g->DrawString(bstr3, -1, f, r3, &format, strBrush); + // ƒtƒHƒ“ƒgŠJ•ú + ::delete f; + + // ŽŸ‚ÌŠî“_ + origin.X += r3.Width; + + // ƒuƒ‰ƒVíœ + ::delete strBrush; + + + // Servent•\Ž¦ + if (!openFlg){ + int count = getServentCount(); + // Servent•\Ž¦•”‚Ì”wŒi‚ð”’‚É‚·‚é + SolidBrush b(Color(160,255,255,255)); + g->FillRectangle(&b, (INT)origin.X, (INT)origin.Y, 14*count, 14); + + sd = serventDataTop; + int index = 0; + while(sd){ + SolidBrush *serventBrush; + if (sd->getInfoFlg()){ + ChanHit *hit = sd->getChanHit(); + if (hit->firewalled){ + SolidBrush bb(Color(180,255,0,0)); + g->FillRectangle(&bb, (INT)origin.X + 14*index, (INT)origin.Y, 14, 14); + } + if (hit->relay){ + // ƒŠƒŒ[‚n‚j + serventBrush = ::new SolidBrush(Color::Green); + } else { + // ƒŠƒŒ[•s‰Â + if (hit->numRelays){ + // ƒŠƒŒ[ˆê”t + serventBrush = ::new SolidBrush(Color::Blue); + } else { + // ƒŠƒŒ[‚È‚µ + serventBrush = ::new SolidBrush(Color::Purple); + } + } + } else { + // î•ñ‚È‚µ + serventBrush = ::new SolidBrush(Color::Black); + } + // ŽlŠp•`‰æ + backGra->FillRectangle(serventBrush, (INT)origin.X + index*14 + 1, (INT)origin.Y + 1, 12, 12); + + ::delete serventBrush; + sd = sd->getNextData(); + index++; + } + } + + // ŽŸ‚ÌŠî“_ + origin.Y += 15; + + // ƒTƒCƒY‚ð•Û‘¶ + setWidth((int)origin.X - posX); + setHeight((int)origin.Y - posY); + + // ServentData•\Ž¦ + sd = serventDataTop; + while(sd){ + if (openFlg || sd->getSelected()){ + sd->drawServent(g, (INT)x+12, (INT)origin.Y); + // ŽŸ‚ÌŠî“_ + origin.Y += 15; + } + sd = sd->getNextData(); + } + + + return (int)(origin.Y); +} + +bool ChannelData::checkDown(int x,int y){ + // ”͈͓àƒ`ƒFƒbƒN + if ( + (x > posX) + && (x < posX + getWidth()) + && (y > posY) + && (y < posY + getHeight()) + ){ + return TRUE; + } + return FALSE; +} + +ServentData *ChannelData::findServentData(int servent_id){ + ServentData *sv = serventDataTop; + while(sv){ + if (sv->getServentId() == servent_id){ + return sv; + } + sv = sv->getNextData(); + } + return NULL; +} + +void ChannelData::addServentData(ServentData *sd){ + sd->setNextData(serventDataTop); + serventDataTop = sd; +} + +void ChannelData::deleteDisableServents(){ + ServentData *sd = serventDataTop; + ServentData *prev = NULL; + + while(sd){ + if (!(sd->getEnableFlg())){ + ServentData *next = sd->getNextData(); + if (prev){ + prev->setNextData(next); + } else { + serventDataTop = next; + } + ::delete sd; + sd = next; + } else { + prev = sd; + sd = sd->getNextData(); + } + } +} + +int ChannelData::getServentCount(){ + int ret = 0; + + ServentData *sd = serventDataTop; + while(sd){ + ret++; + sd = sd->getNextData(); + } + return ret; +} + +bool ChannelData::setName(int servent_id, String name){ + ServentData *sd = serventDataTop; + while(sd){ + if (sd->getServentId() == servent_id){ + sd->setName(name); + return TRUE; + } + sd = sd->getNextData(); + } + return FALSE; +} + +void ServentData::setData(Servent *s, ChanHit *hit, unsigned int listeners, unsigned int relays, bool f){ + servent_id = s->servent_id; + type = s->type; + status = s->status; + lastSkipTime = s->lastSkipTime; + host = s->getHost(); + + chanHit.numRelays = hit->numRelays; + chanHit.relay = hit->relay; + chanHit.firewalled = hit->firewalled; + chanHit.version = hit->version; + chanHit.version_vp = hit->version_vp; + chanHit.version_ex_number = hit->version_ex_number; + chanHit.version_ex_prefix[0] = hit->version_ex_prefix[0]; + chanHit.version_ex_prefix[1] = hit->version_ex_prefix[1]; + + totalListeners = listeners; + totalRelays = relays; + + infoFlg = f; +} + +int ServentData::drawServent(Gdiplus::Graphics *g, int x, int y){ + REAL xx = x * 1.0f; + REAL yy = y * 1.0f; + int w,h; + + // ˆÊ’u‚ð•Û‘¶ + posX = x; + posY = y; + + if (getWidth() == 0){ + if (gWS){ + w = gWS; + } else { + w = 400; + } + } else { + w = getWidth(); + gWS = w; + } + + // •`‰æŠî“_ + PointF origin(xx, yy); + + // ƒtƒHƒ“ƒgÝ’è + Font font(L"‚l‚r ‚oƒSƒVƒbƒN",9); + // •¶ŽšF + SolidBrush *strBrush; + if (chanHit.firewalled){ + strBrush = ::new SolidBrush(Color::Red); + } else { + if (getSelected()){ + // ‘I‘ð’† + strBrush = ::new SolidBrush(Color::White); + } else { + // ”ñ‘I‘ð + strBrush = ::new SolidBrush(Color::Black); + } + } + // ServantData•\Ž¦ + g->SetTextRenderingHint(TextRenderingHintAntiAlias); + // •¶Žš—ñì¬ + char tmp[256]; + char host1[256]; + host.toStr(host1); + + if (infoFlg){ + if (chanHit.version_ex_number){ + // Šg’£ƒo[ƒWƒ‡ƒ“ + sprintf(tmp, "%c%c%04d - %d/%d - %s(%s)", + chanHit.version_ex_prefix[0], + chanHit.version_ex_prefix[1], + chanHit.version_ex_number, + totalListeners, + totalRelays, + host1, + hostname.cstr() + ); + } else if (chanHit.version_vp){ + sprintf(tmp, "VP%04d - %d/%d - %s(%s)", + chanHit.version_vp, + totalListeners, + totalRelays, + host1, + hostname.cstr() + ); + } else { + sprintf(tmp, "(-----) - %d/%d - %s(%s)", + totalListeners, + totalRelays, + host1, + hostname.cstr() + ); + } + } else { + sprintf(tmp, "(-----) - %d/%d - %s(%s)", + totalListeners, + totalRelays, + host1, + hostname.cstr() + ); + } + _bstr_t bstr1(tmp); + + // ƒXƒe[ƒ^ƒX•\Ž¦ + Gdiplus::Image *img = NULL; + unsigned int nowTime = sys->getTime(); + switch(getStatus()){ + case Servent::S_CONNECTING: + img = img_connect; + break; + case Servent::S_CONNECTED: + if (lastSkipTime + 120 > nowTime){ + if (chanHit.relay){ + img = img_conn_ok_skip; + } else { + if (chanHit.numRelays){ + img = img_conn_full_skip; + } else { + img = img_conn_over_skip; + } + } + } else { + if (chanHit.relay){ + img = img_conn_ok; + } else { + if (chanHit.numRelays){ + img = img_conn_full; + } else { + img = img_conn_over; + } + } + } + break; + default: + break; + } + + // •¶Žš•`‰æ”͈͎w’è + RectF r1(origin.X + img->GetWidth() + 2, origin.Y, 800.0f, 13.0f); + RectF r2; + StringFormat format; + format.SetAlignment(StringAlignmentNear); + g->MeasureString(bstr1, -1, &font, r1, &format, &r2); + + w = (INT)r2.Width + img->GetWidth() + 2; + // ServentData•\Ž¦•”‚Ì”wŒi‚ð“h‚é + if (getSelected()){ + // ‘I‘ð’† + SolidBrush b(Color(160,49,106,197)); + g->FillRectangle(&b, x, y, w, 13); + } else { + // ”ñ‘I‘ð + SolidBrush b(Color(160,200,200,200)); + g->FillRectangle(&b, x, y, w, 13); + } + + // ƒXƒe[ƒ^ƒX•\Ž¦ˆÊ’u + Rect img_rect((INT)origin.X, (INT)origin.Y+1, img ? img->GetWidth() : 12, 12); + // ƒXƒe[ƒ^ƒX•`‰æ + ImageAttributes att; +// att.SetColorKey(Color::White, Color::White, ColorAdjustTypeBitmap); + g->DrawImage(img, img_rect, 0, 0, img_rect.Width, 12, UnitPixel, &att); + // ŽŸ‚ÌŠî“_ + origin.X += 12; + + g->DrawString(bstr1, -1, &font, r2, &format, strBrush); + // ŽŸ‚ÌŠî“_ + origin.X += r2.Width; + origin.Y += 13; + + setWidth((int)origin.X-posX); + setHeight((int)origin.Y - posY); + + ::delete strBrush; + return 0; +} + +bool ServentData::checkDown(int x, int y){ + if ( + (x > posX) + && (x < posX + getWidth()) + && (y > posY) + && (y < posY + getHeight()) + ){ + return TRUE; + } + return FALSE; +} + + +THREAD_PROC GUIDataUpdate(ThreadInfo *thread){ + int i; + + // set GUI thread status to running + thread->finish = false; + + while(thread->active){ + // ƒ`ƒƒƒ“ƒlƒ‹ƒf[ƒ^ƒƒbƒN + ChannelDataLock.on(); + // ƒ`ƒƒƒ“ƒlƒ‹ƒf[ƒ^‚̍XVƒtƒ‰ƒO‚ð‘S‚ÄFALSE‚É‚·‚é + ChannelData *cd = channelDataTop; + while(cd){ + // Servent‚̍XVƒtƒ‰ƒO‚ðFALSE‚É‚·‚é + ServentData *sv = cd->getServentDataTop(); + while(sv){ + sv->setEnableFlg(FALSE); + sv = sv->getNextData(); + } + cd->setEnableFlg(FALSE); + cd = cd->getNextData(); + } + + Channel *c = chanMgr->channel; + // Œ»Ý‘¶Ý‚·‚éƒ`ƒƒƒ“ƒlƒ‹•ªƒ‹[ƒv + while(c){ + // Šù‚Ƀ`ƒƒƒ“ƒlƒ‹ƒf[ƒ^‚ðŽ‚Á‚Ä‚¢‚é‚© + cd = channelDataTop; + // ”­Œ©ƒtƒ‰ƒOFALSE + bool bFoundFlg = FALSE; + while(cd){ + if (cd->getChannelId() == c->channel_id){ + //Šù‚Ƀ`ƒƒƒ“ƒlƒ‹ƒf[ƒ^‚ª‚ ‚é‚̂ŁA‚»‚̂܂܍XV + cd->setData(c); + // XVƒtƒ‰ƒOTRUE + cd->setEnableFlg(TRUE); + // ”­Œ©ƒtƒ‰ƒOTRUE + bFoundFlg = TRUE; + // ƒ‹[ƒv—£’E + break; + } + // Œ©‚‚©‚ç‚È‚©‚Á‚½ê‡AŽŸ‚̃f[ƒ^‚ðƒ`ƒFƒbƒN + cd = cd->getNextData(); + } + + // V‚µ‚¢ƒ`ƒƒƒ“ƒlƒ‹‚̏ꍇAV‹Kƒf[ƒ^ì¬ + if (!bFoundFlg){ + // V‹Kƒf[ƒ^ì¬ + cd = ::new ChannelData(); + // ƒf[ƒ^XV + cd->setData(c); + // XVƒtƒ‰ƒOTRUE + cd->setEnableFlg(TRUE); + + // V‹Kƒf[ƒ^‚ðƒŠƒXƒg‚̐擪‚É“ü‚ê‚é + cd->setNextData(channelDataTop); + channelDataTop = cd; + } + // ŽŸ‚̃`ƒƒƒ“ƒlƒ‹‚ðŽæ“¾ + c = c->next; + } + + // ƒ`ƒƒƒ“ƒlƒ‹‚ª‚È‚­‚È‚Á‚Ä‚¢‚éê‡‚̏ˆ— + cd = channelDataTop; + ChannelData *prev = NULL; + while(cd){ + // ƒf[ƒ^‚ðXV‚µ‚È‚©‚Á‚½‚© + if (cd->getEnableFlg() == FALSE){ + // ƒ`ƒƒƒ“ƒlƒ‹‚ª‚È‚­‚È‚Á‚Ä‚¢‚é‚̂ō폜 + ChannelData *next; + next = cd->getNextData(); + if (!prev){ + // æ“ª‚̃f[ƒ^‚ðíœ + channelDataTop = next; + } else { + // “r’†‚̃f[ƒ^‚ðíœ + prev->setNextData(next); + } + // ŽŸ‚̃f[ƒ^‚Ö + cd = next; + } else { + // ƒf[ƒ^XVÏFŽŸ‚̃f[ƒ^‚Ö + prev = cd; + cd = cd->getNextData(); + } + } + + Servent *s = servMgr->servents; + while(s){ + // ‰Šú‰» + ChanHitList *chl; + bool infoFlg = false; + bool relay = true; + bool firewalled = false; + unsigned int numRelays = 0; + int vp_ver = 0; + char ver_ex_prefix[2] = {' ',' '}; + int ver_ex_number = 0; + // ’¼‰ºƒzƒXƒgî•ñƒ`ƒFƒbƒN + unsigned int totalRelays = 0; + unsigned int totalListeners = 0; + + ChanHit hitData; + // ŽóM’†‚© + if ((s->type == Servent::T_RELAY) && (s->status == Servent::S_CONNECTED)){ + // ƒzƒXƒgî•ñƒƒbƒN + chanMgr->hitlistlock.on(); + // ’¼‰ºƒzƒXƒg‚ªŽóM‚µ‚Ä‚¢‚éƒ`ƒƒƒ“ƒlƒ‹‚̃zƒXƒgî•ñ‚ðŽæ“¾ + chl = chanMgr->findHitListByID(s->chanID); + // ƒ`ƒƒƒ“ƒlƒ‹‚̃zƒXƒgî•ñ‚ª‚ ‚é‚© + if (chl){ + // ƒ`ƒƒƒ“ƒlƒ‹‚̃zƒXƒgî•ñ‚ª‚ ‚éê‡ + ChanHit *hit = chl->hit; + //@ƒ`ƒƒƒ“ƒlƒ‹‚̃zƒXƒgî•ñ‚ð‘S‘–¸‚µ‚Ä + while(hit){ + // ID‚ª“¯‚¶‚à‚Ì‚Å‚ ‚ê‚Î + if (hit->servent_id == s->servent_id){ + // ƒg[ƒ^ƒ‹ƒŠƒŒ[‚ƃg[ƒ^ƒ‹ƒŠƒXƒi[‚ð‰ÁŽZ + totalRelays += hit->numRelays; + totalListeners += hit->numListeners; + // ’¼‰º‚Å‚ ‚ê‚Î + if (hit->numHops == 1){ + // î•ñ‚ðˆê’U•Û‘¶ + infoFlg = true; + hitData.relay = hit->relay; + hitData.firewalled = hit->firewalled; + hitData.numRelays = hit->numRelays; + hitData.version_vp = hit->version_vp; + hitData.version_ex_prefix[0] = hit->version_ex_prefix[0]; + hitData.version_ex_prefix[1] = hit->version_ex_prefix[1]; + hitData.version_ex_number = hit->version_ex_number; + } + } + // ŽŸ‚ðƒ`ƒFƒbƒN + hit = hit->next; + } + } + + // ƒ`ƒƒƒ“ƒlƒ‹ƒf[ƒ^‚©‚çServent‚ðŒŸõ + bool bFoundFlg = FALSE; + cd = channelDataTop; + while(cd){ + ServentData *sv = cd->findServentData(s->servent_id); + // ServentData‚ª‚ ‚ê‚Î + if (sv){ + // ƒf[ƒ^Ý’è + sv->setData(s, &hitData, totalListeners, totalRelays, infoFlg); + sv->setEnableFlg(TRUE); + bFoundFlg = TRUE; + break; + } + cd = cd->getNextData(); + } + // ServentData‚ªŒ©‚‚©‚ç‚È‚©‚Á‚½ê‡ + if (!bFoundFlg){ + // ƒ`ƒƒƒ“ƒlƒ‹ƒf[ƒ^‚ð’T‚· + cd = channelDataTop; + while(cd){ + // ƒ`ƒƒƒ“ƒlƒ‹ID‚ª“¯‚¶‚© + if (cd->getChannelId() == s->channel_id){ + // ƒf[ƒ^Ý’è + ServentData *sv = ::new ServentData(); + sv->setData(s, &hitData, totalListeners, totalRelays, infoFlg); + sv->setEnableFlg(TRUE); + // ƒ`ƒƒƒ“ƒlƒ‹ƒf[ƒ^‚ÉServentData’ljÁ + cd->addServentData(sv); + // ƒzƒXƒg–¼‚ðŽæ“¾‚·‚é + IdData *id = ::new IdData(cd->getChannelId(), sv->getServentId(), sv->getHost().ip); + ThreadInfo t; + t.func = GetHostName; + t.data = (void*)id; + sys->startThread(&t); + // ƒ‹[ƒvI—¹ + break; + } + // ŽŸ‚̃f[ƒ^‚Ö + cd = cd->getNextData(); + } + } + // ƒzƒXƒgî•ñƒAƒ“ƒƒbƒN + chanMgr->hitlistlock.off(); + } + s = s->next; + } + + // XV‚µ‚Ä‚¢‚È‚¢ServentData‚ðíœ + cd = channelDataTop; + while(cd){ + cd->deleteDisableServents(); + cd = cd->getNextData(); + } + + // ƒ`ƒƒƒ“ƒlƒ‹ƒf[ƒ^ƒAƒ“ƒƒbƒN + ChannelDataLock.off(); + + // •`‰æXV + if (guiWnd){ + MakeBack(guiWnd); + } + + // 0.1•b~10‚Å1•b‘Ò‚¿ + for(i=0; i<10; i++) + { + if (!thread->active) + break; + sys->sleep(100); + } + + if (gbGetFile && (sys->getTime() > gtGetFile)){ + gbGetFile = false; + gtiGetFile.func = GetInternetFile; + gtiGetFile.data = NULL; + sys->startThread(>iGetFile); + } + else if (gbStart && (sys->getTime() > gtStartTime)){ + gbStart = false; + SendMessage(guiWnd, WM_START, 0, 0); + gtiStart.func = FestivalStart; + gtiStart.data = NULL; + sys->startThread(>iStart); + } + } + + // set GUI thread status to terminated + thread->finish = true; + + return 0; +} + +ChannelData *findChannelData(int channel_id){ + ChannelData *cd = channelDataTop; + + while(cd){ + if (cd->getChannelId() == channel_id){ + return cd; + } + cd = cd->getNextData(); + } + + return NULL; +} + + +void PopupChannelMenu(int channel_id){ + POINT pos; + MENUITEMINFO info, separator; + HMENU hMenu; + DWORD dwID; + + hMenu = CreatePopupMenu(); + + memset(&separator, 0, sizeof(MENUITEMINFO)); + separator.cbSize = sizeof(MENUITEMINFO); + separator.fMask = MIIM_ID | MIIM_TYPE; + separator.fType = MFT_SEPARATOR; + separator.wID = 8000; + + memset(&info, 0, sizeof(MENUITEMINFO)); + info.cbSize = sizeof(MENUITEMINFO); + info.fMask = MIIM_ID | MIIM_TYPE; + info.fType = MFT_STRING; + + ChannelData *cd = findChannelData(channel_id); + + if (cd == NULL){ + return; + } + + info.wID = 1001; + info.dwTypeData = "Ø’f"; + InsertMenuItem(hMenu, -1, true, &info); + + InsertMenuItem(hMenu, -1, true, &separator); + + info.wID = 1000; + info.dwTypeData = "Ä¶"; + InsertMenuItem(hMenu, -1, true, &info); + + InsertMenuItem(hMenu, -1, true, &separator); + + info.wID = 1002; + info.dwTypeData = "ÄÚ‘±"; + InsertMenuItem(hMenu, -1, true, &info); + + info.wID = 1003; + info.dwTypeData = "ƒL[ƒv"; + InsertMenuItem(hMenu, -1, true, &info); + + InsertMenuItem(hMenu, -1, true, &separator); + + if (!cd->getOpenFlg()){ + info.wID = 1004; + info.dwTypeData = "’¼‰º•\Ž¦"; + InsertMenuItem(hMenu, -1, true, &info); + } else { + info.wID = 1005; + info.dwTypeData = "’¼‰º‰B•Á"; + InsertMenuItem(hMenu, -1, true, &info); + } + + GetCursorPos(&pos); + dwID = TrackPopupMenu(hMenu, TPM_LEFTALIGN|TPM_RETURNCMD, pos.x, pos.y, 0, guiWnd, NULL); + + DestroyMenu(hMenu); + + cd = findChannelData(channel_id); + + if (cd == NULL){ + return; + } + + Channel *c = chanMgr->findChannelByChannelID(channel_id); + + if (c == NULL){ + return; + } + + switch(dwID){ + case 1000: // Ä¶ + chanMgr->playChannel(c->info); + break; + + case 1001: // Ø’f + c->thread.active = false; + c->thread.finish = true; + break; + + case 1002: // ÄÚ‘± + c->bump = true; + break; + + case 1003: // ƒL[ƒv + if (!c->stayConnected){ + c->stayConnected = true; + } else { + c->stayConnected = false; + } + break; + + case 1004: // ’¼‰º•\Ž¦ + cd->setOpenFlg(TRUE); + MakeBack(guiWnd); + break; + + case 1005: // ’¼‰º‰B•Á + cd->setOpenFlg(FALSE); + MakeBack(guiWnd); + break; + } +} + +void PopupServentMenu(int servent_id){ + POINT pos; + MENUITEMINFO info, separator; + HMENU hMenu; + DWORD dwID; + + hMenu = CreatePopupMenu(); + + memset(&separator, 0, sizeof(MENUITEMINFO)); + separator.cbSize = sizeof(MENUITEMINFO); + separator.fMask = MIIM_ID | MIIM_TYPE; + separator.fType = MFT_SEPARATOR; + separator.wID = 8000; + + memset(&info, 0, sizeof(MENUITEMINFO)); + info.cbSize = sizeof(MENUITEMINFO); + info.fMask = MIIM_ID | MIIM_TYPE; + info.fType = MFT_STRING; + + ServentData *sd = NULL; + ChannelData *cd = channelDataTop; + while(cd){ + sd = cd->findServentData(servent_id); + if (sd){ + break; + } + cd = cd->getNextData(); + } + + if (cd == NULL || sd == NULL){ + return; + } + + info.wID = 1001; + info.dwTypeData = "Ø’f"; + InsertMenuItem(hMenu, -1, true, &info); + +// InsertMenuItem(hMenu, -1, true, &separator); + + GetCursorPos(&pos); + dwID = TrackPopupMenu(hMenu, TPM_LEFTALIGN|TPM_RETURNCMD, pos.x, pos.y, 0, guiWnd, NULL); + + DestroyMenu(hMenu); + + cd = channelDataTop; + while(cd){ + sd = cd->findServentData(servent_id); + if (sd){ + break; + } + cd = cd->getNextData(); + } + + if (cd == NULL || sd == NULL){ + return; + } + + Servent *s = servMgr->findServentByServentID(servent_id); + + if (s == NULL){ + return; + } + + switch(dwID){ + case 1001: // Ø’f + s->thread.active = false; + break; + + } +} + +void PopupOtherMenu(){ + POINT pos; + MENUITEMINFO info, separator; + HMENU hMenu; + DWORD dwID; + + hMenu = CreatePopupMenu(); + + memset(&separator, 0, sizeof(MENUITEMINFO)); + separator.cbSize = sizeof(MENUITEMINFO); + separator.fMask = MIIM_ID | MIIM_TYPE; + separator.fType = MFT_SEPARATOR; + separator.wID = 8000; + + memset(&info, 0, sizeof(MENUITEMINFO)); + info.cbSize = sizeof(MENUITEMINFO); + info.fMask = MIIM_ID | MIIM_TYPE; + info.fType = MFT_STRING; + + if (!gbDispTop){ + info.wID = 1101; + info.dwTypeData = "Å‘O–Ê•\Ž¦"; + InsertMenuItem(hMenu, -1, true, &info); + } else { + info.wID = 1102; + info.dwTypeData = "Å‘O–ʉðœ"; + InsertMenuItem(hMenu, -1, true, &info); + } + + InsertMenuItem(hMenu, -1, true, &separator); + + if (!gbAllOpen){ + info.wID = 1103; + info.dwTypeData = "‘S’¼‰º“WŠJ"; + InsertMenuItem(hMenu, -1, true, &info); + } else { + info.wID = 1104; + info.dwTypeData = "‘S’¼‰º‰B•Á"; + InsertMenuItem(hMenu, -1, true, &info); + } + + InsertMenuItem(hMenu, -1, true, &separator); + + if (!servMgr->autoServe){ + info.wID = 1105; + info.dwTypeData = "—LŒø"; + InsertMenuItem(hMenu, -1, true, &info); + } else { + info.wID = 1106; + info.dwTypeData = "–³Œø"; + InsertMenuItem(hMenu, -1, true, &info); + } + + GetCursorPos(&pos); + dwID = TrackPopupMenu(hMenu, TPM_LEFTALIGN|TPM_RETURNCMD, pos.x, pos.y, 0, guiWnd, NULL); + + DestroyMenu(hMenu); + + ChannelData *cd = channelDataTop; + + switch(dwID){ + case 1101: // Å‘O–Ê•\Ž¦ + gbDispTop = true; + ::SetWindowPos(guiWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE); + break; + + case 1102: // Å‘O–Ê‰ðœ + gbDispTop = false; + ::SetWindowPos(guiWnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE); + break; + + case 1103: // ‘S’¼‰º“WŠJ + gbAllOpen = true; + while(cd){ + cd->setOpenFlg(true); + cd = cd->getNextData(); + } + break; + + case 1104: // ‘S’¼‰º‰B•Á + gbAllOpen = false; + while(cd){ + cd->setOpenFlg(false); + cd = cd->getNextData(); + } + break; + + case 1105: // —LŒø + servMgr->autoServe = true; + break; + + case 1106: // –³Œø + servMgr->autoServe = false; + break; + + } +} + +void WmCreateProc(HWND hwnd){ + if (backImage){ + ::delete backImage; + } + _bstr_t bstr("back.jpg"); + backImage = ::new Image(bstr); + + MakeBack(hwnd, 800, 600); + + guiThread.func = GUIDataUpdate; + if (!sys->startThread(&guiThread)){ + MessageBox(hwnd,"Unable to start GUI","PeerCast",MB_OK|MB_ICONERROR); + PostMessage(hwnd,WM_DESTROY,0,0); + } + if (guiFlg){ + SetWindowPlacement(hwnd, &winPlace); + } + + if (img_idle){ + ::delete img_idle; + ::delete img_connect; + ::delete img_conn_ok; + ::delete img_conn_full; + ::delete img_conn_over; + ::delete img_conn_ok_skip; + ::delete img_conn_full_skip; + ::delete img_conn_over_skip; + ::delete img_error; + ::delete img_broad_ok; + ::delete img_broad_full; + } + bstr = L"ST_IDLE.bmp"; + img_idle = ::new Image(bstr); + bstr = L"ST_CONNECT.bmp"; + img_connect = ::new Image(bstr); + bstr = L"ST_CONN_OK.bmp"; + img_conn_ok = ::new Image(bstr); + bstr = L"ST_CONN_FULL.bmp"; + img_conn_full = ::new Image(bstr); + bstr = L"ST_CONN_OVER.bmp"; + img_conn_over = ::new Image(bstr); + bstr = L"ST_CONN_OK_SKIP.bmp"; + img_conn_ok_skip = ::new Image(bstr); + bstr = L"ST_CONN_FULL_SKIP.bmp"; + img_conn_full_skip = ::new Image(bstr); + bstr = L"ST_CONN_OVER_SKIP.bmp"; + img_conn_over_skip = ::new Image(bstr); + bstr = L"ST_ERROR.bmp"; + img_error = ::new Image(bstr); + bstr = L"ST_BROAD_OK.bmp"; + img_broad_ok = ::new Image(bstr); + bstr = L"ST_BROAD_FULL.bmp"; + img_broad_full = ::new Image(bstr); +} + +void WmPaintProc(HWND hwnd){ + HDC hdc; + PAINTSTRUCT paint; + + if (backGra){ + MakeBackLock.on(); + hdc = BeginPaint(hwnd, &paint); + RECT *rcRect; // •`‰æ”ÍˆÍ + rcRect = &(paint.rcPaint); + LONG width = rcRect->right - rcRect->left + 1; + LONG height = rcRect->bottom - rcRect->top + 1; + + Graphics g2(hdc); + Rect r(rcRect->left, rcRect->top, width, height); + g2.DrawImage(backBmp,r, rcRect->left, rcRect->top, width, height, UnitPixel); + EndPaint(hwnd, &paint); + MakeBackLock.off(); + } +} + +void WmSizeProc(HWND hwnd, LPARAM lParam){ + UINT width = LOWORD(lParam); + UINT height = HIWORD(lParam); + + MakeBack(hwnd, width, height); + +} + +void WmLButtonDownProc(HWND hwnd, LPARAM lParam){ + ChannelData *cd; + bool changeFlg = FALSE; + + ChannelDataLock.on(); + cd = channelDataTop; + while(cd){ + int x = LOWORD(lParam); + int y = HIWORD(lParam); + if (cd->checkDown(LOWORD(lParam), HIWORD(lParam))){ + if (!(cd->isSelected())){ + changeFlg = TRUE; + } + cd->setSelected(TRUE); + } else { + if (cd->isSelected()){ + changeFlg = TRUE; + } + cd->setSelected(FALSE); + } + int sx = cd->getPosX() + cd->getWidth(); + int sy = cd->getPosY(); + int index = 0; + ServentData *sd = cd->getServentDataTop(); + while(sd){ + if ( ( (!cd->getOpenFlg()) + && (sx + index*14 < x) + && (x < sx + (index+1)*14) + && (sy < y) + && (y < sy + 14) ) + || sd->checkDown(LOWORD(lParam), HIWORD(lParam)) + ){ + if (!sd->getSelected()){ + changeFlg = TRUE; + } + sd->setSelected(TRUE); + } else { + if (sd->getSelected()){ + changeFlg = TRUE; + } + sd->setSelected(FALSE); + } + sd = sd->getNextData(); + index++; + } + cd = cd->getNextData(); + } + ChannelDataLock.off(); + if (changeFlg){ + MakeBack(hwnd); + } +} + +void WmLButtonDblclkProc(HWND hwnd, LPARAM lParam){ + ChannelData *cd; + bool changeFlg = FALSE; + + ChannelDataLock.on(); + cd = channelDataTop; + while(cd){ + int x = LOWORD(lParam); + int y = HIWORD(lParam); + if (cd->checkDown(LOWORD(lParam), HIWORD(lParam))){ + if (!(cd->isSelected())){ + changeFlg = TRUE; + } + if (!(cd->getOpenFlg())){ + changeFlg = TRUE; + cd->setOpenFlg(TRUE); + } else { + changeFlg = TRUE; + cd->setOpenFlg(FALSE); + } + cd->setSelected(TRUE); + } else { + if (cd->isSelected()){ + changeFlg = TRUE; + } + cd->setSelected(FALSE); + } +/* int sx = cd->getPosX() + cd->getWidth(); + int sy = cd->getPosY(); + int index = 0; + ServentData *sd = cd->getServentDataTop(); + while(sd){ + if ( ( (!cd->getOpenFlg()) + && (sx + index*14 < x) + && (x < sx + (index+1)*14) + && (sy < y) + && (y < sy + 14) ) + || sd->checkDown(LOWORD(lParam), HIWORD(lParam)) + ){ + if (!sd->getSelected()){ + changeFlg = TRUE; + } + sd->setSelected(TRUE); + } else { + if (sd->getSelected()){ + changeFlg = TRUE; + } + sd->setSelected(FALSE); + } + sd = sd->getNextData(); + index++; + }*/ + cd = cd->getNextData(); + } + ChannelDataLock.off(); + if (changeFlg){ + MakeBack(hwnd); + } +} + +void WmRButtonDownProc(HWND hwnd, LPARAM lParam){ + ChannelData *cd; + bool changeFlg = FALSE; + bool channel_selected = FALSE; + bool servent_selected = FALSE; + int channel_id = 0; + int servent_id = 0; + + cd = channelDataTop; + while(cd){ + if (cd->checkDown(LOWORD(lParam), HIWORD(lParam))){ + if (!(cd->isSelected())){ + changeFlg = TRUE; + } + cd->setSelected(TRUE); + channel_id = cd->getChannelId(); + channel_selected = TRUE; + } else { + if (cd->isSelected()){ + changeFlg = TRUE; + } + cd->setSelected(FALSE); + } + ServentData *sd = cd->getServentDataTop(); + while(sd){ + if (sd->checkDown(LOWORD(lParam), HIWORD(lParam))){ + if (!sd->getSelected()){ + changeFlg = TRUE; + } + sd->setSelected(TRUE); + servent_id = sd->getServentId(); + servent_selected = TRUE; + } else { + if (sd->getSelected()){ + changeFlg = TRUE; + } + sd->setSelected(FALSE); + } + sd = sd->getNextData(); + } + cd = cd->getNextData(); + } + if (changeFlg){ + MakeBack(hwnd); + } + + if (channel_selected){ + PopupChannelMenu(channel_id); + } else if (servent_selected){ + PopupServentMenu(servent_id); + } else { + PopupOtherMenu(); + } +} + +LRESULT CALLBACK GUIProc (HWND hwnd, UINT message, + WPARAM wParam, LPARAM lParam) +{ + switch(message){ + case WM_CREATE: // ƒEƒBƒ“ƒhƒEì¬ + WmCreateProc(hwnd); + break; + + case WM_PAINT: // •`‰æ + WmPaintProc(hwnd); + break; + + case WM_SIZE: // ƒTƒCƒY•ÏX + WmSizeProc(hwnd,lParam); + break; + + case WM_LBUTTONDOWN: // ¶ƒ{ƒ^ƒ“‰Ÿ‚· + WmLButtonDownProc(hwnd,lParam); + break; + + case WM_RBUTTONDOWN: // ‰Eƒ{ƒ^ƒ“‰Ÿ‚· + WmRButtonDownProc(hwnd,lParam); + break; + + case WM_LBUTTONDBLCLK: // ¶ƒ_ƒuƒ‹ƒNƒŠƒbƒN + WmLButtonDblclkProc(hwnd,lParam); + break; + + case WM_ERASEBKGND: // ”wŒiÁ‹Ž + return TRUE; // ”wŒi‚͏Á‚³‚È‚¢ + + case WM_CLOSE: + //if (backImage){ + // ::delete backImage; + // backImage = NULL; + //} + GetWindowPlacement(hwnd, &winPlace); + guiFlg = true; + DestroyWindow( hwnd ); + break; + case WM_DESTROY: + GetWindowPlacement(hwnd, &winPlace); + guiFlg = true; + guiThread.active = false; + + // wait until GUI thread terminated, + // and then dispose background image. + while (1) + { + if (guiThread.finish) + break; + } + if (backImage) + { + ::delete backImage; + backImage = NULL; + } + + guiWnd = NULL; + break; + case WM_START: + ghStart = ::CreateWindow(szWindowClass3, + "Peercast-IM@S", + WS_OVERLAPPEDWINDOW & ~(WS_MAXIMIZEBOX), + 0, + 0, + 400, + 300, + NULL, + NULL, + hInst, + NULL); + ::ShowWindow(ghStart, SW_SHOWNORMAL); + break; + + default: + return (DefWindowProc(hwnd, message, wParam, lParam)); + } + + return 0; +} + +Gdiplus::Image *data1 = NULL; +Gdiplus::Image *data2 = NULL; +Gdiplus::Bitmap *startBmp = NULL; +Gdiplus::Graphics *startGra = NULL; +WLock MakeStartLock; + +LRESULT CALLBACK StartProc (HWND hwnd, UINT message, + WPARAM wParam, LPARAM lParam) +{ + SolidBrush b(Color::Black); + bstr_t bstr; + + switch(message){ + case WM_CREATE: + startBmp = ::new Bitmap(400,300); + startGra = ::new Graphics(startBmp); + bstr = L"data1.jpg"; + data1 = ::new Image(bstr); + bstr = L"data2.jpg"; + data2 = ::new Image(bstr); + // •‚Å“h‚è‚‚Ԃµ + startGra->FillRectangle(&b, 0, 0, 400, 300); + break; + case WM_PAINT: + if (startGra){ + HDC hdc; + PAINTSTRUCT paint; + + MakeStartLock.on(); + hdc = BeginPaint(hwnd, &paint); + RECT *rcRect; + rcRect = &(paint.rcPaint); + LONG width = rcRect->right - rcRect->left + 1; + LONG height = rcRect->bottom - rcRect->top + 1; + + Graphics g2(hdc); + Rect r(rcRect->left, rcRect->top, width, height); + g2.DrawImage(startBmp, r, rcRect->left, rcRect->top, width, height, UnitPixel); + EndPaint(hwnd, &paint); + MakeStartLock.off(); + } + break; + case WM_ERASEBKGND: + return TRUE; + case WM_CLOSE: + DestroyWindow(ghStart); + if (startBmp){ + ::delete startBmp; + } + if (startGra){ + ::delete startGra; + } + if (data1){ + ::delete data1; + } + if (data2){ + ::delete data2; + } + break; + + default: + return (DefWindowProc(hwnd, message, wParam, lParam)); + } + + return 0; +} + +THREAD_PROC FestivalStart(ThreadInfo *thread){ + + while(startGra==NULL){ + sys->sleep(100); + } + + sys->sleep(1000); + + MakeStartLock.on(); + Font font(L"‚l‚r ‚oƒSƒVƒbƒN",40); + StringFormat format; + format.SetAlignment(StringAlignmentCenter); + startGra->SetTextRenderingHint(TextRenderingHintAntiAlias); + PointF origin(199.0f,49.0f); + RectF rect(0,0,400,100); + LinearGradientBrush b1(rect, Color::LightSkyBlue, Color::White, LinearGradientModeHorizontal); + startGra->DrawString(L"‘æ‚Q‰ñ", -1, &font, origin, &format, &b1); + origin.Y += 50; + LinearGradientBrush b2(rect, Color::LightGreen, Color::White, LinearGradientModeHorizontal); + startGra->DrawString(L"ƒAƒCƒhƒ‹ƒ}ƒXƒ^[", -1, &font, origin, &format, &b2); + origin.Y += 50; + LinearGradientBrush b3(rect, Color::LightGoldenrodYellow, Color::White, LinearGradientModeHorizontal); + startGra->DrawString(L"ƒtƒ@ƒ“Š´ŽÓÕ", -1, &font, origin, &format, &b3); + MakeStartLock.off(); + InvalidateRect(ghStart, NULL, FALSE); + sys->sleep(3000); + + MakeStartLock.on(); + startGra->DrawImage(data1, Rect(0,0,80,400), 200,200,66,330, UnitPixel); + MakeStartLock.off(); + InvalidateRect(ghStart, NULL, FALSE); + sys->sleep(500); + + MakeStartLock.on(); + startGra->DrawImage(data1, Rect(80,0,80,400), 266,200,66,330, UnitPixel); + MakeStartLock.off(); + InvalidateRect(ghStart, NULL, FALSE); + sys->sleep(500); + + MakeStartLock.on(); + startGra->DrawImage(data1, Rect(160,0,80,400), 332,200,66,330, UnitPixel); + MakeStartLock.off(); + InvalidateRect(ghStart, NULL, FALSE); + sys->sleep(500); + + MakeStartLock.on(); + startGra->DrawImage(data1, Rect(240,0,80,400), 398,200,66,330, UnitPixel); + MakeStartLock.off(); + InvalidateRect(ghStart, NULL, FALSE); + sys->sleep(500); + + MakeStartLock.on(); + startGra->DrawImage(data1, Rect(320,0,80,400), 464,200,66,330, UnitPixel); + MakeStartLock.off(); + InvalidateRect(ghStart, NULL, FALSE); + sys->sleep(500); + + MakeStartLock.on(); + startGra->DrawImage(data1, Rect(0,0,80,400), 530,200,54,270, UnitPixel); + MakeStartLock.off(); + InvalidateRect(ghStart, NULL, FALSE); + sys->sleep(500); + + MakeStartLock.on(); + startGra->DrawImage(data1, Rect(80,0,80,400), 584,200,54,270, UnitPixel); + MakeStartLock.off(); + InvalidateRect(ghStart, NULL, FALSE); + sys->sleep(500); + + MakeStartLock.on(); + startGra->DrawImage(data1, Rect(160,0,80,400), 638,200,54,270, UnitPixel); + MakeStartLock.off(); + InvalidateRect(ghStart, NULL, FALSE); + sys->sleep(500); + + MakeStartLock.on(); + startGra->DrawImage(data1, Rect(240,0,80,400), 692,200,54,270, UnitPixel); + MakeStartLock.off(); + InvalidateRect(ghStart, NULL, FALSE); + sys->sleep(500); + + MakeStartLock.on(); + startGra->DrawImage(data1, Rect(320,0,80,400), 746,200,54,270, UnitPixel); + MakeStartLock.off(); + InvalidateRect(ghStart, NULL, FALSE); + sys->sleep(500); + + for (int i=1; i<=10; i++){ + ColorMatrix mtx = { + 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.1f*i, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}; + ImageAttributes att; + + MakeStartLock.on(); + att.SetColorMatrix(&mtx, ColorMatrixFlagsDefault, ColorAdjustTypeBitmap); + startGra->DrawImage(data2, Rect(0,0,400,300), 360,130,400,300, UnitPixel, &att); + MakeStartLock.off(); + InvalidateRect(ghStart, NULL, FALSE); + sys->sleep(100); + } + + sys->sleep(2000); + + MakeStartLock.on(); + INT style = FontStyleBold; + Font font2(L"‚l‚r ‚oƒSƒVƒbƒN",70,style,UnitPoint); + PointF origin2(199.0f,99.0f); + SolidBrush bs(Color::Black); + startGra->DrawString(L"START!", -1, &font2, origin2, &format, &bs); + Font font3(L"‚l‚r ‚oƒSƒVƒbƒN",70,style,UnitPoint); + LinearGradientBrush bx(rect, Color::LightPink, Color::DeepPink, LinearGradientModeHorizontal); + startGra->DrawString(L"START!", -1, &font3, origin2, &format, &bx); + MakeStartLock.off(); + InvalidateRect(ghStart, NULL, FALSE); + sys->sleep(5000); + + SendMessage(ghStart, WM_CLOSE, 0, 0); + return 0; +} diff --git a/PeerCast.root/PeerCast/ui/win32/simple/gui.h b/PeerCast.root/PeerCast/ui/win32/simple/gui.h new file mode 100644 index 0000000..84e7381 --- /dev/null +++ b/PeerCast.root/PeerCast/ui/win32/simple/gui.h @@ -0,0 +1,228 @@ +// ------------------------------------------------ +// File : gui.h +// Date: 4-apr-2002 +// Author: giles +// +// (c) 2002 peercast.org +// ------------------------------------------------ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// ------------------------------------------------ + +#ifndef _GUI_H +#define _GUI_H + +#include "sys.h" +#include "gdiplus.h" +#include "channel.h" + +extern LRESULT CALLBACK GUIProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); +extern LRESULT CALLBACK StartProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); +extern void ADDLOG(const char *str,int id,bool sel,void *data, LogBuffer::TYPE type); + +extern String iniFileName; +extern HWND guiWnd; +extern int logID; + +enum +{ + WM_INITSETTINGS = WM_USER, + WM_GETPORTNUMBER, + WM_PLAYCHANNEL, + WM_TRAYICON, + WM_SHOWGUI, + WM_SHOWMENU, + WM_PROCURL, + WM_START + +}; + +class IdData +{ +private: + int channel_id; + int servent_id; + unsigned int ip_addr; + +public: + IdData(int cid, int sid, unsigned int ip){ + channel_id = cid; + servent_id = sid; + ip_addr = ip; + } + + int getChannelId(){return channel_id;}; + int getServentId(){return servent_id;}; + unsigned int getIpAddr(){return ip_addr;}; +}; + +class ServentData +{ +private: + int servent_id; + int type; +// unsigned int tnum; + int status; +// String agent; + Host host; + String hostname; +// unsigned int syncpos; +// char *typeStr; +// char *statusStr; +// bool infoFlg; +// bool relay; +// bool firewalled; + unsigned int totalRelays; + unsigned int totalListeners; +// int vp_ver; +// char ver_ex_prefix[2]; +// int ver_ex_number; + + bool EnableFlg; + bool infoFlg; + ServentData *next; + ChanHit chanHit; + bool selected; + int posX; + int posY; + int width; + int height; + + unsigned int lastSkipTime; + unsigned int lastSkipCount; + +public: + ServentData(){ + next = NULL; + EnableFlg = false; + infoFlg = false; + + posX = 0; + posY = 0; + width = 0; + selected = false; + + } + void setData(Servent *s, ChanHit *hit, unsigned int listeners, unsigned int relays, bool infoFlg); + bool getInfoFlg(){return infoFlg;} + ChanHit *getChanHit(){return &chanHit;}; + int getStatus(){return status;}; + Host getHost(){return host;}; + + int getServentId(){return servent_id;}; + + bool getEnableFlg(){return EnableFlg;}; + void setEnableFlg(bool f){EnableFlg = f;}; + ServentData *getNextData(){return next;}; + void setNextData(ServentData *s){next = s;}; + bool getSelected(){return selected;}; + void setSelected(bool f){selected = f; if (!f){posX=0;posY=0;}}; + int getWidth(){return width;}; + void setWidth(int w){width = w;}; + int getHeight(){return height;}; + void setHeight(int h){height = h;}; + String getName(){return hostname;}; + void setName(String n){hostname = n;}; + + int drawServent(Gdiplus::Graphics *g, int x, int y); + + bool checkDown(int x, int y); + +}; + +class ChannelData { + +private: + int channel_id; + char name[257]; + int bitRate; + unsigned int lastPlayStart; + int status; + int totalListeners; + int totalRelays; + int localListeners; + int localRelays; + bool stayConnected; + ChanHit chDisp; + bool bTracker; + unsigned int lastSkipTime; + unsigned int skipCount; + + bool EnableFlg; + ChannelData *next; + + int posX; + int posY; + int width; + int height; + bool selected; + ServentData *serventDataTop; + bool openFlg; + +public: + ChannelData(){ + EnableFlg = FALSE; + next = NULL; + posX = 0; + posY = 0; + width = 0; + height = 0; + selected = FALSE; + serventDataTop = NULL; + openFlg = FALSE; + } + int drawChannel(Gdiplus::Graphics *g, int x, int y); + + void setData(Channel *); + int getChannelId(){return channel_id;}; + char* getName(){return &(name[0]);}; + int getBitRate(){return bitRate;}; + bool isStayConnected(){return stayConnected;}; + bool isTracker(){return bTracker;}; + int getStatus(){return status;}; + unsigned int getLastSkipTime(){return lastSkipTime;}; + + int getTotalListeners(){return totalListeners;}; + int getTotalRelays(){return totalRelays;}; + int getLocalListeners(){return localListeners;}; + int getLocalRelays(){return localRelays;}; + + bool getEnableFlg(){return EnableFlg;}; + void setEnableFlg(bool flg){EnableFlg = flg;}; + ChannelData *getNextData(){return next;}; + void setNextData(ChannelData* cd){next = cd;}; + + int getPosX(){return posX;}; + void setPosX(int x){posX = x;} + int getPosY(){return posY;}; + void setPosY(int y){posY = y;}; + int getWidth(){return width;}; + void setWidth(int w){width = w;}; + int getHeight(){return height;}; + void setHeight(int h){height = h;}; + bool isSelected(){return selected;}; + void setSelected(bool sel){selected = sel;}; + bool getOpenFlg(){return openFlg;}; + void setOpenFlg(bool b){openFlg = b;}; + + ServentData* getServentDataTop(){return serventDataTop;}; + ServentData* findServentData(int servent_id); + void addServentData(ServentData *sd); + void deleteDisableServents(); + + bool setName(int servent_id, String name); + int getServentCount(); + + bool checkDown(int x, int y); +}; + + + +#endif \ No newline at end of file diff --git a/PeerCast.root/PeerCast/ui/win32/simple/resource.h b/PeerCast.root/PeerCast/ui/win32/simple/resource.h new file mode 100644 index 0000000..a9a2b6d --- /dev/null +++ b/PeerCast.root/PeerCast/ui/win32/simple/resource.h @@ -0,0 +1,110 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by Simple.rc +// +#define IDC_MYICON 2 +#define IDD_MAINWINDOW 101 +#define IDD_SIMPLE_DIALOG 102 +#define IDD_ABOUTBOX 103 +#define IDS_APP_TITLE 103 +#define IDM_ABOUT 104 +#define IDM_EXIT 105 +#define IDS_HELLO 106 +#define IDI_SIMPLE 107 +#define IDI_SMALL 108 +#define IDC_SIMPLE 109 +#define IDI_SMALL2 109 +#define IDR_MAINFRAME 128 +#define IDR_TRAYMENU 130 +#define IDR_VERMENU 133 +#define IDD_CHANINFO 136 +#define IDR_LTRAYMENU 137 +#define IDC_LIST1 1000 +#define IDC_BUTTON7 1001 +#define IDC_ABOUTVER 1002 +#define IDC_CHECK1 1003 +#define IDC_EDIT1 1004 +#define IDC_LIST2 1005 +#define IDC_EDIT_PLAYING 1005 +#define IDC_COMBO1 1006 +#define IDC_EDIT_MESSAGE 1006 +#define IDC_CHECK2 1007 +#define IDC_EDIT_NAME 1007 +#define IDC_BUTTON1 1008 +#define IDC_EDIT_DESC 1008 +#define IDC_DETAILS 1009 +#define IDC_MAXRELAYS 1009 +#define IDC_LIST3 1010 +#define IDC_PLAY 1010 +#define IDC_CONTACT 1011 +#define IDC_EDIT2 1012 +#define IDC_FORMAT 1013 +#define IDC_EDIT_GENRE 1014 +#define IDC_KEEP 1015 +#define IDC_EDIT_STATUS 1016 +#define IDC_GROUPBOX_RELAY 1016 +#define IDC_EDIT_LISTENERS 1017 +#define IDC_STATIC_CONNECTION 1017 +#define IDC_LIST4 1018 +#define IDC_EDIT_HOSTS 1018 +#define IDC_STATIC_LOG 1018 +#define IDC_BUTTON4 1019 +#define IDC_BUTTON5 1020 +#define IDC_BUTTON6 1021 +#define IDC_EDIT3 1025 +#define IDC_EDIT5 1027 +#define IDC_LOGDEBUG 1037 +#define IDC_LOGNETWORK 1038 +#define IDC_LOGERRORS 1039 +#define IDC_CHECK9 1041 +#define IDC_BUTTON8 1043 +#define IDC_BUTTON10 1046 +#define IDC_BUTTON11 1047 +#define IDC_LOGCHANNELS 1050 +#define IDC_BUTTON2 1056 +#define IDC_EDIT4 1058 +#define IDC_BUTTON3 1059 +#define IDC_EDIT9 1060 +#define IDC_CHECK11 1061 +#define IDC_BUTTON9 1062 +#define IDM_SETTINGS_GUI 32771 +#define ID_POPUP_ABOUT 32779 +#define ID_POPUP_EXIT_CONFIRM 32781 +#define ID_POPUP_EXIT_NO 32782 +#define ID_POPUP_SETTINGS 32785 +#define ID_POPUP_CONNECTIONS 32786 +#define ID_POPUP_SHOWGUI 32788 +#define ID_POPUP_ALLCHANNELS 32791 +#define ID_POPUP_FAVORITES_EDIT 32792 +#define ID_POPUP_ADVANCED_INFORMATION 32793 +#define ID_POPUP_ADVANCED_SAVESETTINGS 32794 +#define ID_POPUP_UPGRADE 32795 +#define ID_POPUP_HELP 32796 +#define ID_POPUP_ADVANCED_VIEWLOG 32797 +#define ID_POPUP_FAVORITES_PLAYALL 32798 +#define ID_POPUP_ADVANCED_ALLCHANNELS 32799 +#define ID_POPUP_ADVANCED_RELAYEDCHANNELS 32800 +#define ID_POPUP_ADVANCED_BROADCAST 32801 +#define ID_FIND_CHANNELS 32808 +#define ID_POPUP_SHOWMESSAGES_PEERCAST 32814 +#define ID_POPUP_SHOWMESSAGES_BROADCASTERS 32815 +#define ID_POPUP_SHOWMESSAGES_TRACKINFO 32816 +#define ID_POPUP_POPUPMESSAGES_UPGRADEALERTS 32817 +#define ID_POPUP_YELLOWPAGES 32818 +#define ID_POPUP_ADVANCED_SHOWGUI 32819 +#define ID_POPUP_YELLOWPAGES1 32820 +#define ID_POPUP_YELLOWPAGES2 32821 +#define ID_POPUP_SAVE_GUI_POS 32823 +#define ID_POPUP_KEEP_DOWNSTREAMS 32825 +#define IDC_STATIC -1 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 142 +#define _APS_NEXT_COMMAND_VALUE 32826 +#define _APS_NEXT_CONTROL_VALUE 1019 +#define _APS_NEXT_SYMED_VALUE 110 +#endif +#endif diff --git a/PeerCast.root/PeerCast/ui/win32/simple/small1.ico b/PeerCast.root/PeerCast/ui/win32/simple/small1.ico new file mode 100644 index 0000000000000000000000000000000000000000..fa5a5dcd8818b15900cbcef9bed4d88269fcdb31 GIT binary patch literal 318 zcmZvYF%H5o3`Kt>Br|qmX5@I;!bUdK6O`O0+@um0Kw>EpYIttShLiWd<2X?isblng zFOO3v9o)eyN9eRerLyWjNfJ{jHA6`usg%M-U8idG3>aQ=k<5h%VYT1VT4Di5qAbQ> z7PQZK^&#Kb3mWqHG+LU=&Us9J)`qd&9j|nGgw40BrKp7`d@jBr|qmX5@I;!bUd6UMbw95*I*XXpvCObJ}h=dH*|(6Gf3aM&I{} zxOCDf9HMfDP6t$~P5()em?~v8loX0;t!#Lka*qrcQ3{bPgh;8`zO*&5gd*>1DL6F1z|v;;aqRdUw9l6_GaIu9mVEp76a%Gaif|-c9RHB_Cmi1)Tr! J2Rz{|{Q%s#L@@vW literal 0 HcmV?d00001 diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/asf.h b/c:/Git/PeerCast.root/PeerCast/core/common/asf.h new file mode 100644 index 0000000..fcd1e3d --- /dev/null +++ b/c:/Git/PeerCast.root/PeerCast/core/common/asf.h @@ -0,0 +1,290 @@ +// ------------------------------------------------ +// File : asf.h +// Date: 10-apr-2003 +// Author: giles +// +// (c) 2002-3 peercast.org +// ------------------------------------------------ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// ------------------------------------------------ + +#ifndef _ASF_H +#define _ASF_H + + +#include "stream.h" + +// ----------------------------------- +class MSID +{ +public: + + void read(Stream &in) + { + data1 = in.readLong(); + data2 = in.readShort(); + data3 = in.readShort(); + in.read(data4,8); + } + + void write(Stream &out) + { + out.writeLong(data1); + out.writeShort(data2); + out.writeShort(data3); + out.write(data4,8); + } + + + void toString(String &s) + { + sprintf(s.data,"%X-%X-%X-%02X%02X%02X%02X%02X%02X%02X%02X", + data1,data2,data3, + data4[0],data4[1],data4[2],data4[3], + data4[4],data4[5],data4[6],data4[7]); + } + + int operator==(const MSID& msid) const{return !memcmp(this, &msid, sizeof(MSID));} + + unsigned int data1; + unsigned short data2,data3; + unsigned char data4[8]; + +}; + + + + +// ----------------------------------- +const MSID headObjID= + {0x75B22630, 0x668E, 0x11CF, 0xA6,0xD9,0x00,0xAA,0x00,0x62,0xCE,0x6C}; +const MSID dataObjID= + {0x75B22636, 0x668E, 0x11CF, 0xA6,0xD9,0x00,0xAA,0x00,0x62,0xCE,0x6C}; +const MSID filePropObjID= + {0x8CABDCA1, 0xA947, 0x11CF, 0x8E,0xE4,0x00,0xC0,0x0C,0x20,0x53,0x65}; +const MSID streamPropObjID= + {0xB7DC0791, 0xA9B7, 0x11CF, 0x8E,0xE6,0x00,0xC0,0x0C,0x20,0x53,0x65}; + +const MSID audioStreamObjID= + {0xF8699E40, 0x5B4D, 0x11CF, 0xA8,0xFD,0x00,0x80,0x5F,0x5C,0x44,0x2B}; +const MSID videoStreamObjID= + {0xBC19EFC0, 0x5B4D, 0x11CF, 0xA8,0xFD,0x00,0x80,0x5F,0x5C,0x44,0x2B}; + +const MSID streamBitrateObjID= + {0x7BF875CE, 0x468D, 0x11D1, 0x8D,0x82,0x00,0x60,0x97,0xC9,0xA2,0xB2}; + + +// ----------------------------------- +class ASFObject +{ +public: + + enum TYPE + { + T_UNKNOWN, + T_HEAD_OBJECT, + T_DATA_OBJECT, + T_FILE_PROP, + T_STREAM_PROP, + T_STREAM_BITRATE + }; + + int getTotalLen() + { + return 24+dataLen; + } + + unsigned int readHead(Stream &in) + { + id.read(in); + + lenLo = in.readLong(); + lenHi = in.readLong(); + + type = T_UNKNOWN; + if (id == headObjID) + type = T_HEAD_OBJECT; + else if (id == dataObjID) + type = T_DATA_OBJECT; + else if (id == filePropObjID) + type = T_FILE_PROP; + else if (id == streamPropObjID) + type = T_STREAM_PROP; + else if (id == streamBitrateObjID) + type = T_STREAM_BITRATE; + + String str; + id.toString(str); + LOG_DEBUG("ASF: %s (%s)= %d : %d\n",str.data,getTypeName(),lenLo,lenHi); + + + dataLen = 0; + + return lenLo-24; + } + + void readData(Stream &in,int len) + { + dataLen = len; + + if ((dataLen > sizeof(data)) || (lenHi)) + throw StreamException("ASF object too big"); + + in.read(data,dataLen); + } + + + void write(Stream &out) + { + id.write(out); + out.writeLong(lenLo); + out.writeLong(lenHi); + if (dataLen) + out.write(data,dataLen); + } + + const char *getTypeName() + { + switch(type) + { + case T_HEAD_OBJECT: + return "ASF_Header_Object"; + case T_DATA_OBJECT: + return "ASF_Data_Object"; + case T_FILE_PROP: + return "ASF_File_Properties_Object"; + case T_STREAM_PROP: + return "ASF_Stream_Properties_Object"; + case T_STREAM_BITRATE: + return "ASF_Stream_Bitrate_Properties_Object"; + default: + return "Unknown_Object"; + } + } + + char data[8192]; + MSID id; + unsigned int lenLo,lenHi,dataLen; + TYPE type; +}; +// ----------------------------------- +class ASFStream +{ +public: + enum TYPE + { + T_UNKNOWN, + T_AUDIO, + T_VIDEO + }; + + void read(Stream &in) + { + MSID sid; + sid.read(in); + + if (sid == videoStreamObjID) + type = T_VIDEO; + else if (sid == audioStreamObjID) + type = T_AUDIO; + else + type = T_UNKNOWN; + + in.skip(32); + id = in.readShort()&0x7f; + } + + + const char *getTypeName() + { + switch(type) + { + case T_VIDEO: + return "Video"; + case T_AUDIO: + return "Audio"; + } + return "Unknown"; + } + + void reset() + { + id = 0; + bitrate = 0; + type = T_UNKNOWN; + } + + unsigned int id; + int bitrate; + TYPE type; +}; + +// ----------------------------------- +class ASFInfo +{ +public: + enum + { + MAX_STREAMS = 128 + }; + + ASFInfo() + { + numPackets = 0; + packetSize = 0; + flags = 0; + bitrate=0; + for(int i=0; i sizeof(data)) + throw StreamException("ASF chunk too big"); + in.read(data,dataLen); + } + + void write(Stream &out) + { + out.writeShort(type); + out.writeShort(len); + out.writeLong(seq); + out.writeShort(v1); + out.writeShort(v2); + out.write(data,dataLen); + } + + unsigned int seq,dataLen; + unsigned short type,len,v1,v2; + unsigned char data[8192]; +}; + + +#endif + diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/atom.h b/c:/Git/PeerCast.root/PeerCast/core/common/atom.h new file mode 100644 index 0000000..94d8e46 --- /dev/null +++ b/c:/Git/PeerCast.root/PeerCast/core/common/atom.h @@ -0,0 +1,208 @@ +// ------------------------------------------------ +// File : atom.h +// Date: 1-mar-2004 +// Author: giles +// +// (c) 2002-4 peercast.org +// ------------------------------------------------ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// ------------------------------------------------ + +#ifndef _ATOM_H +#define _ATOM_H + +#include "stream.h" + +#include "id.h" + +// ------------------------------------------------ +class AtomStream +{ +public: + AtomStream(Stream &s) : io(s),numChildren(0),numData(0) + {} + + void checkData(int d) + { + if (numData != d) + throw StreamException("Bad atom data"); + } + + void writeParent(ID4 id,int nc) + { + io.writeID4(id); + io.writeInt(nc|0x80000000); + } + + void writeInt(ID4 id,int d) + { + io.writeID4(id); + io.writeInt(4); + io.writeInt(d); + } + + void writeID4(ID4 id,ID4 d) + { + io.writeID4(id); + io.writeInt(4); + io.writeID4(d); + } + + void writeShort(ID4 id,short d) + { + io.writeID4(id); + io.writeInt(2); + io.writeShort(d); + } + + void writeChar(ID4 id,char d) + { + io.writeID4(id); + io.writeInt(1); + io.writeChar(d); + } + + void writeBytes(ID4 id,const void *p,int l) + { + io.writeID4(id); + io.writeInt(l); + io.write(p,l); + } + + + int writeStream(ID4 id,Stream &in,int l) + { + io.writeID4(id); + io.writeInt(l); + in.writeTo(io,l); + return (sizeof(int)*2)+l; + + } + + void writeString(ID4 id,const char *p) + { + writeBytes(id,p,strlen(p)+1); + } + + ID4 read(int &numc,int &dlen) + { + ID4 id = io.readID4(); + + unsigned int v = io.readInt(); + if (v & 0x80000000) + { + numc = v&0x7fffffff; + dlen = 0; + }else + { + numc = 0; + dlen = v; + } + + numChildren = numc; + numData = dlen; + + return id; + } + + void skip(int c, int d) + { + if (d) + io.skip(d); + + for(int i=0; i dlen) + readBytes(s,dlen); + else + { + readBytes(s,max); + io.skip(dlen-max); + } + } + + int writeAtoms(ID4 id, Stream &in, int cnt, int data) + { + int total=0; + + if (cnt) + { + writeParent(id,cnt); + total+=sizeof(int)*2; + + for(int i=0; i +#include +#include "common.h" +#include "socket.h" +#include "channel.h" +#include "gnutella.h" +#include "servent.h" +#include "servmgr.h" +#include "sys.h" +#include "xml.h" +#include "http.h" +#include "peercast.h" +#include "atom.h" +#include "pcp.h" + +#include "mp3.h" +#include "ogg.h" +#include "mms.h" +#include "nsv.h" + +#include "icy.h" +#include "url.h" + +#include "version2.h" +#ifdef _DEBUG +#include "chkMemoryLeak.h" +#define DEBUG_NEW new(__FILE__, __LINE__) +#define new DEBUG_NEW +#endif + +// ----------------------------------- +char *Channel::srcTypes[]= +{ + "NONE", + "PEERCAST", + "SHOUTCAST", + "ICECAST", + "URL" +}; +// ----------------------------------- +char *Channel::statusMsgs[]= +{ + "NONE", + "WAIT", + "CONNECT", + "REQUEST", + "CLOSE", + "RECEIVE", + "BROADCAST", + "ABORT", + "SEARCH", + "NOHOSTS", + "IDLE", + "ERROR", + "NOTFOUND" +}; + + +// for PCRaw start. +bool isIndexTxt(ChanInfo *info) +{ + int len; + + if( info && + info->contentType == ChanInfo::T_RAW && + info->bitrate <= 32 && + (len = strlen(info->name.cstr())) >= 9 && + !memcmp(info->name.cstr(), "index", 5) && + !memcmp(info->name.cstr()+len-4, ".txt", 4)) + { + return true; + } + else + { + return false; + } +} + +bool isIndexTxt(Channel *ch) +{ + if(ch && !ch->isBroadcasting() && isIndexTxt(&ch->info)) + return true; + else + return false; +} + +int numMaxRelaysIndexTxt(Channel *ch) +{ + return ((servMgr->maxRelaysIndexTxt < 1) ? 1 : servMgr->maxRelaysIndexTxt); +} + +int canStreamIndexTxt(Channel *ch) +{ + int ret; + + // Ž©•ª‚ª”zM‚µ‚Ä‚¢‚éê‡‚ÍŠÖŒW‚È‚¢ + if(!ch || ch->isBroadcasting()) + return -1; + + ret = numMaxRelaysIndexTxt(ch) - ch->localRelays(); + if(ret < 0) + ret = 0; + + return ret; +} +// for PCRaw end. + +// ----------------------------------- +void readXMLString(String &str, XML::Node *n, const char *arg) +{ + char *p; + p = n->findAttr(arg); + if (p) + { + str.set(p,String::T_HTML); + str.convertTo(String::T_ASCII); + } +} + +int channel_count=1; +// ----------------------------------------------------------------------------- +// Initialise the channel to its default settings of unallocated and reset. +// ----------------------------------------------------------------------------- +Channel::Channel() +{ + next = NULL; + reset(); + channel_id = channel_count++; +} +// ----------------------------------------------------------------------------- +void Channel::endThread(bool flg) +{ + if (pushSock) + { + pushSock->close(); + delete pushSock; + pushSock = NULL; + } + + if (sock) + { + sock->close(); + sock = NULL; + } + + if (sourceData) + { + delete sourceData; + sourceData = NULL; + } + + if (flg == true){ + reset(); + + chanMgr->channellock.on(); + chanMgr->deleteChannel(this); + chanMgr->channellock.off(); + + sys->endThread(&thread); + } +} +// ----------------------------------------------------------------------------- +void Channel::resetPlayTime() +{ + info.lastPlayStart = sys->getTime(); +} +// ----------------------------------------------------------------------------- +void Channel::setStatus(STATUS s) +{ + if (s != status) + { + bool wasPlaying = isPlaying(); + + status = s; + + if (isPlaying()) + { + info.status = ChanInfo::S_PLAY; + resetPlayTime(); + }else + { + if (wasPlaying) + info.lastPlayEnd = sys->getTime(); + info.status = ChanInfo::S_UNKNOWN; + } + + if (isBroadcasting()) + { + ChanHitList *chl = chanMgr->findHitListByID(info.id); + if (!chl) + chanMgr->addHitList(info); + } + + peercastApp->channelUpdate(&info); + + } +} + +// ----------------------------------------------------------------------------- +// Reset channel and make it available +// ----------------------------------------------------------------------------- +void Channel::reset() +{ + sourceHost.init(); + remoteID.clear(); + + streamIndex = 0; + + lastIdleTime = 0; + + info.init(); + + mount.clear(); + bump = false; + stayConnected = false; + + icyMetaInterval = 0; + streamPos = 0; + skipCount = 0; //JP-EX + lastSkipTime = 0; + + insertMeta.init(); + + headPack.init(); + + sourceStream = NULL; + + rawData.init(); + rawData.accept = ChanPacket::T_HEAD|ChanPacket::T_DATA; + + setStatus(S_NONE); + type = T_NONE; + + readDelay = false; + sock = NULL; + pushSock = NULL; + + sourceURL.clear(); + sourceData = NULL; + + lastTrackerUpdate = 0; + lastMetaUpdate = 0; + + srcType = SRC_NONE; + + + startTime = 0; + syncTime = 0; + + channel_id = 0; + finthread = NULL; + + trackerHit.init(); +} + +// ----------------------------------- +void Channel::newPacket(ChanPacket &pack) +{ + if (pack.type != ChanPacket::T_PCP) + { + rawData.writePacket(pack,true); + } +} + + +// ----------------------------------- +bool Channel::checkIdle() +{ + return ( (info.getUptime() > chanMgr->prefetchTime) && (localListeners() == 0) && (!stayConnected) && (status != S_BROADCASTING)); +} + +// ----------------------------------- +bool Channel::isFull() +{ + // for PCRaw (relay) start. + if(isIndexTxt(this)) + { + int ret = canStreamIndexTxt(this); + + if(ret > 0) + return false; + else if(ret == 0) + return true; + } + // for PCRaw (relay) end. + + return chanMgr->maxRelaysPerChannel ? localRelays() >= chanMgr->maxRelaysPerChannel : false; +} +// ----------------------------------- +int Channel::localRelays() +{ + return servMgr->numStreams(info.id,Servent::T_RELAY,true); +} +// ----------------------------------- +int Channel::localListeners() +{ + return servMgr->numStreams(info.id,Servent::T_DIRECT,true); +} + +// ----------------------------------- +int Channel::totalRelays() +{ + int tot = 0; + ChanHitList *chl = chanMgr->findHitListByID(info.id); + if (chl) + tot += chl->numHits(); + return tot; +} +// ----------------------------------- +int Channel::totalListeners() +{ + int tot = localListeners(); + ChanHitList *chl = chanMgr->findHitListByID(info.id); + if (chl) + tot += chl->numListeners(); + return tot; +} + + + + +// ----------------------------------- +void Channel::startGet() +{ + srcType = SRC_PEERCAST; + type = T_RELAY; + info.srcProtocol = ChanInfo::SP_PCP; + + + sourceData = new PeercastSource(); + + startStream(); +} +// ----------------------------------- +void Channel::startURL(const char *u) +{ + sourceURL.set(u); + + srcType = SRC_URL; + type = T_BROADCAST; + stayConnected = true; + + resetPlayTime(); + + sourceData = new URLSource(u); + + startStream(); + +} +// ----------------------------------- +void Channel::startStream() +{ + thread.data = this; + thread.func = stream; + if (!sys->startThread(&thread)) + reset(); +} + +// ----------------------------------- +void Channel::sleepUntil(double time) +{ + double sleepTime = time - (sys->getDTime()-startTime); + +// LOG("sleep %g",sleepTime); + if (sleepTime > 0) + { + if (sleepTime > 60) sleepTime = 60; + + double sleepMS = sleepTime*1000; + + sys->sleep((int)sleepMS); + } +} + + +// ----------------------------------- +void Channel::checkReadDelay(unsigned int len) +{ + if (readDelay) + { + unsigned int time = (len*1000)/((info.bitrate*1024)/8); + sys->sleep(time); + } + + +} + + +// ----------------------------------- +THREAD_PROC Channel::stream(ThreadInfo *thread) +{ +// thread->lock(); + + Channel *ch = (Channel *)thread->data; + + LOG_CHANNEL("Channel started"); + + while (thread->active && !peercastInst->isQuitting && !thread->finish) + { + ChanHitList *chl = chanMgr->findHitList(ch->info); + if (!chl) + chanMgr->addHitList(ch->info); + + ch->sourceData->stream(ch); + + LOG_CHANNEL("Channel stopped"); + ch->rawData.init(); + + if (!ch->stayConnected) + { + thread->active = false; + break; + }else + { + if (!ch->info.lastPlayEnd) + ch->info.lastPlayEnd = sys->getTime(); + + unsigned int diff = (sys->getTime()-ch->info.lastPlayEnd) + 5; + + LOG_DEBUG("Channel sleeping for %d seconds",diff); + for(unsigned int i=0; iactive || peercastInst->isQuitting){ + thread->active = false; + break; + } + sys->sleep(1000); + } + } + } + + LOG_DEBUG("thread.active = %d, thread.finish = %d", + ch->thread.active, ch->thread.finish); + + if (!thread->finish){ + ch->endThread(false); + + if (!ch->finthread){ + ch->finthread = new ThreadInfo(); + ch->finthread->func = waitFinish; + ch->finthread->data = ch; + sys->startThread(ch->finthread); + } + } else { + ch->endThread(true); + } + return 0; +} + +// ----------------------------------- +THREAD_PROC Channel::waitFinish(ThreadInfo *thread) +{ + Channel *ch = (Channel*)thread->data; + LOG_DEBUG("Wait channel finish"); + + while(!(ch->thread.finish) && !thread->finish){ + sys->sleep(1000); + } + + if (ch->thread.finish){ + LOG_DEBUG("channel finish"); + ch->endThread(true); + } else { + LOG_DEBUG("channel restart"); + } + + delete thread; + return 0; +} + +// ----------------------------------- +bool Channel::acceptGIV(ClientSocket *givSock) +{ + if (!pushSock) + { + pushSock = givSock; + return true; + }else + return false; +} +// ----------------------------------- +void Channel::connectFetch() +{ + sock = sys->createSocket(); + + if (!sock) + throw StreamException("Can`t create socket"); + + if (sourceHost.tracker || sourceHost.yp) + { + sock->setReadTimeout(30000); + sock->setWriteTimeout(30000); + LOG_CHANNEL("Channel using longer timeouts"); + } else { + sock->setReadTimeout(5000); + sock->setWriteTimeout(5000); + } + + sock->open(sourceHost.host); + + sock->connect(); +} + +// ----------------------------------- +int Channel::handshakeFetch() +{ + char idStr[64]; + info.id.toStr(idStr); + + char sidStr[64]; + servMgr->sessionID.toStr(sidStr); + + sock->writeLineF("GET /channel/%s HTTP/1.0",idStr); + sock->writeLineF("%s %d",PCX_HS_POS,streamPos); + sock->writeLineF("%s %d",PCX_HS_PCP,1); + + sock->writeLine(""); + + HTTP http(*sock); + + int r = http.readResponse(); + + LOG_CHANNEL("Got response: %d",r); + + while (http.nextHeader()) + { + char *arg = http.getArgStr(); + if (!arg) + continue; + + if (http.isHeader(PCX_HS_POS)) + streamPos = atoi(arg); + else + Servent::readICYHeader(http, info, NULL); + + LOG_CHANNEL("Channel fetch: %s",http.cmdLine); + } + + if ((r != 200) && (r != 503)) + return r; + + if (!servMgr->keepDownstreams) { + if (rawData.getLatestPos() > streamPos) + rawData.init(); + } + + AtomStream atom(*sock); + + String agent; + + Host rhost = sock->host; + + if (info.srcProtocol == ChanInfo::SP_PCP) + { + // don`t need PCP_CONNECT here + Servent::handshakeOutgoingPCP(atom,rhost,remoteID,agent,sourceHost.yp|sourceHost.tracker); + } + + if (r == 503) return 503; + return 0; + +} + +// ----------------------------------- +void PeercastSource::stream(Channel *ch) +{ + int numYPTries=0; + int numYPTries2=0; + bool next_yp = false; + bool tracker_check = (ch->trackerHit.host.ip != 0); + int connFailCnt = 0; + + ch->lastStopTime = 0; + ch->bumped = false; + + while (ch->thread.active) + { + ch->skipCount = 0; //JP-EX + ch->lastSkipTime = 0; + + ChanHitList *chl = NULL; + + ch->sourceHost.init(); + + if (connFailCnt >= 3 && (ch->localListeners() == 0) && (!ch->stayConnected) && !ch->isBroadcasting()) { + ch->lastIdleTime = sys->getTime(); + ch->setStatus(Channel::S_IDLE); + ch->skipCount = 0; + ch->lastSkipTime = 0; + break; + } + + if (!servMgr->keepDownstreams && !ch->bumped) { + ch->trackerHit.lastContact = sys->getTime() - 30 + (rand() % 30); + } + + ch->setStatus(Channel::S_SEARCHING); + LOG_CHANNEL("Channel searching for hit.."); + do + { + + if (ch->pushSock) + { + ch->sock = ch->pushSock; + ch->pushSock = NULL; + ch->sourceHost.host = ch->sock->host; + break; + } + + chanMgr->hitlistlock.on(); + + chl = chanMgr->findHitList(ch->info); + if (chl) + { + ChanHitSearch chs; + + // find local hit + if (!ch->sourceHost.host.ip){ + chs.init(); + chs.matchHost = servMgr->serverHost; + chs.waitDelay = MIN_RELAY_RETRY; + chs.excludeID = servMgr->sessionID; + if (chl->pickSourceHits(chs)){ + ch->sourceHost = chs.best[0]; + LOG_DEBUG("use local hit"); + } + } + + // else find global hit + if (!ch->sourceHost.host.ip) + { + chs.init(); + chs.waitDelay = MIN_RELAY_RETRY; + chs.excludeID = servMgr->sessionID; + if (chl->pickSourceHits(chs)){ + ch->sourceHost = chs.best[0]; + LOG_DEBUG("use global hit"); + } + } + + + // else find local tracker + if (!ch->sourceHost.host.ip) + { + chs.init(); + chs.matchHost = servMgr->serverHost; + chs.waitDelay = MIN_TRACKER_RETRY; + chs.excludeID = servMgr->sessionID; + chs.trackersOnly = true; + if (chl->pickSourceHits(chs)){ + ch->sourceHost = chs.best[0]; + LOG_DEBUG("use local tracker"); + } + } + + // find tracker + unsigned int ctime = sys->getTime(); + if (!ch->sourceHost.host.ip && tracker_check && ch->trackerHit.host.ip){ + if (ch->trackerHit.lastContact + 30 < ctime){ + ch->sourceHost = ch->trackerHit; + ch->trackerHit.lastContact = ctime; + LOG_DEBUG("use saved tracker"); + } + } + + // else find global tracker + if (!ch->sourceHost.host.ip) + { + chs.init(); + chs.waitDelay = MIN_TRACKER_RETRY; + chs.excludeID = servMgr->sessionID; + chs.trackersOnly = true; + if (chl->pickSourceHits(chs)){ + ch->sourceHost = chs.best[0]; + tracker_check = true; + ch->trackerHit = chs.best[0]; + LOG_DEBUG("use global tracker"); + } + } + } + + chanMgr->hitlistlock.off(); + + if (servMgr->keepDownstreams && ch->lastStopTime && ch->lastStopTime < sys->getTime() - 7) { + ch->lastStopTime = 0; + LOG_DEBUG("------------ disconnect all downstreams"); + ChanPacket pack; + MemoryStream mem(pack.data,sizeof(pack.data)); + AtomStream atom(mem); + atom.writeInt(PCP_QUIT,PCP_ERROR_QUIT+PCP_ERROR_OFFAIR); + pack.len = mem.pos; + pack.type = ChanPacket::T_PCP; + GnuID noID; + noID.clear(); + servMgr->broadcastPacket(pack,ch->info.id,ch->remoteID,noID,Servent::T_RELAY); + + chanMgr->hitlistlock.on(); + ChanHitList *hl = chanMgr->findHitList(ch->info); + if (hl){ + hl->clearHits(false); + } + chanMgr->hitlistlock.off(); + } + + // no trackers found so contact YP + if (!tracker_check && !ch->sourceHost.host.ip) + { + next_yp = false; + if (servMgr->rootHost.isEmpty()) + goto yp2; + + if (numYPTries >= 3) + goto yp2; + + if ((!servMgr->rootHost2.isEmpty()) && (numYPTries > numYPTries2)) + goto yp2; + + unsigned int ctime=sys->getTime(); + if ((ctime-chanMgr->lastYPConnect) > MIN_YP_RETRY) + { + ch->sourceHost.host.fromStrName(servMgr->rootHost.cstr(),DEFAULT_PORT); + ch->sourceHost.yp = true; + chanMgr->lastYPConnect=ctime; + numYPTries++; + } + if (numYPTries < 3) + next_yp = true; + } + +yp2: + // no trackers found so contact YP2 + if (!tracker_check && !ch->sourceHost.host.ip) + { +// next_yp = false; + if (servMgr->rootHost2.isEmpty()) + goto yp0; + + if (numYPTries2 >= 3) + goto yp0; + + unsigned int ctime=sys->getTime(); + if ((ctime-chanMgr->lastYPConnect2) > MIN_YP_RETRY) + { + ch->sourceHost.host.fromStrName(servMgr->rootHost2.cstr(),DEFAULT_PORT); + ch->sourceHost.yp = true; + chanMgr->lastYPConnect2=ctime; + numYPTries2++; + } + if (numYPTries2 < 3) + next_yp = true; + } +yp0: + if (!tracker_check && !ch->sourceHost.host.ip && !next_yp) break; + + sys->sleepIdle(); + + }while((ch->sourceHost.host.ip==0) && (ch->thread.active)); + + if (!ch->sourceHost.host.ip) + { + LOG_ERROR("Channel giving up"); + ch->setStatus(Channel::S_ERROR); + break; + } + + if (ch->sourceHost.yp) + { + LOG_CHANNEL("Channel contacting YP, try %d",numYPTries); + }else + { + LOG_CHANNEL("Channel found hit"); + numYPTries=0; + numYPTries2=0; + } + + if (ch->sourceHost.host.ip) + { + bool isTrusted = ch->sourceHost.tracker | ch->sourceHost.yp; + + + //if (ch->sourceHost.tracker) + // peercastApp->notifyMessage(ServMgr::NT_PEERCAST,"Contacting tracker, please wait..."); + + char ipstr[64]; + ch->sourceHost.host.toStr(ipstr); + + char *type = ""; + if (ch->sourceHost.tracker) + type = "(tracker)"; + else if (ch->sourceHost.yp) + type = "(YP)"; + + int error=-1; + int got503 = 0; + try + { + ch->setStatus(Channel::S_CONNECTING); + ch->sourceHost.lastContact = sys->getTime(); + + if (!ch->sock) + { + LOG_CHANNEL("Channel connecting to %s %s",ipstr,type); + ch->connectFetch(); + } + + error = ch->handshakeFetch(); + if (error == 503) { + got503 = 1; + error = 0; + } + if (error) + throw StreamException("Handshake error"); + if (ch->sourceHost.tracker) connFailCnt = 0; + + if (servMgr->autoMaxRelaySetting) //JP-EX + { + double setMaxRelays = ch->info.bitrate?servMgr->maxBitrateOut/(ch->info.bitrate*1.3):0; + if ((unsigned int)setMaxRelays == 0) + servMgr->maxRelays = 1; + else if ((unsigned int)setMaxRelays > servMgr->autoMaxRelaySetting) + servMgr->maxRelays = servMgr->autoMaxRelaySetting; + else + servMgr->maxRelays = (unsigned int)setMaxRelays; + } + + ch->sourceStream = ch->createSource(); + + error = ch->readStream(*ch->sock,ch->sourceStream); + if (error) + throw StreamException("Stream error"); + + error = 0; // no errors, closing normally. +// ch->setStatus(Channel::S_CLOSING); + ch->setStatus(Channel::S_IDLE); + + LOG_CHANNEL("Channel closed normally"); + }catch(StreamException &e) + { + ch->setStatus(Channel::S_ERROR); + LOG_ERROR("Channel to %s %s : %s",ipstr,type,e.msg); + if (!servMgr->allowConnectPCST) //JP-EX + { + if (ch->info.srcProtocol == ChanInfo::SP_PEERCAST) + ch->thread.active = false; + } + //if (!ch->sourceHost.tracker || ((error != 503) && ch->sourceHost.tracker)) + if (!ch->sourceHost.tracker || (!got503 && ch->sourceHost.tracker)) + chanMgr->deadHit(ch->sourceHost); + if (ch->sourceHost.tracker && error == -1) { + LOG_ERROR("can't connect to tracker"); + connFailCnt++; + } + } + + unsigned int ctime = sys->getTime(); + if (ch->rawData.lastWriteTime) { + ch->lastStopTime = ch->rawData.lastWriteTime; + if (isIndexTxt(ch) && ctime - ch->lastStopTime < 60) + ch->lastStopTime = ctime; + } + + if (tracker_check && ch->sourceHost.tracker) + ch->trackerHit.lastContact = ctime - 30 + (rand() % 30); + + // broadcast source host + if (!error && ch->sourceHost.host.ip) { // if closed normally + ChanPacket pack; + MemoryStream mem(pack.data,sizeof(pack.data)); + AtomStream atom(mem); + ch->sourceHost.writeAtoms(atom, ch->info.id); + pack.len = mem.pos; + pack.type = ChanPacket::T_PCP; + GnuID noID; + noID.clear(); + servMgr->broadcastPacket(pack,ch->info.id,ch->remoteID,noID,Servent::T_RELAY); + LOG_DEBUG("stream: broadcast sourceHost"); + } + + // broadcast quit to any connected downstream servents + if (!servMgr->keepDownstreams || (ch->sourceHost.tracker && !got503) || !error) { + ChanPacket pack; + MemoryStream mem(pack.data,sizeof(pack.data)); + AtomStream atom(mem); + atom.writeInt(PCP_QUIT,PCP_ERROR_QUIT+PCP_ERROR_OFFAIR); + pack.len = mem.pos; + pack.type = ChanPacket::T_PCP; + GnuID noID; + noID.clear(); + servMgr->broadcastPacket(pack,ch->info.id,ch->remoteID,noID,Servent::T_RELAY); + LOG_DEBUG("------------ broadcast quit to all downstreams"); + + chanMgr->hitlistlock.on(); + ChanHitList *hl = chanMgr->findHitList(ch->info); + if (hl){ + hl->clearHits(false); + } + chanMgr->hitlistlock.off(); + } + + + if (ch->sourceStream) + { + try + { + if (!error) + { + ch->sourceStream->updateStatus(ch); + ch->sourceStream->flush(*ch->sock); + } + }catch(StreamException &) + {} + ChannelStream *cs = ch->sourceStream; + ch->sourceStream = NULL; + cs->kill(); + delete cs; + } + + if (ch->sock) + { + ch->sock->close(); + delete ch->sock; + ch->sock = NULL; + } + + if (error == 404) + { + LOG_ERROR("Channel not found"); + //if (!next_yp){ + if ((ch->sourceHost.yp && !next_yp) || ch->sourceHost.tracker) { + chanMgr->hitlistlock.on(); + ChanHitList *hl = chanMgr->findHitList(ch->info); + if (hl){ + hl->clearHits(true); + } + chanMgr->hitlistlock.off(); + + if(!isIndexTxt(&ch->info)) // for PCRaw (popup) + peercastApp->notifyMessage(ServMgr::NT_PEERCAST,"Channel not found"); + return; + } + } + + + } + + ch->lastIdleTime = sys->getTime(); + ch->setStatus(Channel::S_IDLE); + ch->skipCount = 0; //JP-EX + ch->lastSkipTime = 0; + while ((ch->checkIdle()) && (ch->thread.active)) + { + sys->sleepIdle(); + } + + sys->sleepIdle(); + } + +} +// ----------------------------------- +void Channel::startICY(ClientSocket *cs, SRC_TYPE st) +{ + srcType = st; + type = T_BROADCAST; + cs->setReadTimeout(0); // stay connected even when theres no data coming through + sock = cs; + info.srcProtocol = ChanInfo::SP_HTTP; + + streamIndex = ++chanMgr->icyIndex; + + sourceData = new ICYSource(); + startStream(); +} + +// ----------------------------------- +static char *nextMetaPart(char *str,char delim) +{ + while (*str) + { + if (*str == delim) + { + *str++ = 0; + return str; + } + str++; + } + return NULL; +} +// ----------------------------------- +static void copyStr(char *to,char *from,int max) +{ + char c; + while ((c=*from++) && (--max)) + if (c != '\'') + *to++ = c; + + *to = 0; +} + +// ----------------------------------- +void Channel::processMp3Metadata(char *str) +{ + ChanInfo newInfo = info; + + char *cmd=str; + while (cmd) + { + char *arg = nextMetaPart(cmd,'='); + if (!arg) + break; + + char *next = nextMetaPart(arg,';'); + + if (strcmp(cmd,"StreamTitle")==0) + { + newInfo.track.title.setUnquote(arg,String::T_ASCII); + newInfo.track.title.convertTo(String::T_UNICODE); + + }else if (strcmp(cmd,"StreamUrl")==0) + { + newInfo.track.contact.setUnquote(arg,String::T_ASCII); + newInfo.track.contact.convertTo(String::T_UNICODE); + } + + + cmd = next; + } + + updateInfo(newInfo); +} + +// ----------------------------------- +XML::Node *ChanHit::createXML() +{ + // IP + char ipStr[64]; + host.toStr(ipStr); + + return new XML::Node("host ip=\"%s\" hops=\"%d\" listeners=\"%d\" relays=\"%d\" uptime=\"%d\" push=\"%d\" relay=\"%d\" direct=\"%d\" cin=\"%d\" stable=\"%d\" version=\"%d\" update=\"%d\" tracker=\"%d\"", + ipStr, + numHops, + numListeners, + numRelays, + upTime, + firewalled?1:0, + relay?1:0, + direct?1:0, + cin?1:0, + stable?1:0, + version, + sys->getTime()-time, + tracker + ); + +} + +// ----------------------------------- +XML::Node *ChanHitList::createXML(bool addHits) +{ + XML::Node *hn = new XML::Node("hits hosts=\"%d\" listeners=\"%d\" relays=\"%d\" firewalled=\"%d\" closest=\"%d\" furthest=\"%d\" newest=\"%d\"", + numHits(), + numListeners(), + numRelays(), + numFirewalled(), + closestHit(), + furthestHit(), + sys->getTime()-newestHit() + ); + + if (addHits) + { + ChanHit *h = hit; + while (h) + { + if (h->host.ip) + hn->add(h->createXML()); + h = h->next; + } + } + + return hn; +} + +// ----------------------------------- +XML::Node *Channel::createRelayXML(bool showStat) +{ + const char *ststr; + ststr = getStatusStr(); + if (!showStat) + if ((status == S_RECEIVING) || (status == S_BROADCASTING)) + ststr = "OK"; + + ChanHitList *chl = chanMgr->findHitList(info); + + return new XML::Node("relay listeners=\"%d\" relays=\"%d\" hosts=\"%d\" status=\"%s\"", + localListeners(), + localRelays(), + (chl!=NULL)?chl->numHits():0, + ststr + ); +} + +// ----------------------------------- +void ChanMeta::fromXML(XML &xml) +{ + MemoryStream tout(data,MAX_DATALEN); + xml.write(tout); + + len = tout.pos; +} +// ----------------------------------- +void ChanMeta::fromMem(void *p, int l) +{ + len = l; + memcpy(data,p,len); +} +// ----------------------------------- +void ChanMeta::addMem(void *p, int l) +{ + if ((len+l) <= MAX_DATALEN) + { + memcpy(data+len,p,l); + len += l; + } +} +// ----------------------------------- +void Channel::broadcastTrackerUpdate(GnuID &svID, bool force) +{ + unsigned int ctime = sys->getTime(); + + if (((ctime-lastTrackerUpdate) > 30) || (force)) + { + ChanPacket pack; + + MemoryStream mem(pack.data,sizeof(pack)); + + AtomStream atom(mem); + + ChanHit hit; + + ChanHitList *chl = chanMgr->findHitListByID(info.id); + if (!chl) + throw StreamException("Broadcast channel has no hitlist"); + + int numListeners = totalListeners(); + int numRelays = totalRelays(); + + unsigned int oldp = rawData.getOldestPos(); + unsigned int newp = rawData.getLatestPos(); + + hit.initLocal(numListeners,numRelays,info.numSkips,info.getUptime(),isPlaying(), false, 0, this, oldp,newp); + hit.tracker = true; + +#ifndef VERSION_EX + atom.writeParent(PCP_BCST,8); +#else + atom.writeParent(PCP_BCST,10); +#endif + atom.writeChar(PCP_BCST_GROUP,PCP_BCST_GROUP_ROOT); + atom.writeChar(PCP_BCST_HOPS,0); + atom.writeChar(PCP_BCST_TTL,11); + atom.writeBytes(PCP_BCST_FROM,servMgr->sessionID.id,16); + atom.writeInt(PCP_BCST_VERSION,PCP_CLIENT_VERSION); + atom.writeInt(PCP_BCST_VERSION_VP,PCP_CLIENT_VERSION_VP); +#ifdef VERSION_EX + atom.writeBytes(PCP_BCST_VERSION_EX_PREFIX,PCP_CLIENT_VERSION_EX_PREFIX,2); + atom.writeShort(PCP_BCST_VERSION_EX_NUMBER,PCP_CLIENT_VERSION_EX_NUMBER); +#endif + atom.writeParent(PCP_CHAN,4); + atom.writeBytes(PCP_CHAN_ID,info.id.id,16); + atom.writeBytes(PCP_CHAN_BCID,chanMgr->broadcastID.id,16); + info.writeInfoAtoms(atom); + info.writeTrackAtoms(atom); + hit.writeAtoms(atom,info.id); + + + pack.len = mem.pos; + pack.type = ChanPacket::T_PCP; + + GnuID noID; + noID.clear(); + int cnt = servMgr->broadcastPacket(pack,noID,servMgr->sessionID,svID,Servent::T_COUT); + + if (cnt) + { + LOG_DEBUG("Sent tracker update for %s to %d client(s)",info.name.cstr(),cnt); + lastTrackerUpdate = ctime; + } + } +} + +// ----------------------------------- +bool Channel::sendPacketUp(ChanPacket &pack,GnuID &cid,GnuID &sid,GnuID &did) +{ + if ( isActive() + && (!cid.isSet() || info.id.isSame(cid)) + && (!sid.isSet() || !remoteID.isSame(sid)) + && sourceStream + ) + return sourceStream->sendPacket(pack,did); + + return false; +} + +// ----------------------------------- +void Channel::updateInfo(ChanInfo &newInfo) +{ + if (info.update(newInfo)) + { + if (isBroadcasting()) + { + unsigned int ctime = sys->getTime(); + if ((ctime-lastMetaUpdate) > 30) + { + lastMetaUpdate = ctime; + + ChanPacket pack; + + MemoryStream mem(pack.data,sizeof(pack)); + + AtomStream atom(mem); + +#ifndef VERSION_EX + atom.writeParent(PCP_BCST,8); +#else + atom.writeParent(PCP_BCST,10); +#endif + atom.writeChar(PCP_BCST_HOPS,0); + atom.writeChar(PCP_BCST_TTL,7); + atom.writeChar(PCP_BCST_GROUP,PCP_BCST_GROUP_RELAYS); + atom.writeBytes(PCP_BCST_FROM,servMgr->sessionID.id,16); + atom.writeInt(PCP_BCST_VERSION,PCP_CLIENT_VERSION); + atom.writeInt(PCP_BCST_VERSION_VP,PCP_CLIENT_VERSION_VP); +#ifdef VERSION_EX + atom.writeBytes(PCP_BCST_VERSION_EX_PREFIX,PCP_CLIENT_VERSION_EX_PREFIX,2); + atom.writeShort(PCP_BCST_VERSION_EX_NUMBER,PCP_CLIENT_VERSION_EX_NUMBER); +#endif + atom.writeBytes(PCP_BCST_CHANID,info.id.id,16); + atom.writeParent(PCP_CHAN,3); + atom.writeBytes(PCP_CHAN_ID,info.id.id,16); + info.writeInfoAtoms(atom); + info.writeTrackAtoms(atom); + + pack.len = mem.pos; + pack.type = ChanPacket::T_PCP; + GnuID noID; + noID.clear(); + servMgr->broadcastPacket(pack,info.id,servMgr->sessionID,noID,Servent::T_RELAY); + + broadcastTrackerUpdate(noID); + } + } + + ChanHitList *chl = chanMgr->findHitList(info); + if (chl) + chl->info = info; + + peercastApp->channelUpdate(&info); + + } + +} +// ----------------------------------- +ChannelStream *Channel::createSource() +{ +// if (servMgr->relayBroadcast) +// chanMgr->broadcastRelays(NULL,chanMgr->minBroadcastTTL,chanMgr->maxBroadcastTTL); + + + ChannelStream *source=NULL; + + if (info.srcProtocol == ChanInfo::SP_PEERCAST) + { + LOG_CHANNEL("Channel is Peercast"); + if (servMgr->allowConnectPCST) //JP-EX + source = new PeercastStream(); + else + throw StreamException("Channel is not allowed"); + } + else if (info.srcProtocol == ChanInfo::SP_PCP) + { + LOG_CHANNEL("Channel is PCP"); + PCPStream *pcp = new PCPStream(remoteID); + source = pcp; + } + else if (info.srcProtocol == ChanInfo::SP_MMS) + { + LOG_CHANNEL("Channel is MMS"); + source = new MMSStream(); + }else + { + switch(info.contentType) + { + case ChanInfo::T_MP3: + LOG_CHANNEL("Channel is MP3 - meta: %d",icyMetaInterval); + source = new MP3Stream(); + break; + case ChanInfo::T_NSV: + LOG_CHANNEL("Channel is NSV"); + source = new NSVStream(); + break; + case ChanInfo::T_WMA: + case ChanInfo::T_WMV: + throw StreamException("Channel is WMA/WMV - but not MMS"); + break; + case ChanInfo::T_OGG: + case ChanInfo::T_OGM: + LOG_CHANNEL("Channel is OGG"); + source = new OGGStream(); + break; + default: + LOG_CHANNEL("Channel is Raw"); + source = new RawStream(); + break; + } + } + + source->parent = this; + + return source; +} +// ------------------------------------------ +void ChannelStream::updateStatus(Channel *ch) +{ + ChanPacket pack; + if (getStatus(ch,pack)) + { + if (!ch->isBroadcasting()) + { + GnuID noID; + noID.clear(); + int cnt = chanMgr->broadcastPacketUp(pack,ch->info.id,servMgr->sessionID,noID); + LOG_CHANNEL("Sent channel status update to %d clients",cnt); + } + } +} + +// ------------------------------------------ +bool ChannelStream::getStatus(Channel *ch,ChanPacket &pack) +{ + unsigned int ctime = sys->getTime(); + + ChanHitList *chl = chanMgr->findHitListByID(ch->info.id); + + if (!chl) + return false; + +/* int newLocalListeners = ch->localListeners(); + int newLocalRelays = ch->localRelays(); + + if ( + ( + (numListeners != newLocalListeners) + || (numRelays != newLocalRelays) + || (ch->isPlaying() != isPlaying) + || (servMgr->getFirewall() != fwState) + || (((ctime-lastUpdate)>chanMgr->hostUpdateInterval) && chanMgr->hostUpdateInterval) + ) + && ((ctime-lastUpdate) > 10) + ) + { + + numListeners = newLocalListeners; + numRelays = newLocalRelays; + isPlaying = ch->isPlaying(); + fwState = servMgr->getFirewall(); + lastUpdate = ctime; + + ChanHit hit; + + hit.initLocal(ch->localListeners(),ch->localRelays(),ch->info.numSkips,ch->info.getUptime(),isPlaying, ch->isFull(), ch->info.bitrate, ch); + hit.tracker = ch->isBroadcasting();*/ + + int newLocalListeners = ch->localListeners(); + int newLocalRelays = ch->localRelays(); + + if ((ch->isPlaying() == isPlaying)){ + if ((ctime-lastUpdate) < 10){ + return false; + } + + if ((ctime-lastCheckTime) < 10){ + return false; + } + lastCheckTime = ctime; + } + + unsigned int oldp = ch->rawData.getOldestPos(); + unsigned int newp = ch->rawData.getLatestPos(); + + ChanHit hit; + +// LOG_DEBUG("isPlaying-------------------------------------- %d %d", ch->isPlaying(), isPlaying); + + hit.initLocal(newLocalListeners,newLocalRelays,ch->info.numSkips,ch->info.getUptime(),ch->isPlaying(), ch->isFull(), ch->info.bitrate, ch, oldp, newp); + hit.tracker = ch->isBroadcasting(); + + if ( (((ctime-lastUpdate)>chanMgr->hostUpdateInterval) && chanMgr->hostUpdateInterval) + || (newLocalListeners != numListeners) + || (newLocalRelays != numRelays) + || (ch->isPlaying() != isPlaying) + || (servMgr->getFirewall() != fwState) + || (ch->chDisp.relay != hit.relay) + || (ch->chDisp.relayfull != hit.relayfull) + || (ch->chDisp.chfull != hit.chfull) + || (ch->chDisp.ratefull != hit.ratefull) + ){ + numListeners = newLocalListeners; + numRelays = newLocalRelays; + isPlaying = ch->isPlaying(); + fwState = servMgr->getFirewall(); + lastUpdate = ctime; + + ch->chDisp = hit; + + if ((numRelays) && ((servMgr->getFirewall() == ServMgr::FW_OFF) && (servMgr->autoRelayKeep!=0))) //JP-EX + ch->stayConnected = true; + + if ((!numRelays && !numListeners) && (servMgr->autoRelayKeep==2)) //JP-EX + ch->stayConnected = false; + + MemoryStream pmem(pack.data,sizeof(pack.data)); + AtomStream atom(pmem); + + GnuID noID; + noID.clear(); + +#ifndef VERSION_EX + atom.writeParent(PCP_BCST,8); +#else + atom.writeParent(PCP_BCST,10); +#endif + atom.writeChar(PCP_BCST_GROUP,PCP_BCST_GROUP_TRACKERS); + atom.writeChar(PCP_BCST_HOPS,0); + atom.writeChar(PCP_BCST_TTL,11); + atom.writeBytes(PCP_BCST_FROM,servMgr->sessionID.id,16); + atom.writeInt(PCP_BCST_VERSION,PCP_CLIENT_VERSION); + atom.writeInt(PCP_BCST_VERSION_VP,PCP_CLIENT_VERSION_VP); +#ifdef VERSION_EX + atom.writeBytes(PCP_BCST_VERSION_EX_PREFIX,PCP_CLIENT_VERSION_EX_PREFIX,2); + atom.writeShort(PCP_BCST_VERSION_EX_NUMBER,PCP_CLIENT_VERSION_EX_NUMBER); +#endif + atom.writeBytes(PCP_BCST_CHANID,ch->info.id.id,16); + hit.writeAtoms(atom,noID); + + pack.len = pmem.pos; + pack.type = ChanPacket::T_PCP; + return true; + }else + return false; +} +// ----------------------------------- +bool Channel::checkBump() +{ + if (!isBroadcasting() && (!sourceHost.tracker)) + if (rawData.lastWriteTime && ((sys->getTime() - rawData.lastWriteTime) > 30)) + { + LOG_ERROR("Channel Auto bumped"); + bump = true; + } + + if (bump) + { + bump = false; + return true; + }else + return false; +} + +// ----------------------------------- +int Channel::readStream(Stream &in,ChannelStream *source) +{ + //sys->sleep(300); + + int error = 0; + + info.numSkips = 0; + + source->readHeader(in,this); + + peercastApp->channelStart(&info); + + rawData.lastWriteTime = 0; + + bool wasBroadcasting=false; + + unsigned int receiveStartTime = 0; + + try + { + while (thread.active && !peercastInst->isQuitting) + { + if (checkIdle()) + { + LOG_DEBUG("Channel idle"); + break; + } + + if (checkBump()) + { + LOG_DEBUG("Channel bumped"); + error = -1; + bumped = true; + break; + } + + if (in.eof()) + { + LOG_DEBUG("Channel eof"); + break; + } + + if (in.readReady()) + { + error = source->readPacket(in,this); + + if (error) + break; + + //if (rawData.writePos > 0) + if (rawData.lastWriteTime > 0) + { + if (isBroadcasting()) + { + if ((sys->getTime()-lastTrackerUpdate) >= chanMgr->hostUpdateInterval) + { + GnuID noID; + noID.clear(); + broadcastTrackerUpdate(noID); + } + wasBroadcasting = true; + + }else + { +/* if (status != Channel::S_RECEIVING){ + receiveStartTime = sys->getTime(); + } else if (receiveStartTime && receiveStartTime + 10 > sys->getTime()){ + chanMgr->hitlistlock.on(); + ChanHitList *hl = chanMgr->findHitList(info); + if (hl){ + hl->clearHits(true); + } + chanMgr->hitlistlock.off(); + receiveStartTime = 0; + }*/ + setStatus(Channel::S_RECEIVING); + bumped = false; + } + source->updateStatus(this); + } + } + + source->flush(in); + + sys->sleepIdle(); + } + }catch(StreamException &e) + { + LOG_ERROR("readStream: %s",e.msg); + error = -1; + } + + if (!servMgr->keepDownstreams) { + if (status == Channel::S_RECEIVING){ + chanMgr->hitlistlock.on(); + ChanHitList *hl = chanMgr->findHitList(info); + if (hl){ + hl->clearHits(false); + } + chanMgr->hitlistlock.off(); + } + } + +// setStatus(S_CLOSING); + setStatus(S_IDLE); + + if (wasBroadcasting) + { + GnuID noID; + noID.clear(); + broadcastTrackerUpdate(noID,true); + } + + peercastApp->channelStop(&info); + + source->readEnd(in,this); + + return error; +} + +// ----------------------------------- +void PeercastStream::readHeader(Stream &in,Channel *ch) +{ + if (in.readTag() != 'PCST') + throw StreamException("Not PeerCast stream"); + +} +// ----------------------------------- +void PeercastStream::readEnd(Stream &,Channel *) +{ + +} +// ----------------------------------- +int PeercastStream::readPacket(Stream &in,Channel *ch) +{ + ChanPacket pack; + + { + + pack.readPeercast(in); + + MemoryStream mem(pack.data,pack.len); + + switch(pack.type) + { + case ChanPacket::T_HEAD: + // update sync pos + ch->headPack = pack; + pack.pos = ch->streamPos; + ch->newPacket(pack); + ch->streamPos+=pack.len; + break; + case ChanPacket::T_DATA: + pack.pos = ch->streamPos; + ch->newPacket(pack); + ch->streamPos+=pack.len; + break; + case ChanPacket::T_META: + ch->insertMeta.fromMem(pack.data,pack.len); + { + if (pack.len) + { + XML xml; + xml.read(mem); + XML::Node *n = xml.findNode("channel"); + if (n) + { + ChanInfo newInfo = ch->info; + newInfo.updateFromXML(n); + ChanHitList *chl = chanMgr->findHitList(ch->info); + if (chl) + newInfo.updateFromXML(n); + ch->updateInfo(newInfo); + } + } + } + break; +#if 0 + case ChanPacket::T_SYNC: + { + unsigned int s = mem.readLong(); + if ((s-ch->syncPos) != 1) + { + LOG_CHANNEL("Ch.%d SKIP: %d to %d (%d)",ch->index,ch->syncPos,s,ch->info.numSkips); + if (ch->syncPos) + { + ch->info.numSkips++; + if (ch->info.numSkips>50) + throw StreamException("Bumped - Too many skips"); + } + } + + ch->syncPos = s; + } + break; +#endif + + } + + } + return 0; +} + +// ----------------------------------- +void ChannelStream::readRaw(Stream &in, Channel *ch) +{ + ChanPacket pack; + + const int readLen = 8192; + + pack.init(ChanPacket::T_DATA,pack.data,readLen,ch->streamPos); + in.read(pack.data,pack.len); + ch->newPacket(pack); + ch->checkReadDelay(pack.len); + + ch->streamPos+=pack.len; + +} +// ------------------------------------------ +void RawStream::readHeader(Stream &,Channel *) +{ +} + +// ------------------------------------------ +int RawStream::readPacket(Stream &in,Channel *ch) +{ + readRaw(in,ch); + return 0; +} + +// ------------------------------------------ +void RawStream::readEnd(Stream &,Channel *) +{ +} + + + +// ----------------------------------- +void ChanPacket::init(ChanPacketv &p) +{ + type = p.type; + len = p.len; + pos = p.pos; + sync = p.sync; + skip = p.skip; + memcpy(data, p.data, len); +} +// ----------------------------------- +void ChanPacket::init(TYPE t, const void *p, unsigned int l,unsigned int _pos) +{ + type = t; + if (l > MAX_DATALEN) + throw StreamException("Packet data too large"); + len = l; + memcpy(data,p,len); + pos = _pos; + skip = false; +} +// ----------------------------------- +void ChanPacket::writeRaw(Stream &out) +{ + out.write(data,len); +} +// ----------------------------------- +void ChanPacket::writePeercast(Stream &out) +{ + unsigned int tp = 0; + switch (type) + { + case T_HEAD: tp = 'HEAD'; break; + case T_META: tp = 'META'; break; + case T_DATA: tp = 'DATA'; break; + } + + if (type != T_UNKNOWN) + { + out.writeTag(tp); + out.writeShort(len); + out.writeShort(0); + out.write(data,len); + } +} +// ----------------------------------- +void ChanPacket::readPeercast(Stream &in) +{ + unsigned int tp = in.readTag(); + + switch (tp) + { + case 'HEAD': type = T_HEAD; break; + case 'DATA': type = T_DATA; break; + case 'META': type = T_META; break; + default: type = T_UNKNOWN; + } + len = in.readShort(); + in.readShort(); + if (len > MAX_DATALEN) + throw StreamException("Bad ChanPacket"); + in.read(data,len); +} +// ----------------------------------- +int ChanPacketBuffer::copyFrom(ChanPacketBuffer &buf, unsigned int reqPos) +{ + lock.on(); + buf.lock.on(); + + firstPos = 0; + lastPos = 0; + safePos = 0; + readPos = 0; + + for(unsigned int i=buf.firstPos; i<=buf.lastPos; i++) + { + //ChanPacket *src = &buf.packets[i%MAX_PACKETS]; + ChanPacketv *src = &buf.packets[i%MAX_PACKETS]; + if (src->type & accept) + { + if (src->pos >= reqPos) + { + lastPos = writePos; + //packets[writePos++] = *src; + packets[writePos++].init(*src); + } + } + + } + + + buf.lock.off(); + lock.off(); + return lastPos-firstPos; +} + +// ----------------------------------- +bool ChanPacketBuffer::findPacket(unsigned int spos, ChanPacket &pack) +{ + if (writePos == 0) + return false; + + lock.on(); + + unsigned int fpos = getStreamPos(firstPos); + if (spos < fpos) + spos = fpos; + + + for(unsigned int i=firstPos; i<=lastPos; i++) + { + //ChanPacket &p = packets[i%MAX_PACKETS]; + ChanPacketv &p = packets[i%MAX_PACKETS]; + if (p.pos >= spos) + { + pack.init(p); + lock.off(); + return true; + } + } + + lock.off(); + return false; +} +// ----------------------------------- +unsigned int ChanPacketBuffer::getLatestPos() +{ + if (!writePos) + return 0; + else + return getStreamPos(lastPos); + +} +// ----------------------------------- +unsigned int ChanPacketBuffer::getOldestPos() +{ + if (!writePos) + return 0; + else + return getStreamPos(firstPos); +} + +// ----------------------------------- +unsigned int ChanPacketBuffer::findOldestPos(unsigned int spos) +{ + unsigned int min = getStreamPos(safePos); + unsigned int max = getStreamPos(lastPos); + + if (min > spos) + return min; + + if (max < spos) + return max; + + return spos; +} + +// ----------------------------------- +unsigned int ChanPacketBuffer::getStreamPos(unsigned int index) +{ + return packets[index%MAX_PACKETS].pos; +} +// ----------------------------------- +unsigned int ChanPacketBuffer::getStreamPosEnd(unsigned int index) +{ + return packets[index%MAX_PACKETS].pos+packets[index%MAX_PACKETS].len; +} +// ----------------------------------- +bool ChanPacketBuffer::writePacket(ChanPacket &pack, bool updateReadPos) +{ + if (pack.len) + { + if (servMgr->keepDownstreams) { + unsigned int lpos = getLatestPos(); + unsigned int diff = pack.pos - lpos; + if (packets[lastPos%MAX_PACKETS].type == ChanPacket::T_HEAD) lpos = 0; + if (lpos && (diff == 0 || diff > 0xfff00000)) { + LOG_DEBUG("* latest pos=%d, pack pos=%d", getLatestPos(), pack.pos); + return false; + } + } + + if (willSkip()) // too far behind + { + lastSkipTime = sys->getTime(); + return false; + } + + lock.on(); + + pack.sync = writePos; + packets[writePos%MAX_PACKETS].init(pack); + +// LOG_DEBUG("packet.len = %d",pack.len); + + + lastPos = writePos; + writePos++; + + if (writePos >= MAX_PACKETS) + firstPos = writePos-MAX_PACKETS; + else + firstPos = 0; + + if (writePos >= NUM_SAFEPACKETS) + safePos = writePos - NUM_SAFEPACKETS; + else + safePos = 0; + + if (updateReadPos) + readPos = writePos; + + lastWriteTime = sys->getTime(); + + lock.off(); + return true; + } + + return false; +} +// ----------------------------------- +void ChanPacketBuffer::readPacket(ChanPacket &pack) +{ + + unsigned int tim = sys->getTime(); + + if (readPos < firstPos) + throw StreamException("Read too far behind"); + + while (readPos >= writePos) + { + sys->sleepIdle(); + if ((sys->getTime() - tim) > 30) + throw TimeoutException(); + } + lock.on(); + pack.init(packets[readPos%MAX_PACKETS]); + readPos++; + lock.off(); + + sys->sleepIdle(); + +} +// ----------------------------------- +bool ChanPacketBuffer::willSkip() +{ + return ((writePos-readPos) >= MAX_PACKETS); +} + +// ----------------------------------- +void Channel::getStreamPath(char *str) +{ + char idStr[64]; + + getIDStr(idStr); + + sprintf(str,"/stream/%s%s",idStr,info.getTypeExt(info.contentType)); +} + + + +// ----------------------------------- +void ChanMgr::startSearch(ChanInfo &info) +{ + searchInfo = info; + clearHitLists(); + numFinds = 0; + lastHit = 0; +// lastSearch = 0; + searchActive = true; +} +// ----------------------------------- +void ChanMgr::quit() +{ + LOG_DEBUG("ChanMgr is quitting.."); + closeAll(); +} +// ----------------------------------- +int ChanMgr::numIdleChannels() +{ + int cnt=0; + Channel *ch = channel; + while (ch) + { + if (ch->isActive()) + if (ch->thread.active) + if (ch->status == Channel::S_IDLE) + cnt++; + ch=ch->next; + } + return cnt; +} +// ----------------------------------- +void ChanMgr::closeOldestIdle() +{ + unsigned int idleTime = (unsigned int)-1; + Channel *ch = channel,*oldest=NULL; + while (ch) + { + if (ch->isActive()) + if (ch->thread.active) + if (ch->status == Channel::S_IDLE) + if (ch->lastIdleTime < idleTime) + { + oldest = ch; + idleTime = ch->lastIdleTime; + } + ch=ch->next; + } + + if (oldest) + oldest->thread.active = false; +} + +// ----------------------------------- +void ChanMgr::closeAll() +{ + Channel *ch = channel; + while (ch) + { + if (ch->thread.active) + ch->thread.shutdown(); + ch=ch->next; + } +} +// ----------------------------------- +Channel *ChanMgr::findChannelByNameID(ChanInfo &info) +{ + Channel *ch = channel; + while (ch) + { + if (ch->isActive()) + if (ch->info.matchNameID(info)) + return ch; + ch=ch->next; + } + return NULL; +} + +// ----------------------------------- +Channel *ChanMgr::findChannelByName(const char *n) +{ + Channel *ch = channel; + while (ch) + { + if (ch->isActive()) + if (stricmp(ch->info.name,n)==0) + return ch; + ch=ch->next; + } + + return NULL; +} +// ----------------------------------- +Channel *ChanMgr::findChannelByIndex(int index) +{ + int cnt=0; + Channel *ch = channel; + while (ch) + { + if (ch->isActive()) + { + if (cnt == index) + return ch; + cnt++; + } + ch=ch->next; + } + return NULL; +} +// ----------------------------------- +Channel *ChanMgr::findChannelByMount(const char *str) +{ + Channel *ch = channel; + while (ch) + { + if (ch->isActive()) + if (strcmp(ch->mount,str)==0) + return ch; + ch=ch->next; + } + + return NULL; +} +// ----------------------------------- +Channel *ChanMgr::findChannelByID(GnuID &id) +{ + Channel *ch = channel; + while (ch) + { + if (ch->isActive()) + if (ch->info.id.isSame(id)) + return ch; + ch=ch->next; + } + return NULL; +} +// ----------------------------------- +Channel *ChanMgr::findChannelByChannelID(int id) +{ + int cnt=0; + Channel *ch = channel; + while (ch) + { + if (ch->isActive()){ + if (ch->channel_id == id){ + return ch; + } + } + ch = ch->next; + } + return NULL; +} +// ----------------------------------- +int ChanMgr::findChannels(ChanInfo &info, Channel **chlist, int max) +{ + int cnt=0; + Channel *ch = channel; + while (ch) + { + if (ch->isActive()) + if (ch->info.match(info)) + { + chlist[cnt++] = ch; + if (cnt >= max) + break; + } + ch=ch->next; + } + return cnt; +} +// ----------------------------------- +int ChanMgr::findChannelsByStatus(Channel **chlist, int max, Channel::STATUS status) +{ + int cnt=0; + Channel *ch = channel; + while (ch) + { + if (ch->isActive()) + if (ch->status == status) + { + chlist[cnt++] = ch; + if (cnt >= max) + break; + } + ch=ch->next; + } + return cnt; +} +// ----------------------------------- +Channel *ChanMgr::createRelay(ChanInfo &info, bool stayConnected) +{ + Channel *c = chanMgr->createChannel(info,NULL); + if (c) + { + c->stayConnected = stayConnected; + c->startGet(); + return c; + } + return NULL; +} +// ----------------------------------- +Channel *ChanMgr::findAndRelay(ChanInfo &info) +{ + char idStr[64]; + info.id.toStr(idStr); + LOG_CHANNEL("Searching for: %s (%s)",idStr,info.name.cstr()); + + if(!isIndexTxt(&info)) // for PCRaw (popup) + peercastApp->notifyMessage(ServMgr::NT_PEERCAST,"Finding channel..."); + + + Channel *c = NULL; + + WLockBlock wb(&(chanMgr->channellock)); + + wb.on(); + + c = findChannelByNameID(info); + + if (!c) + { + c = chanMgr->createChannel(info,NULL); + if (c) + { + c->setStatus(Channel::S_SEARCHING); + c->startGet(); + } + } else if (!(c->thread.active)){ + c->thread.active = true; + c->thread.finish = false; + if (c->finthread){ + c->finthread->finish = true; + c->finthread = NULL; + } + if (c->status != Channel::S_CONNECTING && c->status != Channel::S_SEARCHING){ + c->setStatus(Channel::S_SEARCHING); + c->startGet(); + } + } + + wb.off(); + + for(int i=0; i<600; i++) // search for 1 minute. + { + + + wb.on(); + c = findChannelByNameID(info); + + if (!c) + { +// peercastApp->notifyMessage(ServMgr::NT_PEERCAST,"Channel not found"); + return NULL; + } + + + if (c->isPlaying() && (c->info.contentType!=ChanInfo::T_UNKNOWN)) + break; + + wb.off(); + + sys->sleep(100); + } + + return c; +} +// ----------------------------------- +ChanMgr::ChanMgr() +{ + channel = NULL; + + hitlist = NULL; + + currFindAndPlayChannel.clear(); + + broadcastMsg.clear(); + broadcastMsgInterval=10; + + broadcastID.generate(PCP_BROADCAST_FLAGS); + + deadHitAge = 600; + + icyIndex = 0; + icyMetaInterval = 8192; + maxRelaysPerChannel = 1; + + searchInfo.init(); + + minBroadcastTTL = 1; + maxBroadcastTTL = 7; + + pushTimeout = 60; // 1 minute + pushTries = 5; // 5 times + maxPushHops = 8; // max 8 hops away + maxUptime = 0; // 0 = none + + prefetchTime = 10; // n seconds + + hostUpdateInterval = 120; // 2 minutes + + bufferTime = 5; + + autoQuery = 0; + lastQuery = 0; + + lastYPConnect = 0; + lastYPConnect2 = 0; + +} + +// ----------------------------------- +bool ChanMgr::writeVariable(Stream &out, const String &var, int index) +{ + char buf[1024]; + if (var == "numHitLists") + sprintf(buf,"%d",numHitLists()); + + else if (var == "numChannels") + sprintf(buf,"%d",numChannels()); + else if (var == "djMessage") + strcpy(buf,broadcastMsg.cstr()); + else if (var == "icyMetaInterval") + sprintf(buf,"%d",icyMetaInterval); + else if (var == "maxRelaysPerChannel") + sprintf(buf,"%d",maxRelaysPerChannel); + else if (var == "hostUpdateInterval") + sprintf(buf,"%d",hostUpdateInterval); + else if (var == "broadcastID") + broadcastID.toStr(buf); + else + return false; + + + + out.writeString(buf); + return true; +} + +// ----------------------------------- +bool Channel::writeVariable(Stream &out, const String &var, int index) +{ + char buf[1024]; + + buf[0]=0; + + String utf8; + + if (var == "name") + { + utf8 = info.name; + utf8.convertTo(String::T_UNICODESAFE); + strcpy(buf,utf8.cstr()); + + }else if (var == "bitrate") + { + sprintf(buf,"%d",info.bitrate); + + }else if (var == "srcrate") + { + if (sourceData) + { + unsigned int tot = sourceData->getSourceRate(); + sprintf(buf,"%.1f",BYTES_TO_KBPS(tot)); + }else + strcpy(buf,"0"); + + }else if (var == "genre") + { + utf8 = info.genre; + utf8.convertTo(String::T_UNICODESAFE); + strcpy(buf,utf8.cstr()); + }else if (var == "desc") + { + utf8 = info.desc; + utf8.convertTo(String::T_UNICODESAFE); + strcpy(buf,utf8.cstr()); + }else if (var == "comment") + { + utf8 = info.comment; + utf8.convertTo(String::T_UNICODESAFE); + strcpy(buf,utf8.cstr()); + }else if (var == "uptime") + { + String uptime; + if (info.lastPlayStart) + uptime.setFromStopwatch(sys->getTime()-info.lastPlayStart); + else + uptime.set("-"); + strcpy(buf,uptime.cstr()); + } + else if (var == "type") + sprintf(buf,"%s",ChanInfo::getTypeStr(info.contentType)); + else if (var == "ext") + sprintf(buf,"%s",ChanInfo::getTypeExt(info.contentType)); + else if (var == "proto") { + switch(info.contentType) { + case ChanInfo::T_WMA: + case ChanInfo::T_WMV: + sprintf(buf, "mms://"); + break; + default: + sprintf(buf, "http://"); + } + } + else if (var == "localRelays") + sprintf(buf,"%d",localRelays()); + else if (var == "localListeners") + sprintf(buf,"%d",localListeners()); + + else if (var == "totalRelays") + sprintf(buf,"%d",totalRelays()); + else if (var == "totalListeners") + sprintf(buf,"%d",totalListeners()); + + else if (var == "status") + sprintf(buf,"%s",getStatusStr()); + else if (var == "keep") + sprintf(buf,"%s",stayConnected?"Yes":"No"); + else if (var == "id") + info.id.toStr(buf); + else if (var.startsWith("track.")) + { + + if (var == "track.title") + utf8 = info.track.title; + else if (var == "track.artist") + utf8 = info.track.artist; + else if (var == "track.album") + utf8 = info.track.album; + else if (var == "track.genre") + utf8 = info.track.genre; + else if (var == "track.contactURL") + utf8 = info.track.contact; + + utf8.convertTo(String::T_UNICODESAFE); + strcpy(buf,utf8.cstr()); + + }else if (var == "contactURL") + sprintf(buf,"%s",info.url.cstr()); + else if (var == "streamPos") + sprintf(buf,"%d",streamPos); + else if (var == "sourceType") + strcpy(buf,getSrcTypeStr()); + else if (var == "sourceProtocol") + strcpy(buf,ChanInfo::getProtocolStr(info.srcProtocol)); + else if (var == "sourceURL") + { + if (sourceURL.isEmpty()) + sourceHost.host.toStr(buf); + else + strcpy(buf,sourceURL.cstr()); + } + else if (var == "headPos") + sprintf(buf,"%d",headPack.pos); + else if (var == "headLen") + sprintf(buf,"%d",headPack.len); + else if (var == "numHits") + { + ChanHitList *chl = chanMgr->findHitListByID(info.id); + int numHits = 0; + if (chl){ +// numHits = chl->numHits(); + ChanHit *hit; + hit = chl->hit; + while(hit){ + numHits++; + hit = hit->next; + } + } + sprintf(buf,"%d",numHits); + } else if (var == "isBroadcast") + strcpy(buf, (type == T_BROADCAST) ? "1":"0"); + else + return false; + + out.writeString(buf); + return true; +} + +// ----------------------------------- +void ChanMgr::broadcastTrackerUpdate(GnuID &svID, bool force) +{ + Channel *c = channel; + while(c) + { + if ( c->isActive() && c->isBroadcasting() ) + c->broadcastTrackerUpdate(svID,force); + c=c->next; + } +} + + +// ----------------------------------- +int ChanMgr::broadcastPacketUp(ChanPacket &pack,GnuID &chanID, GnuID &srcID, GnuID &destID) +{ + int cnt=0; + + Channel *c = channel; + while(c) + { + if (c->sendPacketUp(pack,chanID,srcID,destID)) + cnt++; + c=c->next; + } + + return cnt; +} + +// ----------------------------------- +void ChanMgr::broadcastRelays(Servent *serv, int minTTL, int maxTTL) +{ + //if ((servMgr->getFirewall() == ServMgr::FW_OFF) || servMgr->serverHost.localIP()) + { + + Host sh = servMgr->serverHost; + bool push = (servMgr->getFirewall()!=ServMgr::FW_OFF); + bool busy = (servMgr->pubInFull() && servMgr->outFull()) || servMgr->relaysFull(); + bool stable = servMgr->totalStreams>0; + + + GnuPacket hit; + + int numChans=0; + + Channel *c = channel; + while(c) + { + if (c->isPlaying()) + { + + bool tracker = c->isBroadcasting(); + + int ttl = (c->info.getUptime() / servMgr->relayBroadcast); // 1 hop per N seconds + + if (ttl < minTTL) + ttl = minTTL; + + if (ttl > maxTTL) + ttl = maxTTL; + + if (hit.initHit(sh,c,NULL,push,busy,stable,tracker,ttl)) + { + int numOut=0; + numChans++; + if (serv) + { + serv->outputPacket(hit,false); + numOut++; + } + + LOG_NETWORK("Sent channel to %d servents, TTL %d",numOut,ttl); + + } + } + c=c->next; + } + //if (numChans) + // LOG_NETWORK("Sent %d channels to %d servents",numChans,numOut); + } +} +// ----------------------------------- +void ChanMgr::setUpdateInterval(unsigned int v) +{ + hostUpdateInterval = v; +} + + +// ----------------------------------- +// message check +#if 0 + ChanPacket pack; + MemoryStream mem(pack.data,sizeof(pack.data)); + AtomStream atom(mem); + atom.writeParent(PCP_BCST,3); + atom.writeChar(PCP_BCST_GROUP,PCP_BCST_GROUP_ALL); + atom.writeBytes(PCP_BCST_FROM,servMgr->sessionID.id,16); + atom.writeParent(PCP_MESG,1); + atom.writeString(PCP_MESG_DATA,msg.cstr()); + + mem.len = mem.pos; + mem.rewind(); + pack.len = mem.len; + + GnuID noID; + noID.clear(); + + BroadcastState bcs; + PCPStream::readAtom(atom,bcs); + //int cnt = servMgr->broadcastPacketUp(pack,noID,servMgr->sessionID); + //int cnt = servMgr->broadcastPacketDown(pack,noID,servMgr->sessionID); + //int cnt = chanMgr->broadcastPacketUp(pack,noID,servMgr->sessionID); + //LOG_DEBUG("Sent message to %d clients",cnt); +#endif +// ----------------------------------- +void ChanMgr::setBroadcastMsg(String &msg) +{ + if (!msg.isSame(broadcastMsg)) + { + broadcastMsg = msg; + + Channel *c = channel; + while(c) + { + if (c->isActive() && c->isBroadcasting()) + { + ChanInfo newInfo = c->info; + newInfo.comment = broadcastMsg; + c->updateInfo(newInfo); + } + c=c->next; + } + + } +} + + +// ----------------------------------- +void ChanMgr::clearHitLists() +{ + +// LOG_DEBUG("clearHitLists HITLISTLOCK ON-------------"); + chanMgr->hitlistlock.on(); + while (hitlist) + { + peercastApp->delChannel(&hitlist->info); + + ChanHitList *next = hitlist->next; + + delete hitlist; + + hitlist = next; + } +// LOG_DEBUG("clearHitLists HITLISTLOCK OFF-------------"); + chanMgr->hitlistlock.off(); +} +// ----------------------------------- +Channel *ChanMgr::deleteChannel(Channel *delchan) +{ + lock.on(); + + Channel *ch = channel,*prev=NULL,*next=NULL; + + while (ch) + { + if (ch == delchan) + { + Channel *next = ch->next; + if (prev) + prev->next = next; + else + channel = next; + + if (delchan->sourceStream){ + delchan->sourceStream->parent = NULL; + } + + delete delchan; + + break; + } + prev = ch; + ch=ch->next; + } + + + lock.off(); + return next; +} + +// ----------------------------------- +Channel *ChanMgr::createChannel(ChanInfo &info, const char *mount) +{ + lock.on(); + + Channel *nc=NULL; + + nc = new Channel(); + + nc->next = channel; + channel = nc; + + + nc->info = info; + nc->info.lastPlayStart = 0; + nc->info.lastPlayEnd = 0; + nc->info.status = ChanInfo::S_UNKNOWN; + if (mount) + nc->mount.set(mount); + nc->setStatus(Channel::S_WAIT); + nc->type = Channel::T_ALLOCATED; + nc->info.createdTime = sys->getTime(); + + LOG_CHANNEL("New channel created"); + + lock.off(); + return nc; +} +// ----------------------------------- +int ChanMgr::pickHits(ChanHitSearch &chs) +{ + ChanHitList *chl = hitlist; + while(chl) + { + if (chl->isUsed()) + if (chl->pickHits(chs)) + { + chl->info.id; + return 1; + } + chl = chl->next; + } + return 0; +} + +// ----------------------------------- +ChanHitList *ChanMgr::findHitList(ChanInfo &info) +{ + ChanHitList *chl = hitlist; + while(chl) + { + if (chl->isUsed()) + if (chl->info.matchNameID(info)) + return chl; + + chl = chl->next; + } + return NULL; +} +// ----------------------------------- +ChanHitList *ChanMgr::findHitListByID(GnuID &id) +{ + ChanHitList *chl = hitlist; + while(chl) + { + if (chl->isUsed()) + if (chl->info.id.isSame(id)) + return chl; + chl = chl->next; + } + return NULL; +} +// ----------------------------------- +int ChanMgr::numHitLists() +{ + int num=0; + ChanHitList *chl = hitlist; + while(chl) + { + if (chl->isUsed()) + num++; + chl = chl->next; + } + return num; +} +// ----------------------------------- +ChanHitList *ChanMgr::addHitList(ChanInfo &info) +{ + ChanHitList *chl = new ChanHitList(); + + + chl->next = hitlist; + hitlist = chl; + + chl->used = true; + chl->info = info; + chl->info.createdTime = sys->getTime(); + peercastApp->addChannel(&chl->info); + + + return chl; +} +// ----------------------------------- +void ChanMgr::clearDeadHits(bool clearTrackers) +{ + unsigned int interval; + + if (servMgr->isRoot) + interval = 1200; // mainly for old 0.119 clients + else + interval = hostUpdateInterval+120; + + chanMgr->hitlistlock.on(); + ChanHitList *chl = hitlist,*prev = NULL; + while (chl) + { + if (chl->isUsed()) + { + if (chl->clearDeadHits(interval,clearTrackers) == 0) + { + if (!isBroadcasting(chl->info.id)) + { + if (!chanMgr->findChannelByID(chl->info.id)) + { + peercastApp->delChannel(&chl->info); + + ChanHitList *next = chl->next; + if (prev) + prev->next = next; + else + hitlist = next; + + delete chl; + chl = next; + continue; + } + } + } + } + prev = chl; + chl = chl->next; + } + chanMgr->hitlistlock.off(); +} +// ----------------------------------- +bool ChanMgr::isBroadcasting(GnuID &id) +{ + Channel *ch = findChannelByID(id); + if (ch) + return ch->isBroadcasting(); + + return false; +} +// ----------------------------------- +bool ChanMgr::isBroadcasting() +{ + Channel *ch = channel; + while (ch) + { + if (ch->isActive()) + if (ch->isBroadcasting()) + return true; + + ch = ch->next; + } + return false; +} + +// ----------------------------------- +int ChanMgr::numChannels() +{ + int tot = 0; + Channel *ch = channel; + while (ch) + { + if (ch->isActive()) + tot++; + ch = ch->next; + } + return tot; +} + +// ----------------------------------- +void ChanMgr::deadHit(ChanHit &hit) +{ + ChanHitList *chl = findHitListByID(hit.chanID); + if (chl) + chl->deadHit(hit); +} +// ----------------------------------- +void ChanMgr::delHit(ChanHit &hit) +{ + ChanHitList *chl = findHitListByID(hit.chanID); + if (chl) + chl->delHit(hit); +} + +// ----------------------------------- +void ChanMgr::addHit(Host &h,GnuID &id,bool tracker) +{ + ChanHit hit; + hit.init(); + hit.host = h; + hit.rhost[0] = h; + hit.rhost[1].init(); + hit.tracker = tracker; + hit.recv = true; + hit.chanID = id; + addHit(hit); +} +// ----------------------------------- +ChanHit *ChanMgr::addHit(ChanHit &h) +{ + if (searchActive) + lastHit = sys->getTime(); + + ChanHitList *hl=NULL; + + hl = findHitListByID(h.chanID); + + if (!hl) + { + ChanInfo info; + info.id = h.chanID; + hl = addHitList(info); + } + + if (hl) + { + return hl->addHit(h); + }else + return NULL; +} + +// ----------------------------------- +class ChanFindInfo : public ThreadInfo +{ +public: + ChanInfo info; + bool keep; +}; +// ----------------------------------- +THREAD_PROC findAndPlayChannelProc(ThreadInfo *th) +{ + ChanFindInfo *cfi = (ChanFindInfo *)th; + + ChanInfo info; + info = cfi->info; + + + Channel *ch = chanMgr->findChannelByNameID(info); + + chanMgr->currFindAndPlayChannel = info.id; + + if (!ch) + ch = chanMgr->findAndRelay(info); + + if (ch) + { + // check that a different channel hasn`t be selected already. + if (chanMgr->currFindAndPlayChannel.isSame(ch->info.id)) + chanMgr->playChannel(ch->info); + + if (cfi->keep) + ch->stayConnected = cfi->keep; + } + + delete cfi; + return 0; +} +// ----------------------------------- +void ChanMgr::findAndPlayChannel(ChanInfo &info, bool keep) +{ + ChanFindInfo *cfi = new ChanFindInfo; + cfi->info = info; + cfi->keep = keep; + cfi->func = findAndPlayChannelProc; + + + sys->startThread(cfi); +} +// ----------------------------------- +void ChanMgr::playChannel(ChanInfo &info) +{ + + char str[128],fname[256],idStr[128]; + + sprintf(str,"http://localhost:%d",servMgr->serverHost.port); + info.id.toStr(idStr); + + PlayList::TYPE type; + + + if ((info.contentType == ChanInfo::T_WMA) || (info.contentType == ChanInfo::T_WMV)) + { + type = PlayList::T_ASX; + // WMP seems to have a bug where it doesn`t re-read asx files if they have the same name + // so we prepend the channel id to make it unique - NOTE: should be deleted afterwards. + if (servMgr->getModulePath) //JP-EX + { + peercastApp->getDirectory(); + sprintf(fname,"%s/%s.asx",servMgr->modulePath,idStr); + }else + sprintf(fname,"%s/%s.asx",peercastApp->getPath(),idStr); + }else if (info.contentType == ChanInfo::T_OGM) + { + type = PlayList::T_RAM; + if (servMgr->getModulePath) //JP-EX + { + peercastApp->getDirectory(); + sprintf(fname,"%s/play.ram",servMgr->modulePath); + }else + sprintf(fname,"%s/play.ram",peercastApp->getPath()); + + }else + { + type = PlayList::T_SCPLS; + if (servMgr->getModulePath) //JP-EX + { + peercastApp->getDirectory(); + sprintf(fname,"%s/play.pls",servMgr->modulePath); + }else + sprintf(fname,"%s/play.pls",peercastApp->getPath()); + } + + + PlayList *pls = new PlayList(type,1); + pls->addChannel(str,info); + + + LOG_DEBUG("Writing %s",fname); + FileStream file; + file.openWriteReplace(fname); + pls->write(file); + file.close(); + + + LOG_DEBUG("Executing: %s",fname); + sys->executeFile(fname); + delete pls; + +} + +// ----------------------------------- +ChanHitList::ChanHitList() +{ + info.init(); + lastHitTime = 0; + used = false; + hit = NULL; +} +// ----------------------------------- +ChanHitList::~ChanHitList() +{ + chanMgr->hitlistlock.on(); + while (hit) + hit = deleteHit(hit); + chanMgr->hitlistlock.off(); +} +// ----------------------------------- +void ChanHit::pickNearestIP(Host &h) +{ + for(int i=0; i<2; i++) + { + if (h.classType() == rhost[i].classType()) + { + host = rhost[i]; + break; + } + } +} + +// ----------------------------------- +void ChanHit::init() +{ + host.init(); + + rhost[0].init(); + rhost[1].init(); + + next = NULL; + + numListeners = 0; + numRelays = 0; + + dead = tracker = firewalled = stable = yp = false; + recv = cin = direct = relay = true; + relayfull = chfull = ratefull = false; + direct = 0; + numHops = 0; + time = upTime = 0; + lastContact = 0; + + version = 0; + version_vp = 0; + + version_ex_prefix[0] = ' '; + version_ex_prefix[1] = ' '; + version_ex_number = 0; + + status = 0; + + sessionID.clear(); + chanID.clear(); + + + oldestPos = newestPos = 0; + uphost.init(); + uphostHops = 0; +} + +// ----------------------------------- +void ChanHit::initLocal(int numl,int numr,int,int uptm,bool connected,bool isFull,unsigned int bitrate, Channel* ch, unsigned int oldp,unsigned int newp) +{ + init(); + firewalled = (servMgr->getFirewall() != ServMgr::FW_OFF); + numListeners = numl; + numRelays = numr; + upTime = uptm; + stable = servMgr->totalStreams>0; + sessionID = servMgr->sessionID; + recv = connected; + + direct = !servMgr->directFull(); +// relay = !servMgr->relaysFull(); + cin = !servMgr->controlInFull(); + + relayfull = servMgr->relaysFull(); + chfull = isFull; + + Channel *c = chanMgr->channel; + int noRelay = 0; + unsigned int needRate = 0; + unsigned int allRate = 0; + while(c){ + if (c->isPlaying()){ + allRate += c->info.bitrate * c->localRelays(); + if ((c != ch) && (c->localRelays() == 0)){ + if(!isIndexTxt(c)) // for PCRaw (relay) + noRelay++; + needRate+=c->info.bitrate; + } + } + c = c->next; + } + int diff = servMgr->maxRelays - servMgr->numStreams(Servent::T_RELAY,false); + if (ch->localRelays()){ + if (noRelay > diff){ + noRelay = diff; + } + } else { + noRelay = 0; + needRate = 0; + } + + // for PCRaw (relay) start. + bool force_off = false; + + if(isIndexTxt(ch)) + force_off = true; + // for PCRaw (relay) end. + +// ratefull = servMgr->bitrateFull(needRate+bitrate); + ratefull = (servMgr->maxBitrateOut < allRate + needRate + ch->info.bitrate); + + //relay = (!relayfull) && (!chfull) && (!ratefull) && ((servMgr->numStreams(Servent::T_RELAY,false) + noRelay) < servMgr->maxRelays); + relay = (!relayfull || force_off) && (!chfull) && (!ratefull) + && (((servMgr->numStreams(Servent::T_RELAY,false) + noRelay) < servMgr->maxRelays) || force_off); // for PCRaw (relay) (force_off) + +/* if (relayfull){ + LOG_DEBUG("Reject by relay full"); + } + if (chfull){ + LOG_DEBUG("Reject by channel full"); + } + if (ratefull){ + LOG_DEBUG("Reject by rate: Max=%d Now=%d Need=%d ch=%d", servMgr->maxBitrateOut, allRate, needRate, ch->info.bitrate); + }*/ + + host = servMgr->serverHost; + + version = PCP_CLIENT_VERSION; + version_vp = PCP_CLIENT_VERSION_VP; +#ifdef VERSION_EX + strncpy(version_ex_prefix, PCP_CLIENT_VERSION_EX_PREFIX,2); + version_ex_number = PCP_CLIENT_VERSION_EX_NUMBER; +#else + version_ex_prefix[0] = ' '; + version_ex_prefix[1] = ' '; + version_ex_number = 0; +#endif + + status = ch->status; + + rhost[0] = Host(host.ip,host.port); + rhost[1] = Host(ClientSocket::getIP(NULL),host.port); + + if (firewalled) + rhost[0].port = 0; + + oldestPos = oldp; + newestPos = newp; + + uphost.ip = ch->sourceHost.host.ip; + uphost.port = ch->sourceHost.host.port; + uphostHops = 1; +} + +// ----------------------------------- +void ChanHit::writeAtoms(AtomStream &atom,GnuID &chanID) +{ + bool addChan=chanID.isSet(); + bool uphostdata=(uphost.ip != 0); + + int fl1 = 0; + if (recv) fl1 |= PCP_HOST_FLAGS1_RECV; + if (relay) fl1 |= PCP_HOST_FLAGS1_RELAY; + if (direct) fl1 |= PCP_HOST_FLAGS1_DIRECT; + if (cin) fl1 |= PCP_HOST_FLAGS1_CIN; + if (tracker) fl1 |= PCP_HOST_FLAGS1_TRACKER; + if (firewalled) fl1 |= PCP_HOST_FLAGS1_PUSH; + + atom.writeParent(PCP_HOST,13 + (addChan?1:0) + (uphostdata?3:0) + (version_ex_number?2:0)); + + if (addChan) + atom.writeBytes(PCP_HOST_CHANID,chanID.id,16); + atom.writeBytes(PCP_HOST_ID,sessionID.id,16); + atom.writeInt(PCP_HOST_IP,rhost[0].ip); + atom.writeShort(PCP_HOST_PORT,rhost[0].port); + atom.writeInt(PCP_HOST_IP,rhost[1].ip); + atom.writeShort(PCP_HOST_PORT,rhost[1].port); + atom.writeInt(PCP_HOST_NUML,numListeners); + atom.writeInt(PCP_HOST_NUMR,numRelays); + atom.writeInt(PCP_HOST_UPTIME,upTime); + atom.writeInt(PCP_HOST_VERSION,version); + atom.writeInt(PCP_HOST_VERSION_VP,version_vp); + if (version_ex_number){ + atom.writeBytes(PCP_HOST_VERSION_EX_PREFIX,version_ex_prefix,2); + atom.writeShort(PCP_HOST_VERSION_EX_NUMBER,version_ex_number); + } + atom.writeChar(PCP_HOST_FLAGS1,fl1); + atom.writeInt(PCP_HOST_OLDPOS,oldestPos); + atom.writeInt(PCP_HOST_NEWPOS,newestPos); + if (uphostdata){ + atom.writeInt(PCP_HOST_UPHOST_IP,uphost.ip); + atom.writeInt(PCP_HOST_UPHOST_PORT,uphost.port); + atom.writeInt(PCP_HOST_UPHOST_HOPS,uphostHops); + } +} +// ----------------------------------- +bool ChanHit::writeVariable(Stream &out, const String &var) +{ + char buf[1024]; + + if (var == "rhost0") + { + if (servMgr->enableGetName) //JP-EX s + { + char buf2[256]; + if (firewalled) + { + if (numRelays==0) + strcpy(buf,""); + else + strcpy(buf,""); + } + else { + if (!relay){ + if (numRelays==0){ + strcpy(buf,""); + } else { + strcpy(buf,""); + } + } else { + strcpy(buf,""); + } + } + + rhost[0].toStr(buf2); + strcat(buf,buf2); + + char h_name[128]; + if (ClientSocket::getHostname(h_name,rhost[0].ip)) + { + strcat(buf,"["); + strcat(buf,h_name); + strcat(buf,"]"); + } + strcat(buf,""); + } //JP-EX e + else + rhost[0].toStr(buf); + } + else if (var == "rhost1") + rhost[1].toStr(buf); + else if (var == "numHops") + sprintf(buf,"%d",numHops); + else if (var == "numListeners") + sprintf(buf,"%d",numListeners); + else if (var == "numRelays") + sprintf(buf,"%d",numRelays); + else if (var == "uptime") + { + String timeStr; + timeStr.setFromStopwatch(upTime); + strcpy(buf,timeStr.cstr()); + }else if (var == "update") + { + String timeStr; + if (timeStr) + timeStr.setFromStopwatch(sys->getTime()-time); + else + timeStr.set("-"); + strcpy(buf,timeStr.cstr()); + }else if (var == "isFirewalled"){ + sprintf(buf,"%d",firewalled?1:0); + }else if (var == "version"){ + sprintf(buf,"%d",version); + }else if (var == "agent"){ + if (version){ + if (version_ex_number){ + sprintf(buf, "v0.%d(%c%c%04d)", version, version_ex_prefix[0], version_ex_prefix[1], version_ex_number); + } else if (version_vp){ + sprintf(buf,"v0.%d(VP%04d)", version, version_vp); + } else { + sprintf(buf,"v0.%d", version); + } + } else { + strcpy(buf, "0"); + } + } + else if (var == "check") + { + char buf2[256]; + strcpy(buf, "_"); + } + else if (var == "uphost") // tree + uphost.toStr(buf); + else if (var == "uphostHops") // tree + sprintf(buf,"%d",uphostHops); + else if (var == "canRelay") // tree + sprintf(buf, "%d",relay); + else + return false; + + out.writeString(buf); + return true; +} + +// ----------------------------------- +int ChanHitList::getTotalListeners() +{ + int cnt=0; + ChanHit *h = hit; + while (h) + { + if (h->host.ip) + cnt+=h->numListeners; + h=h->next; + } + return cnt; +} +// ----------------------------------- +int ChanHitList::getTotalRelays() +{ + int cnt=0; + ChanHit *h = hit; + while (h) + { + if (h->host.ip) + cnt+=h->numRelays; + h=h->next; + } + return cnt; +} +// ----------------------------------- +int ChanHitList::getTotalFirewalled() +{ + int cnt=0; + ChanHit *h = hit; + while (h) + { + if (h->host.ip) + if (h->firewalled) + cnt++; + h=h->next; + } + return cnt; +} + +// ----------------------------------- +int ChanHitList::contactTrackers(bool connected, int numl, int nums, int uptm) +{ + return 0; +} + +void ChanHitList::clearHits(bool flg) +{ + ChanHit *c = hit, *prev = NULL; + + while(c){ + if (flg || (c->numHops != 0)){ + ChanHit *next = c->next; + if (prev) + prev->next = next; + else + hit = next; + + delete c; + c = next; + } else { + prev = c; + c = c->next; + } + } +} + +// ----------------------------------- +ChanHit *ChanHitList::deleteHit(ChanHit *ch) +{ + ChanHit *c = hit,*prev=NULL; + while (c) + { + if (c == ch) + { + ChanHit *next = c->next; + if (prev) + prev->next = next; + else + hit = next; + + delete c; + + return next; + } + prev=c; + c=c->next; + } + + return NULL; +} +// ----------------------------------- +ChanHit *ChanHitList::addHit(ChanHit &h) +{ + char ip0str[64],ip1str[64]; + h.rhost[0].toStr(ip0str); + h.rhost[1].toStr(ip1str); + char uphostStr[64]; + h.uphost.toStr(uphostStr); + if (h.uphost.ip){ + LOG_DEBUG("Add hit: F%dT%dR%d %s/%s <- %s(%d)",h.firewalled,h.tracker,h.relay,ip0str,ip1str,uphostStr, h.uphostHops); + } else { + LOG_DEBUG("Add hit: F%dT%dR%d %s/%s",h.firewalled,h.tracker,h.relay,ip0str,ip1str); + } + + // dont add our own hits + if (servMgr->sessionID.isSame(h.sessionID)) + return NULL; + + + lastHitTime = sys->getTime(); + h.time = lastHitTime; + + ChanHit *ch = hit; + while (ch) + { + if ((ch->rhost[0].ip == h.rhost[0].ip) && (ch->rhost[0].port == h.rhost[0].port)) + if (((ch->rhost[1].ip == h.rhost[1].ip) && (ch->rhost[1].port == h.rhost[1].port)) || (!ch->rhost[1].isValid())) + { + if (!ch->dead) + { + if (ch->numHops > 0 && h.numHops == 0) + // downstream hit recieved as RelayHost + return ch; + ChanHit *next = ch->next; + *ch = h; + ch->next = next; + return ch; + } + } + ch=ch->next; + } + + // clear hits with same session ID (IP may have changed) + if (h.sessionID.isSet()) + { + ChanHit *ch = hit; + while (ch) + { + if (ch->host.ip) + if (ch->sessionID.isSame(h.sessionID)) + { + ch = deleteHit(ch); + continue; + } + ch=ch->next; + } + } + + + // else add new hit + { + ChanHit *ch = new ChanHit(); + *ch = h; + ch->chanID = info.id; + ch->next = hit; + hit = ch; + return ch; + } + + return NULL; +} + + +// ----------------------------------- +int ChanHitList::clearDeadHits(unsigned int timeout, bool clearTrackers) +{ + int cnt=0; + unsigned int ctime = sys->getTime(); + +// LOG_DEBUG("clearDeadHits HITLISTLOCK ON-------------"); + chanMgr->hitlistlock.on(); + ChanHit *ch = hit; + while (ch) + { + if (ch->host.ip) + { + if (ch->dead || ((ctime-ch->time) > timeout) && (clearTrackers || (!clearTrackers & !ch->tracker))) + { +// ch = deleteHit(ch); + + if (ch->firewalled){ +// LOG_DEBUG("kickKeepTime = %d, %d", servMgr->kickKeepTime, ctime-ch->time); + if ( (servMgr->kickKeepTime == 0) || ((ctime-ch->time) > servMgr->kickKeepTime) ){ + ch = deleteHit(ch); + } else { + ch->numHops = 0; + ch->numListeners = 0; + ch = ch->next; + } + } else { + ch = deleteHit(ch); + } + + continue; + }else + cnt++; + } + ch = ch->next; + } +// LOG_DEBUG("clearDeadHits HITLISTLOCK OFF-------------"); + chanMgr->hitlistlock.off(); + return cnt; +} + + +// ----------------------------------- +void ChanHitList::deadHit(ChanHit &h) +{ + char ip0str[64],ip1str[64]; + h.rhost[0].toStr(ip0str); + h.rhost[1].toStr(ip1str); + LOG_DEBUG("Dead hit: %s/%s",ip0str,ip1str); + + ChanHit *ch = hit; + while (ch) + { + if (ch->host.ip) + if (ch->rhost[0].isSame(h.rhost[0]) && ch->rhost[1].isSame(h.rhost[1])) + { + ch->dead = true; + } + ch = ch->next; + } +} +// ----------------------------------- +void ChanHitList::delHit(ChanHit &h) +{ + char ip0str[64],ip1str[64]; + h.rhost[0].toStr(ip0str); + h.rhost[1].toStr(ip1str); + LOG_DEBUG("Del hit: %s/%s",ip0str,ip1str); + + ChanHit *ch = hit; + while (ch) + { + if (ch->host.ip) + if (ch->rhost[0].isSame(h.rhost[0]) && ch->rhost[1].isSame(h.rhost[1])) + { + ch=deleteHit(ch); + continue; + } + ch = ch->next; + } +} +// ----------------------------------- +int ChanHitList::numHits() +{ + int cnt=0; + ChanHit *ch = hit; + while (ch) + { + if (ch->host.ip && !ch->dead && ch->numHops) + cnt++; + ch = ch->next; + } + + return cnt; +} +// ----------------------------------- +int ChanHitList::numListeners() +{ + int cnt=0; + ChanHit *ch = hit; + while (ch) + { + if (ch->host.ip && !ch->dead && ch->numHops) + cnt += ch->numListeners; + ch=ch->next; + } + + return cnt; +} +// ----------------------------------- +int ChanHitList::numRelays() +{ + int cnt=0; + ChanHit *ch = hit; + while (ch) + { + if (ch->host.ip && !ch->dead) + cnt += ch->numRelays; + ch=ch->next; + } + + return cnt; +} + +// ----------------------------------- +int ChanHitList::numTrackers() +{ + int cnt=0; + ChanHit *ch = hit; + while (ch) + { + if ((ch->host.ip && !ch->dead) && (ch->tracker)) + cnt++; + ch=ch->next; + } + return cnt; +} +// ----------------------------------- +int ChanHitList::numFirewalled() +{ + int cnt=0; + ChanHit *ch = hit; + while (ch) + { + if (ch->host.ip && !ch->dead) + cnt += ch->firewalled?1:0; + ch=ch->next; + } + return cnt; +} +// ----------------------------------- +int ChanHitList::closestHit() +{ + unsigned int hop=10000; + ChanHit *ch = hit; + while (ch) + { + if (ch->host.ip && !ch->dead) + if (ch->numHops < hop) + hop = ch->numHops; + ch=ch->next; + } + + return hop; +} +// ----------------------------------- +int ChanHitList::furthestHit() +{ + unsigned int hop=0; + ChanHit *ch = hit; + while (ch) + { + if (ch->host.ip && !ch->dead) + if (ch->numHops > hop) + hop = ch->numHops; + ch=ch->next; + } + + return hop; +} +// ----------------------------------- +unsigned int ChanHitList::newestHit() +{ + unsigned int time=0; + ChanHit *ch = hit; + while (ch) + { + if (ch->host.ip && !ch->dead) + if (ch->time > time) + time = ch->time; + ch=ch->next; + } + + return time; +} +// ----------------------------------- +int ChanHitList::pickHits(ChanHitSearch &chs) +{ + ChanHit best,*bestP=NULL; + best.init(); + best.numHops = 255; + best.time = 0; + + unsigned int ctime = sys->getTime(); + + ChanHit *c = hit; + while (c) + { + if (c->host.ip && !c->dead) + { + if (!chs.excludeID.isSame(c->sessionID)) + if ((chs.waitDelay==0) || ((ctime-c->lastContact) >= chs.waitDelay)) + if ((c->numHops<=best.numHops)) // (c->time>=best.time)) + if (c->relay || (!c->relay && chs.useBusyRelays)) + if (c->cin || (!c->cin && chs.useBusyControls)) + { + + if (chs.trackersOnly && c->tracker) + { + if (chs.matchHost.ip) + { + if ((c->rhost[0].ip == chs.matchHost.ip) && c->rhost[1].isValid()) + { + bestP = c; + best = *c; + best.host = best.rhost[1]; // use lan ip + } + }else if (c->firewalled == chs.useFirewalled) + { + bestP = c; + best = *c; + best.host = best.rhost[0]; // use wan ip + } + }else if (!chs.trackersOnly && !c->tracker) + { + if (chs.matchHost.ip) + { + if ((c->rhost[0].ip == chs.matchHost.ip) && c->rhost[1].isValid()) + { + bestP = c; + best = *c; + best.host = best.rhost[1]; // use lan ip + } + }else if (c->firewalled == chs.useFirewalled && (!bestP || !bestP->relay)) + { + bestP = c; + best = *c; + best.host = best.rhost[0]; // use wan ip + } + } + } + } + c=c->next; + } + + if (bestP) + { + if (chs.numResults < ChanHitSearch::MAX_RESULTS) + { + if (chs.waitDelay) + bestP->lastContact = ctime; + chs.best[chs.numResults++] = best; + return 1; + } + + } + + return 0; +} + + +// ----------------------------------- +int ChanHitList::pickSourceHits(ChanHitSearch &chs) +{ + if (pickHits(chs) && chs.best[0].numHops == 0) return 1; + return 0; +} + + +// ----------------------------------- +const char *ChanInfo::getTypeStr(TYPE t) +{ + switch (t) + { + case T_RAW: return "RAW"; + + case T_MP3: return "MP3"; + case T_OGG: return "OGG"; + case T_OGM: return "OGM"; + case T_WMA: return "WMA"; + + case T_MOV: return "MOV"; + case T_MPG: return "MPG"; + case T_NSV: return "NSV"; + case T_WMV: return "WMV"; + + case T_PLS: return "PLS"; + case T_ASX: return "ASX"; + + default: return "UNKNOWN"; + } +} +// ----------------------------------- +const char *ChanInfo::getProtocolStr(PROTOCOL t) +{ + switch (t) + { + case SP_PEERCAST: return "PEERCAST"; + case SP_HTTP: return "HTTP"; + case SP_FILE: return "FILE"; + case SP_MMS: return "MMS"; + case SP_PCP: return "PCP"; + default: return "UNKNOWN"; + } +} +// ----------------------------------- +ChanInfo::PROTOCOL ChanInfo::getProtocolFromStr(const char *str) +{ + if (stricmp(str,"PEERCAST")==0) + return SP_PEERCAST; + else if (stricmp(str,"HTTP")==0) + return SP_HTTP; + else if (stricmp(str,"FILE")==0) + return SP_FILE; + else if (stricmp(str,"MMS")==0) + return SP_MMS; + else if (stricmp(str,"PCP")==0) + return SP_PCP; + else + return SP_UNKNOWN; +} + +// ----------------------------------- +const char *ChanInfo::getTypeExt(TYPE t) +{ + switch(t) + { + case ChanInfo::T_OGM: + case ChanInfo::T_OGG: + return ".ogg"; + case ChanInfo::T_MP3: + return ".mp3"; + case ChanInfo::T_MOV: + return ".mov"; + case ChanInfo::T_NSV: + return ".nsv"; + case ChanInfo::T_WMV: + return ".wmv"; + case ChanInfo::T_WMA: + return ".wma"; + default: + return ""; + } +} +// ----------------------------------- +ChanInfo::TYPE ChanInfo::getTypeFromStr(const char *str) +{ + if (stricmp(str,"MP3")==0) + return T_MP3; + else if (stricmp(str,"OGG")==0) + return T_OGG; + else if (stricmp(str,"OGM")==0) + return T_OGM; + else if (stricmp(str,"RAW")==0) + return T_RAW; + else if (stricmp(str,"NSV")==0) + return T_NSV; + else if (stricmp(str,"WMA")==0) + return T_WMA; + else if (stricmp(str,"WMV")==0) + return T_WMV; + else if (stricmp(str,"PLS")==0) + return T_PLS; + else if (stricmp(str,"M3U")==0) + return T_PLS; + else if (stricmp(str,"ASX")==0) + return T_ASX; + else + return T_UNKNOWN; +} +// ----------------------------------- +bool ChanInfo::matchNameID(ChanInfo &inf) +{ + if (inf.id.isSet()) + if (id.isSame(inf.id)) + return true; + + if (!inf.name.isEmpty()) + if (name.contains(inf.name)) + return true; + + return false; +} +// ----------------------------------- +bool ChanInfo::match(ChanInfo &inf) +{ + bool matchAny=true; + + if (inf.status != S_UNKNOWN) + { + if (status != inf.status) + return false; + } + + if (inf.bitrate != 0) + { + if (bitrate == inf.bitrate) + return true; + matchAny = false; + } + + if (inf.id.isSet()) + { + if (id.isSame(inf.id)) + return true; + matchAny = false; + } + + if (inf.contentType != T_UNKNOWN) + { + if (contentType == inf.contentType) + return true; + matchAny = false; + } + + if (!inf.name.isEmpty()) + { + if (name.contains(inf.name)) + return true; + matchAny = false; + } + + if (!inf.genre.isEmpty()) + { + if (genre.contains(inf.genre)) + return true; + matchAny = false; + } + + return matchAny; +} +// ----------------------------------- +bool TrackInfo::update(TrackInfo &inf) +{ + bool changed = false; + + if (!contact.isSame(inf.contact)) + { + contact = inf.contact; + changed = true; + } + + if (!title.isSame(inf.title)) + { + title = inf.title; + changed = true; + } + + if (!artist.isSame(inf.artist)) + { + artist = inf.artist; + changed = true; + } + + if (!album.isSame(inf.album)) + { + album = inf.album; + changed = true; + } + + if (!genre.isSame(inf.genre)) + { + genre = inf.genre; + changed = true; + } + + + return changed; +} + + +// ----------------------------------- +bool ChanInfo::update(ChanInfo &info) +{ + bool changed = false; + + + + // check valid id + if (!info.id.isSet()) + return false; + + // only update from chaninfo that has full name etc.. + if (info.name.isEmpty()) + return false; + + // check valid broadcaster key + if (bcID.isSet()) + { + if (!bcID.isSame(info.bcID)) + { + LOG_ERROR("ChanInfo BC key not valid"); + return false; + } + }else + { + bcID = info.bcID; + } + + + + if (bitrate != info.bitrate) + { + bitrate = info.bitrate; + changed = true; + } + + if (contentType != info.contentType) + { + contentType = info.contentType; + changed = true; + } + + if (!desc.isSame(info.desc)) //JP-EX + { + desc = info.desc; + changed = true; + } + + if (!name.isSame(info.name)) + { + name = info.name; + changed = true; + } + + if (!comment.isSame(info.comment)) + { + comment = info.comment; + changed = true; + } + + if (!genre.isSame(info.genre)) + { + genre = info.genre; + changed = true; + } + + if (!url.isSame(info.url)) + { + url = info.url; + changed = true; + } + + if (track.update(info.track)) + changed = true; + + + return changed; +} +// ----------------------------------- +void ChanInfo::initNameID(const char *n) +{ + init(); + id.fromStr(n); + if (!id.isSet()) + name.set(n); +} + +// ----------------------------------- +void ChanInfo::init() +{ + status = S_UNKNOWN; + name.clear(); + bitrate = 0; + contentType = T_UNKNOWN; + srcProtocol = SP_UNKNOWN; + id.clear(); + url.clear(); + genre.clear(); + comment.clear(); + track.clear(); + lastPlayStart = 0; + lastPlayEnd = 0; + numSkips = 0; + bcID.clear(); + createdTime = 0; +} +// ----------------------------------- +void ChanInfo::readTrackXML(XML::Node *n) +{ + track.clear(); + readXMLString(track.title,n,"title"); + readXMLString(track.contact,n,"contact"); + readXMLString(track.artist,n,"artist"); + readXMLString(track.album,n,"album"); + readXMLString(track.genre,n,"genre"); +} +// ----------------------------------- +unsigned int ChanInfo::getUptime() +{ + // calculate uptime and cap if requested by settings. + unsigned int upt; + upt = lastPlayStart?(sys->getTime()-lastPlayStart):0; + if (chanMgr->maxUptime) + if (upt > chanMgr->maxUptime) + upt = chanMgr->maxUptime; + return upt; +} +// ----------------------------------- +unsigned int ChanInfo::getAge() +{ + return sys->getTime()-createdTime; +} + +// ------------------------------------------ +void ChanInfo::readTrackAtoms(AtomStream &atom,int numc) +{ + for(int i=0; ifindAttrInt("bitrate"); + if (br) + bitrate = br; + + readXMLString(typeStr,n,"type"); + if (!typeStr.isEmpty()) + contentType = getTypeFromStr(typeStr.cstr()); + + + readXMLString(idStr,n,"id"); + if (!idStr.isEmpty()) + id.fromStr(idStr.cstr()); + + readXMLString(comment,n,"comment"); + + XML::Node *tn = n->findNode("track"); + if (tn) + readTrackXML(tn); + +} + +// ----------------------------------- +void ChanInfo::init(const char *n, GnuID &cid, TYPE tp, int br) +{ + init(); + + name.set(n); + bitrate = br; + contentType = tp; + id = cid; +} + +// ----------------------------------- +void ChanInfo::init(const char *fn) +{ + init(); + + if (fn) + name.set(fn); +} +// ----------------------------------- +void PlayList::readASX(Stream &in) +{ + LOG_DEBUG("Reading ASX"); + XML xml; + + try + { + xml.read(in); + }catch(StreamException &) {} // TODO: eof is NOT handled properly in sockets - always get error at end + + if (xml.root) + { + XML::Node *n = xml.root->child; + while (n) + { + if (stricmp("entry",n->getName())==0) + { + XML::Node *rf = n->findNode("ref"); + if (rf) + { + char *hr = rf->findAttr("href"); + if (hr) + { + addURL(hr,""); + //LOG("asx url %s",hr); + } + + } + } + n=n->sibling; + } + } +} +// ----------------------------------- +void PlayList::readSCPLS(Stream &in) +{ + char tmp[256]; + while (in.readLine(tmp,sizeof(tmp))) + { + if (strnicmp(tmp,"file",4)==0) + { + char *p = strstr(tmp,"="); + if (p) + addURL(p+1,""); + } + } +} +// ----------------------------------- +void PlayList::readPLS(Stream &in) +{ + char tmp[256]; + while (in.readLine(tmp,sizeof(tmp))) + { + if (tmp[0] != '#') + addURL(tmp,""); + } +} +// ----------------------------------- +void PlayList::writeSCPLS(Stream &out) +{ + out.writeLine("[playlist]"); + out.writeLine(""); + out.writeLineF("NumberOfEntries=%d",numURLs); + + for(int i=0; i"); + for(int i=0; i"); + out.writeLineF("",urls[i].cstr()); + out.writeLine(""); + } + out.writeLine(""); +} + + +// ----------------------------------- +void PlayList::addChannel(const char *path, ChanInfo &info) +{ + String url; + + char idStr[64]; + + info.id.toStr(idStr); + char *nid = info.id.isSet()?idStr:info.name.cstr(); + + sprintf(url.cstr(),"%s/stream/%s%s",path,nid,ChanInfo::getTypeExt(info.contentType)); + addURL(url.cstr(),info.name); +} + +// ----------------------------------- +void ChanHitSearch::init() +{ + matchHost.init(); + waitDelay = 0; + useFirewalled = false; + trackersOnly = false; + useBusyRelays = true; + useBusyControls = true; + excludeID.clear(); + numResults = 0; + + //seed = sys->getTime(); + //srand(seed); +} + +int ChanHitSearch::getRelayHost(Host host1, Host host2, GnuID exID, ChanHitList *chl) +{ + int cnt = 0; + int loop = 1; + int index = 0; + int prob; + int rnd; + static int base = 0x400; + ChanHit tmpHit[MAX_RESULTS]; + static WLock seqLock; + static unsigned int riSequence = 0; + + //srand(seed); + //seed += 11; + + unsigned int seq; + seqLock.on(); + seq = riSequence++; + riSequence &= 0xffffff; + seqLock.off(); + + ChanHit *hit = chl->hit; + + while(hit){ + if (hit->host.ip && !hit->dead){ + if ( + (!exID.isSame(hit->sessionID)) +// && (hit->relay) + && (!hit->tracker) + && (!hit->firewalled) + && (hit->numHops != 0) + ){ + if ( (hit->rhost[0].ip == host1.ip) + && hit->rhost[1].isValid() + && (host2.ip != hit->rhost[1].ip) + ){ + best[0] = *hit; + best[0].host = hit->rhost[1]; + index++; + } + if ((hit->rhost[0].ip == host2.ip) && hit->rhost[1].isValid()){ + best[0] = *hit; + best[0].host = hit->rhost[1]; + index++; + } + + loop = (index / MAX_RESULTS) + 1; + //prob = (float)1 / (float)loop; + prob = base / loop; + //rnd = (float)rand() / (float)RAND_MAX; + rnd = rand() % base; + if (hit->numHops == 1){ + if (tmpHit[index % MAX_RESULTS].numHops == 1){ + if (rnd < prob){ + tmpHit[index % MAX_RESULTS] = *hit; + tmpHit[index % MAX_RESULTS].host = hit->rhost[0]; + index++; + } + } else { + tmpHit[index % MAX_RESULTS] = *hit; + tmpHit[index % MAX_RESULTS].host = hit->rhost[0]; + index++; + } + } else { + if ((tmpHit[index % MAX_RESULTS].numHops != 1) && (rnd < prob)){ + tmpHit[index % MAX_RESULTS] = *hit; + tmpHit[index % MAX_RESULTS].host = hit->rhost[0]; + index++; + } + } + +// char tmp[50]; +// hit->host.toStr(tmp); +// LOG_DEBUG("TEST %s: %f %f", tmp, rnd, prob); + } + } + hit = hit->next; + } + + if (index > MAX_RESULTS){ + cnt = MAX_RESULTS; + } else { + cnt = index; + } + +/* int use[MAX_RESULTS]; + memset(use, 0, sizeof(use)); + int i; + for (i = 0; i < cnt; i++){ + use[i] = -1; + } + int r; + for (i = 0; i < cnt; i++){ + do { + r = rand(); +// LOG_DEBUG("%d",r); + r = r % cnt; + if (use[r] == -1){ + use[r] = i; + break; + } + } while(1); + } + for (i = 0; i < cnt; i++){ +// LOG_DEBUG("%d", use[i]); + best[use[i]] = tmpHit[i]; + }*/ + + int use[MAX_RESULTS]; + int i; + for (i = 0; i < cnt; i++) { + use[i] = (i + seq) % cnt; + } + + for (i = 0; i < cnt; i++){ +// LOG_DEBUG("%d", use[i]); + best[use[i]] = tmpHit[i]; + } +// for (i = 0; i < cnt; i++){ +// char tmp[50]; +// best[i].host.toStr(tmp); +// LOG_DEBUG("Relay info: Hops = %d, %s", best[i].numHops, tmp); +// } + + return cnt; +} diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/channel.h b/c:/Git/PeerCast.root/PeerCast/core/common/channel.h new file mode 100644 index 0000000..d1d00fb --- /dev/null +++ b/c:/Git/PeerCast.root/PeerCast/core/common/channel.h @@ -0,0 +1,731 @@ +// ------------------------------------------------ +// File : channel.h +// Date: 4-apr-2002 +// Author: giles +// +// (c) 2002 peercast.org +// ------------------------------------------------ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// ------------------------------------------------ + +#ifndef _CHANNEL_H +#define _CHANNEL_H + +#include "sys.h" +#include "stream.h" +#include "gnutella.h" +#include "xml.h" +#include "asf.h" +#include "cstream.h" + +class AtomStream; +class ChanHitSearch; + +// -------------------------------------------------- +struct MP3Header +{ + int lay; + int version; + int error_protection; + int bitrate_index; + int sampling_frequency; + int padding; + int extension; + int mode; + int mode_ext; + int copyright; + int original; + int emphasis; + int stereo; +}; + +// ---------------------------------- +class TrackInfo +{ +public: + void clear() + { + contact.clear(); + title.clear(); + artist.clear(); + album.clear(); + genre.clear(); + } + + void convertTo(String::TYPE t) + { + contact.convertTo(t); + title.convertTo(t); + artist.convertTo(t); + album.convertTo(t); + genre.convertTo(t); + } + + bool update(TrackInfo &); + + ::String contact,title,artist,album,genre; +}; + + + +// ---------------------------------- +class ChanInfo +{ +public: + enum TYPE + { + T_UNKNOWN, + + T_RAW, + T_MP3, + T_OGG, + T_OGM, + T_MOV, + T_MPG, + T_NSV, + + T_WMA, + T_WMV, + + T_PLS, + T_ASX + }; + + + enum PROTOCOL + { + SP_UNKNOWN, + SP_PEERCAST, + SP_HTTP, + SP_FILE, + SP_MMS, + SP_PCP + }; + + + enum STATUS + { + S_UNKNOWN, + S_PLAY + }; + + ChanInfo() {init();} + + void init(); + void init(const char *); + void init(const char *, GnuID &, TYPE, int); + void init(XML::Node *); + void initNameID(const char *); + + void updateFromXML(XML::Node *); + + void readTrackXML(XML::Node *); + void readServentXML(XML::Node *); + bool update(ChanInfo &); + XML::Node *createQueryXML(); + XML::Node *createChannelXML(); + XML::Node *createRelayChannelXML(); + XML::Node *createTrackXML(); + bool match(XML::Node *); + bool match(ChanInfo &); + bool matchNameID(ChanInfo &); + + void writeInfoAtoms(AtomStream &atom); + void writeTrackAtoms(AtomStream &atom); + + void readInfoAtoms(AtomStream &,int); + void readTrackAtoms(AtomStream &,int); + + unsigned int getUptime(); + unsigned int getAge(); + bool isActive() {return id.isSet();} + bool isPrivate() {return bcID.getFlags() & 1;} + static const char *getTypeStr(TYPE); + static const char *getProtocolStr(PROTOCOL); + static const char *getTypeExt(TYPE); + static TYPE getTypeFromStr(const char *str); + static PROTOCOL getProtocolFromStr(const char *str); + + ::String name; + GnuID id,bcID; + int bitrate; + TYPE contentType; + PROTOCOL srcProtocol; + unsigned int lastPlayStart,lastPlayEnd; + unsigned int numSkips; + unsigned int createdTime; + + STATUS status; + + TrackInfo track; + ::String desc,genre,url,comment; + +}; + + +// ---------------------------------- +class ChanHit +{ +public: + void init(); + void initLocal(int numl,int numr,int nums,int uptm,bool,bool,unsigned int,Channel*,unsigned int,unsigned int); + XML::Node *createXML(); + + void writeAtoms(AtomStream &,GnuID &); + bool writeVariable(Stream &, const String &); + + void pickNearestIP(Host &); + + Host host; + Host rhost[2]; + unsigned int numListeners,numRelays,numHops; + unsigned int time,upTime,lastContact; + unsigned int hitID; + GnuID sessionID,chanID; + unsigned int version; + unsigned int version_vp; + + bool firewalled:1,stable:1,tracker:1,recv:1,yp:1,dead:1,direct:1,relay:1,cin:1; + bool relayfull:1,chfull:1,ratefull:1; + + ChanHit *next; + + int status; + int servent_id; + + unsigned int oldestPos,newestPos; + Host uphost; + unsigned int uphostHops; + + char version_ex_prefix[2]; + unsigned int version_ex_number; +}; +// ---------------------------------- +class ChanHitList +{ +public: + ChanHitList(); + ~ChanHitList(); + + int contactTrackers(bool,int,int,int); + + ChanHit *addHit(ChanHit &); + void delHit(ChanHit &); + void deadHit(ChanHit &); + void clearHits(bool); + int numHits(); + int numListeners(); + int numRelays(); + int numFirewalled(); + int numTrackers(); + int closestHit(); + int furthestHit(); + unsigned int newestHit(); + + int pickHits(ChanHitSearch &); + int pickSourceHits(ChanHitSearch &); + + bool isUsed() {return used;} + int clearDeadHits(unsigned int,bool); + XML::Node *createXML(bool addHits = true); + + ChanHit *deleteHit(ChanHit *); + + int getTotalListeners(); + int getTotalRelays(); + int getTotalFirewalled(); + + bool used; + ChanInfo info; + ChanHit *hit; + unsigned int lastHitTime; + ChanHitList *next; + + +}; +// ---------------------------------- +class ChanHitSearch +{ +public: + enum + { + MAX_RESULTS = 8 + }; + + ChanHitSearch() { init(); } + void init(); + + ChanHit best[MAX_RESULTS]; + Host matchHost; + unsigned int waitDelay; + bool useFirewalled; + bool trackersOnly; + bool useBusyRelays,useBusyControls; + GnuID excludeID; + int numResults; + unsigned int seed; + + int getRelayHost(Host host1, Host host2, GnuID exID, ChanHitList *chl); +}; + +// ---------------------------------- +class ChanMeta +{ +public: + enum { + MAX_DATALEN = 65536 + }; + + void init() + { + len = 0; + cnt = 0; + startPos = 0; + } + + void fromXML(XML &); + void fromMem(void *,int); + void addMem(void *,int); + + unsigned int len,cnt,startPos; + char data[MAX_DATALEN]; +}; + + + +// ------------------------------------------ +class RawStream : public ChannelStream +{ +public: + virtual void readHeader(Stream &,Channel *); + virtual int readPacket(Stream &,Channel *); + virtual void readEnd(Stream &,Channel *); + +}; + +// ------------------------------------------ +class PeercastStream : public ChannelStream +{ +public: + virtual void readHeader(Stream &,Channel *); + virtual int readPacket(Stream &,Channel *); + virtual void readEnd(Stream &,Channel *); +}; + +// ------------------------------------------ +class ChannelSource +{ +public: + virtual ~ChannelSource() {} + virtual void stream(Channel *) = 0; + + virtual int getSourceRate() {return 0;} + +}; +// ------------------------------------------ +class PeercastSource : public ChannelSource +{ +public: + + + virtual void stream(Channel *); + +}; + + +// ---------------------------------- +class Channel +{ +public: + + enum STATUS + { + S_NONE, + S_WAIT, + S_CONNECTING, + S_REQUESTING, + S_CLOSING, + S_RECEIVING, + S_BROADCASTING, + S_ABORT, + S_SEARCHING, + S_NOHOSTS, + S_IDLE, + S_ERROR, + S_NOTFOUND + }; + + enum TYPE + { + T_NONE, + T_ALLOCATED, + T_BROADCAST, + T_RELAY + }; + + enum SRC_TYPE + { + SRC_NONE, + SRC_PEERCAST, + SRC_SHOUTCAST, + SRC_ICECAST, + SRC_URL + }; + + + Channel(); + void reset(); + void endThread(bool flg); + + void startMP3File(char *); + void startGet(); + void startICY(ClientSocket *,SRC_TYPE); + void startURL(const char *); + + + ChannelStream *createSource(); + + void resetPlayTime(); + + bool notFound() + { + return (status == S_NOTFOUND); + } + + bool isPlaying() + { + return (status == S_RECEIVING) || (status == S_BROADCASTING); + } + + bool isReceiving() + { + return (status == S_RECEIVING); + } + + bool isBroadcasting() + { + return (status == S_BROADCASTING); + } + + bool isFull(); + + bool checkBump(); + + bool checkIdle(); + void sleepUntil(double); + + bool isActive() + { + return type != T_NONE; + } + + + void connectFetch(); + int handshakeFetch(); + + bool isIdle() {return isActive() && (status==S_IDLE);} + + static THREAD_PROC stream(ThreadInfo *); + + static THREAD_PROC waitFinish(ThreadInfo *); + + void setStatus(STATUS s); + const char *getSrcTypeStr() {return srcTypes[srcType];} + const char *getStatusStr() {return statusMsgs[status];} + const char *getName() {return info.name.cstr();} + GnuID getID() {return info.id;} + int getBitrate() {return info.bitrate; } + void getIDStr(char *s) {info.id.toStr(s);} + void getStreamPath(char *); + + void broadcastTrackerUpdate(GnuID &,bool = false); + bool sendPacketUp(ChanPacket &,GnuID &,GnuID &,GnuID &); + + bool writeVariable(Stream &, const String &,int); + + bool acceptGIV(ClientSocket *); + + void updateInfo(ChanInfo &); + + int readStream(Stream &,ChannelStream *); + + void checkReadDelay(unsigned int); + + void processMp3Metadata(char *); + + void readHeader(); + + void startStream(); + + XML::Node *createRelayXML(bool); + + void newPacket(ChanPacket &); + + int localListeners(); + int localRelays(); + + int totalListeners(); + int totalRelays(); + + ::String mount; + ChanMeta insertMeta; + ChanPacket headPack; + + ChanPacketBuffer rawData; + + ChannelStream *sourceStream; + unsigned int streamIndex; + + + ChanInfo info; + ChanHit sourceHost; + + GnuID remoteID; + + + ::String sourceURL; + + bool bump,stayConnected; + int icyMetaInterval; + unsigned int streamPos; + unsigned int skipCount; //JP-EX + bool readDelay; + + TYPE type; + ChannelSource *sourceData; + + SRC_TYPE srcType; + + MP3Header mp3Head; + ThreadInfo thread; + ThreadInfo *finthread; + + unsigned int lastIdleTime; + int status; + static char *statusMsgs[],*srcTypes[]; + + ClientSocket *sock; + ClientSocket *pushSock; + + unsigned int lastTrackerUpdate; + unsigned int lastMetaUpdate; + + double startTime,syncTime; + + WEvent syncEvent; + + Channel *next; + + int channel_id; + ChanHit chDisp; + ChanHit trackerHit; + bool bumped; + unsigned int lastSkipTime; + unsigned int lastStopTime; +}; + +// ---------------------------------- +class ChanMgr +{ +public: + enum { + MAX_IDLE_CHANNELS = 8, // max. number of channels that can be left idle + MAX_METAINT = 8192 // must be at least smaller than ChanPacket data len (ie. about half) + + }; + + + ChanMgr(); + + Channel *deleteChannel(Channel *); + + Channel *createChannel(ChanInfo &,const char *); + Channel *findChannelByName(const char *); + Channel *findChannelByIndex(int); + Channel *findChannelByMount(const char *); + Channel *findChannelByID(GnuID &); + Channel *findChannelByNameID(ChanInfo &); + Channel *findPushChannel(int); + Channel *findChannelByChannelID(int id); + + void broadcastTrackerSettings(); + void setUpdateInterval(unsigned int v); + void broadcastRelays(Servent *,int,int); + + int broadcastPacketUp(ChanPacket &,GnuID &,GnuID &,GnuID &); + void broadcastTrackerUpdate(GnuID &,bool = false); + + bool writeVariable(Stream &, const String &,int); + + int findChannels(ChanInfo &,Channel **,int); + int findChannelsByStatus(Channel **,int,Channel::STATUS); + + int numIdleChannels(); + int numChannels(); + + void closeOldestIdle(); + void closeAll(); + void quit(); + + void addHit(Host &,GnuID &,bool); + ChanHit *addHit(ChanHit &); + void delHit(ChanHit &); + void deadHit(ChanHit &); + void setFirewalled(Host &); + + ChanHitList *findHitList(ChanInfo &); + ChanHitList *findHitListByID(GnuID &); + ChanHitList *addHitList(ChanInfo &); + + void clearHitLists(); + void clearDeadHits(bool); + int numHitLists(); + + void setBroadcastMsg(::String &); + + Channel *createRelay(ChanInfo &,bool); + Channel *findAndRelay(ChanInfo &); + void startSearch(ChanInfo &); + + void playChannel(ChanInfo &); + void findAndPlayChannel(ChanInfo &,bool); + + bool isBroadcasting(GnuID &); + bool isBroadcasting(); + + int pickHits(ChanHitSearch &); + + + + Channel *channel; + ChanHitList *hitlist; + + GnuID broadcastID; + + ChanInfo searchInfo; + + int numFinds; + ::String broadcastMsg; + unsigned int broadcastMsgInterval; + unsigned int lastHit,lastQuery; + unsigned int maxUptime; + bool searchActive; + unsigned int deadHitAge; + int icyMetaInterval; + int maxRelaysPerChannel; + WLock lock; + int minBroadcastTTL,maxBroadcastTTL; + int pushTimeout,pushTries,maxPushHops; + unsigned int autoQuery; + unsigned int prefetchTime; + unsigned int lastYPConnect; + unsigned int lastYPConnect2; + unsigned int icyIndex; + + unsigned int hostUpdateInterval; + unsigned int bufferTime; + + GnuID currFindAndPlayChannel; + + WLock channellock; + WLock hitlistlock; +}; +// ---------------------------------- +class PlayList +{ +public: + + enum TYPE + { + T_NONE, + T_SCPLS, + T_PLS, + T_ASX, + T_RAM, + }; + + PlayList(TYPE t, int max) + { + maxURLs = max; + numURLs = 0; + type = t; + urls = new ::String[max]; + titles = new ::String[max]; + } + + ~PlayList() + { + delete [] urls; + delete [] titles; + } + + void addURL(const char *url, const char *tit) + { + if (numURLs < maxURLs) + { + urls[numURLs].set(url); + titles[numURLs].set(tit); + numURLs++; + } + } + void addChannels(const char *,Channel **,int); + void addChannel(const char *,ChanInfo &); + + void writeSCPLS(Stream &); + void writePLS(Stream &); + void writeASX(Stream &); + void writeRAM(Stream &); + + void readSCPLS(Stream &); + void readPLS(Stream &); + void readASX(Stream &); + + void read(Stream &s) + { + try + { + switch (type) + { + case T_SCPLS: readSCPLS(s); break; + case T_PLS: readPLS(s); break; + case T_ASX: readASX(s); break; + } + }catch(StreamException &) {} // keep pls regardless of errors (eof isn`t handled properly in sockets) + } + + void write(Stream &s) + { + switch (type) + { + case T_SCPLS: writeSCPLS(s); break; + case T_PLS: writePLS(s); break; + case T_ASX: writeASX(s); break; + case T_RAM: writeRAM(s); break; + } + } + + TYPE type; + int numURLs,maxURLs; + ::String *urls,*titles; +}; + +// ---------------------------------- + +extern ChanMgr *chanMgr; + +// for PCRaw start. +bool isIndexTxt(ChanInfo *info); +bool isIndexTxt(Channel *ch); +int numMaxRelaysIndexTxt(Channel *ch); +int canStreamIndexTxt(Channel *ch); +// for PCRaw end + +#endif diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/common.h b/c:/Git/PeerCast.root/PeerCast/core/common/common.h new file mode 100644 index 0000000..99a1c9b --- /dev/null +++ b/c:/Git/PeerCast.root/PeerCast/core/common/common.h @@ -0,0 +1,293 @@ +// ------------------------------------------------ +// File : common.h +// Date: 4-apr-2002 +// Author: giles +// +// (c) 2002 peercast.org +// ------------------------------------------------ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// ------------------------------------------------ + +#ifndef _COMMON_H +#define _COMMON_H + +#pragma warning (disable: 4996) + +#include +#include + +#ifndef NULL +#define NULL 0 +#endif + +// ---------------------------------- +class GeneralException +{ +public: + GeneralException(const char *m, int e = 0) + { + strcpy(msg,m); + err=e; + } + char msg[128]; + int err; +}; + +// ------------------------------------- +class StreamException : public GeneralException +{ +public: + StreamException(const char *m) : GeneralException(m) {} + StreamException(const char *m,int e) : GeneralException(m,e) {} +}; + +// ---------------------------------- +class SockException : public StreamException +{ +public: + SockException(const char *m="Socket") : StreamException(m) {} + SockException(const char *m, int e) : StreamException(m,e) {} +}; +// ---------------------------------- +class EOFException : public StreamException +{ +public: + EOFException(const char *m="EOF") : StreamException(m) {} + EOFException(const char *m, int e) : StreamException(m,e) {} +}; + +// ---------------------------------- +class CryptException : public StreamException +{ +public: + CryptException(const char *m="Crypt") : StreamException(m) {} + CryptException(const char *m, int e) : StreamException(m,e) {} +}; + + +// ---------------------------------- +class TimeoutException : public StreamException +{ +public: + TimeoutException(const char *m="Timeout") : StreamException(m) {} +}; +// -------------------------------- +class GnuID +{ +public: + bool isSame(GnuID &gid) + { + for(int i=0; i<16; i++) + if (gid.id[i] != id[i]) + return false; + return true; + } + + + bool isSet() + { + for(int i=0; i<16; i++) + if (id[i] != 0) + return true; + return false; + } + + void clear() + { + for(int i=0; i<16; i++) + id[i] = 0; + storeTime = 0; + } + + + void generate(unsigned char = 0); + void encode(class Host *, const char *,const char *,unsigned char); + + void toStr(char *); + void fromStr(const char *); + + unsigned char getFlags(); + + unsigned char id[16]; + unsigned int storeTime; +}; +// -------------------------------- +class GnuIDList +{ +public: + GnuIDList(int); + ~GnuIDList(); + void clear(); + void add(GnuID &); + bool contains(GnuID &); + int numUsed(); + unsigned int getOldest(); + + GnuID *ids; + int maxID; +}; + + +// ---------------------------------- +class Host +{ + inline unsigned int ip3() + { + return (ip>>24); + } + inline unsigned int ip2() + { + return (ip>>16)&0xff; + } + inline unsigned int ip1() + { + return (ip>>8)&0xff; + } + inline unsigned int ip0() + { + return ip&0xff; + } + +public: + Host(){init();} + Host(unsigned int i, unsigned short p) + { + ip = i; + port = p; + value = 0; + } + + void init() + { + ip = 0; + port = 0; + value = 0; + } + + + bool isMemberOf(Host &); + + bool isSame(Host &h) + { + return (h.ip == ip) && (h.port == port); + } + + bool classType() {return globalIP();} + + bool globalIP() + { + // local host + if ((ip3() == 127) && (ip2() == 0) && (ip1() == 0) && (ip0() == 1)) + return false; + + // class A + if (ip3() == 10) + return false; + + // class B + if ((ip3() == 172) && (ip2() >= 16) && (ip2() <= 31)) + return false; + + // class C + if ((ip3() == 192) && (ip2() == 168)) + return false; + + return true; + } + bool localIP() + { + return !globalIP(); + } + + bool loopbackIP() + { +// return ((ipByte[3] == 127) && (ipByte[2] == 0) && (ipByte[1] == 0) && (ipByte[0] == 1)); + return ((ip3() == 127) && (ip2() == 0) && (ip1() == 0) && (ip0() == 1)); + } + + bool isValid() + { + return (ip != 0); + } + + + bool isSameType(Host &h) + { + return ( (globalIP() && h.globalIP()) || + (!globalIP() && !h.globalIP()) ); + } + + void IPtoStr(char *str) + { + sprintf(str,"%d.%d.%d.%d",(ip>>24)&0xff,(ip>>16)&0xff,(ip>>8)&0xff,(ip)&0xff); + } + + void toStr(char *str) + { + sprintf(str,"%d.%d.%d.%d:%d",(ip>>24)&0xff,(ip>>16)&0xff,(ip>>8)&0xff,(ip)&0xff,port); + } + + void fromStrIP(const char *,int); + void fromStrName(const char *,int); + + bool isLocalhost(); + + + union + { + unsigned int ip; +// unsigned char ipByte[4]; + }; + + unsigned short port; + unsigned int value; +}; +// ---------------------------------- +#define SWAP2(v) ( ((v&0xff)<<8) | ((v&0xff00)>>8) ) +#define SWAP3(v) (((v&0xff)<<16) | ((v&0xff00)) | ((v&0xff0000)>>16) ) +#define SWAP4(v) (((v&0xff)<<24) | ((v&0xff00)<<8) | ((v&0xff0000)>>8) | ((v&0xff000000)>>24)) +#define TOUPPER(c) ((((c) >= 'a') && ((c) <= 'z')) ? (c)+'A'-'a' : (c)) +#define TONIBBLE(c) ((((c) >= 'A')&&((c) <= 'F')) ? (((c)-'A')+10) : ((c)-'0')) +#define BYTES_TO_KBPS(n) (float)(((((float)n)*8.0f)/1024.0f)) + +// ---------------------------------- +inline bool isWhiteSpace(char c) +{ + return (c == ' ') || (c == '\r') || (c == '\n') || (c == '\t'); +} + +// ---------------------------------- +inline int strToID(char *str) +{ + union { + int i; + char s[8]; + }; + strncpy(s,str,4); + return i; +} + +// ----------------------------------- +char *getCGIarg(const char *str, const char *arg); +bool cmpCGIarg(char *str, char *arg, char *value); +bool hasCGIarg(char *str, char *arg); + +// ---------------------------------- +extern void LOG(const char *fmt,...); + +extern void LOG_ERROR(const char *fmt,...); +extern void LOG_DEBUG(const char *fmt,...); +extern void LOG_NETWORK(const char *fmt,...); +extern void LOG_CHANNEL(const char *fmt,...); + + +#endif + diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/cstream.h b/c:/Git/PeerCast.root/PeerCast/core/common/cstream.h new file mode 100644 index 0000000..f1a228b --- /dev/null +++ b/c:/Git/PeerCast.root/PeerCast/core/common/cstream.h @@ -0,0 +1,241 @@ +// ------------------------------------------------ +// File : cstream.h +// Date: 12-mar-2004 +// Author: giles +// +// (c) 2002-4 peercast.org +// ------------------------------------------------ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// ------------------------------------------------ + +#ifndef _CSTREAM_H +#define _CSTREAM_H + +// ---------------------------------- + +class Channel; +class ChanPacket; +class ChanPacketv; +class Stream; + + +// ---------------------------------- +class ChanPacket +{ +public: + enum + { + MAX_DATALEN = 16384 + }; + + enum TYPE + { + T_UNKNOWN = 0, + T_HEAD = 1, + T_DATA = 2, + T_META = 4, + T_PCP = 16, + T_ALL = 0xff + }; + + ChanPacket() + { + init(); + } + + void init() + { + type = T_UNKNOWN; + len = 0; + pos = 0; + sync = 0; + skip = false; + } + void init(ChanPacketv &p); + void init(TYPE t, const void *, unsigned int , unsigned int ); + + void writeRaw(Stream &); + void writePeercast(Stream &); + void readPeercast(Stream &); + + + unsigned int sync; + unsigned int pos; + TYPE type; + unsigned int len; + char data[MAX_DATALEN]; + bool skip; + +}; +// ---------------------------------- +class ChanPacketv +{ +public: + enum {BSIZE = 0x100}; + ChanPacketv() + { + init(); + } + ~ChanPacketv() + { + free(); + } + + void free() + { + if (data) { + delete [] data; + data = NULL; + datasize = 0; + } + } + void reset() + { + free(); + init(); + } + void init() + { + type = ChanPacket::T_UNKNOWN; + len = 0; + pos = 0; + sync = 0; + skip = false; + data = NULL; + datasize = 0; + } + void init(ChanPacket &p) + { + if (data && (datasize < p.len || datasize > p.len + BSIZE * 4)) { + free(); + data = NULL; + datasize = 0; + } + type = p.type; + len = p.len; + pos = p.pos; + sync = p.sync; + skip = p.skip; + if (!data) { + datasize = (len & ~(BSIZE - 1)) + BSIZE; + data = new char[datasize]; + } + memcpy(data, p.data, len); + } + void init(ChanPacketv &p) + { + ChanPacket tp; + tp.init(p); + init(tp); + } + + void writeRaw(Stream &); + void writePeercast(Stream &); + void readPeercast(Stream &); + + unsigned int sync; + unsigned int pos; + ChanPacket::TYPE type; + unsigned int len; + char *data; + unsigned int datasize; + bool skip; + +}; +// ---------------------------------- +class ChanPacketBuffer +{ +public: + enum { + MAX_PACKETS = 64, + NUM_SAFEPACKETS = 60 + }; + + void init() + { + lock.on(); + lastPos = firstPos = safePos = 0; + readPos = writePos = 0; + accept = 0; + lastWriteTime = 0; + for (int i = 0; i < MAX_PACKETS; i++) packets[i].reset(); + lock.off(); + + lastSkipTime = 0; + } + + int copyFrom(ChanPacketBuffer &,unsigned in); + + bool writePacket(ChanPacket &,bool = false); + void readPacket(ChanPacket &); + + bool willSkip(); + + int numPending() {return writePos-readPos;} + + unsigned int getLatestPos(); + unsigned int getOldestPos(); + unsigned int findOldestPos(unsigned int); + bool findPacket(unsigned int,ChanPacket &); + unsigned int getStreamPos(unsigned int); + unsigned int getStreamPosEnd(unsigned int); + unsigned int getLastSync(); + + //ChanPacket packets[MAX_PACKETS]; + ChanPacketv packets[MAX_PACKETS]; + volatile unsigned int lastPos,firstPos,safePos; + volatile unsigned int readPos,writePos; + unsigned int accept; + unsigned int lastWriteTime; + WLock lock; + + unsigned int lastSkipTime; +}; + +// ---------------------------------- +class ChannelStream +{ +public: + ChannelStream() + :numListeners(0) + ,numRelays(0) + ,isPlaying(false) + ,fwState(0) + ,lastUpdate(0) + ,lastCheckTime(0) + ,parent(NULL) + {} + virtual ~ChannelStream() {} + + void updateStatus(Channel *); + bool getStatus(Channel *,ChanPacket &); + + virtual void kill() {} + virtual bool sendPacket(ChanPacket &,GnuID &) {return false;} + virtual void flush(Stream &) {} + virtual void readHeader(Stream &,Channel *)=0; + virtual int readPacket(Stream &,Channel *)=0; + virtual void readEnd(Stream &,Channel *)=0; + + void readRaw(Stream &,Channel *); + + int numRelays; + int numListeners; + bool isPlaying; + int fwState; + unsigned int lastUpdate; + unsigned int lastCheckTime; + + Channel *parent; +}; + +#endif + diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/gnutella.cpp b/c:/Git/PeerCast.root/PeerCast/core/common/gnutella.cpp new file mode 100644 index 0000000..bff67fd --- /dev/null +++ b/c:/Git/PeerCast.root/PeerCast/core/common/gnutella.cpp @@ -0,0 +1,751 @@ +// ------------------------------------------------ +// File : gnutella.cpp +// Date: 4-apr-2002 +// Author: giles +// Desc: +// GnuPacket is a Gnutella protocol packet. +// GnuStream is a Stream that reads/writes GnuPackets +// +// +// (c) 2002 peercast.org +// +// ------------------------------------------------ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// ------------------------------------------------ + +#include "gnutella.h" +#include "stream.h" +#include "common.h" +#include "servent.h" +#include "servmgr.h" +#include "stats.h" +#include +#ifdef _DEBUG +#include "chkMemoryLeak.h" +#define DEBUG_NEW new(__FILE__, __LINE__) +#define new DEBUG_NEW +#endif + +// --------------------------- +const char *GNU_FUNC_STR(int func) +{ + switch (func) + { + case GNU_FUNC_PING: return "PING"; break; + case GNU_FUNC_PONG: return "PONG"; break; + case GNU_FUNC_QUERY: return "QUERY"; break; + case GNU_FUNC_HIT: return "HIT"; break; + case GNU_FUNC_PUSH: return "PUSH"; break; + default: return "UNKNOWN"; break; + } +} + +// --------------------------- +const char *GnuStream::getRouteStr(R_TYPE r) +{ + switch(r) + { + case R_PROCESS: return "PROCESS"; break; + case R_DEAD: return "DEAD"; break; + case R_DISCARD: return "DISCARD"; break; + case R_ACCEPTED: return "ACCEPTED"; break; + case R_BROADCAST: return "BROADCAST"; break; + case R_ROUTE: return "ROUTE"; break; + case R_DUPLICATE: return "DUPLICATE"; break; + case R_BADVERSION: return "BADVERSION"; break; + case R_DROP: return "DROP"; break; + default: return "UNKNOWN"; break; + } +} +// --------------------------- +void GnuPacket::makeChecksumID() +{ + for(unsigned int i=0; inumChannels()); // cnt + pk.writeLong(servMgr->totalOutput(false)); // total + }else{ + pk.writeLong(0); // cnt + pk.writeLong(0); // total + } + + +} +// --------------------------- +void GnuPacket::initPush(ChanHit &ch, Host &sh) +{ +#if 0 + func = GNU_FUNC_PUSH; + ttl = ch.numHops; + hops = 0; + len = 26; + id.generate(); + + MemoryStream data(data,len); + + // ID of Hit packet + data.write(ch.packetID.id,16); + + // index of channel + data.writeLong(ch.index); + + data.writeLong(SWAP4(sh.ip)); // ip + data.writeShort(sh.port); // port +#endif +} + + +// --------------------------- +bool GnuPacket::initHit(Host &h, Channel *ch, GnuPacket *query, bool push, bool busy, bool stable, bool tracker, int maxttl) +{ + if (!ch) + return false; + + func = GNU_FUNC_HIT; + hops = 0; + id.generate(); + + ttl = maxttl; + + + MemoryStream mem(data,MAX_DATA); + + mem.writeChar(1); // num hits + mem.writeShort(h.port); // port + mem.writeLong(SWAP4(h.ip)); // ip + + if (query) + mem.writeLong(0); // speed - route + else + mem.writeLong(1); // broadcast + + + //mem.writeLong(ch->index); // index + mem.writeLong(0); // index + mem.writeShort(ch->getBitrate()); // bitrate + mem.writeShort(ch->localListeners()); // num listeners + + mem.writeChar(0); // no name + + XML xml; + XML::Node *cn = ch->info.createChannelXML(); + cn->add(ch->info.createTrackXML()); + xml.setRoot(cn); + xml.writeCompact(mem); + + mem.writeChar(0); // extra null + + + // QHD + mem.writeLong('PCST'); // vendor ID + mem.writeChar(2); // public sector length + + int f1 = 0, f2 = 0; + + f1 = 1 | 4 | 8 | 32 | 64; // use push | busy | stable | broadcast | tracker + + if (push) f2 |= 1; + if (busy) f2 |= 4; + if (stable) f2 |= 8; + if (!query) f2 |= 32; + if (tracker) f2 |= 64; + + mem.writeChar(f1); + mem.writeChar(f2); + + { + // write private sector + char pbuf[256]; + MemoryStream pmem(pbuf,sizeof(pbuf)); + XML xml; + XML::Node *pn = servMgr->createServentXML(); + xml.setRoot(pn); + xml.writeCompact(pmem); + pmem.writeChar(0); // add null terminator + if (pmem.pos <= 255) + { + mem.writeChar(pmem.pos); + mem.write(pmem.buf,pmem.pos); + }else + mem.writeChar(0); + } + + + // queryID/not used + if (query) + mem.write(query->id.id,16); + else + mem.write(id.id,16); + + len = mem.pos; + + LOG_NETWORK("Created Hit packet: %d bytes",len); + + if (len >= MAX_DATA) + return false; + +// servMgr->addReplyID(id); + return true; +} + + +// --------------------------- +void GnuPacket::initFind(const char *str, XML *xml, int maxTTL) +{ + + func = GNU_FUNC_QUERY; + ttl = maxTTL; + hops = 0; + id.generate(); + + MemoryStream mem(data,MAX_DATA); + + mem.writeShort(0); // min speed + + if (str) + { + int slen = strlen(str); + mem.write((void *)str,slen+1); // string + }else + mem.writeChar(0); // null string + + + if (xml) + xml->writeCompact(mem); + + len = mem.pos; +} + +// --------------------------- +void GnuStream::ping(int ttl) +{ + GnuPacket ping; + ping.initPing(ttl); +// servMgr->addReplyID(ping.id); + sendPacket(ping); + LOG_NETWORK("ping out %02x%02x%02x%02x",ping.id.id[0],ping.id.id[1],ping.id.id[2],ping.id.id[3]); +} + +// --------------------------- +void GnuStream::sendPacket(GnuPacket &p) +{ + try + { + lock.on(); + packetsOut++; + stats.add(Stats::NUMPACKETSOUT); + + switch(p.func) + { + case GNU_FUNC_PING: stats.add(Stats::NUMPINGOUT); break; + case GNU_FUNC_PONG: stats.add(Stats::NUMPONGOUT); break; + case GNU_FUNC_QUERY: stats.add(Stats::NUMQUERYOUT); break; + case GNU_FUNC_HIT: stats.add(Stats::NUMHITOUT); break; + case GNU_FUNC_PUSH: stats.add(Stats::NUMPUSHOUT); break; + default: stats.add(Stats::NUMOTHEROUT); break; + } + + + write(p.id.id,16); + writeChar(p.func); // ping func + writeChar(p.ttl); // ttl + writeChar(p.hops); // hops + writeLong(p.len); // len + + if (p.len) + write(p.data,p.len); + + stats.add(Stats::PACKETDATAOUT,23+p.len); + + lock.off(); + }catch(StreamException &e) + { + lock.off(); + throw e; + } +} +// --------------------------- +bool GnuStream::readPacket(GnuPacket &p) +{ + try + { + lock.on(); + packetsIn++; + stats.add(Stats::NUMPACKETSIN); + + read(p.id.id,16); + p.func = readChar(); + p.ttl = readChar(); + p.hops = readChar(); + p.len = readLong(); + + + if ((p.hops >= 1) && (p.hops <= 10)) + stats.add((Stats::STAT)((int)Stats::NUMHOPS1+p.hops-1)); + + stats.add(Stats::PACKETDATAIN,23+p.len); + + switch(p.func) + { + case GNU_FUNC_PING: stats.add(Stats::NUMPINGIN); break; + case GNU_FUNC_PONG: stats.add(Stats::NUMPONGIN); break; + case GNU_FUNC_QUERY: stats.add(Stats::NUMQUERYIN); break; + case GNU_FUNC_HIT: stats.add(Stats::NUMHITIN); break; + case GNU_FUNC_PUSH: stats.add(Stats::NUMPUSHIN); break; + default: stats.add(Stats::NUMOTHERIN); break; + } + + + if (p.len) + { + if (p.len > GnuPacket::MAX_DATA) + { + while (p.len--) + readChar(); + lock.off(); + return false; + } + read(p.data,p.len); + } + + lock.off(); + return true; + }catch(StreamException &e) + { + lock.off(); + throw e; + } +} + +// --------------------------- +GnuStream::R_TYPE GnuStream::processPacket(GnuPacket &in, Servent *serv, GnuID &routeID) +{ + + R_TYPE ret = R_DISCARD; + + MemoryStream data(in.data,in.len); + + Host remoteHost = serv->getHost(); + + in.ttl--; + in.hops++; + + routeID = in.id; + + + + switch(in.func) + { + case GNU_FUNC_PING: // ping + { + LOG_NETWORK("ping: from %d.%d.%d.%d : %02x%02x%02x%02x", + remoteHost.ip>>24&0xff,remoteHost.ip>>16&0xff,remoteHost.ip>>8&0xff,remoteHost.ip&0xff, + in.id.id[0],in.id.id[1],in.id.id[2],in.id.id[3] + ); + Host sh = servMgr->serverHost; + if (sh.isValid()) + { + if ((servMgr->getFirewall() != ServMgr::FW_ON) && (!servMgr->pubInFull())) + { + GnuPacket pong; + pong.initPong(sh,true,in); + if (serv->outputPacket(pong,true)) + LOG_NETWORK("pong out"); + } + ret = R_BROADCAST; + } + } + break; + case GNU_FUNC_PONG: // pong + { + { + int ip,port,cnt,total; + port = data.readShort(); + ip = data.readLong(); + cnt = data.readLong(); + total = data.readLong(); + + ip = SWAP4(ip); + + + Host h; + h.ip = ip; + h.port = port; + + char sIP[64],rIP[64]; + h.toStr(sIP); + remoteHost.toStr(rIP); + + LOG_NETWORK("pong: %s via %s : %02x%02x%02x%02x",sIP,ip,rIP,in.id.id[0],in.id.id[1],in.id.id[2],in.id.id[3]); + + + ret = R_DISCARD; + + if (h.isValid()) + { + + #if 0 + // accept if this pong is a reply from one of our own pings, otherwise route back + if (servMgr->isReplyID(in.id)) + { + servMgr->addHost(h,ServHost::T_SERVENT,sys->getTime()); + ret = R_ACCEPTED; + }else + ret = R_ROUTE; + #endif + } + + } + } + break; + case GNU_FUNC_QUERY: // query + ret = R_BROADCAST; + + { + Host sh = servMgr->serverHost; + if (!sh.isValid()) + sh.ip = 127<<24|1; + + char words[256]; + short spd = data.readShort(); + data.readString(words,sizeof(words)); + words[sizeof(words)-1] = 0; + + MemoryStream xm(&data.buf[data.pos],data.len-data.pos); + xm.buf[xm.len] = 0; + + Channel *hits[16]; + int numHits=0; + + if (strncmp(xm.buf,"findChannels(info,hits,16); + } + LOG_NETWORK("query XML: %s : found %d",xm.buf,numHits); + }else{ + ChanInfo info; + info.name.set(words); + info.genre.set(words); + info.id.fromStr(words); + info.status = ChanInfo::S_PLAY; + numHits = chanMgr->findChannels(info,hits,16); + LOG_NETWORK("query STR: %s : found %d",words,numHits); + } + + + + for(int i=0; igetFirewall()!=ServMgr::FW_OFF); + bool busy = (servMgr->pubInFull() && servMgr->outFull()) || servMgr->relaysFull(); + bool stable = servMgr->totalStreams>0; + bool tracker = hits[i]->isBroadcasting(); + + GnuPacket hit; + if (hit.initHit(sh,hits[i],&in,push,busy,stable,tracker,in.hops)) + serv->outputPacket(hit,true); + } + } + break; + case GNU_FUNC_PUSH: // push + { + + GnuID pid; + data.read(pid.id,16); + + //LOG("push serv= %02x%02x%02x%02x",servMgr->id[0],servMgr->id[1],servMgr->id[2],servMgr->id[3]); + //LOG("pack = %02x%02x%02x%02x",id[0],id[1],id[2],id[3]); + + + int index = data.readLong(); + int ip = data.readLong(); + int port = data.readShort(); + + + ip = SWAP4(ip); + + Host h(ip,port); + char hostName[64]; + h.toStr(hostName); + +#if 0 + if (servMgr->isReplyID(pid)) + { +#if 0 + Channel *c = chanMgr->findChannelByIndex(index); + + if (!c) + { + LOG_NETWORK("push 0x%x to %s: Not found",index,hostName); + }else + { + if (!c->isFull() && !servMgr->streamFull()) + { + LOG_NETWORK("push: 0x%x to %s: OK",index,hostName); + + Servent *s = servMgr->allocServent(); + if (s) + s->initGIV(h,c->info.id); + }else + LOG_NETWORK("push: 0x%x to %s: FULL",index,hostName); + } +#endif + ret = R_ACCEPTED; + }else{ + LOG_NETWORK("push: 0x%x to %s: ROUTE",index,hostName); + routeID = pid; + ret = R_ROUTE; + } +#endif + } + break; + case GNU_FUNC_HIT: // hit + { + ret = R_DISCARD; + + ChanHit hit; + if (readHit(data,hit,in.hops,in.id)) + { + + char flstr[64]; + flstr[0]=0; + if (hit.firewalled) strcat(flstr,"Push,"); + if (hit.tracker) strcat(flstr,"Tracker,"); + +#if 0 + if ((spd == 0) && (!isBroadcastHit)) + { + if (servMgr->isReplyID(queryID)) + { + ret = R_ACCEPTED; + LOG_NETWORK("self-hit: %s 0x%02x %s %d chan",hostName,f2,flstr,num); + }else + { + routeID = queryID; + ret = R_ROUTE; + LOG_NETWORK("route-hit: %s 0x%02x %s %d chan",hostName,f2,flstr,num); + } + }else + { + ret = R_BROADCAST; + LOG_NETWORK("broadcast-hit: %s 0x%02x %s %d chan",hostName,f2,flstr,num); + } +#else + ret = R_BROADCAST; + LOG_NETWORK("broadcast-hit: %s",flstr); +#endif + } + } + break; + default: + LOG_NETWORK("packet: %d",in.func); + break; + } + + + if ((in.ttl > 10) || (in.hops > 10) || (in.ttl==0)) + if ((ret == R_BROADCAST) || (ret == R_ROUTE)) + ret = R_DEAD; + + return ret; +} + +// --------------------------- +bool GnuStream::readHit(Stream &data, ChanHit &ch,int hops,GnuID &id) +{ + int i; + int num = data.readChar(); // hits + int port = data.readShort(); // port + int ip = data.readLong(); // ip + ip = SWAP4(ip); + int spd = data.readLong(); // speed/broadcast + + Host h(ip,port); + char hostName[64]; + + h.IPtoStr(hostName); + + bool dataValid=true; + + ChanHit *hits[100]; + int numHits=0; + + for(i=0; ifindAttrInt("uptime"); + + }else + LOG_NETWORK("Missing Channel node"); + }else + { + LOG_NETWORK("Missing XML data"); + //LOG_NETWORK("%s",xmlData); + dataValid = false; + } + } + + if (info.id.isSet()) + { + if (!chanMgr->findHitList(info)) + chanMgr->addHitList(info); + + ch.recv = true; + ch.chanID = info.id; + ChanHit *chp = chanMgr->addHit(ch); + + if ((chp) && (numHits<100)) + hits[numHits++] = chp; + } + + } + + + int vendor = data.readLong(); // vendor ID + + int pubLen = data.readChar(); // public sec length - should be 2 + + int f1 = data.readChar() & 0xff; // flags 1 + int f2 = data.readChar() & 0xff; // flags 2 + + pubLen -= 2; + while (pubLen-->0) + data.readChar(); + + + char agentStr[16]; + agentStr[0]=0; + int maxPreviewTime=0; + + // read private sector with peercast servant specific info + int privLen = data.readChar(); + + if (privLen) + { + char privData[256]; + data.read(privData,privLen); + if (strncmp(privData,"findAttr("agent"); + if (ag) + { + strncpy(agentStr,ag,16); + agentStr[15]=0; + } + maxPreviewTime = sn->findAttrInt("preview"); + } + + } + } + + + // not used anymore + GnuID queryID; + data.read(queryID.id,16); + + bool isBroadcastHit=false; + if (f1 & 32) + isBroadcastHit = (f2 & 32)!=0; + + for(i=0; ifirewalled = (f2 & 1)!=0; + + if (f1 & 64) + hits[i]->tracker = (f2 & 64)!=0; + + } + + return dataValid; +} + diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/gnutella.h b/c:/Git/PeerCast.root/PeerCast/core/common/gnutella.h new file mode 100644 index 0000000..d31c580 --- /dev/null +++ b/c:/Git/PeerCast.root/PeerCast/core/common/gnutella.h @@ -0,0 +1,295 @@ +// ------------------------------------------------ +// File : gnutella.h +// Date: 4-apr-2002 +// Author: giles +// Desc: +// +// (c) 2002 peercast.org +// ------------------------------------------------ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// ------------------------------------------------ + +#ifndef _GNUTELLA_H +#define _GNUTELLA_H + +// -------------------------------- +#include "stream.h" +#include "sys.h" + + + +#define GNUTELLA_SETUP 0 + + +// -------------------------------- +static const int GNU_FUNC_PING = 0; +static const int GNU_FUNC_PONG = 1; +static const int GNU_FUNC_QUERY = 128; +static const int GNU_FUNC_HIT = 129; +static const int GNU_FUNC_PUSH = 64; + +extern const char *GNU_FUNC_STR(int); + +// -------------------------------- +static const char *GNU_PEERCONN = "PEERCAST CONNECT/0.1"; +static const char *GNU_CONNECT = "GNUTELLA CONNECT/0.6"; +static const char *GNU_OK = "GNUTELLA/0.6 200 OK"; +static const char *PCX_PCP_CONNECT = "pcp"; + +static const char *PCX_HS_OS = "x-peercast-os:"; +static const char *PCX_HS_DL = "x-peercast-download:"; +static const char *PCX_HS_ID = "x-peercast-id:"; +static const char *PCX_HS_CHANNELID = "x-peercast-channelid:"; +static const char *PCX_HS_NETWORKID = "x-peercast-networkid:"; +static const char *PCX_HS_MSG = "x-peercast-msg:"; +static const char *PCX_HS_SUBNET = "x-peercast-subnet:"; +static const char *PCX_HS_FULLHIT = "x-peercast-fullhit:"; +static const char *PCX_HS_MINBCTTL = "x-peercast-minbcttl:"; +static const char *PCX_HS_MAXBCTTL = "x-peercast-maxbcttl:"; +static const char *PCX_HS_RELAYBC = "x-peercast-relaybc:"; +static const char *PCX_HS_PRIORITY = "x-peercast-priority:"; +static const char *PCX_HS_FLOWCTL = "x-peercast-flowctl:"; +static const char *PCX_HS_PCP = "x-peercast-pcp:"; +static const char *PCX_HS_PINGME = "x-peercast-pingme:"; +static const char *PCX_HS_PORT = "x-peercast-port:"; +static const char *PCX_HS_REMOTEIP = "x-peercast-remoteip:"; +static const char *PCX_HS_POS = "x-peercast-pos:"; +static const char *PCX_HS_SESSIONID = "x-peercast-sessionid:"; + +// official version number sent to relay to check for updates +static const char *PCX_OS_WIN32 = "Win32"; +static const char *PCX_OS_LINUX = "Linux"; +static const char *PCX_OS_MACOSX = "Apple-OSX"; +static const char *PCX_OS_WINAMP2 = "Win32-WinAmp2"; +static const char *PCX_OS_ACTIVEX = "Win32-ActiveX"; + +static const char *PCX_DL_URL = "http://www.peercast.org/download.php"; + +// version number sent to other clients +static const char *PCX_OLDAGENT = "PeerCast/0.119E"; + + + + + +// version number used inside packets GUIDs +static const int PEERCAST_PACKETID = 0x0000119E; + +static const char *MIN_ROOTVER = "0.119E"; + +static const char *MIN_CONNECTVER = "0.119D"; +static const int MIN_PACKETVER = 0x0000119D; + +static const char *ICY_OK = "ICY 200 OK"; + +// -------------------------------- + +static const int DEFAULT_PORT = 7144; + +// -------------------------------- + +class Servent; +class Channel; +class ChanHit; + + +// -------------------------------- +class GnuPacket +{ +public: + + + // -------------------------------- + class Hash + { + public: + + bool isSame(Hash &h) + { + return (idChecksum == h.idChecksum) && (dataChecksum == h.dataChecksum); + } + + bool isSameID(Hash &h) + { + return (idChecksum == h.idChecksum); + } + + unsigned int idChecksum; + unsigned int dataChecksum; + + }; + // -------------------------------- + + enum { + MAX_DATA = 2000 + }; + + void initPing(int); + void initPong(Host &, bool, GnuPacket &); + void initFind(const char *, class XML *,int); + bool initHit(Host &, Channel *, GnuPacket *,bool,bool,bool,bool,int); + void initPush(ChanHit &, Host &); + + + void makeChecksumID(); + + unsigned char func; + unsigned char ttl; + unsigned char hops; + unsigned int len; + Hash hash; + GnuID id; + + char data[MAX_DATA]; +}; +// -------------------------------- +class GnuPacketBuffer +{ +public: + GnuPacketBuffer(int s) + :size(s) + ,packets(new GnuPacket[size]) + { + reset(); + } + ~GnuPacketBuffer() + { + delete [] packets; + } + + void reset() + { + readPtr = writePtr = 0; + } + + GnuPacket *curr() + { + if (numPending()) + return &packets[readPtr%size]; + else + return NULL; + + } + void next() + { + readPtr++; + } + + int findMinHop() + { + int min=100; + int n = numPending(); + for(int i=0; i max) + max = packets[idx].hops; + } + return max; + } + + int percentFull() + { + return (numPending()*100) / size; + } + + + int sizeOfPending() + { + int tot=0; + int n = numPending(); + for(int i=0; i= size) + return false; + else + { + packets[writePtr%size] = p; + writePtr++; + return true; + } + } + + int size; + GnuPacket *packets; + int readPtr,writePtr; +}; + + + +// -------------------------------- +class GnuStream : public IndirectStream +{ +public: + + enum R_TYPE + { + R_PROCESS, + R_DEAD, + R_DISCARD, + R_ACCEPTED, + R_BROADCAST, + R_ROUTE, + R_DUPLICATE, + R_BADVERSION, + R_DROP + }; + + GnuStream() + { + init(NULL); + } + + void init(Stream *s) + { + IndirectStream::init(s); + packetsIn = packetsOut = 0; + } + + bool readPacket(GnuPacket &); + void sendPacket(GnuPacket &); + R_TYPE processPacket(GnuPacket &, Servent *, GnuID &); + + static const char *getRouteStr(R_TYPE); + bool readHit(Stream &data, ChanHit &ch,int,GnuID &); + + + + void ping(int); + + int packetsIn,packetsOut; + WLock lock; +}; + + +#endif diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/html-xml.h b/c:/Git/PeerCast.root/PeerCast/core/common/html-xml.h new file mode 100644 index 0000000..ae1d93a --- /dev/null +++ b/c:/Git/PeerCast.root/PeerCast/core/common/html-xml.h @@ -0,0 +1,28 @@ +#ifndef _HTML_H +#define _HTML_H + +// --------------------------------------- +#include "xml.h" + +// --------------------------------------- +class HTML : public XML +{ +public: + HTML(const char *); + + + void startNode(XML::Node *, const char * = NULL); + void addLink(const char *, const char *); + void addArgLink(const char *, const char *); + XML::Node *startTag(const char *, const char * = NULL,...); + XML::Node *startTagEnd(const char *, const char * = NULL,...); + void startSingleTagEnd(const char *,...); + void startTableRow(int); + void end(); + void addRefresh(int); + + char defArgs[128]; + XML::Node *currNode,*headNode,*htmlNode; +}; + +#endif diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/html.cpp b/c:/Git/PeerCast.root/PeerCast/core/common/html.cpp new file mode 100644 index 0000000..ff659ac --- /dev/null +++ b/c:/Git/PeerCast.root/PeerCast/core/common/html.cpp @@ -0,0 +1,558 @@ +// ------------------------------------------------ +// File : html.cpp +// Date: 4-apr-2002 +// Author: giles +// Desc: +// HTML protocol handling +// +// (c) 2002 peercast.org +// ------------------------------------------------ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// ------------------------------------------------ + + +#include +#include +#include "html.h" +#include "http.h" +#include "stream.h" +#include "gnutella.h" +#include "servmgr.h" +#include "channel.h" +#include "stats.h" +#include "version2.h" +#ifdef _DEBUG +#include "chkMemoryLeak.h" +#define DEBUG_NEW new(__FILE__, __LINE__) +#define new DEBUG_NEW +#endif + + +// -------------------------------------- +HTML::HTML(const char *t, Stream &o) +{ + o.writeCRLF = false; + out = new WriteBufferStream(8192, &o); + out->writeCRLF = false; + + title.set(t); + tagLevel = 0; + refresh = 0; +} + +HTML::~HTML() +{ + try { + out->flush(); + } catch (StreamException &) {} + delete out; +} + +// -------------------------------------- +void HTML::writeOK(const char *content) +{ + out->writeLine(HTTP_SC_OK); + out->writeLineF("%s %s",HTTP_HS_SERVER,PCX_AGENT); + //out->writeLine("%s %s",HTTP_HS_CACHE,"no-cache"); + out->writeLineF("%s %s",HTTP_HS_CONNECTION,"close"); + out->writeLineF("%s %s",HTTP_HS_CONTENT,content); + out->writeLine(""); +} +// -------------------------------------- +void HTML::writeVariable(Stream &s,const String &varName, int loop) +{ + bool r=false; + if (varName.startsWith("servMgr.")) + r=servMgr->writeVariable(s,varName+8); + else if (varName.startsWith("chanMgr.")) + r=chanMgr->writeVariable(s,varName+8,loop); + else if (varName.startsWith("stats.")) + r=stats.writeVariable(s,varName+6); + else if (varName.startsWith("sys.")) + { + if (varName == "sys.log.dumpHTML") + { + sys->logBuf->dumpHTML(s); + r=true; + } + } + else if (varName.startsWith("loop.")) + { + if (varName.startsWith("loop.channel.")) + { + Channel *ch = chanMgr->findChannelByIndex(loop); + if (ch) + r = ch->writeVariable(s,varName+13,loop); + }else if (varName.startsWith("loop.servent.")) + { + Servent *sv = servMgr->findServentByIndex(loop); + if (sv) + r = sv->writeVariable(s,varName+13); + }else if (varName.startsWith("loop.filter.")) + { + ServFilter *sf = &servMgr->filters[loop]; + r = sf->writeVariable(s,varName+12); + + }else if (varName.startsWith("loop.bcid.")) + { + BCID *bcid = servMgr->findValidBCID(loop); + if (bcid) + r = bcid->writeVariable(s,varName+10); + + }else if (varName == "loop.indexEven") + { + s.writeStringF("%d",(loop&1)==0); + r = true; + }else if (varName == "loop.index") + { + s.writeStringF("%d",loop); + r = true; + }else if (varName.startsWith("loop.hit.")) + { + char *idstr = getCGIarg(tmplArgs,"id="); + if (idstr) + { + GnuID id; + id.fromStr(idstr); + ChanHitList *chl = chanMgr->findHitListByID(id); + if (chl) + { + int cnt=0; + ChanHit *ch = chl->hit; + while (ch) + { + if (ch->host.ip && !ch->dead) + { + if (cnt == loop) + { + r = ch->writeVariable(s,varName+9); + break; + } + cnt++; + } + ch=ch->next; + } + + } + } + } + + } + else if (varName.startsWith("page.")) + { + if (varName.startsWith("page.channel.")) + { + char *idstr = getCGIarg(tmplArgs,"id="); + if (idstr) + { + GnuID id; + id.fromStr(idstr); + Channel *ch = chanMgr->findChannelByID(id); + if (ch) + r = ch->writeVariable(s,varName+13,loop); + } + }else + { + + String v = varName+5; + v.append('='); + char *a = getCGIarg(tmplArgs,v); + if (a) + { + s.writeString(a); + r=true; + } + } + } + + + if (!r) + s.writeString(varName); +} +// -------------------------------------- +int HTML::getIntVariable(const String &varName,int loop) +{ + String val; + MemoryStream mem(val.cstr(),String::MAX_LEN); + + writeVariable(mem,varName,loop); + + return atoi(val.cstr()); +} +// -------------------------------------- +bool HTML::getBoolVariable(const String &varName,int loop) +{ + String val; + MemoryStream mem(val.cstr(),String::MAX_LEN); + + writeVariable(mem,varName,loop); + + // integer + if ((val[0] >= '0') && (val[0] <= '9')) + return atoi(val.cstr()) != 0; + + // string + if (val[0]!=0) + return true; + + return false; +} + +// -------------------------------------- +void HTML::readIf(Stream &in,Stream *outp,int loop) +{ + String var; + bool varCond=true; + + while (!in.eof()) + { + char c = in.readChar(); + + if (c == '}') + { + if (getBoolVariable(var,loop)==varCond) + { + if (readTemplate(in,outp,loop)) + readTemplate(in,NULL,loop); + }else{ + if (readTemplate(in,NULL,loop)) + readTemplate(in,outp,loop); + } + return; + }else if (c == '!') + { + varCond = !varCond; + }else + { + var.append(c); + } + } + +} + +// -------------------------------------- +void HTML::readLoop(Stream &in,Stream *outp,int loop) +{ + String var; + while (!in.eof()) + { + char c = in.readChar(); + + if (c == '}') + { + int cnt = getIntVariable(var,loop); + + if (cnt) + { + int spos = in.getPosition(); + for(int i=0; iwriteChar(c); + } + else + throw StreamException("Unknown template escape"); + }else + { + if (outp) + outp->writeChar(c); + } + } + return false; +} + +// -------------------------------------- +void HTML::writeTemplate(const char *fileName, const char *args) +{ + FileStream file; + MemoryStream mm; + try + { + file.openReadOnly(fileName); + mm.readFromFile(file); + + tmplArgs = args; + readTemplate(mm,out,0); + + }catch(StreamException &e) + { + out->writeString(e.msg); + out->writeString(" : "); + out->writeString(fileName); + } + + mm.free2(); + file.close(); +} +// -------------------------------------- +void HTML::writeRawFile(const char *fileName) +{ + FileStream file; + try + { + file.openReadOnly(fileName); + + file.writeTo(*out,file.length()); + + }catch(StreamException &) + { + } + + file.close(); +} + +// -------------------------------------- +void HTML::locateTo(const char *url) +{ + out->writeLine(HTTP_SC_FOUND); + out->writeLineF("Location: %s",url); + out->writeLine(""); +} +// -------------------------------------- +void HTML::startHTML() +{ + startNode("html"); +} +// -------------------------------------- +void HTML::startBody() +{ + startNode("body"); +} +// -------------------------------------- +void HTML::addHead() +{ + char buf[512]; + startNode("head"); + startTagEnd("title",title.cstr()); + startTagEnd("meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\""); + + if (!refreshURL.isEmpty()) + { + sprintf(buf,"meta http-equiv=\"refresh\" content=\"%d;URL=%s\"",refresh,refreshURL.cstr()); + startTagEnd(buf); + }else if (refresh) + { + sprintf(buf,"meta http-equiv=\"refresh\" content=\"%d\"",refresh); + startTagEnd(buf); + } + + + end(); +} +// -------------------------------------- +void HTML::addContent(const char *s) +{ + out->writeString(s); +} +// -------------------------------------- +void HTML::startNode(const char *tag, const char *data) +{ + const char *p = tag; + char *o = &currTag[tagLevel][0]; + + int i; + for(i=0; iwriteString("<"); + out->writeString(tag); + out->writeString(">"); + if (data) + out->writeString(data); + + tagLevel++; + if (tagLevel >= MAX_TAGLEVEL) + throw StreamException("HTML too deep!"); +} +// -------------------------------------- +void HTML::end() +{ + tagLevel--; + if (tagLevel < 0) + throw StreamException("HTML premature end!"); + + out->writeString("writeString(&currTag[tagLevel][0]); + out->writeString(">"); +} +// -------------------------------------- +void HTML::addLink(const char *url, const char *text, bool toblank) +{ + char buf[1024]; + + sprintf(buf,"a href=\"%s\" %s",url,toblank?"target=\"_blank\"":""); + startNode(buf,text); + end(); +} +// -------------------------------------- +void HTML::startTag(const char *tag, const char *fmt,...) +{ + if (fmt) + { + + va_list ap; + va_start(ap, fmt); + + char tmp[512]; + vsprintf(tmp,fmt,ap); + startNode(tag,tmp); + + va_end(ap); + }else{ + startNode(tag,NULL); + } +} +// -------------------------------------- +void HTML::startTagEnd(const char *tag, const char *fmt,...) +{ + if (fmt) + { + + va_list ap; + va_start(ap, fmt); + + char tmp[512]; + vsprintf(tmp,fmt,ap); + startNode(tag,tmp); + + va_end(ap); + }else{ + startNode(tag,NULL); + } + end(); +} +// -------------------------------------- +void HTML::startSingleTagEnd(const char *fmt,...) +{ + va_list ap; + va_start(ap, fmt); + + char tmp[512]; + vsprintf(tmp,fmt,ap); + startNode(tmp); + + va_end(ap); + end(); +} + +// -------------------------------------- +void HTML::startTableRow(int i) +{ + if (i & 1) + startTag("tr bgcolor=\"#dddddd\" align=\"left\""); + else + startTag("tr bgcolor=\"#eeeeee\" align=\"left\""); +} diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/html.h b/c:/Git/PeerCast.root/PeerCast/core/common/html.h new file mode 100644 index 0000000..7f05c43 --- /dev/null +++ b/c:/Git/PeerCast.root/PeerCast/core/common/html.h @@ -0,0 +1,91 @@ +// ------------------------------------------------ +// File : html.h +// Date: 4-apr-2002 +// Author: giles +// Desc: +// +// (c) 2002 peercast.org +// ------------------------------------------------ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// ------------------------------------------------ + +#ifndef _HTML_H +#define _HTML_H + +// --------------------------------------- +#include "xml.h" +#include "sys.h" + +class FileStream; +class WriteBufferStream; + +// --------------------------------------- +class HTML +{ +public: + enum + { + MAX_TAGLEVEL = 64, + MAX_TAGLEN = 64 + }; + + enum + { + TMPL_UNKNOWN, + TMPL_LOOP, + TMPL_IF, + TMPL_ELSE, + TMPL_END + }; + + HTML(const char *,Stream &); + ~HTML(); + + void startNode(const char *, const char * = NULL); + void addLink(const char *, const char *, bool = false); + void startTag(const char *, const char * = NULL,...); + void startTagEnd(const char *, const char * = NULL,...); + void startSingleTagEnd(const char *,...); + void startTableRow(int); + void end(); + void setRefresh(int sec) {refresh = sec;} + void setRefreshURL(const char *u){refreshURL.set(u);} + void addHead(); + void startHTML(); + void startBody(); + + void locateTo(const char *); + void addContent(const char *); + + void writeOK(const char *); + void writeTemplate(const char *, const char *); + void writeRawFile(const char *); + void writeVariable(Stream &,const String &,int); + int getIntVariable(const String &,int); + bool getBoolVariable(const String &,int); + + + void readIf(Stream &,Stream *,int); + void readLoop(Stream &,Stream *,int); + void readVariable(Stream &,Stream *,int); + bool readTemplate(Stream &,Stream *,int); + int readCmd(Stream &,Stream *,int); + + + const char *tmplArgs; + String title,refreshURL; + char currTag[MAX_TAGLEVEL][MAX_TAGLEN]; + int tagLevel; + int refresh; + WriteBufferStream *out; +}; + +#endif diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/http.cpp b/c:/Git/PeerCast.root/PeerCast/core/common/http.cpp new file mode 100644 index 0000000..95f4df4 --- /dev/null +++ b/c:/Git/PeerCast.root/PeerCast/core/common/http.cpp @@ -0,0 +1,192 @@ +// ------------------------------------------------ +// File : http.cpp +// Date: 4-apr-2002 +// Author: giles +// Desc: +// HTTP protocol handling +// +// (c) 2002 peercast.org +// ------------------------------------------------ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// ------------------------------------------------ + + +#include +#include "http.h" +#include "sys.h" +#include "common.h" +#ifdef _DEBUG +#include "chkMemoryLeak.h" +#define DEBUG_NEW new(__FILE__, __LINE__) +#define new DEBUG_NEW +#endif + +//----------------------------------------- +bool HTTP::checkResponse(int r) +{ + if (readResponse()!=r) + { + LOG_ERROR("Unexpected HTTP: %s",cmdLine); + throw StreamException("Unexpected HTTP response"); + return false; + } + + return true; +} +//----------------------------------------- +void HTTP::readRequest() +{ + readLine(cmdLine,sizeof(cmdLine)); +} +//----------------------------------------- +int HTTP::readResponse() +{ + readLine(cmdLine,sizeof(cmdLine)); + + char *cp = cmdLine; + + while (*cp) if (*++cp == ' ') break; + while (*cp) if (*++cp != ' ') break; + + char *scp = cp; + + while (*cp) if (*++cp == ' ') break; + *cp = 0; + + return atoi(scp); +} + +//----------------------------------------- +bool HTTP::nextHeader() +{ + if (readLine(cmdLine,sizeof(cmdLine))) + { + char *ap = strstr(cmdLine,":"); + if (ap) + while (*++ap) + if (*ap!=' ') + break; + arg = ap; + return true; + }else + { + arg = NULL; + return false; + } + +} +//----------------------------------------- +bool HTTP::isHeader(const char *hs) +{ + return stristr(cmdLine,hs) != NULL; +} +//----------------------------------------- +bool HTTP::isRequest(const char *rq) +{ + return strncmp(cmdLine,rq,strlen(rq)) == 0; +} +//----------------------------------------- +char *HTTP::getArgStr() +{ + return arg; +} +//----------------------------------------- +int HTTP::getArgInt() +{ + if (arg) + return atoi(arg); + else + return 0; +} +//----------------------------------------- +void HTTP::getAuthUserPass(char *user, char *pass) +{ + if (arg) + { + char *s = stristr(arg,"Basic"); + if (s) + { + while (*s) + if (*s++ == ' ') + break; + String str; + str.set(s,String::T_BASE64); + str.convertTo(String::T_ASCII); + s = strstr(str.cstr(),":"); + if (s) + { + *s = 0; + if (user) + strcpy(user,str.cstr()); + if (pass) + strcpy(pass,s+1); + } + } + } +} +// ----------------------------------- +void CookieList::init() +{ + for(int i=0; igetTime(); + list[oldestIndex]=c; + return true; +} +// ----------------------------------- +void CookieList::remove(Cookie &c) +{ + for(int i=0; isock) + throw StreamException("ICY channel has no socket"); + + ch->resetPlayTime(); + + ch->setStatus(Channel::S_BROADCASTING); + source = ch->createSource(); + ch->readStream(*ch->sock,source); + + }catch(StreamException &e) + { + LOG_ERROR("Channel aborted: %s",e.msg); + } + + + ch->setStatus(Channel::S_CLOSING); + + if (ch->sock) + { + ch->sock->close(); + delete ch->sock; + ch->sock = NULL; + } + + if (source) + delete source; + +} diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/icy.h b/c:/Git/PeerCast.root/PeerCast/core/common/icy.h new file mode 100644 index 0000000..aec507d --- /dev/null +++ b/c:/Git/PeerCast.root/PeerCast/core/common/icy.h @@ -0,0 +1,35 @@ +// ------------------------------------------------ +// File : icy.h +// Date: 20-feb-2004 +// Author: giles +// +// (c) 2002-4 peercast.org +// ------------------------------------------------ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// ------------------------------------------------ + +#ifndef _ICY_H +#define _ICY_H + +#include "channel.h" + +// ------------------------------------------------ +class ICYSource : public ChannelSource +{ +public: + virtual void stream(Channel *); + +}; + + + + +#endif diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/id.h b/c:/Git/PeerCast.root/PeerCast/core/common/id.h new file mode 100644 index 0000000..8052820 --- /dev/null +++ b/c:/Git/PeerCast.root/PeerCast/core/common/id.h @@ -0,0 +1,101 @@ +#ifndef _ID_H +#define _ID_H + +#include + +// --------------------------------------------------- +class IDString +{ +private: + enum + { + LENGTH = 31 + }; + + char data[LENGTH+1]; +public: + IDString(const char *id,int cnt) + { + if (cnt >= LENGTH) + cnt=LENGTH; + int i; + for(i=0; i + * 2001/10/14 First version + * Kazuhiko Iwama + * + */ + +#include +#include +#include +#include +#include "identify_encoding.h" + +enum encoding_id +{ + eid_KNOWN = 0, + eid_ASCII = 1, + eid_JIS = 2, + eid_SJIS = 3, + eid_EUCJP = 4, + eid_UTF8 = 5 +}; + +const char *encoding_str[] = +{ + "KNOWN", "ASCII", "ISO-2022-JP", "SJIS", "EUC-JP", "UTF-8" +}; + +static int +is_ascii(ie_state_t *st, const unsigned char *p) +{ + if (!(isprint(*p) || isspace(*p)) || *p >= 0x80) + st->flag = 0; + return st->flag; +} + +static int +is_jis(ie_state_t *st, const unsigned char *p) +{ + if (*p >= 0x80) + st->flag = 0; + return st->flag; +} + +static int +is_sjis(ie_state_t *st, const unsigned char *p) +{ + switch (st->state) + { + case 0: + st->c_type = 0; + if (*p >= 0x80) + { + st->state = 1; + if (*p >= 0x81 && *p <= 0x9f) st->c_type = 1; + else if (*p >= 0xe0 && *p <= 0xef) st->c_type = 1; + else if (*p >= 0xa1 && *p <= 0xdf) st->state = 0; + else st->flag = 1; + } + break; + case 1: + if (*p >= 0x40 && *p <= 0x7e) st->state = 0; + else if (*p >= 0x80 && *p <= 0xfc) st->state = 0; + else st->flag = 0; + break; + default: + st->flag = 0; + break; + } + + return st->flag; +} + +static int +is_eucjp(ie_state_t *st, const unsigned char *p) +{ + switch (st->state) + { + case 0: + st->c_type = 0; + if (*p >= 0x80) + { + st->state = 1; + if (*p >= 0xa1 && *p <= 0xfe) st->c_type = 1; + else if (*p == 0x8e ) st->c_type = 2; + else if (*p == 0x8f ) st->c_type = 3; + else st->flag = 0; + } + break; + case 1: + switch (st->c_type) + { + case 1: + if (*p >= 0xa1 && *p <= 0xfe) st->state = 0; + else st->flag = 0; + break; + case 2: + if (*p >= 0x81 && *p <= 0xff) st->state = 0; + else st->flag = 0; + break; + case 3: + if (*p >= 0x81 && *p <= 0xff) st->state = 2; + else st->flag = 0; + break; + default: + st->flag = 0; + break; + } + break; + case 2: + if (*p >= 0x81 && *p <= 0xff) st->state = 0; + else st->flag = 0; + default: + st->flag = 0; + break; + } + + return st->flag; +} + +static int +is_utf8(ie_state_t *st, const unsigned char *p) +{ + switch (st->state) + { + case 0: + st->c_type = 0; + if (*p >= 0x80) + { + st->state = 1; + if (*p >= 0xc2 && *p <= 0xdf) st->c_type = 1; + else if (*p == 0xe0 ) st->c_type = 2; + else if (*p >= 0xe1 && *p <= 0xef) st->c_type = 3; + else if (*p == 0xf0 ) st->c_type = 4; + else if (*p >= 0xf1 && *p <= 0xf3) st->c_type = 5; + else if (*p == 0xf4 ) st->c_type = 6; + else st->flag = 0; + } + break; + case 1: + switch (st->c_type) + { + case 1: + if (*p >= 0x80 && *p <= 0xbf) st->state = 0; + else st->flag = 0; + break; + case 2: + if (*p >= 0xa0 && *p <= 0xbf) st->state = 2; + else st->flag = 0; + break; + case 3: + if (*p >= 0x80 && *p <= 0xbf) st->state = 2; + else st->flag = 0; + break; + case 4: + if (*p >= 0x90 && *p <= 0xbf) st->state = 2; + else st->flag = 0; + break; + case 5: + if (*p >= 0x80 && *p <= 0xbf) st->state = 2; + else st->flag = 0; + break; + case 6: + if (*p >= 0x80 && *p <= 0x8f) st->state = 2; + else st->flag = 0; + break; + default: + st->flag = 0; + break; + } + break; + case 2: + if (st->c_type >= 2 && st->c_type <= 3) + { + if (*p >= 0x80 && *p <= 0xbf) st->state = 0; + else st->flag = 0; + }else if (st->c_type >= 4 && st->c_type <= 6) + { + if (*p >= 0x80 && *p <= 0xbf) st->state = 3; + else st->flag = 0; + }else{ + st->flag = 0; + } + break; + case 3: + if (st->c_type >= 4 && st->c_type <= 6) + { + if (*p >= 0x80 && *p <= 0xbf) st->state = 0; + else st->flag = 0; + }else{ + st->flag = 0; + } + break; + default: + st->flag = 0; + break; + } + + return st->flag; +} + +identify_encoding_t* +identify_encoding_open(enum identify_encoding_order order) +{ + identify_encoding_t* cd; + cd = (identify_encoding_t*)malloc(sizeof(identify_encoding_t)); + + if (cd == NULL) + { + cd = (identify_encoding_t*)(-1); + }else{ + cd->order = order; + identify_encoding_reset(cd); + } + return cd; +} + +void +identify_encoding_close(identify_encoding_t* cd) +{ + if (cd != (identify_encoding_t*)(-1) || cd != NULL) + { + free(cd); + } +} + +static void +identify_encoding_reset_state(ie_state_t* st) +{ + st->flag = 1; + st->state = 0; + st->c_type = 0; +} + +void +identify_encoding_reset(identify_encoding_t* cd) +{ + identify_encoding_reset_state(&(cd->st_ascii)); + identify_encoding_reset_state(&(cd->st_jis)); + identify_encoding_reset_state(&(cd->st_sjis)); + identify_encoding_reset_state(&(cd->st_eucjp)); + identify_encoding_reset_state(&(cd->st_utf8)); +} + +const char* +identify_encoding(identify_encoding_t *cd, char* instr) +{ + int n; + unsigned char *p; + enum encoding_id eid = eid_KNOWN; + + identify_encoding_reset(cd); + + for (n = 0, p = (unsigned char *)instr; *p != '\0' && n < IDENTIFY_MAX_LENGTH; p++, n++) + { + if (cd->st_ascii.flag == 1) is_ascii(&(cd->st_ascii), p); + if (cd->st_jis.flag == 1) is_jis(&(cd->st_jis), p); + if (cd->st_sjis.flag == 1) is_sjis(&(cd->st_sjis), p); + if (cd->st_eucjp.flag == 1) is_eucjp(&(cd->st_eucjp), p); + if (cd->st_utf8.flag == 1) is_utf8(&(cd->st_utf8), p); + } + + if (cd->st_ascii.flag == 1) eid = eid_ASCII; + else if (cd->st_jis.flag == 1) eid = eid_JIS; + else if (cd->st_utf8.flag == 1) eid = eid_UTF8; + else if (cd->order == ieo_EUCJP) + { + if (cd->st_eucjp.flag == 1) eid = eid_EUCJP; + else if (cd->st_sjis.flag == 1) eid = eid_SJIS; + }else{ + if (cd->st_sjis.flag == 1) eid = eid_SJIS; + else if (cd->st_eucjp.flag == 1) eid = eid_EUCJP; + } + + return encoding_str[ eid ]; +} diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/identify_encoding.h b/c:/Git/PeerCast.root/PeerCast/core/common/identify_encoding.h new file mode 100644 index 0000000..5ccaf72 --- /dev/null +++ b/c:/Git/PeerCast.root/PeerCast/core/common/identify_encoding.h @@ -0,0 +1,42 @@ +/* + * + * Š¿ŽšƒR[ƒh‚Ì”»•Ê‚µAiconv —p‚Ì•¶ŽšƒGƒ“ƒR[ƒfƒBƒ“ƒO•¶Žš—ñ‚ð•Ô‚· + * + * 2001/10/24 Remove static variables + * Kazuhiko Iwama + * 2001/10/14 First version + * Kazuhiko Iwama + * + */ + +#ifndef IDENTIFY_ENCODING_H +#define IDENTIFY_ENCODING_H + +#define IDENTIFY_MAX_LENGTH 256 + +enum identify_encoding_order { + ieo_EUCJP = 0, + ieo_SJIS = 1 +}; + +typedef struct { + int flag; + int state; + int c_type; +} ie_state_t; + +typedef struct { + enum identify_encoding_order order; + ie_state_t st_ascii; + ie_state_t st_jis; + ie_state_t st_sjis; + ie_state_t st_eucjp; + ie_state_t st_utf8; +} identify_encoding_t; + +identify_encoding_t* identify_encoding_open(enum identify_encoding_order order); +void identify_encoding_close(identify_encoding_t* cd); +void identify_encoding_reset(identify_encoding_t* cd); +const char *identify_encoding(identify_encoding_t *cd, char* instr); + +#endif diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/inifile.cpp b/c:/Git/PeerCast.root/PeerCast/core/common/inifile.cpp new file mode 100644 index 0000000..965f2a9 --- /dev/null +++ b/c:/Git/PeerCast.root/PeerCast/core/common/inifile.cpp @@ -0,0 +1,168 @@ +// ------------------------------------------------ +// File : inifile.cpp +// Date: 4-apr-2002 +// Author: giles +// Desc: +// .INI file reading/writing class +// +// (c) 2002 peercast.org +// ------------------------------------------------ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// ------------------------------------------------ + +#include +#include "inifile.h" +#include "sys.h" +#ifdef _DEBUG +#include "chkMemoryLeak.h" +#define DEBUG_NEW new(__FILE__, __LINE__) +#define new DEBUG_NEW +#endif + + + void openReadOnly(const char *); + void openWriteReplace(const char *); +// ----------------------------------------- +bool IniFile::openReadOnly(const char *fn) +{ + try + { + fStream.openReadOnly(fn); + }catch(StreamException &) + { + return false; + } + return true; +} +// ----------------------------------------- +bool IniFile::openWriteReplace(const char *fn) +{ + try + { + fStream.openWriteReplace(fn); +#if defined(_LINUX) || defined(__APPLE__) + fStream.writeCRLF = false; +#endif + + }catch(StreamException &) + { + return false; + } + return true; +} +// ----------------------------------------- +void IniFile::close() +{ + fStream.close(); +} + + +// ----------------------------------------- +bool IniFile::readNext() +{ + if (fStream.eof()) + return false; + + try + { + fStream.readLine(currLine,256); + }catch(StreamException &) + { + return false; + } + + + // find end of value name and null terminate + char *nend = strstr(currLine,"="); + + if (nend) + { + *nend = 0; + valueStr = trimstr(nend+1); + }else + valueStr = NULL; + + nameStr = trimstr(currLine); + + return true; +} +// ----------------------------------------- +bool IniFile::isName(const char *str) +{ + return stricmp(getName(),str)==0; +} + +// ----------------------------------------- +char * IniFile::getName() +{ + return nameStr; +} +// ----------------------------------------- +int IniFile::getIntValue() +{ + if (valueStr) + return atoi(valueStr); + else + return 0; +} +// ----------------------------------------- +char * IniFile::getStrValue() +{ + if (valueStr) + return valueStr; + else + return ""; +} +// ----------------------------------------- +bool IniFile::getBoolValue() +{ + if (!valueStr) + return false; + + + if ( (stricmp(valueStr,"yes")==0) || + (stricmp(valueStr,"y")==0) || + (stricmp(valueStr,"1")==0) ) + return true; + + return false; +} + +// ----------------------------------------- +void IniFile::writeIntValue(const char *name, int iv) +{ + sprintf(currLine,"%s = %d",name,iv); + fStream.writeLine(currLine); +} +// ----------------------------------------- +void IniFile::writeStrValue(const char *name, const char *sv) +{ + sprintf(currLine,"%s = %s",name,sv); + fStream.writeLine(currLine); +} +// ----------------------------------------- +void IniFile::writeSection(const char *name) +{ + fStream.writeLine(""); + sprintf(currLine,"[%s]",name); + fStream.writeLine(currLine); +} +// ----------------------------------------- +void IniFile::writeBoolValue(const char *name, int v) +{ + sprintf(currLine,"%s = %s",name,(v!=0)?"Yes":"No"); + fStream.writeLine(currLine); +} +// ----------------------------------------- +void IniFile::writeLine(const char *str) +{ + fStream.writeLine(str); +} diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/inifile.h b/c:/Git/PeerCast.root/PeerCast/core/common/inifile.h new file mode 100644 index 0000000..2b75cca --- /dev/null +++ b/c:/Git/PeerCast.root/PeerCast/core/common/inifile.h @@ -0,0 +1,53 @@ +// ------------------------------------------------ +// File : inifile.h +// Date: 4-apr-2002 +// Author: giles +// Desc: +// +// (c) 2002 peercast.org +// ------------------------------------------------ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// ------------------------------------------------ + +#ifndef _INIFILE +#define _INIFILE + +#include "stream.h" + +// ----------------------------------------- +class IniFile +{ +public: + bool openReadOnly(const char *); + bool openWriteReplace(const char *); + void close(); + + bool readNext(); + + bool isName(const char *); + char * getName(); + int getIntValue(); + char * getStrValue(); + bool getBoolValue(); + + void writeSection(const char *); + void writeIntValue(const char *, int); + void writeStrValue(const char *, const char *); + void writeBoolValue(const char *, int); + void writeLine(const char *); + + + FileStream fStream; + char currLine[256]; + char *nameStr,*valueStr; +}; + +#endif diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/jis.cpp b/c:/Git/PeerCast.root/PeerCast/core/common/jis.cpp new file mode 100644 index 0000000..1ce75f2 --- /dev/null +++ b/c:/Git/PeerCast.root/PeerCast/core/common/jis.cpp @@ -0,0 +1,755 @@ +// ------------------------------------------------ +// File : jis.cpp +// Date: 1-april-2004 +// Author: giles +// +// ShiftJIS/EUC to Unicode conversions +// (modified version of program by Y. Kuno, see below) +// +// +// (c) 2002-4 peercast.org +// ------------------------------------------------ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// ------------------------------------------------ + + + +/* J2Uc.c --- written by Y. Kuno, July 1996. */ +/* Compile with -DSJIS if you want to convert from SJIS; otherwise */ +/* EUC-JP is assumed. */ +/* We are thankful to following people for permitting us free use */ +/* of the following materials. */ +/* * Itaru Ichikawa (Fujitsu) --- nkf 1.4 source code. */ +/* * Glenn Adams (Unicode Inc.) --- JISx0208 to Unicode mapping table. */ +/* This source code can freely be used, distributed, modified provided */ +/* that this credit is also included in the source code. */ + +// ----------------------------------- + +#include "jis.h" +#ifdef _DEBUG +#include "chkMemoryLeak.h" +#define DEBUG_NEW new(__FILE__, __LINE__) +#define new DEBUG_NEW +#endif + + +// ----------------------------------- + +#define SJ0162 0x00e1 /* 01 - 62 ku offset */ +#define SJ6394 0x0161 /* 63 - 94 ku offset */ + + +// ----------------------------------- +static unsigned short uniTable[94][94] = { +{12288,12289,12290,65292,65294,12539,65306,65307,65311,65281,12443,12444, + 180,65344,168,65342,65507,65343,12541,12542,12445,12446,12291,20189, + 12293,12294,12295,12540,8213,8208,65295,92,12316,8214,65372,8230, + 8229,8216,8217,8220,8221,65288,65289,12308,12309,65339,65341,65371, + 65373,12296,12297,12298,12299,12300,12301,12302,12303,12304,12305,65291, + 8722,177,215,247,65309,8800,65308,65310,8806,8807,8734,8756, + 9794,9792,176,8242,8243,8451,65509,65284,162,163,65285,65283, + 65286,65290,65312,167,9734,9733,9675,9679,9678,9671,}, +{9670,9633,9632,9651,9650,9661,9660,8251,12306,8594,8592,8593, + 8595,12307,0,0,0,0,0,0,0,0,0,0,0,8712,8715,8838,8839,8834,8835, + 8746,8745,0,0,0,0,0,0,0,0,8743,8744,172,8658,8660,8704,8707,0,0, + 0,0,0,0,0,0,0,0,0,8736,8869,8978,8706,8711,8801,8786,8810,8811, + 8730,8765,8733,8757,8747,8748,0,0,0,0,0,0,0,8491,8240,9839,9837, + 9834,8224,8225,182,0,0,0,0,9711,}, +{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,65296,65297,65298,65299,65300,65301,65302, + 65303,65304,65305,0,0,0,0,0,0,0,65313,65314,65315,65316,65317,65318,65319, + 65320,65321,65322,65323,65324,65325,65326,65327,65328,65329,65330,65331, + 65332,65333,65334,65335,65336,65337,65338,0,0,0,0,0,0,65345,65346,65347, + 65348,65349,65350,65351,65352,65353,65354,65355,65356,65357,65358,65359, + 65360,65361,65362,65363,65364,65365,65366,65367,65368,65369,65370,0,0,0,0,}, +{12353,12354,12355,12356,12357,12358,12359,12360,12361,12362,12363,12364, + 12365,12366,12367,12368,12369,12370,12371,12372,12373,12374,12375,12376, + 12377,12378,12379,12380,12381,12382,12383,12384,12385,12386,12387,12388, + 12389,12390,12391,12392,12393,12394,12395,12396,12397,12398,12399,12400, + 12401,12402,12403,12404,12405,12406,12407,12408,12409,12410,12411,12412, + 12413,12414,12415,12416,12417,12418,12419,12420,12421,12422,12423,12424, + 12425,12426,12427,12428,12429,12430,12431,12432,12433,12434,12435,0,0,0,0, + 0,0,0,0,0,0,0,}, +{12449,12450,12451,12452,12453,12454,12455,12456,12457,12458,12459,12460, + 12461,12462,12463,12464,12465,12466,12467,12468,12469,12470,12471,12472, + 12473,12474,12475,12476,12477,12478,12479,12480,12481,12482,12483,12484, + 12485,12486,12487,12488,12489,12490,12491,12492,12493,12494,12495,12496, + 12497,12498,12499,12500,12501,12502,12503,12504,12505,12506,12507,12508, + 12509,12510,12511,12512,12513,12514,12515,12516,12517,12518,12519,12520, + 12521,12522,12523,12524,12525,12526,12527,12528,12529,12530,12531,12532, + 12533,12534,0,0,0,0,0,0,0,0,}, +{913,914,915,916,917,918,919,920,921,922,923,924, + 925,926,927,928,929,931,932,933,934,935,936,937,0, + 0,0,0,0,0,0,0,945,946,947,948,949,950,951,952,953,954, + 955,956,957,958,959,960,961,963,964,965,966,967, + 968,969,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,}, +{1040,1041,1042,1043,1044,1045,1025,1046,1047,1048,1049,1050, + 1051,1052,1053,1054,1055,1056,1057,1058,1059,1060,1061,1062, + 1063,1064,1065,1066,1067,1068,1069,1070,1071,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,1072,1073,1074,1075,1076,1077,1105,1078,1079,1080, + 1081,1082,1083,1084,1085,1086,1087,1088,1089,1090,1091,1092, + 1093,1094,1095,1096,1097,1098,1099,1100,1101,1102,1103,0,0,0,0, + 0,0,0,0,0,0,0,0,0,}, +{9472,9474,9484,9488,9496,9492,9500,9516,9508,9524,9532,9473, + 9475,9487,9491,9499,9495,9507,9523,9515,9531,9547,9504,9519, + 9512,9527,9535,9501,9520,9509,9528,9538,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,}, +{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,}, +{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,}, +{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,}, +{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,}, +{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,}, +{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,}, +{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,}, +{20124,21782,23043,38463,21696,24859,25384,23030,36898,33909,33564,31312, + 24746,25569,28197,26093,33894,33446,39925,26771,22311,26017,25201,23451, + 22992,34427,39156,32098,32190,39822,25110,31903,34999,23433,24245,25353, + 26263,26696,38343,38797,26447,20197,20234,20301,20381,20553,22258,22839, + 22996,23041,23561,24799,24847,24944,26131,26885,28858,30031,30064,31227, + 32173,32239,32963,33806,34915,35586,36949,36986,21307,20117,20133,22495, + 32946,37057,30959,19968,22769,28322,36920,31282,33576,33419,39983,20801, + 21360,21693,21729,22240,23035,24341,39154,28139,32996,34093,}, +{38498,38512,38560,38907,21515,21491,23431,28879,32701,36802,38632,21359, + 40284,31418,19985,30867,33276,28198,22040,21764,27421,34074,39995,23013, + 21417,28006,29916,38287,22082,20113,36939,38642,33615,39180,21473,21942, + 23344,24433,26144,26355,26628,27704,27891,27945,29787,30408,31310,38964, + 33521,34907,35424,37613,28082,30123,30410,39365,24742,35585,36234,38322, + 27022,21421,20870,22290,22576,22852,23476,24310,24616,25513,25588,27839, + 28436,28814,28948,29017,29141,29503,32257,33398,33489,34199,36960,37467, + 40219,22633,26044,27738,29989,20985,22830,22885,24448,24540,}, +{25276,26106,27178,27431,27572,29579,32705,35158,40236,40206,40644,23713, + 27798,33659,20740,23627,25014,33222,26742,29281,20057,20474,21368,24681, + 28201,31311,38899,19979,21270,20206,20309,20285,20385,20339,21152,21487, + 22025,22799,23233,23478,23521,31185,26247,26524,26550,27468,27827,28779, + 29634,31117,31166,31292,31623,33457,33499,33540,33655,33775,33747,34662, + 35506,22057,36008,36838,36942,38686,34442,20420,23784,25105,29273,30011, + 33253,33469,34558,36032,38597,39187,39381,20171,20250,35299,22238,22602, + 22730,24315,24555,24618,24724,24674,25040,25106,25296,25913,}, +{39745,26214,26800,28023,28784,30028,30342,32117,33445,34809,38283,38542, + 35997,20977,21182,22806,21683,23475,23830,24936,27010,28079,30861,33995, + 34903,35442,37799,39608,28012,39336,34521,22435,26623,34510,37390,21123, + 22151,21508,24275,25313,25785,26684,26680,27579,29554,30906,31339,35226, + 35282,36203,36611,37101,38307,38548,38761,23398,23731,27005,38989,38990, + 25499,31520,27179,27263,26806,39949,28511,21106,21917,24688,25324,27963, + 28167,28369,33883,35088,36676,19988,39993,21494,26907,27194,38788,26666, + 20828,31427,33970,37340,37772,22107,40232,26658,33541,33841,}, +{31909,21000,33477,29926,20094,20355,20896,23506,21002,21208,21223,24059, + 21914,22570,23014,23436,23448,23515,24178,24185,24739,24863,24931,25022, + 25563,25954,26577,26707,26874,27454,27475,27735,28450,28567,28485,29872, + 29976,30435,30475,31487,31649,31777,32233,32566,32752,32925,33382,33694, + 35251,35532,36011,36996,37969,38291,38289,38306,38501,38867,39208,33304, + 20024,21547,23736,24012,29609,30284,30524,23721,32747,36107,38593,38929, + 38996,39000,20225,20238,21361,21916,22120,22522,22855,23305,23492,23696, + 24076,24190,24524,25582,26426,26071,26082,26399,26827,26820,}, +{27231,24112,27589,27671,27773,30079,31048,23395,31232,32000,24509,35215, + 35352,36020,36215,36556,36637,39138,39438,39740,20096,20605,20736,22931, + 23452,25135,25216,25836,27450,29344,30097,31047,32681,34811,35516,35696, + 25516,33738,38816,21513,21507,21931,26708,27224,35440,30759,26485,40653, + 21364,23458,33050,34384,36870,19992,20037,20167,20241,21450,21560,23470, + 24339,24613,25937,26429,27714,27762,27875,28792,29699,31350,31406,31496, + 32026,31998,32102,26087,29275,21435,23621,24040,25298,25312,25369,28192, + 34394,35377,36317,37624,28417,31142,39770,20136,20139,20140,}, +{20379,20384,20689,20807,31478,20849,20982,21332,21281,21375,21483,21932, + 22659,23777,24375,24394,24623,24656,24685,25375,25945,27211,27841,29378, + 29421,30703,33016,33029,33288,34126,37111,37857,38911,39255,39514,20208, + 20957,23597,26241,26989,23616,26354,26997,29577,26704,31873,20677,21220, + 22343,24062,37670,26020,27427,27453,29748,31105,31165,31563,32202,33465, + 33740,34943,35167,35641,36817,37329,21535,37504,20061,20534,21477,21306, + 29399,29590,30697,33510,36527,39366,39368,39378,20855,24858,34398,21936, + 31354,20598,23507,36935,38533,20018,27355,37351,23633,23624,}, +{25496,31391,27795,38772,36705,31402,29066,38536,31874,26647,32368,26705, + 37740,21234,21531,34219,35347,32676,36557,37089,21350,34952,31041,20418, + 20670,21009,20804,21843,22317,29674,22411,22865,24418,24452,24693,24950, + 24935,25001,25522,25658,25964,26223,26690,28179,30054,31293,31995,32076, + 32153,32331,32619,33550,33610,34509,35336,35427,35686,36605,38938,40335, + 33464,36814,39912,21127,25119,25731,28608,38553,26689,20625,27424,27770, + 28500,31348,32080,34880,35363,26376,20214,20537,20518,20581,20860,21048, + 21091,21927,22287,22533,23244,24314,25010,25080,25331,25458,}, +{26908,27177,29309,29356,29486,30740,30831,32121,30476,32937,35211,35609, + 36066,36562,36963,37749,38522,38997,39443,40568,20803,21407,21427,24187, + 24358,28187,28304,29572,29694,32067,33335,35328,35578,38480,20046,20491, + 21476,21628,22266,22993,23396,24049,24235,24359,25144,25925,26543,28246, + 29392,31946,34996,32929,32993,33776,34382,35463,36328,37431,38599,39015, + 40723,20116,20114,20237,21320,21577,21566,23087,24460,24481,24735,26791, + 27278,29786,30849,35486,35492,35703,37264,20062,39881,20132,20348,20399, + 20505,20502,20809,20844,21151,21177,21246,21402,21475,21521,}, +{21518,21897,22353,22434,22909,23380,23389,23439,24037,24039,24055,24184, + 24195,24218,24247,24344,24658,24908,25239,25304,25511,25915,26114,26179, + 26356,26477,26657,26775,27083,27743,27946,28009,28207,28317,30002,30343, + 30828,31295,31968,32005,32024,32094,32177,32789,32771,32943,32945,33108, + 33167,33322,33618,34892,34913,35611,36002,36092,37066,37237,37489,30783, + 37628,38308,38477,38917,39321,39640,40251,21083,21163,21495,21512,22741, + 25335,28640,35946,36703,40633,20811,21051,21578,22269,31296,37239,40288, + 40658,29508,28425,33136,29969,24573,24794,39592,29403,36796,}, +{27492,38915,20170,22256,22372,22718,23130,24680,25031,26127,26118,26681, + 26801,28151,30165,32058,33390,39746,20123,20304,21449,21766,23919,24038, + 24046,26619,27801,29811,30722,35408,37782,35039,22352,24231,25387,20661, + 20652,20877,26368,21705,22622,22971,23472,24425,25165,25505,26685,27507, + 28168,28797,37319,29312,30741,30758,31085,25998,32048,33756,35009,36617, + 38555,21092,22312,26448,32618,36001,20916,22338,38442,22586,27018,32948, + 21682,23822,22524,30869,40442,20316,21066,21643,25662,26152,26388,26613, + 31364,31574,32034,37679,26716,39853,31545,21273,20874,21047,}, +{23519,25334,25774,25830,26413,27578,34217,38609,30352,39894,25420,37638, + 39851,30399,26194,19977,20632,21442,23665,24808,25746,25955,26719,29158, + 29642,29987,31639,32386,34453,35715,36059,37240,39184,26028,26283,27531, + 20181,20180,20282,20351,21050,21496,21490,21987,22235,22763,22987,22985, + 23039,23376,23629,24066,24107,24535,24605,25351,25903,23388,26031,26045, + 26088,26525,27490,27515,27663,29509,31049,31169,31992,32025,32043,32930, + 33026,33267,35222,35422,35433,35430,35468,35566,36039,36060,38604,39164, + 27503,20107,20284,20365,20816,23383,23546,24904,25345,26178,}, +{27425,28363,27835,29246,29885,30164,30913,31034,32780,32819,33258,33940, + 36766,27728,40575,24335,35672,40235,31482,36600,23437,38635,19971,21489, + 22519,22833,23241,23460,24713,28287,28422,30142,36074,23455,34048,31712, + 20594,26612,33437,23649,34122,32286,33294,20889,23556,25448,36198,26012, + 29038,31038,32023,32773,35613,36554,36974,34503,37034,20511,21242,23610, + 26451,28796,29237,37196,37320,37675,33509,23490,24369,24825,20027,21462, + 23432,25163,26417,27530,29417,29664,31278,33131,36259,37202,39318,20754, + 21463,21610,23551,25480,27193,32172,38656,22234,21454,21608,}, +{23447,23601,24030,20462,24833,25342,27954,31168,31179,32066,32333,32722, + 33261,33311,33936,34886,35186,35728,36468,36655,36913,37195,37228,38598, + 37276,20160,20303,20805,21313,24467,25102,26580,27713,28171,29539,32294, + 37325,37507,21460,22809,23487,28113,31069,32302,31899,22654,29087,20986, + 34899,36848,20426,23803,26149,30636,31459,33308,39423,20934,24490,26092, + 26991,27529,28147,28310,28516,30462,32020,24033,36981,37255,38918,20966, + 21021,25152,26257,26329,28186,24246,32210,32626,26360,34223,34295,35576, + 21161,21465,22899,24207,24464,24661,37604,38500,20663,20767,}, +{21213,21280,21319,21484,21736,21830,21809,22039,22888,22974,23100,23477, + 23558,23567,23569,23578,24196,24202,24288,24432,25215,25220,25307,25484, + 25463,26119,26124,26157,26230,26494,26786,27167,27189,27836,28040,28169, + 28248,28988,28966,29031,30151,30465,30813,30977,31077,31216,31456,31505, + 31911,32057,32918,33750,33931,34121,34909,35059,35359,35388,35412,35443, + 35937,36062,37284,37478,37758,37912,38556,38808,19978,19976,19998,20055, + 20887,21104,22478,22580,22732,23330,24120,24773,25854,26465,26454,27972, + 29366,30067,31331,33976,35698,37304,37664,22065,22516,39166,}, +{25325,26893,27542,29165,32340,32887,33394,35302,39135,34645,36785,23611, + 20280,20449,20405,21767,23072,23517,23529,24515,24910,25391,26032,26187, + 26862,27035,28024,28145,30003,30137,30495,31070,31206,32051,33251,33455, + 34218,35242,35386,36523,36763,36914,37341,38663,20154,20161,20995,22645, + 22764,23563,29978,23613,33102,35338,36805,38499,38765,31525,35535,38920, + 37218,22259,21416,36887,21561,22402,24101,25512,27700,28810,30561,31883, + 32736,34928,36930,37204,37648,37656,38543,29790,39620,23815,23913,25968, + 26530,36264,38619,25454,26441,26905,33733,38935,38592,35070,}, +{28548,25722,23544,19990,28716,30045,26159,20932,21046,21218,22995,24449, + 24615,25104,25919,25972,26143,26228,26866,26646,27491,28165,29298,29983, + 30427,31934,32854,22768,35069,35199,35488,35475,35531,36893,37266,38738, + 38745,25993,31246,33030,38587,24109,24796,25114,26021,26132,26512,30707, + 31309,31821,32318,33034,36012,36196,36321,36447,30889,20999,25305,25509, + 25666,25240,35373,31363,31680,35500,38634,32118,33292,34633,20185,20808, + 21315,21344,23459,23554,23574,24029,25126,25159,25776,26643,26676,27849, + 27973,27927,26579,28508,29006,29053,26059,31359,31661,32218,}, +{32330,32680,33146,33307,33337,34214,35438,36046,36341,36984,36983,37549, + 37521,38275,39854,21069,21892,28472,28982,20840,31109,32341,33203,31950, + 22092,22609,23720,25514,26366,26365,26970,29401,30095,30094,30990,31062, + 31199,31895,32032,32068,34311,35380,38459,36961,40736,20711,21109,21452, + 21474,20489,21930,22766,22863,29245,23435,23652,21277,24803,24819,25436, + 25475,25407,25531,25805,26089,26361,24035,27085,27133,28437,29157,20105, + 30185,30456,31379,31967,32207,32156,32865,33609,33624,33900,33980,34299, + 35013,36208,36865,36973,37783,38684,39442,20687,22679,24974,}, +{33235,34101,36104,36896,20419,20596,21063,21363,24687,25417,26463,28204, + 36275,36895,20439,23646,36042,26063,32154,21330,34966,20854,25539,23384, + 23403,23562,25613,26449,36956,20182,22810,22826,27760,35409,21822,22549, + 22949,24816,25171,26561,33333,26965,38464,39364,39464,20307,22534,23550, + 32784,23729,24111,24453,24608,24907,25140,26367,27888,28382,32974,33151, + 33492,34955,36024,36864,36910,38538,40667,39899,20195,21488,22823,31532, + 37261,38988,40441,28381,28711,21331,21828,23429,25176,25246,25299,27810, + 28655,29730,35351,37944,28609,35582,33592,20967,34552,21482,}, +{21481,20294,36948,36784,22890,33073,24061,31466,36799,26842,35895,29432, + 40008,27197,35504,20025,21336,22022,22374,25285,25506,26086,27470,28129, + 28251,28845,30701,31471,31658,32187,32829,32966,34507,35477,37723,22243, + 22727,24382,26029,26262,27264,27573,30007,35527,20516,30693,22320,24347, + 24677,26234,27744,30196,31258,32622,33268,34584,36933,39347,31689,30044, + 31481,31569,33988,36880,31209,31378,33590,23265,30528,20013,20210,23449, + 24544,25277,26172,26609,27880,34411,34935,35387,37198,37619,39376,27159, + 28710,29482,33511,33879,36015,19969,20806,20939,21899,23541,}, +{24086,24115,24193,24340,24373,24427,24500,25074,25361,26274,26397,28526, + 29266,30010,30522,32884,33081,33144,34678,35519,35548,36229,36339,37530, + 38263,38914,40165,21189,25431,30452,26389,27784,29645,36035,37806,38515, + 27941,22684,26894,27084,36861,37786,30171,36890,22618,26626,25524,27131, + 20291,28460,26584,36795,34086,32180,37716,26943,28528,22378,22775,23340, + 32044,29226,21514,37347,40372,20141,20302,20572,20597,21059,35998,21576, + 22564,23450,24093,24213,24237,24311,24351,24716,25269,25402,25552,26799, + 27712,30855,31118,31243,32224,33351,35330,35558,36420,36883,}, +{37048,37165,37336,40718,27877,25688,25826,25973,28404,30340,31515,36969, + 37841,28346,21746,24505,25764,36685,36845,37444,20856,22635,22825,23637, + 24215,28155,32399,29980,36028,36578,39003,28857,20253,27583,28593,30000, + 38651,20814,21520,22581,22615,22956,23648,24466,26007,26460,28193,30331, + 33759,36077,36884,37117,37709,30757,30778,21162,24230,22303,22900,24594, + 20498,20826,20908,20941,20992,21776,22612,22616,22871,23445,23798,23947, + 24764,25237,25645,26481,26691,26812,26847,30423,28120,28271,28059,28783, + 29128,24403,30168,31095,31561,31572,31570,31958,32113,21040,}, +{33891,34153,34276,35342,35588,35910,36367,36867,36879,37913,38518,38957, + 39472,38360,20685,21205,21516,22530,23566,24999,25758,27934,30643,31461, + 33012,33796,36947,37509,23776,40199,21311,24471,24499,28060,29305,30563, + 31167,31716,27602,29420,35501,26627,27233,20984,31361,26932,23626,40182, + 33515,23493,37193,28702,22136,23663,24775,25958,27788,35930,36929,38931, + 21585,26311,37389,22856,37027,20869,20045,20970,34201,35598,28760,25466, + 37707,26978,39348,32260,30071,21335,26976,36575,38627,27741,20108,23612, + 24336,36841,21250,36049,32905,34425,24319,26085,20083,20837,}, +{22914,23615,38894,20219,22922,24525,35469,28641,31152,31074,23527,33905, + 29483,29105,24180,24565,25467,25754,29123,31896,20035,24316,20043,22492, + 22178,24745,28611,32013,33021,33075,33215,36786,35223,34468,24052,25226, + 25773,35207,26487,27874,27966,29750,30772,23110,32629,33453,39340,20467, + 24259,25309,25490,25943,26479,30403,29260,32972,32954,36649,37197,20493, + 22521,23186,26757,26995,29028,29437,36023,22770,36064,38506,36889,34687, + 31204,30695,33833,20271,21093,21338,25293,26575,27850,30333,31636,31893, + 33334,34180,36843,26333,28448,29190,32283,33707,39361,40614,}, +{20989,31665,30834,31672,32903,31560,27368,24161,32908,30033,30048,20843, + 37474,28300,30330,37271,39658,20240,32624,25244,31567,38309,40169,22138, + 22617,34532,38588,20276,21028,21322,21453,21467,24070,25644,26001,26495, + 27710,27726,29256,29359,29677,30036,32321,33324,34281,36009,31684,37318, + 29033,38930,39151,25405,26217,30058,30436,30928,34115,34542,21290,21329, + 21542,22915,24199,24444,24754,25161,25209,25259,26000,27604,27852,30130, + 30382,30865,31192,32203,32631,32933,34987,35513,36027,36991,38750,39131, + 27147,31800,20633,23614,24494,26503,27608,29749,30473,32654,}, +{40763,26570,31255,21305,30091,39661,24422,33181,33777,32920,24380,24517, + 30050,31558,36924,26727,23019,23195,32016,30334,35628,20469,24426,27161, + 27703,28418,29922,31080,34920,35413,35961,24287,25551,30149,31186,33495, + 37672,37618,33948,34541,39981,21697,24428,25996,27996,28693,36007,36051, + 38971,25935,29942,19981,20184,22496,22827,23142,23500,20904,24067,24220, + 24598,25206,25975,26023,26222,28014,29238,31526,33104,33178,33433,35676, + 36000,36070,36212,38428,38468,20398,25771,27494,33310,33889,34154,37096, + 23553,26963,39080,33914,34135,20239,21103,24489,24133,26381,}, +{31119,33145,35079,35206,28149,24343,25173,27832,20175,29289,39826,20998, + 21563,22132,22707,24996,25198,28954,22894,31881,31966,32027,38640,25991, + 32862,19993,20341,20853,22592,24163,24179,24330,26564,20006,34109,38281, + 38491,31859,38913,20731,22721,30294,30887,21029,30629,34065,31622,20559, + 22793,29255,31687,32232,36794,36820,36941,20415,21193,23081,24321,38829, + 20445,33303,37610,22275,25429,27497,29995,35036,36628,31298,21215,22675, + 24917,25098,26286,27597,31807,33769,20515,20472,21253,21574,22577,22857, + 23453,23792,23791,23849,24214,25265,25447,25918,26041,26379,}, +{27861,27873,28921,30770,32299,32990,33459,33804,34028,34562,35090,35370, + 35914,37030,37586,39165,40179,40300,20047,20129,20621,21078,22346,22952, + 24125,24536,24537,25151,26292,26395,26576,26834,20882,32033,32938,33192, + 35584,35980,36031,37502,38450,21536,38956,21271,20693,21340,22696,25778, + 26420,29287,30566,31302,37350,21187,27809,27526,22528,24140,22868,26412, + 32763,20961,30406,25705,30952,39764,40635,22475,22969,26151,26522,27598, + 21737,27097,24149,33180,26517,39850,26622,40018,26717,20134,20451,21448, + 25273,26411,27819,36804,20397,32365,40639,19975,24930,28288,}, +{28459,34067,21619,26410,39749,24051,31637,23724,23494,34588,28234,34001, + 31252,33032,22937,31885,27665,30496,21209,22818,28961,29279,30683,38695, + 40289,26891,23167,23064,20901,21517,21629,26126,30431,36855,37528,40180, + 23018,29277,28357,20813,26825,32191,32236,38754,40634,25720,27169,33538, + 22916,23391,27611,29467,30450,32178,32791,33945,20786,26408,40665,30446, + 26466,21247,39173,23588,25147,31870,36016,21839,24758,32011,38272,21249, + 20063,20918,22812,29242,32822,37326,24357,30690,21380,24441,32004,34220, + 35379,36493,38742,26611,34222,37971,24841,24840,27833,30290,}, +{35565,36664,21807,20305,20778,21191,21451,23461,24189,24736,24962,25558, + 26377,26586,28263,28044,29494,29495,30001,31056,35029,35480,36938,37009, + 37109,38596,34701,22805,20104,20313,19982,35465,36671,38928,20653,24188, + 22934,23481,24248,25562,25594,25793,26332,26954,27096,27915,28342,29076, + 29992,31407,32650,32768,33865,33993,35201,35617,36362,36965,38525,39178, + 24958,25233,27442,27779,28020,32716,32764,28096,32645,34746,35064,26469, + 33713,38972,38647,27931,32097,33853,37226,20081,21365,23888,27396,28651, + 34253,34349,35239,21033,21519,23653,26446,26792,29702,29827,}, +{30178,35023,35041,37324,38626,38520,24459,29575,31435,33870,25504,30053, + 21129,27969,28316,29705,30041,30827,31890,38534,31452,40845,20406,24942, + 26053,34396,20102,20142,20698,20001,20940,23534,26009,26753,28092,29471, + 30274,30637,31260,31975,33391,35538,36988,37327,38517,38936,21147,32209, + 20523,21400,26519,28107,29136,29747,33256,36650,38563,40023,40607,29792, + 22593,28057,32047,39006,20196,20278,20363,20919,21169,23994,24604,29618, + 31036,33491,37428,38583,38646,38666,40599,40802,26278,27508,21015,21155, + 28872,35010,24265,24651,24976,28451,29001,31806,32244,32879,}, +{34030,36899,37676,21570,39791,27347,28809,36034,36335,38706,21172,23105, + 24266,24324,26391,27004,27028,28010,28431,29282,29436,31725,32769,32894, + 34635,37070,20845,40595,31108,32907,37682,35542,20525,21644,35441,27498, + 36036,33031,24785,26528,40434,20121,20120,39952,35435,34241,34152,26880, + 28286,30871,33109,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,}, +{24332,19984,19989,20010,20017,20022,20028,20031,20034,20054,20056,20098, + 20101,35947,20106,33298,24333,20110,20126,20127,20128,20130,20144,20147, + 20150,20174,20173,20164,20166,20162,20183,20190,20205,20191,20215,20233, + 20314,20272,20315,20317,20311,20295,20342,20360,20367,20376,20347,20329, + 20336,20369,20335,20358,20374,20760,20436,20447,20430,20440,20443,20433, + 20442,20432,20452,20453,20506,20520,20500,20522,20517,20485,20252,20470, + 20513,20521,20524,20478,20463,20497,20486,20547,20551,26371,20565,20560, + 20552,20570,20566,20588,20600,20608,20634,20613,20660,20658,}, +{20681,20682,20659,20674,20694,20702,20709,20717,20707,20718,20729,20725, + 20745,20737,20738,20758,20757,20756,20762,20769,20794,20791,20796,20795, + 20799,20800,20818,20812,20820,20834,31480,20841,20842,20846,20864,20866, + 22232,20876,20873,20879,20881,20883,20885,20886,20900,20902,20898,20905, + 20906,20907,20915,20913,20914,20912,20917,20925,20933,20937,20955,20960, + 34389,20969,20973,20976,20981,20990,20996,21003,21012,21006,21031,21034, + 21038,21043,21049,21071,21060,21067,21068,21086,21076,21098,21108,21097, + 21107,21119,21117,21133,21140,21138,21105,21128,21137,36776,}, +{36775,21164,21165,21180,21173,21185,21197,21207,21214,21219,21222,39149, + 21216,21235,21237,21240,21241,21254,21256,30008,21261,21264,21263,21269, + 21274,21283,21295,21297,21299,21304,21312,21318,21317,19991,21321,21325, + 20950,21342,21353,21358,22808,21371,21367,21378,21398,21408,21414,21413, + 21422,21424,21430,21443,31762,38617,21471,26364,29166,21486,21480,21485, + 21498,21505,21565,21568,21548,21549,21564,21550,21558,21545,21533,21582, + 21647,21621,21646,21599,21617,21623,21616,21650,21627,21632,21622,21636, + 21648,21638,21703,21666,21688,21669,21676,21700,21704,21672,}, +{21675,21698,21668,21694,21692,21720,21733,21734,21775,21780,21757,21742, + 21741,21754,21730,21817,21824,21859,21836,21806,21852,21829,21846,21847, + 21816,21811,21853,21913,21888,21679,21898,21919,21883,21886,21912,21918, + 21934,21884,21891,21929,21895,21928,21978,21957,21983,21956,21980,21988, + 21972,22036,22007,22038,22014,22013,22043,22009,22094,22096,29151,22068, + 22070,22066,22072,22123,22116,22063,22124,22122,22150,22144,22154,22176, + 22164,22159,22181,22190,22198,22196,22210,22204,22209,22211,22208,22216, + 22222,22225,22227,22231,22254,22265,22272,22271,22276,22281,}, +{22280,22283,22285,22291,22296,22294,21959,22300,22310,22327,22328,22350, + 22331,22336,22351,22377,22464,22408,22369,22399,22409,22419,22432,22451, + 22436,22442,22448,22467,22470,22484,22482,22483,22538,22486,22499,22539, + 22553,22557,22642,22561,22626,22603,22640,27584,22610,22589,22649,22661, + 22713,22687,22699,22714,22750,22715,22712,22702,22725,22739,22737,22743, + 22745,22744,22757,22748,22756,22751,22767,22778,22777,22779,22780,22781, + 22786,22794,22800,22811,26790,22821,22828,22829,22834,22840,22846,31442, + 22869,22864,22862,22874,22872,22882,22880,22887,22892,22889,}, +{22904,22913,22941,20318,20395,22947,22962,22982,23016,23004,22925,23001, + 23002,23077,23071,23057,23068,23049,23066,23104,23148,23113,23093,23094, + 23138,23146,23194,23228,23230,23243,23234,23229,23267,23255,23270,23273, + 23254,23290,23291,23308,23307,23318,23346,23248,23338,23350,23358,23363, + 23365,23360,23377,23381,23386,23387,23397,23401,23408,23411,23413,23416, + 25992,23418,23424,23427,23462,23480,23491,23495,23497,23508,23504,23524, + 23526,23522,23518,23525,23531,23536,23542,23539,23557,23559,23560,23565, + 23571,23584,23586,23592,23608,23609,23617,23622,23630,23635,}, +{23632,23631,23409,23660,23662,20066,23670,23673,23692,23697,23700,22939, + 23723,23739,23734,23740,23735,23749,23742,23751,23769,23785,23805,23802, + 23789,23948,23786,23819,23829,23831,23900,23839,23835,23825,23828,23842, + 23834,23833,23832,23884,23890,23886,23883,23916,23923,23926,23943,23940, + 23938,23970,23965,23980,23982,23997,23952,23991,23996,24009,24013,24019, + 24018,24022,24027,24043,24050,24053,24075,24090,24089,24081,24091,24118, + 24119,24132,24131,24128,24142,24151,24148,24159,24162,24164,24135,24181, + 24182,24186,40636,24191,24224,24257,24258,24264,24272,24271,}, +{24278,24291,24285,24282,24283,24290,24289,24296,24297,24300,24305,24307, + 24304,24308,24312,24318,24323,24329,24413,24412,24331,24337,24342,24361, + 24365,24376,24385,24392,24396,24398,24367,24401,24406,24407,24409,24417, + 24429,24435,24439,24451,24450,24447,24458,24456,24465,24455,24478,24473, + 24472,24480,24488,24493,24508,24534,24571,24548,24568,24561,24541,24755, + 24575,24609,24672,24601,24592,24617,24590,24625,24603,24597,24619,24614, + 24591,24634,24666,24641,24682,24695,24671,24650,24646,24653,24675,24643, + 24676,24642,24684,24683,24665,24705,24717,24807,24707,24730,}, +{24708,24731,24726,24727,24722,24743,24715,24801,24760,24800,24787,24756, + 24560,24765,24774,24757,24792,24909,24853,24838,24822,24823,24832,24820, + 24826,24835,24865,24827,24817,24845,24846,24903,24894,24872,24871,24906, + 24895,24892,24876,24884,24893,24898,24900,24947,24951,24920,24921,24922, + 24939,24948,24943,24933,24945,24927,24925,24915,24949,24985,24982,24967, + 25004,24980,24986,24970,24977,25003,25006,25036,25034,25033,25079,25032, + 25027,25030,25018,25035,32633,25037,25062,25059,25078,25082,25076,25087, + 25085,25084,25086,25088,25096,25097,25101,25100,25108,25115,}, +{25118,25121,25130,25134,25136,25138,25139,25153,25166,25182,25187,25179, + 25184,25192,25212,25218,25225,25214,25234,25235,25238,25300,25219,25236, + 25303,25297,25275,25295,25343,25286,25812,25288,25308,25292,25290,25282, + 25287,25243,25289,25356,25326,25329,25383,25346,25352,25327,25333,25424, + 25406,25421,25628,25423,25494,25486,25472,25515,25462,25507,25487,25481, + 25503,25525,25451,25449,25534,25577,25536,25542,25571,25545,25554,25590, + 25540,25622,25652,25606,25619,25638,25654,25885,25623,25640,25615,25703, + 25711,25718,25678,25898,25749,25747,25765,25769,25736,25788,}, +{25818,25810,25797,25799,25787,25816,25794,25841,25831,33289,25824,25825, + 25260,25827,25839,25900,25846,25844,25842,25850,25856,25853,25880,25884, + 25861,25892,25891,25899,25908,25909,25911,25910,25912,30027,25928,25942, + 25941,25933,25944,25950,25949,25970,25976,25986,25987,35722,26011,26015, + 26027,26039,26051,26054,26049,26052,26060,26066,26075,26073,26080,26081, + 26097,26482,26122,26115,26107,26483,26165,26166,26164,26140,26191,26180, + 26185,26177,26206,26205,26212,26215,26216,26207,26210,26224,26243,26248, + 26254,26249,26244,26264,26269,26305,26297,26313,26302,26300,}, +{26308,26296,26326,26330,26336,26175,26342,26345,26352,26357,26359,26383, + 26390,26398,26406,26407,38712,26414,26431,26422,26433,26424,26423,26438, + 26462,26464,26457,26467,26468,26505,26480,26537,26492,26474,26508,26507, + 26534,26529,26501,26551,26607,26548,26604,26547,26601,26552,26596,26590, + 26589,26594,26606,26553,26574,26566,26599,27292,26654,26694,26665,26688, + 26701,26674,26702,26803,26667,26713,26723,26743,26751,26783,26767,26797, + 26772,26781,26779,26755,27310,26809,26740,26805,26784,26810,26895,26765, + 26750,26881,26826,26888,26840,26914,26918,26849,26892,26829,}, +{26836,26855,26837,26934,26898,26884,26839,26851,26917,26873,26848,26863, + 26920,26922,26906,26915,26913,26822,27001,26999,26972,27000,26987,26964, + 27006,26990,26937,26996,26941,26969,26928,26977,26974,26973,27009,26986, + 27058,27054,27088,27071,27073,27091,27070,27086,23528,27082,27101,27067, + 27075,27047,27182,27025,27040,27036,27029,27060,27102,27112,27138,27163, + 27135,27402,27129,27122,27111,27141,27057,27166,27117,27156,27115,27146, + 27154,27329,27171,27155,27204,27148,27250,27190,27256,27207,27234,27225, + 27238,27208,27192,27170,27280,27277,27296,27268,27298,27299,}, +{27287,34327,27323,27331,27330,27320,27315,27308,27358,27345,27359,27306, + 27354,27370,27387,27397,34326,27386,27410,27414,39729,27423,27448,27447, + 30428,27449,39150,27463,27459,27465,27472,27481,27476,27483,27487,27489, + 27512,27513,27519,27520,27524,27523,27533,27544,27541,27550,27556,27562, + 27563,27567,27570,27569,27571,27575,27580,27590,27595,27603,27615,27628, + 27627,27635,27631,40638,27656,27667,27668,27675,27684,27683,27742,27733, + 27746,27754,27778,27789,27802,27777,27803,27774,27752,27763,27794,27792, + 27844,27889,27859,27837,27863,27845,27869,27822,27825,27838,}, +{27834,27867,27887,27865,27882,27935,34893,27958,27947,27965,27960,27929, + 27957,27955,27922,27916,28003,28051,28004,27994,28025,27993,28046,28053, + 28644,28037,28153,28181,28170,28085,28103,28134,28088,28102,28140,28126, + 28108,28136,28114,28101,28154,28121,28132,28117,28138,28142,28205,28270, + 28206,28185,28274,28255,28222,28195,28267,28203,28278,28237,28191,28227, + 28218,28238,28196,28415,28189,28216,28290,28330,28312,28361,28343,28371, + 28349,28335,28356,28338,28372,28373,28303,28325,28354,28319,28481,28433, + 28748,28396,28408,28414,28479,28402,28465,28399,28466,28364,}, +{28478,28435,28407,28550,28538,28536,28545,28544,28527,28507,28659,28525, + 28546,28540,28504,28558,28561,28610,28518,28595,28579,28577,28580,28601, + 28614,28586,28639,28629,28652,28628,28632,28657,28654,28635,28681,28683, + 28666,28689,28673,28687,28670,28699,28698,28532,28701,28696,28703,28720, + 28734,28722,28753,28771,28825,28818,28847,28913,28844,28856,28851,28846, + 28895,28875,28893,28889,28937,28925,28956,28953,29029,29013,29064,29030, + 29026,29004,29014,29036,29071,29179,29060,29077,29096,29100,29143,29113, + 29118,29138,29129,29140,29134,29152,29164,29159,29173,29180,}, +{29177,29183,29197,29200,29211,29224,29229,29228,29232,29234,29243,29244, + 29247,29248,29254,29259,29272,29300,29310,29314,29313,29319,29330,29334, + 29346,29351,29369,29362,29379,29382,29380,29390,29394,29410,29408,29409, + 29433,29431,20495,29463,29450,29468,29462,29469,29492,29487,29481,29477, + 29502,29518,29519,40664,29527,29546,29544,29552,29560,29557,29563,29562, + 29640,29619,29646,29627,29632,29669,29678,29662,29858,29701,29807,29733, + 29688,29746,29754,29781,29759,29791,29785,29761,29788,29801,29808,29795, + 29802,29814,29822,29835,29854,29863,29898,29903,29908,29681,}, +{29920,29923,29927,29929,29934,29938,29936,29937,29944,29943,29956,29955, + 29957,29964,29966,29965,29973,29971,29982,29990,29996,30012,30020,30029, + 30026,30025,30043,30022,30042,30057,30052,30055,30059,30061,30072,30070, + 30086,30087,30068,30090,30089,30082,30100,30106,30109,30117,30115,30146, + 30131,30147,30133,30141,30136,30140,30129,30157,30154,30162,30169,30179, + 30174,30206,30207,30204,30209,30192,30202,30194,30195,30219,30221,30217, + 30239,30247,30240,30241,30242,30244,30260,30256,30267,30279,30280,30278, + 30300,30296,30305,30306,30312,30313,30314,30311,30316,30320,}, +{30322,30326,30328,30332,30336,30339,30344,30347,30350,30358,30355,30361, + 30362,30384,30388,30392,30393,30394,30402,30413,30422,30418,30430,30433, + 30437,30439,30442,34351,30459,30472,30471,30468,30505,30500,30494,30501, + 30502,30491,30519,30520,30535,30554,30568,30571,30555,30565,30591,30590, + 30585,30606,30603,30609,30624,30622,30640,30646,30649,30655,30652,30653, + 30651,30663,30669,30679,30682,30684,30691,30702,30716,30732,30738,31014, + 30752,31018,30789,30862,30836,30854,30844,30874,30860,30883,30901,30890, + 30895,30929,30918,30923,30932,30910,30908,30917,30922,30956,}, +{30951,30938,30973,30964,30983,30994,30993,31001,31020,31019,31040,31072, + 31063,31071,31066,31061,31059,31098,31103,31114,31133,31143,40779,31146, + 31150,31155,31161,31162,31177,31189,31207,31212,31201,31203,31240,31245, + 31256,31257,31264,31263,31104,31281,31291,31294,31287,31299,31319,31305, + 31329,31330,31337,40861,31344,31353,31357,31368,31383,31381,31384,31382, + 31401,31432,31408,31414,31429,31428,31423,36995,31431,31434,31437,31439, + 31445,31443,31449,31450,31453,31457,31458,31462,31469,31472,31490,31503, + 31498,31494,31539,31512,31513,31518,31541,31528,31542,31568,}, +{31610,31492,31565,31499,31564,31557,31605,31589,31604,31591,31600,31601, + 31596,31598,31645,31640,31647,31629,31644,31642,31627,31634,31631,31581, + 31641,31691,31681,31692,31695,31668,31686,31709,31721,31761,31764,31718, + 31717,31840,31744,31751,31763,31731,31735,31767,31757,31734,31779,31783, + 31786,31775,31799,31787,31805,31820,31811,31828,31823,31808,31824,31832, + 31839,31844,31830,31845,31852,31861,31875,31888,31908,31917,31906,31915, + 31905,31912,31923,31922,31921,31918,31929,31933,31936,31941,31938,31960, + 31954,31964,31970,39739,31983,31986,31988,31990,31994,32006,}, +{32002,32028,32021,32010,32069,32075,32046,32050,32063,32053,32070,32115, + 32086,32078,32114,32104,32110,32079,32099,32147,32137,32091,32143,32125, + 32155,32186,32174,32163,32181,32199,32189,32171,32317,32162,32175,32220, + 32184,32159,32176,32216,32221,32228,32222,32251,32242,32225,32261,32266, + 32291,32289,32274,32305,32287,32265,32267,32290,32326,32358,32315,32309, + 32313,32323,32311,32306,32314,32359,32349,32342,32350,32345,32346,32377, + 32362,32361,32380,32379,32387,32213,32381,36782,32383,32392,32393,32396, + 32402,32400,32403,32404,32406,32398,32411,32412,32568,32570,}, +{32581,32588,32589,32590,32592,32593,32597,32596,32600,32607,32608,32616, + 32617,32615,32632,32642,32646,32643,32648,32647,32652,32660,32670,32669, + 32666,32675,32687,32690,32697,32686,32694,32696,35697,32709,32710,32714, + 32725,32724,32737,32742,32745,32755,32761,39132,32774,32772,32779,32786, + 32792,32793,32796,32801,32808,32831,32827,32842,32838,32850,32856,32858, + 32863,32866,32872,32883,32882,32880,32886,32889,32893,32895,32900,32902, + 32901,32923,32915,32922,32941,20880,32940,32987,32997,32985,32989,32964, + 32986,32982,33033,33007,33009,33051,33065,33059,33071,33099,}, +{38539,33094,33086,33107,33105,33020,33137,33134,33125,33126,33140,33155, + 33160,33162,33152,33154,33184,33173,33188,33187,33119,33171,33193,33200, + 33205,33214,33208,33213,33216,33218,33210,33225,33229,33233,33241,33240, + 33224,33242,33247,33248,33255,33274,33275,33278,33281,33282,33285,33287, + 33290,33293,33296,33302,33321,33323,33336,33331,33344,33369,33368,33373, + 33370,33375,33380,33378,33384,33386,33387,33326,33393,33399,33400,33406, + 33421,33426,33451,33439,33467,33452,33505,33507,33503,33490,33524,33523, + 33530,33683,33539,33531,33529,33502,33542,33500,33545,33497,}, +{33589,33588,33558,33586,33585,33600,33593,33616,33605,33583,33579,33559, + 33560,33669,33690,33706,33695,33698,33686,33571,33678,33671,33674,33660, + 33717,33651,33653,33696,33673,33704,33780,33811,33771,33742,33789,33795, + 33752,33803,33729,33783,33799,33760,33778,33805,33826,33824,33725,33848, + 34054,33787,33901,33834,33852,34138,33924,33911,33899,33965,33902,33922, + 33897,33862,33836,33903,33913,33845,33994,33890,33977,33983,33951,34009, + 33997,33979,34010,34000,33985,33990,34006,33953,34081,34047,34036,34071, + 34072,34092,34079,34069,34068,34044,34112,34147,34136,34120,}, +{34113,34306,34123,34133,34176,34212,34184,34193,34186,34216,34157,34196, + 34203,34282,34183,34204,34167,34174,34192,34249,34234,34255,34233,34256, + 34261,34269,34277,34268,34297,34314,34323,34315,34302,34298,34310,34338, + 34330,34352,34367,34381,20053,34388,34399,34407,34417,34451,34467,34473, + 34474,34443,34444,34486,34479,34500,34502,34480,34505,34851,34475,34516, + 34526,34537,34540,34527,34523,34543,34578,34566,34568,34560,34563,34555, + 34577,34569,34573,34553,34570,34612,34623,34615,34619,34597,34601,34586, + 34656,34655,34680,34636,34638,34676,34647,34664,34670,34649,}, +{34643,34659,34666,34821,34722,34719,34690,34735,34763,34749,34752,34768, + 38614,34731,34756,34739,34759,34758,34747,34799,34802,34784,34831,34829, + 34814,34806,34807,34830,34770,34833,34838,34837,34850,34849,34865,34870, + 34873,34855,34875,34884,34882,34898,34905,34910,34914,34923,34945,34942, + 34974,34933,34941,34997,34930,34946,34967,34962,34990,34969,34978,34957, + 34980,34992,35007,34993,35011,35012,35028,35032,35033,35037,35065,35074, + 35068,35060,35048,35058,35076,35084,35082,35091,35139,35102,35109,35114, + 35115,35137,35140,35131,35126,35128,35148,35101,35168,35166,}, +{35174,35172,35181,35178,35183,35188,35191,35198,35203,35208,35210,35219, + 35224,35233,35241,35238,35244,35247,35250,35258,35261,35263,35264,35290, + 35292,35293,35303,35316,35320,35331,35350,35344,35340,35355,35357,35365, + 35382,35393,35419,35410,35398,35400,35452,35437,35436,35426,35461,35458, + 35460,35496,35489,35473,35493,35494,35482,35491,35524,35533,35522,35546, + 35563,35571,35559,35556,35569,35604,35552,35554,35575,35550,35547,35596, + 35591,35610,35553,35606,35600,35607,35616,35635,38827,35622,35627,35646, + 35624,35649,35660,35663,35662,35657,35670,35675,35674,35691,}, +{35679,35692,35695,35700,35709,35712,35724,35726,35730,35731,35734,35737, + 35738,35898,35905,35903,35912,35916,35918,35920,35925,35938,35948,35960, + 35962,35970,35977,35973,35978,35981,35982,35988,35964,35992,25117,36013, + 36010,36029,36018,36019,36014,36022,36040,36033,36068,36067,36058,36093, + 36090,36091,36100,36101,36106,36103,36111,36109,36112,40782,36115,36045, + 36116,36118,36199,36205,36209,36211,36225,36249,36290,36286,36282,36303, + 36314,36310,36300,36315,36299,36330,36331,36319,36323,36348,36360,36361, + 36351,36381,36382,36368,36383,36418,36405,36400,36404,36426,}, +{36423,36425,36428,36432,36424,36441,36452,36448,36394,36451,36437,36470, + 36466,36476,36481,36487,36485,36484,36491,36490,36499,36497,36500,36505, + 36522,36513,36524,36528,36550,36529,36542,36549,36552,36555,36571,36579, + 36604,36603,36587,36606,36618,36613,36629,36626,36633,36627,36636,36639, + 36635,36620,36646,36659,36667,36665,36677,36674,36670,36684,36681,36678, + 36686,36695,36700,36706,36707,36708,36764,36767,36771,36781,36783,36791, + 36826,36837,36834,36842,36847,36999,36852,36869,36857,36858,36881,36885, + 36897,36877,36894,36886,36875,36903,36918,36917,36921,36856,}, +{36943,36944,36945,36946,36878,36937,36926,36950,36952,36958,36968,36975, + 36982,38568,36978,36994,36989,36993,36992,37002,37001,37007,37032,37039, + 37041,37045,37090,37092,25160,37083,37122,37138,37145,37170,37168,37194, + 37206,37208,37219,37221,37225,37235,37234,37259,37257,37250,37282,37291, + 37295,37290,37301,37300,37306,37312,37313,37321,37323,37328,37334,37343, + 37345,37339,37372,37365,37366,37406,37375,37396,37420,37397,37393,37470, + 37463,37445,37449,37476,37448,37525,37439,37451,37456,37532,37526,37523, + 37531,37466,37583,37561,37559,37609,37647,37626,37700,37678,}, +{37657,37666,37658,37667,37690,37685,37691,37724,37728,37756,37742,37718, + 37808,37804,37805,37780,37817,37846,37847,37864,37861,37848,37827,37853, + 37840,37832,37860,37914,37908,37907,37891,37895,37904,37942,37931,37941, + 37921,37946,37953,37970,37956,37979,37984,37986,37982,37994,37417,38000, + 38005,38007,38013,37978,38012,38014,38017,38015,38274,38279,38282,38292, + 38294,38296,38297,38304,38312,38311,38317,38332,38331,38329,38334,38346, + 28662,38339,38349,38348,38357,38356,38358,38364,38369,38373,38370,38433, + 38440,38446,38447,38466,38476,38479,38475,38519,38492,38494,}, +{38493,38495,38502,38514,38508,38541,38552,38549,38551,38570,38567,38577, + 38578,38576,38580,38582,38584,38585,38606,38603,38601,38605,35149,38620, + 38669,38613,38649,38660,38662,38664,38675,38670,38673,38671,38678,38681, + 38692,38698,38704,38713,38717,38718,38724,38726,38728,38722,38729,38748, + 38752,38756,38758,38760,21202,38763,38769,38777,38789,38780,38785,38778, + 38790,38795,38799,38800,38812,38824,38822,38819,38835,38836,38851,38854, + 38856,38859,38876,38893,40783,38898,31455,38902,38901,38927,38924,38968, + 38948,38945,38967,38973,38982,38991,38987,39019,39023,39024,}, +{39025,39028,39027,39082,39087,39089,39094,39108,39107,39110,39145,39147, + 39171,39177,39186,39188,39192,39201,39197,39198,39204,39200,39212,39214, + 39229,39230,39234,39241,39237,39248,39243,39249,39250,39244,39253,39319, + 39320,39333,39341,39342,39356,39391,39387,39389,39384,39377,39405,39406, + 39409,39410,39419,39416,39425,39439,39429,39394,39449,39467,39479,39493, + 39490,39488,39491,39486,39509,39501,39515,39511,39519,39522,39525,39524, + 39529,39531,39530,39597,39600,39612,39616,39631,39633,39635,39636,39646, + 39647,39650,39651,39654,39663,39659,39662,39668,39665,39671,}, +{39675,39686,39704,39706,39711,39714,39715,39717,39719,39720,39721,39722, + 39726,39727,39730,39748,39747,39759,39757,39758,39761,39768,39796,39827, + 39811,39825,39830,39831,39839,39840,39848,39860,39872,39882,39865,39878, + 39887,39889,39890,39907,39906,39908,39892,39905,39994,39922,39921,39920, + 39957,39956,39945,39955,39948,39942,39944,39954,39946,39940,39982,39963, + 39973,39972,39969,39984,40007,39986,40006,39998,40026,40032,40039,40054, + 40056,40167,40172,40176,40201,40200,40171,40195,40198,40234,40230,40367, + 40227,40223,40260,40213,40210,40257,40255,40254,40262,40264,}, +{40285,40286,40292,40273,40272,40281,40306,40329,40327,40363,40303,40314, + 40346,40356,40361,40370,40388,40385,40379,40376,40378,40390,40399,40386, + 40409,40403,40440,40422,40429,40431,40445,40474,40475,40478,40565,40569, + 40573,40577,40584,40587,40588,40594,40597,40593,40605,40613,40617,40632, + 40618,40621,38753,40652,40654,40655,40656,40660,40668,40670,40669,40672, + 40677,40680,40687,40692,40694,40695,40697,40699,40700,40701,40711,40712, + 30391,40725,40737,40748,40766,40778,40786,40788,40803,40799,40800,40801, + 40806,40807,40812,40810,40823,40818,40822,40853,40860,40864,}, +{22575,27079,36953,29796,20956,29081,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,}, +{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,}, +{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,}, +{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,}, +{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,}, +{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,}, +{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,}, +{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,}, +{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,}, +{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,}, +{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,}, +}; + + +// ------------------------------------------------------------ +unsigned short JISConverter::sjisToUnicode(unsigned short sjis) +{ + unsigned short u; + unsigned int c = sjis>>8; + unsigned int c1 = sjis&0xff; + + c = c + c - ((c <= 0x9f) ? SJ0162 : SJ6394); + if(c1 < 0x9f) + { + c1 = c1 - ((c1 > 0x7f) ? 0x20 : 0x1f); + } + else + { + c1 = c1 - 0x7e; c++; + } + c -= 33; + c1 -= 33; + if(c < 0 || c1 < 0 || c > 93 || c1 > 93) + u = 0x3013; + else + { + u = uniTable[c][c1]; + if(!u) + u = 0x3013; + } + + return u; +} +// ------------------------------------------------------------ +unsigned short JISConverter::eucToUnicode(unsigned short euc) +{ + unsigned short u; + unsigned int c = euc>>8; + unsigned int c1 = euc&0xff; + + c &= 0x7f; + c -= 33; + c1 &= 0x7f; + c1 -= 33; + if(c < 0 || c1 < 0 || c > 93 || c1 > 93) + u = 0x3013; + else + { + u = uniTable[c][c1]; + if(!u) + u = 0x3013; + } + return u; +} diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/jis.h b/c:/Git/PeerCast.root/PeerCast/core/common/jis.h new file mode 100644 index 0000000..da4df03 --- /dev/null +++ b/c:/Git/PeerCast.root/PeerCast/core/common/jis.h @@ -0,0 +1,35 @@ +// ------------------------------------------------ +// File : jis.h +// Date: 1-april-2004 +// Author: giles +// +// (c) 2002-4 peercast.org +// ------------------------------------------------ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// ------------------------------------------------ + +#ifndef _JIS_H +#define _JIS_H + +// ---------------------------------- +class JISConverter +{ +public: + + static unsigned short sjisToUnicode(unsigned short); + static unsigned short eucToUnicode(unsigned short); +}; + + + +#endif + + diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/mms.cpp b/c:/Git/PeerCast.root/PeerCast/core/common/mms.cpp new file mode 100644 index 0000000..2ddafbc --- /dev/null +++ b/c:/Git/PeerCast.root/PeerCast/core/common/mms.cpp @@ -0,0 +1,194 @@ +// ------------------------------------------------ +// File : mms.cpp +// Date: 28-may-2003 +// Author: giles +// +// (c) 2002-3 peercast.org +// ------------------------------------------------ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// ------------------------------------------------ + +#include "channel.h" +#include "mms.h" +#include "asf.h" +#ifdef _DEBUG +#include "chkMemoryLeak.h" +#define DEBUG_NEW new(__FILE__, __LINE__) +#define new DEBUG_NEW +#endif + +// ------------------------------------------ +ASFInfo parseASFHeader(Stream &in); + + +// ------------------------------------------ +void MMSStream::readEnd(Stream &,Channel *) +{ +} + +// ------------------------------------------ +void MMSStream::readHeader(Stream &,Channel *) +{ +} +// ------------------------------------------ +int MMSStream::readPacket(Stream &in,Channel *ch) +{ + { + ASFChunk chunk; + + chunk.read(in); + + switch (chunk.type) + { + case 0x4824: // asf header + { + MemoryStream mem(ch->headPack.data,sizeof(ch->headPack.data)); + + chunk.write(mem); + + + + + MemoryStream asfm(chunk.data,chunk.dataLen); + ASFObject asfHead; + asfHead.readHead(asfm); + + ASFInfo asf = parseASFHeader(asfm); + LOG_DEBUG("ASF Info: pnum=%d, psize=%d, br=%d",asf.numPackets,asf.packetSize,asf.bitrate); + for(int i=0; iid) + LOG_DEBUG("ASF Stream %d : %s, br=%d",s->id,s->getTypeName(),s->bitrate); + } + + ch->info.bitrate = asf.bitrate/1000; + + ch->headPack.type = ChanPacket::T_HEAD; + ch->headPack.len = mem.pos; + ch->headPack.pos = ch->streamPos; + ch->newPacket(ch->headPack); + + ch->streamPos += ch->headPack.len; + + break; + } + case 0x4424: // asf data + { + + ChanPacket pack; + + MemoryStream mem(pack.data,sizeof(pack.data)); + + chunk.write(mem); + + pack.type = ChanPacket::T_DATA; + pack.len = mem.pos; + pack.pos = ch->streamPos; + + ch->newPacket(pack); + ch->streamPos += pack.len; + + break; + } + default: + throw StreamException("Unknown ASF chunk"); + + } + + } + return 0; +} + + +// ----------------------------------- +ASFInfo parseASFHeader(Stream &in) +{ + ASFInfo asf; + + try + { + int numHeaders = in.readLong(); + + in.readChar(); + in.readChar(); + + LOG_CHANNEL("ASF Headers: %d",numHeaders); + for(int i=0; iicyMetaInterval) + { + + int rlen = ch->icyMetaInterval; + + while (rlen) + { + int rl = rlen; + if (rl > ChanMgr::MAX_METAINT) + rl = ChanMgr::MAX_METAINT; + + pack.init(ChanPacket::T_DATA,pack.data,rl,ch->streamPos); + in.read(pack.data,pack.len); + ch->newPacket(pack); + ch->checkReadDelay(pack.len); + ch->streamPos+=pack.len; + + rlen-=rl; + } + + unsigned char len; + in.read(&len,1); + if (len) + { + if (len*16 > 1024) len = 1024/16; + char buf[1024]; + in.read(buf,len*16); + ch->processMp3Metadata(buf); + } + + }else{ + + pack.init(ChanPacket::T_DATA,pack.data,ChanMgr::MAX_METAINT,ch->streamPos); + in.read(pack.data,pack.len); + ch->newPacket(pack); + ch->checkReadDelay(pack.len); + + ch->streamPos += pack.len; + } + return 0; +} diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/mp3.h b/c:/Git/PeerCast.root/PeerCast/core/common/mp3.h new file mode 100644 index 0000000..2297d10 --- /dev/null +++ b/c:/Git/PeerCast.root/PeerCast/core/common/mp3.h @@ -0,0 +1,35 @@ +// ------------------------------------------------ +// File : mp3.h +// Date: 28-may-2003 +// Author: giles +// +// (c) 2002-3 peercast.org +// ------------------------------------------------ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// ------------------------------------------------ + +#ifndef _MP3_H +#define _MP3_H + + +#include "channel.h" + +// ---------------------------------------------- +class MP3Stream : public ChannelStream +{ +public: + virtual void readHeader(Stream &,Channel *); + virtual int readPacket(Stream &,Channel *); + virtual void readEnd(Stream &,Channel *); +}; + + +#endif diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/nsv.cpp b/c:/Git/PeerCast.root/PeerCast/core/common/nsv.cpp new file mode 100644 index 0000000..55cdb98 --- /dev/null +++ b/c:/Git/PeerCast.root/PeerCast/core/common/nsv.cpp @@ -0,0 +1,80 @@ +// ------------------------------------------------ +// File : nsv.cpp +// Date: 28-may-2003 +// Author: giles +// +// (c) 2002-3 peercast.org +// ------------------------------------------------ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// ------------------------------------------------ + +#include "nsv.h" +#ifdef _DEBUG +#include "chkMemoryLeak.h" +#define DEBUG_NEW new(__FILE__, __LINE__) +#define new DEBUG_NEW +#endif + +// ------------------------------------------ +void NSVStream::readEnd(Stream &,Channel *) +{ +} + +// ------------------------------------------ +void NSVStream::readHeader(Stream &,Channel *) +{ +} +// ------------------------------------------ +int NSVStream::readPacket(Stream &in,Channel *ch) +{ + ChanPacket pack; + + if (ch->icyMetaInterval) + { + + int rlen = ch->icyMetaInterval; + + while (rlen) + { + int rl = rlen; + if (rl > ChanMgr::MAX_METAINT) + rl = ChanMgr::MAX_METAINT; + + pack.init(ChanPacket::T_DATA,pack.data,rl,ch->streamPos); + in.read(pack.data,pack.len); + ch->newPacket(pack); + ch->checkReadDelay(pack.len); + ch->streamPos+=pack.len; + + rlen-=rl; + } + + unsigned char len; + in.read(&len,1); + if (len) + { + if (len*16 > 1024) len = 1024/16; + char buf[1024]; + in.read(buf,len*16); + ch->processMp3Metadata(buf); + } + + }else{ + + pack.init(ChanPacket::T_DATA,pack.data,ChanMgr::MAX_METAINT,ch->streamPos); + in.read(pack.data,pack.len); + ch->newPacket(pack); + ch->checkReadDelay(pack.len); + + ch->streamPos += pack.len; + } + return 0; +} diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/nsv.h b/c:/Git/PeerCast.root/PeerCast/core/common/nsv.h new file mode 100644 index 0000000..cca0106 --- /dev/null +++ b/c:/Git/PeerCast.root/PeerCast/core/common/nsv.h @@ -0,0 +1,35 @@ +// ------------------------------------------------ +// File : nsv.h +// Date: 28-may-2003 +// Author: giles +// +// (c) 2002-3 peercast.org +// ------------------------------------------------ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// ------------------------------------------------ + +#ifndef _NSV_H +#define _NSV_H + + +#include "channel.h" + +// ---------------------------------------------- +class NSVStream : public ChannelStream +{ +public: + virtual void readHeader(Stream &,Channel *); + virtual int readPacket(Stream &,Channel *); + virtual void readEnd(Stream &,Channel *); +}; + + +#endif diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/ogg.cpp b/c:/Git/PeerCast.root/PeerCast/core/common/ogg.cpp new file mode 100644 index 0000000..ed38bc7 --- /dev/null +++ b/c:/Git/PeerCast.root/PeerCast/core/common/ogg.cpp @@ -0,0 +1,494 @@ +// ------------------------------------------------ +// File : mp3.cpp +// Date: 28-may-2003 +// Author: giles +// +// (c) 2002-3 peercast.org +// ------------------------------------------------ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// ------------------------------------------------ + +#include "channel.h" +#include "ogg.h" +#ifdef _DEBUG +#include "chkMemoryLeak.h" +#define DEBUG_NEW new(__FILE__, __LINE__) +#define new DEBUG_NEW +#endif + + +static int test=0; +// ------------------------------------------ +void OGGStream::readHeader(Stream &,Channel *) +{ + test = 0; +} + +// ------------------------------------------ +void OGGStream::readEnd(Stream &,Channel *) +{ +} + +// ------------------------------------------ +int OGGStream::readPacket(Stream &in,Channel *ch) +{ + OggPage ogg; + ChanPacket pack; + + ogg.read(in); + + if (ogg.isBOS()) + { + if (!vorbis.needHeader() && !theora.needHeader()) + { + ch->headPack.len = 0; + } + + if (ogg.detectVorbis()) + vorbis.bos(ogg.getSerialNo()); + if (ogg.detectTheora()) + theora.bos(ogg.getSerialNo()); + } + + if (ogg.isEOS()) + { + + if (ogg.getSerialNo() == vorbis.serialNo) + { + LOG_CHANNEL("Vorbis stream: EOS"); + vorbis.eos(); + } + if (ogg.getSerialNo() == theora.serialNo) + { + LOG_CHANNEL("Theora stream: EOS"); + theora.eos(); + } + } + + if (vorbis.needHeader() || theora.needHeader()) + { + + if (ogg.getSerialNo() == vorbis.serialNo) + vorbis.readHeader(ch,ogg); + else if (ogg.getSerialNo() == theora.serialNo) + theora.readHeader(ch,ogg); + else + throw StreamException("Bad OGG serial no."); + + + if (!vorbis.needHeader() && !theora.needHeader()) + { + + ch->info.bitrate = 0; + + if (vorbis.isActive()) + ch->info.bitrate += vorbis.bitrate; + + if (theora.isActive()) + { + ch->info.bitrate += theora.bitrate; + ch->info.contentType = ChanInfo::T_OGM; + } + + + ch->headPack.type = ChanPacket::T_HEAD; + ch->headPack.pos = ch->streamPos; + + ch->startTime = sys->getDTime(); + + ch->streamPos += ch->headPack.len; + + ch->newPacket(ch->headPack); + LOG_CHANNEL("Got %d bytes of headers",ch->headPack.len); + } + + }else + { + + + pack.init(ChanPacket::T_DATA,ogg.data,ogg.headLen+ogg.bodyLen,ch->streamPos); + ch->newPacket(pack); + + ch->streamPos+=pack.len; + + if (theora.isActive()) + { + if (ogg.getSerialNo() == theora.serialNo) + { + ch->sleepUntil(theora.getTime(ogg)); + } + }else if (vorbis.isActive()) + { + if (ogg.getSerialNo() == vorbis.serialNo) + { + ch->sleepUntil(vorbis.getTime(ogg)); + } + } + + } + return 0; +} + +// ----------------------------------- +void OggSubStream::readHeader(Channel *ch,OggPage &ogg) +{ + if ((pack.bodyLen + ogg.bodyLen) >= OggPacket::MAX_BODYLEN) + throw StreamException("OGG packet too big"); + + if (ch->headPack.len+(ogg.bodyLen+ogg.headLen) >= ChanMeta::MAX_DATALEN) + throw StreamException("OGG packet too big for headMeta"); + +// copy complete packet into head packet + memcpy(&ch->headPack.data[ch->headPack.len],ogg.data,ogg.headLen+ogg.bodyLen); + ch->headPack.len += ogg.headLen+ogg.bodyLen; + + // add body to packet + memcpy(&pack.body[pack.bodyLen],&ogg.data[ogg.headLen],ogg.bodyLen); + pack.bodyLen += ogg.bodyLen; + + pack.addLacing(ogg); + + if (pack.numPackets >= maxHeaders) + procHeaders(ch); + +} +// ----------------------------------- +void OggVorbisSubStream::procHeaders(Channel *ch) +{ + unsigned int packPtr=0; + + for(int i=0; iinfo); + break; + case 3: // comment + { + LOG_CHANNEL("OGG Vorbis Header: Comment (%d bytes)",vin.len); + ChanInfo newInfo = ch->info; + readComment(vin,newInfo); + ch->updateInfo(newInfo); + } + break; + case 5: // setup + LOG_CHANNEL("OGG Vorbis Header: Setup (%d bytes)",vin.len); + //readSetup(vin); + break; + default: + throw StreamException("Unknown Vorbis packet header type"); + break; + } + } + +} +// ----------------------------------- +double OggTheoraSubStream::getTime(OggPage &ogg) +{ + int64_t iframe=ogg.granPos>>granposShift; + int64_t pframe=ogg.granPos-(iframe<info); + break; + default: + LOG_CHANNEL("OGG Theora Header: Unknown %d (%d bytes)",id[0] & 0xff,vin.len); + break; + } + + + + } + +} + +// ----------------------------------- +double OggVorbisSubStream::getTime(OggPage &ogg) +{ + return (double)ogg.granPos / (double)samplerate; + +} + +// ----------------------------------- +void OggVorbisSubStream::readIdent(Stream &in, ChanInfo &info) +{ + int ver = in.readLong(); + int chans = in.readChar(); + samplerate = in.readLong(); + int brMax = in.readLong(); + int brNom = in.readLong(); + int brLow = in.readLong(); + + + in.readChar(); // skip blocksize 0+1 + + LOG_CHANNEL("OGG Vorbis Ident: ver=%d, chans=%d, rate=%d, brMax=%d, brNom=%d, brLow=%d", + ver,chans,samplerate,brMax,brNom,brLow); + + + bitrate = brNom/1000; + + char frame = in.readChar(); // framing bit + if (!frame) + throw StreamException("Bad Indent frame"); + +} + + +// ----------------------------------- +void OggVorbisSubStream::readSetup(Stream &in) +{ + // skip everything in packet + int cnt=0; + while (!in.eof()) + { + cnt++; + in.readChar(); + } + + LOG_CHANNEL("Read %d bytes of Vorbis Setup",cnt); +} +// ----------------------------------- +void OggVorbisSubStream::readComment(Stream &in, ChanInfo &info) +{ + int vLen = in.readLong(); // vendor len + + in.skip(vLen); + + char argBuf[8192]; + + info.track.clear(); + + int cLen = in.readLong(); // comment len + for(int i=0; i sizeof(argBuf)) + throw StreamException("Comment string too long"); + in.read(argBuf,l); + argBuf[l] = 0; + LOG_CHANNEL("OGG Comment: %s",argBuf); + + char *arg; + if ((arg=stristr(argBuf,"ARTIST="))) + { + info.track.artist.set(arg+7,String::T_ASCII); + info.track.artist.convertTo(String::T_UNICODE); + + }else if ((arg=stristr(argBuf,"TITLE="))) + { + info.track.title.set(arg+6,String::T_ASCII); + info.track.title.convertTo(String::T_UNICODE); + + }else if ((arg=stristr(argBuf,"GENRE="))) + { + info.track.genre.set(arg+6,String::T_ASCII); + info.track.genre.convertTo(String::T_UNICODE); + + }else if ((arg=stristr(argBuf,"CONTACT="))) + { + info.track.contact.set(arg+8,String::T_ASCII); + info.track.contact.convertTo(String::T_UNICODE); + + }else if ((arg=stristr(argBuf,"ALBUM="))) + { + info.track.album.set(arg+6,String::T_ASCII); + info.track.album.convertTo(String::T_UNICODE); + } + } + + char frame = in.readChar(); // framing bit + if (!frame) + throw StreamException("Bad Comment frame"); + +// updateMeta(); + +} + +// ----------------------------------- +bool OggPage::isBOS() +{ + return (data[5] & 0x02) != 0; +} +// ----------------------------------- +bool OggPage::isEOS() +{ + return (data[5] & 0x04) != 0; +} +// ----------------------------------- +bool OggPage::isNewPacket() +{ + return (data[5] & 0x01) == 0; +} +// ----------------------------------- +bool OggPage::isHeader() +{ + return ((*(unsigned int *)&data[6]) || (*(unsigned int *)&data[10])) == 0; +} +// ----------------------------------- +unsigned int OggPage::getSerialNo() +{ + return *(unsigned int *)&data[14]; +} + +// ----------------------------------- +void OggPage::read(Stream &in) +{ + // skip until we get OGG capture pattern + bool gotOgg=false; + while (!gotOgg) + { + if (in.readChar() == 'O') + if (in.readChar() == 'g') + if (in.readChar() == 'g') + if (in.readChar() == 'S') + gotOgg = true; + if (!gotOgg) + LOG_CHANNEL("Skipping OGG packet"); + } + + + + memcpy(&data[0],"OggS",4); + + in.read(&data[4],27-4); + + int numSegs = data[26]; + bodyLen = 0; + + // read segment table + in.read(&data[27],numSegs); + for(int i=0; i= MAX_BODYLEN) + throw StreamException("OGG body too big"); + + headLen = 27+numSegs; + + if (headLen > MAX_HEADERLEN) + throw StreamException("OGG header too big"); + + in.read(&data[headLen],bodyLen); + + granPos = *(unsigned int *)&data[10]; + granPos <<= 32; + granPos |= *(unsigned int *)&data[6]; + + + #if 0 + LOG_DEBUG("OGG Packet - page %d, id = %x - %s %s %s - %d:%d - %d segs, %d bytes", + *(unsigned int *)&data[18], + *(unsigned int *)&data[14], + data[5]&0x1?"cont":"new", + data[5]&0x2?"bos":"", + data[5]&0x4?"eos":"", + (unsigned int)(granPos>>32), + (unsigned int)(granPos&0xffffffff), + numSegs, + headLen+bodyLen); + + #endif + +} +// ----------------------------------- +bool OggPage::detectVorbis() +{ + return memcmp(&data[headLen+1],"vorbis",6) == 0; +} +// ----------------------------------- +bool OggPage::detectTheora() +{ + return memcmp(&data[headLen+1],"theora",6) == 0; +} + +// ----------------------------------- +void OggPacket::addLacing(OggPage &ogg) +{ + + int numSegs = ogg.data[26]; + for(int i=0; i= MAX_PACKETS) + throw StreamException("Too many OGG packets"); + packetSizes[numPackets]=0; + } + } + +} diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/ogg.h b/c:/Git/PeerCast.root/PeerCast/core/common/ogg.h new file mode 100644 index 0000000..67a228c --- /dev/null +++ b/c:/Git/PeerCast.root/PeerCast/core/common/ogg.h @@ -0,0 +1,169 @@ +// ------------------------------------------------ +// File : ogg.h +// Date: 28-may-2003 +// Author: giles +// +// (c) 2002-3 peercast.org +// ------------------------------------------------ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// ------------------------------------------------ + +#ifndef _OGG_H +#define _OGG_H + + +#include "channel.h" +// ---------------------------------------------- +class OggPage; + +// ---------------------------------- +class OggPacket +{ +public: + enum + { + MAX_BODYLEN = 65536, // probably too small + MAX_PACKETS = 256 // prolly too small too, but realloc?!?!?! + }; + + void addLacing(OggPage &); + + int bodyLen; + unsigned char body[MAX_BODYLEN]; + + + int numPackets; + unsigned int packetSizes[MAX_PACKETS]; +}; + +// ---------------------------------------------- +class OggSubStream +{ +public: + OggSubStream() + :maxHeaders(0),serialNo(0),bitrate(0) + {} + + bool needHeader() + { + return maxHeaders && (pack.numPackets < maxHeaders); + } + + void eos() + { + maxHeaders=0; + serialNo=0; + } + + void bos(unsigned int ser) + { + maxHeaders = 3; + pack.numPackets=0; + pack.packetSizes[0]=0; + pack.bodyLen = 0; + serialNo = ser; + bitrate = 0; + } + + bool isActive() {return serialNo!=0;} + + void readHeader(Channel *,OggPage &); + + virtual void procHeaders(Channel *) = 0; + + int bitrate; + + OggPacket pack; + int maxHeaders; + unsigned int serialNo; +}; +// ---------------------------------------------- +class OggVorbisSubStream : public OggSubStream +{ +public: + OggVorbisSubStream() + :samplerate(0) + {} + + virtual void procHeaders(Channel *); + + void readIdent(Stream &, ChanInfo &); + void readSetup(Stream &); + void readComment(Stream &, ChanInfo &); + + double getTime(OggPage &); + + int samplerate; + +}; +// ---------------------------------------------- +class OggTheoraSubStream : public OggSubStream +{ +public: + OggTheoraSubStream() : granposShift(0), frameTime(0) {} + + virtual void procHeaders(Channel *); + + void readInfo(Stream &, ChanInfo &); + + double getTime(OggPage &); + + int granposShift; + double frameTime; +}; + +// ---------------------------------------------- +class OGGStream : public ChannelStream +{ +public: + OGGStream() + {} + + + virtual void readHeader(Stream &,Channel *); + virtual int readPacket(Stream &,Channel *); + virtual void readEnd(Stream &,Channel *); + + + void readHeaders(Stream &,Channel *, OggPage &); + + OggVorbisSubStream vorbis; + OggTheoraSubStream theora; +}; + +// ---------------------------------- +class OggPage +{ +public: + enum + { + MAX_BODYLEN = 65536, + MAX_HEADERLEN = 27+256 + }; + + void read(Stream &); + bool isBOS(); + bool isEOS(); + bool isNewPacket(); + bool isHeader(); + unsigned int getSerialNo(); + + bool detectVorbis(); + bool detectTheora(); + + + int64_t granPos; + int headLen,bodyLen; + unsigned char data[MAX_HEADERLEN+MAX_BODYLEN]; +}; + + +#endif diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/pcp.cpp b/c:/Git/PeerCast.root/PeerCast/core/common/pcp.cpp new file mode 100644 index 0000000..37514ed --- /dev/null +++ b/c:/Git/PeerCast.root/PeerCast/core/common/pcp.cpp @@ -0,0 +1,886 @@ +// ------------------------------------------------ +// File : pcp.cpp +// Date: 1-mar-2004 +// Author: giles +// +// (c) 2002-4 peercast.org +// ------------------------------------------------ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// ------------------------------------------------ + +#include "atom.h" +#include "pcp.h" +#include "peercast.h" +#include "version2.h" +#ifdef _DEBUG +#include "chkMemoryLeak.h" +#define DEBUG_NEW new(__FILE__, __LINE__) +#define new DEBUG_NEW +#endif + +// ------------------------------------------ +void PCPStream::init(GnuID &rid) +{ + remoteID = rid; + routeList.clear(); + + lastPacketTime = 0; + nextRootPacket = 0; // 0 seconds (never) + + inData.init(); + inData.accept = ChanPacket::T_PCP; + + outData.init(); + outData.accept = ChanPacket::T_PCP; +} +// ------------------------------------------ +void PCPStream::readVersion(Stream &in) +{ + int len = in.readInt(); + + if (len != 4) + throw StreamException("Invalid PCP"); + + int ver = in.readInt(); + + LOG_DEBUG("PCP ver: %d",ver); +} +// ------------------------------------------ +void PCPStream::readHeader(Stream &in,Channel *) +{ +// AtomStream atom(in); + +// if (in.readInt() != PCP_CONNECT) +// throw StreamException("Not PCP"); + +// readVersion(in); +} +// ------------------------------------------ +bool PCPStream::sendPacket(ChanPacket &pack,GnuID &destID) +{ + if (destID.isSet()) + if (!destID.isSame(remoteID)) + if (!routeList.contains(destID)) + return false; + + return outData.writePacket(pack); +} +// ------------------------------------------ +void PCPStream::flush(Stream &in) +{ + ChanPacket pack; + // send outward packets + while (outData.numPending()) + { + outData.readPacket(pack); + pack.writeRaw(in); + } +} +// ------------------------------------------ +int PCPStream::readPacket(Stream &in,Channel *) +{ + BroadcastState bcs; + return readPacket(in,bcs); +} +// ------------------------------------------ +int PCPStream::readPacket(Stream &in,BroadcastState &bcs) +{ + int error = PCP_ERROR_GENERAL; + try + { + AtomStream atom(in); + + ChanPacket pack; + MemoryStream mem(pack.data,sizeof(pack.data)); + AtomStream patom(mem); + + + // send outward packets + error = PCP_ERROR_WRITE; + if (outData.numPending()) + { + outData.readPacket(pack); + pack.writeRaw(in); + } + error = PCP_ERROR_GENERAL; + + if (outData.willSkip()) + { + error = PCP_ERROR_WRITE+PCP_ERROR_SKIP; + throw StreamException("Send too slow"); + } + + + error = PCP_ERROR_READ; + // poll for new downward packet + if (in.readReady()) + { + int numc,numd; + ID4 id; + + id = atom.read(numc,numd); + + mem.rewind(); + pack.len = patom.writeAtoms(id, in, numc, numd); + pack.type = ChanPacket::T_PCP; + + //inData.writePacket(pack); + //} + error = PCP_ERROR_GENERAL; + + // process downward packets + //if (inData.numPending()) + //{ + //inData.readPacket(pack); + + mem.rewind(); + + //int numc,numd; + id = patom.read(numc,numd); + + error = PCPStream::procAtom(patom,id,numc,numd,bcs); + + if (error) + throw StreamException("PCP exception"); + } + + error = 0; + + }catch(StreamException &e) + { + LOG_ERROR("PCP readPacket: %s (%d)",e.msg,error); + } + + return error; +} + +// ------------------------------------------ +void PCPStream::readEnd(Stream &,Channel *) +{ +} + + +// ------------------------------------------ +void PCPStream::readPushAtoms(AtomStream &atom, int numc,BroadcastState &bcs) +{ + Host host; + GnuID chanID; + + chanID.clear(); + + for(int i=0; ifindChannelByID(chanID); + if (ch) + if (ch->isBroadcasting() || !ch->isFull() && !servMgr->relaysFull() && ch->info.id.isSame(chanID)) + s = servMgr->allocServent(); + }else{ + s = servMgr->allocServent(); + } + + if (s) + { + LOG_DEBUG("GIVing to %s",ipstr); + s->initGIV(host,chanID); + } + } + +} +// ------------------------------------------ +void PCPStream::readRootAtoms(AtomStream &atom, int numc,BroadcastState &bcs) +{ + String url; + + for(int i=0; isetUpdateInterval(si); + LOG_DEBUG("PCP got new host update interval: %ds",si); + }else if (id == PCP_ROOT_URL) + { + url = "http://www.peercast.org/"; + String loc; + atom.readString(loc.data,sizeof(loc.data),d); + url.append(loc); + + }else if (id == PCP_ROOT_CHECKVER) + { + unsigned int newVer = atom.readInt(); + if (newVer > PCP_CLIENT_VERSION) + { + strcpy(servMgr->downloadURL,url.cstr()); + peercastApp->notifyMessage(ServMgr::NT_UPGRADE,"There is a new version available, please click here to upgrade your client."); + } + LOG_DEBUG("PCP got version check: %d / %d",newVer,PCP_CLIENT_VERSION); + + }else if (id == PCP_ROOT_NEXT) + { + unsigned int time = atom.readInt(); + + if (time) + { + unsigned int ctime = sys->getTime(); + nextRootPacket = ctime+time; + LOG_DEBUG("PCP expecting next root packet in %ds",time); + }else + { + nextRootPacket = 0; + } + + }else if (id == PCP_ROOT_UPDATE) + { + atom.skip(c,d); + + chanMgr->broadcastTrackerUpdate(remoteID,true); + + }else if ((id == PCP_MESG_ASCII) || (id == PCP_MESG)) // PCP_MESG_ASCII to be depreciated + { + String newMsg; + + atom.readString(newMsg.data,sizeof(newMsg.data),d); + if (!newMsg.isSame(servMgr->rootMsg.cstr())) + { + servMgr->rootMsg = newMsg; + LOG_DEBUG("PCP got new root mesg: %s",servMgr->rootMsg.cstr()); + peercastApp->notifyMessage(ServMgr::NT_PEERCAST,servMgr->rootMsg.cstr()); + } + }else + { + LOG_DEBUG("PCP skip: %s,%d,%d",id.getString().str(),c,d); + atom.skip(c,d); + } + } +} + +// ------------------------------------------ +void PCPStream::readPktAtoms(Channel *ch,AtomStream &atom,int numc,BroadcastState &bcs) +{ + ChanPacket pack; + ID4 type; + + + for(int i=0; istreamPos; + if (diff) + { + LOG_DEBUG("PCP skipping %s%8d (%10d -> %10d) count=%2d",(diff>0)?"+":"",diff,ch->streamPos,pack.pos, ch->skipCount); + if (ch->lastSkipTime + 120 < sys->getTime()){ + ch->skipCount = 0; + } + ch->lastSkipTime = sys->getTime(); + ch->skipCount++; //JP-EX + pack.skip = true; + } + + if (servMgr->autoBumpSkipCount) //JP-EX + { + if (ch->skipCount > servMgr->autoBumpSkipCount) + { + LOG_DEBUG("Auto bump"); + ch->bump = true; + } + } + + if (pack.type == ChanPacket::T_HEAD) + { + LOG_DEBUG("New head packet at %d",pack.pos); + bool renewhead; + if (servMgr->keepDownstreams) + renewhead = (memcmp(ch->headPack.data, pack.data, pack.len) != 0); + else + renewhead = true; + + /* + // check for stream restart + if (pack.pos == 0) + { + LOG_CHANNEL("PCP resetting stream"); + ch->streamIndex++; + ch->rawData.init(); + } + */ + if (renewhead || ch->lastStopTime + 30 < sys->getTime()) { + // check for stream restart + if (pack.pos == 0) + { + LOG_CHANNEL("PCP resetting stream"); + ch->streamIndex++; + ch->rawData.init(); + } + + ch->headPack = pack; + + ch->rawData.writePacket(pack,true); + ch->streamPos = pack.pos+pack.len; + } + + }else if (pack.type == ChanPacket::T_DATA) + { + ch->rawData.writePacket(pack,true); + ch->streamPos = pack.pos+pack.len; + } + + } + + // update this parent packet stream position + if ((pack.pos) && (!bcs.streamPos || (pack.pos < bcs.streamPos))) + bcs.streamPos = pack.pos; + +} +// ----------------------------------- +void PCPStream::readHostAtoms(AtomStream &atom, int numc, BroadcastState &bcs, ChanHit &hit, bool flg) +{ +// ChanHit hit; + hit.init(); + GnuID chanID = bcs.chanID; //use default + + bool busy=false; + + unsigned int ipNum=0; + + for(int i=0; i 1) + ipNum = 1; + } + else if (id == PCP_HOST_NUML) + hit.numListeners = atom.readInt(); + else if (id == PCP_HOST_NUMR) + hit.numRelays = atom.readInt(); + else if (id == PCP_HOST_UPTIME) + hit.upTime = atom.readInt(); + else if (id == PCP_HOST_OLDPOS) + hit.oldestPos = atom.readInt(); + else if (id == PCP_HOST_NEWPOS) + hit.newestPos = atom.readInt(); + else if (id == PCP_HOST_VERSION) + hit.version = atom.readInt(); + else if (id == PCP_HOST_VERSION_VP) + hit.version_vp = atom.readInt(); + else if (id == PCP_HOST_VERSION_EX_PREFIX) + atom.readBytes(hit.version_ex_prefix,2); + else if (id == PCP_HOST_VERSION_EX_NUMBER){ + hit.version_ex_number = atom.readShort(); + } + else if (id == PCP_HOST_FLAGS1) + { + int fl1 = atom.readChar(); + + hit.recv = (fl1 & PCP_HOST_FLAGS1_RECV) !=0; + hit.relay = (fl1 & PCP_HOST_FLAGS1_RELAY) !=0; + hit.direct = (fl1 & PCP_HOST_FLAGS1_DIRECT) !=0; + hit.cin = (fl1 & PCP_HOST_FLAGS1_CIN) !=0; + hit.tracker = (fl1 & PCP_HOST_FLAGS1_TRACKER) !=0; + hit.firewalled = (fl1 & PCP_HOST_FLAGS1_PUSH) !=0; + + + }else if (id == PCP_HOST_ID) + atom.readBytes(hit.sessionID.id,16); + else if (id == PCP_HOST_CHANID) + atom.readBytes(chanID.id,16); + else if (id == PCP_HOST_UPHOST_IP) + hit.uphost.ip = atom.readInt(); + else if (id == PCP_HOST_UPHOST_PORT) + hit.uphost.port = atom.readInt(); + else if (id == PCP_HOST_UPHOST_HOPS) + hit.uphostHops = atom.readInt(); + else + { + LOG_DEBUG("PCP skip: %s,%d,%d",id.getString().str(),c,d); + atom.skip(c,d); + } + } + + hit.host = hit.rhost[0]; + hit.chanID = chanID; + + hit.numHops = bcs.numHops; + + hit.servent_id = bcs.servent_id; + + if (flg){ +// LOG_DEBUG("readHostAtoms HITLISTLOCK ON-------------"); + chanMgr->hitlistlock.on(); + if (hit.recv) + chanMgr->addHit(hit); + else + chanMgr->delHit(hit); +// LOG_DEBUG("readHostAtoms HITLISTLOCK OFF-------------"); + chanMgr->hitlistlock.off(); + } + + if (hit.numHops == 1){ + Servent *sv = servMgr->findServentByServentID(hit.servent_id); + if (sv){ +// LOG_DEBUG("set servent's waitPort = %d", hit.host.port); + sv->waitPort = hit.host.port; + } + } +} + +// ------------------------------------------ +void PCPStream::readChanAtoms(AtomStream &atom,int numc,BroadcastState &bcs) +{ +/* Channel *ch=NULL; + ChanHitList *chl=NULL; + ChanInfo newInfo; + + ch = chanMgr->findChannelByID(bcs.chanID); + chl = chanMgr->findHitListByID(bcs.chanID); + + if (ch) + newInfo = ch->info; + else if (chl) + newInfo = chl->info;*/ + + Channel *ch=NULL; + ChanHitList *chl=NULL; + ChanInfo newInfo, chaInfo; + + ch = this->parent; + if (ch){ + newInfo = ch->info; + chaInfo = ch->info; + } + + for(int i=0; ifindChannelByID(newInfo.id); + chl = chanMgr->findHitListByID(newInfo.id); + + }else + { + LOG_DEBUG("PCP skip: %s,%d,%d",id.getString().str(),c,d); + atom.skip(c,d); + } + } + + chl = chanMgr->findHitList(newInfo); + + if (!chl) + chl = chanMgr->addHitList(newInfo); + + if (chl) + { + chl->info.update(newInfo); + + if (!servMgr->chanLog.isEmpty()) + { + //if (chl->numListeners()) + { + try + { + FileStream file; + file.openWriteAppend(servMgr->chanLog.cstr()); + + XML::Node *rn = new XML::Node("update time=\"%d\"",sys->getTime()); + XML::Node *n = chl->info.createChannelXML(); + n->add(chl->createXML(false)); + n->add(chl->info.createTrackXML()); + rn->add(n); + + rn->write(file,0); + delete rn; + file.close(); + }catch(StreamException &e) + { + LOG_ERROR("Unable to update channel log: %s",e.msg); + } + } + } + + } + + if (ch && !ch->isBroadcasting()) + ch->updateInfo(newInfo); + + +} +// ------------------------------------------ +int PCPStream::readBroadcastAtoms(AtomStream &atom,int numc,BroadcastState &bcs) +{ + ChanPacket pack; + int ttl=0; + int ver=0; + int ver_vp=0; + GnuID fromID,destID; + int r=0; + char ver_ex_prefix[2]; + int ver_ex_number = 0; + + fromID.clear(); + destID.clear(); + + bcs.initPacketSettings(); + + MemoryStream pmem(pack.data,sizeof(pack.data)); + AtomStream patom(pmem); + + patom.writeParent(PCP_BCST,numc); + + for(int i=0; isessionID); + + char idstr1[64]; + char idstr2[64]; + + destID.toStr(idstr1); + servMgr->sessionID.toStr(idstr2); + + }else if (id == PCP_BCST_CHANID) + { + atom.readBytes(bcs.chanID.id,16); + patom.writeBytes(id,bcs.chanID.id,16); + }else if (id == PCP_BCST_VERSION) + { + ver = atom.readInt(); + patom.writeInt(id,ver); + }else if (id == PCP_BCST_VERSION_VP) + { + ver_vp = atom.readInt(); + patom.writeInt(id,ver_vp); + }else if (id == PCP_BCST_VERSION_EX_PREFIX) + { + atom.readBytes(ver_ex_prefix,2); + patom.writeBytes(id,ver_ex_prefix,2); + }else if (id == PCP_BCST_VERSION_EX_NUMBER) + { + ver_ex_number = atom.readShort(); + patom.writeShort(id,ver_ex_number); + }else if (id == PCP_HOST) + { + ChanHit hit; + readHostAtoms(atom,c,bcs,hit,false); + if (hit.uphost.ip == 0){ +// LOG_DEBUG("bcs servent_id = %d", bcs.servent_id); + if (bcs.numHops == 1){ + hit.uphost.ip = servMgr->serverHost.ip; + hit.uphost.port = servMgr->serverHost.port; + hit.uphostHops = 1; + } else { + Servent *sv = servMgr->findServentByServentID(bcs.servent_id); + if (sv){ + hit.uphost.ip = sv->getHost().ip; + hit.uphost.port = sv->waitPort; + hit.uphostHops = bcs.numHops - 1; + } + } + } + int oldPos = pmem.pos; + hit.writeAtoms(patom, hit.chanID); + pmem.pos = oldPos; + r = readAtom(patom,bcs); + } else { + // copy and process atoms + int oldPos = pmem.pos; + patom.writeAtoms(id,atom.io,c,d); + pmem.pos = oldPos; + r = readAtom(patom,bcs); + } + } + + char fromStr[64]; + fromStr[0] = 0; + if (fromID.isSet()) + fromID.toStr(fromStr); + char destStr[64]; + destStr[0] = 0; + if (destID.isSet()) + destID.toStr(destStr); + char tmp[64]; + bcs.chanID.toStr(tmp); + +// LOG_DEBUG(tmp); + + if (ver_ex_number){ + LOG_DEBUG("PCP bcst: group=%d, hops=%d, ver=%d(%c%c%04d), from=%s, dest=%s ttl=%d", + bcs.group,bcs.numHops,ver,ver_ex_prefix[0],ver_ex_prefix[1],ver_ex_number,fromStr,destStr,ttl); + } else if (ver_vp){ + LOG_DEBUG("PCP bcst: group=%d, hops=%d, ver=%d(VP%04d), from=%s, dest=%s ttl=%d",bcs.group,bcs.numHops,ver,ver_vp,fromStr,destStr,ttl); + } else { + LOG_DEBUG("PCP bcst: group=%d, hops=%d, ver=%d, from=%s, dest=%s ttl=%d",bcs.group,bcs.numHops,ver,fromStr,destStr,ttl); + } + + if (fromID.isSet()) + if (fromID.isSame(servMgr->sessionID)) + { + LOG_ERROR("BCST loopback"); + return PCP_ERROR_BCST+PCP_ERROR_LOOPBACK; + } + + // broadcast back out if ttl > 0 + if ((ttl>0) && (!bcs.forMe)) + { + pack.len = pmem.pos; + pack.type = ChanPacket::T_PCP; + + if (bcs.group & (/*PCP_BCST_GROUP_ROOT|*/PCP_BCST_GROUP_TRACKERS|PCP_BCST_GROUP_RELAYS)) + { + chanMgr->broadcastPacketUp(pack,bcs.chanID,remoteID,destID); + } + + if (bcs.group & (/*PCP_BCST_GROUP_ROOT|*/PCP_BCST_GROUP_TRACKERS|PCP_BCST_GROUP_RELAYS)) + { + servMgr->broadcastPacket(pack,bcs.chanID,remoteID,destID,Servent::T_COUT); + } + + if (bcs.group & (PCP_BCST_GROUP_RELAYS|PCP_BCST_GROUP_TRACKERS)) + { + servMgr->broadcastPacket(pack,bcs.chanID,remoteID,destID,Servent::T_CIN); + } + + if (bcs.group & (PCP_BCST_GROUP_RELAYS)) + { + servMgr->broadcastPacket(pack,bcs.chanID,remoteID,destID,Servent::T_RELAY); + } + + +// LOG_DEBUG("ttl=%d",ttl); + + } else { +// LOG_DEBUG("ttl=%d",ttl); + } + return r; +} + + +// ------------------------------------------ +int PCPStream::procAtom(AtomStream &atom,ID4 id,int numc, int dlen,BroadcastState &bcs) +{ + int r=0; + ChanHit hit; + int rBan = 0; + + if (id == PCP_CHAN) + { + readChanAtoms(atom,numc,bcs); + }else if (id == PCP_ROOT) + { + if (servMgr->isRoot) + throw StreamException("Unauthorized root message"); + else + readRootAtoms(atom,numc,bcs); + + }else if (id == PCP_HOST) + { + readHostAtoms(atom,numc,bcs,hit); + Channel *ch = chanMgr->findChannelByID(hit.chanID); + if (ch && (ch->isBroadcasting() || servMgr->vpDebug)){ + if (servMgr->autoPort0Kick && (hit.numHops == 1) && (hit.firewalled || (!hit.relay && !hit.numRelays))){ + char tmp[32]; + hit.host.IPtoStr(tmp); + LOG_DEBUG("host that can't relay is disconnect: %s", tmp); + rBan = PCP_ERROR_BANNED; + } + if (servMgr->allowOnlyVP && (hit.numHops == 1) && !hit.version_vp){ + char tmp[32]; + hit.host.IPtoStr(tmp); + LOG_DEBUG("host that is not VP is disconnect: %s", tmp); + rBan = PCP_ERROR_BANNED; + } + } + + }else if ((id == PCP_MESG_ASCII) || (id == PCP_MESG)) // PCP_MESG_ASCII to be depreciated + { + String msg; + atom.readString(msg.data,sizeof(msg.data),dlen); + LOG_DEBUG("PCP got text: %s",msg.cstr()); + }else if (id == PCP_BCST) + { + r = readBroadcastAtoms(atom,numc,bcs); + }else if (id == PCP_HELO) + { + atom.skip(numc,dlen); + atom.writeParent(PCP_OLEH,1); + atom.writeBytes(PCP_HELO_SESSIONID,servMgr->sessionID.id,16); + }else if (id == PCP_PUSH) + { + + readPushAtoms(atom,numc,bcs); + }else if (id == PCP_OK) + { + atom.readInt(); + + }else if (id == PCP_QUIT) + { + r = atom.readInt(); + if (!r) + r = PCP_ERROR_QUIT; + + }else if (id == PCP_ATOM) + { + for(int i=0; igetIniFilename()) + servMgr->loadSettings(peercastApp->getIniFilename()); + + servMgr->start(); +} +// -------------------------------------------------- +void APICALL PeercastInstance::setNotifyMask(int mask) +{ + if (servMgr) + servMgr->notifyMask = mask; +} +// -------------------------------------------------- +int APICALL PeercastInstance::getNotifyMask() +{ + if (servMgr) + return servMgr->notifyMask; + else + return 0; +} + +// -------------------------------------------------- +void APICALL PeercastInstance::setAutoConnect(bool on) +{ + if (servMgr) + servMgr->autoConnect = on; +} +// -------------------------------------------------- +bool APICALL PeercastInstance::getAutoConnect() +{ + if (servMgr) + return servMgr->autoConnect; + else + return false; +} +// -------------------------------------------------- +void APICALL PeercastInstance::setMaxOutput(int kbps) +{ + if (servMgr) + servMgr->maxBitrateOut = kbps; +} +// -------------------------------------------------- +int APICALL PeercastInstance::getMaxOutput() +{ + if (servMgr) + return servMgr->maxBitrateOut; + else + return 0; +} +// -------------------------------------------------- +void APICALL PeercastInstance::setMaxRelays(int max) +{ + if (servMgr) + servMgr->setMaxRelays(max); +} +// -------------------------------------------------- +int APICALL PeercastInstance::getMaxRelays() +{ + if (servMgr) + return servMgr->maxRelays; + else + return 0; +} +// -------------------------------------------------- +void APICALL PeercastInstance::setActive(bool on) +{ + if (servMgr) + { + servMgr->autoConnect = on; + servMgr->autoServe = on; + } +} +// -------------------------------------------------- +bool APICALL PeercastInstance::getActive() +{ + if (servMgr) + return servMgr->autoConnect&&servMgr->autoServe; + else + return false; +} +// -------------------------------------------------- +void APICALL PeercastInstance::saveSettings() +{ + if (servMgr) + servMgr->saveSettings(peercastApp->getIniFilename()); +} +// -------------------------------------------------- +void APICALL PeercastInstance::quit() +{ + isQuitting = true; + if (chanMgr) + chanMgr->quit(); + if (servMgr) + servMgr->quit(); +} +// -------------------------------------------------- +void APICALL PeercastInstance::setServerPort(int port) +{ + if (servMgr) + { + servMgr->serverHost.port = port; + servMgr->restartServer = true; + } +} +// -------------------------------------------------- +int APICALL PeercastInstance::getServerPort() +{ + if (servMgr) + return servMgr->serverHost.port; + else + return 0; +} +// -------------------------------------------------- +void APICALL PeercastInstance::setServerPassword(const char *pwd) +{ + if (servMgr) + strcpy(servMgr->password,pwd); +} +// -------------------------------------------------- +const char *APICALL PeercastInstance::getServerPassword() +{ + return servMgr->password; +} +// -------------------------------------------------- +void APICALL PeercastInstance::callLocalURL(const char *url) +{ + if (sys && servMgr) + sys->callLocalURL(url,servMgr->serverHost.port); +} + + +// -------------------------------------------------- +void ADDLOG(const char *fmt,va_list ap,LogBuffer::TYPE type) +{ + if(sys) + { + const int MAX_LINELEN = 1024; + + char str[MAX_LINELEN+1]; + vsnprintf(str,MAX_LINELEN-1,fmt,ap); + str[MAX_LINELEN-1]=0; + + if (type != LogBuffer::T_NONE) + sys->logBuf->write(str,type); + + peercastApp->printLog(type,str); + } +} +// -------------------------------------------------- +void LOG(const char *fmt,...) +{ + va_list ap; + va_start(ap, fmt); + ADDLOG(fmt,ap,LogBuffer::T_DEBUG); + va_end(ap); +} + +// -------------------------------------------------- +void LOG_ERROR(const char *fmt,...) +{ + if (servMgr) + { + if ((servMgr->showLog & (1<pauseLog)) + { + va_list ap; + va_start(ap, fmt); + ADDLOG(fmt,ap,LogBuffer::T_ERROR); + va_end(ap); + } + } +} +// -------------------------------------------------- +void LOG_DEBUG(const char *fmt,...) +{ + if (servMgr) + { + if ((servMgr->showLog & (1<pauseLog)) + { + va_list ap; + va_start(ap, fmt); + ADDLOG(fmt,ap,LogBuffer::T_DEBUG); + va_end(ap); + } + } +} +// -------------------------------------------------- +void LOG_NETWORK(const char *fmt,...) +{ + if (servMgr) + { + if ((servMgr->showLog & (1<pauseLog)) + { + va_list ap; + va_start(ap, fmt); + ADDLOG(fmt,ap,LogBuffer::T_NETWORK); + va_end(ap); + } + } +} +// -------------------------------------------------- +void LOG_CHANNEL(const char *fmt,...) +{ + if (servMgr) + { + if ((servMgr->showLog & (1<pauseLog)) + { + va_list ap; + va_start(ap, fmt); + ADDLOG(fmt,ap,LogBuffer::T_CHANNEL); + va_end(ap); + } + } +} diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/peercast.h b/c:/Git/PeerCast.root/PeerCast/core/common/peercast.h new file mode 100644 index 0000000..ef8732b --- /dev/null +++ b/c:/Git/PeerCast.root/PeerCast/core/common/peercast.h @@ -0,0 +1,102 @@ +#ifndef _PEERCAST_H +#define _PEERCAST_H + + +//#define APICALL _stdcall +#ifdef WIN32 +#define APICALL _cdecl +#else +#define APICALL +#endif + + +class ChanInfo; +class Sys; + +#include "servmgr.h" + + +// ------------------------------------------------------------ +// This is the interface from the application to the core. +class PeercastInstance +{ +public: + PeercastInstance() + :isQuitting(false) + {} + + virtual void APICALL init(); + + virtual void APICALL setAutoConnect(bool); + virtual bool APICALL getAutoConnect(); + + virtual void APICALL setActive(bool); + virtual bool APICALL getActive(); + + virtual int APICALL getMaxOutput(); + virtual void APICALL setMaxOutput(int); + + virtual int APICALL getMaxRelays(); + virtual void APICALL setMaxRelays(int); + + virtual void APICALL setServerPort(int); + virtual int APICALL getServerPort(); + virtual void APICALL setServerPassword(const char *); + virtual const char *APICALL getServerPassword(); + + virtual void APICALL saveSettings(); + + virtual void APICALL callLocalURL(const char *); + + virtual void APICALL setNotifyMask(int); + virtual int APICALL getNotifyMask(); + + virtual void APICALL quit(); + + virtual Sys * APICALL createSys()=0; + + bool isQuitting; + +}; +// ------------------------------------------------------------ +// This is the interface from the core to the application. +class PeercastApplication +{ +public: + + virtual const char * APICALL getPath() {return "./";} + virtual const char * APICALL getIniFilename() {return "peercast.ini";} + virtual bool APICALL clearTemp() { return false; } //JP-EX + virtual void APICALL openLogFile() {} //JP-EX + virtual void APICALL getDirectory() {} //JP-EX + virtual void APICALL printLog(LogBuffer::TYPE, const char *) {} + virtual void APICALL addChannel(ChanInfo *) {} + virtual void APICALL delChannel(ChanInfo *) {} + virtual void APICALL resetChannels() {} + virtual void APICALL test(char *) {} + virtual const char *APICALL getClientTypeOS() = 0; + virtual void APICALL updateSettings() {} + + virtual void APICALL notifyMessage(ServMgr::NOTIFY_TYPE, const char *) {} + virtual void APICALL channelStart(ChanInfo *) {} + virtual void APICALL channelStop(ChanInfo *) {} + virtual void APICALL channelUpdate(ChanInfo *) {} +}; + + +// ---------------------------------- +extern PeercastInstance *peercastInst; +extern PeercastApplication *peercastApp; + +// ---------------------------------- +#ifdef WIN32 +extern "C" +{ +__declspec( dllexport ) PeercastInstance * newPeercast(PeercastApplication *); +}; +#endif + +// ---------------------------------- + + +#endif diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/rtsp.cpp b/c:/Git/PeerCast.root/PeerCast/core/common/rtsp.cpp new file mode 100644 index 0000000..4101852 --- /dev/null +++ b/c:/Git/PeerCast.root/PeerCast/core/common/rtsp.cpp @@ -0,0 +1,26 @@ +// ------------------------------------------------ +// File : rtsp.cpp +// Date: 4-apr-2002 +// Author: giles +// Desc: +// RTSP protocol handling (experimental) +// +// (c) 2002 peercast.org +// ------------------------------------------------ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// ------------------------------------------------ + +#include "rtsp.h" +#ifdef _DEBUG +#include "chkMemoryLeak.h" +#define DEBUG_NEW new(__FILE__, __LINE__) +#define new DEBUG_NEW +#endif diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/rtsp.h b/c:/Git/PeerCast.root/PeerCast/core/common/rtsp.h new file mode 100644 index 0000000..60bb71d --- /dev/null +++ b/c:/Git/PeerCast.root/PeerCast/core/common/rtsp.h @@ -0,0 +1,32 @@ +// ------------------------------------------------ +// File : rtsp.h +// Date: 4-apr-2002 +// Author: giles +// Desc: +// +// (c) 2002 peercast.org +// ------------------------------------------------ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// ------------------------------------------------ + +#ifndef _RTSP_H +#define _RTSP_H + +#include "http.h" + +// --------------------------------------------- +class RTSP : public HTTP +{ +public: + RTSP(Stream &s):HTTP(s){} +}; + +#endif diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/servent.cpp b/c:/Git/PeerCast.root/PeerCast/core/common/servent.cpp new file mode 100644 index 0000000..1ce8a26 --- /dev/null +++ b/c:/Git/PeerCast.root/PeerCast/core/common/servent.cpp @@ -0,0 +1,3163 @@ +// ------------------------------------------------ +// File : servent.cpp +// Date: 4-apr-2002 +// Author: giles +// Desc: +// Servents are the actual connections between clients. They do the handshaking, +// transfering of data and processing of GnuPackets. Each servent has one socket allocated +// to it on connect, it uses this to transfer all of its data. +// +// (c) 2002 peercast.org +// ------------------------------------------------ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// ------------------------------------------------ +// todo: make lan->yp not check firewall + +#include +#include "servent.h" +#include "sys.h" +#include "gnutella.h" +#include "xml.h" +#include "html.h" +#include "http.h" +#include "stats.h" +#include "servmgr.h" +#include "peercast.h" +#include "atom.h" +#include "pcp.h" +#include "version2.h" +#ifdef _DEBUG +#include "chkMemoryLeak.h" +#define DEBUG_NEW new(__FILE__, __LINE__) +#define new DEBUG_NEW +#endif + + +const int DIRECT_WRITE_TIMEOUT = 60; + +// ----------------------------------- +char *Servent::statusMsgs[]= +{ + "NONE", + "CONNECTING", + "PROTOCOL", + "HANDSHAKE", + "CONNECTED", + "CLOSING", + "LISTENING", + "TIMEOUT", + "REFUSED", + "VERIFIED", + "ERROR", + "WAIT", + "FREE" +}; + +// ----------------------------------- +char *Servent::typeMsgs[]= +{ + "NONE", + "INCOMING", + "SERVER", + "RELAY", + "DIRECT", + "COUT", + "CIN", + "PGNU" +}; +// ----------------------------------- +bool Servent::isPrivate() +{ + Host h = getHost(); + return servMgr->isFiltered(ServFilter::F_PRIVATE,h) || h.isLocalhost(); +} +// ----------------------------------- +bool Servent::isAllowed(int a) +{ + Host h = getHost(); + + if (servMgr->isFiltered(ServFilter::F_BAN,h)) + return false; + + return (allow&a)!=0; +} + +// ----------------------------------- +bool Servent::isFiltered(int f) +{ + Host h = getHost(); + return servMgr->isFiltered(f,h); +} + +int servent_count = 1; +// ----------------------------------- +Servent::Servent(int index) +:outPacketsPri(MAX_OUTPACKETS) +,outPacketsNorm(MAX_OUTPACKETS) +,seenIDs(MAX_HASH) +,serventIndex(index) +,sock(NULL) +,next(NULL) +{ + reset(); + servent_id = servent_count++; + lastSkipTime = 0; + lastSkipCount = 0; + waitPort = 0; +} + +// ----------------------------------- +Servent::~Servent() +{ + +} +// ----------------------------------- +void Servent::kill() +{ + thread.active = false; + + setStatus(S_CLOSING); + + if (pcpStream) + { + PCPStream *pcp = pcpStream; + pcpStream = NULL; + pcp->kill(); + delete pcp; + } + + chanMgr->hitlistlock.on(); + ChanHitList *chl = chanMgr->findHitListByID(chanID); + if (chl) { + ChanHit *chh = chl->hit; + ChanHit *prev = NULL; + while (chh) { + if (chh->servent_id == this->servent_id){ + if ((servMgr->kickKeepTime != 0) && (chh->firewalled == 1)){ + chh->numHops = 0; + chh->numListeners = 0; + chh->numRelays = 0; + prev = chh; + chh = chh->next; + } else { + ChanHit *next = chh->next; + if (prev) + prev->next = next; + else + chl->hit = next; + + char ip0str[64],ip1str[64]; + chh->rhost[0].toStr(ip0str); + chh->rhost[1].toStr(ip1str); + LOG_DEBUG("Delete hit (servent_id=%d): F%dT%dR%d %s/%s", + chh->servent_id,chh->firewalled,chh->tracker,chh->relay,ip0str,ip1str); + + delete chh; + chh = next; + } + } else { + prev = chh; + chh = chh->next; + } + } + } + chanMgr->hitlistlock.off(); + + if (sock) + { + sock->close(); + delete sock; + sock = NULL; + } + + if (pushSock) + { + pushSock->close(); + delete pushSock; + pushSock = NULL; + } + +// thread.unlock(); + + if (type != T_SERVER) + { + reset(); + setStatus(S_FREE); + } + +} +// ----------------------------------- +void Servent::abort() +{ + thread.active = false; + if (sock) + { + sock->close(); + } + +} + +// ----------------------------------- +void Servent::reset() +{ + + remoteID.clear(); + + servPort = 0; + + pcpStream = NULL; + + flowControl = false; + networkID.clear(); + + chanID.clear(); + + outputProtocol = ChanInfo::SP_UNKNOWN; + + agent.clear(); + sock = NULL; + allow = ALLOW_ALL; + syncPos = 0; + addMetadata = false; + nsSwitchNum = 0; + pack.func = 255; + lastConnect = lastPing = lastPacket = 0; + loginPassword[0] = 0; + loginMount[0] = 0; + bytesPerSecond = 0; + priorityConnect = false; + pushSock = NULL; + sendHeader = true; + + outPacketsNorm.reset(); + outPacketsPri.reset(); + + seenIDs.clear(); + + status = S_NONE; + type = T_NONE; + + channel_id = 0; +} +// ----------------------------------- +bool Servent::sendPacket(ChanPacket &pack,GnuID &cid,GnuID &sid,GnuID &did,Servent::TYPE t) +{ + + if ( (type == t) + && (isConnected()) + && (!cid.isSet() || chanID.isSame(cid)) + && (!sid.isSet() || !sid.isSame(remoteID)) + && (pcpStream != NULL) + ) + { + return pcpStream->sendPacket(pack,did); + } + return false; +} + + +// ----------------------------------- +bool Servent::acceptGIV(ClientSocket *givSock) +{ + if (!pushSock) + { + pushSock = givSock; + return true; + }else + return false; +} + +// ----------------------------------- +Host Servent::getHost() +{ + Host h(0,0); + + if (sock) + h = sock->host; + + return h; +} + +// ----------------------------------- +bool Servent::outputPacket(GnuPacket &p, bool pri) +{ + lock.on(); + + bool r=false; + if (pri) + r = outPacketsPri.write(p); + else + { + if (servMgr->useFlowControl) + { + int per = outPacketsNorm.percentFull(); + if (per > 50) + flowControl = true; + else if (per < 25) + flowControl = false; + } + + + bool send=true; + if (flowControl) + { + // if in flowcontrol, only allow packets with less of a hop count than already in queue + if (p.hops >= outPacketsNorm.findMinHop()) + send = false; + } + + if (send) + r = outPacketsNorm.write(p); + } + + lock.off(); + return r; +} + +// ----------------------------------- +bool Servent::initServer(Host &h) +{ + try + { + checkFree(); + + status = S_WAIT; + + createSocket(); + + sock->bind(h); + + thread.data = this; + + thread.func = serverProc; + + type = T_SERVER; + + if (!sys->startThread(&thread)) + throw StreamException("Can`t start thread"); + + }catch(StreamException &e) + { + LOG_ERROR("Bad server: %s",e.msg); + kill(); + return false; + } + + return true; +} +// ----------------------------------- +void Servent::checkFree() +{ + if (sock) + throw StreamException("Socket already set"); + if (thread.active) + throw StreamException("Thread already active"); +} +// ----------------------------------- +void Servent::initIncoming(ClientSocket *s, unsigned int a) +{ + + try{ + + checkFree(); + + type = T_INCOMING; + sock = s; + allow = a; + thread.data = this; + thread.func = incomingProc; + + setStatus(S_PROTOCOL); + + char ipStr[64]; + sock->host.toStr(ipStr); + LOG_DEBUG("Incoming from %s",ipStr); + + + if (!sys->startThread(&thread)) + throw StreamException("Can`t start thread"); + }catch(StreamException &e) + { + //LOG_ERROR("!!FATAL!! Incoming error: %s",e.msg); + //servMgr->shutdownTimer = 1; + kill(); + + LOG_ERROR("INCOMING FAILED: %s",e.msg); + + } +} + +// ----------------------------------- +void Servent::initOutgoing(TYPE ty) +{ + try + { + checkFree(); + + + type = ty; + + thread.data = this; + thread.func = outgoingProc; + + if (!sys->startThread(&thread)) + throw StreamException("Can`t start thread"); + + }catch(StreamException &e) + { + LOG_ERROR("Unable to start outgoing: %s",e.msg); + kill(); + } +} + +// ----------------------------------- +void Servent::initPCP(Host &rh) +{ + char ipStr[64]; + rh.toStr(ipStr); + try + { + checkFree(); + + createSocket(); + + type = T_COUT; + + sock->open(rh); + + if (!isAllowed(ALLOW_NETWORK)) + throw StreamException("Servent not allowed"); + + thread.data = this; + thread.func = outgoingProc; + + LOG_DEBUG("Outgoing to %s",ipStr); + + if (!sys->startThread(&thread)) + throw StreamException("Can`t start thread"); + + }catch(StreamException &e) + { + LOG_ERROR("Unable to open connection to %s - %s",ipStr,e.msg); + kill(); + } +} + +#if 0 +// ----------------------------------- +void Servent::initChannelFetch(Host &host) +{ + type = T_STREAM; + + char ipStr[64]; + host.toStr(ipStr); + + checkFree(); + + createSocket(); + + sock->open(host); + + + if (!isAllowed(ALLOW_DATA)) + throw StreamException("Servent not allowed"); + + sock->connect(); +} +#endif + +// ----------------------------------- +void Servent::initGIV(Host &h, GnuID &id) +{ + char ipStr[64]; + h.toStr(ipStr); + try + { + checkFree(); + + givID = id; + + createSocket(); + + sock->open(h); + + if (!isAllowed(ALLOW_NETWORK)) + throw StreamException("Servent not allowed"); + + sock->connect(); + + thread.data = this; + thread.func = givProc; + + type = T_RELAY; + + if (!sys->startThread(&thread)) + throw StreamException("Can`t start thread"); + + }catch(StreamException &e) + { + LOG_ERROR("GIV error to %s: %s",ipStr,e.msg); + kill(); + } +} +// ----------------------------------- +void Servent::createSocket() +{ + if (sock) + LOG_ERROR("Servent::createSocket attempt made while active"); + + sock = sys->createSocket(); +} +// ----------------------------------- +void Servent::setStatus(STATUS s) +{ + if (s != status) + { + status = s; + + if ((s == S_HANDSHAKE) || (s == S_CONNECTED) || (s == S_LISTENING)) + lastConnect = sys->getTime(); + } + +} + +// ----------------------------------- +void Servent::handshakeOut() +{ + sock->writeLine(GNU_PEERCONN); + + char str[64]; + + sock->writeLineF("%s %s",HTTP_HS_AGENT,PCX_AGENT); + sock->writeLineF("%s %d",PCX_HS_PCP,1); + + if (priorityConnect) + sock->writeLineF("%s %d",PCX_HS_PRIORITY,1); + + if (networkID.isSet()) + { + networkID.toStr(str); + sock->writeLineF("%s %s",PCX_HS_NETWORKID,str); + } + + servMgr->sessionID.toStr(str); + sock->writeLineF("%s %s",PCX_HS_ID,str); + + + sock->writeLineF("%s %s",PCX_HS_OS,peercastApp->getClientTypeOS()); + + sock->writeLine(""); + + HTTP http(*sock); + + int r = http.readResponse(); + + if (r != 200) + { + LOG_ERROR("Expected 200, got %d",r); + throw StreamException("Unexpected HTTP response"); + } + + + bool versionValid = false; + + GnuID clientID; + clientID.clear(); + + while (http.nextHeader()) + { + LOG_DEBUG(http.cmdLine); + + char *arg = http.getArgStr(); + if (!arg) + continue; + + if (http.isHeader(HTTP_HS_AGENT)) + { + agent.set(arg); + + if (strnicmp(arg,"PeerCast/",9)==0) + versionValid = (stricmp(arg+9,MIN_CONNECTVER)>=0); + }else if (http.isHeader(PCX_HS_NETWORKID)) + clientID.fromStr(arg); + } + + if (!clientID.isSame(networkID)) + throw HTTPException(HTTP_SC_UNAVAILABLE,503); + + if (!versionValid) + throw HTTPException(HTTP_SC_UNAUTHORIZED,401); + + + sock->writeLine(GNU_OK); + sock->writeLine(""); + +} + + +// ----------------------------------- +void Servent::processOutChannel() +{ +} + + +// ----------------------------------- +void Servent::handshakeIn() +{ + + int osType=0; + + HTTP http(*sock); + + + bool versionValid = false; + bool diffRootVer = false; + + GnuID clientID; + clientID.clear(); + + while (http.nextHeader()) + { + LOG_DEBUG("%s",http.cmdLine); + + char *arg = http.getArgStr(); + if (!arg) + continue; + + if (http.isHeader(HTTP_HS_AGENT)) + { + agent.set(arg); + + if (strnicmp(arg,"PeerCast/",9)==0) + { + versionValid = (stricmp(arg+9,MIN_CONNECTVER)>=0); + diffRootVer = stricmp(arg+9,MIN_ROOTVER)<0; + } + }else if (http.isHeader(PCX_HS_NETWORKID)) + { + clientID.fromStr(arg); + + }else if (http.isHeader(PCX_HS_PRIORITY)) + { + priorityConnect = atoi(arg)!=0; + + }else if (http.isHeader(PCX_HS_ID)) + { + GnuID id; + id.fromStr(arg); + if (id.isSame(servMgr->sessionID)) + throw StreamException("Servent loopback"); + + }else if (http.isHeader(PCX_HS_OS)) + { + if (stricmp(arg,PCX_OS_LINUX)==0) + osType = 1; + else if (stricmp(arg,PCX_OS_WIN32)==0) + osType = 2; + else if (stricmp(arg,PCX_OS_MACOSX)==0) + osType = 3; + else if (stricmp(arg,PCX_OS_WINAMP2)==0) + osType = 4; + } + + } + + if (!clientID.isSame(networkID)) + throw HTTPException(HTTP_SC_UNAVAILABLE,503); + + // if this is a priority connection and all incoming connections + // are full then kill an old connection to make room. Otherwise reject connection. + //if (!priorityConnect) + { + if (!isPrivate()) + if (servMgr->pubInFull()) + throw HTTPException(HTTP_SC_UNAVAILABLE,503); + } + + if (!versionValid) + throw HTTPException(HTTP_SC_FORBIDDEN,403); + + sock->writeLine(GNU_OK); + + sock->writeLineF("%s %s",HTTP_HS_AGENT,PCX_OLDAGENT); + + if (networkID.isSet()) + { + char idStr[64]; + networkID.toStr(idStr); + sock->writeLineF("%s %s",PCX_HS_NETWORKID,idStr); + } + + if (servMgr->isRoot) + { + sock->writeLineF("%s %d",PCX_HS_FLOWCTL,servMgr->useFlowControl?1:0); + sock->writeLineF("%s %d",PCX_HS_MINBCTTL,chanMgr->minBroadcastTTL); + sock->writeLineF("%s %d",PCX_HS_MAXBCTTL,chanMgr->maxBroadcastTTL); + sock->writeLineF("%s %d",PCX_HS_RELAYBC,servMgr->relayBroadcast); + //sock->writeLine("%s %d",PCX_HS_FULLHIT,2); + + + if (diffRootVer) + { + sock->writeString(PCX_HS_DL); + sock->writeLine(PCX_DL_URL); + } + + sock->writeLineF("%s %s",PCX_HS_MSG,servMgr->rootMsg.cstr()); + } + + + char hostIP[64]; + Host h = sock->host; + h.IPtoStr(hostIP); + sock->writeLineF("%s %s",PCX_HS_REMOTEIP,hostIP); + + + sock->writeLine(""); + + + while (http.nextHeader()); +} + +// ----------------------------------- +bool Servent::pingHost(Host &rhost,GnuID &rsid) +{ + char ipstr[64]; + rhost.toStr(ipstr); + LOG_DEBUG("Ping host %s: trying..",ipstr); + ClientSocket *s=NULL; + bool hostOK=false; + try + { + s = sys->createSocket(); + if (!s) + return false; + else + { + + s->setReadTimeout(15000); + s->setWriteTimeout(15000); + s->open(rhost); + s->connect(); + + AtomStream atom(*s); + + atom.writeInt(PCP_CONNECT,1); + atom.writeParent(PCP_HELO,1); + atom.writeBytes(PCP_HELO_SESSIONID,servMgr->sessionID.id,16); + + GnuID sid; + sid.clear(); + + int numc,numd; + ID4 id = atom.read(numc,numd); + if (id == PCP_OLEH) + { + for(int i=0; iclose(); + delete s; + } + + if (!hostOK) + rhost.port = 0; + + return true; +} + +WLock canStreamLock; + +// ----------------------------------- +bool Servent::handshakeStream(ChanInfo &chanInfo) +{ + + HTTP http(*sock); + + + bool gotPCP=false; + unsigned int reqPos=0; + + nsSwitchNum=0; + + while (http.nextHeader()) + { + char *arg = http.getArgStr(); + if (!arg) + continue; + + if (http.isHeader(PCX_HS_PCP)) + gotPCP = atoi(arg)!=0; + else if (http.isHeader(PCX_HS_POS)) + reqPos = atoi(arg); + else if (http.isHeader("icy-metadata")) + addMetadata = atoi(arg) > 0; + else if (http.isHeader(HTTP_HS_AGENT)) + agent = arg; + else if (http.isHeader("Pragma")) + { + char *ssc = stristr(arg,"stream-switch-count="); + char *so = stristr(arg,"stream-offset"); + + if (ssc || so) + { + nsSwitchNum=1; + //nsSwitchNum = atoi(ssc+20); + } + } + + LOG_DEBUG("Stream: %s",http.cmdLine); + } + + + if ((!gotPCP) && (outputProtocol == ChanInfo::SP_PCP)) + outputProtocol = ChanInfo::SP_PEERCAST; + + if (outputProtocol == ChanInfo::SP_HTTP) + { + if ( (chanInfo.srcProtocol == ChanInfo::SP_MMS) + || (chanInfo.contentType == ChanInfo::T_WMA) + || (chanInfo.contentType == ChanInfo::T_WMV) + || (chanInfo.contentType == ChanInfo::T_ASX) + ) + outputProtocol = ChanInfo::SP_MMS; + } + + + bool chanFound=false; + bool chanReady=false; + + Channel *ch = chanMgr->findChannelByID(chanInfo.id); + if (ch) + { + sendHeader = true; +// if (reqPos) +// { +// streamPos = ch->rawData.findOldestPos(reqPos); +// }else +// { + streamPos = ch->rawData.getLatestPos(); +// } + + chanID = chanInfo.id; + canStreamLock.on(); + chanReady = canStream(ch); + if (!chanReady) type = T_INCOMING; + thread.active = chanReady; + setStatus(S_CONNECTED); + canStreamLock.off(); + channel_id = ch->channel_id; + + //JP-Patch add-s + if (servMgr->isCheckPushStream()) + { + if (chanReady == true) + { + Host h = getHost(); + + if (!h.isLocalhost()) + { + do + { + if (strstr(agent.cstr(),"PeerCast/0.119") != NULL) + { + char strip[256]; + h.toStr(strip); + LOG_ERROR("Block v0.119 Servent : %s (%s)",strip,agent.cstr()); + chanReady = false; + break; + } + +/* ChanHitList *hits[ChanMgr::MAX_HITLISTS]; + int numHits=0; + for(int i=0; ihitlists[i]; + if (chl->isUsed()) + hits[numHits++] = chl; + } + bool isfw = false; + int numRelay = 0; + for(int i=0; iisUsed()) + { + for (int j=0; jhits[j]; + if (hit->host.isValid() && (h.ip == hit->host.ip)) + { + if (hit->firewalled) + isfw = true; + numRelay = hit->numRelays; + } + } + } + } + if ((isfw == true) && (numRelay == 0)) + { + char strip[256]; + h.toStr(strip); + LOG_ERROR("Block firewalled Servent : %s",strip); + chanReady = false; + }*/ + + ChanHitList *chl = chanMgr->findHitList(chanInfo); + ChanHit *hit = chl->hit; + while(hit){ + if (hit->host.isValid() && (h.ip == hit->host.ip)) + { + if ((hit->firewalled) && (hit->numRelays == 0)){ + char strip[256]; + h.toStr(strip); + LOG_ERROR("Block firewalled Servent : %s",strip); + chanReady = false; + } + } + hit = hit->next; + } + }while (0); + } + } + } + //JP-Patch add-e + } + +// LockBlock lockblock(chanMgr->hitlistlock); + +// lockblock.lockon(); + ChanHitList *chl = chanMgr->findHitList(chanInfo); + + if (chl) + { + chanFound = true; + } + + + bool result = false; + + char idStr[64]; + chanInfo.id.toStr(idStr); + + char sidStr[64]; + servMgr->sessionID.toStr(sidStr); + + Host rhost = sock->host; + + + + + AtomStream atom(*sock); + + + + if (!chanFound) + { + sock->writeLine(HTTP_SC_NOTFOUND); + sock->writeLine(""); + LOG_DEBUG("Sending channel not found"); + return false; + } + + + if (!chanReady) + { + if (outputProtocol == ChanInfo::SP_PCP) + { + + char tbuf[8196]; + MemoryStream mem(tbuf, sizeof(tbuf)); + mem.writeLine(HTTP_SC_UNAVAILABLE); + mem.writeLineF("%s %s",HTTP_HS_CONTENT,MIME_XPCP); + mem.writeLine(""); + sock->write(tbuf, mem.getPosition()); + + handshakeIncomingPCP(atom,rhost,remoteID,agent); + + char ripStr[64]; + rhost.toStr(ripStr); + + LOG_DEBUG("Sending channel unavailable"); + + ChanHitSearch chs; + + mem.rewind(); + AtomStream atom2(mem); + + int error = PCP_ERROR_QUIT+PCP_ERROR_UNAVAILABLE; + + chanMgr->hitlistlock.on(); + + chl = chanMgr->findHitList(chanInfo); + + if (chl) + { + ChanHit best; + + // search for up to 8 other hits + int cnt=0; + for(int i=0; i<8; i++) + { + best.init(); + + + // find best hit this network if local IP + if (!rhost.globalIP()) + { + chs.init(); + chs.matchHost = servMgr->serverHost; + chs.waitDelay = 2; + chs.excludeID = remoteID; + if (chl->pickHits(chs)){ + best = chs.best[0]; + LOG_DEBUG("find best hit this network if local IP"); + } + } + + // find best hit on same network + if (!best.host.ip) + { + chs.init(); + chs.matchHost = rhost; + chs.waitDelay = 2; + chs.excludeID = remoteID; + if (chl->pickHits(chs)){ + best = chs.best[0]; + LOG_DEBUG("find best hit on same network"); + } + + } + + // find best hit on other networks +/* if (!best.host.ip) + { + chs.init(); + chs.waitDelay = 2; + chs.excludeID = remoteID; + if (chl->pickHits(chs)){ + best = chs.best[0]; + LOG_DEBUG("find best hit on other networks"); + } + + }*/ + + if (!best.host.ip) + break; + + best.writeAtoms(atom2,chanInfo.id); + cnt++; + } + + if (!best.host.ip){ + char tmp[50]; +// chanMgr->hitlistlock.on(); + int cnt = chs.getRelayHost(servMgr->serverHost, rhost, remoteID, chl); +// chanMgr->hitlistlock.off(); + for (int i = 0; i < cnt; i++){ + chs.best[i].writeAtoms(atom2, chanInfo.id); + chs.best[i].host.toStr(tmp); + LOG_DEBUG("relay info: %s hops = %d", tmp, chs.best[i].numHops); + best.host.ip = chs.best[i].host.ip; + } + } + + if (cnt) + { + LOG_DEBUG("Sent %d channel hit(s) to %s",cnt,ripStr); + + } + else if (rhost.port) + { + // find firewalled host + chs.init(); + chs.waitDelay = 30; + chs.useFirewalled = true; + chs.excludeID = remoteID; + if (chl->pickHits(chs)) + { + best = chs.best[0]; + int cnt = servMgr->broadcastPushRequest(best,rhost,chl->info.id,Servent::T_RELAY); + LOG_DEBUG("Broadcasted channel push request to %d clients for %s",cnt,ripStr); + } + } + + // if all else fails, use tracker + if (!best.host.ip) + { + // find best tracker on this network if local IP + if (!rhost.globalIP()) + { + chs.init(); + chs.matchHost = servMgr->serverHost; + chs.trackersOnly = true; + chs.excludeID = remoteID; + if (chl->pickHits(chs)) + best = chs.best[0]; + + } + + // find local tracker + if (!best.host.ip) + { + chs.init(); + chs.matchHost = rhost; + chs.trackersOnly = true; + chs.excludeID = remoteID; + if (chl->pickHits(chs)) + best = chs.best[0]; + } + + // find global tracker + if (!best.host.ip) + { + chs.init(); + chs.trackersOnly = true; + chs.excludeID = remoteID; + if (chl->pickHits(chs)) + best = chs.best[0]; + } + + if (best.host.ip) + { + best.writeAtoms(atom2,chanInfo.id); + LOG_DEBUG("Sent 1 tracker hit to %s",ripStr); + }else if (rhost.port) + { + // find firewalled tracker + chs.init(); + chs.useFirewalled = true; + chs.trackersOnly = true; + chs.excludeID = remoteID; + chs.waitDelay = 30; + if (chl->pickHits(chs)) + { + best = chs.best[0]; + int cnt = servMgr->broadcastPushRequest(best,rhost,chl->info.id,Servent::T_CIN); + LOG_DEBUG("Broadcasted tracker push request to %d clients for %s",cnt,ripStr); + } + } + + } + + + } + + chanMgr->hitlistlock.off(); + + // return not available yet code + atom2.writeInt(PCP_QUIT,error); + sock->write(tbuf, mem.getPosition()); + result = false; + + /* + char c[512]; + // wait disconnect from other host + try{ + while(sock->read(c, sizeof(c))){ + sys->sleep(10); + } + }catch(StreamException &e){ + LOG_DEBUG("RelayInfoWait: %s",e.msg); + } + */ + }else + { + LOG_DEBUG("Sending channel unavailable"); + sock->writeLine(HTTP_SC_UNAVAILABLE); + sock->writeLine(""); + result = false; + } + + } else { + + if (chanInfo.contentType != ChanInfo::T_MP3) + addMetadata=false; + + if (addMetadata && (outputProtocol == ChanInfo::SP_HTTP)) // winamp mp3 metadata check + { + + sock->writeLine(ICY_OK); + + sock->writeLineF("%s %s",HTTP_HS_SERVER,PCX_AGENT); + sock->writeLineF("icy-name:%s",chanInfo.name.cstr()); + sock->writeLineF("icy-br:%d",chanInfo.bitrate); + sock->writeLineF("icy-genre:%s",chanInfo.genre.cstr()); + sock->writeLineF("icy-url:%s",chanInfo.url.cstr()); + sock->writeLineF("icy-metaint:%d",chanMgr->icyMetaInterval); + sock->writeLineF("%s %s",PCX_HS_CHANNELID,idStr); + + sock->writeLineF("%s %s",HTTP_HS_CONTENT,MIME_MP3); + + }else + { + + sock->writeLine(HTTP_SC_OK); + + if ((chanInfo.contentType != ChanInfo::T_ASX) && (chanInfo.contentType != ChanInfo::T_WMV) && (chanInfo.contentType != ChanInfo::T_WMA)) + { + sock->writeLineF("%s %s",HTTP_HS_SERVER,PCX_AGENT); + + sock->writeLine("Accept-Ranges: none"); + + sock->writeLineF("x-audiocast-name: %s",chanInfo.name.cstr()); + sock->writeLineF("x-audiocast-bitrate: %d",chanInfo.bitrate); + sock->writeLineF("x-audiocast-genre: %s",chanInfo.genre.cstr()); + sock->writeLineF("x-audiocast-description: %s",chanInfo.desc.cstr()); + sock->writeLineF("x-audiocast-url: %s",chanInfo.url.cstr()); + sock->writeLineF("%s %s",PCX_HS_CHANNELID,idStr); + } + + + if (outputProtocol == ChanInfo::SP_HTTP) + { + switch (chanInfo.contentType) + { + case ChanInfo::T_OGG: + sock->writeLineF("%s %s",HTTP_HS_CONTENT,MIME_XOGG); + break; + case ChanInfo::T_MP3: + sock->writeLineF("%s %s",HTTP_HS_CONTENT,MIME_MP3); + break; + case ChanInfo::T_MOV: + sock->writeLine("Connection: close"); + sock->writeLine("Content-Length: 10000000"); + sock->writeLineF("%s %s",HTTP_HS_CONTENT,MIME_MOV); + break; + case ChanInfo::T_MPG: + sock->writeLineF("%s %s",HTTP_HS_CONTENT,MIME_MPG); + break; + case ChanInfo::T_NSV: + sock->writeLineF("%s %s",HTTP_HS_CONTENT,MIME_NSV); + break; + case ChanInfo::T_ASX: + sock->writeLineF("%s %s",HTTP_HS_CONTENT,MIME_ASX); + break; + case ChanInfo::T_WMA: + sock->writeLineF("%s %s",HTTP_HS_CONTENT,MIME_WMA); + break; + case ChanInfo::T_WMV: + sock->writeLineF("%s %s",HTTP_HS_CONTENT,MIME_WMV); + break; + } + } else if (outputProtocol == ChanInfo::SP_MMS) + { + sock->writeLine("Server: Rex/9.0.0.2980"); + sock->writeLine("Cache-Control: no-cache"); + sock->writeLine("Pragma: no-cache"); + sock->writeLine("Pragma: client-id=3587303426"); + sock->writeLine("Pragma: features=\"broadcast,playlist\""); + + if (nsSwitchNum) + { + sock->writeLineF("%s %s",HTTP_HS_CONTENT,MIME_MMS); + }else + { + sock->writeLine("Content-Type: application/vnd.ms.wms-hdr.asfv1"); + if (ch) + sock->writeLineF("Content-Length: %d",ch->headPack.len); + sock->writeLine("Connection: Keep-Alive"); + } + + } else if (outputProtocol == ChanInfo::SP_PCP) + { + sock->writeLineF("%s %d",PCX_HS_POS,streamPos); + sock->writeLineF("%s %s",HTTP_HS_CONTENT,MIME_XPCP); + + }else if (outputProtocol == ChanInfo::SP_PEERCAST) + { + sock->writeLineF("%s %s",HTTP_HS_CONTENT,MIME_XPEERCAST); + } + } + sock->writeLine(""); + result = true; + + if (gotPCP) + { + handshakeIncomingPCP(atom,rhost,remoteID,agent); + atom.writeInt(PCP_OK,0); + } + + } + + + + return result; +} + +// ----------------------------------- +void Servent::handshakeGiv(GnuID &id) +{ + if (id.isSet()) + { + char idstr[64]; + id.toStr(idstr); + sock->writeLineF("GIV /%s",idstr); + }else + sock->writeLine("GIV"); + + sock->writeLine(""); +} + + +// ----------------------------------- +void Servent::processGnutella() +{ + type = T_PGNU; + + //if (servMgr->isRoot && !servMgr->needConnections()) + if (servMgr->isRoot) + { + processRoot(); + return; + } + + + + gnuStream.init(sock); + setStatus(S_CONNECTED); + + if (!servMgr->isRoot) + { + chanMgr->broadcastRelays(this, 1, 1); + GnuPacket *p; + + if ((p=outPacketsNorm.curr())) + gnuStream.sendPacket(*p); + return; + } + + gnuStream.ping(2); + +// if (type != T_LOOKUP) +// chanMgr->broadcastRelays(this,chanMgr->minBroadcastTTL,2); + + lastPacket = lastPing = sys->getTime(); + bool doneBigPing=false; + + const unsigned int abortTimeoutSecs = 60; // abort connection after 60 secs of no activitiy + const unsigned int packetTimeoutSecs = 30; // ping connection after 30 secs of no activity + + unsigned int currBytes=0; + unsigned int lastWait=0; + + unsigned int lastTotalIn=0,lastTotalOut=0; + + while (thread.active && sock->active()) + { + + if (sock->readReady()) + { + lastPacket = sys->getTime(); + + if (gnuStream.readPacket(pack)) + { + char ipstr[64]; + sock->host.toStr(ipstr); + + GnuID routeID; + GnuStream::R_TYPE ret = GnuStream::R_PROCESS; + + if (pack.func != GNU_FUNC_PONG) + if (servMgr->seenPacket(pack)) + ret = GnuStream::R_DUPLICATE; + + seenIDs.add(pack.id); + + + if (ret == GnuStream::R_PROCESS) + { + GnuID routeID; + ret = gnuStream.processPacket(pack,this,routeID); + + if (flowControl && (ret == GnuStream::R_BROADCAST)) + ret = GnuStream::R_DROP; + + } + + switch(ret) + { + case GnuStream::R_BROADCAST: + if (servMgr->broadcast(pack,this)) + stats.add(Stats::NUMBROADCASTED); + else + stats.add(Stats::NUMDROPPED); + break; + case GnuStream::R_ROUTE: + if (servMgr->route(pack,routeID,NULL)) + stats.add(Stats::NUMROUTED); + else + stats.add(Stats::NUMDROPPED); + break; + case GnuStream::R_ACCEPTED: + stats.add(Stats::NUMACCEPTED); + break; + case GnuStream::R_DUPLICATE: + stats.add(Stats::NUMDUP); + break; + case GnuStream::R_DEAD: + stats.add(Stats::NUMDEAD); + break; + case GnuStream::R_DISCARD: + stats.add(Stats::NUMDISCARDED); + break; + case GnuStream::R_BADVERSION: + stats.add(Stats::NUMOLD); + break; + case GnuStream::R_DROP: + stats.add(Stats::NUMDROPPED); + break; + } + + + LOG_NETWORK("packet in: %s-%s, %d bytes, %d hops, %d ttl, from %s",GNU_FUNC_STR(pack.func),GnuStream::getRouteStr(ret),pack.len,pack.hops,pack.ttl,ipstr); + + + + }else{ + LOG_ERROR("Bad packet"); + } + } + + + GnuPacket *p; + + if ((p=outPacketsPri.curr())) // priority packet + { + gnuStream.sendPacket(*p); + seenIDs.add(p->id); + outPacketsPri.next(); + } else if ((p=outPacketsNorm.curr())) // or.. normal packet + { + gnuStream.sendPacket(*p); + seenIDs.add(p->id); + outPacketsNorm.next(); + } + + int lpt = sys->getTime()-lastPacket; + + if (!doneBigPing) + { + if ((sys->getTime()-lastPing) > 15) + { + gnuStream.ping(7); + lastPing = sys->getTime(); + doneBigPing = true; + } + }else{ + if (lpt > packetTimeoutSecs) + { + + if ((sys->getTime()-lastPing) > packetTimeoutSecs) + { + gnuStream.ping(1); + lastPing = sys->getTime(); + } + + } + } + if (lpt > abortTimeoutSecs) + throw TimeoutException(); + + + unsigned int totIn = sock->totalBytesIn-lastTotalIn; + unsigned int totOut = sock->totalBytesOut-lastTotalOut; + + unsigned int bytes = totIn+totOut; + + lastTotalIn = sock->totalBytesIn; + lastTotalOut = sock->totalBytesOut; + + const int serventBandwidth = 1000; + + int delay = sys->idleSleepTime; + if ((bytes) && (serventBandwidth >= 8)) + delay = (bytes*1000)/(serventBandwidth/8); // set delay relative packetsize + + if (delay < (int)sys->idleSleepTime) + delay = sys->idleSleepTime; + //LOG("delay %d, in %d, out %d",delay,totIn,totOut); + + sys->sleep(delay); + } + +} + + +// ----------------------------------- +void Servent::processRoot() +{ + try + { + + gnuStream.init(sock); + setStatus(S_CONNECTED); + + gnuStream.ping(2); + + unsigned int lastConnect = sys->getTime(); + + while (thread.active && sock->active()) + { + if (gnuStream.readPacket(pack)) + { + char ipstr[64]; + sock->host.toStr(ipstr); + + LOG_NETWORK("packet in: %d from %s",pack.func,ipstr); + + + if (pack.func == GNU_FUNC_PING) // if ping then pong back some hosts and close + { + + Host hl[32]; + int cnt = servMgr->getNewestServents(hl,32,sock->host); + if (cnt) + { + int start = sys->rnd() % cnt; + int max = cnt>8?8:cnt; + + for(int i=0; ihost.toStr(str); + LOG_NETWORK("Sent %d pong(s) to %s",max,str); + }else + { + LOG_NETWORK("No Pongs to send"); + //return; + } + }else if (pack.func == GNU_FUNC_PONG) // pong? + { + MemoryStream pong(pack.data,pack.len); + + int ip,port; + port = pong.readShort(); + ip = pong.readLong(); + ip = SWAP4(ip); + + + Host h(ip,port); + if ((ip) && (port) && (h.globalIP())) + { + + LOG_NETWORK("added pong: %d.%d.%d.%d:%d",ip>>24&0xff,ip>>16&0xff,ip>>8&0xff,ip&0xff,port); + servMgr->addHost(h,ServHost::T_SERVENT,sys->getTime()); + } + //return; + } else if (pack.func == GNU_FUNC_HIT) + { + MemoryStream data(pack.data,pack.len); + ChanHit hit; + gnuStream.readHit(data,hit,pack.hops,pack.id); + } + + //if (gnuStream.packetsIn > 5) // die if we get too many packets + // return; + } + + if((sys->getTime()-lastConnect > 60)) + break; + } + + + }catch(StreamException &e) + { + LOG_ERROR("Relay: %s",e.msg); + } + + +} + +// ----------------------------------- +int Servent::givProc(ThreadInfo *thread) +{ +// thread->lock(); + Servent *sv = (Servent*)thread->data; + try + { + sv->handshakeGiv(sv->givID); + sv->handshakeIncoming(); + + }catch(StreamException &e) + { + LOG_ERROR("GIV: %s",e.msg); + } + + sv->kill(); + sys->endThread(thread); + return 0; +} + +// ----------------------------------- +void Servent::handshakeOutgoingPCP(AtomStream &atom, Host &rhost, GnuID &rid, String &agent, bool isTrusted) +{ + + bool nonFW = (servMgr->getFirewall() != ServMgr::FW_ON); + bool testFW = (servMgr->getFirewall() == ServMgr::FW_UNKNOWN); + + bool sendBCID = isTrusted && chanMgr->isBroadcasting(); + + char tbuf[1024]; + MemoryStream mem(tbuf, sizeof(tbuf)); + AtomStream atom2(mem); + atom2.writeParent(PCP_HELO,3 + (testFW?1:0) + (nonFW?1:0) + (sendBCID?1:0)); + atom2.writeString(PCP_HELO_AGENT,PCX_AGENT); + atom2.writeInt(PCP_HELO_VERSION,PCP_CLIENT_VERSION); + atom2.writeBytes(PCP_HELO_SESSIONID,servMgr->sessionID.id,16); + if (nonFW) + atom2.writeShort(PCP_HELO_PORT,servMgr->serverHost.port); + if (testFW) + atom2.writeShort(PCP_HELO_PING,servMgr->serverHost.port); + if (sendBCID) + atom2.writeBytes(PCP_HELO_BCID,chanMgr->broadcastID.id,16); + atom.io.write(tbuf, mem.getPosition()); + + + LOG_DEBUG("PCP outgoing waiting for OLEH.."); + + int numc,numd; + ID4 id = atom.read(numc,numd); + if (id != PCP_OLEH) + { + LOG_DEBUG("PCP outgoing reply: %s",id.getString().str()); + atom.writeInt(PCP_QUIT,PCP_ERROR_QUIT+PCP_ERROR_BADRESPONSE); + throw StreamException("Got unexpected PCP response"); + } + + + + char arg[64]; + + GnuID clientID; + clientID.clear(); + rid.clear(); + int version=0; + int disable=0; + + Host thisHost; + + // read OLEH response + for(int i=0; isessionID)) + throw StreamException("Servent loopback"); + + }else + { + LOG_DEBUG("PCP handshake skip: %s",id.getString().str()); + atom.skip(c,dlen); + } + + } + + + // update server ip/firewall status + if (isTrusted) + { + if (thisHost.isValid()) + { + if ((servMgr->serverHost.ip != thisHost.ip) && (servMgr->forceIP.isEmpty())) + { + char ipstr[64]; + thisHost.toStr(ipstr); + LOG_DEBUG("Got new ip: %s",ipstr); + servMgr->serverHost.ip = thisHost.ip; + } + + if (servMgr->getFirewall() == ServMgr::FW_UNKNOWN) + { + if (thisHost.port && thisHost.globalIP()) + servMgr->setFirewall(ServMgr::FW_OFF); + else + servMgr->setFirewall(ServMgr::FW_ON); + } + } + + if (disable == 1) + { + LOG_ERROR("client disabled: %d",disable); + servMgr->isDisabled = true; + }else + { + servMgr->isDisabled = false; + } + } + + + + if (!rid.isSet()) + { + atom.writeInt(PCP_QUIT,PCP_ERROR_QUIT+PCP_ERROR_NOTIDENTIFIED); + throw StreamException("Remote host not identified"); + } + + LOG_DEBUG("PCP Outgoing handshake complete."); + +} + +// ----------------------------------- +void Servent::handshakeIncomingPCP(AtomStream &atom, Host &rhost, GnuID &rid, String &agent) +{ + int numc,numd; + ID4 id = atom.read(numc,numd); + + + if (id != PCP_HELO) + { + LOG_DEBUG("PCP incoming reply: %s",id.getString().str()); + atom.writeInt(PCP_QUIT,PCP_ERROR_QUIT+PCP_ERROR_BADRESPONSE); + throw StreamException("Got unexpected PCP response"); + } + + char arg[64]; + + ID4 osType; + + int version=0; + + int pingPort=0; + + GnuID bcID; + GnuID clientID; + + bcID.clear(); + clientID.clear(); + + rhost.port = 0; + + for(int i=0; isessionID)) + throw StreamException("Servent loopback"); + + }else if (id == PCP_HELO_BCID) + { + atom.readBytes(bcID.id,16); + + }else if (id == PCP_HELO_OSTYPE) + { + osType = atom.readInt(); + }else if (id == PCP_HELO_PORT) + { + rhost.port = atom.readShort(); + }else if (id == PCP_HELO_PING) + { + pingPort = atom.readShort(); + }else + { + LOG_DEBUG("PCP handshake skip: %s",id.getString().str()); + atom.skip(c,dlen); + } + + } + + if (version) + LOG_DEBUG("Incoming PCP is %s : v%d", agent.cstr(),version); + + + if (!rhost.globalIP() && servMgr->serverHost.globalIP()) + rhost.ip = servMgr->serverHost.ip; + + if (pingPort) + { + char ripStr[64]; + rhost.toStr(ripStr); + LOG_DEBUG("Incoming firewalled test request: %s ", ripStr); + rhost.port = pingPort; + if (!rhost.globalIP() || !pingHost(rhost,rid)) + rhost.port = 0; + } + + if (servMgr->isRoot) + { + if (bcID.isSet()) + { + if (bcID.getFlags() & 1) // private + { + BCID *bcid = servMgr->findValidBCID(bcID); + if (!bcid || (bcid && !bcid->valid)) + { + atom.writeParent(PCP_OLEH,1); + atom.writeInt(PCP_HELO_DISABLE,1); + throw StreamException("Client is banned"); + } + } + } + } + + + char tbuf[1024]; + MemoryStream mem(tbuf, sizeof(tbuf)); + AtomStream atom2(mem); + atom2.writeParent(PCP_OLEH,5); + atom2.writeString(PCP_HELO_AGENT,PCX_AGENT); + atom2.writeBytes(PCP_HELO_SESSIONID,servMgr->sessionID.id,16); + atom2.writeInt(PCP_HELO_VERSION,PCP_CLIENT_VERSION); + atom2.writeInt(PCP_HELO_REMOTEIP,rhost.ip); + atom2.writeShort(PCP_HELO_PORT,rhost.port); + + if (version) + { + if (version < PCP_CLIENT_MINVERSION) + { + atom2.writeInt(PCP_QUIT,PCP_ERROR_QUIT+PCP_ERROR_BADAGENT); + atom.io.write(tbuf, mem.getPosition()); + throw StreamException("Agent is not valid"); + } + } + + if (!rid.isSet()) + { + atom2.writeInt(PCP_QUIT,PCP_ERROR_QUIT+PCP_ERROR_NOTIDENTIFIED); + atom.io.write(tbuf, mem.getPosition()); + throw StreamException("Remote host not identified"); + } + + + + if (servMgr->isRoot) + { + servMgr->writeRootAtoms(atom2,false); + } + + atom.io.write(tbuf, mem.getPosition()); + + LOG_DEBUG("PCP Incoming handshake complete."); + +} + +// ----------------------------------- +void Servent::processIncomingPCP(bool suggestOthers) +{ + PCPStream::readVersion(*sock); + + + AtomStream atom(*sock); + Host rhost = sock->host; + + handshakeIncomingPCP(atom,rhost,remoteID,agent); + + + bool alreadyConnected = (servMgr->findConnection(Servent::T_COUT,remoteID)!=NULL) + || (servMgr->findConnection(Servent::T_CIN,remoteID)!=NULL); + bool unavailable = servMgr->controlInFull(); + bool offair = !servMgr->isRoot && !chanMgr->isBroadcasting(); + + char rstr[64]; + rhost.toStr(rstr); + + if (unavailable || alreadyConnected || offair) + { + int error; + + if (alreadyConnected) + error = PCP_ERROR_QUIT+PCP_ERROR_ALREADYCONNECTED; + else if (unavailable) + error = PCP_ERROR_QUIT+PCP_ERROR_UNAVAILABLE; + else if (offair) + error = PCP_ERROR_QUIT+PCP_ERROR_OFFAIR; + else + error = PCP_ERROR_QUIT; + + + if (suggestOthers) + { + + ChanHit best; + ChanHitSearch chs; + + int cnt=0; + for(int i=0; i<8; i++) + { + best.init(); + + // find best hit on this network + if (!rhost.globalIP()) + { + chs.init(); + chs.matchHost = servMgr->serverHost; + chs.waitDelay = 2; + chs.excludeID = remoteID; + chs.trackersOnly = true; + chs.useBusyControls = false; + if (chanMgr->pickHits(chs)) + best = chs.best[0]; + } + + // find best hit on same network + if (!best.host.ip) + { + chs.init(); + chs.matchHost = rhost; + chs.waitDelay = 2; + chs.excludeID = remoteID; + chs.trackersOnly = true; + chs.useBusyControls = false; + if (chanMgr->pickHits(chs)) + best = chs.best[0]; + } + + // else find best hit on other networks + if (!best.host.ip) + { + chs.init(); + chs.waitDelay = 2; + chs.excludeID = remoteID; + chs.trackersOnly = true; + chs.useBusyControls = false; + if (chanMgr->pickHits(chs)) + best = chs.best[0]; + } + + if (!best.host.ip) + break; + + GnuID noID; + noID.clear(); + best.writeAtoms(atom,noID); + cnt++; + } + if (cnt) + { + LOG_DEBUG("Sent %d tracker(s) to %s",cnt,rstr); + } + else if (rhost.port) + { + // send push request to best firewalled tracker on other network + chs.init(); + chs.waitDelay = 30; + chs.excludeID = remoteID; + chs.trackersOnly = true; + chs.useFirewalled = true; + chs.useBusyControls = false; + if (chanMgr->pickHits(chs)) + { + best = chs.best[0]; + GnuID noID; + noID.clear(); + int cnt = servMgr->broadcastPushRequest(best,rhost,noID,Servent::T_CIN); + LOG_DEBUG("Broadcasted tracker push request to %d clients for %s",cnt,rstr); + } + }else + { + LOG_DEBUG("No available trackers"); + } + } + + + LOG_ERROR("Sending QUIT to incoming: %d",error); + + atom.writeInt(PCP_QUIT,error); + return; + } + + + type = T_CIN; + setStatus(S_CONNECTED); + + atom.writeInt(PCP_OK,0); + + // ask for update + atom.writeParent(PCP_ROOT,1); + atom.writeParent(PCP_ROOT_UPDATE,0); + + pcpStream = new PCPStream(remoteID); + + int error = 0; + BroadcastState bcs; + while (!error && thread.active && !sock->eof()) + { + error = pcpStream->readPacket(*sock,bcs); + sys->sleepIdle(); + + if (!servMgr->isRoot && !chanMgr->isBroadcasting()) + error = PCP_ERROR_OFFAIR; + if (peercastInst->isQuitting) + error = PCP_ERROR_SHUTDOWN; + } + + pcpStream->flush(*sock); + + error += PCP_ERROR_QUIT; + atom.writeInt(PCP_QUIT,error); + + LOG_DEBUG("PCP Incoming to %s closed: %d",rstr,error); + +} + +// ----------------------------------- +int Servent::outgoingProc(ThreadInfo *thread) +{ +// thread->lock(); + LOG_DEBUG("COUT started"); + + Servent *sv = (Servent*)thread->data; + + GnuID noID; + noID.clear(); + sv->pcpStream = new PCPStream(noID); + + while (sv->thread.active) + { + sv->setStatus(S_WAIT); + + if (chanMgr->isBroadcasting() && servMgr->autoServe) + { + ChanHit bestHit; + ChanHitSearch chs; + char ipStr[64]; + + do + { + bestHit.init(); + + if (servMgr->rootHost.isEmpty()) + break; + + if (sv->pushSock) + { + sv->sock = sv->pushSock; + sv->pushSock = NULL; + bestHit.host = sv->sock->host; + break; + } + + GnuID noID; + noID.clear(); + ChanHitList *chl = chanMgr->findHitListByID(noID); + if (chl) + { + // find local tracker + chs.init(); + chs.matchHost = servMgr->serverHost; + chs.waitDelay = MIN_TRACKER_RETRY; + chs.excludeID = servMgr->sessionID; + chs.trackersOnly = true; + if (!chl->pickHits(chs)) + { + // else find global tracker + chs.init(); + chs.waitDelay = MIN_TRACKER_RETRY; + chs.excludeID = servMgr->sessionID; + chs.trackersOnly = true; + chl->pickHits(chs); + } + + if (chs.numResults) + { + bestHit = chs.best[0]; + } + } + + + unsigned int ctime = sys->getTime(); + + if ((!bestHit.host.ip) && ((ctime-chanMgr->lastYPConnect) > MIN_YP_RETRY)) + { + bestHit.host.fromStrName(servMgr->rootHost.cstr(),DEFAULT_PORT); + bestHit.yp = true; + chanMgr->lastYPConnect = ctime; + } + sys->sleepIdle(); + + }while (!bestHit.host.ip && (sv->thread.active)); + + + if (!bestHit.host.ip) // give up + { + LOG_ERROR("COUT giving up"); + break; + } + + + bestHit.host.toStr(ipStr); + + int error=0; + try + { + + LOG_DEBUG("COUT to %s: Connecting..",ipStr); + + if (!sv->sock) + { + sv->setStatus(S_CONNECTING); + sv->sock = sys->createSocket(); + if (!sv->sock) + throw StreamException("Unable to create socket"); + sv->sock->open(bestHit.host); + sv->sock->connect(); + + } + + sv->sock->setReadTimeout(30000); + AtomStream atom(*sv->sock); + + sv->setStatus(S_HANDSHAKE); + + Host rhost = sv->sock->host; + atom.writeInt(PCP_CONNECT,1); + handshakeOutgoingPCP(atom,rhost,sv->remoteID,sv->agent,bestHit.yp); + + sv->setStatus(S_CONNECTED); + + LOG_DEBUG("COUT to %s: OK",ipStr); + + sv->pcpStream->init(sv->remoteID); + + BroadcastState bcs; + bcs.servent_id = sv->servent_id; + error = 0; + while (!error && sv->thread.active && !sv->sock->eof() && servMgr->autoServe) + { + error = sv->pcpStream->readPacket(*sv->sock,bcs); + + sys->sleepIdle(); + + if (!chanMgr->isBroadcasting()) + error = PCP_ERROR_OFFAIR; + if (peercastInst->isQuitting) + error = PCP_ERROR_SHUTDOWN; + + if (sv->pcpStream->nextRootPacket) + if (sys->getTime() > (sv->pcpStream->nextRootPacket+30)) + error = PCP_ERROR_NOROOT; + } + sv->setStatus(S_CLOSING); + + sv->pcpStream->flush(*sv->sock); + + error += PCP_ERROR_QUIT; + atom.writeInt(PCP_QUIT,error); + + LOG_ERROR("COUT to %s closed: %d",ipStr,error); + + }catch(TimeoutException &e) + { + LOG_ERROR("COUT to %s: timeout (%s)",ipStr,e.msg); + sv->setStatus(S_TIMEOUT); + }catch(StreamException &e) + { + LOG_ERROR("COUT to %s: %s",ipStr,e.msg); + sv->setStatus(S_ERROR); + } + + try + { + if (sv->sock) + { + sv->sock->close(); + delete sv->sock; + sv->sock = NULL; + } + + }catch(StreamException &) {} + + // don`t discard this hit if we caused the disconnect (stopped broadcasting) + if (error != (PCP_ERROR_QUIT+PCP_ERROR_OFFAIR)) + chanMgr->deadHit(bestHit); + + } + + sys->sleepIdle(); + } + + sv->kill(); + sys->endThread(thread); + LOG_DEBUG("COUT ended"); + return 0; +} +// ----------------------------------- +int Servent::incomingProc(ThreadInfo *thread) +{ +// thread->lock(); + + Servent *sv = (Servent*)thread->data; + + char ipStr[64]; + sv->sock->host.toStr(ipStr); + + try + { + sv->handshakeIncoming(); + }catch(HTTPException &e) + { + try + { + sv->sock->writeLine(e.msg); + if (e.code == 401) + sv->sock->writeLine("WWW-Authenticate: Basic realm=\"PeerCast\""); + sv->sock->writeLine(""); + }catch(StreamException &){} + LOG_ERROR("Incoming from %s: %s",ipStr,e.msg); + }catch(StreamException &e) + { + LOG_ERROR("Incoming from %s: %s",ipStr,e.msg); + } + + + sv->kill(); + sys->endThread(thread); + return 0; +} +// ----------------------------------- +void Servent::processServent() +{ + setStatus(S_HANDSHAKE); + + handshakeIn(); + + if (!sock) + throw StreamException("Servent has no socket"); + + processGnutella(); +} + +// ----------------------------------- +void Servent::processStream(bool doneHandshake,ChanInfo &chanInfo) +{ + if (!doneHandshake) + { + setStatus(S_HANDSHAKE); + + if (!handshakeStream(chanInfo)) + return; + } + + if (chanInfo.id.isSet()) + { + + chanID = chanInfo.id; + + LOG_CHANNEL("Sending channel: %s ",ChanInfo::getProtocolStr(outputProtocol)); + + if (!waitForChannelHeader(chanInfo)) + throw StreamException("Channel not ready"); + + servMgr->totalStreams++; + + Host host = sock->host; + host.port = 0; // force to 0 so we ignore the incoming port + + Channel *ch = chanMgr->findChannelByID(chanID); + if (!ch) + throw StreamException("Channel not found"); + + if (outputProtocol == ChanInfo::SP_HTTP) + { + if ((addMetadata) && (chanMgr->icyMetaInterval)) + sendRawMetaChannel(chanMgr->icyMetaInterval); + else + sendRawChannel(true,true); + + }else if (outputProtocol == ChanInfo::SP_MMS) + { + if (nsSwitchNum) + { + sendRawChannel(true,true); + }else + { + sendRawChannel(true,false); + } + + }else if (outputProtocol == ChanInfo::SP_PCP) + { + sendPCPChannel(); + + } else if (outputProtocol == ChanInfo::SP_PEERCAST) + { + sendPeercastChannel(); + } + } + + setStatus(S_CLOSING); +} + +// ----------------------------------------- +#if 0 +// debug + FileStream file; + file.openReadOnly("c://test.mp3"); + + LOG_DEBUG("raw file read"); + char buf[4000]; + int cnt=0; + while (!file.eof()) + { + LOG_DEBUG("send %d",cnt++); + file.read(buf,sizeof(buf)); + sock->write(buf,sizeof(buf)); + + } + file.close(); + LOG_DEBUG("raw file sent"); + + return; +// debug +#endif +// ----------------------------------- +bool Servent::waitForChannelHeader(ChanInfo &info) +{ + for(int i=0; i<30*10; i++) + { + Channel *ch = chanMgr->findChannelByID(info.id); + if (!ch) + return false; + + if (ch->isPlaying() && (ch->rawData.writePos>0)) + return true; + + if (!thread.active || !sock->active()) + break; + sys->sleep(100); + } + return false; +} +// ----------------------------------- +void Servent::sendRawChannel(bool sendHead, bool sendData) +{ + try + { + + sock->setWriteTimeout(DIRECT_WRITE_TIMEOUT*1000); + + Channel *ch = chanMgr->findChannelByID(chanID); + if (!ch) + throw StreamException("Channel not found"); + + setStatus(S_CONNECTED); + + LOG_DEBUG("Starting Raw stream of %s at %d",ch->info.name.cstr(),streamPos); + + if (sendHead) + { + ch->headPack.writeRaw(*sock); + streamPos = ch->headPack.pos + ch->headPack.len; + LOG_DEBUG("Sent %d bytes header ",ch->headPack.len); + } + + if (sendData) + { + + unsigned int streamIndex = ch->streamIndex; + unsigned int connectTime = sys->getTime(); + unsigned int lastWriteTime = connectTime; + + while ((thread.active) && sock->active()) + { + ch = chanMgr->findChannelByID(chanID); + + if (ch) + { + + if (streamIndex != ch->streamIndex) + { + streamIndex = ch->streamIndex; + streamPos = ch->headPack.pos; + LOG_DEBUG("sendRaw got new stream index"); + } + + ChanPacket rawPack; + if (ch->rawData.findPacket(streamPos,rawPack)) + { + if (syncPos != rawPack.sync) + LOG_ERROR("Send skip: %d",rawPack.sync-syncPos); + syncPos = rawPack.sync+1; + + if ((rawPack.type == ChanPacket::T_DATA) || (rawPack.type == ChanPacket::T_HEAD)) + { + rawPack.writeRaw(*sock); + lastWriteTime = sys->getTime(); + } + + if (rawPack.pos < streamPos) + LOG_DEBUG("raw: skip back %d",rawPack.pos-streamPos); + streamPos = rawPack.pos+rawPack.len; + } else if (sock->readReady()) { + char c; + int error = sock->readUpto(&c, 1); + if (error == 0) sock->close(); + } + } + + if ((sys->getTime()-lastWriteTime) > DIRECT_WRITE_TIMEOUT) + throw TimeoutException(); + + sys->sleepIdle(); + } + } + }catch(StreamException &e) + { + LOG_ERROR("Stream channel: %s",e.msg); + } +} + +#if 0 +// ----------------------------------- +void Servent::sendRawMultiChannel(bool sendHead, bool sendData) +{ + try + { + unsigned int chanStreamIndex[ChanMgr::MAX_CHANNELS]; + unsigned int chanStreamPos[ChanMgr::MAX_CHANNELS]; + GnuID chanIDs[ChanMgr::MAX_CHANNELS]; + int numChanIDs=0; + for(int i=0; ichannels[i]; + if (ch->isPlaying()) + chanIDs[numChanIDs++]=ch->info.id; + } + + + + setStatus(S_CONNECTED); + + + if (sendHead) + { + for(int i=0; ifindChannelByID(chanIDs[i]); + if (ch) + { + LOG_DEBUG("Starting RawMulti stream: %s",ch->info.name.cstr()); + ch->headPack.writeRaw(*sock); + chanStreamPos[i] = ch->headPack.pos + ch->headPack.len; + chanStreamIndex[i] = ch->streamIndex; + LOG_DEBUG("Sent %d bytes header",ch->headPack.len); + + } + } + } + + if (sendData) + { + + unsigned int connectTime=sys->getTime(); + + while ((thread.active) && sock->active()) + { + + for(int i=1; ifindChannelByID(chanIDs[i]); + if (ch) + { + if (chanStreamIndex[i] != ch->streamIndex) + { + chanStreamIndex[i] = ch->streamIndex; + chanStreamPos[i] = ch->headPack.pos; + LOG_DEBUG("sendRawMulti got new stream index for chan %d",i); + } + + ChanPacket rawPack; + if (ch->rawData.findPacket(chanStreamPos[i],rawPack)) + { + if ((rawPack.type == ChanPacket::T_DATA) || (rawPack.type == ChanPacket::T_HEAD)) + rawPack.writeRaw(*sock); + + + if (rawPack.pos < chanStreamPos[i]) + LOG_DEBUG("raw: skip back %d",rawPack.pos-chanStreamPos[i]); + chanStreamPos[i] = rawPack.pos+rawPack.len; + + + //LOG("raw at %d: %d %d",streamPos,ch->rawData.getStreamPos(ch->rawData.firstPos),ch->rawData.getStreamPos(ch->rawData.lastPos)); + } + } + break; + } + + + sys->sleepIdle(); + } + } + }catch(StreamException &e) + { + LOG_ERROR("Stream channel: %s",e.msg); + } +} +#endif + +// ----------------------------------- +void Servent::sendRawMetaChannel(int interval) +{ + + try + { + Channel *ch = chanMgr->findChannelByID(chanID); + if (!ch) + throw StreamException("Channel not found"); + + sock->setWriteTimeout(DIRECT_WRITE_TIMEOUT*1000); + + setStatus(S_CONNECTED); + + LOG_DEBUG("Starting Raw Meta stream of %s (metaint: %d) at %d",ch->info.name.cstr(),interval,streamPos); + + + String lastTitle,lastURL; + + int lastMsgTime=sys->getTime(); + bool showMsg=true; + + char buf[16384]; + int bufPos=0; + + if ((interval > sizeof(buf)) || (interval < 1)) + throw StreamException("Bad ICY Meta Interval value"); + + unsigned int connectTime = sys->getTime(); + unsigned int lastWriteTime = connectTime; + + streamPos = 0; // raw meta channel has no header (its MP3) + + while ((thread.active) && sock->active()) + { + ch = chanMgr->findChannelByID(chanID); + + if (ch) + { + + ChanPacket rawPack; + if (ch->rawData.findPacket(streamPos,rawPack)) + { + + if (syncPos != rawPack.sync) + LOG_ERROR("Send skip: %d",rawPack.sync-syncPos); + syncPos = rawPack.sync+1; + + MemoryStream mem(rawPack.data,rawPack.len); + + if (rawPack.type == ChanPacket::T_DATA) + { + + int len = rawPack.len; + char *p = rawPack.data; + while (len) + { + int rl = len; + if ((bufPos+rl) > interval) + rl = interval-bufPos; + memcpy(&buf[bufPos],p,rl); + bufPos+=rl; + p+=rl; + len-=rl; + + if (bufPos >= interval) + { + bufPos = 0; + sock->write(buf,interval); + lastWriteTime = sys->getTime(); + + if (chanMgr->broadcastMsgInterval) + if ((sys->getTime()-lastMsgTime) >= chanMgr->broadcastMsgInterval) + { + showMsg ^= true; + lastMsgTime = sys->getTime(); + } + + String *metaTitle = &ch->info.track.title; + if (!ch->info.comment.isEmpty() && (showMsg)) + metaTitle = &ch->info.comment; + + + if (!metaTitle->isSame(lastTitle) || !ch->info.url.isSame(lastURL)) + { + + char tmp[1024]; + String title,url; + + title = *metaTitle; + url = ch->info.url; + + title.convertTo(String::T_META); + url.convertTo(String::T_META); + + sprintf(tmp,"StreamTitle='%s';StreamUrl='%s';\0",title.cstr(),url.cstr()); + int len = ((strlen(tmp) + 15+1) / 16); + sock->writeChar(len); + sock->write(tmp,len*16); + + lastTitle = *metaTitle; + lastURL = ch->info.url; + + LOG_DEBUG("StreamTitle: %s, StreamURL: %s",lastTitle.cstr(),lastURL.cstr()); + + }else + { + sock->writeChar(0); + } + + } + } + } + streamPos = rawPack.pos + rawPack.len; + } + } + if ((sys->getTime()-lastWriteTime) > DIRECT_WRITE_TIMEOUT) + throw TimeoutException(); + + sys->sleepIdle(); + + } + }catch(StreamException &e) + { + LOG_ERROR("Stream channel: %s",e.msg); + } +} +// ----------------------------------- +void Servent::sendPeercastChannel() +{ + try + { + setStatus(S_CONNECTED); + + Channel *ch = chanMgr->findChannelByID(chanID); + if (!ch) + throw StreamException("Channel not found"); + + LOG_DEBUG("Starting PeerCast stream: %s",ch->info.name.cstr()); + + sock->writeTag("PCST"); + + ChanPacket pack; + + ch->headPack.writePeercast(*sock); + + pack.init(ChanPacket::T_META,ch->insertMeta.data,ch->insertMeta.len,ch->streamPos); + pack.writePeercast(*sock); + + streamPos = 0; + unsigned int syncPos=0; + while ((thread.active) && sock->active()) + { + ch = chanMgr->findChannelByID(chanID); + if (ch) + { + + ChanPacket rawPack; + if (ch->rawData.findPacket(streamPos,rawPack)) + { + if ((rawPack.type == ChanPacket::T_DATA) || (rawPack.type == ChanPacket::T_HEAD)) + { + sock->writeTag("SYNC"); + sock->writeShort(4); + sock->writeShort(0); + sock->write(&syncPos,4); + syncPos++; + + rawPack.writePeercast(*sock); + } + streamPos = rawPack.pos + rawPack.len; + } + } + sys->sleepIdle(); + } + + }catch(StreamException &e) + { + LOG_ERROR("Stream channel: %s",e.msg); + } +} + +//WLock canStreamLock; + +// ----------------------------------- +void Servent::sendPCPChannel() +{ + bool skipCheck = false; + + Channel *ch = chanMgr->findChannelByID(chanID); + if (!ch) + throw StreamException("Channel not found"); + + AtomStream atom(*sock); + + pcpStream = new PCPStream(remoteID); + int error=0; + + try + { + + LOG_DEBUG("Starting PCP stream of channel at %d",streamPos); + + +// setStatus(S_CONNECTED); + + //canStreamLock.on(); + //thread.active = canStream(ch); + //setStatus(S_CONNECTED); + //canStreamLock.off(); + + lastSkipTime = 0; + lastSkipCount = 0; + waitPort = 0; + + if (thread.active){ + atom.writeParent(PCP_CHAN,3 + ((sendHeader)?1:0)); + atom.writeBytes(PCP_CHAN_ID,chanID.id,16); + ch->info.writeInfoAtoms(atom); + ch->info.writeTrackAtoms(atom); + if (sendHeader) + { + atom.writeParent(PCP_CHAN_PKT,3); + atom.writeID4(PCP_CHAN_PKT_TYPE,PCP_CHAN_PKT_HEAD); + atom.writeInt(PCP_CHAN_PKT_POS,ch->headPack.pos); + atom.writeBytes(PCP_CHAN_PKT_DATA,ch->headPack.data,ch->headPack.len); + + streamPos = ch->headPack.pos+ch->headPack.len; + LOG_DEBUG("Sent %d bytes header",ch->headPack.len); + } + } + + unsigned int streamIndex = ch->streamIndex; + + ChanPacket rawPack; + char pbuf[ChanPacket::MAX_DATALEN*3]; + MemoryStream mems(pbuf,sizeof(pbuf)); + AtomStream atom2(mems); + + while (thread.active) + { + + Channel *ch = chanMgr->findChannelByID(chanID); + + if (ch) + { + + if (streamIndex != ch->streamIndex) + { + streamIndex = ch->streamIndex; + streamPos = ch->headPack.pos; + LOG_DEBUG("sendPCPStream got new stream index"); + } + + mems.rewind(); + + if (ch->rawData.findPacket(streamPos,rawPack)) + { + if ((streamPos < rawPack.pos) && !rawPack.skip){ + if (skipCheck){ + char tmp[32]; + getHost().IPtoStr(tmp); + LOG_NETWORK("##### send skipping ##### %d (%d, %d) -> %s", (rawPack.pos - streamPos), streamPos, rawPack.pos, tmp); + + if (sys->getTime() == lastSkipTime) { + LOG_DEBUG("##### skip all buffer"); + streamPos = ch->rawData.getLatestPos(); + continue; + } + + lastSkipTime = sys->getTime(); + lastSkipCount++; + } else { + skipCheck = true; + } + } + + if (rawPack.type == ChanPacket::T_HEAD) + { + atom2.writeParent(PCP_CHAN,2); + atom2.writeBytes(PCP_CHAN_ID,chanID.id,16); + atom2.writeParent(PCP_CHAN_PKT,3); + atom2.writeID4(PCP_CHAN_PKT_TYPE,PCP_CHAN_PKT_HEAD); + atom2.writeInt(PCP_CHAN_PKT_POS,rawPack.pos); + atom2.writeBytes(PCP_CHAN_PKT_DATA,rawPack.data,rawPack.len); + + sock->write(pbuf, mems.getPosition()); + }else if (rawPack.type == ChanPacket::T_DATA) + { + atom2.writeParent(PCP_CHAN,2); + atom2.writeBytes(PCP_CHAN_ID,chanID.id,16); + atom2.writeParent(PCP_CHAN_PKT,3); + atom2.writeID4(PCP_CHAN_PKT_TYPE,PCP_CHAN_PKT_DATA); + atom2.writeInt(PCP_CHAN_PKT_POS,rawPack.pos); + atom2.writeBytes(PCP_CHAN_PKT_DATA,rawPack.data,rawPack.len); + +#ifdef WIN32 + sock->bufferingWrite(pbuf, mems.getPosition()); + lastSkipTime = sock->bufList.lastSkipTime; + lastSkipCount = sock->bufList.skipCount; +#else + sock->write(pbuf, mems.getPosition()); +#endif + } + + if (rawPack.pos < streamPos) + LOG_DEBUG("pcp: skip back %d",rawPack.pos-streamPos); + + //LOG_DEBUG("Sending %d-%d (%d,%d,%d)",rawPack.pos,rawPack.pos+rawPack.len,ch->streamPos,ch->rawData.getLatestPos(),ch->rawData.getOldestPos()); + + streamPos = rawPack.pos+rawPack.len; + } + } else { + pcpStream->flush(*sock); + throw StreamException("Channel not found"); + } + +#ifdef WIN32 + sock->bufferingWrite(NULL, 0); + lastSkipTime = sock->bufList.lastSkipTime; + lastSkipCount = sock->bufList.skipCount; +#endif + BroadcastState bcs; + bcs.servent_id = servent_id; +// error = pcpStream->readPacket(*sock,bcs); + do { + error = pcpStream->readPacket(*sock,bcs); + if (error) + throw StreamException("PCP exception"); + } while (sock->readReady() || pcpStream->outData.numPending()); + + sys->sleepIdle(); + + } + + LOG_DEBUG("PCP channel stream closed normally."); + + }catch(StreamException &e) + { + LOG_ERROR("Stream channel: %s",e.msg); + } + + try + { + atom.writeInt(PCP_QUIT,error); + }catch(StreamException &) {} + +} + +// ----------------------------------- +int Servent::serverProc(ThreadInfo *thread) +{ +// thread->lock(); + + + Servent *sv = (Servent*)thread->data; + + try + { + if (!sv->sock) + throw StreamException("Server has no socket"); + + sv->setStatus(S_LISTENING); + + + char servIP[64]; + sv->sock->host.toStr(servIP); + + if (servMgr->isRoot) + LOG_DEBUG("Root Server started: %s",servIP); + else + LOG_DEBUG("Server started: %s",servIP); + + + while ((thread->active) && (sv->sock->active())) + { + if (servMgr->numActiveOnPort(sv->sock->host.port) < servMgr->maxServIn) + { + ClientSocket *cs = sv->sock->accept(); + if (cs) + { + LOG_DEBUG("accepted incoming"); + Servent *ns = servMgr->allocServent(); + if (ns) + { + servMgr->lastIncoming = sys->getTime(); + ns->servPort = sv->sock->host.port; + ns->networkID = servMgr->networkID; + ns->initIncoming(cs,sv->allow); + }else + LOG_ERROR("Out of servents"); + } + } + sys->sleep(100); + } + }catch(StreamException &e) + { + LOG_ERROR("Server Error: %s:%d",e.msg,e.err); + } + + + LOG_DEBUG("Server stopped"); + + sv->kill(); + sys->endThread(thread); + return 0; +} + +// ----------------------------------- +bool Servent::writeVariable(Stream &s, const String &var) +{ + char buf[1024]; + + if (var == "type") + strcpy(buf,getTypeStr()); + else if (var == "status") + strcpy(buf,getStatusStr()); + else if (var == "address") + { + if (servMgr->enableGetName) //JP-EX s + { + getHost().toStr(buf); + char h_ip[64]; + Host h = getHost(); + h.toStr(h_ip); + +/* ChanHitList *hits[ChanMgr::MAX_HITLISTS]; + int numHits=0; + for(int i=0; ihitlists[i]; + if (chl->isUsed()) + hits[numHits++] = chl; + } + bool ishit,isfw; + ishit = isfw = false; + int numRelay = 0; + if (numHits) + { + for(int k=0; kisUsed()) + { + for (int j=0; jhits[j]; + if (hit->host.isValid() && (h.ip == hit->host.ip)) + { + ishit = true; + if (hit->firewalled) + isfw = true; + numRelay += hit->numRelays; + } + } + } + } + } + strcpy(buf,""); + if (ishit == true) + { + if (isfw == true) + { + if (numRelay== 0) + strcat(buf,""); + else + strcat(buf,""); + } + else + strcat(buf,""); + } + strcat(buf,h_ip); + char h_name[128]; + if (ClientSocket::getHostname(h_name,h.ip)) + { + strcat(buf,"["); + strcat(buf,h_name); + strcat(buf,"]"); + } + if (ishit == true) + { + strcat(buf,""); + } + } //JP-EX e*/ + + + bool isfw = false; + bool isRelay = true; + int numRelay = 0; + ChanHitList *chl = chanMgr->findHitListByID(chanID); + if (chl){ + ChanHit *hit = chl->hit; + while(hit){ + if (hit->host.isValid() && (h.ip == hit->host.ip)){ + isfw = hit->firewalled; + isRelay = hit->relay; + numRelay = hit->numRelays; + break; + } + hit = hit->next; + } + } + strcpy(buf, ""); + if (isfw){ + if (numRelay == 0){ + strcat(buf,""); + } else { + strcat(buf,""); + } + } else { + if (!isRelay){ + if (numRelay==0){ + strcpy(buf,""); + } else { + strcpy(buf,""); + } + } else { + strcpy(buf,""); + } + } + strcat(buf,h_ip); + char h_name[128]; + if (ClientSocket::getHostname(h_name,h.ip)) + { + strcat(buf,"["); + strcat(buf,h_name); + strcat(buf,"]"); + } + strcat(buf,""); + } + else + getHost().toStr(buf); + } + else if (var == "agent") + strcpy(buf,agent.cstr()); + else if (var == "bitrate") + { + if (sock) + { + unsigned int tot = sock->bytesInPerSec+sock->bytesOutPerSec; + sprintf(buf,"%.1f",BYTES_TO_KBPS(tot)); + }else + strcpy(buf,"0"); + }else if (var == "uptime") + { + String uptime; + if (lastConnect) + uptime.setFromStopwatch(sys->getTime()-lastConnect); + else + uptime.set("-"); + strcpy(buf,uptime.cstr()); + }else if (var.startsWith("gnet.")) + { + + float ctime = (float)(sys->getTime()-lastConnect); + if (var == "gnet.packetsIn") + sprintf(buf,"%d",gnuStream.packetsIn); + else if (var == "gnet.packetsInPerSec") + sprintf(buf,"%.1f",ctime>0?((float)gnuStream.packetsIn)/ctime:0); + else if (var == "gnet.packetsOut") + sprintf(buf,"%d",gnuStream.packetsOut); + else if (var == "gnet.packetsOutPerSec") + sprintf(buf,"%.1f",ctime>0?((float)gnuStream.packetsOut)/ctime:0); + else if (var == "gnet.normQueue") + sprintf(buf,"%d",outPacketsNorm.numPending()); + else if (var == "gnet.priQueue") + sprintf(buf,"%d",outPacketsPri.numPending()); + else if (var == "gnet.flowControl") + sprintf(buf,"%d",flowControl?1:0); + else if (var == "gnet.routeTime") + { + int nr = seenIDs.numUsed(); + unsigned int tim = sys->getTime()-seenIDs.getOldest(); + + String tstr; + tstr.setFromStopwatch(tim); + + if (nr) + strcpy(buf,tstr.cstr()); + else + strcpy(buf,"-"); + } + else + return false; + + }else + return false; + + s.writeString(buf); + + return true; +} diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/servent.h b/c:/Git/PeerCast.root/PeerCast/core/common/servent.h new file mode 100644 index 0000000..b1c2241 --- /dev/null +++ b/c:/Git/PeerCast.root/PeerCast/core/common/servent.h @@ -0,0 +1,298 @@ +// ------------------------------------------------ +// File : servent.h +// Date: 4-apr-2002 +// Author: giles +// Desc: +// +// (c) 2002 peercast.org +// ------------------------------------------------ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// ------------------------------------------------ + + +#ifndef _SERVENT_H +#define _SERVENT_H + +// ---------------------------------- +#include "socket.h" +#include "sys.h" +#include "gnutella.h" +#include "channel.h" +#include "http.h" +#include "rtsp.h" +#include "pcp.h" + +class HTML; + +class AtomStream; + +// ---------------------------------- +// Servent handles the actual connection between clients +class Servent +{ +public: + + enum + { + MAX_HASH = 500, // max. amount of packet hashes Servents can store + MAX_OUTPACKETS = 32 // max. output packets per queue (normal/priority) + }; + + enum TYPE + { + T_NONE, // Not allocated + T_INCOMING, // Unknown incoming + T_SERVER, // The main server + T_RELAY, // Outgoing relay + T_DIRECT, // Outgoing direct connection + T_COUT, // PCP out connection + T_CIN, // PCP in connection + T_PGNU // old protocol connection + }; + + enum STATUS + { + S_NONE, + S_CONNECTING, + S_PROTOCOL, + S_HANDSHAKE, + S_CONNECTED, + S_CLOSING, + S_LISTENING, + S_TIMEOUT, + S_REFUSED, + S_VERIFIED, + S_ERROR, + S_WAIT, + S_FREE + }; + + enum PROTOCOL + { + P_UNKNOWN, + P_GNUTELLA06, + P_PCP + }; + + + enum SORT + { + SORT_NAME = 0, + SORT_BITRATE, + SORT_LISTENERS, + SORT_HOSTS, + SORT_TYPE, + SORT_GENRE + }; + + enum ALLOW + { + ALLOW_HTML = 0x01, + ALLOW_BROADCAST = 0x02, + ALLOW_NETWORK = 0x04, + ALLOW_DIRECT = 0x08, + ALLOW_ALL = 0xff + }; + + Servent(int); + ~Servent(); + + void reset(); + bool initServer(Host &); + void initIncoming(ClientSocket *,unsigned int); + void initOutgoing(TYPE); + void initGIV(Host &, GnuID &); + void initPCP(Host &); + + void checkFree(); + + + + + // funcs for handling status/type + void setStatus(STATUS); + static char * getTypeStr(Servent::TYPE t) {return typeMsgs[t];} + char * getTypeStr() {return getTypeStr(type);} + char * getStatusStr() {return statusMsgs[status];} + int getOutput(); + void addBytes(unsigned int); + bool isOlderThan(Servent *s) + { + if (s) + { + unsigned int t = sys->getTime(); + return ((t-lastConnect) > (t-s->lastConnect)); + }else + return true; + } + + + + // static funcs that do the actual work in the servent thread + static THREAD_PROC serverProc(ThreadInfo *); + static THREAD_PROC outgoingProc(ThreadInfo *); + static THREAD_PROC incomingProc(ThreadInfo *); + static THREAD_PROC givProc(ThreadInfo *); + static THREAD_PROC pcpProc(ThreadInfo *); + static THREAD_PROC fetchProc(ThreadInfo *); + + static bool pingHost(Host &,GnuID &); + + bool getLocalURL(char *); + bool getLocalTypeURL(char *, ChanInfo::TYPE); + + // various types of handshaking are needed + void handshakePLS(ChanHitList **, int, bool); + void handshakePLS(ChanInfo &, bool); + + void handshakeHTML(char *); + void handshakeXML(); + void handshakeCMD(char *); + bool handshakeAuth(HTTP &,const char *,bool); + void handshakeIn(); + void handshakeOut(); + + + void processOutPCP(); + void processOutChannel(); + + bool handshakeStream(ChanInfo &); + void handshakeGiv(GnuID &); + + void handshakeICY(Channel::SRC_TYPE,bool); + void handshakeIncoming(); + void handshakePOST(); + void handshakeRTSP(RTSP &); + void handshakeHTTP(HTTP &,bool); + + void handshakeRemoteFile(const char *); + void handshakeLocalFile(const char *); + + static void handshakeOutgoingPCP(AtomStream &,Host &,GnuID &,String &,bool); + static void handshakeIncomingPCP(AtomStream &,Host &,GnuID &,String &); + + void processIncomingPCP(bool); + + bool waitForChannelHeader(ChanInfo &); + ChanInfo findChannel(char *str,ChanInfo &); + + bool writeVariable(Stream &, const String &); + + + // the "mainloop" of servents + void processGnutella(); + void processRoot(); + void processServent(); + void processStream(bool,ChanInfo &); + void processPCP(bool,bool); + + bool procAtoms(AtomStream &); + void procRootAtoms(AtomStream &,int); + void procHeloAtoms(AtomStream &,int,bool); + void procGetAtoms(AtomStream &,int); + + void triggerChannel(char *,ChanInfo::PROTOCOL,bool); + void sendPeercastChannel(); + void sendRawChannel(bool,bool); +// void sendRawMultiChannel(bool,bool); + void sendRawMetaChannel(int); + void sendPCPChannel(); + void checkPCPComms(Channel *, AtomStream &); + + static void readICYHeader(HTTP &, ChanInfo &, char *); + bool canStream(Channel *); + + bool isConnected() {return status == S_CONNECTED;} + bool isListening() {return status == S_LISTENING;} + + bool isAllowed(int); + bool isFiltered(int); + + // connection handling funcs + void createSocket(); + void kill(); + void abort(); + bool isPrivate(); + bool isLocal(); + + + Host getHost(); + + bool outputPacket(GnuPacket &,bool); + bool hasSeenPacket(GnuPacket &p) {return seenIDs.contains(p.id);} + bool acceptGIV(ClientSocket *); + bool sendPacket(ChanPacket &,GnuID &,GnuID &,GnuID &,Servent::TYPE); + + + TYPE type; + STATUS status; + + static char *statusMsgs[],*typeMsgs[]; + GnuStream gnuStream; + GnuPacket pack; + unsigned int lastConnect,lastPing,lastPacket; + String agent; + + GnuIDList seenIDs; + GnuID networkID; + int serventIndex; + + GnuID remoteID; + + GnuID chanID; + + GnuID givID; + + ThreadInfo thread; + + + char loginPassword[64]; + char loginMount[64]; + + bool priorityConnect; + bool addMetadata; + int nsSwitchNum; + + unsigned int allow; + + ClientSocket *sock,*pushSock; + + WLock lock; + + bool sendHeader; + unsigned int syncPos,streamPos; + int servPort; + + ChanInfo::PROTOCOL outputProtocol; + + GnuPacketBuffer outPacketsNorm,outPacketsPri; + + unsigned int bytesPerSecond; + bool flowControl; + + Servent *next; + + PCPStream *pcpStream; + Cookie cookie; + + int servent_id; + unsigned int lastSkipTime; + unsigned int lastSkipCount; + unsigned int waitPort; + + int channel_id; +}; + +extern char *nextCGIarg(char *cp, char *cmd, char *arg); + + +#endif + diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/servhs.cpp b/c:/Git/PeerCast.root/PeerCast/core/common/servhs.cpp new file mode 100644 index 0000000..8e352bf --- /dev/null +++ b/c:/Git/PeerCast.root/PeerCast/core/common/servhs.cpp @@ -0,0 +1,1954 @@ +// ------------------------------------------------ +// File : servhs.cpp +// Date: 4-apr-2002 +// Author: giles +// Desc: +// Servent handshaking, TODO: should be in its own class +// +// (c) 2002 peercast.org +// ------------------------------------------------ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// ------------------------------------------------ + + +#include +#include "servent.h" +#include "servmgr.h" +#include "html.h" +#include "stats.h" +#include "peercast.h" +#include "pcp.h" +#include "version2.h" +#ifdef _DEBUG +#include "chkMemoryLeak.h" +#define DEBUG_NEW new(__FILE__, __LINE__) +#define new DEBUG_NEW +#endif + +// ----------------------------------- +static void termArgs(char *str) +{ + if (str) + { + int slen = strlen(str); + for(int i=0; i= (MAX_CGI_LEN-1)) + break; + } + *arg = 0; + + return cp; +} +// ----------------------------------- +bool getCGIargBOOL(char *a) +{ + return (strcmp(a,"1")==0); +} +// ----------------------------------- +int getCGIargINT(char *a) +{ + return atoi(a); +} + +// ----------------------------------- +void Servent::handshakeHTTP(HTTP &http, bool isHTTP) +{ + char *in = http.cmdLine; + + if (http.isRequest("GET /")) + { + char *fn = in+4; + + char *pt = strstr(fn,HTTP_PROTO1); + if (pt) + pt[-1] = 0; + + if (strncmp(fn,"/admin?",7)==0) + { + if (!isAllowed(ALLOW_HTML)) + throw HTTPException(HTTP_SC_UNAVAILABLE,503); + + + LOG_DEBUG("Admin client"); + handshakeCMD(fn+7); + + }else if (strncmp(fn,"/http/",6)==0) + { + String dirName = fn+6; + + if (!isAllowed(ALLOW_HTML)) + throw HTTPException(HTTP_SC_UNAVAILABLE,503); + + if (!handshakeAuth(http,fn,false)) + throw HTTPException(HTTP_SC_UNAUTHORIZED,401); + + + handshakeRemoteFile(dirName); + + + }else if (strncmp(fn,"/html/",6)==0) + { + String dirName = fn+1; + + if (!isAllowed(ALLOW_HTML)) + throw HTTPException(HTTP_SC_UNAVAILABLE,503); + + if (handshakeAuth(http,fn,true)) + handshakeLocalFile(dirName); + + + }else if (strncmp(fn,"/admin/?",8)==0) + { + if (!isAllowed(ALLOW_HTML)) + throw HTTPException(HTTP_SC_UNAVAILABLE,503); + + LOG_DEBUG("Admin client"); + handshakeCMD(fn+8); + + }else if (strncmp(fn,"/admin.cgi",10)==0) + { + if (!isAllowed(ALLOW_BROADCAST)) + throw HTTPException(HTTP_SC_UNAVAILABLE,503); + + char *pwdArg = getCGIarg(fn,"pass="); + char *songArg = getCGIarg(fn,"song="); + char *mountArg = getCGIarg(fn,"mount="); + char *urlArg = getCGIarg(fn,"url="); + + if (pwdArg && songArg) + { + int i; + int slen = strlen(fn); + for(i=0; ichannel; + while (c) + { + if ((c->status == Channel::S_BROADCASTING) && + (c->info.contentType == ChanInfo::T_MP3) ) + { + // if we have a mount point then check for it, otherwise update all channels. + bool match=true; + + if (mountArg) + match = strcmp(c->mount,mountArg)==0; + + if (match) + { + ChanInfo newInfo = c->info; + newInfo.track.title.set(songArg,String::T_ESC); + newInfo.track.title.convertTo(String::T_UNICODE); + + if (urlArg) + if (urlArg[0]) + newInfo.track.contact.set(urlArg,String::T_ESC); + LOG_CHANNEL("Channel Shoutcast update: %s",songArg); + c->updateInfo(newInfo); + } + } + c=c->next; + } + } + + }else if (strncmp(fn,"/pls/",5)==0) + { + + if (!sock->host.isLocalhost()) + if (!isAllowed(ALLOW_DIRECT) || !isFiltered(ServFilter::F_DIRECT)) + throw HTTPException(HTTP_SC_UNAVAILABLE,503); + + + ChanInfo info; + if (servMgr->getChannel(fn+5,info,isPrivate())) + handshakePLS(info,false); + else + throw HTTPException(HTTP_SC_NOTFOUND,404); + + }else if (strncmp(fn,"/stream/",8)==0) + { + + if (!sock->host.isLocalhost()) + if (!isAllowed(ALLOW_DIRECT) || !isFiltered(ServFilter::F_DIRECT)) + throw HTTPException(HTTP_SC_UNAVAILABLE,503); + + triggerChannel(fn+8,ChanInfo::SP_HTTP,isPrivate()); + + + }else if (strncmp(fn,"/channel/",9)==0) + { + + if (!sock->host.isLocalhost()) + if (!isAllowed(ALLOW_NETWORK) || !isFiltered(ServFilter::F_NETWORK)) + throw HTTPException(HTTP_SC_UNAVAILABLE,503); + + triggerChannel(fn+9,ChanInfo::SP_PCP,false); + + }else + { + while (http.nextHeader()); + http.writeLine(HTTP_SC_FOUND); + http.writeLineF("Location: /%s/index.html",servMgr->htmlPath); + http.writeLine(""); + } + } + else if (http.isRequest("POST /")) + { + char *fn = in+5; + + char *pt = strstr(fn,HTTP_PROTO1); + if (pt) + pt[-1] = 0; + + if (strncmp(fn,"/pls/",5)==0) + { + + if (!sock->host.isLocalhost()) + if (!isAllowed(ALLOW_DIRECT) || !isFiltered(ServFilter::F_DIRECT)) + throw HTTPException(HTTP_SC_UNAVAILABLE,503); + + + ChanInfo info; + if (servMgr->getChannel(fn+5,info,isPrivate())) + handshakePLS(info,false); + else + throw HTTPException(HTTP_SC_NOTFOUND,404); + + }else if (strncmp(fn,"/stream/",8)==0) + { + + if (!sock->host.isLocalhost()) + if (!isAllowed(ALLOW_DIRECT) || !isFiltered(ServFilter::F_DIRECT)) + throw HTTPException(HTTP_SC_UNAVAILABLE,503); + + triggerChannel(fn+8,ChanInfo::SP_HTTP,isPrivate()); + + }else if (strncmp(fn,"/admin",7)==0) + { + if (!isAllowed(ALLOW_HTML)) + throw HTTPException(HTTP_SC_UNAVAILABLE,503); + + + LOG_DEBUG("Admin client"); + while(http.nextHeader()){ + LOG_DEBUG("%s",http.cmdLine); + } + char buf[8192]; + if (sock->readLine(buf, sizeof(buf)) != 0){ + handshakeCMD(buf); + } + + }else + { + while (http.nextHeader()); + http.writeLine(HTTP_SC_FOUND); + http.writeLineF("Location: /%s/index.html",servMgr->htmlPath); + http.writeLine(""); + } + }else if (http.isRequest("GIV")) + { + HTTP http(*sock); + + while (http.nextHeader()) ; + + if (!isAllowed(ALLOW_NETWORK)) + throw HTTPException(HTTP_SC_UNAVAILABLE,503); + + GnuID id; + id.clear(); + + char *idstr = strstr(in,"/"); + if (idstr) + id.fromStr(idstr+1); + + char ipstr[64]; + sock->host.toStr(ipstr); + + if (id.isSet()) + { + // at the moment we don`t really care where the GIV came from, so just give to chan. no. if its waiting. + Channel *ch = chanMgr->findChannelByID(id); + + if (!ch) + throw HTTPException(HTTP_SC_NOTFOUND,404); + + if (!ch->acceptGIV(sock)) + throw HTTPException(HTTP_SC_UNAVAILABLE,503); + + + LOG_DEBUG("Accepted GIV channel %s from: %s",idstr,ipstr); + + sock=NULL; // release this servent but dont close socket. + }else + { + + if (!servMgr->acceptGIV(sock)) + throw HTTPException(HTTP_SC_UNAVAILABLE,503); + + LOG_DEBUG("Accepted GIV PCP from: %s",ipstr); + sock=NULL; // release this servent but dont close socket. + } + + }else if (http.isRequest(PCX_PCP_CONNECT)) + { + + if (!isAllowed(ALLOW_NETWORK) || !isFiltered(ServFilter::F_NETWORK)) + throw HTTPException(HTTP_SC_UNAVAILABLE,503); + + processIncomingPCP(true); + + }else if (http.isRequest("PEERCAST CONNECT")) + { + if (!isAllowed(ALLOW_NETWORK) || !isFiltered(ServFilter::F_NETWORK)) + throw HTTPException(HTTP_SC_UNAVAILABLE,503); + + LOG_DEBUG("PEERCAST client"); + processServent(); + + }else if (http.isRequest("SOURCE")) + { + if (!isAllowed(ALLOW_BROADCAST)) + throw HTTPException(HTTP_SC_UNAVAILABLE,503); + + char *mount = NULL; + + char *ps; + if (ps=strstr(in,"ICE/1.0")) + { + mount = in+7; + *ps = 0; + LOG_DEBUG("ICE 1.0 client to %s",mount?mount:"unknown"); + }else{ + mount = in+strlen(in); + while (*--mount) + if (*mount == '/') + { + mount[-1] = 0; // password preceeds + break; + } + strcpy(loginPassword,in+7); + + LOG_DEBUG("ICY client: %s %s",loginPassword,mount?mount:"unknown"); + } + + if (mount) + strcpy(loginMount,mount); + + handshakeICY(Channel::SRC_ICECAST,isHTTP); + sock = NULL; // socket is taken over by channel, so don`t close it + + }else if (http.isRequest(servMgr->password)) + { + if (!isAllowed(ALLOW_BROADCAST)) + throw HTTPException(HTTP_SC_UNAVAILABLE,503); + + strcpy(loginPassword,servMgr->password); // pwd already checked + + sock->writeLine("OK2"); + sock->writeLine("icy-caps:11"); + sock->writeLine(""); + LOG_DEBUG("ShoutCast client"); + + handshakeICY(Channel::SRC_SHOUTCAST,isHTTP); + sock = NULL; // socket is taken over by channel, so don`t close it + + }else + { + throw HTTPException(HTTP_SC_BADREQUEST,400); + } + +} +// ----------------------------------- +bool Servent::canStream(Channel *ch) +{ + if (ch==NULL) + return false; + + if (servMgr->isDisabled) + return false; + + if (!isPrivate()) + { + Channel *c = chanMgr->channel; + int noRelay = 0; + unsigned int needRate = 0; + unsigned int allRate = 0; + while(c){ + if (c->isPlaying()){ + allRate += c->info.bitrate * c->localRelays(); + if ((c != ch) && (c->localRelays() == 0)){ + if(!isIndexTxt(c)) // for PCRaw (relay) + noRelay++; + needRate+=c->info.bitrate; + } + } + c = c->next; + } + int diff = servMgr->maxRelays - servMgr->numStreams(Servent::T_RELAY,false); + if (ch->localRelays()){ + if (noRelay > diff){ + noRelay = diff; + } + } else { + noRelay = 0; + needRate = 0; + } + + // for PCRaw (relay) start. + bool force_off = true; + + if(isIndexTxt(ch)) + force_off = false; + // for PCRaw (relay) end. + + LOG_DEBUG("Relay check: Max=%d Now=%d Need=%d ch=%d", + servMgr->maxBitrateOut, allRate, needRate, ch->info.bitrate); + if ( !ch->isPlaying() + || ch->isFull() +// || servMgr->bitrateFull(needRate+ch->getBitrate()) + || (allRate + needRate + ch->info.bitrate > servMgr->maxBitrateOut) + || ((type == T_RELAY) && servMgr->relaysFull() && force_off) // for PCRaw (relay) (force_off) + || ((type == T_RELAY) && (((servMgr->numStreams(Servent::T_RELAY,false) + noRelay) >= servMgr->maxRelays)) && force_off) // for PCRaw (relay) (force_off) + || ((type == T_DIRECT) && servMgr->directFull()) + ){ + LOG_DEBUG("Relay check: NG"); + return false; + } + } + + LOG_DEBUG("Relay check: OK"); + return true; +} +// ----------------------------------- +void Servent::handshakeIncoming() +{ + + setStatus(S_HANDSHAKE); + + char buf[2048]; + sock->readLine(buf,sizeof(buf)); + + char sb[64]; + sock->host.toStr(sb); + + + if (stristr(buf,RTSP_PROTO1)) + { + LOG_DEBUG("RTSP from %s '%s'",sb,buf); + RTSP rtsp(*sock); + rtsp.initRequest(buf); + handshakeRTSP(rtsp); + }else if (stristr(buf,HTTP_PROTO1)) + { + LOG_DEBUG("HTTP from %s '%s'",sb,buf); + HTTP http(*sock); + http.initRequest(buf); + handshakeHTTP(http,true); + }else + { + LOG_DEBUG("Connect from %s '%s'",sb,buf); + HTTP http(*sock); + http.initRequest(buf); + handshakeHTTP(http,false); + } + +} +// ----------------------------------- +void Servent::triggerChannel(char *str, ChanInfo::PROTOCOL proto,bool relay) +{ + + ChanInfo info; +// WLockBlock lb(&(chanMgr->channellock)); + +// LOG_DEBUG("----------triggerChannel LOCK ON"); +// lb.on(); + servMgr->getChannel(str,info,relay); +// LOG_DEBUG("==========triggerChannel LOCK OFF"); +// lb.off(); + + if (proto == ChanInfo::SP_PCP) + type = T_RELAY; + else + type = T_DIRECT; + + outputProtocol = proto; + + processStream(false,info); + +} +// ----------------------------------- +void writePLSHeader(Stream &s, PlayList::TYPE type) +{ + s.writeLine(HTTP_SC_OK); + s.writeLineF("%s %s",HTTP_HS_SERVER,PCX_AGENT); + + const char *content; + switch(type) + { + case PlayList::T_PLS: + content = MIME_XM3U; + break; + case PlayList::T_ASX: + content = MIME_ASX; + break; + case PlayList::T_RAM: + content = MIME_RAM; + break; + default: + content = MIME_TEXT; + break; + } + s.writeLineF("%s %s",HTTP_HS_CONTENT,content); + s.writeLine("Content-Disposition: inline"); + s.writeLine("Cache-Control: private" ); + s.writeLineF("%s %s",HTTP_HS_CONNECTION,"close"); + + s.writeLine(""); +} + +// ----------------------------------- +void Servent::handshakePLS(ChanInfo &info, bool doneHandshake) +{ + char url[256]; + + char in[128]; + + if (!doneHandshake) + while (sock->readLine(in,128)); + + + if (getLocalTypeURL(url,info.contentType)) + { + + PlayList::TYPE type; + + if ((info.contentType == ChanInfo::T_WMA) || (info.contentType == ChanInfo::T_WMV)) + type = PlayList::T_ASX; + else if (info.contentType == ChanInfo::T_OGM) + type = PlayList::T_RAM; + else + type = PlayList::T_PLS; + + writePLSHeader(*sock,type); + + PlayList *pls; + + pls = new PlayList(type,1); + + pls->addChannel(url,info); + + pls->write(*sock); + + delete pls; + } +} +// ----------------------------------- +void Servent::handshakePLS(ChanHitList **cl, int num, bool doneHandshake) +{ + char url[256]; + char in[128]; + + if (!doneHandshake) + while (sock->readLine(in,128)); + + if (getLocalURL(url)) + { + writePLSHeader(*sock,PlayList::T_SCPLS); + + PlayList *pls; + + pls = new PlayList(PlayList::T_SCPLS,num); + + for(int i=0; iaddChannel(url,cl[i]->info); + + pls->write(*sock); + + delete pls; + } +} +// ----------------------------------- +bool Servent::getLocalURL(char *str) +{ + if (!sock) + throw StreamException("Not connected"); + + + char ipStr[64]; + + Host h; + + if (sock->host.localIP()) + h = sock->getLocalHost(); + else + h = servMgr->serverHost; + + h.port = servMgr->serverHost.port; + + h.toStr(ipStr); + + sprintf(str,"http://%s",ipStr); + return true; +} + +// ----------------------------------- +bool Servent::getLocalTypeURL(char *str, ChanInfo::TYPE type) +{ + if (!sock) + throw StreamException("Not connected"); + + + char ipStr[64]; + + Host h; + + if (sock->host.localIP()) + h = sock->getLocalHost(); + else + h = servMgr->serverHost; + + h.port = servMgr->serverHost.port; + + h.toStr(ipStr); + switch(type) { + case ChanInfo::T_WMA: + case ChanInfo::T_WMV: + sprintf(str,"mms://%s",ipStr); + break; + default: + sprintf(str,"http://%s",ipStr); + } + return true; +} +// ----------------------------------- +// Warning: testing RTSP/RTP stuff below. +// .. moved over to seperate app now. +// ----------------------------------- +void Servent::handshakePOST() +{ + char tmp[1024]; + while (sock->readLine(tmp,sizeof(tmp))) + LOG_DEBUG("POST: %s",tmp); + + throw HTTPException(HTTP_SC_BADREQUEST,400); +} + + +// ----------------------------------- +void Servent::handshakeRTSP(RTSP &rtsp) +{ + throw HTTPException(HTTP_SC_BADREQUEST,400); +} +// ----------------------------------- +bool Servent::handshakeAuth(HTTP &http,const char *args,bool local) +{ + char user[1024],pass[1024]; + user[0] = pass[0] = 0; + + char *pwd = getCGIarg(args, "pass="); + + if ((pwd) && strlen(servMgr->password)) + { + String tmp = pwd; + char *as = strstr(tmp.cstr(),"&"); + if (as) *as = 0; + if (strcmp(tmp,servMgr->password)==0) + { + while (http.nextHeader()); + return true; + } + } + + Cookie gotCookie; + cookie.clear(); + + while (http.nextHeader()) + { + char *arg = http.getArgStr(); + if (!arg) + continue; + + switch (servMgr->authType) + { + case ServMgr::AUTH_HTTPBASIC: + if (http.isHeader("Authorization")) + http.getAuthUserPass(user,pass); + break; + case ServMgr::AUTH_COOKIE: + if (http.isHeader("Cookie")) + { + LOG_DEBUG("Got cookie: %s",arg); + char *idp=arg; + while ((idp = strstr(idp,"id="))) + { + idp+=3; + gotCookie.set(idp,sock->host.ip); + if (servMgr->cookieList.contains(gotCookie)) + { + LOG_DEBUG("Cookie found"); + cookie = gotCookie; + break; + } + + } + } + break; + } + } + + if (sock->host.isLocalhost()) + return true; + + + switch (servMgr->authType) + { + case ServMgr::AUTH_HTTPBASIC: + + if ((strcmp(pass,servMgr->password)==0) && strlen(servMgr->password)) + return true; + break; + case ServMgr::AUTH_COOKIE: + if (servMgr->cookieList.contains(cookie)) + return true; + break; + } + + + + if (servMgr->authType == ServMgr::AUTH_HTTPBASIC) + { + http.writeLine(HTTP_SC_UNAUTHORIZED); + http.writeLine("WWW-Authenticate: Basic realm=\"PeerCast Admin\""); + }else if (servMgr->authType == ServMgr::AUTH_COOKIE) + { + String file = servMgr->htmlPath; + file.append("/login.html"); + if (local) + handshakeLocalFile(file); + else + handshakeRemoteFile(file); + } + + + return false; +} + +// ----------------------------------- +void Servent::handshakeCMD(char *cmd) +{ + char result[MAX_CGI_LEN]; + char arg[MAX_CGI_LEN]; + char curr[MAX_CGI_LEN]; + + char jumpStr[128]; + char *jumpArg=NULL; + bool retHTML=true; + strcpy(result,"OK"); + + HTTP http(*sock); + HTML html("",*sock); + + + if (!handshakeAuth(http,cmd,true)) + return; + + try + { + if (cmpCGIarg(cmd,"cmd=","redirect")) + { + char *j = getCGIarg(cmd,"url="); + if (j) + { + termArgs(cmd); + String url; + url.set(j,String::T_ESC); + url.convertTo(String::T_ASCII); + + if (!url.contains("http://")) + url.prepend("http://"); + + html.setRefreshURL(url.cstr()); + html.startHTML(); + html.addHead(); + html.startBody(); + html.startTagEnd("h3","Please wait..."); + html.end(); + html.end(); + + } + }else{ + + if (cmpCGIarg(cmd,"cmd=","viewxml")) + { + + handshakeXML(); + retHTML = false; + }else if (cmpCGIarg(cmd,"cmd=","clearlog")) + { + sys->logBuf->clear(); + sprintf(jumpStr,"/%s/viewlog.html",servMgr->htmlPath); + jumpArg = jumpStr; + + }else if (cmpCGIarg(cmd,"cmd=","save")) + { + + peercastInst->saveSettings(); + + sprintf(jumpStr,"/%s/settings.html",servMgr->htmlPath); + jumpArg = jumpStr; + }else if (cmpCGIarg(cmd,"cmd=","reg")) + { + char idstr[128]; + chanMgr->broadcastID.toStr(idstr); + sprintf(jumpStr,"http://www.peercast.org/register/?id=%s",idstr); + jumpArg = jumpStr; + }else if (cmpCGIarg(cmd,"cmd=","edit_bcid")) + { + char *cp = cmd; + GnuID id; + BCID *bcid; + while (cp=nextCGIarg(cp,curr,arg)) + { + if (strcmp(curr,"id")==0) + id.fromStr(arg); + else if (strcmp(curr,"del")==0) + servMgr->removeValidBCID(id); + else if (strcmp(curr,"valid")==0) + { + bcid = servMgr->findValidBCID(id); + if (bcid) + bcid->valid = getCGIargBOOL(arg); + } + } + peercastInst->saveSettings(); + sprintf(jumpStr,"/%s/bcid.html",servMgr->htmlPath); + jumpArg = jumpStr; + + }else if (cmpCGIarg(cmd,"cmd=","add_bcid")) + { + BCID *bcid = new BCID(); + + char *cp = cmd; + bool result=false; + while (cp=nextCGIarg(cp,curr,arg)) + { + if (strcmp(curr,"id")==0) + bcid->id.fromStr(arg); + else if (strcmp(curr,"name")==0) + bcid->name.set(arg); + else if (strcmp(curr,"email")==0) + bcid->email.set(arg); + else if (strcmp(curr,"url")==0) + bcid->url.set(arg); + else if (strcmp(curr,"valid")==0) + bcid->valid = getCGIargBOOL(arg); + else if (strcmp(curr,"result")==0) + result = true; + + } + + LOG_DEBUG("Adding BCID : %s",bcid->name.cstr()); + servMgr->addValidBCID(bcid); + peercastInst->saveSettings(); + if (result) + { + http.writeLine(HTTP_SC_OK); + http.writeLine(""); + http.writeString("OK"); + }else + { + sprintf(jumpStr,"/%s/bcid.html",servMgr->htmlPath); + jumpArg = jumpStr; + } + + + }else if (cmpCGIarg(cmd,"cmd=","apply")) + { + //servMgr->numFilters = 0; + ServFilter *currFilter=servMgr->filters; + bool beginfilt = false; + + bool brRoot=false; + bool getUpd=false; + int showLog=0; + int allowServer1=0; + int allowServer2=0; + int newPort=servMgr->serverHost.port; + int enableGetName = 0; + int allowConnectPCST = 0; + + char *cp = cmd; + while (cp=nextCGIarg(cp,curr,arg)) + { + // server + if (strcmp(curr,"serveractive")==0) + servMgr->autoServe = getCGIargBOOL(arg); + else if (strcmp(curr,"port")==0) + newPort = getCGIargINT(arg); + else if (strcmp(curr,"icymeta")==0) + { + int iv = getCGIargINT(arg); + if (iv < 0) iv = 0; + else if (iv > 16384) iv = 16384; + + chanMgr->icyMetaInterval = iv; + + }else if (strcmp(curr,"passnew")==0) + strcpy(servMgr->password,arg); + else if (strcmp(curr,"root")==0) + servMgr->isRoot = getCGIargBOOL(arg); + else if (strcmp(curr,"brroot")==0) + brRoot = getCGIargBOOL(arg); + else if (strcmp(curr,"getupd")==0) + getUpd = getCGIargBOOL(arg); + else if (strcmp(curr,"huint")==0) + chanMgr->setUpdateInterval(getCGIargINT(arg)); + else if (strcmp(curr,"forceip")==0) + servMgr->forceIP = arg; + else if (strcmp(curr,"htmlPath")==0) + { + strcpy(servMgr->htmlPath,"html/"); + strcat(servMgr->htmlPath,arg); + }else if (strcmp(curr,"djmsg")==0) + { + String msg; + msg.set(arg,String::T_ESC); + msg.convertTo(String::T_UNICODE); + chanMgr->setBroadcastMsg(msg); + } + else if (strcmp(curr,"pcmsg")==0) + { + servMgr->rootMsg.set(arg,String::T_ESC); + servMgr->rootMsg.convertTo(String::T_UNICODE); + }else if (strcmp(curr,"minpgnu")==0) + servMgr->minGnuIncoming = atoi(arg); + else if (strcmp(curr,"maxpgnu")==0) + servMgr->maxGnuIncoming = atoi(arg); + + + + // connections + else if (strcmp(curr,"maxcin")==0) + servMgr->maxControl = getCGIargINT(arg); + + else if (strcmp(curr,"maxup")==0) + servMgr->maxBitrateOut = getCGIargINT(arg); + else if (strcmp(curr,"maxrelays")==0) + servMgr->setMaxRelays(getCGIargINT(arg)); + else if (strcmp(curr,"maxdirect")==0) + servMgr->maxDirect = getCGIargINT(arg); + else if (strcmp(curr,"maxrelaypc")==0) + chanMgr->maxRelaysPerChannel = getCGIargINT(arg); + else if (strncmp(curr,"filt_",5)==0) + { + if (!beginfilt) { + servMgr->numFilters = 0; + beginfilt = true; + } + char *fs = curr+5; + { + if (strncmp(fs,"ip",2)==0) // ip must be first + { + currFilter = &servMgr->filters[servMgr->numFilters]; + currFilter->init(); + currFilter->host.fromStrIP(arg,DEFAULT_PORT); + if ((currFilter->host.ip) && (servMgr->numFilters < (ServMgr::MAX_FILTERS-1))) + { + servMgr->numFilters++; + servMgr->filters[servMgr->numFilters].init(); // clear new entry + } + + }else if (strncmp(fs,"bn",2)==0) + currFilter->flags |= ServFilter::F_BAN; + else if (strncmp(fs,"pr",2)==0) + currFilter->flags |= ServFilter::F_PRIVATE; + else if (strncmp(fs,"nw",2)==0) + currFilter->flags |= ServFilter::F_NETWORK; + else if (strncmp(fs,"di",2)==0) + currFilter->flags |= ServFilter::F_DIRECT; + } + } + + // client + else if (strcmp(curr,"clientactive")==0) + servMgr->autoConnect = getCGIargBOOL(arg); + else if (strcmp(curr,"yp")==0) + { + if (!PCP_FORCE_YP) + { + String str(arg,String::T_ESC); + str.convertTo(String::T_ASCII); + servMgr->rootHost = str; + } + } + else if (strcmp(curr,"yp2")==0) + { + if (!PCP_FORCE_YP) + { + String str(arg,String::T_ESC); + str.convertTo(String::T_ASCII); + servMgr->rootHost2 = str; + } + } + else if (strcmp(curr,"deadhitage")==0) + chanMgr->deadHitAge = getCGIargINT(arg); + else if (strcmp(curr,"refresh")==0) + servMgr->refreshHTML = getCGIargINT(arg); + else if (strcmp(curr,"auth")==0) + { + if (strcmp(arg,"cookie")==0) + servMgr->authType = ServMgr::AUTH_COOKIE; + else if (strcmp(arg,"http")==0) + servMgr->authType = ServMgr::AUTH_HTTPBASIC; + + }else if (strcmp(curr,"expire")==0) + { + if (strcmp(arg,"session")==0) + servMgr->cookieList.neverExpire = false; + else if (strcmp(arg,"never")==0) + servMgr->cookieList.neverExpire = true; + } + + else if (strcmp(curr,"logDebug")==0) + showLog |= atoi(arg)?(1<autoRelayKeep = getCGIargINT(arg); + else if (strcmp(curr, "autoMaxRelaySetting") ==0) + servMgr->autoMaxRelaySetting = getCGIargINT(arg); + else if (strcmp(curr, "autoBumpSkipCount") ==0) + servMgr->autoBumpSkipCount = getCGIargINT(arg); + else if (strcmp(curr, "kickPushStartRelays") ==0) + servMgr->kickPushStartRelays = getCGIargINT(arg); + else if (strcmp(curr, "kickPushInterval") ==0) + servMgr->kickPushInterval = getCGIargINT(arg); + else if (strcmp(curr, "allowConnectPCST") ==0) + allowConnectPCST = atoi(arg) ? 1 : 0; + else if (strcmp(curr, "enableGetName") ==0) + enableGetName = atoi(arg)? 1 : 0; + else if (strcmp(curr, "autoPort0Kick") ==0) + servMgr->autoPort0Kick = getCGIargBOOL(arg); + else if (strcmp(curr, "allowOnlyVP") ==0) + servMgr->allowOnlyVP = getCGIargBOOL(arg); + else if (strcmp(curr, "kickKeepTime") ==0) + servMgr->kickKeepTime = getCGIargINT(arg); + + else if (strcmp(curr, "maxRelaysIndexTxt") ==0) // for PCRaw (relay) + servMgr->maxRelaysIndexTxt = getCGIargINT(arg); + } + + + + servMgr->showLog = showLog; + servMgr->allowServer1 = allowServer1; + servMgr->allowServer2 = allowServer2; + servMgr->enableGetName = enableGetName; + servMgr->allowConnectPCST = allowConnectPCST; + if (!(servMgr->allowServer1 & ALLOW_HTML) && !(servMgr->allowServer2 & ALLOW_HTML)) + servMgr->allowServer1 |= ALLOW_HTML; + + if (servMgr->serverHost.port != newPort) + { + Host lh(ClientSocket::getIP(NULL),newPort); + char ipstr[64]; + lh.toStr(ipstr); + sprintf(jumpStr,"http://%s/%s/settings.html",ipstr,servMgr->htmlPath); + + servMgr->serverHost.port = newPort; + servMgr->restartServer=true; + //html.setRefresh(3); + //html.setRefreshURL(jumpStr); + //html.startHTML(); + //html.addHead(); + // html.startBody(); + // html.startTagEnd("h1","Please wait..."); + // html.end(); + //html.end(); + + + + //char ipstr[64]; + //servMgr->serverHost.toStr(ipstr); + //sprintf(jumpStr,"/%s/settings.html",ipstr,servMgr->htmlPath); + jumpArg = jumpStr; + + }else + { + sprintf(jumpStr,"/%s/settings.html",servMgr->htmlPath); + jumpArg = jumpStr; + } + + peercastInst->saveSettings(); + + peercastApp->updateSettings(); + + if ((servMgr->isRoot) && (brRoot)) + servMgr->broadcastRootSettings(getUpd); + + + + + + }else if (cmpCGIarg(cmd,"cmd=","fetch")) + { + + ChanInfo info; + String curl; + + char *cp = cmd; + while (cp=nextCGIarg(cp,curr,arg)) + { + if (strcmp(curr,"url")==0) + { + curl.set(arg,String::T_ESC); + curl.convertTo(String::T_UNICODE); + }else if (strcmp(curr,"name")==0) + { + info.name.set(arg,String::T_ESC); + info.name.convertTo(String::T_UNICODE); + }else if (strcmp(curr,"desc")==0) + { + info.desc.set(arg,String::T_ESC); + info.desc.convertTo(String::T_UNICODE); + }else if (strcmp(curr,"genre")==0) + { + info.genre.set(arg,String::T_ESC); + info.genre.convertTo(String::T_UNICODE); + }else if (strcmp(curr,"contact")==0) + { + info.url.set(arg,String::T_ESC); + info.url.convertTo(String::T_UNICODE); + }else if (strcmp(curr,"bitrate")==0) + { + info.bitrate = atoi(arg); + }else if (strcmp(curr,"type")==0) + { + info.contentType = ChanInfo::getTypeFromStr(arg); + } + + } + + info.bcID = chanMgr->broadcastID; + + Channel *c = chanMgr->createChannel(info,NULL); + if (c) + c->startURL(curl.cstr()); + + + sprintf(jumpStr,"/%s/relays.html",servMgr->htmlPath); + jumpArg = jumpStr; + + }else if (cmpCGIarg(cmd,"cmd=","stopserv")) + { + + char *cp = cmd; + while (cp=nextCGIarg(cp,curr,arg)) + { + if (strcmp(curr,"index")==0) + { + Servent *s = servMgr->findServentByIndex(atoi(arg)); + if (s) + s->abort(); + } + } + sprintf(jumpStr,"/%s/connections.html",servMgr->htmlPath); + jumpArg = jumpStr; + + + }else if (cmpCGIarg(cmd,"cmd=","hitlist")) + { + + bool stayConnected=hasCGIarg(cmd,"relay"); + + int index = 0; + ChanHitList *chl = chanMgr->hitlist; + while (chl) + { + if (chl->isUsed()) + { + char tmp[64]; + sprintf(tmp,"c%d=",index); + if (cmpCGIarg(cmd,tmp,"1")) + { + Channel *c; + if (!(c=chanMgr->findChannelByID(chl->info.id))) + { + c = chanMgr->createChannel(chl->info,NULL); + if (!c) + throw StreamException("out of channels"); + c->stayConnected = stayConnected; + c->startGet(); + } + } + } + chl = chl->next; + index++; + } + + char *findArg = getCGIarg(cmd,"keywords="); + + if (hasCGIarg(cmd,"relay")) + { + sys->sleep(500); + sprintf(jumpStr,"/%s/relays.html",servMgr->htmlPath); + jumpArg = jumpStr; + } + }else if (cmpCGIarg(cmd,"cmd=","clear")) + { + char *cp = cmd; + while (cp=nextCGIarg(cp,curr,arg)) + { + if (strcmp(curr,"hostcache")==0) + servMgr->clearHostCache(ServHost::T_SERVENT); + else if (strcmp(curr,"hitlists")==0) + chanMgr->clearHitLists(); + else if (strcmp(curr,"packets")==0) + { + stats.clearRange(Stats::PACKETSSTART,Stats::PACKETSEND); + servMgr->numVersions = 0; + } + } + + sprintf(jumpStr,"/%s/index.html",servMgr->htmlPath); + jumpArg = jumpStr; + + }else if (cmpCGIarg(cmd,"cmd=","upgrade")) + { + if (servMgr->downloadURL[0]) + { + sprintf(jumpStr,"/admin?cmd=redirect&url=%s",servMgr->downloadURL); + jumpArg = jumpStr; + } + + + + + }else if (cmpCGIarg(cmd,"cmd=","connect")) + { + + + Servent *s = servMgr->servents; + { + char tmp[64]; + sprintf(tmp,"c%d=",s->serventIndex); + if (cmpCGIarg(cmd,tmp,"1")) + { + if (hasCGIarg(cmd,"stop")) + s->thread.active = false; + } + s=s->next; + } + sprintf(jumpStr,"/%s/connections.html",servMgr->htmlPath); + jumpArg = jumpStr; + + }else if (cmpCGIarg(cmd,"cmd=","shutdown")) + { + servMgr->shutdownTimer = 1; + + }else if (cmpCGIarg(cmd,"cmd=","stop")) + { + GnuID id; + char *cp = cmd; + while (cp=nextCGIarg(cp,curr,arg)) + { + if (strcmp(curr,"id")==0) + id.fromStr(arg); + } + + Channel *c = chanMgr->findChannelByID(id); + if (c){ + c->thread.active = false; + c->thread.finish = true; + } + + sys->sleep(500); + sprintf(jumpStr,"/%s/relays.html",servMgr->htmlPath); + jumpArg = jumpStr; + + }else if (cmpCGIarg(cmd,"cmd=","bump")) + { + GnuID id; + char *cp = cmd; + while (cp=nextCGIarg(cp,curr,arg)) + { + if (strcmp(curr,"id")==0) + id.fromStr(arg); + } + + Channel *c = chanMgr->findChannelByID(id); + if (c) + c->bump = true; + + sprintf(jumpStr,"/%s/relays.html",servMgr->htmlPath); + jumpArg = jumpStr; + + }else if (cmpCGIarg(cmd,"cmd=","keep")) + { + GnuID id; + char *cp = cmd; + while (cp=nextCGIarg(cp,curr,arg)) + { + if (strcmp(curr,"id")==0) + id.fromStr(arg); + } + + Channel *c = chanMgr->findChannelByID(id); + if (c) + { //JP-Patch + //c->stayConnected = true; + if (!c->stayConnected) + { + //if (servMgr->getFirewall() == ServMgr::FW_OFF) + c->stayConnected = true; + } + else + c->stayConnected = false; + } //JP-Patch + + sprintf(jumpStr,"/%s/relays.html",servMgr->htmlPath); + jumpArg = jumpStr; + + }else if (cmpCGIarg(cmd,"cmd=","relay")) + { + ChanInfo info; + char *cp = cmd; + while (cp=nextCGIarg(cp,curr,arg)) + { + if (strcmp(curr,"id")==0) + info.id.fromStr(arg); + } + + + if (!chanMgr->findChannelByID(info.id)) + { + + ChanHitList *chl = chanMgr->findHitList(info); + if (!chl) + throw StreamException("channel not found"); + + + Channel *c = chanMgr->createChannel(chl->info,NULL); + if (!c) + throw StreamException("out of channels"); + + c->stayConnected = true; + c->startGet(); + } + + sprintf(jumpStr,"/%s/relays.html",servMgr->htmlPath); + jumpArg = jumpStr; + + + }else if (cmpCGIarg(cmd,"net=","add")) + { + + GnuID id; + id.clear(); + while (cmd=nextCGIarg(cmd,curr,arg)) + { + if (strcmp(curr,"ip")==0) + { + Host h; + h.fromStrIP(arg,DEFAULT_PORT); + if (servMgr->addOutgoing(h,id,true)) + LOG_NETWORK("Added connection: %s",arg); + + }else if (strcmp(curr,"id")==0) + { + id.fromStr(arg); + } + + } + + }else if (cmpCGIarg(cmd,"cmd=","logout")) + { + jumpArg = "/"; + servMgr->cookieList.remove(cookie); + + }else if (cmpCGIarg(cmd,"cmd=","login")) + { + GnuID id; + char idstr[64]; + id.generate(); + id.toStr(idstr); + + cookie.set(idstr,sock->host.ip); + servMgr->cookieList.add(cookie); + + http.writeLine(HTTP_SC_FOUND); + if (servMgr->cookieList.neverExpire) + http.writeLineF("%s id=%s; path=/; expires=\"Mon, 01-Jan-3000 00:00:00 GMT\";",HTTP_HS_SETCOOKIE,idstr); + else + http.writeLineF("%s id=%s; path=/;",HTTP_HS_SETCOOKIE,idstr); + http.writeLineF("Location: /%s/index.html",servMgr->htmlPath); + http.writeLine(""); + + }else if (cmpCGIarg(cmd,"cmd=","setmeta")) + { + char *cp = cmd; + while (cp=nextCGIarg(cp,curr,arg)) + { + if (strcmp(curr,"name")==0) + { +/* String chname; + chname.set(arg,String::T_ESC); + chname.convertTo(String::T_ASCII); + for(int i=0; ichannels[i]; + if ((c->isActive()) && (c->status == Channel::S_BROADCASTING) && (strcmp(c->info.name.cstr(),chname.cstr())==0)) + { + ChanInfo newInfo = c->info; + + while (cmd=nextCGIarg(cmd,curr,arg)) + { + String chmeta; + chmeta.set(arg,String::T_ESC); + chmeta.convertTo(String::T_ASCII); + if (strcmp(curr,"desc")==0) + newInfo.desc = chmeta.cstr(); + else if (strcmp(curr,"url")==0) + newInfo.url = chmeta.cstr(); + else if (strcmp(curr,"genre")==0) + newInfo.genre = chmeta.cstr(); + else if (strcmp(curr,"comment")==0) + newInfo.comment = chmeta.cstr(); + else if (strcmp(curr,"t_contact")==0) + newInfo.track.contact = chmeta.cstr(); + else if (strcmp(curr,"t_title")==0) + newInfo.track.title = chmeta.cstr(); + else if (strcmp(curr,"t_artist")==0) + newInfo.track.artist = chmeta.cstr(); + else if (strcmp(curr,"t_album")==0) + newInfo.track.album = chmeta.cstr(); + else if (strcmp(curr,"t_genre")==0) + newInfo.track.genre = chmeta.cstr(); + } + c->updateInfo(newInfo); + char idstr[64]; + newInfo.id.toStr(idstr); + sprintf(jumpStr,"/%s/relayinfo.html?id=%s",servMgr->htmlPath,idstr); + jumpArg = jumpStr; + break; + } + }*/ + String chname; + chname.set(arg,String::T_ESC); + chname.convertTo(String::T_ASCII); + + Channel *c = chanMgr->findChannelByName(chname.cstr()); + if (c && (c->isActive()) && (c->status == Channel::S_BROADCASTING)){ + ChanInfo newInfo = c->info; + while (cmd=nextCGIarg(cmd,curr,arg)) + { + String chmeta; + chmeta.set(arg,String::T_ESC); + chmeta.convertTo(String::T_ASCII); + if (strcmp(curr,"desc")==0) + newInfo.desc = chmeta.cstr(); + else if (strcmp(curr,"url")==0) + newInfo.url = chmeta.cstr(); + else if (strcmp(curr,"genre")==0) + newInfo.genre = chmeta.cstr(); + else if (strcmp(curr,"comment")==0) + newInfo.comment = chmeta.cstr(); + else if (strcmp(curr,"t_contact")==0) + newInfo.track.contact = chmeta.cstr(); + else if (strcmp(curr,"t_title")==0) + newInfo.track.title = chmeta.cstr(); + else if (strcmp(curr,"t_artist")==0) + newInfo.track.artist = chmeta.cstr(); + else if (strcmp(curr,"t_album")==0) + newInfo.track.album = chmeta.cstr(); + else if (strcmp(curr,"t_genre")==0) + newInfo.track.genre = chmeta.cstr(); + } + c->updateInfo(newInfo); + char idstr[64]; + newInfo.id.toStr(idstr); + sprintf(jumpStr,"/%s/relayinfo.html?id=%s",servMgr->htmlPath,idstr); + jumpArg = jumpStr; + } + } + } + if (!jumpArg) + { + jumpArg = "/"; + } + + }else{ + + sprintf(jumpStr,"/%s/index.html",servMgr->htmlPath); + jumpArg = jumpStr; + } + } + + }catch(StreamException &e) + { + html.startTagEnd("h1","ERROR - %s",e.msg); + LOG_ERROR("html: %s",e.msg); + } + + + if (retHTML) + { + if (jumpArg) + { + String jmp(jumpArg,String::T_HTML); + jmp.convertTo(String::T_ASCII); + html.locateTo(jmp.cstr()); + } + } + + +} +// ----------------------------------- +static XML::Node *createChannelXML(Channel *c) +{ + XML::Node *n = c->info.createChannelXML(); + n->add(c->createRelayXML(true)); + n->add(c->info.createTrackXML()); +// n->add(c->info.createServentXML()); + return n; +} +// ----------------------------------- +static XML::Node *createChannelXML(ChanHitList *chl) +{ + XML::Node *n = chl->info.createChannelXML(); + n->add(chl->createXML()); + n->add(chl->info.createTrackXML()); +// n->add(chl->info.createServentXML()); + return n; +} +// ----------------------------------- +void Servent::handshakeXML() +{ + int i; + + + + XML xml; + + XML::Node *rn = new XML::Node("peercast"); + xml.setRoot(rn); + + + rn->add(new XML::Node("servent uptime=\"%d\"",servMgr->getUptime())); + + rn->add(new XML::Node("bandwidth out=\"%d\" in=\"%d\"", + stats.getPerSecond(Stats::BYTESOUT)-stats.getPerSecond(Stats::LOCALBYTESOUT), + stats.getPerSecond(Stats::BYTESIN)-stats.getPerSecond(Stats::LOCALBYTESIN) + )); + + rn->add(new XML::Node("connections total=\"%d\" relays=\"%d\" direct=\"%d\"",servMgr->totalConnected(),servMgr->numStreams(Servent::T_RELAY,true),servMgr->numStreams(Servent::T_DIRECT,true))); + + XML::Node *an = new XML::Node("channels_relayed total=\"%d\"",chanMgr->numChannels()); + rn->add(an); + + Channel *c = chanMgr->channel; + while (c) + { + if (c->isActive()) + an->add(createChannelXML(c)); + c=c->next; + } + + + // add public channels + { + XML::Node *fn = new XML::Node("channels_found total=\"%d\"",chanMgr->numHitLists()); + rn->add(fn); + + ChanHitList *chl = chanMgr->hitlist; + while (chl) + { + if (chl->isUsed()) + fn->add(createChannelXML(chl)); + chl = chl->next; + } + } + + +#if 0 + if (servMgr->isRoot) + { + // add private channels + { + XML::Node *pn = new XML::Node("priv_channels"); + rn->add(pn); + + ChanHitList *chl = chanMgr->hitlist; + while (chl) + { + if (chl->isUsed()) + if (chl->info.isPrivate()) + pn->add(createChannelXML(chl)); + chl = chl->next; + } + } + } +#endif + + XML::Node *hc = new XML::Node("host_cache"); + for(i=0; ihostCache[i]; + if (sh->type != ServHost::T_NONE) + { + char ipstr[64]; + sh->host.toStr(ipstr); + + hc->add(new XML::Node("host ip=\"%s\" type=\"%s\" time=\"%d\"",ipstr,ServHost::getTypeStr(sh->type),sh->time)); + + } + } + rn->add(hc); + + + sock->writeLine(HTTP_SC_OK); + sock->writeLineF("%s %s",HTTP_HS_SERVER,PCX_AGENT); + sock->writeLineF("%s %s",HTTP_HS_CONTENT,MIME_XML); + sock->writeLine("Connection: close"); + + sock->writeLine(""); + + xml.write(*sock); + +} +// ----------------------------------- +void Servent::readICYHeader(HTTP &http, ChanInfo &info, char *pwd) +{ + char *arg = http.getArgStr(); + if (!arg) return; + + if (http.isHeader("x-audiocast-name") || http.isHeader("icy-name") || http.isHeader("ice-name")) + { + info.name.set(arg,String::T_ASCII); + info.name.convertTo(String::T_UNICODE); + + }else if (http.isHeader("x-audiocast-url") || http.isHeader("icy-url") || http.isHeader("ice-url")) + info.url.set(arg,String::T_ASCII); + else if (http.isHeader("x-audiocast-bitrate") || (http.isHeader("icy-br")) || http.isHeader("ice-bitrate") || http.isHeader("icy-bitrate")) + info.bitrate = atoi(arg); + else if (http.isHeader("x-audiocast-genre") || http.isHeader("ice-genre") || http.isHeader("icy-genre")) + { + info.genre.set(arg,String::T_ASCII); + info.genre.convertTo(String::T_UNICODE); + + }else if (http.isHeader("x-audiocast-description") || http.isHeader("ice-description")) + { + info.desc.set(arg,String::T_ASCII); + info.desc.convertTo(String::T_UNICODE); + + }else if (http.isHeader("Authorization")) + http.getAuthUserPass(NULL,pwd); + else if (http.isHeader(PCX_HS_CHANNELID)) + info.id.fromStr(arg); + else if (http.isHeader("ice-password")) + { + if (pwd) + if (strlen(arg) < 64) + strcpy(pwd,arg); + }else if (http.isHeader("content-type")) + { + if (stristr(arg,MIME_OGG)) + info.contentType = ChanInfo::T_OGG; + else if (stristr(arg,MIME_XOGG)) + info.contentType = ChanInfo::T_OGG; + + else if (stristr(arg,MIME_MP3)) + info.contentType = ChanInfo::T_MP3; + else if (stristr(arg,MIME_XMP3)) + info.contentType = ChanInfo::T_MP3; + + else if (stristr(arg,MIME_WMA)) + info.contentType = ChanInfo::T_WMA; + else if (stristr(arg,MIME_WMV)) + info.contentType = ChanInfo::T_WMV; + else if (stristr(arg,MIME_ASX)) + info.contentType = ChanInfo::T_ASX; + + else if (stristr(arg,MIME_NSV)) + info.contentType = ChanInfo::T_NSV; + else if (stristr(arg,MIME_RAW)) + info.contentType = ChanInfo::T_RAW; + + else if (stristr(arg,MIME_MMS)) + info.srcProtocol = ChanInfo::SP_MMS; + else if (stristr(arg,MIME_XPCP)) + info.srcProtocol = ChanInfo::SP_PCP; + else if (stristr(arg,MIME_XPEERCAST)) + info.srcProtocol = ChanInfo::SP_PEERCAST; + + else if (stristr(arg,MIME_XSCPLS)) + info.contentType = ChanInfo::T_PLS; + else if (stristr(arg,MIME_PLS)) + info.contentType = ChanInfo::T_PLS; + else if (stristr(arg,MIME_XPLS)) + info.contentType = ChanInfo::T_PLS; + else if (stristr(arg,MIME_M3U)) + info.contentType = ChanInfo::T_PLS; + else if (stristr(arg,MIME_MPEGURL)) + info.contentType = ChanInfo::T_PLS; + else if (stristr(arg,MIME_TEXT)) + info.contentType = ChanInfo::T_PLS; + + + } + +} + +// ----------------------------------- +void Servent::handshakeICY(Channel::SRC_TYPE type, bool isHTTP) +{ + ChanInfo info; + + HTTP http(*sock); + + // default to mp3 for shoutcast DSP (doesn`t send content-type) + if (type == Channel::SRC_SHOUTCAST) + info.contentType = ChanInfo::T_MP3; + + while (http.nextHeader()) + { + LOG_DEBUG("ICY %s",http.cmdLine); + readICYHeader(http,info,loginPassword); + } + + + + // check password before anything else, if needed + if (strcmp(servMgr->password,loginPassword)!=0) + { + if (!sock->host.isLocalhost() || strlen(loginPassword)) + throw HTTPException(HTTP_SC_UNAUTHORIZED,401); + } + + + // we need a valid IP address before we start + servMgr->checkFirewall(); + + + // attach channel ID to name, channel ID is also encoded with IP address + // to help prevent channel hijacking. + + + info.id = chanMgr->broadcastID; + info.id.encode(NULL,info.name.cstr(),loginMount,info.bitrate); + + LOG_DEBUG("Incoming source: %s : %s",info.name.cstr(),ChanInfo::getTypeStr(info.contentType)); + + + if (isHTTP) + sock->writeStringF("%s\n\n",HTTP_SC_OK); + else + sock->writeLine("OK"); + + Channel *c = chanMgr->findChannelByID(info.id); + if (c) + { + LOG_CHANNEL("ICY channel already active, closing old one"); + c->thread.shutdown(); + } + + + info.comment = chanMgr->broadcastMsg; + info.bcID = chanMgr->broadcastID; + + c = chanMgr->createChannel(info,loginMount); + if (!c) + throw HTTPException(HTTP_SC_UNAVAILABLE,503); + + c->startICY(sock,type); +} + + +// ----------------------------------- +void Servent::handshakeLocalFile(const char *fn) +{ + HTTP http(*sock); + String fileName; + + if (servMgr->getModulePath) //JP-EX + { + peercastApp->getDirectory(); + fileName = servMgr->modulePath; + }else + fileName = peercastApp->getPath(); + + fileName.append(fn); + + LOG_DEBUG("Writing HTML file: %s",fileName.cstr()); + + HTML html("",*sock); + + char *args = strstr(fileName.cstr(),"?"); + if (args) + *args++=0; + + if (fileName.contains(".htm")) + { + html.writeOK(MIME_HTML); + html.writeTemplate(fileName.cstr(),args); + + }else if (fileName.contains(".css")) + { + html.writeOK(MIME_CSS); + html.writeRawFile(fileName.cstr()); + }else if (fileName.contains(".jpg")) + { + html.writeOK(MIME_JPEG); + html.writeRawFile(fileName.cstr()); + }else if (fileName.contains(".gif")) + { + html.writeOK(MIME_GIF); + html.writeRawFile(fileName.cstr()); + }else if (fileName.contains(".png")) + { + html.writeOK(MIME_PNG); + html.writeRawFile(fileName.cstr()); + } +} + +// ----------------------------------- +void Servent::handshakeRemoteFile(const char *dirName) +{ + ClientSocket *rsock = sys->createSocket(); + if (!rsock) + throw HTTPException(HTTP_SC_UNAVAILABLE,503); + + + const char *hostName = "www.peercast.org"; // hardwired for "security" + + Host host; + host.fromStrName(hostName,80); + + + rsock->open(host); + rsock->connect(); + + HTTP rhttp(*rsock); + + rhttp.writeLineF("GET /%s HTTP/1.0",dirName); + rhttp.writeLineF("%s %s",HTTP_HS_HOST,hostName); + rhttp.writeLineF("%s %s",HTTP_HS_CONNECTION,"close"); + rhttp.writeLineF("%s %s",HTTP_HS_ACCEPT,"*/*"); + rhttp.writeLine(""); + + String contentType; + bool isTemplate = false; + while (rhttp.nextHeader()) + { + char *arg = rhttp.getArgStr(); + if (arg) + { + if (rhttp.isHeader("content-type")) + contentType = arg; + } + } + + MemoryStream mem(100*1024); + while (!rsock->eof()) + { + int len=0; + char buf[4096]; + len = rsock->readUpto(buf,sizeof(buf)); + if (len==0) + break; + else + mem.write(buf,len); + + } + rsock->close(); + + int fileLen = mem.getPosition(); + mem.len = fileLen; + mem.rewind(); + + + if (contentType.contains(MIME_HTML)) + isTemplate = true; + + sock->writeLine(HTTP_SC_OK); + sock->writeLineF("%s %s",HTTP_HS_SERVER,PCX_AGENT); + sock->writeLineF("%s %s",HTTP_HS_CACHE,"no-cache"); + sock->writeLineF("%s %s",HTTP_HS_CONNECTION,"close"); + sock->writeLineF("%s %s",HTTP_HS_CONTENT,contentType.cstr()); + + sock->writeLine(""); + + if (isTemplate) + { + HTML html("",*sock); + html.readTemplate(mem,sock,0); + }else + sock->write(mem.buf,fileLen); + + mem.free2(); +} diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/servmgr.cpp b/c:/Git/PeerCast.root/PeerCast/core/common/servmgr.cpp new file mode 100644 index 0000000..7f72944 --- /dev/null +++ b/c:/Git/PeerCast.root/PeerCast/core/common/servmgr.cpp @@ -0,0 +1,2608 @@ +// ------------------------------------------------ +// File : servmgr.cpp +// Date: 4-apr-2002 +// Author: giles +// Desc: +// Management class for handling multiple servent connections. +// +// (c) 2002 peercast.org +// ------------------------------------------------ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// ------------------------------------------------ + +#include +#include "servent.h" +#include "servmgr.h" +#include "inifile.h" +#include "stats.h" +#include "peercast.h" +#include "pcp.h" +#include "atom.h" +#include "version2.h" +#ifdef _DEBUG +#include "chkMemoryLeak.h" +#define DEBUG_NEW new(__FILE__, __LINE__) +#define new DEBUG_NEW +#endif + +ThreadInfo ServMgr::serverThread,ServMgr::idleThread; + +// ----------------------------------- +ServMgr::ServMgr() +{ + validBCID = NULL; + + authType = AUTH_COOKIE; + cookieList.init(); + + serventNum = 0; + + startTime = sys->getTime(); + + allowServer1 = Servent::ALLOW_ALL; + allowServer2 = Servent::ALLOW_BROADCAST; + + clearHostCache(ServHost::T_NONE); + password[0]=0; + + allowGnutella = false; + useFlowControl = true; + + maxServIn = 50; + minGnuIncoming = 10; + maxGnuIncoming = 20; + + lastIncoming = 0; + + maxBitrateOut = 540; //JP-Patch 0-> 540 + maxRelays = MIN_RELAYS; + maxDirect = 0; + refreshHTML = 1800; + + networkID.clear(); + + notifyMask = 0xffff; + + tryoutDelay = 10; + numVersions = 0; + + sessionID.generate(); + + isDisabled = false; + isRoot = false; + + forceIP.clear(); + + strcpy(connectHost,"connect1.peercast.org"); + strcpy(htmlPath,"html/ja"); + + rootHost = "yp.peercast.org"; + rootHost2 = ""; + + serverHost.fromStrIP("127.0.0.1",DEFAULT_PORT); + + firewalled = FW_UNKNOWN; + allowDirect = true; + autoConnect = true; + forceLookup = true; + autoServe = true; + forceNormal = false; + + maxControl = 3; + + queryTTL = 7; + + totalStreams = 0; + firewallTimeout = 30; + pauseLog = false; + showLog = 0; + + shutdownTimer = 0; + + downloadURL[0] = 0; + rootMsg.clear(); + + + restartServer=false; + + setFilterDefaults(); + + servents = NULL; + + modulePath[0] = 0; //JP-EX + kickPushStartRelays = 1; //JP-EX + kickPushInterval = 60; //JP-EX + kickPushTime = 0; //JP-EX + autoRelayKeep = 2; //JP-EX + autoMaxRelaySetting = 0; //JP-EX + autoBumpSkipCount = 50; //JP-EX + enableGetName = 1; //JP-EX + allowConnectPCST = 0; //JP-EX + getModulePath = true; //JP-EX + clearPLS = false; //JP-EX + writeLogFile = false; //JP-EX + + autoPort0Kick = false; + allowOnlyVP = false; + kickKeepTime = 0; + vpDebug = false; + saveIniChannel = true; + saveGuiPos = false; + keepDownstreams = true; + + chanLog=""; + + maxRelaysIndexTxt = 1; // for PCRaw (relay) +} +// ----------------------------------- +BCID *ServMgr::findValidBCID(int index) +{ + int cnt = 0; + BCID *bcid = validBCID; + while (bcid) + { + if (cnt == index) + return bcid; + cnt++; + bcid=bcid->next; + } + return 0; +} +// ----------------------------------- +BCID *ServMgr::findValidBCID(GnuID &id) +{ + BCID *bcid = validBCID; + while (bcid) + { + if (bcid->id.isSame(id)) + return bcid; + bcid=bcid->next; + } + return 0; +} +// ----------------------------------- +void ServMgr::removeValidBCID(GnuID &id) +{ + BCID *bcid = validBCID,*prev=0; + while (bcid) + { + if (bcid->id.isSame(id)) + { + if (prev) + prev->next = bcid->next; + else + validBCID = bcid->next; + return; + } + prev = bcid; + bcid=bcid->next; + } +} +// ----------------------------------- +void ServMgr::addValidBCID(BCID *bcid) +{ + removeValidBCID(bcid->id); + + bcid->next = validBCID; + validBCID = bcid; +} + +// ----------------------------------- +void ServMgr::connectBroadcaster() +{ + if (!rootHost.isEmpty()) + { + if (!numUsed(Servent::T_COUT)) + { + Servent *sv = allocServent(); + if (sv) + { + sv->initOutgoing(Servent::T_COUT); + sys->sleep(3000); + } + } + } +} +// ----------------------------------- +void ServMgr::addVersion(unsigned int ver) +{ + for(int i=0; i 0) && (t < 60)) +// t = 60; +// passiveSearch = t; +} +// ----------------------------------- +bool ServMgr::seenHost(Host &h, ServHost::TYPE type,unsigned int time) +{ + time = sys->getTime()-time; + + for(int i=0; i= time) + return true; + return false; +} + +// ----------------------------------- +void ServMgr::addHost(Host &h, ServHost::TYPE type, unsigned int time) +{ + int i; + if (!h.isValid()) + return; + + ServHost *sh=NULL; + + for(i=0; itime) + sh = &hostCache[i]; + }else{ + sh = &hostCache[i]; + } + } + } + + if (sh) + sh->init(h,type,time); +} + +// ----------------------------------- +void ServMgr::deadHost(Host &h,ServHost::TYPE t) +{ + for(int i=0; i sh->time) + sh = &hostCache[j]; + } + } + } + } + + // add to list + if (sh) + hl[cnt++]=sh->host; + } + + return cnt; +} +// ----------------------------------- +ServHost ServMgr::getOutgoingServent(GnuID &netid) +{ + ServHost host; + + Host lh(ClientSocket::getIP(NULL),0); + + // find newest host not in list + ServHost *sh=NULL; + for(int j=0; jtype == ServHost::T_SERVENT) + { + if (!((lh.globalIP() && !hc->host.globalIP()) || lh.isSame(hc->host))) + { +#if 0 + if (!findServent(Servent::T_OUTGOING,hc->host,netid)) + { + if (!sh) + { + sh = hc; + }else{ + if (hc->time > sh->time) + sh = hc; + } + } +#endif + } + } + } + + if (sh) + host = *sh; + + return host; +} +// ----------------------------------- +Servent *ServMgr::findOldestServent(Servent::TYPE type, bool priv) +{ + Servent *oldest=NULL; + + Servent *s = servents; + while (s) + { + if (s->type == type) + if (s->thread.active) + if (s->isOlderThan(oldest)) + if (s->isPrivate() == priv) + oldest = s; + s=s->next; + } + return oldest; +} +// ----------------------------------- +Servent *ServMgr::findServent(Servent::TYPE type, Host &host, GnuID &netid) +{ + lock.on(); + Servent *s = servents; + while (s) + { + if (s->type == type) + { + Host h = s->getHost(); + if (h.isSame(host) && s->networkID.isSame(netid)) + { + lock.off(); + return s; + } + } + s=s->next; + } + lock.off(); + return NULL; + +} + +// ----------------------------------- +Servent *ServMgr::findServent(unsigned int ip, unsigned short port, GnuID &netid) +{ + lock.on(); + Servent *s = servents; + while (s) + { + if (s->type != Servent::T_NONE) + { + Host h = s->getHost(); + if ((h.ip == ip) && (h.port == port) && (s->networkID.isSame(netid))) + { + lock.off(); + return s; + } + } + s=s->next; + } + lock.off(); + return NULL; + +} + +// ----------------------------------- +Servent *ServMgr::findServent(Servent::TYPE t) +{ + Servent *s = servents; + while (s) + { + if (s->type == t) + return s; + s=s->next; + } + return NULL; +} +// ----------------------------------- +Servent *ServMgr::findServentByIndex(int id) +{ + Servent *s = servents; + int cnt=0; + while (s) + { + if (cnt == id) + return s; + cnt++; + s=s->next; + } + return NULL; +} + +// ----------------------------------- +Servent *ServMgr::findServentByServentID(int id) +{ + Servent *s = servents; + while (s) + { + if (id == s->servent_id){ + return s; + } + s=s->next; + } + return NULL; +} + +// ----------------------------------- +Servent *ServMgr::allocServent() +{ + lock.on(); + + Servent *s = servents; + while (s) + { + if (s->status == Servent::S_FREE) + break; + s=s->next; + } + + if (!s) + { + s = new Servent(++serventNum); + s->next = servents; + servents = s; + + LOG_DEBUG("allocated servent %d",serventNum); + }else + LOG_DEBUG("reused servent %d",s->serventIndex); + + + s->reset(); + + lock.off(); + + return s; +} +// -------------------------------------------------- +void ServMgr::closeConnections(Servent::TYPE type) +{ + Servent *sv = servents; + while (sv) + { + if (sv->isConnected()) + if (sv->type == type) + sv->thread.active = false; + sv=sv->next; + } +} + +// ----------------------------------- +unsigned int ServMgr::numConnected(int type,bool priv,unsigned int uptime) +{ + unsigned int cnt=0; + + unsigned int ctime=sys->getTime(); + Servent *s = servents; + while (s) + { + if (s->thread.active) + if (s->isConnected()) + if (s->type == type) + if (s->isPrivate()==priv) + if ((ctime-s->lastConnect) >= uptime) + cnt++; + + s=s->next; + } + return cnt; +} +// ----------------------------------- +unsigned int ServMgr::numConnected() +{ + unsigned int cnt=0; + + Servent *s = servents; + while (s) + { + if (s->thread.active) + if (s->isConnected()) + cnt++; + + s=s->next; + } + return cnt; +} +// ----------------------------------- +unsigned int ServMgr::numServents() +{ + unsigned int cnt=0; + + Servent *s = servents; + while (s) + { + cnt++; + s=s->next; + } + return cnt; +} + +// ----------------------------------- +unsigned int ServMgr::numUsed(int type) +{ + unsigned int cnt=0; + + Servent *s = servents; + while (s) + { + if (s->type == type) + cnt++; + s=s->next; + } + return cnt; +} +// ----------------------------------- +unsigned int ServMgr::numActiveOnPort(int port) +{ + unsigned int cnt=0; + + Servent *s = servents; + while (s) + { + if (s->thread.active && s->sock && (s->servPort == port)) + cnt++; + s=s->next; + } + return cnt; +} +// ----------------------------------- +unsigned int ServMgr::numActive(Servent::TYPE tp) +{ + unsigned int cnt=0; + + Servent *s = servents; + while (s) + { + if (s->thread.active && s->sock && (s->type == tp)) + cnt++; + s=s->next; + } + return cnt; +} + +// ----------------------------------- +unsigned int ServMgr::totalOutput(bool all) +{ + unsigned int tot = 0; + Servent *s = servents; + while (s) + { + if (s->isConnected()) + if (all || !s->isPrivate()) + if (s->sock) + tot += s->sock->bytesOutPerSec; + s=s->next; + } + + return tot; +} + +// ----------------------------------- +unsigned int ServMgr::totalInput(bool all) +{ + unsigned int tot = 0; + Servent *s = servents; + while (s) + { + if (s->isConnected()) + if (all || !s->isPrivate()) + if (s->sock) + tot += s->sock->bytesInPerSec; + s=s->next; + } + + return tot; +} + +// ----------------------------------- +unsigned int ServMgr::numOutgoing() +{ + int cnt=0; + + Servent *s = servents; + while (s) + { +// if ((s->type == Servent::T_INCOMING) || +// (s->type == Servent::T_OUTGOING)) +// cnt++; + s=s->next; + } + return cnt; +} + +// ----------------------------------- +bool ServMgr::seenPacket(GnuPacket &p) +{ + Servent *s = servents; + while (s) + { + if (s->isConnected()) + if (s->seenIDs.contains(p.id)) + return true; + s=s->next; + } + return false; +} + +// ----------------------------------- +void ServMgr::quit() +{ + LOG_DEBUG("ServMgr is quitting.."); + + serverThread.shutdown(); + + idleThread.shutdown(); + + Servent *s = servents; + while (s) + { + try + { + if (s->thread.active) + { + s->thread.shutdown(); + } + + }catch(StreamException &) + { + } + s=s->next; + } +} + +// ----------------------------------- +int ServMgr::broadcast(GnuPacket &pack,Servent *src) +{ + int cnt=0; + if (pack.ttl) + { + Servent *s = servents; + while (s) + { + + if (s != src) + if (s->isConnected()) + if (s->type == Servent::T_PGNU) + if (!s->seenIDs.contains(pack.id)) + { + + if (src) + if (!src->networkID.isSame(s->networkID)) + continue; + + if (s->outputPacket(pack,false)) + cnt++; + } + s=s->next; + } + } + + LOG_NETWORK("broadcast: %s (%d) to %d servents",GNU_FUNC_STR(pack.func),pack.ttl,cnt); + + return cnt; +} +// ----------------------------------- +int ServMgr::route(GnuPacket &pack, GnuID &routeID, Servent *src) +{ + int cnt=0; + if (pack.ttl) + { + Servent *s = servents; + while (s) + { + if (s != src) + if (s->isConnected()) + if (s->type == Servent::T_PGNU) + if (!s->seenIDs.contains(pack.id)) + if (s->seenIDs.contains(routeID)) + { + if (src) + if (!src->networkID.isSame(s->networkID)) + continue; + + if (s->outputPacket(pack,true)) + cnt++; + } + s=s->next; + } + + } + + LOG_NETWORK("route: %s (%d) to %d servents",GNU_FUNC_STR(pack.func),pack.ttl,cnt); + return cnt; +} +// ----------------------------------- +bool ServMgr::checkForceIP() +{ + if (!forceIP.isEmpty()) + { + unsigned int newIP = ClientSocket::getIP(forceIP.cstr()); + if (serverHost.ip != newIP) + { + serverHost.ip = newIP; + char ipstr[64]; + serverHost.IPtoStr(ipstr); + LOG_DEBUG("Server IP changed to %s",ipstr); + return true; + } + } + return false; +} + +// ----------------------------------- +void ServMgr::checkFirewall() +{ + if ((getFirewall() == FW_UNKNOWN) && !servMgr->rootHost.isEmpty()) + { + + LOG_DEBUG("Checking firewall.."); + Host host; + host.fromStrName(servMgr->rootHost.cstr(),DEFAULT_PORT); + + ClientSocket *sock = sys->createSocket(); + if (!sock) + throw StreamException("Unable to create socket"); + sock->setReadTimeout(30000); + sock->open(host); + sock->connect(); + + AtomStream atom(*sock); + + atom.writeInt(PCP_CONNECT,1); + + GnuID remoteID; + String agent; + Servent::handshakeOutgoingPCP(atom,sock->host,remoteID,agent,true); + + atom.writeInt(PCP_QUIT,PCP_ERROR_QUIT); + + sock->close(); + delete sock; + } +} + +// ----------------------------------- +void ServMgr::setFirewall(FW_STATE state) +{ + if (firewalled != state) + { + char *str; + switch (state) + { + case FW_ON: + str = "ON"; + break; + case FW_OFF: + str = "OFF"; + break; + case FW_UNKNOWN: + default: + str = "UNKNOWN"; + break; + } + + LOG_DEBUG("Firewall is set to %s",str); + firewalled = state; + } +} +// ----------------------------------- +bool ServMgr::isFiltered(int fl, Host &h) +{ + for(int i=0; igetHost(); + + if (sh.globalIP() || (sh.localIP() && h.localIP())) + return true; + } + return false; +} +#endif + +// -------------------------------------------------- +void writeServerSettings(IniFile &iniFile, unsigned int a) +{ + iniFile.writeBoolValue("allowHTML",a & Servent::ALLOW_HTML); + iniFile.writeBoolValue("allowBroadcast",a & Servent::ALLOW_BROADCAST); + iniFile.writeBoolValue("allowNetwork",a & Servent::ALLOW_NETWORK); + iniFile.writeBoolValue("allowDirect",a & Servent::ALLOW_DIRECT); +} +// -------------------------------------------------- +void writeFilterSettings(IniFile &iniFile, ServFilter &f) +{ + char ipstr[64]; + f.host.IPtoStr(ipstr); + iniFile.writeStrValue("ip",ipstr); + iniFile.writeBoolValue("private",f.flags & ServFilter::F_PRIVATE); + iniFile.writeBoolValue("ban",f.flags & ServFilter::F_BAN); + iniFile.writeBoolValue("network",f.flags & ServFilter::F_NETWORK); + iniFile.writeBoolValue("direct",f.flags & ServFilter::F_DIRECT); +} + +// -------------------------------------------------- +static void writeServHost(IniFile &iniFile, ServHost &sh) +{ + iniFile.writeSection("Host"); + + char ipStr[64]; + sh.host.toStr(ipStr); + iniFile.writeStrValue("type",ServHost::getTypeStr(sh.type)); + iniFile.writeStrValue("address",ipStr); + iniFile.writeIntValue("time",sh.time); + + iniFile.writeLine("[End]"); +} + +#ifdef WIN32 +extern bool guiFlg; +extern WINDOWPLACEMENT winPlace; +extern HWND guiWnd; +#endif + +// -------------------------------------------------- +void ServMgr::saveSettings(const char *fn) +{ + IniFile iniFile; + if (!iniFile.openWriteReplace(fn)) + { + LOG_ERROR("Unable to open ini file"); + }else{ + LOG_DEBUG("Saving settings to: %s",fn); + + char idStr[64]; + + iniFile.writeSection("Server"); + iniFile.writeIntValue("serverPort",servMgr->serverHost.port); + iniFile.writeBoolValue("autoServe",servMgr->autoServe); + iniFile.writeStrValue("forceIP",servMgr->forceIP); + iniFile.writeBoolValue("isRoot",servMgr->isRoot); + iniFile.writeIntValue("maxBitrateOut",servMgr->maxBitrateOut); + iniFile.writeIntValue("maxRelays",servMgr->maxRelays); + iniFile.writeIntValue("maxDirect",servMgr->maxDirect); + iniFile.writeIntValue("maxRelaysPerChannel",chanMgr->maxRelaysPerChannel); + iniFile.writeIntValue("firewallTimeout",firewallTimeout); + iniFile.writeBoolValue("forceNormal",forceNormal); + iniFile.writeStrValue("rootMsg",rootMsg.cstr()); + iniFile.writeStrValue("authType",servMgr->authType==ServMgr::AUTH_COOKIE?"cookie":"http-basic"); + iniFile.writeStrValue("cookiesExpire",servMgr->cookieList.neverExpire==true?"never":"session"); + iniFile.writeStrValue("htmlPath",servMgr->htmlPath); + iniFile.writeIntValue("minPGNUIncoming",servMgr->minGnuIncoming); + iniFile.writeIntValue("maxPGNUIncoming",servMgr->maxGnuIncoming); + iniFile.writeIntValue("maxServIn",servMgr->maxServIn); + iniFile.writeStrValue("chanLog",servMgr->chanLog.cstr()); + + networkID.toStr(idStr); + iniFile.writeStrValue("networkID",idStr); + + + iniFile.writeSection("Broadcast"); + iniFile.writeIntValue("broadcastMsgInterval",chanMgr->broadcastMsgInterval); + iniFile.writeStrValue("broadcastMsg",chanMgr->broadcastMsg.cstr()); + iniFile.writeIntValue("icyMetaInterval",chanMgr->icyMetaInterval); + chanMgr->broadcastID.toStr(idStr); + iniFile.writeStrValue("broadcastID",idStr); + iniFile.writeIntValue("hostUpdateInterval",chanMgr->hostUpdateInterval); + iniFile.writeIntValue("maxControlConnections",servMgr->maxControl); + iniFile.writeStrValue("rootHost",servMgr->rootHost.cstr()); + + iniFile.writeSection("Client"); + iniFile.writeIntValue("refreshHTML",refreshHTML); + iniFile.writeIntValue("relayBroadcast",servMgr->relayBroadcast); + iniFile.writeIntValue("minBroadcastTTL",chanMgr->minBroadcastTTL); + iniFile.writeIntValue("maxBroadcastTTL",chanMgr->maxBroadcastTTL); + iniFile.writeIntValue("pushTries",chanMgr->pushTries); + iniFile.writeIntValue("pushTimeout",chanMgr->pushTimeout); + iniFile.writeIntValue("maxPushHops",chanMgr->maxPushHops); + iniFile.writeIntValue("autoQuery",chanMgr->autoQuery); + iniFile.writeIntValue("queryTTL",servMgr->queryTTL); + + + iniFile.writeSection("Privacy"); + iniFile.writeStrValue("password",servMgr->password); + iniFile.writeIntValue("maxUptime",chanMgr->maxUptime); + + //JP-EX + iniFile.writeSection("Extend"); + iniFile.writeIntValue("autoRelayKeep",servMgr->autoRelayKeep); + iniFile.writeIntValue("autoMaxRelaySetting",servMgr->autoMaxRelaySetting); + iniFile.writeIntValue("autoBumpSkipCount",servMgr->autoBumpSkipCount); + iniFile.writeIntValue("kickPushStartRelays",servMgr->kickPushStartRelays); + iniFile.writeIntValue("kickPushInterval",servMgr->kickPushInterval); + iniFile.writeIntValue("allowConnectPCST",servMgr->allowConnectPCST); + iniFile.writeIntValue("enableGetName",servMgr->enableGetName); + + iniFile.writeIntValue("maxRelaysIndexTxt", servMgr->maxRelaysIndexTxt); // for PCRaw (relay) + + //JP-EX + iniFile.writeSection("Windows"); + iniFile.writeBoolValue("getModulePath",servMgr->getModulePath); + iniFile.writeBoolValue("clearPLS",servMgr->clearPLS); + iniFile.writeBoolValue("writeLogFile",servMgr->writeLogFile); + + //VP-EX + iniFile.writeStrValue("rootHost2",servMgr->rootHost2.cstr()); + iniFile.writeBoolValue("autoPort0Kick",servMgr->autoPort0Kick); + iniFile.writeBoolValue("allowOnlyVP",servMgr->allowOnlyVP); + iniFile.writeIntValue("kickKeepTime",servMgr->kickKeepTime); + iniFile.writeBoolValue("vpDebug", servMgr->vpDebug); + iniFile.writeBoolValue("saveIniChannel", servMgr->saveIniChannel); +#ifdef WIN32 + iniFile.writeBoolValue("saveGuiPos", servMgr->saveGuiPos); + if (guiFlg){ + GetWindowPlacement(guiWnd, &winPlace); + iniFile.writeIntValue("guiTop", winPlace.rcNormalPosition.top); + iniFile.writeIntValue("guiBottom", winPlace.rcNormalPosition.bottom); + iniFile.writeIntValue("guiLeft", winPlace.rcNormalPosition.left); + iniFile.writeIntValue("guiRight", winPlace.rcNormalPosition.right); + } +#endif + int i; + + for(i=0; inumFilters; i++) + { + iniFile.writeSection("Filter"); + writeFilterSettings(iniFile,servMgr->filters[i]); + iniFile.writeLine("[End]"); + } + + iniFile.writeSection("Notify"); + iniFile.writeBoolValue("PeerCast",notifyMask&NT_PEERCAST); + iniFile.writeBoolValue("Broadcasters",notifyMask&NT_BROADCASTERS); + iniFile.writeBoolValue("TrackInfo",notifyMask&NT_TRACKINFO); + iniFile.writeLine("[End]"); + + + iniFile.writeSection("Server1"); + writeServerSettings(iniFile,allowServer1); + iniFile.writeLine("[End]"); + + iniFile.writeSection("Server2"); + writeServerSettings(iniFile,allowServer2); + iniFile.writeLine("[End]"); + + + + iniFile.writeSection("Debug"); + iniFile.writeBoolValue("logDebug",(showLog&(1<idleSleepTime); + + + if (servMgr->validBCID) + { + BCID *bcid = servMgr->validBCID; + while (bcid) + { + iniFile.writeSection("ValidBCID"); + char idstr[128]; + bcid->id.toStr(idstr); + iniFile.writeStrValue("id",idstr); + iniFile.writeStrValue("name",bcid->name.cstr()); + iniFile.writeStrValue("email",bcid->email.cstr()); + iniFile.writeStrValue("url",bcid->url.cstr()); + iniFile.writeBoolValue("valid",bcid->valid); + iniFile.writeLine("[End]"); + + bcid=bcid->next; + } + } + + if (servMgr->saveIniChannel){ + Channel *c = chanMgr->channel; + while (c) + { + char idstr[64]; + if (c->isActive() && c->stayConnected) + { + c->getIDStr(idstr); + + iniFile.writeSection("RelayChannel"); + iniFile.writeStrValue("name",c->getName()); + iniFile.writeStrValue("genre",c->info.genre.cstr()); + if (!c->sourceURL.isEmpty()) + iniFile.writeStrValue("sourceURL",c->sourceURL.cstr()); + iniFile.writeStrValue("sourceProtocol",ChanInfo::getProtocolStr(c->info.srcProtocol)); + iniFile.writeStrValue("contentType",ChanInfo::getTypeStr(c->info.contentType)); + iniFile.writeIntValue("bitrate",c->info.bitrate); + iniFile.writeStrValue("contactURL",c->info.url.cstr()); + iniFile.writeStrValue("id",idstr); + iniFile.writeBoolValue("stayConnected",c->stayConnected); + + ChanHitList *chl = chanMgr->findHitListByID(c->info.id); + if (chl) + { + + ChanHitSearch chs; + chs.trackersOnly = true; + if (chl->pickHits(chs)) + { + char ipStr[64]; + chs.best[0].host.toStr(ipStr); + iniFile.writeStrValue("tracker",ipStr); + } + } + iniFile.writeLine("[End]"); + } + c=c->next; + } + } + + + +#if 0 + Servent *s = servents; + while (s) + { + if (s->type == Servent::T_OUTGOING) + if (s->isConnected()) + { + ServHost sh; + Host h = s->getHost(); + sh.init(h,ServHost::T_SERVENT,0,s->networkID); + writeServHost(iniFile,sh); + } + s=s->next; + } +#endif + + for(i=0; ihostCache[i]; + if (sh->type != ServHost::T_NONE) + writeServHost(iniFile,*sh); + } + + iniFile.close(); + } +} +// -------------------------------------------------- +unsigned int readServerSettings(IniFile &iniFile, unsigned int a) +{ + while (iniFile.readNext()) + { + if (iniFile.isName("[End]")) + break; + else if (iniFile.isName("allowHTML")) + a = iniFile.getBoolValue()?a|Servent::ALLOW_HTML:a&~Servent::ALLOW_HTML; + else if (iniFile.isName("allowDirect")) + a = iniFile.getBoolValue()?a|Servent::ALLOW_DIRECT:a&~Servent::ALLOW_DIRECT; + else if (iniFile.isName("allowNetwork")) + a = iniFile.getBoolValue()?a|Servent::ALLOW_NETWORK:a&~Servent::ALLOW_NETWORK; + else if (iniFile.isName("allowBroadcast")) + a = iniFile.getBoolValue()?a|Servent::ALLOW_BROADCAST:a&~Servent::ALLOW_BROADCAST; + } + return a; +} +// -------------------------------------------------- +void readFilterSettings(IniFile &iniFile, ServFilter &sv) +{ + sv.host.init(); + + while (iniFile.readNext()) + { + if (iniFile.isName("[End]")) + break; + else if (iniFile.isName("ip")) + sv.host.fromStrIP(iniFile.getStrValue(),0); + else if (iniFile.isName("private")) + sv.flags = (sv.flags & ~ServFilter::F_PRIVATE) | (iniFile.getBoolValue()?ServFilter::F_PRIVATE:0); + else if (iniFile.isName("ban")) + sv.flags = (sv.flags & ~ServFilter::F_BAN) | (iniFile.getBoolValue()?ServFilter::F_BAN:0); + else if (iniFile.isName("allow") || iniFile.isName("network")) + sv.flags = (sv.flags & ~ServFilter::F_NETWORK) | (iniFile.getBoolValue()?ServFilter::F_NETWORK:0); + else if (iniFile.isName("direct")) + sv.flags = (sv.flags & ~ServFilter::F_DIRECT) | (iniFile.getBoolValue()?ServFilter::F_DIRECT:0); + } + +} +// -------------------------------------------------- +void ServMgr::loadSettings(const char *fn) +{ + IniFile iniFile; + + if (!iniFile.openReadOnly(fn)) + saveSettings(fn); + + + servMgr->numFilters = 0; + showLog = 0; + + if (iniFile.openReadOnly(fn)) + { + while (iniFile.readNext()) + { + // server settings + if (iniFile.isName("serverPort")) + servMgr->serverHost.port = iniFile.getIntValue(); + else if (iniFile.isName("autoServe")) + servMgr->autoServe = iniFile.getBoolValue(); + else if (iniFile.isName("autoConnect")) + servMgr->autoConnect = iniFile.getBoolValue(); + else if (iniFile.isName("icyPassword")) // depreciated + strcpy(servMgr->password,iniFile.getStrValue()); + else if (iniFile.isName("forceIP")) + servMgr->forceIP = iniFile.getStrValue(); + else if (iniFile.isName("isRoot")) + servMgr->isRoot = iniFile.getBoolValue(); + else if (iniFile.isName("broadcastID")) + { + chanMgr->broadcastID.fromStr(iniFile.getStrValue()); + chanMgr->broadcastID.id[0] = PCP_BROADCAST_FLAGS; // hacky, but we need to fix old clients + + }else if (iniFile.isName("htmlPath")) + strcpy(servMgr->htmlPath,iniFile.getStrValue()); + else if (iniFile.isName("maxPGNUIncoming")) + servMgr->maxGnuIncoming = iniFile.getIntValue(); + else if (iniFile.isName("minPGNUIncoming")) + servMgr->minGnuIncoming = iniFile.getIntValue(); + + else if (iniFile.isName("maxControlConnections")) + { + servMgr->maxControl = iniFile.getIntValue(); + + } + else if (iniFile.isName("maxBitrateOut")) + servMgr->maxBitrateOut = iniFile.getIntValue(); + + else if (iniFile.isName("maxStreamsOut")) // depreciated + servMgr->setMaxRelays(iniFile.getIntValue()); + else if (iniFile.isName("maxRelays")) + servMgr->setMaxRelays(iniFile.getIntValue()); + else if (iniFile.isName("maxDirect")) + servMgr->maxDirect = iniFile.getIntValue(); + + else if (iniFile.isName("maxStreamsPerChannel")) // depreciated + chanMgr->maxRelaysPerChannel = iniFile.getIntValue(); + else if (iniFile.isName("maxRelaysPerChannel")) + chanMgr->maxRelaysPerChannel = iniFile.getIntValue(); + + else if (iniFile.isName("firewallTimeout")) + firewallTimeout = iniFile.getIntValue(); + else if (iniFile.isName("forceNormal")) + forceNormal = iniFile.getBoolValue(); + else if (iniFile.isName("broadcastMsgInterval")) + chanMgr->broadcastMsgInterval = iniFile.getIntValue(); + else if (iniFile.isName("broadcastMsg")) + chanMgr->broadcastMsg.set(iniFile.getStrValue(),String::T_ASCII); + else if (iniFile.isName("hostUpdateInterval")) + chanMgr->hostUpdateInterval = iniFile.getIntValue(); + else if (iniFile.isName("icyMetaInterval")) + chanMgr->icyMetaInterval = iniFile.getIntValue(); + else if (iniFile.isName("maxServIn")) + servMgr->maxServIn = iniFile.getIntValue(); + else if (iniFile.isName("chanLog")) + servMgr->chanLog.set(iniFile.getStrValue(),String::T_ASCII); + + else if (iniFile.isName("rootMsg")) + rootMsg.set(iniFile.getStrValue()); + else if (iniFile.isName("networkID")) + networkID.fromStr(iniFile.getStrValue()); + else if (iniFile.isName("authType")) + { + char *t = iniFile.getStrValue(); + if (stricmp(t,"cookie")==0) + servMgr->authType = ServMgr::AUTH_COOKIE; + else if (stricmp(t,"http-basic")==0) + servMgr->authType = ServMgr::AUTH_HTTPBASIC; + }else if (iniFile.isName("cookiesExpire")) + { + char *t = iniFile.getStrValue(); + if (stricmp(t,"never")==0) + servMgr->cookieList.neverExpire = true; + else if (stricmp(t,"session")==0) + servMgr->cookieList.neverExpire = false; + + + } + + // privacy settings + else if (iniFile.isName("password")) + strcpy(servMgr->password,iniFile.getStrValue()); + else if (iniFile.isName("maxUptime")) + chanMgr->maxUptime = iniFile.getIntValue(); + + // client settings + + else if (iniFile.isName("rootHost")) + { + if (!PCP_FORCE_YP) + servMgr->rootHost = iniFile.getStrValue(); + + }else if (iniFile.isName("deadHitAge")) + chanMgr->deadHitAge = iniFile.getIntValue(); + else if (iniFile.isName("tryoutDelay")) + servMgr->tryoutDelay = iniFile.getIntValue(); + else if (iniFile.isName("refreshHTML")) + refreshHTML = iniFile.getIntValue(); + else if (iniFile.isName("relayBroadcast")) + { + servMgr->relayBroadcast = iniFile.getIntValue(); + if (servMgr->relayBroadcast < 30) + servMgr->relayBroadcast = 30; + } + else if (iniFile.isName("minBroadcastTTL")) + chanMgr->minBroadcastTTL = iniFile.getIntValue(); + else if (iniFile.isName("maxBroadcastTTL")) + chanMgr->maxBroadcastTTL = iniFile.getIntValue(); + else if (iniFile.isName("pushTimeout")) + chanMgr->pushTimeout = iniFile.getIntValue(); + else if (iniFile.isName("pushTries")) + chanMgr->pushTries = iniFile.getIntValue(); + else if (iniFile.isName("maxPushHops")) + chanMgr->maxPushHops = iniFile.getIntValue(); + else if (iniFile.isName("autoQuery")) + { + chanMgr->autoQuery = iniFile.getIntValue(); + if ((chanMgr->autoQuery < 300) && (chanMgr->autoQuery > 0)) + chanMgr->autoQuery = 300; + } + else if (iniFile.isName("queryTTL")) + { + servMgr->queryTTL = iniFile.getIntValue(); + } + + //JP-Extend + else if (iniFile.isName("autoRelayKeep")) + servMgr->autoRelayKeep = iniFile.getIntValue(); + else if (iniFile.isName("autoMaxRelaySetting")) + servMgr->autoMaxRelaySetting = iniFile.getIntValue(); + else if (iniFile.isName("autoBumpSkipCount")) + servMgr->autoBumpSkipCount = iniFile.getIntValue(); + else if (iniFile.isName("kickPushStartRelays")) + servMgr->kickPushStartRelays = iniFile.getIntValue(); + else if (iniFile.isName("kickPushInterval")) + { + servMgr->kickPushInterval = iniFile.getIntValue(); + if (servMgr->kickPushInterval < 60) + servMgr->kickPushInterval = 0; + } + else if (iniFile.isName("allowConnectPCST")) + servMgr->allowConnectPCST = iniFile.getIntValue(); + else if (iniFile.isName("enableGetName")) + servMgr->enableGetName = iniFile.getIntValue(); + + else if (iniFile.isName("maxRelaysIndexTxt")) // for PCRaw (relay) + servMgr->maxRelaysIndexTxt = iniFile.getIntValue(); + + //JP-Windows + else if (iniFile.isName("getModulePath")) + servMgr->getModulePath = iniFile.getBoolValue(); + else if (iniFile.isName("clearPLS")) + servMgr->clearPLS = iniFile.getBoolValue(); + else if (iniFile.isName("writeLogFile")) + servMgr->writeLogFile = iniFile.getBoolValue(); + + //VP-EX + else if (iniFile.isName("rootHost2")) + { + if (!PCP_FORCE_YP) + servMgr->rootHost2 = iniFile.getStrValue(); + } + else if (iniFile.isName("autoPort0Kick")) + servMgr->autoPort0Kick = iniFile.getBoolValue(); + else if (iniFile.isName("allowOnlyVP")) + servMgr->allowOnlyVP = iniFile.getBoolValue(); + else if (iniFile.isName("kickKeepTime")) + servMgr->kickKeepTime = iniFile.getIntValue(); + else if (iniFile.isName("vpDebug")) + servMgr->vpDebug = iniFile.getBoolValue(); + else if (iniFile.isName("saveIniChannel")) + servMgr->saveIniChannel = iniFile.getBoolValue(); +#ifdef WIN32 + else if (iniFile.isName("saveGuiPos")) + servMgr->saveGuiPos = iniFile.getBoolValue(); + else if (iniFile.isName("guiTop")) + winPlace.rcNormalPosition.top = iniFile.getIntValue(); + else if (iniFile.isName("guiBottom")) + winPlace.rcNormalPosition.bottom = iniFile.getIntValue(); + else if (iniFile.isName("guiLeft")) + winPlace.rcNormalPosition.left = iniFile.getIntValue(); + else if (iniFile.isName("guiRight")){ + winPlace.rcNormalPosition.right = iniFile.getIntValue(); + winPlace.length = sizeof(winPlace); + winPlace.flags = 0; + winPlace.showCmd = 1; + winPlace.ptMinPosition.x = -1; + winPlace.ptMinPosition.y = -1; + winPlace.ptMaxPosition.x = -1; + winPlace.ptMaxPosition.y = -1; + if (servMgr->saveGuiPos){ + guiFlg = true; + } + } +#endif + + // debug + else if (iniFile.isName("logDebug")) + showLog |= iniFile.getBoolValue() ? 1<idleSleepTime = iniFile.getIntValue(); + else if (iniFile.isName("[Server1]")) + allowServer1 = readServerSettings(iniFile,allowServer1); + else if (iniFile.isName("[Server2]")) + allowServer2 = readServerSettings(iniFile,allowServer2); + else if (iniFile.isName("[Filter]")) + { + readFilterSettings(iniFile,filters[numFilters]); + + if (numFilters < (MAX_FILTERS-1)) + numFilters++; + } + else if (iniFile.isName("[Notify]")) + { + notifyMask = NT_UPGRADE; + while (iniFile.readNext()) + { + if (iniFile.isName("[End]")) + break; + else if (iniFile.isName("PeerCast")) + notifyMask |= iniFile.getBoolValue()?NT_PEERCAST:0; + else if (iniFile.isName("Broadcasters")) + notifyMask |= iniFile.getBoolValue()?NT_BROADCASTERS:0; + else if (iniFile.isName("TrackInfo")) + notifyMask |= iniFile.getBoolValue()?NT_TRACKINFO:0; + } + + } + else if (iniFile.isName("[RelayChannel]")) + { + ChanInfo info; + bool stayConnected=false; + String sourceURL; + while (iniFile.readNext()) + { + if (iniFile.isName("[End]")) + break; + else if (iniFile.isName("name")) + info.name.set(iniFile.getStrValue()); + else if (iniFile.isName("id")) + info.id.fromStr(iniFile.getStrValue()); + else if (iniFile.isName("sourceType")) + info.srcProtocol = ChanInfo::getProtocolFromStr(iniFile.getStrValue()); + else if (iniFile.isName("contentType")) + info.contentType = ChanInfo::getTypeFromStr(iniFile.getStrValue()); + else if (iniFile.isName("stayConnected")) + stayConnected = iniFile.getBoolValue(); + else if (iniFile.isName("sourceURL")) + sourceURL.set(iniFile.getStrValue()); + else if (iniFile.isName("genre")) + info.genre.set(iniFile.getStrValue()); + else if (iniFile.isName("contactURL")) + info.url.set(iniFile.getStrValue()); + else if (iniFile.isName("bitrate")) + info.bitrate = atoi(iniFile.getStrValue()); + else if (iniFile.isName("tracker")) + { + ChanHit hit; + hit.init(); + hit.tracker = true; + hit.host.fromStrName(iniFile.getStrValue(),DEFAULT_PORT); + hit.rhost[0] = hit.host; + hit.rhost[1] = hit.host; + hit.chanID = info.id; + hit.recv = true; + chanMgr->addHit(hit); + } + + } + if (sourceURL.isEmpty()) + { + chanMgr->createRelay(info,stayConnected); + }else + { + info.bcID = chanMgr->broadcastID; + Channel *c = chanMgr->createChannel(info,NULL); + if (c) + c->startURL(sourceURL.cstr()); + } + } else if (iniFile.isName("[Host]")) + { + Host h; + ServHost::TYPE type=ServHost::T_NONE; + bool firewalled=false; + unsigned int time=0; + while (iniFile.readNext()) + { + if (iniFile.isName("[End]")) + break; + else if (iniFile.isName("address")) + h.fromStrIP(iniFile.getStrValue(),DEFAULT_PORT); + else if (iniFile.isName("type")) + type = ServHost::getTypeFromStr(iniFile.getStrValue()); + else if (iniFile.isName("time")) + time = iniFile.getIntValue(); + } + servMgr->addHost(h,type,time); + + } else if (iniFile.isName("[ValidBCID]")) + { + BCID *bcid = new BCID(); + while (iniFile.readNext()) + { + if (iniFile.isName("[End]")) + break; + else if (iniFile.isName("id")) + bcid->id.fromStr(iniFile.getStrValue()); + else if (iniFile.isName("name")) + bcid->name.set(iniFile.getStrValue()); + else if (iniFile.isName("email")) + bcid->email.set(iniFile.getStrValue()); + else if (iniFile.isName("url")) + bcid->url.set(iniFile.getStrValue()); + else if (iniFile.isName("valid")) + bcid->valid = iniFile.getBoolValue(); + } + servMgr->addValidBCID(bcid); + } + } + } + + if (!numFilters) + setFilterDefaults(); + +} + +// -------------------------------------------------- +unsigned int ServMgr::numStreams(GnuID &cid, Servent::TYPE tp, bool all) +{ + int cnt = 0; + Servent *sv = servents; + while (sv) + { + if (sv->isConnected()) + if (sv->type == tp) + if (sv->chanID.isSame(cid)) + if (all || !sv->isPrivate()) + cnt++; + sv=sv->next; + } + return cnt; +} +// -------------------------------------------------- +unsigned int ServMgr::numStreams(Servent::TYPE tp, bool all) +{ + int cnt = 0; + Servent *sv = servents; + while (sv) + { + if (sv->isConnected()) + if (sv->type == tp) + if (all || !sv->isPrivate()) + { + // for PCRaw (relay) start. + if(tp == Servent::T_RELAY) + { + Channel *ch = chanMgr->findChannelByID(sv->chanID); + + // index.txt‚̓JƒEƒ“ƒg‚µ‚È‚¢ + if(!isIndexTxt(ch)) + cnt++; + } + else + // for PCRaw (relay) end. + { + cnt++; + } + } + sv=sv->next; + } + return cnt; +} + +// -------------------------------------------------- +bool ServMgr::getChannel(char *str,ChanInfo &info, bool relay) +{ + // remove file extension (only added for winamp) + //char *ext = strstr(str,"."); + //if (ext) *ext = 0; + + procConnectArgs(str,info); + + WLockBlock wb(&(chanMgr->channellock)); + + wb.on(); + Channel *ch; + + ch = chanMgr->findChannelByNameID(info); + if (ch && ch->thread.active) + { + + if (!ch->isPlaying()) + { + if (relay) + { + ch->info.lastPlayStart = 0; // force reconnect + ch->info.lastPlayEnd = 0; + }else + return false; + } + + info = ch->info; // get updated channel info + + return true; + }else + { + if (relay) + { + wb.off(); + ch = chanMgr->findAndRelay(info); + if (ch) + { + // «Exception point + info = ch->info; //get updated channel info + return true; + } + } + } + + return false; +} +// -------------------------------------------------- +int ServMgr::findChannel(ChanInfo &info) +{ +#if 0 + char idStr[64]; + info.id.toStr(idStr); + + + if (info.id.isSet()) + { + // if we have an ID then try and connect to known hosts carrying channel. + ServHost sh = getOutgoingServent(info.id); + addOutgoing(sh.host,info.id,true); + } + + GnuPacket pack; + + XML xml; + XML::Node *n = info.createQueryXML(); + xml.setRoot(n); + pack.initFind(NULL,&xml,servMgr->queryTTL); + + addReplyID(pack.id); + int cnt = broadcast(pack,NULL); + + LOG_NETWORK("Querying network: %s %s - %d servents",info.name.cstr(),idStr,cnt); + + return cnt; +#endif + return 0; +} +// -------------------------------------------------- +// add outgoing network connection from string (ip:port format) +bool ServMgr::addOutgoing(Host h, GnuID &netid, bool pri) +{ +#if 0 + if (h.ip) + { + if (!findServent(h.ip,h.port,netid)) + { + Servent *sv = allocServent(); + if (sv) + { + if (pri) + sv->priorityConnect = true; + sv->networkID = netid; + sv->initOutgoing(h,Servent::T_OUTGOING); + return true; + } + } + } +#endif + return false; +} +// -------------------------------------------------- +Servent *ServMgr::findConnection(Servent::TYPE t,GnuID &sid) +{ + Servent *sv = servents; + while (sv) + { + if (sv->isConnected()) + if (sv->type == t) + if (sv->remoteID.isSame(sid)) + return sv; + sv=sv->next; + } + return NULL; +} + +// -------------------------------------------------- +void ServMgr::procConnectArgs(char *str,ChanInfo &info) +{ + char arg[MAX_CGI_LEN]; + char curr[MAX_CGI_LEN]; + + char *args = strstr(str,"?"); + if (args) + *args++=0; + + info.initNameID(str); + + if (args) + { + + while (args=nextCGIarg(args,curr,arg)) + { + LOG_DEBUG("cmd: %s, arg: %s",curr,arg); + + if (strcmp(curr,"sip")==0) + // sip - add network connection to client with channel + { + Host h; + h.fromStrName(arg,DEFAULT_PORT); + if (addOutgoing(h,servMgr->networkID,true)) + LOG_NETWORK("Added connection: %s",arg); + + }else if (strcmp(curr,"pip")==0) + // pip - add private network connection to client with channel + { + Host h; + h.fromStrName(arg,DEFAULT_PORT); + if (addOutgoing(h,info.id,true)) + LOG_NETWORK("Added private connection: %s",arg); + }else if (strcmp(curr,"ip")==0) + // ip - add hit + { + Host h; + h.fromStrName(arg,DEFAULT_PORT); + ChanHit hit; + hit.init(); + hit.host = h; + hit.rhost[0] = h; + hit.rhost[1].init(); + hit.chanID = info.id; + hit.recv = true; + + chanMgr->addHit(hit); + }else if (strcmp(curr,"tip")==0) + // tip - add tracker hit + { + Host h; + h.fromStrName(arg,DEFAULT_PORT); + chanMgr->hitlistlock.on(); + chanMgr->addHit(h,info.id,true); + chanMgr->hitlistlock.off(); + + } + + + } + } +} + +// -------------------------------------------------- +bool ServMgr::start() +{ + char idStr[64]; + + + const char *priv; +#if PRIVATE_BROADCASTER + priv = "(private)"; +#else + priv = ""; +#endif +#ifdef VERSION_EX + LOG_DEBUG("Peercast %s, %s %s",PCX_VERSTRING_EX,peercastApp->getClientTypeOS(),priv); +#else + LOG_DEBUG("Peercast %s, %s %s",PCX_VERSTRING,peercastApp->getClientTypeOS(),priv); +#endif + + sessionID.toStr(idStr); + LOG_DEBUG("SessionID: %s",idStr); + + chanMgr->broadcastID.toStr(idStr); + LOG_DEBUG("BroadcastID: %s",idStr); + checkForceIP(); + + + serverThread.func = ServMgr::serverProc; + if (!sys->startThread(&serverThread)) + return false; + + idleThread.func = ServMgr::idleProc; + if (!sys->startThread(&idleThread)) + return false; + + return true; +} +// -------------------------------------------------- +int ServMgr::clientProc(ThreadInfo *thread) +{ +#if 0 + thread->lock(); + + GnuID netID; + netID = servMgr->networkID; + + while(thread->active) + { + if (servMgr->autoConnect) + { + if (servMgr->needConnections() || servMgr->forceLookup) + { + if (servMgr->needHosts() || servMgr->forceLookup) + { + // do lookup to find some hosts + + Host lh; + lh.fromStrName(servMgr->connectHost,DEFAULT_PORT); + + + if (!servMgr->findServent(lh.ip,lh.port,netID)) + { + Servent *sv = servMgr->allocServent(); + if (sv) + { + LOG_DEBUG("Lookup: %s",servMgr->connectHost); + sv->networkID = netID; + sv->initOutgoing(lh,Servent::T_LOOKUP); + servMgr->forceLookup = false; + } + } + } + + for(int i=0; ioutUsedFull()) + break; + if (servMgr->tryFull()) + break; + + + ServHost sh = servMgr->getOutgoingServent(netID); + + if (!servMgr->addOutgoing(sh.host,netID,false)) + servMgr->deadHost(sh.host,ServHost::T_SERVENT); + sys->sleep(servMgr->tryoutDelay); + break; + } + } + }else{ +#if 0 + Servent *s = servMgr->servents; + while (s) + { + + if (s->type == Servent::T_OUTGOING) + s->thread.active = false; + s=s->next; + } +#endif + } + sys->sleepIdle(); + } + thread->unlock(); +#endif + return 0; +} +// ----------------------------------- +bool ServMgr::acceptGIV(ClientSocket *sock) +{ + Servent *sv = servents; + while (sv) + { + if (sv->type == Servent::T_COUT) + { + if (sv->acceptGIV(sock)) + return true; + } + sv=sv->next; + } + return false; +} + +// ----------------------------------- +int ServMgr::broadcastPushRequest(ChanHit &hit, Host &to, GnuID &chanID, Servent::TYPE type) +{ + ChanPacket pack; + MemoryStream pmem(pack.data,sizeof(pack.data)); + AtomStream atom(pmem); + +#ifndef VERSION_EX + atom.writeParent(PCP_BCST,8); +#else + atom.writeParent(PCP_BCST,10); +#endif + atom.writeChar(PCP_BCST_GROUP,PCP_BCST_GROUP_ALL); + atom.writeChar(PCP_BCST_HOPS,0); + atom.writeChar(PCP_BCST_TTL,7); + atom.writeBytes(PCP_BCST_DEST,hit.sessionID.id,16); + atom.writeBytes(PCP_BCST_FROM,servMgr->sessionID.id,16); + atom.writeInt(PCP_BCST_VERSION,PCP_CLIENT_VERSION); + atom.writeInt(PCP_BCST_VERSION_VP,PCP_CLIENT_VERSION_VP); +#ifdef VERSION_EX + atom.writeBytes(PCP_BCST_VERSION_EX_PREFIX,PCP_CLIENT_VERSION_EX_PREFIX,2); + atom.writeShort(PCP_BCST_VERSION_EX_NUMBER,PCP_CLIENT_VERSION_EX_NUMBER); +#endif + atom.writeParent(PCP_PUSH,3); + atom.writeInt(PCP_PUSH_IP,to.ip); + atom.writeShort(PCP_PUSH_PORT,to.port); + atom.writeBytes(PCP_PUSH_CHANID,chanID.id,16); + + + pack.len = pmem.pos; + pack.type = ChanPacket::T_PCP; + + + GnuID noID; + noID.clear(); + + return servMgr->broadcastPacket(pack,noID,servMgr->sessionID,hit.sessionID,type); +} + +// -------------------------------------------------- +void ServMgr::writeRootAtoms(AtomStream &atom, bool getUpdate) +{ + atom.writeParent(PCP_ROOT,5 + (getUpdate?1:0)); + atom.writeInt(PCP_ROOT_UPDINT,chanMgr->hostUpdateInterval); + atom.writeString(PCP_ROOT_URL,"download.php"); + atom.writeInt(PCP_ROOT_CHECKVER,PCP_ROOT_VERSION); + atom.writeInt(PCP_ROOT_NEXT,chanMgr->hostUpdateInterval); + atom.writeString(PCP_MESG_ASCII,rootMsg.cstr()); + if (getUpdate) + atom.writeParent(PCP_ROOT_UPDATE,0); + +} +// -------------------------------------------------- +void ServMgr::broadcastRootSettings(bool getUpdate) +{ + if (isRoot) + { + + ChanPacket pack; + MemoryStream mem(pack.data,sizeof(pack.data)); + AtomStream atom(mem); +#ifndef VERSION_EX + atom.writeParent(PCP_BCST,7); +#else + atom.writeParent(PCP_BCST,9); +#endif + atom.writeChar(PCP_BCST_GROUP,PCP_BCST_GROUP_TRACKERS); + atom.writeChar(PCP_BCST_HOPS,0); + atom.writeChar(PCP_BCST_TTL,7); + atom.writeBytes(PCP_BCST_FROM,sessionID.id,16); + atom.writeInt(PCP_BCST_VERSION,PCP_CLIENT_VERSION); + atom.writeInt(PCP_BCST_VERSION_VP,PCP_CLIENT_VERSION_VP); +#ifdef VERSION_EX + atom.writeBytes(PCP_BCST_VERSION_EX_PREFIX,PCP_CLIENT_VERSION_EX_PREFIX,2); + atom.writeShort(PCP_BCST_VERSION_EX_NUMBER,PCP_CLIENT_VERSION_EX_NUMBER); +#endif + writeRootAtoms(atom,getUpdate); + + mem.len = mem.pos; + mem.rewind(); + pack.len = mem.len; + + GnuID noID; + noID.clear(); + + broadcastPacket(pack,noID,servMgr->sessionID,noID,Servent::T_CIN); + } +} +// -------------------------------------------------- +int ServMgr::broadcastPacket(ChanPacket &pack,GnuID &chanID,GnuID &srcID, GnuID &destID, Servent::TYPE type) +{ + int cnt=0; + + Servent *sv = servents; + while (sv) + { + if (sv->sendPacket(pack,chanID,srcID,destID,type)) + cnt++; + sv=sv->next; + } + return cnt; +} + +// -------------------------------------------------- +int ServMgr::idleProc(ThreadInfo *thread) +{ + +// thread->lock(); + + unsigned int lastPasvFind=0; + unsigned int lastBroadcast=0; + + + // nothing much to do for the first couple of seconds, so just hang around. + sys->sleep(2000); + + unsigned int lastBWcheck=0; + unsigned int bytesIn=0,bytesOut=0; + + unsigned int lastBroadcastConnect = 0; + unsigned int lastRootBroadcast = 0; + + unsigned int lastForceIPCheck = 0; + + while(thread->active) + { + stats.update(); + + + + unsigned int ctime = sys->getTime(); + + + if (!servMgr->forceIP.isEmpty()) + { + if ((ctime-lastForceIPCheck) > 60) + { + if (servMgr->checkForceIP()) + { + GnuID noID; + noID.clear(); + chanMgr->broadcastTrackerUpdate(noID,true); + } + lastForceIPCheck = ctime; + } + } + + + if (chanMgr->isBroadcasting()) + { + if ((ctime-lastBroadcastConnect) > 30) + { + servMgr->connectBroadcaster(); + lastBroadcastConnect = ctime; + } + } + + if (servMgr->isRoot) + { + if ((servMgr->lastIncoming) && ((ctime-servMgr->lastIncoming) > 60*60)) + { + peercastInst->saveSettings(); + sys->exit(); + } + + if ((ctime-lastRootBroadcast) > chanMgr->hostUpdateInterval) + { + servMgr->broadcastRootSettings(true); + lastRootBroadcast = ctime; + } + } + + + // clear dead hits + chanMgr->clearDeadHits(true); + + if (servMgr->kickPushStartRelays && servMgr->kickPushInterval) //JP-EX + { + servMgr->banFirewalledHost(); + } + + if (servMgr->shutdownTimer) + { + if (--servMgr->shutdownTimer <= 0) + { + peercastInst->saveSettings(); + sys->exit(); + } + } + + // shutdown idle channels + if (chanMgr->numIdleChannels() > ChanMgr::MAX_IDLE_CHANNELS) + chanMgr->closeOldestIdle(); + + + sys->sleep(500); + } + + sys->endThread(thread); +// thread->unlock(); + return 0; +} + +// -------------------------------------------------- +int ServMgr::serverProc(ThreadInfo *thread) +{ + +// thread->lock(); + + Servent *serv = servMgr->allocServent(); + Servent *serv2 = servMgr->allocServent(); + + unsigned int lastLookupTime=0; + + + while (thread->active) + { + + if (servMgr->restartServer) + { + serv->abort(); // force close + serv2->abort(); // force close + servMgr->quit(); + + servMgr->restartServer = false; + } + + if (servMgr->autoServe) + { + serv->allow = servMgr->allowServer1; + serv2->allow = servMgr->allowServer2; + + + if ((!serv->sock) || (!serv2->sock)) + { + LOG_DEBUG("Starting servers"); +// servMgr->forceLookup = true; + + //if (servMgr->serverHost.ip != 0) + { + + if (servMgr->forceNormal) + servMgr->setFirewall(ServMgr::FW_OFF); + else + servMgr->setFirewall(ServMgr::FW_UNKNOWN); + + Host h = servMgr->serverHost; + + if (!serv->sock) + serv->initServer(h); + + h.port++; + if (!serv2->sock) + serv2->initServer(h); + + + } + } + }else{ + // stop server + serv->abort(); // force close + serv2->abort(); // force close + + // cancel incoming connectuions + Servent *s = servMgr->servents; + while (s) + { + if (s->type == Servent::T_INCOMING) + s->thread.active = false; + s=s->next; + } + + servMgr->setFirewall(ServMgr::FW_ON); + } + + sys->sleepIdle(); + + } + + sys->endThread(thread); +// thread->unlock(); + return 0; +} + +// ----------------------------------- +void ServMgr::setMaxRelays(int max) +{ + if (max < MIN_RELAYS) + max = MIN_RELAYS; + maxRelays = max; +} + +// ----------------------------------- +XML::Node *ServMgr::createServentXML() +{ + + return new XML::Node("servent agent=\"%s\" ",PCX_AGENT); +} + +// -------------------------------------------------- +const char *ServHost::getTypeStr(TYPE t) +{ + switch(t) + { + case T_NONE: return "NONE"; + case T_STREAM: return "STREAM"; + case T_CHANNEL: return "CHANNEL"; + case T_SERVENT: return "SERVENT"; + case T_TRACKER: return "TRACKER"; + } + return "UNKNOWN"; +} +// -------------------------------------------------- +ServHost::TYPE ServHost::getTypeFromStr(const char *s) +{ + if (stricmp(s,"NONE")==0) + return T_NONE; + else if (stricmp(s,"SERVENT")==0) + return T_SERVENT; + else if (stricmp(s,"STREAM")==0) + return T_STREAM; + else if (stricmp(s,"CHANNEL")==0) + return T_CHANNEL; + else if (stricmp(s,"TRACKER")==0) + return T_TRACKER; + + return T_NONE; +} + + +// -------------------------------------------------- +bool ServFilter::writeVariable(Stream &out, const String &var) +{ + char buf[1024]; + + if (var == "network") + strcpy(buf,(flags & F_NETWORK)?"1":"0"); + else if (var == "private") + strcpy(buf,(flags & F_PRIVATE)?"1":"0"); + else if (var == "direct") + strcpy(buf,(flags & F_DIRECT)?"1":"0"); + else if (var == "banned") + strcpy(buf,(flags & F_BAN)?"1":"0"); + else if (var == "ip") + host.IPtoStr(buf); + else + return false; + + + out.writeString(buf); + return true; +} +// -------------------------------------------------- +bool BCID::writeVariable(Stream &out, const String &var) +{ + char buf[1024]; + + if (var == "id") + id.toStr(buf); + else if (var == "name") + strcpy(buf,name.cstr()); + else if (var == "email") + strcpy(buf,email.cstr()); + else if (var == "url") + strcpy(buf,url.cstr()); + else if (var == "valid") + strcpy(buf,valid?"Yes":"No"); + else + return false; + + + out.writeString(buf); + return true; +} + + +// -------------------------------------------------- +bool ServMgr::writeVariable(Stream &out, const String &var) +{ + char buf[1024]; + String str; + + if (var == "version") +#ifdef VERSION_EX + strcpy(buf,PCX_VERSTRING_EX); +#else + strcpy(buf,PCX_VERSTRING); +#endif + else if (var == "uptime") + { + str.setFromStopwatch(getUptime()); + str.convertTo(String::T_HTML); + strcpy(buf,str.cstr()); + }else if (var == "numRelays") + sprintf(buf,"%d",numStreams(Servent::T_RELAY,true)); + else if (var == "numDirect") + sprintf(buf,"%d",numStreams(Servent::T_DIRECT,true)); + else if (var == "totalConnected") + sprintf(buf,"%d",totalConnected()); + else if (var == "numServHosts") + sprintf(buf,"%d",numHosts(ServHost::T_SERVENT)); + else if (var == "numServents") + sprintf(buf,"%d",numServents()); + else if (var == "serverPort") + sprintf(buf,"%d",serverHost.port); + else if (var == "serverIP") + serverHost.IPtoStr(buf); + else if (var == "ypAddress") + strcpy(buf,rootHost.cstr()); + else if (var == "password") + strcpy(buf,password); + else if (var == "isFirewalled") + sprintf(buf,"%d",getFirewall()==FW_ON?1:0); + else if (var == "firewallKnown") + sprintf(buf,"%d",getFirewall()==FW_UNKNOWN?0:1); + else if (var == "rootMsg") + strcpy(buf,rootMsg); + else if (var == "isRoot") + sprintf(buf,"%d",isRoot?1:0); + else if (var == "isPrivate") + sprintf(buf,"%d",(PCP_BROADCAST_FLAGS&1)?1:0); + else if (var == "forceYP") + sprintf(buf,"%d",PCP_FORCE_YP?1:0); + else if (var == "refreshHTML") + sprintf(buf,"%d",refreshHTML?refreshHTML:0x0fffffff); + else if (var == "maxRelays") + sprintf(buf,"%d",maxRelays); + else if (var == "maxDirect") + sprintf(buf,"%d",maxDirect); + else if (var == "maxBitrateOut") + sprintf(buf,"%d",maxBitrateOut); + else if (var == "maxControlsIn") + sprintf(buf,"%d",maxControl); + else if (var == "numFilters") + sprintf(buf,"%d",numFilters+1); + else if (var == "maxPGNUIn") + sprintf(buf,"%d",maxGnuIncoming); + else if (var == "minPGNUIn") + sprintf(buf,"%d",minGnuIncoming); + else if (var == "numActive1") + sprintf(buf,"%d",numActiveOnPort(serverHost.port)); + else if (var == "numActive2") + sprintf(buf,"%d",numActiveOnPort(serverHost.port+1)); + else if (var == "numPGNU") + sprintf(buf,"%d",numConnected(Servent::T_PGNU)); + else if (var == "numCIN") + sprintf(buf,"%d",numConnected(Servent::T_CIN)); + else if (var == "numCOUT") + sprintf(buf,"%d",numConnected(Servent::T_COUT)); + else if (var == "numIncoming") + sprintf(buf,"%d",numActive(Servent::T_INCOMING)); + else if (var == "numValidBCID") + { + int cnt = 0; + BCID *bcid = validBCID; + while (bcid) + { + cnt++; + bcid=bcid->next; + } + sprintf(buf,"%d",cnt); + } + + else if (var == "disabled") + sprintf(buf,"%d",isDisabled); + + // JP-EX + else if (var.startsWith("autoRelayKeep")) { + if (var == "autoRelayKeep.0") + strcpy(buf, (autoRelayKeep == 0) ? "1":"0"); + else if (var == "autoRelayKeep.1") + strcpy(buf, (autoRelayKeep == 1) ? "1":"0"); + else if (var == "autoRelayKeep.2") + strcpy(buf, (autoRelayKeep == 2) ? "1":"0"); + } else if (var == "autoMaxRelaySetting") + sprintf(buf,"%d",autoMaxRelaySetting); + else if (var == "autoBumpSkipCount") + sprintf(buf,"%d",autoBumpSkipCount); + else if (var == "kickPushStartRelays") + sprintf(buf,"%d",kickPushStartRelays); + else if (var == "kickPushInterval") + sprintf(buf,"%d",kickPushInterval); + else if (var == "allowConnectPCST") + strcpy(buf, (allowConnectPCST == 1) ? "1":"0"); + else if (var == "enableGetName") + strcpy(buf, (enableGetName == 1)? "1":"0"); + + // VP-EX + else if (var == "ypAddress2") + strcpy(buf,rootHost2.cstr()); + else if (var.startsWith("autoPort0Kick")) { + if (var == "autoPort0Kick.0") + strcpy(buf, (autoPort0Kick == 0) ? "1":"0"); + else if (var == "autoPort0Kick.1") + strcpy(buf, (autoPort0Kick == 1) ? "1":"0"); + } + else if (var.startsWith("allowOnlyVP")) { + if (var == "allowOnlyVP.0") + strcpy(buf, (allowOnlyVP == 0) ? "1":"0"); + else if (var == "allowOnlyVP.1") + strcpy(buf, (allowOnlyVP == 1) ? "1":"0"); + } + else if (var == "kickKeepTime") + sprintf(buf, "%d",kickKeepTime); + + else if (var == "serverPort1") + sprintf(buf,"%d",serverHost.port); + else if (var == "serverLocalIP") + { + Host lh(ClientSocket::getIP(NULL),0); + char ipStr[64]; + lh.IPtoStr(ipStr); + strcpy(buf,ipStr); + }else if (var == "upgradeURL") + strcpy(buf,servMgr->downloadURL); + else if (var == "serverPort2") + sprintf(buf,"%d",serverHost.port+1); + else if (var.startsWith("allow.")) + { + if (var == "allow.HTML1") + strcpy(buf,(allowServer1&Servent::ALLOW_HTML)?"1":"0"); + else if (var == "allow.HTML2") + strcpy(buf,(allowServer2&Servent::ALLOW_HTML)?"1":"0"); + else if (var == "allow.broadcasting1") + strcpy(buf,(allowServer1&Servent::ALLOW_BROADCAST)?"1":"0"); + else if (var == "allow.broadcasting2") + strcpy(buf,(allowServer2&Servent::ALLOW_BROADCAST)?"1":"0"); + else if (var == "allow.network1") + strcpy(buf,(allowServer1&Servent::ALLOW_NETWORK)?"1":"0"); + else if (var == "allow.direct1") + strcpy(buf,(allowServer1&Servent::ALLOW_DIRECT)?"1":"0"); + }else if (var.startsWith("auth.")) + { + if (var == "auth.useCookies") + strcpy(buf,(authType==AUTH_COOKIE)?"1":"0"); + else if (var == "auth.useHTTP") + strcpy(buf,(authType==AUTH_HTTPBASIC)?"1":"0"); + else if (var == "auth.useSessionCookies") + strcpy(buf,(cookieList.neverExpire==false)?"1":"0"); + + }else if (var.startsWith("log.")) + { + if (var == "log.debug") + strcpy(buf,(showLog&(1<kickPushStartRelays) + if (servMgr->numStreams(Servent::T_RELAY,false)>=(servMgr->kickPushStartRelays-1)) + return true; + + return false; +} +// -------------------------------------------------- +//JP-EX +void ServMgr::banFirewalledHost() +{ + unsigned int kickpushtime = sys->getTime(); + if ((kickpushtime-servMgr->kickPushTime) > servMgr->kickPushInterval) + { + servMgr->kickPushTime = kickpushtime; + Servent *s = servMgr->servents; + LOG_DEBUG("Servent scan start."); + while (s) + { + if (s->type != Servent::T_NONE) + { + Host h = s->getHost(); + int ip = h.ip; + int port = h.port; + Host h2(ip,port); + unsigned int tnum = 0; + + if (s->lastConnect) + tnum = sys->getTime() - s->lastConnect; + if ((s->type==Servent::T_RELAY) && (s->status==Servent::S_CONNECTED) && (tnum>servMgr->kickPushInterval)) + { +/* ChanHitList *hits[ChanMgr::MAX_HITLISTS]; + int numHits=0; + for(int i=0; ihitlists[i]; + if (chl->isUsed()) + hits[numHits++] = chl; + } + + bool isfw = false; + int numRelay = 0; + if (numHits) + { + for(int k=0; kisUsed()) + { + for (int j=0; jhits[j]; + if (hit->host.isValid() && (h2.ip == hit->host.ip)) + { + if (hit->firewalled) + isfw = true; + numRelay = hit->numRelays; + } + } + } + } + } + if ((isfw==true) && (numRelay==0)) + { + char hostName[256]; + h2.toStr(hostName); + if (servMgr->isCheckPushStream()) + { + s->thread.active = false; + LOG_ERROR("Stop firewalled Servent : %s",hostName); + } + }*/ + + chanMgr->hitlistlock.on(); + ChanHitList *chl = chanMgr->findHitListByID(s->chanID); + if (chl){ + ChanHit *hit = chl->hit; + while(hit){ + if ((hit->numHops == 1) && hit->host.isValid() && (h2.ip == hit->host.ip) && hit->firewalled /*&& !hit->numRelays*/) + { + char hostName[256]; + h2.toStr(hostName); + if (servMgr->isCheckPushStream()) + { + s->thread.active = false; + LOG_ERROR("Stop firewalled Servent : %s",hostName); + } + } + hit = hit->next; + } + + } + chanMgr->hitlistlock.off(); + + + } + } + s=s->next; + } + LOG_DEBUG("Servent scan finished."); + } +} + diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/servmgr.h b/c:/Git/PeerCast.root/PeerCast/core/common/servmgr.h new file mode 100644 index 0000000..492520e --- /dev/null +++ b/c:/Git/PeerCast.root/PeerCast/core/common/servmgr.h @@ -0,0 +1,428 @@ +// ------------------------------------------------ +// File : servmgr.h +// Date: 4-apr-2002 +// Author: giles +// Desc: +// +// (c) 2002 peercast.org +// ------------------------------------------------ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// ------------------------------------------------ + +#ifndef _SERVMGR_H +#define _SERVMGR_H + +#include "servent.h" + +// ---------------------------------- + +const int MIN_YP_RETRY = 20; +const int MIN_TRACKER_RETRY = 10; +const int MIN_RELAY_RETRY = 5; + +// ---------------------------------- +class BCID +{ +public: + BCID() + :next(0),valid(true) + {} + + bool writeVariable(Stream &, const String &); + + GnuID id; + String name,email,url; + bool valid; + BCID *next; +}; + + +// ---------------------------------- +class ServHost +{ +public: + enum TYPE + { + T_NONE, + T_STREAM, + T_CHANNEL, + T_SERVENT, + T_TRACKER + }; + + ServHost() {init();} + void init() + { + host.init(); + time = 0; + type = T_NONE; + } + void init(Host &h, TYPE tp, unsigned int tim) + { + init(); + host = h; + type = tp; + if (tim) + time = tim; + else + time = sys->getTime(); + } + + static const char *getTypeStr(TYPE); + static TYPE getTypeFromStr(const char *); + + TYPE type; + Host host; + unsigned int time; +}; +// ---------------------------------- +class ServFilter +{ +public: + enum + { + F_PRIVATE = 0x01, + F_BAN = 0x02, + F_NETWORK = 0x04, + F_DIRECT = 0x08 + }; + + ServFilter() {init();} + void init() + { + flags = 0; + host.init(); + } + + bool writeVariable(Stream &, const String &); + + Host host; + unsigned int flags; +}; + +// ---------------------------------- +// ServMgr keeps track of Servents +class ServMgr +{ + + + +public: + + enum NOTIFY_TYPE + { + NT_UPGRADE = 0x0001, + NT_PEERCAST = 0x0002, + NT_BROADCASTERS = 0x0004, + NT_TRACKINFO = 0x0008 + }; + + enum FW_STATE + { + FW_OFF, + FW_ON, + FW_UNKNOWN + }; + enum { + + MAX_HOSTCACHE = 100, // max. amount of hosts in cache + MIN_HOSTS = 3, // min. amount of hosts that should be kept in cache + + MAX_OUTGOING = 3, // max. number of outgoing servents to use + MAX_INCOMING = 6, // max. number of public incoming servents to use + MAX_TRYOUT = 10, // max. number of outgoing servents to try connect + MIN_CONNECTED = 3, // min. amount of connected hosts that should be kept + + MIN_RELAYS = 1, + + MAX_FILTERS = 50, + + MAX_VERSIONS = 16, + + MAX_PREVIEWTIME = 300, // max. seconds preview per channel available (direct connections) + MAX_PREVIEWWAIT = 300, // max. seconds wait between previews + + }; + + enum AUTH_TYPE + { + AUTH_COOKIE, + AUTH_HTTPBASIC + }; + + + + ServMgr(); + + bool start(); + + Servent *findServent(unsigned int,unsigned short,GnuID &); + Servent *findServent(Servent::TYPE); + Servent *findServent(Servent::TYPE,Host &,GnuID &); + Servent *findOldestServent(Servent::TYPE,bool); + Servent *findServentByIndex(int); + Servent *findServentByServentID(int); + + bool writeVariable(Stream &, const String &); + Servent *allocServent(); + unsigned int numUsed(int); + unsigned int numStreams(GnuID &, Servent::TYPE,bool); + unsigned int numStreams(Servent::TYPE,bool); + unsigned int numConnected(int,bool,unsigned int); + unsigned int numConnected(int t,int tim = 0) + { + return numConnected(t,false,tim)+numConnected(t,true,tim); + } + unsigned int numConnected(); + unsigned int numServents(); + + unsigned int totalConnected() + { + //return numConnected(Servent::T_OUTGOING) + numConnected(Servent::T_INCOMING); + return numConnected(); + } + unsigned int numOutgoing(); + bool isFiltered(int,Host &h); + bool addOutgoing(Host,GnuID &,bool); + Servent *findConnection(Servent::TYPE,GnuID &); + + + static THREAD_PROC serverProc(ThreadInfo *); + static THREAD_PROC clientProc(ThreadInfo *); + static THREAD_PROC trackerProc(ThreadInfo *); + static THREAD_PROC idleProc(ThreadInfo *); + + int broadcast(GnuPacket &,Servent * = NULL); + int route(GnuPacket &, GnuID &, Servent * = NULL); + + XML::Node *createServentXML(); + + void connectBroadcaster(); + void procConnectArgs(char *,ChanInfo &); + + void quit(); + void closeConnections(Servent::TYPE); + + void checkFirewall(); + + // host cache + void addHost(Host &,ServHost::TYPE,unsigned int); + int getNewestServents(Host *,int, Host &); + ServHost getOutgoingServent(GnuID &); + void deadHost(Host &,ServHost::TYPE); + unsigned int numHosts(ServHost::TYPE); + void clearHostCache(ServHost::TYPE); + bool seenHost(Host &,ServHost::TYPE,unsigned int); + + void setMaxRelays(int); + void setFirewall(FW_STATE); + bool checkForceIP(); + FW_STATE getFirewall() {return firewalled;} + void saveSettings(const char *); + void loadSettings(const char *); + void setPassiveSearch(unsigned int); + int findChannel(ChanInfo &); + bool getChannel(char *,ChanInfo &,bool); + void setFilterDefaults(); + + bool acceptGIV(ClientSocket *); + void addVersion(unsigned int); + + void broadcastRootSettings(bool); + int broadcastPushRequest(ChanHit &, Host &, GnuID &, Servent::TYPE); + void writeRootAtoms(AtomStream &,bool); + + int broadcastPacket(ChanPacket &,GnuID &,GnuID &,GnuID &,Servent::TYPE type); + + void addValidBCID(BCID *); + void removeValidBCID(GnuID &); + BCID *findValidBCID(GnuID &); + BCID *findValidBCID(int); + + unsigned int getUptime() + { + return sys->getTime()-startTime; + } + + bool seenPacket(GnuPacket &); + + + bool needHosts() + { + return false; + //return numHosts(ServHost::T_SERVENT) < maxTryout; + } + + unsigned int numActiveOnPort(int); + unsigned int numActive(Servent::TYPE); + + bool needConnections() + { + return numConnected(Servent::T_PGNU,60) < minGnuIncoming; + } + bool tryFull() + { + return false; + //return maxTryout ? numUsed(Servent::T_OUTGOING) > maxTryout: false; + } + + bool pubInOver() + { + return numConnected(Servent::T_PGNU) > maxGnuIncoming; +// return maxIncoming ? numConnected(Servent::T_INCOMING,false) > maxIncoming : false; + } + bool pubInFull() + { + return numConnected(Servent::T_PGNU) >= maxGnuIncoming; +// return maxIncoming ? numConnected(Servent::T_INCOMING,false) >= maxIncoming : false; + } + + bool outUsedFull() + { + return false; +// return maxOutgoing ? numUsed(Servent::T_OUTGOING) >= maxOutgoing: false; + } + bool outOver() + { + return false; +// return maxOutgoing ? numConnected(Servent::T_OUTGOING) > maxOutgoing : false; + } + + bool controlInFull() + { + return numConnected(Servent::T_CIN)>=maxControl; + } + + bool outFull() + { + return false; +// return maxOutgoing ? numConnected(Servent::T_OUTGOING) >= maxOutgoing : false; + } + + bool relaysFull() + { + return numStreams(Servent::T_RELAY,false) >= maxRelays; + } + bool directFull() + { + return numStreams(Servent::T_DIRECT,false) >= maxDirect; + } + + bool bitrateFull(unsigned int br) + { + return maxBitrateOut ? (BYTES_TO_KBPS(totalOutput(false))+br) > maxBitrateOut : false; + } + + unsigned int totalOutput(bool); + unsigned int totalInput(bool); + + static ThreadInfo serverThread,idleThread; + + + Servent *servents; + WLock lock; + + ServHost hostCache[MAX_HOSTCACHE]; + + char password[64]; + + bool allowGnutella; + + unsigned int maxBitrateOut,maxControl,maxRelays,maxDirect; + unsigned int minGnuIncoming,maxGnuIncoming; + unsigned int maxServIn; + + bool isDisabled; + bool isRoot; + int totalStreams; + + Host serverHost; + String rootHost; + String rootHost2; + + char downloadURL[128]; + String rootMsg; + String forceIP; + char connectHost[128]; + GnuID networkID; + unsigned int firewallTimeout; + int showLog; + int shutdownTimer; + bool pauseLog; + bool forceNormal; + bool useFlowControl; + unsigned int lastIncoming; + + bool restartServer; + bool allowDirect; + bool autoConnect,autoServe,forceLookup; + int queryTTL; + + unsigned int allowServer1,allowServer2; + unsigned int startTime; + unsigned int tryoutDelay; + unsigned int refreshHTML; + unsigned int relayBroadcast; + + unsigned int notifyMask; + + BCID *validBCID; + GnuID sessionID; + + ServFilter filters[MAX_FILTERS]; + int numFilters; + + + CookieList cookieList; + AUTH_TYPE authType; + + char htmlPath[128]; + unsigned int clientVersions[MAX_VERSIONS],clientCounts[MAX_VERSIONS]; + int numVersions; + + int serventNum; + String chanLog; + + char modulePath[256]; //JP-EX + int enableGetName; //JP-EX + int allowConnectPCST; //JP-EX + int autoRelayKeep; //JP-EX + unsigned int autoMaxRelaySetting; //JP-EX + unsigned int autoBumpSkipCount;//JP-EX + unsigned int kickPushStartRelays; //JP-EX + unsigned int kickPushInterval; //JP-EX + unsigned int kickPushTime; + bool isCheckPushStream(); //JP-EX + void banFirewalledHost(); //JP-EX + + bool getModulePath; //JP-EX + bool clearPLS; //JP-EX + bool writeLogFile; //JP-EX + + bool autoPort0Kick; + bool allowOnlyVP; + unsigned int kickKeepTime; + bool vpDebug; + bool saveIniChannel; + bool saveGuiPos; + bool keepDownstreams; + + int maxRelaysIndexTxt; // for PCRaw (relay) + +private: + FW_STATE firewalled; +}; + +// ---------------------------------- +extern ServMgr *servMgr; + + +#endif diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/socket.cpp b/c:/Git/PeerCast.root/PeerCast/core/common/socket.cpp new file mode 100644 index 0000000..80ac2dd --- /dev/null +++ b/c:/Git/PeerCast.root/PeerCast/core/common/socket.cpp @@ -0,0 +1,32 @@ +// ------------------------------------------------ +// File : socket.cpp +// Date: 4-apr-2002 +// Author: giles +// Desc: +// ClientSocket is a generic socket interface, Non OS/HW dependant. +// +// (c) 2002 peercast.org +// ------------------------------------------------ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// ------------------------------------------------ + + +#include +#include +#include "socket.h" +#include "sys.h" +#ifdef _DEBUG +#include "chkMemoryLeak.h" +#define DEBUG_NEW new(__FILE__, __LINE__) +#define new DEBUG_NEW +#endif + + diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/socket.h b/c:/Git/PeerCast.root/PeerCast/core/common/socket.h new file mode 100644 index 0000000..0e47e07 --- /dev/null +++ b/c:/Git/PeerCast.root/PeerCast/core/common/socket.h @@ -0,0 +1,185 @@ +// ------------------------------------------------ +// File : socket.h +// Date: 4-apr-2002 +// Author: giles +// Desc: +// +// (c) 2002 peercast.org +// ------------------------------------------------ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// ------------------------------------------------ + +#ifndef _SOCKET_H +#define _SOCKET_H + + +#include "common.h" +#include "stream.h" + +//#define DISABLE_NAGLE 1 + +class SocketBuffer { + +public: + SocketBuffer(const void *p, int l){ + buf = ::new char[l]; + len = l; + pos = 0; + next = NULL; + ctime = sys->getTime(); + memcpy((void*)buf, p, l); + } + + ~SocketBuffer(){ + if (buf){ + ::delete [] buf; + } + } + char *buf; + int len; + int pos; + unsigned int ctime; + SocketBuffer *next; +}; + +class SocketBufferList { + +public: + SocketBufferList(){ + top = NULL; + last = NULL; + skipCount = 0; + lastSkipTime = 0; + } + + bool isNull(){ return (top == NULL); } + void add(const void *p, int l){ + SocketBuffer *tmp = new SocketBuffer(p,l); + + if (!last){ + top = tmp; + last = tmp; + } else { + last->next = tmp; + last = tmp; + } + +// LOG_DEBUG("tmp = %d, top = %d, last = %d", tmp, top, last); + } + + SocketBuffer *getTop(){ + unsigned int ctime = sys->getTime(); + + while(top){ + if (top && (top->ctime + 10 >= ctime)){ + break; + } else { +// LOG_DEBUG("over 10sec(data skip)"); + skipCount++; + lastSkipTime = sys->getTime(); + deleteTop(); + } + } + return top; + } + + void deleteTop(){ +// LOG_DEBUG("oldtop = %d", top); + SocketBuffer *tmp = top; + top = tmp->next; + delete tmp; + if (!top){ + last = NULL; + } + +// LOG_DEBUG("newtop = %d",top); + } + + void clear(){ + while(top){ + SocketBuffer *tmp = top; + top = tmp->next; + delete tmp; + } + top = NULL; + last = NULL; + } + + SocketBuffer *top; + SocketBuffer *last; + unsigned int skipCount; + unsigned int lastSkipTime; + +}; + +// -------------------------------------------------- +class ClientSocket : public Stream +{ +public: + + ClientSocket() + { + readTimeout = 30000; + writeTimeout = 30000; +#ifdef WIN32 + skipCount = 0; + lastSkipTime = 0; +#endif + } + + ~ClientSocket(){ +#ifdef WIN32 + bufList.clear(); +#endif + } + + // required interface + virtual void open(Host &) = 0; + virtual void bind(Host &) = 0; + virtual void connect() = 0; + virtual bool active() = 0; + virtual ClientSocket *accept() = 0; + virtual Host getLocalHost() = 0; + + virtual void setReadTimeout(unsigned int t) + { + readTimeout = t; + } + virtual void setWriteTimeout(unsigned int t) + { + writeTimeout = t; + } + virtual void setBlocking(bool) {} + + + static unsigned int getIP(char *); + static bool getHostname(char *,unsigned int); + + virtual bool eof() + { + return active()==false; + } + + Host host; + +#ifdef WIN32 + SocketBufferList bufList; + virtual void bufferingWrite(const void *, int) = 0; + unsigned int skipCount; + unsigned int lastSkipTime; +#endif + + unsigned int readTimeout,writeTimeout; + +}; + + +#endif diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/stats.cpp b/c:/Git/PeerCast.root/PeerCast/core/common/stats.cpp new file mode 100644 index 0000000..46e0a44 --- /dev/null +++ b/c:/Git/PeerCast.root/PeerCast/core/common/stats.cpp @@ -0,0 +1,102 @@ +// ------------------------------------------------ +// File : stats.cpp +// Date: 4-apr-2002 +// Author: giles +// Desc: +// Statistic logging +// +// (c) 2002 peercast.org +// ------------------------------------------------ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// ------------------------------------------------ + + +#include "stats.h" +#include "common.h" +#include "sys.h" +#include "stream.h" +#ifdef _DEBUG +#include "chkMemoryLeak.h" +#define DEBUG_NEW new(__FILE__, __LINE__) +#define new DEBUG_NEW +#endif + +Stats stats; +// ------------------------------------ +void Stats::clear() +{ + for(int i=0; igetTime(); + + unsigned int diff = ctime - lastUpdate; + if (diff >= /* 5 */ 1) + { + + for(int i=0; i= 4) + { + out += String::base64WordToChars(out,in); + in += 4; + rl -= 4; + } + *out = 0; + len = out-buf; +} +// ------------------------------------- +void FileStream::openReadOnly(const char *fn) +{ + file = fopen(fn,"rb"); + + if (!file) + throw StreamException("Unable to open file"); +} +// ------------------------------------- +void FileStream::openWriteReplace(const char *fn) +{ + file = fopen(fn,"wb"); + + if (!file) + throw StreamException("Unable to open file"); +} +// ------------------------------------- +void FileStream::openWriteAppend(const char *fn) +{ + file = fopen(fn,"ab"); + + if (!file) + throw StreamException("Unable to open file"); +} + +// ------------------------------------- +void FileStream::close() +{ + if (file) + { + fclose(file); + file = NULL; + } +} +// ------------------------------------- +void FileStream::rewind() +{ + if (file) + fseek(file,0,SEEK_SET); +} +// ------------------------------------- +int FileStream::length() +{ + int len = 0; + if (file) + { + int old = ftell(file); + fseek(file,0,SEEK_END); + len = ftell(file); + fseek(file,old,SEEK_SET); + + } + return len; +} + +// ------------------------------------- +bool FileStream::eof() +{ + if (file) + return (feof(file)!=0); + else + return true; +} +// ------------------------------------- +int FileStream::read(void *ptr, int len) +{ + if (!file) + return 0; + if (feof(file)) + throw StreamException("End of file"); + + int r = (int)fread(ptr,1,len,file); + + updateTotals(r, 0); + return r; +} + +// ------------------------------------- +void FileStream::write(const void *ptr, int len) +{ + if (!file) + return; + fwrite(ptr,1,len,file); + updateTotals(0, len); + +} +// ------------------------------------- +void FileStream::flush() +{ + if (!file) + return; + fflush(file); +} +// ------------------------------------- +int FileStream::pos() +{ + if (!file) + return 0; + return ftell(file); +} + +// ------------------------------------- +void FileStream::seekTo(int pos) +{ + if (!file) + return; + fseek(file,pos,SEEK_SET); +} + +// ------------------------------------- +void Stream::writeTo(Stream &out, int len) +{ + char tmp[4096]; + while (len) + { + int rlen = sizeof(tmp); + if (rlen > len) + rlen = len; + + read(tmp,rlen); + out.write(tmp,rlen); + + len-=rlen; + } +} +// ------------------------------------- +int Stream::writeUTF8(unsigned int code) +{ + if (code < 0x80) + { + writeChar(code); + return 1; + }else + if (code < 0x0800) + { + writeChar(code>>6 | 0xC0); + writeChar(code & 0x3F | 0x80); + return 2; + }else if (code < 0x10000) + { + writeChar(code>>12 | 0xE0); + writeChar(code>>6 & 0x3F | 0x80); + writeChar(code & 0x3F | 0x80); + return 3; + }else + { + writeChar(code>>18 | 0xF0); + writeChar(code>>12 & 0x3F | 0x80); + writeChar(code>>6 & 0x3F | 0x80); + writeChar(code & 0x3F | 0x80); + return 4; + } + +} + +// ------------------------------------- +void Stream::skip(int len) +{ + char tmp[4096]; + while (len) + { + int rlen = sizeof(tmp); + if (rlen > len) + rlen = len; + read(tmp,rlen); + len-=rlen; + } + +} + + +// ------------------------------------- +void Stream::updateTotals(unsigned int in, unsigned int out) +{ + totalBytesIn += in; + totalBytesOut += out; + + unsigned int tdiff = sys->getTime()-lastUpdate; + if (tdiff >= 5) + { + bytesInPerSec = (totalBytesIn-lastBytesIn)/tdiff; + bytesOutPerSec = (totalBytesOut-lastBytesOut)/tdiff; + lastBytesIn = totalBytesIn; + lastBytesOut = totalBytesOut; + lastUpdate = sys->getTime(); + } +} +// ------------------------------------- +int Stream::readLine(char *in, int max) +{ + int i=0; + max -= 2; + + while(max--) + { + char c; + read(&c,1); + if (c == '\n') + break; + if (c == '\r') + continue; + in[i++] = c; + } + in[i] = 0; + return i; +} +// ------------------------------------- +void Stream::write(const char *fmt,va_list ap) +{ + char tmp[4096]; + vsprintf(tmp,fmt,ap); + write(tmp,strlen(tmp)); +} +// ------------------------------------- +void Stream::writeStringF(const char *fmt,...) +{ + va_list ap; + va_start(ap, fmt); + write(fmt,ap); + va_end(ap); +} +// ------------------------------------- +void Stream::writeString(const char *str) +{ + write(str,strlen(str)); +} +// ------------------------------------- +void Stream::writeLineF(const char *fmt,...) +{ + va_list ap; + va_start(ap, fmt); + + write(fmt,ap); + + if (writeCRLF) + write("\r\n",2); + else + write("\n",1); + + va_end(ap); +} + +// ------------------------------------- +void Stream::writeLine(const char *str) +{ + writeString(str); + + if (writeCRLF) + write("\r\n",2); + else + write("\n",1); +} + +// ------------------------------------- +int Stream::readWord(char *in, int max) +{ + int i=0; + while (!eof()) + { + char c = readChar(); + + if ((c == ' ') || (c == '\t') || (c == '\r') || (c == '\n')) + { + if (i) + break; // stop reading + else + continue; // skip whitespace + } + + if (i >= (max-1)) + break; + + in[i++] = c; + } + + in[i]=0; + return i; +} + + +// -------------------------------------------------- +int Stream::readBase64(char *p, int max) +{ + char vals[4]; + + int cnt=0; + while (cnt < (max-4)) + { + read(vals,4); + int rl = String::base64WordToChars(p,vals); + if (!rl) + break; + + p+=rl; + cnt+=rl; + } + *p = 0; + return cnt; +} + + +// ------------------------------------- +int Stream::readBits(int cnt) +{ + int v = 0; + + while (cnt) + { + if (!bitsPos) + bitsBuffer = readChar(); + + cnt--; + + v |= (bitsBuffer&(1<<(7-bitsPos)))?(1< +#include +#include +#include "common.h" +#include "sys.h" +#include "id.h" + +// ------------------------------------- +class Stream +{ +public: + Stream() + :writeCRLF(true) + ,totalBytesIn(0) + ,totalBytesOut(0) + ,lastBytesIn(0) + ,lastBytesOut(0) + ,bytesInPerSec(0) + ,bytesOutPerSec(0) + ,lastUpdate(0) + ,bitsBuffer(0) + ,bitsPos(0) + { + } + virtual ~Stream() {} + + virtual int readUpto(void *,int) {return 0;} + virtual int read(void *,int)=0; + virtual void write(const void *,int) = 0; + virtual bool eof() + { + throw StreamException("Stream can`t eof"); + return false; + } + + virtual void rewind() + { + throw StreamException("Stream can`t rewind"); + } + + virtual void seekTo(int) + { + throw StreamException("Stream can`t seek"); + } + + void writeTo(Stream &out, int len); + virtual void skip(int i); + + virtual void close() + { + } + + virtual void setReadTimeout(unsigned int ) + { + } + virtual void setWriteTimeout(unsigned int ) + { + } + virtual void setPollRead(bool) + { + } + + virtual int getPosition() {return 0;} + + + // binary + char readChar() + { + char v; + read(&v,1); + return v; + } + short readShort() + { + short v; + read(&v,2); + CHECK_ENDIAN2(v); + return v; + } + long readLong() + { + long v; + read(&v,4); + CHECK_ENDIAN4(v); + return v; + } + int readInt() + { + return readLong(); + } + ID4 readID4() + { + ID4 id; + read(id.getData(),4); + return id; + } + int readInt24() + { + int v=0; + read(&v,3); + CHECK_ENDIAN3(v); + } + + + + long readTag() + { + long v = readLong(); + return SWAP4(v); + } + + int readString(char *s, int max) + { + int cnt=0; + while (max) + { + char c = readChar(); + *s++ = c; + cnt++; + max--; + if (!c) + break; + } + return cnt; + } + + virtual bool readReady() {return true;} + virtual int numPending() {return 0;} + + + void writeID4(ID4 id) + { + write(id.getData(),4); + } + + void writeChar(char v) + { + write(&v,1); + } + void writeShort(short v) + { + CHECK_ENDIAN2(v); + write(&v,2); + } + void writeLong(long v) + { + CHECK_ENDIAN4(v); + write(&v,4); + } + void writeInt(int v) {writeLong(v);} + + void writeTag(long v) + { + //CHECK_ENDIAN4(v); + writeLong(SWAP4(v)); + } + + void writeTag(char id[4]) + { + write(id,4); + } + + int writeUTF8(unsigned int); + + // text + int readLine(char *in, int max); + + int readWord(char *, int); + int readBase64(char *, int); + + void write(const char *,va_list); + void writeLine(const char *); + void writeLineF(const char *,...); + void writeString(const char *); + void writeStringF(const char *,...); + + bool writeCRLF; + + int readBits(int); + + void updateTotals(unsigned int,unsigned int); + + + unsigned char bitsBuffer; + unsigned int bitsPos; + + unsigned int totalBytesIn,totalBytesOut; + unsigned int lastBytesIn,lastBytesOut; + unsigned int bytesInPerSec,bytesOutPerSec; + unsigned int lastUpdate; + +}; + + +// ------------------------------------- +class FileStream : public Stream +{ +public: + FileStream() {file=NULL;} + + void openReadOnly(const char *); + void openWriteReplace(const char *); + void openWriteAppend(const char *); + bool isOpen(){return file!=NULL;} + int length(); + int pos(); + + virtual void seekTo(int); + virtual int getPosition() {return pos();} + virtual void flush(); + virtual int read(void *,int); + virtual void write(const void *,int); + virtual bool eof(); + virtual void rewind(); + virtual void close(); + + FILE *file; +}; +// ------------------------------------- +class MemoryStream : public Stream +{ +public: + MemoryStream() + :buf(NULL) + ,len(0) + ,pos(0) + ,own(false) + { + } + + MemoryStream(void *p, int l) + :buf((char *)p) + ,len(l) + ,pos(0) + ,own(false) + { + } + + MemoryStream(int l) + :buf(new char[l]) + ,len(l) + ,pos(0) + ,own(true) + { + } + + ~MemoryStream() {free2();} + + void readFromFile(FileStream &file) + { + len = file.length(); + buf = new char[len]; + own = true; + pos = 0; + file.read(buf,len); + } + + void free2() + { + if (own && buf) + { + delete buf; + buf = NULL; + own = false; + } + + } + + virtual int read(void *p,int l) + { + if (pos+l <= len) + { + memcpy(p,&buf[pos],l); + pos += l; + return l; + }else + { + memset(p,0,l); + return 0; + } + } + + virtual void write(const void *p,int l) + { + if ((pos+l) > len) + throw StreamException("Stream - premature end of write()"); + memcpy(&buf[pos],p,l); + pos += l; + } + + virtual bool eof() + { + return pos >= len; + } + + virtual void rewind() + { + pos = 0; + } + + virtual void seekTo(int p) + { + pos = p; + } + + virtual int getPosition() + { + return pos; + } + + void convertFromBase64(); + + + char *buf; + bool own; + int len,pos; +}; +// -------------------------------------------------- +class IndirectStream : public Stream +{ +public: + + void init(Stream *s) + { + stream = s; + } + + virtual int read(void *p,int l) + { + return stream->read(p,l); + } + + virtual void write(const void *p,int l) + { + stream->write(p,l); + } + + virtual bool eof() + { + return stream->eof(); + } + + virtual void close() + { + stream->close(); + } + + Stream *stream; +}; + +// ------------------------------------- + +class SockBufStream : public Stream +{ +public: + SockBufStream(Stream &sockStream, int bufsize=128*1024) + : sock(sockStream), mem(bufsize) + { + } + + ~SockBufStream() + { + flush(); + mem.free2(); + } + + virtual int read(void *p,int l) + { + return sock.read(p, l); + } + + virtual void write(const void *p, int len) + { + if ( mem.pos+len > mem.len ) + flush(); + + mem.write(p, len); + } + + void flush() + { + if ( mem.pos > 0 ) { + sock.write(mem.buf, mem.pos); + clearWriteBuffer(); + } + } + + void clearWriteBuffer() + { + mem.rewind(); + } + +private: + Stream &sock; + MemoryStream mem; +}; + +// ------------------------------------- +class WriteBufferStream : public Stream +{ +public: + WriteBufferStream(Stream *out_) + :buf(NULL) + ,own(false) + ,len(0) + ,pos(0) + ,out(out_) + { + } + + WriteBufferStream(void *p, int l, Stream *out_) + :buf((char *)p) + ,own(false) + ,len(l) + ,pos(0) + ,out(out_) + { + } + + WriteBufferStream(int l, Stream *out_) + :buf(new char[l]) + ,own(true) + ,len(l) + ,pos(0) + ,out(out_) + { + } + + virtual ~WriteBufferStream() + { + try { + flush(); + } catch (StreamException &) {} + free(); + } + + void readFromFile(FileStream &file) + { + len = file.length(); + buf = new char[len]; + own = true; + pos = 0; + file.read(buf,len); + } + + void flush() + { + if (!out || !buf) return; + out->write(buf, pos); + pos = 0; + } + + void free() + { + if (own && buf) + { + delete buf; + buf = NULL; + own = false; + } + + } + + virtual int read(void *p,int l) + { + return 0; + } + + virtual void write(const void *p,int l) + { + char *cp = (char *) p; + while ((pos + l) >= len) { + int n = len - pos; + memcpy(&buf[pos], cp, n); + l -= n; + cp += n; + pos = len; + flush(); + if (pos != 0) return; + } + if (l > 0) { + memcpy(&buf[pos], cp, l); + pos += l; + } + } + + virtual bool eof() + { + return true; + } + + virtual void rewind() + { + pos = 0; + } + + virtual void seekTo(int p) + { + pos = p; + } + + virtual int getPosition() + { + return pos; + } + + void convertFromBase64(); + + + char *buf; + bool own; + int len,pos; + Stream *out; +}; + +#endif + diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/sys.cpp b/c:/Git/PeerCast.root/PeerCast/core/common/sys.cpp new file mode 100644 index 0000000..1e0704b --- /dev/null +++ b/c:/Git/PeerCast.root/PeerCast/core/common/sys.cpp @@ -0,0 +1,1041 @@ +// ------------------------------------------------ +// File : sys.cpp +// Date: 4-apr-2002 +// Author: giles +// Desc: +// Sys is a base class for all things systemy, like starting threads, creating sockets etc.. +// Lock is a very basic cross platform CriticalSection class +// SJIS-UTF8 conversion by ???? +// +// (c) 2002 peercast.org +// ------------------------------------------------ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// ------------------------------------------------ + +#include "common.h" +#include "sys.h" +#include "socket.h" +#include "gnutella.h" +#include "servmgr.h" //JP-EX +#ifdef WIN32 +#include "utf8.h" //JP-Patch +#endif +#include +#include +#include "jis.h" +#ifdef _DEBUG +#include "chkMemoryLeak.h" +#define DEBUG_NEW new(__FILE__, __LINE__) +#define new DEBUG_NEW +#endif + +// ----------------------------------- +#define isSJIS(a,b) ((a >= 0x81 && a <= 0x9f || a >= 0xe0 && a<=0xfc) && (b >= 0x40 && b <= 0x7e || b >= 0x80 && b<=0xfc)) +#define isEUC(a) (a >= 0xa1 && a <= 0xfe) +#define isASCII(a) (a <= 0x7f) +#define isPLAINASCII(a) (((a >= '0') && (a <= '9')) || ((a >= 'a') && (a <= 'z')) || ((a >= 'A') && (a <= 'Z'))) +#define isUTF8(a,b) ((a & 0xc0) == 0xc0 && (b & 0x80) == 0x80 ) +#define isESCAPE(a,b) ((a == '&') && (b == '#')) +#define isHTMLSPECIAL(a) ((a == '&') || (a == '\"') || (a == '\'') || (a == '<') || (a == '>')) + + + +// ----------------------------------- +const char *LogBuffer::logTypes[]= +{ + "", + "DBUG", + "EROR", + "GNET", + "CHAN", +}; + +// ----------------------------------- +// base64 encode/decode taken from ices2 source.. +static char base64table[64] = { + 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P', + 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f', + 'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v', + 'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/' +}; +#if 0 +// ----------------------------------- +static char *util_base64_encode(char *data) +{ + int len = strlen(data); + char *out = malloc(len*4/3 + 4); + char *result = out; + int chunk; + + while(len > 0) { + chunk = (len >3)?3:len; + *out++ = base64table[(*data & 0xFC)>>2]; + *out++ = base64table[((*data & 0x03)<<4) | ((*(data+1) & 0xF0) >> 4)]; + switch(chunk) { + case 3: + *out++ = base64table[((*(data+1) & 0x0F)<<2) | ((*(data+2) & 0xC0)>>6)]; + *out++ = base64table[(*(data+2)) & 0x3F]; + break; + case 2: + *out++ = base64table[((*(data+1) & 0x0F)<<2)]; + *out++ = '='; + break; + case 1: + *out++ = '='; + *out++ = '='; + break; + } + data += chunk; + len -= chunk; + } + + return result; +} +#endif + +// ----------------------------------- +static int base64chartoval(char input) +{ + if(input >= 'A' && input <= 'Z') + return input - 'A'; + else if(input >= 'a' && input <= 'z') + return input - 'a' + 26; + else if(input >= '0' && input <= '9') + return input - '0' + 52; + else if(input == '+') + return 62; + else if(input == '/') + return 63; + else if(input == '=') + return -1; + else + return -2; +} + +// ----------------------------------- +static char *util_base64_decode(char *input) +{ + return NULL; +} + + + + + +// ------------------------------------------ +Sys::Sys() +{ + idleSleepTime = 10; + logBuf = new LogBuffer(1000,100); + numThreads=0; +} + +// ------------------------------------------ +void Sys::sleepIdle() +{ + sleep(idleSleepTime); +} + +// ------------------------------------------ +bool Host::isLocalhost() +{ + return loopbackIP() || (ip == ClientSocket::getIP(NULL)); +} +// ------------------------------------------ +void Host::fromStrName(const char *str, int p) +{ + if (!strlen(str)) + { + port = 0; + ip = 0; + return; + } + + char name[128]; + strncpy(name,str,sizeof(name)-1); + name[127] = '\0'; + port = p; + char *pp = strstr(name,":"); + if (pp) + { + port = atoi(pp+1); + pp[0] = 0; + } + + ip = ClientSocket::getIP(name); +} +// ------------------------------------------ +void Host::fromStrIP(const char *str, int p) +{ + unsigned int ipb[4]; + unsigned int ipp; + + + if (strstr(str,":")) + { + if (sscanf(str,"%03d.%03d.%03d.%03d:%d",&ipb[0],&ipb[1],&ipb[2],&ipb[3],&ipp) == 5) + { + ip = ((ipb[0]&0xff) << 24) | ((ipb[1]&0xff) << 16) | ((ipb[2]&0xff) << 8) | ((ipb[3]&0xff)); + port = ipp; + }else + { + ip = 0; + port = 0; + } + }else{ + port = p; + if (sscanf(str,"%03d.%03d.%03d.%03d",&ipb[0],&ipb[1],&ipb[2],&ipb[3]) == 4) + ip = ((ipb[0]&0xff) << 24) | ((ipb[1]&0xff) << 16) | ((ipb[2]&0xff) << 8) | ((ipb[3]&0xff)); + else + ip = 0; + } +} +// ----------------------------------- +bool Host::isMemberOf(Host &h) +{ + if (h.ip==0) + return false; + + if( h.ip0() != 255 && ip0() != h.ip0() ) + return false; + if( h.ip1() != 255 && ip1() != h.ip1() ) + return false; + if( h.ip2() != 255 && ip2() != h.ip2() ) + return false; + if( h.ip3() != 255 && ip3() != h.ip3() ) + return false; + +/* removed for endieness compatibility + for(int i=0; i<4; i++) + if (h.ipByte[i] != 255) + if (ipByte[i] != h.ipByte[i]) + return false; +*/ + return true; +} + +// ----------------------------------- +char *trimstr(char *s1) +{ + while (*s1) + { + if ((*s1 == ' ') || (*s1 == '\t')) + s1++; + else + break; + + } + + char *s = s1; + + if(strlen(s1) > 0) { +/* s1 = s1+strlen(s1); + + while (*--s1) + if ((*s1 != ' ') && (*s1 != '\t')) + break;*/ + + s1 = s1+strlen(s1); + +// s1[1] = 0; + + while (*--s1) + if ((*s1 != ' ') && (*s1 != '\t')) + break; + + s1[1] = 0; + } + return s; +} + +// ----------------------------------- +char *stristr(const char *s1, const char *s2) +{ + while (*s1) + { + if (TOUPPER(*s1) == TOUPPER(*s2)) + { + const char *c1 = s1; + const char *c2 = s2; + + while (*c1 && *c2) + { + if (TOUPPER(*c1) != TOUPPER(*c2)) + break; + c1++; + c2++; + } + if (*c2==0) + return (char *)s1; + } + + s1++; + } + return NULL; +} +// ----------------------------------- +bool String::isValidURL() +{ + return (strnicmp(data,"http://",7)==0) || (strnicmp(data,"mailto:",7)==0); +} + +// ----------------------------------- +void String::setFromTime(unsigned int t) +{ +// char *p = ctime((time_t*)&t); + time_t tmp = t; + char *p = ctime(&tmp); + if (p) + strcpy(data,p); + else + strcpy(data,"-"); + type = T_ASCII; +} +// ----------------------------------- +void String::setFromStopwatch(unsigned int t) +{ + unsigned int sec,min,hour,day; + + sec = t%60; + min = (t/60)%60; + hour = (t/3600)%24; + day = (t/86400); + + if (day) + sprintf(data,"%d day, %d hour",day,hour); + else if (hour) + sprintf(data,"%d hour, %d min",hour,min); + else if (min) + sprintf(data,"%d min, %d sec",min,sec); + else if (sec) + sprintf(data,"%d sec",sec); + else + sprintf(data,"-"); + + type = T_ASCII; +} +// ----------------------------------- +void String::setFromString(const char *str, TYPE t) +{ + int cnt=0; + bool quote=false; + while (*str) + { + bool add=true; + if (*str == '\"') + { + if (quote) + break; + else + quote = true; + add = false; + }else if (*str == ' ') + { + if (!quote) + { + if (cnt) + break; + else + add = false; + } + } + + if (add) + { + data[cnt++] = *str++; + if (cnt >= (MAX_LEN-1)) + break; + }else + str++; + } + data[cnt] = 0; + type = t; +} + +// ----------------------------------- +int String::base64WordToChars(char *out,const char *input) +{ + char *start = out; + signed char vals[4]; + + vals[0] = base64chartoval(*input++); + vals[1] = base64chartoval(*input++); + vals[2] = base64chartoval(*input++); + vals[3] = base64chartoval(*input++); + + if(vals[0] < 0 || vals[1] < 0 || vals[2] < -1 || vals[3] < -1) + return 0; + + *out++ = vals[0]<<2 | vals[1]>>4; + if(vals[2] >= 0) + *out++ = ((vals[1]&0x0F)<<4) | (vals[2]>>2); + else + *out++ = 0; + + if(vals[3] >= 0) + *out++ = ((vals[2]&0x03)<<6) | (vals[3]); + else + *out++ = 0; + + return out-start; +} + +// ----------------------------------- +void String::BASE642ASCII(const char *input) +{ + char *out = data; + int len = strlen(input); + + while(len >= 4) + { + out += base64WordToChars(out,input); + input += 4; + len -= 4; + } + *out = 0; +} + + + +// ----------------------------------- +void String::UNKNOWN2UNICODE(const char *in,bool safe) +{ + MemoryStream utf8(data,MAX_LEN-1); + + unsigned char c; + unsigned char d; + + while (c = *in++) + { + d = *in; + + if (isUTF8(c,d)) // utf8 encoded + { + int numChars=0; + int i; + + for(i=0; i<6; i++) + { + if (c & (0x80>>i)) + numChars++; + else + break; + } + + utf8.writeChar(c); + for(i=0; i') str = ">"; + else str = "?"; + + utf8.writeString(str); + } + else + { + utf8.writeUTF8(c); + } + + if (utf8.pos >= (MAX_LEN-10)) + break; + + + } + + utf8.writeChar(0); // null terminate + +} + +// ----------------------------------- +void String::ASCII2HTML(const char *in) +{ + char *op = data; + char *oe = data+MAX_LEN-10; + unsigned char c; + const char *p = in; + while (c = *p++) + { + + if (((c >= '0') && (c <= '9')) || ((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z'))) + { + *op++ = c; + }else + { + sprintf(op,"&#x%02X;",(int)c); + op+=6; + } + if (op >= oe) + break; + } + *op = 0; +} +// ----------------------------------- +void String::ASCII2ESC(const char *in, bool safe) +{ + char *op = data; + char *oe = data+MAX_LEN-10; + const char *p = in; + unsigned char c; + while (c = *p++) + { + if (((c >= '0') && (c <= '9')) || ((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z'))) + *op++ = c; + else + { + *op++ = '%'; + if (safe) + *op++ = '%'; + *op=0; + sprintf(op,"%02X",(int)c); + op+=2; + } + if (op >= oe) + break; + } + *op=0; +} +// ----------------------------------- +void String::HTML2ASCII(const char *in) +{ + unsigned char c; + char *o = data; + char *oe = data+MAX_LEN-10; + const char *p = in; + while (c = *p++) + { + if ((c == '&') && (p[0] == '#')) + { + p++; + char code[8]; + char *cp = code; + char ec = *p++; // hex/dec + while (c=*p++) + { + if (c!=';') + *cp++ = c; + else + break; + } + *cp = 0; + c = (unsigned char)strtoul(code,NULL,ec=='x'?16:10); + } + *o++ = c; + if (o >= oe) + break; + } + + *o=0; +} +// ----------------------------------- +void String::HTML2UNICODE(const char *in) +{ + MemoryStream utf8(data,MAX_LEN-1); + + unsigned char c; + while (c = *in++) + { + if ((c == '&') && (*in == '#')) + { + in++; + char code[16]; + char *cp = code; + char ec = *in++; // hex/dec + while (c=*in++) + { + if (c!=';') + *cp++ = c; + else + break; + } + *cp = 0; + utf8.writeUTF8(strtoul(code,NULL,ec=='x'?16:10)); + }else + utf8.writeUTF8(c); + + if (utf8.pos >= (MAX_LEN-10)) + break; + } + + utf8.writeUTF8(0); +} + +// ----------------------------------- +void String::ESC2ASCII(const char *in) +{ + unsigned char c; + char *o = data; + char *oe = data+MAX_LEN-10; + const char *p = in; + while (c = *p++) + { + if (c == '+') + c = ' '; + else if (c == '%') + { + if (p[0] == '%') + p++; + + char hi = TOUPPER(p[0]); + char lo = TOUPPER(p[1]); + c = (TONIBBLE(hi)<<4) | TONIBBLE(lo); + p+=2; + } + *o++ = c; + if (o >= oe) + break; + } + + *o=0; +} +// ----------------------------------- +void String::ASCII2META(const char *in, bool safe) +{ + char *op = data; + char *oe = data+MAX_LEN-10; + const char *p = in; + unsigned char c; + while (c = *p++) + { + switch (c) + { + case '%': + if (safe) + *op++='%'; + break; + case ';': + c = ':'; + break; + } + + *op++=c; + if (op >= oe) + break; + } + *op=0; +} +#ifdef WIN32 +// ----------------------------------- +void String::ASCII2SJIS(const char *in) //JP-EX +{ + char *op = data; + char *p; + if (utf8_decode(in,&p)<0) + { + strcpy(op,in); + return; + } + strcpy(op,p); + free(p); +} +#endif +// ----------------------------------- +void String::convertTo(TYPE t) +{ + if (t != type) + { + String tmp = *this; + + // convert to ASCII + switch (type) + { + case T_UNKNOWN: + case T_ASCII: + break; + case T_HTML: + tmp.HTML2ASCII(data); + break; + case T_ESC: + case T_ESCSAFE: + tmp.ESC2ASCII(data); + break; + case T_META: + case T_METASAFE: + break; + case T_BASE64: + tmp.BASE642ASCII(data); + break; + } + + // convert to new format + switch (t) + { + case T_UNKNOWN: + case T_ASCII: + strcpy(data,tmp.data); + break; + case T_UNICODE: + UNKNOWN2UNICODE(tmp.data,false); + break; + case T_UNICODESAFE: + UNKNOWN2UNICODE(tmp.data,true); + break; + case T_HTML: + ASCII2HTML(tmp.data); + break; + case T_ESC: + ASCII2ESC(tmp.data,false); + break; + case T_ESCSAFE: + ASCII2ESC(tmp.data,true); + break; + case T_META: + ASCII2META(tmp.data,false); + break; + case T_METASAFE: + ASCII2META(tmp.data,true); + break; +#ifdef WIN32 + case T_SJIS: //JP-EX + ASCII2SJIS(tmp.data); + break; +#endif + } + + type = t; + } +} +// ----------------------------------- +void LogBuffer::write(const char *str, TYPE t) +{ + lock.on(); + + unsigned int len = strlen(str); + int cnt=0; + while (len) + { + unsigned int rlen = len; + if (rlen > (lineLen-1)) + rlen = lineLen-1; + + int i = currLine % maxLines; + int bp = i*lineLen; + strncpy(&buf[bp],str,rlen); + buf[bp+rlen] = 0; + if (cnt==0) + { + times[i] = sys->getTime(); + types[i] = t; + }else + { + times[i] = 0; + types[i] = T_NONE; + } + currLine++; + + str += rlen; + len -= rlen; + cnt++; + } + + lock.off(); +} + +// ----------------------------------- +char *getCGIarg(const char *str, const char *arg) +{ + if (!str) + return NULL; + +// char *s = strstr(str,arg); + char *s = (char*)strstr(str,arg); + + if (!s) + return NULL; + + s += strlen(arg); + + return s; +} + +// ----------------------------------- +bool cmpCGIarg(char *str, char *arg, char *value) +{ + if ((!str) || (!strlen(value))) + return false; + + if (strnicmp(str,arg,strlen(arg)) == 0) + { + + str += strlen(arg); + + return strncmp(str,value,strlen(value))==0; + }else + return false; +} +// ----------------------------------- +bool hasCGIarg(char *str, char *arg) +{ + if (!str) + return false; + + char *s = strstr(str,arg); + + if (!s) + return false; + + return true; +} + + +// --------------------------- +void GnuID::encode(Host *h, const char *salt1, const char *salt2, unsigned char salt3) +{ + int s1=0,s2=0; + for(int i=0; i<16; i++) + { + unsigned char ipb = id[i]; + + // encode with IP address + if (h) + ipb ^= ((unsigned char *)&h->ip)[i&3]; + + // add a bit of salt + if (salt1) + { + if (salt1[s1]) + ipb ^= salt1[s1++]; + else + s1=0; + } + + // and some more + if (salt2) + { + if (salt2[s2]) + ipb ^= salt2[s2++]; + else + s2=0; + } + + // plus some pepper + ipb ^= salt3; + + id[i] = ipb; + } + +} +// --------------------------- +void GnuID::toStr(char *str) +{ + + str[0] = 0; + for(int i=0; i<16; i++) + { + char tmp[8]; + unsigned char ipb = id[i]; + + sprintf(tmp,"%02X",ipb); + strcat(str,tmp); + } + +} +// --------------------------- +void GnuID::fromStr(const char *str) +{ + clear(); + + if (strlen(str) < 32) + return; + + char buf[8]; + + buf[2] = 0; + + for(int i=0; i<16; i++) + { + buf[0] = str[i*2]; + buf[1] = str[i*2+1]; + id[i] = (unsigned char)strtoul(buf,NULL,16); + } + +} + +// --------------------------- +void GnuID::generate(unsigned char flags) +{ + clear(); + + for(int i=0; i<16; i++) + id[i] = sys->rnd(); + + id[0] = flags; +} + +// --------------------------- +unsigned char GnuID::getFlags() +{ + return id[0]; +} + +// --------------------------- +GnuIDList::GnuIDList(int max) +:ids(new GnuID[max]) +{ + maxID = max; + for(int i=0; igetTime(); + return; + } + if (ids[i].storeTime <= minTime) + { + minTime = ids[i].storeTime; + minIndex = i; + } + } + + ids[minIndex] = id; + ids[minIndex].storeTime = sys->getTime(); +} +// --------------------------- +void GnuIDList::clear() +{ + for(int i=0; i maxLines) + { + nl = maxLines-1; + sp = (currLine+1)%maxLines; + } + + String tim,str; + if (nl) + { + for(unsigned int i=0; i["); + out.writeString(getTypeStr(types[sp])); + out.writeString("] "); + } + str.set(&buf[bp]); + str.convertTo(String::T_HTML); + + out.writeString(str.cstr()); + out.writeString("
"); + + sp++; + sp %= maxLines; + } + } + + lb.off(); + +} + +// --------------------------- +void ThreadInfo::shutdown() +{ + active = false; + //sys->waitThread(this); +} diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/sys.h b/c:/Git/PeerCast.root/PeerCast/core/common/sys.h new file mode 100644 index 0000000..5583a9d --- /dev/null +++ b/c:/Git/PeerCast.root/PeerCast/core/common/sys.h @@ -0,0 +1,534 @@ +// ------------------------------------------------ +// File : sys.h +// Date: 4-apr-2002 +// Author: giles +// Desc: +// +// (c) 2002 peercast.org +// ------------------------------------------------ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// ------------------------------------------------ + +#ifndef _SYS_H +#define _SYS_H + +#include +#include "common.h" + +#define RAND(a,b) (((a = 36969 * (a & 65535) + (a >> 16)) << 16) + \ + (b = 18000 * (b & 65535) + (b >> 16)) ) +extern char *stristr(const char *s1, const char *s2); +extern char *trimstr(char *s); + + +#define MAX_CGI_LEN 1024 +// ------------------------------------ +class String +{ +public: + enum { + MAX_LEN = 256 + }; + + enum TYPE + { + T_UNKNOWN, + T_ASCII, + T_HTML, + T_ESC, + T_ESCSAFE, + T_META, + T_METASAFE, + T_BASE64, + T_UNICODE, + T_UNICODESAFE, +#ifdef WIN32 + T_SJIS, //JP-EX +#endif + }; + + String() {clear();} + String(const char *p, TYPE t=T_ASCII) + { + set(p,t); + } + + // set from straight null terminated string + void set(const char *p, TYPE t=T_ASCII) + { + strncpy(data,p,MAX_LEN-1); + data[MAX_LEN-1] = 0; + type = t; + } + + // set from quoted or unquoted null terminated string + void setFromString(const char *str, TYPE t=T_ASCII); + + // set from stopwatch + void setFromStopwatch(unsigned int t); + + // set from time + void setFromTime(unsigned int t); + + + // from single word (end at whitespace) + void setFromWord(const char *str) + { + int i; + for(i=0; i 2) + { + if (slen >= MAX_LEN) slen = MAX_LEN; + strncpy(data,p+1,slen-2); + data[slen-2]=0; + }else + clear(); + type = t; + } + + void clear() + { + data[0]=0; + type = T_UNKNOWN; + } + void ASCII2ESC(const char *,bool); + void ASCII2HTML(const char *); + void ASCII2META(const char *,bool); + void ESC2ASCII(const char *); + void HTML2ASCII(const char *); + void HTML2UNICODE(const char *); + void BASE642ASCII(const char *); + void UNKNOWN2UNICODE(const char *,bool); +#ifdef WIN32 + void ASCII2SJIS(const char *); //JP-EX +#endif + + static int base64WordToChars(char *,const char *); + + static bool isSame(const char *s1, const char *s2) {return strcmp(s1,s2)==0;} + + bool startsWith(const char *s) const {return strncmp(data,s,strlen(s))==0;} + bool isValidURL(); + bool isEmpty() {return data[0]==0;} + bool isSame(::String &s) const {return strcmp(data,s.data)==0;} + bool isSame(const char *s) const {return strcmp(data,s)==0;} + bool contains(::String &s) {return stristr(data,s.data)!=NULL;} + bool contains(const char *s) {return stristr(data,s)!=NULL;} + void append(const char *s) + { + if ((strlen(s)+strlen(data) < (MAX_LEN-1))) + strcat(data,s); + } + void append(char c) + { + char tmp[2]; + tmp[0]=c; + tmp[1]=0; + append(tmp); + } + + void prepend(const char *s) + { + ::String tmp; + tmp.set(s); + tmp.append(data); + tmp.type = type; + *this = tmp; + } + + bool operator == (const char *s) const {return isSame(s);} + + operator const char *() const {return data;} + + void convertTo(TYPE t); + + char *cstr() {return data;} + + static bool isWhitespace(char c) {return c==' ' || c=='\t';} + + TYPE type; + char data[MAX_LEN]; +}; + +// ------------------------------------ +namespace peercast { +class Random { +public: + Random(int s=0x14235465) + { + setSeed(s); + } + + unsigned int next() + { + return RAND(a[0],a[1]); + } + + void setSeed(int s) + { + a[0] = a[1] = s; + } + + unsigned long a[2]; +}; +} +// ------------------------------------ +class Sys +{ +public: + Sys(); + + + + virtual class ClientSocket *createSocket() = 0; + virtual bool startThread(class ThreadInfo *) = 0; + virtual void sleep(int) = 0; + virtual void appMsg(long,long = 0) = 0; + virtual unsigned int getTime() = 0; + virtual double getDTime() = 0; + virtual unsigned int rnd() = 0; + virtual void getURL(const char *) = 0; + virtual void exit() = 0; + virtual bool hasGUI() = 0; + virtual void callLocalURL(const char *,int)=0; + virtual void executeFile(const char *) = 0; + virtual void endThread(ThreadInfo *) {} + virtual void waitThread(ThreadInfo *, int timeout = 30000) {} + + + +#ifdef __BIG_ENDIAN__ + unsigned short convertEndian(unsigned short v) { return SWAP2(v); } + unsigned int convertEndian(unsigned int v) { return SWAP4(v); } +#else + unsigned short convertEndian(unsigned short v) { return v; } + unsigned int convertEndian(unsigned int v) { return v; } +#endif + + + void sleepIdle(); + + unsigned int idleSleepTime; + unsigned int rndSeed; + unsigned int numThreads; + + class LogBuffer *logBuf; +}; + + +#ifdef WIN32 +#include + +typedef __int64 int64_t; + + +// ------------------------------------ +class WEvent +{ +public: + WEvent() + { + event = ::CreateEvent(NULL, // no security attributes + TRUE, // manual-reset + FALSE,// initially non-signaled + NULL);// anonymous + } + + ~WEvent() + { + ::CloseHandle(event); + } + + void signal() + { + ::SetEvent(event); + } + + void wait(int timeout = 30000) + { + switch(::WaitForSingleObject(event, timeout)) + { + case WAIT_TIMEOUT: + throw TimeoutException(); + break; + //case WAIT_OBJECT_0: + //break; + } + } + + void reset() + { + ::ResetEvent(event); + } + + + + HANDLE event; +}; + + + +// ------------------------------------ +typedef int (WINAPI *THREAD_FUNC)(ThreadInfo *); +typedef unsigned int THREAD_HANDLE; +#define THREAD_PROC int WINAPI +#define vsnprintf _vsnprintf + +// ------------------------------------ +class WLock +{ +public: + WLock() + { + InitializeCriticalSection(&cs); + } + + + void on() + { + EnterCriticalSection(&cs); + } + + void off() + { + LeaveCriticalSection(&cs); + } + + CRITICAL_SECTION cs; +}; +#endif + + +#ifdef _UNIX +// ------------------------------------ +#include +#include + +#ifdef __APPLE__ +#include +#define _BIG_ENDIAN 1 +#endif + +typedef long long int64_t; + +typedef int (*THREAD_FUNC)(ThreadInfo *); +#define THREAD_PROC int +typedef pthread_t THREAD_HANDLE; + +// ------------------------------------ +#define stricmp strcasecmp +#define strnicmp strncasecmp + + +// ------------------------------------ +class WEvent +{ +public: + + WEvent() + { + } + + void signal() + { + } + + void wait(int timeout = 30000) + { + } + + void reset() + { + } + +}; + +// ------------------------------------ +class WLock +{ +private: + pthread_mutex_t mutex; +public: + WLock() + { + const pthread_mutexattr_t mattr = + { +#ifdef __APPLE__ + PTHREAD_MUTEX_RECURSIVE +#else + PTHREAD_MUTEX_RECURSIVE_NP +#endif + }; + + pthread_mutex_init( &mutex, &mattr ); + } + + ~WLock() + { + pthread_mutex_destroy( &mutex ); + } + + + void on() + { + pthread_mutex_lock(&mutex); + } + + void off() + { + pthread_mutex_unlock(&mutex); + } + +}; +#endif + +class WLockBlock +{ +private: + WLock *lock; + bool flg; +public: + WLockBlock(WLock *l){ + lock = l; + flg = false; + } + ~WLockBlock(){ + if (flg){ + lock->off(); + LOG_DEBUG("LOCK OFF by destructor"); + } + } + void on(){ + flg = true; + lock->on(); + } + void off(){ + flg = false; + lock->off(); + } +}; + +// ------------------------------------ +class ThreadInfo +{ +public: + //typedef int (__stdcall *THREAD_FUNC)(ThreadInfo *); + + ThreadInfo() + { + active = false; + finish = false; + id = 0; + func = NULL; + data = NULL; + } + + void shutdown(); + + volatile bool active; + volatile bool finish; + int id; + THREAD_FUNC func; + THREAD_HANDLE handle; + + + void *data; +}; + + +// ------------------------------------ +class LogBuffer +{ +public: + enum TYPE + { + T_NONE, + T_DEBUG, + T_ERROR, + T_NETWORK, + T_CHANNEL, + }; + + LogBuffer(int i, int l) + { + lineLen = l; + maxLines = i; + currLine = 0; + buf = new char[lineLen*maxLines]; + times = new unsigned int [maxLines]; + types = new TYPE [maxLines]; + } + + void clear() + { + currLine = 0; + } + void write(const char *, TYPE); + static const char *getTypeStr(TYPE t) {return logTypes[t];} + void dumpHTML(class Stream &); + + char *buf; + unsigned int *times; + unsigned int currLine,maxLines,lineLen; + TYPE *types; + WLock lock; + static const char *logTypes[]; + +}; + +#define RWLOCK_READ_MAX 32 + +class LockBlock +{ +public: + LockBlock(WLock &l){ flg = false; lock = l; } + ~LockBlock(){ if (flg) lock.off(); } + void lockon(){ flg = true; lock.on(); } + void lockoff(){ flg = false; lock.off(); } + +private: + WLock lock; + bool flg; +}; + +// ------------------------------------ +extern Sys *sys; + +// ------------------------------------ + + +#if _BIG_ENDIAN +#define CHECK_ENDIAN2(v) v=SWAP2(v) +#define CHECK_ENDIAN3(v) v=SWAP3(v) +#define CHECK_ENDIAN4(v) v=SWAP4(v) +#else +#define CHECK_ENDIAN2 +#define CHECK_ENDIAN3 +#define CHECK_ENDIAN4 +#endif + + +// ------------------------------------ +#endif + diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/url.cpp b/c:/Git/PeerCast.root/PeerCast/core/common/url.cpp new file mode 100644 index 0000000..f98d195 --- /dev/null +++ b/c:/Git/PeerCast.root/PeerCast/core/common/url.cpp @@ -0,0 +1,355 @@ +// ------------------------------------------------ +// File : url.h +// Date: 20-feb-2004 +// Author: giles +// +// (c) 2002-4 peercast.org +// ------------------------------------------------ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// ------------------------------------------------ + +#include "url.h" +#include "socket.h" +#include "http.h" +#include "servent.h" +#include "servmgr.h" +#include "peercast.h" +#include "version2.h" +#ifdef _DEBUG +#include "chkMemoryLeak.h" +#define DEBUG_NEW new(__FILE__, __LINE__) +#define new DEBUG_NEW +#endif + +// ------------------------------------------------ +void URLSource::stream(Channel *ch) +{ + + String url,tmpUrl; + while (ch->thread.active && !peercastInst->isQuitting) + { + tmpUrl = url; + if (url.isEmpty()) + url = baseurl; + + url = streamURL(ch,url.cstr()); + if (url == tmpUrl){ + sys->sleep(2000); + } + } + +} +// ------------------------------------------------ +int URLSource::getSourceRate() +{ + if (inputStream) + return inputStream->bytesInPerSec; + else + return 0; +} + +// ------------------------------------------------ +::String URLSource::streamURL(Channel *ch, const char *url) +{ + String nextURL; + + if (peercastInst->isQuitting || !ch->thread.active) + return nextURL; + + + String urlTmp; + urlTmp.set(url); + + char *fileName = urlTmp.cstr(); + + PlayList *pls=NULL; + ChannelStream *source=NULL; + + LOG_CHANNEL("Fetch URL=%s",fileName); + + try + { + + // get the source protocol + if (strnicmp(fileName,"http://",7)==0) + { + ch->info.srcProtocol = ChanInfo::SP_HTTP; + fileName += 7; + } + else if (strnicmp(fileName,"mms://",6)==0) + { + ch->info.srcProtocol = ChanInfo::SP_MMS; + fileName += 6; + } + else if (strnicmp(fileName,"pcp://",6)==0) + { + ch->info.srcProtocol = ChanInfo::SP_PCP; + fileName += 6; + } + else if (strnicmp(fileName,"file://",7)==0) + { + ch->info.srcProtocol = ChanInfo::SP_FILE; + fileName += 7; + } + else + { + ch->info.srcProtocol = ChanInfo::SP_FILE; + } + + // default to mp3 for shoutcast servers + if (ch->info.contentType == ChanInfo::T_PLS) + ch->info.contentType = ChanInfo::T_MP3; + + + ch->setStatus(Channel::S_CONNECTING); + + if ((ch->info.srcProtocol == ChanInfo::SP_HTTP) || (ch->info.srcProtocol == ChanInfo::SP_PCP) || (ch->info.srcProtocol == ChanInfo::SP_MMS)) + { + + if ((ch->info.contentType == ChanInfo::T_WMA) || (ch->info.contentType == ChanInfo::T_WMV)) + ch->info.srcProtocol = ChanInfo::SP_MMS; + + + LOG_CHANNEL("Channel source is HTTP"); + + ClientSocket *inputSocket = sys->createSocket(); + if (!inputSocket) + throw StreamException("Channel cannot create socket"); + + + inputStream = inputSocket; + + + char *dir = strstr(fileName,"/"); + if (dir) + *dir++=0; + + + LOG_CHANNEL("Fetch Host=%s",fileName); + if (dir) + LOG_CHANNEL("Fetch Dir=%s",dir); + + + Host host; + host.fromStrName(fileName,80); + + inputSocket->open(host); + inputSocket->connect(); + + HTTP http(*inputSocket); + http.writeLineF("GET /%s HTTP/1.0",dir?dir:""); + + http.writeLineF("%s %s",HTTP_HS_HOST,fileName); + http.writeLineF("%s %s",HTTP_HS_CONNECTION,"close"); + http.writeLineF("%s %s",HTTP_HS_ACCEPT,"*/*"); + + if (ch->info.srcProtocol == ChanInfo::SP_MMS) + { + http.writeLineF("%s %s",HTTP_HS_AGENT,"NSPlayer/4.1.0.3856"); + http.writeLine("Pragma: no-cache,rate=1.000000,request-context=1"); + //http.writeLine("Pragma: no-cache,rate=1.000000,stream-time=0,stream-offset=4294967295:4294967295,request-context=22605256,max-duration=0"); + http.writeLine("Pragma: xPlayStrm=1"); + http.writeLine("Pragma: xClientGUID={c77e7400-738a-11d2-9add-0020af0a3278}"); + http.writeLine("Pragma: stream-switch-count=2"); + http.writeLine("Pragma: stream-switch-entry=ffff:1:0 ffff:2:0"); + }else + { + http.writeLineF("%s %s",HTTP_HS_AGENT,PCX_AGENT); + http.writeLineF("%s %d",PCX_HS_PCP,1); + http.writeLine("Icy-MetaData:1"); // fix by ravon + } + + http.writeLine(""); + + int res = http.readResponse(); + + + String name = ch->info.name; + + while (http.nextHeader()) + { + + LOG_CHANNEL("Fetch HTTP: %s",http.cmdLine); + + ChanInfo tmpInfo = ch->info; + Servent::readICYHeader(http,ch->info,NULL); + + if (!tmpInfo.name.isEmpty()) + ch->info.name = tmpInfo.name; + if (!tmpInfo.genre.isEmpty()) + ch->info.genre = tmpInfo.genre; + if (!tmpInfo.url.isEmpty()) + ch->info.url = tmpInfo.url; + + if (http.isHeader("icy-metaint")) + ch->icyMetaInterval = http.getArgInt(); + else if (http.isHeader("Location:")) + nextURL.set(http.getArgStr()); + + char *arg = http.getArgStr(); + if (arg) + { + if (http.isHeader("content-type")) + { + if (stristr(arg,MIME_XSCPLS)) + pls = new PlayList(PlayList::T_SCPLS, 1000); + else if (stristr(arg,MIME_PLS)) + pls = new PlayList(PlayList::T_PLS, 1000); + else if (stristr(arg,MIME_XPLS)) + pls = new PlayList(PlayList::T_PLS, 1000); + else if (stristr(arg,MIME_M3U)) + pls = new PlayList(PlayList::T_PLS, 1000); + else if (stristr(arg,MIME_TEXT)) + pls = new PlayList(PlayList::T_PLS, 1000); + else if (stristr(arg,MIME_ASX)) + pls = new PlayList(PlayList::T_ASX, 1000); + else if (stristr(arg,MIME_MMS)) + ch->info.srcProtocol = ChanInfo::SP_MMS; + } + } + + } + + if ((!nextURL.isEmpty()) && (res==302)) + { + LOG_CHANNEL("Channel redirect: %s",nextURL.cstr()); + inputSocket->close(); + delete inputSocket; + inputSocket = NULL; + return nextURL; + } + + if (res!=200) + { + LOG_ERROR("HTTP response: %d",res); + throw StreamException("Bad HTTP connect"); + } + + + }else if (ch->info.srcProtocol == ChanInfo::SP_FILE) + { + + LOG_CHANNEL("Channel source is FILE"); + + FileStream *fs = new FileStream(); + fs->openReadOnly(fileName); + inputStream = fs; + + ChanInfo::TYPE fileType = ChanInfo::T_UNKNOWN; + // if filetype is unknown, try and figure it out from file extension. + //if ((info.srcType == ChanInfo::T_UNKNOWN) || (info.srcType == ChanInfo::T_PLAYLIST)) + { + const char *ext = fileName+strlen(fileName); + while (*--ext) + if (*ext=='.') + { + ext++; + break; + } + + fileType = ChanInfo::getTypeFromStr(ext); + } + + + if (ch->info.bitrate) + ch->readDelay = true; + + + if (fileType == ChanInfo::T_PLS) + pls = new PlayList(PlayList::T_PLS, 1000); + else if (fileType == ChanInfo::T_ASX) + pls = new PlayList(PlayList::T_ASX, 1000); + else + ch->info.contentType = fileType; + + }else + { + throw StreamException("Unsupported URL"); + } + + + if (pls) + { + + LOG_CHANNEL("Channel is Playlist"); + + pls->read(*inputStream); + + inputStream->close(); + delete inputStream; + inputStream = NULL; + + int urlNum=0; + String url; + + LOG_CHANNEL("Playlist: %d URLs",pls->numURLs); + while ((ch->thread.active) && (pls->numURLs) && (!peercastInst->isQuitting)) + { + if (url.isEmpty()) + { + url = pls->urls[urlNum%pls->numURLs]; + urlNum++; + } + try + { + url = streamURL(ch,url.cstr()); + }catch(StreamException &) + {} + } + + delete pls; + + }else + { + + // if we didn`t get a channel id from the source, then create our own (its an original broadcast) + if (!ch->info.id.isSet()) + { + ch->info.id = chanMgr->broadcastID; + ch->info.id.encode(NULL,ch->info.name.cstr(),ch->info.genre,ch->info.bitrate); + } + + if (ch->info.contentType == ChanInfo::T_ASX) + ch->info.contentType = ChanInfo::T_WMV; + + ch->setStatus(Channel::S_BROADCASTING); + + inputStream->setReadTimeout(60); // use longer read timeout + + source = ch->createSource(); + + ch->readStream(*inputStream,source); + + inputStream->close(); + } + + }catch(StreamException &e) + { + ch->setStatus(Channel::S_ERROR); + LOG_ERROR("Channel error: %s",e.msg); + sys->sleep(1000); + } + + + ch->setStatus(Channel::S_CLOSING); + if (inputStream) + { + delete inputStream; + inputStream = NULL; + } + + if (source) + delete source; + + + return nextURL; + +} diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/url.h b/c:/Git/PeerCast.root/PeerCast/core/common/url.h new file mode 100644 index 0000000..8d113c0 --- /dev/null +++ b/c:/Git/PeerCast.root/PeerCast/core/common/url.h @@ -0,0 +1,49 @@ +// ------------------------------------------------ +// File : url.h +// Date: 20-feb-2004 +// Author: giles +// +// (c) 2002-4 peercast.org +// ------------------------------------------------ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// ------------------------------------------------ + +#ifndef _URL_H +#define _URL_H + +#include "channel.h" + +// ------------------------------------------------ +class URLSource : public ChannelSource +{ +public: + URLSource(const char *url) + :inputStream(NULL) + { + baseurl.set(url); + } + + ::String streamURL(Channel *, const char *); + + virtual void stream(Channel *); + + virtual int getSourceRate(); + + + Stream *inputStream; + ::String baseurl; +}; + + + + +#endif + diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/utf8.c b/c:/Git/PeerCast.root/PeerCast/core/common/utf8.c new file mode 100644 index 0000000..4747c3f --- /dev/null +++ b/c:/Git/PeerCast.root/PeerCast/core/common/utf8.c @@ -0,0 +1,343 @@ +/* + * Copyright (C) 2001 Peter Harris + * Copyright (C) 2001 Edmund Grimley Evans + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * Convert a string between UTF-8 and the locale's charset. + */ + +#include +#include + +#include "utf8.h" +#include "identify_encoding.h" +#ifdef _WIN32 + +/* Thanks to Peter Harris for this win32 + * code. + */ + +#include +#include + +static unsigned char *make_utf8_string(const wchar_t *unicode) +{ + int size = 0, index = 0, out_index = 0; + unsigned char *out; + unsigned short c; + + /* first calculate the size of the target string */ + c = unicode[index++]; + while (c) + { + if (c < 0x0080) + { + size += 1; + } + else if (c < 0x0800) + { + size += 2; + }else{ + size += 3; + } + c = unicode[index++]; + } + + out = (unsigned char *)malloc(size + 1); + if (out == NULL) + return NULL; + index = 0; + + c = unicode[index++]; + while (c) + { + if (c < 0x080) + { + out[out_index++] = (unsigned char)c; + }else if (c < 0x800) + { + out[out_index++] = 0xc0 | (c >> 6); + out[out_index++] = 0x80 | (c & 0x3f); + }else{ + out[out_index++] = 0xe0 | (c >> 12); + out[out_index++] = 0x80 | ((c >> 6) & 0x3f); + out[out_index++] = 0x80 | (c & 0x3f); + } + c = unicode[index++]; + } + out[out_index] = 0x00; + + return out; +} + +static wchar_t *make_unicode_string(const unsigned char *utf8) +{ + int size = 0, index = 0, out_index = 0; + wchar_t *out; + unsigned char c; + + /* first calculate the size of the target string */ + c = utf8[index++]; + while (c) + { + if ((c & 0x80) == 0) + { + index += 0; + }else if((c & 0xe0) == 0xe0) + { + index += 2; + }else{ + index += 1; + } + size += 1; + c = utf8[index++]; + } + + out = (wchar_t *)malloc((size + 1) * sizeof(wchar_t)); + if (out == NULL) + return NULL; + index = 0; + + c = utf8[index++]; + while (c) + { + if ((c & 0x80) == 0) + { + out[out_index++] = c; + }else if ((c & 0xe0) == 0xe0) + { + out[out_index] = (c & 0x1F) << 12; + c = utf8[index++]; + out[out_index] |= (c & 0x3F) << 6; + c = utf8[index++]; + out[out_index++] |= (c & 0x3F); + }else{ + out[out_index] = (c & 0x3F) << 6; + c = utf8[index++]; + out[out_index++] |= (c & 0x3F); + } + c = utf8[index++]; + } + out[out_index] = 0; + + return out; +} + +int utf8_encode(const char *from, char **to) +{ + wchar_t *unicode; + int wchars, err; + + + wchars = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, from, + strlen(from), NULL, 0); + + if(wchars == 0) + { +// fprintf(stderr, "Unicode translation error %d\n", GetLastError()); + return -1; + } + + unicode = (wchar_t *)calloc(wchars + 1, sizeof(unsigned short)); + if(unicode == NULL) + { +// fprintf(stderr, "Out of memory processing string to UTF8\n"); + return -1; + } + + err = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, from, strlen(from), unicode, wchars); + if (err != wchars) + { + free(unicode); +// fprintf(stderr, "Unicode translation error %d\n", GetLastError()); + return -1; + } + + /* On NT-based windows systems, we could use WideCharToMultiByte(), but + * MS doesn't actually have a consistent API across win32. + */ + *to = (char *)make_utf8_string(unicode); + + free(unicode); + return 0; +} + +int utf8_decode(const char *from, char **to) +{ + wchar_t *unicode; + int chars, err; + + const char *cds; + identify_encoding_t *cdt; + enum identify_encoding_order order; + order = ieo_SJIS; + cdt = identify_encoding_open(order); + cds = identify_encoding(cdt,(char *)from); + if (strcmp(cds,"UTF-8")!=0) + { + identify_encoding_close(cdt); + return -1; + } + identify_encoding_close(cdt); + + + /* On NT-based windows systems, we could use MultiByteToWideChar(CP_UTF8), but + * MS doesn't actually have a consistent API across win32. + */ + unicode = (wchar_t *)make_unicode_string((const unsigned char *)from); + if (unicode == NULL) + { +// fprintf(stderr, "Out of memory processing string from UTF8 to UNICODE16\n"); + return -1; + } + + chars = WideCharToMultiByte(GetConsoleCP(), WC_COMPOSITECHECK, unicode, -1, NULL, 0, NULL, NULL); + + if (chars == 0) + { +// fprintf(stderr, "Unicode translation error %d\n", GetLastError()); + free(unicode); + return -1; + } + + *to = (char *)calloc(chars + 1, sizeof(unsigned char)); + if (*to == NULL) + { +// fprintf(stderr, "Out of memory processing string to local charset\n"); + free(unicode); + return -1; + } + + err = WideCharToMultiByte(GetConsoleCP(), WC_COMPOSITECHECK, unicode, -1, *to, chars, NULL, NULL); + if (err != chars) + { +// fprintf(stderr, "Unicode translation error %d\n", GetLastError()); + free(unicode); + free(*to); + *to = NULL; + return -1; + } + + free(unicode); + return 0; +} + +#else /* End win32. Rest is for real operating systems */ + + +#ifdef HAVE_LANGINFO_CODESET +#include +#endif + +int iconvert(const char *fromcode, const char *tocode, + const char *from, size_t fromlen, + char **to, size_t *tolen); + +static char *current_charset = 0; /* means "US-ASCII" */ + +void convert_set_charset(const char *charset) +{ + + if (!charset) + charset = getenv("CHARSET"); + +#ifdef HAVE_LANGINFO_CODESET + if (!charset) + charset = nl_langinfo(CODESET); +#endif + + free(current_charset); + current_charset = 0; + if (charset && *charset) + current_charset = strdup(charset); +} + +static int convert_buffer(const char *fromcode, const char *tocode, + const char *from, size_t fromlen, + char **to, size_t *tolen) +{ + int ret = -1; + +#ifdef HAVE_ICONV + ret = iconvert(fromcode, tocode, from, fromlen, to, tolen); + if (ret != -1) + return ret; +#endif + +#ifndef HAVE_ICONV /* should be ifdef USE_CHARSET_CONVERT */ + ret = charset_convert(fromcode, tocode, from, fromlen, to, tolen); + if (ret != -1) + return ret; +#endif + + return ret; +} + +static int convert_string(const char *fromcode, const char *tocode, + const char *from, char **to, char replace) +{ + int ret; + size_t fromlen; + char *s; + + fromlen = strlen(from); + ret = convert_buffer(fromcode, tocode, from, fromlen, to, 0); + if (ret == -2) + return -1; + if (ret != -1) + return ret; + + s = malloc(fromlen + 1); + if (!s) + return -1; + strcpy(s, from); + *to = s; + for (; *s; s++) + if (*s & ~0x7f) + *s = replace; + return 3; +} + +int utf8_encode(const char *from, char **to) +{ + char *charset; + + if (!current_charset) + convert_set_charset(0); + charset = current_charset ? current_charset : "US-ASCII"; + return convert_string(charset, "UTF-8", from, to, '#'); +} + +int utf8_decode(const char *from, char **to) +{ + char *charset; + + if (*from == 0) + { + *to = malloc(1); + **to = 0; + return 1; + } + + if (!current_charset) + convert_set_charset(0); + charset = current_charset ? current_charset : "US-ASCII"; + return convert_string("UTF-8", charset, from, to, '?'); +} + +#endif diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/utf8.h b/c:/Git/PeerCast.root/PeerCast/core/common/utf8.h new file mode 100644 index 0000000..f701319 --- /dev/null +++ b/c:/Git/PeerCast.root/PeerCast/core/common/utf8.h @@ -0,0 +1,36 @@ + +/* + * Convert a string between UTF-8 and the locale's charset. + * Invalid bytes are replaced by '#', and characters that are + * not available in the target encoding are replaced by '?'. + * + * If the locale's charset is not set explicitly then it is + * obtained using nl_langinfo(CODESET), where available, the + * environment variable CHARSET, or assumed to be US-ASCII. + * + * Return value of conversion functions: + * + * -1 : memory allocation failed + * 0 : data was converted exactly + * 1 : valid data was converted approximately (using '?') + * 2 : input was invalid (but still converted, using '#') + * 3 : unknown encoding (but still converted, using '?') + */ + +#ifndef __UTF8_H +#define __UTF8_H + +#ifdef __cplusplus +extern "C" { +#endif + +void convert_set_charset(const char *charset); + +int utf8_encode(const char *from, char **to); +int utf8_decode(const char *from, char **to); + +#ifdef __cplusplus +} +#endif + +#endif /* __UTF8_H */ diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/version2.h b/c:/Git/PeerCast.root/PeerCast/core/common/version2.h new file mode 100644 index 0000000..24a45ce --- /dev/null +++ b/c:/Git/PeerCast.root/PeerCast/core/common/version2.h @@ -0,0 +1,53 @@ +// ------------------------------------------------ +// File : version2.h +// Date: 17-june-2005 +// Author: giles +// +// (c) 2005 peercast.org +// ------------------------------------------------ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// ------------------------------------------------ + +#ifndef _VERSION2_H +#define _VERSION2_H + +// ------------------------------------------------ +#ifdef PRIVATE_BROADCASTER +static const char PCP_BROADCAST_FLAGS = 0x01; +static bool PCP_FORCE_YP = true; +#else +static const char PCP_BROADCAST_FLAGS = 0x00; +static bool PCP_FORCE_YP = false; +#endif +// ------------------------------------------------ +static const int PCP_CLIENT_VERSION = 1217; +static const int PCP_CLIENT_VERSION_VP = 23; +static const int PCP_ROOT_VERSION = 1212; + +static const int PCP_CLIENT_MINVERSION = 1200; + +static const char *PCX_AGENT = "PeerCast/0.1217"; +static const char *PCX_AGENTJP = "PeerCast/0.1217-J"; +static const char *PCX_AGENTVP = "PeerCast/0.1217(VP0023)"; +static const char *PCX_VERSTRING = "v0.1217(VP0023)"; + +#if 1 /* for VP extend version */ +#define VERSION_EX 1 +static const char *PCP_CLIENT_VERSION_EX_PREFIX = "IM"; // 2bytes only +static const int PCP_CLIENT_VERSION_EX_NUMBER = 7651; +static const char *PCX_AGENTEX = "PeerCast/0.1217(IM7651)"; +static const char *PCX_VERSTRING_EX = "v0.1217(IM7651)"; +#endif + +// ------------------------------------------------ + + +#endif diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/xml.cpp b/c:/Git/PeerCast.root/PeerCast/core/common/xml.cpp new file mode 100644 index 0000000..19c1035 --- /dev/null +++ b/c:/Git/PeerCast.root/PeerCast/core/common/xml.cpp @@ -0,0 +1,491 @@ +// ------------------------------------------------ +// File : xml.cpp +// Date: 4-apr-2002 +// Author: giles +// Desc: +// Basic XML parsing/creation +// +// (c) 2002 peercast.org +// ------------------------------------------------ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// ------------------------------------------------ + +#include "xml.h" +#include "stream.h" +#include +#include +#ifdef _DEBUG +#include "chkMemoryLeak.h" +#define DEBUG_NEW new(__FILE__, __LINE__) +#define new DEBUG_NEW +#endif + +// ---------------------------------- +void XML::Node::add(Node *n) +{ + if (!n) + return; + + n->parent = this; + + if (child) + { + // has children, add to last sibling + Node *s = child; + while (s->sibling) + s = s->sibling; + s->sibling = n; + + }else{ + // no children yet + child = n; + } +} +// --------------------------------- +inline char nibsToByte(char n1, char n2) +{ + if (n1 >= 'A') n1 = n1-'A'+10; + else n1 = n1-'0'; + if (n2 >= 'A') n2 = n2-'A'+10; + else n2 = n2-'0'; + + return ((n2&0xf)<<4)|(n1&0xf); +} + +// ---------------------------------- +int XML::Node::getBinaryContent(void *ptr, int size) +{ + char *in = contData; + char *out = (char *)ptr; + + int i=0; + while (*in) + { + if (isWhiteSpace(*in)) + { + in++; + }else + { + if (i >= size) + throw StreamException("Too much binary data"); + out[i++] = nibsToByte(in[0],in[1]); + in+=2; + } + } + return i; +} +// ---------------------------------- +void XML::Node::setBinaryContent(void *ptr, int size) +{ + const char hexTable[] = "0123456789ABCDEF"; + const int lineWidth = 1023; + + contData = new char[size*2+1+(size/lineWidth)]; + + char *bp = (char *)ptr; + register char *ap = contData; + + for(register int i=0; i>4)&0xf]; + if ((i&lineWidth)==lineWidth) + *ap++ = '\n'; + } + ap[0] = 0; +} + + +// ---------------------------------- +void XML::Node::setContent(const char *n) +{ + contData = strdup(n); +} +// ---------------------------------- +void XML::Node::setAttributes(const char *n) +{ + char c; + + attrData = strdup(n); + + // count maximum amount of attributes + int maxAttr = 1; // 1 for tag name + bool inQ = false; + int i=0; + while ((c=attrData[i++])!=0) + { + if (c=='\"') + inQ ^= true; + + if (!inQ) + if (c=='=') + maxAttr++; + } + + + attr = new Attribute[maxAttr]; + + attr[0].namePos = 0; + attr[0].valuePos = 0; + + numAttr=1; + + i=0; + + // skip until whitespace + while (c=attrData[i++]) + if (isWhiteSpace(c)) + break; + + if (!c) return; // no values + + attrData[i-1]=0; + + + while ((c=attrData[i])!=0) + { + if (!isWhiteSpace(c)) + { + if (numAttr>=maxAttr) + throw StreamException("Too many attributes"); + + // get start of tag name + attr[numAttr].namePos = i; + + + // skip whitespaces until next '=' + // terminate name on next whitespace or '=' + while (attrData[i]) + { + c = attrData[i++]; + + if ((c == '=') || isWhiteSpace(c)) + { + attrData[i-1] = 0; // null term. name + if (c == '=') + break; + } + } + + // skip whitespaces + while (attrData[i]) + { + if (isWhiteSpace(attrData[i])) + i++; + else + break; + } + + // check for valid start of attribute value - '"' + if (attrData[i++] != '\"') + throw StreamException("Bad tag value"); + + attr[numAttr++].valuePos = i; + + // terminate attribute value at next '"' + + while (attrData[i]) + if (attrData[i++] == '\"') + break; + + attrData[i-1] = 0; // null term. value + + + }else{ + i++; + } + } +} +// ---------------------------------- +XML::Node::Node(const char *fmt,...) +{ + va_list ap; + va_start(ap, fmt); + + char tmp[8192]; + vsprintf(tmp,fmt,ap); + setAttributes(tmp); + + va_end(ap); + init(); +} + +// ---------------------------------- +void XML::Node::init() +{ + parent = sibling = child = NULL; + contData = NULL; + userPtr = NULL; +} +// ---------------------------------- +int XML::Node::findAttrInt(const char *name) +{ + char *v = findAttr(name); + if (!v) return 0; + return atoi(v); +} +// ---------------------------------- +int XML::Node::findAttrID(const char *name) +{ + char *v = findAttr(name); + if (!v) return 0; + return strToID(v); +} +// ---------------------------------- +char *XML::Node::findAttr(const char *name) +{ + int nlen = strlen(name); + for(int i=1; i\n",3); + }else + { + out.write(">\n",2); + + if (contData) + out.write(contData,strlen(contData)); + + if (child) + child->write(out,level+1); +#if 0 + if (level) + out.write(tabs,strlen(tabs)); +#endif + out.write("\n",2); + } + + if (sibling) + sibling->write(out,level); +} +// ---------------------------------- +XML::Node::~Node() +{ +// LOG("delete %s",getName()); + + if (contData) + delete [] contData; + if (attrData) + delete [] attrData; + if (attr) + delete [] attr; + + Node *n = child; + while (n) + { + Node *nn = n->sibling; + delete n; + n = nn; + } +} + + +// ---------------------------------- +XML::~XML() +{ + if (root) + delete root; +} + +// ---------------------------------- +void XML::write(Stream &out) +{ + if (!root) + throw StreamException("No XML root"); + + out.writeLine(""); + root->write(out,1); + +} +// ---------------------------------- +void XML::writeCompact(Stream &out) +{ + if (!root) + throw StreamException("No XML root"); + + out.writeLine(""); + root->write(out,1); + +} +// ---------------------------------- +void XML::writeHTML(Stream &out) +{ + if (!root) + throw StreamException("No XML root"); + + root->write(out,1); +} + +// ---------------------------------- +void XML::setRoot(Node *n) +{ + root=n; +} + + +// ---------------------------------- +XML::Node *XML::findNode(const char *n) +{ + if (root) + return root->findNode(n); + else + return NULL; +} + + +// ---------------------------------- +XML::Node *XML::Node::findNode(const char *name) +{ + if (stricmp(getName(),name)==0) + return this; + + XML::Node *c = child; + + while (c) + { + XML::Node *fn = c->findNode(name); + if (fn) + return fn; + c=c->sibling; + } + + return NULL; +} + +// ---------------------------------- +void XML::read(Stream &in) +{ + const int BUFFER_LEN = 100*1024; + static char buf[BUFFER_LEN]; + + Node *currNode=NULL; + int tp=0; + + while (!in.eof()) + { + char c = in.readChar(); + + if (c == '<') + { + if (tp && currNode) // check for content + { + buf[tp] = 0; + currNode->setContent(buf); + } + tp = 0; + + // read to next '>' + while (!in.eof()) + { + c = in.readChar(); + if (c == '>') + break; + + if (tp >= BUFFER_LEN) + throw StreamException("Tag too long"); + + buf[tp++] = c; + } + buf[tp]=0; + + if (buf[0] == '!') // comment + { + // do nothing + }else if (buf[0] == '?') // doc type + { + if (strnicmp(&buf[1],"xml ",4)) + throw StreamException("Not XML document"); + }else if (buf[0] == '/') // end tag + { + if (!currNode) + throw StreamException("Unexpected end tag"); + currNode = currNode->parent; + }else // new tag + { + //LOG("tag: %s",buf); + + bool singleTag = false; + + if (buf[tp-1] == '/') // check for single tag + { + singleTag = true; + buf[tp-1] = 0; + } + + // only add valid tags + if (strlen(buf)) + { + Node *n = new Node(buf); + + if (currNode) + currNode->add(n); + else + setRoot(n); + + if (!singleTag) + currNode = n; + } + } + + tp = 0; + } else { + + if (tp >= BUFFER_LEN) + throw StreamException("Content too big"); + + buf[tp++] = c; + + } + } +} + diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/xml.h b/c:/Git/PeerCast.root/PeerCast/core/common/xml.h new file mode 100644 index 0000000..df157a4 --- /dev/null +++ b/c:/Git/PeerCast.root/PeerCast/core/common/xml.h @@ -0,0 +1,92 @@ +// ------------------------------------------------ +// File : xml.h +// Date: 4-apr-2002 +// Author: giles +// Desc: +// +// (c) 2002 peercast.org +// ------------------------------------------------ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// ------------------------------------------------ + +#ifndef _XML_H +#define _XML_H + +//----------------------- +#include "common.h" +#include + +//----------------------- +class Stream; + +//----------------------- +class XML +{ +public: + class Node + { + public: + class Attribute + { + public: + int namePos,valuePos; + }; + + Node(const char *,...); + + void init(); + + ~Node(); + + void add(Node *); + void write(Stream &,int); // output, level + char *getName() {return getAttrName(0);} + + char *getAttrValue(int i) {return &attrData[attr[i].valuePos];} + char *getAttrName(int i) {return &attrData[attr[i].namePos];} + char *getContent() {return contData; } + int getBinaryContent(void *, int); + + void setAttributes(const char *); + void setContent(const char *); + void setBinaryContent(void *, int); + + Node *findNode(const char *); + char *findAttr(const char *); + int findAttrInt(const char *); + int findAttrID(const char *); + + char *contData,*attrData; + + Attribute *attr; + int numAttr; + + Node *child,*parent,*sibling; + void *userPtr; + }; + + XML() + { + root = NULL; + } + + ~XML(); + + void setRoot(Node *n); + void write(Stream &); + void writeCompact(Stream &); + void writeHTML(Stream &); + void read(Stream &); + Node *findNode(const char *n); + + Node *root; +}; +#endif diff --git a/c:/Git/PeerCast.root/PeerCast/core/win32/lib/corelib.vcproj b/c:/Git/PeerCast.root/PeerCast/core/win32/lib/corelib.vcproj new file mode 100644 index 0000000..6f7743e --- /dev/null +++ b/c:/Git/PeerCast.root/PeerCast/core/win32/lib/corelib.vcproj @@ -0,0 +1,1573 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/c:/Git/PeerCast.root/PeerCast/core/win32/lib/corelib.vcproj.vspscc b/c:/Git/PeerCast.root/PeerCast/core/win32/lib/corelib.vcproj.vspscc new file mode 100644 index 0000000..16d4a14 --- /dev/null +++ b/c:/Git/PeerCast.root/PeerCast/core/win32/lib/corelib.vcproj.vspscc @@ -0,0 +1,10 @@ +"" +{ +"FILE_VERSION" = "9237" +"ENLISTMENT_CHOICE" = "NEVER" +"PROJECT_FILE_RELATIVE_PATH" = "relative:core\\win32\\lib" +"NUMBER_OF_EXCLUDED_FILES" = "0" +"ORIGINAL_PROJECT_FILE_PATH" = "" +"NUMBER_OF_NESTED_PROJECTS" = "0" +"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROJECT" +} diff --git a/c:/Git/PeerCast.root/PeerCast/core/win32/wsocket.cpp b/c:/Git/PeerCast.root/PeerCast/core/win32/wsocket.cpp new file mode 100644 index 0000000..5b03e4c --- /dev/null +++ b/c:/Git/PeerCast.root/PeerCast/core/win32/wsocket.cpp @@ -0,0 +1,675 @@ +// ------------------------------------------------ +// File : wsocket.cpp +// Date: 4-apr-2002 +// Author: giles +// Desc: +// Windows version of ClientSocket. Handles the nitty gritty of actually +// reading and writing TCP +// +// (c) 2002 peercast.org +// ------------------------------------------------ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// ------------------------------------------------ + +// TODO: fix socket closing + + +//#include "stdafx.h" +//#include "winsock2.h" +#include +#include +#include "wsocket.h" +#include "stats.h" +#ifdef _DEBUG +#include "chkMemoryLeak.h" +#define DEBUG_NEW new(__FILE__, __LINE__) +#define new DEBUG_NEW +#endif + + +// -------------------------------------------------- +void WSAClientSocket::init() +{ + WORD wVersionRequested; + WSADATA wsaData; + int err; + + wVersionRequested = MAKEWORD( 2, 0 ); + err = WSAStartup( wVersionRequested, &wsaData ); + if ( err != 0 ) + throw SockException("Unable to init sockets"); + + //LOG4("WSAStartup: OK"); + +} +// -------------------------------------------------- +bool ClientSocket::getHostname(char *str,unsigned int ip) +{ + HOSTENT *he; + + ip = htonl(ip); + + he = gethostbyaddr((char *)&ip,sizeof(ip),AF_INET); + + if (he) + { + strcpy(str,he->h_name); + return true; + }else + return false; +} + +unsigned int cache_ip = 0; +unsigned int cache_time = 0; + +// -------------------------------------------------- +unsigned int ClientSocket::getIP(char *name) +{ + unsigned int ctime = sys->getTime(); + bool null_flg = (name == NULL); + + if (null_flg){ + if ((cache_time != 0) && (cache_time + 60 > ctime)){ + return cache_ip; + } else { + cache_time = 0; + cache_ip = 0; + } + } + + char szHostName[256]; + + if (!name) + { + if (gethostname(szHostName, sizeof(szHostName))==0) + name = szHostName; + else + return 0; + } + + HOSTENT *he = WSAClientSocket::resolveHost(name); + + if (!he) + return 0; + + + LPSTR lpAddr = he->h_addr_list[0]; + if (lpAddr) + { + unsigned int ret; + struct in_addr inAddr; + memmove (&inAddr, lpAddr, 4); + + ret = inAddr.S_un.S_un_b.s_b1<<24 | + inAddr.S_un.S_un_b.s_b2<<16 | + inAddr.S_un.S_un_b.s_b3<<8 | + inAddr.S_un.S_un_b.s_b4; + + if (null_flg){ + cache_ip = ret; + cache_time = ctime; + } + return ret; + } + return 0; +} +// -------------------------------------------------- +void WSAClientSocket::setLinger(int sec) +{ + linger linger; + linger.l_onoff = (sec>0)?1:0; + linger.l_linger = sec; + + if (setsockopt(sockNum, SOL_SOCKET, SO_LINGER, (const char *)&linger, sizeof (linger)) == -1) + throw SockException("Unable to set LINGER"); +} + +// -------------------------------------------------- +void WSAClientSocket::setBlocking(bool yes) +{ + unsigned long op = yes ? 0 : 1; + if (ioctlsocket(sockNum, FIONBIO, &op) == SOCKET_ERROR) + throw SockException("Can`t set blocking"); +} +// -------------------------------------------------- +void WSAClientSocket::setNagle(bool on) +{ + int nodelay = (on==false); + if (setsockopt(sockNum, SOL_SOCKET, TCP_NODELAY, (char *)&nodelay, sizeof nodelay) == -1) + throw SockException("Unable to set NODELAY"); + +} + +// -------------------------------------------------- +void WSAClientSocket::setReuse(bool yes) +{ + unsigned long op = yes ? 1 : 0; + if (setsockopt(sockNum,SOL_SOCKET,SO_REUSEADDR,(char *)&op,sizeof(unsigned long)) == -1) + throw SockException("Unable to set REUSE"); +} + +// -------------------------------------------------- +void WSAClientSocket::setBufSize(int size) +{ + int oldop; + int op = size; + int len = sizeof(op); + if (getsockopt(sockNum,SOL_SOCKET,SO_RCVBUF,(char *)&oldop,&len) == -1) { + LOG_DEBUG("Unable to get RCVBUF"); + } else if (oldop < size) { + if (setsockopt(sockNum,SOL_SOCKET,SO_RCVBUF,(char *)&op,len) == -1) + LOG_DEBUG("Unable to set RCVBUF"); + //else + // LOG_DEBUG("*** recvbufsize:%d -> %d", oldop, op); + } + + if (getsockopt(sockNum,SOL_SOCKET,SO_SNDBUF,(char *)&oldop,&len) == -1) { + LOG_DEBUG("Unable to get SNDBUF"); + } else if (oldop < size) { + if (setsockopt(sockNum,SOL_SOCKET,SO_SNDBUF,(char *)&op,len) == -1) + LOG_DEBUG("Unable to set SNDBUF"); + //else + // LOG_DEBUG("*** sendbufsize: %d -> %d", oldop, op); + } +} + +// -------------------------------------------------- +HOSTENT *WSAClientSocket::resolveHost(const char *hostName) +{ + HOSTENT *he; + + if ((he = gethostbyname(hostName)) == NULL) + { + // if failed, try using gethostbyaddr instead + + unsigned long ip = inet_addr(hostName); + + if (ip == INADDR_NONE) + return NULL; + + if ((he = gethostbyaddr((char *)&ip,sizeof(ip),AF_INET)) == NULL) + return NULL; + } + return he; +} + +// -------------------------------------------------- +void WSAClientSocket::open(Host &rh) +{ + sockNum = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); + + if (sockNum == INVALID_SOCKET) + throw SockException("Can`t open socket"); + + setBlocking(false); +#ifdef DISABLE_NAGLE + setNagle(false); +#endif + setBufSize(65535); + + host = rh; + + memset(&remoteAddr,0,sizeof(remoteAddr)); + + remoteAddr.sin_family = AF_INET; + remoteAddr.sin_port = htons(host.port); + remoteAddr.sin_addr.S_un.S_addr = htonl(host.ip); + +} +// -------------------------------------------------- +void WSAClientSocket::checkTimeout(bool r, bool w) +{ + int err = WSAGetLastError(); + if (err == WSAEWOULDBLOCK) + { + + timeval timeout; + fd_set read_fds; + fd_set write_fds; + + timeout.tv_sec = 0; + timeout.tv_usec = 0; + + FD_ZERO (&write_fds); + if (w) + { + timeout.tv_sec = (int)this->writeTimeout/1000; + FD_SET (sockNum, &write_fds); + } + + FD_ZERO (&read_fds); + if (r) + { + timeout.tv_sec = (int)this->readTimeout/1000; + FD_SET (sockNum, &read_fds); + } + + timeval *tp; + if (timeout.tv_sec) + tp = &timeout; + else + tp = NULL; + + + int r=select (NULL, &read_fds, &write_fds, NULL, tp); + + if (r == 0) + throw TimeoutException(); + else if (r == SOCKET_ERROR) + throw SockException("select failed."); + + }else{ + char str[32]; + sprintf(str,"%d",err); + throw SockException(str); + } +} + +// -------------------------------------------------- +void WSAClientSocket::checkTimeout2(bool r, bool w) +{ + { + + timeval timeout; + fd_set read_fds; + fd_set write_fds; + + timeout.tv_sec = 0; + timeout.tv_usec = 0; + + FD_ZERO (&write_fds); + if (w) + { + timeout.tv_sec = (int)this->writeTimeout/1000; + FD_SET (sockNum, &write_fds); + } + + FD_ZERO (&read_fds); + if (r) + { + timeout.tv_sec = (int)this->readTimeout/1000; + FD_SET (sockNum, &read_fds); + } + + timeval *tp; + if (timeout.tv_sec) + tp = &timeout; + else + tp = NULL; + + + int r=select (NULL, &read_fds, &write_fds, NULL, tp); + + if (r == 0) + throw TimeoutException(); + else if (r == SOCKET_ERROR) + throw SockException("select failed."); + } +} + +// -------------------------------------------------- +Host WSAClientSocket::getLocalHost() +{ + struct sockaddr_in localAddr; + + int len = sizeof(localAddr); + if (getsockname(sockNum, (sockaddr *)&localAddr, &len) == 0) + return Host(SWAP4(localAddr.sin_addr.s_addr),0); + else + return Host(0,0); +} + +// -------------------------------------------------- +void WSAClientSocket::connect() +{ + if (::connect(sockNum,(struct sockaddr *)&remoteAddr,sizeof(remoteAddr)) == SOCKET_ERROR) + checkTimeout(false,true); + +} +// -------------------------------------------------- +int WSAClientSocket::read(void *p, int l) +{ + int bytesRead=0; + + while (l) + { + if (rbDataSize >= l) { + memcpy(p, &apReadBuf[rbPos], l); + rbPos += l; + rbDataSize -= l; + return l; + } else if (rbDataSize > 0) { + memcpy(p, &apReadBuf[rbPos], rbDataSize); + p = (char *) p + rbDataSize; + l -= rbDataSize; + bytesRead += rbDataSize; + } + + rbPos = 0; + rbDataSize = 0; + //int r = recv(sockNum, (char *)p, l, 0); + int r = recv(sockNum, apReadBuf, RBSIZE, 0); + if (r == SOCKET_ERROR) + { + // non-blocking sockets always fall through to here + checkTimeout(true,false); + + }else if (r == 0) + { + throw EOFException("Closed on read"); + + }else + { + stats.add(Stats::BYTESIN,r); + if (host.localIP()) + stats.add(Stats::LOCALBYTESIN,r); + updateTotals(r,0); + //bytesRead += r; + //l -= r; + //p = (char *)p+r; + + rbDataSize += r; + } + } + return bytesRead; +} +// -------------------------------------------------- +int WSAClientSocket::readUpto(void *p, int l) +{ + int bytesRead=0; + while (l) + { + int r = recv(sockNum, (char *)p, l, 0); + if (r == SOCKET_ERROR) + { + // non-blocking sockets always fall through to here + //checkTimeout(true,false); + return r; + + }else if (r == 0) + { + break; + }else + { + stats.add(Stats::BYTESIN,r); + if (host.localIP()) + stats.add(Stats::LOCALBYTESIN,r); + updateTotals(r,0); + bytesRead += r; + l -= r; + p = (char *)p+r; + } + if (bytesRead) break; + } + return bytesRead; +} + + +// -------------------------------------------------- +void WSAClientSocket::write(const void *p, int l) +{ + while (l) + { + int r = send(sockNum, (char *)p, l, 0); + if (r == SOCKET_ERROR) + { + checkTimeout(false,true); + } + else if (r == 0) + { + throw SockException("Closed on write"); + } + else + if (r > 0) + { + stats.add(Stats::BYTESOUT,r); + if (host.localIP()) + stats.add(Stats::LOCALBYTESOUT,r); + + updateTotals(0,r); + l -= r; + p = (char *)p+r; + } + } +} + +// -------------------------------------------------- +void WSAClientSocket::bufferingWrite(const void *p, int l) +{ + if (bufList.isNull() && p != NULL){ + while(l){ + int r = send(sockNum, (char *)p, l, 0); + if (r == SOCKET_ERROR){ + int err = WSAGetLastError(); + if (err == WSAEWOULDBLOCK){ + bufList.add(p, l); +// LOG_DEBUG("normal add"); + break; + } else { + char str[32]; + sprintf(str,"%d",err); + throw SockException(str); + } + } else if (r == 0) { + throw SockException("Closed on write"); + } else if (r > 0){ + stats.add(Stats::BYTESOUT,r); + if (host.localIP()) + stats.add(Stats::LOCALBYTESOUT,r); + + updateTotals(0,r); + l -= r; + p = (char *)p+r; + } + } + } else { +// LOG_DEBUG("***************BufferingWrite"); + if (p) + bufList.add(p,l); + + bool flg = true; + + while(flg){ + SocketBuffer *tmp; + tmp = bufList.getTop(); + + if (tmp){ +// LOG_DEBUG("tmp->pos = %d, tmp->len = %d, %d", tmp->pos, tmp->len, tmp); + while(tmp->pos < tmp->len){ + int r = send(sockNum, (char*)(tmp->buf + tmp->pos), tmp->len - tmp->pos, 0); +// LOG_DEBUG("send = %d", r); + if (r == SOCKET_ERROR){ + int err = WSAGetLastError(); + if (err == WSAEWOULDBLOCK){ + flg = false; + break; + } else { + bufList.clear(); + char str[32]; + sprintf(str,"%d",err); + throw SockException(str); + } + } else if (r == 0){ + bufList.clear(); + throw SockException("Closed on write"); + } else if (r > 0){ + stats.add(Stats::BYTESOUT,r); + if (host.localIP()) + stats.add(Stats::LOCALBYTESOUT,r); + + updateTotals(0,r); + + tmp->pos += r; + if (tmp->pos >= tmp->len){ +// LOG_DEBUG("deleteTop"); + bufList.deleteTop(); + break; + } + } + } + } else { + flg = false; + } + } +// LOG_DEBUG("bufferingWrite end"); + } +} + +// -------------------------------------------------- +void WSAClientSocket::checkBuffering(bool r, bool w) +{ + int err = WSAGetLastError(); + if (err == WSAEWOULDBLOCK) + { + + timeval timeout; + fd_set read_fds; + fd_set write_fds; + + timeout.tv_sec = 0; + timeout.tv_usec = 0; + + FD_ZERO (&write_fds); + if (w) + { + timeout.tv_sec = (int)this->writeTimeout/1000; + FD_SET (sockNum, &write_fds); + } + + FD_ZERO (&read_fds); + if (r) + { + timeout.tv_sec = (int)this->readTimeout/1000; + FD_SET (sockNum, &read_fds); + } + + timeval *tp; + if (timeout.tv_sec) + tp = &timeout; + else + tp = NULL; + + + int r=select (NULL, &read_fds, &write_fds, NULL, tp); + + if (r == 0) + throw TimeoutException(); + else if (r == SOCKET_ERROR) + throw SockException("select failed."); + + }else{ + char str[32]; + sprintf(str,"%d",err); + throw SockException(str); + } +} + +// -------------------------------------------------- +void WSAClientSocket::bind(Host &h) +{ + struct sockaddr_in localAddr; + + if ((sockNum = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) + throw SockException("Can`t open socket"); + + setBlocking(false); + setReuse(true); + + memset(&localAddr,0,sizeof(localAddr)); + localAddr.sin_family = AF_INET; + localAddr.sin_port = htons(h.port); + localAddr.sin_addr.s_addr = INADDR_ANY; + + if( ::bind (sockNum, (sockaddr *)&localAddr, sizeof(localAddr)) == -1) + throw SockException("Can`t bind socket"); + + if (::listen(sockNum,SOMAXCONN)) + throw SockException("Can`t listen",WSAGetLastError()); + + host = h; +} +// -------------------------------------------------- +ClientSocket *WSAClientSocket::accept() +{ + + int fromSize = sizeof(sockaddr_in); + sockaddr_in from; + + int conSock = ::accept(sockNum,(sockaddr *)&from,&fromSize); + + + if (conSock == INVALID_SOCKET) + return NULL; + + + WSAClientSocket *cs = new WSAClientSocket(); + cs->sockNum = conSock; + + cs->host.port = from.sin_port; + cs->host.ip = from.sin_addr.S_un.S_un_b.s_b1<<24 | + from.sin_addr.S_un.S_un_b.s_b2<<16 | + from.sin_addr.S_un.S_un_b.s_b3<<8 | + from.sin_addr.S_un.S_un_b.s_b4; + + + cs->setBlocking(false); +#ifdef DISABLE_NAGLE + cs->setNagle(false); +#endif + cs->setBufSize(65535); + + return cs; +} + +// -------------------------------------------------- +void WSAClientSocket::close() +{ + sockLock.on(); + if (sockNum) + { +// shutdown(sockNum,SD_SEND); + + setReadTimeout(2000); + unsigned int stime = sys->getTime(); + try + { + char c[1024]; + while (readUpto(&c,1024) > 0) + if (sys->getTime() - stime > 5) break; + //readUpto(&c,1); + }catch(StreamException &) {} + + if (closesocket (sockNum)) + LOG_ERROR("closesocket() error"); + + + sockNum=0; + } + sockLock.off(); +} + +// -------------------------------------------------- +bool WSAClientSocket::readReady() +{ + if (rbDataSize) return true; + + timeval timeout; + fd_set read_fds; + + timeout.tv_sec = 0; + timeout.tv_usec = 0; + + FD_ZERO (&read_fds); + FD_SET (sockNum, &read_fds); + + return select (sockNum+1, &read_fds, NULL, NULL, &timeout) == 1; +} + diff --git a/c:/Git/PeerCast.root/PeerCast/core/win32/wsocket.h b/c:/Git/PeerCast.root/PeerCast/core/win32/wsocket.h new file mode 100644 index 0000000..fdf4055 --- /dev/null +++ b/c:/Git/PeerCast.root/PeerCast/core/win32/wsocket.h @@ -0,0 +1,86 @@ +// ------------------------------------------------ +// File : wsocket.h +// Date: 4-apr-2002 +// Author: giles +// Desc: +// see .cpp for details +// +// (c) 2002 peercast.org +// ------------------------------------------------ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// ------------------------------------------------ + +#ifndef _WSOCKET_H +#define _WSOCKET_H + +#include +#include "socket.h" +//#include "winsock2.h" + + +// -------------------------------------------------- +class WSAClientSocket : public ClientSocket +{ +public: + static void init(); + + WSAClientSocket() + :sockNum(0) + ,writeCnt(0) + ,rbPos(0) + ,rbDataSize(0) + { + } + + ~WSAClientSocket(){ + bufList.clear(); + } + + virtual void open(Host &); + virtual int read(void *, int); + virtual int readUpto(void *, int); + virtual void write(const void *, int); + virtual void bind(Host &); + virtual void connect(); + virtual void close(); + virtual ClientSocket * accept(); + virtual bool active() {return sockNum != 0;} + virtual bool readReady(); + virtual Host getLocalHost(); + virtual void setBlocking(bool); + void setReuse(bool); + void setNagle(bool); + void setLinger(int); + void setBufSize(int size); + +// static HOSTENT *resolveHost(const char *); + static hostent *resolveHost(const char *); + + void checkTimeout(bool,bool); + void checkTimeout2(bool,bool); + + virtual void bufferingWrite(const void*, int); + void checkBuffering(bool, bool); + + unsigned int writeCnt; + unsigned int sockNum; + struct sockaddr_in remoteAddr; + + enum {RBSIZE = 8192}; + char apReadBuf[RBSIZE]; + int rbPos; + int rbDataSize; + + WLock sockLock; +}; + +#endif + \ No newline at end of file diff --git a/c:/Git/PeerCast.root/PeerCast/core/win32/wsys.cpp b/c:/Git/PeerCast.root/PeerCast/core/win32/wsys.cpp new file mode 100644 index 0000000..9ed1fcf --- /dev/null +++ b/c:/Git/PeerCast.root/PeerCast/core/win32/wsys.cpp @@ -0,0 +1,150 @@ +// ------------------------------------------------ +// File : wsys.cpp +// Date: 4-apr-2002 +// Author: giles +// Desc: +// WSys derives from Sys to provide basic win32 functions such as starting threads. +// +// (c) 2002 peercast.org +// ------------------------------------------------ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// ------------------------------------------------ + + +//#include "stdafx.h" +#include +#include +#include +#include "win32/wsys.h" +#include "win32/wsocket.h" +#include "stats.h" +#include "peercast.h" +#include +#include +#include "shellapi.h" +#ifdef _DEBUG +#include "chkMemoryLeak.h" +#define DEBUG_NEW new(__FILE__, __LINE__) +#define new DEBUG_NEW +#endif + +// --------------------------------- +WSys::WSys(HWND w) +{ + stats.clear(); + + rndGen.setSeed(getTime()); + + mainWindow = w; + WSAClientSocket::init(); + + rndSeed = rnd(); +} +// --------------------------------- +double WSys::getDTime() +{ + struct _timeb timebuffer; + + _ftime( &timebuffer ); + + return (double)timebuffer.time+(((double)timebuffer.millitm)/1000); +} +// --------------------------------- +unsigned int WSys::getTime() +{ + time_t ltime; + time( <ime ); + return ltime; +} + +// --------------------------------- +ClientSocket *WSys::createSocket() +{ + return new WSAClientSocket(); +} +// --------------------------------- +void WSys::endThread(ThreadInfo *info) +{ +} +// --------------------------------- +void WSys::waitThread(ThreadInfo *info, int timeout) +{ + switch(WaitForSingleObject((void *)info->handle, timeout)) + { + case WAIT_TIMEOUT: + throw TimeoutException(); + break; + } +} + + +// --------------------------------- +bool WSys::startThread(ThreadInfo *info) +{ + info->active = true; + +/* typedef unsigned ( __stdcall *start_address )( void * ); + + unsigned int threadID; + info->handle = (unsigned int)_beginthreadex( NULL, 0, (start_address)info->func, info, 0, &threadID ); + + if(info->handle == 0) + return false;*/ + + typedef void (__cdecl *start_address)( void * ); + info->handle = _beginthread((start_address)info->func, 0,info); + + if(info->handle == -1) + return false; + + return true; + +} +// --------------------------------- +void WSys::sleep(int ms) +{ + Sleep(ms); +} + +// --------------------------------- +void WSys::appMsg(long msg, long arg) +{ + //SendMessage(mainWindow,WM_USER,(WPARAM)msg,(LPARAM)arg); +} + +// -------------------------------------------------- +void WSys::callLocalURL(const char *str,int port) +{ + char cmd[512]; + sprintf(cmd,"http://localhost:%d/%s",port,str); + ShellExecute(mainWindow, NULL, cmd, NULL, NULL, SW_SHOWNORMAL); +} + +// --------------------------------- +void WSys::getURL(const char *url) +{ + if (mainWindow) + if (strnicmp(url,"http://",7) || strnicmp(url,"mailto:",7)) + ShellExecute(mainWindow, NULL, url, NULL, NULL, SW_SHOWNORMAL); +} +// --------------------------------- +void WSys::exit() +{ + if (mainWindow) + PostMessage(mainWindow,WM_CLOSE,0,0); + else + ::exit(0); +} +// -------------------------------------------------- +void WSys::executeFile(const char *file) +{ + ShellExecute(NULL,"open",file,NULL,NULL,SW_SHOWNORMAL); +} diff --git a/c:/Git/PeerCast.root/PeerCast/core/win32/wsys.h b/c:/Git/PeerCast.root/PeerCast/core/win32/wsys.h new file mode 100644 index 0000000..95f479a --- /dev/null +++ b/c:/Git/PeerCast.root/PeerCast/core/win32/wsys.h @@ -0,0 +1,61 @@ +// ------------------------------------------------ +// File : wsys.h +// Date: 4-apr-2002 +// Author: giles +// Desc: +// WSys derives from Sys to provide basic win32 functions such as starting threads. +// +// (c) 2002 peercast.org +// ------------------------------------------------ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// ------------------------------------------------ + + + +#ifndef _WSYS_H +#define _WSYS_H +// ------------------------------------ +#include +#include "socket.h" +#include "sys.h" + +// ------------------------------------ +class WSys : public Sys +{ +public: + WSys(HWND); + + virtual ClientSocket *createSocket(); + virtual bool startThread(ThreadInfo *); + virtual void sleep(int ); + virtual void appMsg(long,long); + virtual unsigned int getTime(); + virtual double getDTime(); + virtual unsigned int rnd() {return rndGen.next();} + virtual void getURL(const char *); + virtual void exit(); + virtual bool hasGUI() {return mainWindow!=NULL;} + virtual void callLocalURL(const char *str,int port); + virtual void executeFile(const char *); + virtual void endThread(ThreadInfo *); + virtual void waitThread(ThreadInfo *, int timeout = 30000); + + + HWND mainWindow; + peercast::Random rndGen; +}; + + +// ------------------------------------ +#endif + + + \ No newline at end of file diff --git a/c:/Git/PeerCast.root/PeerCast/ui/win32/PeerCast.sln b/c:/Git/PeerCast.root/PeerCast/ui/win32/PeerCast.sln new file mode 100644 index 0000000..9768be1 --- /dev/null +++ b/c:/Git/PeerCast.root/PeerCast/ui/win32/PeerCast.sln @@ -0,0 +1,49 @@ + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "corelib", "..\..\core\win32\lib\corelib.vcproj", "{7BCFE65B-8757-45F3-8DFB-1E7D683950D1}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Simple", "simple\Simple.vcproj", "{7D4833CE-1286-4587-9470-52E098B29C12}" +EndProject +Global + GlobalSection(SourceCodeControl) = preSolution + SccNumberOfProjects = 3 + SccProjectName0 = \u0022$/PeerCast.root/PeerCast\u0022,\u0020JCAAAAAA + SccLocalPath0 = ..\\.. + SccProvider0 = MSSCCI:Microsoft\u0020Visual\u0020SourceSafe + SccProjectFilePathRelativizedFromConnection0 = ui\\win32\\ + SccProjectUniqueName1 = ..\\..\\core\\win32\\lib\\corelib.vcproj + SccLocalPath1 = ..\\.. + SccProjectFilePathRelativizedFromConnection1 = core\\win32\\lib\\ + SccProjectUniqueName2 = simple\\Simple.vcproj + SccLocalPath2 = ..\\.. + SccProjectFilePathRelativizedFromConnection2 = ui\\win32\\simple\\ + EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Private Debug|Win32 = Private Debug|Win32 + Private Release|Win32 = Private Release|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {7BCFE65B-8757-45F3-8DFB-1E7D683950D1}.Debug|Win32.ActiveCfg = Debug|Win32 + {7BCFE65B-8757-45F3-8DFB-1E7D683950D1}.Debug|Win32.Build.0 = Debug|Win32 + {7BCFE65B-8757-45F3-8DFB-1E7D683950D1}.Private Debug|Win32.ActiveCfg = Private Debug|Win32 + {7BCFE65B-8757-45F3-8DFB-1E7D683950D1}.Private Debug|Win32.Build.0 = Private Debug|Win32 + {7BCFE65B-8757-45F3-8DFB-1E7D683950D1}.Private Release|Win32.ActiveCfg = Private Release|Win32 + {7BCFE65B-8757-45F3-8DFB-1E7D683950D1}.Private Release|Win32.Build.0 = Private Release|Win32 + {7BCFE65B-8757-45F3-8DFB-1E7D683950D1}.Release|Win32.ActiveCfg = Release|Win32 + {7BCFE65B-8757-45F3-8DFB-1E7D683950D1}.Release|Win32.Build.0 = Release|Win32 + {7D4833CE-1286-4587-9470-52E098B29C12}.Debug|Win32.ActiveCfg = Debug|Win32 + {7D4833CE-1286-4587-9470-52E098B29C12}.Debug|Win32.Build.0 = Debug|Win32 + {7D4833CE-1286-4587-9470-52E098B29C12}.Private Debug|Win32.ActiveCfg = Private Debug|Win32 + {7D4833CE-1286-4587-9470-52E098B29C12}.Private Debug|Win32.Build.0 = Private Debug|Win32 + {7D4833CE-1286-4587-9470-52E098B29C12}.Private Release|Win32.ActiveCfg = Private Release|Win32 + {7D4833CE-1286-4587-9470-52E098B29C12}.Private Release|Win32.Build.0 = Private Release|Win32 + {7D4833CE-1286-4587-9470-52E098B29C12}.Release|Win32.ActiveCfg = Release|Win32 + {7D4833CE-1286-4587-9470-52E098B29C12}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/c:/Git/PeerCast.root/PeerCast/ui/win32/PeerCast.vsscc b/c:/Git/PeerCast.root/PeerCast/ui/win32/PeerCast.vsscc new file mode 100644 index 0000000000000000000000000000000000000000..51e2532bd4dcd18ab95de08486939f4f14bc5f60 GIT binary patch literal 26 gcmezW&x;|Ep_0LXp_Cz$A%>wGNaisZGZ--d0BiULKL7v# literal 0 HcmV?d00001 diff --git a/c:/Git/PeerCast.root/PeerCast/ui/win32/PeerCast.vssscc b/c:/Git/PeerCast.root/PeerCast/ui/win32/PeerCast.vssscc new file mode 100644 index 0000000..e957f02 --- /dev/null +++ b/c:/Git/PeerCast.root/PeerCast/ui/win32/PeerCast.vssscc @@ -0,0 +1,10 @@ +"" +{ +"FILE_VERSION" = "9237" +"ENLISTMENT_CHOICE" = "NEVER" +"PROJECT_FILE_RELATIVE_PATH" = "relative:ui\\win32" +"NUMBER_OF_EXCLUDED_FILES" = "0" +"ORIGINAL_PROJECT_FILE_PATH" = "" +"NUMBER_OF_NESTED_PROJECTS" = "0" +"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROJECT" +} diff --git a/c:/Git/PeerCast.root/PeerCast/ui/win32/simple/SMALL.ICO b/c:/Git/PeerCast.root/PeerCast/ui/win32/simple/SMALL.ICO new file mode 100644 index 0000000000000000000000000000000000000000..c7dee299bec9d38ea44c45432b48fd10214e226c GIT binary patch literal 318 zcmZvYF%H5o3`Kt>Br|qmX5@I;!bUd6UMbw95*I*XXpvCObJ}h=dH*|(6Gf3aM&I{} zxOCDf9HMfDP6t$~P5()em?~v8loX0;t!#Lka*qrcQ3{bPgh;8`zO*&5gd*>1DL6F1z|v;;aqRdUw9l6_GaIu9mVEp76a%Gaif|-c9RHB_Cmi1)Tr! J2Rz{|{Q%s#L@@vW literal 0 HcmV?d00001 diff --git a/c:/Git/PeerCast.root/PeerCast/ui/win32/simple/Simple.ICO b/c:/Git/PeerCast.root/PeerCast/ui/win32/simple/Simple.ICO new file mode 100644 index 0000000000000000000000000000000000000000..51811ea4819dbdb4726fbb0f5f4347425ca2a566 GIT binary patch literal 1078 zcma)6v2KGv41F|}%+&G+WvcQQ?I*Eaww%-}Ol7KSw$g}-y zpYJeMfDBJ4%L2B3o`84iqDXw30WTY1OJ7NR5*eN;fyms)D>BGPj7d?_BqG|jWkCH0 zRkH{_<}%?+!emUULbY@(xj+`-HLq6jb-61~$6mL)KZLYhs1f+s3L)(310e1N^180| z#`A{nqD-CQPKVu+_r_sW;qksUE-UU=_xNG3xZNS;hl#U9?#G={oYEa3Vs4XEtia=D z&N_|SK?Yxv8^3E~RWG^N#qQ#6U$c#M?IvU=1!iUXyL6pQi=Pm8WD^8c- zd^5phG#AA`=6vo(mAW=lNrqI^6am5swC?jGyKZz~tl}5!Pc|<}Lw4Fn+bd0Yi1o;Ujh literal 0 HcmV?d00001 diff --git a/c:/Git/PeerCast.root/PeerCast/ui/win32/simple/Simple.cpp b/c:/Git/PeerCast.root/PeerCast/ui/win32/simple/Simple.cpp new file mode 100644 index 0000000..928ceee --- /dev/null +++ b/c:/Git/PeerCast.root/PeerCast/ui/win32/simple/Simple.cpp @@ -0,0 +1,1437 @@ +// ------------------------------------------------ +// File : simple.cpp +// Date: 4-apr-2002 +// Author: giles +// Desc: +// Simple tray icon interface to PeerCast, mostly win32 related stuff. +// +// (c) 2002 peercast.org +// ------------------------------------------------ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// ------------------------------------------------ + +#include +#include +#include "stdafx.h" +#include "resource.h" +#include "gui.h" +#include "channel.h" +#include "servent.h" +#include "servmgr.h" +#include "win32/wsys.h" +#include "peercast.h" +#include "simple.h" +#include "version2.h" +#include "gdiplus.h" +#include "time.h" +#ifdef _DEBUG +#include "chkMemoryLeak.h" +#define DEBUG_NEW new(__FILE__, __LINE__) +#define new DEBUG_NEW +#endif + +#define MAX_LOADSTRING 100 + +#define PLAY_CMD 7000 +#define RELAY_CMD 8000 +#define INFO_CMD 9000 +#define URL_CMD 10000 + +#define MAX_CHANNELS 999 + + +extern "C" +{ + void loadIcons(HINSTANCE hInstance, HWND hWnd); +}; + +UINT g_iTaskbarCreated = ~0; // for PCRaw (tray icon) + +// PeerCast globals + +static int currNotify=0; +String iniFileName; +HWND guiWnd; +HWND mainWnd; +static HMENU trayMenu = NULL,ltrayMenu = NULL; // for PCRaw (tray icon) +bool showGUI=true; +bool allowMulti=false; +bool killMe=false; +bool allowTrayMenu=true; +static bool winDistinctionNT=false; +int seenNewVersionTime=0; +HICON icon1,icon2; +ChanInfo chanInfo; +bool chanInfoIsRelayed; +//GnuID lastPlayID; +String exePath; +ULONG_PTR gdiplusToken; + +// --------------------------------- +Sys * APICALL MyPeercastInst::createSys() +{ + return new WSys(mainWnd); +} +// --------------------------------- +const char * APICALL MyPeercastApp ::getIniFilename() +{ + return iniFileName.cstr(); +} + +// --------------------------------- +const char *APICALL MyPeercastApp ::getClientTypeOS() +{ + return PCX_OS_WIN32; +} + +// --------------------------------- +const char * APICALL MyPeercastApp::getPath() +{ + return exePath.cstr(); +} + +// --------------------------------- JP-EX +void APICALL MyPeercastApp ::openLogFile() +{ + logFile.openWriteReplace("log.txt"); +} +// --------------------------------- JP-EX +void APICALL MyPeercastApp ::getDirectory() +{ + char path_buffer[256],drive[32],dir[128]; + GetModuleFileName(NULL,path_buffer,255); + _splitpath(path_buffer,drive,dir,NULL,NULL); + sprintf(servMgr->modulePath,"%s%s",drive,dir); +} +// --------------------------------- JP-EX +bool APICALL MyPeercastApp ::clearTemp() +{ + if (servMgr->clearPLS) + return true; + + return false; +} + + +class NOTIFYICONDATA2 +{ +public: + DWORD cbSize; // DWORD + HWND hWnd; // HWND + UINT uID; // UINT + UINT uFlags; // UINT + UINT uCallbackMessage; // UINT + HICON hIcon; // HICON + char szTip[128]; // char[128] + DWORD dwState; // DWORD + DWORD dwStateMask; // DWORD + char szInfo[256]; // char[256] + UINT uTimeoutOrVersion; // UINT + char szInfoTitle[64]; // char[64] + DWORD dwInfoFlags; // DWORD + //GUID guidItem; > IE 6 +}; + +NOTIFYICONDATA2 trayIcon; + + +// Global Variables: +HINSTANCE hInst; // current instance +TCHAR szTitle[MAX_LOADSTRING]; // The title bar text +TCHAR szWindowClass[MAX_LOADSTRING]; // The title bar text +TCHAR szWindowClass2[MAX_LOADSTRING]; // The title bar text +TCHAR szWindowClass3[MAX_LOADSTRING]; // The title bar text + +// Foward declarations of functions included in this code module: +ATOM MyRegisterClass(HINSTANCE hInstance); +ATOM MyRegisterClass2(HINSTANCE hInstance); +ATOM MyRegisterClass3(HINSTANCE hInstance); +BOOL InitInstance(HINSTANCE, int); +LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); +LRESULT CALLBACK About(HWND, UINT, WPARAM, LPARAM); +LRESULT CALLBACK ChanInfoProc(HWND, UINT, WPARAM, LPARAM); + +void setTrayIcon(int type, const char *,const char *,bool); +void flipNotifyPopup(int id, ServMgr::NOTIFY_TYPE nt); + + +HWND chWnd=NULL; + +bool gbGetFile = FALSE; +bool gbStart = FALSE; +time_t gtGetFile; +time_t gtStartTime; +// -------------------------------------------------- +void LOG2(const char *fmt,...) +{ + va_list ap; + va_start(ap, fmt); + char str[4096]; + vsprintf(str,fmt,ap); + OutputDebugString(str); + va_end(ap); +} + + + +// --------------------------------------- +int APIENTRY WinMain(HINSTANCE hInstance, + HINSTANCE hPrevInstance, + LPSTR lpCmdLine, + int nCmdShow) +{ +#ifdef _DEBUG + // memory leak check + ::_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF); +#endif + + char tmpURL[8192]; + tmpURL[0]=0; + char *chanURL=NULL; + + hInst = hInstance; + + iniFileName.set(".\\peercast.ini"); + + WIN32_FIND_DATA fd; //JP-EX + HANDLE hFind; //JP-EX + + OSVERSIONINFO osInfo; //JP-EX + osInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); //JP-EX + GetVersionEx(&osInfo); + if (osInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) + winDistinctionNT = true; + else + winDistinctionNT = false; + + // off by default now + showGUI = false; + + if (strlen(lpCmdLine) > 0) + { + char *p; + if ((p = strstr(lpCmdLine,"-inifile"))!=NULL) + iniFileName.setFromString(p+8); + + if (strstr(lpCmdLine,"-zen")) + showGUI = false; + + if (strstr(lpCmdLine,"-multi")) + allowMulti = true; + + if (strstr(lpCmdLine,"-kill")) + killMe = true; + + if ((p = strstr(lpCmdLine,"-url"))!=NULL) + { + p+=4; + while (*p) + { + if (*p=='"') + { + p++; + break; + } + if (*p != ' ') + break; + p++; + } + if (*p) + strncpy(tmpURL,p,sizeof(tmpURL)-1); + } + } + + // get current path + { + exePath = iniFileName; + char *s = exePath.cstr(); + char *end = NULL; + while (*s) + { + if (*s++ == '\\') + end = s; + } + if (end) + *end = 0; + } + + + if (strnicmp(tmpURL,"peercast://",11)==0) + { + if (strnicmp(tmpURL+11,"pls/",4)==0) + chanURL = tmpURL+11+4; + else + chanURL = tmpURL+11; + showGUI = false; + } + + + MSG msg; + HACCEL hAccelTable; + + // Initialize global strings + //LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING); + //LoadString(hInstance, IDC_APP_TITLE, szWindowClass, MAX_LOADSTRING); + + strcpy(szTitle,"PeerCast"); + strcpy(szWindowClass,"PeerCast"); + strcpy(szWindowClass2,"Main"); + strcpy(szWindowClass3,"Start"); + + + + if (!allowMulti) + { + HANDLE mutex = CreateMutex(NULL,TRUE,szWindowClass); + + if (GetLastError() == ERROR_ALREADY_EXISTS) + { + HWND oldWin = FindWindow(szWindowClass,NULL); + if (oldWin) + { + SendMessage(oldWin,WM_SHOWGUI,0,0); + if (killMe) + { + SendMessage(oldWin,WM_DESTROY,0,0); + return 0; + } + + if (chanURL) + { + COPYDATASTRUCT copy; + copy.dwData = WM_PLAYCHANNEL; + copy.cbData = strlen(chanURL)+1; // plus null term + copy.lpData = chanURL; + SendMessage(oldWin,WM_COPYDATA,NULL,(LPARAM)©); + }else{ + if (showGUI) + SendMessage(oldWin,WM_SHOWGUI,0,0); + } + } + return 0; + } + } + + if (killMe) + return 0; + + MyRegisterClass(hInstance); + MyRegisterClass2(hInstance); + MyRegisterClass3(hInstance); + + // Perform application initialization: + if (!InitInstance (hInstance, nCmdShow)) + return FALSE; + + peercastInst = new MyPeercastInst(); + peercastApp = new MyPeercastApp(); + + peercastInst->init(); + + LOG_DEBUG("Set OS Type: %s",winDistinctionNT?"WinNT":"Win9x"); + + if (peercastApp->clearTemp()) //JP-EX + { + DeleteFile("play.pls"); + hFind = FindFirstFile("*.asx",&fd); + if (hFind != INVALID_HANDLE_VALUE) + { + do + { + DeleteFile((char *)&fd.cFileName); + } + while (FindNextFile(hFind,&fd)); + + FindClose(hFind); + } + } + + if (chanURL) + { + ChanInfo info; + servMgr->procConnectArgs(chanURL,info); + chanMgr->findAndPlayChannel(info,false); + } + + struct tm t; + memset(&t,0,sizeof(t)); + t.tm_year = 2007 - 1900; + t.tm_mon = 4 - 1; + t.tm_mday = 7; + t.tm_hour = 21; + t.tm_min = 0; + t.tm_sec = 0; + gtStartTime = ::mktime(&t); + t.tm_hour = 20; + t.tm_min = 50; + gtGetFile = ::mktime(&t); + + if (gtStartTime > sys->getTime()){ + gbGetFile = TRUE; + gbStart = TRUE; + } + + hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_SIMPLE); + + // setup menu notifes + int mask = peercastInst->getNotifyMask(); + if (mask & ServMgr::NT_PEERCAST) + CheckMenuItem(trayMenu,ID_POPUP_SHOWMESSAGES_PEERCAST,MF_CHECKED|MF_BYCOMMAND); + if (mask & ServMgr::NT_BROADCASTERS) + CheckMenuItem(trayMenu,ID_POPUP_SHOWMESSAGES_BROADCASTERS,MF_CHECKED|MF_BYCOMMAND); + if (mask & ServMgr::NT_TRACKINFO) + CheckMenuItem(trayMenu,ID_POPUP_SHOWMESSAGES_TRACKINFO,MF_CHECKED|MF_BYCOMMAND); + + // Main message loop: + while (GetMessage(&msg, NULL, 0, 0)) + { + if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } + + Shell_NotifyIcon(NIM_DELETE, (NOTIFYICONDATA*)&trayIcon); + + peercastInst->saveSettings(); + peercastInst->quit(); + + Gdiplus::GdiplusShutdown(gdiplusToken); + + return msg.wParam; +} + + + +// +// FUNCTION: MyRegisterClass() +// +// PURPOSE: Registers the window class. +// +// COMMENTS: +// +// This function and its usage is only necessary if you want this code +// to be compatible with Win32 systems prior to the 'RegisterClassEx' +// function that was added to Windows 95. It is important to call this function +// so that the application will get 'well formed' small icons associated +// with it. +// +ATOM MyRegisterClass(HINSTANCE hInstance) +{ + WNDCLASSEX wcex; + + wcex.cbSize = sizeof(WNDCLASSEX); + + wcex.style = CS_HREDRAW | CS_VREDRAW; + wcex.lpfnWndProc = (WNDPROC)WndProc; + wcex.cbClsExtra = 0; + wcex.cbWndExtra = 0; + wcex.hInstance = hInstance; + wcex.hIcon = LoadIcon(hInstance, (LPCTSTR)IDI_SIMPLE); + wcex.hCursor = LoadCursor(NULL, IDC_ARROW); + wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); +// wcex.lpszMenuName = (LPCSTR)IDC_SIMPLE; + wcex.lpszMenuName = NULL; + wcex.lpszClassName = szWindowClass; + wcex.hIconSm = LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL); + + return RegisterClassEx(&wcex); +} + +ATOM MyRegisterClass2(HINSTANCE hInstance) +{ + WNDCLASSEX wcex; + + wcex.cbSize = sizeof(WNDCLASSEX); + + wcex.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS ; + wcex.lpfnWndProc = (WNDPROC)GUIProc; + wcex.cbClsExtra = 0; + wcex.cbWndExtra = 0; + wcex.hInstance = hInstance; + wcex.hIcon = LoadIcon(hInstance, (LPCTSTR)IDI_SIMPLE); + wcex.hCursor = LoadCursor(NULL, IDC_ARROW); + wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); +// wcex.lpszMenuName = (LPCSTR)IDC_SIMPLE; + wcex.lpszMenuName = NULL; + wcex.lpszClassName = szWindowClass2; + wcex.hIconSm = LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL); + + return RegisterClassEx(&wcex); +} + +ATOM MyRegisterClass3(HINSTANCE hInstance) +{ + WNDCLASSEX wcex; + + wcex.cbSize = sizeof(WNDCLASSEX); + + wcex.style = CS_HREDRAW | CS_VREDRAW; + wcex.lpfnWndProc = (WNDPROC)StartProc; + wcex.cbClsExtra = 0; + wcex.cbWndExtra = 0; + wcex.hInstance = hInstance; + wcex.hIcon = LoadIcon(hInstance, (LPCTSTR)IDI_SIMPLE); + wcex.hCursor = LoadCursor(NULL, IDC_ARROW); + wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); +// wcex.lpszMenuName = (LPCSTR)IDC_SIMPLE; + wcex.lpszMenuName = NULL; + wcex.lpszClassName = szWindowClass3; + wcex.hIconSm = LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL); + + return RegisterClassEx(&wcex); +} + +//----------------------------- +void loadIcons(HINSTANCE hInstance, HWND hWnd) +{ + icon1 = LoadIcon(hInstance, (LPCTSTR)IDI_SMALL); + icon2 = LoadIcon(hInstance, (LPCTSTR)IDI_SMALL2); + + trayIcon.cbSize = sizeof(trayIcon); + trayIcon.hWnd = hWnd; + trayIcon.uID = 100; + trayIcon.uFlags = NIF_MESSAGE + NIF_ICON + NIF_TIP; + trayIcon.uCallbackMessage = WM_TRAYICON; + trayIcon.hIcon = icon1; + strcpy(trayIcon.szTip, "PeerCast"); + + Shell_NotifyIcon(NIM_ADD, (NOTIFYICONDATA*)&trayIcon); + + //ShowWindow(hWnd, nCmdShow); + UpdateWindow(hWnd); + + if(!trayMenu) // for PCRaw (tray icon) + trayMenu = LoadMenu(hInstance,MAKEINTRESOURCE(IDR_TRAYMENU)); + if(!ltrayMenu) // for PCRaw (tray icon) + ltrayMenu = LoadMenu(hInstance,MAKEINTRESOURCE(IDR_LTRAYMENU)); + + +} + +//----------------------------- +// +// FUNCTION: InitInstance(HANDLE, int) +// +// PURPOSE: Saves instance handle and creates main window +// +// COMMENTS: +// +// In this function, we save the instance handle in a global variable and +// create and display the main program window. +// +BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) +{ + HWND hWnd; + + hInst = hInstance; // Store instance handle in our global variable + + hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL); + + if (!hWnd) + { + return FALSE; + } + + mainWnd = hWnd; + + g_iTaskbarCreated = RegisterWindowMessage("TaskbarCreated"); // for PCRaw (tray icon) + + loadIcons(hInstance,hWnd); + + using namespace Gdiplus; + GdiplusStartupInput gdiplusStartupInput; + GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL); + + return TRUE; +} +//----------------------------- +//static String trackTitle; +//static String channelComment; + +//----------------------------- +void channelPopup(const char *title, const char *msg, bool isPopup = true) +{ + String both; + + if (*title == '\0') return; + both.append(msg); + both.append(" ("); + both.append(title); + both.append(")"); + + trayIcon.uFlags = NIF_ICON|NIF_TIP; + strncpy(trayIcon.szTip, both.cstr(),sizeof(trayIcon.szTip)-1); + trayIcon.szTip[sizeof(trayIcon.szTip)-1]=0; + + if (isPopup) trayIcon.uFlags |= 16; + trayIcon.uTimeoutOrVersion = 10000; + strncpy(trayIcon.szInfo,msg,sizeof(trayIcon.szInfo)-1); + strncpy(trayIcon.szInfoTitle,title,sizeof(trayIcon.szInfoTitle)-1); + + Shell_NotifyIcon(NIM_MODIFY, (NOTIFYICONDATA*)&trayIcon); +} +//----------------------------- +void clearChannelPopup() +{ + trayIcon.uFlags = NIF_ICON|16; + trayIcon.uTimeoutOrVersion = 10000; + strncpy(trayIcon.szInfo,"",sizeof(trayIcon.szInfo)-1); + strncpy(trayIcon.szInfoTitle,"",sizeof(trayIcon.szInfoTitle)-1); + Shell_NotifyIcon(NIM_MODIFY, (NOTIFYICONDATA*)&trayIcon); +} + +//----------------------------- +// PopupEntry +struct PopupEntry { + GnuID id; + String name; + String track; + String comment; + PopupEntry *next; +}; +static PopupEntry *PEList = NULL; +static WLock PELock; + +static void putPopupEntry(PopupEntry *pe) +{ + PELock.on(); + pe->next = PEList; + PEList = pe; + PELock.off(); +} + +static PopupEntry *getPopupEntry(GnuID id) +{ + PELock.on(); + PopupEntry *pe = PEList; + PopupEntry *prev = NULL; + while (pe) { + if (id.isSame(pe->id)) { + if (prev) prev->next = pe->next; + else PEList = pe->next; + PELock.off(); + pe->next = NULL; + return pe; + } + prev = pe; + pe = pe->next; + } + PELock.off(); + return NULL; +} + +static PopupEntry *getTopPopupEntry() +{ + PopupEntry *p = NULL; + PELock.on(); + if (PEList) { + p = PEList; + PEList = PEList->next; + } + PELock.off(); + return p; +} + +//----------------------------- +void APICALL MyPeercastApp::channelStart(ChanInfo *info) +{ + +// lastPlayID = info->id; +// +// if(!isIndexTxt(info)) // for PCRaw (popup) +// clearChannelPopup(); + + PopupEntry *pe = getPopupEntry(info->id); + if (!pe) { + pe = new PopupEntry; + pe->id = info->id; + } + if (!isIndexTxt(info)) + putPopupEntry(pe); + else + delete pe; +} +//----------------------------- +void APICALL MyPeercastApp::channelStop(ChanInfo *info) +{ +// if (info->id.isSame(lastPlayID)) +// { +// lastPlayID.clear(); +// +// if(!isIndexTxt(info)) // for PCRaw (popup) +// clearChannelPopup(); +// } + + PopupEntry *pe = getPopupEntry(info->id); + if (pe) delete pe; + + pe = getTopPopupEntry(); + if (!pe) { + clearChannelPopup(); + } else { + if (ServMgr::NT_TRACKINFO & peercastInst->getNotifyMask()) + { + String name,track; //JP-Patch + name = pe->name; //JP-Patch + track = pe->track; //JP-Patch + name.convertTo(String::T_SJIS); //JP-Patch + track.convertTo(String::T_SJIS); //JP-Patch + clearChannelPopup(); + // channelPopup(info->name.cstr(),trackTitle.cstr()); + channelPopup(name.cstr(),track.cstr(), false); //JP-Patch + } + putPopupEntry(pe); + } +} +//----------------------------- +void APICALL MyPeercastApp::channelUpdate(ChanInfo *info) +{ + if (info) + { + PopupEntry *pe = getPopupEntry(info->id); + if (!pe) return; + + String tmp; + tmp.append(info->track.artist); + tmp.append(" "); + tmp.append(info->track.title); + + + if (!tmp.isSame(pe->track)) + { + pe->name = info->name; + pe->track = tmp; + if (ServMgr::NT_TRACKINFO & peercastInst->getNotifyMask()) + { + //trackTitle=tmp; + String name,track; //JP-Patch + name = info->name; //JP-Patch + track = tmp; //JP-Patch + name.convertTo(String::T_SJIS); //JP-Patch + track.convertTo(String::T_SJIS); //JP-Patch + if(!isIndexTxt(info)) // for PCRaw (popup) + { + clearChannelPopup(); + // channelPopup(info->name.cstr(),trackTitle.cstr()); + channelPopup(name.cstr(),track.cstr()); //JP-Patch + } + } + } else if (!info->comment.isSame(pe->comment)) + { + pe->name = info->name; + pe->comment = info->comment; + if (ServMgr::NT_BROADCASTERS & peercastInst->getNotifyMask()) + { + //channelComment = info->comment; + String name,comment; //JP-Patch + name = info->name; //JP-Patch + comment = info->comment; //JP-Patch + name.convertTo(String::T_SJIS); //JP-Patch + comment.convertTo(String::T_SJIS); //JP-Patch + if(!isIndexTxt(info)) // for PCRaw (popup) + { + clearChannelPopup(); + // channelPopup(info->name.cstr(),channelComment.cstr()); + channelPopup(name.cstr(),comment.cstr()); + } + } + } + + if (!isIndexTxt(info)) + putPopupEntry(pe); + else + delete pe; + } +} +//----------------------------- +void APICALL MyPeercastApp::notifyMessage(ServMgr::NOTIFY_TYPE type, const char *msg) +{ + currNotify = type; + + if (type == ServMgr::NT_UPGRADE) + { + trayIcon.uFlags = NIF_ICON; + trayIcon.hIcon = icon2; + }else{ + trayIcon.uFlags = NIF_ICON; + trayIcon.hIcon = icon1; + } + + const char *title=""; + + switch(type) + { + case ServMgr::NT_UPGRADE: + title = "Upgrade alert"; + break; + case ServMgr::NT_PEERCAST: + title = "Message from PeerCast:"; + break; + + } + + if (type & peercastInst->getNotifyMask()) + { + trayIcon.uFlags |= 16; + trayIcon.uTimeoutOrVersion = 10000; + strncpy(trayIcon.szInfo,msg,sizeof(trayIcon.szInfo)-1); + strncpy(trayIcon.szInfoTitle,title,sizeof(trayIcon.szInfoTitle)-1); + Shell_NotifyIcon(NIM_MODIFY, (NOTIFYICONDATA*)&trayIcon); + } +} +//----------------------------- + +// createGUI() +// +void createGUI(HWND hWnd) +{ + if (!guiWnd){ + guiWnd = ::CreateWindow(szWindowClass2, + "Peercast-IM@S", + WS_OVERLAPPEDWINDOW & ~(WS_MAXIMIZEBOX) /*| WS_VSCROLL | WS_HSCROLL*/, + 0, + 0, + 800, + 600, + NULL, + NULL, + hInst, + NULL); + } + ShowWindow(guiWnd,SW_SHOWNORMAL); +} + + +// +// addRelayedChannelsMenu(HMENU m) +// +// +void addRelayedChannelsMenu(HMENU cm) +{ + int cnt = GetMenuItemCount(cm); + for(int i=0; ichannel; + while(c) + { + if (c->isActive()) + { + char str[128],name[64]; + strncpy(name,c->info.name,32); + name[32]=0; + if (strlen(c->info.name) > 32) + strcat(name,"..."); + + + sprintf(str,"%s (%d kb/s %s)",name,c->info.bitrate,ChanInfo::getTypeStr(c->info.contentType)); + //InsertMenu(cm,0,MF_BYPOSITION,RELAY_CMD+i,str); + } + c=c->next; + } +} + +typedef int (*COMPARE_FUNC)(const void *,const void *); + +static int compareHitLists(ChanHitList **c2, ChanHitList **c1) +{ + return stricmp(c1[0]->info.name.cstr(),c2[0]->info.name.cstr()); +} + +static int compareChannels(Channel **c2, Channel **c1) +{ + return stricmp(c1[0]->info.name.cstr(),c2[0]->info.name.cstr()); +} + +// +// addAllChannelsMenu(HMENU m) +// +// +void addAllChannelsMenu(HMENU cm) +{ + int cnt = GetMenuItemCount(cm); +/* for(int i=0; irootHost2.isEmpty()){ + InsertMenu(yMenu,0,MF_BYPOSITION,ID_POPUP_YELLOWPAGES2,servMgr->rootHost2); + } + if (!servMgr->rootHost.isEmpty()){ + InsertMenu(yMenu,0,MF_BYPOSITION,ID_POPUP_YELLOWPAGES1,servMgr->rootHost); + } + + InsertMenu(cm,0,MF_BYPOSITION|MF_POPUP,(UINT)yMenu,"ƒCƒGƒ[ƒy[ƒW"); + InsertMenu(cm,0,MF_BYPOSITION|MF_SEPARATOR,NULL,NULL); + // add channels to menu + int numActive=0; + Channel *ch = chanMgr->channel; + while(ch) + { + char str[128],name[64]; + String sjis; //JP-Patch + sjis = ch->info.name; //JP-Patch + sjis.convertTo(String::T_SJIS); //JP-Patch + strncpy(name,sjis.cstr(),32); + //strncpy(name,ch->info.name,32); + name[32]=0; + //if (strlen(ch->info.name) > 32) + if (strlen(sjis.cstr()) > 32) //JP-Patch + strcat(name,"..."); + + sprintf(str,"%s (%d kb/s %s)",name,ch->info.bitrate,ChanInfo::getTypeStr(ch->info.contentType)); + + HMENU opMenu = CreatePopupMenu(); + InsertMenu(opMenu,0,MF_BYPOSITION,INFO_CMD+numActive,"Info"); + if (ch->info.url.isValidURL()) + InsertMenu(opMenu,0,MF_BYPOSITION,URL_CMD+numActive,"URL"); + InsertMenu(opMenu,0,MF_BYPOSITION,PLAY_CMD+numActive,"Play"); + + UINT fl = MF_BYPOSITION|MF_POPUP; + if (ch) + fl |= (ch->isPlaying()?MF_CHECKED:0); + + InsertMenu(cm,0,fl,(UINT)opMenu,str); + + numActive++; + + ch=ch->next; + } + + + //if (!numActive) + // InsertMenu(cm,0,MF_BYPOSITION,0,""); + + + + +} + + +// +// flipNotifyPopup(id, flag) +void flipNotifyPopup(int id, ServMgr::NOTIFY_TYPE nt) +{ + int mask = peercastInst->getNotifyMask(); + + mask ^= nt; + if (mask & nt) + CheckMenuItem(trayMenu,id,MF_CHECKED|MF_BYCOMMAND); + else + CheckMenuItem(trayMenu,id,MF_UNCHECKED|MF_BYCOMMAND); + + peercastInst->setNotifyMask(mask); + peercastInst->saveSettings(); +} + + +static void showHTML(const char *file) +{ + char url[256]; + sprintf(url,"%s/%s",servMgr->htmlPath,file); + +// sys->callLocalURL(url,servMgr->serverHost.port); + sys->callLocalURL(url, // for PCRaw (url) + (servMgr->allowServer1&Servent::ALLOW_HTML)?(servMgr->serverHost.port):(servMgr->serverHost.port+1)); +} + +static ChanInfo getChannelInfo(int index) +{ + Channel *c = chanMgr->findChannelByIndex(index); + if (c) + return c->info; + + ChanInfo info; + return info; +} + +// +// FUNCTION: WndProc(HWND, unsigned, WORD, LONG) +// +// PURPOSE: Processes messages for the main window. +// +// WM_COMMAND - process the application menu +// WM_PAINT - Paint the main window +// WM_DESTROY - post a quit message and return +// +// +LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + int wmId, wmEvent; + POINT point; + char buf[1024]; + + if(message == g_iTaskbarCreated) // for PCRaw (tray icon) + loadIcons(hInst, hWnd); + + switch (message) + { + case WM_SHOWGUI: + createGUI(hWnd); + break; + + + case WM_TRAYICON: + switch((UINT)lParam) + { + case WM_LBUTTONDOWN: + if (allowTrayMenu) + SendMessage(hWnd,WM_SHOWMENU,2,0); + SetForegroundWindow(hWnd); + break; + case WM_RBUTTONDOWN: + if (allowTrayMenu) + SendMessage(hWnd,WM_SHOWMENU,1,0); + SetForegroundWindow(hWnd); + break; + case WM_LBUTTONDBLCLK: + createGUI(hWnd); + break; + } + break; + + case WM_COPYDATA: + { + COPYDATASTRUCT *pc = (COPYDATASTRUCT *)lParam; + LOG_DEBUG("URL request: %s",pc->lpData); + if (pc->dwData == WM_PLAYCHANNEL) + { + ChanInfo info; + servMgr->procConnectArgs((char *)pc->lpData,info); + chanMgr->findAndPlayChannel(info,false); + } + //sys->callLocalURL((const char *)pc->lpData,servMgr->serverHost.port); + } + break; + case WM_GETPORTNUMBER: + { + int port; + port=servMgr->serverHost.port; + ReplyMessage(port); + } + break; + + case WM_SHOWMENU: + { + if (servMgr->saveGuiPos){ + CheckMenuItem(trayMenu, ID_POPUP_SAVE_GUI_POS, MF_CHECKED|MF_BYCOMMAND); + } else { + CheckMenuItem(trayMenu, ID_POPUP_SAVE_GUI_POS, MF_UNCHECKED|MF_BYCOMMAND); + } + + SetForegroundWindow(hWnd); + bool skipMenu=false; + + allowTrayMenu = false; + + // check for notifications + if (currNotify & ServMgr::NT_UPGRADE) + { + if (servMgr->downloadURL[0]) + { + if ((sys->getTime()-seenNewVersionTime) > (60*60)) // notify every hour + { + if (MessageBox(hWnd,"A newer version of PeerCast is available, press OK to upgrade.","PeerCast",MB_OKCANCEL|MB_APPLMODAL|MB_ICONEXCLAMATION) == IDOK) + sys->getURL(servMgr->downloadURL); + + seenNewVersionTime=sys->getTime(); + skipMenu=true; + } + } + } + + + if (!skipMenu) + { + RECT rcWnd; + HMENU menu; + UINT flg = 0; + + SystemParametersInfo(SPI_GETWORKAREA, 0, &rcWnd, 0); + GetCursorPos(&point); + + if (point.x < rcWnd.left){ + point.x = rcWnd.left; + flg |= TPM_LEFTALIGN; + } + if (point.x > rcWnd.right){ + point.x = rcWnd.right; + flg |= TPM_RIGHTALIGN; + } + if (point.y < rcWnd.top){ + point.y = rcWnd.top; + flg |= TPM_TOPALIGN; + } + if (point.y > rcWnd.bottom){ + point.y = rcWnd.bottom; + flg |= TPM_BOTTOMALIGN; + } + if (flg == 0){ + flg = TPM_RIGHTALIGN; + } + + switch (wParam) + { + case 1: + menu = GetSubMenu(trayMenu,0); + addAllChannelsMenu(GetSubMenu(menu,0)); + addRelayedChannelsMenu(GetSubMenu(menu,1)); + break; + case 2: + menu = GetSubMenu(ltrayMenu,0); + addAllChannelsMenu(menu); + break; + } + if (!TrackPopupMenu(menu,flg,point.x,point.y,0,hWnd,NULL)) + { + LOG_ERROR("Can`t track popup menu: %d",GetLastError()); + } + PostMessage(hWnd,WM_NULL,0,0); + + } + allowTrayMenu = true; + } + break; + + case WM_CREATE: + if (showGUI) + createGUI(hWnd); + break; + + case WM_COMMAND: + wmId = LOWORD(wParam); + wmEvent = HIWORD(wParam); + + if ((wmId >= INFO_CMD) && (wmId < INFO_CMD+MAX_CHANNELS)) + { + int c = wmId - INFO_CMD; + chanInfo = getChannelInfo(c); + chanInfoIsRelayed = false; + if (winDistinctionNT) + DialogBox(hInst, (LPCTSTR)IDD_CHANINFO, hWnd, (DLGPROC)ChanInfoProc); + else + { + HWND WKDLG; //JP-Patch + WKDLG = CreateDialog(hInst, (LPCTSTR)IDD_CHANINFO, hWnd, (DLGPROC)ChanInfoProc); //JP-Patch + ShowWindow(WKDLG,SW_SHOWNORMAL); //JP-Patch + } + return 0; + } + if ((wmId >= URL_CMD) && (wmId < URL_CMD+MAX_CHANNELS)) + { + int c = wmId - URL_CMD; + chanInfo = getChannelInfo(c); + if (chanInfo.url.isValidURL()) + sys->getURL(chanInfo.url); + return 0; + } + if ((wmId >= PLAY_CMD) && (wmId < PLAY_CMD+MAX_CHANNELS)) + { + int c = wmId - PLAY_CMD; + chanInfo = getChannelInfo(c); + chanMgr->findAndPlayChannel(chanInfo,false); + return 0; + } + if ((wmId >= RELAY_CMD) && (wmId < RELAY_CMD+MAX_CHANNELS)) + { + int c = wmId - RELAY_CMD; + chanInfo = getChannelInfo(c); + chanMgr->findAndPlayChannel(chanInfo,true); + return 0; + } + + // Parse the menu selections: + switch (wmId) + { + case ID_POPUP_SHOWMESSAGES_PEERCAST: + flipNotifyPopup(ID_POPUP_SHOWMESSAGES_PEERCAST,ServMgr::NT_PEERCAST); + break; + case ID_POPUP_SHOWMESSAGES_BROADCASTERS: + flipNotifyPopup(ID_POPUP_SHOWMESSAGES_BROADCASTERS,ServMgr::NT_BROADCASTERS); + break; + case ID_POPUP_SHOWMESSAGES_TRACKINFO: + flipNotifyPopup(ID_POPUP_SHOWMESSAGES_TRACKINFO,ServMgr::NT_TRACKINFO); + break; + + case ID_POPUP_ABOUT: + case IDM_ABOUT: + DialogBox(hInst, (LPCTSTR)IDD_ABOUTBOX, hWnd, (DLGPROC)About); + break; + case ID_POPUP_SHOWGUI: + case IDM_SETTINGS_GUI: + case ID_POPUP_ADVANCED_SHOWGUI: + { + createGUI(hWnd); + break; + } + case ID_POPUP_YELLOWPAGES: + sys->getURL("http://yp.peercast.org/"); + break; + case ID_POPUP_YELLOWPAGES1: + sprintf(buf, "http://%s",servMgr->rootHost.cstr()); + sys->getURL(buf); + break; + case ID_POPUP_YELLOWPAGES2: + sprintf(buf, "http://%s",servMgr->rootHost2.cstr()); + sys->getURL(buf); + break; + + case ID_POPUP_ADVANCED_VIEWLOG: + showHTML("viewlog.html"); + break; + case ID_POPUP_ADVANCED_SAVESETTINGS: + servMgr->saveSettings(iniFileName.cstr()); + break; + case ID_POPUP_ADVANCED_INFORMATION: + showHTML("index.html"); + break; + case ID_FIND_CHANNELS: + case ID_POPUP_ADVANCED_ALLCHANNELS: + case ID_POPUP_UPGRADE: + sys->callLocalURL("admin?cmd=upgrade",servMgr->serverHost.port); + break; + case ID_POPUP_ADVANCED_RELAYEDCHANNELS: + case ID_POPUP_FAVORITES_EDIT: + showHTML("relays.html"); + break; + case ID_POPUP_ADVANCED_BROADCAST: + showHTML("broadcast.html"); + break; + case ID_POPUP_SETTINGS: + showHTML("settings.html"); + break; + case ID_POPUP_CONNECTIONS: + showHTML("connections.html"); + break; + case ID_POPUP_HELP: + sys->getURL("http://www.peercast.org/help.php"); + break; + + case ID_POPUP_SAVE_GUI_POS: + if (servMgr->saveGuiPos){ + servMgr->saveGuiPos = false; + CheckMenuItem(trayMenu, ID_POPUP_SAVE_GUI_POS, MF_UNCHECKED|MF_BYCOMMAND); + } else { + servMgr->saveGuiPos = true; + CheckMenuItem(trayMenu, ID_POPUP_SAVE_GUI_POS, MF_CHECKED|MF_BYCOMMAND); + } + peercastInst->saveSettings(); + break; + + case ID_POPUP_KEEP_DOWNSTREAMS: + if (servMgr->keepDownstreams){ + servMgr->keepDownstreams = false; + CheckMenuItem(trayMenu, ID_POPUP_KEEP_DOWNSTREAMS, MF_UNCHECKED|MF_BYCOMMAND); + } else { + servMgr->keepDownstreams = true; + CheckMenuItem(trayMenu, ID_POPUP_KEEP_DOWNSTREAMS, MF_CHECKED|MF_BYCOMMAND); + } + //peercastInst->saveSettings(); + break; + + case ID_POPUP_EXIT_CONFIRM: + case IDM_EXIT: + DestroyWindow(hWnd); + break; + default: + return DefWindowProc(hWnd, message, wParam, lParam); + } + break; + case WM_DESTROY: + PostQuitMessage(0); + break; + default: + return DefWindowProc(hWnd, message, wParam, lParam); + } + return 0; +} +// Mesage handler for about box. +LRESULT CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch (message) + { + case WM_INITDIALOG: + //SendDlgItemMessage(hDlg,IDC_ABOUTVER,WM_SETTEXT,0,(LONG)PCX_AGENT); +// SendDlgItemMessage(hDlg,IDC_ABOUTVER,WM_SETTEXT,0,(LONG)PCX_AGENTJP); +#ifdef VERSION_EX + SendDlgItemMessage(hDlg,IDC_ABOUTVER,WM_SETTEXT,0,(LONG)PCX_AGENTEX); +#else + SendDlgItemMessage(hDlg,IDC_ABOUTVER,WM_SETTEXT,0,(LONG)PCX_AGENTVP); +#endif + return TRUE; + + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDOK: + case IDCANCEL: + EndDialog(hDlg, LOWORD(wParam)); + return TRUE; + case IDC_BUTTON1: + sys->getURL("http://www.peercast.org"); + EndDialog(hDlg, LOWORD(wParam)); + return TRUE; + + } + break; + case WM_DESTROY: + break; + } + return FALSE; +} + +// Mesage handler for chaninfo box +LRESULT CALLBACK ChanInfoProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch (message) + { + case WM_INITDIALOG: + { + char str[1024]; + //strcpy(str,chanInfo.track.artist.cstr()); + strcpy(str,chanInfo.track.artist); //JP-Patch + strcat(str," - "); + //strcat(str,chanInfo.track.title.cstr()); + strcat(str,chanInfo.track.title); + String name,track,comment,desc,genre; //JP-Patch + name = chanInfo.name; //JP-Patch + track = str; //JP-Patch + comment = chanInfo.comment; //JP-Patch + desc = chanInfo.desc; //JP-Patc + genre = chanInfo.genre; //JP-Patch + name.convertTo(String::T_SJIS); //JP-Patc + track.convertTo(String::T_SJIS); //JP-Patch + comment.convertTo(String::T_SJIS); //JP-Patch + desc.convertTo(String::T_SJIS); //JP-Patch + genre.convertTo(String::T_SJIS); //JP-Patch + + //SendDlgItemMessage(hDlg,IDC_EDIT_NAME,WM_SETTEXT,0,(LONG)chanInfo.name.cstr()); + SendDlgItemMessage(hDlg,IDC_EDIT_NAME,WM_SETTEXT,0,(LONG)name.cstr()); //JP-Patch + //SendDlgItemMessage(hDlg,IDC_EDIT_PLAYING,WM_SETTEXT,0,(LONG)str); + SendDlgItemMessage(hDlg,IDC_EDIT_PLAYING,WM_SETTEXT,0,(LONG)track.cstr()); //JP-Patch + //SendDlgItemMessage(hDlg,IDC_EDIT_MESSAGE,WM_SETTEXT,0,(LONG)chanInfo.comment.cstr()); + SendDlgItemMessage(hDlg,IDC_EDIT_MESSAGE,WM_SETTEXT,0,(LONG)comment.cstr()); //JP-Patch + //SendDlgItemMessage(hDlg,IDC_EDIT_DESC,WM_SETTEXT,0,(LONG)chanInfo.desc.cstr()); + SendDlgItemMessage(hDlg,IDC_EDIT_DESC,WM_SETTEXT,0,(LONG)desc.cstr()); //JP-Patch + //SendDlgItemMessage(hDlg,IDC_EDIT_GENRE,WM_SETTEXT,0,(LONG)chanInfo.genre.cstr()); + SendDlgItemMessage(hDlg,IDC_EDIT_GENRE,WM_SETTEXT,0,(LONG)genre.cstr()); //JP-Patch + + sprintf(str,"%d kb/s %s",chanInfo.bitrate,ChanInfo::getTypeStr(chanInfo.contentType)); + SendDlgItemMessage(hDlg,IDC_FORMAT,WM_SETTEXT,0,(LONG)str); + + + if (!chanInfo.url.isValidURL()) + EnableWindow(GetDlgItem(hDlg,IDC_CONTACT),false); + + Channel *ch = chanMgr->findChannelByID(chanInfo.id); + if (ch) + { + SendDlgItemMessage(hDlg,IDC_EDIT_STATUS,WM_SETTEXT,0,(LONG)ch->getStatusStr()); + SendDlgItemMessage(hDlg, IDC_KEEP,BM_SETCHECK, ch->stayConnected, 0); + }else + { + SendDlgItemMessage(hDlg,IDC_EDIT_STATUS,WM_SETTEXT,0,(LONG)"OK"); + EnableWindow(GetDlgItem(hDlg,IDC_KEEP),false); + } + + + + POINT point; + RECT rect,drect; + HWND hDsk = GetDesktopWindow(); + GetWindowRect(hDsk,&drect); + GetWindowRect(hDlg,&rect); + GetCursorPos(&point); + + POINT pos,size; + size.x = rect.right-rect.left; + size.y = rect.bottom-rect.top; + + if (point.x-drect.left < size.x) + pos.x = point.x; + else + pos.x = point.x-size.x; + + if (point.y-drect.top < size.y) + pos.y = point.y; + else + pos.y = point.y-size.y; + + SetWindowPos(hDlg,HWND_TOPMOST,pos.x,pos.y,size.x,size.y,0); + chWnd = hDlg; + } + return TRUE; + + case WM_COMMAND: + { + char str[1024],idstr[64]; + chanInfo.id.toStr(idstr); + + switch (LOWORD(wParam)) + { + case IDC_CONTACT: + { + sys->getURL(chanInfo.url); + return TRUE; + } + case IDC_DETAILS: + { + sprintf(str,"admin?page=chaninfo&id=%s&relay=%d",idstr,chanInfoIsRelayed); + sys->callLocalURL(str,servMgr->serverHost.port); + return TRUE; + } + case IDC_KEEP: + { + Channel *ch = chanMgr->findChannelByID(chanInfo.id); + if (ch) + ch->stayConnected = SendDlgItemMessage(hDlg, IDC_KEEP,BM_GETCHECK, 0, 0) == BST_CHECKED;; + return TRUE; + } + + + case IDC_PLAY: + { + chanMgr->findAndPlayChannel(chanInfo,false); + return TRUE; + } + + } + } + break; + + case WM_CLOSE: + if (winDistinctionNT) + EndDialog(hDlg, 0); + else + DestroyWindow(hDlg); //JP-Patch + break; + + case WM_ACTIVATE: + if (LOWORD(wParam) == WA_INACTIVE) + if (winDistinctionNT) + EndDialog(hDlg, 0); + else + DestroyWindow(hDlg); //JP-Patch + break; + case WM_DESTROY: + chWnd = NULL; + break; + + + } + return FALSE; +} diff --git a/c:/Git/PeerCast.root/PeerCast/ui/win32/simple/Simple.h b/c:/Git/PeerCast.root/PeerCast/ui/win32/simple/Simple.h new file mode 100644 index 0000000..ad59a96 --- /dev/null +++ b/c:/Git/PeerCast.root/PeerCast/ui/win32/simple/Simple.h @@ -0,0 +1,65 @@ + +// ------------------------------------------------ +// File : simple.h +// Date: 4-apr-2002 +// Author: giles +// +// (c) 2002 peercast.org +// ------------------------------------------------ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// ------------------------------------------------ + +#if !defined(AFX_SIMPLE_H__F2E64B1B_62DE_473C_A6B6_E7826D41E0FA__INCLUDED_) +#define AFX_SIMPLE_H__F2E64B1B_62DE_473C_A6B6_E7826D41E0FA__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#include "resource.h" + +// --------------------------------- +class MyPeercastInst : public PeercastInstance +{ +public: + virtual Sys * APICALL createSys(); +}; +// --------------------------------- +class MyPeercastApp : public PeercastApplication +{ +public: + MyPeercastApp () + { + //logFile.openWriteReplace("log.txt"); + } + + virtual const char * APICALL getPath(); + + virtual const char * APICALL getIniFilename(); + virtual const char *APICALL getClientTypeOS(); + virtual void APICALL openLogFile(); //JP-EX + virtual void APICALL getDirectory(); //JP-EX + virtual bool APICALL clearTemp(); //JP-EX + virtual void APICALL printLog(LogBuffer::TYPE t, const char *str); + + virtual void APICALL updateSettings(); + virtual void APICALL notifyMessage(ServMgr::NOTIFY_TYPE, const char *); + + virtual void APICALL channelStart(ChanInfo *); + virtual void APICALL channelStop(ChanInfo *); + virtual void APICALL channelUpdate(ChanInfo *); + + FileStream logFile; + +}; + + +#endif // !defined(AFX_SIMPLE_H__F2E64B1B_62DE_473C_A6B6_E7826D41E0FA__INCLUDED_) diff --git a/c:/Git/PeerCast.root/PeerCast/ui/win32/simple/Simple.rc b/c:/Git/PeerCast.root/PeerCast/ui/win32/simple/Simple.rc new file mode 100644 index 0000000..311c8fc --- /dev/null +++ b/c:/Git/PeerCast.root/PeerCast/ui/win32/simple/Simple.rc @@ -0,0 +1,379 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +// Generated Help ID header file +#define APSTUDIO_HIDDEN_SYMBOLS +#include "resource.hm" +#undef APSTUDIO_HIDDEN_SYMBOLS + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#define APSTUDIO_HIDDEN_SYMBOLS +#include "windows.h" +#undef APSTUDIO_HIDDEN_SYMBOLS +#include "resource.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// ƒjƒ…[ƒgƒ‰ƒ‹ (ƒVƒXƒeƒ€•W€) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEUSD) +#ifdef _WIN32 +LANGUAGE LANG_NEUTRAL, SUBLANG_SYS_DEFAULT +#pragma code_page(932) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Menu +// + +IDR_TRAYMENU MENU +BEGIN + POPUP "popup" + BEGIN + MENUITEM "î•ñ", ID_POPUP_ABOUT + MENUITEM "ƒwƒ‹ƒv", ID_POPUP_HELP + MENUITEM SEPARATOR + POPUP "ƒ|ƒbƒvƒAƒbƒvƒƒbƒZ[ƒW" + BEGIN + MENUITEM "PeerCast", ID_POPUP_SHOWMESSAGES_PEERCAST + + MENUITEM "”zMŽÒ", ID_POPUP_SHOWMESSAGES_BROADCASTERS + + MENUITEM "ƒgƒ‰ƒbƒNî•ñ", ID_POPUP_SHOWMESSAGES_TRACKINFO + + MENUITEM "ƒAƒbƒvƒf[ƒgî•ñ", ID_POPUP_POPUPMESSAGES_UPGRADEALERTS + , CHECKED, GRAYED + END + POPUP "‚“x" + BEGIN + MENUITEM "î•ñ", ID_POPUP_ADVANCED_INFORMATION + + MENUITEM "ƒŠƒŒ[ƒ`ƒƒƒ“ƒlƒ‹", ID_POPUP_ADVANCED_RELAYEDCHANNELS + + MENUITEM "”zM", ID_POPUP_ADVANCED_BROADCAST + + MENUITEM "ƒRƒlƒNƒVƒ‡ƒ“", ID_POPUP_CONNECTIONS + MENUITEM "ƒƒO", ID_POPUP_ADVANCED_VIEWLOG + + MENUITEM "Ý’è", ID_POPUP_SETTINGS + MENUITEM "GUI‚ðŠJ‚­", ID_POPUP_ADVANCED_SHOWGUI + + END + POPUP "’ljÁÝ’è" + BEGIN + MENUITEM "I—¹ŽžA•\Ž¦ˆÊ’u‚ð•Û‘¶", ID_POPUP_SAVE_GUI_POS + , CHECKED + MENUITEM "ÄÚ‘±Žž‰º—¬ˆÛŽ", ID_POPUP_KEEP_DOWNSTREAMS + , CHECKED + END + MENUITEM SEPARATOR + POPUP "I—¹" + BEGIN + MENUITEM "‚Í‚¢", ID_POPUP_EXIT_CONFIRM + MENUITEM "‚¢‚¢‚¦", ID_POPUP_EXIT_NO + END + END +END + +IDR_LTRAYMENU MENU +BEGIN + POPUP "popup" + BEGIN + MENUITEM SEPARATOR + MENUITEM "ƒCƒGƒ[ƒy[ƒW", ID_POPUP_YELLOWPAGES + POPUP "ƒCƒGƒ[ƒy[ƒW" + BEGIN + MENUITEM "AAA", ID_POPUP_YELLOWPAGES1 + MENUITEM "BBB", ID_POPUP_YELLOWPAGES2 + END + END +END + +IDR_GUIMENU MENU +BEGIN + POPUP "popup" + BEGIN + MENUITEM SEPARATOR + MENUITEM "§Œä", ID_POPUP_YELLOWPAGES + POPUP "§Œä" + BEGIN + MENUITEM "AAA", ID_POPUP_YELLOWPAGES1 + MENUITEM "BBB", ID_POPUP_YELLOWPAGES2 + END + END +END + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_MAINWINDOW DIALOGEX 0, 0, 298, 341 +STYLE DS_SETFONT | DS_CENTER | WS_MINIMIZEBOX | WS_CAPTION | WS_SYSMENU | + WS_THICKFRAME +EXSTYLE WS_EX_APPWINDOW +CAPTION "PeerCast" +FONT 9, "MS UI Gothic", 0, 0, 0x1 +BEGIN + LISTBOX IDC_LIST1,3,291,291,43,LBS_NOINTEGRALHEIGHT | WS_VSCROLL | + WS_TABSTOP + CONTROL "—LŒø",IDC_CHECK1,"Button",BS_AUTOCHECKBOX | BS_PUSHLIKE | + WS_TABSTOP,9,29,60,20,WS_EX_TRANSPARENT + EDITTEXT IDC_EDIT1,127,18,47,12,ES_AUTOHSCROLL + RTEXT "ƒ|[ƒg :",IDC_STATIC,107,20,18,8 + LISTBOX IDC_LIST2,3,206,291,71,LBS_OWNERDRAWFIXED | + LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP + LTEXT "ƒƒO",IDC_STATIC_LOG,3,282,13,8 + LTEXT "ƒRƒlƒNƒVƒ‡ƒ“",IDC_STATIC_CONNECTION,3,184,40,8 + GROUPBOX "",IDC_STATIC,3,4,291,49 + PUSHBUTTON "ƒNƒŠƒA",IDC_BUTTON1,35,279,25,11 + LISTBOX IDC_LIST3,3,81,291,67,LBS_OWNERDRAWFIXED | + LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Ø’f",IDC_BUTTON5,67,65,43,13 + GROUPBOX "ƒŠƒŒ[",IDC_GROUPBOX_RELAY,3,54,291,96 + EDITTEXT IDC_EDIT3,127,34,47,12,ES_PASSWORD | ES_AUTOHSCROLL + RTEXT "ƒpƒXƒ[ƒh :",IDC_STATIC,89,36,36,8 + CONTROL "ƒfƒoƒbƒO",IDC_LOGDEBUG,"Button",BS_AUTOCHECKBOX | + BS_PUSHLIKE | WS_TABSTOP,127,279,32,11 + CONTROL "ƒlƒbƒgƒ[ƒN",IDC_LOGNETWORK,"Button",BS_AUTOCHECKBOX | + BS_PUSHLIKE | WS_TABSTOP,185,279,35,11 + CONTROL "ƒGƒ‰[",IDC_LOGERRORS,"Button",BS_AUTOCHECKBOX | + BS_PUSHLIKE | WS_TABSTOP,159,279,25,11 + CONTROL "’âŽ~",IDC_CHECK9,"Button",BS_AUTOCHECKBOX | BS_PUSHLIKE | + WS_TABSTOP,60,279,30,11 + PUSHBUTTON "Ä¶",IDC_BUTTON8,10,65,22,13 + CONTROL "ƒ`ƒƒƒ“ƒlƒ‹",IDC_LOGCHANNELS,"Button",BS_AUTOCHECKBOX | + BS_PUSHLIKE | WS_TABSTOP,221,279,35,11 + PUSHBUTTON "ÄÚ‘±",IDC_BUTTON3,41,65,24,13 + EDITTEXT IDC_EDIT9,33,159,261,14,ES_AUTOHSCROLL + CONTROL "DJ",IDC_CHECK11,"Button",BS_AUTOCHECKBOX | BS_PUSHLIKE | + WS_TABSTOP,5,160,23,12 + RTEXT "Å‘僊ƒŒ[” :",IDC_STATIC,203,20,40,8 + EDITTEXT IDC_MAXRELAYS,248,18,40,14,ES_AUTOHSCROLL | ES_NUMBER + PUSHBUTTON "ƒL[ƒv",IDC_BUTTON9,112,65,24,13 + PUSHBUTTON "Ø’f",IDC_BUTTON6,47,179,43,13 + LTEXT "Peercast-VP",IDC_STATIC,21,14,39,8 +END + +IDD_CHANINFO DIALOGEX 0, 0, 184, 207 +STYLE DS_SETFONT | DS_SETFOREGROUND | WS_POPUP | WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_TOOLWINDOW +CAPTION "Channel Information" +FONT 9, "MS UI Gothic", 400, 0, 0x80 +BEGIN + LTEXT "–¼‘O:",IDC_STATIC,7,8,24,9 + EDITTEXT IDC_EDIT_NAME,7,18,170,21,ES_MULTILINE | ES_READONLY | + NOT WS_BORDER | NOT WS_TABSTOP,WS_EX_STATICEDGE + LTEXT "“à—e:",IDC_STATIC,7,79,93,9 + EDITTEXT IDC_EDIT_PLAYING,8,90,170,21,ES_MULTILINE | ES_READONLY | + NOT WS_BORDER | NOT WS_TABSTOP,WS_EX_STATICEDGE + LTEXT "DJ ƒƒbƒZ[ƒW:",IDC_STATIC,7,117,41,9 + EDITTEXT IDC_EDIT_MESSAGE,8,128,170,21,ES_MULTILINE | ES_READONLY | + NOT WS_BORDER | NOT WS_TABSTOP,WS_EX_STATICEDGE + PUSHBUTTON "URL",IDC_CONTACT,7,185,34,15,0,0,HIDC_CONTACT + LTEXT "Ú×:",IDC_STATIC,7,43,67,8 + EDITTEXT IDC_EDIT_DESC,8,53,170,21,ES_MULTILINE | ES_READONLY | + NOT WS_BORDER | NOT WS_TABSTOP,WS_EX_STATICEDGE + RTEXT "Œ`Ž®",IDC_FORMAT,69,80,107,8 + LTEXT "ƒWƒƒƒ“ƒ‹:",IDC_STATIC,63,5,22,8 + EDITTEXT IDC_EDIT_GENRE,87,3,90,12,ES_AUTOHSCROLL | ES_READONLY | + NOT WS_BORDER | NOT WS_TABSTOP,WS_EX_STATICEDGE + CONTROL "ƒL[ƒv",IDC_KEEP,"Button",BS_AUTOCHECKBOX | WS_TABSTOP, + 144,188,33,10 + LTEXT "ƒXƒe[ƒ^ƒX:",IDC_STATIC,7,153,41,9 + EDITTEXT IDC_EDIT_STATUS,8,163,82,12,ES_READONLY | NOT WS_BORDER | + NOT WS_TABSTOP,WS_EX_STATICEDGE + PUSHBUTTON "Ä¶",IDC_PLAY,56,185,34,15 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_MAINWINDOW, DIALOG + BEGIN + LEFTMARGIN, 3 + RIGHTMARGIN, 294 + TOPMARGIN, 3 + BOTTOMMARGIN, 336 + END + + IDD_CHANINFO, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 177 + TOPMARGIN, 7 + BOTTOMMARGIN, 200 + END +END +#endif // APSTUDIO_INVOKED + +#endif // ƒjƒ…[ƒgƒ‰ƒ‹ (ƒVƒXƒeƒ€•W€) resources +///////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////// +// ‰pŒê (•Ä‘) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Menu +// + +IDC_SIMPLE MENU +BEGIN + POPUP "&File" + BEGIN + MENUITEM "E&xit", IDM_EXIT + END + POPUP "&Help" + BEGIN + MENUITEM "&About ...", IDM_ABOUT + END + POPUP "Settings" + BEGIN + MENUITEM "GUI", IDM_SETTINGS_GUI + END +END + +IDR_VERMENU MENU +BEGIN + POPUP "popup" + BEGIN + MENUITEM "Please upgrade PeerCast. Click here to download.", + ID_POPUP_UPGRADE + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_ABOUTBOX DIALOG 22, 17, 163, 59 +STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_CENTER | WS_CAPTION | + WS_SYSMENU +CAPTION "About" +FONT 8, "System" +BEGIN + ICON IDI_SIMPLE,IDC_MYICON,14,9,20,20 + LTEXT "PeerCast",IDC_ABOUTVER,43,9,103,8,SS_NOPREFIX + LTEXT "Copyright (C) 2005",IDC_STATIC,43,22,119,8 + PUSHBUTTON "OK",IDOK,134,40,24,12,WS_GROUP + PUSHBUTTON "www.peercast.org",IDC_BUTTON1,42,40,66,12 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_ABOUTBOX, DIALOG + BEGIN + BOTTOMMARGIN, 58 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_SIMPLE ICON "Simple.ICO" +IDI_SMALL2 ICON "small1.ico" +IDI_SMALL ICON "small3.ico" + +///////////////////////////////////////////////////////////////////////////// +// +// Accelerator +// + +IDC_SIMPLE ACCELERATORS +BEGIN + "?", IDM_ABOUT, ASCII, ALT + "/", IDM_ABOUT, ASCII, ALT +END + + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +2 TEXTINCLUDE +BEGIN + "#define APSTUDIO_HIDDEN_SYMBOLS\r\n" + "#include ""windows.h""\r\n" + "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n" + "#include ""resource.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE +BEGIN + IDS_APP_TITLE "PeerCast" +END + +#endif // ‰pŒê (•Ä‘) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/c:/Git/PeerCast.root/PeerCast/ui/win32/simple/Simple.vcproj b/c:/Git/PeerCast.root/PeerCast/ui/win32/simple/Simple.vcproj new file mode 100644 index 0000000..2241604 --- /dev/null +++ b/c:/Git/PeerCast.root/PeerCast/ui/win32/simple/Simple.vcproj @@ -0,0 +1,906 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/c:/Git/PeerCast.root/PeerCast/ui/win32/simple/Simple.vcproj.vspscc b/c:/Git/PeerCast.root/PeerCast/ui/win32/simple/Simple.vcproj.vspscc new file mode 100644 index 0000000..f30e03c --- /dev/null +++ b/c:/Git/PeerCast.root/PeerCast/ui/win32/simple/Simple.vcproj.vspscc @@ -0,0 +1,10 @@ +"" +{ +"FILE_VERSION" = "9237" +"ENLISTMENT_CHOICE" = "NEVER" +"PROJECT_FILE_RELATIVE_PATH" = "relative:ui\\win32\\simple" +"NUMBER_OF_EXCLUDED_FILES" = "0" +"ORIGINAL_PROJECT_FILE_PATH" = "" +"NUMBER_OF_NESTED_PROJECTS" = "0" +"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROJECT" +} diff --git a/c:/Git/PeerCast.root/PeerCast/ui/win32/simple/StdAfx.cpp b/c:/Git/PeerCast.root/PeerCast/ui/win32/simple/StdAfx.cpp new file mode 100644 index 0000000..fe41f64 --- /dev/null +++ b/c:/Git/PeerCast.root/PeerCast/ui/win32/simple/StdAfx.cpp @@ -0,0 +1,9 @@ +// stdafx.cpp : source file that includes just the standard includes +// Simple.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + +// TODO: reference any additional headers you need in STDAFX.H +// and not in this file + diff --git a/c:/Git/PeerCast.root/PeerCast/ui/win32/simple/StdAfx.h b/c:/Git/PeerCast.root/PeerCast/ui/win32/simple/StdAfx.h new file mode 100644 index 0000000..1e47eff --- /dev/null +++ b/c:/Git/PeerCast.root/PeerCast/ui/win32/simple/StdAfx.h @@ -0,0 +1,32 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#if !defined(AFX_STDAFX_H__A9DB83DB_A9FD_11D0_BFD1_444553540000__INCLUDED_) +#define AFX_STDAFX_H__A9DB83DB_A9FD_11D0_BFD1_444553540000__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers + + +// Windows Header Files: +#include + +// C RunTime Header Files +#include +#include +#include +#include + +// Local Header Files + +// TODO: reference additional headers your program requires here + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_STDAFX_H__A9DB83DB_A9FD_11D0_BFD1_444553540000__INCLUDED_) diff --git a/c:/Git/PeerCast.root/PeerCast/ui/win32/simple/chkMemoryLeak.cpp b/c:/Git/PeerCast.root/PeerCast/ui/win32/simple/chkMemoryLeak.cpp new file mode 100644 index 0000000..4c8df0d --- /dev/null +++ b/c:/Git/PeerCast.root/PeerCast/ui/win32/simple/chkMemoryLeak.cpp @@ -0,0 +1,21 @@ +#ifdef _DEBUG +//#include "stdafx.h" +#include "chkMemoryLeak.h" + +#ifdef __AFXWIN_H__ // MFC‚̃EƒBƒ“ƒhƒE‚ðŽg‚¤ê‡‚ÉŒÀ’肵‚Ä‚¢‚Ü‚· +#else + #if defined(_DEBUG) + #define __chkMemoryLeak_H__ + void* operator new(size_t size, const char *filename, int linenumber) + { + return _malloc_dbg(size, _NORMAL_BLOCK, filename, linenumber); + } + void operator delete(void * _P, const char *filename, int linenumber) + { + _free_dbg(_P, _NORMAL_BLOCK); + return; + } + + #endif +#endif +#endif diff --git a/c:/Git/PeerCast.root/PeerCast/ui/win32/simple/chkMemoryLeak.h b/c:/Git/PeerCast.root/PeerCast/ui/win32/simple/chkMemoryLeak.h new file mode 100644 index 0000000..aa47729 --- /dev/null +++ b/c:/Git/PeerCast.root/PeerCast/ui/win32/simple/chkMemoryLeak.h @@ -0,0 +1,25 @@ +#ifndef _CHKMEMORYLEAK_H +#define _CHKMEMORYLEAK_H + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#ifdef _DEBUG + #define _CRTDBG_MAP_ALLOC + + #define SET_CRT_DEBUG_FIELD(a) _CrtSetDbgFlag((a) | _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG)) + #define CLEAR_CRT_DEBUG_FIELD(a) _CrtSetDbgFlag(~(a) & _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG)) + + void* operator new(size_t size, const char *filename, int linenumber); + void operator delete(void * _P, const char *filename, int linenumber); +#else + #define SET_CRT_DEBUG_FIELD(a) ((void) 0) + #define CLEAR_CRT_DEBUG_FIELD(a) ((void) 0) +#endif + +#include + +#include + +#endif diff --git a/c:/Git/PeerCast.root/PeerCast/ui/win32/simple/gui.cpp b/c:/Git/PeerCast.root/PeerCast/ui/win32/simple/gui.cpp new file mode 100644 index 0000000..1ef53b1 --- /dev/null +++ b/c:/Git/PeerCast.root/PeerCast/ui/win32/simple/gui.cpp @@ -0,0 +1,1853 @@ +// ------------------------------------------------ +// File : gui.cpp +// Date: 4-apr-2002 +// Author: giles +// Desc: +// Windows front end GUI, PeerCast core is not dependant on any of this. +// Its very messy at the moment, but then again Windows UI always is. +// I really don`t like programming win32 UI.. I want my borland back.. +// +// (c) 2002 peercast.org +// ------------------------------------------------ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// ------------------------------------------------ + +#define _WIN32_WINNT 0x0500 + +#include +#include "stdio.h" +#include "string.h" +#include "stdarg.h" +#include "resource.h" +#include "socket.h" +#include "win32/wsys.h" +#include "servent.h" +#include "win32/wsocket.h" +#include "inifile.h" +#include "gui.h" +#include "servmgr.h" +#include "peercast.h" +#include "simple.h" +#include "gdiplus.h" +#include "commctrl.h" +#include "locale.h" +#include "stats.h" +#include "socket.h" +#include "wininet.h" +#ifdef _DEBUG +#include "chkMemoryLeak.h" +#define DEBUG_NEW new(__FILE__, __LINE__) +#define new DEBUG_NEW +#endif + +ThreadInfo guiThread; +bool shownChannels=false; +WINDOWPLACEMENT winPlace; +bool guiFlg = false; + +using namespace Gdiplus; + +#include + +void APICALL MyPeercastApp ::printLog(LogBuffer::TYPE t, const char *str) +{ +/* ADDLOG(str,logID,true,NULL,t); + if (logFile.isOpen()) + { + logFile.writeLine(str); + logFile.flush(); + }*/ +} + +void APICALL MyPeercastApp::updateSettings() +{ +// setControls(true); +} + +Gdiplus::Bitmap bmpBack(800,600,PixelFormat24bppRGB); +UINT backWidth; +UINT backHeight; + +Gdiplus::Image *backImage; +Gdiplus::Bitmap *backBmp; +Gdiplus::Graphics *backGra; + +Gdiplus::Image *img_idle; +Gdiplus::Image *img_connect; +Gdiplus::Image *img_conn_ok; +Gdiplus::Image *img_conn_full; +Gdiplus::Image *img_conn_over; +Gdiplus::Image *img_conn_ok_skip; +Gdiplus::Image *img_conn_full_skip; +Gdiplus::Image *img_conn_over_skip; +Gdiplus::Image *img_error; +Gdiplus::Image *img_broad_ok; +Gdiplus::Image *img_broad_full; + +UINT winWidth=0; +UINT winHeight=0; + +static HWND hTree; +extern HINSTANCE hInst; +extern HWND guiWnd; +extern Stats stats; + +WLock sd_lock; +WLock ChannelDataLock; +WLock MakeBackLock; +ChannelData *channelDataTop = NULL; + +extern bool gbGetFile; +extern bool gbStart; +extern time_t gtGetFile; +extern time_t gtStartTime; +ThreadInfo gtiStart; +ThreadInfo gtiGetFile; +static char *data1URL = "http://www.idolmaster.jp/download/images/wallpaper/imas360p_800.jpg"; +static char *data2URL = "http://www.xbox.com/NR/rdonlyres/CAB05E2F-3051-409B-A4C8-830167C1C138/0/wpr0701idolmasterw120001.jpg"; +HWND ghStart; + +bool gbDispTop = false; +bool gbAllOpen = false; + +THREAD_PROC FestivalStart(ThreadInfo *thread); + +THREAD_PROC GetHostName(ThreadInfo *thread){ + IdData *id = (IdData*)(thread->data); + + HOSTENT *he; + unsigned int ip; + bool flg = TRUE; + + ChannelDataLock.on(); + ip = htonl(id->getIpAddr()); + + for (int i=0; i<5 && flg; i++){ + he = gethostbyaddr((char *)&ip,sizeof(ip),AF_INET); + + ChannelData* cd = channelDataTop; + if (he) + { + while(cd){ + if (cd->setName(id->getServentId(), he->h_name)){ + flg = FALSE; + break; + } + cd = cd->getNextData(); + } + } +// ::delete id; + ChannelDataLock.off(); + sys->sleep(1000); + } + + + return 0; +} + +bool DownloadFile(LPCTSTR URL, LPCTSTR local){ + char header[] = "Accept: */*\r\n\r\n"; + char buf[4096]; + + FileStream f; + HINTERNET hInternet; + HINTERNET hConnect; + + try{ + f.openWriteReplace(local); + }catch(StreamException &e){ + return false; + } + + hInternet = ::InternetOpen(NULL, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0); + if (hInternet == NULL){ + return false; + } + + hConnect = ::InternetOpenUrl(hInternet, URL, header, strlen(header), INTERNET_FLAG_DONT_CACHE, 0); + if (hConnect == NULL){ + ::InternetCloseHandle(hInternet); + return false; + } + + while(1){ + sys->sleep(0); + DWORD dwReadSize; + BOOL ret = ::InternetReadFile(hConnect, buf, 4096, &dwReadSize); + if (ret){ + if (dwReadSize == 0){ + break; + } + try{ + f.write(buf, dwReadSize); + continue; + } catch(StreamException e){ + } + f.close(); + ::InternetCloseHandle(hConnect); + ::InternetCloseHandle(hInternet); + return false; + } + } + + f.flush(); + f.close(); + ::InternetCloseHandle(hConnect); + ::InternetCloseHandle(hInternet); + + return true; +} + +THREAD_PROC GetInternetFile(ThreadInfo *thread){ + + DownloadFile(data1URL, "data1.jpg"); + DownloadFile(data2URL, "data2.jpg"); + return 0; +} + +extern TCHAR szWindowClass3[]; // The title bar text + + +int drawSpeed(Graphics *gra, int posX, int posY){ + + // ‘¬“x•\Ž¦•”‚Ì”wŒi‚ð”’‚­‚·‚é + SolidBrush b(Color(180,255,255,255)); + backGra->FillRectangle(&b, posX, posY, 200, 14); + // ƒtƒHƒ“ƒgÝ’è + Font font(L"‚l‚r ‚oƒSƒVƒbƒN",10); + // •¶ŽšF + SolidBrush strBrush(Color::Black); + // •¶Žš—ñì¬ + char tmp[256]; + sprintf(tmp, "R:%.1fkbps S:%.1fkbps", + BYTES_TO_KBPS(stats.getPerSecond(Stats::BYTESIN)-stats.getPerSecond(Stats::LOCALBYTESIN)), + BYTES_TO_KBPS(stats.getPerSecond(Stats::BYTESOUT)-stats.getPerSecond(Stats::LOCALBYTESOUT))); + _bstr_t bstr(tmp); + // •¶Žš•\Ž¦”͈͎w’è + StringFormat format; + format.SetAlignment(StringAlignmentCenter); + RectF r((REAL)posX, (REAL)posY, (REAL)200, (REAL)14); + // •¶Žš•`‰æ + gra->DrawString(bstr, -1, &font, r, &format, &strBrush); + + + + return posY + 15; +} + +void MakeBack(HWND hwnd, UINT x, UINT y){ + MakeBackLock.on(); + + winWidth = x; + winHeight = y; + + if (backGra){ + ::delete backBmp; + ::delete backGra; + } + + backBmp = ::new Bitmap(x,y); + backGra = ::new Graphics(backBmp); + + // ‘S‚Ä”’‚Å“h‚è‚‚Ԃµ + SolidBrush b(Color(255,255,255,255)); + backGra->FillRectangle(&b, 0, 0, x, y); + + backWidth = backImage->GetWidth(); + backHeight = backImage->GetHeight(); + + // ”wŒi‰æ‘œ‚ð•`‰æ + for (UINT xx = 0; xx < x/backWidth + 1; xx++){ + for (UINT yy = 0; yy < y/backHeight + 1; yy++){ + UINT width,height; + if (backWidth*(xx+1) > x){ + width = x % backWidth; + } else { + width = backWidth; + } + if (backHeight*(yy+1) > y){ + height = y % backHeight; + } else { + height = backHeight; + } + Rect r((INT)backWidth*xx, (INT)backHeight*yy, width, height); + backGra->DrawImage(backImage, r, 0, 0, (INT)width, (INT)height, UnitPixel); + } + } + + INT posX = 20; + INT posY = 20; + + // ‘¬“x•`‰æ + drawSpeed(backGra, winWidth-205, 5); + + // ƒ`ƒƒƒ“ƒlƒ‹î•ñ‚ð•`‰æ + ChannelDataLock.on(); + ChannelData *cd = channelDataTop; + while(cd){ + posY = cd->drawChannel(backGra, 20, posY); + cd = cd->getNextData(); + } + ChannelDataLock.off(); + MakeBackLock.off(); +} + +void MakeBack(HWND hwnd){ + MakeBack(hwnd, winWidth, winHeight); + ::InvalidateRect(guiWnd, NULL, FALSE); +} + +void ChannelData::setData(Channel *c){ + String sjis; + sjis = c->getName(); + sjis.convertTo(String::T_SJIS); + + strncpy(name, sjis, 256); + name[256] = '\0'; + channel_id = c->channel_id; + bitRate = c->info.bitrate; + lastPlayStart = c->info.lastPlayStart; + status = c->status; + totalListeners = c->totalListeners(); + totalRelays = c->totalRelays(); + localListeners = c->localListeners(); + localRelays = c->localRelays(); + stayConnected = c->stayConnected; + chDisp = c->chDisp; + bTracker = c->sourceHost.tracker; + lastSkipTime = c->lastSkipTime; + skipCount = c->skipCount; +} + +int gW = 0; +int gWS = 0; + +int ChannelData::drawChannel(Graphics *g, int x, int y){ + REAL xx = x * 1.0f; + REAL yy = y * 1.0f; + ServentData* sd; + + // ˆÊ’u‚ð•Û‘¶ + posX = x; + posY = y; + + int w,h; + + if (getWidth() == 0){ + if (gW){ + w = gW; + } else { + w = 400; + } + } else { + w = getWidth(); + gW = w; + } + + // ƒ`ƒƒƒ“ƒlƒ‹•\Ž¦•”‚Ì”wŒi‚ð“h‚é + if (isSelected()){ + // ‘I‘ð’† + SolidBrush b(Color(160,49,106,197)); + g->FillRectangle(&b, x, y, w, 14); + } else { + // ”ñ‘I‘ð + SolidBrush b(Color(160,255,255,255)); + g->FillRectangle(&b, x, y, w, 14); + } + + // ƒXƒe[ƒ^ƒX•\Ž¦ + Gdiplus::Image *img = NULL; + unsigned int nowTime = sys->getTime(); + switch(this->getStatus()){ + case Channel::S_IDLE: + img = img_idle; + break; + case Channel::S_SEARCHING: + case Channel::S_CONNECTING: + img = img_connect; + break; + case Channel::S_RECEIVING: + if ((skipCount > 2) && (lastSkipTime + 120 > nowTime)){ + if (chDisp.relay){ + img = img_conn_ok_skip; + } else { + if (chDisp.numRelays){ + img = img_conn_full_skip; + } else { + img = img_conn_over_skip; + } + } + } else { + if (chDisp.relay){ + img = img_conn_ok; + } else { + if (chDisp.numRelays){ + img = img_conn_full; + } else { + img = img_conn_over; + } + } + } + break; + case Channel::S_BROADCASTING: + img = img_broad_ok; + break; + case Channel::S_ERROR: + img = img_error; + break; + default: + img = img_idle; + break; + } + // •`‰æŠî“_ + PointF origin(xx, yy); + // ƒXƒe[ƒ^ƒX•\Ž¦ˆÊ’u + Rect img_rect((INT)origin.X, (INT)origin.Y + 1, img ? img->GetWidth() : 12, 12); + // ƒXƒe[ƒ^ƒX•`‰æ + ImageAttributes att; +// att.SetColorKey(Color::White, Color::White, ColorAdjustTypeBitmap); + g->DrawImage(img, img_rect, 0, 0, img_rect.Width, 12, UnitPixel, &att); + // ŽŸ‚ÌŠî“_ + origin.X += img_rect.Width; + + // ƒtƒHƒ“ƒgÝ’è + Gdiplus::Font font(L"‚l‚r ‚oƒSƒVƒbƒN",10); + // •¶ŽšF + SolidBrush *strBrush; + if (servMgr->getFirewall() == ServMgr::FW_ON){ + strBrush = ::new SolidBrush(Color::Red); + } else if (isTracker() && (getStatus() == Channel::S_RECEIVING)){ + strBrush = ::new SolidBrush(Color::Green); + } else { + if (isSelected()){ + // ‘I‘ð’† + strBrush = ::new SolidBrush(Color::White); + } else { + // ”ñ‘I‘ð + strBrush = ::new SolidBrush(Color::Black); + } + } + // ƒ`ƒƒƒ“ƒlƒ‹–¼•\Ž¦ + g->SetTextRenderingHint(TextRenderingHintAntiAlias); + _bstr_t bstr1(getName()); + // •¶Žš•`‰æ”͈͎w’è + RectF r1(origin.X, origin.Y, 120.0f, 13.0f); + StringFormat format; + format.SetAlignment(StringAlignmentNear); + g->DrawString(bstr1, -1, &font, r1, &format, strBrush); + // ŽŸ‚ÌŠî“_ + origin.X += r1.Width; + + // ƒŠƒXƒi[”/ƒŠƒŒ[”•\Ž¦ + char tmp[256]; + sprintf(tmp, "%d/%d - [%d/%d]", getTotalListeners(), getTotalRelays(), getLocalListeners(), getLocalRelays()); + _bstr_t bstr2(tmp); + // •¶Žš•\Ž¦”͈͎w’è + RectF r2(origin.X, origin.Y, 100.0f, 13.0f); + format.SetAlignment(StringAlignmentCenter); + g->DrawString(bstr2, -1, &font, r2, &format, strBrush); + // ŽŸ‚ÌŠî“_ + origin.X += r2.Width; + + // bps•\Ž¦ + Font *f; + if (isStayConnected()){ + f = ::new Font(L"Arial", 9.0f, FontStyleItalic|FontStyleBold, UnitPoint); + } else { + f = ::new Font(L"Arial", 9.0f); + } + sprintf(tmp, "%dkbps", getBitRate()); + _bstr_t bstr3(tmp); + format.SetAlignment(StringAlignmentFar); + // •¶Žš•\Ž¦”͈͎w’è + RectF r3(origin.X, origin.Y, 80.0f, 13.0f); + g->DrawString(bstr3, -1, f, r3, &format, strBrush); + // ƒtƒHƒ“ƒgŠJ•ú + ::delete f; + + // ŽŸ‚ÌŠî“_ + origin.X += r3.Width; + + // ƒuƒ‰ƒVíœ + ::delete strBrush; + + + // Servent•\Ž¦ + if (!openFlg){ + int count = getServentCount(); + // Servent•\Ž¦•”‚Ì”wŒi‚ð”’‚É‚·‚é + SolidBrush b(Color(160,255,255,255)); + g->FillRectangle(&b, (INT)origin.X, (INT)origin.Y, 14*count, 14); + + sd = serventDataTop; + int index = 0; + while(sd){ + SolidBrush *serventBrush; + if (sd->getInfoFlg()){ + ChanHit *hit = sd->getChanHit(); + if (hit->firewalled){ + SolidBrush bb(Color(180,255,0,0)); + g->FillRectangle(&bb, (INT)origin.X + 14*index, (INT)origin.Y, 14, 14); + } + if (hit->relay){ + // ƒŠƒŒ[‚n‚j + serventBrush = ::new SolidBrush(Color::Green); + } else { + // ƒŠƒŒ[•s‰Â + if (hit->numRelays){ + // ƒŠƒŒ[ˆê”t + serventBrush = ::new SolidBrush(Color::Blue); + } else { + // ƒŠƒŒ[‚È‚µ + serventBrush = ::new SolidBrush(Color::Purple); + } + } + } else { + // î•ñ‚È‚µ + serventBrush = ::new SolidBrush(Color::Black); + } + // ŽlŠp•`‰æ + backGra->FillRectangle(serventBrush, (INT)origin.X + index*14 + 1, (INT)origin.Y + 1, 12, 12); + + ::delete serventBrush; + sd = sd->getNextData(); + index++; + } + } + + // ŽŸ‚ÌŠî“_ + origin.Y += 15; + + // ƒTƒCƒY‚ð•Û‘¶ + setWidth((int)origin.X - posX); + setHeight((int)origin.Y - posY); + + // ServentData•\Ž¦ + sd = serventDataTop; + while(sd){ + if (openFlg || sd->getSelected()){ + sd->drawServent(g, (INT)x+12, (INT)origin.Y); + // ŽŸ‚ÌŠî“_ + origin.Y += 15; + } + sd = sd->getNextData(); + } + + + return (int)(origin.Y); +} + +bool ChannelData::checkDown(int x,int y){ + // ”͈͓àƒ`ƒFƒbƒN + if ( + (x > posX) + && (x < posX + getWidth()) + && (y > posY) + && (y < posY + getHeight()) + ){ + return TRUE; + } + return FALSE; +} + +ServentData *ChannelData::findServentData(int servent_id){ + ServentData *sv = serventDataTop; + while(sv){ + if (sv->getServentId() == servent_id){ + return sv; + } + sv = sv->getNextData(); + } + return NULL; +} + +void ChannelData::addServentData(ServentData *sd){ + sd->setNextData(serventDataTop); + serventDataTop = sd; +} + +void ChannelData::deleteDisableServents(){ + ServentData *sd = serventDataTop; + ServentData *prev = NULL; + + while(sd){ + if (!(sd->getEnableFlg())){ + ServentData *next = sd->getNextData(); + if (prev){ + prev->setNextData(next); + } else { + serventDataTop = next; + } + ::delete sd; + sd = next; + } else { + prev = sd; + sd = sd->getNextData(); + } + } +} + +int ChannelData::getServentCount(){ + int ret = 0; + + ServentData *sd = serventDataTop; + while(sd){ + ret++; + sd = sd->getNextData(); + } + return ret; +} + +bool ChannelData::setName(int servent_id, String name){ + ServentData *sd = serventDataTop; + while(sd){ + if (sd->getServentId() == servent_id){ + sd->setName(name); + return TRUE; + } + sd = sd->getNextData(); + } + return FALSE; +} + +void ServentData::setData(Servent *s, ChanHit *hit, unsigned int listeners, unsigned int relays, bool f){ + servent_id = s->servent_id; + type = s->type; + status = s->status; + lastSkipTime = s->lastSkipTime; + host = s->getHost(); + + chanHit.numRelays = hit->numRelays; + chanHit.relay = hit->relay; + chanHit.firewalled = hit->firewalled; + chanHit.version = hit->version; + chanHit.version_vp = hit->version_vp; + chanHit.version_ex_number = hit->version_ex_number; + chanHit.version_ex_prefix[0] = hit->version_ex_prefix[0]; + chanHit.version_ex_prefix[1] = hit->version_ex_prefix[1]; + + totalListeners = listeners; + totalRelays = relays; + + infoFlg = f; +} + +int ServentData::drawServent(Gdiplus::Graphics *g, int x, int y){ + REAL xx = x * 1.0f; + REAL yy = y * 1.0f; + int w,h; + + // ˆÊ’u‚ð•Û‘¶ + posX = x; + posY = y; + + if (getWidth() == 0){ + if (gWS){ + w = gWS; + } else { + w = 400; + } + } else { + w = getWidth(); + gWS = w; + } + + // •`‰æŠî“_ + PointF origin(xx, yy); + + // ƒtƒHƒ“ƒgÝ’è + Font font(L"‚l‚r ‚oƒSƒVƒbƒN",9); + // •¶ŽšF + SolidBrush *strBrush; + if (chanHit.firewalled){ + strBrush = ::new SolidBrush(Color::Red); + } else { + if (getSelected()){ + // ‘I‘ð’† + strBrush = ::new SolidBrush(Color::White); + } else { + // ”ñ‘I‘ð + strBrush = ::new SolidBrush(Color::Black); + } + } + // ServantData•\Ž¦ + g->SetTextRenderingHint(TextRenderingHintAntiAlias); + // •¶Žš—ñì¬ + char tmp[256]; + char host1[256]; + host.toStr(host1); + + if (infoFlg){ + if (chanHit.version_ex_number){ + // Šg’£ƒo[ƒWƒ‡ƒ“ + sprintf(tmp, "%c%c%04d - %d/%d - %s(%s)", + chanHit.version_ex_prefix[0], + chanHit.version_ex_prefix[1], + chanHit.version_ex_number, + totalListeners, + totalRelays, + host1, + hostname.cstr() + ); + } else if (chanHit.version_vp){ + sprintf(tmp, "VP%04d - %d/%d - %s(%s)", + chanHit.version_vp, + totalListeners, + totalRelays, + host1, + hostname.cstr() + ); + } else { + sprintf(tmp, "(-----) - %d/%d - %s(%s)", + totalListeners, + totalRelays, + host1, + hostname.cstr() + ); + } + } else { + sprintf(tmp, "(-----) - %d/%d - %s(%s)", + totalListeners, + totalRelays, + host1, + hostname.cstr() + ); + } + _bstr_t bstr1(tmp); + + // ƒXƒe[ƒ^ƒX•\Ž¦ + Gdiplus::Image *img = NULL; + unsigned int nowTime = sys->getTime(); + switch(getStatus()){ + case Servent::S_CONNECTING: + img = img_connect; + break; + case Servent::S_CONNECTED: + if (lastSkipTime + 120 > nowTime){ + if (chanHit.relay){ + img = img_conn_ok_skip; + } else { + if (chanHit.numRelays){ + img = img_conn_full_skip; + } else { + img = img_conn_over_skip; + } + } + } else { + if (chanHit.relay){ + img = img_conn_ok; + } else { + if (chanHit.numRelays){ + img = img_conn_full; + } else { + img = img_conn_over; + } + } + } + break; + default: + break; + } + + // •¶Žš•`‰æ”͈͎w’è + RectF r1(origin.X + img->GetWidth() + 2, origin.Y, 800.0f, 13.0f); + RectF r2; + StringFormat format; + format.SetAlignment(StringAlignmentNear); + g->MeasureString(bstr1, -1, &font, r1, &format, &r2); + + w = (INT)r2.Width + img->GetWidth() + 2; + // ServentData•\Ž¦•”‚Ì”wŒi‚ð“h‚é + if (getSelected()){ + // ‘I‘ð’† + SolidBrush b(Color(160,49,106,197)); + g->FillRectangle(&b, x, y, w, 13); + } else { + // ”ñ‘I‘ð + SolidBrush b(Color(160,200,200,200)); + g->FillRectangle(&b, x, y, w, 13); + } + + // ƒXƒe[ƒ^ƒX•\Ž¦ˆÊ’u + Rect img_rect((INT)origin.X, (INT)origin.Y+1, img ? img->GetWidth() : 12, 12); + // ƒXƒe[ƒ^ƒX•`‰æ + ImageAttributes att; +// att.SetColorKey(Color::White, Color::White, ColorAdjustTypeBitmap); + g->DrawImage(img, img_rect, 0, 0, img_rect.Width, 12, UnitPixel, &att); + // ŽŸ‚ÌŠî“_ + origin.X += 12; + + g->DrawString(bstr1, -1, &font, r2, &format, strBrush); + // ŽŸ‚ÌŠî“_ + origin.X += r2.Width; + origin.Y += 13; + + setWidth((int)origin.X-posX); + setHeight((int)origin.Y - posY); + + ::delete strBrush; + return 0; +} + +bool ServentData::checkDown(int x, int y){ + if ( + (x > posX) + && (x < posX + getWidth()) + && (y > posY) + && (y < posY + getHeight()) + ){ + return TRUE; + } + return FALSE; +} + + +THREAD_PROC GUIDataUpdate(ThreadInfo *thread){ + int i; + + // set GUI thread status to running + thread->finish = false; + + while(thread->active){ + // ƒ`ƒƒƒ“ƒlƒ‹ƒf[ƒ^ƒƒbƒN + ChannelDataLock.on(); + // ƒ`ƒƒƒ“ƒlƒ‹ƒf[ƒ^‚̍XVƒtƒ‰ƒO‚ð‘S‚ÄFALSE‚É‚·‚é + ChannelData *cd = channelDataTop; + while(cd){ + // Servent‚̍XVƒtƒ‰ƒO‚ðFALSE‚É‚·‚é + ServentData *sv = cd->getServentDataTop(); + while(sv){ + sv->setEnableFlg(FALSE); + sv = sv->getNextData(); + } + cd->setEnableFlg(FALSE); + cd = cd->getNextData(); + } + + Channel *c = chanMgr->channel; + // Œ»Ý‘¶Ý‚·‚éƒ`ƒƒƒ“ƒlƒ‹•ªƒ‹[ƒv + while(c){ + // Šù‚Ƀ`ƒƒƒ“ƒlƒ‹ƒf[ƒ^‚ðŽ‚Á‚Ä‚¢‚é‚© + cd = channelDataTop; + // ”­Œ©ƒtƒ‰ƒOFALSE + bool bFoundFlg = FALSE; + while(cd){ + if (cd->getChannelId() == c->channel_id){ + //Šù‚Ƀ`ƒƒƒ“ƒlƒ‹ƒf[ƒ^‚ª‚ ‚é‚̂ŁA‚»‚̂܂܍XV + cd->setData(c); + // XVƒtƒ‰ƒOTRUE + cd->setEnableFlg(TRUE); + // ”­Œ©ƒtƒ‰ƒOTRUE + bFoundFlg = TRUE; + // ƒ‹[ƒv—£’E + break; + } + // Œ©‚‚©‚ç‚È‚©‚Á‚½ê‡AŽŸ‚̃f[ƒ^‚ðƒ`ƒFƒbƒN + cd = cd->getNextData(); + } + + // V‚µ‚¢ƒ`ƒƒƒ“ƒlƒ‹‚̏ꍇAV‹Kƒf[ƒ^ì¬ + if (!bFoundFlg){ + // V‹Kƒf[ƒ^ì¬ + cd = ::new ChannelData(); + // ƒf[ƒ^XV + cd->setData(c); + // XVƒtƒ‰ƒOTRUE + cd->setEnableFlg(TRUE); + + // V‹Kƒf[ƒ^‚ðƒŠƒXƒg‚̐擪‚É“ü‚ê‚é + cd->setNextData(channelDataTop); + channelDataTop = cd; + } + // ŽŸ‚̃`ƒƒƒ“ƒlƒ‹‚ðŽæ“¾ + c = c->next; + } + + // ƒ`ƒƒƒ“ƒlƒ‹‚ª‚È‚­‚È‚Á‚Ä‚¢‚éê‡‚̏ˆ— + cd = channelDataTop; + ChannelData *prev = NULL; + while(cd){ + // ƒf[ƒ^‚ðXV‚µ‚È‚©‚Á‚½‚© + if (cd->getEnableFlg() == FALSE){ + // ƒ`ƒƒƒ“ƒlƒ‹‚ª‚È‚­‚È‚Á‚Ä‚¢‚é‚̂ō폜 + ChannelData *next; + next = cd->getNextData(); + if (!prev){ + // æ“ª‚̃f[ƒ^‚ðíœ + channelDataTop = next; + } else { + // “r’†‚̃f[ƒ^‚ðíœ + prev->setNextData(next); + } + // ŽŸ‚̃f[ƒ^‚Ö + cd = next; + } else { + // ƒf[ƒ^XVÏFŽŸ‚̃f[ƒ^‚Ö + prev = cd; + cd = cd->getNextData(); + } + } + + Servent *s = servMgr->servents; + while(s){ + // ‰Šú‰» + ChanHitList *chl; + bool infoFlg = false; + bool relay = true; + bool firewalled = false; + unsigned int numRelays = 0; + int vp_ver = 0; + char ver_ex_prefix[2] = {' ',' '}; + int ver_ex_number = 0; + // ’¼‰ºƒzƒXƒgî•ñƒ`ƒFƒbƒN + unsigned int totalRelays = 0; + unsigned int totalListeners = 0; + + ChanHit hitData; + // ŽóM’†‚© + if ((s->type == Servent::T_RELAY) && (s->status == Servent::S_CONNECTED)){ + // ƒzƒXƒgî•ñƒƒbƒN + chanMgr->hitlistlock.on(); + // ’¼‰ºƒzƒXƒg‚ªŽóM‚µ‚Ä‚¢‚éƒ`ƒƒƒ“ƒlƒ‹‚̃zƒXƒgî•ñ‚ðŽæ“¾ + chl = chanMgr->findHitListByID(s->chanID); + // ƒ`ƒƒƒ“ƒlƒ‹‚̃zƒXƒgî•ñ‚ª‚ ‚é‚© + if (chl){ + // ƒ`ƒƒƒ“ƒlƒ‹‚̃zƒXƒgî•ñ‚ª‚ ‚éê‡ + ChanHit *hit = chl->hit; + //@ƒ`ƒƒƒ“ƒlƒ‹‚̃zƒXƒgî•ñ‚ð‘S‘–¸‚µ‚Ä + while(hit){ + // ID‚ª“¯‚¶‚à‚Ì‚Å‚ ‚ê‚Î + if (hit->servent_id == s->servent_id){ + // ƒg[ƒ^ƒ‹ƒŠƒŒ[‚ƃg[ƒ^ƒ‹ƒŠƒXƒi[‚ð‰ÁŽZ + totalRelays += hit->numRelays; + totalListeners += hit->numListeners; + // ’¼‰º‚Å‚ ‚ê‚Î + if (hit->numHops == 1){ + // î•ñ‚ðˆê’U•Û‘¶ + infoFlg = true; + hitData.relay = hit->relay; + hitData.firewalled = hit->firewalled; + hitData.numRelays = hit->numRelays; + hitData.version_vp = hit->version_vp; + hitData.version_ex_prefix[0] = hit->version_ex_prefix[0]; + hitData.version_ex_prefix[1] = hit->version_ex_prefix[1]; + hitData.version_ex_number = hit->version_ex_number; + } + } + // ŽŸ‚ðƒ`ƒFƒbƒN + hit = hit->next; + } + } + + // ƒ`ƒƒƒ“ƒlƒ‹ƒf[ƒ^‚©‚çServent‚ðŒŸõ + bool bFoundFlg = FALSE; + cd = channelDataTop; + while(cd){ + ServentData *sv = cd->findServentData(s->servent_id); + // ServentData‚ª‚ ‚ê‚Î + if (sv){ + // ƒf[ƒ^Ý’è + sv->setData(s, &hitData, totalListeners, totalRelays, infoFlg); + sv->setEnableFlg(TRUE); + bFoundFlg = TRUE; + break; + } + cd = cd->getNextData(); + } + // ServentData‚ªŒ©‚‚©‚ç‚È‚©‚Á‚½ê‡ + if (!bFoundFlg){ + // ƒ`ƒƒƒ“ƒlƒ‹ƒf[ƒ^‚ð’T‚· + cd = channelDataTop; + while(cd){ + // ƒ`ƒƒƒ“ƒlƒ‹ID‚ª“¯‚¶‚© + if (cd->getChannelId() == s->channel_id){ + // ƒf[ƒ^Ý’è + ServentData *sv = ::new ServentData(); + sv->setData(s, &hitData, totalListeners, totalRelays, infoFlg); + sv->setEnableFlg(TRUE); + // ƒ`ƒƒƒ“ƒlƒ‹ƒf[ƒ^‚ÉServentData’ljÁ + cd->addServentData(sv); + // ƒzƒXƒg–¼‚ðŽæ“¾‚·‚é + IdData *id = ::new IdData(cd->getChannelId(), sv->getServentId(), sv->getHost().ip); + ThreadInfo t; + t.func = GetHostName; + t.data = (void*)id; + sys->startThread(&t); + // ƒ‹[ƒvI—¹ + break; + } + // ŽŸ‚̃f[ƒ^‚Ö + cd = cd->getNextData(); + } + } + // ƒzƒXƒgî•ñƒAƒ“ƒƒbƒN + chanMgr->hitlistlock.off(); + } + s = s->next; + } + + // XV‚µ‚Ä‚¢‚È‚¢ServentData‚ðíœ + cd = channelDataTop; + while(cd){ + cd->deleteDisableServents(); + cd = cd->getNextData(); + } + + // ƒ`ƒƒƒ“ƒlƒ‹ƒf[ƒ^ƒAƒ“ƒƒbƒN + ChannelDataLock.off(); + + // •`‰æXV + if (guiWnd){ + MakeBack(guiWnd); + } + + // 0.1•b~10‚Å1•b‘Ò‚¿ + for(i=0; i<10; i++) + { + if (!thread->active) + break; + sys->sleep(100); + } + + if (gbGetFile && (sys->getTime() > gtGetFile)){ + gbGetFile = false; + gtiGetFile.func = GetInternetFile; + gtiGetFile.data = NULL; + sys->startThread(>iGetFile); + } + else if (gbStart && (sys->getTime() > gtStartTime)){ + gbStart = false; + SendMessage(guiWnd, WM_START, 0, 0); + gtiStart.func = FestivalStart; + gtiStart.data = NULL; + sys->startThread(>iStart); + } + } + + // set GUI thread status to terminated + thread->finish = true; + + return 0; +} + +ChannelData *findChannelData(int channel_id){ + ChannelData *cd = channelDataTop; + + while(cd){ + if (cd->getChannelId() == channel_id){ + return cd; + } + cd = cd->getNextData(); + } + + return NULL; +} + + +void PopupChannelMenu(int channel_id){ + POINT pos; + MENUITEMINFO info, separator; + HMENU hMenu; + DWORD dwID; + + hMenu = CreatePopupMenu(); + + memset(&separator, 0, sizeof(MENUITEMINFO)); + separator.cbSize = sizeof(MENUITEMINFO); + separator.fMask = MIIM_ID | MIIM_TYPE; + separator.fType = MFT_SEPARATOR; + separator.wID = 8000; + + memset(&info, 0, sizeof(MENUITEMINFO)); + info.cbSize = sizeof(MENUITEMINFO); + info.fMask = MIIM_ID | MIIM_TYPE; + info.fType = MFT_STRING; + + ChannelData *cd = findChannelData(channel_id); + + if (cd == NULL){ + return; + } + + info.wID = 1001; + info.dwTypeData = "Ø’f"; + InsertMenuItem(hMenu, -1, true, &info); + + InsertMenuItem(hMenu, -1, true, &separator); + + info.wID = 1000; + info.dwTypeData = "Ä¶"; + InsertMenuItem(hMenu, -1, true, &info); + + InsertMenuItem(hMenu, -1, true, &separator); + + info.wID = 1002; + info.dwTypeData = "ÄÚ‘±"; + InsertMenuItem(hMenu, -1, true, &info); + + info.wID = 1003; + info.dwTypeData = "ƒL[ƒv"; + InsertMenuItem(hMenu, -1, true, &info); + + InsertMenuItem(hMenu, -1, true, &separator); + + if (!cd->getOpenFlg()){ + info.wID = 1004; + info.dwTypeData = "’¼‰º•\Ž¦"; + InsertMenuItem(hMenu, -1, true, &info); + } else { + info.wID = 1005; + info.dwTypeData = "’¼‰º‰B•Á"; + InsertMenuItem(hMenu, -1, true, &info); + } + + GetCursorPos(&pos); + dwID = TrackPopupMenu(hMenu, TPM_LEFTALIGN|TPM_RETURNCMD, pos.x, pos.y, 0, guiWnd, NULL); + + DestroyMenu(hMenu); + + cd = findChannelData(channel_id); + + if (cd == NULL){ + return; + } + + Channel *c = chanMgr->findChannelByChannelID(channel_id); + + if (c == NULL){ + return; + } + + switch(dwID){ + case 1000: // Ä¶ + chanMgr->playChannel(c->info); + break; + + case 1001: // Ø’f + c->thread.active = false; + c->thread.finish = true; + break; + + case 1002: // ÄÚ‘± + c->bump = true; + break; + + case 1003: // ƒL[ƒv + if (!c->stayConnected){ + c->stayConnected = true; + } else { + c->stayConnected = false; + } + break; + + case 1004: // ’¼‰º•\Ž¦ + cd->setOpenFlg(TRUE); + MakeBack(guiWnd); + break; + + case 1005: // ’¼‰º‰B•Á + cd->setOpenFlg(FALSE); + MakeBack(guiWnd); + break; + } +} + +void PopupServentMenu(int servent_id){ + POINT pos; + MENUITEMINFO info, separator; + HMENU hMenu; + DWORD dwID; + + hMenu = CreatePopupMenu(); + + memset(&separator, 0, sizeof(MENUITEMINFO)); + separator.cbSize = sizeof(MENUITEMINFO); + separator.fMask = MIIM_ID | MIIM_TYPE; + separator.fType = MFT_SEPARATOR; + separator.wID = 8000; + + memset(&info, 0, sizeof(MENUITEMINFO)); + info.cbSize = sizeof(MENUITEMINFO); + info.fMask = MIIM_ID | MIIM_TYPE; + info.fType = MFT_STRING; + + ServentData *sd = NULL; + ChannelData *cd = channelDataTop; + while(cd){ + sd = cd->findServentData(servent_id); + if (sd){ + break; + } + cd = cd->getNextData(); + } + + if (cd == NULL || sd == NULL){ + return; + } + + info.wID = 1001; + info.dwTypeData = "Ø’f"; + InsertMenuItem(hMenu, -1, true, &info); + +// InsertMenuItem(hMenu, -1, true, &separator); + + GetCursorPos(&pos); + dwID = TrackPopupMenu(hMenu, TPM_LEFTALIGN|TPM_RETURNCMD, pos.x, pos.y, 0, guiWnd, NULL); + + DestroyMenu(hMenu); + + cd = channelDataTop; + while(cd){ + sd = cd->findServentData(servent_id); + if (sd){ + break; + } + cd = cd->getNextData(); + } + + if (cd == NULL || sd == NULL){ + return; + } + + Servent *s = servMgr->findServentByServentID(servent_id); + + if (s == NULL){ + return; + } + + switch(dwID){ + case 1001: // Ø’f + s->thread.active = false; + break; + + } +} + +void PopupOtherMenu(){ + POINT pos; + MENUITEMINFO info, separator; + HMENU hMenu; + DWORD dwID; + + hMenu = CreatePopupMenu(); + + memset(&separator, 0, sizeof(MENUITEMINFO)); + separator.cbSize = sizeof(MENUITEMINFO); + separator.fMask = MIIM_ID | MIIM_TYPE; + separator.fType = MFT_SEPARATOR; + separator.wID = 8000; + + memset(&info, 0, sizeof(MENUITEMINFO)); + info.cbSize = sizeof(MENUITEMINFO); + info.fMask = MIIM_ID | MIIM_TYPE; + info.fType = MFT_STRING; + + if (!gbDispTop){ + info.wID = 1101; + info.dwTypeData = "Å‘O–Ê•\Ž¦"; + InsertMenuItem(hMenu, -1, true, &info); + } else { + info.wID = 1102; + info.dwTypeData = "Å‘O–ʉðœ"; + InsertMenuItem(hMenu, -1, true, &info); + } + + InsertMenuItem(hMenu, -1, true, &separator); + + if (!gbAllOpen){ + info.wID = 1103; + info.dwTypeData = "‘S’¼‰º“WŠJ"; + InsertMenuItem(hMenu, -1, true, &info); + } else { + info.wID = 1104; + info.dwTypeData = "‘S’¼‰º‰B•Á"; + InsertMenuItem(hMenu, -1, true, &info); + } + + InsertMenuItem(hMenu, -1, true, &separator); + + if (!servMgr->autoServe){ + info.wID = 1105; + info.dwTypeData = "—LŒø"; + InsertMenuItem(hMenu, -1, true, &info); + } else { + info.wID = 1106; + info.dwTypeData = "–³Œø"; + InsertMenuItem(hMenu, -1, true, &info); + } + + GetCursorPos(&pos); + dwID = TrackPopupMenu(hMenu, TPM_LEFTALIGN|TPM_RETURNCMD, pos.x, pos.y, 0, guiWnd, NULL); + + DestroyMenu(hMenu); + + ChannelData *cd = channelDataTop; + + switch(dwID){ + case 1101: // Å‘O–Ê•\Ž¦ + gbDispTop = true; + ::SetWindowPos(guiWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE); + break; + + case 1102: // Å‘O–Ê‰ðœ + gbDispTop = false; + ::SetWindowPos(guiWnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE); + break; + + case 1103: // ‘S’¼‰º“WŠJ + gbAllOpen = true; + while(cd){ + cd->setOpenFlg(true); + cd = cd->getNextData(); + } + break; + + case 1104: // ‘S’¼‰º‰B•Á + gbAllOpen = false; + while(cd){ + cd->setOpenFlg(false); + cd = cd->getNextData(); + } + break; + + case 1105: // —LŒø + servMgr->autoServe = true; + break; + + case 1106: // –³Œø + servMgr->autoServe = false; + break; + + } +} + +void WmCreateProc(HWND hwnd){ + if (backImage){ + ::delete backImage; + } + _bstr_t bstr("back.jpg"); + backImage = ::new Image(bstr); + + MakeBack(hwnd, 800, 600); + + guiThread.func = GUIDataUpdate; + if (!sys->startThread(&guiThread)){ + MessageBox(hwnd,"Unable to start GUI","PeerCast",MB_OK|MB_ICONERROR); + PostMessage(hwnd,WM_DESTROY,0,0); + } + if (guiFlg){ + SetWindowPlacement(hwnd, &winPlace); + } + + if (img_idle){ + ::delete img_idle; + ::delete img_connect; + ::delete img_conn_ok; + ::delete img_conn_full; + ::delete img_conn_over; + ::delete img_conn_ok_skip; + ::delete img_conn_full_skip; + ::delete img_conn_over_skip; + ::delete img_error; + ::delete img_broad_ok; + ::delete img_broad_full; + } + bstr = L"ST_IDLE.bmp"; + img_idle = ::new Image(bstr); + bstr = L"ST_CONNECT.bmp"; + img_connect = ::new Image(bstr); + bstr = L"ST_CONN_OK.bmp"; + img_conn_ok = ::new Image(bstr); + bstr = L"ST_CONN_FULL.bmp"; + img_conn_full = ::new Image(bstr); + bstr = L"ST_CONN_OVER.bmp"; + img_conn_over = ::new Image(bstr); + bstr = L"ST_CONN_OK_SKIP.bmp"; + img_conn_ok_skip = ::new Image(bstr); + bstr = L"ST_CONN_FULL_SKIP.bmp"; + img_conn_full_skip = ::new Image(bstr); + bstr = L"ST_CONN_OVER_SKIP.bmp"; + img_conn_over_skip = ::new Image(bstr); + bstr = L"ST_ERROR.bmp"; + img_error = ::new Image(bstr); + bstr = L"ST_BROAD_OK.bmp"; + img_broad_ok = ::new Image(bstr); + bstr = L"ST_BROAD_FULL.bmp"; + img_broad_full = ::new Image(bstr); +} + +void WmPaintProc(HWND hwnd){ + HDC hdc; + PAINTSTRUCT paint; + + if (backGra){ + MakeBackLock.on(); + hdc = BeginPaint(hwnd, &paint); + RECT *rcRect; // •`‰æ”ÍˆÍ + rcRect = &(paint.rcPaint); + LONG width = rcRect->right - rcRect->left + 1; + LONG height = rcRect->bottom - rcRect->top + 1; + + Graphics g2(hdc); + Rect r(rcRect->left, rcRect->top, width, height); + g2.DrawImage(backBmp,r, rcRect->left, rcRect->top, width, height, UnitPixel); + EndPaint(hwnd, &paint); + MakeBackLock.off(); + } +} + +void WmSizeProc(HWND hwnd, LPARAM lParam){ + UINT width = LOWORD(lParam); + UINT height = HIWORD(lParam); + + MakeBack(hwnd, width, height); + +} + +void WmLButtonDownProc(HWND hwnd, LPARAM lParam){ + ChannelData *cd; + bool changeFlg = FALSE; + + ChannelDataLock.on(); + cd = channelDataTop; + while(cd){ + int x = LOWORD(lParam); + int y = HIWORD(lParam); + if (cd->checkDown(LOWORD(lParam), HIWORD(lParam))){ + if (!(cd->isSelected())){ + changeFlg = TRUE; + } + cd->setSelected(TRUE); + } else { + if (cd->isSelected()){ + changeFlg = TRUE; + } + cd->setSelected(FALSE); + } + int sx = cd->getPosX() + cd->getWidth(); + int sy = cd->getPosY(); + int index = 0; + ServentData *sd = cd->getServentDataTop(); + while(sd){ + if ( ( (!cd->getOpenFlg()) + && (sx + index*14 < x) + && (x < sx + (index+1)*14) + && (sy < y) + && (y < sy + 14) ) + || sd->checkDown(LOWORD(lParam), HIWORD(lParam)) + ){ + if (!sd->getSelected()){ + changeFlg = TRUE; + } + sd->setSelected(TRUE); + } else { + if (sd->getSelected()){ + changeFlg = TRUE; + } + sd->setSelected(FALSE); + } + sd = sd->getNextData(); + index++; + } + cd = cd->getNextData(); + } + ChannelDataLock.off(); + if (changeFlg){ + MakeBack(hwnd); + } +} + +void WmLButtonDblclkProc(HWND hwnd, LPARAM lParam){ + ChannelData *cd; + bool changeFlg = FALSE; + + ChannelDataLock.on(); + cd = channelDataTop; + while(cd){ + int x = LOWORD(lParam); + int y = HIWORD(lParam); + if (cd->checkDown(LOWORD(lParam), HIWORD(lParam))){ + if (!(cd->isSelected())){ + changeFlg = TRUE; + } + if (!(cd->getOpenFlg())){ + changeFlg = TRUE; + cd->setOpenFlg(TRUE); + } else { + changeFlg = TRUE; + cd->setOpenFlg(FALSE); + } + cd->setSelected(TRUE); + } else { + if (cd->isSelected()){ + changeFlg = TRUE; + } + cd->setSelected(FALSE); + } +/* int sx = cd->getPosX() + cd->getWidth(); + int sy = cd->getPosY(); + int index = 0; + ServentData *sd = cd->getServentDataTop(); + while(sd){ + if ( ( (!cd->getOpenFlg()) + && (sx + index*14 < x) + && (x < sx + (index+1)*14) + && (sy < y) + && (y < sy + 14) ) + || sd->checkDown(LOWORD(lParam), HIWORD(lParam)) + ){ + if (!sd->getSelected()){ + changeFlg = TRUE; + } + sd->setSelected(TRUE); + } else { + if (sd->getSelected()){ + changeFlg = TRUE; + } + sd->setSelected(FALSE); + } + sd = sd->getNextData(); + index++; + }*/ + cd = cd->getNextData(); + } + ChannelDataLock.off(); + if (changeFlg){ + MakeBack(hwnd); + } +} + +void WmRButtonDownProc(HWND hwnd, LPARAM lParam){ + ChannelData *cd; + bool changeFlg = FALSE; + bool channel_selected = FALSE; + bool servent_selected = FALSE; + int channel_id = 0; + int servent_id = 0; + + cd = channelDataTop; + while(cd){ + if (cd->checkDown(LOWORD(lParam), HIWORD(lParam))){ + if (!(cd->isSelected())){ + changeFlg = TRUE; + } + cd->setSelected(TRUE); + channel_id = cd->getChannelId(); + channel_selected = TRUE; + } else { + if (cd->isSelected()){ + changeFlg = TRUE; + } + cd->setSelected(FALSE); + } + ServentData *sd = cd->getServentDataTop(); + while(sd){ + if (sd->checkDown(LOWORD(lParam), HIWORD(lParam))){ + if (!sd->getSelected()){ + changeFlg = TRUE; + } + sd->setSelected(TRUE); + servent_id = sd->getServentId(); + servent_selected = TRUE; + } else { + if (sd->getSelected()){ + changeFlg = TRUE; + } + sd->setSelected(FALSE); + } + sd = sd->getNextData(); + } + cd = cd->getNextData(); + } + if (changeFlg){ + MakeBack(hwnd); + } + + if (channel_selected){ + PopupChannelMenu(channel_id); + } else if (servent_selected){ + PopupServentMenu(servent_id); + } else { + PopupOtherMenu(); + } +} + +LRESULT CALLBACK GUIProc (HWND hwnd, UINT message, + WPARAM wParam, LPARAM lParam) +{ + switch(message){ + case WM_CREATE: // ƒEƒBƒ“ƒhƒEì¬ + WmCreateProc(hwnd); + break; + + case WM_PAINT: // •`‰æ + WmPaintProc(hwnd); + break; + + case WM_SIZE: // ƒTƒCƒY•ÏX + WmSizeProc(hwnd,lParam); + break; + + case WM_LBUTTONDOWN: // ¶ƒ{ƒ^ƒ“‰Ÿ‚· + WmLButtonDownProc(hwnd,lParam); + break; + + case WM_RBUTTONDOWN: // ‰Eƒ{ƒ^ƒ“‰Ÿ‚· + WmRButtonDownProc(hwnd,lParam); + break; + + case WM_LBUTTONDBLCLK: // ¶ƒ_ƒuƒ‹ƒNƒŠƒbƒN + WmLButtonDblclkProc(hwnd,lParam); + break; + + case WM_ERASEBKGND: // ”wŒiÁ‹Ž + return TRUE; // ”wŒi‚͏Á‚³‚È‚¢ + + case WM_CLOSE: + //if (backImage){ + // ::delete backImage; + // backImage = NULL; + //} + GetWindowPlacement(hwnd, &winPlace); + guiFlg = true; + DestroyWindow( hwnd ); + break; + case WM_DESTROY: + GetWindowPlacement(hwnd, &winPlace); + guiFlg = true; + guiThread.active = false; + + // wait until GUI thread terminated, + // and then dispose background image. + while (1) + { + if (guiThread.finish) + break; + } + if (backImage) + { + ::delete backImage; + backImage = NULL; + } + + guiWnd = NULL; + break; + case WM_START: + ghStart = ::CreateWindow(szWindowClass3, + "Peercast-IM@S", + WS_OVERLAPPEDWINDOW & ~(WS_MAXIMIZEBOX), + 0, + 0, + 400, + 300, + NULL, + NULL, + hInst, + NULL); + ::ShowWindow(ghStart, SW_SHOWNORMAL); + break; + + default: + return (DefWindowProc(hwnd, message, wParam, lParam)); + } + + return 0; +} + +Gdiplus::Image *data1 = NULL; +Gdiplus::Image *data2 = NULL; +Gdiplus::Bitmap *startBmp = NULL; +Gdiplus::Graphics *startGra = NULL; +WLock MakeStartLock; + +LRESULT CALLBACK StartProc (HWND hwnd, UINT message, + WPARAM wParam, LPARAM lParam) +{ + SolidBrush b(Color::Black); + bstr_t bstr; + + switch(message){ + case WM_CREATE: + startBmp = ::new Bitmap(400,300); + startGra = ::new Graphics(startBmp); + bstr = L"data1.jpg"; + data1 = ::new Image(bstr); + bstr = L"data2.jpg"; + data2 = ::new Image(bstr); + // •‚Å“h‚è‚‚Ԃµ + startGra->FillRectangle(&b, 0, 0, 400, 300); + break; + case WM_PAINT: + if (startGra){ + HDC hdc; + PAINTSTRUCT paint; + + MakeStartLock.on(); + hdc = BeginPaint(hwnd, &paint); + RECT *rcRect; + rcRect = &(paint.rcPaint); + LONG width = rcRect->right - rcRect->left + 1; + LONG height = rcRect->bottom - rcRect->top + 1; + + Graphics g2(hdc); + Rect r(rcRect->left, rcRect->top, width, height); + g2.DrawImage(startBmp, r, rcRect->left, rcRect->top, width, height, UnitPixel); + EndPaint(hwnd, &paint); + MakeStartLock.off(); + } + break; + case WM_ERASEBKGND: + return TRUE; + case WM_CLOSE: + DestroyWindow(ghStart); + if (startBmp){ + ::delete startBmp; + } + if (startGra){ + ::delete startGra; + } + if (data1){ + ::delete data1; + } + if (data2){ + ::delete data2; + } + break; + + default: + return (DefWindowProc(hwnd, message, wParam, lParam)); + } + + return 0; +} + +THREAD_PROC FestivalStart(ThreadInfo *thread){ + + while(startGra==NULL){ + sys->sleep(100); + } + + sys->sleep(1000); + + MakeStartLock.on(); + Font font(L"‚l‚r ‚oƒSƒVƒbƒN",40); + StringFormat format; + format.SetAlignment(StringAlignmentCenter); + startGra->SetTextRenderingHint(TextRenderingHintAntiAlias); + PointF origin(199.0f,49.0f); + RectF rect(0,0,400,100); + LinearGradientBrush b1(rect, Color::LightSkyBlue, Color::White, LinearGradientModeHorizontal); + startGra->DrawString(L"‘æ‚Q‰ñ", -1, &font, origin, &format, &b1); + origin.Y += 50; + LinearGradientBrush b2(rect, Color::LightGreen, Color::White, LinearGradientModeHorizontal); + startGra->DrawString(L"ƒAƒCƒhƒ‹ƒ}ƒXƒ^[", -1, &font, origin, &format, &b2); + origin.Y += 50; + LinearGradientBrush b3(rect, Color::LightGoldenrodYellow, Color::White, LinearGradientModeHorizontal); + startGra->DrawString(L"ƒtƒ@ƒ“Š´ŽÓÕ", -1, &font, origin, &format, &b3); + MakeStartLock.off(); + InvalidateRect(ghStart, NULL, FALSE); + sys->sleep(3000); + + MakeStartLock.on(); + startGra->DrawImage(data1, Rect(0,0,80,400), 200,200,66,330, UnitPixel); + MakeStartLock.off(); + InvalidateRect(ghStart, NULL, FALSE); + sys->sleep(500); + + MakeStartLock.on(); + startGra->DrawImage(data1, Rect(80,0,80,400), 266,200,66,330, UnitPixel); + MakeStartLock.off(); + InvalidateRect(ghStart, NULL, FALSE); + sys->sleep(500); + + MakeStartLock.on(); + startGra->DrawImage(data1, Rect(160,0,80,400), 332,200,66,330, UnitPixel); + MakeStartLock.off(); + InvalidateRect(ghStart, NULL, FALSE); + sys->sleep(500); + + MakeStartLock.on(); + startGra->DrawImage(data1, Rect(240,0,80,400), 398,200,66,330, UnitPixel); + MakeStartLock.off(); + InvalidateRect(ghStart, NULL, FALSE); + sys->sleep(500); + + MakeStartLock.on(); + startGra->DrawImage(data1, Rect(320,0,80,400), 464,200,66,330, UnitPixel); + MakeStartLock.off(); + InvalidateRect(ghStart, NULL, FALSE); + sys->sleep(500); + + MakeStartLock.on(); + startGra->DrawImage(data1, Rect(0,0,80,400), 530,200,54,270, UnitPixel); + MakeStartLock.off(); + InvalidateRect(ghStart, NULL, FALSE); + sys->sleep(500); + + MakeStartLock.on(); + startGra->DrawImage(data1, Rect(80,0,80,400), 584,200,54,270, UnitPixel); + MakeStartLock.off(); + InvalidateRect(ghStart, NULL, FALSE); + sys->sleep(500); + + MakeStartLock.on(); + startGra->DrawImage(data1, Rect(160,0,80,400), 638,200,54,270, UnitPixel); + MakeStartLock.off(); + InvalidateRect(ghStart, NULL, FALSE); + sys->sleep(500); + + MakeStartLock.on(); + startGra->DrawImage(data1, Rect(240,0,80,400), 692,200,54,270, UnitPixel); + MakeStartLock.off(); + InvalidateRect(ghStart, NULL, FALSE); + sys->sleep(500); + + MakeStartLock.on(); + startGra->DrawImage(data1, Rect(320,0,80,400), 746,200,54,270, UnitPixel); + MakeStartLock.off(); + InvalidateRect(ghStart, NULL, FALSE); + sys->sleep(500); + + for (int i=1; i<=10; i++){ + ColorMatrix mtx = { + 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.1f*i, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}; + ImageAttributes att; + + MakeStartLock.on(); + att.SetColorMatrix(&mtx, ColorMatrixFlagsDefault, ColorAdjustTypeBitmap); + startGra->DrawImage(data2, Rect(0,0,400,300), 360,130,400,300, UnitPixel, &att); + MakeStartLock.off(); + InvalidateRect(ghStart, NULL, FALSE); + sys->sleep(100); + } + + sys->sleep(2000); + + MakeStartLock.on(); + INT style = FontStyleBold; + Font font2(L"‚l‚r ‚oƒSƒVƒbƒN",70,style,UnitPoint); + PointF origin2(199.0f,99.0f); + SolidBrush bs(Color::Black); + startGra->DrawString(L"START!", -1, &font2, origin2, &format, &bs); + Font font3(L"‚l‚r ‚oƒSƒVƒbƒN",70,style,UnitPoint); + LinearGradientBrush bx(rect, Color::LightPink, Color::DeepPink, LinearGradientModeHorizontal); + startGra->DrawString(L"START!", -1, &font3, origin2, &format, &bx); + MakeStartLock.off(); + InvalidateRect(ghStart, NULL, FALSE); + sys->sleep(5000); + + SendMessage(ghStart, WM_CLOSE, 0, 0); + return 0; +} diff --git a/c:/Git/PeerCast.root/PeerCast/ui/win32/simple/gui.h b/c:/Git/PeerCast.root/PeerCast/ui/win32/simple/gui.h new file mode 100644 index 0000000..84e7381 --- /dev/null +++ b/c:/Git/PeerCast.root/PeerCast/ui/win32/simple/gui.h @@ -0,0 +1,228 @@ +// ------------------------------------------------ +// File : gui.h +// Date: 4-apr-2002 +// Author: giles +// +// (c) 2002 peercast.org +// ------------------------------------------------ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// ------------------------------------------------ + +#ifndef _GUI_H +#define _GUI_H + +#include "sys.h" +#include "gdiplus.h" +#include "channel.h" + +extern LRESULT CALLBACK GUIProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); +extern LRESULT CALLBACK StartProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); +extern void ADDLOG(const char *str,int id,bool sel,void *data, LogBuffer::TYPE type); + +extern String iniFileName; +extern HWND guiWnd; +extern int logID; + +enum +{ + WM_INITSETTINGS = WM_USER, + WM_GETPORTNUMBER, + WM_PLAYCHANNEL, + WM_TRAYICON, + WM_SHOWGUI, + WM_SHOWMENU, + WM_PROCURL, + WM_START + +}; + +class IdData +{ +private: + int channel_id; + int servent_id; + unsigned int ip_addr; + +public: + IdData(int cid, int sid, unsigned int ip){ + channel_id = cid; + servent_id = sid; + ip_addr = ip; + } + + int getChannelId(){return channel_id;}; + int getServentId(){return servent_id;}; + unsigned int getIpAddr(){return ip_addr;}; +}; + +class ServentData +{ +private: + int servent_id; + int type; +// unsigned int tnum; + int status; +// String agent; + Host host; + String hostname; +// unsigned int syncpos; +// char *typeStr; +// char *statusStr; +// bool infoFlg; +// bool relay; +// bool firewalled; + unsigned int totalRelays; + unsigned int totalListeners; +// int vp_ver; +// char ver_ex_prefix[2]; +// int ver_ex_number; + + bool EnableFlg; + bool infoFlg; + ServentData *next; + ChanHit chanHit; + bool selected; + int posX; + int posY; + int width; + int height; + + unsigned int lastSkipTime; + unsigned int lastSkipCount; + +public: + ServentData(){ + next = NULL; + EnableFlg = false; + infoFlg = false; + + posX = 0; + posY = 0; + width = 0; + selected = false; + + } + void setData(Servent *s, ChanHit *hit, unsigned int listeners, unsigned int relays, bool infoFlg); + bool getInfoFlg(){return infoFlg;} + ChanHit *getChanHit(){return &chanHit;}; + int getStatus(){return status;}; + Host getHost(){return host;}; + + int getServentId(){return servent_id;}; + + bool getEnableFlg(){return EnableFlg;}; + void setEnableFlg(bool f){EnableFlg = f;}; + ServentData *getNextData(){return next;}; + void setNextData(ServentData *s){next = s;}; + bool getSelected(){return selected;}; + void setSelected(bool f){selected = f; if (!f){posX=0;posY=0;}}; + int getWidth(){return width;}; + void setWidth(int w){width = w;}; + int getHeight(){return height;}; + void setHeight(int h){height = h;}; + String getName(){return hostname;}; + void setName(String n){hostname = n;}; + + int drawServent(Gdiplus::Graphics *g, int x, int y); + + bool checkDown(int x, int y); + +}; + +class ChannelData { + +private: + int channel_id; + char name[257]; + int bitRate; + unsigned int lastPlayStart; + int status; + int totalListeners; + int totalRelays; + int localListeners; + int localRelays; + bool stayConnected; + ChanHit chDisp; + bool bTracker; + unsigned int lastSkipTime; + unsigned int skipCount; + + bool EnableFlg; + ChannelData *next; + + int posX; + int posY; + int width; + int height; + bool selected; + ServentData *serventDataTop; + bool openFlg; + +public: + ChannelData(){ + EnableFlg = FALSE; + next = NULL; + posX = 0; + posY = 0; + width = 0; + height = 0; + selected = FALSE; + serventDataTop = NULL; + openFlg = FALSE; + } + int drawChannel(Gdiplus::Graphics *g, int x, int y); + + void setData(Channel *); + int getChannelId(){return channel_id;}; + char* getName(){return &(name[0]);}; + int getBitRate(){return bitRate;}; + bool isStayConnected(){return stayConnected;}; + bool isTracker(){return bTracker;}; + int getStatus(){return status;}; + unsigned int getLastSkipTime(){return lastSkipTime;}; + + int getTotalListeners(){return totalListeners;}; + int getTotalRelays(){return totalRelays;}; + int getLocalListeners(){return localListeners;}; + int getLocalRelays(){return localRelays;}; + + bool getEnableFlg(){return EnableFlg;}; + void setEnableFlg(bool flg){EnableFlg = flg;}; + ChannelData *getNextData(){return next;}; + void setNextData(ChannelData* cd){next = cd;}; + + int getPosX(){return posX;}; + void setPosX(int x){posX = x;} + int getPosY(){return posY;}; + void setPosY(int y){posY = y;}; + int getWidth(){return width;}; + void setWidth(int w){width = w;}; + int getHeight(){return height;}; + void setHeight(int h){height = h;}; + bool isSelected(){return selected;}; + void setSelected(bool sel){selected = sel;}; + bool getOpenFlg(){return openFlg;}; + void setOpenFlg(bool b){openFlg = b;}; + + ServentData* getServentDataTop(){return serventDataTop;}; + ServentData* findServentData(int servent_id); + void addServentData(ServentData *sd); + void deleteDisableServents(); + + bool setName(int servent_id, String name); + int getServentCount(); + + bool checkDown(int x, int y); +}; + + + +#endif \ No newline at end of file diff --git a/c:/Git/PeerCast.root/PeerCast/ui/win32/simple/resource.h b/c:/Git/PeerCast.root/PeerCast/ui/win32/simple/resource.h new file mode 100644 index 0000000..a9a2b6d --- /dev/null +++ b/c:/Git/PeerCast.root/PeerCast/ui/win32/simple/resource.h @@ -0,0 +1,110 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by Simple.rc +// +#define IDC_MYICON 2 +#define IDD_MAINWINDOW 101 +#define IDD_SIMPLE_DIALOG 102 +#define IDD_ABOUTBOX 103 +#define IDS_APP_TITLE 103 +#define IDM_ABOUT 104 +#define IDM_EXIT 105 +#define IDS_HELLO 106 +#define IDI_SIMPLE 107 +#define IDI_SMALL 108 +#define IDC_SIMPLE 109 +#define IDI_SMALL2 109 +#define IDR_MAINFRAME 128 +#define IDR_TRAYMENU 130 +#define IDR_VERMENU 133 +#define IDD_CHANINFO 136 +#define IDR_LTRAYMENU 137 +#define IDC_LIST1 1000 +#define IDC_BUTTON7 1001 +#define IDC_ABOUTVER 1002 +#define IDC_CHECK1 1003 +#define IDC_EDIT1 1004 +#define IDC_LIST2 1005 +#define IDC_EDIT_PLAYING 1005 +#define IDC_COMBO1 1006 +#define IDC_EDIT_MESSAGE 1006 +#define IDC_CHECK2 1007 +#define IDC_EDIT_NAME 1007 +#define IDC_BUTTON1 1008 +#define IDC_EDIT_DESC 1008 +#define IDC_DETAILS 1009 +#define IDC_MAXRELAYS 1009 +#define IDC_LIST3 1010 +#define IDC_PLAY 1010 +#define IDC_CONTACT 1011 +#define IDC_EDIT2 1012 +#define IDC_FORMAT 1013 +#define IDC_EDIT_GENRE 1014 +#define IDC_KEEP 1015 +#define IDC_EDIT_STATUS 1016 +#define IDC_GROUPBOX_RELAY 1016 +#define IDC_EDIT_LISTENERS 1017 +#define IDC_STATIC_CONNECTION 1017 +#define IDC_LIST4 1018 +#define IDC_EDIT_HOSTS 1018 +#define IDC_STATIC_LOG 1018 +#define IDC_BUTTON4 1019 +#define IDC_BUTTON5 1020 +#define IDC_BUTTON6 1021 +#define IDC_EDIT3 1025 +#define IDC_EDIT5 1027 +#define IDC_LOGDEBUG 1037 +#define IDC_LOGNETWORK 1038 +#define IDC_LOGERRORS 1039 +#define IDC_CHECK9 1041 +#define IDC_BUTTON8 1043 +#define IDC_BUTTON10 1046 +#define IDC_BUTTON11 1047 +#define IDC_LOGCHANNELS 1050 +#define IDC_BUTTON2 1056 +#define IDC_EDIT4 1058 +#define IDC_BUTTON3 1059 +#define IDC_EDIT9 1060 +#define IDC_CHECK11 1061 +#define IDC_BUTTON9 1062 +#define IDM_SETTINGS_GUI 32771 +#define ID_POPUP_ABOUT 32779 +#define ID_POPUP_EXIT_CONFIRM 32781 +#define ID_POPUP_EXIT_NO 32782 +#define ID_POPUP_SETTINGS 32785 +#define ID_POPUP_CONNECTIONS 32786 +#define ID_POPUP_SHOWGUI 32788 +#define ID_POPUP_ALLCHANNELS 32791 +#define ID_POPUP_FAVORITES_EDIT 32792 +#define ID_POPUP_ADVANCED_INFORMATION 32793 +#define ID_POPUP_ADVANCED_SAVESETTINGS 32794 +#define ID_POPUP_UPGRADE 32795 +#define ID_POPUP_HELP 32796 +#define ID_POPUP_ADVANCED_VIEWLOG 32797 +#define ID_POPUP_FAVORITES_PLAYALL 32798 +#define ID_POPUP_ADVANCED_ALLCHANNELS 32799 +#define ID_POPUP_ADVANCED_RELAYEDCHANNELS 32800 +#define ID_POPUP_ADVANCED_BROADCAST 32801 +#define ID_FIND_CHANNELS 32808 +#define ID_POPUP_SHOWMESSAGES_PEERCAST 32814 +#define ID_POPUP_SHOWMESSAGES_BROADCASTERS 32815 +#define ID_POPUP_SHOWMESSAGES_TRACKINFO 32816 +#define ID_POPUP_POPUPMESSAGES_UPGRADEALERTS 32817 +#define ID_POPUP_YELLOWPAGES 32818 +#define ID_POPUP_ADVANCED_SHOWGUI 32819 +#define ID_POPUP_YELLOWPAGES1 32820 +#define ID_POPUP_YELLOWPAGES2 32821 +#define ID_POPUP_SAVE_GUI_POS 32823 +#define ID_POPUP_KEEP_DOWNSTREAMS 32825 +#define IDC_STATIC -1 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 142 +#define _APS_NEXT_COMMAND_VALUE 32826 +#define _APS_NEXT_CONTROL_VALUE 1019 +#define _APS_NEXT_SYMED_VALUE 110 +#endif +#endif diff --git a/c:/Git/PeerCast.root/PeerCast/ui/win32/simple/small1.ico b/c:/Git/PeerCast.root/PeerCast/ui/win32/simple/small1.ico new file mode 100644 index 0000000000000000000000000000000000000000..fa5a5dcd8818b15900cbcef9bed4d88269fcdb31 GIT binary patch literal 318 zcmZvYF%H5o3`Kt>Br|qmX5@I;!bUdK6O`O0+@um0Kw>EpYIttShLiWd<2X?isblng zFOO3v9o)eyN9eRerLyWjNfJ{jHA6`usg%M-U8idG3>aQ=k<5h%VYT1VT4Di5qAbQ> z7PQZK^&#Kb3mWqHG+LU=&Us9J)`qd&9j|nGgw40BrKp7`d@jBr|qmX5@I;!bUd6UMbw95*I*XXpvCObJ}h=dH*|(6Gf3aM&I{} zxOCDf9HMfDP6t$~P5()em?~v8loX0;t!#Lka*qrcQ3{bPgh;8`zO*&5gd*>1DL6F1z|v;;aqRdUw9l6_GaIu9mVEp76a%Gaif|-c9RHB_Cmi1)Tr! J2Rz{|{Q%s#L@@vW literal 0 HcmV?d00001 -- 2.11.0