लेन-देन गाइड

शुरुआती जानकारी

सैंडबॉक्स नहीं की गई C/C++ लाइब्रेरी का इस्तेमाल करते समय, लिंकर यह पक्का करता है कि कंपाइलेशन के बाद सभी ज़रूरी फ़ंक्शन उपलब्ध हों. इसलिए, रनटाइम के दौरान कोई एपीआई कॉल फ़ेल हो सकता है या नहीं, इस बारे में चिंता करने की ज़रूरत नहीं होती.

हालांकि, सैंडबॉक्स की गई लाइब्रेरी का इस्तेमाल करते समय, लाइब्रेरी को चलाने की प्रोसेस एक अलग प्रोसेस में होती है. किसी API कॉल में विफल होने पर RPC लेयर से कॉल पास करने से संबंधित सभी प्रकार की समस्याओं की जांच करना आवश्यक है. कभी-कभी, हो सकता है कि RPC लेयर की गड़बड़ियों में कोई दिलचस्पी न हो. उदाहरण के लिए, बल्क प्रोसेसिंग के दौरान और सैंडबॉक्स के रीस्टार्ट होने पर.

फिर भी, ऊपर बताई गई वजहों से, सैंडबॉक्स किए गए एपीआई कॉल की रिटर्न वैल्यू की नियमित गड़बड़ियों की जांच का समय बढ़ाना ज़रूरी है, ताकि यह जांच की जा सके कि RPC लेयर पर कोई गड़बड़ी मिली है या नहीं. इसी वजह से सभी लाइब्रेरी फ़ंक्शन प्रोटोटाइप, T के बजाय ::sapi::StatusOr<T> दिखाते हैं. अगर लाइब्रेरी फ़ंक्शन शुरू न हो पाने की स्थिति में (उदाहरण के लिए, सैंडबॉक्स उल्लंघन की वजह से), तो रिटर्न वैल्यू में उस गड़बड़ी के बारे में जानकारी शामिल होगी.

RPC लेयर की गड़बड़ियों को हैंडल करने का मतलब यह होगा कि सैंडबॉक्स की गई लाइब्रेरी को किए जाने वाले हर कॉल के बाद, SAPI की RPC लेयर की एक और जांच की जाएगी. इन गंभीर स्थितियों से निपटने के लिए, SAPI, SAPI लेन-देन मॉड्यूल (transaction.h) उपलब्ध कराता है. इस मॉड्यूल में ::sapi::Transaction क्लास होती है और यह पक्का करता है कि सैंडबॉक्स की गई लाइब्रेरी में सभी फ़ंक्शन कॉल बिना किसी आरपीसी लेवल की समस्या के पूरे हो गए हों या काम की कोई गड़बड़ी दिखाते हों.

SAPI लेन-देन

SAPI, सैंडबॉक्स की गई लाइब्रेरी से होस्ट कोड को अलग करता है और कॉलर को समस्या वाले डेटा प्रोसेसिंग अनुरोध को रीस्टार्ट या रद्द करने की सुविधा देता है. SAPI लेन-देन एक और कदम आगे बढ़कर, असफल प्रक्रियाओं को अपने-आप दोहराता है.

SAPI लेन-देन का इस्तेमाल दो अलग-अलग तरीकों से किया जा सकता है: सीधे ::sapi::Transaction से इनहेरिट करना या ::sapi::BasicTransaction को पास किए गए फ़ंक्शन पॉइंटर का इस्तेमाल करना.

SAPI लेन-देन को इन तीन फ़ंक्शन में बदलाव करके तय किया जाता है:

SAPI लेन-देन के तरीके
::sapi::Transaction::Init() यह किसी सामान्य C/C++ लाइब्रेरी के शुरू करने के तरीके को कॉल करने जैसा है. सैंडबॉक्स की गई लाइब्रेरी में होने वाले हर लेन-देन के दौरान, इस तरीके को सिर्फ़ एक बार कॉल किया जाता है. ऐसा तब तक होता है, जब तक लेन-देन फिर से शुरू नहीं हो जाता. रीस्टार्ट होने की स्थिति में, तरीके को फिर से कॉल किया जाता है, चाहे पहले कितने भी रीस्टार्ट हुए हों.
::sapi::Transaction::Main() ::sapi::Transaction::Run() पर किए जाने वाले हर कॉल के लिए, यह तरीका कॉल किया जाता है.
::sapi::Transaction::Finish() यह किसी सामान्य C/C++ लाइब्रेरी के डेटा को क्लीनअप करने के तरीके जैसा ही है. SAPI ट्रांज़ैक्शन ऑब्जेक्ट खत्म होने के दौरान, इस तरीके को सिर्फ़ एक बार कॉल किया जाता है.

