├── ogm.wav ├── .gitignore ├── coverity_model.cpp ├── Makefile ├── callgen323.cbp ├── version.h ├── ReadMe.txt ├── callgen323.vcproj ├── callgen323_2005.vcproj ├── callgen323_2008.vcproj ├── main.h ├── license.html └── main.cxx /ogm.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/willamowius/callgen323/HEAD/ogm.wav -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | obj_*_*_*_s 2 | obj_*_*_*_d_s 3 | obj_*_*_* 4 | cov-int* 5 | *.proj 6 | *.save 7 | *.layout 8 | 9 | -------------------------------------------------------------------------------- /coverity_model.cpp: -------------------------------------------------------------------------------- 1 | // This is the modeling file for Coverity to avoid false positives. 2 | // This code is not supposed to be compiled into callgen323! 3 | 4 | struct _ios_fields{ 5 | int _precision; 6 | }; 7 | class ios : public _ios_fields{ 8 | 9 | int precision() const { return _precision; } 10 | int precision(int newp) {return _precision; } 11 | 12 | }; 13 | 14 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Makefile 3 | # 4 | # Makefile for H.323 Call Generator 5 | # 6 | 7 | PROG = callgen323 8 | SOURCES = main.cxx 9 | 10 | ifndef OPENH323DIR 11 | OPENH323DIR=$(HOME)/h323plus 12 | endif 13 | 14 | include $(OPENH323DIR)/openh323u.mak 15 | 16 | # add cleanup files 17 | CLEAN_FILES += PWL* 18 | 19 | STDCCFLAGS += -Wno-unused-variable 20 | 21 | # dependencies 22 | $(OBJDIR)/main.o: main.h version.h 23 | 24 | -------------------------------------------------------------------------------- /callgen323.cbp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 38 | 39 | -------------------------------------------------------------------------------- /version.h: -------------------------------------------------------------------------------- 1 | /* 2 | * version.h 3 | * 4 | * Version number header file for CallGen323 5 | * 6 | * Copyright (c) 1993-2000 Equivalence Pty. Ltd. 7 | * 8 | * The contents of this file are subject to the Mozilla Public License 9 | * Version 1.0 (the "License"); you may not use this file except in 10 | * compliance with the License. You may obtain a copy of the License at 11 | * http://www.mozilla.org/MPL/ 12 | * 13 | * Software distributed under the License is distributed on an "AS IS" 14 | * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See 15 | * the License for the specific language governing rights and limitations 16 | * under the License. 17 | * 18 | * The Original Code is Portable Windows Library. 19 | * 20 | * The Initial Developer of the Original Code is Equivalence Pty. Ltd. 21 | * 22 | * Contributor(s): ______________________________________. 23 | * 24 | * 25 | * Library dependencies: 26 | * 27 | * pwlib: v1.5.0 CVS tag: 28 | * openh323: v1.12.0 CVS tag: v1_12_0 29 | */ 30 | 31 | #ifndef _CallGen_VERSION_H 32 | #define _CallGen_VERSION_H 33 | 34 | #define MAJOR_VERSION 2 35 | #define MINOR_VERSION 3 36 | #define BUILD_TYPE ReleaseCode 37 | #define BUILD_NUMBER 0 38 | 39 | 40 | #endif // _CallGen_VERSION_H 41 | 42 | -------------------------------------------------------------------------------- /ReadMe.txt: -------------------------------------------------------------------------------- 1 | H.323 Call Generator 2 | ==================== 3 | 4 | This call generator allows you to do load testing of H.323 endpoints, 5 | gateways and gatekeepers. 6 | 7 | It supports audio, video and H.239. It also supports H.235 AES media encoding 8 | and RTP fuzzing to test the codecs. 9 | 10 | License: MPL 11 | 12 | Repository: https://github.com/willamowius/callgen323 13 | Support: https://www.willamowius.com/h323plus-support.html 14 | 15 | 16 | HOW TO COMPILE 17 | ============== 18 | 19 | On Linux, *BSD, Solaris or MacOS X: 20 | 21 | Install gcc, OpenSSL dev package and all libraries that might be needed to compile H323Plus video codecs. 22 | 23 | Get and compile PTLib: 24 | 25 | cd ~ 26 | git clone https://github.com/willamowius/ptlib.git 27 | cd ptlib 28 | export PTLIBDIR=~/ptlib 29 | ./configure --enable-ipv6 --disable-odbc --disable-sdl --disable-lua --disable-expat 30 | make debugnoshared 31 | 32 | Get and compile H323Plus: 33 | 34 | cd ~ 35 | git clone https://github.com/willamowius/h323plus.git 36 | cd h323plus 37 | export OPENH323DIR=~/h323plus 38 | ./configure --enable-h235 -enable-h46017 --enable-h46019m 39 | make debugnoshared 40 | 41 | Get and compile callgen323: 42 | 43 | cd ~ 44 | git clone https://github.com/willamowius/callgen323.git 45 | cd callgen323 46 | make debugnoshared 47 | 48 | Once the compile is finished, the binary can be found as 49 | 50 | ~/gnugk/obj_linux_x86_64_d_s/callgen323 51 | 52 | (assuming you use a 64bit Linux system). 53 | 54 | 55 | HOW TO RUN 56 | ========== 57 | 58 | Every call has 2 sides: The dialing side and the side answering the call. 59 | Callgen323 can act as either side (or both if you start 2 instances). 60 | 61 | If you want to test a H.323 endpoint, you can let it wait for calls and 62 | have callgen323 call it or you can start callgen323 in listening mode (-l) and 63 | let the endpoint dial out to it. 64 | 65 | if you want to test a gatekeeper or gateway, you would start one instance 66 | of callgen323 in listening mode and one in dialing mode. 67 | 68 | By default calls are made audio-only. Use command lines switches to enable video and H.239. 69 | 70 | Examples 71 | -------- 72 | 73 | Start in listening mode (no gatekeeper) and allow it to receive a maximum of 5 concurrent calls: 74 | callgen323 -n -m 5 -l 75 | 76 | Start in dialing mode, 5 concurrent calls, dialing IP 1.2.3.4 77 | callgen -n -m 5 1.2.4 78 | 79 | Start in dialing mode, register to a gatekeeper using H.460.18 and H.460.19 RTP multiplexing, 80 | enable H.264 video and sending of H.239: 81 | PWLIBPLUGINDIR=/usr/local/lib/pwlib 82 | callgen323 -g 192.168.1.189 --h46018enable --h46019multiplexenable -b 768 -v -P H.264 --h239enable -m 10 -r 1 1.2.3.4 83 | 84 | Make sure you have compiled and installed the H323Plus H.264 video codec in /usr/local/lib/pwlib before you do this. 85 | 86 | 87 | You can run both instances in a single host if you want, as long as 88 | you have two IP interfaces on your host. All you need to do is to 89 | specify different IP or port to listen for each callgen (with 90 | the -i option). 91 | 92 | Audio files for OGM messages must be 16bit Microsoft PCM files 93 | in WAV format at 8000 Hz (like the supplied ogm.wav). 94 | 95 | 96 | Limitations 97 | ----------- 98 | 99 | Establishing lots of calls uses lots of resources. Make sure the process get enough resources. 100 | On Linux set 101 | 102 | ulimit -n 10240 103 | ulimit -s unlimited 104 | 105 | You can also start multiple instances of callgen323 to produce more calls. 106 | 107 | 108 | COMMAND LINE OPTIONS (SELECTED) 109 | =============================== 110 | -h Show usage with all command line options 111 | -l Passive/listening mode 112 | -m --max num Maximum number of simultaneous calls 113 | -r --repeat num Repeat calls n times 114 | -C --cycle Each simultaneous call cycles through destination list 115 | -t --trace Trace enable (use multiple times for more detail) 116 | -o --output file Specify filename for trace output [stdout] 117 | -i --interface addr Specify IP address and port listen on [*:1720] 118 | -g --gatekeeper host Specify gatekeeper host [auto-discover] 119 | --mediaenc Enable Media encryption (value max cipher 128, 192 or 256) 120 | --maxtoken Set max token size for H.235.6 (1024, 2048, 4096, ...) 121 | -k --h46017 Use H.460.17 Gatekeeper 122 | --h46018enable Enable H.460.18/.19 123 | --h46019multiplexenable Enable H.460.19 RTP multiplexing 124 | --h46023enable Enable H.460.23/.24 125 | --h239enable Enable sending and receiving H.239 presentations 126 | --h239videopattern Set video pattern to send for H.239, eg. 'Fake', 'Fake/BouncingBoxes' or 'Fake/MovingBlocks' 127 | -n --no-gatekeeper Disable gatekeeper discovery [false] 128 | --require-gatekeeper Exit if gatekeeper discovery fails [false] 129 | -u --user username Specify local username [login name] 130 | -p --password pwd Specify gatekeeper H.235 password [none] 131 | -P --prefer codec Set codec preference (use multiple times) [none] 132 | -D --disable codec Disable codec (use multiple times) [none] 133 | -b -- bandwidth kbps Specify bandwidth per call 134 | -v --video Enable Video Support 135 | --videopattern Set video pattern to send, eg. 'Fake', 'Fake/BouncingBoxes' or 'Fake/MovingBlocks' 136 | -R --framerate n Set frame rate for outgoing video (fps) 137 | --maxframe name Maximum Frame Size (qcif, cif, 4cif, 16cif, 480i, 720p, 1080i) 138 | --tls TLS Enabled (must be set for TLS). 139 | --tls-cafile TLS Certificate Authority File. 140 | --tls-cert TLS Certificate File. 141 | --tls-privkey TLS Private Key File. 142 | --tls-passphrase TLS Private Key PassPhrase. 143 | --tls-listenport TLS listen port (default: 1300). 144 | -f --fast-disable Disable fast start 145 | -T --h245tunneldisable Disable H245 tunneling 146 | -O --out-msg file Specify PCM16 WAV file for outgoing message [ogm.wav] 147 | -I --in-dir dir Specify directory for incoming WAV files [disabled] 148 | -c --cdr file Specify Call Detail Record file [none] 149 | --tcp-base port Specific the base TCP port to use 150 | --tcp-max port Specific the maximum TCP port to use 151 | --udp-base port Specific the base UDP port to use 152 | --udp-max port Specific the maximum UDP port to use 153 | --rtp-base port Specific the base RTP/RTCP pair of UDP port to use 154 | --rtp-max port Specific the maximum RTP/RTCP pair of UDP port to use 155 | --tmaxest secs Maximum time to wait for "Established" [0] 156 | --tmincall secs Minimum call duration in seconds [10] 157 | --tmaxcall secs Maximum call duration in seconds [30] 158 | --tminwait secs Minimum interval between calls in seconds [10] 159 | --tmaxwait secs Maximum interval between calls in seconds [30] 160 | --fuzzing Enable RTP fuzzing 161 | --fuzz-header Percentage of RTP header to randomly overwrite [50] 162 | --fuzz-media Percentage of RTP media to randomly overwrite [0] 163 | --fuzz-rtcp Percentage of RTCP to randomly overwrite [5] 164 | 165 | 166 | -------------------------------------------------------------------------------- /callgen323.vcproj: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 10 | 11 | 12 | 19 | 36 | 38 | 48 | 52 | 54 | 56 | 58 | 62 | 64 | 66 | 68 | 70 | 72 | 73 | 80 | 96 | 98 | 108 | 112 | 114 | 116 | 118 | 122 | 124 | 126 | 128 | 130 | 132 | 133 | 140 | 158 | 160 | 170 | 174 | 176 | 178 | 180 | 184 | 186 | 188 | 190 | 192 | 194 | 195 | 196 | 197 | 198 | 199 | 202 | 204 | 206 | 212 | 213 | 215 | 220 | 221 | 223 | 228 | 229 | 230 | 232 | 234 | 241 | 242 | 244 | 250 | 251 | 253 | 259 | 260 | 261 | 262 | 265 | 267 | 268 | 270 | 271 | 272 | 275 | 276 | 277 | 278 | 279 | 280 | -------------------------------------------------------------------------------- /callgen323_2005.vcproj: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 12 | 13 | 14 | 15 | 16 | 25 | 28 | 31 | 34 | 37 | 42 | 60 | 63 | 68 | 71 | 82 | 85 | 88 | 91 | 94 | 97 | 100 | 103 | 106 | 107 | 116 | 119 | 122 | 125 | 128 | 133 | 150 | 153 | 158 | 161 | 172 | 175 | 178 | 181 | 184 | 187 | 190 | 193 | 196 | 197 | 206 | 209 | 212 | 215 | 218 | 223 | 242 | 245 | 250 | 253 | 264 | 267 | 270 | 273 | 276 | 279 | 282 | 285 | 288 | 289 | 290 | 291 | 292 | 293 | 297 | 300 | 303 | 310 | 311 | 314 | 320 | 321 | 324 | 330 | 331 | 332 | 335 | 338 | 346 | 347 | 350 | 357 | 358 | 361 | 368 | 369 | 370 | 371 | 375 | 378 | 379 | 382 | 383 | 384 | 388 | 389 | 390 | 391 | 392 | 393 | -------------------------------------------------------------------------------- /callgen323_2008.vcproj: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 14 | 15 | 16 | 17 | 18 | 27 | 30 | 33 | 36 | 39 | 44 | 62 | 65 | 70 | 73 | 86 | 89 | 92 | 95 | 98 | 101 | 104 | 107 | 108 | 117 | 120 | 123 | 126 | 129 | 134 | 151 | 154 | 159 | 162 | 175 | 178 | 181 | 184 | 187 | 190 | 193 | 196 | 197 | 206 | 209 | 212 | 215 | 218 | 223 | 242 | 245 | 250 | 253 | 266 | 269 | 272 | 275 | 278 | 281 | 284 | 287 | 288 | 289 | 290 | 291 | 292 | 296 | 299 | 302 | 309 | 310 | 313 | 319 | 320 | 323 | 329 | 330 | 331 | 334 | 337 | 345 | 346 | 349 | 356 | 357 | 360 | 367 | 368 | 369 | 370 | 374 | 377 | 378 | 381 | 382 | 383 | 387 | 388 | 389 | 390 | 391 | 392 | -------------------------------------------------------------------------------- /main.h: -------------------------------------------------------------------------------- 1 | /* 2 | * main.h 3 | * 4 | * H.323 call generator 5 | * 6 | * Copyright (c) 2001 Benny L. Prijono 7 | * Copyright (c) 2008-2018 Jan Willamowius 8 | * 9 | * The contents of this file are subject to the Mozilla Public License 10 | * Version 1.0 (the "License"); you may not use this file except in 11 | * compliance with the License. You may obtain a copy of the License at 12 | * https://www.mozilla.org/MPL/ 13 | * 14 | * Software distributed under the License is distributed on an "AS IS" 15 | * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See 16 | * the License for the specific language governing rights and limitations 17 | * under the License. 18 | * 19 | * The Original Code is CallGen323. 20 | * 21 | * The Initial Developer of the Original Code is Benny L. Prijono 22 | * 23 | * Contributor(s): Equivalence Pty. Ltd. 24 | * 25 | */ 26 | 27 | 28 | #include 29 | #include 30 | 31 | #include 32 | #include 33 | 34 | #if !defined(P_USE_STANDARD_CXX_BOOL) && !defined(P_USE_INTEGER_BOOL) 35 | typedef int PBoolean; 36 | #endif 37 | 38 | /////////////////////////////////////////////////////////////////////////////// 39 | 40 | class PlayMessage : public PDelayChannel 41 | { 42 | PCLASSINFO(PlayMessage, PDelayChannel); 43 | public: 44 | PlayMessage(const PString & filename, unsigned frameDelay, unsigned frameSize); 45 | virtual PBoolean Read(void *, PINDEX); 46 | virtual PBoolean Close(); 47 | protected: 48 | PWAVFile wavFile; 49 | }; 50 | 51 | 52 | /////////////////////////////////////////////////////////////////////////////// 53 | 54 | class RecordMessage : public PDelayChannel 55 | { 56 | PCLASSINFO(RecordMessage, PDelayChannel); 57 | public: 58 | RecordMessage(const PString & filename, unsigned frameDelay, unsigned frameSize); 59 | virtual PBoolean Write(const void *, PINDEX); 60 | virtual PBoolean Close(); 61 | protected: 62 | PBoolean reallyClose; 63 | }; 64 | 65 | /////////////////////////////////////////////////////////////////////////////// 66 | 67 | class MyH323EndPoint; 68 | 69 | class RTPFuzzingChannel : public H323_ExternalRTPChannel 70 | { 71 | PCLASSINFO(RTPFuzzingChannel, H323_ExternalRTPChannel); 72 | public: 73 | RTPFuzzingChannel(MyH323EndPoint & ep, H323Connection & connection, const H323Capability & capability, Directions direction, unsigned sessionID, WORD rtpPort, WORD rtcpPort); 74 | virtual ~RTPFuzzingChannel(); 75 | 76 | virtual PBoolean Start(); 77 | PDECLARE_NOTIFIER(PTimer, RTPFuzzingChannel, TransmitRTP); 78 | PDECLARE_NOTIFIER(PTimer, RTPFuzzingChannel, TransmitRTCP); 79 | 80 | protected: 81 | PUDPSocket m_rtpSocket; 82 | PUDPSocket m_rtcpSocket; 83 | RTP_DataFrame m_rtpPacket; 84 | PTimer m_rtpTransmitTimer; 85 | PTimer m_rtcpTransmitTimer; 86 | unsigned m_frameTime; 87 | unsigned m_frameTimeUnits; 88 | RTP_DataFrame::PayloadTypes m_payloadType; 89 | DWORD m_syncSource; 90 | DWORD m_timestamp; 91 | unsigned m_percentBadRTPHeader; 92 | unsigned m_percentBadRTPMedia; 93 | unsigned m_percentBadRTCP; 94 | }; 95 | 96 | /////////////////////////////////////////////////////////////////////////////// 97 | 98 | struct CallDetail 99 | { 100 | CallDetail() 101 | : openedTransmitMedia(0), 102 | openedReceiveMedia(0), 103 | receivedMedia(0), 104 | receivedAudio(false), 105 | receivedVideo(false) 106 | { } 107 | 108 | PTime openedTransmitMedia; 109 | PTime openedReceiveMedia; 110 | PTime receivedMedia; 111 | bool receivedAudio; 112 | bool receivedVideo; 113 | H323TransportAddress mediaGateway; 114 | 115 | void Drop(H323Connection & connection); 116 | 117 | void OnRTPStatistics(const RTP_Session & session, const PString & token); 118 | }; 119 | 120 | 121 | /////////////////////////////////////////////////////////////////////////////// 122 | 123 | class MyH323EndPoint; 124 | 125 | class MyH323Connection : public H323Connection 126 | { 127 | PCLASSINFO(MyH323Connection, H323Connection); 128 | public: 129 | MyH323Connection(MyH323EndPoint & ep, unsigned callRef); 130 | virtual ~MyH323Connection(); 131 | 132 | virtual PBoolean OnSendSignalSetup(H323SignalPDU & setupPDU); 133 | 134 | virtual PBoolean OpenAudioChannel( 135 | PBoolean isEncoding, /// Direction of data flow 136 | unsigned bufferSize, /// Size of each audio buffer 137 | H323AudioCodec & codec /// codec that is doing the opening 138 | ); 139 | 140 | #ifdef H323_VIDEO 141 | virtual PBoolean OpenVideoChannel(PBoolean isEncoding, H323VideoCodec & codec); 142 | #ifdef H323_H239 143 | void StartH239Transmission(); 144 | void StopH239Transmission(); 145 | PDECLARE_NOTIFIER(PTimer, MyH323Connection, StartH239TransmissionTrigger); 146 | PDECLARE_NOTIFIER(PTimer, MyH323Connection, StopH239TransmissionTrigger); 147 | virtual void OnEstablished(); 148 | virtual PBoolean OnInitialFlowRestriction(H323Channel & channel); 149 | virtual PBoolean OpenExtendedVideoChannel(PBoolean isEncoding, H323VideoCodec & codec); 150 | #endif 151 | #endif 152 | 153 | virtual H323Channel * CreateRealTimeLogicalChannel(const H323Capability & capability, H323Channel::Directions dir, 154 | unsigned sessionID, const H245_H2250LogicalChannelParameters * param, RTP_QOS * rtpqos = NULL); 155 | 156 | virtual void OnRTPStatistics(const RTP_Session & session) const; 157 | 158 | CallDetail details; 159 | 160 | protected: 161 | MyH323EndPoint & endpoint; 162 | PVideoChannel * videoChannelIn; 163 | PVideoChannel * videoChannelOut; 164 | map m_sessionPorts; 165 | bool m_isH239ready; 166 | bool m_haveStartedH239; 167 | PTimer m_h239StartTimer; 168 | PTimer m_h239StopTimer; 169 | }; 170 | 171 | /////////////////////////////////////////////////////////////////////////////// 172 | 173 | class MyH323EndPoint : public H323EndPoint 174 | { 175 | PCLASSINFO(MyH323EndPoint, H323EndPoint); 176 | public: 177 | MyH323EndPoint(); 178 | 179 | // override from H323EndPoint 180 | virtual H323Connection * CreateConnection(unsigned callReference); 181 | 182 | virtual void OnConnectionEstablished( 183 | H323Connection & connection, /// Connection that was established 184 | const PString & token /// Token for identifying connection 185 | ); 186 | virtual void OnConnectionCleared( 187 | H323Connection & connection, /// Connection that was established 188 | const PString & token /// Token for identifying connection 189 | ); 190 | virtual PBoolean OnStartLogicalChannel(H323Connection & connection, H323Channel & PTRACE_channel); 191 | virtual PBoolean SetVideoFrameSize(H323Capability::CapabilityFrameSize frameSize, int frameUnits = 1); 192 | virtual H323Capability::CapabilityFrameSize GetMaxFrameSize() const { return m_maxFrameSize; } 193 | 194 | // TODO: include in codec negotiations, only sets bearer capabilities right now 195 | void SetPerCallBandwidth(unsigned bw) { m_rateMultiplier = ceil((float)bw / 64); } 196 | BYTE GetRateMultiplier() const { return m_rateMultiplier; } 197 | 198 | void SetVideoPattern(const PString & pattern, bool isH239 = false) { if (isH239) m_h239videoPattern = pattern; else m_videoPattern = pattern; } 199 | PString GetVideoPattern(bool isH239) const { return isH239 ? m_h239videoPattern : m_videoPattern; } 200 | 201 | void SetFrameRate(unsigned fps) { m_frameRate = fps; } 202 | unsigned GetFrameRate() const { return m_frameRate; } 203 | 204 | void SetFuzzing(bool val) { m_fuzzing = val; } 205 | bool IsFuzzing() const { return m_fuzzing; } 206 | void SetPercentBadRTPHeader(unsigned val) { m_percentBadRTPHeader = val; } 207 | unsigned GetPercentBadRTPHeader() const { return m_percentBadRTPHeader; } 208 | void SetPercentBadRTPMedia(unsigned val) { m_percentBadRTPMedia = val; } 209 | unsigned GetPercentBadRTPMedia() const { return m_percentBadRTPMedia; } 210 | void SetPercentBadRTCP(unsigned val) { m_percentBadRTCP = val; } 211 | unsigned GetPercentBadRTCP() const { return m_percentBadRTCP; } 212 | 213 | void SetStartH239(bool start) { m_startH239 = start; } 214 | bool IsStartH239() const { return m_startH239; } 215 | 216 | void SetH239Delay(int delay) { m_h239delay = delay; } 217 | int GetH239Delay() { return m_h239delay; } 218 | void SetH239Duration(int duration) { m_h239duration = duration; } 219 | int GetH239Duration() { return m_h239duration; } 220 | 221 | protected: 222 | BYTE m_rateMultiplier; 223 | PString m_videoPattern; 224 | PString m_h239videoPattern; 225 | unsigned m_frameRate; 226 | H323Capability::CapabilityFrameSize m_maxFrameSize; 227 | bool m_fuzzing; 228 | unsigned m_percentBadRTPHeader; 229 | unsigned m_percentBadRTPMedia; 230 | unsigned m_percentBadRTCP; 231 | bool m_startH239; 232 | int m_h239delay; 233 | int m_h239duration; 234 | }; 235 | 236 | /////////////////////////////////////////////////////////////////////////////// 237 | 238 | class CallGen; 239 | 240 | struct CallParams 241 | { 242 | CallParams(CallGen & app) 243 | : callgen(app), repeat(0) { } 244 | 245 | CallGen & callgen; 246 | 247 | unsigned repeat; 248 | PTimeInterval tmax_est; 249 | PTimeInterval tmin_call; 250 | PTimeInterval tmax_call; 251 | PTimeInterval tmin_wait; 252 | PTimeInterval tmax_wait; 253 | }; 254 | 255 | 256 | /////////////////////////////////////////////////////////////////////////////// 257 | 258 | class CallThread : public PThread 259 | { 260 | PCLASSINFO(CallThread, PThread); 261 | public: 262 | CallThread( 263 | unsigned index, 264 | const PStringArray & destinations, 265 | const CallParams & params 266 | ); 267 | void Main(); 268 | void Stop(); 269 | 270 | protected: 271 | PStringArray destinations; 272 | unsigned index; 273 | CallParams params; 274 | PSyncPoint exit; 275 | }; 276 | 277 | PLIST(CallThreadList, CallThread); 278 | 279 | 280 | /////////////////////////////////////////////////////////////////////////////// 281 | 282 | class CallGen : public PProcess 283 | { 284 | PCLASSINFO(CallGen, PProcess) 285 | 286 | public: 287 | CallGen(); 288 | void Main(); 289 | static CallGen & Current() { return (CallGen&)PProcess::Current(); } 290 | 291 | PString outgoingMessageFile; 292 | PString incomingAudioDirectory; 293 | PTextFile cdrFile; 294 | 295 | PSyncPoint threadEnded; 296 | unsigned totalAttempts; 297 | unsigned totalEstablished; 298 | PMutex coutMutex; 299 | 300 | MyH323EndPoint * h323; 301 | 302 | PBoolean Start(const PString & destination, PString & token) { 303 | return h323->MakeCall(destination, token) != NULL; 304 | } 305 | PBoolean Exists(const PString & token) { 306 | return h323->HasConnection(token); 307 | } 308 | PBoolean IsEstablished(const PString & token) { 309 | return h323->IsConnectionEstablished(token); 310 | } 311 | PBoolean Clear(PString & token) { 312 | return h323->ClearCallSynchronous(token); 313 | } 314 | void ClearAll() { 315 | h323->ClearAllCalls(); 316 | } 317 | 318 | protected: 319 | PDECLARE_NOTIFIER(PThread, CallGen, Cancel); 320 | PConsoleChannel console; 321 | CallThreadList threadList; 322 | }; 323 | 324 | 325 | /////////////////////////////////////////////////////////////////////////////// 326 | -------------------------------------------------------------------------------- /license.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Mozilla Public License version 1.1 5 | 16 | 17 | 18 |

