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 /mcast | |
download | vdr-plugin-mcli-ccf6e0f9c6b0481ed13e0f4794e3fbead750f385.tar.gz vdr-plugin-mcli-ccf6e0f9c6b0481ed13e0f4794e3fbead750f385.tar.bz2 |
added vdr-plugin-mcli-0.0.1+svn20120927
Diffstat (limited to 'mcast')
182 files changed, 30949 insertions, 0 deletions
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 |