From 2f9e8a878135e856d91c803537b9e02f6ca5ad21 Mon Sep 17 00:00:00 2001 From: LX3JL Date: Thu, 11 Feb 2016 18:51:12 +0100 Subject: [PATCH] xlxd 1.2.4 / db 2.1.0 implement XLX interlink feature --- dashboard/changes.txt | 10 + dashboard/css/layout.css | 16 +- dashboard/favicon.ico | Bin dashboard/img/dvc.jpg | Bin dashboard/img/flags/ad.png | Bin dashboard/img/flags/ae.png | Bin dashboard/img/flags/af.png | Bin dashboard/img/flags/ag.png | Bin dashboard/img/flags/al.png | Bin dashboard/img/flags/am.png | Bin dashboard/img/flags/ao.png | Bin dashboard/img/flags/ar.png | Bin dashboard/img/flags/at.png | Bin dashboard/img/flags/au.png | Bin dashboard/img/flags/az.png | Bin dashboard/img/flags/ba.png | Bin dashboard/img/flags/bb.png | Bin dashboard/img/flags/bd.png | Bin dashboard/img/flags/be.png | Bin dashboard/img/flags/bf.png | Bin dashboard/img/flags/bg.png | Bin dashboard/img/flags/bh.png | Bin dashboard/img/flags/bi.png | Bin dashboard/img/flags/bj.png | Bin dashboard/img/flags/bn.png | Bin dashboard/img/flags/bo.png | Bin dashboard/img/flags/br.png | Bin dashboard/img/flags/bs.png | Bin dashboard/img/flags/bt.png | Bin dashboard/img/flags/bw.png | Bin dashboard/img/flags/by.png | Bin dashboard/img/flags/bz.png | Bin dashboard/img/flags/ca.png | Bin dashboard/img/flags/cd.png | Bin dashboard/img/flags/cf.png | Bin dashboard/img/flags/cg.png | Bin dashboard/img/flags/ch.png | Bin dashboard/img/flags/ci.png | Bin dashboard/img/flags/cl.png | Bin dashboard/img/flags/cm.png | Bin dashboard/img/flags/cn.png | Bin dashboard/img/flags/co.png | Bin dashboard/img/flags/cr.png | Bin dashboard/img/flags/cu.png | Bin dashboard/img/flags/cv.png | Bin dashboard/img/flags/cy.png | Bin dashboard/img/flags/cz.png | Bin dashboard/img/flags/de.png | Bin dashboard/img/flags/dj.png | Bin dashboard/img/flags/dk.png | Bin dashboard/img/flags/dm.png | Bin dashboard/img/flags/do.png | Bin dashboard/img/flags/dz.png | Bin dashboard/img/flags/ec.png | Bin dashboard/img/flags/ee.png | Bin dashboard/img/flags/eg.png | Bin dashboard/img/flags/eh.png | Bin dashboard/img/flags/er.png | Bin dashboard/img/flags/es.png | Bin dashboard/img/flags/et.png | Bin dashboard/img/flags/fi.png | Bin dashboard/img/flags/fj.png | Bin dashboard/img/flags/fm.png | Bin dashboard/img/flags/fr.png | Bin dashboard/img/flags/ga.png | Bin dashboard/img/flags/gb.png | Bin dashboard/img/flags/gd.png | Bin dashboard/img/flags/ge.png | Bin dashboard/img/flags/gh.png | Bin dashboard/img/flags/gm.png | Bin dashboard/img/flags/gn.png | Bin dashboard/img/flags/gq.png | Bin dashboard/img/flags/gr.png | Bin dashboard/img/flags/gt.png | Bin dashboard/img/flags/gw.png | Bin dashboard/img/flags/gy.png | Bin dashboard/img/flags/hn.png | Bin dashboard/img/flags/hr.png | Bin dashboard/img/flags/ht.png | Bin dashboard/img/flags/hu.png | Bin dashboard/img/flags/id.png | Bin dashboard/img/flags/ie.png | Bin dashboard/img/flags/il.png | Bin dashboard/img/flags/in.png | Bin dashboard/img/flags/iq.png | Bin dashboard/img/flags/ir.png | Bin dashboard/img/flags/is.png | Bin dashboard/img/flags/it.png | Bin dashboard/img/flags/jm.png | Bin dashboard/img/flags/jo.png | Bin dashboard/img/flags/jp.png | Bin dashboard/img/flags/ke.png | Bin dashboard/img/flags/kg.png | Bin dashboard/img/flags/kh.png | Bin dashboard/img/flags/ki.png | Bin dashboard/img/flags/km.png | Bin dashboard/img/flags/kn.png | Bin dashboard/img/flags/kp.png | Bin dashboard/img/flags/kr.png | Bin dashboard/img/flags/ks.png | Bin dashboard/img/flags/kw.png | Bin dashboard/img/flags/kz.png | Bin dashboard/img/flags/la.png | Bin dashboard/img/flags/lb.png | Bin dashboard/img/flags/lc.png | Bin dashboard/img/flags/li.png | Bin dashboard/img/flags/lk.png | Bin dashboard/img/flags/lr.png | Bin dashboard/img/flags/ls.png | Bin dashboard/img/flags/lt.png | Bin dashboard/img/flags/lu.png | Bin dashboard/img/flags/lv.png | Bin dashboard/img/flags/ly.png | Bin dashboard/img/flags/ma.png | Bin dashboard/img/flags/mc.png | Bin dashboard/img/flags/md.png | Bin dashboard/img/flags/me.png | Bin dashboard/img/flags/mg.png | Bin dashboard/img/flags/mh.png | Bin dashboard/img/flags/mk.png | Bin dashboard/img/flags/ml.png | Bin dashboard/img/flags/mm.png | Bin dashboard/img/flags/mn.png | Bin dashboard/img/flags/mr.png | Bin dashboard/img/flags/mt.png | Bin dashboard/img/flags/mu.png | Bin dashboard/img/flags/mv.png | Bin dashboard/img/flags/mw.png | Bin dashboard/img/flags/mx.png | Bin dashboard/img/flags/my.png | Bin dashboard/img/flags/mz.png | Bin dashboard/img/flags/na.png | Bin dashboard/img/flags/ne.png | Bin dashboard/img/flags/ng.png | Bin dashboard/img/flags/ni.png | Bin dashboard/img/flags/nl.png | Bin dashboard/img/flags/no.png | Bin dashboard/img/flags/np.png | Bin dashboard/img/flags/nr.png | Bin dashboard/img/flags/nz.png | Bin dashboard/img/flags/om.png | Bin dashboard/img/flags/pa.png | Bin dashboard/img/flags/pe.png | Bin dashboard/img/flags/pg.png | Bin dashboard/img/flags/ph.png | Bin dashboard/img/flags/pk.png | Bin dashboard/img/flags/pl.png | Bin dashboard/img/flags/pt.png | Bin dashboard/img/flags/pw.png | Bin dashboard/img/flags/py.png | Bin dashboard/img/flags/qa.png | Bin dashboard/img/flags/ro.png | Bin dashboard/img/flags/rs.png | Bin dashboard/img/flags/ru.png | Bin dashboard/img/flags/rw.png | Bin dashboard/img/flags/sa.png | Bin dashboard/img/flags/sb.png | Bin dashboard/img/flags/sc.png | Bin dashboard/img/flags/sd.png | Bin dashboard/img/flags/se.png | Bin dashboard/img/flags/sg.png | Bin dashboard/img/flags/si.png | Bin dashboard/img/flags/sk.png | Bin dashboard/img/flags/sl.png | Bin dashboard/img/flags/sm.png | Bin dashboard/img/flags/sn.png | Bin dashboard/img/flags/so.png | Bin dashboard/img/flags/sr.png | Bin dashboard/img/flags/st.png | Bin dashboard/img/flags/sv.png | Bin dashboard/img/flags/sy.png | Bin dashboard/img/flags/sz.png | Bin dashboard/img/flags/td.png | Bin dashboard/img/flags/tg.png | Bin dashboard/img/flags/th.png | Bin dashboard/img/flags/tj.png | Bin dashboard/img/flags/tl.png | Bin dashboard/img/flags/tm.png | Bin dashboard/img/flags/tn.png | Bin dashboard/img/flags/to.png | Bin dashboard/img/flags/tr.png | Bin dashboard/img/flags/tt.png | Bin dashboard/img/flags/tv.png | Bin dashboard/img/flags/tw.png | Bin dashboard/img/flags/tz.png | Bin dashboard/img/flags/ua.png | Bin dashboard/img/flags/ug.png | Bin dashboard/img/flags/us.png | Bin dashboard/img/flags/uy.png | Bin dashboard/img/flags/uz.png | Bin dashboard/img/flags/va.png | Bin dashboard/img/flags/vc.png | Bin dashboard/img/flags/ve.png | Bin dashboard/img/flags/vn.png | Bin dashboard/img/flags/vu.png | Bin dashboard/img/flags/ws.png | Bin dashboard/img/flags/ye.png | Bin dashboard/img/flags/za.png | Bin dashboard/img/flags/zm.png | Bin dashboard/img/flags/zw.png | Bin dashboard/img/header.jpg | Bin dashboard/img/radio-waves-hi.png | Bin dashboard/img/sat.png | Bin dashboard/index.php | 51 +-- dashboard/log/xlxlog.php | 62 +-- dashboard/pgs/class.node.php | 42 +- dashboard/pgs/class.parsexml.php | 42 +- dashboard/pgs/class.peer.php | 32 ++ dashboard/pgs/class.reflector.php | 43 +- dashboard/pgs/class.station.php | 39 +- dashboard/pgs/country.csv | 6 +- dashboard/pgs/functions.php | 38 +- dashboard/pgs/liveccs.php | 25 +- dashboard/pgs/liveircddb.php | 25 +- dashboard/pgs/peers.php | 35 ++ dashboard/pgs/repeaters.php | 40 +- dashboard/pgs/users.php | 36 +- readme | 177 ++++---- src/cbuffer.cpp | 6 + src/cbuffer.h | 1 + src/ccallsignlist.cpp | 80 +++- src/ccallsignlist.h | 15 +- src/ccallsignlistitem.cpp | 96 +++++ src/ccallsignlistitem.h | 67 +++ src/cclient.cpp | 2 +- src/cclient.h | 5 +- src/cdcsclient.h | 1 + src/cdcsprotocol.cpp | 96 +++-- src/cdcsprotocol.h | 9 +- src/cdextraclient.h | 1 + src/cdextraprotocol.cpp | 90 ++-- src/cdextraprotocol.h | 5 +- src/cdplusclient.h | 1 + src/cdplusprotocol.cpp | 80 ++-- src/cdplusprotocol.h | 8 +- src/cgatekeeper.cpp | 138 ++++-- src/cgatekeeper.h | 24 +- src/cip.cpp | 15 +- src/cpacket.cpp | 2 + src/cpacket.h | 7 + src/cpeercallsignlist.cpp | 95 +++++ src/cpeercallsignlist.h | 51 +++ src/cprotocol.cpp | 17 + src/cprotocol.h | 8 + src/cprotocols.cpp | 7 +- src/creflector.cpp | 49 ++- src/cudpsocket.cpp | 20 + src/cudpsocket.h | 2 + src/cuser.cpp | 9 +- src/cuser.h | 3 +- src/cusers.cpp | 9 +- src/cusers.h | 1 + src/cxlxclient.cpp | 100 +++++ src/cxlxclient.h | 70 ++++ src/cxlxprotocol.cpp | 542 ++++++++++++++++++++++++ src/cxlxprotocol.h | 86 ++++ src/license.txt | 674 ++++++++++++++++++++++++++++++ src/main.h | 17 +- src/makefile | 22 +- 259 files changed, 2603 insertions(+), 647 deletions(-) mode change 100755 => 100644 dashboard/css/layout.css mode change 100755 => 100644 dashboard/favicon.ico mode change 100755 => 100644 dashboard/img/dvc.jpg mode change 100755 => 100644 dashboard/img/flags/ad.png mode change 100755 => 100644 dashboard/img/flags/ae.png mode change 100755 => 100644 dashboard/img/flags/af.png mode change 100755 => 100644 dashboard/img/flags/ag.png mode change 100755 => 100644 dashboard/img/flags/al.png mode change 100755 => 100644 dashboard/img/flags/am.png mode change 100755 => 100644 dashboard/img/flags/ao.png mode change 100755 => 100644 dashboard/img/flags/ar.png mode change 100755 => 100644 dashboard/img/flags/at.png mode change 100755 => 100644 dashboard/img/flags/au.png mode change 100755 => 100644 dashboard/img/flags/az.png mode change 100755 => 100644 dashboard/img/flags/ba.png mode change 100755 => 100644 dashboard/img/flags/bb.png mode change 100755 => 100644 dashboard/img/flags/bd.png mode change 100755 => 100644 dashboard/img/flags/be.png mode change 100755 => 100644 dashboard/img/flags/bf.png mode change 100755 => 100644 dashboard/img/flags/bg.png mode change 100755 => 100644 dashboard/img/flags/bh.png mode change 100755 => 100644 dashboard/img/flags/bi.png mode change 100755 => 100644 dashboard/img/flags/bj.png mode change 100755 => 100644 dashboard/img/flags/bn.png mode change 100755 => 100644 dashboard/img/flags/bo.png mode change 100755 => 100644 dashboard/img/flags/br.png mode change 100755 => 100644 dashboard/img/flags/bs.png mode change 100755 => 100644 dashboard/img/flags/bt.png mode change 100755 => 100644 dashboard/img/flags/bw.png mode change 100755 => 100644 dashboard/img/flags/by.png mode change 100755 => 100644 dashboard/img/flags/bz.png mode change 100755 => 100644 dashboard/img/flags/ca.png mode change 100755 => 100644 dashboard/img/flags/cd.png mode change 100755 => 100644 dashboard/img/flags/cf.png mode change 100755 => 100644 dashboard/img/flags/cg.png mode change 100755 => 100644 dashboard/img/flags/ch.png mode change 100755 => 100644 dashboard/img/flags/ci.png mode change 100755 => 100644 dashboard/img/flags/cl.png mode change 100755 => 100644 dashboard/img/flags/cm.png mode change 100755 => 100644 dashboard/img/flags/cn.png mode change 100755 => 100644 dashboard/img/flags/co.png mode change 100755 => 100644 dashboard/img/flags/cr.png mode change 100755 => 100644 dashboard/img/flags/cu.png mode change 100755 => 100644 dashboard/img/flags/cv.png mode change 100755 => 100644 dashboard/img/flags/cy.png mode change 100755 => 100644 dashboard/img/flags/cz.png mode change 100755 => 100644 dashboard/img/flags/de.png mode change 100755 => 100644 dashboard/img/flags/dj.png mode change 100755 => 100644 dashboard/img/flags/dk.png mode change 100755 => 100644 dashboard/img/flags/dm.png mode change 100755 => 100644 dashboard/img/flags/do.png mode change 100755 => 100644 dashboard/img/flags/dz.png mode change 100755 => 100644 dashboard/img/flags/ec.png mode change 100755 => 100644 dashboard/img/flags/ee.png mode change 100755 => 100644 dashboard/img/flags/eg.png mode change 100755 => 100644 dashboard/img/flags/eh.png mode change 100755 => 100644 dashboard/img/flags/er.png mode change 100755 => 100644 dashboard/img/flags/es.png mode change 100755 => 100644 dashboard/img/flags/et.png mode change 100755 => 100644 dashboard/img/flags/fi.png mode change 100755 => 100644 dashboard/img/flags/fj.png mode change 100755 => 100644 dashboard/img/flags/fm.png mode change 100755 => 100644 dashboard/img/flags/fr.png mode change 100755 => 100644 dashboard/img/flags/ga.png mode change 100755 => 100644 dashboard/img/flags/gb.png mode change 100755 => 100644 dashboard/img/flags/gd.png mode change 100755 => 100644 dashboard/img/flags/ge.png mode change 100755 => 100644 dashboard/img/flags/gh.png mode change 100755 => 100644 dashboard/img/flags/gm.png mode change 100755 => 100644 dashboard/img/flags/gn.png mode change 100755 => 100644 dashboard/img/flags/gq.png mode change 100755 => 100644 dashboard/img/flags/gr.png mode change 100755 => 100644 dashboard/img/flags/gt.png mode change 100755 => 100644 dashboard/img/flags/gw.png mode change 100755 => 100644 dashboard/img/flags/gy.png mode change 100755 => 100644 dashboard/img/flags/hn.png mode change 100755 => 100644 dashboard/img/flags/hr.png mode change 100755 => 100644 dashboard/img/flags/ht.png mode change 100755 => 100644 dashboard/img/flags/hu.png mode change 100755 => 100644 dashboard/img/flags/id.png mode change 100755 => 100644 dashboard/img/flags/ie.png mode change 100755 => 100644 dashboard/img/flags/il.png mode change 100755 => 100644 dashboard/img/flags/in.png mode change 100755 => 100644 dashboard/img/flags/iq.png mode change 100755 => 100644 dashboard/img/flags/ir.png mode change 100755 => 100644 dashboard/img/flags/is.png mode change 100755 => 100644 dashboard/img/flags/it.png mode change 100755 => 100644 dashboard/img/flags/jm.png mode change 100755 => 100644 dashboard/img/flags/jo.png mode change 100755 => 100644 dashboard/img/flags/jp.png mode change 100755 => 100644 dashboard/img/flags/ke.png mode change 100755 => 100644 dashboard/img/flags/kg.png mode change 100755 => 100644 dashboard/img/flags/kh.png mode change 100755 => 100644 dashboard/img/flags/ki.png mode change 100755 => 100644 dashboard/img/flags/km.png mode change 100755 => 100644 dashboard/img/flags/kn.png mode change 100755 => 100644 dashboard/img/flags/kp.png mode change 100755 => 100644 dashboard/img/flags/kr.png mode change 100755 => 100644 dashboard/img/flags/ks.png mode change 100755 => 100644 dashboard/img/flags/kw.png mode change 100755 => 100644 dashboard/img/flags/kz.png mode change 100755 => 100644 dashboard/img/flags/la.png mode change 100755 => 100644 dashboard/img/flags/lb.png mode change 100755 => 100644 dashboard/img/flags/lc.png mode change 100755 => 100644 dashboard/img/flags/li.png mode change 100755 => 100644 dashboard/img/flags/lk.png mode change 100755 => 100644 dashboard/img/flags/lr.png mode change 100755 => 100644 dashboard/img/flags/ls.png mode change 100755 => 100644 dashboard/img/flags/lt.png mode change 100755 => 100644 dashboard/img/flags/lu.png mode change 100755 => 100644 dashboard/img/flags/lv.png mode change 100755 => 100644 dashboard/img/flags/ly.png mode change 100755 => 100644 dashboard/img/flags/ma.png mode change 100755 => 100644 dashboard/img/flags/mc.png mode change 100755 => 100644 dashboard/img/flags/md.png mode change 100755 => 100644 dashboard/img/flags/me.png mode change 100755 => 100644 dashboard/img/flags/mg.png mode change 100755 => 100644 dashboard/img/flags/mh.png mode change 100755 => 100644 dashboard/img/flags/mk.png mode change 100755 => 100644 dashboard/img/flags/ml.png mode change 100755 => 100644 dashboard/img/flags/mm.png mode change 100755 => 100644 dashboard/img/flags/mn.png mode change 100755 => 100644 dashboard/img/flags/mr.png mode change 100755 => 100644 dashboard/img/flags/mt.png mode change 100755 => 100644 dashboard/img/flags/mu.png mode change 100755 => 100644 dashboard/img/flags/mv.png mode change 100755 => 100644 dashboard/img/flags/mw.png mode change 100755 => 100644 dashboard/img/flags/mx.png mode change 100755 => 100644 dashboard/img/flags/my.png mode change 100755 => 100644 dashboard/img/flags/mz.png mode change 100755 => 100644 dashboard/img/flags/na.png mode change 100755 => 100644 dashboard/img/flags/ne.png mode change 100755 => 100644 dashboard/img/flags/ng.png mode change 100755 => 100644 dashboard/img/flags/ni.png mode change 100755 => 100644 dashboard/img/flags/nl.png mode change 100755 => 100644 dashboard/img/flags/no.png mode change 100755 => 100644 dashboard/img/flags/np.png mode change 100755 => 100644 dashboard/img/flags/nr.png mode change 100755 => 100644 dashboard/img/flags/nz.png mode change 100755 => 100644 dashboard/img/flags/om.png mode change 100755 => 100644 dashboard/img/flags/pa.png mode change 100755 => 100644 dashboard/img/flags/pe.png mode change 100755 => 100644 dashboard/img/flags/pg.png mode change 100755 => 100644 dashboard/img/flags/ph.png mode change 100755 => 100644 dashboard/img/flags/pk.png mode change 100755 => 100644 dashboard/img/flags/pl.png mode change 100755 => 100644 dashboard/img/flags/pt.png mode change 100755 => 100644 dashboard/img/flags/pw.png mode change 100755 => 100644 dashboard/img/flags/py.png mode change 100755 => 100644 dashboard/img/flags/qa.png mode change 100755 => 100644 dashboard/img/flags/ro.png mode change 100755 => 100644 dashboard/img/flags/rs.png mode change 100755 => 100644 dashboard/img/flags/ru.png mode change 100755 => 100644 dashboard/img/flags/rw.png mode change 100755 => 100644 dashboard/img/flags/sa.png mode change 100755 => 100644 dashboard/img/flags/sb.png mode change 100755 => 100644 dashboard/img/flags/sc.png mode change 100755 => 100644 dashboard/img/flags/sd.png mode change 100755 => 100644 dashboard/img/flags/se.png mode change 100755 => 100644 dashboard/img/flags/sg.png mode change 100755 => 100644 dashboard/img/flags/si.png mode change 100755 => 100644 dashboard/img/flags/sk.png mode change 100755 => 100644 dashboard/img/flags/sl.png mode change 100755 => 100644 dashboard/img/flags/sm.png mode change 100755 => 100644 dashboard/img/flags/sn.png mode change 100755 => 100644 dashboard/img/flags/so.png mode change 100755 => 100644 dashboard/img/flags/sr.png mode change 100755 => 100644 dashboard/img/flags/st.png mode change 100755 => 100644 dashboard/img/flags/sv.png mode change 100755 => 100644 dashboard/img/flags/sy.png mode change 100755 => 100644 dashboard/img/flags/sz.png mode change 100755 => 100644 dashboard/img/flags/td.png mode change 100755 => 100644 dashboard/img/flags/tg.png mode change 100755 => 100644 dashboard/img/flags/th.png mode change 100755 => 100644 dashboard/img/flags/tj.png mode change 100755 => 100644 dashboard/img/flags/tl.png mode change 100755 => 100644 dashboard/img/flags/tm.png mode change 100755 => 100644 dashboard/img/flags/tn.png mode change 100755 => 100644 dashboard/img/flags/to.png mode change 100755 => 100644 dashboard/img/flags/tr.png mode change 100755 => 100644 dashboard/img/flags/tt.png mode change 100755 => 100644 dashboard/img/flags/tv.png mode change 100755 => 100644 dashboard/img/flags/tw.png mode change 100755 => 100644 dashboard/img/flags/tz.png mode change 100755 => 100644 dashboard/img/flags/ua.png mode change 100755 => 100644 dashboard/img/flags/ug.png mode change 100755 => 100644 dashboard/img/flags/us.png mode change 100755 => 100644 dashboard/img/flags/uy.png mode change 100755 => 100644 dashboard/img/flags/uz.png mode change 100755 => 100644 dashboard/img/flags/va.png mode change 100755 => 100644 dashboard/img/flags/vc.png mode change 100755 => 100644 dashboard/img/flags/ve.png mode change 100755 => 100644 dashboard/img/flags/vn.png mode change 100755 => 100644 dashboard/img/flags/vu.png mode change 100755 => 100644 dashboard/img/flags/ws.png mode change 100755 => 100644 dashboard/img/flags/ye.png mode change 100755 => 100644 dashboard/img/flags/za.png mode change 100755 => 100644 dashboard/img/flags/zm.png mode change 100755 => 100644 dashboard/img/flags/zw.png mode change 100755 => 100644 dashboard/img/header.jpg mode change 100755 => 100644 dashboard/img/radio-waves-hi.png mode change 100755 => 100644 dashboard/img/sat.png mode change 100755 => 100644 dashboard/log/xlxlog.php mode change 100755 => 100644 dashboard/pgs/class.node.php mode change 100755 => 100644 dashboard/pgs/class.parsexml.php create mode 100644 dashboard/pgs/class.peer.php mode change 100755 => 100644 dashboard/pgs/class.station.php mode change 100755 => 100644 dashboard/pgs/functions.php mode change 100755 => 100644 dashboard/pgs/liveccs.php mode change 100755 => 100644 dashboard/pgs/liveircddb.php create mode 100644 dashboard/pgs/peers.php create mode 100644 src/ccallsignlistitem.cpp create mode 100644 src/ccallsignlistitem.h create mode 100644 src/cpeercallsignlist.cpp create mode 100644 src/cpeercallsignlist.h create mode 100644 src/cxlxclient.cpp create mode 100644 src/cxlxclient.h create mode 100644 src/cxlxprotocol.cpp create mode 100644 src/cxlxprotocol.h create mode 100644 src/license.txt diff --git a/dashboard/changes.txt b/dashboard/changes.txt index 399b946..e587f33 100644 --- a/dashboard/changes.txt +++ b/dashboard/changes.txt @@ -1,3 +1,13 @@ +xlx db v2.1.0 + +- "index.php" + button "Peers" added + button "Repeaters/Nodes" shows now the number of connected devices + moved XLX name, version and service uptime to improve view on mobile devices +- "class.peer.php" added +- "peers.php" added +- "repeaters.php" limits nodes show up to 100 nodes + xlx db v2.0.6 - "index.php" now reads out the XLX service uptime and not the server uptime diff --git a/dashboard/css/layout.css b/dashboard/css/layout.css old mode 100755 new mode 100644 index bf0167b..35bb41b --- a/dashboard/css/layout.css +++ b/dashboard/css/layout.css @@ -3,6 +3,7 @@ body { padding : 0px; background-color : #D3D3D3; font-family : calibri, verdana, arial, comic sans; + min-width : 760px; } h1 { @@ -10,7 +11,7 @@ h1 { } #top { - height : 105px; + height : 115px; background-color : #FFFFFF; width : 100%; background-image : url('../img/dvc.jpg'); @@ -19,6 +20,8 @@ h1 { position : absolute; left : 0px; top : 0px; + min-width : 760px; + padding-left : 3px; } #menu { @@ -33,20 +36,15 @@ h1 { background-color : #FEC456; position : absolute; left : 0px; - top : 105px; -} - -#info { - float : right; - font-size : 11pt; + top : 115px; + min-width : 760px; } #content { - width : 100%; position : absolute; left : 0px; - top : 150px; + top : 175px; } .menulink { diff --git a/dashboard/favicon.ico b/dashboard/favicon.ico old mode 100755 new mode 100644 diff --git a/dashboard/img/dvc.jpg b/dashboard/img/dvc.jpg old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/ad.png b/dashboard/img/flags/ad.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/ae.png b/dashboard/img/flags/ae.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/af.png b/dashboard/img/flags/af.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/ag.png b/dashboard/img/flags/ag.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/al.png b/dashboard/img/flags/al.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/am.png b/dashboard/img/flags/am.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/ao.png b/dashboard/img/flags/ao.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/ar.png b/dashboard/img/flags/ar.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/at.png b/dashboard/img/flags/at.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/au.png b/dashboard/img/flags/au.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/az.png b/dashboard/img/flags/az.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/ba.png b/dashboard/img/flags/ba.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/bb.png b/dashboard/img/flags/bb.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/bd.png b/dashboard/img/flags/bd.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/be.png b/dashboard/img/flags/be.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/bf.png b/dashboard/img/flags/bf.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/bg.png b/dashboard/img/flags/bg.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/bh.png b/dashboard/img/flags/bh.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/bi.png b/dashboard/img/flags/bi.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/bj.png b/dashboard/img/flags/bj.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/bn.png b/dashboard/img/flags/bn.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/bo.png b/dashboard/img/flags/bo.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/br.png b/dashboard/img/flags/br.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/bs.png b/dashboard/img/flags/bs.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/bt.png b/dashboard/img/flags/bt.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/bw.png b/dashboard/img/flags/bw.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/by.png b/dashboard/img/flags/by.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/bz.png b/dashboard/img/flags/bz.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/ca.png b/dashboard/img/flags/ca.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/cd.png b/dashboard/img/flags/cd.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/cf.png b/dashboard/img/flags/cf.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/cg.png b/dashboard/img/flags/cg.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/ch.png b/dashboard/img/flags/ch.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/ci.png b/dashboard/img/flags/ci.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/cl.png b/dashboard/img/flags/cl.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/cm.png b/dashboard/img/flags/cm.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/cn.png b/dashboard/img/flags/cn.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/co.png b/dashboard/img/flags/co.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/cr.png b/dashboard/img/flags/cr.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/cu.png b/dashboard/img/flags/cu.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/cv.png b/dashboard/img/flags/cv.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/cy.png b/dashboard/img/flags/cy.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/cz.png b/dashboard/img/flags/cz.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/de.png b/dashboard/img/flags/de.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/dj.png b/dashboard/img/flags/dj.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/dk.png b/dashboard/img/flags/dk.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/dm.png b/dashboard/img/flags/dm.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/do.png b/dashboard/img/flags/do.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/dz.png b/dashboard/img/flags/dz.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/ec.png b/dashboard/img/flags/ec.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/ee.png b/dashboard/img/flags/ee.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/eg.png b/dashboard/img/flags/eg.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/eh.png b/dashboard/img/flags/eh.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/er.png b/dashboard/img/flags/er.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/es.png b/dashboard/img/flags/es.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/et.png b/dashboard/img/flags/et.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/fi.png b/dashboard/img/flags/fi.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/fj.png b/dashboard/img/flags/fj.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/fm.png b/dashboard/img/flags/fm.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/fr.png b/dashboard/img/flags/fr.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/ga.png b/dashboard/img/flags/ga.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/gb.png b/dashboard/img/flags/gb.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/gd.png b/dashboard/img/flags/gd.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/ge.png b/dashboard/img/flags/ge.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/gh.png b/dashboard/img/flags/gh.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/gm.png b/dashboard/img/flags/gm.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/gn.png b/dashboard/img/flags/gn.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/gq.png b/dashboard/img/flags/gq.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/gr.png b/dashboard/img/flags/gr.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/gt.png b/dashboard/img/flags/gt.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/gw.png b/dashboard/img/flags/gw.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/gy.png b/dashboard/img/flags/gy.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/hn.png b/dashboard/img/flags/hn.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/hr.png b/dashboard/img/flags/hr.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/ht.png b/dashboard/img/flags/ht.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/hu.png b/dashboard/img/flags/hu.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/id.png b/dashboard/img/flags/id.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/ie.png b/dashboard/img/flags/ie.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/il.png b/dashboard/img/flags/il.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/in.png b/dashboard/img/flags/in.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/iq.png b/dashboard/img/flags/iq.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/ir.png b/dashboard/img/flags/ir.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/is.png b/dashboard/img/flags/is.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/it.png b/dashboard/img/flags/it.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/jm.png b/dashboard/img/flags/jm.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/jo.png b/dashboard/img/flags/jo.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/jp.png b/dashboard/img/flags/jp.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/ke.png b/dashboard/img/flags/ke.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/kg.png b/dashboard/img/flags/kg.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/kh.png b/dashboard/img/flags/kh.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/ki.png b/dashboard/img/flags/ki.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/km.png b/dashboard/img/flags/km.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/kn.png b/dashboard/img/flags/kn.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/kp.png b/dashboard/img/flags/kp.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/kr.png b/dashboard/img/flags/kr.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/ks.png b/dashboard/img/flags/ks.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/kw.png b/dashboard/img/flags/kw.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/kz.png b/dashboard/img/flags/kz.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/la.png b/dashboard/img/flags/la.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/lb.png b/dashboard/img/flags/lb.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/lc.png b/dashboard/img/flags/lc.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/li.png b/dashboard/img/flags/li.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/lk.png b/dashboard/img/flags/lk.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/lr.png b/dashboard/img/flags/lr.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/ls.png b/dashboard/img/flags/ls.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/lt.png b/dashboard/img/flags/lt.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/lu.png b/dashboard/img/flags/lu.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/lv.png b/dashboard/img/flags/lv.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/ly.png b/dashboard/img/flags/ly.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/ma.png b/dashboard/img/flags/ma.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/mc.png b/dashboard/img/flags/mc.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/md.png b/dashboard/img/flags/md.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/me.png b/dashboard/img/flags/me.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/mg.png b/dashboard/img/flags/mg.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/mh.png b/dashboard/img/flags/mh.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/mk.png b/dashboard/img/flags/mk.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/ml.png b/dashboard/img/flags/ml.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/mm.png b/dashboard/img/flags/mm.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/mn.png b/dashboard/img/flags/mn.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/mr.png b/dashboard/img/flags/mr.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/mt.png b/dashboard/img/flags/mt.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/mu.png b/dashboard/img/flags/mu.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/mv.png b/dashboard/img/flags/mv.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/mw.png b/dashboard/img/flags/mw.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/mx.png b/dashboard/img/flags/mx.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/my.png b/dashboard/img/flags/my.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/mz.png b/dashboard/img/flags/mz.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/na.png b/dashboard/img/flags/na.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/ne.png b/dashboard/img/flags/ne.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/ng.png b/dashboard/img/flags/ng.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/ni.png b/dashboard/img/flags/ni.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/nl.png b/dashboard/img/flags/nl.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/no.png b/dashboard/img/flags/no.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/np.png b/dashboard/img/flags/np.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/nr.png b/dashboard/img/flags/nr.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/nz.png b/dashboard/img/flags/nz.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/om.png b/dashboard/img/flags/om.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/pa.png b/dashboard/img/flags/pa.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/pe.png b/dashboard/img/flags/pe.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/pg.png b/dashboard/img/flags/pg.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/ph.png b/dashboard/img/flags/ph.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/pk.png b/dashboard/img/flags/pk.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/pl.png b/dashboard/img/flags/pl.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/pt.png b/dashboard/img/flags/pt.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/pw.png b/dashboard/img/flags/pw.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/py.png b/dashboard/img/flags/py.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/qa.png b/dashboard/img/flags/qa.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/ro.png b/dashboard/img/flags/ro.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/rs.png b/dashboard/img/flags/rs.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/ru.png b/dashboard/img/flags/ru.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/rw.png b/dashboard/img/flags/rw.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/sa.png b/dashboard/img/flags/sa.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/sb.png b/dashboard/img/flags/sb.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/sc.png b/dashboard/img/flags/sc.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/sd.png b/dashboard/img/flags/sd.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/se.png b/dashboard/img/flags/se.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/sg.png b/dashboard/img/flags/sg.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/si.png b/dashboard/img/flags/si.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/sk.png b/dashboard/img/flags/sk.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/sl.png b/dashboard/img/flags/sl.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/sm.png b/dashboard/img/flags/sm.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/sn.png b/dashboard/img/flags/sn.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/so.png b/dashboard/img/flags/so.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/sr.png b/dashboard/img/flags/sr.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/st.png b/dashboard/img/flags/st.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/sv.png b/dashboard/img/flags/sv.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/sy.png b/dashboard/img/flags/sy.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/sz.png b/dashboard/img/flags/sz.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/td.png b/dashboard/img/flags/td.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/tg.png b/dashboard/img/flags/tg.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/th.png b/dashboard/img/flags/th.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/tj.png b/dashboard/img/flags/tj.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/tl.png b/dashboard/img/flags/tl.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/tm.png b/dashboard/img/flags/tm.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/tn.png b/dashboard/img/flags/tn.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/to.png b/dashboard/img/flags/to.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/tr.png b/dashboard/img/flags/tr.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/tt.png b/dashboard/img/flags/tt.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/tv.png b/dashboard/img/flags/tv.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/tw.png b/dashboard/img/flags/tw.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/tz.png b/dashboard/img/flags/tz.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/ua.png b/dashboard/img/flags/ua.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/ug.png b/dashboard/img/flags/ug.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/us.png b/dashboard/img/flags/us.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/uy.png b/dashboard/img/flags/uy.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/uz.png b/dashboard/img/flags/uz.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/va.png b/dashboard/img/flags/va.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/vc.png b/dashboard/img/flags/vc.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/ve.png b/dashboard/img/flags/ve.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/vn.png b/dashboard/img/flags/vn.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/vu.png b/dashboard/img/flags/vu.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/ws.png b/dashboard/img/flags/ws.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/ye.png b/dashboard/img/flags/ye.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/za.png b/dashboard/img/flags/za.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/zm.png b/dashboard/img/flags/zm.png old mode 100755 new mode 100644 diff --git a/dashboard/img/flags/zw.png b/dashboard/img/flags/zw.png old mode 100755 new mode 100644 diff --git a/dashboard/img/header.jpg b/dashboard/img/header.jpg old mode 100755 new mode 100644 diff --git a/dashboard/img/radio-waves-hi.png b/dashboard/img/radio-waves-hi.png old mode 100755 new mode 100644 diff --git a/dashboard/img/sat.png b/dashboard/img/sat.png old mode 100755 new mode 100644 diff --git a/dashboard/index.php b/dashboard/index.php index f73c005..dfde41d 100644 --- a/dashboard/index.php +++ b/dashboard/index.php @@ -1,28 +1,4 @@ . ----------------------------------------------------------------------------- -*/ $FILE = "/var/log/xlxd.xml"; $PID = "/var/log/xlxd.pid"; @@ -32,7 +8,7 @@ if (!class_exists('ParseXML')) require_once("./pgs/class.parsexml.php"); if (!class_exists('Node')) require_once("./pgs/class.node.php"); if (!class_exists('xReflector')) require_once("./pgs/class.reflector.php"); if (!class_exists('Station')) require_once("./pgs/class.station.php"); - +if (!class_exists('Peer')) require_once("./pgs/class.peer.php"); //if (!isset($_GET['show'])) { $_GET['show'] == ''; } @@ -51,6 +27,7 @@ $Reflector->SetFlagFile("./pgs/country.csv"); $ServiceName = substr($FILECONTENT, strpos($FILECONTENT, "GetElement($FILECONTENT, $LinkedUsersName); $tmpStations = $XML->GetAllElements($AllStationsString, "STATION"); for ($i=0;$iGetElement($tmpStations[$i], 'Callsign'), $XML->GetElement($tmpStations[$i], 'Via'), $XML->GetElement($tmpStations[$i], 'LastHeardTime')); + $Station = new Station($XML->GetElement($tmpStations[$i], 'Callsign'), $XML->GetElement($tmpStations[$i], 'Via node'), $XML->GetElement($tmpStations[$i], 'Via peer'), $XML->GetElement($tmpStations[$i], 'LastHeardTime')); $Reflector->AddStation($Station, false); } +$AllPeersString = $XML->GetElement($FILECONTENT, $LinkedPeersName); +$tmpPeers = $XML->GetAllElements($AllPeersString, "PEER"); +for ($i=0;$iGetElement($tmpPeers[$i], 'Callsign'), $XML->GetElement($tmpPeers[$i], 'IP'), $XML->GetElement($tmpPeers[$i], 'LinkedModule'), $XML->GetElement($tmpPeers[$i], 'Protocol'), $XML->GetElement($tmpPeers[$i], 'ConnectTime'), $XML->GetElement($tmpPeers[$i], 'LastHeardTime')); + $Reflector->AddPeer($Peer, false); +} ?> @@ -96,21 +79,20 @@ for ($i=0;$i -
XLX Multiprotocol Gateway Reflector
+
XLX Multiprotocol Gateway Reflector +
 XLX vGetElement($FILECONTENT, "Version"); ?> - Dashboard v2.1.0  /  Service uptime:
@@ -121,6 +103,7 @@ for ($i=0;$i. -// ---------------------------------------------------------------------------- session_start(); if (isset($_POST['password'])) { @@ -28,31 +6,31 @@ if (isset($_POST['password'])) { } if (isset($_SESSION['password'])) { - + if ($_SESSION['password'] != "-D-Star+") { echo '
- + - +
'; - + die(); } } else { echo '
- + - +
'; - + die(); } - + ?> XLX Live Log - +
 
 
    
diff --git a/dashboard/pgs/class.node.php b/dashboard/pgs/class.node.php old mode 100755 new mode 100644 index e1f17d7..8f2e519 --- a/dashboard/pgs/class.node.php +++ b/dashboard/pgs/class.node.php @@ -1,29 +1,7 @@ . -// ---------------------------------------------------------------------------- class Node { - + private $Callsign; private $IP; private $LinkedModule; @@ -31,15 +9,15 @@ class Node { private $ConnectTime; private $LastHeardTime; private $Suffix; - + public function __construct($Callsign, $IP, $LinkedModule, $Protocol, $ConnectTime, $LastHeardTime) { - + $this->IP = $IP; - + $this->Protocol = $Protocol; $this->ConnectTime = ParseTime($ConnectTime); $this->LastHeardTime = ParseTime($LastHeardTime); - + if (strpos($Callsign, " ") !== false) { $this->Callsign = trim(substr($Callsign, 0, strpos($Callsign, " "))); $this->Suffix = trim(substr($Callsign, strpos($Callsign, " "), strlen($Callsign))); @@ -48,11 +26,11 @@ class Node { $this->Callsign = trim($Callsign); $this->Suffix = ""; } - - + + $this->LinkedModule = trim($LinkedModule); } - + public function GetCallsign() { return $this->Callsign; } public function GetIP() { return $this->IP; } @@ -61,7 +39,7 @@ class Node { public function GetConnectTime() { return $this->ConnectTime; } public function GetLastHeardTime() { return $this->LastHeardTime; } public function GetSuffix() { return $this->Suffix; } - + } -?> +?> \ No newline at end of file diff --git a/dashboard/pgs/class.parsexml.php b/dashboard/pgs/class.parsexml.php old mode 100755 new mode 100644 index 07409f2..9ebf722 --- a/dashboard/pgs/class.parsexml.php +++ b/dashboard/pgs/class.parsexml.php @@ -1,54 +1,32 @@ . -// ---------------------------------------------------------------------------- class ParseXML { - + public function __construct() { - return true; + return true; } - + public function GetElement($InputString, $ElementName) { if (strpos($InputString, "<".$ElementName.">") === false) return false; if (strpos($InputString, "") === false) return false; - + $Element = substr($InputString, strpos($InputString, "<".$ElementName.">")+strlen($ElementName)+2, strpos($InputString, "")-strpos($InputString, "<".$ElementName.">")-strlen($ElementName)-2); return $Element; - + } - + public function GetAllElements($InputString, $ElementName) { $Elements = array(); while (strpos($InputString, $ElementName) !== false) { $Elements[] = $this->GetElement($InputString, $ElementName); - $InputString = substr($InputString, strpos($InputString, "")+strlen($ElementName)+3, strlen($InputString)); + $InputString = substr($InputString, strpos($InputString, "")+strlen($ElementName)+3, strlen($InputString)); } return $Elements; } - - + + } -?> +?> \ No newline at end of file diff --git a/dashboard/pgs/class.peer.php b/dashboard/pgs/class.peer.php new file mode 100644 index 0000000..ae39c1b --- /dev/null +++ b/dashboard/pgs/class.peer.php @@ -0,0 +1,32 @@ +IP = $IP; + $this->Protocol = $Protocol; + $this->ConnectTime = ParseTime($ConnectTime); + $this->LastHeardTime = ParseTime($LastHeardTime); + $this->Callsign = trim($Callsign); + $this->LinkedModule = trim($LinkedModule); + } + + + public function GetCallsign() { return $this->Callsign; } + public function GetIP() { return $this->IP; } + public function GetLinkedModule() { return $this->LinkedModule; } + public function GetProtocol() { return $this->Protocol; } + public function GetConnectTime() { return $this->ConnectTime; } + public function GetLastHeardTime() { return $this->LastHeardTime; } + +} + +?> \ No newline at end of file diff --git a/dashboard/pgs/class.reflector.php b/dashboard/pgs/class.reflector.php index c391f3d..35265a7 100644 --- a/dashboard/pgs/class.reflector.php +++ b/dashboard/pgs/class.reflector.php @@ -1,39 +1,17 @@ . ----------------------------------------------------------------------------- -*/ class xReflector { public $Nodes = null; public $Stations = null; + public $Peers = null; private $Flagarray = null; private $Flagfile = null; public function __construct() { $this->Nodes = array(); $this->Stations = array(); + $this->Peers = array(); } public function SetFlagFile($Flagfile) { @@ -89,6 +67,23 @@ class xReflector { return false; } + public function AddPeer($PeerObject) { + if (is_object($PeerObject)) { + $this->Peers[] = $PeerObject; + } + } + + public function PeerCount() { + return count($this->Peers); + } + + public function GetPeer($ArrayIndex) { + if (isset($this->Peer[$ArrayIndex])) { + return $this->Peer[$ArrayIndex]; + } + return false; + } + public function AddStation($StationObject, $AllowDouble = false) { if (is_object($StationObject)) { diff --git a/dashboard/pgs/class.station.php b/dashboard/pgs/class.station.php old mode 100755 new mode 100644 index ec1d858..82e247c --- a/dashboard/pgs/class.station.php +++ b/dashboard/pgs/class.station.php @@ -1,38 +1,18 @@ . -// ---------------------------------------------------------------------------- class Station { - + private $Callsign; private $Via; private $LastHeardTime; private $Suffix; private $CallsignOnly; - - public function __construct($Callsign, $Via, $LastHeardTime) { + private $Peer; + + public function __construct($Callsign, $Via, $Peer, $LastHeardTime) { $this->Callsign = trim($Callsign); $this->Via = trim($Via); + $this->Peer = trim($Peer); $this->LastHeardTime = ParseTime($LastHeardTime); if (strpos($Callsign, " / ") !== false) { $this->Suffix = trim(substr($Callsign, strpos($Callsign, " / ")+3, strlen($Callsign))); @@ -40,17 +20,18 @@ class Station { else { $this->Suffix = ""; } - + $tmp = explode(" ", $Callsign); $this->CallsignOnly = $tmp[0]; } - + public function GetCallsign() { return $this->Callsign; } public function GetVIA() { return $this->Via; } + public function GetPeer() { return $this->Peer; } public function GetLastHeardTime() { return $this->LastHeardTime; } public function GetSuffix() { return $this->Suffix; } public function GetCallsignOnly() { return $this->CallsignOnly; } - + } -?> +?> \ No newline at end of file diff --git a/dashboard/pgs/country.csv b/dashboard/pgs/country.csv index d950590..a8f092c 100644 --- a/dashboard/pgs/country.csv +++ b/dashboard/pgs/country.csv @@ -107,7 +107,7 @@ Iraq;IQ;YI Ireland;IE;EI-EJ Isle of Man;IM;GD-GT Israel;IL;4X-4Z -Italy;IT;I0-I1-I2-I3-I4-I5-I6-I7-I8-I9-IU-IZ-IR-IW-IK-IS +Italy;IT;I0-I1-I2-I3-I4-I5-I6-I7-I8-I9-IU-IZ-IR-IW-IK Jamaica;JM;6Y Japan;JP;JA-JB-JC-JD-JE-JF-JG-JH-JI-JJ-JK-JL-JM-JN-JO-JP-JQ-JR-JS-7J-7K-7L-7M-7N Jersey;JE;GJ-GH @@ -175,7 +175,7 @@ Peru;PE;OA-OB-OC Philippines;PH;DU-DV-DW-DX-DY-DZ-4D-4E-4F-4G-4H-4I Pitcairn;PN;VP6 Poland;PL;SN-SO-SP-SQ-SR -Portugal;PT;CT-CU-CQ-CS-CR +Portugal;PT;CT Puerto Rico;PR;KP3-KP4 Qatar;QA;A7 Runion;RE;FR-TO @@ -232,7 +232,7 @@ Tuvalu;TV;T2 Uganda;UG;5X Ukraine;UA;UR-US-UT-UU-UV-UW-UX-UY-UZ United Arab Emirates;AE;A6 -United Kingdom;GB;2E-M0-M1-M2-M3-M4-M5-M6-M7-M8-M9-G0-G1-G2-G3-G4-G5-G6-G7-G8-G9-GX +United Kingdom;GB;2E-M0-M1-M2-M3-M4-M5-M6-M7-M8-M9-MI-G0-G1-G2-G3-G4-G5-G6-G7-G8-G9-GX United States;US;K0-K1-K2-K3-K4-K5-K6-K7-K8-K9-KC-W0-W1-W2-W3-W4-W5-W6-W7-W8-W9-N0-N1-N2-N3-N4-N5-N6-N7-N8-N9-NO-WB-AA-AB-AC-AD-AE-AF-AG-AH-AI-AJ-AK-NS-KD United States Minor Outlying Islands;UM; Uruguay;UY;CV-CW-CX diff --git a/dashboard/pgs/functions.php b/dashboard/pgs/functions.php old mode 100755 new mode 100644 index 82dd0d2..6826df1 --- a/dashboard/pgs/functions.php +++ b/dashboard/pgs/functions.php @@ -1,26 +1,4 @@ . -// ---------------------------------------------------------------------------- function GetSystemUptime() { $out = exec("uptime"); @@ -34,11 +12,11 @@ function Debug($message) { } function ParseTime($Input) { - + if (strpos($Input, "<") !== false) { $Input = substr($Input, 0, strpos($Input, "<")); } - + // Tuesday Tue Nov 17 14:23:22 2015 $tmp = explode(" ", $Input); if (strlen(trim($tmp[3])) == 0) { @@ -46,7 +24,7 @@ function ParseTime($Input) { $tmp = array_values($tmp); } - $tmp1 = explode(":", $tmp[4]); + $tmp1 = explode(":", $tmp[4]); $month = ""; switch (strtolower($tmp[2])) { case 'jan' : $month = 1; break; @@ -61,15 +39,15 @@ function ParseTime($Input) { case 'oct' : $month = 10; break; case 'nov' : $month = 11; break; case 'dec' : $month = 12; break; - default : $month = 1; + default : $month = 1; } return mktime($tmp1[0], $tmp1[1], $tmp1[2], $month, $tmp[3], $tmp[5]); - + } function FormatSeconds($seconds) { - $seconds = abs($seconds); + $seconds = abs($seconds); return sprintf("%d days %02d:%02d:%02d", $seconds/60/60/24,($seconds/60/60)%24,($seconds/60)%60,$seconds%60); -} +} -?> +?> \ No newline at end of file diff --git a/dashboard/pgs/liveccs.php b/dashboard/pgs/liveccs.php old mode 100755 new mode 100644 index 3ab47dd..6497083 --- a/dashboard/pgs/liveccs.php +++ b/dashboard/pgs/liveccs.php @@ -1,27 +1,4 @@ -. -// ---------------------------------------------------------------------------- -?>
+ \ No newline at end of file diff --git a/dashboard/pgs/liveircddb.php b/dashboard/pgs/liveircddb.php old mode 100755 new mode 100644 index 1719aa0..13f5a90 --- a/dashboard/pgs/liveircddb.php +++ b/dashboard/pgs/liveircddb.php @@ -1,27 +1,4 @@ -. -// ---------------------------------------------------------------------------- -?>
+ \ No newline at end of file diff --git a/dashboard/pgs/peers.php b/dashboard/pgs/peers.php new file mode 100644 index 0000000..367dff6 --- /dev/null +++ b/dashboard/pgs/peers.php @@ -0,0 +1,35 @@ + + + + + + + + + + +LoadFlags(); + +for ($i=0;$i<$Reflector->PeerCount();$i++) { + + if ($odd == "#FFFFFF") { $odd = "#F1FAFA"; } else { $odd = "#FFFFFF"; } + + echo ' + + + + + + + + + '; + if ($i == 99) { $i = $Reflector->PeerCount()+1; } +} + +?> + +
#XLX PeerLast HeardLinked forProtocolModuleIP
'.($i+1).''.$Reflector->Peers[$i]->GetCallSign().''.date("d.m.Y H:i", $Reflector->Peers[$i]->GetLastHeardTime()).''.FormatSeconds(time()-$Reflector->Peers[$i]->GetConnectTime()).' s'.$Reflector->Peers[$i]->GetProtocol().''.$Reflector->Peers[$i]->GetLinkedModule().''.$Reflector->Peers[$i]->GetIP().'
diff --git a/dashboard/pgs/repeaters.php b/dashboard/pgs/repeaters.php index 75c749c..f3d0509 100644 --- a/dashboard/pgs/repeaters.php +++ b/dashboard/pgs/repeaters.php @@ -1,40 +1,14 @@ -. ----------------------------------------------------------------------------- -*/ -?> - + - - - + + + - - + + NodeCount();$i++) { '; - if ($i == 39) { $i = $Reflector->NodeCount()+1; } + if ($i == 99) { $i = $Reflector->NodeCount()+1; } } ?> diff --git a/dashboard/pgs/users.php b/dashboard/pgs/users.php index 5fb194a..5958f05 100644 --- a/dashboard/pgs/users.php +++ b/dashboard/pgs/users.php @@ -1,29 +1,3 @@ -. ----------------------------------------------------------------------------- -*/ -?>
#FlagFlag DV StationBandLast HeardLinked forBandLast HeardLinked for ProtocolModuleIPModuleIP
'.$Reflector->Nodes[$i]->GetLinkedModule().' '.$Reflector->Nodes[$i]->GetIP().'
- + StationCount();$i++) { echo ' - - + '; if ($i == 39) { $i = $Reflector->StationCount()+1; } diff --git a/readme b/readme index acfd711..d5287d7 100644 --- a/readme +++ b/readme @@ -1,87 +1,90 @@ -1. Copyright: - -© 2016 Luc Engelmann LX1IQ - -The XLX Multiprotocol Gateway Reflector Server is part of the software system -for the D-Star Network. -The sources are published under GPL Licenses. - -2. Usage: - -The packages which are described in this document are designed to install server -software which is used for the D-Star network infrastructure. -It requires a 24/7 internet connection which can support 20 voice streams or more -to connect repeaters and hotspot dongles!! - -- The server requires a fix IP-address ! -- The public IP address should have a DNS record which must be published in the -common host files. - -If you want to run this software please make sure that you can provide this -service free of charge, like the developer team provides the software and the -network infrastructure free of charge! - -3. Requirements: - -The software packages for Linux are tested on Debian7 (Wheezy) 32 and 64bit or newer. -Raspbian will work but is not recommended. -Please use the stable version listed above, we cannot support others. - -4. Installation: - -Debian 7 (Wheezy) 32 and 64bit: - -// after a clean installation of debian make sure to run update and upgrade -# apt-get update -# apt-get upgrade - -// install git -# apt-get install git git-core - -// install webserver with PHP5 support -# apt-get install apache2 php5 - -//install g++ compiler - # apt-get install build-essential - -//download and compile the XLX sources -# git clone https://github.com/LX3JL/xlxd.git -# cd xlxd/src/ -# make -# make clean -# make install - -// copy startup script “xlxd” to /etc/init.d -# cp ~/xlxd/scripts/xlxd /etc/init.d/xlxd - -// adapt the default startup parameters to your needs -# pico /etc/init.d/xlxd - -// Last step is to declare the service for automatic startup and shutdown -# service xlxd start -# service xlxd status -# update-rc.d xlxd defaults - -// start or stop the service with: -# service xlxd start -# service xlxd stop - -// copy dashboard to /var/www -# cp -r ~/xlxd/dashboard /var/www/db - -// reboot server to see if the auto-start is working -# reboot - - -5. Firewall settings: - -XLX Server requires the following ports to be open and forwarded properly for in- and outgoing network traffic: - TCP port 80 (http) optional TCP port 443 (https) - TCP port 8080 (RepNet) - UDP port 10001 (json interface XLX Core) - TCP port 22 (ssh) optional TCP port 10022 - UDP port 30001 (DExtra protocol) - UPD port 20001 (DPlus protocol) - UDP port 30051 (DCS protocol) - -© 2016 Luc Engelmann LX1IQ +1. Copyright: + + 2016 Luc Engelmann LX1IQ + +The XLX Multiprotocol Gateway Reflector Server is part of the software system +for the D-Star Network. +The sources are published under GPL Licenses. + +2. Usage: + +The packages which are described in this document are designed to install server +software which is used for the D-Star network infrastructure. +It requires a 24/7 internet connection which can support 20 voice streams or more +to connect repeaters and hotspot dongles!! + +- The server requires a fix IP-address ! +- The public IP address should have a DNS record which must be published in the +common host files. + +If you want to run this software please make sure that you can provide this +service free of charge, like the developer team provides the software and the +network infrastructure free of charge! + +3. Requirements: + +The software packages for Linux are tested on Debian7 (Wheezy) 32 and 64bit or newer. +Raspbian will work but is not recommended. +Please use the stable version listed above, we cannot support others. + +4. Installation: + +Debian 7 (Wheezy) 32 and 64bit: + +// after a clean installation of debian make sure to run update and upgrade +# apt-get update +# apt-get upgrade + +// install git +# apt-get install git git-core + +// install webserver with PHP5 support +# apt-get install apache2 php5 + +//install g++ compiler + # apt-get install build-essential + # apt-get install g++-4.7 (skip this step on Debian 8.x) + +//download and compile the XLX sources +# git clone https://github.com/LX3JL/xlxd.git +# cd xlxd/src/ +# make +# make clean +# make install + +// copy startup script "xlxd" to /etc/init.d +# cp ~/xlxd/scripts/xlxd /etc/init.d/xlxd + +// adapt the default startup parameters to your needs +# pico /etc/init.d/xlxd + +// Last step is to declare the service for automatic startup and shutdown +# update-rc.d xlxd defaults + +// start or stop the service with: +# service xlxd start +# service xlxd stop + +// copy dashboard to /var/www +# cp -r ~/xlxd/dashboard /var/www/db + +// give the dashboard read access to the server log file +# chmod +r /var/log/messages + +// reboot server to see if the auto-start is working +# reboot + + +5. Firewall settings: + +XLX Server requires the following ports to be open and forwarded properly for in- and outgoing network traffic: + TCP port 80 (http) optional TCP port 443 (https) + TCP port 8080 (RepNet) + UDP port 10001 (json interface XLX Core) + UDP port 10002 (XLX interlink) + TCP port 22 (ssh) optional TCP port 10022 + UDP port 30001 (DExtra protocol) + UPD port 20001 (DPlus protocol) + UDP port 30051 (DCS protocol) + + 2016 Luc Engelmann LX1IQ diff --git a/src/cbuffer.cpp b/src/cbuffer.cpp index 879ba8d..097267b 100644 --- a/src/cbuffer.cpp +++ b/src/cbuffer.cpp @@ -78,6 +78,12 @@ void CBuffer::Append(uint16 ui) ::memcpy(&(data()[n]), &ui, sizeof(uint16)); } +void CBuffer::Append(const char *sz) +{ + Append((uint8 *)sz, (int)strlen(sz)); + Append((uint8)0x00); +} + //////////////////////////////////////////////////////////////////////////////////////// // operation diff --git a/src/cbuffer.h b/src/cbuffer.h index 5f1b08d..8b6b574 100644 --- a/src/cbuffer.h +++ b/src/cbuffer.h @@ -44,6 +44,7 @@ public: void Append(uint8, int); void Append(uint8); void Append(uint16); + void Append(const char *); // operation int Compare(uint8 *, int) const; diff --git a/src/ccallsignlist.cpp b/src/ccallsignlist.cpp index 2554054..cddf346 100644 --- a/src/ccallsignlist.cpp +++ b/src/ccallsignlist.cpp @@ -37,26 +37,13 @@ CCallsignList::CCallsignList() ::memset(&m_LastModTime, 0, sizeof(CCallsignList)); } -//////////////////////////////////////////////////////////////////////////////////////// -// destructor - -CCallsignList::~CCallsignList() -{ - if ( m_Filename != NULL ) - { - delete m_Filename; - } -} - - - //////////////////////////////////////////////////////////////////////////////////////// // file io bool CCallsignList::LoadFromFile(const char *filename) { bool ok = false; - char sz[32]; + char sz[256]; // and load std::ifstream file (filename); @@ -71,10 +58,10 @@ bool CCallsignList::LoadFromFile(const char *filename) { // remove leading & trailing spaces char *szt = TrimWhiteSpaces(sz); - // and load - if ( ::strlen(szt) > 0 ) + // and load if not comment + if ( (::strlen(szt) > 0) && (szt[0] != '#') ) { - push_back(CCallsign(szt)); + push_back(CCallsignListItem(CCallsign(szt), CIp(), NULL)); } } // close file @@ -125,7 +112,7 @@ bool CCallsignList::NeedReload(void) //////////////////////////////////////////////////////////////////////////////////////// // compare -bool CCallsignList::IsListed(const CCallsign &callsign) const +bool CCallsignList::IsCallsignListed(const CCallsign &callsign) const { bool listed = false; @@ -137,6 +124,55 @@ bool CCallsignList::IsListed(const CCallsign &callsign) const return listed; } +bool CCallsignList::IsCallsignListed(const CCallsign &callsign, char module) const +{ + bool listed = false; + + for ( int i = 0; (i < size()) && !listed; i++ ) + { + const CCallsignListItem *item = &(data()[i]); + listed = (item->HasSameCallsign(callsign) && item->HasModuleListed(module)); + + } + + return listed; +} + +bool CCallsignList::IsCallsignListed(const CCallsign &callsign, char *modules) const +{ + bool listed = false; + + for ( int i = 0; (i < size()) && !listed; i++ ) + { + const CCallsignListItem *item = &(data()[i]); + listed = (item->HasSameCallsign(callsign) && item->CheckListedModules(modules)); + + } + + return listed; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// find + +CCallsignListItem *CCallsignList::FindListItem(const CCallsign &Callsign) +{ + CCallsignListItem *item = NULL; + + // find client + for ( int i = 0; (i < size()) && (item == NULL); i++ ) + { + if ( (data()[i]).GetCallsign().HasSameCallsign(Callsign) ) + { + item = &(data()[i]); + } + } + + // done + return item; + +} + //////////////////////////////////////////////////////////////////////////////////////// // helpers @@ -144,16 +180,16 @@ char *CCallsignList::TrimWhiteSpaces(char *str) { char *end; - // Trim leading space - while(*str == ' ') str++; + // Trim leading space & tabs + while((*str == ' ') || (*str == '\t')) str++; // All spaces? if(*str == 0) return str; - // Trim trailing space + // Trim trailing space, tab or lf end = str + ::strlen(str) - 1; - while((end > str) && (*end == ' ')) end--; + while((end > str) && ((*end == ' ') || (*end == '\t') || (*end == '\r'))) end--; // Write new null terminator *(end+1) = 0; diff --git a/src/ccallsignlist.h b/src/ccallsignlist.h index 3f749f4..90b7c96 100644 --- a/src/ccallsignlist.h +++ b/src/ccallsignlist.h @@ -27,32 +27,37 @@ #define ccallsignlist_h #include "main.h" -#include "ccallsign.h" +#include "ccallsignlistitem.h" //////////////////////////////////////////////////////////////////////////////////////// // class -class CCallsignList : public std::vector +class CCallsignList : public std::vector { public: // constructor CCallsignList(); // destructor - virtual ~CCallsignList(); + virtual ~CCallsignList() {} // locks void Lock(void) { m_Mutex.lock(); } void Unlock(void) { m_Mutex.unlock(); } // file io - bool LoadFromFile(const char *); + virtual bool LoadFromFile(const char *); bool ReloadFromFile(void); bool NeedReload(void); // compare - bool IsListed(const CCallsign &) const; + bool IsCallsignListed(const CCallsign &) const; + bool IsCallsignListed(const CCallsign &, char) const; + bool IsCallsignListed(const CCallsign &, char*) const; + // find + CCallsignListItem *FindListItem(const CCallsign &); + protected: // bool GetLastModTime(time_t *); diff --git a/src/ccallsignlistitem.cpp b/src/ccallsignlistitem.cpp new file mode 100644 index 0000000..6e2817b --- /dev/null +++ b/src/ccallsignlistitem.cpp @@ -0,0 +1,96 @@ +// +// ccallsignlistitem.cpp +// xlxd +// +// Created by Jean-Luc Deltombe (LX3JL) on 31/01/2016. +// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved. +// +// ---------------------------------------------------------------------------- +// This file is part of xlxd. +// +// xlxd 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 3 of the License, or +// (at your option) any later version. +// +// xlxd 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 Foobar. If not, see . +// ---------------------------------------------------------------------------- + +#include +#include "main.h" +#include "ccallsignlistitem.h" + +//////////////////////////////////////////////////////////////////////////////////////// +// constructor + +CCallsignListItem::CCallsignListItem() +{ + ::memset(m_Modules, 0, sizeof(m_Modules)); +} + +CCallsignListItem::CCallsignListItem(const CCallsign &callsign, const CIp &ip, const char *modules) +{ + m_Callsign = callsign; + m_Ip = ip; + if ( modules != NULL ) + { + :: memset(m_Modules, 0, sizeof(m_Modules)); + ::memcpy(m_Modules, modules, MIN(strlen(modules), sizeof(m_Modules)-1)); + } +} + +CCallsignListItem::CCallsignListItem(const CCallsignListItem &item) +{ + m_Callsign = item.m_Callsign; + m_Ip = item.m_Ip; + ::memcpy(m_Modules, item.m_Modules, sizeof(m_Modules)); +} + + +//////////////////////////////////////////////////////////////////////////////////////// +// compare + +bool CCallsignListItem::HasSameCallsign(const CCallsign &callsign) const +{ + return m_Callsign.HasSameCallsign(callsign); +} + +bool CCallsignListItem::HasSameCallsignWithWidlcard(const CCallsign &callsign) const +{ + return m_Callsign.HasSameCallsignWithWidlcard(callsign); +} + +bool CCallsignListItem::HasModuleListed(char module) const +{ + return (::strchr(m_Modules, (int)module) != NULL); +} + +bool CCallsignListItem::CheckListedModules(char *Modules) const +{ + bool listed = false; + + if ( Modules != NULL ) + { + // build a list of common modules + char list[NB_MODULES_MAX+1]; + list[0] = 0; + // + for ( int i = 0; i < ::strlen(Modules); i++ ) + { + if ( HasModuleListed(Modules[i]) ) + { + ::strncat(list, &(Modules[i]), 1); + listed = true; + } + } + ::strcpy(Modules, list); + } + return listed; +} + diff --git a/src/ccallsignlistitem.h b/src/ccallsignlistitem.h new file mode 100644 index 0000000..1164ee7 --- /dev/null +++ b/src/ccallsignlistitem.h @@ -0,0 +1,67 @@ +// +// ccallsignlistitem.h +// xlxd +// +// Created by Jean-Luc Deltombe (LX3JL) on 31/01/2016. +// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved. +// +// ---------------------------------------------------------------------------- +// This file is part of xlxd. +// +// xlxd 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 3 of the License, or +// (at your option) any later version. +// +// xlxd 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 Foobar. If not, see . +// ---------------------------------------------------------------------------- + +#ifndef ccallsignlistitem_h +#define ccallsignlistitem_h + +#include "main.h" +#include "ccallsign.h" +#include "cip.h" + +//////////////////////////////////////////////////////////////////////////////////////// +// class + +class CCallsignListItem +{ +public: + // constructor + CCallsignListItem(); + CCallsignListItem(const CCallsign &, const CIp &, const char *); + CCallsignListItem(const CCallsignListItem &); + + // destructor + virtual ~CCallsignListItem() {} + + // compare + bool HasSameCallsign(const CCallsign &) const; + bool HasSameCallsignWithWidlcard(const CCallsign &) const; + bool HasModuleListed(char) const; + bool CheckListedModules(char*) const; + + // get + const CCallsign &GetCallsign(void) const { return m_Callsign; } + const CIp &GetIp(void) const { return m_Ip; } + const char *GetModules(void) { return m_Modules; } + +protected: + // data + CCallsign m_Callsign; + CIp m_Ip; + char m_Modules[NB_MODULES_MAX+1]; +}; + + +//////////////////////////////////////////////////////////////////////////////////////// + +#endif /* ccallsignlistitem_h */ diff --git a/src/cclient.cpp b/src/cclient.cpp index f559cb3..173fc6a 100644 --- a/src/cclient.cpp +++ b/src/cclient.cpp @@ -92,7 +92,7 @@ void CClient::WriteXml(std::ofstream &xmlFile) char mbstr[100]; if (std::strftime(mbstr, sizeof(mbstr), "%A %c", std::localtime(&m_ConnectTime))) { - xmlFile << "\t" << mbstr << "" << std::endl; + xmlFile << "\t" << mbstr << "" << std::endl; } if (std::strftime(mbstr, sizeof(mbstr), "%A %c", std::localtime(&m_LastHeardTime))) { diff --git a/src/cclient.h b/src/cclient.h index 1106c76..ab3d53d 100644 --- a/src/cclient.h +++ b/src/cclient.h @@ -56,7 +56,8 @@ public: bool HasModule(void) const { return m_Callsign.HasModule(); } char GetModule(void) const { return m_Callsign.GetModule(); } char GetReflectorModule(void) const { return m_ReflectorModule; } - + virtual bool HasThisReflectorModule(char m) const { return (m_ReflectorModule == m); } + // set void SetModule(char c) { m_Callsign.SetModule(c); } void SetReflectorModule(char c) { m_ReflectorModule = c; } @@ -64,6 +65,8 @@ public: // identity virtual int GetProtocol(void) const { return PROTOCOL_NONE; } virtual const char *GetProtocolName(void) const { return "none"; } + virtual bool IsNode(void) const { return false; } + virtual bool IsPeer(void) const { return false; } // status virtual void Alive(void); diff --git a/src/cdcsclient.h b/src/cdcsclient.h index d8ca7f9..2fd48f9 100644 --- a/src/cdcsclient.h +++ b/src/cdcsclient.h @@ -48,6 +48,7 @@ public: // identity int GetProtocol(void) const { return PROTOCOL_DCS; } const char *GetProtocolName(void) const { return "DCS"; } + bool IsNode(void) const { return true; } // status bool IsAlive(void) const; diff --git a/src/cdcsprotocol.cpp b/src/cdcsprotocol.cpp index 21981d5..358a0f0 100644 --- a/src/cdcsprotocol.cpp +++ b/src/cdcsprotocol.cpp @@ -56,6 +56,10 @@ bool CDcsProtocol::Init(void) // create our socket ok &= m_Socket.Open(DCS_PORT); + if ( !ok ) + { + std::cout << "Error opening socket on port UDP" << DCS_PORT << " on ip " << g_Reflector.GetListenIp() << std::endl; + } // update time m_LastKeepaliveTime.Now(); @@ -183,47 +187,8 @@ void CDcsProtocol::Task(void) // keep client alive if ( m_LastKeepaliveTime.DurationSinceNow() > DCS_KEEPALIVE_PERIOD ) { - // DCS protocol sends and monitors keepalives packets - // event if the client is currently streaming - // so, send keepalives to all - CBuffer keepalive1; - EncodeKeepAlivePacket(&keepalive1); - - // iterate on clients - CClients *clients = g_Reflector.GetClients(); - int index = -1; - CClient *client = NULL; - while ( (client = clients->FindNextClient(PROTOCOL_DCS, &index)) != NULL ) - { - // encode client's specific keepalive packet - CBuffer keepalive2; - EncodeKeepAlivePacket(&keepalive2, client); - - // send keepalive - m_Socket.Send(keepalive1, client->GetIp()); - m_Socket.Send(keepalive2, client->GetIp()); - - // is this client busy ? - if ( client->IsAMaster() ) - { - // yes, just tickle it - client->Alive(); - } - // check it's still with us - else if ( !client->IsAlive() ) - { - // no, disconnect - CBuffer disconnect; - EncodeDisconnectPacket(&disconnect, client); - m_Socket.Send(disconnect, client->GetIp()); - - // remove it - std::cout << "DCS client " << client->GetCallsign() << " keepalive timeout" << std::endl; - clients->RemoveClient(client); - } - - } - g_Reflector.ReleaseClients(); + // + HandleKeepalives(); // update time m_LastKeepaliveTime.Now(); @@ -336,6 +301,53 @@ void CDcsProtocol::HandleQueue(void) m_Queue.Unlock(); } +//////////////////////////////////////////////////////////////////////////////////////// +// keepalive helpers + +void CDcsProtocol::HandleKeepalives(void) +{ + // DCS protocol sends and monitors keepalives packets + // event if the client is currently streaming + // so, send keepalives to all + CBuffer keepalive1; + EncodeKeepAlivePacket(&keepalive1); + + // iterate on clients + CClients *clients = g_Reflector.GetClients(); + int index = -1; + CClient *client = NULL; + while ( (client = clients->FindNextClient(PROTOCOL_DCS, &index)) != NULL ) + { + // encode client's specific keepalive packet + CBuffer keepalive2; + EncodeKeepAlivePacket(&keepalive2, client); + + // send keepalive + m_Socket.Send(keepalive1, client->GetIp()); + m_Socket.Send(keepalive2, client->GetIp()); + + // is this client busy ? + if ( client->IsAMaster() ) + { + // yes, just tickle it + client->Alive(); + } + // check it's still with us + else if ( !client->IsAlive() ) + { + // no, disconnect + CBuffer disconnect; + EncodeDisconnectPacket(&disconnect, client); + m_Socket.Send(disconnect, client->GetIp()); + + // remove it + std::cout << "DCS client " << client->GetCallsign() << " keepalive timeout" << std::endl; + clients->RemoveClient(client); + } + + } + g_Reflector.ReleaseClients(); +} //////////////////////////////////////////////////////////////////////////////////////// // packet decoding helpers @@ -348,7 +360,7 @@ bool CDcsProtocol::IsValidConnectPacket(const CBuffer &Buffer, CCallsign *callsi callsign->SetCallsign(Buffer.data(), 8); callsign->SetModule(Buffer.data()[8]); *reflectormodule = Buffer.data()[9]; - valid = (callsign->IsValid() && std::isupper(*reflectormodule)); + valid = (callsign->IsValid() && IsLetter(*reflectormodule)); } return valid; } diff --git a/src/cdcsprotocol.h b/src/cdcsprotocol.h index bc00c95..dba1637 100644 --- a/src/cdcsprotocol.h +++ b/src/cdcsprotocol.h @@ -53,6 +53,12 @@ public: void Task(void); protected: + // queue helper + void HandleQueue(void); + + // keepalive helpers + void HandleKeepalives(void); + // stream helpers bool OnDvHeaderPacketIn(CDvHeaderPacket *, const CIp &); @@ -71,9 +77,6 @@ protected: void EncodeDvPacket(const CDvHeaderPacket &, const CDvFramePacket &, uint32, CBuffer *) const; void EncodeDvLastPacket(const CDvHeaderPacket &, const CDvFramePacket &, uint32, CBuffer *) const; - // queue helper - void HandleQueue(void); - protected: // for keep alive CTimePoint m_LastKeepaliveTime; diff --git a/src/cdextraclient.h b/src/cdextraclient.h index bb0576e..9c6a10e 100644 --- a/src/cdextraclient.h +++ b/src/cdextraclient.h @@ -48,6 +48,7 @@ public: // identity int GetProtocol(void) const { return PROTOCOL_DEXTRA; } const char *GetProtocolName(void) const { return "Dextra"; } + bool IsNode(void) const { return true; } // status bool IsAlive(void) const; diff --git a/src/cdextraprotocol.cpp b/src/cdextraprotocol.cpp index 2101296..aa7434f 100644 --- a/src/cdextraprotocol.cpp +++ b/src/cdextraprotocol.cpp @@ -45,6 +45,10 @@ bool CDextraProtocol::Init(void) // create our socket ok &= m_Socket.Open(DEXTRA_PORT); + if ( !ok ) + { + std::cout << "Error opening socket on port UDP" << DEXTRA_PORT << " on ip " << g_Reflector.GetListenIp() << std::endl; + } // update time m_LastKeepaliveTime.Now(); @@ -139,7 +143,7 @@ void CDextraProtocol::Task(void) } else if ( IsValidKeepAlivePacket(Buffer, &Callsign) ) { - //std::cout << "DExtra keepalive packet from " << Callsign << " at " << Ip << std::endl; + //std::cout << "DExtra keepalive packet from " << Callsign << " at " << Ip << std::endl; // find all clients with that callsign & ip and keep them alive CClients *clients = g_Reflector.GetClients(); @@ -166,42 +170,8 @@ void CDextraProtocol::Task(void) // keep client alive if ( m_LastKeepaliveTime.DurationSinceNow() > DEXTRA_KEEPALIVE_PERIOD ) { - // DExtra protocol sends and monitors keepalives packets - // event if the client is currently streaming - // so, send keepalives to all - CBuffer keepalive; - EncodeKeepAlivePacket(&keepalive); - - // iterate on clients - CClients *clients = g_Reflector.GetClients(); - int index = -1; - CClient *client = NULL; - while ( (client = clients->FindNextClient(PROTOCOL_DEXTRA, &index)) != NULL ) - { - // send keepalive - m_Socket.Send(keepalive, client->GetIp()); - - // client busy ? - if ( client->IsAMaster() ) - { - // yes, just tickle it - client->Alive(); - } - // otherwise check if still with us - else if ( !client->IsAlive() ) - { - // no, disconnect - CBuffer disconnect; - EncodeDisconnectPacket(&disconnect); - m_Socket.Send(disconnect, client->GetIp()); - - // remove it - std::cout << "DExtra client " << client->GetCallsign() << " keepalive timeout" << std::endl; - clients->RemoveClient(client); - } - - } - g_Reflector.ReleaseClients(); + // + HandleKeepalives(); // update time m_LastKeepaliveTime.Now(); @@ -248,6 +218,49 @@ void CDextraProtocol::HandleQueue(void) m_Queue.Unlock(); } +//////////////////////////////////////////////////////////////////////////////////////// +// keepalive helpers + +void CDextraProtocol::HandleKeepalives(void) +{ + // DExtra protocol sends and monitors keepalives packets + // event if the client is currently streaming + // so, send keepalives to all + CBuffer keepalive; + EncodeKeepAlivePacket(&keepalive); + + // iterate on clients + CClients *clients = g_Reflector.GetClients(); + int index = -1; + CClient *client = NULL; + while ( (client = clients->FindNextClient(PROTOCOL_DEXTRA, &index)) != NULL ) + { + // send keepalive + m_Socket.Send(keepalive, client->GetIp()); + + // client busy ? + if ( client->IsAMaster() ) + { + // yes, just tickle it + client->Alive(); + } + // otherwise check if still with us + else if ( !client->IsAlive() ) + { + // no, disconnect + CBuffer disconnect; + EncodeDisconnectPacket(&disconnect); + m_Socket.Send(disconnect, client->GetIp()); + + // remove it + std::cout << "DExtra client " << client->GetCallsign() << " keepalive timeout" << std::endl; + clients->RemoveClient(client); + } + + } + g_Reflector.ReleaseClients(); +} + //////////////////////////////////////////////////////////////////////////////////////// // streams helpers @@ -301,7 +314,7 @@ bool CDextraProtocol::IsValidConnectPacket(const CBuffer &Buffer, CCallsign *cal callsign->SetCallsign(Buffer.data(), 8); callsign->SetModule(Buffer.data()[8]); *reflectormodule = Buffer.data()[9]; - valid = (callsign->IsValid() && std::isupper(*reflectormodule)); + valid = (callsign->IsValid() && IsLetter(*reflectormodule)); } return valid; } @@ -437,7 +450,6 @@ void CDextraProtocol::EncodeDisconnectPacket(CBuffer *Buffer) Buffer->Set(tag, sizeof(tag)); } - bool CDextraProtocol::EncodeDvHeaderPacket(const CDvHeaderPacket &Packet, CBuffer *Buffer) const { uint8 tag[] = { 'D','S','V','T',0x10,0x00,0x00,0x00,0x20,0x00,0x01,0x02 }; diff --git a/src/cdextraprotocol.h b/src/cdextraprotocol.h index a681676..9c4ab5d 100644 --- a/src/cdextraprotocol.h +++ b/src/cdextraprotocol.h @@ -55,7 +55,10 @@ public: protected: // queue helper void HandleQueue(void); - + + // keepalive helpers + void HandleKeepalives(void); + // stream helpers bool OnDvHeaderPacketIn(CDvHeaderPacket *, const CIp &); diff --git a/src/cdplusclient.h b/src/cdplusclient.h index 186205d..5d7a630 100644 --- a/src/cdplusclient.h +++ b/src/cdplusclient.h @@ -48,6 +48,7 @@ public: // identity int GetProtocol(void) const { return PROTOCOL_DPLUS; } const char *GetProtocolName(void) const { return "Dplus"; } + bool IsNode(void) const { return true; } // status bool IsAlive(void) const; diff --git a/src/cdplusprotocol.cpp b/src/cdplusprotocol.cpp index 1854cf0..6468a4f 100644 --- a/src/cdplusprotocol.cpp +++ b/src/cdplusprotocol.cpp @@ -46,6 +46,10 @@ bool CDplusProtocol::Init(void) // create our socket ok &= m_Socket.Open(DPLUS_PORT); + if ( !ok ) + { + std::cout << "Error opening socket on port UDP" << DPLUS_PORT << " on ip " << g_Reflector.GetListenIp() << std::endl; + } // update time m_LastKeepaliveTime.Now(); @@ -176,40 +180,8 @@ void CDplusProtocol::Task(void) // keep client alive if ( m_LastKeepaliveTime.DurationSinceNow() > DPLUS_KEEPALIVE_PERIOD ) { - // send keepalives - CBuffer keepalive; - EncodeKeepAlivePacket(&keepalive); - - // iterate on clients - CClients *clients = g_Reflector.GetClients(); - int index = -1; - CClient *client = NULL; - while ( (client = clients->FindNextClient(PROTOCOL_DPLUS, &index)) != NULL ) - { - // send keepalive - //std::cout << "Sending DPlus packet @ " << client->GetIp() << std::endl; - m_Socket.Send(keepalive, client->GetIp()); - - // is this client busy ? - if ( client->IsAMaster() ) - { - // yes, just tickle it - client->Alive(); - } - // check it's still with us - else if ( !client->IsAlive() ) - { - // no, disconnect - CBuffer disconnect; - EncodeDisconnectPacket(&disconnect); - m_Socket.Send(disconnect, client->GetIp()); - - // and remove it - std::cout << "DPlus client " << client->GetCallsign() << " keepalive timeout" << std::endl; - clients->RemoveClient(client); - } - } - g_Reflector.ReleaseClients(); + // + HandleKeepalives(); // update time m_LastKeepaliveTime.Now(); @@ -307,6 +279,46 @@ void CDplusProtocol::HandleQueue(void) m_Queue.Unlock(); } +//////////////////////////////////////////////////////////////////////////////////////// +// keepalive helpers + +void CDplusProtocol::HandleKeepalives(void) +{ + // send keepalives + CBuffer keepalive; + EncodeKeepAlivePacket(&keepalive); + + // iterate on clients + CClients *clients = g_Reflector.GetClients(); + int index = -1; + CClient *client = NULL; + while ( (client = clients->FindNextClient(PROTOCOL_DPLUS, &index)) != NULL ) + { + // send keepalive + //std::cout << "Sending DPlus packet @ " << client->GetIp() << std::endl; + m_Socket.Send(keepalive, client->GetIp()); + + // is this client busy ? + if ( client->IsAMaster() ) + { + // yes, just tickle it + client->Alive(); + } + // check it's still with us + else if ( !client->IsAlive() ) + { + // no, disconnect + CBuffer disconnect; + EncodeDisconnectPacket(&disconnect); + m_Socket.Send(disconnect, client->GetIp()); + + // and remove it + std::cout << "DPlus client " << client->GetCallsign() << " keepalive timeout" << std::endl; + clients->RemoveClient(client); + } + } + g_Reflector.ReleaseClients(); +} //////////////////////////////////////////////////////////////////////////////////////// // packet decoding helpers diff --git a/src/cdplusprotocol.h b/src/cdplusprotocol.h index 9cd1bec..799cc04 100644 --- a/src/cdplusprotocol.h +++ b/src/cdplusprotocol.h @@ -53,6 +53,12 @@ public: void Task(void); protected: + // queue helper + void HandleQueue(void); + + // keepalive helpers + void HandleKeepalives(void); + // stream helpers bool OnDvHeaderPacketIn(CDvHeaderPacket *, const CIp &); @@ -74,8 +80,6 @@ protected: bool EncodeDvFramePacket(const CDvFramePacket &, CBuffer *) const; bool EncodeDvLastFramePacket(const CDvLastFramePacket &, CBuffer *) const; - // queue helper - void HandleQueue(void); protected: // for keep alive diff --git a/src/cgatekeeper.cpp b/src/cgatekeeper.cpp index 345bd5e..139f0ec 100644 --- a/src/cgatekeeper.cpp +++ b/src/cgatekeeper.cpp @@ -62,8 +62,9 @@ bool CGateKeeper::Init(void) { // load lists from files - m_WhiteList.LoadFromFile(WHITELIST_PATH); - m_BlackList.LoadFromFile(BLACKLIST_PATH); + m_NodeWhiteList.LoadFromFile(WHITELIST_PATH); + m_NodeBlackList.LoadFromFile(BLACKLIST_PATH); + m_PeerList.LoadFromFile(INTERLINKLIST_PATH); // reset stop flag m_bStopThread = false; @@ -86,16 +87,34 @@ void CGateKeeper::Close(void) } //////////////////////////////////////////////////////////////////////////////////////// -// operation +// authorisations -bool CGateKeeper::MayLink(const CCallsign &callsign, const CIp &ip, int protocol) const +bool CGateKeeper::MayLink(const CCallsign &callsign, const CIp &ip, int protocol, char *modules) const { bool ok = true; - // first check is IP & callsigned listed OK - ok &= IsListedOk(callsign, ip); - - // then apply any protocol specific authorisation for the operation + switch (protocol) + { + // repeaters + case PROTOCOL_DEXTRA: + case PROTOCOL_DPLUS: + case PROTOCOL_DCS: + // first check is IP & callsigned listed OK + ok &= IsNodeListedOk(callsign, ip); + // todo: then apply any protocol specific authorisation for the operation + break; + + // XLX interlinks + case PROTOCOL_XLX: + ok &= IsPeerListedOk(callsign, ip, modules); + break; + + // unsupported + case PROTOCOL_NONE: + default: + ok = false; + break; + } // report if ( !ok ) @@ -107,14 +126,33 @@ bool CGateKeeper::MayLink(const CCallsign &callsign, const CIp &ip, int protocol return ok; } -bool CGateKeeper::MayTransmit(const CCallsign &callsign, const CIp &ip, int protocol) const +bool CGateKeeper::MayTransmit(const CCallsign &callsign, const CIp &ip, int protocol, char module) const { bool ok = true; - // first check is IP & callsigned listed OK - ok &= IsListedOk(callsign, ip); - - // then apply any protocol specific authorisation for the operation + switch (protocol) + { + // repeaters, protocol specific + case PROTOCOL_ANY: + case PROTOCOL_DEXTRA: + case PROTOCOL_DPLUS: + case PROTOCOL_DCS: + // first check is IP & callsigned listed OK + ok &= IsNodeListedOk(callsign, ip); + // todo: then apply any protocol specific authorisation for the operation + break; + + // XLX interlinks + case PROTOCOL_XLX: + ok &= IsPeerListedOk(callsign, ip, module); + break; + + // unsupported + case PROTOCOL_NONE: + default: + ok = false; + break; + } // report if ( !ok ) @@ -126,7 +164,6 @@ bool CGateKeeper::MayTransmit(const CCallsign &callsign, const CIp &ip, int prot return ok; } - //////////////////////////////////////////////////////////////////////////////////////// // thread @@ -138,13 +175,17 @@ void CGateKeeper::Thread(CGateKeeper *This) CTimePoint::TaskSleepFor(30000); // have lists files changed ? - if ( This->m_WhiteList.NeedReload() ) + if ( This->m_NodeWhiteList.NeedReload() ) { - This->m_WhiteList.ReloadFromFile(); + This->m_NodeWhiteList.ReloadFromFile(); } - if ( This->m_BlackList.NeedReload() ) + if ( This->m_NodeBlackList.NeedReload() ) { - This->m_BlackList.ReloadFromFile(); + This->m_NodeBlackList.ReloadFromFile(); + } + if ( This->m_PeerList.NeedReload() ) + { + This->m_PeerList.ReloadFromFile(); } } } @@ -152,7 +193,7 @@ void CGateKeeper::Thread(CGateKeeper *This) //////////////////////////////////////////////////////////////////////////////////////// // operation helpers -bool CGateKeeper::IsListedOk(const CCallsign &callsign, const CIp &ip) const +bool CGateKeeper::IsNodeListedOk(const CCallsign &callsign, const CIp &ip) const { bool ok = true; @@ -163,20 +204,65 @@ bool CGateKeeper::IsListedOk(const CCallsign &callsign, const CIp &ip) const { // first check if callsign is in white list // note if white list is empty, everybody is authorized - const_cast(m_WhiteList).Lock(); - if ( !m_WhiteList.empty() ) + const_cast(m_NodeWhiteList).Lock(); + if ( !m_NodeWhiteList.empty() ) { - ok = m_WhiteList.IsListed(callsign); + ok = m_NodeWhiteList.IsCallsignListed(callsign); } - const_cast(m_WhiteList).Unlock(); + const_cast(m_NodeWhiteList).Unlock(); // then check if not blacklisted - const_cast(m_BlackList).Lock(); - ok &= !m_BlackList.IsListed(callsign); - const_cast(m_BlackList).Unlock(); + const_cast(m_NodeBlackList).Lock(); + ok &= !m_NodeBlackList.IsCallsignListed(callsign); + const_cast(m_NodeBlackList).Unlock(); } // done return ok; } + +bool CGateKeeper::IsPeerListedOk(const CCallsign &callsign, const CIp &ip, char module) const +{ + bool ok = true; + + // first check IP + + // next, check callsign + if ( ok ) + { + // look for an exact match in the list + const_cast(m_PeerList).Lock(); + if ( !m_PeerList.empty() ) + { + ok = m_PeerList.IsCallsignListed(callsign, module); + } + const_cast(m_PeerList).Unlock(); + } + + // done + return ok; +} + +bool CGateKeeper::IsPeerListedOk(const CCallsign &callsign, const CIp &ip, char *modules) const +{ + bool ok = true; + + // first check IP + + // next, check callsign + if ( ok ) + { + // look for an exact match in the list + const_cast(m_PeerList).Lock(); + if ( !m_PeerList.empty() ) + { + ok = m_PeerList.IsCallsignListed(callsign, modules); + } + const_cast(m_PeerList).Unlock(); + } + + // done + return ok; +} + diff --git a/src/cgatekeeper.h b/src/cgatekeeper.h index b6bff36..599b198 100644 --- a/src/cgatekeeper.h +++ b/src/cgatekeeper.h @@ -29,6 +29,7 @@ #include "ccallsign.h" #include "cip.h" #include "ccallsignlist.h" +#include "cpeercallsignlist.h" //////////////////////////////////////////////////////////////////////////////////////// // class @@ -46,25 +47,32 @@ public: bool Init(void); void Close(void); - // operation - bool MayLink(const CCallsign &, const CIp &, int) const; - bool MayTransmit(const CCallsign &, const CIp &, int) const; + // authorizations + bool MayLink(const CCallsign &, const CIp &, int, char * = NULL) const; + bool MayTransmit(const CCallsign &, const CIp &, int = PROTOCOL_ANY, char = ' ') const; + + // peer list handeling + CPeerCallsignList *GetPeerList(void) { m_PeerList.Lock(); return &m_PeerList; } + void ReleasePeerList(void) { m_PeerList.Unlock(); } protected: // thread static void Thread(CGateKeeper *); // operation helpers - bool IsListedOk(const CCallsign &, const CIp &) const; + bool IsNodeListedOk(const CCallsign &, const CIp &) const; + bool IsPeerListedOk(const CCallsign &, const CIp &, char) const; + bool IsPeerListedOk(const CCallsign &, const CIp &, char *) const; protected: // data - CCallsignList m_WhiteList; - CCallsignList m_BlackList; + CCallsignList m_NodeWhiteList; + CCallsignList m_NodeBlackList; + CPeerCallsignList m_PeerList; // thread - bool m_bStopThread; - std::thread *m_pThread; + bool m_bStopThread; + std::thread *m_pThread; }; diff --git a/src/cip.cpp b/src/cip.cpp index 6d496d4..10ac1ca 100644 --- a/src/cip.cpp +++ b/src/cip.cpp @@ -24,21 +24,34 @@ #include "main.h" #include -#include #include "cip.h" +#include + //////////////////////////////////////////////////////////////////////////////////////// // constructors CIp::CIp() { ::memset(&m_Addr, 0, sizeof(m_Addr)); + m_Addr.sin_family = AF_INET; } CIp::CIp(const char *sz) { ::memset(&m_Addr, 0, sizeof(m_Addr)); + m_Addr.sin_family = AF_INET; + // try xxx.xxx.xxx.xxxx first m_Addr.sin_addr.s_addr = inet_addr(sz); + if ( m_Addr.sin_addr.s_addr == INADDR_NONE ) + { + // otherwise try to resolve via dns + hostent *record = gethostbyname(sz); + if( record != NULL ) + { + m_Addr.sin_addr.s_addr = ((in_addr * )record->h_addr)->s_addr; + } + } } CIp::CIp(const struct sockaddr_in *sa) diff --git a/src/cpacket.cpp b/src/cpacket.cpp index 2c24bc1..f6b9154 100644 --- a/src/cpacket.cpp +++ b/src/cpacket.cpp @@ -33,6 +33,7 @@ CPacket::CPacket() m_uiStreamId = 0; m_uiPacketId = 0; m_uiModuleId = ' '; + m_uiOriginId = ORIGIN_LOCAL; }; CPacket::CPacket(uint16 sid, uint8 pid) @@ -40,6 +41,7 @@ CPacket::CPacket(uint16 sid, uint8 pid) m_uiStreamId = sid; m_uiPacketId = pid; m_uiModuleId = ' '; + m_uiOriginId = ORIGIN_LOCAL; }; //////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/cpacket.h b/src/cpacket.h index 34439e1..0f6d46f 100644 --- a/src/cpacket.h +++ b/src/cpacket.h @@ -27,7 +27,10 @@ //////////////////////////////////////////////////////////////////////////////////////// +// Origin Id +#define ORIGIN_LOCAL 0 +#define ORIGIN_PEER 1 //////////////////////////////////////////////////////////////////////////////////////// // class @@ -55,15 +58,19 @@ public: uint16 GetStreamId(void) const { return m_uiStreamId; } uint8 GetPacketId(void) const { return m_uiPacketId; } uint8 GetModuleId(void) const { return m_uiModuleId; } + bool IsLocalOrigin(void) const { return (m_uiOriginId == ORIGIN_LOCAL); } // set void SetModuleId(uint8 uiId) { m_uiModuleId = uiId; } + void SetLocalOrigin(void) { m_uiOriginId = ORIGIN_LOCAL; } + void SetRemotePeerOrigin(void) { m_uiOriginId = ORIGIN_PEER; } protected: // data uint16 m_uiStreamId; uint8 m_uiPacketId; uint8 m_uiModuleId; + uint8 m_uiOriginId; }; diff --git a/src/cpeercallsignlist.cpp b/src/cpeercallsignlist.cpp new file mode 100644 index 0000000..45b826d --- /dev/null +++ b/src/cpeercallsignlist.cpp @@ -0,0 +1,95 @@ +// +// cxlxcallsignlist.cpp +// xlxd +// +// Created by Jean-Luc Deltombe (LX3JL) on 31/01/2016. +// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved. +// +// ---------------------------------------------------------------------------- +// This file is part of xlxd. +// +// xlxd 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 3 of the License, or +// (at your option) any later version. +// +// xlxd 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 Foobar. If not, see . +// ---------------------------------------------------------------------------- + +#include +#include "main.h" +#include "cpeercallsignlist.h" + + +//////////////////////////////////////////////////////////////////////////////////////// +// file io + +bool CPeerCallsignList::LoadFromFile(const char *filename) +{ + bool ok = false; + char sz[256]; + + // and load + std::ifstream file (filename); + if ( file.is_open() ) + { + Lock(); + + // empty list + clear(); + // fill with file content + while ( file.getline(sz, sizeof(sz)).good() ) + { + // remove leading & trailing spaces + char *szt = TrimWhiteSpaces(sz); + + // crack it + if ( (::strlen(szt) > 0) && (szt[0] != '#') ) + { + // 1st token is callsign + if ( (szt = ::strtok(szt, " ,\t")) != NULL ) + { + CCallsign callsign(szt); + // 2nd token is ip + if ( (szt = ::strtok(NULL, " ,\t")) != NULL ) + { + CIp ip(szt); + // 3rd token is modules list + if ( (szt = ::strtok(NULL, " ,\t")) != NULL ) + { + // and load + push_back(CCallsignListItem(callsign, ip, szt)); + } + } + } + } + } + // close file + file.close(); + + // keep file path + m_Filename = filename; + + // update time + GetLastModTime(&m_LastModTime); + + // and done + Unlock(); + ok = true; + std::cout << "Gatekeeper loaded " << size() << " lines from " << filename << std::endl; + } + else + { + std::cout << "Gatekeeper cannot find " << filename << std::endl; + } + + return ok; +} + + diff --git a/src/cpeercallsignlist.h b/src/cpeercallsignlist.h new file mode 100644 index 0000000..1c58f18 --- /dev/null +++ b/src/cpeercallsignlist.h @@ -0,0 +1,51 @@ +// +// cpeercallsignlist.h +// xlxd +// +// Created by Jean-Luc Deltombe (LX3JL) on 31/01/2016. +// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved. +// +// ---------------------------------------------------------------------------- +// This file is part of xlxd. +// +// xlxd 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 3 of the License, or +// (at your option) any later version. +// +// xlxd 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 Foobar. If not, see . +// ---------------------------------------------------------------------------- + + +#ifndef cpeercallsignlist_h +#define cpeercallsignlist_h + + +#include "main.h" +#include "ccallsignlist.h" + +//////////////////////////////////////////////////////////////////////////////////////// +// class + +class CPeerCallsignList : public CCallsignList +{ +public: + // constructor + CPeerCallsignList() {}; + + // destructor + virtual ~CPeerCallsignList() {}; + + // file io + bool LoadFromFile(const char *); +}; + + +//////////////////////////////////////////////////////////////////////////////////////// +#endif /* cpeercallsignlist_h */ diff --git a/src/cprotocol.cpp b/src/cprotocol.cpp index 04cadff..6922d68 100644 --- a/src/cprotocol.cpp +++ b/src/cprotocol.cpp @@ -216,5 +216,22 @@ void CProtocol::HandleQueue(void) m_Queue.Unlock(); } +//////////////////////////////////////////////////////////////////////////////////////// +// syntax helper + +bool CProtocol::IsNumber(char c) const +{ + return ((c >= '0') && (c <= '9')); +} + +bool CProtocol::IsLetter(char c) const +{ + return ((c >= 'A') && (c <= 'Z')); +} + +bool CProtocol::IsSpace(char c) const +{ + return (c == ' '); +} diff --git a/src/cprotocol.h b/src/cprotocol.h index 64129d5..f176e57 100644 --- a/src/cprotocol.h +++ b/src/cprotocol.h @@ -80,6 +80,14 @@ protected: // queue helper virtual void HandleQueue(void); + // keepalive helpers + virtual void HandleKeepalives(void) {} + + // syntax helper + bool IsNumber(char) const; + bool IsLetter(char) const; + bool IsSpace(char) const; + protected: // socket CUdpSocket m_Socket; diff --git a/src/cprotocols.cpp b/src/cprotocols.cpp index 1254592..341cc97 100644 --- a/src/cprotocols.cpp +++ b/src/cprotocols.cpp @@ -26,6 +26,7 @@ #include "cdextraprotocol.h" #include "cdplusprotocol.h" #include "cdcsprotocol.h" +#include "cxlxprotocol.h" #include "cprotocols.h" @@ -78,7 +79,11 @@ bool CProtocols::Init(void) delete m_Protocols[2]; m_Protocols[2] = new CDcsProtocol; ok &= m_Protocols[2]->Init(); - + + // create and initialize XLX - interlink + delete m_Protocols[3]; + m_Protocols[3] = new CXlxProtocol; + ok &= m_Protocols[3]->Init(); } m_Mutex.unlock(); diff --git a/src/creflector.cpp b/src/creflector.cpp index dfcc8fb..a094daa 100644 --- a/src/creflector.cpp +++ b/src/creflector.cpp @@ -96,18 +96,26 @@ bool CReflector::Start(void) // create protocols ok &= m_Protocols.Init(); - - // start one thread per reflector module - for ( int i = 0; i < NB_OF_MODULES; i++ ) + + // if ok, start threads + if ( ok ) { - m_RouterThreads[i] = new std::thread(CReflector::RouterThread, this, &(m_Streams[i])); - } + // start one thread per reflector module + for ( int i = 0; i < NB_OF_MODULES; i++ ) + { + m_RouterThreads[i] = new std::thread(CReflector::RouterThread, this, &(m_Streams[i])); + } - // start the reporting threads - m_XmlReportThread = new std::thread(CReflector::XmlReportThread, this); + // start the reporting threads + m_XmlReportThread = new std::thread(CReflector::XmlReportThread, this); #ifdef JSON_MONITOR - m_JsonReportThread = new std::thread(CReflector::JsonReportThread, this); + m_JsonReportThread = new std::thread(CReflector::JsonReportThread, this); #endif + } + else + { + m_Protocols.Close(); + } // done return ok; @@ -531,14 +539,33 @@ void CReflector::WriteXmlFile(std::ofstream &xmlFile) ::sprintf(sz, "%d.%d.%d", VERSION_MAJOR, VERSION_MINOR, VERSION_REVISION); xmlFile << "" << sz << "" << std::endl; - // linked nodes - xmlFile << "<" << m_Callsign << "linked nodes>" << std::endl; + // linked peers + xmlFile << "<" << m_Callsign << "linked peers>" << std::endl; // lock CClients *clients = GetClients(); // iterate on clients for ( int i = 0; i < clients->GetSize(); i++ ) { - clients->GetClient(i)->WriteXml(xmlFile); + if ( clients->GetClient(i)->IsPeer() ) + { + clients->GetClient(i)->WriteXml(xmlFile); + } + } + // unlock + ReleaseClients(); + xmlFile << "" << std::endl; + + // linked nodes + xmlFile << "<" << m_Callsign << "linked nodes>" << std::endl; + // lock + clients = GetClients(); + // iterate on clients + for ( int i = 0; i < clients->GetSize(); i++ ) + { + if ( clients->GetClient(i)->IsNode() ) + { + clients->GetClient(i)->WriteXml(xmlFile); + } } // unlock ReleaseClients(); diff --git a/src/cudpsocket.cpp b/src/cudpsocket.cpp index c6404c9..5caa074 100644 --- a/src/cudpsocket.cpp +++ b/src/cudpsocket.cpp @@ -151,3 +151,23 @@ int CUdpSocket::Send(const char *Buffer, const CIp &Ip) (void *)Buffer, ::strlen(Buffer), 0, (struct sockaddr *)temp.GetSockAddr(), sizeof(struct sockaddr_in)); } + +int CUdpSocket::Send(const CBuffer &Buffer, const CIp &Ip, uint16 destport) +{ + CIp temp(Ip); + temp.GetSockAddr()->sin_port = htons(destport); + return (int)::sendto(m_Socket, + (void *)Buffer.data(), Buffer.size(), + 0, (struct sockaddr *)temp.GetSockAddr(), sizeof(struct sockaddr_in)); +} + +int CUdpSocket::Send(const char *Buffer, const CIp &Ip, uint16 destport) +{ + CIp temp(Ip); + temp.GetSockAddr()->sin_port = htons(destport); + return (int)::sendto(m_Socket, + (void *)Buffer, ::strlen(Buffer), + 0, (struct sockaddr *)temp.GetSockAddr(), sizeof(struct sockaddr_in)); +} + + diff --git a/src/cudpsocket.h b/src/cudpsocket.h index 01d6ace..e91ed80 100644 --- a/src/cudpsocket.h +++ b/src/cudpsocket.h @@ -64,7 +64,9 @@ public: // write int Send(const CBuffer &, const CIp &); + int Send(const CBuffer &, const CIp &, uint16); int Send(const char *, const CIp &); + int Send(const char *, const CIp &, uint16); protected: // data diff --git a/src/cuser.cpp b/src/cuser.cpp index 3a0ff88..ce03b9f 100644 --- a/src/cuser.cpp +++ b/src/cuser.cpp @@ -35,10 +35,11 @@ CUser::CUser() m_LastHeardTime = std::time(NULL); } -CUser::CUser(const CCallsign &my, const CCallsign &rpt1) +CUser::CUser(const CCallsign &my, const CCallsign &rpt1, const CCallsign &xlx) { m_My = my; m_Rpt1 = rpt1; + m_Xlx = xlx; m_LastHeardTime = std::time(NULL); } @@ -46,6 +47,7 @@ CUser::CUser(const CUser &user) { m_My = user.m_My; m_Rpt1 = user.m_Rpt1; + m_Xlx = user.m_Xlx; m_LastHeardTime = user.m_LastHeardTime; } @@ -54,7 +56,7 @@ CUser::CUser(const CUser &user) bool CUser::operator ==(const CUser &user) const { - return ((user.m_My == m_My) && (user.m_Rpt1 == m_Rpt1)); + return ((user.m_My == m_My) && (user.m_Rpt1 == m_Rpt1) && (user.m_Xlx == m_Xlx)); } @@ -71,7 +73,8 @@ void CUser::WriteXml(std::ofstream &xmlFile) { xmlFile << "" << std::endl; xmlFile << "\t" << m_My << "" << std::endl; - xmlFile << "\t" << m_Rpt1 << "" << std::endl; + xmlFile << "\t" << m_Rpt1 << "" << std::endl; + xmlFile << "\t" << m_Xlx << "" << std::endl; char mbstr[100]; if (std::strftime(mbstr, sizeof(mbstr), "%A %c", std::localtime(&m_LastHeardTime))) diff --git a/src/cuser.h b/src/cuser.h index 04b6556..1e3d53a 100644 --- a/src/cuser.h +++ b/src/cuser.h @@ -35,7 +35,7 @@ class CUser public: // constructor CUser(); - CUser(const CCallsign &, const CCallsign &); + CUser(const CCallsign &, const CCallsign &, const CCallsign &); CUser(const CUser &); // destructor @@ -56,6 +56,7 @@ protected: // data CCallsign m_My; CCallsign m_Rpt1; + CCallsign m_Xlx; std::time_t m_LastHeardTime; }; diff --git a/src/cusers.cpp b/src/cusers.cpp index 164279b..1d32dc1 100644 --- a/src/cusers.cpp +++ b/src/cusers.cpp @@ -59,8 +59,13 @@ void CUsers::AddUser(const CUser &user) // operation void CUsers::Hearing(const CCallsign &my, const CCallsign &rpt1) -{ - CUser heard(my, rpt1); +{ + Hearing(my, rpt1, g_Reflector.GetCallsign()); +} + +void CUsers::Hearing(const CCallsign &my, const CCallsign &rpt1, const CCallsign &xlx) +{ + CUser heard(my, rpt1, xlx); // first check if we have this user listed yet bool found = false; diff --git a/src/cusers.h b/src/cusers.h index 90427df..7f12445 100644 --- a/src/cusers.h +++ b/src/cusers.h @@ -49,6 +49,7 @@ public: // operation void Hearing(const CCallsign &, const CCallsign &); + void Hearing(const CCallsign &, const CCallsign &, const CCallsign &); protected: // data diff --git a/src/cxlxclient.cpp b/src/cxlxclient.cpp new file mode 100644 index 0000000..97d6be5 --- /dev/null +++ b/src/cxlxclient.cpp @@ -0,0 +1,100 @@ +// +// cxlxclient.cpp +// xlxd +// +// Created by Jean-Luc Deltombe (LX3JL) on 28/01/2016. +// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved. +// +// ---------------------------------------------------------------------------- +// This file is part of xlxd. +// +// xlxd 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 3 of the License, or +// (at your option) any later version. +// +// xlxd 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 Foobar. If not, see . +// ---------------------------------------------------------------------------- + +#include +#include "main.h" +#include "cxlxclient.h" + + +//////////////////////////////////////////////////////////////////////////////////////// +// constructors + +CXlxClient::CXlxClient() +{ + ::memset(m_ReflectorModules, 0, sizeof(m_ReflectorModules)); +} + +CXlxClient::CXlxClient(const CCallsign &callsign, const CIp &ip, char *reflectorModules) +: CClient(callsign, ip) +{ + ::memset(m_ReflectorModules, 0, sizeof(m_ReflectorModules)); + if ( reflectorModules != NULL ) + { + while ( *reflectorModules != 0x00 ) + { + if ( (*reflectorModules >= 'A') && (*reflectorModules < ('A'+ NB_OF_MODULES)) ) + { + ::strncat(m_ReflectorModules, reflectorModules, 1); + } + reflectorModules++; + } + } + +} + +CXlxClient::CXlxClient(const CXlxClient &client) +: CClient(client) +{ + ::strcpy(m_ReflectorModules, client.m_ReflectorModules); +} + +//////////////////////////////////////////////////////////////////////////////////////// +// status + +bool CXlxClient::IsAlive(void) const +{ + return (m_LastKeepaliveTime.DurationSinceNow() < XLX_KEEPALIVE_TIMEOUT); +} + +//////////////////////////////////////////////////////////////////////////////////////// +// get + +bool CXlxClient::HasThisReflectorModule(char module) const +{ + return (::strchr(m_ReflectorModules, module) != NULL); +} + +//////////////////////////////////////////////////////////////////////////////////////// +// reporting + +void CXlxClient::WriteXml(std::ofstream &xmlFile) +{ + xmlFile << "" << std::endl; + xmlFile << "\t" << m_Callsign << "" << std::endl; + xmlFile << "\t" << m_Ip << "" << std::endl; + xmlFile << "\t" << m_ReflectorModules << "" << std::endl; + xmlFile << "\t" << GetProtocolName() << "" << std::endl; + char mbstr[100]; + if (std::strftime(mbstr, sizeof(mbstr), "%A %c", std::localtime(&m_ConnectTime))) + { + xmlFile << "\t" << mbstr << "" << std::endl; + } + if (std::strftime(mbstr, sizeof(mbstr), "%A %c", std::localtime(&m_LastHeardTime))) + { + xmlFile << "\t" << mbstr << "" << std::endl; + } + xmlFile << "" << std::endl; +} + + diff --git a/src/cxlxclient.h b/src/cxlxclient.h new file mode 100644 index 0000000..862bb74 --- /dev/null +++ b/src/cxlxclient.h @@ -0,0 +1,70 @@ +// +// cxlxclient.h +// xlxd +// +// Created by Jean-Luc Deltombe (LX3JL) on 28/01/2016. +// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved. +// +// ---------------------------------------------------------------------------- +// This file is part of xlxd. +// +// xlxd 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 3 of the License, or +// (at your option) any later version. +// +// xlxd 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 Foobar. If not, see . +// ---------------------------------------------------------------------------- + +#ifndef cxlxclient_h +#define cxlxclient_h + + +#include "cclient.h" + +//////////////////////////////////////////////////////////////////////////////////////// +// define + + +//////////////////////////////////////////////////////////////////////////////////////// +// class + +class CXlxClient : public CClient +{ +public: + // constructors + CXlxClient(); + CXlxClient(const CCallsign &, const CIp &, char * = NULL); + CXlxClient(const CXlxClient &); + + // destructor + virtual ~CXlxClient() {}; + + // identity + int GetProtocol(void) const { return PROTOCOL_XLX; } + const char *GetProtocolName(void) const { return "XLX"; } + bool IsPeer(void) const { return true; } + + // status + bool IsAlive(void) const; + + // get + bool HasThisReflectorModule(char) const; + + // reporting + void WriteXml(std::ofstream &); + +protected: + // linked to + char m_ReflectorModules[NB_OF_MODULES+1]; + +}; + +//////////////////////////////////////////////////////////////////////////////////////// +#endif /* cxlxclient_h */ diff --git a/src/cxlxprotocol.cpp b/src/cxlxprotocol.cpp new file mode 100644 index 0000000..442907d --- /dev/null +++ b/src/cxlxprotocol.cpp @@ -0,0 +1,542 @@ +// +// cxlxprotocol.cpp +// xlxd +// +// Created by Jean-Luc Deltombe (LX3JL) on 28/01/2016. +// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved. +// +// ---------------------------------------------------------------------------- +// This file is part of xlxd. +// +// xlxd 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 3 of the License, or +// (at your option) any later version. +// +// xlxd 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 Foobar. If not, see . +// ---------------------------------------------------------------------------- + +#include "main.h" +#include +#include "cxlxclient.h" +#include "cxlxprotocol.h" +#include "creflector.h" +#include "cgatekeeper.h" + + +//////////////////////////////////////////////////////////////////////////////////////// +// operation + +bool CXlxProtocol::Init(void) +{ + bool ok; + + // base class + ok = CProtocol::Init(); + + // update the reflector callsign + m_ReflectorCallsign.PatchCallsign(0, (const uint8 *)"XLX", 3); + + // create our socket + ok &= m_Socket.Open(XLX_PORT); + if ( !ok ) + { + std::cout << "Error opening socket on port UDP" << XLX_PORT << " on ip " << g_Reflector.GetListenIp() << std::endl; + } + + // update time + m_LastKeepaliveTime.Now(); + + // done + return ok; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// task + +void CXlxProtocol::Task(void) +{ + CBuffer Buffer; + CIp Ip; + CCallsign Callsign; + char Modules[NB_MODULES_MAX+1]; + CDvHeaderPacket *Header; + CDvFramePacket *Frame; + CDvLastFramePacket *LastFrame; + + // any incoming packet ? + if ( m_Socket.Receive(&Buffer, &Ip, 20) != -1 ) + { + // crack the packet + if ( (Frame = IsValidDvFramePacket(Buffer)) != NULL ) + { + //std::cout << "XLX (DExtra) DV frame" << std::endl; + + // handle it + OnDvFramePacketIn(Frame); + } + else if ( (Header = IsValidDvHeaderPacket(Buffer)) != NULL ) + { + //std::cout << "XLX (DExtra) DV header:" << std::endl << *Header << std::endl; + + // callsign muted? + if ( g_GateKeeper.MayTransmit(Header->GetMyCallsign(), Ip) ) + { + // handle it + OnDvHeaderPacketIn(Header, Ip); + } + else + { + delete Header; + } + } + else if ( (LastFrame = IsValidDvLastFramePacket(Buffer)) != NULL ) + { + //std::cout << "XLX (DExtra) DV last frame" << std::endl; + + // handle it + OnDvLastFramePacketIn(LastFrame); + } + else if ( IsValidConnectPacket(Buffer, &Callsign, Modules) || IsValidAckPacket(Buffer, &Callsign, Modules) ) + { + std::cout << "XLX connect/ack packet for modules " << Modules << " from " << Callsign << " at " << Ip << std::endl; + + // already connected ? + CClients *clients = g_Reflector.GetClients(); + if ( clients->FindClient(Callsign, Ip, PROTOCOL_XLX) == NULL ) + { + // callsign authorized? + if ( g_GateKeeper.MayLink(Callsign, Ip, PROTOCOL_XLX, Modules) ) + { + // acknowledge the request + EncodeConnectAckPacket(&Buffer, Modules); + m_Socket.Send(Buffer, Ip); + + // create the client + CXlxClient *client = new CXlxClient(Callsign, Ip, Modules); + + // and append + clients->AddClient(client); + } + else + { + // deny the request + EncodeConnectNackPacket(&Buffer); + m_Socket.Send(Buffer, Ip); + } + } + + // done + g_Reflector.ReleaseClients(); + + + } + else if ( IsValidDisconnectPacket(Buffer, &Callsign) ) + { + std::cout << "XLX disconnect packet from " << Callsign << " at " << Ip << std::endl; + + // find client & remove it + CClients *clients = g_Reflector.GetClients(); + CClient *client = clients->FindClient(Callsign, Ip, PROTOCOL_XLX); + if ( client != NULL ) + { + clients->RemoveClient(client); + } + g_Reflector.ReleaseClients(); + } + else if ( IsValidNackPacket(Buffer, &Callsign) ) + { + std::cout << "XLX nack packet from " << Callsign << " at " << Ip << std::endl; + } + else if ( IsValidKeepAlivePacket(Buffer, &Callsign) ) + { + //std::cout << "XLX keepalive packet from " << Callsign << " at " << Ip << std::endl; + + // find client & keep it alive + CClient *GetClient(const CCallsign &, const CIp &, char, int); + + CClient *client = g_Reflector.GetClients()->FindClient(Callsign, Ip, PROTOCOL_XLX); + if ( client != NULL ) + { + client->Alive(); + } + g_Reflector.ReleaseClients(); + } + else + { + std::cout << "XLX packet (" << Buffer.size() << ")" << std::endl; + } + } + + // handle end of streaming timeout + CheckStreamsTimeout(); + + // handle queue from reflector + HandleQueue(); + + // keep alive + if ( m_LastKeepaliveTime.DurationSinceNow() > XLX_KEEPALIVE_PERIOD ) + { + // handle keep alives + HandleKeepalives(); + + // handle remote peers connections + HandlePeerLinks(); + + // update time + m_LastKeepaliveTime.Now(); + } +} + +//////////////////////////////////////////////////////////////////////////////////////// +// queue helper + +void CXlxProtocol::HandleQueue(void) +{ + m_Queue.Lock(); + while ( !m_Queue.empty() ) + { + // get the packet + CPacket *packet = m_Queue.front(); + m_Queue.pop(); + + // check if origin of packet is local + // if not, do not stream it out as it will cause + // network loop between linked XLX peers + if ( packet->IsLocalOrigin() ) + { + // encode it + CBuffer buffer; + if ( EncodeDvPacket(*packet, &buffer) ) + { + // and push it to all our clients linked to the module and who are not streaming in + CClients *clients = g_Reflector.GetClients(); + int index = -1; + CClient *client = NULL; + while ( (client = clients->FindNextClient(PROTOCOL_XLX, &index)) != NULL ) + { + // is this client busy ? + // here check that origin module of the stream is listed in client xlx + // TODO: and check that client of origin is not another XLX to avoid loops + if ( !client->IsAMaster() && client->HasThisReflectorModule(packet->GetModuleId()) ) + { + // no, send the packet + m_Socket.Send(buffer, client->GetIp()); + + } + } + g_Reflector.ReleaseClients(); + } + } + + // done + delete packet; + } + m_Queue.Unlock(); +} + +//////////////////////////////////////////////////////////////////////////////////////// +// keepalive helpers + +void CXlxProtocol::HandleKeepalives(void) +{ + // DExtra protocol sends and monitors keepalives packets + // event if the client is currently streaming + // so, send keepalives to all + CBuffer keepalive; + EncodeKeepAlivePacket(&keepalive); + + // iterate on clients + CClients *clients = g_Reflector.GetClients(); + int index = -1; + CClient *client = NULL; + while ( (client = clients->FindNextClient(PROTOCOL_XLX, &index)) != NULL ) + { + // send keepalive + m_Socket.Send(keepalive, client->GetIp()); + + // client busy ? + if ( client->IsAMaster() ) + { + // yes, just tickle it + client->Alive(); + } + // otherwise check if still with us + else if ( !client->IsAlive() ) + { + // no, disconnect + CBuffer disconnect; + EncodeDisconnectPacket(&disconnect); + m_Socket.Send(disconnect, client->GetIp()); + + // remove it + std::cout << "XLX peer " << client->GetCallsign() << " keepalive timeout" << std::endl; + clients->RemoveClient(client); + } + + } + g_Reflector.ReleaseClients(); +} + +//////////////////////////////////////////////////////////////////////////////////////// +// Peers helpers + +void CXlxProtocol::HandlePeerLinks(void) +{ + CBuffer buffer; + + // get the list of peers + CPeerCallsignList *list = g_GateKeeper.GetPeerList(); + // todo: analyse possibility of double-lock hang-up + CClients *clients = g_Reflector.GetClients(); + + // check if all our connected client are still listed by gatekeeper + // if not, disconnect + int index = -1; + CClient *client = NULL; + while ( (client = clients->FindNextClient(PROTOCOL_XLX, &index)) != NULL ) + { + if ( list->FindListItem(client->GetCallsign()) == NULL ) + { + // send disconnect packet + EncodeDisconnectPacket(&buffer); + m_Socket.Send(buffer, client->GetIp(), XLX_PORT); + std::cout << "Sending disconnect packet to XLX peer " << client->GetCallsign() << std::endl; + // remove client + clients->RemoveClient(client); + } + } + + // check if all ours peers listed by gatekeeper are connected + // if not, connect or reconnect + for ( int i = 0; i < list->size(); i++ ) + { + CCallsignListItem *item = &((list->data())[i]); + if ( clients->FindClient(item->GetCallsign(), item->GetIp(), PROTOCOL_XLX) == NULL ) + { + // send connect packet to re-initiate peer link + EncodeConnectPacket(&buffer, item->GetModules()); + m_Socket.Send(buffer, item->GetIp(), XLX_PORT); + std::cout << "Sending connect packet to XLX peer " << item->GetCallsign() << " @ " << item->GetIp() << " for modules " << item->GetModules() << std::endl; + } + } + + // done + g_Reflector.ReleaseClients(); + g_GateKeeper.ReleasePeerList(); +} + + +//////////////////////////////////////////////////////////////////////////////////////// +// streams helpers + +bool CXlxProtocol::OnDvHeaderPacketIn(CDvHeaderPacket *Header, const CIp &Ip) +{ + bool newstream = false; + CCallsign peer; + + // todo: verify Packet.GetModuleId() is in authorized list of XLX of origin + // todo: do the same for DVFrame and DVLAstFrame packets + + // tag packet as remote peer origin + Header->SetRemotePeerOrigin(); + + // find the stream + CPacketStream *stream = GetStream(Header->GetStreamId()); + if ( stream == NULL ) + { + // no stream open yet, open a new one + // find this client + CClient *client = g_Reflector.GetClients()->FindClient(Ip, PROTOCOL_XLX); + if ( client != NULL ) + { + // and try to open the stream + if ( (stream = g_Reflector.OpenStream(Header, client)) != NULL ) + { + // keep the handle + m_Streams.push_back(stream); + newstream = true; + } + // get origin + peer = client->GetCallsign(); + } + // release + g_Reflector.ReleaseClients(); + } + else + { + // stream already open + // skip packet, but tickle the stream + stream->Tickle(); + } + + // update last heard + g_Reflector.GetUsers()->Hearing(Header->GetMyCallsign(), Header->GetRpt1Callsign(), peer); + g_Reflector.ReleaseUsers(); + + // done + return newstream; +} + +void CXlxProtocol::OnDvFramePacketIn(CDvFramePacket *DvFrame) +{ + // tag packet as remote peer origin + DvFrame->SetRemotePeerOrigin(); + + // anc call base class + CDextraProtocol::OnDvFramePacketIn(DvFrame); +} + +void CXlxProtocol::OnDvLastFramePacketIn(CDvLastFramePacket *DvFrame) +{ + // tag packet as remote peer origin + DvFrame->SetRemotePeerOrigin(); + + // anc call base class + CDextraProtocol::OnDvLastFramePacketIn(DvFrame); +} + + +//////////////////////////////////////////////////////////////////////////////////////// +// packet decoding helpers + +bool CXlxProtocol::IsValidKeepAlivePacket(const CBuffer &Buffer, CCallsign *callsign) +{ + bool valid = false; + if (Buffer.size() == 9) + { + callsign->SetCallsign(Buffer.data(), 8); + valid = callsign->IsValid(); + } + return valid; +} + + +bool CXlxProtocol::IsValidConnectPacket(const CBuffer &Buffer, CCallsign *callsign, char *modules) +{ + bool valid = false; + if ((Buffer.size() == 39) && (Buffer.data()[0] == 'L') && (Buffer.data()[38] == 0)) + { + callsign->SetCallsign((const uint8 *)&(Buffer.data()[1]), 8); + ::strcpy(modules, (const char *)&(Buffer.data()[12])); + valid = callsign->IsValid(); + for ( int i = 0; i < ::strlen(modules); i++ ) + { + valid &= IsLetter(modules[i]); + } + } + return valid; +} + +bool CXlxProtocol::IsValidDisconnectPacket(const CBuffer &Buffer, CCallsign *callsign) +{ + bool valid = false; + if ((Buffer.size() == 10) && (Buffer.data()[0] == 'U') && (Buffer.data()[9] == 0)) + { + callsign->SetCallsign((const uint8 *)&(Buffer.data()[1]), 8); + valid = callsign->IsValid(); + } + return valid; +} + +bool CXlxProtocol::IsValidAckPacket(const CBuffer &Buffer, CCallsign *callsign, char *modules) +{ + bool valid = false; + if ((Buffer.size() == 39) && (Buffer.data()[0] == 'A') && (Buffer.data()[38] == 0)) + { + callsign->SetCallsign((const uint8 *)&(Buffer.data()[1]), 8); + ::strcpy(modules, (const char *)&(Buffer.data()[12])); + valid = callsign->IsValid(); + for ( int i = 0; i < ::strlen(modules); i++ ) + { + valid &= IsLetter(modules[i]); + } + } + return valid; +} + +bool CXlxProtocol::IsValidNackPacket(const CBuffer &Buffer, CCallsign *callsign) +{ + bool valid = false; + if ((Buffer.size() == 10) && (Buffer.data()[0] == 'N') && (Buffer.data()[9] == 0)) + { + callsign->SetCallsign((const uint8 *)&(Buffer.data()[1]), 8); + valid = callsign->IsValid(); + } + return valid; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// packet encoding helpers + +void CXlxProtocol::EncodeKeepAlivePacket(CBuffer *Buffer) +{ + Buffer->Set(GetReflectorCallsign()); +} + +void CXlxProtocol::EncodeConnectPacket(CBuffer *Buffer, const char *Modules) +{ + uint8 tag[] = { 'L' }; + + // tag + Buffer->Set(tag, sizeof(tag)); + // our callsign + Buffer->resize(Buffer->size()+8); + g_Reflector.GetCallsign().GetCallsign(Buffer->data()+1); + // our version + Buffer->Append((uint8)VERSION_MAJOR); + Buffer->Append((uint8)VERSION_MINOR); + Buffer->Append((uint8)VERSION_REVISION); + // the modules we share + Buffer->Append(Modules); + Buffer->resize(39); +} + +void CXlxProtocol::EncodeDisconnectPacket(CBuffer *Buffer) +{ + uint8 tag[] = { 'U' }; + + // tag + Buffer->Set(tag, sizeof(tag)); + // our callsign + Buffer->resize(Buffer->size()+8); + g_Reflector.GetCallsign().GetCallsign(Buffer->data()+1); + Buffer->Append((uint8)0); +} + +void CXlxProtocol::EncodeConnectAckPacket(CBuffer *Buffer, const char *Modules) +{ + uint8 tag[] = { 'A' }; + + // tag + Buffer->Set(tag, sizeof(tag)); + // our callsign + Buffer->resize(Buffer->size()+8); + g_Reflector.GetCallsign().GetCallsign(Buffer->data()+1); + // our version + Buffer->Append((uint8)VERSION_MAJOR); + Buffer->Append((uint8)VERSION_MINOR); + Buffer->Append((uint8)VERSION_REVISION); + // the modules we share + Buffer->Append(Modules); + Buffer->resize(39); +} + +void CXlxProtocol::EncodeConnectNackPacket(CBuffer *Buffer) +{ + uint8 tag[] = { 'N' }; + + // tag + Buffer->Set(tag, sizeof(tag)); + // our callsign + Buffer->resize(Buffer->size()+8); + g_Reflector.GetCallsign().GetCallsign(Buffer->data()+1); + Buffer->Append((uint8)0); +} + diff --git a/src/cxlxprotocol.h b/src/cxlxprotocol.h new file mode 100644 index 0000000..d61d877 --- /dev/null +++ b/src/cxlxprotocol.h @@ -0,0 +1,86 @@ +// +// cxlxprotocol.h +// xlxd +// +// Created by Jean-Luc Deltombe (LX3JL) on 28/01/2016. +// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved. +// +// ---------------------------------------------------------------------------- +// This file is part of xlxd. +// +// xlxd 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 3 of the License, or +// (at your option) any later version. +// +// xlxd 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 Foobar. If not, see . +// ---------------------------------------------------------------------------- + +#ifndef cxlxprotocol_h +#define cxlxprotocol_h + + +#include "ctimepoint.h" +#include "cdextraprotocol.h" + +//////////////////////////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////////////////////////// +// class + +class CXlxProtocol : public CDextraProtocol +{ +public: + // constructor + CXlxProtocol() {}; + + // destructor + virtual ~CXlxProtocol() {}; + + // initialization + bool Init(void); + + // task + void Task(void); + +protected: + // queue helper + void HandleQueue(void); + + // keepalive helper + void HandlePeerLinks(void); + void HandleKeepalives(void); + + // stream helpers + bool OnDvHeaderPacketIn(CDvHeaderPacket *, const CIp &); + void OnDvFramePacketIn(CDvFramePacket *); + void OnDvLastFramePacketIn(CDvLastFramePacket *); + + // packet decoding helpers + bool IsValidKeepAlivePacket(const CBuffer &, CCallsign *); + bool IsValidConnectPacket(const CBuffer &, CCallsign *, char *); + bool IsValidDisconnectPacket(const CBuffer &, CCallsign *); + bool IsValidAckPacket(const CBuffer &, CCallsign *, char *); + bool IsValidNackPacket(const CBuffer &, CCallsign *); + + // packet encoding helpers + void EncodeKeepAlivePacket(CBuffer *); + void EncodeConnectPacket(CBuffer *, const char *); + void EncodeDisconnectPacket(CBuffer *); + void EncodeConnectAckPacket(CBuffer *, const char *); + void EncodeConnectNackPacket(CBuffer *); + +protected: + // time + CTimePoint m_LastKeepaliveTime; +}; + +//////////////////////////////////////////////////////////////////////////////////////// +#endif /* cxlxprotocol_h */ diff --git a/src/license.txt b/src/license.txt new file mode 100644 index 0000000..3d90694 --- /dev/null +++ b/src/license.txt @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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 3 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, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. \ No newline at end of file diff --git a/src/main.h b/src/main.h index 702f276..1f8f32d 100644 --- a/src/main.h +++ b/src/main.h @@ -47,8 +47,8 @@ // version ----------------------------------------------------- #define VERSION_MAJOR 1 -#define VERSION_MINOR 1 -#define VERSION_REVISION 3 +#define VERSION_MINOR 2 +#define VERSION_REVISION 4 // global ------------------------------------------------------ @@ -61,12 +61,14 @@ // protocols --------------------------------------------------- -#define NB_OF_PROTOCOLS 3 +#define NB_OF_PROTOCOLS 4 +#define PROTOCOL_ANY -1 #define PROTOCOL_NONE 0 #define PROTOCOL_DEXTRA 1 #define PROTOCOL_DPLUS 2 #define PROTOCOL_DCS 3 +#define PROTOCOL_XLX 4 // DExtra #define DEXTRA_PORT 30001 // UDP port @@ -83,6 +85,11 @@ #define DCS_KEEPALIVE_PERIOD 1 // in seconds #define DCS_KEEPALIVE_TIMEOUT (DCS_KEEPALIVE_PERIOD*30) // in seconds +// XLX +#define XLX_PORT 10002 // UDP port +#define XLX_KEEPALIVE_PERIOD 3 // in seconds +#define XLX_KEEPALIVE_TIMEOUT (XLX_KEEPALIVE_PERIOD*10) // in seconds + // xml & json reporting ----------------------------------------- #define LASTHEARD_USERS_MAX_SIZE 100 @@ -95,7 +102,11 @@ #define XML_PATH "/var/log/xlxd.xml" #define WHITELIST_PATH "/xlxd/xlxd.whitelist" #define BLACKLIST_PATH "/xlxd/xlxd.blacklist" +#define INTERLINKLIST_PATH "/xlxd/xlxd.interlink" +// system constants --------------------------------------------- + +#define NB_MODULES_MAX 26 //////////////////////////////////////////////////////////////////////////////////////// // typedefs diff --git a/src/makefile b/src/makefile index e9692ac..d2baee0 100644 --- a/src/makefile +++ b/src/makefile @@ -7,17 +7,21 @@ EXECUTABLE=xlxd all: $(SOURCES) $(EXECUTABLE) -$(EXECUTABLE): $(OBJECTS) +$(EXECUTABLE): $(OBJECTS) $(CC) $(LDFLAGS) $(OBJECTS) -o $@ .cpp.o: $(CC) $(CFLAGS) $< -o $@ -clean: - rm *.o - -install: - mkdir -p /xlxd - cp ./xlxd /xlxd/ - cp ../config/xlxd.blacklist /xlxd/ - cp ../config/xlxd.whitelist /xlxd/ +clean: + rm *.o + +install: + mkdir -p /xlxd + mv /xlxd/xlxd.blacklist /xlxd/xlxd.blacklist.bak + mv /xlxd/xlxd.whitelist /xlxd/xlxd.whitelist.bak + mv /xlxd/xlxd.interlink /xlxd/xlxd.interlink.bak + cp ./xlxd /xlxd/ + cp ../config/xlxd.blacklist /xlxd/ + cp ../config/xlxd.whitelist /xlxd/ + cp ../config/xlxd.interlink /xlxd/
@@ -36,7 +10,7 @@ Callsign Suffix DPRSViaVia / Peer Last heard
'; + '; if (file_exists("./img/flags/".$Reflector->GetFlag($Reflector->Stations[$i]->GetCallSign()).".png")) { echo ''; @@ -61,7 +35,11 @@ for ($i=0;$i<$Reflector->StationCount();$i++) { '.$Reflector->Stations[$i]->GetCallsignOnly().' '.$Reflector->Stations[$i]->GetSuffix().' '.$Reflector->Stations[$i]->GetVia().''.$Reflector->Stations[$i]->GetVia(); + if ($Reflector->Stations[$i]->GetPeer() != 'XLX'.$ServiceName) { + echo ' / '.$Reflector->Stations[$i]->GetPeer(); + } + echo ' '.date("d.m.Y H:i", $Reflector->Stations[$i]->GetLastHeardTime()).'