diff options
author | Lars Heer <l.heer@gmx.de> | 2013-09-18 05:50:03 +0200 |
---|---|---|
committer | Lars Heer <l.heer@gmx.de> | 2013-09-18 05:50:03 +0200 |
commit | ccf6e0f9c6b0481ed13e0f4794e3fbead750f385 (patch) | |
tree | ed86efb54f7ee41edfba5c89ca519b5fd10aa0d5 | |
download | vdr-plugin-mcli-ccf6e0f9c6b0481ed13e0f4794e3fbead750f385.tar.gz vdr-plugin-mcli-ccf6e0f9c6b0481ed13e0f4794e3fbead750f385.tar.bz2 |
added vdr-plugin-mcli-0.0.1+svn20120927
220 files changed, 37656 insertions, 0 deletions
@@ -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. @@ -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 @@ -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__ @@ -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" @@ -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! @@ -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); |