AJA NTV2 SDK  18.0.0.2717
NTV2 SDK 18.0.0.2717
ntv2nubaccess.cpp
Go to the documentation of this file.
1 /* SPDX-License-Identifier: MIT */
7 #include "ajatypes.h"
8 #include "ntv2utils.h"
9 #include "ntv2nubaccess.h"
10 #include "ntv2publicinterface.h"
11 #include "ntv2version.h"
12 #include "ajabase/system/debug.h"
13 #include "ajabase/common/common.h"
15 #include "ajabase/system/atomic.h"
16 #include "ajabase/system/info.h" // for AJASystemInfo
17 #include <iomanip>
18 #if !defined(NTV2_PREVENT_PLUGIN_LOAD)
20  #include "ajabase/system/thread.h"
21  #include <fstream>
22  #include "mbedtls/x509.h"
23  #include "mbedtls/error.h"
24  #include "mbedtls/md.h"
25  #include "mbedtls/ssl.h"
26 #endif // defined(NTV2_PREVENT_PLUGIN_LOAD)
27 #if defined(AJAMac)
28  #include <CoreFoundation/CoreFoundation.h>
29  #include <dlfcn.h>
30  #define DLL_EXTENSION ".dylib"
31  #define PATH_DELIMITER "/"
32  #define FIRMWARE_FOLDER "Firmware"
33 #elif defined(AJALinux)
34  #include <dlfcn.h>
35  #define DLL_EXTENSION ".so"
36  #define PATH_DELIMITER "/"
37  #define FIRMWARE_FOLDER "firmware"
38 #elif defined(MSWindows)
39  #define DLL_EXTENSION ".dll"
40  #define PATH_DELIMITER "\\"
41  #define FIRMWARE_FOLDER "Firmware"
42 #elif defined(AJABareMetal)
43  #define DLL_EXTENSION ".so"
44  #define PATH_DELIMITER "/"
45  #define FIRMWARE_FOLDER "firmware"
46 #endif
47 #define SIG_EXTENSION ".sig"
48 
49 using namespace std;
50 
51 #define INSTP(_p_) xHEX0N(uint64_t(_p_),16)
52 #define NBFAIL(__x__) AJA_sERROR (AJA_DebugUnit_RPCClient, INSTP(this) << "::" << AJAFUNC << ": " << __x__)
53 #define NBWARN(__x__) AJA_sWARNING(AJA_DebugUnit_RPCClient, INSTP(this) << "::" << AJAFUNC << ": " << __x__)
54 #define NBNOTE(__x__) AJA_sNOTICE (AJA_DebugUnit_RPCClient, INSTP(this) << "::" << AJAFUNC << ": " << __x__)
55 #define NBINFO(__x__) AJA_sINFO (AJA_DebugUnit_RPCClient, INSTP(this) << "::" << AJAFUNC << ": " << __x__)
56 #define NBDBG(__x__) AJA_sDEBUG (AJA_DebugUnit_RPCClient, INSTP(this) << "::" << AJAFUNC << ": " << __x__)
57 #define NBCFAIL(__x__) AJA_sERROR (AJA_DebugUnit_RPCClient, AJAFUNC << ": " << __x__)
58 #define NBCWARN(__x__) AJA_sWARNING(AJA_DebugUnit_RPCClient, AJAFUNC << ": " << __x__)
59 #define NBCNOTE(__x__) AJA_sNOTICE (AJA_DebugUnit_RPCClient, AJAFUNC << ": " << __x__)
60 #define NBCINFO(__x__) AJA_sINFO (AJA_DebugUnit_RPCClient, AJAFUNC << ": " << __x__)
61 #define NBCDBG(__x__) AJA_sDEBUG (AJA_DebugUnit_RPCClient, AJAFUNC << ": " << __x__)
62 #define NBSFAIL(__x__) AJA_sERROR (AJA_DebugUnit_RPCServer, AJAFUNC << ": " << __x__)
63 #define NBSWARN(__x__) AJA_sWARNING(AJA_DebugUnit_RPCServer, AJAFUNC << ": " << __x__)
64 #define NBSNOTE(__x__) AJA_sNOTICE (AJA_DebugUnit_RPCServer, AJAFUNC << ": " << __x__)
65 #define NBSINFO(__x__) AJA_sINFO (AJA_DebugUnit_RPCServer, AJAFUNC << ": " << __x__)
66 #define NBSDBG(__x__) AJA_sDEBUG (AJA_DebugUnit_RPCServer, AJAFUNC << ": " << __x__)
67 
68 #define PLGFAIL(__x__) AJA_sERROR (AJA_DebugUnit_Plugins, AJAFUNC << ": " << __x__)
69 #define PLGWARN(__x__) AJA_sWARNING(AJA_DebugUnit_Plugins, AJAFUNC << ": " << __x__)
70 #define PLGNOTE(__x__) AJA_sNOTICE (AJA_DebugUnit_Plugins, AJAFUNC << ": " << __x__)
71 #define PLGINFO(__x__) AJA_sINFO (AJA_DebugUnit_Plugins, AJAFUNC << ": " << __x__)
72 #define PLGDBG(__x__) AJA_sDEBUG (AJA_DebugUnit_Plugins, AJAFUNC << ": " << __x__)
73 
74 #define P_FAIL(__x__) do \
75  { \
76  ostringstream _os_; \
77  _os_ << AJAFUNC << ": " << __x__; \
78  if (useStdout()) \
79  cout << "## ERROR: " << _os_.str() << endl; \
80  AJA_sERROR (AJA_DebugUnit_Plugins, _os_.str()); \
81  errMsg = _os_.str(); \
82  } while (false)
83 #define P_WARN(__x__) if (useStdout()) cout << "## WARNING: " << AJAFUNC << ": " << __x__ << endl; \
84  AJA_sWARNING(AJA_DebugUnit_Plugins, AJAFUNC << ": " << __x__)
85 #define P_NOTE(__x__) if (useStdout()) cout << "## NOTE: " << AJAFUNC << ": " << __x__ << endl; \
86  AJA_sNOTICE (AJA_DebugUnit_Plugins, AJAFUNC << ": " << __x__)
87 #define P_INFO(__x__) if (useStdout()) cout << "## INFO: " << AJAFUNC << ": " << __x__ << endl; \
88  AJA_sINFO (AJA_DebugUnit_Plugins, AJAFUNC << ": " << __x__)
89 #define P_DBG(__x__) if (useStdout()) cout << "## DEBUG: " << AJAFUNC << ": " << __x__ << endl; \
90  AJA_sDEBUG (AJA_DebugUnit_Plugins, AJAFUNC << ": " << __x__)
91 //#define _DEBUGSTATS_ // Define this to log above construct/destruct & open/close tallies
92 #if defined(_DEBUGSTATS_)
93  #define PDBGX(__x__) AJA_sDEBUG (AJA_DebugUnit_Plugins, INSTP(this) << "::" << AJAFUNC << ": " << __x__)
94 #else
95  #define PDBGX(__x__)
96 #endif
97 
98 
99 // Stats
100 uint32_t gBaseConstructCount(0); // Number of NTV2RPCBase constructor calls made
101 uint32_t gBaseDestructCount(0); // Number of NTV2RPCBase destructor calls made
102 uint32_t gClientConstructCount(0); // Number of NTV2RPCClient constructor calls made
103 uint32_t gClientDestructCount(0); // Number of NTV2RPCClient destructor calls made
104 uint32_t gServerConstructCount(0); // Number of NTV2RPCServer constructor calls made
105 uint32_t gServerDestructCount(0); // Number of NTV2RPCServer destructor calls made
106 uint32_t gLoaderConstructCount(0); // Number of NTV2PluginLoader constructor calls made
107 uint32_t gLoaderDestructCount(0); // Number of NTV2PluginLoader destructor calls made
108 uint32_t gPluginConstructCount(0); // Number of NTV2Plugin constructor calls made
109 uint32_t gPluginDestructCount(0); // Number of NTV2Plugin destructor calls made
110 
111 
112 string NTV2Dictionary::valueForKey (const string & inKey) const
113 {
114  DictConstIter it(mDict.find(inKey));
115  if (it == mDict.end())
116  return "";
117  return it->second;
118 }
119 
120 uint16_t NTV2Dictionary::u16ValueForKey (const string & inKey, const uint16_t inDefault) const
121 {
122  string str(valueForKey(inKey));
123  if (str.empty())
124  return inDefault;
125  if (str.find("0x") == 0 || str.find("0X") == 0)
126  {
127  str.erase(0,2);
128  if (str.empty())
129  return inDefault;
130  return uint16_t(aja::stoul(str, AJA_NULL, 16));
131  }
132  if (str.find("x") == 0 || str.find("X") == 0)
133  {
134  str.erase(0,1);
135  if (str.empty())
136  return inDefault;
137  return uint16_t(aja::stoul(str, AJA_NULL, 16));
138  }
139  if (str.find("o") == 0 || str.find("O") == 0)
140  {
141  str.erase(0,1);
142  if (str.empty())
143  return inDefault;
144  return uint16_t(aja::stoul(str, AJA_NULL, 8));
145  }
146  if (str.find("b") == 0 || str.find("B") == 0)
147  {
148  str.erase(0,1);
149  if (str.empty())
150  return inDefault;
151  return uint16_t(aja::stoul(str, AJA_NULL, 2));
152  }
153  return uint16_t(aja::stoul(str, AJA_NULL, 10));
154 }
155 
156 ostream & NTV2Dictionary::Print (ostream & oss, const bool inCompact) const
157 {
158  if (inCompact)
159  for (DictConstIter it(mDict.begin()); it != mDict.end(); )
160  {
161  const string & key(it->first), val(it->second), quote(val.find(' ') != string::npos ? "'" : "");
162  oss << key << "=" << quote << val << quote;
163  if (++it != mDict.end())
164  oss << " ";
165  }
166  else if (empty())
167  oss << "0 entries";
168  else
169  {
170  const int kyWdth(int(largestKeySize()+0)), valWdth(int(largestValueSize()+0));
171  oss << string(size_t(kyWdth), '-') << " " << string(size_t(valWdth), '-') << endl;
172  for (DictConstIter it(mDict.begin()); it != mDict.end(); )
173  {
174  const string & key(it->first), val(it->second);
175  oss << std::setw(kyWdth) << key << " : " << val;
176  if (++it != mDict.end())
177  oss << endl;
178  }
179  }
180  return oss;
181 }
182 
183 bool NTV2Dictionary::deserialize (const string & inStr)
184 {
185  size_t badKVPairs(0), insertFailures(0);
186  clear();
187  const NTV2StringList keyValPairs (aja::split(inStr, "\n"));
188  for (NTV2StringListConstIter it(keyValPairs.begin()); it != keyValPairs.end(); ++it)
189  {
190  const NTV2StringList keyValPair (aja::split(*it, "\t"));
191  if (keyValPair.size() != 2)
192  {badKVPairs++; continue;}
193  const string k(keyValPair.at(0)), v(keyValPair.at(1));
194  if (!insert(k, v))
195  insertFailures++;
196  }
197  return !empty() && !badKVPairs && !insertFailures;
198 }
199 
200 bool NTV2Dictionary::serialize (string & outStr) const
201 {
202  outStr.clear();
203  ostringstream oss;
204  for (DictConstIter it(mDict.begin()); it != mDict.end(); )
205  {
206  oss << it->first << "\t" << it->second;
207  if (++it != mDict.end())
208  oss << "\n";
209  }
210  outStr = oss.str();
211  return !outStr.empty();
212 }
213 
215 {
216  NTV2StringSet result;
217  for (DictConstIter it(mDict.begin()); it != mDict.end(); ++it)
218  result.insert(it->first);
219  return result;
220 }
221 
223 {
224  size_t result(0);
225  for (DictConstIter it(mDict.begin()); it != mDict.end(); ++it)
226  if (it->first.length() > result)
227  result = it->first.length();
228  return result;
229 }
230 
232 {
233  size_t result(0);
234  for (DictConstIter it(mDict.begin()); it != mDict.end(); ++it)
235  if (it->second.length() > result)
236  result = it->second.length();
237  return result;
238 }
239 
240 bool NTV2Dictionary::insert (const string & inKey, const string & inValue)
241 {
242  if (inKey.empty())
243  return false;
244  if (inKey.find("\t") != string::npos)
245  return false;
246  if (inKey.find("\n") != string::npos)
247  return false;
248  if (inValue.find("\t") != string::npos)
249  return false;
250  if (inValue.find("\n") != string::npos)
251  return false;
252  mDict[inKey] = inValue;
253  return true;
254 }
255 
257 {
258  size_t numUpdated(0);
259  for (DictConstIter it(inDict.mDict.begin()); it != inDict.mDict.end(); ++it)
260  if (hasKey(it->first))
261  {mDict[it->first] = it->second; numUpdated++;}
262  return numUpdated;
263 }
264 
266 {
267  size_t numAdded(0);
268  for (DictConstIter it(inDict.mDict.begin()); it != inDict.mDict.end(); ++it)
269  if (!hasKey(it->first))
270  {mDict[it->first] = it->second; numAdded++;}
271  return numAdded;
272 }
273 
274 
276 {
277  Reset(inSpec);
278 }
279 
280 void NTV2DeviceSpecParser::Reset (const string inSpec)
281 {
282  mErrors.clear();
283  mResult.clear();
284  mQueryParams.clear();
285  mPos = 0;
286  mSpec = inSpec;
287  if (!mSpec.empty())
288  Parse(); // Go ahead and parse it
289 }
290 
291 string NTV2DeviceSpecParser::Resource (const bool inStripLeadSlash) const
292 {
293  string rsrc (Result(kConnectParamResource));
294  if (rsrc.empty())
295  return rsrc;
296  if (!inStripLeadSlash)
297  return rsrc;
298  if (rsrc.at(0) == '/')
299  rsrc.erase(0,1);
300  return rsrc;
301 }
302 
303 void NTV2DeviceSpecParser::Parse (void)
304 {
305  // A run of 3 consecutive letters that match "ntv" -- probably a scheme
306  // A run of 1 or 2 decimal digits -- probably a local device index number
307  // "0X" or "0x":
308  // - maybe a hexadecimal 32-bit value -- a local device ID
309  // - maybe a hexadecimal 64-bit value -- a local device serial number
310  // A run of 8 or 9 alphanumeric chars -- probably a local device serial number
311  ostringstream err;
312  string tokDevID, tokIndexNum, tokScheme, tokSerial, tokModelName, tokIPV4, tokPortNum;
313  size_t posDevID(0), posIndexNum(0), posScheme(0), posSerial(0), posModelName(0), posNetAddr(0);
314  bool isSerial(ParseSerialNum(posSerial, tokSerial)), isScheme(ParseScheme(posScheme, tokScheme));
315  bool isIndexNum(ParseDecNumber(posIndexNum, tokIndexNum)), isDeviceID(ParseDeviceID(posDevID, tokDevID));
316  bool isModelName(ParseModelName(posModelName, tokModelName));
317  bool isIPV4Port(ParseHostAddressAndPortNumber(posNetAddr, tokIPV4, tokPortNum));
318  if (isScheme && tokScheme == kLegalSchemeNTV2Local)
319  { // Re-parse serial#, index#, deviceID, modelName from just past "://"...
320  posDevID = posIndexNum = posSerial = posModelName = posScheme;
321  isSerial = ParseSerialNum(posSerial, tokSerial);
322  isIndexNum = ParseDecNumber(posIndexNum, tokIndexNum);
323  isDeviceID = ParseDeviceID(posDevID, tokDevID);
324  isModelName = ParseModelName(posModelName, tokModelName);
325  }
326  do
327  {
328  if (isModelName)
329  {
330  mPos = posModelName;
332  mResult.insert(kConnectParamDevModel, tokModelName);
333  break;
334  }
335  if (isSerial)
336  { // Final serial number checks...
337  bool converted(false);
338  mPos = posSerial;
339  if (tokSerial.length() == 18) // 64-bit hex value?
340  {
341  // Convert numeric serial number into character string...
342  const bool hasLeading0X (tokSerial.find("0X") == 0 || tokSerial.find("0x") == 0);
343  const string hex64(tokSerial.substr(hasLeading0X ? 2 : 0, 16));
344  const ULWord64 serNum64(aja::stoull(hex64, AJA_NULL, 16));
345  string serTxt; // (CNTV2Card::SerialNum64ToString(serNum64));
346  for (size_t ndx(0); ndx < 8; ndx++)
347  serTxt += char(serNum64 >> ((7-ndx)*8));
348  //cerr << "Converted '" << tokSerial << "' into '" << serTxt << "'" << endl;
349  tokSerial = serTxt;
350  converted = true;
351  }
352  // Check for illegal characters in serial number:
353  for (size_t ndx(0); ndx < tokSerial.length(); ndx++)
354  { char ch(tokSerial.at(ndx));
355  if ( ! ( ( (ch >= '0') && (ch <= '9') ) ||
356  ( (ch >= 'A') && (ch <= 'Z') ) ||
357  ( (ch >= 'a') && (ch <= 'z') ) ||
358  (ch == ' ') || (ch == '-') ) )
359  {
360  err << "Illegal serial number character '" << (ch ? ch : '?') << "' (" << xHEX0N(UWord(ch),2) << ")";
361  AddError(err.str());
362  mPos -= converted ? 16 : 8; mPos += ndx * (converted ? 2 : 1) + (converted ? 1 : 0);
363  break;
364  }
365  }
366  mResult.insert(kConnectParamDevSerial, tokSerial);
368  break;
369  }
370  if (isDeviceID)
371  {
372  mPos = posDevID;
373  mResult.insert(kConnectParamDevID, tokDevID);
375  break;
376  }
377  if (isIndexNum)
378  {
379  if (posIndexNum < SpecLength())
380  { // Check if extra chars past index num is dotted quad:
381  if (isIPV4Port && !tokIPV4.empty())
382  {
383  mPos = posNetAddr;
384  mResult.insert(kConnectParamScheme, "ntv2nubrpclib");
385  mResult.insert(kConnectParamHost, tokIPV4);
386  if (!tokPortNum.empty())
387  mResult.insert(kConnectParamPort, tokPortNum);
388  break;
389  }
390  err << "Extra characters past index number";
391  AddError(err.str());
392  break;
393  }
394  mPos = posIndexNum;
395  mResult.insert(kConnectParamDevIndex, tokIndexNum);
397  break;
398  }
399  if (!isScheme || (isScheme && tokScheme == kLegalSchemeNTV2Local))
400  { // No such local device
401  err << "Invalid local device specification";
402  AddError(err.str());
403  mPos += isScheme ? 12 : 0;
404  break;
405  }
406  if (isScheme)
407  { // Continue parsing URLspec...
408  mPos = posScheme;
409  // "xxxx://swdevice/?"
410  // "nosharedmemory"
411  // "&supportlog=file%3A%2F%2F%2FUsers%2Fdemo%2FDesktop%2FAJAWatcherSupport.log"
412  // "&sdram=file%3A%2F%2F%2FUsers%2Fdemo%2FDesktop%2FSDRAMsnapshot.dat");
413  // Host[port]/[resource[?query]]
414  size_t posURL(posScheme), posRsrc(0);
415  string host, port, rsrcPath;
416  if (!ParseHostAddressAndPortNumber(posURL, host, port))
417  {mPos = posURL; AddError("Bad host address or port number"); break;}
418  mPos = posURL;
419  mResult.insert(kConnectParamScheme, tokScheme);
420  mResult.insert(kConnectParamHost, host);
421  if (!port.empty())
422  mResult.insert(kConnectParamPort, port);
423 
424  // Parse resource path...
425  posRsrc = mPos;
426  if (ParseResourcePath(posRsrc, rsrcPath))
427  {mPos = posRsrc; mResult.insert(kConnectParamResource, rsrcPath);}
428  // Parse query...
429  size_t posQuery(mPos);
430  NTV2Dictionary params;
431  if (ParseQuery(posQuery, params))
432  {
433  mResult.insert(kConnectParamQuery, DeviceSpec().substr(mPos, posQuery-mPos+1));
434  mQueryParams = params;
435  mPos = posQuery;
436  }
437  }
438  } while (false); // Once thru
439  if (mPos < SpecLength())
440  {err << "Parser failed at character position " << DEC(mPos); AddError(err.str());}
441  #if defined(_DEBUG)
442  ostringstream oss;
443  if (Successful())
444  { oss << "NTV2DeviceSpecParser::Parse success: '" << DeviceSpec() << "' -- ";
445  Print(oss);
447  }
448  else
449  { oss << "NTV2DeviceSpecParser::Parse failed: ";
450  PrintErrors(oss);
452  }
453  #endif // defined(_DEBUG)
454 } // Parse
455 
456 ostream & NTV2DeviceSpecParser::Print (ostream & oss, const bool inDumpResults) const
457 {
458  if (IsLocalDevice())
459  oss << "local device";
460  else if (HasScheme())
461  oss << "device '" << Scheme() << "'";
462  else
463  oss << "device";
464  if (HasResult(kConnectParamDevSerial))
465  oss << " serial '" << DeviceSerial() << "'";
466  else if (HasResult(kConnectParamDevModel))
467  oss << " model '" << DeviceModel() << "'";
468  else if (HasResult(kConnectParamDevID))
469  oss << " ID '" << DeviceID() << "'";
470  else if (HasResult(kConnectParamDevIndex))
471  oss << " " << DeviceIndex();
472  if (HasResult(kConnectParamHost))
473  oss << " host '" << Result(kConnectParamHost) << "'";
474  if (HasResult(kConnectParamPort))
475  oss << " port " << Result(kConnectParamPort);
476  if (HasResult(kConnectParamResource))
477  oss << " resource '" << Result(kConnectParamResource) << "'";
478  if (HasResult(kConnectParamQuery))
479  oss << " query '" << Result(kConnectParamQuery) << "'";
480  if (inDumpResults)
481  {oss << endl; Results().Print(oss, /*compact?*/false);}
482  return oss;
483 }
484 
485 string NTV2DeviceSpecParser::MakeDeviceSpec (const bool urlEncodeQuery) const
486 {
487  if (!Successful())
488  return "";
489  ostringstream result;
490  if (IsLocalDevice())
491  {
492  result << "ntv2local://";
493  if (HasResult(kConnectParamDevSerial))
494  result << DeviceSerial();
495  else if (HasResult(kConnectParamDevModel))
496  result << DeviceModel();
497  else if (HasResult(kConnectParamDevID))
498  result << DeviceID();
499  else if (HasResult(kConnectParamDevIndex))
500  result << DeviceIndex();
501  else
502  return "";
503  return result.str();
504  }
505  result << Scheme() << "://";
506  if (HasResult(kConnectParamHost))
507  result << Result(kConnectParamHost);
508  if (HasResult(kConnectParamPort))
509  result << ":" << Result(kConnectParamPort);
510  result << Result(kConnectParamResource);
511  if (HasQueryParams())
512  {
513  string q (MakeQueryString(urlEncodeQuery));
514  if (!q.empty())
515  result << "?" << q;
516  }
517  return result.str();
518 }
519 
520 string NTV2DeviceSpecParser::MakeQueryString (const bool urlEncode) const
521 {
522  if (!Successful())
523  return "";
524  if (!HasQueryParams())
525  return "";
526  NTV2StringList parms;
527  const NTV2StringSet ks (mQueryParams.keys());
528  for (NTV2StringSetConstIter it(ks.begin()); it != ks.end(); ++it)
529  {
530  ostringstream oss;
531  string k(*it), v(mQueryParams.valueForKey(k));
532  if (urlEncode)
533  oss << ::PercentEncode(k) << "=" << ::PercentEncode(v);
534  else
535  oss << k << "=" << v;
536  parms.push_back(oss.str());
537  }
538  return aja::join(parms, "&");
539 }
540 
542 {
543  ostringstream oss;
544  Print(oss);
545  return oss.str();
546 }
547 
549 {
550  string devIDStr (Result(kConnectParamDevID));
551  if (devIDStr.find("0X") != string::npos)
552  devIDStr.erase(0,2); // Delete "0x"
553  ULWord u32 = ULWord(aja::stoull(devIDStr, AJA_NULL, 16));
554  return NTV2DeviceID(u32);
555 }
556 
558 {
559  string devIDStr (Result(kConnectParamDevIndex));
560  UWord u16 = UWord(aja::stoul(devIDStr));
561  return u16;
562 }
563 
564 ostream & NTV2DeviceSpecParser::PrintErrors (ostream & oss) const
565 {
566  oss << DEC(ErrorCount()) << (ErrorCount() == 1 ? " error" : " errors") << (HasErrors() ? ":" : "");
567  if (HasErrors())
568  {
569  oss << endl
570  << DeviceSpec() << endl
571  << string(mPos ? mPos : 0,' ') << "^" << endl;
572  for (size_t num(0); num < ErrorCount(); )
573  {
574  oss << Error(num);
575  if (++num < ErrorCount())
576  oss << endl;
577  }
578  }
579  return oss;
580 }
581 
582 bool NTV2DeviceSpecParser::ParseHexNumber (size_t & pos, string & outToken)
583 {
584  outToken.clear();
585  string tokHexNum;
586  while (pos < SpecLength())
587  {
588  const char ch(CharAt(pos));
589  if (tokHexNum.length() == 0)
590  {
591  if (ch != '0')
592  break;
593  ++pos; tokHexNum = ch;
594  }
595  else if (tokHexNum.length() == 1)
596  {
597  if (ch != 'x' && ch != 'X')
598  break;
599  ++pos; tokHexNum += ch;
600  }
601  else
602  {
603  if (!IsHexDigit(ch))
604  break;
605  ++pos; tokHexNum += ch;
606  }
607  }
608  if (tokHexNum.length() > 2) // At least 3 chars
609  {aja::upper(tokHexNum); outToken = tokHexNum;} // Force upper-case hex
610  return !outToken.empty();
611 }
612 
613 bool NTV2DeviceSpecParser::ParseDecNumber (size_t & pos, string & outToken)
614 {
615  outToken.clear();
616  string tokDecNum;
617  while (pos < SpecLength())
618  {
619  const char ch(CharAt(pos));
620  if (!IsDecimalDigit(ch))
621  break;
622  ++pos;
623  if (ch != '0' || tokDecNum != "0") // This prevents accumulating more than one leading zero
624  tokDecNum += ch;
625  }
626  if (tokDecNum.length() > 0) // At least 1 char
627  outToken = tokDecNum;
628  return !outToken.empty();
629 }
630 
631 bool NTV2DeviceSpecParser::ParseAlphaNum (size_t & pos, string & outToken, const std::string & inOtherChars)
632 { // Run of letters and/or digits, but must start with letter
633  outToken.clear();
634  string tokAlphaNum;
635  while (pos < SpecLength())
636  {
637  const char ch(CharAt(pos));
638  if (!IsLetter(ch) && !IsDecimalDigit(ch) && inOtherChars.find(ch) == string::npos)
639  break; // Break if not letter/digit
640  if (tokAlphaNum.empty() && !IsLetter(ch))
641  break; // Didn't start with letter!
642  ++pos; tokAlphaNum += ch;
643  }
644  if (tokAlphaNum.length() > 0)
645  outToken = tokAlphaNum;
646  return !outToken.empty();
647 }
648 
649 bool NTV2DeviceSpecParser::ParseAlphaNumeric (size_t & pos, string & outToken, const std::string & inOtherChars)
650 { // Run of letters and/or digits (and can start with either)
651  outToken.clear();
652  string tokAlphaNum;
653  while (pos < SpecLength())
654  {
655  const char ch(CharAt(pos));
656  if (!IsLetter(ch) && !IsDecimalDigit(ch) && inOtherChars.find(ch) == string::npos)
657  break;
658  ++pos; tokAlphaNum += ch;
659  }
660  if (tokAlphaNum.length() > 0)
661  outToken = tokAlphaNum;
662  return !outToken.empty();
663 }
664 
665 bool NTV2DeviceSpecParser::ParseScheme (size_t & pos, string & outToken)
666 {
667  outToken.clear();
668  string rawScheme, tokScheme;
669  while (ParseAlphaNum(pos, rawScheme))
670  {
671  tokScheme = rawScheme;
672  char ch(CharAt(pos));
673  if (ch != ':')
674  break;
675  ++pos; tokScheme += ch;
676 
677  ch = CharAt(pos);
678  if (ch != '/')
679  break;
680  ++pos; tokScheme += ch;
681 
682  ch = CharAt(pos);
683  if (ch != '/')
684  break;
685  ++pos; tokScheme += ch;
686  break;
687  }
688  if (tokScheme.find("://") != string::npos) // Contains "://"
689  {aja::lower(rawScheme); outToken = rawScheme;} // Force lower-case
690  return !outToken.empty();
691 }
692 
693 bool NTV2DeviceSpecParser::ParseSerialNum (size_t & pos, string & outToken)
694 {
695  outToken.clear();
696  string tokAlphaNum, tokHexNum;
697  size_t origPos(pos), posAlphaNum(pos), posHexNum(pos);
698  do
699  {
700  while (posAlphaNum < SpecLength())
701  {
702  const char ch(CharAt(posAlphaNum));
703  if (!IsUpperLetter(ch) && !IsLowerLetter(ch) && !IsDecimalDigit(ch) && ch != '-' && ch != ' ')
704  break;
705  ++posAlphaNum; tokAlphaNum += ch;
706  }
707  if (tokAlphaNum.length() < 2) // At least 2 upper-case chars
708  tokAlphaNum.clear();
709  else if (tokAlphaNum.length() == 8 || tokAlphaNum.length() == 9)
710  {pos = posAlphaNum; outToken = tokAlphaNum; break;}
711 
712  if (ParseHexNumber(posHexNum, tokHexNum))
713  if (tokHexNum.length() == 18) // 64-bit value!
714  {pos = posHexNum; outToken = tokHexNum;}
715  } while (false);
716  if (tokAlphaNum == "ntv2kona1") // HACK! Can't open 'ntv2kona1' plugin without this hack!
717  {outToken.clear(); pos = origPos; return false;} // ('ntv2kona1' looks like a serial number!)
718  return !outToken.empty();
719 }
720 
721 bool NTV2DeviceSpecParser::ParseDeviceID (size_t & pos, string & outToken)
722 {
723  outToken.clear();
724  string tokHexNum;
725  if (!ParseHexNumber(pos, tokHexNum))
726  return false;
727  if (tokHexNum.length() != 10)
728  return false;
729  aja::upper(tokHexNum); // Fold to upper case
730 
731  // Check if it matches a known supported NTV2DeviceID...
733  NTV2StringSet devIDStrs;
734  for (NTV2DeviceIDSetConstIter it(allDevIDs.begin()); it != allDevIDs.end(); ++it)
735  {
736  ostringstream devID; devID << xHEX0N(*it,8);
737  string devIDStr(devID.str());
738  aja::upper(devIDStr);
739  devIDStrs.insert(devIDStr);
740  } // for each known/supported NTV2DeviceID
741  if (devIDStrs.find(tokHexNum) != devIDStrs.end())
742  outToken = tokHexNum; // Valid!
743  return !outToken.empty();
744 }
745 
746 bool NTV2DeviceSpecParser::ParseModelName (size_t & pos, string & outToken)
747 {
748  outToken.clear();
749  string tokName;
750  if (!ParseAlphaNum(pos, tokName, " "))
751  return false;
752  aja::lower(tokName); // Fold to lower case
753 
754  // Check if it matches a known supported device model name...
756  NTV2StringSet modelNames;
757  for (NTV2DeviceIDSetConstIter it(allDevIDs.begin()); it != allDevIDs.end(); ++it)
758  {
759  string modelName(::NTV2DeviceIDToString(*it));
760  aja::lower(modelName);
761  modelNames.insert(modelName);
762  } // for each known/supported NTV2DeviceID
763  if (modelNames.find(tokName) != modelNames.end())
764  outToken = tokName; // Valid!
765  return !outToken.empty();
766 }
767 
768 bool NTV2DeviceSpecParser::ParseDNSName (size_t & pos, string & outDNSName)
769 {
770  outDNSName.clear();
771  string dnsName, name;
772  size_t dnsPos(pos);
773  char ch(0);
774  while (ParseAlphaNum(dnsPos, name, "_-")) // also allow '_' and '-'
775  {
776  if (!dnsName.empty())
777  dnsName += '.';
778  dnsName += name;
779  ch = CharAt(dnsPos);
780  if (ch != '.')
781  break;
782  ++dnsPos;
783  }
784  if (!dnsName.empty())
785  pos = dnsPos;
786  outDNSName = dnsName;
787  return !outDNSName.empty();
788 }
789 
790 bool NTV2DeviceSpecParser::ParseIPv4Address (size_t & pos, string & outIPv4)
791 {
792  outIPv4.clear();
793  NTV2StringList ipv4Name;
794  string num;
795  size_t ipv4Pos(pos);
796  char ch(0);
797  while (ParseDecNumber(ipv4Pos, num))
798  {
799  ipv4Name.push_back(num);
800  ch = CharAt(ipv4Pos);
801  if (ch != '.')
802  break;
803  ++ipv4Pos;
804  }
805  if (ipv4Name.size() == 4)
806  pos = ipv4Pos;
807  outIPv4 = aja::join(ipv4Name, ".");
808  return ipv4Name.size() == 4;
809 }
810 
811 bool NTV2DeviceSpecParser::ParseHostAddressAndPortNumber (size_t & pos, string & outAddr, string & outPort)
812 {
813  outAddr.clear(); outPort.clear();
814  // Look for a DNSName or an IPv4 dotted quad...
815  string dnsName, ipv4, port;
816  size_t dnsPos(pos), ipv4Pos(pos), portPos(0);
817  bool isDNS(ParseDNSName(dnsPos, dnsName)), isIPv4(ParseIPv4Address(ipv4Pos, ipv4));
818  if (!isDNS && !isIPv4)
819  {pos = dnsPos < ipv4Pos ? ipv4Pos : dnsPos; return false;}
820  // NOTE: It's possible to have both isIPv4 && isDNS true -- in this case, isIPv4 takes precedence:
821  if (isIPv4)
822  {outAddr = ipv4; pos = portPos = ipv4Pos;}
823  else if (isDNS)
824  {outAddr = dnsName; pos = portPos = dnsPos;}
825 
826  // Check for optional port number
827  char ch (CharAt(portPos));
828  if (ch != ':')
829  return true;
830  ++portPos;
831  if (!ParseDecNumber(portPos, port))
832  {pos = portPos; return false;} // Bad port number!
833  outPort = port;
834  pos = portPos;
835  return true;
836 }
837 
838 bool NTV2DeviceSpecParser::ParseResourcePath (size_t & pos, string & outRsrc)
839 {
840  outRsrc.clear();
841  string rsrc, name;
842  size_t rsrcPos(pos);
843  char ch(CharAt(rsrcPos));
844  while (ch == '/')
845  {
846  ++rsrcPos;
847  rsrc += '/';
848  if (!ParseAlphaNumeric(rsrcPos, name, " "))
849  break;
850  rsrc += name;
851  ch = CharAt(rsrcPos);
852  }
853  if (!rsrc.empty())
854  pos = rsrcPos;
855  outRsrc = rsrc;
856  return !outRsrc.empty();
857 }
858 
859 bool NTV2DeviceSpecParser::ParseParamAssignment (size_t & pos, string & outKey, string & outValue)
860 {
861  outKey.clear(); outValue.clear();
862  string key, value;
863  size_t paramPos(pos);
864  char ch(CharAt(paramPos));
865  if (ch == '&')
866  ch = CharAt(++paramPos);
867  do
868  {
869  if (!ParseAlphaNumeric(paramPos, key))
870  break;
871  ch = CharAt(paramPos);
872  if (ch != '=')
873  break;
874  ch = CharAt(++paramPos);
875  while (ch != 0 && ch != '&')
876  {
877  value += ch;
878  ch = CharAt(++paramPos);
879  }
880  } while (false);
881  if (!key.empty())
882  {pos = paramPos; outKey = key; outValue = value;}
883  return !key.empty();
884 }
885 
886 bool NTV2DeviceSpecParser::ParseQuery (size_t & pos, NTV2Dictionary & outParams)
887 {
888  outParams.clear();
889  string key, value;
890  size_t queryPos(pos);
891  char ch(CharAt(queryPos));
892  if (ch != '?')
893  return false;
894  queryPos++;
895 
896  while (ParseParamAssignment(queryPos, key, value))
897  {
898  outParams.insert(key, value);
899  ch = CharAt(queryPos);
900  if (ch != '&')
901  break;
902  }
903  if (!outParams.empty())
904  pos = queryPos;
905  return !outParams.empty();
906 }
907 
908 bool NTV2DeviceSpecParser::IsUpperLetter (const char inChar)
909 { static const string sHexDigits("_ABCDEFGHIJKLMNOPQRSTUVWXYZ");
910  return sHexDigits.find(inChar) != string::npos;
911 }
912 
913 bool NTV2DeviceSpecParser::IsLowerLetter (const char inChar)
914 { static const string sHexDigits("abcdefghijklmnopqrstuvwxyz");
915  return sHexDigits.find(inChar) != string::npos;
916 }
917 
918 bool NTV2DeviceSpecParser::IsLetter (const char inChar, const bool inIncludeUnderscore)
919 { return (inIncludeUnderscore && inChar == '_') || IsUpperLetter(inChar) || IsLowerLetter(inChar);
920 }
921 
922 bool NTV2DeviceSpecParser::IsDecimalDigit (const char inChar)
923 { static const string sDecDigits("0123456789");
924  return sDecDigits.find(inChar) != string::npos;
925 }
926 
927 bool NTV2DeviceSpecParser::IsHexDigit (const char inChar)
928 { static const string sHexDigits("0123456789ABCDEFabcdef");
929  return sHexDigits.find(inChar) != string::npos;
930 }
931 
932 bool NTV2DeviceSpecParser::IsLegalSerialNumChar (const char inChar)
933 { return IsLetter(inChar) || IsDecimalDigit(inChar);
934 }
935 
936 #if defined(_DEBUG)
937  void NTV2DeviceSpecParser::test (void)
938  {
939  NTV2DeviceSpecParser specParser;
940  specParser.Reset("1");
941  specParser.Reset("00000000000000000000000000000000000000000000000000000000000000000000000000000000000001");
942  specParser.Reset("corvid24");
943  specParser.Reset("corvid88");
944  specParser.Reset("konalhi");
945  specParser.Reset("alpha");
946  specParser.Reset("00T64450");
947  specParser.Reset("00t6-450");
948  specParser.Reset("BLATZBE0");
949  specParser.Reset("0x424C41545A424530");
950  specParser.Reset("0x424C415425424530");
951 
952  specParser.Reset("badscheme://1");
953 
954  specParser.Reset("ntv2local://1");
955  specParser.Reset("NtV2lOcAl://00000000000000000000000000000000000000000000000000000000000000000000000000000000000001");
956  specParser.Reset("NTV2Local://corvid24");
957  specParser.Reset("ntv2local://corvid88");
958  specParser.Reset("ntv2local://konalhi");
959  specParser.Reset("ntv2local://alpha");
960  specParser.Reset("ntv2local://00T64450");
961  specParser.Reset("ntv2local://00t6-450");
962  specParser.Reset("ntv2local://BLATZBE0");
963 
964  specParser.Reset("ntv2nub://1.2.3.4");
965  specParser.Reset("ntv2nub://1.2.3.4/doc");
966  specParser.Reset("ntv2nub://1.2.3.4/doc/");
967  specParser.Reset("ntv2nub://1.2.3.4/doc/alpha?one&two=2&three=&four=4");
968  specParser.Reset("ntv2nub://1.2.3.4/doc/?one&two=2&three=&four=4");
969  specParser.Reset("ntv2nub://1.2.3.4:badport/doc?one&two=2&three=&four=4");
970  specParser.Reset("ntv2nub://1.2.3.4:200/doc?one&two=2&three=&four=4");
971  specParser.Reset("ntv2nub://1.2.3.4:200/doc/?one&two=2&three=&four=4");
972  specParser.Reset("ntv2nub://1.2.3.4:12345");
973  specParser.Reset("ntv2nub://1.2.3.4:65000/doc");
974  specParser.Reset("ntv2nub://1.2.3.4:32767/doc/");
975  specParser.Reset("ntv2nub://1.2.3.4/path/to/doc/");
976  specParser.Reset("ntv2nub://1.2.3.4/path/to/doc/?");
977  specParser.Reset("ntv2nub://1.2.3.4/path/to/doc?");
978  specParser.Reset("ntv2nub://1.2.3.4/path/to/doc/?one");
979  specParser.Reset("ntv2nub://1.2.3.4/path/to/doc?one");
980  specParser.Reset("ntv2nub://1.2.3.4/path/to/doc/?one=");
981  specParser.Reset("ntv2nub://1.2.3.4/path/to/doc?one=");
982  specParser.Reset("ntv2nub://1.2.3.4/path/to/doc/?one=1");
983  specParser.Reset("ntv2nub://1.2.3.4/path/to/doc?one=1");
984  specParser.Reset("ntv2nub://1.2.3.4/path/to/doc/?one=1&two");
985  specParser.Reset("ntv2nub://1.2.3.4/path/to/doc?one=1&two");
986  specParser.Reset("ntv2nub://50.200.250.300");
987  specParser.Reset("ntv2nub://fully.qualified.domain.name.com/path/to/doc/?one=1&two");
988  specParser.Reset("ntv2nub://fully.qualified.domain.name.edu:badport/path/to/doc/?one=1&two");
989  specParser.Reset("ntv2nub://fully.qualified.domain.name.info:5544/path/to/doc/?one=1&two");
990  specParser.Reset("ntv2nub://fully.qualified.domain.name.org/path/to/doc/?one=1&two");
991  specParser.Reset("ntv2nub://fully.qualified.domain.name.nz:badport/path/to/doc/?one=1&two");
992  specParser.Reset("ntv2nub://fully.qualified.domain.name.au:000004/path/to/doc/?one=1&two");
993  specParser.Reset("ntv2nub://fully.qualified.domain.name.ch:4/corvid88");
994  specParser.Reset("ntv2nub://fully.qualified.domain.name.cn:4/00T64450");
995  specParser.Reset("ntv2nub://fully.qualified.domain.name.ru:4/2");
996  specParser.Reset("ntv2nub://fully.qualified.domain.name.co.uk:4/00000000000000000000000000000001");
997  specParser.Reset("ntv2nub://fully.qualified.domain.name.com:4/0000000000000000000000000000000001");
998  specParser.Reset("ntv2://swdevice/?"
999  "nosharedmemory"
1000  "&supportlog=file%3A%2F%2F%2FUsers%2Fdemo%2FDesktop%2FAJAWatcherSupport.log"
1001  "&sdram=file%3A%2F%2F%2FUsers%2Fdemo%2FDesktop%2FSDRAMsnapshot.dat");
1002  }
1003 #endif // defined(_DEBUG)
1004 
1005 #if defined(MSWindows)
1006  static string WinErrStr (const DWORD inErr)
1007  {
1008  string result("foo");
1009  LPVOID lpMsgBuf;
1010  const DWORD res(FormatMessage ( FORMAT_MESSAGE_ALLOCATE_BUFFER
1011  | FORMAT_MESSAGE_FROM_SYSTEM
1012  | FORMAT_MESSAGE_IGNORE_INSERTS, // dwFlags
1013  AJA_NULL, // lpSource: n/a
1014  inErr, // dwMessageId: n/a
1015  MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // dwLanguageId
1016  (LPTSTR) &lpMsgBuf, // output buffer
1017  0, // output buffer size, in TCHARs
1018  AJA_NULL)); // user params
1019  if (lpMsgBuf)
1020  {
1021  result = reinterpret_cast<const char *>(lpMsgBuf);
1022  LocalFree(lpMsgBuf);
1023  }
1024  return result;
1025  }
1026 #endif // MSWindows
1027 
1028 
1029 #if !defined(NTV2_PREVENT_PLUGIN_LOAD)
1030 
1031 /*****************************************************************************************************************************************************
1032  NTV2Plugin
1033 *****************************************************************************************************************************************************/
1034 
1037 
1038 // Wraps handle returned from dlopen/LoadLibrary, calls dlclose/FreeLibrary upon destruction
1040 {
1041  public:
1042  static bool LoadPlugin (const string & path, const string & folderPath, NTV2PluginPtr & outPtr, string & outErrMsg, const bool inUseStdout);
1043 
1044  public:
1045  #if defined(MSWindows)
1046  NTV2Plugin (HMODULE handle, const string & path, const bool useStdout);
1047  inline operator HMODULE() const {return mHandle;}
1048  #else
1049  NTV2Plugin (void * handle, const string & path, const bool useStdout);
1050  inline operator void*() const {return mHandle;}
1051  #endif
1052  ~NTV2Plugin (void);
1053  inline bool isLoaded (void) const {return mHandle && !mPath.empty() ? true : false;}
1054  void * addressForSymbol (const string & inSymbol, string & outErrorMsg);
1055 
1056  private:
1057  NTV2Plugin();
1058  NTV2Plugin(const NTV2Plugin & rhs);
1059  NTV2Plugin & operator = (const NTV2Plugin & rhs);
1060  inline bool useStdout(void) {return mUseStdout;}
1061  private:
1062  #if defined(MSWindows)
1063  HMODULE mHandle;
1064  #else
1065  void * mHandle;
1066  #endif
1067  string mPath;
1068  bool mUseStdout;
1069 }; // NTV2Plugin
1070 
1071 // One-stop-shop to load a plugin & instantiate its NTV2Plugin instance
1072 bool NTV2Plugin::LoadPlugin (const string & path, const string & folderPath, NTV2PluginPtr & outPtr, string & outErrMsg, const bool inUseStdout)
1073 {
1074  ostringstream loadErr;
1075  #if defined(AJABareMetal)
1076  return false; // unimplemented
1077  #elif defined(MSWindows)
1078  // Open the DLL (Windows)...
1079  std::wstring dllsFolderW;
1080  aja::string_to_wstring(folderPath, dllsFolderW);
1081  if (!AddDllDirectory(dllsFolderW.c_str()))
1082  {
1083  loadErr << "AddDllDirectory '" << path << "' failed: " << WinErrStr(::GetLastError());
1084  return false;
1085  } // AddDllDirectory failed
1086  HMODULE h = ::LoadLibraryExA(LPCSTR(path.c_str()), AJA_NULL, LOAD_LIBRARY_SEARCH_DEFAULT_DIRS);
1087  if (!h)
1088  loadErr << "Unable to open '" << path << "': " << WinErrStr(::GetLastError());
1089  #else // MacOS or Linux
1090  // Open the .dylib (MacOS) or .so (Linux)...
1091  void * h = ::dlopen(path.c_str(), RTLD_LAZY);
1092  if (!h)
1093  {
1094  const char * pErrorStr(::dlerror());
1095  const string errStr (pErrorStr ? pErrorStr : "");
1096  loadErr << "Unable to open '" << path << "': " << errStr;
1097  } // dlopen failed
1098  #endif // MacOS or Linux
1099  if (!loadErr.str().empty())
1100  outErrMsg = loadErr.str();
1101  if (!h)
1102  return false;
1103  outPtr = new NTV2Plugin(h, path, inUseStdout);
1104  return outPtr;
1105 }
1106 
1107 NTV2Plugin::NTV2Plugin()
1108 {
1109  NTV2_ASSERT(false);
1111 }
1112 
1114 {
1115  NTV2_ASSERT(false);
1117 }
1118 
1119 NTV2Plugin & NTV2Plugin::operator = (const NTV2Plugin & rhs)
1120 {
1121  NTV2_ASSERT(false);
1122  return *this;
1123 }
1124 
1125 #if defined(MSWindows)
1126 NTV2Plugin::NTV2Plugin (HMODULE handle, const string & path, const bool inUseStdout)
1127 #else
1128 NTV2Plugin::NTV2Plugin (void * handle, const string & path, const bool inUseStdout)
1129 #endif
1130  : mHandle(handle),
1131  mPath(path)
1132 {
1133  NTV2_ASSERT(mHandle);
1134  NTV2_ASSERT(!mPath.empty());
1136  P_NOTE("Dynamic/shared library '" << mPath << "' (" << INSTP(mHandle) << ") loaded, "
1137  << DEC(gPluginConstructCount) << " created, " << DEC(gPluginDestructCount) << " destroyed");
1138 }
1139 
1141 {
1142  if (mHandle)
1143  #if defined(AJABareMetal)
1144  ; // unimplemented
1145  #elif !defined(MSWindows)
1146  ::dlclose(mHandle);
1147  #else // macOS or Linux
1148  ::FreeLibrary(mHandle);
1149  #endif
1151  P_NOTE("Dynamic/shared library '" << mPath << "' (" << INSTP(mHandle) << ") unloaded, "
1152  << DEC(gPluginConstructCount) << " created, " << DEC(gPluginDestructCount) << " destroyed");
1153  mHandle = AJA_NULL;
1154  mPath.clear();
1155 }
1156 
1157 void * NTV2Plugin::addressForSymbol (const string & inSymbolName, string & outErrorMsg)
1158 {
1159  outErrorMsg.clear();
1160  if (!mHandle)
1161  return AJA_NULL;
1162  if (inSymbolName.empty())
1163  return AJA_NULL;
1164  void * result(AJA_NULL);
1165  ostringstream err;
1166  #if defined(AJABareMetal)
1167  // TODO
1168  #elif defined(MSWindows)
1169  result = reinterpret_cast<void*>(::GetProcAddress(reinterpret_cast<HMODULE>(mHandle), inSymbolName.c_str()));
1170  if (!result)
1171  err << "'GetProcAddress' failed for '" << inSymbolName << "': " << WinErrStr(::GetLastError());
1172  #else // MacOS or Linux
1173  result = ::dlsym(mHandle, inSymbolName.c_str());
1174  if (!result)
1175  { const char * pErrorStr(::dlerror());
1176  const string errStr (pErrorStr ? pErrorStr : "");
1177  err << "'dlsym' failed for '" << inSymbolName << "': " << errStr;
1178  }
1179  #endif // MacOS or Linux
1180  outErrorMsg = err.str();
1181  return result;
1182 } // addressForSymbol
1183 
1184 
1185 /*****************************************************************************************************************************************************
1186  @brief A singleton that tracks and monitors loaded plugins, and frees them when no one is using them.
1187  @bug This doesn't work on some platforms when libajantv2 is statically linked into the plugin. When
1188  the plugin loads, the plugin gets its own separate libajantv2 static globals, and thus, a second
1189  set of libajantv2 singletons, including this one.
1190 *****************************************************************************************************************************************************/
1193 
1194 // Singleton that tracks plugin use
1196 {
1197  public: // Class Methods
1198  static PluginRegistry & Get (void);
1199  static void Terminate (void);
1200  static inline void EnableDebugging (const bool inEnable = true) {sDebugRegistry = inEnable;}
1201  static inline bool DebuggingEnabled (void) {return sDebugRegistry;}
1202 
1203  public: // Instance Methods
1204  PluginRegistry();
1205  ~PluginRegistry();
1206  bool loadPlugin (const string & path, const string & folderPath, NTV2PluginPtr & outPtr, string & errMsg, const bool useStdout);
1207  bool unloadPlugin (const string & path, string & errMsg);
1208  bool pluginIsLoaded (const string & path);
1209  bool pluginForPath (const string & path, NTV2PluginPtr & outHandle);
1210  NTV2StringList loadedPlugins (void);
1211  NTV2StringList pluginStats (void); // returns string list, each has pluginPath<tab>refCount
1212  bool hasPath (const string & path);
1213  bool indexForPath (const string & path, size_t & outIndex);
1214  ULWord countForPath (const string & path);
1215  uint32_t * refConForPath (const string & path);
1216  inline bool useStdout (void) const {return DebuggingEnabled();}
1217 
1218  private:
1219  typedef map<string, NTV2PluginPtr> NTV2PluginMap;
1220  NTV2StringList mPluginPaths; // List of unique known plugins; only grows, never shrinks
1221  ULWordSequence mPluginCounts; // Per-plugin instance counts: correlates to gPluginPaths
1222  ULWordSequence mCompareCounts; // For detecting changes to mPluginCounts
1223  NTV2PluginMap mPluginMap; // Maps each unique plugin path to its corresponding NTV2Plugin instance
1224  AJALock mPluginMapLock; // Mutex to serialize access to these registry globals
1225  AJAThread mMonitor; // Thread that monitors plugin utilization
1226  bool mQuitMonitor; // Set true to terminate monitor
1227  private:
1228  static void Monitor (AJAThread * pThread, void * pContext);
1229  void monitor (void); // Monitor thread function
1230  static PluginRegistryPtr sSingleton;
1231  static AJALock sMutex;
1232  static bool sDebugRegistry;
1233 }; // PluginRegistry
1234 
1235 PluginRegistryPtr PluginRegistry::sSingleton;
1236 AJALock PluginRegistry::sMutex;
1237 bool PluginRegistry::sDebugRegistry(false);
1238 
1240 {
1241  AJAAutoLock tmp(&sMutex);
1242  if (!sSingleton)
1243  sSingleton = new PluginRegistry;
1244  return *sSingleton;
1245 }
1246 
1248 {
1249  AJAAutoLock tmp(&sMutex);
1250  PLGWARN("");
1251  sSingleton = PluginRegistryPtr();
1252 }
1253 
1254 void PluginRegistry::Monitor (AJAThread * pThread, void * pContext)
1255 { (void) pThread;
1256  PluginRegistry * pObj (reinterpret_cast<PluginRegistry*>(pContext));
1257  if (pObj)
1258  pObj->monitor();
1259 }
1260 
1262  : mQuitMonitor(false)
1263 {
1264  P_NOTE ("PluginRegistry " << INSTP(this) << " constructed");
1265  mPluginCounts.reserve(256);
1266  for (size_t num(0); num < 256; num++)
1267  mPluginCounts.push_back(0);
1268  mCompareCounts = mPluginCounts;
1269  mMonitor.Attach(Monitor, this);
1271  mMonitor.Start();
1272 }
1273 
1275 {
1276  mQuitMonitor = true;
1277  while (mMonitor.Active())
1278  AJATime::Sleep(10);
1279  P_NOTE("PluginRegistry singleton " << INSTP(this) << " destroyed:" << endl << aja::join(pluginStats(), "\n"));
1280 }
1281 
1282 bool PluginRegistry::loadPlugin (const string & path, const string & folderPath, NTV2PluginPtr & outPtr, string & errMsg, const bool inUseStdout)
1283 {
1284  AJAAutoLock tmp(&mPluginMapLock);
1285  outPtr = NTV2PluginPtr();
1286  if (path.empty())
1287  {P_FAIL("empty path"); return false;}
1288  if (pluginForPath(path, outPtr))
1289  {
1290  NTV2_ASSERT(hasPath(path));
1291  return true;
1292  }
1293  if (hasPath(path))
1294  {P_WARN(INSTP(this) << ": '" << path << "': 'pluginForPath' returned false, but 'hasPath' returned true, count=" << countForPath(path));}
1295  string msg;
1296  if (!NTV2Plugin::LoadPlugin (path, folderPath, outPtr, msg, inUseStdout))
1297  {P_FAIL(msg); return false;}
1298  P_NOTE(INSTP(this) << ": Dynamic/shared library '" << path << "' loaded");
1299  mPluginMap[path] = outPtr;
1300  mPluginPaths.push_back(path);
1301  mPluginCounts.at(mPluginPaths.size()-1) = 0;
1302  return true;
1303 }
1304 
1305 bool PluginRegistry::unloadPlugin (const string & path, string & errMsg)
1306 {
1307  AJAAutoLock tmp(&mPluginMapLock);
1308  NTV2PluginPtr ptr;
1309  if (path.empty())
1310  return false;
1311  if (!pluginForPath(path, ptr))
1312  {P_FAIL(INSTP(this) << ": '" << path << "' requested to unload, but not loaded"); return false;}
1313  mPluginMap.erase(path); // This should cause NTV2Plugin destructor to be called
1314  P_NOTE(INSTP(this) << ": '" << path << "' unloaded");
1315  return true;
1316 }
1317 
1318 bool PluginRegistry::pluginIsLoaded (const string & path)
1319 {
1320  AJAAutoLock tmp(&mPluginMapLock);
1321  return mPluginMap.find(path) != mPluginMap.end();
1322 }
1323 
1324 bool PluginRegistry::pluginForPath (const string & path, NTV2PluginPtr & outHandle)
1325 {
1326  AJAAutoLock tmp(&mPluginMapLock);
1327  NTV2PluginMap::const_iterator it(mPluginMap.find(path));
1328  if (it == mPluginMap.end())
1329  outHandle = NTV2PluginPtr();
1330  else
1331  outHandle = it->second;
1332  return outHandle;
1333 }
1334 
1336 {
1337  NTV2StringList result;
1338  AJAAutoLock tmp(&mPluginMapLock);
1339  for (NTV2PluginMap::const_iterator it(mPluginMap.begin()); it != mPluginMap.end(); ++it)
1340  result.push_back(it->first);
1341  return result;
1342 }
1343 
1345 {
1346  NTV2StringList result;
1347  AJAAutoLock tmp(&mPluginMapLock);
1348  for (size_t ndx(0); ndx < mPluginPaths.size(); ndx++)
1349  {
1350  const string path (mPluginPaths.at(ndx));
1351  ostringstream oss; oss << path << "\t" << DEC(countForPath(path));
1352  NTV2PluginPtr p;
1353  if (pluginForPath(path, p))
1354  oss << "\t" << (p->isLoaded() ? "loaded" : "unloaded");
1355  else
1356  oss << "\t" << "---";
1357  result.push_back(oss.str());
1358  }
1359  return result;
1360 }
1361 
1362 bool PluginRegistry::hasPath (const string & path)
1363 {
1364  size_t ndx(0);
1365  return indexForPath(path,ndx);
1366 }
1367 
1368 bool PluginRegistry::indexForPath (const string & path, size_t & outIndex)
1369 {
1370  AJAAutoLock tmp(&mPluginMapLock);
1371  for (outIndex = 0; outIndex < mPluginPaths.size(); outIndex++)
1372  if (path == mPluginPaths.at(outIndex))
1373  return true;
1374  return false;
1375 }
1376 
1377 uint32_t * PluginRegistry::refConForPath (const string & path)
1378 {
1379  AJAAutoLock tmp(&mPluginMapLock);
1380  size_t ndx(0);
1381  if (indexForPath(path, ndx))
1382  return &mPluginCounts[ndx];
1383  return AJA_NULL;
1384 }
1385 
1387 {
1388  size_t ndx(0);
1389  if (indexForPath(path, ndx))
1390  return mPluginCounts.at(ndx);
1391  return 0;
1392 }
1393 
1394 void PluginRegistry::monitor (void)
1395 {
1396  P_NOTE("PluginRegistry " << INSTP(this) << " monitor started");
1397  ostringstream oss; oss << "PluginReg" << HEX0N(uint32_t(uint64_t(this)),8);
1398  mMonitor.SetThreadName(oss.str().c_str());
1399  while (!mQuitMonitor)
1400  {
1401  {
1402  AJAAutoLock tmp(&mPluginMapLock);
1403  for (size_t ndx(0); ndx < mPluginPaths.size(); ndx++)
1404  {
1405  const uint32_t oldCount(mCompareCounts.at(ndx)), newCount(mPluginCounts.at(ndx));
1406  if (newCount != oldCount)
1407  {
1408  string errMsg, path(mPluginPaths.at(ndx));
1409  if (newCount > oldCount)
1410  {P_NOTE("PluginRegistry " << INSTP(this) << ": Plugin '" << path << "' utilization "
1411  << "increased from " << DEC(oldCount) << " to " << DEC(newCount));}
1412  else
1413  {
1414  P_NOTE("PluginRegistry " << INSTP(this) << ": Plugin '" << path << "' utilization "
1415  << "decreased from " << DEC(oldCount) << " to " << DEC(newCount));
1416  if (newCount == 0)
1417  unloadPlugin(path, errMsg);
1418  } // else count decreased
1419  mCompareCounts.at(ndx) = newCount;
1420  } // something changed
1421  } // for each plugin
1422  }
1423  AJATime::Sleep(250);
1424  }
1425  P_NOTE("PluginRegistry " << INSTP(this) << " monitor stopped");
1426 }
1427 
1428 /*****************************************************************************************************************************************************
1429  @brief Knows how to load & validate a plugin
1430 *****************************************************************************************************************************************************/
1432 {
1433  public: // Instance Methods
1434  NTV2PluginLoader (NTV2Dictionary & params);
1435  ~NTV2PluginLoader ();
1436  void * getFunctionAddress (const string & inFuncName);
1437  inline string pluginPath (void) const {return mDict.valueForKey(kNTV2PluginInfoKey_PluginPath);}
1438  inline string pluginSigPath (void) const {return mDict.valueForKey(kNTV2PluginInfoKey_PluginSigPath);}
1439  inline string pluginsPath (void) const {return mDict.valueForKey(kNTV2PluginInfoKey_PluginsPath);}
1440  inline string pluginBaseName (void) const {return mDict.valueForKey(kNTV2PluginInfoKey_PluginBaseName);}
1441  bool isValidated (void) const;
1442  inline bool showParams (void) const {return mQueryParams.hasKey(kQParamShowParams);}
1443  void * refCon (void) const;
1445  protected: // Used internally
1446  bool validate (void);
1447  void * getSymbolAddress (const string & inSymbolName, string & outErrorMsg);
1448  bool getPluginsFolder (string & outPath) const;
1449  bool getBaseNameFromScheme (string & outName) const;
1450  inline bool isOpen (void) {return mpPlugin ? mpPlugin->isLoaded() : false;}
1451  inline bool useStdout (void) const {return mQueryParams.hasKey(kQParamLogToStdout);}
1452  inline bool isVerbose (void) const {return mQueryParams.hasKey(kQParamVerboseLogging);}
1453  inline bool showCertificate (void) const {return mQueryParams.hasKey(kQParamShowX509Cert);}
1454  bool fail (void);
1456  private: // Instance Data
1457  NTV2Dictionary & mDict;
1458  NTV2Dictionary mQueryParams;
1459  NTV2PluginPtr mpPlugin;
1460  bool mValidated;
1461  mutable string errMsg;
1462 
1463  protected: // Class Methods
1464  static bool ExtractCertInfo (NTV2Dictionary & outInfo, const string & inStr);
1465  static bool ExtractIssuerInfo (NTV2Dictionary & outInfo, const string & inStr, const string & inParentKey);
1466  static string mbedErrStr (const int mbedtlsReturnCode);
1467 }; // NTV2PluginLoader
1468 
1469 
1470 // Constructor -- peforms all preparatory work: determines which plugin to load, then loads & validates it
1472  : mDict(params),
1473  mValidated(false)
1474 {
1477  const NTV2Dictionary originalParams(mDict);
1478  if (NTV2DeviceSpecParser::ParseQueryParams (mDict, mQueryParams) && !mQueryParams.empty())
1479  mDict.addFrom(mQueryParams);
1480  if (mDict.hasKey(kNTV2PluginInfoKey_Fingerprint))
1481  mDict.erase(kNTV2PluginInfoKey_Fingerprint); // Be sure caller can't cheat
1482  P_INFO("Loader created for '" << mDict.valueForKey(kConnectParamScheme) << "', " << DEC(gLoaderConstructCount) << " created, "
1483  << DEC(gLoaderDestructCount) << " destroyed");
1484 
1485  // Determine plugin base name & where to find the dylib/dll/so...
1486  string pluginBaseName, pluginsFolder;
1487  if (getBaseNameFromScheme(pluginBaseName) && getPluginsFolder(pluginsFolder))
1488  {
1489  const string path (pluginsFolder + pluginBaseName);
1490  const string sigPath (path + SIG_EXTENSION), dllPath (path + DLL_EXTENSION);
1491  mDict.insert(kNTV2PluginInfoKey_PluginPath, dllPath);
1492  mDict.insert(kNTV2PluginInfoKey_PluginSigPath, sigPath);
1493  if (showParams())
1494  { cout << "## NOTE: Original params for '" << pluginPath() << "':" << endl;
1495  originalParams.Print(cout, false) << endl;
1496  }
1497  // Validate the plugin...
1498  validate();
1499  if (showParams())
1500  { cout << "## NOTE: Final params for '" << pluginPath() << "':" << endl;
1501  mDict.Print(cout, false) << endl;
1502  }
1503  }
1504 }
1505 
1507 {
1509  P_INFO("Loader destroyed for '" << pluginBaseName() << "', " << DEC(gLoaderConstructCount) << " created, "
1510  << DEC(gLoaderDestructCount) << " destroyed");
1511 }
1512 
1513 string NTV2PluginLoader::mbedErrStr (const int mbedtlsReturnCode)
1514 {
1515  NTV2Buffer errBuff(4096);
1516  string str;
1517  mbedtls_strerror (mbedtlsReturnCode, errBuff, errBuff);
1518  errBuff.GetString (str, /*U8Offset*/0, /*maxSize*/errBuff);
1519  return str;
1520 }
1521 
1522 bool NTV2PluginLoader::ExtractCertInfo (NTV2Dictionary & outInfo, const string & inStr)
1523 {
1524  outInfo.clear();
1525  if (inStr.empty())
1526  return false;
1527  string keyPrefix;
1528  NTV2StringList lines(aja::split(inStr, "\n"));
1529  for (size_t lineNdx(0); lineNdx < lines.size(); lineNdx++)
1530  {
1531  string line (lines.at(lineNdx));
1532  const bool indented (line.empty() ? false : line.at(0) == ' ');
1533  aja::strip(line);
1534  if (line.empty()) // there shouldn't be empty lines...
1535  continue; // ...but skip them anyway if they happen to appear
1536  NTV2StringList keyValPair (aja::split(line, " : "));
1537  if (keyValPair.size() != 2)
1538  {
1539  if (keyValPair.size() == 1)
1540  {
1541  keyPrefix = keyValPair.at(0);
1542  aja::replace(keyPrefix, ":", "");
1543  aja::strip(keyPrefix);
1544  continue; // next line
1545  }
1546  PLGFAIL("cert info line " << DEC(lineNdx+1) << " '" << line << "' has "
1547  << DEC(keyValPair.size()) << " column(s) -- expected 2");
1548  return false;
1549  }
1550  string key(keyValPair.at(0)), val(keyValPair.at(1));
1551  if (key.empty())
1552  {PLGFAIL("cert info line " << DEC(lineNdx+1) << " '" << line << "' empty key for value '" << val << "'"); continue;}
1553  if (indented && !keyPrefix.empty())
1554  {aja::strip(key); key = keyPrefix + ": " + key;}
1555  else
1556  {aja::strip(key); keyPrefix.clear();}
1557  if (outInfo.hasKey(key))
1558  val = outInfo.valueForKey(key) + ", " + val;
1559  outInfo.insert(key, aja::strip(val)); // ignore errors for now
1560  } // for each info line
1561  return true;
1562 } // ExtractCertInfo
1563 
1564 bool NTV2PluginLoader::ExtractIssuerInfo (NTV2Dictionary & outInfo, const string & inStr, const string & inParentKey)
1565 {
1566  outInfo.clear();
1567  if (inStr.empty())
1568  return false;
1569  string str(inStr);
1570  NTV2StringList pairs(aja::split(aja::replace(str, "\\,", ","), ", ")), normalized;
1571  string lastKey;
1572  for (size_t ndx(0); ndx < pairs.size(); ndx++)
1573  {
1574  string assignment (pairs.at(ndx));
1575  if (assignment.find('=') == string::npos)
1576  {
1577  if (!lastKey.empty())
1578  outInfo.insert (lastKey, outInfo.valueForKey(lastKey) + ", " + assignment);
1579  }
1580  else
1581  {
1582  NTV2StringList pieces (aja::split(assignment, "="));
1583  if (pieces.size() != 2)
1584  {PLGFAIL("'" << inParentKey << "' assignment '" << assignment << "' has " << pieces.size() << " component(s) -- expected 2"); continue;}
1585  lastKey = pieces.at(0);
1586  string val(pieces.at(1));
1587  outInfo.insert (aja::strip(lastKey), val);
1588  }
1589  } // for each key/val assignment
1590  return true;
1591 } // ExtractIssuerInfo
1592 
1594 {
1595  if (!inParams.hasKey(kConnectParamQuery))
1596  return false;
1597  string queryStr(inParams.valueForKey(kConnectParamQuery));
1598  if (!queryStr.empty())
1599  if (queryStr[0] == '?')
1600  queryStr.erase(0,1); // Remove leading '?'
1601  PLGDBG("Query: '" << queryStr << "'");
1602  const NTV2StringList strs(aja::split(queryStr, "&"));
1603  for (NTV2StringListConstIter it(strs.begin()); it != strs.end(); ++it)
1604  {
1605  string str(*it), key, value;
1606  if (str.find("=") == string::npos)
1607  { // No assignment (i.e. no '=') --- just insert key with empty value...
1608  key = aja::lower(str);
1609  outQueryParams.insert(key, value);
1610  PLGDBG("'" << key << "' = ''");
1611  continue;
1612  }
1613  NTV2StringList pieces(aja::split(str,"="));
1614  if (pieces.empty())
1615  continue;
1616  key = aja::lower(pieces.at(0));
1617  if (pieces.size() > 1)
1618  value = pieces.at(1);
1619  if (key.empty())
1620  {PLGWARN("Empty key '" << key << "'"); continue;}
1621  if (outQueryParams.hasKey(key))
1622  PLGDBG("Param '" << key << "' value '" << outQueryParams.valueForKey(key) << "' to be replaced with '" << value << "'");
1623  outQueryParams.insert(key, ::PercentDecode(value));
1624  PLGDBG("'" << key << "' = '" << outQueryParams.valueForKey(key) << "'");
1625  } // for each &param
1626  return true;
1627 } // ParseQueryParams
1628 
1629 void * NTV2PluginLoader::getSymbolAddress (const string & inSymbolName, string & outErrorMsg)
1630 {
1631  outErrorMsg.clear();
1632  if (!mpPlugin)
1633  return AJA_NULL;
1634  return mpPlugin->addressForSymbol(inSymbolName, outErrorMsg);
1635 } // getSymbolAddress
1636 
1637 void * NTV2PluginLoader::refCon (void) const
1638 {
1640 }
1641 
1642 bool NTV2PluginLoader::getPluginsFolder (string & outPath) const
1643 {
1644  if (!pluginsPath().empty())
1645  {outPath = pluginsPath(); return true;} // already known, assumed to be good
1646 
1647  // Plugins are expected to be in the "aja" folder (the parent folder of the "aja/firmware" folder)...
1648  outPath = ::NTV2GetPluginsFolderPath(true/*include trailing slash*/);
1649  if (outPath.empty())
1650  return false;
1651  PLGDBG("AJA plugin path is '" << outPath << "'");
1652  mDict.insert(kNTV2PluginInfoKey_PluginsPath, outPath); // Store it in 'PluginsPath'
1653  return !outPath.empty(); // Success if not empty
1654 }
1655 
1656 bool NTV2PluginLoader::getBaseNameFromScheme (string & outName) const
1657 {
1658  if (!pluginBaseName().empty())
1659  {outName = pluginBaseName(); return true;} // already known, assumed to be good
1660 
1661  // URL scheme determines plugin base name...
1662  if (!mDict.hasKey(kConnectParamScheme))
1663  {P_FAIL("Missing scheme -- params: " << mDict); return false;} // No scheme
1664  string scheme(mDict.valueForKey(kConnectParamScheme));
1665  outName = scheme;
1666  mDict.insert(kNTV2PluginInfoKey_PluginBaseName, outName);
1667  return !outName.empty(); // Success if not empty
1668 }
1669 
1671 {
1672  if (mDict.hasKey(kNTV2PluginInfoKey_Errors))
1673  { const string v(mDict.valueForKey(kNTV2PluginInfoKey_Errors) + "\n" + errMsg);
1674  mDict.erase(kNTV2PluginInfoKey_Errors);
1676  }
1677  else
1678  mDict.insert(kNTV2PluginInfoKey_Errors, errMsg);
1679  return false;
1680 }
1681 
1683 {
1684  // Load contents of plugin & sig files into sigContent & dllContent buffers...
1685  NTV2Buffer sigContent, dllContent;
1686  {
1687  // no more than 500MB
1688  const size_t maxBufSize = 512*1024*1024;
1689 
1690  ifstream dllF;
1691  dllF.open(pluginPath(), std::ios::in | std::ios::binary);
1692  if (dllF.fail())
1693  {P_FAIL("Could not open plugin file '" << pluginPath() << "'"); return fail();}
1694  if (!dllF.seekg(0, ios_base::end))
1695  {P_FAIL("Could not seek to end of plugin file '" << pluginPath() << "'"); return fail();}
1696  ifstream::pos_type curOffset(dllF.tellg());
1697  if (int(curOffset) == -1)
1698  {P_FAIL("Could not determine size of plugin file '" << pluginPath() << "'"); return fail();}
1699  size_t size = size_t(curOffset);
1700  if (size == 0)
1701  {P_FAIL("Plugin file '" << pluginPath() << "' is empty"); return fail();}
1702  if (size > maxBufSize)
1703  {P_FAIL("EOF not reached in plugin file '" << pluginPath() << "' -- over 500MB in size?"); return fail();}
1704  size += 1;
1705 
1706  NTV2Buffer tmp(size);
1707  if (!dllF.seekg(0, ios_base::beg))
1708  {P_FAIL("Could not seek back to start of plugin file '" << pluginPath() << "'");return fail();}
1709  if (!dllF.read(tmp, tmp.GetByteCount()).eof())
1710  {P_FAIL("EOF not reached in plugin file '" << pluginPath() << "' -- over 500MB in size?"); return fail();}
1711  tmp.Truncate(size_t(dllF.gcount()));
1712  dllContent = tmp;
1713 
1714  tmp.Allocate(size);
1715  ifstream sigF(pluginSigPath().c_str(), std::ios::in | std::ios::binary);
1716  if (!sigF.good())
1717  {P_FAIL("Signature file '" << pluginSigPath() << "' missing"); return fail();}
1718  if (!sigF.read(tmp, tmp.GetByteCount()).eof())
1719  {P_FAIL("EOF not reached in signature file '" << pluginSigPath() << "' -- over 500MB in size?"); return fail();}
1720  tmp.Truncate(size_t(sigF.gcount()));
1721  sigContent = tmp;
1722  }
1723 
1724  // Decode sigContent...
1725  NTV2Dictionary dict;
1726  { const string dictStr (reinterpret_cast<const char*>(sigContent.GetHostPointer()), size_t(sigContent.GetByteCount()));
1727  if (!dict.deserialize(dictStr))
1728  {P_FAIL("Unable to decode signature file '" << pluginSigPath() << "'"); return fail();}
1729  }
1730  P_DBG(DEC(dict.keys().size()) << " keys found in signature file '" << pluginSigPath() << "': " << dict.keys());
1731  NTV2Buffer checksumFromSigFile, x509CertFromSigFile, signature;
1732  if (!dict.hasKey(kNTV2PluginSigFileKey_X509Certificate))
1733  {P_FAIL("Signature file '" << pluginSigPath() << "' missing '" << kNTV2PluginSigFileKey_X509Certificate << "' key"); return fail();}
1734  if (!dict.hasKey(kNTV2PluginSigFileKey_Signature))
1735  {P_FAIL("Signature file '" << pluginSigPath() << "' missing '" << kNTV2PluginSigFileKey_Signature << "' key"); return fail();}
1736  if (!x509CertFromSigFile.SetFromHexString(dict.valueForKey(kNTV2PluginSigFileKey_X509Certificate)))
1737  {P_FAIL("'SetFromHexString' failed to decode X509 certificate extracted from '" << pluginSigPath() << "' key '" << kNTV2PluginSigFileKey_X509Certificate << "'"); return fail();}
1739  {P_FAIL("'SetFromHexString' failed to decode signature extracted from '" << pluginSigPath() << "' key '" << kNTV2PluginSigFileKey_Signature << "'"); return fail();}
1740 
1741  // Grab the signing certificate found in the .sig file...
1742  mbedtls_x509_crt crt; // Container for X509 certificate
1743  mbedtls_x509_crt_init(&crt); // Initialize it as empty
1744  int ret = mbedtls_x509_crt_parse(&crt, x509CertFromSigFile, x509CertFromSigFile);
1745  if (ret)
1746  { P_FAIL("'mbedtls_x509_crt_parse' returned " << ret << " (" << mbedErrStr(ret) << ") for X509 cert found in '" << pluginSigPath() << "'");
1747  mbedtls_x509_crt_free(&crt);
1748  return fail();
1749  }
1750 
1751  // Extract certificate info...
1752  NTV2Dictionary certInfo, issuerInfo, subjectInfo;
1753  {
1754  NTV2Buffer msgBuff(4096);
1755  int msgLength (mbedtls_x509_crt_info (msgBuff, msgBuff, /*prefixString*/"", &crt));
1756  string msg (msgBuff, size_t(msgLength));
1757  if (msg.empty())
1758  { P_FAIL("'mbedtls_x509_crt_info' returned no info for X509 cert found in '" << pluginSigPath() << "'");
1759  return fail();
1760  }
1761  if (showCertificate())
1762  cout << "## DEBUG: Raw X509 certificate info extracted from signature file '" << pluginSigPath() << "':" << endl
1763  << " " << msg << endl;
1764  if (!ExtractCertInfo (certInfo, msg))
1765  return false;
1766  if (isVerbose())
1767  { cout << "## NOTE: X509 certificate info extracted from signature file '" << pluginSigPath() << "':" << endl;
1768  certInfo.Print(cout, false) << endl;
1769  }
1770  if (certInfo.hasKey("issuer name"))
1771  if (!ExtractIssuerInfo (issuerInfo, certInfo.valueForKey("issuer name"), "issuer name"))
1772  return false;
1773  if (certInfo.hasKey("subject name"))
1774  if (!ExtractIssuerInfo (subjectInfo, certInfo.valueForKey("subject name"), "subject name"))
1775  return false;
1776  if (!certInfo.hasKey(kNTV2PluginInfoKey_Fingerprint))
1777  { P_FAIL("Missing key '" << kNTV2PluginInfoKey_Fingerprint << "' in X509 certificate from '" << pluginSigPath() << "'");
1778  return fail();
1779  }
1780  if (isVerbose() && !issuerInfo.empty())
1781  { cout << "## NOTE: 'issuer name' info:" << endl;
1782  issuerInfo.Print(cout, false) << endl;
1783  }
1784  if (isVerbose() && !subjectInfo.empty())
1785  { cout << "## NOTE: 'subject name' info:" << endl;
1786  subjectInfo.Print(cout, false) << endl;
1787  }
1788  if (!issuerInfo.hasKey(kNTV2PluginX500AttrKey_CommonName))
1789  { P_FAIL("Missing 'Issuer' key '" << kNTV2PluginX500AttrKey_CommonName << "' in X509 certificate from '" << pluginSigPath() << "'");
1790  return fail();
1791  }
1792  if (!issuerInfo.hasKey(kNTV2PluginX500AttrKey_OrganizationName))
1793  { P_FAIL("Missing 'Issuer' key '" << kNTV2PluginX500AttrKey_OrganizationName << "' in X509 certificate from '" << pluginSigPath() << "'");
1794  return fail();
1795  }
1796  if (!subjectInfo.hasKey(kNTV2PluginX500AttrKey_OrganizationalUnitName))
1797  { P_FAIL("Missing 'Subject' key '" << kNTV2PluginX500AttrKey_OrganizationalUnitName << "' in X509 certificate from '" << pluginSigPath() << "'");
1798  return fail();
1799  }
1800  mDict.addFrom(certInfo); // Store certInfo key/value pairs into client/server instance's params...
1801  }
1802 
1803  // Compute SHA256 hash of plugin...
1804  NTV2Buffer checksumFromDLL(32);
1805  ret = mbedtls_md_file (mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), pluginPath().c_str(), checksumFromDLL);
1806  if (ret)
1807  { P_FAIL("'mbedtls_md_file' returned " << ret << " (" << mbedErrStr(ret) << ") for '" << pluginPath() << "'");
1808  return fail();
1809  }
1810  if (isVerbose()) {string str; if (checksumFromDLL.toHexString(str)) cout << "## DEBUG: Digest: " << str << endl;}
1811 
1812  // Verify the dylib/DLL/so signature...
1813  ret = mbedtls_pk_verify (&crt.pk, MBEDTLS_MD_SHA256,
1814  /*msgHash*/checksumFromDLL, /*msgHashLength*/0,//checksumFromDLL,
1815  /*signatureToVerify*/signature, /*signatureLength*/signature);
1816  if (ret)
1817  { P_FAIL("'mbedtls_pk_verify' returned " << ret << " (" << mbedErrStr(ret) << ") for '" << pluginSigPath() << "'");
1818  return fail();
1819  }
1820  mbedtls_x509_crt_free(&crt); // Done using the mbedtls_x509_crt struct
1821  P_DBG("'mbedtls_pk_verify' succeeded for '" << pluginPath() << "' -- signature valid");
1822 
1823  // Load/open the shared library...
1824  if (!mpPlugin)
1825  if (!PluginRegistry::Get().loadPlugin (pluginPath(), pluginsPath(), mpPlugin, errMsg, useStdout()))
1826  return fail();
1827  PLGDBG("'" << pluginPath() << "' opened");
1828 
1829  // Obtain AJA Registration Info...
1830  NTV2Dictionary regInfo;
1831  string errGetInfo;
1832  void * pGetInfo = getSymbolAddress(kFuncNameGetRegInfo, errGetInfo);
1833  if (!pGetInfo)
1834  { P_FAIL("'" << pluginPath() << "': '" kFuncNameGetRegInfo "' failed: " << errGetInfo);
1835  return fail();
1836  }
1837  fpGetRegistrationInfo pGetRegInfo = reinterpret_cast<fpGetRegistrationInfo>(pGetInfo);
1838  if (!(*pGetRegInfo)(uint32_t(AJA_NTV2_SDK_VERSION), regInfo))
1839  {P_FAIL("'" << pluginPath() << "': '" << kFuncNameGetRegInfo << "' failed"); return fail();}
1840  PLGDBG("'" << pluginPath() << "': '" << kFuncNameGetRegInfo << "': returned " << regInfo.keys());
1841  if (regInfo.empty())
1842  {P_FAIL("'" << pluginPath() << "': no registration info (empty)"); return fail();}
1843 
1844  // Check for required registration info keys...
1845  NTV2StringList missingRegInfoKeys;
1850  for (size_t ndx(0); ndx < reqKeys.size(); ndx++)
1851  if (!regInfo.hasKey(reqKeys.at(ndx)))
1852  missingRegInfoKeys.push_back(reqKeys.at(ndx));
1853  if (!missingRegInfoKeys.empty())
1854  { P_FAIL("'" << pluginPath() << "': missing key(s) in registration info: '"
1855  << aja::join(missingRegInfoKeys, "','") << "'");
1856  return fail(); // fail
1857  }
1858  mDict.addFrom(regInfo); // Add registration info to plugin's dictionary
1859 
1860  // Check planet alignment...
1861  const string cnReg(regInfo.valueForKey(kNTV2PluginRegInfoKey_CommonName)),
1862  cnCert(issuerInfo.valueForKey(kNTV2PluginX500AttrKey_CommonName));
1863  const string onReg(regInfo.valueForKey(kNTV2PluginRegInfoKey_Vendor)),
1865  const string ouReg(regInfo.valueForKey(kNTV2PluginRegInfoKey_OrgUnit)),
1867  const string myVers(NTV2RPCBase::ShortSDKVersion()),
1869  const string ajaFingerprint(NTV2RPCBase::AJAFingerprint (/*lowerCase*/true, /*stripColons*/false));
1870  string fingerprint(mDict.valueForKey(kNTV2PluginInfoKey_Fingerprint));
1871  aja::lower(fingerprint); // since ajaFingerprint is lower case
1872  if (onReg != onCert)
1873  { P_FAIL("Vendor name (key='" << kNTV2PluginRegInfoKey_Vendor << "') \"" << onReg << "\" from plugin \""
1874  << pluginPath() << "\" doesn't match organization name (key='" << kNTV2PluginX500AttrKey_OrganizationName
1875  << "') \"" << onCert << "\" from X509 certificate 'Issuer' in '" << pluginSigPath() << "'");
1876  return fail();
1877  }
1878  if (cnReg != cnCert)
1879  { P_FAIL("Common name (key='" << kNTV2PluginRegInfoKey_CommonName << "') \"" << cnReg << "\" from plugin \""
1880  << pluginPath() << "\" doesn't match common name (key='" << kNTV2PluginX500AttrKey_CommonName
1881  << "') \"" << cnCert << "\" from X509 certificate 'Issuer' in '" << pluginSigPath() << "'");
1882  return fail();
1883  }
1884  if (ouReg != ouCert)
1885  { P_FAIL("Org unit (key='" << kNTV2PluginX500AttrKey_OrganizationalUnitName << "') \"" << ouReg << "\" from plugin \""
1886  << pluginPath() << "\" doesn't match org unit (key='" << kNTV2PluginX500AttrKey_OrganizationalUnitName
1887  << "') \"" << ouCert << "\" from X509 certificate 'Subject' in '" << pluginSigPath() << "'");
1888  return fail();
1889  }
1890  if (myVers != plVers)
1891  { P_FAIL("SDK version '" << plVers << "' from plugin \"" << pluginPath()
1892  << "\" doesn't match client SDK version '" << myVers << "'");
1893  return fail();
1894  }
1895  if (fingerprint != ajaFingerprint)
1896  { P_FAIL("'" << pluginPath() << "':|Plugin not authorized/signed by AJA:|"
1897  << "Issuer serial: " << fingerprint << "|AJA serial: " << ajaFingerprint);
1898  return fail(); // fail
1899  }
1900 
1901  // Green light
1902  mValidated = true;
1903  return true;
1904 } // validate
1905 
1906 // Returns address of function having given name
1907 void * NTV2PluginLoader::getFunctionAddress (const string & inFuncName)
1908 {
1909  // Load/open the shared library...
1910  if (!isOpen())
1911  {P_FAIL("'" << inFuncName << "': '" << pluginPath() << "' not loaded"); return AJA_NULL;}
1912  if (!isValidated())
1913  {P_FAIL("'" << inFuncName << "': '" << pluginPath() << "' not validated"); return AJA_NULL;}
1914 
1915  // Finally, the last step ---- get address of requested function...
1916  string errStr;
1917  void * pResult = getSymbolAddress(inFuncName, errStr);
1918  if (!pResult)
1919  {P_FAIL("'" << inFuncName << "': '" << pluginPath() << "': " << errStr); return AJA_NULL;}
1920  P_DBG("Calling '" << inFuncName << "' in '" << pluginPath() << "'");
1921  return pResult;
1922 } // getFunctionAddress
1923 
1925 {
1926  return mpPlugin && mValidated;
1927 }
1928 
1930 {
1931  const NTV2StringList paths (PluginRegistry::Get().loadedPlugins());
1932  if (paths.empty())
1933  cout << "0 plugins" << endl;
1934  else if (paths.size() == 1)
1935  cout << "1 plugin: " << paths.at(0) << endl;
1936  else cout << DEC(paths.size()) << " plugins:" << endl << aja::join(paths, "\n") << endl;
1937 }
1938 #endif // !defined(NTV2_PREVENT_PLUGIN_LOAD)
1939 
1940 
1941 /*****************************************************************************************************************************************************
1942  NTV2RPCBase
1943 *****************************************************************************************************************************************************/
1944 
1946  : mParams(params),
1947  mpRefCon(pRefCon)
1948 {
1949  NTV2Dictionary queryParams;
1951  if (mpRefCon)
1953  PDBGX("refCnt=" << DEC(mpRefCon ? *mpRefCon : 0) << ", " << DEC(gBaseConstructCount) << " created, "
1954  << DEC(gBaseDestructCount) << " destroyed");
1956  {cout << __FILE__ << "(" << __LINE__ << "):" << AJAFUNC << ":" << endl; mParams.Print(cout, false) << endl;}
1957 }
1958 
1960 {
1962  if (mpRefCon)
1964  PDBGX("refCnt=" << DEC(mpRefCon ? *mpRefCon : 0) << ", " << DEC(gBaseConstructCount) << " created, "
1965  << DEC(gBaseDestructCount) << " destroyed");
1966 }
1967 
1968 bool NTV2RPCBase::SetParams (const NTV2ConnectParams & inNewParams, const bool inAugment)
1969 {
1970  AJAAutoLock tmp(&mParamLock);
1971  size_t oldCount(mParams.size()), updated(0), added(0);
1972  if (inAugment)
1973  {
1974  updated = mParams.updateFrom(inNewParams);
1975  added = mParams.addFrom(inNewParams);
1976  NBSDBG(DEC(updated) << " param(s) updated, " << DEC(added) << " added: " << mParams);
1977  }
1978  else
1979  {
1980  mParams = inNewParams;
1981  NBSDBG(DEC(oldCount) << " param(s) removed, replaced with " << inNewParams);
1982  }
1983  if (mParams.empty())
1984  NBSWARN("No params");
1985  return true;
1986 }
1987 
1989 {
1990  string result(::NTV2Version());
1991  const NTV2StringList halves(aja::split(result, " "));
1992  if (halves.empty())
1993  return result;
1994  NTV2StringList nums(aja::split(halves.front(), "."));
1995  while (nums.size() > 3)
1996  nums.pop_back();
1997  return aja::join(nums, ".");
1998 }
1999 
2000 
2001 string NTV2RPCBase::AJAFingerprint (const bool inLowerCase, const bool inStripColons)
2002 {
2003  static const string sAJAFingerprint ("70:1A:37:93:FA:4F:34:30:58:55:51:0C:01:4E:45:7C:BE:5B:41:65");
2004  string result(sAJAFingerprint);
2005  if (inStripColons)
2006  aja::replace(result, ":", "");
2007  if (inLowerCase)
2008  aja::lower(result);
2009  return result;
2010 }
2011 
2012 
2013 /*****************************************************************************************************************************************************
2014  NTV2RPCClientAPI
2015 *****************************************************************************************************************************************************/
2016 
2018  : NTV2RPCBase(inParams, reinterpret_cast<ULWord*>(pRefCon))
2019 {
2020  AJADebug::Open();
2022  PDBGX(DEC(gClientConstructCount) << " created, " << DEC(gClientDestructCount) << " destroyed");
2023 }
2024 
2026 {
2027  if (IsConnected())
2028  NTV2Disconnect();
2030  PDBGX(DEC(gClientConstructCount) << " created, " << DEC(gClientDestructCount) << " destroyed");
2031 }
2032 
2034 {
2035  AJAAutoLock tmp(&mParamLock);
2036  return mParams;
2037 }
2038 
2039 bool NTV2RPCClientAPI::HasConnectParam (const string & inParam) const
2040 {
2041  AJAAutoLock tmp(&mParamLock);
2042  return mParams.hasKey(inParam);
2043 }
2044 
2045 string NTV2RPCClientAPI::ConnectParam (const string & inParam) const
2046 {
2047  AJAAutoLock tmp(&mParamLock);
2048  return mParams.valueForKey(inParam);
2049 }
2050 
2052 {
2054 }
2055 
2056 ostream & NTV2RPCClientAPI::Print (ostream & oss) const
2057 {
2058  oss << (IsConnected() ? "Connected" : "Disconnected");
2059  if (IsConnected() && !Name().empty())
2060  oss << " to '" << Name() << "'";
2061  return oss;
2062 }
2063 
2065 {
2066  NTV2StringList strs;
2067  string fName(ConnectParam(kQParamVDevFileName)), hostName;
2068  if (!fName.empty())
2069  strs.push_back(string("from '") + fName + "'");
2071  sysInfo.GetValue(AJA_SystemInfoTag_System_Name, hostName);
2072  if (!hostName.empty())
2073  {strs.push_back("on"); strs.push_back(string("'") + hostName + "'");}
2074  return aja::join(strs, " ");
2075 }
2076 
2078 {
2079  if (IsConnected())
2080  NTV2Disconnect();
2081  return NTV2OpenRemote();
2082 }
2083 
2085 {
2086  return NTV2CloseRemote();
2087 }
2088 
2089 bool NTV2RPCClientAPI::NTV2ReadRegisterRemote (const ULWord regNum, ULWord & outRegValue, const ULWord regMask, const ULWord regShift)
2090 { (void) regNum; (void) outRegValue; (void) regMask; (void) regShift;
2091  return false; // UNIMPLEMENTED
2092 }
2093 
2094 bool NTV2RPCClientAPI::NTV2WriteRegisterRemote (const ULWord regNum, const ULWord regValue, const ULWord regMask, const ULWord regShift)
2095 { (void) regNum; (void) regValue; (void) regMask; (void) regShift;
2096  return false; // UNIMPLEMENTED
2097 }
2098 
2100 { (void) autoCircData;
2101  return false; // UNIMPLEMENTED
2102 }
2103 
2105 { (void) eInterrupt; (void) timeOutMs;
2106  return false; // UNIMPLEMENTED
2107 }
2108 
2109 #if !defined(NTV2_DEPRECATE_16_3)
2111  { (void) bitFileType;
2112  ::memset(&bitFileInfo, 0, sizeof(bitFileInfo));
2113  return false; // UNIMPLEMENTED
2114  }
2115 
2117  {
2118  ::memset(&buildInfo, 0, sizeof(buildInfo));
2119  return false; // UNIMPLEMENTED
2120  }
2121 
2123  const UWord signalMask, const bool testPatDMAEnb, const ULWord testPatNum)
2124  { (void) channel; (void) testPatternFBF; (void) signalMask; (void) testPatDMAEnb; (void) testPatNum;
2125  return false; // UNIMPLEMENTED
2126  }
2127 
2128  bool NTV2RPCClientAPI::NTV2ReadRegisterMultiRemote (const ULWord numRegs, ULWord & outFailedRegNum, NTV2RegInfo outRegs[])
2129  { (void) numRegs; (void) outFailedRegNum; (void) outRegs;
2130  return false; // UNIMPLEMENTED
2131  }
2132 
2134  {
2135  outDriverVersion = 0xFFFFFFFF;
2136  return false; // UNIMPLEMENTED
2137  }
2138 #endif // !defined(NTV2_DEPRECATE_16_3)
2139 
2140 bool NTV2RPCClientAPI::NTV2DMATransferRemote ( const NTV2DMAEngine inDMAEngine, const bool inIsRead, const ULWord inFrameNumber,
2141  NTV2Buffer & inOutFrameBuffer, const ULWord inCardOffsetBytes,
2142  const ULWord inNumSegments, const ULWord inSegmentHostPitch,
2143  const ULWord inSegmentCardPitch, const bool inSynchronous)
2144 { (void) inDMAEngine; (void) inIsRead; (void) inFrameNumber; (void) inOutFrameBuffer;
2145  (void) inCardOffsetBytes; (void) inNumSegments; (void) inSegmentHostPitch;
2146  (void) inSegmentCardPitch; (void) inSynchronous;
2147  return false; // UNIMPLEMENTED
2148 }
2149 
2151 { (void) pInMessage;
2152  return false; // UNIMPLEMENTED
2153 }
2154 
2155 bool NTV2RPCClientAPI::NTV2GetBoolParamRemote (const ULWord inParamID, ULWord & outValue)
2156 { (void) inParamID;
2157  outValue = 0;
2158  return false; // UNIMPLEMENTED
2159 }
2160 
2162 { (void) inParamID;
2163  outValue = 0;
2164  return false; // UNIMPLEMENTED
2165 }
2166 
2167 bool NTV2RPCClientAPI::NTV2GetSupportedRemote (const ULWord inEnumsID, ULWordSet & outSupported)
2168 { (void) inEnumsID;
2169  outSupported.clear();
2170  return false; // UNIMPLEMENTED
2171 }
2172 
2174 {
2175  return false; // UNIMPLEMENTED
2176 }
2177 
2179 {
2180 // AJAAutoLock tmp(&mParamLock);
2181 // mParams.clear();
2182  return true;
2183 }
2184 
2186 {
2187 #if defined(NTV2_PREVENT_PLUGIN_LOAD)
2188  return AJA_NULL;
2189 #else
2190  NTV2RPCClientAPI * pRPCObject(AJA_NULL);
2191  {
2192  NTV2PluginLoader loader(params);
2193  fpCreateClient pFunc (reinterpret_cast<fpCreateClient>(loader.getFunctionAddress(kFuncNameCreateClient)));
2194  if (!pFunc)
2195  return AJA_NULL;
2196 
2197  // Call plugin's Create function to instantiate the NTV2RPCClientAPI object...
2198  pRPCObject = (*pFunc) (loader.refCon(), params, AJA_NTV2_SDK_VERSION);
2199  if (!pRPCObject)
2200  NBCFAIL("'" << kFuncNameCreateClient << "' returned NULL client instance from: " << params);
2201  else
2202  NBCINFO("'" << kFuncNameCreateClient << "' created client instance " << xHEX0N(uint64_t(pRPCObject),16));
2203  } // loader freed here
2204  return pRPCObject;
2205 #endif
2206 } // CreateClient
2207 
2208 
2209 /*****************************************************************************************************************************************************
2210  NTV2RPCServerAPI
2211 *****************************************************************************************************************************************************/
2212 
2214 {
2215 #if defined(NTV2_PREVENT_PLUGIN_LOAD)
2216  return AJA_NULL;
2217 #else
2218  NTV2RPCServerAPI * pRPCObject(AJA_NULL);
2219  {
2220  NTV2PluginLoader loader(params);
2221  fpCreateServer pFunc = reinterpret_cast<fpCreateServer>(loader.getFunctionAddress(kFuncNameCreateServer));
2222  if (!pFunc)
2223  return AJA_NULL;
2224 
2225  // Call plugin's Create function to instantiate the NTV2RPCServerAPI object...
2226  pRPCObject = (*pFunc) (loader.refCon(), params, AJA_NTV2_SDK_VERSION);
2227  if (!pRPCObject)
2228  NBSFAIL("'" << kFuncNameCreateServer << "' returned NULL server instance from: " << params);
2229  else
2230  NBSINFO("'" << kFuncNameCreateServer << "' created server instance " << xHEX0N(uint64_t(pRPCObject),16));
2231  }
2232  return pRPCObject; // It's caller's responsibility to delete pRPCObject
2233 #endif
2234 } // CreateServer
2235 
2236 NTV2RPCServerAPI * NTV2RPCServerAPI::CreateServer (const string & inURL) // CLASS METHOD
2237 {
2238  NTV2DeviceSpecParser parser(inURL);
2239  if (parser.HasErrors())
2240  {
2241  NBSFAIL(parser.Error() << " in URL:\n" << inURL);
2242  parser.PrintErrors(cerr);
2243  return AJA_NULL;
2244  }
2245  NTV2ConfigParams parms(parser.Results());
2246  return CreateServer(parms);
2247 }
2248 
2250  : NTV2RPCBase(inParams, reinterpret_cast<ULWord*>(pRefCon))
2251 {
2252  NTV2Buffer spare(&mSpare, sizeof(mSpare)); spare.Fill(0ULL);
2253  AJADebug::Open();
2255  PDBGX(DEC(gServerConstructCount) << " created, " << DEC(gServerDestructCount) << " destroyed");
2256 }
2257 
2259 {
2260  Stop();
2261  while (IsRunning())
2262  AJATime::Sleep(50);
2264  PDBGX(DEC(gServerConstructCount) << " created, " << DEC(gServerDestructCount) << " destroyed");
2265 }
2266 
2268 { // This function normally should never be called;
2269  // It's usually overridden by a subclass
2270  NBSDBG("Started");
2271  while (!mTerminate)
2272  AJATime::Sleep(500);
2273  NBSDBG("Terminated");
2274 } // ServerFunction
2275 
2276 ostream & NTV2RPCServerAPI::Print (ostream & oss) const
2277 {
2278  oss << mParams;
2279  return oss;
2280 }
2281 
2283 {
2284  AJAAutoLock tmp(&mParamLock);
2285  return mParams;
2286 }
2287 
2288 bool NTV2RPCServerAPI::HasConfigParam (const string & inParam) const
2289 {
2290  AJAAutoLock tmp(&mParamLock);
2291  return mParams.hasKey(inParam);
2292 }
2293 
2294 string NTV2RPCServerAPI::ConfigParam (const string & inParam) const
2295 {
2296  AJAAutoLock tmp(&mParamLock);
2297  return mParams.valueForKey(inParam);
2298 }
NTV2RPCClientAPI::NTV2WriteRegisterRemote
virtual bool NTV2WriteRegisterRemote(const ULWord regNum, const ULWord regValue, const ULWord regMask, const ULWord regShift)
Definition: ntv2nubaccess.cpp:2094
NTV2RPCClientAPI::NTV2GetNumericParamRemote
virtual bool NTV2GetNumericParamRemote(const ULWord inParamID, ULWord &outValue)
Definition: ntv2nubaccess.cpp:2161
nlohmann::json_abiNLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON_v3_11_NLOHMANN_JSON_VERSION_PATCH::detail2::end
end_tag end(T &&...)
PluginRegistry
Definition: ntv2nubaccess.cpp:1195
kNTV2PluginRegInfoKey_ShortName
#define kNTV2PluginRegInfoKey_ShortName
Plugin short name.
Definition: ntv2nubaccess.h:68
aja::stoul
unsigned long stoul(const std::string &str, std::size_t *idx, int base)
Definition: common.cpp:143
nlohmann::json_abiNLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON_v3_11_NLOHMANN_JSON_VERSION_PATCH::detail::parse_event_t::value
@ value
the parser finished reading a JSON value
PluginRegistry::Terminate
static void Terminate(void)
Definition: ntv2nubaccess.cpp:1247
NTV2RPCServerAPI::CreateServer
static NTV2RPCServerAPI * CreateServer(NTV2ConfigParams &inParams)
Factory method that instantiates a new NTV2RPCServerAPI instance using a plugin based on the specifie...
Definition: ntv2nubaccess.cpp:2213
P_DBG
#define P_DBG(__x__)
Definition: ntv2nubaccess.cpp:89
NTV2RPCServerAPI::ConfigParam
virtual std::string ConfigParam(const std::string &inParam) const
Definition: ntv2nubaccess.cpp:2294
PluginRegistry::DebuggingEnabled
static bool DebuggingEnabled(void)
Definition: ntv2nubaccess.cpp:1201
kLegalSchemeNTV2Local
#define kLegalSchemeNTV2Local
Definition: ntv2nubaccess.h:49
NTV2DeviceSpecParser::Reset
void Reset(const std::string inSpec="")
Resets me, then parses the given device specification.
Definition: ntv2nubaccess.cpp:280
gBaseDestructCount
uint32_t gBaseDestructCount(0)
DLL_EXTENSION
#define DLL_EXTENSION
Definition: ntv2nubaccess.cpp:30
info.h
Declares the AJASystemInfo class.
NTV2PluginLoader::mbedErrStr
static string mbedErrStr(const int mbedtlsReturnCode)
Definition: ntv2nubaccess.cpp:1513
NTV2RPCClientAPI::NTV2OpenRemote
virtual bool NTV2OpenRemote(void)
Definition: ntv2nubaccess.cpp:2173
INTERRUPT_ENUMS
enum _INTERRUPT_ENUMS_ INTERRUPT_ENUMS
kNTV2PluginRegInfoKey_Vendor
#define kNTV2PluginRegInfoKey_Vendor
Plugin vendor (manufacturer) name.
Definition: ntv2nubaccess.h:65
BUILD_INFO_STRUCT
Definition: ntv2publicinterface.h:5097
AJA_SystemInfoMemoryUnit_Megabytes
@ AJA_SystemInfoMemoryUnit_Megabytes
Definition: info.h:23
PluginRegistry::unloadPlugin
bool unloadPlugin(const string &path, string &errMsg)
Definition: ntv2nubaccess.cpp:1305
kQParamShowX509Cert
#define kQParamShowX509Cert
Query parameter option that dumps X509 certificate info into message log.
Definition: ntv2nubaccess.h:37
NTV2Dictionary::addFrom
size_t addFrom(const NTV2Dictionary &inDict)
Adds all values from inDict with non-matching keys, ignoring all matching keys.
Definition: ntv2nubaccess.cpp:265
kNTV2PluginRegInfoKey_Copyright
#define kNTV2PluginRegInfoKey_Copyright
Plugin copyright notice.
Definition: ntv2nubaccess.h:71
NTV2RPCClientAPI::NTV2Disconnect
virtual bool NTV2Disconnect(void)
Disconnects me from the remote/fake host, closing the connection.
Definition: ntv2nubaccess.cpp:2084
NTV2RPCBase::AJAFingerprint
static std::string AJAFingerprint(const bool inLowerCase=false, const bool inStripColons=false)
Definition: ntv2nubaccess.cpp:2001
NTV2StringSet
std::set< std::string > NTV2StringSet
Definition: ntv2utils.h:1158
NTV2RPCClientAPI::NTV2DriverGetBitFileInformationRemote
virtual bool NTV2DriverGetBitFileInformationRemote(BITFILE_INFO_STRUCT &bitFileInfo, const NTV2BitFileType bitFileType)
Definition: ntv2nubaccess.cpp:2110
aja::strip
std::string & strip(std::string &str, const std::string &ws)
Definition: common.cpp:461
PluginRegistry::countForPath
ULWord countForPath(const string &path)
Definition: ntv2nubaccess.cpp:1386
gPluginConstructCount
uint32_t gPluginConstructCount(0)
kQParamDebugRegistry
#define kQParamDebugRegistry
Query parameter option that enables debugging of PluginRegistry.
Definition: ntv2nubaccess.h:39
NTV2GetSupportedDevices
NTV2DeviceIDSet NTV2GetSupportedDevices(const NTV2DeviceKinds inKinds=NTV2_DEVICEKIND_ALL)
Returns an NTV2DeviceIDSet of devices supported by the SDK.
Definition: ntv2utils.cpp:7716
NTV2Channel
NTV2Channel
These enum values are mostly used to identify a specific widget_framestore. They're also commonly use...
Definition: ntv2enums.h:1353
NTV2Buffer
Describes a user-space buffer on the host computer. I have an address and a length,...
Definition: ntv2publicinterface.h:6216
NTV2Plugin::NTV2Plugin
NTV2Plugin(void *handle, const string &path, const bool useStdout)
Definition: ntv2nubaccess.cpp:1128
AJARefPtr< NTV2Plugin >
aja::join
std::string join(const std::vector< std::string > &parts, const std::string &delim)
Definition: common.cpp:468
aja::split
void split(const std::string &str, const char delim, std::vector< std::string > &elems)
Definition: common.cpp:350
NTV2Buffer::GetByteCount
ULWord GetByteCount(void) const
Definition: ntv2publicinterface.h:6290
NTV2_ASSERT
#define NTV2_ASSERT(_expr_)
Definition: ajatypes.h:529
fpCreateClient
NTV2RPCClientAPI *(* fpCreateClient)(void *, const NTV2ConnectParams &, const uint32_t)
Instantiates a new client instance to talk to a remote server.
Definition: ntv2nubaccess.h:477
INSTP
#define INSTP(_p_)
Definition: ntv2nubaccess.cpp:51
PLGWARN
#define PLGWARN(__x__)
Definition: ntv2nubaccess.cpp:69
AJAThread::Attach
virtual AJAStatus Attach(AJAThreadFunction *pThreadFunction, void *pUserContext)
Definition: thread.cpp:169
NTV2PluginLoader::ExtractIssuerInfo
static bool ExtractIssuerInfo(NTV2Dictionary &outInfo, const string &inStr, const string &inParentKey)
Definition: ntv2nubaccess.cpp:1564
fpCreateServer
NTV2RPCServerAPI *(* fpCreateServer)(void *, const NTV2ConfigParams &, const uint32_t)
Instantiates a new server instance for talking to clients.
Definition: ntv2nubaccess.h:487
kConnectParamDevID
#define kConnectParamDevID
First device having this ID (e.g. '0x10518400')
Definition: ntv2nubaccess.h:30
kNTV2PluginInfoKey_PluginSigPath
#define kNTV2PluginInfoKey_PluginSigPath
Local host full path to plugin signature file.
Definition: ntv2nubaccess.h:59
systemtime.h
Declares the AJATime class.
NTV2RPCServerAPI
Base class of objects that can serve device operation RPCs with NTV2RPCClientAPI instances.
Definition: ntv2nubaccess.h:387
NTV2RPCBase
Common base class for NTV2RPCClientAPI and NTV2RPCServerAPI.
Definition: ntv2nubaccess.h:241
kNTV2PluginX500AttrKey_OrganizationName
#define kNTV2PluginX500AttrKey_OrganizationName
Definition: ntv2nubaccess.h:86
NTV2RPCClientAPI::~NTV2RPCClientAPI
virtual ~NTV2RPCClientAPI()
My destructor, automatically calls NTV2Disconnect.
Definition: ntv2nubaccess.cpp:2025
NTV2RPCClientAPI::NTV2DMATransferRemote
virtual bool NTV2DMATransferRemote(const NTV2DMAEngine inDMAEngine, const bool inIsRead, const ULWord inFrameNumber, NTV2Buffer &inOutBuffer, const ULWord inCardOffsetBytes, const ULWord inNumSegments, const ULWord inSegmentHostPitch, const ULWord inSegmentCardPitch, const bool inSynchronous)
Definition: ntv2nubaccess.cpp:2140
P_FAIL
#define P_FAIL(__x__)
Definition: ntv2nubaccess.cpp:74
NTV2RPCBase::SetParams
bool SetParams(const NTV2ConfigParams &inNewParams, const bool inAugment=false)
Definition: ntv2nubaccess.cpp:1968
NBSINFO
#define NBSINFO(__x__)
Definition: ntv2nubaccess.cpp:65
NTV2PluginLoader::showParams
bool showParams(void) const
Definition: ntv2nubaccess.cpp:1444
NTV2PluginLoader::validate
bool validate(void)
Definition: ntv2nubaccess.cpp:1682
NTV2DeviceID
NTV2DeviceID
Identifies a specific AJA NTV2 device model number. The NTV2DeviceID is actually the PROM part number...
Definition: ntv2enums.h:20
NTV2DeviceSpecParser::DeviceID
NTV2DeviceID DeviceID(void) const
Definition: ntv2nubaccess.cpp:548
NTV2FrameBufferFormat
NTV2FrameBufferFormat
Identifies a particular video frame buffer format. See Device Frame Buffer Formats for details.
Definition: ntv2enums.h:215
NTV2Dictionary::Print
std::ostream & Print(std::ostream &oss, const bool inCompact=true) const
Prints human-readable representation to ostream.
Definition: ntv2nubaccess.cpp:156
P_NOTE
#define P_NOTE(__x__)
Definition: ntv2nubaccess.cpp:85
NTV2DeviceSpecParser::MakeQueryString
std::string MakeQueryString(const bool urlEncode) const
Definition: ntv2nubaccess.cpp:520
NBSFAIL
#define NBSFAIL(__x__)
Definition: ntv2nubaccess.cpp:62
NTV2Buffer::Allocate
bool Allocate(const size_t inByteCount, const bool inPageAligned=false)
Allocates (or re-allocates) my user-space storage using the given byte count. I assume full responsib...
Definition: ntv2publicinterface.cpp:1810
kNTV2PluginInfoKey_Errors
#define kNTV2PluginInfoKey_Errors
Plugin load or validation error(s), if any.
Definition: ntv2nubaccess.h:62
NTV2RPCClientAPI::ConnectHasScheme
virtual bool ConnectHasScheme(void) const
Definition: ntv2nubaccess.cpp:2051
NTV2DeviceIDSetConstIter
NTV2DeviceIDSet::const_iterator NTV2DeviceIDSetConstIter
A convenient const iterator for NTV2DeviceIDSet.
Definition: ntv2utils.h:1046
NTV2Dictionary::insert
bool insert(const std::string &inKey, const std::string &inValue)
Stores the given value using the given key; overwrites existing value if already present.
Definition: ntv2nubaccess.cpp:240
NTV2Buffer::toHexString
bool toHexString(std::string &outStr, const size_t inLineBreakInterval=0) const
Converts my contents into a hex-encoded string.
Definition: ntv2publicinterface.cpp:453
kConnectParamPort
#define kConnectParamPort
Port number (optional)
Definition: ntv2nubaccess.h:26
NTV2RPCServerAPI::NTV2RPCServerAPI
NTV2RPCServerAPI(NTV2ConnectParams inParams, void *pRefCon)
My constructor.
Definition: ntv2nubaccess.cpp:2249
PluginRegistry::~PluginRegistry
~PluginRegistry()
Definition: ntv2nubaccess.cpp:1274
NTV2RPCClientAPI::HasConnectParam
virtual bool HasConnectParam(const std::string &inParam) const
Definition: ntv2nubaccess.cpp:2039
NTV2StringSetConstIter
NTV2StringSet::const_iterator NTV2StringSetConstIter
Definition: ntv2utils.h:1159
PercentEncode
std::string PercentEncode(const std::string &inStr)
nlohmann::json_abiNLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON_v3_11_NLOHMANN_JSON_VERSION_PATCH::detail::void
j template void())
Definition: json.hpp:4893
NTV2PluginLoader::fail
bool fail(void)
Definition: ntv2nubaccess.cpp:1670
NTV2RPCClientAPI::NTV2GetDriverVersionRemote
virtual bool NTV2GetDriverVersionRemote(ULWord &outDriverVersion)
Definition: ntv2nubaccess.cpp:2133
NTV2PluginPtr
AJARefPtr< NTV2Plugin > NTV2PluginPtr
Definition: ntv2nubaccess.cpp:1035
gServerConstructCount
uint32_t gServerConstructCount(0)
NTV2Plugin::addressForSymbol
void * addressForSymbol(const string &inSymbol, string &outErrorMsg)
Definition: ntv2nubaccess.cpp:1157
kFuncNameCreateServer
#define kFuncNameCreateServer
Create an NTV2RPCServerAPI instance.
Definition: ntv2nubaccess.h:53
ajatypes.h
Declares the most fundamental data types used by NTV2. Since Windows NT was the first principal devel...
PLGDBG
#define PLGDBG(__x__)
Definition: ntv2nubaccess.cpp:72
NTV2DeviceSpecParser::Print
std::ostream & Print(std::ostream &oss, const bool inDumpResults=false) const
Definition: ntv2nubaccess.cpp:456
NTV2RPCClientAPI::NTV2CloseRemote
virtual bool NTV2CloseRemote(void)
Definition: ntv2nubaccess.cpp:2178
NTV2DeviceSpecParser::Resource
std::string Resource(const bool inStripLeadSlash=true) const
Definition: ntv2nubaccess.cpp:291
nlohmann::json_abiNLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON_v3_11_NLOHMANN_JSON_VERSION_PATCH::detail::parse_event_t::key
@ key
the parser read a key of a value in an object
PDBGX
#define PDBGX(__x__)
Definition: ntv2nubaccess.cpp:95
NTV2DeviceSpecParser::ParseQueryParams
static bool ParseQueryParams(const NTV2Dictionary &inParams, NTV2Dictionary &outQueryParams)
Definition: ntv2nubaccess.cpp:1593
kConnectParamDevModel
#define kConnectParamDevModel
First device of this model (e.g. 'kona4')
Definition: ntv2nubaccess.h:29
AJAThread
Definition: thread.h:69
AJAThread::Active
virtual bool Active()
Definition: thread.cpp:116
NTV2Dictionary::updateFrom
size_t updateFrom(const NTV2Dictionary &inDict)
Updates all values from inDict with matching keys, ignoring all non-matching keys.
Definition: ntv2nubaccess.cpp:256
NBCFAIL
#define NBCFAIL(__x__)
Definition: ntv2nubaccess.cpp:57
NTV2RPCServerAPI::mSpare
uint32_t mSpare[1024]
Reserved.
Definition: ntv2nubaccess.h:443
NTV2RPCBase::mParams
NTV2Dictionary mParams
Copy of config params passed to my constructor.
Definition: ntv2nubaccess.h:253
NTV2DMAEngine
NTV2DMAEngine
Definition: ntv2enums.h:1852
kNTV2PluginSigFileKey_X509Certificate
#define kNTV2PluginSigFileKey_X509Certificate
X509 certificate (encoded as hex string)
Definition: ntv2nubaccess.h:79
NTV2PluginLoader::pluginPath
string pluginPath(void) const
Definition: ntv2nubaccess.cpp:1439
NTV2RPCClientAPI::ConnectParams
virtual NTV2ConnectParams ConnectParams(void) const
Definition: ntv2nubaccess.cpp:2033
aja::lower
std::string & lower(std::string &str)
Definition: common.cpp:436
kNTV2PluginX500AttrKey_OrganizationalUnitName
#define kNTV2PluginX500AttrKey_OrganizationalUnitName
Definition: ntv2nubaccess.h:87
kQParamLogToStdout
#define kQParamLogToStdout
Query parameter option that logs messages to standard output.
Definition: ntv2nubaccess.h:36
AJATime::Sleep
static void Sleep(const int32_t inMilliseconds)
Suspends execution of the current thread for a given number of milliseconds.
Definition: systemtime.cpp:284
kNTV2PluginRegInfoKey_CommonName
#define kNTV2PluginRegInfoKey_CommonName
Plugin vendor domain name.
Definition: ntv2nubaccess.h:66
ULWordSet
std::set< ULWord > ULWordSet
A collection of unique ULWord (uint32_t) values.
Definition: ntv2publicinterface.h:54
aja::replace
std::string & replace(std::string &str, const std::string &from, const std::string &to)
Definition: common.cpp:110
NTV2PluginLoader
Definition: ntv2nubaccess.cpp:1431
AJASystemInfo::GetValue
virtual AJAStatus GetValue(const AJASystemInfoTag inTag, std::string &outValue) const
Answers with the host system info value string for the given AJASystemInfoTag.
Definition: info.cpp:153
NTV2PluginLoader::~NTV2PluginLoader
~NTV2PluginLoader()
Definition: ntv2nubaccess.cpp:1506
ULWord
uint32_t ULWord
Definition: ajatypes.h:276
NTV2BitFileType
NTV2BitFileType
Definition: ntv2enums.h:3337
NTV2RPCClientAPI::NTV2GetBoolParamRemote
virtual bool NTV2GetBoolParamRemote(const ULWord inParamID, ULWord &outValue)
Definition: ntv2nubaccess.cpp:2155
NTV2RPCClientAPI::ConnectParam
virtual std::string ConnectParam(const std::string &inParam) const
Definition: ntv2nubaccess.cpp:2045
AJA_SystemInfoTag_System_Name
@ AJA_SystemInfoTag_System_Name
Definition: info.h:33
kNTV2PluginInfoKey_Fingerprint
#define kNTV2PluginInfoKey_Fingerprint
Issuer cert fingerprint.
Definition: ntv2nubaccess.h:61
NTV2PluginLoader::NTV2PluginLoader
NTV2PluginLoader(NTV2Dictionary &params)
Definition: ntv2nubaccess.cpp:1471
kConnectParamHost
#define kConnectParamHost
DNS name, IPv4 or sw device DLL name.
Definition: ntv2nubaccess.h:25
NTV2RPCServerAPI::ConfigParams
virtual NTV2ConfigParams ConfigParams(void) const
Definition: ntv2nubaccess.cpp:2282
NTV2RPCServerAPI::Print
virtual std::ostream & Print(std::ostream &oss) const
Definition: ntv2nubaccess.cpp:2276
NTV2RPCServerAPI::HasConfigParam
virtual bool HasConfigParam(const std::string &inParam) const
Definition: ntv2nubaccess.cpp:2288
NTV2DeviceSpecParser::MakeDeviceSpec
std::string MakeDeviceSpec(const bool urlEncodeQuery) const
Definition: ntv2nubaccess.cpp:485
PluginRegistry::Get
static PluginRegistry & Get(void)
Definition: ntv2nubaccess.cpp:1239
NTV2RPCBase::ShortSDKVersion
static std::string ShortSDKVersion(void)
Definition: ntv2nubaccess.cpp:1988
gBaseConstructCount
uint32_t gBaseConstructCount(0)
NTV2DeviceIDToString
std::string NTV2DeviceIDToString(const NTV2DeviceID inValue, const bool inForRetailDisplay=false)
Definition: ntv2utils.cpp:4608
NTV2RPCClientAPI::NTV2DriverGetBuildInformationRemote
virtual bool NTV2DriverGetBuildInformationRemote(BUILD_INFO_STRUCT &buildInfo)
Definition: ntv2nubaccess.cpp:2116
NTV2RPCServerAPI::mTerminate
bool mTerminate
Set true to stop server.
Definition: ntv2nubaccess.h:442
PluginRegistry::loadedPlugins
NTV2StringList loadedPlugins(void)
Definition: ntv2nubaccess.cpp:1335
NTV2Plugin::~NTV2Plugin
~NTV2Plugin(void)
Definition: ntv2nubaccess.cpp:1140
kNTV2PluginInfoKey_PluginPath
#define kNTV2PluginInfoKey_PluginPath
Local host full path to plugin file.
Definition: ntv2nubaccess.h:58
NTV2PluginLoader::ExtractCertInfo
static bool ExtractCertInfo(NTV2Dictionary &outInfo, const string &inStr)
Definition: ntv2nubaccess.cpp:1522
NTV2Dictionary::deserialize
bool deserialize(const std::string &inStr)
Resets me from the given string.
Definition: ntv2nubaccess.cpp:183
NTV2PluginLoader::isOpen
bool isOpen(void)
Definition: ntv2nubaccess.cpp:1452
NTV2RPCClientAPI::Description
virtual std::string Description(void) const
Definition: ntv2nubaccess.cpp:2064
NTV2PluginLoader::showCertificate
bool showCertificate(void) const
Definition: ntv2nubaccess.cpp:1455
kNTV2PluginRegInfoKey_OrgUnit
#define kNTV2PluginRegInfoKey_OrgUnit
Plugin organization unit (to match certificate subject OU)
Definition: ntv2nubaccess.h:67
DumpLoadedPlugins
void DumpLoadedPlugins(void)
Definition: ntv2nubaccess.cpp:1929
NTV2_HEADER
All new NTV2 structs start with this common header.
Definition: ntv2publicinterface.h:7196
NBCINFO
#define NBCINFO(__x__)
Definition: ntv2nubaccess.cpp:60
aja::upper
std::string & upper(std::string &str)
Definition: common.cpp:442
UWord
uint16_t UWord
Definition: ajatypes.h:274
NTV2RPCServerAPI::~NTV2RPCServerAPI
virtual ~NTV2RPCServerAPI()
My destructor, automatically calls NTV2Disconnect.
Definition: ntv2nubaccess.cpp:2258
NTV2DeviceSpecParser::NTV2DeviceSpecParser
NTV2DeviceSpecParser(const std::string inSpec="")
My constructor. If given device specification is non-empty, proceeds to Parse it.
Definition: ntv2nubaccess.cpp:275
aja::string_to_wstring
bool string_to_wstring(const std::string &str, std::wstring &wstr)
Definition: common.cpp:248
kNTV2PluginInfoKey_PluginBaseName
#define kNTV2PluginInfoKey_PluginBaseName
Plugin base name (i.e. without extension)
Definition: ntv2nubaccess.h:60
ntv2utils.h
Declares numerous NTV2 utility functions.
NTV2PluginLoader::pluginsPath
string pluginsPath(void) const
Definition: ntv2nubaccess.cpp:1441
NTV2Version
std::string NTV2Version(const bool inDetailed=false)
Definition: ntv2version.cpp:41
PluginRegistry::pluginStats
NTV2StringList pluginStats(void)
Definition: ntv2nubaccess.cpp:1344
NTV2PluginLoader::getBaseNameFromScheme
bool getBaseNameFromScheme(string &outName) const
Definition: ntv2nubaccess.cpp:1656
NTV2RPCClientAPI::NTV2DownloadTestPatternRemote
virtual bool NTV2DownloadTestPatternRemote(const NTV2Channel channel, const NTV2PixelFormat testPatternFBF, const UWord signalMask, const bool testPatDMAEnb, const ULWord testPatNum)
Definition: ntv2nubaccess.cpp:2122
NTV2DeviceSpecParser::DeviceIndex
UWord DeviceIndex(void) const
Definition: ntv2nubaccess.cpp:557
AJA_NTV2_SDK_VERSION
#define AJA_NTV2_SDK_VERSION
Definition: ntv2version.h:20
kQParamVDevFileName
#define kQParamVDevFileName
.vdev file name (with extension)
Definition: ntv2nubaccess.h:44
NTV2PluginLoader::useStdout
bool useStdout(void) const
Definition: ntv2nubaccess.cpp:1453
NTV2GetPluginsFolderPath
std::string NTV2GetPluginsFolderPath(const bool inAddTrailingPathDelim=false)
Definition: ntv2utils.cpp:7691
SIG_EXTENSION
#define SIG_EXTENSION
Definition: ntv2nubaccess.cpp:47
NTV2RPCBase::NTV2RPCBase
NTV2RPCBase(NTV2Dictionary params, uint32_t *pRefCon)
Definition: ntv2nubaccess.cpp:1945
NTV2Buffer::GetString
bool GetString(std::string &outString, const size_t inU8Offset=0, const size_t inMaxSize=128) const
Answers with my contents as a character string.
Definition: ntv2publicinterface.cpp:771
NTV2RPCBase::mParamLock
AJALock mParamLock
Mutex to protect mParams.
Definition: ntv2nubaccess.h:254
aja::stoull
unsigned long long stoull(const std::string &str, std::size_t *idx, int base)
Definition: common.cpp:154
NTV2Plugin::LoadPlugin
static bool LoadPlugin(const string &path, const string &folderPath, NTV2PluginPtr &outPtr, string &outErrMsg, const bool inUseStdout)
Definition: ntv2nubaccess.cpp:1072
ntv2version.h
Defines for the NTV2 SDK version number, used by ajantv2/includes/ntv2enums.h. See the ajantv2/includ...
NTV2Dictionary::DictConstIter
Dict::const_iterator DictConstIter
Definition: ntv2nubaccess.h:141
kNTV2PluginX500AttrKey_CommonName
#define kNTV2PluginX500AttrKey_CommonName
Definition: ntv2nubaccess.h:83
PercentDecode
std::string PercentDecode(const std::string &inStr)
NTV2Dictionary::u16ValueForKey
uint16_t u16ValueForKey(const std::string &inKey, const uint16_t inDefault=0) const
Definition: ntv2nubaccess.cpp:120
PluginRegistry::loadPlugin
bool loadPlugin(const string &path, const string &folderPath, NTV2PluginPtr &outPtr, string &errMsg, const bool useStdout)
Definition: ntv2nubaccess.cpp:1282
NTV2StringList
std::vector< std::string > NTV2StringList
Definition: ntv2utils.h:1155
AJALock
Definition: lock.h:28
kConnectParamScheme
#define kConnectParamScheme
URL scheme.
Definition: ntv2nubaccess.h:24
AJADebug::Open
static AJAStatus Open(bool incrementRefCount=false)
Definition: debug.cpp:44
kNTV2PluginRegInfoKey_Description
#define kNTV2PluginRegInfoKey_Description
Brief plugin description.
Definition: ntv2nubaccess.h:70
AJA_NULL
#define AJA_NULL
Definition: ajatypes.h:220
PluginRegistry::pluginIsLoaded
bool pluginIsLoaded(const string &path)
Definition: ntv2nubaccess.cpp:1318
NTV2RPCClientAPI::NTV2AutoCirculateRemote
virtual bool NTV2AutoCirculateRemote(AUTOCIRCULATE_DATA &autoCircData)
Definition: ntv2nubaccess.cpp:2099
NTV2Plugin::isLoaded
bool isLoaded(void) const
Definition: ntv2nubaccess.cpp:1053
NTV2RPCClientAPI::NTV2WaitForInterruptRemote
virtual bool NTV2WaitForInterruptRemote(const INTERRUPT_ENUMS eInterrupt, const ULWord timeOutMs)
Definition: ntv2nubaccess.cpp:2104
NTV2DeviceSpecParser
One-stop shop for parsing device specifications. (New in SDK 16.3) I do very little in the way of val...
Definition: ntv2nubaccess.h:161
NTV2RPCServerAPI::RunServer
virtual void RunServer(void)
Principal server thread function, subclsses should override.
Definition: ntv2nubaccess.cpp:2267
NTV2Buffer::GetHostPointer
void * GetHostPointer(void) const
Definition: ntv2publicinterface.h:6273
AJAAutoLock
Definition: lock.h:89
kNTV2PluginRegInfoKey_NTV2SDKVersion
#define kNTV2PluginRegInfoKey_NTV2SDKVersion
NTV2 SDK version that plugin was compiled with.
Definition: ntv2nubaccess.h:72
gLoaderDestructCount
uint32_t gLoaderDestructCount(0)
AJAAtomic::Increment
static int32_t Increment(int32_t volatile *pTarget)
Definition: atomic.cpp:82
kConnectParamDevIndex
#define kConnectParamDevIndex
Device having this index number.
Definition: ntv2nubaccess.h:27
NTV2PluginLoader::pluginBaseName
string pluginBaseName(void) const
Definition: ntv2nubaccess.cpp:1442
PLGFAIL
#define PLGFAIL(__x__)
Definition: ntv2nubaccess.cpp:68
kFuncNameCreateClient
#define kFuncNameCreateClient
Create an NTV2RPCClientAPI instance.
Definition: ntv2nubaccess.h:52
NTV2Dictionary::serialize
bool serialize(std::string &outStr) const
Serializes my contents into the given string.
Definition: ntv2nubaccess.cpp:200
PluginRegistry::pluginForPath
bool pluginForPath(const string &path, NTV2PluginPtr &outHandle)
Definition: ntv2nubaccess.cpp:1324
DEC
#define DEC(__x__)
Definition: ntv2publicinterface.h:5769
kQParamShowParams
#define kQParamShowParams
Query parameter option that dumps parameters into message log.
Definition: ntv2nubaccess.h:38
false
#define false
Definition: ntv2devicefeatures.h:25
NTV2RegInfo
Everything needed to call CNTV2Card::ReadRegister or CNTV2Card::WriteRegister functions.
Definition: ntv2publicinterface.h:4046
common.h
Private include file for all ajabase sources.
NTV2DeviceSpecParser::PrintErrors
std::ostream & PrintErrors(std::ostream &oss) const
Definition: ntv2nubaccess.cpp:564
HEX0N
#define HEX0N(__x__, __n__)
Definition: debug.cpp:1175
NTV2Buffer::SetFromHexString
bool SetFromHexString(const std::string &inStr)
Replaces my contents from the given hex-encoded string, resizing me if necessary.
Definition: ntv2publicinterface.cpp:1964
PluginRegistry::hasPath
bool hasPath(const string &path)
Definition: ntv2nubaccess.cpp:1362
P_WARN
#define P_WARN(__x__)
Definition: ntv2nubaccess.cpp:83
NTV2RPCClientAPI::CreateClient
static NTV2RPCClientAPI * CreateClient(NTV2ConnectParams &inParams)
Instantiates a new NTV2RPCClientAPI instance using the given NTV2ConnectParams.
Definition: ntv2nubaccess.cpp:2185
PluginRegistryPtr
AJARefPtr< PluginRegistry > PluginRegistryPtr
Definition: ntv2nubaccess.cpp:1191
ULWord64
uint64_t ULWord64
Definition: ajatypes.h:279
AJAThread::SetThreadName
virtual AJAStatus SetThreadName(const char *name)
Definition: thread.cpp:176
std
Definition: json.hpp:5362
NBSWARN
#define NBSWARN(__x__)
Definition: ntv2nubaccess.cpp:63
AJA_ThreadPriority_Low
@ AJA_ThreadPriority_Low
Definition: thread.h:42
NTV2RPCClientAPI::NTV2Connect
virtual bool NTV2Connect(void)
Definition: ntv2nubaccess.cpp:2077
kFuncNameGetRegInfo
#define kFuncNameGetRegInfo
Answers with plugin registration info.
Definition: ntv2nubaccess.h:54
PluginRegistry::PluginRegistry
PluginRegistry()
Definition: ntv2nubaccess.cpp:1261
ULWordSequence
std::vector< uint32_t > ULWordSequence
An ordered sequence of ULWord (uint32_t) values.
Definition: ntv2publicinterface.h:46
kNTV2PluginSigFileKey_Signature
#define kNTV2PluginSigFileKey_Signature
X509 digital signature (encoded as hex string)
Definition: ntv2nubaccess.h:80
AJA_sERROR
#define AJA_sERROR(_index_, _expr_)
Definition: debug.h:176
AJA_DebugUnit_Application
@ AJA_DebugUnit_Application
Definition: debugshare.h:58
atomic.h
Declares the AJAAtomic class.
gServerDestructCount
uint32_t gServerDestructCount(0)
gClientDestructCount
uint32_t gClientDestructCount(0)
kNTV2PluginInfoKey_PluginsPath
#define kNTV2PluginInfoKey_PluginsPath
Local host full path to folder containing plugins.
Definition: ntv2nubaccess.h:57
NTV2RPCClientAPI::NTV2GetSupportedRemote
virtual bool NTV2GetSupportedRemote(const ULWord inEnumsID, ULWordSet &outSupported)
Definition: ntv2nubaccess.cpp:2167
kConnectParamResource
#define kConnectParamResource
Resource path – everything past URL [scheme://host[:port]/], excluding [?query].
Definition: ntv2nubaccess.h:31
NTV2DeviceIDSet
std::set< NTV2DeviceID > NTV2DeviceIDSet
A set of NTV2DeviceIDs.
Definition: ntv2utils.h:1044
true
#define true
Definition: ntv2devicefeatures.h:26
gLoaderConstructCount
uint32_t gLoaderConstructCount(0)
PluginRegistry::EnableDebugging
static void EnableDebugging(const bool inEnable=true)
Definition: ntv2nubaccess.cpp:1200
NTV2StringListConstIter
NTV2StringList::const_iterator NTV2StringListConstIter
Definition: ntv2utils.h:1157
NTV2Buffer::Truncate
bool Truncate(const size_t inByteCount)
Truncates me to the given length. No reallocation takes place.
Definition: ntv2publicinterface.cpp:1724
NTV2PluginLoader::refCon
void * refCon(void) const
Definition: ntv2nubaccess.cpp:1637
NTV2RPCClientAPI::NTV2MessageRemote
virtual bool NTV2MessageRemote(NTV2_HEADER *pInMessage)
Definition: ntv2nubaccess.cpp:2150
NTV2Buffer::Fill
bool Fill(const T &inValue)
Fills me with the given scalar value.
Definition: ntv2publicinterface.h:6442
AJAThread::SetPriority
virtual AJAStatus SetPriority(AJAThreadPriority priority)
Definition: thread.cpp:133
NTV2RPCClientAPI::NTV2ReadRegisterMultiRemote
virtual bool NTV2ReadRegisterMultiRemote(const ULWord numRegs, ULWord &outFailedRegNum, NTV2RegInfo outRegs[])
Definition: ntv2nubaccess.cpp:2128
NTV2RPCBase::~NTV2RPCBase
virtual ~NTV2RPCBase()
Definition: ntv2nubaccess.cpp:1959
ntv2publicinterface.h
Declares enums and structs used by all platform drivers and the SDK.
PluginRegistry::indexForPath
bool indexForPath(const string &path, size_t &outIndex)
Definition: ntv2nubaccess.cpp:1368
kConnectParamQuery
#define kConnectParamQuery
Query – everything past '?' in URL.
Definition: ntv2nubaccess.h:32
NTV2Dictionary::largestKeySize
size_t largestKeySize(void) const
Definition: ntv2nubaccess.cpp:222
AJAThread::Start
virtual AJAStatus Start()
Definition: thread.cpp:91
gClientConstructCount
uint32_t gClientConstructCount(0)
NTV2RPCClientAPI::Print
virtual std::ostream & Print(std::ostream &oss) const
Definition: ntv2nubaccess.cpp:2056
kNTV2PluginRegInfoKey_Version
#define kNTV2PluginRegInfoKey_Version
Plugin version (string)
Definition: ntv2nubaccess.h:73
xHEX0N
#define xHEX0N(__x__, __n__)
Definition: ntv2publicinterface.h:5768
NTV2PluginLoader::isValidated
bool isValidated(void) const
Definition: ntv2nubaccess.cpp:1924
gPluginDestructCount
uint32_t gPluginDestructCount(0)
kConnectParamDevSerial
#define kConnectParamDevSerial
Device with this serial number.
Definition: ntv2nubaccess.h:28
fpGetRegistrationInfo
bool(* fpGetRegistrationInfo)(const uint32_t, NTV2Dictionary &)
Obtains a plugin's registration information. Starting in SDK 17.1, all plugins must implement this fu...
Definition: ntv2nubaccess.h:468
NTV2PluginLoader::getPluginsFolder
bool getPluginsFolder(string &outPath) const
Definition: ntv2nubaccess.cpp:1642
NTV2PluginLoader::pluginSigPath
string pluginSigPath(void) const
Definition: ntv2nubaccess.cpp:1440
NTV2RPCClientAPI
An object that can connect to, and operate remote or fake devices. I have three general API groups:
Definition: ntv2nubaccess.h:271
NTV2PluginLoader::isVerbose
bool isVerbose(void) const
Definition: ntv2nubaccess.cpp:1454
NTV2Dictionary::valueForKey
std::string valueForKey(const std::string &inKey) const
Definition: ntv2nubaccess.cpp:112
thread.h
Declares the AJAThread class.
NTV2RPCBase::mpRefCon
uint32_t * mpRefCon
Reserved for internal use.
Definition: ntv2nubaccess.h:255
NTV2Dictionary::largestValueSize
size_t largestValueSize(void) const
Definition: ntv2nubaccess.cpp:231
NTV2Dictionary::keys
NTV2StringSet keys(void) const
Definition: ntv2nubaccess.cpp:214
AJAFUNC
#define AJAFUNC
Definition: ajatypes.h:346
NTV2Dictionary
A simple (not thread-safe) set of key/value pairs. (New in SDK 16.3)
Definition: ntv2nubaccess.h:104
ajarefptr.h
Defines the AJARefPtr template class.
NTV2PluginLoader::getFunctionAddress
void * getFunctionAddress(const string &inFuncName)
Definition: ntv2nubaccess.cpp:1907
NTV2DeviceSpecParser::InfoString
std::string InfoString(void) const
Definition: ntv2nubaccess.cpp:541
AJA_SystemInfoSection_System
@ AJA_SystemInfoSection_System
Definition: info.h:64
AJA_sDEBUG
#define AJA_sDEBUG(_index_, _expr_)
Definition: debug.h:220
BITFILE_INFO_STRUCT
Definition: ntv2publicinterface.h:4982
NTV2RPCClientAPI::NTV2ReadRegisterRemote
virtual bool NTV2ReadRegisterRemote(const ULWord regNum, ULWord &outRegValue, const ULWord regMask, const ULWord regShift)
Definition: ntv2nubaccess.cpp:2089
ntv2nubaccess.h
Declares NTV2 "nub" client functions.
PluginRegistry::useStdout
bool useStdout(void) const
Definition: ntv2nubaccess.cpp:1216
PluginRegistry::refConForPath
uint32_t * refConForPath(const string &path)
Definition: ntv2nubaccess.cpp:1377
debug.h
Declares the AJADebug class.
AUTOCIRCULATE_DATA
Definition: ntv2publicinterface.h:4547
NTV2Plugin
Definition: ntv2nubaccess.cpp:1039
AJAAtomic::Decrement
static int32_t Decrement(int32_t volatile *pTarget)
Definition: atomic.cpp:95
P_INFO
#define P_INFO(__x__)
Definition: ntv2nubaccess.cpp:87
NBSDBG
#define NBSDBG(__x__)
Definition: ntv2nubaccess.cpp:66
NTV2RPCClientAPI::NTV2RPCClientAPI
NTV2RPCClientAPI(NTV2ConnectParams inParams, void *pRefCon)
My constructor.
Definition: ntv2nubaccess.cpp:2017
NTV2PluginLoader::getSymbolAddress
void * getSymbolAddress(const string &inSymbolName, string &outErrorMsg)
Definition: ntv2nubaccess.cpp:1629
kQParamVerboseLogging
#define kQParamVerboseLogging
Query parameter option that enables verbose message logging.
Definition: ntv2nubaccess.h:35
AJASystemInfo
Definition: info.h:80
kNTV2PluginRegInfoKey_LongName
#define kNTV2PluginRegInfoKey_LongName
Plugin long name.
Definition: ntv2nubaccess.h:69