(Plain text version)

19 |

Mozilla Public License Version 1.1

20 |

1. Definitions.

21 |
22 |
1.0.1. "Commercial Use" 23 |
means distribution or otherwise making the Covered Code available to a third party. 24 |
1.1. "Contributor" 25 |
means each entity that creates or contributes to the creation of Modifications. 26 |
1.2. "Contributor Version" 27 |
means the combination of the Original Code, prior Modifications used by a Contributor, 28 | and the Modifications made by that particular Contributor. 29 |
1.3. "Covered Code" 30 |
means the Original Code or Modifications or the combination of the Original Code and 31 | Modifications, in each case including portions thereof. 32 |
1.4. "Electronic Distribution Mechanism" 33 |
means a mechanism generally accepted in the software development community for the 34 | electronic transfer of data. 35 |
1.5. "Executable" 36 |
means Covered Code in any form other than Source Code. 37 |
1.6. "Initial Developer" 38 |
means the individual or entity identified as the Initial Developer in the Source Code 39 | notice required by Exhibit A. 40 |
1.7. "Larger Work" 41 |
means a work which combines Covered Code or portions thereof with code not governed 42 | by the terms of this License. 43 |
1.8. "License" 44 |
means this document. 45 |
1.8.1. "Licensable" 46 |
means having the right to grant, to the maximum extent possible, whether at the 47 | time of the initial grant or subsequently acquired, any and all of the rights 48 | conveyed herein. 49 |
1.9. "Modifications" 50 |
51 |

