├── .gitignore ├── AUTHORS ├── COPYING ├── ChangeLog ├── INSTALL ├── Makefile.am ├── NEWS ├── README ├── README.md ├── configure.ac ├── rtp2httpd.conf └── src ├── Makefile.am ├── configuration.c ├── httpclients.c ├── rtp2httpd.c └── rtp2httpd.h /.gitignore: -------------------------------------------------------------------------------- 1 | Makefile 2 | rtp2httpd 3 | *.o 4 | *.in 5 | config.* 6 | stamp-h1 7 | .deps 8 | autom4te.cache 9 | aclocal.m4 10 | compile 11 | configure 12 | depcomp 13 | install-sh 14 | missing 15 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Written by: 2 | Ondrej Caletka 3 | 4 | MUDP Support by: 5 | Richard Golier 6 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc. 5 | 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Library General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License 307 | along with this program; if not, write to the Free Software 308 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 309 | 310 | 311 | Also add information on how to contact you by electronic and paper mail. 312 | 313 | If the program is interactive, make it output a short notice like this 314 | when it starts in an interactive mode: 315 | 316 | Gnomovision version 69, Copyright (C) year name of author 317 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 318 | This is free software, and you are welcome to redistribute it 319 | under certain conditions; type `show c' for details. 320 | 321 | The hypothetical commands `show w' and `show c' should show the appropriate 322 | parts of the General Public License. Of course, the commands you use may 323 | be called something other than `show w' and `show c'; they could even be 324 | mouse-clicks or menu items--whatever suits your program. 325 | 326 | You should also get your employer (if you work as a programmer) or your 327 | school, if any, to sign a "copyright disclaimer" for the program, if 328 | necessary. Here is a sample; alter the names: 329 | 330 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 331 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 332 | 333 | , 1 April 1989 334 | Ty Coon, President of Vice 335 | 336 | This General Public License does not permit incorporating your program into 337 | proprietary programs. If your program is a subroutine library, you may 338 | consider it more useful to permit linking proprietary applications with the 339 | library. If this is what you want to do, use the GNU Library General 340 | Public License instead of this License. 341 | -------------------------------------------------------------------------------- /ChangeLog: -------------------------------------------------------------------------------- 1 | 2010-05-26 16:00 Ondrej Caletka 2 | Version 0.4 3 | Fixed zombie processes creation when more than one 4 | client disconnects in a short period of time. 5 | Fix by David Seidl 6 | 7 | 2009-04-05 23:30 Ondrej Caletka 8 | Version 0.3 9 | Added support for RAW UDP (MUDP) streams by 10 | Richard Golier 11 | 12 | 2009-01-16 10:00 Ondrej Caletka 13 | Version 0.2b 14 | Fixed reporting errors od getaddrinfo(); 15 | 16 | 2009-01-08 16:00 Ondrej Caletka 17 | Version 0.2a 18 | Fixed fatal error in writeToClient(); 19 | 20 | 2009-01-08 11:00 Ondrej Caletka 21 | Version 0.2 22 | Added -D option to force not to daemonise. 23 | Changed configfile read order so configfile is 24 | parsed before parsing command-line args. 25 | 26 | 2009-01-07 23:00 Ondrej Caletka 27 | Fixes address in use when two clients wants same 28 | source mRTP stream. 29 | 30 | 2009-01-07 17:20 Ondrej Caletka 31 | Initial release. 32 | -------------------------------------------------------------------------------- /INSTALL: -------------------------------------------------------------------------------- 1 | Installation Instructions 2 | ************************* 3 | 4 | Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005, 5 | 2006, 2007, 2008, 2009 Free Software Foundation, Inc. 6 | 7 | Copying and distribution of this file, with or without modification, 8 | are permitted in any medium without royalty provided the copyright 9 | notice and this notice are preserved. This file is offered as-is, 10 | without warranty of any kind. 11 | 12 | Basic Installation 13 | ================== 14 | 15 | Briefly, the shell commands `./configure; make; make install' should 16 | configure, build, and install this package. The following 17 | more-detailed instructions are generic; see the `README' file for 18 | instructions specific to this package. Some packages provide this 19 | `INSTALL' file but do not implement all of the features documented 20 | below. The lack of an optional feature in a given package is not 21 | necessarily a bug. More recommendations for GNU packages can be found 22 | in *note Makefile Conventions: (standards)Makefile Conventions. 23 | 24 | The `configure' shell script attempts to guess correct values for 25 | various system-dependent variables used during compilation. It uses 26 | those values to create a `Makefile' in each directory of the package. 27 | It may also create one or more `.h' files containing system-dependent 28 | definitions. Finally, it creates a shell script `config.status' that 29 | you can run in the future to recreate the current configuration, and a 30 | file `config.log' containing compiler output (useful mainly for 31 | debugging `configure'). 32 | 33 | It can also use an optional file (typically called `config.cache' 34 | and enabled with `--cache-file=config.cache' or simply `-C') that saves 35 | the results of its tests to speed up reconfiguring. Caching is 36 | disabled by default to prevent problems with accidental use of stale 37 | cache files. 38 | 39 | If you need to do unusual things to compile the package, please try 40 | to figure out how `configure' could check whether to do them, and mail 41 | diffs or instructions to the address given in the `README' so they can 42 | be considered for the next release. If you are using the cache, and at 43 | some point `config.cache' contains results you don't want to keep, you 44 | may remove or edit it. 45 | 46 | The file `configure.ac' (or `configure.in') is used to create 47 | `configure' by a program called `autoconf'. You need `configure.ac' if 48 | you want to change it or regenerate `configure' using a newer version 49 | of `autoconf'. 50 | 51 | The simplest way to compile this package is: 52 | 53 | 1. `cd' to the directory containing the package's source code and type 54 | `./configure' to configure the package for your system. 55 | 56 | Running `configure' might take a while. While running, it prints 57 | some messages telling which features it is checking for. 58 | 59 | 2. Type `make' to compile the package. 60 | 61 | 3. Optionally, type `make check' to run any self-tests that come with 62 | the package, generally using the just-built uninstalled binaries. 63 | 64 | 4. Type `make install' to install the programs and any data files and 65 | documentation. When installing into a prefix owned by root, it is 66 | recommended that the package be configured and built as a regular 67 | user, and only the `make install' phase executed with root 68 | privileges. 69 | 70 | 5. Optionally, type `make installcheck' to repeat any self-tests, but 71 | this time using the binaries in their final installed location. 72 | This target does not install anything. Running this target as a 73 | regular user, particularly if the prior `make install' required 74 | root privileges, verifies that the installation completed 75 | correctly. 76 | 77 | 6. You can remove the program binaries and object files from the 78 | source code directory by typing `make clean'. To also remove the 79 | files that `configure' created (so you can compile the package for 80 | a different kind of computer), type `make distclean'. There is 81 | also a `make maintainer-clean' target, but that is intended mainly 82 | for the package's developers. If you use it, you may have to get 83 | all sorts of other programs in order to regenerate files that came 84 | with the distribution. 85 | 86 | 7. Often, you can also type `make uninstall' to remove the installed 87 | files again. In practice, not all packages have tested that 88 | uninstallation works correctly, even though it is required by the 89 | GNU Coding Standards. 90 | 91 | 8. Some packages, particularly those that use Automake, provide `make 92 | distcheck', which can by used by developers to test that all other 93 | targets like `make install' and `make uninstall' work correctly. 94 | This target is generally not run by end users. 95 | 96 | Compilers and Options 97 | ===================== 98 | 99 | Some systems require unusual options for compilation or linking that 100 | the `configure' script does not know about. Run `./configure --help' 101 | for details on some of the pertinent environment variables. 102 | 103 | You can give `configure' initial values for configuration parameters 104 | by setting variables in the command line or in the environment. Here 105 | is an example: 106 | 107 | ./configure CC=c99 CFLAGS=-g LIBS=-lposix 108 | 109 | *Note Defining Variables::, for more details. 110 | 111 | Compiling For Multiple Architectures 112 | ==================================== 113 | 114 | You can compile the package for more than one kind of computer at the 115 | same time, by placing the object files for each architecture in their 116 | own directory. To do this, you can use GNU `make'. `cd' to the 117 | directory where you want the object files and executables to go and run 118 | the `configure' script. `configure' automatically checks for the 119 | source code in the directory that `configure' is in and in `..'. This 120 | is known as a "VPATH" build. 121 | 122 | With a non-GNU `make', it is safer to compile the package for one 123 | architecture at a time in the source code directory. After you have 124 | installed the package for one architecture, use `make distclean' before 125 | reconfiguring for another architecture. 126 | 127 | On MacOS X 10.5 and later systems, you can create libraries and 128 | executables that work on multiple system types--known as "fat" or 129 | "universal" binaries--by specifying multiple `-arch' options to the 130 | compiler but only a single `-arch' option to the preprocessor. Like 131 | this: 132 | 133 | ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ 134 | CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ 135 | CPP="gcc -E" CXXCPP="g++ -E" 136 | 137 | This is not guaranteed to produce working output in all cases, you 138 | may have to build one architecture at a time and combine the results 139 | using the `lipo' tool if you have problems. 140 | 141 | Installation Names 142 | ================== 143 | 144 | By default, `make install' installs the package's commands under 145 | `/usr/local/bin', include files under `/usr/local/include', etc. You 146 | can specify an installation prefix other than `/usr/local' by giving 147 | `configure' the option `--prefix=PREFIX', where PREFIX must be an 148 | absolute file name. 149 | 150 | You can specify separate installation prefixes for 151 | architecture-specific files and architecture-independent files. If you 152 | pass the option `--exec-prefix=PREFIX' to `configure', the package uses 153 | PREFIX as the prefix for installing programs and libraries. 154 | Documentation and other data files still use the regular prefix. 155 | 156 | In addition, if you use an unusual directory layout you can give 157 | options like `--bindir=DIR' to specify different values for particular 158 | kinds of files. Run `configure --help' for a list of the directories 159 | you can set and what kinds of files go in them. In general, the 160 | default for these options is expressed in terms of `${prefix}', so that 161 | specifying just `--prefix' will affect all of the other directory 162 | specifications that were not explicitly provided. 163 | 164 | The most portable way to affect installation locations is to pass the 165 | correct locations to `configure'; however, many packages provide one or 166 | both of the following shortcuts of passing variable assignments to the 167 | `make install' command line to change installation locations without 168 | having to reconfigure or recompile. 169 | 170 | The first method involves providing an override variable for each 171 | affected directory. For example, `make install 172 | prefix=/alternate/directory' will choose an alternate location for all 173 | directory configuration variables that were expressed in terms of 174 | `${prefix}'. Any directories that were specified during `configure', 175 | but not in terms of `${prefix}', must each be overridden at install 176 | time for the entire installation to be relocated. The approach of 177 | makefile variable overrides for each directory variable is required by 178 | the GNU Coding Standards, and ideally causes no recompilation. 179 | However, some platforms have known limitations with the semantics of 180 | shared libraries that end up requiring recompilation when using this 181 | method, particularly noticeable in packages that use GNU Libtool. 182 | 183 | The second method involves providing the `DESTDIR' variable. For 184 | example, `make install DESTDIR=/alternate/directory' will prepend 185 | `/alternate/directory' before all installation names. The approach of 186 | `DESTDIR' overrides is not required by the GNU Coding Standards, and 187 | does not work on platforms that have drive letters. On the other hand, 188 | it does better at avoiding recompilation issues, and works well even 189 | when some directory options were not specified in terms of `${prefix}' 190 | at `configure' time. 191 | 192 | Optional Features 193 | ================= 194 | 195 | If the package supports it, you can cause programs to be installed 196 | with an extra prefix or suffix on their names by giving `configure' the 197 | option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. 198 | 199 | Some packages pay attention to `--enable-FEATURE' options to 200 | `configure', where FEATURE indicates an optional part of the package. 201 | They may also pay attention to `--with-PACKAGE' options, where PACKAGE 202 | is something like `gnu-as' or `x' (for the X Window System). The 203 | `README' should mention any `--enable-' and `--with-' options that the 204 | package recognizes. 205 | 206 | For packages that use the X Window System, `configure' can usually 207 | find the X include and library files automatically, but if it doesn't, 208 | you can use the `configure' options `--x-includes=DIR' and 209 | `--x-libraries=DIR' to specify their locations. 210 | 211 | Some packages offer the ability to configure how verbose the 212 | execution of `make' will be. For these packages, running `./configure 213 | --enable-silent-rules' sets the default to minimal output, which can be 214 | overridden with `make V=1'; while running `./configure 215 | --disable-silent-rules' sets the default to verbose, which can be 216 | overridden with `make V=0'. 217 | 218 | Particular systems 219 | ================== 220 | 221 | On HP-UX, the default C compiler is not ANSI C compatible. If GNU 222 | CC is not installed, it is recommended to use the following options in 223 | order to use an ANSI C compiler: 224 | 225 | ./configure CC="cc -Ae -D_XOPEN_SOURCE=500" 226 | 227 | and if that doesn't work, install pre-built binaries of GCC for HP-UX. 228 | 229 | On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot 230 | parse its `' header file. The option `-nodtk' can be used as 231 | a workaround. If GNU CC is not installed, it is therefore recommended 232 | to try 233 | 234 | ./configure CC="cc" 235 | 236 | and if that doesn't work, try 237 | 238 | ./configure CC="cc -nodtk" 239 | 240 | On Solaris, don't put `/usr/ucb' early in your `PATH'. This 241 | directory contains several dysfunctional programs; working variants of 242 | these programs are available in `/usr/bin'. So, if you need `/usr/ucb' 243 | in your `PATH', put it _after_ `/usr/bin'. 244 | 245 | On Haiku, software installed for all users goes in `/boot/common', 246 | not `/usr/local'. It is recommended to use the following options: 247 | 248 | ./configure --prefix=/boot/common 249 | 250 | Specifying the System Type 251 | ========================== 252 | 253 | There may be some features `configure' cannot figure out 254 | automatically, but needs to determine by the type of machine the package 255 | will run on. Usually, assuming the package is built to be run on the 256 | _same_ architectures, `configure' can figure that out, but if it prints 257 | a message saying it cannot guess the machine type, give it the 258 | `--build=TYPE' option. TYPE can either be a short name for the system 259 | type, such as `sun4', or a canonical name which has the form: 260 | 261 | CPU-COMPANY-SYSTEM 262 | 263 | where SYSTEM can have one of these forms: 264 | 265 | OS 266 | KERNEL-OS 267 | 268 | See the file `config.sub' for the possible values of each field. If 269 | `config.sub' isn't included in this package, then this package doesn't 270 | need to know the machine type. 271 | 272 | If you are _building_ compiler tools for cross-compiling, you should 273 | use the option `--target=TYPE' to select the type of system they will 274 | produce code for. 275 | 276 | If you want to _use_ a cross compiler, that generates code for a 277 | platform different from the build platform, you should specify the 278 | "host" platform (i.e., that on which the generated programs will 279 | eventually be run) with `--host=TYPE'. 280 | 281 | Sharing Defaults 282 | ================ 283 | 284 | If you want to set default values for `configure' scripts to share, 285 | you can create a site shell script called `config.site' that gives 286 | default values for variables like `CC', `cache_file', and `prefix'. 287 | `configure' looks for `PREFIX/share/config.site' if it exists, then 288 | `PREFIX/etc/config.site' if it exists. Or, you can set the 289 | `CONFIG_SITE' environment variable to the location of the site script. 290 | A warning: not all `configure' scripts look for a site script. 291 | 292 | Defining Variables 293 | ================== 294 | 295 | Variables not defined in a site shell script can be set in the 296 | environment passed to `configure'. However, some packages may run 297 | configure again during the build, and the customized values of these 298 | variables may be lost. In order to avoid this problem, you should set 299 | them in the `configure' command line, using `VAR=value'. For example: 300 | 301 | ./configure CC=/usr/local2/bin/gcc 302 | 303 | causes the specified `gcc' to be used as the C compiler (unless it is 304 | overridden in the site shell script). 305 | 306 | Unfortunately, this technique does not work for `CONFIG_SHELL' due to 307 | an Autoconf bug. Until the bug is fixed you can use this workaround: 308 | 309 | CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash 310 | 311 | `configure' Invocation 312 | ====================== 313 | 314 | `configure' recognizes the following options to control how it 315 | operates. 316 | 317 | `--help' 318 | `-h' 319 | Print a summary of all of the options to `configure', and exit. 320 | 321 | `--help=short' 322 | `--help=recursive' 323 | Print a summary of the options unique to this package's 324 | `configure', and exit. The `short' variant lists options used 325 | only in the top level, while the `recursive' variant lists options 326 | also present in any nested packages. 327 | 328 | `--version' 329 | `-V' 330 | Print the version of Autoconf used to generate the `configure' 331 | script, and exit. 332 | 333 | `--cache-file=FILE' 334 | Enable the cache: use and save the results of the tests in FILE, 335 | traditionally `config.cache'. FILE defaults to `/dev/null' to 336 | disable caching. 337 | 338 | `--config-cache' 339 | `-C' 340 | Alias for `--cache-file=config.cache'. 341 | 342 | `--quiet' 343 | `--silent' 344 | `-q' 345 | Do not print messages saying which checks are being made. To 346 | suppress all normal output, redirect it to `/dev/null' (any error 347 | messages will still be shown). 348 | 349 | `--srcdir=DIR' 350 | Look for the package's source code in directory DIR. Usually 351 | `configure' can determine that directory automatically. 352 | 353 | `--prefix=DIR' 354 | Use DIR as the installation prefix. *note Installation Names:: 355 | for more details, including other options available for fine-tuning 356 | the installation locations. 357 | 358 | `--no-create' 359 | `-n' 360 | Run the configure checks, but stop before creating any output 361 | files. 362 | 363 | `configure' also accepts some other, not widely useful, options. Run 364 | `configure --help' for more details. 365 | 366 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | SUBDIRS = src 2 | dist_sysconf_DATA = rtp2httpd.conf 3 | -------------------------------------------------------------------------------- /NEWS: -------------------------------------------------------------------------------- 1 | Version 0.4 2 | - Fixed zombie processes creation when more than one 3 | client disconnects in a short period of time. 4 | 5 | Version 0.3 6 | - Support for RAW UDP (MUDP) streams 7 | 8 | Version 0.2 9 | - Fix address in use when two clients wanted same 10 | source mRTP stream. 11 | - Changed configfile and commandline options 12 | resolving order so commandline opts do override 13 | configfile defaults. 14 | 15 | Version 0.1 16 | - Initial release 17 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | Multicast RTP to Unicast HTTP stream convertor 2 | ============================================== 3 | 4 | Copyright (c) 2008-2020 Ondřej Caletka 5 | 6 | What is it 7 | ---------- 8 | 9 | This program converts multicast RTP/UDP media into http stream. 10 | It acts as a tiny HTTP server. When client connect, 11 | pre-configured multicast RTP service is choosen by URL. 12 | Program then join pre-configured multicast address and translate 13 | incoming RTP data to HTTP stream. 14 | 15 | As an alternative to pre-configured address, there is also a [UDPxy][1] 16 | compatibility mode. If URL looks like `//:` 17 | and UDPxy mode is enabled (which is default), the program joins address 18 | contained in the URL. 19 | 20 | It's main purpose is to remotely watch multicast video and audio 21 | broadcast, when your internet connection in the first-mile 22 | (e.g. broadband router) does not support multicast routing. 23 | 24 | Main advantage over translating streams in vlc (http://www.videolan.org) 25 | is that multicast group is joined _after_ the HTTP client connects, 26 | and is leaved immediately after HTTP client disconnects. So, 27 | server can be run all the time and consume almost no bandwidth nor CPU 28 | power, until HTTP client connects. 29 | 30 | [1]: http://www.udpxy.com/index-en.html 31 | 32 | Installation 33 | ------------ 34 | 35 | The package uses GNU autotools. See the file `INSTALL` for details. 36 | 37 | Configuration 38 | ------------- 39 | 40 | See provided configfile for example, run program with `--help` for 41 | a list of command line switches. 42 | 43 | __Do not run rtp2httpd as root. Choose some unprivileged port number and run 44 | it under unprivileged user account.__ 45 | 46 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | README -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | # -*- Autoconf -*- 2 | # Process this file with autoconf to produce a configure script. 3 | 4 | AC_PREREQ([2.69]) 5 | AC_INIT([rtp2httpd], [1.5], [ondrej@caletka.cz]) 6 | AC_CONFIG_SRCDIR([src/rtp2httpd.h]) 7 | AC_CONFIG_HEADERS([src/config.h]) 8 | AM_INIT_AUTOMAKE 9 | 10 | # Checks for programs. 11 | AC_PROG_CC 12 | 13 | # Checks for libraries. 14 | 15 | # Checks for header files. 16 | AC_CHECK_HEADERS([arpa/inet.h fcntl.h netdb.h netinet/in.h stdlib.h string.h strings.h sys/socket.h unistd.h]) 17 | 18 | # Checks for typedefs, structures, and compiler characteristics. 19 | AC_C_INLINE 20 | AC_TYPE_PID_T 21 | AC_TYPE_SIZE_T 22 | AC_TYPE_UINT16_T 23 | AC_TYPE_UINT8_T 24 | 25 | # Checks for library functions. 26 | AC_FUNC_FORK 27 | AC_FUNC_MALLOC 28 | AC_CHECK_FUNCS([memmove memset select socket strcasecmp strdup strerror strndup getopt_long getaddrinfo getnameinfo]) 29 | 30 | AC_CONFIG_FILES([Makefile 31 | src/Makefile]) 32 | AC_OUTPUT 33 | -------------------------------------------------------------------------------- /rtp2httpd.conf: -------------------------------------------------------------------------------- 1 | #RTP2HTTPD Config file 2 | 3 | # All blank lines and lines starting with # or ; are ignored 4 | [global] 5 | #GLOBAL OPTIONS 6 | #These options can be overrided by command-line switches 7 | 8 | #VERBOSITY: 0-quiet 1-error 2-info 3-debug (default 1) 9 | verbosity = 2 10 | 11 | #maximum paralell clients (default 5) 12 | ;maxclients = 5 13 | 14 | #wheather daemonise (default no) 15 | ;daemonise = no 16 | 17 | # UDPxy URL compatibility (default yes) 18 | ;udpxy = yes 19 | 20 | # Hostname to check in the Host: HTTP header (default none) 21 | ;hostname = somehost.example.com 22 | 23 | [bind] 24 | #List of address and ports to bind to, eg. 25 | ;mybox.example.net 8080 26 | ;mybox2.example.net 8000 27 | ;2001::1 http-alt 28 | 29 | #Note that binding to port number < 1024 will 30 | #require root privelegies and therefore is 31 | #not recommended. (Dropping privilegies is 32 | #not implemeted at this moment) 33 | 34 | #below is default - all addresses, port 8080 35 | * 8080 36 | 37 | [services] 38 | #Format: 39 | #SERVICE_URL TYPE=MRTP MADDR MPORT 40 | # 41 | #TYPE may be MRTP for RTP/UDP streams 42 | #or MUDP for RAW UDP streams 43 | # 44 | # MADDR can contain @ 45 | 46 | ;ct1 MRTP 239.194.10.11 1234 47 | ;ct2 MRTP 239.194.10.12 1234 48 | ;nova MRTP 192.0.2.1@239.194.10.13 1234 49 | -------------------------------------------------------------------------------- /src/Makefile.am: -------------------------------------------------------------------------------- 1 | 2 | bin_PROGRAMS = rtp2httpd 3 | 4 | rtp2httpd_SOURCES = rtp2httpd.c httpclients.c configuration.c 5 | 6 | noinst_HEADERS = rtp2httpd.h 7 | 8 | AM_CFLAGS= -DSYSCONFDIR=\"@sysconfdir@\" 9 | -------------------------------------------------------------------------------- /src/configuration.c: -------------------------------------------------------------------------------- 1 | /* 2 | * RTP2HTTP Proxy - Multicast RTP stream to UNICAST HTTP translator 3 | * 4 | * Copyright (C) 2008-2010 Ondrej Caletka 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License version 2 8 | * as published by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program (see the file COPYING included with this 17 | * distribution); if not, write to the Free Software Foundation, Inc., 18 | * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 | */ 20 | 21 | #define _GNU_SOURCE 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | #include "rtp2httpd.h" 37 | 38 | #ifdef HAVE_CONFIG_H 39 | #include "config.h" 40 | #endif /* HAVE_CONFIG_H */ 41 | 42 | #define MAX_LINE 150 43 | 44 | /* GLOBAL CONFIGURATION VARIABLES */ 45 | 46 | 47 | enum loglevel conf_verbosity; 48 | int conf_daemonise; 49 | int conf_udpxy; 50 | int conf_maxclients; 51 | char *conf_hostname = NULL; 52 | 53 | /* *** */ 54 | 55 | int cmd_verbosity_set; 56 | int cmd_daemonise_set; 57 | int cmd_udpxy_set; 58 | int cmd_maxclients_set; 59 | int cmd_bind_set; 60 | 61 | enum section_e { 62 | SEC_NONE = 0, 63 | SEC_BIND, 64 | SEC_SERVICES, 65 | SEC_GLOBAL 66 | }; 67 | 68 | 69 | void parseBindSec(char *line) { 70 | int i, j; 71 | char *node, *service; 72 | struct bindaddr_s *ba; 73 | 74 | j=i=0; 75 | while (!isspace(line[j])) 76 | j++; 77 | node = strndup(line, j); 78 | 79 | i=j; 80 | while (isspace(line[i])) 81 | i++; 82 | j=i; 83 | while (!isspace(line[j])) 84 | j++; 85 | service = strndup(line+i, j-i); 86 | 87 | if (strcmp("*", node) == 0) { 88 | free(node); 89 | node = NULL; 90 | } 91 | logger(LOG_DEBUG, "node: %s, port: %s\n",node, service); 92 | 93 | ba = malloc(sizeof(struct bindaddr_s)); 94 | ba->node = node; 95 | ba->service = service; 96 | ba->next = bindaddr; 97 | bindaddr = ba; 98 | } 99 | 100 | void parseServicesSec(char *line) { 101 | int i, j, r, rr; 102 | struct addrinfo hints; 103 | char *servname, *type, *maddr, *mport, *msrc="", *msaddr="", *msport=""; 104 | struct services_s *service; 105 | 106 | memset(&hints, 0, sizeof(hints)); 107 | hints.ai_socktype = SOCK_DGRAM; 108 | 109 | j=i=0; 110 | while (!isspace(line[j])) 111 | j++; 112 | servname = strndup(line, j); 113 | 114 | i=j; 115 | while (isspace(line[i])) 116 | i++; 117 | j=i; 118 | while (!isspace(line[j])) 119 | j++; 120 | type = strndupa(line+i, j-i); 121 | 122 | i=j; 123 | while (isspace(line[i])) 124 | i++; 125 | j=i; 126 | while (!isspace(line[j])) 127 | j++; 128 | maddr = strndupa(line+i, j-i); 129 | 130 | i=j; 131 | while (isspace(line[i])) 132 | i++; 133 | j=i; 134 | while (!isspace(line[j])) 135 | j++; 136 | mport = strndupa(line+i, j-i); 137 | 138 | if (strstr(maddr, "@") != NULL) { 139 | char *split; 140 | char *current; 141 | int cnt = 0; 142 | split = strtok(maddr, "@"); 143 | while (split != NULL) { 144 | current = split; 145 | if (cnt == 0) msrc = current; 146 | split = strtok(NULL, "@"); 147 | if (cnt > 0 && split != NULL) { 148 | strcat(msrc, "@"); 149 | strcat(msrc, current); 150 | } 151 | if (cnt > 0 && split == NULL) maddr = current; 152 | cnt++; 153 | } 154 | 155 | cnt = 0; 156 | msaddr = msrc; 157 | split = strtok(msrc, ":"); 158 | while (split != NULL) { 159 | current = split; 160 | if (cnt == 0) msaddr = current; 161 | split = strtok(NULL, ":"); 162 | if (cnt > 0 && split != NULL) { 163 | strcat(msaddr, ":"); 164 | strcat(msaddr, current); 165 | } 166 | if (cnt > 0 && split == NULL) msport = current; 167 | cnt++; 168 | } 169 | } 170 | 171 | logger(LOG_DEBUG,"serv: %s, type: %s, maddr: %s, mport: %s, msaddr: %s, msport: %s\n", 172 | servname, type, maddr, mport, msaddr, msport); 173 | 174 | if ((strcasecmp("MRTP", type) != 0) && (strcasecmp("MUDP", type) != 0)) { 175 | logger(LOG_ERROR, "Unsupported service type: %s\n", type); 176 | free(servname); 177 | free(msrc); 178 | return; 179 | } 180 | 181 | service = malloc(sizeof(struct services_s)); 182 | memset(service, 0, sizeof(*service)); 183 | 184 | r = getaddrinfo(maddr, mport, &hints, &(service->addr)); 185 | rr = 0; 186 | if (strcmp(msrc, "") != 0 && msrc != NULL) { 187 | rr = getaddrinfo(msaddr, msport, &hints, &(service->msrc_addr)); 188 | } 189 | if (r || rr) { 190 | if (r) { 191 | logger(LOG_ERROR, "Cannot init service %s. GAI: %s\n", 192 | servname, gai_strerror(r)); 193 | } 194 | if (rr) { 195 | logger(LOG_ERROR, "Cannot init service %s. GAI: %s\n", 196 | servname, gai_strerror(rr)); 197 | } 198 | free(servname); 199 | free(msrc); 200 | free(service); 201 | return; 202 | } 203 | if (service->addr->ai_next != NULL) { 204 | logger(LOG_ERROR, "Warning: maddr is ambiguos.\n"); 205 | } 206 | if (strcmp(msrc, "") != 0 && msrc != NULL) { 207 | if (service->msrc_addr->ai_next != NULL) { 208 | logger(LOG_ERROR, "Warning: msrc is ambiguos.\n"); 209 | } 210 | } 211 | 212 | if(strcasecmp("MRTP", type) == 0) { 213 | service->service_type = SERVICE_MRTP; 214 | } else if (strcasecmp("MUDP", type) == 0) { 215 | service->service_type = SERVICE_MUDP; 216 | } 217 | 218 | service->url = servname; 219 | service->msrc = strdup(msrc); 220 | service->next = services; 221 | services = service; 222 | } 223 | 224 | void parseGlobalSec(char *line){ 225 | int i, j; 226 | char *param, *value; 227 | char *ind; 228 | 229 | j=i=0; 230 | while (!isspace(line[j])) 231 | j++; 232 | param = strndupa(line, j); 233 | 234 | ind = index(line+j, '='); 235 | if (ind == NULL) { 236 | logger(LOG_ERROR,"Unrecognised config line: %s\n",line); 237 | return; 238 | } 239 | 240 | i = ind - line + 1; 241 | while (isspace(line[i])) 242 | i++; 243 | j=i; 244 | while (!isspace(line[j])) 245 | j++; 246 | value = strndupa(line+i, j-i); 247 | 248 | if (strcasecmp("verbosity", param) == 0) { 249 | if (!cmd_verbosity_set) { 250 | conf_verbosity = atoi(value); 251 | } else { 252 | logger(LOG_INFO, "Warning: Config file value \"verbosity\" ignored. It's already set on CmdLine.\n"); 253 | } 254 | return; 255 | } 256 | if (strcasecmp("daemonise", param) == 0) { 257 | if (!cmd_daemonise_set) { 258 | if ((strcasecmp("on", value) == 0) || 259 | (strcasecmp("true", value) == 0) || 260 | (strcasecmp("yes", value) == 0) || 261 | (strcasecmp("1", value) == 0)) { 262 | conf_daemonise = 1; 263 | } else { 264 | conf_daemonise = 0; 265 | } 266 | } else { 267 | logger(LOG_INFO, "Warning: Config file value \"daemonise\" ignored. It's already set on CmdLine.\n"); 268 | } 269 | return; 270 | } 271 | if (strcasecmp("maxclients", param) == 0) { 272 | if (!cmd_maxclients_set) { 273 | if ( atoi(value) < 1) { 274 | logger(LOG_ERROR, "Invalid maxclients! Ignoring.\n"); 275 | return; 276 | } 277 | conf_maxclients = atoi(value); 278 | } else { 279 | logger(LOG_INFO, "Warning: Config file value \"maxclients\" ignored. It's already set on CmdLine.\n"); 280 | } 281 | return; 282 | } 283 | if (strcasecmp("udpxy", param) == 0) { 284 | if (!cmd_udpxy_set) { 285 | if ((strcasecmp("on", value) == 0) || 286 | (strcasecmp("true", value) == 0) || 287 | (strcasecmp("yes", value) == 0) || 288 | (strcasecmp("1", value) == 0)) { 289 | conf_udpxy = 1; 290 | } else { 291 | conf_udpxy = 0; 292 | } 293 | } else { 294 | logger(LOG_INFO, "Warning: Config file value \"udpxy\" ignored. It's already set on CmdLine.\n"); 295 | } 296 | return; 297 | } 298 | if (strcasecmp("hostname", param) == 0) { 299 | conf_hostname = strdup(value); 300 | return; 301 | } 302 | 303 | logger(LOG_ERROR,"Unknown config parameter: %s\n", param); 304 | } 305 | 306 | 307 | 308 | int parseConfigFile(char *path) { 309 | FILE *cfile; 310 | char line[MAX_LINE]; 311 | int i, bindMsgDone=0; 312 | enum section_e section = SEC_NONE; 313 | 314 | logger(LOG_DEBUG, "Opening %s\n",path); 315 | cfile = fopen(path, "r"); 316 | if (cfile == NULL) 317 | return -1; 318 | 319 | while (fgets(line, MAX_LINE, cfile)) { 320 | i=0; 321 | 322 | while (isspace(line[i])) 323 | i++; 324 | 325 | if (line[i] == '\0' || line[i] == '#' || 326 | line[i] == ';') 327 | continue; 328 | if (line[i] == '[') { /* section change */ 329 | char *end = index(line+i, ']'); 330 | if (end) { 331 | char *secname = strndupa(line+i+1, end-line-i-1); 332 | if (strcasecmp("bind", secname) == 0) { 333 | section = SEC_BIND; 334 | continue; 335 | } 336 | if (strcasecmp("services", secname) == 0) { 337 | section = SEC_SERVICES; 338 | continue; 339 | } 340 | if (strcasecmp("global", secname) == 0) { 341 | section = SEC_GLOBAL; 342 | continue; 343 | } 344 | logger(LOG_ERROR,"Invalid section name: %s\n", secname); 345 | continue; 346 | } else { 347 | logger(LOG_ERROR,"Unterminated section: %s\n", line+i); 348 | continue; 349 | } 350 | } 351 | 352 | if (cmd_bind_set && section == SEC_BIND) { 353 | if (!bindMsgDone) { 354 | logger(LOG_INFO, "Warning: Config file section \"[bind]\" ignored. It's already set on CmdLine.\n"); 355 | bindMsgDone = 1; 356 | } 357 | continue; 358 | } 359 | 360 | switch(section) { 361 | case SEC_BIND: 362 | parseBindSec(line+i); 363 | break; 364 | case SEC_SERVICES: 365 | parseServicesSec(line+i); 366 | break; 367 | case SEC_GLOBAL: 368 | parseGlobalSec(line+i); 369 | break; 370 | default: 371 | logger(LOG_ERROR, "Unrecognised config line: %s\n",line); 372 | } 373 | } 374 | fclose(cfile); 375 | return 0; 376 | } 377 | 378 | struct bindaddr_s* newEmptyBindaddr() { 379 | struct bindaddr_s* ba; 380 | ba = malloc(sizeof(struct bindaddr_s)); 381 | memset(ba, 0, sizeof(*ba)); 382 | ba->service = strdup("8080"); 383 | return ba; 384 | } 385 | 386 | void freeBindaddr(struct bindaddr_s* ba){ 387 | struct bindaddr_s* bat; 388 | while (ba) { 389 | bat=ba; 390 | ba=ba->next; 391 | if (bat->node) 392 | free(bat->node); 393 | if (bat->service) 394 | free(bat->service); 395 | free(bat); 396 | } 397 | } 398 | 399 | /* Setup configuration defaults */ 400 | void restoreConfDefaults() { 401 | struct services_s *servtmp; 402 | struct bindaddr_s *bindtmp; 403 | 404 | conf_verbosity = LOG_ERROR; 405 | cmd_verbosity_set = 0; 406 | conf_daemonise = 0; 407 | cmd_daemonise_set = 0; 408 | conf_maxclients = 5; 409 | cmd_maxclients_set = 0; 410 | conf_udpxy = 1; 411 | cmd_udpxy_set = 0; 412 | cmd_bind_set = 0; 413 | 414 | while (services != NULL) { 415 | servtmp = services; 416 | services = services->next; 417 | if (servtmp->url != NULL) { 418 | free(servtmp->url); 419 | } 420 | if (servtmp->addr != NULL) { 421 | freeaddrinfo(servtmp->addr); 422 | } 423 | } 424 | 425 | while (bindaddr != NULL) { 426 | bindtmp = bindaddr; 427 | bindaddr = bindaddr->next; 428 | if (bindtmp->node != NULL) 429 | free(bindtmp->node); 430 | if (bindtmp->service != NULL) 431 | free(bindtmp->service); 432 | } 433 | } 434 | 435 | 436 | void usage(FILE* f, char* progname) { 437 | char * prog = basename(progname); 438 | fprintf (f, 439 | PACKAGE " - Multicast RTP to Unicast HTTP stream convertor\n" 440 | "\n" 441 | "Version " VERSION "\n" 442 | "Copyright 2008-2014 Ondrej Caletka \n" 443 | "\n" 444 | "This program is free software; you can redistribute it and/or modify\n" 445 | "it under the terms of the GNU General Public License version 2\n" 446 | "as published by the Free Software Foundation.\n"); 447 | fprintf (f, 448 | "\n" 449 | "Usage: %s [options]\n" 450 | "\n" 451 | "Options:\n" 452 | "\t-h --help Show this help\n" 453 | "\t-v --verbose Increase verbosity\n" 454 | "\t-q --quiet Report only fatal errors\n" 455 | "\t-d --daemon Fork to background (implies -q)\n" 456 | "\t-D --nodaemon Do not daemonise. (default)\n" 457 | "\t-U --noudpxy Disable UDPxy compatibility\n" 458 | "\t-m --maxclients Serve max n requests simultaneously (dfl 5)\n" 459 | "\t-l --listen [addr:]port Address/port to bind (default ANY:8080)\n" 460 | "\t-c --config Read this file, instead of\n" 461 | "\t default " CONFIGFILE "\n", prog); 462 | } 463 | 464 | 465 | void parseBindCmd(char *optarg) { 466 | char *p, *node, *service; 467 | struct bindaddr_s *ba; 468 | 469 | if (optarg[0] == '[') { 470 | p = index(optarg++, ']'); 471 | if (p) { 472 | *p = '\0'; 473 | p = rindex(++p, ':'); 474 | } 475 | } else { 476 | p = rindex(optarg, ':'); 477 | } 478 | if (p) { 479 | *p = '\0'; 480 | node = strdup(optarg); 481 | service = strdup(p+1); 482 | } else { 483 | node = NULL; 484 | service = strdup(optarg); 485 | } 486 | 487 | logger(LOG_DEBUG, "node: %s, port: %s\n",node, service); 488 | ba = malloc(sizeof(struct bindaddr_s)); 489 | ba->node = node; 490 | ba->service = service; 491 | ba->next = bindaddr; 492 | bindaddr = ba; 493 | } 494 | 495 | void parseCmdLine(int argc, char *argv[]) { 496 | const struct option longopts[] = { 497 | { "verbose", no_argument, 0, 'v' }, 498 | { "quiet", no_argument, 0, 'q' }, 499 | { "help", no_argument, 0, 'h' }, 500 | { "daemon", no_argument, 0, 'd' }, 501 | { "nodaemon", no_argument, 0, 'D' }, 502 | { "noudpxy", no_argument, 0, 'U' }, 503 | { "maxclients", required_argument, 0, 'm' }, 504 | { "listen", required_argument, 0, 'l' }, 505 | { "config", required_argument, 0, 'c' }, 506 | { 0, 0, 0, 0} 507 | }; 508 | 509 | const char shortopts[] = "vqhdDUm:c:l:"; 510 | int option_index, opt; 511 | int configfile_failed = 1; 512 | 513 | restoreConfDefaults(); 514 | 515 | while ((opt = getopt_long(argc, argv, shortopts, 516 | longopts, &option_index)) != -1) { 517 | switch (opt) { 518 | case 0: 519 | break; 520 | case 'v': 521 | conf_verbosity++; 522 | cmd_verbosity_set = 1; 523 | break; 524 | case 'q': 525 | conf_verbosity=0; 526 | cmd_verbosity_set = 1; 527 | break; 528 | case 'h': 529 | usage(stdout, argv[0]); 530 | exit(EXIT_SUCCESS); 531 | break; 532 | case 'd': 533 | conf_daemonise=1; 534 | cmd_daemonise_set = 1; 535 | break; 536 | case 'D': 537 | conf_daemonise=0; 538 | cmd_daemonise_set = 1; 539 | break; 540 | case 'U': 541 | conf_udpxy=0; 542 | cmd_udpxy_set = 1; 543 | break; 544 | case 'm': 545 | if (atoi(optarg) < 1) { 546 | logger(LOG_ERROR, "Invalid maxclients! Ignoring.\n"); 547 | } else { 548 | conf_maxclients = atoi(optarg); 549 | cmd_maxclients_set = 1; 550 | } 551 | break; 552 | case 'c': 553 | configfile_failed = parseConfigFile(optarg); 554 | break; 555 | case 'l': 556 | parseBindCmd(optarg); 557 | cmd_bind_set = 1; 558 | break; 559 | default: 560 | logger(LOG_FATAL, "Unknown option! %d \n",opt); 561 | usage(stderr, argv[0]); 562 | exit(EXIT_FAILURE); 563 | } 564 | } 565 | if(configfile_failed) { 566 | configfile_failed = parseConfigFile(CONFIGFILE); 567 | } 568 | if(configfile_failed) { 569 | logger(LOG_INFO, "Warning: No configfile found.\n"); 570 | } 571 | logger(LOG_DEBUG, "Verbosity: %d, Daemonise: %d, Maxclients: %d\n", 572 | conf_verbosity, conf_daemonise, conf_maxclients); 573 | } 574 | 575 | -------------------------------------------------------------------------------- /src/httpclients.c: -------------------------------------------------------------------------------- 1 | /* 2 | * RTP2HTTP Proxy - Multicast RTP stream to UNICAST HTTP translator 3 | * 4 | * Copyright (C) 2008-2010 Ondrej Caletka 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License version 2 8 | * as published by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program (see the file COPYING included with this 17 | * distribution); if not, write to the Free Software Foundation, Inc., 18 | * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 | */ 20 | 21 | #define _GNU_SOURCE 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | #include "rtp2httpd.h" 35 | 36 | #ifdef HAVE_CONFIG_H 37 | #include "config.h" 38 | #endif /* HAVE_CONFIG_H */ 39 | 40 | #define BUFLEN 50 41 | #define UDPBUFLEN 2000 42 | 43 | static const char unimplemented[] = 44 | "\r\n" 45 | "\r\n" 46 | "501 Method Not Implemented\r\n" 47 | "\r\n" 48 | "

501 Method Not Implemented

\r\n" 49 | "

Sorry, only GET is supported.

\r\n" 50 | "
\r\n" 51 | "
Server " PACKAGE " version " VERSION "
\r\n" 52 | "\r\n"; 53 | 54 | static const char badrequest[] = 55 | "\r\n" 56 | "\r\n" 57 | "400 Bad Request\r\n" 58 | "\r\n" 59 | "

400 Bad Request

\r\n" 60 | "

Your browser sent a request that this server could not understand.
\r\n" 61 | "

\r\n" 62 | "
\r\n" 63 | "
Server " PACKAGE " version " VERSION "
\r\n" 64 | "\r\n"; 65 | 66 | static const char serviceNotFound[] = 67 | "\r\n" 68 | "\r\n" 69 | "404 Service not found!\r\n" 70 | "\r\n" 71 | "

404 Service not found!

\r\n" 72 | "

Sorry, this service was not configured.

\r\n" 73 | "
\r\n" 74 | "
Server " PACKAGE " version " VERSION "
\r\n" 75 | "\r\n"; 76 | 77 | static const char serviceUnavailable[] = 78 | "\r\n" 79 | "\r\n" 80 | "503 Service Unavaliable\r\n" 81 | "\r\n" 82 | "

503 Service Unavaliable

\r\n" 83 | "

Sorry, there are too many connections at this time.\r\n" 84 | "Try again later.

\r\n" 85 | "
\r\n" 86 | "
Server " PACKAGE " version " VERSION "
\r\n" 87 | "\r\n"; 88 | 89 | static const char *responseCodes[] = { 90 | "HTTP/1.1 200 OK\r\n", /* 0 */ 91 | "HTTP/1.1 404 Not Found\r\n", /* 1 */ 92 | "HTTP/1.1 400 Bad Request\r\n", /* 2 */ 93 | "HTTP/1.1 501 Not Implemented\r\n", /* 3 */ 94 | "HTTP/1.1 503 Service Unavailable\r\n", /* 4 */ 95 | }; 96 | 97 | #define STATUS_200 0 98 | #define STATUS_404 1 99 | #define STATUS_400 2 100 | #define STATUS_501 3 101 | #define STATUS_503 4 102 | 103 | static const char *contentTypes[] = { 104 | "Content-Type: application/octet-stream\r\n", /* 0 */ 105 | "Content-Type: text/html\r\n", /* 1 */ 106 | "Content-Type: text/html; charset=utf-8\r\n", /* 2 */ 107 | "Content-Type: video/mpeg\r\n", /* 3 */ 108 | "Content-Type: audio/mpeg\r\n", /* 4 */ 109 | }; 110 | 111 | #define CONTENT_OSTREAM 0 112 | #define CONTENT_HTML 1 113 | #define CONTENT_HTMLUTF 2 114 | #define CONTENT_MPEGV 3 115 | #define CONTENT_MPEGA 4 116 | 117 | static const char staticHeaders[] = 118 | "Server: " PACKAGE "/" VERSION "\r\n" 119 | "\r\n"; 120 | 121 | /* 122 | * Linked list of allowed services 123 | */ 124 | 125 | struct services_s *services = NULL; 126 | 127 | 128 | /* 129 | * Ensures that all data are written to the socket 130 | */ 131 | static void writeToClient(int s,const uint8_t *buf, const size_t buflen) { 132 | ssize_t actual; 133 | size_t written=0; 134 | while (written:port 165 | * returns a pointer to statically alocated service struct if success, 166 | * NULL otherwise. 167 | */ 168 | 169 | static struct services_s* udpxy_parse(char* url) { 170 | static struct services_s serv; 171 | static struct addrinfo res_ai, msrc_res_ai; 172 | static struct sockaddr_storage res_addr, msrc_res_addr; 173 | 174 | char *addrstr, *portstr, *msrc="", *msaddr="", *msport=""; 175 | int i, r, rr; 176 | char c; 177 | struct addrinfo hints, *res, *msrc_res; 178 | 179 | 180 | if (strncmp("/rtp/", url, 5) == 0) 181 | serv.service_type = SERVICE_MRTP; 182 | else if (strncmp("/udp/", url, 5) == 0) 183 | serv.service_type = SERVICE_MUDP; 184 | else 185 | return NULL; 186 | addrstr = rindex(url, '/'); 187 | if (!addrstr) 188 | return NULL; 189 | /* Decode URL encoded strings */ 190 | for (i=0; i<(strlen(addrstr)-2); i++) { 191 | if (addrstr[i] == '%' && 192 | sscanf(addrstr+i+1, "%2hhx", (unsigned char *) &c) >0 ) { 193 | addrstr[i] = c; 194 | memmove(addrstr+i+1, addrstr+i+3, 1+strlen(addrstr+i+3)); 195 | } 196 | } 197 | logger(LOG_DEBUG, "decoded addr: %s\n", addrstr); 198 | if (addrstr[1] == '[') { 199 | portstr = index(addrstr, ']'); 200 | addrstr += 2; 201 | if (portstr) { 202 | *portstr = '\0'; 203 | portstr = rindex(++portstr, ':'); 204 | } 205 | } else { 206 | portstr = rindex(addrstr++, ':'); 207 | } 208 | 209 | if (strstr(addrstr, "@") != NULL) { 210 | char *split; 211 | char *current; 212 | int cnt = 0; 213 | split = strtok(addrstr, "@"); 214 | while (split != NULL) { 215 | current = split; 216 | if (cnt == 0) msrc = current; 217 | split = strtok(NULL, "@"); 218 | if (cnt > 0 && split != NULL) { 219 | strcat(msrc, "@"); 220 | strcat(msrc, current); 221 | } 222 | if (cnt > 0 && split == NULL) addrstr = current; 223 | cnt++; 224 | } 225 | 226 | cnt = 0; 227 | msaddr = msrc; 228 | split = strtok(msrc, ":"); 229 | while (split != NULL) { 230 | current = split; 231 | if (cnt == 0) msaddr = current; 232 | split = strtok(NULL, ":"); 233 | if (cnt > 0 && split != NULL) { 234 | strcat(msaddr, ":"); 235 | strcat(msaddr, current); 236 | } 237 | if (cnt > 0 && split == NULL) msport = current; 238 | cnt++; 239 | } 240 | } 241 | 242 | if (portstr) { 243 | *portstr = '\0'; 244 | portstr++; 245 | } else 246 | portstr = "1234"; 247 | 248 | logger(LOG_DEBUG, "addrstr: %s portstr: %s msrc: %s\n", addrstr, portstr, msrc); 249 | 250 | memset(&hints, 0, sizeof(hints)); 251 | hints.ai_socktype = SOCK_DGRAM; 252 | r = getaddrinfo(addrstr, portstr, &hints, &res); 253 | rr = 0; 254 | if (strcmp(msrc, "") != 0 && msrc != NULL) { 255 | rr = getaddrinfo(msrc, 0, &hints, &msrc_res); 256 | } 257 | if (r | rr) { 258 | if (r) { 259 | logger(LOG_ERROR, "Cannot resolve Multicast address. GAI: %s\n", 260 | gai_strerror(r)); 261 | } 262 | if (rr) { 263 | logger(LOG_ERROR, "Cannot resolve Multicast source address. GAI: %s\n", 264 | gai_strerror(rr)); 265 | } 266 | 267 | free(msrc); 268 | return NULL; 269 | } 270 | if (res->ai_next != NULL) { 271 | logger(LOG_ERROR, "Warning: maddr is ambiguos.\n"); 272 | } 273 | if (strcmp(msrc, "") != 0 && msrc != NULL) { 274 | if (msrc_res->ai_next != NULL) { 275 | logger(LOG_ERROR, "Warning: msrc is ambiguos.\n"); 276 | } 277 | } 278 | 279 | /* Copy result into statically allocated structs */ 280 | memcpy(&res_addr, res->ai_addr, res->ai_addrlen); 281 | memcpy(&res_ai, res, sizeof(struct addrinfo)); 282 | res_ai.ai_addr = (struct sockaddr*) &res_addr; 283 | res_ai.ai_canonname = NULL; 284 | res_ai.ai_next = NULL; 285 | serv.addr = &res_ai; 286 | 287 | if (strcmp(msrc, "") != 0 && msrc != NULL) { 288 | /* Copy result into statically allocated structs */ 289 | memcpy(&msrc_res_addr, msrc_res->ai_addr, msrc_res->ai_addrlen); 290 | memcpy(&msrc_res_ai, msrc_res, sizeof(struct addrinfo)); 291 | msrc_res_ai.ai_addr = (struct sockaddr*) &msrc_res_addr; 292 | msrc_res_ai.ai_canonname = NULL; 293 | msrc_res_ai.ai_next = NULL; 294 | serv.msrc_addr = &msrc_res_ai; 295 | } 296 | 297 | serv.msrc = strdup(msrc); 298 | 299 | return &serv; 300 | } 301 | 302 | 303 | static void startRTPstream(int client, struct services_s *service){ 304 | int sock, level; 305 | int r; 306 | struct group_req gr; 307 | struct group_source_req gsr; 308 | uint8_t buf[UDPBUFLEN]; 309 | int actualr; 310 | uint16_t seqn, oldseqn, notfirst=0; 311 | int payloadstart, payloadlength; 312 | fd_set rfds; 313 | struct timeval timeout; 314 | int on = 1; 315 | 316 | sock = socket(service->addr->ai_family, service->addr->ai_socktype, 317 | service->addr->ai_protocol); 318 | r = setsockopt(sock, SOL_SOCKET, 319 | SO_REUSEADDR, &on, sizeof(on)); 320 | if (r) { 321 | logger(LOG_ERROR, "SO_REUSEADDR " 322 | "failed: %s\n", strerror(errno)); 323 | } 324 | 325 | r = bind(sock,(struct sockaddr *) service->addr->ai_addr, service->addr->ai_addrlen); 326 | if (r) { 327 | logger(LOG_ERROR, "Cannot bind: %s\n", 328 | strerror(errno)); 329 | exit(RETVAL_RTP_FAILED); 330 | } 331 | 332 | memcpy(&(gr.gr_group), service->addr->ai_addr, service->addr->ai_addrlen); 333 | 334 | switch (service->addr->ai_family) { 335 | case AF_INET: 336 | level = SOL_IP; 337 | gr.gr_interface = 0; 338 | break; 339 | 340 | case AF_INET6: 341 | level = SOL_IPV6; 342 | gr.gr_interface = ((const struct sockaddr_in6 *) 343 | (service->addr->ai_addr))->sin6_scope_id; 344 | break; 345 | default: 346 | logger(LOG_ERROR, "Address family don't support mcast.\n"); 347 | exit(RETVAL_SOCK_READ_FAILED); 348 | } 349 | 350 | if (strcmp(service->msrc, "") != 0 && service->msrc != NULL) { 351 | gsr.gsr_group = gr.gr_group; 352 | gsr.gsr_interface = gr.gr_interface; 353 | memcpy(&(gsr.gsr_source), service->msrc_addr->ai_addr, service->msrc_addr->ai_addrlen); 354 | r = setsockopt(sock, level, 355 | MCAST_JOIN_SOURCE_GROUP, &gsr, sizeof(gsr)); 356 | } else { 357 | r = setsockopt(sock, level, 358 | MCAST_JOIN_GROUP, &gr, sizeof(gr)); 359 | } 360 | 361 | if (r) { 362 | logger(LOG_ERROR, "Cannot join mcast group: %s\n", 363 | strerror(errno)); 364 | exit(RETVAL_RTP_FAILED); 365 | } 366 | 367 | 368 | 369 | while(1) { 370 | FD_ZERO(&rfds); 371 | FD_SET(sock, &rfds); 372 | FD_SET(client, &rfds); /* Will be set if connection to client lost.*/ 373 | timeout.tv_sec = 5; 374 | timeout.tv_usec = 0; 375 | 376 | /* We use select to get rid of recv stuck if 377 | * multicast group is unoperated. 378 | */ 379 | r=select(sock+1, &rfds, NULL, NULL, &timeout); 380 | if (r<0 && errno==EINTR) 381 | continue; 382 | if (r==0) { /* timeout reached */ 383 | exit(RETVAL_SOCK_READ_FAILED); 384 | } 385 | if (FD_ISSET(client, &rfds)) { /* client written stg, or conn. lost */ 386 | exit(RETVAL_WRITE_FAILED); 387 | } 388 | 389 | actualr = recv(sock, buf, sizeof(buf), 0); 390 | if (actualr < 0){ 391 | exit(RETVAL_SOCK_READ_FAILED); 392 | } 393 | if (service->service_type == SERVICE_MUDP) { 394 | writeToClient(client, buf, sizeof(buf)); 395 | continue; 396 | } 397 | 398 | if (actualr < 12 || (buf[0]&0xC0) != 0x80) { 399 | /*malformed RTP/UDP/IP packet*/ 400 | logger(LOG_DEBUG,"Malformed RTP packet received\n"); 401 | continue; 402 | } 403 | 404 | payloadstart = 12; /* basic RTP header length */ 405 | payloadstart += (buf[0]&0x0F) * 4; /*CRSC headers*/ 406 | if (buf[0]&0x10) { /*Extension header*/ 407 | payloadstart += 4 + 4*ntohs(*((uint16_t *)(buf+payloadstart+2))); 408 | } 409 | payloadlength = actualr - payloadstart; 410 | if (buf[0]&0x20) { /*Padding*/ 411 | payloadlength -= buf[actualr]; 412 | /*last octet indicate padding length*/ 413 | } 414 | if(payloadlength<0) { 415 | logger(LOG_DEBUG,"Malformed RTP packet received\n"); 416 | continue; 417 | } 418 | seqn = ntohs(*((uint16_t *)(buf+2))); 419 | if (notfirst && seqn==oldseqn) { 420 | logger(LOG_DEBUG,"Duplicated RTP packet " 421 | "received (seqn %d)\n", seqn); 422 | continue; 423 | } 424 | if (notfirst && (seqn != ((oldseqn+1)&0xFFFF))) { 425 | logger(LOG_DEBUG,"Congestion - expected %d, " 426 | "received %d\n", (oldseqn+1)&0xFFFF, seqn); 427 | } 428 | oldseqn=seqn; 429 | notfirst=1; 430 | 431 | writeToClient(client, buf+payloadstart, payloadlength); 432 | } 433 | 434 | /*SHOULD NEVER REACH THIS*/ 435 | return; 436 | } 437 | 438 | /* 439 | * Service for connected client. 440 | * Run in forked thread. 441 | */ 442 | void clientService(int s) { 443 | char buf[BUFLEN]; 444 | FILE *client; 445 | int numfields; 446 | char *method, *url, httpver; 447 | char *hostname; 448 | char *urlfrom; 449 | struct services_s *servi; 450 | 451 | signal(SIGPIPE, &sigpipe_handler); 452 | 453 | client = fdopen(s, "r"); 454 | /*read only one line*/ 455 | if (fgets(buf, sizeof(buf), client) == NULL) { 456 | exit(RETVAL_READ_FAILED); 457 | } 458 | numfields = sscanf(buf,"%ms %ms %c", &method, &url, &httpver); 459 | if(numfields<2) { 460 | logger(LOG_DEBUG, "Non-HTTP input.\n"); 461 | } 462 | logger(LOG_INFO,"request: %s %s \n", method, url); 463 | 464 | if(numfields == 3) { /* Read and discard all headers before replying */ 465 | while(fgets(buf, sizeof(buf), client) != NULL && 466 | strcmp("\r\n", buf) != 0) { 467 | if (strncasecmp("Host: ", buf, 6) == 0) { 468 | hostname = strpbrk(buf+6, ":\r\n"); 469 | if (hostname) 470 | hostname = strndup(buf+6, hostname-buf-6); 471 | logger(LOG_DEBUG, "Host header: %s\n", hostname); 472 | } 473 | } 474 | } 475 | 476 | if (strcmp(method, "GET") != 0) { 477 | if (numfields == 3) 478 | headers(s, STATUS_501, CONTENT_HTML); 479 | writeToClient(s, (uint8_t*) unimplemented, sizeof(unimplemented)-1); 480 | exit(RETVAL_UNKNOWN_METHOD); 481 | } 482 | free(method); method=NULL; 483 | 484 | urlfrom = rindex(url, '/'); 485 | if (urlfrom == NULL || (conf_hostname && strcasecmp(conf_hostname, hostname)!=0)) { 486 | if (numfields == 3) 487 | headers(s, STATUS_400, CONTENT_HTML); 488 | writeToClient(s, (uint8_t*) badrequest, sizeof(badrequest)-1); 489 | exit(RETVAL_BAD_REQUEST); 490 | } 491 | 492 | for (servi = services; servi; servi=servi->next) { 493 | if (strcmp(urlfrom+1, servi->url) == 0) 494 | break; 495 | } 496 | 497 | if (servi == NULL && conf_udpxy) 498 | servi = udpxy_parse(url); 499 | 500 | free(url); url=NULL; 501 | 502 | if (servi == NULL) { 503 | if (numfields == 3) 504 | headers(s, STATUS_404, CONTENT_HTML); 505 | writeToClient(s, (uint8_t*) serviceNotFound, sizeof(serviceNotFound)-1); 506 | exit(RETVAL_CLEAN); 507 | } 508 | 509 | if (clientcount > conf_maxclients) { /*Too much clients*/ 510 | if (numfields == 3) 511 | headers(s, STATUS_503, CONTENT_HTML); 512 | writeToClient(s, (uint8_t*) serviceUnavailable, sizeof(serviceUnavailable)-1); 513 | exit(RETVAL_CLEAN); 514 | } 515 | 516 | if (numfields == 3) 517 | headers(s, STATUS_200, CONTENT_OSTREAM); 518 | startRTPstream(s, servi); 519 | /* SHOULD NEVER REACH HERE */ 520 | exit(RETVAL_CLEAN); 521 | } 522 | -------------------------------------------------------------------------------- /src/rtp2httpd.c: -------------------------------------------------------------------------------- 1 | /* 2 | * RTP2HTTP Proxy - Multicast RTP stream to UNICAST HTTP translator 3 | * 4 | * Copyright (C) 2008-2010 Ondrej Caletka 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License version 2 8 | * as published by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program (see the file COPYING included with this 17 | * distribution); if not, write to the Free Software Foundation, Inc., 18 | * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 | */ 20 | 21 | #define _GNU_SOURCE 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | 38 | #include "rtp2httpd.h" 39 | 40 | 41 | #ifdef HAVE_CONFIG_H 42 | #include "config.h" 43 | #endif /* HAVE_CONFIG_H */ 44 | 45 | #define max(a,b) ((a)>(b) ? (a):(b)) 46 | #define min(a,b) ((a)<(b) ? (a):(b)) 47 | 48 | 49 | #define MAX_S 10 50 | 51 | /** 52 | * Linked list of clients 53 | */ 54 | struct client_s { 55 | struct sockaddr_storage ss; /* Client host-port */ 56 | pid_t pid; 57 | struct client_s *next; 58 | }; 59 | 60 | static struct client_s *clients; 61 | 62 | 63 | /* GLOBALS */ 64 | struct bindaddr_s *bindaddr = NULL; 65 | 66 | int clientcount = 0; 67 | 68 | /* *** */ 69 | 70 | /** 71 | * Logger function. Show the message if current verbosity is above 72 | * logged level. 73 | * 74 | * @param levem Message log level 75 | * @param format printf style format string 76 | * @returns Whatever printf returns 77 | */ 78 | int logger(enum loglevel level, const char *format, ...) { 79 | va_list ap; 80 | int r=0; 81 | //if (conf_verbosity >= level) { 82 | va_start(ap, format); 83 | r=vfprintf(stderr,format, ap); 84 | va_end(ap); 85 | //} 86 | return r; 87 | } 88 | 89 | 90 | void childhandler(int signum) { /* SIGCHLD handler */ 91 | int child; 92 | int status; 93 | struct client_s *cli, *cli2; 94 | int r; 95 | char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV]; 96 | 97 | 98 | while ( (child = waitpid (-1, &status, WNOHANG)) > 0){ 99 | 100 | for (cli = clients; cli; cli = cli->next) { 101 | if (child == cli->pid) 102 | break; 103 | } 104 | if (cli != NULL) { 105 | r = getnameinfo((struct sockaddr *) &(cli->ss), sizeof(cli->ss), 106 | hbuf, sizeof(hbuf), 107 | sbuf, sizeof(sbuf), 108 | NI_NUMERICHOST | NI_NUMERICSERV); 109 | if (r) { 110 | logger(LOG_ERROR, "getnameinfo failed: %s\n", 111 | gai_strerror(r)); 112 | } else { 113 | logger(LOG_DEBUG, "Client %s port %s disconnected (%d, %d)\n", 114 | hbuf, sbuf, WEXITSTATUS(status), 115 | WIFSIGNALED(status)); 116 | } 117 | 118 | /* remove client from the list */ 119 | if (cli == clients) { 120 | clients=cli->next; 121 | free(cli); 122 | } else { 123 | for (cli2=clients; cli2 != NULL; cli2=cli2->next) { 124 | if (cli2->next == cli) { 125 | cli2->next = cli->next; 126 | free(cli); 127 | break; 128 | } 129 | } 130 | } 131 | } else { 132 | if( child != 1 ) 133 | logger(LOG_ERROR, "Unknown child finished - pid %d\n", child); 134 | } 135 | 136 | clientcount--; 137 | signal(signum, &childhandler); 138 | } 139 | } 140 | 141 | 142 | int main(int argc, char *argv[]) { 143 | struct addrinfo hints, *res, *ai; 144 | struct bindaddr_s *bai; 145 | struct sockaddr_storage client; 146 | socklen_t client_len = sizeof(client); 147 | int cls; 148 | int r, i, j; 149 | int s[MAX_S]; 150 | int maxs, nfds; 151 | char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV]; 152 | fd_set rfd, rfd0; 153 | pid_t child; 154 | struct client_s *newc; 155 | const int on = 1; 156 | sigset_t childset; 157 | 158 | sigaddset(&childset, SIGCHLD); 159 | 160 | parseCmdLine(argc, argv); 161 | 162 | memset(&hints, 0, sizeof(hints)); 163 | hints.ai_socktype = SOCK_STREAM; 164 | hints.ai_flags = AI_PASSIVE; 165 | maxs = 0; 166 | nfds = -1; 167 | 168 | if (bindaddr == NULL) { 169 | bindaddr = newEmptyBindaddr(); 170 | } 171 | 172 | for (bai=bindaddr; bai; bai=bai->next) { 173 | r = getaddrinfo(bai->node, bai->service, 174 | &hints, &res); 175 | if (r) { 176 | logger(LOG_FATAL, "GAI: %s\n", gai_strerror(r)); 177 | exit(EXIT_FAILURE); 178 | } 179 | 180 | for (ai = res; ai && maxs < MAX_S; ai = ai->ai_next) { 181 | s[maxs] = socket(ai->ai_family, ai->ai_socktype, 182 | ai->ai_protocol); 183 | if (s[maxs] < 0) 184 | continue; 185 | r = setsockopt(s[maxs], SOL_SOCKET, 186 | SO_REUSEADDR, &on, sizeof(on)); 187 | if (r) { 188 | logger(LOG_ERROR, "SO_REUSEADDR " 189 | "failed: %s\n", strerror(errno)); 190 | } 191 | 192 | #ifdef IPV6_V6ONLY 193 | if (ai->ai_family == AF_INET6) { 194 | r = setsockopt(s[maxs], IPPROTO_IPV6, 195 | IPV6_V6ONLY, &on, sizeof(on)); 196 | if (r) { 197 | logger(LOG_ERROR, "IPV6_V6ONLY " 198 | "failed: %s\n", strerror(errno)); 199 | } 200 | } 201 | #endif /* IPV6_V6ONLY */ 202 | 203 | r = bind(s[maxs], ai->ai_addr, ai->ai_addrlen); 204 | if (r) { 205 | logger(LOG_ERROR, "Cannot bind: %s\n", 206 | strerror(errno)); 207 | close(s[maxs]); 208 | continue; 209 | } 210 | r = listen(s[maxs], 0); 211 | if (r) { 212 | logger(LOG_ERROR, "Cannot listen: %s\n", 213 | strerror(errno)); 214 | close(s[maxs]); 215 | continue; 216 | } 217 | r = getnameinfo(ai->ai_addr, ai->ai_addrlen, 218 | hbuf, sizeof(hbuf), 219 | sbuf, sizeof(sbuf), 220 | NI_NUMERICHOST | NI_NUMERICSERV); 221 | if (r) { 222 | logger(LOG_ERROR, "getnameinfo failed: %s\n", 223 | gai_strerror(r)); 224 | } else { 225 | logger(LOG_INFO, "Listening on %s port %s\n", 226 | hbuf, sbuf); 227 | } 228 | 229 | if (s[maxs] > nfds) 230 | nfds = s[maxs]; 231 | maxs++; 232 | } 233 | freeaddrinfo(res); 234 | } 235 | freeBindaddr(bindaddr); 236 | 237 | if (maxs == 0) { 238 | logger(LOG_FATAL, "No socket to listen!\n"); 239 | exit(EXIT_FAILURE); 240 | } 241 | 242 | FD_ZERO(&rfd0); 243 | for (i = 0; i < maxs; i++) { 244 | FD_SET(s[i], &rfd0); 245 | } 246 | 247 | if (conf_daemonise) { 248 | logger(LOG_INFO, "Forking to background...\n"); 249 | if (daemon(1, 0) != 0) { 250 | logger(LOG_FATAL, "Cannot fork: %s\n", strerror(errno)); 251 | exit(EXIT_FAILURE); 252 | } 253 | } 254 | 255 | signal(SIGCHLD, &childhandler); 256 | while (1) { 257 | rfd = rfd0; 258 | r = select(nfds+1, &rfd, NULL, NULL, NULL); 259 | if (r<0) { 260 | if (errno == EINTR) 261 | continue; 262 | logger(LOG_FATAL,"select() failed: %s\n", 263 | strerror(errno)); 264 | exit(EXIT_FAILURE); 265 | } 266 | for (i = 0; i < maxs; i++) { 267 | if (FD_ISSET(s[i], &rfd)) { 268 | cls = accept(s[i], 269 | (struct sockaddr*) &client, 270 | &client_len); 271 | 272 | /* We have to mask SIGCHLD before we add child to the list*/ 273 | sigprocmask(SIG_BLOCK, &childset, NULL); 274 | clientcount++; 275 | if ((child = fork())) { /* PARENT */ 276 | close(cls); 277 | newc = malloc(sizeof(struct client_s)); 278 | newc->ss = client; 279 | newc->pid = child; 280 | newc->next = clients; 281 | clients = newc; 282 | 283 | r = getnameinfo((struct sockaddr *) &client, client_len, 284 | hbuf, sizeof(hbuf), 285 | sbuf, sizeof(sbuf), 286 | NI_NUMERICHOST | NI_NUMERICSERV); 287 | if (r) { 288 | logger(LOG_ERROR, "getnameinfo failed: %s\n", 289 | gai_strerror(r)); 290 | } else { 291 | logger(LOG_INFO, "Connection from %s port %s\n", 292 | hbuf, sbuf); 293 | } 294 | sigprocmask(SIG_UNBLOCK, &childset, NULL); 295 | 296 | } else { /* CHILD */ 297 | for (j = 0; j < maxs; j++) close(s[j]); 298 | clientService(cls); 299 | exit(EXIT_SUCCESS); 300 | } 301 | } 302 | } 303 | } 304 | /* Should never reach this */ 305 | return 0; 306 | } 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | -------------------------------------------------------------------------------- /src/rtp2httpd.h: -------------------------------------------------------------------------------- 1 | /* 2 | * RTP2HTTP Proxy - Multicast RTP stream to UNICAST HTTP translator 3 | * 4 | * Copyright (C) 2008,2009 Ondrej Caletka 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License version 2 8 | * as published by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program (see the file COPYING included with this 17 | * distribution); if not, write to the Free Software Foundation, Inc., 18 | * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 | */ 20 | 21 | #ifndef __RTP2HTTPD_H__ 22 | #define __RTP2HTTPD_H__ 23 | 24 | #include 25 | #include 26 | #include 27 | 28 | 29 | #ifdef HAVE_CONFIG_H 30 | #include "config.h" 31 | #endif /* HAVE_CONFIG_H */ 32 | 33 | #ifndef SYSCONFDIR 34 | #define SYSCONFDIR "." 35 | #endif /* SYSCONFDIR */ 36 | 37 | #define CONFIGFILE SYSCONFDIR "/rtp2httpd.conf" 38 | 39 | 40 | enum loglevel { 41 | LOG_FATAL = 0, /* Always shown */ 42 | LOG_ERROR, /* Could be silenced */ 43 | LOG_INFO, /* Default verbosity */ 44 | LOG_DEBUG 45 | }; 46 | 47 | enum service_type { 48 | SERVICE_MRTP = 0, 49 | SERVICE_MUDP 50 | }; 51 | 52 | /* 53 | * Linked list of adresses to bind 54 | */ 55 | struct bindaddr_s { 56 | char *node; 57 | char *service; 58 | struct bindaddr_s *next; 59 | }; 60 | 61 | /* 62 | * Linked list of allowed services 63 | */ 64 | struct services_s { 65 | char *url; 66 | char *msrc; 67 | enum service_type service_type; 68 | struct addrinfo *addr; 69 | struct addrinfo *msrc_addr; 70 | struct services_s *next; 71 | }; 72 | 73 | /* GLOBAL CONFIGURATION VARIABLES */ 74 | 75 | extern enum loglevel conf_verbosity; 76 | extern int conf_daemonise; 77 | extern int conf_udpxy; 78 | extern int conf_maxclients; 79 | extern char *conf_hostname; 80 | 81 | /* GLOBALS */ 82 | extern struct services_s *services; 83 | extern struct bindaddr_s *bindaddr; 84 | extern int clientcount; 85 | 86 | 87 | /* rtp2httpd.c INTERFACE */ 88 | 89 | /** 90 | * Logger function. Show the message if current verbosity is above 91 | * logged level. 92 | * 93 | * @param levem Message log level 94 | * @param format printf style format string 95 | * @returns Whatever printf returns 96 | */ 97 | int logger(enum loglevel level, const char *format, ...); 98 | 99 | 100 | /* httpclients.c INTERFACE */ 101 | 102 | /* 103 | * Service for connected client. 104 | * Run in forked thread. 105 | * 106 | * @params s connected socket 107 | */ 108 | void clientService(int s); 109 | 110 | /* Return values of clientService() */ 111 | #define RETVAL_CLEAN 0 112 | #define RETVAL_WRITE_FAILED 1 113 | #define RETVAL_READ_FAILED 2 114 | #define RETVAL_UNKNOWN_METHOD 3 115 | #define RETVAL_BAD_REQUEST 4 116 | #define RETVAL_RTP_FAILED 5 117 | #define RETVAL_SOCK_READ_FAILED 6 118 | 119 | /* configfile.c INTERFACE */ 120 | 121 | void parseCmdLine(int argc, char *argv[]); 122 | struct bindaddr_s* newEmptyBindaddr(); 123 | void freeBindaddr(struct bindaddr_s*); 124 | 125 | #endif /* __RTP2HTTPD_H__*/ 126 | 127 | #ifndef strndupa 128 | #define strndupa(s, n) \ 129 | (__extension__ ({const char *__in = (s); \ 130 | size_t __len = strnlen (__in, (n)) + 1; \ 131 | char *__out = (char *) alloca (__len); \ 132 | __out[__len-1] = '\0'; \ 133 | (char *) memcpy (__out, __in, __len-1);})) 134 | #endif --------------------------------------------------------------------------------