├── res └── .keep ├── jni ├── udpxy │ ├── BUILD │ ├── PATCH │ ├── BLDTYPE │ ├── VERSION │ ├── test │ │ ├── dlna.txt │ │ ├── ifcbuf.dat │ │ ├── mktestcache.sh │ │ ├── getflv.c │ │ ├── test_txtf.c │ │ ├── test_ifaddr.c │ │ ├── test_a2size.c │ │ ├── test_addrport.c │ │ ├── test_a2time.c │ │ ├── cache.h │ │ ├── test_cache.c │ │ ├── upxc.c │ │ └── fbsd │ │ │ └── ifaddr.c │ ├── .gitignore │ ├── util │ │ ├── cfg-brcm.sh │ │ └── mkipk.sh │ ├── Android.mk │ ├── TODO │ ├── Specfile │ ├── mtrace.h │ ├── sloop.c │ ├── main.c │ ├── mkpg.h │ ├── osdef.h │ ├── ifaddr.h │ ├── extrn.c │ ├── prbuf.h │ ├── prbuf.c │ ├── udpxy.h │ ├── doc │ │ └── en │ │ │ ├── udpxrec.1 │ │ │ └── udpxy.1 │ ├── rparse.h │ ├── netop.h │ ├── dpkt.h │ ├── rtp.h │ ├── gcc.mk │ ├── ctx.h │ ├── rparse.c │ ├── uopt.h │ ├── Makefile │ ├── util.h │ ├── statpg.h │ ├── ifaddr.c │ ├── sloop_p.c │ ├── uopt.c │ ├── sloop_s.c │ ├── mkpg.c │ ├── rtp.c │ ├── README │ ├── README.russian │ ├── CHANGES │ └── ctx.c └── Android.mk ├── AUTHORS ├── Dockerfile ├── .gitignore ├── AndroidManifest.xml ├── local.properties.sample ├── project.properties ├── custom_rules.xml ├── proguard-project.txt ├── .travis.yml ├── src └── com │ └── rom1v │ └── andudpxy │ ├── FileUtils.java │ └── UdpxyService.java └── README.md /res/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /jni/udpxy/BUILD: -------------------------------------------------------------------------------- 1 | 23 2 | -------------------------------------------------------------------------------- /jni/udpxy/PATCH: -------------------------------------------------------------------------------- 1 | 12 2 | -------------------------------------------------------------------------------- /jni/udpxy/BLDTYPE: -------------------------------------------------------------------------------- 1 | "prod" 2 | -------------------------------------------------------------------------------- /jni/udpxy/VERSION: -------------------------------------------------------------------------------- 1 | "1.0" 2 | -------------------------------------------------------------------------------- /jni/Android.mk: -------------------------------------------------------------------------------- 1 | include $(call all-subdir-makefiles) 2 | -------------------------------------------------------------------------------- /jni/udpxy/test/dlna.txt: -------------------------------------------------------------------------------- 1 | contentFeatures.dlna.org: 1 2 | contentFeatures.dlna.org: DLNA.ORG_OP=11 3 | 4 | -------------------------------------------------------------------------------- /jni/udpxy/test/ifcbuf.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ewwink/android-udpxy/HEAD/jni/udpxy/test/ifcbuf.dat -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | andudpxy: 2 | - Romain Vimont (®om) 3 | 4 | udpxy: 5 | - Pavel V. Cherenkov 6 | -------------------------------------------------------------------------------- /jni/udpxy/test/mktestcache.sh: -------------------------------------------------------------------------------- 1 | gcc -g -W -Wall -Werror --pedantic -DTRACE_MODULE -I. -o tcache test/test_cache.c dpkt.c util.c cache.c extrn.c rtp.c 2 | -------------------------------------------------------------------------------- /jni/udpxy/.gitignore: -------------------------------------------------------------------------------- 1 | #Object files 2 | *.o 3 | udpxy.dep 4 | 5 | #RPM build folder 6 | build/ 7 | 8 | #Make binaries 9 | udpxy 10 | udpxrec 11 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM gcc:latest 2 | ADD ./chipmunk /udpxy 3 | WORKDIR /udpxy 4 | RUN make && make install 5 | ENV PORT=80 6 | EXPOSE $PORT 7 | CMD udpxy -T -p $PORT 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # generated files 2 | /bin/ 3 | /gen/ 4 | 5 | 6 | # look at local.properties.sample 7 | /local.properties 8 | 9 | # Eclipse stuff 10 | /.classpath 11 | /.project 12 | /.settings/ 13 | -------------------------------------------------------------------------------- /jni/udpxy/util/cfg-brcm.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # @(#) configures environment to use Broadcom MIPS toolchain 3 | 4 | export PATH=$PATH:/opt/brcm/hndtools-mipsel-uclibc/bin 5 | export BRCM_CC=mipsel-uclibc-gcc 6 | export STRIP=mipsel-uclibc-strip 7 | 8 | -------------------------------------------------------------------------------- /AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 7 | 8 | -------------------------------------------------------------------------------- /jni/udpxy/Android.mk: -------------------------------------------------------------------------------- 1 | LOCAL_PATH := $(call my-dir) 2 | 3 | include $(CLEAR_VARS) 4 | 5 | LOCAL_MODULE := udpxy 6 | LOCAL_SRC_FILES := udpxy.c sloop.c rparse.c util.c prbuf.c ifaddr.c ctx.c mkpg.c \ 7 | rtp.c uopt.c dpkt.c netop.c extrn.c main.c 8 | 9 | include $(BUILD_EXECUTABLE) 10 | -------------------------------------------------------------------------------- /jni/udpxy/TODO: -------------------------------------------------------------------------------- 1 | 2 | FEATURES: 3 | *. separate multicast-connect timeout (as vs. unified read timeout); 4 | *. switch to another channel on timeout (on connect, on read) 5 | *. allow unicast UDP stream as source 6 | *. winamp support 7 | *. PCH 2xx, 3xx support (content-length headers) 8 | 9 | 10 | DEV: 11 | *. switch to allow trace levels (need a level to trace all packets in/out, for instance) 12 | 13 | 14 | # EOF 15 | 16 | -------------------------------------------------------------------------------- /local.properties.sample: -------------------------------------------------------------------------------- 1 | # This file is automatically generated by Android Tools. 2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED! 3 | # 4 | # This file must *NOT* be checked into Version Control Systems, 5 | # as it contains information specific to your local configuration. 6 | 7 | # location of the SDK. This is only used by Ant 8 | # For customization when using a Version Control System, please read the 9 | # header note. 10 | sdk.dir=YOUR_SDK_HERE 11 | ndk.dir=YOUR_NDK_HERE 12 | -------------------------------------------------------------------------------- /jni/udpxy/test/getflv.c: -------------------------------------------------------------------------------- 1 | /* @(#) test get_flagval method */ 2 | 3 | #include 4 | #include "util.h" 5 | 6 | int 7 | main( int argc, char* const argv[] ) 8 | { 9 | int flag = 0; 10 | const char* varname = NULL; 11 | 12 | if ( argc < 2 ) { 13 | (void) fprintf( stderr, "Usage: %s var\n", argv[0] ); 14 | return 1; 15 | } 16 | 17 | varname = argv[1]; 18 | flag = get_flagval( varname, 0 ); 19 | (void) printf( "flag [%s] in %s\n", varname, 20 | (flag ? "ON" : "OFF") ); 21 | return 0; 22 | } 23 | 24 | /* __EOF__ */ 25 | 26 | -------------------------------------------------------------------------------- /project.properties: -------------------------------------------------------------------------------- 1 | # This file is automatically generated by Android Tools. 2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED! 3 | # 4 | # This file must be checked in Version Control Systems. 5 | # 6 | # To customize properties used by the Ant build system edit 7 | # "ant.properties", and override values to adapt the script to your 8 | # project structure. 9 | # 10 | # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): 11 | #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt 12 | 13 | # Project target. 14 | target=android-19 15 | android.library=true 16 | -------------------------------------------------------------------------------- /jni/udpxy/Specfile: -------------------------------------------------------------------------------- 1 | # $Id 2 | 3 | %define name udpxy 4 | %define version %{VERSION} 5 | %define release el%{?rhel} 6 | %global __os_install_post %{nil} 7 | 8 | Name: %{name} 9 | Version: %{version} 10 | Release: %{release} 11 | Summary: Udpxy 12 | Group: Development/Tools 13 | License: None 14 | Source: https://github.com/squarebracket/udpxy 15 | Packager: Chuck Wilson 16 | Requires: glibc >= 2.14 17 | Autoreq: 0 18 | Autoprov: 0 19 | 20 | %description 21 | UDP-to-HTTP multicast traffic relay daemon 22 | 23 | %files 24 | %defattr(-,root,root,-) 25 | %{_prefix}/local/bin/udpxy 26 | %{_mandir}/man1/udpxy.1.gz 27 | %{_mandir}/man1/udpxrec.1.gz 28 | 29 | -------------------------------------------------------------------------------- /custom_rules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | 11 | 12 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /jni/udpxy/test/test_txtf.c: -------------------------------------------------------------------------------- 1 | /* @(#) txtf_read unit test */ 2 | 3 | #include 4 | #include 5 | 6 | #include "util.h" 7 | 8 | int main (int argc, char* const argv[]) 9 | { 10 | char txtbuf[2048]; 11 | ssize_t n = -1; 12 | 13 | if (argc < 2) { 14 | (void) fprintf (stderr, "Usage: %s filepath\n", argv[0]); 15 | return 1; 16 | } 17 | 18 | n = txtf_read (argv[1], txtbuf, sizeof(txtbuf), stderr); 19 | (void) fprintf (stderr, "got %ld from txtf_read\n", n); 20 | if (n <= 0) return 1; 21 | 22 | (void) printf ("Read %ld bytes from %s:\n", n, argv[0]); 23 | (void) printf ("\n"); 24 | (void) printf ("%s\n", txtbuf); 25 | (void) printf ("\n"); 26 | 27 | return 0; 28 | } 29 | 30 | 31 | /* __EOF__ */ 32 | 33 | -------------------------------------------------------------------------------- /proguard-project.txt: -------------------------------------------------------------------------------- 1 | # To enable ProGuard in your project, edit project.properties 2 | # to define the proguard.config property as described in that file. 3 | # 4 | # Add project specific ProGuard rules here. 5 | # By default, the flags in this file are appended to flags specified 6 | # in ${sdk.dir}/tools/proguard/proguard-android.txt 7 | # You can edit the include path and order by changing the ProGuard 8 | # include property in project.properties. 9 | # 10 | # For more details, see 11 | # http://developer.android.com/guide/developing/tools/proguard.html 12 | 13 | # Add any project specific keep options here: 14 | 15 | # If your project uses WebView with JS, uncomment the following 16 | # and specify the fully qualified class name to the JavaScript interface 17 | # class: 18 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 19 | # public *; 20 | #} 21 | -------------------------------------------------------------------------------- /jni/udpxy/test/test_ifaddr.c: -------------------------------------------------------------------------------- 1 | /* @(#) unit test for if2addr */ 2 | 3 | #include 4 | 5 | #include "ifaddr.h" 6 | 7 | int main( int argc, char* const argv[] ) 8 | { 9 | int i = 0, rc = 0; 10 | char ipaddr[ 16 ] = {'\0'}; 11 | 12 | if( argc < 2 ) { 13 | (void) fprintf( stderr, "Usage: %s ifc1 [ifc2] ...\n", 14 | argv[0] ); 15 | return 1; 16 | } 17 | 18 | for( i = 1; i < argc; ++i ) { 19 | rc = get_ipv4_address( argv[i], ipaddr, sizeof(ipaddr) ); 20 | if( 0 != rc ) { 21 | (void) fprintf( stderr, "%d. [%s] - error [%d]\n", 22 | i, argv[i], rc ); 23 | continue; 24 | } 25 | 26 | (void) printf( "%d. [%s] - addr [%s]\n", 27 | i, argv[i], ipaddr ); 28 | } 29 | 30 | return rc; 31 | } 32 | 33 | /* __EOF__ */ 34 | 35 | -------------------------------------------------------------------------------- /jni/udpxy/test/test_a2size.c: -------------------------------------------------------------------------------- 1 | /* @(#) unit test for a2time */ 2 | 3 | #include 4 | #include 5 | 6 | #include "util.h" 7 | 8 | int main( int argc, char* const argv[] ) 9 | { 10 | int rc = 0; 11 | ssize_t len = 0; 12 | int i = 0; 13 | 14 | if( argc < 2 ) { 15 | (void) fprintf( stderr, "Usage: %s sizespec [sizespec] ...\n", 16 | argv[0] ); 17 | return 1; 18 | } 19 | 20 | for( i = 1; i < argc; ++i ) { 21 | rc = a2size( argv[i], &len ); 22 | if( 0 != rc ) break; 23 | 24 | (void) printf( "%d. size [%s] = (%ld) bytes\n", 25 | i, argv[i], (long)len ); 26 | } 27 | 28 | if( 0 != rc ) { 29 | (void) fprintf( stderr, "Error [%d] parsing [%s]\n", 30 | rc, argv[i] ); 31 | } 32 | 33 | return rc; 34 | } 35 | 36 | /* __EOF__ */ 37 | 38 | -------------------------------------------------------------------------------- /jni/udpxy/test/test_addrport.c: -------------------------------------------------------------------------------- 1 | /* @(#) unit test for get_addrport */ 2 | 3 | #include 4 | 5 | #include "ifaddr.h" 6 | 7 | int main( int argc, char* const argv[] ) 8 | { 9 | int rc = 0; 10 | int i = 0, port = -1; 11 | char ipaddr[ 16 ] = {'\0'}; 12 | 13 | if( argc < 2 ) { 14 | (void) fprintf( stderr, "Usage: %s aport [aport] ...\n", 15 | argv[0] ); 16 | return 1; 17 | } 18 | 19 | for( i = 1; i < argc; ++i ) { 20 | rc = get_addrport( argv[i], ipaddr, sizeof(ipaddr), &port ); 21 | if( 0 != rc ) break; 22 | 23 | (void) printf( "%d. [%s] - addr [%s:%d]\n", 24 | i, argv[i], ipaddr, port ); 25 | } 26 | 27 | if( 0 != rc ) { 28 | (void) fprintf( stderr, "Error [%d] parsing [%s]\n", 29 | rc, argv[i] ); 30 | } 31 | 32 | return rc; 33 | } 34 | 35 | /* __EOF__ */ 36 | 37 | -------------------------------------------------------------------------------- /jni/udpxy/test/test_a2time.c: -------------------------------------------------------------------------------- 1 | /* @(#) unit test for a2time */ 2 | 3 | #include 4 | #include 5 | 6 | #include "util.h" 7 | 8 | int main( int argc, char* const argv[] ) 9 | { 10 | int rc = 0; 11 | time_t tm = (time_t)0; 12 | int i = 0; 13 | 14 | if( argc < 2 ) { 15 | (void) fprintf( stderr, "Usage: %s timespec [timespec] ...\n", 16 | argv[0] ); 17 | return 1; 18 | } 19 | 20 | for( i = 1; i < argc; ++i ) { 21 | rc = a2time( argv[i], &tm, time(NULL) ); 22 | if( 0 != rc ) break; 23 | 24 | (void) printf( "%d. time [%s] = time_t(%ld) [%s]\n", 25 | i, argv[i], (long)tm, 26 | Zasctime(localtime(&tm)) ); 27 | } 28 | 29 | if( 0 != rc ) { 30 | (void) fprintf( stderr, "Error [%d] parsing [%s]\n", 31 | rc, argv[i] ); 32 | } 33 | 34 | return rc; 35 | } 36 | 37 | /* __EOF__ */ 38 | 39 | -------------------------------------------------------------------------------- /jni/udpxy/mtrace.h: -------------------------------------------------------------------------------- 1 | /* @(#) debug tracing facilities 2 | * 3 | * Copyright 2008-2011 Pavel V. Cherenkov (pcherenkov@gmail.com) (pcherenkov@gmail.com) 4 | * 5 | * This file is part of udpxy. 6 | * 7 | * udpxy is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * udpxy is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with udpxy. If not, see . 19 | */ 20 | #ifndef _MTRACE_H_09182007_1541_ 21 | #define _MTRACE_H_09182007_1541_ 22 | 23 | /* 24 | * Evaluate expression if TRACE_MODULE 25 | * is defined in the enclosing module 26 | */ 27 | #ifdef TRACE_MODULE 28 | #define TRACE( expr ) (expr) 29 | #else 30 | #define TRACE( expr ) ((void)0) 31 | #endif 32 | 33 | #endif /* _MTRACE_H_09182007_1541_ */ 34 | 35 | /* __EOF__ */ 36 | 37 | -------------------------------------------------------------------------------- /jni/udpxy/sloop.c: -------------------------------------------------------------------------------- 1 | /* @(#) wrapper for udpxy server loop 2 | * 3 | * Copyright 2008-2012 Pavel V. Cherenkov (pcherenkov@gmail.com) 4 | * 5 | * This file is part of udpxy. 6 | * 7 | * udpxy is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * udpxy is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with udpxy. If not, see . 19 | */ 20 | 21 | #include 22 | 23 | /* need to know if pselect(2) is available */ 24 | #if defined(SYS_pselect6) 25 | #define HAS_PSELECT 1 26 | #endif 27 | 28 | /* use pselect(2) in server loop unless select(2) demanded */ 29 | #if defined(HAS_PSELECT) && !defined(USE_SELECT) 30 | #define USE_PSELECT 1 31 | #endif 32 | 33 | #ifdef USE_PSELECT 34 | #include "sloop_p.c" 35 | #else 36 | #include "sloop_s.c" 37 | #endif 38 | 39 | /* __EOF__ */ 40 | 41 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: android 2 | sudo: true 3 | android: 4 | components: 5 | - tools 6 | - platform-tools 7 | - extra-google-m2repository 8 | - extra-android-m2repository 9 | addons: 10 | # artifacts: 11 | # paths: 12 | # - $(git ls-files -o | grep libs/armeabi | tr "\n" ":") 13 | before_install: 14 | - sudo apt-get install ant 15 | install: 16 | - echo y | sdkmanager "ndk-bundle" 17 | # - echo y | sdkmanager "cmake;3.6.4111459" 18 | # - echo y | sdkmanager "lldb;3.1" 19 | # - sdkmanager --update 20 | before_script: 21 | - export ANDROID_NDK_HOME=$ANDROID_HOME/ndk-bundle 22 | - export SYSROOT="$ANDROID_NDK_HOME/platforms/android-19/arch-arm" 23 | - export CC="$ANDROID_NDK_HOME/toolchains/arm-linux-androideabi-4.8/prebuilt/linux-x86_64/bin/arm-linux-androideabi-gcc --sysroot=$SYSROOT" 24 | 25 | script: 26 | # scripts excutes inside our repo directory on CI machine 27 | - cd jni/ 28 | - $ANDROID_HOME/ndk-bundle/ndk-build 29 | - cd ../libs 30 | - ls 31 | - mv "x86/udpxy" "x86/udpxy.x86" 32 | - mv "x86_64/udpxy" "x86_64/udpxy.x86_64" 33 | - mv "arm64-v8a/udpxy" "arm64-v8a/udpxy.arm64-v8a" 34 | - mv "armeabi-v7a/udpxy" "armeabi-v7a/udpxy.armeabi-v7a" 35 | - cd $TRAVIS_BUILD_DIR 36 | - ls 37 | 38 | deploy: 39 | provider: releases 40 | api_key: $GITHUB_TOKEN 41 | file: 42 | - "libs/x86/udpxy.x86" 43 | - "libs/x86_64/udpxy.x86_64" 44 | - "libs/arm64-v8a/udpxy.arm64-v8a" 45 | - "libs/armeabi-v7a/udpxy.armeabi-v7a" 46 | skip_cleanup: true 47 | on: 48 | all_branches: true 49 | tags: true 50 | -------------------------------------------------------------------------------- /jni/udpxy/main.c: -------------------------------------------------------------------------------- 1 | /* @(#) main module: dispatches command to apps within udpxy 2 | * 3 | * Copyright 2008-2011 Pavel V. Cherenkov (pcherenkov@gmail.com) 4 | * 5 | * This file is part of udpxy. 6 | * 7 | * udpxy is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * udpxy is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with udpxy. If not, see . 19 | */ 20 | 21 | #include 22 | #include 23 | #include 24 | 25 | static const char UDPXY[] = "udpxy"; 26 | extern int udpxy_main( int argc, char* const argv[] ); 27 | 28 | #ifdef UDPXREC_MOD 29 | static const char UDPXREC[] = "udpxrec"; 30 | extern int udpxrec_main( int argc, char* const argv[] ); 31 | #endif 32 | 33 | int 34 | main( int argc, char* const argv[] ) 35 | { 36 | const char* app = basename(argv[0]); 37 | 38 | if( 0 == strncmp( UDPXY, app, sizeof(UDPXY) ) ) 39 | return udpxy_main( argc, argv ); 40 | #ifdef UDPXREC_MOD 41 | else if( 0 == strncmp( UDPXREC, app, sizeof(UDPXREC) ) ) 42 | return udpxrec_main( argc, argv ); 43 | #endif 44 | 45 | (void)fprintf( stderr, "Unsupported udpxy module [%s]\n", app); 46 | return 1; 47 | } 48 | 49 | /* __EOF__ */ 50 | -------------------------------------------------------------------------------- /jni/udpxy/mkpg.h: -------------------------------------------------------------------------------- 1 | /* @(#) HTML-page generation methods 2 | * 3 | * Copyright 2008-2011 Pavel V. Cherenkov (pcherenkov@gmail.com) (pcherenkov@gmail.com) 4 | * 5 | * This file is part of udpxy. 6 | * 7 | * udpxy is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * udpxy is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with udpxy. If not, see . 19 | */ 20 | 21 | #ifndef UDPXY_MKPG_H_0115081656 22 | #define UDPXY_MKPG_H_0115081656 23 | 24 | #include 25 | #include "ctx.h" 26 | 27 | #ifdef __cplusplus 28 | extern "C" { 29 | #endif 30 | 31 | /* generate service's (HTML) status page 32 | * 33 | * @param ctx server context 34 | * @param buf destination buffer 35 | * @param len destination buffer's length 36 | * @param options options as a bitset of flags 37 | * 38 | * @return 0 if success, len gets updated with page text's size 39 | * -1 in case of failure 40 | */ 41 | 42 | #define MSO_HTTP_HEADER 1 /* prepend page with HTTP header */ 43 | #define MSO_SKIP_CLIENTS 2 /* do not output client info */ 44 | #define MSO_RESTART 4 /* use restart-page format */ 45 | 46 | 47 | int 48 | mk_status_page( const struct server_ctx* ctx, 49 | char* buf, size_t* len, int options ); 50 | 51 | 52 | #ifdef __cplusplus 53 | } 54 | #endif 55 | 56 | #endif /* UDPXY_MKPG_H_0115081656 */ 57 | 58 | /* __EOF__ */ 59 | 60 | -------------------------------------------------------------------------------- /src/com/rom1v/andudpxy/FileUtils.java: -------------------------------------------------------------------------------- 1 | package com.rom1v.andudpxy; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | import java.io.InputStream; 6 | import java.io.OutputStream; 7 | 8 | /** 9 | * Class with file util methods. 10 | * 11 | * @author rom 12 | */ 13 | public class FileUtils { 14 | 15 | /** Do not instantiate. */ 16 | private FileUtils() {} 17 | 18 | /** 19 | * Buffer-copy from {@code in} to {code out}. 20 | * 21 | * @param in 22 | * the input stream 23 | * @param os 24 | * the output stream 25 | * @throws IOException 26 | * if a I/O error occurs 27 | */ 28 | public static void copy(InputStream in, OutputStream os) throws IOException { 29 | byte[] buf = new byte[4096]; 30 | int read; 31 | while ((read = (in.read(buf))) != -1) { 32 | os.write(buf, 0, read); 33 | } 34 | } 35 | 36 | /** 37 | * Change the permissions of a file. 38 | * 39 | * The {@code mode} is better expressed as octal value, for instance {@code 0755}. 40 | * 41 | * @param file 42 | * the file to have its permission changed 43 | * @param mode 44 | * the mode 45 | * @return {@code true} if the native {@code chmod} command returns {@code 0}, {@code false} 46 | * otherwise 47 | * @throws IOException 48 | * if {@code chmod} cannot be called 49 | */ 50 | public static boolean chmod(File file, int mode) throws IOException { 51 | String sMode = String.format("%03o", mode); // to string octal value 52 | String path = file.getAbsolutePath(); 53 | String[] argv = { "chmod", sMode, path }; 54 | try { 55 | return Runtime.getRuntime().exec(argv).waitFor() == 0; 56 | } catch (InterruptedException e) { 57 | throw new IOException(e); 58 | } 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /jni/udpxy/osdef.h: -------------------------------------------------------------------------------- 1 | /* @(#) define OS-specific types/constants 2 | * 3 | * Copyright 2008-2011 Pavel V. Cherenkov (pcherenkov@gmail.com) (pcherenkov@gmail.com) 4 | * 5 | * This file is part of udpxy. 6 | * 7 | * udpxy is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * udpxy is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with udpxy. If not, see . 19 | */ 20 | 21 | #ifndef UDPXY_OSDEFH_0101082158 22 | #define UDPXY_OSDEFH_0101082158 23 | 24 | #include 25 | 26 | /* define OS-specific types/constants 27 | * 28 | */ 29 | 30 | #define HAS_SOCKLEN 31 | #define HAS_SETLINEBUF 32 | #define HAS_VARRUN 33 | #define HAS_VARTMP 34 | 35 | #ifdef __hpux 36 | #undef HAS_SOCKLEN 37 | #undef HAS_SETLINEBUF 38 | #define NO_SOCKADDR_SA_LEN 39 | #endif 40 | 41 | #if defined(__CYGWIN__) 42 | #define NO_INET6_SUPPORT 43 | #define NO_SOCKADDR_SA_LEN 44 | #endif 45 | 46 | #if defined(__linux) 47 | #define NO_SOCKADDR_SA_LEN 48 | #endif 49 | 50 | #ifndef HAS_SOCKLEN 51 | typedef int a_socklen_t; 52 | #else 53 | typedef socklen_t a_socklen_t; 54 | #endif 55 | 56 | #ifndef HAS_SETLINEBUF 57 | #define Setlinebuf(a) setvbuf(a, NULL, _IOLBF, BUFSIZ) 58 | #else 59 | #define Setlinebuf(a) setlinebuf(a) 60 | #endif 61 | 62 | #if defined(HAS_VARRUN) 63 | #define PIDFILE_DIR "/var/run" 64 | #elif defined(HAS_VARTMP) 65 | #define PIDFILE_DIR "/var/tmp" 66 | #endif 67 | 68 | #endif /* UDPXY_OSDEFH_0101082158 */ 69 | 70 | /* __EOF__ */ 71 | 72 | -------------------------------------------------------------------------------- /jni/udpxy/ifaddr.h: -------------------------------------------------------------------------------- 1 | /* @(#) definition of packet-io functions for udpxy 2 | * 3 | * Copyright 2008-2011 Pavel V. Cherenkov (pcherenkov@gmail.com) 4 | * 5 | * This file is part of udpxy. 6 | * 7 | * udpxy is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * udpxy is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with udpxy. If not, see . 19 | */ 20 | 21 | #ifndef IFADDR_UDPXY_0102081930 22 | #define IFADDR_UDPXY_0102081930 23 | 24 | #include 25 | 26 | #ifdef __cplusplus 27 | extern "C" { 28 | #endif 29 | 30 | struct sockaddr; 31 | 32 | /* retrieve IPv4 address of the given network interface 33 | * 34 | * @param ifname name of the network interface 35 | * @param addr pointer to socket address structure 36 | * @param addrlen socket structure size 37 | * 38 | * @return 0 if success, -1 otherwise 39 | */ 40 | int 41 | if2addr( const char* ifname, 42 | struct sockaddr *addr, size_t addrlen ); 43 | 44 | 45 | /* convert input parameter into an IPv4-address string 46 | * 47 | * @param s input text string 48 | * @param buf buffer for the destination string 49 | * @param len size of the string buffer 50 | * 51 | * @return 0 if success, -1 otherwise 52 | */ 53 | int 54 | get_ipv4_address( const char* s, char* buf, size_t len ); 55 | 56 | 57 | /* split input string into IP address and port 58 | * 59 | * @param s input text string 60 | * @param addr IP address (string) destination buffer 61 | * @param len buffer length 62 | * @param port address of port variable 63 | * 64 | * @return 0 in success, !=0 otherwise 65 | */ 66 | int 67 | get_addrport( const char* s, char* addr, size_t len, int* port ); 68 | 69 | 70 | #ifdef __cplusplus 71 | } 72 | #endif 73 | 74 | #endif /* IFADDR_UDPXY_0102081930 */ 75 | 76 | /* __EOF__ */ 77 | 78 | -------------------------------------------------------------------------------- /jni/udpxy/extrn.c: -------------------------------------------------------------------------------- 1 | /* @(#) external common resources (variables and constants) 2 | * 3 | * Copyright 2008-2011 Pavel V. Cherenkov (pcherenkov@gmail.com) 4 | * 5 | * This file is part of udpxy. 6 | * 7 | * udpxy is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * udpxy is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with udpxy. If not, see . 19 | */ 20 | 21 | #include 22 | #include 23 | #include 24 | 25 | /* server commands 26 | */ 27 | const char CMD_UDP[] = "udp"; 28 | const char CMD_STATUS[] = "status"; 29 | const char CMD_RESTART[] = "restart"; 30 | const char CMD_RTP[] = "rtp"; 31 | 32 | const size_t CMD_UDP_LEN = sizeof(CMD_UDP); 33 | const size_t CMD_STATUS_LEN = sizeof(CMD_STATUS); 34 | const size_t CMD_RESTART_LEN = sizeof(CMD_RESTART); 35 | const size_t CMD_RTP_LEN = sizeof(CMD_RTP); 36 | 37 | const char UDPXY_COPYRIGHT_NOTICE[] = 38 | "udpxy and udpxrec are Copyright (C) 2008-2018 Pavel V. Cherenkov and licensed under GNU GPLv3"; 39 | const char UDPXY_CONTACT[] = 40 | "Email: support@udpxy.com; Telegram: GigaX-discussions; Google+: udpxy community"; 41 | 42 | #ifndef TRACE_MODULE 43 | const char COMPILE_MODE[] = "lean"; 44 | #else 45 | const char COMPILE_MODE[] = "standard"; 46 | #endif 47 | 48 | const char g_udpxy_app[] = "udpxy"; 49 | 50 | #ifdef UDPXREC_MOD 51 | const char g_udpxrec_app[] = "udpxrec"; 52 | #endif 53 | 54 | const char IPv4_ALL[] = "0.0.0.0"; 55 | 56 | const char VERSION[] = 57 | #include "VERSION" 58 | ; 59 | 60 | const int BUILDNUM = 61 | #include "BUILD" 62 | ; 63 | 64 | const int PATCH = 65 | #include "PATCH" 66 | ; 67 | 68 | const char BUILD_TYPE[] = 69 | #include "BLDTYPE" 70 | ; 71 | 72 | /* application log */ 73 | FILE* g_flog = NULL; 74 | 75 | /* signal-handler set quit flag */ 76 | volatile sig_atomic_t g_quit = 0; 77 | 78 | 79 | /* __EOF__ */ 80 | 81 | -------------------------------------------------------------------------------- /jni/udpxy/prbuf.h: -------------------------------------------------------------------------------- 1 | /* @(#) interface to memory-buffer printf API 2 | * 3 | * Copyright 2008-2011 Pavel V. Cherenkov (pcherenkov@gmail.com) 4 | * 5 | * This file is part of udpxy. 6 | * 7 | * udpxy is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * udpxy is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with udpxy. If not, see . 19 | */ 20 | 21 | #ifndef PRBUF_H_12272007bsl_ 22 | #define PRBUF_H_12272007bsl_ 23 | 24 | typedef struct printbuf* prbuf_t; 25 | 26 | #ifdef __cplusplus 27 | extern "C" { 28 | #endif 29 | 30 | 31 | /* create/open print buffer 32 | * 33 | * @param pb - address of the new print buffer 34 | * @param buf - (pre-allocated) memory buffer 35 | * to associate new printbuffer with 36 | * @param n - size (in bytes) of the memory buffer 37 | * 38 | * @return 0 if success: contents of pb are updated with 39 | * the address on new printbuffer; -1 otherwise 40 | */ 41 | int prbuf_open( prbuf_t* pb, void* buf, size_t n ); 42 | 43 | 44 | /* close print buffer 45 | * 46 | * @param pb - print buffer to close 47 | * 48 | * @return 0 if success, -1 otherwise 49 | */ 50 | int prbuf_close( prbuf_t pb ); 51 | 52 | 53 | /* write a formatted string into the print buffer, 54 | * beginning at the current position (each write 55 | * advances the position appropriately) 56 | * 57 | * @param - destination print buffer 58 | * @param - printf-style format string 59 | * 60 | * @return 0 if end of buffer has been reached, 61 | * -1 in case of error, 62 | * n > 0, where n is the number of characters written 63 | * into the buffer (not including trailing zero character) 64 | */ 65 | int prbuf_printf( prbuf_t pb, const char* format, ... ); 66 | 67 | 68 | /* @ return length of the text inside the buffer 69 | * NOT including the termination zero character 70 | * 71 | */ 72 | size_t prbuf_len( prbuf_t pb ); 73 | 74 | 75 | /* set current position to the beginning of the print buffer 76 | * 77 | * @param pb - destination print buffer 78 | */ 79 | void prbuf_rewind( prbuf_t pb ); 80 | 81 | #ifdef __cplusplus 82 | } 83 | #endif 84 | 85 | #endif /* PRBUF_H_12272007bsl_ */ 86 | 87 | /* __EOF__ */ 88 | 89 | -------------------------------------------------------------------------------- /jni/udpxy/prbuf.c: -------------------------------------------------------------------------------- 1 | /* @(#) formatted printing into a buffer 2 | * 3 | * Copyright 2008-2011 Pavel V. Cherenkov (pcherenkov@gmail.com) 4 | * 5 | * This file is part of udpxy. 6 | * 7 | * udpxy is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * udpxy is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with udpxy. If not, see . 19 | */ 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #include "prbuf.h" 30 | 31 | struct printbuf 32 | { 33 | char* buf; 34 | size_t len, 35 | pos; 36 | }; 37 | 38 | 39 | int 40 | prbuf_open( prbuf_t* pb, void* buf, size_t n ) 41 | { 42 | prbuf_t p = NULL; 43 | 44 | assert( pb && buf && (n > (size_t)0) ); 45 | 46 | p = malloc( sizeof(struct printbuf) ); 47 | if( NULL == p ) return -1; 48 | 49 | *pb = p; 50 | 51 | p->buf = (char*)buf; 52 | p->len = n; 53 | p->pos = 0; 54 | 55 | return 0; 56 | } 57 | 58 | 59 | void 60 | prbuf_rewind( prbuf_t pb ) 61 | { 62 | assert( pb ); 63 | 64 | pb->pos = 0; 65 | pb->buf[0] = '\0'; 66 | } 67 | 68 | 69 | 70 | int 71 | prbuf_close( prbuf_t pb ) 72 | { 73 | assert( pb ); 74 | 75 | free( pb ); 76 | return 0; 77 | } 78 | 79 | size_t 80 | prbuf_len( prbuf_t pb ) 81 | { 82 | assert( pb ); 83 | return pb->pos; 84 | } 85 | 86 | int 87 | prbuf_printf( prbuf_t pb, const char* format, ... ) 88 | { 89 | va_list ap; 90 | char* p = NULL; 91 | int n = -1; 92 | size_t left; 93 | 94 | assert( pb && format ); 95 | 96 | if( pb->pos >= pb->len ) return 0; 97 | 98 | left = pb->len - pb->pos - 1; 99 | p = pb->buf + pb->pos; 100 | 101 | va_start( ap, format ); 102 | errno = 0; 103 | n = vsnprintf( p, left, format, ap ); 104 | va_end( ap ); 105 | 106 | if( n < 0 ) return -1; 107 | 108 | if( (size_t)n >= left ) { 109 | n = left; 110 | } 111 | 112 | p[ n ] = '\0'; 113 | pb->pos += (size_t)n; 114 | return n; 115 | } 116 | 117 | 118 | /* __EOF__ */ 119 | 120 | -------------------------------------------------------------------------------- /jni/udpxy/udpxy.h: -------------------------------------------------------------------------------- 1 | /* @(#) common definitions for udpxy 2 | * 3 | * Copyright 2008-2012 Pavel V. Cherenkov (pcherenkov@gmail.com) 4 | * 5 | * This file is part of udpxy. 6 | * 7 | * udpxy is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * udpxy is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with udpxy. If not, see . 19 | */ 20 | 21 | #ifndef UDPXY_H_0110081654 22 | #define UDPXY_H_0110081654 23 | 24 | #include 25 | 26 | /* application error codes 27 | * 28 | */ 29 | static const int ERR_PARAM = 1; /* invalid parameter(s) */ 30 | static const int ERR_REQ = 2; /* error parsing request */ 31 | static const int ERR_INTERNAL = 3; /* internal error */ 32 | 33 | static const int LQ_BACKLOG = 16; /* server backlog value */ 34 | static const int RCV_LWMARK = 0; /* low watermaek on the receiving (m-cast) socket */ 35 | 36 | /* max size of string with IPv4 address */ 37 | #define IPADDR_STR_SIZE 16 38 | 39 | /* max size of string with TCP/UDP port */ 40 | #define PORT_STR_SIZE 6 41 | 42 | /* max length of an HTTP command */ 43 | #define MAX_CMD_LEN 31 44 | 45 | /* max length of a command parameter (address:port, etc.) */ 46 | #define MAX_PARAM_LEN 79 47 | 48 | /* max length of a command's supplementary part (URI-embedded variables) */ 49 | #define MAX_TAIL_LEN 255 50 | 51 | static const int ETHERNET_MTU = 1500; 52 | 53 | /* socket timeouts in seconds */ 54 | #define RLY_SOCK_TIMEOUT 5 55 | #define SRVSOCK_TIMEOUT 1 56 | #define SSEL_TIMEOUT 1 57 | 58 | /* time-out (sec) to hold buffered data 59 | * before sending/flushing to client(s) */ 60 | #define DHOLD_TIMEOUT 1 61 | 62 | typedef u_short flag_t; 63 | #if !defined( uf_TRUE ) && !defined( uf_FALSE ) 64 | #define uf_TRUE ((flag_t)1) 65 | #define uf_FALSE ((flag_t)0) 66 | #else 67 | #error uf_TRUE or uf_FALSE already defined 68 | #endif 69 | 70 | #ifndef MAXPATHLEN 71 | #define MAXPATHLEN 1024 72 | #endif 73 | 74 | /* max size of string with IPv4 address */ 75 | #define IPADDR_STR_SIZE 16 76 | 77 | typedef struct tmfd { 78 | int fd; 79 | time_t atime; 80 | } tmfd_t; 81 | 82 | #endif /* UDPXY_H_0110081654 */ 83 | 84 | /* __EOF__ */ 85 | 86 | -------------------------------------------------------------------------------- /jni/udpxy/doc/en/udpxrec.1: -------------------------------------------------------------------------------- 1 | .\" 2 | .\" udpxrec.1 3 | .\" 4 | .\" Original: (pcherenkov@gmail.com) 5 | .\" 6 | .TH udpxrec 1 "November 18, 2012" "Version 1.0" "udpxrec manual page" 7 | 8 | .SH NAME 9 | udpxrec \- a programmable multicast traffic recording utility. 10 | 11 | .SH SYNOPSIS 12 | .B udpxrec 13 | [\-v] [\-b \fI\fP] [\-e \fI\fP] [\-M \fI\fP] [\-p \fI\fP] [\-B \fI\fP] 14 | [\-n \fI\fP] [\-u \fI\fP] [\-m \fI\fP] [\-l \fI\fP] \-c \fI\fP:\fI\fP \fI\fP 15 | 16 | .SH DESCRIPTION 17 | .PP 18 | udpxrec is a utility designed to record (save into a disk file) a segment of multicast network traffic; the amount of data saved/recorded could be specified in length (KB) or duration (seconds). 19 | 20 | .SH OPTIONS 21 | udpxrec accepts the following options: 22 | 23 | .TP 8 24 | .B \-v 25 | Enable verbose output [default = \fIdisabled\fP]. 26 | .TP 8 27 | .B \-T 28 | Do NOT run as a daemon [default = \fIdaemon if root\fP]. 29 | .TP 8 30 | .B \-m \fI\fP 31 | IPv4 address/interface of (multicast) source [default = \fI0.0.0.0\fP]. 32 | .TP 8 33 | .B \-l \fI\fP 34 | Log output to file [default = \fIstderr\fP]. 35 | .TP 8 36 | .B \-n \fI\fP 37 | Nice value increment [default = \fI0\fP]. 38 | .TP 8 39 | .B \-B \fI\fP 40 | Buffer size (65536, 32Kb, 1Mb) for inbound (multicast) data [default = \fI2048 bytes\fP]. 41 | .TP 8 42 | .B \-R \fI\fP 43 | Maximum number of messages to buffer (\fI\-1\fP = \fIall\fP) [default = \fI1\fP]. 44 | .TP 8 45 | .B \-b \fI\fP 46 | Begin recording at \fI[+]dd:hh24:mi.ss\fP, '\fB+\fP' signifies relative timing (in N hours/min/sec). 47 | .TP 8 48 | .B \-e \fI\fP 49 | Stop recording at \fI[+]dd:hh24:mi.ss\fP, '\fB+\fP' signifies relative timing (in N hours/min/sec). 50 | .TP 8 51 | .B \-M \fI\fP 52 | Maximum size of destination file. 53 | .TP 8 54 | .B \-p \fI\fP 55 | Pidfile for this process [\fBMUST be specified if daemon\fP]. 56 | .TP 8 57 | .B \-u \fI\fP 58 | Seconds to wait before updating on how long till recording starts. 59 | 60 | .SH EXAMPLES 61 | .PP 62 | .B udpxrec \-b 15:45.00 \-e +2:00.00 \-M 1.5Gb \-n 2 \-B 64K \-c 224.0.11.31:5050 /opt/video/tv5.mpg 63 | .PP 64 | Begin recording multicast channel 224.0.11.31:5050 at 15:45 today, 65 | finish recording in two hours or if destination file size >= 1.5 Gb; 66 | set socket buffer to 64Kb; increment nice value by 2; 67 | write captured video to /opt/video/tv5.mpg. 68 | 69 | .SH AUTHORS 70 | Pavel V. Cherenkov and all the good people who submitted patches or otherwise contributed to the project. 71 | 72 | .SH "SEE ALSO" 73 | .BR udpxy (1) 74 | 75 | .\" __EOF__ 76 | 77 | -------------------------------------------------------------------------------- /jni/udpxy/test/cache.h: -------------------------------------------------------------------------------- 1 | /* @(#) header of data-stream cache for udpxy 2 | * 3 | * Copyright 2008-2011 Pavel V. Cherenkov (pcherenkov@gmail.com) 4 | * 5 | * This file is part of udpxy. 6 | * 7 | * udpxy is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * udpxy is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with udpxy. If not, see . 19 | */ 20 | 21 | #ifndef UDPXY_CACHEH_06122008 22 | #define UDPXY_CACHEH_06122008 23 | 24 | #include 25 | 26 | #include "dpkt.h" 27 | 28 | extern FILE* g_flog; 29 | 30 | struct chunk { 31 | char* data; 32 | size_t length; 33 | size_t used_length; 34 | 35 | struct dstream_ctx 36 | spc; 37 | 38 | 39 | struct chunk* next; 40 | }; 41 | 42 | struct dscache; 43 | 44 | #define ERR_CACHE_END 20 /* reached end of data */ 45 | #define ERR_CACHE_ALLOC 21 /* cannot allocate memory */ 46 | #define ERR_CACHE_BADDATA 22 /* data at a cache's head is invalid */ 47 | #define ERR_CACHE_INTRNL 99 /* internal error */ 48 | 49 | #ifdef __cplusplus 50 | extern "C" { 51 | #endif 52 | 53 | /* initialize the cache 54 | */ 55 | struct dscache* 56 | dscache_init( size_t maxlen, struct dstream_ctx* spc, 57 | size_t chunklen, unsigned nchunks ); 58 | 59 | 60 | /* get chunk at R-head, allocate new one if needed 61 | */ 62 | struct chunk* 63 | dscache_rget( struct dscache* cache, int* error ); 64 | 65 | 66 | /* specify length of the used chunk's portion 67 | */ 68 | int 69 | dscache_rset( struct dscache* cache, size_t usedlen ); 70 | 71 | 72 | /* specify length of the used chunk's portion 73 | * and advance R-head 74 | */ 75 | int 76 | dscache_rnext( struct dscache* cache, size_t usedlen ); 77 | 78 | 79 | /* get a chunk at W-head 80 | */ 81 | struct chunk* 82 | dscache_wget( struct dscache* cache, int* error ); 83 | 84 | 85 | /* advance (W-head) to the next chunk, 86 | * release unneeded resources 87 | */ 88 | int 89 | dscache_wnext( struct dscache* cache, int* error ); 90 | 91 | 92 | /* release all resources from cache 93 | */ 94 | void 95 | dscache_free( struct dscache* cache ); 96 | 97 | 98 | #ifdef __cplusplus 99 | } 100 | #endif 101 | 102 | 103 | #endif /* UDPXY_CACHEH_06122008 */ 104 | 105 | /* __EOF__*/ 106 | 107 | 108 | -------------------------------------------------------------------------------- /jni/udpxy/rparse.h: -------------------------------------------------------------------------------- 1 | /* @(#) header for parsing functions for udpxy 2 | * 3 | * Copyright 2008-2011 Pavel V. Cherenkov (pcherenkov@gmail.com) 4 | * 5 | * This file is part of udpxy. 6 | * 7 | * udpxy is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * udpxy is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with udpxy. If not, see . 19 | */ 20 | 21 | #ifndef RPARSE_H_121420071651_ 22 | #define RPARSE_H_121420071651_ 23 | 24 | #include 25 | #include 26 | 27 | #ifdef __cplusplus 28 | extern "C" { 29 | #endif 30 | 31 | /* parse and copy parameters of HTTP GET request into 32 | * request buffer 33 | * 34 | * @param src buffer with raw source data 35 | * @param srclen length of raw data 36 | * @param request destination buffer for the request 37 | * @param rqlen length of request buffer on entry 38 | * length of request on exit 39 | * 40 | * @return 0 if success: request buffer gets populated, 41 | * non-zero if error 42 | */ 43 | int 44 | get_request( const char* src, size_t srclen, 45 | char* request, size_t* rqlen ); 46 | 47 | 48 | /* parse (GET) request into command and parameters (options) 49 | * c-strings 50 | * 51 | * @param s source c-string 52 | * @param cmd buffer for the parsed command c-string 53 | * @param clen length of command buffer 54 | * @param opt buffer for the parsed options c-string 55 | * @param optlen length of options buffer 56 | * @param tail buffer for tail (whatever is beyond options) 57 | * @param tlen length of tail buffer 58 | * 59 | * @return 0 if success: cmd and opt get get populated 60 | * non-zero if an error ocurred 61 | */ 62 | int 63 | parse_param( const char* s, size_t slen, 64 | char* cmd, size_t clen, 65 | char* opt, size_t optlen, 66 | char* tail, size_t tlen); 67 | 68 | 69 | /* parse options of upd-relay command into IP address 70 | * and port 71 | * 72 | * @param opt options string 73 | * @param optlen options string size (including zero-terminating byte) 74 | * @param addr destination for address string 75 | * @param addrlen length of address string buffer 76 | * @param port port to populate 77 | * 78 | * @return 0 if success: inaddr and port get populated 79 | * non-zero if error 80 | */ 81 | int 82 | parse_udprelay( const char* opt, size_t optlen, 83 | char* addr, size_t addrlen, 84 | uint16_t* port ); 85 | 86 | 87 | #ifdef __cplusplus 88 | } /* extern "C" */ 89 | #endif 90 | 91 | #endif 92 | 93 | /* __EOF__ */ 94 | 95 | -------------------------------------------------------------------------------- /jni/udpxy/util/mkipk.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # @(#) utility to create ipkg package for a udpxy distro 3 | 4 | # extract architecture tag from file 5 | getarch() 6 | { 7 | fname=${1:?} 8 | 9 | tag=`file -b $fname | cut -d',' -f2 | tr -d ' '` || return 1 10 | case "$tag" in 11 | Intel80386) arch=i686 ;; 12 | MIPS*) arch=mipsel ;; 13 | *) arch=$tag ;; 14 | esac 15 | 16 | echo $arch 17 | return 0 18 | } 19 | 20 | #### 21 | # main 22 | # 23 | 24 | if [ $# -lt 1 ]; then 25 | echo >&2 Usage: $0 udpxy_source_dir package_dest_dir 26 | exit $? 27 | fi 28 | 29 | udpxy_root=${1:?} 30 | destdir=${2:-.} 31 | 32 | if [ ! -d "$udpxy_root" -o ! -d "$destdir" ]; then 33 | echo >&2 "Cannot find [$udpxy_root] or [$destdir] directory" 34 | exit 1 35 | fi 36 | 37 | binfiles="$udpxy_root/udpxy $udpxy_root/udpxrec" 38 | 39 | files="$binfiles $udpxy_root/BUILD $udpxy_root/VERSION" 40 | for f in `echo $files`; do 41 | if [ ! -f "$f" ]; then 42 | echo >&2 "$0: Cannot find [$f] executable" 43 | exit 1 44 | fi 45 | done 46 | 47 | if ! type ipkg-build >/dev/null 2>&1; then 48 | echo >&2 "$0: ipkg-build tool is not accessible" 49 | exit 1 50 | else 51 | build=`which ipkg-build` || exit 1 52 | fi 53 | 54 | ARCH=`getarch $udpxy_root/udpxy 2>/dev/null` || return $? 55 | [ -n "$MKIPK_DEBUG" ] && echo "Architecture: [${ARCH}]" 56 | 57 | #case $EUID in 58 | # 0) SUDO= ;; 59 | # *) SUDO=sudo ;; 60 | #esac 61 | SUDO= 62 | : ${MKIPK_USE_TAR:='1'} 63 | 64 | 65 | rc=1; while : 66 | do 67 | ipkg_dir=${TMPDIR:-/tmp}/ipkg.$$ 68 | 69 | ${SUDO} mkdir -p $ipkg_dir/opt/bin $ipkg_dir/CONTROL || break 70 | 71 | UDPXY_NAME="udpxy" 72 | VERSION=`cat $udpxy_root/VERSION | tr -d '"'`-`cat $udpxy_root/BUILD` 73 | control_spec=$ipkg_dir/CONTROL/control 74 | 75 | [ -n "$MKIPK_DEBUG" ] && echo >&2 "Creating [$control_spec]" 76 | ${SUDO} touch $control_spec || break 77 | ${SUDO} chmod o+w $control_spec || break 78 | 79 | cat <<__EOM_ >$control_spec 80 | Package: $UDPXY_NAME 81 | Architecture: ${ARCH} 82 | Priority: optional 83 | Section: base 84 | Version: ${VERSION} 85 | Maintainer: Pavel Cherenkov 86 | Source: http://downloads.sourceforge.net/udpxy/udpxy.${VERSION}.tgz 87 | Description: UDP-to-HTTP multicast traffic relay daemon 88 | Depends: 89 | Suggests: 90 | Conflicts: 91 | __EOM_ 92 | [ $? -eq 0 ] || break 93 | 94 | ${SUDO} cp -P $binfiles $ipkg_dir/opt/bin || break 95 | if [ -n "${STRIP}" ]; then 96 | [ -n "${MKIPK_DEBUG}" ] && echo >&2 "Stripping udpxy executable" 97 | ${SUDO} ${STRIP} $ipkg_dir/opt/bin/udpxy || break 98 | [ -n "${MKIPK_DEBUG}" ] && ls -lh $ipkg_dir/opt/bin/udpxy 99 | fi 100 | 101 | buildopt="-o root -g root" 102 | [ -n "${MKIPK_USE_TAR}" -a "0" != "${MKIPK_USE_TAR}" ] && \ 103 | buildopt="$buildopt -c" 104 | ${SUDO} ${build} $buildopt $ipkg_dir $destdir || break 105 | 106 | rc=0; break 107 | done 108 | 109 | if [ -z "$MKIPK_DEBUG" ]; then 110 | ${SUDO} rm -fr $ipkg_dir 111 | else 112 | echo >&2 "Leaving behind [$ipkg_dir]" 113 | fi 114 | 115 | [ -n "${MKIPK_DEBUG}" ] && echo "$0: exiting with rc=$rc" 116 | exit $rc 117 | 118 | # __EOF__ 119 | 120 | -------------------------------------------------------------------------------- /jni/udpxy/netop.h: -------------------------------------------------------------------------------- 1 | /* @(#) interface to network operations for udpxy 2 | * 3 | * Copyright 2008-2011 Pavel V. Cherenkov (pcherenkov@gmail.com) (pcherenkov@gmail.com) 4 | * 5 | * This file is part of udpxy. 6 | * 7 | * udpxy is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * udpxy is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with udpxy. If not, see . 19 | */ 20 | 21 | #ifndef NETOP_UDPXY_0313082217_ 22 | #define NETOP_UDPXY_0313082217_ 23 | 24 | #include 25 | 26 | struct in_addr; 27 | struct sockaddr_in; 28 | 29 | #ifdef __cplusplus 30 | extern "C" { 31 | #endif 32 | 33 | /* set up (server) listening sockfd 34 | */ 35 | int 36 | setup_listener( const char* ipaddr, int port, int* sockfd, int bklog ); 37 | 38 | 39 | /* set up the socket to receive multicast data 40 | * 41 | */ 42 | int 43 | setup_mcast_listener( struct sockaddr_in* sa, 44 | const struct in_addr* mifaddr, 45 | int* mcastfd, 46 | int sockbuflen ); 47 | 48 | 49 | /* unsubscribe from multicast and close the reader socket 50 | * 51 | */ 52 | void 53 | close_mcast_listener( int msockfd, const struct in_addr* mifaddr ); 54 | 55 | 56 | /* add or drop membership in a multicast group 57 | */ 58 | int 59 | set_multicast( int msockfd, const struct in_addr* mifaddr, 60 | int opname ); 61 | 62 | 63 | /* drop from and add into a multicast group 64 | */ 65 | int 66 | renew_multicast( int msockfd, const struct in_addr* mifaddr ); 67 | 68 | 69 | /* set send/receive timeouts on socket(s) 70 | */ 71 | int 72 | set_timeouts( int rsock, int ssock, 73 | u_short rcv_tmout_sec, u_short rcv_tmout_usec, 74 | u_short snd_tmout_sec, u_short snd_tmout_usec ); 75 | 76 | 77 | /* set socket's send buffer value 78 | */ 79 | int 80 | set_sendbuf( int sockfd, const size_t len ); 81 | 82 | 83 | /* set socket's send buffer value 84 | */ 85 | int 86 | set_rcvbuf( int sockfd, const size_t len ); 87 | 88 | 89 | /* get socket's send buffer size 90 | */ 91 | int 92 | get_sendbuf( int sockfd, size_t* const len ); 93 | 94 | 95 | /* get socket's send buffer size 96 | */ 97 | int 98 | get_rcvbuf( int sockfd, size_t* const len ); 99 | 100 | 101 | /* set/clear file/socket's mode as non-blocking 102 | */ 103 | int 104 | set_nblock( int fd, int set ); 105 | 106 | /* retrieve string address, int port of local/remote 107 | end of the socket 108 | */ 109 | int 110 | get_sockinfo (int sockfd, char* addr, size_t alen, int* port); 111 | int 112 | get_peerinfo (int sockfd, char* addr, size_t alen, int* port); 113 | 114 | #ifdef __cplusplus 115 | } 116 | #endif 117 | 118 | 119 | #endif /* NETOP_UDPXY_0313082217_ */ 120 | 121 | 122 | /* __EOF__ */ 123 | 124 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | # Android udpxy 6 | Android library-project wrapper for **udpxy** UDP-to-HTTP Proxy Server. 7 | 8 | udpxy is a RTP-to-HTTP proxy server that will convert the RTP/UDP multicast stream to HTTP unicast. 9 | 10 | ## Download & Usage 11 | Download *udpxy* binary for Android from [Release](https://github.com/ewwink/android-udpxy/releases) page, install `Termux` or any terminal emulator for Android and run the following command 12 | 13 | for single network interface 14 | 15 | ./udpxy -p 8888 16 | 17 | for multiple network interface 18 | 19 | ./udpxy -vT -a wlan0 -m eth0 -p 8888 20 | # or 21 | ./udpxy -vT -a 192.168.1.2 -m 10.70.1.2 -p 8888 22 | 23 | For **non-rooted** device you can't execute udpxy on `sdcard` or `internal storage` try to copy it to `/data/local/` and change permission to executable but if you can't you must use `wget` and download it from server. Open terminal emulator run the following command 24 | 25 | # this is for armeabi-v7a CPU 26 | # for other version see Release page 27 | # 28 | cd $HOME 29 | wget https://github.com/ewwink/android-udpxy/releases/download/1.0/udpxy.armeabi-v7a 30 | mv udpxy.armeabi-v7a udpxy 31 | chmod +x udpxy 32 | 33 | or download from your server 34 | 35 | cd $HOME 36 | wget http://yourServer/udpxy 37 | chmod +x udpxy 38 | 39 | and then run previous command above. 40 | 41 | If it’s working you can see status page in your browser 42 | 43 | http://192.168.1.2:8888/status 44 | 45 | ![udpxy-status](https://user-images.githubusercontent.com/760764/43703419-f2cf42a0-9986-11e8-8768-2a6d0dc109e9.png) 46 | 47 | ### Play the stream 48 | Open your video player like `VLC`, `GoodPlayer` or `MX Player` and input the stream URL like 49 | 50 | http://192.168.1.2:8888/rtp/239.1.1.159:8928 51 | 52 | This will start receiving an RTP multicast stream from `239.1.1.159` on port `8928` (which is ANTV in my setup) and will relay it over HTTP. 53 | 54 | ## Options 55 | 56 | udpxy accepts the following options: 57 | 58 | `-v` Enable verbose output [default = disabled]. 59 | 60 | `-S` Enable client statistics [default = disabled]. 61 | 62 | `-T` Do NOT run as a daemon [default = daemon if root]. 63 | 64 | `-a` IPv4 address/interface to listen on [default = 0.0.0.0]. 65 | 66 | `-m ` IPv4 address/interface of (multicast) source [default = 0.0.0.0]. 67 | 68 | `-c ` Maximum number of clients to accept [default = 3, max = 5000]. 69 | 70 | `-l ` Log output to file [default = stderr]. 71 | 72 | `-B ` Buffer size (65536, 32Kb, 1Mb) for inbound (multicast) data [default = 2048 bytes]. 73 | 74 | `-R ` Maximum number of messages to buffer (-1 = all) [default = 1]. 75 | 76 | `-H ` Maximum time (in seconds) to hold data in a buffer (-1 = unlimited) [default = 1]. 77 | 78 | `-n ` Nice value increment [default = 0]. 79 | 80 | `-M ` Renew multicast subscription every M seconds (skip if 0) [default = 0]. 81 | 82 | `-p ` Port to listen on. 83 | 84 | ## Compile for Android 85 | 86 | This will compile udpxy to binary, to create APK please read rom1v blog in the bottom. Download [NDK](https://developer.android.com/ndk/downloads/), extract and add the directory to your system `path`. 87 | 88 | git clone https://github.com/ewwink/android-udpxy.git 89 | cd android-udpxy/jni/ 90 | ndk-build 91 | 92 | The binary will be generated in `libs/` 93 | 94 | to compile to another OS just run `make` in `jni/` directory. 95 | 96 | --------------------- 97 | ### credits: 98 | - Android wrapper by [rom1v](http://blog.rom1v.com/2014/03/compiler-un-executable-pour-android) 99 | - Original repo [udpxy](https://github.com/pcherenkov/udpxy) 100 | 101 | -------------------------------------------------------------------------------- /jni/udpxy/dpkt.h: -------------------------------------------------------------------------------- 1 | /* @(#) definition of packet-io functions for udpxy 2 | * 3 | * Copyright 2008-2011 Pavel V. Cherenkov (pcherenkov@gmail.com) 4 | * 5 | * This file is part of udpxy. 6 | * 7 | * udpxy is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * udpxy is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with udpxy. If not, see . 19 | */ 20 | 21 | #ifndef UDPXY_DPKTH_02182008 22 | #define UDPXY_DPKTH_02182008 23 | 24 | #include 25 | #include "udpxy.h" 26 | 27 | typedef int upxfmt_t; 28 | 29 | 30 | /* data stream context 31 | */ 32 | struct dstream_ctx { 33 | upxfmt_t stype; 34 | int32_t flags; 35 | size_t mtu; 36 | 37 | struct iovec* pkt; 38 | int32_t max_pkt, 39 | pkt_count; 40 | }; 41 | 42 | /* data-stream context flags 43 | */ 44 | static const int32_t F_DROP_PACKET = (1 << 1); 45 | static const int32_t F_CHECK_FMT = (1 << 2); 46 | static const int32_t F_SCATTERED = (1 << 3); 47 | static const int32_t F_FILE_INPUT = (1 << 4); 48 | 49 | 50 | #ifdef __cplusplus 51 | extern "C" { 52 | #endif 53 | 54 | /* return human-readable name of file/stream format 55 | */ 56 | const char* fmt2str( upxfmt_t fmt ); 57 | 58 | 59 | /* determine type of stream saved in file 60 | */ 61 | upxfmt_t 62 | get_fstream_type( int fd, FILE* log ); 63 | 64 | /* determine type of stream in memory 65 | */ 66 | upxfmt_t 67 | get_mstream_type( const char* data, size_t len, FILE* log ); 68 | 69 | 70 | /* read record of one of the supported types from file 71 | */ 72 | ssize_t 73 | read_frecord( int fd, char* data, const size_t len, 74 | upxfmt_t* stream_type, FILE* log ); 75 | 76 | 77 | /* write record after converting it from source into destination 78 | * format 79 | */ 80 | ssize_t 81 | write_frecord( int fd, const char* data, size_t len, 82 | upxfmt_t sfmt, upxfmt_t dfmt, FILE* log ); 83 | 84 | 85 | /* reset packet-buffer registry in stream context 86 | */ 87 | void 88 | reset_pkt_registry( struct dstream_ctx* ds ); 89 | 90 | 91 | /* release resources allocated for stream context 92 | */ 93 | void 94 | free_dstream_ctx( struct dstream_ctx* ds ); 95 | 96 | 97 | /* initialize incoming-stream context: 98 | * set data type (if possible) and flags 99 | */ 100 | int 101 | init_dstream_ctx( struct dstream_ctx* ds, const char* cmd, const char* fname, 102 | ssize_t nmsgs ); 103 | 104 | 105 | /* read data from source of specified type (UDP socket or otherwise); 106 | * read as many fragments as specified (max_frgs) into the buffer 107 | */ 108 | struct rdata_opt { 109 | int max_frgs; /* max fragments to read in */ 110 | time_t buf_tmout; /* max time (sec) to hold data in buffer */ 111 | }; 112 | 113 | ssize_t 114 | read_data( struct dstream_ctx* spc, int fd, char* data, 115 | const ssize_t data_len, const struct rdata_opt* opt ); 116 | 117 | 118 | /* write data to destination(s) 119 | */ 120 | ssize_t 121 | write_data( const struct dstream_ctx* spc, 122 | const char* data, 123 | const ssize_t len, 124 | int fd ); 125 | 126 | #ifdef __cplusplus 127 | } 128 | #endif 129 | 130 | #endif /* UDPXY_DPKTH_02182008 */ 131 | 132 | /* __EOF__ */ 133 | 134 | -------------------------------------------------------------------------------- /jni/udpxy/rtp.h: -------------------------------------------------------------------------------- 1 | /* @(#) interface to RTP-protocol parsing functions for udpxy 2 | * 3 | * Copyright 2008-2011 Pavel V. Cherenkov (pcherenkov@gmail.com) 4 | * 5 | * This file is part of udpxy. 6 | * 7 | * udpxy is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * udpxy is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with udpxy. If not, see . 19 | */ 20 | 21 | #ifndef RTPH_UDPXY_021308 22 | #define RTPH_UDPXY_021308 23 | 24 | #include 25 | 26 | static const int MPEG_TS_SIG = 0x47; 27 | static const size_t RTP_MIN_SIZE = 4; 28 | static const size_t RTP_HDR_SIZE = 12; /* RFC 3550 */ 29 | static const int RTP_VER2 = 0x02; 30 | 31 | /* offset to header extension and extension length, 32 | * as per RFC 3550 5.3.1 */ 33 | static const size_t XTLEN_OFFSET = 14; 34 | static const size_t XTSIZE = 4; 35 | 36 | /* minimum length to determine size of an extended RTP header 37 | */ 38 | #define RTP_XTHDRLEN (XTLEN_OFFSET + XTSIZE) 39 | 40 | static const size_t CSRC_SIZE = 4; 41 | 42 | /* MPEG payload-type constants - adopted from VLC 0.8.6 */ 43 | #define P_MPGA 0x0E /* MPEG audio */ 44 | #define P_MPGV 0x20 /* MPEG video */ 45 | #define P_MPGTS 0x21 /* MPEG TS */ 46 | 47 | #ifdef __cplusplus 48 | extern "C" { 49 | #endif 50 | 51 | 52 | /* check if the buffer is an RTP packet 53 | * 54 | * @param buf buffer to analyze 55 | * @param len size of the buffer 56 | * @param is_rtp variable to set to 1 if data is an RTP packet 57 | * @param log log file 58 | * 59 | * @return 0 if there was no error, -1 otherwise 60 | */ 61 | int RTP_check( const char* buf, const size_t len, int* is_rtp, FILE* log ); 62 | 63 | 64 | /* process RTP package to retrieve the payload: set 65 | * pbuf to the start of the payload area; set len to 66 | * be equal payload's length 67 | * 68 | * @param pbuf address of pointer to beginning of RTP packet 69 | * @param len pointer to RTP packet's length 70 | * @param verify verify that it is an RTP packet if != 0 71 | * @param log log file 72 | * 73 | * @return 0 if there was no error, -1 otherwise; 74 | * set pbuf to point to beginning of payload and len 75 | * be payload size in bytes 76 | */ 77 | int RTP_process( void** pbuf, size_t* len, int verify, FILE* log ); 78 | 79 | 80 | /* verify if buffer contains an RTP packet, 0 otherwise 81 | * 82 | * @param buf buffer to analyze 83 | * @param len size of the buffer 84 | * @param log error log 85 | * 86 | * @return 1 if buffer contains an RTP packet, 0 otherwise 87 | */ 88 | int RTP_verify( const char* buf, const size_t len, FILE* log ); 89 | 90 | 91 | /* calculate length of an RTP header 92 | * 93 | * @param buf buffer to analyze 94 | * @param len size of the buffer 95 | * @param hdrlen pointer to header length variable 96 | * @param log error log 97 | * 98 | * @return 0 if header length has been calculated, 99 | * ENOMEM if buffer is not big enough 100 | */ 101 | int RTP_hdrlen( const char* buf, const size_t len, size_t* hdrlen, 102 | FILE* log ); 103 | 104 | #ifdef __cplusplus 105 | } 106 | #endif 107 | 108 | #endif /* RTPH_UDPXY_021308 */ 109 | 110 | 111 | /* __EOF__ */ 112 | 113 | -------------------------------------------------------------------------------- /jni/udpxy/gcc.mk: -------------------------------------------------------------------------------- 1 | # @(#) gcc makefile for udpxy project 2 | # 3 | # Copyright 2008 Pavel V. Cherenkov 4 | # 5 | # This file is part of udpxy. 6 | # 7 | # udpxy is free software: you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation, either version 3 of the License, or 10 | # (at your option) any later version. 11 | # 12 | # udpxy is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | # GNU General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License 18 | # along with udpxy. If not, see . 19 | # 20 | 21 | .SUFFIXES : .o .c .d 22 | 23 | EXEC = udpxy 24 | UPXC = upxc 25 | CC = gcc 26 | CFLAGS = -W -Wall -Werror --pedantic 27 | 28 | BUILDFILE = BUILD 29 | BUILDNO = `cat $(BUILDFILE)` 30 | 31 | VERSIONFILE = VERSION 32 | VERSION = `cat $(VERSIONFILE) | tr -d '"'` 33 | 34 | CHANGEFILE = CHANGES 35 | READMEFILE = README 36 | 37 | ARCDIR = .. 38 | ARCFILE = $(ARCDIR)/$(EXEC).$(VERSION)-$(BUILDNO).tgz 39 | WL_ARCFILE = $(ARCDIR)/$(EXEC).wl.$(VERSION)-$(BUILDNO).tgz 40 | 41 | COMMON_OPT = 42 | DEBUG_OPT = $(COMMON_OPT) -g -DTRACE_MODULE 43 | PROD_OPT = $(COMMON_OPT) -DNDEBUG -DTRACE_MODULE 44 | LEAN_OPT = -DNDEBUG 45 | 46 | MKDEPOPT = -M 47 | 48 | SRC = udpxy.c rparse.c util.c prbuf.c ifaddr.c ctx.c mkpg.c \ 49 | rtp.c uopt.c dpkt.c netop.c extrn.c udpxrec.c main.c 50 | OBJ = ${SRC:.c=.o} 51 | DEP = ${SRC:.c=.d} 52 | 53 | UPXC_SRC = upxc.c util.c rtp.c dpkt.c extrn.c 54 | UPXC_OBJ = ${UPXC_SRC:.c=.o} 55 | UPXC_DEP = upxc.dep 56 | 57 | WLDIR = udpxy-wl 58 | 59 | CORES = core.* core 60 | 61 | .c.d : 62 | $(CC) $(CFLAGS) $(MKDEPOPT) $< -o $@ 63 | 64 | .c.o : 65 | $(CC) $(CFLAGS) $(CDEFS) $(COPT) -c $< -o $@ 66 | 67 | release: 68 | @echo -e "\nMaking a [release] version (use 'debug' target as an alternative)\n" 69 | @make all "COPT=${PROD_OPT}" 70 | @strip $(EXEC) 71 | 72 | debug: 73 | @echo -e "\nMaking a [debug] version (use 'release' target as an alternative)\n" 74 | @make all "COPT=${DEBUG_OPT}" 75 | 76 | lean: 77 | @echo -e "\nMaking a [lean] version (minimal size)\n" 78 | @make all "COPT=${LEAN_OPT}" 79 | @strip $(EXEC) 80 | 81 | verify: 82 | @echo -e "\nVerifying all build targets\n" 83 | @make clean 84 | @make lean 85 | @make clean 86 | @make release 87 | @make clean 88 | @make debug 89 | make clean 90 | 91 | all: $(DEP) $(UPXC_DEP) $(EXEC) 92 | # include $(UPXC) (if needed) in all target to build 93 | 94 | deps: 95 | $(CC) $(CFLAGS) $(MKDEPOPT) $(SRC) 96 | 97 | -include $(DEP) $(UPXC_DEP) 98 | 99 | $(DEP): $(SRC) 100 | $(UPXC_DEP) : $(UPXC_SRC) 101 | 102 | $(EXEC) : $(OBJ) 103 | @rm -f $(EXEC) 104 | $(CC) $(CFLAGS) $(COPT) -o $(EXEC) $(OBJ) 105 | @ls -l $(EXEC) 106 | 107 | $(UPXC) : $(UPXC_OBJ) 108 | rm -f $(UPXC) 109 | $(CC) $(CFLAGS) $(COPT) -o $(UPXC) $(UPXC_OBJ) 110 | ls -l $(UPXC) 111 | 112 | strip: 113 | @echo "Stripping $(EXEC)" 114 | @strip $(EXEC) $(UPXC) 115 | @ls -l $(EXEC) $(UPXC) 116 | 117 | touch: 118 | touch $(SRC) $(UPXC_SRC) 119 | 120 | clean: 121 | rm -f $(CORES) $(DEP) $(OBJ) $(UPXC_DEP) $(UPXC_OBJ) $(EXEC) $(UPXC) 122 | 123 | incbuild: 124 | @expr `cat $(BUILDFILE)` + 1 > $(BUILDFILE) 125 | @echo "Set build number to: `cat $(BUILDFILE)`" 126 | @make touch 127 | 128 | tar: 129 | tar -cvzf $(ARCFILE) $(SRC) *.h *.mk *.txt \ 130 | $(BUILDFILE) $(VERSIONFILE) $(CHANGEFILE) $(READMEFILE) 131 | @ls -l $(ARCFILE) 132 | 133 | wl-distro: 134 | rm -fr $(WLDIR) 135 | mkdir $(WLDIR) 136 | cp $(SRC) $(UPXC_SRC) *.h gpl.txt \ 137 | $(BUILDFILE) $(VERSIONFILE) $(CHANGEFILE) $(READMEFILE) $(WLDIR) 138 | cp wl500-gcc.mk $(WLDIR)/makefile 139 | tar -cvzf $(WL_ARCFILE) $(WLDIR)/* 140 | @ls -l $(WL_ARCFILE) 141 | rm -fr $(WLDIR) 142 | 143 | # __EOF__ 144 | 145 | -------------------------------------------------------------------------------- /jni/udpxy/test/test_cache.c: -------------------------------------------------------------------------------- 1 | /* @(#) unit test of udpxy data-stream cache */ 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "util.h" 9 | #include "cache.h" 10 | #include "dpkt.h" 11 | #include "udpxy.h" 12 | 13 | extern FILE* g_flog; 14 | 15 | extern const char CMD_UDP[]; 16 | 17 | #define BUFSZ (64 * 1024) 18 | #define NUM_MSGS (BUFSZ / ETHERNET_MTU) 19 | #define CACHE_MAXSZ (BUFSZ * 10) 20 | 21 | static struct dscache* cache = NULL; 22 | static struct dstream_ctx spc; 23 | 24 | 25 | static int 26 | test_init() 27 | { 28 | int rc = 0; 29 | 30 | (void) fprintf( g_flog, "\n%s: TEST STARTED\n", __func__ ); 31 | 32 | rc = init_dstream_ctx( &spc, CMD_UDP, NULL, NUM_MSGS ); 33 | if( 0 != rc ) 34 | return -1; 35 | 36 | cache = dscache_init( CACHE_MAXSZ, &spc, BUFSZ, 3 ); 37 | if( NULL == cache ) 38 | return -1; 39 | 40 | dscache_free( cache ); 41 | free_dstream_ctx( &spc ); 42 | 43 | (void) fprintf( g_flog, "\n%s: TEST FINISHED\n", __func__ ); 44 | return 0; 45 | } 46 | 47 | 48 | static void 49 | dump_chunk( FILE* out, const struct chunk* chnk, 50 | const char* tag ) 51 | { 52 | assert( out && chnk ); 53 | 54 | (void) fprintf( out, "%s(%p)=[l:%ld,u:%ld,n:%p]\n", 55 | (tag ? tag : "chunk"), (const void*)chnk, 56 | (long)chnk->length, 57 | (long)chnk->used_length, (const void*)chnk->next ); 58 | } 59 | 60 | 61 | 62 | static int 63 | test_read_into() 64 | { 65 | int rc = 0, numiter = 10; 66 | ssize_t i; 67 | struct chunk *rchnk = NULL, *wchnk = NULL; 68 | 69 | (void) fprintf( g_flog, "\n%s: TEST STARTED\n", __func__ ); 70 | 71 | rc = init_dstream_ctx( &spc, CMD_UDP, NULL, NUM_MSGS ); 72 | if( 0 != rc ) 73 | return -1; 74 | 75 | cache = dscache_init( CACHE_MAXSZ, &spc, BUFSZ, 3 ); 76 | if( NULL == cache ) 77 | return -1; 78 | 79 | do { 80 | (void) fprintf( g_flog, "%d: -------- BEGIN\n", 81 | numiter ); 82 | 83 | rchnk = dscache_rget( cache, &rc ); 84 | if( !rchnk ) break; 85 | 86 | dump_chunk( g_flog, rchnk, "R" ); 87 | 88 | for( i = 0; i < (rchnk->length - 64); ++i ) 89 | rchnk->data[i] = 'U'; 90 | 91 | (void) fprintf( g_flog, "%d: data updated [%ld]\n", 92 | numiter, (long)i ); 93 | 94 | rc = dscache_rset( cache, i ); 95 | if( 0 != rc ) break; 96 | 97 | wchnk = dscache_wget( cache, &rc ); 98 | if( !wchnk ) break; 99 | 100 | (void) fprintf( g_flog, "%d: grabbed W-chunk(%p)\n", 101 | numiter, (const void*)wchnk ); 102 | dump_chunk( g_flog, wchnk, "W" ); 103 | 104 | for( i = 0; (i < wchnk->used_length) && !rc; ++i ) { 105 | if( 'U' != wchnk->data[i] ) 106 | rc = 1; 107 | } 108 | 109 | (void) fprintf( g_flog, "%d: W-chunk(%p) read\n", 110 | numiter, (const void*)wchnk ); 111 | 112 | (void) fprintf( g_flog, "%d: -------- END\n", numiter ); 113 | } while( --numiter > 0 ); 114 | 115 | if( rc ) { 116 | (void) fprintf( g_flog, "Error = [%d]\n", rc ); 117 | } 118 | 119 | dscache_free( cache ); 120 | free_dstream_ctx( &spc ); 121 | 122 | (void) fprintf( g_flog, "\n%s: TEST FINISHED\n", __func__ ); 123 | return rc; 124 | } 125 | 126 | 127 | int 128 | main( int argc, char* const argv[] ) 129 | { 130 | int rc = 0, tlevel = 0; 131 | const char* trace_str = getenv( "UDPXY_TRACE_CACHE" ); 132 | 133 | 134 | (void)(&argc && &argv); 135 | 136 | g_flog = stderr; 137 | if( trace_str ) { 138 | tlevel = atoi( trace_str ); 139 | if( !tlevel && '0' != trace_str[0] ) { 140 | (void) fprintf( g_flog, "Error specifying trace level [%s]\n", 141 | trace_str ); 142 | return 1; 143 | } 144 | 145 | set_cache_trace( tlevel ); 146 | } 147 | 148 | do { 149 | if( 0 != (rc = test_init()) ) 150 | break; 151 | if( 0 != (rc = test_read_into()) ) 152 | break; 153 | 154 | } while(0); 155 | 156 | return rc; 157 | } 158 | 159 | 160 | /* __EOF__ */ 161 | 162 | -------------------------------------------------------------------------------- /jni/udpxy/ctx.h: -------------------------------------------------------------------------------- 1 | /* @(#) client/server context data structures and interfaces 2 | * 3 | * Copyright 2008-2011 Pavel V. Cherenkov (pcherenkov@gmail.com) (pcherenkov@gmail.com) 4 | * 5 | * This file is part of udpxy. 6 | * 7 | * udpxy is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * udpxy is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with udpxy. If not, see . 19 | */ 20 | 21 | 22 | #ifndef UDPXY_CTX_H_0111081738 23 | #define UDPXY_CTX_H_0111081738 24 | 25 | #include 26 | #include 27 | #include 28 | 29 | #include "udpxy.h" 30 | #include "dpkt.h" 31 | 32 | #ifdef __cpluspplus 33 | extern "C" { 34 | #endif 35 | 36 | 37 | /* throughput statistics */ 38 | struct tput_stat { 39 | int32_t sender_id; 40 | double nbytes; /* how many bytes transferred */ 41 | double nsec; /* within how many seconds */ 42 | }; 43 | 44 | /* context of a relay client */ 45 | struct client_ctx 46 | { 47 | pid_t pid; 48 | char mcast_addr[ IPADDR_STR_SIZE ]; 49 | uint16_t mcast_port; 50 | char src_addr[ IPADDR_STR_SIZE ]; 51 | uint16_t src_port; 52 | 53 | struct tput_stat 54 | tstat; 55 | 56 | char tail[ MAX_TAIL_LEN + 1 ]; 57 | }; 58 | 59 | 60 | /* statistics on traffic relay & data gathering 61 | */ 62 | struct tps_data { 63 | pid_t pid; /* our PID - cached */ 64 | time_t tm_from; /* last time update sent (successfully) */ 65 | double niter; /* number of iterations since last try */ 66 | double nbytes; /* bytes transferred since last update */ 67 | }; 68 | 69 | 70 | /* server request components */ 71 | struct srv_request { 72 | char cmd[ MAX_CMD_LEN + 1 ]; 73 | char param[ MAX_PARAM_LEN + 1 ]; 74 | char tail[ MAX_TAIL_LEN + 1 ]; 75 | }; 76 | 77 | 78 | /* context of the server */ 79 | struct server_ctx 80 | { 81 | int lsockfd; 82 | char listen_addr[ IPADDR_STR_SIZE ]; 83 | uint16_t listen_port; 84 | char mcast_ifc_addr[ IPADDR_STR_SIZE ]; 85 | struct in_addr 86 | mcast_inaddr; 87 | 88 | struct srv_request rq; /* (current) request to process */ 89 | 90 | size_t clfree, 91 | clmax; 92 | struct client_ctx* 93 | cl; 94 | u_short rcv_tmout, /* receive/send timeout */ 95 | snd_tmout; 96 | 97 | int cpipe[ 2 ]; /* client communications pipe */ 98 | }; 99 | 100 | 101 | /* initialize server context data 102 | */ 103 | int 104 | init_server_ctx( struct server_ctx* ctx, 105 | const size_t max, 106 | const char* laddr, 107 | uint16_t lport, 108 | const char* mifc_addr ); 109 | 110 | /* release server context 111 | */ 112 | void 113 | free_server_ctx( struct server_ctx* ctx ); 114 | 115 | 116 | /* find index of the first client with the given pid 117 | */ 118 | int 119 | find_client( const struct server_ctx* ctx, pid_t pid ); 120 | 121 | 122 | /* add client to server context 123 | */ 124 | int 125 | add_client( struct server_ctx* ctx, 126 | pid_t cpid, const char* maddr, uint16_t mport, 127 | int sockfd ); 128 | 129 | 130 | /* delete client from server context 131 | */ 132 | int 133 | delete_client( struct server_ctx* ctx, pid_t cpid ); 134 | 135 | 136 | /* init traffic relay statistics 137 | */ 138 | void 139 | tpstat_init( struct tps_data* d, int setpid ); 140 | 141 | 142 | /* send statistics update to server (if it's time) 143 | */ 144 | void 145 | tpstat_update( struct server_ctx* ctx, 146 | struct tps_data* d, ssize_t nbytes ); 147 | 148 | 149 | /* read client statistics data and update the context 150 | */ 151 | int 152 | tpstat_read( struct server_ctx* ctx ); 153 | 154 | 155 | #ifdef __cpluspplus 156 | } 157 | #endif 158 | 159 | #endif /* UDPXY_CTX_H_0111081738 */ 160 | 161 | /* __EOF__ */ 162 | 163 | -------------------------------------------------------------------------------- /jni/udpxy/rparse.c: -------------------------------------------------------------------------------- 1 | /* @(#) parsing functions for udpxy 2 | * 3 | * Copyright 2008-2011 Pavel V. Cherenkov (pcherenkov@gmail.com) 4 | * 5 | * This file is part of udpxy. 6 | * 7 | * udpxy is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * udpxy is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with udpxy. If not, see . 19 | */ 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include 28 | #include 29 | #include 30 | 31 | #include 32 | 33 | #include "rparse.h" 34 | #include "mtrace.h" 35 | 36 | /* parse and copy parameters of HTTP GET request into 37 | * request buffer 38 | * 39 | * @param src buffer with raw source data 40 | * @param srclen length of raw data 41 | * @param request destination buffer for the request 42 | * @param rqlen length of request buffer on entry 43 | * length of request on exit 44 | * 45 | * @return 0 if success: request buffer gets populated, 46 | * non-zero if error 47 | */ 48 | int 49 | get_request( const char* src, size_t srclen, 50 | char* request, size_t* rqlen ) 51 | { 52 | const char HEAD[] = "GET /"; 53 | char* p = NULL; 54 | const char* EOD = src + srclen - 1; 55 | size_t n = 0; 56 | const char SPACE[] = " "; 57 | 58 | p = strstr( src, HEAD ); 59 | if( NULL == p ) return 1; /* no header */ 60 | 61 | p += (sizeof(HEAD) - 1); 62 | if( p >= EOD) /* no request */ 63 | return 2; 64 | 65 | n = strcspn( p, " " ); 66 | if( (SPACE[0] != p[n]) || ((p + n) > EOD) || (n >= *rqlen) ) /* overflow */ 67 | return 3; 68 | 69 | (void) strncpy( request, p, n ); 70 | request[ n ] = '\0'; 71 | 72 | *rqlen = n; 73 | 74 | return 0; 75 | } 76 | 77 | 78 | /* parse (GET) request into command and parameters (options) 79 | * c-strings 80 | * 81 | * @param s source c-string 82 | * @param cmd buffer for the parsed command c-string 83 | * @param clen length of command buffer 84 | * @param opt buffer for the parsed options c-string 85 | * @param optlen length of options buffer 86 | * @param tail buffer for tail (whatever is beyond options) 87 | * @param tlen length of tail buffer 88 | * 89 | * @return 0 if success: cmd and opt get get populated 90 | * non-zero if an error ocurred 91 | */ 92 | int 93 | parse_param( const char* s, size_t slen, 94 | char* cmd, size_t clen, 95 | char* opt, size_t optlen, 96 | char* tail, size_t tlen) 97 | { 98 | const char DLM = '/'; 99 | size_t i, j, n = 0; 100 | 101 | assert( s && cmd && (clen > (size_t)0) && opt && (optlen > (size_t)0) ); 102 | 103 | *cmd = *opt = '\0'; 104 | if( (size_t)0 == slen ) return 0; /* empty source */ 105 | 106 | /* request ::= [DLM] cmd [DLM opt] */ 107 | 108 | /* skip leading delimiter */ 109 | i = ( DLM == s[0] ) ? 1 : 0; 110 | 111 | /* copy into cmd until next delimiter or EOD */ 112 | for( j = 0; (i < slen) && (j < clen) && s[i] && (s[i] != DLM); ) { 113 | cmd[j++] = s[i++]; 114 | } 115 | if( j >= clen ) return EOVERFLOW; 116 | cmd[ j ] = '\0'; 117 | 118 | /* skip dividing delimiter */ 119 | if( DLM == s[i] ) 120 | ++i; 121 | 122 | /* over the edge yet? */ 123 | if (i >= slen) 124 | return 0; 125 | 126 | /* look for '?' separating options from tail */ 127 | n = strcspn(s + i, "?"); 128 | if (n < optlen) { 129 | (void) strncpy( opt, s + i, n ); 130 | opt[n] = '\0'; 131 | } 132 | else 133 | return EOVERFLOW; 134 | 135 | i += n; 136 | if (i >= slen) return 0; 137 | 138 | if (tail && tlen > 0) { 139 | (void) strncpy(tail, s + i, tlen); 140 | tail[tlen - 1] = '\0'; 141 | } 142 | 143 | return 0; 144 | } 145 | 146 | 147 | 148 | /* parse options of upd-relay command into IP address 149 | * and port 150 | * 151 | * @param opt options string 152 | * @param addr destination for address string 153 | * @param addrlen length of address string buffer 154 | * @param port port to populate 155 | * 156 | * @return 0 if success: inaddr and port get populated 157 | * non-zero if error 158 | */ 159 | int 160 | parse_udprelay( const char* opt, size_t optlen, 161 | char* addr, size_t addrlen, 162 | uint16_t* port ) 163 | { 164 | int rc = 1; 165 | size_t n; 166 | int pval; 167 | 168 | const char* SEP = ":%~+-^"; 169 | const int MAX_PORT = 65535; 170 | 171 | #define MAX_OPTLEN 512 172 | char s[ MAX_OPTLEN ]; 173 | 174 | assert( opt && addr && addrlen && port ); 175 | 176 | (void) strncpy( s, opt, MAX_OPTLEN ); 177 | s[ MAX_OPTLEN - 1 ] = '\0'; 178 | do { 179 | n = strcspn( s, SEP ); 180 | if( !n || n >= optlen ) break; 181 | s[n] = '\0'; 182 | 183 | strncpy( addr, s, addrlen ); 184 | addr[ addrlen - 1 ] ='\0'; 185 | 186 | ++n; 187 | pval = atoi( s + n ); 188 | if( (pval > 0) && (pval < MAX_PORT) ) { 189 | *port = (uint16_t)pval; 190 | } 191 | else { 192 | rc = 3; 193 | break; 194 | } 195 | 196 | rc = 0; 197 | } 198 | while(0); 199 | 200 | return rc; 201 | } 202 | 203 | /* __EOF__ */ 204 | 205 | -------------------------------------------------------------------------------- /jni/udpxy/uopt.h: -------------------------------------------------------------------------------- 1 | /* @(#) option definitions and associated structures for udpxy 2 | * 3 | * Copyright 2008-2011 Pavel V. Cherenkov (pcherenkov@gmail.com) 4 | * 5 | * This file is part of udpxy. 6 | * 7 | * udpxy is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * udpxy is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with udpxy. If not, see . 19 | */ 20 | 21 | #ifndef UOPT_H_0215082300 22 | #define UOPT_H_0215082300 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #include "udpxy.h" 30 | 31 | static const int MIN_CLIENT_COUNT = 1; 32 | static const int MAX_CLIENT_COUNT = 5000; 33 | static const int DEFAULT_CLIENT_COUNT = 3; 34 | 35 | static const ssize_t MIN_MCACHE_LEN = 4 * 1024; 36 | static const ssize_t MAX_MCACHE_LEN = 2048 * 1024; 37 | static const ssize_t DEFAULT_CACHE_LEN = 2 * 1024; 38 | static const u_short DEFAULT_MCAST_REFRESH = 0; 39 | 40 | static const ssize_t MIN_SOCKBUF_LEN = (1024 * 64); 41 | 42 | 43 | /* udpxy options 44 | */ 45 | struct udpxy_opt { 46 | flag_t is_verbose; /* verbose output on/off */ 47 | flag_t cl_tpstat; /* client reports throughput stats */ 48 | int nice_incr; /* value to increment nice by */ 49 | ssize_t rbuf_len; /* size of read buffer */ 50 | int rbuf_msgs; /* max msgs in read buffer (-1 = all) */ 51 | int max_clients; /* max clients to accept */ 52 | u_short mcast_refresh; /* refresh rate (sec) for multicast 53 | subscription */ 54 | 55 | time_t rcv_tmout; /* receive (mcast) socket timeout */ 56 | time_t dhold_tmout; /* timeout to hold buffered data (milisec) */ 57 | 58 | time_t sr_tmout, /* server READ/RCV timeout (sec) */ 59 | sw_tmout; /* server WRITE/SND timeout (sec) */ 60 | long ssel_tmout; /* server select/poll timeout (sec) */ 61 | int lq_backlog; /* accept queue length for listening socket */ 62 | int rcv_lwmark; /* receive low watermark on listening socket */ 63 | 64 | flag_t nosync_sbuf, /* do not alter source-socket's buffer size */ 65 | nosync_dbuf; /* do not alter dest-socket's buffer size */ 66 | 67 | char* srcfile; /* file to read (video stream) from */ 68 | char* dstfile; /* file to save (video stream) to */ 69 | 70 | char h200_ftr[2048]; /* text to add to HTTP 200 response */ 71 | flag_t tcp_nodelay; /* apply TCP_NODELAY option to 72 | newly-accepted sockets */ 73 | char cnt_type[80]; /* custom HTTP 200 content type */ 74 | }; 75 | 76 | 77 | #ifdef UDPXREC_MOD 78 | /* udpxrec options 79 | */ 80 | struct udpxrec_opt { 81 | flag_t is_verbose; /* verbose output on/off */ 82 | int nice_incr; /* value to increment nice by */ 83 | 84 | time_t bg_time; /* time to start recording */ 85 | time_t end_time; /* time to end recording */ 86 | int64_t max_fsize; /* max size of dest file (in bytes) */ 87 | ssize_t bufsize; /* size of receiving socket buffer */ 88 | int rbuf_msgs; /* max number of messages to save 89 | in buffer (-1 = as many as would fit) */ 90 | 91 | /* address of the multicast interface */ 92 | char mcast_addr[ IPADDR_STR_SIZE ]; 93 | char rec_channel[ IPADDR_STR_SIZE ]; 94 | int rec_port; 95 | int waitupd_sec; /* update every N seconds while waiting 96 | to start recording */ 97 | 98 | time_t rcv_tmout; /* receive (mcast) socket timeout */ 99 | time_t sr_tmout, /* server READ/RCV timeout (sec) */ 100 | sw_tmout; /* server WRITE/SND timeout (sec) */ 101 | 102 | flag_t nosync_sbuf, /* do not alter source-socket's buffer size */ 103 | nosync_dbuf; /* do not alter dest-socket's buffer size */ 104 | 105 | 106 | char* pidfile; /* file to store app's PID */ 107 | char* dstfile; /* file to save (video stream) to */ 108 | }; 109 | #endif /* UDPXREC_MOD */ 110 | 111 | #ifdef __cplusplus 112 | extern "C" { 113 | #endif 114 | 115 | /* populate udpxy options with default/initial values 116 | */ 117 | int 118 | init_uopt( struct udpxy_opt* uo ); 119 | 120 | 121 | /* release udpxy resources allocated for udpxy options 122 | */ 123 | void 124 | free_uopt( struct udpxy_opt* uo ); 125 | 126 | 127 | #ifdef UDPXREC_MOD 128 | /* populate udpxrec options with default/initial values 129 | */ 130 | int 131 | init_recopt( struct udpxrec_opt* ro ); 132 | 133 | 134 | /* release resources allocated for udpxy options 135 | */ 136 | void 137 | free_recopt( struct udpxrec_opt* ro ); 138 | 139 | /* print udpxrec options to stream 140 | */ 141 | void 142 | fprint_recopt( FILE* stream, struct udpxrec_opt* ro ); 143 | 144 | #endif /* UDPXREC_MOD */ 145 | 146 | /* set verbose output on 147 | */ 148 | void 149 | set_verbose( flag_t* verbose ); 150 | 151 | 152 | #ifdef __cplusplus 153 | } /* extern "C" */ 154 | #endif 155 | 156 | #endif /* UOPT_H_0215082300 */ 157 | 158 | /* __EOF__ */ 159 | 160 | -------------------------------------------------------------------------------- /jni/udpxy/Makefile: -------------------------------------------------------------------------------- 1 | # @(#) GNU Makefile for udpxy project 2 | # 3 | # Copyright 2008-2012 Pavel V. Cherenkov 4 | # 5 | # This file is part of udpxy. 6 | # 7 | # udpxy is free software: you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation, either version 3 of the License, or 10 | # (at your option) any later version. 11 | # 12 | # udpxy is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | # GNU General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License 18 | # along with udpxy. If not, see . 19 | # 20 | 21 | .SUFFIXES : .o .c .d 22 | 23 | EXEC := udpxy 24 | UDPXREC := udpxrec 25 | 26 | STRIP := /usr/bin/strip 27 | GZIP := /bin/gzip 28 | 29 | MKDEPOPT := -MM 30 | DEBUG_ON := -g 31 | 32 | ALL_CFLAGS = -W -Wall -Werror --pedantic $(CFLAGS) 33 | 34 | SYSTEM=$(shell uname 2>/dev/null) 35 | ifneq (,$(filter $(SYSTEM),FreeBSD)) 36 | MAKE := gmake 37 | GZIP := /usr/bin/gzip 38 | endif 39 | ifneq (,$(filter $(SYSTEM),Darwin)) 40 | GZIP := /usr/bin/gzip 41 | endif 42 | 43 | BUILDFILE = BUILD 44 | BUILDNO := `cat $(BUILDFILE)` 45 | 46 | BTYPEFILE = BLDTYPE 47 | BTYPE := `cat $(BTYPEFILE) | tr -d '"'` 48 | 49 | VERSIONFILE = VERSION 50 | VERSION := `cat $(VERSIONFILE) | tr -d '"'` 51 | 52 | PATCHFILE = PATCH 53 | PATCHNO := `cat $(PATCHFILE)` 54 | 55 | CHANGEFILE := CHANGES 56 | READMEFILE := README 57 | 58 | ifndef PREFIX 59 | PREFIX := /usr/local 60 | endif 61 | 62 | INSTALLROOT := $(DESTDIR)$(PREFIX) 63 | 64 | ARCDIR = .. 65 | ARCFILE := $(ARCDIR)/$(EXEC).$(VERSION).$(BUILDNO)-$(PATCHNO)-$(BTYPE).tar.gz 66 | 67 | DEBUG_OPT := $(COPT) $(DEBUG_ON) -DTRACE_MODULE 68 | PROD_OPT := $(COPT) -DNDEBUG -DTRACE_MODULE 69 | LEAN_OPT := $(COPT) -DNDEBUG 70 | 71 | UTILDIR := util 72 | 73 | SLOOP_FILES := sloop_p.c sloop_s.c 74 | 75 | UDPXY_MAN1 := udpxy.1 76 | UDPXREC_MAN1 := udpxrec.1 77 | 78 | UDPXY_MANPAGE_EN := doc/en/$(UDPXY_MAN1) 79 | # UDPXY_MANPAGE_RU := doc/ru/$(UDPXY_MAN1) 80 | 81 | UDPXREC_MANPAGE_EN := doc/en/$(UDPXREC_MAN1) 82 | # UDPXYREC_MANPAGE_RU := doc/ru/$(UDPXREC_MAN1) 83 | 84 | MANPAGE_DIR := $(DESTDIR)/usr/share/man/man1 85 | 86 | DOCDIR := doc 87 | DOCFILES := *.txt $(DOCDIR) 88 | 89 | SRC := udpxy.c sloop.c rparse.c util.c prbuf.c ifaddr.c ctx.c mkpg.c \ 90 | rtp.c uopt.c dpkt.c netop.c extrn.c main.c 91 | 92 | ifneq (yes,$(NO_UDPXREC)) 93 | SRC += udpxrec.c 94 | CDEFS += -DUDPXREC_MOD 95 | endif 96 | 97 | OBJ := ${SRC:.c=.o} 98 | 99 | DEPFILE := $(EXEC).dep 100 | CORES := core.* core 101 | 102 | .PHONY: clean distclean distro install uninstall all \ 103 | debug ldebug rdebug lean verify touch incbuild 104 | 105 | .c.o : 106 | $(CC) $(ALL_CFLAGS) $(CPPFLAGS) $(CDEFS) $(COPT) -c $< -o $@ 107 | 108 | release: 109 | @echo -e "\nMaking a [release] version (use 'debug' target as an alternative)\n" 110 | @$(MAKE) all "COPT=${PROD_OPT}" "CFLAGS=${CFLAGS}" "CDEFS=${CDEFS}" "CPPFLAGS=${CPPFLAGS}" 111 | 112 | debug: 113 | @echo -e "\nMaking a [debug] version (use 'release' target as an alternative)\n" 114 | @$(MAKE) all "COPT=${DEBUG_OPT}" "CFLAGS=${CFLAGS}" "CDEFS=${CDEFS}" "CPPFLAGS=${CPPFLAGS}" 115 | 116 | lean: 117 | @echo -e "\nMaking a [lean] version (minimal size)\n" 118 | @$(MAKE) all "COPT=${LEAN_OPT}" "CFLAGS=${CFLAGS}" "CDEFS=${CDEFS}" "CPPFLAGS=${CPPFLAGS}" 119 | 120 | ldebug: 121 | @echo -e "\nMaking a [lean] version with debug info\n" 122 | @$(MAKE) all "COPT=${LEAN_OPT} ${DEBUG_ON}" "CFLAGS=${CFLAGS}" "CDEFS=${CDEFS}" "CPPFLAGS=${CPPFLAGS}" 123 | 124 | rdebug: 125 | @echo -e "\nMaking a [release] version with debug info\n" 126 | @$(MAKE) all "COPT=${PROD_OPT} ${DEBUG_ON}" "CDEFS=${CDEFS}" "CPPFLAGS=${CPPFLAGS}" 127 | 128 | verify: 129 | @echo -e "\nVerifying all build targets\n" 130 | @$(MAKE) clean 131 | @$(MAKE) release 132 | @$(MAKE) clean 133 | @$(MAKE) lean 134 | @$(MAKE) clean 135 | @$(MAKE) ldebug 136 | @$(MAKE) clean 137 | @$(MAKE) rdebug 138 | @$(MAKE) clean 139 | @$(MAKE) debug 140 | @$(MAKE) clean 141 | 142 | mk_deps := $(CC) $(CFLAGS) $(CDEFS) $(MKDEPOPT) $(SRC) 143 | 144 | all: $(DEPFILE) $(EXEC) 145 | 146 | $(DEPFILE): $(SRC) 147 | $(mk_deps) > $(DEPFILE) 148 | 149 | $(EXEC) : $(DEPFILE) $(OBJ) 150 | @rm -f $(EXEC) 151 | $(CC) $(CFLAGS) $(LDFLAGS) $(COPT) -o $(EXEC) $(OBJ) 152 | @ls -l $(EXEC) 153 | ifneq (yes, $(NO_UDPXREC)) 154 | @rm -f $(UDPXREC) 155 | ln -s $(EXEC) $(UDPXREC) 156 | endif 157 | 158 | clean: 159 | rm -f $(CORES) $(DEPFILE) $(OBJ) $(EXEC) $(UDPXREC) 160 | 161 | distclean: clean 162 | 163 | incbuild: 164 | @expr `cat $(BUILDFILE)` + 1 > $(BUILDFILE) 165 | @echo "Set build number to: `cat $(BUILDFILE)`" 166 | @$(MAKE) touch 167 | 168 | DISTRO_DIR := udpxy-$(VERSION).$(BUILDNO)-$(PATCHNO) 169 | DISTRO_FILES := $(SRC) $(SLOOP_FILES) *.h Makefile $(DOCFILES) $(BUILDFILE) $(BTYPEFILE) \ 170 | $(VERSIONFILE) $(CHANGEFILE) $(READMEFILE) $(PATCHFILE) 171 | 172 | distro: dist 173 | 174 | dist: 175 | @rm -fr $(DISTRO_DIR) 176 | @mkdir $(DISTRO_DIR) 177 | @mkdir $(DISTRO_DIR)/$(UTILDIR) 178 | cp -R $(DISTRO_FILES) $(DISTRO_DIR) 179 | tar -cvzf $(ARCFILE) $(DISTRO_DIR) 180 | @ls -l $(ARCFILE) 181 | @rm -fr $(DISTRO_DIR) 182 | 183 | install: $(EXEC) 184 | @mkdir -p -m 755 $(INSTALLROOT)/bin 185 | @cp $(EXEC) $(INSTALLROOT)/bin 186 | @ls -l $(INSTALLROOT)/bin/$(EXEC) 187 | @mkdir -p -m 755 $(MANPAGE_DIR) 188 | @$(GZIP) -c $(UDPXY_MANPAGE_EN) > $(MANPAGE_DIR)/$(UDPXY_MAN1).gz 189 | ifneq (yes, $(NO_UDPXREC)) 190 | @cp $(UDPXREC) $(INSTALLROOT)/bin/$(UDPXREC) 191 | @ls -l $(INSTALLROOT)/bin/$(UDPXREC) 192 | @$(GZIP) -c $(UDPXREC_MANPAGE_EN) > $(MANPAGE_DIR)/$(UDPXREC_MAN1).gz 193 | endif 194 | @echo "Installation of udpxy is complete" 195 | 196 | install-strip: install 197 | $(STRIP) $(INSTALLROOT)/bin/$(EXEC) 198 | @ls -l $(INSTALLROOT)/bin/$(EXEC) 199 | @echo "udpxy executable stripped" 200 | 201 | uninstall: 202 | @rm -f $(INSTALLROOT)/bin/$(EXEC) $(INSTALLROOT)/bin/$(UDPXREC) 203 | @rm -f $(MANPAGE_DIR)/$(UDPXY_MAN1).gz $(MANPAGE_DIR)/$(UDPXREC_MAN1).gz 204 | @echo "udpxy successfully uninstalled" 205 | 206 | ifneq ($(MAKECMDGOALS), clean) 207 | -include $(DEPFILE) 208 | endif 209 | 210 | # __EOF__ 211 | 212 | -------------------------------------------------------------------------------- /jni/udpxy/test/upxc.c: -------------------------------------------------------------------------------- 1 | /* @(#) udpxy multiple file-format converter 2 | * 3 | * Copyright 2008-2011 Pavel V. Cherenkov (pcherenkov@gmail.com) 4 | * 5 | * This file is part of udpxy. 6 | * 7 | * udpxy is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * udpxy is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with udpxy. If not, see . 19 | */ 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #include "udpxy.h" 31 | #include "dpkt.h" 32 | #include "util.h" 33 | #include "mtrace.h" 34 | 35 | #define MAX_REC_SIZE 1501 36 | 37 | static const char appname[] = "upxc"; 38 | 39 | /* convert source file into destination format 40 | */ 41 | static int 42 | convert2( const char* srcfile, const char* dstfile, 43 | upxfmt_t dfmt, FILE* log ) 44 | { 45 | char data[ MAX_REC_SIZE ]; 46 | ssize_t nrd = -1, nwr = -1; 47 | 48 | int sfd = -1, dfd = -1; 49 | upxfmt_t sfmt = DT_UNKNOWN; 50 | 51 | double rrec = 0, wrec = 0, 52 | rtotal = 0, wtotal = 0; 53 | 54 | assert( srcfile && log ); 55 | assert( ETHERNET_MTU < MAX_REC_SIZE ); 56 | 57 | sfd = open( srcfile, O_RDONLY ); 58 | if( -1 == sfd ) { 59 | mperror( log, errno, "srcfile - open" ); 60 | return -1; 61 | } 62 | 63 | if( dstfile ) { 64 | dfd = creat( dstfile, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH ); 65 | if( -1 == dfd ) { 66 | mperror( log, errno, "dstfile - open" ); 67 | return -1; 68 | } 69 | } 70 | 71 | if( dfmt == sfmt ) { 72 | (void) tmfprintf( log, "%s: Same format for source and destination: " 73 | "writing will be skipped\n", appname); 74 | nwr = 0; /* set to 0 not to confuse with an error condition */ 75 | } 76 | 77 | do { 78 | nrd = read_frecord( sfd, data, ETHERNET_MTU, &sfmt, log ); 79 | /* 80 | TRACE( (void)tmfprintf( log, "%s:R nrd=[%ld], nwr=[%ld]\n", 81 | __func__, (long)nrd, (long)nwr) ); 82 | */ 83 | if( nrd <= 0 ) break; 84 | 85 | ++rrec; 86 | rtotal += (double)nrd; 87 | 88 | TRACE( (void) tmfprintf( log, "Read record [%ld] of [%ld] bytes\n", 89 | (long)rrec, (long)nrd ) ); 90 | 91 | if( (dfd <= 0) || (sfmt == dfmt) ) 92 | continue; 93 | 94 | nwr = write_frecord( dfd, data, nrd, sfmt, dfmt, log ); 95 | if( nwr <= 0 ) break; 96 | 97 | ++wrec; 98 | wtotal += (double)nwr; 99 | 100 | TRACE( (void) tmfprintf( log, "Wrote record [%ld] of [%ld] bytes\n", 101 | (long)wrec, (long)nwr ) ); 102 | } while( 1 ); 103 | 104 | if( dfd > 0 ) (void) close( dfd ); 105 | if( sfd > 0 ) (void) close( sfd ); 106 | 107 | (void) tmfprintf( log, "Read records=[%.f], bytes=[%.f], " 108 | "wrote records=[%.f], bytes=[%.f]\n", 109 | rrec, rtotal, wrec, wtotal ); 110 | 111 | if( (nrd < 0) || (nwr < 0)) { 112 | TRACE( (void)tmfprintf( log, "%s: nrd=[%ld], nwr=[%ld]\n", 113 | __func__, (long)nrd, (long)nwr) ); 114 | return -1; 115 | } 116 | 117 | return 0; 118 | } 119 | 120 | 121 | static void 122 | usage() 123 | { 124 | (void) tmfprintf( stderr, "Usage: %s -[dtu] -i srcfile " 125 | "-o dstfile\n", appname ); 126 | return; 127 | } 128 | 129 | 130 | int 131 | main( int argc, char* const argv[] ) 132 | { 133 | static const char* clopt = "i:o:dtr"; 134 | 135 | char srcfile[ MAXPATHLEN ] = { '\0' }; 136 | char dstfile[ MAXPATHLEN ] = { '\0' }; 137 | 138 | upxfmt_t dst_fmt = DT_UNKNOWN; 139 | 140 | int ch, rc = 0, debug = 0; 141 | FILE* flog = NULL; 142 | 143 | while( -1 != (ch = getopt(argc, argv, clopt)) ) { 144 | switch( ch ) { 145 | case 'i': 146 | (void)strncpy( srcfile, optarg, sizeof(srcfile) - 1 ); 147 | break; 148 | 149 | case 'o': 150 | (void)strncpy( dstfile, optarg, sizeof(dstfile) - 1 ); 151 | break; 152 | 153 | case 't': 154 | dst_fmt = DT_TS; 155 | break; 156 | 157 | case 'u': 158 | dst_fmt = DT_UDS; 159 | break; 160 | 161 | case 'd': 162 | debug = 1; 163 | break; 164 | 165 | default: 166 | (void) tmfprintf( stderr, "%s: Unrecognized option [%c]\n", 167 | appname, (char)ch ); 168 | usage(); 169 | return ERR_PARAM; 170 | } /* switch */ 171 | } /* getopt loop */ 172 | 173 | if( !srcfile[0] ) { 174 | (void) tmfprintf( stderr, "%s: Missing source-file parameter\n", 175 | appname ); 176 | usage(); 177 | return ERR_PARAM; 178 | } 179 | else { 180 | if( 0 != (rc = access( srcfile, R_OK)) ) { 181 | perror( "srcfile - access" ); 182 | return ERR_PARAM; 183 | } 184 | } 185 | 186 | flog = debug ? stderr : fopen( "/dev/null", "a" ); 187 | if( NULL == flog ) { 188 | perror( "fopen" ); 189 | return ERR_INTERNAL; 190 | } 191 | 192 | TRACE( (void)tmfprintf( flog, "%s: destination format = [%s]\n", 193 | appname, fmt2str(dst_fmt)) ); 194 | if( DT_UNKNOWN == dst_fmt ) { 195 | (void)tmfprintf( flog, "%s: destination format must be specified\n", 196 | appname ); 197 | return ERR_PARAM; 198 | } 199 | 200 | rc = convert2( srcfile, dstfile, dst_fmt, flog ); 201 | 202 | if( (NULL != flog) && (stderr != flog) ) 203 | (void) fclose(flog); 204 | 205 | return (rc ? ERR_INTERNAL : 0); 206 | } 207 | 208 | 209 | /* __EOF__ */ 210 | 211 | -------------------------------------------------------------------------------- /jni/udpxy/util.h: -------------------------------------------------------------------------------- 1 | /* @(#) interface to utility functions for udpxy 2 | * 3 | * Copyright 2008-2011 Pavel V. Cherenkov (pcherenkov@gmail.com) 4 | * 5 | * This file is part of udpxy. 6 | * 7 | * udpxy is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * udpxy is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with udpxy. If not, see . 19 | */ 20 | 21 | #ifndef UTILH_UDPXY_200712181853 22 | #define UTILH_UDPXY_200712181853 23 | 24 | #include 25 | #include 26 | 27 | struct timeval; 28 | 29 | #ifdef __cplusplus 30 | extern "C" { 31 | #endif 32 | 33 | /* write buffer to a file 34 | */ 35 | ssize_t 36 | save_buffer( const void* buf, size_t len, const char* filename ); 37 | 38 | /* read text file into a buffer 39 | * 40 | */ 41 | ssize_t 42 | txtf_read (const char* fpath, char* dst, size_t maxlen, FILE* log); 43 | 44 | /* start process as a daemon 45 | * 46 | */ 47 | #define DZ_STDIO_OPEN 1 /* do not close STDIN, STDOUT, STDERR */ 48 | int 49 | daemonize(int options, FILE* log); 50 | 51 | 52 | /* multiplex error output to custom log 53 | * and syslog 54 | */ 55 | void 56 | mperror( FILE* fp, int err, const char* format, ... ); 57 | 58 | 59 | /* create and lock file with process's ID 60 | */ 61 | int 62 | make_pidfile( const char* fpath, pid_t pid, FILE* log ); 63 | 64 | 65 | /* write path to application's pidfile into the the buffer 66 | * (fail of destination directory is not writable) 67 | */ 68 | int 69 | set_pidfile( const char* appname, int port, char* buf, size_t len ); 70 | 71 | /* write buffer to designated socket/file 72 | * return number of bytes read/written or one of the error 73 | * codes below 74 | */ 75 | #define IO_ERR -1 /* generic error */ 76 | #define IO_BLK -2 /* operation timed out or would block */ 77 | ssize_t 78 | write_buf( int fd, const char* data, const ssize_t len, FILE* log ); 79 | 80 | /* read data chunk of designated size into buffer 81 | */ 82 | ssize_t 83 | read_buf( int fd, char* buf, const ssize_t len, FILE* log ); 84 | 85 | /* output hex dump of a memory fragment 86 | */ 87 | void 88 | hex_dump( const char* msg, const char* data, size_t len, FILE* log ); 89 | 90 | /* check for expected size, complain if not matched 91 | */ 92 | int 93 | sizecheck( const char* msg, ssize_t expct, ssize_t len, 94 | FILE* log, const char* func ); 95 | 96 | /* check for a potential buffer overrun by 97 | * evaluating target buffer and the portion 98 | * of that buffer to be accessed 99 | */ 100 | int 101 | buf_overrun( const char* buf, size_t buflen, 102 | size_t offset, size_t dlen, 103 | FILE* log ); 104 | 105 | 106 | /* write timestamp-prepended formatted message to file 107 | */ 108 | int 109 | tmfprintf( FILE* stream, const char* format, ... ); 110 | 111 | 112 | /* write timestamp-prepended message to file 113 | */ 114 | int 115 | tmfputs( const char* s, FILE* stream ); 116 | 117 | 118 | /* print out command-line 119 | */ 120 | void 121 | printcmdln( FILE* stream, const char* msg, 122 | int argc, char* const argv[] ); 123 | 124 | 125 | /* convert timespec to time_t 126 | * where 127 | * timespec format: [+|-]dd:hh24:mi:ss 128 | * 129 | * @return 0 if success, n>0 if parse error at position n, 130 | * -1 otherwise 131 | */ 132 | int 133 | a2time( const char* str, time_t* t, time_t from ); 134 | 135 | 136 | /* convert ASCII size spec (positive) into numeric value 137 | * size spec format: 138 | * num[modifier], where num is an ASCII representation of 139 | * any positive integer and 140 | * modifier ::= [Kb|K|Mb|M|Gb|G] 141 | */ 142 | int 143 | a2size( const char* str, ssize_t* pval ); 144 | 145 | int 146 | a2int64( const char* str, int64_t* pval ); 147 | 148 | /* returns asctime w/o CR character at the end 149 | */ 150 | struct tm; 151 | 152 | const char* 153 | Zasctime( const struct tm* tm ); 154 | 155 | 156 | /* adjust nice value if needed 157 | */ 158 | int 159 | set_nice( int val, FILE* log ); 160 | 161 | 162 | /* check and report a deviation in values: n_was and n_is are not supposed 163 | * to differ more than by delta 164 | */ 165 | void 166 | check_fragments( const char* action, ssize_t total, ssize_t n_was, ssize_t n_is, 167 | ssize_t delta, FILE* log ); 168 | 169 | /* create timestamp string in YYYY-mm-dd HH24:MI:SS.MSEC from struct timeval 170 | */ 171 | static const int32_t TVSTAMP_GMT = 1; 172 | 173 | int 174 | mk_tvstamp( const struct timeval* tv, char* buf, size_t* len, 175 | int32_t flags ); 176 | 177 | 178 | /* retrieve UNIX time value from given environment 179 | * variable, otherwise return default */ 180 | time_t 181 | get_timeval( const char* envar, const time_t deflt ); 182 | 183 | 184 | /* retrieve flag value as 1 = true, 0 = false 185 | * from an environment variable set in the form 186 | * of 0|1|'true'|'false'|'yes'|'no' 187 | */ 188 | int 189 | get_flagval( const char* envar, const int deflt ); 190 | 191 | /* retrieve LONG value from given environment 192 | * variable, otherwise return default */ 193 | ssize_t 194 | get_sizeval( const char* envar, const ssize_t deflt ); 195 | 196 | 197 | /* retrieve/reset string representation of pid, 198 | */ 199 | const char* 200 | get_pidstr( int reset, const char* pfx ); 201 | 202 | /* retrieve system info string 203 | */ 204 | const char* 205 | get_sysinfo (int* perr); 206 | 207 | /* return 1 if err is one of the errors signifying possibility of a block, 0 otherwise. 208 | */ 209 | int 210 | would_block(int err); 211 | 212 | /* return 1 if this kind of error should not be captures in syslog, 0 otherwise. 213 | */ 214 | int 215 | no_fault(int err); 216 | 217 | /* populate info string with application's credentials (version, patch, etc.) 218 | */ 219 | void 220 | mk_app_info(const char *appname, char *info, size_t infolen); 221 | 222 | #ifdef __cplusplus 223 | } 224 | #endif 225 | 226 | #endif /* UTILH_UDPXY_200712181853 */ 227 | 228 | /* __EOF__ */ 229 | 230 | -------------------------------------------------------------------------------- /jni/udpxy/statpg.h: -------------------------------------------------------------------------------- 1 | /* @(#) HTML-page templates/generation for udpxy status page 2 | * 3 | * Copyright 2008-2011 Pavel V. Cherenkov (pcherenkov@gmail.com) 4 | * 5 | * This file is part of udpxy. 6 | * 7 | * udpxy is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * udpxy is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with udpxy. If not, see . 19 | */ 20 | 21 | #ifndef STATPG_H_0110081157_ 22 | #define STATPG_H_0110081157_ 23 | 24 | #ifdef __cplusplus 25 | extern "C" { 26 | #endif 27 | 28 | /* NB: strings are exposed in the header to be included 29 | * by unit tests, yet made static to confine to a single unit */ 30 | 31 | static const char HTML_PAGE_HEADER[] = 32 | "HTTP/1.0 200 OK\n" 33 | "Content-type: text/html\n\n"; 34 | 35 | static const char* STAT_PAGE_BASE[] = { 36 | "\n" 37 | "\n" 38 | "\n" 98 | "\n" 99 | }; 100 | static const size_t LEN_STAT_PAGE_BASE = 3; 101 | 102 | static const char STAT_PAGE_FMT1[] = 103 | "\n" 104 | "
\n" 105 | "

