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