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