summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLars Heer <l.heer@gmx.de>2013-09-18 05:50:03 +0200
committerLars Heer <l.heer@gmx.de>2013-09-18 05:50:03 +0200
commitccf6e0f9c6b0481ed13e0f4794e3fbead750f385 (patch)
treeed86efb54f7ee41edfba5c89ca519b5fd10aa0d5
downloadvdr-plugin-mcli-ccf6e0f9c6b0481ed13e0f4794e3fbead750f385.tar.gz
vdr-plugin-mcli-ccf6e0f9c6b0481ed13e0f4794e3fbead750f385.tar.bz2
added vdr-plugin-mcli-0.0.1+svn20120927
-rw-r--r--COPYING340
-rw-r--r--HISTORY10
-rw-r--r--Makefile168
-rw-r--r--README60
-rw-r--r--cam_menu.c627
-rw-r--r--cam_menu.h56
-rw-r--r--def.h.defs73
-rw-r--r--defs2.h366
-rw-r--r--device.c962
-rw-r--r--device.h165
-rw-r--r--filter.c463
-rw-r--r--filter.h56
-rw-r--r--mcast/.svn/entries40
-rw-r--r--mcast/client/.indent.pro1
-rw-r--r--mcast/client/.svn/entries1357
-rw-r--r--mcast/client/.svn/prop-base/api_shm_test.c.svn-base5
-rw-r--r--mcast/client/.svn/prop-base/api_sock_test.c.svn-base5
-rw-r--r--mcast/client/.svn/prop-base/ciparser.c.svn-base5
-rw-r--r--mcast/client/.svn/prop-base/inet_aton.c.svn-base5
-rw-r--r--mcast/client/.svn/prop-base/inet_ntop.c.svn-base5
-rw-r--r--mcast/client/.svn/prop-base/inet_pton.c.svn-base5
-rw-r--r--mcast/client/.svn/prop-base/interfaces.c.svn-base5
-rw-r--r--mcast/client/.svn/prop-base/mcast.c.svn-base5
-rw-r--r--mcast/client/.svn/prop-base/mld_client.c.svn-base5
-rw-r--r--mcast/client/.svn/prop-base/mld_common.c.svn-base5
-rw-r--r--mcast/client/.svn/prop-base/recv_ccpp.c.svn-base5
-rw-r--r--mcast/client/.svn/prop-base/tools.c.svn-base5
-rw-r--r--mcast/client/.svn/prop-base/win32.svn-base5
-rw-r--r--mcast/client/.svn/text-base/.indent.pro.svn-base1
-rw-r--r--mcast/client/.svn/text-base/Makefile.svn-base210
-rw-r--r--mcast/client/.svn/text-base/api_server.c.svn-base397
-rw-r--r--mcast/client/.svn/text-base/api_server.h.svn-base67
-rw-r--r--mcast/client/.svn/text-base/api_shm_test.c.svn-base1
-rw-r--r--mcast/client/.svn/text-base/api_sock_test.c.svn-base1
-rw-r--r--mcast/client/.svn/text-base/api_test.c.svn-base127
-rw-r--r--mcast/client/.svn/text-base/ci_handler.c.svn-base321
-rw-r--r--mcast/client/.svn/text-base/ci_handler.h.svn-base30
-rw-r--r--mcast/client/.svn/text-base/ciparser.c.svn-base1
-rw-r--r--mcast/client/.svn/text-base/dummy_client.c.svn-base101
-rw-r--r--mcast/client/.svn/text-base/dummy_client.h.svn-base10
-rw-r--r--mcast/client/.svn/text-base/dvblo_handler.c.svn-base716
-rw-r--r--mcast/client/.svn/text-base/dvblo_handler.h.svn-base40
-rw-r--r--mcast/client/.svn/text-base/headers.h.svn-base32
-rw-r--r--mcast/client/.svn/text-base/inet_aton.c.svn-base1
-rw-r--r--mcast/client/.svn/text-base/inet_ntop.c.svn-base1
-rw-r--r--mcast/client/.svn/text-base/inet_pton.c.svn-base1
-rw-r--r--mcast/client/.svn/text-base/input.c.svn-base145
-rw-r--r--mcast/client/.svn/text-base/interfaces.c.svn-base1
-rw-r--r--mcast/client/.svn/text-base/main.c.svn-base83
-rw-r--r--mcast/client/.svn/text-base/mcast.c.svn-base1
-rw-r--r--mcast/client/.svn/text-base/mld_client.c.svn-base1
-rw-r--r--mcast/client/.svn/text-base/mld_common.c.svn-base1
-rw-r--r--mcast/client/.svn/text-base/mld_reporter.c.svn-base225
-rw-r--r--mcast/client/.svn/text-base/mld_reporter.h.svn-base11
-rw-r--r--mcast/client/.svn/text-base/mmi_handler.c.svn-base336
-rw-r--r--mcast/client/.svn/text-base/mmi_handler.h.svn-base46
-rw-r--r--mcast/client/.svn/text-base/recv_ccpp.c.svn-base1
-rw-r--r--mcast/client/.svn/text-base/recv_tv.c.svn-base905
-rw-r--r--mcast/client/.svn/text-base/recv_tv.h.svn-base96
-rw-r--r--mcast/client/.svn/text-base/satlists.c.svn-base133
-rw-r--r--mcast/client/.svn/text-base/sock_test.c.svn-base93
-rw-r--r--mcast/client/.svn/text-base/tca_handler.c.svn-base84
-rw-r--r--mcast/client/.svn/text-base/tca_handler.h.svn-base18
-rw-r--r--mcast/client/.svn/text-base/tools.c.svn-base1
-rw-r--r--mcast/client/.svn/text-base/tra_handler.c.svn-base56
-rw-r--r--mcast/client/.svn/text-base/tra_handler.h.svn-base10
-rw-r--r--mcast/client/.svn/text-base/win32.svn-base1
-rw-r--r--mcast/client/Makefile210
-rw-r--r--mcast/client/api_server.c397
-rw-r--r--mcast/client/api_server.h67
l---------mcast/client/api_shm_test.c1
l---------mcast/client/api_sock_test.c1
-rw-r--r--mcast/client/api_test.c127
-rw-r--r--mcast/client/ci_handler.c321
-rw-r--r--mcast/client/ci_handler.h30
l---------mcast/client/ciparser.c1
-rw-r--r--mcast/client/dummy_client.c101
-rw-r--r--mcast/client/dummy_client.h10
-rw-r--r--mcast/client/dvblo_handler.c716
-rw-r--r--mcast/client/dvblo_handler.h40
-rw-r--r--mcast/client/headers.h32
l---------mcast/client/inet_aton.c1
l---------mcast/client/inet_ntop.c1
l---------mcast/client/inet_pton.c1
-rw-r--r--mcast/client/input.c145
l---------mcast/client/interfaces.c1
-rw-r--r--mcast/client/main.c83
l---------mcast/client/mcast.c1
-rw-r--r--mcast/client/mingw/.svn/entries96
-rw-r--r--mcast/client/mingw/.svn/text-base/Makefile.svn-base55
-rw-r--r--mcast/client/mingw/.svn/text-base/build.cmd.svn-base2
-rw-r--r--mcast/client/mingw/Makefile55
-rw-r--r--mcast/client/mingw/build.cmd2
l---------mcast/client/mld_client.c1
l---------mcast/client/mld_common.c1
-rw-r--r--mcast/client/mld_reporter.c225
-rw-r--r--mcast/client/mld_reporter.h11
-rw-r--r--mcast/client/mmi_handler.c336
-rw-r--r--mcast/client/mmi_handler.h46
l---------mcast/client/recv_ccpp.c1
-rw-r--r--mcast/client/recv_tv.c905
-rw-r--r--mcast/client/recv_tv.h96
-rw-r--r--mcast/client/satlists.c133
-rw-r--r--mcast/client/sock_test.c93
-rw-r--r--mcast/client/tca_handler.c84
-rw-r--r--mcast/client/tca_handler.h18
l---------mcast/client/tools.c1
-rw-r--r--mcast/client/tra_handler.c56
-rw-r--r--mcast/client/tra_handler.h10
l---------mcast/client/win321
-rw-r--r--mcast/common/.indent.pro1
-rw-r--r--mcast/common/.svn/entries847
-rw-r--r--mcast/common/.svn/text-base/.indent.pro.svn-base1
-rw-r--r--mcast/common/.svn/text-base/ciparser.c.svn-base702
-rw-r--r--mcast/common/.svn/text-base/ciparser.h.svn-base140
-rw-r--r--mcast/common/.svn/text-base/crc32.c.svn-base88
-rw-r--r--mcast/common/.svn/text-base/crc32.h.svn-base35
-rw-r--r--mcast/common/.svn/text-base/defs.h.svn-base389
-rw-r--r--mcast/common/.svn/text-base/dvb_ca_wrapper.h.svn-base18
-rw-r--r--mcast/common/.svn/text-base/input.h.svn-base38
-rw-r--r--mcast/common/.svn/text-base/interfaces.c.svn-base347
-rw-r--r--mcast/common/.svn/text-base/interfaces.h.svn-base52
-rw-r--r--mcast/common/.svn/text-base/list.h.svn-base238
-rw-r--r--mcast/common/.svn/text-base/mcast.c.svn-base674
-rw-r--r--mcast/common/.svn/text-base/mcast.h.svn-base64
-rw-r--r--mcast/common/.svn/text-base/mld.h.svn-base339
-rw-r--r--mcast/common/.svn/text-base/mld_client.c.svn-base244
-rw-r--r--mcast/common/.svn/text-base/mld_common.c.svn-base243
-rw-r--r--mcast/common/.svn/text-base/recv_ccpp.c.svn-base1333
-rw-r--r--mcast/common/.svn/text-base/recv_ccpp.h.svn-base129
-rw-r--r--mcast/common/.svn/text-base/satlists.h.svn-base92
-rw-r--r--mcast/common/.svn/text-base/siparser.c.svn-base1049
-rw-r--r--mcast/common/.svn/text-base/siparser.h.svn-base369
-rw-r--r--mcast/common/.svn/text-base/tools.c.svn-base777
-rw-r--r--mcast/common/.svn/text-base/tools.h.svn-base108
-rw-r--r--mcast/common/.svn/text-base/version.h.svn-base18
-rw-r--r--mcast/common/ciparser.c702
-rw-r--r--mcast/common/ciparser.h140
-rw-r--r--mcast/common/crc32.c88
-rw-r--r--mcast/common/crc32.h35
-rw-r--r--mcast/common/darwin/.svn/entries31
-rw-r--r--mcast/common/darwin/include/.svn/entries62
-rw-r--r--mcast/common/darwin/include/.svn/prop-base/linux.svn-base5
-rw-r--r--mcast/common/darwin/include/.svn/text-base/linux.svn-base1
l---------mcast/common/darwin/include/linux1
-rw-r--r--mcast/common/defs.h389
-rw-r--r--mcast/common/dvb_ca_wrapper.h18
-rw-r--r--mcast/common/input.h38
-rw-r--r--mcast/common/interfaces.c347
-rw-r--r--mcast/common/interfaces.h52
-rw-r--r--mcast/common/list.h238
-rw-r--r--mcast/common/mcast.c674
-rw-r--r--mcast/common/mcast.h64
-rw-r--r--mcast/common/mld.h339
-rw-r--r--mcast/common/mld_client.c244
-rw-r--r--mcast/common/mld_common.c243
-rw-r--r--mcast/common/recv_ccpp.c1333
-rw-r--r--mcast/common/recv_ccpp.h129
-rw-r--r--mcast/common/satlists.h92
-rw-r--r--mcast/common/siparser.c1049
-rw-r--r--mcast/common/siparser.h369
-rw-r--r--mcast/common/tools.c777
-rw-r--r--mcast/common/tools.h108
-rw-r--r--mcast/common/version.h18
-rw-r--r--mcast/dvbloop/.svn/entries266
-rw-r--r--mcast/dvbloop/.svn/text-base/dvblo.h.svn-base58
-rw-r--r--mcast/dvbloop/.svn/text-base/dvblo_adap.h.svn-base155
-rw-r--r--mcast/dvbloop/.svn/text-base/dvblo_adap_ca.h.svn-base43
-rw-r--r--mcast/dvbloop/.svn/text-base/dvblo_adap_fe.h.svn-base30
-rw-r--r--mcast/dvbloop/.svn/text-base/dvblo_char.h.svn-base33
-rw-r--r--mcast/dvbloop/.svn/text-base/dvblo_ioctl.h.svn-base203
-rw-r--r--mcast/dvbloop/.svn/text-base/dvblo_util.h.svn-base45
-rw-r--r--mcast/dvbloop/dvblo.h58
-rw-r--r--mcast/dvbloop/dvblo_adap.h155
-rw-r--r--mcast/dvbloop/dvblo_adap_ca.h43
-rw-r--r--mcast/dvbloop/dvblo_adap_fe.h30
-rw-r--r--mcast/dvbloop/dvblo_char.h33
-rw-r--r--mcast/dvbloop/dvblo_ioctl.h203
-rw-r--r--mcast/dvbloop/dvblo_util.h45
-rw-r--r--mcast/tool/.svn/entries232
-rw-r--r--mcast/tool/.svn/prop-base/mcast.c.svn-base5
-rw-r--r--mcast/tool/.svn/prop-base/tools.c.svn-base5
-rw-r--r--mcast/tool/.svn/text-base/Makefile.svn-base137
-rw-r--r--mcast/tool/.svn/text-base/mcast.c.svn-base1
-rw-r--r--mcast/tool/.svn/text-base/netcvdiag.c.svn-base433
-rw-r--r--mcast/tool/.svn/text-base/netcvlogview.c.svn-base206
-rw-r--r--mcast/tool/.svn/text-base/netcvupdate.c.svn-base773
-rw-r--r--mcast/tool/.svn/text-base/tools.c.svn-base1
-rw-r--r--mcast/tool/Makefile137
l---------mcast/tool/mcast.c1
-rw-r--r--mcast/tool/netcvdiag.c433
-rw-r--r--mcast/tool/netcvlogview.c206
-rw-r--r--mcast/tool/netcvupdate.c773
l---------mcast/tool/tools.c1
-rw-r--r--mcli-i18n.diff22
-rw-r--r--mcli.c1122
-rw-r--r--mcli.h180
-rw-r--r--mcli_service.h25
-rw-r--r--mcliheaders.h29
-rw-r--r--packetbuffer.c283
-rw-r--r--packetbuffer.h57
-rw-r--r--patches/.svn/entries232
-rw-r--r--patches/.svn/text-base/reelvdr-device-handling-patch.diff.svn-base158
-rw-r--r--patches/.svn/text-base/vdr-1.4.0-closefilter.patch.svn-base45
-rw-r--r--patches/.svn/text-base/vdr-1.6-device-consistent-destruct.patch.svn-base97
-rw-r--r--patches/.svn/text-base/vdr-1.6-section-read-abstraction.patch.svn-base38
-rw-r--r--patches/.svn/text-base/vdr-1.6.0-altmenuaction.patch.svn-base38
-rw-r--r--patches/.svn/text-base/vdr-1.6.0-intcamdevices.patch.svn-base78
-rw-r--r--patches/reelvdr-device-handling-patch.diff158
-rw-r--r--patches/vdr-1.4.0-closefilter.patch45
-rw-r--r--patches/vdr-1.6-device-consistent-destruct.patch97
-rw-r--r--patches/vdr-1.6-section-read-abstraction.patch38
-rw-r--r--patches/vdr-1.6.0-altmenuaction.patch38
-rw-r--r--patches/vdr-1.6.0-intcamdevices.patch78
-rw-r--r--po/.svn/entries96
-rw-r--r--po/.svn/text-base/de_DE.po.svn-base86
-rw-r--r--po/.svn/text-base/nl_NL.po.svn-base87
-rw-r--r--po/de_DE.po86
-rw-r--r--po/nl_NL.po87
-rw-r--r--wait4ncv.diff61
220 files changed, 37656 insertions, 0 deletions
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..f90922e
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.) 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
+this service 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 make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. 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.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+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
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the 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 a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE 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.
+
+ 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
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision 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, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This 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.
diff --git a/HISTORY b/HISTORY
new file mode 100644
index 0000000..c16981a
--- /dev/null
+++ b/HISTORY
@@ -0,0 +1,10 @@
+VDR Plugin 'mcli' Revision History
+----------------------------------
+
+2008-12-18: Version 0.0.1
+
+- Initial revision.
+
+2010-06-23:
+
+- Moved the mcli-library to LGPL-2.1-license. \ No newline at end of file
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..103e0c3
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,168 @@
+#
+# Makefile for a Video Disk Recorder plugin
+#
+
+# The official name of this plugin.
+# This name will be used in the '-P...' option of VDR to load the plugin.
+# By default the main source file also carries this name.
+# IMPORTANT: the presence of this macro is important for the Make.config
+# file. So it must be defined, even if it is not used here!
+#
+#MCLI_SHARED=1
+PLUGIN = mcli
+APPLE_DARWIN = $(shell gcc -dumpmachine | grep -q 'apple-darwin' && echo "1" || echo "0")
+
+### The version number of this plugin (taken from the main source file):
+
+VERSION = $(shell grep 'static const char \*VERSION *=' $(PLUGIN).c | awk '{ print $$6 }' | sed -e 's/[";]//g')
+
+### The C++ compiler and options:
+
+CXX ?= g++
+ifeq ($(APPLE_DARWIN), 1)
+CXXFLAGS ?= -fPIC -pg -O2 -Wall -Woverloaded-virtual -Wno-parentheses -fno-common -bundle -flat_namespace -undefined suppress
+else
+CXXFLAGS ?= -fPIC -pg -O2 -Wall -Woverloaded-virtual -Wno-parentheses
+endif
+
+### The directory environment:
+
+VDRDIR = ../../..
+LIBDIR = ../../lib
+TMPDIR = /tmp
+
+### Make sure that necessary options are included:
+
+-include $(VDRDIR)/Make.global
+
+### Allow user defined options to overwrite defaults:
+
+-include $(VDRDIR)/Make.config
+
+### The version number of VDR's plugin API (taken from VDR's "config.h"):
+
+APIVERSION = $(shell sed -ne '/define APIVERSION/s/^.*"\(.*\)".*$$/\1/p' $(VDRDIR)/config.h)
+
+### The name of the distribution archive:
+
+ARCHIVE = $(PLUGIN)-$(VERSION)
+PACKAGE = vdr-$(ARCHIVE)
+
+### Includes and Defines (add further entries here):
+
+ifdef RBMINI
+ XML_INC := -I/usr/arm-linux-gnueabi/include/libxml2
+ XML_LIB := -lxml2
+else
+ XML_INC := `xml2-config --cflags`
+ XML_LIB := `xml2-config --libs`
+endif
+
+
+ifdef MCLI_SHARED
+ LIBS = -lmcli -Lmcast/client $(XML_LIB)
+else
+ LIBS = mcast/client/libmcli.a $(XML_LIB)
+endif
+
+INCLUDES += -I$(VDRDIR)/include -I. $(XML_INC)
+
+
+ifeq ($(APPLE_DARWIN), 1)
+INCLUDES += -I/sw/include -Imcast/common/darwin/include/
+DEFINES += -DAPPLE
+ifdef MCLI_SHARED
+DEFINES += -Imcast/common/darwin/include/
+endif
+endif
+
+ifdef REELVDR
+ DEFINES += -DREELVDR
+endif
+
+DEFINES += -D_GNU_SOURCE -DPLUGIN_NAME_I18N='"$(PLUGIN)"'
+# -DDEVICE_ATTRIBUTES
+
+### The object files (add further files here):
+
+OBJS = $(PLUGIN).o cam_menu.o device.o filter.o packetbuffer.o
+
+### The main target:
+
+plug: libmcli.so libvdr-$(PLUGIN).so
+
+all: libmcli.so libvdr-$(PLUGIN).so i18n
+
+libmcli.so:
+ $(MAKE) -C mcast/client/
+
+
+### Implicit rules:
+
+%.o: %.c
+ $(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) $<
+
+### Dependencies:
+
+MAKEDEP = $(CXX) -MM -MG
+DEPFILE = .dependencies
+$(DEPFILE): Makefile
+ @$(MAKEDEP) $(DEFINES) $(INCLUDES) $(OBJS:%.o=%.c) > $@
+
+-include $(DEPFILE)
+
+### Internationalization (I18N):
+
+PODIR = po
+LOCALEDIR = $(VDRDIR)/locale
+I18Npo = $(wildcard $(PODIR)/*.po)
+I18Nmsgs = $(addprefix $(LOCALEDIR)/, $(addsuffix /LC_MESSAGES/vdr-$(PLUGIN).mo, $(notdir $(foreach file, $(I18Npo), $(basename $(file))))))
+I18Npot = $(PODIR)/$(PLUGIN).pot
+
+%.mo: %.po
+ msgfmt -c -o $@ $<
+
+$(I18Npot): $(wildcard *.c)
+ xgettext -C -cTRANSLATORS --no-wrap --no-location -k -ktr -ktrNOOP --msgid-bugs-address='<see README>' -o $@ $^
+
+%.po: $(I18Npot)
+ msgmerge -U --no-wrap --no-location --backup=none -q $@ $<
+ @touch $@
+
+$(I18Nmsgs): $(LOCALEDIR)/%/LC_MESSAGES/vdr-$(PLUGIN).mo: $(PODIR)/%.mo
+ @mkdir -p $(dir $@)
+ cp $< $@
+
+.PHONY: i18n
+i18n: $(I18Nmsgs) $(I18Npot)
+
+i18n-dist: $(I18Nmsgs)
+
+### Targets:
+
+libvdr-$(PLUGIN).so: $(OBJS)
+ifeq ($(APPLE_DARWIN), 1)
+ $(CXX) $(CXXFLAGS) $(OBJS) $(LIBS) -o $@
+ @cp $@ $(LIBDIR)/$@.$(APIVERSION)
+else
+ $(CXX) $(CXXFLAGS) -shared $(OBJS) $(LIBS) -o $@
+ @cp --remove-destination $@ $(LIBDIR)/$@.$(APIVERSION)
+endif
+
+install:
+ifdef MCLI_SHARED
+ install -m 755 -D mcast/client/libmcli.so /usr/lib
+endif
+ install -m 755 -D libvdr-$(PLUGIN).so $(PLUGINLIBDIR)/libvdr-$(PLUGIN).so.$(APIVERSION)
+
+
+dist: clean
+ @-rm -rf $(TMPDIR)/$(ARCHIVE)
+ @mkdir $(TMPDIR)/$(ARCHIVE)
+ @cp -a * $(TMPDIR)/$(ARCHIVE)
+ @tar czf $(PACKAGE).tgz -C $(TMPDIR) $(ARCHIVE)
+ @-rm -rf $(TMPDIR)/$(ARCHIVE)
+ @echo Distribution package created as $(PACKAGE).tgz
+
+clean:
+ @-rm -f $(OBJS) $(DEPFILE) *.so *.tgz core* *~ $(PODIR)/*.mo $(PODIR)/*.pot $(LIBDIR)/libvdr-$(PLUGIN).so.* mcast/client/*.o mcast/client/*.so mcast/client/*.a
diff --git a/README b/README
new file mode 100644
index 0000000..b9a3800
--- /dev/null
+++ b/README
@@ -0,0 +1,60 @@
+This is a "plugin" for the Video Disk Recorder (VDR) to access DVB-streams
+produced by the NetCeiver-hardware.
+
+Project's homepage:
+http://www.baycom.de/wiki/index.php/Products::netceiver
+
+Latest version available via SVN at:
+https://svn.baycom.de/repos/vdr-mcli-plugin/
+
+The vdr-plugin, mcli-library and associated tools&drivers
+except netcv2dvbip are
+Copyright (C) 2007-2010 by BayCom GmbH <info@baycom.de>
+
+netcv2dvbip is
+Copyright (C) 2010 by Christian Cier-Zniewski <c.cier@gmx.de>
+
+------------------------------------------------------------------
+
+The mcli-library (libmcli.so) is covered by the
+GNU LESSER GENERAL PUBLIC LICENSE (LGPL), version 2.1:
+
+This library is free software; you can redistribute it and/or modify it
+under the terms of the GNU Lesser General Public License version 2.1 as
+published by the Free Software Foundation.
+
+This library 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 Lesser General Public License
+for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this library; if not, write to the Free Software Foundation,
+Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+------------------------------------------------------------------
+
+The vdr-plugin and associated tools are covered by the
+GNU GENERAL PUBLIC LICENSE (GPL), version 2:
+
+This program is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License version 2 as published by
+the Free Software Foundation.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 51
+Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+
+To properly integrate the mcli plugin into your VDR please apply these two
+patches:
+
+vdr-1.6.0-altmenuaction.patch (allows CAM messages to be displayed)
+vdr-1.6.0-intcamdevices.patch (enables selection of encrypted channels
+ without local CI stack).
+ \ No newline at end of file
diff --git a/cam_menu.c b/cam_menu.c
new file mode 100644
index 0000000..8af1eef
--- /dev/null
+++ b/cam_menu.c
@@ -0,0 +1,627 @@
+/***************************************************************************
+ * Copyright (C) 2009; Author: Tobias Bratfisch *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ *
+ ***************************************************************************/
+
+
+#include "cam_menu.h"
+#include "filter.h"
+#include "device.h"
+
+#include <vdr/plugin.h>
+#include <string.h>
+
+#define TMP_PATH "/tmp"
+#define TMP_FILE TMP_PATH"/netceiver.conf"
+
+class cCamMtd : public cMenuEditIntItem {
+ friend class cNCUpdate;
+ public:
+ cCamMtd(const char *uuid, int slot, const char *info, nc_ca_caps_t flags) :
+ cMenuEditIntItem((const char *)cString::sprintf(" %s", tr("Multi-Transponder")), &m_flags, 1, 2, trVDR("no"), trVDR("yes")) {
+ m_oflags = m_flags = flags;
+ if(uuid) strcpy (m_uuid, uuid); else m_uuid[0]=0;
+ if(info) strcpy (m_info, info); else m_info[0]=0;
+ m_slot = slot;
+ Set();
+ }; // cCamMtd
+ virtual bool MtdModified() { return m_flags != m_oflags; };
+ virtual void MtdSaved() { m_oflags = m_flags; }
+ protected:
+ char m_uuid[UUID_SIZE];
+ int m_slot;
+ char m_info[MMI_TEXT_LENGTH];
+ int m_flags;
+ int m_oflags;
+
+}; // cCamMtd
+
+class cCamInfo : public cOsdItem {
+ public:
+ cCamInfo(const char *uuid, int slot, const char *info) {
+ SetText(cString::sprintf (" %s:\t%s", slot == 0 ? trVDR ("lower slot") : trVDR ("upper slot"),
+ info ? info[0] ? info : trVDR ("Error") : trVDR ("No CI-Module")));
+ if(uuid) strcpy (m_uuid, uuid); else m_uuid[0]=0;
+ if(info) strcpy (m_info, info); else m_info[0]=0;
+ m_hascam = (info!=NULL);
+ m_slot = slot;
+ }; // cCamInfo
+ int CamMenuOpen (char *iface) {
+ isyslog("Opening CAM Menu at NetCeiver %s Slot %d info %s\n", m_uuid, m_slot, m_info);
+ int mmi_session = 0;
+ if(m_slot != -1 && strlen(m_info)) {
+ mmi_session = mmi_open_menu_session (m_uuid, iface, 0, m_slot);
+ if (mmi_session > 0) {
+ sleep (1);
+ const char *c = "00000000000000\n";
+ mmi_send_menu_answer (mmi_session, (char *) c, strlen (c));
+ } else {
+ esyslog("Could not open mcli menu session for %s/%d(%s): %d", m_uuid, m_slot, m_info, mmi_session);
+ mmi_session = -1;
+ } // if
+ } // if
+ return mmi_session;
+ }; // CamMenuOpen
+ virtual void CamReset (char *iface) {
+ if(CanCamReset())
+ mmi_cam_reset(m_uuid, iface, 0, m_slot);
+ }; // CamMenuOpen
+ virtual bool CanCamReset() {
+ return (m_slot != -1) && m_hascam;
+ }; // CanCamReset
+ virtual bool MtdPossible() {
+ return MtdPossible(m_info);
+ }; // MtdPossible
+ static bool MtdPossible(const char *info) {
+ if(info && strlen(info))
+ if (strncmp(info, "Alpha", 5) == 0
+ || strncmp(info, "easy.TV", 7) == 0
+ || strncmp(info, "Power", 5) == 0
+ )
+ return true;
+ return false;
+ }; // MtdPossible
+ protected:
+ bool m_hascam;
+ char m_uuid[UUID_SIZE];
+ int m_slot;
+ char m_info[MMI_TEXT_LENGTH];
+}; // cCamInfo
+
+class cNCUpdate : public cThread {
+ public:
+ cNCUpdate(cCamMenu *menu, const char *iface) {
+ m_menu = menu;
+ m_iface = iface;
+ if(m_iface && !strlen(m_iface)) m_iface = NULL;
+ m_state=1;
+ Start();
+ }; // cNCUpdate
+ virtual bool Done() { return !m_state; };
+ virtual const char *GetStateStr() {
+ return m_statestr;
+ }; // GetStateStr
+ protected:
+ virtual void Action() {
+ char uuid[UUID_SIZE];
+ while(Running() && m_menu && m_state) {
+ switch(m_state) {
+ case 1: {
+ m_statestr=tr("Updating configuration...");
+ m_state = 0;
+ for(cOsdItem *i=m_menu->First(); i; i=m_menu->Next(i)) {
+ cCamMtd *m = dynamic_cast<cCamMtd *>(i);
+ if(m && m->MtdModified()) {
+ strcpy(uuid, m->m_uuid);
+ m_state = 2;
+ break;
+ } // if
+ } // for
+ if(!m_state) m_statestr=tr("Configuration is up to date...");
+ break;
+ } // case 1
+ case 2: {
+ m_statestr = cString::sprintf(tr("Getting configuration from Netceiver %s"), uuid);
+ cString c = cString::sprintf("rm -f %s; cd %s; netcvupdate -i %s%s%s -D", TMP_FILE, TMP_PATH, uuid, m_iface ? " -d " : "", m_iface ? m_iface : "");
+//isyslog("EXEC1 %s", (const char *)c);
+ if(SystemExec(c)) {
+ m_statestr = cString::sprintf(tr("Failed to get configuration from Netceiver %s"), uuid);
+ m_state = 0;
+ continue;
+ } // if
+ m_state = 3;
+ break;
+ } // case 2
+ case 3: {
+ m_statestr = cString::sprintf(tr("Changing configuration for Netceiver %s"), uuid);
+ xmlDocPtr doc = xmlReadFile(TMP_FILE, NULL, 0);
+ if(doc == NULL) {
+ m_statestr = cString::sprintf(tr("Failed to parse configuration from Netceiver %s"), uuid);
+ m_state = 0;
+ continue;
+ } // if
+ if(!PatchAllCamFlags(doc, uuid)) {
+ xmlFreeDoc(doc);
+ m_statestr = cString::sprintf(tr("Failed to set configuration for Netceiver %s"), uuid);
+ m_state = 0;
+ continue;
+ } // if
+ if(xmlSaveFormatFileEnc(TMP_FILE, doc, "UTF-8", 1)==-1) {
+ xmlFreeDoc(doc);
+ m_statestr = cString::sprintf(tr("Failed to save configuration for Netceiver %s"), uuid);
+ m_state = 0;
+ continue;
+ } // if
+ xmlFreeDoc(doc);
+ m_state=4;
+ break;
+ } // case 3
+ case 4: {
+ m_statestr = cString::sprintf(tr("Saving configuration for Netceiver %s"), uuid);
+ cString c = cString::sprintf("netcvupdate -i %s%s%s -U %s -K", uuid, m_iface ? " -d " : "", m_iface ? m_iface : "", TMP_FILE);
+//isyslog("EXEC2 %s", (const char *)c);
+ if(SystemExec(c)) {
+ m_statestr = cString::sprintf(tr("Failed to save configuration for Netceiver %s"), uuid);
+ m_state = 0;
+ continue;
+ } // if
+ m_state=1;
+ break;
+ } // case 4
+ } // switch
+ } // while
+ m_state = 0;
+ }; // Action
+ virtual bool PatchAllCamFlags(xmlDocPtr doc, const char *uuid) {
+ for(cOsdItem *i=m_menu->First(); i; i=m_menu->Next(i)) {
+ cCamMtd *m = dynamic_cast<cCamMtd *>(i);
+ if(m && !strcmp(m->m_uuid, uuid)) {
+ if(!PatchCamFlags(doc, uuid, itoa(m->m_slot), itoa(m->m_flags)))
+ return false;
+ m->MtdSaved();
+ } // if
+ } // for
+ return true;
+ }; // PatchAllCamFlags
+ virtual bool PatchCamFlags(xmlDocPtr doc, const char *uuid, const char *slot, const char *flags) {
+ bool uuid_match=false;
+ bool flags_set =false;
+ xmlNode *node = xmlDocGetRootElement(doc);
+ node = node ? node->children : NULL;
+ while(node && xmlStrcmp(node->name, (const xmlChar *)"Description"))
+ node=node->next;
+ node = node ? node->children : NULL;
+ while(node) {
+ if(node && !xmlStrcmp(node->name, (const xmlChar *)"component")) {
+ xmlNode *item = node->children;
+ while(item && xmlStrcmp(item->name, (const xmlChar *)"Description")) {
+ item = item->next;
+ } // while
+ xmlChar *about = item ? xmlGetProp(item, (const xmlChar *)"about") : NULL;
+ if(about) {
+ if (!xmlStrcmp(about, (const xmlChar *)"Platform")) {
+ xmlNode *sub = item->children;
+ while(sub) {
+ if(!xmlStrcmp(sub->name, (const xmlChar *)"UUID")) {
+ xmlChar *value=xmlNodeListGetString(doc, sub->children, 1);
+ if(value) {
+ uuid_match=!xmlStrcmp(value, (const xmlChar *)uuid);
+ xmlFree(value);
+ } // if
+ } // if
+ sub = sub->next;
+ } // while
+ } else if(!xmlStrcmp(about, (const xmlChar *)"CAM")) {
+ xmlNode *sub = item->children;
+ while(sub) {
+ if(!xmlStrcmp(sub->name, (const xmlChar *)"Slot")) {
+ xmlChar *value=xmlNodeListGetString(doc, sub->children, 1);
+ if(value) {
+ if (!xmlStrcmp(value, (const xmlChar *)slot)) {
+ xmlNode *tst = item->children;
+ while(tst) {
+ if(!xmlStrcmp(tst->name, (const xmlChar *)"Flags")) {
+ xmlReplaceNode(tst, xmlNewChild(item, xmlSearchNs(doc, tst, (const xmlChar *)"prf"), (const xmlChar *)"Flags", (const xmlChar *)flags));
+ xmlFreeNode(tst);
+ flags_set=true;
+ tst = NULL;
+ continue;
+ } // if
+ tst = tst->next;
+ } // while
+ } // if
+ xmlFree(value);
+ } // if
+ } // if
+ sub = sub->next;
+ } // while
+ } // if
+ xmlFree(about);
+ } // if
+ } // if
+ node = node->next;
+ } // while
+ return uuid_match && flags_set;
+ }; // PatchCamFlags
+ cCamMenu *m_menu;
+ const char *m_iface;
+ unsigned int m_state;
+ cString m_statestr;
+}; // cNCUpdate
+
+cCamMenu::cCamMenu (cmdline_t * cmd)
+#if APIVERSNUM < 10700
+: cOsdMenu (trVDR ("Common Interface"), 18)
+#else
+: cOsdMenu (trVDR ("Common Interface"), 23)
+#endif
+{
+ NCUpdate=NULL;
+ m_cmd = cmd;
+ inCamMenu = false;
+ inMMIBroadcastMenu = false;
+ inputRequested = eInputNone;
+ end = false;
+ currentSelected = -1;
+ pinCounter = 0;
+ alreadyReceived = false;
+ mmi_session = -1;
+ SetNeedsFastResponse (true);
+ CamFind ();
+}
+
+cCamMenu::cCamMenu (cmdline_t * cmd, mmi_info_t * mmi_info):cOsdMenu (trVDR ("Common Interface"), 18)
+{
+ NCUpdate=NULL;
+ m_cmd = cmd;
+ inCamMenu = false;
+ inMMIBroadcastMenu = false;
+ inputRequested = eInputNone;
+ end = false;
+ currentSelected = -1;
+ pinCounter = 0;
+ alreadyReceived = false;
+ mmi_session = -1;
+ SetNeedsFastResponse (true);
+ mmi_session = CamMenuOpen (mmi_info);
+}
+
+
+cCamMenu::~cCamMenu ()
+{
+ CamMenuClose (mmi_session);
+}
+
+void cCamMenu::OpenCamMenu ()
+{
+ bool timeout = true;
+ cCamInfo *item = dynamic_cast<cCamInfo *>(Get(currentSelected));
+ mmi_session = item ? item->CamMenuOpen (m_cmd->iface) : 0;
+ char buf2[MMI_TEXT_LENGTH * 2];
+ printf ("mmi_session: %d\n", mmi_session);
+ if (mmi_session > 0) {
+ Clear ();
+ Skins.Message(mtWarning, trVDR("Opening CAM menu..."));
+ inCamMenu = true;
+ time_t t = time (NULL);
+ while ((time (NULL) - t) < CAMMENU_TIMEOUT) {
+ memset(buf2, 0, sizeof(buf2));
+ // receive the CAM MENU
+ if (CamMenuReceive (mmi_session, buf, MMI_TEXT_LENGTH) > 0) {
+ cCharSetConv conv = cCharSetConv ("ISO-8859-1", "UTF-8");
+ conv.Convert (buf, buf2, MMI_TEXT_LENGTH * 2);
+ char *saveptr = NULL;
+ char *ret = strtok_r (buf2, "\n", &saveptr);
+ if (ret) {
+ Add (new cOsdItem (ret));
+ while (ret != NULL) {
+ ret = strtok_r (NULL, "\n", &saveptr);
+ if (ret)
+ Add (new cOsdItem (ret));
+ }
+ }
+ timeout = false;
+ break;
+ }
+ }
+ }
+ if (mmi_session && timeout) {
+ printf ("%s: Error\n", __PRETTY_FUNCTION__);
+ Clear ();
+ Add (new cOsdItem (trVDR ("Error")));
+ }
+ Display ();
+}
+
+void cCamMenu::Receive ()
+{
+ bool timeout = true;
+ if (mmi_session > 0) {
+ char buf2[MMI_TEXT_LENGTH * 2];
+ time_t t = time (NULL);
+ while ((time (NULL) - t) < CAMMENU_TIMEOUT) {
+ memset(buf2, 0, sizeof(buf2));
+ // receive the CAM MENU
+ if (alreadyReceived || CamMenuReceive (mmi_session, buf, MMI_TEXT_LENGTH) > 0) {
+ Clear ();
+ alreadyReceived = false;
+ printf ("MMI: \"%s\"\n", buf);
+ if (!strncmp (buf, "blind = 0", 9))
+ inputRequested = eInputNotBlind;
+ else if (!strncmp (buf, "blind = 1", 9))
+ inputRequested = eInputBlind;
+ cCharSetConv conv = cCharSetConv ("ISO-8859-1", "UTF-8");
+ conv.Convert (inputRequested ? buf + 28 : buf, buf2, MMI_TEXT_LENGTH * 2);
+ printf ("MMI-UTF8: \"%s\"\n", buf2);
+ if (!strcmp (buf, "end")) {
+ /** The Alphacrypt returns "end" when pressing "Back" in it's main menu */
+ end = true;
+ return;
+ }
+ char *saveptr = NULL;
+ char *ret = strtok_r (buf2, "\n", &saveptr);
+ if (ret) {
+ Add (new cOsdItem (ret));
+ while (ret != NULL) {
+ ret = strtok_r (NULL, "\n", &saveptr);
+ if (ret)
+ Add (new cOsdItem (ret));
+ }
+ }
+ timeout = false;
+ break;
+ }
+ }
+ }
+ if (timeout) {
+ printf ("%s: mmi_session: %i\n", __PRETTY_FUNCTION__, mmi_session);
+ Add (new cOsdItem (trVDR ("Error")));
+ }
+ Display ();
+}
+
+int cCamMenu::CamFind ()
+{
+ Clear ();
+ int n, cnt = 0, i;
+ netceiver_info_list_t *nc_list = nc_get_list ();
+ //printf ("Looking for netceivers out there....\n");
+ nc_lock_list ();
+ for (n = 0; n < nc_list->nci_num; n++) {
+ netceiver_info_t *nci = nc_list->nci + n;
+ //printf ("\nFound NetCeiver: %s \n", nci->uuid);
+ char buf[128];
+ Add (new cOsdItem ("Netceiver", osUnknown, false));
+ snprintf (buf, 128, " %s: %s", "ID", nci->uuid);
+ Add (new cOsdItem (buf, osUnknown, false));
+ Add (new cOsdItem ("", osUnknown, false));
+ printf (" CAMS [%d]: \n", nci->cam_num);
+ int nrAlphaCrypts = 0;
+ int nrOtherCams = 0;
+
+ for (i = nci->cam_num - 1; i >= 0 /*nci->cam_num */ ; i--) {
+ if((2==nci->cam[i].status)&&strlen(nci->cam[i].menu_string)) {
+ if (cCamInfo::MtdPossible(nci->cam[i].menu_string))
+ nrAlphaCrypts++;
+ else
+ nrOtherCams++;
+ } // if
+ } // for
+ bool mtdImpossible = nrAlphaCrypts > 0 && nrOtherCams > 0; // as in netcvmenu.c
+ for (i = nci->cam_num - 1; i >= 0 /*nci->cam_num */ ; i--) {
+ switch (nci->cam[i].status) {
+ case 2: {//DVBCA_CAMSTATE_READY:
+ cCamInfo *item = new cCamInfo(nci->uuid, nci->cam[i].slot, nci->cam[i].menu_string);
+ Add(item);
+ if(!mtdImpossible && item->MtdPossible())
+ Add(new cCamMtd(nci->uuid, nci->cam[i].slot, nci->cam[i].menu_string, nci->cam[i].flags));
+ break;
+ }
+ case 0: // no cam?
+ Add(new cCamInfo(nci->uuid, nci->cam[i].slot, NULL));
+ break;
+ default:
+ Add(new cCamInfo(nci->uuid, nci->cam[i].slot, nci->cam[i].menu_string));
+ }
+ Add (new cOsdItem ("", osUnknown, false));
+ cnt++;
+ }
+ if (mtdImpossible) {
+ Add(new cOsdItem(cString::sprintf(" %s", tr("Multi-Transponder-Decryption is"))));
+ Add(new cOsdItem(cString::sprintf(" %s", tr("impossible because of mixed CAMs"))));
+ Add (new cOsdItem ("", osUnknown, false));
+ } // if
+ }
+ nc_unlock_list ();
+ Display ();
+ return cnt;
+}
+
+int cCamMenu::CamMenuOpen (mmi_info_t * mmi_info)
+{
+ //printf ("Opening CAM Menu at NetCeiver %s Slot %d\n", mmi_info->uuid, mmi_info->slot);
+
+ char buf[MMI_TEXT_LENGTH * 2];
+
+ inMMIBroadcastMenu = true;
+ inCamMenu = true;
+ cCharSetConv conv = cCharSetConv ("ISO-8859-1", "UTF-8");
+ conv.Convert (mmi_info->mmi_text, buf, MMI_TEXT_LENGTH * 2);
+ //printf ("MMI-UTF8: \"%s\"\n", buf);
+ char *saveptr = NULL;
+ char *ret = strtok_r (buf, "\n", &saveptr);
+ if (ret) {
+ Add (new cOsdItem (ret));
+ while (ret != NULL) {
+ ret = strtok_r (NULL, "\n", &saveptr);
+ if (ret)
+ Add (new cOsdItem (ret));
+ }
+ }
+
+ int mmi_session = mmi_open_menu_session (mmi_info->uuid, m_cmd->iface, 0, mmi_info->slot);
+
+ //printf ("CamMenuOpen: mmi_session: %i\n", mmi_session);
+ return mmi_session;
+}
+
+int cCamMenu::CamMenuSend (int mmi_session, const char *c)
+{
+ return mmi_send_menu_answer (mmi_session, (char *) c, strlen (c));
+}
+
+int cCamMenu::CamMenuReceive (int mmi_session, char *buf, int bufsize)
+{
+ return mmi_get_menu_text (mmi_session, buf, bufsize, 50000);
+}
+
+void cCamMenu::CamMenuClose (int mmi_session)
+{
+ close (mmi_session);
+}
+
+int cCamMenu::CamPollText (mmi_info_t * text)
+{
+ return mmi_poll_for_menu_text (m_cam_mmi, text, 10);
+}
+
+eOSState cCamMenu::ProcessKey (eKeys Key)
+{
+ if(NCUpdate) {
+ if(NCUpdate->Done()) {
+ SetStatus("");
+ Skins.Message(mtWarning, NCUpdate->GetStateStr());
+ delete NCUpdate;
+ NCUpdate=NULL;
+ return osBack;
+ } else
+ SetStatus(NCUpdate->GetStateStr());
+ Display();
+ return osContinue;
+ } // if
+ eOSState ret = cOsdMenu::ProcessKey (Key);
+
+ currentSelected = Current ();
+
+ if (end) {
+ end = false;
+ inCamMenu = false;
+ if (inMMIBroadcastMenu)
+ return osEnd;
+ CamMenuClose (mmi_session);
+ CamFind ();
+ return osContinue;
+ }
+ bool MtdModified=false;
+ for(cOsdItem *i=First(); i; i=Next(i)){
+ cCamMtd *m = dynamic_cast<cCamMtd *>(i);
+ if(m&&m->MtdModified()) MtdModified=true;
+ } // for
+ cCamInfo *info = dynamic_cast<cCamInfo *>(Get(Current()));
+ SetHelp(MtdModified?tr("Save"):NULL, NULL, (info&&info->CanCamReset()) ? trVDR("Reset") : NULL, NULL);
+ switch (Key) {
+#if 0
+ case kUp:
+ case kDown:
+ {
+ unsigned int nrInCamList = currentSelected - ((int) currentSelected / 5) * 3 - 3; // minus the empty rows
+ if(strlen(cam_list[nrInCamList].info))
+ SetHelp(trVDR("Reset"), NULL, NULL, NULL);
+ else
+ SetHelp(NULL, NULL, NULL, NULL);
+ break;
+ }
+#endif
+ case kRed: { // modify mtd settings
+ NCUpdate = new cNCUpdate(this, m_cmd->iface);
+ SetHelp(NULL, NULL, NULL, NULL);
+ SetStatus(tr("Updating configuration..."));
+ Display();
+ return osContinue;
+ }
+ case kYellow: {
+ cCamInfo *item = dynamic_cast<cCamInfo *>(Get(currentSelected));
+ if(item) item->CamReset(m_cmd->iface);
+ break;
+ }
+ case kOk:
+ SetStatus ("");
+ pinCounter = 0; // reset pin
+ if (inCamMenu && inputRequested) {
+ inputRequested = eInputNone; // input was sent
+ //printf ("Sending pin: \"%s\"\n", pin);
+ CamMenuSend (mmi_session, pin);
+ Receive ();
+ } else if (inMMIBroadcastMenu) {
+ //printf ("Sending: \"%s\"\n", Get (Current())->Text());
+ CamMenuSend (mmi_session, Get (Current ())->Text ());
+ Receive ();
+ } else if (inCamMenu) {
+ //printf ("Sending: \"%s\"\n", Get (Current ())->Text ());
+ if (strcmp(Get ( Current ())->Text(), trVDR("Error"))) // never send Error...
+ CamMenuSend (mmi_session, Get (Current ())->Text ());
+ Receive ();
+ } else
+ OpenCamMenu ();
+ break;
+ case kBack:
+ pinCounter = 0; // reset pin
+ if (!inCamMenu)
+ return osBack;
+ inCamMenu = false;
+ SetStatus ("");
+ CamMenuClose (mmi_session);
+ CamFind ();
+ return osContinue;
+ case k0...k9:
+ if (inputRequested) {
+ pin[pinCounter++] = 48 + Key - k0;
+ pin[pinCounter] = '\0';
+ printf ("key: %c, pin: \"%s\"\n", 48 + Key - k0, pin);
+ char buf[16];
+ int i;
+ for (i = 0; i < pinCounter; i++)
+ (inputRequested == eInputBlind) ? buf[i] = '*' : buf[i] = pin[i];
+ buf[i] = '\0';
+ SetStatus (buf);
+ } else {
+ pinCounter = 0; // reset pin
+ SetStatus ("");
+ for (int i = 0; Get (i); i++) {
+ const char *txt = Get (i)->Text ();
+ if (txt[0] == 48 + Key - k0 && txt[1] == '.') {
+ CamMenuSend (mmi_session, txt);
+ Receive ();
+ }
+ }
+ }
+ break;
+ default:
+ int bla = 0;
+ if (mmi_session > 0) {
+ bla = CamMenuReceive (mmi_session, buf, MMI_TEXT_LENGTH);
+ if (bla > 0) {
+ alreadyReceived = true;
+ //printf ("bla: %i\n", bla);
+ Receive ();
+ }
+ }
+ break;
+ }
+ return ret;
+}
diff --git a/cam_menu.h b/cam_menu.h
new file mode 100644
index 0000000..3ee5f51
--- /dev/null
+++ b/cam_menu.h
@@ -0,0 +1,56 @@
+#ifndef CAM_MENU_H
+#define CAM_MENU_H
+
+#include <vdr/osdbase.h>
+#include "filter.h"
+#include "device.h"
+
+#define MAX_CAMS_IN_MENU 16
+#define CAMMENU_TIMEOUT 15
+
+typedef struct
+{
+ int port;
+ char iface[IFNAMSIZ];
+ char cmd_sock_path[_POSIX_PATH_MAX];
+ int tuner_type_limit[FE_DVBS2 + 1];
+ int mld_start;
+} cmdline_t;
+
+enum eInputRequest
+{ eInputNone, eInputBlind, eInputNotBlind };
+
+class cNCUpdate;
+
+class cCamMenu:public cOsdMenu
+{
+private:
+ int CamFind ();
+ int CamMenuOpen (mmi_info_t * mmi_info);
+ int CamMenuSend (int fd, const char *c);
+ int CamMenuReceive (int fd, char *buf, int bufsize);
+ void CamMenuClose (int fd);
+ int CamPollText (mmi_info_t * text);
+ cmdline_t *m_cmd;
+ UDPContext *m_cam_mmi;
+ int mmi_session;
+ bool inCamMenu;
+ bool inMMIBroadcastMenu;
+ bool end;
+ int currentSelected;
+ eInputRequest inputRequested;
+ char pin[32];
+ int pinCounter;
+ char buf[MMI_TEXT_LENGTH];
+ bool alreadyReceived;
+ cNCUpdate *NCUpdate;;
+public:
+ cCamMenu (cmdline_t * m_cmd);
+ cCamMenu (cmdline_t * m_cmd, mmi_info_t * mmi_info);
+ ~cCamMenu ();
+ eOSState ProcessKey (eKeys Key);
+ void OpenCamMenu ();
+ void Receive ();
+};
+
+#endif
diff --git a/def.h.defs b/def.h.defs
new file mode 100644
index 0000000..2e7b9b7
--- /dev/null
+++ b/def.h.defs
@@ -0,0 +1,73 @@
+#ifndef __DEFS_H__
+#ifdef WIN32
+ #ifdef __CYGWIN__
+ #else
+ #ifndef IP_ADAPTER_IPV6_ENABLED
+ #endif
+
+ #ifndef s6_addr16
+ #endif
+
+ #if ! defined _GNU_SOURCE && defined __cplusplus
+ #else
+ #endif
+
+ #ifdef LIBRARY
+ #else
+ #endif
+ #endif
+#else
+ #if defined __cplusplus
+ #else
+ #endif
+
+ #if ! (defined __uClinux__ || defined APPLE || defined MIPSEL)
+ #endif
+
+ #ifndef APPLE
+ #else
+ #ifndef s6_addr16
+ #endif
+ #endif
+
+ #ifdef APPLE
+ #endif
+
+ #if defined __uClinux__
+ #endif
+#endif // WIN32
+
+#ifndef __uClinux__
+ #if ! (defined WIN32 || defined APPLE)
+ #endif
+// #else
+// #endif
+#else
+#endif // __uClinux__
+
+#ifdef DMALLOC
+#endif
+
+#if ! defined GETTID && ! defined WIN32 && ! defined APPLE
+#else
+#endif
+
+#ifndef WIN32
+ #ifdef SYSLOG
+ #ifdef DEBUG
+ #else
+ #endif
+ #else
+ #endif // Syslog
+#else // WIN32
+ #ifdef DEBUG
+ #else
+ #endif //DEBUG
+#endif // WIN32
+
+ #ifndef MICROBLAZE
+ #endif
+ #ifdef MICROBLAZE
+ #else
+ #endif
+#endif //__DEFS_H__
diff --git a/defs2.h b/defs2.h
new file mode 100644
index 0000000..bab5cbf
--- /dev/null
+++ b/defs2.h
@@ -0,0 +1,366 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ */
+
+#ifndef __DEFS_H__
+#define __DEFS_H__
+
+#ifdef WIN32
+#ifdef __CYGWIN__
+#include <cygwin/version.h>
+#include <cygwin/in.h>
+#include <cygwin/socket.h>
+#else
+#define _CRT_SECURE_NO_WARNINGS
+#define _WIN32_WINNT 0x0502
+#include <winsock2.h>
+#include <WS2tcpip.h>
+#include <iphlpapi.h>
+
+#define _SOTYPE char*
+#define IFNAMSIZ 1024
+#define CA_TPDU_MAX 2048
+#define _POSIX_PATH_MAX MAX_PATH
+#define usleep(useconds) Sleep((useconds+500)/1000)
+#define sleep(seconds) Sleep((seconds)*1000)
+#define EAFNOSUPPORT WSAEAFNOSUPPORT
+#ifndef IP_ADAPTER_IPV6_ENABLED
+#define IP_ADAPTER_IPV6_ENABLED 0x0100
+#endif
+
+int inet_pton(int af, const char *src, void *dst);
+const char *inet_ntop(int af, const void *src, char *dst, size_t size);
+int inet_aton(const char *cp, struct in_addr *addr);
+int getopt(int nargc, char **nargv, char *ostr);
+extern int opterr, optind, optopt, optreset;
+extern char *optarg;
+
+typedef struct
+{
+ DWORD thread;
+ HANDLE threadH; /* Win32 thread handle - POSIX thread is invalid if threadH == 0 */
+} ptw32_thread_t;
+
+typedef unsigned int uint32_t;
+typedef uint32_t __u32;
+typedef uint32_t u_int32_t;
+typedef unsigned short uint16_t;
+typedef uint16_t __u16;
+typedef uint16_t u_int16_t;
+typedef unsigned char uint8_t;
+typedef uint8_t __u8;
+typedef uint8_t u_int8_t;
+#ifndef s6_addr16
+#define s6_addr16 s6_words
+#endif
+#if ! defined _GNU_SOURCE && defined __cplusplus
+#define CALLCONV extern "C"
+#else
+#define CALLCONV
+#endif
+#ifdef LIBRARY
+#define DLL_SYMBOL CALLCONV __declspec( dllexport )
+#else
+#define DLL_SYMBOL CALLCONV __declspec( dllimport )
+#endif
+
+#define pthread_exist(x) (x).p
+#define pthread_null(x) (x).p=NULL
+#define _SOTYPE char*
+#define INET6
+#define API_WIN
+#define LIBXML_STATIC
+#define PTW32_STATIC_LIB
+#define MULTI_THREAD_RECEIVER
+#endif
+#else
+#if defined __cplusplus
+#define CALLCONV extern "C"
+#else
+#define CALLCONV
+#endif
+#define DLL_SYMBOL CALLCONV
+#define pthread_exist(x) x
+#define pthread_null(x) x=0
+#define _SOTYPE void*
+#define SOCKET int
+
+#if ! (defined __uClinux__ || defined APPLE || defined MIPSEL)
+#include <mcheck.h>
+#include <ifaddrs.h>
+#endif
+#include <pwd.h>
+#include <sched.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <stdint.h>
+#include <termios.h>
+
+#include <arpa/inet.h>
+#ifndef APPLE
+#include <linux/version.h>
+#include <netpacket/packet.h>
+#include <sys/sysinfo.h>
+#else
+typedef unsigned int uint32_t;
+typedef uint32_t __u32;
+typedef uint32_t u_int32_t;
+typedef unsigned short uint16_t;
+typedef uint16_t __u16;
+typedef uint16_t u_int16_t;
+typedef unsigned char uint8_t;
+typedef uint8_t __u8;
+typedef uint8_t u_int8_t;
+
+#define CA_TPDU_MAX 2048
+
+#define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP
+#define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP
+#ifndef s6_addr16
+#define s6_addr16 __u6_addr.__u6_addr16
+#endif
+#endif
+
+#include <netdb.h>
+
+#include <net/if.h>
+#ifdef APPLE
+#include <ifaddrs.h>
+#include <net/if_types.h>
+#endif
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <netinet/icmp6.h>
+#include <netinet/ip_icmp.h>
+#include <netinet/if_ether.h>
+#include <netinet/ip6.h>
+#include <netinet/tcp.h>
+#include <netinet/udp.h>
+
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/poll.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/uio.h> /* for iovec{} and readv/writev */
+#include <sys/un.h> /* for Unix domain sockets */
+#include <sys/utsname.h>
+#include <sys/wait.h>
+
+#if defined __uClinux__
+#include <mathf.h>
+#endif
+#define closesocket close
+#endif
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <math.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <zlib.h>
+
+#include <sys/stat.h>
+
+//----------------------------------------------------------------------
+#ifndef __uClinux__
+ //DVBAPI
+#include <linux/dvb/frontend.h>
+#include <linux/dvb/ca.h>
+#if ! (defined WIN32 || defined APPLE)
+#include <linux/dvb/dmx.h>
+#endif
+// #else
+// #endif
+
+#define dvb_ioctl ioctl
+#define dvb_close close
+#else
+#include <dvb/frontend.h>
+#include <ci/ca.h>
+#endif // __uClinux__
+
+#define CA_TPDU_MAX 2048
+
+typedef struct recv_sec
+{
+ struct dvb_diseqc_master_cmd diseqc_cmd;
+ fe_sec_mini_cmd_t mini_cmd;
+ fe_sec_tone_mode_t tone_mode;
+ fe_sec_voltage_t voltage;
+} recv_sec_t;
+
+#define CA_MAX_SLOTS 16
+typedef struct
+{
+ ca_caps_t cap;
+ ca_slot_info_t info[CA_MAX_SLOTS];
+} recv_cacaps_t;
+
+typedef struct recv_festatus
+{
+ fe_status_t st;
+ uint32_t ber;
+ uint16_t strength;
+ uint16_t snr;
+ uint32_t ucblocks;
+} recv_festatus_t;
+
+//XML
+#include <libxml/encoding.h>
+#include <libxml/xmlwriter.h>
+#include <libxml/xmlmemory.h>
+#include <libxml/parser.h>
+#include <libxml/xpath.h>
+
+#ifdef DMALLOC
+#include <dmalloc.h>
+#endif
+
+#if ! defined GETTID && ! defined WIN32 && ! defined APPLE
+#include <asm/unistd.h>
+#define gettid() syscall (__NR_gettid)
+#else
+#define gettid pthread_self
+#endif
+
+#define UUID_SIZE 256
+
+
+#ifndef WIN32
+
+#ifdef SYSLOG
+extern char *_logstr;
+extern pthread_mutex_t _loglock;
+
+#ifdef DEBUG
+#define dbg(format, arg...) { pthread_mutex_lock (&_loglock); sprintf(_logstr, "%s:%d " format , __FILE__ , __LINE__ , ## arg); syslog_write(_logstr); pthread_mutex_unlock (&_loglock);}
+#else
+#define dbg(format, arg...) do {} while (0)
+#endif
+
+#define err(format, arg...) {pthread_mutex_lock (&_loglock); sprintf(_logstr, "err:%s:%d: %s (%d): " format , __FILE__ , __LINE__ ,strerror(errno), errno, ## arg); fprintf(stdout, "%s", _logstr); syslog_write(_logstr);abort(); pthread_mutex_unlock (&_loglock);}
+#define info(format, arg...){pthread_mutex_lock (&_loglock); sprintf(_logstr, format ,## arg); fprintf(stdout, "%s", _logstr); syslog_write(_logstr); pthread_mutex_unlock (&_loglock);}
+#define warn(format, arg...){pthread_mutex_lock (&_loglock); sprintf(_logstr, format ,## arg); fprintf(stdout, "%s", _logstr); syslog_write(_logstr); pthread_mutex_unlock (&_loglock);}
+#define sys(format, arg...){pthread_mutex_lock (&_loglock); sprintf(_logstr, format ,## arg); syslog_write(_logstr); pthread_mutex_unlock (&_loglock);}
+#elif defined DEBUG
+#define dbg(format, arg...) {printf("%s:%d " format , __FILE__ , __LINE__ , ## arg)}
+#define err(format, arg...) {fprintf(stderr,"err:%s:%d: %s (%d): " format , __FILE__ , __LINE__ ,strerror(errno), errno, ## arg);print_trace();abort();}
+#define info(format, arg...) printf("%s:%d: " format , __FILE__ , __LINE__ ,## arg)
+#define warn(format, arg...) fprintf(stderr,"%s:%d: " format , __FILE__ , __LINE__ ,## arg)
+#else
+#define dbg(format, arg...) do {} while (0)
+#define err(format, arg...) {fprintf(stderr,"%s (%d): " format, strerror(errno), errno, ## arg);exit(-1);}
+#define info(format, arg...) printf(format , ## arg)
+#define warn(format, arg...) fprintf(stderr, format , ## arg)
+#define sys(format, arg...) printf(format, ## arg)
+#endif // Syslog
+
+#else // WIN32
+#ifdef DEBUG
+static void inline dbg(char *format, ...)
+{
+ char buffer[1024];
+ va_list args;
+ va_start(args, format);
+ vsprintf(buffer, format, args);
+ printf("%s:%d %s", __FILE__, __LINE__, buffer);
+ va_end(args);
+}
+static void inline err(char *format, ...)
+{
+ char buffer[1024];
+ va_list args;
+ va_start(args, format);
+ vsprintf(buffer, format, args);
+ fprintf(stderr, "err:%s:%d: %s (%d): %s ", __FILE__, __LINE__,
+ strerror(errno), errno, buffer);
+ va_end(args);
+ abort();
+}
+static void inline info(const char *format, ...)
+{
+ char buffer[1024];
+ va_list args;
+ va_start(args, format);
+ vsprintf(buffer, format, args);
+ printf("%s:%d: %s", __FILE__, __LINE__, buffer);
+ va_end(args);
+}
+static void inline warn(const char *format, ...)
+{
+ char buffer[1024];
+ va_list args;
+ va_start(args, format);
+ vsprintf(buffer, format, args);
+ fprintf(stderr, "%s:%d: %s", __FILE__, __LINE__, buffer);
+ va_end(args);
+}
+#else
+static void inline dbg(char *format, ...)
+{
+}
+static void inline err(char *format, ...)
+{
+ char buffer[1024];
+ va_list args;
+ va_start(args, format);
+ vsprintf(buffer, format, args);
+ fprintf(stderr, "err:%s:%d: %s", strerror(errno), errno, buffer);
+ va_end(args);
+ abort();
+}
+static void inline info(const char *format, ...)
+{
+ char buffer[1024];
+ va_list args;
+ va_start(args, format);
+ vsprintf(buffer, format, args);
+ puts(buffer);
+ va_end(args);
+}
+static void inline warn(const char *format, ...)
+{
+ char buffer[1024];
+ va_list args;
+ va_start(args, format);
+ vsprintf(buffer, format, args);
+ fputs(buffer, stderr);
+ va_end(args);
+}
+
+#endif //DEBUG
+#endif // WIN32
+
+#ifndef MICROBLAZE
+#define FE_DVBS2 (FE_ATSC+1)
+#endif
+
+// RMM S2 Extension
+#define FEC_1_4 10
+#define FEC_1_3 11
+#define FEC_2_5 12
+#define FEC_3_5 13
+#define FEC_9_10 14
+#define QPSK_S2 9
+#define PSK8 10
+
+#ifdef MICROBLAZE
+#define STATIC
+#else
+#define STATIC static
+#endif
+#endif
diff --git a/device.c b/device.c
new file mode 100644
index 0000000..2acabe0
--- /dev/null
+++ b/device.c
@@ -0,0 +1,962 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ */
+
+#include <time.h>
+#include <iostream>
+
+#include <vdr/channels.h>
+#include <vdr/ringbuffer.h>
+#include <vdr/eit.h>
+#include <vdr/timers.h>
+#include <vdr/skins.h>
+#include <vdr/eitscan.h>
+
+#include "filter.h"
+#include "device.h"
+#include "mcli.h"
+
+#define st_Pos 0x07FF
+#define st_Neg 0x0800
+
+using namespace std;
+
+static int handle_ts (unsigned char *buffer, size_t len, void *p)
+{
+ return p ? ((cMcliDevice *) p)->HandleTsData (buffer, len) : len;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+static int handle_ten (tra_t * ten, void *p)
+{
+ cMcliDevice *m = (cMcliDevice *) p;
+ if (ten) {
+// fprintf (stderr, "Status:%02X, Strength:%04X, SNR:%04X, BER:%04X\n", ten->s.st, ten->s.strength, ten->s.snr, ten->s.ber);
+ m->SetTenData (ten);
+ if (ten->s.st & FE_HAS_LOCK) {
+ m->m_locked.Broadcast ();
+ }
+ } else {
+ tra_t ten;
+ memset (&ten, 0, sizeof (tra_t));
+ m->SetTenData (&ten);
+// fprintf (stderr, "Signal lost\n");
+ }
+ return 0;
+}
+
+cMcliDevice::cMcliDevice (void)
+{
+ m_enable = false;
+ m_tuned = false;
+ StartSectionHandler ();
+#ifdef USE_VDR_PACKET_BUFFER
+ m_PB = new cRingBufferLinear(MEGABYTE(4), TS_SIZE, false, "MCLI_TS");
+ m_PB->SetTimeouts (0, 100);
+ delivered = false;
+#else
+ m_PB = new cMyPacketBuffer (10000 * TS_SIZE, 10000);
+ m_PB->SetTimeouts (0, CLOCKS_PER_SEC * 20 / 1000);
+#endif
+ m_filters = new cMcliFilters ();
+// printf ("cMcliDevice: got device number %d\n", CardIndex () + 1);
+ m_pidsnum = 0;
+ m_mcpidsnum = 0;
+ m_filternum = 0;
+ m_mcli = NULL;
+ m_fetype = -1;
+ m_last = 0;
+ m_showtuning = 0;
+ m_ca_enable = false;
+ m_ca_override = false;
+ memset (m_pids, 0, sizeof (m_pids));
+ memset (&m_ten, 0, sizeof (tra_t));
+ m_pids[0].pid=-1;
+ m_disabletimeout = TEMP_DISABLE_TIMEOUT_DEFAULT;
+ m_tunerref = NULL;
+ m_camref = NULL;
+ InitMcli ();
+}
+
+cMcliDevice::~cMcliDevice ()
+{
+ LOCK_THREAD;
+ StopSectionHandler ();
+ printf ("Device %d gets destructed\n", CardIndex () + 1);
+ Cancel (0);
+ m_locked.Broadcast ();
+ ExitMcli ();
+ DELETENULL (m_filters);
+ DELETENULL (m_PB);
+}
+
+bool cMcliDevice::Ready() {
+ return m_mcli ? m_mcli->Ready() : false;
+}
+
+void cMcliDevice::SetTenData (tra_t * ten)
+{
+ if(!ten->lastseen) {
+ ten->lastseen=m_ten.lastseen;
+ }
+ m_ten = *ten;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+void cMcliDevice::SetEnable (bool val)
+{
+ LOCK_THREAD;
+ m_enable = val;
+ if (!m_enable) {
+ recv_stop (m_r);
+ m_tuned = false;
+ if(GetCaEnable()) {
+ SetCaEnable(false);
+ m_mcli->CAMFree(m_camref);
+ m_camref = NULL;
+ }
+ if(m_tunerref) {
+ m_mcli->TunerFree(m_tunerref);
+ m_tunerref = NULL;
+ m_fetype = -1;
+ }
+ } else {
+ if(m_tunerref == NULL) {
+#if VDRVERSNUM < 10702
+ bool s2=m_chan.Modulation() == QPSK_S2 || m_chan.Modulation() == PSK8;
+#elif VDRVERSNUM < 10714
+ bool s2=m_chan.System() == SYS_DVBS2;
+#else
+ cDvbTransponderParameters dtp(m_chan.Parameters());
+ bool s2=dtp.System() == SYS_DVBS2;
+#endif
+ bool ret = false;
+ int pos;
+ int type;
+
+ TranslateTypePos(type, pos, m_chan.Source());
+ if(s2) {
+ type=FE_DVBS2;
+ }
+ ret = m_mcli->TunerAvailable((fe_type_t)type, pos);
+ if(!ret && type == FE_QPSK) {
+ type = FE_DVBS2;
+ ret = m_mcli->TunerAvailable((fe_type_t)type, pos);
+ }
+ if(!ret) {
+ return;
+ }
+ m_fetype = type;
+
+ int slot = -1;
+ if(m_chan.Ca(0)<=0xff) {
+ slot=m_chan.Ca(0)&0x03;
+ if(slot) {
+ slot--;
+ }
+ }
+
+ if(m_chan.Ca() && !GetCaEnable() && m_mcli->CAMAvailable(NULL, slot) && (m_camref=m_mcli->CAMAlloc(NULL, slot))) {
+ SetCaEnable();
+ }
+
+ recv_tune (m_r, (fe_type_t)m_fetype, m_pos, &m_sec, &m_fep, m_pids);
+ m_tuned = true;
+ }
+ }
+}
+
+bool cMcliDevice::SetTempDisable (bool now)
+{
+ if(!now) {
+ Lock();
+ }
+//#ifndef REELVDR // they might find it out in some other place
+ // Check for tuning timeout
+ if(m_showtuning && Receiving(true) && ((time(NULL)-m_ten.lastseen)>=LASTSEEN_TIMEOUT)) {
+ Skins.QueueMessage(mtInfo, cString::sprintf(tr("Waiting for a free tuner (%s)"),m_chan.Name()));
+ m_showtuning = false;
+ }
+//#endif
+// printf("Device %d Receiving %d Priority %d\n",CardIndex () + 1, Receiving (true), Priority());
+ if(!Receiving (true) && (((time(NULL)-m_last) >= m_disabletimeout)) || now) {
+ recv_stop (m_r);
+ m_tuned = false;
+ if(GetCaEnable()) {
+ SetCaEnable(false);
+#ifdef DEBUG_TUNE
+ printf("Releasing CAM on %d (%s) (disable, %d)\n",CardIndex()+1, m_chan.Name(), now);
+#endif
+ m_mcli->CAMFree(m_camref);
+ m_camref = NULL;
+ }
+ if(m_tunerref) {
+#ifdef DEBUG_TUNE
+ printf("Releasing tuner on %d (%s)\n",CardIndex()+1, m_chan.Name());
+#endif
+ m_mcli->TunerFree(m_tunerref, false);
+ m_tunerref = NULL;
+ m_fetype = -1;
+ }
+ if(!now) {
+ Unlock();
+ }
+ return true;
+ }
+ if(!now) {
+ Unlock();
+ }
+ return false;
+}
+
+void cMcliDevice::SetFEType (fe_type_t val)
+{
+ m_fetype = (int)val;
+}
+
+int cMcliDevice::HandleTsData (unsigned char *buffer, size_t len)
+{
+#ifdef USE_VDR_PACKET_BUFFER
+ cMutexLock lock (&m_PB_Lock);
+#endif
+ m_filters->PutTS (buffer, len);
+#ifdef GET_TS_PACKETS
+ unsigned char *ptr = m_PB->PutStart (len);
+ if (ptr) {
+ memcpy (ptr, buffer, len);
+ m_PB->PutEnd (len, 0, 0);
+ }
+#else
+#ifdef USE_VDR_PACKET_BUFFER
+ if(m_PB->Free() < len) {
+ m_PB->Clear();
+ if(Receiving(true)) isyslog("MCLI: HandleTsData buffer overflow [%d] %s", CardIndex()+1, m_chan.Name());
+ }
+ return m_PB->Put(buffer, len);
+#else
+ unsigned int i;
+ for (i = 0; i < len; i += TS_SIZE) {
+ unsigned char *ptr = m_PB->PutStart (TS_SIZE);
+ if (ptr) {
+ memcpy (ptr, buffer + i, TS_SIZE);
+ m_PB->PutEnd (TS_SIZE, 0, 0);
+ }
+ }
+#endif
+#endif
+ return len;
+}
+
+
+void cMcliDevice::InitMcli (void)
+{
+ m_r = recv_add ();
+
+ register_ten_handler (m_r, handle_ten, this);
+ register_ts_handler (m_r, handle_ts, this);
+}
+
+void cMcliDevice::ExitMcli (void)
+{
+ register_ten_handler (m_r, NULL, NULL);
+ register_ts_handler (m_r, NULL, NULL);
+ recv_del (m_r);
+ m_r = NULL;
+}
+
+bool cMcliDevice::ProvidesSource (int Source) const
+{
+ int pos;
+ int type;
+ bool ret=false;
+
+ if (!m_enable) {
+ return false;
+ }
+
+ TranslateTypePos(type, pos, Source);
+
+ if(m_tunerref) {
+ ret= (type == m_fetype) || (type == FE_QPSK && m_fetype == FE_DVBS2);
+ if(ret) {
+ ret = m_mcli->TunerSatelitePositionLookup(m_tunerref, pos);
+ }
+ }
+
+ if(!ret) {
+ ret = m_mcli->TunerAvailable((fe_type_t)type, pos);
+ if(!ret && type == FE_QPSK) {
+ type = FE_DVBS2;
+ ret = m_mcli->TunerAvailable((fe_type_t)type, pos);
+ }
+ }
+#ifdef DEBUG_TUNE_EXTRA
+ printf ("ProvidesSource:%d Type:%d Pos:%d -> %d\n", CardIndex () + 1, type, pos, ret);
+#endif
+ return ret;
+}
+
+bool cMcliDevice::ProvidesTransponder (const cChannel * Channel) const
+{
+ if (!m_enable) {
+ return false;
+ }
+#if VDRVERSNUM < 10702
+ bool s2=Channel->Modulation() == QPSK_S2 || Channel->Modulation() == PSK8;
+#elif VDRVERSNUM < 10714
+ bool s2=Channel->System() == SYS_DVBS2;
+#else
+ cDvbTransponderParameters dtp(Channel->Parameters());
+ bool s2=dtp.System() == SYS_DVBS2;
+#endif
+ bool ret=ProvidesSource (Channel->Source ());
+ if(ret) {
+ int pos;
+ int type;
+ TranslateTypePos(type, pos, Channel->Source());
+ if(s2) {
+ type=FE_DVBS2;
+ }
+ if(m_tunerref) {
+ ret = (m_fetype == type) || (type == FE_QPSK && m_fetype == FE_DVBS2);
+ } else {
+ ret = false;
+ }
+ if(!ret) {
+ ret = m_mcli->TunerAvailable((fe_type_t)type, pos);
+ if(!ret && type == FE_QPSK) {
+ type = FE_DVBS2;
+ ret = m_mcli->TunerAvailable((fe_type_t)type, pos);
+ }
+ }
+ }
+#ifdef DEBUG_TUNE_EXTRA
+ printf ("ProvidesTransponder:%d S2:%d %s@%p -> %d\n", CardIndex () + 1, s2, Channel->Name (), this, ret);
+#endif
+ return ret;
+}
+
+bool cMcliDevice::IsTunedToTransponderConst (const cChannel * Channel) const
+{
+// printf ("IsTunedToTransponder %s == %s \n", Channel->Name (), m_chan.Name ());
+ if (!m_enable || !m_tuned) {
+ return false;
+ }
+
+#if VDRVERSNUM > 10713
+ cDvbTransponderParameters m_dtp(m_chan.Parameters());
+ cDvbTransponderParameters dtp(Channel->Parameters());
+#endif
+
+ if (m_ten.s.st & FE_HAS_LOCK && m_chan.Source() == Channel->Source() &&
+ m_chan.Transponder() == Channel->Transponder() && m_chan.Frequency() == Channel->Frequency() &&
+#if VDRVERSNUM > 10713
+ m_dtp.Modulation() == dtp.Modulation() &&
+#else
+ m_chan.Modulation() == Channel->Modulation() &&
+#endif
+ m_chan.Srate() == Channel->Srate()) {
+// printf ("Yes!!!");
+ return true;
+ }
+// printf ("Nope!!!");
+ return false;
+}
+
+bool cMcliDevice::IsTunedToTransponder (const cChannel * Channel)
+{
+ return IsTunedToTransponderConst(Channel);
+}
+
+bool cMcliDevice::CheckCAM(const cChannel * Channel, bool steal) const
+{
+ if(GetCaOverride() || !Channel->Ca()) {
+ return true;
+ }
+ int slot = -1;
+ if(Channel->Ca(0)<=0xff) {
+ slot=Channel->Ca(0)&0x03;
+ if(slot) {
+ slot--;
+ }
+ }
+ if(m_camref && (m_camref->slot == slot || slot == -1)) {
+ return true;
+ }
+ if(!m_mcli->CAMAvailable(NULL, slot) && !m_mcli->CAMSteal(NULL, slot, steal)) {
+ return false;
+ }
+ return true;
+}
+
+bool cMcliDevice::ProvidesChannel (const cChannel * Channel, int Priority, bool * NeedsDetachReceivers) const
+{
+ bool result = false;
+ bool hasPriority = Priority < 0 || Priority > this->Priority ();
+ bool needsDetachReceivers = false;
+ if (!m_enable) {
+ return false;
+ }
+ if(!CheckCAM(Channel, false)) {
+#ifdef DEBUG_TUNE
+ printf ("ProvidesChannel:%d Channel:%s, Prio:%d this->Prio:%d m_chan.Name:%s -> %d\n", CardIndex () + 1, Channel->Name (), Priority, this->Priority (), m_chan.Name(), false);
+#endif
+ return false;
+ }
+ if(ProvidesTransponder(Channel)) {
+ result = hasPriority;
+ if (Priority >= 0 && Receiving (true))
+ {
+ if (!IsTunedToTransponderConst(Channel)) {
+ needsDetachReceivers = true;
+ } else {
+ result = true;
+ }
+ }
+ }
+#ifdef DEBUG_TUNE
+ printf ("ProvidesChannel:%d Channel:%s, Prio:%d this->Prio:%d m_chan.Name:%s NeedsDetachReceivers:%d -> %d\n", CardIndex () + 1, Channel->Name (), Priority, this->Priority (), m_chan.Name(), needsDetachReceivers, result);
+#endif
+ if (NeedsDetachReceivers) {
+ *NeedsDetachReceivers = needsDetachReceivers;
+ }
+ return result;
+}
+
+void cMcliDevice::TranslateTypePos(int &type, int &pos, const int Source) const
+{
+#if VDRVERSNUM < 10713
+ pos = Source;
+ pos = ((pos & st_Neg) ? 1 : -1) * (pos & st_Pos);
+#else
+ int n = (Source & 0xffff);
+
+ if (n > 0x00007FFF) {
+ n |= 0xFFFF0000;
+ }
+
+ pos=abs(n);
+
+ if (n > 0 ){
+ pos = -pos;
+ }
+#endif
+ if (pos) {
+ pos += 1800;
+ } else {
+ pos = NO_SAT_POS;
+ }
+
+ type = Source & cSource::st_Mask;
+ switch(type) {
+ case cSource::stCable:
+ type = FE_QAM;
+ break;
+ case cSource::stSat:
+ type = FE_QPSK;
+ break;
+ case cSource::stTerr:
+ type = FE_OFDM;
+ break;
+ default:
+ type = -1;
+ }
+}
+
+bool cMcliDevice::SetChannelDevice (const cChannel * Channel, bool LiveView)
+{
+ bool is_scan = false;
+ int pos;
+ int type;
+ bool s2;
+
+ is_scan = !strlen(Channel->Name()) && !strlen(Channel->Provider());
+
+#ifdef DEBUG_TUNE
+ printf ("SetChannelDevice:%d Channel(%p):%s, Provider:%s, Source:%d, LiveView:%s, IsScan:%d, m_chan.Name:%s\n", CardIndex () + 1, Channel, Channel->Name (), Channel->Provider (), Channel->Source (), LiveView ? "true" : "false", is_scan, m_chan.Name());
+#endif
+ if (!m_enable) {
+ return false;
+ }
+ LOCK_THREAD;
+
+ if(is_scan) {
+ m_disabletimeout = TEMP_DISABLE_TIMEOUT_SCAN;
+ } else if (GetCaOverride()) {
+ m_disabletimeout = TEMP_DISABLE_TIMEOUT_CAOVERRIDE;
+ } else {
+ m_disabletimeout = TEMP_DISABLE_TIMEOUT_DEFAULT;
+ }
+ bool cam_force=!EITScanner.UsesDevice(this);
+ if(cam_force && !CheckCAM(Channel, true)) {
+#ifdef DEBUG_TUNE
+ printf("No CAM on %d available even after tried to steal one\n", CardIndex () + 1);
+#endif
+ return false;
+ }
+
+ if(!GetCaOverride() && Channel->Ca() && !GetCaEnable()) {
+ int slot = -1;
+ if(Channel->Ca(0)<=0xff) {
+ slot=Channel->Ca(0)&0x03;
+ if(slot) {
+ slot--;
+ }
+ }
+ if(!(m_camref=m_mcli->CAMAlloc(NULL, slot))) {
+#ifdef DEBUG_TUNE
+ printf("failed to get CAM on %d\n",CardIndex () + 1);
+#endif
+ if(cam_force) {
+ return false;
+ }
+ }
+ if(m_camref) {
+ SetCaEnable();
+ }
+ }
+ TranslateTypePos(type, pos, Channel->Source());
+#if VDRVERSNUM < 10702
+ s2=Channel->Modulation() == QPSK_S2 || Channel->Modulation() == PSK8;
+#elif VDRVERSNUM < 10714
+ s2=Channel->System() == SYS_DVBS2;
+#else
+ cDvbTransponderParameters dtp(Channel->Parameters());
+ s2=dtp.System() == SYS_DVBS2;
+#endif
+ if(s2) {
+ type = FE_DVBS2;
+ }
+
+ if(m_tunerref && (FE_QPSK == type) && (FE_DVBS2 == m_fetype)) type = FE_DVBS2;
+ if(m_tunerref && (m_fetype != type || !m_mcli->TunerSatelitePositionLookup(m_tunerref, pos))) {
+ m_mcli->TunerFree(m_tunerref);
+ m_tunerref = NULL;
+ }
+
+ if(s2 && (m_fetype != FE_DVBS2)) {
+ if(m_tunerref) {
+ m_mcli->TunerFree(m_tunerref);
+ m_tunerref = NULL;
+ }
+ type=FE_DVBS2;
+ }
+
+ if(m_tunerref == NULL) {
+ m_tunerref = m_mcli->TunerAlloc((fe_type_t)type, pos);
+ if(m_tunerref == NULL && type == FE_QPSK) {
+ type = FE_DVBS2;
+ m_tunerref = m_mcli->TunerAlloc((fe_type_t)type, pos);
+ }
+ m_tuned = false;
+ if(m_tunerref == NULL) {
+ return false;
+ }
+ m_fetype = type;
+ }
+
+ m_pos = pos;
+
+ if (IsTunedToTransponder (Channel) && !is_scan) {
+ m_chan = *Channel;
+
+#ifdef DEBUG_TUNE
+ printf("Already tuned to transponder on %d\n",CardIndex () + 1);
+#endif
+ return true;
+ } else {
+ memset (&m_ten, 0, sizeof (tra_t));
+ }
+ memset (&m_sec, 0, sizeof (recv_sec_t));
+ memset (&m_fep, 0, sizeof (struct dvb_frontend_parameters));
+ m_chan = *Channel;
+
+// printf("Really tuning on %d\n",CardIndex () + 1);
+ switch (m_fetype) {
+ case FE_DVBS2:
+ case FE_QPSK:{ // DVB-S
+
+ unsigned int frequency = Channel->Frequency ();
+
+#if VDRVERSNUM < 10714
+ fe_sec_voltage_t volt = (Channel->Polarization () == 'v' || Channel->Polarization () == 'V' || Channel->Polarization () == 'r' || Channel->Polarization () == 'R') ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18;
+#else
+ fe_sec_voltage_t volt = (dtp.Polarization () == 'v' || dtp.Polarization () == 'V' || dtp.Polarization () == 'r' || dtp.Polarization () == 'R') ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18;
+#endif
+ m_sec.voltage = volt;
+ frequency =::abs (frequency); // Allow for C-band, where the frequency is less than the LOF
+ m_fep.frequency = frequency * 1000UL;
+#if VDRVERSNUM < 10714
+ m_fep.inversion = fe_spectral_inversion_t (Channel->Inversion ());
+#else
+ m_fep.inversion = fe_spectral_inversion_t (dtp.Inversion ());
+#endif
+ m_fep.u.qpsk.symbol_rate = Channel->Srate () * 1000UL;
+#if VDRVERSNUM < 10702
+// m_fep.u.qpsk.fec_inner = fe_code_rate_t (Channel->CoderateH () | (Channel->Modulation () << 16));
+ int modulation = Channel->Modulation ();
+#if DVB_API_VERSION > 3
+ if (modulation==PSK_8) // Needed if PSK_8 != PSK8
+ modulation = PSK8;
+ else if(modulation==PSK_8+4) // patched DVB_V5 QPSK for S2
+ modulation = QPSK_S2;
+#endif
+ m_fep.u.qpsk.fec_inner = fe_code_rate_t (Channel->CoderateH () | (modulation << 16));
+#elif VDRVERSNUM < 10714
+ if(s2) {
+ int modulation = 0;
+ switch(Channel->Modulation ()) {
+ case QPSK:
+ modulation = QPSK_S2;
+ break;
+ case PSK_8:
+ modulation = PSK8;
+ break;
+ }
+ m_fep.u.qpsk.fec_inner = fe_code_rate_t (Channel->CoderateH () | (modulation << 16));
+ }
+#else
+ if(s2) {
+ int modulation = 0;
+ switch(dtp.Modulation ()) {
+ case QPSK:
+ modulation = QPSK_S2;
+ break;
+ case PSK_8:
+ modulation = PSK8;
+ break;
+ }
+ int coderateH = dtp.CoderateH ();
+ switch(dtp.CoderateH()) {
+ case FEC_AUTO+1: // DVB-API 5 FEC_3_5
+ coderateH = FEC_AUTO+4; // MCLI-API FEC_3_5
+ break;
+ case FEC_AUTO+2: // DVB-API 5 FEC_9_10
+ coderateH = FEC_AUTO+5; // MCLI-API FEC_9_10
+ break;
+ }
+ m_fep.u.qpsk.fec_inner = fe_code_rate_t (coderateH | (modulation << 16));
+ }
+#endif
+ }
+ break;
+ case FE_QAM:{ // DVB-C
+
+ // Frequency and symbol rate:
+ m_fep.frequency = FrequencyToHz (Channel->Frequency ());
+#if VDRVERSNUM < 10714
+ m_fep.inversion = fe_spectral_inversion_t (Channel->Inversion ());
+ m_fep.u.qam.fec_inner = fe_code_rate_t (Channel->CoderateH ());
+ m_fep.u.qam.modulation = fe_modulation_t (Channel->Modulation ());
+#else
+ m_fep.inversion = fe_spectral_inversion_t (dtp.Inversion ());
+ m_fep.u.qam.fec_inner = fe_code_rate_t (dtp.CoderateH ());
+ m_fep.u.qam.modulation = fe_modulation_t (dtp.Modulation ());
+#endif
+ m_fep.u.qam.symbol_rate = Channel->Srate () * 1000UL;
+ }
+ break;
+ case FE_OFDM:{ // DVB-T
+
+ // Frequency and OFDM paramaters:
+ m_fep.frequency = FrequencyToHz (Channel->Frequency ());
+#if VDRVERSNUM < 10714
+ m_fep.inversion = fe_spectral_inversion_t (Channel->Inversion ());
+ m_fep.u.ofdm.bandwidth = fe_bandwidth_t (Channel->Bandwidth ());
+ m_fep.u.ofdm.code_rate_HP = fe_code_rate_t (Channel->CoderateH ());
+ m_fep.u.ofdm.code_rate_LP = fe_code_rate_t (Channel->CoderateL ());
+ m_fep.u.ofdm.constellation = fe_modulation_t (Channel->Modulation ());
+ m_fep.u.ofdm.transmission_mode = fe_transmit_mode_t (Channel->Transmission ());
+ m_fep.u.ofdm.guard_interval = fe_guard_interval_t (Channel->Guard ());
+ m_fep.u.ofdm.hierarchy_information = fe_hierarchy_t (Channel->Hierarchy ());
+#else
+ m_fep.inversion = fe_spectral_inversion_t (dtp.Inversion ());
+ m_fep.u.ofdm.bandwidth = fe_bandwidth_t (dtp.Bandwidth ());
+ m_fep.u.ofdm.code_rate_HP = fe_code_rate_t (dtp.CoderateH ());
+ m_fep.u.ofdm.code_rate_LP = fe_code_rate_t (dtp.CoderateL ());
+ m_fep.u.ofdm.constellation = fe_modulation_t (dtp.Modulation ());
+ m_fep.u.ofdm.transmission_mode = fe_transmit_mode_t (dtp.Transmission ());
+ m_fep.u.ofdm.guard_interval = fe_guard_interval_t (dtp.Guard ());
+ m_fep.u.ofdm.hierarchy_information = fe_hierarchy_t (dtp.Hierarchy ());
+#endif
+ }
+ break;
+ default:
+ esyslog ("ERROR: attempt to set channel with unknown DVB frontend type");
+ return false;
+ }
+
+ recv_tune (m_r, (fe_type_t)m_fetype, m_pos, &m_sec, &m_fep, m_pids);
+ m_tuned = true;
+ if((m_pids[0].pid==-1)) {
+ dvb_pid_t pi;
+ memset(&pi, 0, sizeof(dvb_pid_t));
+ recv_pid_add (m_r, &pi);
+// printf("add dummy pid 0 @ %p\n", this);
+ }
+#ifdef DEBUG_PIDS
+ printf ("%p SetChannelDevice: Pidsnum:%d m_pidsnum:%d\n", m_r, m_mcpidsnum, m_pidsnum);
+ for (int i = 0; i < m_mcpidsnum; i++) {
+ printf ("Pid:%d\n", m_pids[i].pid);
+ }
+#endif
+ m_ten.lastseen=m_last=time(NULL);
+ m_showtuning = true;
+ return true;
+}
+
+bool cMcliDevice::HasLock (int TimeoutMs)
+{
+// printf ("HasLock TimeoutMs:%d\n", TimeoutMs);
+
+ if ((m_ten.s.st & FE_HAS_LOCK) || !TimeoutMs) {
+ return m_ten.s.st & FE_HAS_LOCK;
+ }
+ cMutexLock MutexLock (&mutex);
+ if (TimeoutMs && !(m_ten.s.st & FE_HAS_LOCK)) {
+ m_locked.TimedWait (mutex, TimeoutMs);
+ }
+ if (m_ten.s.st & FE_HAS_LOCK) {
+ return true;
+ }
+ return false;
+}
+
+bool cMcliDevice::SetPid (cPidHandle * Handle, int Type, bool On)
+{
+#ifdef DEBUG_TUNE
+ printf ("SetPid %d Pid:%d (%s), Type:%d, On:%d, used:%d sid:%d ca_enable:%d channel_ca:%d\n", CardIndex () + 1, Handle->pid, m_chan.Name(), Type, On, Handle->used, m_chan.Sid(), GetCaEnable(), m_chan.Ca (0));
+#endif
+ dvb_pid_t pi;
+ memset (&pi, 0, sizeof (dvb_pid_t));
+ if (!m_enable) {
+ return false;
+ }
+ LOCK_THREAD;
+ if (Handle->pid && (On || !Handle->used)) {
+ m_pidsnum += On ? 1 : -1;
+ if (m_pidsnum < 0) {
+ m_pidsnum = 0;
+ }
+
+ if (On) {
+ pi.pid = Handle->pid;
+ if (GetCaEnable() && m_chan.Ca (0)) {
+ pi.id= m_chan.Sid();
+ if(m_chan.Ca(0)<=0xff) {
+ pi.priority=m_chan.Ca(0)&0x03;
+ }
+ }
+#ifdef ENABLE_DEVICE_PRIORITY
+ int Prio = Priority();
+ if(Prio>50) // Recording prio high
+ pi.priority |= 3<<2;
+ else if(Prio > 10) // Recording prio normal
+ pi.priority |= 2<<2;
+ else if(Prio >= 0) // Recording prio low
+ pi.priority |= 1<<2;
+ else if(Prio == -1) // Live
+ pi.priority |= 1<<2;
+#endif
+// printf ("Add Pid:%d Sid:%d Type:%d Prio:%d %d\n", pi.pid, pi.id, Type, pi.priority, m_chan.Ca(0));
+ recv_pid_add (m_r, &pi);
+ } else {
+// printf ("Del Pid:%d\n", Handle->pid);
+ recv_pid_del (m_r, Handle->pid);
+ }
+ }
+ m_mcpidsnum = recv_pids_get (m_r, m_pids);
+#ifdef DEBUG_PIDS
+ printf ("%p SetPid: Pidsnum:%d m_pidsnum:%d m_filternum:%d\n", m_r, m_mcpidsnum, m_pidsnum, m_filternum);
+ for (int i = 0; i < m_mcpidsnum; i++) {
+ printf ("Pid:%d\n", m_pids[i].pid);
+ }
+#endif
+ m_last=time(NULL);
+ return true;
+}
+
+bool cMcliDevice::OpenDvr (void)
+{
+// printf ("OpenDvr\n");
+ m_dvr_open = true;
+ return true;
+}
+
+void cMcliDevice::CloseDvr (void)
+{
+// printf ("CloseDvr\n");
+ m_dvr_open = false;
+}
+
+#ifdef GET_TS_PACKETS
+int cMcliDevice::GetTSPackets (uchar * Data, int count)
+{
+ if (!m_enable || !m_dvr_open) {
+ return 0;
+ }
+ m_PB->GetEnd ();
+
+ int size;
+ uchar *buf = m_PB->GetStartMultiple (count, &size, 0, 0);
+ if (buf) {
+ memcpy (Data, buf, size);
+ m_PB->GetEnd ();
+ return size;
+ } else {
+ return 0;
+ }
+} // cMcliDevice::GetTSPackets
+#endif
+
+bool cMcliDevice::GetTSPacket (uchar * &Data)
+{
+#ifdef USE_VDR_PACKET_BUFFER
+ if (!m_enable || !m_dvr_open) return false;
+ Data = NULL;
+ int Count = 0;
+ if(delivered) {
+ m_PB->Del(TS_SIZE);
+ delivered=false;
+ }
+ uchar *p = m_PB->Get(Count);
+ if (p && Count >= TS_SIZE) {
+ if (*p != TS_SYNC_BYTE) {
+ for (int i = 1; i < Count; i++) {
+ if (p[i] == TS_SYNC_BYTE) {
+ Count = i;
+ break;
+ }
+ }
+ m_PB->Del(Count);
+ esyslog("cMcliDevice::GetTSPacket: skipped %d bytes to sync on TS packet on device %d", Count, CardIndex());
+ return true;
+ }
+ delivered = true;
+ Data = p;
+ }
+ return true;
+#else
+ if (m_enable && m_dvr_open) {
+ m_PB->GetEnd ();
+
+ int size;
+ Data = m_PB->GetStart (&size, 0, 0);
+ }
+ return true;
+#endif
+}
+
+int cMcliDevice::OpenFilter (u_short Pid, u_char Tid, u_char Mask)
+{
+ if (!m_enable) {
+ return -1;
+ }
+ LOCK_THREAD;
+ m_filternum++;
+// printf ("OpenFilter (%d/%d/%d) pid:%d tid:%d mask:%04x %s\n", m_filternum, m_pidsnum, m_mcpidsnum, Pid, Tid, Mask, ((m_filternum+m_pidsnum) < m_mcpidsnum) ? "PROBLEM!!!":"");
+ dvb_pid_t pi;
+ memset (&pi, 0, sizeof (dvb_pid_t));
+ pi.pid = Pid;
+// printf ("Add Pid:%d\n", pi.pid);
+ recv_pid_add (m_r, &pi);
+ m_mcpidsnum = recv_pids_get (m_r, m_pids);
+#ifdef DEBUG_PIDS
+ printf ("%p OpenFilter: Pidsnum:%d m_pidsnum:%d\n", m_r, m_mcpidsnum, m_pidsnum);
+ for (int i = 0; i < m_mcpidsnum; i++) {
+ printf ("Pid:%d\n", m_pids[i].pid);
+ }
+#endif
+ return m_filters->OpenFilter (Pid, Tid, Mask);
+}
+
+void cMcliDevice::CloseFilter (int Handle)
+{
+ if (!m_enable) {
+ return;
+ }
+
+ LOCK_THREAD;
+ int pid = m_filters->CloseFilter (Handle);
+
+ if ( pid != -1) {
+// printf("CloseFilter FULL\n");
+ recv_pid_del (m_r, pid);
+ m_mcpidsnum = recv_pids_get (m_r, m_pids);
+ }
+ m_filternum--;
+// printf ("CloseFilter(%d/%d/%d) pid:%d %s\n", m_filternum, m_pidsnum, m_mcpidsnum, pid, pid==-1?"PID STILL USED":"");
+}
+
+#ifdef DEVICE_ATTRIBUTES
+/* Attribute classes for dvbdevice
+ main main attributes
+ .name (String) "DVB", "IPTV", ...
+
+ fe : frontend attributes (-> get from tuner)
+ .type (int) FE_QPSK, ...
+ .name (string) Tuner name
+ .status,.snr,... (int)
+*/
+int cMcliDevice::GetAttribute (const char *attr_name, uint64_t * val)
+{
+ int ret = 0;
+ uint64_t rval = 0;
+
+ if (!strcmp (attr_name, "fe.status")) {
+ rval = m_ten.s.st;
+ if ((m_ten.lastseen+LASTSEEN_TIMEOUT)>time(0)) {
+ rval|= (m_ten.rotor_status&3)<<8;
+ rval|= (1+m_ten.slot)<<12;
+ }
+ } else if (!strcmp (attr_name, "fe.signal")) {
+ rval = m_ten.s.strength;
+ } else if (!strcmp (attr_name, "fe.snr")) {
+ rval = m_ten.s.snr;
+ } else if (!strcmp (attr_name, "fe.ber")) {
+ rval = m_ten.s.ber;
+ } else if (!strcmp (attr_name, "fe.unc")) {
+ rval = m_ten.s.ucblocks;
+ } else if (!strcmp (attr_name, "fe.type")) {
+ rval = m_fetype;
+ } else if (!strcmp (attr_name, "is.mcli")) {
+ rval = 1;
+ } else if (!strcmp (attr_name, "fe.lastseen")) {
+ rval = m_ten.lastseen;
+ } else
+ ret = -1;
+
+ if (val)
+ *val = rval;
+ return ret;
+}
+
+int cMcliDevice::GetAttribute (const char *attr_name, char *val, int maxret)
+{
+ int ret = 0;
+ if (!strcmp (attr_name, "fe.uuid")) {
+ strncpy (val, "NetCeiver", maxret);
+ val[maxret - 1] = 0;
+ } else if (!strcmp (attr_name, "fe.name")) {
+ strncpy (val, "NetCeiver", maxret);
+ val[maxret - 1] = 0;
+ } else if (!strncmp (attr_name, "main.", 5)) {
+ if (!strncmp (attr_name + 5, "name", 4)) {
+ if (val && maxret > 0) {
+ strncpy (val, "NetCeiver", maxret);
+ val[maxret - 1] = 0;
+ }
+ return 0;
+ }
+ } else {
+ ret = -1;
+ }
+ return ret;
+}
+#endif
diff --git a/device.h b/device.h
new file mode 100644
index 0000000..a8cb426
--- /dev/null
+++ b/device.h
@@ -0,0 +1,165 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ */
+
+#ifndef VDR_MCLI_DEVICE_H
+#define VDR_MCLI_DEVICE_H
+
+#include <vdr/device.h>
+#include <mcliheaders.h>
+
+#include "packetbuffer.h"
+
+class cPluginMcli;
+struct tuner_pool;
+struct cam_pool;
+
+class cMcliDevice:public cDevice
+{
+
+ private:
+ int m_pidsnum;
+ int m_mcpidsnum;
+ bool m_dvr_open;
+ recv_info_t *m_r;
+ recv_sec_t m_sec;
+ int m_pos;
+ struct dvb_frontend_parameters m_fep;
+ dvb_pid_t m_pids[RECV_MAX_PIDS];
+ tra_t m_ten;
+ int m_fetype;
+ cChannel m_chan;
+ cMutex mutex;
+ bool m_enable;
+ time_t m_last;
+ int m_filternum;
+ int m_disabletimeout;
+ bool m_tuned;
+ bool m_showtuning;
+ bool m_ca_enable;
+ bool m_ca_override;
+ struct tuner_pool *m_tunerref;
+ struct cam_pool *m_camref;
+
+ protected:
+ cPluginMcli *m_mcli;
+ virtual bool SetChannelDevice (const cChannel * Channel, bool LiveView);
+ virtual bool HasLock (int TimeoutMs);
+ virtual bool SetPid (cPidHandle * Handle, int Type, bool On);
+ virtual bool OpenDvr (void);
+ virtual void CloseDvr (void);
+ virtual bool GetTSPacket (uchar * &Data);
+
+ virtual int OpenFilter (u_short Pid, u_char Tid, u_char Mask);
+ virtual void CloseFilter (int Handle);
+ virtual bool CheckCAM(const cChannel * Channel, bool steal=false) const;
+
+#ifdef GET_TS_PACKETS
+ virtual int GetTSPackets (uchar *, int);
+#endif
+ bool IsTunedToTransponderConst (const cChannel * Channel) const;
+ void TranslateTypePos(int &type, int &pos, const int Source) const;
+
+
+ public:
+ cCondVar m_locked;
+#ifdef USE_VDR_PACKET_BUFFER
+ cRingBufferLinear *m_PB;
+ cMutex m_PB_Lock;
+ bool delivered;
+#else
+ cMyPacketBuffer *m_PB;
+#endif
+ cMcliFilters *m_filters;
+ cMcliDevice (void);
+ virtual ~ cMcliDevice ();
+ virtual bool Ready();
+ void SetMcliRef(cPluginMcli *m)
+ {
+ m_mcli=m;
+ }
+ virtual int NumProvidedSystems(void) const
+ {
+ return (m_fetype == FE_DVBS2)?2:1;
+ }
+
+#ifdef REELVDR
+ const cChannel *CurChan () const
+ {
+ return &m_chan;
+ };
+#endif
+ unsigned int FrequencyToHz (unsigned int f)
+ {
+ while (f && f < 1000000)
+ f *= 1000;
+ return f;
+ }
+ virtual bool HasInternalCam (void)
+ {
+ return true;
+ }
+ virtual bool ProvidesSource (int Source) const;
+ virtual bool ProvidesTransponder (const cChannel * Channel) const;
+ virtual bool ProvidesChannel (const cChannel * Channel, int Priority = -1, bool * NeedsDetachReceivers = NULL) const;
+ virtual bool IsTunedToTransponder (const cChannel * Channel);
+
+ virtual int HandleTsData (unsigned char *buffer, size_t len);
+ tra_t *GetTenData (void) {
+ return &m_ten;
+ }
+ void SetTenData (tra_t * ten);
+ void SetCaEnable (bool val = true)
+ {
+ m_ca_enable=val;
+ }
+ bool GetCaEnable (void) const
+ {
+ return m_ca_enable;
+ }
+ struct cam_pool *GetCAMref (void) const
+ {
+ return m_camref;
+ }
+ void SetCaOverride (bool val = true)
+ {
+ m_ca_override=val;
+ }
+ bool GetCaOverride (void) const
+ {
+ return m_ca_override;
+ }
+ void SetEnable (bool val = true);
+ bool SetTempDisable (bool now = false);
+ void SetFEType (fe_type_t val);
+ fe_type_t GetFEType (void)
+ {
+ return (fe_type_t)m_fetype;
+ };
+ void InitMcli (void);
+ void ExitMcli (void);
+ virtual bool ProvidesS2 () const
+ {
+ return m_fetype == FE_DVBS2;
+ }
+ virtual bool HasInput (void) const
+ {
+ return m_enable;
+ }
+#ifdef DEVICE_ATTRIBUTES
+ // Reel extension
+ virtual int GetAttribute (const char *attr_name, uint64_t * val);
+ virtual int GetAttribute (const char *attr_name, char *val, int maxret);
+#endif
+#if VDRVERSNUM > 10720
+ bool ProvidesEIT(void) const {
+ return true;
+ }
+#endif
+};
+
+#endif // VDR_MCLI_DEVICE_H
diff --git a/filter.c b/filter.c
new file mode 100644
index 0000000..fdcbe7a
--- /dev/null
+++ b/filter.c
@@ -0,0 +1,463 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ */
+
+#include "filter.h"
+#include "device.h"
+
+#include <vdr/device.h>
+
+#define PID_MASK_HI 0x1F
+
+class cMcliPid:public cListObject
+{
+ private:
+ int m_Pid;
+ int m_Tid;
+
+ public:
+ cMcliPid (int Pid, int Tid)
+ {
+ m_Pid = Pid;
+ m_Tid = Tid;
+ }
+ ~cMcliPid ()
+ {
+ }
+
+ int Tid (void)
+ {
+ return m_Tid;
+ }
+ int Pid (void)
+ {
+ return m_Pid;
+ }
+ void SetTid (int Tid)
+ {
+ m_Tid = Tid;
+ }
+};
+
+// --- cMcliFilter ------------------------------------------------------
+
+class cMcliFilter:public cListObject
+{
+ private:
+ uchar m_Buffer[65536];
+ int m_Used;
+ bool m_closed;
+ int m_Pipe[2];
+ u_short m_Pid;
+ u_char m_Tid;
+ u_char m_Mask;
+
+ public:
+ cMcliFilter (u_short Pid, u_char Tid, u_char Mask);
+ virtual ~ cMcliFilter ();
+
+ bool Matches (u_short Pid, u_char Tid);
+ bool PutSection (const uchar * Data, int Length, bool Pusi);
+ int ReadPipe (void) const
+ {
+ return m_Pipe[0];
+ }
+
+ bool IsClosed (void);
+ void Close (void);
+ void Reset (void);
+
+ u_short Pid (void) const
+ {
+ return m_Pid;
+ }
+ u_char Tid (void) const
+ {
+ return m_Tid;
+ }
+ u_char Mask (void) const
+ {
+ return m_Mask;
+ }
+};
+
+inline bool cMcliFilter::Matches (u_short Pid, u_char Tid)
+{
+// printf("Match: %d == %d m_Tid %d == %d %02x\n", m_Pid, Pid, m_Tid, Tid & m_Mask, m_Mask);
+ return m_Pid == Pid && m_Tid == (Tid & m_Mask);
+}
+
+cMcliFilter::cMcliFilter (u_short Pid, u_char Tid, u_char Mask)
+{
+ m_Used = 0;
+ m_Pid = Pid;
+ m_Tid = Tid;
+ m_Mask = Mask;
+ m_Pipe[0] = m_Pipe[1] = -1;
+ m_closed = false;
+
+#ifdef SOCK_SEQPACKET
+ // SOCK_SEQPACKET (since kernel 2.6.4)
+ if (socketpair (AF_UNIX, SOCK_SEQPACKET, 0, m_Pipe) != 0) {
+ esyslog ("mcli: socketpair(SOCK_SEQPACKET) failed: %m, trying SOCK_DGRAM");
+ }
+#endif
+ if (m_Pipe[0] < 0 && socketpair (AF_UNIX, SOCK_DGRAM, 0, m_Pipe) != 0) {
+ esyslog ("mcli: couldn't open section filter socket: %m");
+ }
+
+ else if (fcntl (m_Pipe[0], F_SETFL, O_NONBLOCK) != 0 || fcntl (m_Pipe[1], F_SETFL, O_NONBLOCK) != 0) {
+ esyslog ("mcli: couldn't set section filter socket to non-blocking mode: %m");
+ }
+}
+
+cMcliFilter::~cMcliFilter ()
+{
+// printf ("~cMcliFilter %p\n", this);
+ Close();
+}
+
+
+bool cMcliFilter::PutSection (const uchar * Data, int Length, bool Pusi)
+{
+
+ if (!m_Used && !Pusi) { /* wait for payload unit start indicator */
+// printf("Mittendrin pid %d tid %d mask %02x \n", Pid(), Tid(), Mask());
+ return true;
+ }
+ if (m_Used && Pusi) { /* reset at payload unit start */
+// int length = (((m_Buffer[1] & 0x0F) << 8) | m_Buffer[2]) + 3;
+// printf("RESET expect %d got %d for pid %d tid %d mask %02x \n",length, m_Used, Pid(), Tid(), Mask());
+ Reset ();
+ }
+ if (m_Used + Length >= (int) sizeof (m_Buffer)) {
+ esyslog ("ERROR: Mcli: Section handler buffer overflow (%d bytes lost)", Length);
+ Reset ();
+ return true;
+ }
+
+ memcpy (m_Buffer + m_Used, Data, Length);
+ m_Used += Length;
+ if (m_Used > 3) {
+ int length = (((m_Buffer[1] & 0x0F) << 8) | m_Buffer[2]) + 3;
+// printf("-> pid %d Tid %d Mask %02x expect %d got %d\n",Pid(), Tid(), Mask(), length, m_Used);
+ if (m_Used >= length) {
+// printf("Section complete\n");
+ m_Used = 0;
+ if (write (m_Pipe[1], m_Buffer, length) < 0) {
+ if (errno == EAGAIN || errno == EWOULDBLOCK)
+ //dsyslog ("cMcliFilter::PutSection socket overflow, " "Pid %4d Tid %3d", m_Pid, m_Tid);
+ ;
+ else {
+ m_closed=true;
+ return false;
+ }
+ }
+ }
+
+ if (m_Used > length) {
+ dsyslog ("cMcliFilter::PutSection: m_Used > length ! Pid %2d, Tid%2d " "(len %3d, got %d/%d)", m_Pid, m_Tid, Length, m_Used, length);
+ if (Length < TS_SIZE - 5) {
+ // TS packet not full -> this must be last TS packet of section data -> safe to reset now
+ Reset ();
+ }
+ }
+ }
+ return true;
+}
+
+void cMcliFilter::Reset (void)
+{
+#ifdef DEBUG_FILTER
+ if (m_Used)
+ dsyslog ("cMcliFilter::Reset skipping %d bytes", m_Used);
+#endif
+ m_Used = 0;
+}
+
+bool cMcliFilter::IsClosed (void)
+{
+ char m_Buffer[3] = { 0, 0, 0 }; /* tid 0, 0 bytes */
+ if(m_closed) {
+ return m_closed;
+ }
+
+ // Test if pipe/socket has been closed by writing empty section
+ if ((write (m_Pipe[1], m_Buffer, 3) < 0 && errno != EAGAIN && errno != EWOULDBLOCK)) {
+ if (errno != ECONNREFUSED && errno != ECONNRESET && errno != EPIPE)
+ esyslog ("cMcliFilter::IsClosed failed: %m");
+ m_closed = true;
+ return true;
+ }
+
+ return false;
+}
+
+void cMcliFilter::Close (void)
+{
+ if(m_Pipe[0]>=0) {
+ close (m_Pipe[0]);
+ m_Pipe[0]=-1;
+ }
+ if(m_Pipe[1]>=0) {
+ close (m_Pipe[1]);
+ m_Pipe[1]=-1;
+ }
+ m_closed=true;
+}
+
+// --- cMcliFilters -----------------------------------------------------
+
+cMcliFilters::cMcliFilters (void):
+cThread ("mcli: sections assembler")
+{
+ m_PB = NULL;
+}
+
+cMcliFilters::~cMcliFilters ()
+{
+}
+
+int cMcliFilters::PutTS (const uchar * data, int len)
+{
+ u_short pid = (((u_short) data[1] & PID_MASK_HI) << 8) | data[2];
+ if (m_PB && WantPid (pid)) {
+ int i;
+ for (i = 0; i < len; i += TS_SIZE) {
+ unsigned char *ptr = m_PB->PutStart (TS_SIZE);
+ if (ptr) {
+ memcpy (ptr, data + i, TS_SIZE);
+ m_PB->PutEnd (TS_SIZE, 0, 0);
+ }
+ }
+ }
+ return 0;
+}
+
+int cMcliFilters::CloseFilter (int Handle)
+{
+// printf("cMcliFilters::CloseFilter: %d\n", Handle);
+ GarbageCollect ();
+
+ int pid = GetPid (Handle);
+ if (pid != -1) {
+ m_pl.SetPid (pid, -1);
+ }
+ cMcliFilter *f=GetFilter(Handle);
+ if(f) {
+ LOCK_THREAD;
+ f->Close();
+ Del(f);
+ }
+ return pid;
+}
+
+int cMcliFilters::OpenFilter (u_short Pid, u_char Tid, u_char Mask)
+{
+// printf("cMcliFilters::OpenFilter: %d %d %02x\n", Pid, Tid, Mask);
+ GarbageCollect ();
+
+ if (!WantPid (Pid)) {
+ m_pl.SetPid (Pid, 0xffff);
+ }
+
+ if (!m_PB) {
+ m_PB = new cMyPacketBuffer (10000 * TS_SIZE, 10000);
+ m_PB->SetTimeouts (0, CLOCKS_PER_SEC * 20 / 1000);
+ }
+ Start ();
+
+ cMcliFilter *f = new cMcliFilter (Pid, Tid, Mask);
+ int fh = f->ReadPipe ();
+
+ Lock ();
+ Add (f);
+ Unlock ();
+
+ return fh;
+}
+
+int cMcliPidList::GetTidFromPid (int pid)
+{
+ for (cMcliPid * p = First (); p; p = Next (p)) {
+ if (p->Pid () == pid) {
+// printf("Found pid %d -> tid %d\n",pid, p->Tid());
+ return p->Tid ();
+ }
+ }
+ return -1;
+}
+
+void cMcliPidList::SetPid (int Pid, int Tid)
+{
+ if (Tid >= 0) {
+ for (cMcliPid * p = First (); p; p = Next (p)) {
+ if (p->Pid () == Pid) {
+// printf("Change pid %d -> tid %d\n", Pid, Tid);
+ if (Tid != 0xffff) {
+ p->SetTid (Tid);
+ }
+ return;
+ }
+ }
+ cMcliPid *pid = new cMcliPid (Pid, Tid);
+ Add (pid);
+// printf("Add pid %d -> tid %d\n", Pid, Tid);
+ } else {
+ for (cMcliPid * p = First (); p; p = Next (p)) {
+ if (p->Pid () == Pid) {
+// printf("Del pid %d\n", Pid);
+ Del (p);
+ return;
+ }
+ }
+ }
+}
+
+int cMcliFilters::GetPid (int Handle)
+{
+ int used = 0;
+ int pid = -1;
+
+ LOCK_THREAD;
+ for (cMcliFilter * fi = First (); fi; fi = Next (fi)) {
+ if (fi->ReadPipe () == Handle) {
+ pid = fi->Pid ();
+ break;
+ }
+ }
+ if(pid != -1) {
+ for (cMcliFilter * fi = First (); fi; fi = Next (fi)) {
+ if (pid == fi->Pid ()) {
+ used++;
+ }
+ }
+ }
+// printf("Pid %d used %dx\n", pid, used);
+ if (used==1) {
+ return pid;
+ }
+ return -1;
+}
+
+cMcliFilter *cMcliFilters::GetFilter (int Handle)
+{
+ LOCK_THREAD;
+ for (cMcliFilter * fi = First (); fi; fi = Next (fi)) {
+ if (fi->ReadPipe () == Handle) {
+ return fi;
+ }
+ }
+ return NULL;
+}
+
+bool cMcliFilters::WantPid (int pid)
+{
+ LOCK_THREAD;
+ for (cMcliFilter * fi = First (); fi; fi = Next (fi)) {
+ if (pid == fi->Pid ()) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void cMcliFilters::GarbageCollect (void)
+{
+ LOCK_THREAD;
+ for (cMcliFilter * fi = First (); fi;) {
+ if (fi->IsClosed ()) {
+ if (errno == ECONNREFUSED || errno == ECONNRESET || errno == EPIPE) {
+// printf ("cMcliFilters::GarbageCollector: filter closed: Pid %4d, Tid %3d, Mask %2x (%d filters left)\n", (int) fi->Pid (), (int) fi->Tid (), fi->Mask (), Count () - 1);
+
+ cMcliFilter *next = Prev (fi);
+ Del (fi);
+ fi = next ? Next (next) : First ();
+ } else {
+ esyslog ("cMcliFilters::GarbageCollector() error: " "Pid %4d, Tid %3d, Mask %2x (%d filters left) failed", (int) fi->Pid (), (int) fi->Tid (), fi->Mask (), Count () - 1);
+ LOG_ERROR;
+ fi = Next (fi);
+ }
+ } else {
+ fi = Next (fi);
+ }
+ }
+}
+
+void cMcliFilters::Action (void)
+{
+
+ while (Running ()) {
+ m_PB->GetEnd ();
+ int size;
+ const uchar *block = m_PB->GetStart (&size, 0, 0);
+ if (block) {
+ u_short pid = (((u_short) block[1] & PID_MASK_HI) << 8) | block[2];
+ int offset = ((block[3] & 0x20) >> 5) * (block[4] + 1); // offset is the length of the adaption field (see vdr/remux.c).
+ bool Pusi = (block[1] & 0x40) >> 6;
+ int len=188-4-offset; //payload len
+ block=block+4+offset; //point to payload
+ if ( Pusi ) {
+ if ( len>(block[0]) ) { //process last section chunk
+ ProcessChunk(pid,block+1,block[0],0);
+ len -= block[0]+1;
+ block += block[0]+1;
+ } else {
+ len=0; //error!?!
+ }
+ } else {
+ if ( len>0 ) { //process section chunk
+ ProcessChunk(pid,block,len,0);
+ block +=len;
+ len = 0;
+ }
+ }
+ while ( len>0 ) { //process complete section or initial chunk
+ int chunklen= ( ( (block[1]<<8) | block[2] ) & 0xFFF ) + 3 ;
+ if ( chunklen>len ) {
+ chunklen=len;
+ }
+ ProcessChunk(pid,block,chunklen,1);
+ block +=chunklen;
+ len -= chunklen;
+ }
+ }
+ }
+ DELETENULL (m_PB);
+ dsyslog ("McliFilters::Action() ended");
+}
+
+void cMcliFilters::ProcessChunk(u_short pid, const uchar *block, int len, bool Pusi) {
+ int tid = -1;
+ if (Pusi) {
+ tid = (int) block[0];
+ m_pl.SetPid (pid, tid);
+ } else {
+ tid = m_pl.GetTidFromPid (pid);
+ if (tid == -1) {
+ //printf("Failed to get tid for pid %d\n", pid);
+ }
+ }
+ //printf("pid:%d tid:%d Pusi: %d len: %d\n", pid, tid, Pusi, len);
+ LOCK_THREAD;
+ cMcliFilter *f = First ();
+ while (f) {
+ cMcliFilter *next = Next (f);
+ if (tid != -1 && f->Matches (pid, tid)) {
+ //printf("Match!!!!");
+ if (!f->PutSection (block, len, Pusi)) {
+ if (errno != ECONNREFUSED && errno != ECONNRESET && errno != EPIPE) {
+ esyslog ("mcli: couldn't send section packet");
+ }
+ Del (f);
+ // Filter was closed.
+ // - need to check remaining filters for another match
+ } // if
+ }
+ f = next;
+ }
+}
diff --git a/filter.h b/filter.h
new file mode 100644
index 0000000..d42bc18
--- /dev/null
+++ b/filter.h
@@ -0,0 +1,56 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ */
+
+#ifndef VDR_STREAMDEV_FILTER_H
+#define VDR_STREAMDEV_FILTER_H
+
+#include <vdr/config.h>
+#include <vdr/tools.h>
+#include <vdr/thread.h>
+#include "packetbuffer.h"
+
+class cMcliFilter;
+class cMcliPid;
+
+class cMcliPidList:public cList < cMcliPid >
+{
+ public:
+ cMcliPidList (void)
+ {
+ };
+ ~cMcliPidList () {
+ };
+ int GetTidFromPid (int pid);
+ void SetPid (int Pid, int Tid);
+};
+
+class cMcliFilters:public cList < cMcliFilter >, public cThread
+{
+ private:
+ cMyPacketBuffer * m_PB;
+ cMcliPidList m_pl;
+ bool m_closed;
+
+ protected:
+ virtual void Action (void);
+ void GarbageCollect (void);
+ void ProcessChunk(u_short pid, const uchar *block, int len, bool Pusi);
+
+ public:
+ cMcliFilters (void);
+ virtual ~ cMcliFilters ();
+ bool WantPid (int pid);
+ int GetTidFromPid (int pid);
+ int GetPid (int Handle);
+ cMcliFilter *GetFilter (int Handle);
+ int PutTS (const uchar * data, int len);
+ int OpenFilter (u_short Pid, u_char Tid, u_char Mask);
+ int CloseFilter (int Handle);
+};
+
+#endif // VDR_STREAMDEV_FILTER_H
diff --git a/mcast/.svn/entries b/mcast/.svn/entries
new file mode 100644
index 0000000..2fee7ce
--- /dev/null
+++ b/mcast/.svn/entries
@@ -0,0 +1,40 @@
+10
+
+dir
+18963
+svn://reelbox.org/testing/src/vdr-plugins/src/mcli-1/mcast
+svn://reelbox.org
+
+
+
+2011-08-18T10:09:14.813360Z
+17158
+dirk
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+12be777f-adf9-0310-842f-e37ecc4c7426
+
+tool
+dir
+
+client
+dir
+
+dvbloop
+dir
+
+common
+dir
+
diff --git a/mcast/client/.indent.pro b/mcast/client/.indent.pro
new file mode 100644
index 0000000..2faef85
--- /dev/null
+++ b/mcast/client/.indent.pro
@@ -0,0 +1 @@
+-i8 -br -l0 -ce -npsl
diff --git a/mcast/client/.svn/entries b/mcast/client/.svn/entries
new file mode 100644
index 0000000..11f10fe
--- /dev/null
+++ b/mcast/client/.svn/entries
@@ -0,0 +1,1357 @@
+10
+
+dir
+18963
+svn://reelbox.org/testing/src/vdr-plugins/src/mcli-1/mcast/client
+svn://reelbox.org
+
+
+
+2011-08-18T10:09:14.813360Z
+17158
+dirk
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+12be777f-adf9-0310-842f-e37ecc4c7426
+
+dvblo_handler.c
+file
+
+
+
+
+2012-09-27T17:22:49.690848Z
+c4b6b1eb8cd3a18164b5e331f0a38e66
+2011-08-18T10:09:14.813360Z
+17158
+dirk
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+20024
+
+recv_ccpp.c
+file
+
+
+
+
+2012-09-27T17:22:49.690848Z
+5f878ec9ebd38288cfcc82ee5020c35f
+2011-07-12T13:36:23.313379Z
+16905
+rollercoaster
+has-props
+
+
+svn:special
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+21
+
+api_server.h
+file
+
+
+
+
+2012-09-27T17:22:49.690848Z
+b8b3a949bf3dd399db5549c95421ddcb
+2011-07-12T13:36:23.313379Z
+16905
+rollercoaster
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1357
+
+tca_handler.c
+file
+
+
+
+
+2012-09-27T17:22:49.690848Z
+2b508aed689369915aa2901edb11ac20
+2011-07-12T13:36:23.313379Z
+16905
+rollercoaster
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1840
+
+satlists.c
+file
+
+
+
+
+2012-09-27T17:22:49.690848Z
+d3b50554e8c693cfd4af919fad07fbc0
+2011-08-18T10:09:14.813360Z
+17158
+dirk
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+5049
+
+api_test.c
+file
+
+
+
+
+2012-09-27T17:22:49.690848Z
+fce170fc6462af495657d8669b043b41
+2011-07-12T13:36:23.313379Z
+16905
+rollercoaster
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+4459
+
+dvblo_handler.h
+file
+
+
+
+
+2012-09-27T17:22:49.690848Z
+9adb433e99e33b9e2d694ff475b740de
+2011-07-12T13:36:23.313379Z
+16905
+rollercoaster
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+743
+
+tca_handler.h
+file
+
+
+
+
+2012-09-27T17:22:49.690848Z
+3a3b79eee5e1dba852b69f2000a3ccee
+2011-07-12T13:36:23.313379Z
+16905
+rollercoaster
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+405
+
+mld_client.c
+file
+
+
+
+
+2012-09-27T17:22:49.690848Z
+e05bdc7ebc621c510360568867dfdecf
+2011-07-12T13:36:23.313379Z
+16905
+rollercoaster
+has-props
+
+
+svn:special
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+22
+
+.indent.pro
+file
+
+
+
+
+2012-09-27T17:22:49.690848Z
+536d6397e801893325c24ec292dee74f
+2011-07-12T13:36:23.313379Z
+16905
+rollercoaster
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+22
+
+mmi_handler.c
+file
+
+
+
+
+2012-09-27T17:22:49.690848Z
+f85ea2246efdb5607ee9a20366bfcd51
+2011-08-18T10:09:14.813360Z
+17158
+dirk
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+9851
+
+inet_aton.c
+file
+
+
+
+
+2012-09-27T17:22:49.690848Z
+48b37f322a2ae164aa3fb4204c83f6a3
+2011-07-12T13:36:23.313379Z
+16905
+rollercoaster
+has-props
+
+
+svn:special
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+27
+
+headers.h
+file
+
+
+
+
+2012-09-27T17:22:49.690848Z
+aeaf120e1dfc0892b0c49cdf722c9fef
+2011-07-12T13:36:23.313379Z
+16905
+rollercoaster
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+638
+
+interfaces.c
+file
+
+
+
+
+2012-09-27T17:22:49.690848Z
+bd70360e68db12e0e2fe335bc92ad0e3
+2011-07-12T13:36:23.313379Z
+16905
+rollercoaster
+has-props
+
+
+svn:special
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+22
+
+mmi_handler.h
+file
+
+
+
+
+2012-09-27T17:22:49.690848Z
+ed868ea810d05d4fe0ea795cad357faa
+2011-07-12T13:36:23.313379Z
+16905
+rollercoaster
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1225
+
+ci_handler.c
+file
+
+
+
+
+2012-09-27T17:22:49.690848Z
+d8f14df45e26ee759bb661076b00df2f
+2011-08-18T10:09:14.813360Z
+17158
+dirk
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+8218
+
+dummy_client.c
+file
+
+
+
+
+2012-09-27T17:22:49.690848Z
+c109d8ba8e2dec6b0b5b519c605148f5
+2011-08-18T10:09:14.813360Z
+17158
+dirk
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+2677
+
+Makefile
+file
+
+
+
+
+2012-09-27T17:22:49.690848Z
+ece098cc6788e85c17ce068287a98921
+2011-07-12T13:36:23.313379Z
+16905
+rollercoaster
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+4977
+
+ci_handler.h
+file
+
+
+
+
+2012-09-27T17:22:49.690848Z
+fefcc7f7895850402b2326d8801c41c7
+2011-07-12T13:36:23.313379Z
+16905
+rollercoaster
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+859
+
+dummy_client.h
+file
+
+
+
+
+2012-09-27T17:22:49.690848Z
+1d353edb3158ed94c160c71b499b6591
+2011-07-12T13:36:23.313379Z
+16905
+rollercoaster
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+180
+
+mld_reporter.c
+file
+
+
+
+
+2012-09-27T17:22:49.690848Z
+e3965ad4570cff659778eec00fbb7e4c
+2011-08-18T10:09:14.813360Z
+17158
+dirk
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+6670
+
+input.c
+file
+
+
+
+
+2012-09-27T17:22:49.694848Z
+d1e761e12f3e1dec2a559289cb35cde8
+2011-08-18T10:09:14.813360Z
+17158
+dirk
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+3730
+
+tools.c
+file
+
+
+
+
+2012-09-27T17:22:49.694848Z
+c0906e8f658e6d84d4e12dca1e3ffc57
+2011-07-12T13:36:23.313379Z
+16905
+rollercoaster
+has-props
+
+
+svn:special
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+17
+
+mingw
+dir
+
+mld_reporter.h
+file
+
+
+
+
+2012-09-27T17:22:49.694848Z
+d2eab4a0ce39c3aa79acf912f5bdf7ae
+2011-07-12T13:36:23.313379Z
+16905
+rollercoaster
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+239
+
+mcast.c
+file
+
+
+
+
+2012-09-27T17:22:49.694848Z
+b6c289caaedfc9f9a24d597c72a5d8ce
+2011-07-12T13:36:23.313379Z
+16905
+rollercoaster
+has-props
+
+
+svn:special
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+17
+
+recv_tv.c
+file
+
+
+
+
+2012-09-27T17:22:49.694848Z
+e7bafc54679736def7ce798acacea0e7
+2011-08-18T10:09:14.813360Z
+17158
+dirk
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+25663
+
+ciparser.c
+file
+
+
+
+
+2012-09-27T17:22:49.694848Z
+0cc85089fb87cd0fd0e240e4163510ae
+2011-07-12T13:36:23.313379Z
+16905
+rollercoaster
+has-props
+
+
+svn:special
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+20
+
+recv_tv.h
+file
+
+
+
+
+2012-09-27T17:22:49.694848Z
+e270bffd77d17ca32d976a57be19ea2c
+2011-07-12T13:36:23.313379Z
+16905
+rollercoaster
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+2396
+
+api_shm_test.c
+file
+
+
+
+
+2012-09-27T17:22:49.694848Z
+3be100d9064c5186f90d3efe17ae5e0a
+2011-07-12T13:36:23.313379Z
+16905
+rollercoaster
+has-props
+
+
+svn:special
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+10
+
+win32
+file
+
+
+
+
+2012-09-27T17:22:49.694848Z
+7e2c1fbd0a7ddc76a7a55f662d59e6e3
+2011-07-12T13:36:23.313379Z
+16905
+rollercoaster
+has-props
+
+
+svn:special
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+15
+
+tra_handler.c
+file
+
+
+
+
+2012-09-27T17:22:49.694848Z
+720a9b9450e8d072850a8632f9efb3bc
+2011-07-12T13:36:23.313379Z
+16905
+rollercoaster
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1121
+
+mld_common.c
+file
+
+
+
+
+2012-09-27T17:22:49.694848Z
+d0224283be18ec0774fb34c10667634a
+2011-07-12T13:36:23.313379Z
+16905
+rollercoaster
+has-props
+
+
+svn:special
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+22
+
+main.c
+file
+
+
+
+
+2012-09-27T17:22:49.694848Z
+f1a5585bbe9a3711ad03bc10cb2def5a
+2011-08-18T10:09:14.813360Z
+17158
+dirk
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1599
+
+api_sock_test.c
+file
+
+
+
+
+2012-09-27T17:22:49.694848Z
+3be100d9064c5186f90d3efe17ae5e0a
+2011-07-12T13:36:23.313379Z
+16905
+rollercoaster
+has-props
+
+
+svn:special
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+10
+
+tra_handler.h
+file
+
+
+
+
+2012-09-27T17:22:49.694848Z
+694293ed706ea26dc96111413def41d4
+2011-07-12T13:36:23.313379Z
+16905
+rollercoaster
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+234
+
+sock_test.c
+file
+
+
+
+
+2012-09-27T17:22:49.686848Z
+7d714bc587133294a02cb2edf0e6a841
+2011-07-12T13:36:23.313379Z
+16905
+rollercoaster
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+2911
+
+inet_pton.c
+file
+
+
+
+
+2012-09-27T17:22:49.686848Z
+935bd6f5bff2d3724e7e1913bf6f0b81
+2011-07-12T13:36:23.313379Z
+16905
+rollercoaster
+has-props
+
+
+svn:special
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+27
+
+inet_ntop.c
+file
+
+
+
+
+2012-09-27T17:22:49.690848Z
+04380ba6685b175467f790aba9963a01
+2011-07-12T13:36:23.313379Z
+16905
+rollercoaster
+has-props
+
+
+svn:special
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+27
+
+api_server.c
+file
+
+
+
+
+2012-09-27T17:22:49.690848Z
+853f06ad8aec7ec15e6fda43b1f66a77
+2011-07-12T13:36:23.313379Z
+16905
+rollercoaster
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+10766
+
diff --git a/mcast/client/.svn/prop-base/api_shm_test.c.svn-base b/mcast/client/.svn/prop-base/api_shm_test.c.svn-base
new file mode 100644
index 0000000..d222469
--- /dev/null
+++ b/mcast/client/.svn/prop-base/api_shm_test.c.svn-base
@@ -0,0 +1,5 @@
+K 11
+svn:special
+V 1
+*
+END
diff --git a/mcast/client/.svn/prop-base/api_sock_test.c.svn-base b/mcast/client/.svn/prop-base/api_sock_test.c.svn-base
new file mode 100644
index 0000000..d222469
--- /dev/null
+++ b/mcast/client/.svn/prop-base/api_sock_test.c.svn-base
@@ -0,0 +1,5 @@
+K 11
+svn:special
+V 1
+*
+END
diff --git a/mcast/client/.svn/prop-base/ciparser.c.svn-base b/mcast/client/.svn/prop-base/ciparser.c.svn-base
new file mode 100644
index 0000000..d222469
--- /dev/null
+++ b/mcast/client/.svn/prop-base/ciparser.c.svn-base
@@ -0,0 +1,5 @@
+K 11
+svn:special
+V 1
+*
+END
diff --git a/mcast/client/.svn/prop-base/inet_aton.c.svn-base b/mcast/client/.svn/prop-base/inet_aton.c.svn-base
new file mode 100644
index 0000000..d222469
--- /dev/null
+++ b/mcast/client/.svn/prop-base/inet_aton.c.svn-base
@@ -0,0 +1,5 @@
+K 11
+svn:special
+V 1
+*
+END
diff --git a/mcast/client/.svn/prop-base/inet_ntop.c.svn-base b/mcast/client/.svn/prop-base/inet_ntop.c.svn-base
new file mode 100644
index 0000000..d222469
--- /dev/null
+++ b/mcast/client/.svn/prop-base/inet_ntop.c.svn-base
@@ -0,0 +1,5 @@
+K 11
+svn:special
+V 1
+*
+END
diff --git a/mcast/client/.svn/prop-base/inet_pton.c.svn-base b/mcast/client/.svn/prop-base/inet_pton.c.svn-base
new file mode 100644
index 0000000..d222469
--- /dev/null
+++ b/mcast/client/.svn/prop-base/inet_pton.c.svn-base
@@ -0,0 +1,5 @@
+K 11
+svn:special
+V 1
+*
+END
diff --git a/mcast/client/.svn/prop-base/interfaces.c.svn-base b/mcast/client/.svn/prop-base/interfaces.c.svn-base
new file mode 100644
index 0000000..d222469
--- /dev/null
+++ b/mcast/client/.svn/prop-base/interfaces.c.svn-base
@@ -0,0 +1,5 @@
+K 11
+svn:special
+V 1
+*
+END
diff --git a/mcast/client/.svn/prop-base/mcast.c.svn-base b/mcast/client/.svn/prop-base/mcast.c.svn-base
new file mode 100644
index 0000000..d222469
--- /dev/null
+++ b/mcast/client/.svn/prop-base/mcast.c.svn-base
@@ -0,0 +1,5 @@
+K 11
+svn:special
+V 1
+*
+END
diff --git a/mcast/client/.svn/prop-base/mld_client.c.svn-base b/mcast/client/.svn/prop-base/mld_client.c.svn-base
new file mode 100644
index 0000000..d222469
--- /dev/null
+++ b/mcast/client/.svn/prop-base/mld_client.c.svn-base
@@ -0,0 +1,5 @@
+K 11
+svn:special
+V 1
+*
+END
diff --git a/mcast/client/.svn/prop-base/mld_common.c.svn-base b/mcast/client/.svn/prop-base/mld_common.c.svn-base
new file mode 100644
index 0000000..d222469
--- /dev/null
+++ b/mcast/client/.svn/prop-base/mld_common.c.svn-base
@@ -0,0 +1,5 @@
+K 11
+svn:special
+V 1
+*
+END
diff --git a/mcast/client/.svn/prop-base/recv_ccpp.c.svn-base b/mcast/client/.svn/prop-base/recv_ccpp.c.svn-base
new file mode 100644
index 0000000..d222469
--- /dev/null
+++ b/mcast/client/.svn/prop-base/recv_ccpp.c.svn-base
@@ -0,0 +1,5 @@
+K 11
+svn:special
+V 1
+*
+END
diff --git a/mcast/client/.svn/prop-base/tools.c.svn-base b/mcast/client/.svn/prop-base/tools.c.svn-base
new file mode 100644
index 0000000..d222469
--- /dev/null
+++ b/mcast/client/.svn/prop-base/tools.c.svn-base
@@ -0,0 +1,5 @@
+K 11
+svn:special
+V 1
+*
+END
diff --git a/mcast/client/.svn/prop-base/win32.svn-base b/mcast/client/.svn/prop-base/win32.svn-base
new file mode 100644
index 0000000..d222469
--- /dev/null
+++ b/mcast/client/.svn/prop-base/win32.svn-base
@@ -0,0 +1,5 @@
+K 11
+svn:special
+V 1
+*
+END
diff --git a/mcast/client/.svn/text-base/.indent.pro.svn-base b/mcast/client/.svn/text-base/.indent.pro.svn-base
new file mode 100644
index 0000000..2faef85
--- /dev/null
+++ b/mcast/client/.svn/text-base/.indent.pro.svn-base
@@ -0,0 +1 @@
+-i8 -br -l0 -ce -npsl
diff --git a/mcast/client/.svn/text-base/Makefile.svn-base b/mcast/client/.svn/text-base/Makefile.svn-base
new file mode 100644
index 0000000..1ea0844
--- /dev/null
+++ b/mcast/client/.svn/text-base/Makefile.svn-base
@@ -0,0 +1,210 @@
+#Comment this out to disable debugging output
+#DEBUG=1
+#VERBOSE=1
+#WIN32=1
+#API_SOCK=1
+#VERBOSE=1
+#BACKTRACE=1
+
+ifdef RBMINI
+ ARMEL=1
+endif
+
+ARCH= $(shell $(CC) -dumpmachine)
+APPLE_DARWIN = $(shell echo $(ARCH) | grep -q 'apple-darwin' && echo "1" || echo "0")
+CYGWIN = $(shell echo $(ARCH) | grep -q 'cygwin' && echo "1" || echo "0")
+MIPSEL = $(shell echo $(ARCH) | grep -q 'mipsel' && echo "1" || echo "0")
+
+DEFS=-DCLIENT -DLIBRARY -D_REENTRANT -D_GNU_SOURCE
+
+ifeq ($(CYGWIN), 1)
+WIN32=1
+else
+API_SOCK=1
+endif
+
+ifeq ($(APPLE_DARWIN), 1)
+DEFS:=$(DEFS) -I../common/darwin/include/ -DAPPLE
+APPLE=1
+endif
+
+VDRDIR=../../../../..
+-include $(VDRDIR)/Make.config
+
+ifdef ARMEL
+ XML_INC := -I/usr/arm-linux-gnueabi/include/libxml2
+ XML_LIB := -lxml2
+ CROSS = arm-linux-gnueabi-
+else
+ifeq ($(MIPSEL),1)
+DEFS:=$(DEFS) -DMIPSEL
+XML_INC:=-I../../libxml2/include
+XML_LIB:=-L../../libxml2/lib
+else
+XML_INC:=`xml2-config --cflags`
+XML_LIB:=`xml2-config --libs`
+LIBRARY_PATH=/usr/lib
+endif
+endif
+ifeq ($(APPLE_DARWIN), 1)
+CFLAGS:= $(CFLAGS) -fPIC -fno-common -Wall -I../common $(DEFS)
+else
+CFLAGS:= $(CFLAGS) -fPIC -Wall -I../common $(DEFS)
+endif
+
+ifdef BACKTRACE
+CFLAGS:= $(CFLAGS) -DBACKTRACE -g
+endif
+
+ifdef API_SHM
+LDFLAGS:= $(LDFLAGS) -lrt
+CFLAGS:= $(CFLAGS) -DAPI_SHM
+endif
+ifdef API_SOCK
+CFLAGS:= $(CFLAGS) -DAPI_SOCK
+endif
+
+ifdef VERBOSE
+CFLAGS:= $(CFLAGS) -DDEBUG
+DEBUG=1
+endif
+
+ifdef WIN32
+CFLAGS:= -Iwin32/include $(CFLAGS) -mno-cygwin -fPIC -DWIN32
+LDFLAGS:= -Lwin32/lib $(LDFLAGS) -mno-cygwin
+LDLIBS:= -lpthreadGC2 -lxml2 -lz -lws2_32 -liphlpapi
+else
+CFLAGS:= $(CFLAGS) -I../dvbloop $(XML_INC)
+LDFLAGS:=$(LDFLAGS)
+LDLIBS:=$(XML_LIB) -lpthread -lz -lm
+endif
+
+ifdef DEBUG
+LDFLAGS:= $(LDFLAGS) -g -rdynamic
+CFLAGS:= $(CFLAGS) -g -O0
+else
+CFLAGS:= $(CFLAGS) -O3
+endif
+
+MCLI = mcli
+
+MCLI_OBJS= mld_common.o mld_client.o mld_reporter.o mcast.o recv_tv.o recv_ccpp.o tools.o tca_handler.o tra_handler.o satlists.o interfaces.o api_server.o ciparser.o ci_handler.o mmi_handler.o
+ifdef WIN32
+MCLI_OBJS := $(MCLI_OBJS) inet_pton.o inet_ntop.o inet_aton.o
+else
+MCLI_OBJS := $(MCLI_OBJS)
+endif
+
+MCLI_SOBJS = main.o
+ifdef WIN32
+MCLI_SOBJS := $(MCLI_SOBJS) dummy_client.o
+else
+ifdef APPLE
+MCLI_SOBJS := $(MCLI_SOBJS) dummy_client.o input.o
+else
+MCLI_SOBJS := $(MCLI_SOBJS) dvblo_handler.o input.o
+endif
+endif
+
+all: lib$(MCLI)
+
+static: $(MCLI)-static
+
+
+MAKEDEP = $(CXX) -MM -MG
+DEPFILE = .dependencies
+$(DEPFILE): Makefile
+ $(MAKEDEP) $(CFLAGS) $(MCLI_OBJS:%.o=%.c) > $@
+
+-include $(DEPFILE)
+
+
+$(MCLI): $(MCLI_OBJS) $(MCLI_SOBJS)
+ $(CC) $(LDFLAGS) -o $@ $(MCLI_OBJS) $(MCLI_SOBJS) $(LDLIBS)
+ifndef DEBUG
+ifndef WIN32
+ strip $(MCLI)
+endif
+endif
+
+lib$(MCLI): $(MCLI_OBJS)
+ifdef WIN32
+ $(CC) $(LDFLAGS) -shared -o $@.dll $(MCLI_OBJS) $(LDLIBS) -Wl,--out-implib,$@.a -Wl,--output-def,$@.def
+ lib /def:$@.def /machine:x86 /out:..\\common\\win32\\lib\\$@.lib
+# dlltool -k --dllname $@.dll --output-lib win32/lib/$@.lib --def $@.def
+ cp -a $@.dll win32/lib/
+ cp -a $@.a win32/lib/
+ cp -a $@.def win32/lib/
+endif
+ifdef APPLE
+ $(CC) $(LDFLAGS) -dynamiclib -o $@.dylib $(MCLI_OBJS) $(LDLIBS)
+ $(AR) $(ARFLAGS) $@.a $(MCLI_OBJS)
+else
+ $(CC) $(LDFLAGS) -shared -o $@.so $(MCLI_OBJS) $(LDLIBS)
+ $(AR) $(ARFLAGS) $@.a $(MCLI_OBJS)
+endif
+
+
+$(MCLI)-shared: lib$(MCLI)
+ $(CC) -c $(CFLAGS) -ULIBRARY -o main.o main.c
+ifdef WIN32
+ $(CC) -c $(CFLAGS) -ULIBRARY -o dummy_client.o dummy_client.c
+else
+ifdef APPLE
+ $(CC) -c $(CFLAGS) -ULIBRARY -o input.o input.c
+ $(CC) -c $(CFLAGS) -ULIBRARY -o dummy_client.o dummy_client.c
+else
+ $(CC) -c $(CFLAGS) -ULIBRARY -o input.o input.c
+ $(CC) -c $(CFLAGS) -ULIBRARY -o dvblo_handler.o dvblo_handler.c
+endif
+endif
+ $(CC) $(LDFLAGS) -o $@ $(MCLI_SOBJS) $(LDLIBS) -L. -lmcli
+
+$(MCLI)-static: $(MCLI_OBJS) $(MCLI_SOBJS)
+ $(CC) $(LDFLAGS) -static -static-libgcc -o $@ $(MCLI_OBJS) $(MCLI_SOBJS) $(LDLIBS) $(LIBRARY_PATH)/libxml2.a $(LIBRARY_PATH)/libz.a $(LIBRARY_PATH)/libm.a $(LIBRARY_PATH)/libpthread.a
+ifndef DEBUG
+ifndef WIN32
+ strip $(MCLI)-static
+endif
+endif
+
+api_shm_test.o: api_shm_test.c
+ $(CC) -c $(CFLAGS) -DUSE_SHM_API -o $@ $<
+
+api_sock_test.o:api_sock_test.c
+ $(CC) -c $(CFLAGS) -DUSE_SOCK_API -o $@ $<
+
+$(MCLI)-shmtest: api_shm_test.o
+ $(CC) $(LDFLAGS) -o $@ api_shm_test.o $(LDLIBS) -lrt
+
+$(MCLI)-socktest: api_sock_test.o
+ $(CC) $(LDFLAGS) -o $@ api_sock_test.o
+
+install: mcli
+ install -p $< /usr/sbin/$<
+
+install-lib: libmcli.la
+ libtool --mode=install install $< /usr/local/lib/
+
+install-shared: mcli-shared
+ libtool --mode=install install $< /usr/local/bin
+
+depend: .dependencies
+ #makedepend -Y -- $(CFLAGS) -- *c >/dev/null 2>&1
+
+clean:
+ rm -f $(MCLI) $(MCLI)-* *.elf *.gdb *.o *.lo *.la *~ *.so *.a *.def *.dll *.dylib out.ts
+
+mingw32:
+ rm -rf mingw/*.c mingw/*.h mingw/win32
+ cp *.c *.h mingw/
+ mkdir mingw/win32
+ cp -a win32/lib mingw/win32/
+ cp -a win32/include mingw/win32/
+ @echo "Created mingw directory - now ready to rumble... (call build.cmd)"
+
+%.o: %.c
+ $(CC) -c $(CFLAGS) -o $@ $<
+
+%.lo: %.c
+ $(CC) -c $(CFLAGS) -o $@ $<
diff --git a/mcast/client/.svn/text-base/api_server.c.svn-base b/mcast/client/.svn/text-base/api_server.c.svn-base
new file mode 100644
index 0000000..c3d7617
--- /dev/null
+++ b/mcast/client/.svn/text-base/api_server.c.svn-base
@@ -0,0 +1,397 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ */
+
+#include "headers.h"
+
+#if defined(API_SOCK) || defined(API_SHM) || defined (API_WIN)
+
+static int process_cmd (api_cmd_t * api_cmd, tra_info_t * trl, netceiver_info_list_t * nci)
+{
+ if(api_cmd->magic != MCLI_MAGIC || api_cmd->version != MCLI_VERSION) {
+ api_cmd->magic = MCLI_MAGIC;
+ api_cmd->version = MCLI_VERSION;
+ api_cmd->state = API_RESPONSE;
+ return 0;
+ }
+ if (api_cmd->state != API_REQUEST) {
+ return 0;
+ }
+
+ switch (api_cmd->cmd) {
+ case API_GET_NC_NUM:
+ api_cmd->parm[API_PARM_NC_NUM] = nci->nci_num;
+ api_cmd->state = API_RESPONSE;
+ break;
+
+ case API_GET_NC_INFO:
+ if (api_cmd->parm[API_PARM_NC_NUM] < nci->nci_num) {
+ api_cmd->u.nc_info = nci->nci[api_cmd->parm[API_PARM_NC_NUM]];
+ api_cmd->state = API_RESPONSE;
+ } else {
+ api_cmd->state = API_ERROR;
+ }
+ break;
+ case API_GET_TUNER_INFO:
+ if (api_cmd->parm[API_PARM_NC_NUM] < nci->nci_num) {
+ if (api_cmd->parm[API_PARM_TUNER_NUM] < nci->nci[api_cmd->parm[API_PARM_NC_NUM]].tuner_num) {
+ api_cmd->u.tuner_info = nci->nci[api_cmd->parm[API_PARM_NC_NUM]].tuner[api_cmd->parm[API_PARM_TUNER_NUM]];
+ api_cmd->state = API_RESPONSE;
+ } else {
+ api_cmd->state = API_ERROR;
+ }
+ } else {
+ api_cmd->state = API_ERROR;
+ }
+ break;
+ case API_GET_SAT_LIST_INFO:
+ if (api_cmd->parm[API_PARM_NC_NUM] < nci->nci_num) {
+ if (api_cmd->parm[API_PARM_SAT_LIST_NUM] < nci->nci[api_cmd->parm[API_PARM_NC_NUM]].sat_list_num) {
+ api_cmd->u.sat_list = nci->nci[api_cmd->parm[API_PARM_NC_NUM]].sat_list[api_cmd->parm[API_PARM_SAT_LIST_NUM]];
+ api_cmd->state = API_RESPONSE;
+ } else {
+ api_cmd->state = API_ERROR;
+ }
+ } else {
+ api_cmd->state = API_ERROR;
+ }
+ break;
+ case API_GET_SAT_INFO:
+ if (api_cmd->parm[API_PARM_NC_NUM] < nci->nci_num) {
+ if (api_cmd->parm[API_PARM_SAT_LIST_NUM] < nci->nci[api_cmd->parm[API_PARM_NC_NUM]].sat_list_num) {
+ if (api_cmd->parm[API_PARM_SAT_NUM] < nci->nci[api_cmd->parm[API_PARM_NC_NUM]].sat_list[api_cmd->parm[API_PARM_SAT_LIST_NUM]].sat_num) {
+ api_cmd->u.sat_info = nci->nci[api_cmd->parm[API_PARM_NC_NUM]].sat_list[api_cmd->parm[API_PARM_SAT_LIST_NUM]].sat[api_cmd->parm[API_PARM_SAT_NUM]];
+ api_cmd->state = API_RESPONSE;
+ } else {
+ api_cmd->state = API_ERROR;
+ }
+ } else {
+ api_cmd->state = API_ERROR;
+ }
+ } else {
+ api_cmd->state = API_ERROR;
+ }
+ break;
+
+ case API_GET_SAT_COMP_INFO:
+ if (api_cmd->parm[API_PARM_NC_NUM] < nci->nci_num) {
+ if (api_cmd->parm[API_PARM_SAT_LIST_NUM] < nci->nci[api_cmd->parm[API_PARM_NC_NUM]].sat_list_num) {
+ if (api_cmd->parm[API_PARM_SAT_NUM] < nci->nci[api_cmd->parm[API_PARM_NC_NUM]].sat_list[api_cmd->parm[API_PARM_SAT_LIST_NUM]].sat_num) {
+ if (api_cmd->parm[API_PARM_SAT_COMP_NUM] < nci->nci[api_cmd->parm[API_PARM_NC_NUM]].sat_list[api_cmd->parm[API_PARM_SAT_LIST_NUM]].sat[api_cmd->parm[API_PARM_SAT_NUM]].comp_num) {
+ api_cmd->u.sat_comp = nci->nci[api_cmd->parm[API_PARM_NC_NUM]].sat_list[api_cmd->parm[API_PARM_SAT_LIST_NUM]].sat[api_cmd->parm[API_PARM_SAT_NUM]].comp[api_cmd->parm[API_PARM_SAT_COMP_NUM]];
+ api_cmd->state = API_RESPONSE;
+ } else {
+ api_cmd->state = API_ERROR;
+ }
+ } else {
+ api_cmd->state = API_ERROR;
+ }
+ } else {
+ api_cmd->state = API_ERROR;
+ }
+ } else {
+ api_cmd->state = API_ERROR;
+ }
+ break;
+ case API_GET_TRA_NUM:
+ api_cmd->parm[API_PARM_TRA_NUM] = trl->tra_num;
+ api_cmd->state = API_RESPONSE;
+ break;
+ case API_GET_TRA_INFO:
+ if (api_cmd->parm[API_PARM_TRA_NUM] < trl->tra_num) {
+ api_cmd->u.tra = trl->tra[api_cmd->parm[API_PARM_TRA_NUM]];
+ api_cmd->state = API_RESPONSE;
+ } else {
+ api_cmd->state = API_ERROR;
+ }
+ break;
+ default:
+ api_cmd->state = API_ERROR;
+ }
+ return 1;
+}
+#endif
+#ifdef API_SOCK
+typedef struct
+{
+ pthread_t thread;
+ int fd;
+ struct sockaddr_un addr;
+ socklen_t len;
+ int run;
+} sock_t;
+
+static void *sock_cmd_loop (void *p)
+{
+ sock_t *s = (sock_t *) p;
+ api_cmd_t sock_cmd;
+ int n;
+ netceiver_info_list_t *nc_list=nc_get_list();
+ tra_info_t *tra_list=tra_get_list();
+
+ dbg ("new api client connected\n");
+ s->run = 1;
+ while (s->run){
+ n = recv (s->fd, &sock_cmd, sizeof (api_cmd_t), 0);
+ if (n == sizeof (api_cmd_t)) {
+ nc_lock_list();
+ process_cmd (&sock_cmd, tra_list, nc_list);
+ nc_unlock_list();
+ send (s->fd, &sock_cmd, sizeof (api_cmd_t), 0);
+ } else {
+ sock_cmd.magic = MCLI_MAGIC;
+ sock_cmd.version = MCLI_VERSION;
+ sock_cmd.state = API_RESPONSE;
+ send (s->fd, &sock_cmd, sizeof (api_cmd_t), 0);
+ break;
+ }
+ pthread_testcancel();
+ }
+
+ close (s->fd);
+ pthread_detach (s->thread);
+ free (s);
+ return NULL;
+}
+
+static void *sock_cmd_listen_loop (void *p)
+{
+ sock_t tmp;
+ sock_t *s = (sock_t *) p;
+ dbg ("sock api listen loop started\n");
+ s->run = 1;
+
+ while (s->run) {
+ tmp.len = sizeof (struct sockaddr_un);
+ tmp.fd = accept (s->fd, (struct sockaddr*)&tmp.addr, &tmp.len);
+ if (tmp.fd >= 0) {
+ sock_t *as = (sock_t *) malloc (sizeof (sock_t));
+ if (as == NULL) {
+ err ("Cannot get memory for socket\n");
+ }
+ *as=tmp;
+ as->run = 0;
+ pthread_create (&as->thread, NULL, sock_cmd_loop, as);
+ } else {
+ break;
+ }
+ pthread_testcancel();
+ }
+ pthread_detach (s->thread);
+ return NULL;
+}
+
+static sock_t s;
+int api_sock_init (const char *cmd_sock_path)
+{
+ s.addr.sun_family = AF_UNIX;
+ strcpy (s.addr.sun_path, cmd_sock_path);
+ s.len = sizeof(struct sockaddr_un); //strlen (cmd_sock_path) + sizeof (s.addr.sun_family);
+
+ if ((s.fd = socket (AF_UNIX, SOCK_STREAM, 0)) < 0) {
+ warn ("Cannot get socket %d\n", errno);
+ return -1;
+ }
+ unlink (cmd_sock_path);
+ if (bind (s.fd, (struct sockaddr*)&s.addr, s.len) < 0) {
+ warn ("Cannot bind control socket\n");
+ return -1;
+ }
+ if (chmod(cmd_sock_path, S_IRWXU|S_IRWXG|S_IRWXO)) {
+ warn ("Cannot chmod 777 socket %s\n", cmd_sock_path);
+ }
+ if (listen (s.fd, 5) < 0) {
+ warn ("Cannot listen on socket\n");
+ return -1;
+ }
+ return pthread_create (&s.thread, NULL, sock_cmd_listen_loop, &s);
+}
+
+void api_sock_exit (void)
+{
+ //FIXME memory leak on exit in context structres
+ s.run=0;
+ close(s.fd);
+
+ if(pthread_exist(s.thread) && !pthread_cancel (s.thread)) {
+ pthread_join (s.thread, NULL);
+ }
+}
+#endif
+#ifdef API_SHM
+static api_cmd_t *api_cmd = NULL;
+static pthread_t api_cmd_loop_thread;
+
+static void *api_cmd_loop (void *p)
+{
+ netceiver_info_list_t *nc_list=nc_get_list();
+ tra_info_t *tra_list=tra_get_list();
+ while (1) {
+ nc_lock_list();
+ process_cmd (api_cmd, tra_list, nc_list);
+ nc_unlock_list();
+ usleep (1);
+ pthread_testcancel();
+ }
+
+ return NULL;
+}
+
+int api_shm_init (void)
+{
+ int fd = shm_open (API_SHM_NAMESPACE, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
+ if (fd == -1) {
+ warn ("Cannot get a shared memory handle\n");
+ return -1;
+ }
+ if (ftruncate (fd, sizeof (api_cmd_t)) == -1) {
+ err ("Cannot truncate shared memory\n");
+ }
+ api_cmd = mmap (NULL, sizeof (api_cmd_t), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+ if (api_cmd == MAP_FAILED) {
+ err ("MMap of shared memory region failed\n");
+ }
+ close (fd);
+
+ memset (api_cmd, 0, sizeof (api_cmd_t));
+
+ pthread_create (&api_cmd_loop_thread, NULL, api_cmd_loop, NULL);
+ return 0;
+}
+
+void api_shm_exit (void)
+{
+ if(pthread_exist(api_cmd_loop_thread) && !pthread_cancel (api_cmd_loop_thread)) {
+ pthread_join (api_cmd_loop_thread, NULL);
+ }
+ shm_unlink (API_SHM_NAMESPACE);
+}
+#endif
+#ifdef API_WIN
+
+void *api_cmd_loop(void *lpvParam)
+{
+ netceiver_info_list_t *nc_list=nc_get_list();
+ tra_info_t *tra_list=tra_get_list();
+ api_cmd_t sock_cmd;
+ DWORD cbBytesRead, cbWritten;
+ BOOL fSuccess;
+ HANDLE hPipe;
+
+ hPipe = (HANDLE) lpvParam;
+
+ while (1) {
+ fSuccess = ReadFile(
+ hPipe, // handle to pipe
+ &sock_cmd, // buffer to receive data
+ sizeof(sock_cmd), // size of buffer
+ &cbBytesRead, // number of bytes read
+ NULL); // not overlapped I/O
+
+ if (! fSuccess || cbBytesRead == 0) {
+ break;
+ }
+
+ if (cbBytesRead == sizeof (api_cmd_t)) {
+ nc_lock_list();
+ process_cmd (&sock_cmd, tra_list, nc_list);
+ nc_unlock_list();
+
+ fSuccess = WriteFile(
+ hPipe, // handle to pipe
+ &sock_cmd, // buffer to write from
+ sizeof(sock_cmd), // number of bytes to write
+ &cbWritten, // number of bytes written
+ NULL); // not overlapped I/O
+
+ if (! fSuccess || sizeof(sock_cmd) != cbWritten) {
+ break;
+ }
+ } else {
+ sock_cmd.magic = MCLI_MAGIC;
+ sock_cmd.version = MCLI_VERSION;
+ sock_cmd.state = API_RESPONSE;
+ fSuccess = WriteFile(
+ hPipe, // handle to pipe
+ &sock_cmd, // buffer to write from
+ sizeof(sock_cmd), // number of bytes to write
+ &cbWritten, // number of bytes written
+ NULL); // not overlapped I/O
+
+ if (! fSuccess || sizeof(sock_cmd) != cbWritten) {
+ break;
+ }
+ break;
+ }
+ }
+
+ FlushFileBuffers(hPipe);
+ DisconnectNamedPipe(hPipe);
+ CloseHandle(hPipe);
+
+ return NULL;
+}
+
+#define BUFSIZE 2048
+void *api_listen_loop(void *p)
+{
+ BOOL fConnected;
+ pthread_t api_cmd_loop_thread;
+ HANDLE hPipe;
+ LPTSTR lpszPipename=(LPTSTR)p;
+
+ while(1) {
+ hPipe = CreateNamedPipe(
+ lpszPipename, // pipe name
+ PIPE_ACCESS_DUPLEX, // read/write access
+ PIPE_TYPE_MESSAGE | // message type pipe
+ PIPE_READMODE_MESSAGE | // message-read mode
+ PIPE_WAIT, // blocking mode
+ PIPE_UNLIMITED_INSTANCES, // max. instances
+ BUFSIZE, // output buffer size
+ BUFSIZE, // input buffer size
+ 0, // client time-out
+ NULL); // default security attribute
+
+ if (hPipe == INVALID_HANDLE_VALUE) {
+ err ("CreatePipe failed");
+ return NULL;
+ }
+ pthread_testcancel();
+ fConnected = ConnectNamedPipe(hPipe, NULL) ? TRUE : (GetLastError() == ERROR_PIPE_CONNECTED);
+
+ if (fConnected) {
+ if(pthread_create(&api_cmd_loop_thread, NULL, api_cmd_loop, hPipe)) {
+ err ("CreateThread failed");
+ return NULL;
+ } else {
+ pthread_detach(api_cmd_loop_thread);
+ }
+ }
+ else {
+ CloseHandle(hPipe);
+ }
+ }
+ return NULL;
+}
+
+pthread_t api_listen_loop_thread;
+
+int api_init (LPTSTR cmd_pipe_path)
+{
+ return pthread_create (&api_listen_loop_thread, NULL, api_listen_loop, cmd_pipe_path);
+}
+
+void api_exit (void)
+{
+ if(pthread_exist(api_listen_loop_thread) && !pthread_cancel (api_listen_loop_thread)) {
+ TerminateThread(pthread_getw32threadhandle_np(api_listen_loop_thread),0);
+ pthread_join (api_listen_loop_thread, NULL);
+ }
+}
+
+#endif
diff --git a/mcast/client/.svn/text-base/api_server.h.svn-base b/mcast/client/.svn/text-base/api_server.h.svn-base
new file mode 100644
index 0000000..e0f946f
--- /dev/null
+++ b/mcast/client/.svn/text-base/api_server.h.svn-base
@@ -0,0 +1,67 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ */
+
+#define API_SHM_NAMESPACE "/mcli"
+#define API_SOCK_NAMESPACE "/var/tmp/mcli.sock"
+
+typedef enum { API_IDLE,
+ API_REQUEST,
+ API_RESPONSE,
+ API_ERROR
+} api_state_t;
+
+typedef enum { API_GET_NC_NUM,
+ API_GET_NC_INFO,
+ API_GET_TUNER_INFO,
+ API_GET_SAT_LIST_INFO,
+ API_GET_SAT_INFO,
+ API_GET_SAT_COMP_INFO,
+ API_GET_TRA_NUM,
+ API_GET_TRA_INFO,
+ API_GET_DEVICE_INFO
+} api_cmdval_t;
+
+typedef enum { API_PARM_NC_NUM=0,
+ API_PARM_DEVICE_NUM=0,
+ API_PARM_TUNER_NUM,
+ API_PARM_SAT_LIST_NUM,
+ API_PARM_SAT_NUM,
+ API_PARM_SAT_COMP_NUM,
+ API_PARM_TRA_NUM,
+ API_PARM_MAX
+} api_parm_t;
+
+typedef struct {
+ int magic;
+ int version;
+
+ api_cmdval_t cmd;
+ api_state_t state;
+ int parm[API_PARM_MAX];
+ union {
+ netceiver_info_t nc_info;
+ tuner_info_t tuner_info;
+ satellite_list_t sat_list;
+ satellite_info_t sat_info;
+ satellite_component_t sat_comp;
+ tra_t tra;
+ } u;
+} api_cmd_t;
+
+#ifdef API_SHM
+DLL_SYMBOL int api_shm_init (void);
+DLL_SYMBOL void api_shm_exit (void);
+#endif
+#ifdef API_SOCK
+DLL_SYMBOL int api_sock_init (const char *cmd_sock_path);
+DLL_SYMBOL void api_sock_exit (void);
+#endif
+#ifdef API_WIN
+DLL_SYMBOL int api_init (LPTSTR cmd_pipe_path);
+DLL_SYMBOL void api_exit (void);
+#endif
diff --git a/mcast/client/.svn/text-base/api_shm_test.c.svn-base b/mcast/client/.svn/text-base/api_shm_test.c.svn-base
new file mode 100644
index 0000000..fa5a0e7
--- /dev/null
+++ b/mcast/client/.svn/text-base/api_shm_test.c.svn-base
@@ -0,0 +1 @@
+link api_test.c \ No newline at end of file
diff --git a/mcast/client/.svn/text-base/api_sock_test.c.svn-base b/mcast/client/.svn/text-base/api_sock_test.c.svn-base
new file mode 100644
index 0000000..fa5a0e7
--- /dev/null
+++ b/mcast/client/.svn/text-base/api_sock_test.c.svn-base
@@ -0,0 +1 @@
+link api_test.c \ No newline at end of file
diff --git a/mcast/client/.svn/text-base/api_test.c.svn-base b/mcast/client/.svn/text-base/api_test.c.svn-base
new file mode 100644
index 0000000..cfe6afd
--- /dev/null
+++ b/mcast/client/.svn/text-base/api_test.c.svn-base
@@ -0,0 +1,127 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ */
+
+#include "headers.h"
+
+
+int main (int argc, char **argv)
+{
+#ifdef USE_SHM_API
+ #define API_WAIT_RESPONSE(cmd) { cmd->state=API_REQUEST; while (cmd->state == API_REQUEST) usleep(10*1000); if (cmd->state == API_ERROR) warn ("SHM parameter error\n");}
+
+ int fd = shm_open (API_SHM_NAMESPACE, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
+ if (fd == -1 ) {
+ warn ("Cannot get a shared memory handle\n");
+ return -1;
+ }
+
+ if (ftruncate (fd, sizeof(api_cmd_t)) == -1) {
+ err ("Cannot truncate shared memory\n");
+ }
+
+ api_cmd_t *api_cmd = mmap(NULL, sizeof(api_cmd_t), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+ if ( api_cmd == MAP_FAILED ) {
+ err ("MMap of shared memory region failed\n");
+ }
+ close(fd);
+#endif
+#ifdef USE_SOCK_API
+ #define API_WAIT_RESPONSE(cmd) { cmd->state=API_REQUEST; send (sock_comm, &sock_cmd, sizeof(api_cmd_t), 0); recv (sock_comm, &sock_cmd, sizeof(api_cmd_t), 0); if (cmd->state == API_ERROR) warn ("SHM parameter error\n");}
+
+ int sock_comm;
+ int sock_name_len = 0;
+ struct sockaddr_un sock_name;
+ api_cmd_t sock_cmd;
+ api_cmd_t *api_cmd=&sock_cmd;
+ sock_name.sun_family = AF_UNIX;
+
+ strcpy(sock_name.sun_path, API_SOCK_NAMESPACE);
+ sock_name_len = strlen(API_SOCK_NAMESPACE) + sizeof(sock_name.sun_family);
+
+ if((sock_comm = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
+ {
+ warn ("socket create failure %d\n", errno);
+ return -1;
+ }
+
+ if (connect(sock_comm, &sock_name, sock_name_len) < 0) {
+ err ("connect failure\n");
+ }
+#endif
+ api_cmd->cmd=API_GET_NC_NUM;
+ API_WAIT_RESPONSE(api_cmd);
+
+ printf("nc_num: %d\n", api_cmd->parm[API_PARM_NC_NUM]);
+ int nc_num=api_cmd->parm[API_PARM_NC_NUM];
+ int i;
+ for(i=0;i<nc_num;i++) {
+ api_cmd->cmd=API_GET_NC_INFO;
+ api_cmd->parm[API_PARM_NC_NUM]=i;
+ API_WAIT_RESPONSE(api_cmd);
+ printf("nc_info.uuid: %s nc_info.lastseen: %u nc_info.tuner_num: %d\n", api_cmd->u.nc_info.uuid, (unsigned int) api_cmd->u.nc_info.lastseen, api_cmd->u.nc_info.tuner_num);
+ int j;
+ int tuner_num=api_cmd->u.nc_info.tuner_num;
+ for(j=0;j<tuner_num;j++) {
+ api_cmd->cmd=API_GET_TUNER_INFO;
+ api_cmd->parm[API_PARM_TUNER_NUM]=j;
+ API_WAIT_RESPONSE(api_cmd);
+ printf("tuner_info.fe_info.name: %s SatList: %s\n",api_cmd->u.tuner_info.fe_info.name, api_cmd->u.tuner_info.SatelliteListName);
+ }
+
+
+ int sat_list_num=api_cmd->u.nc_info.sat_list_num;
+ for(j=0;j<sat_list_num;j++) {
+ api_cmd->cmd=API_GET_SAT_LIST_INFO;
+ api_cmd->parm[API_PARM_NC_NUM]=i;
+ api_cmd->parm[API_PARM_SAT_LIST_NUM]=j;
+ API_WAIT_RESPONSE(api_cmd);
+
+ printf("sat_list_info.Name: %s sat_list_info.sat_num: %d\n", api_cmd->u.sat_list.Name, api_cmd->u.sat_list.sat_num);
+
+ int sat_num=api_cmd->u.sat_list.sat_num;
+ int k;
+ for(k=0;k<sat_num;k++) {
+ api_cmd->cmd=API_GET_SAT_INFO;
+ api_cmd->parm[API_PARM_SAT_LIST_NUM]=j;
+ api_cmd->parm[API_PARM_SAT_NUM]=k;
+ API_WAIT_RESPONSE(api_cmd);
+ printf("sat_info.Name: %s\n",api_cmd->u.sat_info.Name);
+ int comp_num=api_cmd->u.sat_info.comp_num;
+ int l;
+ for(l=0;l<comp_num;l++) {
+ api_cmd->cmd=API_GET_SAT_COMP_INFO;
+ api_cmd->parm[API_PARM_SAT_LIST_NUM]=j;
+ api_cmd->parm[API_PARM_SAT_NUM]=k;
+ api_cmd->parm[API_PARM_SAT_COMP_NUM]=l;
+ API_WAIT_RESPONSE(api_cmd);
+ printf("sat_comp.Polarisation: %d sat_comp.RangeMin: %d sat_comp.RangeMax: %d sat_comp.LOF: %d\n", api_cmd->u.sat_comp.Polarisation, api_cmd->u.sat_comp.RangeMin, api_cmd->u.sat_comp.RangeMax, api_cmd->u.sat_comp.LOF);
+ }
+ }
+ }
+ }
+
+ while (1) {
+ api_cmd->cmd=API_GET_TRA_NUM;
+ API_WAIT_RESPONSE(api_cmd);
+
+ printf("tra_num: %d\n", api_cmd->parm[API_PARM_TRA_NUM]);
+ int tra_num=api_cmd->parm[API_PARM_TRA_NUM];
+ for(i=0;i<tra_num;i++) {
+ api_cmd->cmd=API_GET_TRA_INFO;
+ api_cmd->parm[API_PARM_TRA_NUM]=i;
+ API_WAIT_RESPONSE(api_cmd);
+ char host[INET6_ADDRSTRLEN];
+ inet_ntop (AF_INET6, &api_cmd->u.tra.mcg, (char *) host, INET6_ADDRSTRLEN);
+
+ printf("tra.slot:%d tra.fe_type: %d tra.InUse: % 3d tra.mcg: %s tra.uuid: %s tra.lastseen: %u tra.lock:%d tra.strength:%d tra.snr:%d tra.ber:%d\n", api_cmd->u.tra.slot, api_cmd->u.tra.fe_type, api_cmd->u.tra.InUse, host, api_cmd->u.tra.uuid, (unsigned int) api_cmd->u.tra.lastseen, api_cmd->u.tra.s.st, api_cmd->u.tra.s.strength, api_cmd->u.tra.s.snr, api_cmd->u.tra.s.ber);
+ }
+ sleep(2);
+ }
+ return 0;
+}
+
diff --git a/mcast/client/.svn/text-base/ci_handler.c.svn-base b/mcast/client/.svn/text-base/ci_handler.c.svn-base
new file mode 100644
index 0000000..beef8ff
--- /dev/null
+++ b/mcast/client/.svn/text-base/ci_handler.c.svn-base
@@ -0,0 +1,321 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ */
+
+#include "headers.h"
+
+//#define SHOW_TPDU
+
+static ci_dev_t devs;
+static int dev_num = 0;
+static int ci_run = 0;
+static pthread_t ci_handler_thread;
+static int port = 23000;
+static char iface[IFNAMSIZ];
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+static int ci_connect (ci_dev_t * c)
+{
+ int ret;
+ int j;
+ struct in6_addr nc;
+
+ if (c->connected) {
+ return 0;
+ }
+
+ if (c->fd_ci) {
+ closesocket (c->fd_ci);
+ }
+
+ c->fd_ci = socket (PF_INET6, SOCK_STREAM, 0);
+ j = 1;
+ if (setsockopt (c->fd_ci, SOL_SOCKET, SO_REUSEADDR, (_SOTYPE) & j, sizeof (j)) < 0) {
+ warn ("setsockopt REUSEADDR\n");
+ }
+
+ j = 1;
+ if (setsockopt (c->fd_ci, SOL_SOCKET, TCP_NODELAY, (_SOTYPE) & j, sizeof (j)) < 0) {
+ warn ("setsockopt TCP_NODELAY\n");
+ }
+
+ inet_pton (AF_INET6, c->uuid, &nc);
+#ifdef SHOW_TPDU
+ char host[INET6_ADDRSTRLEN];
+ inet_ntop (AF_INET6, &nc, (char *) host, INET6_ADDRSTRLEN);
+ info ("Connect To: %s\n", host);
+#endif
+ struct sockaddr_in6 addr;
+ memset (&addr, 0, sizeof (struct sockaddr_in6));
+
+ addr.sin6_family = AF_INET6;
+ addr.sin6_port = htons (port);
+ addr.sin6_addr = nc;
+ addr.sin6_scope_id = if_nametoindex (iface);
+
+ ret = connect (c->fd_ci, (struct sockaddr *) &addr, sizeof (struct sockaddr_in6));
+ if (ret < 0) {
+ warn ("Failed to access NetCeiver CA support\n");
+ } else {
+ c->connected = 1;
+ }
+ return ret;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+int ci_write_pdu (ci_dev_t * c, ci_pdu_t * tpdu)
+{
+ int ret = -1;
+
+ dbg ("ci_write_pdu: %p %d\n", tpdu->data, tpdu->len);
+
+ ci_decode_ll (tpdu->data, tpdu->len);
+ memcpy (c->txdata + 2, tpdu->data, tpdu->len);
+ c->txdata[0] = tpdu->len >> 8;
+ c->txdata[1] = tpdu->len & 0xff;
+ if (!ci_connect (c)) {
+#ifdef SHOW_TPDU
+ int j;
+ info ("Send TPDU: ");
+ for (j = 0; j < tpdu->len; j++) {
+ info ("%02x ", tpdu->data[j]);
+ }
+ info ("\n");
+#endif
+ ret = send (c->fd_ci, (char *) c->txdata, tpdu->len + 2, 0);
+ if (ret < 0) {
+ c->connected = 0;
+ }
+ }
+ return ret;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+static void clean_ci_recv_thread (void *argp)
+{
+ ci_dev_t *c = (ci_dev_t *) argp;
+ if (c->txdata) {
+ free (c->txdata);
+ }
+ if (c->rxdata) {
+ free (c->rxdata);
+ }
+ closesocket (c->fd_ci);
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+static void *ci_recv (void *argp)
+{
+ ci_dev_t *c = (ci_dev_t *) argp;
+ ci_pdu_t tpdu;
+ int ret = -1;
+
+ pthread_cleanup_push (clean_ci_recv_thread, c);
+
+ c->rxdata = (u_int8_t *) malloc (CA_TPDU_MAX + 2);
+ if (!c->rxdata)
+ err ("ci_recv: out of memory\n");
+ c->txdata = (u_int8_t *) malloc (CA_TPDU_MAX + 2);
+ if (!c->txdata)
+ err ("ci_recv: out of memory\n");
+
+ if (c->rxdata && c->txdata) {
+ c->recv_run = 1;
+
+ while (c->recv_run) {
+ if (c->connected) {
+ ret = recv (c->fd_ci, (char *) c->rxdata, CA_TPDU_MAX + 2, 0);
+ if (ret > 0) {
+ tpdu.data = c->rxdata;
+ while (ret > 0) {
+ tpdu.len = ntohs16 (tpdu.data);
+ if (tpdu.len >= ret) {
+ break;
+ }
+ tpdu.data += 2;
+#ifdef SHOW_TPDU
+ int j;
+ info ("Received TPDU: ");
+ for (j = 0; j < tpdu.len; j++) {
+ info ("%02x ", tpdu.data[j]);
+ }
+ info ("\n");
+#endif
+ ci_decode_ll (tpdu.data, tpdu.len);
+ unsigned int slot = (unsigned int) tpdu.data[0];
+ if (slot < CA_MAX_SLOTS) {
+ if (c->handle_ci_slot[slot]) {
+ c->handle_ci_slot[slot] (&tpdu, c->handle_ci_slot_context[slot]);
+ }
+ }
+
+ tpdu.data += tpdu.len;
+ ret -= tpdu.len + 2;
+ }
+ } else {
+ if (errno == EAGAIN) {
+ ret = 0;
+ } else {
+ c->connected = 0;
+ }
+ }
+ }
+ usleep (10 * 1000);
+ }
+ }
+ pthread_cleanup_pop (1);
+
+ return NULL;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+int ci_register_handler (ci_dev_t * c, int slot, int (*p) (ci_pdu_t *, void *), void *context)
+{
+ if (slot < CA_MAX_SLOTS) {
+ c->handle_ci_slot[slot] = p;
+ c->handle_ci_slot_context[slot] = context;
+ return 0;
+ }
+ return -1;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+int ci_unregister_handler (ci_dev_t * c, int slot)
+{
+ if (slot < CA_MAX_SLOTS) {
+ c->handle_ci_slot[slot] = NULL;
+ c->handle_ci_slot_context[slot] = NULL;
+ return 0;
+ }
+ return -1;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+static ci_dev_t *ci_add (void)
+{
+ ci_dev_t *c = (ci_dev_t *) malloc (sizeof (ci_dev_t));
+ if (!c)
+ return NULL;
+ memset (c, 0, sizeof (ci_dev_t));
+ dvbmc_list_add_head (&devs.list, &c->list);
+ return c;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+static void ci_del (ci_dev_t * c)
+{
+ c->recv_run = 0;
+ if (pthread_exist(c->ci_recv_thread) && !pthread_cancel (c->ci_recv_thread)) {
+ pthread_join (c->ci_recv_thread, NULL);
+ }
+ dvbmc_list_remove (&c->list);
+ free (c);
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+
+ci_dev_t *ci_find_dev_by_uuid (char *uuid)
+{
+ ci_dev_t *c;
+ DVBMC_LIST_FOR_EACH_ENTRY (c, &devs.list, ci_dev_t, list) {
+ if (!strcmp (c->uuid, uuid)) {
+ return c;
+ }
+ }
+ return NULL;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+static void *ci_handler (void *p)
+{
+ int n;
+ netceiver_info_list_t *nc_list = nc_get_list ();
+ ci_run = 1;
+ while (ci_run) {
+ nc_lock_list ();
+ for (n = 0; n < nc_list->nci_num; n++) {
+ netceiver_info_t *nci = nc_list->nci + n;
+ char *uuid = nci->uuid;
+ if (!strlen (uuid) || ci_find_dev_by_uuid (uuid)) {
+ //already seen
+ continue;
+ }
+
+ ci_dev_t *c = ci_add ();
+ if (!c) {
+ err ("Cannot get memory for dvb loopback context\n");
+ }
+
+ dbg ("allocate ci dev %d for uuid %s\n", dev_num, uuid);
+
+ strcpy (c->uuid, uuid);
+ c->cacaps = &nci->ci;
+ c->device = dev_num++;
+
+ info ("Starting ci thread for netceiver UUID %s\n", c->uuid);
+ int ret = pthread_create (&c->ci_recv_thread, NULL, ci_recv, c);
+ while (!ret && !c->recv_run) {
+ usleep (10000);
+ }
+ if (ret) {
+ err ("pthread_create failed with %d\n", ret);
+ }
+ }
+ nc_unlock_list ();
+ sleep (1);
+ }
+ return NULL;
+}
+
+int ci_init (int ca_enable, char *intf, int p)
+{
+ int ret = 0;
+ if (intf) {
+ strcpy (iface, intf);
+ } else {
+ iface[0] = 0;
+ }
+ if (p) {
+ port = p;
+ }
+
+ dvbmc_list_init (&devs.list);
+ if (ca_enable) {
+ ret = pthread_create (&ci_handler_thread, NULL, ci_handler, NULL);
+ while (!ret && !ci_run) {
+ usleep (10000);
+ }
+ }
+ return ret;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+void ci_exit (void)
+{
+ ci_dev_t *c;
+ ci_dev_t *ctmp;
+ if (pthread_exist (ci_handler_thread)) {
+ if (pthread_exist(ci_handler_thread) && !pthread_cancel (ci_handler_thread)) {
+ pthread_join (ci_handler_thread, NULL);
+ }
+
+ DVBMC_LIST_FOR_EACH_ENTRY_SAFE (c, ctmp, &devs.list, ci_dev_t, list) {
+ ci_del (c);
+ }
+ }
+}
diff --git a/mcast/client/.svn/text-base/ci_handler.h.svn-base b/mcast/client/.svn/text-base/ci_handler.h.svn-base
new file mode 100644
index 0000000..3ecfc02
--- /dev/null
+++ b/mcast/client/.svn/text-base/ci_handler.h.svn-base
@@ -0,0 +1,30 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ */
+
+typedef struct {
+ struct list list;
+
+ pthread_t ci_recv_thread;
+ char uuid[UUID_SIZE];
+ SOCKET fd_ci;
+ int recv_run;
+ int device;
+ int connected;
+ recv_cacaps_t *cacaps;
+ u_int8_t *txdata;
+ u_int8_t *rxdata;
+ int (*handle_ci_slot[CA_MAX_SLOTS]) (ci_pdu_t *tpdu, void *context);
+ void *handle_ci_slot_context[CA_MAX_SLOTS];
+} ci_dev_t;
+
+DLL_SYMBOL int ci_register_handler(ci_dev_t *c, int slot, int (*p) (ci_pdu_t *, void *), void *context);
+DLL_SYMBOL int ci_unregister_handler(ci_dev_t *c, int slot);
+DLL_SYMBOL int ci_write_pdu(ci_dev_t *c, ci_pdu_t *tpdu);
+DLL_SYMBOL ci_dev_t *ci_find_dev_by_uuid (char *uuid);
+DLL_SYMBOL int ci_init (int ca_enable, char *intf, int p);
+DLL_SYMBOL void ci_exit (void);
diff --git a/mcast/client/.svn/text-base/ciparser.c.svn-base b/mcast/client/.svn/text-base/ciparser.c.svn-base
new file mode 100644
index 0000000..0a2c0bf
--- /dev/null
+++ b/mcast/client/.svn/text-base/ciparser.c.svn-base
@@ -0,0 +1 @@
+link ../common/ciparser.c \ No newline at end of file
diff --git a/mcast/client/.svn/text-base/dummy_client.c.svn-base b/mcast/client/.svn/text-base/dummy_client.c.svn-base
new file mode 100644
index 0000000..2a397d9
--- /dev/null
+++ b/mcast/client/.svn/text-base/dummy_client.c.svn-base
@@ -0,0 +1,101 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ */
+
+#define DEBUG 1
+#include "headers.h"
+
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+static int dummy_handle_ts (unsigned char *buffer, size_t len, void *p)
+{
+ FILE *f=(FILE*)p;
+ fwrite(buffer, len, 1, f);
+ return len;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+static int dummy_handle_ten (tra_t *ten, void *p)
+{
+ FILE *f=(FILE*)p;
+ if(ten) {
+ fprintf(f,"Status: %02X, Strength: %04X, SNR: %04X, BER: %04X\n",ten->s.st,ten->s.strength, ten->s.snr, ten->s.ber);
+ }
+ return 0;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+void dummy_client (void)
+{
+ int i;
+ int n;
+ int run=1;
+ FILE *f;
+ recv_info_t *r;
+ recv_sec_t sec;
+ struct dvb_frontend_parameters fep;
+ dvb_pid_t pids[3];
+
+ netceiver_info_list_t *nc_list=nc_get_list();
+#if 0
+ printf("Looking for netceivers out there....\n");
+ while(run) {
+ nc_lock_list();
+ for (n = 0; n < nc_list->nci_num; n++) {
+ netceiver_info_t *nci = nc_list->nci + n;
+ printf("\nFound NetCeiver: %s\n",nci->uuid);
+ for (i = 0; i < nci->tuner_num; i++) {
+ printf(" Tuner: %s, Type %d\n",nci->tuner[i].fe_info.name, nci->tuner[i].fe_info.type);
+ }
+ }
+ nc_unlock_list();
+ if(nc_list->nci_num) {
+ break;
+ }
+ sleep(1);
+ }
+#endif
+ f=fopen("out.ts","wb");
+
+ r = recv_add();
+ if (!r) {
+ fprintf (stderr, "Cannot get memory for receiver\n");
+ return;
+ }
+ register_ten_handler (r, dummy_handle_ten, stderr);
+ register_ts_handler (r, dummy_handle_ts, f);
+
+ memset(&sec, 0, sizeof(recv_sec_t));
+ sec.voltage=SEC_VOLTAGE_18;
+ sec.mini_cmd=SEC_MINI_A;
+ sec.tone_mode=SEC_TONE_ON;
+
+ memset(&fep, 0, sizeof(struct dvb_frontend_parameters));
+ fep.frequency=12544000;
+ fep.inversion=INVERSION_AUTO;
+ fep.u.qpsk.symbol_rate=22000000;
+ fep.u.qpsk.fec_inner=FEC_5_6;
+
+ memset(&pids, 0, sizeof(pids));
+ pids[0].pid=511;
+ pids[1].pid=512;
+ pids[2].pid=511;
+ pids[2].id=2;
+ pids[3].pid=511;
+ pids[3].id=1;
+ pids[4].pid=-1;
+
+ printf("\nTuning a station and writing transport data to file 'out.ts':\n");
+ recv_tune (r, (fe_type_t)FE_QPSK, 1800+192, &sec, &fep, pids);
+ getchar();
+ register_ten_handler (r, NULL, NULL);
+ register_ts_handler (r, NULL, NULL);
+ fclose(f);
+}
diff --git a/mcast/client/.svn/text-base/dummy_client.h.svn-base b/mcast/client/.svn/text-base/dummy_client.h.svn-base
new file mode 100644
index 0000000..e79cbf1
--- /dev/null
+++ b/mcast/client/.svn/text-base/dummy_client.h.svn-base
@@ -0,0 +1,10 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ */
+
+void dummy_client (void);
+
diff --git a/mcast/client/.svn/text-base/dvblo_handler.c.svn-base b/mcast/client/.svn/text-base/dvblo_handler.c.svn-base
new file mode 100644
index 0000000..875749d
--- /dev/null
+++ b/mcast/client/.svn/text-base/dvblo_handler.c.svn-base
@@ -0,0 +1,716 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ */
+
+#include "headers.h"
+#include "dvblo_ioctl.h"
+#include "dvblo_handler.h"
+
+//#define SHOW_EVENTS
+//#define SHOW_TPDU
+//#define SHOW_PIDS
+
+#define TUNE_FORCED_TIMEOUT 5
+
+extern pthread_mutex_t lock;
+extern recv_info_t receivers;
+
+static dvblo_dev_t devs;
+static int dev_num = 0;
+static int dvblo_run = 1;
+static int cidev = 0;
+static int reload = 0;
+static dvblo_cacaps_t cacaps;
+
+static int special_status_mode=0; // 1: return rotor mode and tuner slot in status
+
+static int dvblo_get_nc_addr (char *addrstr, char *uuid)
+{
+ int len = strlen (uuid);
+ if (len <= 5) {
+ return -1;
+ }
+ memset (addrstr, 0, INET6_ADDRSTRLEN);
+
+ strncpy (addrstr, uuid, len - 5);
+ return 0;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+static int dvblo_handle_ts (unsigned char *buffer, size_t len, void *p)
+{
+ dvblo_dev_t * d=( dvblo_dev_t *)p;
+ return write (d->fd, buffer, len);
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+static int dvblo_handle_ten (tra_t * ten, void *c)
+{
+ dvblo_dev_t *d = (dvblo_dev_t *) c;
+ dbg ("TEN: %ld %p %p\n", gettid (), ten, d);
+
+ if (ten) {
+ dvblo_festatus_t stat;
+ memcpy(&stat, &ten->s, sizeof(dvblo_festatus_t));
+
+ d->ten = *ten;
+
+ if (special_status_mode) {
+ stat.st|=(ten->rotor_status&3)<<8;
+ stat.st|=(1+ten->slot)<<12;
+ }
+
+ return ioctl (d->fd, DVBLO_SET_FRONTEND_STATUS, (dvblo_festatus_t*)&stat);
+ } else {
+ dvblo_festatus_t s;
+ memset (&s, 0, sizeof (dvblo_festatus_t));
+
+ return ioctl (d->fd, DVBLO_SET_FRONTEND_STATUS, &s);
+ }
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+static void sig_handler (int signal)
+{
+ dbg ("Signal: %d\n", signal);
+
+ switch (signal) {
+ case SIGHUP:
+ reload = 1;
+ break;
+ case SIGTERM:
+ case SIGINT:
+ dbg ("Trying to exit, got signal %d...\n", signal);
+ dvblo_run = 0;
+ break;
+ }
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+int dvblo_init (void)
+{
+ char char_dev[100];
+ int j, k = 0;
+ struct dvb_frontend_info fe_info;
+ dvblo_festatus_t fe_status;
+
+ dvbmc_list_init (&devs.list);
+
+ memset (&fe_info, 0, sizeof (struct dvb_frontend_info));
+ fe_info.type = -1;
+ strcpy (fe_info.name, "Unconfigured");
+ memset (&fe_status, 0, sizeof (dvblo_festatus_t));
+
+ for (j = 0; j < MAX_DEVICES; j++) {
+
+ sprintf (char_dev, "/dev/dvblo%d", j);
+ int fd = open (char_dev, O_RDWR);
+
+ if (fd == -1) {
+ warn ("Cannot Open %s\n", char_dev);
+ continue;
+ }
+ k++;
+ ioctl (fd, DVBLO_SET_FRONTEND_INFO, &fe_info);
+ ioctl (fd, DVBLO_SET_FRONTEND_STATUS, &fe_status);
+ ioctl (fd, DVBLO_SET_CA_CAPS, &cacaps);
+ dvblo_tpdu_t tpdu;
+ while (1) {
+ if (ioctl (fd, DVBLO_GET_TPDU, &tpdu) || !tpdu.len) {
+ break;
+ }
+ }
+ close (fd);
+ }
+
+ signal (SIGTERM, &sig_handler);
+ signal (SIGINT, &sig_handler);
+ signal (SIGHUP, &sig_handler);
+ signal (SIGPIPE, &sig_handler);
+ return k;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+static int dvblo_convert_pids (dvblo_dev_t * d)
+{
+ dvb_pid_t *dst = d->dstpids;
+ dvblo_pids_t *src = &d->pids;
+ int i;
+#ifdef SHOW_PIDS
+ info ("devnum:%d pidnum:%d\n", d->device, src->num);
+#endif
+ for (i = 0; i < src->num; i++) {
+#ifdef SHOW_PIDS
+ printf ("devnum:%d pid:%04x\n", d->device, src->pid[i]);
+#endif
+ dst[i].pid = src->pid[i];
+ if (d->ca_enable) {
+ dst[i].id = ci_cpl_find_caid_by_pid (src->pid[i]);
+ if (dst[i].id != 0) {
+ dbg ("pid: %04x id: %04x\n", dst[i].pid, dst[i].id);
+ }
+ }
+ }
+ dst[i].pid = -1;
+ return i;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+static int dvblo_tune (dvblo_dev_t * d, int force)
+{
+ satellite_reference_t satref;
+ int SatPos;
+ int mode;
+ int ret = 0;
+
+ nc_lock_list ();
+
+ for (mode = 0; mode < 3; mode++) {
+ if (satellite_find_by_diseqc (&satref, (recv_sec_t*)&d->sec, &d->fe_parms, mode))
+ break;
+ }
+
+ if (mode == 3 || (mode == 2 && (d->type == FE_QAM || d->type == FE_OFDM))) {
+ SatPos = NO_SAT_POS;
+ } else {
+ int LOF = 0;
+ if (mode) {
+ LOF = satellite_get_lof_by_ref (&satref);
+ d->fe_parms.frequency += LOF * 1000;
+ }
+ SatPos = satellite_get_pos_by_ref (&satref);
+ recv_sec_t *sec=satellite_find_sec_by_ref (&satref);
+ memcpy(&d->sec, sec, sizeof(recv_sec_t));
+ d->sec.voltage = satellite_find_pol_by_ref (&satref);
+#if 1 //def SHOW_EVENTS
+ printf ("Found satellite position: %d fe_parms: %d LOF: %d voltage: %d mode: %d\n", SatPos, d->fe_parms.frequency, LOF, d->sec.voltage, mode);
+#endif
+ }
+ nc_unlock_list ();
+ if (force && d->pids.num == 0) {
+ d->dstpids[0].pid = 0;
+ d->dstpids[0].id = 0;
+ d->dstpids[1].pid = -1;
+ ret = 2;
+ } else {
+ dvblo_convert_pids (d);
+ }
+ recv_tune (d->r, d->type, SatPos, (recv_sec_t*)&d->sec, &d->fe_parms, d->dstpids);
+ return ret;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+int dvblo_write_ci (ci_pdu_t * pdu, void *context)
+{
+ dvblo_dev_t *d = (dvblo_dev_t *) context;
+ dvblo_tpdu_t tpdu;
+ memcpy (tpdu.data, pdu->data, pdu->len);
+ tpdu.len = pdu->len;
+ if (!cmd.reelcammode)
+ tpdu.data[0] = 0;
+ return ioctl (d->fd, DVBLO_SET_TPDU, &tpdu);
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+static void clean_dvblo_recv_thread (void *argp)
+{
+ dvblo_dev_t *d = (dvblo_dev_t *) argp;
+ recv_del (d->r);
+ close (d->fd);
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+static void *dvblo_recv (void *argp)
+{
+ dvblo_dev_t *d = (dvblo_dev_t *) argp;
+ dvblo_tpdu_t tpdu;
+ struct dvb_frontend_parameters old_fe_parms;
+ dvblo_sec_t old_sec;
+ struct pollfd fds[1];
+ int timeout_msecs = 50;
+ int ret;
+ time_t last_ci_reset = 0;
+ char char_dev[100];
+ int need_tune = 0;
+ time_t forced = 0;
+ unsigned int event = 0;
+
+ dvblo_cacaps_t cacap;
+
+ sprintf (char_dev, "/dev/dvblo%d", d->device);
+ dbg ("Using character device %s for dvb loopback\n", char_dev);
+
+ d->fd = open (char_dev, O_RDWR);
+
+ if (d->fd < 0) {
+ err ("Cannot open %s - dvbloop driver loaded?\n", char_dev);
+ }
+
+ pthread_cleanup_push (clean_dvblo_recv_thread, d);
+
+ fds[0].fd = d->fd;
+
+ if (!ioctl (d->fd, DVBLO_IOCCHECKDEV)) {
+ if (!ioctl (d->fd, DVBLO_IOCADDDEV)) {
+ info ("created dvb adapter: %d\n", d->device);
+ }
+ }
+ d->info.frequency_min = 1;
+ d->info.frequency_max = 2000000000;
+
+ ioctl (d->fd, DVBLO_SET_FRONTEND_INFO, &d->info);
+ ioctl (d->fd, DVBLO_GET_FRONTEND_PARAMETERS, &d->fe_parms);
+ ioctl (d->fd, DVBLO_GET_PIDLIST, &d->pids);
+ ioctl (d->fd, DVBLO_GET_SEC_PARAMETERS, &d->sec);
+
+ old_fe_parms = d->fe_parms;
+ old_sec = d->sec;
+#ifdef DEBUG
+ print_fe_info (&d->info);
+#endif
+ d->recv_run = 1;
+
+ if (dvblo_tune (d, 1) == 2) {
+ forced = time (NULL);
+ }
+
+ while (d->recv_run) {
+ if (d->cacaps->cap.slot_num) {
+ nc_lock_list ();
+#ifdef SHOW_TPDU
+ info ("ca_caps->: %p ci_slot:%d info[0]:%02x info[1]:%02x\n", d->cacaps, d->ci_slot, d->cacaps->info[0].flags, d->cacaps->info[1].flags);
+#endif
+ cacap = *d->cacaps;
+ if (!cmd.reelcammode) {
+ if (d->ci_slot != 0) {
+ cacap.info[0] = cacap.info[d->ci_slot];
+ }
+ cacap.cap.slot_num = 1;
+ }
+ if ((time (NULL) - last_ci_reset) < cmd.ci_timeout) {
+ cacap.info[0].flags = 0;
+ }
+ ioctl (d->fd, DVBLO_SET_CA_CAPS, &cacap);
+ nc_unlock_list ();
+ }
+
+ fds[0].events = POLLIN;
+ ret = poll (fds, 1, timeout_msecs);
+ if (ret > 0) {
+ ioctl (d->fd, DVBLO_GET_EVENT_MASK, &event);
+ ioctl (d->fd, DVBLO_GET_FRONTEND_PARAMETERS, &d->fe_parms);
+ ioctl (d->fd, DVBLO_GET_PIDLIST, &d->pids);
+ ioctl (d->fd, DVBLO_GET_SEC_PARAMETERS, &d->sec);
+ if (event & EV_MASK_FE) {
+#ifdef SHOW_EVENTS
+ printf ("%p/%p Event Received: FE+Tuner/", d, d->r);
+ if (event & EV_FRONTEND) {
+ printf ("Frontend ");
+ }
+ if (event & EV_TUNER) {
+ printf ("Tuner ");
+ }
+ if (event & EV_FREQUENCY) {
+ printf ("Frequency:%d ", d->fe_parms.frequency);
+ }
+ if (event & EV_BANDWIDTH) {
+ printf ("Bandwidth ");
+ }
+ printf ("\n");
+#endif
+ if (memcmp (&d->fe_parms, &old_fe_parms, sizeof (struct dvb_frontend_parameters))) {
+ old_fe_parms = d->fe_parms;
+ dbg ("fe_parms have changed!\n");
+ need_tune = 1;
+ if (d->ca_enable) {
+ ci_cpl_clear (d->ci_slot);
+ }
+ }
+ }
+ if (event & EV_MASK_SEC) {
+#ifdef SHOW_EVENTS
+ printf ("%p/%p Event Received: SEC/", d, d->r);
+ if (event & EV_TONE) {
+ printf ("Tone:%d ", d->sec.tone_mode);
+ }
+ if (event & EV_VOLTAGE) {
+ printf ("Voltage:%d ", d->sec.voltage);
+ }
+ if (event & EV_DISEC_MSG) {
+ printf ("DISEC-Message:");
+ int j;
+ for (j = 0; j < d->sec.diseqc_cmd.msg_len; j++) {
+ printf ("%02x ", d->sec.diseqc_cmd.msg[j]);
+ }
+ }
+ if (event & EV_DISEC_BURST) {
+ printf ("DISEC-Burst:%d ", d->sec.mini_cmd);
+ }
+ printf ("\n");
+#endif
+ if (d->sec.voltage == SEC_VOLTAGE_OFF) {
+ recv_stop (d->r);
+ memset (&old_fe_parms, 0, sizeof (struct dvb_frontend_parameters));
+ need_tune = 0;
+ dbg ("Stop %p\n", d->r);
+ } else if (memcmp (&d->sec, &old_sec, sizeof (dvblo_sec_t))) {
+ dbg ("SEC parms have changed!\n");
+ old_sec = d->sec;
+ need_tune = 1;
+ if (d->ca_enable) {
+ ci_cpl_clear (d->ci_slot);
+ }
+ }
+ }
+ if (event & EV_MASK_CA) {
+#ifdef SHOW_EVENTS
+ printf ("%p/%p Event Received: CA/", d, d->r);
+#endif
+ if (event & EV_CA_WRITE) {
+#ifdef SHOW_EVENTS
+ printf ("WRITE ");
+#endif
+ while (1) {
+ if (!ioctl (d->fd, DVBLO_GET_TPDU, &tpdu) && tpdu.len) {
+ if (d->c && d->ca_enable) {
+ ci_pdu_t pdu;
+ pdu.len = tpdu.len;
+ pdu.data = tpdu.data;
+ if (!cmd.reelcammode) {
+ pdu.data[0] = d->ci_slot;
+ }
+ ci_write_pdu (d->c, &pdu);
+ event |= EV_PIDFILTER;
+ }
+ } else {
+ break;
+ }
+ }
+ }
+ if (event & EV_CA_RESET) {
+#ifdef SHOW_EVENTS
+ printf ("RESET ");
+#endif
+ last_ci_reset = time (NULL);
+ if (d->ca_enable) {
+ ci_cpl_clear (d->ci_slot);
+ }
+ }
+#ifdef SHOW_EVENTS
+ printf ("\n");
+#endif
+ }
+ if (need_tune) {
+ if (dvblo_tune (d, 1) == 2) {
+ forced = time (NULL);
+ }
+ need_tune = 0;
+ } else if (event & EV_MASK_PID) {
+#ifdef SHOW_EVENTS
+ printf ("%p/%p Event Received: Demux/", d, d->r);
+ if (event & EV_PIDFILTER) {
+ printf ("PID filter: %d pids", d->pids.num);
+ }
+ printf ("\n");
+#endif
+ forced = 0;
+ }
+ }
+ if (forced) {
+ if ((time (NULL) - forced) < TUNE_FORCED_TIMEOUT) {
+ event &= ~EV_PIDFILTER;
+ } else {
+ event |= EV_PIDFILTER;
+ forced = 0;
+ }
+ }
+ if (event & EV_PIDFILTER) {
+ dvblo_convert_pids (d);
+ recv_pids (d->r, d->dstpids);
+ }
+ event = 0;
+ }
+ pthread_cleanup_pop (1);
+ return NULL;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+static dvblo_dev_t *dvblo_add (void)
+{
+ dvblo_dev_t *d = (dvblo_dev_t *) malloc (sizeof (dvblo_dev_t));
+
+ if (!d)
+ return NULL;
+ memset (d, 0, sizeof (dvblo_dev_t));
+ dvbmc_list_add_head (&devs.list, &d->list);
+ return d;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+static void dvblo_del (dvblo_dev_t * d)
+{
+ d->recv_run = 0;
+ if (pthread_exist(d->dvblo_recv_thread) && !pthread_cancel (d->dvblo_recv_thread)) {
+ pthread_join (d->dvblo_recv_thread, NULL);
+ }
+ dvbmc_list_remove (&d->list);
+ free (d);
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+void dvblo_exit (void)
+{
+ dvblo_dev_t *d;
+ dvblo_dev_t *dtmp;
+
+ DVBMC_LIST_FOR_EACH_ENTRY_SAFE (d, dtmp, &devs.list, dvblo_dev_t, list) {
+ dvblo_del (d);
+ }
+}
+
+static dvblo_dev_t *find_dev_by_uuid (dvblo_dev_t * devs, char *uuid)
+{
+ dvblo_dev_t *d;
+ DVBMC_LIST_FOR_EACH_ENTRY (d, &devs->list, dvblo_dev_t, list) {
+ if (!strcmp (d->uuid, uuid)) {
+ return d;
+ }
+ }
+ return NULL;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+static int count_dev_by_type (dvblo_dev_t * devs, fe_type_t type)
+{
+ int ret = 0;
+ dvblo_dev_t *d;
+ DVBMC_LIST_FOR_EACH_ENTRY (d, &devs->list, dvblo_dev_t, list) {
+ if (type == d->type) {
+ ret++;
+ }
+ }
+ return ret;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+satellite_list_t *dvblo_get_sat_list (char *SatelliteListName, netceiver_info_t * nci)
+{
+ int i;
+ dbg ("looking for %s\n", SatelliteListName);
+ for (i = 0; i < nci->sat_list_num; i++) {
+ if (!strcmp (SatelliteListName, nci->sat_list[i].Name)) {
+ dbg ("found uuid in sat list %d\n", i);
+ return nci->sat_list + i;
+ }
+ }
+ return NULL;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+static int diseqc_write_conf (char *disec_conf_path, char *rotor_conf_path, dvblo_dev_t * devs, int mode)
+{
+ int j, k;
+ dvblo_dev_t *d;
+ char buf[80];
+ char tstr[16];
+ FILE *f = NULL;
+ FILE *fr = NULL;
+
+ f = fopen (disec_conf_path, "wt");
+ if (f == NULL) {
+ return 0;
+ }
+ fprintf (f, "# diseqc.conf in VDR format auto generated\n\n");
+
+ if (strlen(rotor_conf_path)) {
+ special_status_mode=1;
+ fr = fopen (rotor_conf_path, "wt");
+ }
+ if (fr)
+ fprintf (fr, "# rotor.conf auto generated\n\n");
+
+ DVBMC_LIST_FOR_EACH_ENTRY (d, &devs->list, dvblo_dev_t, list) {
+ satellite_list_t *sat_list = dvblo_get_sat_list (d->nci->tuner[d->tuner].SatelliteListName, d->nci);
+ if (!sat_list) {
+ continue;
+ }
+ for (j = 0; j < sat_list->sat_num; j++) {
+ satellite_info_t *sat = sat_list->sat + j;
+ for (k = 0; k < sat->comp_num; k++) {
+ satellite_component_t *comp = sat->comp + k;
+ int newpos = sat->SatPos ^ 1800;
+ sprintf (buf, "e0 10 6f %02x %02x %02x", newpos & 0xff, (newpos >> 8) & 0xff, comp->Polarisation << 1 | !(comp->sec.tone_mode & 1));
+ if (mode) {
+ sprintf (tstr, "A%d ", d->device + 1);
+ } else {
+ tstr[0] = 0;
+ }
+ fprintf (f, "%s%s %d %c 0 [ %s ]\n", tstr, sat->Name, comp->RangeMax, comp->Polarisation == POL_H ? 'H' : 'V', buf);
+ }
+ fprintf (f, "\n");
+ if (j==0 && fr && sat->type==SAT_SRC_ROTOR) {
+ fprintf(fr, "%s %i %i %i %i %i\n", tstr, sat->SatPosMin, sat->SatPosMax,
+ sat->AutoFocus, sat->Latitude, sat->Longitude);
+ }
+ }
+ }
+ info ("created %s\n", disec_conf_path);
+ fclose (f);
+ if (fr) {
+ info ("created %s\n", rotor_conf_path);
+ fclose(fr);
+ }
+ return 1;
+}
+
+void dvblo_handler (void)
+{
+ int i;
+ int n;
+ int nci_num = 0;
+ int write_conf = strlen (cmd.disec_conf_path);
+ netceiver_info_list_t *nc_list = nc_get_list ();
+ memset (&cacaps, 0, sizeof (dvblo_cacaps_t));
+
+ info ("Device Type Limits: DVB-S: %d DVB-C: %d DVB-T: %d ATSC: %d DVB-S2: %d\n\n", cmd.tuner_type_limit[FE_QPSK], cmd.tuner_type_limit[FE_QAM], cmd.tuner_type_limit[FE_OFDM], cmd.tuner_type_limit[FE_ATSC], cmd.tuner_type_limit[FE_DVBS2]);
+
+ while (dvblo_run) {
+ nc_lock_list ();
+ for (n = 0; n < nc_list->nci_num; n++) {
+ netceiver_info_t *nci = nc_list->nci + n;
+ for (i = 0; i < nci->tuner_num; i++) {
+ char *uuid = nci->tuner[i].uuid;
+ if (nci->tuner[i].preference < 0 || !strlen (uuid) || find_dev_by_uuid (&devs, uuid)) {
+ //already seen
+ continue;
+ }
+ fe_type_t type = nci->tuner[i].fe_info.type;
+
+ if (type > FE_DVBS2) {
+ continue;
+ }
+ if(dev_num >= MAX_DEVICES) {
+ dbg("Limit dev_num reached limit of "MAX_DEVICES"\n");
+ continue;
+ }
+ if (count_dev_by_type (&devs, type) == cmd.tuner_type_limit[type]) {
+ dbg ("Limit: %d %d>%d\n", type, count_dev_by_type (&devs, type), cmd.tuner_type_limit[type]);
+ continue;
+ }
+
+ dvblo_dev_t *d = dvblo_add ();
+ if (!d) {
+ err ("Cannot get memory for dvb loopback context\n");
+ }
+
+ dbg ("allocate dev %d for uuid %s\n", dev_num, uuid);
+
+ d->info = nci->tuner[i].fe_info;
+
+ if (type == FE_DVBS2) {
+ d->info.type = FE_QPSK;
+ }
+
+ strcpy (d->uuid, nci->tuner[i].uuid);
+ if (!cmd.reelcammode) {
+ if (cidev < CA_MAX_SLOTS && (cmd.ca_enable & (1 << dev_num))) {
+ d->cacaps=(dvblo_cacaps_t*)((void *) &nci->ci);
+ d->ca_enable = 1;
+ dbg ("Enabling CA support for device %d\n", dev_num);
+ char addrstr[INET6_ADDRSTRLEN];
+ dvblo_get_nc_addr (addrstr, d->uuid);
+ dbg ("dvblo_get_nc_addr: %s %s\n", addrstr, d->uuid);
+ d->c = ci_find_dev_by_uuid (addrstr);
+ if (d->c) {
+ dbg ("Attaching ci dev %p to dvblo dev %p\n", d->c, d);
+ ci_register_handler (d->c, cidev, dvblo_write_ci, d);
+ d->ci_slot = cidev++;
+ } else {
+ dvblo_del (d); //retry next time
+ break;
+ }
+ } else {
+ d->cacaps = &cacaps;
+ d->ca_enable = 0;
+ dbg ("Disabling CA support for device %d\n", dev_num);
+ }
+ } else {
+ if (nci->ci.cap.slot_num && cmd.ca_enable) {
+ d->ca_enable = 1;
+ dbg ("Enabling CA support for device %d\n", dev_num);
+ if (!cidev) {
+ d->cacaps = (dvblo_cacaps_t*)((void *) &nci->ci);
+ char addrstr[INET6_ADDRSTRLEN];
+ dvblo_get_nc_addr (addrstr, d->uuid);
+ dbg ("dvblo_get_nc_addr: %s %s\n", addrstr, d->uuid);
+ d->c = ci_find_dev_by_uuid (addrstr);
+ if (d->c) {
+ dbg ("Attaching ci dev %p to dvblo dev %p\n", d->c, d);
+ ci_register_handler (d->c, cidev++, dvblo_write_ci, d);
+ ci_register_handler (d->c, cidev++, dvblo_write_ci, d);
+ } else {
+ dvblo_del (d); //retry next time
+ break;
+ }
+ } else {
+ d->cacaps = &cacaps;
+ }
+ } else {
+ d->cacaps = &cacaps;
+ d->ca_enable = 0;
+ dbg ("Disabling CA support for device %d\n", dev_num);
+ }
+ }
+
+ d->r = recv_add ();
+ if (!d->r) {
+ err ("Cannot get memory for receiver\n");
+ }
+
+ d->device = dev_num++;
+ d->type = type;
+ d->tuner = i;
+ d->nci = nci;
+
+ register_ten_handler (d->r, dvblo_handle_ten, d);
+ register_ts_handler (d->r, dvblo_handle_ts, d);
+
+ info ("Starting thread for tuner UUID %s [%s] at device %d with type %d\n", d->uuid, nci->tuner[i].fe_info.name, nci->tuner[i].slot, nci->tuner[i].fe_info.type);
+ int ret = pthread_create (&d->dvblo_recv_thread, NULL, dvblo_recv, d);
+ while (!ret && !d->recv_run) {
+ usleep (10000);
+ }
+ if (ret) {
+ err ("pthread_create failed with %d\n", ret);
+ }
+ }
+ }
+ if (write_conf) {
+ if (reload || (nci_num != nc_list->nci_num)) {
+ nci_num = nc_list->nci_num;
+ diseqc_write_conf (cmd.disec_conf_path, cmd.rotor_conf_path, &devs, cmd.vdrdiseqcmode);
+ reload = 0;
+ }
+ }
+ nc_unlock_list ();
+ sleep (1);
+ }
+}
diff --git a/mcast/client/.svn/text-base/dvblo_handler.h.svn-base b/mcast/client/.svn/text-base/dvblo_handler.h.svn-base
new file mode 100644
index 0000000..beaa7ac
--- /dev/null
+++ b/mcast/client/.svn/text-base/dvblo_handler.h.svn-base
@@ -0,0 +1,40 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ */
+
+#define MAX_DEVICES 8
+
+typedef struct dvblo_dev {
+ struct list list;
+
+ pthread_t dvblo_recv_thread;
+ char uuid[UUID_SIZE];
+ int device;
+ int fd;
+ pthread_t dvblo_ca_thread;
+ int fd_ca;
+ int recv_run;
+ int ci_slot;
+ int ca_enable;
+
+ fe_type_t type;
+ recv_info_t *r;
+ ci_dev_t *c;
+ struct dvb_frontend_info info;
+ dvblo_cacaps_t *cacaps;
+ dvblo_pids_t pids;
+ dvb_pid_t dstpids[RECV_MAX_PIDS];
+ dvblo_sec_t sec;
+ struct dvb_frontend_parameters fe_parms;
+ tra_t ten;
+ int tuner;
+ netceiver_info_t *nci;
+} dvblo_dev_t;
+
+int dvblo_init (void);
+void dvblo_exit (void);
+void dvblo_handler (void);
diff --git a/mcast/client/.svn/text-base/headers.h.svn-base b/mcast/client/.svn/text-base/headers.h.svn-base
new file mode 100644
index 0000000..c371395
--- /dev/null
+++ b/mcast/client/.svn/text-base/headers.h.svn-base
@@ -0,0 +1,32 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ */
+
+#ifndef __HEADERS_H__
+#define __HEADERS_H__
+
+#include "defs.h"
+#include "version.h"
+#include "list.h"
+#include "satlists.h"
+#include "mcast.h"
+#include "input.h"
+#include "recv_ccpp.h"
+#include "recv_tv.h"
+#include "tools.h"
+#include "interfaces.h"
+#include "mcast.h"
+#include "mld.h"
+#include "api_server.h"
+#include "tca_handler.h"
+#include "tra_handler.h"
+#include "mld_reporter.h"
+#include "ciparser.h"
+#include "ci_handler.h"
+#include "mmi_handler.h"
+#include "siparser.h"
+#endif
diff --git a/mcast/client/.svn/text-base/inet_aton.c.svn-base b/mcast/client/.svn/text-base/inet_aton.c.svn-base
new file mode 100644
index 0000000..1fd34cc
--- /dev/null
+++ b/mcast/client/.svn/text-base/inet_aton.c.svn-base
@@ -0,0 +1 @@
+link ../common/win32/inet_aton.c \ No newline at end of file
diff --git a/mcast/client/.svn/text-base/inet_ntop.c.svn-base b/mcast/client/.svn/text-base/inet_ntop.c.svn-base
new file mode 100644
index 0000000..d11af10
--- /dev/null
+++ b/mcast/client/.svn/text-base/inet_ntop.c.svn-base
@@ -0,0 +1 @@
+link ../common/win32/inet_ntop.c \ No newline at end of file
diff --git a/mcast/client/.svn/text-base/inet_pton.c.svn-base b/mcast/client/.svn/text-base/inet_pton.c.svn-base
new file mode 100644
index 0000000..7956a55
--- /dev/null
+++ b/mcast/client/.svn/text-base/inet_pton.c.svn-base
@@ -0,0 +1 @@
+link ../common/win32/inet_pton.c \ No newline at end of file
diff --git a/mcast/client/.svn/text-base/input.c.svn-base b/mcast/client/.svn/text-base/input.c.svn-base
new file mode 100644
index 0000000..f10cf4f
--- /dev/null
+++ b/mcast/client/.svn/text-base/input.c.svn-base
@@ -0,0 +1,145 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ */
+
+#include "headers.h"
+#define CI_RESET_WAIT 10
+
+#ifdef __MINGW32__
+#include <getopt.h>
+#endif
+
+cmdline_t cmd;
+
+//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+static void print_help (int argc, char *argv[])
+{
+ printf ("Usage:\n" \
+ " mcli --ifname <network interface>\n" \
+ " mcli --port <port> (default: -port 23000)\n" \
+ " mcli --dvb-s <num> --dvb-c <num> --dvb-t <num> --atsc <num> --dvb-s2 <num>\n" \
+ " limit number of device types (default: 8 of every type)\n" \
+ " mcli --diseqc-conf <filepath>\n" \
+ " mcli --rotor-conf <filepath>\n" \
+ " mcli --mld-reporter-disable\n" \
+ " mcli --sock-path <filepath>\n"\
+ " mcli --ca-enable <bitmask>\n"\
+ " mcli --ci-timeout <time>\n"\
+ " mcli --vdr-diseqc-bind <0|1>\n"\
+ " mcli --reel-cam-mode\n"\
+ "\n");
+}
+
+//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+static void init_cmd_line_parameters ()
+{
+ int i;
+ memset (&cmd, 0, sizeof (cmdline_t));
+
+ for (i=0; i<=FE_DVBS2; i++) {
+ cmd.tuner_type_limit[i] = 8;
+ }
+ cmd.port = 23000;
+ cmd.mld_start = 1;
+ cmd.ca_enable = 3;
+ cmd.vdrdiseqcmode = 1;
+ cmd.reelcammode = 0;
+ cmd.ci_timeout = CI_RESET_WAIT;
+ strcpy (cmd.cmd_sock_path, API_SOCK_NAMESPACE);
+ cmd.disec_conf_path[0]=0;
+ cmd.rotor_conf_path[0]=0;
+}
+
+//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+void get_options (int argc, char *argv[])
+{
+ int tuners = 0, i;
+ char c;
+ int ret;
+ //init parameters
+ init_cmd_line_parameters ();
+ while (1) {
+ //int this_option_optind = optind ? optind : 1;
+ int option_index = 0;
+ static struct option long_options[] = {
+ {"port", 1, 0, 0}, //0
+ {"ifname", 1, 0, 0}, //1
+ {"help", 0, 0, 0}, //2
+ {"dvb-s", 1, 0, 0}, //3
+ {"dvb-c", 1, 0, 0}, //4
+ {"dvb-t", 1, 0, 0}, //5
+ {"atsc", 1, 0, 0}, //6
+ {"dvb-s2", 1, 0, 0}, //7
+ {"diseqc-conf", 1, 0, 0}, //8
+ {"mld-reporter-disable", 0, 0, 0}, //9
+ {"sock-path", 1, 0, 0}, //10
+ {"ca-enable", 1, 0, 0}, //11
+ {"ci-timeout", 1, 0, 0}, //12
+ {"vdr-diseqc-bind", 1, 0, 0}, //13
+ {"reel-cam-mode", 0, 0, 0}, //14
+ {"rotor-conf", 1, 0, 0}, //15
+ {NULL, 0, 0, 0}
+ };
+
+ ret = getopt_long_only (argc, argv, "", long_options, &option_index);
+ c=(char)ret;
+ if (ret == -1 || c == '?') {
+ break;
+ }
+
+ switch (option_index) {
+ case 0:
+ cmd.port = atoi (optarg);
+ break;
+ case 1:
+ strncpy (cmd.iface, optarg, IFNAMSIZ-1);
+ break;
+ case 2:
+ print_help (argc, argv);
+ exit (0);
+ break;
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ i = atoi (optarg);
+ if (!tuners) {
+ memset (cmd.tuner_type_limit, 0, sizeof (cmd.tuner_type_limit));
+ }
+ cmd.tuner_type_limit[option_index - 3] = i;
+ tuners += i;
+ break;
+ case 8:
+ strncpy (cmd.disec_conf_path, optarg, _POSIX_PATH_MAX-1);
+ break;
+ case 9:
+ cmd.mld_start = 0;
+ break;
+ case 10:
+ strncpy (cmd.cmd_sock_path, optarg, _POSIX_PATH_MAX-1);
+ break;
+ case 11:
+ cmd.ca_enable=atoi(optarg);
+ break;
+ case 12:
+ cmd.ci_timeout=atoi(optarg);
+ break;
+ case 13:
+ cmd.vdrdiseqcmode=atoi(optarg);
+ break;
+ case 14:
+ cmd.reelcammode = 1;
+ break;
+ case 15:
+ strncpy (cmd.rotor_conf_path, optarg, _POSIX_PATH_MAX-1);
+ break;
+ default:
+ printf ("?? getopt returned character code 0%o ??\n", c);
+ }
+ }
+}
diff --git a/mcast/client/.svn/text-base/interfaces.c.svn-base b/mcast/client/.svn/text-base/interfaces.c.svn-base
new file mode 100644
index 0000000..177e32f
--- /dev/null
+++ b/mcast/client/.svn/text-base/interfaces.c.svn-base
@@ -0,0 +1 @@
+link ../common/interfaces.c \ No newline at end of file
diff --git a/mcast/client/.svn/text-base/main.c.svn-base b/mcast/client/.svn/text-base/main.c.svn-base
new file mode 100644
index 0000000..895fced
--- /dev/null
+++ b/mcast/client/.svn/text-base/main.c.svn-base
@@ -0,0 +1,83 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ */
+
+#include "headers.h"
+#if ! (defined WIN32 || defined APPLE)
+ #include "dvblo_ioctl.h"
+ #include "dvblo_handler.h"
+#else
+ #include "dummy_client.h"
+#endif
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+int main (int argc, char **argv)
+{
+ printf ("DVB - TV Client Version " MCLI_VERSION_STR " (c) BayCom GmbH\n\n");
+//#if (defined WIN32 || defined APPLE)
+#ifdef WIN32
+#ifndef __MINGW32__
+ cmdline_t cmd;
+ cmd.iface[0]=0;
+ cmd.port=0;
+ cmd.mld_start=1;
+#else
+ get_options (argc, argv);
+#endif
+#else
+#ifdef BACKTRACE
+ signal(SIGSEGV, SignalHandlerCrash);
+ signal(SIGBUS, SignalHandlerCrash);
+ signal(SIGABRT, SignalHandlerCrash);
+#endif
+ get_options (argc, argv);
+#endif
+ recv_init (cmd.iface, cmd.port);
+
+ #ifdef API_SHM
+ api_shm_init();
+ #endif
+ #ifdef API_SOCK
+ api_sock_init(cmd.cmd_sock_path);
+ #endif
+ #ifdef API_WIN
+ api_init(TEXT("\\\\.\\pipe\\mcli"));
+ #endif
+
+ if(cmd.mld_start) {
+ mld_client_init (cmd.iface);
+ }
+#if ! (defined WIN32 || defined APPLE)
+ ci_init(cmd.ca_enable, cmd.iface, cmd.port);
+ dvblo_init();
+
+ dvblo_handler();
+
+ dvblo_exit();
+ ci_exit();
+#else
+ dummy_client ();
+#endif
+
+ if(cmd.mld_start) {
+ mld_client_exit ();
+ }
+
+ #ifdef API_SHM
+ api_shm_exit();
+ #endif
+ #ifdef API_SOCK
+ api_sock_exit();
+ #endif
+ #ifdef API_WIN
+ api_exit();
+ #endif
+
+ recv_exit ();
+
+ return 0;
+}
diff --git a/mcast/client/.svn/text-base/mcast.c.svn-base b/mcast/client/.svn/text-base/mcast.c.svn-base
new file mode 100644
index 0000000..8900452
--- /dev/null
+++ b/mcast/client/.svn/text-base/mcast.c.svn-base
@@ -0,0 +1 @@
+link ../common/mcast.c \ No newline at end of file
diff --git a/mcast/client/.svn/text-base/mld_client.c.svn-base b/mcast/client/.svn/text-base/mld_client.c.svn-base
new file mode 100644
index 0000000..1871f5d
--- /dev/null
+++ b/mcast/client/.svn/text-base/mld_client.c.svn-base
@@ -0,0 +1 @@
+link ../common/mld_client.c \ No newline at end of file
diff --git a/mcast/client/.svn/text-base/mld_common.c.svn-base b/mcast/client/.svn/text-base/mld_common.c.svn-base
new file mode 100644
index 0000000..ee607dc
--- /dev/null
+++ b/mcast/client/.svn/text-base/mld_common.c.svn-base
@@ -0,0 +1 @@
+link ../common/mld_common.c \ No newline at end of file
diff --git a/mcast/client/.svn/text-base/mld_reporter.c.svn-base b/mcast/client/.svn/text-base/mld_reporter.c.svn-base
new file mode 100644
index 0000000..e0530ab
--- /dev/null
+++ b/mcast/client/.svn/text-base/mld_reporter.c.svn-base
@@ -0,0 +1,225 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ */
+
+#undef DEBUG
+#include "headers.h"
+
+extern pthread_mutex_t lock;
+extern recv_info_t receivers;
+
+extern int mld_start;
+static pthread_t mld_send_reports_thread;
+static char iface[IFNAMSIZ];
+
+static int find_mcg_in_mld_mcas (struct in6_addr *mld_mca, int len, struct in6_addr *mcg)
+{
+ int i;
+
+ for (i = 0; i < len; i++) {
+ if (!memcmp (mld_mca + i, mcg, sizeof (struct in6_addr))) {
+ return 1;
+ }
+ }
+ return 0;
+}
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+typedef struct {
+ struct in6_addr *mld_mca_add;
+ struct in6_addr *mld_mca_drop;
+} mld_reporter_context_t;
+
+static void clean_mld_send_reports_thread(void *p)
+{
+ mld_reporter_context_t *c=(mld_reporter_context_t*)p;
+ if(c->mld_mca_add) {
+ free(c->mld_mca_add);
+ }
+ if(c->mld_mca_drop) {
+ free(c->mld_mca_drop);
+ }
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+static void *mld_send_reports (void *arg)
+{
+ recv_info_t *receivers = (recv_info_t *) arg;
+
+ int grec_num_drop;
+ int grec_num_add;
+ pid_info_t *p;
+ pid_info_t *ptmp;
+ recv_info_t *r;
+ int maxpids=128;
+ mld_reporter_context_t c;
+ memset(&c, 0, sizeof(mld_reporter_context_t));
+
+ c.mld_mca_add=(struct in6_addr *)malloc(maxpids*sizeof(struct in6_addr));
+ if (!c.mld_mca_add)
+ err ("mld_send_reports: out of memory\n");
+ c.mld_mca_drop=(struct in6_addr *)malloc(maxpids*sizeof(struct in6_addr));
+ if (!c.mld_mca_drop)
+ err ("mld_send_reports: out of memory\n");
+
+ pthread_cleanup_push (clean_mld_send_reports_thread, &c);
+
+ struct intnode *intn = int_find_name (iface);
+
+ if( !c.mld_mca_add || !c.mld_mca_drop) {
+ err ("Cannot get memory for add/drop list\n");
+ }
+ mld_start=1;
+ while (mld_start) {
+ grec_num_drop=0;
+ pthread_mutex_lock (&lock);
+
+ int pids=count_all_pids(receivers);
+ if(pids>maxpids) {
+ maxpids=pids;
+ c.mld_mca_add=(struct in6_addr *)realloc(c.mld_mca_add, pids*sizeof(struct in6_addr));
+ if (!c.mld_mca_add)
+ err ("mld_send_reports: out of memory\n");
+ c.mld_mca_drop=(struct in6_addr *)realloc(c.mld_mca_drop, pids*sizeof(struct in6_addr));
+ if (!c.mld_mca_drop)
+ err ("mld_send_reports: out of memory\n");
+ }
+
+ //Send listener reports for all recently dropped MCGs
+ DVBMC_LIST_FOR_EACH_ENTRY (r, &receivers->list, recv_info_t, list) {
+ DVBMC_LIST_FOR_EACH_ENTRY_SAFE (p, ptmp, &r->slots.list, pid_info_t, list) {
+ // prevent a somewhere running mcg on any device to be dropped and prevent to drop same mcg multiple times
+ if (!p->run) {
+ if ( p->dropped && !find_any_slot_by_mcg (receivers, &p->mcg) && !find_mcg_in_mld_mcas (c.mld_mca_drop, grec_num_drop, &p->mcg)) {
+ memcpy (c.mld_mca_drop + grec_num_drop++, &p->mcg.s6_addr, sizeof (struct in6_addr));
+ p->dropped--;
+#ifdef DEBUG
+ char host[INET6_ADDRSTRLEN];
+ inet_ntop (AF_INET6, p->mcg.s6_addr, (char *) host, INET6_ADDRSTRLEN);
+ dbg ("DROP_GROUP %d %s\n", grec_num_drop, host);
+#endif
+ } else {
+ dvbmc_list_remove(&p->list);
+ free(p);
+ }
+ }
+ }
+ }
+ if(grec_num_drop > maxpids) {
+ err ("Wrong number of pids: %d>%d\n", grec_num_drop, maxpids);
+ }
+ grec_num_add=0;
+ //Send listener reports for all current MCG in use
+ DVBMC_LIST_FOR_EACH_ENTRY (r, &receivers->list, recv_info_t, list) {
+ DVBMC_LIST_FOR_EACH_ENTRY (p, &r->slots.list, pid_info_t, list) {
+ if (p->run && !find_mcg_in_mld_mcas (c.mld_mca_add, grec_num_add, &p->mcg)) {
+ memcpy (c.mld_mca_add + grec_num_add++, p->mcg.s6_addr, sizeof (struct in6_addr));
+#ifdef DEBUG
+ char host[INET6_ADDRSTRLEN];
+ inet_ntop (AF_INET6, &p->mcg.s6_addr, (char *) host, INET6_ADDRSTRLEN);
+ dbg ("ADD_GROUP %d %s\n", grec_num_add, host);
+#endif
+ }
+ }
+ }
+
+ if(grec_num_add > maxpids) {
+ err ("Wrong number of pids: %d>%d\n", grec_num_add, maxpids);
+ }
+
+ pthread_mutex_unlock (&lock);
+
+ if (intn && intn->mtu) {
+ if (grec_num_drop) {
+ send_mldv2_report (intn, grec_num_drop, c.mld_mca_drop, 0, NULL, MLD2_MODE_IS_INCLUDE);
+ }
+ if (grec_num_add) {
+ send_mldv2_report (intn, grec_num_add, c.mld_mca_add, 0, NULL, MLD2_MODE_IS_EXCLUDE);
+ }
+ }
+ usleep (REP_TIME);
+ pthread_testcancel();
+ }
+ pthread_cleanup_pop (1);
+ return NULL;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+int mld_client_init (char *intf)
+{
+ if(intf) {
+ strcpy(iface, intf);
+ } else {
+ iface[0]=0;
+ }
+
+ if (!strlen (iface)) {
+ struct intnode *intn = int_find_first ();
+ if (intn) {
+ strcpy (iface, intn->name);
+ } else {
+ warn ("Cannot find any usable network interface\n");
+ return -1;
+ }
+ }
+
+#if ! (defined WIN32 || defined APPLE)
+ g_conf->rawsocket = socket (PF_PACKET, SOCK_DGRAM, htons (ETH_P_ALL));
+#endif
+#ifdef WIN32
+ g_conf->rawsocket = socket (PF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
+#endif
+#ifdef APPLE
+ g_conf->rawsocket = socket (PF_INET6, SOCK_RAW, IPPROTO_HOPOPTS);
+#endif
+ if (g_conf->rawsocket < 0) {
+ warn ("Cannot get a packet socket\n");
+ return -1;
+ }
+#ifdef WIN32
+ #define IPV6_HDRINCL 2
+ DWORD n=1;
+ if (setsockopt (g_conf->rawsocket, IPPROTO_IPV6, IPV6_HDRINCL, (char *)&n, sizeof (n)) < 0) {
+ err ("setsockopt IPV6_HDRINCL");
+ }
+ int idx;
+ if ((idx = if_nametoindex (iface))>0) {
+ int ret=setsockopt (g_conf->rawsocket, IPPROTO_IPV6, IPV6_MULTICAST_IF, (_SOTYPE)&idx, sizeof (idx));
+ if(ret<0) {
+ warn("setsockopt for IPV6_MULTICAST_IF failed with %d error %s (%d)\n",ret,strerror (errno), errno);
+ }
+ }
+#endif
+ pthread_create (&mld_send_reports_thread, NULL, mld_send_reports, &receivers);
+ return 0;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+void mld_client_exit (void)
+{
+ if(g_conf) {
+ mld_start=0;
+ if(pthread_exist(mld_send_reports_thread)) {
+ if(pthread_exist(mld_send_reports_thread) && !pthread_cancel (mld_send_reports_thread)) {
+ pthread_join (mld_send_reports_thread, NULL);
+ }
+ }
+#if 0
+ struct intnode *intn;
+ unsigned int i;
+ for (i = 0; i < g_conf->maxinterfaces; i++) {
+ intn = &g_conf->ints[i];
+ if (intn->mtu == 0)
+ continue;
+ int_destroy (intn);
+ }
+#endif
+ closesocket(g_conf->rawsocket);
+ }
+}
diff --git a/mcast/client/.svn/text-base/mld_reporter.h.svn-base b/mcast/client/.svn/text-base/mld_reporter.h.svn-base
new file mode 100644
index 0000000..3036061
--- /dev/null
+++ b/mcast/client/.svn/text-base/mld_reporter.h.svn-base
@@ -0,0 +1,11 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ */
+
+DLL_SYMBOL int mld_client_init (char *intf);
+DLL_SYMBOL void mld_client_exit (void);
+
diff --git a/mcast/client/.svn/text-base/mmi_handler.c.svn-base b/mcast/client/.svn/text-base/mmi_handler.c.svn-base
new file mode 100644
index 0000000..716c7f1
--- /dev/null
+++ b/mcast/client/.svn/text-base/mmi_handler.c.svn-base
@@ -0,0 +1,336 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ * modified by Reel Multimedia, http://www.reel-multimedia.com, info@reel-multimedia.com
+ * 01042010 DL: use a single thread for reading from network layer (uses less resources)
+ *
+ */
+
+#include "headers.h"
+
+//---------------------------------------------------------------------------------------------
+void mmi_print_info (mmi_info_t * m)
+{
+ char str[INET6_ADDRSTRLEN];
+ printf ("------------------\n");
+ inet_ntop (AF_INET6, &m->ipv6, (char *) str, INET6_ADDRSTRLEN);
+ printf ("IP: %s\n", str);
+ printf ("UUID: %s\n", m->uuid);
+ printf ("Slot: %d\n", m->slot);
+
+ int i;
+ for (i = 0; i < m->caid_num; i++) {
+ caid_mcg_t *cm = m->caids + i;
+ printf ("%i.SID: %d\n", i, cm->caid);
+ inet_ntop (AF_INET6, &cm->mcg, (char *) str, INET6_ADDRSTRLEN);
+ printf ("%i.MCG: %s\n", i, str);
+ }
+ printf ("TEXT:\n===================\n %s \n===================\n", m->mmi_text);
+
+}
+
+//---------------------------------------------------------------------------------------------
+int mmi_open_menu_session (char *uuid, char *intf, int port, int cmd)
+{
+ int ret;
+ int j, sockfd;
+ struct in6_addr ipv6;
+ char iface[IFNAMSIZ];
+
+ inet_pton (AF_INET6, uuid, &ipv6);
+
+ if (!intf || !strlen (intf)) {
+ struct intnode *intn = int_find_first ();
+ if (intn) {
+ strcpy (iface, intn->name);
+ }
+ } else {
+ strncpy (iface, intf, sizeof (iface));
+ iface[sizeof (iface) - 1] = 0;
+ }
+ if (!port) {
+ port = 23013;
+ }
+
+ sockfd = socket (PF_INET6, SOCK_STREAM, 0);
+ j = 1;
+ if (setsockopt (sockfd, SOL_SOCKET, SO_REUSEADDR, (_SOTYPE) & j, sizeof (j)) < 0) {
+ err ("setsockopt REUSEADDR\n");
+ }
+
+ j = 1;
+ if (setsockopt (sockfd, SOL_SOCKET, TCP_NODELAY, (_SOTYPE) & j, sizeof (j)) < 0) {
+ warn ("setsockopt TCP_NODELAY\n");
+ }
+
+ dbg ("Connect To: %s\n", uuid);
+
+ struct sockaddr_in6 addr;
+ memset (&addr, 0, sizeof (struct sockaddr_in6));
+
+ addr.sin6_family = AF_INET6;
+ addr.sin6_port = htons (port);
+ addr.sin6_addr = ipv6;
+ addr.sin6_scope_id = if_nametoindex (iface);
+
+ ret = connect (sockfd, (struct sockaddr *) &addr, sizeof (struct sockaddr_in6));
+ if (ret < 0) {
+ dbg ("Failed to access NetCeiver MMI support\n");
+ return -1;
+ }
+ //send init cmd
+ char buf[128];
+ memset (buf, 0, sizeof (buf));
+ dbg ("Request CAM slot %d \n", cmd);
+ sprintf (buf, "%x", cmd);
+ int n = send (sockfd, buf, strlen (buf) + 1, 0);
+ if (n < 0) {
+ dbg ("unable to sent mmi connection cmd !\n");
+ closesocket (sockfd);
+ return -1;
+ }
+ dbg ("MMI SESSION : OK\n");
+ return sockfd;
+}
+
+//---------------------------------------------------------------------------------------------
+void mmi_close_menu_session (int s)
+{
+ closesocket (s);
+}
+
+//---------------------------------------------------------------------------------------------
+int mmi_cam_reset (char *uuid, char *intf, int port, int slot)
+{
+ int cmd = (slot << 12) | 0xfff;
+ printf ("Reseting slot %d (cmd %x)...\n", slot, cmd);
+ int sock = mmi_open_menu_session (uuid, intf, port, cmd);
+ if (sock < 1) {
+ printf ("Unable to reset slot %d on netceiver %s...\n", slot, uuid);
+ }
+ closesocket (sock);
+ return 0;
+}
+//---------------------------------------------------------------------------------------------
+int mmi_cam_reinit (char *uuid, char *intf, int port, int slot)
+{
+ int cmd = (slot << 12) | 0xeee;
+ printf ("Reinitializing slot %d (cmd %x)...\n", slot, cmd);
+ int sock = mmi_open_menu_session (uuid, intf, port, cmd);
+ if (sock < 1) {
+ printf ("Unable to reset slot %d on netceiver %s...\n", slot, uuid);
+ }
+ closesocket (sock);
+ return 0;
+}
+//---------------------------------------------------------------------------------------------
+int mmi_get_menu_text (int sockfd, char *buf, int buf_len, int timeout)
+{
+ int n = -1;
+ struct pollfd p;
+ memset (buf, 0, buf_len);
+ p.fd = sockfd;
+ p.events = POLLIN;
+ if (poll (&p, 1, (timeout+999)>>10) > 0) {
+ n = recv (sockfd, buf, buf_len, 0); //MSG_DONTWAIT);
+ }
+ if (n > 0) {
+ dbg ("recv:\n%s \n", buf);
+ }
+ return n;
+}
+
+//---------------------------------------------------------------------------------------------
+int mmi_send_menu_answer (int sockfd, char *buf, int buf_len)
+{
+ dbg ("send: %s len %d \n", buf, buf_len);
+ int n;
+ n = send (sockfd, buf, buf_len, 0);
+ if (n < 0) {
+ dbg ("mmi_send_answer: error sending !\n");
+ }
+ return n;
+}
+
+//---------------------------------------------------------------------------------------------
+UDPContext *mmi_broadcast_client_init (int port, char *intf)
+{
+ UDPContext *s;
+ char mcg[1024];
+ char iface[IFNAMSIZ];
+ //FIXME: move to common
+ strcpy (mcg, "ff18:6000::");
+ if (!intf || !strlen (intf)) {
+ struct intnode *intn = int_find_first ();
+ if (intn) {
+ strcpy (iface, intn->name);
+ }
+ } else {
+ strncpy (iface, intf, sizeof (iface));
+ iface[sizeof (iface) - 1] = 0;
+ }
+ if (!port) {
+ port = 23000;
+ }
+
+ s = client_udp_open_host (mcg, port, iface);
+ if (!s) {
+ dbg ("client udp open host error !\n");
+ }
+
+ return s;
+}
+
+void mmi_broadcast_client_exit (UDPContext * s)
+{
+ udp_close (s);
+}
+
+//---------------------------------------------------------------------------------------------
+typedef struct
+{
+ xmlDocPtr doc;
+ xmlChar *str, *key;
+} xml_parser_context_t;
+
+static void clean_xml_parser_thread (void *arg)
+{
+ xml_parser_context_t *c = (xml_parser_context_t *) arg;
+ if (c->str) {
+ xmlFree (c->str);
+ }
+ if (c->key) {
+ xmlFree (c->key);
+ }
+ if (c->doc) {
+ xmlFreeDoc (c->doc);
+ }
+ dbg ("Free XML parser structures!\n");
+}
+
+//---------------------------------------------------------------------------------------------
+int mmi_get_data (xmlChar * xmlbuff, int buffersize, mmi_info_t * mmi_info)
+{
+ xml_parser_context_t c;
+ xmlNode *root_element = NULL, *cur_node = NULL;
+
+ xmlKeepBlanksDefault (0); //reomve this f. "text" nodes
+ c.doc = xmlParseMemory ((char *) xmlbuff, buffersize);
+ root_element = xmlDocGetRootElement (c.doc);
+ pthread_cleanup_push (clean_xml_parser_thread, &c);
+
+
+ if (root_element != NULL) {
+ cur_node = root_element->children;
+ if (!xmlStrcmp (cur_node->name, (xmlChar *) "Description")) {
+ root_element = cur_node->children;
+ while (root_element != NULL) {
+ c.key = NULL;
+ c.str = NULL;
+ if ((xmlStrcmp (root_element->name, (const xmlChar *) "component"))) {
+ warn ("Cannot parse XML data\n");
+ root_element = root_element->next;
+ continue;
+ }
+ cur_node = root_element->children;
+ if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "Description"))) {
+ c.str = xmlGetProp (cur_node, (unsigned char *) "about");
+ //fprintf(stdout,"\n%s:\n",c.str);
+ //fprintf(stdout,"-----------------------------------------------------------\n");
+ } else {
+ warn ("Cannot parse XML data\n");
+ root_element = root_element->next;
+ continue;
+ }
+ if (c.str && (!xmlStrcmp (c.str, (const xmlChar *) "MMIData"))) {
+ cur_node = cur_node->children;
+ while (cur_node != NULL) {
+ if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "IP"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("IP: %s\n", c.key);
+ inet_pton (AF_INET6, (char *) c.key, &mmi_info->ipv6);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "UUID"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("UUID: %s\n", c.key);
+ strcpy (mmi_info->uuid, (char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "Slot"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("Slot: %s\n", c.key);
+ mmi_info->slot = atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "TEXT"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("TEXT: %s\n", c.key);
+ int olen = MMI_TEXT_LENGTH, ilen = strlen ((char *) c.key);
+
+ UTF8Toisolat1 ((unsigned char *) mmi_info->mmi_text, &olen, c.key, &ilen);
+
+ xmlFree (c.key);
+ }
+ }
+ cur_node = cur_node->next;
+ }
+ } else if (c.str && (!xmlStrcmp (c.str, (const xmlChar *) "ProgramNumberIDs"))) {
+ cur_node = cur_node->children;
+ while (cur_node != NULL) {
+ if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "MCG"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("MCG: %s\n", c.key);
+ struct in6_addr mcg;
+ inet_pton (AF_INET6, (char *) c.key, &mcg);
+ int sid;
+ mcg_get_id (&mcg, &sid);
+ mcg_set_id (&mcg, 0);
+ mmi_info->caids = (caid_mcg_t *) realloc (mmi_info->caids, sizeof (caid_mcg_t) * (mmi_info->caid_num + 1));
+ if (!mmi_info->caids)
+ err ("mmi_get_data: out of memory\n");
+ caid_mcg_t *cm = mmi_info->caids + mmi_info->caid_num;
+ cm->caid = sid;
+ cm->mcg = mcg;
+ mmi_info->caid_num++;
+ xmlFree (c.key);
+ }
+ }
+ cur_node = cur_node->next;
+ }
+ }
+ xmlFree (c.str);
+ root_element = root_element->next;
+ }
+ }
+ }
+
+ xmlFreeDoc (c.doc);
+ pthread_cleanup_pop (0);
+ return 1;
+}
+
+//---------------------------------------------------------------------------------------------
+int mmi_poll_for_menu_text (UDPContext * s, mmi_info_t * m, int timeout)
+{
+ char buf[8192];
+ int n = 0;
+ if (s) {
+ n = udp_read (s, (unsigned char *) buf, sizeof (buf), timeout, NULL);
+ if (n > 0) {
+ dbg ("recv:\n%s \n", buf);
+ memset (m, 0, sizeof (mmi_info_t));
+ mmi_get_data ((xmlChar *) buf, n, m);
+ }
+ }
+ return n;
+}
+//---------------------------------------------------------------------------------------------
diff --git a/mcast/client/.svn/text-base/mmi_handler.h.svn-base b/mcast/client/.svn/text-base/mmi_handler.h.svn-base
new file mode 100644
index 0000000..37b0af5
--- /dev/null
+++ b/mcast/client/.svn/text-base/mmi_handler.h.svn-base
@@ -0,0 +1,46 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ */
+
+#ifndef _MMI_HANDLER_H
+#define _MMI_HANDLER_H
+
+#define MMI_TEXT_LENGTH 1024
+
+typedef struct caid_mcg {
+
+ int caid;
+ struct in6_addr mcg;
+
+
+} caid_mcg_t;
+
+typedef struct mmi_info {
+
+ int slot;
+ caid_mcg_t *caids;
+ int caid_num;
+
+ struct in6_addr ipv6;
+ char uuid[UUID_SIZE];
+
+ char mmi_text[MMI_TEXT_LENGTH];
+
+} mmi_info_t;
+
+DLL_SYMBOL void mmi_print_info(mmi_info_t *m);
+DLL_SYMBOL int mmi_get_menu_text(int sockfd, char *buf, int buf_len, int timeout);
+DLL_SYMBOL int mmi_send_menu_answer(int sockfd, char *buf, int buf_len);
+DLL_SYMBOL UDPContext *mmi_broadcast_client_init(int port, char *iface);
+DLL_SYMBOL void mmi_broadcast_client_exit(UDPContext *s);
+DLL_SYMBOL int mmi_poll_for_menu_text(UDPContext *s, mmi_info_t *m, int timeout);
+DLL_SYMBOL int mmi_open_menu_session(char *uuid, char *iface,int port, int cmd);
+DLL_SYMBOL void mmi_close_menu_session(int s);
+DLL_SYMBOL int mmi_cam_reset(char *uuid, char *intf, int port, int slot);
+DLL_SYMBOL int mmi_cam_reinit(char *uuid, char *intf, int port, int slot);
+
+#endif
diff --git a/mcast/client/.svn/text-base/recv_ccpp.c.svn-base b/mcast/client/.svn/text-base/recv_ccpp.c.svn-base
new file mode 100644
index 0000000..cdd7e14
--- /dev/null
+++ b/mcast/client/.svn/text-base/recv_ccpp.c.svn-base
@@ -0,0 +1 @@
+link ../common/recv_ccpp.c \ No newline at end of file
diff --git a/mcast/client/.svn/text-base/recv_tv.c.svn-base b/mcast/client/.svn/text-base/recv_tv.c.svn-base
new file mode 100644
index 0000000..f453ed4
--- /dev/null
+++ b/mcast/client/.svn/text-base/recv_tv.c.svn-base
@@ -0,0 +1,905 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ * modified by Reel Multimedia, http://www.reel-multimedia.com, info@reel-multimedia.com
+ * 01042010 DL: use a single thread for reading from network layer (uses less resources)
+ *
+ */
+
+//#define DEBUG 1
+#include "headers.h"
+#if ! defined WIN32 || defined __CYGWIN__
+#define RT
+#endif
+
+#define RE 1
+
+#if defined(RE)
+int set_redirected(recv_info_t *r, int sid);
+int check_if_already_redirected(recv_info_t *r, int sid);
+#endif
+
+recv_info_t receivers;
+pthread_mutex_t lock;
+
+int mld_start=0;
+
+int port=23000;
+char iface[IFNAMSIZ];
+
+static pthread_t recv_tra_thread;
+static pthread_t recv_tca_thread;
+
+#if ! defined WIN32 || defined __CYGWIN__
+static void sig_handler (int signal)
+{
+ dbg ("Signal: %d\n", signal);
+
+ switch (signal) {
+ case SIGUSR1:
+ recv_show_all_pids (&receivers);
+ break;
+ }
+}
+#endif
+
+#ifdef MULTI_THREAD_RECEIVER
+static void clean_recv_ts_thread (void *arg)
+{
+ pid_info_t *p = (pid_info_t *) arg;
+#ifdef DEBUG
+ dbg ("Stop stream receiving for pid %d\n", p->pid.pid);
+#endif
+
+ if (p->s) {
+ udp_close (p->s);
+ }
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+static void *recv_ts (void *arg)
+{
+ unsigned char buf[32712];
+ unsigned char *ptr;
+ int n, res;
+ int cont_old = -1;
+
+ pid_info_t *p = (pid_info_t *) arg;
+ recv_info_t *r = p->recv;
+
+#ifdef RT
+#if 1
+ if (setpriority (PRIO_PROCESS, 0, -15) == -1)
+#else
+ if (pthread_setschedprio (p->recv_ts_thread, -15))
+#endif
+ {
+ dbg ("Cannot raise priority to -15\n");
+ }
+#endif
+
+ pthread_cleanup_push (clean_recv_ts_thread, p);
+#ifdef DEBUG
+ char addr_str[INET6_ADDRSTRLEN];
+ inet_ntop (AF_INET6, p->mcg.s6_addr, addr_str, INET6_ADDRSTRLEN);
+ dbg ("Start stream receiving for %s on port %d %s\n", addr_str, port, iface);
+#endif
+ p->s = client_udp_open (&p->mcg, port, iface);
+ if (!p->s) {
+ warn ("client_udp_open error !\n");
+ } else {
+ p->run = 1;
+ }
+ while (p->run>0) {
+ n = udp_read (p->s, buf, sizeof (buf), 1000, NULL);
+ if (n >0 ) {
+ ptr = buf;
+ if (n % 188) {
+ warn ("Received %d bytes is not multiple of 188!\n", n);
+ }
+ int i;
+ for (i = 0; i < (n / 188); i++) {
+ unsigned char *ts = buf + (i * 188);
+ int adaption_field = (ts[3] >> 4) & 3;
+ int cont = ts[3] & 0xf;
+ int pid = ((ts[1] << 8) | ts[2]) & 0x1fff;
+ int transport_error_indicator = ts[1]&0x80;
+
+ if (pid != 8191 && (adaption_field & 1) && (((cont_old + 1) & 0xf) != cont) && cont_old >= 0) {
+ warn ("Discontinuity on receiver %p for pid %d: %d->%d at pos %d/%d\n", r, pid, cont_old, cont, i, n / 188);
+ }
+ if (transport_error_indicator) {
+ warn ("Transport error indicator set on receiver %p for pid %d: %d->%d at pos %d/%d\n", r, pid, cont_old, cont, i, n / 188);
+ }
+ cont_old = cont;
+ }
+ if(r->handle_ts) {
+ while (n) {
+ res = r->handle_ts (ptr, n, r->handle_ts_context);
+ if (res != n) {
+ warn ("Not same amount of data written: res:%d<=n:%d\n", res, n);
+ }
+ if (res < 0) {
+ warn ("write of %d bytes returned %d\n", n, res);
+ perror ("Write failed");
+ break;
+ } else {
+ ptr += res;
+ n -= res;
+ }
+ }
+ }
+ }
+ pthread_testcancel();
+ }
+ pthread_cleanup_pop (1);
+
+ return NULL;
+ }
+
+#else
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+static void recv_ts_func (unsigned char *buf, int n, void *arg) {
+ if (n >0 ) {
+ pid_info_t *p = (pid_info_t *) arg;
+ recv_info_t *r = p->recv;
+ int i;
+ for (i = 0; i < n; i += 188) {
+ unsigned char *ts = buf + i;
+ int adaption_field = (ts[3] >> 4) & 3;
+ int cont = ts[3] & 0xf;
+ int pid = ((ts[1] << 8) | ts[2]) & 0x1fff;
+ int transport_error_indicator = ts[1]&0x80;
+
+ if (pid != 8191 && (adaption_field & 1) && (((p->cont_old + 1) & 0xf) != cont) && p->cont_old >= 0) {
+ warn ("Discontinuity on receiver %p for pid %d: %d->%d at pos %d/%d\n", r, pid, p->cont_old, cont, i / 188, n / 188);
+ }
+ if (transport_error_indicator) {
+ warn ("Transport error indicator set on receiver %p for pid %d: %d->%d at pos %d/%d\n", r, pid, p->cont_old, cont, i / 188, n / 188);
+ }
+ p->cont_old = cont;
+ }
+ if (i != n) {
+ warn ("Received %d bytes is not multiple of 188!\n", n);
+ }
+ if(r->handle_ts) {
+ while (n) {
+ int res = r->handle_ts (buf, n, r->handle_ts_context);
+ if (res != n) {
+ warn ("Not same amount of data written: res:%d<=n:%d\n", res, n);
+ }
+ if (res < 0) {
+ warn ("write of %d bytes returned %d\n", n, res);
+ perror ("Write failed");
+ break;
+ } else {
+ buf += res;
+ n -= res;
+ }
+ }
+ }
+ }
+}
+#endif
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+int register_ts_handler (recv_info_t * r, int (*p)(unsigned char *, size_t, void *), void *c)
+{
+ r->handle_ts=(int (*)(unsigned char *buffer, size_t len, void *context))p;
+ r->handle_ts_context=c;
+ return 0;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+static pid_info_t *find_slot_by_pid (recv_info_t * r, int pid, int id)
+{
+ pid_info_t *slot;
+ DVBMC_LIST_FOR_EACH_ENTRY (slot, &r->slots.list, pid_info_t, list) {
+ if (slot->run && slot->pid.pid == pid && (id == -1 || slot->pid.id == id)) {
+ return slot;
+ }
+ }
+
+ return NULL;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+static pid_info_t *find_slot_by_mcg (recv_info_t * r, struct in6_addr *mcg)
+{
+ pid_info_t *slot;
+
+ DVBMC_LIST_FOR_EACH_ENTRY (slot, &r->slots.list, pid_info_t, list) {
+ if (slot->run && !memcmp (&slot->mcg, mcg, sizeof (struct in6_addr))) {
+ return slot;
+ }
+ }
+ return NULL;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+int find_any_slot_by_mcg (recv_info_t * receivers, struct in6_addr *mcg)
+{
+ recv_info_t *r;
+ int ret=0;
+
+ DVBMC_LIST_FOR_EACH_ENTRY (r, &receivers->head->list, recv_info_t, list) {
+ pid_info_t *slot = find_slot_by_mcg (r, mcg);
+ if(slot) {
+ ret++;
+ }
+ }
+ return ret;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+int count_receivers(recv_info_t *receivers)
+{
+ int ret=0;
+ struct list *pos;
+
+ DVBMC_LIST_FOR_EACH (pos, &receivers->list) {
+ ret++;
+ }
+ return ret;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+static int count_pids(recv_info_t *r)
+{
+ int ret=0;
+ struct list *pos;
+
+ DVBMC_LIST_FOR_EACH (pos, &r->slots.list) {
+ ret++;
+ }
+ return ret;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+int count_all_pids (recv_info_t * receivers)
+{
+ int ret=0;
+ recv_info_t *r;
+
+ DVBMC_LIST_FOR_EACH_ENTRY (r, &receivers->head->list, recv_info_t, list) {
+ ret += count_pids(r);
+ }
+ return ret;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+void recv_show_pids(recv_info_t *r)
+{
+ pid_info_t *slot;
+ char addr_str[INET6_ADDRSTRLEN];
+ inet_ntop (AF_INET6, r->mcg.s6_addr, addr_str, INET6_ADDRSTRLEN);
+
+ info("pids on receiver %p (%s):\n",r, addr_str);
+ DVBMC_LIST_FOR_EACH_ENTRY (slot, &r->slots.list, pid_info_t, list) {
+ info("%d,", slot->pid.pid);
+ }
+ info("\n");
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+int recv_show_all_pids (recv_info_t * receivers)
+{
+ int ret=0;
+ recv_info_t *r;
+ DVBMC_LIST_FOR_EACH_ENTRY (r, &receivers->head->list, recv_info_t, list) {
+ recv_show_pids(r);
+ }
+ return ret;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+static void deallocate_slot (recv_info_t * r, pid_info_t *p)
+{
+ int nodrop=0;
+
+#ifdef MULTI_THREAD_RECEIVER
+ if (pthread_exist(p->recv_ts_thread)) {
+#else
+ if (p->run) {
+
+#endif //info ("Deallocating PID %d from slot %p\n", p->pid.pid, p);
+ p->run = 0;
+
+ //Do not leave multicast group if there is another dvb adapter using the same group
+ if (find_any_slot_by_mcg (r, &p->mcg)) {
+ dbg ("MCG is still in use not dropping\n");
+ p->s->is_multicast = 0;
+ nodrop=1;
+ }
+
+#ifdef MULTI_THREAD_RECEIVER
+ pthread_join (p->recv_ts_thread, NULL);
+#else
+ udp_close_buff(p->s);
+#endif
+ p->dropped = MAX_DROP_NUM;
+ }
+ //printf("NO DROP: %d\n",nodrop);
+ if(!mld_start || nodrop) {
+ dvbmc_list_remove(&p->list);
+ free(p);
+ }
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+static pid_info_t *allocate_slot (recv_info_t * r, struct in6_addr *mcg, dvb_pid_t *pid)
+{
+ pid_info_t *p = (pid_info_t *)malloc(sizeof(pid_info_t));
+ if(!p) {
+ err ("Cannot get memory for pid\n");
+ }
+
+ dbg ("Allocating new PID %d to Slot %p\n", pid->pid, p);
+
+ memset(p, 0, sizeof(pid_info_t));
+
+ p->cont_old = -1;
+ p->mcg = *mcg;
+ mcg_set_pid (&p->mcg, pid->pid);
+#if defined(RE)
+ if (!check_if_already_redirected(r, pid->id)) {
+ //printf("PID %d not red. ===> SETTING ID to %d\n",pid->pid,pid->id);
+ mcg_set_id (&p->mcg, pid->id);
+ mcg_set_priority(&p->mcg, pid->priority);
+ } else {
+ set_redirected(r, pid->id);
+ //printf("send pid %d to noid mcg !\n",pid->pid);
+ mcg_set_id(&p->mcg, 0);
+ mcg_set_priority(&p->mcg, 0);
+ }
+ //mcg_set_id(&p->mcg,pid->id);
+#else
+ mcg_set_id (&p->mcg, pid->id);
+ mcg_set_priority(&p->mcg, pid->priority);
+#endif
+
+
+#ifdef DEBUG
+ print_mcg (&p->mcg);
+#endif
+ p->pid = *pid;
+ p->recv = r;
+#ifdef MULTI_THREAD_RECEIVER
+ int ret = pthread_create (&p->recv_ts_thread, NULL, recv_ts, p);
+ while (!ret && !p->run) {
+ usleep (10000);
+ }
+ if (ret) {
+ err ("pthread_create failed with %d\n", ret);
+#else
+ p->cont_old=-1;
+ p->s = client_udp_open_cb (&p->mcg, port, iface, recv_ts_func, p);
+ if (!p->s) {
+ warn ("client_udp_open error !\n");
+ return 0;
+#endif
+ } else {
+ p->run = 1;
+ dvbmc_list_add_head (&r->slots.list, &p->list);
+ }
+
+ return p;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+static void stop_ten_receive (recv_info_t * r)
+{
+ dbg ("->>>>>>>>>>>>>>>>>stop_ten_receive on receiver %p\n",r);
+ if (pthread_exist(r->recv_ten_thread) && r->ten_run) {
+ dbg ("cancel TEN receiver %p %p\n", r, r->recv_ten_thread);
+
+ r->ten_run=0;
+ pthread_mutex_unlock (&lock);
+ do {
+ dbg ("wait TEN stop receiver %p %p\n", r, r->recv_ten_thread);
+ usleep(10000);
+ } while (!r->ten_run);
+ pthread_mutex_lock (&lock);
+ r->ten_run=0;
+ dbg ("cancel TEN done receiver %p\n", r);
+ pthread_detach (r->recv_ten_thread);
+ pthread_null(r->recv_ten_thread);
+ }
+}
+
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+static void start_ten_receive (recv_info_t * r)
+{
+ if (r->pidsnum && !pthread_exist(r->recv_ten_thread)) {
+#ifdef DEBUG
+ char host[INET6_ADDRSTRLEN];
+ inet_ntop (AF_INET6, &r->mcg, (char *) host, INET6_ADDRSTRLEN);
+
+ dbg ("Start TEN for receiver %p %s\n", r, host);
+#endif
+ r->ten_run = 0;
+
+ int ret = pthread_create (&r->recv_ten_thread, NULL, recv_ten, r);
+ while (!ret && !r->ten_run) {
+ dbg ("wait TEN startup receiver %p %p\n", r, r->recv_ten_thread);
+ usleep (10000);
+ }
+ if (ret) {
+ err ("pthread_create failed with %d\n", ret);
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+static int cmppids(const void *p1, const void *p2)
+{
+ dvb_pid_t *pid1=(dvb_pid_t *)p1;
+ dvb_pid_t *pid2=(dvb_pid_t *)p2;
+
+ if(pid1->pid == pid2->pid) {
+ return pid1->id < pid2->id;
+ }
+ return pid1->pid < pid2->pid;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+static void update_mcg (recv_info_t * r, int handle_ten)
+{
+ int i;
+ pid_info_t *p;
+ pid_info_t *ptmp;
+
+ if(handle_ten) {
+ if(r->pidsnum) {
+ start_ten_receive(r);
+ } else {
+ stop_ten_receive(r);
+ }
+ }
+ dbg("update_mcg(%p, %d)\n", r, handle_ten);
+ qsort(r->pids, r->pidsnum, sizeof(dvb_pid_t), cmppids);
+
+ DVBMC_LIST_FOR_EACH_ENTRY_SAFE (p, ptmp, &r->slots.list, pid_info_t, list) {
+ //dbg ("DVBMC_LIST_FOR_EACH_ENTRY_SAFE: %p\n", p);
+ if(p->run) {
+ int found_pid = 0;
+ for (i = 0; i < r->pidsnum; i++) {
+ // pid already there without id but now also with id required
+ if (r->pids[i].pid == p->pid.pid && r->pids[i].id && !p->pid.id) {
+ found_pid = 0;
+ break;
+ }
+ if (r->pids[i].pid == p->pid.pid && r->pids[i].id == p->pid.id) {
+ found_pid = 1;
+ }
+ }
+ if (!found_pid) {
+ deallocate_slot (r, p);
+ }
+ }
+ }
+
+ for (i = 0; i < r->pidsnum; i++) {
+ unsigned int pid = r->pids[i].pid;
+ if (!find_slot_by_pid (r, pid, -1)) { //pid with any id there?
+ allocate_slot (r, &r->mcg, r->pids+i);
+ }
+ }
+
+
+}
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+static void stop_receive (recv_info_t * r, int mode)
+{
+ dbg ("stop_receive on receiver %p mode %d\n",r, mode);
+ int pidsnum=r->pidsnum;
+ //Remove all PIDs
+ r->pidsnum = 0;
+ update_mcg (r, mode);
+ r->pidsnum=pidsnum;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+#ifdef RE
+#if 0
+static int find_redirected_sid (recv_info_t * r, int id)
+{
+ pid_info_t *slot;
+ DVBMC_LIST_FOR_EACH_ENTRY (slot, &r->slots.list, pid_info_t, list) {
+ if (slot->pid.id == id && slot->pid.re) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+#endif
+
+int check_if_already_redirected(recv_info_t *r, int sid)
+{
+ int i;
+ for (i = 0; i < r->pidsnum; i++) {
+ //printf("PID %d SID %d RE %d\n",r->pids[i].pid, r->pids[i].id, r->pids[i].re);
+ if (r->pids[i].re && r->pids[i].id == sid) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+int check_if_sid_in(recv_info_t *r, int sid)
+{
+ int i;
+ for (i = 0; i < r->pidsnum; i++) {
+ //printf("PID %d SID %d RE %d\n",r->pids[i].pid, r->pids[i].id, r->pids[i].re);
+ if (r->pids[i].id == sid) {
+// printf("%s: SID in %d!\n",__func__,sid);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+int set_redirected(recv_info_t *r, int sid)
+{
+ int i;
+ for (i = 0; i < r->pidsnum; i++) {
+ if (r->pids[i].id == sid)
+ r->pids[i].re=1;
+ }
+
+ return 0;
+}
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+int stop_sid_mcgs(recv_info_t *r, int sid)
+{
+ pid_info_t *p;
+ pid_info_t *ptmp;
+
+ DVBMC_LIST_FOR_EACH_ENTRY_SAFE (p, ptmp, &r->slots.list, pid_info_t, list) {
+ if(p->run) {
+ if (p->pid.pid && p->pid.id == sid) {
+ //info ("Deallocating PID %d ID %d RE %d from slot %p\n", p->pid.pid,p->pid.id,p->pid.re, p);
+ deallocate_slot (r, p);
+ }
+ }
+ }
+
+ return 0;
+}
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+int rejoin_mcgs(recv_info_t *r, int sid)
+{
+
+ int i;
+ for (i = 0; i < r->pidsnum; i++) {
+ unsigned int pid = r->pids[i].pid;
+ unsigned int id = r->pids[i].id;
+ if (!find_slot_by_pid (r, pid, id) && id == sid) {
+ char addr_str[INET6_ADDRSTRLEN];
+ inet_ntop (AF_INET6, &r->mcg, addr_str, INET6_ADDRSTRLEN);
+ //info ("Rejoin mcg %s with no ID (PID %d ID %d RE %d)...\n", addr_str, pid, id, r->pids[i].re);
+ allocate_slot (r, &r->mcg, r->pids+i);
+ }
+ }
+
+ return 0;
+}
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+#endif
+int recv_redirect (recv_info_t * r, struct in6_addr mcg)
+{
+ int ret = 0;
+
+ pthread_mutex_lock (&lock);
+ dbg ("\n+++++++++++++\nIn redirect for receiver %p\n", r);
+#if 0
+ char addr_str[INET6_ADDRSTRLEN];
+ inet_ntop (AF_INET6, &r->mcg, addr_str, INET6_ADDRSTRLEN);
+ info ("Redirect to ===> %s\n",addr_str);
+#endif
+ int sid;
+ mcg_get_id(&mcg,&sid);
+ mcg_set_id(&mcg,0);
+
+ //printf("SID in: %d\n",sid);
+
+ if (!sid || ( !check_if_already_redirected(r, sid) && check_if_sid_in(r, sid)) ) {
+ if (sid == 0) {
+ stop_receive (r, 0);
+ r->mcg = mcg;
+ update_mcg (r, 0);
+ ret = 1;
+ } else {
+ //stop sid mcgs
+ stop_sid_mcgs(r, sid);
+ set_redirected(r, sid);
+ //start new mcgs with no sid
+ rejoin_mcgs(r, sid);
+ }
+ }
+
+ dbg ("Redirect done for receiver %p\n", r);
+ pthread_mutex_unlock (&lock);
+
+ return ret;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+int recv_stop (recv_info_t * r)
+{
+ pthread_mutex_lock (&lock);
+ stop_receive (r, 1);
+ pthread_mutex_unlock (&lock);
+ return 0;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+int recv_count_pids(recv_info_t * r)
+{
+ int i;
+ for (i=0; r->pids[i].pid!=-1; i++);
+ return i;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+static int recv_copy_pids(dvb_pid_t *dst, dvb_pid_t *src)
+{
+ int i;
+ for (i=0; (src[i].pid!=-1) && (i<(RECV_MAX_PIDS-1)); i++) {
+ dst[i]=src[i];
+ }
+ if(i==(RECV_MAX_PIDS-1)) {
+ warn("Cannot receive more than %d pids\n", RECV_MAX_PIDS-1);
+ }
+ return i;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+int recv_pids (recv_info_t *r, dvb_pid_t *pids)
+{
+ pthread_mutex_lock (&lock);
+ if(pids) {
+ r->pidsnum=recv_copy_pids(r->pids, pids);
+ }
+ update_mcg(r, 1);
+ pthread_mutex_unlock (&lock);
+ return 0;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+int recv_pids_get (recv_info_t *r, dvb_pid_t *pids)
+{
+ pthread_mutex_lock (&lock);
+ if(pids) {
+ memcpy(pids, r->pids, sizeof(dvb_pid_t)*r->pidsnum);
+ pids[r->pidsnum].pid=-1;
+ }
+ pthread_mutex_unlock (&lock);
+ return r->pidsnum;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+int recv_pid_add (recv_info_t * r, dvb_pid_t *pid)
+{
+ int ret=0;
+
+ pthread_mutex_lock (&lock);
+ pid_info_t *p=find_slot_by_pid (r, pid->pid, pid->id);
+ if(!p && (r->pidsnum < (RECV_MAX_PIDS-2))) {
+#if defined(RE)
+ r->pids[r->pidsnum].re = 0;
+#endif
+ r->pids[r->pidsnum]=*pid;
+ r->pids[++r->pidsnum].pid=-1;
+ update_mcg(r, 1);
+ ret = 1;
+ }
+ pthread_mutex_unlock (&lock);
+
+ return ret;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+int recv_pid_del (recv_info_t * r, int pid)
+{
+ int i;
+ int ret=0;
+
+ pthread_mutex_lock (&lock);
+ if(pid>=0) {
+ for (i = 0; i < r->pidsnum; i++) {
+ if(r->pids[i].pid==pid || ret) {
+ r->pids[i]=r->pids[i+1];
+ ret=1;
+ }
+ }
+ if(ret) {
+ r->pidsnum--;
+ update_mcg(r, 1);
+ }
+ } else {
+ r->pids[0].pid=-1;
+ r->pidsnum=0;
+ update_mcg(r, 1);
+ }
+ pthread_mutex_unlock (&lock);
+
+ return ret;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+int recv_tune (recv_info_t * r, fe_type_t type, int satpos, recv_sec_t *sec, struct dvb_frontend_parameters *fe_parms, dvb_pid_t *pids)
+{
+ pthread_mutex_lock (&lock);
+ dbg ("kick_tune receiver %p\n", r);
+
+ stop_receive (r, 1);
+ if(fe_parms) {
+ r->fe_parms=*fe_parms;
+ }
+ if(sec) {
+ r->sec=*sec;
+ }
+ if(pids) {
+ r->pidsnum=recv_copy_pids(r->pids, pids);
+ }
+
+ fe_parms_to_mcg (&r->mcg, STREAMING_PID, type, &r->sec, &r->fe_parms, 0);
+ mcg_set_satpos (&r->mcg, satpos);
+
+ update_mcg (r, 1);
+
+ pthread_mutex_unlock (&lock);
+ dbg ("kick_tune done receiver %p\n", r);
+ return 0;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+recv_info_t *recv_add (void)
+{
+ recv_info_t *r=(recv_info_t *)malloc(sizeof(recv_info_t));
+ if(!r) {
+ err ("Cannot get memory for receiver\n");
+ }
+ memset (r, 0, sizeof (recv_info_t));
+ r->head=&receivers;
+ dvbmc_list_init (&r->slots.list);
+ pthread_mutex_lock (&lock);
+ dvbmc_list_add_head(&receivers.list, &r->list);
+ pthread_mutex_unlock (&lock);
+ return r;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+void recv_del (recv_info_t *r)
+{
+ pthread_mutex_lock (&lock);
+ stop_receive (r, 1);
+ dvbmc_list_remove(&r->list);
+ pthread_mutex_unlock (&lock);
+ free(r);
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+int recv_init(char *intf, int p)
+{
+ LIBXML_TEST_VERSION;
+#ifdef WIN32
+ WSADATA wsaData;
+ if (WSAStartup (MAKEWORD (2, 2), &wsaData) != 0) {
+ err ("WSAStartup failed\n");
+ }
+#endif
+
+ if(intf) {
+ strcpy(iface, intf);
+ } else {
+ iface[0]=0;
+ }
+ if(p) {
+ port=p;
+ }
+
+ g_conf = (struct conf*) malloc (sizeof (struct conf));
+ if (!g_conf) {
+ err ("Cannot get memory for configuration\n");
+ exit (-1);
+ }
+
+ memset (g_conf, 0, sizeof (struct conf));
+ update_interfaces (NULL);
+
+ if (!strlen (iface)) {
+ struct intnode *intn = int_find_first ();
+ if (intn) {
+ strcpy (iface, intn->name);
+ } else {
+ warn ("Cannot find any usable network interface\n");
+ if(g_conf->ints) {
+ free (g_conf->ints);
+ }
+ #ifdef PTW32_STATIC_LIB
+ pthread_win32_process_detach_np();
+ #endif
+ free(g_conf);
+ return -1;
+ }
+ }
+
+ dvbmc_list_init (&receivers.list);
+ pthread_mutex_init (&lock, NULL);
+ receivers.head=&receivers;
+#if ! defined WIN32 || defined __CYGWIN__
+ signal (SIGUSR1, &sig_handler);
+#endif
+#ifdef PTW32_STATIC_LIB
+ pthread_win32_process_attach_np();
+#endif
+ pthread_create (&recv_tra_thread, NULL, recv_tra, NULL);
+ pthread_create (&recv_tca_thread, NULL, recv_tca, NULL);
+
+ return 0;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+int recv_exit(void)
+{
+ recv_info_t *r;
+ recv_info_t *rtmp;
+ if(pthread_exist(recv_tra_thread) && !pthread_cancel (recv_tra_thread)) {
+ pthread_join (recv_tra_thread, NULL);
+ }
+ if(pthread_exist(recv_tca_thread) && !pthread_cancel (recv_tca_thread)) {
+ pthread_join (recv_tca_thread, NULL);
+ }
+ DVBMC_LIST_FOR_EACH_ENTRY_SAFE (r, rtmp, &receivers.head->list, recv_info_t, list) {
+ recv_del(r);
+ }
+#if ! defined WIN32 || defined __CYGWIN__
+ signal (SIGUSR1, NULL);
+#endif
+ g_conf->maxinterfaces=0;
+ if(g_conf->ints) {
+ free (g_conf->ints);
+ }
+#ifdef PTW32_STATIC_LIB
+ pthread_win32_process_detach_np();
+#endif
+ free(g_conf);
+ xmlCleanupParser ();
+ xmlMemoryDump ();
+ return 0;
+}
diff --git a/mcast/client/.svn/text-base/recv_tv.h.svn-base b/mcast/client/.svn/text-base/recv_tv.h.svn-base
new file mode 100644
index 0000000..9feb673
--- /dev/null
+++ b/mcast/client/.svn/text-base/recv_tv.h.svn-base
@@ -0,0 +1,96 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ * modified by Reel Multimedia, http://www.reel-multimedia.com, info@reel-multimedia.com
+ * 01042010 DL: use a single thread for reading from network layer (uses less resources)
+ *
+ */
+
+#ifndef __RECV_TV_H__
+#define __RECV_TV__H__
+
+#define REP_TIME 1000000
+#define MAX_DROP_NUM 5
+#define RECV_MAX_PIDS 256
+
+//typedef struct recv_info recv_info_t;
+
+typedef struct {
+ int pid;
+ int id;
+ int priority;
+#if 1
+ int re;
+#endif
+} dvb_pid_t;
+
+typedef struct pid_info
+{
+ struct list list;
+ UDPContext *s;
+ dvb_pid_t pid;
+ struct in6_addr mcg;
+ recv_info_t *recv;
+ pthread_t recv_ts_thread;
+ int run;
+ int dropped;
+ int cont_old;
+} pid_info_t;
+
+struct recv_info
+{
+ struct list list;
+ recv_info_t *head;
+ pid_info_t slots;
+ int lastalloc;
+ pthread_t recv_ten_thread;
+ struct in6_addr mcg;
+ int ten_run;
+
+ dvb_pid_t pids[RECV_MAX_PIDS];
+ int pidsnum;
+ recv_sec_t sec;
+ struct dvb_frontend_parameters fe_parms;
+
+ recv_festatus_t fe_status;
+
+ int (*handle_ten) (tra_t *ten, void *context);
+ void *handle_ten_context;
+
+ int (*handle_ts) (unsigned char *buffer, size_t len, void *context);
+ void *handle_ts_context;
+};
+
+// Internal Stuff
+int recv_redirect (recv_info_t * r, struct in6_addr mcg);
+int count_all_pids (recv_info_t * receivers);
+int count_receivers(recv_info_t *receivers);
+
+// PID-Handling
+DLL_SYMBOL int recv_pid_add (recv_info_t * r, dvb_pid_t *pid);
+DLL_SYMBOL int recv_pid_del (recv_info_t * r, int pid);
+DLL_SYMBOL int recv_pids (recv_info_t * r, dvb_pid_t *pids);
+DLL_SYMBOL int recv_pids_get (recv_info_t *r, dvb_pid_t *pids);
+DLL_SYMBOL int recv_show_all_pids (recv_info_t * receivers);
+void recv_show_pids(recv_info_t *r);
+
+// Complete Tune
+DLL_SYMBOL int recv_tune (recv_info_t * r, fe_type_t type, int satpos, recv_sec_t *sec, struct dvb_frontend_parameters *fe_parms, dvb_pid_t *pids);
+
+// Receiver Handling
+DLL_SYMBOL recv_info_t *recv_add (void);
+DLL_SYMBOL void recv_del (recv_info_t *r);
+DLL_SYMBOL int recv_stop (recv_info_t * r);
+DLL_SYMBOL int register_ts_handler (recv_info_t * r, int (*p)(unsigned char *, size_t, void *), void *c);
+
+// Module global functions
+DLL_SYMBOL int recv_init(char *intf, int p);
+DLL_SYMBOL int recv_exit(void);
+
+
+int find_any_slot_by_mcg (recv_info_t * receivers, struct in6_addr *mcg);
+
+#endif
diff --git a/mcast/client/.svn/text-base/satlists.c.svn-base b/mcast/client/.svn/text-base/satlists.c.svn-base
new file mode 100644
index 0000000..6dccb39
--- /dev/null
+++ b/mcast/client/.svn/text-base/satlists.c.svn-base
@@ -0,0 +1,133 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ */
+
+#include "headers.h"
+
+int satellite_find_by_diseqc (satellite_reference_t * ref, recv_sec_t *sec, struct dvb_frontend_parameters *fep, int mode)
+{
+ int i, j, k, l;
+ netceiver_info_list_t *nc_list=nc_get_list();
+ char buf[6];
+ memcpy(buf,"\xe0\x10\x6f\x0\x0\x0",6);
+ int freq = fep->frequency/1000;
+ int ret=0;
+ int explicit_position=NO_SAT_POS;
+
+ if (sec->diseqc_cmd.msg_len > 6 || !ref || !freq) {
+ return 0;
+ }
+
+ for (l = 0; l < nc_list->nci_num; l++) {
+ netceiver_info_t *nci = nc_list->nci + l;
+
+ for (i = 0; i < nci->sat_list_num; i++) {
+ satellite_list_t *sat_list = nci->sat_list + i;
+
+ for (j = 0; j < sat_list->sat_num; j++) {
+ satellite_info_t *sat = sat_list->sat + j;
+
+ for (k = 0; k < sat->comp_num; k++) {
+ satellite_component_t *comp = sat->comp + k;
+ int oldpos=sat->SatPos^1800;
+ int newpos=(sec->diseqc_cmd.msg[3]+(sec->diseqc_cmd.msg[4]<<8))^1800;
+ // prepare synthetic messsage from satpos and pol./volt.
+ buf[3]=oldpos;
+ buf[4]=oldpos>>8;
+ buf[5]=(comp->Polarisation&1)<<1 | !(comp->sec.tone_mode&1);
+ dbg("compare: old/new %i/%i, %02x %02x %02x %02x %02x %02x <-> %02x %02x %02x %02x %02x %02x\n", oldpos, newpos,
+ buf[0]&0xff,buf[1]&0xff,buf[2]&0xff,buf[3]&0xff, buf[4]&0xff, buf[5]&0xff,
+ sec->diseqc_cmd.msg[0], sec->diseqc_cmd.msg[1], sec->diseqc_cmd.msg[2],
+ sec->diseqc_cmd.msg[3], sec->diseqc_cmd.msg[4], sec->diseqc_cmd.msg[5]);
+
+ dbg("%i mode %i, len %i, %i > %i , %i < %i, %i < %i, %i > %i\n",sat->type,
+ mode, sec->diseqc_cmd.msg_len, freq, comp->RangeMin, freq, comp->RangeMax,
+ sat->SatPosMin, newpos , sat->SatPosMax, newpos);
+
+ // Check if coded sat pos matches
+ if ((sat->type==SAT_SRC_LNB || sat->type==SAT_SRC_UNI) && mode == 0 && sec->diseqc_cmd.msg_len>0 &&
+ (freq >= comp->RangeMin) && (freq <= comp->RangeMax) &&
+ !memcmp (buf, &sec->diseqc_cmd.msg, sec->diseqc_cmd.msg_len)) {
+ dbg("Satpos MATCH\n");
+ ret=1;
+ }
+ // check for rotor
+ else if (sat->type==SAT_SRC_ROTOR && mode == 0 && sec->diseqc_cmd.msg_len>0 &&
+ (freq >= comp->RangeMin) && (freq <= comp->RangeMax) &&
+ (buf[5]==sec->diseqc_cmd.msg[5]) &&
+ (sat->SatPosMin<=newpos && sat->SatPosMax>=newpos)) {
+ dbg("ROTOR MATCH %i\n",newpos);
+ explicit_position=newpos;
+ ret=1;
+ }
+ // check if given diseqc matches raw tuner diseqc
+ else if (mode == 1 && sec->diseqc_cmd.msg_len>0 && !memcmp (&comp->sec.diseqc_cmd.msg, &sec->diseqc_cmd.msg, sec->diseqc_cmd.msg_len)) {
+ dbg("Diseqc 1.0 Match %02x %02x %02x %02x %02x %02x\n",
+ comp->sec.diseqc_cmd.msg[0], comp->sec.diseqc_cmd.msg[1], comp->sec.diseqc_cmd.msg[2],
+ comp->sec.diseqc_cmd.msg[3], comp->sec.diseqc_cmd.msg[4], comp->sec.diseqc_cmd.msg[5]);
+ ret=1;
+ }else if (mode == 2 && (fe_sec_voltage_t)comp->Polarisation == sec->voltage && comp->sec.tone_mode== sec->tone_mode && comp->sec.mini_cmd == sec->mini_cmd) {
+ dbg("Legacy Match, pol %i, tone %i, cmd %i\n",comp->Polarisation,comp->sec.tone_mode,comp->sec.mini_cmd);
+ ret=1;
+ }
+ if (ret) {
+ ref->netceiver = l;
+ ref->sat_list = i;
+ ref->sat = j;
+ ref->comp = k;
+ ref->position=explicit_position;
+ info("Sat found: %d %d %d %d, rotor %d\n",l,i,j,k, explicit_position);
+ return ret;
+ }
+ }
+ }
+ }
+ }
+ return ret;
+}
+
+int satellite_get_pos_by_ref (satellite_reference_t * ref)
+{
+ netceiver_info_list_t *nc_list=nc_get_list();
+ netceiver_info_t *nci = nc_list->nci + ref->netceiver;
+ satellite_list_t *sat_list = nci->sat_list + ref->sat_list;
+ satellite_info_t *sat = sat_list->sat + ref->sat;
+ if (sat->type==SAT_SRC_ROTOR && ref->position!=NO_SAT_POS) {
+ return ref->position;
+ }
+ return sat->SatPos;
+}
+
+int satellite_get_lof_by_ref (satellite_reference_t * ref)
+{
+ netceiver_info_list_t *nc_list=nc_get_list();
+ netceiver_info_t *nci = nc_list->nci + ref->netceiver;
+ satellite_list_t *sat_list = nci->sat_list + ref->sat_list;
+ satellite_info_t *sat = sat_list->sat + ref->sat;
+ satellite_component_t *comp = sat->comp + ref->comp;
+ return comp->LOF;
+}
+
+recv_sec_t *satellite_find_sec_by_ref (satellite_reference_t * ref)
+{
+ netceiver_info_list_t *nc_list=nc_get_list();
+ netceiver_info_t *nci = nc_list->nci + ref->netceiver;
+ satellite_list_t *sat_list = nci->sat_list + ref->sat_list;
+ satellite_info_t *sat = sat_list->sat + ref->sat;
+ satellite_component_t *comp = sat->comp + ref->comp;
+ return &comp->sec;
+}
+
+polarisation_t satellite_find_pol_by_ref (satellite_reference_t * ref)
+{
+ netceiver_info_list_t *nc_list=nc_get_list();
+ netceiver_info_t *nci = nc_list->nci + ref->netceiver;
+ satellite_list_t *sat_list = nci->sat_list + ref->sat_list;
+ satellite_info_t *sat = sat_list->sat + ref->sat;
+ satellite_component_t *comp = sat->comp + ref->comp;
+ return comp->Polarisation;
+}
diff --git a/mcast/client/.svn/text-base/sock_test.c.svn-base b/mcast/client/.svn/text-base/sock_test.c.svn-base
new file mode 100644
index 0000000..1b4fd39
--- /dev/null
+++ b/mcast/client/.svn/text-base/sock_test.c.svn-base
@@ -0,0 +1,93 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ */
+
+#include "headers.h"
+
+#define SHM_WAIT_RESPONSE(cmd) { cmd->state=SHM_REQUEST; send (sock_comm, &sock_cmd, sizeof(shm_cmd_t), 0); recv (sock_comm, &sock_cmd, sizeof(shm_cmd_t), 0); if (cmd->state == SHM_ERROR) warn ("SHM parameter error\n");}
+
+int main (int argc, char **argv)
+{
+ int sock_comm;
+ int sock_name_len = 0;
+ struct sockaddr sock_name;
+ shm_cmd_t sock_cmd;
+ shm_cmd_t *shm_cmd=&sock_cmd;
+ sock_name.sa_family = AF_UNIX;
+
+ strcpy(sock_name.sa_data, SOCK_NAMESPACE);
+ sock_name_len = strlen(sock_name.sa_data) + sizeof(sock_name.sa_family);
+
+ if((sock_comm = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
+ {
+ warn ("socket create failure %d\n", errno);
+ return -1;
+ }
+
+ if (connect(sock_comm, &sock_name, sock_name_len) < 0) {
+ err ("connect failure\n");
+ }
+
+ shm_cmd->cmd=SHM_GET_NC_NUM;
+ SHM_WAIT_RESPONSE(shm_cmd);
+
+ printf("nc_num: %d\n", shm_cmd->parm[SHM_PARM_NC_NUM]);
+ int nc_num=shm_cmd->parm[SHM_PARM_NC_NUM];
+ int i;
+ for(i=0;i<nc_num;i++) {
+ shm_cmd->cmd=SHM_GET_NC_INFO;
+ shm_cmd->parm[SHM_PARM_NC_NUM]=i;
+ SHM_WAIT_RESPONSE(shm_cmd);
+ printf("nc_info.uuid: %s nc_info.lastseen: %u nc_info.tuner_num: %d\n", shm_cmd->u.nc_info.uuid, (unsigned int) shm_cmd->u.nc_info.lastseen, shm_cmd->u.nc_info.tuner_num);
+ int j;
+ int tuner_num=shm_cmd->u.nc_info.tuner_num;
+ for(j=0;j<tuner_num;j++) {
+ shm_cmd->cmd=SHM_GET_TUNER_INFO;
+ shm_cmd->parm[SHM_PARM_TUNER_NUM]=j;
+ SHM_WAIT_RESPONSE(shm_cmd);
+ printf("tuner_info.fe_info.name: %s\n",shm_cmd->u.tuner_info.fe_info.name);
+ }
+
+
+ int sat_list_num=shm_cmd->u.nc_info.sat_list_num;
+ for(j=0;j<sat_list_num;j++) {
+ shm_cmd->cmd=SHM_GET_SAT_LIST_INFO;
+ shm_cmd->parm[SHM_PARM_NC_NUM]=i;
+ shm_cmd->parm[SHM_PARM_SAT_LIST_NUM]=j;
+ SHM_WAIT_RESPONSE(shm_cmd);
+
+ printf("sat_list_info.Name: %s sat_list_info.sat_num: %d\n", shm_cmd->u.sat_list.Name, shm_cmd->u.sat_list.sat_num);
+
+ int sat_num=shm_cmd->u.sat_list.sat_num;
+ int k;
+ for(k=0;k<sat_num;k++) {
+ shm_cmd->cmd=SHM_GET_SAT_INFO;
+ shm_cmd->parm[SHM_PARM_SAT_LIST_NUM]=j;
+ shm_cmd->parm[SHM_PARM_SAT_NUM]=k;
+ SHM_WAIT_RESPONSE(shm_cmd);
+ printf("sat_info.Name: %s\n",shm_cmd->u.sat_info.Name);
+ }
+ }
+ }
+
+ while (1) {
+ shm_cmd->cmd=SHM_GET_TRA_NUM;
+ SHM_WAIT_RESPONSE(shm_cmd);
+
+ printf("tra_num: %d\n", shm_cmd->parm[SHM_PARM_TRA_NUM]);
+ int tra_num=shm_cmd->parm[SHM_PARM_TRA_NUM];
+ for(i=0;i<tra_num;i++) {
+ shm_cmd->cmd=SHM_GET_TRA_INFO;
+ shm_cmd->parm[SHM_PARM_TRA_NUM]=i;
+ SHM_WAIT_RESPONSE(shm_cmd);
+ printf("tra uuid: %s lastseen: %u lock:%d str:%d snr:%d ber:%d\n", shm_cmd->u.tra.uuid, (unsigned int) shm_cmd->u.tra.lastseen, shm_cmd->u.tra.s.st, shm_cmd->u.tra.s.strength, shm_cmd->u.tra.s.snr, shm_cmd->u.tra.s.ber);
+ }
+ sleep(2);
+ }
+ return 0;
+}
+
diff --git a/mcast/client/.svn/text-base/tca_handler.c.svn-base b/mcast/client/.svn/text-base/tca_handler.c.svn-base
new file mode 100644
index 0000000..3817332
--- /dev/null
+++ b/mcast/client/.svn/text-base/tca_handler.c.svn-base
@@ -0,0 +1,84 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ */
+
+#include "headers.h"
+
+static netceiver_info_list_t nc_list;
+static pthread_mutex_t nci_lock=PTHREAD_MUTEX_INITIALIZER;
+
+static netceiver_info_t *nci_find_unique (netceiver_info_list_t * ncl, char *uuid)
+{
+ int i;
+ for (i = 0; i < ncl->nci_num; i++) {
+ if (!strcmp (ncl->nci[i].uuid, uuid)) {
+ return ncl->nci + i;
+ }
+ }
+ return NULL;
+}
+
+static void nci_free(netceiver_info_t * nc_info)
+{
+ int i, j;
+ for (i = 0; i < nc_info->sat_list_num; i++) {
+ satellite_list_t *sat_list = nc_info->sat_list + i;
+
+ for (j = 0; j < sat_list->sat_num; j++) {
+ satellite_info_t *sat = sat_list->sat + j;
+
+ free (sat->comp);
+ }
+ free (sat_list->sat);
+ }
+ free (nc_info->sat_list);
+ free (nc_info->tuner);
+}
+
+static int nci_add_unique (netceiver_info_list_t * ncl, netceiver_info_t * nci)
+{
+ netceiver_info_t *ncf=nci_find_unique (ncl, nci->uuid);
+ if (!ncf) {
+ ncl->nci = (netceiver_info_t *) realloc (ncl->nci, sizeof (netceiver_info_t) * (ncl->nci_num + 1));
+ if (!ncl->nci) {
+ err ("Cannot get memory for netceiver_info\n");
+ }
+ memcpy (ncl->nci + ncl->nci_num, nci, sizeof (netceiver_info_t));
+ (ncl->nci+ncl->nci_num)->lastseen = time(NULL);
+ ncl->nci_num++;
+ return 1;
+ } else {
+ nci_free(ncf);
+ memcpy(ncf, nci, sizeof (netceiver_info_t));
+ ncf->lastseen = time(NULL);
+ }
+ return 0;
+}
+
+netceiver_info_list_t *nc_get_list(void)
+{
+ return &nc_list;
+}
+
+int nc_lock_list(void)
+{
+ return pthread_mutex_lock (&nci_lock);
+}
+
+int nc_unlock_list(void)
+{
+ return pthread_mutex_unlock (&nci_lock);
+}
+
+void handle_tca (netceiver_info_t * nc_info)
+{
+ nc_lock_list();
+ if (nci_add_unique (&nc_list, nc_info)) {
+ dbg ("New TCA from %s added\n", nc_info->uuid);
+ }
+ nc_unlock_list();
+}
diff --git a/mcast/client/.svn/text-base/tca_handler.h.svn-base b/mcast/client/.svn/text-base/tca_handler.h.svn-base
new file mode 100644
index 0000000..1803b28
--- /dev/null
+++ b/mcast/client/.svn/text-base/tca_handler.h.svn-base
@@ -0,0 +1,18 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ */
+
+typedef struct
+{
+ netceiver_info_t *nci;
+ int nci_num;
+} netceiver_info_list_t;
+
+DLL_SYMBOL netceiver_info_list_t *nc_get_list(void);
+DLL_SYMBOL int nc_lock_list(void);
+DLL_SYMBOL int nc_unlock_list(void);
+void handle_tca (netceiver_info_t * nc_info);
diff --git a/mcast/client/.svn/text-base/tools.c.svn-base b/mcast/client/.svn/text-base/tools.c.svn-base
new file mode 100644
index 0000000..d249f01
--- /dev/null
+++ b/mcast/client/.svn/text-base/tools.c.svn-base
@@ -0,0 +1 @@
+link ../common/tools.c \ No newline at end of file
diff --git a/mcast/client/.svn/text-base/tra_handler.c.svn-base b/mcast/client/.svn/text-base/tra_handler.c.svn-base
new file mode 100644
index 0000000..8148a1f
--- /dev/null
+++ b/mcast/client/.svn/text-base/tra_handler.c.svn-base
@@ -0,0 +1,56 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ */
+
+#include "headers.h"
+
+static tra_info_t tra_list;
+
+static tra_t *tra_find_unique (tra_info_t *trl, char *uuid)
+{
+ int i;
+ for (i = 0; i < trl->tra_num; i++) {
+ if (!strcmp (trl->tra[i].uuid, uuid)) {
+ return trl->tra + i;
+ }
+ }
+ return NULL;
+}
+
+static int tra_add_unique (tra_info_t *trl, tra_t *tri)
+{
+ tra_t *trf=tra_find_unique (trl, tri->uuid);
+ if (!trf) {
+ trl->tra = (tra_t *) realloc (trl->tra, sizeof (tra_t) * (trl->tra_num + 1));
+ if (!trl->tra) {
+ err ("Cannot get memory for netceiver_info\n");
+ }
+ trf = trl->tra + trl->tra_num;
+ trl->tra_num++;
+ }
+ memcpy (trf, tri, sizeof (tra_t));
+ return 1;
+}
+
+tra_info_t *tra_get_list(void)
+{
+ return &tra_list;
+}
+
+int handle_tra(tra_info_t *tra_info)
+{
+ int i;
+ if(tra_info->tra_num) {
+ for (i = 0; i < tra_info->tra_num; i++) {
+ tra_add_unique (&tra_list, tra_info->tra+i);
+ }
+ memcpy(tra_list.cam, tra_info->cam, MAX_CAMS*sizeof(cam_info_t));
+ free (tra_info->tra);
+ return 1;
+ }
+ return 0;
+}
diff --git a/mcast/client/.svn/text-base/tra_handler.h.svn-base b/mcast/client/.svn/text-base/tra_handler.h.svn-base
new file mode 100644
index 0000000..fe5ac2c
--- /dev/null
+++ b/mcast/client/.svn/text-base/tra_handler.h.svn-base
@@ -0,0 +1,10 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ */
+
+DLL_SYMBOL tra_info_t *tra_get_list(void);
+int handle_tra(tra_info_t *tra_info);
diff --git a/mcast/client/.svn/text-base/win32.svn-base b/mcast/client/.svn/text-base/win32.svn-base
new file mode 100644
index 0000000..c90f0e1
--- /dev/null
+++ b/mcast/client/.svn/text-base/win32.svn-base
@@ -0,0 +1 @@
+link ../common/win32 \ No newline at end of file
diff --git a/mcast/client/Makefile b/mcast/client/Makefile
new file mode 100644
index 0000000..1ea0844
--- /dev/null
+++ b/mcast/client/Makefile
@@ -0,0 +1,210 @@
+#Comment this out to disable debugging output
+#DEBUG=1
+#VERBOSE=1
+#WIN32=1
+#API_SOCK=1
+#VERBOSE=1
+#BACKTRACE=1
+
+ifdef RBMINI
+ ARMEL=1
+endif
+
+ARCH= $(shell $(CC) -dumpmachine)
+APPLE_DARWIN = $(shell echo $(ARCH) | grep -q 'apple-darwin' && echo "1" || echo "0")
+CYGWIN = $(shell echo $(ARCH) | grep -q 'cygwin' && echo "1" || echo "0")
+MIPSEL = $(shell echo $(ARCH) | grep -q 'mipsel' && echo "1" || echo "0")
+
+DEFS=-DCLIENT -DLIBRARY -D_REENTRANT -D_GNU_SOURCE
+
+ifeq ($(CYGWIN), 1)
+WIN32=1
+else
+API_SOCK=1
+endif
+
+ifeq ($(APPLE_DARWIN), 1)
+DEFS:=$(DEFS) -I../common/darwin/include/ -DAPPLE
+APPLE=1
+endif
+
+VDRDIR=../../../../..
+-include $(VDRDIR)/Make.config
+
+ifdef ARMEL
+ XML_INC := -I/usr/arm-linux-gnueabi/include/libxml2
+ XML_LIB := -lxml2
+ CROSS = arm-linux-gnueabi-
+else
+ifeq ($(MIPSEL),1)
+DEFS:=$(DEFS) -DMIPSEL
+XML_INC:=-I../../libxml2/include
+XML_LIB:=-L../../libxml2/lib
+else
+XML_INC:=`xml2-config --cflags`
+XML_LIB:=`xml2-config --libs`
+LIBRARY_PATH=/usr/lib
+endif
+endif
+ifeq ($(APPLE_DARWIN), 1)
+CFLAGS:= $(CFLAGS) -fPIC -fno-common -Wall -I../common $(DEFS)
+else
+CFLAGS:= $(CFLAGS) -fPIC -Wall -I../common $(DEFS)
+endif
+
+ifdef BACKTRACE
+CFLAGS:= $(CFLAGS) -DBACKTRACE -g
+endif
+
+ifdef API_SHM
+LDFLAGS:= $(LDFLAGS) -lrt
+CFLAGS:= $(CFLAGS) -DAPI_SHM
+endif
+ifdef API_SOCK
+CFLAGS:= $(CFLAGS) -DAPI_SOCK
+endif
+
+ifdef VERBOSE
+CFLAGS:= $(CFLAGS) -DDEBUG
+DEBUG=1
+endif
+
+ifdef WIN32
+CFLAGS:= -Iwin32/include $(CFLAGS) -mno-cygwin -fPIC -DWIN32
+LDFLAGS:= -Lwin32/lib $(LDFLAGS) -mno-cygwin
+LDLIBS:= -lpthreadGC2 -lxml2 -lz -lws2_32 -liphlpapi
+else
+CFLAGS:= $(CFLAGS) -I../dvbloop $(XML_INC)
+LDFLAGS:=$(LDFLAGS)
+LDLIBS:=$(XML_LIB) -lpthread -lz -lm
+endif
+
+ifdef DEBUG
+LDFLAGS:= $(LDFLAGS) -g -rdynamic
+CFLAGS:= $(CFLAGS) -g -O0
+else
+CFLAGS:= $(CFLAGS) -O3
+endif
+
+MCLI = mcli
+
+MCLI_OBJS= mld_common.o mld_client.o mld_reporter.o mcast.o recv_tv.o recv_ccpp.o tools.o tca_handler.o tra_handler.o satlists.o interfaces.o api_server.o ciparser.o ci_handler.o mmi_handler.o
+ifdef WIN32
+MCLI_OBJS := $(MCLI_OBJS) inet_pton.o inet_ntop.o inet_aton.o
+else
+MCLI_OBJS := $(MCLI_OBJS)
+endif
+
+MCLI_SOBJS = main.o
+ifdef WIN32
+MCLI_SOBJS := $(MCLI_SOBJS) dummy_client.o
+else
+ifdef APPLE
+MCLI_SOBJS := $(MCLI_SOBJS) dummy_client.o input.o
+else
+MCLI_SOBJS := $(MCLI_SOBJS) dvblo_handler.o input.o
+endif
+endif
+
+all: lib$(MCLI)
+
+static: $(MCLI)-static
+
+
+MAKEDEP = $(CXX) -MM -MG
+DEPFILE = .dependencies
+$(DEPFILE): Makefile
+ $(MAKEDEP) $(CFLAGS) $(MCLI_OBJS:%.o=%.c) > $@
+
+-include $(DEPFILE)
+
+
+$(MCLI): $(MCLI_OBJS) $(MCLI_SOBJS)
+ $(CC) $(LDFLAGS) -o $@ $(MCLI_OBJS) $(MCLI_SOBJS) $(LDLIBS)
+ifndef DEBUG
+ifndef WIN32
+ strip $(MCLI)
+endif
+endif
+
+lib$(MCLI): $(MCLI_OBJS)
+ifdef WIN32
+ $(CC) $(LDFLAGS) -shared -o $@.dll $(MCLI_OBJS) $(LDLIBS) -Wl,--out-implib,$@.a -Wl,--output-def,$@.def
+ lib /def:$@.def /machine:x86 /out:..\\common\\win32\\lib\\$@.lib
+# dlltool -k --dllname $@.dll --output-lib win32/lib/$@.lib --def $@.def
+ cp -a $@.dll win32/lib/
+ cp -a $@.a win32/lib/
+ cp -a $@.def win32/lib/
+endif
+ifdef APPLE
+ $(CC) $(LDFLAGS) -dynamiclib -o $@.dylib $(MCLI_OBJS) $(LDLIBS)
+ $(AR) $(ARFLAGS) $@.a $(MCLI_OBJS)
+else
+ $(CC) $(LDFLAGS) -shared -o $@.so $(MCLI_OBJS) $(LDLIBS)
+ $(AR) $(ARFLAGS) $@.a $(MCLI_OBJS)
+endif
+
+
+$(MCLI)-shared: lib$(MCLI)
+ $(CC) -c $(CFLAGS) -ULIBRARY -o main.o main.c
+ifdef WIN32
+ $(CC) -c $(CFLAGS) -ULIBRARY -o dummy_client.o dummy_client.c
+else
+ifdef APPLE
+ $(CC) -c $(CFLAGS) -ULIBRARY -o input.o input.c
+ $(CC) -c $(CFLAGS) -ULIBRARY -o dummy_client.o dummy_client.c
+else
+ $(CC) -c $(CFLAGS) -ULIBRARY -o input.o input.c
+ $(CC) -c $(CFLAGS) -ULIBRARY -o dvblo_handler.o dvblo_handler.c
+endif
+endif
+ $(CC) $(LDFLAGS) -o $@ $(MCLI_SOBJS) $(LDLIBS) -L. -lmcli
+
+$(MCLI)-static: $(MCLI_OBJS) $(MCLI_SOBJS)
+ $(CC) $(LDFLAGS) -static -static-libgcc -o $@ $(MCLI_OBJS) $(MCLI_SOBJS) $(LDLIBS) $(LIBRARY_PATH)/libxml2.a $(LIBRARY_PATH)/libz.a $(LIBRARY_PATH)/libm.a $(LIBRARY_PATH)/libpthread.a
+ifndef DEBUG
+ifndef WIN32
+ strip $(MCLI)-static
+endif
+endif
+
+api_shm_test.o: api_shm_test.c
+ $(CC) -c $(CFLAGS) -DUSE_SHM_API -o $@ $<
+
+api_sock_test.o:api_sock_test.c
+ $(CC) -c $(CFLAGS) -DUSE_SOCK_API -o $@ $<
+
+$(MCLI)-shmtest: api_shm_test.o
+ $(CC) $(LDFLAGS) -o $@ api_shm_test.o $(LDLIBS) -lrt
+
+$(MCLI)-socktest: api_sock_test.o
+ $(CC) $(LDFLAGS) -o $@ api_sock_test.o
+
+install: mcli
+ install -p $< /usr/sbin/$<
+
+install-lib: libmcli.la
+ libtool --mode=install install $< /usr/local/lib/
+
+install-shared: mcli-shared
+ libtool --mode=install install $< /usr/local/bin
+
+depend: .dependencies
+ #makedepend -Y -- $(CFLAGS) -- *c >/dev/null 2>&1
+
+clean:
+ rm -f $(MCLI) $(MCLI)-* *.elf *.gdb *.o *.lo *.la *~ *.so *.a *.def *.dll *.dylib out.ts
+
+mingw32:
+ rm -rf mingw/*.c mingw/*.h mingw/win32
+ cp *.c *.h mingw/
+ mkdir mingw/win32
+ cp -a win32/lib mingw/win32/
+ cp -a win32/include mingw/win32/
+ @echo "Created mingw directory - now ready to rumble... (call build.cmd)"
+
+%.o: %.c
+ $(CC) -c $(CFLAGS) -o $@ $<
+
+%.lo: %.c
+ $(CC) -c $(CFLAGS) -o $@ $<
diff --git a/mcast/client/api_server.c b/mcast/client/api_server.c
new file mode 100644
index 0000000..c3d7617
--- /dev/null
+++ b/mcast/client/api_server.c
@@ -0,0 +1,397 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ */
+
+#include "headers.h"
+
+#if defined(API_SOCK) || defined(API_SHM) || defined (API_WIN)
+
+static int process_cmd (api_cmd_t * api_cmd, tra_info_t * trl, netceiver_info_list_t * nci)
+{
+ if(api_cmd->magic != MCLI_MAGIC || api_cmd->version != MCLI_VERSION) {
+ api_cmd->magic = MCLI_MAGIC;
+ api_cmd->version = MCLI_VERSION;
+ api_cmd->state = API_RESPONSE;
+ return 0;
+ }
+ if (api_cmd->state != API_REQUEST) {
+ return 0;
+ }
+
+ switch (api_cmd->cmd) {
+ case API_GET_NC_NUM:
+ api_cmd->parm[API_PARM_NC_NUM] = nci->nci_num;
+ api_cmd->state = API_RESPONSE;
+ break;
+
+ case API_GET_NC_INFO:
+ if (api_cmd->parm[API_PARM_NC_NUM] < nci->nci_num) {
+ api_cmd->u.nc_info = nci->nci[api_cmd->parm[API_PARM_NC_NUM]];
+ api_cmd->state = API_RESPONSE;
+ } else {
+ api_cmd->state = API_ERROR;
+ }
+ break;
+ case API_GET_TUNER_INFO:
+ if (api_cmd->parm[API_PARM_NC_NUM] < nci->nci_num) {
+ if (api_cmd->parm[API_PARM_TUNER_NUM] < nci->nci[api_cmd->parm[API_PARM_NC_NUM]].tuner_num) {
+ api_cmd->u.tuner_info = nci->nci[api_cmd->parm[API_PARM_NC_NUM]].tuner[api_cmd->parm[API_PARM_TUNER_NUM]];
+ api_cmd->state = API_RESPONSE;
+ } else {
+ api_cmd->state = API_ERROR;
+ }
+ } else {
+ api_cmd->state = API_ERROR;
+ }
+ break;
+ case API_GET_SAT_LIST_INFO:
+ if (api_cmd->parm[API_PARM_NC_NUM] < nci->nci_num) {
+ if (api_cmd->parm[API_PARM_SAT_LIST_NUM] < nci->nci[api_cmd->parm[API_PARM_NC_NUM]].sat_list_num) {
+ api_cmd->u.sat_list = nci->nci[api_cmd->parm[API_PARM_NC_NUM]].sat_list[api_cmd->parm[API_PARM_SAT_LIST_NUM]];
+ api_cmd->state = API_RESPONSE;
+ } else {
+ api_cmd->state = API_ERROR;
+ }
+ } else {
+ api_cmd->state = API_ERROR;
+ }
+ break;
+ case API_GET_SAT_INFO:
+ if (api_cmd->parm[API_PARM_NC_NUM] < nci->nci_num) {
+ if (api_cmd->parm[API_PARM_SAT_LIST_NUM] < nci->nci[api_cmd->parm[API_PARM_NC_NUM]].sat_list_num) {
+ if (api_cmd->parm[API_PARM_SAT_NUM] < nci->nci[api_cmd->parm[API_PARM_NC_NUM]].sat_list[api_cmd->parm[API_PARM_SAT_LIST_NUM]].sat_num) {
+ api_cmd->u.sat_info = nci->nci[api_cmd->parm[API_PARM_NC_NUM]].sat_list[api_cmd->parm[API_PARM_SAT_LIST_NUM]].sat[api_cmd->parm[API_PARM_SAT_NUM]];
+ api_cmd->state = API_RESPONSE;
+ } else {
+ api_cmd->state = API_ERROR;
+ }
+ } else {
+ api_cmd->state = API_ERROR;
+ }
+ } else {
+ api_cmd->state = API_ERROR;
+ }
+ break;
+
+ case API_GET_SAT_COMP_INFO:
+ if (api_cmd->parm[API_PARM_NC_NUM] < nci->nci_num) {
+ if (api_cmd->parm[API_PARM_SAT_LIST_NUM] < nci->nci[api_cmd->parm[API_PARM_NC_NUM]].sat_list_num) {
+ if (api_cmd->parm[API_PARM_SAT_NUM] < nci->nci[api_cmd->parm[API_PARM_NC_NUM]].sat_list[api_cmd->parm[API_PARM_SAT_LIST_NUM]].sat_num) {
+ if (api_cmd->parm[API_PARM_SAT_COMP_NUM] < nci->nci[api_cmd->parm[API_PARM_NC_NUM]].sat_list[api_cmd->parm[API_PARM_SAT_LIST_NUM]].sat[api_cmd->parm[API_PARM_SAT_NUM]].comp_num) {
+ api_cmd->u.sat_comp = nci->nci[api_cmd->parm[API_PARM_NC_NUM]].sat_list[api_cmd->parm[API_PARM_SAT_LIST_NUM]].sat[api_cmd->parm[API_PARM_SAT_NUM]].comp[api_cmd->parm[API_PARM_SAT_COMP_NUM]];
+ api_cmd->state = API_RESPONSE;
+ } else {
+ api_cmd->state = API_ERROR;
+ }
+ } else {
+ api_cmd->state = API_ERROR;
+ }
+ } else {
+ api_cmd->state = API_ERROR;
+ }
+ } else {
+ api_cmd->state = API_ERROR;
+ }
+ break;
+ case API_GET_TRA_NUM:
+ api_cmd->parm[API_PARM_TRA_NUM] = trl->tra_num;
+ api_cmd->state = API_RESPONSE;
+ break;
+ case API_GET_TRA_INFO:
+ if (api_cmd->parm[API_PARM_TRA_NUM] < trl->tra_num) {
+ api_cmd->u.tra = trl->tra[api_cmd->parm[API_PARM_TRA_NUM]];
+ api_cmd->state = API_RESPONSE;
+ } else {
+ api_cmd->state = API_ERROR;
+ }
+ break;
+ default:
+ api_cmd->state = API_ERROR;
+ }
+ return 1;
+}
+#endif
+#ifdef API_SOCK
+typedef struct
+{
+ pthread_t thread;
+ int fd;
+ struct sockaddr_un addr;
+ socklen_t len;
+ int run;
+} sock_t;
+
+static void *sock_cmd_loop (void *p)
+{
+ sock_t *s = (sock_t *) p;
+ api_cmd_t sock_cmd;
+ int n;
+ netceiver_info_list_t *nc_list=nc_get_list();
+ tra_info_t *tra_list=tra_get_list();
+
+ dbg ("new api client connected\n");
+ s->run = 1;
+ while (s->run){
+ n = recv (s->fd, &sock_cmd, sizeof (api_cmd_t), 0);
+ if (n == sizeof (api_cmd_t)) {
+ nc_lock_list();
+ process_cmd (&sock_cmd, tra_list, nc_list);
+ nc_unlock_list();
+ send (s->fd, &sock_cmd, sizeof (api_cmd_t), 0);
+ } else {
+ sock_cmd.magic = MCLI_MAGIC;
+ sock_cmd.version = MCLI_VERSION;
+ sock_cmd.state = API_RESPONSE;
+ send (s->fd, &sock_cmd, sizeof (api_cmd_t), 0);
+ break;
+ }
+ pthread_testcancel();
+ }
+
+ close (s->fd);
+ pthread_detach (s->thread);
+ free (s);
+ return NULL;
+}
+
+static void *sock_cmd_listen_loop (void *p)
+{
+ sock_t tmp;
+ sock_t *s = (sock_t *) p;
+ dbg ("sock api listen loop started\n");
+ s->run = 1;
+
+ while (s->run) {
+ tmp.len = sizeof (struct sockaddr_un);
+ tmp.fd = accept (s->fd, (struct sockaddr*)&tmp.addr, &tmp.len);
+ if (tmp.fd >= 0) {
+ sock_t *as = (sock_t *) malloc (sizeof (sock_t));
+ if (as == NULL) {
+ err ("Cannot get memory for socket\n");
+ }
+ *as=tmp;
+ as->run = 0;
+ pthread_create (&as->thread, NULL, sock_cmd_loop, as);
+ } else {
+ break;
+ }
+ pthread_testcancel();
+ }
+ pthread_detach (s->thread);
+ return NULL;
+}
+
+static sock_t s;
+int api_sock_init (const char *cmd_sock_path)
+{
+ s.addr.sun_family = AF_UNIX;
+ strcpy (s.addr.sun_path, cmd_sock_path);
+ s.len = sizeof(struct sockaddr_un); //strlen (cmd_sock_path) + sizeof (s.addr.sun_family);
+
+ if ((s.fd = socket (AF_UNIX, SOCK_STREAM, 0)) < 0) {
+ warn ("Cannot get socket %d\n", errno);
+ return -1;
+ }
+ unlink (cmd_sock_path);
+ if (bind (s.fd, (struct sockaddr*)&s.addr, s.len) < 0) {
+ warn ("Cannot bind control socket\n");
+ return -1;
+ }
+ if (chmod(cmd_sock_path, S_IRWXU|S_IRWXG|S_IRWXO)) {
+ warn ("Cannot chmod 777 socket %s\n", cmd_sock_path);
+ }
+ if (listen (s.fd, 5) < 0) {
+ warn ("Cannot listen on socket\n");
+ return -1;
+ }
+ return pthread_create (&s.thread, NULL, sock_cmd_listen_loop, &s);
+}
+
+void api_sock_exit (void)
+{
+ //FIXME memory leak on exit in context structres
+ s.run=0;
+ close(s.fd);
+
+ if(pthread_exist(s.thread) && !pthread_cancel (s.thread)) {
+ pthread_join (s.thread, NULL);
+ }
+}
+#endif
+#ifdef API_SHM
+static api_cmd_t *api_cmd = NULL;
+static pthread_t api_cmd_loop_thread;
+
+static void *api_cmd_loop (void *p)
+{
+ netceiver_info_list_t *nc_list=nc_get_list();
+ tra_info_t *tra_list=tra_get_list();
+ while (1) {
+ nc_lock_list();
+ process_cmd (api_cmd, tra_list, nc_list);
+ nc_unlock_list();
+ usleep (1);
+ pthread_testcancel();
+ }
+
+ return NULL;
+}
+
+int api_shm_init (void)
+{
+ int fd = shm_open (API_SHM_NAMESPACE, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
+ if (fd == -1) {
+ warn ("Cannot get a shared memory handle\n");
+ return -1;
+ }
+ if (ftruncate (fd, sizeof (api_cmd_t)) == -1) {
+ err ("Cannot truncate shared memory\n");
+ }
+ api_cmd = mmap (NULL, sizeof (api_cmd_t), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+ if (api_cmd == MAP_FAILED) {
+ err ("MMap of shared memory region failed\n");
+ }
+ close (fd);
+
+ memset (api_cmd, 0, sizeof (api_cmd_t));
+
+ pthread_create (&api_cmd_loop_thread, NULL, api_cmd_loop, NULL);
+ return 0;
+}
+
+void api_shm_exit (void)
+{
+ if(pthread_exist(api_cmd_loop_thread) && !pthread_cancel (api_cmd_loop_thread)) {
+ pthread_join (api_cmd_loop_thread, NULL);
+ }
+ shm_unlink (API_SHM_NAMESPACE);
+}
+#endif
+#ifdef API_WIN
+
+void *api_cmd_loop(void *lpvParam)
+{
+ netceiver_info_list_t *nc_list=nc_get_list();
+ tra_info_t *tra_list=tra_get_list();
+ api_cmd_t sock_cmd;
+ DWORD cbBytesRead, cbWritten;
+ BOOL fSuccess;
+ HANDLE hPipe;
+
+ hPipe = (HANDLE) lpvParam;
+
+ while (1) {
+ fSuccess = ReadFile(
+ hPipe, // handle to pipe
+ &sock_cmd, // buffer to receive data
+ sizeof(sock_cmd), // size of buffer
+ &cbBytesRead, // number of bytes read
+ NULL); // not overlapped I/O
+
+ if (! fSuccess || cbBytesRead == 0) {
+ break;
+ }
+
+ if (cbBytesRead == sizeof (api_cmd_t)) {
+ nc_lock_list();
+ process_cmd (&sock_cmd, tra_list, nc_list);
+ nc_unlock_list();
+
+ fSuccess = WriteFile(
+ hPipe, // handle to pipe
+ &sock_cmd, // buffer to write from
+ sizeof(sock_cmd), // number of bytes to write
+ &cbWritten, // number of bytes written
+ NULL); // not overlapped I/O
+
+ if (! fSuccess || sizeof(sock_cmd) != cbWritten) {
+ break;
+ }
+ } else {
+ sock_cmd.magic = MCLI_MAGIC;
+ sock_cmd.version = MCLI_VERSION;
+ sock_cmd.state = API_RESPONSE;
+ fSuccess = WriteFile(
+ hPipe, // handle to pipe
+ &sock_cmd, // buffer to write from
+ sizeof(sock_cmd), // number of bytes to write
+ &cbWritten, // number of bytes written
+ NULL); // not overlapped I/O
+
+ if (! fSuccess || sizeof(sock_cmd) != cbWritten) {
+ break;
+ }
+ break;
+ }
+ }
+
+ FlushFileBuffers(hPipe);
+ DisconnectNamedPipe(hPipe);
+ CloseHandle(hPipe);
+
+ return NULL;
+}
+
+#define BUFSIZE 2048
+void *api_listen_loop(void *p)
+{
+ BOOL fConnected;
+ pthread_t api_cmd_loop_thread;
+ HANDLE hPipe;
+ LPTSTR lpszPipename=(LPTSTR)p;
+
+ while(1) {
+ hPipe = CreateNamedPipe(
+ lpszPipename, // pipe name
+ PIPE_ACCESS_DUPLEX, // read/write access
+ PIPE_TYPE_MESSAGE | // message type pipe
+ PIPE_READMODE_MESSAGE | // message-read mode
+ PIPE_WAIT, // blocking mode
+ PIPE_UNLIMITED_INSTANCES, // max. instances
+ BUFSIZE, // output buffer size
+ BUFSIZE, // input buffer size
+ 0, // client time-out
+ NULL); // default security attribute
+
+ if (hPipe == INVALID_HANDLE_VALUE) {
+ err ("CreatePipe failed");
+ return NULL;
+ }
+ pthread_testcancel();
+ fConnected = ConnectNamedPipe(hPipe, NULL) ? TRUE : (GetLastError() == ERROR_PIPE_CONNECTED);
+
+ if (fConnected) {
+ if(pthread_create(&api_cmd_loop_thread, NULL, api_cmd_loop, hPipe)) {
+ err ("CreateThread failed");
+ return NULL;
+ } else {
+ pthread_detach(api_cmd_loop_thread);
+ }
+ }
+ else {
+ CloseHandle(hPipe);
+ }
+ }
+ return NULL;
+}
+
+pthread_t api_listen_loop_thread;
+
+int api_init (LPTSTR cmd_pipe_path)
+{
+ return pthread_create (&api_listen_loop_thread, NULL, api_listen_loop, cmd_pipe_path);
+}
+
+void api_exit (void)
+{
+ if(pthread_exist(api_listen_loop_thread) && !pthread_cancel (api_listen_loop_thread)) {
+ TerminateThread(pthread_getw32threadhandle_np(api_listen_loop_thread),0);
+ pthread_join (api_listen_loop_thread, NULL);
+ }
+}
+
+#endif
diff --git a/mcast/client/api_server.h b/mcast/client/api_server.h
new file mode 100644
index 0000000..e0f946f
--- /dev/null
+++ b/mcast/client/api_server.h
@@ -0,0 +1,67 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ */
+
+#define API_SHM_NAMESPACE "/mcli"
+#define API_SOCK_NAMESPACE "/var/tmp/mcli.sock"
+
+typedef enum { API_IDLE,
+ API_REQUEST,
+ API_RESPONSE,
+ API_ERROR
+} api_state_t;
+
+typedef enum { API_GET_NC_NUM,
+ API_GET_NC_INFO,
+ API_GET_TUNER_INFO,
+ API_GET_SAT_LIST_INFO,
+ API_GET_SAT_INFO,
+ API_GET_SAT_COMP_INFO,
+ API_GET_TRA_NUM,
+ API_GET_TRA_INFO,
+ API_GET_DEVICE_INFO
+} api_cmdval_t;
+
+typedef enum { API_PARM_NC_NUM=0,
+ API_PARM_DEVICE_NUM=0,
+ API_PARM_TUNER_NUM,
+ API_PARM_SAT_LIST_NUM,
+ API_PARM_SAT_NUM,
+ API_PARM_SAT_COMP_NUM,
+ API_PARM_TRA_NUM,
+ API_PARM_MAX
+} api_parm_t;
+
+typedef struct {
+ int magic;
+ int version;
+
+ api_cmdval_t cmd;
+ api_state_t state;
+ int parm[API_PARM_MAX];
+ union {
+ netceiver_info_t nc_info;
+ tuner_info_t tuner_info;
+ satellite_list_t sat_list;
+ satellite_info_t sat_info;
+ satellite_component_t sat_comp;
+ tra_t tra;
+ } u;
+} api_cmd_t;
+
+#ifdef API_SHM
+DLL_SYMBOL int api_shm_init (void);
+DLL_SYMBOL void api_shm_exit (void);
+#endif
+#ifdef API_SOCK
+DLL_SYMBOL int api_sock_init (const char *cmd_sock_path);
+DLL_SYMBOL void api_sock_exit (void);
+#endif
+#ifdef API_WIN
+DLL_SYMBOL int api_init (LPTSTR cmd_pipe_path);
+DLL_SYMBOL void api_exit (void);
+#endif
diff --git a/mcast/client/api_shm_test.c b/mcast/client/api_shm_test.c
new file mode 120000
index 0000000..6390750
--- /dev/null
+++ b/mcast/client/api_shm_test.c
@@ -0,0 +1 @@
+api_test.c \ No newline at end of file
diff --git a/mcast/client/api_sock_test.c b/mcast/client/api_sock_test.c
new file mode 120000
index 0000000..6390750
--- /dev/null
+++ b/mcast/client/api_sock_test.c
@@ -0,0 +1 @@
+api_test.c \ No newline at end of file
diff --git a/mcast/client/api_test.c b/mcast/client/api_test.c
new file mode 100644
index 0000000..cfe6afd
--- /dev/null
+++ b/mcast/client/api_test.c
@@ -0,0 +1,127 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ */
+
+#include "headers.h"
+
+
+int main (int argc, char **argv)
+{
+#ifdef USE_SHM_API
+ #define API_WAIT_RESPONSE(cmd) { cmd->state=API_REQUEST; while (cmd->state == API_REQUEST) usleep(10*1000); if (cmd->state == API_ERROR) warn ("SHM parameter error\n");}
+
+ int fd = shm_open (API_SHM_NAMESPACE, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
+ if (fd == -1 ) {
+ warn ("Cannot get a shared memory handle\n");
+ return -1;
+ }
+
+ if (ftruncate (fd, sizeof(api_cmd_t)) == -1) {
+ err ("Cannot truncate shared memory\n");
+ }
+
+ api_cmd_t *api_cmd = mmap(NULL, sizeof(api_cmd_t), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+ if ( api_cmd == MAP_FAILED ) {
+ err ("MMap of shared memory region failed\n");
+ }
+ close(fd);
+#endif
+#ifdef USE_SOCK_API
+ #define API_WAIT_RESPONSE(cmd) { cmd->state=API_REQUEST; send (sock_comm, &sock_cmd, sizeof(api_cmd_t), 0); recv (sock_comm, &sock_cmd, sizeof(api_cmd_t), 0); if (cmd->state == API_ERROR) warn ("SHM parameter error\n");}
+
+ int sock_comm;
+ int sock_name_len = 0;
+ struct sockaddr_un sock_name;
+ api_cmd_t sock_cmd;
+ api_cmd_t *api_cmd=&sock_cmd;
+ sock_name.sun_family = AF_UNIX;
+
+ strcpy(sock_name.sun_path, API_SOCK_NAMESPACE);
+ sock_name_len = strlen(API_SOCK_NAMESPACE) + sizeof(sock_name.sun_family);
+
+ if((sock_comm = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
+ {
+ warn ("socket create failure %d\n", errno);
+ return -1;
+ }
+
+ if (connect(sock_comm, &sock_name, sock_name_len) < 0) {
+ err ("connect failure\n");
+ }
+#endif
+ api_cmd->cmd=API_GET_NC_NUM;
+ API_WAIT_RESPONSE(api_cmd);
+
+ printf("nc_num: %d\n", api_cmd->parm[API_PARM_NC_NUM]);
+ int nc_num=api_cmd->parm[API_PARM_NC_NUM];
+ int i;
+ for(i=0;i<nc_num;i++) {
+ api_cmd->cmd=API_GET_NC_INFO;
+ api_cmd->parm[API_PARM_NC_NUM]=i;
+ API_WAIT_RESPONSE(api_cmd);
+ printf("nc_info.uuid: %s nc_info.lastseen: %u nc_info.tuner_num: %d\n", api_cmd->u.nc_info.uuid, (unsigned int) api_cmd->u.nc_info.lastseen, api_cmd->u.nc_info.tuner_num);
+ int j;
+ int tuner_num=api_cmd->u.nc_info.tuner_num;
+ for(j=0;j<tuner_num;j++) {
+ api_cmd->cmd=API_GET_TUNER_INFO;
+ api_cmd->parm[API_PARM_TUNER_NUM]=j;
+ API_WAIT_RESPONSE(api_cmd);
+ printf("tuner_info.fe_info.name: %s SatList: %s\n",api_cmd->u.tuner_info.fe_info.name, api_cmd->u.tuner_info.SatelliteListName);
+ }
+
+
+ int sat_list_num=api_cmd->u.nc_info.sat_list_num;
+ for(j=0;j<sat_list_num;j++) {
+ api_cmd->cmd=API_GET_SAT_LIST_INFO;
+ api_cmd->parm[API_PARM_NC_NUM]=i;
+ api_cmd->parm[API_PARM_SAT_LIST_NUM]=j;
+ API_WAIT_RESPONSE(api_cmd);
+
+ printf("sat_list_info.Name: %s sat_list_info.sat_num: %d\n", api_cmd->u.sat_list.Name, api_cmd->u.sat_list.sat_num);
+
+ int sat_num=api_cmd->u.sat_list.sat_num;
+ int k;
+ for(k=0;k<sat_num;k++) {
+ api_cmd->cmd=API_GET_SAT_INFO;
+ api_cmd->parm[API_PARM_SAT_LIST_NUM]=j;
+ api_cmd->parm[API_PARM_SAT_NUM]=k;
+ API_WAIT_RESPONSE(api_cmd);
+ printf("sat_info.Name: %s\n",api_cmd->u.sat_info.Name);
+ int comp_num=api_cmd->u.sat_info.comp_num;
+ int l;
+ for(l=0;l<comp_num;l++) {
+ api_cmd->cmd=API_GET_SAT_COMP_INFO;
+ api_cmd->parm[API_PARM_SAT_LIST_NUM]=j;
+ api_cmd->parm[API_PARM_SAT_NUM]=k;
+ api_cmd->parm[API_PARM_SAT_COMP_NUM]=l;
+ API_WAIT_RESPONSE(api_cmd);
+ printf("sat_comp.Polarisation: %d sat_comp.RangeMin: %d sat_comp.RangeMax: %d sat_comp.LOF: %d\n", api_cmd->u.sat_comp.Polarisation, api_cmd->u.sat_comp.RangeMin, api_cmd->u.sat_comp.RangeMax, api_cmd->u.sat_comp.LOF);
+ }
+ }
+ }
+ }
+
+ while (1) {
+ api_cmd->cmd=API_GET_TRA_NUM;
+ API_WAIT_RESPONSE(api_cmd);
+
+ printf("tra_num: %d\n", api_cmd->parm[API_PARM_TRA_NUM]);
+ int tra_num=api_cmd->parm[API_PARM_TRA_NUM];
+ for(i=0;i<tra_num;i++) {
+ api_cmd->cmd=API_GET_TRA_INFO;
+ api_cmd->parm[API_PARM_TRA_NUM]=i;
+ API_WAIT_RESPONSE(api_cmd);
+ char host[INET6_ADDRSTRLEN];
+ inet_ntop (AF_INET6, &api_cmd->u.tra.mcg, (char *) host, INET6_ADDRSTRLEN);
+
+ printf("tra.slot:%d tra.fe_type: %d tra.InUse: % 3d tra.mcg: %s tra.uuid: %s tra.lastseen: %u tra.lock:%d tra.strength:%d tra.snr:%d tra.ber:%d\n", api_cmd->u.tra.slot, api_cmd->u.tra.fe_type, api_cmd->u.tra.InUse, host, api_cmd->u.tra.uuid, (unsigned int) api_cmd->u.tra.lastseen, api_cmd->u.tra.s.st, api_cmd->u.tra.s.strength, api_cmd->u.tra.s.snr, api_cmd->u.tra.s.ber);
+ }
+ sleep(2);
+ }
+ return 0;
+}
+
diff --git a/mcast/client/ci_handler.c b/mcast/client/ci_handler.c
new file mode 100644
index 0000000..beef8ff
--- /dev/null
+++ b/mcast/client/ci_handler.c
@@ -0,0 +1,321 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ */
+
+#include "headers.h"
+
+//#define SHOW_TPDU
+
+static ci_dev_t devs;
+static int dev_num = 0;
+static int ci_run = 0;
+static pthread_t ci_handler_thread;
+static int port = 23000;
+static char iface[IFNAMSIZ];
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+static int ci_connect (ci_dev_t * c)
+{
+ int ret;
+ int j;
+ struct in6_addr nc;
+
+ if (c->connected) {
+ return 0;
+ }
+
+ if (c->fd_ci) {
+ closesocket (c->fd_ci);
+ }
+
+ c->fd_ci = socket (PF_INET6, SOCK_STREAM, 0);
+ j = 1;
+ if (setsockopt (c->fd_ci, SOL_SOCKET, SO_REUSEADDR, (_SOTYPE) & j, sizeof (j)) < 0) {
+ warn ("setsockopt REUSEADDR\n");
+ }
+
+ j = 1;
+ if (setsockopt (c->fd_ci, SOL_SOCKET, TCP_NODELAY, (_SOTYPE) & j, sizeof (j)) < 0) {
+ warn ("setsockopt TCP_NODELAY\n");
+ }
+
+ inet_pton (AF_INET6, c->uuid, &nc);
+#ifdef SHOW_TPDU
+ char host[INET6_ADDRSTRLEN];
+ inet_ntop (AF_INET6, &nc, (char *) host, INET6_ADDRSTRLEN);
+ info ("Connect To: %s\n", host);
+#endif
+ struct sockaddr_in6 addr;
+ memset (&addr, 0, sizeof (struct sockaddr_in6));
+
+ addr.sin6_family = AF_INET6;
+ addr.sin6_port = htons (port);
+ addr.sin6_addr = nc;
+ addr.sin6_scope_id = if_nametoindex (iface);
+
+ ret = connect (c->fd_ci, (struct sockaddr *) &addr, sizeof (struct sockaddr_in6));
+ if (ret < 0) {
+ warn ("Failed to access NetCeiver CA support\n");
+ } else {
+ c->connected = 1;
+ }
+ return ret;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+int ci_write_pdu (ci_dev_t * c, ci_pdu_t * tpdu)
+{
+ int ret = -1;
+
+ dbg ("ci_write_pdu: %p %d\n", tpdu->data, tpdu->len);
+
+ ci_decode_ll (tpdu->data, tpdu->len);
+ memcpy (c->txdata + 2, tpdu->data, tpdu->len);
+ c->txdata[0] = tpdu->len >> 8;
+ c->txdata[1] = tpdu->len & 0xff;
+ if (!ci_connect (c)) {
+#ifdef SHOW_TPDU
+ int j;
+ info ("Send TPDU: ");
+ for (j = 0; j < tpdu->len; j++) {
+ info ("%02x ", tpdu->data[j]);
+ }
+ info ("\n");
+#endif
+ ret = send (c->fd_ci, (char *) c->txdata, tpdu->len + 2, 0);
+ if (ret < 0) {
+ c->connected = 0;
+ }
+ }
+ return ret;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+static void clean_ci_recv_thread (void *argp)
+{
+ ci_dev_t *c = (ci_dev_t *) argp;
+ if (c->txdata) {
+ free (c->txdata);
+ }
+ if (c->rxdata) {
+ free (c->rxdata);
+ }
+ closesocket (c->fd_ci);
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+static void *ci_recv (void *argp)
+{
+ ci_dev_t *c = (ci_dev_t *) argp;
+ ci_pdu_t tpdu;
+ int ret = -1;
+
+ pthread_cleanup_push (clean_ci_recv_thread, c);
+
+ c->rxdata = (u_int8_t *) malloc (CA_TPDU_MAX + 2);
+ if (!c->rxdata)
+ err ("ci_recv: out of memory\n");
+ c->txdata = (u_int8_t *) malloc (CA_TPDU_MAX + 2);
+ if (!c->txdata)
+ err ("ci_recv: out of memory\n");
+
+ if (c->rxdata && c->txdata) {
+ c->recv_run = 1;
+
+ while (c->recv_run) {
+ if (c->connected) {
+ ret = recv (c->fd_ci, (char *) c->rxdata, CA_TPDU_MAX + 2, 0);
+ if (ret > 0) {
+ tpdu.data = c->rxdata;
+ while (ret > 0) {
+ tpdu.len = ntohs16 (tpdu.data);
+ if (tpdu.len >= ret) {
+ break;
+ }
+ tpdu.data += 2;
+#ifdef SHOW_TPDU
+ int j;
+ info ("Received TPDU: ");
+ for (j = 0; j < tpdu.len; j++) {
+ info ("%02x ", tpdu.data[j]);
+ }
+ info ("\n");
+#endif
+ ci_decode_ll (tpdu.data, tpdu.len);
+ unsigned int slot = (unsigned int) tpdu.data[0];
+ if (slot < CA_MAX_SLOTS) {
+ if (c->handle_ci_slot[slot]) {
+ c->handle_ci_slot[slot] (&tpdu, c->handle_ci_slot_context[slot]);
+ }
+ }
+
+ tpdu.data += tpdu.len;
+ ret -= tpdu.len + 2;
+ }
+ } else {
+ if (errno == EAGAIN) {
+ ret = 0;
+ } else {
+ c->connected = 0;
+ }
+ }
+ }
+ usleep (10 * 1000);
+ }
+ }
+ pthread_cleanup_pop (1);
+
+ return NULL;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+int ci_register_handler (ci_dev_t * c, int slot, int (*p) (ci_pdu_t *, void *), void *context)
+{
+ if (slot < CA_MAX_SLOTS) {
+ c->handle_ci_slot[slot] = p;
+ c->handle_ci_slot_context[slot] = context;
+ return 0;
+ }
+ return -1;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+int ci_unregister_handler (ci_dev_t * c, int slot)
+{
+ if (slot < CA_MAX_SLOTS) {
+ c->handle_ci_slot[slot] = NULL;
+ c->handle_ci_slot_context[slot] = NULL;
+ return 0;
+ }
+ return -1;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+static ci_dev_t *ci_add (void)
+{
+ ci_dev_t *c = (ci_dev_t *) malloc (sizeof (ci_dev_t));
+ if (!c)
+ return NULL;
+ memset (c, 0, sizeof (ci_dev_t));
+ dvbmc_list_add_head (&devs.list, &c->list);
+ return c;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+static void ci_del (ci_dev_t * c)
+{
+ c->recv_run = 0;
+ if (pthread_exist(c->ci_recv_thread) && !pthread_cancel (c->ci_recv_thread)) {
+ pthread_join (c->ci_recv_thread, NULL);
+ }
+ dvbmc_list_remove (&c->list);
+ free (c);
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+
+ci_dev_t *ci_find_dev_by_uuid (char *uuid)
+{
+ ci_dev_t *c;
+ DVBMC_LIST_FOR_EACH_ENTRY (c, &devs.list, ci_dev_t, list) {
+ if (!strcmp (c->uuid, uuid)) {
+ return c;
+ }
+ }
+ return NULL;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+static void *ci_handler (void *p)
+{
+ int n;
+ netceiver_info_list_t *nc_list = nc_get_list ();
+ ci_run = 1;
+ while (ci_run) {
+ nc_lock_list ();
+ for (n = 0; n < nc_list->nci_num; n++) {
+ netceiver_info_t *nci = nc_list->nci + n;
+ char *uuid = nci->uuid;
+ if (!strlen (uuid) || ci_find_dev_by_uuid (uuid)) {
+ //already seen
+ continue;
+ }
+
+ ci_dev_t *c = ci_add ();
+ if (!c) {
+ err ("Cannot get memory for dvb loopback context\n");
+ }
+
+ dbg ("allocate ci dev %d for uuid %s\n", dev_num, uuid);
+
+ strcpy (c->uuid, uuid);
+ c->cacaps = &nci->ci;
+ c->device = dev_num++;
+
+ info ("Starting ci thread for netceiver UUID %s\n", c->uuid);
+ int ret = pthread_create (&c->ci_recv_thread, NULL, ci_recv, c);
+ while (!ret && !c->recv_run) {
+ usleep (10000);
+ }
+ if (ret) {
+ err ("pthread_create failed with %d\n", ret);
+ }
+ }
+ nc_unlock_list ();
+ sleep (1);
+ }
+ return NULL;
+}
+
+int ci_init (int ca_enable, char *intf, int p)
+{
+ int ret = 0;
+ if (intf) {
+ strcpy (iface, intf);
+ } else {
+ iface[0] = 0;
+ }
+ if (p) {
+ port = p;
+ }
+
+ dvbmc_list_init (&devs.list);
+ if (ca_enable) {
+ ret = pthread_create (&ci_handler_thread, NULL, ci_handler, NULL);
+ while (!ret && !ci_run) {
+ usleep (10000);
+ }
+ }
+ return ret;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+void ci_exit (void)
+{
+ ci_dev_t *c;
+ ci_dev_t *ctmp;
+ if (pthread_exist (ci_handler_thread)) {
+ if (pthread_exist(ci_handler_thread) && !pthread_cancel (ci_handler_thread)) {
+ pthread_join (ci_handler_thread, NULL);
+ }
+
+ DVBMC_LIST_FOR_EACH_ENTRY_SAFE (c, ctmp, &devs.list, ci_dev_t, list) {
+ ci_del (c);
+ }
+ }
+}
diff --git a/mcast/client/ci_handler.h b/mcast/client/ci_handler.h
new file mode 100644
index 0000000..3ecfc02
--- /dev/null
+++ b/mcast/client/ci_handler.h
@@ -0,0 +1,30 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ */
+
+typedef struct {
+ struct list list;
+
+ pthread_t ci_recv_thread;
+ char uuid[UUID_SIZE];
+ SOCKET fd_ci;
+ int recv_run;
+ int device;
+ int connected;
+ recv_cacaps_t *cacaps;
+ u_int8_t *txdata;
+ u_int8_t *rxdata;
+ int (*handle_ci_slot[CA_MAX_SLOTS]) (ci_pdu_t *tpdu, void *context);
+ void *handle_ci_slot_context[CA_MAX_SLOTS];
+} ci_dev_t;
+
+DLL_SYMBOL int ci_register_handler(ci_dev_t *c, int slot, int (*p) (ci_pdu_t *, void *), void *context);
+DLL_SYMBOL int ci_unregister_handler(ci_dev_t *c, int slot);
+DLL_SYMBOL int ci_write_pdu(ci_dev_t *c, ci_pdu_t *tpdu);
+DLL_SYMBOL ci_dev_t *ci_find_dev_by_uuid (char *uuid);
+DLL_SYMBOL int ci_init (int ca_enable, char *intf, int p);
+DLL_SYMBOL void ci_exit (void);
diff --git a/mcast/client/ciparser.c b/mcast/client/ciparser.c
new file mode 120000
index 0000000..419a448
--- /dev/null
+++ b/mcast/client/ciparser.c
@@ -0,0 +1 @@
+../common/ciparser.c \ No newline at end of file
diff --git a/mcast/client/dummy_client.c b/mcast/client/dummy_client.c
new file mode 100644
index 0000000..2a397d9
--- /dev/null
+++ b/mcast/client/dummy_client.c
@@ -0,0 +1,101 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ */
+
+#define DEBUG 1
+#include "headers.h"
+
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+static int dummy_handle_ts (unsigned char *buffer, size_t len, void *p)
+{
+ FILE *f=(FILE*)p;
+ fwrite(buffer, len, 1, f);
+ return len;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+static int dummy_handle_ten (tra_t *ten, void *p)
+{
+ FILE *f=(FILE*)p;
+ if(ten) {
+ fprintf(f,"Status: %02X, Strength: %04X, SNR: %04X, BER: %04X\n",ten->s.st,ten->s.strength, ten->s.snr, ten->s.ber);
+ }
+ return 0;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+void dummy_client (void)
+{
+ int i;
+ int n;
+ int run=1;
+ FILE *f;
+ recv_info_t *r;
+ recv_sec_t sec;
+ struct dvb_frontend_parameters fep;
+ dvb_pid_t pids[3];
+
+ netceiver_info_list_t *nc_list=nc_get_list();
+#if 0
+ printf("Looking for netceivers out there....\n");
+ while(run) {
+ nc_lock_list();
+ for (n = 0; n < nc_list->nci_num; n++) {
+ netceiver_info_t *nci = nc_list->nci + n;
+ printf("\nFound NetCeiver: %s\n",nci->uuid);
+ for (i = 0; i < nci->tuner_num; i++) {
+ printf(" Tuner: %s, Type %d\n",nci->tuner[i].fe_info.name, nci->tuner[i].fe_info.type);
+ }
+ }
+ nc_unlock_list();
+ if(nc_list->nci_num) {
+ break;
+ }
+ sleep(1);
+ }
+#endif
+ f=fopen("out.ts","wb");
+
+ r = recv_add();
+ if (!r) {
+ fprintf (stderr, "Cannot get memory for receiver\n");
+ return;
+ }
+ register_ten_handler (r, dummy_handle_ten, stderr);
+ register_ts_handler (r, dummy_handle_ts, f);
+
+ memset(&sec, 0, sizeof(recv_sec_t));
+ sec.voltage=SEC_VOLTAGE_18;
+ sec.mini_cmd=SEC_MINI_A;
+ sec.tone_mode=SEC_TONE_ON;
+
+ memset(&fep, 0, sizeof(struct dvb_frontend_parameters));
+ fep.frequency=12544000;
+ fep.inversion=INVERSION_AUTO;
+ fep.u.qpsk.symbol_rate=22000000;
+ fep.u.qpsk.fec_inner=FEC_5_6;
+
+ memset(&pids, 0, sizeof(pids));
+ pids[0].pid=511;
+ pids[1].pid=512;
+ pids[2].pid=511;
+ pids[2].id=2;
+ pids[3].pid=511;
+ pids[3].id=1;
+ pids[4].pid=-1;
+
+ printf("\nTuning a station and writing transport data to file 'out.ts':\n");
+ recv_tune (r, (fe_type_t)FE_QPSK, 1800+192, &sec, &fep, pids);
+ getchar();
+ register_ten_handler (r, NULL, NULL);
+ register_ts_handler (r, NULL, NULL);
+ fclose(f);
+}
diff --git a/mcast/client/dummy_client.h b/mcast/client/dummy_client.h
new file mode 100644
index 0000000..e79cbf1
--- /dev/null
+++ b/mcast/client/dummy_client.h
@@ -0,0 +1,10 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ */
+
+void dummy_client (void);
+
diff --git a/mcast/client/dvblo_handler.c b/mcast/client/dvblo_handler.c
new file mode 100644
index 0000000..875749d
--- /dev/null
+++ b/mcast/client/dvblo_handler.c
@@ -0,0 +1,716 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ */
+
+#include "headers.h"
+#include "dvblo_ioctl.h"
+#include "dvblo_handler.h"
+
+//#define SHOW_EVENTS
+//#define SHOW_TPDU
+//#define SHOW_PIDS
+
+#define TUNE_FORCED_TIMEOUT 5
+
+extern pthread_mutex_t lock;
+extern recv_info_t receivers;
+
+static dvblo_dev_t devs;
+static int dev_num = 0;
+static int dvblo_run = 1;
+static int cidev = 0;
+static int reload = 0;
+static dvblo_cacaps_t cacaps;
+
+static int special_status_mode=0; // 1: return rotor mode and tuner slot in status
+
+static int dvblo_get_nc_addr (char *addrstr, char *uuid)
+{
+ int len = strlen (uuid);
+ if (len <= 5) {
+ return -1;
+ }
+ memset (addrstr, 0, INET6_ADDRSTRLEN);
+
+ strncpy (addrstr, uuid, len - 5);
+ return 0;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+static int dvblo_handle_ts (unsigned char *buffer, size_t len, void *p)
+{
+ dvblo_dev_t * d=( dvblo_dev_t *)p;
+ return write (d->fd, buffer, len);
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+static int dvblo_handle_ten (tra_t * ten, void *c)
+{
+ dvblo_dev_t *d = (dvblo_dev_t *) c;
+ dbg ("TEN: %ld %p %p\n", gettid (), ten, d);
+
+ if (ten) {
+ dvblo_festatus_t stat;
+ memcpy(&stat, &ten->s, sizeof(dvblo_festatus_t));
+
+ d->ten = *ten;
+
+ if (special_status_mode) {
+ stat.st|=(ten->rotor_status&3)<<8;
+ stat.st|=(1+ten->slot)<<12;
+ }
+
+ return ioctl (d->fd, DVBLO_SET_FRONTEND_STATUS, (dvblo_festatus_t*)&stat);
+ } else {
+ dvblo_festatus_t s;
+ memset (&s, 0, sizeof (dvblo_festatus_t));
+
+ return ioctl (d->fd, DVBLO_SET_FRONTEND_STATUS, &s);
+ }
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+static void sig_handler (int signal)
+{
+ dbg ("Signal: %d\n", signal);
+
+ switch (signal) {
+ case SIGHUP:
+ reload = 1;
+ break;
+ case SIGTERM:
+ case SIGINT:
+ dbg ("Trying to exit, got signal %d...\n", signal);
+ dvblo_run = 0;
+ break;
+ }
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+int dvblo_init (void)
+{
+ char char_dev[100];
+ int j, k = 0;
+ struct dvb_frontend_info fe_info;
+ dvblo_festatus_t fe_status;
+
+ dvbmc_list_init (&devs.list);
+
+ memset (&fe_info, 0, sizeof (struct dvb_frontend_info));
+ fe_info.type = -1;
+ strcpy (fe_info.name, "Unconfigured");
+ memset (&fe_status, 0, sizeof (dvblo_festatus_t));
+
+ for (j = 0; j < MAX_DEVICES; j++) {
+
+ sprintf (char_dev, "/dev/dvblo%d", j);
+ int fd = open (char_dev, O_RDWR);
+
+ if (fd == -1) {
+ warn ("Cannot Open %s\n", char_dev);
+ continue;
+ }
+ k++;
+ ioctl (fd, DVBLO_SET_FRONTEND_INFO, &fe_info);
+ ioctl (fd, DVBLO_SET_FRONTEND_STATUS, &fe_status);
+ ioctl (fd, DVBLO_SET_CA_CAPS, &cacaps);
+ dvblo_tpdu_t tpdu;
+ while (1) {
+ if (ioctl (fd, DVBLO_GET_TPDU, &tpdu) || !tpdu.len) {
+ break;
+ }
+ }
+ close (fd);
+ }
+
+ signal (SIGTERM, &sig_handler);
+ signal (SIGINT, &sig_handler);
+ signal (SIGHUP, &sig_handler);
+ signal (SIGPIPE, &sig_handler);
+ return k;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+static int dvblo_convert_pids (dvblo_dev_t * d)
+{
+ dvb_pid_t *dst = d->dstpids;
+ dvblo_pids_t *src = &d->pids;
+ int i;
+#ifdef SHOW_PIDS
+ info ("devnum:%d pidnum:%d\n", d->device, src->num);
+#endif
+ for (i = 0; i < src->num; i++) {
+#ifdef SHOW_PIDS
+ printf ("devnum:%d pid:%04x\n", d->device, src->pid[i]);
+#endif
+ dst[i].pid = src->pid[i];
+ if (d->ca_enable) {
+ dst[i].id = ci_cpl_find_caid_by_pid (src->pid[i]);
+ if (dst[i].id != 0) {
+ dbg ("pid: %04x id: %04x\n", dst[i].pid, dst[i].id);
+ }
+ }
+ }
+ dst[i].pid = -1;
+ return i;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+static int dvblo_tune (dvblo_dev_t * d, int force)
+{
+ satellite_reference_t satref;
+ int SatPos;
+ int mode;
+ int ret = 0;
+
+ nc_lock_list ();
+
+ for (mode = 0; mode < 3; mode++) {
+ if (satellite_find_by_diseqc (&satref, (recv_sec_t*)&d->sec, &d->fe_parms, mode))
+ break;
+ }
+
+ if (mode == 3 || (mode == 2 && (d->type == FE_QAM || d->type == FE_OFDM))) {
+ SatPos = NO_SAT_POS;
+ } else {
+ int LOF = 0;
+ if (mode) {
+ LOF = satellite_get_lof_by_ref (&satref);
+ d->fe_parms.frequency += LOF * 1000;
+ }
+ SatPos = satellite_get_pos_by_ref (&satref);
+ recv_sec_t *sec=satellite_find_sec_by_ref (&satref);
+ memcpy(&d->sec, sec, sizeof(recv_sec_t));
+ d->sec.voltage = satellite_find_pol_by_ref (&satref);
+#if 1 //def SHOW_EVENTS
+ printf ("Found satellite position: %d fe_parms: %d LOF: %d voltage: %d mode: %d\n", SatPos, d->fe_parms.frequency, LOF, d->sec.voltage, mode);
+#endif
+ }
+ nc_unlock_list ();
+ if (force && d->pids.num == 0) {
+ d->dstpids[0].pid = 0;
+ d->dstpids[0].id = 0;
+ d->dstpids[1].pid = -1;
+ ret = 2;
+ } else {
+ dvblo_convert_pids (d);
+ }
+ recv_tune (d->r, d->type, SatPos, (recv_sec_t*)&d->sec, &d->fe_parms, d->dstpids);
+ return ret;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+int dvblo_write_ci (ci_pdu_t * pdu, void *context)
+{
+ dvblo_dev_t *d = (dvblo_dev_t *) context;
+ dvblo_tpdu_t tpdu;
+ memcpy (tpdu.data, pdu->data, pdu->len);
+ tpdu.len = pdu->len;
+ if (!cmd.reelcammode)
+ tpdu.data[0] = 0;
+ return ioctl (d->fd, DVBLO_SET_TPDU, &tpdu);
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+static void clean_dvblo_recv_thread (void *argp)
+{
+ dvblo_dev_t *d = (dvblo_dev_t *) argp;
+ recv_del (d->r);
+ close (d->fd);
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+static void *dvblo_recv (void *argp)
+{
+ dvblo_dev_t *d = (dvblo_dev_t *) argp;
+ dvblo_tpdu_t tpdu;
+ struct dvb_frontend_parameters old_fe_parms;
+ dvblo_sec_t old_sec;
+ struct pollfd fds[1];
+ int timeout_msecs = 50;
+ int ret;
+ time_t last_ci_reset = 0;
+ char char_dev[100];
+ int need_tune = 0;
+ time_t forced = 0;
+ unsigned int event = 0;
+
+ dvblo_cacaps_t cacap;
+
+ sprintf (char_dev, "/dev/dvblo%d", d->device);
+ dbg ("Using character device %s for dvb loopback\n", char_dev);
+
+ d->fd = open (char_dev, O_RDWR);
+
+ if (d->fd < 0) {
+ err ("Cannot open %s - dvbloop driver loaded?\n", char_dev);
+ }
+
+ pthread_cleanup_push (clean_dvblo_recv_thread, d);
+
+ fds[0].fd = d->fd;
+
+ if (!ioctl (d->fd, DVBLO_IOCCHECKDEV)) {
+ if (!ioctl (d->fd, DVBLO_IOCADDDEV)) {
+ info ("created dvb adapter: %d\n", d->device);
+ }
+ }
+ d->info.frequency_min = 1;
+ d->info.frequency_max = 2000000000;
+
+ ioctl (d->fd, DVBLO_SET_FRONTEND_INFO, &d->info);
+ ioctl (d->fd, DVBLO_GET_FRONTEND_PARAMETERS, &d->fe_parms);
+ ioctl (d->fd, DVBLO_GET_PIDLIST, &d->pids);
+ ioctl (d->fd, DVBLO_GET_SEC_PARAMETERS, &d->sec);
+
+ old_fe_parms = d->fe_parms;
+ old_sec = d->sec;
+#ifdef DEBUG
+ print_fe_info (&d->info);
+#endif
+ d->recv_run = 1;
+
+ if (dvblo_tune (d, 1) == 2) {
+ forced = time (NULL);
+ }
+
+ while (d->recv_run) {
+ if (d->cacaps->cap.slot_num) {
+ nc_lock_list ();
+#ifdef SHOW_TPDU
+ info ("ca_caps->: %p ci_slot:%d info[0]:%02x info[1]:%02x\n", d->cacaps, d->ci_slot, d->cacaps->info[0].flags, d->cacaps->info[1].flags);
+#endif
+ cacap = *d->cacaps;
+ if (!cmd.reelcammode) {
+ if (d->ci_slot != 0) {
+ cacap.info[0] = cacap.info[d->ci_slot];
+ }
+ cacap.cap.slot_num = 1;
+ }
+ if ((time (NULL) - last_ci_reset) < cmd.ci_timeout) {
+ cacap.info[0].flags = 0;
+ }
+ ioctl (d->fd, DVBLO_SET_CA_CAPS, &cacap);
+ nc_unlock_list ();
+ }
+
+ fds[0].events = POLLIN;
+ ret = poll (fds, 1, timeout_msecs);
+ if (ret > 0) {
+ ioctl (d->fd, DVBLO_GET_EVENT_MASK, &event);
+ ioctl (d->fd, DVBLO_GET_FRONTEND_PARAMETERS, &d->fe_parms);
+ ioctl (d->fd, DVBLO_GET_PIDLIST, &d->pids);
+ ioctl (d->fd, DVBLO_GET_SEC_PARAMETERS, &d->sec);
+ if (event & EV_MASK_FE) {
+#ifdef SHOW_EVENTS
+ printf ("%p/%p Event Received: FE+Tuner/", d, d->r);
+ if (event & EV_FRONTEND) {
+ printf ("Frontend ");
+ }
+ if (event & EV_TUNER) {
+ printf ("Tuner ");
+ }
+ if (event & EV_FREQUENCY) {
+ printf ("Frequency:%d ", d->fe_parms.frequency);
+ }
+ if (event & EV_BANDWIDTH) {
+ printf ("Bandwidth ");
+ }
+ printf ("\n");
+#endif
+ if (memcmp (&d->fe_parms, &old_fe_parms, sizeof (struct dvb_frontend_parameters))) {
+ old_fe_parms = d->fe_parms;
+ dbg ("fe_parms have changed!\n");
+ need_tune = 1;
+ if (d->ca_enable) {
+ ci_cpl_clear (d->ci_slot);
+ }
+ }
+ }
+ if (event & EV_MASK_SEC) {
+#ifdef SHOW_EVENTS
+ printf ("%p/%p Event Received: SEC/", d, d->r);
+ if (event & EV_TONE) {
+ printf ("Tone:%d ", d->sec.tone_mode);
+ }
+ if (event & EV_VOLTAGE) {
+ printf ("Voltage:%d ", d->sec.voltage);
+ }
+ if (event & EV_DISEC_MSG) {
+ printf ("DISEC-Message:");
+ int j;
+ for (j = 0; j < d->sec.diseqc_cmd.msg_len; j++) {
+ printf ("%02x ", d->sec.diseqc_cmd.msg[j]);
+ }
+ }
+ if (event & EV_DISEC_BURST) {
+ printf ("DISEC-Burst:%d ", d->sec.mini_cmd);
+ }
+ printf ("\n");
+#endif
+ if (d->sec.voltage == SEC_VOLTAGE_OFF) {
+ recv_stop (d->r);
+ memset (&old_fe_parms, 0, sizeof (struct dvb_frontend_parameters));
+ need_tune = 0;
+ dbg ("Stop %p\n", d->r);
+ } else if (memcmp (&d->sec, &old_sec, sizeof (dvblo_sec_t))) {
+ dbg ("SEC parms have changed!\n");
+ old_sec = d->sec;
+ need_tune = 1;
+ if (d->ca_enable) {
+ ci_cpl_clear (d->ci_slot);
+ }
+ }
+ }
+ if (event & EV_MASK_CA) {
+#ifdef SHOW_EVENTS
+ printf ("%p/%p Event Received: CA/", d, d->r);
+#endif
+ if (event & EV_CA_WRITE) {
+#ifdef SHOW_EVENTS
+ printf ("WRITE ");
+#endif
+ while (1) {
+ if (!ioctl (d->fd, DVBLO_GET_TPDU, &tpdu) && tpdu.len) {
+ if (d->c && d->ca_enable) {
+ ci_pdu_t pdu;
+ pdu.len = tpdu.len;
+ pdu.data = tpdu.data;
+ if (!cmd.reelcammode) {
+ pdu.data[0] = d->ci_slot;
+ }
+ ci_write_pdu (d->c, &pdu);
+ event |= EV_PIDFILTER;
+ }
+ } else {
+ break;
+ }
+ }
+ }
+ if (event & EV_CA_RESET) {
+#ifdef SHOW_EVENTS
+ printf ("RESET ");
+#endif
+ last_ci_reset = time (NULL);
+ if (d->ca_enable) {
+ ci_cpl_clear (d->ci_slot);
+ }
+ }
+#ifdef SHOW_EVENTS
+ printf ("\n");
+#endif
+ }
+ if (need_tune) {
+ if (dvblo_tune (d, 1) == 2) {
+ forced = time (NULL);
+ }
+ need_tune = 0;
+ } else if (event & EV_MASK_PID) {
+#ifdef SHOW_EVENTS
+ printf ("%p/%p Event Received: Demux/", d, d->r);
+ if (event & EV_PIDFILTER) {
+ printf ("PID filter: %d pids", d->pids.num);
+ }
+ printf ("\n");
+#endif
+ forced = 0;
+ }
+ }
+ if (forced) {
+ if ((time (NULL) - forced) < TUNE_FORCED_TIMEOUT) {
+ event &= ~EV_PIDFILTER;
+ } else {
+ event |= EV_PIDFILTER;
+ forced = 0;
+ }
+ }
+ if (event & EV_PIDFILTER) {
+ dvblo_convert_pids (d);
+ recv_pids (d->r, d->dstpids);
+ }
+ event = 0;
+ }
+ pthread_cleanup_pop (1);
+ return NULL;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+static dvblo_dev_t *dvblo_add (void)
+{
+ dvblo_dev_t *d = (dvblo_dev_t *) malloc (sizeof (dvblo_dev_t));
+
+ if (!d)
+ return NULL;
+ memset (d, 0, sizeof (dvblo_dev_t));
+ dvbmc_list_add_head (&devs.list, &d->list);
+ return d;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+static void dvblo_del (dvblo_dev_t * d)
+{
+ d->recv_run = 0;
+ if (pthread_exist(d->dvblo_recv_thread) && !pthread_cancel (d->dvblo_recv_thread)) {
+ pthread_join (d->dvblo_recv_thread, NULL);
+ }
+ dvbmc_list_remove (&d->list);
+ free (d);
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+void dvblo_exit (void)
+{
+ dvblo_dev_t *d;
+ dvblo_dev_t *dtmp;
+
+ DVBMC_LIST_FOR_EACH_ENTRY_SAFE (d, dtmp, &devs.list, dvblo_dev_t, list) {
+ dvblo_del (d);
+ }
+}
+
+static dvblo_dev_t *find_dev_by_uuid (dvblo_dev_t * devs, char *uuid)
+{
+ dvblo_dev_t *d;
+ DVBMC_LIST_FOR_EACH_ENTRY (d, &devs->list, dvblo_dev_t, list) {
+ if (!strcmp (d->uuid, uuid)) {
+ return d;
+ }
+ }
+ return NULL;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+static int count_dev_by_type (dvblo_dev_t * devs, fe_type_t type)
+{
+ int ret = 0;
+ dvblo_dev_t *d;
+ DVBMC_LIST_FOR_EACH_ENTRY (d, &devs->list, dvblo_dev_t, list) {
+ if (type == d->type) {
+ ret++;
+ }
+ }
+ return ret;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+satellite_list_t *dvblo_get_sat_list (char *SatelliteListName, netceiver_info_t * nci)
+{
+ int i;
+ dbg ("looking for %s\n", SatelliteListName);
+ for (i = 0; i < nci->sat_list_num; i++) {
+ if (!strcmp (SatelliteListName, nci->sat_list[i].Name)) {
+ dbg ("found uuid in sat list %d\n", i);
+ return nci->sat_list + i;
+ }
+ }
+ return NULL;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+static int diseqc_write_conf (char *disec_conf_path, char *rotor_conf_path, dvblo_dev_t * devs, int mode)
+{
+ int j, k;
+ dvblo_dev_t *d;
+ char buf[80];
+ char tstr[16];
+ FILE *f = NULL;
+ FILE *fr = NULL;
+
+ f = fopen (disec_conf_path, "wt");
+ if (f == NULL) {
+ return 0;
+ }
+ fprintf (f, "# diseqc.conf in VDR format auto generated\n\n");
+
+ if (strlen(rotor_conf_path)) {
+ special_status_mode=1;
+ fr = fopen (rotor_conf_path, "wt");
+ }
+ if (fr)
+ fprintf (fr, "# rotor.conf auto generated\n\n");
+
+ DVBMC_LIST_FOR_EACH_ENTRY (d, &devs->list, dvblo_dev_t, list) {
+ satellite_list_t *sat_list = dvblo_get_sat_list (d->nci->tuner[d->tuner].SatelliteListName, d->nci);
+ if (!sat_list) {
+ continue;
+ }
+ for (j = 0; j < sat_list->sat_num; j++) {
+ satellite_info_t *sat = sat_list->sat + j;
+ for (k = 0; k < sat->comp_num; k++) {
+ satellite_component_t *comp = sat->comp + k;
+ int newpos = sat->SatPos ^ 1800;
+ sprintf (buf, "e0 10 6f %02x %02x %02x", newpos & 0xff, (newpos >> 8) & 0xff, comp->Polarisation << 1 | !(comp->sec.tone_mode & 1));
+ if (mode) {
+ sprintf (tstr, "A%d ", d->device + 1);
+ } else {
+ tstr[0] = 0;
+ }
+ fprintf (f, "%s%s %d %c 0 [ %s ]\n", tstr, sat->Name, comp->RangeMax, comp->Polarisation == POL_H ? 'H' : 'V', buf);
+ }
+ fprintf (f, "\n");
+ if (j==0 && fr && sat->type==SAT_SRC_ROTOR) {
+ fprintf(fr, "%s %i %i %i %i %i\n", tstr, sat->SatPosMin, sat->SatPosMax,
+ sat->AutoFocus, sat->Latitude, sat->Longitude);
+ }
+ }
+ }
+ info ("created %s\n", disec_conf_path);
+ fclose (f);
+ if (fr) {
+ info ("created %s\n", rotor_conf_path);
+ fclose(fr);
+ }
+ return 1;
+}
+
+void dvblo_handler (void)
+{
+ int i;
+ int n;
+ int nci_num = 0;
+ int write_conf = strlen (cmd.disec_conf_path);
+ netceiver_info_list_t *nc_list = nc_get_list ();
+ memset (&cacaps, 0, sizeof (dvblo_cacaps_t));
+
+ info ("Device Type Limits: DVB-S: %d DVB-C: %d DVB-T: %d ATSC: %d DVB-S2: %d\n\n", cmd.tuner_type_limit[FE_QPSK], cmd.tuner_type_limit[FE_QAM], cmd.tuner_type_limit[FE_OFDM], cmd.tuner_type_limit[FE_ATSC], cmd.tuner_type_limit[FE_DVBS2]);
+
+ while (dvblo_run) {
+ nc_lock_list ();
+ for (n = 0; n < nc_list->nci_num; n++) {
+ netceiver_info_t *nci = nc_list->nci + n;
+ for (i = 0; i < nci->tuner_num; i++) {
+ char *uuid = nci->tuner[i].uuid;
+ if (nci->tuner[i].preference < 0 || !strlen (uuid) || find_dev_by_uuid (&devs, uuid)) {
+ //already seen
+ continue;
+ }
+ fe_type_t type = nci->tuner[i].fe_info.type;
+
+ if (type > FE_DVBS2) {
+ continue;
+ }
+ if(dev_num >= MAX_DEVICES) {
+ dbg("Limit dev_num reached limit of "MAX_DEVICES"\n");
+ continue;
+ }
+ if (count_dev_by_type (&devs, type) == cmd.tuner_type_limit[type]) {
+ dbg ("Limit: %d %d>%d\n", type, count_dev_by_type (&devs, type), cmd.tuner_type_limit[type]);
+ continue;
+ }
+
+ dvblo_dev_t *d = dvblo_add ();
+ if (!d) {
+ err ("Cannot get memory for dvb loopback context\n");
+ }
+
+ dbg ("allocate dev %d for uuid %s\n", dev_num, uuid);
+
+ d->info = nci->tuner[i].fe_info;
+
+ if (type == FE_DVBS2) {
+ d->info.type = FE_QPSK;
+ }
+
+ strcpy (d->uuid, nci->tuner[i].uuid);
+ if (!cmd.reelcammode) {
+ if (cidev < CA_MAX_SLOTS && (cmd.ca_enable & (1 << dev_num))) {
+ d->cacaps=(dvblo_cacaps_t*)((void *) &nci->ci);
+ d->ca_enable = 1;
+ dbg ("Enabling CA support for device %d\n", dev_num);
+ char addrstr[INET6_ADDRSTRLEN];
+ dvblo_get_nc_addr (addrstr, d->uuid);
+ dbg ("dvblo_get_nc_addr: %s %s\n", addrstr, d->uuid);
+ d->c = ci_find_dev_by_uuid (addrstr);
+ if (d->c) {
+ dbg ("Attaching ci dev %p to dvblo dev %p\n", d->c, d);
+ ci_register_handler (d->c, cidev, dvblo_write_ci, d);
+ d->ci_slot = cidev++;
+ } else {
+ dvblo_del (d); //retry next time
+ break;
+ }
+ } else {
+ d->cacaps = &cacaps;
+ d->ca_enable = 0;
+ dbg ("Disabling CA support for device %d\n", dev_num);
+ }
+ } else {
+ if (nci->ci.cap.slot_num && cmd.ca_enable) {
+ d->ca_enable = 1;
+ dbg ("Enabling CA support for device %d\n", dev_num);
+ if (!cidev) {
+ d->cacaps = (dvblo_cacaps_t*)((void *) &nci->ci);
+ char addrstr[INET6_ADDRSTRLEN];
+ dvblo_get_nc_addr (addrstr, d->uuid);
+ dbg ("dvblo_get_nc_addr: %s %s\n", addrstr, d->uuid);
+ d->c = ci_find_dev_by_uuid (addrstr);
+ if (d->c) {
+ dbg ("Attaching ci dev %p to dvblo dev %p\n", d->c, d);
+ ci_register_handler (d->c, cidev++, dvblo_write_ci, d);
+ ci_register_handler (d->c, cidev++, dvblo_write_ci, d);
+ } else {
+ dvblo_del (d); //retry next time
+ break;
+ }
+ } else {
+ d->cacaps = &cacaps;
+ }
+ } else {
+ d->cacaps = &cacaps;
+ d->ca_enable = 0;
+ dbg ("Disabling CA support for device %d\n", dev_num);
+ }
+ }
+
+ d->r = recv_add ();
+ if (!d->r) {
+ err ("Cannot get memory for receiver\n");
+ }
+
+ d->device = dev_num++;
+ d->type = type;
+ d->tuner = i;
+ d->nci = nci;
+
+ register_ten_handler (d->r, dvblo_handle_ten, d);
+ register_ts_handler (d->r, dvblo_handle_ts, d);
+
+ info ("Starting thread for tuner UUID %s [%s] at device %d with type %d\n", d->uuid, nci->tuner[i].fe_info.name, nci->tuner[i].slot, nci->tuner[i].fe_info.type);
+ int ret = pthread_create (&d->dvblo_recv_thread, NULL, dvblo_recv, d);
+ while (!ret && !d->recv_run) {
+ usleep (10000);
+ }
+ if (ret) {
+ err ("pthread_create failed with %d\n", ret);
+ }
+ }
+ }
+ if (write_conf) {
+ if (reload || (nci_num != nc_list->nci_num)) {
+ nci_num = nc_list->nci_num;
+ diseqc_write_conf (cmd.disec_conf_path, cmd.rotor_conf_path, &devs, cmd.vdrdiseqcmode);
+ reload = 0;
+ }
+ }
+ nc_unlock_list ();
+ sleep (1);
+ }
+}
diff --git a/mcast/client/dvblo_handler.h b/mcast/client/dvblo_handler.h
new file mode 100644
index 0000000..beaa7ac
--- /dev/null
+++ b/mcast/client/dvblo_handler.h
@@ -0,0 +1,40 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ */
+
+#define MAX_DEVICES 8
+
+typedef struct dvblo_dev {
+ struct list list;
+
+ pthread_t dvblo_recv_thread;
+ char uuid[UUID_SIZE];
+ int device;
+ int fd;
+ pthread_t dvblo_ca_thread;
+ int fd_ca;
+ int recv_run;
+ int ci_slot;
+ int ca_enable;
+
+ fe_type_t type;
+ recv_info_t *r;
+ ci_dev_t *c;
+ struct dvb_frontend_info info;
+ dvblo_cacaps_t *cacaps;
+ dvblo_pids_t pids;
+ dvb_pid_t dstpids[RECV_MAX_PIDS];
+ dvblo_sec_t sec;
+ struct dvb_frontend_parameters fe_parms;
+ tra_t ten;
+ int tuner;
+ netceiver_info_t *nci;
+} dvblo_dev_t;
+
+int dvblo_init (void);
+void dvblo_exit (void);
+void dvblo_handler (void);
diff --git a/mcast/client/headers.h b/mcast/client/headers.h
new file mode 100644
index 0000000..c371395
--- /dev/null
+++ b/mcast/client/headers.h
@@ -0,0 +1,32 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ */
+
+#ifndef __HEADERS_H__
+#define __HEADERS_H__
+
+#include "defs.h"
+#include "version.h"
+#include "list.h"
+#include "satlists.h"
+#include "mcast.h"
+#include "input.h"
+#include "recv_ccpp.h"
+#include "recv_tv.h"
+#include "tools.h"
+#include "interfaces.h"
+#include "mcast.h"
+#include "mld.h"
+#include "api_server.h"
+#include "tca_handler.h"
+#include "tra_handler.h"
+#include "mld_reporter.h"
+#include "ciparser.h"
+#include "ci_handler.h"
+#include "mmi_handler.h"
+#include "siparser.h"
+#endif
diff --git a/mcast/client/inet_aton.c b/mcast/client/inet_aton.c
new file mode 120000
index 0000000..e14646e
--- /dev/null
+++ b/mcast/client/inet_aton.c
@@ -0,0 +1 @@
+../common/win32/inet_aton.c \ No newline at end of file
diff --git a/mcast/client/inet_ntop.c b/mcast/client/inet_ntop.c
new file mode 120000
index 0000000..f6e4222
--- /dev/null
+++ b/mcast/client/inet_ntop.c
@@ -0,0 +1 @@
+../common/win32/inet_ntop.c \ No newline at end of file
diff --git a/mcast/client/inet_pton.c b/mcast/client/inet_pton.c
new file mode 120000
index 0000000..37f2533
--- /dev/null
+++ b/mcast/client/inet_pton.c
@@ -0,0 +1 @@
+../common/win32/inet_pton.c \ No newline at end of file
diff --git a/mcast/client/input.c b/mcast/client/input.c
new file mode 100644
index 0000000..f10cf4f
--- /dev/null
+++ b/mcast/client/input.c
@@ -0,0 +1,145 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ */
+
+#include "headers.h"
+#define CI_RESET_WAIT 10
+
+#ifdef __MINGW32__
+#include <getopt.h>
+#endif
+
+cmdline_t cmd;
+
+//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+static void print_help (int argc, char *argv[])
+{
+ printf ("Usage:\n" \
+ " mcli --ifname <network interface>\n" \
+ " mcli --port <port> (default: -port 23000)\n" \
+ " mcli --dvb-s <num> --dvb-c <num> --dvb-t <num> --atsc <num> --dvb-s2 <num>\n" \
+ " limit number of device types (default: 8 of every type)\n" \
+ " mcli --diseqc-conf <filepath>\n" \
+ " mcli --rotor-conf <filepath>\n" \
+ " mcli --mld-reporter-disable\n" \
+ " mcli --sock-path <filepath>\n"\
+ " mcli --ca-enable <bitmask>\n"\
+ " mcli --ci-timeout <time>\n"\
+ " mcli --vdr-diseqc-bind <0|1>\n"\
+ " mcli --reel-cam-mode\n"\
+ "\n");
+}
+
+//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+static void init_cmd_line_parameters ()
+{
+ int i;
+ memset (&cmd, 0, sizeof (cmdline_t));
+
+ for (i=0; i<=FE_DVBS2; i++) {
+ cmd.tuner_type_limit[i] = 8;
+ }
+ cmd.port = 23000;
+ cmd.mld_start = 1;
+ cmd.ca_enable = 3;
+ cmd.vdrdiseqcmode = 1;
+ cmd.reelcammode = 0;
+ cmd.ci_timeout = CI_RESET_WAIT;
+ strcpy (cmd.cmd_sock_path, API_SOCK_NAMESPACE);
+ cmd.disec_conf_path[0]=0;
+ cmd.rotor_conf_path[0]=0;
+}
+
+//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+void get_options (int argc, char *argv[])
+{
+ int tuners = 0, i;
+ char c;
+ int ret;
+ //init parameters
+ init_cmd_line_parameters ();
+ while (1) {
+ //int this_option_optind = optind ? optind : 1;
+ int option_index = 0;
+ static struct option long_options[] = {
+ {"port", 1, 0, 0}, //0
+ {"ifname", 1, 0, 0}, //1
+ {"help", 0, 0, 0}, //2
+ {"dvb-s", 1, 0, 0}, //3
+ {"dvb-c", 1, 0, 0}, //4
+ {"dvb-t", 1, 0, 0}, //5
+ {"atsc", 1, 0, 0}, //6
+ {"dvb-s2", 1, 0, 0}, //7
+ {"diseqc-conf", 1, 0, 0}, //8
+ {"mld-reporter-disable", 0, 0, 0}, //9
+ {"sock-path", 1, 0, 0}, //10
+ {"ca-enable", 1, 0, 0}, //11
+ {"ci-timeout", 1, 0, 0}, //12
+ {"vdr-diseqc-bind", 1, 0, 0}, //13
+ {"reel-cam-mode", 0, 0, 0}, //14
+ {"rotor-conf", 1, 0, 0}, //15
+ {NULL, 0, 0, 0}
+ };
+
+ ret = getopt_long_only (argc, argv, "", long_options, &option_index);
+ c=(char)ret;
+ if (ret == -1 || c == '?') {
+ break;
+ }
+
+ switch (option_index) {
+ case 0:
+ cmd.port = atoi (optarg);
+ break;
+ case 1:
+ strncpy (cmd.iface, optarg, IFNAMSIZ-1);
+ break;
+ case 2:
+ print_help (argc, argv);
+ exit (0);
+ break;
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ i = atoi (optarg);
+ if (!tuners) {
+ memset (cmd.tuner_type_limit, 0, sizeof (cmd.tuner_type_limit));
+ }
+ cmd.tuner_type_limit[option_index - 3] = i;
+ tuners += i;
+ break;
+ case 8:
+ strncpy (cmd.disec_conf_path, optarg, _POSIX_PATH_MAX-1);
+ break;
+ case 9:
+ cmd.mld_start = 0;
+ break;
+ case 10:
+ strncpy (cmd.cmd_sock_path, optarg, _POSIX_PATH_MAX-1);
+ break;
+ case 11:
+ cmd.ca_enable=atoi(optarg);
+ break;
+ case 12:
+ cmd.ci_timeout=atoi(optarg);
+ break;
+ case 13:
+ cmd.vdrdiseqcmode=atoi(optarg);
+ break;
+ case 14:
+ cmd.reelcammode = 1;
+ break;
+ case 15:
+ strncpy (cmd.rotor_conf_path, optarg, _POSIX_PATH_MAX-1);
+ break;
+ default:
+ printf ("?? getopt returned character code 0%o ??\n", c);
+ }
+ }
+}
diff --git a/mcast/client/interfaces.c b/mcast/client/interfaces.c
new file mode 120000
index 0000000..cd41b03
--- /dev/null
+++ b/mcast/client/interfaces.c
@@ -0,0 +1 @@
+../common/interfaces.c \ No newline at end of file
diff --git a/mcast/client/main.c b/mcast/client/main.c
new file mode 100644
index 0000000..895fced
--- /dev/null
+++ b/mcast/client/main.c
@@ -0,0 +1,83 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ */
+
+#include "headers.h"
+#if ! (defined WIN32 || defined APPLE)
+ #include "dvblo_ioctl.h"
+ #include "dvblo_handler.h"
+#else
+ #include "dummy_client.h"
+#endif
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+int main (int argc, char **argv)
+{
+ printf ("DVB - TV Client Version " MCLI_VERSION_STR " (c) BayCom GmbH\n\n");
+//#if (defined WIN32 || defined APPLE)
+#ifdef WIN32
+#ifndef __MINGW32__
+ cmdline_t cmd;
+ cmd.iface[0]=0;
+ cmd.port=0;
+ cmd.mld_start=1;
+#else
+ get_options (argc, argv);
+#endif
+#else
+#ifdef BACKTRACE
+ signal(SIGSEGV, SignalHandlerCrash);
+ signal(SIGBUS, SignalHandlerCrash);
+ signal(SIGABRT, SignalHandlerCrash);
+#endif
+ get_options (argc, argv);
+#endif
+ recv_init (cmd.iface, cmd.port);
+
+ #ifdef API_SHM
+ api_shm_init();
+ #endif
+ #ifdef API_SOCK
+ api_sock_init(cmd.cmd_sock_path);
+ #endif
+ #ifdef API_WIN
+ api_init(TEXT("\\\\.\\pipe\\mcli"));
+ #endif
+
+ if(cmd.mld_start) {
+ mld_client_init (cmd.iface);
+ }
+#if ! (defined WIN32 || defined APPLE)
+ ci_init(cmd.ca_enable, cmd.iface, cmd.port);
+ dvblo_init();
+
+ dvblo_handler();
+
+ dvblo_exit();
+ ci_exit();
+#else
+ dummy_client ();
+#endif
+
+ if(cmd.mld_start) {
+ mld_client_exit ();
+ }
+
+ #ifdef API_SHM
+ api_shm_exit();
+ #endif
+ #ifdef API_SOCK
+ api_sock_exit();
+ #endif
+ #ifdef API_WIN
+ api_exit();
+ #endif
+
+ recv_exit ();
+
+ return 0;
+}
diff --git a/mcast/client/mcast.c b/mcast/client/mcast.c
new file mode 120000
index 0000000..b2f4f7b
--- /dev/null
+++ b/mcast/client/mcast.c
@@ -0,0 +1 @@
+../common/mcast.c \ No newline at end of file
diff --git a/mcast/client/mingw/.svn/entries b/mcast/client/mingw/.svn/entries
new file mode 100644
index 0000000..23db38d
--- /dev/null
+++ b/mcast/client/mingw/.svn/entries
@@ -0,0 +1,96 @@
+10
+
+dir
+18963
+svn://reelbox.org/testing/src/vdr-plugins/src/mcli-1/mcast/client/mingw
+svn://reelbox.org
+
+
+
+2011-08-18T10:09:14.813360Z
+17158
+dirk
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+12be777f-adf9-0310-842f-e37ecc4c7426
+
+Makefile
+file
+
+
+
+
+2012-09-27T17:22:49.674848Z
+deb39207a48338fe8c29c810cded35f8
+2011-07-12T13:36:23.313379Z
+16905
+rollercoaster
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1469
+
+build.cmd
+file
+
+
+
+
+2012-09-27T17:22:49.674848Z
+f09be9592dd9c22b707bba5dc4591931
+2011-08-18T10:09:14.813360Z
+17158
+dirk
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+44
+
diff --git a/mcast/client/mingw/.svn/text-base/Makefile.svn-base b/mcast/client/mingw/.svn/text-base/Makefile.svn-base
new file mode 100644
index 0000000..356ecf3
--- /dev/null
+++ b/mcast/client/mingw/.svn/text-base/Makefile.svn-base
@@ -0,0 +1,55 @@
+PATH:=/MinGW/bin/:$(PATH)
+CC:=gcc
+
+#Comment this out to disable debugging output
+DEBUG=1
+#VERBOSE=1
+#API_SOCK=1
+
+DEFS=-DCLIENT -DLIBRARY -DWIN32 -D_REENTRANT -D_GNU_SOURCE
+
+ifdef VERBOSE
+DEFS:= $(DEFS) -DDEBUG
+DEBUG=1
+endif
+
+CFLAGS:= $(DEFS) -Wall -Iwin32/include $(CFLAGS)
+LDFLAGS:= -Lwin32/lib $(LDFLAGS)
+LDLIBS:= -lwsock32 -liphlpapi -lpthreadGC2 -lxml2 -lzdll
+
+ifdef DEBUG
+LDFLAGS:= $(LDFLAGS) -g
+CFLAGS:= $(CFLAGS) -g
+else
+#CFLAGS:= $(CFLAGS) -Os
+endif
+
+MCLI = mcli
+MCLI_OBJS = mld_common.o mld_client.o mld_reporter.o mcast.o recv_tv.o recv_ccpp.o tools.o tca_handler.o tra_handler.o satlists.o interfaces.o inet_pton.o inet_ntop.o inet_aton.o
+MCLI_SOBJS := main.o dummy_client.o
+
+all: lib$(MCLI)
+
+lib$(MCLI): $(MCLI_OBJS)
+ $(CC) $(LDFLAGS) -shared -o $@.dll $(MCLI_OBJS) $(LDLIBS) -Wl,--out-implib,$@.a -Wl,--output-def,$@.def
+# $(AR) $(ARFLAGS) $@.a $(MCLI_OBJS)
+ @copy /b $@.dll win32\\lib\\
+ @copy /b $@.a win32\\lib\\
+ @copy /b $@.def win32\\lib\\
+ lib.exe /def:$@.def /machine:x86 /out:win32\\lib\\$@.lib
+ @echo "You can find all libraries in directory win32\lib"
+
+$(MCLI): $(MCLI_OBJS) $(MCLI_SOBJS)
+ $(CC) $(LDFLAGS) -o $@ $(MCLI_OBJS) $(MCLI_SOBJS) $(LDLIBS)
+
+$(MCLI)-shared: lib$(MCLI)
+ $(CC) -c $(CFLAGS) -ULIBRARY -o main.o main.c
+ $(CC) -c $(CFLAGS) -ULIBRARY -o dummy_client.o dummy_client.c
+ $(CC) $(LDFLAGS) -o $@ $(MCLI_SOBJS) $(LDLIBS) -lmcli
+
+clean:
+ @del $(MCLI)*.exe lib$(MCLI).* *.lib *.o *.la *~
+
+%.o: %.c
+ $(CC) -c $(CFLAGS) -o $@ $<
+
diff --git a/mcast/client/mingw/.svn/text-base/build.cmd.svn-base b/mcast/client/mingw/.svn/text-base/build.cmd.svn-base
new file mode 100644
index 0000000..3d3efdb
--- /dev/null
+++ b/mcast/client/mingw/.svn/text-base/build.cmd.svn-base
@@ -0,0 +1,2 @@
+@set PATH=c:\MinGw\bin;%PATH%
+@mingw32-make
diff --git a/mcast/client/mingw/Makefile b/mcast/client/mingw/Makefile
new file mode 100644
index 0000000..356ecf3
--- /dev/null
+++ b/mcast/client/mingw/Makefile
@@ -0,0 +1,55 @@
+PATH:=/MinGW/bin/:$(PATH)
+CC:=gcc
+
+#Comment this out to disable debugging output
+DEBUG=1
+#VERBOSE=1
+#API_SOCK=1
+
+DEFS=-DCLIENT -DLIBRARY -DWIN32 -D_REENTRANT -D_GNU_SOURCE
+
+ifdef VERBOSE
+DEFS:= $(DEFS) -DDEBUG
+DEBUG=1
+endif
+
+CFLAGS:= $(DEFS) -Wall -Iwin32/include $(CFLAGS)
+LDFLAGS:= -Lwin32/lib $(LDFLAGS)
+LDLIBS:= -lwsock32 -liphlpapi -lpthreadGC2 -lxml2 -lzdll
+
+ifdef DEBUG
+LDFLAGS:= $(LDFLAGS) -g
+CFLAGS:= $(CFLAGS) -g
+else
+#CFLAGS:= $(CFLAGS) -Os
+endif
+
+MCLI = mcli
+MCLI_OBJS = mld_common.o mld_client.o mld_reporter.o mcast.o recv_tv.o recv_ccpp.o tools.o tca_handler.o tra_handler.o satlists.o interfaces.o inet_pton.o inet_ntop.o inet_aton.o
+MCLI_SOBJS := main.o dummy_client.o
+
+all: lib$(MCLI)
+
+lib$(MCLI): $(MCLI_OBJS)
+ $(CC) $(LDFLAGS) -shared -o $@.dll $(MCLI_OBJS) $(LDLIBS) -Wl,--out-implib,$@.a -Wl,--output-def,$@.def
+# $(AR) $(ARFLAGS) $@.a $(MCLI_OBJS)
+ @copy /b $@.dll win32\\lib\\
+ @copy /b $@.a win32\\lib\\
+ @copy /b $@.def win32\\lib\\
+ lib.exe /def:$@.def /machine:x86 /out:win32\\lib\\$@.lib
+ @echo "You can find all libraries in directory win32\lib"
+
+$(MCLI): $(MCLI_OBJS) $(MCLI_SOBJS)
+ $(CC) $(LDFLAGS) -o $@ $(MCLI_OBJS) $(MCLI_SOBJS) $(LDLIBS)
+
+$(MCLI)-shared: lib$(MCLI)
+ $(CC) -c $(CFLAGS) -ULIBRARY -o main.o main.c
+ $(CC) -c $(CFLAGS) -ULIBRARY -o dummy_client.o dummy_client.c
+ $(CC) $(LDFLAGS) -o $@ $(MCLI_SOBJS) $(LDLIBS) -lmcli
+
+clean:
+ @del $(MCLI)*.exe lib$(MCLI).* *.lib *.o *.la *~
+
+%.o: %.c
+ $(CC) -c $(CFLAGS) -o $@ $<
+
diff --git a/mcast/client/mingw/build.cmd b/mcast/client/mingw/build.cmd
new file mode 100644
index 0000000..3d3efdb
--- /dev/null
+++ b/mcast/client/mingw/build.cmd
@@ -0,0 +1,2 @@
+@set PATH=c:\MinGw\bin;%PATH%
+@mingw32-make
diff --git a/mcast/client/mld_client.c b/mcast/client/mld_client.c
new file mode 120000
index 0000000..2737525
--- /dev/null
+++ b/mcast/client/mld_client.c
@@ -0,0 +1 @@
+../common/mld_client.c \ No newline at end of file
diff --git a/mcast/client/mld_common.c b/mcast/client/mld_common.c
new file mode 120000
index 0000000..2bf5a0d
--- /dev/null
+++ b/mcast/client/mld_common.c
@@ -0,0 +1 @@
+../common/mld_common.c \ No newline at end of file
diff --git a/mcast/client/mld_reporter.c b/mcast/client/mld_reporter.c
new file mode 100644
index 0000000..e0530ab
--- /dev/null
+++ b/mcast/client/mld_reporter.c
@@ -0,0 +1,225 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ */
+
+#undef DEBUG
+#include "headers.h"
+
+extern pthread_mutex_t lock;
+extern recv_info_t receivers;
+
+extern int mld_start;
+static pthread_t mld_send_reports_thread;
+static char iface[IFNAMSIZ];
+
+static int find_mcg_in_mld_mcas (struct in6_addr *mld_mca, int len, struct in6_addr *mcg)
+{
+ int i;
+
+ for (i = 0; i < len; i++) {
+ if (!memcmp (mld_mca + i, mcg, sizeof (struct in6_addr))) {
+ return 1;
+ }
+ }
+ return 0;
+}
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+typedef struct {
+ struct in6_addr *mld_mca_add;
+ struct in6_addr *mld_mca_drop;
+} mld_reporter_context_t;
+
+static void clean_mld_send_reports_thread(void *p)
+{
+ mld_reporter_context_t *c=(mld_reporter_context_t*)p;
+ if(c->mld_mca_add) {
+ free(c->mld_mca_add);
+ }
+ if(c->mld_mca_drop) {
+ free(c->mld_mca_drop);
+ }
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+static void *mld_send_reports (void *arg)
+{
+ recv_info_t *receivers = (recv_info_t *) arg;
+
+ int grec_num_drop;
+ int grec_num_add;
+ pid_info_t *p;
+ pid_info_t *ptmp;
+ recv_info_t *r;
+ int maxpids=128;
+ mld_reporter_context_t c;
+ memset(&c, 0, sizeof(mld_reporter_context_t));
+
+ c.mld_mca_add=(struct in6_addr *)malloc(maxpids*sizeof(struct in6_addr));
+ if (!c.mld_mca_add)
+ err ("mld_send_reports: out of memory\n");
+ c.mld_mca_drop=(struct in6_addr *)malloc(maxpids*sizeof(struct in6_addr));
+ if (!c.mld_mca_drop)
+ err ("mld_send_reports: out of memory\n");
+
+ pthread_cleanup_push (clean_mld_send_reports_thread, &c);
+
+ struct intnode *intn = int_find_name (iface);
+
+ if( !c.mld_mca_add || !c.mld_mca_drop) {
+ err ("Cannot get memory for add/drop list\n");
+ }
+ mld_start=1;
+ while (mld_start) {
+ grec_num_drop=0;
+ pthread_mutex_lock (&lock);
+
+ int pids=count_all_pids(receivers);
+ if(pids>maxpids) {
+ maxpids=pids;
+ c.mld_mca_add=(struct in6_addr *)realloc(c.mld_mca_add, pids*sizeof(struct in6_addr));
+ if (!c.mld_mca_add)
+ err ("mld_send_reports: out of memory\n");
+ c.mld_mca_drop=(struct in6_addr *)realloc(c.mld_mca_drop, pids*sizeof(struct in6_addr));
+ if (!c.mld_mca_drop)
+ err ("mld_send_reports: out of memory\n");
+ }
+
+ //Send listener reports for all recently dropped MCGs
+ DVBMC_LIST_FOR_EACH_ENTRY (r, &receivers->list, recv_info_t, list) {
+ DVBMC_LIST_FOR_EACH_ENTRY_SAFE (p, ptmp, &r->slots.list, pid_info_t, list) {
+ // prevent a somewhere running mcg on any device to be dropped and prevent to drop same mcg multiple times
+ if (!p->run) {
+ if ( p->dropped && !find_any_slot_by_mcg (receivers, &p->mcg) && !find_mcg_in_mld_mcas (c.mld_mca_drop, grec_num_drop, &p->mcg)) {
+ memcpy (c.mld_mca_drop + grec_num_drop++, &p->mcg.s6_addr, sizeof (struct in6_addr));
+ p->dropped--;
+#ifdef DEBUG
+ char host[INET6_ADDRSTRLEN];
+ inet_ntop (AF_INET6, p->mcg.s6_addr, (char *) host, INET6_ADDRSTRLEN);
+ dbg ("DROP_GROUP %d %s\n", grec_num_drop, host);
+#endif
+ } else {
+ dvbmc_list_remove(&p->list);
+ free(p);
+ }
+ }
+ }
+ }
+ if(grec_num_drop > maxpids) {
+ err ("Wrong number of pids: %d>%d\n", grec_num_drop, maxpids);
+ }
+ grec_num_add=0;
+ //Send listener reports for all current MCG in use
+ DVBMC_LIST_FOR_EACH_ENTRY (r, &receivers->list, recv_info_t, list) {
+ DVBMC_LIST_FOR_EACH_ENTRY (p, &r->slots.list, pid_info_t, list) {
+ if (p->run && !find_mcg_in_mld_mcas (c.mld_mca_add, grec_num_add, &p->mcg)) {
+ memcpy (c.mld_mca_add + grec_num_add++, p->mcg.s6_addr, sizeof (struct in6_addr));
+#ifdef DEBUG
+ char host[INET6_ADDRSTRLEN];
+ inet_ntop (AF_INET6, &p->mcg.s6_addr, (char *) host, INET6_ADDRSTRLEN);
+ dbg ("ADD_GROUP %d %s\n", grec_num_add, host);
+#endif
+ }
+ }
+ }
+
+ if(grec_num_add > maxpids) {
+ err ("Wrong number of pids: %d>%d\n", grec_num_add, maxpids);
+ }
+
+ pthread_mutex_unlock (&lock);
+
+ if (intn && intn->mtu) {
+ if (grec_num_drop) {
+ send_mldv2_report (intn, grec_num_drop, c.mld_mca_drop, 0, NULL, MLD2_MODE_IS_INCLUDE);
+ }
+ if (grec_num_add) {
+ send_mldv2_report (intn, grec_num_add, c.mld_mca_add, 0, NULL, MLD2_MODE_IS_EXCLUDE);
+ }
+ }
+ usleep (REP_TIME);
+ pthread_testcancel();
+ }
+ pthread_cleanup_pop (1);
+ return NULL;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+int mld_client_init (char *intf)
+{
+ if(intf) {
+ strcpy(iface, intf);
+ } else {
+ iface[0]=0;
+ }
+
+ if (!strlen (iface)) {
+ struct intnode *intn = int_find_first ();
+ if (intn) {
+ strcpy (iface, intn->name);
+ } else {
+ warn ("Cannot find any usable network interface\n");
+ return -1;
+ }
+ }
+
+#if ! (defined WIN32 || defined APPLE)
+ g_conf->rawsocket = socket (PF_PACKET, SOCK_DGRAM, htons (ETH_P_ALL));
+#endif
+#ifdef WIN32
+ g_conf->rawsocket = socket (PF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
+#endif
+#ifdef APPLE
+ g_conf->rawsocket = socket (PF_INET6, SOCK_RAW, IPPROTO_HOPOPTS);
+#endif
+ if (g_conf->rawsocket < 0) {
+ warn ("Cannot get a packet socket\n");
+ return -1;
+ }
+#ifdef WIN32
+ #define IPV6_HDRINCL 2
+ DWORD n=1;
+ if (setsockopt (g_conf->rawsocket, IPPROTO_IPV6, IPV6_HDRINCL, (char *)&n, sizeof (n)) < 0) {
+ err ("setsockopt IPV6_HDRINCL");
+ }
+ int idx;
+ if ((idx = if_nametoindex (iface))>0) {
+ int ret=setsockopt (g_conf->rawsocket, IPPROTO_IPV6, IPV6_MULTICAST_IF, (_SOTYPE)&idx, sizeof (idx));
+ if(ret<0) {
+ warn("setsockopt for IPV6_MULTICAST_IF failed with %d error %s (%d)\n",ret,strerror (errno), errno);
+ }
+ }
+#endif
+ pthread_create (&mld_send_reports_thread, NULL, mld_send_reports, &receivers);
+ return 0;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+void mld_client_exit (void)
+{
+ if(g_conf) {
+ mld_start=0;
+ if(pthread_exist(mld_send_reports_thread)) {
+ if(pthread_exist(mld_send_reports_thread) && !pthread_cancel (mld_send_reports_thread)) {
+ pthread_join (mld_send_reports_thread, NULL);
+ }
+ }
+#if 0
+ struct intnode *intn;
+ unsigned int i;
+ for (i = 0; i < g_conf->maxinterfaces; i++) {
+ intn = &g_conf->ints[i];
+ if (intn->mtu == 0)
+ continue;
+ int_destroy (intn);
+ }
+#endif
+ closesocket(g_conf->rawsocket);
+ }
+}
diff --git a/mcast/client/mld_reporter.h b/mcast/client/mld_reporter.h
new file mode 100644
index 0000000..3036061
--- /dev/null
+++ b/mcast/client/mld_reporter.h
@@ -0,0 +1,11 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ */
+
+DLL_SYMBOL int mld_client_init (char *intf);
+DLL_SYMBOL void mld_client_exit (void);
+
diff --git a/mcast/client/mmi_handler.c b/mcast/client/mmi_handler.c
new file mode 100644
index 0000000..716c7f1
--- /dev/null
+++ b/mcast/client/mmi_handler.c
@@ -0,0 +1,336 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ * modified by Reel Multimedia, http://www.reel-multimedia.com, info@reel-multimedia.com
+ * 01042010 DL: use a single thread for reading from network layer (uses less resources)
+ *
+ */
+
+#include "headers.h"
+
+//---------------------------------------------------------------------------------------------
+void mmi_print_info (mmi_info_t * m)
+{
+ char str[INET6_ADDRSTRLEN];
+ printf ("------------------\n");
+ inet_ntop (AF_INET6, &m->ipv6, (char *) str, INET6_ADDRSTRLEN);
+ printf ("IP: %s\n", str);
+ printf ("UUID: %s\n", m->uuid);
+ printf ("Slot: %d\n", m->slot);
+
+ int i;
+ for (i = 0; i < m->caid_num; i++) {
+ caid_mcg_t *cm = m->caids + i;
+ printf ("%i.SID: %d\n", i, cm->caid);
+ inet_ntop (AF_INET6, &cm->mcg, (char *) str, INET6_ADDRSTRLEN);
+ printf ("%i.MCG: %s\n", i, str);
+ }
+ printf ("TEXT:\n===================\n %s \n===================\n", m->mmi_text);
+
+}
+
+//---------------------------------------------------------------------------------------------
+int mmi_open_menu_session (char *uuid, char *intf, int port, int cmd)
+{
+ int ret;
+ int j, sockfd;
+ struct in6_addr ipv6;
+ char iface[IFNAMSIZ];
+
+ inet_pton (AF_INET6, uuid, &ipv6);
+
+ if (!intf || !strlen (intf)) {
+ struct intnode *intn = int_find_first ();
+ if (intn) {
+ strcpy (iface, intn->name);
+ }
+ } else {
+ strncpy (iface, intf, sizeof (iface));
+ iface[sizeof (iface) - 1] = 0;
+ }
+ if (!port) {
+ port = 23013;
+ }
+
+ sockfd = socket (PF_INET6, SOCK_STREAM, 0);
+ j = 1;
+ if (setsockopt (sockfd, SOL_SOCKET, SO_REUSEADDR, (_SOTYPE) & j, sizeof (j)) < 0) {
+ err ("setsockopt REUSEADDR\n");
+ }
+
+ j = 1;
+ if (setsockopt (sockfd, SOL_SOCKET, TCP_NODELAY, (_SOTYPE) & j, sizeof (j)) < 0) {
+ warn ("setsockopt TCP_NODELAY\n");
+ }
+
+ dbg ("Connect To: %s\n", uuid);
+
+ struct sockaddr_in6 addr;
+ memset (&addr, 0, sizeof (struct sockaddr_in6));
+
+ addr.sin6_family = AF_INET6;
+ addr.sin6_port = htons (port);
+ addr.sin6_addr = ipv6;
+ addr.sin6_scope_id = if_nametoindex (iface);
+
+ ret = connect (sockfd, (struct sockaddr *) &addr, sizeof (struct sockaddr_in6));
+ if (ret < 0) {
+ dbg ("Failed to access NetCeiver MMI support\n");
+ return -1;
+ }
+ //send init cmd
+ char buf[128];
+ memset (buf, 0, sizeof (buf));
+ dbg ("Request CAM slot %d \n", cmd);
+ sprintf (buf, "%x", cmd);
+ int n = send (sockfd, buf, strlen (buf) + 1, 0);
+ if (n < 0) {
+ dbg ("unable to sent mmi connection cmd !\n");
+ closesocket (sockfd);
+ return -1;
+ }
+ dbg ("MMI SESSION : OK\n");
+ return sockfd;
+}
+
+//---------------------------------------------------------------------------------------------
+void mmi_close_menu_session (int s)
+{
+ closesocket (s);
+}
+
+//---------------------------------------------------------------------------------------------
+int mmi_cam_reset (char *uuid, char *intf, int port, int slot)
+{
+ int cmd = (slot << 12) | 0xfff;
+ printf ("Reseting slot %d (cmd %x)...\n", slot, cmd);
+ int sock = mmi_open_menu_session (uuid, intf, port, cmd);
+ if (sock < 1) {
+ printf ("Unable to reset slot %d on netceiver %s...\n", slot, uuid);
+ }
+ closesocket (sock);
+ return 0;
+}
+//---------------------------------------------------------------------------------------------
+int mmi_cam_reinit (char *uuid, char *intf, int port, int slot)
+{
+ int cmd = (slot << 12) | 0xeee;
+ printf ("Reinitializing slot %d (cmd %x)...\n", slot, cmd);
+ int sock = mmi_open_menu_session (uuid, intf, port, cmd);
+ if (sock < 1) {
+ printf ("Unable to reset slot %d on netceiver %s...\n", slot, uuid);
+ }
+ closesocket (sock);
+ return 0;
+}
+//---------------------------------------------------------------------------------------------
+int mmi_get_menu_text (int sockfd, char *buf, int buf_len, int timeout)
+{
+ int n = -1;
+ struct pollfd p;
+ memset (buf, 0, buf_len);
+ p.fd = sockfd;
+ p.events = POLLIN;
+ if (poll (&p, 1, (timeout+999)>>10) > 0) {
+ n = recv (sockfd, buf, buf_len, 0); //MSG_DONTWAIT);
+ }
+ if (n > 0) {
+ dbg ("recv:\n%s \n", buf);
+ }
+ return n;
+}
+
+//---------------------------------------------------------------------------------------------
+int mmi_send_menu_answer (int sockfd, char *buf, int buf_len)
+{
+ dbg ("send: %s len %d \n", buf, buf_len);
+ int n;
+ n = send (sockfd, buf, buf_len, 0);
+ if (n < 0) {
+ dbg ("mmi_send_answer: error sending !\n");
+ }
+ return n;
+}
+
+//---------------------------------------------------------------------------------------------
+UDPContext *mmi_broadcast_client_init (int port, char *intf)
+{
+ UDPContext *s;
+ char mcg[1024];
+ char iface[IFNAMSIZ];
+ //FIXME: move to common
+ strcpy (mcg, "ff18:6000::");
+ if (!intf || !strlen (intf)) {
+ struct intnode *intn = int_find_first ();
+ if (intn) {
+ strcpy (iface, intn->name);
+ }
+ } else {
+ strncpy (iface, intf, sizeof (iface));
+ iface[sizeof (iface) - 1] = 0;
+ }
+ if (!port) {
+ port = 23000;
+ }
+
+ s = client_udp_open_host (mcg, port, iface);
+ if (!s) {
+ dbg ("client udp open host error !\n");
+ }
+
+ return s;
+}
+
+void mmi_broadcast_client_exit (UDPContext * s)
+{
+ udp_close (s);
+}
+
+//---------------------------------------------------------------------------------------------
+typedef struct
+{
+ xmlDocPtr doc;
+ xmlChar *str, *key;
+} xml_parser_context_t;
+
+static void clean_xml_parser_thread (void *arg)
+{
+ xml_parser_context_t *c = (xml_parser_context_t *) arg;
+ if (c->str) {
+ xmlFree (c->str);
+ }
+ if (c->key) {
+ xmlFree (c->key);
+ }
+ if (c->doc) {
+ xmlFreeDoc (c->doc);
+ }
+ dbg ("Free XML parser structures!\n");
+}
+
+//---------------------------------------------------------------------------------------------
+int mmi_get_data (xmlChar * xmlbuff, int buffersize, mmi_info_t * mmi_info)
+{
+ xml_parser_context_t c;
+ xmlNode *root_element = NULL, *cur_node = NULL;
+
+ xmlKeepBlanksDefault (0); //reomve this f. "text" nodes
+ c.doc = xmlParseMemory ((char *) xmlbuff, buffersize);
+ root_element = xmlDocGetRootElement (c.doc);
+ pthread_cleanup_push (clean_xml_parser_thread, &c);
+
+
+ if (root_element != NULL) {
+ cur_node = root_element->children;
+ if (!xmlStrcmp (cur_node->name, (xmlChar *) "Description")) {
+ root_element = cur_node->children;
+ while (root_element != NULL) {
+ c.key = NULL;
+ c.str = NULL;
+ if ((xmlStrcmp (root_element->name, (const xmlChar *) "component"))) {
+ warn ("Cannot parse XML data\n");
+ root_element = root_element->next;
+ continue;
+ }
+ cur_node = root_element->children;
+ if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "Description"))) {
+ c.str = xmlGetProp (cur_node, (unsigned char *) "about");
+ //fprintf(stdout,"\n%s:\n",c.str);
+ //fprintf(stdout,"-----------------------------------------------------------\n");
+ } else {
+ warn ("Cannot parse XML data\n");
+ root_element = root_element->next;
+ continue;
+ }
+ if (c.str && (!xmlStrcmp (c.str, (const xmlChar *) "MMIData"))) {
+ cur_node = cur_node->children;
+ while (cur_node != NULL) {
+ if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "IP"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("IP: %s\n", c.key);
+ inet_pton (AF_INET6, (char *) c.key, &mmi_info->ipv6);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "UUID"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("UUID: %s\n", c.key);
+ strcpy (mmi_info->uuid, (char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "Slot"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("Slot: %s\n", c.key);
+ mmi_info->slot = atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "TEXT"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("TEXT: %s\n", c.key);
+ int olen = MMI_TEXT_LENGTH, ilen = strlen ((char *) c.key);
+
+ UTF8Toisolat1 ((unsigned char *) mmi_info->mmi_text, &olen, c.key, &ilen);
+
+ xmlFree (c.key);
+ }
+ }
+ cur_node = cur_node->next;
+ }
+ } else if (c.str && (!xmlStrcmp (c.str, (const xmlChar *) "ProgramNumberIDs"))) {
+ cur_node = cur_node->children;
+ while (cur_node != NULL) {
+ if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "MCG"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("MCG: %s\n", c.key);
+ struct in6_addr mcg;
+ inet_pton (AF_INET6, (char *) c.key, &mcg);
+ int sid;
+ mcg_get_id (&mcg, &sid);
+ mcg_set_id (&mcg, 0);
+ mmi_info->caids = (caid_mcg_t *) realloc (mmi_info->caids, sizeof (caid_mcg_t) * (mmi_info->caid_num + 1));
+ if (!mmi_info->caids)
+ err ("mmi_get_data: out of memory\n");
+ caid_mcg_t *cm = mmi_info->caids + mmi_info->caid_num;
+ cm->caid = sid;
+ cm->mcg = mcg;
+ mmi_info->caid_num++;
+ xmlFree (c.key);
+ }
+ }
+ cur_node = cur_node->next;
+ }
+ }
+ xmlFree (c.str);
+ root_element = root_element->next;
+ }
+ }
+ }
+
+ xmlFreeDoc (c.doc);
+ pthread_cleanup_pop (0);
+ return 1;
+}
+
+//---------------------------------------------------------------------------------------------
+int mmi_poll_for_menu_text (UDPContext * s, mmi_info_t * m, int timeout)
+{
+ char buf[8192];
+ int n = 0;
+ if (s) {
+ n = udp_read (s, (unsigned char *) buf, sizeof (buf), timeout, NULL);
+ if (n > 0) {
+ dbg ("recv:\n%s \n", buf);
+ memset (m, 0, sizeof (mmi_info_t));
+ mmi_get_data ((xmlChar *) buf, n, m);
+ }
+ }
+ return n;
+}
+//---------------------------------------------------------------------------------------------
diff --git a/mcast/client/mmi_handler.h b/mcast/client/mmi_handler.h
new file mode 100644
index 0000000..37b0af5
--- /dev/null
+++ b/mcast/client/mmi_handler.h
@@ -0,0 +1,46 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ */
+
+#ifndef _MMI_HANDLER_H
+#define _MMI_HANDLER_H
+
+#define MMI_TEXT_LENGTH 1024
+
+typedef struct caid_mcg {
+
+ int caid;
+ struct in6_addr mcg;
+
+
+} caid_mcg_t;
+
+typedef struct mmi_info {
+
+ int slot;
+ caid_mcg_t *caids;
+ int caid_num;
+
+ struct in6_addr ipv6;
+ char uuid[UUID_SIZE];
+
+ char mmi_text[MMI_TEXT_LENGTH];
+
+} mmi_info_t;
+
+DLL_SYMBOL void mmi_print_info(mmi_info_t *m);
+DLL_SYMBOL int mmi_get_menu_text(int sockfd, char *buf, int buf_len, int timeout);
+DLL_SYMBOL int mmi_send_menu_answer(int sockfd, char *buf, int buf_len);
+DLL_SYMBOL UDPContext *mmi_broadcast_client_init(int port, char *iface);
+DLL_SYMBOL void mmi_broadcast_client_exit(UDPContext *s);
+DLL_SYMBOL int mmi_poll_for_menu_text(UDPContext *s, mmi_info_t *m, int timeout);
+DLL_SYMBOL int mmi_open_menu_session(char *uuid, char *iface,int port, int cmd);
+DLL_SYMBOL void mmi_close_menu_session(int s);
+DLL_SYMBOL int mmi_cam_reset(char *uuid, char *intf, int port, int slot);
+DLL_SYMBOL int mmi_cam_reinit(char *uuid, char *intf, int port, int slot);
+
+#endif
diff --git a/mcast/client/recv_ccpp.c b/mcast/client/recv_ccpp.c
new file mode 120000
index 0000000..69e4b7e
--- /dev/null
+++ b/mcast/client/recv_ccpp.c
@@ -0,0 +1 @@
+../common/recv_ccpp.c \ No newline at end of file
diff --git a/mcast/client/recv_tv.c b/mcast/client/recv_tv.c
new file mode 100644
index 0000000..f453ed4
--- /dev/null
+++ b/mcast/client/recv_tv.c
@@ -0,0 +1,905 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ * modified by Reel Multimedia, http://www.reel-multimedia.com, info@reel-multimedia.com
+ * 01042010 DL: use a single thread for reading from network layer (uses less resources)
+ *
+ */
+
+//#define DEBUG 1
+#include "headers.h"
+#if ! defined WIN32 || defined __CYGWIN__
+#define RT
+#endif
+
+#define RE 1
+
+#if defined(RE)
+int set_redirected(recv_info_t *r, int sid);
+int check_if_already_redirected(recv_info_t *r, int sid);
+#endif
+
+recv_info_t receivers;
+pthread_mutex_t lock;
+
+int mld_start=0;
+
+int port=23000;
+char iface[IFNAMSIZ];
+
+static pthread_t recv_tra_thread;
+static pthread_t recv_tca_thread;
+
+#if ! defined WIN32 || defined __CYGWIN__
+static void sig_handler (int signal)
+{
+ dbg ("Signal: %d\n", signal);
+
+ switch (signal) {
+ case SIGUSR1:
+ recv_show_all_pids (&receivers);
+ break;
+ }
+}
+#endif
+
+#ifdef MULTI_THREAD_RECEIVER
+static void clean_recv_ts_thread (void *arg)
+{
+ pid_info_t *p = (pid_info_t *) arg;
+#ifdef DEBUG
+ dbg ("Stop stream receiving for pid %d\n", p->pid.pid);
+#endif
+
+ if (p->s) {
+ udp_close (p->s);
+ }
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+static void *recv_ts (void *arg)
+{
+ unsigned char buf[32712];
+ unsigned char *ptr;
+ int n, res;
+ int cont_old = -1;
+
+ pid_info_t *p = (pid_info_t *) arg;
+ recv_info_t *r = p->recv;
+
+#ifdef RT
+#if 1
+ if (setpriority (PRIO_PROCESS, 0, -15) == -1)
+#else
+ if (pthread_setschedprio (p->recv_ts_thread, -15))
+#endif
+ {
+ dbg ("Cannot raise priority to -15\n");
+ }
+#endif
+
+ pthread_cleanup_push (clean_recv_ts_thread, p);
+#ifdef DEBUG
+ char addr_str[INET6_ADDRSTRLEN];
+ inet_ntop (AF_INET6, p->mcg.s6_addr, addr_str, INET6_ADDRSTRLEN);
+ dbg ("Start stream receiving for %s on port %d %s\n", addr_str, port, iface);
+#endif
+ p->s = client_udp_open (&p->mcg, port, iface);
+ if (!p->s) {
+ warn ("client_udp_open error !\n");
+ } else {
+ p->run = 1;
+ }
+ while (p->run>0) {
+ n = udp_read (p->s, buf, sizeof (buf), 1000, NULL);
+ if (n >0 ) {
+ ptr = buf;
+ if (n % 188) {
+ warn ("Received %d bytes is not multiple of 188!\n", n);
+ }
+ int i;
+ for (i = 0; i < (n / 188); i++) {
+ unsigned char *ts = buf + (i * 188);
+ int adaption_field = (ts[3] >> 4) & 3;
+ int cont = ts[3] & 0xf;
+ int pid = ((ts[1] << 8) | ts[2]) & 0x1fff;
+ int transport_error_indicator = ts[1]&0x80;
+
+ if (pid != 8191 && (adaption_field & 1) && (((cont_old + 1) & 0xf) != cont) && cont_old >= 0) {
+ warn ("Discontinuity on receiver %p for pid %d: %d->%d at pos %d/%d\n", r, pid, cont_old, cont, i, n / 188);
+ }
+ if (transport_error_indicator) {
+ warn ("Transport error indicator set on receiver %p for pid %d: %d->%d at pos %d/%d\n", r, pid, cont_old, cont, i, n / 188);
+ }
+ cont_old = cont;
+ }
+ if(r->handle_ts) {
+ while (n) {
+ res = r->handle_ts (ptr, n, r->handle_ts_context);
+ if (res != n) {
+ warn ("Not same amount of data written: res:%d<=n:%d\n", res, n);
+ }
+ if (res < 0) {
+ warn ("write of %d bytes returned %d\n", n, res);
+ perror ("Write failed");
+ break;
+ } else {
+ ptr += res;
+ n -= res;
+ }
+ }
+ }
+ }
+ pthread_testcancel();
+ }
+ pthread_cleanup_pop (1);
+
+ return NULL;
+ }
+
+#else
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+static void recv_ts_func (unsigned char *buf, int n, void *arg) {
+ if (n >0 ) {
+ pid_info_t *p = (pid_info_t *) arg;
+ recv_info_t *r = p->recv;
+ int i;
+ for (i = 0; i < n; i += 188) {
+ unsigned char *ts = buf + i;
+ int adaption_field = (ts[3] >> 4) & 3;
+ int cont = ts[3] & 0xf;
+ int pid = ((ts[1] << 8) | ts[2]) & 0x1fff;
+ int transport_error_indicator = ts[1]&0x80;
+
+ if (pid != 8191 && (adaption_field & 1) && (((p->cont_old + 1) & 0xf) != cont) && p->cont_old >= 0) {
+ warn ("Discontinuity on receiver %p for pid %d: %d->%d at pos %d/%d\n", r, pid, p->cont_old, cont, i / 188, n / 188);
+ }
+ if (transport_error_indicator) {
+ warn ("Transport error indicator set on receiver %p for pid %d: %d->%d at pos %d/%d\n", r, pid, p->cont_old, cont, i / 188, n / 188);
+ }
+ p->cont_old = cont;
+ }
+ if (i != n) {
+ warn ("Received %d bytes is not multiple of 188!\n", n);
+ }
+ if(r->handle_ts) {
+ while (n) {
+ int res = r->handle_ts (buf, n, r->handle_ts_context);
+ if (res != n) {
+ warn ("Not same amount of data written: res:%d<=n:%d\n", res, n);
+ }
+ if (res < 0) {
+ warn ("write of %d bytes returned %d\n", n, res);
+ perror ("Write failed");
+ break;
+ } else {
+ buf += res;
+ n -= res;
+ }
+ }
+ }
+ }
+}
+#endif
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+int register_ts_handler (recv_info_t * r, int (*p)(unsigned char *, size_t, void *), void *c)
+{
+ r->handle_ts=(int (*)(unsigned char *buffer, size_t len, void *context))p;
+ r->handle_ts_context=c;
+ return 0;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+static pid_info_t *find_slot_by_pid (recv_info_t * r, int pid, int id)
+{
+ pid_info_t *slot;
+ DVBMC_LIST_FOR_EACH_ENTRY (slot, &r->slots.list, pid_info_t, list) {
+ if (slot->run && slot->pid.pid == pid && (id == -1 || slot->pid.id == id)) {
+ return slot;
+ }
+ }
+
+ return NULL;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+static pid_info_t *find_slot_by_mcg (recv_info_t * r, struct in6_addr *mcg)
+{
+ pid_info_t *slot;
+
+ DVBMC_LIST_FOR_EACH_ENTRY (slot, &r->slots.list, pid_info_t, list) {
+ if (slot->run && !memcmp (&slot->mcg, mcg, sizeof (struct in6_addr))) {
+ return slot;
+ }
+ }
+ return NULL;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+int find_any_slot_by_mcg (recv_info_t * receivers, struct in6_addr *mcg)
+{
+ recv_info_t *r;
+ int ret=0;
+
+ DVBMC_LIST_FOR_EACH_ENTRY (r, &receivers->head->list, recv_info_t, list) {
+ pid_info_t *slot = find_slot_by_mcg (r, mcg);
+ if(slot) {
+ ret++;
+ }
+ }
+ return ret;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+int count_receivers(recv_info_t *receivers)
+{
+ int ret=0;
+ struct list *pos;
+
+ DVBMC_LIST_FOR_EACH (pos, &receivers->list) {
+ ret++;
+ }
+ return ret;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+static int count_pids(recv_info_t *r)
+{
+ int ret=0;
+ struct list *pos;
+
+ DVBMC_LIST_FOR_EACH (pos, &r->slots.list) {
+ ret++;
+ }
+ return ret;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+int count_all_pids (recv_info_t * receivers)
+{
+ int ret=0;
+ recv_info_t *r;
+
+ DVBMC_LIST_FOR_EACH_ENTRY (r, &receivers->head->list, recv_info_t, list) {
+ ret += count_pids(r);
+ }
+ return ret;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+void recv_show_pids(recv_info_t *r)
+{
+ pid_info_t *slot;
+ char addr_str[INET6_ADDRSTRLEN];
+ inet_ntop (AF_INET6, r->mcg.s6_addr, addr_str, INET6_ADDRSTRLEN);
+
+ info("pids on receiver %p (%s):\n",r, addr_str);
+ DVBMC_LIST_FOR_EACH_ENTRY (slot, &r->slots.list, pid_info_t, list) {
+ info("%d,", slot->pid.pid);
+ }
+ info("\n");
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+int recv_show_all_pids (recv_info_t * receivers)
+{
+ int ret=0;
+ recv_info_t *r;
+ DVBMC_LIST_FOR_EACH_ENTRY (r, &receivers->head->list, recv_info_t, list) {
+ recv_show_pids(r);
+ }
+ return ret;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+static void deallocate_slot (recv_info_t * r, pid_info_t *p)
+{
+ int nodrop=0;
+
+#ifdef MULTI_THREAD_RECEIVER
+ if (pthread_exist(p->recv_ts_thread)) {
+#else
+ if (p->run) {
+
+#endif //info ("Deallocating PID %d from slot %p\n", p->pid.pid, p);
+ p->run = 0;
+
+ //Do not leave multicast group if there is another dvb adapter using the same group
+ if (find_any_slot_by_mcg (r, &p->mcg)) {
+ dbg ("MCG is still in use not dropping\n");
+ p->s->is_multicast = 0;
+ nodrop=1;
+ }
+
+#ifdef MULTI_THREAD_RECEIVER
+ pthread_join (p->recv_ts_thread, NULL);
+#else
+ udp_close_buff(p->s);
+#endif
+ p->dropped = MAX_DROP_NUM;
+ }
+ //printf("NO DROP: %d\n",nodrop);
+ if(!mld_start || nodrop) {
+ dvbmc_list_remove(&p->list);
+ free(p);
+ }
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+static pid_info_t *allocate_slot (recv_info_t * r, struct in6_addr *mcg, dvb_pid_t *pid)
+{
+ pid_info_t *p = (pid_info_t *)malloc(sizeof(pid_info_t));
+ if(!p) {
+ err ("Cannot get memory for pid\n");
+ }
+
+ dbg ("Allocating new PID %d to Slot %p\n", pid->pid, p);
+
+ memset(p, 0, sizeof(pid_info_t));
+
+ p->cont_old = -1;
+ p->mcg = *mcg;
+ mcg_set_pid (&p->mcg, pid->pid);
+#if defined(RE)
+ if (!check_if_already_redirected(r, pid->id)) {
+ //printf("PID %d not red. ===> SETTING ID to %d\n",pid->pid,pid->id);
+ mcg_set_id (&p->mcg, pid->id);
+ mcg_set_priority(&p->mcg, pid->priority);
+ } else {
+ set_redirected(r, pid->id);
+ //printf("send pid %d to noid mcg !\n",pid->pid);
+ mcg_set_id(&p->mcg, 0);
+ mcg_set_priority(&p->mcg, 0);
+ }
+ //mcg_set_id(&p->mcg,pid->id);
+#else
+ mcg_set_id (&p->mcg, pid->id);
+ mcg_set_priority(&p->mcg, pid->priority);
+#endif
+
+
+#ifdef DEBUG
+ print_mcg (&p->mcg);
+#endif
+ p->pid = *pid;
+ p->recv = r;
+#ifdef MULTI_THREAD_RECEIVER
+ int ret = pthread_create (&p->recv_ts_thread, NULL, recv_ts, p);
+ while (!ret && !p->run) {
+ usleep (10000);
+ }
+ if (ret) {
+ err ("pthread_create failed with %d\n", ret);
+#else
+ p->cont_old=-1;
+ p->s = client_udp_open_cb (&p->mcg, port, iface, recv_ts_func, p);
+ if (!p->s) {
+ warn ("client_udp_open error !\n");
+ return 0;
+#endif
+ } else {
+ p->run = 1;
+ dvbmc_list_add_head (&r->slots.list, &p->list);
+ }
+
+ return p;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+static void stop_ten_receive (recv_info_t * r)
+{
+ dbg ("->>>>>>>>>>>>>>>>>stop_ten_receive on receiver %p\n",r);
+ if (pthread_exist(r->recv_ten_thread) && r->ten_run) {
+ dbg ("cancel TEN receiver %p %p\n", r, r->recv_ten_thread);
+
+ r->ten_run=0;
+ pthread_mutex_unlock (&lock);
+ do {
+ dbg ("wait TEN stop receiver %p %p\n", r, r->recv_ten_thread);
+ usleep(10000);
+ } while (!r->ten_run);
+ pthread_mutex_lock (&lock);
+ r->ten_run=0;
+ dbg ("cancel TEN done receiver %p\n", r);
+ pthread_detach (r->recv_ten_thread);
+ pthread_null(r->recv_ten_thread);
+ }
+}
+
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+static void start_ten_receive (recv_info_t * r)
+{
+ if (r->pidsnum && !pthread_exist(r->recv_ten_thread)) {
+#ifdef DEBUG
+ char host[INET6_ADDRSTRLEN];
+ inet_ntop (AF_INET6, &r->mcg, (char *) host, INET6_ADDRSTRLEN);
+
+ dbg ("Start TEN for receiver %p %s\n", r, host);
+#endif
+ r->ten_run = 0;
+
+ int ret = pthread_create (&r->recv_ten_thread, NULL, recv_ten, r);
+ while (!ret && !r->ten_run) {
+ dbg ("wait TEN startup receiver %p %p\n", r, r->recv_ten_thread);
+ usleep (10000);
+ }
+ if (ret) {
+ err ("pthread_create failed with %d\n", ret);
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+static int cmppids(const void *p1, const void *p2)
+{
+ dvb_pid_t *pid1=(dvb_pid_t *)p1;
+ dvb_pid_t *pid2=(dvb_pid_t *)p2;
+
+ if(pid1->pid == pid2->pid) {
+ return pid1->id < pid2->id;
+ }
+ return pid1->pid < pid2->pid;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+static void update_mcg (recv_info_t * r, int handle_ten)
+{
+ int i;
+ pid_info_t *p;
+ pid_info_t *ptmp;
+
+ if(handle_ten) {
+ if(r->pidsnum) {
+ start_ten_receive(r);
+ } else {
+ stop_ten_receive(r);
+ }
+ }
+ dbg("update_mcg(%p, %d)\n", r, handle_ten);
+ qsort(r->pids, r->pidsnum, sizeof(dvb_pid_t), cmppids);
+
+ DVBMC_LIST_FOR_EACH_ENTRY_SAFE (p, ptmp, &r->slots.list, pid_info_t, list) {
+ //dbg ("DVBMC_LIST_FOR_EACH_ENTRY_SAFE: %p\n", p);
+ if(p->run) {
+ int found_pid = 0;
+ for (i = 0; i < r->pidsnum; i++) {
+ // pid already there without id but now also with id required
+ if (r->pids[i].pid == p->pid.pid && r->pids[i].id && !p->pid.id) {
+ found_pid = 0;
+ break;
+ }
+ if (r->pids[i].pid == p->pid.pid && r->pids[i].id == p->pid.id) {
+ found_pid = 1;
+ }
+ }
+ if (!found_pid) {
+ deallocate_slot (r, p);
+ }
+ }
+ }
+
+ for (i = 0; i < r->pidsnum; i++) {
+ unsigned int pid = r->pids[i].pid;
+ if (!find_slot_by_pid (r, pid, -1)) { //pid with any id there?
+ allocate_slot (r, &r->mcg, r->pids+i);
+ }
+ }
+
+
+}
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+static void stop_receive (recv_info_t * r, int mode)
+{
+ dbg ("stop_receive on receiver %p mode %d\n",r, mode);
+ int pidsnum=r->pidsnum;
+ //Remove all PIDs
+ r->pidsnum = 0;
+ update_mcg (r, mode);
+ r->pidsnum=pidsnum;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+#ifdef RE
+#if 0
+static int find_redirected_sid (recv_info_t * r, int id)
+{
+ pid_info_t *slot;
+ DVBMC_LIST_FOR_EACH_ENTRY (slot, &r->slots.list, pid_info_t, list) {
+ if (slot->pid.id == id && slot->pid.re) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+#endif
+
+int check_if_already_redirected(recv_info_t *r, int sid)
+{
+ int i;
+ for (i = 0; i < r->pidsnum; i++) {
+ //printf("PID %d SID %d RE %d\n",r->pids[i].pid, r->pids[i].id, r->pids[i].re);
+ if (r->pids[i].re && r->pids[i].id == sid) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+int check_if_sid_in(recv_info_t *r, int sid)
+{
+ int i;
+ for (i = 0; i < r->pidsnum; i++) {
+ //printf("PID %d SID %d RE %d\n",r->pids[i].pid, r->pids[i].id, r->pids[i].re);
+ if (r->pids[i].id == sid) {
+// printf("%s: SID in %d!\n",__func__,sid);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+int set_redirected(recv_info_t *r, int sid)
+{
+ int i;
+ for (i = 0; i < r->pidsnum; i++) {
+ if (r->pids[i].id == sid)
+ r->pids[i].re=1;
+ }
+
+ return 0;
+}
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+int stop_sid_mcgs(recv_info_t *r, int sid)
+{
+ pid_info_t *p;
+ pid_info_t *ptmp;
+
+ DVBMC_LIST_FOR_EACH_ENTRY_SAFE (p, ptmp, &r->slots.list, pid_info_t, list) {
+ if(p->run) {
+ if (p->pid.pid && p->pid.id == sid) {
+ //info ("Deallocating PID %d ID %d RE %d from slot %p\n", p->pid.pid,p->pid.id,p->pid.re, p);
+ deallocate_slot (r, p);
+ }
+ }
+ }
+
+ return 0;
+}
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+int rejoin_mcgs(recv_info_t *r, int sid)
+{
+
+ int i;
+ for (i = 0; i < r->pidsnum; i++) {
+ unsigned int pid = r->pids[i].pid;
+ unsigned int id = r->pids[i].id;
+ if (!find_slot_by_pid (r, pid, id) && id == sid) {
+ char addr_str[INET6_ADDRSTRLEN];
+ inet_ntop (AF_INET6, &r->mcg, addr_str, INET6_ADDRSTRLEN);
+ //info ("Rejoin mcg %s with no ID (PID %d ID %d RE %d)...\n", addr_str, pid, id, r->pids[i].re);
+ allocate_slot (r, &r->mcg, r->pids+i);
+ }
+ }
+
+ return 0;
+}
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+#endif
+int recv_redirect (recv_info_t * r, struct in6_addr mcg)
+{
+ int ret = 0;
+
+ pthread_mutex_lock (&lock);
+ dbg ("\n+++++++++++++\nIn redirect for receiver %p\n", r);
+#if 0
+ char addr_str[INET6_ADDRSTRLEN];
+ inet_ntop (AF_INET6, &r->mcg, addr_str, INET6_ADDRSTRLEN);
+ info ("Redirect to ===> %s\n",addr_str);
+#endif
+ int sid;
+ mcg_get_id(&mcg,&sid);
+ mcg_set_id(&mcg,0);
+
+ //printf("SID in: %d\n",sid);
+
+ if (!sid || ( !check_if_already_redirected(r, sid) && check_if_sid_in(r, sid)) ) {
+ if (sid == 0) {
+ stop_receive (r, 0);
+ r->mcg = mcg;
+ update_mcg (r, 0);
+ ret = 1;
+ } else {
+ //stop sid mcgs
+ stop_sid_mcgs(r, sid);
+ set_redirected(r, sid);
+ //start new mcgs with no sid
+ rejoin_mcgs(r, sid);
+ }
+ }
+
+ dbg ("Redirect done for receiver %p\n", r);
+ pthread_mutex_unlock (&lock);
+
+ return ret;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+int recv_stop (recv_info_t * r)
+{
+ pthread_mutex_lock (&lock);
+ stop_receive (r, 1);
+ pthread_mutex_unlock (&lock);
+ return 0;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+int recv_count_pids(recv_info_t * r)
+{
+ int i;
+ for (i=0; r->pids[i].pid!=-1; i++);
+ return i;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+static int recv_copy_pids(dvb_pid_t *dst, dvb_pid_t *src)
+{
+ int i;
+ for (i=0; (src[i].pid!=-1) && (i<(RECV_MAX_PIDS-1)); i++) {
+ dst[i]=src[i];
+ }
+ if(i==(RECV_MAX_PIDS-1)) {
+ warn("Cannot receive more than %d pids\n", RECV_MAX_PIDS-1);
+ }
+ return i;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+int recv_pids (recv_info_t *r, dvb_pid_t *pids)
+{
+ pthread_mutex_lock (&lock);
+ if(pids) {
+ r->pidsnum=recv_copy_pids(r->pids, pids);
+ }
+ update_mcg(r, 1);
+ pthread_mutex_unlock (&lock);
+ return 0;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+int recv_pids_get (recv_info_t *r, dvb_pid_t *pids)
+{
+ pthread_mutex_lock (&lock);
+ if(pids) {
+ memcpy(pids, r->pids, sizeof(dvb_pid_t)*r->pidsnum);
+ pids[r->pidsnum].pid=-1;
+ }
+ pthread_mutex_unlock (&lock);
+ return r->pidsnum;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+int recv_pid_add (recv_info_t * r, dvb_pid_t *pid)
+{
+ int ret=0;
+
+ pthread_mutex_lock (&lock);
+ pid_info_t *p=find_slot_by_pid (r, pid->pid, pid->id);
+ if(!p && (r->pidsnum < (RECV_MAX_PIDS-2))) {
+#if defined(RE)
+ r->pids[r->pidsnum].re = 0;
+#endif
+ r->pids[r->pidsnum]=*pid;
+ r->pids[++r->pidsnum].pid=-1;
+ update_mcg(r, 1);
+ ret = 1;
+ }
+ pthread_mutex_unlock (&lock);
+
+ return ret;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+int recv_pid_del (recv_info_t * r, int pid)
+{
+ int i;
+ int ret=0;
+
+ pthread_mutex_lock (&lock);
+ if(pid>=0) {
+ for (i = 0; i < r->pidsnum; i++) {
+ if(r->pids[i].pid==pid || ret) {
+ r->pids[i]=r->pids[i+1];
+ ret=1;
+ }
+ }
+ if(ret) {
+ r->pidsnum--;
+ update_mcg(r, 1);
+ }
+ } else {
+ r->pids[0].pid=-1;
+ r->pidsnum=0;
+ update_mcg(r, 1);
+ }
+ pthread_mutex_unlock (&lock);
+
+ return ret;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+int recv_tune (recv_info_t * r, fe_type_t type, int satpos, recv_sec_t *sec, struct dvb_frontend_parameters *fe_parms, dvb_pid_t *pids)
+{
+ pthread_mutex_lock (&lock);
+ dbg ("kick_tune receiver %p\n", r);
+
+ stop_receive (r, 1);
+ if(fe_parms) {
+ r->fe_parms=*fe_parms;
+ }
+ if(sec) {
+ r->sec=*sec;
+ }
+ if(pids) {
+ r->pidsnum=recv_copy_pids(r->pids, pids);
+ }
+
+ fe_parms_to_mcg (&r->mcg, STREAMING_PID, type, &r->sec, &r->fe_parms, 0);
+ mcg_set_satpos (&r->mcg, satpos);
+
+ update_mcg (r, 1);
+
+ pthread_mutex_unlock (&lock);
+ dbg ("kick_tune done receiver %p\n", r);
+ return 0;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+recv_info_t *recv_add (void)
+{
+ recv_info_t *r=(recv_info_t *)malloc(sizeof(recv_info_t));
+ if(!r) {
+ err ("Cannot get memory for receiver\n");
+ }
+ memset (r, 0, sizeof (recv_info_t));
+ r->head=&receivers;
+ dvbmc_list_init (&r->slots.list);
+ pthread_mutex_lock (&lock);
+ dvbmc_list_add_head(&receivers.list, &r->list);
+ pthread_mutex_unlock (&lock);
+ return r;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+void recv_del (recv_info_t *r)
+{
+ pthread_mutex_lock (&lock);
+ stop_receive (r, 1);
+ dvbmc_list_remove(&r->list);
+ pthread_mutex_unlock (&lock);
+ free(r);
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+int recv_init(char *intf, int p)
+{
+ LIBXML_TEST_VERSION;
+#ifdef WIN32
+ WSADATA wsaData;
+ if (WSAStartup (MAKEWORD (2, 2), &wsaData) != 0) {
+ err ("WSAStartup failed\n");
+ }
+#endif
+
+ if(intf) {
+ strcpy(iface, intf);
+ } else {
+ iface[0]=0;
+ }
+ if(p) {
+ port=p;
+ }
+
+ g_conf = (struct conf*) malloc (sizeof (struct conf));
+ if (!g_conf) {
+ err ("Cannot get memory for configuration\n");
+ exit (-1);
+ }
+
+ memset (g_conf, 0, sizeof (struct conf));
+ update_interfaces (NULL);
+
+ if (!strlen (iface)) {
+ struct intnode *intn = int_find_first ();
+ if (intn) {
+ strcpy (iface, intn->name);
+ } else {
+ warn ("Cannot find any usable network interface\n");
+ if(g_conf->ints) {
+ free (g_conf->ints);
+ }
+ #ifdef PTW32_STATIC_LIB
+ pthread_win32_process_detach_np();
+ #endif
+ free(g_conf);
+ return -1;
+ }
+ }
+
+ dvbmc_list_init (&receivers.list);
+ pthread_mutex_init (&lock, NULL);
+ receivers.head=&receivers;
+#if ! defined WIN32 || defined __CYGWIN__
+ signal (SIGUSR1, &sig_handler);
+#endif
+#ifdef PTW32_STATIC_LIB
+ pthread_win32_process_attach_np();
+#endif
+ pthread_create (&recv_tra_thread, NULL, recv_tra, NULL);
+ pthread_create (&recv_tca_thread, NULL, recv_tca, NULL);
+
+ return 0;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+int recv_exit(void)
+{
+ recv_info_t *r;
+ recv_info_t *rtmp;
+ if(pthread_exist(recv_tra_thread) && !pthread_cancel (recv_tra_thread)) {
+ pthread_join (recv_tra_thread, NULL);
+ }
+ if(pthread_exist(recv_tca_thread) && !pthread_cancel (recv_tca_thread)) {
+ pthread_join (recv_tca_thread, NULL);
+ }
+ DVBMC_LIST_FOR_EACH_ENTRY_SAFE (r, rtmp, &receivers.head->list, recv_info_t, list) {
+ recv_del(r);
+ }
+#if ! defined WIN32 || defined __CYGWIN__
+ signal (SIGUSR1, NULL);
+#endif
+ g_conf->maxinterfaces=0;
+ if(g_conf->ints) {
+ free (g_conf->ints);
+ }
+#ifdef PTW32_STATIC_LIB
+ pthread_win32_process_detach_np();
+#endif
+ free(g_conf);
+ xmlCleanupParser ();
+ xmlMemoryDump ();
+ return 0;
+}
diff --git a/mcast/client/recv_tv.h b/mcast/client/recv_tv.h
new file mode 100644
index 0000000..9feb673
--- /dev/null
+++ b/mcast/client/recv_tv.h
@@ -0,0 +1,96 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ * modified by Reel Multimedia, http://www.reel-multimedia.com, info@reel-multimedia.com
+ * 01042010 DL: use a single thread for reading from network layer (uses less resources)
+ *
+ */
+
+#ifndef __RECV_TV_H__
+#define __RECV_TV__H__
+
+#define REP_TIME 1000000
+#define MAX_DROP_NUM 5
+#define RECV_MAX_PIDS 256
+
+//typedef struct recv_info recv_info_t;
+
+typedef struct {
+ int pid;
+ int id;
+ int priority;
+#if 1
+ int re;
+#endif
+} dvb_pid_t;
+
+typedef struct pid_info
+{
+ struct list list;
+ UDPContext *s;
+ dvb_pid_t pid;
+ struct in6_addr mcg;
+ recv_info_t *recv;
+ pthread_t recv_ts_thread;
+ int run;
+ int dropped;
+ int cont_old;
+} pid_info_t;
+
+struct recv_info
+{
+ struct list list;
+ recv_info_t *head;
+ pid_info_t slots;
+ int lastalloc;
+ pthread_t recv_ten_thread;
+ struct in6_addr mcg;
+ int ten_run;
+
+ dvb_pid_t pids[RECV_MAX_PIDS];
+ int pidsnum;
+ recv_sec_t sec;
+ struct dvb_frontend_parameters fe_parms;
+
+ recv_festatus_t fe_status;
+
+ int (*handle_ten) (tra_t *ten, void *context);
+ void *handle_ten_context;
+
+ int (*handle_ts) (unsigned char *buffer, size_t len, void *context);
+ void *handle_ts_context;
+};
+
+// Internal Stuff
+int recv_redirect (recv_info_t * r, struct in6_addr mcg);
+int count_all_pids (recv_info_t * receivers);
+int count_receivers(recv_info_t *receivers);
+
+// PID-Handling
+DLL_SYMBOL int recv_pid_add (recv_info_t * r, dvb_pid_t *pid);
+DLL_SYMBOL int recv_pid_del (recv_info_t * r, int pid);
+DLL_SYMBOL int recv_pids (recv_info_t * r, dvb_pid_t *pids);
+DLL_SYMBOL int recv_pids_get (recv_info_t *r, dvb_pid_t *pids);
+DLL_SYMBOL int recv_show_all_pids (recv_info_t * receivers);
+void recv_show_pids(recv_info_t *r);
+
+// Complete Tune
+DLL_SYMBOL int recv_tune (recv_info_t * r, fe_type_t type, int satpos, recv_sec_t *sec, struct dvb_frontend_parameters *fe_parms, dvb_pid_t *pids);
+
+// Receiver Handling
+DLL_SYMBOL recv_info_t *recv_add (void);
+DLL_SYMBOL void recv_del (recv_info_t *r);
+DLL_SYMBOL int recv_stop (recv_info_t * r);
+DLL_SYMBOL int register_ts_handler (recv_info_t * r, int (*p)(unsigned char *, size_t, void *), void *c);
+
+// Module global functions
+DLL_SYMBOL int recv_init(char *intf, int p);
+DLL_SYMBOL int recv_exit(void);
+
+
+int find_any_slot_by_mcg (recv_info_t * receivers, struct in6_addr *mcg);
+
+#endif
diff --git a/mcast/client/satlists.c b/mcast/client/satlists.c
new file mode 100644
index 0000000..6dccb39
--- /dev/null
+++ b/mcast/client/satlists.c
@@ -0,0 +1,133 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ */
+
+#include "headers.h"
+
+int satellite_find_by_diseqc (satellite_reference_t * ref, recv_sec_t *sec, struct dvb_frontend_parameters *fep, int mode)
+{
+ int i, j, k, l;
+ netceiver_info_list_t *nc_list=nc_get_list();
+ char buf[6];
+ memcpy(buf,"\xe0\x10\x6f\x0\x0\x0",6);
+ int freq = fep->frequency/1000;
+ int ret=0;
+ int explicit_position=NO_SAT_POS;
+
+ if (sec->diseqc_cmd.msg_len > 6 || !ref || !freq) {
+ return 0;
+ }
+
+ for (l = 0; l < nc_list->nci_num; l++) {
+ netceiver_info_t *nci = nc_list->nci + l;
+
+ for (i = 0; i < nci->sat_list_num; i++) {
+ satellite_list_t *sat_list = nci->sat_list + i;
+
+ for (j = 0; j < sat_list->sat_num; j++) {
+ satellite_info_t *sat = sat_list->sat + j;
+
+ for (k = 0; k < sat->comp_num; k++) {
+ satellite_component_t *comp = sat->comp + k;
+ int oldpos=sat->SatPos^1800;
+ int newpos=(sec->diseqc_cmd.msg[3]+(sec->diseqc_cmd.msg[4]<<8))^1800;
+ // prepare synthetic messsage from satpos and pol./volt.
+ buf[3]=oldpos;
+ buf[4]=oldpos>>8;
+ buf[5]=(comp->Polarisation&1)<<1 | !(comp->sec.tone_mode&1);
+ dbg("compare: old/new %i/%i, %02x %02x %02x %02x %02x %02x <-> %02x %02x %02x %02x %02x %02x\n", oldpos, newpos,
+ buf[0]&0xff,buf[1]&0xff,buf[2]&0xff,buf[3]&0xff, buf[4]&0xff, buf[5]&0xff,
+ sec->diseqc_cmd.msg[0], sec->diseqc_cmd.msg[1], sec->diseqc_cmd.msg[2],
+ sec->diseqc_cmd.msg[3], sec->diseqc_cmd.msg[4], sec->diseqc_cmd.msg[5]);
+
+ dbg("%i mode %i, len %i, %i > %i , %i < %i, %i < %i, %i > %i\n",sat->type,
+ mode, sec->diseqc_cmd.msg_len, freq, comp->RangeMin, freq, comp->RangeMax,
+ sat->SatPosMin, newpos , sat->SatPosMax, newpos);
+
+ // Check if coded sat pos matches
+ if ((sat->type==SAT_SRC_LNB || sat->type==SAT_SRC_UNI) && mode == 0 && sec->diseqc_cmd.msg_len>0 &&
+ (freq >= comp->RangeMin) && (freq <= comp->RangeMax) &&
+ !memcmp (buf, &sec->diseqc_cmd.msg, sec->diseqc_cmd.msg_len)) {
+ dbg("Satpos MATCH\n");
+ ret=1;
+ }
+ // check for rotor
+ else if (sat->type==SAT_SRC_ROTOR && mode == 0 && sec->diseqc_cmd.msg_len>0 &&
+ (freq >= comp->RangeMin) && (freq <= comp->RangeMax) &&
+ (buf[5]==sec->diseqc_cmd.msg[5]) &&
+ (sat->SatPosMin<=newpos && sat->SatPosMax>=newpos)) {
+ dbg("ROTOR MATCH %i\n",newpos);
+ explicit_position=newpos;
+ ret=1;
+ }
+ // check if given diseqc matches raw tuner diseqc
+ else if (mode == 1 && sec->diseqc_cmd.msg_len>0 && !memcmp (&comp->sec.diseqc_cmd.msg, &sec->diseqc_cmd.msg, sec->diseqc_cmd.msg_len)) {
+ dbg("Diseqc 1.0 Match %02x %02x %02x %02x %02x %02x\n",
+ comp->sec.diseqc_cmd.msg[0], comp->sec.diseqc_cmd.msg[1], comp->sec.diseqc_cmd.msg[2],
+ comp->sec.diseqc_cmd.msg[3], comp->sec.diseqc_cmd.msg[4], comp->sec.diseqc_cmd.msg[5]);
+ ret=1;
+ }else if (mode == 2 && (fe_sec_voltage_t)comp->Polarisation == sec->voltage && comp->sec.tone_mode== sec->tone_mode && comp->sec.mini_cmd == sec->mini_cmd) {
+ dbg("Legacy Match, pol %i, tone %i, cmd %i\n",comp->Polarisation,comp->sec.tone_mode,comp->sec.mini_cmd);
+ ret=1;
+ }
+ if (ret) {
+ ref->netceiver = l;
+ ref->sat_list = i;
+ ref->sat = j;
+ ref->comp = k;
+ ref->position=explicit_position;
+ info("Sat found: %d %d %d %d, rotor %d\n",l,i,j,k, explicit_position);
+ return ret;
+ }
+ }
+ }
+ }
+ }
+ return ret;
+}
+
+int satellite_get_pos_by_ref (satellite_reference_t * ref)
+{
+ netceiver_info_list_t *nc_list=nc_get_list();
+ netceiver_info_t *nci = nc_list->nci + ref->netceiver;
+ satellite_list_t *sat_list = nci->sat_list + ref->sat_list;
+ satellite_info_t *sat = sat_list->sat + ref->sat;
+ if (sat->type==SAT_SRC_ROTOR && ref->position!=NO_SAT_POS) {
+ return ref->position;
+ }
+ return sat->SatPos;
+}
+
+int satellite_get_lof_by_ref (satellite_reference_t * ref)
+{
+ netceiver_info_list_t *nc_list=nc_get_list();
+ netceiver_info_t *nci = nc_list->nci + ref->netceiver;
+ satellite_list_t *sat_list = nci->sat_list + ref->sat_list;
+ satellite_info_t *sat = sat_list->sat + ref->sat;
+ satellite_component_t *comp = sat->comp + ref->comp;
+ return comp->LOF;
+}
+
+recv_sec_t *satellite_find_sec_by_ref (satellite_reference_t * ref)
+{
+ netceiver_info_list_t *nc_list=nc_get_list();
+ netceiver_info_t *nci = nc_list->nci + ref->netceiver;
+ satellite_list_t *sat_list = nci->sat_list + ref->sat_list;
+ satellite_info_t *sat = sat_list->sat + ref->sat;
+ satellite_component_t *comp = sat->comp + ref->comp;
+ return &comp->sec;
+}
+
+polarisation_t satellite_find_pol_by_ref (satellite_reference_t * ref)
+{
+ netceiver_info_list_t *nc_list=nc_get_list();
+ netceiver_info_t *nci = nc_list->nci + ref->netceiver;
+ satellite_list_t *sat_list = nci->sat_list + ref->sat_list;
+ satellite_info_t *sat = sat_list->sat + ref->sat;
+ satellite_component_t *comp = sat->comp + ref->comp;
+ return comp->Polarisation;
+}
diff --git a/mcast/client/sock_test.c b/mcast/client/sock_test.c
new file mode 100644
index 0000000..1b4fd39
--- /dev/null
+++ b/mcast/client/sock_test.c
@@ -0,0 +1,93 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ */
+
+#include "headers.h"
+
+#define SHM_WAIT_RESPONSE(cmd) { cmd->state=SHM_REQUEST; send (sock_comm, &sock_cmd, sizeof(shm_cmd_t), 0); recv (sock_comm, &sock_cmd, sizeof(shm_cmd_t), 0); if (cmd->state == SHM_ERROR) warn ("SHM parameter error\n");}
+
+int main (int argc, char **argv)
+{
+ int sock_comm;
+ int sock_name_len = 0;
+ struct sockaddr sock_name;
+ shm_cmd_t sock_cmd;
+ shm_cmd_t *shm_cmd=&sock_cmd;
+ sock_name.sa_family = AF_UNIX;
+
+ strcpy(sock_name.sa_data, SOCK_NAMESPACE);
+ sock_name_len = strlen(sock_name.sa_data) + sizeof(sock_name.sa_family);
+
+ if((sock_comm = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
+ {
+ warn ("socket create failure %d\n", errno);
+ return -1;
+ }
+
+ if (connect(sock_comm, &sock_name, sock_name_len) < 0) {
+ err ("connect failure\n");
+ }
+
+ shm_cmd->cmd=SHM_GET_NC_NUM;
+ SHM_WAIT_RESPONSE(shm_cmd);
+
+ printf("nc_num: %d\n", shm_cmd->parm[SHM_PARM_NC_NUM]);
+ int nc_num=shm_cmd->parm[SHM_PARM_NC_NUM];
+ int i;
+ for(i=0;i<nc_num;i++) {
+ shm_cmd->cmd=SHM_GET_NC_INFO;
+ shm_cmd->parm[SHM_PARM_NC_NUM]=i;
+ SHM_WAIT_RESPONSE(shm_cmd);
+ printf("nc_info.uuid: %s nc_info.lastseen: %u nc_info.tuner_num: %d\n", shm_cmd->u.nc_info.uuid, (unsigned int) shm_cmd->u.nc_info.lastseen, shm_cmd->u.nc_info.tuner_num);
+ int j;
+ int tuner_num=shm_cmd->u.nc_info.tuner_num;
+ for(j=0;j<tuner_num;j++) {
+ shm_cmd->cmd=SHM_GET_TUNER_INFO;
+ shm_cmd->parm[SHM_PARM_TUNER_NUM]=j;
+ SHM_WAIT_RESPONSE(shm_cmd);
+ printf("tuner_info.fe_info.name: %s\n",shm_cmd->u.tuner_info.fe_info.name);
+ }
+
+
+ int sat_list_num=shm_cmd->u.nc_info.sat_list_num;
+ for(j=0;j<sat_list_num;j++) {
+ shm_cmd->cmd=SHM_GET_SAT_LIST_INFO;
+ shm_cmd->parm[SHM_PARM_NC_NUM]=i;
+ shm_cmd->parm[SHM_PARM_SAT_LIST_NUM]=j;
+ SHM_WAIT_RESPONSE(shm_cmd);
+
+ printf("sat_list_info.Name: %s sat_list_info.sat_num: %d\n", shm_cmd->u.sat_list.Name, shm_cmd->u.sat_list.sat_num);
+
+ int sat_num=shm_cmd->u.sat_list.sat_num;
+ int k;
+ for(k=0;k<sat_num;k++) {
+ shm_cmd->cmd=SHM_GET_SAT_INFO;
+ shm_cmd->parm[SHM_PARM_SAT_LIST_NUM]=j;
+ shm_cmd->parm[SHM_PARM_SAT_NUM]=k;
+ SHM_WAIT_RESPONSE(shm_cmd);
+ printf("sat_info.Name: %s\n",shm_cmd->u.sat_info.Name);
+ }
+ }
+ }
+
+ while (1) {
+ shm_cmd->cmd=SHM_GET_TRA_NUM;
+ SHM_WAIT_RESPONSE(shm_cmd);
+
+ printf("tra_num: %d\n", shm_cmd->parm[SHM_PARM_TRA_NUM]);
+ int tra_num=shm_cmd->parm[SHM_PARM_TRA_NUM];
+ for(i=0;i<tra_num;i++) {
+ shm_cmd->cmd=SHM_GET_TRA_INFO;
+ shm_cmd->parm[SHM_PARM_TRA_NUM]=i;
+ SHM_WAIT_RESPONSE(shm_cmd);
+ printf("tra uuid: %s lastseen: %u lock:%d str:%d snr:%d ber:%d\n", shm_cmd->u.tra.uuid, (unsigned int) shm_cmd->u.tra.lastseen, shm_cmd->u.tra.s.st, shm_cmd->u.tra.s.strength, shm_cmd->u.tra.s.snr, shm_cmd->u.tra.s.ber);
+ }
+ sleep(2);
+ }
+ return 0;
+}
+
diff --git a/mcast/client/tca_handler.c b/mcast/client/tca_handler.c
new file mode 100644
index 0000000..3817332
--- /dev/null
+++ b/mcast/client/tca_handler.c
@@ -0,0 +1,84 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ */
+
+#include "headers.h"
+
+static netceiver_info_list_t nc_list;
+static pthread_mutex_t nci_lock=PTHREAD_MUTEX_INITIALIZER;
+
+static netceiver_info_t *nci_find_unique (netceiver_info_list_t * ncl, char *uuid)
+{
+ int i;
+ for (i = 0; i < ncl->nci_num; i++) {
+ if (!strcmp (ncl->nci[i].uuid, uuid)) {
+ return ncl->nci + i;
+ }
+ }
+ return NULL;
+}
+
+static void nci_free(netceiver_info_t * nc_info)
+{
+ int i, j;
+ for (i = 0; i < nc_info->sat_list_num; i++) {
+ satellite_list_t *sat_list = nc_info->sat_list + i;
+
+ for (j = 0; j < sat_list->sat_num; j++) {
+ satellite_info_t *sat = sat_list->sat + j;
+
+ free (sat->comp);
+ }
+ free (sat_list->sat);
+ }
+ free (nc_info->sat_list);
+ free (nc_info->tuner);
+}
+
+static int nci_add_unique (netceiver_info_list_t * ncl, netceiver_info_t * nci)
+{
+ netceiver_info_t *ncf=nci_find_unique (ncl, nci->uuid);
+ if (!ncf) {
+ ncl->nci = (netceiver_info_t *) realloc (ncl->nci, sizeof (netceiver_info_t) * (ncl->nci_num + 1));
+ if (!ncl->nci) {
+ err ("Cannot get memory for netceiver_info\n");
+ }
+ memcpy (ncl->nci + ncl->nci_num, nci, sizeof (netceiver_info_t));
+ (ncl->nci+ncl->nci_num)->lastseen = time(NULL);
+ ncl->nci_num++;
+ return 1;
+ } else {
+ nci_free(ncf);
+ memcpy(ncf, nci, sizeof (netceiver_info_t));
+ ncf->lastseen = time(NULL);
+ }
+ return 0;
+}
+
+netceiver_info_list_t *nc_get_list(void)
+{
+ return &nc_list;
+}
+
+int nc_lock_list(void)
+{
+ return pthread_mutex_lock (&nci_lock);
+}
+
+int nc_unlock_list(void)
+{
+ return pthread_mutex_unlock (&nci_lock);
+}
+
+void handle_tca (netceiver_info_t * nc_info)
+{
+ nc_lock_list();
+ if (nci_add_unique (&nc_list, nc_info)) {
+ dbg ("New TCA from %s added\n", nc_info->uuid);
+ }
+ nc_unlock_list();
+}
diff --git a/mcast/client/tca_handler.h b/mcast/client/tca_handler.h
new file mode 100644
index 0000000..1803b28
--- /dev/null
+++ b/mcast/client/tca_handler.h
@@ -0,0 +1,18 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ */
+
+typedef struct
+{
+ netceiver_info_t *nci;
+ int nci_num;
+} netceiver_info_list_t;
+
+DLL_SYMBOL netceiver_info_list_t *nc_get_list(void);
+DLL_SYMBOL int nc_lock_list(void);
+DLL_SYMBOL int nc_unlock_list(void);
+void handle_tca (netceiver_info_t * nc_info);
diff --git a/mcast/client/tools.c b/mcast/client/tools.c
new file mode 120000
index 0000000..71f8bc6
--- /dev/null
+++ b/mcast/client/tools.c
@@ -0,0 +1 @@
+../common/tools.c \ No newline at end of file
diff --git a/mcast/client/tra_handler.c b/mcast/client/tra_handler.c
new file mode 100644
index 0000000..8148a1f
--- /dev/null
+++ b/mcast/client/tra_handler.c
@@ -0,0 +1,56 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ */
+
+#include "headers.h"
+
+static tra_info_t tra_list;
+
+static tra_t *tra_find_unique (tra_info_t *trl, char *uuid)
+{
+ int i;
+ for (i = 0; i < trl->tra_num; i++) {
+ if (!strcmp (trl->tra[i].uuid, uuid)) {
+ return trl->tra + i;
+ }
+ }
+ return NULL;
+}
+
+static int tra_add_unique (tra_info_t *trl, tra_t *tri)
+{
+ tra_t *trf=tra_find_unique (trl, tri->uuid);
+ if (!trf) {
+ trl->tra = (tra_t *) realloc (trl->tra, sizeof (tra_t) * (trl->tra_num + 1));
+ if (!trl->tra) {
+ err ("Cannot get memory for netceiver_info\n");
+ }
+ trf = trl->tra + trl->tra_num;
+ trl->tra_num++;
+ }
+ memcpy (trf, tri, sizeof (tra_t));
+ return 1;
+}
+
+tra_info_t *tra_get_list(void)
+{
+ return &tra_list;
+}
+
+int handle_tra(tra_info_t *tra_info)
+{
+ int i;
+ if(tra_info->tra_num) {
+ for (i = 0; i < tra_info->tra_num; i++) {
+ tra_add_unique (&tra_list, tra_info->tra+i);
+ }
+ memcpy(tra_list.cam, tra_info->cam, MAX_CAMS*sizeof(cam_info_t));
+ free (tra_info->tra);
+ return 1;
+ }
+ return 0;
+}
diff --git a/mcast/client/tra_handler.h b/mcast/client/tra_handler.h
new file mode 100644
index 0000000..fe5ac2c
--- /dev/null
+++ b/mcast/client/tra_handler.h
@@ -0,0 +1,10 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ */
+
+DLL_SYMBOL tra_info_t *tra_get_list(void);
+int handle_tra(tra_info_t *tra_info);
diff --git a/mcast/client/win32 b/mcast/client/win32
new file mode 120000
index 0000000..6de80a3
--- /dev/null
+++ b/mcast/client/win32
@@ -0,0 +1 @@
+../common/win32 \ No newline at end of file
diff --git a/mcast/common/.indent.pro b/mcast/common/.indent.pro
new file mode 100644
index 0000000..2faef85
--- /dev/null
+++ b/mcast/common/.indent.pro
@@ -0,0 +1 @@
+-i8 -br -l0 -ce -npsl
diff --git a/mcast/common/.svn/entries b/mcast/common/.svn/entries
new file mode 100644
index 0000000..158235c
--- /dev/null
+++ b/mcast/common/.svn/entries
@@ -0,0 +1,847 @@
+10
+
+dir
+18963
+svn://reelbox.org/testing/src/vdr-plugins/src/mcli-1/mcast/common
+svn://reelbox.org
+
+
+
+2011-08-18T10:09:14.813360Z
+17158
+dirk
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+12be777f-adf9-0310-842f-e37ecc4c7426
+
+darwin
+dir
+
+recv_ccpp.c
+file
+
+
+
+
+2012-09-27T17:22:49.630848Z
+3088282b10ec5b66a5edbbd1da7bb364
+2011-08-18T10:09:14.813360Z
+17158
+dirk
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+49800
+
+input.h
+file
+
+
+
+
+2012-09-27T17:22:49.630848Z
+14ae9dfd7385824644e7f41891e4431a
+2011-07-12T13:36:23.313379Z
+16905
+rollercoaster
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+701
+
+tools.h
+file
+
+
+
+
+2012-09-27T17:22:49.634848Z
+3b18ae738d8c2f2be127479e3d332d13
+2011-07-12T13:36:23.313379Z
+16905
+rollercoaster
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+3001
+
+mcast.c
+file
+
+
+
+
+2012-09-27T17:22:49.634848Z
+372fb40dbd41035d414020df3c1aedc1
+2011-08-18T10:09:14.813360Z
+17158
+dirk
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+19168
+
+ciparser.c
+file
+
+
+
+
+2012-09-27T17:22:49.634848Z
+1b02f18bba452905d60a1829dbbb8abd
+2011-08-18T10:09:14.813360Z
+17158
+dirk
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+17272
+
+recv_ccpp.h
+file
+
+
+
+
+2012-09-27T17:22:49.634848Z
+b9f6b18254b50dfe7956532de35a15bf
+2011-07-12T13:36:23.313379Z
+16905
+rollercoaster
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+2358
+
+mld_client.c
+file
+
+
+
+
+2012-09-27T17:22:49.634848Z
+322113266b07500ca0f71e5565889090
+2011-07-12T13:36:23.313379Z
+16905
+rollercoaster
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+8945
+
+satlists.h
+file
+
+
+
+
+2012-09-27T17:22:49.634848Z
+eb22a7df1560514879ab880a04d71e96
+2011-07-12T13:36:23.313379Z
+16905
+rollercoaster
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+2273
+
+crc32.c
+file
+
+
+
+
+2012-09-27T17:22:49.634848Z
+980e8b3fd7efed5f9d560d02685ce653
+2011-07-12T13:36:23.313379Z
+16905
+rollercoaster
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+3829
+
+mcast.h
+file
+
+
+
+
+2012-09-27T17:22:49.634848Z
+197fd7134d088c87a4735f4526d6b584
+2011-08-18T10:09:14.813360Z
+17158
+dirk
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+2165
+
+.indent.pro
+file
+
+
+
+
+2012-09-27T17:22:49.634848Z
+536d6397e801893325c24ec292dee74f
+2011-07-12T13:36:23.313379Z
+16905
+rollercoaster
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+22
+
+ciparser.h
+file
+
+
+
+
+2012-09-27T17:22:49.634848Z
+d9404810159811a969622947f61d7d72
+2011-07-12T13:36:23.313379Z
+16905
+rollercoaster
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+2898
+
+list.h
+file
+
+
+
+
+2012-09-27T17:22:49.634848Z
+f5c2a2b3d49871370bd06133ecda42ca
+2011-07-12T13:36:23.313379Z
+16905
+rollercoaster
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+7470
+
+mld.h
+file
+
+
+
+
+2012-09-27T17:22:49.634848Z
+2bcbbcdc985f98caf098b8e8e497c2c0
+2011-07-12T13:36:23.313379Z
+16905
+rollercoaster
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+8620
+
+crc32.h
+file
+
+
+
+
+2012-09-27T17:22:49.634848Z
+35c6650ae24801e91dcd2db610364391
+2011-07-12T13:36:23.313379Z
+16905
+rollercoaster
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+490
+
+interfaces.c
+file
+
+
+
+
+2012-09-27T17:22:49.634848Z
+fffc315c72a40a84dcb8154954e91633
+2011-08-18T10:09:14.813360Z
+17158
+dirk
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+10873
+
+dvb_ca_wrapper.h
+file
+
+
+
+
+2012-09-27T17:22:49.634848Z
+bbd78f2a51fdda538e017905d73fe87f
+2011-07-12T13:36:23.313379Z
+16905
+rollercoaster
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+546
+
+mld_common.c
+file
+
+
+
+
+2012-09-27T17:22:49.634848Z
+5ffbd26840cb83a21c509ce0346c7d94
+2011-07-12T13:36:23.313379Z
+16905
+rollercoaster
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+7550
+
+defs.h
+file
+
+
+
+
+2012-09-27T17:22:49.634848Z
+22e61c4d81f14dce61fcf598f6caf402
+2011-08-18T10:09:14.813360Z
+17158
+dirk
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+10220
+
+interfaces.h
+file
+
+
+
+
+2012-09-27T17:22:49.634848Z
+6be8ad42834e22c1b5785d0f2525d1d3
+2011-07-12T13:36:23.313379Z
+16905
+rollercoaster
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1611
+
+siparser.c
+file
+
+
+
+
+2012-09-27T17:22:49.634848Z
+d8bd70909b3ce29323833a53c83febd1
+2011-08-18T10:09:14.813360Z
+17158
+dirk
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+36549
+
+version.h
+file
+
+
+
+
+2012-09-27T17:22:49.634848Z
+c4bfaad7e6177b714740dcc479f289e5
+2011-07-12T13:36:23.313379Z
+16905
+rollercoaster
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+437
+
+siparser.h
+file
+
+
+
+
+2012-09-27T17:22:49.634848Z
+d52dd1d53b4730204b6edc37ad121d99
+2011-07-12T13:36:23.313379Z
+16905
+rollercoaster
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+12062
+
+tools.c
+file
+
+
+
+
+2012-09-27T17:22:49.630848Z
+14b8ecc113fb224ca7e655ffe5b4890f
+2011-08-18T10:09:14.813360Z
+17158
+dirk
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+22386
+
diff --git a/mcast/common/.svn/text-base/.indent.pro.svn-base b/mcast/common/.svn/text-base/.indent.pro.svn-base
new file mode 100644
index 0000000..2faef85
--- /dev/null
+++ b/mcast/common/.svn/text-base/.indent.pro.svn-base
@@ -0,0 +1 @@
+-i8 -br -l0 -ce -npsl
diff --git a/mcast/common/.svn/text-base/ciparser.c.svn-base b/mcast/common/.svn/text-base/ciparser.c.svn-base
new file mode 100644
index 0000000..5ce563d
--- /dev/null
+++ b/mcast/common/.svn/text-base/ciparser.c.svn-base
@@ -0,0 +1,702 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ */
+
+//#define TESTING
+#ifdef TESTING
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <netinet/in.h>
+#include <stdlib.h>
+
+#include "ciparser.h"
+static unsigned char ll[] = { 0x00, 0x01, 0xA0, 0x28, 0x01, 0x90, 0x02, 0x00, 0x05, 0x9F, 0x80, 0x32, 0x1F, 0x03, 0x32, 0xC9, 0x01, 0x00, 0x0F, 0x01, 0x09, 0x06, 0x17, 0x62, 0xE0, 0x65, 0x00, 0x09, 0x09, 0x04, 0x17, 0x02, 0xE1, 0x2D, 0x02, 0x00, 0xA0, 0x00, 0x00, 0x04, 0x00, 0xA1, 0x00, 0x00 };
+static unsigned char lr[] = { 0x00, 0x01, 0x80, 0x02, 0x01, 0x80 };
+static unsigned char la[] = { 0x00, 0x01, 0xA0, 0x07, 0x01, 0x91, 0x04, 0x00, 0x01, 0x00, 0x41, 0x80, 0x02, 0x01, 0x00 };
+static unsigned char lb[] = { 0x00, 0x01, 0xA0, 0x82, 0x00, 0x17, 0x01, 0x90, 0x02, 0x00, 0x03, 0x9F, 0x80, 0x31, 0x0E, 0x06, 0x02, 0x06, 0x02, 0x17, 0x02, 0x17, 0x62, 0x01, 0x00, 0x05, 0x00, 0x18, 0x00, 0x80, 0x02, 0x01, 0x00 };
+static unsigned char lc[] = { 0x01, 0x02, 0xA0, 0x5F, 0x02, 0x90, 0x02, 0x00, 0x06, 0x9F, 0x80, 0x32, 0x56, 0x03, 0x03, 0x8B, 0x01, 0x00, 0x00, 0x02, 0x00, 0xA3, 0x00, 0x23, 0x01, 0x09, 0x0F, 0x05, 0x00, 0xE2, 0xC3, 0x10, 0x01, 0x00, 0x13, 0x01, 0x20, 0x14, 0x03, 0x00, 0x94, 0x0D, 0x09, 0x0F, 0x05, 0x00, 0xE2, 0xCD, 0x10, 0x01, 0x00, 0x13, 0x01, 0x20, 0x14, 0x03, 0x02, 0x38, 0x08, 0x04, 0x00, 0x5C, 0x00, 0x23, 0x01, 0x09, 0x0F, 0x05, 0x00, 0xE2, 0xC3, 0x10, 0x01, 0x00, 0x13, 0x01, 0x20, 0x14, 0x03, 0x00, 0x94, 0x0D, 0x09, 0x0F, 0x05, 0x00, 0xE2, 0xCD, 0x10, 0x01, 0x00, 0x13, 0x01, 0x20, 0x14, 0x03, 0x02, 0x38, 0x08 };
+static unsigned char ld[] = { 0x00, 0x01, 0xA0, 0x82, 0x00, 0x10, 0x01, 0x90, 0x02, 0x00, 0x03, 0x9F, 0x80, 0x33, 0x07, 0x2D, 0xB9, 0x01, 0x81, 0x00, 0x08, 0x00, 0x80, 0x02, 0x01, 0x00 };
+static unsigned char le[] = { 0x00, 0x01, 0xA0, 0x34, 0x01, 0x90, 0x02, 0x00, 0x03, 0x9F, 0x80, 0x32, 0x2B, 0x03, 0x00, 0x0B, 0x01, 0x00, 0x11, 0x01, 0x09, 0x06, 0x17, 0x22, 0xF0, 0x0B, 0x00, 0x0B, 0x09, 0x06, 0x17, 0x02, 0xF0, 0x0B, 0x00, 0x0B, 0x02, 0x06, 0xFF, 0x00, 0x00, 0x04, 0x07, 0x00, 0x00, 0x00, 0x04, 0x07, 0x01, 0x00, 0x00, 0x00, 0x07, 0x03, 0x00, 0x00};
+
+#define dbg(format, arg...) printf("%s:%d " format , __FILE__ , __LINE__ , ## arg)
+#define err(format, arg...) {printf("err:%s:%d: %s (%d): " format , __FILE__ , __LINE__ ,strerror(errno), errno, ## arg);print_trace();abort();}
+#define info(format, arg...) printf("%s:%d: " format , __FILE__ , __LINE__ ,## arg)
+#define warn(format, arg...) printf("%s:%d: " format , __FILE__ , __LINE__ ,## arg)
+#define STATIC
+#else
+//#define DEBUG
+#include "headers.h"
+#endif
+
+#define CA_MAX_CAIDS 16
+#define CA_MAX_PIDS 16
+#ifndef CA_MAX_SLOTS
+#define CA_MAX_SLOTS 3
+#endif
+typedef struct
+{
+ u_int16_t caid[CA_MAX_CAIDS];
+ u_int16_t pid[CA_MAX_PIDS];
+ u_int16_t capid[CA_MAX_PIDS];
+} caid_pid_list_t;
+
+static caid_pid_list_t cpl[CA_MAX_SLOTS];
+
+STATIC void dump(u_int8_t *data, int len)
+{
+#ifdef DEBUG
+ int j;
+ printf("Dump: ");
+ for(j=0;j<len;j++) {
+ printf("%02x ",data[j]);
+ }
+ printf("\n");
+#endif
+}
+
+STATIC int ci_cpl_find_pid (int slot, int pid)
+{
+ if (slot < 0 || slot >= CA_MAX_SLOTS) {
+ return -1;
+ }
+ int i;
+ for (i = 0; i < CA_MAX_PIDS; i++) {
+ if (pid == cpl[slot].pid[i])
+ return 1;
+ }
+ return 0;
+}
+
+STATIC int ci_cpl_find_caid (int slot, int caid)
+{
+ if (slot < 0 || slot >= CA_MAX_SLOTS) {
+ return -1;
+ }
+ int i;
+ for (i = 0; i < CA_MAX_CAIDS; i++) {
+ if (caid == cpl[slot].caid[i])
+ return 1;
+ }
+ return 0;
+}
+
+STATIC int ci_cpl_find_capid (int slot, int pid)
+{
+ if (slot < 0 || slot >= CA_MAX_SLOTS) {
+ return -1;
+ }
+ int i;
+ for (i = 0; i < CA_MAX_PIDS; i++) {
+ if (pid == cpl[slot].capid[i])
+ return 1;
+ }
+ return 0;
+}
+
+STATIC int ci_cpl_delete_pid (int slot, int pid)
+{
+ if (slot < 0 || slot >= CA_MAX_SLOTS) {
+ return -1;
+ }
+ int i;
+ for (i = 0; i < CA_MAX_PIDS; i++) {
+ if (cpl[slot].pid[i]==pid) {
+ cpl[slot].pid[i] = 0;
+ dbg ("-------> Slot: %d Deleted pid: %04x\n", slot, pid);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+STATIC int ci_cpl_update_pid (int slot, int pid)
+{
+ if (slot < 0 || slot >= CA_MAX_SLOTS) {
+ return -1;
+ }
+ if (!ci_cpl_find_pid (slot, pid)) {
+ int i;
+ for (i = 0; i < CA_MAX_PIDS; i++) {
+ if (!cpl[slot].pid[i]) {
+ cpl[slot].pid[i] = pid;
+ dbg ("-------> Slot: %d Added pid: %04x\n", slot, pid);
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+STATIC int ci_cpl_update_caid (int slot, int caid)
+{
+ if (slot < 0 || slot >= CA_MAX_SLOTS) {
+ return -1;
+ }
+ if (!ci_cpl_find_caid (slot, caid)) {
+ int i;
+ for (i = 0; i < CA_MAX_CAIDS; i++) {
+ if (!cpl[slot].caid[i]) {
+ cpl[slot].caid[i] = caid;
+ dbg ("-------> Slot: %d Added caid: %04x\n", slot, caid);
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+STATIC int ci_cpl_update_capid (int slot, int capid)
+{
+ if (slot < 0 || slot >= CA_MAX_SLOTS) {
+ return -1;
+ }
+ if (!ci_cpl_find_capid (slot, capid)) {
+ int i;
+ for (i = 0; i < CA_MAX_PIDS; i++) {
+ if (!cpl[slot].capid[i]) {
+ cpl[slot].capid[i] = capid;
+ dbg ("-------> Slot: %d Added capid: %04x\n", slot, capid);
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+int ci_cpl_find_caid_by_pid (int pid)
+{
+ int i;
+ int slot;
+
+ if(!pid) {
+ return 0;
+ }
+ for (slot = 0; slot < CA_MAX_SLOTS; slot++) {
+ for (i = 0; i < CA_MAX_PIDS; i++) {
+ if (pid == cpl[slot].pid[i]) {
+ return cpl[slot].caid[0];
+ }
+ }
+ }
+ return 0;
+}
+
+int ci_cpl_find_slot_by_caid_and_pid (int caid, int pid)
+{
+ int slot;
+ for (slot = 0; slot < CA_MAX_SLOTS; slot++) {
+ if (ci_cpl_find_pid (slot, pid) && ci_cpl_find_caid (slot, caid)) {
+ return slot;
+ }
+ }
+ return -1;
+}
+
+int ci_cpl_clear (int slot)
+{
+ if (slot < 0 || slot >= CA_MAX_SLOTS) {
+ return -1;
+ }
+ memset (&cpl[slot], 0, sizeof (caid_pid_list_t));
+ return 0;
+}
+
+int ci_cpl_clear_pids (int slot)
+{
+ if (slot < 0 || slot >= CA_MAX_SLOTS) {
+ return -1;
+ }
+ memset (cpl[slot].pid, 0, sizeof (u_int16_t) * CA_MAX_PIDS);
+ return 0;
+}
+
+int ci_cpl_clear_caids (int slot)
+{
+ if (slot < 0 || slot >= CA_MAX_SLOTS) {
+ return -1;
+ }
+ memset (cpl[slot].caid, 0, sizeof (u_int16_t) * CA_MAX_CAIDS);
+ return 0;
+}
+
+int ci_cpl_clear_capids (int slot)
+{
+ if (slot < 0 || slot >= CA_MAX_SLOTS) {
+ return -1;
+ }
+ memset (cpl[slot].capid, 0, sizeof (u_int16_t) * CA_MAX_PIDS);
+ return 0;
+}
+
+STATIC int ci_decode_length (unsigned int *len, u_int8_t * v)
+{
+ int ret = 0;
+
+ if (*v & LENGTH_SIZE_INDICATOR) {
+ int l = *v & 0x7f;
+ if (l > 4) {
+ return -1;
+ }
+ ret = l + 1;
+ *len = 0;
+ while (l--) {
+ v++;
+ *len <<= 8;
+ *len |= *v;
+ }
+ } else {
+ *len = *v;
+ ret = 1;
+ }
+ return ret;
+}
+
+#if 0
+STATIC int ci_decode_al_ca_info (ci_al_t * al)
+{
+ int i = 0;
+ u_int8_t *data = al->data;
+ int len = al->length;
+
+ if (len & 1) {
+ dbg ("ci_decode_al_ca_info: invalid length %d\n", len);
+ }
+
+ len >>= 1;
+
+ u_int16_t *caid = (u_int16_t *) malloc (sizeof (u_int16_t) * len);
+ ci_cpl_clear_caids (al->sl->tl->ll->slot);
+ while (i < len) {
+ caid[i++] = ntohs16 (data);
+ data += 2;
+ ci_cpl_update_caid (al->sl->tl->ll->slot, caid[i - 1]);
+ dbg ("CAID[%d]: %04x\n", i - 1, caid[i - 1]);
+ }
+ if (caid) {
+ free (caid);
+ }
+ return data - al->data;
+}
+#endif
+
+STATIC int ca_decode_ca_descr (ca_desc_t ** cadescr, int count, u_int8_t * data, int len, int *magic)
+{
+ *cadescr = (ca_desc_t *) realloc (*cadescr, sizeof (ca_desc_t *) * (count + 1));
+ if (!*cadescr) {
+ err ("ca_decode_ca_descr: out of memory\n");
+ }
+ ca_desc_t *c = *cadescr + count;
+
+// u_int8_t descriptor_tag = *data;
+ data++;
+ u_int8_t descriptor_length = *data;
+ data++;
+ c->ca_id = ntohs16 (data);
+ data += 2;
+ c->ca_pid = ntohs16 (data);
+ data += 2;
+ dbg ("cadescr: %p %d ca_id: %04x ca_pid: %04x\n", cadescr, count, c->ca_id, c->ca_pid);
+ if(magic && c->ca_id > 0 && c->ca_id < 3 && c->ca_pid > 0 && c->ca_pid < 3 && c->ca_id == c->ca_pid){
+ *magic = c->ca_id;
+ }
+ return descriptor_length + 2;
+}
+
+
+STATIC int ci_decode_al_ca_pmt (ci_al_t * al)
+{
+ ca_pmt_t p;
+ int magic = 0;
+ int slot = 0;
+ int cleared = 0;
+
+ memset (&p, 0, sizeof (ca_pmt_t));
+
+ int ret;
+ u_int8_t *data = al->data;
+ int len;
+
+ p.ca_pmt_list_management = *data;
+ data++;
+
+ p.program_number = ntohs16 (data);
+ data += 2;
+
+ p.version_number = *data;
+ data++;
+
+ p.program_info_length = (u_int16_t) ntohs16 (data);
+ data += 2;
+
+ dbg ("ci_decode_al_ca_pmt: ca_pmt_list_management:%02x program_number:%04x version_number:%02x program_info_length:%04x\n", p.ca_pmt_list_management, p.program_number, p.version_number, p.program_info_length);
+ if (p.program_info_length) {
+ int ca_descr_count = 0;
+ len = p.program_info_length - 1;
+ p.ca_pmt_cmd_id = *data;
+ dbg ("p.ca_pmt_cmd_id:%02x\n", p.ca_pmt_cmd_id);
+ data++;
+ while (len>0) {
+ ret = ca_decode_ca_descr (&p.cadescr, ca_descr_count, data, len, &magic);
+ if (magic)
+ slot = magic - 1;
+ else
+ slot = al->sl->tl->ll->slot;
+ if (!cleared) {
+ if(p.ca_pmt_list_management == CPLM_ONLY || p.ca_pmt_list_management == CPLM_FIRST || p.ca_pmt_list_management == CPLM_UPDATE) {
+ ci_cpl_clear_pids(slot);
+ ci_cpl_clear_capids(slot);
+ ci_cpl_clear_caids(slot);
+ cleared = 1;
+ }
+ }
+ if (ret < 0) {
+ warn ("error decoding ca_descriptor\n");
+ break;
+ }
+ if((magic != p.cadescr[ca_descr_count].ca_id) || (magic != p.cadescr[ca_descr_count].ca_pid)){
+ ci_cpl_update_caid (slot, p.cadescr[ca_descr_count].ca_id);
+ ci_cpl_update_capid (slot, p.cadescr[ca_descr_count].ca_pid);
+ }
+ ca_descr_count++;
+ data += ret;
+ len -= ret;
+ }
+ if (p.cadescr) {
+ free (p.cadescr);
+ }
+ }
+
+ len = al->length - (data - al->data);
+ int pidn = 0;
+
+ while (len>0) {
+ p.pidinfo = (pidinfo_t *) realloc (p.pidinfo, sizeof (pidinfo_t) * (pidn + 1));
+ if (!p.pidinfo) {
+ err ("ci_decode_al_ca_pmt: out of memory");
+ }
+ memset (&p.pidinfo[pidn], 0, sizeof (pidinfo_t));
+ p.pidinfo[pidn].stream_type = *data;
+ data++;
+ len--;
+ p.pidinfo[pidn].pid = ntohs16 (data);
+ data += 2;
+ len -= 2;
+ p.pidinfo[pidn].es_info_length = ntohs16 (data);
+ data += 2;
+ len -= 2;
+
+ dbg ("len: %d count: %d, stream_type: %02x, pid: %04x es_info_length: %04x\n", len, pidn, p.pidinfo[pidn].stream_type, p.pidinfo[pidn].pid, p.pidinfo[pidn].es_info_length);
+ if (p.pidinfo[pidn].es_info_length) {
+ int pi_len = p.pidinfo[pidn].es_info_length - 1;
+ p.pidinfo[pidn].ca_pmt_cmd_id = *data;
+ data++;
+ len--;
+ int pid_ca_descr_count = 0;
+ while (pi_len>0) {
+ ret = ca_decode_ca_descr (&p.pidinfo[pidn].cadescr, pid_ca_descr_count, data, pi_len, NULL);
+ if (!cleared) {
+ if(p.ca_pmt_list_management == CPLM_ONLY || p.ca_pmt_list_management == CPLM_FIRST || p.ca_pmt_list_management == CPLM_UPDATE) {
+ ci_cpl_clear_pids(slot);
+ ci_cpl_clear_capids(slot);
+ ci_cpl_clear_caids(slot);
+ cleared = 1;
+ }
+ }
+ if (ret < 0) {
+ warn ("error decoding ca_descriptor\n");
+ break;
+ }
+ if((magic != p.pidinfo[pidn].cadescr[pid_ca_descr_count].ca_id) || (magic != p.pidinfo[pidn].cadescr[pid_ca_descr_count].ca_pid)){
+ ci_cpl_update_pid (slot, p.pidinfo[pidn].pid);
+ ci_cpl_update_caid (slot, p.pidinfo[pidn].cadescr[pid_ca_descr_count].ca_id);
+ ci_cpl_update_capid (slot, p.pidinfo[pidn].cadescr[pid_ca_descr_count].ca_pid);
+ }
+ pid_ca_descr_count++;
+ data += ret;
+ pi_len -= ret;
+ len -= ret;
+ }
+ }
+ if (p.pidinfo[pidn].cadescr) {
+ free (p.pidinfo[pidn].cadescr);
+ }
+ pidn++;
+ }
+ if (p.pidinfo) {
+ free (p.pidinfo);
+ }
+ return 0;
+}
+
+STATIC int ci_decode_al_ca_pmt_reply (ci_al_t * al)
+{
+ ca_pmt_reply_t p;
+
+ memset (&p, 0, sizeof (ca_pmt_reply_t));
+
+ u_int8_t *data = al->data;
+ int len;
+
+ p.program_number = ntohs16 (data);
+ data += 2;
+
+ p.version_number = *data;
+ data++;
+
+ p.ca_enable = *data;
+ data++;
+
+ len = al->length - (data - al->data);
+ int pidn = 0;
+
+ dbg ("ci_decode_al_ca_pmt_reply: program_number: %04x ca_enable: %02x\n", p.program_number, p.ca_enable);
+
+ while (len>0) {
+ p.pidcaenable = (pid_ca_enable_t *) realloc (p.pidcaenable, sizeof (pid_ca_enable_t) * (pidn + 1));
+ if (!p.pidcaenable) {
+ err ("ci_decode_al_ca_pmt_reply: out of memory\n");
+ }
+ memset (&p.pidcaenable[pidn], 0, sizeof (pid_ca_enable_t));
+ p.pidcaenable[pidn].pid = ntohs16 (data);
+ data += 2;
+ p.pidcaenable[pidn].ca_enable = *data;
+ data++;
+ len -= 3;
+ if ((p.pidcaenable[pidn].ca_enable == CPCI_OK_DESCRAMBLING) || (p.pidcaenable[pidn].ca_enable == CPCI_OK_MMI) || (p.pidcaenable[pidn].ca_enable == CPCI_QUERY)) {
+ ci_cpl_update_pid (al->sl->tl->ll->slot, p.pidcaenable[pidn].pid);
+ } else {
+ ci_cpl_delete_pid (al->sl->tl->ll->slot, p.pidcaenable[pidn].pid);
+ }
+ dbg ("count: %d pid: %04x pid_ca_enable: %02x\n", pidn, p.pidcaenable[pidn].pid, p.pidcaenable[pidn].ca_enable);
+ pidn++;
+ }
+ if (p.pidcaenable) {
+ free (p.pidcaenable);
+ }
+ return 0;
+}
+
+STATIC int ci_decode_al (ci_sl_t * sl)
+{
+ int ret = 0;
+ int done = 0;
+ int len = 3;
+ ci_al_t al;
+ u_int8_t *data = sl->data;
+ al.sl = sl;
+
+ al.tag = 0;
+ while (len--) {
+ al.tag <<= 8;
+ al.tag |= *data;
+ data++;
+ }
+ done += 3;
+ ret = ci_decode_length (&al.length, data);
+ if (ret < 0) {
+ warn ("ci_decode_al ci_decode_length failed\n");
+ return ret;
+ }
+
+ data += ret;
+ done += ret;
+ //Fake
+ al.data = data;
+
+ dbg ("ci_decode_al: tag:%03x length: %02x data[0]:%02x done: %02x\n", al.tag, al.length, al.data[0], done);
+
+ switch (al.tag) {
+ case AOT_CA_INFO:
+// ci_decode_al_ca_info (&al);
+ break;
+ case AOT_CA_PMT:
+ ci_decode_al_ca_pmt (&al);
+ break;
+ case AOT_CA_PMT_REPLY:
+ ci_decode_al_ca_pmt_reply (&al);
+ break;
+ }
+
+ done += al.length;
+
+ dbg ("ci_decode_al: done %02x\n", done);
+ return done;
+}
+
+STATIC int ci_decode_sl (ci_tl_t * tl)
+{
+ int ret = 0;
+ int done = 0;
+ unsigned int len;
+ ci_sl_t sl;
+ u_int8_t *data = tl->data;
+ sl.tl = tl;
+
+ sl.tag = *data;
+ data++;
+ done++;
+
+ if(sl.tag != ST_SESSION_NUMBER) {
+ return tl->length;
+ }
+
+ ret = ci_decode_length (&len, data);
+ if (ret < 0) {
+ warn ("ci_decode_sl ci_decode_length failed\n");
+ return ret;
+ }
+ data += ret;
+ done += ret;
+
+ if (len > 4) {
+ warn ("invalid length (%d) for session_object_value\n", len);
+ return -1;
+ }
+
+ sl.object_value = 0;
+ while (len--) {
+ sl.object_value <<= 8;
+ sl.object_value |= *data;
+ data++;
+ done++;
+ }
+
+ sl.data = data;
+ sl.length = tl->length - done;
+
+ while (sl.length>0) {
+ dbg ("ci_decode_sl: object_value:%02x length: %02x done: %02x\n", sl.object_value, sl.length, done);
+ ret = ci_decode_al (&sl);
+ if (ret < 0) {
+ warn ("ci_decode_al failed\n");
+ return ret;
+ }
+ sl.length -= ret;
+ sl.data += ret;
+ done += ret;
+ }
+ dbg ("ci_decode_sl: done %02x\n", done);
+ return done;
+}
+
+STATIC int ci_decode_tl (ci_ll_t * ll)
+{
+ int ret = 0;
+ int done = 0;
+ ci_tl_t tl;
+ u_int8_t *data = ll->data;
+ tl.ll = ll;
+
+ tl.c_tpdu_tag = *data;
+ data++;
+ done++;
+
+ ret = ci_decode_length (&tl.length, data);
+ if (ret < 0) {
+ warn ("ci_decode_tl ci_decode_length failed\n");
+ return ret;
+ }
+
+ data += ret;
+ done += ret;
+
+ tl.tcid = *data;
+ data++;
+ done++;
+
+ if (tl.tcid != ll->tcid) {
+ warn ("Error: redundant tcid mismatch %02x %02x\n",tl.tcid, ll->tcid);
+ return -1;
+ }
+
+ tl.data = data;
+
+ //According to A.4.1.1
+ tl.length--;
+
+ while (tl.length>0) {
+ dbg ("ci_decode_tl: c_tpdu_tag:%02x tcid:%02x length: %02x done: %02x\n", tl.c_tpdu_tag, tl.tcid, tl.length, done);
+ if (tl.c_tpdu_tag == T_DATA_LAST || tl.c_tpdu_tag == T_DATA_MORE) {
+ ret = ci_decode_sl (&tl);
+ if (ret < 0) {
+ warn ("ci_decode_sl failed\n");
+ return ret;
+ }
+ } else {
+ ret = tl.length;
+ }
+ tl.length -= ret;
+ tl.data += ret;
+ done += ret;
+ }
+ dbg ("ci_decode_tl: done %02x\n", done);
+ return done;
+}
+
+int ci_decode_ll (uint8_t * tpdu, int len)
+{
+ int ret = 0;
+ int done = 0;
+ u_int8_t *data=tpdu;
+ ci_ll_t ll;
+ dump(tpdu,len);
+
+ ll.slot = *data;
+ data++;
+
+ ll.tcid = *data;
+ data++;
+
+ ll.data = data;
+ ll.length = len - (data-tpdu);
+
+ while (ll.length) {
+
+ dbg ("ci_decode_ll: slot:%02x tcid:%02x length: %02x\n", ll.slot, ll.tcid, ll.length);
+ ret = ci_decode_tl (&ll);
+ if (ret < 0) {
+ warn ("ci_decode_tl failed\n");
+ return ret;
+ }
+ ll.length -= ret;
+ ll.data += ret;
+ }
+ dbg ("ci_decode_ll: done %02x\n", len);
+ return done;
+}
+
+#ifdef TESTING
+int main (int argc, char **argv)
+{
+ int ret;
+
+ printf ("ci_decode_ll len: %02x\n", sizeof (lb));
+ ret = ci_decode_ll (lb, sizeof (lb));
+ printf ("ci_decode_ll ret: %02x\n", ret);
+
+ printf ("ci_decode_ll len: %02x\n", sizeof (ll));
+ ret = ci_decode_ll (ll, sizeof (ll));
+ printf ("ci_decode_ll ret: %02x\n", ret);
+
+
+ printf ("ci_decode_ll len: %02x\n", sizeof (ld));
+ ret = ci_decode_ll (ld, sizeof (ld));
+ printf ("ci_decode_ll ret: %02x\n", ret);
+
+ printf ("ci_decode_ll len: %02x\n", sizeof (lc));
+ ret = ci_decode_ll (lc, sizeof (lc));
+ printf ("ci_decode_ll ret: %02x\n", ret);
+
+ printf ("ci_decode_ll len: %02x\n", sizeof (le));
+ ret = ci_decode_ll (le, sizeof (le));
+ printf ("ci_decode_ll ret: %02x\n", ret);
+
+// printf ("caid %04x for pid %04x\n", ci_cpl_find_caid_by_pid (0x5c), 0x5c);
+ return 0;
+}
+#endif
diff --git a/mcast/common/.svn/text-base/ciparser.h.svn-base b/mcast/common/.svn/text-base/ciparser.h.svn-base
new file mode 100644
index 0000000..44cb810
--- /dev/null
+++ b/mcast/common/.svn/text-base/ciparser.h.svn-base
@@ -0,0 +1,140 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ */
+
+#define ntohs16(data) ((u_int16_t)data[0]<<8 | (u_int16_t)data[1])
+typedef struct {
+ u_int16_t len;
+ u_int8_t *data;
+} ci_pdu_t;
+
+typedef struct
+{
+ u_int8_t slot;
+ u_int8_t tcid;
+ u_int32_t length;
+ u_int8_t *data;
+} ci_ll_t;
+
+typedef struct
+{
+ ci_ll_t *ll;
+ u_int8_t c_tpdu_tag;
+ u_int32_t length;
+ u_int8_t tcid;
+ u_int8_t *data;
+} ci_tl_t;
+
+typedef struct
+{
+ ci_tl_t *tl;
+ u_int8_t tag;
+ u_int32_t length;
+ u_int32_t object_value;
+ u_int8_t *data;
+} ci_sl_t;
+
+typedef struct
+{
+ ci_sl_t *sl;
+ u_int32_t tag;
+ u_int32_t length;
+ u_int8_t *data;
+} ci_al_t;
+
+typedef struct
+{
+ u_int16_t ca_id;
+ u_int16_t ca_pid;
+} ca_desc_t;
+
+typedef struct
+{
+ u_int8_t stream_type;
+ u_int16_t pid;
+ u_int16_t es_info_length;
+ u_int8_t ca_pmt_cmd_id;
+ ca_desc_t *cadescr;
+} pidinfo_t;
+
+typedef struct
+{
+ u_int8_t ca_pmt_list_management;
+ u_int16_t program_number;
+ u_int8_t version_number;
+ u_int8_t current_next;
+ u_int16_t program_info_length;
+ u_int8_t ca_pmt_cmd_id;
+ ca_desc_t *cadescr;
+ pidinfo_t *pidinfo;
+} ca_pmt_t;
+
+typedef struct
+{
+ u_int16_t pid;
+ u_int8_t ca_enable;
+} pid_ca_enable_t;
+
+typedef struct
+{
+ u_int16_t program_number;
+ u_int8_t version_number;
+ u_int8_t current_next;
+ u_int8_t ca_enable;
+ pid_ca_enable_t *pidcaenable;
+} ca_pmt_reply_t;
+
+
+#define LENGTH_SIZE_INDICATOR 0x80
+
+#define CPLM_MORE 0x00
+#define CPLM_FIRST 0x01
+#define CPLM_LAST 0x02
+#define CPLM_ONLY 0x03
+#define CPLM_ADD 0x04
+#define CPLM_UPDATE 0x05
+
+#define CPCI_OK_DESCRAMBLING 0x01
+#define CPCI_OK_MMI 0x02
+#define CPCI_QUERY 0x03
+#define CPCI_NOT_SELECTED 0x04
+
+#define AOT_CA_INFO_ENQ 0x9F8030
+#define AOT_CA_INFO 0x9F8031
+#define AOT_CA_PMT 0x9F8032
+#define AOT_CA_PMT_REPLY 0x9F8033
+
+#define ST_SESSION_NUMBER 0x90
+#define ST_OPEN_SESSION_REQUEST 0x91
+#define ST_OPEN_SESSION_RESPONSE 0x92
+#define ST_CREATE_SESSION 0x93
+#define ST_CREATE_SESSION_RESPONSE 0x94
+#define ST_CLOSE_SESSION_REQUEST 0x95
+#define ST_CLOSE_SESSION_RESPONSE 0x96
+
+#define DATA_INDICATOR 0x80
+
+#define T_SB 0x80
+#define T_RCV 0x81
+#define T_CREATE_TC 0x82
+#define T_CTC_REPLY 0x83
+#define T_DELETE_TC 0x84
+#define T_DTC_REPLY 0x85
+#define T_REQUEST_TC 0x86
+#define T_NEW_TC 0x87
+#define T_TC_ERROR 0x88
+#define T_DATA_LAST 0xA0
+#define T_DATA_MORE 0xA1
+
+
+DLL_SYMBOL int ci_cpl_find_caid_by_pid (int pid);
+DLL_SYMBOL int ci_cpl_find_slot_by_caid_and_pid (int caid, int pid);
+DLL_SYMBOL int ci_cpl_clear (int slot);
+DLL_SYMBOL int ci_cpl_clear_pids (int slot);
+DLL_SYMBOL int ci_cpl_clear_caids (int slot);
+DLL_SYMBOL int ci_cpl_clear_capids (int slot);
+DLL_SYMBOL int ci_decode_ll (uint8_t * data, int len);
diff --git a/mcast/common/.svn/text-base/crc32.c.svn-base b/mcast/common/.svn/text-base/crc32.c.svn-base
new file mode 100644
index 0000000..65f08ac
--- /dev/null
+++ b/mcast/common/.svn/text-base/crc32.c.svn-base
@@ -0,0 +1,88 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ */
+
+/*
+$Id: crc32.c,v 1.2 2006/01/02 18:24:04 rasc Exp $
+
+
+ DVBSNOOP
+
+ a dvb sniffer and mpeg2 stream analyzer tool
+ http://dvbsnoop.sourceforge.net/
+
+ (c) 2001-2006 Rainer.Scherg@gmx.de (rasc)
+
+
+ -- Code Module CRC32 taken von linuxtv.org
+*/
+
+
+
+
+#include "defs.h"
+#include "crc32.h"
+
+
+
+// CRC32 lookup table for polynomial 0x04c11db7
+
+static u_long crc_table[256] = {
+ 0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b,
+ 0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
+ 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7,
+ 0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
+ 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3,
+ 0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
+ 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef,
+ 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
+ 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb,
+ 0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1,
+ 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0,
+ 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
+ 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4,
+ 0x0808d07d, 0x0cc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde,
+ 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08,
+ 0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
+ 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc,
+ 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6,
+ 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050,
+ 0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
+ 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34,
+ 0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637,
+ 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1,
+ 0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
+ 0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5,
+ 0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
+ 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9,
+ 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
+ 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd,
+ 0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7,
+ 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71,
+ 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
+ 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2,
+ 0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8,
+ 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e,
+ 0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
+ 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a,
+ 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0,
+ 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676,
+ 0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
+ 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662,
+ 0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668,
+ 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4};
+
+uint32_t dvb_crc32 (char *data, int len)
+{
+ register int i;
+ u_long crc = 0xffffffff;
+
+ for (i=0; i<len; i++)
+ crc = (crc << 8) ^ crc_table[((crc >> 24) ^ *data++) & 0xff];
+
+ return crc;
+}
diff --git a/mcast/common/.svn/text-base/crc32.h.svn-base b/mcast/common/.svn/text-base/crc32.h.svn-base
new file mode 100644
index 0000000..f4bef5e
--- /dev/null
+++ b/mcast/common/.svn/text-base/crc32.h.svn-base
@@ -0,0 +1,35 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ */
+
+/*
+$Id: crc32.h,v 1.2 2006/01/02 18:24:04 rasc Exp $
+
+
+ DVBSNOOP
+
+ a dvb sniffer and mpeg2 stream analyzer tool
+ http://dvbsnoop.sourceforge.net/
+
+ (c) 2001-2006 Rainer.Scherg@gmx.de (rasc)
+
+
+ -- Code Module CRC32 taken von linuxtv.org
+
+*/
+
+
+
+#ifndef __CRC32_H
+#define __CRC32_H
+
+
+uint32_t dvb_crc32 (char *data, int len);
+
+
+#endif
+
diff --git a/mcast/common/.svn/text-base/defs.h.svn-base b/mcast/common/.svn/text-base/defs.h.svn-base
new file mode 100644
index 0000000..979b339
--- /dev/null
+++ b/mcast/common/.svn/text-base/defs.h.svn-base
@@ -0,0 +1,389 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ */
+
+#ifndef __DEFS_H__
+#define __DEFS_H__
+
+#ifdef WIN32
+ #ifdef __CYGWIN__
+ #include <cygwin/version.h>
+ #include <cygwin/in.h>
+ #include <cygwin/socket.h>
+ #else
+ #define _CRT_SECURE_NO_WARNINGS
+ #define _WIN32_WINNT 0x0502
+ #include <winsock2.h>
+ #include <WS2tcpip.h>
+ #include <iphlpapi.h>
+
+ #define _SOTYPE char*
+ #define IFNAMSIZ 1024
+ #define CA_TPDU_MAX 2048
+ #define _POSIX_PATH_MAX MAX_PATH
+ #define usleep(useconds) Sleep((useconds+500)/1000)
+ #define sleep(seconds) Sleep((seconds)*1000)
+ #define EAFNOSUPPORT WSAEAFNOSUPPORT
+ #ifndef IP_ADAPTER_IPV6_ENABLED
+ #define IP_ADAPTER_IPV6_ENABLED 0x0100
+ #endif
+
+ int inet_pton(int af, const char *src, void *dst);
+ const char *inet_ntop(int af, const void *src, char *dst, size_t size);
+ int inet_aton(const char *cp, struct in_addr *addr);
+ #ifndef __MINGW32__
+ int getopt(int nargc, char **nargv, char *ostr);
+ extern int opterr, optind, optopt, optreset;
+ extern char *optarg;
+ #define inline __inline
+ #endif
+
+ typedef struct
+ {
+ DWORD thread;
+ HANDLE threadH; /* Win32 thread handle - POSIX thread is invalid if threadH == 0 */
+ } ptw32_thread_t;
+
+ typedef unsigned int uint32_t;
+ typedef uint32_t __u32;
+ typedef uint32_t u_int32_t;
+ typedef unsigned short uint16_t;
+ typedef uint16_t __u16;
+ typedef uint16_t u_int16_t;
+ typedef unsigned char uint8_t;
+ typedef uint8_t __u8;
+ typedef uint8_t u_int8_t;
+ #ifndef s6_addr16
+ #define s6_addr16 s6_words
+ #endif
+ #if ! defined _GNU_SOURCE && defined __cplusplus
+ #define CALLCONV extern "C"
+ #else
+ #define CALLCONV
+ #endif
+ #ifdef LIBRARY
+ #define DLL_SYMBOL CALLCONV __declspec( dllexport )
+ #else
+ #ifdef STATICLIB
+ #define DLL_SYMBOL CALLCONV
+ #else
+ #define DLL_SYMBOL CALLCONV __declspec( dllimport )
+ #endif
+ #endif
+
+ #define pthread_exist(x) (x).p
+ #define pthread_null(x) (x).p=NULL
+ #define _SOTYPE char*
+ #define INET6
+ #define API_WIN
+ #define LIBXML_STATIC
+ #define PTW32_STATIC_LIB
+ #define MULTI_THREAD_RECEIVER
+
+ #include <poll.h>
+ #endif
+#else
+ #if defined __cplusplus
+ #define CALLCONV extern "C"
+ #else
+ #define CALLCONV
+ #endif
+ #define DLL_SYMBOL CALLCONV
+ #define pthread_exist(x) x
+ #define pthread_null(x) x=0
+ #define _SOTYPE void*
+ #define SOCKET int
+
+ #if ! (defined __uClinux__ || defined APPLE || defined MIPSEL)
+ #include <mcheck.h>
+ #include <ifaddrs.h>
+ #endif
+ #include <pwd.h>
+ #include <sched.h>
+ #include <syslog.h>
+ #include <unistd.h>
+ #include <getopt.h>
+ #include <stdint.h>
+ #include <termios.h>
+
+ #include <arpa/inet.h>
+ #ifndef APPLE
+ #include <linux/version.h>
+ #include <netpacket/packet.h>
+ #include <sys/sysinfo.h>
+ #else
+ typedef unsigned int uint32_t;
+ typedef uint32_t __u32;
+ typedef uint32_t u_int32_t;
+ typedef unsigned short uint16_t;
+ typedef uint16_t __u16;
+ typedef uint16_t u_int16_t;
+ typedef unsigned char uint8_t;
+ typedef uint8_t __u8;
+ typedef uint8_t u_int8_t;
+
+ #define CA_TPDU_MAX 2048
+
+ #define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP
+ #define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP
+ #ifndef s6_addr16
+ #define s6_addr16 __u6_addr.__u6_addr16
+ #endif
+ #endif
+
+ #include <netdb.h>
+
+ #include <net/if.h>
+ #ifdef APPLE
+ #include <ifaddrs.h>
+ #include <net/if_types.h>
+ #endif
+ #include <netinet/in.h>
+ #include <netinet/ip.h>
+ #include <netinet/icmp6.h>
+ #include <netinet/ip_icmp.h>
+ #include <netinet/if_ether.h>
+ #include <netinet/ip6.h>
+ #include <netinet/tcp.h>
+ #include <netinet/udp.h>
+
+ #include <sys/ioctl.h>
+ #include <sys/mman.h>
+ #include <sys/poll.h>
+ #include <sys/resource.h>
+ #include <sys/socket.h>
+ #include <sys/types.h>
+ #include <sys/uio.h> /* for iovec{} and readv/writev */
+ #include <sys/un.h> /* for Unix domain sockets */
+ #include <sys/utsname.h>
+ #include <sys/wait.h>
+
+ #if defined __uClinux__
+ #include <mathf.h>
+ #endif
+ #define closesocket close
+#endif
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <math.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <zlib.h>
+
+#include <sys/stat.h>
+
+//----------------------------------------------------------------------
+#ifndef __uClinux__
+ //DVBAPI
+ #include <linux/dvb/version.h>
+ #include <linux/dvb/frontend.h>
+ #include <linux/dvb/ca.h>
+ #if ! (defined WIN32 || defined APPLE)
+ #include <linux/dvb/dmx.h>
+ #endif
+// #else
+// #endif
+
+ #define dvb_ioctl ioctl
+ #define dvb_close close
+#else
+ #include <dvb/frontend.h>
+ #include <ci/ca.h>
+#endif
+
+#define CA_TPDU_MAX 2048
+
+typedef struct recv_sec
+{
+ struct dvb_diseqc_master_cmd diseqc_cmd;
+ fe_sec_mini_cmd_t mini_cmd;
+ fe_sec_tone_mode_t tone_mode;
+ fe_sec_voltage_t voltage;
+} recv_sec_t;
+
+#define CA_MAX_SLOTS 16
+typedef struct {
+ ca_caps_t cap;
+ ca_slot_info_t info[CA_MAX_SLOTS];
+} recv_cacaps_t;
+
+typedef struct recv_festatus
+{
+ fe_status_t st;
+ uint32_t ber;
+ uint16_t strength;
+ uint16_t snr;
+ uint32_t ucblocks;
+} recv_festatus_t;
+
+//XML
+#include <libxml/encoding.h>
+#include <libxml/xmlwriter.h>
+#include <libxml/xmlmemory.h>
+#include <libxml/parser.h>
+#include <libxml/xpath.h>
+
+#ifdef DMALLOC
+ #include <dmalloc.h>
+#endif
+
+#if ! defined GETTID && ! defined WIN32 && ! defined APPLE
+ #include <asm/unistd.h>
+ #define gettid() syscall (__NR_gettid)
+#else
+ #define gettid pthread_self
+#endif
+
+#define UUID_SIZE 256
+#ifndef WIN32
+
+#ifdef SYSLOG
+extern char *_logstr;
+extern pthread_mutex_t _loglock;
+
+ #ifdef DEBUG
+ #define dbg(format, arg...) { pthread_mutex_lock (&_loglock); sprintf(_logstr, "%s:%d " format , __FILE__ , __LINE__ , ## arg); syslog_write(_logstr); pthread_mutex_unlock (&_loglock);}
+ #else
+ #define dbg(format, arg...) do {} while (0)
+ #endif
+ #define err(format, arg...) {pthread_mutex_lock (&_loglock); sprintf(_logstr, "err:%s:%d: %s (%d): " format , __FILE__ , __LINE__ ,strerror(errno), errno, ## arg); fprintf(stdout, "%s", _logstr); syslog_write(_logstr);abort(); pthread_mutex_unlock (&_loglock);}
+ #define info(format, arg...){pthread_mutex_lock (&_loglock); sprintf(_logstr, format ,## arg); fprintf(stdout, "%s", _logstr); syslog_write(_logstr); pthread_mutex_unlock (&_loglock);}
+ #define warn(format, arg...){pthread_mutex_lock (&_loglock); sprintf(_logstr, format ,## arg); fprintf(stdout, "%s", _logstr); syslog_write(_logstr); pthread_mutex_unlock (&_loglock);}
+ #define sys(format, arg...){pthread_mutex_lock (&_loglock); sprintf(_logstr, format ,## arg); syslog_write(_logstr); pthread_mutex_unlock (&_loglock);}
+#elif defined DEBUG
+ #define dbg(format, arg...) {printf("%s:%d " format , __FILE__ , __LINE__ , ## arg)}
+ #define err(format, arg...) {fprintf(stderr,"err:%s:%d: %s (%d): " format , __FILE__ , __LINE__ ,strerror(errno), errno, ## arg);print_trace();abort();}
+ #define info(format, arg...) printf("%s:%d: " format , __FILE__ , __LINE__ ,## arg)
+ #define warn(format, arg...) fprintf(stderr,"%s:%d: " format , __FILE__ , __LINE__ ,## arg)
+#else
+ #define dbg(format, arg...) do {} while (0)
+ #define err(format, arg...) {fprintf(stderr,"%s (%d): " format, strerror(errno), errno, ## arg);exit(-1);}
+ #define info(format, arg...) printf(format , ## arg)
+ #define warn(format, arg...) fprintf(stderr, format , ## arg)
+ #define sys(format, arg...) printf(format, ## arg)
+#endif // SYSLOG
+
+#else // !WIN32
+ #ifdef DEBUG
+ static void inline dbg (char *format, ...)
+ {
+ char buffer[1024];
+ va_list args;
+ va_start (args, format);
+ vsprintf (buffer, format, args);
+ printf("%s:%d %s", __FILE__ , __LINE__ , buffer);
+ va_end (args);
+ }
+ static void inline err (char *format, ...)
+ {
+ char buffer[1024];
+ va_list args;
+ va_start (args, format);
+ vsprintf(buffer, format , args);
+ fprintf(stderr, "err:%s:%d: %s (%d): %s " , __FILE__ , __LINE__ ,strerror(errno), errno, buffer);
+ va_end (args);
+ abort();
+ }
+ static void inline info(const char *format, ...)
+ {
+ char buffer[1024];
+ va_list args;
+ va_start (args, format);
+ vsprintf(buffer, format , args);
+ printf("%s:%d: %s" , __FILE__ , __LINE__ , buffer);
+ va_end (args);
+ }
+ static void inline warn(const char *format, ...)
+ {
+ char buffer[1024];
+ va_list args;
+ va_start (args, format);
+ vsprintf(buffer, format , args);
+ fprintf(stderr, "%s:%d: %s", __FILE__ , __LINE__ , buffer );
+ va_end (args);
+ }
+ static void inline sys(const char *format, ...)
+ {
+ char buffer[1024];
+ va_list args;
+ va_start (args, format);
+ vsprintf(buffer, format , args);
+ printf("%s:%d: %s", __FILE__ , __LINE__ , buffer );
+ va_end (args);
+ }
+ #else
+ static void inline dbg (char *format, ...)
+ {
+ }
+ static void inline err (char *format, ...)
+ {
+ char buffer[1024];
+ va_list args;
+ va_start (args, format);
+ vsprintf(buffer, format, args);
+ fprintf(stderr, "err:%s:%d: %s",strerror(errno), errno, buffer);
+ va_end (args);
+ abort();
+ }
+ static void inline info(const char *format, ...)
+ {
+ char buffer[1024];
+ va_list args;
+ va_start (args, format);
+ vsprintf(buffer, format, args);
+ puts(buffer);
+ va_end (args);
+ }
+ static void inline warn(const char *format, ...)
+ {
+ char buffer[1024];
+ va_list args;
+ va_start (args, format);
+ vsprintf(buffer, format, args);
+ fputs(buffer, stderr);
+ va_end (args);
+ }
+ static void inline sys(const char *format, ...)
+ {
+ char buffer[1024];
+ va_list args;
+ va_start (args, format);
+ vsprintf(buffer, format, args);
+ fputs(buffer, stdout);
+ va_end (args);
+ }
+
+ #endif //DEBUG
+#endif // WIN32
+
+#ifndef MICROBLAZE
+ #define FE_DVBS2 (FE_ATSC+1)
+#endif
+
+// RMM S2 Extension
+#define FEC_1_4 10
+#define FEC_1_3 11
+#define FEC_2_5 12
+#define FEC_3_5 13
+#define FEC_9_10 14
+#define QPSK_S2 9
+#define PSK8 10
+
+#ifdef MICROBLAZE
+ #define STATIC
+#else
+ #define STATIC static
+#endif
+#endif
diff --git a/mcast/common/.svn/text-base/dvb_ca_wrapper.h.svn-base b/mcast/common/.svn/text-base/dvb_ca_wrapper.h.svn-base
new file mode 100644
index 0000000..d0873aa
--- /dev/null
+++ b/mcast/common/.svn/text-base/dvb_ca_wrapper.h.svn-base
@@ -0,0 +1,18 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ */
+
+#ifndef __DVB_CA_WRAPPER_H
+#define __user
+unsigned int dvb_cam_poll(struct pollfd *pfd, int fdnum, int timeout_ms);
+ssize_t dvb_cam_read(int dummy, char __user * buf, size_t count);
+ssize_t dvb_cam_write(int dummy, char __user * buf, size_t count);
+int dvb_cam_ioctl(int dummy, unsigned int cmd, void *parg);
+int dvb_cam_open(const char* dummy, int dummy1);
+int dvb_cam_close(int fd);
+
+#endif
diff --git a/mcast/common/.svn/text-base/input.h.svn-base b/mcast/common/.svn/text-base/input.h.svn-base
new file mode 100644
index 0000000..fbda65b
--- /dev/null
+++ b/mcast/common/.svn/text-base/input.h.svn-base
@@ -0,0 +1,38 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ */
+
+#ifndef __INPUT_H__
+#define __INPUT_H__
+typedef struct
+{
+ int port;
+ char iface[IFNAMSIZ];
+ time_t start_time;
+#ifdef SERVER
+ int tuner_number;
+ char cfgpath[_POSIX_PATH_MAX];
+ int verbose;
+#endif
+#ifdef CLIENT
+ char disec_conf_path[_POSIX_PATH_MAX];
+ char rotor_conf_path[_POSIX_PATH_MAX];
+ char cmd_sock_path[_POSIX_PATH_MAX];
+ int tuner_type_limit[FE_DVBS2+1];
+ int mld_start;
+ int ca_enable;
+ int ci_timeout;
+ int vdrdiseqcmode;
+ int reelcammode;
+#endif
+} cmdline_t;
+
+extern cmdline_t cmd;
+
+void get_options (int argc, char *argv[]);
+
+#endif
diff --git a/mcast/common/.svn/text-base/interfaces.c.svn-base b/mcast/common/.svn/text-base/interfaces.c.svn-base
new file mode 100644
index 0000000..bd19c8d
--- /dev/null
+++ b/mcast/common/.svn/text-base/interfaces.c.svn-base
@@ -0,0 +1,347 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ */
+
+#include "headers.h"
+
+void int_destroy (struct intnode *intn)
+{
+ dbg ("Destroying interface %s\n", intn->name);
+
+ /* Resetting the MTU to zero disabled the interface */
+ intn->mtu = 0;
+}
+
+struct intnode *int_find (unsigned int ifindex)
+{
+ unsigned int i;
+ for (i = 0; i < g_conf->maxinterfaces; i++) {
+ if(g_conf->ints[i].ifindex == ifindex) {
+ return g_conf->ints+i;
+ }
+ }
+ return NULL;
+}
+
+struct intnode *int_find_name (char *ifname)
+{
+ unsigned int i;
+ for (i = 0; i < g_conf->maxinterfaces; i++) {
+ if (!strcmp (ifname, g_conf->ints[i].name) && g_conf->ints[i].mtu != 0) {
+ return g_conf->ints+i;
+ }
+ }
+ return NULL;
+}
+
+
+struct intnode *int_find_first (void)
+{
+ unsigned int i;
+ for (i = 0; i < g_conf->maxinterfaces; i++) {
+ dbg("int: %d %s\n",i, g_conf->ints[i].name);
+ if (g_conf->ints[i].mtu != 0) {
+ return g_conf->ints+i;
+ }
+ }
+ return NULL;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+#if ! (defined WIN32 || defined APPLE) || defined __CYGWIN__
+
+/* Initiliaze interfaces */
+void update_interfaces (struct intnode *intn)
+{
+ struct in6_addr addr;
+
+ FILE *file;
+ unsigned int prefixlen, scope, flags, ifindex;
+ char devname[IFNAMSIZ];
+
+ /* Only update every 5 seconds to avoid rerunning it every packet */
+ if (g_conf->maxinterfaces)
+ return;
+
+ dbg ("Updating Interfaces\n");
+
+ /* Get link local addresses from /proc/net/if_inet6 */
+ file = fopen ("/proc/net/if_inet6", "r");
+
+ /* We can live without it though */
+ if (!file) {
+ err ("Cannot open /proc/net/if_inet6\n");
+ return;
+ }
+
+ char buf[255];
+ /* Format "fe80000000000000029027fffe24bbab 02 0a 20 80 eth0" */
+ while (fgets (buf, sizeof (buf), file)) {
+ if (21 != sscanf (buf, "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx %x %x %x %x %8s", &addr.s6_addr[0], &addr.s6_addr[1], &addr.s6_addr[2], &addr.s6_addr[3], &addr.s6_addr[4], &addr.s6_addr[5], &addr.s6_addr[6], &addr.s6_addr[7], &addr.s6_addr[8], &addr.s6_addr[9], &addr.s6_addr[10], &addr.s6_addr[11], &addr.s6_addr[12], &addr.s6_addr[13], &addr.s6_addr[14], &addr.s6_addr[15], &ifindex, &prefixlen, &scope, &flags, devname)) {
+
+ warn ("/proc/net/if_inet6 in wrong format!\n");
+ continue;
+ }
+ if (!IN6_IS_ADDR_LINKLOCAL (&addr) && (IN6_IS_ADDR_UNSPECIFIED (&addr) || IN6_IS_ADDR_LOOPBACK (&addr) || IN6_IS_ADDR_MULTICAST (&addr))) {
+ continue;
+ }
+
+ if((intn=int_find(ifindex))==NULL) {
+ g_conf->ints=(struct intnode*)realloc(g_conf->ints, sizeof(struct intnode)*(++g_conf->maxinterfaces));
+ if (!g_conf->ints) {
+ err ("Cannot get memory for interface structures.\n");
+ }
+ intn=g_conf->ints+g_conf->maxinterfaces-1;
+ memset(intn, 0, sizeof(struct intnode));
+ }
+#ifdef WIN32
+ // Ugly WINXP workaround
+ if(scope==0x20 && flags==0x80) {
+ intn->mtu=1480;
+ } else {
+ intn->mtu=0;
+ }
+#else
+ intn->ifindex = ifindex;
+ strcpy(intn->name, devname);
+
+ struct ifreq ifreq;
+ int sock;
+ sock = socket (AF_INET6, SOCK_DGRAM, 0);
+ if (sock < 0) {
+ err ("Cannot get socket for setup\n");
+ }
+
+ memcpy (&ifreq.ifr_name, &intn->name, sizeof (ifreq.ifr_name));
+ /* Get the MTU size of this interface */
+ /* We will use that for fragmentation */
+ if (ioctl (sock, SIOCGIFMTU, &ifreq) != 0) {
+ warn ("Cannot get MTU size for %s index %d: %s\n", intn->name, intn->ifindex, strerror (errno));
+ }
+ intn->mtu = ifreq.ifr_mtu;
+
+ /* Get hardware address + type */
+ if (ioctl (sock, SIOCGIFHWADDR, &ifreq) != 0) {
+ warn ("Cannot get hardware address for %s, interface index %d : %s\n", intn->name, intn->ifindex, strerror (errno));
+ }
+ intn->hwaddr = ifreq.ifr_hwaddr;
+ close (sock);
+#endif
+ /* Link Local IPv6 address ? */
+ if (IN6_IS_ADDR_LINKLOCAL (&addr)) {
+ /* Update the linklocal address */
+ intn->linklocal = addr;
+ } else {
+ intn->global = addr;
+ }
+
+ dbg ("Available interface %s index %u hardware %s/%u MTU %d\n", intn->name, intn->ifindex, (intn->hwaddr.sa_family == ARPHRD_ETHER ? "Ethernet" : (intn->hwaddr.sa_family == ARPHRD_SIT ? "sit" : "Unknown")), intn->hwaddr.sa_family, intn->mtu);
+ }
+
+ fclose (file);
+}
+#endif
+#if defined WIN32 && ! defined __CYGWIN__
+
+unsigned int if_nametoindex (const char *ifname)
+{
+ unsigned int ifindex;
+ for (ifindex = 0; ifindex < g_conf->maxinterfaces; ifindex++) {
+ if (!strcmp (ifname, g_conf->ints[ifindex].name) && g_conf->ints[ifindex].mtu != 0) {
+ return g_conf->ints[ifindex].ifindex;
+ }
+ }
+ return 0;
+}
+
+void update_interfaces (struct intnode *intn)
+{
+
+ /* Declare and initialize variables */
+
+ DWORD dwRetVal = 0;
+
+ int i = 0;
+
+ // Set the flags to pass to GetAdaptersAddresses
+ ULONG flags = GAA_FLAG_INCLUDE_PREFIX;
+
+ // default to unspecified address family (both)
+ ULONG family = AF_INET6;
+
+ PIP_ADAPTER_ADDRESSES pAddresses = NULL;
+ ULONG outBufLen = 0;
+
+ PIP_ADAPTER_ADDRESSES pCurrAddresses = NULL;
+ PIP_ADAPTER_UNICAST_ADDRESS pUnicast = NULL;
+
+ outBufLen = sizeof (IP_ADAPTER_ADDRESSES);
+ pAddresses = (IP_ADAPTER_ADDRESSES *) malloc (outBufLen);
+ if (pAddresses == NULL) {
+ printf ("Memory allocation failed for IP_ADAPTER_ADDRESSES struct\n");
+ exit (1);
+ }
+ // Make an initial call to GetAdaptersAddresses to get the
+ // size needed into the outBufLen variable
+ if (GetAdaptersAddresses (family, flags, NULL, pAddresses, &outBufLen) == ERROR_BUFFER_OVERFLOW) {
+ free (pAddresses);
+ pAddresses = (IP_ADAPTER_ADDRESSES *) malloc (outBufLen);
+ }
+
+ if (pAddresses == NULL) {
+ printf ("Memory allocation failed for IP_ADAPTER_ADDRESSES struct\n");
+ exit (1);
+ }
+
+ dwRetVal = GetAdaptersAddresses (family, flags, NULL, pAddresses, &outBufLen);
+
+ if (dwRetVal == NO_ERROR) {
+ // If successful, output some information from the data we received
+ pCurrAddresses = pAddresses;
+ g_conf->maxinterfaces=0;
+
+ while (pCurrAddresses) {
+
+ if( /* pCurrAddresses->Flags & IP_ADAPTER_IPV6_ENABLED && */ (pCurrAddresses->IfType == IF_TYPE_ETHERNET_CSMACD || pCurrAddresses->IfType == IF_TYPE_IEEE80211) && pCurrAddresses->OperStatus == IfOperStatusUp ) {
+ g_conf->ints=(struct intnode*)realloc(g_conf->ints, sizeof(struct intnode)*(g_conf->maxinterfaces+1));
+ if (!g_conf->ints) {
+ err ("update_interfaces: out of memory\n");
+ }
+ intn=g_conf->ints+g_conf->maxinterfaces;
+ memset(intn, 0, sizeof(struct intnode));
+
+#ifndef __MINGW32__
+ printf ("Interface: %s (%wS)\n", pCurrAddresses->AdapterName, pCurrAddresses->Description);
+ dbg ("\tFriendly name: %wS\n", pCurrAddresses->FriendlyName);
+#else
+ printf ("Interface: %s (%ls)\n", pCurrAddresses->AdapterName, pCurrAddresses->Description);
+ dbg ("\tFriendly name: %ls\n", pCurrAddresses->FriendlyName);
+#endif
+ dbg ("\tFlags: %x\n", pCurrAddresses->Flags);
+ dbg ("\tIfType: %ld\n", pCurrAddresses->IfType);
+ dbg ("\tOperStatus: %ld\n", pCurrAddresses->OperStatus);
+ dbg ("\tMtu: %lu\n", pCurrAddresses->Mtu);
+ dbg ("\tIpv6IfIndex (IPv6 interface): %u\n", pCurrAddresses->Ipv6IfIndex);
+
+ strncpy(intn->name, pCurrAddresses->AdapterName, IFNAMSIZ-1);
+
+ intn->mtu = pCurrAddresses->Mtu;
+ intn->ifindex= pCurrAddresses->Ipv6IfIndex;
+
+ pUnicast = pCurrAddresses->FirstUnicastAddress;
+ if (pUnicast != NULL) {
+ for (i = 0; pUnicast != NULL; i++) {
+ char host[80];
+ inet_ntop (AF_INET6, ((struct sockaddr_in6 *)(pUnicast->Address.lpSockaddr))->sin6_addr.s6_addr, host, sizeof(host));
+ dbg("\tIP:%s LL:%d\n",host, IN6_IS_ADDR_LINKLOCAL(&((struct sockaddr_in6 *)(pUnicast->Address.lpSockaddr))->sin6_addr));
+ if(IN6_IS_ADDR_LINKLOCAL(&((struct sockaddr_in6 *)(pUnicast->Address.lpSockaddr))->sin6_addr)) {
+ intn->linklocal=((struct sockaddr_in6 *)(pUnicast->Address.lpSockaddr))->sin6_addr;
+ } else {
+ intn->global=((struct sockaddr_in6 *)(pUnicast->Address.lpSockaddr))->sin6_addr;
+ }
+ pUnicast = pUnicast->Next;
+ }
+ dbg ("\tNumber of Unicast Addresses: %d\n", i);
+ }
+#ifdef DEBUG
+ if (pCurrAddresses->PhysicalAddressLength != 0) {
+ dbg ("\tPhysical address: ");
+ for (i = 0; i < (int) pCurrAddresses->PhysicalAddressLength; i++) {
+ if (i == (pCurrAddresses->PhysicalAddressLength - 1))
+ printf ("%.2X\n", (int) pCurrAddresses->PhysicalAddress[i]);
+ else
+ printf ("%.2X:", (int) pCurrAddresses->PhysicalAddress[i]);
+ }
+ }
+#endif
+ g_conf->maxinterfaces++;
+ }
+ pCurrAddresses = pCurrAddresses->Next;
+ }
+ }
+
+ free (pAddresses);
+}
+
+#endif
+#ifdef APPLE
+void update_interfaces (struct intnode *intn)
+{
+ struct ifaddrs *myaddrs, *ifa;
+ struct sockaddr_in *s4;
+ struct sockaddr_in6 *s6;
+ int if_index;
+ /*
+ * buf must be big enough for an IPv6 address (e.g.
+ * 3ffe:2fa0:1010:ca22:020a:95ff:fe8a:1cf8)
+ */
+ char buf[64];
+
+ if (getifaddrs(&myaddrs)) {
+ err ("getifaddrs");
+ }
+
+ for (ifa = myaddrs; ifa != NULL; ifa = ifa->ifa_next) {
+ if (ifa->ifa_addr == NULL)
+ continue;
+ if ((ifa->ifa_flags & IFF_UP) == 0)
+ continue;
+
+ if_index=if_nametoindex(ifa->ifa_name);
+ dbg("%s(%d): ", ifa->ifa_name,if_index);
+
+ if(!if_index) {
+ warn("cannot get interface index for %s\n",ifa->ifa_name);
+ continue;
+ }
+
+ if((intn=int_find(if_index))==NULL) {
+ g_conf->ints=(struct intnode*)realloc(g_conf->ints, sizeof(struct intnode)*(++g_conf->maxinterfaces));
+ if (!g_conf->ints) {
+ err ("Cannot get memory for interface structures.\n");
+ }
+ intn=g_conf->ints+g_conf->maxinterfaces-1;
+ memset(intn, 0, sizeof(struct intnode));
+ }
+
+ intn->ifindex=if_index;
+ strcpy(intn->name,ifa->ifa_name);
+
+ if(ifa->ifa_addr->sa_family == AF_LINK && ((struct if_data *)ifa->ifa_data)->ifi_type != IFT_LOOP && ifa->ifa_data) {
+ dbg("MTU: %d\n", ((struct if_data *)ifa->ifa_data)->ifi_mtu);
+ intn->mtu=((struct if_data *)ifa->ifa_data)->ifi_mtu;
+ memcpy(&intn->hwaddr, ifa->ifa_addr, sizeof(struct sockaddr_in));
+ }
+
+ if (ifa->ifa_addr->sa_family == AF_INET) {
+ s4 = (struct sockaddr_in *) (ifa->ifa_addr);
+ if (inet_ntop(ifa->ifa_addr->sa_family, (void *) &(s4->sin_addr), buf, sizeof(buf)) == NULL) {
+ warn("%s: inet_ntop failed!\n", ifa->ifa_name);
+ } else {
+ dbg("%s\n", buf);
+ }
+ } else if (ifa->ifa_addr->sa_family == AF_INET6) {
+ s6 = (struct sockaddr_in6 *) (ifa->ifa_addr);
+ /* Link Local IPv6 address ? */
+ if (IN6_IS_ADDR_LINKLOCAL (&s6->sin6_addr)) {
+ /* Update the linklocal address */
+ intn->linklocal = s6->sin6_addr;
+ } else {
+ intn->global = s6->sin6_addr;
+ }
+ if (inet_ntop(ifa->ifa_addr->sa_family, (void *) &(s6->sin6_addr), buf, sizeof(buf)) == NULL) {
+ warn("%s: inet_ntop failed!\n", ifa->ifa_name);
+ } else {
+ dbg("%s\n", buf);
+ }
+ }
+ }
+
+ freeifaddrs(myaddrs);
+}
+
+#endif
diff --git a/mcast/common/.svn/text-base/interfaces.h.svn-base b/mcast/common/.svn/text-base/interfaces.h.svn-base
new file mode 100644
index 0000000..8ef942c
--- /dev/null
+++ b/mcast/common/.svn/text-base/interfaces.h.svn-base
@@ -0,0 +1,52 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ */
+
+#ifndef __INTERFACES_H
+#define __INTERFACES_H
+
+#define INTNODE_MAXIPV4 4 /* Maximum number of IPv4 aliases */
+#define bool int
+
+/*
+ * The list of interfaces we do multicast on
+ * These are discovered on the fly, very handy ;)
+ */
+struct intnode
+{
+ unsigned int ifindex; /* The ifindex */
+ char name[IFNAMSIZ]; /* Name of the interface */
+ unsigned int groupcount; /* Number of groups this interface joined */
+ unsigned int mtu; /* The MTU of this interface (mtu = 0 -> invalid interface) */
+
+ struct sockaddr hwaddr; /* Hardware bytes */
+
+ struct in6_addr linklocal; /* Link local address */
+ struct in6_addr global; /* Global unicast address */
+
+ /* Per interface statistics */
+ uint32_t stat_packets_received; /* Number of packets received */
+ uint32_t stat_packets_sent; /* Number of packets sent */
+ uint32_t stat_bytes_received; /* Number of bytes received */
+ uint32_t stat_bytes_sent; /* Number of bytes sent */
+ uint32_t stat_icmp_received; /* Number of ICMP's received */
+ uint32_t stat_icmp_sent; /* Number of ICMP's sent */
+};
+
+/* Node functions */
+struct intnode *int_create (unsigned int ifindex);
+void int_destroy (struct intnode *intn);
+void update_interfaces (struct intnode *intn);
+
+/* List functions */
+struct intnode *int_find (unsigned int ifindex);
+struct intnode *int_find_name (char *ifname);
+struct intnode *int_find_first (void);
+#if defined WIN32 || ! defined __CYGWIN__
+unsigned if_nametoindex (const char *ifname);
+#endif
+#endif
diff --git a/mcast/common/.svn/text-base/list.h.svn-base b/mcast/common/.svn/text-base/list.h.svn-base
new file mode 100644
index 0000000..4bb50a4
--- /dev/null
+++ b/mcast/common/.svn/text-base/list.h.svn-base
@@ -0,0 +1,238 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ */
+
+/*
+ * Linked lists support
+ *
+ * Copyright (C) 2002 Alexandre Julliard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef __WINE_SERVER_DVBMC_LIST_H
+#define __WINE_SERVER_DVBMC_LIST_H
+
+struct list
+{
+ struct list *next;
+ struct list *prev;
+};
+
+/* Define a list like so:
+ *
+ * struct gadget
+ * {
+ * struct list entry; <-- doesn't have to be the first item in the struct
+ * int a, b;
+ * };
+ *
+ * static struct list global_gadgets = DVBMC_LIST_INIT( global_gadgets );
+ *
+ * or
+ *
+ * struct some_global_thing
+ * {
+ * struct list gadgets;
+ * };
+ *
+ * dvbmc_list_init( &some_global_thing->gadgets );
+ *
+ * Manipulate it like this:
+ *
+ * dvbmc_list_add_head( &global_gadgets, &new_gadget->entry );
+ * dvbmc_list_remove( &new_gadget->entry );
+ * dvbmc_list_add_after( &some_random_gadget->entry, &new_gadget->entry );
+ *
+ * And to iterate over it:
+ *
+ * struct gadget *gadget;
+ * DVBMC_LIST_FOR_EACH_ENTRY( gadget, &global_gadgets, struct gadget, entry )
+ * {
+ * ...
+ * }
+ *
+ */
+
+/* add an element after the specified one */
+static inline void dvbmc_list_add_after( struct list *elem, struct list *to_add )
+{
+ to_add->next = elem->next;
+ to_add->prev = elem;
+ elem->next->prev = to_add;
+ elem->next = to_add;
+}
+
+/* add an element before the specified one */
+static inline void dvbmc_list_add_before( struct list *elem, struct list *to_add )
+{
+ to_add->next = elem;
+ to_add->prev = elem->prev;
+ elem->prev->next = to_add;
+ elem->prev = to_add;
+}
+
+/* add element at the head of the list */
+static inline void dvbmc_list_add_head( struct list *list, struct list *elem )
+{
+ dvbmc_list_add_after( list, elem );
+}
+
+/* add element at the tail of the list */
+static inline void dvbmc_list_add_tail( struct list *list, struct list *elem )
+{
+ dvbmc_list_add_before( list, elem );
+}
+
+/* remove an element from its list */
+static inline void dvbmc_list_remove( struct list *elem )
+{
+ elem->next->prev = elem->prev;
+ elem->prev->next = elem->next;
+}
+
+/* get the next element */
+static inline struct list *dvbmc_list_next( const struct list *list, const struct list *elem )
+{
+ struct list *ret = elem->next;
+ if (elem->next == list) ret = NULL;
+ return ret;
+}
+
+/* get the previous element */
+static inline struct list *dvbmc_list_prev( const struct list *list, const struct list *elem )
+{
+ struct list *ret = elem->prev;
+ if (elem->prev == list) ret = NULL;
+ return ret;
+}
+
+/* get the first element */
+static inline struct list *dvbmc_list_head( const struct list *list )
+{
+ return dvbmc_list_next( list, list );
+}
+
+/* get the last element */
+static inline struct list *dvbmc_list_tail( const struct list *list )
+{
+ return dvbmc_list_prev( list, list );
+}
+
+/* check if a list is empty */
+static inline int dvbmc_list_empty( const struct list *list )
+{
+ return list->next == list;
+}
+
+/* initialize a list */
+static inline void dvbmc_list_init( struct list *list )
+{
+ list->next = list->prev = list;
+}
+
+/* count the elements of a list */
+static inline unsigned int dvbmc_list_count( const struct list *list )
+{
+ unsigned count = 0;
+ const struct list *ptr;
+ for (ptr = list->next; ptr != list; ptr = ptr->next) count++;
+ return count;
+}
+
+/* move all elements from src to the tail of dst */
+static inline void dvbmc_list_move_tail( struct list *dst, struct list *src )
+{
+ if (dvbmc_list_empty(src)) return;
+
+ dst->prev->next = src->next;
+ src->next->prev = dst->prev;
+ dst->prev = src->prev;
+ src->prev->next = dst;
+ dvbmc_list_init(src);
+}
+
+/* move all elements from src to the head of dst */
+static inline void dvbmc_list_move_head( struct list *dst, struct list *src )
+{
+ if (dvbmc_list_empty(src)) return;
+
+ dst->next->prev = src->prev;
+ src->prev->next = dst->next;
+ dst->next = src->next;
+ src->next->prev = dst;
+ dvbmc_list_init(src);
+}
+
+/* iterate through the list */
+#define DVBMC_LIST_FOR_EACH(cursor,list) \
+ for ((cursor) = (list)->next; (cursor) != (list); (cursor) = (cursor)->next)
+
+/* iterate through the list, with safety against removal */
+#define DVBMC_LIST_FOR_EACH_SAFE(cursor, cursor2, list) \
+ for ((cursor) = (list)->next, (cursor2) = (cursor)->next; \
+ (cursor) != (list); \
+ (cursor) = (cursor2), (cursor2) = (cursor)->next)
+
+/* iterate through the list using a list entry */
+#define DVBMC_LIST_FOR_EACH_ENTRY(elem, list, type, field) \
+ for ((elem) = DVBMC_LIST_ENTRY((list)->next, type, field); \
+ &(elem)->field != (list); \
+ (elem) = DVBMC_LIST_ENTRY((elem)->field.next, type, field))
+
+/* iterate through the list using a list entry, with safety against removal */
+#define DVBMC_LIST_FOR_EACH_ENTRY_SAFE(cursor, cursor2, list, type, field) \
+ for ((cursor) = DVBMC_LIST_ENTRY((list)->next, type, field), \
+ (cursor2) = DVBMC_LIST_ENTRY((cursor)->field.next, type, field); \
+ &(cursor)->field != (list); \
+ (cursor) = (cursor2), \
+ (cursor2) = DVBMC_LIST_ENTRY((cursor)->field.next, type, field))
+
+/* iterate through the list in reverse order */
+#define DVBMC_LIST_FOR_EACH_REV(cursor,list) \
+ for ((cursor) = (list)->prev; (cursor) != (list); (cursor) = (cursor)->prev)
+
+/* iterate through the list in reverse order, with safety against removal */
+#define DVBMC_LIST_FOR_EACH_SAFE_REV(cursor, cursor2, list) \
+ for ((cursor) = (list)->prev, (cursor2) = (cursor)->prev; \
+ (cursor) != (list); \
+ (cursor) = (cursor2), (cursor2) = (cursor)->prev)
+
+/* iterate through the list in reverse order using a list entry */
+#define DVBMC_LIST_FOR_EACH_ENTRY_REV(elem, list, type, field) \
+ for ((elem) = DVBMC_LIST_ENTRY((list)->prev, type, field); \
+ &(elem)->field != (list); \
+ (elem) = DVBMC_LIST_ENTRY((elem)->field.prev, type, field))
+
+/* iterate through the list in reverse order using a list entry, with safety against removal */
+#define DVBMC_LIST_FOR_EACH_ENTRY_SAFE_REV(cursor, cursor2, list, type, field) \
+ for ((cursor) = DVBMC_LIST_ENTRY((list)->prev, type, field), \
+ (cursor2) = DVBMC_LIST_ENTRY((cursor)->field.prev, type, field); \
+ &(cursor)->field != (list); \
+ (cursor) = (cursor2), \
+ (cursor2) = DVBMC_LIST_ENTRY((cursor)->field.prev, type, field))
+
+/* macros for statically initialized lists */
+//#define DVBMC_LIST_INIT(list) { &(list), &(list) }
+
+/* get pointer to object containing list element */
+#define DVBMC_LIST_ENTRY(elem, type, field) \
+ ((type *)((char *)(elem) - (unsigned long)(&((type *)0)->field)))
+
+#endif /* __WINE_SERVER_DVBMC_LIST_H */
diff --git a/mcast/common/.svn/text-base/mcast.c.svn-base b/mcast/common/.svn/text-base/mcast.c.svn-base
new file mode 100644
index 0000000..41991cf
--- /dev/null
+++ b/mcast/common/.svn/text-base/mcast.c.svn-base
@@ -0,0 +1,674 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ * modified by Reel Multimedia, http://www.reel-multimedia.com, info@reel-multimedia.com
+ * 01042010 DL: use a single thread for reading from network layer (uses less resources)
+ *
+ */
+
+#include "headers.h"
+//----------------------------------------------------------------------------------------------------------------------------------
+STATIC int udp_ipv6_is_multicast_address (const struct sockaddr *addr)
+{
+#ifdef IPV4
+ if (addr->sa_family == AF_INET)
+ return IN_MULTICAST (ntohl (((struct sockaddr_in *) addr)->sin_addr.s_addr));
+#endif
+ if (addr->sa_family == AF_INET6)
+ return IN6_IS_ADDR_MULTICAST (&((struct sockaddr_in6 *) addr)->sin6_addr);
+ return -1;
+}
+
+//---------------------------------------------------------------------------------------------------------------------------------
+STATIC int udp_ipv6_set_multicast_ttl (SOCKET sockfd, int mcastTTL, struct sockaddr *addr)
+{
+#ifdef IPV4
+ if (addr->sa_family == AF_INET) {
+ if (setsockopt (sockfd, IPPROTO_IP, IP_MULTICAST_TTL, &mcastTTL, sizeof (mcastTTL)) < 0) {
+ perror ("setsockopt(IP_MULTICAST_TTL)");
+ return -1;
+ }
+ }
+#endif
+ if (addr->sa_family == AF_INET6) {
+ if (setsockopt (sockfd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (_SOTYPE)&mcastTTL, sizeof (mcastTTL)) < 0) {
+ perror ("setsockopt(IPV6_MULTICAST_HOPS)");
+ return -1;
+ }
+ }
+ return 0;
+}
+
+//---------------------------------------------------------------------------------------------------------------------------------
+int udp_ipv6_join_multicast_group (SOCKET sockfd, int iface, struct sockaddr *addr)
+{
+#ifdef IPV4
+ if (addr->sa_family == AF_INET) {
+ struct ip_mreq mreq;
+ mreq.imr_multiaddr.s_addr = ((struct sockaddr_in *) addr)->sin_addr.s_addr;
+ mreq.imr_interface.s_addr = INADDR_ANY;
+ if (setsockopt (sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (const void *) &mreq, sizeof (mreq)) < 0) {
+ perror ("setsockopt(IP_ADD_MEMBERSHIP)");
+ return -1;
+ }
+ }
+#endif
+ if (addr->sa_family == AF_INET6) {
+ struct ipv6_mreq mreq6;
+ memcpy (&mreq6.ipv6mr_multiaddr, &(((struct sockaddr_in6 *) addr)->sin6_addr), sizeof (struct in6_addr));
+ mreq6.ipv6mr_interface = iface;
+ if (setsockopt (sockfd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, (_SOTYPE)&mreq6, sizeof (mreq6)) < 0) {
+ perror ("setsockopt(IPV6_ADD_MEMBERSHIP)");
+ return -1;
+ }
+ }
+ return 0;
+}
+
+//---------------------------------------------------------------------------------------------------------------------------------
+int udp_ipv6_leave_multicast_group (SOCKET sockfd, int iface, struct sockaddr *addr)
+{
+#ifdef IPV4
+ if (addr->sa_family == AF_INET) {
+ struct ip_mreq mreq;
+ mreq.imr_multiaddr.s_addr = ((struct sockaddr_in *) addr)->sin_addr.s_addr;
+ mreq.imr_interface.s_addr = INADDR_ANY;
+ if (setsockopt (sockfd, IPPROTO_IP, IP_DROP_MEMBERSHIP, (const void *) &mreq, sizeof (mreq)) < 0) {
+ perror ("setsockopt(IP_DROP_MEMBERSHIP)");
+ return -1;
+ }
+ }
+#endif
+ if (addr->sa_family == AF_INET6) {
+ struct ipv6_mreq mreq6;
+ memcpy (&mreq6.ipv6mr_multiaddr, &(((struct sockaddr_in6 *) addr)->sin6_addr), sizeof (struct in6_addr));
+ mreq6.ipv6mr_interface = iface;
+ if (setsockopt (sockfd, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, (_SOTYPE)&mreq6, sizeof (mreq6)) < 0) {
+ perror ("setsockopt(IPV6_DROP_MEMBERSHIP)");
+ return -1;
+ }
+ }
+ return 0;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------
+STATIC int sockfd_to_family (SOCKET sockfd)
+{
+ struct sockaddr_storage ss;
+ socklen_t len;
+
+ len = sizeof (ss);
+ if (getsockname (sockfd, (SA *) & ss, &len) < 0)
+ return (-1);
+ return (ss.ss_family);
+}
+
+/* end sockfd_to_family */
+//----------------------------------------------------------------------------------------------------------------------------------
+int mcast_set_if (SOCKET sockfd, const char *ifname, u_int ifindex)
+{
+ switch (sockfd_to_family (sockfd)) {
+#ifdef IPV4
+ case AF_INET:{
+ struct in_addr inaddr;
+ struct ifreq ifreq;
+
+ if (ifindex > 0) {
+ if (if_indextoname (ifindex, ifreq.ifr_name) == NULL) {
+ errno = ENXIO; /* i/f index not found */
+ return (-1);
+ }
+ goto doioctl;
+ } else if (ifname != NULL) {
+ memset(&ifreq, 0, sizeof(struct ifreq));
+ strncpy (ifreq.ifr_name, ifname, IFNAMSIZ-1);
+ doioctl:
+ if (ioctl (sockfd, SIOCGIFADDR, &ifreq) < 0)
+ return (-1);
+ memcpy (&inaddr, &((struct sockaddr_in *) &ifreq.ifr_addr)->sin_addr, sizeof (struct in_addr));
+ } else
+ inaddr.s_addr = htonl (INADDR_ANY); /* remove prev. set default */
+
+ return (setsockopt (sockfd, IPPROTO_IP, IP_MULTICAST_IF, &inaddr, sizeof (struct in_addr)));
+ }
+#endif
+ case AF_INET6:{
+ u_int idx;
+// printf("Changing interface IPV6...\n");
+ if ((idx = ifindex) == 0) {
+ if (ifname == NULL) {
+ errno = EINVAL; /* must supply either index or name */
+ return (-1);
+ }
+ if ((idx = if_nametoindex (ifname)) == 0) {
+ errno = ENXIO; /* i/f name not found */
+ return (-1);
+ }
+ }
+ return (setsockopt (sockfd, IPPROTO_IPV6, IPV6_MULTICAST_IF, (_SOTYPE)&idx, sizeof (idx)));
+ }
+
+ default:
+// errno = EAFNOSUPPORT;
+ return (-1);
+ }
+}
+
+//--------------------------------------------------------------------------------------------------------------------------------------------
+UDPContext *server_udp_open (const struct in6_addr *mcg, int port, const char *ifname)
+{
+ UDPContext *s;
+ int sendfd;
+ int n;
+
+ pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, NULL);
+
+ s = (UDPContext *) calloc (1, sizeof (UDPContext));
+ if (!s) {
+ err ("Cannot allocate memory !\n");
+ goto error;
+ }
+ struct sockaddr_in6 *addr = (struct sockaddr_in6 *) &s->dest_addr;
+
+ addr->sin6_addr=*mcg;;
+ addr->sin6_family = AF_INET6;
+ addr->sin6_port = htons (port);
+ s->dest_addr_len = sizeof (struct sockaddr_in6);
+
+ sendfd = socket (PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
+ if (sendfd < 0) {
+ err ("cannot get socket\n");
+ }
+
+ s->dest_addr_len = sizeof (struct sockaddr_in6);
+
+ if ((udp_ipv6_is_multicast_address ((struct sockaddr *) &s->dest_addr))) {
+ if (ifname && strlen (ifname) && (mcast_set_if (sendfd, ifname, 0) < 0)) {
+ warn ("mcast_set_if error\n");
+ goto error;
+ }
+ if (udp_ipv6_set_multicast_ttl (sendfd, MCAST_TTL, (struct sockaddr *) &s->dest_addr) < 0) {
+ warn ("udp_ipv6_set_multicast_ttl");
+ }
+ }
+
+ n = UDP_TX_BUF_SIZE;
+ if (setsockopt (sendfd, SOL_SOCKET, SO_SNDBUF, (_SOTYPE)&n, sizeof (n)) < 0) {
+ warn ("setsockopt sndbuf");
+ }
+ s->is_multicast = 0; //server
+ s->udp_fd = sendfd;
+ s->local_port = port;
+
+ dbg ("Multicast streamer initialized successfully ! \n");
+
+ pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, NULL);
+ return s;
+ error:
+ err ("Cannot init udp_server !\n");
+ if (s) {
+ free (s);
+ }
+
+ pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, NULL);
+ return NULL;
+}
+
+UDPContext *server_udp_open_host (const char *host, int port, const char *ifname)
+{
+ struct in6_addr addr;
+
+ inet_pton (AF_INET6, host, &addr);
+
+ return server_udp_open (&addr, port, ifname);
+}
+
+//--------------------------------------------------------------------------------------------------------------------------------------------
+UDPContext *client_udp_open (const struct in6_addr *mcg, int port, const char *ifname)
+{
+ UDPContext *s;
+ int recvfd;
+ int n;
+
+ pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, NULL);
+
+ s = (UDPContext *) calloc (1, sizeof (UDPContext));
+ if (!s) {
+ err ("Cannot allocate memory !\n");
+ goto error;
+ }
+
+ struct sockaddr_in6 *addr = (struct sockaddr_in6 *) &s->dest_addr;
+#ifndef WIN32
+ addr->sin6_addr=*mcg;
+#else
+ struct in6_addr any;
+ memset(&any,0,sizeof(any));
+ addr->sin6_addr=any;
+#endif
+ addr->sin6_family = AF_INET6;
+ addr->sin6_port = htons (port);
+ s->dest_addr_len = sizeof (struct sockaddr_in6);
+
+ recvfd = socket (PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
+ if (recvfd < 0) {
+ err ("cannot get socket\n");
+ }
+#ifdef WIN32
+# ifndef IPV6_PROTECTION_LEVEL
+# define IPV6_PROTECTION_LEVEL 23
+# endif
+ n = 10 /*PROTECTION_LEVEL_UNRESTRICTED*/;
+ if(setsockopt( recvfd, IPPROTO_IPV6, IPV6_PROTECTION_LEVEL, (_SOTYPE)&n, sizeof(n) ) < 0 ) {
+ warn ("setsockopt IPV6_PROTECTION_LEVEL\n");
+ }
+#endif
+ n = 1;
+ if (setsockopt (recvfd, SOL_SOCKET, SO_REUSEADDR, (_SOTYPE)&n, sizeof (n)) < 0) {
+ warn ("setsockopt REUSEADDR\n");
+ }
+
+#if ! (defined WIN32 || defined APPLE)
+ if (ifname && strlen (ifname) && setsockopt (recvfd, SOL_SOCKET, SO_BINDTODEVICE, ifname, strlen (ifname) + 1)) {
+ dbg ("setsockopt SO_BINDTODEVICE %s failed\n", ifname);
+ }
+#endif
+ if (bind (recvfd, (struct sockaddr *) &s->dest_addr, s->dest_addr_len) < 0) {
+ warn ("bind failed\n");
+ goto error;
+ }
+#ifdef WIN32
+ addr->sin6_addr=*mcg;
+#endif
+ if (udp_ipv6_is_multicast_address ((struct sockaddr *) &s->dest_addr)) {
+#if 0
+ if (ifname && strlen (ifname) && (mcast_set_if (recvfd, ifname, 0) < 0)) {
+ warn ("mcast_set_if error \n");
+ goto error;
+ }
+#endif
+ if (ifname) {
+ if ((s->idx = if_nametoindex (ifname)) == 0) {
+ s->idx = 0;
+ } else {
+ dbg("Selecting interface %s (%d)", ifname, s->idx);
+ }
+ } else {
+ s->idx = 0;
+ }
+
+ if (udp_ipv6_join_multicast_group (recvfd, s->idx, (struct sockaddr *) &s->dest_addr) < 0) {
+ warn ("Cannot join multicast group !\n");
+ goto error;
+ }
+ s->is_multicast = 1;
+ }
+
+ n = UDP_RX_BUF_SIZE;
+ if (setsockopt (recvfd, SOL_SOCKET, SO_RCVBUF, (_SOTYPE)&n, sizeof (n)) < 0) {
+ warn ("setsockopt rcvbuf");
+ goto error;
+ }
+
+ s->udp_fd = recvfd;
+ s->local_port = port;
+
+ pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, NULL);
+
+ return s;
+ error:
+ warn ("socket error !\n");
+ if (s) {
+ free (s);
+ }
+ pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, NULL);
+ return NULL;
+}
+
+UDPContext *client_udp_open_host (const char *host, int port, const char *ifname)
+{
+ struct in6_addr addr;
+
+ inet_pton (AF_INET6, host, &addr);
+
+ return client_udp_open (&addr, port, ifname);
+}
+
+//--------------------------------------------------------------------------------------------------------------------------------------------
+int udp_read (UDPContext * s, uint8_t * buf, int size, int timeout, struct sockaddr_storage *from)
+{
+ socklen_t from_len = sizeof (struct sockaddr_storage);
+ struct sockaddr_storage from_local;
+
+ if(!from) {
+ from=&from_local;
+ }
+
+ struct pollfd p;
+ p.fd = s->udp_fd;
+ p.events = POLLIN;
+
+ if(poll(&p,1,(timeout+999)>>10)>0) {
+ return recvfrom (s->udp_fd, (char *)buf, size, 0, (struct sockaddr *) from, &from_len);
+ }
+ return -1;
+}
+
+//--------------------------------------------------------------------------------------------------------------------------------------------------
+int udp_write (UDPContext * s, uint8_t * buf, int size)
+{
+ int ret;
+
+ for (;;) {
+ ret = sendto (s->udp_fd, (char *) buf, size, 0, (struct sockaddr *) &s->dest_addr, s->dest_addr_len);
+
+ if (ret < 0) {
+ if (errno != EINTR && errno != EAGAIN)
+ return -1;
+ } else {
+ break;
+ }
+ }
+ return size;
+}
+
+//----------------------------------------------------------------------------------------------------------------------------------------------------
+int udp_close (UDPContext * s)
+{
+ if (s->is_multicast)
+ udp_ipv6_leave_multicast_group (s->udp_fd, s->idx, (struct sockaddr *) &s->dest_addr);
+
+ closesocket (s->udp_fd);
+ free (s);
+
+ return 0;
+}
+
+//--------------------------------------------------------------------------------------------------------------------------------------------
+
+#ifndef MULTI_THREAD_RECEIVER
+
+#define MAX_BUFF_SIZE 0x10000
+#define MAX_CON_LIST 128
+UDPContext *gConList[MAX_CON_LIST];
+pthread_mutex_t gConListLock = PTHREAD_MUTEX_INITIALIZER;
+static int gConListInit=0;
+static int gConListModified;
+static UDPContext *gConChain;
+
+STATIC void client_upd_cleanup (void *arg) {
+ if(!gConListInit) return;
+ pthread_mutex_lock(&gConListLock);
+ memset(&gConList, 0, sizeof(gConList));
+ gConListInit=0;
+ pthread_mutex_unlock(&gConListLock);
+} // client_upd_cleanup
+
+void *client_upd_process(void *arg) {
+#ifdef RT
+#if 1
+ if (setpriority (PRIO_PROCESS, 0, -15) == -1)
+#else
+ if (pthread_setschedprio (p->recv_ts_thread, -15))
+#endif
+ {
+ dbg ("Cannot raise priority to -15\n");
+ }
+#endif
+ unsigned char buff[MAX_BUFF_SIZE];
+ socklen_t from_len = sizeof (struct sockaddr_storage);
+ struct sockaddr_storage from_local;
+ struct pollfd fds[MAX_CON_LIST];
+
+ pthread_cleanup_push (client_upd_cleanup, 0);
+ int max_fd=0;
+ while(1) {
+ UDPContext *e;
+ pthread_mutex_lock(&gConListLock);
+
+ if(gConListModified) {
+ gConListModified=0;
+ max_fd=0;
+ for(e=gConChain;e;e=e->next) {
+ fds[max_fd].fd = e->udp_fd;
+ fds[max_fd].events = POLLIN;
+ fds[max_fd].revents = 0;
+ e->pfd = &fds[max_fd];
+ max_fd++;
+ } // for
+ } // if
+ pthread_mutex_unlock(&gConListLock);
+ int rs = poll(fds, max_fd, 1000);
+ if(rs>0) {
+ pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, NULL);
+ pthread_mutex_lock(&gConListLock);
+ for(e=gConChain;e;e=e->next) {
+ if(e->pfd && (e->pfd->revents & POLLIN)) {
+ if(e->cb) {
+ int ret = recvfrom (e->udp_fd, (char *)buff, MAX_BUFF_SIZE, 0, 0, 0/*(struct sockaddr *) &from_local, &from_len*/);
+ if(ret>0)
+ e->cb(buff, ret, e->arg);
+ } else if(e->buff && !e->bufflen) {
+ pthread_mutex_lock(&e->bufflock);
+ int ret = recvfrom (e->udp_fd, (char *)e->buff, e->buffmax, 0, (struct sockaddr *) &from_local, &from_len);
+ if(ret>0)
+ e->bufflen = ret;
+ pthread_mutex_unlock(&e->bufflock);
+ } // if
+ } // if
+ } // for
+ pthread_mutex_unlock(&gConListLock);
+ pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, NULL);
+ } // if
+ pthread_testcancel();
+ } // while
+ pthread_cleanup_pop (1);
+ return NULL;
+}
+
+static int client_upd_init() {
+ pthread_mutex_lock(&gConListLock);
+ if(gConListInit) {
+ pthread_mutex_unlock(&gConListLock);
+ return 1;
+ } // if
+ memset(&gConList, 0, sizeof(gConList));
+ gConListModified = 0;
+ gConChain = NULL;
+ pthread_t client_upd_thread;
+ if(0==pthread_create (&client_upd_thread, NULL, client_upd_process, 0)) {
+ gConListInit = 1;
+ pthread_detach(client_upd_thread);
+ } // if
+ pthread_mutex_unlock(&gConListLock);
+ return gConListInit;
+} // client_upd_init
+
+UDPContext *client_udp_open_buff (const struct in6_addr *mcg, int port, const char *ifname, int buff_size) {
+ UDPContext *ret = client_udp_open_cb (mcg, port, ifname, 0, 0);
+ if(ret) {
+ ret->buff = (unsigned char *)malloc(buff_size);
+ ret->buffmax = buff_size;
+ ret->bufflen = 0;
+ if (!ret->buff) {
+ err ("client_udp_open_buff: out of memory\n");
+ }
+ } // if
+ return ret;
+} // client_udp_open_buff
+
+UDPContext *client_udp_open_cb (const struct in6_addr *mcg, int port, const char *ifname, client_udp_cb cb, void *arg)
+{
+ if(!client_upd_init()) return NULL;
+
+ UDPContext *s;
+ int recvfd = -1;
+ int n;
+
+ pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, NULL);
+
+ s = (UDPContext *) calloc (1, sizeof (UDPContext));
+ if (!s) {
+ err ("Cannot allocate memory !\n");
+ goto error;
+ }
+
+ struct sockaddr_in6 *addr = (struct sockaddr_in6 *) &s->dest_addr;
+#ifndef WIN32
+ addr->sin6_addr=*mcg;
+#else
+ struct in6_addr any=IN6ADDR_ANY_INIT;
+ addr->sin6_addr=any;
+#endif
+ addr->sin6_family = AF_INET6;
+ addr->sin6_port = htons (port);
+ s->dest_addr_len = sizeof (struct sockaddr_in6);
+
+ recvfd = socket (PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
+ if (recvfd < 0) {
+ err ("cannot get socket\n");
+ }
+#ifdef WIN32
+# ifndef IPV6_PROTECTION_LEVEL
+# define IPV6_PROTECTION_LEVEL 23
+# endif
+ n = 10 /*PROTECTION_LEVEL_UNRESTRICTED*/;
+ if(setsockopt( recvfd, IPPROTO_IPV6, IPV6_PROTECTION_LEVEL, (_SOTYPE)&n, sizeof(n) ) < 0 ) {
+ warn ("setsockopt IPV6_PROTECTION_LEVEL\n");
+ }
+#endif
+ n = 1;
+ if (setsockopt (recvfd, SOL_SOCKET, SO_REUSEADDR, (_SOTYPE)&n, sizeof (n)) < 0) {
+ warn ("setsockopt REUSEADDR\n");
+ }
+
+#if ! (defined WIN32 || defined APPLE)
+ if (ifname && strlen (ifname) && setsockopt (recvfd, SOL_SOCKET, SO_BINDTODEVICE, ifname, strlen (ifname) + 1)) {
+ dbg ("setsockopt SO_BINDTODEVICE %s failed\n", ifname);
+ }
+#endif
+ if (bind (recvfd, (struct sockaddr *) &s->dest_addr, s->dest_addr_len) < 0) {
+ warn ("bind failed\n");
+ goto error;
+ }
+#ifdef WIN32
+ addr->sin6_addr=*mcg;
+#endif
+ if (udp_ipv6_is_multicast_address ((struct sockaddr *) &s->dest_addr)) {
+#if 0
+ if (ifname && strlen (ifname) && (mcast_set_if (recvfd, ifname, 0) < 0)) {
+ warn ("mcast_set_if error \n");
+ goto error;
+ }
+#endif
+ if (ifname) {
+ if ((s->idx = if_nametoindex (ifname)) == 0) {
+ s->idx = 0;
+ } else {
+ dbg("Selecting interface %s (%d)", ifname, s->idx);
+ }
+ } else {
+ s->idx = 0;
+ }
+
+ if (udp_ipv6_join_multicast_group (recvfd, s->idx, (struct sockaddr *) &s->dest_addr) < 0) {
+ warn ("Cannot join multicast group !\n");
+ goto error;
+ }
+ s->is_multicast = 1;
+ }
+
+ n = cb ? UDP_PID_BUF_SIZE : UDP_RX_BUF_SIZE;
+ if (setsockopt (recvfd, SOL_SOCKET, SO_RCVBUF, (_SOTYPE)&n, sizeof (n)) < 0) {
+ warn ("setsockopt rcvbuf");
+ goto error;
+ }
+
+ s->udp_fd = recvfd;
+ s->local_port = port;
+
+ pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, NULL);
+
+ s->cb = cb;
+ s->arg = arg;
+ pthread_mutex_init(&s->bufflock, NULL);
+ int i;
+ pthread_mutex_lock(&gConListLock);
+ for(i=0;i<MAX_CON_LIST;i++) {
+ if(!gConList[i]) {
+ gConList[i]=s;
+ gConListModified=1;
+ s->next=gConChain;
+ gConChain=s;
+ break;
+ } // if
+ } // for
+ pthread_mutex_unlock(&gConListLock);
+ if(i>=MAX_CON_LIST)
+ warn("---------------------------------------------No slot found!\n");
+
+ return s;
+ error:
+ warn ("socket error !\n");
+ if (s) {
+ free (s);
+ }
+ pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, NULL);
+ return NULL;
+}
+
+UDPContext *client_udp_open_host_buff (const char *host, int port, const char *ifname, int buff_size)
+{
+ struct in6_addr addr;
+
+ inet_pton (AF_INET6, host, &addr);
+
+ return client_udp_open_buff (&addr, port, ifname, buff_size);
+}
+
+//--------------------------------------------------------------------------------------------------------------------------------------------
+int udp_read_buff (UDPContext * s, uint8_t * buf, int size, int timeout, struct sockaddr_storage *from)
+{
+ pthread_mutex_lock(&s->bufflock);
+ int ret = s->bufflen>size ? size : s->bufflen;
+ if(ret>0) {
+ memcpy(buf, s->buff, ret);
+ s->bufflen-=ret;
+ }
+ pthread_mutex_unlock(&s->bufflock);
+ return ret;
+}
+//----------------------------------------------------------------------------------------------------------------------------------------------------
+int udp_close_buff (UDPContext * s)
+{
+ int i;
+ pthread_mutex_lock(&gConListLock);
+ for(i=0;i<MAX_CON_LIST;i++) {
+ if(gConList[i] == s) {
+ gConList[i]=0;
+ gConListModified=1;
+ UDPContext **e;
+ for(e=&gConChain;*e;e=&(*e)->next) {
+ if(*e == s) {
+ *e=(*e)->next;
+ break;
+ }
+ }
+ break;
+ }
+ }
+ pthread_mutex_unlock(&gConListLock);
+ if (s->is_multicast)
+ udp_ipv6_leave_multicast_group (s->udp_fd, s->idx, (struct sockaddr *) &s->dest_addr);
+
+ closesocket (s->udp_fd);
+ free(s->buff);
+ pthread_mutex_destroy(&s->bufflock);
+ free (s);
+
+ return 0;
+}
+#endif
diff --git a/mcast/common/.svn/text-base/mcast.h.svn-base b/mcast/common/.svn/text-base/mcast.h.svn-base
new file mode 100644
index 0000000..33a6ed5
--- /dev/null
+++ b/mcast/common/.svn/text-base/mcast.h.svn-base
@@ -0,0 +1,64 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ * modified by Reel Multimedia, http://www.reel-multimedia.com, info@reel-multimedia.com
+ * 01042010 DL: use a single thread for reading from network layer (uses less resources)
+ *
+ */
+
+#ifndef __MCAST_H__
+#define __MCAST_H__
+
+typedef void (*client_udp_cb)(unsigned char *buf, int n, void *arg);
+
+typedef struct _UDPContext
+{
+ struct _UDPContext *next;
+ SOCKET udp_fd;
+ int ttl;
+ int idx;
+ int is_multicast;
+ int local_port;
+ int reuse_socket;
+ struct sockaddr_storage dest_addr;
+ size_t dest_addr_len;
+
+ client_udp_cb cb;
+ void *arg;
+ unsigned char *buff;
+ int buffmax;
+ int bufflen;
+ pthread_mutex_t bufflock;
+ struct pollfd *pfd;
+} UDPContext;
+
+#define SA struct sockaddr
+
+#define UDP_TX_BUF_SIZE 131072
+#define UDP_RX_BUF_SIZE 131072
+#define UDP_PID_BUF_SIZE 1048576
+#define MCAST_TTL 16
+
+UDPContext *server_udp_open_host (const char *host, int port, const char *ifname);
+UDPContext *server_udp_open (const struct in6_addr *mcg, int port, const char *ifname);
+UDPContext *client_udp_open (const struct in6_addr *mcg, int port, const char *ifname);
+UDPContext *client_udp_open_host (const char *host, int port, const char *ifname);
+
+int udp_read (UDPContext * s, uint8_t * buf, int size, int timeout, struct sockaddr_storage *from);
+int udp_write (UDPContext * s, uint8_t * buf, int size);
+int udp_close (UDPContext * s);
+
+#ifndef MULTI_THREAD_RECEIVER
+UDPContext *client_udp_open_host_buff (const char *host, int port, const char *ifname, int buff_size);
+UDPContext *client_udp_open_cb (const struct in6_addr *mcg, int port, const char *ifname, client_udp_cb cb, void *arg);
+UDPContext *client_udp_open_buff (const struct in6_addr *mcg, int port, const char *ifname, int buff_size);
+int udp_read_buff (UDPContext * s, uint8_t * buf, int size, int timeout, struct sockaddr_storage *from);
+int udp_close_buff (UDPContext * s);
+#endif
+
+int udp_ipv6_join_multicast_group (SOCKET sockfd, int iface, struct sockaddr *addr);
+int udp_ipv6_leave_multicast_group (SOCKET sockfd, int iface, struct sockaddr *addr);
+#endif
diff --git a/mcast/common/.svn/text-base/mld.h.svn-base b/mcast/common/.svn/text-base/mld.h.svn-base
new file mode 100644
index 0000000..93d2bd6
--- /dev/null
+++ b/mcast/common/.svn/text-base/mld.h.svn-base
@@ -0,0 +1,339 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ */
+
+#ifndef __MLD_H__
+#define __MLD_H__
+
+/* Wrappers so we don't have to change the copied stuff ;) */
+#define __u8 uint8_t
+#define __u16 uint16_t
+/* Booleans */
+#define false 0
+#define true (!false)
+
+
+/* Determine Endianness */
+#if ! defined __LITTLE_ENDIAN_BITFIELD && ! defined __BIG_ENDIAN_BITFIELD
+ #if BYTE_ORDER == LITTLE_ENDIAN
+ /* 1234 machines */
+ #define __LITTLE_ENDIAN_BITFIELD 1
+ #elif BYTE_ORDER == BIG_ENDIAN
+ /* 4321 machines */
+ #define __BIG_ENDIAN_BITFIELD 1
+ # define WORDS_BIGENDIAN 1
+ #elif BYTE_ORDER == PDP_ENDIAN
+ /* 3412 machines */
+ #error PDP endianness not supported yet!
+ #else
+ #error unknown endianness!
+ #endif
+#endif
+
+/* Per RFC */
+struct mld1
+{
+ __u8 type;
+ __u8 code;
+ __u16 csum;
+ __u16 mrc;
+ __u16 resv1;
+ struct in6_addr mca;
+};
+
+/* The timeout for queries */
+/* as per RFC3810 MLDv2 "9.2. Query Interval" */
+#define ECMH_SUBSCRIPTION_TIMEOUT 15
+
+/* Robustness Factor, per RFC3810 MLDv2 "9.1. Robustness Variable" */
+#define ECMH_ROBUSTNESS_FACTOR 2
+
+
+/* MLDv2 Report */
+#ifndef ICMP6_V2_MEMBERSHIP_REPORT
+#define ICMP6_V2_MEMBERSHIP_REPORT 143
+#endif
+/* MLDv2 Report - Experimental Code */
+#ifndef ICMP6_V2_MEMBERSHIP_REPORT_EXP
+#define ICMP6_V2_MEMBERSHIP_REPORT_EXP 206
+#endif
+
+/* MLDv2 Exclude/Include */
+
+#ifndef MLD2_MODE_IS_INCLUDE
+#define MLD2_MODE_IS_INCLUDE 1
+#endif
+#ifndef MLD2_MODE_IS_EXCLUDE
+#define MLD2_MODE_IS_EXCLUDE 2
+#endif
+#ifndef MLD2_CHANGE_TO_INCLUDE
+#define MLD2_CHANGE_TO_INCLUDE 3
+#endif
+#ifndef MLD2_CHANGE_TO_EXCLUDE
+#define MLD2_CHANGE_TO_EXCLUDE 4
+#endif
+#ifndef MLD2_ALLOW_NEW_SOURCES
+#define MLD2_ALLOW_NEW_SOURCES 5
+#endif
+#ifndef MLD2_BLOCK_OLD_SOURCES
+#define MLD2_BLOCK_OLD_SOURCES 6
+#endif
+
+#ifndef MLD2_ALL_MCR_INIT
+#define MLD2_ALL_MCR_INIT { { { 0xff,0x02,0,0,0,0,0,0,0,0,0,0,0,0,0,0x16 } } }
+#endif
+
+#ifndef ICMP6_ROUTER_RENUMBERING
+#define ICMP6_ROUTER_RENUMBERING 138 /* router renumbering */
+#endif
+#ifndef ICMP6_NI_QUERY
+#define ICMP6_NI_QUERY 139 /* node information request */
+#endif
+#ifndef ICMP6_NI_REPLY
+#define ICMP6_NI_REPLY 140 /* node information reply */
+#endif
+#ifndef MLD_MTRACE_RESP
+#define MLD_MTRACE_RESP 200 /* Mtrace response (to sender) */
+#endif
+#ifndef MLD_MTRACE
+#define MLD_MTRACE 201 /* Mtrace messages */
+#endif
+
+#ifndef ICMP6_DST_UNREACH_BEYONDSCOPE
+#define ICMP6_DST_UNREACH_BEYONDSCOPE 2 /* Beyond scope of source address */
+#endif
+
+#ifndef ICMP6_NI_SUCCESS
+#define ICMP6_NI_SUCCESS 0 /* node information successful reply */
+#endif
+#ifndef ICMP6_NI_REFUSED
+#define ICMP6_NI_REFUSED 1 /* node information request is refused */
+#endif
+#ifndef ICMP6_NI_UNKNOWN
+#define ICMP6_NI_UNKNOWN 2 /* unknown Qtype */
+#endif
+
+#ifndef ICMP6_ROUTER_RENUMBERING_COMMAND
+#define ICMP6_ROUTER_RENUMBERING_COMMAND 0 /* rr command */
+#endif
+#ifndef ICMP6_ROUTER_RENUMBERING_RESULT
+#define ICMP6_ROUTER_RENUMBERING_RESULT 1 /* rr result */
+#endif
+#ifndef ICMP6_ROUTER_RENUMBERING_SEQNUM_RESET
+#define ICMP6_ROUTER_RENUMBERING_SEQNUM_RESET 255 /* rr seq num reset */
+#endif
+
+#ifndef ICMP6_MEMBERSHIP_QUERY
+#define ICMP6_MEMBERSHIP_QUERY 130
+#endif
+
+#ifndef ICMP6_MEMBERSHIP_REPORT
+#define ICMP6_MEMBERSHIP_REPORT 131
+#endif
+
+#ifndef ICMP6_MEMBERSHIP_REDUCTION
+#define ICMP6_MEMBERSHIP_REDUCTION 132
+#endif
+
+#ifndef ICMP6_DST_UNREACH_NOTNEIGHBOR
+#define ICMP6_DST_UNREACH_NOTNEIGHBOR 2 /* not a neighbor */
+#endif
+
+#ifdef __UCLIBC__
+
+#ifndef IP6OPT_PADN
+#define IP6OPT_PADN 1
+#endif
+
+#ifndef ip6_ext
+struct ip6_ext
+{
+ uint8_t ip6e_nxt;
+ uint8_t ip6e_len;
+};
+#endif
+#endif
+
+#ifdef WIN32
+struct ip6_hdr
+ {
+ union
+ {
+ struct ip6_hdrctl
+ {
+ uint32_t ip6_un1_flow; /* 4 bits version, 8 bits TC,
+ 20 bits flow-ID */
+ uint16_t ip6_un1_plen; /* payload length */
+ uint8_t ip6_un1_nxt; /* next header */
+ uint8_t ip6_un1_hlim; /* hop limit */
+ } ip6_un1;
+ uint8_t ip6_un2_vfc; /* 4 bits version, top 4 bits tclass */
+ } ip6_ctlun;
+ struct in6_addr ip6_src; /* source address */
+ struct in6_addr ip6_dst; /* destination address */
+ };
+#define ICMP6_DST_UNREACH 1
+#define ICMP6_TIME_EXCEEDED 3
+#define ICMP6_PARAM_PROB 4
+
+#define ip6_vfc ip6_ctlun.ip6_un2_vfc
+#define ip6_plen ip6_ctlun.ip6_un1.ip6_un1_plen
+#define ip6_nxt ip6_ctlun.ip6_un1.ip6_un1_nxt
+#define ip6_hlim ip6_ctlun.ip6_un1.ip6_un1_hlim
+
+#define IP6OPT_PADN 1
+
+/* Hop-by-Hop options header. */
+struct ip6_hbh
+ {
+ uint8_t ip6h_nxt; /* next header. */
+ uint8_t ip6h_len; /* length in units of 8 octets. */
+ /* followed by options */
+ };
+
+#endif
+
+
+/* From linux/net/ipv6/mcast.c */
+
+/*
+ * These header formats should be in a separate include file, but icmpv6.h
+ * doesn't have in6_addr defined in all cases, there is no __u128, and no
+ * other files reference these.
+ *
+ * +-DLS 4/14/03
+ *
+ * Multicast Listener Discovery version 2 headers
+ * Modified as they are where not ANSI C compliant
+ */
+struct mld2_grec
+{
+ __u8 grec_type;
+ __u8 grec_auxwords;
+ __u16 grec_nsrcs;
+ struct in6_addr grec_mca;
+/* struct in6_addr grec_src[0]; */
+};
+
+struct mld2_report
+{
+ __u8 type;
+ __u8 resv1;
+ __u16 csum;
+ __u16 resv2;
+ __u16 ngrec;
+/* struct mld2_grec grec[0]; */
+};
+
+struct mld2_query
+{
+ __u8 type;
+ __u8 code;
+ __u16 csum;
+ __u16 mrc;
+ __u16 resv1;
+ struct in6_addr mca;
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ uint32_t qrv:3, suppress:1, resv2:4;
+#elif defined(__BIG_ENDIAN_BITFIELD)
+ uint32_t resv2:4, suppress:1, qrv:3;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+ __u8 qqic;
+ __u16 nsrcs;
+/* struct in6_addr srcs[0]; */
+};
+
+#define IGMP6_UNSOLICITED_IVAL (10*HZ)
+#define MLD_QRV_DEFAULT 2
+
+#define MLD_V1_SEEN(idev) ((idev)->mc_v1_seen && \
+ time_before(jiffies, (idev)->mc_v1_seen))
+
+#define MLDV2_MASK(value, nb) ((nb)>=32 ? (value) : ((1<<(nb))-1) & (value))
+#define MLDV2_EXP(thresh, nbmant, nbexp, value) \
+ ((value) < (thresh) ? (value) : \
+ ((MLDV2_MASK(value, nbmant) | (1<<(nbmant+nbexp))) << \
+ (MLDV2_MASK((value) >> (nbmant), nbexp) + (nbexp))))
+
+#define MLDV2_QQIC(value) MLDV2_EXP(0x80, 4, 3, value)
+#define MLDV2_MRC(value) MLDV2_EXP(0x8000, 12, 3, value)
+
+#define bool int
+
+#define RAW_RX_BUF_SIZE 1024*1024
+
+struct lookup
+{
+ unsigned int num;
+ const char *desc;
+};
+
+/* Our configuration structure */
+struct conf
+{
+ unsigned int maxinterfaces; /* The max number of interfaces the array can hold */
+ struct intnode *ints; /* The interfaces we are watching */
+
+ struct mc_group *groups;
+
+ bool quit; /* Global Quit signal */
+
+ bool promisc; /* Make interfaces promisc? (To be sure to receive all MLD's) */
+ bool mode; /* Streamer 0 /Client mode 1 */
+
+ uint8_t *buffer; /* Our buffer */
+ unsigned int bufferlen; /* Length of the buffer */
+
+ int rawsocket; /* Single RAW socket for sending and receiving everything */
+
+ unsigned int stat_packets_received; /* Number of packets received */
+ unsigned int stat_packets_sent; /* Number of packets forwarded */
+ unsigned int stat_bytes_received; /* Number of bytes received */
+ unsigned int stat_bytes_sent; /* Number of bytes forwarded */
+ unsigned int stat_icmp_received; /* Number of ICMP's received */
+ unsigned int stat_icmp_sent; /* Number of ICMP's sent */
+
+ unsigned int mca_groups;
+ unsigned int subscribers;
+ cmdline_t *cmd;
+#ifdef SERVER
+ tuner_t *tuner_parms;
+ int tuner_number;
+
+ satellite_list_t *sat_list;
+ int sat_list_num;
+ int readconfig;
+ pthread_t mld_timer_thread;
+ pthread_t collect_stats_thread;
+ pthread_t stream_tca_thread;
+ pthread_t stream_tra_thread;
+
+ int tca_id;
+#endif
+
+ pthread_mutex_t lock;
+};
+
+/* Global Stuff */
+extern struct conf *g_conf;
+extern struct lookup mld2_grec_types[];
+
+
+const char *lookup (struct lookup *l, unsigned int num);
+const char *icmpv6_type (unsigned int type);
+const char *icmpv6_code (unsigned int type, unsigned int code);
+
+uint16_t ipv6_checksum (const struct ip6_hdr *ip6, uint8_t protocol, const void *data, const uint16_t length);
+void sendpacket6 (struct intnode *intn, const struct ip6_hdr *iph, const uint16_t len);
+//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+int send_mldv2_report (struct intnode *intn, int grec_number, struct in6_addr *mcas, int srcn, struct in6_addr *sources, int mode);
+int start_mld_daemon (void);
+
+#endif
diff --git a/mcast/common/.svn/text-base/mld_client.c.svn-base b/mcast/common/.svn/text-base/mld_client.c.svn-base
new file mode 100644
index 0000000..d291466
--- /dev/null
+++ b/mcast/common/.svn/text-base/mld_client.c.svn-base
@@ -0,0 +1,244 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ */
+
+#undef DEBUG
+#include "headers.h"
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+int send_mldv2_report (struct intnode *intn, int grec_number, struct in6_addr *mcas, int srcn, struct in6_addr *sources, int mode)
+{
+ unsigned int length;
+ struct mld_report_packet
+ {
+ struct ip6_hdr ip6;
+ struct ip6_hbh hbh;
+ struct
+ {
+ uint8_t type;
+ uint8_t length;
+ uint16_t value;
+ uint8_t optpad[2];
+ } routeralert;
+ struct mld2_report mld2r;
+ } *packet;
+ struct mld2_grec *grec = NULL;
+ struct in6_addr *src = NULL;
+ int mca_index, src_index;
+ int count = 0;
+
+ bool any = false;
+
+
+ //printf("creating multicast listener report packet....\n");
+ //printf("size src = %d size grec = %d \n",sizeof(*src),sizeof(*grec));
+ if (intn->mtu < sizeof (*packet)) {
+ /*
+ * MTU is too small to support this type of packet
+ * Should not happen though
+ */
+ dbg ("MTU too small for packet while sending MLDv2 report on interface %s/%u mtu=%u!?\n", intn->name, intn->ifindex, intn->mtu);
+ return -1;
+ }
+
+ /* Allocate a buffer matching the MTU size of this interface */
+ packet = (struct mld_report_packet *) malloc (intn->mtu);
+
+ if (!packet) {
+ err ("Cannot get memory for MLD2 report packet, aborting\n");
+ }
+// printf("addr packet = %u \n",packet);
+ memset (packet, 0, intn->mtu);
+
+
+ /* Create the IPv6 packet */
+ packet->ip6.ip6_vfc = 0x60;
+ packet->ip6.ip6_plen = ntohs (sizeof (*packet) - sizeof (packet->ip6));
+ packet->ip6.ip6_nxt = IPPROTO_HOPOPTS;
+ packet->ip6.ip6_hlim = 1;
+
+ /*
+ * The source address must be the link-local address
+ * of the interface we are sending on
+ */
+ memcpy (&packet->ip6.ip6_src, &intn->linklocal, sizeof (packet->ip6.ip6_src));
+
+ /* MLDv2 Report -> All IPv6 Multicast Routers (ff02::16) */
+ packet->ip6.ip6_dst.s6_addr[0] = 0xff;
+ packet->ip6.ip6_dst.s6_addr[1] = 0x02;
+ packet->ip6.ip6_dst.s6_addr[15] = 0x16;
+
+ /* HopByHop Header Extension */
+ packet->hbh.ip6h_nxt = IPPROTO_ICMPV6;
+ packet->hbh.ip6h_len = 0;
+
+ /* Router Alert Option */
+ packet->routeralert.type = 5;
+ packet->routeralert.length = sizeof (packet->routeralert.value);
+ packet->routeralert.value = 0; /* MLD ;) */
+
+ /* Option Padding */
+ packet->routeralert.optpad[0] = IP6OPT_PADN;
+ packet->routeralert.optpad[1] = 0;
+
+ /* ICMPv6 MLD Report */
+ packet->mld2r.type = ICMP6_V2_MEMBERSHIP_REPORT;
+ //number of multi cast address reocrds
+ packet->mld2r.ngrec = 0; //grec_number;//htons(1);
+ length = 0;
+ count = 0;
+ for (mca_index = 0; mca_index < grec_number; mca_index++) {
+ src = NULL;
+ if (!grec) {
+ length = sizeof (*packet) + sizeof (*grec) - sizeof (packet->ip6);
+ //fprintf(stdout,"(grec = %02d) %02d. current report length = %04d MTU: %04d)\n",packet->mld2r.ngrec,mca_index,length+sizeof(packet->ip6),intn->mtu);
+
+ if (length + sizeof (packet->ip6) > intn->mtu) {
+ /* Should not happen! Would mean the MTU is smaller than a standard mld report */
+ dbg ("No grec and MTU too small for packet while sending MLDv2 report on interface %s/%u mtu=%u!?\n", intn->name, intn->ifindex, intn->mtu);
+ free (packet);
+ return (-1);
+ } else
+ grec = (struct mld2_grec *) (((char *) packet) + sizeof (*packet));
+
+ packet->mld2r.ngrec++;
+ } else {
+ if (!src)
+ length = ((((char *) grec) - ((char *) packet)) + sizeof (*grec) + (sizeof (*src) * (grec->grec_nsrcs))) - sizeof (packet->ip6);
+
+ //fprintf(stdout,"\nloop1:(grec = %02d) %02d.length = %04d (Total : %04d MTU: %04d)\n\n", packet->mld2r.ngrec , mca_index,length,(length + sizeof(packet->ip6)), intn->mtu);
+
+ if (((length + sizeof (packet->ip6) + sizeof (*grec)) > intn->mtu)) {
+
+ /* Take care of endianess */
+ //fprintf(stdout,"next grec record does not fit... sending... \n");
+
+ packet->mld2r.ngrec = htons (packet->mld2r.ngrec);
+ grec->grec_nsrcs = htons (grec->grec_nsrcs);
+
+ /* Calculate and fill in the checksum */
+ packet->ip6.ip6_plen = htons (length);
+ packet->mld2r.csum = htons (0);
+ packet->mld2r.csum = ipv6_checksum (&packet->ip6, IPPROTO_ICMPV6, (uint8_t *) & packet->mld2r, length - sizeof (struct ip6_hbh) - sizeof (packet->routeralert));
+ count++;
+#ifdef DEBUG
+ dbg ("%04d.Sending2 MLDv2 Report on %s/%u, ngrec=%u, length=%u sources=%u (in last grec)\n", count, intn->name, intn->ifindex, ntohs (packet->mld2r.ngrec), length, ntohs (grec->grec_nsrcs));
+ sendpacket6 (intn, (const struct ip6_hdr *) packet, length + sizeof (packet->ip6));
+#endif
+ /* Increase ICMP sent statistics */
+ g_conf->stat_icmp_sent++;
+ intn->stat_icmp_sent++;
+
+ /* Reset the MLDv2 struct */
+ packet->mld2r.ngrec = 0;
+ grec = (struct mld2_grec *) (((char *) packet) + sizeof (*packet));
+ } else {
+ //next grec
+ grec->grec_nsrcs = htons (grec->grec_nsrcs);
+ grec = (struct mld2_grec *) (((char *) grec) + sizeof (*grec) + (sizeof (*src) * ntohs (grec->grec_nsrcs)));
+
+ }
+ packet->mld2r.ngrec++;
+ }
+ //Copy MCA to record
+ memcpy (&grec->grec_mca, mcas + mca_index, sizeof (grec->grec_mca));
+
+ /* Zero sources upto now */
+ grec->grec_nsrcs = 0;
+ /* 0 Sources -> Exclude those */
+ grec->grec_type = MLD2_MODE_IS_EXCLUDE;
+ if (mode) {
+ grec->grec_type = mode;
+ }
+
+ /* Nothing added yet */
+ any = false;
+
+ for (src_index = 0; src_index < srcn || (!srcn && src_index == 0); src_index++) {
+
+ //check for duplicate source reocrds and any address
+
+ /* Packet with at least one grec and one or more src's, excluding ip6 header */
+
+ length = (((char *) grec) - ((char *) packet)) + sizeof (*grec) + (sizeof (*src) * (grec->grec_nsrcs)) - sizeof (packet->ip6);
+
+ //fprintf(stdout,"loop2:(grec = %02d) %02d.length = %04d (Total : %04d MTU: %04d)\n", packet->mld2r.ngrec,mca_index,length,(length + sizeof(packet->ip6)),intn->mtu);
+ /* Would adding it not fit? -> Send it out */
+ if (((length + sizeof (packet->ip6) + sizeof (*src)) > (intn->mtu)) && srcn) {
+ //fprintf(stdout,"next source addr. does not fit... sending... \n");
+ //fprintf(stdout,"src_index = %d grec->grec_nsrcs = %d \n",src_index,grec->grec_nsrcs);
+
+ /* Take care of endianess */
+ packet->mld2r.ngrec = htons (packet->mld2r.ngrec);
+ grec->grec_nsrcs = htons (grec->grec_nsrcs);
+ /* Calculate and fill in the checksum */
+
+ packet->ip6.ip6_plen = htons (length);
+ packet->mld2r.csum = htons (0);
+ packet->mld2r.csum = ipv6_checksum (&packet->ip6, IPPROTO_ICMPV6, (uint8_t *) & packet->mld2r, length - sizeof (struct ip6_hbh) - sizeof (packet->routeralert));
+
+ count++;
+ dbg ("%04d.Sending2 MLDv2 Report on %s/%u, ngrec=%u, length=%u sources=%u (in last grec)\n", count, intn->name, intn->ifindex, ntohs (packet->mld2r.ngrec), length, ntohs (grec->grec_nsrcs));
+ sendpacket6 (intn, (const struct ip6_hdr *) packet, length + sizeof (packet->ip6));
+
+ /* Increase ICMP sent statistics */
+ g_conf->stat_icmp_sent++;
+ intn->stat_icmp_sent++;
+
+ /* Reset the MLDv2 struct */
+ packet->mld2r.ngrec = 0;
+ src = NULL;
+ grec = NULL;
+ //if not IS_EX or TO EXCLUDE_MODE splitting must be done
+ break;
+ }
+
+ /* Only add non-:: addresses */
+ if (!srcn)
+ break;
+ if (!IN6_IS_ADDR_UNSPECIFIED (sources + src_index) && srcn) {
+ /* First/Next address */
+ src = (struct in6_addr *) (((char *) grec) + sizeof (*grec) + (sizeof (*src) * grec->grec_nsrcs));
+ /* An additional source */
+ grec->grec_nsrcs++;
+ if (mode) {
+ grec->grec_type = mode; //MLD2_MODE_IS_EXCLUDE;
+ }
+ /* Append the source address */
+ memcpy (src, sources + src_index, sizeof (*src));
+ }
+ }
+ }
+
+ //fprintf(stdout,"done\n");
+ if (packet->mld2r.ngrec == 0) {
+ //fprintf(stdout,"All data sent !!!!!!\n");
+ free (packet);
+ packet = NULL;
+ return (1);
+ }
+ /* Take care of endianess */
+ length = (((char *) grec) - ((char *) packet) + sizeof (*grec) + (sizeof (*src) * (grec->grec_nsrcs)) - sizeof (packet->ip6));
+ packet->mld2r.ngrec = htons (packet->mld2r.ngrec);
+ grec->grec_nsrcs = htons (grec->grec_nsrcs);
+
+ /* Calculate and fill in the checksum */
+ packet->ip6.ip6_plen = htons (length);
+ packet->mld2r.csum = htons (0);
+ packet->mld2r.csum = ipv6_checksum (&packet->ip6, IPPROTO_ICMPV6, (uint8_t *) & packet->mld2r, length - sizeof (struct ip6_hbh) - sizeof (packet->routeralert));
+ count++;
+ dbg ("%04d.Sending2 MLDv2 Report on %s/%u, ngrec=%u, length=%u sources=%u (in last grec)\n", count, intn->name, intn->ifindex, ntohs (packet->mld2r.ngrec), length, ntohs (grec->grec_nsrcs));
+ sendpacket6 (intn, (const struct ip6_hdr *) packet, length + sizeof (packet->ip6));
+
+ /* Increase ICMP sent statistics */
+ g_conf->stat_icmp_sent++;
+ intn->stat_icmp_sent++;
+
+ free (packet);
+ //fprintf(stdout,"Total ICMP packets sent = %llu\n", intn->stat_icmp_sent );
+ return 0;
+}
diff --git a/mcast/common/.svn/text-base/mld_common.c.svn-base b/mcast/common/.svn/text-base/mld_common.c.svn-base
new file mode 100644
index 0000000..77e05bd
--- /dev/null
+++ b/mcast/common/.svn/text-base/mld_common.c.svn-base
@@ -0,0 +1,243 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ */
+
+#include "headers.h"
+struct conf *g_conf=NULL;
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+#ifdef DEBUG
+struct lookup icmpv6_types[] = {
+ {ICMP6_DST_UNREACH, "Destination Unreachable"},
+ {ICMP6_PACKET_TOO_BIG, "Packet too big"},
+ {ICMP6_TIME_EXCEEDED, "Time Exceeded"},
+ {ICMP6_PARAM_PROB, "Parameter Problem"},
+ {ICMP6_ECHO_REQUEST, "Echo Request"},
+ {ICMP6_ECHO_REPLY, "Echo Reply"},
+ {ICMP6_MEMBERSHIP_QUERY, "Membership Query"},
+ {ICMP6_MEMBERSHIP_REPORT, "Membership Report"},
+ {ICMP6_MEMBERSHIP_REDUCTION, "Membership Reduction"},
+ {ICMP6_V2_MEMBERSHIP_REPORT, "Membership Report (V2)"},
+ {ICMP6_V2_MEMBERSHIP_REPORT_EXP, "Membership Report (V2) - Experimental"},
+ {ND_ROUTER_SOLICIT, "ND Router Solicitation"},
+ {ND_ROUTER_ADVERT, "ND Router Advertisement"},
+ {ND_NEIGHBOR_SOLICIT, "ND Neighbour Solicitation"},
+ {ND_NEIGHBOR_ADVERT, "ND Neighbour Advertisement"},
+ {ND_REDIRECT, "ND Redirect"},
+ {ICMP6_ROUTER_RENUMBERING, "Router Renumbering",},
+ {ICMP6_NI_QUERY, "Node Information Query"},
+ {ICMP6_NI_REPLY, "Node Information Reply"},
+ {MLD_MTRACE_RESP, "Mtrace Response"},
+ {MLD_MTRACE, "Mtrace Message"},
+ {0, NULL},
+}, icmpv6_codes_unreach[] = {
+ {ICMP6_DST_UNREACH_NOROUTE, "No route to destination"},
+ {ICMP6_DST_UNREACH_ADMIN, "Administratively prohibited"},
+ {ICMP6_DST_UNREACH_NOTNEIGHBOR, "Not a neighbor (obsolete)"},
+ {ICMP6_DST_UNREACH_BEYONDSCOPE, "Beyond scope of source address"},
+ {ICMP6_DST_UNREACH_ADDR, "Address Unreachable"},
+ {ICMP6_DST_UNREACH_NOPORT, "Port Unreachable"},
+}, icmpv6_codes_ttl[] = {
+
+ {ICMP6_TIME_EXCEED_TRANSIT, "Time Exceeded during Transit",},
+ {ICMP6_TIME_EXCEED_REASSEMBLY, "Time Exceeded during Reassembly"},
+}, icmpv6_codes_param[] = {
+
+ {ICMP6_PARAMPROB_HEADER, "Erroneous Header Field"},
+ {ICMP6_PARAMPROB_NEXTHEADER, "Unrecognized Next Header"},
+ {ICMP6_PARAMPROB_OPTION, "Unrecognized Option"},
+}, icmpv6_codes_ni[] = {
+
+ {ICMP6_NI_SUCCESS, "Node Information Successful Reply"},
+ {ICMP6_NI_REFUSED, "Node Information Request Is Refused"},
+ {ICMP6_NI_UNKNOWN, "Unknown Qtype"},
+}, icmpv6_codes_renumber[] = {
+
+ {ICMP6_ROUTER_RENUMBERING_COMMAND, "Router Renumbering Command"},
+ {ICMP6_ROUTER_RENUMBERING_RESULT, "Router Renumbering Result"},
+ {ICMP6_ROUTER_RENUMBERING_SEQNUM_RESET, "Router Renumbering Sequence Number Reset"},
+}, mld2_grec_types[] = {
+
+ {MLD2_MODE_IS_INCLUDE, "MLDv2 Mode Is Include"},
+ {MLD2_MODE_IS_EXCLUDE, "MLDv2 Mode Is Exclude"},
+ {MLD2_CHANGE_TO_INCLUDE, "MLDv2 Change to Include"},
+ {MLD2_CHANGE_TO_EXCLUDE, "MLDv2 Change to Exclude"},
+ {MLD2_ALLOW_NEW_SOURCES, "MLDv2 Allow New Source"},
+ {MLD2_BLOCK_OLD_SOURCES, "MLDv2 Block Old Sources"},
+};
+#endif
+
+//----------------------------------------------------------------------------------------------------------------
+const char *lookup (struct lookup *l, unsigned int num)
+{
+ unsigned int i;
+ for (i = 0; l && l[i].desc; i++) {
+ if (l[i].num != num)
+ continue;
+ return l[i].desc;
+ }
+ return "Unknown";
+}
+
+const char *icmpv6_type (unsigned int type)
+{
+#ifdef DEBUG
+ return lookup (icmpv6_types, type);
+#else
+ return "";
+#endif
+}
+
+const char *icmpv6_code (unsigned int type, unsigned int code)
+{
+#ifdef DEBUG
+ struct lookup *l = NULL;
+ switch (type) {
+ case ICMP6_DST_UNREACH:
+ l = icmpv6_codes_unreach;
+ break;
+ case ICMP6_TIME_EXCEEDED:
+ l = icmpv6_codes_ttl;
+ break;
+ case ICMP6_PARAM_PROB:
+ l = icmpv6_codes_param;
+ break;
+ case ICMP6_NI_QUERY:
+ case ICMP6_NI_REPLY:
+ l = icmpv6_codes_ni;
+ break;
+ case ICMP6_ROUTER_RENUMBERING:
+ l = icmpv6_codes_renumber;
+ break;
+ }
+ return lookup (l, code);
+#else
+ return "";
+#endif
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+uint16_t inchksum (const void *data, uint32_t length)
+{
+ register long sum = 0;
+ register const uint16_t *wrd = (const uint16_t *) data;
+ register long slen = (long) length;
+
+ while (slen >= 2) {
+ sum += *wrd++;
+ slen -= 2;
+ }
+
+ if (slen > 0)
+ sum += *(const uint8_t *) wrd;
+
+ while (sum >> 16)
+ sum = (sum & 0xffff) + (sum >> 16);
+
+ return (uint16_t) sum;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+uint16_t ipv6_checksum (const struct ip6_hdr * ip6, uint8_t protocol, const void *data, const uint16_t length)
+{
+ struct
+ {
+ uint16_t length;
+ uint16_t zero1;
+ uint8_t zero2;
+ uint8_t next;
+ } pseudo;
+ register uint32_t chksum = 0;
+
+ pseudo.length = htons (length);
+ pseudo.zero1 = 0;
+ pseudo.zero2 = 0;
+ pseudo.next = protocol;
+
+ /* IPv6 Source + Dest */
+ chksum = inchksum (&ip6->ip6_src, sizeof (ip6->ip6_src) + sizeof (ip6->ip6_dst));
+ chksum += inchksum (&pseudo, sizeof (pseudo));
+ chksum += inchksum (data, length);
+
+ /* Wrap in the carries to reduce chksum to 16 bits. */
+ chksum = (chksum >> 16) + (chksum & 0xffff);
+ chksum += (chksum >> 16);
+
+ /* Take ones-complement and replace 0 with 0xFFFF. */
+ chksum = (uint16_t) ~ chksum;
+ if (chksum == 0UL)
+ chksum = 0xffffUL;
+ return (uint16_t) chksum;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+void sendpacket6 (struct intnode *intn, const struct ip6_hdr *iph, const uint16_t len)
+{
+ int sent;
+#if ! (defined WIN32 || defined APPLE)
+ struct sockaddr_ll sa;
+
+ memset (&sa, 0, sizeof (sa));
+
+ sa.sll_family = AF_PACKET;
+ sa.sll_protocol = htons (ETH_P_IPV6);
+ sa.sll_ifindex = intn->ifindex;
+ sa.sll_hatype = intn->hwaddr.sa_family;
+ sa.sll_pkttype = 0;
+ sa.sll_halen = 6;
+
+ /*
+ * Construct a Ethernet MAC address from the IPv6 destination multicast address.
+ * Per RFC2464
+ */
+ sa.sll_addr[0] = 0x33;
+ sa.sll_addr[1] = 0x33;
+ sa.sll_addr[2] = iph->ip6_dst.s6_addr[12];
+ sa.sll_addr[3] = iph->ip6_dst.s6_addr[13];
+ sa.sll_addr[4] = iph->ip6_dst.s6_addr[14];
+ sa.sll_addr[5] = iph->ip6_dst.s6_addr[15];
+
+ /* Send the packet */
+ errno = 0;
+
+#else
+// info("Send on Interface %s@%d len:%d\n",intn->name, intn->ifindex, len);
+ struct sockaddr_in6 sa;
+ memset (&sa, 0, sizeof (sa));
+
+ sa.sin6_family = AF_INET6;
+ sa.sin6_addr = iph->ip6_dst;
+#endif
+#ifdef APPLE
+ unsigned char *x=(unsigned char *)iph;
+ sent = sendto (g_conf->rawsocket, (_SOTYPE)x+40, len-40, 0, (struct sockaddr *) &sa, sizeof (sa));
+#else
+ sent = sendto (g_conf->rawsocket, (_SOTYPE)iph, len, 0, (struct sockaddr *) &sa, sizeof (sa));
+#endif
+ if (sent < 0) {
+ /*
+ * Remove the device if it doesn't exist anymore,
+ * can happen with dynamic tunnels etc
+ */
+ if (errno == ENXIO) {
+ warn ("Cannot send %u bytes on interface %s received ENXIO, interface %u no longer usable\n", len, intn->name, intn->ifindex);
+ /* Destroy the interface itself */
+ int_destroy (intn);
+ } else
+ warn ("Cannot send %u bytes on interface %s (%d) failed with a mtu of %u: %s (errno %d)\n", len, intn->name, intn->ifindex, intn->mtu, strerror (errno), errno);
+ return;
+ }
+
+ /* Update the global statistics */
+ g_conf->stat_packets_sent++;
+ g_conf->stat_bytes_sent += len;
+
+ /* Update interface statistics */
+ intn->stat_bytes_sent += len;
+ intn->stat_packets_sent++;
+ return;
+}
diff --git a/mcast/common/.svn/text-base/recv_ccpp.c.svn-base b/mcast/common/.svn/text-base/recv_ccpp.c.svn-base
new file mode 100644
index 0000000..ce15e4c
--- /dev/null
+++ b/mcast/common/.svn/text-base/recv_ccpp.c.svn-base
@@ -0,0 +1,1333 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ */
+
+#undef DEBUG
+#include "headers.h"
+
+extern int port;
+extern char iface[IFNAMSIZ];
+
+typedef struct
+{
+ xmlDocPtr doc;
+ xmlChar *str, *key;
+} xml_parser_context_t;
+
+STATIC void clean_xml_parser_thread (void *arg)
+{
+ xml_parser_context_t *c = (xml_parser_context_t *) arg;
+ if (c->str) {
+ xmlFree (c->str);
+ }
+ if (c->key) {
+ xmlFree (c->key);
+ }
+ if (c->doc) {
+ xmlFreeDoc (c->doc);
+ }
+ dbg ("Free XML parser structures!\n");
+}
+
+int get_tra_data (xmlChar * xmlbuff, int buffersize, tra_info_t * tra_info)
+{
+ xml_parser_context_t c;
+ xmlNode *root_element = NULL, *cur_node = NULL;
+
+// xmlKeepBlanksDefault (0); //reomve this f. "text" nodes
+// c.doc = xmlParseMemory ((char *) xmlbuff, buffersize);
+// xmlKeepBlanksDefault doesn't work after patching cam flags
+ c.doc = xmlReadMemory((char *) xmlbuff, buffersize, NULL, "UTF-8", XML_PARSE_NOERROR | XML_PARSE_NOWARNING | XML_PARSE_NOBLANKS );
+ root_element = xmlDocGetRootElement (c.doc);
+ pthread_cleanup_push (clean_xml_parser_thread, &c);
+ time_t t=time(NULL);
+
+ if (root_element != NULL) {
+
+ cur_node = root_element->children;
+
+ if (!xmlStrcmp (cur_node->name, (xmlChar *) "Description")) {
+
+ root_element = cur_node->children;
+ while (root_element != NULL) {
+ c.key = NULL;
+ c.str = NULL;
+ if ((xmlStrcmp (root_element->name, (const xmlChar *) "component"))) {
+ warn ("Cannot parse XML data\n");
+ root_element = root_element->next;
+ continue;
+ }
+
+ cur_node = root_element->children;
+ if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "Description"))) {
+ c.str = xmlGetProp (cur_node, (unsigned char *) "about");
+// fprintf(stdout,"\n%s:\n",c.str);
+// fprintf(stdout,"-----------------------------------------------------------\n");
+ } else {
+ warn ("Cannot parse XML data\n");
+ root_element = root_element->next;
+ continue;
+ }
+#ifdef P2P
+ if (c.str && (!xmlStrcmp (c.str, (const xmlChar *) "P2P_Data"))) {
+ cur_node = cur_node->children;
+ while (cur_node != NULL) {
+ if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "Quit"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("Quit: %s\n", c.key);
+ tra_info->quit = atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "TCA_ID"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("TCA_ID: %s\n", c.key);
+ tra_info->tca_id = atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "MC_Groups"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("MC_Groups: %s\n", c.key);
+ tra_info->mca_grps = atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "IP"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("IP: %s\n", c.key);
+ inet_pton (AF_INET6, (char *) c.key, &tra_info->ipv6);
+ xmlFree (c.key);
+ }
+ }
+ cur_node = cur_node->next;
+ }
+ } else if (c.str && (!xmlStrcmp (c.str, (const xmlChar *) "Tuner_Status"))) {
+#else
+ if (c.str && (!xmlStrcmp (c.str, (const xmlChar *) "Tuner_Status"))) {
+#endif
+ cur_node = cur_node->children;
+ tra_info->tra = (tra_t *) realloc (tra_info->tra, (tra_info->tra_num + 1) * sizeof (tra_t));
+ if (!tra_info->tra) {
+ err ("Cannot get memory for tra_t\n");
+ }
+ tra_t *tra = tra_info->tra + tra_info->tra_num;
+ memset(tra, 0, sizeof (tra_t));
+ tra->magic=MCLI_MAGIC;
+ tra->version=MCLI_VERSION;
+
+ while (cur_node != NULL) {
+ if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "Status"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("Status: %s\n", c.key);
+ tra->s.st = (fe_status_t) atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "Signal"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("Signal: %s\n", c.key);
+ tra->s.strength = (u_int16_t) atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "SNR"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("SNR: %s\n", c.key);
+ tra->s.snr = (u_int16_t) atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "BER"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("BER: %s\n", c.key);
+ tra->s.ber = (u_int32_t) atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "UNC"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("UNC: %s\n", c.key);
+ tra->s.ucblocks = (u_int32_t) atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "Slot"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("Slot: %s\n", c.key);
+ tra->slot = atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "RotorStatus"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("Rotor: %s\n", c.key);
+ tra->rotor_status = (u_int32_t) atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "RotorDiff"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("Rotor: %s\n", c.key);
+ tra->rotor_diff = (u_int32_t) atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "UUID"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("UUID: %s\n", c.key);
+ strncpy (tra->uuid, (char *) c.key, UUID_SIZE-1);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "MCG"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("MCG: %s\n", c.key);
+ inet_pton (AF_INET6, (char *) c.key, &tra->mcg);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "Redirect"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("Redirect: %s\n", c.key);
+ tra->redirect = atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "NIMCurrent"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("NIMCurrent: %s\n", c.key);
+ tra->NIMCurrent = atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "InUse"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("InUse: %s\n", c.key);
+ tra->InUse = atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "Frequency"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("Frequency: %s\n", c.key);
+ tra->fep.frequency = atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "Inversion"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("Inversion: %s\n", c.key);
+ tra->fep.inversion = (fe_spectral_inversion_t)atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "Type"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("Type: %s\n", c.key);
+ tra->fe_type = (fe_type_t)atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ }
+#ifdef P2P
+ else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "Token"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("Token: %s\n", c.key);
+ tra->token = atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "Preference"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("Preference: %s\n", c.key);
+ tra->preference = atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ }
+#endif
+ else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "SymbolRate"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("SymbolRate: %s\n", c.key);
+ int val=atoi ((char *) c.key);
+ switch((int)tra->fe_type) {
+ case FE_DVBS2:
+ case FE_QPSK:
+ tra->fep.u.qpsk.symbol_rate=val;
+ break;
+ case FE_QAM:
+ tra->fep.u.qam.symbol_rate=val;
+ break;
+ case FE_OFDM:
+ default:
+ break;
+ }
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "FecInner"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("FecInner: %s\n", c.key);
+ int val=atoi ((char *) c.key);
+ switch((int)tra->fe_type) {
+ case FE_DVBS2:
+ case FE_QPSK:
+ tra->fep.u.qpsk.fec_inner=(fe_code_rate_t)val;
+ break;
+ case FE_QAM:
+ tra->fep.u.qam.fec_inner=(fe_code_rate_t)val;
+ break;
+ case FE_OFDM:
+ default:
+ break;
+ }
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "Modulation"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("Modulation: %s\n", c.key);
+ int val=atoi ((char *) c.key);
+ switch((int)tra->fe_type) {
+ case FE_QAM:
+ tra->fep.u.qam.modulation=(fe_modulation_t)val;
+ break;
+ case FE_ATSC:
+ tra->fep.u.vsb.modulation=(fe_modulation_t)val;
+ break;
+ case FE_DVBS2:
+ case FE_QPSK:
+ case FE_OFDM:
+ default:
+ break;
+
+ }
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "Bandwidth"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("Bandwidth: %s\n", c.key);
+ tra->fep.u.ofdm.bandwidth=(fe_bandwidth_t)atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "CodeRateHP"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("CodeRateHP: %s\n", c.key);
+ tra->fep.u.ofdm.code_rate_HP=(fe_code_rate_t)atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "CodeRateLP"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("CodeRateLP: %s\n", c.key);
+ tra->fep.u.ofdm.code_rate_LP=(fe_code_rate_t)atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "Constellation"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("Constellation: %s\n", c.key);
+ tra->fep.u.ofdm.constellation=(fe_modulation_t)atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "TransmissionMode"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("TransmissionMode: %s\n", c.key);
+ tra->fep.u.ofdm.transmission_mode=(fe_transmit_mode_t)atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "GuardInterval"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("GuardInterval: %s\n", c.key);
+ tra->fep.u.ofdm.guard_interval=(fe_guard_interval_t)atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "HierarchyInformation"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("HierarchyInformation: %s\n", c.key);
+ tra->fep.u.ofdm.hierarchy_information=(fe_hierarchy_t)atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ }
+ cur_node = cur_node->next;
+ }
+ tra->lastseen=t;
+ tra_info->tra_num++;
+ } else if (c.str && (!xmlStrcmp (c.str, (const xmlChar *) "CAM"))) {
+ cur_node = cur_node->children;
+ cam_info_t *cam = tra_info->cam + tra_info->cam_num;
+ while(cur_node) {
+ if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "Slot"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ cam->slot = atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "Status"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ cam->status = atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "MenuString"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ strncpy(cam->menu_string, (char *) c.key, MAX_MENU_STR_LEN-1);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "Flags"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ cam->flags = (nc_ca_caps_t)atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "MaxSids"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ cam->max_sids = atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "UseSids"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ cam->use_sids = atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "PmtFlag"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ cam->capmt_flag = atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ }
+ cur_node = cur_node->next;
+ }
+ tra_info->cam_num++;
+ }
+ xmlFree (c.str);
+ root_element = root_element->next;
+ }
+ }
+ }
+ xmlFreeDoc (c.doc);
+ pthread_cleanup_pop (0);
+ return (1);
+}
+
+#ifdef CLIENT
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+typedef struct ccpp_thread_context
+{
+ UDPContext *s;
+ xmlChar *buf;
+ xmlChar *dst;
+ int run;
+} ccpp_thread_context_t;
+
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+STATIC void clean_ccpp_thread (void *arg)
+{
+ ccpp_thread_context_t *c = (ccpp_thread_context_t *) arg;
+ if (c->s) {
+#ifdef MULTI_THREAD_RECEIVER
+ udp_close (c->s);
+#else
+ udp_close_buff (c->s);
+#endif
+ }
+ if(c->buf) {
+ free (c->buf);
+ }
+ if(c->dst) {
+ free (c->dst);
+ }
+ dbg ("CCPP thread data buffer for tid %d freed !\n", gettid ());
+}
+
+void *recv_ten (void *arg)
+{
+ recv_info_t *r = (recv_info_t *) arg;
+ ccpp_thread_context_t c;
+ struct in6_addr ten = r->mcg;
+ int n;
+ tra_info_t tra_info;
+ unsigned int dstlen;
+ clock_t lastrecv=0;
+ int donetimeout=0;
+
+ pthread_cleanup_push (clean_ccpp_thread, &c);
+ memset (&c, 0, sizeof (ccpp_thread_context_t));
+
+ c.buf=(xmlChar *)malloc(XML_BUFLEN);
+ if (!c.buf) {
+ err ("Cannot get memory for TEN buffer\n");
+ }
+ c.dst=(xmlChar *)malloc(XML_BUFLEN * 5);
+ if (!c.dst) {
+ err ("Cannot get memory for TEN destination buffer\n");
+ }
+
+#ifdef FE_STATUS_CLEAR
+ memset (&r->fe_status, 0, sizeof(recv_festatus_t));
+ ioctl (r->fd, DVBLO_SET_FRONTEND_STATUS, &r->fe_status);
+#endif
+ memset (&tra_info, 0, sizeof (tra_info_t));
+ tra_info.magic=MCLI_MAGIC;
+ tra_info.version=MCLI_VERSION;
+
+ mcg_set_streaming_group (&ten, STREAMING_TEN);
+#ifdef MULTI_THREAD_RECEIVER
+ c.s = client_udp_open (&ten, port, iface);
+#else
+ c.s = client_udp_open_buff (&ten, port, iface, XML_BUFLEN);
+#endif
+ if (!c.s) {
+ warn ("client_udp_open error !\n");
+ } else {
+#ifdef DEBUG
+ char host[INET6_ADDRSTRLEN];
+ inet_ntop (AF_INET6, &ten, (char *) host, INET6_ADDRSTRLEN);
+ dbg ("Start receive TEN for tid %d receiver %p at %s port %d %s\n", gettid (), r, host, port, iface);
+#endif
+ r->ten_run = 1;
+ while (r->ten_run) {
+#ifdef MULTI_THREAD_RECEIVER
+ if ((n = udp_read (c.s, c.buf, XML_BUFLEN, 1000, NULL)) > 0) {
+#else
+ usleep(100000); // 10 times per seconds should be enough
+ if ((n = udp_read_buff (c.s, c.buf, XML_BUFLEN, 1000, NULL)) > 0) {
+#endif
+ dstlen = XML_BUFLEN*5;
+ if (!gunzip (c.dst, &dstlen, c.buf, n)) {
+ memset (&tra_info, 0, sizeof (tra_info_t));
+ tra_info.magic=MCLI_MAGIC;
+ tra_info.version=MCLI_VERSION;
+
+ pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, NULL);
+ if (get_tra_data (c.dst, dstlen, &tra_info)) {
+ lastrecv=clock();
+ donetimeout=0;
+ if (tra_info.tra_num) {
+ r->fe_status = tra_info.tra->s;
+ if(r->handle_ten) {
+ r->handle_ten (tra_info.tra, r->handle_ten_context);
+ }
+
+ if (tra_info.tra->redirect) {
+#ifdef DEBUG
+ char hostname[INET6_ADDRSTRLEN];
+ inet_ntop (AF_INET6, &tra_info.tra->mcg, hostname, INET6_ADDRSTRLEN);
+ dbg ("Redirect for receiver %p: MCG is at %s\n", r, hostname);
+#endif
+ int ret = recv_redirect (r, tra_info.tra->mcg);
+
+ if (ret) {
+ printf("New MCG for recv_ten !\n");
+#ifdef MULTI_THREAD_RECEIVER
+ udp_close (c.s);
+#else
+ udp_close_buff (c.s);
+#endif
+ struct in6_addr ten = r->mcg;
+ mcg_set_streaming_group (&ten, STREAMING_TEN);
+#ifdef MULTI_THREAD_RECEIVER
+ c.s = client_udp_open (&ten, port, iface);
+#else
+ c.s = client_udp_open_buff (&ten, port, iface, XML_BUFLEN);
+#endif
+ if (!c.s) {
+ warn ("client_udp_open error !\n");
+ break;
+ }
+ }
+ }
+ }
+ free (tra_info.tra);
+ tra_info.tra=NULL;
+ }
+ pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, NULL);
+ } else {
+ dbg ("uncompress failed\n");
+ }
+ } else {
+ if (!donetimeout && (clock()-lastrecv)>(TEN_TIMEOUT*CLOCKS_PER_SEC)) {
+ donetimeout=1;
+ memset (&r->fe_status, 0, sizeof(recv_festatus_t));
+ if(r->handle_ten) {
+ r->handle_ten (NULL, r->handle_ten_context);
+ }
+ dbg ("Signal Timeout on receiver %p!\n", r);
+ }
+ }
+ pthread_testcancel();
+ }
+#ifdef DEBUG
+ dbg ("Stop receive TEN on receiver %p %s %d %s\n", r, host, port, iface);
+#endif
+ }
+ pthread_cleanup_pop (1);
+ r->ten_run = 1;
+ return NULL;
+}
+
+int register_ten_handler (recv_info_t * r, int (*p) (tra_t *, void *c), void *c)
+{
+ r->handle_ten=p;
+ r->handle_ten_context=c;
+ return 0;
+}
+
+void *recv_tra (void *arg)
+{
+ ccpp_thread_context_t c;
+ int n;
+ tra_info_t tra_info;
+ unsigned int dstlen;
+ struct in6_addr tra;
+
+ pthread_cleanup_push (clean_ccpp_thread, &c);
+ memset (&c, 0, sizeof (ccpp_thread_context_t));
+
+ c.buf=(xmlChar *)malloc(XML_BUFLEN);
+ if (!c.buf) {
+ err ("Cannot get memory for TRA buffer\n");
+ }
+ c.dst=(xmlChar *)malloc(XML_BUFLEN * 5);
+ if (!c.dst) {
+ err ("Cannot get memory for TRA destination buffer\n");
+ }
+
+ mcg_init_streaming_group (&tra, STREAMING_TRA);
+
+#ifdef MULTI_THREAD_RECEIVER
+ c.s = client_udp_open (&tra, port, iface);
+#else
+ c.s = client_udp_open_buff (&tra, port, iface, XML_BUFLEN);
+#endif
+ if (!c.s) {
+ warn ("client_udp_open error !\n");
+ } else {
+ c.run=1;
+#ifdef DEBUG
+ char host[INET6_ADDRSTRLEN];
+ inet_ntop (AF_INET6, &tra, (char *) host, INET6_ADDRSTRLEN);
+ dbg ("Start receive TRA at %s port %d %s\n", host, port, iface);
+#endif
+ while (c.run) {
+#ifdef MULTI_THREAD_RECEIVER
+ if ((n = udp_read (c.s, c.buf, XML_BUFLEN, 500000, NULL)) > 0) {
+#else
+ usleep(100000); // 10 times per seconds should be enough
+ if ((n = udp_read_buff (c.s, c.buf, XML_BUFLEN, 500000, NULL)) > 0) {
+#endif
+ dstlen = XML_BUFLEN*5;
+ if (!gunzip (c.dst, &dstlen, c.buf, n)) {
+ memset (&tra_info, 0, sizeof (tra_info_t));
+ tra_info.magic=MCLI_MAGIC;
+ tra_info.version=MCLI_VERSION;
+
+ pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, NULL);
+ if (get_tra_data (c.dst, dstlen, &tra_info)) {
+ handle_tra (&tra_info);
+ }
+ pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, NULL);
+ } else {
+ dbg ("uncompress failed\n");
+ }
+ }
+#ifdef DEBUG
+ dbg ("Stop receive TRA on %s %d %s len:%d\n", host, port, iface, n);
+#endif
+ pthread_testcancel();
+ }
+ }
+ pthread_cleanup_pop (1);
+ return NULL;
+}
+#endif
+
+//--------------------------------------------------------------------------------------------------------------------------
+int get_tca_data (xmlChar * xmlbuff, int buffersize, netceiver_info_t * nc_info)
+{
+ xml_parser_context_t c;
+ xmlNode *root_element, *cur_node;
+
+// xmlKeepBlanksDefault (0); //reomve this f. "text" nodes
+// c.doc = xmlParseMemory ((char *) xmlbuff, buffersize);
+// xmlKeepBlanksDefault doesn't work after patching cam flags
+ c.doc = xmlReadMemory((char *) xmlbuff, buffersize, NULL, "UTF-8", XML_PARSE_NOERROR | XML_PARSE_NOWARNING | XML_PARSE_NOBLANKS );
+ root_element = xmlDocGetRootElement (c.doc);
+ pthread_cleanup_push (clean_xml_parser_thread, &c);
+ nc_info->magic=MCLI_MAGIC;
+ nc_info->version=MCLI_VERSION;
+
+ if (root_element != NULL) {
+ cur_node = root_element->children;
+
+ if (!xmlStrcmp (cur_node->name, (xmlChar *) "Description")) {
+
+ root_element = cur_node->children;
+ while (root_element != NULL) {
+ c.key = NULL;
+ c.str = NULL;
+ if ((xmlStrcmp (root_element->name, (const xmlChar *) "component"))) {
+ warn ("Cannot parse XML data\n");
+ root_element = root_element->next;
+ continue;
+ }
+
+ cur_node = root_element->children;
+ if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "Description"))) {
+ c.str = xmlGetProp (cur_node, (unsigned char *) "about");
+ } else {
+ warn ("Cannot parse XML data\n");
+ root_element = root_element->next;
+ continue;
+ }
+ if (c.str && (!xmlStrcmp (c.str, (const xmlChar *) "Platform"))) {
+ cur_node = cur_node->children;
+ while (cur_node != NULL) {
+ if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "OSVersion"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("OSVersion: %s\n", c.key);
+ strncpy (nc_info->OSVersion, (char *) c.key, UUID_SIZE-1);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "AppVersion"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("AppVersion: %s\n", c.key);
+ strncpy (nc_info->AppVersion, (char *) c.key, UUID_SIZE-1);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "FirmwareVersion"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("FirmwareVersion: %s\n", c.key);
+ strncpy (nc_info->FirmwareVersion, (char *) c.key, UUID_SIZE-1);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "HardwareVersion"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("HardwareVersion: %s\n", c.key);
+ strncpy (nc_info->HardwareVersion, (char *) c.key, UUID_SIZE-1);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "Serial"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("Serial: %s\n", c.key);
+ strncpy (nc_info->Serial, (char *) c.key, UUID_SIZE-1);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "Vendor"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("Vendor: %s\n", c.key);
+ strncpy (nc_info->Vendor, (char *) c.key, UUID_SIZE-1);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "DefCon"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("DefCon: %s\n", c.key);
+ nc_info->DefCon = atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "UUID"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("UUID: %s\n", c.key);
+ strncpy (nc_info->uuid, (char *) c.key, UUID_SIZE-1);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "Description"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("Description: %s\n", c.key);
+ strncpy (nc_info->Description, (char *) c.key, UUID_SIZE-1);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "IP"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("IP: %s\n", c.key);
+ inet_pton (AF_INET6, (char *) c.key, &nc_info->ip);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "ProcessUptime"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("ProcessUptime: %s\n", c.key);
+ nc_info->ProcessUptime=atoi((char *)c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "SystemUptime"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("SystemUptime: %s\n", c.key);
+ nc_info->SystemUptime=atoi((char *)c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "TunerTimeout"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("TunerTimeout: %s\n", c.key);
+ nc_info->TunerTimeout=atoi((char *)c.key);
+ xmlFree (c.key);
+ }
+ }
+ cur_node = cur_node->next;
+ }
+ } else if (c.str && (!xmlStrcmp (c.str, (const xmlChar *) "Tuner"))) {
+ cur_node = cur_node->children;
+ nc_info->tuner = (tuner_info_t *) realloc (nc_info->tuner, (nc_info->tuner_num + 1) * sizeof (tuner_info_t));
+ if (!nc_info->tuner) {
+ err ("Cannot get memory for tuner_info\n");
+ }
+
+ tuner_info_t *t = nc_info->tuner + nc_info->tuner_num;
+ memset (t, 0, sizeof (tuner_info_t));
+ t->magic=MCLI_MAGIC;
+ t->version=MCLI_VERSION;
+
+ while (cur_node != NULL) {
+ if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "Name"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ strncpy (t->fe_info.name, (char *) c.key, 127);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "Type"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ if ((!xmlStrcmp (c.key, (const xmlChar *) "DVB-S")))
+ t->fe_info.type = FE_QPSK;
+ if ((!xmlStrcmp (c.key, (const xmlChar *) "DVB-S2")))
+ t->fe_info.type = (fe_type_t)FE_DVBS2;
+ if ((!xmlStrcmp (c.key, (const xmlChar *) "DVB-C")))
+ t->fe_info.type = FE_QAM;
+ if ((!xmlStrcmp (c.key, (const xmlChar *) "DVB-T")))
+ t->fe_info.type = FE_OFDM;
+ if ((!xmlStrcmp (c.key, (const xmlChar *) "ATSC")))
+ t->fe_info.type = FE_ATSC;
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "FrequencyMin"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ t->fe_info.frequency_min = atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "FrequencyMax"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ t->fe_info.frequency_max = atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "FrequencyStepSize"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ t->fe_info.frequency_stepsize = atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "FrequencyTolerance"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ t->fe_info.frequency_tolerance = atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "SymbolRateMin"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ t->fe_info.symbol_rate_min = atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "SymbolRateMax"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ t->fe_info.symbol_rate_max = atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "SymbolRateTolerance"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ t->fe_info.symbol_rate_tolerance = atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "Caps"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ t->fe_info.caps = (fe_caps_t)atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "Slot"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ t->slot = atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "Preference"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ t->preference = atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "UUID"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ strncpy (t->uuid, (char *) c.key, UUID_SIZE-1);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "SatelliteListName"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ strncpy (t->SatelliteListName, (char *) c.key, UUID_SIZE-1);
+ xmlFree (c.key);
+ }
+ }
+ cur_node = cur_node->next;
+ }
+ nc_info->tuner_num++;
+ } else if (c.str && !(xmlStrcmp (c.str, (xmlChar *) "CI"))) {
+ cur_node = cur_node->children;
+ recv_cacaps_t *ci=&nc_info->ci;
+ while(cur_node) {
+ if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "component"))) {
+ xmlNode *l2_node = cur_node->children;
+ if ((!xmlStrcmp (l2_node->name, (const xmlChar *) "Description"))) {
+ c.key = xmlGetProp (l2_node, (unsigned char *) "about");
+ dbg ("Parsing CI-Description: %s\n", c.key);
+ if (c.key && !xmlStrcmp (c.key, (xmlChar *) "Capabilities")) {
+ xmlFree (c.key);
+ xmlNode * l3_node = l2_node->children;
+ while (l3_node != NULL) {
+ dbg ("Capability-Element: %s\n", l3_node->name);
+ if ((!xmlStrcmp (l3_node->name, (const xmlChar *) "SlotNum"))) {
+ c.key = xmlNodeListGetString (c.doc, l3_node->xmlChildrenNode, 1);
+ if(c.key) {
+ dbg ("SlotNum: %s\n", c.key);
+ ci->cap.slot_num=atoi((char*)c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (l3_node->name, (const xmlChar *) "SlotType"))) {
+ c.key = xmlNodeListGetString (c.doc, l3_node->xmlChildrenNode, 1);
+ if(c.key) {
+ dbg ("SlotType: %s\n", c.key);
+ ci->cap.slot_type=atoi((char*)c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (l3_node->name, (const xmlChar *) "DescrNum"))) {
+ c.key = xmlNodeListGetString (c.doc, l3_node->xmlChildrenNode, 1);
+ if(c.key) {
+ dbg ("DescrNum: %s\n", c.key);
+ ci->cap.descr_num=atoi((char*)c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (l3_node->name, (const xmlChar *) "DescrType"))) {
+ c.key = xmlNodeListGetString (c.doc, l3_node->xmlChildrenNode, 1);
+ if(c.key) {
+ dbg ("DescrType: %s\n", c.key);
+ ci->cap.descr_type=atoi((char*)c.key);
+ xmlFree (c.key);
+ }
+ }
+ l3_node = l3_node->next;
+ }
+ } else if (c.key && !xmlStrcmp (c.key, (xmlChar *) "Slot")) {
+ xmlFree (c.key);
+ xmlNode *l3_node = l2_node->children;
+ int slot=-1;
+ while (l3_node != NULL) {
+ dbg ("Slot-Element: %s\n", l3_node->name);
+ if ((!xmlStrcmp (l3_node->name, (const xmlChar *) "Num"))) {
+ c.key = xmlNodeListGetString (c.doc, l3_node->xmlChildrenNode, 1);
+ if(c.key) {
+ dbg ("Num: %s\n", c.key);
+ int x=atoi((char*)c.key);
+ if( (x < 0) || (x >= CA_MAX_SLOTS) ) {
+ continue;
+ }
+ slot=x;
+ ci->info[slot].num=slot;
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (l3_node->name, (const xmlChar *) "Type"))) {
+ c.key = xmlNodeListGetString (c.doc, l3_node->xmlChildrenNode, 1);
+ if(c.key) {
+ dbg ("Type: %s\n", c.key);
+ if(slot>=0) {
+ ci->info[slot].type=atoi((char*)c.key);
+ }
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (l3_node->name, (const xmlChar *) "Flags"))) {
+ c.key = xmlNodeListGetString (c.doc, l3_node->xmlChildrenNode, 1);
+ if(c.key) {
+ dbg ("Flags: %s\n", c.key);
+ if(slot>=0) {
+ ci->info[slot].flags=atoi((char*)c.key);
+ }
+ xmlFree (c.key);
+ }
+ }
+ l3_node = l3_node->next;
+ }
+ }
+ }
+ }
+ cur_node = cur_node->next;
+ }
+ //CAM start
+ } else if (c.str && !(xmlStrcmp (c.str, (xmlChar *) "CAM"))) {
+ cur_node = cur_node->children;
+ cam_info_t *cam = nc_info->cam + nc_info->cam_num;
+ while(cur_node) {
+ if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "Slot"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ cam->slot = atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "Status"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ cam->status = atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "MenuString"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ strncpy(cam->menu_string, (char *) c.key, MAX_MENU_STR_LEN-1);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "Flags"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ cam->flags = (nc_ca_caps_t)atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "MaxSids"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ cam->max_sids = atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "UseSids"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ cam->use_sids = atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "PmtFlag"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ cam->capmt_flag = atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ }
+ cur_node = cur_node->next;
+ }
+ nc_info->cam_num++;
+ //CAM end
+ } else if (c.str && !(xmlStrcmp (c.str, (xmlChar *) "SatelliteList"))) {
+ cur_node = cur_node->children;
+ nc_info->sat_list = (satellite_list_t *) realloc (nc_info->sat_list, (nc_info->sat_list_num + 1) * sizeof (satellite_list_t));
+ if (!nc_info->sat_list) {
+ err ("Cannot get memory for sat_list\n");
+ }
+
+ satellite_list_t *sat_list = nc_info->sat_list + nc_info->sat_list_num;
+ memset (sat_list, 0, sizeof (satellite_list_t));
+ sat_list->magic=MCLI_MAGIC;
+ sat_list->version=MCLI_VERSION;
+
+ while (cur_node != NULL) {
+ if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "SatelliteListName"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("SatelliteListName: %s\n", c.key);
+ strncpy (sat_list->Name, (char *) c.key, UUID_SIZE-1);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "component"))) {
+ xmlNode *l2_node = cur_node->children;
+ if ((!xmlStrcmp (l2_node->name, (const xmlChar *) "Description"))) {
+ c.key = xmlGetProp (l2_node, (unsigned char *) "about");
+ dbg ("Parsing L2-Description: %s\n", c.key);
+ if (c.key && !xmlStrcmp (c.key, (xmlChar *) "Satellite")) {
+ xmlFree (c.key);
+ l2_node = l2_node->children;
+ sat_list->sat = (satellite_info_t *) realloc (sat_list->sat, (sat_list->sat_num + 1) * sizeof (satellite_info_t));
+ if (!sat_list->sat) {
+ err ("Cannot get memory for sat\n");
+ }
+
+ satellite_info_t *sat = sat_list->sat + sat_list->sat_num;
+ memset (sat, 0, sizeof (satellite_info_t));
+ sat->magic=MCLI_MAGIC;
+ sat->version=MCLI_VERSION;
+
+ while (l2_node != NULL) {
+ dbg ("L2-Element: %s\n", l2_node->name);
+ if ((!xmlStrcmp (l2_node->name, (const xmlChar *) "Name"))) {
+ c.key = xmlNodeListGetString (c.doc, l2_node->xmlChildrenNode, 1);
+ if(c.key) {
+ dbg ("Name: %s\n", c.key);
+ strncpy (sat->Name, (char *) c.key, UUID_SIZE-1);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (l2_node->name, (const xmlChar *) "Position"))) {
+ c.key = xmlNodeListGetString (c.doc, l2_node->xmlChildrenNode, 1);
+ if(c.key) {
+ dbg ("Position: %s\n", c.key);
+ sat->SatPos = atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (l2_node->name, (const xmlChar *) "PositionMin"))) {
+ c.key = xmlNodeListGetString (c.doc, l2_node->xmlChildrenNode, 1);
+ if(c.key) {
+ dbg ("PositionMin: %s\n", c.key);
+ sat->SatPosMin = atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (l2_node->name, (const xmlChar *) "PositionMax"))) {
+ c.key = xmlNodeListGetString (c.doc, l2_node->xmlChildrenNode, 1);
+ if(c.key) {
+ dbg ("PositionMax: %s\n", c.key);
+ sat->SatPosMax = atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (l2_node->name, (const xmlChar *) "AutoFocus"))) {
+ c.key = xmlNodeListGetString (c.doc, l2_node->xmlChildrenNode, 1);
+ if(c.key) {
+ dbg ("AutoFocus: %s\n", c.key);
+ sat->AutoFocus = atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (l2_node->name, (const xmlChar *) "Latitude"))) {
+ c.key = xmlNodeListGetString (c.doc, l2_node->xmlChildrenNode, 1);
+ if(c.key) {
+ dbg ("Latitude: %s\n", c.key);
+ sat->Latitude = atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (l2_node->name, (const xmlChar *) "Longitude"))) {
+ c.key = xmlNodeListGetString (c.doc, l2_node->xmlChildrenNode, 1);
+ if(c.key) {
+ dbg ("Longitude: %s\n", c.key);
+ sat->Longitude = atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (l2_node->name, (const xmlChar *) "Type"))) {
+ c.key = xmlNodeListGetString (c.doc, l2_node->xmlChildrenNode, 1);
+ if(c.key) {
+ dbg ("Type: %s\n", c.key);
+ sat->type = (satellite_source_t)atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (l2_node->name, (const xmlChar *) "component"))) {
+ xmlNode *l3_node = l2_node->children;
+
+ if ((!xmlStrcmp (l3_node->name, (const xmlChar *) "Description"))) {
+ c.key = xmlGetProp (l3_node, (unsigned char *) "about");
+ dbg ("Parsing L3-Description: %s\n", c.key);
+ if (c.key && !xmlStrcmp (c.key, (xmlChar *) "SatelliteComponent")) {
+ xmlFree (c.key);
+ l3_node = l3_node->children;
+ dbg ("Now checking for SatelliteCompontents\n");
+ sat->comp = (satellite_component_t *) realloc (sat->comp, (sat->comp_num + 1) * sizeof (satellite_component_t));
+ if (!sat->comp) {
+ err ("Cannot get memory for comp\n");
+ }
+
+ satellite_component_t *comp = sat->comp + sat->comp_num;
+ memset (comp, 0, sizeof (satellite_component_t));
+ comp->magic=MCLI_MAGIC;
+ comp->version=MCLI_VERSION;
+
+ while (l3_node != NULL) {
+ dbg ("L3-Element: %s\n", l3_node->name);
+ if ((!xmlStrcmp (l3_node->name, (const xmlChar *) "Polarisation"))) {
+ c.key = xmlNodeListGetString (c.doc, l3_node->xmlChildrenNode, 1);
+ if(c.key) {
+ dbg ("Polarisation: %s\n", c.key);
+ comp->Polarisation = (polarisation_t)atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (l3_node->name, (const xmlChar *) "RangeMin"))) {
+ c.key = xmlNodeListGetString (c.doc, l3_node->xmlChildrenNode, 1);
+ if(c.key) {
+ dbg ("RangeMin: %s\n", c.key);
+ comp->RangeMin = atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (l3_node->name, (const xmlChar *) "RangeMax"))) {
+ c.key = xmlNodeListGetString (c.doc, l3_node->xmlChildrenNode, 1);
+ if(c.key) {
+ dbg ("RangeMax: %s\n", c.key);
+ comp->RangeMax = atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (l3_node->name, (const xmlChar *) "LOF"))) {
+ c.key = xmlNodeListGetString (c.doc, l3_node->xmlChildrenNode, 1);
+ if(c.key) {
+ dbg ("LOF: %s\n", c.key);
+ comp->LOF = atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (l3_node->name, (const xmlChar *) "Voltage"))) {
+ c.key = xmlNodeListGetString (c.doc, l3_node->xmlChildrenNode, 1);
+ if(c.key) {
+ dbg ("Voltage: %s\n", c.key);
+ comp->sec.voltage = (fe_sec_voltage_t)atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (l3_node->name, (const xmlChar *) "Tone"))) {
+ c.key = xmlNodeListGetString (c.doc, l3_node->xmlChildrenNode, 1);
+ if(c.key) {
+ dbg ("Tone: %s\n", c.key);
+ comp->sec.tone_mode = (fe_sec_tone_mode_t)atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (l3_node->name, (const xmlChar *) "MiniCmd"))) {
+ c.key = xmlNodeListGetString (c.doc, l3_node->xmlChildrenNode, 1);
+ if(c.key) {
+ dbg ("MiniCmd: %s\n", c.key);
+ comp->sec.mini_cmd = (fe_sec_mini_cmd_t)atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (l3_node->name, (const xmlChar *) "DiSEqC_Cmd"))) {
+ c.key = xmlNodeListGetString (c.doc, l3_node->xmlChildrenNode, 1);
+ dbg ("DiSEqC_Cmd: %s\n", c.key);
+ if(c.key) {
+ int v[6], i, n=0;
+ char *s= (char *)c.key;
+ struct dvb_diseqc_master_cmd *diseqc_cmd=&comp->sec.diseqc_cmd;
+ do {
+ dbg("Parsing: %s\n",s);
+ diseqc_cmd->msg_len = sscanf (s, "%x %x %x %x %x %x", v, v + 1, v + 2, v + 3, v + 4, v + 5);
+ for (i = 0; i < diseqc_cmd->msg_len; i++) {
+ diseqc_cmd->msg[i] = v[i];
+ }
+ s=strchr(s,',');
+ if(s) {
+ s++;
+ }
+ diseqc_cmd=comp->diseqc_cmd+n;
+ n++;
+ } while(s && n<=DISEQC_MAX_EXTRA);
+ xmlFree (c.key);
+ comp->diseqc_cmd_num=n;
+ }
+ }
+ l3_node = l3_node->next;
+ }
+ sat->comp_num++;
+ } else {
+ xmlFree (c.key);
+ }
+ }
+ }
+ l2_node = l2_node->next;
+ }
+ sat_list->sat_num++;
+ } else {
+ xmlFree (c.key);
+ }
+ }
+ }
+ cur_node = cur_node->next;
+ }
+ nc_info->sat_list_num++;
+ }
+ xmlFree (c.str);
+ root_element = root_element->next;
+ }
+ }
+ }
+
+ xmlFreeDoc (c.doc);
+ pthread_cleanup_pop (0);
+ return (1);
+}
+
+#ifdef CLIENT
+
+void *recv_tca (void *arg)
+{
+ int n;
+ ccpp_thread_context_t c;
+ unsigned int dstlen;
+ netceiver_info_t nc_info;
+ struct in6_addr tca;
+
+ pthread_cleanup_push (clean_ccpp_thread, &c);
+
+ c.buf=(xmlChar *)malloc(XML_BUFLEN);
+ if (!c.buf) {
+ err ("Cannot get memory for TRA buffer\n");
+ }
+ c.dst=(xmlChar *)malloc(XML_BUFLEN * 5);
+ if (!c.dst) {
+ err ("Cannot get memory for TRA destination buffer\n");
+ }
+
+ mcg_init_streaming_group (&tca, STREAMING_TCA);
+
+#ifdef MULTI_THREAD_RECEIVER
+ c.s = client_udp_open (&tca, port, iface);
+#else
+ c.s = client_udp_open_buff (&tca, port, iface, XML_BUFLEN);
+#endif
+ if (!c.s) {
+ warn ("client_udp_open error !\n");
+ } else {
+ c.run=1;
+#ifdef DEBUG
+ char host[INET6_ADDRSTRLEN];
+ inet_ntop (AF_INET6, &tca, (char *) host, INET6_ADDRSTRLEN);
+ dbg ("Start Receive TCA on interface %s port %d\n", iface, port);
+#endif
+ while (c.run) {
+#ifdef MULTI_THREAD_RECEIVER
+ if ((n = udp_read (c.s, c.buf, XML_BUFLEN, 500000, NULL)) > 0) {
+#else
+ usleep(100000); // 10 times per seconds should be enough
+ if ((n = udp_read_buff (c.s, c.buf, XML_BUFLEN, 500000, NULL)) > 0) {
+#endif
+ dstlen = XML_BUFLEN * 5;
+ if (!gunzip (c.dst, &dstlen, c.buf, n)) {
+ memset (&nc_info, 0, sizeof (netceiver_info_t));
+
+ pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, NULL);
+ get_tca_data (c.dst, dstlen, &nc_info);
+ handle_tca (&nc_info);
+ pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, NULL);
+ } else {
+ dbg ("uncompress failed\n");
+ }
+ }
+ pthread_testcancel();
+ }
+ }
+ pthread_cleanup_pop (1);
+ return NULL;
+}
+#endif
diff --git a/mcast/common/.svn/text-base/recv_ccpp.h.svn-base b/mcast/common/.svn/text-base/recv_ccpp.h.svn-base
new file mode 100644
index 0000000..78e1b83
--- /dev/null
+++ b/mcast/common/.svn/text-base/recv_ccpp.h.svn-base
@@ -0,0 +1,129 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ */
+
+#ifndef __RECV_CCPP_H
+#define __RECV_CCPP_H
+
+#define XML_BUFLEN 65536
+#define TEN_TIMEOUT 2
+#define MAX_MENU_STR_LEN 64
+#define MAX_CAMS 2
+
+
+typedef struct tuner_info
+{
+ int magic;
+ int version;
+
+ struct dvb_frontend_info fe_info;
+ int slot;
+ int preference;
+ char uuid[UUID_SIZE];
+ char SatelliteListName[UUID_SIZE];
+} tuner_info_t;
+
+typedef enum { CA_SINGLE, CA_MULTI_SID, CA_MULTI_TRANSPONDER} nc_ca_caps_t;
+enum { DVBCA_CAMSTATE_MISSING, DVBCA_CAMSTATE_INITIALISING, DVBCA_CAMSTATE_READY};
+
+typedef struct cam_info {
+
+ uint8_t slot;
+ uint8_t status;
+ int max_sids;
+ int use_sids;
+ int capmt_flag;
+ int reserved;
+ nc_ca_caps_t flags;
+
+ char menu_string[MAX_MENU_STR_LEN];
+
+} cam_info_t;
+
+typedef struct netceiver_info
+{
+ int magic;
+ int version;
+
+ char OSVersion[UUID_SIZE];
+ char AppVersion[UUID_SIZE];
+ char FirmwareVersion[UUID_SIZE];
+ char HardwareVersion[UUID_SIZE];
+ char Serial[UUID_SIZE];
+ char Vendor[UUID_SIZE];
+ char uuid[UUID_SIZE];
+ char Description[UUID_SIZE];
+ int TunerTimeout;
+ struct in6_addr ip;
+ int DefCon;
+ time_t SystemUptime;
+ time_t ProcessUptime;
+
+ time_t lastseen;
+
+ tuner_info_t *tuner;
+ recv_cacaps_t ci;
+ satellite_list_t *sat_list;
+ cam_info_t cam[MAX_CAMS];
+
+
+ int tuner_num;
+ int sat_list_num;
+ int cam_num;
+} netceiver_info_t;
+
+typedef struct tra
+{
+ int magic;
+ int version;
+
+ recv_festatus_t s;
+ fe_type_t fe_type;
+ struct dvb_frontend_parameters fep;
+ struct in6_addr mcg;
+ int slot;
+ char uuid[UUID_SIZE];
+ int redirect;
+ int NIMCurrent;
+ int InUse;
+ int rotor_status;
+ time_t lastseen;
+ int rotor_diff;
+#ifdef P2P
+ int preference;
+ int token;
+#endif
+
+} tra_t;
+
+typedef struct tra_info
+{
+ int magic;
+ int version;
+
+ tra_t *tra;
+ int tra_num;
+ cam_info_t cam[MAX_CAMS];
+ int cam_num;
+#ifdef P2P
+ int quit;
+ int tca_id;
+ int mca_grps;
+ struct in6_addr ipv6;
+#endif
+
+} tra_info_t;
+
+typedef struct recv_info recv_info_t;
+
+void *recv_ten (void *arg);
+void *recv_tca (void *arg);
+void *recv_tra (void *arg);
+int get_tca_data (xmlChar * xmlbuff, int buffersize, netceiver_info_t * nc_info);
+int get_tra_data (xmlChar * xmlbuff, int buffersize, tra_info_t * tra_info);
+DLL_SYMBOL int register_ten_handler (recv_info_t * r, int (*p)(tra_t *, void *), void *c);
+#endif
diff --git a/mcast/common/.svn/text-base/satlists.h.svn-base b/mcast/common/.svn/text-base/satlists.h.svn-base
new file mode 100644
index 0000000..ad95889
--- /dev/null
+++ b/mcast/common/.svn/text-base/satlists.h.svn-base
@@ -0,0 +1,92 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ */
+
+#define DISEQC_MAX_EXTRA 8
+#define MAX_EXTRA_DATA 16
+
+typedef enum
+{
+//the defines for circular polarisation are taken from official DiSEqC-Spec at
+//http://www.eutelsat.com/satellites/pdf/Diseqc/Reference%20docs/bus_spec.pdf
+ POL_V = SEC_VOLTAGE_13,
+ POL_H = SEC_VOLTAGE_18,
+ POL_R = SEC_VOLTAGE_13,
+ POL_L = SEC_VOLTAGE_18,
+} polarisation_t;
+
+typedef struct
+{
+ int magic;
+ int version;
+
+ polarisation_t Polarisation; // H/V/L/R
+ int RangeMin; // 11700
+ int RangeMax; // 12750
+
+// SEC Settings to be used for the specification above
+ int LOF; // 9750
+ recv_sec_t sec;
+ struct dvb_diseqc_master_cmd diseqc_cmd[DISEQC_MAX_EXTRA];
+ int diseqc_cmd_num;
+} satellite_component_t;
+
+typedef enum
+{
+ SAT_SRC_LNB=0,
+ SAT_SRC_ROTOR=1,
+ SAT_SRC_UNI=2, // !!! match DISEQC_* values in dvb_server.h !!!
+} satellite_source_t;
+
+typedef struct
+{
+ int magic;
+ int version;
+
+// Specification of satellite parameters
+ char Name[UUID_SIZE]; // Astra 19,2
+ int SatPos; // 1920
+ int SatPosMin; // Only used for SAT_SRC_ROTOR
+ int SatPosMax; // Only used for SAT_SRC_ROTOR
+ satellite_source_t type; // see above
+
+ satellite_component_t *comp; // What to do for polarisation and range for SEC?
+ int comp_num; // Number of components
+ int AutoFocus;
+ int Latitude;
+ int Longitude;
+ int num_extra_data;
+ int extra_data[MAX_EXTRA_DATA]; // reserved
+} satellite_info_t;
+
+typedef struct satellite_list
+{
+ int magic;
+ int version;
+
+ char Name[UUID_SIZE]; // Magic unique identifier
+ satellite_info_t *sat;
+ int sat_num;
+} satellite_list_t;
+
+typedef struct
+{
+ int magic;
+ int version;
+
+ int netceiver;
+ int sat_list;
+ int sat;
+ int comp;
+ int position; // for rotor
+} satellite_reference_t;
+
+DLL_SYMBOL int satellite_find_by_diseqc (satellite_reference_t * ref, recv_sec_t *sec, struct dvb_frontend_parameters *fep, int mode);
+DLL_SYMBOL int satellite_get_pos_by_ref (satellite_reference_t * ref);
+DLL_SYMBOL int satellite_get_lof_by_ref (satellite_reference_t * ref);
+DLL_SYMBOL polarisation_t satellite_find_pol_by_ref (satellite_reference_t * ref);
+DLL_SYMBOL recv_sec_t *satellite_find_sec_by_ref (satellite_reference_t * ref);
diff --git a/mcast/common/.svn/text-base/siparser.c.svn-base b/mcast/common/.svn/text-base/siparser.c.svn-base
new file mode 100644
index 0000000..4ce7032
--- /dev/null
+++ b/mcast/common/.svn/text-base/siparser.c.svn-base
@@ -0,0 +1,1049 @@
+#include "headers.h"
+
+//#define DBG 1
+#define CRC32_CHECK 1
+
+enum ca_desc_type { EMM, ECM };
+
+//-----------------------------------------------------------------------------------
+void printhex_buf(char *msg,unsigned char *buf,int len)
+{
+ int i,j,k;
+ int width=8;
+
+ i=k=0;
+ sys ("%s: %d bytes (0x%04x)\n",msg,len,len);
+ sys ("---------------------------------------------------------------\n");
+ while(len) {
+ sys ("%04x ",k++*width*2);
+ j=i;
+ for(;i < j + width ; i++){
+ if (i >= len) break;
+ sys ("%02x ",buf[i]);
+ }
+ if (i >= len) {
+ sys ("\n");
+ break;
+ }
+ sys(" ");
+ j=i;
+ for(;i < j + width ; i++){
+ if (i >= len) break;
+ sys("%02x ",buf[i]);
+ }
+ sys("\n");
+ if (i >= len) break;
+ }
+ sys("---------------------------------------------------------------\n");
+}
+//-----------------------------------------------------------------------------------
+void writehex_buf(FILE *f, char *msg,unsigned char *buf,int len)
+{
+ int i,j,k;
+ int width=8;
+
+ i=k=0;
+ fprintf(f,"%s: %d bytes (0x%04x)\n",msg,len,len);
+ fprintf(f,"---------------------------------------------------------------\n");
+ while(len) {
+ fprintf(f,"%04x ",k++*width*2);
+ j=i;
+ for(;i < j + width ; i++){
+ if (i >= len) break;
+ fprintf(f,"%02x ",buf[i]);
+ }
+ if (i >= len) {
+ fprintf(f,"\n");
+ break;
+ }
+ fprintf(f," ");
+ j=i;
+ for(;i < j + width ; i++){
+ if (i >= len) break;
+ fprintf(f,"%02x ",buf[i]);
+ }
+ fprintf(f,"\n");
+ if (i >= len) break;
+ }
+ fprintf(f,"---------------------------------------------------------------\n");
+
+
+}
+//-----------------------------------------------------------------------------------
+void print_ts_header(ts_packet_hdr_t *p)
+{
+ info("--------------------------------------------------------------\n");
+ info("TS header data:\n");
+ info("Sync-byte : 0x%04x\n",p->sync_byte);
+ info("Transport error indicator : 0x%04x\n",p->transport_error_indicator);
+ info("Payload unit start indicator : 0x%04x\n",p->payload_unit_start_indicator);
+ info("Transport priority : 0x%04x\n",p->transport_priority);
+ info("PID : 0x%04x\n",p->pid);
+ info("Transport scrambling control : 0x%04x\n",p->transport_scrambling_control);
+ info("Adaptation field control : 0x%04x\n",p->adaptation_field_control);
+ info("Continuity_counter : 0x%04x\n",p->continuity_counter);
+
+}
+//-----------------------------------------------------------------------------------
+void print_pmt(pmt_t *p)
+{
+ info("--------------------------------------------------------------\n");
+ info("PMT section:\n");
+ info("Table ID : %-5d (0x%04x)\n",p->table_id,p->table_id);
+ info("(fixed): : %-5d (0x%04x)\n",0,0);
+ info("Section syntax indicator : %-5d (0x%04x)\n",p->section_syntax_indicator,p->section_syntax_indicator);
+ info("Reserved 1 : %-5d (0x%04x)\n",p->reserved_1,p->reserved_1);
+ info("Section length : %-5d (0x%04x)\n",p->section_length,p->section_length);
+ info("Program number : %-5d (0x%04x)\n",p->program_number,p->program_number);
+ info("Reserved 2 : %-5d (0x%04x)\n",p->reserved_2,p->reserved_2);
+ info("Version number : %-5d (0x%04x)\n",p->version_number,p->version_number);
+ info("Current next indicator : %-5d (0x%04x)\n",p->current_next_indicator,p->current_next_indicator);
+ info("Section number : %-5d (0x%04x)\n",p->section_number,p->section_number);
+ info("Last section number : %-5d (0x%04x)\n",p->last_section_number,p->last_section_number);
+ info("Reserved 3 : %-5d (0x%04x)\n",p->reserved_3,p->reserved_3);
+ info("PCR pid : %-5d (0x%04x)\n",p->pcr_pid,p->pcr_pid);
+ info("Reserved 4 : %-5d (0x%04x)\n",p->reserved_4,p->reserved_4);
+ info("Program info length : %-5d (0x%04x)\n",p->program_info_length,p->program_info_length);
+
+
+
+ info("CRC32 : 0x%04x\n",p->crc32);
+}
+//-----------------------------------------------------------------------------------
+void print_pat(pat_t *p, pat_list_t *pl, int pmt_num)
+{
+ info("--------------------------------------------------------------\n");
+ info("PAT section:\n");
+ info("Table_id : %-5d (0x%04x)\n",p->table_id,p->table_id);
+ info("(fixed): : %-5d (0x%04x)\n",0,0);
+ info("Section syntax indicator : %-5d (0x%04x)\n",p->section_syntax_indicator,p->section_syntax_indicator);
+ info("Reserved_1 : %-5d (0x%04x)\n",p->reserved_1,p->reserved_1);
+ info("Section length : %-5d (0x%04x)\n",p->section_length,p->section_length);
+ info("Transport stream id : %-5d (0x%04x)\n",p->transport_stream_id,p->transport_stream_id);
+ info("Reserved 2 : %-5d (0x%04x)\n",p->reserved_2,p->reserved_2);
+ info("Version number : %-5d (0x%04x)\n",p->version_number,p->version_number);
+ info("Current next indicator : %-5d (0x%04x)\n",p->current_next_indicator,p->current_next_indicator);
+ info("Section number : %-5d (0x%04x)\n",p->section_number,p->section_number);
+ info("Last section number : %-5d (0x%04x)\n",p->last_section_number,p->last_section_number);
+
+ if (pl && pmt_num){
+ int i;
+ info("Number of PMTs in PAT : %-5d \n", pmt_num);
+ for(i=0;i<pmt_num;i++) {
+ pat_list_t *pat = pl + i;
+ info("\nProgram number : %-5d (0x%04x)\n",pat->program_number,pat->program_number);
+ info("Reserved : %-5d (0x%04x)\n",pat->reserved,pat->reserved);
+ info("Network PMT PID : %-5d (0x%04x)\n",pat->network_pmt_pid,pat->network_pmt_pid);
+ }
+ }
+
+ info("CRC32 : 0x%04x\n",p->crc32);
+
+
+}
+//-----------------------------------------------------------------------------------
+char *si_caid_to_name(unsigned int caid)
+{
+
+ str_table table[] = {
+ // -- updated from dvb.org 2003-10-16
+ { 0x0000, 0x0000, "Reserved" },
+ { 0x0001, 0x00FF, "Standardized Systems" },
+ { 0x0100, 0x01FF, "Canal Plus (Seca/MediaGuard)" },
+ { 0x0200, 0x02FF, "CCETT" },
+ { 0x0300, 0x03FF, "MSG MediaServices GmbH" },
+ { 0x0400, 0x04FF, "Eurodec" },
+ { 0x0500, 0x05FF, "France Telecom (Viaccess)" },
+ { 0x0600, 0x06FF, "Irdeto" },
+ { 0x0700, 0x07FF, "Jerrold/GI/Motorola" },
+ { 0x0800, 0x08FF, "Matra Communication" },
+ { 0x0900, 0x09FF, "News Datacom (Videoguard)" },
+ { 0x0A00, 0x0AFF, "Nokia" },
+ { 0x0B00, 0x0BFF, "Norwegian Telekom (Conax)" },
+ { 0x0C00, 0x0CFF, "NTL" },
+ { 0x0D00, 0x0DFF, "Philips (Cryptoworks)" },
+ { 0x0E00, 0x0EFF, "Scientific Atlanta (Power VU)" },
+ { 0x0F00, 0x0FFF, "Sony" },
+ { 0x1000, 0x10FF, "Tandberg Television" },
+ { 0x1100, 0x11FF, "Thompson" },
+ { 0x1200, 0x12FF, "TV/COM" },
+ { 0x1300, 0x13FF, "HPT - Croatian Post and Telecommunications" },
+ { 0x1400, 0x14FF, "HRT - Croatian Radio and Television" },
+ { 0x1500, 0x15FF, "IBM" },
+ { 0x1600, 0x16FF, "Nera" },
+ { 0x1700, 0x17FF, "Beta Technik (Betacrypt)" },
+ { 0x1800, 0x18FF, "Kudelski SA"},
+ { 0x1900, 0x19FF, "Titan Information Systems"},
+ { 0x2000, 0x20FF, "TelefXnica Servicios Audiovisuales"},
+ { 0x2100, 0x21FF, "STENTOR (France Telecom, CNES and DGA)"},
+ { 0x2200, 0x22FF, "Scopus Network Technologies"},
+ { 0x2300, 0x23FF, "BARCO AS"},
+ { 0x2400, 0x24FF, "StarGuide Digital Networks "},
+ { 0x2500, 0x25FF, "Mentor Data System, Inc."},
+ { 0x2600, 0x26FF, "European Broadcasting Union"},
+ { 0x4700, 0x47FF, "General Instrument"},
+ { 0x4800, 0x48FF, "Telemann"},
+ { 0x4900, 0x49FF, "Digital TV Industry Alliance of China"},
+ { 0x4A00, 0x4A0F, "Tsinghua TongFang"},
+ { 0x4A10, 0x4A1F, "Easycas"},
+ { 0x4A20, 0x4A2F, "AlphaCrypt"},
+ { 0x4A30, 0x4A3F, "DVN Holdings"},
+ { 0x4A40, 0x4A4F, "Shanghai Advanced Digital Technology Co. Ltd. (ADT)"},
+ { 0x4A50, 0x4A5F, "Shenzhen Kingsky Company (China) Ltd"},
+ { 0x4A60, 0x4A6F, "@SKY"},
+ { 0x4A70, 0x4A7F, "DreamCrypt"},
+ { 0x4A80, 0x4A8F, "THALESCrypt"},
+ { 0x4A90, 0x4A9F, "Runcom Technologies"},
+ { 0x4AA0, 0x4AAF, "SIDSA"},
+ { 0x4AB0, 0x4ABF, "Beijing Comunicate Technology Inc."},
+ { 0x4AC0, 0x4ACF, "Latens Systems Ltd"},
+ { 0,0, NULL }
+ };
+
+ int i = 0;
+ while (table[i].str) {
+ if (table[i].from <= caid && table[i].to >= caid)
+ return (char *) table[i].str;
+ i++;
+ }
+
+ return (char *) "ERROR: Undefined!";
+}
+//-----------------------------------------------------------------------------------
+void get_time_mjd (unsigned long mjd, long *year , long *month, long *day)
+{
+ if (mjd > 0) {
+ long y,m,d ,k;
+
+ // algo: ETSI EN 300 468 - ANNEX C
+
+ y = (long) ((mjd - 15078.2) / 365.25);
+ m = (long) ((mjd - 14956.1 - (long)(y * 365.25) ) / 30.6001);
+ d = (long) (mjd - 14956 - (long)(y * 365.25) - (long)(m * 30.6001));
+ k = (m == 14 || m == 15) ? 1 : 0;
+ y = y + k + 1900;
+ m = m - 1 - k*12;
+ *year = y;
+ *month = m;
+ *day = d;
+
+ } else {
+ *year = 0;
+ *month = 0;
+ *day = 0;
+ }
+
+}
+//-----------------------------------------------------------------------------------
+void print_tdt(tdt_sect_t *tdt, uint16_t mjd, uint32_t utc)
+{
+ info("--------------------------------------------------------------\n");
+ info("TDT section:\n");
+ info("Table_id : %-5d (0x%04x)\n",tdt->table_id,tdt->table_id);
+ info("Reserved : %-5d (0x%04x)\n",tdt->reserved,tdt->reserved);
+ info("Reserved_1 : %-5d (0x%04x)\n",tdt->reserved_1,tdt->reserved_1);
+ info("Section length : %-5d (0x%04x)\n",tdt->section_length,tdt->section_length);
+ info("UTC_time : 0x%2x%2x%2x%2x%2x\n",tdt->dvbdate[0],tdt->dvbdate[1],tdt->dvbdate[2],tdt->dvbdate[3],tdt->dvbdate[4]);
+
+ long y,m,d;
+ get_time_mjd(mjd, &y, &m, &d);
+ info("TIME: [= %02ld-%02ld-%02ld %02x:%02x:%02x (UTC) ]\n\n",y,m,d,(utc>>16) &0xFF, (utc>>8) &0xFF, (utc) &0xFF);
+ info("--------------------------------------------------------------\n");
+
+}
+//-----------------------------------------------------------------------------------
+void print_ca_desc(si_desc_t *p)
+{
+ info("CA desc. tag : %d (%#x)\n",p->descriptor_tag,p->descriptor_tag);
+ info("CA desc. length : %d (%#x)\n",p->descriptor_length,p->descriptor_length);
+ info("CA system id : %d (%#x)\n",p->ca_system_id,p->ca_system_id);
+ info("Reserverd : %d (%#x)\n",p->reserved,p->reserved);
+ info("CA pid : %d (%#x)\n",p->ca_pid,p->ca_pid);
+
+ printhex_buf((char *)"Private data",p->private_data,p->descriptor_length-4);
+
+}
+//-----------------------------------------------------------------------------------
+void print_ca_bytes(si_desc_t *p)
+{
+ unsigned int i;
+ info("%x %x %x %x %x ",p->descriptor_tag, p->descriptor_length, p->ca_system_id, p->reserved, p->ca_pid);
+ for (i = 0; i < p->descriptor_length - 4; i++)
+ info("%x ",p->private_data[i]);
+ info(";");
+
+}
+//-----------------------------------------------------------------------------------
+void print_cad_lst(si_cad_t *l, int ts_id)
+{
+ int i;
+
+ for (i = 0; i < l->cads; i++) {
+ print_ca_desc(&l->cad[i]);
+ }
+ info("Total CA desc. for TS ID %d : %d\n",ts_id,l->cads);
+}
+//-----------------------------------------------------------------------------------
+int parse_ca_descriptor(unsigned char *desc, si_desc_t *t)
+{
+ unsigned char *ptr=desc;
+ int tag=0,len=0;
+
+ tag=ptr[0];
+ len=ptr[1];
+
+ if (len > MAX_DESC_LEN) {
+ info("descriptor():Descriptor too long !\n");
+ return -1;
+ }
+
+ switch(tag){
+ case 0x09: {
+ t->descriptor_tag=tag;
+ t->descriptor_length=len; //???
+ t->ca_system_id=((ptr[2] << 8) | ptr[3]);
+ t->reserved=(ptr[4] >> 5) & 7;
+ t->ca_pid=((ptr[4] << 8) | ptr[5]) & 0x1fff;
+ //header 4 bytes + 2 bytes
+ memcpy(t->private_data,ptr+6,len-4);
+
+ //print_ca_desc(t);
+
+ break;
+ }
+ default:
+ break;
+ }
+
+ return len + 2; //2 bytes tag + length
+}
+//--------------------------------------------------------------------------------------------
+int ca_free_cpl_desc(ca_pmt_list_t *cpl)
+{
+ if (cpl->pm.size > 0 && cpl->pm.cad)
+ free(cpl->pm.cad);
+ if (cpl->es.size > 0 && cpl->es.cad)
+ free(cpl->es.cad);
+
+ memset(cpl,0,sizeof(ca_pmt_list_t));
+
+ return 0;
+}
+//--------------------------------------------------------------------------------------------
+int descriptor(unsigned char *desc, si_cad_t *c)
+{
+ unsigned char *ptr=desc;
+ int tag=0,len=0;
+
+ tag=ptr[0];
+ len=ptr[1];
+
+ if (len > MAX_DESC_LEN) {
+ info("descriptor():Descriptor too long !\n");
+ return -1;
+ }
+
+ switch(tag){
+ case 0x09: {
+ c->cads++;
+ c->cad = (si_desc_t*)realloc(c->cad,sizeof(si_desc_t)*c->cads);
+ if (!c->cad) {
+ c->cads--;
+ info("descriptor():realloc error\n");
+ return -1;
+ }
+ si_desc_t *t = c->cad + c->cads - 1;
+ t->descriptor_tag=tag;
+ t->descriptor_length=len; //???
+ t->ca_system_id=((ptr[2] << 8) | ptr[3]);
+ t->reserved=(ptr[4] >> 5) & 7;
+ t->ca_pid=((ptr[4] << 8) | ptr[5]) & 0x1fff;
+ //header 4 bytes + 2 bytes
+ if (len - 4 > 0)
+ memcpy(t->private_data,ptr+6,len-4);
+
+ //print_ca_desc(t);
+ break;
+ }
+ default: {
+#if 0
+ other_desc_t d;
+ d.descriptor_tag=tag;
+ d.descriptor_length=len;
+ memcpy(d.data,ptr+2,len);
+ //print_desc(d);
+#endif
+ }
+ }
+
+ return len + 2; //2 bytes tag + length
+}
+
+//-----------------------------------------------------------------------------------
+int si_get_video_pid(unsigned char *esi_buf, int size, int *vpid)
+{
+ int index, pid_num, es_len;
+ unsigned char *ptr = esi_buf;
+
+ index = pid_num = 0;
+ while(index < size) {
+ //ptr[0] //stream type
+ if (ptr[0] == 2 || ptr[0] == 0x1b)
+ {
+ *vpid = ((ptr[1] << 8) | ptr[2]) & 0x1fff;
+ return 1;
+ }
+ es_len = ((ptr[3] << 8) | ptr[4]) & 0x0fff;
+ index += 5 + es_len;
+ ptr += 5 + es_len;
+ }
+
+ *vpid = -1;
+ return 0;
+
+}
+//-----------------------------------------------------------------------------------
+int si_get_audio_pid(unsigned char *esi_buf, int size, int *apid)
+{
+ int index, pid_num, es_len;
+ unsigned char *ptr = esi_buf;
+
+ index = pid_num = 0;
+ while(index < size) {
+ //ptr[0] //stream type
+ if (ptr[0] == 0x1 || ptr[0] == 0x3 || ptr[0] == 0x4)
+ {
+ *apid = ((ptr[1] << 8) | ptr[2]) & 0x1fff;
+ return 1;
+ }
+ es_len = ((ptr[3] << 8) | ptr[4]) & 0x0fff;
+ index += 5 + es_len;
+ ptr += 5 + es_len;
+ }
+
+ *apid = -1;
+ return 0;
+
+}
+//-----------------------------------------------------------------------------------
+int si_get_private_pids(unsigned char *esi_buf, int size, int *upids)
+{
+
+ int index, pid_num, es_len;
+ unsigned char *ptr = esi_buf;
+
+ index = pid_num = 0;
+ while(index < size) {
+ if (ptr[0] == 0x6)
+ {
+ upids[pid_num] = ((ptr[1] << 8) | ptr[2]) & 0x1fff;
+ pid_num++;
+ if (pid_num >= MAX_ES_PIDS) {
+ info ("error: ES pids number out of bounds !\n");
+ return -1;
+ }
+ }
+ es_len = ((ptr[3] << 8) | ptr[4]) & 0x0fff;
+ index += 5 + es_len;
+ ptr += 5 + es_len;
+ }
+
+ return pid_num;
+
+}
+//-----------------------------------------------------------------------------------
+int get_pmt_es_pids(unsigned char *esi_buf, int size, int *es_pids, int all)
+{
+ int index, pid_num, es_len;
+ unsigned char *ptr = esi_buf;
+
+ index = pid_num = 0;
+ while(index < size) {
+ //ptr[0] //stream type
+ //int pid = ((ptr[1] << 8) | ptr[2]) & 0x1fff;
+ //printf("Stream type: %d (%#x) pid = %d (%#x)\n",ptr[0], ptr[0], pid, pid);
+ if (ptr[0] == 0x1 || ptr[0] == 0x2 || ptr[0] == 0x3 || ptr[0] == 0x4 || ptr[0] == 0x6 || ptr[0] == 0x1b || all)
+ {
+ es_pids[pid_num] = ((ptr[1] << 8) | ptr[2]) & 0x1fff;
+ pid_num++;
+ if (pid_num >= MAX_ES_PIDS) {
+ info ("error: ES pids number out of bounds !\n");
+ return -1;
+ }
+ }
+ es_len = ((ptr[3] << 8) | ptr[4]) & 0x0fff;
+ index += 5 + es_len;
+ ptr += 5 + es_len;
+ }
+
+ return pid_num;
+}
+//-----------------------------------------------------------------------------------
+int parse_pmt_ca_desc(unsigned char *buf, int size, int sid, si_ca_pmt_t *pm_cads, si_ca_pmt_t *es_cads, pmt_t *pmt_hdr, int *fta, ca_es_pid_info_t *espids, int *es_pid_num)
+{
+ unsigned char *ptr=buf, tmp[PSI_BUF_SIZE]; //sections can be only 12 bit long
+
+ memset(pm_cads,0,sizeof(si_ca_pmt_t));
+ memset(es_cads,0,sizeof(si_ca_pmt_t));
+ memset(pmt_hdr,0,sizeof(pmt_hdr));
+
+ pmt_hdr->table_id=ptr[0];
+ pmt_hdr->section_syntax_indicator=(ptr[1] >> 7) & 1;
+ pmt_hdr->reserved_1=(ptr[1] >> 4) & 3;
+ pmt_hdr->section_length=((ptr[1] << 8) | ptr[2]) & 0xfff;
+
+ if (pmt_hdr->section_length < 13 || pmt_hdr->section_length > 1021 || (int)pmt_hdr->section_length > size) {
+ info("#####\nERROR: Invalid section length!\n");
+ return -1;
+ }
+
+ u_long crc = dvb_crc32 ((char *)buf,pmt_hdr->section_length+3);
+
+#ifdef DBG
+ info("CRCcc: 0x%lx\n",crc);
+ info("len = %d\n", pmt_hdr->section_length+3);
+#endif
+ if (crc & 0xffffffff) { //FIXME: makr arch flags
+ info("#####\nPMT -> ERROR: parse_pmt_ca_desc() : CRC err. crc = 0x%lx\n", crc);
+ return -1;
+ }
+
+ pmt_hdr->program_number=(ptr[3] << 8) | ptr[4];
+ if ((int)pmt_hdr->program_number != sid) {
+ info("#####\nERROR: Invalid SID in PMT !!!\n");
+ return -1;
+ }
+ pmt_hdr->program_info_length=((ptr[10] << 8) | ptr[11]) & 0x0fff;
+ if (pmt_hdr->program_info_length < 0 || pmt_hdr->program_info_length > 1021 - 9 || (int)pmt_hdr->program_info_length > size - 9) {
+ info("#####\nERROR: Invalid PI length in PMT!\n");
+ return -1;
+ }
+
+ pmt_hdr->reserved_2=(ptr[5] >> 6) & 3;
+ pmt_hdr->version_number=(ptr[5] >> 1) & 0x1f;
+ pmt_hdr->current_next_indicator=ptr[5] & 1;
+ pmt_hdr->section_number=ptr[6];
+ pmt_hdr->last_section_number=ptr[7];
+ pmt_hdr->reserved_3=(ptr[8] >> 5) & 7;
+ pmt_hdr->pcr_pid=((ptr[8] << 8) | ptr[9]) & 0x1fff;
+ pmt_hdr->reserved_4=(ptr[10] >> 4) & 0xf;
+
+ //pmt_hdr->program_info_length=((ptr[10] << 8) | ptr[11]) & 0x0fff;
+ //print_pmt(pmt_hdr);
+
+ int buf_len=0,len=0;
+ unsigned int i=0;
+
+ buf_len = pmt_hdr->section_length - 9;
+ ptr += 12; // 12 byte header
+
+ pm_cads->size = pm_cads->cads = 0;
+ for (i = 0; i < pmt_hdr->program_info_length;) {
+ int dtag = ptr[0];
+ int dlen = ptr[1] + 2;
+ if (dlen > size || dlen > MAX_DESC_LEN) {
+ info("PMT: Invalide CA desc. length!\n");
+ return -1;
+ }
+ if (dtag == 0x09) { //we have CA descriptor
+ memcpy(tmp + pm_cads->size, ptr, dlen);
+ pm_cads->size+=dlen;
+ pm_cads->cads++;
+ *fta=0;
+ }
+ i+=dlen;
+ if (i > pmt_hdr->program_info_length) {
+ info("PMT: Index out of bounds!\n");
+ return -1;
+ }
+
+ ptr+=dlen; //desc. length plus 2 bytes for tag and header;
+ if (ptr >= buf + size) {
+ info("PMT: Invalid Buffer offset !\n");
+ return -1;
+ }
+
+ buf_len-=dlen;
+ if (buf_len < 0) {
+ info("PMT: Index out of bounds!\n");
+ return -1;
+
+ }
+ }
+
+ //parsing ok we can take this program level descriptors
+ if (pm_cads->size && pm_cads->cads) {
+ pm_cads->cad = (unsigned char*)malloc(sizeof(unsigned char)*pm_cads->size);
+ if (!pm_cads->cad) {
+ info("ERROR: parse_ca_desc() : out of memory\n");
+ return -1;
+ }
+ memcpy(pm_cads->cad, tmp, pm_cads->size);
+ }
+
+#ifdef DBG
+ info("%d bytes remaining (program info len = %d bytes)\n",buf_len,i);
+#endif
+
+ int err = 0;
+ es_pmt_info_t esi;
+ es_cads->size = es_cads->cads = 0;
+ *es_pid_num = 0;
+ while (buf_len > 4) { //end of section crc32 is 4 bytes
+ esi.stream_type=ptr[0];
+ esi.reserved_1=(ptr[1] >> 5) & 7;
+ esi.elementary_pid=((ptr[1] << 8) | ptr[2]) & 0x1fff;
+ esi.reserved_2=(ptr[3] >> 4) & 0xf;
+ esi.es_info_length=((ptr[3] << 8) | ptr[4]) & 0x0fff;
+
+ if ((int)esi.es_info_length > buf_len) {
+ info("PMT: Invalid ES info length !\n");
+ err = -1;
+ break;
+ }
+
+ if (espids) {
+ switch(esi.stream_type) {
+ case VIDEO_11172_STREAM_TYPE:
+ case VIDEO_13818_STREAM_TYPE:
+ case VISUAL_MPEG4_STREAM_TYPE:
+ case VIDEO_H264_STREAM_TYPE:
+ case AUDIO_11172_STREAM_TYPE:
+ case AUDIO_13818_STREAM_TYPE:
+ espids[*es_pid_num].pid = esi.elementary_pid;
+ espids[*es_pid_num].type = esi.stream_type;
+ break;
+ default:
+ espids[*es_pid_num].pid = esi.elementary_pid;
+ espids[*es_pid_num].type = 0;
+
+ }
+ }
+ memcpy(tmp + es_cads->size, ptr, 5);
+ tmp[es_cads->size+1] &= 0x1f; //remove reserved value ???
+ tmp[es_cads->size+3] &= 0x0f; //remove reserved value ???
+
+ int es_info_len_pos = es_cads->size+3; //mark length position to set it later
+ int cur_len = 0; //current ES stream descriptor length
+
+ es_cads->size += 5;
+ ptr += 5;
+ buf_len -= 5;
+ len=esi.es_info_length;
+ while(len > 0) {
+ int dtag = ptr[0];
+ int dlen = ptr[1] + 2; //2 bytes for tag and len
+
+ if (dlen > len || dlen > MAX_DESC_LEN) {
+ info("PMT: Invalide CA desc. length!\n");
+ err = -1;
+ break;
+ }
+
+ if (dtag == 0x09) { //we have CA descriptor
+ memcpy(tmp + es_cads->size, ptr, dlen);
+ es_cads->size += dlen;
+ es_cads->cads++;
+ cur_len += dlen;
+ *fta=0;
+ }
+ if (espids) {
+ if (espids[*es_pid_num].type == 0) {
+ switch(dtag) {
+ case TeletextDescriptorTag:
+ case SubtitlingDescriptorTag:
+ case AC3DescriptorTag:
+ case EnhancedAC3DescriptorTag:
+ case DTSDescriptorTag:
+ case AACDescriptorTag:
+ espids[*es_pid_num].type = dtag;
+ //go to next pid
+ }
+ }
+ }
+
+ ptr += dlen;
+ if (ptr >= buf + size) {
+ info("PMT: Invalid Buffer offset !\n");
+ err = -1;
+ break;
+ }
+
+ len -= dlen;
+ buf_len -= dlen;
+ }
+ if (err == -1) {
+ break;
+ }
+ tmp[es_info_len_pos] = (cur_len >> 8) & 0xff;
+ tmp[es_info_len_pos+1] = cur_len & 0xff;
+ if (espids) {
+ if (espids[*es_pid_num].type) {
+ //go to next pid
+ (*es_pid_num)++;
+ if (*es_pid_num >= MAX_ES_PIDS) {
+ info ("ERROR: ES pids array index out bounds (pids %d sid %d)!\n", *es_pid_num, pmt_hdr->program_number);
+ break;
+ }
+ }
+ }
+ }
+
+ //parsing ok we can take this ES level descriptors
+ if (((es_cads->cads && es_cads->size) || (pm_cads->cads && es_cads->size)) || *fta) { //take ES stream info if we have PM or ES desc.
+ es_cads->cad = (unsigned char*)malloc(sizeof(unsigned char)*es_cads->size);
+ if (!es_cads->cad) {
+ info("ERROR: parse_ca_desc() : out of memory\n");
+ if (pm_cads->cad)
+ free(pm_cads->cad);
+ return -1;
+ }
+ memcpy(es_cads->cad, tmp, es_cads->size);
+
+ }
+
+#ifdef DBG
+ info("%d bytes remaining\n",buf_len);
+#endif
+
+ pmt_hdr->crc32=(ptr[0] << 24) | (ptr[1] << 16) | (ptr[2] << 8) | ptr[3];
+
+ if (len < 0 || err == -1) {
+ info("ERROR: parse_ca_desc() : section index out of bounds %d or (CRC err.) crc in sec. = 0x%x crc calc. = 0x%lx\n", buf_len,pmt_hdr->crc32, crc);
+#ifdef DBG
+ print_pmt(&pmt_hdr);
+#endif
+ //cleanup ...
+ if (pm_cads->cad)
+ free(pm_cads->cad);
+ if (es_cads->cad)
+ free(es_cads->cad);
+ *es_pid_num = 0;
+ memset(pm_cads,0,sizeof(si_ca_pmt_t));
+ memset(es_cads,0,sizeof(si_ca_pmt_t));
+ return -1;
+ }
+
+#ifdef DBG
+ info("#####################################\n");
+ info("parse_ca_desc(): section parsed: OK !\n");
+#endif
+ return 0;
+}
+//-----------------------------------------------------------------------------------
+int parse_cat_sect(unsigned char *buf, int size, si_cad_t *emm)
+{
+ unsigned char *ptr=buf;
+ int len,i,ret;
+ cat_t c;
+
+ c.table_id = ptr[0];
+ c.section_syntax_indicator = (ptr[1] >> 7) & 1;
+ c.reserved_1 = (ptr[1] >> 4) & 3;
+ c.section_length = ((ptr[1] << 8) | ptr[2]) & 0xfff;
+
+ if (c.section_length < 9 || c.section_length > 1021 || (int)c.section_length > size) {
+ info("CAT: Invalid section length!\n");
+ return -1;
+ }
+
+#ifdef CRC32_CHECK
+ u_long crc = dvb_crc32 ((char *)buf,c.section_length+3);
+#ifdef DBG
+ info("CRCcc: 0x%lx\n",crc);
+#endif
+ if (crc & 0xffffffff) {
+ info("CAT:CRC32 error (0x%lx)!\n",crc);
+ return -1;
+ }
+#endif
+
+ c.reserved_2 = (ptr[3] << 10) | (ptr[4] << 2) | ((ptr[5] >> 6) & 3);
+ c.version_number = (ptr[5] >> 1) & 0x1f;
+ c.current_next_indicator = ptr[5] & 1;
+ c.section_number = ptr[6];
+ c.last_section_number = ptr[7];
+
+
+ //do desc. here
+ len = c.section_length - 5;
+ ptr+=8; //go after hdr.
+
+ i = len;
+ while(i > 4) { //crc32 4 bytes
+ ret = descriptor(ptr, emm);
+ if (ret < 0) {
+ info ("cannot parse CA descriptor in CAT !\n");
+ return -1;
+ }
+ i-=ret;
+ ptr+=ret;
+ if (ptr >= buf + size) {
+ info("CAT: Invalid Buffer offset !\n");
+ break;
+ }
+ }
+ if (i != 4) {
+ info("CAT: index out of bounds !\n");
+ return -1;
+ }
+#ifdef DBG
+ info("%d bytes remaining (program info len = %d bytes)\n",len-i,len);
+#endif
+ c.crc32 = (ptr[0] << 24) | (ptr[1] << 16) | (ptr[2] << 8) | ptr[3];
+
+
+ return 0;
+}
+//-----------------------------------------------------------------------------------
+int parse_pat_sect(unsigned char *buf, int size, pmt_pid_list_t *pmt)
+{
+ unsigned char *ptr=buf;
+ pat_t p;
+ pat_list_t *pat_info = NULL;
+
+ memset(&p,0,sizeof(p));
+
+ p.table_id=ptr[0];
+ p.section_syntax_indicator=(ptr[1] & 0x80) >> 7;
+ p.reserved_1=(ptr[1] & 0x30) >> 4;
+ p.section_length=((ptr[1] << 8) | ptr[2]) & 0x0fff;
+
+ if (p.section_length < 9 || p.section_length > 1021 || (int)p.section_length > size) {
+ info("PAT: Invalid section length !\n");
+ return -1;
+
+ }
+
+#ifdef CRC32_CHECK
+ u_long crc = dvb_crc32 ((char *)buf,p.section_length+3);
+ //FIXME: is it the right way ?
+ if (crc & 0xffffffff) {
+ info("PAT:CRC32 error (0x%lx)!\n",crc);
+ return -1;
+ }
+#endif
+
+ p.transport_stream_id=(ptr[3] << 8) | ptr[4];
+ p.reserved_2=(ptr[5] & 0xc0) >> 6;
+ p.version_number=(ptr[5] & 0x3e) >> 1;
+ p.current_next_indicator=(ptr[5] & 1);
+ p.section_number=ptr[6];
+ p.last_section_number=ptr[7];
+
+ int n,i,pmt_num;
+
+ n = p.section_length - 5 - 4; //bytes following section_length field + crc32 chk_sum
+
+ ptr+=8;
+ pmt_num=0;
+ if (n > 0 && ((ptr + n) < (buf + size))) {
+ pat_info=(pat_list_t *)malloc(sizeof(pat_list_t)*n/4);
+ if (!pat_info) {
+ info ("PAT: out of memory\n");
+ return -1;
+ }
+ for(i=0;i<n;i+=4) {
+ pat_list_t *pat = pat_info + pmt_num;
+ pat->program_number=(ptr[0] << 8) | (ptr[1]);
+ pat->reserved=(ptr[2] & 0xe0) >> 5;
+ pat->network_pmt_pid=((ptr[2] << 8) | ptr[3]) & 0x1fff;
+ if (pat->network_pmt_pid != 0x10) { //NIT => FIXME: remove other known pids
+ // memset(&pat->desc,0,sizeof(pmt_desc_list_t));
+ pmt_num++;
+ }
+ ptr+=4;
+ }
+
+ p.crc32=(ptr[0] << 24) | (ptr[1] << 16) | (ptr[2] << 8) | ptr[3];
+ if (n != pmt_num)
+ pat_info=(pat_list_t *)realloc(pat_info,sizeof(pat_list_t)*pmt_num);
+ if (!pat_info) {
+ info("parse_pat_sect():realloc error\n");
+ return -1;
+ }
+ }
+ if (pmt) {
+ pmt->p=p;
+ pmt->pl=pat_info;
+ pmt->pmt_pids=pmt_num;
+ }
+
+ return 0;
+}
+int parse_tdt_sect(unsigned char *buf, int size, tdt_sect_t *tdt)
+{
+ unsigned char *ptr = buf;
+
+ tdt->table_id=ptr[0];
+ tdt->section_syntax_indicator=(ptr[1] & 0x80) >> 7;
+ tdt->reserved_1=(ptr[1] >> 4) >> 3;
+ tdt->section_length=((ptr[1] << 8) | ptr[2]) & 0x0fff;
+
+ if (tdt->section_length != 5) {
+ info("TDT: Invalid section length !\n");
+ return -1;
+ }
+
+ //copy UTC time MJD + UTC
+ memcpy(tdt->dvbdate, ptr + 3, 5);
+
+ return 0;
+
+}
+//-----------------------------------------------------------------------------------
+//TS packets handling
+int get_ts_packet_hdr(unsigned char *buf, ts_packet_hdr_t *p)
+{
+ unsigned char *ptr=buf;
+
+ memset(p,0,sizeof(p));
+
+ p->sync_byte=ptr[0];
+ p->transport_error_indicator=(ptr[1] & 0x80) >> 7;
+ p->payload_unit_start_indicator=(ptr[1] & 0x40) >> 6;
+ p->transport_priority=(ptr[1] & 0x20) >> 5;
+ p->pid=((ptr[1] << 8) | ptr[2]) & 0x1fff;
+ p->transport_scrambling_control=(ptr[3] & 0xC0) >> 6;
+ p->adaptation_field_control=(ptr[3] & 0x30) >> 4;
+ p->continuity_counter=(ptr[3] & 0xf);
+
+#ifdef DBG
+ print_ts_header(p);
+#endif
+
+ return 0;
+
+}
+//-----------------------------------------------------------------------------------
+int ts2psi_data(unsigned char *buf,psi_buf_t *p,int len, int pid_req)
+{
+ unsigned char *b=buf;
+ ts_packet_hdr_t h;
+
+
+ get_ts_packet_hdr(buf,&h);
+
+ b+=4;
+ len-=4;
+
+ if (h.sync_byte != 0x47) {
+#ifdef SERVER
+ sys("%s:No sync byte in header !\n",__FUNCTION__);
+#endif
+ return -1;
+ }
+
+
+ if (pid_req != (int)h.pid) {
+#ifdef DBG
+ info("%s:pids mismatch (pid req = %#x ts pid = %#x )!\n", __FUNCTION__,pid_req, h.pid);
+#endif
+ return -1;
+ }
+
+ //FIXME:Handle adaptation field if present/needed
+ if (h.adaptation_field_control & 0x2) {
+ int n;
+
+ n=b[0]+1;
+ b+=n;
+ len-=n;
+
+ }
+
+ if (h.adaptation_field_control & 0x1) {
+ if (h.transport_error_indicator) {
+#ifdef DBG
+ info("Transport error flag set !\n");
+#endif
+ return -1;
+ }
+ if (h.transport_scrambling_control) {
+#ifdef DBG
+ info("Transport scrambling flag set !\n");
+#endif
+ //return -1;
+ }
+
+ if (h.payload_unit_start_indicator && p->start) { //whole section new begin packet
+#ifdef DBG
+ info("%s:section read !\n",__FUNCTION__);
+#endif
+ return 1;
+ }
+
+ if (h.payload_unit_start_indicator && !p->start) { //packet beginning
+ int si_offset=b[0]+1; //always pointer field in first byte of TS packet payload with start indicator set
+ b+=si_offset;
+ len-=si_offset;
+ if (len < 0 || len > 184) {
+#ifdef DBG
+ info("WARNING 1: TS Packet damaged !\n");
+#endif
+ return -1;
+ }
+ //move to buffer
+ memcpy(p->buf,b,len);
+ p->len=len;
+ p->start=((b[1] << 8) | b[2]) & 0x0fff; //get section length, using start for length
+ p->pid=h.pid;
+ p->continuity=h.continuity_counter;
+
+ }
+
+ if (!h.payload_unit_start_indicator && p->start) { //packet continuation
+ //duplicate packet
+ if ((p->pid == (int)h.pid) && (p->continuity == (int)h.continuity_counter)){
+#ifdef DBG
+ info("Packet duplicate ???\n");
+#endif
+ return -1;
+ }
+ //new packet
+ if (p->pid != (int)h.pid) {
+#ifdef DBG
+ info("New pid buf start %d len %d bytes (pid in buf = %d pid in ts = %d) !\n", p->start,p->len, p->pid, h.pid);
+#endif
+ return -1;
+ }
+ //discontinuity of packets
+ if (((++p->continuity)%16) != (int)h.continuity_counter) {
+#ifdef DBG
+ info("Discontinuity of ts stream !!!\n");
+#endif
+ return -1;
+ }
+ p->continuity=h.continuity_counter;
+ if (len < 0 || len > 184) {
+ info("WARNING 2: TS Packet damaged !\n");
+ return -1;
+ }
+ //move to buffer
+ memcpy(p->buf+p->len,b,len);
+ p->len+=len; //FIXME: circular buffer
+ if (p->len + 188 > PSI_BUF_SIZE) {
+ info("Error: Buffer full !\n");
+ return -1;
+ //FIXME:realloc
+ }
+ }
+ }
+
+#if 1
+ //3 bytes for bytes containing table id and section length
+ TS_SECT_LEN(b);
+ if (slen+3 <= len && h.payload_unit_start_indicator) //len = 188 bytes - 4 bytes ts hdr. - adapt. field bytes - 1 byte offset - offset
+ return 1;
+#else //possible opt.
+ /*if (p->start+3 == len)
+ return 1;*/
+#endif
+
+ return 0;
+}
+//TS packets handling end
+//-----------------------------------------------------------------------------------
+
+
+
diff --git a/mcast/common/.svn/text-base/siparser.h.svn-base b/mcast/common/.svn/text-base/siparser.h.svn-base
new file mode 100644
index 0000000..255ebe0
--- /dev/null
+++ b/mcast/common/.svn/text-base/siparser.h.svn-base
@@ -0,0 +1,369 @@
+#ifndef __SIPARSER_H__
+#define __SIPARSER_H__
+
+#define TS_SECT_LEN(buf) \
+ unsigned char *ptr = buf; \
+ int slen = (((ptr[1] << 8) | ptr[2]) & 0x0fff);
+
+
+#define TS_PACKET_LEN (188) /* TS RDSIZE is fixed !! */
+#define TS_SYNC_BYTE (0x47) /* SyncByte for TS ISO 138181-1 */
+#define TS_BUF_SIZE (256 * 1024) /* default DMX_Buffer Size for TS */
+#define PSI_BUF_SIZE (2 * 4096) /* Section length max. 12 bits */
+#define READ_BUF_SIZE (256*TS_PACKET_LEN) /* min. 2x TS_PACKET_LEN!!! */
+#define BILLION 1000000000L;
+#define MAX_DESC_LEN 255 //descriptor_length field 8-bit ISO/IEC 13818-1
+#define MAX_ES_PIDS 32
+
+
+#define VIDEO_11172_STREAM_TYPE 0x1 // STREAMTYPE_11172_VIDEO
+#define VIDEO_13818_STREAM_TYPE 0x2 // STREAMTYPE_13818_VIDEO
+#define VISUAL_MPEG4_STREAM_TYPE 0x10 // 14496-2 Visual MPEG-4
+#define VIDEO_H264_STREAM_TYPE 0x1b // 14496-10 Video h.264
+#define AUDIO_11172_STREAM_TYPE 0x3 // STREAMTYPE_11172_AUDIO
+#define AUDIO_13818_STREAM_TYPE 0x4 // STREAMTYPE_13818_AUDIO
+#define PRIVATE_13818_STREAM_TYPE 0x5 // STREAMTYPE_13818_PRIVATE
+#define PRIVATE_13818_PES_STREAM_TYPE 0x6 // STREAMTYPE_13818_PES_PRIVATE
+
+enum DescriptorTag {
+ // defined by ISO/IEC 13818-1
+ VideoStreamDescriptorTag = 0x02,
+ AudioStreamDescriptorTag = 0x03,
+ HierarchyDescriptorTag = 0x04,
+ RegistrationDescriptorTag = 0x05,
+ DataStreamAlignmentDescriptorTag = 0x06,
+ TargetBackgroundGridDescriptorTag = 0x07,
+ VideoWindowDescriptorTag = 0x08,
+ CaDescriptorTag = 0x09,
+ ISO639LanguageDescriptorTag = 0x0A,
+ SystemClockDescriptorTag = 0x0B,
+ MultiplexBufferUtilizationDescriptorTag = 0x0C,
+ CopyrightDescriptorTag = 0x0D,
+ MaximumBitrateDescriptorTag = 0x0E,
+ PrivateDataIndicatorDescriptorTag = 0x0F,
+ SmoothingBufferDescriptorTag = 0x10,
+ STDDescriptorTag = 0x11,
+ IBPDescriptorTag = 0x12,
+ // defined by ISO-13818-6 (DSM-CC)
+ CarouselIdentifierDescriptorTag = 0x13,
+ // 0x14 - 0x3F Reserved
+ // defined by ETSI (EN 300 468)
+ NetworkNameDescriptorTag = 0x40,
+ ServiceListDescriptorTag = 0x41,
+ StuffingDescriptorTag = 0x42,
+ SatelliteDeliverySystemDescriptorTag = 0x43,
+ CableDeliverySystemDescriptorTag = 0x44,
+ VBIDataDescriptorTag = 0x45,
+ VBITeletextDescriptorTag = 0x46,
+ BouquetNameDescriptorTag = 0x47,
+ ServiceDescriptorTag = 0x48,
+ CountryAvailabilityDescriptorTag = 0x49,
+ LinkageDescriptorTag = 0x4A,
+ NVODReferenceDescriptorTag = 0x4B,
+ TimeShiftedServiceDescriptorTag = 0x4C,
+ ShortEventDescriptorTag = 0x4D,
+ ExtendedEventDescriptorTag = 0x4E,
+ TimeShiftedEventDescriptorTag = 0x4F,
+ ComponentDescriptorTag = 0x50,
+ MocaicDescriptorTag = 0x51,
+ StreamIdentifierDescriptorTag = 0x52,
+ CaIdentifierDescriptorTag = 0x53,
+ ContentDescriptorTag = 0x54,
+ ParentalRatingDescriptorTag = 0x55,
+ TeletextDescriptorTag = 0x56,
+ TelephoneDescriptorTag = 0x57,
+ LocalTimeOffsetDescriptorTag = 0x58,
+ SubtitlingDescriptorTag = 0x59,
+ TerrestrialDeliverySystemDescriptorTag = 0x5A,
+ MultilingualNetworkNameDescriptorTag = 0x5B,
+ MultilingualBouquetNameDescriptorTag = 0x5C,
+ MultilingualServiceNameDescriptorTag = 0x5D,
+ MultilingualComponentDescriptorTag = 0x5E,
+ PrivateDataSpecifierDescriptorTag = 0x5F,
+ ServiceMoveDescriptorTag = 0x60,
+ ShortSmoothingBufferDescriptorTag = 0x61,
+ FrequencyListDescriptorTag = 0x62,
+ PartialTransportStreamDescriptorTag = 0x63,
+ DataBroadcastDescriptorTag = 0x64,
+ ScramblingDescriptorTag = 0x65,
+ DataBroadcastIdDescriptorTag = 0x66,
+ TransportStreamDescriptorTag = 0x67,
+ DSNGDescriptorTag = 0x68,
+ PDCDescriptorTag = 0x69,
+ AC3DescriptorTag = 0x6A,
+ AncillaryDataDescriptorTag = 0x6B,
+ CellListDescriptorTag = 0x6C,
+ CellFrequencyLinkDescriptorTag = 0x6D,
+ AnnouncementSupportDescriptorTag = 0x6E,
+ ApplicationSignallingDescriptorTag = 0x6F,
+ AdaptationFieldDataDescriptorTag = 0x70,
+ ServiceIdentifierDescriptorTag = 0x71,
+ ServiceAvailabilityDescriptorTag = 0x72,
+ // defined by ETSI (EN 300 468) v 1.7.1
+ DefaultAuthorityDescriptorTag = 0x73,
+ RelatedContentDescriptorTag = 0x74,
+ TVAIdDescriptorTag = 0x75,
+ ContentIdentifierDescriptorTag = 0x76,
+ TimeSliceFecIdentifierDescriptorTag = 0x77,
+ ECMRepetitionRateDescriptorTag = 0x78,
+ S2SatelliteDeliverySystemDescriptorTag = 0x79,
+ EnhancedAC3DescriptorTag = 0x7A,
+ DTSDescriptorTag = 0x7B,
+ AACDescriptorTag = 0x7C,
+ ExtensionDescriptorTag = 0x7F,
+
+ // Defined by ETSI TS 102 812 (MHP)
+ // They once again start with 0x00 (see page 234, MHP specification)
+ MHP_ApplicationDescriptorTag = 0x00,
+ MHP_ApplicationNameDescriptorTag = 0x01,
+ MHP_TransportProtocolDescriptorTag = 0x02,
+ MHP_DVBJApplicationDescriptorTag = 0x03,
+ MHP_DVBJApplicationLocationDescriptorTag = 0x04,
+ // 0x05 - 0x0A is unimplemented this library
+ MHP_ExternalApplicationAuthorisationDescriptorTag = 0x05,
+ MHP_IPv4RoutingDescriptorTag = 0x06,
+ MHP_IPv6RoutingDescriptorTag = 0x07,
+ MHP_DVBHTMLApplicationDescriptorTag = 0x08,
+ MHP_DVBHTMLApplicationLocationDescriptorTag = 0x09,
+ MHP_DVBHTMLApplicationBoundaryDescriptorTag = 0x0A,
+ MHP_ApplicationIconsDescriptorTag = 0x0B,
+ MHP_PrefetchDescriptorTag = 0x0C,
+ MHP_DelegatedApplicationDescriptorTag = 0x0E,
+ MHP_ApplicationStorageDescriptorTag = 0x10,
+ // Premiere private Descriptor Tags
+ PremiereContentTransmissionDescriptorTag = 0xF2,
+
+ //a descriptor currently unimplemented in this library
+ //the actual value 0xFF is "forbidden" according to the spec.
+ UnimplementedDescriptorTag = 0xFF
+};
+
+
+
+typedef struct ts_packet_hdr
+{
+ unsigned int sync_byte;
+ unsigned int transport_error_indicator;
+ unsigned int payload_unit_start_indicator;
+ unsigned int transport_priority;
+ unsigned int pid;
+ unsigned int transport_scrambling_control;
+ unsigned int adaptation_field_control;
+ unsigned int continuity_counter;
+} ts_packet_hdr_t;
+
+typedef struct pat {
+ unsigned int table_id;
+ unsigned int section_syntax_indicator;
+ unsigned int reserved_1;
+ unsigned int section_length;
+ unsigned int transport_stream_id;
+ unsigned int reserved_2;
+ unsigned int version_number;
+ unsigned int current_next_indicator;
+ unsigned int section_number;
+ unsigned int last_section_number;
+
+ // FIXME: list of programs
+
+ unsigned int crc32;
+} pat_t;
+
+typedef struct _pat_list {
+ unsigned int program_number; //SID
+ unsigned int reserved;
+ unsigned int network_pmt_pid;
+
+ int cads_present;
+ int cads_num;
+
+} pat_list_t;
+
+typedef struct pmt_pid_list {
+
+ pat_t p;
+ pat_list_t *pl;
+ unsigned int pmt_pids;
+
+} pmt_pid_list_t;
+
+typedef struct psi_buf {
+
+ unsigned char *buf;
+ unsigned int len;//used for offset
+ unsigned int start;
+
+ int pid;
+ int continuity;
+
+} psi_buf_t;
+
+typedef struct pmt {
+ unsigned int table_id;
+ unsigned int section_syntax_indicator;
+ unsigned int reserved_1;
+ unsigned int section_length;
+ unsigned int program_number;
+ unsigned int reserved_2;
+ unsigned int version_number;
+ unsigned int current_next_indicator;
+ unsigned int section_number;
+ unsigned int last_section_number;
+ unsigned int reserved_3;
+ unsigned int pcr_pid;
+ unsigned int reserved_4;
+ unsigned int program_info_length;
+
+ // N descriptors
+
+ // N1 stream types and descriptors
+
+ unsigned int crc32;
+} pmt_t;
+
+typedef struct es_pmt_info {
+ unsigned int stream_type;
+ unsigned int reserved_1;
+ unsigned int elementary_pid;
+ unsigned int reserved_2;
+ unsigned int es_info_length;
+
+ // N2 descriptor
+
+} es_pmt_info_t;
+
+typedef struct ca_descriptor {
+
+ unsigned int descriptor_tag;
+ unsigned int descriptor_length;
+ unsigned int ca_system_id;
+ unsigned int reserved;
+ unsigned int ca_pid;
+ unsigned char private_data[MAX_DESC_LEN];
+
+} si_desc_t;
+
+typedef struct pmt_descriptor {
+
+ pmt_t pmt_hdr;
+
+ int cas;
+ si_desc_t *cad;
+
+} si_pmt_desc_t;
+
+typedef struct ca_descriptor_list {
+
+ int cads;
+ si_desc_t *cad;
+
+} si_cad_t;
+
+typedef struct ca_sid_info {
+
+ int sid;
+ int version;
+ int offset;
+ int len;
+
+} ca_sid_t;
+
+typedef struct ca_pmt_descriptors {
+
+ int cads;
+ int size;
+ unsigned char *cad;
+
+} si_ca_pmt_t;
+
+typedef struct ca_es_pid_info {
+
+ int pid;
+ uint8_t type;
+
+} ca_es_pid_info_t;
+
+typedef struct ca_pmt_list {
+
+ int sid;
+ int pmt_pid;
+
+ pmt_t p;
+ si_ca_pmt_t pm;
+ si_ca_pmt_t es;
+
+ ca_es_pid_info_t espids[MAX_ES_PIDS];
+ int es_pid_num;
+
+} ca_pmt_list_t;
+
+
+typedef struct ca_sid_list {
+
+ int tc; //total number of CA desc.
+ int num;
+ ca_pmt_list_t *l;
+
+} ca_sid_list_t;
+
+typedef struct _cat {
+ unsigned int table_id;
+ unsigned int section_syntax_indicator;
+ unsigned int reserved_1;
+ unsigned int section_length;
+ unsigned int reserved_2;
+ unsigned int version_number;
+ unsigned int current_next_indicator;
+ unsigned int section_number;
+ unsigned int last_section_number;
+
+ // private section
+
+ unsigned int crc32;
+} cat_t;
+
+typedef struct tdt_sect {
+
+ uint8_t table_id;
+ uint8_t section_syntax_indicator;
+ uint8_t reserved; //0 future use
+ uint8_t reserved_1;
+ uint16_t section_length;
+ uint8_t dvbdate[5];
+} tdt_sect_t;
+
+typedef struct _str_table {
+ unsigned int from;
+ unsigned int to;
+ const char *str;
+} str_table;
+
+
+int parse_ca_descriptor(unsigned char *desc, si_desc_t *t);
+
+int ts2psi_data(unsigned char *buf,psi_buf_t *p,int len, int pid_req);
+int parse_pat_sect(unsigned char *buf, int size, pmt_pid_list_t *pmt);
+int parse_pmt_ca_desc(unsigned char *buf, int size, int sid, si_ca_pmt_t *pm_cads, si_ca_pmt_t *es_cads, pmt_t *pmt_hdr, int *fta, ca_es_pid_info_t *espid, int *es_pid_num);
+int parse_cat_sect(unsigned char *buf, int size, si_cad_t *emm);
+int parse_tdt_sect(unsigned char *buf, int size, tdt_sect_t *tdt);
+int get_ts_packet_hdr(unsigned char *buf, ts_packet_hdr_t *p);
+int si_get_video_pid(unsigned char *esi_buf, int size, int *vpid);
+int si_get_audio_pid(unsigned char *esi_buf, int size, int *apid);
+int si_get_private_pids(unsigned char *esi_buf, int size, int *upids);
+int get_pmt_es_pids(unsigned char *esi_buf, int size, int *es_pids, int all);
+void print_pat(pat_t *p, pat_list_t *pl, int pmt_num);
+void printhex_buf(char *msg,unsigned char *buf,int len);
+void writehex_buf(FILE *f,char *msg,unsigned char *buf,int len);
+void print_cad_lst(si_cad_t *l, int ts_id);
+void print_ca_bytes(si_desc_t *p);
+void get_time_mjd (unsigned long mjd, long *year , long *month, long *day);
+void print_tdt(tdt_sect_t *tdt, uint16_t mjd, uint32_t utc);
+int ca_free_cpl_desc(ca_pmt_list_t *cpl);
+char *si_caid_to_name(unsigned int caid);
+
+#endif
+
+
+
+
+
diff --git a/mcast/common/.svn/text-base/tools.c.svn-base b/mcast/common/.svn/text-base/tools.c.svn-base
new file mode 100644
index 0000000..9e05a10
--- /dev/null
+++ b/mcast/common/.svn/text-base/tools.c.svn-base
@@ -0,0 +1,777 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ */
+
+#define DEBUG 1
+#include "headers.h"
+
+#ifdef DEBUG
+const Param inversion_list[] = {
+ {"INVERSION_OFF", INVERSION_OFF},
+ {"INVERSION_ON", INVERSION_ON},
+ {"INVERSION_AUTO", INVERSION_AUTO}
+};
+
+const Param bw_list[] = {
+ {"BANDWIDTH_6_MHZ", BANDWIDTH_6_MHZ},
+ {"BANDWIDTH_7_MHZ", BANDWIDTH_7_MHZ},
+ {"BANDWIDTH_8_MHZ", BANDWIDTH_8_MHZ}
+};
+
+const Param fec_list[] = {
+ {"FEC_1_2", FEC_1_2},
+ {"FEC_2_3", FEC_2_3},
+ {"FEC_3_4", FEC_3_4},
+ {"FEC_4_5", FEC_4_5},
+ {"FEC_5_6", FEC_5_6},
+ {"FEC_6_7", FEC_6_7},
+ {"FEC_7_8", FEC_7_8},
+ {"FEC_8_9", FEC_8_9},
+ {"FEC_AUTO", FEC_AUTO},
+ {"FEC_NONE", FEC_NONE},
+ {"FEC_1_4", FEC_1_4}, // RMM S2 Extension
+ {"FEC_1_3", FEC_1_3},
+ {"FEC_2_5", FEC_2_5},
+ {"FEC_9_10", FEC_9_10}
+};
+
+const Param guard_list[] = {
+ {"GUARD_INTERVAL_1_16", GUARD_INTERVAL_1_16},
+ {"GUARD_INTERVAL_1_32", GUARD_INTERVAL_1_32},
+ {"GUARD_INTERVAL_1_4", GUARD_INTERVAL_1_4},
+ {"GUARD_INTERVAL_1_8", GUARD_INTERVAL_1_8}
+};
+
+const Param hierarchy_list[] = {
+ {"HIERARCHY_1", HIERARCHY_1},
+ {"HIERARCHY_2", HIERARCHY_2},
+ {"HIERARCHY_4", HIERARCHY_4},
+ {"HIERARCHY_NONE", HIERARCHY_NONE}
+};
+
+const Param constellation_list[] = {
+ {"QPSK", QPSK},
+ {"QAM_128", QAM_128},
+ {"QAM_16", QAM_16},
+ {"QAM_256", QAM_256},
+ {"QAM_32", QAM_32},
+ {"QAM_64", QAM_64},
+ {"QPSK_S2", QPSK_S2}, // RMM S2 Extension
+ {"PSK8", PSK8}
+};
+
+const Param transmissionmode_list[] = {
+ {"TRANSMISSION_MODE_2K", TRANSMISSION_MODE_2K},
+ {"TRANSMISSION_MODE_8K", TRANSMISSION_MODE_8K},
+};
+
+const Param capabilities_list[] = {
+ {"Stupid: ", FE_IS_STUPID},
+ {"FE_CAN_INVERSION_AUTO: ", FE_CAN_INVERSION_AUTO},
+ {"CAN_FEC_1_2: ", FE_CAN_FEC_1_2},
+ {"CAN_FEC_2_3: ", FE_CAN_FEC_2_3},
+ {"CAN_FEC_3_4: ", FE_CAN_FEC_3_4},
+ {"CAN_FEC_4_5: ", FE_CAN_FEC_4_5},
+ {"CAN_FEC_6_7: ", FE_CAN_FEC_6_7},
+ {"CAN_FEC_7_8: ", FE_CAN_FEC_7_8},
+ {"CAN_FEC_8_9: ", FE_CAN_FEC_8_9},
+ {"CAN_FEC_AUTO: ", FE_CAN_FEC_AUTO},
+ {"FE_CAN_QPSK: ", FE_CAN_QPSK},
+ {"FE_CAN_QAM_16: ", FE_CAN_QAM_16},
+ {"FE_CAN_QAM_32: ", FE_CAN_QAM_32},
+ {"FE_CAN_QAM_64: ", FE_CAN_QAM_64},
+ {"FE_CAN_QAM_128: ", FE_CAN_QAM_128},
+ {"FE_CAN_QAM_256: ", FE_CAN_QAM_256},
+ {"FE_CAN_QAM_AUTO: ", FE_CAN_QAM_AUTO},
+ {"FE_CAN_TRANSMISSION_MODE_AUTO: ", FE_CAN_TRANSMISSION_MODE_AUTO},
+ {"FE_CAN_BANDWIDTH_AUTO: ", FE_CAN_BANDWIDTH_AUTO},
+ {"FE_CAN_GUARD_INTERVAL_AUTO: ", FE_CAN_GUARD_INTERVAL_AUTO},
+ {"FE_CAN_HIERARCHY_AUTO: ", FE_CAN_HIERARCHY_AUTO},
+ {"FE_CAN_MUTE_TS: ", FE_CAN_MUTE_TS}
+// {"FE_CAN_CLEAN_SETUP: ",FE_CAN_CLEAN_SETUP}
+};
+
+#define LIST_SIZE(x) sizeof(x)/sizeof(Param)
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+void print_fe_info (struct dvb_frontend_info *fe_info)
+{
+ fprintf (stdout, "-------------------------------------------\n");
+ fprintf (stdout, "Tuner name: %s\n", fe_info->name);
+ fprintf (stdout, "Tuner type: %u\n", (unsigned int) fe_info->type);
+ fprintf (stdout, "Frequency min.: %u\n", fe_info->frequency_min);
+ fprintf (stdout, "Frequency max.: %u\n", fe_info->frequency_max);
+ fprintf (stdout, "Frequency stepsize: %u\n", fe_info->frequency_stepsize);
+ fprintf (stdout, "Frequency tolerance: %u\n", fe_info->frequency_tolerance);
+ fprintf (stdout, "Symbol rate min: %u\n", fe_info->symbol_rate_min);
+ fprintf (stdout, "Symbol rate max: %u\n", fe_info->symbol_rate_max);
+ fprintf (stdout, "Symbol rate tolerance: %u\n", fe_info->symbol_rate_tolerance);
+ fprintf (stdout, "Notifier delay: %u\n", fe_info->notifier_delay);
+ fprintf (stdout, "Cpas: 0x%x\n", (unsigned int) fe_info->caps);
+
+ fprintf (stdout, "-------------------------------------------\n");
+ fprintf (stdout, "Frontend Capabilities:\n");
+ int i;
+
+ for (i = 0; i < LIST_SIZE (capabilities_list); i++) {
+ if (fe_info->caps & capabilities_list[i].value)
+ fprintf (stdout, "%syes\n", capabilities_list[i].name);
+ else
+ fprintf (stdout, "%sno\n", capabilities_list[i].name);
+ }
+ fprintf (stdout, "-------------------------------------------\n");
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+void print_frontend_settings (struct dvb_frontend_parameters *frontend_param)
+{
+ int i;
+ fprintf (stdout, "\n----- Front End Settings ----- ");
+ fprintf (stdout, "\nFrequency : %u \n", frontend_param->frequency);
+ for (i = 0; i < LIST_SIZE (inversion_list); i++) {
+ if (inversion_list[i].value == frontend_param->inversion)
+ fprintf (stdout, "Inversion : %s\n", inversion_list[i].name);
+
+ }
+ //
+ for (i = 0; i < LIST_SIZE (bw_list); i++) {
+ if (frontend_param->u.ofdm.bandwidth == bw_list[i].value)
+ fprintf (stdout, "Bandwidth : %s\n", bw_list[i].name);
+
+ }
+ for (i = 0; i < LIST_SIZE (fec_list); i++) {
+ if (fec_list[i].value == frontend_param->u.ofdm.code_rate_HP)
+ fprintf (stdout, "Code Rate HP : %s\n", fec_list[i].name);
+
+ }
+ for (i = 0; i < LIST_SIZE (fec_list); i++) {
+ if (fec_list[i].value == frontend_param->u.ofdm.code_rate_LP)
+ fprintf (stdout, "Code Rate LP : %s\n", fec_list[i].name);
+
+ }
+
+ for (i = 0; i < LIST_SIZE (constellation_list); i++) {
+ if (constellation_list[i].value == frontend_param->u.ofdm.constellation)
+ fprintf (stdout, "Modulation : %s\n", constellation_list[i].name);
+
+ }
+
+ for (i = 0; i < LIST_SIZE (transmissionmode_list); i++) {
+ if (transmissionmode_list[i].value == frontend_param->u.ofdm.transmission_mode)
+ fprintf (stdout, "Transmission mode : %s\n", transmissionmode_list[i].name);
+
+ }
+
+ for (i = 0; i < LIST_SIZE (guard_list); i++) {
+ if (guard_list[i].value == frontend_param->u.ofdm.guard_interval)
+ fprintf (stdout, "Guard interval : %s\n", guard_list[i].name);
+
+ }
+
+ for (i = 0; i < LIST_SIZE (hierarchy_list); i++) {
+ if (hierarchy_list[i].value == frontend_param->u.ofdm.hierarchy_information)
+ fprintf (stdout, "Hierarchy Information : %s\n", hierarchy_list[i].name);
+
+ }
+
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+void print_mcg (struct in6_addr *mcg)
+{
+ char host[80];
+ unsigned int freq;
+ struct in6_addr mc;
+ int i;
+
+ for (i = 0; i < 8; i++) {
+ mc.s6_addr16[i] = ntohs (mcg->s6_addr16[i]);
+ }
+
+ freq = mc.s6_addr16[6] | (mc.s6_addr16[7] & NOPID_MASK) << 3;
+
+ inet_ntop (AF_INET6, mcg->s6_addr, (char *) host, INET6_ADDRSTRLEN);
+ fprintf (stdout, "MCG: %s\n", host);
+
+ fprintf (stdout, "\n");
+ fprintf (stdout, "TS-Streaming group\n");
+ fprintf (stdout, "-----------------------------\n");
+ fprintf (stdout, "Streaming Group - 0x%x \n", (mc.s6_addr16[1] >> 12) & 0xf);
+ fprintf (stdout, "Priority - 0x%x \n", (mc.s6_addr16[1] >> 8) & 0xf);
+ fprintf (stdout, "Reception System - 0x%x \n", mc.s6_addr16[1] & 0xff);
+ fprintf (stdout, "CAM Handling - 0x%x \n", mc.s6_addr16[2]);
+ fprintf (stdout, "Polarisation - 0x%x \n", (mc.s6_addr16[3] >> 12) & 0xf);
+ fprintf (stdout, "SATPosition - 0x%x \n", mc.s6_addr16[3] & 0xfff);
+ fprintf (stdout, "Symbol Rate - 0x%x \n", mc.s6_addr16[4]);
+ fprintf (stdout, "Modulation - 0x%x \n", mc.s6_addr16[5]);
+ fprintf (stdout, "Frequency (0x%x) - %d / %d\n\n", freq, freq * (16667 / 8), freq * (250 / 8));
+
+ fprintf (stdout, "PID - 0x%x \n", mc.s6_addr16[7] & PID_MASK);
+}
+#endif
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+/* Frequency 19Bit
+ DVB-T/DVB-C 524288 Steps * (25/12)kHz = 0...1092MHz in 2.083333kHz steps
+ DVB-S 524288 Steps * (1/20) MHz = 0...26.2GHz in 50kHz steps
+*/
+void fe_parms_to_mcg (struct in6_addr *mcg, streaming_group_t StreamingGroup, fe_type_t type, recv_sec_t * sec, struct dvb_frontend_parameters *fep, int vpid)
+{
+ int i;
+ unsigned int Priority = 0;
+ unsigned int ReceptionSystem = 0;
+ unsigned int CAMHandling = 0;
+ unsigned int Polarisation = 0;
+ unsigned int SATPosition = NO_SAT_POS;
+ unsigned int Symbolrate = 0;
+ unsigned int Modulation = 0;
+ unsigned int TransmissionMode = 0;
+ unsigned int Frequency;
+ double fmul;
+
+ // Default for DVB-T and DVB-C
+ fmul = 12.0 * (((double) fep->frequency) + 1041);
+ Frequency = (unsigned int) (fmul / 25000.0);
+
+ switch ((int)type) {
+ case FE_QPSK:
+ case FE_DVBS2:
+ Frequency = (fep->frequency + 24) / 50;
+ //sec->diseqc_cmd currently not used
+ // Fixme: Translation Diseqc->position/LOF-frequency
+ Polarisation = (sec->mini_cmd << 3) | (sec->tone_mode << 2) | sec->voltage;
+ Symbolrate = fep->u.qpsk.symbol_rate / 1000;
+ Modulation |= (fep->u.qpsk.fec_inner) & 0xf;
+
+ // RMM S2 extension: Put Modulation in 23:16 and rolloff in 31:24
+ if (((fep->u.qpsk.fec_inner >> 16) & 0xff) == PSK8)
+ Modulation |= 2 << 4;
+ if (((fep->u.qpsk.fec_inner >> 16) & 0xff) == QPSK_S2)
+ Modulation |= 1 << 4;
+ Modulation |= fep->inversion << 14;
+ break;
+ case FE_QAM:
+ Symbolrate = fep->u.qam.symbol_rate / 200;
+ Modulation |= fep->u.qam.modulation;
+ Modulation |= fep->inversion << 14;
+ break;
+ case FE_OFDM:
+ TransmissionMode = fep->u.ofdm.transmission_mode;
+ Symbolrate = (TransmissionMode & 0x7) << 8 | (fep->u.ofdm.code_rate_HP << 4) | fep->u.ofdm.code_rate_LP;
+ Modulation |= (fep->u.ofdm.constellation & 0xf) | (fep->u.ofdm.hierarchy_information & 3) << 4 | (fep->u.ofdm.bandwidth & 3) << 7 | (fep->u.ofdm.guard_interval & 7) << 9 | (fep->inversion & 3) << 14;
+ break;
+ case FE_ATSC:
+ Modulation |= fep->u.vsb.modulation;
+ Modulation |= fep->inversion << 14;
+ break;
+ }
+
+ if (type == FE_DVBS2 && !(Modulation & 0x30) ){
+ type=FE_QPSK;
+ }
+
+ ReceptionSystem = type;
+
+ mcg->s6_addr16[0] = MC_PREFIX;
+ mcg->s6_addr16[1] = ((StreamingGroup & 0xf) << 12) | ((Priority & 0xf) << 8) | (ReceptionSystem & 0xff);
+ mcg->s6_addr16[2] = CAMHandling;
+ mcg->s6_addr16[3] = ((Polarisation & 0xf) << 12) | (SATPosition & 0xfff);
+ mcg->s6_addr16[4] = Symbolrate;
+ mcg->s6_addr16[5] = Modulation;
+ mcg->s6_addr16[6] = Frequency;
+ mcg->s6_addr16[7] = (vpid & PID_MASK) | ((Frequency >> 16) << 13);
+
+ for (i = 0; i < 8; i++) {
+ mcg->s6_addr16[i] = htons (mcg->s6_addr16[i]);
+ }
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+int mcg_to_all_parms(struct in6_addr *mcg, struct mcg_data * mcd)
+{
+ int ret;
+ mcd->mcg=*mcg;
+ int n;
+
+ ret=mcg_to_fe_parms(mcg, &mcd->type, &mcd->sec, &mcd->fep, &mcd->vpid);
+
+ if (ret)
+ return ret;
+ mcg_get_satpos(mcg, &mcd->satpos);
+
+ for(n=0;n<MAX_TUNER_CACHE;n++) {
+ mcd->sat_cache[n].resolved=NOT_RESOLVED;
+ mcd->sat_cache[n].num=0;
+ mcd->sat_cache[n].component=0;
+ }
+
+ return 0;
+}
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+int mcg_to_fe_parms (struct in6_addr *mcg, fe_type_t * type, recv_sec_t * sec, struct dvb_frontend_parameters *fep, int *vpid)
+{
+ struct in6_addr mc = *mcg;
+ streaming_group_t StreamingGroup;
+ unsigned int freq;
+ double fmul;
+ fe_type_t fetype;
+
+ int i;
+ for (i = 0; i < 8; i++) {
+ mc.s6_addr16[i] = ntohs (mc.s6_addr16[i]);
+ }
+
+ StreamingGroup = (streaming_group_t)((mc.s6_addr16[1] >> 12) & 0xf);
+
+ if (StreamingGroup != STREAMING_PID) {
+ return -1;
+ }
+
+ if (fep) {
+ memset (fep, 0, sizeof (struct dvb_frontend_parameters));
+ }
+ if (sec) {
+ memset (sec, 0, sizeof (recv_sec_t));
+ }
+
+
+ freq = mc.s6_addr16[6] | ((mc.s6_addr16[7] & NOPID_MASK) << 3);
+
+ fmul = 25000.0 * (double) freq;
+
+ fep->frequency = (unsigned int) (fmul / 12.0);
+ fep->inversion = (fe_spectral_inversion_t)((mc.s6_addr16[5] >> 14) & 3);
+ fetype = (fe_type_t)(mc.s6_addr16[1] & 0xff);
+
+ if (type) {
+ *type = fetype;
+ }
+ switch ((int)fetype) {
+ case FE_QPSK:
+ case FE_DVBS2:
+ {
+ int Polarisation = mc.s6_addr16[3] >> 12;
+ fep->frequency = freq * 50;
+ sec->mini_cmd = (fe_sec_mini_cmd_t)((Polarisation >> 3) & 1);
+ sec->tone_mode = (fe_sec_tone_mode_t)((Polarisation >> 2) & 1);
+ sec->voltage = (fe_sec_voltage_t)(Polarisation & 3);
+
+ fep->u.qpsk.symbol_rate = mc.s6_addr16[4] * 1000;
+ fep->u.qpsk.fec_inner = (fe_code_rate_t)(mc.s6_addr16[5] & 0xf);
+
+ unsigned int fec_inner=(unsigned int)fep->u.qpsk.fec_inner;
+
+ // RMM S2 Extension
+ switch (mc.s6_addr16[5] & 0x30) {
+ case 0x10:
+ fec_inner |= QPSK_S2 << 16;
+ fep->u.qpsk.fec_inner=(fe_code_rate_t)fec_inner;
+ *type = (fe_type_t) FE_DVBS2; // force FE type
+ break;
+ case 0x20:
+ fec_inner |= PSK8 << 16;
+ fep->u.qpsk.fec_inner=(fe_code_rate_t)fec_inner;
+ *type = (fe_type_t) FE_DVBS2;
+ break;
+ default:
+ *type = FE_QPSK;
+ }
+ }
+ break;
+ case FE_QAM:
+ fep->u.qam.symbol_rate = mc.s6_addr16[4] * 200;
+ fep->u.qam.modulation = (fe_modulation_t)(mc.s6_addr16[5] & 0xf);
+ // Ignore inversion
+ break;
+ case FE_OFDM:
+ fep->u.ofdm.transmission_mode = (fe_transmit_mode_t)((mc.s6_addr16[4] >> 8) & 3);
+ fep->u.ofdm.code_rate_HP = (fe_code_rate_t)((mc.s6_addr16[4] >> 4) & 0xf);
+ fep->u.ofdm.code_rate_LP = (fe_code_rate_t)(mc.s6_addr16[4] & 0xf);
+
+ fep->u.ofdm.constellation = (fe_modulation_t) (mc.s6_addr16[5] & 0xf);
+ fep->u.ofdm.hierarchy_information = (fe_hierarchy_t)((mc.s6_addr16[5] >> 4) & 3);
+ fep->u.ofdm.bandwidth = (fe_bandwidth_t)((mc.s6_addr16[5] >> 7) & 3);
+ fep->u.ofdm.guard_interval = (fe_guard_interval_t)((mc.s6_addr16[5] >> 9) & 7);
+ break;
+ case FE_ATSC:
+ fep->u.vsb.modulation = (fe_modulation_t)(mc.s6_addr16[5] & 0xf);
+ break;
+ }
+
+ if (vpid) {
+ *vpid = mc.s6_addr16[7] & PID_MASK;
+ }
+ //print_frontend_settings(fep);
+ return 0;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+void mcg_set_streaming_group (struct in6_addr *mcg, streaming_group_t StreamingGroup)
+{
+ int i;
+
+ for (i = 0; i < 8; i++) {
+ mcg->s6_addr16[i] = ntohs (mcg->s6_addr16[i]);
+ }
+
+ // Change StreamingGroup
+ mcg->s6_addr16[1] = ((StreamingGroup & 0xf) << 12) | (mcg->s6_addr16[1] & 0x0fff);
+
+ // Remove PID
+ mcg->s6_addr16[7] &= NOPID_MASK;
+
+ // Remove CAID
+ mcg->s6_addr16[2] = 0;
+
+ for (i = 0; i < 8; i++) {
+ mcg->s6_addr16[i] = htons (mcg->s6_addr16[i]);
+ }
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+void mcg_get_streaming_group (struct in6_addr *mcg, streaming_group_t *StreamingGroup)
+{
+ if(StreamingGroup) {
+ *StreamingGroup=(streaming_group_t)((ntohs (mcg->s6_addr16[1]) >> 12) & 0xf);
+ }
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+void mcg_set_pid (struct in6_addr *mcg, int pid)
+{
+
+ mcg->s6_addr16[7] = ntohs (mcg->s6_addr16[7]);
+
+ // Remove PID
+ mcg->s6_addr16[7] &= NOPID_MASK;
+
+ // Set new PID
+ mcg->s6_addr16[7] |= pid;
+
+ mcg->s6_addr16[7] = htons (mcg->s6_addr16[7]);
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+void mcg_get_pid (struct in6_addr *mcg, int *pid)
+{
+ if (pid) {
+ *pid=ntohs (mcg->s6_addr16[7]) & PID_MASK;
+ }
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+void mcg_init_streaming_group (struct in6_addr *mcg, streaming_group_t StreamingGroup)
+{
+ unsigned int Priority = 1;
+ mcg->s6_addr16[0] = MC_PREFIX;
+ mcg->s6_addr16[1] = ((StreamingGroup & 0xf) << 12) | ((Priority & 0xf) << 8) | (0 & 0xff);
+ mcg->s6_addr16[2] = 0;
+ mcg->s6_addr16[3] = 0;
+ mcg->s6_addr16[4] = 0;
+ mcg->s6_addr16[5] = 0;
+ mcg->s6_addr16[6] = 0;
+ mcg->s6_addr16[7] = 0;
+ int i;
+ for (i = 0; i < 8; i++) {
+ mcg->s6_addr16[i] = htons (mcg->s6_addr16[i]);
+ }
+
+}
+
+void mcg_get_priority (struct in6_addr *mcg, int *priority)
+{
+ if (priority) {
+ *priority = (ntohs (mcg->s6_addr16[1])>>8) & 0xf;
+ }
+}
+
+void mcg_set_priority (struct in6_addr *mcg, int priority)
+{
+ mcg->s6_addr16[1] = ntohs (mcg->s6_addr16[1]);
+ mcg->s6_addr16[1] &= 0xf0ff;
+ mcg->s6_addr16[1] |= (priority & 0xf) << 8;
+ mcg->s6_addr16[1] = htons (mcg->s6_addr16[1]);
+}
+
+void mcg_get_satpos (struct in6_addr *mcg, int *satpos)
+{
+ if (satpos) {
+ *satpos = ntohs (mcg->s6_addr16[3]) & 0xfff;
+ }
+}
+
+void mcg_set_satpos (struct in6_addr *mcg, int satpos)
+{
+ mcg->s6_addr16[3] = ntohs (mcg->s6_addr16[3]);
+
+ // Remove SatPos
+ mcg->s6_addr16[3] &= ~NO_SAT_POS;
+
+ // Set new SatPos
+ mcg->s6_addr16[3] |= (satpos & NO_SAT_POS);
+
+ mcg->s6_addr16[3] = htons (mcg->s6_addr16[3]);
+}
+
+void mcg_get_id (struct in6_addr *mcg, int *id)
+{
+ if (id) {
+ *id = ntohs (mcg->s6_addr16[2]);
+ }
+}
+
+void mcg_set_id (struct in6_addr *mcg, int id)
+{
+ mcg->s6_addr16[2] = htons(id);
+}
+
+#if defined LIBRARY || defined SERVER
+#ifndef OS_CODE
+ #define OS_CODE 3
+#endif
+#if MAX_MEM_LEVEL >= 8
+# define DEF_MEM_LEVEL 8
+#else
+# define DEF_MEM_LEVEL MAX_MEM_LEVEL
+#endif
+
+static unsigned char gzip_hdr[] = { 0x1f, 0x8b, Z_DEFLATED, 0 /*flags */ , 0, 0, 0, 0 /*time */ , 0 /*xflags */ , OS_CODE };
+
+int check_header (const Bytef * buf, unsigned int buflen)
+{
+ if (buflen <= 10)
+ return 0;
+
+ if (buf[0] != gzip_hdr[0] || buf[1] != gzip_hdr[1]) {
+ return -1;
+ }
+
+ if (memcmp (buf, gzip_hdr, sizeof (gzip_hdr))) {
+ return -2;
+ }
+ return 10;
+}
+
+unsigned int get32_lsb_first (unsigned char *ptr)
+{
+ int i;
+ unsigned int val = 0;
+ for (i = 3; i >= 0; i--) {
+ val <<= 8;
+ val |= (ptr[i] & 0xff);
+ }
+ return val;
+}
+
+void put32_lsb_first (unsigned char *ptr, unsigned int val)
+{
+ int i;
+ for (i = 0; i < 4; i++) {
+ ptr[i] = val & 0xff;
+ val >>= 8;
+ }
+}
+
+int gzip_ (Bytef * dest, unsigned int *destLen, const Bytef * source, unsigned int sourceLen, int level)
+{
+ unsigned int crc = crc32 (0L, Z_NULL, 0);
+ z_stream stream;
+ int err;
+
+ if (*destLen <= 10) {
+ return Z_BUF_ERROR;
+ }
+ memcpy (dest, gzip_hdr, sizeof (gzip_hdr));
+
+ stream.next_in = (Bytef *) source;
+ stream.avail_in = sourceLen;
+
+ stream.next_out = dest + 10;
+ stream.avail_out = *destLen - 10;
+
+ stream.zalloc = (alloc_func) 0;
+ stream.zfree = (free_func) 0;
+ stream.opaque = (voidpf) 0;
+
+ err = deflateInit2 (&stream, level, Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY);
+
+ if (err != Z_OK)
+ return err;
+
+ err = deflate (&stream, Z_FINISH);
+ if (err != Z_STREAM_END) {
+ deflateEnd (&stream);
+ return err == Z_OK ? Z_BUF_ERROR : err;
+ }
+ *destLen = stream.total_out + 10;
+
+ err = deflateEnd (&stream);
+ crc = crc32 (crc, source, sourceLen);
+
+ put32_lsb_first ((unsigned char *) (dest + *destLen), crc);
+ put32_lsb_first ((unsigned char *) (dest + *destLen + 4), sourceLen);
+
+ *destLen += 8;
+ return err;
+}
+
+int gzip (Bytef * dest, unsigned int *destLen, const Bytef * source, unsigned int sourceLen, int level)
+{
+ if (!level) {
+ memcpy (dest, source, sourceLen);
+ *destLen = sourceLen;
+ return 0;
+ }
+ return gzip_ (dest, destLen, source, sourceLen,level);
+}
+
+int gunzip_ (Bytef * dest, unsigned int *destLen, const Bytef * source, unsigned int sourceLen)
+{
+ unsigned int crc = crc32 (0L, Z_NULL, 0);
+ z_stream stream;
+ int err;
+ int ret = check_header (source, sourceLen);
+ if (ret < 0) {
+ return ret;
+ }
+
+ stream.next_in = (Bytef *) source + ret;
+ stream.avail_in = sourceLen - ret;
+
+ stream.next_out = dest;
+ stream.avail_out = *destLen;
+
+ stream.zalloc = (alloc_func) 0;
+ stream.zfree = (free_func) 0;
+
+ err = inflateInit2 (&stream, -MAX_WBITS);
+ if (err != Z_OK)
+ return err;
+
+ err = inflate (&stream, Z_FINISH);
+ if (err != Z_STREAM_END) {
+ inflateEnd (&stream);
+ if (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0))
+ return Z_DATA_ERROR;
+ return err;
+ }
+ *destLen = stream.total_out;
+
+ err = inflateEnd (&stream);
+ crc = crc32 (crc, dest, stream.total_out);
+
+ int crc_found = get32_lsb_first ((unsigned char *) (stream.next_in));
+ int len_found = get32_lsb_first ((unsigned char *) (stream.next_in + 4));
+
+ if (crc_found == crc && len_found == stream.total_out) {
+ return err;
+ }
+
+ return Z_DATA_ERROR;
+}
+
+int gunzip (Bytef * dest, unsigned int *destLen, const Bytef * source, unsigned int sourceLen)
+{
+ int ret = gunzip_ (dest, destLen, source, sourceLen);
+ if (ret == -1) {
+ memcpy (dest, source, sourceLen);
+ *destLen = sourceLen;
+ return 0;
+ } else if (ret < 0) {
+ return -1;
+ }
+ return 0;
+}
+#endif
+#ifndef BACKTRACE
+ void print_trace (void)
+ {
+ }
+#else
+#include <execinfo.h>
+/* Obtain a backtrace and print it to stdout. */
+void print_trace (void)
+{
+ void *array[10];
+ size_t size;
+ char **strings;
+ size_t i;
+
+ size = backtrace (array, 10);
+ strings = backtrace_symbols (array, size);
+
+ printf ("Obtained %zd stack frames.\n", size);
+
+ for (i = 0; i < size; i++) {
+ printf ("%s\n", strings[i]);
+ }
+ free (strings);
+}
+
+
+void SignalHandlerCrash(int signum)
+{
+ void *array[15];
+ size_t size;
+ char **strings;
+ size_t i;
+ FILE *f;
+ char dtstr[16];
+ time_t t=time(NULL);
+ struct tm *tm=localtime(&t);
+
+ signal(signum,SIG_DFL); // Allow core dump
+
+ f=fopen("/var/log/mcli.crashlog","a");
+ if (f) {
+ strftime(dtstr, sizeof(dtstr), "%b %e %T", tm);
+ size = backtrace (array, 15);
+ strings = backtrace_symbols (array, size);
+ fprintf(f,"%s ### Crash signal %i ###\n",dtstr, signum);
+ for (i = 0; i < size; i++)
+ fprintf (f, "%s Backtrace %i: %s\n", dtstr, i, strings[i]);
+ free (strings);
+ fclose(f);
+ }
+}
+#endif
+
+#ifdef SYSLOG
+pthread_mutex_t _loglock = PTHREAD_MUTEX_INITIALIZER;
+
+UDPContext * syslog_fd = NULL;
+char *_logstr = NULL;
+
+int syslog_init(void)
+{
+ struct in6_addr mcglog;
+ mcg_init_streaming_group (&mcglog, STREAMING_LOG);
+ syslog_fd = server_udp_open (&mcglog, 23000, NULL);
+ if(syslog_fd) {
+ _logstr=(char *)malloc(10240);
+ }
+
+ return syslog_fd?0:-1;
+}
+
+int syslog_write(char *s)
+{
+ return udp_write (syslog_fd, (uint8_t *)s, strlen(s));
+}
+
+void syslog_exit(void)
+{
+ if(syslog_fd) {
+ udp_close(syslog_fd);
+ free(_logstr);
+ }
+}
+#endif
diff --git a/mcast/common/.svn/text-base/tools.h.svn-base b/mcast/common/.svn/text-base/tools.h.svn-base
new file mode 100644
index 0000000..bdcdf69
--- /dev/null
+++ b/mcast/common/.svn/text-base/tools.h.svn-base
@@ -0,0 +1,108 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ */
+
+#ifndef __TOOLS_H__
+#define __TOOLS_H__
+
+#define PID_MASK 0x1fff
+#define NOPID_MASK 0xe000
+
+#define MC_PREFIX 0xff18
+
+#define NO_SAT_POS 0xfff
+
+// value from sat_resolved
+#define NOT_RESOLVED -1 // Not run through mcg_is_equivalent/satellite_resolver
+#define NOT_SUPPORTED -2 // requested position not available
+#define LEGACY_DISEQC -3
+
+
+#define COMPRESSION_ON 1
+#define COMPRESSION_OFF 0
+
+struct lookup_dvb_t_fec
+{
+ int fec_hp;
+ int fec_lp;
+ int val;
+};
+
+typedef struct
+{
+ char *name;
+ int value;
+} Param;
+
+typedef enum
+{
+ STREAMING_TCA = 1,
+ STREAMING_TRA = 2,
+ STREAMING_PID = 3,
+ STREAMING_TEN = 4,
+ STREAMING_LOG = 5,
+} streaming_group_t;
+
+
+// 8=max. tuner slots (some safety)
+#define MAX_TUNER_CACHE 8
+
+// contains parsed/cached FE params
+
+
+struct sat_cache {
+ int resolved; // -1=not resolved
+ int num;
+ int component;
+};
+
+struct mcg_data {
+ struct in6_addr mcg;
+ fe_type_t type;
+ recv_sec_t sec;
+ int vpid;
+ struct dvb_frontend_parameters fep;
+ int satpos;
+ // Small temporary cache for SAT-resolution
+ struct sat_cache sat_cache[MAX_TUNER_CACHE];
+};
+
+void print_fe_info (struct dvb_frontend_info *fe_info);
+void print_mcg (struct in6_addr *mcg);
+void print_frontend_settings (struct dvb_frontend_parameters *fe_parms);
+
+DLL_SYMBOL void fe_parms_to_mcg (struct in6_addr *mcg, streaming_group_t StreamingGroup, fe_type_t type, recv_sec_t * sec, struct dvb_frontend_parameters *fep, int vpid);
+DLL_SYMBOL int mcg_to_fe_parms (struct in6_addr *mcg, fe_type_t * type, recv_sec_t * sec, struct dvb_frontend_parameters *fep, int *vpid);
+DLL_SYMBOL int mcg_to_all_parms(struct in6_addr *mcg, struct mcg_data * mcd);
+
+DLL_SYMBOL void mcg_set_streaming_group (struct in6_addr *mcg, streaming_group_t StreamingGroup);
+DLL_SYMBOL void mcg_get_streaming_group (struct in6_addr *mcg, streaming_group_t *StreamingGroup);
+DLL_SYMBOL void mcg_init_streaming_group (struct in6_addr *mcg, streaming_group_t StreamingGroup);
+
+DLL_SYMBOL void mcg_set_pid (struct in6_addr *mcg, int pid);
+DLL_SYMBOL void mcg_get_pid (struct in6_addr *mcg, int *pid);
+
+DLL_SYMBOL void mcg_get_priority (struct in6_addr *mcg, int *priority);
+DLL_SYMBOL void mcg_set_priority (struct in6_addr *mcg, int priority);
+
+DLL_SYMBOL void mcg_get_satpos (struct in6_addr *mcg, int *satpos);
+DLL_SYMBOL void mcg_set_satpos (struct in6_addr *mcg, int satpos);
+
+DLL_SYMBOL void mcg_get_id (struct in6_addr *mcg, int *id);
+DLL_SYMBOL void mcg_set_id (struct in6_addr *mcg, int id);
+
+
+int gzip (Bytef * dest, unsigned int *destLen, const Bytef * source, unsigned int sourceLen, int level);
+int gunzip (Bytef * dest, unsigned int *destLen, const Bytef * source, unsigned int sourceLen);
+void print_trace (void);
+void SignalHandlerCrash(int signum);
+
+int syslog_init(void);
+int syslog_write(char *s);
+void syslog_exit(void);
+
+#endif
diff --git a/mcast/common/.svn/text-base/version.h.svn-base b/mcast/common/.svn/text-base/version.h.svn-base
new file mode 100644
index 0000000..e7aea47
--- /dev/null
+++ b/mcast/common/.svn/text-base/version.h.svn-base
@@ -0,0 +1,18 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ */
+
+#ifdef P2P
+ #define MCLI_P2PSTR "-P2P"
+#else
+ #define MCLI_P2PSTR ""
+#endif
+#define MCLI_APP_VERSION "0.99.33"MCLI_P2PSTR
+#define MCLI_COMPILED __DATE__" "__TIME__
+#define MCLI_VERSION_STR MCLI_APP_VERSION" ("MCLI_COMPILED")"
+#define MCLI_MAGIC 0xDEADBEEF
+#define MCLI_VERSION 0x14
diff --git a/mcast/common/ciparser.c b/mcast/common/ciparser.c
new file mode 100644
index 0000000..5ce563d
--- /dev/null
+++ b/mcast/common/ciparser.c
@@ -0,0 +1,702 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ */
+
+//#define TESTING
+#ifdef TESTING
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <netinet/in.h>
+#include <stdlib.h>
+
+#include "ciparser.h"
+static unsigned char ll[] = { 0x00, 0x01, 0xA0, 0x28, 0x01, 0x90, 0x02, 0x00, 0x05, 0x9F, 0x80, 0x32, 0x1F, 0x03, 0x32, 0xC9, 0x01, 0x00, 0x0F, 0x01, 0x09, 0x06, 0x17, 0x62, 0xE0, 0x65, 0x00, 0x09, 0x09, 0x04, 0x17, 0x02, 0xE1, 0x2D, 0x02, 0x00, 0xA0, 0x00, 0x00, 0x04, 0x00, 0xA1, 0x00, 0x00 };
+static unsigned char lr[] = { 0x00, 0x01, 0x80, 0x02, 0x01, 0x80 };
+static unsigned char la[] = { 0x00, 0x01, 0xA0, 0x07, 0x01, 0x91, 0x04, 0x00, 0x01, 0x00, 0x41, 0x80, 0x02, 0x01, 0x00 };
+static unsigned char lb[] = { 0x00, 0x01, 0xA0, 0x82, 0x00, 0x17, 0x01, 0x90, 0x02, 0x00, 0x03, 0x9F, 0x80, 0x31, 0x0E, 0x06, 0x02, 0x06, 0x02, 0x17, 0x02, 0x17, 0x62, 0x01, 0x00, 0x05, 0x00, 0x18, 0x00, 0x80, 0x02, 0x01, 0x00 };
+static unsigned char lc[] = { 0x01, 0x02, 0xA0, 0x5F, 0x02, 0x90, 0x02, 0x00, 0x06, 0x9F, 0x80, 0x32, 0x56, 0x03, 0x03, 0x8B, 0x01, 0x00, 0x00, 0x02, 0x00, 0xA3, 0x00, 0x23, 0x01, 0x09, 0x0F, 0x05, 0x00, 0xE2, 0xC3, 0x10, 0x01, 0x00, 0x13, 0x01, 0x20, 0x14, 0x03, 0x00, 0x94, 0x0D, 0x09, 0x0F, 0x05, 0x00, 0xE2, 0xCD, 0x10, 0x01, 0x00, 0x13, 0x01, 0x20, 0x14, 0x03, 0x02, 0x38, 0x08, 0x04, 0x00, 0x5C, 0x00, 0x23, 0x01, 0x09, 0x0F, 0x05, 0x00, 0xE2, 0xC3, 0x10, 0x01, 0x00, 0x13, 0x01, 0x20, 0x14, 0x03, 0x00, 0x94, 0x0D, 0x09, 0x0F, 0x05, 0x00, 0xE2, 0xCD, 0x10, 0x01, 0x00, 0x13, 0x01, 0x20, 0x14, 0x03, 0x02, 0x38, 0x08 };
+static unsigned char ld[] = { 0x00, 0x01, 0xA0, 0x82, 0x00, 0x10, 0x01, 0x90, 0x02, 0x00, 0x03, 0x9F, 0x80, 0x33, 0x07, 0x2D, 0xB9, 0x01, 0x81, 0x00, 0x08, 0x00, 0x80, 0x02, 0x01, 0x00 };
+static unsigned char le[] = { 0x00, 0x01, 0xA0, 0x34, 0x01, 0x90, 0x02, 0x00, 0x03, 0x9F, 0x80, 0x32, 0x2B, 0x03, 0x00, 0x0B, 0x01, 0x00, 0x11, 0x01, 0x09, 0x06, 0x17, 0x22, 0xF0, 0x0B, 0x00, 0x0B, 0x09, 0x06, 0x17, 0x02, 0xF0, 0x0B, 0x00, 0x0B, 0x02, 0x06, 0xFF, 0x00, 0x00, 0x04, 0x07, 0x00, 0x00, 0x00, 0x04, 0x07, 0x01, 0x00, 0x00, 0x00, 0x07, 0x03, 0x00, 0x00};
+
+#define dbg(format, arg...) printf("%s:%d " format , __FILE__ , __LINE__ , ## arg)
+#define err(format, arg...) {printf("err:%s:%d: %s (%d): " format , __FILE__ , __LINE__ ,strerror(errno), errno, ## arg);print_trace();abort();}
+#define info(format, arg...) printf("%s:%d: " format , __FILE__ , __LINE__ ,## arg)
+#define warn(format, arg...) printf("%s:%d: " format , __FILE__ , __LINE__ ,## arg)
+#define STATIC
+#else
+//#define DEBUG
+#include "headers.h"
+#endif
+
+#define CA_MAX_CAIDS 16
+#define CA_MAX_PIDS 16
+#ifndef CA_MAX_SLOTS
+#define CA_MAX_SLOTS 3
+#endif
+typedef struct
+{
+ u_int16_t caid[CA_MAX_CAIDS];
+ u_int16_t pid[CA_MAX_PIDS];
+ u_int16_t capid[CA_MAX_PIDS];
+} caid_pid_list_t;
+
+static caid_pid_list_t cpl[CA_MAX_SLOTS];
+
+STATIC void dump(u_int8_t *data, int len)
+{
+#ifdef DEBUG
+ int j;
+ printf("Dump: ");
+ for(j=0;j<len;j++) {
+ printf("%02x ",data[j]);
+ }
+ printf("\n");
+#endif
+}
+
+STATIC int ci_cpl_find_pid (int slot, int pid)
+{
+ if (slot < 0 || slot >= CA_MAX_SLOTS) {
+ return -1;
+ }
+ int i;
+ for (i = 0; i < CA_MAX_PIDS; i++) {
+ if (pid == cpl[slot].pid[i])
+ return 1;
+ }
+ return 0;
+}
+
+STATIC int ci_cpl_find_caid (int slot, int caid)
+{
+ if (slot < 0 || slot >= CA_MAX_SLOTS) {
+ return -1;
+ }
+ int i;
+ for (i = 0; i < CA_MAX_CAIDS; i++) {
+ if (caid == cpl[slot].caid[i])
+ return 1;
+ }
+ return 0;
+}
+
+STATIC int ci_cpl_find_capid (int slot, int pid)
+{
+ if (slot < 0 || slot >= CA_MAX_SLOTS) {
+ return -1;
+ }
+ int i;
+ for (i = 0; i < CA_MAX_PIDS; i++) {
+ if (pid == cpl[slot].capid[i])
+ return 1;
+ }
+ return 0;
+}
+
+STATIC int ci_cpl_delete_pid (int slot, int pid)
+{
+ if (slot < 0 || slot >= CA_MAX_SLOTS) {
+ return -1;
+ }
+ int i;
+ for (i = 0; i < CA_MAX_PIDS; i++) {
+ if (cpl[slot].pid[i]==pid) {
+ cpl[slot].pid[i] = 0;
+ dbg ("-------> Slot: %d Deleted pid: %04x\n", slot, pid);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+STATIC int ci_cpl_update_pid (int slot, int pid)
+{
+ if (slot < 0 || slot >= CA_MAX_SLOTS) {
+ return -1;
+ }
+ if (!ci_cpl_find_pid (slot, pid)) {
+ int i;
+ for (i = 0; i < CA_MAX_PIDS; i++) {
+ if (!cpl[slot].pid[i]) {
+ cpl[slot].pid[i] = pid;
+ dbg ("-------> Slot: %d Added pid: %04x\n", slot, pid);
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+STATIC int ci_cpl_update_caid (int slot, int caid)
+{
+ if (slot < 0 || slot >= CA_MAX_SLOTS) {
+ return -1;
+ }
+ if (!ci_cpl_find_caid (slot, caid)) {
+ int i;
+ for (i = 0; i < CA_MAX_CAIDS; i++) {
+ if (!cpl[slot].caid[i]) {
+ cpl[slot].caid[i] = caid;
+ dbg ("-------> Slot: %d Added caid: %04x\n", slot, caid);
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+STATIC int ci_cpl_update_capid (int slot, int capid)
+{
+ if (slot < 0 || slot >= CA_MAX_SLOTS) {
+ return -1;
+ }
+ if (!ci_cpl_find_capid (slot, capid)) {
+ int i;
+ for (i = 0; i < CA_MAX_PIDS; i++) {
+ if (!cpl[slot].capid[i]) {
+ cpl[slot].capid[i] = capid;
+ dbg ("-------> Slot: %d Added capid: %04x\n", slot, capid);
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+int ci_cpl_find_caid_by_pid (int pid)
+{
+ int i;
+ int slot;
+
+ if(!pid) {
+ return 0;
+ }
+ for (slot = 0; slot < CA_MAX_SLOTS; slot++) {
+ for (i = 0; i < CA_MAX_PIDS; i++) {
+ if (pid == cpl[slot].pid[i]) {
+ return cpl[slot].caid[0];
+ }
+ }
+ }
+ return 0;
+}
+
+int ci_cpl_find_slot_by_caid_and_pid (int caid, int pid)
+{
+ int slot;
+ for (slot = 0; slot < CA_MAX_SLOTS; slot++) {
+ if (ci_cpl_find_pid (slot, pid) && ci_cpl_find_caid (slot, caid)) {
+ return slot;
+ }
+ }
+ return -1;
+}
+
+int ci_cpl_clear (int slot)
+{
+ if (slot < 0 || slot >= CA_MAX_SLOTS) {
+ return -1;
+ }
+ memset (&cpl[slot], 0, sizeof (caid_pid_list_t));
+ return 0;
+}
+
+int ci_cpl_clear_pids (int slot)
+{
+ if (slot < 0 || slot >= CA_MAX_SLOTS) {
+ return -1;
+ }
+ memset (cpl[slot].pid, 0, sizeof (u_int16_t) * CA_MAX_PIDS);
+ return 0;
+}
+
+int ci_cpl_clear_caids (int slot)
+{
+ if (slot < 0 || slot >= CA_MAX_SLOTS) {
+ return -1;
+ }
+ memset (cpl[slot].caid, 0, sizeof (u_int16_t) * CA_MAX_CAIDS);
+ return 0;
+}
+
+int ci_cpl_clear_capids (int slot)
+{
+ if (slot < 0 || slot >= CA_MAX_SLOTS) {
+ return -1;
+ }
+ memset (cpl[slot].capid, 0, sizeof (u_int16_t) * CA_MAX_PIDS);
+ return 0;
+}
+
+STATIC int ci_decode_length (unsigned int *len, u_int8_t * v)
+{
+ int ret = 0;
+
+ if (*v & LENGTH_SIZE_INDICATOR) {
+ int l = *v & 0x7f;
+ if (l > 4) {
+ return -1;
+ }
+ ret = l + 1;
+ *len = 0;
+ while (l--) {
+ v++;
+ *len <<= 8;
+ *len |= *v;
+ }
+ } else {
+ *len = *v;
+ ret = 1;
+ }
+ return ret;
+}
+
+#if 0
+STATIC int ci_decode_al_ca_info (ci_al_t * al)
+{
+ int i = 0;
+ u_int8_t *data = al->data;
+ int len = al->length;
+
+ if (len & 1) {
+ dbg ("ci_decode_al_ca_info: invalid length %d\n", len);
+ }
+
+ len >>= 1;
+
+ u_int16_t *caid = (u_int16_t *) malloc (sizeof (u_int16_t) * len);
+ ci_cpl_clear_caids (al->sl->tl->ll->slot);
+ while (i < len) {
+ caid[i++] = ntohs16 (data);
+ data += 2;
+ ci_cpl_update_caid (al->sl->tl->ll->slot, caid[i - 1]);
+ dbg ("CAID[%d]: %04x\n", i - 1, caid[i - 1]);
+ }
+ if (caid) {
+ free (caid);
+ }
+ return data - al->data;
+}
+#endif
+
+STATIC int ca_decode_ca_descr (ca_desc_t ** cadescr, int count, u_int8_t * data, int len, int *magic)
+{
+ *cadescr = (ca_desc_t *) realloc (*cadescr, sizeof (ca_desc_t *) * (count + 1));
+ if (!*cadescr) {
+ err ("ca_decode_ca_descr: out of memory\n");
+ }
+ ca_desc_t *c = *cadescr + count;
+
+// u_int8_t descriptor_tag = *data;
+ data++;
+ u_int8_t descriptor_length = *data;
+ data++;
+ c->ca_id = ntohs16 (data);
+ data += 2;
+ c->ca_pid = ntohs16 (data);
+ data += 2;
+ dbg ("cadescr: %p %d ca_id: %04x ca_pid: %04x\n", cadescr, count, c->ca_id, c->ca_pid);
+ if(magic && c->ca_id > 0 && c->ca_id < 3 && c->ca_pid > 0 && c->ca_pid < 3 && c->ca_id == c->ca_pid){
+ *magic = c->ca_id;
+ }
+ return descriptor_length + 2;
+}
+
+
+STATIC int ci_decode_al_ca_pmt (ci_al_t * al)
+{
+ ca_pmt_t p;
+ int magic = 0;
+ int slot = 0;
+ int cleared = 0;
+
+ memset (&p, 0, sizeof (ca_pmt_t));
+
+ int ret;
+ u_int8_t *data = al->data;
+ int len;
+
+ p.ca_pmt_list_management = *data;
+ data++;
+
+ p.program_number = ntohs16 (data);
+ data += 2;
+
+ p.version_number = *data;
+ data++;
+
+ p.program_info_length = (u_int16_t) ntohs16 (data);
+ data += 2;
+
+ dbg ("ci_decode_al_ca_pmt: ca_pmt_list_management:%02x program_number:%04x version_number:%02x program_info_length:%04x\n", p.ca_pmt_list_management, p.program_number, p.version_number, p.program_info_length);
+ if (p.program_info_length) {
+ int ca_descr_count = 0;
+ len = p.program_info_length - 1;
+ p.ca_pmt_cmd_id = *data;
+ dbg ("p.ca_pmt_cmd_id:%02x\n", p.ca_pmt_cmd_id);
+ data++;
+ while (len>0) {
+ ret = ca_decode_ca_descr (&p.cadescr, ca_descr_count, data, len, &magic);
+ if (magic)
+ slot = magic - 1;
+ else
+ slot = al->sl->tl->ll->slot;
+ if (!cleared) {
+ if(p.ca_pmt_list_management == CPLM_ONLY || p.ca_pmt_list_management == CPLM_FIRST || p.ca_pmt_list_management == CPLM_UPDATE) {
+ ci_cpl_clear_pids(slot);
+ ci_cpl_clear_capids(slot);
+ ci_cpl_clear_caids(slot);
+ cleared = 1;
+ }
+ }
+ if (ret < 0) {
+ warn ("error decoding ca_descriptor\n");
+ break;
+ }
+ if((magic != p.cadescr[ca_descr_count].ca_id) || (magic != p.cadescr[ca_descr_count].ca_pid)){
+ ci_cpl_update_caid (slot, p.cadescr[ca_descr_count].ca_id);
+ ci_cpl_update_capid (slot, p.cadescr[ca_descr_count].ca_pid);
+ }
+ ca_descr_count++;
+ data += ret;
+ len -= ret;
+ }
+ if (p.cadescr) {
+ free (p.cadescr);
+ }
+ }
+
+ len = al->length - (data - al->data);
+ int pidn = 0;
+
+ while (len>0) {
+ p.pidinfo = (pidinfo_t *) realloc (p.pidinfo, sizeof (pidinfo_t) * (pidn + 1));
+ if (!p.pidinfo) {
+ err ("ci_decode_al_ca_pmt: out of memory");
+ }
+ memset (&p.pidinfo[pidn], 0, sizeof (pidinfo_t));
+ p.pidinfo[pidn].stream_type = *data;
+ data++;
+ len--;
+ p.pidinfo[pidn].pid = ntohs16 (data);
+ data += 2;
+ len -= 2;
+ p.pidinfo[pidn].es_info_length = ntohs16 (data);
+ data += 2;
+ len -= 2;
+
+ dbg ("len: %d count: %d, stream_type: %02x, pid: %04x es_info_length: %04x\n", len, pidn, p.pidinfo[pidn].stream_type, p.pidinfo[pidn].pid, p.pidinfo[pidn].es_info_length);
+ if (p.pidinfo[pidn].es_info_length) {
+ int pi_len = p.pidinfo[pidn].es_info_length - 1;
+ p.pidinfo[pidn].ca_pmt_cmd_id = *data;
+ data++;
+ len--;
+ int pid_ca_descr_count = 0;
+ while (pi_len>0) {
+ ret = ca_decode_ca_descr (&p.pidinfo[pidn].cadescr, pid_ca_descr_count, data, pi_len, NULL);
+ if (!cleared) {
+ if(p.ca_pmt_list_management == CPLM_ONLY || p.ca_pmt_list_management == CPLM_FIRST || p.ca_pmt_list_management == CPLM_UPDATE) {
+ ci_cpl_clear_pids(slot);
+ ci_cpl_clear_capids(slot);
+ ci_cpl_clear_caids(slot);
+ cleared = 1;
+ }
+ }
+ if (ret < 0) {
+ warn ("error decoding ca_descriptor\n");
+ break;
+ }
+ if((magic != p.pidinfo[pidn].cadescr[pid_ca_descr_count].ca_id) || (magic != p.pidinfo[pidn].cadescr[pid_ca_descr_count].ca_pid)){
+ ci_cpl_update_pid (slot, p.pidinfo[pidn].pid);
+ ci_cpl_update_caid (slot, p.pidinfo[pidn].cadescr[pid_ca_descr_count].ca_id);
+ ci_cpl_update_capid (slot, p.pidinfo[pidn].cadescr[pid_ca_descr_count].ca_pid);
+ }
+ pid_ca_descr_count++;
+ data += ret;
+ pi_len -= ret;
+ len -= ret;
+ }
+ }
+ if (p.pidinfo[pidn].cadescr) {
+ free (p.pidinfo[pidn].cadescr);
+ }
+ pidn++;
+ }
+ if (p.pidinfo) {
+ free (p.pidinfo);
+ }
+ return 0;
+}
+
+STATIC int ci_decode_al_ca_pmt_reply (ci_al_t * al)
+{
+ ca_pmt_reply_t p;
+
+ memset (&p, 0, sizeof (ca_pmt_reply_t));
+
+ u_int8_t *data = al->data;
+ int len;
+
+ p.program_number = ntohs16 (data);
+ data += 2;
+
+ p.version_number = *data;
+ data++;
+
+ p.ca_enable = *data;
+ data++;
+
+ len = al->length - (data - al->data);
+ int pidn = 0;
+
+ dbg ("ci_decode_al_ca_pmt_reply: program_number: %04x ca_enable: %02x\n", p.program_number, p.ca_enable);
+
+ while (len>0) {
+ p.pidcaenable = (pid_ca_enable_t *) realloc (p.pidcaenable, sizeof (pid_ca_enable_t) * (pidn + 1));
+ if (!p.pidcaenable) {
+ err ("ci_decode_al_ca_pmt_reply: out of memory\n");
+ }
+ memset (&p.pidcaenable[pidn], 0, sizeof (pid_ca_enable_t));
+ p.pidcaenable[pidn].pid = ntohs16 (data);
+ data += 2;
+ p.pidcaenable[pidn].ca_enable = *data;
+ data++;
+ len -= 3;
+ if ((p.pidcaenable[pidn].ca_enable == CPCI_OK_DESCRAMBLING) || (p.pidcaenable[pidn].ca_enable == CPCI_OK_MMI) || (p.pidcaenable[pidn].ca_enable == CPCI_QUERY)) {
+ ci_cpl_update_pid (al->sl->tl->ll->slot, p.pidcaenable[pidn].pid);
+ } else {
+ ci_cpl_delete_pid (al->sl->tl->ll->slot, p.pidcaenable[pidn].pid);
+ }
+ dbg ("count: %d pid: %04x pid_ca_enable: %02x\n", pidn, p.pidcaenable[pidn].pid, p.pidcaenable[pidn].ca_enable);
+ pidn++;
+ }
+ if (p.pidcaenable) {
+ free (p.pidcaenable);
+ }
+ return 0;
+}
+
+STATIC int ci_decode_al (ci_sl_t * sl)
+{
+ int ret = 0;
+ int done = 0;
+ int len = 3;
+ ci_al_t al;
+ u_int8_t *data = sl->data;
+ al.sl = sl;
+
+ al.tag = 0;
+ while (len--) {
+ al.tag <<= 8;
+ al.tag |= *data;
+ data++;
+ }
+ done += 3;
+ ret = ci_decode_length (&al.length, data);
+ if (ret < 0) {
+ warn ("ci_decode_al ci_decode_length failed\n");
+ return ret;
+ }
+
+ data += ret;
+ done += ret;
+ //Fake
+ al.data = data;
+
+ dbg ("ci_decode_al: tag:%03x length: %02x data[0]:%02x done: %02x\n", al.tag, al.length, al.data[0], done);
+
+ switch (al.tag) {
+ case AOT_CA_INFO:
+// ci_decode_al_ca_info (&al);
+ break;
+ case AOT_CA_PMT:
+ ci_decode_al_ca_pmt (&al);
+ break;
+ case AOT_CA_PMT_REPLY:
+ ci_decode_al_ca_pmt_reply (&al);
+ break;
+ }
+
+ done += al.length;
+
+ dbg ("ci_decode_al: done %02x\n", done);
+ return done;
+}
+
+STATIC int ci_decode_sl (ci_tl_t * tl)
+{
+ int ret = 0;
+ int done = 0;
+ unsigned int len;
+ ci_sl_t sl;
+ u_int8_t *data = tl->data;
+ sl.tl = tl;
+
+ sl.tag = *data;
+ data++;
+ done++;
+
+ if(sl.tag != ST_SESSION_NUMBER) {
+ return tl->length;
+ }
+
+ ret = ci_decode_length (&len, data);
+ if (ret < 0) {
+ warn ("ci_decode_sl ci_decode_length failed\n");
+ return ret;
+ }
+ data += ret;
+ done += ret;
+
+ if (len > 4) {
+ warn ("invalid length (%d) for session_object_value\n", len);
+ return -1;
+ }
+
+ sl.object_value = 0;
+ while (len--) {
+ sl.object_value <<= 8;
+ sl.object_value |= *data;
+ data++;
+ done++;
+ }
+
+ sl.data = data;
+ sl.length = tl->length - done;
+
+ while (sl.length>0) {
+ dbg ("ci_decode_sl: object_value:%02x length: %02x done: %02x\n", sl.object_value, sl.length, done);
+ ret = ci_decode_al (&sl);
+ if (ret < 0) {
+ warn ("ci_decode_al failed\n");
+ return ret;
+ }
+ sl.length -= ret;
+ sl.data += ret;
+ done += ret;
+ }
+ dbg ("ci_decode_sl: done %02x\n", done);
+ return done;
+}
+
+STATIC int ci_decode_tl (ci_ll_t * ll)
+{
+ int ret = 0;
+ int done = 0;
+ ci_tl_t tl;
+ u_int8_t *data = ll->data;
+ tl.ll = ll;
+
+ tl.c_tpdu_tag = *data;
+ data++;
+ done++;
+
+ ret = ci_decode_length (&tl.length, data);
+ if (ret < 0) {
+ warn ("ci_decode_tl ci_decode_length failed\n");
+ return ret;
+ }
+
+ data += ret;
+ done += ret;
+
+ tl.tcid = *data;
+ data++;
+ done++;
+
+ if (tl.tcid != ll->tcid) {
+ warn ("Error: redundant tcid mismatch %02x %02x\n",tl.tcid, ll->tcid);
+ return -1;
+ }
+
+ tl.data = data;
+
+ //According to A.4.1.1
+ tl.length--;
+
+ while (tl.length>0) {
+ dbg ("ci_decode_tl: c_tpdu_tag:%02x tcid:%02x length: %02x done: %02x\n", tl.c_tpdu_tag, tl.tcid, tl.length, done);
+ if (tl.c_tpdu_tag == T_DATA_LAST || tl.c_tpdu_tag == T_DATA_MORE) {
+ ret = ci_decode_sl (&tl);
+ if (ret < 0) {
+ warn ("ci_decode_sl failed\n");
+ return ret;
+ }
+ } else {
+ ret = tl.length;
+ }
+ tl.length -= ret;
+ tl.data += ret;
+ done += ret;
+ }
+ dbg ("ci_decode_tl: done %02x\n", done);
+ return done;
+}
+
+int ci_decode_ll (uint8_t * tpdu, int len)
+{
+ int ret = 0;
+ int done = 0;
+ u_int8_t *data=tpdu;
+ ci_ll_t ll;
+ dump(tpdu,len);
+
+ ll.slot = *data;
+ data++;
+
+ ll.tcid = *data;
+ data++;
+
+ ll.data = data;
+ ll.length = len - (data-tpdu);
+
+ while (ll.length) {
+
+ dbg ("ci_decode_ll: slot:%02x tcid:%02x length: %02x\n", ll.slot, ll.tcid, ll.length);
+ ret = ci_decode_tl (&ll);
+ if (ret < 0) {
+ warn ("ci_decode_tl failed\n");
+ return ret;
+ }
+ ll.length -= ret;
+ ll.data += ret;
+ }
+ dbg ("ci_decode_ll: done %02x\n", len);
+ return done;
+}
+
+#ifdef TESTING
+int main (int argc, char **argv)
+{
+ int ret;
+
+ printf ("ci_decode_ll len: %02x\n", sizeof (lb));
+ ret = ci_decode_ll (lb, sizeof (lb));
+ printf ("ci_decode_ll ret: %02x\n", ret);
+
+ printf ("ci_decode_ll len: %02x\n", sizeof (ll));
+ ret = ci_decode_ll (ll, sizeof (ll));
+ printf ("ci_decode_ll ret: %02x\n", ret);
+
+
+ printf ("ci_decode_ll len: %02x\n", sizeof (ld));
+ ret = ci_decode_ll (ld, sizeof (ld));
+ printf ("ci_decode_ll ret: %02x\n", ret);
+
+ printf ("ci_decode_ll len: %02x\n", sizeof (lc));
+ ret = ci_decode_ll (lc, sizeof (lc));
+ printf ("ci_decode_ll ret: %02x\n", ret);
+
+ printf ("ci_decode_ll len: %02x\n", sizeof (le));
+ ret = ci_decode_ll (le, sizeof (le));
+ printf ("ci_decode_ll ret: %02x\n", ret);
+
+// printf ("caid %04x for pid %04x\n", ci_cpl_find_caid_by_pid (0x5c), 0x5c);
+ return 0;
+}
+#endif
diff --git a/mcast/common/ciparser.h b/mcast/common/ciparser.h
new file mode 100644
index 0000000..44cb810
--- /dev/null
+++ b/mcast/common/ciparser.h
@@ -0,0 +1,140 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ */
+
+#define ntohs16(data) ((u_int16_t)data[0]<<8 | (u_int16_t)data[1])
+typedef struct {
+ u_int16_t len;
+ u_int8_t *data;
+} ci_pdu_t;
+
+typedef struct
+{
+ u_int8_t slot;
+ u_int8_t tcid;
+ u_int32_t length;
+ u_int8_t *data;
+} ci_ll_t;
+
+typedef struct
+{
+ ci_ll_t *ll;
+ u_int8_t c_tpdu_tag;
+ u_int32_t length;
+ u_int8_t tcid;
+ u_int8_t *data;
+} ci_tl_t;
+
+typedef struct
+{
+ ci_tl_t *tl;
+ u_int8_t tag;
+ u_int32_t length;
+ u_int32_t object_value;
+ u_int8_t *data;
+} ci_sl_t;
+
+typedef struct
+{
+ ci_sl_t *sl;
+ u_int32_t tag;
+ u_int32_t length;
+ u_int8_t *data;
+} ci_al_t;
+
+typedef struct
+{
+ u_int16_t ca_id;
+ u_int16_t ca_pid;
+} ca_desc_t;
+
+typedef struct
+{
+ u_int8_t stream_type;
+ u_int16_t pid;
+ u_int16_t es_info_length;
+ u_int8_t ca_pmt_cmd_id;
+ ca_desc_t *cadescr;
+} pidinfo_t;
+
+typedef struct
+{
+ u_int8_t ca_pmt_list_management;
+ u_int16_t program_number;
+ u_int8_t version_number;
+ u_int8_t current_next;
+ u_int16_t program_info_length;
+ u_int8_t ca_pmt_cmd_id;
+ ca_desc_t *cadescr;
+ pidinfo_t *pidinfo;
+} ca_pmt_t;
+
+typedef struct
+{
+ u_int16_t pid;
+ u_int8_t ca_enable;
+} pid_ca_enable_t;
+
+typedef struct
+{
+ u_int16_t program_number;
+ u_int8_t version_number;
+ u_int8_t current_next;
+ u_int8_t ca_enable;
+ pid_ca_enable_t *pidcaenable;
+} ca_pmt_reply_t;
+
+
+#define LENGTH_SIZE_INDICATOR 0x80
+
+#define CPLM_MORE 0x00
+#define CPLM_FIRST 0x01
+#define CPLM_LAST 0x02
+#define CPLM_ONLY 0x03
+#define CPLM_ADD 0x04
+#define CPLM_UPDATE 0x05
+
+#define CPCI_OK_DESCRAMBLING 0x01
+#define CPCI_OK_MMI 0x02
+#define CPCI_QUERY 0x03
+#define CPCI_NOT_SELECTED 0x04
+
+#define AOT_CA_INFO_ENQ 0x9F8030
+#define AOT_CA_INFO 0x9F8031
+#define AOT_CA_PMT 0x9F8032
+#define AOT_CA_PMT_REPLY 0x9F8033
+
+#define ST_SESSION_NUMBER 0x90
+#define ST_OPEN_SESSION_REQUEST 0x91
+#define ST_OPEN_SESSION_RESPONSE 0x92
+#define ST_CREATE_SESSION 0x93
+#define ST_CREATE_SESSION_RESPONSE 0x94
+#define ST_CLOSE_SESSION_REQUEST 0x95
+#define ST_CLOSE_SESSION_RESPONSE 0x96
+
+#define DATA_INDICATOR 0x80
+
+#define T_SB 0x80
+#define T_RCV 0x81
+#define T_CREATE_TC 0x82
+#define T_CTC_REPLY 0x83
+#define T_DELETE_TC 0x84
+#define T_DTC_REPLY 0x85
+#define T_REQUEST_TC 0x86
+#define T_NEW_TC 0x87
+#define T_TC_ERROR 0x88
+#define T_DATA_LAST 0xA0
+#define T_DATA_MORE 0xA1
+
+
+DLL_SYMBOL int ci_cpl_find_caid_by_pid (int pid);
+DLL_SYMBOL int ci_cpl_find_slot_by_caid_and_pid (int caid, int pid);
+DLL_SYMBOL int ci_cpl_clear (int slot);
+DLL_SYMBOL int ci_cpl_clear_pids (int slot);
+DLL_SYMBOL int ci_cpl_clear_caids (int slot);
+DLL_SYMBOL int ci_cpl_clear_capids (int slot);
+DLL_SYMBOL int ci_decode_ll (uint8_t * data, int len);
diff --git a/mcast/common/crc32.c b/mcast/common/crc32.c
new file mode 100644
index 0000000..65f08ac
--- /dev/null
+++ b/mcast/common/crc32.c
@@ -0,0 +1,88 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ */
+
+/*
+$Id: crc32.c,v 1.2 2006/01/02 18:24:04 rasc Exp $
+
+
+ DVBSNOOP
+
+ a dvb sniffer and mpeg2 stream analyzer tool
+ http://dvbsnoop.sourceforge.net/
+
+ (c) 2001-2006 Rainer.Scherg@gmx.de (rasc)
+
+
+ -- Code Module CRC32 taken von linuxtv.org
+*/
+
+
+
+
+#include "defs.h"
+#include "crc32.h"
+
+
+
+// CRC32 lookup table for polynomial 0x04c11db7
+
+static u_long crc_table[256] = {
+ 0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b,
+ 0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
+ 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7,
+ 0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
+ 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3,
+ 0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
+ 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef,
+ 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
+ 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb,
+ 0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1,
+ 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0,
+ 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
+ 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4,
+ 0x0808d07d, 0x0cc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde,
+ 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08,
+ 0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
+ 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc,
+ 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6,
+ 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050,
+ 0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
+ 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34,
+ 0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637,
+ 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1,
+ 0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
+ 0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5,
+ 0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
+ 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9,
+ 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
+ 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd,
+ 0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7,
+ 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71,
+ 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
+ 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2,
+ 0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8,
+ 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e,
+ 0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
+ 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a,
+ 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0,
+ 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676,
+ 0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
+ 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662,
+ 0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668,
+ 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4};
+
+uint32_t dvb_crc32 (char *data, int len)
+{
+ register int i;
+ u_long crc = 0xffffffff;
+
+ for (i=0; i<len; i++)
+ crc = (crc << 8) ^ crc_table[((crc >> 24) ^ *data++) & 0xff];
+
+ return crc;
+}
diff --git a/mcast/common/crc32.h b/mcast/common/crc32.h
new file mode 100644
index 0000000..f4bef5e
--- /dev/null
+++ b/mcast/common/crc32.h
@@ -0,0 +1,35 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ */
+
+/*
+$Id: crc32.h,v 1.2 2006/01/02 18:24:04 rasc Exp $
+
+
+ DVBSNOOP
+
+ a dvb sniffer and mpeg2 stream analyzer tool
+ http://dvbsnoop.sourceforge.net/
+
+ (c) 2001-2006 Rainer.Scherg@gmx.de (rasc)
+
+
+ -- Code Module CRC32 taken von linuxtv.org
+
+*/
+
+
+
+#ifndef __CRC32_H
+#define __CRC32_H
+
+
+uint32_t dvb_crc32 (char *data, int len);
+
+
+#endif
+
diff --git a/mcast/common/darwin/.svn/entries b/mcast/common/darwin/.svn/entries
new file mode 100644
index 0000000..884c498
--- /dev/null
+++ b/mcast/common/darwin/.svn/entries
@@ -0,0 +1,31 @@
+10
+
+dir
+18963
+svn://reelbox.org/testing/src/vdr-plugins/src/mcli-1/mcast/common/darwin
+svn://reelbox.org
+
+
+
+2011-07-12T13:36:23.313379Z
+16905
+rollercoaster
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+12be777f-adf9-0310-842f-e37ecc4c7426
+
+include
+dir
+
diff --git a/mcast/common/darwin/include/.svn/entries b/mcast/common/darwin/include/.svn/entries
new file mode 100644
index 0000000..04c4a12
--- /dev/null
+++ b/mcast/common/darwin/include/.svn/entries
@@ -0,0 +1,62 @@
+10
+
+dir
+18963
+svn://reelbox.org/testing/src/vdr-plugins/src/mcli-1/mcast/common/darwin/include
+svn://reelbox.org
+
+
+
+2011-07-12T13:36:23.313379Z
+16905
+rollercoaster
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+12be777f-adf9-0310-842f-e37ecc4c7426
+
+linux
+file
+
+
+
+
+2012-09-27T17:22:49.586848Z
+e366d17ffb75fe35b2b26671aa0c3471
+2011-07-12T13:36:23.313379Z
+16905
+rollercoaster
+has-props
+
+
+svn:special
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+25
+
diff --git a/mcast/common/darwin/include/.svn/prop-base/linux.svn-base b/mcast/common/darwin/include/.svn/prop-base/linux.svn-base
new file mode 100644
index 0000000..d222469
--- /dev/null
+++ b/mcast/common/darwin/include/.svn/prop-base/linux.svn-base
@@ -0,0 +1,5 @@
+K 11
+svn:special
+V 1
+*
+END
diff --git a/mcast/common/darwin/include/.svn/text-base/linux.svn-base b/mcast/common/darwin/include/.svn/text-base/linux.svn-base
new file mode 100644
index 0000000..af4b301
--- /dev/null
+++ b/mcast/common/darwin/include/.svn/text-base/linux.svn-base
@@ -0,0 +1 @@
+link ../../win32/include/linux \ No newline at end of file
diff --git a/mcast/common/darwin/include/linux b/mcast/common/darwin/include/linux
new file mode 120000
index 0000000..72e4ad7
--- /dev/null
+++ b/mcast/common/darwin/include/linux
@@ -0,0 +1 @@
+../../win32/include/linux \ No newline at end of file
diff --git a/mcast/common/defs.h b/mcast/common/defs.h
new file mode 100644
index 0000000..979b339
--- /dev/null
+++ b/mcast/common/defs.h
@@ -0,0 +1,389 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ */
+
+#ifndef __DEFS_H__
+#define __DEFS_H__
+
+#ifdef WIN32
+ #ifdef __CYGWIN__
+ #include <cygwin/version.h>
+ #include <cygwin/in.h>
+ #include <cygwin/socket.h>
+ #else
+ #define _CRT_SECURE_NO_WARNINGS
+ #define _WIN32_WINNT 0x0502
+ #include <winsock2.h>
+ #include <WS2tcpip.h>
+ #include <iphlpapi.h>
+
+ #define _SOTYPE char*
+ #define IFNAMSIZ 1024
+ #define CA_TPDU_MAX 2048
+ #define _POSIX_PATH_MAX MAX_PATH
+ #define usleep(useconds) Sleep((useconds+500)/1000)
+ #define sleep(seconds) Sleep((seconds)*1000)
+ #define EAFNOSUPPORT WSAEAFNOSUPPORT
+ #ifndef IP_ADAPTER_IPV6_ENABLED
+ #define IP_ADAPTER_IPV6_ENABLED 0x0100
+ #endif
+
+ int inet_pton(int af, const char *src, void *dst);
+ const char *inet_ntop(int af, const void *src, char *dst, size_t size);
+ int inet_aton(const char *cp, struct in_addr *addr);
+ #ifndef __MINGW32__
+ int getopt(int nargc, char **nargv, char *ostr);
+ extern int opterr, optind, optopt, optreset;
+ extern char *optarg;
+ #define inline __inline
+ #endif
+
+ typedef struct
+ {
+ DWORD thread;
+ HANDLE threadH; /* Win32 thread handle - POSIX thread is invalid if threadH == 0 */
+ } ptw32_thread_t;
+
+ typedef unsigned int uint32_t;
+ typedef uint32_t __u32;
+ typedef uint32_t u_int32_t;
+ typedef unsigned short uint16_t;
+ typedef uint16_t __u16;
+ typedef uint16_t u_int16_t;
+ typedef unsigned char uint8_t;
+ typedef uint8_t __u8;
+ typedef uint8_t u_int8_t;
+ #ifndef s6_addr16
+ #define s6_addr16 s6_words
+ #endif
+ #if ! defined _GNU_SOURCE && defined __cplusplus
+ #define CALLCONV extern "C"
+ #else
+ #define CALLCONV
+ #endif
+ #ifdef LIBRARY
+ #define DLL_SYMBOL CALLCONV __declspec( dllexport )
+ #else
+ #ifdef STATICLIB
+ #define DLL_SYMBOL CALLCONV
+ #else
+ #define DLL_SYMBOL CALLCONV __declspec( dllimport )
+ #endif
+ #endif
+
+ #define pthread_exist(x) (x).p
+ #define pthread_null(x) (x).p=NULL
+ #define _SOTYPE char*
+ #define INET6
+ #define API_WIN
+ #define LIBXML_STATIC
+ #define PTW32_STATIC_LIB
+ #define MULTI_THREAD_RECEIVER
+
+ #include <poll.h>
+ #endif
+#else
+ #if defined __cplusplus
+ #define CALLCONV extern "C"
+ #else
+ #define CALLCONV
+ #endif
+ #define DLL_SYMBOL CALLCONV
+ #define pthread_exist(x) x
+ #define pthread_null(x) x=0
+ #define _SOTYPE void*
+ #define SOCKET int
+
+ #if ! (defined __uClinux__ || defined APPLE || defined MIPSEL)
+ #include <mcheck.h>
+ #include <ifaddrs.h>
+ #endif
+ #include <pwd.h>
+ #include <sched.h>
+ #include <syslog.h>
+ #include <unistd.h>
+ #include <getopt.h>
+ #include <stdint.h>
+ #include <termios.h>
+
+ #include <arpa/inet.h>
+ #ifndef APPLE
+ #include <linux/version.h>
+ #include <netpacket/packet.h>
+ #include <sys/sysinfo.h>
+ #else
+ typedef unsigned int uint32_t;
+ typedef uint32_t __u32;
+ typedef uint32_t u_int32_t;
+ typedef unsigned short uint16_t;
+ typedef uint16_t __u16;
+ typedef uint16_t u_int16_t;
+ typedef unsigned char uint8_t;
+ typedef uint8_t __u8;
+ typedef uint8_t u_int8_t;
+
+ #define CA_TPDU_MAX 2048
+
+ #define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP
+ #define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP
+ #ifndef s6_addr16
+ #define s6_addr16 __u6_addr.__u6_addr16
+ #endif
+ #endif
+
+ #include <netdb.h>
+
+ #include <net/if.h>
+ #ifdef APPLE
+ #include <ifaddrs.h>
+ #include <net/if_types.h>
+ #endif
+ #include <netinet/in.h>
+ #include <netinet/ip.h>
+ #include <netinet/icmp6.h>
+ #include <netinet/ip_icmp.h>
+ #include <netinet/if_ether.h>
+ #include <netinet/ip6.h>
+ #include <netinet/tcp.h>
+ #include <netinet/udp.h>
+
+ #include <sys/ioctl.h>
+ #include <sys/mman.h>
+ #include <sys/poll.h>
+ #include <sys/resource.h>
+ #include <sys/socket.h>
+ #include <sys/types.h>
+ #include <sys/uio.h> /* for iovec{} and readv/writev */
+ #include <sys/un.h> /* for Unix domain sockets */
+ #include <sys/utsname.h>
+ #include <sys/wait.h>
+
+ #if defined __uClinux__
+ #include <mathf.h>
+ #endif
+ #define closesocket close
+#endif
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <math.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <zlib.h>
+
+#include <sys/stat.h>
+
+//----------------------------------------------------------------------
+#ifndef __uClinux__
+ //DVBAPI
+ #include <linux/dvb/version.h>
+ #include <linux/dvb/frontend.h>
+ #include <linux/dvb/ca.h>
+ #if ! (defined WIN32 || defined APPLE)
+ #include <linux/dvb/dmx.h>
+ #endif
+// #else
+// #endif
+
+ #define dvb_ioctl ioctl
+ #define dvb_close close
+#else
+ #include <dvb/frontend.h>
+ #include <ci/ca.h>
+#endif
+
+#define CA_TPDU_MAX 2048
+
+typedef struct recv_sec
+{
+ struct dvb_diseqc_master_cmd diseqc_cmd;
+ fe_sec_mini_cmd_t mini_cmd;
+ fe_sec_tone_mode_t tone_mode;
+ fe_sec_voltage_t voltage;
+} recv_sec_t;
+
+#define CA_MAX_SLOTS 16
+typedef struct {
+ ca_caps_t cap;
+ ca_slot_info_t info[CA_MAX_SLOTS];
+} recv_cacaps_t;
+
+typedef struct recv_festatus
+{
+ fe_status_t st;
+ uint32_t ber;
+ uint16_t strength;
+ uint16_t snr;
+ uint32_t ucblocks;
+} recv_festatus_t;
+
+//XML
+#include <libxml/encoding.h>
+#include <libxml/xmlwriter.h>
+#include <libxml/xmlmemory.h>
+#include <libxml/parser.h>
+#include <libxml/xpath.h>
+
+#ifdef DMALLOC
+ #include <dmalloc.h>
+#endif
+
+#if ! defined GETTID && ! defined WIN32 && ! defined APPLE
+ #include <asm/unistd.h>
+ #define gettid() syscall (__NR_gettid)
+#else
+ #define gettid pthread_self
+#endif
+
+#define UUID_SIZE 256
+#ifndef WIN32
+
+#ifdef SYSLOG
+extern char *_logstr;
+extern pthread_mutex_t _loglock;
+
+ #ifdef DEBUG
+ #define dbg(format, arg...) { pthread_mutex_lock (&_loglock); sprintf(_logstr, "%s:%d " format , __FILE__ , __LINE__ , ## arg); syslog_write(_logstr); pthread_mutex_unlock (&_loglock);}
+ #else
+ #define dbg(format, arg...) do {} while (0)
+ #endif
+ #define err(format, arg...) {pthread_mutex_lock (&_loglock); sprintf(_logstr, "err:%s:%d: %s (%d): " format , __FILE__ , __LINE__ ,strerror(errno), errno, ## arg); fprintf(stdout, "%s", _logstr); syslog_write(_logstr);abort(); pthread_mutex_unlock (&_loglock);}
+ #define info(format, arg...){pthread_mutex_lock (&_loglock); sprintf(_logstr, format ,## arg); fprintf(stdout, "%s", _logstr); syslog_write(_logstr); pthread_mutex_unlock (&_loglock);}
+ #define warn(format, arg...){pthread_mutex_lock (&_loglock); sprintf(_logstr, format ,## arg); fprintf(stdout, "%s", _logstr); syslog_write(_logstr); pthread_mutex_unlock (&_loglock);}
+ #define sys(format, arg...){pthread_mutex_lock (&_loglock); sprintf(_logstr, format ,## arg); syslog_write(_logstr); pthread_mutex_unlock (&_loglock);}
+#elif defined DEBUG
+ #define dbg(format, arg...) {printf("%s:%d " format , __FILE__ , __LINE__ , ## arg)}
+ #define err(format, arg...) {fprintf(stderr,"err:%s:%d: %s (%d): " format , __FILE__ , __LINE__ ,strerror(errno), errno, ## arg);print_trace();abort();}
+ #define info(format, arg...) printf("%s:%d: " format , __FILE__ , __LINE__ ,## arg)
+ #define warn(format, arg...) fprintf(stderr,"%s:%d: " format , __FILE__ , __LINE__ ,## arg)
+#else
+ #define dbg(format, arg...) do {} while (0)
+ #define err(format, arg...) {fprintf(stderr,"%s (%d): " format, strerror(errno), errno, ## arg);exit(-1);}
+ #define info(format, arg...) printf(format , ## arg)
+ #define warn(format, arg...) fprintf(stderr, format , ## arg)
+ #define sys(format, arg...) printf(format, ## arg)
+#endif // SYSLOG
+
+#else // !WIN32
+ #ifdef DEBUG
+ static void inline dbg (char *format, ...)
+ {
+ char buffer[1024];
+ va_list args;
+ va_start (args, format);
+ vsprintf (buffer, format, args);
+ printf("%s:%d %s", __FILE__ , __LINE__ , buffer);
+ va_end (args);
+ }
+ static void inline err (char *format, ...)
+ {
+ char buffer[1024];
+ va_list args;
+ va_start (args, format);
+ vsprintf(buffer, format , args);
+ fprintf(stderr, "err:%s:%d: %s (%d): %s " , __FILE__ , __LINE__ ,strerror(errno), errno, buffer);
+ va_end (args);
+ abort();
+ }
+ static void inline info(const char *format, ...)
+ {
+ char buffer[1024];
+ va_list args;
+ va_start (args, format);
+ vsprintf(buffer, format , args);
+ printf("%s:%d: %s" , __FILE__ , __LINE__ , buffer);
+ va_end (args);
+ }
+ static void inline warn(const char *format, ...)
+ {
+ char buffer[1024];
+ va_list args;
+ va_start (args, format);
+ vsprintf(buffer, format , args);
+ fprintf(stderr, "%s:%d: %s", __FILE__ , __LINE__ , buffer );
+ va_end (args);
+ }
+ static void inline sys(const char *format, ...)
+ {
+ char buffer[1024];
+ va_list args;
+ va_start (args, format);
+ vsprintf(buffer, format , args);
+ printf("%s:%d: %s", __FILE__ , __LINE__ , buffer );
+ va_end (args);
+ }
+ #else
+ static void inline dbg (char *format, ...)
+ {
+ }
+ static void inline err (char *format, ...)
+ {
+ char buffer[1024];
+ va_list args;
+ va_start (args, format);
+ vsprintf(buffer, format, args);
+ fprintf(stderr, "err:%s:%d: %s",strerror(errno), errno, buffer);
+ va_end (args);
+ abort();
+ }
+ static void inline info(const char *format, ...)
+ {
+ char buffer[1024];
+ va_list args;
+ va_start (args, format);
+ vsprintf(buffer, format, args);
+ puts(buffer);
+ va_end (args);
+ }
+ static void inline warn(const char *format, ...)
+ {
+ char buffer[1024];
+ va_list args;
+ va_start (args, format);
+ vsprintf(buffer, format, args);
+ fputs(buffer, stderr);
+ va_end (args);
+ }
+ static void inline sys(const char *format, ...)
+ {
+ char buffer[1024];
+ va_list args;
+ va_start (args, format);
+ vsprintf(buffer, format, args);
+ fputs(buffer, stdout);
+ va_end (args);
+ }
+
+ #endif //DEBUG
+#endif // WIN32
+
+#ifndef MICROBLAZE
+ #define FE_DVBS2 (FE_ATSC+1)
+#endif
+
+// RMM S2 Extension
+#define FEC_1_4 10
+#define FEC_1_3 11
+#define FEC_2_5 12
+#define FEC_3_5 13
+#define FEC_9_10 14
+#define QPSK_S2 9
+#define PSK8 10
+
+#ifdef MICROBLAZE
+ #define STATIC
+#else
+ #define STATIC static
+#endif
+#endif
diff --git a/mcast/common/dvb_ca_wrapper.h b/mcast/common/dvb_ca_wrapper.h
new file mode 100644
index 0000000..d0873aa
--- /dev/null
+++ b/mcast/common/dvb_ca_wrapper.h
@@ -0,0 +1,18 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ */
+
+#ifndef __DVB_CA_WRAPPER_H
+#define __user
+unsigned int dvb_cam_poll(struct pollfd *pfd, int fdnum, int timeout_ms);
+ssize_t dvb_cam_read(int dummy, char __user * buf, size_t count);
+ssize_t dvb_cam_write(int dummy, char __user * buf, size_t count);
+int dvb_cam_ioctl(int dummy, unsigned int cmd, void *parg);
+int dvb_cam_open(const char* dummy, int dummy1);
+int dvb_cam_close(int fd);
+
+#endif
diff --git a/mcast/common/input.h b/mcast/common/input.h
new file mode 100644
index 0000000..fbda65b
--- /dev/null
+++ b/mcast/common/input.h
@@ -0,0 +1,38 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ */
+
+#ifndef __INPUT_H__
+#define __INPUT_H__
+typedef struct
+{
+ int port;
+ char iface[IFNAMSIZ];
+ time_t start_time;
+#ifdef SERVER
+ int tuner_number;
+ char cfgpath[_POSIX_PATH_MAX];
+ int verbose;
+#endif
+#ifdef CLIENT
+ char disec_conf_path[_POSIX_PATH_MAX];
+ char rotor_conf_path[_POSIX_PATH_MAX];
+ char cmd_sock_path[_POSIX_PATH_MAX];
+ int tuner_type_limit[FE_DVBS2+1];
+ int mld_start;
+ int ca_enable;
+ int ci_timeout;
+ int vdrdiseqcmode;
+ int reelcammode;
+#endif
+} cmdline_t;
+
+extern cmdline_t cmd;
+
+void get_options (int argc, char *argv[]);
+
+#endif
diff --git a/mcast/common/interfaces.c b/mcast/common/interfaces.c
new file mode 100644
index 0000000..bd19c8d
--- /dev/null
+++ b/mcast/common/interfaces.c
@@ -0,0 +1,347 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ */
+
+#include "headers.h"
+
+void int_destroy (struct intnode *intn)
+{
+ dbg ("Destroying interface %s\n", intn->name);
+
+ /* Resetting the MTU to zero disabled the interface */
+ intn->mtu = 0;
+}
+
+struct intnode *int_find (unsigned int ifindex)
+{
+ unsigned int i;
+ for (i = 0; i < g_conf->maxinterfaces; i++) {
+ if(g_conf->ints[i].ifindex == ifindex) {
+ return g_conf->ints+i;
+ }
+ }
+ return NULL;
+}
+
+struct intnode *int_find_name (char *ifname)
+{
+ unsigned int i;
+ for (i = 0; i < g_conf->maxinterfaces; i++) {
+ if (!strcmp (ifname, g_conf->ints[i].name) && g_conf->ints[i].mtu != 0) {
+ return g_conf->ints+i;
+ }
+ }
+ return NULL;
+}
+
+
+struct intnode *int_find_first (void)
+{
+ unsigned int i;
+ for (i = 0; i < g_conf->maxinterfaces; i++) {
+ dbg("int: %d %s\n",i, g_conf->ints[i].name);
+ if (g_conf->ints[i].mtu != 0) {
+ return g_conf->ints+i;
+ }
+ }
+ return NULL;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+#if ! (defined WIN32 || defined APPLE) || defined __CYGWIN__
+
+/* Initiliaze interfaces */
+void update_interfaces (struct intnode *intn)
+{
+ struct in6_addr addr;
+
+ FILE *file;
+ unsigned int prefixlen, scope, flags, ifindex;
+ char devname[IFNAMSIZ];
+
+ /* Only update every 5 seconds to avoid rerunning it every packet */
+ if (g_conf->maxinterfaces)
+ return;
+
+ dbg ("Updating Interfaces\n");
+
+ /* Get link local addresses from /proc/net/if_inet6 */
+ file = fopen ("/proc/net/if_inet6", "r");
+
+ /* We can live without it though */
+ if (!file) {
+ err ("Cannot open /proc/net/if_inet6\n");
+ return;
+ }
+
+ char buf[255];
+ /* Format "fe80000000000000029027fffe24bbab 02 0a 20 80 eth0" */
+ while (fgets (buf, sizeof (buf), file)) {
+ if (21 != sscanf (buf, "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx %x %x %x %x %8s", &addr.s6_addr[0], &addr.s6_addr[1], &addr.s6_addr[2], &addr.s6_addr[3], &addr.s6_addr[4], &addr.s6_addr[5], &addr.s6_addr[6], &addr.s6_addr[7], &addr.s6_addr[8], &addr.s6_addr[9], &addr.s6_addr[10], &addr.s6_addr[11], &addr.s6_addr[12], &addr.s6_addr[13], &addr.s6_addr[14], &addr.s6_addr[15], &ifindex, &prefixlen, &scope, &flags, devname)) {
+
+ warn ("/proc/net/if_inet6 in wrong format!\n");
+ continue;
+ }
+ if (!IN6_IS_ADDR_LINKLOCAL (&addr) && (IN6_IS_ADDR_UNSPECIFIED (&addr) || IN6_IS_ADDR_LOOPBACK (&addr) || IN6_IS_ADDR_MULTICAST (&addr))) {
+ continue;
+ }
+
+ if((intn=int_find(ifindex))==NULL) {
+ g_conf->ints=(struct intnode*)realloc(g_conf->ints, sizeof(struct intnode)*(++g_conf->maxinterfaces));
+ if (!g_conf->ints) {
+ err ("Cannot get memory for interface structures.\n");
+ }
+ intn=g_conf->ints+g_conf->maxinterfaces-1;
+ memset(intn, 0, sizeof(struct intnode));
+ }
+#ifdef WIN32
+ // Ugly WINXP workaround
+ if(scope==0x20 && flags==0x80) {
+ intn->mtu=1480;
+ } else {
+ intn->mtu=0;
+ }
+#else
+ intn->ifindex = ifindex;
+ strcpy(intn->name, devname);
+
+ struct ifreq ifreq;
+ int sock;
+ sock = socket (AF_INET6, SOCK_DGRAM, 0);
+ if (sock < 0) {
+ err ("Cannot get socket for setup\n");
+ }
+
+ memcpy (&ifreq.ifr_name, &intn->name, sizeof (ifreq.ifr_name));
+ /* Get the MTU size of this interface */
+ /* We will use that for fragmentation */
+ if (ioctl (sock, SIOCGIFMTU, &ifreq) != 0) {
+ warn ("Cannot get MTU size for %s index %d: %s\n", intn->name, intn->ifindex, strerror (errno));
+ }
+ intn->mtu = ifreq.ifr_mtu;
+
+ /* Get hardware address + type */
+ if (ioctl (sock, SIOCGIFHWADDR, &ifreq) != 0) {
+ warn ("Cannot get hardware address for %s, interface index %d : %s\n", intn->name, intn->ifindex, strerror (errno));
+ }
+ intn->hwaddr = ifreq.ifr_hwaddr;
+ close (sock);
+#endif
+ /* Link Local IPv6 address ? */
+ if (IN6_IS_ADDR_LINKLOCAL (&addr)) {
+ /* Update the linklocal address */
+ intn->linklocal = addr;
+ } else {
+ intn->global = addr;
+ }
+
+ dbg ("Available interface %s index %u hardware %s/%u MTU %d\n", intn->name, intn->ifindex, (intn->hwaddr.sa_family == ARPHRD_ETHER ? "Ethernet" : (intn->hwaddr.sa_family == ARPHRD_SIT ? "sit" : "Unknown")), intn->hwaddr.sa_family, intn->mtu);
+ }
+
+ fclose (file);
+}
+#endif
+#if defined WIN32 && ! defined __CYGWIN__
+
+unsigned int if_nametoindex (const char *ifname)
+{
+ unsigned int ifindex;
+ for (ifindex = 0; ifindex < g_conf->maxinterfaces; ifindex++) {
+ if (!strcmp (ifname, g_conf->ints[ifindex].name) && g_conf->ints[ifindex].mtu != 0) {
+ return g_conf->ints[ifindex].ifindex;
+ }
+ }
+ return 0;
+}
+
+void update_interfaces (struct intnode *intn)
+{
+
+ /* Declare and initialize variables */
+
+ DWORD dwRetVal = 0;
+
+ int i = 0;
+
+ // Set the flags to pass to GetAdaptersAddresses
+ ULONG flags = GAA_FLAG_INCLUDE_PREFIX;
+
+ // default to unspecified address family (both)
+ ULONG family = AF_INET6;
+
+ PIP_ADAPTER_ADDRESSES pAddresses = NULL;
+ ULONG outBufLen = 0;
+
+ PIP_ADAPTER_ADDRESSES pCurrAddresses = NULL;
+ PIP_ADAPTER_UNICAST_ADDRESS pUnicast = NULL;
+
+ outBufLen = sizeof (IP_ADAPTER_ADDRESSES);
+ pAddresses = (IP_ADAPTER_ADDRESSES *) malloc (outBufLen);
+ if (pAddresses == NULL) {
+ printf ("Memory allocation failed for IP_ADAPTER_ADDRESSES struct\n");
+ exit (1);
+ }
+ // Make an initial call to GetAdaptersAddresses to get the
+ // size needed into the outBufLen variable
+ if (GetAdaptersAddresses (family, flags, NULL, pAddresses, &outBufLen) == ERROR_BUFFER_OVERFLOW) {
+ free (pAddresses);
+ pAddresses = (IP_ADAPTER_ADDRESSES *) malloc (outBufLen);
+ }
+
+ if (pAddresses == NULL) {
+ printf ("Memory allocation failed for IP_ADAPTER_ADDRESSES struct\n");
+ exit (1);
+ }
+
+ dwRetVal = GetAdaptersAddresses (family, flags, NULL, pAddresses, &outBufLen);
+
+ if (dwRetVal == NO_ERROR) {
+ // If successful, output some information from the data we received
+ pCurrAddresses = pAddresses;
+ g_conf->maxinterfaces=0;
+
+ while (pCurrAddresses) {
+
+ if( /* pCurrAddresses->Flags & IP_ADAPTER_IPV6_ENABLED && */ (pCurrAddresses->IfType == IF_TYPE_ETHERNET_CSMACD || pCurrAddresses->IfType == IF_TYPE_IEEE80211) && pCurrAddresses->OperStatus == IfOperStatusUp ) {
+ g_conf->ints=(struct intnode*)realloc(g_conf->ints, sizeof(struct intnode)*(g_conf->maxinterfaces+1));
+ if (!g_conf->ints) {
+ err ("update_interfaces: out of memory\n");
+ }
+ intn=g_conf->ints+g_conf->maxinterfaces;
+ memset(intn, 0, sizeof(struct intnode));
+
+#ifndef __MINGW32__
+ printf ("Interface: %s (%wS)\n", pCurrAddresses->AdapterName, pCurrAddresses->Description);
+ dbg ("\tFriendly name: %wS\n", pCurrAddresses->FriendlyName);
+#else
+ printf ("Interface: %s (%ls)\n", pCurrAddresses->AdapterName, pCurrAddresses->Description);
+ dbg ("\tFriendly name: %ls\n", pCurrAddresses->FriendlyName);
+#endif
+ dbg ("\tFlags: %x\n", pCurrAddresses->Flags);
+ dbg ("\tIfType: %ld\n", pCurrAddresses->IfType);
+ dbg ("\tOperStatus: %ld\n", pCurrAddresses->OperStatus);
+ dbg ("\tMtu: %lu\n", pCurrAddresses->Mtu);
+ dbg ("\tIpv6IfIndex (IPv6 interface): %u\n", pCurrAddresses->Ipv6IfIndex);
+
+ strncpy(intn->name, pCurrAddresses->AdapterName, IFNAMSIZ-1);
+
+ intn->mtu = pCurrAddresses->Mtu;
+ intn->ifindex= pCurrAddresses->Ipv6IfIndex;
+
+ pUnicast = pCurrAddresses->FirstUnicastAddress;
+ if (pUnicast != NULL) {
+ for (i = 0; pUnicast != NULL; i++) {
+ char host[80];
+ inet_ntop (AF_INET6, ((struct sockaddr_in6 *)(pUnicast->Address.lpSockaddr))->sin6_addr.s6_addr, host, sizeof(host));
+ dbg("\tIP:%s LL:%d\n",host, IN6_IS_ADDR_LINKLOCAL(&((struct sockaddr_in6 *)(pUnicast->Address.lpSockaddr))->sin6_addr));
+ if(IN6_IS_ADDR_LINKLOCAL(&((struct sockaddr_in6 *)(pUnicast->Address.lpSockaddr))->sin6_addr)) {
+ intn->linklocal=((struct sockaddr_in6 *)(pUnicast->Address.lpSockaddr))->sin6_addr;
+ } else {
+ intn->global=((struct sockaddr_in6 *)(pUnicast->Address.lpSockaddr))->sin6_addr;
+ }
+ pUnicast = pUnicast->Next;
+ }
+ dbg ("\tNumber of Unicast Addresses: %d\n", i);
+ }
+#ifdef DEBUG
+ if (pCurrAddresses->PhysicalAddressLength != 0) {
+ dbg ("\tPhysical address: ");
+ for (i = 0; i < (int) pCurrAddresses->PhysicalAddressLength; i++) {
+ if (i == (pCurrAddresses->PhysicalAddressLength - 1))
+ printf ("%.2X\n", (int) pCurrAddresses->PhysicalAddress[i]);
+ else
+ printf ("%.2X:", (int) pCurrAddresses->PhysicalAddress[i]);
+ }
+ }
+#endif
+ g_conf->maxinterfaces++;
+ }
+ pCurrAddresses = pCurrAddresses->Next;
+ }
+ }
+
+ free (pAddresses);
+}
+
+#endif
+#ifdef APPLE
+void update_interfaces (struct intnode *intn)
+{
+ struct ifaddrs *myaddrs, *ifa;
+ struct sockaddr_in *s4;
+ struct sockaddr_in6 *s6;
+ int if_index;
+ /*
+ * buf must be big enough for an IPv6 address (e.g.
+ * 3ffe:2fa0:1010:ca22:020a:95ff:fe8a:1cf8)
+ */
+ char buf[64];
+
+ if (getifaddrs(&myaddrs)) {
+ err ("getifaddrs");
+ }
+
+ for (ifa = myaddrs; ifa != NULL; ifa = ifa->ifa_next) {
+ if (ifa->ifa_addr == NULL)
+ continue;
+ if ((ifa->ifa_flags & IFF_UP) == 0)
+ continue;
+
+ if_index=if_nametoindex(ifa->ifa_name);
+ dbg("%s(%d): ", ifa->ifa_name,if_index);
+
+ if(!if_index) {
+ warn("cannot get interface index for %s\n",ifa->ifa_name);
+ continue;
+ }
+
+ if((intn=int_find(if_index))==NULL) {
+ g_conf->ints=(struct intnode*)realloc(g_conf->ints, sizeof(struct intnode)*(++g_conf->maxinterfaces));
+ if (!g_conf->ints) {
+ err ("Cannot get memory for interface structures.\n");
+ }
+ intn=g_conf->ints+g_conf->maxinterfaces-1;
+ memset(intn, 0, sizeof(struct intnode));
+ }
+
+ intn->ifindex=if_index;
+ strcpy(intn->name,ifa->ifa_name);
+
+ if(ifa->ifa_addr->sa_family == AF_LINK && ((struct if_data *)ifa->ifa_data)->ifi_type != IFT_LOOP && ifa->ifa_data) {
+ dbg("MTU: %d\n", ((struct if_data *)ifa->ifa_data)->ifi_mtu);
+ intn->mtu=((struct if_data *)ifa->ifa_data)->ifi_mtu;
+ memcpy(&intn->hwaddr, ifa->ifa_addr, sizeof(struct sockaddr_in));
+ }
+
+ if (ifa->ifa_addr->sa_family == AF_INET) {
+ s4 = (struct sockaddr_in *) (ifa->ifa_addr);
+ if (inet_ntop(ifa->ifa_addr->sa_family, (void *) &(s4->sin_addr), buf, sizeof(buf)) == NULL) {
+ warn("%s: inet_ntop failed!\n", ifa->ifa_name);
+ } else {
+ dbg("%s\n", buf);
+ }
+ } else if (ifa->ifa_addr->sa_family == AF_INET6) {
+ s6 = (struct sockaddr_in6 *) (ifa->ifa_addr);
+ /* Link Local IPv6 address ? */
+ if (IN6_IS_ADDR_LINKLOCAL (&s6->sin6_addr)) {
+ /* Update the linklocal address */
+ intn->linklocal = s6->sin6_addr;
+ } else {
+ intn->global = s6->sin6_addr;
+ }
+ if (inet_ntop(ifa->ifa_addr->sa_family, (void *) &(s6->sin6_addr), buf, sizeof(buf)) == NULL) {
+ warn("%s: inet_ntop failed!\n", ifa->ifa_name);
+ } else {
+ dbg("%s\n", buf);
+ }
+ }
+ }
+
+ freeifaddrs(myaddrs);
+}
+
+#endif
diff --git a/mcast/common/interfaces.h b/mcast/common/interfaces.h
new file mode 100644
index 0000000..8ef942c
--- /dev/null
+++ b/mcast/common/interfaces.h
@@ -0,0 +1,52 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ */
+
+#ifndef __INTERFACES_H
+#define __INTERFACES_H
+
+#define INTNODE_MAXIPV4 4 /* Maximum number of IPv4 aliases */
+#define bool int
+
+/*
+ * The list of interfaces we do multicast on
+ * These are discovered on the fly, very handy ;)
+ */
+struct intnode
+{
+ unsigned int ifindex; /* The ifindex */
+ char name[IFNAMSIZ]; /* Name of the interface */
+ unsigned int groupcount; /* Number of groups this interface joined */
+ unsigned int mtu; /* The MTU of this interface (mtu = 0 -> invalid interface) */
+
+ struct sockaddr hwaddr; /* Hardware bytes */
+
+ struct in6_addr linklocal; /* Link local address */
+ struct in6_addr global; /* Global unicast address */
+
+ /* Per interface statistics */
+ uint32_t stat_packets_received; /* Number of packets received */
+ uint32_t stat_packets_sent; /* Number of packets sent */
+ uint32_t stat_bytes_received; /* Number of bytes received */
+ uint32_t stat_bytes_sent; /* Number of bytes sent */
+ uint32_t stat_icmp_received; /* Number of ICMP's received */
+ uint32_t stat_icmp_sent; /* Number of ICMP's sent */
+};
+
+/* Node functions */
+struct intnode *int_create (unsigned int ifindex);
+void int_destroy (struct intnode *intn);
+void update_interfaces (struct intnode *intn);
+
+/* List functions */
+struct intnode *int_find (unsigned int ifindex);
+struct intnode *int_find_name (char *ifname);
+struct intnode *int_find_first (void);
+#if defined WIN32 || ! defined __CYGWIN__
+unsigned if_nametoindex (const char *ifname);
+#endif
+#endif
diff --git a/mcast/common/list.h b/mcast/common/list.h
new file mode 100644
index 0000000..4bb50a4
--- /dev/null
+++ b/mcast/common/list.h
@@ -0,0 +1,238 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ */
+
+/*
+ * Linked lists support
+ *
+ * Copyright (C) 2002 Alexandre Julliard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef __WINE_SERVER_DVBMC_LIST_H
+#define __WINE_SERVER_DVBMC_LIST_H
+
+struct list
+{
+ struct list *next;
+ struct list *prev;
+};
+
+/* Define a list like so:
+ *
+ * struct gadget
+ * {
+ * struct list entry; <-- doesn't have to be the first item in the struct
+ * int a, b;
+ * };
+ *
+ * static struct list global_gadgets = DVBMC_LIST_INIT( global_gadgets );
+ *
+ * or
+ *
+ * struct some_global_thing
+ * {
+ * struct list gadgets;
+ * };
+ *
+ * dvbmc_list_init( &some_global_thing->gadgets );
+ *
+ * Manipulate it like this:
+ *
+ * dvbmc_list_add_head( &global_gadgets, &new_gadget->entry );
+ * dvbmc_list_remove( &new_gadget->entry );
+ * dvbmc_list_add_after( &some_random_gadget->entry, &new_gadget->entry );
+ *
+ * And to iterate over it:
+ *
+ * struct gadget *gadget;
+ * DVBMC_LIST_FOR_EACH_ENTRY( gadget, &global_gadgets, struct gadget, entry )
+ * {
+ * ...
+ * }
+ *
+ */
+
+/* add an element after the specified one */
+static inline void dvbmc_list_add_after( struct list *elem, struct list *to_add )
+{
+ to_add->next = elem->next;
+ to_add->prev = elem;
+ elem->next->prev = to_add;
+ elem->next = to_add;
+}
+
+/* add an element before the specified one */
+static inline void dvbmc_list_add_before( struct list *elem, struct list *to_add )
+{
+ to_add->next = elem;
+ to_add->prev = elem->prev;
+ elem->prev->next = to_add;
+ elem->prev = to_add;
+}
+
+/* add element at the head of the list */
+static inline void dvbmc_list_add_head( struct list *list, struct list *elem )
+{
+ dvbmc_list_add_after( list, elem );
+}
+
+/* add element at the tail of the list */
+static inline void dvbmc_list_add_tail( struct list *list, struct list *elem )
+{
+ dvbmc_list_add_before( list, elem );
+}
+
+/* remove an element from its list */
+static inline void dvbmc_list_remove( struct list *elem )
+{
+ elem->next->prev = elem->prev;
+ elem->prev->next = elem->next;
+}
+
+/* get the next element */
+static inline struct list *dvbmc_list_next( const struct list *list, const struct list *elem )
+{
+ struct list *ret = elem->next;
+ if (elem->next == list) ret = NULL;
+ return ret;
+}
+
+/* get the previous element */
+static inline struct list *dvbmc_list_prev( const struct list *list, const struct list *elem )
+{
+ struct list *ret = elem->prev;
+ if (elem->prev == list) ret = NULL;
+ return ret;
+}
+
+/* get the first element */
+static inline struct list *dvbmc_list_head( const struct list *list )
+{
+ return dvbmc_list_next( list, list );
+}
+
+/* get the last element */
+static inline struct list *dvbmc_list_tail( const struct list *list )
+{
+ return dvbmc_list_prev( list, list );
+}
+
+/* check if a list is empty */
+static inline int dvbmc_list_empty( const struct list *list )
+{
+ return list->next == list;
+}
+
+/* initialize a list */
+static inline void dvbmc_list_init( struct list *list )
+{
+ list->next = list->prev = list;
+}
+
+/* count the elements of a list */
+static inline unsigned int dvbmc_list_count( const struct list *list )
+{
+ unsigned count = 0;
+ const struct list *ptr;
+ for (ptr = list->next; ptr != list; ptr = ptr->next) count++;
+ return count;
+}
+
+/* move all elements from src to the tail of dst */
+static inline void dvbmc_list_move_tail( struct list *dst, struct list *src )
+{
+ if (dvbmc_list_empty(src)) return;
+
+ dst->prev->next = src->next;
+ src->next->prev = dst->prev;
+ dst->prev = src->prev;
+ src->prev->next = dst;
+ dvbmc_list_init(src);
+}
+
+/* move all elements from src to the head of dst */
+static inline void dvbmc_list_move_head( struct list *dst, struct list *src )
+{
+ if (dvbmc_list_empty(src)) return;
+
+ dst->next->prev = src->prev;
+ src->prev->next = dst->next;
+ dst->next = src->next;
+ src->next->prev = dst;
+ dvbmc_list_init(src);
+}
+
+/* iterate through the list */
+#define DVBMC_LIST_FOR_EACH(cursor,list) \
+ for ((cursor) = (list)->next; (cursor) != (list); (cursor) = (cursor)->next)
+
+/* iterate through the list, with safety against removal */
+#define DVBMC_LIST_FOR_EACH_SAFE(cursor, cursor2, list) \
+ for ((cursor) = (list)->next, (cursor2) = (cursor)->next; \
+ (cursor) != (list); \
+ (cursor) = (cursor2), (cursor2) = (cursor)->next)
+
+/* iterate through the list using a list entry */
+#define DVBMC_LIST_FOR_EACH_ENTRY(elem, list, type, field) \
+ for ((elem) = DVBMC_LIST_ENTRY((list)->next, type, field); \
+ &(elem)->field != (list); \
+ (elem) = DVBMC_LIST_ENTRY((elem)->field.next, type, field))
+
+/* iterate through the list using a list entry, with safety against removal */
+#define DVBMC_LIST_FOR_EACH_ENTRY_SAFE(cursor, cursor2, list, type, field) \
+ for ((cursor) = DVBMC_LIST_ENTRY((list)->next, type, field), \
+ (cursor2) = DVBMC_LIST_ENTRY((cursor)->field.next, type, field); \
+ &(cursor)->field != (list); \
+ (cursor) = (cursor2), \
+ (cursor2) = DVBMC_LIST_ENTRY((cursor)->field.next, type, field))
+
+/* iterate through the list in reverse order */
+#define DVBMC_LIST_FOR_EACH_REV(cursor,list) \
+ for ((cursor) = (list)->prev; (cursor) != (list); (cursor) = (cursor)->prev)
+
+/* iterate through the list in reverse order, with safety against removal */
+#define DVBMC_LIST_FOR_EACH_SAFE_REV(cursor, cursor2, list) \
+ for ((cursor) = (list)->prev, (cursor2) = (cursor)->prev; \
+ (cursor) != (list); \
+ (cursor) = (cursor2), (cursor2) = (cursor)->prev)
+
+/* iterate through the list in reverse order using a list entry */
+#define DVBMC_LIST_FOR_EACH_ENTRY_REV(elem, list, type, field) \
+ for ((elem) = DVBMC_LIST_ENTRY((list)->prev, type, field); \
+ &(elem)->field != (list); \
+ (elem) = DVBMC_LIST_ENTRY((elem)->field.prev, type, field))
+
+/* iterate through the list in reverse order using a list entry, with safety against removal */
+#define DVBMC_LIST_FOR_EACH_ENTRY_SAFE_REV(cursor, cursor2, list, type, field) \
+ for ((cursor) = DVBMC_LIST_ENTRY((list)->prev, type, field), \
+ (cursor2) = DVBMC_LIST_ENTRY((cursor)->field.prev, type, field); \
+ &(cursor)->field != (list); \
+ (cursor) = (cursor2), \
+ (cursor2) = DVBMC_LIST_ENTRY((cursor)->field.prev, type, field))
+
+/* macros for statically initialized lists */
+//#define DVBMC_LIST_INIT(list) { &(list), &(list) }
+
+/* get pointer to object containing list element */
+#define DVBMC_LIST_ENTRY(elem, type, field) \
+ ((type *)((char *)(elem) - (unsigned long)(&((type *)0)->field)))
+
+#endif /* __WINE_SERVER_DVBMC_LIST_H */
diff --git a/mcast/common/mcast.c b/mcast/common/mcast.c
new file mode 100644
index 0000000..41991cf
--- /dev/null
+++ b/mcast/common/mcast.c
@@ -0,0 +1,674 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ * modified by Reel Multimedia, http://www.reel-multimedia.com, info@reel-multimedia.com
+ * 01042010 DL: use a single thread for reading from network layer (uses less resources)
+ *
+ */
+
+#include "headers.h"
+//----------------------------------------------------------------------------------------------------------------------------------
+STATIC int udp_ipv6_is_multicast_address (const struct sockaddr *addr)
+{
+#ifdef IPV4
+ if (addr->sa_family == AF_INET)
+ return IN_MULTICAST (ntohl (((struct sockaddr_in *) addr)->sin_addr.s_addr));
+#endif
+ if (addr->sa_family == AF_INET6)
+ return IN6_IS_ADDR_MULTICAST (&((struct sockaddr_in6 *) addr)->sin6_addr);
+ return -1;
+}
+
+//---------------------------------------------------------------------------------------------------------------------------------
+STATIC int udp_ipv6_set_multicast_ttl (SOCKET sockfd, int mcastTTL, struct sockaddr *addr)
+{
+#ifdef IPV4
+ if (addr->sa_family == AF_INET) {
+ if (setsockopt (sockfd, IPPROTO_IP, IP_MULTICAST_TTL, &mcastTTL, sizeof (mcastTTL)) < 0) {
+ perror ("setsockopt(IP_MULTICAST_TTL)");
+ return -1;
+ }
+ }
+#endif
+ if (addr->sa_family == AF_INET6) {
+ if (setsockopt (sockfd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (_SOTYPE)&mcastTTL, sizeof (mcastTTL)) < 0) {
+ perror ("setsockopt(IPV6_MULTICAST_HOPS)");
+ return -1;
+ }
+ }
+ return 0;
+}
+
+//---------------------------------------------------------------------------------------------------------------------------------
+int udp_ipv6_join_multicast_group (SOCKET sockfd, int iface, struct sockaddr *addr)
+{
+#ifdef IPV4
+ if (addr->sa_family == AF_INET) {
+ struct ip_mreq mreq;
+ mreq.imr_multiaddr.s_addr = ((struct sockaddr_in *) addr)->sin_addr.s_addr;
+ mreq.imr_interface.s_addr = INADDR_ANY;
+ if (setsockopt (sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (const void *) &mreq, sizeof (mreq)) < 0) {
+ perror ("setsockopt(IP_ADD_MEMBERSHIP)");
+ return -1;
+ }
+ }
+#endif
+ if (addr->sa_family == AF_INET6) {
+ struct ipv6_mreq mreq6;
+ memcpy (&mreq6.ipv6mr_multiaddr, &(((struct sockaddr_in6 *) addr)->sin6_addr), sizeof (struct in6_addr));
+ mreq6.ipv6mr_interface = iface;
+ if (setsockopt (sockfd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, (_SOTYPE)&mreq6, sizeof (mreq6)) < 0) {
+ perror ("setsockopt(IPV6_ADD_MEMBERSHIP)");
+ return -1;
+ }
+ }
+ return 0;
+}
+
+//---------------------------------------------------------------------------------------------------------------------------------
+int udp_ipv6_leave_multicast_group (SOCKET sockfd, int iface, struct sockaddr *addr)
+{
+#ifdef IPV4
+ if (addr->sa_family == AF_INET) {
+ struct ip_mreq mreq;
+ mreq.imr_multiaddr.s_addr = ((struct sockaddr_in *) addr)->sin_addr.s_addr;
+ mreq.imr_interface.s_addr = INADDR_ANY;
+ if (setsockopt (sockfd, IPPROTO_IP, IP_DROP_MEMBERSHIP, (const void *) &mreq, sizeof (mreq)) < 0) {
+ perror ("setsockopt(IP_DROP_MEMBERSHIP)");
+ return -1;
+ }
+ }
+#endif
+ if (addr->sa_family == AF_INET6) {
+ struct ipv6_mreq mreq6;
+ memcpy (&mreq6.ipv6mr_multiaddr, &(((struct sockaddr_in6 *) addr)->sin6_addr), sizeof (struct in6_addr));
+ mreq6.ipv6mr_interface = iface;
+ if (setsockopt (sockfd, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, (_SOTYPE)&mreq6, sizeof (mreq6)) < 0) {
+ perror ("setsockopt(IPV6_DROP_MEMBERSHIP)");
+ return -1;
+ }
+ }
+ return 0;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------
+STATIC int sockfd_to_family (SOCKET sockfd)
+{
+ struct sockaddr_storage ss;
+ socklen_t len;
+
+ len = sizeof (ss);
+ if (getsockname (sockfd, (SA *) & ss, &len) < 0)
+ return (-1);
+ return (ss.ss_family);
+}
+
+/* end sockfd_to_family */
+//----------------------------------------------------------------------------------------------------------------------------------
+int mcast_set_if (SOCKET sockfd, const char *ifname, u_int ifindex)
+{
+ switch (sockfd_to_family (sockfd)) {
+#ifdef IPV4
+ case AF_INET:{
+ struct in_addr inaddr;
+ struct ifreq ifreq;
+
+ if (ifindex > 0) {
+ if (if_indextoname (ifindex, ifreq.ifr_name) == NULL) {
+ errno = ENXIO; /* i/f index not found */
+ return (-1);
+ }
+ goto doioctl;
+ } else if (ifname != NULL) {
+ memset(&ifreq, 0, sizeof(struct ifreq));
+ strncpy (ifreq.ifr_name, ifname, IFNAMSIZ-1);
+ doioctl:
+ if (ioctl (sockfd, SIOCGIFADDR, &ifreq) < 0)
+ return (-1);
+ memcpy (&inaddr, &((struct sockaddr_in *) &ifreq.ifr_addr)->sin_addr, sizeof (struct in_addr));
+ } else
+ inaddr.s_addr = htonl (INADDR_ANY); /* remove prev. set default */
+
+ return (setsockopt (sockfd, IPPROTO_IP, IP_MULTICAST_IF, &inaddr, sizeof (struct in_addr)));
+ }
+#endif
+ case AF_INET6:{
+ u_int idx;
+// printf("Changing interface IPV6...\n");
+ if ((idx = ifindex) == 0) {
+ if (ifname == NULL) {
+ errno = EINVAL; /* must supply either index or name */
+ return (-1);
+ }
+ if ((idx = if_nametoindex (ifname)) == 0) {
+ errno = ENXIO; /* i/f name not found */
+ return (-1);
+ }
+ }
+ return (setsockopt (sockfd, IPPROTO_IPV6, IPV6_MULTICAST_IF, (_SOTYPE)&idx, sizeof (idx)));
+ }
+
+ default:
+// errno = EAFNOSUPPORT;
+ return (-1);
+ }
+}
+
+//--------------------------------------------------------------------------------------------------------------------------------------------
+UDPContext *server_udp_open (const struct in6_addr *mcg, int port, const char *ifname)
+{
+ UDPContext *s;
+ int sendfd;
+ int n;
+
+ pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, NULL);
+
+ s = (UDPContext *) calloc (1, sizeof (UDPContext));
+ if (!s) {
+ err ("Cannot allocate memory !\n");
+ goto error;
+ }
+ struct sockaddr_in6 *addr = (struct sockaddr_in6 *) &s->dest_addr;
+
+ addr->sin6_addr=*mcg;;
+ addr->sin6_family = AF_INET6;
+ addr->sin6_port = htons (port);
+ s->dest_addr_len = sizeof (struct sockaddr_in6);
+
+ sendfd = socket (PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
+ if (sendfd < 0) {
+ err ("cannot get socket\n");
+ }
+
+ s->dest_addr_len = sizeof (struct sockaddr_in6);
+
+ if ((udp_ipv6_is_multicast_address ((struct sockaddr *) &s->dest_addr))) {
+ if (ifname && strlen (ifname) && (mcast_set_if (sendfd, ifname, 0) < 0)) {
+ warn ("mcast_set_if error\n");
+ goto error;
+ }
+ if (udp_ipv6_set_multicast_ttl (sendfd, MCAST_TTL, (struct sockaddr *) &s->dest_addr) < 0) {
+ warn ("udp_ipv6_set_multicast_ttl");
+ }
+ }
+
+ n = UDP_TX_BUF_SIZE;
+ if (setsockopt (sendfd, SOL_SOCKET, SO_SNDBUF, (_SOTYPE)&n, sizeof (n)) < 0) {
+ warn ("setsockopt sndbuf");
+ }
+ s->is_multicast = 0; //server
+ s->udp_fd = sendfd;
+ s->local_port = port;
+
+ dbg ("Multicast streamer initialized successfully ! \n");
+
+ pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, NULL);
+ return s;
+ error:
+ err ("Cannot init udp_server !\n");
+ if (s) {
+ free (s);
+ }
+
+ pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, NULL);
+ return NULL;
+}
+
+UDPContext *server_udp_open_host (const char *host, int port, const char *ifname)
+{
+ struct in6_addr addr;
+
+ inet_pton (AF_INET6, host, &addr);
+
+ return server_udp_open (&addr, port, ifname);
+}
+
+//--------------------------------------------------------------------------------------------------------------------------------------------
+UDPContext *client_udp_open (const struct in6_addr *mcg, int port, const char *ifname)
+{
+ UDPContext *s;
+ int recvfd;
+ int n;
+
+ pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, NULL);
+
+ s = (UDPContext *) calloc (1, sizeof (UDPContext));
+ if (!s) {
+ err ("Cannot allocate memory !\n");
+ goto error;
+ }
+
+ struct sockaddr_in6 *addr = (struct sockaddr_in6 *) &s->dest_addr;
+#ifndef WIN32
+ addr->sin6_addr=*mcg;
+#else
+ struct in6_addr any;
+ memset(&any,0,sizeof(any));
+ addr->sin6_addr=any;
+#endif
+ addr->sin6_family = AF_INET6;
+ addr->sin6_port = htons (port);
+ s->dest_addr_len = sizeof (struct sockaddr_in6);
+
+ recvfd = socket (PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
+ if (recvfd < 0) {
+ err ("cannot get socket\n");
+ }
+#ifdef WIN32
+# ifndef IPV6_PROTECTION_LEVEL
+# define IPV6_PROTECTION_LEVEL 23
+# endif
+ n = 10 /*PROTECTION_LEVEL_UNRESTRICTED*/;
+ if(setsockopt( recvfd, IPPROTO_IPV6, IPV6_PROTECTION_LEVEL, (_SOTYPE)&n, sizeof(n) ) < 0 ) {
+ warn ("setsockopt IPV6_PROTECTION_LEVEL\n");
+ }
+#endif
+ n = 1;
+ if (setsockopt (recvfd, SOL_SOCKET, SO_REUSEADDR, (_SOTYPE)&n, sizeof (n)) < 0) {
+ warn ("setsockopt REUSEADDR\n");
+ }
+
+#if ! (defined WIN32 || defined APPLE)
+ if (ifname && strlen (ifname) && setsockopt (recvfd, SOL_SOCKET, SO_BINDTODEVICE, ifname, strlen (ifname) + 1)) {
+ dbg ("setsockopt SO_BINDTODEVICE %s failed\n", ifname);
+ }
+#endif
+ if (bind (recvfd, (struct sockaddr *) &s->dest_addr, s->dest_addr_len) < 0) {
+ warn ("bind failed\n");
+ goto error;
+ }
+#ifdef WIN32
+ addr->sin6_addr=*mcg;
+#endif
+ if (udp_ipv6_is_multicast_address ((struct sockaddr *) &s->dest_addr)) {
+#if 0
+ if (ifname && strlen (ifname) && (mcast_set_if (recvfd, ifname, 0) < 0)) {
+ warn ("mcast_set_if error \n");
+ goto error;
+ }
+#endif
+ if (ifname) {
+ if ((s->idx = if_nametoindex (ifname)) == 0) {
+ s->idx = 0;
+ } else {
+ dbg("Selecting interface %s (%d)", ifname, s->idx);
+ }
+ } else {
+ s->idx = 0;
+ }
+
+ if (udp_ipv6_join_multicast_group (recvfd, s->idx, (struct sockaddr *) &s->dest_addr) < 0) {
+ warn ("Cannot join multicast group !\n");
+ goto error;
+ }
+ s->is_multicast = 1;
+ }
+
+ n = UDP_RX_BUF_SIZE;
+ if (setsockopt (recvfd, SOL_SOCKET, SO_RCVBUF, (_SOTYPE)&n, sizeof (n)) < 0) {
+ warn ("setsockopt rcvbuf");
+ goto error;
+ }
+
+ s->udp_fd = recvfd;
+ s->local_port = port;
+
+ pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, NULL);
+
+ return s;
+ error:
+ warn ("socket error !\n");
+ if (s) {
+ free (s);
+ }
+ pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, NULL);
+ return NULL;
+}
+
+UDPContext *client_udp_open_host (const char *host, int port, const char *ifname)
+{
+ struct in6_addr addr;
+
+ inet_pton (AF_INET6, host, &addr);
+
+ return client_udp_open (&addr, port, ifname);
+}
+
+//--------------------------------------------------------------------------------------------------------------------------------------------
+int udp_read (UDPContext * s, uint8_t * buf, int size, int timeout, struct sockaddr_storage *from)
+{
+ socklen_t from_len = sizeof (struct sockaddr_storage);
+ struct sockaddr_storage from_local;
+
+ if(!from) {
+ from=&from_local;
+ }
+
+ struct pollfd p;
+ p.fd = s->udp_fd;
+ p.events = POLLIN;
+
+ if(poll(&p,1,(timeout+999)>>10)>0) {
+ return recvfrom (s->udp_fd, (char *)buf, size, 0, (struct sockaddr *) from, &from_len);
+ }
+ return -1;
+}
+
+//--------------------------------------------------------------------------------------------------------------------------------------------------
+int udp_write (UDPContext * s, uint8_t * buf, int size)
+{
+ int ret;
+
+ for (;;) {
+ ret = sendto (s->udp_fd, (char *) buf, size, 0, (struct sockaddr *) &s->dest_addr, s->dest_addr_len);
+
+ if (ret < 0) {
+ if (errno != EINTR && errno != EAGAIN)
+ return -1;
+ } else {
+ break;
+ }
+ }
+ return size;
+}
+
+//----------------------------------------------------------------------------------------------------------------------------------------------------
+int udp_close (UDPContext * s)
+{
+ if (s->is_multicast)
+ udp_ipv6_leave_multicast_group (s->udp_fd, s->idx, (struct sockaddr *) &s->dest_addr);
+
+ closesocket (s->udp_fd);
+ free (s);
+
+ return 0;
+}
+
+//--------------------------------------------------------------------------------------------------------------------------------------------
+
+#ifndef MULTI_THREAD_RECEIVER
+
+#define MAX_BUFF_SIZE 0x10000
+#define MAX_CON_LIST 128
+UDPContext *gConList[MAX_CON_LIST];
+pthread_mutex_t gConListLock = PTHREAD_MUTEX_INITIALIZER;
+static int gConListInit=0;
+static int gConListModified;
+static UDPContext *gConChain;
+
+STATIC void client_upd_cleanup (void *arg) {
+ if(!gConListInit) return;
+ pthread_mutex_lock(&gConListLock);
+ memset(&gConList, 0, sizeof(gConList));
+ gConListInit=0;
+ pthread_mutex_unlock(&gConListLock);
+} // client_upd_cleanup
+
+void *client_upd_process(void *arg) {
+#ifdef RT
+#if 1
+ if (setpriority (PRIO_PROCESS, 0, -15) == -1)
+#else
+ if (pthread_setschedprio (p->recv_ts_thread, -15))
+#endif
+ {
+ dbg ("Cannot raise priority to -15\n");
+ }
+#endif
+ unsigned char buff[MAX_BUFF_SIZE];
+ socklen_t from_len = sizeof (struct sockaddr_storage);
+ struct sockaddr_storage from_local;
+ struct pollfd fds[MAX_CON_LIST];
+
+ pthread_cleanup_push (client_upd_cleanup, 0);
+ int max_fd=0;
+ while(1) {
+ UDPContext *e;
+ pthread_mutex_lock(&gConListLock);
+
+ if(gConListModified) {
+ gConListModified=0;
+ max_fd=0;
+ for(e=gConChain;e;e=e->next) {
+ fds[max_fd].fd = e->udp_fd;
+ fds[max_fd].events = POLLIN;
+ fds[max_fd].revents = 0;
+ e->pfd = &fds[max_fd];
+ max_fd++;
+ } // for
+ } // if
+ pthread_mutex_unlock(&gConListLock);
+ int rs = poll(fds, max_fd, 1000);
+ if(rs>0) {
+ pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, NULL);
+ pthread_mutex_lock(&gConListLock);
+ for(e=gConChain;e;e=e->next) {
+ if(e->pfd && (e->pfd->revents & POLLIN)) {
+ if(e->cb) {
+ int ret = recvfrom (e->udp_fd, (char *)buff, MAX_BUFF_SIZE, 0, 0, 0/*(struct sockaddr *) &from_local, &from_len*/);
+ if(ret>0)
+ e->cb(buff, ret, e->arg);
+ } else if(e->buff && !e->bufflen) {
+ pthread_mutex_lock(&e->bufflock);
+ int ret = recvfrom (e->udp_fd, (char *)e->buff, e->buffmax, 0, (struct sockaddr *) &from_local, &from_len);
+ if(ret>0)
+ e->bufflen = ret;
+ pthread_mutex_unlock(&e->bufflock);
+ } // if
+ } // if
+ } // for
+ pthread_mutex_unlock(&gConListLock);
+ pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, NULL);
+ } // if
+ pthread_testcancel();
+ } // while
+ pthread_cleanup_pop (1);
+ return NULL;
+}
+
+static int client_upd_init() {
+ pthread_mutex_lock(&gConListLock);
+ if(gConListInit) {
+ pthread_mutex_unlock(&gConListLock);
+ return 1;
+ } // if
+ memset(&gConList, 0, sizeof(gConList));
+ gConListModified = 0;
+ gConChain = NULL;
+ pthread_t client_upd_thread;
+ if(0==pthread_create (&client_upd_thread, NULL, client_upd_process, 0)) {
+ gConListInit = 1;
+ pthread_detach(client_upd_thread);
+ } // if
+ pthread_mutex_unlock(&gConListLock);
+ return gConListInit;
+} // client_upd_init
+
+UDPContext *client_udp_open_buff (const struct in6_addr *mcg, int port, const char *ifname, int buff_size) {
+ UDPContext *ret = client_udp_open_cb (mcg, port, ifname, 0, 0);
+ if(ret) {
+ ret->buff = (unsigned char *)malloc(buff_size);
+ ret->buffmax = buff_size;
+ ret->bufflen = 0;
+ if (!ret->buff) {
+ err ("client_udp_open_buff: out of memory\n");
+ }
+ } // if
+ return ret;
+} // client_udp_open_buff
+
+UDPContext *client_udp_open_cb (const struct in6_addr *mcg, int port, const char *ifname, client_udp_cb cb, void *arg)
+{
+ if(!client_upd_init()) return NULL;
+
+ UDPContext *s;
+ int recvfd = -1;
+ int n;
+
+ pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, NULL);
+
+ s = (UDPContext *) calloc (1, sizeof (UDPContext));
+ if (!s) {
+ err ("Cannot allocate memory !\n");
+ goto error;
+ }
+
+ struct sockaddr_in6 *addr = (struct sockaddr_in6 *) &s->dest_addr;
+#ifndef WIN32
+ addr->sin6_addr=*mcg;
+#else
+ struct in6_addr any=IN6ADDR_ANY_INIT;
+ addr->sin6_addr=any;
+#endif
+ addr->sin6_family = AF_INET6;
+ addr->sin6_port = htons (port);
+ s->dest_addr_len = sizeof (struct sockaddr_in6);
+
+ recvfd = socket (PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
+ if (recvfd < 0) {
+ err ("cannot get socket\n");
+ }
+#ifdef WIN32
+# ifndef IPV6_PROTECTION_LEVEL
+# define IPV6_PROTECTION_LEVEL 23
+# endif
+ n = 10 /*PROTECTION_LEVEL_UNRESTRICTED*/;
+ if(setsockopt( recvfd, IPPROTO_IPV6, IPV6_PROTECTION_LEVEL, (_SOTYPE)&n, sizeof(n) ) < 0 ) {
+ warn ("setsockopt IPV6_PROTECTION_LEVEL\n");
+ }
+#endif
+ n = 1;
+ if (setsockopt (recvfd, SOL_SOCKET, SO_REUSEADDR, (_SOTYPE)&n, sizeof (n)) < 0) {
+ warn ("setsockopt REUSEADDR\n");
+ }
+
+#if ! (defined WIN32 || defined APPLE)
+ if (ifname && strlen (ifname) && setsockopt (recvfd, SOL_SOCKET, SO_BINDTODEVICE, ifname, strlen (ifname) + 1)) {
+ dbg ("setsockopt SO_BINDTODEVICE %s failed\n", ifname);
+ }
+#endif
+ if (bind (recvfd, (struct sockaddr *) &s->dest_addr, s->dest_addr_len) < 0) {
+ warn ("bind failed\n");
+ goto error;
+ }
+#ifdef WIN32
+ addr->sin6_addr=*mcg;
+#endif
+ if (udp_ipv6_is_multicast_address ((struct sockaddr *) &s->dest_addr)) {
+#if 0
+ if (ifname && strlen (ifname) && (mcast_set_if (recvfd, ifname, 0) < 0)) {
+ warn ("mcast_set_if error \n");
+ goto error;
+ }
+#endif
+ if (ifname) {
+ if ((s->idx = if_nametoindex (ifname)) == 0) {
+ s->idx = 0;
+ } else {
+ dbg("Selecting interface %s (%d)", ifname, s->idx);
+ }
+ } else {
+ s->idx = 0;
+ }
+
+ if (udp_ipv6_join_multicast_group (recvfd, s->idx, (struct sockaddr *) &s->dest_addr) < 0) {
+ warn ("Cannot join multicast group !\n");
+ goto error;
+ }
+ s->is_multicast = 1;
+ }
+
+ n = cb ? UDP_PID_BUF_SIZE : UDP_RX_BUF_SIZE;
+ if (setsockopt (recvfd, SOL_SOCKET, SO_RCVBUF, (_SOTYPE)&n, sizeof (n)) < 0) {
+ warn ("setsockopt rcvbuf");
+ goto error;
+ }
+
+ s->udp_fd = recvfd;
+ s->local_port = port;
+
+ pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, NULL);
+
+ s->cb = cb;
+ s->arg = arg;
+ pthread_mutex_init(&s->bufflock, NULL);
+ int i;
+ pthread_mutex_lock(&gConListLock);
+ for(i=0;i<MAX_CON_LIST;i++) {
+ if(!gConList[i]) {
+ gConList[i]=s;
+ gConListModified=1;
+ s->next=gConChain;
+ gConChain=s;
+ break;
+ } // if
+ } // for
+ pthread_mutex_unlock(&gConListLock);
+ if(i>=MAX_CON_LIST)
+ warn("---------------------------------------------No slot found!\n");
+
+ return s;
+ error:
+ warn ("socket error !\n");
+ if (s) {
+ free (s);
+ }
+ pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, NULL);
+ return NULL;
+}
+
+UDPContext *client_udp_open_host_buff (const char *host, int port, const char *ifname, int buff_size)
+{
+ struct in6_addr addr;
+
+ inet_pton (AF_INET6, host, &addr);
+
+ return client_udp_open_buff (&addr, port, ifname, buff_size);
+}
+
+//--------------------------------------------------------------------------------------------------------------------------------------------
+int udp_read_buff (UDPContext * s, uint8_t * buf, int size, int timeout, struct sockaddr_storage *from)
+{
+ pthread_mutex_lock(&s->bufflock);
+ int ret = s->bufflen>size ? size : s->bufflen;
+ if(ret>0) {
+ memcpy(buf, s->buff, ret);
+ s->bufflen-=ret;
+ }
+ pthread_mutex_unlock(&s->bufflock);
+ return ret;
+}
+//----------------------------------------------------------------------------------------------------------------------------------------------------
+int udp_close_buff (UDPContext * s)
+{
+ int i;
+ pthread_mutex_lock(&gConListLock);
+ for(i=0;i<MAX_CON_LIST;i++) {
+ if(gConList[i] == s) {
+ gConList[i]=0;
+ gConListModified=1;
+ UDPContext **e;
+ for(e=&gConChain;*e;e=&(*e)->next) {
+ if(*e == s) {
+ *e=(*e)->next;
+ break;
+ }
+ }
+ break;
+ }
+ }
+ pthread_mutex_unlock(&gConListLock);
+ if (s->is_multicast)
+ udp_ipv6_leave_multicast_group (s->udp_fd, s->idx, (struct sockaddr *) &s->dest_addr);
+
+ closesocket (s->udp_fd);
+ free(s->buff);
+ pthread_mutex_destroy(&s->bufflock);
+ free (s);
+
+ return 0;
+}
+#endif
diff --git a/mcast/common/mcast.h b/mcast/common/mcast.h
new file mode 100644
index 0000000..33a6ed5
--- /dev/null
+++ b/mcast/common/mcast.h
@@ -0,0 +1,64 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ * modified by Reel Multimedia, http://www.reel-multimedia.com, info@reel-multimedia.com
+ * 01042010 DL: use a single thread for reading from network layer (uses less resources)
+ *
+ */
+
+#ifndef __MCAST_H__
+#define __MCAST_H__
+
+typedef void (*client_udp_cb)(unsigned char *buf, int n, void *arg);
+
+typedef struct _UDPContext
+{
+ struct _UDPContext *next;
+ SOCKET udp_fd;
+ int ttl;
+ int idx;
+ int is_multicast;
+ int local_port;
+ int reuse_socket;
+ struct sockaddr_storage dest_addr;
+ size_t dest_addr_len;
+
+ client_udp_cb cb;
+ void *arg;
+ unsigned char *buff;
+ int buffmax;
+ int bufflen;
+ pthread_mutex_t bufflock;
+ struct pollfd *pfd;
+} UDPContext;
+
+#define SA struct sockaddr
+
+#define UDP_TX_BUF_SIZE 131072
+#define UDP_RX_BUF_SIZE 131072
+#define UDP_PID_BUF_SIZE 1048576
+#define MCAST_TTL 16
+
+UDPContext *server_udp_open_host (const char *host, int port, const char *ifname);
+UDPContext *server_udp_open (const struct in6_addr *mcg, int port, const char *ifname);
+UDPContext *client_udp_open (const struct in6_addr *mcg, int port, const char *ifname);
+UDPContext *client_udp_open_host (const char *host, int port, const char *ifname);
+
+int udp_read (UDPContext * s, uint8_t * buf, int size, int timeout, struct sockaddr_storage *from);
+int udp_write (UDPContext * s, uint8_t * buf, int size);
+int udp_close (UDPContext * s);
+
+#ifndef MULTI_THREAD_RECEIVER
+UDPContext *client_udp_open_host_buff (const char *host, int port, const char *ifname, int buff_size);
+UDPContext *client_udp_open_cb (const struct in6_addr *mcg, int port, const char *ifname, client_udp_cb cb, void *arg);
+UDPContext *client_udp_open_buff (const struct in6_addr *mcg, int port, const char *ifname, int buff_size);
+int udp_read_buff (UDPContext * s, uint8_t * buf, int size, int timeout, struct sockaddr_storage *from);
+int udp_close_buff (UDPContext * s);
+#endif
+
+int udp_ipv6_join_multicast_group (SOCKET sockfd, int iface, struct sockaddr *addr);
+int udp_ipv6_leave_multicast_group (SOCKET sockfd, int iface, struct sockaddr *addr);
+#endif
diff --git a/mcast/common/mld.h b/mcast/common/mld.h
new file mode 100644
index 0000000..93d2bd6
--- /dev/null
+++ b/mcast/common/mld.h
@@ -0,0 +1,339 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ */
+
+#ifndef __MLD_H__
+#define __MLD_H__
+
+/* Wrappers so we don't have to change the copied stuff ;) */
+#define __u8 uint8_t
+#define __u16 uint16_t
+/* Booleans */
+#define false 0
+#define true (!false)
+
+
+/* Determine Endianness */
+#if ! defined __LITTLE_ENDIAN_BITFIELD && ! defined __BIG_ENDIAN_BITFIELD
+ #if BYTE_ORDER == LITTLE_ENDIAN
+ /* 1234 machines */
+ #define __LITTLE_ENDIAN_BITFIELD 1
+ #elif BYTE_ORDER == BIG_ENDIAN
+ /* 4321 machines */
+ #define __BIG_ENDIAN_BITFIELD 1
+ # define WORDS_BIGENDIAN 1
+ #elif BYTE_ORDER == PDP_ENDIAN
+ /* 3412 machines */
+ #error PDP endianness not supported yet!
+ #else
+ #error unknown endianness!
+ #endif
+#endif
+
+/* Per RFC */
+struct mld1
+{
+ __u8 type;
+ __u8 code;
+ __u16 csum;
+ __u16 mrc;
+ __u16 resv1;
+ struct in6_addr mca;
+};
+
+/* The timeout for queries */
+/* as per RFC3810 MLDv2 "9.2. Query Interval" */
+#define ECMH_SUBSCRIPTION_TIMEOUT 15
+
+/* Robustness Factor, per RFC3810 MLDv2 "9.1. Robustness Variable" */
+#define ECMH_ROBUSTNESS_FACTOR 2
+
+
+/* MLDv2 Report */
+#ifndef ICMP6_V2_MEMBERSHIP_REPORT
+#define ICMP6_V2_MEMBERSHIP_REPORT 143
+#endif
+/* MLDv2 Report - Experimental Code */
+#ifndef ICMP6_V2_MEMBERSHIP_REPORT_EXP
+#define ICMP6_V2_MEMBERSHIP_REPORT_EXP 206
+#endif
+
+/* MLDv2 Exclude/Include */
+
+#ifndef MLD2_MODE_IS_INCLUDE
+#define MLD2_MODE_IS_INCLUDE 1
+#endif
+#ifndef MLD2_MODE_IS_EXCLUDE
+#define MLD2_MODE_IS_EXCLUDE 2
+#endif
+#ifndef MLD2_CHANGE_TO_INCLUDE
+#define MLD2_CHANGE_TO_INCLUDE 3
+#endif
+#ifndef MLD2_CHANGE_TO_EXCLUDE
+#define MLD2_CHANGE_TO_EXCLUDE 4
+#endif
+#ifndef MLD2_ALLOW_NEW_SOURCES
+#define MLD2_ALLOW_NEW_SOURCES 5
+#endif
+#ifndef MLD2_BLOCK_OLD_SOURCES
+#define MLD2_BLOCK_OLD_SOURCES 6
+#endif
+
+#ifndef MLD2_ALL_MCR_INIT
+#define MLD2_ALL_MCR_INIT { { { 0xff,0x02,0,0,0,0,0,0,0,0,0,0,0,0,0,0x16 } } }
+#endif
+
+#ifndef ICMP6_ROUTER_RENUMBERING
+#define ICMP6_ROUTER_RENUMBERING 138 /* router renumbering */
+#endif
+#ifndef ICMP6_NI_QUERY
+#define ICMP6_NI_QUERY 139 /* node information request */
+#endif
+#ifndef ICMP6_NI_REPLY
+#define ICMP6_NI_REPLY 140 /* node information reply */
+#endif
+#ifndef MLD_MTRACE_RESP
+#define MLD_MTRACE_RESP 200 /* Mtrace response (to sender) */
+#endif
+#ifndef MLD_MTRACE
+#define MLD_MTRACE 201 /* Mtrace messages */
+#endif
+
+#ifndef ICMP6_DST_UNREACH_BEYONDSCOPE
+#define ICMP6_DST_UNREACH_BEYONDSCOPE 2 /* Beyond scope of source address */
+#endif
+
+#ifndef ICMP6_NI_SUCCESS
+#define ICMP6_NI_SUCCESS 0 /* node information successful reply */
+#endif
+#ifndef ICMP6_NI_REFUSED
+#define ICMP6_NI_REFUSED 1 /* node information request is refused */
+#endif
+#ifndef ICMP6_NI_UNKNOWN
+#define ICMP6_NI_UNKNOWN 2 /* unknown Qtype */
+#endif
+
+#ifndef ICMP6_ROUTER_RENUMBERING_COMMAND
+#define ICMP6_ROUTER_RENUMBERING_COMMAND 0 /* rr command */
+#endif
+#ifndef ICMP6_ROUTER_RENUMBERING_RESULT
+#define ICMP6_ROUTER_RENUMBERING_RESULT 1 /* rr result */
+#endif
+#ifndef ICMP6_ROUTER_RENUMBERING_SEQNUM_RESET
+#define ICMP6_ROUTER_RENUMBERING_SEQNUM_RESET 255 /* rr seq num reset */
+#endif
+
+#ifndef ICMP6_MEMBERSHIP_QUERY
+#define ICMP6_MEMBERSHIP_QUERY 130
+#endif
+
+#ifndef ICMP6_MEMBERSHIP_REPORT
+#define ICMP6_MEMBERSHIP_REPORT 131
+#endif
+
+#ifndef ICMP6_MEMBERSHIP_REDUCTION
+#define ICMP6_MEMBERSHIP_REDUCTION 132
+#endif
+
+#ifndef ICMP6_DST_UNREACH_NOTNEIGHBOR
+#define ICMP6_DST_UNREACH_NOTNEIGHBOR 2 /* not a neighbor */
+#endif
+
+#ifdef __UCLIBC__
+
+#ifndef IP6OPT_PADN
+#define IP6OPT_PADN 1
+#endif
+
+#ifndef ip6_ext
+struct ip6_ext
+{
+ uint8_t ip6e_nxt;
+ uint8_t ip6e_len;
+};
+#endif
+#endif
+
+#ifdef WIN32
+struct ip6_hdr
+ {
+ union
+ {
+ struct ip6_hdrctl
+ {
+ uint32_t ip6_un1_flow; /* 4 bits version, 8 bits TC,
+ 20 bits flow-ID */
+ uint16_t ip6_un1_plen; /* payload length */
+ uint8_t ip6_un1_nxt; /* next header */
+ uint8_t ip6_un1_hlim; /* hop limit */
+ } ip6_un1;
+ uint8_t ip6_un2_vfc; /* 4 bits version, top 4 bits tclass */
+ } ip6_ctlun;
+ struct in6_addr ip6_src; /* source address */
+ struct in6_addr ip6_dst; /* destination address */
+ };
+#define ICMP6_DST_UNREACH 1
+#define ICMP6_TIME_EXCEEDED 3
+#define ICMP6_PARAM_PROB 4
+
+#define ip6_vfc ip6_ctlun.ip6_un2_vfc
+#define ip6_plen ip6_ctlun.ip6_un1.ip6_un1_plen
+#define ip6_nxt ip6_ctlun.ip6_un1.ip6_un1_nxt
+#define ip6_hlim ip6_ctlun.ip6_un1.ip6_un1_hlim
+
+#define IP6OPT_PADN 1
+
+/* Hop-by-Hop options header. */
+struct ip6_hbh
+ {
+ uint8_t ip6h_nxt; /* next header. */
+ uint8_t ip6h_len; /* length in units of 8 octets. */
+ /* followed by options */
+ };
+
+#endif
+
+
+/* From linux/net/ipv6/mcast.c */
+
+/*
+ * These header formats should be in a separate include file, but icmpv6.h
+ * doesn't have in6_addr defined in all cases, there is no __u128, and no
+ * other files reference these.
+ *
+ * +-DLS 4/14/03
+ *
+ * Multicast Listener Discovery version 2 headers
+ * Modified as they are where not ANSI C compliant
+ */
+struct mld2_grec
+{
+ __u8 grec_type;
+ __u8 grec_auxwords;
+ __u16 grec_nsrcs;
+ struct in6_addr grec_mca;
+/* struct in6_addr grec_src[0]; */
+};
+
+struct mld2_report
+{
+ __u8 type;
+ __u8 resv1;
+ __u16 csum;
+ __u16 resv2;
+ __u16 ngrec;
+/* struct mld2_grec grec[0]; */
+};
+
+struct mld2_query
+{
+ __u8 type;
+ __u8 code;
+ __u16 csum;
+ __u16 mrc;
+ __u16 resv1;
+ struct in6_addr mca;
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ uint32_t qrv:3, suppress:1, resv2:4;
+#elif defined(__BIG_ENDIAN_BITFIELD)
+ uint32_t resv2:4, suppress:1, qrv:3;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+ __u8 qqic;
+ __u16 nsrcs;
+/* struct in6_addr srcs[0]; */
+};
+
+#define IGMP6_UNSOLICITED_IVAL (10*HZ)
+#define MLD_QRV_DEFAULT 2
+
+#define MLD_V1_SEEN(idev) ((idev)->mc_v1_seen && \
+ time_before(jiffies, (idev)->mc_v1_seen))
+
+#define MLDV2_MASK(value, nb) ((nb)>=32 ? (value) : ((1<<(nb))-1) & (value))
+#define MLDV2_EXP(thresh, nbmant, nbexp, value) \
+ ((value) < (thresh) ? (value) : \
+ ((MLDV2_MASK(value, nbmant) | (1<<(nbmant+nbexp))) << \
+ (MLDV2_MASK((value) >> (nbmant), nbexp) + (nbexp))))
+
+#define MLDV2_QQIC(value) MLDV2_EXP(0x80, 4, 3, value)
+#define MLDV2_MRC(value) MLDV2_EXP(0x8000, 12, 3, value)
+
+#define bool int
+
+#define RAW_RX_BUF_SIZE 1024*1024
+
+struct lookup
+{
+ unsigned int num;
+ const char *desc;
+};
+
+/* Our configuration structure */
+struct conf
+{
+ unsigned int maxinterfaces; /* The max number of interfaces the array can hold */
+ struct intnode *ints; /* The interfaces we are watching */
+
+ struct mc_group *groups;
+
+ bool quit; /* Global Quit signal */
+
+ bool promisc; /* Make interfaces promisc? (To be sure to receive all MLD's) */
+ bool mode; /* Streamer 0 /Client mode 1 */
+
+ uint8_t *buffer; /* Our buffer */
+ unsigned int bufferlen; /* Length of the buffer */
+
+ int rawsocket; /* Single RAW socket for sending and receiving everything */
+
+ unsigned int stat_packets_received; /* Number of packets received */
+ unsigned int stat_packets_sent; /* Number of packets forwarded */
+ unsigned int stat_bytes_received; /* Number of bytes received */
+ unsigned int stat_bytes_sent; /* Number of bytes forwarded */
+ unsigned int stat_icmp_received; /* Number of ICMP's received */
+ unsigned int stat_icmp_sent; /* Number of ICMP's sent */
+
+ unsigned int mca_groups;
+ unsigned int subscribers;
+ cmdline_t *cmd;
+#ifdef SERVER
+ tuner_t *tuner_parms;
+ int tuner_number;
+
+ satellite_list_t *sat_list;
+ int sat_list_num;
+ int readconfig;
+ pthread_t mld_timer_thread;
+ pthread_t collect_stats_thread;
+ pthread_t stream_tca_thread;
+ pthread_t stream_tra_thread;
+
+ int tca_id;
+#endif
+
+ pthread_mutex_t lock;
+};
+
+/* Global Stuff */
+extern struct conf *g_conf;
+extern struct lookup mld2_grec_types[];
+
+
+const char *lookup (struct lookup *l, unsigned int num);
+const char *icmpv6_type (unsigned int type);
+const char *icmpv6_code (unsigned int type, unsigned int code);
+
+uint16_t ipv6_checksum (const struct ip6_hdr *ip6, uint8_t protocol, const void *data, const uint16_t length);
+void sendpacket6 (struct intnode *intn, const struct ip6_hdr *iph, const uint16_t len);
+//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+int send_mldv2_report (struct intnode *intn, int grec_number, struct in6_addr *mcas, int srcn, struct in6_addr *sources, int mode);
+int start_mld_daemon (void);
+
+#endif
diff --git a/mcast/common/mld_client.c b/mcast/common/mld_client.c
new file mode 100644
index 0000000..d291466
--- /dev/null
+++ b/mcast/common/mld_client.c
@@ -0,0 +1,244 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ */
+
+#undef DEBUG
+#include "headers.h"
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+int send_mldv2_report (struct intnode *intn, int grec_number, struct in6_addr *mcas, int srcn, struct in6_addr *sources, int mode)
+{
+ unsigned int length;
+ struct mld_report_packet
+ {
+ struct ip6_hdr ip6;
+ struct ip6_hbh hbh;
+ struct
+ {
+ uint8_t type;
+ uint8_t length;
+ uint16_t value;
+ uint8_t optpad[2];
+ } routeralert;
+ struct mld2_report mld2r;
+ } *packet;
+ struct mld2_grec *grec = NULL;
+ struct in6_addr *src = NULL;
+ int mca_index, src_index;
+ int count = 0;
+
+ bool any = false;
+
+
+ //printf("creating multicast listener report packet....\n");
+ //printf("size src = %d size grec = %d \n",sizeof(*src),sizeof(*grec));
+ if (intn->mtu < sizeof (*packet)) {
+ /*
+ * MTU is too small to support this type of packet
+ * Should not happen though
+ */
+ dbg ("MTU too small for packet while sending MLDv2 report on interface %s/%u mtu=%u!?\n", intn->name, intn->ifindex, intn->mtu);
+ return -1;
+ }
+
+ /* Allocate a buffer matching the MTU size of this interface */
+ packet = (struct mld_report_packet *) malloc (intn->mtu);
+
+ if (!packet) {
+ err ("Cannot get memory for MLD2 report packet, aborting\n");
+ }
+// printf("addr packet = %u \n",packet);
+ memset (packet, 0, intn->mtu);
+
+
+ /* Create the IPv6 packet */
+ packet->ip6.ip6_vfc = 0x60;
+ packet->ip6.ip6_plen = ntohs (sizeof (*packet) - sizeof (packet->ip6));
+ packet->ip6.ip6_nxt = IPPROTO_HOPOPTS;
+ packet->ip6.ip6_hlim = 1;
+
+ /*
+ * The source address must be the link-local address
+ * of the interface we are sending on
+ */
+ memcpy (&packet->ip6.ip6_src, &intn->linklocal, sizeof (packet->ip6.ip6_src));
+
+ /* MLDv2 Report -> All IPv6 Multicast Routers (ff02::16) */
+ packet->ip6.ip6_dst.s6_addr[0] = 0xff;
+ packet->ip6.ip6_dst.s6_addr[1] = 0x02;
+ packet->ip6.ip6_dst.s6_addr[15] = 0x16;
+
+ /* HopByHop Header Extension */
+ packet->hbh.ip6h_nxt = IPPROTO_ICMPV6;
+ packet->hbh.ip6h_len = 0;
+
+ /* Router Alert Option */
+ packet->routeralert.type = 5;
+ packet->routeralert.length = sizeof (packet->routeralert.value);
+ packet->routeralert.value = 0; /* MLD ;) */
+
+ /* Option Padding */
+ packet->routeralert.optpad[0] = IP6OPT_PADN;
+ packet->routeralert.optpad[1] = 0;
+
+ /* ICMPv6 MLD Report */
+ packet->mld2r.type = ICMP6_V2_MEMBERSHIP_REPORT;
+ //number of multi cast address reocrds
+ packet->mld2r.ngrec = 0; //grec_number;//htons(1);
+ length = 0;
+ count = 0;
+ for (mca_index = 0; mca_index < grec_number; mca_index++) {
+ src = NULL;
+ if (!grec) {
+ length = sizeof (*packet) + sizeof (*grec) - sizeof (packet->ip6);
+ //fprintf(stdout,"(grec = %02d) %02d. current report length = %04d MTU: %04d)\n",packet->mld2r.ngrec,mca_index,length+sizeof(packet->ip6),intn->mtu);
+
+ if (length + sizeof (packet->ip6) > intn->mtu) {
+ /* Should not happen! Would mean the MTU is smaller than a standard mld report */
+ dbg ("No grec and MTU too small for packet while sending MLDv2 report on interface %s/%u mtu=%u!?\n", intn->name, intn->ifindex, intn->mtu);
+ free (packet);
+ return (-1);
+ } else
+ grec = (struct mld2_grec *) (((char *) packet) + sizeof (*packet));
+
+ packet->mld2r.ngrec++;
+ } else {
+ if (!src)
+ length = ((((char *) grec) - ((char *) packet)) + sizeof (*grec) + (sizeof (*src) * (grec->grec_nsrcs))) - sizeof (packet->ip6);
+
+ //fprintf(stdout,"\nloop1:(grec = %02d) %02d.length = %04d (Total : %04d MTU: %04d)\n\n", packet->mld2r.ngrec , mca_index,length,(length + sizeof(packet->ip6)), intn->mtu);
+
+ if (((length + sizeof (packet->ip6) + sizeof (*grec)) > intn->mtu)) {
+
+ /* Take care of endianess */
+ //fprintf(stdout,"next grec record does not fit... sending... \n");
+
+ packet->mld2r.ngrec = htons (packet->mld2r.ngrec);
+ grec->grec_nsrcs = htons (grec->grec_nsrcs);
+
+ /* Calculate and fill in the checksum */
+ packet->ip6.ip6_plen = htons (length);
+ packet->mld2r.csum = htons (0);
+ packet->mld2r.csum = ipv6_checksum (&packet->ip6, IPPROTO_ICMPV6, (uint8_t *) & packet->mld2r, length - sizeof (struct ip6_hbh) - sizeof (packet->routeralert));
+ count++;
+#ifdef DEBUG
+ dbg ("%04d.Sending2 MLDv2 Report on %s/%u, ngrec=%u, length=%u sources=%u (in last grec)\n", count, intn->name, intn->ifindex, ntohs (packet->mld2r.ngrec), length, ntohs (grec->grec_nsrcs));
+ sendpacket6 (intn, (const struct ip6_hdr *) packet, length + sizeof (packet->ip6));
+#endif
+ /* Increase ICMP sent statistics */
+ g_conf->stat_icmp_sent++;
+ intn->stat_icmp_sent++;
+
+ /* Reset the MLDv2 struct */
+ packet->mld2r.ngrec = 0;
+ grec = (struct mld2_grec *) (((char *) packet) + sizeof (*packet));
+ } else {
+ //next grec
+ grec->grec_nsrcs = htons (grec->grec_nsrcs);
+ grec = (struct mld2_grec *) (((char *) grec) + sizeof (*grec) + (sizeof (*src) * ntohs (grec->grec_nsrcs)));
+
+ }
+ packet->mld2r.ngrec++;
+ }
+ //Copy MCA to record
+ memcpy (&grec->grec_mca, mcas + mca_index, sizeof (grec->grec_mca));
+
+ /* Zero sources upto now */
+ grec->grec_nsrcs = 0;
+ /* 0 Sources -> Exclude those */
+ grec->grec_type = MLD2_MODE_IS_EXCLUDE;
+ if (mode) {
+ grec->grec_type = mode;
+ }
+
+ /* Nothing added yet */
+ any = false;
+
+ for (src_index = 0; src_index < srcn || (!srcn && src_index == 0); src_index++) {
+
+ //check for duplicate source reocrds and any address
+
+ /* Packet with at least one grec and one or more src's, excluding ip6 header */
+
+ length = (((char *) grec) - ((char *) packet)) + sizeof (*grec) + (sizeof (*src) * (grec->grec_nsrcs)) - sizeof (packet->ip6);
+
+ //fprintf(stdout,"loop2:(grec = %02d) %02d.length = %04d (Total : %04d MTU: %04d)\n", packet->mld2r.ngrec,mca_index,length,(length + sizeof(packet->ip6)),intn->mtu);
+ /* Would adding it not fit? -> Send it out */
+ if (((length + sizeof (packet->ip6) + sizeof (*src)) > (intn->mtu)) && srcn) {
+ //fprintf(stdout,"next source addr. does not fit... sending... \n");
+ //fprintf(stdout,"src_index = %d grec->grec_nsrcs = %d \n",src_index,grec->grec_nsrcs);
+
+ /* Take care of endianess */
+ packet->mld2r.ngrec = htons (packet->mld2r.ngrec);
+ grec->grec_nsrcs = htons (grec->grec_nsrcs);
+ /* Calculate and fill in the checksum */
+
+ packet->ip6.ip6_plen = htons (length);
+ packet->mld2r.csum = htons (0);
+ packet->mld2r.csum = ipv6_checksum (&packet->ip6, IPPROTO_ICMPV6, (uint8_t *) & packet->mld2r, length - sizeof (struct ip6_hbh) - sizeof (packet->routeralert));
+
+ count++;
+ dbg ("%04d.Sending2 MLDv2 Report on %s/%u, ngrec=%u, length=%u sources=%u (in last grec)\n", count, intn->name, intn->ifindex, ntohs (packet->mld2r.ngrec), length, ntohs (grec->grec_nsrcs));
+ sendpacket6 (intn, (const struct ip6_hdr *) packet, length + sizeof (packet->ip6));
+
+ /* Increase ICMP sent statistics */
+ g_conf->stat_icmp_sent++;
+ intn->stat_icmp_sent++;
+
+ /* Reset the MLDv2 struct */
+ packet->mld2r.ngrec = 0;
+ src = NULL;
+ grec = NULL;
+ //if not IS_EX or TO EXCLUDE_MODE splitting must be done
+ break;
+ }
+
+ /* Only add non-:: addresses */
+ if (!srcn)
+ break;
+ if (!IN6_IS_ADDR_UNSPECIFIED (sources + src_index) && srcn) {
+ /* First/Next address */
+ src = (struct in6_addr *) (((char *) grec) + sizeof (*grec) + (sizeof (*src) * grec->grec_nsrcs));
+ /* An additional source */
+ grec->grec_nsrcs++;
+ if (mode) {
+ grec->grec_type = mode; //MLD2_MODE_IS_EXCLUDE;
+ }
+ /* Append the source address */
+ memcpy (src, sources + src_index, sizeof (*src));
+ }
+ }
+ }
+
+ //fprintf(stdout,"done\n");
+ if (packet->mld2r.ngrec == 0) {
+ //fprintf(stdout,"All data sent !!!!!!\n");
+ free (packet);
+ packet = NULL;
+ return (1);
+ }
+ /* Take care of endianess */
+ length = (((char *) grec) - ((char *) packet) + sizeof (*grec) + (sizeof (*src) * (grec->grec_nsrcs)) - sizeof (packet->ip6));
+ packet->mld2r.ngrec = htons (packet->mld2r.ngrec);
+ grec->grec_nsrcs = htons (grec->grec_nsrcs);
+
+ /* Calculate and fill in the checksum */
+ packet->ip6.ip6_plen = htons (length);
+ packet->mld2r.csum = htons (0);
+ packet->mld2r.csum = ipv6_checksum (&packet->ip6, IPPROTO_ICMPV6, (uint8_t *) & packet->mld2r, length - sizeof (struct ip6_hbh) - sizeof (packet->routeralert));
+ count++;
+ dbg ("%04d.Sending2 MLDv2 Report on %s/%u, ngrec=%u, length=%u sources=%u (in last grec)\n", count, intn->name, intn->ifindex, ntohs (packet->mld2r.ngrec), length, ntohs (grec->grec_nsrcs));
+ sendpacket6 (intn, (const struct ip6_hdr *) packet, length + sizeof (packet->ip6));
+
+ /* Increase ICMP sent statistics */
+ g_conf->stat_icmp_sent++;
+ intn->stat_icmp_sent++;
+
+ free (packet);
+ //fprintf(stdout,"Total ICMP packets sent = %llu\n", intn->stat_icmp_sent );
+ return 0;
+}
diff --git a/mcast/common/mld_common.c b/mcast/common/mld_common.c
new file mode 100644
index 0000000..77e05bd
--- /dev/null
+++ b/mcast/common/mld_common.c
@@ -0,0 +1,243 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ */
+
+#include "headers.h"
+struct conf *g_conf=NULL;
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+#ifdef DEBUG
+struct lookup icmpv6_types[] = {
+ {ICMP6_DST_UNREACH, "Destination Unreachable"},
+ {ICMP6_PACKET_TOO_BIG, "Packet too big"},
+ {ICMP6_TIME_EXCEEDED, "Time Exceeded"},
+ {ICMP6_PARAM_PROB, "Parameter Problem"},
+ {ICMP6_ECHO_REQUEST, "Echo Request"},
+ {ICMP6_ECHO_REPLY, "Echo Reply"},
+ {ICMP6_MEMBERSHIP_QUERY, "Membership Query"},
+ {ICMP6_MEMBERSHIP_REPORT, "Membership Report"},
+ {ICMP6_MEMBERSHIP_REDUCTION, "Membership Reduction"},
+ {ICMP6_V2_MEMBERSHIP_REPORT, "Membership Report (V2)"},
+ {ICMP6_V2_MEMBERSHIP_REPORT_EXP, "Membership Report (V2) - Experimental"},
+ {ND_ROUTER_SOLICIT, "ND Router Solicitation"},
+ {ND_ROUTER_ADVERT, "ND Router Advertisement"},
+ {ND_NEIGHBOR_SOLICIT, "ND Neighbour Solicitation"},
+ {ND_NEIGHBOR_ADVERT, "ND Neighbour Advertisement"},
+ {ND_REDIRECT, "ND Redirect"},
+ {ICMP6_ROUTER_RENUMBERING, "Router Renumbering",},
+ {ICMP6_NI_QUERY, "Node Information Query"},
+ {ICMP6_NI_REPLY, "Node Information Reply"},
+ {MLD_MTRACE_RESP, "Mtrace Response"},
+ {MLD_MTRACE, "Mtrace Message"},
+ {0, NULL},
+}, icmpv6_codes_unreach[] = {
+ {ICMP6_DST_UNREACH_NOROUTE, "No route to destination"},
+ {ICMP6_DST_UNREACH_ADMIN, "Administratively prohibited"},
+ {ICMP6_DST_UNREACH_NOTNEIGHBOR, "Not a neighbor (obsolete)"},
+ {ICMP6_DST_UNREACH_BEYONDSCOPE, "Beyond scope of source address"},
+ {ICMP6_DST_UNREACH_ADDR, "Address Unreachable"},
+ {ICMP6_DST_UNREACH_NOPORT, "Port Unreachable"},
+}, icmpv6_codes_ttl[] = {
+
+ {ICMP6_TIME_EXCEED_TRANSIT, "Time Exceeded during Transit",},
+ {ICMP6_TIME_EXCEED_REASSEMBLY, "Time Exceeded during Reassembly"},
+}, icmpv6_codes_param[] = {
+
+ {ICMP6_PARAMPROB_HEADER, "Erroneous Header Field"},
+ {ICMP6_PARAMPROB_NEXTHEADER, "Unrecognized Next Header"},
+ {ICMP6_PARAMPROB_OPTION, "Unrecognized Option"},
+}, icmpv6_codes_ni[] = {
+
+ {ICMP6_NI_SUCCESS, "Node Information Successful Reply"},
+ {ICMP6_NI_REFUSED, "Node Information Request Is Refused"},
+ {ICMP6_NI_UNKNOWN, "Unknown Qtype"},
+}, icmpv6_codes_renumber[] = {
+
+ {ICMP6_ROUTER_RENUMBERING_COMMAND, "Router Renumbering Command"},
+ {ICMP6_ROUTER_RENUMBERING_RESULT, "Router Renumbering Result"},
+ {ICMP6_ROUTER_RENUMBERING_SEQNUM_RESET, "Router Renumbering Sequence Number Reset"},
+}, mld2_grec_types[] = {
+
+ {MLD2_MODE_IS_INCLUDE, "MLDv2 Mode Is Include"},
+ {MLD2_MODE_IS_EXCLUDE, "MLDv2 Mode Is Exclude"},
+ {MLD2_CHANGE_TO_INCLUDE, "MLDv2 Change to Include"},
+ {MLD2_CHANGE_TO_EXCLUDE, "MLDv2 Change to Exclude"},
+ {MLD2_ALLOW_NEW_SOURCES, "MLDv2 Allow New Source"},
+ {MLD2_BLOCK_OLD_SOURCES, "MLDv2 Block Old Sources"},
+};
+#endif
+
+//----------------------------------------------------------------------------------------------------------------
+const char *lookup (struct lookup *l, unsigned int num)
+{
+ unsigned int i;
+ for (i = 0; l && l[i].desc; i++) {
+ if (l[i].num != num)
+ continue;
+ return l[i].desc;
+ }
+ return "Unknown";
+}
+
+const char *icmpv6_type (unsigned int type)
+{
+#ifdef DEBUG
+ return lookup (icmpv6_types, type);
+#else
+ return "";
+#endif
+}
+
+const char *icmpv6_code (unsigned int type, unsigned int code)
+{
+#ifdef DEBUG
+ struct lookup *l = NULL;
+ switch (type) {
+ case ICMP6_DST_UNREACH:
+ l = icmpv6_codes_unreach;
+ break;
+ case ICMP6_TIME_EXCEEDED:
+ l = icmpv6_codes_ttl;
+ break;
+ case ICMP6_PARAM_PROB:
+ l = icmpv6_codes_param;
+ break;
+ case ICMP6_NI_QUERY:
+ case ICMP6_NI_REPLY:
+ l = icmpv6_codes_ni;
+ break;
+ case ICMP6_ROUTER_RENUMBERING:
+ l = icmpv6_codes_renumber;
+ break;
+ }
+ return lookup (l, code);
+#else
+ return "";
+#endif
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+uint16_t inchksum (const void *data, uint32_t length)
+{
+ register long sum = 0;
+ register const uint16_t *wrd = (const uint16_t *) data;
+ register long slen = (long) length;
+
+ while (slen >= 2) {
+ sum += *wrd++;
+ slen -= 2;
+ }
+
+ if (slen > 0)
+ sum += *(const uint8_t *) wrd;
+
+ while (sum >> 16)
+ sum = (sum & 0xffff) + (sum >> 16);
+
+ return (uint16_t) sum;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+uint16_t ipv6_checksum (const struct ip6_hdr * ip6, uint8_t protocol, const void *data, const uint16_t length)
+{
+ struct
+ {
+ uint16_t length;
+ uint16_t zero1;
+ uint8_t zero2;
+ uint8_t next;
+ } pseudo;
+ register uint32_t chksum = 0;
+
+ pseudo.length = htons (length);
+ pseudo.zero1 = 0;
+ pseudo.zero2 = 0;
+ pseudo.next = protocol;
+
+ /* IPv6 Source + Dest */
+ chksum = inchksum (&ip6->ip6_src, sizeof (ip6->ip6_src) + sizeof (ip6->ip6_dst));
+ chksum += inchksum (&pseudo, sizeof (pseudo));
+ chksum += inchksum (data, length);
+
+ /* Wrap in the carries to reduce chksum to 16 bits. */
+ chksum = (chksum >> 16) + (chksum & 0xffff);
+ chksum += (chksum >> 16);
+
+ /* Take ones-complement and replace 0 with 0xFFFF. */
+ chksum = (uint16_t) ~ chksum;
+ if (chksum == 0UL)
+ chksum = 0xffffUL;
+ return (uint16_t) chksum;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+void sendpacket6 (struct intnode *intn, const struct ip6_hdr *iph, const uint16_t len)
+{
+ int sent;
+#if ! (defined WIN32 || defined APPLE)
+ struct sockaddr_ll sa;
+
+ memset (&sa, 0, sizeof (sa));
+
+ sa.sll_family = AF_PACKET;
+ sa.sll_protocol = htons (ETH_P_IPV6);
+ sa.sll_ifindex = intn->ifindex;
+ sa.sll_hatype = intn->hwaddr.sa_family;
+ sa.sll_pkttype = 0;
+ sa.sll_halen = 6;
+
+ /*
+ * Construct a Ethernet MAC address from the IPv6 destination multicast address.
+ * Per RFC2464
+ */
+ sa.sll_addr[0] = 0x33;
+ sa.sll_addr[1] = 0x33;
+ sa.sll_addr[2] = iph->ip6_dst.s6_addr[12];
+ sa.sll_addr[3] = iph->ip6_dst.s6_addr[13];
+ sa.sll_addr[4] = iph->ip6_dst.s6_addr[14];
+ sa.sll_addr[5] = iph->ip6_dst.s6_addr[15];
+
+ /* Send the packet */
+ errno = 0;
+
+#else
+// info("Send on Interface %s@%d len:%d\n",intn->name, intn->ifindex, len);
+ struct sockaddr_in6 sa;
+ memset (&sa, 0, sizeof (sa));
+
+ sa.sin6_family = AF_INET6;
+ sa.sin6_addr = iph->ip6_dst;
+#endif
+#ifdef APPLE
+ unsigned char *x=(unsigned char *)iph;
+ sent = sendto (g_conf->rawsocket, (_SOTYPE)x+40, len-40, 0, (struct sockaddr *) &sa, sizeof (sa));
+#else
+ sent = sendto (g_conf->rawsocket, (_SOTYPE)iph, len, 0, (struct sockaddr *) &sa, sizeof (sa));
+#endif
+ if (sent < 0) {
+ /*
+ * Remove the device if it doesn't exist anymore,
+ * can happen with dynamic tunnels etc
+ */
+ if (errno == ENXIO) {
+ warn ("Cannot send %u bytes on interface %s received ENXIO, interface %u no longer usable\n", len, intn->name, intn->ifindex);
+ /* Destroy the interface itself */
+ int_destroy (intn);
+ } else
+ warn ("Cannot send %u bytes on interface %s (%d) failed with a mtu of %u: %s (errno %d)\n", len, intn->name, intn->ifindex, intn->mtu, strerror (errno), errno);
+ return;
+ }
+
+ /* Update the global statistics */
+ g_conf->stat_packets_sent++;
+ g_conf->stat_bytes_sent += len;
+
+ /* Update interface statistics */
+ intn->stat_bytes_sent += len;
+ intn->stat_packets_sent++;
+ return;
+}
diff --git a/mcast/common/recv_ccpp.c b/mcast/common/recv_ccpp.c
new file mode 100644
index 0000000..ce15e4c
--- /dev/null
+++ b/mcast/common/recv_ccpp.c
@@ -0,0 +1,1333 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ */
+
+#undef DEBUG
+#include "headers.h"
+
+extern int port;
+extern char iface[IFNAMSIZ];
+
+typedef struct
+{
+ xmlDocPtr doc;
+ xmlChar *str, *key;
+} xml_parser_context_t;
+
+STATIC void clean_xml_parser_thread (void *arg)
+{
+ xml_parser_context_t *c = (xml_parser_context_t *) arg;
+ if (c->str) {
+ xmlFree (c->str);
+ }
+ if (c->key) {
+ xmlFree (c->key);
+ }
+ if (c->doc) {
+ xmlFreeDoc (c->doc);
+ }
+ dbg ("Free XML parser structures!\n");
+}
+
+int get_tra_data (xmlChar * xmlbuff, int buffersize, tra_info_t * tra_info)
+{
+ xml_parser_context_t c;
+ xmlNode *root_element = NULL, *cur_node = NULL;
+
+// xmlKeepBlanksDefault (0); //reomve this f. "text" nodes
+// c.doc = xmlParseMemory ((char *) xmlbuff, buffersize);
+// xmlKeepBlanksDefault doesn't work after patching cam flags
+ c.doc = xmlReadMemory((char *) xmlbuff, buffersize, NULL, "UTF-8", XML_PARSE_NOERROR | XML_PARSE_NOWARNING | XML_PARSE_NOBLANKS );
+ root_element = xmlDocGetRootElement (c.doc);
+ pthread_cleanup_push (clean_xml_parser_thread, &c);
+ time_t t=time(NULL);
+
+ if (root_element != NULL) {
+
+ cur_node = root_element->children;
+
+ if (!xmlStrcmp (cur_node->name, (xmlChar *) "Description")) {
+
+ root_element = cur_node->children;
+ while (root_element != NULL) {
+ c.key = NULL;
+ c.str = NULL;
+ if ((xmlStrcmp (root_element->name, (const xmlChar *) "component"))) {
+ warn ("Cannot parse XML data\n");
+ root_element = root_element->next;
+ continue;
+ }
+
+ cur_node = root_element->children;
+ if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "Description"))) {
+ c.str = xmlGetProp (cur_node, (unsigned char *) "about");
+// fprintf(stdout,"\n%s:\n",c.str);
+// fprintf(stdout,"-----------------------------------------------------------\n");
+ } else {
+ warn ("Cannot parse XML data\n");
+ root_element = root_element->next;
+ continue;
+ }
+#ifdef P2P
+ if (c.str && (!xmlStrcmp (c.str, (const xmlChar *) "P2P_Data"))) {
+ cur_node = cur_node->children;
+ while (cur_node != NULL) {
+ if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "Quit"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("Quit: %s\n", c.key);
+ tra_info->quit = atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "TCA_ID"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("TCA_ID: %s\n", c.key);
+ tra_info->tca_id = atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "MC_Groups"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("MC_Groups: %s\n", c.key);
+ tra_info->mca_grps = atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "IP"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("IP: %s\n", c.key);
+ inet_pton (AF_INET6, (char *) c.key, &tra_info->ipv6);
+ xmlFree (c.key);
+ }
+ }
+ cur_node = cur_node->next;
+ }
+ } else if (c.str && (!xmlStrcmp (c.str, (const xmlChar *) "Tuner_Status"))) {
+#else
+ if (c.str && (!xmlStrcmp (c.str, (const xmlChar *) "Tuner_Status"))) {
+#endif
+ cur_node = cur_node->children;
+ tra_info->tra = (tra_t *) realloc (tra_info->tra, (tra_info->tra_num + 1) * sizeof (tra_t));
+ if (!tra_info->tra) {
+ err ("Cannot get memory for tra_t\n");
+ }
+ tra_t *tra = tra_info->tra + tra_info->tra_num;
+ memset(tra, 0, sizeof (tra_t));
+ tra->magic=MCLI_MAGIC;
+ tra->version=MCLI_VERSION;
+
+ while (cur_node != NULL) {
+ if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "Status"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("Status: %s\n", c.key);
+ tra->s.st = (fe_status_t) atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "Signal"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("Signal: %s\n", c.key);
+ tra->s.strength = (u_int16_t) atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "SNR"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("SNR: %s\n", c.key);
+ tra->s.snr = (u_int16_t) atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "BER"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("BER: %s\n", c.key);
+ tra->s.ber = (u_int32_t) atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "UNC"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("UNC: %s\n", c.key);
+ tra->s.ucblocks = (u_int32_t) atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "Slot"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("Slot: %s\n", c.key);
+ tra->slot = atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "RotorStatus"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("Rotor: %s\n", c.key);
+ tra->rotor_status = (u_int32_t) atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "RotorDiff"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("Rotor: %s\n", c.key);
+ tra->rotor_diff = (u_int32_t) atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "UUID"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("UUID: %s\n", c.key);
+ strncpy (tra->uuid, (char *) c.key, UUID_SIZE-1);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "MCG"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("MCG: %s\n", c.key);
+ inet_pton (AF_INET6, (char *) c.key, &tra->mcg);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "Redirect"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("Redirect: %s\n", c.key);
+ tra->redirect = atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "NIMCurrent"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("NIMCurrent: %s\n", c.key);
+ tra->NIMCurrent = atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "InUse"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("InUse: %s\n", c.key);
+ tra->InUse = atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "Frequency"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("Frequency: %s\n", c.key);
+ tra->fep.frequency = atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "Inversion"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("Inversion: %s\n", c.key);
+ tra->fep.inversion = (fe_spectral_inversion_t)atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "Type"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("Type: %s\n", c.key);
+ tra->fe_type = (fe_type_t)atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ }
+#ifdef P2P
+ else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "Token"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("Token: %s\n", c.key);
+ tra->token = atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "Preference"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("Preference: %s\n", c.key);
+ tra->preference = atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ }
+#endif
+ else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "SymbolRate"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("SymbolRate: %s\n", c.key);
+ int val=atoi ((char *) c.key);
+ switch((int)tra->fe_type) {
+ case FE_DVBS2:
+ case FE_QPSK:
+ tra->fep.u.qpsk.symbol_rate=val;
+ break;
+ case FE_QAM:
+ tra->fep.u.qam.symbol_rate=val;
+ break;
+ case FE_OFDM:
+ default:
+ break;
+ }
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "FecInner"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("FecInner: %s\n", c.key);
+ int val=atoi ((char *) c.key);
+ switch((int)tra->fe_type) {
+ case FE_DVBS2:
+ case FE_QPSK:
+ tra->fep.u.qpsk.fec_inner=(fe_code_rate_t)val;
+ break;
+ case FE_QAM:
+ tra->fep.u.qam.fec_inner=(fe_code_rate_t)val;
+ break;
+ case FE_OFDM:
+ default:
+ break;
+ }
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "Modulation"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("Modulation: %s\n", c.key);
+ int val=atoi ((char *) c.key);
+ switch((int)tra->fe_type) {
+ case FE_QAM:
+ tra->fep.u.qam.modulation=(fe_modulation_t)val;
+ break;
+ case FE_ATSC:
+ tra->fep.u.vsb.modulation=(fe_modulation_t)val;
+ break;
+ case FE_DVBS2:
+ case FE_QPSK:
+ case FE_OFDM:
+ default:
+ break;
+
+ }
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "Bandwidth"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("Bandwidth: %s\n", c.key);
+ tra->fep.u.ofdm.bandwidth=(fe_bandwidth_t)atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "CodeRateHP"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("CodeRateHP: %s\n", c.key);
+ tra->fep.u.ofdm.code_rate_HP=(fe_code_rate_t)atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "CodeRateLP"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("CodeRateLP: %s\n", c.key);
+ tra->fep.u.ofdm.code_rate_LP=(fe_code_rate_t)atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "Constellation"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("Constellation: %s\n", c.key);
+ tra->fep.u.ofdm.constellation=(fe_modulation_t)atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "TransmissionMode"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("TransmissionMode: %s\n", c.key);
+ tra->fep.u.ofdm.transmission_mode=(fe_transmit_mode_t)atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "GuardInterval"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("GuardInterval: %s\n", c.key);
+ tra->fep.u.ofdm.guard_interval=(fe_guard_interval_t)atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "HierarchyInformation"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("HierarchyInformation: %s\n", c.key);
+ tra->fep.u.ofdm.hierarchy_information=(fe_hierarchy_t)atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ }
+ cur_node = cur_node->next;
+ }
+ tra->lastseen=t;
+ tra_info->tra_num++;
+ } else if (c.str && (!xmlStrcmp (c.str, (const xmlChar *) "CAM"))) {
+ cur_node = cur_node->children;
+ cam_info_t *cam = tra_info->cam + tra_info->cam_num;
+ while(cur_node) {
+ if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "Slot"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ cam->slot = atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "Status"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ cam->status = atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "MenuString"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ strncpy(cam->menu_string, (char *) c.key, MAX_MENU_STR_LEN-1);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "Flags"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ cam->flags = (nc_ca_caps_t)atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "MaxSids"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ cam->max_sids = atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "UseSids"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ cam->use_sids = atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "PmtFlag"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ cam->capmt_flag = atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ }
+ cur_node = cur_node->next;
+ }
+ tra_info->cam_num++;
+ }
+ xmlFree (c.str);
+ root_element = root_element->next;
+ }
+ }
+ }
+ xmlFreeDoc (c.doc);
+ pthread_cleanup_pop (0);
+ return (1);
+}
+
+#ifdef CLIENT
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+typedef struct ccpp_thread_context
+{
+ UDPContext *s;
+ xmlChar *buf;
+ xmlChar *dst;
+ int run;
+} ccpp_thread_context_t;
+
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+STATIC void clean_ccpp_thread (void *arg)
+{
+ ccpp_thread_context_t *c = (ccpp_thread_context_t *) arg;
+ if (c->s) {
+#ifdef MULTI_THREAD_RECEIVER
+ udp_close (c->s);
+#else
+ udp_close_buff (c->s);
+#endif
+ }
+ if(c->buf) {
+ free (c->buf);
+ }
+ if(c->dst) {
+ free (c->dst);
+ }
+ dbg ("CCPP thread data buffer for tid %d freed !\n", gettid ());
+}
+
+void *recv_ten (void *arg)
+{
+ recv_info_t *r = (recv_info_t *) arg;
+ ccpp_thread_context_t c;
+ struct in6_addr ten = r->mcg;
+ int n;
+ tra_info_t tra_info;
+ unsigned int dstlen;
+ clock_t lastrecv=0;
+ int donetimeout=0;
+
+ pthread_cleanup_push (clean_ccpp_thread, &c);
+ memset (&c, 0, sizeof (ccpp_thread_context_t));
+
+ c.buf=(xmlChar *)malloc(XML_BUFLEN);
+ if (!c.buf) {
+ err ("Cannot get memory for TEN buffer\n");
+ }
+ c.dst=(xmlChar *)malloc(XML_BUFLEN * 5);
+ if (!c.dst) {
+ err ("Cannot get memory for TEN destination buffer\n");
+ }
+
+#ifdef FE_STATUS_CLEAR
+ memset (&r->fe_status, 0, sizeof(recv_festatus_t));
+ ioctl (r->fd, DVBLO_SET_FRONTEND_STATUS, &r->fe_status);
+#endif
+ memset (&tra_info, 0, sizeof (tra_info_t));
+ tra_info.magic=MCLI_MAGIC;
+ tra_info.version=MCLI_VERSION;
+
+ mcg_set_streaming_group (&ten, STREAMING_TEN);
+#ifdef MULTI_THREAD_RECEIVER
+ c.s = client_udp_open (&ten, port, iface);
+#else
+ c.s = client_udp_open_buff (&ten, port, iface, XML_BUFLEN);
+#endif
+ if (!c.s) {
+ warn ("client_udp_open error !\n");
+ } else {
+#ifdef DEBUG
+ char host[INET6_ADDRSTRLEN];
+ inet_ntop (AF_INET6, &ten, (char *) host, INET6_ADDRSTRLEN);
+ dbg ("Start receive TEN for tid %d receiver %p at %s port %d %s\n", gettid (), r, host, port, iface);
+#endif
+ r->ten_run = 1;
+ while (r->ten_run) {
+#ifdef MULTI_THREAD_RECEIVER
+ if ((n = udp_read (c.s, c.buf, XML_BUFLEN, 1000, NULL)) > 0) {
+#else
+ usleep(100000); // 10 times per seconds should be enough
+ if ((n = udp_read_buff (c.s, c.buf, XML_BUFLEN, 1000, NULL)) > 0) {
+#endif
+ dstlen = XML_BUFLEN*5;
+ if (!gunzip (c.dst, &dstlen, c.buf, n)) {
+ memset (&tra_info, 0, sizeof (tra_info_t));
+ tra_info.magic=MCLI_MAGIC;
+ tra_info.version=MCLI_VERSION;
+
+ pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, NULL);
+ if (get_tra_data (c.dst, dstlen, &tra_info)) {
+ lastrecv=clock();
+ donetimeout=0;
+ if (tra_info.tra_num) {
+ r->fe_status = tra_info.tra->s;
+ if(r->handle_ten) {
+ r->handle_ten (tra_info.tra, r->handle_ten_context);
+ }
+
+ if (tra_info.tra->redirect) {
+#ifdef DEBUG
+ char hostname[INET6_ADDRSTRLEN];
+ inet_ntop (AF_INET6, &tra_info.tra->mcg, hostname, INET6_ADDRSTRLEN);
+ dbg ("Redirect for receiver %p: MCG is at %s\n", r, hostname);
+#endif
+ int ret = recv_redirect (r, tra_info.tra->mcg);
+
+ if (ret) {
+ printf("New MCG for recv_ten !\n");
+#ifdef MULTI_THREAD_RECEIVER
+ udp_close (c.s);
+#else
+ udp_close_buff (c.s);
+#endif
+ struct in6_addr ten = r->mcg;
+ mcg_set_streaming_group (&ten, STREAMING_TEN);
+#ifdef MULTI_THREAD_RECEIVER
+ c.s = client_udp_open (&ten, port, iface);
+#else
+ c.s = client_udp_open_buff (&ten, port, iface, XML_BUFLEN);
+#endif
+ if (!c.s) {
+ warn ("client_udp_open error !\n");
+ break;
+ }
+ }
+ }
+ }
+ free (tra_info.tra);
+ tra_info.tra=NULL;
+ }
+ pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, NULL);
+ } else {
+ dbg ("uncompress failed\n");
+ }
+ } else {
+ if (!donetimeout && (clock()-lastrecv)>(TEN_TIMEOUT*CLOCKS_PER_SEC)) {
+ donetimeout=1;
+ memset (&r->fe_status, 0, sizeof(recv_festatus_t));
+ if(r->handle_ten) {
+ r->handle_ten (NULL, r->handle_ten_context);
+ }
+ dbg ("Signal Timeout on receiver %p!\n", r);
+ }
+ }
+ pthread_testcancel();
+ }
+#ifdef DEBUG
+ dbg ("Stop receive TEN on receiver %p %s %d %s\n", r, host, port, iface);
+#endif
+ }
+ pthread_cleanup_pop (1);
+ r->ten_run = 1;
+ return NULL;
+}
+
+int register_ten_handler (recv_info_t * r, int (*p) (tra_t *, void *c), void *c)
+{
+ r->handle_ten=p;
+ r->handle_ten_context=c;
+ return 0;
+}
+
+void *recv_tra (void *arg)
+{
+ ccpp_thread_context_t c;
+ int n;
+ tra_info_t tra_info;
+ unsigned int dstlen;
+ struct in6_addr tra;
+
+ pthread_cleanup_push (clean_ccpp_thread, &c);
+ memset (&c, 0, sizeof (ccpp_thread_context_t));
+
+ c.buf=(xmlChar *)malloc(XML_BUFLEN);
+ if (!c.buf) {
+ err ("Cannot get memory for TRA buffer\n");
+ }
+ c.dst=(xmlChar *)malloc(XML_BUFLEN * 5);
+ if (!c.dst) {
+ err ("Cannot get memory for TRA destination buffer\n");
+ }
+
+ mcg_init_streaming_group (&tra, STREAMING_TRA);
+
+#ifdef MULTI_THREAD_RECEIVER
+ c.s = client_udp_open (&tra, port, iface);
+#else
+ c.s = client_udp_open_buff (&tra, port, iface, XML_BUFLEN);
+#endif
+ if (!c.s) {
+ warn ("client_udp_open error !\n");
+ } else {
+ c.run=1;
+#ifdef DEBUG
+ char host[INET6_ADDRSTRLEN];
+ inet_ntop (AF_INET6, &tra, (char *) host, INET6_ADDRSTRLEN);
+ dbg ("Start receive TRA at %s port %d %s\n", host, port, iface);
+#endif
+ while (c.run) {
+#ifdef MULTI_THREAD_RECEIVER
+ if ((n = udp_read (c.s, c.buf, XML_BUFLEN, 500000, NULL)) > 0) {
+#else
+ usleep(100000); // 10 times per seconds should be enough
+ if ((n = udp_read_buff (c.s, c.buf, XML_BUFLEN, 500000, NULL)) > 0) {
+#endif
+ dstlen = XML_BUFLEN*5;
+ if (!gunzip (c.dst, &dstlen, c.buf, n)) {
+ memset (&tra_info, 0, sizeof (tra_info_t));
+ tra_info.magic=MCLI_MAGIC;
+ tra_info.version=MCLI_VERSION;
+
+ pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, NULL);
+ if (get_tra_data (c.dst, dstlen, &tra_info)) {
+ handle_tra (&tra_info);
+ }
+ pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, NULL);
+ } else {
+ dbg ("uncompress failed\n");
+ }
+ }
+#ifdef DEBUG
+ dbg ("Stop receive TRA on %s %d %s len:%d\n", host, port, iface, n);
+#endif
+ pthread_testcancel();
+ }
+ }
+ pthread_cleanup_pop (1);
+ return NULL;
+}
+#endif
+
+//--------------------------------------------------------------------------------------------------------------------------
+int get_tca_data (xmlChar * xmlbuff, int buffersize, netceiver_info_t * nc_info)
+{
+ xml_parser_context_t c;
+ xmlNode *root_element, *cur_node;
+
+// xmlKeepBlanksDefault (0); //reomve this f. "text" nodes
+// c.doc = xmlParseMemory ((char *) xmlbuff, buffersize);
+// xmlKeepBlanksDefault doesn't work after patching cam flags
+ c.doc = xmlReadMemory((char *) xmlbuff, buffersize, NULL, "UTF-8", XML_PARSE_NOERROR | XML_PARSE_NOWARNING | XML_PARSE_NOBLANKS );
+ root_element = xmlDocGetRootElement (c.doc);
+ pthread_cleanup_push (clean_xml_parser_thread, &c);
+ nc_info->magic=MCLI_MAGIC;
+ nc_info->version=MCLI_VERSION;
+
+ if (root_element != NULL) {
+ cur_node = root_element->children;
+
+ if (!xmlStrcmp (cur_node->name, (xmlChar *) "Description")) {
+
+ root_element = cur_node->children;
+ while (root_element != NULL) {
+ c.key = NULL;
+ c.str = NULL;
+ if ((xmlStrcmp (root_element->name, (const xmlChar *) "component"))) {
+ warn ("Cannot parse XML data\n");
+ root_element = root_element->next;
+ continue;
+ }
+
+ cur_node = root_element->children;
+ if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "Description"))) {
+ c.str = xmlGetProp (cur_node, (unsigned char *) "about");
+ } else {
+ warn ("Cannot parse XML data\n");
+ root_element = root_element->next;
+ continue;
+ }
+ if (c.str && (!xmlStrcmp (c.str, (const xmlChar *) "Platform"))) {
+ cur_node = cur_node->children;
+ while (cur_node != NULL) {
+ if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "OSVersion"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("OSVersion: %s\n", c.key);
+ strncpy (nc_info->OSVersion, (char *) c.key, UUID_SIZE-1);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "AppVersion"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("AppVersion: %s\n", c.key);
+ strncpy (nc_info->AppVersion, (char *) c.key, UUID_SIZE-1);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "FirmwareVersion"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("FirmwareVersion: %s\n", c.key);
+ strncpy (nc_info->FirmwareVersion, (char *) c.key, UUID_SIZE-1);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "HardwareVersion"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("HardwareVersion: %s\n", c.key);
+ strncpy (nc_info->HardwareVersion, (char *) c.key, UUID_SIZE-1);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "Serial"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("Serial: %s\n", c.key);
+ strncpy (nc_info->Serial, (char *) c.key, UUID_SIZE-1);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "Vendor"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("Vendor: %s\n", c.key);
+ strncpy (nc_info->Vendor, (char *) c.key, UUID_SIZE-1);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "DefCon"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("DefCon: %s\n", c.key);
+ nc_info->DefCon = atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "UUID"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("UUID: %s\n", c.key);
+ strncpy (nc_info->uuid, (char *) c.key, UUID_SIZE-1);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "Description"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("Description: %s\n", c.key);
+ strncpy (nc_info->Description, (char *) c.key, UUID_SIZE-1);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "IP"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("IP: %s\n", c.key);
+ inet_pton (AF_INET6, (char *) c.key, &nc_info->ip);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "ProcessUptime"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("ProcessUptime: %s\n", c.key);
+ nc_info->ProcessUptime=atoi((char *)c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "SystemUptime"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("SystemUptime: %s\n", c.key);
+ nc_info->SystemUptime=atoi((char *)c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "TunerTimeout"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("TunerTimeout: %s\n", c.key);
+ nc_info->TunerTimeout=atoi((char *)c.key);
+ xmlFree (c.key);
+ }
+ }
+ cur_node = cur_node->next;
+ }
+ } else if (c.str && (!xmlStrcmp (c.str, (const xmlChar *) "Tuner"))) {
+ cur_node = cur_node->children;
+ nc_info->tuner = (tuner_info_t *) realloc (nc_info->tuner, (nc_info->tuner_num + 1) * sizeof (tuner_info_t));
+ if (!nc_info->tuner) {
+ err ("Cannot get memory for tuner_info\n");
+ }
+
+ tuner_info_t *t = nc_info->tuner + nc_info->tuner_num;
+ memset (t, 0, sizeof (tuner_info_t));
+ t->magic=MCLI_MAGIC;
+ t->version=MCLI_VERSION;
+
+ while (cur_node != NULL) {
+ if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "Name"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ strncpy (t->fe_info.name, (char *) c.key, 127);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "Type"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ if ((!xmlStrcmp (c.key, (const xmlChar *) "DVB-S")))
+ t->fe_info.type = FE_QPSK;
+ if ((!xmlStrcmp (c.key, (const xmlChar *) "DVB-S2")))
+ t->fe_info.type = (fe_type_t)FE_DVBS2;
+ if ((!xmlStrcmp (c.key, (const xmlChar *) "DVB-C")))
+ t->fe_info.type = FE_QAM;
+ if ((!xmlStrcmp (c.key, (const xmlChar *) "DVB-T")))
+ t->fe_info.type = FE_OFDM;
+ if ((!xmlStrcmp (c.key, (const xmlChar *) "ATSC")))
+ t->fe_info.type = FE_ATSC;
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "FrequencyMin"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ t->fe_info.frequency_min = atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "FrequencyMax"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ t->fe_info.frequency_max = atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "FrequencyStepSize"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ t->fe_info.frequency_stepsize = atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "FrequencyTolerance"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ t->fe_info.frequency_tolerance = atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "SymbolRateMin"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ t->fe_info.symbol_rate_min = atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "SymbolRateMax"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ t->fe_info.symbol_rate_max = atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "SymbolRateTolerance"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ t->fe_info.symbol_rate_tolerance = atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "Caps"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ t->fe_info.caps = (fe_caps_t)atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "Slot"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ t->slot = atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "Preference"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ t->preference = atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "UUID"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ strncpy (t->uuid, (char *) c.key, UUID_SIZE-1);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "SatelliteListName"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ strncpy (t->SatelliteListName, (char *) c.key, UUID_SIZE-1);
+ xmlFree (c.key);
+ }
+ }
+ cur_node = cur_node->next;
+ }
+ nc_info->tuner_num++;
+ } else if (c.str && !(xmlStrcmp (c.str, (xmlChar *) "CI"))) {
+ cur_node = cur_node->children;
+ recv_cacaps_t *ci=&nc_info->ci;
+ while(cur_node) {
+ if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "component"))) {
+ xmlNode *l2_node = cur_node->children;
+ if ((!xmlStrcmp (l2_node->name, (const xmlChar *) "Description"))) {
+ c.key = xmlGetProp (l2_node, (unsigned char *) "about");
+ dbg ("Parsing CI-Description: %s\n", c.key);
+ if (c.key && !xmlStrcmp (c.key, (xmlChar *) "Capabilities")) {
+ xmlFree (c.key);
+ xmlNode * l3_node = l2_node->children;
+ while (l3_node != NULL) {
+ dbg ("Capability-Element: %s\n", l3_node->name);
+ if ((!xmlStrcmp (l3_node->name, (const xmlChar *) "SlotNum"))) {
+ c.key = xmlNodeListGetString (c.doc, l3_node->xmlChildrenNode, 1);
+ if(c.key) {
+ dbg ("SlotNum: %s\n", c.key);
+ ci->cap.slot_num=atoi((char*)c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (l3_node->name, (const xmlChar *) "SlotType"))) {
+ c.key = xmlNodeListGetString (c.doc, l3_node->xmlChildrenNode, 1);
+ if(c.key) {
+ dbg ("SlotType: %s\n", c.key);
+ ci->cap.slot_type=atoi((char*)c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (l3_node->name, (const xmlChar *) "DescrNum"))) {
+ c.key = xmlNodeListGetString (c.doc, l3_node->xmlChildrenNode, 1);
+ if(c.key) {
+ dbg ("DescrNum: %s\n", c.key);
+ ci->cap.descr_num=atoi((char*)c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (l3_node->name, (const xmlChar *) "DescrType"))) {
+ c.key = xmlNodeListGetString (c.doc, l3_node->xmlChildrenNode, 1);
+ if(c.key) {
+ dbg ("DescrType: %s\n", c.key);
+ ci->cap.descr_type=atoi((char*)c.key);
+ xmlFree (c.key);
+ }
+ }
+ l3_node = l3_node->next;
+ }
+ } else if (c.key && !xmlStrcmp (c.key, (xmlChar *) "Slot")) {
+ xmlFree (c.key);
+ xmlNode *l3_node = l2_node->children;
+ int slot=-1;
+ while (l3_node != NULL) {
+ dbg ("Slot-Element: %s\n", l3_node->name);
+ if ((!xmlStrcmp (l3_node->name, (const xmlChar *) "Num"))) {
+ c.key = xmlNodeListGetString (c.doc, l3_node->xmlChildrenNode, 1);
+ if(c.key) {
+ dbg ("Num: %s\n", c.key);
+ int x=atoi((char*)c.key);
+ if( (x < 0) || (x >= CA_MAX_SLOTS) ) {
+ continue;
+ }
+ slot=x;
+ ci->info[slot].num=slot;
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (l3_node->name, (const xmlChar *) "Type"))) {
+ c.key = xmlNodeListGetString (c.doc, l3_node->xmlChildrenNode, 1);
+ if(c.key) {
+ dbg ("Type: %s\n", c.key);
+ if(slot>=0) {
+ ci->info[slot].type=atoi((char*)c.key);
+ }
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (l3_node->name, (const xmlChar *) "Flags"))) {
+ c.key = xmlNodeListGetString (c.doc, l3_node->xmlChildrenNode, 1);
+ if(c.key) {
+ dbg ("Flags: %s\n", c.key);
+ if(slot>=0) {
+ ci->info[slot].flags=atoi((char*)c.key);
+ }
+ xmlFree (c.key);
+ }
+ }
+ l3_node = l3_node->next;
+ }
+ }
+ }
+ }
+ cur_node = cur_node->next;
+ }
+ //CAM start
+ } else if (c.str && !(xmlStrcmp (c.str, (xmlChar *) "CAM"))) {
+ cur_node = cur_node->children;
+ cam_info_t *cam = nc_info->cam + nc_info->cam_num;
+ while(cur_node) {
+ if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "Slot"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ cam->slot = atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "Status"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ cam->status = atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "MenuString"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ strncpy(cam->menu_string, (char *) c.key, MAX_MENU_STR_LEN-1);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "Flags"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ cam->flags = (nc_ca_caps_t)atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "MaxSids"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ cam->max_sids = atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "UseSids"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ cam->use_sids = atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "PmtFlag"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ cam->capmt_flag = atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ }
+ cur_node = cur_node->next;
+ }
+ nc_info->cam_num++;
+ //CAM end
+ } else if (c.str && !(xmlStrcmp (c.str, (xmlChar *) "SatelliteList"))) {
+ cur_node = cur_node->children;
+ nc_info->sat_list = (satellite_list_t *) realloc (nc_info->sat_list, (nc_info->sat_list_num + 1) * sizeof (satellite_list_t));
+ if (!nc_info->sat_list) {
+ err ("Cannot get memory for sat_list\n");
+ }
+
+ satellite_list_t *sat_list = nc_info->sat_list + nc_info->sat_list_num;
+ memset (sat_list, 0, sizeof (satellite_list_t));
+ sat_list->magic=MCLI_MAGIC;
+ sat_list->version=MCLI_VERSION;
+
+ while (cur_node != NULL) {
+ if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "SatelliteListName"))) {
+ c.key = xmlNodeListGetString (c.doc, cur_node->xmlChildrenNode, 1);
+ if (c.key) {
+ dbg ("SatelliteListName: %s\n", c.key);
+ strncpy (sat_list->Name, (char *) c.key, UUID_SIZE-1);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (cur_node->name, (const xmlChar *) "component"))) {
+ xmlNode *l2_node = cur_node->children;
+ if ((!xmlStrcmp (l2_node->name, (const xmlChar *) "Description"))) {
+ c.key = xmlGetProp (l2_node, (unsigned char *) "about");
+ dbg ("Parsing L2-Description: %s\n", c.key);
+ if (c.key && !xmlStrcmp (c.key, (xmlChar *) "Satellite")) {
+ xmlFree (c.key);
+ l2_node = l2_node->children;
+ sat_list->sat = (satellite_info_t *) realloc (sat_list->sat, (sat_list->sat_num + 1) * sizeof (satellite_info_t));
+ if (!sat_list->sat) {
+ err ("Cannot get memory for sat\n");
+ }
+
+ satellite_info_t *sat = sat_list->sat + sat_list->sat_num;
+ memset (sat, 0, sizeof (satellite_info_t));
+ sat->magic=MCLI_MAGIC;
+ sat->version=MCLI_VERSION;
+
+ while (l2_node != NULL) {
+ dbg ("L2-Element: %s\n", l2_node->name);
+ if ((!xmlStrcmp (l2_node->name, (const xmlChar *) "Name"))) {
+ c.key = xmlNodeListGetString (c.doc, l2_node->xmlChildrenNode, 1);
+ if(c.key) {
+ dbg ("Name: %s\n", c.key);
+ strncpy (sat->Name, (char *) c.key, UUID_SIZE-1);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (l2_node->name, (const xmlChar *) "Position"))) {
+ c.key = xmlNodeListGetString (c.doc, l2_node->xmlChildrenNode, 1);
+ if(c.key) {
+ dbg ("Position: %s\n", c.key);
+ sat->SatPos = atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (l2_node->name, (const xmlChar *) "PositionMin"))) {
+ c.key = xmlNodeListGetString (c.doc, l2_node->xmlChildrenNode, 1);
+ if(c.key) {
+ dbg ("PositionMin: %s\n", c.key);
+ sat->SatPosMin = atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (l2_node->name, (const xmlChar *) "PositionMax"))) {
+ c.key = xmlNodeListGetString (c.doc, l2_node->xmlChildrenNode, 1);
+ if(c.key) {
+ dbg ("PositionMax: %s\n", c.key);
+ sat->SatPosMax = atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (l2_node->name, (const xmlChar *) "AutoFocus"))) {
+ c.key = xmlNodeListGetString (c.doc, l2_node->xmlChildrenNode, 1);
+ if(c.key) {
+ dbg ("AutoFocus: %s\n", c.key);
+ sat->AutoFocus = atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (l2_node->name, (const xmlChar *) "Latitude"))) {
+ c.key = xmlNodeListGetString (c.doc, l2_node->xmlChildrenNode, 1);
+ if(c.key) {
+ dbg ("Latitude: %s\n", c.key);
+ sat->Latitude = atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (l2_node->name, (const xmlChar *) "Longitude"))) {
+ c.key = xmlNodeListGetString (c.doc, l2_node->xmlChildrenNode, 1);
+ if(c.key) {
+ dbg ("Longitude: %s\n", c.key);
+ sat->Longitude = atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (l2_node->name, (const xmlChar *) "Type"))) {
+ c.key = xmlNodeListGetString (c.doc, l2_node->xmlChildrenNode, 1);
+ if(c.key) {
+ dbg ("Type: %s\n", c.key);
+ sat->type = (satellite_source_t)atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (l2_node->name, (const xmlChar *) "component"))) {
+ xmlNode *l3_node = l2_node->children;
+
+ if ((!xmlStrcmp (l3_node->name, (const xmlChar *) "Description"))) {
+ c.key = xmlGetProp (l3_node, (unsigned char *) "about");
+ dbg ("Parsing L3-Description: %s\n", c.key);
+ if (c.key && !xmlStrcmp (c.key, (xmlChar *) "SatelliteComponent")) {
+ xmlFree (c.key);
+ l3_node = l3_node->children;
+ dbg ("Now checking for SatelliteCompontents\n");
+ sat->comp = (satellite_component_t *) realloc (sat->comp, (sat->comp_num + 1) * sizeof (satellite_component_t));
+ if (!sat->comp) {
+ err ("Cannot get memory for comp\n");
+ }
+
+ satellite_component_t *comp = sat->comp + sat->comp_num;
+ memset (comp, 0, sizeof (satellite_component_t));
+ comp->magic=MCLI_MAGIC;
+ comp->version=MCLI_VERSION;
+
+ while (l3_node != NULL) {
+ dbg ("L3-Element: %s\n", l3_node->name);
+ if ((!xmlStrcmp (l3_node->name, (const xmlChar *) "Polarisation"))) {
+ c.key = xmlNodeListGetString (c.doc, l3_node->xmlChildrenNode, 1);
+ if(c.key) {
+ dbg ("Polarisation: %s\n", c.key);
+ comp->Polarisation = (polarisation_t)atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (l3_node->name, (const xmlChar *) "RangeMin"))) {
+ c.key = xmlNodeListGetString (c.doc, l3_node->xmlChildrenNode, 1);
+ if(c.key) {
+ dbg ("RangeMin: %s\n", c.key);
+ comp->RangeMin = atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (l3_node->name, (const xmlChar *) "RangeMax"))) {
+ c.key = xmlNodeListGetString (c.doc, l3_node->xmlChildrenNode, 1);
+ if(c.key) {
+ dbg ("RangeMax: %s\n", c.key);
+ comp->RangeMax = atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (l3_node->name, (const xmlChar *) "LOF"))) {
+ c.key = xmlNodeListGetString (c.doc, l3_node->xmlChildrenNode, 1);
+ if(c.key) {
+ dbg ("LOF: %s\n", c.key);
+ comp->LOF = atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (l3_node->name, (const xmlChar *) "Voltage"))) {
+ c.key = xmlNodeListGetString (c.doc, l3_node->xmlChildrenNode, 1);
+ if(c.key) {
+ dbg ("Voltage: %s\n", c.key);
+ comp->sec.voltage = (fe_sec_voltage_t)atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (l3_node->name, (const xmlChar *) "Tone"))) {
+ c.key = xmlNodeListGetString (c.doc, l3_node->xmlChildrenNode, 1);
+ if(c.key) {
+ dbg ("Tone: %s\n", c.key);
+ comp->sec.tone_mode = (fe_sec_tone_mode_t)atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (l3_node->name, (const xmlChar *) "MiniCmd"))) {
+ c.key = xmlNodeListGetString (c.doc, l3_node->xmlChildrenNode, 1);
+ if(c.key) {
+ dbg ("MiniCmd: %s\n", c.key);
+ comp->sec.mini_cmd = (fe_sec_mini_cmd_t)atoi ((char *) c.key);
+ xmlFree (c.key);
+ }
+ } else if ((!xmlStrcmp (l3_node->name, (const xmlChar *) "DiSEqC_Cmd"))) {
+ c.key = xmlNodeListGetString (c.doc, l3_node->xmlChildrenNode, 1);
+ dbg ("DiSEqC_Cmd: %s\n", c.key);
+ if(c.key) {
+ int v[6], i, n=0;
+ char *s= (char *)c.key;
+ struct dvb_diseqc_master_cmd *diseqc_cmd=&comp->sec.diseqc_cmd;
+ do {
+ dbg("Parsing: %s\n",s);
+ diseqc_cmd->msg_len = sscanf (s, "%x %x %x %x %x %x", v, v + 1, v + 2, v + 3, v + 4, v + 5);
+ for (i = 0; i < diseqc_cmd->msg_len; i++) {
+ diseqc_cmd->msg[i] = v[i];
+ }
+ s=strchr(s,',');
+ if(s) {
+ s++;
+ }
+ diseqc_cmd=comp->diseqc_cmd+n;
+ n++;
+ } while(s && n<=DISEQC_MAX_EXTRA);
+ xmlFree (c.key);
+ comp->diseqc_cmd_num=n;
+ }
+ }
+ l3_node = l3_node->next;
+ }
+ sat->comp_num++;
+ } else {
+ xmlFree (c.key);
+ }
+ }
+ }
+ l2_node = l2_node->next;
+ }
+ sat_list->sat_num++;
+ } else {
+ xmlFree (c.key);
+ }
+ }
+ }
+ cur_node = cur_node->next;
+ }
+ nc_info->sat_list_num++;
+ }
+ xmlFree (c.str);
+ root_element = root_element->next;
+ }
+ }
+ }
+
+ xmlFreeDoc (c.doc);
+ pthread_cleanup_pop (0);
+ return (1);
+}
+
+#ifdef CLIENT
+
+void *recv_tca (void *arg)
+{
+ int n;
+ ccpp_thread_context_t c;
+ unsigned int dstlen;
+ netceiver_info_t nc_info;
+ struct in6_addr tca;
+
+ pthread_cleanup_push (clean_ccpp_thread, &c);
+
+ c.buf=(xmlChar *)malloc(XML_BUFLEN);
+ if (!c.buf) {
+ err ("Cannot get memory for TRA buffer\n");
+ }
+ c.dst=(xmlChar *)malloc(XML_BUFLEN * 5);
+ if (!c.dst) {
+ err ("Cannot get memory for TRA destination buffer\n");
+ }
+
+ mcg_init_streaming_group (&tca, STREAMING_TCA);
+
+#ifdef MULTI_THREAD_RECEIVER
+ c.s = client_udp_open (&tca, port, iface);
+#else
+ c.s = client_udp_open_buff (&tca, port, iface, XML_BUFLEN);
+#endif
+ if (!c.s) {
+ warn ("client_udp_open error !\n");
+ } else {
+ c.run=1;
+#ifdef DEBUG
+ char host[INET6_ADDRSTRLEN];
+ inet_ntop (AF_INET6, &tca, (char *) host, INET6_ADDRSTRLEN);
+ dbg ("Start Receive TCA on interface %s port %d\n", iface, port);
+#endif
+ while (c.run) {
+#ifdef MULTI_THREAD_RECEIVER
+ if ((n = udp_read (c.s, c.buf, XML_BUFLEN, 500000, NULL)) > 0) {
+#else
+ usleep(100000); // 10 times per seconds should be enough
+ if ((n = udp_read_buff (c.s, c.buf, XML_BUFLEN, 500000, NULL)) > 0) {
+#endif
+ dstlen = XML_BUFLEN * 5;
+ if (!gunzip (c.dst, &dstlen, c.buf, n)) {
+ memset (&nc_info, 0, sizeof (netceiver_info_t));
+
+ pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, NULL);
+ get_tca_data (c.dst, dstlen, &nc_info);
+ handle_tca (&nc_info);
+ pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, NULL);
+ } else {
+ dbg ("uncompress failed\n");
+ }
+ }
+ pthread_testcancel();
+ }
+ }
+ pthread_cleanup_pop (1);
+ return NULL;
+}
+#endif
diff --git a/mcast/common/recv_ccpp.h b/mcast/common/recv_ccpp.h
new file mode 100644
index 0000000..78e1b83
--- /dev/null
+++ b/mcast/common/recv_ccpp.h
@@ -0,0 +1,129 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ */
+
+#ifndef __RECV_CCPP_H
+#define __RECV_CCPP_H
+
+#define XML_BUFLEN 65536
+#define TEN_TIMEOUT 2
+#define MAX_MENU_STR_LEN 64
+#define MAX_CAMS 2
+
+
+typedef struct tuner_info
+{
+ int magic;
+ int version;
+
+ struct dvb_frontend_info fe_info;
+ int slot;
+ int preference;
+ char uuid[UUID_SIZE];
+ char SatelliteListName[UUID_SIZE];
+} tuner_info_t;
+
+typedef enum { CA_SINGLE, CA_MULTI_SID, CA_MULTI_TRANSPONDER} nc_ca_caps_t;
+enum { DVBCA_CAMSTATE_MISSING, DVBCA_CAMSTATE_INITIALISING, DVBCA_CAMSTATE_READY};
+
+typedef struct cam_info {
+
+ uint8_t slot;
+ uint8_t status;
+ int max_sids;
+ int use_sids;
+ int capmt_flag;
+ int reserved;
+ nc_ca_caps_t flags;
+
+ char menu_string[MAX_MENU_STR_LEN];
+
+} cam_info_t;
+
+typedef struct netceiver_info
+{
+ int magic;
+ int version;
+
+ char OSVersion[UUID_SIZE];
+ char AppVersion[UUID_SIZE];
+ char FirmwareVersion[UUID_SIZE];
+ char HardwareVersion[UUID_SIZE];
+ char Serial[UUID_SIZE];
+ char Vendor[UUID_SIZE];
+ char uuid[UUID_SIZE];
+ char Description[UUID_SIZE];
+ int TunerTimeout;
+ struct in6_addr ip;
+ int DefCon;
+ time_t SystemUptime;
+ time_t ProcessUptime;
+
+ time_t lastseen;
+
+ tuner_info_t *tuner;
+ recv_cacaps_t ci;
+ satellite_list_t *sat_list;
+ cam_info_t cam[MAX_CAMS];
+
+
+ int tuner_num;
+ int sat_list_num;
+ int cam_num;
+} netceiver_info_t;
+
+typedef struct tra
+{
+ int magic;
+ int version;
+
+ recv_festatus_t s;
+ fe_type_t fe_type;
+ struct dvb_frontend_parameters fep;
+ struct in6_addr mcg;
+ int slot;
+ char uuid[UUID_SIZE];
+ int redirect;
+ int NIMCurrent;
+ int InUse;
+ int rotor_status;
+ time_t lastseen;
+ int rotor_diff;
+#ifdef P2P
+ int preference;
+ int token;
+#endif
+
+} tra_t;
+
+typedef struct tra_info
+{
+ int magic;
+ int version;
+
+ tra_t *tra;
+ int tra_num;
+ cam_info_t cam[MAX_CAMS];
+ int cam_num;
+#ifdef P2P
+ int quit;
+ int tca_id;
+ int mca_grps;
+ struct in6_addr ipv6;
+#endif
+
+} tra_info_t;
+
+typedef struct recv_info recv_info_t;
+
+void *recv_ten (void *arg);
+void *recv_tca (void *arg);
+void *recv_tra (void *arg);
+int get_tca_data (xmlChar * xmlbuff, int buffersize, netceiver_info_t * nc_info);
+int get_tra_data (xmlChar * xmlbuff, int buffersize, tra_info_t * tra_info);
+DLL_SYMBOL int register_ten_handler (recv_info_t * r, int (*p)(tra_t *, void *), void *c);
+#endif
diff --git a/mcast/common/satlists.h b/mcast/common/satlists.h
new file mode 100644
index 0000000..ad95889
--- /dev/null
+++ b/mcast/common/satlists.h
@@ -0,0 +1,92 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ */
+
+#define DISEQC_MAX_EXTRA 8
+#define MAX_EXTRA_DATA 16
+
+typedef enum
+{
+//the defines for circular polarisation are taken from official DiSEqC-Spec at
+//http://www.eutelsat.com/satellites/pdf/Diseqc/Reference%20docs/bus_spec.pdf
+ POL_V = SEC_VOLTAGE_13,
+ POL_H = SEC_VOLTAGE_18,
+ POL_R = SEC_VOLTAGE_13,
+ POL_L = SEC_VOLTAGE_18,
+} polarisation_t;
+
+typedef struct
+{
+ int magic;
+ int version;
+
+ polarisation_t Polarisation; // H/V/L/R
+ int RangeMin; // 11700
+ int RangeMax; // 12750
+
+// SEC Settings to be used for the specification above
+ int LOF; // 9750
+ recv_sec_t sec;
+ struct dvb_diseqc_master_cmd diseqc_cmd[DISEQC_MAX_EXTRA];
+ int diseqc_cmd_num;
+} satellite_component_t;
+
+typedef enum
+{
+ SAT_SRC_LNB=0,
+ SAT_SRC_ROTOR=1,
+ SAT_SRC_UNI=2, // !!! match DISEQC_* values in dvb_server.h !!!
+} satellite_source_t;
+
+typedef struct
+{
+ int magic;
+ int version;
+
+// Specification of satellite parameters
+ char Name[UUID_SIZE]; // Astra 19,2
+ int SatPos; // 1920
+ int SatPosMin; // Only used for SAT_SRC_ROTOR
+ int SatPosMax; // Only used for SAT_SRC_ROTOR
+ satellite_source_t type; // see above
+
+ satellite_component_t *comp; // What to do for polarisation and range for SEC?
+ int comp_num; // Number of components
+ int AutoFocus;
+ int Latitude;
+ int Longitude;
+ int num_extra_data;
+ int extra_data[MAX_EXTRA_DATA]; // reserved
+} satellite_info_t;
+
+typedef struct satellite_list
+{
+ int magic;
+ int version;
+
+ char Name[UUID_SIZE]; // Magic unique identifier
+ satellite_info_t *sat;
+ int sat_num;
+} satellite_list_t;
+
+typedef struct
+{
+ int magic;
+ int version;
+
+ int netceiver;
+ int sat_list;
+ int sat;
+ int comp;
+ int position; // for rotor
+} satellite_reference_t;
+
+DLL_SYMBOL int satellite_find_by_diseqc (satellite_reference_t * ref, recv_sec_t *sec, struct dvb_frontend_parameters *fep, int mode);
+DLL_SYMBOL int satellite_get_pos_by_ref (satellite_reference_t * ref);
+DLL_SYMBOL int satellite_get_lof_by_ref (satellite_reference_t * ref);
+DLL_SYMBOL polarisation_t satellite_find_pol_by_ref (satellite_reference_t * ref);
+DLL_SYMBOL recv_sec_t *satellite_find_sec_by_ref (satellite_reference_t * ref);
diff --git a/mcast/common/siparser.c b/mcast/common/siparser.c
new file mode 100644
index 0000000..4ce7032
--- /dev/null
+++ b/mcast/common/siparser.c
@@ -0,0 +1,1049 @@
+#include "headers.h"
+
+//#define DBG 1
+#define CRC32_CHECK 1
+
+enum ca_desc_type { EMM, ECM };
+
+//-----------------------------------------------------------------------------------
+void printhex_buf(char *msg,unsigned char *buf,int len)
+{
+ int i,j,k;
+ int width=8;
+
+ i=k=0;
+ sys ("%s: %d bytes (0x%04x)\n",msg,len,len);
+ sys ("---------------------------------------------------------------\n");
+ while(len) {
+ sys ("%04x ",k++*width*2);
+ j=i;
+ for(;i < j + width ; i++){
+ if (i >= len) break;
+ sys ("%02x ",buf[i]);
+ }
+ if (i >= len) {
+ sys ("\n");
+ break;
+ }
+ sys(" ");
+ j=i;
+ for(;i < j + width ; i++){
+ if (i >= len) break;
+ sys("%02x ",buf[i]);
+ }
+ sys("\n");
+ if (i >= len) break;
+ }
+ sys("---------------------------------------------------------------\n");
+}
+//-----------------------------------------------------------------------------------
+void writehex_buf(FILE *f, char *msg,unsigned char *buf,int len)
+{
+ int i,j,k;
+ int width=8;
+
+ i=k=0;
+ fprintf(f,"%s: %d bytes (0x%04x)\n",msg,len,len);
+ fprintf(f,"---------------------------------------------------------------\n");
+ while(len) {
+ fprintf(f,"%04x ",k++*width*2);
+ j=i;
+ for(;i < j + width ; i++){
+ if (i >= len) break;
+ fprintf(f,"%02x ",buf[i]);
+ }
+ if (i >= len) {
+ fprintf(f,"\n");
+ break;
+ }
+ fprintf(f," ");
+ j=i;
+ for(;i < j + width ; i++){
+ if (i >= len) break;
+ fprintf(f,"%02x ",buf[i]);
+ }
+ fprintf(f,"\n");
+ if (i >= len) break;
+ }
+ fprintf(f,"---------------------------------------------------------------\n");
+
+
+}
+//-----------------------------------------------------------------------------------
+void print_ts_header(ts_packet_hdr_t *p)
+{
+ info("--------------------------------------------------------------\n");
+ info("TS header data:\n");
+ info("Sync-byte : 0x%04x\n",p->sync_byte);
+ info("Transport error indicator : 0x%04x\n",p->transport_error_indicator);
+ info("Payload unit start indicator : 0x%04x\n",p->payload_unit_start_indicator);
+ info("Transport priority : 0x%04x\n",p->transport_priority);
+ info("PID : 0x%04x\n",p->pid);
+ info("Transport scrambling control : 0x%04x\n",p->transport_scrambling_control);
+ info("Adaptation field control : 0x%04x\n",p->adaptation_field_control);
+ info("Continuity_counter : 0x%04x\n",p->continuity_counter);
+
+}
+//-----------------------------------------------------------------------------------
+void print_pmt(pmt_t *p)
+{
+ info("--------------------------------------------------------------\n");
+ info("PMT section:\n");
+ info("Table ID : %-5d (0x%04x)\n",p->table_id,p->table_id);
+ info("(fixed): : %-5d (0x%04x)\n",0,0);
+ info("Section syntax indicator : %-5d (0x%04x)\n",p->section_syntax_indicator,p->section_syntax_indicator);
+ info("Reserved 1 : %-5d (0x%04x)\n",p->reserved_1,p->reserved_1);
+ info("Section length : %-5d (0x%04x)\n",p->section_length,p->section_length);
+ info("Program number : %-5d (0x%04x)\n",p->program_number,p->program_number);
+ info("Reserved 2 : %-5d (0x%04x)\n",p->reserved_2,p->reserved_2);
+ info("Version number : %-5d (0x%04x)\n",p->version_number,p->version_number);
+ info("Current next indicator : %-5d (0x%04x)\n",p->current_next_indicator,p->current_next_indicator);
+ info("Section number : %-5d (0x%04x)\n",p->section_number,p->section_number);
+ info("Last section number : %-5d (0x%04x)\n",p->last_section_number,p->last_section_number);
+ info("Reserved 3 : %-5d (0x%04x)\n",p->reserved_3,p->reserved_3);
+ info("PCR pid : %-5d (0x%04x)\n",p->pcr_pid,p->pcr_pid);
+ info("Reserved 4 : %-5d (0x%04x)\n",p->reserved_4,p->reserved_4);
+ info("Program info length : %-5d (0x%04x)\n",p->program_info_length,p->program_info_length);
+
+
+
+ info("CRC32 : 0x%04x\n",p->crc32);
+}
+//-----------------------------------------------------------------------------------
+void print_pat(pat_t *p, pat_list_t *pl, int pmt_num)
+{
+ info("--------------------------------------------------------------\n");
+ info("PAT section:\n");
+ info("Table_id : %-5d (0x%04x)\n",p->table_id,p->table_id);
+ info("(fixed): : %-5d (0x%04x)\n",0,0);
+ info("Section syntax indicator : %-5d (0x%04x)\n",p->section_syntax_indicator,p->section_syntax_indicator);
+ info("Reserved_1 : %-5d (0x%04x)\n",p->reserved_1,p->reserved_1);
+ info("Section length : %-5d (0x%04x)\n",p->section_length,p->section_length);
+ info("Transport stream id : %-5d (0x%04x)\n",p->transport_stream_id,p->transport_stream_id);
+ info("Reserved 2 : %-5d (0x%04x)\n",p->reserved_2,p->reserved_2);
+ info("Version number : %-5d (0x%04x)\n",p->version_number,p->version_number);
+ info("Current next indicator : %-5d (0x%04x)\n",p->current_next_indicator,p->current_next_indicator);
+ info("Section number : %-5d (0x%04x)\n",p->section_number,p->section_number);
+ info("Last section number : %-5d (0x%04x)\n",p->last_section_number,p->last_section_number);
+
+ if (pl && pmt_num){
+ int i;
+ info("Number of PMTs in PAT : %-5d \n", pmt_num);
+ for(i=0;i<pmt_num;i++) {
+ pat_list_t *pat = pl + i;
+ info("\nProgram number : %-5d (0x%04x)\n",pat->program_number,pat->program_number);
+ info("Reserved : %-5d (0x%04x)\n",pat->reserved,pat->reserved);
+ info("Network PMT PID : %-5d (0x%04x)\n",pat->network_pmt_pid,pat->network_pmt_pid);
+ }
+ }
+
+ info("CRC32 : 0x%04x\n",p->crc32);
+
+
+}
+//-----------------------------------------------------------------------------------
+char *si_caid_to_name(unsigned int caid)
+{
+
+ str_table table[] = {
+ // -- updated from dvb.org 2003-10-16
+ { 0x0000, 0x0000, "Reserved" },
+ { 0x0001, 0x00FF, "Standardized Systems" },
+ { 0x0100, 0x01FF, "Canal Plus (Seca/MediaGuard)" },
+ { 0x0200, 0x02FF, "CCETT" },
+ { 0x0300, 0x03FF, "MSG MediaServices GmbH" },
+ { 0x0400, 0x04FF, "Eurodec" },
+ { 0x0500, 0x05FF, "France Telecom (Viaccess)" },
+ { 0x0600, 0x06FF, "Irdeto" },
+ { 0x0700, 0x07FF, "Jerrold/GI/Motorola" },
+ { 0x0800, 0x08FF, "Matra Communication" },
+ { 0x0900, 0x09FF, "News Datacom (Videoguard)" },
+ { 0x0A00, 0x0AFF, "Nokia" },
+ { 0x0B00, 0x0BFF, "Norwegian Telekom (Conax)" },
+ { 0x0C00, 0x0CFF, "NTL" },
+ { 0x0D00, 0x0DFF, "Philips (Cryptoworks)" },
+ { 0x0E00, 0x0EFF, "Scientific Atlanta (Power VU)" },
+ { 0x0F00, 0x0FFF, "Sony" },
+ { 0x1000, 0x10FF, "Tandberg Television" },
+ { 0x1100, 0x11FF, "Thompson" },
+ { 0x1200, 0x12FF, "TV/COM" },
+ { 0x1300, 0x13FF, "HPT - Croatian Post and Telecommunications" },
+ { 0x1400, 0x14FF, "HRT - Croatian Radio and Television" },
+ { 0x1500, 0x15FF, "IBM" },
+ { 0x1600, 0x16FF, "Nera" },
+ { 0x1700, 0x17FF, "Beta Technik (Betacrypt)" },
+ { 0x1800, 0x18FF, "Kudelski SA"},
+ { 0x1900, 0x19FF, "Titan Information Systems"},
+ { 0x2000, 0x20FF, "TelefXnica Servicios Audiovisuales"},
+ { 0x2100, 0x21FF, "STENTOR (France Telecom, CNES and DGA)"},
+ { 0x2200, 0x22FF, "Scopus Network Technologies"},
+ { 0x2300, 0x23FF, "BARCO AS"},
+ { 0x2400, 0x24FF, "StarGuide Digital Networks "},
+ { 0x2500, 0x25FF, "Mentor Data System, Inc."},
+ { 0x2600, 0x26FF, "European Broadcasting Union"},
+ { 0x4700, 0x47FF, "General Instrument"},
+ { 0x4800, 0x48FF, "Telemann"},
+ { 0x4900, 0x49FF, "Digital TV Industry Alliance of China"},
+ { 0x4A00, 0x4A0F, "Tsinghua TongFang"},
+ { 0x4A10, 0x4A1F, "Easycas"},
+ { 0x4A20, 0x4A2F, "AlphaCrypt"},
+ { 0x4A30, 0x4A3F, "DVN Holdings"},
+ { 0x4A40, 0x4A4F, "Shanghai Advanced Digital Technology Co. Ltd. (ADT)"},
+ { 0x4A50, 0x4A5F, "Shenzhen Kingsky Company (China) Ltd"},
+ { 0x4A60, 0x4A6F, "@SKY"},
+ { 0x4A70, 0x4A7F, "DreamCrypt"},
+ { 0x4A80, 0x4A8F, "THALESCrypt"},
+ { 0x4A90, 0x4A9F, "Runcom Technologies"},
+ { 0x4AA0, 0x4AAF, "SIDSA"},
+ { 0x4AB0, 0x4ABF, "Beijing Comunicate Technology Inc."},
+ { 0x4AC0, 0x4ACF, "Latens Systems Ltd"},
+ { 0,0, NULL }
+ };
+
+ int i = 0;
+ while (table[i].str) {
+ if (table[i].from <= caid && table[i].to >= caid)
+ return (char *) table[i].str;
+ i++;
+ }
+
+ return (char *) "ERROR: Undefined!";
+}
+//-----------------------------------------------------------------------------------
+void get_time_mjd (unsigned long mjd, long *year , long *month, long *day)
+{
+ if (mjd > 0) {
+ long y,m,d ,k;
+
+ // algo: ETSI EN 300 468 - ANNEX C
+
+ y = (long) ((mjd - 15078.2) / 365.25);
+ m = (long) ((mjd - 14956.1 - (long)(y * 365.25) ) / 30.6001);
+ d = (long) (mjd - 14956 - (long)(y * 365.25) - (long)(m * 30.6001));
+ k = (m == 14 || m == 15) ? 1 : 0;
+ y = y + k + 1900;
+ m = m - 1 - k*12;
+ *year = y;
+ *month = m;
+ *day = d;
+
+ } else {
+ *year = 0;
+ *month = 0;
+ *day = 0;
+ }
+
+}
+//-----------------------------------------------------------------------------------
+void print_tdt(tdt_sect_t *tdt, uint16_t mjd, uint32_t utc)
+{
+ info("--------------------------------------------------------------\n");
+ info("TDT section:\n");
+ info("Table_id : %-5d (0x%04x)\n",tdt->table_id,tdt->table_id);
+ info("Reserved : %-5d (0x%04x)\n",tdt->reserved,tdt->reserved);
+ info("Reserved_1 : %-5d (0x%04x)\n",tdt->reserved_1,tdt->reserved_1);
+ info("Section length : %-5d (0x%04x)\n",tdt->section_length,tdt->section_length);
+ info("UTC_time : 0x%2x%2x%2x%2x%2x\n",tdt->dvbdate[0],tdt->dvbdate[1],tdt->dvbdate[2],tdt->dvbdate[3],tdt->dvbdate[4]);
+
+ long y,m,d;
+ get_time_mjd(mjd, &y, &m, &d);
+ info("TIME: [= %02ld-%02ld-%02ld %02x:%02x:%02x (UTC) ]\n\n",y,m,d,(utc>>16) &0xFF, (utc>>8) &0xFF, (utc) &0xFF);
+ info("--------------------------------------------------------------\n");
+
+}
+//-----------------------------------------------------------------------------------
+void print_ca_desc(si_desc_t *p)
+{
+ info("CA desc. tag : %d (%#x)\n",p->descriptor_tag,p->descriptor_tag);
+ info("CA desc. length : %d (%#x)\n",p->descriptor_length,p->descriptor_length);
+ info("CA system id : %d (%#x)\n",p->ca_system_id,p->ca_system_id);
+ info("Reserverd : %d (%#x)\n",p->reserved,p->reserved);
+ info("CA pid : %d (%#x)\n",p->ca_pid,p->ca_pid);
+
+ printhex_buf((char *)"Private data",p->private_data,p->descriptor_length-4);
+
+}
+//-----------------------------------------------------------------------------------
+void print_ca_bytes(si_desc_t *p)
+{
+ unsigned int i;
+ info("%x %x %x %x %x ",p->descriptor_tag, p->descriptor_length, p->ca_system_id, p->reserved, p->ca_pid);
+ for (i = 0; i < p->descriptor_length - 4; i++)
+ info("%x ",p->private_data[i]);
+ info(";");
+
+}
+//-----------------------------------------------------------------------------------
+void print_cad_lst(si_cad_t *l, int ts_id)
+{
+ int i;
+
+ for (i = 0; i < l->cads; i++) {
+ print_ca_desc(&l->cad[i]);
+ }
+ info("Total CA desc. for TS ID %d : %d\n",ts_id,l->cads);
+}
+//-----------------------------------------------------------------------------------
+int parse_ca_descriptor(unsigned char *desc, si_desc_t *t)
+{
+ unsigned char *ptr=desc;
+ int tag=0,len=0;
+
+ tag=ptr[0];
+ len=ptr[1];
+
+ if (len > MAX_DESC_LEN) {
+ info("descriptor():Descriptor too long !\n");
+ return -1;
+ }
+
+ switch(tag){
+ case 0x09: {
+ t->descriptor_tag=tag;
+ t->descriptor_length=len; //???
+ t->ca_system_id=((ptr[2] << 8) | ptr[3]);
+ t->reserved=(ptr[4] >> 5) & 7;
+ t->ca_pid=((ptr[4] << 8) | ptr[5]) & 0x1fff;
+ //header 4 bytes + 2 bytes
+ memcpy(t->private_data,ptr+6,len-4);
+
+ //print_ca_desc(t);
+
+ break;
+ }
+ default:
+ break;
+ }
+
+ return len + 2; //2 bytes tag + length
+}
+//--------------------------------------------------------------------------------------------
+int ca_free_cpl_desc(ca_pmt_list_t *cpl)
+{
+ if (cpl->pm.size > 0 && cpl->pm.cad)
+ free(cpl->pm.cad);
+ if (cpl->es.size > 0 && cpl->es.cad)
+ free(cpl->es.cad);
+
+ memset(cpl,0,sizeof(ca_pmt_list_t));
+
+ return 0;
+}
+//--------------------------------------------------------------------------------------------
+int descriptor(unsigned char *desc, si_cad_t *c)
+{
+ unsigned char *ptr=desc;
+ int tag=0,len=0;
+
+ tag=ptr[0];
+ len=ptr[1];
+
+ if (len > MAX_DESC_LEN) {
+ info("descriptor():Descriptor too long !\n");
+ return -1;
+ }
+
+ switch(tag){
+ case 0x09: {
+ c->cads++;
+ c->cad = (si_desc_t*)realloc(c->cad,sizeof(si_desc_t)*c->cads);
+ if (!c->cad) {
+ c->cads--;
+ info("descriptor():realloc error\n");
+ return -1;
+ }
+ si_desc_t *t = c->cad + c->cads - 1;
+ t->descriptor_tag=tag;
+ t->descriptor_length=len; //???
+ t->ca_system_id=((ptr[2] << 8) | ptr[3]);
+ t->reserved=(ptr[4] >> 5) & 7;
+ t->ca_pid=((ptr[4] << 8) | ptr[5]) & 0x1fff;
+ //header 4 bytes + 2 bytes
+ if (len - 4 > 0)
+ memcpy(t->private_data,ptr+6,len-4);
+
+ //print_ca_desc(t);
+ break;
+ }
+ default: {
+#if 0
+ other_desc_t d;
+ d.descriptor_tag=tag;
+ d.descriptor_length=len;
+ memcpy(d.data,ptr+2,len);
+ //print_desc(d);
+#endif
+ }
+ }
+
+ return len + 2; //2 bytes tag + length
+}
+
+//-----------------------------------------------------------------------------------
+int si_get_video_pid(unsigned char *esi_buf, int size, int *vpid)
+{
+ int index, pid_num, es_len;
+ unsigned char *ptr = esi_buf;
+
+ index = pid_num = 0;
+ while(index < size) {
+ //ptr[0] //stream type
+ if (ptr[0] == 2 || ptr[0] == 0x1b)
+ {
+ *vpid = ((ptr[1] << 8) | ptr[2]) & 0x1fff;
+ return 1;
+ }
+ es_len = ((ptr[3] << 8) | ptr[4]) & 0x0fff;
+ index += 5 + es_len;
+ ptr += 5 + es_len;
+ }
+
+ *vpid = -1;
+ return 0;
+
+}
+//-----------------------------------------------------------------------------------
+int si_get_audio_pid(unsigned char *esi_buf, int size, int *apid)
+{
+ int index, pid_num, es_len;
+ unsigned char *ptr = esi_buf;
+
+ index = pid_num = 0;
+ while(index < size) {
+ //ptr[0] //stream type
+ if (ptr[0] == 0x1 || ptr[0] == 0x3 || ptr[0] == 0x4)
+ {
+ *apid = ((ptr[1] << 8) | ptr[2]) & 0x1fff;
+ return 1;
+ }
+ es_len = ((ptr[3] << 8) | ptr[4]) & 0x0fff;
+ index += 5 + es_len;
+ ptr += 5 + es_len;
+ }
+
+ *apid = -1;
+ return 0;
+
+}
+//-----------------------------------------------------------------------------------
+int si_get_private_pids(unsigned char *esi_buf, int size, int *upids)
+{
+
+ int index, pid_num, es_len;
+ unsigned char *ptr = esi_buf;
+
+ index = pid_num = 0;
+ while(index < size) {
+ if (ptr[0] == 0x6)
+ {
+ upids[pid_num] = ((ptr[1] << 8) | ptr[2]) & 0x1fff;
+ pid_num++;
+ if (pid_num >= MAX_ES_PIDS) {
+ info ("error: ES pids number out of bounds !\n");
+ return -1;
+ }
+ }
+ es_len = ((ptr[3] << 8) | ptr[4]) & 0x0fff;
+ index += 5 + es_len;
+ ptr += 5 + es_len;
+ }
+
+ return pid_num;
+
+}
+//-----------------------------------------------------------------------------------
+int get_pmt_es_pids(unsigned char *esi_buf, int size, int *es_pids, int all)
+{
+ int index, pid_num, es_len;
+ unsigned char *ptr = esi_buf;
+
+ index = pid_num = 0;
+ while(index < size) {
+ //ptr[0] //stream type
+ //int pid = ((ptr[1] << 8) | ptr[2]) & 0x1fff;
+ //printf("Stream type: %d (%#x) pid = %d (%#x)\n",ptr[0], ptr[0], pid, pid);
+ if (ptr[0] == 0x1 || ptr[0] == 0x2 || ptr[0] == 0x3 || ptr[0] == 0x4 || ptr[0] == 0x6 || ptr[0] == 0x1b || all)
+ {
+ es_pids[pid_num] = ((ptr[1] << 8) | ptr[2]) & 0x1fff;
+ pid_num++;
+ if (pid_num >= MAX_ES_PIDS) {
+ info ("error: ES pids number out of bounds !\n");
+ return -1;
+ }
+ }
+ es_len = ((ptr[3] << 8) | ptr[4]) & 0x0fff;
+ index += 5 + es_len;
+ ptr += 5 + es_len;
+ }
+
+ return pid_num;
+}
+//-----------------------------------------------------------------------------------
+int parse_pmt_ca_desc(unsigned char *buf, int size, int sid, si_ca_pmt_t *pm_cads, si_ca_pmt_t *es_cads, pmt_t *pmt_hdr, int *fta, ca_es_pid_info_t *espids, int *es_pid_num)
+{
+ unsigned char *ptr=buf, tmp[PSI_BUF_SIZE]; //sections can be only 12 bit long
+
+ memset(pm_cads,0,sizeof(si_ca_pmt_t));
+ memset(es_cads,0,sizeof(si_ca_pmt_t));
+ memset(pmt_hdr,0,sizeof(pmt_hdr));
+
+ pmt_hdr->table_id=ptr[0];
+ pmt_hdr->section_syntax_indicator=(ptr[1] >> 7) & 1;
+ pmt_hdr->reserved_1=(ptr[1] >> 4) & 3;
+ pmt_hdr->section_length=((ptr[1] << 8) | ptr[2]) & 0xfff;
+
+ if (pmt_hdr->section_length < 13 || pmt_hdr->section_length > 1021 || (int)pmt_hdr->section_length > size) {
+ info("#####\nERROR: Invalid section length!\n");
+ return -1;
+ }
+
+ u_long crc = dvb_crc32 ((char *)buf,pmt_hdr->section_length+3);
+
+#ifdef DBG
+ info("CRCcc: 0x%lx\n",crc);
+ info("len = %d\n", pmt_hdr->section_length+3);
+#endif
+ if (crc & 0xffffffff) { //FIXME: makr arch flags
+ info("#####\nPMT -> ERROR: parse_pmt_ca_desc() : CRC err. crc = 0x%lx\n", crc);
+ return -1;
+ }
+
+ pmt_hdr->program_number=(ptr[3] << 8) | ptr[4];
+ if ((int)pmt_hdr->program_number != sid) {
+ info("#####\nERROR: Invalid SID in PMT !!!\n");
+ return -1;
+ }
+ pmt_hdr->program_info_length=((ptr[10] << 8) | ptr[11]) & 0x0fff;
+ if (pmt_hdr->program_info_length < 0 || pmt_hdr->program_info_length > 1021 - 9 || (int)pmt_hdr->program_info_length > size - 9) {
+ info("#####\nERROR: Invalid PI length in PMT!\n");
+ return -1;
+ }
+
+ pmt_hdr->reserved_2=(ptr[5] >> 6) & 3;
+ pmt_hdr->version_number=(ptr[5] >> 1) & 0x1f;
+ pmt_hdr->current_next_indicator=ptr[5] & 1;
+ pmt_hdr->section_number=ptr[6];
+ pmt_hdr->last_section_number=ptr[7];
+ pmt_hdr->reserved_3=(ptr[8] >> 5) & 7;
+ pmt_hdr->pcr_pid=((ptr[8] << 8) | ptr[9]) & 0x1fff;
+ pmt_hdr->reserved_4=(ptr[10] >> 4) & 0xf;
+
+ //pmt_hdr->program_info_length=((ptr[10] << 8) | ptr[11]) & 0x0fff;
+ //print_pmt(pmt_hdr);
+
+ int buf_len=0,len=0;
+ unsigned int i=0;
+
+ buf_len = pmt_hdr->section_length - 9;
+ ptr += 12; // 12 byte header
+
+ pm_cads->size = pm_cads->cads = 0;
+ for (i = 0; i < pmt_hdr->program_info_length;) {
+ int dtag = ptr[0];
+ int dlen = ptr[1] + 2;
+ if (dlen > size || dlen > MAX_DESC_LEN) {
+ info("PMT: Invalide CA desc. length!\n");
+ return -1;
+ }
+ if (dtag == 0x09) { //we have CA descriptor
+ memcpy(tmp + pm_cads->size, ptr, dlen);
+ pm_cads->size+=dlen;
+ pm_cads->cads++;
+ *fta=0;
+ }
+ i+=dlen;
+ if (i > pmt_hdr->program_info_length) {
+ info("PMT: Index out of bounds!\n");
+ return -1;
+ }
+
+ ptr+=dlen; //desc. length plus 2 bytes for tag and header;
+ if (ptr >= buf + size) {
+ info("PMT: Invalid Buffer offset !\n");
+ return -1;
+ }
+
+ buf_len-=dlen;
+ if (buf_len < 0) {
+ info("PMT: Index out of bounds!\n");
+ return -1;
+
+ }
+ }
+
+ //parsing ok we can take this program level descriptors
+ if (pm_cads->size && pm_cads->cads) {
+ pm_cads->cad = (unsigned char*)malloc(sizeof(unsigned char)*pm_cads->size);
+ if (!pm_cads->cad) {
+ info("ERROR: parse_ca_desc() : out of memory\n");
+ return -1;
+ }
+ memcpy(pm_cads->cad, tmp, pm_cads->size);
+ }
+
+#ifdef DBG
+ info("%d bytes remaining (program info len = %d bytes)\n",buf_len,i);
+#endif
+
+ int err = 0;
+ es_pmt_info_t esi;
+ es_cads->size = es_cads->cads = 0;
+ *es_pid_num = 0;
+ while (buf_len > 4) { //end of section crc32 is 4 bytes
+ esi.stream_type=ptr[0];
+ esi.reserved_1=(ptr[1] >> 5) & 7;
+ esi.elementary_pid=((ptr[1] << 8) | ptr[2]) & 0x1fff;
+ esi.reserved_2=(ptr[3] >> 4) & 0xf;
+ esi.es_info_length=((ptr[3] << 8) | ptr[4]) & 0x0fff;
+
+ if ((int)esi.es_info_length > buf_len) {
+ info("PMT: Invalid ES info length !\n");
+ err = -1;
+ break;
+ }
+
+ if (espids) {
+ switch(esi.stream_type) {
+ case VIDEO_11172_STREAM_TYPE:
+ case VIDEO_13818_STREAM_TYPE:
+ case VISUAL_MPEG4_STREAM_TYPE:
+ case VIDEO_H264_STREAM_TYPE:
+ case AUDIO_11172_STREAM_TYPE:
+ case AUDIO_13818_STREAM_TYPE:
+ espids[*es_pid_num].pid = esi.elementary_pid;
+ espids[*es_pid_num].type = esi.stream_type;
+ break;
+ default:
+ espids[*es_pid_num].pid = esi.elementary_pid;
+ espids[*es_pid_num].type = 0;
+
+ }
+ }
+ memcpy(tmp + es_cads->size, ptr, 5);
+ tmp[es_cads->size+1] &= 0x1f; //remove reserved value ???
+ tmp[es_cads->size+3] &= 0x0f; //remove reserved value ???
+
+ int es_info_len_pos = es_cads->size+3; //mark length position to set it later
+ int cur_len = 0; //current ES stream descriptor length
+
+ es_cads->size += 5;
+ ptr += 5;
+ buf_len -= 5;
+ len=esi.es_info_length;
+ while(len > 0) {
+ int dtag = ptr[0];
+ int dlen = ptr[1] + 2; //2 bytes for tag and len
+
+ if (dlen > len || dlen > MAX_DESC_LEN) {
+ info("PMT: Invalide CA desc. length!\n");
+ err = -1;
+ break;
+ }
+
+ if (dtag == 0x09) { //we have CA descriptor
+ memcpy(tmp + es_cads->size, ptr, dlen);
+ es_cads->size += dlen;
+ es_cads->cads++;
+ cur_len += dlen;
+ *fta=0;
+ }
+ if (espids) {
+ if (espids[*es_pid_num].type == 0) {
+ switch(dtag) {
+ case TeletextDescriptorTag:
+ case SubtitlingDescriptorTag:
+ case AC3DescriptorTag:
+ case EnhancedAC3DescriptorTag:
+ case DTSDescriptorTag:
+ case AACDescriptorTag:
+ espids[*es_pid_num].type = dtag;
+ //go to next pid
+ }
+ }
+ }
+
+ ptr += dlen;
+ if (ptr >= buf + size) {
+ info("PMT: Invalid Buffer offset !\n");
+ err = -1;
+ break;
+ }
+
+ len -= dlen;
+ buf_len -= dlen;
+ }
+ if (err == -1) {
+ break;
+ }
+ tmp[es_info_len_pos] = (cur_len >> 8) & 0xff;
+ tmp[es_info_len_pos+1] = cur_len & 0xff;
+ if (espids) {
+ if (espids[*es_pid_num].type) {
+ //go to next pid
+ (*es_pid_num)++;
+ if (*es_pid_num >= MAX_ES_PIDS) {
+ info ("ERROR: ES pids array index out bounds (pids %d sid %d)!\n", *es_pid_num, pmt_hdr->program_number);
+ break;
+ }
+ }
+ }
+ }
+
+ //parsing ok we can take this ES level descriptors
+ if (((es_cads->cads && es_cads->size) || (pm_cads->cads && es_cads->size)) || *fta) { //take ES stream info if we have PM or ES desc.
+ es_cads->cad = (unsigned char*)malloc(sizeof(unsigned char)*es_cads->size);
+ if (!es_cads->cad) {
+ info("ERROR: parse_ca_desc() : out of memory\n");
+ if (pm_cads->cad)
+ free(pm_cads->cad);
+ return -1;
+ }
+ memcpy(es_cads->cad, tmp, es_cads->size);
+
+ }
+
+#ifdef DBG
+ info("%d bytes remaining\n",buf_len);
+#endif
+
+ pmt_hdr->crc32=(ptr[0] << 24) | (ptr[1] << 16) | (ptr[2] << 8) | ptr[3];
+
+ if (len < 0 || err == -1) {
+ info("ERROR: parse_ca_desc() : section index out of bounds %d or (CRC err.) crc in sec. = 0x%x crc calc. = 0x%lx\n", buf_len,pmt_hdr->crc32, crc);
+#ifdef DBG
+ print_pmt(&pmt_hdr);
+#endif
+ //cleanup ...
+ if (pm_cads->cad)
+ free(pm_cads->cad);
+ if (es_cads->cad)
+ free(es_cads->cad);
+ *es_pid_num = 0;
+ memset(pm_cads,0,sizeof(si_ca_pmt_t));
+ memset(es_cads,0,sizeof(si_ca_pmt_t));
+ return -1;
+ }
+
+#ifdef DBG
+ info("#####################################\n");
+ info("parse_ca_desc(): section parsed: OK !\n");
+#endif
+ return 0;
+}
+//-----------------------------------------------------------------------------------
+int parse_cat_sect(unsigned char *buf, int size, si_cad_t *emm)
+{
+ unsigned char *ptr=buf;
+ int len,i,ret;
+ cat_t c;
+
+ c.table_id = ptr[0];
+ c.section_syntax_indicator = (ptr[1] >> 7) & 1;
+ c.reserved_1 = (ptr[1] >> 4) & 3;
+ c.section_length = ((ptr[1] << 8) | ptr[2]) & 0xfff;
+
+ if (c.section_length < 9 || c.section_length > 1021 || (int)c.section_length > size) {
+ info("CAT: Invalid section length!\n");
+ return -1;
+ }
+
+#ifdef CRC32_CHECK
+ u_long crc = dvb_crc32 ((char *)buf,c.section_length+3);
+#ifdef DBG
+ info("CRCcc: 0x%lx\n",crc);
+#endif
+ if (crc & 0xffffffff) {
+ info("CAT:CRC32 error (0x%lx)!\n",crc);
+ return -1;
+ }
+#endif
+
+ c.reserved_2 = (ptr[3] << 10) | (ptr[4] << 2) | ((ptr[5] >> 6) & 3);
+ c.version_number = (ptr[5] >> 1) & 0x1f;
+ c.current_next_indicator = ptr[5] & 1;
+ c.section_number = ptr[6];
+ c.last_section_number = ptr[7];
+
+
+ //do desc. here
+ len = c.section_length - 5;
+ ptr+=8; //go after hdr.
+
+ i = len;
+ while(i > 4) { //crc32 4 bytes
+ ret = descriptor(ptr, emm);
+ if (ret < 0) {
+ info ("cannot parse CA descriptor in CAT !\n");
+ return -1;
+ }
+ i-=ret;
+ ptr+=ret;
+ if (ptr >= buf + size) {
+ info("CAT: Invalid Buffer offset !\n");
+ break;
+ }
+ }
+ if (i != 4) {
+ info("CAT: index out of bounds !\n");
+ return -1;
+ }
+#ifdef DBG
+ info("%d bytes remaining (program info len = %d bytes)\n",len-i,len);
+#endif
+ c.crc32 = (ptr[0] << 24) | (ptr[1] << 16) | (ptr[2] << 8) | ptr[3];
+
+
+ return 0;
+}
+//-----------------------------------------------------------------------------------
+int parse_pat_sect(unsigned char *buf, int size, pmt_pid_list_t *pmt)
+{
+ unsigned char *ptr=buf;
+ pat_t p;
+ pat_list_t *pat_info = NULL;
+
+ memset(&p,0,sizeof(p));
+
+ p.table_id=ptr[0];
+ p.section_syntax_indicator=(ptr[1] & 0x80) >> 7;
+ p.reserved_1=(ptr[1] & 0x30) >> 4;
+ p.section_length=((ptr[1] << 8) | ptr[2]) & 0x0fff;
+
+ if (p.section_length < 9 || p.section_length > 1021 || (int)p.section_length > size) {
+ info("PAT: Invalid section length !\n");
+ return -1;
+
+ }
+
+#ifdef CRC32_CHECK
+ u_long crc = dvb_crc32 ((char *)buf,p.section_length+3);
+ //FIXME: is it the right way ?
+ if (crc & 0xffffffff) {
+ info("PAT:CRC32 error (0x%lx)!\n",crc);
+ return -1;
+ }
+#endif
+
+ p.transport_stream_id=(ptr[3] << 8) | ptr[4];
+ p.reserved_2=(ptr[5] & 0xc0) >> 6;
+ p.version_number=(ptr[5] & 0x3e) >> 1;
+ p.current_next_indicator=(ptr[5] & 1);
+ p.section_number=ptr[6];
+ p.last_section_number=ptr[7];
+
+ int n,i,pmt_num;
+
+ n = p.section_length - 5 - 4; //bytes following section_length field + crc32 chk_sum
+
+ ptr+=8;
+ pmt_num=0;
+ if (n > 0 && ((ptr + n) < (buf + size))) {
+ pat_info=(pat_list_t *)malloc(sizeof(pat_list_t)*n/4);
+ if (!pat_info) {
+ info ("PAT: out of memory\n");
+ return -1;
+ }
+ for(i=0;i<n;i+=4) {
+ pat_list_t *pat = pat_info + pmt_num;
+ pat->program_number=(ptr[0] << 8) | (ptr[1]);
+ pat->reserved=(ptr[2] & 0xe0) >> 5;
+ pat->network_pmt_pid=((ptr[2] << 8) | ptr[3]) & 0x1fff;
+ if (pat->network_pmt_pid != 0x10) { //NIT => FIXME: remove other known pids
+ // memset(&pat->desc,0,sizeof(pmt_desc_list_t));
+ pmt_num++;
+ }
+ ptr+=4;
+ }
+
+ p.crc32=(ptr[0] << 24) | (ptr[1] << 16) | (ptr[2] << 8) | ptr[3];
+ if (n != pmt_num)
+ pat_info=(pat_list_t *)realloc(pat_info,sizeof(pat_list_t)*pmt_num);
+ if (!pat_info) {
+ info("parse_pat_sect():realloc error\n");
+ return -1;
+ }
+ }
+ if (pmt) {
+ pmt->p=p;
+ pmt->pl=pat_info;
+ pmt->pmt_pids=pmt_num;
+ }
+
+ return 0;
+}
+int parse_tdt_sect(unsigned char *buf, int size, tdt_sect_t *tdt)
+{
+ unsigned char *ptr = buf;
+
+ tdt->table_id=ptr[0];
+ tdt->section_syntax_indicator=(ptr[1] & 0x80) >> 7;
+ tdt->reserved_1=(ptr[1] >> 4) >> 3;
+ tdt->section_length=((ptr[1] << 8) | ptr[2]) & 0x0fff;
+
+ if (tdt->section_length != 5) {
+ info("TDT: Invalid section length !\n");
+ return -1;
+ }
+
+ //copy UTC time MJD + UTC
+ memcpy(tdt->dvbdate, ptr + 3, 5);
+
+ return 0;
+
+}
+//-----------------------------------------------------------------------------------
+//TS packets handling
+int get_ts_packet_hdr(unsigned char *buf, ts_packet_hdr_t *p)
+{
+ unsigned char *ptr=buf;
+
+ memset(p,0,sizeof(p));
+
+ p->sync_byte=ptr[0];
+ p->transport_error_indicator=(ptr[1] & 0x80) >> 7;
+ p->payload_unit_start_indicator=(ptr[1] & 0x40) >> 6;
+ p->transport_priority=(ptr[1] & 0x20) >> 5;
+ p->pid=((ptr[1] << 8) | ptr[2]) & 0x1fff;
+ p->transport_scrambling_control=(ptr[3] & 0xC0) >> 6;
+ p->adaptation_field_control=(ptr[3] & 0x30) >> 4;
+ p->continuity_counter=(ptr[3] & 0xf);
+
+#ifdef DBG
+ print_ts_header(p);
+#endif
+
+ return 0;
+
+}
+//-----------------------------------------------------------------------------------
+int ts2psi_data(unsigned char *buf,psi_buf_t *p,int len, int pid_req)
+{
+ unsigned char *b=buf;
+ ts_packet_hdr_t h;
+
+
+ get_ts_packet_hdr(buf,&h);
+
+ b+=4;
+ len-=4;
+
+ if (h.sync_byte != 0x47) {
+#ifdef SERVER
+ sys("%s:No sync byte in header !\n",__FUNCTION__);
+#endif
+ return -1;
+ }
+
+
+ if (pid_req != (int)h.pid) {
+#ifdef DBG
+ info("%s:pids mismatch (pid req = %#x ts pid = %#x )!\n", __FUNCTION__,pid_req, h.pid);
+#endif
+ return -1;
+ }
+
+ //FIXME:Handle adaptation field if present/needed
+ if (h.adaptation_field_control & 0x2) {
+ int n;
+
+ n=b[0]+1;
+ b+=n;
+ len-=n;
+
+ }
+
+ if (h.adaptation_field_control & 0x1) {
+ if (h.transport_error_indicator) {
+#ifdef DBG
+ info("Transport error flag set !\n");
+#endif
+ return -1;
+ }
+ if (h.transport_scrambling_control) {
+#ifdef DBG
+ info("Transport scrambling flag set !\n");
+#endif
+ //return -1;
+ }
+
+ if (h.payload_unit_start_indicator && p->start) { //whole section new begin packet
+#ifdef DBG
+ info("%s:section read !\n",__FUNCTION__);
+#endif
+ return 1;
+ }
+
+ if (h.payload_unit_start_indicator && !p->start) { //packet beginning
+ int si_offset=b[0]+1; //always pointer field in first byte of TS packet payload with start indicator set
+ b+=si_offset;
+ len-=si_offset;
+ if (len < 0 || len > 184) {
+#ifdef DBG
+ info("WARNING 1: TS Packet damaged !\n");
+#endif
+ return -1;
+ }
+ //move to buffer
+ memcpy(p->buf,b,len);
+ p->len=len;
+ p->start=((b[1] << 8) | b[2]) & 0x0fff; //get section length, using start for length
+ p->pid=h.pid;
+ p->continuity=h.continuity_counter;
+
+ }
+
+ if (!h.payload_unit_start_indicator && p->start) { //packet continuation
+ //duplicate packet
+ if ((p->pid == (int)h.pid) && (p->continuity == (int)h.continuity_counter)){
+#ifdef DBG
+ info("Packet duplicate ???\n");
+#endif
+ return -1;
+ }
+ //new packet
+ if (p->pid != (int)h.pid) {
+#ifdef DBG
+ info("New pid buf start %d len %d bytes (pid in buf = %d pid in ts = %d) !\n", p->start,p->len, p->pid, h.pid);
+#endif
+ return -1;
+ }
+ //discontinuity of packets
+ if (((++p->continuity)%16) != (int)h.continuity_counter) {
+#ifdef DBG
+ info("Discontinuity of ts stream !!!\n");
+#endif
+ return -1;
+ }
+ p->continuity=h.continuity_counter;
+ if (len < 0 || len > 184) {
+ info("WARNING 2: TS Packet damaged !\n");
+ return -1;
+ }
+ //move to buffer
+ memcpy(p->buf+p->len,b,len);
+ p->len+=len; //FIXME: circular buffer
+ if (p->len + 188 > PSI_BUF_SIZE) {
+ info("Error: Buffer full !\n");
+ return -1;
+ //FIXME:realloc
+ }
+ }
+ }
+
+#if 1
+ //3 bytes for bytes containing table id and section length
+ TS_SECT_LEN(b);
+ if (slen+3 <= len && h.payload_unit_start_indicator) //len = 188 bytes - 4 bytes ts hdr. - adapt. field bytes - 1 byte offset - offset
+ return 1;
+#else //possible opt.
+ /*if (p->start+3 == len)
+ return 1;*/
+#endif
+
+ return 0;
+}
+//TS packets handling end
+//-----------------------------------------------------------------------------------
+
+
+
diff --git a/mcast/common/siparser.h b/mcast/common/siparser.h
new file mode 100644
index 0000000..255ebe0
--- /dev/null
+++ b/mcast/common/siparser.h
@@ -0,0 +1,369 @@
+#ifndef __SIPARSER_H__
+#define __SIPARSER_H__
+
+#define TS_SECT_LEN(buf) \
+ unsigned char *ptr = buf; \
+ int slen = (((ptr[1] << 8) | ptr[2]) & 0x0fff);
+
+
+#define TS_PACKET_LEN (188) /* TS RDSIZE is fixed !! */
+#define TS_SYNC_BYTE (0x47) /* SyncByte for TS ISO 138181-1 */
+#define TS_BUF_SIZE (256 * 1024) /* default DMX_Buffer Size for TS */
+#define PSI_BUF_SIZE (2 * 4096) /* Section length max. 12 bits */
+#define READ_BUF_SIZE (256*TS_PACKET_LEN) /* min. 2x TS_PACKET_LEN!!! */
+#define BILLION 1000000000L;
+#define MAX_DESC_LEN 255 //descriptor_length field 8-bit ISO/IEC 13818-1
+#define MAX_ES_PIDS 32
+
+
+#define VIDEO_11172_STREAM_TYPE 0x1 // STREAMTYPE_11172_VIDEO
+#define VIDEO_13818_STREAM_TYPE 0x2 // STREAMTYPE_13818_VIDEO
+#define VISUAL_MPEG4_STREAM_TYPE 0x10 // 14496-2 Visual MPEG-4
+#define VIDEO_H264_STREAM_TYPE 0x1b // 14496-10 Video h.264
+#define AUDIO_11172_STREAM_TYPE 0x3 // STREAMTYPE_11172_AUDIO
+#define AUDIO_13818_STREAM_TYPE 0x4 // STREAMTYPE_13818_AUDIO
+#define PRIVATE_13818_STREAM_TYPE 0x5 // STREAMTYPE_13818_PRIVATE
+#define PRIVATE_13818_PES_STREAM_TYPE 0x6 // STREAMTYPE_13818_PES_PRIVATE
+
+enum DescriptorTag {
+ // defined by ISO/IEC 13818-1
+ VideoStreamDescriptorTag = 0x02,
+ AudioStreamDescriptorTag = 0x03,
+ HierarchyDescriptorTag = 0x04,
+ RegistrationDescriptorTag = 0x05,
+ DataStreamAlignmentDescriptorTag = 0x06,
+ TargetBackgroundGridDescriptorTag = 0x07,
+ VideoWindowDescriptorTag = 0x08,
+ CaDescriptorTag = 0x09,
+ ISO639LanguageDescriptorTag = 0x0A,
+ SystemClockDescriptorTag = 0x0B,
+ MultiplexBufferUtilizationDescriptorTag = 0x0C,
+ CopyrightDescriptorTag = 0x0D,
+ MaximumBitrateDescriptorTag = 0x0E,
+ PrivateDataIndicatorDescriptorTag = 0x0F,
+ SmoothingBufferDescriptorTag = 0x10,
+ STDDescriptorTag = 0x11,
+ IBPDescriptorTag = 0x12,
+ // defined by ISO-13818-6 (DSM-CC)
+ CarouselIdentifierDescriptorTag = 0x13,
+ // 0x14 - 0x3F Reserved
+ // defined by ETSI (EN 300 468)
+ NetworkNameDescriptorTag = 0x40,
+ ServiceListDescriptorTag = 0x41,
+ StuffingDescriptorTag = 0x42,
+ SatelliteDeliverySystemDescriptorTag = 0x43,
+ CableDeliverySystemDescriptorTag = 0x44,
+ VBIDataDescriptorTag = 0x45,
+ VBITeletextDescriptorTag = 0x46,
+ BouquetNameDescriptorTag = 0x47,
+ ServiceDescriptorTag = 0x48,
+ CountryAvailabilityDescriptorTag = 0x49,
+ LinkageDescriptorTag = 0x4A,
+ NVODReferenceDescriptorTag = 0x4B,
+ TimeShiftedServiceDescriptorTag = 0x4C,
+ ShortEventDescriptorTag = 0x4D,
+ ExtendedEventDescriptorTag = 0x4E,
+ TimeShiftedEventDescriptorTag = 0x4F,
+ ComponentDescriptorTag = 0x50,
+ MocaicDescriptorTag = 0x51,
+ StreamIdentifierDescriptorTag = 0x52,
+ CaIdentifierDescriptorTag = 0x53,
+ ContentDescriptorTag = 0x54,
+ ParentalRatingDescriptorTag = 0x55,
+ TeletextDescriptorTag = 0x56,
+ TelephoneDescriptorTag = 0x57,
+ LocalTimeOffsetDescriptorTag = 0x58,
+ SubtitlingDescriptorTag = 0x59,
+ TerrestrialDeliverySystemDescriptorTag = 0x5A,
+ MultilingualNetworkNameDescriptorTag = 0x5B,
+ MultilingualBouquetNameDescriptorTag = 0x5C,
+ MultilingualServiceNameDescriptorTag = 0x5D,
+ MultilingualComponentDescriptorTag = 0x5E,
+ PrivateDataSpecifierDescriptorTag = 0x5F,
+ ServiceMoveDescriptorTag = 0x60,
+ ShortSmoothingBufferDescriptorTag = 0x61,
+ FrequencyListDescriptorTag = 0x62,
+ PartialTransportStreamDescriptorTag = 0x63,
+ DataBroadcastDescriptorTag = 0x64,
+ ScramblingDescriptorTag = 0x65,
+ DataBroadcastIdDescriptorTag = 0x66,
+ TransportStreamDescriptorTag = 0x67,
+ DSNGDescriptorTag = 0x68,
+ PDCDescriptorTag = 0x69,
+ AC3DescriptorTag = 0x6A,
+ AncillaryDataDescriptorTag = 0x6B,
+ CellListDescriptorTag = 0x6C,
+ CellFrequencyLinkDescriptorTag = 0x6D,
+ AnnouncementSupportDescriptorTag = 0x6E,
+ ApplicationSignallingDescriptorTag = 0x6F,
+ AdaptationFieldDataDescriptorTag = 0x70,
+ ServiceIdentifierDescriptorTag = 0x71,
+ ServiceAvailabilityDescriptorTag = 0x72,
+ // defined by ETSI (EN 300 468) v 1.7.1
+ DefaultAuthorityDescriptorTag = 0x73,
+ RelatedContentDescriptorTag = 0x74,
+ TVAIdDescriptorTag = 0x75,
+ ContentIdentifierDescriptorTag = 0x76,
+ TimeSliceFecIdentifierDescriptorTag = 0x77,
+ ECMRepetitionRateDescriptorTag = 0x78,
+ S2SatelliteDeliverySystemDescriptorTag = 0x79,
+ EnhancedAC3DescriptorTag = 0x7A,
+ DTSDescriptorTag = 0x7B,
+ AACDescriptorTag = 0x7C,
+ ExtensionDescriptorTag = 0x7F,
+
+ // Defined by ETSI TS 102 812 (MHP)
+ // They once again start with 0x00 (see page 234, MHP specification)
+ MHP_ApplicationDescriptorTag = 0x00,
+ MHP_ApplicationNameDescriptorTag = 0x01,
+ MHP_TransportProtocolDescriptorTag = 0x02,
+ MHP_DVBJApplicationDescriptorTag = 0x03,
+ MHP_DVBJApplicationLocationDescriptorTag = 0x04,
+ // 0x05 - 0x0A is unimplemented this library
+ MHP_ExternalApplicationAuthorisationDescriptorTag = 0x05,
+ MHP_IPv4RoutingDescriptorTag = 0x06,
+ MHP_IPv6RoutingDescriptorTag = 0x07,
+ MHP_DVBHTMLApplicationDescriptorTag = 0x08,
+ MHP_DVBHTMLApplicationLocationDescriptorTag = 0x09,
+ MHP_DVBHTMLApplicationBoundaryDescriptorTag = 0x0A,
+ MHP_ApplicationIconsDescriptorTag = 0x0B,
+ MHP_PrefetchDescriptorTag = 0x0C,
+ MHP_DelegatedApplicationDescriptorTag = 0x0E,
+ MHP_ApplicationStorageDescriptorTag = 0x10,
+ // Premiere private Descriptor Tags
+ PremiereContentTransmissionDescriptorTag = 0xF2,
+
+ //a descriptor currently unimplemented in this library
+ //the actual value 0xFF is "forbidden" according to the spec.
+ UnimplementedDescriptorTag = 0xFF
+};
+
+
+
+typedef struct ts_packet_hdr
+{
+ unsigned int sync_byte;
+ unsigned int transport_error_indicator;
+ unsigned int payload_unit_start_indicator;
+ unsigned int transport_priority;
+ unsigned int pid;
+ unsigned int transport_scrambling_control;
+ unsigned int adaptation_field_control;
+ unsigned int continuity_counter;
+} ts_packet_hdr_t;
+
+typedef struct pat {
+ unsigned int table_id;
+ unsigned int section_syntax_indicator;
+ unsigned int reserved_1;
+ unsigned int section_length;
+ unsigned int transport_stream_id;
+ unsigned int reserved_2;
+ unsigned int version_number;
+ unsigned int current_next_indicator;
+ unsigned int section_number;
+ unsigned int last_section_number;
+
+ // FIXME: list of programs
+
+ unsigned int crc32;
+} pat_t;
+
+typedef struct _pat_list {
+ unsigned int program_number; //SID
+ unsigned int reserved;
+ unsigned int network_pmt_pid;
+
+ int cads_present;
+ int cads_num;
+
+} pat_list_t;
+
+typedef struct pmt_pid_list {
+
+ pat_t p;
+ pat_list_t *pl;
+ unsigned int pmt_pids;
+
+} pmt_pid_list_t;
+
+typedef struct psi_buf {
+
+ unsigned char *buf;
+ unsigned int len;//used for offset
+ unsigned int start;
+
+ int pid;
+ int continuity;
+
+} psi_buf_t;
+
+typedef struct pmt {
+ unsigned int table_id;
+ unsigned int section_syntax_indicator;
+ unsigned int reserved_1;
+ unsigned int section_length;
+ unsigned int program_number;
+ unsigned int reserved_2;
+ unsigned int version_number;
+ unsigned int current_next_indicator;
+ unsigned int section_number;
+ unsigned int last_section_number;
+ unsigned int reserved_3;
+ unsigned int pcr_pid;
+ unsigned int reserved_4;
+ unsigned int program_info_length;
+
+ // N descriptors
+
+ // N1 stream types and descriptors
+
+ unsigned int crc32;
+} pmt_t;
+
+typedef struct es_pmt_info {
+ unsigned int stream_type;
+ unsigned int reserved_1;
+ unsigned int elementary_pid;
+ unsigned int reserved_2;
+ unsigned int es_info_length;
+
+ // N2 descriptor
+
+} es_pmt_info_t;
+
+typedef struct ca_descriptor {
+
+ unsigned int descriptor_tag;
+ unsigned int descriptor_length;
+ unsigned int ca_system_id;
+ unsigned int reserved;
+ unsigned int ca_pid;
+ unsigned char private_data[MAX_DESC_LEN];
+
+} si_desc_t;
+
+typedef struct pmt_descriptor {
+
+ pmt_t pmt_hdr;
+
+ int cas;
+ si_desc_t *cad;
+
+} si_pmt_desc_t;
+
+typedef struct ca_descriptor_list {
+
+ int cads;
+ si_desc_t *cad;
+
+} si_cad_t;
+
+typedef struct ca_sid_info {
+
+ int sid;
+ int version;
+ int offset;
+ int len;
+
+} ca_sid_t;
+
+typedef struct ca_pmt_descriptors {
+
+ int cads;
+ int size;
+ unsigned char *cad;
+
+} si_ca_pmt_t;
+
+typedef struct ca_es_pid_info {
+
+ int pid;
+ uint8_t type;
+
+} ca_es_pid_info_t;
+
+typedef struct ca_pmt_list {
+
+ int sid;
+ int pmt_pid;
+
+ pmt_t p;
+ si_ca_pmt_t pm;
+ si_ca_pmt_t es;
+
+ ca_es_pid_info_t espids[MAX_ES_PIDS];
+ int es_pid_num;
+
+} ca_pmt_list_t;
+
+
+typedef struct ca_sid_list {
+
+ int tc; //total number of CA desc.
+ int num;
+ ca_pmt_list_t *l;
+
+} ca_sid_list_t;
+
+typedef struct _cat {
+ unsigned int table_id;
+ unsigned int section_syntax_indicator;
+ unsigned int reserved_1;
+ unsigned int section_length;
+ unsigned int reserved_2;
+ unsigned int version_number;
+ unsigned int current_next_indicator;
+ unsigned int section_number;
+ unsigned int last_section_number;
+
+ // private section
+
+ unsigned int crc32;
+} cat_t;
+
+typedef struct tdt_sect {
+
+ uint8_t table_id;
+ uint8_t section_syntax_indicator;
+ uint8_t reserved; //0 future use
+ uint8_t reserved_1;
+ uint16_t section_length;
+ uint8_t dvbdate[5];
+} tdt_sect_t;
+
+typedef struct _str_table {
+ unsigned int from;
+ unsigned int to;
+ const char *str;
+} str_table;
+
+
+int parse_ca_descriptor(unsigned char *desc, si_desc_t *t);
+
+int ts2psi_data(unsigned char *buf,psi_buf_t *p,int len, int pid_req);
+int parse_pat_sect(unsigned char *buf, int size, pmt_pid_list_t *pmt);
+int parse_pmt_ca_desc(unsigned char *buf, int size, int sid, si_ca_pmt_t *pm_cads, si_ca_pmt_t *es_cads, pmt_t *pmt_hdr, int *fta, ca_es_pid_info_t *espid, int *es_pid_num);
+int parse_cat_sect(unsigned char *buf, int size, si_cad_t *emm);
+int parse_tdt_sect(unsigned char *buf, int size, tdt_sect_t *tdt);
+int get_ts_packet_hdr(unsigned char *buf, ts_packet_hdr_t *p);
+int si_get_video_pid(unsigned char *esi_buf, int size, int *vpid);
+int si_get_audio_pid(unsigned char *esi_buf, int size, int *apid);
+int si_get_private_pids(unsigned char *esi_buf, int size, int *upids);
+int get_pmt_es_pids(unsigned char *esi_buf, int size, int *es_pids, int all);
+void print_pat(pat_t *p, pat_list_t *pl, int pmt_num);
+void printhex_buf(char *msg,unsigned char *buf,int len);
+void writehex_buf(FILE *f,char *msg,unsigned char *buf,int len);
+void print_cad_lst(si_cad_t *l, int ts_id);
+void print_ca_bytes(si_desc_t *p);
+void get_time_mjd (unsigned long mjd, long *year , long *month, long *day);
+void print_tdt(tdt_sect_t *tdt, uint16_t mjd, uint32_t utc);
+int ca_free_cpl_desc(ca_pmt_list_t *cpl);
+char *si_caid_to_name(unsigned int caid);
+
+#endif
+
+
+
+
+
diff --git a/mcast/common/tools.c b/mcast/common/tools.c
new file mode 100644
index 0000000..9e05a10
--- /dev/null
+++ b/mcast/common/tools.c
@@ -0,0 +1,777 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ */
+
+#define DEBUG 1
+#include "headers.h"
+
+#ifdef DEBUG
+const Param inversion_list[] = {
+ {"INVERSION_OFF", INVERSION_OFF},
+ {"INVERSION_ON", INVERSION_ON},
+ {"INVERSION_AUTO", INVERSION_AUTO}
+};
+
+const Param bw_list[] = {
+ {"BANDWIDTH_6_MHZ", BANDWIDTH_6_MHZ},
+ {"BANDWIDTH_7_MHZ", BANDWIDTH_7_MHZ},
+ {"BANDWIDTH_8_MHZ", BANDWIDTH_8_MHZ}
+};
+
+const Param fec_list[] = {
+ {"FEC_1_2", FEC_1_2},
+ {"FEC_2_3", FEC_2_3},
+ {"FEC_3_4", FEC_3_4},
+ {"FEC_4_5", FEC_4_5},
+ {"FEC_5_6", FEC_5_6},
+ {"FEC_6_7", FEC_6_7},
+ {"FEC_7_8", FEC_7_8},
+ {"FEC_8_9", FEC_8_9},
+ {"FEC_AUTO", FEC_AUTO},
+ {"FEC_NONE", FEC_NONE},
+ {"FEC_1_4", FEC_1_4}, // RMM S2 Extension
+ {"FEC_1_3", FEC_1_3},
+ {"FEC_2_5", FEC_2_5},
+ {"FEC_9_10", FEC_9_10}
+};
+
+const Param guard_list[] = {
+ {"GUARD_INTERVAL_1_16", GUARD_INTERVAL_1_16},
+ {"GUARD_INTERVAL_1_32", GUARD_INTERVAL_1_32},
+ {"GUARD_INTERVAL_1_4", GUARD_INTERVAL_1_4},
+ {"GUARD_INTERVAL_1_8", GUARD_INTERVAL_1_8}
+};
+
+const Param hierarchy_list[] = {
+ {"HIERARCHY_1", HIERARCHY_1},
+ {"HIERARCHY_2", HIERARCHY_2},
+ {"HIERARCHY_4", HIERARCHY_4},
+ {"HIERARCHY_NONE", HIERARCHY_NONE}
+};
+
+const Param constellation_list[] = {
+ {"QPSK", QPSK},
+ {"QAM_128", QAM_128},
+ {"QAM_16", QAM_16},
+ {"QAM_256", QAM_256},
+ {"QAM_32", QAM_32},
+ {"QAM_64", QAM_64},
+ {"QPSK_S2", QPSK_S2}, // RMM S2 Extension
+ {"PSK8", PSK8}
+};
+
+const Param transmissionmode_list[] = {
+ {"TRANSMISSION_MODE_2K", TRANSMISSION_MODE_2K},
+ {"TRANSMISSION_MODE_8K", TRANSMISSION_MODE_8K},
+};
+
+const Param capabilities_list[] = {
+ {"Stupid: ", FE_IS_STUPID},
+ {"FE_CAN_INVERSION_AUTO: ", FE_CAN_INVERSION_AUTO},
+ {"CAN_FEC_1_2: ", FE_CAN_FEC_1_2},
+ {"CAN_FEC_2_3: ", FE_CAN_FEC_2_3},
+ {"CAN_FEC_3_4: ", FE_CAN_FEC_3_4},
+ {"CAN_FEC_4_5: ", FE_CAN_FEC_4_5},
+ {"CAN_FEC_6_7: ", FE_CAN_FEC_6_7},
+ {"CAN_FEC_7_8: ", FE_CAN_FEC_7_8},
+ {"CAN_FEC_8_9: ", FE_CAN_FEC_8_9},
+ {"CAN_FEC_AUTO: ", FE_CAN_FEC_AUTO},
+ {"FE_CAN_QPSK: ", FE_CAN_QPSK},
+ {"FE_CAN_QAM_16: ", FE_CAN_QAM_16},
+ {"FE_CAN_QAM_32: ", FE_CAN_QAM_32},
+ {"FE_CAN_QAM_64: ", FE_CAN_QAM_64},
+ {"FE_CAN_QAM_128: ", FE_CAN_QAM_128},
+ {"FE_CAN_QAM_256: ", FE_CAN_QAM_256},
+ {"FE_CAN_QAM_AUTO: ", FE_CAN_QAM_AUTO},
+ {"FE_CAN_TRANSMISSION_MODE_AUTO: ", FE_CAN_TRANSMISSION_MODE_AUTO},
+ {"FE_CAN_BANDWIDTH_AUTO: ", FE_CAN_BANDWIDTH_AUTO},
+ {"FE_CAN_GUARD_INTERVAL_AUTO: ", FE_CAN_GUARD_INTERVAL_AUTO},
+ {"FE_CAN_HIERARCHY_AUTO: ", FE_CAN_HIERARCHY_AUTO},
+ {"FE_CAN_MUTE_TS: ", FE_CAN_MUTE_TS}
+// {"FE_CAN_CLEAN_SETUP: ",FE_CAN_CLEAN_SETUP}
+};
+
+#define LIST_SIZE(x) sizeof(x)/sizeof(Param)
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+void print_fe_info (struct dvb_frontend_info *fe_info)
+{
+ fprintf (stdout, "-------------------------------------------\n");
+ fprintf (stdout, "Tuner name: %s\n", fe_info->name);
+ fprintf (stdout, "Tuner type: %u\n", (unsigned int) fe_info->type);
+ fprintf (stdout, "Frequency min.: %u\n", fe_info->frequency_min);
+ fprintf (stdout, "Frequency max.: %u\n", fe_info->frequency_max);
+ fprintf (stdout, "Frequency stepsize: %u\n", fe_info->frequency_stepsize);
+ fprintf (stdout, "Frequency tolerance: %u\n", fe_info->frequency_tolerance);
+ fprintf (stdout, "Symbol rate min: %u\n", fe_info->symbol_rate_min);
+ fprintf (stdout, "Symbol rate max: %u\n", fe_info->symbol_rate_max);
+ fprintf (stdout, "Symbol rate tolerance: %u\n", fe_info->symbol_rate_tolerance);
+ fprintf (stdout, "Notifier delay: %u\n", fe_info->notifier_delay);
+ fprintf (stdout, "Cpas: 0x%x\n", (unsigned int) fe_info->caps);
+
+ fprintf (stdout, "-------------------------------------------\n");
+ fprintf (stdout, "Frontend Capabilities:\n");
+ int i;
+
+ for (i = 0; i < LIST_SIZE (capabilities_list); i++) {
+ if (fe_info->caps & capabilities_list[i].value)
+ fprintf (stdout, "%syes\n", capabilities_list[i].name);
+ else
+ fprintf (stdout, "%sno\n", capabilities_list[i].name);
+ }
+ fprintf (stdout, "-------------------------------------------\n");
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+void print_frontend_settings (struct dvb_frontend_parameters *frontend_param)
+{
+ int i;
+ fprintf (stdout, "\n----- Front End Settings ----- ");
+ fprintf (stdout, "\nFrequency : %u \n", frontend_param->frequency);
+ for (i = 0; i < LIST_SIZE (inversion_list); i++) {
+ if (inversion_list[i].value == frontend_param->inversion)
+ fprintf (stdout, "Inversion : %s\n", inversion_list[i].name);
+
+ }
+ //
+ for (i = 0; i < LIST_SIZE (bw_list); i++) {
+ if (frontend_param->u.ofdm.bandwidth == bw_list[i].value)
+ fprintf (stdout, "Bandwidth : %s\n", bw_list[i].name);
+
+ }
+ for (i = 0; i < LIST_SIZE (fec_list); i++) {
+ if (fec_list[i].value == frontend_param->u.ofdm.code_rate_HP)
+ fprintf (stdout, "Code Rate HP : %s\n", fec_list[i].name);
+
+ }
+ for (i = 0; i < LIST_SIZE (fec_list); i++) {
+ if (fec_list[i].value == frontend_param->u.ofdm.code_rate_LP)
+ fprintf (stdout, "Code Rate LP : %s\n", fec_list[i].name);
+
+ }
+
+ for (i = 0; i < LIST_SIZE (constellation_list); i++) {
+ if (constellation_list[i].value == frontend_param->u.ofdm.constellation)
+ fprintf (stdout, "Modulation : %s\n", constellation_list[i].name);
+
+ }
+
+ for (i = 0; i < LIST_SIZE (transmissionmode_list); i++) {
+ if (transmissionmode_list[i].value == frontend_param->u.ofdm.transmission_mode)
+ fprintf (stdout, "Transmission mode : %s\n", transmissionmode_list[i].name);
+
+ }
+
+ for (i = 0; i < LIST_SIZE (guard_list); i++) {
+ if (guard_list[i].value == frontend_param->u.ofdm.guard_interval)
+ fprintf (stdout, "Guard interval : %s\n", guard_list[i].name);
+
+ }
+
+ for (i = 0; i < LIST_SIZE (hierarchy_list); i++) {
+ if (hierarchy_list[i].value == frontend_param->u.ofdm.hierarchy_information)
+ fprintf (stdout, "Hierarchy Information : %s\n", hierarchy_list[i].name);
+
+ }
+
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+void print_mcg (struct in6_addr *mcg)
+{
+ char host[80];
+ unsigned int freq;
+ struct in6_addr mc;
+ int i;
+
+ for (i = 0; i < 8; i++) {
+ mc.s6_addr16[i] = ntohs (mcg->s6_addr16[i]);
+ }
+
+ freq = mc.s6_addr16[6] | (mc.s6_addr16[7] & NOPID_MASK) << 3;
+
+ inet_ntop (AF_INET6, mcg->s6_addr, (char *) host, INET6_ADDRSTRLEN);
+ fprintf (stdout, "MCG: %s\n", host);
+
+ fprintf (stdout, "\n");
+ fprintf (stdout, "TS-Streaming group\n");
+ fprintf (stdout, "-----------------------------\n");
+ fprintf (stdout, "Streaming Group - 0x%x \n", (mc.s6_addr16[1] >> 12) & 0xf);
+ fprintf (stdout, "Priority - 0x%x \n", (mc.s6_addr16[1] >> 8) & 0xf);
+ fprintf (stdout, "Reception System - 0x%x \n", mc.s6_addr16[1] & 0xff);
+ fprintf (stdout, "CAM Handling - 0x%x \n", mc.s6_addr16[2]);
+ fprintf (stdout, "Polarisation - 0x%x \n", (mc.s6_addr16[3] >> 12) & 0xf);
+ fprintf (stdout, "SATPosition - 0x%x \n", mc.s6_addr16[3] & 0xfff);
+ fprintf (stdout, "Symbol Rate - 0x%x \n", mc.s6_addr16[4]);
+ fprintf (stdout, "Modulation - 0x%x \n", mc.s6_addr16[5]);
+ fprintf (stdout, "Frequency (0x%x) - %d / %d\n\n", freq, freq * (16667 / 8), freq * (250 / 8));
+
+ fprintf (stdout, "PID - 0x%x \n", mc.s6_addr16[7] & PID_MASK);
+}
+#endif
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+/* Frequency 19Bit
+ DVB-T/DVB-C 524288 Steps * (25/12)kHz = 0...1092MHz in 2.083333kHz steps
+ DVB-S 524288 Steps * (1/20) MHz = 0...26.2GHz in 50kHz steps
+*/
+void fe_parms_to_mcg (struct in6_addr *mcg, streaming_group_t StreamingGroup, fe_type_t type, recv_sec_t * sec, struct dvb_frontend_parameters *fep, int vpid)
+{
+ int i;
+ unsigned int Priority = 0;
+ unsigned int ReceptionSystem = 0;
+ unsigned int CAMHandling = 0;
+ unsigned int Polarisation = 0;
+ unsigned int SATPosition = NO_SAT_POS;
+ unsigned int Symbolrate = 0;
+ unsigned int Modulation = 0;
+ unsigned int TransmissionMode = 0;
+ unsigned int Frequency;
+ double fmul;
+
+ // Default for DVB-T and DVB-C
+ fmul = 12.0 * (((double) fep->frequency) + 1041);
+ Frequency = (unsigned int) (fmul / 25000.0);
+
+ switch ((int)type) {
+ case FE_QPSK:
+ case FE_DVBS2:
+ Frequency = (fep->frequency + 24) / 50;
+ //sec->diseqc_cmd currently not used
+ // Fixme: Translation Diseqc->position/LOF-frequency
+ Polarisation = (sec->mini_cmd << 3) | (sec->tone_mode << 2) | sec->voltage;
+ Symbolrate = fep->u.qpsk.symbol_rate / 1000;
+ Modulation |= (fep->u.qpsk.fec_inner) & 0xf;
+
+ // RMM S2 extension: Put Modulation in 23:16 and rolloff in 31:24
+ if (((fep->u.qpsk.fec_inner >> 16) & 0xff) == PSK8)
+ Modulation |= 2 << 4;
+ if (((fep->u.qpsk.fec_inner >> 16) & 0xff) == QPSK_S2)
+ Modulation |= 1 << 4;
+ Modulation |= fep->inversion << 14;
+ break;
+ case FE_QAM:
+ Symbolrate = fep->u.qam.symbol_rate / 200;
+ Modulation |= fep->u.qam.modulation;
+ Modulation |= fep->inversion << 14;
+ break;
+ case FE_OFDM:
+ TransmissionMode = fep->u.ofdm.transmission_mode;
+ Symbolrate = (TransmissionMode & 0x7) << 8 | (fep->u.ofdm.code_rate_HP << 4) | fep->u.ofdm.code_rate_LP;
+ Modulation |= (fep->u.ofdm.constellation & 0xf) | (fep->u.ofdm.hierarchy_information & 3) << 4 | (fep->u.ofdm.bandwidth & 3) << 7 | (fep->u.ofdm.guard_interval & 7) << 9 | (fep->inversion & 3) << 14;
+ break;
+ case FE_ATSC:
+ Modulation |= fep->u.vsb.modulation;
+ Modulation |= fep->inversion << 14;
+ break;
+ }
+
+ if (type == FE_DVBS2 && !(Modulation & 0x30) ){
+ type=FE_QPSK;
+ }
+
+ ReceptionSystem = type;
+
+ mcg->s6_addr16[0] = MC_PREFIX;
+ mcg->s6_addr16[1] = ((StreamingGroup & 0xf) << 12) | ((Priority & 0xf) << 8) | (ReceptionSystem & 0xff);
+ mcg->s6_addr16[2] = CAMHandling;
+ mcg->s6_addr16[3] = ((Polarisation & 0xf) << 12) | (SATPosition & 0xfff);
+ mcg->s6_addr16[4] = Symbolrate;
+ mcg->s6_addr16[5] = Modulation;
+ mcg->s6_addr16[6] = Frequency;
+ mcg->s6_addr16[7] = (vpid & PID_MASK) | ((Frequency >> 16) << 13);
+
+ for (i = 0; i < 8; i++) {
+ mcg->s6_addr16[i] = htons (mcg->s6_addr16[i]);
+ }
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+int mcg_to_all_parms(struct in6_addr *mcg, struct mcg_data * mcd)
+{
+ int ret;
+ mcd->mcg=*mcg;
+ int n;
+
+ ret=mcg_to_fe_parms(mcg, &mcd->type, &mcd->sec, &mcd->fep, &mcd->vpid);
+
+ if (ret)
+ return ret;
+ mcg_get_satpos(mcg, &mcd->satpos);
+
+ for(n=0;n<MAX_TUNER_CACHE;n++) {
+ mcd->sat_cache[n].resolved=NOT_RESOLVED;
+ mcd->sat_cache[n].num=0;
+ mcd->sat_cache[n].component=0;
+ }
+
+ return 0;
+}
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+int mcg_to_fe_parms (struct in6_addr *mcg, fe_type_t * type, recv_sec_t * sec, struct dvb_frontend_parameters *fep, int *vpid)
+{
+ struct in6_addr mc = *mcg;
+ streaming_group_t StreamingGroup;
+ unsigned int freq;
+ double fmul;
+ fe_type_t fetype;
+
+ int i;
+ for (i = 0; i < 8; i++) {
+ mc.s6_addr16[i] = ntohs (mc.s6_addr16[i]);
+ }
+
+ StreamingGroup = (streaming_group_t)((mc.s6_addr16[1] >> 12) & 0xf);
+
+ if (StreamingGroup != STREAMING_PID) {
+ return -1;
+ }
+
+ if (fep) {
+ memset (fep, 0, sizeof (struct dvb_frontend_parameters));
+ }
+ if (sec) {
+ memset (sec, 0, sizeof (recv_sec_t));
+ }
+
+
+ freq = mc.s6_addr16[6] | ((mc.s6_addr16[7] & NOPID_MASK) << 3);
+
+ fmul = 25000.0 * (double) freq;
+
+ fep->frequency = (unsigned int) (fmul / 12.0);
+ fep->inversion = (fe_spectral_inversion_t)((mc.s6_addr16[5] >> 14) & 3);
+ fetype = (fe_type_t)(mc.s6_addr16[1] & 0xff);
+
+ if (type) {
+ *type = fetype;
+ }
+ switch ((int)fetype) {
+ case FE_QPSK:
+ case FE_DVBS2:
+ {
+ int Polarisation = mc.s6_addr16[3] >> 12;
+ fep->frequency = freq * 50;
+ sec->mini_cmd = (fe_sec_mini_cmd_t)((Polarisation >> 3) & 1);
+ sec->tone_mode = (fe_sec_tone_mode_t)((Polarisation >> 2) & 1);
+ sec->voltage = (fe_sec_voltage_t)(Polarisation & 3);
+
+ fep->u.qpsk.symbol_rate = mc.s6_addr16[4] * 1000;
+ fep->u.qpsk.fec_inner = (fe_code_rate_t)(mc.s6_addr16[5] & 0xf);
+
+ unsigned int fec_inner=(unsigned int)fep->u.qpsk.fec_inner;
+
+ // RMM S2 Extension
+ switch (mc.s6_addr16[5] & 0x30) {
+ case 0x10:
+ fec_inner |= QPSK_S2 << 16;
+ fep->u.qpsk.fec_inner=(fe_code_rate_t)fec_inner;
+ *type = (fe_type_t) FE_DVBS2; // force FE type
+ break;
+ case 0x20:
+ fec_inner |= PSK8 << 16;
+ fep->u.qpsk.fec_inner=(fe_code_rate_t)fec_inner;
+ *type = (fe_type_t) FE_DVBS2;
+ break;
+ default:
+ *type = FE_QPSK;
+ }
+ }
+ break;
+ case FE_QAM:
+ fep->u.qam.symbol_rate = mc.s6_addr16[4] * 200;
+ fep->u.qam.modulation = (fe_modulation_t)(mc.s6_addr16[5] & 0xf);
+ // Ignore inversion
+ break;
+ case FE_OFDM:
+ fep->u.ofdm.transmission_mode = (fe_transmit_mode_t)((mc.s6_addr16[4] >> 8) & 3);
+ fep->u.ofdm.code_rate_HP = (fe_code_rate_t)((mc.s6_addr16[4] >> 4) & 0xf);
+ fep->u.ofdm.code_rate_LP = (fe_code_rate_t)(mc.s6_addr16[4] & 0xf);
+
+ fep->u.ofdm.constellation = (fe_modulation_t) (mc.s6_addr16[5] & 0xf);
+ fep->u.ofdm.hierarchy_information = (fe_hierarchy_t)((mc.s6_addr16[5] >> 4) & 3);
+ fep->u.ofdm.bandwidth = (fe_bandwidth_t)((mc.s6_addr16[5] >> 7) & 3);
+ fep->u.ofdm.guard_interval = (fe_guard_interval_t)((mc.s6_addr16[5] >> 9) & 7);
+ break;
+ case FE_ATSC:
+ fep->u.vsb.modulation = (fe_modulation_t)(mc.s6_addr16[5] & 0xf);
+ break;
+ }
+
+ if (vpid) {
+ *vpid = mc.s6_addr16[7] & PID_MASK;
+ }
+ //print_frontend_settings(fep);
+ return 0;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+void mcg_set_streaming_group (struct in6_addr *mcg, streaming_group_t StreamingGroup)
+{
+ int i;
+
+ for (i = 0; i < 8; i++) {
+ mcg->s6_addr16[i] = ntohs (mcg->s6_addr16[i]);
+ }
+
+ // Change StreamingGroup
+ mcg->s6_addr16[1] = ((StreamingGroup & 0xf) << 12) | (mcg->s6_addr16[1] & 0x0fff);
+
+ // Remove PID
+ mcg->s6_addr16[7] &= NOPID_MASK;
+
+ // Remove CAID
+ mcg->s6_addr16[2] = 0;
+
+ for (i = 0; i < 8; i++) {
+ mcg->s6_addr16[i] = htons (mcg->s6_addr16[i]);
+ }
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+void mcg_get_streaming_group (struct in6_addr *mcg, streaming_group_t *StreamingGroup)
+{
+ if(StreamingGroup) {
+ *StreamingGroup=(streaming_group_t)((ntohs (mcg->s6_addr16[1]) >> 12) & 0xf);
+ }
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+void mcg_set_pid (struct in6_addr *mcg, int pid)
+{
+
+ mcg->s6_addr16[7] = ntohs (mcg->s6_addr16[7]);
+
+ // Remove PID
+ mcg->s6_addr16[7] &= NOPID_MASK;
+
+ // Set new PID
+ mcg->s6_addr16[7] |= pid;
+
+ mcg->s6_addr16[7] = htons (mcg->s6_addr16[7]);
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+void mcg_get_pid (struct in6_addr *mcg, int *pid)
+{
+ if (pid) {
+ *pid=ntohs (mcg->s6_addr16[7]) & PID_MASK;
+ }
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+void mcg_init_streaming_group (struct in6_addr *mcg, streaming_group_t StreamingGroup)
+{
+ unsigned int Priority = 1;
+ mcg->s6_addr16[0] = MC_PREFIX;
+ mcg->s6_addr16[1] = ((StreamingGroup & 0xf) << 12) | ((Priority & 0xf) << 8) | (0 & 0xff);
+ mcg->s6_addr16[2] = 0;
+ mcg->s6_addr16[3] = 0;
+ mcg->s6_addr16[4] = 0;
+ mcg->s6_addr16[5] = 0;
+ mcg->s6_addr16[6] = 0;
+ mcg->s6_addr16[7] = 0;
+ int i;
+ for (i = 0; i < 8; i++) {
+ mcg->s6_addr16[i] = htons (mcg->s6_addr16[i]);
+ }
+
+}
+
+void mcg_get_priority (struct in6_addr *mcg, int *priority)
+{
+ if (priority) {
+ *priority = (ntohs (mcg->s6_addr16[1])>>8) & 0xf;
+ }
+}
+
+void mcg_set_priority (struct in6_addr *mcg, int priority)
+{
+ mcg->s6_addr16[1] = ntohs (mcg->s6_addr16[1]);
+ mcg->s6_addr16[1] &= 0xf0ff;
+ mcg->s6_addr16[1] |= (priority & 0xf) << 8;
+ mcg->s6_addr16[1] = htons (mcg->s6_addr16[1]);
+}
+
+void mcg_get_satpos (struct in6_addr *mcg, int *satpos)
+{
+ if (satpos) {
+ *satpos = ntohs (mcg->s6_addr16[3]) & 0xfff;
+ }
+}
+
+void mcg_set_satpos (struct in6_addr *mcg, int satpos)
+{
+ mcg->s6_addr16[3] = ntohs (mcg->s6_addr16[3]);
+
+ // Remove SatPos
+ mcg->s6_addr16[3] &= ~NO_SAT_POS;
+
+ // Set new SatPos
+ mcg->s6_addr16[3] |= (satpos & NO_SAT_POS);
+
+ mcg->s6_addr16[3] = htons (mcg->s6_addr16[3]);
+}
+
+void mcg_get_id (struct in6_addr *mcg, int *id)
+{
+ if (id) {
+ *id = ntohs (mcg->s6_addr16[2]);
+ }
+}
+
+void mcg_set_id (struct in6_addr *mcg, int id)
+{
+ mcg->s6_addr16[2] = htons(id);
+}
+
+#if defined LIBRARY || defined SERVER
+#ifndef OS_CODE
+ #define OS_CODE 3
+#endif
+#if MAX_MEM_LEVEL >= 8
+# define DEF_MEM_LEVEL 8
+#else
+# define DEF_MEM_LEVEL MAX_MEM_LEVEL
+#endif
+
+static unsigned char gzip_hdr[] = { 0x1f, 0x8b, Z_DEFLATED, 0 /*flags */ , 0, 0, 0, 0 /*time */ , 0 /*xflags */ , OS_CODE };
+
+int check_header (const Bytef * buf, unsigned int buflen)
+{
+ if (buflen <= 10)
+ return 0;
+
+ if (buf[0] != gzip_hdr[0] || buf[1] != gzip_hdr[1]) {
+ return -1;
+ }
+
+ if (memcmp (buf, gzip_hdr, sizeof (gzip_hdr))) {
+ return -2;
+ }
+ return 10;
+}
+
+unsigned int get32_lsb_first (unsigned char *ptr)
+{
+ int i;
+ unsigned int val = 0;
+ for (i = 3; i >= 0; i--) {
+ val <<= 8;
+ val |= (ptr[i] & 0xff);
+ }
+ return val;
+}
+
+void put32_lsb_first (unsigned char *ptr, unsigned int val)
+{
+ int i;
+ for (i = 0; i < 4; i++) {
+ ptr[i] = val & 0xff;
+ val >>= 8;
+ }
+}
+
+int gzip_ (Bytef * dest, unsigned int *destLen, const Bytef * source, unsigned int sourceLen, int level)
+{
+ unsigned int crc = crc32 (0L, Z_NULL, 0);
+ z_stream stream;
+ int err;
+
+ if (*destLen <= 10) {
+ return Z_BUF_ERROR;
+ }
+ memcpy (dest, gzip_hdr, sizeof (gzip_hdr));
+
+ stream.next_in = (Bytef *) source;
+ stream.avail_in = sourceLen;
+
+ stream.next_out = dest + 10;
+ stream.avail_out = *destLen - 10;
+
+ stream.zalloc = (alloc_func) 0;
+ stream.zfree = (free_func) 0;
+ stream.opaque = (voidpf) 0;
+
+ err = deflateInit2 (&stream, level, Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY);
+
+ if (err != Z_OK)
+ return err;
+
+ err = deflate (&stream, Z_FINISH);
+ if (err != Z_STREAM_END) {
+ deflateEnd (&stream);
+ return err == Z_OK ? Z_BUF_ERROR : err;
+ }
+ *destLen = stream.total_out + 10;
+
+ err = deflateEnd (&stream);
+ crc = crc32 (crc, source, sourceLen);
+
+ put32_lsb_first ((unsigned char *) (dest + *destLen), crc);
+ put32_lsb_first ((unsigned char *) (dest + *destLen + 4), sourceLen);
+
+ *destLen += 8;
+ return err;
+}
+
+int gzip (Bytef * dest, unsigned int *destLen, const Bytef * source, unsigned int sourceLen, int level)
+{
+ if (!level) {
+ memcpy (dest, source, sourceLen);
+ *destLen = sourceLen;
+ return 0;
+ }
+ return gzip_ (dest, destLen, source, sourceLen,level);
+}
+
+int gunzip_ (Bytef * dest, unsigned int *destLen, const Bytef * source, unsigned int sourceLen)
+{
+ unsigned int crc = crc32 (0L, Z_NULL, 0);
+ z_stream stream;
+ int err;
+ int ret = check_header (source, sourceLen);
+ if (ret < 0) {
+ return ret;
+ }
+
+ stream.next_in = (Bytef *) source + ret;
+ stream.avail_in = sourceLen - ret;
+
+ stream.next_out = dest;
+ stream.avail_out = *destLen;
+
+ stream.zalloc = (alloc_func) 0;
+ stream.zfree = (free_func) 0;
+
+ err = inflateInit2 (&stream, -MAX_WBITS);
+ if (err != Z_OK)
+ return err;
+
+ err = inflate (&stream, Z_FINISH);
+ if (err != Z_STREAM_END) {
+ inflateEnd (&stream);
+ if (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0))
+ return Z_DATA_ERROR;
+ return err;
+ }
+ *destLen = stream.total_out;
+
+ err = inflateEnd (&stream);
+ crc = crc32 (crc, dest, stream.total_out);
+
+ int crc_found = get32_lsb_first ((unsigned char *) (stream.next_in));
+ int len_found = get32_lsb_first ((unsigned char *) (stream.next_in + 4));
+
+ if (crc_found == crc && len_found == stream.total_out) {
+ return err;
+ }
+
+ return Z_DATA_ERROR;
+}
+
+int gunzip (Bytef * dest, unsigned int *destLen, const Bytef * source, unsigned int sourceLen)
+{
+ int ret = gunzip_ (dest, destLen, source, sourceLen);
+ if (ret == -1) {
+ memcpy (dest, source, sourceLen);
+ *destLen = sourceLen;
+ return 0;
+ } else if (ret < 0) {
+ return -1;
+ }
+ return 0;
+}
+#endif
+#ifndef BACKTRACE
+ void print_trace (void)
+ {
+ }
+#else
+#include <execinfo.h>
+/* Obtain a backtrace and print it to stdout. */
+void print_trace (void)
+{
+ void *array[10];
+ size_t size;
+ char **strings;
+ size_t i;
+
+ size = backtrace (array, 10);
+ strings = backtrace_symbols (array, size);
+
+ printf ("Obtained %zd stack frames.\n", size);
+
+ for (i = 0; i < size; i++) {
+ printf ("%s\n", strings[i]);
+ }
+ free (strings);
+}
+
+
+void SignalHandlerCrash(int signum)
+{
+ void *array[15];
+ size_t size;
+ char **strings;
+ size_t i;
+ FILE *f;
+ char dtstr[16];
+ time_t t=time(NULL);
+ struct tm *tm=localtime(&t);
+
+ signal(signum,SIG_DFL); // Allow core dump
+
+ f=fopen("/var/log/mcli.crashlog","a");
+ if (f) {
+ strftime(dtstr, sizeof(dtstr), "%b %e %T", tm);
+ size = backtrace (array, 15);
+ strings = backtrace_symbols (array, size);
+ fprintf(f,"%s ### Crash signal %i ###\n",dtstr, signum);
+ for (i = 0; i < size; i++)
+ fprintf (f, "%s Backtrace %i: %s\n", dtstr, i, strings[i]);
+ free (strings);
+ fclose(f);
+ }
+}
+#endif
+
+#ifdef SYSLOG
+pthread_mutex_t _loglock = PTHREAD_MUTEX_INITIALIZER;
+
+UDPContext * syslog_fd = NULL;
+char *_logstr = NULL;
+
+int syslog_init(void)
+{
+ struct in6_addr mcglog;
+ mcg_init_streaming_group (&mcglog, STREAMING_LOG);
+ syslog_fd = server_udp_open (&mcglog, 23000, NULL);
+ if(syslog_fd) {
+ _logstr=(char *)malloc(10240);
+ }
+
+ return syslog_fd?0:-1;
+}
+
+int syslog_write(char *s)
+{
+ return udp_write (syslog_fd, (uint8_t *)s, strlen(s));
+}
+
+void syslog_exit(void)
+{
+ if(syslog_fd) {
+ udp_close(syslog_fd);
+ free(_logstr);
+ }
+}
+#endif
diff --git a/mcast/common/tools.h b/mcast/common/tools.h
new file mode 100644
index 0000000..bdcdf69
--- /dev/null
+++ b/mcast/common/tools.h
@@ -0,0 +1,108 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ */
+
+#ifndef __TOOLS_H__
+#define __TOOLS_H__
+
+#define PID_MASK 0x1fff
+#define NOPID_MASK 0xe000
+
+#define MC_PREFIX 0xff18
+
+#define NO_SAT_POS 0xfff
+
+// value from sat_resolved
+#define NOT_RESOLVED -1 // Not run through mcg_is_equivalent/satellite_resolver
+#define NOT_SUPPORTED -2 // requested position not available
+#define LEGACY_DISEQC -3
+
+
+#define COMPRESSION_ON 1
+#define COMPRESSION_OFF 0
+
+struct lookup_dvb_t_fec
+{
+ int fec_hp;
+ int fec_lp;
+ int val;
+};
+
+typedef struct
+{
+ char *name;
+ int value;
+} Param;
+
+typedef enum
+{
+ STREAMING_TCA = 1,
+ STREAMING_TRA = 2,
+ STREAMING_PID = 3,
+ STREAMING_TEN = 4,
+ STREAMING_LOG = 5,
+} streaming_group_t;
+
+
+// 8=max. tuner slots (some safety)
+#define MAX_TUNER_CACHE 8
+
+// contains parsed/cached FE params
+
+
+struct sat_cache {
+ int resolved; // -1=not resolved
+ int num;
+ int component;
+};
+
+struct mcg_data {
+ struct in6_addr mcg;
+ fe_type_t type;
+ recv_sec_t sec;
+ int vpid;
+ struct dvb_frontend_parameters fep;
+ int satpos;
+ // Small temporary cache for SAT-resolution
+ struct sat_cache sat_cache[MAX_TUNER_CACHE];
+};
+
+void print_fe_info (struct dvb_frontend_info *fe_info);
+void print_mcg (struct in6_addr *mcg);
+void print_frontend_settings (struct dvb_frontend_parameters *fe_parms);
+
+DLL_SYMBOL void fe_parms_to_mcg (struct in6_addr *mcg, streaming_group_t StreamingGroup, fe_type_t type, recv_sec_t * sec, struct dvb_frontend_parameters *fep, int vpid);
+DLL_SYMBOL int mcg_to_fe_parms (struct in6_addr *mcg, fe_type_t * type, recv_sec_t * sec, struct dvb_frontend_parameters *fep, int *vpid);
+DLL_SYMBOL int mcg_to_all_parms(struct in6_addr *mcg, struct mcg_data * mcd);
+
+DLL_SYMBOL void mcg_set_streaming_group (struct in6_addr *mcg, streaming_group_t StreamingGroup);
+DLL_SYMBOL void mcg_get_streaming_group (struct in6_addr *mcg, streaming_group_t *StreamingGroup);
+DLL_SYMBOL void mcg_init_streaming_group (struct in6_addr *mcg, streaming_group_t StreamingGroup);
+
+DLL_SYMBOL void mcg_set_pid (struct in6_addr *mcg, int pid);
+DLL_SYMBOL void mcg_get_pid (struct in6_addr *mcg, int *pid);
+
+DLL_SYMBOL void mcg_get_priority (struct in6_addr *mcg, int *priority);
+DLL_SYMBOL void mcg_set_priority (struct in6_addr *mcg, int priority);
+
+DLL_SYMBOL void mcg_get_satpos (struct in6_addr *mcg, int *satpos);
+DLL_SYMBOL void mcg_set_satpos (struct in6_addr *mcg, int satpos);
+
+DLL_SYMBOL void mcg_get_id (struct in6_addr *mcg, int *id);
+DLL_SYMBOL void mcg_set_id (struct in6_addr *mcg, int id);
+
+
+int gzip (Bytef * dest, unsigned int *destLen, const Bytef * source, unsigned int sourceLen, int level);
+int gunzip (Bytef * dest, unsigned int *destLen, const Bytef * source, unsigned int sourceLen);
+void print_trace (void);
+void SignalHandlerCrash(int signum);
+
+int syslog_init(void);
+int syslog_write(char *s);
+void syslog_exit(void);
+
+#endif
diff --git a/mcast/common/version.h b/mcast/common/version.h
new file mode 100644
index 0000000..e7aea47
--- /dev/null
+++ b/mcast/common/version.h
@@ -0,0 +1,18 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ */
+
+#ifdef P2P
+ #define MCLI_P2PSTR "-P2P"
+#else
+ #define MCLI_P2PSTR ""
+#endif
+#define MCLI_APP_VERSION "0.99.33"MCLI_P2PSTR
+#define MCLI_COMPILED __DATE__" "__TIME__
+#define MCLI_VERSION_STR MCLI_APP_VERSION" ("MCLI_COMPILED")"
+#define MCLI_MAGIC 0xDEADBEEF
+#define MCLI_VERSION 0x14
diff --git a/mcast/dvbloop/.svn/entries b/mcast/dvbloop/.svn/entries
new file mode 100644
index 0000000..27a2288
--- /dev/null
+++ b/mcast/dvbloop/.svn/entries
@@ -0,0 +1,266 @@
+10
+
+dir
+18963
+svn://reelbox.org/testing/src/vdr-plugins/src/mcli-1/mcast/dvbloop
+svn://reelbox.org
+
+
+
+2011-07-13T10:29:48.841676Z
+16920
+rollercoaster
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+12be777f-adf9-0310-842f-e37ecc4c7426
+
+dvblo_char.h
+file
+
+
+
+
+2012-09-27T17:22:49.554848Z
+7553ff59846c61f88d2c7171141787db
+2011-07-13T10:29:48.841676Z
+16920
+rollercoaster
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+861
+
+dvblo_util.h
+file
+
+
+
+
+2012-09-27T17:22:49.558848Z
+46c77702134b5e6a2d12f523b6bc24c0
+2011-07-13T10:29:48.841676Z
+16920
+rollercoaster
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1085
+
+dvblo_adap_fe.h
+file
+
+
+
+
+2012-09-27T17:22:49.558848Z
+46ddf82ea04127779d379b1322eb5917
+2011-07-13T10:29:48.841676Z
+16920
+rollercoaster
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1061
+
+dvblo.h
+file
+
+
+
+
+2012-09-27T17:22:49.558848Z
+6e4aa28638d3a37d219f92cc767e622f
+2011-07-13T10:29:48.841676Z
+16920
+rollercoaster
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1653
+
+dvblo_adap.h
+file
+
+
+
+
+2012-09-27T17:22:49.554848Z
+fc1f91fe9ae2874f3f81208624d86a8a
+2011-07-13T10:29:48.841676Z
+16920
+rollercoaster
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+3964
+
+dvblo_adap_ca.h
+file
+
+
+
+
+2012-09-27T17:22:49.554848Z
+63e84e959a0e8ca86b0b177cf02456bb
+2011-07-13T10:29:48.841676Z
+16920
+rollercoaster
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1063
+
+dvblo_ioctl.h
+file
+
+
+
+
+2012-09-27T17:22:49.554848Z
+89d6a7d362e0ccde5d23822e9a060187
+2011-07-13T10:29:48.841676Z
+16920
+rollercoaster
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+5102
+
diff --git a/mcast/dvbloop/.svn/text-base/dvblo.h.svn-base b/mcast/dvbloop/.svn/text-base/dvblo.h.svn-base
new file mode 100644
index 0000000..2ce7a4b
--- /dev/null
+++ b/mcast/dvbloop/.svn/text-base/dvblo.h.svn-base
@@ -0,0 +1,58 @@
+/* dvbloop - A DVB Loopback Device
+ * Copyright (C) 2006 Christian Praehauser, Deti Fliegl
+ -----------------------------------------
+ * File: dvblo.h
+ * Desc: Common Header File
+ * Date: October 2006
+ * Author: Christian Praehauser <cpreahaus@cosy.sbg.ac.at>, Deti Fliegl <deti@fliegl.de>
+ *
+ * This file is released under the GPLv2.
+ */
+
+#ifndef _DVBLO_H_
+#define _DVBLO_H_
+
+#include <linux/stringify.h>
+
+#define DVBLO_NAME "dvblo"
+#define DVBLO_VERSION "0.9.4"
+#define DVBLO_LONGMANE "DVB Loopback Adapter Version "DVBLO_VERSION
+
+#define DVBLO_DEVMAX 8
+
+#define DVBLO_TS_SZ 188
+
+#define SUCCESS 0
+
+/* DVBLO_DEFINE_GLOBALS is defined by the file which defines the global
+ * variables, which is usally dvblo.c.
+ */
+#ifndef DVBLO_DEFINE_GLOBALS
+/* defined in dvblo.c */
+extern unsigned int dvblo_debug;
+extern unsigned int dvblo_autocreate;
+
+#endif /* */
+
+#define DVBLO_DEBUG_LEVELS 3
+
+#define DBGLEV_ADAP DVBLO_DEBUG_LEVELS
+#define DBGLEV_ADAP_FE (DBGLEV_ADAP+DVBLO_DEBUG_LEVELS)
+#define DBGLEV_ADAP_CA (DBGLEV_ADAP_FE+DVBLO_DEBUG_LEVELS)
+#define DBGLEV_CHAR (DBGLEV_ADAP_CA+DVBLO_DEBUG_LEVELS)
+
+#define DBGLEV_ALL 0
+#define DBGLEV_1 (1<<0)
+#define DBGLEV_2 (1<<1)
+#define DBGLEV_3 (1<<2)
+
+#define dprintk(level,args...) \
+ do { if ((dvblo_debug & level) == level) { printk (KERN_DEBUG "%s: %s(): ", DVBLO_NAME, __FUNCTION__); printk (args); } } while (0)
+
+/*#define dprintk(level,args...) \
+ do {{ printk(KERN_DEBUG "%s: %s(): ", __stringify(DVBLO_NAME), __FUNCTION__); printk(args); } } while (0)
+*/
+#define mprintk(level, args...) \
+ do { printk (level "%s: %s(): ", DVBLO_NAME, __FUNCTION__); printk (args); } while (0)
+
+#endif /* _DVBLO_H_ */
diff --git a/mcast/dvbloop/.svn/text-base/dvblo_adap.h.svn-base b/mcast/dvbloop/.svn/text-base/dvblo_adap.h.svn-base
new file mode 100644
index 0000000..26f6bfc
--- /dev/null
+++ b/mcast/dvbloop/.svn/text-base/dvblo_adap.h.svn-base
@@ -0,0 +1,155 @@
+/* dvbloop - A DVB Loopback Device
+ * Copyright (C) 2006 Christian Praehauser, Deti Fliegl
+ -----------------------------------------
+ * File: dvblo_adap.h
+ * Desc: Support for virtual DVB adapters
+ * Date: October 2006
+ * Author: Christian Praehauser <cpreahaus@cosy.sbg.ac.at>, Deti Fliegl <deti@fliegl.de>
+ *
+ * This file is released under the GPLv2.
+ */
+
+#ifndef _DVBLO_ADAP_H_
+#define _DVBLO_ADAP_H_
+
+#include <linux/types.h>
+#include "dvb-core/dvbdev.h"
+#include "dvb-core/dvb_demux.h"
+#include "dvb-core/dmxdev.h"
+#include "dvb-core/dvb_net.h"
+#include "dvb-core/dvb_frontend.h"
+#include <linux/dvb/ca.h>
+#include "dvblo_ioctl.h"
+
+struct dvblo_adap_statistics
+{
+
+ /// Number of TS packets received on the adapter
+ unsigned long ts_count;
+};
+
+/**
+ * Structure that represents a virtual DVB adapter instance
+ * @todo rename this to dvblo_adap
+ */
+struct dvblo
+{
+
+ /**
+ * Level of initialization
+ * This help dvblo_destroy() to determine which things have to be
+ * cleaned/unregistered as it is used by dvblo_init() when an error occurs
+ */
+ unsigned int initlev:8;
+
+ /// Flag that is set to 1 if this dvblo structure is completely initialized
+ unsigned int initdone:1;
+
+ /// The name of this adapter, e.g. "dvblo_adap0"
+ char name[16];
+ struct
+ {
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,12)
+ /* Since kernel version 2.6.12 the dvb_adapter structure has to be
+ * embedded into our structure
+ */
+ struct dvb_adapter adap;
+
+#define DVBLO_DVB_ADAP(dvblop) (&(dvblop)->dvb.adap)
+#else /* */
+ struct dvb_adapter *adap;
+
+#define DVBLO_DVB_ADAP(dvblop) ((dvblop)->dvb.adap)
+#endif /* */
+ struct dvb_device *ca_dev;
+ struct dmxdev dmxdev;
+ struct dvb_demux demux;
+ struct dvb_net net;
+ struct dvb_frontend frontend;
+
+ /* struct dvb_frontend: tuner_priv was added in 2.6.18 */
+#define FE_PRIV(fep) ((fep)->demodulator_priv)
+
+#define DVBLO_DVB_ADAP_FEPRIV(dvblop) FE_PRIV(&((dvblop)->dvb.frontend))
+ struct dmx_frontend hw_frontend;
+ struct dmx_frontend mem_frontend;
+ } dvb;
+
+ /// count, how many times dvblo_demux_start_feed() has been called
+ int feeding;
+ struct semaphore sem;
+ spinlock_t event_lock;
+ wait_queue_head_t event_queue;
+ unsigned int event;
+ struct dvblo_adap_statistics stats;
+ struct
+ {
+ struct dvb_frontend_parameters params;
+ struct
+ {
+ struct dvb_frontend_parameters params;
+ u32 status;
+ } tuner;
+ dvblo_sec_t sec;
+ dvblo_festatus_t status;
+ } fe;
+
+ struct dvb_ringbuffer ci_rbuffer;
+ struct dvb_ringbuffer ci_wbuffer;
+ dvblo_cacaps_t ca;
+
+ dvblo_private_t private;
+};
+
+/**
+ * Adapter configuration paramters
+ */
+struct dvblo_adap_config
+{
+
+ /// Whether a MAC address is specified by this structure
+ unsigned int mac_valid:1;
+
+ /// The MAC address of the DVB adapter (if mac_valid == 1)
+ u8 mac[6];
+};
+
+/**
+ * Creates a new virtual DVB adapter
+ * @param adapnum The desired adapter number (set to -1 for automatic assignment)
+ * @param cfg Adapter configuration (may be NULL)
+ * @param dvblo_out A pointer to the newly allocated DVB adapter context is
+ * returned via this parameter
+ */
+int dvblo_adap_create (int adapnum, struct dvblo_adap_config *cfg, struct dvblo **dvblo_out);
+
+/**
+ * Destroys a virtual DVB adapter
+ */
+int dvblo_adap_destroy (struct dvblo *dvblo);
+
+/**
+ * Deliver TS packets to the virtual DVB adapter
+ * @param dvblo The dvblo adapter context
+ * @param buf Pointer to buffer containing TS packets
+ * @param len Length of buf in bytes
+ */
+ssize_t dvblo_adap_deliver_packets (struct dvblo *dvblo, const u8 * buf, size_t len);
+
+/**
+ * Handle event bitpattern without race conditions
+ */
+unsigned int dvblo_set_event (struct dvblo *dvblo, unsigned int event);
+
+/**
+ * Get list of currently active PIDs from DVB adapter
+ */
+int dvblog_adap_get_pids (struct dvblo *dvblo, dvblo_pids_t * pids_out);
+
+/**
+ * Get MAC address of virtual DVB adapter
+ */
+int dvblo_adap_get_mac (struct dvblo *dvblo, u8 * mac_out);
+
+#endif /* _DVBLO_ADAP_H_ */
diff --git a/mcast/dvbloop/.svn/text-base/dvblo_adap_ca.h.svn-base b/mcast/dvbloop/.svn/text-base/dvblo_adap_ca.h.svn-base
new file mode 100644
index 0000000..192fa60
--- /dev/null
+++ b/mcast/dvbloop/.svn/text-base/dvblo_adap_ca.h.svn-base
@@ -0,0 +1,43 @@
+/* dvbloop - A DVB Loopback Device
+ * Copyright (C) 2006 Christian Praehauser, Deti Flieg
+ -----------------------------------------
+ * File: dvblo_adap.c
+ * Desc: Support for virtual DVB adapters - Frontend implementation
+ * Date: October 2006
+ * Author: Christian Praehauser <cpreahaus@cosy.sbg.ac.at>, Deti Fliegl <deti@fliegl.de>
+ *
+ * This file is released under the GPLv2.
+ */
+
+#ifndef _DVBLO_ADAP_CA_H_
+#define _DVBLO_ADAP_CA_H_
+
+#include "dvb-core/dvbdev.h"
+#include "dvb-core/dvb_demux.h"
+#include "dvb-core/dmxdev.h"
+#include "dvb-core/dvb_net.h"
+#include "dvb-core/dvb_frontend.h"
+#include "dvb-core/dvb_ringbuffer.h"
+#include "linux/dvb/ca.h"
+
+void ci_get_data(struct dvb_ringbuffer *cibuf, u8 *data, int len);
+
+/**
+ * Register new ca device
+ */
+int dvblo_ca_register(struct dvblo *dvblo);
+/**
+ * Unregister ca device
+ */
+void dvblo_ca_unregister(struct dvblo *dvblo);
+/**
+ * Initialize ca device
+ */
+int dvblo_ca_init(struct dvblo* dvblo);
+/**
+ * Uninitialize ca device
+ */
+void dvblo_ca_exit(struct dvblo* dvblo);
+
+
+#endif /* _DVBLO_ADAP_FE_H_ */
diff --git a/mcast/dvbloop/.svn/text-base/dvblo_adap_fe.h.svn-base b/mcast/dvbloop/.svn/text-base/dvblo_adap_fe.h.svn-base
new file mode 100644
index 0000000..fcdef0d
--- /dev/null
+++ b/mcast/dvbloop/.svn/text-base/dvblo_adap_fe.h.svn-base
@@ -0,0 +1,30 @@
+/* dvbloop - A DVB Loopback Device
+ * Copyright (C) 2006 Christian Praehauser, Deti Flieg
+ -----------------------------------------
+ * File: dvblo_adap.c
+ * Desc: Support for virtual DVB adapters - Frontend implementation
+ * Date: October 2006
+ * Author: Christian Praehauser <cpreahaus@cosy.sbg.ac.at>, Deti Fliegl <deti@fliegl.de>
+ *
+ * This file is released under the GPLv2.
+ */
+
+#ifndef _DVBLO_ADAP_FE_H_
+#define _DVBLO_ADAP_FE_H_
+
+#include "dvb-core/dvbdev.h"
+#include "dvb-core/dvb_demux.h"
+#include "dvb-core/dmxdev.h"
+#include "dvb-core/dvb_net.h"
+#include "dvb-core/dvb_frontend.h"
+extern struct dvb_frontend_ops dvblo_adap_fe_ops;
+int dvblo_fe_get_info (struct dvblo *dvblo, struct dvb_frontend_info *info);
+int dvblo_fe_set_info (struct dvblo *dvblo, struct dvb_frontend_info *info);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,18)
+int dvblo_fe_get_tunerinfo (struct dvblo *dvblo, struct dvb_tuner_info *tunerinfo);
+int dvblo_fe_set_tunerinfo (struct dvblo *dvblo, struct dvb_tuner_info *tunerinfo);
+
+#endif /* */
+
+#endif /* _DVBLO_ADAP_FE_H_ */
diff --git a/mcast/dvbloop/.svn/text-base/dvblo_char.h.svn-base b/mcast/dvbloop/.svn/text-base/dvblo_char.h.svn-base
new file mode 100644
index 0000000..41f5744
--- /dev/null
+++ b/mcast/dvbloop/.svn/text-base/dvblo_char.h.svn-base
@@ -0,0 +1,33 @@
+/* dvbloop - A DVB Loopback Device
+ * Copyright (C) 2006 Christian Praehauser, Deti Fliegl
+ -----------------------------------------
+ * File: dvblo_char.h
+ * Desc: Char device support for dvblo
+ * Date: October 2006
+ * Author: Christian Praehauser <cpreahaus@cosy.sbg.ac.at>, Deti Fliegl <deti@fliegl.de>
+ *
+ * This file is released under the GPLv2.
+ */
+
+#ifndef _DVBLO_CHAR_H_
+#define _DVBLO_CHAR_H_
+
+#include "dvblo.h"
+#include "dvblo_adap.h"
+
+/**
+ * Maximum number of devices
+ */
+#define DVBLO_CHAR_DEVMAX 8
+struct dvblo_chardev_config
+{
+
+ /// The configuration for the corresponding virtual DVB adapter
+ struct dvblo_adap_config dvbcfg;
+};
+int dvblo_char_init (void);
+int dvblo_char_exit (void);
+int dvblo_char_add_dev (struct dvblo_chardev_config *cfg, unsigned int *devnum_out);
+int dvblo_char_del_dev (unsigned int devnum);
+
+#endif /* _DVBLO_CHAR_H_ */
diff --git a/mcast/dvbloop/.svn/text-base/dvblo_ioctl.h.svn-base b/mcast/dvbloop/.svn/text-base/dvblo_ioctl.h.svn-base
new file mode 100644
index 0000000..08e737c
--- /dev/null
+++ b/mcast/dvbloop/.svn/text-base/dvblo_ioctl.h.svn-base
@@ -0,0 +1,203 @@
+/* dvbloop - A DVB Loopback Device
+ * Copyright (C) 2006 Christian Praehauser, Deti Fliegl
+ -----------------------------------------
+ * File: dvblo_char.h
+ * Desc: Char device support for dvblo
+ * Date: October 2006
+ * Author: Christian Praehauser <cpreahaus@cosy.sbg.ac.at>, Deti Fliegl <deti@fliegl.de>
+ *
+ * This file is released under the GPLv2.
+ */
+
+#ifndef _DVBLO_IOCTL_H_
+#define _DVBLO_IOCTL_H_
+
+#ifndef WIN32
+#include <linux/ioctl.h>
+#endif
+/**
+ * Maximum number of devices
+ */
+#define DVBLO_IOC_MAGIC 'd'
+#define PRIV_DATA_SIZE 4096
+typedef struct
+{
+ u_int16_t pid[256];
+ int num;
+} dvblo_pids_t;
+typedef struct dvblo_sec
+{
+ struct dvb_diseqc_master_cmd diseqc_cmd;
+ fe_sec_mini_cmd_t mini_cmd;
+ fe_sec_tone_mode_t tone_mode;
+ fe_sec_voltage_t voltage;
+} dvblo_sec_t;
+typedef struct dvblo_festatus
+{
+ fe_status_t st;
+ u_int32_t ber;
+ u_int16_t strength;
+ u_int16_t snr;
+ u_int32_t ucblocks;
+} dvblo_festatus_t;
+typedef unsigned char dvblo_private_t[PRIV_DATA_SIZE];
+
+#define CA_MAX_SLOTS 16
+typedef struct {
+ ca_caps_t cap;
+ ca_slot_info_t info[CA_MAX_SLOTS];
+} dvblo_cacaps_t;
+
+#define CA_TPDU_MAX 2048
+typedef struct {
+ u_int16_t len;
+ u_int8_t data[CA_TPDU_MAX];
+} dvblo_tpdu_t;
+
+#define EV_MASK_FE 0x0000000f
+#define EV_MASK_PID 0x000000f0
+#define EV_MASK_SEC 0x00000f00
+#define EV_MASK_PRIV 0x0000f000
+#define EV_MASK_CA 0x000f0000
+
+#define EV_FRONTEND 0x00000001
+#define EV_TUNER 0x00000002
+#define EV_FREQUENCY 0x00000004
+#define EV_BANDWIDTH 0x00000008
+
+#define EV_PIDFILTER 0x00000010
+
+#define EV_TONE 0x00000100
+#define EV_VOLTAGE 0x00000200
+#define EV_DISEC_MSG 0x00000400
+#define EV_DISEC_BURST 0x00000800
+
+#define EV_PRIV_READ 0x00001000
+#define EV_PRIV_WRITE 0x00002000
+
+#define EV_CA_RESET 0x00010000
+#define EV_CA_WRITE 0x00020000
+#define EV_CA_PID 0x00040000
+#define EV_CA_DESCR 0x00080000
+
+struct dvblo_ioc_dev
+{
+
+ /// The MAC address of the virtual DVB adapter
+ u_int8_t mac[6];
+
+ /**
+ * This is set to the number of the new device when ioctl(DVBLO_IOCADDDEV)
+ * was successful.
+ * @note This corresponds to the minor device number.
+ */
+ int num;
+};
+
+/**
+ * @brief Add a new DVBLoop adapter device
+ */
+#define DVBLO_IOCADDDEV _IO(DVBLO_IOC_MAGIC, 1)
+/**
+ * @brief Remove the DVBLoop adapter device with the specified number
+ */
+#define DVBLO_IOCDELDEV _IO(DVBLO_IOC_MAGIC, 2)
+/**
+ * @brief Check if DVBLoop adapter has a corresponding dvb device
+ */
+#define DVBLO_IOCCHECKDEV _IO(DVBLO_IOC_MAGIC, 30)
+/**
+ * @brief Get event mask
+ */
+#define DVBLO_GET_EVENT_MASK _IOR(DVBLO_IOC_MAGIC, 3, unsigned int)
+/**
+ * @brief Get FE parameters
+ */
+#define DVBLO_GET_FRONTEND_PARAMETERS _IOR(DVBLO_IOC_MAGIC, 4, struct dvb_frontend_parameters)
+/**
+ * @brief Set FE parameters
+ */
+#define DVBLO_SET_FRONTEND_PARAMETERS _IOW(DVBLO_IOC_MAGIC, 4, struct dvb_frontend_parameters)
+/**
+ * @brief Get tuner parameters
+ */
+#define DVBLO_GET_TUNER_PARAMETERS _IOR(DVBLO_IOC_MAGIC, 5, struct dvb_frontend_parameters)
+/**
+ * @brief Set tuner parameters
+ */
+#define DVBLO_SET_TUNER_PARAMETERS _IOW(DVBLO_IOC_MAGIC, 5, struct dvb_frontend_parameters)
+/**
+ * @brief Get SEC parameters
+ */
+#define DVBLO_GET_SEC_PARAMETERS _IOR(DVBLO_IOC_MAGIC, 6, struct dvblo_sec)
+/**
+ * @brief Get SEC parameters
+ */
+#define DVBLO_SET_SEC_PARAMETERS _IOW(DVBLO_IOC_MAGIC, 6, struct dvblo_sec)
+/**
+ * @brief Set FE-Status parameters
+ */
+#define DVBLO_GET_FRONTEND_STATUS _IOR(DVBLO_IOC_MAGIC, 7, struct dvblo_festatus)
+/**
+ * @brief Set Tuner-Status parameters
+ */
+#define DVBLO_SET_FRONTEND_STATUS _IOW(DVBLO_IOC_MAGIC, 7, struct dvblo_festatus)
+/**
+ * @brief Get Tuner-Status parameters
+ */
+#define DVBLO_GET_TUNER_STATUS _IOR(DVBLO_IOC_MAGIC, 8, u_int32_t)
+/**
+ * @brief Set Tuner-Status parameters
+ */
+#define DVBLO_SET_TUNER_STATUS _IOW(DVBLO_IOC_MAGIC, 8, u_int32_t)
+/**
+ * @brief Set FE-Info
+ */
+#define DVBLO_GET_FRONTEND_INFO _IOR(DVBLO_IOC_MAGIC, 9, struct dvb_frontend_info)
+/**
+ * @brief Set FE-Info
+ */
+#define DVBLO_SET_FRONTEND_INFO _IOW(DVBLO_IOC_MAGIC, 9, struct dvb_frontend_info)
+
+#ifndef WIN32
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,18)
+/**
+ * @brief Set Tuner-Info
+ */
+#define DVBLO_GET_TUNER_INFO _IOR(DVBLO_IOC_MAGIC, 10, struct dvb_tuner_info)
+/**
+ * @brief Set Tuner-Info
+ */
+#define DVBLO_SET_TUNER_INFO _IOW(DVBLO_IOC_MAGIC, 10, struct dvb_tuner_info)
+#endif /* */
+/**
+ * @brief Get list of PIDS
+ */
+#define DVBLO_GET_PIDLIST _IOR(DVBLO_IOC_MAGIC, 20, dvblo_pids_t)
+/**
+ * @brief Pass through of private data
+ */
+#define DVBLO_GET_PRIVATE _IOR(DVBLO_IOC_MAGIC, 40, dvblo_private_t)
+/**
+ * @brief Pass through of private data
+ */
+#define DVBLO_SET_PRIVATE _IOW(DVBLO_IOC_MAGIC, 40, dvblo_private_t)
+/**
+ * @brief Get CA_CAPS including slot_info
+ */
+#define DVBLO_GET_CA_CAPS _IOR(DVBLO_IOC_MAGIC, 80, dvblo_cacaps_t)
+/**
+ * @brief Set CA_CAPS including slot_info
+ */
+#define DVBLO_SET_CA_CAPS _IOW(DVBLO_IOC_MAGIC, 80, dvblo_cacaps_t)
+/**
+ * @brief Get TPDU
+ */
+#define DVBLO_GET_TPDU _IOR(DVBLO_IOC_MAGIC, 81, dvblo_tpdu_t)
+/**
+ * @brief Send TPDU
+ */
+#define DVBLO_SET_TPDU _IOW(DVBLO_IOC_MAGIC, 81, dvblo_tpdu_t)
+
+#endif /* _DVBLO_IOCTL_H_ */
+#endif
diff --git a/mcast/dvbloop/.svn/text-base/dvblo_util.h.svn-base b/mcast/dvbloop/.svn/text-base/dvblo_util.h.svn-base
new file mode 100644
index 0000000..e86bfa6
--- /dev/null
+++ b/mcast/dvbloop/.svn/text-base/dvblo_util.h.svn-base
@@ -0,0 +1,45 @@
+/* dvbloop - A DVB Loopback Device
+ * Copyright (C) 2006 Christian Praehauser, Deti Fliegl
+ -----------------------------------------
+ * File: dvblo_char.h
+ * Desc: Char device support for dvblo
+ * Date: October 2006
+ * Author: Christian Praehauser <cpreahaus@cosy.sbg.ac.at>, Deti Fliegl <deti@fliegl.de>
+ *
+ * This file is released under the GPLv2.
+ */
+
+#ifndef _DVBLO_UTIL_H_
+#define _DVBLO_UTIL_H_
+
+#include <linux/types.h>
+int dvblo_parse_mac (const char *macstr, u8 * mac_out);
+
+#if 0
+/**
+ * Ring buffer implementation
+ * @todo maybe use kfifo which is provided by Linux kernels >= 2.6.10
+ */
+struct dvblo_ringbuf
+{
+ u8 *buf;
+ size_t size;
+ unsigned int wr;
+ unsigned int rd;
+};
+typedef struct dvblo_ringbuf dvblo_ringbuf_t;
+static inline int dvblo_rb_alloc (size_t size, dvblo_ringbuf_t * rb_out)
+{
+ rb_out->buf = kmalloc (size, GFP_KERNEL);
+ if (rb_out->buf == NULL)
+ return -ENOMEM;
+
+ else {
+ rb_out->size = size;
+ rb_out->in = rb_out->out = 0;
+ }
+ return 0;
+}
+static inline ssize_t dvblo_rb_write (dvblo_ringbuf_t * rb_out,
+#endif /* */
+#endif /* _DVBLO_UTIL_H_ */
diff --git a/mcast/dvbloop/dvblo.h b/mcast/dvbloop/dvblo.h
new file mode 100644
index 0000000..2ce7a4b
--- /dev/null
+++ b/mcast/dvbloop/dvblo.h
@@ -0,0 +1,58 @@
+/* dvbloop - A DVB Loopback Device
+ * Copyright (C) 2006 Christian Praehauser, Deti Fliegl
+ -----------------------------------------
+ * File: dvblo.h
+ * Desc: Common Header File
+ * Date: October 2006
+ * Author: Christian Praehauser <cpreahaus@cosy.sbg.ac.at>, Deti Fliegl <deti@fliegl.de>
+ *
+ * This file is released under the GPLv2.
+ */
+
+#ifndef _DVBLO_H_
+#define _DVBLO_H_
+
+#include <linux/stringify.h>
+
+#define DVBLO_NAME "dvblo"
+#define DVBLO_VERSION "0.9.4"
+#define DVBLO_LONGMANE "DVB Loopback Adapter Version "DVBLO_VERSION
+
+#define DVBLO_DEVMAX 8
+
+#define DVBLO_TS_SZ 188
+
+#define SUCCESS 0
+
+/* DVBLO_DEFINE_GLOBALS is defined by the file which defines the global
+ * variables, which is usally dvblo.c.
+ */
+#ifndef DVBLO_DEFINE_GLOBALS
+/* defined in dvblo.c */
+extern unsigned int dvblo_debug;
+extern unsigned int dvblo_autocreate;
+
+#endif /* */
+
+#define DVBLO_DEBUG_LEVELS 3
+
+#define DBGLEV_ADAP DVBLO_DEBUG_LEVELS
+#define DBGLEV_ADAP_FE (DBGLEV_ADAP+DVBLO_DEBUG_LEVELS)
+#define DBGLEV_ADAP_CA (DBGLEV_ADAP_FE+DVBLO_DEBUG_LEVELS)
+#define DBGLEV_CHAR (DBGLEV_ADAP_CA+DVBLO_DEBUG_LEVELS)
+
+#define DBGLEV_ALL 0
+#define DBGLEV_1 (1<<0)
+#define DBGLEV_2 (1<<1)
+#define DBGLEV_3 (1<<2)
+
+#define dprintk(level,args...) \
+ do { if ((dvblo_debug & level) == level) { printk (KERN_DEBUG "%s: %s(): ", DVBLO_NAME, __FUNCTION__); printk (args); } } while (0)
+
+/*#define dprintk(level,args...) \
+ do {{ printk(KERN_DEBUG "%s: %s(): ", __stringify(DVBLO_NAME), __FUNCTION__); printk(args); } } while (0)
+*/
+#define mprintk(level, args...) \
+ do { printk (level "%s: %s(): ", DVBLO_NAME, __FUNCTION__); printk (args); } while (0)
+
+#endif /* _DVBLO_H_ */
diff --git a/mcast/dvbloop/dvblo_adap.h b/mcast/dvbloop/dvblo_adap.h
new file mode 100644
index 0000000..26f6bfc
--- /dev/null
+++ b/mcast/dvbloop/dvblo_adap.h
@@ -0,0 +1,155 @@
+/* dvbloop - A DVB Loopback Device
+ * Copyright (C) 2006 Christian Praehauser, Deti Fliegl
+ -----------------------------------------
+ * File: dvblo_adap.h
+ * Desc: Support for virtual DVB adapters
+ * Date: October 2006
+ * Author: Christian Praehauser <cpreahaus@cosy.sbg.ac.at>, Deti Fliegl <deti@fliegl.de>
+ *
+ * This file is released under the GPLv2.
+ */
+
+#ifndef _DVBLO_ADAP_H_
+#define _DVBLO_ADAP_H_
+
+#include <linux/types.h>
+#include "dvb-core/dvbdev.h"
+#include "dvb-core/dvb_demux.h"
+#include "dvb-core/dmxdev.h"
+#include "dvb-core/dvb_net.h"
+#include "dvb-core/dvb_frontend.h"
+#include <linux/dvb/ca.h>
+#include "dvblo_ioctl.h"
+
+struct dvblo_adap_statistics
+{
+
+ /// Number of TS packets received on the adapter
+ unsigned long ts_count;
+};
+
+/**
+ * Structure that represents a virtual DVB adapter instance
+ * @todo rename this to dvblo_adap
+ */
+struct dvblo
+{
+
+ /**
+ * Level of initialization
+ * This help dvblo_destroy() to determine which things have to be
+ * cleaned/unregistered as it is used by dvblo_init() when an error occurs
+ */
+ unsigned int initlev:8;
+
+ /// Flag that is set to 1 if this dvblo structure is completely initialized
+ unsigned int initdone:1;
+
+ /// The name of this adapter, e.g. "dvblo_adap0"
+ char name[16];
+ struct
+ {
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,12)
+ /* Since kernel version 2.6.12 the dvb_adapter structure has to be
+ * embedded into our structure
+ */
+ struct dvb_adapter adap;
+
+#define DVBLO_DVB_ADAP(dvblop) (&(dvblop)->dvb.adap)
+#else /* */
+ struct dvb_adapter *adap;
+
+#define DVBLO_DVB_ADAP(dvblop) ((dvblop)->dvb.adap)
+#endif /* */
+ struct dvb_device *ca_dev;
+ struct dmxdev dmxdev;
+ struct dvb_demux demux;
+ struct dvb_net net;
+ struct dvb_frontend frontend;
+
+ /* struct dvb_frontend: tuner_priv was added in 2.6.18 */
+#define FE_PRIV(fep) ((fep)->demodulator_priv)
+
+#define DVBLO_DVB_ADAP_FEPRIV(dvblop) FE_PRIV(&((dvblop)->dvb.frontend))
+ struct dmx_frontend hw_frontend;
+ struct dmx_frontend mem_frontend;
+ } dvb;
+
+ /// count, how many times dvblo_demux_start_feed() has been called
+ int feeding;
+ struct semaphore sem;
+ spinlock_t event_lock;
+ wait_queue_head_t event_queue;
+ unsigned int event;
+ struct dvblo_adap_statistics stats;
+ struct
+ {
+ struct dvb_frontend_parameters params;
+ struct
+ {
+ struct dvb_frontend_parameters params;
+ u32 status;
+ } tuner;
+ dvblo_sec_t sec;
+ dvblo_festatus_t status;
+ } fe;
+
+ struct dvb_ringbuffer ci_rbuffer;
+ struct dvb_ringbuffer ci_wbuffer;
+ dvblo_cacaps_t ca;
+
+ dvblo_private_t private;
+};
+
+/**
+ * Adapter configuration paramters
+ */
+struct dvblo_adap_config
+{
+
+ /// Whether a MAC address is specified by this structure
+ unsigned int mac_valid:1;
+
+ /// The MAC address of the DVB adapter (if mac_valid == 1)
+ u8 mac[6];
+};
+
+/**
+ * Creates a new virtual DVB adapter
+ * @param adapnum The desired adapter number (set to -1 for automatic assignment)
+ * @param cfg Adapter configuration (may be NULL)
+ * @param dvblo_out A pointer to the newly allocated DVB adapter context is
+ * returned via this parameter
+ */
+int dvblo_adap_create (int adapnum, struct dvblo_adap_config *cfg, struct dvblo **dvblo_out);
+
+/**
+ * Destroys a virtual DVB adapter
+ */
+int dvblo_adap_destroy (struct dvblo *dvblo);
+
+/**
+ * Deliver TS packets to the virtual DVB adapter
+ * @param dvblo The dvblo adapter context
+ * @param buf Pointer to buffer containing TS packets
+ * @param len Length of buf in bytes
+ */
+ssize_t dvblo_adap_deliver_packets (struct dvblo *dvblo, const u8 * buf, size_t len);
+
+/**
+ * Handle event bitpattern without race conditions
+ */
+unsigned int dvblo_set_event (struct dvblo *dvblo, unsigned int event);
+
+/**
+ * Get list of currently active PIDs from DVB adapter
+ */
+int dvblog_adap_get_pids (struct dvblo *dvblo, dvblo_pids_t * pids_out);
+
+/**
+ * Get MAC address of virtual DVB adapter
+ */
+int dvblo_adap_get_mac (struct dvblo *dvblo, u8 * mac_out);
+
+#endif /* _DVBLO_ADAP_H_ */
diff --git a/mcast/dvbloop/dvblo_adap_ca.h b/mcast/dvbloop/dvblo_adap_ca.h
new file mode 100644
index 0000000..192fa60
--- /dev/null
+++ b/mcast/dvbloop/dvblo_adap_ca.h
@@ -0,0 +1,43 @@
+/* dvbloop - A DVB Loopback Device
+ * Copyright (C) 2006 Christian Praehauser, Deti Flieg
+ -----------------------------------------
+ * File: dvblo_adap.c
+ * Desc: Support for virtual DVB adapters - Frontend implementation
+ * Date: October 2006
+ * Author: Christian Praehauser <cpreahaus@cosy.sbg.ac.at>, Deti Fliegl <deti@fliegl.de>
+ *
+ * This file is released under the GPLv2.
+ */
+
+#ifndef _DVBLO_ADAP_CA_H_
+#define _DVBLO_ADAP_CA_H_
+
+#include "dvb-core/dvbdev.h"
+#include "dvb-core/dvb_demux.h"
+#include "dvb-core/dmxdev.h"
+#include "dvb-core/dvb_net.h"
+#include "dvb-core/dvb_frontend.h"
+#include "dvb-core/dvb_ringbuffer.h"
+#include "linux/dvb/ca.h"
+
+void ci_get_data(struct dvb_ringbuffer *cibuf, u8 *data, int len);
+
+/**
+ * Register new ca device
+ */
+int dvblo_ca_register(struct dvblo *dvblo);
+/**
+ * Unregister ca device
+ */
+void dvblo_ca_unregister(struct dvblo *dvblo);
+/**
+ * Initialize ca device
+ */
+int dvblo_ca_init(struct dvblo* dvblo);
+/**
+ * Uninitialize ca device
+ */
+void dvblo_ca_exit(struct dvblo* dvblo);
+
+
+#endif /* _DVBLO_ADAP_FE_H_ */
diff --git a/mcast/dvbloop/dvblo_adap_fe.h b/mcast/dvbloop/dvblo_adap_fe.h
new file mode 100644
index 0000000..fcdef0d
--- /dev/null
+++ b/mcast/dvbloop/dvblo_adap_fe.h
@@ -0,0 +1,30 @@
+/* dvbloop - A DVB Loopback Device
+ * Copyright (C) 2006 Christian Praehauser, Deti Flieg
+ -----------------------------------------
+ * File: dvblo_adap.c
+ * Desc: Support for virtual DVB adapters - Frontend implementation
+ * Date: October 2006
+ * Author: Christian Praehauser <cpreahaus@cosy.sbg.ac.at>, Deti Fliegl <deti@fliegl.de>
+ *
+ * This file is released under the GPLv2.
+ */
+
+#ifndef _DVBLO_ADAP_FE_H_
+#define _DVBLO_ADAP_FE_H_
+
+#include "dvb-core/dvbdev.h"
+#include "dvb-core/dvb_demux.h"
+#include "dvb-core/dmxdev.h"
+#include "dvb-core/dvb_net.h"
+#include "dvb-core/dvb_frontend.h"
+extern struct dvb_frontend_ops dvblo_adap_fe_ops;
+int dvblo_fe_get_info (struct dvblo *dvblo, struct dvb_frontend_info *info);
+int dvblo_fe_set_info (struct dvblo *dvblo, struct dvb_frontend_info *info);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,18)
+int dvblo_fe_get_tunerinfo (struct dvblo *dvblo, struct dvb_tuner_info *tunerinfo);
+int dvblo_fe_set_tunerinfo (struct dvblo *dvblo, struct dvb_tuner_info *tunerinfo);
+
+#endif /* */
+
+#endif /* _DVBLO_ADAP_FE_H_ */
diff --git a/mcast/dvbloop/dvblo_char.h b/mcast/dvbloop/dvblo_char.h
new file mode 100644
index 0000000..41f5744
--- /dev/null
+++ b/mcast/dvbloop/dvblo_char.h
@@ -0,0 +1,33 @@
+/* dvbloop - A DVB Loopback Device
+ * Copyright (C) 2006 Christian Praehauser, Deti Fliegl
+ -----------------------------------------
+ * File: dvblo_char.h
+ * Desc: Char device support for dvblo
+ * Date: October 2006
+ * Author: Christian Praehauser <cpreahaus@cosy.sbg.ac.at>, Deti Fliegl <deti@fliegl.de>
+ *
+ * This file is released under the GPLv2.
+ */
+
+#ifndef _DVBLO_CHAR_H_
+#define _DVBLO_CHAR_H_
+
+#include "dvblo.h"
+#include "dvblo_adap.h"
+
+/**
+ * Maximum number of devices
+ */
+#define DVBLO_CHAR_DEVMAX 8
+struct dvblo_chardev_config
+{
+
+ /// The configuration for the corresponding virtual DVB adapter
+ struct dvblo_adap_config dvbcfg;
+};
+int dvblo_char_init (void);
+int dvblo_char_exit (void);
+int dvblo_char_add_dev (struct dvblo_chardev_config *cfg, unsigned int *devnum_out);
+int dvblo_char_del_dev (unsigned int devnum);
+
+#endif /* _DVBLO_CHAR_H_ */
diff --git a/mcast/dvbloop/dvblo_ioctl.h b/mcast/dvbloop/dvblo_ioctl.h
new file mode 100644
index 0000000..08e737c
--- /dev/null
+++ b/mcast/dvbloop/dvblo_ioctl.h
@@ -0,0 +1,203 @@
+/* dvbloop - A DVB Loopback Device
+ * Copyright (C) 2006 Christian Praehauser, Deti Fliegl
+ -----------------------------------------
+ * File: dvblo_char.h
+ * Desc: Char device support for dvblo
+ * Date: October 2006
+ * Author: Christian Praehauser <cpreahaus@cosy.sbg.ac.at>, Deti Fliegl <deti@fliegl.de>
+ *
+ * This file is released under the GPLv2.
+ */
+
+#ifndef _DVBLO_IOCTL_H_
+#define _DVBLO_IOCTL_H_
+
+#ifndef WIN32
+#include <linux/ioctl.h>
+#endif
+/**
+ * Maximum number of devices
+ */
+#define DVBLO_IOC_MAGIC 'd'
+#define PRIV_DATA_SIZE 4096
+typedef struct
+{
+ u_int16_t pid[256];
+ int num;
+} dvblo_pids_t;
+typedef struct dvblo_sec
+{
+ struct dvb_diseqc_master_cmd diseqc_cmd;
+ fe_sec_mini_cmd_t mini_cmd;
+ fe_sec_tone_mode_t tone_mode;
+ fe_sec_voltage_t voltage;
+} dvblo_sec_t;
+typedef struct dvblo_festatus
+{
+ fe_status_t st;
+ u_int32_t ber;
+ u_int16_t strength;
+ u_int16_t snr;
+ u_int32_t ucblocks;
+} dvblo_festatus_t;
+typedef unsigned char dvblo_private_t[PRIV_DATA_SIZE];
+
+#define CA_MAX_SLOTS 16
+typedef struct {
+ ca_caps_t cap;
+ ca_slot_info_t info[CA_MAX_SLOTS];
+} dvblo_cacaps_t;
+
+#define CA_TPDU_MAX 2048
+typedef struct {
+ u_int16_t len;
+ u_int8_t data[CA_TPDU_MAX];
+} dvblo_tpdu_t;
+
+#define EV_MASK_FE 0x0000000f
+#define EV_MASK_PID 0x000000f0
+#define EV_MASK_SEC 0x00000f00
+#define EV_MASK_PRIV 0x0000f000
+#define EV_MASK_CA 0x000f0000
+
+#define EV_FRONTEND 0x00000001
+#define EV_TUNER 0x00000002
+#define EV_FREQUENCY 0x00000004
+#define EV_BANDWIDTH 0x00000008
+
+#define EV_PIDFILTER 0x00000010
+
+#define EV_TONE 0x00000100
+#define EV_VOLTAGE 0x00000200
+#define EV_DISEC_MSG 0x00000400
+#define EV_DISEC_BURST 0x00000800
+
+#define EV_PRIV_READ 0x00001000
+#define EV_PRIV_WRITE 0x00002000
+
+#define EV_CA_RESET 0x00010000
+#define EV_CA_WRITE 0x00020000
+#define EV_CA_PID 0x00040000
+#define EV_CA_DESCR 0x00080000
+
+struct dvblo_ioc_dev
+{
+
+ /// The MAC address of the virtual DVB adapter
+ u_int8_t mac[6];
+
+ /**
+ * This is set to the number of the new device when ioctl(DVBLO_IOCADDDEV)
+ * was successful.
+ * @note This corresponds to the minor device number.
+ */
+ int num;
+};
+
+/**
+ * @brief Add a new DVBLoop adapter device
+ */
+#define DVBLO_IOCADDDEV _IO(DVBLO_IOC_MAGIC, 1)
+/**
+ * @brief Remove the DVBLoop adapter device with the specified number
+ */
+#define DVBLO_IOCDELDEV _IO(DVBLO_IOC_MAGIC, 2)
+/**
+ * @brief Check if DVBLoop adapter has a corresponding dvb device
+ */
+#define DVBLO_IOCCHECKDEV _IO(DVBLO_IOC_MAGIC, 30)
+/**
+ * @brief Get event mask
+ */
+#define DVBLO_GET_EVENT_MASK _IOR(DVBLO_IOC_MAGIC, 3, unsigned int)
+/**
+ * @brief Get FE parameters
+ */
+#define DVBLO_GET_FRONTEND_PARAMETERS _IOR(DVBLO_IOC_MAGIC, 4, struct dvb_frontend_parameters)
+/**
+ * @brief Set FE parameters
+ */
+#define DVBLO_SET_FRONTEND_PARAMETERS _IOW(DVBLO_IOC_MAGIC, 4, struct dvb_frontend_parameters)
+/**
+ * @brief Get tuner parameters
+ */
+#define DVBLO_GET_TUNER_PARAMETERS _IOR(DVBLO_IOC_MAGIC, 5, struct dvb_frontend_parameters)
+/**
+ * @brief Set tuner parameters
+ */
+#define DVBLO_SET_TUNER_PARAMETERS _IOW(DVBLO_IOC_MAGIC, 5, struct dvb_frontend_parameters)
+/**
+ * @brief Get SEC parameters
+ */
+#define DVBLO_GET_SEC_PARAMETERS _IOR(DVBLO_IOC_MAGIC, 6, struct dvblo_sec)
+/**
+ * @brief Get SEC parameters
+ */
+#define DVBLO_SET_SEC_PARAMETERS _IOW(DVBLO_IOC_MAGIC, 6, struct dvblo_sec)
+/**
+ * @brief Set FE-Status parameters
+ */
+#define DVBLO_GET_FRONTEND_STATUS _IOR(DVBLO_IOC_MAGIC, 7, struct dvblo_festatus)
+/**
+ * @brief Set Tuner-Status parameters
+ */
+#define DVBLO_SET_FRONTEND_STATUS _IOW(DVBLO_IOC_MAGIC, 7, struct dvblo_festatus)
+/**
+ * @brief Get Tuner-Status parameters
+ */
+#define DVBLO_GET_TUNER_STATUS _IOR(DVBLO_IOC_MAGIC, 8, u_int32_t)
+/**
+ * @brief Set Tuner-Status parameters
+ */
+#define DVBLO_SET_TUNER_STATUS _IOW(DVBLO_IOC_MAGIC, 8, u_int32_t)
+/**
+ * @brief Set FE-Info
+ */
+#define DVBLO_GET_FRONTEND_INFO _IOR(DVBLO_IOC_MAGIC, 9, struct dvb_frontend_info)
+/**
+ * @brief Set FE-Info
+ */
+#define DVBLO_SET_FRONTEND_INFO _IOW(DVBLO_IOC_MAGIC, 9, struct dvb_frontend_info)
+
+#ifndef WIN32
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,18)
+/**
+ * @brief Set Tuner-Info
+ */
+#define DVBLO_GET_TUNER_INFO _IOR(DVBLO_IOC_MAGIC, 10, struct dvb_tuner_info)
+/**
+ * @brief Set Tuner-Info
+ */
+#define DVBLO_SET_TUNER_INFO _IOW(DVBLO_IOC_MAGIC, 10, struct dvb_tuner_info)
+#endif /* */
+/**
+ * @brief Get list of PIDS
+ */
+#define DVBLO_GET_PIDLIST _IOR(DVBLO_IOC_MAGIC, 20, dvblo_pids_t)
+/**
+ * @brief Pass through of private data
+ */
+#define DVBLO_GET_PRIVATE _IOR(DVBLO_IOC_MAGIC, 40, dvblo_private_t)
+/**
+ * @brief Pass through of private data
+ */
+#define DVBLO_SET_PRIVATE _IOW(DVBLO_IOC_MAGIC, 40, dvblo_private_t)
+/**
+ * @brief Get CA_CAPS including slot_info
+ */
+#define DVBLO_GET_CA_CAPS _IOR(DVBLO_IOC_MAGIC, 80, dvblo_cacaps_t)
+/**
+ * @brief Set CA_CAPS including slot_info
+ */
+#define DVBLO_SET_CA_CAPS _IOW(DVBLO_IOC_MAGIC, 80, dvblo_cacaps_t)
+/**
+ * @brief Get TPDU
+ */
+#define DVBLO_GET_TPDU _IOR(DVBLO_IOC_MAGIC, 81, dvblo_tpdu_t)
+/**
+ * @brief Send TPDU
+ */
+#define DVBLO_SET_TPDU _IOW(DVBLO_IOC_MAGIC, 81, dvblo_tpdu_t)
+
+#endif /* _DVBLO_IOCTL_H_ */
+#endif
diff --git a/mcast/dvbloop/dvblo_util.h b/mcast/dvbloop/dvblo_util.h
new file mode 100644
index 0000000..e86bfa6
--- /dev/null
+++ b/mcast/dvbloop/dvblo_util.h
@@ -0,0 +1,45 @@
+/* dvbloop - A DVB Loopback Device
+ * Copyright (C) 2006 Christian Praehauser, Deti Fliegl
+ -----------------------------------------
+ * File: dvblo_char.h
+ * Desc: Char device support for dvblo
+ * Date: October 2006
+ * Author: Christian Praehauser <cpreahaus@cosy.sbg.ac.at>, Deti Fliegl <deti@fliegl.de>
+ *
+ * This file is released under the GPLv2.
+ */
+
+#ifndef _DVBLO_UTIL_H_
+#define _DVBLO_UTIL_H_
+
+#include <linux/types.h>
+int dvblo_parse_mac (const char *macstr, u8 * mac_out);
+
+#if 0
+/**
+ * Ring buffer implementation
+ * @todo maybe use kfifo which is provided by Linux kernels >= 2.6.10
+ */
+struct dvblo_ringbuf
+{
+ u8 *buf;
+ size_t size;
+ unsigned int wr;
+ unsigned int rd;
+};
+typedef struct dvblo_ringbuf dvblo_ringbuf_t;
+static inline int dvblo_rb_alloc (size_t size, dvblo_ringbuf_t * rb_out)
+{
+ rb_out->buf = kmalloc (size, GFP_KERNEL);
+ if (rb_out->buf == NULL)
+ return -ENOMEM;
+
+ else {
+ rb_out->size = size;
+ rb_out->in = rb_out->out = 0;
+ }
+ return 0;
+}
+static inline ssize_t dvblo_rb_write (dvblo_ringbuf_t * rb_out,
+#endif /* */
+#endif /* _DVBLO_UTIL_H_ */
diff --git a/mcast/tool/.svn/entries b/mcast/tool/.svn/entries
new file mode 100644
index 0000000..ecfbfc1
--- /dev/null
+++ b/mcast/tool/.svn/entries
@@ -0,0 +1,232 @@
+10
+
+dir
+18963
+svn://reelbox.org/testing/src/vdr-plugins/src/mcli-1/mcast/tool
+svn://reelbox.org
+
+
+
+2011-08-18T10:09:14.813360Z
+17158
+dirk
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+12be777f-adf9-0310-842f-e37ecc4c7426
+
+Makefile
+file
+
+
+
+
+2012-09-27T17:22:49.646848Z
+5d30b5398eb2c233a1bd77b484d9de30
+2011-08-18T10:09:14.813360Z
+17158
+dirk
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+3056
+
+netcvlogview.c
+file
+
+
+
+
+2012-09-27T17:22:49.646848Z
+6d046be96a3c706912b56105f3b0d085
+2011-08-18T10:09:14.813360Z
+17158
+dirk
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+5324
+
+tools.c
+file
+
+
+
+
+2012-09-27T17:22:49.646848Z
+c0906e8f658e6d84d4e12dca1e3ffc57
+2011-07-12T13:36:23.313379Z
+16905
+rollercoaster
+has-props
+
+
+svn:special
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+17
+
+netcvupdate.c
+file
+
+
+
+
+2012-09-27T17:22:49.646848Z
+4e59ba021a9f0008be90832c0a093d2d
+2011-07-12T13:36:23.313379Z
+16905
+rollercoaster
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+19278
+
+netcvdiag.c
+file
+
+
+
+
+2012-09-27T17:22:49.646848Z
+f5245b3c34a379143d0d6f070aa0e908
+2011-08-18T10:09:14.813360Z
+17158
+dirk
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+13267
+
+mcast.c
+file
+
+
+
+
+2012-09-27T17:22:49.646848Z
+b6c289caaedfc9f9a24d597c72a5d8ce
+2011-07-12T13:36:23.313379Z
+16905
+rollercoaster
+has-props
+
+
+svn:special
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+17
+
diff --git a/mcast/tool/.svn/prop-base/mcast.c.svn-base b/mcast/tool/.svn/prop-base/mcast.c.svn-base
new file mode 100644
index 0000000..d222469
--- /dev/null
+++ b/mcast/tool/.svn/prop-base/mcast.c.svn-base
@@ -0,0 +1,5 @@
+K 11
+svn:special
+V 1
+*
+END
diff --git a/mcast/tool/.svn/prop-base/tools.c.svn-base b/mcast/tool/.svn/prop-base/tools.c.svn-base
new file mode 100644
index 0000000..d222469
--- /dev/null
+++ b/mcast/tool/.svn/prop-base/tools.c.svn-base
@@ -0,0 +1,5 @@
+K 11
+svn:special
+V 1
+*
+END
diff --git a/mcast/tool/.svn/text-base/Makefile.svn-base b/mcast/tool/.svn/text-base/Makefile.svn-base
new file mode 100644
index 0000000..3cee3dc
--- /dev/null
+++ b/mcast/tool/.svn/text-base/Makefile.svn-base
@@ -0,0 +1,137 @@
+#Comment this out to disable debugging output
+#DEBUG = 1
+#API_SOCK=1
+
+ifdef RBMINI
+ ARMEL=1
+endif
+
+APPLE_DARWIN = $(shell gcc -dumpmachine | grep -q 'apple-darwin' && echo "1" || echo "0")
+CYGWIN = $(shell gcc -dumpmachine | grep -q 'cygwin' && echo "1" || echo "0")
+
+DEFINES = -DCLIENT -D_REENTRANT -D_GNU_SOURCE
+
+ifeq ($(CYGWIN), 1)
+WIN32=1
+else
+API_SOCK=1
+endif
+
+ifeq ($(APPLE_DARWIN), 1)
+INCLUDES += -I../common/darwin/include/
+DEFINES += -DAPPLE
+APPLE=1
+endif
+
+VDRDIR=../../../../..
+-include $(VDRDIR)/Make.config
+
+ifdef ARMEL
+ XML_INC := -I/usr/arm-linux-gnueabi/include/libxml2
+ XML_LIB := -lxml2
+else
+ XML_INC := `xml2-config --cflags`
+ XML_LIB := `xml2-config --libs`
+ LIBRARY_PATH = /usr/lib
+endif
+
+CFLAGS ?= -Os -Wall
+
+INCLUDES += $(XML_INC) -I../dvbloop -I../common/ -I../client
+
+LDFLAGS:=$(XML_LIB) -lpthread
+
+ifdef API_SHM
+LDFLAGS:= $(LDFLAGS) -lrt
+CFLAGS:= $(CFLAGS) -DAPI_SHM
+endif
+
+ifdef API_SOCK
+CFLAGS:= $(CFLAGS) -DAPI_SOCK
+endif
+
+ifdef DEBUG
+LDFLAGS:= $(LDFLAGS) -g
+CFLAGS:= $(CFLAGS) -g -DDEBUG
+endif
+
+ifdef WIN32
+CFLAGS:= $(CFLAGS) -DWIN32
+endif
+
+
+
+NETCVDIAG = netcvdiag
+NETCVDIAG_OBJS = netcvdiag.o tools.o
+
+NETCVUPDATE = netcvupdate
+NETCVUPDATE_OBJS = netcvupdate.o
+
+NETCVLOGVIEW = netcvlogview
+NETCVLOGVIEW_OBJS = netcvlogview.o mcast.o
+
+OBJS := $(NETCVDIAG_OBJS) $(NETCVUPDATE_OBJS) $(NETCVLOGVIEW_OBJS)
+
+all: $(NETCVDIAG) $(NETCVUPDATE) $(NETCVLOGVIEW)
+
+static: $(NETCVDIAG)-static $(NETCVUPDATE)-static
+
+
+MAKEDEP = $(CXX) -MM -MG
+DEPFILE = .dependencies
+$(DEPFILE): Makefile
+ @$(MAKEDEP) $(DEFINES) $(INCLUDES) $(OBJS:%.o=%.c) > $@
+
+-include $(DEPFILE)
+
+
+$(NETCVDIAG): $(NETCVDIAG_OBJS)
+ $(CC) $(LDFLAGS) -o $@ $(NETCVDIAG_OBJS) $(LDLIBS)
+ifndef DEBUG
+ifndef WIN32
+ strip $(NETCVDIAG)
+endif
+endif
+
+$(NETCVUPDATE): $(NETCVUPDATE_OBJS)
+ $(CC) $(LDFLAGS) -o $@ $(NETCVUPDATE_OBJS) $(LDLIBS)
+ifndef DEBUG
+ifndef WIN32
+ strip $(NETCVUPDATE)
+endif
+endif
+
+$(NETCVLOGVIEW): $(NETCVLOGVIEW_OBJS)
+ $(CC) $(LDFLAGS) -o $@ $(NETCVLOGVIEW_OBJS) $(LDLIBS)
+ifndef DEBUG
+ifndef WIN32
+ strip $(NETCVLOGVIEW)
+endif
+endif
+
+$(NETCVDIAG)-static: $(NETCVDIAG_OBJS)
+ $(CC) $(LDFLAGS) -static -static-libgcc -o $@ $(NETCVDIAG_OBJS) $(LDLIBS) $(LIBRARY_PATH)/libm.a $(LIBRARY_PATH)/libz.a
+ strip $(NETCVDIAG)-static
+
+$(NETCVUPDATE)-static: $(NETCVUPDATE_OBJS)
+ $(CC) $(LDFLAGS) -static -static-libgcc -o $@ $(NETCVUPDATE_OBJS) $(LDLIBS) $(LIBRARY_PATH)/libm.a
+ strip $(NETCVUPDATE)-static
+
+$(NETCVLOGVIEW)-static: $(NETCVLOGVIEW_OBJS)
+ $(CC) $(LDFLAGS) -static -static-libgcc -o $@ $(NETCVLOGVIEW_OBJS) $(LDLIBS) $(LIBRARY_PATH)/libm.a $(LIBRARY_PATH)/libz.a $(LIBRARY_PATH)/libpthread.a
+ strip $(NETCVLOGVIEW)-static
+
+install: $(NETCVDIAG) $(NETCVUPDATE) $(NETCVLOGVIEW)
+ install -p $(NETCVDIAG) /usr/sbin/$(NETCVDIAG)
+ install -p $(NETCVUPDATE) /usr/sbin/$(NETCVUPDATE)
+ install -p $(NETCVLOGVIEW) /usr/sbin/$(NETCVLOGVIEW)
+
+depend: .dependencies
+ #makedepend -Y -- $(CFLAGS) -- *c >/dev/null 2>&1
+
+clean:
+ rm -f $(NETCVDIAG) $(NETCVUPDATE) $(NETCVLOGVIEW) *.elf *.gdb *.o *~
+
+%.o: %.c
+ $(CC) -c $(CFLAGS) $(INCLUDES) $(DEFINES) -o $@ $<
+
diff --git a/mcast/tool/.svn/text-base/mcast.c.svn-base b/mcast/tool/.svn/text-base/mcast.c.svn-base
new file mode 100644
index 0000000..8900452
--- /dev/null
+++ b/mcast/tool/.svn/text-base/mcast.c.svn-base
@@ -0,0 +1 @@
+link ../common/mcast.c \ No newline at end of file
diff --git a/mcast/tool/.svn/text-base/netcvdiag.c.svn-base b/mcast/tool/.svn/text-base/netcvdiag.c.svn-base
new file mode 100644
index 0000000..5b6e490
--- /dev/null
+++ b/mcast/tool/.svn/text-base/netcvdiag.c.svn-base
@@ -0,0 +1,433 @@
+/*------------------------------------------------------------------------
+ * netcvdiag - NetCeiver diagnosis tool
+ *
+ *------------------------------------------------------------------------*/
+
+#include "headers.h"
+
+#ifdef __MINGW32__
+#include <getopt.h>
+#endif
+
+#ifdef API_SOCK
+
+/*------------------------------------------------------------------------*/
+#define API_WAIT_RESPONSE(cmd) { cmd->state=API_REQUEST; \
+ send (sock_comm, &sock_cmd, sizeof(api_cmd_t), 0); \
+ recv (sock_comm, &sock_cmd, sizeof(api_cmd_t), 0); \
+ if (cmd->state == API_ERROR) warn ( "SHM parameter error\n");}
+
+int sock_comm;
+
+int nc_api_init(char *path)
+{
+ int sock_name_len = 0;
+ struct sockaddr_un sock_name;
+ sock_name.sun_family = AF_UNIX;
+
+ strcpy(sock_name.sun_path, path);
+ sock_name_len = sizeof(struct sockaddr_un);
+
+ if((sock_comm = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
+ {
+ warn ("socket create failure %d\n", errno);
+ return -1;
+ }
+
+ if (connect(sock_comm, (struct sockaddr*)&sock_name, sock_name_len) < 0) {
+ warn ("connect failure to %s: %s\n",path, strerror(errno));
+ return -1;
+ }
+ return 0;
+}
+#endif
+#ifdef API_WIN
+/*------------------------------------------------------------------------*/
+#define API_WAIT_RESPONSE(cmd) { cmd->state=API_REQUEST; \
+ WriteFile( hPipe, &sock_cmd, sizeof(api_cmd_t), &cbWritten, NULL); \
+ ReadFile( hPipe, &sock_cmd, sizeof(api_cmd_t), &cbRead, NULL); \
+ if (cmd->state == API_ERROR) {warn ( "SHM parameter error, incompatible versions?\n"); exit(-1);}}
+
+HANDLE hPipe;
+DWORD cbRead, cbWritten;
+
+int nc_api_init(char *path)
+{
+ hPipe = CreateFile(
+ TEXT("\\\\.\\pipe\\mcli"), // pipe name
+ GENERIC_READ | // read and write access
+ GENERIC_WRITE,
+ 0, // no sharing
+ NULL, // default security attributes
+ OPEN_EXISTING, // opens existing pipe
+ 0, // default attributes
+ NULL); // no template file
+
+ if (hPipe == INVALID_HANDLE_VALUE) {
+ warn("CreatePipe failed");
+ return -1;
+ }
+ return 0;
+}
+#endif
+/*------------------------------------------------------------------------*/
+void usage(void)
+{
+ fprintf(stderr,
+ "netcvdiag - NetCeiver diagnosis tool, version " MCLI_VERSION_STR "\n"
+ "(c) BayCom GmbH\n"
+ "Usage: netcvdiag <options>\n"
+ "Options: -a Show all\n"
+ " -u Show UUIDs\n"
+ " -t Show tuners\n"
+ " -c Get NetCeiver count\n"
+ " -S Show satellite settings\n"
+ " -s Show tuner state\n"
+ " -r <n> Repeat every n seconds\n"
+ " -v Show HW/SW-versions\n"
+ " -P <path> Set API socket\n"
+ );
+ exit(0);
+}
+/*------------------------------------------------------------------------*/
+void show_it(int show_count, int show_uuids, int show_tuners, int show_sats, int show_versions, int show_cams)
+{
+ int nc_num;
+ int i;
+ time_t now=time(0);
+ api_cmd_t sock_cmd;
+ api_cmd_t *api_cmd=&sock_cmd;
+
+ api_cmd->cmd=API_GET_NC_NUM;
+ api_cmd->magic = MCLI_MAGIC;
+ api_cmd->version = MCLI_VERSION;
+
+ API_WAIT_RESPONSE(api_cmd);
+ if(api_cmd->magic != MCLI_MAGIC || api_cmd->version != MCLI_VERSION) {
+ info("API version mismatch!\n");
+ return;
+ }
+ if (show_count)
+ printf("Count: %i\n", api_cmd->parm[API_PARM_NC_NUM]);
+ nc_num=api_cmd->parm[API_PARM_NC_NUM];
+
+ for(i=0;i<nc_num;i++) {
+ api_cmd->cmd=API_GET_NC_INFO;
+ api_cmd->parm[API_PARM_NC_NUM]=i;
+ API_WAIT_RESPONSE(api_cmd);
+ if(api_cmd->u.nc_info.magic != MCLI_MAGIC || api_cmd->u.nc_info.version != MCLI_VERSION) {
+ err("API version mismatch!\n");
+ }
+ if (show_uuids||show_versions) {
+ char buf[UUID_SIZE];
+ if(strlen(api_cmd->u.nc_info.Description)) {
+ sprintf(buf, "%s, ", api_cmd->u.nc_info.Description);
+ } else {
+ buf[0]=0;
+ }
+ printf("NetCeiver %i:\n"
+ " UUID <%s>, %s%s, tuners %d\n",
+ i,
+ api_cmd->u.nc_info.uuid,
+ buf,
+ (unsigned int) api_cmd->u.nc_info.lastseen<(now-10)?"DEAD":"ALIVE",
+ api_cmd->u.nc_info.tuner_num);
+ }
+ if (show_versions) {
+ printf(" OS <%s>, App <%s>, FW <%s>, HW <%s>\n",
+ api_cmd->u.nc_info.OSVersion, api_cmd->u.nc_info.AppVersion,
+ api_cmd->u.nc_info.FirmwareVersion, api_cmd->u.nc_info.HardwareVersion
+ );
+ printf(" Serial <%s>, Vendor <%s>, state %i\n",
+ api_cmd->u.nc_info.Serial, api_cmd->u.nc_info.Vendor, api_cmd->u.nc_info.DefCon);
+ printf(" SystemUptime %d, ProcessUptime %d\n",
+ (int)api_cmd->u.nc_info.SystemUptime, (int)api_cmd->u.nc_info.ProcessUptime);
+ printf(" TunerTimeout %d\n",
+ (int)api_cmd->u.nc_info.TunerTimeout);
+ }
+ if (show_cams) {
+ int i;
+ for (i = 0; i < api_cmd->u.nc_info.cam_num; i++) {
+ char *camstate="";
+ char *cammode="";
+
+ switch(api_cmd->u.nc_info.cam[i].status) {
+ case DVBCA_CAMSTATE_MISSING:
+ camstate="MISSING"; break;
+ case DVBCA_CAMSTATE_INITIALISING:
+ camstate="INIT"; break;
+ case DVBCA_CAMSTATE_READY:
+ camstate="READY"; break;
+ }
+ switch(api_cmd->u.nc_info.cam[i].flags) {
+ case CA_SINGLE:
+ cammode="CA_SINGLE";break;
+ case CA_MULTI_SID:
+ cammode="CA_MULTI_SID";break;
+ case CA_MULTI_TRANSPONDER:
+ cammode="CA_MULTI_TRANSPONDER";break;
+ }
+ printf(" CI-Slot %d: State <%s>, Mode <%s>, CAPMT-Flag: %d, SIDs %d/%d, CAM <%s>\n", api_cmd->u.nc_info.cam[i].slot, camstate, cammode, api_cmd->u.nc_info.cam[i].capmt_flag, api_cmd->u.nc_info.cam[i].use_sids, api_cmd->u.nc_info.cam[i].max_sids, api_cmd->u.nc_info.cam[i].menu_string);
+ }
+ }
+ if (show_tuners) {
+ int j;
+ int tuner_num=api_cmd->u.nc_info.tuner_num;
+ for(j=0;j<tuner_num;j++) {
+ api_cmd->cmd=API_GET_TUNER_INFO;
+ api_cmd->parm[API_PARM_TUNER_NUM]=j;
+ API_WAIT_RESPONSE(api_cmd);
+ printf(" Tuner %i: <%s>, SatList: <%s>, Preference %i\n",
+ j,
+ api_cmd->u.tuner_info.fe_info.name,
+ api_cmd->u.tuner_info.SatelliteListName,
+ api_cmd->u.tuner_info.preference
+ );
+ }
+ puts("");
+ }
+
+ if (show_sats) {
+ int sat_list_num=api_cmd->u.nc_info.sat_list_num;
+ int j;
+ for(j=0;j<sat_list_num;j++) {
+ api_cmd->cmd=API_GET_SAT_LIST_INFO;
+ api_cmd->parm[API_PARM_NC_NUM]=i;
+ api_cmd->parm[API_PARM_SAT_LIST_NUM]=j;
+ API_WAIT_RESPONSE(api_cmd);
+ if(api_cmd->u.sat_list.magic != MCLI_MAGIC || api_cmd->u.sat_list.version != MCLI_VERSION) {
+ err("API version mismatch!\n");
+ }
+
+ printf("NetCeiver %i: SatList <%s>, entries %d\n",
+ i,
+ api_cmd->u.sat_list.Name,
+ api_cmd->u.sat_list.sat_num);
+
+ int sat_num=api_cmd->u.sat_list.sat_num;
+ int k;
+ for(k=0;k<sat_num;k++) {
+ api_cmd->cmd=API_GET_SAT_INFO;
+ api_cmd->parm[API_PARM_SAT_LIST_NUM]=j;
+ api_cmd->parm[API_PARM_SAT_NUM]=k;
+ API_WAIT_RESPONSE(api_cmd);
+ int comp_num=api_cmd->u.sat_info.comp_num;
+ float pos=(float)((api_cmd->u.sat_info.SatPos-1800.0)/10.0);
+ float minr=(float)((api_cmd->u.sat_info.SatPosMin-1800.0)/10.0);
+ float maxr=(float)((api_cmd->u.sat_info.SatPosMax-1800.0)/10.0);
+ float af=(float)((api_cmd->u.sat_info.AutoFocus)/10.0);
+ float longitude=(float)((api_cmd->u.sat_info.Longitude)/10.0);
+ float latitude=(float)((api_cmd->u.sat_info.Latitude)/10.0);
+
+ printf(" Satname: <%s>, Position <%.1f%c>, entries %i\n",
+ api_cmd->u.sat_info.Name,
+ fabs(pos),pos<0?'W':'E',
+ comp_num);
+
+ if (api_cmd->u.sat_info.type==SAT_SRC_ROTOR)
+ printf(" Rotor: Range <%.1f%c>-<%.1f%c>, AF <%.1f>, Long <%.1f%c>, Lat <%.1f%c>\n",
+ fabs(minr),minr<0?'W':'E',
+ fabs(maxr),maxr<0?'W':'E',
+ fabs(af),
+ fabs(longitude),longitude<0?'W':'E',
+ fabs(latitude),longitude<0?'S':'N');
+
+ int l;
+ for(l=0;l<comp_num;l++) {
+ api_cmd->cmd=API_GET_SAT_COMP_INFO;
+ api_cmd->parm[API_PARM_SAT_LIST_NUM]=j;
+ api_cmd->parm[API_PARM_SAT_NUM]=k;
+ api_cmd->parm[API_PARM_SAT_COMP_NUM]=l;
+ API_WAIT_RESPONSE(api_cmd);
+ int m=0,n;
+ char diseqc[256];
+ char *ptr=diseqc;
+ struct dvb_diseqc_master_cmd *diseqc_cmd=&api_cmd->u.sat_comp.sec.diseqc_cmd;
+
+ diseqc[0]=0;
+
+ for(n=0;n<api_cmd->u.sat_comp.diseqc_cmd_num;n++) {
+ for(*ptr=0,m=0;m<diseqc_cmd->msg_len;m++) {
+ ptr+=sprintf(ptr, "%02X ", diseqc_cmd->msg[m]);
+ }
+ ptr+=sprintf(ptr, ", ");
+ diseqc_cmd=api_cmd->u.sat_comp.diseqc_cmd+n;
+ }
+ if(m>0) {
+ *(ptr-3)=0;
+ }
+ char *mini="MINI_OFF";
+ switch(api_cmd->u.sat_comp.sec.mini_cmd) {
+ case SEC_MINI_A:mini="MINI_A ";break;
+ case SEC_MINI_B:mini="MINI_B ";break;
+ }
+ printf(" Entry %i: Polarisation %c, Min% 6d, "
+ "Max% 6d, LOF% 6d %s %s %s DiSEqC <%s>\n",
+ l,
+ api_cmd->u.sat_comp.Polarisation?'H':'V',
+ api_cmd->u.sat_comp.RangeMin,
+ api_cmd->u.sat_comp.RangeMax,
+ api_cmd->u.sat_comp.LOF,
+ mini,
+ api_cmd->u.sat_comp.sec.tone_mode==SEC_TONE_ON ?"TONE_ON ":"TONE_OFF",
+ api_cmd->u.sat_comp.sec.voltage==SEC_VOLTAGE_18?"VOLTAGE_18":"VOLTAGE_13",
+ diseqc
+ );
+ }
+ }
+ }
+ }
+ }
+ puts("");
+}
+/*------------------------------------------------------------------------*/
+void show_stats(void)
+{
+ api_cmd_t sock_cmd;
+ api_cmd_t *api_cmd=&sock_cmd;
+ int i;
+ char *types[]={"DVB-S","DVB-C","DVB-T", "?", "DVB-S2"};
+ int type;
+
+ api_cmd->cmd=API_GET_TRA_NUM;
+ api_cmd->magic = MCLI_MAGIC;
+ api_cmd->version = MCLI_VERSION;
+ API_WAIT_RESPONSE(api_cmd);
+
+// printf("tra_num: %d\n", api_cmd->parm[API_PARM_TRA_NUM]);
+ int tra_num=api_cmd->parm[API_PARM_TRA_NUM];
+ for(i=0;i<tra_num;i++) {
+ char uuid[256];
+ char *p;
+
+ api_cmd->cmd=API_GET_TRA_INFO;
+ api_cmd->parm[API_PARM_TRA_NUM]=i;
+ API_WAIT_RESPONSE(api_cmd);
+ char host[INET6_ADDRSTRLEN];
+ inet_ntop (AF_INET6, &api_cmd->u.tra.mcg, (char *) host, INET6_ADDRSTRLEN);
+ type=api_cmd->u.tra.fe_type;
+ if (type<0 || type>4)
+ type=3;
+
+ strncpy(uuid,api_cmd->u.tra.uuid,255);
+ uuid[255]=0;
+ p=strrchr(uuid,':');
+ if (p)
+ *p=0;
+
+ fe_type_t t;
+ recv_sec_t sec;
+ int satpos;
+ struct dvb_frontend_parameters fep;
+
+ if(mcg_to_fe_parms(&api_cmd->u.tra.mcg, &t, &sec, &fep, NULL)<0) {
+ memset(&fep,0,sizeof(struct dvb_frontend_parameters));
+ }
+
+ mcg_get_satpos(&api_cmd->u.tra.mcg, &satpos);
+ float pos=(float)((satpos-1800.0)/10.0);
+ char pos_str[256];
+ if(satpos != 0xfff) {
+ sprintf(pos_str, ", position <%.1f%c>", fabs(pos), pos<0?'W':'E');
+ } else {
+ pos_str[0]=0;
+ }
+
+ printf("UUID <%s>:\n"
+ " slot %s%d.%d, type %s, used: % 3d\n"
+ " %s, frequency %d%s (%.1f%s)%s\n"
+ " strength %04x, snr %04x, ber %04x, unc %04x\n"
+ " NIMCurrent %d\n"
+ " RotorStatus %i, RotorDiff %.1f\n",
+ uuid,
+ (time(0)-api_cmd->u.tra.lastseen)>15?"-":"",
+ api_cmd->u.tra.slot/2,api_cmd->u.tra.slot%2,
+ types[type], api_cmd->u.tra.InUse,
+ api_cmd->u.tra.s.st==0x1f?"LOCK ":"NO LOCK",
+ fep.frequency, (type==1||type==2)?"Hz":"kHz", api_cmd->u.tra.fep.frequency/1000.0,
+ (type==1||type==2)?"kHz":"MHz",pos_str,
+ api_cmd->u.tra.s.strength,
+ api_cmd->u.tra.s.snr, api_cmd->u.tra.s.ber, api_cmd->u.tra.s.ucblocks,
+ api_cmd->u.tra.NIMCurrent,
+ api_cmd->u.tra.rotor_status,
+ api_cmd->u.tra.rotor_diff/10.0
+ );
+
+ }
+}
+/*------------------------------------------------------------------------*/
+int main(int argc, char **argv)
+{
+ int repeat=0;
+ int show_uuids=0,show_tuners=0,show_sats=0,show_state=0,show_cams=0;
+ int show_count=0, show_versions=0;
+#ifdef API_SOCK
+ char path[256]=API_SOCK_NAMESPACE;
+#endif
+#ifdef API_WIN
+ char path[256]="\\\\.\\pipe\\mcli";
+#endif
+ while(1) {
+ int ret = getopt(argc,argv, "aucCtsSvr:P:");
+ if (ret==-1)
+ break;
+
+ char c=(char)ret;
+
+ switch (c) {
+ case 'a':
+ show_uuids=1;
+ show_tuners=1;
+ show_sats=1;
+ show_state=1;
+ show_count=1;
+ show_versions=1;
+ show_cams=1;
+ break;
+ case 'u':
+ show_uuids=1;
+ break;
+ case 'c':
+ show_count=1;
+ break;
+ case 'C':
+ show_cams=1;
+ break;
+ case 't':
+ show_tuners=1;
+ break;
+ case 's':
+ show_state=1;
+ break;
+ case 'r':
+ repeat=abs(atoi(optarg));
+ break;
+ case 'S':
+ show_sats=1;
+ break;
+ case 'v':
+ show_versions=1;
+ break;
+ case 'P':
+ strncpy(path,optarg,255);
+ path[255]=0;
+ break;
+ default:
+ usage();
+ break;
+ }
+ }
+ if (nc_api_init(path)==-1) {
+ exit(-1);
+ }
+
+ do {
+ show_it(show_count, show_uuids, show_tuners, show_sats, show_versions, show_cams);
+ if (show_state)
+ show_stats();
+ sleep(repeat);
+ } while(repeat);
+
+ exit(0);
+}
+
diff --git a/mcast/tool/.svn/text-base/netcvlogview.c.svn-base b/mcast/tool/.svn/text-base/netcvlogview.c.svn-base
new file mode 100644
index 0000000..4d8bc9f
--- /dev/null
+++ b/mcast/tool/.svn/text-base/netcvlogview.c.svn-base
@@ -0,0 +1,206 @@
+#include "headers.h"
+
+#ifdef __MINGW32__
+#include <getopt.h>
+extern void bzero(void *s, size_t n);
+#endif
+
+#define HDR_CHK_PACKET_LENGTH 1424
+#define HDR_CHK_LENGTH 16
+
+static int quit=0;
+
+void sighandler(int sig) {
+ quit=1;
+}
+
+int main (int argc, char **argv)
+{
+ UDPContext *s;
+ unsigned char buf[UDP_TX_BUF_SIZE];
+ memset (buf, 0x55, sizeof (buf));
+ int ret, len, i, mode = 1, mcg_num = 1, port = 23000, c, needhelp = 0, wait = 0, file = 0, loop = 0, header = 0, lost = 0;
+ char mcg[10][1024];
+ char *ifname = NULL;
+ strcpy (mcg[0], "ff18:5100::");
+
+ do {
+ ret = getopt_long (argc, argv, "hrtp:g:xi:w:flH", NULL, NULL);
+ if(ret<0) {
+ break;
+ }
+ c=(char)ret;
+ switch (c) {
+ case 'i':
+ ifname = optarg;
+ break;
+ case 'f':
+ file = 1;
+ break;
+ case 'r':
+ mode = 1;
+ break;
+ case 't':
+ mode = 2;
+ break;
+ case 'x':
+ mode = 3;
+ break;
+ case 'H':
+ header = 1;
+ break;
+ case 'l':
+ loop = 1;
+ break;
+ case 'p':
+ port = atoi (optarg);
+ break;
+ case 'w':
+ wait = atoi (optarg);
+ break;
+ case 'g':
+ for (mcg_num = 0, optind--; optind < argc; optind++, mcg_num++) {
+ if (argv[optind][0] != '-') {
+ strcpy (mcg[mcg_num], argv[optind]);
+ } else {
+ break;
+ }
+ }
+ break;
+ case 'h':
+ needhelp = 1;
+ break;
+ }
+ }
+ while (c >= 0);
+
+ if (needhelp) {
+ fprintf (stderr, "usage: netcvlogview -i <network interface> <-r|-t> -g <multicast groups> -p <port> -w <seconds timeout> -H\n");
+ return -1;
+ }
+
+ fprintf (stderr, "mode:%d port:%d mcg:%d [ ", mode, port, mcg_num);
+ for (i = 0; i < mcg_num; i++) {
+ fprintf (stderr, "%s ", mcg[i]);
+ }
+ fprintf (stderr, "]\n");
+
+#ifdef __MINGW32__
+ recv_init (ifname, port);
+#endif
+
+ switch (mode) {
+
+ case 1:
+ s = client_udp_open_host (mcg[0], port, ifname);
+ if (s) {
+ struct sockaddr_in6 addr;
+ addr.sin6_family = AF_INET6;
+ addr.sin6_port = htons (port);
+
+ for (i = 1; i < mcg_num; i++) {
+ fprintf (stderr, "mcg: [%s]\n", mcg[i]);
+ inet_pton (AF_INET6, mcg[i], &addr.sin6_addr);
+ if (udp_ipv6_join_multicast_group (s->udp_fd, s->idx, (struct sockaddr *) &addr) < 0) {
+ err ("Cannot join multicast group !\n");
+ }
+
+ }
+ signal(SIGTERM, sighandler);
+ signal(SIGINT, sighandler);
+
+ FILE *f;
+ time_t first;
+ time_t last;
+ int hc, i;
+ do {
+ first=last=hc=lost=0;
+ if(file) {
+ f=fopen("rawfile.temp", "wb");
+ if(f==NULL) {
+ perror("Cannot open file for writing\n");
+ return -1;
+ }
+ } else {
+ f=stdout;
+ }
+ while (!quit &&(!wait || !last || ((time(NULL)-last) < wait))) {
+ len = udp_read (s, buf, sizeof (buf), 50, NULL);
+ if(len>0) {
+ if(header) {
+ if(len!=HDR_CHK_PACKET_LENGTH) {
+ fprintf(stderr, "Expected header length mismatch %d != %d!\n", len, HDR_CHK_PACKET_LENGTH);
+ }
+ uint32_t *cnt=(uint32_t *)buf;
+ int hv=ntohl(*cnt);
+ if(hv == hc) {
+ fwrite (buf+HDR_CHK_LENGTH, len-HDR_CHK_LENGTH, 1, f);
+ hc++;
+ } else {
+ bzero(buf, HDR_CHK_PACKET_LENGTH);
+ for(i=hc; i<hv; i++) {
+ fwrite(buf, HDR_CHK_PACKET_LENGTH-HDR_CHK_LENGTH, 1, f);
+ }
+ lost+=(hv-hc);
+ hc=i;
+ }
+ } else {
+ fwrite (buf, len, 1, f);
+ }
+ last=time(NULL);
+ if(!first) {
+ first=last;
+ }
+ }
+ }
+ fclose(f);
+ if(file) {
+ if(quit) {
+ unlink("rawfile.temp");
+ } else {
+ struct tm *now=localtime(&first);
+ char fname[80];
+ sprintf(fname, "%04d%02d%02d-%02d%02d%02d.raw", now->tm_year+1900, now->tm_mon+1, now->tm_mday, now->tm_hour, now->tm_min, now->tm_sec);
+ rename("rawfile.temp", fname);
+ fprintf(stderr, "[%s] New log file: %s (%u packets)\n",ifname, fname, hc);
+ if(lost) {
+ fprintf(stderr, "Warning: Lost %d frames of %d payload bytes, now filled with padding bytes (0)\n", lost, HDR_CHK_PACKET_LENGTH-HDR_CHK_LENGTH);
+ }
+ }
+ }
+ } while(loop && ! quit);
+ udp_close (s);
+ }
+ break;
+
+ case 2:
+ s = server_udp_open_host (mcg[0], port, ifname);
+ if (s) {
+ while (1) {
+ if(!fread (buf, 1316, 1, stdin)) {
+ break;
+ }
+ udp_write (s, buf, 1316);
+ }
+ udp_close (s);
+ }
+ break;
+
+ case 3:
+ s = server_udp_open_host (mcg[0], port, ifname);
+ if (s) {
+ int i;
+ for (i = 0; i < sizeof (buf); i++) {
+ buf[i] = rand ();
+ }
+ while (1) {
+ i = rand ();
+ udp_write (s, buf, ((i % 4) + 4) * 188);
+ }
+ udp_close (s);
+ }
+ break;
+ }
+
+ return 0;
+}
diff --git a/mcast/tool/.svn/text-base/netcvupdate.c.svn-base b/mcast/tool/.svn/text-base/netcvupdate.c.svn-base
new file mode 100644
index 0000000..e311470
--- /dev/null
+++ b/mcast/tool/.svn/text-base/netcvupdate.c.svn-base
@@ -0,0 +1,773 @@
+/*------------------------------------------------------------------------
+ * netcvupdate - NetCeiver update tool
+ *
+ * Principle for firmware update
+ * - Unpack given .tgz into host /tmp/mkdtemp()
+ * - "md5sum -c md5sums.txt"
+ * - read script file update.scr
+ * - feed commands into tnftp
+ *
+ *
+ *------------------------------------------------------------------------*/
+#define USE_MCLI_API
+
+#ifdef USE_MCLI_API
+#include "headers.h"
+#else
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <signal.h>
+#include <ctype.h>
+#endif
+
+#define STATE_FILE "update.log"
+#define FTP_CMD "ftp"
+#define NC_CONFPATH "/mmc/etc/"
+#define NC_CONFFILE "netceiver.conf"
+
+char ftp_cmd[512]=FTP_CMD;
+int verbose=0;
+int no_reboot=0;
+char username[256]="root";
+char password[256]="root";
+char device[256]="eth0";
+char *uuids[256]={0};
+char *versions[256]={0};
+int num_uuids=0;
+char socket_path[256]=API_SOCK_NAMESPACE;
+
+#ifdef USE_MCLI_API
+/*------------------------------------------------------------------------*/
+#define API_WAIT_RESPONSE(cmd) { cmd->state=API_REQUEST; \
+ send (sock_comm, &sock_cmd, sizeof(api_cmd_t), 0); \
+ recv (sock_comm, &sock_cmd, sizeof(api_cmd_t), 0); \
+ if (cmd->state == API_ERROR) {warn ( "SHM parameter error, incompatible versions?\n"); exit(-1);}}
+
+int sock_comm;
+
+int api_init(char *path)
+{
+ int sock_name_len = 0;
+ struct sockaddr_un sock_name;
+ sock_name.sun_family = AF_UNIX;
+
+ strcpy(sock_name.sun_path, path);
+ sock_name_len = sizeof(struct sockaddr_un);
+
+ if((sock_comm = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
+ {
+ warn ("socket create failure %d\n", errno);
+ return -1;
+ }
+
+ if (connect(sock_comm, (struct sockaddr*)&sock_name, sock_name_len) < 0) {
+ warn ("connect failure to %s: %s (are you root?)\n",path, strerror(errno));
+ return -1;
+ }
+ return 0;
+}
+#endif
+/*------------------------------------------------------------------------*/
+void add_upload(char* cmd, char* localfile, char *remotepath, char *remotefile)
+{
+ char tmp[1024];
+ sprintf(tmp,
+ "cd %s\n"
+ "site exec rm -f /tmp/update/%s\n"
+ "put %s\n",
+ remotepath, remotefile, localfile);
+ strcat(cmd,tmp);
+}
+/*------------------------------------------------------------------------*/
+void add_download(char* cmd, char *remotepath, char *remotefile)
+{
+ char tmp[1024];
+ sprintf(tmp,
+ "cd %s\n"
+ "get %s\n",
+ remotepath,remotefile);
+ strcat(cmd,tmp);
+}
+/*------------------------------------------------------------------------*/
+int script_interpreter(char *script, char *line,
+ char *ip, char *iface, char *user, char *pwd)
+{
+ char cmd[256],p1[256],p2[256];
+ int end=0;
+
+ *cmd=0;
+ *p1=0;
+ *p2=0;
+ sscanf(line,"%s %s %s\n",cmd,p1,p2);
+
+ if (cmd[0]=='#')
+ return 0;
+ if (!strcmp(cmd,"connect")) {
+ char tmp[1024];
+ sprintf(tmp,
+ "open %s%%%s\n"
+ "user %s %s\n",
+ ip,iface,user,pwd);
+ strcat(script,tmp);
+ }
+ else if (!strcmp(cmd,"upload")) {
+ add_upload(script,p2,p1,p2);
+ }
+ else if (!strcmp(cmd,"download")) {
+ add_download(script,p1,p2);
+ }
+ else if (!strcmp(cmd,"exit")) {
+ strcat(script,"quit\n");
+ end=1;
+ }
+ else {
+ strcat(script,line);
+ }
+ return end;
+}
+/*------------------------------------------------------------------------*/
+char script[128*1024];
+int generate_script(char *filename, char *tmpname, char *ip, char *iface, char *user, char *pwd)
+{
+ FILE *f;
+ f=fopen(filename,"r");
+ if (!f) {
+ fprintf(stderr,"Can't open script file <%s>: %s\n",filename,strerror(errno));
+ return -1;
+ }
+ script[0]=0;
+
+ while(!feof(f)) {
+ char line[256];
+ fgets(line,255,f);
+ if (script_interpreter(script,line,ip,iface,user,pwd))
+ break;
+ }
+ fclose(f);
+ return 0;
+}
+/*------------------------------------------------------------------------*/
+int check_state_file(char *tmpname)
+{
+ char cmd[512];
+ int ret;
+ printf("\nUPDATE RESULT:\n");
+ snprintf(cmd,512,"cat %s/update.log",tmpname);
+ ret=system(cmd);
+ printf("\n");
+ return ret;
+}
+/*------------------------------------------------------------------------*/
+void sigground(int x)
+{
+}
+/*------------------------------------------------------------------------*/
+int run_ftp(char *tmpdir,char *script, int timeout, char *pipeout)
+{
+ FILE *f;
+ char cmd[512];
+ int ret;
+ if (!strlen(ftp_cmd))
+ return -1;
+ signal(SIGPIPE,sigground);
+ if (strlen(tmpdir))
+// snprintf(cmd,511,"cd %s; %s -q %i -n %s",tmpdir,ftp_cmd,timeout,verbose?"":"-V");
+ snprintf(cmd,511,"cd %s; %s -n %s %s",tmpdir,ftp_cmd,verbose?"":"-V",pipeout);
+ else
+ snprintf(cmd,511,"%s -q %i -n %s %s",ftp_cmd,timeout,verbose?"":"-V",pipeout);
+
+ f=popen(cmd,"w");
+ if (!f)
+ return -1;
+ fputs(script,f);
+ ret=pclose(f);
+ return ret;
+}
+/*------------------------------------------------------------------------*/
+int do_reboot(char *tmpdir, char *ip, char* iface, char *user, char* pwd)
+{
+ sprintf(script,
+ "open %s%%%s\n"
+ "user %s %s\n"
+ "site exec reboot -d 5\n"
+ "quit\n"
+ ,
+ ip,iface,user,pwd);
+ return run_ftp(tmpdir, script, 15,"");
+}
+/*------------------------------------------------------------------------*/
+
+int do_list_fw(char *tmpdir, char *ip, char* iface, char *user, char* pwd, int maxf, int *found, char **versions)
+{
+ char tmpfile[256]="/tmp/ncvup.XXXXXX";
+ char pipeout[256];
+ int n=0;
+ int ret=0;
+ FILE *file;
+
+ *found=0;
+
+ if (!mkstemp(tmpfile)) {
+ fprintf(stderr,"Can't make temporary directory %s!\n",tmpfile);
+ return -2;
+ }
+
+ sprintf(script,
+ "open %s%%%s\n"
+ "user %s %s\n"
+ "ls /mmc/\n"
+ "quit\n"
+ ,
+ ip,iface,user,pwd);
+ sprintf(pipeout," > %s",tmpfile);
+ ret=run_ftp(tmpdir, script, 15, pipeout);
+ if (ret) {
+ unlink(tmpfile);
+ return ret;
+ }
+
+ file=fopen(tmpfile,"r");
+ if (!file) {
+ unlink(tmpfile); // ?
+ perror("Can't read temp file");
+ return ret;
+ }
+
+ while(!feof(file)) {
+ char line[1024];
+ char *p;
+ *line=0;
+ fgets(line, 1023,file);
+ line[1023]=0;
+ p=strstr(line,"etceivr.");
+ if (p) {
+
+ char *pp=strchr(p,'\n');
+ if (pp)
+ *pp=0;
+
+ if (n < maxf) {
+ n++;
+ *versions++=strdup(p-1);
+ }
+ }
+ }
+ *found=n;
+ fclose(file);
+ unlink(tmpfile);
+ return 0;
+}
+/*------------------------------------------------------------------------*/
+int do_kill(char *tmpdir, char *ip, char* iface, char *user, char* pwd)
+{
+ sprintf(script,
+ "open %s%%%s\n"
+ "user %s %s\n"
+ "site exec killall -9 mserv\n"
+ "quit\n"
+ ,
+ ip,iface,user,pwd);
+ return run_ftp(tmpdir, script, 15,"");
+}
+/*------------------------------------------------------------------------*/
+int do_single_update(char *tmpdir, char *uuid, char *device)
+{
+ char path[256];
+ int ret;
+
+ snprintf(path,255,"%s/%s",tmpdir,"update.scr");
+ if (generate_script(path, tmpdir, uuid, device, username, password))
+ return -1;
+// puts(script);
+
+ printf("Upload update... ");
+ fflush(stdout);
+
+ ret=run_ftp(tmpdir, script, 600,"");
+ if (ret)
+ return ret;
+
+ printf("check result... \n");
+ fflush(stdout);
+
+ if (check_state_file(tmpdir))
+ return -1;
+
+#if 1
+ if (!no_reboot) {
+ printf("Issue Reboot... ");
+ fflush(stdout);
+ ret=do_reboot(tmpdir, uuid, device, username, password);
+ if (!ret)
+ return ret;
+ }
+#endif
+ return 0;
+}
+/*------------------------------------------------------------------------*/
+int do_single_upload( char *uuid, char *device, char *remote_path, char *fname, char *remote_file)
+{
+ int ret;
+ sprintf(script,
+ "open %s%%%s\n"
+ "user %s %s\n"
+ "cd %s\n"
+ "put %s %s\n"
+// "site exec killall -HUP mserv\n"
+ "quit",
+ uuid,device,username,password,remote_path,fname,remote_file);
+ ret=run_ftp("", script, 120,"");
+ return ret;
+}
+/*------------------------------------------------------------------------*/
+int do_single_download( char *uuid, char *device, char *remote_path, char *fname)
+{
+ int ret;
+ sprintf(script,
+ "open %s%%%s\n"
+ "user %s %s\n"
+ "cd %s\n"
+ "get %s\n"
+ "quit",
+ uuid,device,username,password,remote_path,fname);
+ ret=run_ftp("", script, 120,"");
+ return ret;
+}
+/*------------------------------------------------------------------------*/
+int fw_action(char *uuid, char* iface, char *user, char* pwd, int mode, char *version)
+{
+ int ret;
+ if (mode==0) { // inactivate
+ printf("Inactivating version %s\n",version);
+ sprintf(script,
+ "open %s%%%s\n"
+ "user %s %s\n"
+ "cd /mmc\n"
+ "rename netceivr.%s xetceivr.%s\n"
+ "quit",
+ uuid,device,username,password,version,version);
+ ret=run_ftp("", script, 120,"");
+ return ret;
+ }
+ else if (mode==1) { // enable
+ printf("Enabling version %s\n",version);
+ sprintf(script,
+ "open %s%%%s\n"
+ "user %s %s\n"
+ "cd /mmc\n"
+ "rename xetceivr.%s netceivr.%s\n"
+ "quit",
+ uuid,device,username,password,version,version);
+ ret=run_ftp("", script, 120,"");
+ return ret;
+ }
+ else if (mode==2) { // delete
+ printf("Removing version %s\n",version);
+ sprintf(script,
+ "open %s%%%s\n"
+ "user %s %s\n"
+ "site exec rm -rf /mmc/netceivr.%s\n"
+ "site exec rm -rf /mmc/xetceivr.%s\n"
+ "quit",
+ uuid,device,username,password,version,version);
+ ret=run_ftp("", script, 120,"");
+ return ret;
+ }
+ return 0;
+}
+/*------------------------------------------------------------------------*/
+int cleanup(char *tmpdir)
+{
+ int ret;
+ char cmd[1024];
+ snprintf(cmd,1024,"rm -rf '%s'",tmpdir);
+// puts(cmd);
+ ret=system(cmd);
+ return ret;
+}
+/*------------------------------------------------------------------------*/
+int unpack(char *tmpdir, char *file)
+{
+ int ret;
+ char cmd[1024];
+ snprintf(cmd,1024,"tar xfz '%s' --directory %s",file,tmpdir);
+// puts(cmd);
+ ret=system(cmd);
+ return ret;
+}
+/*------------------------------------------------------------------------*/
+int check_xml(char *file)
+{
+ int ret;
+ char cmd[1024];
+ snprintf(cmd,1024,"xmllint --noout '%s'\n",file);
+// puts(cmd);
+ ret=system(cmd);
+ return ret;
+}
+/*------------------------------------------------------------------------*/
+int check_integrity(char *tmpdir)
+{
+ int ret;
+ char cmd[1024];
+ snprintf(cmd,1024,"cd %s; md5sum -c --status md5sums.txt \n",tmpdir);
+// puts(cmd);
+ ret=system(cmd);
+ return ret;
+}
+/*------------------------------------------------------------------------*/
+int do_update(char **uuids, int num_uuids, char *device, char *optarg)
+{
+ char tmpdir[256]="/tmp/ncvupXXXXXX";
+ int n;
+ int ret=0;
+ if (!mkdtemp(tmpdir)) {
+ fprintf(stderr,"Can't make temporary directory %s!\n",tmpdir);
+ return -2;
+ }
+// printf("TEMP DIR %s\n",tmpdir);
+ if (unpack(tmpdir,optarg)) {
+ fprintf(stderr,"Update file <%s> cannot be unpacked!\n",optarg);
+ cleanup(tmpdir);
+ return -2;
+ }
+ if (check_integrity(tmpdir)) {
+ fprintf(stderr,"Update file <%s> corrupted!\n",optarg);
+ cleanup(tmpdir);
+ return -2;
+ }
+ printf("Update file integrity OK\n");
+ printf("NUM uuids %i\n",num_uuids);
+ for(n=0;n<num_uuids;n++) {
+ if (!uuids[n])
+ continue;
+
+ printf("UUID %s: ",uuids[n]);
+ fflush(stdout);
+ ret=do_single_update(tmpdir, uuids[n], device);
+ if (!ret)
+ printf("-> Update done <-\n");
+ else {
+ printf("-> Update failed (ret=%i) <-\n",ret);
+ uuids[n]=NULL;
+ }
+ }
+
+ cleanup(tmpdir);
+ return ret;
+}
+/*------------------------------------------------------------------------*/
+int do_upload(char **uuids, int num_uuids, char *device, char *optarg)
+{
+ int n;
+ int ret=0;
+ if (check_xml(optarg)) {
+ fprintf(stderr,"Configuration file <%s> not valid XML\n",optarg);
+ return -2;
+ }
+ for(n=0;n<num_uuids;n++) {
+ if (!uuids[n])
+ continue;
+
+ printf("UUID %s: Uploading %s ... ",uuids[n], optarg);
+ fflush(stdout);
+ ret=do_single_upload(uuids[n], device, "/mmc/etc/", optarg, NC_CONFFILE);
+ if (!ret)
+ printf("Upload done\n");
+ else {
+ printf("Upload failed (ret=%i)\n",ret);
+ uuids[n]=NULL;
+ }
+ }
+ return ret;
+}
+/*------------------------------------------------------------------------*/
+int do_download(char **uuids, int num_uuids, char *device, char *remotepath, char *file)
+{
+ int n,ret=0;
+
+ for(n=0;n<num_uuids;n++) {
+ char newfile[1024];
+ if (!uuids[n])
+ continue;
+
+ if (num_uuids!=1)
+ snprintf(newfile,1024,"%s-%s",file,uuids[n]);
+ else
+ strncpy(newfile,file,1024);
+
+ printf("UUID %s: Downloading %s ... ",uuids[n], newfile);
+ fflush(stdout);
+ ret=do_single_download(uuids[n], device, remotepath, file);
+ if (!ret) {
+ printf("Done\n");
+ if (num_uuids!=1)
+ rename(file,newfile);
+ }
+ else {
+ printf("Download failed (ret=%i)\n",ret);
+ uuids[n]=NULL;
+ }
+ }
+ return ret;
+}
+/*------------------------------------------------------------------------*/
+int do_all_reboot(char **uuids, int num_uuids, char *device)
+{
+ int n,ret=0;
+
+ for(n=0;n<num_uuids;n++) {
+ if (!uuids[n])
+ continue;
+ printf("UUID %s: Issue Reboot... ",uuids[n]);
+ fflush(stdout);
+ ret=do_reboot("/tmp", uuids[n], device, username, password);
+ if (!ret)
+ printf("Reboot done\n");
+ else
+ printf("Reboot failed (ret=%i)\n",ret);
+ }
+ return ret;
+}
+/*------------------------------------------------------------------------*/
+int do_all_kill(char **uuids, int num_uuids, char *device)
+{
+ int n,ret=0;
+
+ for(n=0;n<num_uuids;n++) {
+ if (!uuids[n])
+ continue;
+ printf("UUID %s: Issue Kill... ",uuids[n]);
+ fflush(stdout);
+ ret=do_kill("/tmp", uuids[n], device, username, password);
+ if (!ret)
+ printf("Kill done\n");
+ else
+ printf("Kill failed (ret=%i)\n",ret);
+ }
+ return ret;
+}
+/*------------------------------------------------------------------------*/
+int get_uuids(char **uuids, int max)
+{
+ int count,n;
+ api_cmd_t sock_cmd;
+ api_cmd_t *api_cmd=&sock_cmd;
+
+ if (api_init(socket_path)==-1) {
+ exit(-1);
+ }
+ api_cmd->cmd=API_GET_NC_NUM;
+ api_cmd->magic = MCLI_MAGIC;
+ api_cmd->version = MCLI_VERSION;
+ API_WAIT_RESPONSE(api_cmd);
+ if(api_cmd->magic != MCLI_MAGIC || api_cmd->version != MCLI_VERSION) {
+ err("API version mismatch!\n");
+ }
+ count=api_cmd->parm[API_PARM_NC_NUM];
+
+ for(n=0;n<max && n<count;n++) {
+ api_cmd->cmd=API_GET_NC_INFO;
+ api_cmd->parm[API_PARM_NC_NUM]=n;
+ API_WAIT_RESPONSE(api_cmd);
+ if(api_cmd->u.nc_info.magic != MCLI_MAGIC || api_cmd->u.nc_info.version != MCLI_VERSION) {
+ err("API version mismatch!\n");
+ }
+
+ uuids[n]=strdup(api_cmd->u.nc_info.uuid);
+ versions[n]=strdup(api_cmd->u.nc_info.FirmwareVersion);
+ }
+ return count;
+}
+/*------------------------------------------------------------------------*/
+int show_uuids(void)
+{
+ char *uuids[256]={0};
+ int num_uuids,n;
+ num_uuids=get_uuids(uuids,256);
+ for(n=0;n<num_uuids;n++) {
+ printf("%s %s\n",uuids[n],versions[n]);
+ }
+ return 0;
+}
+/*------------------------------------------------------------------------*/
+#define MAX_FWS 64
+void show_firmwares(char *uuid, char *device, char *username, char *passwd)
+{
+ char *fwversions[MAX_FWS];
+ int found,m;
+ found=0;
+
+ do_list_fw("/tmp", uuid, device, username, password, MAX_FWS, &found, fwversions);
+
+ printf("Firmware versions found: %i\n Versions: ", found);
+ for(m=0;m<found;m++) {
+ if (m!=0) printf(", ");
+ if (fwversions[m][0]!='n')
+ printf("%s (disabled)",fwversions[m]+9);
+ else
+ printf("%s",fwversions[m]+9);
+
+ free(versions[m]);
+ }
+ puts("");
+}
+/*------------------------------------------------------------------------*/
+
+int show_all_firmwares(char **uuids, int num_uuids)
+{
+ int n;
+
+ for(n=0;n<num_uuids;n++) {
+ printf("%s: ",uuids[n]);
+ fflush(stdout);
+ show_firmwares(uuids[n],device,username,password);
+ }
+ return 0;
+}
+/*------------------------------------------------------------------------*/
+void do_fw_actions(char **uuids, int max, int mode, char *version)
+{
+ int n;
+
+ if (strlen(version)!=3 || !strcmp(version,"000")) {
+ fprintf(stderr,"Invalid version number\n");
+ return;
+ }
+
+ for(n=0;n<3;n++)
+ version[n]=toupper(version[n]);
+
+ for(n=0;n<max;n++) {
+ printf("UUID %s\n",uuids[n]);
+ if (fw_action(uuids[n], device, username, password, mode, version)) {
+ fprintf(stderr,"Failed\n");
+ return;
+ }
+ show_firmwares(uuids[n],device,username,password);
+ }
+}
+/*------------------------------------------------------------------------*/
+void usage(void)
+{
+ fprintf(stderr,
+ "netcvupdate - NetCeiver update tool, version " MCLI_VERSION_STR "\n"
+ "(c) BayCom GmbH\n"
+ "Usage: netcvupdate <options> <actions> \n"
+ "Actions: \n"
+ " -l List all seen NetCeivers and their UUID\n"
+ " -L List available FWs\n"
+ " -X <Update.tgz> Update with given file\n"
+ " -U <configfile> Upload configfile\n"
+ " -D Download configfile netceiver.conf\n"
+ " -I <version> Inactivate FW version\n"
+ " -E <version> Enable FW version\n"
+ " -Z <version> Remove FW version\n"
+ " -K Restart streaming server\n"
+ " -R Issue reboot\n"
+ "Options:\n"
+ " -A Use all found NetCeivers (mcli must be running)\n"
+ " -i <uuid> Use specific UUID (can be used multiple times)\n"
+ " *** Either -A or -i must be given for most actions! ***\n"
+ "Rare options:\n"
+ " -d <device> Set network device (default: eth0)\n"
+ " -F <ftp-command> Set ftp command/path\n"
+ " *** ftp command must understand the -q (timeout) option! ***\n"
+ " -P <path> Set API socket\n"
+ " -u <user> Set username\n"
+ " -p <password> Set password\n"
+ " -r No reboot after update\n"
+ " -q Be more quiet\n"
+ );
+ exit(0);
+}
+/*------------------------------------------------------------------------*/
+int main(int argc, char **argv)
+{
+ int ret=0;
+
+ while(1) {
+ int ret = getopt(argc,argv, "U:X:Di:AlLI:E:Z:d:F:P:u:p:rRqK");
+ if (ret==-1)
+ break;
+
+ char c=(char)ret;
+
+ switch(c) {
+ case 'F':
+ strncpy(ftp_cmd,optarg,512);
+ ftp_cmd[511]=0;
+ break;
+ case 'X':
+ ret=do_update(uuids, num_uuids, device, optarg);
+ if (ret==-2)
+ exit(ret);
+ break;
+ case 'U':
+ ret=do_upload(uuids, num_uuids, device, optarg);
+ if (ret==-2)
+ exit(ret);
+ break;
+ case 'D':
+ ret|=do_download(uuids, num_uuids, device, NC_CONFPATH, NC_CONFFILE);
+ break;
+ case 'i':
+ uuids[num_uuids]=strdup(optarg);
+ num_uuids++;
+ break;
+ case 'A':
+ num_uuids=get_uuids(uuids,255);
+ break;
+ case 'l':
+ show_uuids();
+ break;
+ case 'd':
+ strncpy(device,optarg,255);
+ device[255]=0;
+ break;
+ case 'P':
+ strncpy(socket_path,optarg,255);
+ socket_path[255]=0;
+ break;
+ case 'p':
+ strncpy(password,optarg,255);
+ password[255]=0;
+ break;
+ case 'u':
+ strncpy(username,optarg,255);
+ username[255]=0;
+ break;
+ case 'r':
+ no_reboot=1;
+ break;
+ case 'K':
+ ret|=do_all_kill(uuids,num_uuids,device);
+ break;
+ case 'R':
+ ret|=do_all_reboot(uuids, num_uuids, device);
+ break;
+ case 'L':
+ show_all_firmwares(uuids, num_uuids);
+ break;
+ case 'I':
+ do_fw_actions(uuids, num_uuids, 0, optarg);
+ break;
+ case 'E':
+ do_fw_actions(uuids, num_uuids, 1, optarg);
+ break;
+ case 'Z':
+ do_fw_actions(uuids, num_uuids, 2, optarg);
+ break;
+ case 'q':
+ verbose=0;
+ break;
+ default:
+ usage();
+ break;
+ }
+ }
+ exit(ret);
+}
diff --git a/mcast/tool/.svn/text-base/tools.c.svn-base b/mcast/tool/.svn/text-base/tools.c.svn-base
new file mode 100644
index 0000000..d249f01
--- /dev/null
+++ b/mcast/tool/.svn/text-base/tools.c.svn-base
@@ -0,0 +1 @@
+link ../common/tools.c \ No newline at end of file
diff --git a/mcast/tool/Makefile b/mcast/tool/Makefile
new file mode 100644
index 0000000..3cee3dc
--- /dev/null
+++ b/mcast/tool/Makefile
@@ -0,0 +1,137 @@
+#Comment this out to disable debugging output
+#DEBUG = 1
+#API_SOCK=1
+
+ifdef RBMINI
+ ARMEL=1
+endif
+
+APPLE_DARWIN = $(shell gcc -dumpmachine | grep -q 'apple-darwin' && echo "1" || echo "0")
+CYGWIN = $(shell gcc -dumpmachine | grep -q 'cygwin' && echo "1" || echo "0")
+
+DEFINES = -DCLIENT -D_REENTRANT -D_GNU_SOURCE
+
+ifeq ($(CYGWIN), 1)
+WIN32=1
+else
+API_SOCK=1
+endif
+
+ifeq ($(APPLE_DARWIN), 1)
+INCLUDES += -I../common/darwin/include/
+DEFINES += -DAPPLE
+APPLE=1
+endif
+
+VDRDIR=../../../../..
+-include $(VDRDIR)/Make.config
+
+ifdef ARMEL
+ XML_INC := -I/usr/arm-linux-gnueabi/include/libxml2
+ XML_LIB := -lxml2
+else
+ XML_INC := `xml2-config --cflags`
+ XML_LIB := `xml2-config --libs`
+ LIBRARY_PATH = /usr/lib
+endif
+
+CFLAGS ?= -Os -Wall
+
+INCLUDES += $(XML_INC) -I../dvbloop -I../common/ -I../client
+
+LDFLAGS:=$(XML_LIB) -lpthread
+
+ifdef API_SHM
+LDFLAGS:= $(LDFLAGS) -lrt
+CFLAGS:= $(CFLAGS) -DAPI_SHM
+endif
+
+ifdef API_SOCK
+CFLAGS:= $(CFLAGS) -DAPI_SOCK
+endif
+
+ifdef DEBUG
+LDFLAGS:= $(LDFLAGS) -g
+CFLAGS:= $(CFLAGS) -g -DDEBUG
+endif
+
+ifdef WIN32
+CFLAGS:= $(CFLAGS) -DWIN32
+endif
+
+
+
+NETCVDIAG = netcvdiag
+NETCVDIAG_OBJS = netcvdiag.o tools.o
+
+NETCVUPDATE = netcvupdate
+NETCVUPDATE_OBJS = netcvupdate.o
+
+NETCVLOGVIEW = netcvlogview
+NETCVLOGVIEW_OBJS = netcvlogview.o mcast.o
+
+OBJS := $(NETCVDIAG_OBJS) $(NETCVUPDATE_OBJS) $(NETCVLOGVIEW_OBJS)
+
+all: $(NETCVDIAG) $(NETCVUPDATE) $(NETCVLOGVIEW)
+
+static: $(NETCVDIAG)-static $(NETCVUPDATE)-static
+
+
+MAKEDEP = $(CXX) -MM -MG
+DEPFILE = .dependencies
+$(DEPFILE): Makefile
+ @$(MAKEDEP) $(DEFINES) $(INCLUDES) $(OBJS:%.o=%.c) > $@
+
+-include $(DEPFILE)
+
+
+$(NETCVDIAG): $(NETCVDIAG_OBJS)
+ $(CC) $(LDFLAGS) -o $@ $(NETCVDIAG_OBJS) $(LDLIBS)
+ifndef DEBUG
+ifndef WIN32
+ strip $(NETCVDIAG)
+endif
+endif
+
+$(NETCVUPDATE): $(NETCVUPDATE_OBJS)
+ $(CC) $(LDFLAGS) -o $@ $(NETCVUPDATE_OBJS) $(LDLIBS)
+ifndef DEBUG
+ifndef WIN32
+ strip $(NETCVUPDATE)
+endif
+endif
+
+$(NETCVLOGVIEW): $(NETCVLOGVIEW_OBJS)
+ $(CC) $(LDFLAGS) -o $@ $(NETCVLOGVIEW_OBJS) $(LDLIBS)
+ifndef DEBUG
+ifndef WIN32
+ strip $(NETCVLOGVIEW)
+endif
+endif
+
+$(NETCVDIAG)-static: $(NETCVDIAG_OBJS)
+ $(CC) $(LDFLAGS) -static -static-libgcc -o $@ $(NETCVDIAG_OBJS) $(LDLIBS) $(LIBRARY_PATH)/libm.a $(LIBRARY_PATH)/libz.a
+ strip $(NETCVDIAG)-static
+
+$(NETCVUPDATE)-static: $(NETCVUPDATE_OBJS)
+ $(CC) $(LDFLAGS) -static -static-libgcc -o $@ $(NETCVUPDATE_OBJS) $(LDLIBS) $(LIBRARY_PATH)/libm.a
+ strip $(NETCVUPDATE)-static
+
+$(NETCVLOGVIEW)-static: $(NETCVLOGVIEW_OBJS)
+ $(CC) $(LDFLAGS) -static -static-libgcc -o $@ $(NETCVLOGVIEW_OBJS) $(LDLIBS) $(LIBRARY_PATH)/libm.a $(LIBRARY_PATH)/libz.a $(LIBRARY_PATH)/libpthread.a
+ strip $(NETCVLOGVIEW)-static
+
+install: $(NETCVDIAG) $(NETCVUPDATE) $(NETCVLOGVIEW)
+ install -p $(NETCVDIAG) /usr/sbin/$(NETCVDIAG)
+ install -p $(NETCVUPDATE) /usr/sbin/$(NETCVUPDATE)
+ install -p $(NETCVLOGVIEW) /usr/sbin/$(NETCVLOGVIEW)
+
+depend: .dependencies
+ #makedepend -Y -- $(CFLAGS) -- *c >/dev/null 2>&1
+
+clean:
+ rm -f $(NETCVDIAG) $(NETCVUPDATE) $(NETCVLOGVIEW) *.elf *.gdb *.o *~
+
+%.o: %.c
+ $(CC) -c $(CFLAGS) $(INCLUDES) $(DEFINES) -o $@ $<
+
diff --git a/mcast/tool/mcast.c b/mcast/tool/mcast.c
new file mode 120000
index 0000000..b2f4f7b
--- /dev/null
+++ b/mcast/tool/mcast.c
@@ -0,0 +1 @@
+../common/mcast.c \ No newline at end of file
diff --git a/mcast/tool/netcvdiag.c b/mcast/tool/netcvdiag.c
new file mode 100644
index 0000000..5b6e490
--- /dev/null
+++ b/mcast/tool/netcvdiag.c
@@ -0,0 +1,433 @@
+/*------------------------------------------------------------------------
+ * netcvdiag - NetCeiver diagnosis tool
+ *
+ *------------------------------------------------------------------------*/
+
+#include "headers.h"
+
+#ifdef __MINGW32__
+#include <getopt.h>
+#endif
+
+#ifdef API_SOCK
+
+/*------------------------------------------------------------------------*/
+#define API_WAIT_RESPONSE(cmd) { cmd->state=API_REQUEST; \
+ send (sock_comm, &sock_cmd, sizeof(api_cmd_t), 0); \
+ recv (sock_comm, &sock_cmd, sizeof(api_cmd_t), 0); \
+ if (cmd->state == API_ERROR) warn ( "SHM parameter error\n");}
+
+int sock_comm;
+
+int nc_api_init(char *path)
+{
+ int sock_name_len = 0;
+ struct sockaddr_un sock_name;
+ sock_name.sun_family = AF_UNIX;
+
+ strcpy(sock_name.sun_path, path);
+ sock_name_len = sizeof(struct sockaddr_un);
+
+ if((sock_comm = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
+ {
+ warn ("socket create failure %d\n", errno);
+ return -1;
+ }
+
+ if (connect(sock_comm, (struct sockaddr*)&sock_name, sock_name_len) < 0) {
+ warn ("connect failure to %s: %s\n",path, strerror(errno));
+ return -1;
+ }
+ return 0;
+}
+#endif
+#ifdef API_WIN
+/*------------------------------------------------------------------------*/
+#define API_WAIT_RESPONSE(cmd) { cmd->state=API_REQUEST; \
+ WriteFile( hPipe, &sock_cmd, sizeof(api_cmd_t), &cbWritten, NULL); \
+ ReadFile( hPipe, &sock_cmd, sizeof(api_cmd_t), &cbRead, NULL); \
+ if (cmd->state == API_ERROR) {warn ( "SHM parameter error, incompatible versions?\n"); exit(-1);}}
+
+HANDLE hPipe;
+DWORD cbRead, cbWritten;
+
+int nc_api_init(char *path)
+{
+ hPipe = CreateFile(
+ TEXT("\\\\.\\pipe\\mcli"), // pipe name
+ GENERIC_READ | // read and write access
+ GENERIC_WRITE,
+ 0, // no sharing
+ NULL, // default security attributes
+ OPEN_EXISTING, // opens existing pipe
+ 0, // default attributes
+ NULL); // no template file
+
+ if (hPipe == INVALID_HANDLE_VALUE) {
+ warn("CreatePipe failed");
+ return -1;
+ }
+ return 0;
+}
+#endif
+/*------------------------------------------------------------------------*/
+void usage(void)
+{
+ fprintf(stderr,
+ "netcvdiag - NetCeiver diagnosis tool, version " MCLI_VERSION_STR "\n"
+ "(c) BayCom GmbH\n"
+ "Usage: netcvdiag <options>\n"
+ "Options: -a Show all\n"
+ " -u Show UUIDs\n"
+ " -t Show tuners\n"
+ " -c Get NetCeiver count\n"
+ " -S Show satellite settings\n"
+ " -s Show tuner state\n"
+ " -r <n> Repeat every n seconds\n"
+ " -v Show HW/SW-versions\n"
+ " -P <path> Set API socket\n"
+ );
+ exit(0);
+}
+/*------------------------------------------------------------------------*/
+void show_it(int show_count, int show_uuids, int show_tuners, int show_sats, int show_versions, int show_cams)
+{
+ int nc_num;
+ int i;
+ time_t now=time(0);
+ api_cmd_t sock_cmd;
+ api_cmd_t *api_cmd=&sock_cmd;
+
+ api_cmd->cmd=API_GET_NC_NUM;
+ api_cmd->magic = MCLI_MAGIC;
+ api_cmd->version = MCLI_VERSION;
+
+ API_WAIT_RESPONSE(api_cmd);
+ if(api_cmd->magic != MCLI_MAGIC || api_cmd->version != MCLI_VERSION) {
+ info("API version mismatch!\n");
+ return;
+ }
+ if (show_count)
+ printf("Count: %i\n", api_cmd->parm[API_PARM_NC_NUM]);
+ nc_num=api_cmd->parm[API_PARM_NC_NUM];
+
+ for(i=0;i<nc_num;i++) {
+ api_cmd->cmd=API_GET_NC_INFO;
+ api_cmd->parm[API_PARM_NC_NUM]=i;
+ API_WAIT_RESPONSE(api_cmd);
+ if(api_cmd->u.nc_info.magic != MCLI_MAGIC || api_cmd->u.nc_info.version != MCLI_VERSION) {
+ err("API version mismatch!\n");
+ }
+ if (show_uuids||show_versions) {
+ char buf[UUID_SIZE];
+ if(strlen(api_cmd->u.nc_info.Description)) {
+ sprintf(buf, "%s, ", api_cmd->u.nc_info.Description);
+ } else {
+ buf[0]=0;
+ }
+ printf("NetCeiver %i:\n"
+ " UUID <%s>, %s%s, tuners %d\n",
+ i,
+ api_cmd->u.nc_info.uuid,
+ buf,
+ (unsigned int) api_cmd->u.nc_info.lastseen<(now-10)?"DEAD":"ALIVE",
+ api_cmd->u.nc_info.tuner_num);
+ }
+ if (show_versions) {
+ printf(" OS <%s>, App <%s>, FW <%s>, HW <%s>\n",
+ api_cmd->u.nc_info.OSVersion, api_cmd->u.nc_info.AppVersion,
+ api_cmd->u.nc_info.FirmwareVersion, api_cmd->u.nc_info.HardwareVersion
+ );
+ printf(" Serial <%s>, Vendor <%s>, state %i\n",
+ api_cmd->u.nc_info.Serial, api_cmd->u.nc_info.Vendor, api_cmd->u.nc_info.DefCon);
+ printf(" SystemUptime %d, ProcessUptime %d\n",
+ (int)api_cmd->u.nc_info.SystemUptime, (int)api_cmd->u.nc_info.ProcessUptime);
+ printf(" TunerTimeout %d\n",
+ (int)api_cmd->u.nc_info.TunerTimeout);
+ }
+ if (show_cams) {
+ int i;
+ for (i = 0; i < api_cmd->u.nc_info.cam_num; i++) {
+ char *camstate="";
+ char *cammode="";
+
+ switch(api_cmd->u.nc_info.cam[i].status) {
+ case DVBCA_CAMSTATE_MISSING:
+ camstate="MISSING"; break;
+ case DVBCA_CAMSTATE_INITIALISING:
+ camstate="INIT"; break;
+ case DVBCA_CAMSTATE_READY:
+ camstate="READY"; break;
+ }
+ switch(api_cmd->u.nc_info.cam[i].flags) {
+ case CA_SINGLE:
+ cammode="CA_SINGLE";break;
+ case CA_MULTI_SID:
+ cammode="CA_MULTI_SID";break;
+ case CA_MULTI_TRANSPONDER:
+ cammode="CA_MULTI_TRANSPONDER";break;
+ }
+ printf(" CI-Slot %d: State <%s>, Mode <%s>, CAPMT-Flag: %d, SIDs %d/%d, CAM <%s>\n", api_cmd->u.nc_info.cam[i].slot, camstate, cammode, api_cmd->u.nc_info.cam[i].capmt_flag, api_cmd->u.nc_info.cam[i].use_sids, api_cmd->u.nc_info.cam[i].max_sids, api_cmd->u.nc_info.cam[i].menu_string);
+ }
+ }
+ if (show_tuners) {
+ int j;
+ int tuner_num=api_cmd->u.nc_info.tuner_num;
+ for(j=0;j<tuner_num;j++) {
+ api_cmd->cmd=API_GET_TUNER_INFO;
+ api_cmd->parm[API_PARM_TUNER_NUM]=j;
+ API_WAIT_RESPONSE(api_cmd);
+ printf(" Tuner %i: <%s>, SatList: <%s>, Preference %i\n",
+ j,
+ api_cmd->u.tuner_info.fe_info.name,
+ api_cmd->u.tuner_info.SatelliteListName,
+ api_cmd->u.tuner_info.preference
+ );
+ }
+ puts("");
+ }
+
+ if (show_sats) {
+ int sat_list_num=api_cmd->u.nc_info.sat_list_num;
+ int j;
+ for(j=0;j<sat_list_num;j++) {
+ api_cmd->cmd=API_GET_SAT_LIST_INFO;
+ api_cmd->parm[API_PARM_NC_NUM]=i;
+ api_cmd->parm[API_PARM_SAT_LIST_NUM]=j;
+ API_WAIT_RESPONSE(api_cmd);
+ if(api_cmd->u.sat_list.magic != MCLI_MAGIC || api_cmd->u.sat_list.version != MCLI_VERSION) {
+ err("API version mismatch!\n");
+ }
+
+ printf("NetCeiver %i: SatList <%s>, entries %d\n",
+ i,
+ api_cmd->u.sat_list.Name,
+ api_cmd->u.sat_list.sat_num);
+
+ int sat_num=api_cmd->u.sat_list.sat_num;
+ int k;
+ for(k=0;k<sat_num;k++) {
+ api_cmd->cmd=API_GET_SAT_INFO;
+ api_cmd->parm[API_PARM_SAT_LIST_NUM]=j;
+ api_cmd->parm[API_PARM_SAT_NUM]=k;
+ API_WAIT_RESPONSE(api_cmd);
+ int comp_num=api_cmd->u.sat_info.comp_num;
+ float pos=(float)((api_cmd->u.sat_info.SatPos-1800.0)/10.0);
+ float minr=(float)((api_cmd->u.sat_info.SatPosMin-1800.0)/10.0);
+ float maxr=(float)((api_cmd->u.sat_info.SatPosMax-1800.0)/10.0);
+ float af=(float)((api_cmd->u.sat_info.AutoFocus)/10.0);
+ float longitude=(float)((api_cmd->u.sat_info.Longitude)/10.0);
+ float latitude=(float)((api_cmd->u.sat_info.Latitude)/10.0);
+
+ printf(" Satname: <%s>, Position <%.1f%c>, entries %i\n",
+ api_cmd->u.sat_info.Name,
+ fabs(pos),pos<0?'W':'E',
+ comp_num);
+
+ if (api_cmd->u.sat_info.type==SAT_SRC_ROTOR)
+ printf(" Rotor: Range <%.1f%c>-<%.1f%c>, AF <%.1f>, Long <%.1f%c>, Lat <%.1f%c>\n",
+ fabs(minr),minr<0?'W':'E',
+ fabs(maxr),maxr<0?'W':'E',
+ fabs(af),
+ fabs(longitude),longitude<0?'W':'E',
+ fabs(latitude),longitude<0?'S':'N');
+
+ int l;
+ for(l=0;l<comp_num;l++) {
+ api_cmd->cmd=API_GET_SAT_COMP_INFO;
+ api_cmd->parm[API_PARM_SAT_LIST_NUM]=j;
+ api_cmd->parm[API_PARM_SAT_NUM]=k;
+ api_cmd->parm[API_PARM_SAT_COMP_NUM]=l;
+ API_WAIT_RESPONSE(api_cmd);
+ int m=0,n;
+ char diseqc[256];
+ char *ptr=diseqc;
+ struct dvb_diseqc_master_cmd *diseqc_cmd=&api_cmd->u.sat_comp.sec.diseqc_cmd;
+
+ diseqc[0]=0;
+
+ for(n=0;n<api_cmd->u.sat_comp.diseqc_cmd_num;n++) {
+ for(*ptr=0,m=0;m<diseqc_cmd->msg_len;m++) {
+ ptr+=sprintf(ptr, "%02X ", diseqc_cmd->msg[m]);
+ }
+ ptr+=sprintf(ptr, ", ");
+ diseqc_cmd=api_cmd->u.sat_comp.diseqc_cmd+n;
+ }
+ if(m>0) {
+ *(ptr-3)=0;
+ }
+ char *mini="MINI_OFF";
+ switch(api_cmd->u.sat_comp.sec.mini_cmd) {
+ case SEC_MINI_A:mini="MINI_A ";break;
+ case SEC_MINI_B:mini="MINI_B ";break;
+ }
+ printf(" Entry %i: Polarisation %c, Min% 6d, "
+ "Max% 6d, LOF% 6d %s %s %s DiSEqC <%s>\n",
+ l,
+ api_cmd->u.sat_comp.Polarisation?'H':'V',
+ api_cmd->u.sat_comp.RangeMin,
+ api_cmd->u.sat_comp.RangeMax,
+ api_cmd->u.sat_comp.LOF,
+ mini,
+ api_cmd->u.sat_comp.sec.tone_mode==SEC_TONE_ON ?"TONE_ON ":"TONE_OFF",
+ api_cmd->u.sat_comp.sec.voltage==SEC_VOLTAGE_18?"VOLTAGE_18":"VOLTAGE_13",
+ diseqc
+ );
+ }
+ }
+ }
+ }
+ }
+ puts("");
+}
+/*------------------------------------------------------------------------*/
+void show_stats(void)
+{
+ api_cmd_t sock_cmd;
+ api_cmd_t *api_cmd=&sock_cmd;
+ int i;
+ char *types[]={"DVB-S","DVB-C","DVB-T", "?", "DVB-S2"};
+ int type;
+
+ api_cmd->cmd=API_GET_TRA_NUM;
+ api_cmd->magic = MCLI_MAGIC;
+ api_cmd->version = MCLI_VERSION;
+ API_WAIT_RESPONSE(api_cmd);
+
+// printf("tra_num: %d\n", api_cmd->parm[API_PARM_TRA_NUM]);
+ int tra_num=api_cmd->parm[API_PARM_TRA_NUM];
+ for(i=0;i<tra_num;i++) {
+ char uuid[256];
+ char *p;
+
+ api_cmd->cmd=API_GET_TRA_INFO;
+ api_cmd->parm[API_PARM_TRA_NUM]=i;
+ API_WAIT_RESPONSE(api_cmd);
+ char host[INET6_ADDRSTRLEN];
+ inet_ntop (AF_INET6, &api_cmd->u.tra.mcg, (char *) host, INET6_ADDRSTRLEN);
+ type=api_cmd->u.tra.fe_type;
+ if (type<0 || type>4)
+ type=3;
+
+ strncpy(uuid,api_cmd->u.tra.uuid,255);
+ uuid[255]=0;
+ p=strrchr(uuid,':');
+ if (p)
+ *p=0;
+
+ fe_type_t t;
+ recv_sec_t sec;
+ int satpos;
+ struct dvb_frontend_parameters fep;
+
+ if(mcg_to_fe_parms(&api_cmd->u.tra.mcg, &t, &sec, &fep, NULL)<0) {
+ memset(&fep,0,sizeof(struct dvb_frontend_parameters));
+ }
+
+ mcg_get_satpos(&api_cmd->u.tra.mcg, &satpos);
+ float pos=(float)((satpos-1800.0)/10.0);
+ char pos_str[256];
+ if(satpos != 0xfff) {
+ sprintf(pos_str, ", position <%.1f%c>", fabs(pos), pos<0?'W':'E');
+ } else {
+ pos_str[0]=0;
+ }
+
+ printf("UUID <%s>:\n"
+ " slot %s%d.%d, type %s, used: % 3d\n"
+ " %s, frequency %d%s (%.1f%s)%s\n"
+ " strength %04x, snr %04x, ber %04x, unc %04x\n"
+ " NIMCurrent %d\n"
+ " RotorStatus %i, RotorDiff %.1f\n",
+ uuid,
+ (time(0)-api_cmd->u.tra.lastseen)>15?"-":"",
+ api_cmd->u.tra.slot/2,api_cmd->u.tra.slot%2,
+ types[type], api_cmd->u.tra.InUse,
+ api_cmd->u.tra.s.st==0x1f?"LOCK ":"NO LOCK",
+ fep.frequency, (type==1||type==2)?"Hz":"kHz", api_cmd->u.tra.fep.frequency/1000.0,
+ (type==1||type==2)?"kHz":"MHz",pos_str,
+ api_cmd->u.tra.s.strength,
+ api_cmd->u.tra.s.snr, api_cmd->u.tra.s.ber, api_cmd->u.tra.s.ucblocks,
+ api_cmd->u.tra.NIMCurrent,
+ api_cmd->u.tra.rotor_status,
+ api_cmd->u.tra.rotor_diff/10.0
+ );
+
+ }
+}
+/*------------------------------------------------------------------------*/
+int main(int argc, char **argv)
+{
+ int repeat=0;
+ int show_uuids=0,show_tuners=0,show_sats=0,show_state=0,show_cams=0;
+ int show_count=0, show_versions=0;
+#ifdef API_SOCK
+ char path[256]=API_SOCK_NAMESPACE;
+#endif
+#ifdef API_WIN
+ char path[256]="\\\\.\\pipe\\mcli";
+#endif
+ while(1) {
+ int ret = getopt(argc,argv, "aucCtsSvr:P:");
+ if (ret==-1)
+ break;
+
+ char c=(char)ret;
+
+ switch (c) {
+ case 'a':
+ show_uuids=1;
+ show_tuners=1;
+ show_sats=1;
+ show_state=1;
+ show_count=1;
+ show_versions=1;
+ show_cams=1;
+ break;
+ case 'u':
+ show_uuids=1;
+ break;
+ case 'c':
+ show_count=1;
+ break;
+ case 'C':
+ show_cams=1;
+ break;
+ case 't':
+ show_tuners=1;
+ break;
+ case 's':
+ show_state=1;
+ break;
+ case 'r':
+ repeat=abs(atoi(optarg));
+ break;
+ case 'S':
+ show_sats=1;
+ break;
+ case 'v':
+ show_versions=1;
+ break;
+ case 'P':
+ strncpy(path,optarg,255);
+ path[255]=0;
+ break;
+ default:
+ usage();
+ break;
+ }
+ }
+ if (nc_api_init(path)==-1) {
+ exit(-1);
+ }
+
+ do {
+ show_it(show_count, show_uuids, show_tuners, show_sats, show_versions, show_cams);
+ if (show_state)
+ show_stats();
+ sleep(repeat);
+ } while(repeat);
+
+ exit(0);
+}
+
diff --git a/mcast/tool/netcvlogview.c b/mcast/tool/netcvlogview.c
new file mode 100644
index 0000000..4d8bc9f
--- /dev/null
+++ b/mcast/tool/netcvlogview.c
@@ -0,0 +1,206 @@
+#include "headers.h"
+
+#ifdef __MINGW32__
+#include <getopt.h>
+extern void bzero(void *s, size_t n);
+#endif
+
+#define HDR_CHK_PACKET_LENGTH 1424
+#define HDR_CHK_LENGTH 16
+
+static int quit=0;
+
+void sighandler(int sig) {
+ quit=1;
+}
+
+int main (int argc, char **argv)
+{
+ UDPContext *s;
+ unsigned char buf[UDP_TX_BUF_SIZE];
+ memset (buf, 0x55, sizeof (buf));
+ int ret, len, i, mode = 1, mcg_num = 1, port = 23000, c, needhelp = 0, wait = 0, file = 0, loop = 0, header = 0, lost = 0;
+ char mcg[10][1024];
+ char *ifname = NULL;
+ strcpy (mcg[0], "ff18:5100::");
+
+ do {
+ ret = getopt_long (argc, argv, "hrtp:g:xi:w:flH", NULL, NULL);
+ if(ret<0) {
+ break;
+ }
+ c=(char)ret;
+ switch (c) {
+ case 'i':
+ ifname = optarg;
+ break;
+ case 'f':
+ file = 1;
+ break;
+ case 'r':
+ mode = 1;
+ break;
+ case 't':
+ mode = 2;
+ break;
+ case 'x':
+ mode = 3;
+ break;
+ case 'H':
+ header = 1;
+ break;
+ case 'l':
+ loop = 1;
+ break;
+ case 'p':
+ port = atoi (optarg);
+ break;
+ case 'w':
+ wait = atoi (optarg);
+ break;
+ case 'g':
+ for (mcg_num = 0, optind--; optind < argc; optind++, mcg_num++) {
+ if (argv[optind][0] != '-') {
+ strcpy (mcg[mcg_num], argv[optind]);
+ } else {
+ break;
+ }
+ }
+ break;
+ case 'h':
+ needhelp = 1;
+ break;
+ }
+ }
+ while (c >= 0);
+
+ if (needhelp) {
+ fprintf (stderr, "usage: netcvlogview -i <network interface> <-r|-t> -g <multicast groups> -p <port> -w <seconds timeout> -H\n");
+ return -1;
+ }
+
+ fprintf (stderr, "mode:%d port:%d mcg:%d [ ", mode, port, mcg_num);
+ for (i = 0; i < mcg_num; i++) {
+ fprintf (stderr, "%s ", mcg[i]);
+ }
+ fprintf (stderr, "]\n");
+
+#ifdef __MINGW32__
+ recv_init (ifname, port);
+#endif
+
+ switch (mode) {
+
+ case 1:
+ s = client_udp_open_host (mcg[0], port, ifname);
+ if (s) {
+ struct sockaddr_in6 addr;
+ addr.sin6_family = AF_INET6;
+ addr.sin6_port = htons (port);
+
+ for (i = 1; i < mcg_num; i++) {
+ fprintf (stderr, "mcg: [%s]\n", mcg[i]);
+ inet_pton (AF_INET6, mcg[i], &addr.sin6_addr);
+ if (udp_ipv6_join_multicast_group (s->udp_fd, s->idx, (struct sockaddr *) &addr) < 0) {
+ err ("Cannot join multicast group !\n");
+ }
+
+ }
+ signal(SIGTERM, sighandler);
+ signal(SIGINT, sighandler);
+
+ FILE *f;
+ time_t first;
+ time_t last;
+ int hc, i;
+ do {
+ first=last=hc=lost=0;
+ if(file) {
+ f=fopen("rawfile.temp", "wb");
+ if(f==NULL) {
+ perror("Cannot open file for writing\n");
+ return -1;
+ }
+ } else {
+ f=stdout;
+ }
+ while (!quit &&(!wait || !last || ((time(NULL)-last) < wait))) {
+ len = udp_read (s, buf, sizeof (buf), 50, NULL);
+ if(len>0) {
+ if(header) {
+ if(len!=HDR_CHK_PACKET_LENGTH) {
+ fprintf(stderr, "Expected header length mismatch %d != %d!\n", len, HDR_CHK_PACKET_LENGTH);
+ }
+ uint32_t *cnt=(uint32_t *)buf;
+ int hv=ntohl(*cnt);
+ if(hv == hc) {
+ fwrite (buf+HDR_CHK_LENGTH, len-HDR_CHK_LENGTH, 1, f);
+ hc++;
+ } else {
+ bzero(buf, HDR_CHK_PACKET_LENGTH);
+ for(i=hc; i<hv; i++) {
+ fwrite(buf, HDR_CHK_PACKET_LENGTH-HDR_CHK_LENGTH, 1, f);
+ }
+ lost+=(hv-hc);
+ hc=i;
+ }
+ } else {
+ fwrite (buf, len, 1, f);
+ }
+ last=time(NULL);
+ if(!first) {
+ first=last;
+ }
+ }
+ }
+ fclose(f);
+ if(file) {
+ if(quit) {
+ unlink("rawfile.temp");
+ } else {
+ struct tm *now=localtime(&first);
+ char fname[80];
+ sprintf(fname, "%04d%02d%02d-%02d%02d%02d.raw", now->tm_year+1900, now->tm_mon+1, now->tm_mday, now->tm_hour, now->tm_min, now->tm_sec);
+ rename("rawfile.temp", fname);
+ fprintf(stderr, "[%s] New log file: %s (%u packets)\n",ifname, fname, hc);
+ if(lost) {
+ fprintf(stderr, "Warning: Lost %d frames of %d payload bytes, now filled with padding bytes (0)\n", lost, HDR_CHK_PACKET_LENGTH-HDR_CHK_LENGTH);
+ }
+ }
+ }
+ } while(loop && ! quit);
+ udp_close (s);
+ }
+ break;
+
+ case 2:
+ s = server_udp_open_host (mcg[0], port, ifname);
+ if (s) {
+ while (1) {
+ if(!fread (buf, 1316, 1, stdin)) {
+ break;
+ }
+ udp_write (s, buf, 1316);
+ }
+ udp_close (s);
+ }
+ break;
+
+ case 3:
+ s = server_udp_open_host (mcg[0], port, ifname);
+ if (s) {
+ int i;
+ for (i = 0; i < sizeof (buf); i++) {
+ buf[i] = rand ();
+ }
+ while (1) {
+ i = rand ();
+ udp_write (s, buf, ((i % 4) + 4) * 188);
+ }
+ udp_close (s);
+ }
+ break;
+ }
+
+ return 0;
+}
diff --git a/mcast/tool/netcvupdate.c b/mcast/tool/netcvupdate.c
new file mode 100644
index 0000000..e311470
--- /dev/null
+++ b/mcast/tool/netcvupdate.c
@@ -0,0 +1,773 @@
+/*------------------------------------------------------------------------
+ * netcvupdate - NetCeiver update tool
+ *
+ * Principle for firmware update
+ * - Unpack given .tgz into host /tmp/mkdtemp()
+ * - "md5sum -c md5sums.txt"
+ * - read script file update.scr
+ * - feed commands into tnftp
+ *
+ *
+ *------------------------------------------------------------------------*/
+#define USE_MCLI_API
+
+#ifdef USE_MCLI_API
+#include "headers.h"
+#else
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <signal.h>
+#include <ctype.h>
+#endif
+
+#define STATE_FILE "update.log"
+#define FTP_CMD "ftp"
+#define NC_CONFPATH "/mmc/etc/"
+#define NC_CONFFILE "netceiver.conf"
+
+char ftp_cmd[512]=FTP_CMD;
+int verbose=0;
+int no_reboot=0;
+char username[256]="root";
+char password[256]="root";
+char device[256]="eth0";
+char *uuids[256]={0};
+char *versions[256]={0};
+int num_uuids=0;
+char socket_path[256]=API_SOCK_NAMESPACE;
+
+#ifdef USE_MCLI_API
+/*------------------------------------------------------------------------*/
+#define API_WAIT_RESPONSE(cmd) { cmd->state=API_REQUEST; \
+ send (sock_comm, &sock_cmd, sizeof(api_cmd_t), 0); \
+ recv (sock_comm, &sock_cmd, sizeof(api_cmd_t), 0); \
+ if (cmd->state == API_ERROR) {warn ( "SHM parameter error, incompatible versions?\n"); exit(-1);}}
+
+int sock_comm;
+
+int api_init(char *path)
+{
+ int sock_name_len = 0;
+ struct sockaddr_un sock_name;
+ sock_name.sun_family = AF_UNIX;
+
+ strcpy(sock_name.sun_path, path);
+ sock_name_len = sizeof(struct sockaddr_un);
+
+ if((sock_comm = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
+ {
+ warn ("socket create failure %d\n", errno);
+ return -1;
+ }
+
+ if (connect(sock_comm, (struct sockaddr*)&sock_name, sock_name_len) < 0) {
+ warn ("connect failure to %s: %s (are you root?)\n",path, strerror(errno));
+ return -1;
+ }
+ return 0;
+}
+#endif
+/*------------------------------------------------------------------------*/
+void add_upload(char* cmd, char* localfile, char *remotepath, char *remotefile)
+{
+ char tmp[1024];
+ sprintf(tmp,
+ "cd %s\n"
+ "site exec rm -f /tmp/update/%s\n"
+ "put %s\n",
+ remotepath, remotefile, localfile);
+ strcat(cmd,tmp);
+}
+/*------------------------------------------------------------------------*/
+void add_download(char* cmd, char *remotepath, char *remotefile)
+{
+ char tmp[1024];
+ sprintf(tmp,
+ "cd %s\n"
+ "get %s\n",
+ remotepath,remotefile);
+ strcat(cmd,tmp);
+}
+/*------------------------------------------------------------------------*/
+int script_interpreter(char *script, char *line,
+ char *ip, char *iface, char *user, char *pwd)
+{
+ char cmd[256],p1[256],p2[256];
+ int end=0;
+
+ *cmd=0;
+ *p1=0;
+ *p2=0;
+ sscanf(line,"%s %s %s\n",cmd,p1,p2);
+
+ if (cmd[0]=='#')
+ return 0;
+ if (!strcmp(cmd,"connect")) {
+ char tmp[1024];
+ sprintf(tmp,
+ "open %s%%%s\n"
+ "user %s %s\n",
+ ip,iface,user,pwd);
+ strcat(script,tmp);
+ }
+ else if (!strcmp(cmd,"upload")) {
+ add_upload(script,p2,p1,p2);
+ }
+ else if (!strcmp(cmd,"download")) {
+ add_download(script,p1,p2);
+ }
+ else if (!strcmp(cmd,"exit")) {
+ strcat(script,"quit\n");
+ end=1;
+ }
+ else {
+ strcat(script,line);
+ }
+ return end;
+}
+/*------------------------------------------------------------------------*/
+char script[128*1024];
+int generate_script(char *filename, char *tmpname, char *ip, char *iface, char *user, char *pwd)
+{
+ FILE *f;
+ f=fopen(filename,"r");
+ if (!f) {
+ fprintf(stderr,"Can't open script file <%s>: %s\n",filename,strerror(errno));
+ return -1;
+ }
+ script[0]=0;
+
+ while(!feof(f)) {
+ char line[256];
+ fgets(line,255,f);
+ if (script_interpreter(script,line,ip,iface,user,pwd))
+ break;
+ }
+ fclose(f);
+ return 0;
+}
+/*------------------------------------------------------------------------*/
+int check_state_file(char *tmpname)
+{
+ char cmd[512];
+ int ret;
+ printf("\nUPDATE RESULT:\n");
+ snprintf(cmd,512,"cat %s/update.log",tmpname);
+ ret=system(cmd);
+ printf("\n");
+ return ret;
+}
+/*------------------------------------------------------------------------*/
+void sigground(int x)
+{
+}
+/*------------------------------------------------------------------------*/
+int run_ftp(char *tmpdir,char *script, int timeout, char *pipeout)
+{
+ FILE *f;
+ char cmd[512];
+ int ret;
+ if (!strlen(ftp_cmd))
+ return -1;
+ signal(SIGPIPE,sigground);
+ if (strlen(tmpdir))
+// snprintf(cmd,511,"cd %s; %s -q %i -n %s",tmpdir,ftp_cmd,timeout,verbose?"":"-V");
+ snprintf(cmd,511,"cd %s; %s -n %s %s",tmpdir,ftp_cmd,verbose?"":"-V",pipeout);
+ else
+ snprintf(cmd,511,"%s -q %i -n %s %s",ftp_cmd,timeout,verbose?"":"-V",pipeout);
+
+ f=popen(cmd,"w");
+ if (!f)
+ return -1;
+ fputs(script,f);
+ ret=pclose(f);
+ return ret;
+}
+/*------------------------------------------------------------------------*/
+int do_reboot(char *tmpdir, char *ip, char* iface, char *user, char* pwd)
+{
+ sprintf(script,
+ "open %s%%%s\n"
+ "user %s %s\n"
+ "site exec reboot -d 5\n"
+ "quit\n"
+ ,
+ ip,iface,user,pwd);
+ return run_ftp(tmpdir, script, 15,"");
+}
+/*------------------------------------------------------------------------*/
+
+int do_list_fw(char *tmpdir, char *ip, char* iface, char *user, char* pwd, int maxf, int *found, char **versions)
+{
+ char tmpfile[256]="/tmp/ncvup.XXXXXX";
+ char pipeout[256];
+ int n=0;
+ int ret=0;
+ FILE *file;
+
+ *found=0;
+
+ if (!mkstemp(tmpfile)) {
+ fprintf(stderr,"Can't make temporary directory %s!\n",tmpfile);
+ return -2;
+ }
+
+ sprintf(script,
+ "open %s%%%s\n"
+ "user %s %s\n"
+ "ls /mmc/\n"
+ "quit\n"
+ ,
+ ip,iface,user,pwd);
+ sprintf(pipeout," > %s",tmpfile);
+ ret=run_ftp(tmpdir, script, 15, pipeout);
+ if (ret) {
+ unlink(tmpfile);
+ return ret;
+ }
+
+ file=fopen(tmpfile,"r");
+ if (!file) {
+ unlink(tmpfile); // ?
+ perror("Can't read temp file");
+ return ret;
+ }
+
+ while(!feof(file)) {
+ char line[1024];
+ char *p;
+ *line=0;
+ fgets(line, 1023,file);
+ line[1023]=0;
+ p=strstr(line,"etceivr.");
+ if (p) {
+
+ char *pp=strchr(p,'\n');
+ if (pp)
+ *pp=0;
+
+ if (n < maxf) {
+ n++;
+ *versions++=strdup(p-1);
+ }
+ }
+ }
+ *found=n;
+ fclose(file);
+ unlink(tmpfile);
+ return 0;
+}
+/*------------------------------------------------------------------------*/
+int do_kill(char *tmpdir, char *ip, char* iface, char *user, char* pwd)
+{
+ sprintf(script,
+ "open %s%%%s\n"
+ "user %s %s\n"
+ "site exec killall -9 mserv\n"
+ "quit\n"
+ ,
+ ip,iface,user,pwd);
+ return run_ftp(tmpdir, script, 15,"");
+}
+/*------------------------------------------------------------------------*/
+int do_single_update(char *tmpdir, char *uuid, char *device)
+{
+ char path[256];
+ int ret;
+
+ snprintf(path,255,"%s/%s",tmpdir,"update.scr");
+ if (generate_script(path, tmpdir, uuid, device, username, password))
+ return -1;
+// puts(script);
+
+ printf("Upload update... ");
+ fflush(stdout);
+
+ ret=run_ftp(tmpdir, script, 600,"");
+ if (ret)
+ return ret;
+
+ printf("check result... \n");
+ fflush(stdout);
+
+ if (check_state_file(tmpdir))
+ return -1;
+
+#if 1
+ if (!no_reboot) {
+ printf("Issue Reboot... ");
+ fflush(stdout);
+ ret=do_reboot(tmpdir, uuid, device, username, password);
+ if (!ret)
+ return ret;
+ }
+#endif
+ return 0;
+}
+/*------------------------------------------------------------------------*/
+int do_single_upload( char *uuid, char *device, char *remote_path, char *fname, char *remote_file)
+{
+ int ret;
+ sprintf(script,
+ "open %s%%%s\n"
+ "user %s %s\n"
+ "cd %s\n"
+ "put %s %s\n"
+// "site exec killall -HUP mserv\n"
+ "quit",
+ uuid,device,username,password,remote_path,fname,remote_file);
+ ret=run_ftp("", script, 120,"");
+ return ret;
+}
+/*------------------------------------------------------------------------*/
+int do_single_download( char *uuid, char *device, char *remote_path, char *fname)
+{
+ int ret;
+ sprintf(script,
+ "open %s%%%s\n"
+ "user %s %s\n"
+ "cd %s\n"
+ "get %s\n"
+ "quit",
+ uuid,device,username,password,remote_path,fname);
+ ret=run_ftp("", script, 120,"");
+ return ret;
+}
+/*------------------------------------------------------------------------*/
+int fw_action(char *uuid, char* iface, char *user, char* pwd, int mode, char *version)
+{
+ int ret;
+ if (mode==0) { // inactivate
+ printf("Inactivating version %s\n",version);
+ sprintf(script,
+ "open %s%%%s\n"
+ "user %s %s\n"
+ "cd /mmc\n"
+ "rename netceivr.%s xetceivr.%s\n"
+ "quit",
+ uuid,device,username,password,version,version);
+ ret=run_ftp("", script, 120,"");
+ return ret;
+ }
+ else if (mode==1) { // enable
+ printf("Enabling version %s\n",version);
+ sprintf(script,
+ "open %s%%%s\n"
+ "user %s %s\n"
+ "cd /mmc\n"
+ "rename xetceivr.%s netceivr.%s\n"
+ "quit",
+ uuid,device,username,password,version,version);
+ ret=run_ftp("", script, 120,"");
+ return ret;
+ }
+ else if (mode==2) { // delete
+ printf("Removing version %s\n",version);
+ sprintf(script,
+ "open %s%%%s\n"
+ "user %s %s\n"
+ "site exec rm -rf /mmc/netceivr.%s\n"
+ "site exec rm -rf /mmc/xetceivr.%s\n"
+ "quit",
+ uuid,device,username,password,version,version);
+ ret=run_ftp("", script, 120,"");
+ return ret;
+ }
+ return 0;
+}
+/*------------------------------------------------------------------------*/
+int cleanup(char *tmpdir)
+{
+ int ret;
+ char cmd[1024];
+ snprintf(cmd,1024,"rm -rf '%s'",tmpdir);
+// puts(cmd);
+ ret=system(cmd);
+ return ret;
+}
+/*------------------------------------------------------------------------*/
+int unpack(char *tmpdir, char *file)
+{
+ int ret;
+ char cmd[1024];
+ snprintf(cmd,1024,"tar xfz '%s' --directory %s",file,tmpdir);
+// puts(cmd);
+ ret=system(cmd);
+ return ret;
+}
+/*------------------------------------------------------------------------*/
+int check_xml(char *file)
+{
+ int ret;
+ char cmd[1024];
+ snprintf(cmd,1024,"xmllint --noout '%s'\n",file);
+// puts(cmd);
+ ret=system(cmd);
+ return ret;
+}
+/*------------------------------------------------------------------------*/
+int check_integrity(char *tmpdir)
+{
+ int ret;
+ char cmd[1024];
+ snprintf(cmd,1024,"cd %s; md5sum -c --status md5sums.txt \n",tmpdir);
+// puts(cmd);
+ ret=system(cmd);
+ return ret;
+}
+/*------------------------------------------------------------------------*/
+int do_update(char **uuids, int num_uuids, char *device, char *optarg)
+{
+ char tmpdir[256]="/tmp/ncvupXXXXXX";
+ int n;
+ int ret=0;
+ if (!mkdtemp(tmpdir)) {
+ fprintf(stderr,"Can't make temporary directory %s!\n",tmpdir);
+ return -2;
+ }
+// printf("TEMP DIR %s\n",tmpdir);
+ if (unpack(tmpdir,optarg)) {
+ fprintf(stderr,"Update file <%s> cannot be unpacked!\n",optarg);
+ cleanup(tmpdir);
+ return -2;
+ }
+ if (check_integrity(tmpdir)) {
+ fprintf(stderr,"Update file <%s> corrupted!\n",optarg);
+ cleanup(tmpdir);
+ return -2;
+ }
+ printf("Update file integrity OK\n");
+ printf("NUM uuids %i\n",num_uuids);
+ for(n=0;n<num_uuids;n++) {
+ if (!uuids[n])
+ continue;
+
+ printf("UUID %s: ",uuids[n]);
+ fflush(stdout);
+ ret=do_single_update(tmpdir, uuids[n], device);
+ if (!ret)
+ printf("-> Update done <-\n");
+ else {
+ printf("-> Update failed (ret=%i) <-\n",ret);
+ uuids[n]=NULL;
+ }
+ }
+
+ cleanup(tmpdir);
+ return ret;
+}
+/*------------------------------------------------------------------------*/
+int do_upload(char **uuids, int num_uuids, char *device, char *optarg)
+{
+ int n;
+ int ret=0;
+ if (check_xml(optarg)) {
+ fprintf(stderr,"Configuration file <%s> not valid XML\n",optarg);
+ return -2;
+ }
+ for(n=0;n<num_uuids;n++) {
+ if (!uuids[n])
+ continue;
+
+ printf("UUID %s: Uploading %s ... ",uuids[n], optarg);
+ fflush(stdout);
+ ret=do_single_upload(uuids[n], device, "/mmc/etc/", optarg, NC_CONFFILE);
+ if (!ret)
+ printf("Upload done\n");
+ else {
+ printf("Upload failed (ret=%i)\n",ret);
+ uuids[n]=NULL;
+ }
+ }
+ return ret;
+}
+/*------------------------------------------------------------------------*/
+int do_download(char **uuids, int num_uuids, char *device, char *remotepath, char *file)
+{
+ int n,ret=0;
+
+ for(n=0;n<num_uuids;n++) {
+ char newfile[1024];
+ if (!uuids[n])
+ continue;
+
+ if (num_uuids!=1)
+ snprintf(newfile,1024,"%s-%s",file,uuids[n]);
+ else
+ strncpy(newfile,file,1024);
+
+ printf("UUID %s: Downloading %s ... ",uuids[n], newfile);
+ fflush(stdout);
+ ret=do_single_download(uuids[n], device, remotepath, file);
+ if (!ret) {
+ printf("Done\n");
+ if (num_uuids!=1)
+ rename(file,newfile);
+ }
+ else {
+ printf("Download failed (ret=%i)\n",ret);
+ uuids[n]=NULL;
+ }
+ }
+ return ret;
+}
+/*------------------------------------------------------------------------*/
+int do_all_reboot(char **uuids, int num_uuids, char *device)
+{
+ int n,ret=0;
+
+ for(n=0;n<num_uuids;n++) {
+ if (!uuids[n])
+ continue;
+ printf("UUID %s: Issue Reboot... ",uuids[n]);
+ fflush(stdout);
+ ret=do_reboot("/tmp", uuids[n], device, username, password);
+ if (!ret)
+ printf("Reboot done\n");
+ else
+ printf("Reboot failed (ret=%i)\n",ret);
+ }
+ return ret;
+}
+/*------------------------------------------------------------------------*/
+int do_all_kill(char **uuids, int num_uuids, char *device)
+{
+ int n,ret=0;
+
+ for(n=0;n<num_uuids;n++) {
+ if (!uuids[n])
+ continue;
+ printf("UUID %s: Issue Kill... ",uuids[n]);
+ fflush(stdout);
+ ret=do_kill("/tmp", uuids[n], device, username, password);
+ if (!ret)
+ printf("Kill done\n");
+ else
+ printf("Kill failed (ret=%i)\n",ret);
+ }
+ return ret;
+}
+/*------------------------------------------------------------------------*/
+int get_uuids(char **uuids, int max)
+{
+ int count,n;
+ api_cmd_t sock_cmd;
+ api_cmd_t *api_cmd=&sock_cmd;
+
+ if (api_init(socket_path)==-1) {
+ exit(-1);
+ }
+ api_cmd->cmd=API_GET_NC_NUM;
+ api_cmd->magic = MCLI_MAGIC;
+ api_cmd->version = MCLI_VERSION;
+ API_WAIT_RESPONSE(api_cmd);
+ if(api_cmd->magic != MCLI_MAGIC || api_cmd->version != MCLI_VERSION) {
+ err("API version mismatch!\n");
+ }
+ count=api_cmd->parm[API_PARM_NC_NUM];
+
+ for(n=0;n<max && n<count;n++) {
+ api_cmd->cmd=API_GET_NC_INFO;
+ api_cmd->parm[API_PARM_NC_NUM]=n;
+ API_WAIT_RESPONSE(api_cmd);
+ if(api_cmd->u.nc_info.magic != MCLI_MAGIC || api_cmd->u.nc_info.version != MCLI_VERSION) {
+ err("API version mismatch!\n");
+ }
+
+ uuids[n]=strdup(api_cmd->u.nc_info.uuid);
+ versions[n]=strdup(api_cmd->u.nc_info.FirmwareVersion);
+ }
+ return count;
+}
+/*------------------------------------------------------------------------*/
+int show_uuids(void)
+{
+ char *uuids[256]={0};
+ int num_uuids,n;
+ num_uuids=get_uuids(uuids,256);
+ for(n=0;n<num_uuids;n++) {
+ printf("%s %s\n",uuids[n],versions[n]);
+ }
+ return 0;
+}
+/*------------------------------------------------------------------------*/
+#define MAX_FWS 64
+void show_firmwares(char *uuid, char *device, char *username, char *passwd)
+{
+ char *fwversions[MAX_FWS];
+ int found,m;
+ found=0;
+
+ do_list_fw("/tmp", uuid, device, username, password, MAX_FWS, &found, fwversions);
+
+ printf("Firmware versions found: %i\n Versions: ", found);
+ for(m=0;m<found;m++) {
+ if (m!=0) printf(", ");
+ if (fwversions[m][0]!='n')
+ printf("%s (disabled)",fwversions[m]+9);
+ else
+ printf("%s",fwversions[m]+9);
+
+ free(versions[m]);
+ }
+ puts("");
+}
+/*------------------------------------------------------------------------*/
+
+int show_all_firmwares(char **uuids, int num_uuids)
+{
+ int n;
+
+ for(n=0;n<num_uuids;n++) {
+ printf("%s: ",uuids[n]);
+ fflush(stdout);
+ show_firmwares(uuids[n],device,username,password);
+ }
+ return 0;
+}
+/*------------------------------------------------------------------------*/
+void do_fw_actions(char **uuids, int max, int mode, char *version)
+{
+ int n;
+
+ if (strlen(version)!=3 || !strcmp(version,"000")) {
+ fprintf(stderr,"Invalid version number\n");
+ return;
+ }
+
+ for(n=0;n<3;n++)
+ version[n]=toupper(version[n]);
+
+ for(n=0;n<max;n++) {
+ printf("UUID %s\n",uuids[n]);
+ if (fw_action(uuids[n], device, username, password, mode, version)) {
+ fprintf(stderr,"Failed\n");
+ return;
+ }
+ show_firmwares(uuids[n],device,username,password);
+ }
+}
+/*------------------------------------------------------------------------*/
+void usage(void)
+{
+ fprintf(stderr,
+ "netcvupdate - NetCeiver update tool, version " MCLI_VERSION_STR "\n"
+ "(c) BayCom GmbH\n"
+ "Usage: netcvupdate <options> <actions> \n"
+ "Actions: \n"
+ " -l List all seen NetCeivers and their UUID\n"
+ " -L List available FWs\n"
+ " -X <Update.tgz> Update with given file\n"
+ " -U <configfile> Upload configfile\n"
+ " -D Download configfile netceiver.conf\n"
+ " -I <version> Inactivate FW version\n"
+ " -E <version> Enable FW version\n"
+ " -Z <version> Remove FW version\n"
+ " -K Restart streaming server\n"
+ " -R Issue reboot\n"
+ "Options:\n"
+ " -A Use all found NetCeivers (mcli must be running)\n"
+ " -i <uuid> Use specific UUID (can be used multiple times)\n"
+ " *** Either -A or -i must be given for most actions! ***\n"
+ "Rare options:\n"
+ " -d <device> Set network device (default: eth0)\n"
+ " -F <ftp-command> Set ftp command/path\n"
+ " *** ftp command must understand the -q (timeout) option! ***\n"
+ " -P <path> Set API socket\n"
+ " -u <user> Set username\n"
+ " -p <password> Set password\n"
+ " -r No reboot after update\n"
+ " -q Be more quiet\n"
+ );
+ exit(0);
+}
+/*------------------------------------------------------------------------*/
+int main(int argc, char **argv)
+{
+ int ret=0;
+
+ while(1) {
+ int ret = getopt(argc,argv, "U:X:Di:AlLI:E:Z:d:F:P:u:p:rRqK");
+ if (ret==-1)
+ break;
+
+ char c=(char)ret;
+
+ switch(c) {
+ case 'F':
+ strncpy(ftp_cmd,optarg,512);
+ ftp_cmd[511]=0;
+ break;
+ case 'X':
+ ret=do_update(uuids, num_uuids, device, optarg);
+ if (ret==-2)
+ exit(ret);
+ break;
+ case 'U':
+ ret=do_upload(uuids, num_uuids, device, optarg);
+ if (ret==-2)
+ exit(ret);
+ break;
+ case 'D':
+ ret|=do_download(uuids, num_uuids, device, NC_CONFPATH, NC_CONFFILE);
+ break;
+ case 'i':
+ uuids[num_uuids]=strdup(optarg);
+ num_uuids++;
+ break;
+ case 'A':
+ num_uuids=get_uuids(uuids,255);
+ break;
+ case 'l':
+ show_uuids();
+ break;
+ case 'd':
+ strncpy(device,optarg,255);
+ device[255]=0;
+ break;
+ case 'P':
+ strncpy(socket_path,optarg,255);
+ socket_path[255]=0;
+ break;
+ case 'p':
+ strncpy(password,optarg,255);
+ password[255]=0;
+ break;
+ case 'u':
+ strncpy(username,optarg,255);
+ username[255]=0;
+ break;
+ case 'r':
+ no_reboot=1;
+ break;
+ case 'K':
+ ret|=do_all_kill(uuids,num_uuids,device);
+ break;
+ case 'R':
+ ret|=do_all_reboot(uuids, num_uuids, device);
+ break;
+ case 'L':
+ show_all_firmwares(uuids, num_uuids);
+ break;
+ case 'I':
+ do_fw_actions(uuids, num_uuids, 0, optarg);
+ break;
+ case 'E':
+ do_fw_actions(uuids, num_uuids, 1, optarg);
+ break;
+ case 'Z':
+ do_fw_actions(uuids, num_uuids, 2, optarg);
+ break;
+ case 'q':
+ verbose=0;
+ break;
+ default:
+ usage();
+ break;
+ }
+ }
+ exit(ret);
+}
diff --git a/mcast/tool/tools.c b/mcast/tool/tools.c
new file mode 120000
index 0000000..71f8bc6
--- /dev/null
+++ b/mcast/tool/tools.c
@@ -0,0 +1 @@
+../common/tools.c \ No newline at end of file
diff --git a/mcli-i18n.diff b/mcli-i18n.diff
new file mode 100644
index 0000000..1febf42
--- /dev/null
+++ b/mcli-i18n.diff
@@ -0,0 +1,22 @@
+Index: po/de_DE.po
+===================================================================
+--- po/de_DE.po (Revision 180)
++++ po/de_DE.po (Arbeitskopie)
+@@ -22,7 +22,7 @@
+ msgstr "Aktualisiere Konfiguration..."
+
+ msgid "Configuration is up to date..."
+-msgstr "Konfuguration ist aktuell..."
++msgstr "Konfiguration ist aktuell..."
+
+ #, c-format
+ msgid "Getting configuration from Netceiver %s"
+@@ -30,7 +30,7 @@
+
+ #, c-format
+ msgid "Failed to get configuration from Netceiver %s"
+-msgstr "Fehler beim Holen der Konfiguration von Netceiver %s"
++msgstr "Fehler beim Laden der Konfiguration von Netceiver %s"
+
+ #, c-format
+ msgid "Changing configuration for Netceiver %s"
diff --git a/mcli.c b/mcli.c
new file mode 100644
index 0000000..a24abff
--- /dev/null
+++ b/mcli.c
@@ -0,0 +1,1122 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ */
+
+/*
+ * mcli.c: A plugin for the Video Disk Recorder
+ */
+
+#include <vdr/plugin.h>
+#include <vdr/player.h>
+
+#include "filter.h"
+#include "device.h"
+#include "cam_menu.h"
+#include "mcli_service.h"
+#include "mcli.h"
+#include <sstream>
+
+static int reconf = 0;
+
+//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+class cMenuSetupMcli:public cMenuSetupPage
+{
+ private:
+ cmdline_t * m_cmd;
+ protected:
+ virtual void Store (void);
+ public:
+ cMenuSetupMcli (cmdline_t * cmd);
+};
+
+cMenuSetupMcli::cMenuSetupMcli (cmdline_t * cmd)
+{
+ m_cmd = cmd;
+ Add (new cMenuEditIntItem (trNOOP ("DVB-C"), &m_cmd->tuner_type_limit[FE_QAM]));
+ Add (new cMenuEditIntItem (trNOOP ("DVB-T"), &m_cmd->tuner_type_limit[FE_OFDM]));
+ Add (new cMenuEditIntItem (trNOOP ("DVB-S"), &m_cmd->tuner_type_limit[FE_QPSK]));
+ Add (new cMenuEditIntItem (trNOOP ("DVB-S2"), &m_cmd->tuner_type_limit[FE_DVBS2]));
+}
+
+void cMenuSetupMcli::Store (void)
+{
+ SetupStore ("DVB-C", m_cmd->tuner_type_limit[FE_QAM]);
+ SetupStore ("DVB-T", m_cmd->tuner_type_limit[FE_OFDM]);
+ SetupStore ("DVB-S", m_cmd->tuner_type_limit[FE_QPSK]);
+ SetupStore ("DVB-S2", m_cmd->tuner_type_limit[FE_DVBS2]);
+ reconf = 1;
+}
+
+cOsdObject *cPluginMcli::AltMenuAction (void)
+{
+ // Call this code periodically to find out if any CAM out there want's us to tell something.
+ // If it's relevant to us we need to check if any of our DVB-Devices gets programm from a NetCeiver with this UUID.
+ // The text received should pop up via OSD with a CAM-Session opened afterwards (CamMenuOpen...CamMenuReceive...CamMenuSend...CamMenuClose).
+ mmi_info_t m;
+ if (CamPollText (&m) > 0) {
+ printf ("NetCeiver %s CAM slot %d Received %s valid for:\n", m.uuid, m.slot, m.mmi_text);
+ for (int i = 0; i < m.caid_num; i++) {
+ caid_mcg_t *c = m.caids + i;
+ int satpos;
+ fe_type_t type;
+ recv_sec_t sec;
+ struct dvb_frontend_parameters fep;
+ int vpid;
+
+ mcg_get_satpos (&c->mcg, &satpos);
+ mcg_to_fe_parms (&c->mcg, &type, &sec, &fep, &vpid);
+
+ for (cMcliDeviceObject * dev = m_devs.First (); dev; dev = m_devs.Next (dev)) {
+ cMcliDevice *d = dev->d ();
+ //printf("satpos: %i vpid: %i fep.freq: %i dev.freq: %i\n", satpos, vpid, fep.frequency, dev->CurChan()->Frequency());
+ struct in6_addr mcg = d->GetTenData ()->mcg;
+ mcg_set_id (&mcg, 0);
+
+#if 1 //def DEBUG
+ char str[INET6_ADDRSTRLEN];
+ inet_ntop (AF_INET6, &c->mcg, str, INET6_ADDRSTRLEN);
+ printf ("MCG from MMI: %s\n", str);
+ inet_ntop (AF_INET6, &mcg, str, INET6_ADDRSTRLEN);
+ printf ("MCG from DEV: %s\n", str);
+#endif
+
+ if (IN6_IS_ADDR_UNSPECIFIED (&c->mcg) || !memcmp (&c->mcg, &mcg, sizeof (struct in6_addr)))
+ return new cCamMenu (&m_cmd, &m);
+ }
+ printf ("SID/Program Number:%04x, SatPos:%d Freqency:%d\n", c->caid, satpos, fep.frequency);
+ }
+ if (m.caid_num && m.caids) {
+ free (m.caids);
+ }
+ }
+ return NULL;
+}
+
+int cPluginMcli::CamPollText (mmi_info_t * text)
+{
+ if (m_mmi_init_done && !reconf) {
+ return mmi_poll_for_menu_text (m_cam_mmi, text, 10);
+ } else {
+ return 0;
+ }
+}
+
+cPluginMcli::cPluginMcli (void)
+{
+ // printf ("cPluginMcli::cPluginMcli\n");
+ int i;
+ //init parameters
+ memset (&m_cmd, 0, sizeof (cmdline_t));
+
+ for (i = 0; i <= FE_DVBS2; i++) {
+ m_cmd.tuner_type_limit[i] = MCLI_MAX_DEVICES;
+ }
+ m_cmd.port = 23000;
+ m_cmd.mld_start = 1;
+ m_mmi_init_done = 0;
+ m_recv_init_done = 0;
+ m_mld_init_done = 0;
+ m_api_init_done = 0;
+ memset (m_cam_pool, 0, sizeof (cam_pool_t) * CAM_POOL_MAX);
+ for(i=0; i<CAM_POOL_MAX; i++) {
+ m_cam_pool[i].max = -1;
+ }
+ strcpy (m_cmd.cmd_sock_path, API_SOCK_NAMESPACE);
+ memset (m_tuner_pool, 0, sizeof(tuner_pool_t)*TUNER_POOL_MAX);
+ for(i=0; i<TUNER_POOL_MAX; i++) {
+ m_tuner_pool[i].type = -1;
+ }
+}
+
+cPluginMcli::~cPluginMcli ()
+{
+// printf ("cPluginMcli::~cPluginMcli\n");
+ ExitMcli ();
+
+}
+
+bool cPluginMcli::InitMcli (void)
+{
+ if (!recv_init (m_cmd.iface, m_cmd.port)) {
+ m_recv_init_done = 1;
+ }
+ if (m_cmd.mld_start && !mld_client_init (m_cmd.iface)) {
+ m_mld_init_done = 1;
+ }
+ if (!api_sock_init (m_cmd.cmd_sock_path)) {
+ m_api_init_done = 1;
+ }
+ m_cam_mmi = mmi_broadcast_client_init (m_cmd.port, m_cmd.iface);
+ if (m_cam_mmi > 0) {
+ m_mmi_init_done = 1;
+ }
+ for(int i=m_devs.Count(); i < MCLI_MAX_DEVICES; i++) {
+ cMcliDevice *m = NULL;
+ cPluginManager::CallAllServices ("OnNewMcliDevice-" MCLI_DEVICE_VERSION, &m);
+ if(!m) {
+ m = new cMcliDevice;
+ }
+ if(m) {
+ m->SetMcliRef (this);
+ cMcliDeviceObject *d = new cMcliDeviceObject (m);
+ m_devs.Add (d);
+ }
+ }
+ return true;
+}
+
+void cPluginMcli::ExitMcli (void)
+{
+ if (m_mmi_init_done) {
+ mmi_broadcast_client_exit (m_cam_mmi);
+ }
+ if (m_api_init_done) {
+ api_sock_exit ();
+ }
+ if (m_mld_init_done) {
+ mld_client_exit ();
+ }
+ if (m_recv_init_done) {
+ recv_exit ();
+ }
+}
+
+const char *cPluginMcli::CommandLineHelp (void)
+{
+ return (" --ifname <network interface>\n" " --port <port> (default: -port 23000)\n" " --dvb-s <num> --dvb-c <num> --dvb-t <num> --atsc <num> --dvb-s2 <num>\n" " limit number of device types (default: 8 of every type)\n" " --mld-reporter-disable\n" " --sock-path <filepath>\n" "\n");
+}
+
+bool cPluginMcli::ProcessArgs (int argc, char *argv[])
+{
+// printf ("cPluginMcli::ProcessArgs\n");
+ int tuners = 0, i;
+ char c;
+ int ret;
+
+ while (1) {
+ //int this_option_optind = optind ? optind : 1;
+ int option_index = 0;
+ static struct option long_options[] = {
+ {"port", 1, 0, 0}, //0
+ {"ifname", 1, 0, 0}, //1
+ {"dvb-s", 1, 0, 0}, //2
+ {"dvb-c", 1, 0, 0}, //3
+ {"dvb-t", 1, 0, 0}, //4
+ {"atsc", 1, 0, 0}, //5
+ {"dvb-s2", 1, 0, 0}, //6
+ {"mld-reporter-disable", 0, 0, 0}, //7
+ {"sock-path", 1, 0, 0}, //8
+ {NULL, 0, 0, 0}
+ };
+
+ ret = getopt_long_only (argc, argv, "", long_options, &option_index);
+ c = (char) ret;
+ if (ret == -1 || c == '?') {
+ break;
+ }
+
+ switch (option_index) {
+ case 0:
+ m_cmd.port = atoi (optarg);
+ break;
+ case 1:
+ strncpy (m_cmd.iface, optarg, IFNAMSIZ - 1);
+ break;
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ i = atoi (optarg);
+ if (!tuners) {
+ memset (m_cmd.tuner_type_limit, 0, sizeof (m_cmd.tuner_type_limit));
+ }
+ m_cmd.tuner_type_limit[option_index - 2] = i;
+ tuners += i;
+ break;
+ case 7:
+ m_cmd.mld_start = 0;
+ break;
+ case 8:
+ strncpy (m_cmd.cmd_sock_path, optarg, _POSIX_PATH_MAX - 1);
+ break;
+ default:
+ printf ("?? getopt returned character code 0%o ??\n", c);
+ }
+ }
+ // Implement command line argument processing here if applicable.
+ return true;
+}
+
+cam_pool_t *cPluginMcli::CAMFindByUUID (const char *uuid, int slot)
+{
+ cam_pool_t *cp;
+ for(int i=0; i<CAM_POOL_MAX; i++) {
+ cp = m_cam_pool + i;
+ if(cp->max >= 0 && !strcmp(cp->uuid, uuid) && (slot == -1 || slot == cp->slot)) {
+ return cp;
+ }
+ }
+ return NULL;
+}
+
+cam_pool_t *cPluginMcli::CAMPoolFindFree(void)
+{
+ for(int i=0; i<CAM_POOL_MAX; i++) {
+ cam_pool_t *cp = m_cam_pool + i;
+ if(cp->max == -1) {
+ return cp;
+ }
+ }
+ return NULL;
+}
+int cPluginMcli::CAMPoolAdd(netceiver_info_t *nci)
+{
+ bool update = false;
+ int ret = 0;
+ for(int j=0; j < nci->cam_num; j++) {
+ update = false;
+ cam_pool_t *cp=CAMFindByUUID(nci->uuid, nci->cam[j].slot);
+ if(!cp) {
+ cp=CAMPoolFindFree();
+ if(!ret) {
+ ret = 1;
+ }
+ } else {
+ update = true;
+ ret = 2;
+ }
+ if(!cp){
+ return ret;
+ }
+ if (nci->cam[j].status) {
+ switch (nci->cam[j].flags) {
+ case CA_SINGLE:
+ case CA_MULTI_SID:
+ cp->max = 1;
+ break;
+ case CA_MULTI_TRANSPONDER:
+ cp->max = nci->cam[j].max_sids/* - nci->cam[j].use_sids*/;
+ break;
+ }
+ } else {
+ cp->max = 0;
+ }
+ cp->status = nci->cam[j].status;
+ if(!update) {
+ cp->slot = nci->cam[j].slot;
+ strcpy(cp->uuid, nci->uuid);
+ cp->use = 0;
+ }
+ }
+ return ret;
+}
+bool cPluginMcli::CAMPoolDel(const char *uuid)
+{
+ cam_pool_t *cp;
+ bool ret=false;
+ for(int i=0; i<CAM_POOL_MAX; i++) {
+ cp = m_cam_pool + i;
+ if(cp->max>=0 && !strcmp(cp->uuid, uuid)) {
+ cp->max = -1;
+ ret=true;
+ }
+ }
+ return ret;
+}
+
+cam_pool_t *cPluginMcli::CAMAvailable (const char *uuid, int slot, bool lock)
+{
+ cam_pool_t *ret = NULL;
+ if(lock) {
+ Lock();
+ }
+ cam_pool_t *cp;
+ for(int i=0; i<CAM_POOL_MAX; i++) {
+ cp = m_cam_pool + i;
+ if(cp->max>0 && (!uuid || !strcmp(cp->uuid, uuid)) && (slot == -1 || (cp->slot == slot))) {
+ if((cp->max - cp->use) > 0){
+ ret = cp;
+ break;
+ }
+ }
+ }
+#ifdef DEBUG_RESOURCES
+ if(ret) {
+ printf("CAMAvailable %s %d -> %s %d\n", uuid, slot, ret->uuid, ret->slot);
+ }
+#endif
+ if(lock) {
+ Unlock();
+ }
+ return ret;
+}
+cam_pool_t *cPluginMcli::CAMAlloc (const char *uuid, int slot)
+{
+ LOCK_THREAD;
+#ifdef DEBUG_RESOURCES
+ printf ("Alloc CAM %s %d\n", uuid, slot);
+#endif
+ cam_pool_t *cp;
+ if ((cp = CAMAvailable (uuid, slot, false))) {
+ cp->use++;
+ return cp;
+ }
+ return NULL;
+}
+int cPluginMcli::CAMFree (cam_pool_t *cp)
+{
+ LOCK_THREAD;
+#ifdef DEBUG_RESOURCES
+ printf ("FreeCAM %s %d\n", cp->uuid, cp->slot);
+#endif
+ if (cp->use > 0) {
+ cp->use--;
+ }
+ return cp->use;
+}
+bool cPluginMcli::CAMSteal(const char *uuid, int slot, bool force)
+{
+ for (cMcliDeviceObject * d = m_devs.First (); d; d = m_devs.Next (d)) {
+ cam_pool_t *cp=d->d()->GetCAMref();
+ if(d->d()->Priority()<0 && d->d()->GetCaEnable() && (slot == -1 || slot == cp->slot)) {
+#ifdef DEBUG_RESOURCES
+ printf("Can Steal CAM on slot %d from %d\n", slot, d->d()->CardIndex()+1);
+#endif
+ if(force) {
+ d->d ()->SetTempDisable (true);
+#ifdef DEBUG_RESOURCES
+ printf("Stole CAM on slot %d from %d\n", slot, d->d()->CardIndex()+1);
+#endif
+ }
+ return true;
+ }
+ }
+ return false;
+}
+
+satellite_list_t *cPluginMcli::TunerFindSatList(const netceiver_info_t *nc_info, const char *SatelliteListName) const
+{
+ if(SatelliteListName == NULL) {
+ return NULL;
+ }
+
+ for (int i = 0; i < nc_info->sat_list_num; i++) {
+ if (!strcmp (SatelliteListName, nc_info->sat_list[i].Name)) {
+// printf ("found uuid in sat list %d\n", i);
+ return nc_info->sat_list + i;
+ }
+ }
+ return NULL;
+}
+
+bool cPluginMcli::SatelitePositionLookup(const satellite_list_t *satlist, int pos) const
+{
+ if(satlist == NULL) {
+ return false;
+ }
+ for(int i=0; i<satlist->sat_num;i ++) {
+ satellite_info_t *s=satlist->sat+i;
+ switch(s->type){
+ case SAT_SRC_LNB:
+ case SAT_SRC_UNI:
+ if(pos == s->SatPos) {
+// printf("satlist found\n");
+ return true;
+ }
+ break;
+ case SAT_SRC_ROTOR:
+ if(pos>=s->SatPosMin && pos <=s->SatPosMax) {
+// printf("satlist found\n");
+ return true;
+ }
+ break;
+ }
+ }
+// printf("satlist not found\n");
+
+ return false;
+}
+
+bool cPluginMcli::TunerSatelitePositionLookup(tuner_pool_t *tp, int pos) const
+{
+ if((tp->type != FE_QPSK) && (tp->type != FE_DVBS2)) {
+ return true;
+ }
+ if(pos == NO_SAT_POS) {
+ return true;
+ }
+ nc_lock_list ();
+ netceiver_info_list_t *nc_list = nc_get_list ();
+ satellite_list_t *satlist=NULL;
+ for (int n = 0; n < nc_list->nci_num; n++) {
+ netceiver_info_t *nci = nc_list->nci + n;
+ int l=strlen(tp->uuid)-5;
+ if(strncmp(nci->uuid, tp->uuid, l)) {
+ continue;
+ }
+ satlist=TunerFindSatList(nci, tp->SatListName);
+ if(satlist) {
+ break;
+ }
+ }
+ bool ret;
+ if(satlist == NULL) {
+ ret = false;
+ } else {
+ ret=SatelitePositionLookup(satlist, pos);
+ }
+ nc_unlock_list ();
+ return ret;
+}
+tuner_pool_t *cPluginMcli::TunerFindByUUID (const char *uuid)
+{
+ tuner_pool_t *tp;
+ for(int i=0; i<TUNER_POOL_MAX; i++) {
+ tp=m_tuner_pool+i;
+ if(tp->type != -1 && !strcmp(tp->uuid, uuid)) {
+ return tp;
+ }
+ }
+ return NULL;
+}
+
+bool cPluginMcli::Ready()
+{
+ for(int i=0; i<CAM_POOL_MAX; i++)
+ if((m_cam_pool[i].max >= 0) && (DVBCA_CAMSTATE_INITIALISING == m_cam_pool[i].status)) return false;
+ for (cMcliDeviceObject * d = m_devs.First (); d; d = m_devs.Next (d))
+ if(d->d ()->HasInput()) return true;
+ return false;
+}
+
+#define MAX_TUNER_TYPE_COUNT (FE_DVBS2+1)
+int cPluginMcli::TunerCount() {
+ tuner_pool_t *tp;
+ int tct[MAX_TUNER_TYPE_COUNT];
+ memset(&tct, 0, sizeof(tct));
+ for(int i=0; i<TUNER_POOL_MAX; i++) {
+ tp=m_tuner_pool+i;
+ if((tp->type >= 0) && (tp->type < MAX_TUNER_TYPE_COUNT))
+ if(tct[tp->type] < m_cmd.tuner_type_limit[tp->type])
+ tct[tp->type]++;
+ }
+ int tc=0;
+ for(int i=0; i<MAX_TUNER_TYPE_COUNT; i++)
+ tc+=tct[i];
+ return tc;
+}
+
+int cPluginMcli::TunerCountByType (const fe_type_t type)
+{
+ int ret=0;
+ tuner_pool_t *tp;
+ for(int i=0; i<TUNER_POOL_MAX; i++) {
+ tp=m_tuner_pool+i;
+ if(tp->inuse && tp->type == type) {
+ ret++;
+ }
+ }
+ return ret;
+}
+
+bool cPluginMcli::TunerPoolAdd(tuner_info_t *t)
+{
+ tuner_pool_t *tp;
+ for(int i=0; i<TUNER_POOL_MAX; i++) {
+ tp=m_tuner_pool+i;
+ if(tp->type == -1) {
+ tp->type=t->fe_info.type;
+ strcpy(tp->uuid, t->uuid);
+ strcpy(tp->SatListName, t->SatelliteListName);
+ return true;
+ }
+ }
+ return false;
+}
+bool cPluginMcli::TunerPoolDel(tuner_pool_t *tp)
+{
+ if(tp->type != -1) {
+ tp->type=-1;
+ return true;
+ }
+ return false;
+}
+
+tuner_pool_t *cPluginMcli::TunerAvailable(fe_type_t type, int pos, bool lock)
+{
+ tuner_pool_t *tp;
+ if(lock) {
+ Lock();
+ }
+// printf("TunerAvailable: %d %d\n",type, pos);
+ if (TunerCountByType (type) == m_cmd.tuner_type_limit[type]) {
+#ifdef DEBUG_RESOURCES
+ //printf("Type %d limit (%d) reached\n", type, m_cmd.tuner_type_limit[type]);
+#endif
+ if(lock) {
+ Unlock();
+ }
+ return NULL;
+ }
+
+ for(int i=0; i<TUNER_POOL_MAX; i++) {
+ tp=m_tuner_pool+i;
+// printf("Tuner %d(%p), type %d, inuse %d\n", i, tp, tp->type, tp->inuse);
+
+ if(tp->inuse) {
+ continue;
+ }
+ if(tp->type != type) {
+ continue;
+ }
+ if(TunerSatelitePositionLookup(tp, pos)) {
+// printf("TunerAvailable: %d/%p\n",i,tp);
+ if(lock) {
+ Unlock();
+ }
+ return tp;
+ }
+ }
+ if(lock) {
+ Unlock();
+ }
+ return NULL;
+}
+
+tuner_pool_t *cPluginMcli::TunerAlloc(fe_type_t type, int pos, bool lock)
+{
+ tuner_pool_t *tp;
+ if(lock) {
+ Lock();
+ }
+ tp=TunerAvailable(type, pos, false);
+ if(tp) {
+ tp->inuse=true;
+#ifdef DEBUG_RESOURCES
+ printf("TunerAlloc: %p type %d\n",tp, tp->type);
+#endif
+ if(lock) {
+ Unlock();
+ }
+ return tp;
+ }
+ if(lock) {
+ Unlock();
+ }
+ return NULL;
+}
+bool cPluginMcli::TunerFree(tuner_pool_t *tp, bool lock)
+{
+ if(lock) {
+ Lock();
+ }
+ if(tp->inuse) {
+ tp->inuse=false;
+#ifdef DEBUG_RESOURCES
+ printf("TunerFree: %p type %d\n",tp, tp->type);
+#endif
+ if(lock) {
+ Unlock();
+ }
+ return true;
+ }
+ if(lock) {
+ Unlock();
+ }
+ return false;
+}
+
+void cPluginMcli::Action (void)
+{
+ netceiver_info_list_t *nc_list = nc_get_list ();
+// printf ("Looking for netceivers out there....\n");
+#if 1 //ndef REELVDR
+ bool channel_switch_ok = false;
+#endif
+#define NOTIFY_CAM_CHANGE 1
+#ifdef NOTIFY_CAM_CHANGE
+ int cam_stats[CAM_POOL_MAX] = { 0 };
+ char menu_strings[CAM_POOL_MAX][MAX_MENU_STR_LEN];
+ bool first_run = true;
+
+ for (int i = 0; i < CAM_POOL_MAX; i++)
+ menu_strings[i][0] = '\0';
+#endif
+ /** lets inform vdr and its plugins if TunerChange event happened */
+ bool netCVChanged;
+
+ while (Running ()) {
+ netCVChanged = false;
+ Lock ();
+ nc_lock_list ();
+ time_t now = time (NULL);
+ bool tpa = false;
+
+ for (int n = 0; n < nc_list->nci_num; n++) {
+ netceiver_info_t *nci = nc_list->nci + n;
+ if ((now - nci->lastseen) > MCLI_DEVICE_TIMEOUT) {
+ if(CAMPoolDel(nci->uuid)) {
+ printf ("mcli: Remove CAMs from NetCeiver %s\n", nci->uuid);
+ isyslog ("mcli: Remove CAMs from NetCeiver %s\n", nci->uuid);
+ netCVChanged = true;
+ }
+ } else {
+ int cpa = CAMPoolAdd(nci);
+ if(cpa==1) {
+ printf ("mcli: Add CAMs from NetCeiver %s -> %d\n", nci->uuid, cpa);
+ isyslog ("mcli: Add CAMs from NetCeiver %s -> %d\n", nci->uuid, cpa);
+ netCVChanged = true;
+ }
+ }
+
+#if NOTIFY_CAM_CHANGE
+ if (n == 0) {
+ for(int j = 0; j < nci->cam_num && j < CAM_POOL_MAX; j++) {
+ if (nci->cam[j].status != cam_stats[j]) {
+ char buf[64];
+ if (nci->cam[j].status) {
+ if(nci->cam[j].status == 2 && !first_run) {
+ snprintf(buf, 64, tr("Module '%s' ready"), nci->cam[j].menu_string);
+ Skins.QueueMessage(mtInfo, buf);
+ }
+ cam_stats[j] = nci->cam[j].status;
+ strncpy(menu_strings[j], nci->cam[j].menu_string, MAX_MENU_STR_LEN);
+ } else if (nci->cam[j].status == 0) {
+ cam_stats[j] = nci->cam[j].status;
+ if (!first_run) {
+ snprintf(buf, 64, tr("Module '%s' removed"), (char*)menu_strings[j]);
+ Skins.QueueMessage(mtInfo, buf);
+ }
+ menu_strings[j][0] = '\0';
+ }
+ }
+ }
+ first_run = false;
+ }
+#endif
+
+ for (int i = 0; i < nci->tuner_num; i++) {
+ tuner_pool_t *t = TunerFindByUUID (nci->tuner[i].uuid);
+ if (((now - nci->lastseen) > MCLI_DEVICE_TIMEOUT) || (nci->tuner[i].preference < 0) || !strlen (nci->tuner[i].uuid)) {
+ if (t) {
+ int pos=TunerPoolDel(t);
+ printf ("mcli: Remove Tuner %s [%s] @ %d\n", nci->tuner[i].fe_info.name, nci->tuner[i].uuid, pos);
+ isyslog ("mcli: Remove Tuner %s [%s] @ %d", nci->tuner[i].fe_info.name, nci->tuner[i].uuid, pos);
+ netCVChanged = true;
+ }
+ continue;
+ }
+ if (!t) {
+ tpa=TunerPoolAdd(nci->tuner+i);
+ printf ("mcli: Add Tuner: %s [%s], Type %d @ %d\n", nci->tuner[i].fe_info.name, nci->tuner[i].uuid, nci->tuner[i].fe_info.type, tpa);
+ isyslog ("mcli: Add Tuner: %s [%s], Type %d @ %d", nci->tuner[i].fe_info.name, nci->tuner[i].uuid, nci->tuner[i].fe_info.type, tpa);
+ netCVChanged = true;
+ }
+ }
+ }
+ nc_unlock_list ();
+ Unlock ();
+ UpdateDevices();
+
+ if (netCVChanged) {
+ cPluginManager::CallAllServices("NetCeiver changed");
+ }
+
+//TB: reelvdr itself tunes if the first tuner appears, don't do it twice
+#if 1 //ndef REELVDR
+ if (tpa) {
+ if (!channel_switch_ok) { // the first tuner that was found, so make VDR retune to the channel it wants...
+ cChannel *ch = Channels.GetByNumber (cDevice::CurrentChannel ());
+ if (ch) {
+ printf("cDevice::PrimaryDevice ()%p\n", cDevice::PrimaryDevice ());
+ channel_switch_ok = cDevice::PrimaryDevice ()->SwitchChannel (ch, true);
+ }
+ }
+ } else {
+ channel_switch_ok = 0;
+ }
+#endif
+
+#ifdef TEMP_DISABLE_DEVICE
+ TempDisableDevices();
+#endif
+ usleep (250 * 1000);
+ }
+}
+void cPluginMcli::TempDisableDevices(bool now)
+{
+ for (cMcliDeviceObject * d = m_devs.First (); d; d = m_devs.Next (d)) {
+ d->d ()->SetTempDisable (now);
+ }
+
+}
+bool cPluginMcli::Initialize (void)
+{
+ return InitMcli ();
+}
+
+
+bool cPluginMcli::Start (void)
+{
+// printf ("cPluginMcli::Start\n");
+ isyslog("mcli v"MCLI_PLUGIN_VERSION" started");
+#ifdef REELVDR
+ if (access("/dev/dvb/adapter0", F_OK) != 0) //TB: this line allows the client to be used with usb-sticks without conflicts
+#endif
+ cThread::Start ();
+ // Start any background activities the plugin shall perform.
+ return true;
+}
+
+void cPluginMcli::Stop (void)
+{
+// printf ("cPluginMcli::Stop\n");
+ cThread::Cancel (0);
+ for (cMcliDeviceObject * d = m_devs.First (); d; d = m_devs.Next (d)) {
+ d->d ()->SetEnable (false);
+ }
+ // Stop any background activities the plugin is performing.
+}
+
+void cPluginMcli::Housekeeping (void)
+{
+ // printf ("cPluginMcli::Housekeeping\n");
+}
+
+void cPluginMcli::MainThreadHook (void)
+{
+// printf("cPluginMcli::MainThreadHook\n");
+ if (reconf) {
+ reconfigure ();
+ reconf = 0;
+ }
+#if 0
+ cOsdObject *MyMenu = AltMenuAction ();
+ if (MyMenu) { // is there any cam-menu waiting?
+ if (cControl::Control ()) {
+ cControl::Control ()->Hide ();
+ }
+ MyMenu->Show ();
+ }
+#endif
+}
+
+cString cPluginMcli::Active (void)
+{
+// printf ("cPluginMcli::Active\n");
+ // Return a message string if shutdown should be postponed
+ return NULL;
+}
+
+time_t cPluginMcli::WakeupTime (void)
+{
+// printf ("cPluginMcli::WakeupTime\n");
+ // Return custom wakeup time for shutdown script
+ return 0;
+}
+
+void cPluginMcli::reconfigure (void)
+{
+ Lock();
+ for (cMcliDeviceObject * d = m_devs.First (); d;) {
+ cMcliDeviceObject *next = m_devs.Next (d);
+ d->d ()->SetEnable (false);
+ d->d ()->ExitMcli ();
+ d = next;
+ }
+ ExitMcli ();
+ memset (m_tuner_pool, 0, sizeof(tuner_pool_t)*TUNER_POOL_MAX);
+ for(int i=0; i<TUNER_POOL_MAX; i++) {
+ m_tuner_pool[i].type = -1;
+ }
+ for(int i=0; i<CAM_POOL_MAX; i++) {
+ m_cam_pool[i].max = -1;
+ }
+ InitMcli ();
+ for (cMcliDeviceObject * d = m_devs.First (); d; d = m_devs.Next (d)) {
+ d->d ()->InitMcli ();
+ }
+ Unlock();
+ usleep(3*1000*1000);
+ UpdateDevices();
+}
+
+void cPluginMcli::UpdateDevices() {
+ int tc = TunerCount();
+ int dc = min(tc, m_devs.Count());
+ int c = dc;
+ for (cMcliDeviceObject * d = m_devs.First (); d; d = m_devs.Next (d)) {
+ if(c>0) {
+ if(!d->d ()->HasInput())
+ d->d ()->SetEnable(true);
+ c--;
+ } else if(d->d ()->HasInput())
+ if(!d->d ()->Receiving())
+ d->d ()->SetEnable(false);
+ }
+ static int last_dc=0;
+ if(last_dc != dc) isyslog("%d tuner available: enabling %d devices", tc, dc);
+ last_dc = dc;
+}
+
+cOsdObject *cPluginMcli::MainMenuAction (void)
+{
+// printf ("cPluginMcli::MainMenuAction\n");
+ // Perform the action when selected from the main VDR menu.
+ return new cCamMenu (&m_cmd);
+}
+
+
+cMenuSetupPage *cPluginMcli::SetupMenu (void)
+{
+// printf ("cPluginMcli::SetupMenu\n");
+ // Return a setup menu in case the plugin supports one.
+ return new cMenuSetupMcli (&m_cmd);
+}
+
+bool cPluginMcli::SetupParse (const char *Name, const char *Value)
+{
+// printf ("cPluginMcli::SetupParse\n");
+ if (!strcasecmp (Name, "DVB-C") && m_cmd.tuner_type_limit[FE_QAM] == MCLI_MAX_DEVICES)
+ m_cmd.tuner_type_limit[FE_QAM] = atoi (Value);
+ else if (!strcasecmp (Name, "DVB-T") && m_cmd.tuner_type_limit[FE_OFDM] == MCLI_MAX_DEVICES)
+ m_cmd.tuner_type_limit[FE_OFDM] = atoi (Value);
+ else if (!strcasecmp (Name, "DVB-S") && m_cmd.tuner_type_limit[FE_QPSK] == MCLI_MAX_DEVICES)
+ m_cmd.tuner_type_limit[FE_QPSK] = atoi (Value);
+ else if (!strcasecmp (Name, "DVB-S2") && m_cmd.tuner_type_limit[FE_DVBS2] == MCLI_MAX_DEVICES)
+ m_cmd.tuner_type_limit[FE_DVBS2] = atoi (Value);
+ else
+ return false;
+ return true;
+}
+
+bool cPluginMcli::Service (const char *Id, void *Data)
+{
+ //printf ("cPluginMcli::Service: \"%s\"\n", Id);
+ mclituner_info_t *infos = (mclituner_info_t *) Data;
+
+ if (Id && strcmp (Id, "GetTunerInfo") == 0) {
+ int j=0;
+ time_t now = time (NULL);
+ netceiver_info_list_t *nc_list = nc_get_list ();
+ nc_lock_list ();
+ for (int n = 0; n < nc_list->nci_num; n++) {
+ netceiver_info_t *nci = nc_list->nci + n;
+ if ((now - nci->lastseen) > MCLI_DEVICE_TIMEOUT) {
+ continue;
+ }
+ for (int i = 0; i < nci->tuner_num && j < MAX_TUNERS_IN_MENU; i++) {
+ strcpy (infos->name[j], nci->tuner[i].fe_info.name);
+ infos->type[j] = nci->tuner[i].fe_info.type;
+ infos->preference[j++] = nci->tuner[i].preference;
+ //printf("Tuner: %s\n", nci->tuner[i].fe_info.name);
+ }
+ }
+ nc_unlock_list ();
+ return true;
+ } else if (Id && strcmp (Id, "Reinit") == 0) {
+ if (Data && strlen ((char *) Data) && (strncmp ((char *) Data, "eth", 3) || strncmp ((char *) Data, "br", 2))) {
+ strncpy (m_cmd.iface, (char *) Data, IFNAMSIZ - 1);
+ }
+ reconfigure ();
+ return true;
+ } else if (Id && strcmp (Id, "Set tuner count") == 0) {
+ if (Data) {
+ mcli_tuner_count_t *tuner_count = (mcli_tuner_count_t*)Data;
+ int count;
+
+ count = tuner_count->dvb_c;
+ if (count < 0) count = MCLI_MAX_DEVICES;
+ //SetupParse("DVB-C", itoa(count));
+ m_cmd.tuner_type_limit[FE_QAM] = count;
+ /* save settings to .conf*/
+ SetupStore("DVB-C", count);
+
+ count = tuner_count->dvb_t;
+ if (count < 0) count = MCLI_MAX_DEVICES;
+ //SetupParse("DVB-T", itoa(count));
+ m_cmd.tuner_type_limit[FE_OFDM] = count;
+ /* save settings to .conf*/
+ SetupStore("DVB-T", count);
+
+ count = tuner_count->dvb_s;
+ if (count < 0) count = MCLI_MAX_DEVICES;
+ //SetupParse("DVB-S", itoa(count));
+ m_cmd.tuner_type_limit[FE_QPSK] = count;
+ /* save settings to .conf*/
+ SetupStore("DVB-S", count);
+
+ count = tuner_count->dvb_s2;
+ if (count < 0) count = MCLI_MAX_DEVICES;
+ //SetupParse("DVB-S2", itoa(count));
+ m_cmd.tuner_type_limit[FE_DVBS2] = count;
+ /* save settings to .conf*/
+ SetupStore("DVB-S2", count);
+ }
+ return true;
+ } // set tuner count
+ else if (Id && strcmp (Id, "Get tuner count") == 0) {
+ if (Data) {
+ mcli_tuner_count_t *tuner_count = (mcli_tuner_count_t*)Data;
+
+ tuner_count->dvb_c = TunerCountByType(FE_QAM);
+ tuner_count->dvb_t = TunerCountByType(FE_OFDM);
+ tuner_count->dvb_s = TunerCountByType(FE_QPSK);
+ tuner_count->dvb_s2 = TunerCountByType((fe_type_t)FE_DVBS2);
+ }
+ return true;
+ }
+ // Handle custom service requests from other plugins
+ return false;
+}
+
+const char **cPluginMcli::SVDRPHelpPages (void)
+{
+// printf ("cPluginMcli::SVDRPHelpPages\n");
+ // Return help text for SVDRP commands this plugin implements
+ static const char *HelpPages[] = {
+ "GETTC\n" " List available tuners.",
+ "REINIT [dev]\n" " Reinitalize the plugin on a certain network device - e.g.: plug mcli REINIT eth0",
+ NULL
+ };
+ return HelpPages;
+}
+
+cString cPluginMcli::SVDRPCommand (const char *Command, const char *Option, int &ReplyCode)
+{
+ typedef struct nrTuners
+ {
+ int sat;
+ int satS2;
+ int cable;
+ int terr;
+ } nrTuners_t;
+
+// printf ("cPluginMcli::SVDRPCommand\n");
+ // Process SVDRP commands this plugin implements
+
+ if (strcasecmp (Command, "REINIT") == 0) {
+ if (Option && (strncmp (Option, "eth", 3) || strncmp (Option, "br", 2))) {
+ strncpy (m_cmd.iface, (char *) Option, IFNAMSIZ - 1);
+ }
+ reconfigure ();
+ return cString ("Mcli-plugin: reconfiguring...");
+ }
+ else if (strcasecmp(Command, "GETTC") == 0)
+ {
+ std::stringstream sdat;
+ std::string sout;
+
+ char *buffer = NULL;
+ std::string strBuff;
+ FILE *file = NULL;
+
+ int cable =0;
+ int sat =0;
+ int satS2 = 0;
+ int terr = 0;
+ file = fopen("/etc/default/mcli", "r");
+ if(file)
+ {
+ cReadLine readline;
+ buffer = readline.Read(file);
+ while(buffer)
+ {
+ if(strstr(buffer, "DVB_C_DEVICES=\"") && !strstr(buffer, "\"\""))
+ cable = atoi(buffer+15);
+ if(strstr(buffer, "DVB_S_DEVICES=\"") && !strstr(buffer, "\"\""))
+ sat = atoi(buffer+15);
+ if(strstr(buffer, "DVB_S2_DEVICES=\"") && !strstr(buffer, "\"\""))
+ satS2 = atoi(buffer+16);
+ if(strstr(buffer, "DVB_T_DEVICES=\"") && !strstr(buffer, "\"\""))
+ terr = atoi(buffer+15);
+
+ buffer = readline.Read(file);
+ }
+ fclose(file);
+ }
+
+ nrTuners_t nrTunersPhys;
+ nrTunersPhys.sat = nrTunersPhys.satS2 = nrTunersPhys.terr = nrTunersPhys.cable = 0;
+ cPlugin *mcliPlugin = cPluginManager::GetPlugin("mcli");
+ if (mcliPlugin)
+ {
+ mclituner_info_t info;
+ for (int i = 0; i < MAX_TUNERS_IN_MENU; i++)
+ info.name[i][0] = '\0';
+ mcliPlugin->Service("GetTunerInfo", &info);
+ for (int i = 0; i < MAX_TUNERS_IN_MENU; i++)
+ {
+ if (info.preference[i] == -1 || strlen(info.name[i]) == 0)
+ break;
+ else
+ {
+ switch(info.type[i])
+ {
+ case FE_QPSK: // DVB-S
+ nrTunersPhys.sat++;
+ break;
+ case FE_DVBS2: // DVB-S2
+ nrTunersPhys.satS2++;
+ break;
+ case FE_OFDM: // DVB-T
+ nrTunersPhys.terr++;
+ break;
+ case FE_QAM: // DVB-C
+ nrTunersPhys.cable++;
+ break;
+ }
+ }
+ }
+ }
+
+ if ( cable > nrTunersPhys.cable )
+ cable = nrTunersPhys.cable;
+ if ( sat > nrTunersPhys.sat )
+ sat = nrTunersPhys.sat;
+ if ( satS2 > nrTunersPhys.satS2 )
+ satS2 = nrTunersPhys.sat;
+ if ( terr > nrTunersPhys.terr )
+ terr = nrTunersPhys.terr;
+
+ sdat.str("");
+ if ( asprintf( &buffer, "DVB_C_DEVICES=%d\n", cable ) >= 0 )
+ {
+ sdat.str(""); sdat << buffer;
+ sout += sdat.str();
+ free(buffer);
+ }
+
+ if ( asprintf( &buffer, "DVB_S_DEVICES=%d\n", sat ) >= 0 )
+ {
+ sdat.str(""); sdat << buffer;
+ sout += sdat.str();
+ free(buffer);
+ }
+
+ if ( asprintf( &buffer, "DVB_S2_DEVICES=%d\n", satS2 ) >= 0 )
+ {
+ sdat.str(""); sdat << buffer;
+ sout += sdat.str();
+ free(buffer);
+ }
+
+ if ( asprintf( &buffer, "DVB_T_DEVICES=%d\n", terr ) >= 0 )
+ {
+ sdat.str(""); sdat << buffer;
+ sout += sdat.str();
+ free(buffer);
+ }
+ ReplyCode = 215;
+ return cString( sout.c_str() );
+ }
+ return NULL;
+}
+
+VDRPLUGINCREATOR (cPluginMcli); // Don't touch this!
diff --git a/mcli.h b/mcli.h
new file mode 100644
index 0000000..d14795f
--- /dev/null
+++ b/mcli.h
@@ -0,0 +1,180 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ */
+
+/*
+ * mcli.c: A plugin for the Video Disk Recorder
+ */
+
+#include <vdr/plugin.h>
+#include <vdr/player.h>
+#include "filter.h"
+#include "device.h"
+#include "cam_menu.h"
+
+#define MCLI_DEVICE_VERSION "0.9.1"
+#define MCLI_PLUGIN_VERSION "0.9.1"
+#define MCLI_PLUGIN_DESCRIPTION trNOOP ("NetCeiver Client Application")
+#define MCLI_SETUPMENU_DESCRIPTION trNOOP ("NetCeiver Client Application")
+#define MCLI_MAINMENU_DESCRIPTION trNOOP ("Common Interface")
+
+#define MCLI_MAX_DEVICES 8
+#define MCLI_DEVICE_TIMEOUT 120
+
+#define TUNER_POOL_MAX 32
+#define CAM_POOL_MAX 10
+
+#define TEMP_DISABLE_DEVICE
+#define TEMP_DISABLE_TIMEOUT_DEFAULT (10)
+#define TEMP_DISABLE_TIMEOUT_SCAN (30)
+#define TEMP_DISABLE_TIMEOUT_CAOVERRIDE (30)
+#define LASTSEEN_TIMEOUT (10)
+//#define ENABLE_DEVICE_PRIORITY
+
+//#define DEBUG_PIDS
+//#define DEBUG_TUNE_EXTRA
+#define DEBUG_TUNE
+#define DEBUG_RESOURCES
+
+class cMcliDeviceObject:public cListObject
+{
+ public:
+ cMcliDeviceObject (cMcliDevice * d)
+ {
+ m_d = d;
+ }
+ ~cMcliDeviceObject (void)
+ {
+ }
+ cMcliDevice *d (void)
+ {
+ return m_d;
+ }
+ private:
+ cMcliDevice * m_d;
+};
+
+class cMcliDeviceList:public cList < cMcliDeviceObject >
+{
+ public:
+ cMcliDeviceList (void)
+ {
+ };
+ ~cMcliDeviceList () {
+ printf ("Delete my Dev list\n");
+ };
+};
+
+typedef struct tuner_pool {
+ int type;
+ char uuid[UUID_SIZE+1];
+ char SatListName[UUID_SIZE+1];
+ bool inuse;
+} tuner_pool_t;
+
+typedef struct cam_pool {
+ char uuid[UUID_SIZE+1];
+ int slot;
+ int use;
+ int max;
+ int status;
+} cam_pool_t;
+
+class cPluginMcli:public cPlugin, public cThread
+{
+ private:
+ // Add any member variables or functions you may need here.
+ cMcliDeviceList m_devs;
+ cmdline_t m_cmd;
+ UDPContext *m_cam_mmi;
+ cam_pool_t m_cam_pool[CAM_POOL_MAX];
+ int m_mmi_init_done;
+ int m_recv_init_done;
+ int m_mld_init_done;
+ int m_api_init_done;
+ tuner_pool_t m_tuner_pool[TUNER_POOL_MAX];
+ tuner_pool_t *TunerAvailableInt(fe_type_t type, int pos);
+
+ public:
+ cPluginMcli (void);
+ virtual ~ cPluginMcli ();
+ virtual const char *Version (void)
+ {
+ return MCLI_PLUGIN_VERSION;
+ }
+ virtual const char *Description (void)
+ {
+ return MCLI_PLUGIN_DESCRIPTION;
+ }
+ virtual const char *CommandLineHelp (void);
+ virtual bool ProcessArgs (int argc, char *argv[]);
+ virtual bool Initialize (void);
+ virtual bool Start (void);
+ virtual void Stop (void);
+ virtual void Housekeeping (void);
+ virtual void MainThreadHook (void);
+ virtual cString Active (void);
+ virtual time_t WakeupTime (void);
+#ifdef REELVDR
+ virtual bool HasSetupOptions (void)
+ {
+ return false;
+ }
+#endif
+ virtual const char *MenuSetupPluginEntry (void)
+ {
+#ifdef REELVDR
+ return NULL;
+#else
+ return MCLI_SETUPMENU_DESCRIPTION;
+#endif
+ }
+ virtual const char *MainMenuEntry (void)
+ {
+ return MCLI_MAINMENU_DESCRIPTION;
+ }
+ virtual cOsdObject *MainMenuAction (void);
+ virtual cMenuSetupPage *SetupMenu (void);
+ virtual bool SetupParse (const char *Name, const char *Value);
+ virtual bool Service (const char *Id, void *Data = NULL);
+ virtual const char **SVDRPHelpPages (void);
+ virtual cString SVDRPCommand (const char *Command, const char *Option, int &ReplyCode);
+ virtual void Action (void);
+
+ void ExitMcli (void);
+ bool InitMcli (void);
+ void reconfigure (void);
+ void UpdateDevices();
+
+ int CAMPoolAdd(netceiver_info_t *nci);
+ bool CAMPoolDel(const char *uuid);
+ cam_pool_t *CAMPoolFindFree(void);
+ cam_pool_t *CAMFindByUUID (const char *uuid, int slot=-1);
+ cam_pool_t *CAMAvailable (const char *uuid=NULL, int slot=-1, bool lock=true);
+ cam_pool_t *CAMAlloc (const char *uuid=NULL, int slot=-1);
+ int CAMFree (cam_pool_t *cp);
+ bool CAMSteal(const char *uuid=NULL, int slot=-1, bool force=false);
+
+ satellite_list_t *TunerFindSatList(const netceiver_info_t *nc_info, const char *SatelliteListName) const;
+ bool SatelitePositionLookup(const satellite_list_t *satlist, int pos) const;
+ bool TunerSatelitePositionLookup(tuner_pool_t *tp, int pos) const;
+
+ tuner_pool_t *TunerFindByUUID (const char *uuid);
+ bool Ready();
+ int TunerCount();
+ int TunerCountByType (const fe_type_t type);
+ bool TunerPoolAdd(tuner_info_t *t);
+ bool TunerPoolDel(tuner_pool_t *tp);
+ tuner_pool_t *TunerAvailable(fe_type_t type, int pos, bool lock=true);
+ tuner_pool_t *TunerAlloc(fe_type_t type, int pos, bool lock=true);
+ bool TunerFree(tuner_pool_t *tp, bool lock=true);
+
+ int CamPollText (mmi_info_t * text);
+ void TempDisableDevices(bool now=false);
+
+ virtual cOsdObject *AltMenuAction (void);
+};
diff --git a/mcli_service.h b/mcli_service.h
new file mode 100644
index 0000000..4daed2a
--- /dev/null
+++ b/mcli_service.h
@@ -0,0 +1,25 @@
+#ifndef MCLI_SERVICE_H
+#define MCLI_SERVICE_H
+
+#define MAX_TUNERS_IN_MENU 16
+
+typedef struct
+{
+ int type[MAX_TUNERS_IN_MENU];
+ char name[MAX_TUNERS_IN_MENU][128];
+ int preference[MAX_TUNERS_IN_MENU];
+} mclituner_info_t;
+
+
+/**
+ * struct used to get and set the number of tuner used by mcli
+ * negative value indicates : use all available tuners
+ */
+typedef struct
+{
+ int dvb_s;
+ int dvb_s2;
+ int dvb_t;
+ int dvb_c;
+} mcli_tuner_count_t;
+#endif
diff --git a/mcliheaders.h b/mcliheaders.h
new file mode 100644
index 0000000..41de926
--- /dev/null
+++ b/mcliheaders.h
@@ -0,0 +1,29 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ */
+
+#ifndef VDR_MCLI_HEADERS_H
+#define VDR_MCLI_HEADERS_H
+
+#define CLIENT
+#define API_SOCK
+#include <mcast/common/defs.h>
+#include <mcast/common/version.h>
+#include <mcast/common/list.h>
+#include <mcast/common/satlists.h>
+#include <mcast/common/mcast.h>
+#include <mcast/common/recv_ccpp.h>
+#include <mcast/client/recv_tv.h>
+#include <mcast/client/mld_reporter.h>
+#include <mcast/client/tca_handler.h>
+#include <mcast/client/tra_handler.h>
+#include <mcast/common/tools.h>
+#include <mcast/client/api_server.h>
+#include <mcast/client/mmi_handler.h>
+
+
+#endif // VDR_MCLI_HEADERS_H
diff --git a/packetbuffer.c b/packetbuffer.c
new file mode 100644
index 0000000..0e2b53d
--- /dev/null
+++ b/packetbuffer.c
@@ -0,0 +1,283 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ */
+
+#include <vdr/plugin.h>
+#include <sys/time.h>
+#include "packetbuffer.h"
+
+uint64_t Now (void)
+{
+#if 0
+ struct timeval t;
+ if (gettimeofday (&t, NULL) == 0)
+ return (uint64_t (t.tv_sec)) * 1000 + t.tv_usec / 1000;
+ return 0;
+#else
+ return clock();
+#endif
+}
+
+//--------------------------------------------------------------------------
+//--------------------------------------------------------------------------
+cMyPacketBuffer::cMyPacketBuffer (int Size, int Packets)
+{
+ if (Packets == 0)
+ Packets = Size / 2048;
+
+ // Make Packets a power of 2 to avoid expensive modulo
+ int n = 1;
+ for (int i = 0; i < 16; i++) {
+ if (n >= Packets) {
+ Packets = n;
+ break;
+ }
+ n <<= 1;
+ }
+
+ dataBuffer = (uchar *) malloc (Size);
+ memset (dataBuffer, 0, Size);
+ posBuffer = (posData *) malloc (Packets * sizeof (posData));
+ pthread_mutex_init (&m_lock, NULL);
+
+ posSize = Packets;
+ dataSize = Size;
+ memset (posBuffer, 0, Packets * sizeof (posData));
+ rp = wp = 0;
+ posRead = NULL;
+ posWrite = NULL;
+ posReadNum = 0;
+ invalidate = 0;
+ putTimeout = getTimeout = 0;
+}
+
+//--------------------------------------------------------------------------
+cMyPacketBuffer::~cMyPacketBuffer (void)
+{
+ free (dataBuffer);
+ free (posBuffer);
+}
+
+//--------------------------------------------------------------------------
+int cMyPacketBuffer::FindSpace (int size)
+{
+ int wpm = (wp - 1) & (posSize - 1);
+ posData *pr, *pw;
+
+ if (wpm < 0)
+ wpm += posSize;
+
+ if (rp == wp) {
+ if (size > dataSize)
+ return -1;
+ return 0;
+ }
+ pr = posBuffer + rp;
+ pw = posBuffer + wpm;
+
+ if (pr->offset <= pw->offset) {
+ if (pw->offset + pw->realSize + size < dataSize) {
+ return pw->offset + pw->realSize;
+ }
+ if (size < pr->offset)
+ return 0;
+ return -1;
+ } else {
+ if (pw->offset + pw->realSize + size < dataSize)
+ return pw->offset + pw->realSize;
+ return -1;
+ }
+ return -1;
+}
+
+//--------------------------------------------------------------------------
+uchar *cMyPacketBuffer::PutStart (int size)
+{
+ uint64_t starttime = 0;
+ int offset;
+ int nwp;
+ int rsize;
+ pthread_mutex_lock (&m_lock);
+// rsize= (size+15)&~15;
+ rsize = size;
+ while (true) {
+ offset = FindSpace (rsize);
+ if (offset != -1)
+ break;
+ if (putTimeout && !starttime)
+ starttime = Now ();
+ if (!putTimeout || (Now () - starttime) > (uint64_t) (putTimeout)) {
+ pthread_mutex_unlock (&m_lock);
+ return NULL;
+ }
+ usleep (5 * 1000);
+ }
+ nwp = (wp) & (posSize - 1);
+
+ posWrite = posBuffer + nwp;
+ posWrite->offset = offset;
+ posWrite->realSize = rsize;
+
+// printf("PUTSTART wp %i, start %x\n",nwp, offset);
+ return dataBuffer + offset;
+}
+
+//--------------------------------------------------------------------------
+void cMyPacketBuffer::PutEnd (int size, int flags, uint64_t timestamp)
+{
+ if (!posWrite)
+ return;
+
+ if (size > posWrite->realSize)
+ size = posWrite->realSize;
+
+ posWrite->size = size;
+ posWrite->flags = flags;
+ posWrite->timestamp = timestamp;
+ wp = (wp + 1) & (posSize - 1);
+ pthread_mutex_unlock (&m_lock);
+
+}
+
+//--------------------------------------------------------------------------
+uchar *cMyPacketBuffer::GetStartSub (int *readp, int timeout, int *size, int *flags, uint64_t * timestamp)
+{
+ uint64_t starttime = 0;
+
+ if (*readp == wp && timeout)
+ starttime = Now ();
+// printf("GET rp %i wp %i\n",readp,wp);
+ while (*readp == wp) {
+ if (!timeout || (Now () - starttime) > (uint64_t) (timeout))
+ return 0;
+ usleep (20 * 1000);
+ }
+#if 0
+ if (readp > posSize) {
+ // Fixme sync
+ return 0;
+ }
+#endif
+ posRead = posBuffer + *readp;
+
+ if (flags)
+ *flags = posRead->flags;
+ if (size)
+ *size = posRead->size;
+ if (timestamp)
+ *timestamp = posRead->timestamp;
+// printf("GET rp %i, offset %x\n",readp,posRead->offset);
+ return dataBuffer + posRead->offset;
+}
+
+//--------------------------------------------------------------------------
+uchar *cMyPacketBuffer::GetStart (int *size, int *flags, uint64_t * timestamp)
+{
+ if (posRead) {
+#if 1
+ if (flags)
+ *flags = posRead->flags;
+ if (size)
+ *size = posRead->size;
+ return dataBuffer + posRead->offset;
+#else
+ GetEnd ();
+#endif
+ }
+
+ if (invalidate) {
+ rp = wp;
+ invalidate = 0;
+ return 0;
+ }
+ posReadNum = 1;
+ return GetStartSub (&rp, getTimeout, size, flags, timestamp);
+}
+
+//--------------------------------------------------------------------------
+void cMyPacketBuffer::GetEnd (void)
+{
+ if (!posRead)
+ return;
+ rp = (rp + posReadNum) & (posSize - 1);
+ posRead = NULL;
+ posReadNum = 0;
+}
+
+//--------------------------------------------------------------------------
+// Try to get multiple PES at once
+uchar *cMyPacketBuffer::GetStartMultiple (int maxsize, int *size, int *flags, uint64_t * timestamp)
+{
+ uchar *buf, *lastbuf, *startbuf;
+ int sz, fl;
+ int readp, packets;
+ int totalsize;
+ int startflags;
+ int timeout = getTimeout;
+ uint64_t tsp, starttsp;
+#if 0
+ if (posRead)
+ GetEnd ();
+#endif
+//printf("fill %d \r", (wp>=rp) ? wp-rp : posSize-rp+wp);
+ if (invalidate) {
+ rp = wp;
+ invalidate = 0;
+ return 0;
+ }
+ readp = rp;
+ startbuf = NULL;
+ lastbuf = NULL;
+ totalsize = 0;
+ packets = 0;
+ startflags = 0;
+ starttsp = 0;
+ while (1) {
+ sz = 0;
+ buf = GetStartSub (&readp, timeout, &sz, &fl, &tsp);
+// printf("GOT %x %i\n",buf,sz);
+ if (!startbuf) {
+ if (!buf)
+ return NULL;
+ startbuf = buf;
+ startflags = fl;
+ starttsp = tsp;
+ } else {
+ if (lastbuf + sz != buf || // Buffer wraparound or no buffer
+ (totalsize + sz) > maxsize || //
+ fl != 0) { // packet start
+ if (size)
+ *size = totalsize;
+ if (flags)
+ *flags = startflags;
+ if (timestamp)
+ *timestamp = starttsp;
+ posReadNum = packets;
+ return startbuf;
+ }
+ }
+ readp = (readp + 1) & (posSize - 1);
+ packets++;
+ totalsize += sz;
+ lastbuf = buf;
+ timeout = 0;
+ }
+ return NULL;
+}
+
+//--------------------------------------------------------------------------
+void cMyPacketBuffer::SetTimeouts (int PutTimeout, int GetTimeout)
+{
+ putTimeout = PutTimeout;
+ getTimeout = GetTimeout;
+}
+
+//--------------------------------------------------------------------------
+void cMyPacketBuffer::Invalidate (void)
+{
+ invalidate = 1;
+}
diff --git a/packetbuffer.h b/packetbuffer.h
new file mode 100644
index 0000000..d3d63f0
--- /dev/null
+++ b/packetbuffer.h
@@ -0,0 +1,57 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ */
+
+#ifndef VDR_MCLI_PACKETBUFFER_H
+#define VDR_MCLI_PACKETBUFFER_H
+
+#define USE_VDR_PACKET_BUFFER
+#ifdef USE_VDR_PACKET_BUFFER
+#include <vdr/ringbuffer.h>
+#endif
+//--------------------------------------------------------------------------
+// Packetized Buffer
+//--------------------------------------------------------------------------
+
+typedef struct
+{
+ int offset;
+ int size;
+ int realSize; // incl. alignment
+ int flags;
+ uint64_t timestamp;
+} posData;
+
+class cMyPacketBuffer
+{
+ int dataSize;
+ int posSize;
+ uchar *dataBuffer;
+ posData *posBuffer;
+ int rp, wp;
+ posData *posRead, *posWrite;
+ int posReadNum;
+ int invalidate;
+ int putTimeout, getTimeout;
+ pthread_mutex_t m_lock;
+
+ int FindSpace (int size);
+
+ uchar *GetStartSub (int *readp, int timeout, int *size, int *flags, uint64_t * timestamp);
+ public:
+ cMyPacketBuffer (int Size, int Packets);
+ ~cMyPacketBuffer ();
+ uchar *PutStart (int size);
+ void PutEnd (int size, int flags, uint64_t timestamp);
+ uchar *GetStart (int *size, int *flags, uint64_t * timestamp);
+ uchar *GetStartMultiple (int maxsize, int *size, int *flags, uint64_t * timestamp);
+ void GetEnd (void);
+// void GetEndMultiple(void);
+ void Invalidate (void);
+ void SetTimeouts (int PutTimeout, int GetTimeout);
+};
+#endif
diff --git a/patches/.svn/entries b/patches/.svn/entries
new file mode 100644
index 0000000..2a0dc74
--- /dev/null
+++ b/patches/.svn/entries
@@ -0,0 +1,232 @@
+10
+
+dir
+18963
+svn://reelbox.org/testing/src/vdr-plugins/src/mcli-1/patches
+svn://reelbox.org
+
+
+
+2011-07-12T13:36:23.313379Z
+16905
+rollercoaster
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+12be777f-adf9-0310-842f-e37ecc4c7426
+
+vdr-1.6.0-intcamdevices.patch
+file
+
+
+
+
+2012-09-27T17:22:49.486848Z
+d32580d7ee6e033fa8754b408ef17dad
+2011-07-12T13:36:23.313379Z
+16905
+rollercoaster
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+5742
+
+reelvdr-device-handling-patch.diff
+file
+
+
+
+
+2012-09-27T17:22:49.486848Z
+258a74a6d2dd9adfb93ba6e2cae04e6f
+2011-07-12T13:36:23.313379Z
+16905
+rollercoaster
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+5301
+
+vdr-1.6-device-consistent-destruct.patch
+file
+
+
+
+
+2012-09-27T17:22:49.486848Z
+a577595d5404ebeb755d3068843663a5
+2011-07-12T13:36:23.313379Z
+16905
+rollercoaster
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+3078
+
+vdr-1.6.0-altmenuaction.patch
+file
+
+
+
+
+2012-09-27T17:22:49.486848Z
+3fba8e9949af8cb9ebee9f659e49f531
+2011-07-12T13:36:23.313379Z
+16905
+rollercoaster
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1265
+
+vdr-1.6-section-read-abstraction.patch
+file
+
+
+
+
+2012-09-27T17:22:49.486848Z
+d73a367e8f7160ad8f3a29f0451d96b8
+2011-07-12T13:36:23.313379Z
+16905
+rollercoaster
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1773
+
+vdr-1.4.0-closefilter.patch
+file
+
+
+
+
+2012-09-27T17:22:49.486848Z
+b4de0862c8b127039dc5425780e4dfd4
+2011-07-12T13:36:23.313379Z
+16905
+rollercoaster
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1585
+
diff --git a/patches/.svn/text-base/reelvdr-device-handling-patch.diff.svn-base b/patches/.svn/text-base/reelvdr-device-handling-patch.diff.svn-base
new file mode 100644
index 0000000..d0592aa
--- /dev/null
+++ b/patches/.svn/text-base/reelvdr-device-handling-patch.diff.svn-base
@@ -0,0 +1,158 @@
+Index: device.c
+===================================================================
+--- device.c (Revision 10504)
++++ device.c (Arbeitskopie)
+@@ -270,14 +270,19 @@
+ for (int i = 0; i < MAXRECEIVERS; i++)
+ receiver[i] = NULL;
+
+- if (numDevices < MAXDEVICES)
+- device[numDevices++] = this;
+- else
+- esyslog("ERROR: too many devices!");
++ for (int i = 0; i < MAXDEVICES; i++)
++ if (!device[i]) {
++ device[i] = this;
++ numDevices++;
++ return;
++ }
++ esyslog("ERROR: too many devices!");
+ }
+
+ cDevice::~cDevice()
+ {
++ numDevices--;
++ device[DeviceNumber()] = NULL;
+ Detach(player);
+ for (int i = 0; i < MAXRECEIVERS; i++)
+ Detach(receiver[i]);
+@@ -290,7 +295,7 @@
+ {
+ for (time_t t0 = time(NULL); time(NULL) - t0 < Timeout; ) {
+ bool ready = true;
+- for (int i = 0; i < numDevices; i++) {
++ for (int i = 0; i < MAXDEVICES; i++) {
+ if (device[i] && !device[i]->Ready())
+ ready = false;
+ }
+@@ -322,7 +327,7 @@
+
+ int cDevice::DeviceNumber(void) const
+ {
+- for (int i = 0; i < numDevices; i++) {
++ for (int i = 0; i < MAXDEVICES; i++) {
+ if (device[i] == this)
+ return i;
+ }
+@@ -336,7 +341,7 @@
+ bool cDevice::SetPrimaryDevice(int n)
+ {
+ n--;
+- if (0 <= n && n < numDevices && device[n]) {
++ if (0 <= n && n < MAXDEVICES && device[n]) {
+ isyslog("setting primary device to %d", n + 1);
+ if (primaryDevice)
+ primaryDevice->MakePrimaryDevice(false);
+@@ -369,15 +374,17 @@
+
+ cDevice *cDevice::GetDevice(int Index)
+ {
+- return (0 <= Index && Index < numDevices) ? device[Index] : NULL;
++ return (0 <= Index && Index < MAXDEVICES) ? device[Index] : NULL;
+ }
+
+ cDevice *cDevice::GetDevice(const cChannel *Channel, int Priority, bool *NeedsDetachReceivers)
+ {
+ cDevice *d = NULL;
+ uint Impact = 0xFFFFFFFF; // we're looking for a device with the least impact
+- for (int i = 0; i < numDevices; i++) {
++ for (int i = 0; i < MAXDEVICES; i++) {
+ bool ndr;
++ if (device[i] == NULL)
++ continue; // this device was not allocated
+ #ifdef DETACH_UNUSED_DEVICES
+ if(!device[i]->Receiving()) {
+ isyslog("device %d (%p) not receiving", i, device[i]);
+@@ -419,10 +426,11 @@
+ void cDevice::Shutdown(void)
+ {
+ primaryDevice = NULL;
+- for (int i = 0; i < numDevices; i++) {
+- delete device[i];
+- device[i] = NULL;
++ for (int i = 0; i < MAXDEVICES; i++) {
++ if( device[i]) {
++ delete device[i];
+ }
++ }
+ }
+
+ uchar *cDevice::GrabImage(int &Size, bool Jpeg, int Quality, int SizeX, int SizeY)
+@@ -724,6 +732,16 @@
+ return -1;
+ }
+
++int cDevice::ReadFilter(int Handle, void *Buffer, size_t Length)
++{
++ return safe_read(Handle, Buffer, Length);
++}
++
++void cDevice::CloseFilter(int Handle)
++{
++ close(Handle);
++}
++
+ void cDevice::AttachFilter(cFilter *Filter)
+ {
+ if (sectionHandler)
+@@ -753,7 +771,7 @@
+
+ bool cDevice::ProvidesTransponderExclusively(const cChannel *Channel) const
+ {
+- for (int i = 0; i < numDevices; i++) {
++ for (int i = 0; i < MAXDEVICES; i++) {
+ if (device[i] && device[i] != this && device[i]->ProvidesTransponder(Channel))
+ return false;
+ }
+Index: device.h
+===================================================================
+--- device.h (Revision 10504)
++++ device.h (Arbeitskopie)
+@@ -326,6 +326,15 @@
+ ///< Opens a file handle for the given filter data.
+ ///< A derived device that provides section data must
+ ///< implement this function.
++ virtual int ReadFilter(int Handle, void *Buffer, size_t Length);
++ ///< Read from a handle for the given filter data.
++ ///< a derived class need not implement this function, because this
++ ///< is done by the default implementation.
++ virtual void CloseFilter(int Handle);
++ ///< Closes a file handle that has previously been opened
++ ///< by OpenFilter(). If this is as simple as calling close(Handle),
++ ///< a derived class need not implement this function, because this
++ ///< is done by the default implementation.
+ void AttachFilter(cFilter *Filter);
+ ///< Attaches the given filter to this device.
+ void Detach(cFilter *Filter);
+Index: sections.c
+===================================================================
+--- sections.c (Revision 10504)
++++ sections.c (Arbeitskopie)
+@@ -105,7 +105,7 @@
+ for (fh = filterHandles.First(); fh; fh = filterHandles.Next(fh)) {
+ if (fh->filterData.Is(FilterData->pid, FilterData->tid, FilterData->mask)) {
+ if (--fh->used <= 0) {
+- close(fh->handle);
++ device->CloseFilter(fh->handle);
+ filterHandles.Del(fh);
+ break;
+ }
+@@ -198,7 +198,7 @@
+ if (fh) {
+ // Read section data:
+ unsigned char buf[4096]; // max. allowed size for any EIT section
+- int r = safe_read(fh->handle, buf, sizeof(buf));
++ int r = device->ReadFilter(fh->handle, buf, sizeof(buf));
+ if (!DeviceHasLock)
+ continue; // we do the read anyway, to flush any data that might have come from a different transponder
+ if (r > 3) { // minimum number of bytes necessary to get section length
diff --git a/patches/.svn/text-base/vdr-1.4.0-closefilter.patch.svn-base b/patches/.svn/text-base/vdr-1.4.0-closefilter.patch.svn-base
new file mode 100644
index 0000000..cd87632
--- /dev/null
+++ b/patches/.svn/text-base/vdr-1.4.0-closefilter.patch.svn-base
@@ -0,0 +1,45 @@
+Index: device.c
+===================================================================
+--- device.c (Revision 10449)
++++ device.c (Arbeitskopie)
+@@ -724,6 +724,11 @@
+ return -1;
+ }
+
++void cDevice::CloseFilter(int Handle)
++{
++ close(Handle);
++}
++
+ void cDevice::AttachFilter(cFilter *Filter)
+ {
+ if (sectionHandler)
+Index: device.h
+===================================================================
+--- device.h (Revision 10449)
++++ device.h (Arbeitskopie)
+@@ -326,6 +326,11 @@
+ ///< Opens a file handle for the given filter data.
+ ///< A derived device that provides section data must
+ ///< implement this function.
++ virtual void CloseFilter(int Handle);
++ ///< Closes a file handle that has previously been opened
++ ///< by OpenFilter(). If this is as simple as calling close(Handle),
++ ///< a derived class need not implement this function, because this
++ ///< is done by the default implementation.
+ void AttachFilter(cFilter *Filter);
+ ///< Attaches the given filter to this device.
+ void Detach(cFilter *Filter);
+Index: sections.c
+===================================================================
+--- sections.c (Revision 10449)
++++ sections.c (Arbeitskopie)
+@@ -105,7 +105,7 @@
+ for (fh = filterHandles.First(); fh; fh = filterHandles.Next(fh)) {
+ if (fh->filterData.Is(FilterData->pid, FilterData->tid, FilterData->mask)) {
+ if (--fh->used <= 0) {
+- close(fh->handle);
++ device->CloseFilter(fh->handle);
+ filterHandles.Del(fh);
+ break;
+ }
diff --git a/patches/.svn/text-base/vdr-1.6-device-consistent-destruct.patch.svn-base b/patches/.svn/text-base/vdr-1.6-device-consistent-destruct.patch.svn-base
new file mode 100644
index 0000000..9299be0
--- /dev/null
+++ b/patches/.svn/text-base/vdr-1.6-device-consistent-destruct.patch.svn-base
@@ -0,0 +1,97 @@
+--- ../vdr-1.6.0/device.c 2009-01-26 20:26:49.000000000 +0100
++++ device.c 2009-01-26 22:32:03.000000000 +0100
+@@ -253,14 +253,19 @@
+ for (int i = 0; i < MAXRECEIVERS; i++)
+ receiver[i] = NULL;
+
+- if (numDevices < MAXDEVICES)
+- device[numDevices++] = this;
+- else
+- esyslog("ERROR: too many devices!");
++ for (int i = 0; i < MAXDEVICES; i++)
++ if (!device[i]) {
++ device[i] = this;
++ numDevices++;
++ return;
++ }
++ esyslog("ERROR: too many devices!");
+ }
+
+ cDevice::~cDevice()
+ {
++ numDevices--;
++ device[DeviceNumber()] = NULL;
+ Detach(player);
+ DetachAllReceivers();
+ delete liveSubtitle;
+@@ -272,7 +277,7 @@
+ {
+ for (time_t t0 = time(NULL); time(NULL) - t0 < Timeout; ) {
+ bool ready = true;
+- for (int i = 0; i < numDevices; i++) {
++ for (int i = 0; i < MAXDEVICES; i++) {
+ if (device[i] && !device[i]->Ready()) {
+ ready = false;
+ cCondWait::SleepMs(100);
+@@ -304,7 +309,7 @@
+
+ int cDevice::DeviceNumber(void) const
+ {
+- for (int i = 0; i < numDevices; i++) {
++ for (int i = 0; i < MAXDEVICES; i++) {
+ if (device[i] == this)
+ return i;
+ }
+@@ -318,7 +323,7 @@
+ bool cDevice::SetPrimaryDevice(int n)
+ {
+ n--;
+- if (0 <= n && n < numDevices && device[n]) {
++ if (0 <= n && n < MAXDEVICES && device[n]) {
+ isyslog("setting primary device to %d", n + 1);
+ if (primaryDevice)
+ primaryDevice->MakePrimaryDevice(false);
+@@ -352,7 +357,7 @@
+
+ cDevice *cDevice::GetDevice(int Index)
+ {
+- return (0 <= Index && Index < numDevices) ? device[Index] : NULL;
++ return (0 <= Index && Index < MAXDEVICES) ? device[Index] : NULL;
+ }
+
+ cDevice *cDevice::GetDevice(const cChannel *Channel, int Priority, bool LiveView)
+@@ -388,8 +393,8 @@
+ for (int j = 0; j < NumCamSlots || !NumUsableSlots; j++) {
+ if (NumUsableSlots && SlotPriority[j] > MAXPRIORITY)
+ continue; // there is no CAM available in this slot
+- for (int i = 0; i < numDevices; i++) {
+- if (device[i] == AvoidDevice)
++ for (int i = 0; i < MAXDEVICES; i++) {
++ if (device[i] == NULL || device[i] == AvoidDevice)
+ continue; // this device shall be temporarily avoided
+ if (Channel->Ca() && Channel->Ca() <= CA_DVB_MAX && Channel->Ca() != device[i]->CardIndex() + 1)
+ continue; // a specific card was requested, but not this one
+@@ -463,10 +468,11 @@
+ void cDevice::Shutdown(void)
+ {
+ primaryDevice = NULL;
+- for (int i = 0; i < numDevices; i++) {
+- delete device[i];
+- device[i] = NULL;
++ for (int i = 0; i < MAXDEVICES; i++) {
++ if( device[i]) {
++ delete device[i];
+ }
++ }
+ }
+
+ uchar *cDevice::GrabImage(int &Size, bool Jpeg, int Quality, int SizeX, int SizeY)
+@@ -703,7 +709,7 @@
+
+ bool cDevice::ProvidesTransponderExclusively(const cChannel *Channel) const
+ {
+- for (int i = 0; i < numDevices; i++) {
++ for (int i = 0; i < MAXDEVICES; i++) {
+ if (device[i] && device[i] != this && device[i]->ProvidesTransponder(Channel))
+ return false;
+ }
diff --git a/patches/.svn/text-base/vdr-1.6-section-read-abstraction.patch.svn-base b/patches/.svn/text-base/vdr-1.6-section-read-abstraction.patch.svn-base
new file mode 100644
index 0000000..3d1bea4
--- /dev/null
+++ b/patches/.svn/text-base/vdr-1.6-section-read-abstraction.patch.svn-base
@@ -0,0 +1,38 @@
+--- ../vdr-1.6.0/device.c 2009-01-26 20:26:49.000000000 +0100
++++ device.c 2009-01-26 23:12:59.000000000 +0100
+@@ -674,6 +680,11 @@
+ return -1;
+ }
+
++int cDevice::ReadFilter(int Handle, void *Buffer, size_t Length)
++{
++ return safe_read(Handle, Buffer, Length);
++}
++
+ void cDevice::CloseFilter(int Handle)
+ {
+ close(Handle);
+--- ../vdr-1.6.0/device.h 2009-01-26 20:26:49.000000000 +0100
++++ device.h 2009-01-26 23:12:41.000000000 +0100
+@@ -317,6 +317,10 @@
+ ///< Opens a file handle for the given filter data.
+ ///< A derived device that provides section data must
+ ///< implement this function.
++ virtual int ReadFilter(int Handle, void *Buffer, size_t Length);
++ ///< Read from a handle for the given filter data.
++ ///< a derived class need not implement this function, because this
++ ///< is done by the default implementation.
+ virtual void CloseFilter(int Handle);
+ ///< Closes a file handle that has previously been opened
+ ///< by OpenFilter(). If this is as simple as calling close(Handle),
+--- ../vdr-1.6.0/sections.c 2007-10-14 14:52:07.000000000 +0200
++++ sections.c 2009-01-26 23:14:00.000000000 +0100
+@@ -198,7 +198,7 @@
+ if (fh) {
+ // Read section data:
+ unsigned char buf[4096]; // max. allowed size for any EIT section
+- int r = safe_read(fh->handle, buf, sizeof(buf));
++ int r = device->ReadFilter(fh->handle, buf, sizeof(buf));
+ if (!DeviceHasLock)
+ continue; // we do the read anyway, to flush any data that might have come from a different transponder
+ if (r > 3) { // minimum number of bytes necessary to get section length
diff --git a/patches/.svn/text-base/vdr-1.6.0-altmenuaction.patch.svn-base b/patches/.svn/text-base/vdr-1.6.0-altmenuaction.patch.svn-base
new file mode 100644
index 0000000..4b06850
--- /dev/null
+++ b/patches/.svn/text-base/vdr-1.6.0-altmenuaction.patch.svn-base
@@ -0,0 +1,38 @@
+Index: plugin.h
+===================================================================
+--- plugin.h (revision 2072)
++++ plugin.h (working copy)
+@@ -45,7 +45,8 @@
+
+ virtual const char *MainMenuEntry(void);
+ virtual cOsdObject *MainMenuAction(void);
+-
++ virtual cOsdObject *AltMenuAction(void) { return NULL; };
++
+ virtual cMenuSetupPage *SetupMenu(void);
+ virtual bool SetupParse(const char *Name, const char *Value);
+ void SetupStore(const char *Name, const char *Value = NULL);
+Index: vdr.c
+===================================================================
+--- vdr.c (revision 2072)
++++ vdr.c (working copy)
+@@ -929,6 +929,19 @@
+ Recordings.Update();
+ DeletedRecordings.Update();
+ }
++ cPlugin *mcliPlugin = cPluginManager::GetPlugin("mcli");
++ if (mcliPlugin) {
++ if (!ShutdownHandler.countdown) { // if kPower has been pressed, cMenuShutdown takes precedence over other menus
++ cOsdObject *MyMenu = mcliPlugin->AltMenuAction();
++ if (MyMenu) { // is there any cam-menu waiting?
++ DELETE_MENU;
++ if (cControl::Control())
++ cControl::Control()->Hide();
++ Menu = MyMenu;
++ Menu->Show();
++ }
++ }
++ }
+ // CAM control:
+ if (!Menu && !cOsd::IsOpen())
+ Menu = CamControl();
diff --git a/patches/.svn/text-base/vdr-1.6.0-intcamdevices.patch.svn-base b/patches/.svn/text-base/vdr-1.6.0-intcamdevices.patch.svn-base
new file mode 100644
index 0000000..aab1fb4
--- /dev/null
+++ b/patches/.svn/text-base/vdr-1.6.0-intcamdevices.patch.svn-base
@@ -0,0 +1,78 @@
+Index: vdr-1.6.0-nocamdevices/device.c
+===================================================================
+--- vdr-1.6.0-nocamdevices/device.c
++++ vdr-1.6.0-nocamdevices/device.c 2008-04-27 18:55:37.000000000 +0300
+@@ -363,6 +363,7 @@
+ int NumCamSlots = CamSlots.Count();
+ int SlotPriority[NumCamSlots];
+ int NumUsableSlots = 0;
++ bool InternalCamNeeded = false;
+ if (Channel->Ca() >= CA_ENCRYPTED_MIN) {
+ for (cCamSlot *CamSlot = CamSlots.First(); CamSlot; CamSlot = CamSlots.Next(CamSlot)) {
+ SlotPriority[CamSlot->Index()] = MAXPRIORITY + 1; // assumes it can't be used
+@@ -376,7 +377,7 @@
+ }
+ }
+ if (!NumUsableSlots)
+- return NULL; // no CAM is able to decrypt this channel
++ InternalCamNeeded = true; // no CAM is able to decrypt this channel
+ }
+
+ bool NeedsDetachReceivers = false;
+@@ -392,11 +393,13 @@
+ continue; // this device shall be temporarily avoided
+ if (Channel->Ca() && Channel->Ca() <= CA_DVB_MAX && Channel->Ca() != device[i]->CardIndex() + 1)
+ continue; // a specific card was requested, but not this one
+- if (NumUsableSlots && !CamSlots.Get(j)->Assign(device[i], true))
++ if (InternalCamNeeded && !device[i]->HasInternalCam())
++ continue; // no CAM is able to decrypt this channel and the device uses vdr handled CAMs
++ if (NumUsableSlots && !device[i]->HasInternalCam() && !CamSlots.Get(j)->Assign(device[i], true))
+ continue; // CAM slot can't be used with this device
+ bool ndr;
+ if (device[i]->ProvidesChannel(Channel, Priority, &ndr)) { // this device is basicly able to do the job
+- if (NumUsableSlots && device[i]->CamSlot() && device[i]->CamSlot() != CamSlots.Get(j))
++ if (NumUsableSlots && !device[i]->HasInternalCam() && device[i]->CamSlot() && device[i]->CamSlot() != CamSlots.Get(j))
+ ndr = true; // using a different CAM slot requires detaching receivers
+ // Put together an integer number that reflects the "impact" using
+ // this device would have on the overall system. Each condition is represented
+@@ -410,18 +413,18 @@
+ imp <<= 1; imp |= device[i]->Receiving(); // avoid devices that are receiving
+ imp <<= 1; imp |= device[i] == cTransferControl::ReceiverDevice(); // avoid the Transfer Mode receiver device
+ imp <<= 8; imp |= min(max(device[i]->Priority() + MAXPRIORITY, 0), 0xFF); // use the device with the lowest priority (+MAXPRIORITY to assure that values -99..99 can be used)
+- imp <<= 8; imp |= min(max((NumUsableSlots ? SlotPriority[j] : 0) + MAXPRIORITY, 0), 0xFF); // use the CAM slot with the lowest priority (+MAXPRIORITY to assure that values -99..99 can be used)
++ imp <<= 8; imp |= min(max(((NumUsableSlots && !device[i]->HasInternalCam()) ? SlotPriority[j] : 0) + MAXPRIORITY, 0), 0xFF); // use the CAM slot with the lowest priority (+MAXPRIORITY to assure that values -99..99 can be used)
+ imp <<= 1; imp |= ndr; // avoid devices if we need to detach existing receivers
+ imp <<= 1; imp |= device[i]->IsPrimaryDevice(); // avoid the primary device
+- imp <<= 1; imp |= NumUsableSlots ? 0 : device[i]->HasCi(); // avoid cards with Common Interface for FTA channels
++ imp <<= 1; imp |= (NumUsableSlots || InternalCamNeeded) ? 0 : device[i]->HasCi(); // avoid cards with Common Interface for FTA channels
+ imp <<= 1; imp |= device[i]->HasDecoder(); // avoid full featured cards
+- imp <<= 1; imp |= NumUsableSlots ? !ChannelCamRelations.CamDecrypt(Channel->GetChannelID(), j + 1) : 0; // prefer CAMs that are known to decrypt this channel
++ imp <<= 1; imp |= (NumUsableSlots && !device[i]->HasInternalCam()) ? !ChannelCamRelations.CamDecrypt(Channel->GetChannelID(), j + 1) : 0; // prefer CAMs that are known to decrypt this channel
+ if (imp < Impact) {
+ // This device has less impact than any previous one, so we take it.
+ Impact = imp;
+ d = device[i];
+ NeedsDetachReceivers = ndr;
+- if (NumUsableSlots)
++ if (NumUsableSlots && !device[i]->HasInternalCam())
+ s = CamSlots.Get(j);
+ }
+ }
+Index: vdr-1.6.0-nocamdevices/device.h
+===================================================================
+--- vdr-1.6.0-nocamdevices/device.h
++++ vdr-1.6.0-nocamdevices/device.h 2008-04-27 18:55:49.000000000 +0300
+@@ -335,6 +335,12 @@
+ public:
+ virtual bool HasCi(void);
+ ///< Returns true if this device has a Common Interface.
++ virtual bool HasInternalCam(void) { return false; }
++ ///< Returns true if this device handles encrypted channels itself
++ ///< without VDR assistance. This can be e.g. when the device is a
++ ///< client that gets the stream from another VDR instance that has
++ ///< already decrypted the stream. In this case ProvidesChannel()
++ ///< shall check whether the channel can be decrypted.
+ void SetCamSlot(cCamSlot *CamSlot);
+ ///< Sets the given CamSlot to be used with this device.
+ cCamSlot *CamSlot(void) const { return camSlot; }
+
diff --git a/patches/reelvdr-device-handling-patch.diff b/patches/reelvdr-device-handling-patch.diff
new file mode 100644
index 0000000..d0592aa
--- /dev/null
+++ b/patches/reelvdr-device-handling-patch.diff
@@ -0,0 +1,158 @@
+Index: device.c
+===================================================================
+--- device.c (Revision 10504)
++++ device.c (Arbeitskopie)
+@@ -270,14 +270,19 @@
+ for (int i = 0; i < MAXRECEIVERS; i++)
+ receiver[i] = NULL;
+
+- if (numDevices < MAXDEVICES)
+- device[numDevices++] = this;
+- else
+- esyslog("ERROR: too many devices!");
++ for (int i = 0; i < MAXDEVICES; i++)
++ if (!device[i]) {
++ device[i] = this;
++ numDevices++;
++ return;
++ }
++ esyslog("ERROR: too many devices!");
+ }
+
+ cDevice::~cDevice()
+ {
++ numDevices--;
++ device[DeviceNumber()] = NULL;
+ Detach(player);
+ for (int i = 0; i < MAXRECEIVERS; i++)
+ Detach(receiver[i]);
+@@ -290,7 +295,7 @@
+ {
+ for (time_t t0 = time(NULL); time(NULL) - t0 < Timeout; ) {
+ bool ready = true;
+- for (int i = 0; i < numDevices; i++) {
++ for (int i = 0; i < MAXDEVICES; i++) {
+ if (device[i] && !device[i]->Ready())
+ ready = false;
+ }
+@@ -322,7 +327,7 @@
+
+ int cDevice::DeviceNumber(void) const
+ {
+- for (int i = 0; i < numDevices; i++) {
++ for (int i = 0; i < MAXDEVICES; i++) {
+ if (device[i] == this)
+ return i;
+ }
+@@ -336,7 +341,7 @@
+ bool cDevice::SetPrimaryDevice(int n)
+ {
+ n--;
+- if (0 <= n && n < numDevices && device[n]) {
++ if (0 <= n && n < MAXDEVICES && device[n]) {
+ isyslog("setting primary device to %d", n + 1);
+ if (primaryDevice)
+ primaryDevice->MakePrimaryDevice(false);
+@@ -369,15 +374,17 @@
+
+ cDevice *cDevice::GetDevice(int Index)
+ {
+- return (0 <= Index && Index < numDevices) ? device[Index] : NULL;
++ return (0 <= Index && Index < MAXDEVICES) ? device[Index] : NULL;
+ }
+
+ cDevice *cDevice::GetDevice(const cChannel *Channel, int Priority, bool *NeedsDetachReceivers)
+ {
+ cDevice *d = NULL;
+ uint Impact = 0xFFFFFFFF; // we're looking for a device with the least impact
+- for (int i = 0; i < numDevices; i++) {
++ for (int i = 0; i < MAXDEVICES; i++) {
+ bool ndr;
++ if (device[i] == NULL)
++ continue; // this device was not allocated
+ #ifdef DETACH_UNUSED_DEVICES
+ if(!device[i]->Receiving()) {
+ isyslog("device %d (%p) not receiving", i, device[i]);
+@@ -419,10 +426,11 @@
+ void cDevice::Shutdown(void)
+ {
+ primaryDevice = NULL;
+- for (int i = 0; i < numDevices; i++) {
+- delete device[i];
+- device[i] = NULL;
++ for (int i = 0; i < MAXDEVICES; i++) {
++ if( device[i]) {
++ delete device[i];
+ }
++ }
+ }
+
+ uchar *cDevice::GrabImage(int &Size, bool Jpeg, int Quality, int SizeX, int SizeY)
+@@ -724,6 +732,16 @@
+ return -1;
+ }
+
++int cDevice::ReadFilter(int Handle, void *Buffer, size_t Length)
++{
++ return safe_read(Handle, Buffer, Length);
++}
++
++void cDevice::CloseFilter(int Handle)
++{
++ close(Handle);
++}
++
+ void cDevice::AttachFilter(cFilter *Filter)
+ {
+ if (sectionHandler)
+@@ -753,7 +771,7 @@
+
+ bool cDevice::ProvidesTransponderExclusively(const cChannel *Channel) const
+ {
+- for (int i = 0; i < numDevices; i++) {
++ for (int i = 0; i < MAXDEVICES; i++) {
+ if (device[i] && device[i] != this && device[i]->ProvidesTransponder(Channel))
+ return false;
+ }
+Index: device.h
+===================================================================
+--- device.h (Revision 10504)
++++ device.h (Arbeitskopie)
+@@ -326,6 +326,15 @@
+ ///< Opens a file handle for the given filter data.
+ ///< A derived device that provides section data must
+ ///< implement this function.
++ virtual int ReadFilter(int Handle, void *Buffer, size_t Length);
++ ///< Read from a handle for the given filter data.
++ ///< a derived class need not implement this function, because this
++ ///< is done by the default implementation.
++ virtual void CloseFilter(int Handle);
++ ///< Closes a file handle that has previously been opened
++ ///< by OpenFilter(). If this is as simple as calling close(Handle),
++ ///< a derived class need not implement this function, because this
++ ///< is done by the default implementation.
+ void AttachFilter(cFilter *Filter);
+ ///< Attaches the given filter to this device.
+ void Detach(cFilter *Filter);
+Index: sections.c
+===================================================================
+--- sections.c (Revision 10504)
++++ sections.c (Arbeitskopie)
+@@ -105,7 +105,7 @@
+ for (fh = filterHandles.First(); fh; fh = filterHandles.Next(fh)) {
+ if (fh->filterData.Is(FilterData->pid, FilterData->tid, FilterData->mask)) {
+ if (--fh->used <= 0) {
+- close(fh->handle);
++ device->CloseFilter(fh->handle);
+ filterHandles.Del(fh);
+ break;
+ }
+@@ -198,7 +198,7 @@
+ if (fh) {
+ // Read section data:
+ unsigned char buf[4096]; // max. allowed size for any EIT section
+- int r = safe_read(fh->handle, buf, sizeof(buf));
++ int r = device->ReadFilter(fh->handle, buf, sizeof(buf));
+ if (!DeviceHasLock)
+ continue; // we do the read anyway, to flush any data that might have come from a different transponder
+ if (r > 3) { // minimum number of bytes necessary to get section length
diff --git a/patches/vdr-1.4.0-closefilter.patch b/patches/vdr-1.4.0-closefilter.patch
new file mode 100644
index 0000000..cd87632
--- /dev/null
+++ b/patches/vdr-1.4.0-closefilter.patch
@@ -0,0 +1,45 @@
+Index: device.c
+===================================================================
+--- device.c (Revision 10449)
++++ device.c (Arbeitskopie)
+@@ -724,6 +724,11 @@
+ return -1;
+ }
+
++void cDevice::CloseFilter(int Handle)
++{
++ close(Handle);
++}
++
+ void cDevice::AttachFilter(cFilter *Filter)
+ {
+ if (sectionHandler)
+Index: device.h
+===================================================================
+--- device.h (Revision 10449)
++++ device.h (Arbeitskopie)
+@@ -326,6 +326,11 @@
+ ///< Opens a file handle for the given filter data.
+ ///< A derived device that provides section data must
+ ///< implement this function.
++ virtual void CloseFilter(int Handle);
++ ///< Closes a file handle that has previously been opened
++ ///< by OpenFilter(). If this is as simple as calling close(Handle),
++ ///< a derived class need not implement this function, because this
++ ///< is done by the default implementation.
+ void AttachFilter(cFilter *Filter);
+ ///< Attaches the given filter to this device.
+ void Detach(cFilter *Filter);
+Index: sections.c
+===================================================================
+--- sections.c (Revision 10449)
++++ sections.c (Arbeitskopie)
+@@ -105,7 +105,7 @@
+ for (fh = filterHandles.First(); fh; fh = filterHandles.Next(fh)) {
+ if (fh->filterData.Is(FilterData->pid, FilterData->tid, FilterData->mask)) {
+ if (--fh->used <= 0) {
+- close(fh->handle);
++ device->CloseFilter(fh->handle);
+ filterHandles.Del(fh);
+ break;
+ }
diff --git a/patches/vdr-1.6-device-consistent-destruct.patch b/patches/vdr-1.6-device-consistent-destruct.patch
new file mode 100644
index 0000000..9299be0
--- /dev/null
+++ b/patches/vdr-1.6-device-consistent-destruct.patch
@@ -0,0 +1,97 @@
+--- ../vdr-1.6.0/device.c 2009-01-26 20:26:49.000000000 +0100
++++ device.c 2009-01-26 22:32:03.000000000 +0100
+@@ -253,14 +253,19 @@
+ for (int i = 0; i < MAXRECEIVERS; i++)
+ receiver[i] = NULL;
+
+- if (numDevices < MAXDEVICES)
+- device[numDevices++] = this;
+- else
+- esyslog("ERROR: too many devices!");
++ for (int i = 0; i < MAXDEVICES; i++)
++ if (!device[i]) {
++ device[i] = this;
++ numDevices++;
++ return;
++ }
++ esyslog("ERROR: too many devices!");
+ }
+
+ cDevice::~cDevice()
+ {
++ numDevices--;
++ device[DeviceNumber()] = NULL;
+ Detach(player);
+ DetachAllReceivers();
+ delete liveSubtitle;
+@@ -272,7 +277,7 @@
+ {
+ for (time_t t0 = time(NULL); time(NULL) - t0 < Timeout; ) {
+ bool ready = true;
+- for (int i = 0; i < numDevices; i++) {
++ for (int i = 0; i < MAXDEVICES; i++) {
+ if (device[i] && !device[i]->Ready()) {
+ ready = false;
+ cCondWait::SleepMs(100);
+@@ -304,7 +309,7 @@
+
+ int cDevice::DeviceNumber(void) const
+ {
+- for (int i = 0; i < numDevices; i++) {
++ for (int i = 0; i < MAXDEVICES; i++) {
+ if (device[i] == this)
+ return i;
+ }
+@@ -318,7 +323,7 @@
+ bool cDevice::SetPrimaryDevice(int n)
+ {
+ n--;
+- if (0 <= n && n < numDevices && device[n]) {
++ if (0 <= n && n < MAXDEVICES && device[n]) {
+ isyslog("setting primary device to %d", n + 1);
+ if (primaryDevice)
+ primaryDevice->MakePrimaryDevice(false);
+@@ -352,7 +357,7 @@
+
+ cDevice *cDevice::GetDevice(int Index)
+ {
+- return (0 <= Index && Index < numDevices) ? device[Index] : NULL;
++ return (0 <= Index && Index < MAXDEVICES) ? device[Index] : NULL;
+ }
+
+ cDevice *cDevice::GetDevice(const cChannel *Channel, int Priority, bool LiveView)
+@@ -388,8 +393,8 @@
+ for (int j = 0; j < NumCamSlots || !NumUsableSlots; j++) {
+ if (NumUsableSlots && SlotPriority[j] > MAXPRIORITY)
+ continue; // there is no CAM available in this slot
+- for (int i = 0; i < numDevices; i++) {
+- if (device[i] == AvoidDevice)
++ for (int i = 0; i < MAXDEVICES; i++) {
++ if (device[i] == NULL || device[i] == AvoidDevice)
+ continue; // this device shall be temporarily avoided
+ if (Channel->Ca() && Channel->Ca() <= CA_DVB_MAX && Channel->Ca() != device[i]->CardIndex() + 1)
+ continue; // a specific card was requested, but not this one
+@@ -463,10 +468,11 @@
+ void cDevice::Shutdown(void)
+ {
+ primaryDevice = NULL;
+- for (int i = 0; i < numDevices; i++) {
+- delete device[i];
+- device[i] = NULL;
++ for (int i = 0; i < MAXDEVICES; i++) {
++ if( device[i]) {
++ delete device[i];
+ }
++ }
+ }
+
+ uchar *cDevice::GrabImage(int &Size, bool Jpeg, int Quality, int SizeX, int SizeY)
+@@ -703,7 +709,7 @@
+
+ bool cDevice::ProvidesTransponderExclusively(const cChannel *Channel) const
+ {
+- for (int i = 0; i < numDevices; i++) {
++ for (int i = 0; i < MAXDEVICES; i++) {
+ if (device[i] && device[i] != this && device[i]->ProvidesTransponder(Channel))
+ return false;
+ }
diff --git a/patches/vdr-1.6-section-read-abstraction.patch b/patches/vdr-1.6-section-read-abstraction.patch
new file mode 100644
index 0000000..3d1bea4
--- /dev/null
+++ b/patches/vdr-1.6-section-read-abstraction.patch
@@ -0,0 +1,38 @@
+--- ../vdr-1.6.0/device.c 2009-01-26 20:26:49.000000000 +0100
++++ device.c 2009-01-26 23:12:59.000000000 +0100
+@@ -674,6 +680,11 @@
+ return -1;
+ }
+
++int cDevice::ReadFilter(int Handle, void *Buffer, size_t Length)
++{
++ return safe_read(Handle, Buffer, Length);
++}
++
+ void cDevice::CloseFilter(int Handle)
+ {
+ close(Handle);
+--- ../vdr-1.6.0/device.h 2009-01-26 20:26:49.000000000 +0100
++++ device.h 2009-01-26 23:12:41.000000000 +0100
+@@ -317,6 +317,10 @@
+ ///< Opens a file handle for the given filter data.
+ ///< A derived device that provides section data must
+ ///< implement this function.
++ virtual int ReadFilter(int Handle, void *Buffer, size_t Length);
++ ///< Read from a handle for the given filter data.
++ ///< a derived class need not implement this function, because this
++ ///< is done by the default implementation.
+ virtual void CloseFilter(int Handle);
+ ///< Closes a file handle that has previously been opened
+ ///< by OpenFilter(). If this is as simple as calling close(Handle),
+--- ../vdr-1.6.0/sections.c 2007-10-14 14:52:07.000000000 +0200
++++ sections.c 2009-01-26 23:14:00.000000000 +0100
+@@ -198,7 +198,7 @@
+ if (fh) {
+ // Read section data:
+ unsigned char buf[4096]; // max. allowed size for any EIT section
+- int r = safe_read(fh->handle, buf, sizeof(buf));
++ int r = device->ReadFilter(fh->handle, buf, sizeof(buf));
+ if (!DeviceHasLock)
+ continue; // we do the read anyway, to flush any data that might have come from a different transponder
+ if (r > 3) { // minimum number of bytes necessary to get section length
diff --git a/patches/vdr-1.6.0-altmenuaction.patch b/patches/vdr-1.6.0-altmenuaction.patch
new file mode 100644
index 0000000..4b06850
--- /dev/null
+++ b/patches/vdr-1.6.0-altmenuaction.patch
@@ -0,0 +1,38 @@
+Index: plugin.h
+===================================================================
+--- plugin.h (revision 2072)
++++ plugin.h (working copy)
+@@ -45,7 +45,8 @@
+
+ virtual const char *MainMenuEntry(void);
+ virtual cOsdObject *MainMenuAction(void);
+-
++ virtual cOsdObject *AltMenuAction(void) { return NULL; };
++
+ virtual cMenuSetupPage *SetupMenu(void);
+ virtual bool SetupParse(const char *Name, const char *Value);
+ void SetupStore(const char *Name, const char *Value = NULL);
+Index: vdr.c
+===================================================================
+--- vdr.c (revision 2072)
++++ vdr.c (working copy)
+@@ -929,6 +929,19 @@
+ Recordings.Update();
+ DeletedRecordings.Update();
+ }
++ cPlugin *mcliPlugin = cPluginManager::GetPlugin("mcli");
++ if (mcliPlugin) {
++ if (!ShutdownHandler.countdown) { // if kPower has been pressed, cMenuShutdown takes precedence over other menus
++ cOsdObject *MyMenu = mcliPlugin->AltMenuAction();
++ if (MyMenu) { // is there any cam-menu waiting?
++ DELETE_MENU;
++ if (cControl::Control())
++ cControl::Control()->Hide();
++ Menu = MyMenu;
++ Menu->Show();
++ }
++ }
++ }
+ // CAM control:
+ if (!Menu && !cOsd::IsOpen())
+ Menu = CamControl();
diff --git a/patches/vdr-1.6.0-intcamdevices.patch b/patches/vdr-1.6.0-intcamdevices.patch
new file mode 100644
index 0000000..aab1fb4
--- /dev/null
+++ b/patches/vdr-1.6.0-intcamdevices.patch
@@ -0,0 +1,78 @@
+Index: vdr-1.6.0-nocamdevices/device.c
+===================================================================
+--- vdr-1.6.0-nocamdevices/device.c
++++ vdr-1.6.0-nocamdevices/device.c 2008-04-27 18:55:37.000000000 +0300
+@@ -363,6 +363,7 @@
+ int NumCamSlots = CamSlots.Count();
+ int SlotPriority[NumCamSlots];
+ int NumUsableSlots = 0;
++ bool InternalCamNeeded = false;
+ if (Channel->Ca() >= CA_ENCRYPTED_MIN) {
+ for (cCamSlot *CamSlot = CamSlots.First(); CamSlot; CamSlot = CamSlots.Next(CamSlot)) {
+ SlotPriority[CamSlot->Index()] = MAXPRIORITY + 1; // assumes it can't be used
+@@ -376,7 +377,7 @@
+ }
+ }
+ if (!NumUsableSlots)
+- return NULL; // no CAM is able to decrypt this channel
++ InternalCamNeeded = true; // no CAM is able to decrypt this channel
+ }
+
+ bool NeedsDetachReceivers = false;
+@@ -392,11 +393,13 @@
+ continue; // this device shall be temporarily avoided
+ if (Channel->Ca() && Channel->Ca() <= CA_DVB_MAX && Channel->Ca() != device[i]->CardIndex() + 1)
+ continue; // a specific card was requested, but not this one
+- if (NumUsableSlots && !CamSlots.Get(j)->Assign(device[i], true))
++ if (InternalCamNeeded && !device[i]->HasInternalCam())
++ continue; // no CAM is able to decrypt this channel and the device uses vdr handled CAMs
++ if (NumUsableSlots && !device[i]->HasInternalCam() && !CamSlots.Get(j)->Assign(device[i], true))
+ continue; // CAM slot can't be used with this device
+ bool ndr;
+ if (device[i]->ProvidesChannel(Channel, Priority, &ndr)) { // this device is basicly able to do the job
+- if (NumUsableSlots && device[i]->CamSlot() && device[i]->CamSlot() != CamSlots.Get(j))
++ if (NumUsableSlots && !device[i]->HasInternalCam() && device[i]->CamSlot() && device[i]->CamSlot() != CamSlots.Get(j))
+ ndr = true; // using a different CAM slot requires detaching receivers
+ // Put together an integer number that reflects the "impact" using
+ // this device would have on the overall system. Each condition is represented
+@@ -410,18 +413,18 @@
+ imp <<= 1; imp |= device[i]->Receiving(); // avoid devices that are receiving
+ imp <<= 1; imp |= device[i] == cTransferControl::ReceiverDevice(); // avoid the Transfer Mode receiver device
+ imp <<= 8; imp |= min(max(device[i]->Priority() + MAXPRIORITY, 0), 0xFF); // use the device with the lowest priority (+MAXPRIORITY to assure that values -99..99 can be used)
+- imp <<= 8; imp |= min(max((NumUsableSlots ? SlotPriority[j] : 0) + MAXPRIORITY, 0), 0xFF); // use the CAM slot with the lowest priority (+MAXPRIORITY to assure that values -99..99 can be used)
++ imp <<= 8; imp |= min(max(((NumUsableSlots && !device[i]->HasInternalCam()) ? SlotPriority[j] : 0) + MAXPRIORITY, 0), 0xFF); // use the CAM slot with the lowest priority (+MAXPRIORITY to assure that values -99..99 can be used)
+ imp <<= 1; imp |= ndr; // avoid devices if we need to detach existing receivers
+ imp <<= 1; imp |= device[i]->IsPrimaryDevice(); // avoid the primary device
+- imp <<= 1; imp |= NumUsableSlots ? 0 : device[i]->HasCi(); // avoid cards with Common Interface for FTA channels
++ imp <<= 1; imp |= (NumUsableSlots || InternalCamNeeded) ? 0 : device[i]->HasCi(); // avoid cards with Common Interface for FTA channels
+ imp <<= 1; imp |= device[i]->HasDecoder(); // avoid full featured cards
+- imp <<= 1; imp |= NumUsableSlots ? !ChannelCamRelations.CamDecrypt(Channel->GetChannelID(), j + 1) : 0; // prefer CAMs that are known to decrypt this channel
++ imp <<= 1; imp |= (NumUsableSlots && !device[i]->HasInternalCam()) ? !ChannelCamRelations.CamDecrypt(Channel->GetChannelID(), j + 1) : 0; // prefer CAMs that are known to decrypt this channel
+ if (imp < Impact) {
+ // This device has less impact than any previous one, so we take it.
+ Impact = imp;
+ d = device[i];
+ NeedsDetachReceivers = ndr;
+- if (NumUsableSlots)
++ if (NumUsableSlots && !device[i]->HasInternalCam())
+ s = CamSlots.Get(j);
+ }
+ }
+Index: vdr-1.6.0-nocamdevices/device.h
+===================================================================
+--- vdr-1.6.0-nocamdevices/device.h
++++ vdr-1.6.0-nocamdevices/device.h 2008-04-27 18:55:49.000000000 +0300
+@@ -335,6 +335,12 @@
+ public:
+ virtual bool HasCi(void);
+ ///< Returns true if this device has a Common Interface.
++ virtual bool HasInternalCam(void) { return false; }
++ ///< Returns true if this device handles encrypted channels itself
++ ///< without VDR assistance. This can be e.g. when the device is a
++ ///< client that gets the stream from another VDR instance that has
++ ///< already decrypted the stream. In this case ProvidesChannel()
++ ///< shall check whether the channel can be decrypted.
+ void SetCamSlot(cCamSlot *CamSlot);
+ ///< Sets the given CamSlot to be used with this device.
+ cCamSlot *CamSlot(void) const { return camSlot; }
+
diff --git a/po/.svn/entries b/po/.svn/entries
new file mode 100644
index 0000000..011a36d
--- /dev/null
+++ b/po/.svn/entries
@@ -0,0 +1,96 @@
+10
+
+dir
+18963
+svn://reelbox.org/testing/src/vdr-plugins/src/mcli-1/po
+svn://reelbox.org
+
+
+
+2011-11-04T11:47:36.091991Z
+17510
+rollercoaster
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+12be777f-adf9-0310-842f-e37ecc4c7426
+
+de_DE.po
+file
+
+
+
+
+2012-09-27T17:22:49.698848Z
+6a543242c7b7257f7cb19647b17b1467
+2011-07-12T13:36:23.313379Z
+16905
+rollercoaster
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+2224
+
+nl_NL.po
+file
+
+
+
+
+2012-09-27T17:22:49.698848Z
+4324ef38b956dbcd5daf8c89a0c62cdc
+2011-11-04T11:47:36.091991Z
+17510
+rollercoaster
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+2237
+
diff --git a/po/.svn/text-base/de_DE.po.svn-base b/po/.svn/text-base/de_DE.po.svn-base
new file mode 100644
index 0000000..d03ec2d
--- /dev/null
+++ b/po/.svn/text-base/de_DE.po.svn-base
@@ -0,0 +1,86 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: vdr-mcli 1.0\n"
+"Report-Msgid-Bugs-To: <see README>\n"
+"POT-Creation-Date: 2010-06-29 16:08+0200\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: German <reelbox-devel@mailings.reelbox.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+msgid "Multi-Transponder"
+msgstr "Multi-Transponder"
+
+msgid "Updating configuration..."
+msgstr "Aktualisiere Konfiguration..."
+
+msgid "Configuration is up to date..."
+msgstr "Konfiguration ist aktuell..."
+
+#, c-format
+msgid "Getting configuration from Netceiver %s"
+msgstr "Hole Konfiguration von Netceiver %s"
+
+#, c-format
+msgid "Failed to get configuration from Netceiver %s"
+msgstr "Fehler beim Laden der Konfiguration von Netceiver %s"
+
+#, c-format
+msgid "Changing configuration for Netceiver %s"
+msgstr "Aktualisiere Konfiguration von Netceiver %s"
+
+#, c-format
+msgid "Failed to parse configuration from Netceiver %s"
+msgstr "Fehler beim Parsen der Konfiguration von Netceiver %s"
+
+#, c-format
+msgid "Failed to set configuration for Netceiver %s"
+msgstr "Fehler beim Bearbeiten der Konfiguration von Netceiver %s"
+
+#, c-format
+msgid "Failed to save configuration for Netceiver %s"
+msgstr "Fehler beim Speichern der Konfiguration von Netceiver %s"
+
+#, c-format
+msgid "Saving configuration for Netceiver %s"
+msgstr "Speichere die Konfiguration von Netceiver %s"
+
+msgid "Multi-Transponder-Decryption is"
+msgstr "Multi-Transponder-Entschlüsselung ist"
+
+msgid "impossible because of mixed CAMs"
+msgstr "nicht möglich wegen gemischter CAMs"
+
+msgid "Save"
+msgstr "Speichern"
+
+#, c-format
+msgid "Waiting for a free tuner (%s)"
+msgstr "Auf einen freien Tuner wird gewartet (%s)"
+
+msgid "DVB-C"
+msgstr "DVB-C"
+
+msgid "DVB-T"
+msgstr "DVB-T"
+
+msgid "DVB-S"
+msgstr "DVB-S"
+
+msgid "DVB-S2"
+msgstr "DVB-S2"
+
+#, c-format
+msgid "Module '%s' ready"
+msgstr "'%s'-Modul bereit"
+
+#, c-format
+msgid "Module '%s' removed"
+msgstr "'%s'-Modul entfernt"
diff --git a/po/.svn/text-base/nl_NL.po.svn-base b/po/.svn/text-base/nl_NL.po.svn-base
new file mode 100644
index 0000000..668e969
--- /dev/null
+++ b/po/.svn/text-base/nl_NL.po.svn-base
@@ -0,0 +1,87 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: vdr-mcli 1.0\n"
+"Report-Msgid-Bugs-To: <see README>\n"
+"POT-Creation-Date: 2010-06-29 16:08+0200\n"
+"PO-Revision-Date: 2011-09-07 17:59+0100\n"
+"Last-Translator: TechNL <technl@gmx.net>\n"
+"Language-Team: German <reelbox-devel@mailings.reelbox.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+msgid "Multi-Transponder"
+msgstr "Multi-Transponder"
+
+msgid "Updating configuration..."
+msgstr "Konfiguratie updaten..."
+
+msgid "Configuration is up to date..."
+msgstr "Konfuguratie is aktueel..."
+
+#, c-format
+msgid "Getting configuration from Netceiver %s"
+msgstr "Configuratie van Netceiver %s ophalen"
+
+#, c-format
+msgid "Failed to get configuration from Netceiver %s"
+msgstr "Fout tijdens het ophalen van de configuratie van Netceiver %s"
+
+#, c-format
+msgid "Changing configuration for Netceiver %s"
+msgstr "Configuratie aktualiseren van Netceiver %s"
+
+#, c-format
+msgid "Failed to parse configuration from Netceiver %s"
+msgstr "Fout tijdens het parsen van de config van Netceiver %s"
+
+#, c-format
+msgid "Failed to set configuration for Netceiver %s"
+msgstr "Fout tijdens het instellen van de config van Netceiver %s"
+
+#, c-format
+msgid "Failed to save configuration for Netceiver %s"
+msgstr "Fout bij het opslaan van de config van Netceiver %s"
+
+#, c-format
+msgid "Saving configuration for Netceiver %s"
+msgstr "Opslaan van de configuratie van Netceiver %s"
+
+msgid "Multi-Transponder-Decryption is"
+msgstr "Multi-Transponder decoderen is niet"
+
+msgid "impossible because of mixed CAMs"
+msgstr "mogelijk omdat verschillende CAM's worden gebruikt"
+
+msgid "Save"
+msgstr "Opslaan"
+
+#, c-format
+msgid "Waiting for a free tuner (%s)"
+msgstr "Wachten tot tuner voor (%s) beschikbaar komt"
+
+msgid "DVB-C"
+msgstr "DVB-C"
+
+msgid "DVB-T"
+msgstr "DVB-T"
+
+msgid "DVB-S"
+msgstr "DVB-S"
+
+msgid "DVB-S2"
+msgstr "DVB-S2"
+
+#, c-format
+msgid "Module '%s' ready"
+msgstr "Module '%s' gereed"
+
+#, c-format
+msgid "Module '%s' removed"
+msgstr "Module '%s' verwijderd"
+
diff --git a/po/de_DE.po b/po/de_DE.po
new file mode 100644
index 0000000..d03ec2d
--- /dev/null
+++ b/po/de_DE.po
@@ -0,0 +1,86 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: vdr-mcli 1.0\n"
+"Report-Msgid-Bugs-To: <see README>\n"
+"POT-Creation-Date: 2010-06-29 16:08+0200\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: German <reelbox-devel@mailings.reelbox.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+msgid "Multi-Transponder"
+msgstr "Multi-Transponder"
+
+msgid "Updating configuration..."
+msgstr "Aktualisiere Konfiguration..."
+
+msgid "Configuration is up to date..."
+msgstr "Konfiguration ist aktuell..."
+
+#, c-format
+msgid "Getting configuration from Netceiver %s"
+msgstr "Hole Konfiguration von Netceiver %s"
+
+#, c-format
+msgid "Failed to get configuration from Netceiver %s"
+msgstr "Fehler beim Laden der Konfiguration von Netceiver %s"
+
+#, c-format
+msgid "Changing configuration for Netceiver %s"
+msgstr "Aktualisiere Konfiguration von Netceiver %s"
+
+#, c-format
+msgid "Failed to parse configuration from Netceiver %s"
+msgstr "Fehler beim Parsen der Konfiguration von Netceiver %s"
+
+#, c-format
+msgid "Failed to set configuration for Netceiver %s"
+msgstr "Fehler beim Bearbeiten der Konfiguration von Netceiver %s"
+
+#, c-format
+msgid "Failed to save configuration for Netceiver %s"
+msgstr "Fehler beim Speichern der Konfiguration von Netceiver %s"
+
+#, c-format
+msgid "Saving configuration for Netceiver %s"
+msgstr "Speichere die Konfiguration von Netceiver %s"
+
+msgid "Multi-Transponder-Decryption is"
+msgstr "Multi-Transponder-Entschlüsselung ist"
+
+msgid "impossible because of mixed CAMs"
+msgstr "nicht möglich wegen gemischter CAMs"
+
+msgid "Save"
+msgstr "Speichern"
+
+#, c-format
+msgid "Waiting for a free tuner (%s)"
+msgstr "Auf einen freien Tuner wird gewartet (%s)"
+
+msgid "DVB-C"
+msgstr "DVB-C"
+
+msgid "DVB-T"
+msgstr "DVB-T"
+
+msgid "DVB-S"
+msgstr "DVB-S"
+
+msgid "DVB-S2"
+msgstr "DVB-S2"
+
+#, c-format
+msgid "Module '%s' ready"
+msgstr "'%s'-Modul bereit"
+
+#, c-format
+msgid "Module '%s' removed"
+msgstr "'%s'-Modul entfernt"
diff --git a/po/nl_NL.po b/po/nl_NL.po
new file mode 100644
index 0000000..668e969
--- /dev/null
+++ b/po/nl_NL.po
@@ -0,0 +1,87 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: vdr-mcli 1.0\n"
+"Report-Msgid-Bugs-To: <see README>\n"
+"POT-Creation-Date: 2010-06-29 16:08+0200\n"
+"PO-Revision-Date: 2011-09-07 17:59+0100\n"
+"Last-Translator: TechNL <technl@gmx.net>\n"
+"Language-Team: German <reelbox-devel@mailings.reelbox.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+msgid "Multi-Transponder"
+msgstr "Multi-Transponder"
+
+msgid "Updating configuration..."
+msgstr "Konfiguratie updaten..."
+
+msgid "Configuration is up to date..."
+msgstr "Konfuguratie is aktueel..."
+
+#, c-format
+msgid "Getting configuration from Netceiver %s"
+msgstr "Configuratie van Netceiver %s ophalen"
+
+#, c-format
+msgid "Failed to get configuration from Netceiver %s"
+msgstr "Fout tijdens het ophalen van de configuratie van Netceiver %s"
+
+#, c-format
+msgid "Changing configuration for Netceiver %s"
+msgstr "Configuratie aktualiseren van Netceiver %s"
+
+#, c-format
+msgid "Failed to parse configuration from Netceiver %s"
+msgstr "Fout tijdens het parsen van de config van Netceiver %s"
+
+#, c-format
+msgid "Failed to set configuration for Netceiver %s"
+msgstr "Fout tijdens het instellen van de config van Netceiver %s"
+
+#, c-format
+msgid "Failed to save configuration for Netceiver %s"
+msgstr "Fout bij het opslaan van de config van Netceiver %s"
+
+#, c-format
+msgid "Saving configuration for Netceiver %s"
+msgstr "Opslaan van de configuratie van Netceiver %s"
+
+msgid "Multi-Transponder-Decryption is"
+msgstr "Multi-Transponder decoderen is niet"
+
+msgid "impossible because of mixed CAMs"
+msgstr "mogelijk omdat verschillende CAM's worden gebruikt"
+
+msgid "Save"
+msgstr "Opslaan"
+
+#, c-format
+msgid "Waiting for a free tuner (%s)"
+msgstr "Wachten tot tuner voor (%s) beschikbaar komt"
+
+msgid "DVB-C"
+msgstr "DVB-C"
+
+msgid "DVB-T"
+msgstr "DVB-T"
+
+msgid "DVB-S"
+msgstr "DVB-S"
+
+msgid "DVB-S2"
+msgstr "DVB-S2"
+
+#, c-format
+msgid "Module '%s' ready"
+msgstr "Module '%s' gereed"
+
+#, c-format
+msgid "Module '%s' removed"
+msgstr "Module '%s' verwijderd"
+
diff --git a/wait4ncv.diff b/wait4ncv.diff
new file mode 100644
index 0000000..eebcc0b
--- /dev/null
+++ b/wait4ncv.diff
@@ -0,0 +1,61 @@
+Index: device.c
+===================================================================
+--- device.c (Revision 178)
++++ device.c (Arbeitskopie)
+@@ -89,6 +89,10 @@
+ DELETENULL (m_PB);
+ }
+
++bool cMcliDevice::Ready() {
++ return m_mcli ? m_mcli->Ready() : false;
++}
++
+ void cMcliDevice::SetTenData (tra_t * ten)
+ {
+ if(!ten->lastseen) {
+Index: device.h
+===================================================================
+--- device.h (Revision 178)
++++ device.h (Arbeitskopie)
+@@ -71,6 +71,7 @@
+ cMcliFilters *m_filters;
+ cMcliDevice (void);
+ virtual ~ cMcliDevice ();
++ virtual bool Ready();
+ void SetMcliRef(cPluginMcli *m)
+ {
+ m_mcli=m;
+Index: mcli.c
+===================================================================
+--- mcli.c (Revision 178)
++++ mcli.c (Arbeitskopie)
+@@ -471,6 +471,17 @@
+ return NULL;
+ }
+
++bool cPluginMcli::Ready()
++{
++ tuner_pool_t *tp;
++ for(int i=0; i<TUNER_POOL_MAX; i++) {
++ tp=m_tuner_pool+i;
++ if(tp->type != -1)
++ return true;
++ }
++ return false;
++}
++
+ int cPluginMcli::TunerCountByType (const fe_type_t type)
+ {
+ int ret=0;
+Index: mcli.h
+===================================================================
+--- mcli.h (Revision 178)
++++ mcli.h (Arbeitskopie)
+@@ -161,6 +161,7 @@
+ bool TunerSatelitePositionLookup(tuner_pool_t *tp, int pos) const;
+
+ tuner_pool_t *TunerFindByUUID (const char *uuid);
++ bool Ready();
+ int TunerCountByType (const fe_type_t type);
+ bool TunerPoolAdd(tuner_info_t *t);
+ bool TunerPoolDel(tuner_pool_t *tp);