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