OPAL  Version 3.14.3
skinnyep.h
Go to the documentation of this file.
1 /*
2  * skinnyep.h
3  *
4  * Cisco SCCP (Skinny Client Control Protocol) support.
5  *
6  * Open Phone Abstraction Library (OPAL)
7  * Formally known as the Open H323 project.
8  *
9  * Copyright (c) 2014 Vox Lucida Pty. Ltd.
10  *
11  * The contents of this file are subject to the Mozilla Public License
12  * Version 1.0 (the "License"); you may not use this file except in
13  * compliance with the License. You may obtain a copy of the License at
14  * http://www.mozilla.org/MPL/
15  *
16  * Software distributed under the License is distributed on an "AS IS"
17  * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
18  * the License for the specific language governing rights and limitations
19  * under the License.
20  *
21  * The Original Code is Open Phone Abstraction Library.
22  *
23  * The Initial Developer of the Original Code is Vox Lucida Pty. Ltd.
24  *
25  * Contributor(s): Robert Jongbloed (robertj@voxlucida.com.au).
26  *
27  * $Revision: 31667 $
28  * $Author: rjongbloed $
29  * $Date: 2014-04-03 16:09:18 +1100 (Thu, 03 Apr 2014) $
30  */
31 
32 #ifndef OPAL_SKINNY_H
33 #define OPAL_SKINNY_H
34 
35 #include <opal_config.h>
36 
37 #if OPAL_SKINNY
38 
39 #include <rtp/rtpep.h>
40 #include <rtp/rtpconn.h>
41 
42 
43 class OpalSkinnyConnection;
44 
45 
48 class OpalSkinnyEndPoint : public OpalRTPEndPoint
49 {
50  PCLASSINFO(OpalSkinnyEndPoint, OpalRTPEndPoint);
51  public:
56  OpalSkinnyEndPoint(
57  OpalManager & manager,
58  const char *prefix = "sccp"
59  );
60 
63  virtual ~OpalSkinnyEndPoint();
65 
72  virtual void ShutDown();
73 
77  virtual PString GetDefaultTransport() const;
78 
81  virtual WORD GetDefaultSignalPort() const;
82 
90  virtual OpalMediaFormatList GetMediaFormats() const;
91 
94  virtual void NewIncomingConnection(
95  OpalListener & listener,
96  const OpalTransportPtr & transport
97  );
98 
126  virtual PSafePtr<OpalConnection> MakeConnection(
127  OpalCall & call,
128  const PString & party,
129  void * userData,
130  unsigned int options,
131  OpalConnection::StringOptions * stringOptions
132  );
133 
137  virtual PBoolean GarbageCollection();
139 
140 
141  class PhoneDevice;
142 
147  virtual OpalSkinnyConnection * CreateConnection(
148  OpalCall & call,
149  PhoneDevice & client,
150  unsigned callIdentifier,
151  const PString & dialNumber,
152  void * userData,
153  unsigned int options,
154  OpalConnection::StringOptions * stringOptions = NULL
155  );
157 
160  enum { DefaultDeviceType = 30016 }; // Cisco IP Communicator
161 
164  bool Register(
165  const PString & server,
166  const PString & name,
167  unsigned deviceType = DefaultDeviceType
168  );
169 
172  bool Unregister(
173  const PString & name
174  );
175 
176  PhoneDevice * GetPhoneDevice(
177  const PString & name
178  ) const { return m_phoneDevices.GetAt(name); }
179 
180  PArray<PString> GetPhoneDeviceNames() const { return m_phoneDevices.GetKeys(); }
182 
183 
184  class SkinnyMsg;
185 
186  class PhoneDevice : public PObject
187  {
188  PCLASSINFO(PhoneDevice, PObject);
189  public:
190  PhoneDevice(OpalSkinnyEndPoint & ep, const PString & name, unsigned deviceType);
191 
192  virtual void PrintOn(ostream & strm) const;
193 
194  bool Start(const PString & server);
195  void Stop();
196  void Close();
197 
198  bool SendSkinnyMsg(const SkinnyMsg & msg);
199 
200  const PString & GetName() const { return m_name; }
201  const PString & GetStatus() const { return m_status; }
202  OpalTransportAddress GetRemoteAddress() const { return m_transport.GetRemoteAddress(); }
203 
204  protected:
205  void HandleTransport();
206  bool SendRegisterMsg();
207 
208  template <class MSG> bool OnReceiveMsg(const MSG & msg)
209  {
210  PTRACE(3, "Skinny", "Received " << msg);
211  return m_endpoint.OnReceiveMsg(*this, msg);
212  }
213 
214  OpalSkinnyEndPoint & m_endpoint;
215  PString m_name;
216  unsigned m_deviceType;
217  OpalTransportTCP m_transport;
218  PTimeInterval m_delay;
219  PString m_status;
220  PSyncPoint m_exit;
221 
222  friend class OpalSkinnyEndPoint;
223  friend class OpalSkinnyConnection;
224  };
225 
226 
227 #pragma pack(1)
228  class SkinnyMsg : public PObject
229  {
230  PCLASSINFO(SkinnyMsg, PObject);
231  protected:
232  SkinnyMsg(uint32_t id, PINDEX len);
233  void Construct(const PBYTEArray & pdu);
234 
235  public:
236  uint32_t GetID() const { return m_messageId; }
237 
238  const BYTE * GetPacketPtr() const { return (const BYTE *)&m_length; }
239  PINDEX GetPacketLen() const { return m_length + sizeof(m_length) + sizeof(m_headerVersion); }
240 
241  protected:
242  PUInt32l m_length;
243  PUInt32l m_headerVersion;
244  PUInt32l m_messageId;
245  };
246 
247  // Note: all derived classes MUST NOT have composite members, e.g. PString
248 #define OPAL_SKINNY_MSG(cls, id, vars) \
249  class cls : public SkinnyMsg \
250  { \
251  PCLASSINFO(cls, SkinnyMsg); \
252  public: \
253  enum { ID = id }; \
254  cls() : SkinnyMsg(ID, sizeof(*this)) { } \
255  cls(const PBYTEArray & pdu) : SkinnyMsg(ID, sizeof(*this)) { Construct(pdu); } \
256  vars \
257  }; \
258  virtual bool OnReceiveMsg(PhoneDevice & client, const cls & msg)
259 
260  OPAL_SKINNY_MSG(KeepAliveMsg, 0x0000,
261  PUInt32l m_unknown;
262  );
263 
264  OPAL_SKINNY_MSG(KeepAliveAckMsg, 0x0100,
265  );
266 
267  OPAL_SKINNY_MSG(RegisterMsg, 0x0001,
268  enum { MaxNameSize = 15 };
269  char m_deviceName[MaxNameSize+1];
270  PUInt32l m_userId;
271  PUInt32l m_instance;
272  in_addr m_ip;
273  PUInt32l m_deviceType;
274  PUInt32l m_maxStreams;
275  BYTE m_unknown[16];
276  char m_macAddress[12];
277 
278  virtual void PrintOn(ostream & strm) const { strm << GetClass() << " device=" << m_deviceName << " type=" << m_deviceType << " streams=" << m_maxStreams << " ip=" << PIPAddress(m_ip); }
279  );
280 
281  OPAL_SKINNY_MSG(RegisterAckMsg, 0x0081,
282  PUInt32l m_keepAlive;
283  char m_dateFormat[6];
284  BYTE m_unknown1[2];
285  PUInt32l m_secondaryKeepAlive;
286  BYTE m_unknown2[4];
287 
288  virtual void PrintOn(ostream & strm) const { strm << GetClass() << " keepAlive=" << m_keepAlive; }
289  );
290 
291  OPAL_SKINNY_MSG(RegisterRejectMsg, 0x009d,
292  char m_errorText[32];
293  );
294 
295  OPAL_SKINNY_MSG(UnregisterMsg, 0x0027,
296  );
297 
298  OPAL_SKINNY_MSG(UnregisterAckMsg, 0x0118,
299  PUInt32l m_status;
300  );
301 
302  OPAL_SKINNY_MSG(PortMsg, 0x0002,
303  PUInt16l m_port;
304 
305  virtual void PrintOn(ostream & strm) const { strm << GetClass() << ' ' << m_port; }
306  );
307 
308  OPAL_SKINNY_MSG(CapabilityRequestMsg, 0x009B,
309  );
310 
311  OPAL_SKINNY_MSG(CapabilityResponseMsg, 0x0010,
312  PUInt32l m_count;
313  struct Info
314  {
315  PUInt32l m_codec;
316  PUInt16l m_maxFramesPerPacket;
317  char m_unknown[10];
318  } m_capability[32];
319 
320  virtual void PrintOn(ostream & strm) const { strm << GetClass() << ' ' << m_count << " codecs"; }
321 
322  void SetCount(PINDEX count)
323  {
324  m_count = count;
325  m_length = m_length - (PARRAYSIZE(m_capability) - count) * sizeof(Info);
326  }
327  );
328 
329  P_DECLARE_STREAMABLE_ENUM(CallStates,
330  eUnknownState,
331  eStateOffHook,
332  eStateOnHook,
333  eStateRingOut,
334  eStateRingIn,
335  eStateConnected,
336  eStateBusy,
337  eStateCongestion,
338  eStateHold,
339  eStateCallWaiting,
340  eStateCallTransfer,
341  eStateCallPark,
342  eStateProceed,
343  eStateCallRemoteMultiline,
344  eStateInvalidNumber
345  );
346  OPAL_SKINNY_MSG(CallStateMsg, 0x0111,
347  PUInt32l m_state;
348  PUInt32l m_lineInstance;
349  PUInt32l m_callIdentifier;
350  BYTE m_unknown[12];
351 
352  __inline CallStates GetState() const { return (CallStates)(uint32_t)m_state; }
353  virtual void PrintOn(ostream & strm) const { strm << GetClass() << ' ' << GetState() << " line=" << m_lineInstance << " call=" << m_callIdentifier; }
354  );
355 
356  P_DECLARE_STREAMABLE_ENUM(CallType,
357  eTypeUnknownCall,
358  eTypeInboundCall,
359  eTypeOutboundCall,
360  eTypeForwardCall
361  );
362  OPAL_SKINNY_MSG(CallInfoMsg, 0x008f,
363  char m_callingPartyName[40];
364  char m_callingPartyNumber[24];
365  char m_calledPartyName[40];
366  char m_calledPartyNumber[24];
367  PUInt32l m_lineInstance;
368  PUInt32l m_callIdentifier;
369  PUInt32l m_callType;
370  char m_originalCalledPartyName[40];
371  char m_originalCalledPartyNumber[24];
372  char m_lastRedirectingPartyName[40];
373  char m_lastRedirectingPartyNumber[24];
374  PUInt32l m_originalCalledPartyRedirectReason;
375  PUInt32l m_lastRedirectingReason;
376  char m_callingPartyVoiceMailbox[24];
377  char m_calledPartyVoiceMailbox[24];
378  char m_originalCalledPartyVoiceMailbox[24];
379  char m_lastRedirectingVoiceMailbox[24];
380  PUInt32l m_callInstance;
381  PUInt32l m_callSecurityStatus;
382  PUInt32l m_partyPIRestrictionBits;
383 
384  __inline CallType GetType() const { return (CallType)(uint32_t)m_callType; }
385  virtual void PrintOn(ostream & strm) const { strm << GetClass() << ' ' << GetType() << " line=" << m_lineInstance << " call=" << m_callIdentifier; }
386  );
387 
388  enum RingType
389  {
390  eRingOff = 1,
391  eRingInside,
392  eRingOutside,
393  eRingFeature
394  };
395  OPAL_SKINNY_MSG(SetRingerMsg, 0x0085,
396  PUInt32l m_ringType;
397  PUInt32l m_ringMode;
398  PUInt32l m_lineInstance;
399  PUInt32l m_callIdentifier;
400 
401  __inline RingType GetType() const { return (RingType)(uint32_t)m_ringType; }
402  __inline bool IsForever() const { return m_ringMode == 1; }
403  virtual void PrintOn(ostream & strm) const { strm << GetClass() << ' ' << GetType() << " mode=" << m_ringMode << " line=" << m_lineInstance << " call=" << m_callIdentifier; }
404  );
405 
406  OPAL_SKINNY_MSG(OffHookMsg, 0x0006,
407  PUInt32l m_lineInstance;
408  PUInt32l m_callIdentifier;
409 
410  virtual void PrintOn(ostream & strm) const { strm << GetClass() << " line=" << m_lineInstance << " call=" << m_callIdentifier; }
411  );
412 
413  OPAL_SKINNY_MSG(OnHookMsg, 0x0007,
414  PUInt32l m_lineInstance;
415  PUInt32l m_callIdentifier;
416 
417  virtual void PrintOn(ostream & strm) const { strm << GetClass() << " line=" << m_lineInstance << " call=" << m_callIdentifier; }
418  );
419 
420  enum Tones
421  {
422  eToneSilence = 0x00,
423  eToneDial = 0x21,
424  eToneBusy = 0x23,
425  eToneAlert = 0x24,
426  eToneReorder = 0x25,
427  eToneCallWaiting = 0x2d,
428  eToneNoTone = 0x7f
429  };
430  OPAL_SKINNY_MSG(StartToneMsg, 0x0082,
431  PUInt32l m_tone;
432  BYTE m_unknown[4];
433  PUInt32l m_lineInstance;
434  PUInt32l m_callIdentifier;
435 
436  __inline Tones GetType() const { return (Tones)(uint32_t)m_tone; }
437  virtual void PrintOn(ostream & strm) const { strm << GetClass() << ' ' << GetType() << " line=" << m_lineInstance << " call=" << m_callIdentifier; }
438  );
439 
440  OPAL_SKINNY_MSG(StopToneMsg, 0x0083,
441  PUInt32l m_lineInstance;
442  PUInt32l m_callIdentifier;
443 
444  virtual void PrintOn(ostream & strm) const { strm << GetClass() << " line=" << m_lineInstance << " call=" << m_callIdentifier; }
445  );
446 
447  OPAL_SKINNY_MSG(KeyPadButtonMsg, 0x0003,
448  char m_button;
449  PUInt32l m_lineInstance;
450  PUInt32l m_callIdentifier;
451 
452  virtual void PrintOn(ostream & strm) const { strm << GetClass() << " \'" << m_button<< "' line=" << m_lineInstance << " call=" << m_callIdentifier; }
453  );
454 
455  P_DECLARE_STREAMABLE_ENUM(SoftKeyEvents,
456  eSoftUnknown,
457  eSoftKeyRedial,
458  eSoftKeyNewCall,
459  eSoftKeyHold,
460  eSoftKeyTransfer,
461  eSoftKeyCfwdall,
462  eSoftKeyCfwdBusy,
463  eSoftKeyCfwdNoAnswer,
464  eSoftKeyBackspace,
465  eSoftKeyEndcall,
466  eSoftKeyResume,
467  eSoftKeyAnswer,
468  eSoftKeyInfo,
469  eSoftKeyConf,
470  eSoftKeyPark,
471  eSoftKeyJoin,
472  eSoftKeyMeetMe,
473  eSoftKeyCallPickup,
474  eSoftKeyGrpCallPickup,
475  eSoftKeyDND,
476  eSoftKeyDivert
477  );
478  OPAL_SKINNY_MSG(SoftKeyEventMsg, 0x0026,
479  PUInt32l m_event;
480  PUInt32l m_lineInstance;
481  PUInt32l m_callIdentifier;
482 
483  __inline SoftKeyEvents GetEvent() const { return (SoftKeyEvents)(uint32_t)m_event; }
484  virtual void PrintOn(ostream & strm) const { strm << GetClass() << ' ' << GetEvent() << " line=" << m_lineInstance << " call=" << m_callIdentifier; }
485  );
486 
487  OPAL_SKINNY_MSG(OpenReceiveChannelMsg, 0x0105,
488  PUInt32l m_callIdentifier;
489  PUInt32l m_passThruPartyId;
490  PUInt32l m_msPerPacket;
491  PUInt32l m_payloadCapability;
492  PUInt32l m_echoCancelType;
493  PUInt32l m_g723Bitrate;
494  BYTE m_unknown[68];
495 
496  virtual void PrintOn(ostream & strm) const { strm << GetClass() << " call=" << m_callIdentifier; }
497  );
498 
499  OPAL_SKINNY_MSG(OpenReceiveChannelAckMsg, 0x0022,
500  PUInt32l m_status;
501  in_addr m_ip;
502  PUInt16l m_port;
503  BYTE m_padding[2];
504  PUInt32l m_passThruPartyId;
505  virtual void PrintOn(ostream & strm) const { strm << GetClass() << ' ' << PIPAddress(m_ip) << ':' << m_port; }
506  );
507 
508  OPAL_SKINNY_MSG(CloseReceiveChannelMsg, 0x0106,
509  PUInt32l m_callIdentifier;
510  PUInt32l m_passThruPartyId;
511  PUInt32l m_conferenceId2;
512 
513  virtual void PrintOn(ostream & strm) const { strm << GetClass() << " call=" << m_callIdentifier; }
514  );
515 
516  OPAL_SKINNY_MSG(StartMediaTransmissionMsg, 0x008a,
517  PUInt32l m_callIdentifier;
518  PUInt32l m_passThruPartyId;
519  in_addr m_ip;
520  PUInt16l m_port;
521  BYTE m_padding[2];
522  PUInt32l m_msPerPacket;
523  PUInt32l m_payloadCapability;
524  PUInt32l m_precedence;
525  PUInt32l m_silenceSuppression;
526  PUInt32l m_maxFramesPerPacket;
527  PUInt32l m_g723Bitrate;
528  BYTE m_unknown[68];
529 
530  virtual void PrintOn(ostream & strm) const { strm << GetClass() << " call=" << m_callIdentifier << ' ' << PIPAddress(m_ip) << ':' << m_port; }
531  );
532 
533  OPAL_SKINNY_MSG(StopMediaTransmissionMsg, 0x008b,
534  PUInt32l m_callIdentifier;
535  PUInt32l m_passThruPartyId;
536  PUInt32l m_conferenceId2;
537 
538  virtual void PrintOn(ostream & strm) const { strm << GetClass() << " call=" << m_callIdentifier; }
539  );
540 #pragma pack()
541 
545 
546  protected:
547  PSafePtr<OpalSkinnyConnection> GetSkinnyConnection(const PhoneDevice & client, uint32_t callIdentifier, PSafetyMode mode = PSafeReadWrite);
548  template <class MSG> bool DelegateMsg(const PhoneDevice & client, const MSG & msg);
549 
550  typedef PDictionary<PString, PhoneDevice> PhoneDeviceDict;
551  PhoneDeviceDict m_phoneDevices;
552  PMutex m_phoneDevicesMutex;
553 };
554 
555 
558 class OpalSkinnyConnection : public OpalRTPConnection
559 {
560  PCLASSINFO(OpalSkinnyConnection, OpalRTPConnection);
561  public:
566  OpalSkinnyConnection(
567  OpalCall & call,
568  OpalSkinnyEndPoint & ep,
569  OpalSkinnyEndPoint::PhoneDevice & client,
570  unsigned callIdentifier,
571  const PString & dialNumber,
572  void * /*userData*/,
573  unsigned options,
574  OpalConnection::StringOptions * stringOptions
575  );
577 
588  virtual bool IsNetworkConnection() const { return true; }
589 
594  virtual PBoolean SetUpConnection();
595 
611  virtual void OnReleased();
612 
617  virtual OpalMediaFormatList GetMediaFormats() const;
618 
621  virtual PBoolean SetConnected();
622 
629  virtual OpalMediaType::AutoStartMode GetAutoStart(
630  const OpalMediaType & mediaType
631  ) const;
632 
644  virtual PString GetAlertingType() const;
645 
648  virtual OpalTransportAddress GetRemoteAddress() const;
650 
653  virtual bool OnReceiveMsg(const OpalSkinnyEndPoint::CallStateMsg & msg);
654  virtual bool OnReceiveMsg(const OpalSkinnyEndPoint::CallInfoMsg & msg);
655  virtual bool OnReceiveMsg(const OpalSkinnyEndPoint::SetRingerMsg & msg);
656  virtual bool OnReceiveMsg(const OpalSkinnyEndPoint::OpenReceiveChannelMsg & msg);
657  virtual bool OnReceiveMsg(const OpalSkinnyEndPoint::CloseReceiveChannelMsg & msg);
658  virtual bool OnReceiveMsg(const OpalSkinnyEndPoint::StartMediaTransmissionMsg & msg);
659  virtual bool OnReceiveMsg(const OpalSkinnyEndPoint::StopMediaTransmissionMsg & msg);
661 
662  protected:
663  OpalMediaSession * SetUpMediaSession(uint32_t payloadCapability, bool rx);
664  OpalMediaType GetMediaTypeFromId(uint32_t id);
665  void SetFromIdMediaType(const OpalMediaType & mediaType, uint32_t id);
666  void DelayCloseMediaStream(OpalMediaStreamPtr mediaStream);
667 
668  OpalSkinnyEndPoint & m_endpoint;
669  OpalSkinnyEndPoint::PhoneDevice & m_client;
670 
671  uint32_t m_lineInstance;
672  uint32_t m_callIdentifier;
673  PString m_alertingType;
674  bool m_needSoftKeyEndcall;
675 
676  uint32_t m_audioId;
677  uint32_t m_videoId;
678 
679  OpalMediaFormatList m_remoteMediaFormats;
680 };
681 
682 
683 template <class MSG> bool OpalSkinnyEndPoint::DelegateMsg(const PhoneDevice & client, const MSG & msg)
684 {
685  PSafePtr<OpalSkinnyConnection> connection = GetSkinnyConnection(client, msg.m_callIdentifier);
686  PTRACE_CONTEXT_ID_PUSH_THREAD(connection);
687  return connection == NULL || connection->OnReceiveMsg(msg);
688 }
689 
690 
691 #endif // OPAL_SKINNY
692 
693 #endif // OPAL_SKINNY_H