1 /*
2 * h323filetransfer.cxx
3 *
4 * H323 File Transfer class.
5 *
6 * h323plus library
7 *
8 * Copyright (c) 2008 ISVO (Asia) Pte. Ltd.
9 *
10 * The contents of this file are subject to the Mozilla Public License
11 * Version 1.1 (the "License"); you may not use this file except in
12 * compliance with the License. You may obtain a copy of the License at
13 * http://www.mozilla.org/MPL/
14 *
15 * Alternatively, the contents of this file may be used under the terms
16 * of the General Public License (the "GNU License"), in which case the
17 * provisions of GNU License are applicable instead of those
18 * above. If you wish to allow use of your version of this file only
19 * under the terms of the GNU License and not to allow others to use
20 * your version of this file under the MPL, indicate your decision by
21 * deleting the provisions above and replace them with the notice and
22 * other provisions required by the GNU License. If you do not delete
23 * the provisions above, a recipient may use your version of this file
24 * under either the MPL or the GNU License."
25 *
26 * Software distributed under the License is distributed on an "AS IS"
27 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
28 * the License for the specific language governing rights and limitations
29 * under the License.
30 *
31 *
32 * The Initial Developer of the Original Code is ISVO (Asia) Pte. Ltd.
33 *
34 * Contributor(s): ______________________________________.
35 *
36 * $Id$
37 *
38 */
39
40 #include <ptlib.h>
41 #include <h323.h>
42
43 #ifdef H323_FILE
44
45 #ifdef __GNUC__
46 #pragma implementation "h323filetransfer.h"
47 #endif
48
49 #include "h323filetransfer.h"
50
51 #include <h323pdu.h>
52
53
54 static const char * FileTransferOID = "1.3.6.1.4.1.17090.1.2";
55 static const char * FileTransferListOID = "1.3.6.1.4.1.17090.1.2.1";
56
57 static struct {
58 int blocksize;
59 int identifier;
60 } paramBlockSize[8] = {
61 { 512, 1 },
62 { 1024, 2 },
63 { 1428, 4 },
64 { 2048, 8 },
65 { 4096, 16 },
66 { 8192, 32 },
67 { 16384, 64 },
68 { 32768, 128 },
69 };
70
SetParameterBlockSize(int size)71 static int SetParameterBlockSize(int size)
72 {
73 for (PINDEX i = 0; i < 8 ; i++) {
74 if (paramBlockSize[i].blocksize == size)
75 return paramBlockSize[i].identifier;
76 }
77 return 16;
78 }
79
GetParameterBlockSize(int size)80 static int GetParameterBlockSize(int size)
81 {
82 for (PINDEX i = 0; i < 8 ; i++) {
83 if (paramBlockSize[i].identifier == size)
84 return paramBlockSize[i].blocksize;
85 }
86 return 16;
87 }
88
H323FileTransferCapability()89 H323FileTransferCapability::H323FileTransferCapability()
90 : H323DataCapability(132000), m_blockOctets(4096)
91 {
92 m_blockSize = SetParameterBlockSize(m_blockOctets); // parameter block size
93 m_transferMode = 1; // Transfer mode is RTP encapsulated
94 }
95
H323FileTransferCapability(unsigned maxBitRate,unsigned maxBlockSize)96 H323FileTransferCapability::H323FileTransferCapability(unsigned maxBitRate, unsigned maxBlockSize)
97 : H323DataCapability(maxBitRate), m_blockOctets(maxBlockSize)
98 {
99 m_blockSize = SetParameterBlockSize(m_blockOctets); // parameter block size
100 m_transferMode = 1; // Transfer mode is RTP encapsulated
101 }
102
OnReceivedPDU(const H245_DataApplicationCapability & pdu)103 PBoolean H323FileTransferCapability::OnReceivedPDU(const H245_DataApplicationCapability & pdu)
104 {
105 if (pdu.m_application.GetTag() != H245_DataApplicationCapability_application::e_genericDataCapability)
106 return FALSE;
107
108 //maxBitRate = pdu.m_maxBitRate*100;
109 const H245_GenericCapability & genCapability = (const H245_GenericCapability &)pdu.m_application;
110 return OnReceivedPDU(genCapability);
111 }
112
OnSendingPDU(H245_DataApplicationCapability & pdu) const113 PBoolean H323FileTransferCapability::OnSendingPDU(H245_DataApplicationCapability & pdu) const
114 {
115 pdu.m_maxBitRate = maxBitRate/100;
116 pdu.m_application.SetTag(H245_DataApplicationCapability_application::e_genericDataCapability);
117
118 H245_GenericCapability & genCapability = (H245_GenericCapability &)pdu.m_application;
119 return OnSendingPDU(genCapability);
120 }
121
Compare(const PObject & obj) const122 PObject::Comparison H323FileTransferCapability::Compare(const PObject & obj) const
123 {
124 if (!PIsDescendant(&obj, H323FileTransferCapability))
125 return LessThan;
126
127 const H323FileTransferCapability & other = (const H323FileTransferCapability &)obj;
128
129 if (//(m_blockSize == other.GetBlockSize()) && 'We don't need to check the Max Block size
130 (m_transferMode == other.GetTransferMode()))
131 return EqualTo;
132
133 return GreaterThan;
134 }
135
Clone() const136 PObject * H323FileTransferCapability::Clone() const
137 {
138 return new H323FileTransferCapability(*this);
139 }
140
OnReceivedPDU(const H245_GenericCapability & pdu)141 PBoolean H323FileTransferCapability::OnReceivedPDU(const H245_GenericCapability & pdu)
142 {
143
144 const H245_CapabilityIdentifier & capId = pdu.m_capabilityIdentifier;
145
146 if (capId.GetTag() != H245_CapabilityIdentifier::e_standard)
147 return FALSE;
148
149 const PASN_ObjectId & id = capId;
150 if (id.AsString() != FileTransferOID)
151 return FALSE;
152
153 if (pdu.HasOptionalField(H245_GenericCapability::e_maxBitRate)) {
154 const PASN_Integer & bitRate = pdu.m_maxBitRate;
155 maxBitRate = bitRate*100;
156 }
157
158 if (!pdu.HasOptionalField(H245_GenericCapability::e_collapsing))
159 return FALSE;
160
161 const H245_ArrayOf_GenericParameter & params = pdu.m_collapsing;
162 for (PINDEX j=0; j<params.GetSize(); j++) {
163 const H245_GenericParameter & content = params[j];
164 if (content.m_parameterIdentifier.GetTag() == H245_ParameterIdentifier::e_standard) {
165 const PASN_Integer & id = (const PASN_Integer &)content.m_parameterIdentifier;
166 if (content.m_parameterValue.GetTag() == H245_ParameterValue::e_booleanArray) {
167 const PASN_Integer & val = (const PASN_Integer &)content.m_parameterValue;
168 if (id == 1) {
169 m_blockSize = val;
170 m_blockOctets = GetParameterBlockSize(m_blockSize);
171 }
172 if (id == 2)
173 m_transferMode = val;
174 }
175 }
176 }
177
178 return TRUE;
179 }
180
OnSendingPDU(H245_DataMode &) const181 PBoolean H323FileTransferCapability::OnSendingPDU(H245_DataMode & /*pdu*/) const
182 {
183 return false;
184 }
185
OnSendingPDU(H245_GenericCapability & pdu) const186 PBoolean H323FileTransferCapability::OnSendingPDU(H245_GenericCapability & pdu) const
187 {
188 H245_CapabilityIdentifier & capId = pdu.m_capabilityIdentifier;
189
190 capId.SetTag(H245_CapabilityIdentifier::e_standard);
191 PASN_ObjectId & id = capId;
192 id.SetValue(FileTransferOID);
193
194 pdu.IncludeOptionalField(H245_GenericCapability::e_maxBitRate);
195 PASN_Integer & bitRate = pdu.m_maxBitRate;
196 bitRate = maxBitRate/100;
197
198 // Add the Block size parameter
199 H245_GenericParameter * blockparam = new H245_GenericParameter;
200 blockparam->m_parameterIdentifier.SetTag(H245_ParameterIdentifier::e_standard);
201 (PASN_Integer &)blockparam->m_parameterIdentifier = 1;
202 blockparam->m_parameterValue.SetTag(H245_ParameterValue::e_booleanArray);
203 (PASN_Integer &)blockparam->m_parameterValue = SetParameterBlockSize(m_blockOctets);
204
205 // Add the Transfer Mode parameter
206 H245_GenericParameter * modeparam = new H245_GenericParameter;
207 modeparam->m_parameterIdentifier.SetTag(H245_ParameterIdentifier::e_standard);
208 (PASN_Integer &)modeparam->m_parameterIdentifier = 2;
209 modeparam->m_parameterValue.SetTag(H245_ParameterValue::e_booleanArray);
210 (PASN_Integer &)modeparam->m_parameterValue = m_transferMode;
211
212 pdu.IncludeOptionalField(H245_GenericCapability::e_collapsing);
213 pdu.m_collapsing.Append(blockparam);
214 pdu.m_collapsing.Append(modeparam);
215
216 return TRUE;
217 }
218
SetFileTransferList(const H323FileTransferList & list)219 void H323FileTransferCapability::SetFileTransferList(const H323FileTransferList & list)
220 {
221 m_filelist.clear();
222 m_filelist = list;
223 m_filelist.SetMaster(true);
224 }
225
GetDefaultSessionID() const226 unsigned H323FileTransferCapability::GetDefaultSessionID() const
227 {
228 return OpalMediaFormat::DefaultFileSessionID;
229 }
230
GetSubType() const231 unsigned H323FileTransferCapability::GetSubType() const
232 {
233 return H245_DataApplicationCapability_application::e_genericDataCapability;
234 }
235
CreateChannel(H323Connection & connection,H323Channel::Directions direction,unsigned sessionID,const H245_H2250LogicalChannelParameters *) const236 H323Channel * H323FileTransferCapability::CreateChannel(H323Connection & connection,
237 H323Channel::Directions direction,unsigned sessionID,const H245_H2250LogicalChannelParameters * /*param*/
238 ) const
239 {
240 RTP_Session *session;
241 H245_TransportAddress addr;
242 connection.GetControlChannel().SetUpTransportPDU(addr, H323Transport::UseLocalTSAP);
243 session = connection.UseSession(sessionID, addr, direction);
244
245 if(session == NULL) {
246 return NULL;
247 }
248
249 return new H323FileTransferChannel(connection, *this, direction, (RTP_UDP &)*session, sessionID, m_filelist);
250 }
251
252 /////////////////////////////////////////////////////////////////////////////////
253
H323FileTransferChannel(H323Connection & connection,const H323Capability & capability,H323Channel::Directions theDirection,RTP_UDP & rtp,unsigned theSessionID,const H323FileTransferList & list)254 H323FileTransferChannel::H323FileTransferChannel(H323Connection & connection,
255 const H323Capability & capability,
256 H323Channel::Directions theDirection,
257 RTP_UDP & rtp,
258 unsigned theSessionID,
259 const H323FileTransferList & list
260 )
261 : H323Channel(connection, capability),
262 rtpSession(rtp),
263 rtpCallbacks(*(H323_RTP_Session *)rtp.GetUserData()),
264 filelist(list)
265 {
266
267 direction = theDirection;
268 sessionID = theSessionID;
269
270 rtpPayloadType = (RTP_DataFrame::PayloadTypes)101;
271
272 // We create the fileHandler here if we are transmitting (ie. Opening a file Transfer request)
273 if (theDirection == H323Channel::IsTransmitter)
274 fileHandler = connection.CreateFileTransferHandler(sessionID, theDirection,filelist);
275 else
276 fileHandler = NULL;
277 }
278
279
~H323FileTransferChannel()280 H323FileTransferChannel::~H323FileTransferChannel()
281 {
282 }
283
GetDirection() const284 H323Channel::Directions H323FileTransferChannel::GetDirection() const
285 {
286 return direction;
287 }
288
SetInitialBandwidth()289 PBoolean H323FileTransferChannel::SetInitialBandwidth()
290 {
291 return TRUE;
292 }
293
Receive()294 void H323FileTransferChannel::Receive()
295 {
296
297 }
298
Transmit()299 void H323FileTransferChannel::Transmit()
300 {
301
302 }
303
Open()304 PBoolean H323FileTransferChannel::Open()
305 {
306 return H323Channel::Open();
307 }
308
Start()309 PBoolean H323FileTransferChannel::Start()
310 {
311 if (fileHandler == NULL)
312 return FALSE;
313
314 if (!Open())
315 return FALSE;
316
317 fileHandler->SetPayloadType(rtpPayloadType);
318
319 if (fileHandler->GetBlockSize() == 0)
320 fileHandler->SetBlockSize((H323FileTransferCapability::blockSizes)
321 ((H323FileTransferCapability *)capability)->GetOctetSize());
322
323 if (fileHandler->GetBlockRate() == 0)
324 fileHandler->SetMaxBlockRate(((H323FileTransferCapability *)capability)->GetBlockRate());
325
326 return fileHandler->Start(direction);
327 }
328
Close()329 void H323FileTransferChannel::Close()
330 {
331 if (terminating)
332 return;
333
334 if (fileHandler != NULL)
335 fileHandler->Stop(direction);
336 }
337
OnSendingPDU(H245_OpenLogicalChannel & open) const338 PBoolean H323FileTransferChannel::OnSendingPDU(H245_OpenLogicalChannel & open) const
339 {
340 open.m_forwardLogicalChannelNumber = (unsigned)number;
341
342 if (direction == H323Channel::IsTransmitter)
343 SetFileList(open,filelist);
344
345 if (open.HasOptionalField(H245_OpenLogicalChannel::e_reverseLogicalChannelParameters)) {
346
347 open.m_reverseLogicalChannelParameters.IncludeOptionalField(
348 H245_OpenLogicalChannel_reverseLogicalChannelParameters::e_multiplexParameters);
349
350 open.m_reverseLogicalChannelParameters.m_multiplexParameters.SetTag(
351 H245_OpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters::e_h2250LogicalChannelParameters);
352
353 return OnSendingPDU(open.m_reverseLogicalChannelParameters.m_multiplexParameters);
354
355 } else {
356
357 open.m_forwardLogicalChannelParameters.m_multiplexParameters.SetTag(
358 H245_OpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters::e_h2250LogicalChannelParameters);
359
360 return OnSendingPDU(open.m_forwardLogicalChannelParameters.m_multiplexParameters);
361 }
362 }
363
OnSendOpenAck(const H245_OpenLogicalChannel & openPDU,H245_OpenLogicalChannelAck & ack) const364 void H323FileTransferChannel::OnSendOpenAck(const H245_OpenLogicalChannel & openPDU,
365 H245_OpenLogicalChannelAck & ack) const
366 {
367 // set forwardMultiplexAckParameters option
368 ack.IncludeOptionalField(H245_OpenLogicalChannelAck::e_forwardMultiplexAckParameters);
369
370 // select H225 choice
371 ack.m_forwardMultiplexAckParameters.SetTag(
372 H245_OpenLogicalChannelAck_forwardMultiplexAckParameters::e_h2250LogicalChannelAckParameters);
373
374 // get H225 params
375 H245_H2250LogicalChannelAckParameters & param = ack.m_forwardMultiplexAckParameters;
376
377 // set session ID
378 param.IncludeOptionalField(H245_H2250LogicalChannelAckParameters::e_sessionID);
379 const H245_H2250LogicalChannelParameters & openparam =
380 openPDU.m_forwardLogicalChannelParameters.m_multiplexParameters;
381
382 unsigned sessionID = openparam.m_sessionID;
383 param.m_sessionID = sessionID;
384
385 OnSendOpenAck(param);
386 }
387
OnReceivedPDU(const H245_OpenLogicalChannel & open,unsigned & errorCode)388 PBoolean H323FileTransferChannel::OnReceivedPDU(const H245_OpenLogicalChannel & open,
389 unsigned & errorCode)
390 {
391 if (direction == H323Channel::IsReceiver) {
392 number = H323ChannelNumber(open.m_forwardLogicalChannelNumber, TRUE);
393 if (!GetFileList(open))
394 return FALSE;
395 }
396
397 PBoolean reverse = open.HasOptionalField(H245_OpenLogicalChannel::e_reverseLogicalChannelParameters);
398 const H245_DataType & dataType = reverse ? open.m_reverseLogicalChannelParameters.m_dataType
399 : open.m_forwardLogicalChannelParameters.m_dataType;
400
401 if (!capability->OnReceivedPDU(dataType, direction)) {
402
403 errorCode = H245_OpenLogicalChannelReject_cause::e_dataTypeNotSupported;
404 return FALSE;
405 }
406
407 if (reverse) {
408 if (open.m_reverseLogicalChannelParameters.m_multiplexParameters.GetTag() ==
409 H245_OpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters::e_h2250LogicalChannelParameters)
410 {
411 return OnReceivedPDU(open.m_reverseLogicalChannelParameters.m_multiplexParameters, errorCode);
412 }
413
414 } else {
415 if (open.m_forwardLogicalChannelParameters.m_multiplexParameters.GetTag() ==
416 H245_OpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters::e_h2250LogicalChannelParameters)
417 {
418 return OnReceivedPDU(open.m_forwardLogicalChannelParameters.m_multiplexParameters, errorCode);
419 }
420 }
421
422 errorCode = H245_OpenLogicalChannelReject_cause::e_unsuitableReverseParameters;
423 return FALSE;
424 }
425
OnReceivedAckPDU(const H245_OpenLogicalChannelAck & ack)426 PBoolean H323FileTransferChannel::OnReceivedAckPDU(const H245_OpenLogicalChannelAck & ack)
427 {
428 if (!ack.HasOptionalField(H245_OpenLogicalChannelAck::e_forwardMultiplexAckParameters)) {
429 return FALSE;
430 }
431
432 if (ack.m_forwardMultiplexAckParameters.GetTag() !=
433 H245_OpenLogicalChannelAck_forwardMultiplexAckParameters::e_h2250LogicalChannelAckParameters)
434 {
435 return FALSE;
436 }
437
438 return OnReceivedAckPDU(ack.m_forwardMultiplexAckParameters);
439 }
440
OnSendingPDU(H245_H2250LogicalChannelParameters & param) const441 PBoolean H323FileTransferChannel::OnSendingPDU(H245_H2250LogicalChannelParameters & param) const
442 {
443 param.m_sessionID = sessionID;
444
445 param.IncludeOptionalField(H245_H2250LogicalChannelParameters::e_mediaGuaranteedDelivery);
446 param.m_mediaGuaranteedDelivery = FALSE;
447
448 // unicast must have mediaControlChannel
449 if (rtpSession.GetLocalControlPort() > 0) {
450 H323TransportAddress mediaControlAddress(rtpSession.GetLocalAddress(), rtpSession.GetLocalControlPort());
451 param.IncludeOptionalField(H245_H2250LogicalChannelParameters::e_mediaControlChannel);
452 mediaControlAddress.SetPDU(param.m_mediaControlChannel);
453 }
454
455 if (direction == H323Channel::IsReceiver && rtpSession.GetLocalDataPort() > 0) {
456 // set mediaChannel
457 H323TransportAddress mediaAddress(rtpSession.GetLocalAddress(), rtpSession.GetLocalDataPort());
458 param.IncludeOptionalField(H245_H2250LogicalChannelAckParameters::e_mediaChannel);
459 mediaAddress.SetPDU(param.m_mediaChannel);
460 }
461
462 // Set dynamic payload type, if is one
463 int rtpPayloadType = GetDynamicRTPPayloadType();
464
465 if (rtpPayloadType >= RTP_DataFrame::DynamicBase && rtpPayloadType < RTP_DataFrame::IllegalPayloadType) {
466 param.IncludeOptionalField(H245_H2250LogicalChannelParameters::e_dynamicRTPPayloadType);
467 param.m_dynamicRTPPayloadType = rtpPayloadType;
468 }
469
470 return TRUE;
471 }
472
OnSendOpenAck(H245_H2250LogicalChannelAckParameters & param) const473 void H323FileTransferChannel::OnSendOpenAck(H245_H2250LogicalChannelAckParameters & param) const
474 {
475 // set mediaControlChannel
476 if (rtpSession.GetLocalControlPort() > 0) {
477 H323TransportAddress mediaControlAddress(rtpSession.GetLocalAddress(), rtpSession.GetLocalControlPort());
478 param.IncludeOptionalField(H245_H2250LogicalChannelAckParameters::e_mediaControlChannel);
479 mediaControlAddress.SetPDU(param.m_mediaControlChannel);
480 }
481
482 // set mediaChannel
483 if (rtpSession.GetLocalDataPort() > 0) {
484 H323TransportAddress mediaAddress(rtpSession.GetLocalAddress(), rtpSession.GetLocalDataPort());
485 param.IncludeOptionalField(H245_H2250LogicalChannelAckParameters::e_mediaChannel);
486 mediaAddress.SetPDU(param.m_mediaChannel);
487 }
488
489 // Set dynamic payload type, if is one
490 int rtpPayloadType = GetDynamicRTPPayloadType();
491 if (rtpPayloadType >= RTP_DataFrame::DynamicBase && rtpPayloadType < RTP_DataFrame::IllegalPayloadType) {
492 param.IncludeOptionalField(H245_H2250LogicalChannelAckParameters::e_dynamicRTPPayloadType);
493 param.m_dynamicRTPPayloadType = rtpPayloadType;
494 }
495 }
496
OnReceivedPDU(const H245_H2250LogicalChannelParameters & param,unsigned & errorCode)497 PBoolean H323FileTransferChannel::OnReceivedPDU(const H245_H2250LogicalChannelParameters & param,
498 unsigned & errorCode)
499 {
500 if (param.m_sessionID != sessionID) {
501 errorCode = H245_OpenLogicalChannelReject_cause::e_invalidSessionID;
502 return FALSE;
503 }
504
505 PBoolean ok = FALSE;
506
507 if (param.HasOptionalField(H245_H2250LogicalChannelParameters::e_mediaControlChannel)) {
508 if (!ExtractTransport(param.m_mediaControlChannel, FALSE, errorCode)) {
509 return FALSE;
510 }
511
512 ok = TRUE;
513 }
514
515 if (param.HasOptionalField(H245_H2250LogicalChannelParameters::e_mediaChannel)) {
516 if (ok && direction == H323Channel::IsReceiver) {
517
518 } else if (!ExtractTransport(param.m_mediaChannel, TRUE, errorCode)) {
519 return FALSE;
520 }
521
522 ok = TRUE;
523 }
524
525 if (IsMediaTunneled())
526 ok = true;
527
528 if (param.HasOptionalField(H245_H2250LogicalChannelParameters::e_dynamicRTPPayloadType)) {
529 SetDynamicRTPPayloadType(param.m_dynamicRTPPayloadType);
530 }
531
532 if (ok) {
533 return TRUE;
534 }
535
536 errorCode = H245_OpenLogicalChannelReject_cause::e_unspecified;
537 return FALSE;
538 }
539
OnReceivedAckPDU(const H245_H2250LogicalChannelAckParameters & param)540 PBoolean H323FileTransferChannel::OnReceivedAckPDU(const H245_H2250LogicalChannelAckParameters & param)
541 {
542 if (!param.HasOptionalField(H245_H2250LogicalChannelAckParameters::e_sessionID)) {
543 return false;
544 }
545
546 if (!IsMediaTunneled()) {
547 if (!param.HasOptionalField(H245_H2250LogicalChannelAckParameters::e_mediaControlChannel)) {
548 return FALSE;
549 }
550 unsigned errorCode;
551 if (!ExtractTransport(param.m_mediaControlChannel, FALSE, errorCode)) {
552 return FALSE;
553 }
554
555 if (!param.HasOptionalField(H245_H2250LogicalChannelAckParameters::e_mediaChannel)) {
556 return FALSE;
557 }
558 if (!ExtractTransport(param.m_mediaChannel, TRUE, errorCode)) {
559 return FALSE;
560 }
561 }
562
563 if (param.HasOptionalField(H245_H2250LogicalChannelAckParameters::e_dynamicRTPPayloadType)) {
564 SetDynamicRTPPayloadType(param.m_dynamicRTPPayloadType);
565 }
566
567 return TRUE;
568 }
569
SetDynamicRTPPayloadType(int newType)570 PBoolean H323FileTransferChannel::SetDynamicRTPPayloadType(int newType)
571 {
572 if (newType == -1) {
573 return TRUE;
574 }
575
576 if (newType < RTP_DataFrame::DynamicBase || newType >= RTP_DataFrame::IllegalPayloadType) {
577 return FALSE;
578 }
579
580 if (rtpPayloadType < RTP_DataFrame::DynamicBase) {
581 return FALSE;
582 }
583
584 rtpPayloadType = (RTP_DataFrame::PayloadTypes)newType;
585
586 return TRUE;
587 }
588
ExtractTransport(const H245_TransportAddress & pdu,PBoolean isDataPort,unsigned & errorCode)589 PBoolean H323FileTransferChannel::ExtractTransport(const H245_TransportAddress & pdu,
590 PBoolean isDataPort,
591 unsigned & errorCode)
592 {
593 if (pdu.GetTag() != H245_TransportAddress::e_unicastAddress) {
594 errorCode = H245_OpenLogicalChannelReject_cause::e_multicastChannelNotAllowed;
595 return FALSE;
596 }
597
598 H323TransportAddress transAddr = pdu;
599
600 PIPSocket::Address ip;
601 WORD port = 0;
602 if (transAddr.GetIpAndPort(ip, port)) {
603 return rtpSession.SetRemoteSocketInfo(ip, port, isDataPort);
604 }
605
606 return FALSE;
607 }
608
RetreiveFileInfo(const H245_GenericInformation & info,H323FileTransferList & filelist)609 PBoolean H323FileTransferChannel::RetreiveFileInfo(const H245_GenericInformation & info, H323FileTransferList & filelist)
610 {
611 if (info.m_messageIdentifier.GetTag() != H245_CapabilityIdentifier::e_standard)
612 return FALSE;
613
614 const PASN_ObjectId &object_id = info.m_messageIdentifier;
615 if (object_id != FileTransferListOID) // Indicates File Information
616 return FALSE;
617
618 if (!info.HasOptionalField(H245_GenericInformation::e_messageContent))
619 return FALSE;
620
621 const H245_ArrayOf_GenericParameter & params = info.m_messageContent;
622
623 int direction = 0;
624 long size = 0;
625 PString name = PString();
626 for (PINDEX i =0; i < params.GetSize(); i++)
627 {
628 PASN_Integer & pid = params[i].m_parameterIdentifier;
629 H245_ParameterValue & paramval = params[i].m_parameterValue;
630 int val = pid.GetValue();
631
632 if (val == 1) { // tftpDirection
633 PASN_Integer & val = paramval;
634 direction = val.GetValue();
635 } else if (val == 2) { // tftpFilename
636 PASN_OctetString & val = paramval;
637 name = val.AsString();
638 } else if (val == 3) { // tftpFilesize
639 PASN_Integer & val = paramval;
640 size = val.GetValue();
641 }
642 }
643 filelist.Add(name,"",size);
644 if ((direction > 0) && (direction != filelist.GetDirection()))
645 filelist.SetDirection((H323Channel::Directions)direction);
646
647 return TRUE;
648 }
649
GetFileList(const H245_OpenLogicalChannel & open)650 PBoolean H323FileTransferChannel::GetFileList(const H245_OpenLogicalChannel & open)
651 {
652
653 if (!open.HasOptionalField(H245_OpenLogicalChannel::e_genericInformation))
654 return FALSE;
655
656 const H245_ArrayOf_GenericInformation & cape = open.m_genericInformation;
657
658 for (PINDEX i=0; i<cape.GetSize(); i++) {
659 RetreiveFileInfo(cape[i], filelist);
660 }
661
662 // We create the fileHandler once we have received the filelist
663 fileHandler = connection.CreateFileTransferHandler(sessionID, H323Channel::IsReceiver, filelist);
664
665 return (fileHandler != NULL);
666 }
667
BuildGenericParameter(unsigned id,unsigned type,const PString & value)668 static H245_GenericParameter * BuildGenericParameter(unsigned id,unsigned type, const PString & value)
669 {
670
671 H245_GenericParameter * content = new H245_GenericParameter();
672 H245_ParameterIdentifier & paramid = content->m_parameterIdentifier;
673 paramid.SetTag(H245_ParameterIdentifier::e_standard);
674 PASN_Integer & pid = paramid;
675 pid.SetValue(id);
676 H245_ParameterValue & paramval = content->m_parameterValue;
677 paramval.SetTag(type);
678 if ((type == H245_ParameterValue::e_unsignedMin) ||
679 (type == H245_ParameterValue::e_unsignedMax) ||
680 (type == H245_ParameterValue::e_unsigned32Min) ||
681 (type == H245_ParameterValue::e_unsigned32Max)) {
682 PASN_Integer & val = paramval;
683 val.SetValue(value.AsUnsigned());
684 } else if (type == H245_ParameterValue::e_octetString) {
685 PASN_OctetString & val = paramval;
686 val.SetValue(value);
687 }
688 // H245_ParameterValue::e_logical,
689 // H245_ParameterValue::e_booleanArray,
690 // H245_ParameterValue::e_genericParameter
691
692 return content;
693 }
694
SetFileList(H245_OpenLogicalChannel & open,H323FileTransferList flist) const695 void H323FileTransferChannel::SetFileList(H245_OpenLogicalChannel & open, H323FileTransferList flist) const
696 {
697
698 if (flist.GetSize() == 0)
699 return;
700
701 PINDEX i = 0;
702
703 open.IncludeOptionalField(H245_OpenLogicalChannel::e_genericInformation);
704 H245_ArrayOf_GenericInformation & cape = open.m_genericInformation;
705
706 for (H323FileTransferList::const_iterator r = filelist.begin(); r != filelist.end(); ++r) {
707 H245_GenericInformation * gcap = new H245_GenericInformation();
708 gcap->m_messageIdentifier = *(new H245_CapabilityIdentifier(H245_CapabilityIdentifier::e_standard));
709 PASN_ObjectId &object_id = gcap->m_messageIdentifier;
710 object_id = FileTransferListOID; // Indicates File Information
711
712 i++;
713 gcap->IncludeOptionalField(H245_GenericInformation::e_subMessageIdentifier);
714 PASN_Integer & sub_id = gcap->m_subMessageIdentifier;
715 sub_id = i;
716
717 gcap->IncludeOptionalField(H245_GenericInformation::e_messageContent);
718 H245_ArrayOf_GenericParameter & params = gcap->m_messageContent;
719 // tftpDirection
720 params.Append(BuildGenericParameter(1,H245_ParameterValue::e_unsignedMin,flist.GetDirection()));
721 // tftpFilename
722 params.Append(BuildGenericParameter(2,H245_ParameterValue::e_octetString,r->m_Filename));
723 // tftpFilesize
724 if (flist.GetDirection() == H323Channel::IsTransmitter)
725 params.Append(BuildGenericParameter(3,H245_ParameterValue::e_unsigned32Max,r->m_Filesize));
726
727 cape.Append(gcap);
728 }
729 }
730
731 ///////////////////////////////////////////////////////////////////////////////////
732
H323FileTransferList()733 H323FileTransferList::H323FileTransferList()
734 {
735 saveDirectory = PProcess::Current().GetFile().GetDirectory();
736 direction = H323Channel::IsBidirectional;
737 master = false;
738 }
739
Add(const PString & filename,const PDirectory & directory,long filesize)740 void H323FileTransferList::Add(const PString & filename, const PDirectory & directory, long filesize)
741 {
742 H323File file;
743 file.m_Filename = filename;
744 file.m_Directory = directory;
745 file.m_Filesize = filesize;
746 push_back(file);
747 }
748
SetSaveDirectory(const PString directory)749 void H323FileTransferList::SetSaveDirectory(const PString directory)
750 {
751 saveDirectory = directory;
752 }
753
GetSaveDirectory()754 const PDirectory & H323FileTransferList::GetSaveDirectory()
755 {
756 return saveDirectory;
757 }
758
SetDirection(H323Channel::Directions _direction)759 void H323FileTransferList::SetDirection(H323Channel::Directions _direction)
760 {
761 direction = _direction;
762 }
763
GetDirection()764 H323Channel::Directions H323FileTransferList::GetDirection()
765 {
766 return direction;
767 }
768
GetSize()769 PINDEX H323FileTransferList::GetSize()
770 {
771 return size();
772 }
773
774
GetAt(PINDEX i)775 H323File * H323FileTransferList::GetAt(PINDEX i)
776 {
777 PINDEX c=0;
778 for (H323FileTransferList::iterator r = begin(); r != end(); ++r) {
779 if (c == i)
780 return &(*r);
781 c++;
782 }
783 return NULL;
784 }
785
SetMaster(PBoolean state)786 void H323FileTransferList::SetMaster(PBoolean state)
787 {
788 master = state;
789 }
790
IsMaster()791 PBoolean H323FileTransferList::IsMaster()
792 {
793 return master;
794 }
795
796 ///////////////////////////////////////////////////////////////////////////////////
797
798 static PString errString[] = {
799 "Not Defined.",
800 "File Not Found.",
801 "Access Violation.",
802 "Disk Full/Allocation exceeded.",
803 "Illegal TFTP operation.",
804 "Unknown transfer ID.",
805 "File Already Exists.",
806 "No such user.",
807 "Incomplete Block."
808 };
809
810 static PString tranState[] = {
811 "Probing",
812 "Connected",
813 "Waiting",
814 "Sending",
815 "Receiving",
816 "Completed",
817 "Error"
818 };
819
820 static PString blkState[] = {
821 "ok",
822 "partial",
823 "complete",
824 "Incomplete",
825 "Timeout",
826 "Ready"
827 };
828
829 #if PTRACING
830
DataPacketAnalysis(PBoolean isEncoder,const H323FilePacket & packet,PBoolean final)831 PString DataPacketAnalysis(PBoolean isEncoder, const H323FilePacket & packet, PBoolean final)
832 {
833 PString direct = (isEncoder ? "<- " : "-> " );
834
835 if (!final)
836 return direct + "blk partial size : " + PString(packet.GetSize()) + " bytes";
837
838 PString pload;
839 int errcode = 0;
840 PString errstr;
841 switch (packet.GetPacketType()) {
842 case H323FilePacket::e_PROB:
843 pload = direct + "prb size : " + PString(packet.GetSize()) + " bytes";
844 break;
845 case H323FilePacket::e_RRQ:
846 pload = direct + "rrq file " + packet.GetFileName() + " : " + PString(packet.GetFileSize()) + " bytes";
847 break;
848 case H323FilePacket::e_WRQ:
849 pload = direct + "wrq file " + packet.GetFileName() + " : " + PString(packet.GetFileSize()) + " bytes";
850 break;
851 case H323FilePacket::e_DATA:
852 pload = direct + "blk " + PString(packet.GetBlockNo()) + " : " + PString(packet.GetSize()) + " bytes";
853 break;
854 case H323FilePacket::e_ACK:
855 pload = direct + "ack " + PString(packet.GetACKBlockNo());
856 if (packet.GetFileSize() > 0)
857 pload = pload + " : " + PString(packet.GetFileSize()) + " bytes";
858 break;
859 case H323FilePacket::e_ERROR:
860 packet.GetErrorInformation(errcode,errstr);
861 pload = direct + "err " + PString(errcode) + ": " + errstr;
862 break;
863 default:
864 break;
865 }
866
867 return pload;
868 }
869 #endif
870
H323FileTransferHandler(H323Connection & connection,unsigned sessionID,H323Channel::Directions dir,H323FileTransferList & _filelist)871 H323FileTransferHandler::H323FileTransferHandler(H323Connection & connection,
872 unsigned sessionID,
873 H323Channel::Directions dir,
874 H323FileTransferList & _filelist
875 )
876 :filelist(_filelist), master(_filelist.IsMaster())
877 {
878
879 H245_TransportAddress addr;
880 connection.GetControlChannel().SetUpTransportPDU(addr, H323Transport::UseLocalTSAP);
881 session = connection.UseSession(sessionID,addr,H323Channel::IsBidirectional);
882
883 TransmitThread = NULL;
884 ReceiveThread = NULL;
885 blockRate = 0;
886 blockSize = 0;
887 msBetweenBlocks = 0;
888
889 // Transmission Settings
890 curFile = NULL;
891 timestamp = 0;
892 lastBlockNo = 0;
893 lastBlockSize = 0;
894 curFileName = PString();
895 curFileSize = 0;
896 curBlockSize = 0;
897 curProgSize = 0;
898 rtpPayloadType = (RTP_DataFrame::PayloadTypes)101;
899 responseTimeOut = 1500;
900
901 transmitRunning = FALSE;
902 receiveRunning = FALSE;
903
904 StartTime = NULL;
905 ioerr = H323FileIOChannel::e_NotFound;
906 currentState = e_error;
907 blockState = recOK;
908
909 }
910
~H323FileTransferHandler()911 H323FileTransferHandler::~H323FileTransferHandler()
912 {
913 // order is important
914 session->Close(true);
915 if (receiveRunning)
916 exitReceive.Signal();
917
918 if (transmitRunning)
919 exitTransmit.Signal();
920 }
921
Start(H323Channel::Directions direction)922 PBoolean H323FileTransferHandler::Start(H323Channel::Directions direction)
923 {
924 // reset the current state
925 currentState = e_probing;
926
927 StartTime = new PTime();
928 transmitFrame.SetPayloadType(rtpPayloadType);
929 TransmitThread = PThread::Create(PCREATE_NOTIFIER(Transmit), 0, PThread::AutoDeleteThread, PThread::NormalPriority, "FileTransmit");
930 ReceiveThread = PThread::Create(PCREATE_NOTIFIER(Receive), 0, PThread::AutoDeleteThread, PThread::NormalPriority, "FileReceive");
931
932
933 return TRUE;
934 }
935
Stop(H323Channel::Directions direction)936 PBoolean H323FileTransferHandler::Stop(H323Channel::Directions direction)
937 {
938 PWaitAndSignal m(transferMutex);
939
940 delete StartTime;
941 StartTime = NULL;
942
943
944 // CloseDown the Transmit/Receive Threads
945 nextFrame.Signal();
946
947 session->Close(true);
948 if (direction == H323Channel::IsReceiver && receiveRunning)
949 exitReceive.Signal();
950
951 if (direction == H323Channel::IsTransmitter && transmitRunning)
952 exitTransmit.Signal();
953
954 return TRUE;
955 }
956
SetPayloadType(RTP_DataFrame::PayloadTypes _type)957 void H323FileTransferHandler::SetPayloadType(RTP_DataFrame::PayloadTypes _type)
958 {
959 rtpPayloadType = _type;
960 }
961
SetBlockSize(H323FileTransferCapability::blockSizes size)962 void H323FileTransferHandler::SetBlockSize(H323FileTransferCapability::blockSizes size)
963 {
964 blockSize = size;
965 }
966
SetMaxBlockRate(unsigned rate)967 void H323FileTransferHandler::SetMaxBlockRate(unsigned rate)
968 {
969 blockRate = rate;
970 msBetweenBlocks = (int)((1.000/((double)rate))*1000);
971 }
972
ChangeState(transferState newState)973 void H323FileTransferHandler::ChangeState(transferState newState)
974 {
975 PWaitAndSignal m(stateMutex);
976
977 if (currentState == newState)
978 return;
979
980 PTRACE(4,"FT\tState Change to " << tranState[newState]);
981
982 currentState = newState;
983 OnStateChange(currentState);
984 }
985
SetBlockState(receiveStates state)986 void H323FileTransferHandler::SetBlockState(receiveStates state)
987 {
988 PWaitAndSignal m(stateMutex);
989
990 if (blockState == state)
991 return;
992
993 PTRACE(6,"FT\t blk: " << blkState[state]);
994 blockState = state;
995 }
996
TransmitFrame(H323FilePacket & buffer,PBoolean final)997 PBoolean H323FileTransferHandler::TransmitFrame(H323FilePacket & buffer, PBoolean final)
998 {
999
1000 // determining correct timestamp
1001 PTime currentTime = PTime();
1002 PTimeInterval timePassed = currentTime - *StartTime;
1003 transmitFrame.SetTimestamp((DWORD)timePassed.GetMilliSeconds() * 8);
1004 transmitFrame.SetMarker(final);
1005
1006 transmitFrame.SetPayloadSize(buffer.GetSize());
1007 memmove(transmitFrame.GetPayloadPtr(),buffer.GetPointer(), buffer.GetSize());
1008 // TODO: Add Support for Encryption. -SH
1009 return (session && session->PreWriteData(transmitFrame) && session->WriteData(transmitFrame));
1010 }
1011
ReceiveFrame(H323FilePacket & buffer,PBoolean & final)1012 PBoolean H323FileTransferHandler::ReceiveFrame(H323FilePacket & buffer, PBoolean & final)
1013 {
1014
1015 RTP_DataFrame packet = RTP_DataFrame(1440);
1016
1017 if(!session->ReadBufferedData(timestamp, packet))
1018 return FALSE;
1019
1020 timestamp = packet.GetTimestamp();
1021
1022 final = packet.GetMarker();
1023 buffer.SetSize(packet.GetPayloadSize());
1024 memmove(buffer.GetPointer(),packet.GetPayloadPtr(), packet.GetPayloadSize());
1025 return TRUE;
1026 }
1027
Segment(PBYTEArray & lastBlock,const int size,int & segment,PBYTEArray & thearray)1028 PBoolean Segment(PBYTEArray & lastBlock, const int size, int & segment, PBYTEArray & thearray)
1029 {
1030 int bsize = lastBlock.GetSize();
1031 int newsize=0;
1032 if (bsize < (segment + size))
1033 newsize = bsize - segment;
1034 else
1035 newsize = size;
1036
1037 BYTE * seg = lastBlock.GetPointer();
1038 thearray.SetSize(newsize);
1039 memcpy(thearray.GetPointer(),seg+segment, newsize);
1040 segment = segment + newsize;
1041
1042 if (segment == bsize) {
1043 segment = 0;
1044 return TRUE;
1045 }
1046 return FALSE;
1047 }
1048
Transmit(PThread &,H323_INT)1049 void H323FileTransferHandler::Transmit(PThread &, H323_INT)
1050 {
1051 PBoolean success = TRUE;
1052 PBoolean datapacket = FALSE;
1053 H323File * f = NULL;
1054 PFilePath p;
1055
1056 PBoolean read = (filelist.GetDirection() == H323Channel::IsTransmitter);
1057 PBoolean waitforResponse = FALSE;
1058 PBoolean lastFrame = FALSE;
1059 int fileid = 0;
1060 H323FilePacket lastBlock;
1061 PBYTEArray lastSegment;
1062 int offset = 0;
1063 int sentBlock = 0;
1064
1065 transmitRunning = TRUE;
1066
1067 while (success && !exitTransmit.Wait(0)) {
1068
1069 H323FilePacket packet;
1070 PBoolean final = FALSE;
1071 switch (currentState) {
1072 case e_probing:
1073 probMutex.Wait(50);
1074 if (currentState != e_probing)
1075 continue;
1076
1077 packet.BuildPROB();
1078 final = TRUE;
1079 break;
1080 case e_connect:
1081 packet.BuildACK(99);
1082 final = TRUE;
1083 ChangeState(e_waiting);
1084 break;
1085 case e_waiting:
1086 // if we have something to send/Receive
1087 if (master) {
1088 if (waitforResponse) {
1089 if (blockState != recTimeOut) {
1090 waitforResponse = FALSE;
1091 if (read)
1092 ChangeState(e_sending);
1093 break;
1094 }
1095 } else {
1096 fileid++;
1097 if (fileid > filelist.GetSize()) {
1098 ChangeState(e_completed);
1099 OnTransferComplete(master);
1100 break;
1101 }
1102 //delete f;
1103 f = filelist.GetAt(fileid-1);
1104 if (f == NULL) {
1105 ioerr = H323FileIOChannel::e_NotFound;
1106 OnFileOpenError("",ioerr);
1107 ChangeState(e_error);
1108 break;
1109 }
1110
1111 p = f->m_Directory + PDIR_SEPARATOR + f->m_Filename;
1112 curFileName = f->m_Filename;
1113
1114 if (read) {
1115 curFileSize = f->m_Filesize;
1116 delete curFile;
1117 curFile = new H323FileIOChannel(p,read);
1118 if (curFile->IsError(ioerr)) {
1119 OnFileOpenError(p,ioerr);
1120 ChangeState(e_error);
1121 break;
1122 }
1123 OnFileStart(p, curFileSize,read); // Notify to start send
1124 }
1125 }
1126 if (!read) {
1127 packet.BuildRequest(H323FilePacket::e_RRQ ,f->m_Filename, f->m_Filesize, blockSize);
1128 final = TRUE;
1129 waitforResponse = TRUE;
1130 } else {
1131 packet.BuildRequest(H323FilePacket::e_WRQ ,f->m_Filename, f->m_Filesize, blockSize);
1132 final = TRUE;
1133 waitforResponse = TRUE;
1134 }
1135 } else {
1136 if (blockState == recComplete) { // We are waiting to shutdown
1137 if (shutdownTimer.GetResetTime() == 0)
1138 shutdownTimer.SetInterval(responseTimeOut);
1139 else {
1140 if (shutdownTimer == 0) { // We have waited long enough without response
1141 ChangeState(e_completed);
1142 OnTransferComplete(master);
1143 } else
1144 continue;
1145 }
1146 } else
1147 continue;
1148 }
1149 break;
1150 case e_sending:
1151 // Signal we are ready to send file
1152 if (blockState == recReady) {
1153 packet.BuildACK(0,curFileSize);
1154 final = TRUE;
1155 SetBlockState(recOK);
1156 break;
1157 }
1158
1159 if (blockState != recPartial) {
1160 if (blockState == recOK) {
1161 if (lastFrame) {
1162 // We have successfully sent the last frame of data.
1163 // switch back to waiting to queue the next file
1164 OnFileComplete(curFileName);
1165 delete curFile;
1166 curFile = NULL;
1167 curFileName = PString();
1168 waitforResponse = FALSE;
1169 lastFrame = FALSE;
1170 lastBlockSize = 0;
1171 lastBlockNo = 0;
1172 SetBlockState(recComplete);
1173 ChangeState(e_waiting);
1174 continue;
1175 }
1176 offset = 0;
1177 lastBlockNo++;
1178 if (lastBlockNo > 99) lastBlockNo = 1;
1179 lastBlock.BuildData(lastBlockNo,blockSize);
1180 PINDEX size = blockSize;
1181 curFile->Read(lastBlock.GetDataPtr(),size);
1182 // Wait for Bandwidth limits
1183 sendwait.Delay(msBetweenBlocks);
1184 if (size < (int)blockSize) {
1185 lastBlock.SetSize(4+size);
1186 lastFrame = TRUE;
1187 }
1188 lastBlockSize = lastBlock.GetDataSize();
1189 PTRACE(5,"FT\t" << DataPacketAnalysis(true,lastBlock,true));
1190 } else if (blockState != recComplete) {
1191 OnFileError(curFileName,lastBlockNo, TRUE);
1192 }
1193 }
1194 // Segment and mark as recPartial
1195 datapacket = true;
1196 if (blockSize > H323FileTransferCapability::e_1428)
1197 final = Segment(lastBlock, H323FileTransferCapability::e_1428, offset, packet);
1198 else {
1199 packet.Attach(lastBlock.GetPointer(),lastBlock.GetSize());
1200 final = TRUE;
1201 }
1202
1203 if (final) {
1204 SetBlockState(recComplete);
1205 waitforResponse = TRUE;
1206 } else {
1207 SetBlockState(recPartial);
1208 waitforResponse = FALSE;
1209 }
1210 break;
1211 case e_receiving:
1212 // Signal we are ready to receive file.
1213 if (blockState == recReady) {
1214 packet.BuildACK(0);
1215 final = TRUE;
1216 SetBlockState(recOK);
1217 break;
1218 } else if (sentBlock == lastBlockNo) {
1219 nextFrame.Wait(responseTimeOut);
1220 }
1221
1222 if (curFileSize == curProgSize)
1223 SetBlockState(recComplete);
1224
1225 if ((blockState == recOK) || (blockState == recComplete)) {
1226 packet.BuildACK(lastBlockNo);
1227 if (lastBlockNo == 99) lastBlockNo = 0;
1228 sentBlock = lastBlockNo;
1229 final = TRUE;
1230 if (blockState == recComplete) { // Switch to wait for next instruction
1231 lastBlockNo = 0;
1232 curProgSize = 0;
1233 curFile->Close();
1234 ChangeState(e_waiting);
1235 waitforResponse = FALSE;
1236 }
1237 } else if (blockState == recIncomplete) {
1238 OnFileError(curFileName,lastBlockNo, TRUE);
1239 packet.BuildError(0,""); // Indicate to remote to resend the last block
1240 } else {
1241 // Do nothing
1242 continue;
1243 }
1244
1245 break;
1246 case e_error:
1247 packet.BuildError(ioerr,errString[ioerr]);
1248 final = TRUE;
1249 ChangeState(e_completed);
1250 OnTransferComplete(master);
1251 break;
1252 case e_completed:
1253 default:
1254 success = false;
1255 break;
1256 }
1257
1258 if (success && packet.GetSize() > 0) {
1259 success = TransmitFrame(packet,final);
1260
1261 if (!datapacket) {
1262 #if PTRACING
1263 PTRACE(5,"FT\t" << DataPacketAnalysis(true,packet,final));
1264 #endif
1265 packet.SetSize(0);
1266 }
1267 datapacket = false;
1268 if (waitforResponse) {
1269 SetBlockState(recTimeOut);
1270 nextFrame.Wait(responseTimeOut);
1271 }
1272 }
1273 }
1274
1275 session->Close(false);
1276 exitTransmit.Acknowledge();
1277 transmitRunning = FALSE;
1278
1279 PTRACE(6,"FILE\tClosing Transmit Thread");
1280
1281 // close down the channel which will
1282 // release the thread to close automatically
1283 if (receiveRunning)
1284 session->Close(true);
1285
1286 }
1287
Receive(PThread &,H323_INT)1288 void H323FileTransferHandler::Receive(PThread &, H323_INT)
1289 {
1290
1291 PBoolean success = TRUE;
1292 H323FilePacket packet;
1293 packet.SetSize(0);
1294 PFilePath p;
1295
1296 receiveRunning = TRUE;
1297 while (success && !exitReceive.Wait(0)) {
1298
1299 PBoolean final = FALSE;
1300 H323FilePacket buffer;
1301 success = ReceiveFrame(buffer, final);
1302
1303 if (!success || buffer.GetSize() == 0)
1304 continue;
1305
1306 if (currentState == e_receiving) {
1307 packet.Concatenate(buffer);
1308 if (!final)
1309 continue;
1310 else {
1311 buffer.SetSize(0);
1312 }
1313 } else {
1314 packet = buffer;
1315 }
1316
1317 if (packet.GetSize() == 0)
1318 continue;
1319
1320 #if PTRACING
1321 PTRACE(5,"FT\t" << DataPacketAnalysis(false,packet,final));
1322 #endif
1323
1324 int ptype = packet.GetPacketType();
1325 if (ptype == H323FilePacket::e_ERROR) {
1326 int errCode = 0;
1327 PString errString;
1328 packet.GetErrorInformation(errCode, errString);
1329 if (errCode > 0) {
1330 OnError(errString);
1331 ChangeState(e_completed);
1332 OnTransferComplete(master);
1333 nextFrame.Signal();
1334 }
1335 }
1336
1337 switch (currentState) {
1338 case e_probing:
1339 ChangeState(e_connect);
1340 probMutex.Signal();
1341 break;
1342 case e_connect:
1343 // Do nothing
1344 break;
1345 case e_waiting:
1346 if (ptype == H323FilePacket::e_WRQ) {
1347 p = filelist.GetSaveDirectory() + PDIR_SEPARATOR + packet.GetFileName();
1348 curFileName = packet.GetFileName();
1349 curFileSize = packet.GetFileSize();
1350 curBlockSize = packet.GetBlockSize();
1351 delete curFile;
1352 curFile = new H323FileIOChannel(p, FALSE);
1353 if (curFile->IsError(ioerr)) {
1354 OnFileOpenError(p,ioerr);
1355 ChangeState(e_error);
1356 break;
1357 }
1358 SetBlockState(recReady);
1359 ChangeState(e_receiving);
1360 OnFileStart(p, curFileSize,FALSE); // Notify to start receive
1361 shutdownTimer.SetInterval(0);
1362 } else if (ptype == H323FilePacket::e_RRQ) {
1363 p = filelist.GetSaveDirectory() + PDIR_SEPARATOR + packet.GetFileName();
1364 delete curFile;
1365 curFile = new H323FileIOChannel(p,TRUE);
1366 if (curFile->IsError(ioerr)) {
1367 OnFileOpenError(p,ioerr);
1368 ChangeState(e_error);
1369 break;
1370 }
1371 curFileSize = curFile->GetFileSize();
1372 SetBlockState(recReady);
1373 ChangeState(e_sending);
1374 OnFileStart(p, curFileSize,TRUE); // Notify to start send
1375 shutdownTimer.SetInterval(0);
1376 } else if ((ptype == H323FilePacket::e_ACK) && (packet.GetACKBlockNo() == 0)) {
1377 // We have received acknowledgement
1378 int size = packet.GetFileSize();
1379 if (size > 0) {
1380 curFileSize = size;
1381 PStringList saveFile;
1382 saveFile = curFileName.Tokenise(PDIR_SEPARATOR);
1383 p = filelist.GetSaveDirectory() + PDIR_SEPARATOR + saveFile[saveFile.GetSize()-1];
1384 delete curFile;
1385 curFile = new H323FileIOChannel(p,false);
1386 if (curFile->IsError(ioerr)) {
1387 delete curFile;
1388 curFile = NULL;
1389 OnFileOpenError(p,ioerr);
1390 ChangeState(e_error);
1391 break;
1392 }
1393 SetBlockState(recOK);
1394 ChangeState(e_receiving);
1395 OnFileStart(curFileName, curFileSize, false); // Notify to start receive
1396 nextFrame.Signal();
1397 } else {
1398 SetBlockState(recOK);
1399 if (!master || (master && (filelist.GetDirection() == H323Channel::IsTransmitter)))
1400 nextFrame.Signal();
1401 }
1402 break;
1403 }
1404
1405 break;
1406 case e_receiving:
1407 if (ptype == H323FilePacket::e_DATA) {
1408 PBoolean OKtoWrite = FALSE;
1409 int blockNo = 0;
1410 if ((packet.GetDataSize() == blockSize) || // We have complete block
1411 (curFileSize == (curProgSize + packet.GetDataSize()))) { // We have the last block
1412
1413 if (packet.GetBlockNo() > lastBlockNo) { // Make sure we have not already received this block
1414 if (packet.GetBlockNo() != lastBlockNo + 1) {
1415 // This is not the next block request to resend. We are in trouble if we are here!
1416 SetBlockState(recIncomplete);
1417 OnFileError(curFileName, lastBlockNo, FALSE);
1418 packet.SetSize(0);
1419 nextFrame.Signal();
1420 break;
1421 }
1422
1423 lastBlockNo = packet.GetBlockNo();
1424 curProgSize = curProgSize + packet.GetDataSize();
1425
1426 blockNo = lastBlockNo;
1427 OKtoWrite = TRUE;
1428 }
1429 SetBlockState(recOK);
1430 } else {
1431 SetBlockState(recIncomplete);
1432 OnFileError(curFileName, lastBlockNo, FALSE);
1433 }
1434
1435 // Now write away block to file.
1436 if (OKtoWrite) {
1437 curFile->Write(packet.GetDataPtr(),packet.GetDataSize());
1438 OnFileProgress(curFileName, blockNo, curProgSize, FALSE);
1439 }
1440 // Signal to send confirmation
1441 nextFrame.Signal();
1442 }
1443 packet.SetSize(0);
1444 break;
1445 case e_sending:
1446 if (ptype == H323FilePacket::e_ACK) {
1447 if (packet.GetACKBlockNo() == 0) // Control ACKs = 0 so ignore.
1448 continue;
1449 if (packet.GetACKBlockNo() == lastBlockNo) {
1450 curProgSize = curProgSize + lastBlockSize;
1451 OnFileProgress(curFileName, lastBlockNo, curProgSize, TRUE);
1452 SetBlockState(recOK);
1453 } else {
1454 PTRACE(6,"FT\tExpecting block " << lastBlockNo << " Received " << packet.GetACKBlockNo());
1455 }
1456 } else if (ptype == H323FilePacket::e_ERROR) {
1457 OnFileError(curFileName,lastBlockNo, TRUE);
1458 SetBlockState(recIncomplete);
1459 }
1460 nextFrame.Signal();
1461 break;
1462 case e_error:
1463 case e_completed:
1464 default:
1465 success = FALSE;
1466 break;
1467 }
1468 packet.SetSize(0);
1469 }
1470
1471 exitReceive.Acknowledge();
1472 receiveRunning = FALSE;
1473
1474 PTRACE(6,"FILE\tClosing Receive Thread");
1475 }
1476
1477 ///////////////////////////////////////////////////////////////////////////
1478
1479 static PString opStr[] = {
1480 "00",
1481 "01",
1482 "02",
1483 "03",
1484 "04",
1485 "05"
1486 };
1487
attach(PString & data)1488 void H323FilePacket::attach(PString & data)
1489 {
1490 SetSize(data.GetSize());
1491 memcpy(theArray, (const char *)data, data.GetSize());
1492 }
1493
BuildPROB()1494 void H323FilePacket::BuildPROB()
1495 {
1496 PString header = opStr[e_PROB];
1497 Attach(header,header.GetSize());
1498 }
1499
BuildRequest(opcodes code,const PString & filename,int filesize,int blocksize)1500 void H323FilePacket::BuildRequest(opcodes code, const PString & filename, int filesize, int blocksize)
1501 {
1502 PString fn = filename;
1503 fn.Replace("0","*",true);
1504 PString header = opStr[code] + fn + "0octet0blksize0" + PString(blocksize)
1505 + "0tsize0" + PString(filesize) + "0";
1506 attach(header);
1507
1508 }
1509
BuildData(int blockid,int size)1510 void H323FilePacket::BuildData(int blockid, int size)
1511 {
1512 PString blkstr;
1513 if (blockid < 10)
1514 blkstr = "0" + PString(blockid);
1515 else
1516 blkstr = blockid;
1517
1518 PString data = opStr[e_DATA] + blkstr;
1519
1520 SetSize(size+4);
1521 memcpy(theArray, (const char *)data, data.GetSize());
1522 }
1523
BuildACK(int blockid,int filesize)1524 void H323FilePacket::BuildACK(int blockid, int filesize)
1525 {
1526 PString blkstr;
1527 if (blockid < 10)
1528 blkstr = "0" + PString(blockid);
1529 else
1530 blkstr = blockid;
1531
1532 PString header = opStr[e_ACK] + blkstr;
1533
1534 if (filesize > 0)
1535 header = header + "0tsize0" + PString(filesize) + "0";
1536 attach(header);
1537 }
1538
BuildError(int errorcode,PString errmsg)1539 void H323FilePacket::BuildError(int errorcode,PString errmsg)
1540 {
1541 PString blkerr;
1542 if (errorcode < 10)
1543 blkerr = "0" + PString(errorcode);
1544 else
1545 blkerr = PString(errorcode);
1546
1547 PString header = opStr[e_ERROR] + blkerr + errmsg + "0";
1548 attach(header);
1549 }
1550
GetFileName() const1551 PString H323FilePacket::GetFileName() const
1552 {
1553 if ((GetPacketType() != e_RRQ) &&
1554 (GetPacketType() != e_WRQ))
1555 return PString();
1556
1557 PString data(theArray, GetSize());
1558
1559 PStringArray ar = (data.Mid(2)).Tokenise('0');
1560
1561 ar[0].Replace("*","0",true);
1562 return ar[0];
1563 }
1564
GetFileSize() const1565 unsigned H323FilePacket::GetFileSize() const
1566 {
1567 if ((GetPacketType() != e_RRQ) &&
1568 (GetPacketType() != e_WRQ) &&
1569 (GetPacketType() != e_ACK))
1570 return 0;
1571
1572 PString data(theArray, GetSize());
1573
1574 int i = data.Find("tsize");
1575 if (i == P_MAX_INDEX)
1576 return 0;
1577
1578 i = data.Find('0',i);
1579 int l = data.GetLength()-1-i;
1580
1581 return data.Mid(i,l).AsUnsigned();
1582 }
1583
GetBlockSize() const1584 unsigned H323FilePacket::GetBlockSize() const
1585 {
1586 if ((GetPacketType() != e_RRQ) &&
1587 (GetPacketType() != e_WRQ))
1588 return 0;
1589
1590 PString data(theArray, GetSize());
1591
1592 int i = data.Find("blksize");
1593 i = data.Find('0',i);
1594 int j = data.Find("tsize",i)-1;
1595 int l = j-i;
1596
1597 return data.Mid(i,l).AsUnsigned();
1598 }
1599
GetErrorInformation(int & ErrCode,PString & ErrStr) const1600 void H323FilePacket::GetErrorInformation(int & ErrCode, PString & ErrStr) const
1601 {
1602 if (GetPacketType() != e_ERROR)
1603 return;
1604
1605 PString data(theArray, GetSize());
1606 PString ar = data.Mid(2);
1607
1608 ErrCode = (ar.Left(2)).AsInteger();
1609 ErrStr = ar.Mid(2,ar.GetLength()-3);
1610 }
1611
GetDataPtr()1612 BYTE * H323FilePacket::GetDataPtr()
1613 {
1614 return (BYTE *)(theArray+4);
1615 }
1616
GetDataSize() const1617 unsigned H323FilePacket::GetDataSize() const
1618 {
1619 if (GetPacketType() == e_DATA)
1620 return GetSize() - 4;
1621 else
1622 return 0;
1623 }
1624
GetBlockNo() const1625 int H323FilePacket::GetBlockNo() const
1626 {
1627 if (GetPacketType() != e_DATA)
1628 return 0;
1629
1630 PString data(theArray, GetSize());
1631 return data.Mid(2,2).AsInteger();
1632 }
1633
GetACKBlockNo() const1634 int H323FilePacket::GetACKBlockNo() const
1635 {
1636 if (GetPacketType() != e_ACK)
1637 return 0;
1638
1639 PString data(theArray, GetSize());
1640 return data.Mid(2,2).AsInteger();
1641 }
1642
GetPacketType() const1643 H323FilePacket::opcodes H323FilePacket::GetPacketType() const
1644 {
1645 PString data(theArray, GetSize());
1646 return (opcodes)data.Mid(1,1).AsUnsigned();
1647 }
1648
1649 ////////////////////////////////////////////////////////////////////
1650
H323FileIOChannel(PFilePath _file,PBoolean read)1651 H323FileIOChannel::H323FileIOChannel(PFilePath _file, PBoolean read)
1652 : fileopen(false), filesize(0), IOError(e_NotFound)
1653 {
1654 if (!CheckFile(_file,read,IOError))
1655 return;
1656
1657 PFile::OpenMode mode;
1658 if (read)
1659 mode = PFile::ReadOnly;
1660 else
1661 mode = PFile::WriteOnly;
1662
1663 PFile * file = new PFile(_file,mode);
1664 fileopen = file->IsOpen();
1665
1666 if (!fileopen) {
1667 IOError = e_AccessDenied;
1668 delete file;
1669 file = NULL;
1670 filesize = 0;
1671 return;
1672 }
1673
1674 filesize = file->GetLength();
1675
1676 if (read)
1677 SetReadChannel(file, TRUE);
1678 else
1679 SetWriteChannel(file, TRUE);
1680 }
1681
~H323FileIOChannel()1682 H323FileIOChannel::~H323FileIOChannel()
1683 {
1684 }
1685
IsError(fileError & err)1686 PBoolean H323FileIOChannel::IsError(fileError & err)
1687 {
1688 err = IOError;
1689 return (err > 0);
1690 }
1691
CheckFile(PFilePath _file,PBoolean read,fileError & errCode)1692 PBoolean H323FileIOChannel::CheckFile(PFilePath _file, PBoolean read, fileError & errCode)
1693 {
1694 PBoolean exists = PFile::Exists(_file);
1695
1696 if (read && !exists) {
1697 errCode = e_NotFound;
1698 return FALSE;
1699 }
1700
1701 if (!read && exists) {
1702 errCode = e_FileExists;
1703 return FALSE;
1704 }
1705
1706 PFileInfo info;
1707 PFile::GetInfo(_file,info);
1708
1709 if (read && (info.permissions < PFileInfo::UserRead)) {
1710 errCode = e_AccessDenied;
1711 return FALSE;
1712 }
1713
1714 errCode = e_OK;
1715 return TRUE;
1716 }
1717
Open()1718 PBoolean H323FileIOChannel::Open()
1719 {
1720 PWaitAndSignal mutex(chanMutex);
1721
1722 if (fileopen)
1723 return TRUE;
1724
1725 return TRUE;
1726 }
1727
Close()1728 PBoolean H323FileIOChannel::Close()
1729 {
1730 PWaitAndSignal mutex(chanMutex);
1731
1732 if (!fileopen)
1733 return TRUE;
1734
1735 PIndirectChannel::Close();
1736 return TRUE;
1737 }
1738
GetFileSize()1739 unsigned H323FileIOChannel::GetFileSize()
1740 {
1741 return filesize;
1742 }
1743
Read(void * buffer,PINDEX & amount)1744 PBoolean H323FileIOChannel::Read(void * buffer, PINDEX & amount)
1745 {
1746 PWaitAndSignal mutex(chanMutex);
1747
1748 if (!fileopen)
1749 return FALSE;
1750
1751 PBoolean result = PIndirectChannel::Read(buffer, amount);
1752 amount = GetLastReadCount();
1753
1754 return result;
1755 }
1756
Write(const void * buf,PINDEX amount)1757 PBoolean H323FileIOChannel::Write(const void * buf, PINDEX amount)
1758 {
1759 PWaitAndSignal mutex(chanMutex);
1760
1761 if (!fileopen)
1762 return FALSE;
1763
1764 return PIndirectChannel::Write(buf, amount);
1765 }
1766
1767 #endif // H323_FILE
1768
1769
1770
1771