सामान्य लाइब्रेरी का इस्तेमाल

सैंडबॉक्स की गई लाइब्रेरी के बिना प्रोजेक्ट में, लाइब्रेरी के साथ काम करते समय सामान्य पैटर्न कुछ ऐसा दिखता है:

LibInit();
while (data = NextDataToProcess()) {
  result += LibProcessData(data);
}
LibClose();

लाइब्रेरी को शुरू किया जाता है. इसके बाद, लाइब्रेरी के एक्सपोर्ट किए गए फ़ंक्शन इस्तेमाल किए जाते हैं. आखिर में, एनवायरमेंट को साफ़ करने के लिए एंड/क्लोज़ फ़ंक्शन को कॉल किया जाता है.

सैंडबॉक्स की गई लाइब्रेरी का इस्तेमाल

सैंडबॉक्स लाइब्रेरी वाले प्रोजेक्ट में, सामान्य लाइब्रेरी के इस्तेमाल से मिला कोड, कॉलबैक से लेन-देन का इस्तेमाल करते समय नीचे दिए गए कोड स्निपेट में बदल जाता है:

// Overwrite the Init method, passed to BasicTransaction initialization
::absl::Status Init(::sapi::Sandbox* sandbox) {
  // Instantiate the SAPI Object
  LibraryAPI lib(sandbox);
  // Instantiate the Sandboxed Library
  SAPI_RETURN_IF_ERROR(lib.LibInit());
  return ::absl::OkStatus();
}

// Overwrite the Finish method, passed to BasicTransaction initialization
::absl::Status Finish(::sapi::Sandbox *sandbox) {
  // Instantiate the SAPI Object
  LibraryAPI lib(sandbox);
  // Clean-up sandboxed library instance
  SAPI_RETURN_IF_ERROR(lib.LibClose());
  return ::absl::OkStatus();
}

// Wrapper function to process data, passed to Run method call
::absl::Status HandleData(::sapi::Sandbox *sandbox, Data data_to_process,
                           Result *out) {
  // Instantiate the SAPI Object
  LibraryAPI lib(sandbox);
  // Call the sandboxed function LibProcessData
  SAPI_ASSIGN_OR_RETURN(*out, lib.LibProcessData(data_to_process));
  return ::absl::OkStatus();
}

void Handle() {
  // Use SAPI Transactions by passing function pointers to ::sapi::BasicTransaction
  ::sapi::BasicTransaction transaction(Init, Finish);
  while (data = NextDataToProcess()) {
    ::sandbox2::Result result;
    // call the ::sapi::Transaction::Run() method
    transaction.Run(HandleData, data, &result);
    // ...
  }
  // ...
}

अगर handle_data को शुरू करने के दौरान कोई गड़बड़ी होती है, तो ट्रांज़ैक्शन क्लास लाइब्रेरी को फिर से शुरू करना पक्का करती है – इसके बारे में ज़्यादा जानकारी नीचे दिए गए सेक्शन में दी गई है.

लेन-देन फिर से शुरू होना

अगर सैंडबॉक्स की गई लाइब्रेरी एपीआई कॉल से, SAPI लेन-देन के तरीकों (ऊपर दी गई टेबल देखें) को लागू करने के दौरान कोई गड़बड़ी होती है, तो लेन-देन फिर से शुरू हो जाएगा. transaction.h में, kDefaultRetryCnt रीस्टार्ट होने की डिफ़ॉल्ट संख्या तय करता है.

रीस्टार्ट होने वाली गड़बड़ियों के उदाहरण:

  • सैंडबॉक्स से जुड़ी नीति का उल्लंघन हुआ
  • सैंडबॉक्स की गई प्रोसेस क्रैश हो गई
  • लाइब्रेरी की गड़बड़ी की वजह से, सैंडबॉक्स किए गए फ़ंक्शन ने गड़बड़ी कोड दिखाया

रीस्टार्ट करने की प्रोसेस, सामान्य Init() और Main() फ़्लो को ट्रैक करती है. अगर ::sapi::Transaction::Run() तरीके को बार-बार किए जाने पर कॉल करने पर गड़बड़ियां मिलती हैं, तो पूरा तरीका कॉल करने वाले को गड़बड़ी दिखाता है

