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 | - Any addition to or deletion from the contents of a file
56 | containing Original Code or previous Modifications.
57 |
- 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 | - 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 |
- 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 |
- 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 |
- 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 | - 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 |
- 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 |
- 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 |
- 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 | - 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 |
- 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 |
--------------------------------------------------------------------------------