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