सैंडबॉक्स या RPC गड़बड़ी मैनेज करना

अपने-आप जनरेट हुआ सैंडबॉक्स की गई लाइब्रेरी का इंटरफ़ेस, ओरिजनल C/C++ लाइब्रेरी फ़ंक्शन प्रोटोटाइप के ज़्यादा से ज़्यादा करीब होने की कोशिश करता है. हालांकि, सैंडबॉक्स की गई लाइब्रेरी को किसी भी सैंडबॉक्स या आरपीसी गड़बड़ी का सिग्नल देने की ज़रूरत होती है.

ऐसा करने के लिए, सैंडबॉक्स किए गए फ़ंक्शन की रिटर्न वैल्यू को सीधे तौर पर देने के बजाय, ::sapi::StatusOr<T> रिटर्न टाइप (या void लौटाने वाले फ़ंक्शन के लिए ::sapi::Status) का इस्तेमाल किया जाता है.

इसके अलावा, SAPI किसी SAPI स्टेटस ऑब्जेक्ट की जांच करने और उस पर प्रतिक्रिया देने के लिए, कुछ आसान मैक्रो उपलब्ध कराता है. ये मैक्रो status_macro.h हेडर फ़ाइल में तय किए जाते हैं.

यहां दिया गया कोड स्निपेट, योग के उदाहरण से लिया गया एक छोटा हिस्सा है. इसमें, SAPI स्टेटस और मैक्रो के इस्तेमाल के बारे में बताया गया है:

// Instead of void, use ::sapi::Status
::sapi::Status SumTransaction::Main() {
  // Instantiate the SAPI Object
  SumApi f(sandbox());

  // ::sapi::StatusOr<int> sum(int a, int b)
  SAPI_ASSIGN_OR_RETURN(int v, f.sum(1000, 337));
  // ...

  // ::sapi::Status sums(sapi::v::Ptr* params)
  SumParams params;
  params.mutable_data()->a = 1111;
  params.mutable_data()->b = 222;
  params.mutable_data()->ret = 0;
  SAPI_RETURN_IF_ERROR(f.sums(params.PtrBoth()));
  // ...
  // Gets symbol address and prints its value
  int *ssaddr;
  SAPI_RETURN_IF_ERROR(sandbox()->Symbol(
      "sumsymbol", reinterpret_cast<void**>(&ssaddr)));
  ::sapi::v::Int sumsymbol;
  sumsymbol.SetRemote(ssaddr);
  SAPI_RETURN_IF_ERROR(sandbox()->TransferFromSandboxee(&sumsymbol));
  // ...
  return ::sapi::OkStatus();
}

सैंडबॉक्स रीस्टार्ट

सैंडबॉक्स की गई कई लाइब्रेरी, उपयोगकर्ता के संवेदनशील इनपुट को मैनेज करती हैं. अगर सैंडबॉक्स की गई लाइब्रेरी में कभी कोई गड़बड़ी हो गई है और वह एक-दूसरे से कनेक्ट होने के दौरान डेटा सेव करती है, तो इस संवेदनशील डेटा की सुरक्षा को खतरा हो सकता है. उदाहरण के लिए, अगर Imagemagick लाइब्रेरी का कोई सैंडबॉक्स किया गया वर्शन पिछली दौड़ की तस्वीरें भेजना शुरू कर देता है.

ऐसी स्थिति से बचने के लिए, सैंडबॉक्स को एक से ज़्यादा बार चलाने के लिए फिर से इस्तेमाल नहीं किया जाना चाहिए. सैंडबॉक्स का दोबारा इस्तेमाल रोकने के लिए होस्ट कोड, SAPI लेन-देन का इस्तेमाल करते समय ::sapi::Sandbox::Restart() या ::sapi::Transaction::Restart() का इस्तेमाल करके सैंडबॉक्स की गई लाइब्रेरी की प्रोसेस को फिर से शुरू कर सकता है.

रीस्टार्ट करने से, सैंडबॉक्स की गई लाइब्रेरी की प्रोसेस का कोई भी रेफ़रंस अमान्य हो जाएगा. इसका मतलब है कि पास की गई फ़ाइल डिस्क्रिप्टर या असाइन की गई मेमोरी मौजूद नहीं रहेगी.