means any addition to or deletion from the substance or structure of either the 52 | Original Code or any previous Modifications. When Covered Code is released as a 53 | series of files, a Modification is: 54 |

    55 |
  1. Any addition to or deletion from the contents of a file 56 | containing Original Code or previous Modifications. 57 |
  2. Any new file that contains any part of the Original Code or 58 | previous Modifications. 59 |
60 |
1.10. "Original Code" 61 |
means Source Code of computer software code which is described in the Source Code 62 | notice required by Exhibit A as Original Code, and which, 63 | at the time of its release under this License is not already Covered Code governed 64 | by this License. 65 |
1.10.1. "Patent Claims" 66 |
means any patent claim(s), now owned or hereafter acquired, including without 67 | limitation, method, process, and apparatus claims, in any patent Licensable by 68 | grantor. 69 |
1.11. "Source Code" 70 |
means the preferred form of the Covered Code for making modifications to it, 71 | including all modules it contains, plus any associated interface definition files, 72 | scripts used to control compilation and installation of an Executable, or source 73 | code differential comparisons against either the Original Code or another well known, 74 | available Covered Code of the Contributor's choice. The Source Code can be in a 75 | compressed or archival form, provided the appropriate decompression or de-archiving 76 | software is widely available for no charge. 77 |
1.12. "You" (or "Your") 78 |
means an individual or a legal entity exercising rights under, and complying with 79 | all of the terms of, this License or a future version of this License issued under 80 | Section 6.1. For legal entities, "You" includes any entity 81 | which controls, is controlled by, or is under common control with You. For purposes of 82 | this definition, "control" means (a) the power, direct or indirect, to cause the 83 | direction or management of such entity, whether by contract or otherwise, or (b) 84 | ownership of more than fifty percent (50%) of the outstanding shares or beneficial 85 | ownership of such entity. 86 |
87 |

2. Source Code License.

88 |

2.1. The Initial Developer Grant.

89 |

The Initial Developer hereby grants You a world-wide, royalty-free, non-exclusive 90 | license, subject to third party intellectual property claims: 91 |

    92 |
  1. under intellectual property rights (other than patent or 93 | trademark) Licensable by Initial Developer to use, reproduce, modify, display, perform, 94 | sublicense and distribute the Original Code (or portions thereof) with or without 95 | Modifications, and/or as part of a Larger Work; and 96 |
  2. under Patents Claims infringed by the making, using or selling 97 | of Original Code, to make, have made, use, practice, sell, and offer for sale, and/or 98 | otherwise dispose of the Original Code (or portions thereof). 99 |
  3. the licenses granted in this Section 2.1 100 | (a) and (b) are effective on 101 | the date Initial Developer first distributes Original Code under the terms of this 102 | License. 103 |
  4. Notwithstanding Section 2.1 (b) 104 | above, no patent license is granted: 1) for code that You delete from the Original Code; 105 | 2) separate from the Original Code; or 3) for infringements caused by: i) the 106 | modification of the Original Code or ii) the combination of the Original Code with other 107 | software or devices. 108 |
109 |

2.2. Contributor Grant.

110 |

Subject to third party intellectual property claims, each Contributor hereby grants You 111 | a world-wide, royalty-free, non-exclusive license 112 |

    113 |
  1. under intellectual property rights (other than patent or trademark) 114 | Licensable by Contributor, to use, reproduce, modify, display, perform, sublicense and 115 | distribute the Modifications created by such Contributor (or portions thereof) either on 116 | an unmodified basis, with other Modifications, as Covered Code and/or as part of a Larger 117 | Work; and 118 |
  2. under Patent Claims infringed by the making, using, or selling of 119 | Modifications made by that Contributor either alone and/or in combination with its 120 | Contributor Version (or portions of such combination), to make, use, sell, offer for 121 | sale, have made, and/or otherwise dispose of: 1) Modifications made by that Contributor 122 | (or portions thereof); and 2) the combination of Modifications made by that Contributor 123 | with its Contributor Version (or portions of such combination). 124 |
  3. the licenses granted in Sections 2.2 125 | (a) and 2.2 (b) are effective 126 | on the date Contributor first makes Commercial Use of the Covered Code. 127 |
  4. Notwithstanding Section 2.2 (b) 128 | above, no patent license is granted: 1) for any code that Contributor has deleted from 129 | the Contributor Version; 2) separate from the Contributor Version; 3) for infringements 130 | caused by: i) third party modifications of Contributor Version or ii) the combination of 131 | Modifications made by that Contributor with other software (except as part of the 132 | Contributor Version) or other devices; or 4) under Patent Claims infringed by Covered Code 133 | in the absence of Modifications made by that Contributor. 134 |
135 |

3. Distribution Obligations.

136 |

3.1. Application of License.

137 |

The Modifications which You create or to which You contribute are governed by the terms 138 | of this License, including without limitation Section 2.2. The 139 | Source Code version of Covered Code may be distributed only under the terms of this License 140 | or a future version of this License released under Section 6.1, 141 | and You must include a copy of this License with every copy of the Source Code You 142 | distribute. You may not offer or impose any terms on any Source Code version that alters or 143 | restricts the applicable version of this License or the recipients' rights hereunder. 144 | However, You may include an additional document offering the additional rights described in 145 | Section 3.5. 146 |

3.2. Availability of Source Code.

147 |

Any Modification which You create or to which You contribute must be made available in 148 | Source Code form under the terms of this License either on the same media as an Executable 149 | version or via an accepted Electronic Distribution Mechanism to anyone to whom you made an 150 | Executable version available; and if made available via Electronic Distribution Mechanism, 151 | must remain available for at least twelve (12) months after the date it initially became 152 | available, or at least six (6) months after a subsequent version of that particular 153 | Modification has been made available to such recipients. You are responsible for ensuring 154 | that the Source Code version remains available even if the Electronic Distribution 155 | Mechanism is maintained by a third party. 156 |

3.3. Description of Modifications.

157 |

You must cause all Covered Code to which You contribute to contain a file documenting the 158 | changes You made to create that Covered Code and the date of any change. You must include a 159 | prominent statement that the Modification is derived, directly or indirectly, from Original 160 | Code provided by the Initial Developer and including the name of the Initial Developer in 161 | (a) the Source Code, and (b) in any notice in an Executable version or related documentation 162 | in which You describe the origin or ownership of the Covered Code. 163 |

3.4. Intellectual Property Matters

164 |

(a) Third Party Claims

165 |

If Contributor has knowledge that a license under a third party's intellectual property 166 | rights is required to exercise the rights granted by such Contributor under Sections 167 | 2.1 or 2.2, Contributor must include a 168 | text file with the Source Code distribution titled "LEGAL" which describes the claim and the 169 | party making the claim in sufficient detail that a recipient will know whom to contact. If 170 | Contributor obtains such knowledge after the Modification is made available as described in 171 | Section 3.2, Contributor shall promptly modify the LEGAL file in 172 | all copies Contributor makes available thereafter and shall take other steps (such as 173 | notifying appropriate mailing lists or newsgroups) reasonably calculated to inform those who 174 | received the Covered Code that new knowledge has been obtained. 175 |

(b) Contributor APIs

176 |

If Contributor's Modifications include an application programming interface and Contributor 177 | has knowledge of patent licenses which are reasonably necessary to implement that 178 | API, Contributor must also include this information in the 179 | legal file. 180 |

(c) Representations.

181 |

Contributor represents that, except as disclosed pursuant to Section 3.4 182 | (a) above, Contributor believes that Contributor's Modifications 183 | are Contributor's original creation(s) and/or Contributor has sufficient rights to grant the 184 | rights conveyed by this License. 185 |

3.5. Required Notices.

186 |

You must duplicate the notice in Exhibit A in each file of the 187 | Source Code. If it is not possible to put such notice in a particular Source Code file due to 188 | its structure, then You must include such notice in a location (such as a relevant directory) 189 | where a user would be likely to look for such a notice. If You created one or more 190 | Modification(s) You may add your name as a Contributor to the notice described in 191 | Exhibit A. You must also duplicate this License in any documentation 192 | for the Source Code where You describe recipients' rights or ownership rights relating to 193 | Covered Code. You may choose to offer, and to charge a fee for, warranty, support, indemnity 194 | or liability obligations to one or more recipients of Covered Code. However, You may do so 195 | only on Your own behalf, and not on behalf of the Initial Developer or any Contributor. You 196 | must make it absolutely clear than any such warranty, support, indemnity or liability 197 | obligation is offered by You alone, and You hereby agree to indemnify the Initial Developer 198 | and every Contributor for any liability incurred by the Initial Developer or such Contributor 199 | as a result of warranty, support, indemnity or liability terms You offer. 200 |

3.6. Distribution of Executable Versions.

201 |

You may distribute Covered Code in Executable form only if the requirements of Sections 202 | 3.1, 3.2, 203 | 3.3, 3.4 and 204 | 3.5 have been met for that Covered Code, and if You include a 205 | notice stating that the Source Code version of the Covered Code is available under the terms 206 | of this License, including a description of how and where You have fulfilled the obligations 207 | of Section 3.2. The notice must be conspicuously included in any 208 | notice in an Executable version, related documentation or collateral in which You describe 209 | recipients' rights relating to the Covered Code. You may distribute the Executable version of 210 | Covered Code or ownership rights under a license of Your choice, which may contain terms 211 | different from this License, provided that You are in compliance with the terms of this 212 | License and that the license for the Executable version does not attempt to limit or alter the 213 | recipient's rights in the Source Code version from the rights set forth in this License. If 214 | You distribute the Executable version under a different license You must make it absolutely 215 | clear that any terms which differ from this License are offered by You alone, not by the 216 | Initial Developer or any Contributor. You hereby agree to indemnify the Initial Developer and 217 | every Contributor for any liability incurred by the Initial Developer or such Contributor as 218 | a result of any such terms You offer. 219 |

3.7. Larger Works.

220 |

You may create a Larger Work by combining Covered Code with other code not governed by the 221 | terms of this License and distribute the Larger Work as a single product. In such a case, 222 | You must make sure the requirements of this License are fulfilled for the Covered Code. 223 |

4. Inability to Comply Due to Statute or Regulation.

224 |

If it is impossible for You to comply with any of the terms of this License with respect to 225 | some or all of the Covered Code due to statute, judicial order, or regulation then You must: 226 | (a) comply with the terms of this License to the maximum extent possible; and (b) describe 227 | the limitations and the code they affect. Such description must be included in the 228 | legal file described in Section 229 | 3.4 and must be included with all distributions of the Source Code. 230 | Except to the extent prohibited by statute or regulation, such description must be 231 | sufficiently detailed for a recipient of ordinary skill to be able to understand it. 232 |

5. Application of this License.

233 |

This License applies to code to which the Initial Developer has attached the notice in 234 | Exhibit A and to related Covered Code. 235 |

6. Versions of the License.

236 |

6.1. New Versions

237 |

Netscape Communications Corporation ("Netscape") may publish revised and/or new versions 238 | of the License from time to time. Each version will be given a distinguishing version number. 239 |

6.2. Effect of New Versions

240 |

Once Covered Code has been published under a particular version of the License, You may 241 | always continue to use it under the terms of that version. You may also choose to use such 242 | Covered Code under the terms of any subsequent version of the License published by Netscape. 243 | No one other than Netscape has the right to modify the terms applicable to Covered Code 244 | created under this License. 245 |

6.3. Derivative Works

246 |

If You create or use a modified version of this License (which you may only do in order to 247 | apply it to code which is not already Covered Code governed by this License), You must (a) 248 | rename Your license so that the phrases "Mozilla", "MOZILLAPL", "MOZPL", "Netscape", "MPL", 249 | "NPL" or any confusingly similar phrase do not appear in your license (except to note that 250 | your license differs from this License) and (b) otherwise make it clear that Your version of 251 | the license contains terms which differ from the Mozilla Public License and Netscape Public 252 | License. (Filling in the name of the Initial Developer, Original Code or Contributor in the 253 | notice described in Exhibit A shall not of themselves be deemed to 254 | be modifications of this License.) 255 |

7. Disclaimer of warranty

256 |

Covered code is provided under this license on an "as is" 257 | basis, without warranty of any kind, either expressed or implied, including, without 258 | limitation, warranties that the covered code is free of defects, merchantable, fit for a 259 | particular purpose or non-infringing. The entire risk as to the quality and performance of 260 | the covered code is with you. Should any covered code prove defective in any respect, you 261 | (not the initial developer or any other contributor) assume the cost of any necessary 262 | servicing, repair or correction. This disclaimer of warranty constitutes an essential part 263 | of this license. No use of any covered code is authorized hereunder except under this 264 | disclaimer. 265 |

8. Termination

266 |