udpxy status:

\n" 106 | "
\n" 107 | "\n" 108 | "\n" 109 | " \n" 110 | " \n" 111 | " \n" 112 | " \n" 113 | "\n" 114 | "\n" 115 | " \n" 116 | " \n" 117 | " \n" 118 | " \n" 119 | "\n" 120 | "
Server Process IDAccepting clients onMulticast addressActive clients
%d%s:%d%s%d
\n" 121 | "
\n" 122 | "\n" 123 | "
\n" 124 | "\n" 125 | "%s" /* Active clients table goes here */ 126 | "%s" /* Usage guide table */ 127 | "
\n" 128 | "
udpxy v. %s (Build %d) %s - [%s]
%s
\n" /* footer */ 129 | "
\n" 130 | "\n" 131 | "\n"; 132 | 133 | 134 | static const char RST_PAGE_FMT1[] = 135 | "\n" 136 | "
\n" 137 | "

udpxy is RESTARTING - This page will refresh automatically

\n" 138 | "
\n" 139 | "\n" 140 | "\n" 141 | " \n" 142 | " \n" 143 | " \n" 144 | " \n" 145 | "\n" 146 | "\n" 147 | " \n" 148 | " \n" 149 | " \n" 150 | " \n" 151 | "\n" 152 | "
Server Process IDAccepting clients onMulticast addressActive clients
%d%s:%d%s%d
\n" 153 | "\n" 154 | "%s" /* Active clients (nothing in restart page) */ 155 | "%s" /* Usage guide table */ 156 | "
\n" 157 | "
udpxy v. %s (Build %d) %s - [%s]
%s
\n" /* footer */ 158 | "
\n" 159 | "\n" 160 | "\n"; 161 | 162 | static const char* ACLIENT_TABLE[] = { 163 | "

