MythTV  master
dsmccbiop.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) David C.J. Matthews 2005, 2006
3  * Derived from libdsmcc by Richard Palmer
4  */
5 #include <cstdlib>
6 #include <cstring>
7 
8 #include "dsmccbiop.h"
9 #include "dsmccreceiver.h"
10 #include "dsmcccache.h"
11 #include "dsmccobjcarousel.h"
12 #include "dsmcc.h"
13 
14 #include "mythlogging.h"
15 
17 {
18  if (m_id)
19  free(m_id);
20  if (m_kind)
21  free(m_kind);
22 }
23 
24 int BiopNameComp::Process(const unsigned char *data)
25 {
26  int off = 0;
27 
28  m_id_len = data[off++];
29  m_id = (char*) malloc(m_id_len);
30  memcpy(m_id, data + off, m_id_len);
31 
32  off += m_id_len;
33  m_kind_len = data[off++];
34  m_kind = (char*) malloc(m_kind_len);
35  memcpy(m_kind, data + off, m_kind_len);
36 
37  off += m_kind_len;
38 
39  return off;
40 }
41 
43 {
44  delete[] m_comps;
45 }
46 
47 int BiopName::Process(const unsigned char *data)
48 {
49  int off = 0;
50  m_comp_count = data[0];
51 
52  if (m_comp_count != 1)
53  LOG(VB_DSMCC, LOG_WARNING, "[biop] Expected one name");
54 
55  off++;
57 
58  for (int i = 0; i < m_comp_count; i++)
59  {
60  int ret = m_comps[i].Process(data + off);
61  if (ret <= 0)
62  return ret;
63  off += ret;
64  }
65 
66  return off;
67 }
68 
69 int BiopBinding::Process(const unsigned char *data)
70 {
71  int off = 0, ret;
72  ret = m_name.Process(data);
73 
74  if (ret > 0)
75  off += ret;
76  else
77  return ret; // Error
78 
79  m_binding_type = data[off++];
80  ret = m_ior.Process(data + off);
81 
82  if (ret > 0)
83  off += ret;
84  else
85  return ret; // Error
86 
87  m_objinfo_len = (data[off] << 8) | data[off + 1];
88  off += 2;
89 
90  if (m_objinfo_len > 0)
91  {
92  m_objinfo = (char*) malloc(m_objinfo_len);
93  memcpy(m_objinfo, data + off, m_objinfo_len);
94  }
95  else
96  m_objinfo = nullptr;
97 
98  off += m_objinfo_len;
99 
100  return off;
101 }
102 
104 {
105  free(m_objinfo);
106 }
107 
109  unsigned char *data, unsigned long *curp)
110 {
111  // Parse header
112  if (! ProcessMsgHdr(data, curp))
113  {
114  LOG(VB_DSMCC, LOG_ERR,
115  "[biop] Invalid biop header, dropping rest of module");
116 
117  /* not valid, skip rest of data */
118  return false;
119  }
120 
121  // Handle each message type
122  if (strcmp(m_objkind, "fil") == 0)
123  {
124  LOG(VB_DSMCC, LOG_DEBUG, "[biop] Processing file");
125  return ProcessFile(cachep, filecache, data, curp);
126  }
127  if (strcmp(m_objkind, "dir") == 0)
128  {
129  LOG(VB_DSMCC, LOG_DEBUG, "[biop] Processing directory");
130  return ProcessDir(false, cachep, filecache, data, curp);
131  }
132  if (strcmp(m_objkind, "srg") == 0)
133  {
134  LOG(VB_DSMCC, LOG_DEBUG, "[biop] Processing gateway");
135  return ProcessDir(true, cachep, filecache, data, curp);
136  }
137 
138  /* Error */
139  LOG(VB_DSMCC, LOG_WARNING, QString("Unknown or unsupported format %1%2%3%4")
140  .arg(m_objkind[0]).arg(m_objkind[1])
141  .arg(m_objkind[2]).arg(m_objkind[3]));
142  return false;
143 }
144 
146 {
147  free(m_objinfo);
148  free(m_objkind);
149 }
150 
151 bool BiopMessage::ProcessMsgHdr(const unsigned char *data, unsigned long *curp)
152 {
153  const unsigned char *buf = data + (*curp);
154  int off = 0;
155 
156  if (buf[off] !='B' || buf[off +1] !='I' || buf[off +2] !='O' || buf[off +3] !='P')
157  {
158  LOG(VB_DSMCC, LOG_WARNING, "BiopMessage - invalid header");
159  return false;
160  }
161  off += 4;
162 
163  m_version_major = buf[off++];
164  m_version_minor = buf[off++];
165  if (m_version_major != 1 || m_version_minor != 0)
166  {
167  LOG(VB_DSMCC, LOG_WARNING, "BiopMessage invalid version");
168  return false;
169  }
170 
171  if (buf[off++] != 0)
172  {
173  LOG(VB_DSMCC, LOG_WARNING, "BiopMessage invalid byte order");
174  return false;
175  }
176  if (buf[off++] != 0)
177  {
178  LOG(VB_DSMCC, LOG_WARNING, "BiopMessage invalid message type");
179  return false;
180  }
181 
182  m_message_size = COMBINE32(buf, off);
183  off += 4;
184 
185  uint nObjLen = buf[off++];
186  m_objkey = DSMCCCacheKey((const char*)buf + off, nObjLen);
187  off += nObjLen;
188 
189  m_objkind_len = COMBINE32(buf, off);
190  off += 4;
191  m_objkind = (char*) malloc(m_objkind_len);
192  memcpy(m_objkind, buf + off, m_objkind_len);
193  off += m_objkind_len;
194 
195  m_objinfo_len = buf[off] << 8 | buf[off + 1];
196  off += 2;
197  m_objinfo = (char*) malloc(m_objinfo_len);
198  memcpy(m_objinfo, buf + off, m_objinfo_len);
199  off += m_objinfo_len;
200 
201  (*curp) += off;
202 
203  return true;
204 }
205 
206 
216  bool isSrg, DSMCCCacheModuleData *cachep, DSMCCCache *filecache,
217  const unsigned char *data, unsigned long *curp)
218 {
219  int off = 0;
220  const unsigned char * const buf = data + (*curp);
221 
222  if (m_objinfo_len)
223  LOG(VB_DSMCC, LOG_WARNING, "[biop] ProcessDir non-zero objectInfo_length");
224 
225  const unsigned serviceContextList_count = buf[off++];
226  if (serviceContextList_count)
227  {
228  // TODO Handle serviceContextList for service gateway
229  LOG(VB_DSMCC, LOG_WARNING, QString("[biop] ProcessDir serviceContextList count %1")
230  .arg(serviceContextList_count));
231  return false; // Error
232  }
233 
234  unsigned long msgbody_len = COMBINE32(buf, off);
235  off += 4;
236  int const start = off;
237 
238  unsigned int bindings_count = buf[off] << 8 | buf[off + 1];
239  off += 2;
240 
241  DSMCCCacheReference ref(cachep->CarouselId(), cachep->ModuleId(),
242  cachep->StreamId(), m_objkey);
243  DSMCCCacheDir *pDir = isSrg ? filecache->Srg(ref) : filecache->Directory(ref);
244 
245  for (uint i = 0; i < bindings_count; i++)
246  {
247  BiopBinding binding;
248  int ret = binding.Process(buf + off);
249  if (ret > 0)
250  off += ret;
251  else
252  return false; // Error
253 
254  if (binding.m_name.m_comp_count != 1)
255  LOG(VB_DSMCC, LOG_WARNING, "[biop] ProcessDir nameComponents != 1");
256 
257  if (binding.m_binding_type != 1 && binding.m_binding_type != 2)
258  LOG(VB_DSMCC, LOG_WARNING, "[biop] ProcessDir invalid BindingType");
259 
260  // Process any taps in this binding.
261  binding.m_ior.AddTap(filecache->m_Dsmcc);
262 
263  if (pDir && binding.m_name.m_comp_count >= 1)
264  {
265  if (strcmp("fil", binding.m_name.m_comps[0].m_kind) == 0)
266  filecache->AddFileInfo(pDir, &binding);
267  else if (strcmp("dir", binding.m_name.m_comps[0].m_kind) == 0)
268  filecache->AddDirInfo(pDir, &binding);
269  else
270  LOG(VB_DSMCC, LOG_WARNING, QString("[biop] ProcessDir unknown kind %1")
271  .arg(binding.m_name.m_comps[0].m_kind));
272  }
273  }
274 
275  if ((unsigned)(off - start) != msgbody_len)
276  LOG(VB_DSMCC, LOG_WARNING, "[biop] ProcessDir incorrect msgbody_len");
277 
278  (*curp) += off;
279 
280  return true;
281 }
282 
284  unsigned char *data, unsigned long *curp)
285 {
286  int off = 0;
287  const unsigned char *buf = data + (*curp);
288  unsigned long msgbody_len;
289  unsigned long content_len;
290 
291  if (m_objinfo_len != 8)
292  LOG(VB_DSMCC, LOG_WARNING, QString("[biop] ProcessFile objectInfo_length = %1")
293  .arg(m_objinfo_len));
294 
295  const unsigned serviceContextList_count = buf[off++];
296  if (serviceContextList_count)
297  {
298  LOG(VB_DSMCC, LOG_WARNING,
299  QString("[biop] ProcessFile Unexpected serviceContextList_count %1")
300  .arg(serviceContextList_count));
301  return false; // Error
302  }
303 
304  msgbody_len = COMBINE32(buf, off);
305  off += 4;
306  content_len = COMBINE32(buf, off);
307  off += 4;
308  if (content_len + 4 != msgbody_len)
309  LOG(VB_DSMCC, LOG_WARNING, "[biop] ProcessFile incorrect msgbody_len");
310 
311  (*curp) += off;
312 
313  DSMCCCacheReference ref(cachep->CarouselId(), cachep->ModuleId(),
314  cachep->StreamId(), m_objkey);
315 
316  QByteArray filedata = QByteArray((const char *)data+(*curp), content_len);
317  filecache->CacheFileData(ref, filedata);
318 
319  (*curp) += content_len;
320  return true;
321 }
322 
323 void ModuleDescriptorData::Process(const unsigned char *data, int length)
324 {
325  while (length > 0)
326  {
327  unsigned char tag = *data++;
328  unsigned char len = *data++;
329  length -= 2;
330  switch (tag)
331  {
332  case 0x01: // Type
333  break;
334  case 0x02: // Name
335  break;
336  case 0x03: // Info
337  break;
338  case 0x04: // Modlink
339  break;
340  case 0x05: // CRC
341  break;
342  case 0x06: // Location
343  break;
344  case 0x07: // DLtime
345  break;
346  case 0x08: // Grouplink
347  break;
348  case 0x09: // Compressed.
349  // Skip the method.
350  m_isCompressed = true;
351  m_originalSize = COMBINE32(data, 1);
352  break;
353  default:
354  break;
355  }
356  length -= len;
357  data += len;
358  }
359 }
360 
361 int BiopModuleInfo::Process(const unsigned char *data)
362 {
363  int off;
364  m_mod_timeout = COMBINE32(data, 0);
365  m_block_timeout = COMBINE32(data, 4);
366  m_min_blocktime = COMBINE32(data, 8);
367 
368  m_taps_count = data[12];
369  off = 13;
370 
371  LOG(VB_DSMCC, LOG_DEBUG, QString("[Biop] "
372  "ModuleTimeout %1 BlockTimeout %2 MinBlockTime %3 Taps %4")
374  .arg(m_taps_count));
375 
376  if (m_taps_count > 0)
377  {
378  /* only 1 allowed TODO - may not be first though ? */
379  int ret = m_tap.Process(data + off);
380  if (ret <= 0)
381  return ret;
382  off += ret;
383  }
384 
385  unsigned userinfo_len = data[off++];
386 
387  if (userinfo_len > 0)
388  {
389  m_descriptorData.Process(data + off, userinfo_len);
390  off += userinfo_len;
391  }
392  return off;
393 
394 }
395 
396 int BiopTap::Process(const unsigned char *data)
397 {
398  int off=0;
399 
400  m_id = (data[off] << 8) | data[off + 1]; // Ignored
401  off += 2;
402  m_use = (data[off] << 8) | data[off + 1];
403  off += 2;
404  m_assoc_tag = (data[off] << 8) | data[off + 1];
405  off += 2;
406  m_selector_len = data[off++];
407  m_selector_data = (char*) malloc(m_selector_len);
408  memcpy(m_selector_data, data + off, m_selector_len);
409  if (m_use == 0x0016) // BIOP_DELIVERY_PARA_USE
410  {
411  unsigned selector_type = (data[off] << 8) | data[off + 1];
412  if (m_selector_len >= 10 && selector_type == 0x0001)
413  {
414  off += 2;
415  unsigned long transactionId = COMBINE32(data, off);
416  off += 4;
417  unsigned long timeout = COMBINE32(data, off);
418  LOG(VB_DSMCC, LOG_DEBUG, QString("[biop] BIOP_DELIVERY_PARA_USE tag %1 id 0x%2 timeout %3uS")
419  .arg(m_assoc_tag).arg(transactionId,0,16).arg(timeout));
420  off += 4;
421  m_selector_len -= 10;
422  }
423  }
424 
425  off += m_selector_len;
426  return off;
427 }
428 
429 int BiopConnbinder::Process(const unsigned char *data)
430 {
431  int off = 0;
432 
433  m_component_tag = COMBINE32(data, 0);
434  if (0x49534F40 != m_component_tag)
435  {
436  LOG(VB_DSMCC, LOG_WARNING, "[biop] Invalid Connbinder tag");
437  return 0;
438  }
439  off += 4;
440  m_component_data_len = data[off++];
441  m_taps_count = data[off++];
442  if (m_taps_count > 0)
443  {
444  /* UKProfile - only first tap read */
445  int ret = m_tap.Process(data + off);
446 #if 0
447  LOG(VB_GENERAL, LOG_DEBUG, QString("Binder - assoc_tag %1")
448  .arg(m_tap.m_assoc_tag));
449 #endif
450  if (ret > 0)
451  off += ret;
452  /* else TODO error */
453  }
454 
455  return off;
456 }
457 
458 int BiopObjLocation::Process(const unsigned char *data)
459 {
460  int off = 0;
461 
462  m_component_tag = COMBINE32(data, 0);
463  if (0x49534F50 != m_component_tag)
464  {
465  LOG(VB_DSMCC, LOG_WARNING, "[biop] Invalid ObjectLocation tag");
466  return 0;
467  }
468  off += 4;
469 
470  m_component_data_len = data[off++];
471  m_Reference.m_nCarouselId = COMBINE32(data, off);
472 
473  off += 4;
474 
475  m_Reference.m_nModuleId = (data[off] << 8) | data[off + 1];
476  off += 2;
477 
478  m_version_major = data[off++];
479  m_version_minor = data[off++];
480  if (1 != m_version_major || 0 != m_version_minor)
481  {
482  LOG(VB_DSMCC, LOG_WARNING, "[biop] Invalid ObjectLocation version");
483  return 0;
484  }
485 
486  uint objKeyLen = data[off++]; /* <= 4 */
487  m_Reference.m_Key = DSMCCCacheKey((char*)data + off, objKeyLen);
488  off += objKeyLen;
489  return off;
490 }
491 
492 // A Lite profile body is used to refer to an object referenced through
493 // a different PMT, We don't support that, at least at the moment.
494 int ProfileBodyLite::Process(const unsigned char * /*data*/)
495 {
496  LOG(VB_DSMCC, LOG_WARNING, "Found LiteProfileBody - Not Implemented Yet");
497  return 0;
498 }
499 
500 int ProfileBodyFull::Process(const unsigned char *data)
501 {
502  int off = 0, ret;
503 
504  m_data_len = COMBINE32(data, off);
505  off += 4;
506 
507  /* bit order */
508  if (data[off++] != 0)
509  {
510  LOG(VB_DSMCC, LOG_WARNING, "[biop] ProfileBody invalid byte order");
511  return 0;
512  }
513 
514  m_lite_components_count = data[off++];
515  if (m_lite_components_count < 2)
516  {
517  LOG(VB_DSMCC, LOG_WARNING, "[biop] ProfileBody invalid components_count");
518  return 0;
519  }
520 
521  ret = m_obj_loc.Process(data + off);
522  if (ret <= 0)
523  return ret;
524  off += ret;
525 
526  ret = m_dsm_conn.Process(data + off);
527  if (ret <= 0)
528  return ret;
529  off += ret;
530 
532 
533  /* UKProfile - ignore anything else */
534 
535  return off;
536 }
537 
538 int BiopIor::Process(const unsigned char *data)
539 {
540  int off = 0, ret;
541  m_type_id_len = COMBINE32(data, 0);
542  m_type_id = (char*) malloc(m_type_id_len);
543  off += 4;
544  memcpy(m_type_id, data + off, m_type_id_len);
545  off += m_type_id_len;
546 
547  m_tagged_profiles_count = COMBINE32(data, off);
548  if (m_tagged_profiles_count < 1)
549  {
550  LOG(VB_DSMCC, LOG_WARNING, "[biop] IOR missing taggedProfile");
551  return 0;
552  }
553  off += 4;
554 
555  m_profile_id_tag = COMBINE32(data, off);
556  off += 4;
557 
558  if (m_profile_id_tag == 0x49534F06) // profile_id_tag == 0x49534F06
559  {
561  ret = m_profile_body->Process(data + off);
562  if (ret <= 0)
563  return ret;
564  off += ret;
565  }
566  else if(m_profile_id_tag == 0x49534F05) // profile_id_tag == 0x49534F05
567  {
569  ret = m_profile_body->Process(data + off);
570  if (ret <= 0)
571  return ret;
572  off += ret;
573  }
574  else
575  {
576  /* UKProfile - receiver may ignore other profiles */
577  LOG(VB_DSMCC, LOG_WARNING, QString("[biop] Unknown Ior profile 0x%1")
578  .arg(m_profile_id_tag, 0, 16));
579  return 0;
580  }
581 
582  return off;
583 }
584 
585 // An IOR may refer to other streams. We may have to add taps for them.
586 void BiopIor::AddTap(Dsmcc *pStatus)
587 {
589  if (ref != nullptr)
590  pStatus->AddTap(ref->m_nStreamTag, ref->m_nCarouselId);
591 }
592 
594 {
595  free(m_selector_data);
596 }
char * m_kind
Definition: dsmccbiop.h:29
BiopObjLocation m_obj_loc
Definition: dsmccbiop.h:108
unsigned short m_id
Definition: dsmccbiop.h:52
int Process(const unsigned char *)
Definition: dsmccbiop.cpp:458
unsigned int m_objinfo_len
Definition: dsmccbiop.h:193
ProfileBody * m_profile_body
Definition: dsmccbiop.h:145
bool ProcessFile(DSMCCCacheModuleData *cachep, DSMCCCache *cache, unsigned char *data, unsigned long *curp)
Definition: dsmccbiop.cpp:283
BiopTap m_tap
Definition: dsmccbiop.h:221
int Process(const unsigned char *Data)
Definition: dsmccbiop.cpp:361
unsigned long m_originalSize
Definition: dsmccbiop.h:209
void AddTap(Dsmcc *pStatus)
Definition: dsmccbiop.cpp:586
Definition: dsmcc.h:75
Dsmcc * m_Dsmcc
Definition: dsmcccache.h:132
unsigned long m_type_id_len
Definition: dsmccbiop.h:141
int Process(const unsigned char *)
Definition: dsmccbiop.cpp:24
unsigned int uint
Definition: compat.h:140
char * m_objinfo
Definition: dsmccbiop.h:162
unsigned short m_nModuleId
Definition: dsmcccache.h:60
DSMCCCacheDir * Srg(const DSMCCCacheReference &ref)
Definition: dsmcccache.cpp:133
unsigned long m_block_timeout
Definition: dsmccbiop.h:218
unsigned char m_id_len
Definition: dsmccbiop.h:26
char * m_type_id
Definition: dsmccbiop.h:142
void CacheFileData(const DSMCCCacheReference &ref, const QByteArray &data)
Definition: dsmcccache.cpp:179
char m_binding_type
Definition: dsmccbiop.h:159
unsigned long CarouselId(void) const
char * m_objkind
Definition: dsmccbiop.h:197
unsigned short m_use
Definition: dsmccbiop.h:53
virtual DSMCCCacheReference * GetReference()=0
char * m_objinfo
Definition: dsmccbiop.h:194
int Process(const unsigned char *)
Definition: dsmccbiop.cpp:396
unsigned short m_selector_len
Definition: dsmccbiop.h:56
unsigned long m_min_blocktime
Definition: dsmccbiop.h:219
DSMCCCacheKey m_objkey
Definition: dsmccbiop.h:191
#define COMBINE32(data, idx)
Definition: dsmcc.h:117
void AddFileInfo(DSMCCCacheDir *dir, const BiopBinding *)
Definition: dsmcccache.cpp:206
unsigned char m_version_major
Definition: dsmccbiop.h:188
int Process(const unsigned char *)
Definition: dsmccbiop.cpp:47
unsigned short m_nStreamTag
Definition: dsmcccache.h:61
unsigned char m_version_minor
Definition: dsmccbiop.h:189
unsigned char m_taps_count
Definition: dsmccbiop.h:220
DSMCCCacheReference m_Reference
Definition: dsmccbiop.h:84
unsigned int m_objinfo_len
Definition: dsmccbiop.h:161
unsigned short ModuleId(void) const
bool Process(DSMCCCacheModuleData *cachep, DSMCCCache *cache, unsigned char *data, unsigned long *curp)
Definition: dsmccbiop.cpp:108
BiopTap m_tap
Definition: dsmccbiop.h:69
char m_lite_components_count
Definition: dsmccbiop.h:107
void AddDirInfo(DSMCCCacheDir *dir, const BiopBinding *)
Definition: dsmcccache.cpp:223
ObjCarousel * AddTap(unsigned short componentTag, unsigned carouselId)
Add a tap.
Definition: dsmcc.cpp:60
unsigned char m_comp_count
Definition: dsmccbiop.h:40
ModuleDescriptorData m_descriptorData
Definition: dsmccbiop.h:223
DSMCCCacheModuleData contains information about a module and holds the blocks for a partly completed ...
unsigned char m_component_data_len
Definition: dsmccbiop.h:67
DSMCCCacheDir * Directory(const DSMCCCacheReference &ref)
Definition: dsmcccache.cpp:156
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
unsigned long m_tagged_profiles_count
Definition: dsmccbiop.h:143
unsigned short m_assoc_tag
Definition: dsmccbiop.h:55
BiopIor m_ior
Definition: dsmccbiop.h:160
unsigned char m_taps_count
Definition: dsmccbiop.h:68
The object carousel is transmitted as a directed graph.
Definition: dsmcccache.h:94
DSMCCCacheKey m_Key
Definition: dsmcccache.h:62
unsigned char m_kind_len
Definition: dsmccbiop.h:27
int Process(const unsigned char *data)
Definition: dsmccbiop.cpp:69
unsigned int m_message_size
Definition: dsmccbiop.h:190
unsigned long m_nCarouselId
Definition: dsmcccache.h:59
char m_component_data_len
Definition: dsmccbiop.h:81
char m_version_minor
Definition: dsmccbiop.h:83
unsigned long m_data_len
Definition: dsmccbiop.h:105
unsigned long m_objkind_len
Definition: dsmccbiop.h:192
int Process(const unsigned char *)
Definition: dsmccbiop.cpp:429
virtual int Process(const unsigned char *)=0
int Process(const unsigned char *) override
Definition: dsmccbiop.cpp:494
int Process(const unsigned char *)
Definition: dsmccbiop.cpp:538
void Process(const unsigned char *data, int length)
Definition: dsmccbiop.cpp:323
bool ProcessDir(bool isSrg, DSMCCCacheModuleData *cachep, DSMCCCache *cache, const unsigned char *data, unsigned long *curp)
Process a Directory message.
Definition: dsmccbiop.cpp:215
bool ProcessMsgHdr(const unsigned char *data, unsigned long *curp)
Definition: dsmccbiop.cpp:151
unsigned long m_component_tag
Definition: dsmccbiop.h:66
BiopName m_name
Definition: dsmccbiop.h:158
char * m_id
Definition: dsmccbiop.h:28
unsigned long m_profile_id_tag
Definition: dsmccbiop.h:144
char m_version_major
Definition: dsmccbiop.h:82
BiopNameComp * m_comps
Definition: dsmccbiop.h:41
unsigned long m_mod_timeout
Definition: dsmccbiop.h:217
unsigned short StreamId(void) const
unsigned long m_component_tag
Definition: dsmccbiop.h:80
int Process(const unsigned char *) override
Definition: dsmccbiop.cpp:500
char * m_selector_data
Definition: dsmccbiop.h:57
BiopConnbinder m_dsm_conn
Definition: dsmccbiop.h:112