8.1. This License and the rights granted hereunder will terminate 267 | automatically if You fail to comply with terms herein and fail to cure such breach 268 | within 30 days of becoming aware of the breach. All sublicenses to the Covered Code which 269 | are properly granted shall survive any termination of this License. Provisions which, by 270 | their nature, must remain in effect beyond the termination of this License shall survive. 271 |

8.2. If You initiate litigation by asserting a patent infringement 272 | claim (excluding declatory judgment actions) against Initial Developer or a Contributor 273 | (the Initial Developer or Contributor against whom You file such action is referred to 274 | as "Participant") alleging that: 275 |

    276 |
  1. such Participant's Contributor Version directly or indirectly 277 | infringes any patent, then any and all rights granted by such Participant to You under 278 | Sections 2.1 and/or 2.2 of this 279 | License shall, upon 60 days notice from Participant terminate prospectively, unless if 280 | within 60 days after receipt of notice You either: (i) agree in writing to pay 281 | Participant a mutually agreeable reasonable royalty for Your past and future use of 282 | Modifications made by such Participant, or (ii) withdraw Your litigation claim with 283 | respect to the Contributor Version against such Participant. If within 60 days of 284 | notice, a reasonable royalty and payment arrangement are not mutually agreed upon in 285 | writing by the parties or the litigation claim is not withdrawn, the rights granted by 286 | Participant to You under Sections 2.1 and/or 287 | 2.2 automatically terminate at the expiration of the 60 day 288 | notice period specified above. 289 |
  2. any software, hardware, or device, other than such Participant's 290 | Contributor Version, directly or indirectly infringes any patent, then any rights 291 | granted to You by such Participant under Sections 2.1(b) 292 | and 2.2(b) are revoked effective as of the date You first 293 | made, used, sold, distributed, or had made, Modifications made by that Participant. 294 |
295 |

8.3. If You assert a patent infringement claim against Participant 296 | alleging that such Participant's Contributor Version directly or indirectly infringes 297 | any patent where such claim is resolved (such as by license or settlement) prior to the 298 | initiation of patent infringement litigation, then the reasonable value of the licenses 299 | granted by such Participant under Sections 2.1 or 300 | 2.2 shall be taken into account in determining the amount or 301 | value of any payment or license. 302 |

8.4. In the event of termination under Sections 303 | 8.1 or 8.2 above, all end user 304 | license agreements (excluding distributors and resellers) which have been validly 305 | granted by You or any distributor hereunder prior to termination shall survive 306 | termination. 307 |

9. Limitation of liability

308 |

Under no circumstances and under no legal theory, whether 309 | tort (including negligence), contract, or otherwise, shall you, the initial developer, 310 | any other contributor, or any distributor of covered code, or any supplier of any of 311 | such parties, be liable to any person for any indirect, special, incidental, or 312 | consequential damages of any character including, without limitation, damages for loss 313 | of goodwill, work stoppage, computer failure or malfunction, or any and all other 314 | commercial damages or losses, even if such party shall have been informed of the 315 | possibility of such damages. This limitation of liability shall not apply to liability 316 | for death or personal injury resulting from such party's negligence to the extent 317 | applicable law prohibits such limitation. Some jurisdictions do not allow the exclusion 318 | or limitation of incidental or consequential damages, so this exclusion and limitation 319 | may not apply to you. 320 |

10. U.S. government end users

321 |

The Covered Code is a "commercial item," as that term is defined in 48 322 | C.F.R. 2.101 (Oct. 1995), consisting of 323 | "commercial computer software" and "commercial computer software documentation," as such 324 | terms are used in 48 C.F.R. 12.212 (Sept. 325 | 1995). Consistent with 48 C.F.R. 12.212 and 48 C.F.R. 326 | 227.7202-1 through 227.7202-4 (June 1995), all U.S. Government End Users 327 | acquire Covered Code with only those rights set forth herein. 328 |

11. Miscellaneous

329 |

This License represents the complete agreement concerning subject matter hereof. If 330 | any provision of this License is held to be unenforceable, such provision shall be 331 | reformed only to the extent necessary to make it enforceable. This License shall be 332 | governed by California law provisions (except to the extent applicable law, if any, 333 | provides otherwise), excluding its conflict-of-law provisions. With respect to 334 | disputes in which at least one party is a citizen of, or an entity chartered or 335 | registered to do business in the United States of America, any litigation relating to 336 | this License shall be subject to the jurisdiction of the Federal Courts of the 337 | Northern District of California, with venue lying in Santa Clara County, California, 338 | with the losing party responsible for costs, including without limitation, court 339 | costs and reasonable attorneys' fees and expenses. The application of the United 340 | Nations Convention on Contracts for the International Sale of Goods is expressly 341 | excluded. Any law or regulation which provides that the language of a contract 342 | shall be construed against the drafter shall not apply to this License. 343 |

12. Responsibility for claims

344 |

As between Initial Developer and the Contributors, each party is responsible for 345 | claims and damages arising, directly or indirectly, out of its utilization of rights 346 | under this License and You agree to work with Initial Developer and Contributors to 347 | distribute such responsibility on an equitable basis. Nothing herein is intended or 348 | shall be deemed to constitute any admission of liability. 349 |

13. Multiple-licensed code

350 |

Initial Developer may designate portions of the Covered Code as 351 | "Multiple-Licensed". "Multiple-Licensed" means that the Initial Developer permits 352 | you to utilize portions of the Covered Code under Your choice of the MPL 353 | or the alternative licenses, if any, specified by the Initial Developer in the file 354 | described in Exhibit A. 355 |

Exhibit A - Mozilla Public License.

356 |
"The contents of this file are subject to the Mozilla Public License
357 | Version 1.1 (the "License"); you may not use this file except in
358 | compliance with the License. You may obtain a copy of the License at
359 | http://www.mozilla.org/MPL/
360 | 
361 | Software distributed under the License is distributed on an "AS IS"
362 | basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
363 | License for the specific language governing rights and limitations
364 | under the License.
365 | 
366 | The Original Code is ______________________________________.
367 | 
368 | The Initial Developer of the Original Code is ________________________.
369 | Portions created by ______________________ are Copyright (C) ______
370 | _______________________. All Rights Reserved.
371 | 
372 | Contributor(s): ______________________________________.
373 | 
374 | Alternatively, the contents of this file may be used under the terms
375 | of the _____ license (the  "[___] License"), in which case the
376 | provisions of [______] License are applicable instead of those
377 | above. If you wish to allow use of your version of this file only
378 | under the terms of the [____] License and not to allow others to use
379 | your version of this file under the MPL, indicate your decision by
380 | deleting the provisions above and replace them with the notice and
381 | other provisions required by the [___] License. If you do not delete
382 | the provisions above, a recipient may use your version of this file
383 | under either the MPL or the [___] License."
384 |