Active clients:

\n" 164 | "\n" 165 | "\n", 166 | "
Process IDSourceDestinationThroughput
\n" }; 167 | 168 | 169 | static const char* ACLIENT_REC_FMT[] = { 170 | "%d%s:%d%s:%d%s%s\n", 171 | "%d%s:%d%s:%d%s%s\n" }; 172 | 173 | 174 | static const char REDIRECT_SCRIPT_FMT[] = 175 | ""; 180 | 181 | static const char REQUEST_GUIDE[] = 182 | "

Available HTTP requests:

\n" 183 | "\n" 184 | "\n" 185 | "\n" 186 | "" 187 | "\n" 188 | "\n" 189 | "
Request templateFunction
http://address:port/udp/mcast_addr:mport/Relay multicast traffic from mcast_addr:mport
http://address:port/status/Display udpxy status
http://address:port/restart/Restart udpxy
\n"; 190 | 191 | 192 | #ifdef __cplusplus 193 | } 194 | #endif 195 | 196 | #endif /* STATPG_H_0110081157_ */ 197 | 198 | /* __EOF__ */ 199 | 200 | -------------------------------------------------------------------------------- /jni/udpxy/test/fbsd/ifaddr.c: -------------------------------------------------------------------------------- 1 | /* @(#) interface/address conversion */ 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | #include 16 | 17 | #include "osdef.h" 18 | #include "ifaddr.h" 19 | 20 | /* DEBUG */ 21 | #include 22 | /* DEBUG */ 23 | 24 | 25 | /* check if ifr contains info on the desired ifname 26 | */ 27 | static int 28 | chkifr( const struct ifreq* ifr, const char* ifname, 29 | const size_t addrlen, size_t* offset ) 30 | { 31 | size_t sa_len = 0; 32 | 33 | assert(ifr && ifname && offset); 34 | 35 | #ifdef NO_SOCKADDR_SA_LEN 36 | switch( ifr->ifr_addr.sa_family ) 37 | { 38 | #ifndef NO_INET6_SUPPORT 39 | case AF_INET6: sa_len = sizeof(struct sockaddr_in6); break; 40 | #endif 41 | case AF_INET: sa_len = sizeof(struct sockaddr); break; 42 | default: sa_len = 0; break; 43 | } 44 | #else 45 | sa_len = ifr->ifr_addr.sa_len; 46 | #endif 47 | 48 | if( sa_len > 0 ) { 49 | if ( (ifr->ifr_addr.sa_family == AF_INET) && 50 | (0 == strncmp(ifname, ifr->ifr_name, sizeof(struct ifreq))) && 51 | (addrlen >= sa_len) ) { 52 | *offset = sa_len; 53 | return 0; 54 | } 55 | } 56 | 57 | #if defined(__linux) 58 | *offset = sizeof(*ifr); 59 | #else 60 | *offset = (sa_len + sizeof( ifr->ifr_name )); 61 | /* the above is per R. Stevens' book and not working on 64-bit Linux */ 62 | #endif 63 | 64 | return -1; 65 | } 66 | 67 | 68 | 69 | /* retrieve IPv4 address of the given network interface 70 | */ 71 | int 72 | if2addr( const char* ifname, 73 | struct sockaddr *addr, size_t addrlen ) 74 | { 75 | int rc, sockfd; 76 | char *buf, *rec; 77 | size_t buflen, offset; 78 | int last_len; 79 | struct ifconf ifc; 80 | struct ifreq ifr; 81 | 82 | int maxi = 50; 83 | FILE *fp_ifc = NULL; 84 | size_t nsz = 0; 85 | 86 | static size_t IFC_TABLE_SIZE; 87 | 88 | static const size_t IFC_ENTRIES = 32; 89 | static const size_t MAX_IFCBUF_SIZE = (1024 * 256); 90 | 91 | IFC_TABLE_SIZE = sizeof(struct ifreq) * IFC_ENTRIES; 92 | 93 | assert( ifname && addr && addrlen ); 94 | rc = 0; 95 | 96 | /* acquire the list of network interfaces */ 97 | 98 | sockfd = socket( AF_INET, SOCK_DGRAM, 0 ); 99 | if( -1 == sockfd ) return -1; 100 | 101 | buf = NULL; buflen = IFC_TABLE_SIZE; last_len = 0; 102 | for( ; buflen < MAX_IFCBUF_SIZE; buflen += IFC_TABLE_SIZE ) { 103 | if( NULL == (buf = malloc( buflen )) ) { 104 | rc = -1; 105 | break; 106 | } 107 | 108 | ifc.ifc_len = buflen; 109 | ifc.ifc_buf = buf; 110 | if( ioctl( sockfd, SIOCGIFCONF, &ifc ) < 0 ) { 111 | if( (EINVAL != errno) || (last_len != 0) ) { 112 | rc = errno; 113 | break; 114 | } 115 | } 116 | else { 117 | if( ifc.ifc_len == last_len ) 118 | break; 119 | else 120 | last_len = ifc.ifc_len; 121 | } 122 | 123 | free( buf ); 124 | buf = NULL; 125 | } /* for */ 126 | 127 | (void) close( sockfd ); 128 | if( buflen > MAX_IFCBUF_SIZE ) rc = -1; 129 | 130 | if( 0 != rc ) { 131 | if( NULL != buf ) free( buf ); 132 | return rc; 133 | } 134 | 135 | assert( ifc.ifc_buf ); 136 | /* DEBUG */ 137 | fp_ifc = fopen("ifcbuf.dat","w"); 138 | if (NULL==fp_ifc) { 139 | perror("fopen ifcbuf"); 140 | exit(1); 141 | } 142 | nsz = fwrite(ifc.ifc_buf, ifc.ifc_len, 1, fp_ifc ); 143 | (void) fprintf(stderr, "%ld record(s) wtitten to ifcbuf.dat\n", 144 | (long)nsz ); 145 | fclose(fp_ifc); 146 | /* DEBUG */ 147 | 148 | /* look for ifname in the list */ 149 | 150 | for( rec = ifc.ifc_buf; rec < (ifc.ifc_buf + ifc.ifc_len); ) { 151 | (void) memcpy( &ifr, rec, sizeof(struct ifreq) ); 152 | 153 | (void) fprintf(stderr, "DEBUG1: rec=%p, max=%p\n", 154 | (void*)rec, (void*)(ifc.ifc_buf + ifc.ifc_len) ); 155 | if( --maxi <= 0 ) break; 156 | 157 | offset = 0; 158 | rc = chkifr( &ifr, ifname, addrlen, &offset ); 159 | if ( 0 == rc ) { 160 | (void) memcpy( addr, &(ifr.ifr_addr), offset ); 161 | break; 162 | } 163 | 164 | if( 0 == offset ) break; 165 | rec += offset; 166 | } /* for */ 167 | 168 | if( rec >= (buf + ifc.ifc_len) ) { 169 | rc = -1; 170 | } 171 | 172 | free( buf ); 173 | return rc; 174 | } 175 | 176 | 177 | /* convert input parameter into an IPv4-address string 178 | */ 179 | int 180 | get_ipv4_address( const char* s, char* buf, size_t len ) 181 | { 182 | struct sockaddr_in saddr; 183 | int rc = 0; 184 | 185 | assert( s && buf && len ); 186 | 187 | if( 1 == inet_aton(s, &(saddr.sin_addr)) ) { 188 | (void) strncpy( buf, s, len ); 189 | } 190 | else { 191 | rc = if2addr( s, (struct sockaddr*)&saddr, sizeof(saddr) ); 192 | if( 0 != rc ) return rc; 193 | 194 | (void) strncpy( buf, inet_ntoa(saddr.sin_addr), len ); 195 | } 196 | 197 | buf[ len - 1 ] = 0; 198 | return rc; 199 | } 200 | 201 | 202 | /* split input string into IP address and port 203 | */ 204 | int 205 | get_addrport( const char* s, char* addr, size_t len, int* port ) 206 | { 207 | struct sockaddr_in saddr; 208 | size_t i = 0; 209 | int iport = 0; 210 | 211 | static const int ERR_NOPORT = -1; 212 | static const int ERR_BADADDR = -2; 213 | static const int ERR_BADPORT = -3; 214 | static const int ERR_OVERFLOW = -4; 215 | 216 | assert( s && addr && len && port ); 217 | 218 | for( i = 0; (i < len) && s[i] && (':' != s[i]); ++i ) 219 | addr[ i ] = s[ i ]; 220 | if( i >= len ) 221 | return ERR_OVERFLOW; 222 | else 223 | addr[i] = '\0'; 224 | 225 | /* IP address is not followed by port */ 226 | if( ':' != s[ i ] ) return ERR_NOPORT; 227 | 228 | if( 1 != inet_aton( addr, &(saddr.sin_addr)) ) 229 | return ERR_BADADDR; 230 | 231 | ++i; 232 | if( i >= len || !s[i] ) return ERR_NOPORT; 233 | 234 | errno = 0; 235 | iport = atoi( s + i ); 236 | if( errno || (iport <= 0) || (iport > (int)USHRT_MAX) ) 237 | return ERR_BADPORT; 238 | 239 | *port = iport; 240 | return 0; 241 | } 242 | 243 | 244 | /* __EOF__ */ 245 | 246 | -------------------------------------------------------------------------------- /jni/udpxy/ifaddr.c: -------------------------------------------------------------------------------- 1 | /* @(#) interface/address conversion 2 | * 3 | * Copyright 2008-2011 Pavel V. Cherenkov (pcherenkov@gmail.com) 4 | * 5 | * This file is part of udpxy. 6 | * 7 | * udpxy is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * udpxy is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with udpxy. If not, see . 19 | */ 20 | 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | #include 34 | #include 35 | 36 | #include "osdef.h" 37 | #include "ifaddr.h" 38 | 39 | 40 | /* check if ifr contains info on the desired ifname 41 | */ 42 | static int 43 | chkifr( const struct ifreq* ifr, const char* ifname, 44 | const size_t addrlen, size_t* offset ) 45 | { 46 | size_t sa_len = 0; 47 | 48 | assert(ifr && ifname && offset); 49 | 50 | #ifdef NO_SOCKADDR_SA_LEN 51 | switch( ifr->ifr_addr.sa_family ) 52 | { 53 | #ifndef NO_INET6_SUPPORT 54 | case AF_INET6: sa_len = sizeof(struct sockaddr_in6); break; 55 | #endif 56 | case AF_INET: sa_len = sizeof(struct sockaddr); break; 57 | default: sa_len = 0; break; 58 | } 59 | #else 60 | sa_len = ifr->ifr_addr.sa_len; 61 | #endif 62 | 63 | if( sa_len > 0 ) { 64 | if ( (ifr->ifr_addr.sa_family == AF_INET) && 65 | (0 == strncmp(ifname, ifr->ifr_name, sizeof(struct ifreq))) && 66 | (addrlen >= sa_len) ) { 67 | *offset = sa_len; 68 | return 0; 69 | } 70 | } 71 | 72 | #if defined(__linux) 73 | *offset = sizeof(*ifr); 74 | #else 75 | *offset = (sa_len + sizeof( ifr->ifr_name )); 76 | /* the above is per R. Stevens' book and not working on 64-bit Linux */ 77 | #endif 78 | 79 | return -1; 80 | } 81 | 82 | 83 | 84 | /* retrieve IPv4 address of the given network interface 85 | */ 86 | int 87 | if2addr( const char* ifname, 88 | struct sockaddr *addr, size_t addrlen ) 89 | { 90 | int rc, sockfd; 91 | char *buf, *rec; 92 | size_t buflen, offset; 93 | int last_len; 94 | struct ifconf ifc; 95 | struct ifreq ifr; 96 | 97 | static size_t IFC_TABLE_SIZE; 98 | 99 | static const size_t IFC_ENTRIES = 32; 100 | static const size_t MAX_IFCBUF_SIZE = (1024 * 256); 101 | 102 | IFC_TABLE_SIZE = sizeof(struct ifreq) * IFC_ENTRIES; 103 | 104 | assert( ifname && addr && addrlen ); 105 | rc = 0; 106 | 107 | /* acquire the list of network interfaces */ 108 | 109 | sockfd = socket( AF_INET, SOCK_DGRAM, 0 ); 110 | if( -1 == sockfd ) return -1; 111 | 112 | buf = NULL; buflen = IFC_TABLE_SIZE; last_len = 0; 113 | for( ; buflen < MAX_IFCBUF_SIZE; buflen += IFC_TABLE_SIZE ) { 114 | if( NULL == (buf = malloc( buflen )) ) { 115 | rc = -1; 116 | break; 117 | } 118 | 119 | ifc.ifc_len = buflen; 120 | ifc.ifc_buf = buf; 121 | if( ioctl( sockfd, SIOCGIFCONF, &ifc ) < 0 ) { 122 | if( (EINVAL != errno) || (last_len != 0) ) { 123 | rc = errno; 124 | break; 125 | } 126 | } 127 | else { 128 | if( ifc.ifc_len == last_len ) 129 | break; 130 | else 131 | last_len = ifc.ifc_len; 132 | } 133 | 134 | free( buf ); 135 | buf = NULL; 136 | } /* for */ 137 | 138 | (void) close( sockfd ); 139 | if( buflen > MAX_IFCBUF_SIZE ) rc = -1; 140 | 141 | if( 0 != rc ) { 142 | if( NULL != buf ) free( buf ); 143 | return rc; 144 | } 145 | 146 | assert( ifc.ifc_buf ); 147 | 148 | /* look for ifname in the list */ 149 | 150 | for( rec = ifc.ifc_buf; rec < (ifc.ifc_buf + ifc.ifc_len); ) { 151 | (void) memcpy( &ifr, rec, sizeof(struct ifreq) ); 152 | 153 | offset = 0; 154 | rc = chkifr( &ifr, ifname, addrlen, &offset ); 155 | if ( 0 == rc ) { 156 | (void) memcpy( addr, &(ifr.ifr_addr), offset ); 157 | break; 158 | } 159 | 160 | if( 0 == offset ) break; 161 | rec += offset; 162 | } /* for */ 163 | 164 | if( rec >= (buf + ifc.ifc_len) ) { 165 | rc = -1; 166 | } 167 | 168 | free( buf ); 169 | return rc; 170 | } 171 | 172 | 173 | /* convert input parameter into an IPv4-address string 174 | */ 175 | int 176 | get_ipv4_address( const char* s, char* buf, size_t len ) 177 | { 178 | struct sockaddr_in saddr; 179 | int rc = 0; 180 | 181 | assert( s && buf && len ); 182 | 183 | if( 1 == inet_aton(s, &(saddr.sin_addr)) ) { 184 | (void) strncpy( buf, s, len ); 185 | } 186 | else { 187 | rc = if2addr( s, (struct sockaddr*)&saddr, sizeof(saddr) ); 188 | if( 0 != rc ) return rc; 189 | 190 | (void) strncpy( buf, inet_ntoa(saddr.sin_addr), len ); 191 | } 192 | 193 | buf[ len - 1 ] = 0; 194 | return rc; 195 | } 196 | 197 | 198 | /* split input string into IP address and port 199 | */ 200 | int 201 | get_addrport( const char* s, char* addr, size_t len, int* port ) 202 | { 203 | struct sockaddr_in saddr; 204 | size_t i = 0; 205 | int iport = 0; 206 | 207 | static const int ERR_NOPORT = -1; 208 | static const int ERR_BADADDR = -2; 209 | static const int ERR_BADPORT = -3; 210 | static const int ERR_OVERFLOW = -4; 211 | 212 | assert( s && addr && len && port ); 213 | 214 | for( i = 0; (i < len) && s[i] && (':' != s[i]); ++i ) 215 | addr[ i ] = s[ i ]; 216 | if( i >= len ) 217 | return ERR_OVERFLOW; 218 | else 219 | addr[i] = '\0'; 220 | 221 | /* IP address is not followed by port */ 222 | if( ':' != s[ i ] ) return ERR_NOPORT; 223 | 224 | if( 1 != inet_aton( addr, &(saddr.sin_addr)) ) 225 | return ERR_BADADDR; 226 | 227 | ++i; 228 | if( i >= len || !s[i] ) return ERR_NOPORT; 229 | 230 | errno = 0; 231 | iport = atoi( s + i ); 232 | if( errno || (iport <= 0) || (iport > (int)USHRT_MAX) ) 233 | return ERR_BADPORT; 234 | 235 | *port = iport; 236 | return 0; 237 | } 238 | 239 | 240 | /* __EOF__ */ 241 | 242 | -------------------------------------------------------------------------------- /src/com/rom1v/andudpxy/UdpxyService.java: -------------------------------------------------------------------------------- 1 | package com.rom1v.andudpxy; 2 | 3 | import java.io.File; 4 | import java.io.FileOutputStream; 5 | import java.io.IOException; 6 | import java.io.InputStream; 7 | import java.io.OutputStream; 8 | 9 | import android.app.Service; 10 | import android.content.Context; 11 | import android.content.Intent; 12 | import android.os.IBinder; 13 | import android.util.Log; 14 | 15 | /** 16 | * Manager for the native command {@code udpxy}. 17 | * 18 | * The client (typically a video player) can connect to {@code udpxy} using HTTP on 19 | * localhost:UDPXY_PORT specifying the multicast address to subscribe (for instance: 20 | * {@code http://localhost:8379/udp/239.0.0.1:1234/}). 21 | * 22 | * This address can be generated using {@link #proxify(int, String) proxify(udpxyPort, 23 | * videoAddress)}. 24 | * 25 | * @author rom 26 | */ 27 | public class UdpxyService extends Service { 28 | 29 | private static final String TAG = UdpxyService.class.getSimpleName(); 30 | 31 | public static final String EXTRA_PORT = "port"; 32 | 33 | /** The HTTP port to be used by the clients. */ 34 | public static final int DEFAULT_PORT = 8379; 35 | 36 | /** Location of the {@code udpxy} binary. */ 37 | private File udpxyBin; 38 | 39 | /** The {@code udpxy} process associated to this service. */ 40 | private Process udpxyProcess; 41 | 42 | @Override 43 | public int onStartCommand(Intent intent, int flags, int startId) { 44 | int port = intent.getIntExtra(EXTRA_PORT, DEFAULT_PORT); 45 | startUdpxy(port); 46 | return START_STICKY; 47 | } 48 | 49 | @Override 50 | public IBinder onBind(Intent intent) { 51 | // not a bound service 52 | return null; 53 | } 54 | 55 | @Override 56 | public void onCreate() { 57 | super.onCreate(); 58 | udpxyBin = new File(getFilesDir(), "udpxy"); 59 | if (!udpxyBin.exists()) { 60 | extractUdpxyBinary(udpxyBin); 61 | } 62 | } 63 | 64 | @Override 65 | public void onDestroy() { 66 | super.onDestroy(); 67 | // stop udpxy when this service is destroyed, in order to avoid conflicts with future udpxy 68 | // instances 69 | stopUdpxy(); 70 | } 71 | 72 | /** 73 | * Start the {@code udpxy} daemon. 74 | * 75 | * @param port 76 | * the listening port 77 | * @return {@code true} it the command call worked, {@code false} otherwise 78 | */ 79 | private boolean startUdpxy(int port) { 80 | stopUdpxy(); 81 | try { 82 | String[] command = { udpxyBin.getAbsolutePath(), "-p", String.valueOf(port) }; 83 | udpxyProcess = Runtime.getRuntime().exec(command); 84 | return true; 85 | } catch (IOException e) { 86 | Log.e(TAG, "Cannot start udpxy", e); 87 | return false; 88 | } 89 | } 90 | 91 | /** 92 | * Stop the {@code udpxy} process. 93 | * 94 | * Do nothing if there was no active {@code udpxy} process in this service. 95 | */ 96 | private void stopUdpxy() { 97 | if (udpxyProcess != null) { 98 | udpxyProcess.destroy(); 99 | udpxyProcess = null; 100 | } 101 | } 102 | 103 | /** 104 | * The binary file {@code udpxy} is included in assets. This method extracts it to the 105 | * file-system. 106 | * 107 | * @param target 108 | * the target location 109 | */ 110 | private void extractUdpxyBinary(File target) { 111 | InputStream in = null; 112 | OutputStream out = null; 113 | try { 114 | in = getResources().openRawResource(R.raw.udpxy); 115 | out = new FileOutputStream(target); 116 | // copy from R.raw.udpxy to /data/data//files/udpxy 117 | FileUtils.copy(in, out); 118 | // make the file executable 119 | FileUtils.chmod(target, 0755); 120 | } catch (IOException e) { 121 | Log.e(TAG, "Cannot copy udpxy", e); 122 | } finally { 123 | if (in != null) { 124 | try { 125 | in.close(); 126 | } catch (IOException e) { 127 | // don't care 128 | } 129 | } 130 | if (out != null) { 131 | try { 132 | out.close(); 133 | } catch (IOException e) { 134 | // don't care 135 | } 136 | } 137 | } 138 | } 139 | 140 | /** 141 | * Send an intent starting {@code udpxy}. 142 | * 143 | * @param context 144 | * the context 145 | * @param port 146 | * the listening port of {@code udpxy} ({@code 0} for the default port) 147 | */ 148 | public static void startUdpxy(Context context, int port) { 149 | Intent intent = new Intent(context, UdpxyService.class); 150 | if (port != 0) { 151 | intent.putExtra(EXTRA_PORT, port); 152 | } 153 | context.startService(intent); 154 | } 155 | 156 | /** 157 | * Like {@link #startUdpxy(Context, int) startUdpxy(context, 0)}. 158 | * 159 | * @param context 160 | * the context 161 | */ 162 | public static void startUdpxy(Context context) { 163 | startUdpxy(context, 0); 164 | } 165 | 166 | /** 167 | * Send an intent stopping {@code udpxy}. 168 | * 169 | * @param context 170 | * the context 171 | */ 172 | public static void stopUdpxy(Context context) { 173 | Intent intent = new Intent(context, UdpxyService.class); 174 | context.stopService(intent); 175 | } 176 | 177 | /** 178 | * Wrap a channel address ({@code ip:port}) to a {@code udpxy} url ( 179 | * {@code http://udpxy_ip:udpxy_port/udp/ip:port/}). 180 | * 181 | * The input {@code channelAddress} is wrapped unchanged, and is not validated. 182 | * 183 | * @param udpxyPort 184 | * the listening port of {@code udpxy} ({@code 0} for the default port) 185 | * @param videoAddress 186 | * the video address to wrap 187 | * @return the {@code udpxy} url 188 | */ 189 | public static String proxify(int udpxyPort, String videoAddress) { 190 | if (udpxyPort == 0) { 191 | udpxyPort = DEFAULT_PORT; 192 | } 193 | return "http://localhost:" + udpxyPort + "/udp/" + videoAddress + "/"; 194 | } 195 | 196 | /** 197 | * Like {@link #proxify(int,String) proxify(0, videoAddress)}. 198 | * 199 | * @param videoAddress 200 | * the video address to wrap 201 | * @return the {@code udpxy} url 202 | */ 203 | public static String proxify(String videoAddress) { 204 | return proxify(0, videoAddress); 205 | } 206 | 207 | } 208 | -------------------------------------------------------------------------------- /jni/udpxy/sloop_p.c: -------------------------------------------------------------------------------- 1 | /* @(#) abstracted server loop routine */ 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include "osdef.h" /* os-specific definitions */ 26 | #include "udpxy.h" 27 | 28 | #include "mtrace.h" 29 | #include "util.h" 30 | 31 | #include "ctx.h" 32 | #include "uopt.h" 33 | #include "netop.h" 34 | 35 | extern FILE* g_flog; 36 | extern struct udpxy_opt g_uopt; 37 | 38 | extern sig_atomic_t must_quit(); 39 | extern void wait_terminated (struct server_ctx* ctx); 40 | extern void tmout_requests (tmfd_t* asock, size_t *alen); 41 | extern void process_requests (tmfd_t* asock, size_t *alen, 42 | fd_set* rset, struct server_ctx* srv); 43 | extern void accept_requests (int sockfd, tmfd_t* asock, size_t* alen); 44 | extern void terminate_all_clients (struct server_ctx* ctx); 45 | extern void wait_all (struct server_ctx* ctx); 46 | 47 | static const char SLOOP_TAG[] = "pselect(2)"; 48 | 49 | /* global server context */ 50 | struct server_ctx g_srv; 51 | 52 | 53 | /*********************************************************/ 54 | 55 | /* process client requests */ 56 | int 57 | srv_loop( const char* ipaddr, int port, 58 | const char* mcast_addr ) 59 | { 60 | int rc, maxfd, err, nrdy, i; 61 | struct in_addr mcast_inaddr; 62 | fd_set rset; 63 | struct timespec tmout, *ptmout = NULL; 64 | tmfd_t *asock = NULL; 65 | size_t n = 0, nasock = 0, max_nasock = LQ_BACKLOG; 66 | sigset_t oset, bset; 67 | 68 | assert( (port > 0) && mcast_addr && ipaddr ); 69 | 70 | (void)tmfprintf( g_flog, "Server is starting up, max clients = [%u]\n", 71 | g_uopt.max_clients ); 72 | asock = calloc (max_nasock, sizeof(*asock)); 73 | if (!asock) { 74 | mperror (g_flog, ENOMEM, "%s: calloc", __func__); 75 | return ERR_INTERNAL; 76 | } 77 | 78 | if( 1 != inet_aton(mcast_addr, &mcast_inaddr) ) { 79 | mperror(g_flog, errno, "%s: inet_aton", __func__); 80 | free (asock); 81 | return ERR_INTERNAL; 82 | } 83 | 84 | init_server_ctx( &g_srv, g_uopt.max_clients, 85 | (ipaddr[0] ? ipaddr : "0.0.0.0") , (uint16_t)port, mcast_addr ); 86 | 87 | g_srv.rcv_tmout = (u_short)g_uopt.rcv_tmout; 88 | g_srv.snd_tmout = RLY_SOCK_TIMEOUT; 89 | g_srv.mcast_inaddr = mcast_inaddr; 90 | 91 | /* NB: server socket is non-blocking! */ 92 | if( 0 != (rc = setup_listener( ipaddr, port, &g_srv.lsockfd, 93 | g_uopt.lq_backlog )) ) { 94 | free (asock); 95 | return rc; 96 | } 97 | 98 | sigemptyset (&bset); 99 | sigaddset (&bset, SIGINT); 100 | sigaddset (&bset, SIGQUIT); 101 | sigaddset (&bset, SIGCHLD); 102 | sigaddset (&bset, SIGTERM); 103 | 104 | tmout.tv_sec = g_uopt.ssel_tmout; 105 | tmout.tv_nsec = 0; 106 | 107 | if (ptmout) { 108 | TRACE( (void)tmfprintf (g_flog, "pselect() timeout set to " 109 | "[%ld] seconds\n", tmout.tv_sec) ); 110 | } 111 | 112 | (void) sigprocmask (SIG_BLOCK, &bset, &oset); 113 | 114 | TRACE( (void)tmfprintf( g_flog, "Entering server loop [%s]\n", SLOOP_TAG) ); 115 | while (1) { 116 | FD_ZERO( &rset ); 117 | FD_SET( g_srv.lsockfd, &rset ); 118 | FD_SET( g_srv.cpipe[0], &rset ); 119 | 120 | maxfd = (g_srv.lsockfd > g_srv.cpipe[0] ) ? g_srv.lsockfd : g_srv.cpipe[0]; 121 | for (i = 0; (size_t)i < nasock; ++i) { 122 | assert (asock[i].fd >= 0); 123 | FD_SET (asock[i].fd, &rset); 124 | if (asock[i].fd > maxfd) maxfd = asock[i].fd; 125 | } 126 | 127 | /* if there are accepted sockets - apply specified time-out 128 | */ 129 | ptmout = ((nasock > 0) && (g_uopt.ssel_tmout > 0)) ? &tmout : NULL; 130 | 131 | TRACE( (void)tmfprintf( g_flog, "Waiting for input from [%ld] fd's, " 132 | "%s timeout\n", (long)(2 + nasock), (ptmout ? "with" : "NO"))); 133 | 134 | nrdy = pselect (maxfd + 1, &rset, NULL, NULL, ptmout, &oset); 135 | err = errno; 136 | 137 | if( must_quit() ) { 138 | TRACE( (void)tmfputs( "Must quit now\n", g_flog ) ); 139 | rc = 0; break; 140 | } 141 | wait_terminated( &g_srv ); 142 | 143 | if( nrdy < 0 ) { 144 | if (EINTR == err) { 145 | TRACE( (void)tmfputs ("INTERRUPTED, yet " 146 | "will continue.\n", g_flog) ); 147 | rc = 0; continue; 148 | } 149 | 150 | mperror( g_flog, err, "%s: pselect", __func__ ); 151 | break; 152 | } 153 | 154 | TRACE( (void)tmfprintf (g_flog, "Got %ld requests\n", (long)nrdy) ); 155 | if (0 == nrdy) { /* time-out */ 156 | tmout_requests (asock, &nasock); 157 | rc = 0; continue; 158 | } 159 | 160 | if( FD_ISSET(g_srv.cpipe[0], &rset) ) { 161 | (void) tpstat_read( &g_srv ); 162 | if (--nrdy <= 0) continue; 163 | } 164 | 165 | if ((0 < nasock) && 166 | (0 < (nrdy - (FD_ISSET(g_srv.lsockfd, &rset) ? 1 : 0)))) { 167 | process_requests (asock, &nasock, &rset, &g_srv); 168 | /* n now contains # (yet) unprocessed accepted sockets */ 169 | } 170 | 171 | if (FD_ISSET(g_srv.lsockfd, &rset)) { 172 | if (nasock >= max_nasock) { 173 | (void) tmfprintf (g_flog, "Cannot accept sockets beyond " 174 | "the limit [%ld/%ld], skipping\n", 175 | (long)nasock, (long)max_nasock); 176 | } 177 | else { 178 | n = max_nasock - nasock; /* append asock */ 179 | accept_requests (g_srv.lsockfd, &(asock[nasock]), &n); 180 | nasock += n; 181 | } 182 | } 183 | 184 | } /* server loop */ 185 | 186 | TRACE( (void)tmfprintf( g_flog, "Exited server loop [%s]\n", SLOOP_TAG) ); 187 | 188 | for (i = 0; (size_t)i < nasock; ++i) { 189 | if (asock[i].fd > 0) (void) close (asock[i].fd); 190 | } 191 | free (asock); 192 | 193 | /* receive additional (blocked signals) */ 194 | (void) sigprocmask (SIG_SETMASK, &oset, NULL); 195 | wait_terminated( &g_srv ); 196 | terminate_all_clients( &g_srv ); 197 | wait_all( &g_srv ); 198 | 199 | if (0 != close( g_srv.lsockfd )) { 200 | mperror (g_flog, errno, "server socket close"); 201 | } 202 | 203 | free_server_ctx( &g_srv ); 204 | 205 | (void)tmfprintf( g_flog, "Server exits with rc=[%d]\n", rc ); 206 | return rc; 207 | } 208 | 209 | 210 | /* __EOF__ */ 211 | 212 | -------------------------------------------------------------------------------- /jni/udpxy/uopt.c: -------------------------------------------------------------------------------- 1 | /* @(#) option-associated functions for udpxy 2 | * 3 | * Copyright 2008-2011 Pavel V. Cherenkov (pcherenkov@gmail.com) 4 | * 5 | * This file is part of udpxy. 6 | * 7 | * udpxy is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * udpxy is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with udpxy. If not, see . 19 | */ 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include "udpxy.h" 27 | #include "uopt.h" 28 | #include "util.h" 29 | 30 | 31 | static int 32 | read_http_footer (char* buf, size_t len) 33 | { 34 | const char* ev = getenv ("UDPXY_HTTP200_FTR_LN"); 35 | ssize_t n = 0; 36 | 37 | assert (buf && len); 38 | 39 | /* if 1-line footer is specified */ 40 | if (ev) { 41 | (void) strncpy (buf, ev, len-1); 42 | buf[len-1] = '\0'; 43 | return 0; 44 | } 45 | 46 | if (NULL != (ev = getenv ("UDPXY_HTTP200_FTR_FILE"))) { 47 | n = txtf_read (ev, buf, len, stderr); 48 | } 49 | 50 | return (n<0) ? -1 : 0; 51 | } 52 | 53 | 54 | inline static void 55 | get_content_type(char *buf, size_t buflen) 56 | { 57 | static const char DEFAULT_CONTENT_TYPE[] = "Content-Type:application/octet-stream"; 58 | const char* ev = getenv("UDPXY_CONTENT_TYPE"); 59 | 60 | if (ev && *ev) 61 | (void) snprintf(buf, buflen-1, "Content-Type:%s", ev); 62 | else 63 | strncpy(buf, DEFAULT_CONTENT_TYPE, buflen); 64 | 65 | buf[buflen - 1] = '\0'; 66 | } 67 | 68 | 69 | /* populate options with default/initial values 70 | */ 71 | int 72 | init_uopt( struct udpxy_opt* uo ) 73 | { 74 | int rc = 0; 75 | assert( uo ); 76 | 77 | uo->is_verbose = uf_FALSE; 78 | uo->cl_tpstat = uf_FALSE; 79 | uo->nice_incr = 0; 80 | uo->rbuf_len = DEFAULT_CACHE_LEN; 81 | uo->rbuf_msgs = 1; 82 | uo->max_clients = DEFAULT_CLIENT_COUNT; 83 | uo->rcv_tmout = get_timeval( "UDPXY_RCV_TMOUT", 84 | RLY_SOCK_TIMEOUT ); 85 | uo->dhold_tmout = get_timeval( "UDPXY_DHOLD_TMOUT", 86 | DHOLD_TIMEOUT ); 87 | uo->sr_tmout = get_timeval ( "UDPXY_SREAD_TMOUT", SRVSOCK_TIMEOUT ); 88 | uo->sw_tmout = get_timeval ( "UDPXY_SWRITE_TMOUT", SRVSOCK_TIMEOUT ); 89 | uo->ssel_tmout = get_timeval ( "UDPXY_SSEL_TMOUT", SSEL_TIMEOUT ); 90 | uo->lq_backlog = (int) get_sizeval ("UDPXY_LQ_BACKLOG", LQ_BACKLOG); 91 | uo->rcv_lwmark = (int) get_sizeval ("UDPXY_RCV_LWMARK", RCV_LWMARK); 92 | 93 | uo->nosync_sbuf = (u_short)get_flagval( "UDPXY_SSOCKBUF_NOSYNC", 0 ); 94 | uo->nosync_dbuf = (u_short)get_flagval( "UDPXY_DSOCKBUF_NOSYNC", 0 ); 95 | 96 | uo->srcfile = NULL; 97 | uo->dstfile = NULL; 98 | uo->mcast_refresh = DEFAULT_MCAST_REFRESH; 99 | 100 | if (-1 == read_http_footer (uo->h200_ftr, sizeof(uo->h200_ftr))) { 101 | rc = -1; /* modify rc only if there is an error */ 102 | } 103 | 104 | get_content_type(uo->cnt_type, sizeof(uo->cnt_type)); 105 | assert( uo->cnt_type[0] ); 106 | 107 | uo->tcp_nodelay = (flag_t)get_flagval( "UDPXY_TCP_NODELAY", 1); 108 | return rc; 109 | } 110 | 111 | 112 | /* release resources allocated for udpxy options 113 | */ 114 | void 115 | free_uopt( struct udpxy_opt* uo ) 116 | { 117 | assert( uo ); 118 | 119 | if( uo->srcfile ) { 120 | free( uo->srcfile ); uo->srcfile = NULL; 121 | } 122 | 123 | if( uo->dstfile ) { 124 | free( uo->dstfile ); uo->dstfile = NULL; 125 | } 126 | } 127 | 128 | 129 | #ifdef UDPXREC_MOD 130 | 131 | /* populate udpxrec options with default/initial values 132 | */ 133 | int 134 | init_recopt( struct udpxrec_opt* ro ) 135 | { 136 | int rc = 0; 137 | 138 | assert( ro ); 139 | 140 | ro->is_verbose = uf_FALSE; 141 | ro->nice_incr = 0; 142 | 143 | ro->bg_time = ro->end_time = 0; 144 | ro->max_fsize = 0; 145 | ro->bufsize = DEFAULT_CACHE_LEN; 146 | ro->rbuf_msgs = 1; 147 | 148 | ro->mcast_addr[0] = '\0'; 149 | 150 | ro->dstfile = NULL; 151 | ro->pidfile = NULL; 152 | ro->rec_channel[0] = '\0'; 153 | ro->rec_port = 0; 154 | ro->waitupd_sec = -1; 155 | 156 | ro->nosync_sbuf = 157 | (flag_t)get_flagval( "UDPXY_SSOCKBUF_NOSYNC", 0 ); 158 | ro->nosync_dbuf = 159 | (flag_t)get_flagval( "UDPXY_DSOCKBUF_NOSYNC", 0 ); 160 | 161 | ro->rcv_tmout = 0; 162 | 163 | return rc; 164 | } 165 | 166 | 167 | /* release resources allocated for udpxy options 168 | */ 169 | void 170 | free_recopt( struct udpxrec_opt* ro ) 171 | { 172 | assert( ro ); 173 | 174 | if( ro->dstfile ) { 175 | free( ro->dstfile ); ro->dstfile = NULL; 176 | } 177 | if( ro->pidfile ) { 178 | free( ro->pidfile ); ro->pidfile = NULL; 179 | } 180 | 181 | ro->rec_channel[0] = '\0'; 182 | } 183 | 184 | 185 | /* print udpxrec options to stream 186 | */ 187 | void 188 | fprint_recopt( FILE* stream, struct udpxrec_opt* ro ) 189 | { 190 | assert( stream && ro ); 191 | 192 | if( ro->is_verbose ) { 193 | (void)fprintf( stream, "verbose=[ON] " ); 194 | } 195 | if( ro->nice_incr ) { 196 | (void)fprintf( stream, "nice_incr=[%d] ", ro->nice_incr ); 197 | } 198 | if( ro->bg_time > 0 ) { 199 | (void)fprintf( stream, "begin_time=[%s] ", 200 | Zasctime( localtime(&(ro->bg_time) )) ); 201 | } 202 | if( ro->end_time > 0 ) { 203 | (void)fprintf( stream, "end_time=[%s] ", 204 | Zasctime( localtime(&(ro->end_time) )) ); 205 | } 206 | if( ro->max_fsize > 0 ) { 207 | (void)fprintf( stream, "Max filesize=[%.0f] bytes ", 208 | (double)ro->max_fsize ); 209 | } 210 | 211 | (void)fprintf( stream, "Buffer size=[%ld] bytes ", 212 | (long)ro->bufsize ); 213 | 214 | if( ro->rbuf_msgs > 0 ) { 215 | (void)fprintf( stream, "Max messages=[%ld] ", 216 | (long)ro->rbuf_msgs ); 217 | } 218 | if( ro->mcast_addr[0] ) { 219 | (void)fprintf( stream, "Multicast interface=[%s] ", ro->mcast_addr ); 220 | } 221 | if( ro->rec_channel[0] ) { 222 | (void)fprintf( stream, "Channel=[%s:%d] ", ro->rec_channel, ro->rec_port ); 223 | } 224 | if( ro->pidfile ) { 225 | (void)fprintf( stream, "Pidfile=[%s] ", ro->pidfile ); 226 | } 227 | if( ro->dstfile ) { 228 | (void)fprintf( stream, "Destination file=[%s] ", ro->dstfile ); 229 | } 230 | if( ro->waitupd_sec > 0 ) { 231 | (void)fprintf( stream, "Update-wait=[%d] sec ", ro->waitupd_sec ); 232 | } 233 | 234 | (void) fputs( "\n", stream ); 235 | return; 236 | } 237 | 238 | #endif /* UDPXREC_MOD */ 239 | 240 | /* set verbose output on 241 | */ 242 | void 243 | set_verbose( flag_t* verbose ) 244 | { 245 | assert( verbose ); 246 | *verbose = uf_TRUE; 247 | } 248 | 249 | 250 | 251 | /* __EOF__ */ 252 | 253 | -------------------------------------------------------------------------------- /jni/udpxy/sloop_s.c: -------------------------------------------------------------------------------- 1 | /* @(#) abstracted server loop routine */ 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include "osdef.h" /* os-specific definitions */ 26 | #include "udpxy.h" 27 | 28 | #include "mtrace.h" 29 | #include "util.h" 30 | 31 | #include "ctx.h" 32 | #include "uopt.h" 33 | #include "netop.h" 34 | 35 | extern FILE* g_flog; 36 | extern struct udpxy_opt g_uopt; 37 | 38 | extern sig_atomic_t must_quit(); 39 | extern void wait_terminated (struct server_ctx* ctx); 40 | extern void tmout_requests (tmfd_t* asock, size_t *alen); 41 | extern void process_requests (tmfd_t* asock, size_t *alen, 42 | fd_set* rset, struct server_ctx* srv); 43 | extern void accept_requests (int sockfd, tmfd_t* asock, size_t* alen); 44 | extern void terminate_all_clients (struct server_ctx* ctx); 45 | extern void wait_all (struct server_ctx* ctx); 46 | 47 | static const char SLOOP_TAG[] = "select(2)"; 48 | 49 | /* global server context */ 50 | struct server_ctx g_srv; 51 | 52 | 53 | /*********************************************************/ 54 | 55 | /* process client requests */ 56 | int 57 | srv_loop( const char* ipaddr, int port, 58 | const char* mcast_addr ) 59 | { 60 | int rc, maxfd, err, nrdy, i; 61 | struct in_addr mcast_inaddr; 62 | fd_set rset; 63 | struct timeval tmout, idle_tmout, *ptmout = NULL; 64 | tmfd_t *asock = NULL; 65 | size_t n = 0, nasock = 0, max_nasock = LQ_BACKLOG; 66 | sigset_t oset, bset; 67 | 68 | static const long IDLE_TMOUT_SEC = 30; 69 | 70 | assert( (port > 0) && mcast_addr && ipaddr ); 71 | 72 | (void)tmfprintf( g_flog, "Server is starting up, max clients = [%u]\n", 73 | g_uopt.max_clients ); 74 | asock = calloc (max_nasock, sizeof(*asock)); 75 | if (!asock) { 76 | mperror (g_flog, ENOMEM, "%s: calloc", __func__); 77 | return ERR_INTERNAL; 78 | } 79 | 80 | if( 1 != inet_aton(mcast_addr, &mcast_inaddr) ) { 81 | mperror(g_flog, errno, "%s: inet_aton", __func__); 82 | return ERR_INTERNAL; 83 | } 84 | 85 | init_server_ctx( &g_srv, g_uopt.max_clients, 86 | (ipaddr[0] ? ipaddr : "0.0.0.0") , (uint16_t)port, mcast_addr ); 87 | 88 | g_srv.rcv_tmout = (u_short)g_uopt.rcv_tmout; 89 | g_srv.snd_tmout = RLY_SOCK_TIMEOUT; 90 | g_srv.mcast_inaddr = mcast_inaddr; 91 | 92 | /* NB: server socket is non-blocking! */ 93 | if( 0 != (rc = setup_listener( ipaddr, port, &g_srv.lsockfd, 94 | g_uopt.lq_backlog )) ) { 95 | return rc; 96 | } 97 | 98 | sigemptyset (&bset); 99 | sigaddset (&bset, SIGINT); 100 | sigaddset (&bset, SIGQUIT); 101 | sigaddset (&bset, SIGCHLD); 102 | sigaddset (&bset, SIGTERM); 103 | 104 | (void) sigprocmask (SIG_BLOCK, &bset, &oset); 105 | 106 | TRACE( (void)tmfprintf( g_flog, "Entering server loop [%s]\n", 107 | SLOOP_TAG) ); 108 | while (1) { 109 | FD_ZERO( &rset ); 110 | FD_SET( g_srv.lsockfd, &rset ); 111 | FD_SET( g_srv.cpipe[0], &rset ); 112 | 113 | maxfd = (g_srv.lsockfd > g_srv.cpipe[0] ) ? g_srv.lsockfd : g_srv.cpipe[0]; 114 | for (i = 0; (size_t)i < nasock; ++i) { 115 | assert (asock[i].fd >= 0); 116 | FD_SET (asock[i].fd, &rset); 117 | if (asock[i].fd > maxfd) maxfd = asock[i].fd; 118 | } 119 | 120 | /* if there are accepted sockets - apply specified time-out 121 | */ 122 | tmout.tv_sec = g_uopt.ssel_tmout; 123 | tmout.tv_usec = 0; 124 | 125 | idle_tmout.tv_sec = IDLE_TMOUT_SEC; 126 | idle_tmout.tv_usec = 0; 127 | 128 | /* enforce *idle* select(2) timeout to alleviate signal contention */ 129 | ptmout = ((nasock > 0) && (g_uopt.ssel_tmout > 0)) ? &tmout : &idle_tmout; 130 | 131 | TRACE( (void)tmfprintf( g_flog, "Waiting for input from [%ld] fd's, " 132 | "%s timeout\n", (long)(2 + nasock), (ptmout ? "with" : "NO"))); 133 | 134 | if (ptmout && ptmout->tv_sec) { 135 | TRACE( (void)tmfprintf (g_flog, "select() timeout set to " 136 | "[%ld] seconds\n", ptmout->tv_sec) ); 137 | } 138 | 139 | (void) sigprocmask (SIG_UNBLOCK, &bset, NULL); 140 | if( must_quit() ) { 141 | TRACE( (void)tmfputs( "Must quit now\n", g_flog ) ); 142 | rc = 0; break; 143 | } 144 | 145 | nrdy = select (maxfd + 1, &rset, NULL, NULL, ptmout); 146 | err = errno; 147 | (void) sigprocmask (SIG_BLOCK, &bset, NULL); 148 | 149 | if( must_quit() ) { 150 | TRACE( (void)tmfputs( "Must quit now\n", g_flog ) ); 151 | rc = 0; break; 152 | } 153 | wait_terminated( &g_srv ); 154 | 155 | if( nrdy < 0 ) { 156 | if (EINTR == err) { 157 | TRACE( (void)tmfputs ("INTERRUPTED, yet " 158 | "will continue.\n", g_flog) ); 159 | rc = 0; continue; 160 | } 161 | 162 | mperror( g_flog, err, "%s: select", __func__ ); 163 | break; 164 | } 165 | 166 | TRACE( (void)tmfprintf (g_flog, "Got %ld requests\n", (long)nrdy) ); 167 | if (0 == nrdy) { /* time-out */ 168 | tmout_requests (asock, &nasock); 169 | rc = 0; continue; 170 | } 171 | 172 | if( FD_ISSET(g_srv.cpipe[0], &rset) ) { 173 | (void) tpstat_read( &g_srv ); 174 | if (--nrdy <= 0) continue; 175 | } 176 | 177 | if ((0 < nasock) && 178 | (0 < (nrdy - (FD_ISSET(g_srv.lsockfd, &rset) ? 1 : 0)))) { 179 | process_requests (asock, &nasock, &rset, &g_srv); 180 | /* n now contains # (yet) unprocessed accepted sockets */ 181 | } 182 | 183 | if (FD_ISSET(g_srv.lsockfd, &rset)) { 184 | if (nasock >= max_nasock) { 185 | (void) tmfprintf (g_flog, "Cannot accept sockets beyond " 186 | "the limit [%ld/%ld], skipping\n", 187 | (long)nasock, (long)max_nasock); 188 | } 189 | else { 190 | n = max_nasock - nasock; /* append asock */ 191 | accept_requests (g_srv.lsockfd, &(asock[nasock]), &n); 192 | nasock += n; 193 | } 194 | } 195 | } /* server loop */ 196 | 197 | TRACE( (void)tmfprintf( g_flog, "Exited server loop [%s]\n", SLOOP_TAG) ); 198 | 199 | for (i = 0; (size_t)i < nasock; ++i) { 200 | if (asock[i].fd > 0) (void) close (asock[i].fd); 201 | } 202 | free (asock); 203 | 204 | /* receive additional (blocked signals) */ 205 | (void) sigprocmask (SIG_SETMASK, &oset, NULL); 206 | wait_terminated( &g_srv ); 207 | terminate_all_clients( &g_srv ); 208 | wait_all( &g_srv ); 209 | 210 | if (0 != close( g_srv.lsockfd )) { 211 | mperror (g_flog, errno, "server socket close"); 212 | } 213 | 214 | free_server_ctx( &g_srv ); 215 | 216 | (void)tmfprintf( g_flog, "Server exits with rc=[%d]\n", rc ); 217 | return rc; 218 | } 219 | 220 | 221 | /* __EOF__ */ 222 | 223 | -------------------------------------------------------------------------------- /jni/udpxy/doc/en/udpxy.1: -------------------------------------------------------------------------------- 1 | .\" 2 | .\" udpxy.1 3 | .\" 4 | .\" Original: (pcherenkov@gmail.com) 5 | .\" 6 | .TH udpxy 1 "November 17, 2012" "Version 1.0" "udpxy manual page" 7 | 8 | .SH NAME 9 | udpxy \- a UDP-to-HTTP multicast traffic relay daemon. 10 | 11 | .SH SYNOPSIS 12 | .B udpxy 13 | [\-vTS] [\-a \fI\fP] [\-m \fI\fP] [\-c \fI\fP] 14 | [\-l \fI\fP] [\-B \fI\fP] [\-R \fI\fP] [\-H \fI\fP] 15 | [\-n \fI\fP] [\-M \fI\fP] \-p \fI\fP 16 | 17 | .SH DESCRIPTION 18 | .PP 19 | udpxy is a \fIUDP-to-HTTP multicast traffic relay daemon\fP: it forwards UDP traffic 20 | from a given multicast subscription to the requesting HTTP client. 21 | .PP 22 | udpxy listens (on a dedicated address/port) for HTTP requests issued by clients. 23 | A client request should be structured as: 24 | .PP 25 | http://{\fIaddress\fP}:{\fIport\fP}/{\fIcmd\fP}/{\fImgroup_address\fP}[\fBSEP\fP]{\fImgroup_port\fP} 26 | .TP 8 27 | .B [SEP] 28 | :|%|~|+|\-|^ 29 | .TP 8 30 | .B {cmd} 31 | udp|rtp 32 | 33 | .PP 34 | where \fIaddress\fP and \fIport\fP match the listening \fIaddress/port\fP combination of udpxy, 35 | and \fImgroup_address\fP:\fImgroup_port\fP identify the multicast group/channel to subscribe to. 36 | 37 | .PP 38 | .TP 8 39 | .B udp 40 | \fIudp\fP command will have udpxy probe for known types of payload 41 | (such as \fIMPEG\-TS\fP and \fIRTP over MPEG\-TS\fP); 42 | .TP 8 43 | .B rtp 44 | \fIrtp\fP command makes udpxy assume \fIRTP over MPEG\-TS\fP payload, thus skipping the probes. 45 | 46 | .PP 47 | udpxy will start a separate \fIclient process\fP for each new relay request (within the specified limit 48 | on active clients). 49 | The client process will relay/forward all network traffic received (via a UDP socket) from the 50 | specified multicast group to the requesting HTTP connection. 51 | 52 | .PP 53 | udpxy also supports a few administrative requests: 54 | 55 | .PP 56 | .TP 8 57 | .B status 58 | http://\fIaddress\fP:\fIport\fP/\fBstatus\fP/ 59 | to send back an HTML page with daemon status and client statistics. 60 | .TP 8 61 | .B restart 62 | http://\fIaddress\fP:\fIport\fP/\fBrestart\fP/ 63 | to close all active connections and restart. 64 | 65 | 66 | .SH EXAMPLES 67 | .PP 68 | http://192.168.0.12:5056/udp/224.0.2.26:24012 69 | .PP 70 | http://192.168.0.12:5056/rtp/224.0.2.26:24012 71 | .PP 72 | http://192.168.0.15:5056/rtp/224.0.2.26^24055 73 | .PP 74 | http://192.168.0.15:5056/status/ 75 | 76 | .SH OPTIONS 77 | udpxy accepts the following options: 78 | .TP 8 79 | .B \-v 80 | Enable verbose output [default = \fIdisabled\fP]. 81 | .TP 8 82 | .B \-S 83 | Enable client statistics [default = \fIdisabled\fP]. 84 | .TP 8 85 | .B \-T 86 | Do NOT run as a daemon [default = \fIdaemon if root\fP]. 87 | .TP 8 88 | .B \-a \fI\fP 89 | IPv4 address/interface to listen on [default = \fI0.0.0.0\fP]. 90 | .TP 8 91 | .B \-m \fI\fP 92 | IPv4 address/interface of (multicast) source [default = \fI0.0.0.0\fP]. 93 | .TP 8 94 | .B \-c \fI\fP 95 | Maximum number of clients to accept [default = \fI3\fP, max = \fI5000\fP]. 96 | .TP 8 97 | .B \-l \fI\fP 98 | Log output to file [default = \fIstderr\fP]. 99 | .TP 8 100 | .B \-B \fI\fP 101 | Buffer size (65536, 32Kb, 1Mb) for inbound (multicast) data [default = \fI2048 bytes\fP]. 102 | .TP 8 103 | .B \-R \fI\fP 104 | Maximum number of messages to buffer (\fI\-1\fP = \fIall\fP) [default = \fI1\fP]. 105 | .TP 8 106 | .B \-H \fI\fP 107 | Maximum time (in seconds) to hold data in a buffer (\fI\-1\fP = \fIunlimited\fP) [default = \fI1\fP]. 108 | .TP 8 109 | .B \-n \fI\fP 110 | Nice value increment [default = \fI0\fP]. 111 | .TP 8 112 | .B \-M \fI\fP 113 | Renew multicast subscription every M seconds (\fIskip\fP if \fI0\fP) [default = \fI0\fP]. 114 | .TP 8 115 | .B \-p \fI\fP 116 | Port to listen on. 117 | 118 | .SH PAYLOAD TYPES AND HANDLING 119 | 120 | .PP 121 | udpxy recognizes \fIMPEG\-TS\fP and \fIRTP over MPEG\-TS\fP payloads within relayed packets; 122 | if udpxy encounters RTP payload it automatically 'translates' it to MPEG\-TS (by stripping RTP headers) 123 | so that media players not recognizing RTP could still play back the stream. 124 | .PP 125 | So far, no translation is performed for other payload types. 126 | 127 | .SH RECORDING MPEG TRAFFIC 128 | .PP 129 | udpxy includes functionality to record captured traffic as 130 | \fIraw MPEG\-TS stream\fP into a file. This functionality is enabled through \fBudpxrec\fP: 131 | a bundled\-in application that is linked together with udpxy (as one executable). 132 | .PP 133 | udpxrec is invoked via a symbolic link (named \fBudpxrec\fP) to the udpxy executable 134 | (i.e. \fBdo not rename\fP udpxy executable). 135 | .PP 136 | udpxrec creates MPEG files encapsulating MPEG\-TS segments; certain media players 137 | will \fBNOT\fP play such files; in order to make them playable the stream must be transcoded 138 | to MPEG\-PS; vlc 'knows' how to do such transcoding, here is a command-line example: 139 | .PP 140 | .B vlc input\-ts.mpg \-\-sout="#std{access=file,mux=ps,dst=out-ps.mpg}" 141 | .PP 142 | The resulting MPEG-PS file can be played back by most media players. 143 | 144 | 145 | .SH ENVIRONMENT 146 | udpxy utilizes the following environment variables to compliment its 147 | command\-line options; the variables are considered for the options that 148 | most people would not need to change too often (or simply inconvenient 149 | to use from the command line). 150 | .PP 151 | \fBNB\fP: If there is a command-line switch that would intersect in functionality 152 | with an environment variable, the switch \fIalways\fP has higher priority. 153 | .PP 154 | .TP 8 155 | .B UDPXY_RCV_TMOUT 156 | timeout (sec) on the \fIinbound\fP data stream (\fImulticast\fP), default=\fI5\fP; 157 | .TP 8 158 | .B UDPXY_DHOLD_TMOUT 159 | timeout (sec) to hold buffered data before sending/flushing to client(s), default=\fI1\fP; 160 | .TP 8 161 | .B UDPXY_SREAD_TMOUT 162 | timeout (sec) to \fIread\fP from the listening socked (handling HTTP requests), default=\fI1\fP; 163 | .TP 8 164 | .B UDPXY_SWRITE_TMOUT 165 | timeout (sec) to \fIwrite\fP to the listening socked (handling HTTP requests), default=\fI1\fP; 166 | .TP 8 167 | .B UDPXY_SSEL_TMOUT 168 | timeout (sec) to \fIselect(2)\fP in server loop (unused if \fIpselect(2)\fP is employed), default=\fI30\fP; 169 | .TP 8 170 | .B UDPXY_LQ_BACKLOG 171 | size of the listener socket's \fIbacklog\fP, default=\fI16\fP; 172 | .TP 8 173 | .B UDPXY_SRV_RLWMARK 174 | low watermaek on the receiving (m\-cast) socket, default=\fI0\fP (\fInot set\fP); 175 | .TP 8 176 | .B UDPXY_SSOCKBUF_NOSYNC 177 | do not sync \fIinbound\fP (UDP) socket's buffer size (with the value set by \fI\-B\fP), default=\fI1\fP (\fIsync\fP); 178 | .TP 8 179 | .B UDPXY_DSOCKBUF_NOSYNC 180 | do not sync \fIoutbound\fP (TCP) socket's buffer size (with the value set by \fI\-B\fP), default=\fI1\fP (\fIsync\fP); 181 | .TP 8 182 | .B UDPXY_TCP_NODELAY 183 | disable \fINagle algorithm\fP on the newly accepted socket (faster channel switching), default=\fI1\fP; 184 | .TP 8 185 | .B UDPXY_HTTP200_FTR_FILE 186 | append contents of the given text file to the \fIHTTP 200\fP response, default=\fInone\fP; 187 | .TP 8 188 | .B UDPXY_HTTP200_FTR_LN 189 | append the text (line) to the \fIHTTP 200\fP response, default=\fInone\fP; 190 | .TP 8 191 | .B UDPXY_ALLOW_PAUSES 192 | if blocked on a \fIwrite(2)\fP, keep reading data until the buffer (\fB\-B\fP \fI\fP) is full, default=\fIdisabled\fP; 193 | .TP 8 194 | .B UDPXY_PAUSE_MSEC 195 | allow only \fIN\fP milliseconds of reading data when blocked on a \fIwrite(2)\fP. 196 | .TP 8 197 | .B UDPXY_CONTENT_TYPE 198 | specify custom \fBContent\-Type\fP in \fIHTTP\fP responses. 199 | 200 | .SH AUTHORS 201 | Pavel V. Cherenkov and all the good people who submitted patches or otherwise contributed to the project. 202 | 203 | .SH "SEE ALSO" 204 | .BR udpxrec (1) 205 | 206 | .\" __EOF__ 207 | 208 | -------------------------------------------------------------------------------- /jni/udpxy/mkpg.c: -------------------------------------------------------------------------------- 1 | /* @(#) HTML-page templates/generation for udpxy status page 2 | * 3 | * Copyright 2008-2011 Pavel V. Cherenkov (pcherenkov@gmail.com) 4 | * 5 | * This file is part of udpxy. 6 | * 7 | * udpxy is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * udpxy is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with udpxy. If not, see . 19 | */ 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #include 29 | 30 | #include "ctx.h" 31 | #include "prbuf.h" 32 | #include "udpxy.h" 33 | #include "util.h" 34 | #include "mtrace.h" 35 | 36 | #include "statpg.h" 37 | #include "mkpg.h" 38 | 39 | extern FILE* g_flog; 40 | 41 | 42 | /* generate throughput statistic string 43 | */ 44 | static const char* 45 | tpstat_str( const struct tput_stat* ts, char* str, size_t len ) 46 | { 47 | assert( ts && str && len ); 48 | 49 | if( (0 != ts->sender_id) && (ts->nsec > 0.0) ) { 50 | (void) snprintf( str, len, "%.2f Kb/sec", 51 | (ts->nbytes / 1024.0) / ts->nsec ); 52 | } 53 | else { 54 | (void) snprintf( str, len, "N/A" ); 55 | } 56 | 57 | return str; 58 | } 59 | 60 | 61 | /* generate individual clients' status records 62 | */ 63 | static int 64 | mk_client_entries( const struct server_ctx* ctx, 65 | char* buf, size_t* len ) 66 | { 67 | prbuf_t pb = NULL; 68 | int n = -1; 69 | size_t i = 0, total = 0; 70 | ssize_t max_cli_mem = 0, max_cli_tail = 0; 71 | char tpinfo[ 32 ]; 72 | 73 | assert( ctx && buf && len ); 74 | 75 | do { 76 | n = prbuf_open( &pb, buf, *len ); 77 | if( -1 == n ) break; 78 | 79 | /* table header */ 80 | n = prbuf_printf( pb, ACLIENT_TABLE[0] ); 81 | if( -1 == n ) break; 82 | else 83 | total += n; 84 | 85 | for( i = 0, n = -1; n && (i < ctx->clmax); ++i ) { 86 | struct client_ctx* client = &(ctx->cl[i]); 87 | if( client->pid <= 0 ) continue; 88 | 89 | n = prbuf_printf( pb, ACLIENT_REC_FMT[ i % 2 ], 90 | ctx->cl[i].pid, 91 | client->src_addr, client->src_port, 92 | client->mcast_addr, client->mcast_port, 93 | client->tail ? client->tail : "", 94 | tpstat_str( &(client->tstat), tpinfo, 95 | sizeof(tpinfo) ) ); 96 | if( n <= 0 ) break; 97 | 98 | if (n > max_cli_mem) 99 | max_cli_mem = n; 100 | if (client->tail && (ssize_t)strlen(client->tail) > max_cli_tail) 101 | max_cli_tail = strlen(client->tail); 102 | 103 | total += n; 104 | } /* loop */ 105 | 106 | /* table footer */ 107 | n = prbuf_printf( pb, ACLIENT_TABLE[1] ); 108 | if( -1 == n ) break; 109 | else 110 | total += n; 111 | 112 | } while(0); 113 | 114 | if( n > 0 ) { 115 | *len = total; 116 | } 117 | else { 118 | (void)tmfprintf( g_flog, 119 | "Error preparing status (client) HTML: " 120 | "insufficient memory: %ld bytes allowed, " 121 | "%ld clients, max memory per client: %ld bytes, " 122 | "max client tail: %ld bytes\n", 123 | (long)*len, (long)ctx->clmax, (long)max_cli_mem, 124 | (long)max_cli_tail); 125 | } 126 | 127 | (void) prbuf_close( pb ); 128 | return (n > 0 ? 0 : -1); 129 | } 130 | 131 | 132 | 133 | /* generate service's (HTML) status page 134 | */ 135 | int 136 | mk_status_page( const struct server_ctx* ctx, 137 | char* buf, size_t* len, 138 | int options ) 139 | { 140 | int n = -1; 141 | prbuf_t pb = NULL; 142 | time_t tm_now = time(NULL); 143 | const char* str_now = Zasctime(localtime(&tm_now)); 144 | 145 | size_t num_clients = 0, i = 0; 146 | char* client_text = NULL; 147 | const char* page_format = NULL; 148 | const unsigned delay_msec = 3000; 149 | 150 | size_t text_size = 0, HEADER_SIZE = 0; 151 | static size_t MIN_PER_CLI = 80 + (3 * (IPADDR_STR_SIZE + 5) ); 152 | 153 | extern const char UDPXY_COPYRIGHT_NOTICE[]; 154 | extern const char COMPILE_MODE[]; 155 | extern const char VERSION[]; 156 | extern const int BUILDNUM; 157 | 158 | assert( ctx && buf && len ); 159 | 160 | do { 161 | n = prbuf_open( &pb, buf, *len ); 162 | if( -1 == n ) break; 163 | 164 | if( options & MSO_HTTP_HEADER ) { 165 | n = prbuf_printf( pb, "%s", HTML_PAGE_HEADER ); 166 | if( n <= 0 ) break; 167 | } 168 | 169 | if( options & MSO_RESTART ) { 170 | n = prbuf_printf( pb, REDIRECT_SCRIPT_FMT, delay_msec ); 171 | if( n <= 0 ) break; 172 | } 173 | 174 | for( i = 0, n = -1; n && (i < LEN_STAT_PAGE_BASE); ++i ) { 175 | n = prbuf_printf( pb, "%s", STAT_PAGE_BASE[i] ); 176 | } 177 | if( n <= 0 ) break; 178 | 179 | for(text_size = 0, num_clients = 0, i = 0; i < ctx->clmax; ++i ) { 180 | if( ctx->cl[i].pid > 0 ) { 181 | ++num_clients; 182 | text_size += MIN_PER_CLI + strlen(ctx->cl[i].tail); 183 | } 184 | } 185 | 186 | if( ! (options & MSO_SKIP_CLIENTS) ) { 187 | if( num_clients > (size_t)0 ) { 188 | HEADER_SIZE = strlen(ACLIENT_TABLE[0]); 189 | HEADER_SIZE += strlen(ACLIENT_TABLE[1]); 190 | 191 | text_size += HEADER_SIZE; 192 | if (text_size > *len) { 193 | (void) tmfprintf(g_flog, "Client portion of memory [%ld bytes] > " 194 | "[%ld bytes] of the page buffer.\n", 195 | (long)text_size, (long)*len); 196 | n = -1; break; 197 | } 198 | 199 | client_text = malloc( text_size ); 200 | if( NULL == client_text ) { 201 | mperror( g_flog, errno, "%s: calloc", __func__ ); 202 | n = -1; 203 | break; 204 | } 205 | 206 | n = mk_client_entries( ctx, client_text, &text_size ); 207 | if( -1 == n ) break; 208 | } 209 | } /* MSO_SKIP_CLIENTS */ 210 | 211 | page_format = ( options & MSO_RESTART ) ? RST_PAGE_FMT1 : STAT_PAGE_FMT1; 212 | n = prbuf_printf( pb, page_format, 213 | getpid(), ctx->listen_addr, ctx->listen_port, 214 | ctx->mcast_ifc_addr, 215 | num_clients, 216 | (client_text ? client_text : ""), 217 | REQUEST_GUIDE, 218 | VERSION, BUILDNUM, COMPILE_MODE, str_now, 219 | UDPXY_COPYRIGHT_NOTICE ); 220 | if( -1 == n ) break; 221 | 222 | } while(0); 223 | 224 | if( -1 == n ) { 225 | (void)tmfprintf( g_flog, 226 | "Error preparing status HTML: " 227 | "insufficient memory size=[%lu]\n", (u_long)(*len)); 228 | } 229 | else { 230 | *len = prbuf_len( pb ); 231 | } 232 | 233 | free( client_text ); 234 | (void) prbuf_close( pb ); 235 | 236 | return (n > 0 ? 0 : -1); 237 | } 238 | 239 | 240 | /* __EOF__ */ 241 | 242 | -------------------------------------------------------------------------------- /jni/udpxy/rtp.c: -------------------------------------------------------------------------------- 1 | /* @(#) implementation of RTP-protocol parsing functions for udpxy 2 | * 3 | * Copyright 2008-2011 Pavel V. Cherenkov (pcherenkov@gmail.com) 4 | * 5 | * This file is part of udpxy. 6 | * 7 | * udpxy is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * udpxy is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with udpxy. If not, see . 19 | */ 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include "rtp.h" 27 | #include "mtrace.h" 28 | #include "util.h" 29 | 30 | 31 | /* check if the buffer is an RTP packet 32 | */ 33 | int 34 | RTP_check( const char* buf, const size_t len, int* is_rtp, FILE* log ) 35 | { 36 | int rtp_version = 0; 37 | int rtp_payload_type = 0; 38 | 39 | assert( buf && len && is_rtp && log ); 40 | 41 | if( len < RTP_MIN_SIZE ) { 42 | (void)tmfprintf( log, "RTP_check: buffer size [%lu] is " 43 | "less than minimum [%lu]\n" , (u_long)len, (u_long)RTP_MIN_SIZE ); 44 | return -1; 45 | } 46 | 47 | /* initial assumption: is NOT RTP */ 48 | *is_rtp = 0; 49 | 50 | if( MPEG_TS_SIG == buf[0] ) { 51 | TRACE( (void)tmfputs( "MPEG-TS stream detected\n", log ) ); 52 | return 0; 53 | } 54 | 55 | rtp_version = ( buf[0] & 0xC0 ) >> 6; 56 | if( RTP_VER2 != rtp_version ) { 57 | TRACE( (void)tmfprintf( log, "RTP_check: wrong RTP version [%d], " 58 | "must be [%d]\n", (int)rtp_version, (int)RTP_VER2) ); 59 | return 0; 60 | } 61 | 62 | if( len < RTP_HDR_SIZE ) { 63 | TRACE( (void)tmfprintf( log, "RTP_check: header size " 64 | "is too small [%lu]\n", (u_long)len ) ); 65 | return 0; 66 | } 67 | 68 | *is_rtp = 1; 69 | 70 | rtp_payload_type = buf[1] & 0x7F; 71 | switch( rtp_payload_type ) { 72 | case P_MPGA: 73 | TRACE( (void)tmfprintf( log, "RTP_check: [%d] MPEG audio stream\n", 74 | (int)rtp_payload_type ) ); 75 | break; 76 | case P_MPGV: 77 | TRACE( (void)tmfprintf( log, "RTP_check: [%d] MPEG video stream\n", 78 | (int)rtp_payload_type ) ); 79 | break; 80 | case P_MPGTS: 81 | TRACE( (void)tmfprintf( log, "RTP_check: [%d] MPEG TS stream\n", 82 | (int)rtp_payload_type ) ); 83 | break; 84 | 85 | default: 86 | (void) tmfprintf( log, "RTP_check: unsupported RTP " 87 | "payload type [%d]\n", (int)rtp_payload_type ); 88 | return -1; 89 | } 90 | 91 | return 0; 92 | } 93 | 94 | 95 | /* return 1 if buffer contains an RTP packet, 0 otherwise 96 | */ 97 | int 98 | RTP_verify( const char* buf, const size_t len, FILE* log ) 99 | { 100 | int rtp_version = 0; 101 | int rtp_payload_type = 0; 102 | 103 | if( (len < RTP_MIN_SIZE) || (len < RTP_HDR_SIZE) ) { 104 | (void)tmfprintf( log, "RTP_verify: inappropriate size=[%lu] " 105 | "of RTP packet\n", (u_long)len ); 106 | return 0; 107 | } 108 | 109 | rtp_version = ( buf[0] & 0xC0 ) >> 6; 110 | rtp_payload_type = buf[1] & 0x7F; 111 | 112 | /* 113 | TRACE( (void)tmfprintf( log, "RTP version [%d] at [%p]\n", rtp_version, 114 | (const void*)buf ) ); 115 | */ 116 | 117 | if( RTP_VER2 != rtp_version ) { 118 | /* 119 | TRACE( (void)tmfprintf( log, "RTP_verify: wrong RTP version [%d], " 120 | "must be [%d]\n", (int)rtp_version, (int)RTP_VER2) ); 121 | */ 122 | return 0; 123 | } 124 | 125 | switch( rtp_payload_type ) { 126 | case P_MPGA: 127 | case P_MPGV: 128 | case P_MPGTS: 129 | break; 130 | default: 131 | (void) tmfprintf( log, "RTP_verify: unsupported RTP " 132 | "payload type [%d]\n", (int)rtp_payload_type ); 133 | return 0; 134 | } 135 | 136 | return 1; 137 | } 138 | 139 | 140 | /* calculate length of an RTP header 141 | */ 142 | int 143 | RTP_hdrlen( const char* buf, const size_t len, size_t* hdrlen, FILE* log ) 144 | { 145 | int rtp_CSRC = -1, rtp_ext = -1; 146 | int rtp_payload = -1; 147 | ssize_t front_skip = 0, 148 | ext_len = 0; 149 | 150 | assert( buf && (len >= RTP_HDR_SIZE) && hdrlen && log ); 151 | 152 | rtp_payload = buf[1] & 0x7F; 153 | rtp_CSRC = buf[0] & 0x0F; 154 | rtp_ext = buf[0] & 0x10; 155 | 156 | /* profile-based skip: adopted from vlc 0.8.6 code */ 157 | if( (P_MPGA == rtp_payload) || (P_MPGV == rtp_payload) ) 158 | front_skip = 4; 159 | else if( P_MPGTS != rtp_payload ) { 160 | (void)tmfprintf( log, "RTP_process: " 161 | "Unsupported payload type [%d]\n", rtp_payload ); 162 | return -1; 163 | } 164 | 165 | if( rtp_ext ) { 166 | /* 167 | TRACE( (void)tmfprintf( log, "%s: RTP x-header detected, CSRC=[%d]\n", 168 | __func__, rtp_CSRC) ); 169 | */ 170 | 171 | if( len < RTP_XTHDRLEN ) { 172 | /* 173 | TRACE( (void)tmfprintf( log, "%s: RTP x-header requires " 174 | "[%lu] bytes, only [%lu] provided\n", __func__, 175 | (u_long)(XTLEN_OFFSET + 1), (u_long)len ) ); 176 | */ 177 | return ENOMEM; 178 | } 179 | } 180 | 181 | if( rtp_ext ) { 182 | ext_len = XTSIZE + 183 | sizeof(int32_t) * ((buf[ XTLEN_OFFSET ] << 8) + buf[ XTLEN_OFFSET + 1 ]); 184 | } 185 | 186 | front_skip += RTP_HDR_SIZE + (CSRC_SIZE * rtp_CSRC) + ext_len; 187 | 188 | *hdrlen = front_skip; 189 | return 0; 190 | } 191 | 192 | 193 | /* process RTP package to retrieve the payload 194 | */ 195 | int 196 | RTP_process( void** pbuf, size_t* len, int verify, FILE* log ) 197 | { 198 | int rtp_padding = -1; 199 | size_t front_skip = 0, back_skip = 0, pad_len = 0; 200 | 201 | char* buf = NULL; 202 | size_t pkt_len = 0; 203 | 204 | assert( pbuf && len && log ); 205 | buf = *pbuf; 206 | pkt_len = *len; 207 | 208 | if( verify && !RTP_verify( buf, pkt_len, log ) ) 209 | return -1; 210 | 211 | if( 0 != RTP_hdrlen( buf, pkt_len, &front_skip, log ) ) 212 | return -1; 213 | 214 | rtp_padding = buf[0] & 0x20; 215 | if( rtp_padding ) { 216 | pad_len = buf[ pkt_len - 1 ]; 217 | } 218 | 219 | back_skip += pad_len; 220 | 221 | if( verify && (pkt_len < (front_skip + back_skip)) ) { 222 | (void) tmfprintf( log, "RTP_process: invalid header " 223 | "(skip [%lu] exceeds packet length [%lu])\n", 224 | (u_long)(front_skip + back_skip), (u_long)pkt_len ); 225 | return -1; 226 | } 227 | 228 | /* adjust buffer/length to skip heading and padding */ 229 | /* 230 | TRACE( (void)tmfprintf( log, "In: RTP buf=[%p] of [%lu] bytes, " 231 | "fskip=[%ld], bskip=[%lu]\n", 232 | (void*)buf, (u_long)pkt_len, 233 | (u_long)front_skip, (u_long)back_skip ) ); 234 | */ 235 | 236 | buf += front_skip; 237 | pkt_len -= (front_skip + back_skip); 238 | 239 | /* 240 | TRACE( (void)tmfprintf( log, "Out RTP buf=[%p] of [%lu] bytes\n", 241 | (void*)buf, (u_long)pkt_len ) ); 242 | */ 243 | *pbuf = buf; 244 | *len = pkt_len; 245 | 246 | return 0; 247 | } 248 | 249 | 250 | /* __EOF__ */ 251 | 252 | -------------------------------------------------------------------------------- /jni/udpxy/README: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2008-2012 Pavel V. Cherenkov (pcherenkov@gmail.com) 3 | # 4 | # This file is part of udpxy. 5 | # 6 | # udpxy is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # udpxy is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with udpxy. If not, see . 18 | # 19 | 20 | Summary 21 | -------------- 22 | 23 | udpxy is a UDP-to-HTTP multicast traffic relay daemon: 24 | it forwards UDP traffic from a given multicast subscription 25 | to the requesting HTTP client. 26 | 27 | udpxy is released under GPL v.3 28 | 29 | Project status 30 | -------------- 31 | 32 | udpxy has not been extended or supported for 4+ years, having been 33 | replaced by Gigapxy - a superior enterprise-oriented product. 34 | Please see more info at , thank you. 35 | 36 | 37 | Building and installing 38 | -------------- 39 | 40 | Untar the *.tgz source distribution into a directory of your choice by 41 | running 42 | tar -xzvf udpxy.X.Y-ZZ.tgz 43 | or 44 | gzip -dc udpxy.X.Y-ZZ.tgz | tar -xvf - 45 | 46 | Make sure GNU make and gcc are available (gcc 3.x and up should work, lower 47 | versions are not guaranteed to build the source correctly); for compilers 48 | other than gcc alterations to Makefile might be needed. 49 | 50 | Running 'make' without a target will build the 'release' version of 51 | udpxy (no asserts, no debug symbols, verbose mode on). 52 | 53 | Other make targets are: 54 | debug (asserts, debug symbols, verbose mode on); 55 | lean (no asserts, no debug symbols, verbose mode off); 56 | rdebug (same as 'release' but with debug symbols); 57 | ldebug (same as 'lean' but with debug symbols); 58 | 59 | Once the make has succeeded, the udpxy executable file could be 60 | copied to a location of one's choice and run from there - no additional 61 | installation steps are required. 62 | 63 | udpxy can be started with a number of configuration parameters, 64 | such as listening address/port, multicast interface name, etc. 65 | A brief usage summary is provided when udpxy is invoked from command line 66 | without parameters. 67 | 68 | HTTP commands 69 | -------------- 70 | 71 | udpxy responds to HTTP (GET) commands to receive data from 72 | a dedicated multicast group and forward it to the initiating (HTTP) 73 | connection. 74 | 75 | The command to relay traffic is in the format as below: 76 | 77 | http://address:port/cmd/mgroup_address[SEP]mgroup_port/ 78 | 79 | [SEP] ::= :|%|~|+|-|^ 80 | i.e: 81 | http://ip:port/cmd/mgroup_address:mgroup_port/ 82 | http://ip:port/cmd/mgroup_address%mgroup_port/ 83 | http://ip:port/cmd/mgroup_address~mgroup_port/ 84 | ...... 85 | http://ip:port/cmd/mgroup_address^mgroup_port/ 86 | 87 | are acceptable and should all work in the same manner. 88 | 89 | cmd ::= udp | rtp 90 | 91 | where ip and port match the listening address/port combination of udpxy, 92 | and mgroup_address:mgroup_port identify the multicast group to subscribe to. 93 | 94 | Using 'udp' command will instruct udpxy to probe for known types of payload 95 | (such as MPEG-TS and RTP over MPEG-TS); using 'rtp' makes udpxy assume RTP 96 | over MPEG-TS payload, thus skipping the probes. 97 | 98 | udpxy will start a 'client' process for each new relay request as long as 99 | their number would not exceed a pre-set maximum (see usage summary). 100 | 101 | udpxy also supports a few additional HTTP requests, such as: 102 | 103 | http://address:port/status/ - to display basic daemon's statistics 104 | http://address:port/restart/ - to close all active connections and restart 105 | 106 | Payload types and handling 107 | -------------- 108 | 109 | udpxy recognizes MPEG-TS and RTP (over MPEG-TS) payloads within relayed packets; 110 | if udpxy encounters RTP payload it automatically 'translates' it to MPEG-TS so that 111 | media players not recognizing RTP on TCP could still play back the stream. 112 | 113 | So far, no translation is performed for other payload types. 114 | 115 | Recording MPEG traffic 116 | -------------- 117 | udpxy (in builds >0.33) includes functionality to record captured traffic as 118 | raw MPEG-TS stream into a file. This functionality is enabled through udpxrec: 119 | a bundled-in application that is linked together with udpxy (as one executable). 120 | 121 | udpxrec is invoked by a symbolic link (named udpxrec) to the udpxy executable 122 | (NB: do not rename udpxy executable). 123 | 124 | udpxrec creates MPEG files encapsulating MPEG-TS segments; most media players 125 | will *NOT* play such files; to make them playable the stream must be transcoded 126 | to MPEG-PS; vlc knows how to do such transcoding, here is a command-line example: 127 | 128 | vlc input-ts.mpg --sout="#std{access=file,mux=ps,dst=out-ps.mpg}" 129 | 130 | The resulting PS file can be played back by most media players. 131 | 132 | Portability 133 | -------------- 134 | udpxy was written to run on 'POSIX-compliant' systems; 135 | so far all builds have been tested to build and run on Linux 2.4, 2.6, 3.x (IA32, ARM) 136 | and *some* (but not all) on HP-UX 11.11 (PA-RISC 1.1, 2.0w). 137 | 138 | Build 12 of version 1.0 (Chipmunk) was ported to compile under FreeBSD 7.1 139 | using GNU make 3.8; later builds have been tested to compile under later 140 | versions of FreeBSD (up to 9.0); 141 | 142 | Certain builds have been ported to build under cygwin; cygwin is 143 | *NOT* considered to be a fully supported platform yet there is an 144 | ongoing effort to make udpxy run on it as well. 145 | 146 | Environment variables 147 | -------------- 148 | udpxy utilizes the following environment variables to compliment its 149 | command-line options; the variables are considered for the options that 150 | most people would not need to change too often (or simply inconvenient 151 | to use from the command line). 152 | 153 | NB: If there is a command-line switch that would intersect in functionality 154 | with an environment variable, the switch *always* has the higher priority. 155 | 156 | UDPXY_RCV_TMOUT - timeout (sec) on the inbound data stream (multicast), default=5; 157 | UDPXY_DHOLD_TMOUT - timeout (sec) to hold buffered data before sending/flushing to client(s), default=1; 158 | 159 | UDPXY_SREAD_TMOUT - timeout (sec) to read from the listening socked (handling HTTP requests), default=1; 160 | UDPXY_SWRITE_TMOUT - timeout (sec) to write to the listening socked (handling HTTP requests), default=1; 161 | UDPXY_SSEL_TMOUT - timeout (sec) to select(2) in server loop (unused if pselect(2) is employed), default=30; 162 | UDPXY_LQ_BACKLOG - size of the listener socket's backlog, default=16; 163 | UDPXY_SRV_RLWMARK - low watermaek on the receiving (m-cast) socket, default=0 (not set); 164 | UDPXY_SSOCKBUF_NOSYNC - do not sync inbound (UDP) socket's buffer size (with value set by -B), default=1 (sync); 165 | UDPXY_DSOCKBUF_NOSYNC - do not sync outbound (TCP) socket's buffer size (with value set by -B), default=1 (sync); 166 | 167 | UDPXY_TCP_NODELAY - disable Nagle algorithm on the newly accepted socket (faster channel switching), default=1; 168 | 169 | UDPXY_HTTP200_FTR_FILE - append contents of the given file to the HTTP 200 response, default=none; 170 | UDPXY_HTTP200_FTR_LN - append the text (line) to the HTTP 200 response, default=none; 171 | 172 | UDPXY_ALLOW_PAUSES - if blocked on a write, keep reading data until the buffer (-B size) is full, default=disabled; 173 | UDPXY_PAUSE_MSEC - allow only N milliseconds of reading data when blocked on a write. 174 | UDPXY_CONTENT_TYPE - specify custom Content-Type in HTTP responses. 175 | 176 | --EOF-- 177 | 178 | -------------------------------------------------------------------------------- /jni/udpxy/README.russian: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2008-2012 Pavel V. Cherenkov (pcherenkov@gmail.com) 3 | # 4 | # This file is part of udpxy. 5 | # 6 | # udpxy is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # udpxy is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with udpxy. If not, see . 18 | # 19 | 20 | Краткое описание 21 | -------------------- 22 | 23 | udpxy - серверное приложение (daemon) для передачи данных из сетевого потока мультикаст канала 24 | (вещаемого по UDP) в HTTP соединение запрашивающего клиента. 25 | 26 | udpxy - распространяется бесплатно в соответствие с лицензией GNU GPLv3. 27 | 28 | Сборка и установка: 29 | 30 | Разархивируйте исходный код из файла *.tgz в директорию по выбору с помощью команды: 31 | tar -xzvf udpxy.X.Y-ZZ.tgz 32 | или 33 | gzip -dc udpxy.X.Y-ZZ.tgz | tar -xvf - 34 | 35 | Убедитесь в наличии GNU make и gcc (версии gcc начиная с 3.x должны подойти, 36 | предыдущие версии не гарантируют корректной сборки кода); для сборки при помощи 37 | других компиляторов (не gcc) могут понадобиться изменения в Makefile. 38 | 39 | Запуск 'make' без параметра режима приведёт к сборке версии udpxy 'release' 40 | (без вызовов assert(3), без отладочных символов, с возможностью работы в режиме 41 | отладки - verbose). 42 | 43 | Прочие режимы сборки: 44 | debug (assert(3), отладочные символы, режим verbose); 45 | lean (без assert(3), нет отладочных символов, нет режима verbose); 46 | rdebug (то же, что и release, но с отладочными символами); 47 | ldebug (то же, что и lean, но с отладочными символами). 48 | 49 | При успешном окончании работы make, исполныемый файл udpxy может быть 50 | скопирован в любую выбранную директорию и запускаться оттуда - никаких 51 | дополнительных шагов установки не требуется. 52 | 53 | udpxy может быть запущен с различными параметрами, такими как, 54 | к примеру, адрес и номер порта, принимающего запросы, имя сетевого 55 | интерфейса для работы с мультикаст потоками, и т.д. Краткое руководство 56 | к использованию и описание параметров командной строки будет выведено, 57 | если запустить udpxy без параметров. 58 | 59 | HTTP команды 60 | -------------------- 61 | 62 | udpxy реагирует на команды протокола HTTP (GET) для получения данных 63 | из мультикаст группы и перенаправления этих даных в запрашивающее 64 | HTTP соединение. 65 | 66 | Формат команды перенаправления сетевого потока приведён ниже: 67 | 68 | http://address:port/cmd/mgroup_address[SEP]mgroup_port/ 69 | 70 | [SEP] ::= :|%|~|+|-|^ 71 | т.е. команды: 72 | http://ip:port/cmd/mgroup_address:mgroup_port/ 73 | http://ip:port/cmd/mgroup_address%mgroup_port/ 74 | http://ip:port/cmd/mgroup_address~mgroup_port/ 75 | ...... 76 | http://ip:port/cmd/mgroup_address^mgroup_port/ 77 | 78 | принимаются и должны выполняться одинаково. 79 | 80 | cmd ::= udp | rtp 81 | 82 | ip и port соответствуют адресу и порту, на котором udpxy принимает команды, 83 | а mgroup_address:mgroup_port указывают на мультикаст группу для подписки. 84 | 85 | Использование команды 'udp' приведёт к тестированию полученных данных на 86 | известные приложению типы видеоинформации ("чистый" MPEG-TS и 87 | RTP c MPEG-TS); использование команды 'rtp' однозначно укажет udpxy 88 | на RTP c MPEG-TS и отменит тестирование. 89 | 90 | udpxy запускает 'процесс-клиент' для работы с каждым новым запросом на 91 | перенаправление сетевого потока, количество одновременно запущенных потоков 92 | ограничивается соответствующим параметром (см. краткое руководство к 93 | использованию). 94 | 95 | udpxy также поддерживает несколько дополнительных HTTP запросов, таких как: 96 | 97 | http://address:port/status/ - вывести статус программы и статистику 98 | http://address:port/restart/ - закрыть все текущие соединения и перезапустить программу 99 | 100 | Типы видеопотоков и работа с ними 101 | -------------- 102 | 103 | udpxy способно распознать видеопотоки MPEG-TS и RTP с MPEG-TS в перенаправляемых пакетах; 104 | если udpxy получает видеопоток RTP, он автоматически 'переводится' в MPEG-TS, чтобы дать 105 | возможность вопспоизвести видео плеерам, не работающим с RTP потоком по протоколу TCP. 106 | 107 | Пока что трансляция или транскодирование иных типов потоков не производится. 108 | 109 | Запись MPEG потока в файл 110 | -------------- 111 | udpxy (в сборках после 0.33) предусматривает возможность записи обрабатываемого 112 | потока в виде "чистого" MPEG-TS в файл. Данная функциональность предоставляется 113 | посредством включённого в дистрибутив приложения udpxrec, вызываемого через 114 | ссылку на udpxy (т.к. оба приложения содержатся в едином бинарном файле udpxy). 115 | 116 | udpxrec вызывается через символьную ссылку (названную udpxrec) на исполняемый 117 | файл udpxy. (NB: не переименовывайте исполняемый файл udpxy.) 118 | 119 | udpxrec создаёт MPEG файлы, содержащие в себе записи MPEG-TS потока; большинство 120 | медиа-плееров (в 2008 году) не могли проигрывать подобные файлы. Файлы 121 | MPEG-TS могут быть сконвертированы в (знакомый всем плеерам) формат MPEG-PS 122 | при помощи следующей команды плеера vlc (который проигрывает и MPEG-TS, и PS): 123 | 124 | vlc input-ts.mpg --sout="#std{access=file,mux=ps,dst=out-ps.mpg}" 125 | 126 | Полученный в результате файл MPEG-PS проигрывается большинством медиа-плееров. 127 | 128 | Портируемость 129 | -------------- 130 | 131 | udpxy был написан для работы на POSIX-совместимых системах. 132 | На сей день (практически) все сборки должны собираться и работать на Linux 133 | версий 2.4, 2.6 и 3.х (x86, amd64, ARM). Не все *старые* сборки были протестированы 134 | на новых версиях Linux, обратное так же верно. 135 | 136 | Отдельные (старые, т.е. до версии 1.0) сборки были протестированы на HP-UX 11.11 137 | (PA-RISC 1.1, 2.0w). 138 | 139 | Для новых версий udpxy активно поддерживаются ОС Linux и FreeBSD (до версии 9.0). 140 | Сообщество FreeBSD также поддерживает официальный порт udpxy, загружаемый 141 | через систему портов FreeBSD. 142 | 143 | Отдельно, вне этого проекта, существует порт udpxy под cуgwin. Этот порт 144 | поддерживает и распространяет через свой сайт Алексей Сухинин 145 | (пользователь Alexey S на udpxy.com/forum). 146 | 147 | Переменные среды как параметры 148 | -------------- 149 | udpxy использует следующие переменные среды для дополнения 150 | своего набора опций командной строки; данные переменные 151 | прелагаются для тех опций, кои не слишком часто изменяются 152 | пользователем (или которые просто неудобно указывать из 153 | командной строки). 154 | 155 | NB: Если какой-либо параметр командной строки пересекается в функционалиности с 156 | переменной среды, то параметр всегда будет иметь больший приоритет. 157 | 158 | 159 | UDPXY_RCV_TMOUT - тайм-аут (секунд) на чтение входящего (мультикаст) потока, по умолчанию=5; 160 | UDPXY_DHOLD_TMOUT - тайм-аут (секунд) на буферизацию потока перед отправкой клиент(у,ам), по умолчанию=1; 161 | UDPXY_SREAD_TMOUT - тайм-аут (секунд) на чтение из пассивного сокета (обработка HTTP запросов), по умолчанию=1; 162 | UDPXY_SWRITE_TMOUT - тайм-аут (секунд) на запись в пассивный сокет (обработка HTTP запросов), по умолчанию=1; 163 | UDPXY_SSEL_TMOUT - тайм-аут (секунд) на select(2) в основном цикле сервера (не задействован при использовании pselect(2)), по умолчанию=30; 164 | UDPXY_LQ_BACKLOG - размер очереди соединений серверного сокета, по умолчанию=16; 165 | UDPXY_SRV_RLWMARK - размер нижнего порога (low watermark) on на сокете входящих (мультакаст) данных, по умолчанию=0 (не устанавливается); 166 | UDPXY_SSOCKBUF_NOSYNC - не синхронизировать размер буфера (UDP) сокета со значением параметра -B, по умолчанию=1 (синхронизировать); 167 | UDPXY_DSOCKBUF_NOSYNC - не синхронизировать размер буфера (TCP) сокета со значением параметра -B, по умолчанию=1 (синхронизировать); 168 | 169 | UDPXY_TCP_NODELAY - отключать алгоритм Нэйгла (Nagle algorithm) на новопринятых сокетах (ускоряет переключение каналов), по умолчанию=1; 170 | 171 | UDPXY_HTTP200_FTR_FILE - добавить содержимое данного (текстового) файла к ответу HTTP 200 сервера, по умолчанию=none; 172 | UDPXY_HTTP200_FTR_LN - добавить тектовую строку к ответу HTTP 200 сервера, по умолчанию=none; 173 | 174 | UDPXY_ALLOW_PAUSES - В случае блокирования на write(2), продолжать читать данные до заполнения буфера (размер устанавливается параметром -B), по умолчанию=disabled; 175 | UDPXY_PAUSE_MSEC - ограничить время чтения данных в N миллисекунд в случае блокирования на write(2). 176 | UDPXY_CONTENT_TYPE - использовать данное значение HTTP поля Content-Type в ответе на HTTP запросы. 177 | 178 | # --EOF-- 179 | 180 | -------------------------------------------------------------------------------- /jni/udpxy/CHANGES: -------------------------------------------------------------------------------- 1 | # @(#) list changes to udpxy from build to build 2 | # 3 | # Copyright 2008-2012 Pavel V. Cherenkov (pcherenkov@gmail.com) 4 | # 5 | # This file is part of udpxy. 6 | # 7 | # udpxy is free software: you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation, either version 3 of the License, or 10 | # (at your option) any later version. 11 | # 12 | # udpxy is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | # GNU General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License 18 | # along with udpxy. If not, see . 19 | # 20 | 21 | Build 14 (2-Jan-2008): 22 | (*) shutdown command removed 23 | 24 | Build 15-18 (7-Jan-2008): 25 | (*) interface names get translated into IPv4 addresses 26 | (*) lock-enabled pidfile support added 27 | 28 | Build 19 (9-Jan-2008): 29 | (*) 'lean' target added to makefile 30 | (*) -n (nice increment) option added 31 | 32 | Build 20 (9-Jan-2008): 33 | (*) default settings changed for various options 34 | 35 | Build 21-22 (16-Jan-2008): 36 | (*) Web GUI refinements (new design, 'restart' button added to status page) 37 | (*) mipsel-linux-uclibc-gcc support added to wl500-specific makefile 38 | (*) generation of wl500-specific source archive 39 | 40 | Build 23 (18-Jan-2008): 41 | (*) Usage examples added to status page and command-line output 42 | (*) Copyright notice added to status page and usage 43 | (*) make for wl500 will not strip; no default compiler given 44 | 45 | Build 24-30 (27-Feb-2008) 46 | (*) support for RTP over MPEG-TS added 47 | 48 | Build 31 (28-Feb-2008) 49 | (*) bug-fix: lean target compile error corrected 50 | (*) release target for wl500 will not strip the executable 51 | 52 | Build 32 (29-Feb-2008) 53 | (*) throughput statistics displayed on status page 54 | (*) log messages are timestamp-prepended now 55 | 56 | Build 33 (23-Mar-2008) 57 | (*) udpxrec application added to record traffic into file 58 | (*) miliseconds added to log timestamps 59 | 60 | Build 34 (23-Mar-2008) 61 | (*) Bug fix: core dumped if no pidfile specified 62 | 63 | Build 35 (24-Mar-2008) 64 | (*) Bug fix: udpxy terminates with unlink error when run as a daemon 65 | 66 | Build 36 (25-Mar-2008) 67 | (*) Bug fix: udpxrec: specifying a small buffer (-B) produces assert or SEGV 68 | (*) Bug fix: udpxrec: start/end-recording can be in the past 69 | (*) udpxy made accept buffer in bytes by default (was in Kb) 70 | (*) udpxrec will run as daemon if started under root 71 | (*) Bug fix: udpxy, udpxrec will not run in bkg w/o log spec 72 | (*) udpxrec will require pidfile to run as daemon (root in bkg) 73 | 74 | Build 37 (27-Mar-2008) 75 | (*) bug fixes - maintenance build 76 | 77 | Build 38 (11-Apr-2008) 78 | (*) -H parameter added to set max time data can be held in buffer 79 | (*) socket read timeout is configurable through $UDPXY_RCV_TMOUT (env) 80 | (*) migrated to unified makefile for all supported compilers 81 | (*) added dependency-generation support thru mkdep 82 | (*) support added for suncc (Sun Studio 12), icc (Intel C), HP ANSI C compiler (hppa20w, hppa20, hppa11 modes) 83 | 84 | Build 39 (21-May-2008) 85 | (*) resolved issue of WMP refusing to connect to udpxy 86 | (*) added pid to log output 87 | 88 | Version 1.0 'Chipmunk' 89 | -------------------------- 90 | 91 | Build 1 (4-June-2008) 92 | (*) same as Build 39 93 | 94 | Build 2 (6-June-2008) 95 | (*) Rolled back WMP-compatibility changes 96 | 97 | Build 6 (12-August-2008) 98 | (*) Fixed: udpxrec would not write beyond 2Gb; -M option would not accept >2Gb of size 99 | 100 | Build 7 (20-September-2008) 101 | (*) Fixed: multicast-resubscribe default period of zero seconds would cause udpxy to resubscribe 102 | on every iteration; logic changed to make udpxy re-subscribe only on setting's value >0 103 | (0 means 'do NOT' re-subscribe) 104 | 105 | Build 8 (3-December-2008) 106 | (*) SIGPIPE is ignored now (was handled as a signal to quit) 107 | (*) Full version info is displayed on exit 108 | (*) PAUSE support (non-blocking receive socket) can be disabled 109 | (*) DHOLD_TIMEOUT (default max time to buffer data before flush) set to 4 seconds 110 | 111 | Build 9 (17-February-2009) 112 | (*) documentation (in Russian) added 113 | (*) default buffer size changed to 4K, was 64K 114 | (*) minimal send-socket buffer length set to 32K (was previously set to data buffer size) 115 | (*) UDPXY_SENDBUF_LEN environment variable can be set to control send-socket buffer size 116 | 117 | Build 10 (24-February-2009) 118 | (*) read-socket buffer left untouched if bigger than suggested buffer value based on -R 119 | and -B parameters and the minimum buffer size - currently 32K - for send socket 120 | (*) UDPXY_SENDBUF_LEN replaced by UDPXREC_SOCKBUF_LEN: that will be the minimum size 121 | for both read- and send-socket buffers (ignored still if set to less than 32K) 122 | (*) send-socket buffer size will be enlarged to the size of read-socket bufffer size 123 | (if currently smaller) 124 | 125 | Build 11 (25-February-2009) 126 | (*) UDPXY_DSOCKBUF_NOSYNC set to 1 will leave send-socket buffer size unaltered 127 | (*) UDPXY_SSOCKBUF_NOSYNC set to 1 will leave read (mcast)-socket buffer size unaltered 128 | (*) default buffer size (-B) changed to 2K, was 4K 129 | (*) default value for -R (messages to buffer) set to 1 130 | (*) minimum (advisory) socket buffer size set to 64K, was 32K 131 | (*) Fixed: assert when processing RTP-TS with -R 1 132 | (*) Fixed: if2addr() not working under 64-bit linux; -a and -m options would not accept ifc names 133 | (*) Fixed: quit flag value cast incorrectly under 64-bit linux 134 | (*) CFLAGS variable may used for additional compiler options (CFLAGS='-m32' will force 32-bit build, for instance) 135 | (*) NOP statements in udpxy.c, udpxrec.c updated to compile w/o warnings under gcc 3.2.3 136 | (*) util/mkipk.sh script added to create IPKG packages 137 | 138 | Build 12 (9-April-2009) 139 | (*) ported to compile under FreeBSD 7.1 (32-bit) 140 | 141 | Build 13 (10-April-2009) 142 | (*) signedness comparison warnings eliminated 143 | 144 | Build 14 (23-Jul-2009) 145 | (*) ported to compile under FreeBSD 5.5 (32-bit) 146 | 147 | Build 15 (XX-Mar-2010) 148 | (*) FIXED: not compiling with -O2/O3 flags under gcc (select additional options in USER_OPT env variable) 149 | (*) FIXED: would not allow running more than one udpxy daemon 150 | 151 | Build 16 (21-Mar-2010) 152 | (*) FIXED: hanging when specifying network interface by name 153 | 154 | Build 17 (27-Jun-2010) 155 | (*) FIXED: server terminates on ECONNABORTED from accept() 156 | (*) Dynamic memory allocation for HTTP status pages implemented - will not truncate pages 157 | 158 | Build 18 (9-Jan-2011) 159 | (*) IP/port separator in HTTP request to udpxy can be any of those: ":%~+-^" 160 | 161 | Build 19 (9-Jan-2011) 162 | (*) MAX limit of clients (-c option) upped to 5,000 (five thousand) 163 | 164 | Build 20 (18-Jun-2011) 165 | (*) FIXED: player sends last request's traffic to any client with invalid request; 166 | (*) FIXED: unsupported HTTP requests (those that the parser does not handle) are denied [ID: 3294265] 167 | 168 | (*) Added UDPXY_SREAD_TMOUT, UDPXY_SWRITE_TMOUT evn parameters to set read/write timeouts on HTTP server's socket; 169 | (*) Added UDPXY_HTTP200_FTR_LN, UDPXY_HTTP200_FTR_FILE env parameters to allow appending 1 line or contents 170 | of a text file to HTTP 200 (successful request processing) response; 171 | (*) Added Content-type entry to HTTP response; 172 | (*) Added conditional compilation of udpxrec - use NO_UDPXREC=yes make [mode] to *NOT* build udpxrec into the udpxy 173 | binary 174 | 175 | Build 21 (25-Nov-2011) 176 | (*) FIXED: defunct processes appear at a high volume of requests; 177 | (*) FIXED: ECONNRESET, ECONNABORTED and EPROTO in accept cause server to exit prematurely; 178 | (*) FIXED: accept() handled only one request per iteration (select notification); 179 | (*) Low watermark enforced for incoming requests; 180 | 181 | Patch 1 (13-Dec-2011) 182 | (*) FIXED: "variable set but not used" warnings under gcc 4.6.1 183 | (*) FIXED: conflict with dirent.h (DT_UNKNOWN) resolved; 184 | 185 | Patch 2 (20-Dec-2011) 186 | (*) FIXED: misc build errors and inconsistencies 187 | 188 | Patch 4 (9-Feb-2012) 189 | (*) FIXED: SIGSEGV caused by dpkt.c:upxfmt_NAME[] having less members than indexes used (RAW was missing); 190 | (*) rdebug (release with debug symbols), ldebug (lean with debug symbols) targets added; 191 | 192 | Build 22 was skipped to avoid confusion with patches and betas pulled off github; 193 | 194 | Build 23 (3-Jul-2012) 195 | (*) HTTP response lines are now separated by CRLF (not just LF), as per RFC2616; 196 | (*) SO_REUSEPORT used (where available) to allow more that one client 197 | to subscribe to the same channel on BSD-derived systems; 198 | (*) optimization patches by Alexey Suhinin integrated (tcp_nodelay, pause_timeout, mstream_type); 199 | (*) sloop.c uses syscall.h & -DUSE_SELECT to alternate between select(2)- and pselect(2)-based implementations of server loop 200 | (*) FIXED: idle timeout displayed incorrectly in select(2)-based version; 201 | (*) HTTP response includes 'Server:' clause; 202 | 203 | Patch 1 (31-Aug-2012) 204 | (*) Added the capability to capture the HTTP variables submitted via URI beyond command/options 205 | Example: http://hostname:port/udp/mcaddr:mcport?aa=1&bb=2&cc=3 - '?aa=1&bb=2&cc=3' part is now 206 | preserved (for each client) and displayed in status page as part of Destination column; 207 | (*) Added README.russian; 208 | 209 | Patch 2 (14-Oct-2012) 210 | (*) Static linking enabled through LDFLAGS=-static (as a prefix to make); 211 | (*) EPIPE and other 'not really errors' should not go to syslog (time-outs still WILL); 212 | 213 | Patch 3 (18-Nov-2012) 214 | (*) Makefile changed towards better GNU compatibility: added $PREFIX, $DESTDIR, $CPPFLAGS; dist & install-strip targets; 215 | (*) English-language udpxy.1, udpxrec.1 man pages added; 216 | (*) icc, Sun C & HP-UX C compiler support dropped (Makefile); 217 | 218 | Patch 4 (9-Dec-2012) 219 | (*) manpage & Makefile corrections applied (integrated patches from Alex Z (ad_user)); 220 | Patch 5 (13-Dec-2012) 221 | (*) Makefile corrections (purged deprecated options & variables); 222 | Patch 6 (23-Dec-2012) 223 | (*) report_status() adjusts report-buffer size for client tails; 224 | (*) attempt to fix strict-aliasing compiler warnings in sock_info(); 225 | (*) optimizing: removed difftime() as redundant on a POSIX system (may affect non-POSIX ports). 226 | Patch 7 (24-Dec-2012) 227 | (*) more work on report_status() to prevent memory exhaustion when using 'tails' in requests; 228 | Patch 8 (5-Jan-2013) 229 | (*) UDPXY_CONTENT_TYPE - can specify custom HTTP Content-Type. 230 | (*) FIXED: more memory for report header & items; 231 | (*) Socket is made (temporarily) blocking when sending report results; 232 | 233 | # __EOF__ 234 | 235 | -------------------------------------------------------------------------------- /jni/udpxy/ctx.c: -------------------------------------------------------------------------------- 1 | /* @(#) client/server context implementation 2 | * 3 | * Copyright 2008-2011 Pavel V. Cherenkov (pcherenkov@gmail.com) 4 | * 5 | * This file is part of udpxy. 6 | * 7 | * udpxy is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * udpxy is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with udpxy. If not, see . 19 | */ 20 | 21 | #include "osdef.h" /* os-specific definitions */ 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | 39 | #include "ctx.h" 40 | #include "udpxy.h" 41 | #include "util.h" 42 | #include "mtrace.h" 43 | 44 | extern FILE* g_flog; 45 | extern const char IPv4_ALL[]; 46 | 47 | /* initialize server context data 48 | */ 49 | int 50 | init_server_ctx( struct server_ctx* ctx, 51 | const size_t max, 52 | const char* laddr, uint16_t lport, 53 | const char* mifc_addr ) 54 | { 55 | int flags = -1; 56 | 57 | assert( lport && mifc_addr && ctx && max ); 58 | 59 | ctx->lsockfd = 0; 60 | (void) strncpy( ctx->listen_addr, (laddr ? laddr : IPv4_ALL), 61 | IPADDR_STR_SIZE ); 62 | ctx->listen_addr[ IPADDR_STR_SIZE - 1 ] = '\0'; 63 | 64 | ctx->listen_port = lport; 65 | 66 | (void) strncpy( ctx->mcast_ifc_addr, mifc_addr, IPADDR_STR_SIZE ); 67 | ctx->mcast_ifc_addr[ IPADDR_STR_SIZE - 1 ] = '\0'; 68 | 69 | ctx->cl = calloc(max, sizeof(struct client_ctx)); 70 | if( NULL == ctx->cl ) { 71 | mperror( g_flog, errno, "%s: client_t - calloc", __func__ ); 72 | return ERR_INTERNAL; 73 | } 74 | 75 | (void) memset( ctx->cl, 0, max * sizeof(struct client_ctx) ); 76 | ctx->clfree = ctx->clmax = max; 77 | 78 | (void) memset( &ctx->rq, 0, sizeof(ctx->rq) ); 79 | 80 | if( 0 != pipe(ctx->cpipe) ) { 81 | mperror( g_flog, errno, "%s: pipe", __func__ ); 82 | return ERR_INTERNAL; 83 | } 84 | 85 | /* make reading end of pipe non-blocking (we don't want to 86 | * block on pipe read on the server side) 87 | */ 88 | if( -1 == (flags = fcntl( ctx->cpipe[0], F_GETFL )) || 89 | -1 == fcntl( ctx->cpipe[0], F_SETFL, flags | O_NONBLOCK ) ) { 90 | mperror( g_flog, errno, "%s: fcntl", __func__ ); 91 | return ERR_INTERNAL; 92 | } 93 | 94 | return 0; 95 | } 96 | 97 | 98 | void 99 | free_server_ctx( struct server_ctx* ctx ) 100 | { 101 | int i = -1; 102 | 103 | assert(ctx); 104 | free( ctx->cl ); 105 | 106 | for( i = 0; i < 2; ++i ) { 107 | if( ctx->cpipe[i] < 0 ) continue; 108 | 109 | if( 0 != close( ctx->cpipe[i] ) ) { 110 | mperror( g_flog, errno, 111 | "%s: close(pipe)", __func__ ); 112 | } 113 | } 114 | 115 | (void) memset( ctx, 0, sizeof(struct server_ctx) ); 116 | return; 117 | } 118 | 119 | 120 | /* find index of the first client with the given pid 121 | */ 122 | int 123 | find_client( const struct server_ctx* ctx, pid_t pid ) 124 | { 125 | int i = -1; 126 | 127 | assert( ctx && (pid >= 0) ); 128 | 129 | for( i = 0; (size_t)i < ctx->clmax; ++i ) { 130 | if( ctx->cl[ i ].pid == pid ) 131 | return i; 132 | } 133 | 134 | return -1; 135 | } 136 | 137 | /* populate connection's source info in client context 138 | */ 139 | static int 140 | get_src_info( struct client_ctx* cl, int sockfd ) 141 | { 142 | struct stat st; 143 | struct sockaddr_in addr; 144 | a_socklen_t len = 0; 145 | int rc = 0; 146 | 147 | assert( cl ); 148 | if( -1 == (rc = fstat( sockfd, &st )) ) { 149 | mperror( g_flog, errno, "%s: fstat", __func__ ); 150 | return ERR_INTERNAL; 151 | } 152 | 153 | if( S_ISREG( st.st_mode ) ) { 154 | (void) strncpy( cl->src_addr, "File", sizeof(cl->src_addr) ); 155 | cl->src_addr[ sizeof(cl->src_addr) - 1 ] = '\0'; 156 | cl->src_port = 0; 157 | } 158 | else if( S_ISSOCK( st.st_mode ) ) { 159 | len = sizeof(addr); 160 | rc = getpeername( sockfd, (struct sockaddr*)&addr, &len ); 161 | if( 0 == rc ) { 162 | (void)strncpy( cl->src_addr, inet_ntoa(addr.sin_addr), 163 | sizeof(cl->src_addr) - 1 ); 164 | cl->src_addr[ sizeof(cl->src_addr) - 1 ] = '\0'; 165 | 166 | cl->src_port = ntohs(addr.sin_port); 167 | } 168 | else { 169 | mperror( g_flog, errno, "%s: getpeername", __func__ ); 170 | return ERR_INTERNAL; 171 | } 172 | } /* S_ISSOCK */ 173 | 174 | return rc; 175 | } 176 | 177 | 178 | /* add client to server context 179 | */ 180 | int 181 | add_client( struct server_ctx* ctx, 182 | pid_t cpid, const char* maddr, uint16_t mport, 183 | int sockfd ) 184 | { 185 | struct client_ctx* client = NULL; 186 | int index = -1; 187 | int rc = 0; 188 | 189 | assert( ctx && maddr && mport ); 190 | 191 | index = find_client( ctx, 0 ); 192 | if( -1 == index ) 193 | return ERR_INTERNAL; 194 | 195 | client = &(ctx->cl[ index ]); 196 | client->pid = cpid; 197 | 198 | (void) strncpy( client->mcast_addr, maddr, IPADDR_STR_SIZE ); 199 | client->mcast_addr[ IPADDR_STR_SIZE - 1 ] = '\0'; 200 | 201 | client->mcast_port = mport; 202 | 203 | if (ctx->rq.tail[0]) 204 | (void) strcpy( client->tail, ctx->rq.tail ); 205 | 206 | rc = get_src_info( client, sockfd ); 207 | if( 0 != rc ) { 208 | client->pid = 0; 209 | return ERR_INTERNAL; 210 | } 211 | 212 | /* init sender id: 0 indicates no stats */ 213 | client->tstat.sender_id = 0; 214 | 215 | ctx->clfree--; 216 | 217 | if( g_flog ) { 218 | (void)tmfprintf( g_flog, "Added client: pid=[%d], maddr=[%s], mport=[%d], " 219 | "saddr=[%s], sport=[%d]\n", 220 | (int)cpid, maddr, (int)mport, client->src_addr, client->src_port ); 221 | } 222 | return 0; 223 | } 224 | 225 | 226 | /* delete client from server context 227 | */ 228 | int 229 | delete_client( struct server_ctx* ctx, pid_t cpid ) 230 | { 231 | struct client_ctx* client = NULL; 232 | int index = -1; 233 | 234 | assert( ctx && (cpid > 0) ); 235 | 236 | index = find_client( ctx, cpid ); 237 | if( -1 == index ) { 238 | return ERR_INTERNAL; 239 | } 240 | 241 | client = &(ctx->cl[ index ]); 242 | client->pid = 0; 243 | client->tail[0] = '\0'; 244 | 245 | ctx->clfree++; 246 | 247 | if( g_flog ) { 248 | TRACE( (void)tmfprintf( g_flog, "Deleted client: pid=[%d]\n", cpid) ); 249 | } 250 | 251 | return 0; 252 | } 253 | 254 | 255 | /* init traffic relay statistics 256 | */ 257 | void 258 | tpstat_init( struct tps_data* d, int setpid ) 259 | { 260 | assert( d ); 261 | 262 | if( setpid ) 263 | d->pid = getpid(); 264 | 265 | d->tm_from = time(NULL); 266 | d->niter = 0; 267 | d->nbytes = 0; 268 | 269 | return; 270 | } 271 | 272 | 273 | /* send statistics update to server (if it's time) 274 | */ 275 | void 276 | tpstat_update( struct server_ctx* ctx, 277 | struct tps_data* d, ssize_t nbytes ) 278 | { 279 | static const double MAX_NOUPDATE_ITER = 1000.0; 280 | static const double MAX_SEC = 10.0; 281 | 282 | struct tput_stat ts; 283 | int writefd = -1, rc = 0; 284 | const int DO_NOT_SET_PID = 0; 285 | ssize_t nwr = -1; 286 | double nsec; 287 | 288 | assert( ctx && d ); 289 | 290 | d->nbytes += nbytes; 291 | 292 | nsec = difftime( time(NULL), d->tm_from ); 293 | d->niter++; 294 | if( !((d->niter >= MAX_NOUPDATE_ITER) || (nsec >= MAX_SEC)) ) 295 | return; 296 | 297 | /* attempt to send update to server */ 298 | d->niter = 0; 299 | 300 | ts.sender_id = d->pid; 301 | ts.nbytes = d->nbytes; 302 | ts.nsec = nsec; 303 | 304 | writefd = ctx->cpipe[1]; 305 | do { 306 | nwr = write( writefd, &ts, sizeof(ts) ); 307 | if( nwr <= 0 ) { 308 | if( (EINTR != errno) && (EAGAIN != errno) ) { 309 | mperror( g_flog, errno, "%s: write", __func__ ); 310 | rc = -1; 311 | break; 312 | } 313 | /* if it's an interrupt or pipe full - ignore */ 314 | TRACE( (void)tmfprintf( g_flog, "%s - write error [%s] - ignored\n", 315 | __func__, strerror(errno)) ); 316 | break; 317 | } 318 | if( sizeof(ts) != (size_t)nwr ) { 319 | (void)tmfprintf( g_flog, "%s - wrote [%d] bytes to pipe, " 320 | "expected [%u]\n", 321 | __func__, nwr, (int)sizeof(ts) ); 322 | rc = -1; 323 | break; 324 | } 325 | 326 | /* 327 | TRACE( (void)tmfprintf( g_flog, 328 | "Sent TSTAT={ sender=[%ld], bytes=[%f], seconds=[%f] }\n", 329 | (long)ts.sender_id, ts.nbytes, ts.nsec) ); 330 | */ 331 | } while(0); 332 | 333 | 334 | if( 0 == rc ) { 335 | tpstat_init( d, DO_NOT_SET_PID ); 336 | } 337 | 338 | return; 339 | } 340 | 341 | 342 | /* read client statistics data and update the context 343 | */ 344 | int 345 | tpstat_read( struct server_ctx* ctx ) 346 | { 347 | int cindex = -1; 348 | int readfd = -1; 349 | ssize_t nread = 0; 350 | struct tput_stat ts; 351 | struct client_ctx* client = NULL; 352 | 353 | assert( ctx ); 354 | 355 | readfd = ctx->cpipe[0]; 356 | assert( readfd > 0 ); 357 | 358 | (void)memset( &ts, 0, sizeof(ts) ); 359 | 360 | nread = read( readfd, &ts, sizeof(ts) ); 361 | if( nread <= 0 ) { 362 | if( (EINTR != errno) && (EAGAIN != errno) ) { 363 | mperror( g_flog, errno, "%s: read", __func__ ); 364 | return ERR_INTERNAL; 365 | } 366 | /* if it's an interrupt or no data available - ignore */ 367 | TRACE( (void)tmfprintf( g_flog, "%s - read error [%s] - ingored\n", 368 | __func__, strerror(errno)) ); 369 | return 0; 370 | } 371 | if( sizeof(ts) != (size_t)nread ) { 372 | (void)tmfprintf( g_flog, "%s - read [%d] bytes from pipe, expected [%u]\n", 373 | __func__, nread, (int)sizeof(ts) ); 374 | return ERR_INTERNAL; 375 | } 376 | 377 | TRACE( (void)tmfprintf( g_flog, 378 | "Received TSTAT={ sender=[%ld], bytes=[%f], seconds=[%f] }\n", 379 | (long)ts.sender_id, ts.nbytes, ts.nsec) ); 380 | 381 | cindex = find_client( ctx, (pid_t)ts.sender_id ); 382 | if( -1 == cindex ) { 383 | (void)tmfprintf( g_flog, "%s - cannot find client [%ld]\n", 384 | __func__, (long)ts.sender_id ); 385 | /* ignore invalid client id's */ 386 | return 0; 387 | } 388 | 389 | client = &(ctx->cl[ cindex ]); 390 | client->tstat = ts; 391 | 392 | TRACE( (void)tmfprintf( g_flog, "Updated context for pid=[%d]; " 393 | "[%.1f] Kb/sec\n", client->pid, (ts.nbytes / 1024) / ts.nsec ) ); 394 | return 0; 395 | } 396 | 397 | 398 | 399 | /* __EOF__ */ 400 | 401 | --------------------------------------------------------------------------------