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