NOTE: The text of this Exhibit A may differ slightly from the text of 385 | the notices in the Source Code files of the Original Code. You should 386 | use the text of this Exhibit A rather than the text found in the 387 | Original Code Source Code for Your Modifications. 388 | 389 | 390 | -------------------------------------------------------------------------------- /main.cxx: -------------------------------------------------------------------------------- 1 | /* 2 | * main.cxx 3 | * 4 | * H.323 call generator 5 | * 6 | * Copyright (c) 2008-2018 Jan Willamowius 7 | * Copyright (c) 2001 Benny L. Prijono 8 | * 9 | * The contents of this file are subject to the Mozilla Public License 10 | * Version 1.0 (the "License"); you may not use this file except in 11 | * compliance with the License. You may obtain a copy of the License at 12 | * https://www.mozilla.org/MPL/ 13 | * 14 | * Software distributed under the License is distributed on an "AS IS" 15 | * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See 16 | * the License for the specific language governing rights and limitations 17 | * under the License. 18 | * 19 | * The Original Code is CallGen323. 20 | * 21 | * The Initial Developer of the Original Code is Benny L. Prijono 22 | * 23 | * Contributor(s): Equivalence Pty. Ltd. 24 | * 25 | */ 26 | 27 | #include 28 | #include "main.h" 29 | #include "version.h" 30 | 31 | #include 32 | #include 33 | #include 34 | 35 | #ifndef _WIN32 36 | #include 37 | #endif 38 | 39 | PCREATE_PROCESS(CallGen); 40 | 41 | /////////////////////////////////////////////////////////////////////////////// 42 | 43 | CallGen::CallGen() 44 | : PProcess("H323Plus", "CallGen", MAJOR_VERSION, MINOR_VERSION, BUILD_TYPE, BUILD_NUMBER), 45 | console(PConsoleChannel::StandardInput) 46 | { 47 | totalAttempts = 0; 48 | totalEstablished = 0; 49 | h323 = NULL; 50 | } 51 | 52 | void CallGen::Main() 53 | { 54 | #ifndef _WIN32 55 | signal(SIGCHLD, SIG_IGN); // avoid zombies from H.264 plugin helper 56 | #endif 57 | 58 | PArgList & args = GetArguments(); 59 | args.Parse("a-access-token-oid:" 60 | "b-bandwidth:" 61 | "c-cdr:" 62 | "C-cycle." 63 | "D-disable:" 64 | "f-fast-disable." 65 | "g-gatekeeper:" 66 | #ifdef H323_H235 67 | "-mediaenc:" 68 | "-maxtoken:" 69 | #endif 70 | #ifdef H323_H46017 71 | "k-h46017:" 72 | #endif 73 | #ifdef H323_H46018 74 | "-h46018enable." 75 | #endif 76 | #ifdef H323_H46019M 77 | "-h46019multiplexenable." 78 | #endif 79 | #ifdef H323_H46023 80 | "-h46023enable." 81 | #endif 82 | #ifdef H323_H239 83 | "-h239enable." 84 | "-h239videopattern:" 85 | "-h239delay:" 86 | "-h239duration:" 87 | #endif 88 | "I-in-dir:" 89 | "i-interface:" 90 | "l-listen." 91 | "m-max:" 92 | " -mcu." 93 | "n-no-gatekeeper." 94 | "O-out-msg:" 95 | "o-output:" 96 | "P-prefer:" 97 | "p-password:" 98 | "r-repeat:" 99 | "-require-gatekeeper." 100 | "T-h245tunneldisable." 101 | "t-trace." 102 | #ifdef H323_VIDEO 103 | "v-video." 104 | "-videopattern:" 105 | "R-framerate:" 106 | "-maxframe:" 107 | #endif 108 | #ifdef H323_TLS 109 | "-tls." 110 | "-tls-cafile:" 111 | "-tls-cert:" 112 | "-tls-privkey:" 113 | "-tls-passphrase:" 114 | "-tls-listenport:" 115 | #endif 116 | "-tmaxest:" 117 | "-tmincall:" 118 | "-tmaxcall:" 119 | "-tminwait:" 120 | "-tmaxwait:" 121 | "-tcp-base:" 122 | "-tcp-max:" 123 | "-udp-base:" 124 | "-udp-max:" 125 | "-rtp-base:" 126 | "-rtp-max:" 127 | "u-user:" 128 | "-fuzzing." 129 | "-fuzz-header:" 130 | "-fuzz-media:" 131 | "-fuzz-rtcp:" 132 | , FALSE); 133 | 134 | if (args.GetCount() == 0 && !args.HasOption('l')) { 135 | cout << "Usage:\n" 136 | " callgen [options] -l\n" 137 | " callgen [options] destination [ destination ... ]\n" 138 | "where options:\n" 139 | " -l Passive/listening mode\n" 140 | " -m --max num Maximum number of simultaneous calls\n" 141 | " --mcu Pose as MCU (to always win master/slave neg.)\n" 142 | " -r --repeat num Repeat calls n times\n" 143 | " -C --cycle Each simultaneous call cycles through destination list\n" 144 | " -t --trace Trace enable (use multiple times for more detail)\n" 145 | " -o --output file Specify filename for trace output [stdout]\n" 146 | " -i --interface addr Specify IP address and port listen on [*:1720]\n" 147 | " -g --gatekeeper host Specify gatekeeper host [auto-discover]\n" 148 | #ifdef H323_H235 149 | " --mediaenc Enable Media encryption (value max cipher 128, 192 or 256)\n" 150 | " --maxtoken Set max token size for H.235.6 (1024, 2048, 4096, ...)\n" 151 | #endif 152 | #ifdef H323_H46017 153 | " -k --h46017 Use H.460.17 Gatekeeper\n" 154 | #endif 155 | #ifdef H323_H46018 156 | " --h46018enable Enable H.460.18/.19\n" 157 | #endif 158 | #ifdef H323_H46019M 159 | " --h46019multiplexenable Enable H.460.19 RTP multiplexing\n" 160 | #endif 161 | #ifdef H323_H46023 162 | " --h46023enable Enable H.460.23/.24\n" 163 | #endif 164 | #ifdef H323_H239 165 | " --h239enable Enable sending and receiving H.239 presentations\n" 166 | " --h239videopattern Set video pattern to send for H.239, eg. 'Fake', 'Fake/BouncingBoxes' or 'Fake/MovingBlocks'\n" 167 | " --h239delay Delay the start of the H.239 transmission in seconds [1 sec]\n" 168 | " --h239duration Duration the H.239 transmission in seconds [-1 - unlimited]\n" 169 | #endif 170 | " -n --no-gatekeeper Disable gatekeeper discovery [false]\n" 171 | " --require-gatekeeper Exit if gatekeeper discovery fails [false]\n" 172 | " -u --user username Specify local username [login name]\n" 173 | " -p --password pwd Specify gatekeeper H.235 password [none]\n" 174 | " -P --prefer codec Set codec preference (use multiple times) [none]\n" 175 | " -D --disable codec Disable codec (use multiple times) [none]\n" 176 | " -b -- bandwidth kbps Specify bandwidth per call\n" 177 | #ifdef H323_VIDEO 178 | " -v --video Enable Video Support\n" 179 | " --videopattern Set video pattern to send, eg. 'Fake', 'Fake/BouncingBoxes' or 'Fake/MovingBlocks'\n" 180 | " -R --framerate n Set frame rate for outgoing video (fps)\n" 181 | " --maxframe name Maximum Frame Size (qcif, cif, 4cif, 16cif, 480i, 720p, 1080i)\n" 182 | #endif 183 | #ifdef H323_TLS 184 | " --tls TLS Enabled (must be set for TLS).\n" 185 | " --tls-cafile TLS Certificate Authority File.\n" 186 | " --tls-cert TLS Certificate File.\n" 187 | " --tls-privkey TLS Private Key File.\n" 188 | " --tls-passphrase TLS Private Key PassPhrase.\n" 189 | " --tls-listenport TLS listen port (default: 1300).\n" 190 | #endif 191 | " -f --fast-disable Disable fast start\n" 192 | " -T --h245tunneldisable Disable H245 tunneling\n" 193 | " -O --out-msg file Specify PCM16 WAV file for outgoing message [ogm.wav]\n" 194 | " -I --in-dir dir Specify directory for incoming WAV files [disabled]\n" 195 | " -c --cdr file Specify Call Detail Record file [none]\n" 196 | " --tcp-base port Specific the base TCP port to use\n" 197 | " --tcp-max port Specific the maximum TCP port to use\n" 198 | " --udp-base port Specific the base UDP port to use\n" 199 | " --udp-max port Specific the maximum UDP port to use\n" 200 | " --rtp-base port Specific the base RTP/RTCP pair of UDP port to use\n" 201 | " --rtp-max port Specific the maximum RTP/RTCP pair of UDP port to use\n" 202 | " --tmaxest secs Maximum time to wait for \"Established\" [0]\n" 203 | " --tmincall secs Minimum call duration in seconds [10]\n" 204 | " --tmaxcall secs Maximum call duration in seconds [30]\n" 205 | " --tminwait secs Minimum interval between calls in seconds [10]\n" 206 | " --tmaxwait secs Maximum interval between calls in seconds [30]\n" 207 | " --fuzzing Enable RTP fuzzing\n" 208 | " --fuzz-header Percentage of RTP header to randomly overwrite [50]\n" 209 | " --fuzz-media Percentage of RTP media to randomly overwrite [0]\n" 210 | " --fuzz-rtcp Percentage of RTCP to randomly overwrite [5]\n" 211 | "\n" 212 | "Notes:\n" 213 | " If --tmaxest is set a non-zero value then --tmincall is the time to leave\n" 214 | " the call running once established. If zero (the default) then --tmincall\n" 215 | " is the length of the call from initiation. The call may or may not be\n" 216 | " \"answered\" within that time.\n" 217 | "\n"; 218 | return; 219 | } 220 | 221 | #if PTRACING 222 | PTrace::Initialise(args.GetOptionCount('t'), 223 | args.HasOption('o') ? (const char *)args.GetOptionString('o') : NULL, 224 | PTrace::DateAndTime | PTrace::TraceLevel | PTrace::FileAndLine); 225 | #endif 226 | 227 | h323 = new MyH323EndPoint(); 228 | 229 | outgoingMessageFile = args.GetOptionString('O', "ogm.wav"); 230 | if (outgoingMessageFile.IsEmpty()) 231 | cout << "Not using outgoing message file." << endl; 232 | else if (PFile::Exists(outgoingMessageFile)) 233 | cout << "Using outgoing message file: " << outgoingMessageFile << endl; 234 | else { 235 | cout << "Outgoing message file \"" << outgoingMessageFile << "\" does not exist!" << endl; 236 | PTRACE(1, "CallGen\tOutgoing message file \"" << outgoingMessageFile << "\" does not exist"); 237 | outgoingMessageFile = PString::Empty(); 238 | } 239 | 240 | incomingAudioDirectory = args.GetOptionString('I'); 241 | if (incomingAudioDirectory.IsEmpty()) 242 | cout << "Not saving incoming audio data." << endl; 243 | else if (PDirectory::Exists(incomingAudioDirectory) || 244 | PDirectory::Create(incomingAudioDirectory)) { 245 | incomingAudioDirectory = PDirectory(incomingAudioDirectory); 246 | cout << "Using incoming audio directory: " << incomingAudioDirectory << endl; 247 | } 248 | else { 249 | cout << "Could not create incoming audio directory \"" << incomingAudioDirectory << "\"!" << endl; 250 | PTRACE(1, "CallGen\tCould not create incoming audio directory \"" << incomingAudioDirectory << '"'); 251 | incomingAudioDirectory = PString::Empty(); 252 | } 253 | 254 | // start the H.323 listener 255 | H323ListenerTCP * listener = NULL; 256 | PIPSocket::Address interfaceAddress(INADDR_ANY); 257 | WORD listenPort = H323EndPoint::DefaultTcpPort; 258 | if (args.HasOption('i')) { 259 | PString interface = args.GetOptionString('i'); 260 | PINDEX colon = interface.Find(":"); 261 | if (colon != P_MAX_INDEX) { 262 | interfaceAddress = interface.Left(colon); 263 | listenPort = interface.Mid(colon + 1).AsUnsigned(); 264 | } else { 265 | interfaceAddress = interface; 266 | } 267 | } 268 | 269 | listener = new H323ListenerTCP(*h323, interfaceAddress, listenPort); 270 | 271 | if (!h323->StartListener(listener)) { 272 | cout << "Could not open H.323 listener port on " << interfaceAddress << ":" << listener->GetListenerPort() << endl; 273 | delete listener; 274 | return; 275 | } 276 | 277 | cout << "H.323 listening on: " << setfill(',') << h323->GetListeners() << setfill(' ') << endl; 278 | 279 | if (args.HasOption('c')) { 280 | if (cdrFile.Open(args.GetOptionString('c'), PFile::WriteOnly, PFile::Create)) { 281 | cdrFile.SetPosition(0, PFile::End); 282 | PTRACE(1, "CallGen\tSetting CDR to \"" << cdrFile.GetFilePath() << '"'); 283 | cout << "Sending Call Detail Records to \"" << cdrFile.GetFilePath() << '"' << endl; 284 | } 285 | else { 286 | cout << "Could not open \"" << cdrFile.GetFilePath() << "\"!" << endl; 287 | } 288 | } 289 | 290 | if (args.HasOption("tcp-base")) 291 | h323->SetTCPPorts(args.GetOptionString("tcp-base").AsUnsigned(), 292 | args.GetOptionString("tcp-max").AsUnsigned()); 293 | if (args.HasOption("udp-base")) 294 | h323->SetUDPPorts(args.GetOptionString("udp-base").AsUnsigned(), 295 | args.GetOptionString("udp-max").AsUnsigned()); 296 | if (args.HasOption("rtp-base")) 297 | h323->SetRtpIpPorts(args.GetOptionString("rtp-base").AsUnsigned(), 298 | args.GetOptionString("rtp-max").AsUnsigned()); 299 | 300 | #ifdef H323_H239 301 | if (args.HasOption("h239enable")) { 302 | cout << "Enabling H.239" << endl; 303 | if (!args.HasOption('l')) { 304 | h323->SetStartH239(true); // only the calling call generator starts a H.239 channel 305 | 306 | int delay = (args.HasOption("h239delay")) ? args.GetOptionString("h239delay").AsInteger() : 1; 307 | h323->SetH239Delay(delay); 308 | 309 | int duration = (args.HasOption("h239duration")) ? args.GetOptionString("h239duration").AsInteger() : -1; 310 | h323->SetH239Duration(duration); 311 | } 312 | } else { 313 | cout << "Disabling H.239" << endl; 314 | h323->RemoveCapabilities(PStringArray("H.239")); 315 | } 316 | #endif 317 | h323->RemoveCapabilities(args.GetOptionString('D').Lines()); 318 | h323->ReorderCapabilities(args.GetOptionString('P').Lines()); 319 | cout << "Local capabilities:\n" << h323->GetCapabilities() << endl; 320 | 321 | // set local username, is necessary 322 | if (args.HasOption('u')) { 323 | PStringArray aliases = args.GetOptionString('u').Lines(); 324 | h323->SetLocalUserName(aliases[0]); 325 | for (PINDEX i = 1; i < aliases.GetSize(); ++i) 326 | h323->AddAliasName(aliases[i]); 327 | } 328 | cout << "Local username: \"" << h323->GetLocalUserName() << '"' << endl; 329 | 330 | if (args.HasOption("mcu")) { 331 | h323->SetTerminalType(H323EndPoint::e_MCUWithAVMP); // pose as MCU to always win H.245 master/slave negotiation 332 | cout << "Posing as MCU" << endl; 333 | } 334 | 335 | 336 | if (args.HasOption('p')) { 337 | h323->SetGatekeeperPassword(args.GetOptionString('p')); 338 | cout << "Using H.235 security." << endl; 339 | } 340 | 341 | #ifdef H323_TLS // Initialize TLS 342 | bool useTLS = args.HasOption("tls"); 343 | if (useTLS) { 344 | h323->DisableH245Tunneling(false); // Tunneling must be used with TLS 345 | if (args.HasOption("tls-cafile")) 346 | useTLS = h323->TLS_SetCAFile(args.GetOptionString("tls-cafile")); 347 | if (useTLS && args.HasOption("tls-cert")) 348 | useTLS = h323->TLS_SetCertificate(args.GetOptionString("tls-cert")); 349 | if (useTLS && args.HasOption("tls-privkey")) { 350 | PString passphrase = PString(); 351 | if (args.HasOption("tls-passphrase")) 352 | passphrase = args.GetOptionString("tls-passphrase"); 353 | useTLS = h323->TLS_SetPrivateKey(args.GetOptionString("tls-privkey"), passphrase); 354 | } 355 | WORD tlsListenPort = (WORD)args.GetOptionString("tls-listenport", "1300").AsUnsigned(); 356 | 357 | if (useTLS && h323->TLS_Initialise(interfaceAddress, tlsListenPort)) { 358 | cout << "Enabled TLS signal security." << endl; 359 | } else { 360 | cerr << "Could not enable TLS signal security." << endl; 361 | } 362 | } 363 | #endif 364 | 365 | if (args.HasOption('a')) { 366 | h323->SetGkAccessTokenOID(args.GetOptionString('a')); 367 | cout << "Set Access Token OID to \"" << h323->GetGkAccessTokenOID() << '"' << endl; 368 | } 369 | 370 | // process gatekeeper registration options 371 | #ifdef H323_H46017 372 | if (args.HasOption('k')) { 373 | PString gk17 = args.GetOptionString('k'); 374 | if (h323->H46017CreateConnection(gk17, false)) { 375 | PTRACE(2, "Using H.460.17 Gatekeeper Tunneling."); 376 | } else { 377 | cout << "Error: H.460.17 Gatekeeper Tunneling Failed: Gatekeeper=" << gk17 << endl; 378 | return; 379 | } 380 | } else 381 | #endif 382 | { 383 | if (args.HasOption('g')) { 384 | #ifdef H323_H46018 385 | cout << "H.460.18/.19: " << (args.HasOption("h46018enable") ? "enabled" : "disabled") << endl; 386 | h323->H46018Enable(args.HasOption("h46018enable")); 387 | #endif 388 | #ifdef H323_H46019M 389 | cout << "H.460.19 RTP multiplexing: " << (args.HasOption("h46019multiplexenable") ? "enabled" : "disabled") << endl; 390 | h323->H46019MEnable(args.HasOption("h46019multiplexenable")); 391 | h323->H46019MSending(args.HasOption("h46019multiplexenable")); 392 | #endif 393 | #ifdef H323_H46023 394 | cout << "H.460.23/.24: " << (args.HasOption("h46023enable") ? "enabled" : "disabled") << endl; 395 | h323->H46023Enable(args.HasOption("h46023enable")); 396 | #endif 397 | PString gkAddr = args.GetOptionString('g'); 398 | cout << "Registering with gatekeeper \"" << gkAddr << "\" ..." << flush; 399 | if (h323->SetGatekeeper(gkAddr, new H323TransportUDP(*h323, interfaceAddress))) { 400 | cout << "\nGatekeeper set to \"" << *h323->GetGatekeeper() << '"' << endl; 401 | } else { 402 | cout << "\nError registering with gatekeeper at \"" << gkAddr << '"' << endl; 403 | return; 404 | } 405 | } 406 | else if (!args.HasOption('n')) { 407 | cout << "Searching for gatekeeper ..." << flush; 408 | if (h323->UseGatekeeper()) 409 | cout << "\nGatekeeper found: " << *h323->GetGatekeeper() << endl; 410 | else { 411 | cout << "\nNo gatekeeper found." << endl; 412 | if (args.HasOption("require-gatekeeper")) 413 | return; 414 | } 415 | } 416 | } 417 | 418 | if (args.HasOption('f')) 419 | h323->DisableFastStart(TRUE); 420 | if (args.HasOption('T')) 421 | h323->DisableH245Tunneling(TRUE); 422 | 423 | #ifdef H323_H235 424 | if (args.HasOption("mediaenc")) { 425 | H323EndPoint::H235MediaCipher ncipher = H323EndPoint::encypt128; 426 | #ifdef H323_H235_AES256 427 | unsigned maxtoken = 2048; 428 | unsigned cipher = args.GetOptionString("mediaenc").AsInteger(); 429 | if (cipher >= H323EndPoint::encypt192) ncipher = H323EndPoint::encypt192; 430 | if (cipher >= H323EndPoint::encypt256) ncipher = H323EndPoint::encypt256; 431 | if (args.HasOption("maxtoken")) { 432 | maxtoken = args.GetOptionString("maxtoken").AsInteger(); 433 | } 434 | #else 435 | unsigned maxtoken = 1024; 436 | #endif 437 | h323->SetH235MediaEncryption(H323EndPoint::encyptRequest, ncipher, maxtoken); 438 | cout << "Enabled Media Encryption AES" << ncipher << endl; 439 | } 440 | #endif 441 | 442 | unsigned bandwidth = 768; // default to 768 kbps 443 | if (args.HasOption('b')) { 444 | bandwidth = args.GetOptionString('b').AsUnsigned(); 445 | } 446 | cout << "Per call bandwidth: " << bandwidth << " kbps" << endl; 447 | h323->SetPerCallBandwidth(bandwidth); 448 | 449 | #ifdef H323_VIDEO 450 | if (!args.HasOption('v')) { 451 | cout << "Video is disabled" << endl; 452 | h323->RemoveCapability(H323Capability::e_Video); 453 | } 454 | PString videoPattern = "Fake/MovingBlocks"; 455 | if (args.HasOption("videopattern")) { 456 | // options for demo pattern include: Fake, Fake/MovingLine, Fake/BouncingBoxes 457 | videoPattern = args.GetOptionString("videopattern"); 458 | } 459 | h323->SetVideoPattern(videoPattern); 460 | PString h239VideoPattern = "Fake"; 461 | if (args.HasOption("h239videopattern")) { 462 | // options for demo pattern include: Fake, Fake/MovingLine, Fake/BouncingBoxes 463 | h239VideoPattern = args.GetOptionString("h239videopattern"); 464 | } 465 | h323->SetVideoPattern(h239VideoPattern, true); 466 | 467 | if (args.HasOption('R')) { 468 | h323->SetFrameRate(args.GetOptionString('R').AsUnsigned()); 469 | } 470 | 471 | if (args.HasOption("maxframe")) { 472 | PCaselessString maxframe = args.GetOptionString("maxframe"); 473 | if (maxframe == "qcif") 474 | h323->SetVideoFrameSize(H323Capability::qcifMPI); 475 | else if (maxframe == "cif") 476 | h323->SetVideoFrameSize(H323Capability::cifMPI); 477 | else if (maxframe == "4cif") 478 | h323->SetVideoFrameSize(H323Capability::cif4MPI); 479 | else if (maxframe == "16cif") 480 | h323->SetVideoFrameSize(H323Capability::cif16MPI); 481 | else if (maxframe == "480i") 482 | h323->SetVideoFrameSize(H323Capability::i480MPI); 483 | else if (maxframe == "720p") 484 | h323->SetVideoFrameSize(H323Capability::p720MPI); 485 | else if (maxframe == "1080i") 486 | h323->SetVideoFrameSize(H323Capability::i1080MPI); 487 | else { 488 | cerr << "Unknown maxframe value: " << maxframe << endl; 489 | return; 490 | } 491 | } 492 | #endif 493 | 494 | if (args.HasOption("fuzzing")) { 495 | h323->SetFuzzing(true); 496 | } 497 | if (args.HasOption("fuzz-header")) { 498 | h323->SetPercentBadRTPHeader(args.GetOptionString("fuzz-header").AsUnsigned()); 499 | } 500 | if (args.HasOption("fuzz-media")) { 501 | h323->SetPercentBadRTPMedia(args.GetOptionString("fuzz-media").AsUnsigned()); 502 | } 503 | if (args.HasOption("fuzz-rtcp")) { 504 | h323->SetPercentBadRTCP(args.GetOptionString("fuzz-rtcp").AsUnsigned()); 505 | } 506 | 507 | if (args.HasOption('l')) { 508 | cout << "Endpoint is listening for incoming calls, press ENTER to exit.\n"; 509 | console.ReadChar(); 510 | h323->ClearAllCalls(); 511 | } 512 | else { 513 | CallParams params(*this); 514 | params.tmax_est .SetInterval(0, args.GetOptionString("tmaxest", "0" ).AsUnsigned()); 515 | params.tmin_call.SetInterval(0, args.GetOptionString("tmincall", "10").AsUnsigned()); 516 | params.tmax_call.SetInterval(0, args.GetOptionString("tmaxcall", "60").AsUnsigned()); 517 | params.tmin_wait.SetInterval(0, args.GetOptionString("tminwait", "10").AsUnsigned()); 518 | params.tmax_wait.SetInterval(0, args.GetOptionString("tmaxwait", "30").AsUnsigned()); 519 | 520 | if (params.tmin_call == 0 || 521 | params.tmin_wait == 0 || 522 | params.tmin_call > params.tmax_call || 523 | params.tmin_wait > params.tmax_wait) { 524 | cerr << "Invalid times entered!\n"; 525 | return; 526 | } 527 | 528 | unsigned number = args.GetOptionString('m').AsUnsigned(); 529 | if (number == 0) 530 | number = 1; 531 | cout << "Endpoint starting " << number << " simultaneous call"; 532 | if (number > 1) 533 | cout << 's'; 534 | cout << ' '; 535 | 536 | params.repeat = args.GetOptionString('r', "10").AsUnsigned(); 537 | if (params.repeat != 0) 538 | cout << params.repeat; 539 | else 540 | cout << "infinite"; 541 | cout << " time"; 542 | if (params.repeat != 1) 543 | cout << 's'; 544 | if (params.repeat != 0) 545 | cout << ", grand total of " << number*params.repeat << " calls"; 546 | cout << '.' << endl; 547 | 548 | // create some threads to do calls, but start them randomly 549 | for (unsigned idx = 0; idx < number; idx++) { 550 | if (args.HasOption('C')) 551 | threadList.Append(new CallThread(idx+1, args.GetParameters(), params)); 552 | else { 553 | PINDEX arg = idx % args.GetCount(); 554 | threadList.Append(new CallThread(idx+1, args.GetParameters(arg, arg), params)); 555 | } 556 | } 557 | 558 | PThread::Create(PCREATE_NOTIFIER(Cancel), 0); 559 | 560 | for (;;) { 561 | threadEnded.Wait(); 562 | PThread::Sleep(100); 563 | 564 | PBoolean finished = TRUE; 565 | for (PINDEX i = 0; i < threadList.GetSize(); i++) { 566 | if (!threadList[i].IsTerminated()) { 567 | finished = FALSE; 568 | break; 569 | } 570 | } 571 | 572 | if (finished) { 573 | cout << "\nAll call sets completed." << endl; 574 | console.Close(); 575 | break; 576 | } 577 | } 578 | } 579 | 580 | if (totalAttempts > 0) 581 | cout << "Total calls: " << totalAttempts << " attempted, " << totalEstablished << " established\n"; 582 | 583 | // delete endpoint object so we unregister cleanly 584 | delete h323; 585 | } 586 | 587 | void CallGen::Cancel(PThread &, INT) 588 | { 589 | PTRACE(3, "CallGen\tCancel thread started."); 590 | 591 | coutMutex.Wait(); 592 | cout << "Press ENTER at any time to quit.\n" << endl; 593 | coutMutex.Signal(); 594 | 595 | // wait for a keypress 596 | while (console.ReadChar() != '\n') { 597 | if (!console.IsOpen()) { 598 | PTRACE(3, "CallGen\tCancel thread ended."); 599 | return; 600 | } 601 | } 602 | 603 | PTRACE(2, "CallGen\tCancelling calls."); 604 | 605 | coutMutex.Wait(); 606 | cout << "\nAborting all calls ..." << endl; 607 | coutMutex.Signal(); 608 | 609 | // stop threads 610 | for (PINDEX i = 0; i < threadList.GetSize(); i++) 611 | threadList[i].Stop(); 612 | 613 | // stop all calls 614 | CallGen::Current().ClearAll(); 615 | 616 | PTRACE(1, "CallGen\tCancelled calls."); 617 | } 618 | 619 | /////////////////////////////////////////////////////////////////////////////// 620 | 621 | CallThread::CallThread(unsigned _index, const PStringArray & _destinations, const CallParams & _params) 622 | : PThread(1000, NoAutoDeleteThread, NormalPriority, psprintf("CallGen %u", _index)), 623 | destinations(_destinations), 624 | index(_index), 625 | params(_params) 626 | { 627 | Resume(); 628 | } 629 | 630 | static unsigned RandomRange(PRandom & rand, const PTimeInterval & tmin, const PTimeInterval & tmax) 631 | { 632 | unsigned umax = tmax.GetInterval(); 633 | unsigned umin = tmin.GetInterval(); 634 | return rand.Generate() % (umax - umin + 1) + umin; 635 | } 636 | 637 | #define START_OUTPUT(index, token) \ 638 | { \ 639 | CallGen::Current().coutMutex.Wait(); \ 640 | cout << setw(3) << index << ": " << setw(20) << token.Left(20) << ": " 641 | 642 | #define END_OUTPUT() \ 643 | cout << endl; \ 644 | CallGen::Current().coutMutex.Signal(); \ 645 | } 646 | 647 | #define OUTPUT(index, token, info) START_OUTPUT(index, token) << info; END_OUTPUT() 648 | 649 | void CallThread::Main() 650 | { 651 | PTRACE(2, "CallGen\tStarted thread " << index); 652 | 653 | CallGen & callgen = CallGen::Current(); 654 | PRandom rand(PRandom::Number()); 655 | 656 | PTimeInterval delay = RandomRange(rand, (index-1)*500, (index+1)*500); 657 | OUTPUT(index, PString::Empty(), "Initial delay of " << delay << " seconds"); 658 | 659 | if (exit.Wait(delay)) { 660 | PTRACE(2, "CallGen\tAborted thread " << index); 661 | callgen.threadEnded.Signal(); 662 | return; 663 | } 664 | 665 | // Loop "repeat" times for (repeat > 0), or loop forever for (repeat == 0) 666 | unsigned count = 1; 667 | do { 668 | PString destination = destinations[(index-1 + count-1) % destinations.GetSize()]; 669 | 670 | // trigger a call 671 | PString token; 672 | PTRACE(1, "CallGen\tMaking call to " << destination); 673 | unsigned totalAttempts = ++callgen.totalAttempts; 674 | if (!callgen.Start(destination, token)) 675 | PError << setw(3) << index << ": Call creation to " << destination << " failed" << endl; 676 | else { 677 | PBoolean stopping = FALSE; 678 | 679 | delay = RandomRange(rand, params.tmin_call, params.tmax_call); 680 | 681 | START_OUTPUT(index, token) << "Making call " << count; 682 | if (params.repeat) 683 | cout << " of " << params.repeat; 684 | cout << " (total=" << totalAttempts 685 | << ") for " << delay << " seconds to " 686 | << destination; 687 | END_OUTPUT(); 688 | 689 | if (params.tmax_est > 0) { 690 | OUTPUT(index, token, "Waiting " << params.tmax_est << " seconds for establishment"); 691 | 692 | PTimer timeout = params.tmax_est; 693 | while (!callgen.IsEstablished(token)) { 694 | stopping = exit.Wait(100); 695 | if (stopping || !timeout.IsRunning() || !callgen.Exists(token)) { 696 | delay = 0; 697 | break; 698 | } 699 | } 700 | } 701 | 702 | if (delay > 0) { 703 | // wait for a random time 704 | PTRACE(1, "CallGen\tWaiting for " << delay); 705 | stopping = exit.Wait(delay); 706 | } 707 | 708 | // end the call 709 | OUTPUT(index, token, "Clearing call"); 710 | 711 | callgen.Clear(token); 712 | 713 | if (stopping) 714 | break; 715 | } 716 | 717 | count++; 718 | if (params.repeat > 0 && count > params.repeat) 719 | break; 720 | 721 | // wait for a random delay 722 | delay = RandomRange(rand, params.tmin_wait, params.tmax_wait); 723 | OUTPUT(index, PString::Empty(), "Delaying for " << delay << " seconds"); 724 | 725 | PTRACE(1, "CallGen\tDelaying for " << delay); 726 | // wait for a random time 727 | } while (!exit.Wait(delay)); 728 | 729 | OUTPUT(index, PString::Empty(), "Completed call set."); 730 | PTRACE(2, "CallGen\tFinished thread " << index); 731 | 732 | callgen.threadEnded.Signal(); 733 | } 734 | 735 | void CallThread::Stop() 736 | { 737 | if (!IsTerminated()) 738 | OUTPUT(index, PString::Empty(), "Stopping."); 739 | 740 | exit.Signal(); 741 | } 742 | 743 | /////////////////////////////////////////////////////////////////////////////// 744 | 745 | void CallDetail::Drop(H323Connection & connection) 746 | { 747 | PTextFile & cdrFile = CallGen::Current().cdrFile; 748 | 749 | if (!cdrFile.IsOpen()) 750 | return; 751 | 752 | static PMutex cdrMutex; 753 | cdrMutex.Wait(); 754 | 755 | if (cdrFile.GetLength() == 0) 756 | cdrFile << "Call Start Time," 757 | "Total duration," 758 | "Media open transmit time," 759 | "Media open received time," 760 | "Media received time," 761 | "ALERTING time," 762 | "CONNECT time," 763 | "Call End Reason," 764 | "Remote party," 765 | "Signaling gateway," 766 | "Media gateway," 767 | "Call Id," 768 | "Call Token\n"; 769 | 770 | PTime setupTime = connection.GetSetupUpTime(); 771 | 772 | cdrFile << setupTime.AsString("yyyy/M/d hh:mm:ss") << ',' 773 | << setprecision(1) << (connection.GetConnectionEndTime() - setupTime) << ','; 774 | 775 | if (openedTransmitMedia.IsValid()) 776 | cdrFile << (openedTransmitMedia - setupTime); 777 | cdrFile << ','; 778 | 779 | if (openedReceiveMedia.IsValid()) 780 | cdrFile << (openedReceiveMedia - setupTime); 781 | cdrFile << ','; 782 | 783 | if (receivedMedia.IsValid()) 784 | cdrFile << (receivedMedia - setupTime); 785 | cdrFile << ','; 786 | 787 | if (connection.GetAlertingTime().IsValid()) 788 | cdrFile << (connection.GetAlertingTime() - setupTime); 789 | cdrFile << ','; 790 | 791 | if (connection.GetConnectionStartTime().IsValid()) 792 | cdrFile << (connection.GetConnectionStartTime() - setupTime); 793 | cdrFile << ','; 794 | 795 | cdrFile << connection.GetCallEndReason() << ',' 796 | << connection.GetRemotePartyName() << ',' 797 | << connection.GetRemotePartyAddress() << ',' 798 | << mediaGateway << ',' 799 | << connection.GetCallIdentifier() << ',' 800 | << connection.GetCallToken() 801 | << endl; 802 | 803 | cdrMutex.Signal(); 804 | } 805 | 806 | void CallDetail::OnRTPStatistics(const RTP_Session & session, const PString & token) 807 | { 808 | if (session.GetSessionID() == 1 && !receivedAudio) { 809 | receivedAudio = true; 810 | OUTPUT("", token, "Received audio"); 811 | } 812 | if (session.GetSessionID() == 2 && !receivedVideo) { 813 | receivedVideo = true; 814 | OUTPUT("", token, "Received video"); 815 | } 816 | if (receivedMedia.GetTimeInSeconds() == 0 && session.GetPacketsReceived() > 0) { 817 | receivedMedia = PTime(); 818 | 819 | const RTP_UDP * udpSess = dynamic_cast(&session); 820 | if (udpSess != NULL) 821 | mediaGateway = H323TransportAddress(udpSess->GetRemoteAddress(), udpSess->GetRemoteDataPort()); 822 | } 823 | } 824 | 825 | /////////////////////////////////////////////////////////////////////////////// 826 | 827 | MyH323EndPoint::MyH323EndPoint() 828 | { 829 | // load plugins for H.460.17, .18 etc. 830 | LoadBaseFeatureSet(); 831 | 832 | useJitterBuffer = false; // save a little processing time 833 | 834 | AddAllCapabilities(0, P_MAX_INDEX, "*"); 835 | AddAllUserInputCapabilities(0, P_MAX_INDEX); 836 | SetPerCallBandwidth(384); 837 | SetFrameRate(30); 838 | m_maxFrameSize = H323Capability::i1080MPI; 839 | SetFuzzing(false); 840 | SetPercentBadRTPHeader(50); 841 | SetPercentBadRTPMedia(0); 842 | SetPercentBadRTCP(5); 843 | SetStartH239(false); 844 | SetH239Delay(1); 845 | SetH239Duration(-1); 846 | } 847 | 848 | PBoolean MyH323EndPoint::SetVideoFrameSize(H323Capability::CapabilityFrameSize frameSize, int frameUnits) 849 | { 850 | m_maxFrameSize = frameSize; 851 | return H323EndPoint::SetVideoFrameSize(frameSize, frameUnits); 852 | } 853 | 854 | H323Connection * MyH323EndPoint::CreateConnection(unsigned callReference) 855 | { 856 | return new MyH323Connection(*this, callReference); 857 | } 858 | 859 | static PString TidyRemotePartyName(const H323Connection & connection) 860 | { 861 | PString name = connection.GetRemotePartyName(); 862 | 863 | PINDEX bracket = name.FindLast('['); 864 | if (bracket == 0 || bracket == P_MAX_INDEX) 865 | return name; 866 | 867 | return name.Left(bracket).Trim(); 868 | } 869 | 870 | void MyH323EndPoint::OnConnectionEstablished(H323Connection & connection, const PString & token) 871 | { 872 | OUTPUT("", token, "Established \"" << TidyRemotePartyName(connection) << "\"" 873 | " " << connection.GetControlChannel().GetRemoteAddress() << 874 | " active=" << connectionsActive.GetSize() << 875 | " total=" << ++CallGen::Current().totalEstablished); 876 | } 877 | 878 | void MyH323EndPoint::OnConnectionCleared(H323Connection & connection, const PString & token) 879 | { 880 | OUTPUT("", token, "Cleared \"" << TidyRemotePartyName(connection) << "\"" 881 | " " << connection.GetControlChannel().GetRemoteAddress() << 882 | " reason=" << connection.GetCallEndReason()); 883 | ((MyH323Connection&)connection).details.Drop(connection); 884 | } 885 | 886 | PBoolean MyH323EndPoint::OnStartLogicalChannel(H323Connection & connection, H323Channel & channel) 887 | { 888 | (channel.GetDirection() == H323Channel::IsTransmitter 889 | ? ((MyH323Connection&)connection).details.openedTransmitMedia 890 | : ((MyH323Connection&)connection).details.openedReceiveMedia) = PTime(); 891 | 892 | OUTPUT("", connection.GetCallToken(), 893 | "Opened " << (channel.GetDirection() == H323Channel::IsTransmitter ? "transmitter" : "receiver") 894 | << " for " << channel.GetCapability()); 895 | 896 | return H323EndPoint::OnStartLogicalChannel(connection, channel); 897 | } 898 | 899 | /////////////////////////////////////////////////////////////////////////////// 900 | 901 | MyH323Connection::MyH323Connection(MyH323EndPoint & ep, unsigned callRef) 902 | : H323Connection(ep, callRef) 903 | , endpoint(ep) 904 | , videoChannelIn(NULL) 905 | , videoChannelOut(NULL) 906 | , m_isH239ready(false) 907 | , m_haveStartedH239(false) 908 | { 909 | detectInBandDTMF = FALSE; // turn off in-band DTMF detection (uses a huge amount of CPU) 910 | } 911 | 912 | MyH323Connection::~MyH323Connection() 913 | { 914 | delete videoChannelIn; 915 | delete videoChannelOut; 916 | } 917 | 918 | PBoolean MyH323Connection::OnSendSignalSetup(H323SignalPDU & setupPDU) 919 | { 920 | // set outgoing bearer capability to unrestricted information transfer + transfer rate 921 | PBYTEArray caps; 922 | caps.SetSize(4); 923 | caps[0] = 0x88; 924 | caps[1] = 0x18; 925 | caps[2] = 0x80 | endpoint.GetRateMultiplier(); 926 | caps[3] = 0xa5; 927 | setupPDU.GetQ931().SetIE(Q931::BearerCapabilityIE, caps); 928 | 929 | return H323Connection::OnSendSignalSetup(setupPDU); 930 | } 931 | 932 | H323Channel * MyH323Connection::CreateRealTimeLogicalChannel(const H323Capability & capability, H323Channel::Directions dir, 933 | unsigned sessionID, const H245_H2250LogicalChannelParameters * param, RTP_QOS * rtpqos) 934 | { 935 | if (endpoint.IsFuzzing()) { 936 | WORD rtpPort = 0; 937 | map::const_iterator iter = m_sessionPorts.find(sessionID); 938 | if (iter != m_sessionPorts.end()) { 939 | rtpPort = iter->second; 940 | } else { 941 | rtpPort = endpoint.GetRtpIpPortPair(); 942 | m_sessionPorts[sessionID] = rtpPort; 943 | } 944 | return new RTPFuzzingChannel(endpoint, *this, capability, dir, sessionID, rtpPort, rtpPort+1); 945 | } else { 946 | // call super class 947 | return H323Connection::CreateRealTimeLogicalChannel(capability, dir, sessionID, param, rtpqos); 948 | } 949 | } 950 | 951 | void MyH323Connection::OnRTPStatistics(const RTP_Session & session) const 952 | { 953 | ((MyH323Connection *)this)->details.OnRTPStatistics(session, GetCallToken()); 954 | } 955 | 956 | PBoolean MyH323Connection::OpenAudioChannel(PBoolean isEncoding, unsigned bufferSize, H323AudioCodec & codec) 957 | { 958 | unsigned frameDelay = bufferSize / 16; // assume 16 bit PCM 959 | 960 | PIndirectChannel * channel; 961 | if (isEncoding) 962 | channel = new PlayMessage(CallGen::Current().outgoingMessageFile, frameDelay, bufferSize); 963 | else { 964 | PString wavFileName; 965 | if (!CallGen::Current().incomingAudioDirectory) { 966 | PString token = GetCallToken(); 967 | token.Replace("/", "_", TRUE); 968 | wavFileName = CallGen::Current().incomingAudioDirectory + token; 969 | } 970 | channel = new RecordMessage(wavFileName, frameDelay, bufferSize); 971 | } 972 | 973 | codec.AttachChannel(channel); 974 | 975 | return TRUE; 976 | } 977 | 978 | #ifdef H323_VIDEO 979 | PBoolean MyH323Connection::OpenVideoChannel(PBoolean isEncoding, H323VideoCodec & codec) 980 | { 981 | bool isH239 = false; 982 | #if (H323PLUS_VER >= 1271) 983 | isH239 = codec.GetRTPSessionID() > 2; 984 | #endif 985 | PString deviceName = isEncoding ? endpoint.GetVideoPattern(isH239) : "NULL"; 986 | 987 | PVideoDevice * device = isEncoding ? (PVideoDevice *)PVideoInputDevice::CreateDeviceByName(deviceName) 988 | : (PVideoDevice *)PVideoOutputDevice::CreateDeviceByName(deviceName); 989 | 990 | // codec needs a list of possible formats, otherwise the frame size isn't negotiated properly 991 | if (isEncoding) { 992 | #if PTLIB_VER >= 2110 993 | PVideoInputDevice::Capabilities videoCaps; 994 | if (((PVideoInputDevice *)device)->GetDeviceCapabilities(deviceName, deviceDriver, &videoCaps)) { 995 | codec.SetSupportedFormats(videoCaps.framesizes); 996 | } else 997 | #endif // PTLIB_VER 998 | { 999 | // set fixed list of resolutions for PTLib < 2.11 and for drivers that don't provide a list 1000 | PVideoInputDevice::Capabilities caps; 1001 | PVideoFrameInfo cap; 1002 | cap.SetColourFormat("YUV420P"); 1003 | cap.SetFrameRate(endpoint.GetFrameRate()); 1004 | // sizes must be from largest to smallest 1005 | if (endpoint.GetMaxFrameSize() >= H323Capability::i1080MPI) { 1006 | cap.SetFrameSize(1920, 1080); 1007 | caps.framesizes.push_back(cap); 1008 | } 1009 | if (endpoint.GetMaxFrameSize() >= H323Capability::p720MPI) { 1010 | cap.SetFrameSize(1280, 720); 1011 | caps.framesizes.push_back(cap); 1012 | } 1013 | if (endpoint.GetMaxFrameSize() >= H323Capability::cif4MPI) { 1014 | cap.SetFrameSize(704, 576); 1015 | caps.framesizes.push_back(cap); 1016 | } 1017 | if (endpoint.GetMaxFrameSize() >= H323Capability::i480MPI) { 1018 | cap.SetFrameSize(640, 400); 1019 | caps.framesizes.push_back(cap); 1020 | } 1021 | cap.SetFrameSize(352, 288); 1022 | caps.framesizes.push_back(cap); 1023 | codec.SetSupportedFormats(caps.framesizes); 1024 | } 1025 | } 1026 | 1027 | unsigned frameWidth = codec.GetWidth(); 1028 | unsigned frameHeight = codec.GetHeight(); 1029 | PTRACE(1, "Codec says:" << (isEncoding ? " OUT " : " IN ") << frameWidth << "x" << frameHeight); 1030 | 1031 | if (!device || 1032 | !device->SetFrameSize(codec.GetWidth(), codec.GetHeight()) || 1033 | !device->SetColourFormatConverter("YUV420P") || 1034 | !device->SetFrameRate(endpoint.GetFrameRate()) || 1035 | !device->Open(deviceName, TRUE)) { 1036 | PTRACE(1, "Failed to open or configure the video device \"" << deviceName << '"'); 1037 | return FALSE; 1038 | } 1039 | 1040 | device->GetFrameSize(frameWidth, frameHeight); 1041 | PTRACE(1, "Device says:" << (isEncoding ? " OUT " : " IN ") << frameWidth << "x" << frameHeight); 1042 | 1043 | if (isEncoding) { 1044 | videoChannelOut = new PVideoChannel(); 1045 | videoChannelOut->AttachVideoReader((PVideoInputDevice *)device); 1046 | return codec.AttachChannel(videoChannelOut, false); 1047 | } else { 1048 | videoChannelIn = new PVideoChannel(); 1049 | videoChannelIn->AttachVideoPlayer((PVideoOutputDevice *)device); 1050 | return codec.AttachChannel(videoChannelIn, false); 1051 | } 1052 | } 1053 | 1054 | #ifdef H323_H239 1055 | void MyH323Connection::StartH239Transmission() 1056 | { 1057 | if (endpoint.IsStartH239() && !m_haveStartedH239) { 1058 | PTRACE(1, "Starting H.239"); 1059 | if (OpenH239Channel()) { 1060 | PTRACE(1, "H.239 channel open"); 1061 | m_haveStartedH239 = true; 1062 | int duration = endpoint.GetH239Duration(); 1063 | if (duration > 0) { 1064 | m_h239StopTimer.SetInterval(0, duration); // stop H239 transmission after 10 sec 1065 | m_h239StopTimer.SetNotifier(PCREATE_NOTIFIER(StopH239TransmissionTrigger)); 1066 | } 1067 | } else { 1068 | PTRACE(1, "H.239 channel failed"); 1069 | } 1070 | } 1071 | } 1072 | 1073 | void MyH323Connection::StopH239Transmission() 1074 | { 1075 | if (endpoint.IsStartH239()) { 1076 | PTRACE(1, "Stopping H.239"); 1077 | CloseH239Channel(); 1078 | } 1079 | } 1080 | 1081 | void MyH323Connection::StartH239TransmissionTrigger(PTimer &, H323_INT) 1082 | { 1083 | m_h239StartTimer.Stop(); 1084 | if (m_isH239ready) { 1085 | StartH239Transmission(); 1086 | } 1087 | } 1088 | 1089 | void MyH323Connection::StopH239TransmissionTrigger(PTimer &, H323_INT) 1090 | { 1091 | StopH239Transmission(); 1092 | } 1093 | 1094 | void MyH323Connection::OnEstablished() 1095 | { 1096 | H323Connection::OnEstablished(); // call super class, so endpoint method OnConnectionEstablished() runs, too 1097 | // set a timer to start the H.239 channel if the other side didn't send a H.239 OLC by then 1098 | if (endpoint.IsStartH239()) { 1099 | int delay = endpoint.GetH239Delay(); 1100 | m_h239StartTimer.SetInterval(0, delay); // start after 'delay' sec 1101 | m_h239StartTimer.SetNotifier(PCREATE_NOTIFIER(StartH239TransmissionTrigger)); 1102 | } 1103 | } 1104 | 1105 | PBoolean MyH323Connection::OnInitialFlowRestriction(H323Channel & channel) 1106 | { 1107 | // start the H.239 channel after the other side has sent an OLC for H.239 and received the OLCAck 1108 | // TODO: this works with Polycom endpoints that open the channel at the beginning, but not with 1109 | // Cisco and Radvision endpoints that only open the H.239 channel when needed 1110 | // replace with other check if other endpoint supports H.239 1111 | if ((channel.GetCapability().GetMainType() == H323Capability::e_Video) 1112 | && (channel.GetCapability().GetSubType() == H245_VideoCapability::e_extendedVideoCapability) 1113 | && (channel.GetDirection() == H323Channel::IsReceiver)) { 1114 | m_isH239ready = true; 1115 | } 1116 | return true; 1117 | } 1118 | 1119 | PBoolean MyH323Connection::OpenExtendedVideoChannel(PBoolean isEncoding, H323VideoCodec & codec) 1120 | { 1121 | // send same test pattern as regular video channel 1122 | return OpenVideoChannel(isEncoding, codec); 1123 | } 1124 | #endif // H323_H239 1125 | 1126 | #endif // H323_VIDEO 1127 | 1128 | /////////////////////////////////////////////////////////////////////////////// 1129 | 1130 | RTPFuzzingChannel::RTPFuzzingChannel(MyH323EndPoint & ep, H323Connection & connection, const H323Capability & capability, Directions direction, unsigned sessionID, WORD rtpPort, WORD rtcpPort) 1131 | : H323_ExternalRTPChannel(connection, capability, direction, sessionID) 1132 | { 1133 | m_percentBadRTPHeader = ep.GetPercentBadRTPHeader(); 1134 | m_percentBadRTPMedia = ep.GetPercentBadRTPMedia(); 1135 | m_percentBadRTCP = ep.GetPercentBadRTCP(); 1136 | PIPSocket::Address myip; 1137 | const H323ListenerList & listeners = ep.GetListeners(); 1138 | if (listeners.GetSize() > 0) { 1139 | listeners[0].GetTransportAddress().GetIpAddress(myip); 1140 | } 1141 | 1142 | // set the local RTP address and port 1143 | SetExternalAddress(H323TransportAddress(myip, rtpPort), H323TransportAddress(myip, rtcpPort)); 1144 | // for now we ignore everything sent to these ports 1145 | m_rtpSocket.Listen(5, rtpPort); 1146 | m_rtcpSocket.Listen(5, rtcpPort); 1147 | 1148 | // get the payload code 1149 | OpalMediaFormat format(capability.GetFormatName(), false); 1150 | m_payloadType = format.GetPayloadType(); 1151 | if (m_payloadType > RTP_DataFrame::MaxPayloadType) 1152 | m_payloadType = RTP_DataFrame::DynamicBase; 1153 | m_syncSource = PRandom::Number(65000); 1154 | m_rtpPacket.SetPayloadSize(format.GetFrameTime() * format.GetFrameSize()); // G.711: 20 ms * 8 byte 1155 | if (m_rtpPacket.GetPayloadSize() == 0) 1156 | m_rtpPacket.SetPayloadSize(1400); // eg. for video there is no fixed size 1157 | memset(m_rtpPacket.GetPayloadPtr(), 0, m_rtpPacket.GetPayloadSize()); // silence 1158 | 1159 | m_frameTime = format.GetFrameTime(); 1160 | if (m_frameTime == 0) 1161 | m_frameTime = 100; 1162 | m_frameTimeUnits = m_frameTime * format.GetTimeUnits(); 1163 | if (m_frameTimeUnits == 0) 1164 | m_frameTimeUnits = m_frameTime * 8; 1165 | m_timestamp = 0; 1166 | PTRACE(2, "New fuzzing transmit channel: PT=" << (int)m_payloadType << " frame time=" << m_frameTime 1167 | << " frame size=" << m_rtpPacket.GetPayloadSize()); 1168 | } 1169 | 1170 | RTPFuzzingChannel::~RTPFuzzingChannel() 1171 | { 1172 | m_rtpSocket.Close(); 1173 | m_rtcpSocket.Close(); 1174 | } 1175 | 1176 | PBoolean RTPFuzzingChannel::Start() 1177 | { 1178 | if (!H323_ExternalRTPChannel::Start()) 1179 | return false; 1180 | 1181 | if (GetDirection() == IsTransmitter) { 1182 | m_rtpTransmitTimer.RunContinuous(m_frameTime); 1183 | m_rtpTransmitTimer.SetNotifier(PCREATE_NOTIFIER(TransmitRTP)); 1184 | m_rtcpTransmitTimer.RunContinuous(m_frameTime); // way more often than regular RTCP, but we want to get a lot of test cases through 1185 | m_rtcpTransmitTimer.SetNotifier(PCREATE_NOTIFIER(TransmitRTCP)); 1186 | PIPSocket::Address ip; 1187 | WORD port = 0; 1188 | remoteMediaAddress.GetIpAndPort(ip, port); 1189 | m_rtpSocket.SetSendAddress(ip, port); 1190 | remoteMediaControlAddress.GetIpAndPort(ip, port); 1191 | m_rtcpSocket.SetSendAddress(ip, port); 1192 | } 1193 | return true; 1194 | } 1195 | 1196 | void RTPFuzzingChannel::TransmitRTP(PTimer &, H323_INT) 1197 | { 1198 | m_rtpPacket.SetPayloadType(m_payloadType); 1199 | m_rtpPacket.SetSyncSource(m_syncSource); 1200 | m_timestamp += m_frameTimeUnits; 1201 | m_rtpPacket.SetTimestamp(m_timestamp); 1202 | m_rtpPacket.SetSequenceNumber(m_rtpPacket.GetSequenceNumber() + 1); 1203 | 1204 | for (int i = 0; i < m_rtpPacket.GetHeaderSize(); i++) { 1205 | // overwrite n% of the bytes with random values 1206 | if (PRandom::Number(100) > (100 - m_percentBadRTPHeader)) { 1207 | m_rtpPacket[i] = PRandom::Number(255); 1208 | } 1209 | } 1210 | 1211 | // random RTP media 1212 | for (int i = 0; i < m_rtpPacket.GetPayloadSize(); i++) { 1213 | if (PRandom::Number(100) > (100 - m_percentBadRTPMedia)) { 1214 | *(m_rtpPacket.GetPayloadPtr() + i) = PRandom::Number(255); 1215 | } 1216 | } 1217 | 1218 | PTRACE(2, "Sending fuzzed RTP to " << remoteMediaControlAddress << " payload type=" << m_rtpPacket.GetPayloadType()); 1219 | m_rtpSocket.Write(m_rtpPacket, m_rtpPacket.GetHeaderSize() + m_rtpPacket.GetPayloadSize()); 1220 | } 1221 | 1222 | void RTPFuzzingChannel::TransmitRTCP(PTimer &, H323_INT) 1223 | { 1224 | const unsigned SecondsFrom1900to1970 = (70*365+17)*24*60*60U; 1225 | RTP_ControlFrame m_rtcpPacket; 1226 | 1227 | m_rtcpPacket.SetPayloadType(RTP_ControlFrame::e_SenderReport); 1228 | m_rtcpPacket.SetPayloadSize(sizeof(RTP_ControlFrame::SenderReport)); 1229 | 1230 | RTP_ControlFrame::SenderReport * sender = (RTP_ControlFrame::SenderReport *)m_rtcpPacket.GetPayloadPtr(); 1231 | sender->ssrc = m_syncSource; 1232 | PTime now; 1233 | sender->ntp_sec = now.GetTimeInSeconds() + SecondsFrom1900to1970; // Convert from 1970 to 1900 1234 | sender->ntp_frac = now.GetMicrosecond() * 4294; // Scale microseconds to "fraction" from 0 to 2^32 1235 | sender->rtp_ts = m_timestamp; 1236 | sender->psent = m_rtpPacket.GetSequenceNumber(); 1237 | sender->osent = m_rtpPacket.GetSequenceNumber() * m_rtpPacket.GetPayloadSize(); 1238 | /* 1239 | // TODO: add Receiver report 1240 | // TODO: etPayloadType(RTP_ControlFrame::e_ReceiverReport) 1241 | m_rtcpPacket.SetPayloadSize(sizeof(RTP_ControlFrame::SenderReport) + sizeof(RTP_ControlFrame::ReceiverReport)); 1242 | m_rtcpPacket.SetCount(1); 1243 | // TODO: insert ReceiverReport data, for now rely on the random data we insert 1244 | //AddReceiverReport(*(RTP_ControlFrame::ReceiverReport *)&sender[1]); 1245 | */ 1246 | m_rtcpPacket.WriteNextCompound(); 1247 | (void)m_rtcpPacket.AddSourceDescription(m_syncSource); 1248 | 1249 | // send random RTCP packet every time 1250 | for (int i = 0; i < m_rtcpPacket.GetCompoundSize(); i++) { 1251 | // overwrite n% of the bytes with random values 1252 | if (PRandom::Number(100) > (100 - m_percentBadRTCP)) { 1253 | m_rtcpPacket[i] = PRandom::Number(255); 1254 | } 1255 | } 1256 | 1257 | PTRACE(2, "Sending fuzzed RTCP to " << remoteMediaControlAddress); 1258 | m_rtcpSocket.Write(m_rtcpPacket, m_rtcpPacket.GetCompoundSize()); 1259 | } 1260 | 1261 | /////////////////////////////////////////////////////////////////////////////// 1262 | 1263 | 1264 | PlayMessage::PlayMessage(const PString & filename, unsigned frameDelay, unsigned frameSize) 1265 | : PDelayChannel(PDelayChannel::DelayReadsOnly, frameDelay, frameSize) 1266 | { 1267 | if (filename.IsEmpty()) 1268 | PTRACE(2, "CallGen\tPlaying silence, no outgoing message file"); 1269 | else { 1270 | if (wavFile.Open(filename, PFile::ReadOnly)) { 1271 | Open(wavFile); 1272 | if (wavFile.GetFormat() != PWAVFile::fmt_PCM 1273 | || wavFile.GetChannels() != 1 1274 | || wavFile.GetSampleRate() != 8000 1275 | || wavFile.GetSampleSize() != 16) { 1276 | 1277 | wavFile.Close(); 1278 | PTRACE(2, "CallGen\tWrong file format in outgoing message file \"" << wavFile.GetFilePath() << '"'); 1279 | } else { 1280 | PTRACE(2, "CallGen\tPlaying outgoing message file \"" << wavFile.GetFilePath() << '"'); 1281 | } 1282 | } 1283 | else { 1284 | PTRACE(2, "CallGen\tCould not open outgoing message file \"" << wavFile.GetFilePath() << '"'); 1285 | } 1286 | } 1287 | } 1288 | 1289 | PBoolean PlayMessage::Read(void * buf, PINDEX len) 1290 | { 1291 | if (!wavFile.IsOpen()) { 1292 | // just play out silence 1293 | memset(buf, 0, len); 1294 | lastReadCount = len; 1295 | if (mode != DelayWritesOnly) 1296 | Wait(lastReadCount, nextReadTick); // supress outgoing packets flood 1297 | return TRUE; 1298 | } 1299 | 1300 | if (PDelayChannel::Read(buf, len)) { 1301 | // at end of file, re-open and start reading again 1302 | if (lastReadCount < len) { 1303 | wavFile.Open(PFile::ReadOnly); 1304 | PDelayChannel::Read(buf, len); 1305 | } 1306 | return TRUE; 1307 | } 1308 | return FALSE; 1309 | } 1310 | 1311 | 1312 | PBoolean PlayMessage::Close() 1313 | { 1314 | return PDelayChannel::Close(); 1315 | } 1316 | 1317 | /////////////////////////////////////////////////////////////////////////////// 1318 | 1319 | RecordMessage::RecordMessage(const PString & wavFileName, unsigned frameDelay, unsigned frameSize) 1320 | : PDelayChannel(PDelayChannel::DelayWritesOnly, frameDelay, frameSize) 1321 | { 1322 | reallyClose = FALSE; 1323 | 1324 | if (wavFileName.IsEmpty()) 1325 | return; 1326 | 1327 | PWAVFile * wavFile = new PWAVFile(wavFileName, PFile::WriteOnly); 1328 | if (wavFile->IsOpen()) { 1329 | Open(wavFile, TRUE); 1330 | PTRACE(2, "CallGen\tRecording to file \"" << wavFileName << '"'); 1331 | } 1332 | else 1333 | delete wavFile; 1334 | } 1335 | 1336 | PBoolean RecordMessage::Write(const void * buf, PINDEX len) 1337 | { 1338 | if (PDelayChannel::Write(buf, len)) 1339 | return TRUE; 1340 | 1341 | lastWriteCount = len; 1342 | return !reallyClose; 1343 | } 1344 | 1345 | PBoolean RecordMessage::Close() 1346 | { 1347 | reallyClose = TRUE; 1348 | return PDelayChannel::Close(); 1349 | } 1350 | 1351 | --------------------------------------------------------------------------------