ট্রাস্টি দুটি শ্রেণীর অ্যাপ এবং পরিষেবা বিকাশের জন্য API প্রদান করে:
- বিশ্বস্ত অ্যাপ এবং পরিষেবা যা TEE প্রসেসরে চলে
- সাধারণ এবং অবিশ্বস্ত অ্যাপগুলি যেগুলি প্রধান প্রসেসরে চলে এবং বিশ্বস্ত অ্যাপগুলির দ্বারা প্রদত্ত পরিষেবাগুলি ব্যবহার করে৷
ট্রাস্টি এপিআই সাধারণত বিশ্বস্ত আন্তঃপ্রক্রিয়া যোগাযোগ (আইপিসি) সিস্টেমকে বর্ণনা করে, যার মধ্যে অ-নিরাপদ বিশ্বের সাথে যোগাযোগ রয়েছে। প্রধান প্রসেসরে চলমান সফ্টওয়্যার বিশ্বস্ত অ্যাপস এবং পরিষেবাগুলির সাথে সংযোগ করতে বিশ্বস্ত API ব্যবহার করতে পারে এবং আইপি-তে একটি নেটওয়ার্ক পরিষেবার মতোই তাদের সাথে নির্বিচারে বার্তা বিনিময় করতে পারে। একটি অ্যাপ-স্তরের প্রোটোকল ব্যবহার করে এই বার্তাগুলির ডেটা বিন্যাস এবং শব্দার্থবিদ্যা নির্ধারণ করা অ্যাপের উপর নির্ভর করে। বার্তাগুলির নির্ভরযোগ্য ডেলিভারি অন্তর্নিহিত বিশ্বস্ত পরিকাঠামো (প্রধান প্রসেসরে চালিত ড্রাইভারের আকারে) দ্বারা নিশ্চিত করা হয় এবং যোগাযোগ সম্পূর্ণরূপে অসিঙ্ক্রোনাস।
বন্দর এবং চ্যানেল
পোর্টগুলি বিশ্বস্ত অ্যাপগুলি দ্বারা পরিষেবার শেষ-পয়েন্টগুলিকে একটি নামযুক্ত পথের আকারে প্রকাশ করতে ব্যবহৃত হয় যার সাথে ক্লায়েন্টরা সংযোগ করে৷ এটি ক্লায়েন্টদের ব্যবহারের জন্য একটি সাধারণ, স্ট্রিং-ভিত্তিক পরিষেবা আইডি দেয়। নামকরণের নিয়ম হল বিপরীত-DNS-শৈলীর নামকরণ, যেমন com.google.servicename
।
যখন একটি ক্লায়েন্ট একটি পোর্টের সাথে সংযোগ করে, ক্লায়েন্ট একটি পরিষেবার সাথে ইন্টারঅ্যাক্ট করার জন্য একটি চ্যানেল পায়। পরিষেবাটিকে অবশ্যই একটি ইনকামিং সংযোগ গ্রহণ করতে হবে, এবং যখন এটি করে, এটিও একটি চ্যানেল গ্রহণ করে৷ সংক্ষেপে, পোর্টগুলি পরিষেবাগুলি সন্ধান করার জন্য ব্যবহৃত হয় এবং তারপরে এক জোড়া সংযুক্ত চ্যানেলের মাধ্যমে যোগাযোগ ঘটে (অর্থাৎ, একটি বন্দরে সংযোগের উদাহরণ)। যখন একটি ক্লায়েন্ট একটি পোর্টের সাথে সংযোগ করে, একটি প্রতিসম, দ্বি-দিকনির্দেশক সংযোগ স্থাপন করা হয়। এই পূর্ণ-দ্বৈত পথটি ব্যবহার করে, ক্লায়েন্ট এবং সার্ভার উভয় পক্ষই সংযোগটি ছিন্ন করার সিদ্ধান্ত না নেওয়া পর্যন্ত নির্বিচারে বার্তা বিনিময় করতে পারে।
শুধুমাত্র নিরাপদ-সাইড বিশ্বস্ত অ্যাপ বা বিশ্বস্ত কার্নেল মডিউল পোর্ট তৈরি করতে পারে। অ-সুরক্ষিত দিকে (সাধারণ বিশ্বে) চলমান অ্যাপগুলি শুধুমাত্র নিরাপদ দিক দ্বারা প্রকাশিত পরিষেবাগুলির সাথে সংযোগ করতে পারে৷
প্রয়োজনীয়তার উপর নির্ভর করে, একটি বিশ্বস্ত অ্যাপ একই সময়ে ক্লায়েন্ট এবং সার্ভার উভয়ই হতে পারে। একটি বিশ্বস্ত অ্যাপ যা একটি পরিষেবা প্রকাশ করে (একটি সার্ভার হিসাবে) অন্য পরিষেবাগুলির সাথে সংযোগ করতে হতে পারে (ক্লায়েন্ট হিসাবে)৷
হ্যান্ডেল API
হ্যান্ডলগুলি হল স্বাক্ষরবিহীন পূর্ণসংখ্যা যা পোর্ট এবং চ্যানেলের মতো সংস্থানগুলিকে প্রতিনিধিত্ব করে, যা UNIX-এর ফাইল বর্ণনাকারীর মতো। হ্যান্ডেলগুলি তৈরি হওয়ার পরে, সেগুলি একটি অ্যাপ-নির্দিষ্ট হ্যান্ডেল টেবিলে স্থাপন করা হয় এবং পরে উল্লেখ করা যেতে পারে।
একজন কলার set_cookie()
পদ্ধতি ব্যবহার করে একটি হ্যান্ডেলের সাথে ব্যক্তিগত ডেটা সংযুক্ত করতে পারেন।
হ্যান্ডেল API-এ পদ্ধতি
হ্যান্ডলগুলি শুধুমাত্র একটি অ্যাপের প্রসঙ্গে বৈধ৷ স্পষ্টভাবে নির্দিষ্ট না করা পর্যন্ত একটি অ্যাপের অন্য অ্যাপে হ্যান্ডেলের মান দেওয়া উচিত নয়। একটি হ্যান্ডেল মান শুধুমাত্র INVALID_IPC_HANDLE #define,
যেটি একটি অ্যাপ ব্যবহার করতে পারে একটি হ্যান্ডেল অবৈধ বা সেট করা না হওয়ার ইঙ্গিত হিসেবে।
সেট_কুকি()
একটি নির্দিষ্ট হ্যান্ডেলের সাথে কলার-প্রদত্ত ব্যক্তিগত ডেটা সংযুক্ত করে।
long set_cookie(uint32_t handle, void *cookie)
[in] handle
: API কলগুলির একটি দ্বারা যে কোনো হ্যান্ডেল ফেরত দেওয়া হয়
[in] cookie
: বিশ্বস্ত অ্যাপে নির্বিচারে ব্যবহারকারী-স্পেস ডেটার নির্দেশক
[retval]: সাফল্যে NO_ERROR
, < 0
ত্রুটি কোড অন্যথায়
এই কলটি হ্যান্ডেল তৈরি হওয়ার পরে পরবর্তী সময়ে ঘটলে ঘটনাগুলি পরিচালনার জন্য কার্যকর। ইভেন্ট-হ্যান্ডলিং মেকানিজম হ্যান্ডেল এবং এর কুকি ইভেন্ট হ্যান্ডলারকে ফেরত সরবরাহ করে।
wait()
কল ব্যবহার করে ইভেন্টের জন্য হ্যান্ডেলগুলি অপেক্ষা করা যেতে পারে।
অপেক্ষা করুন()
নির্দিষ্ট সময়ের জন্য একটি প্রদত্ত হ্যান্ডেলে একটি ইভেন্ট হওয়ার জন্য অপেক্ষা করে।
long wait(uint32_t handle_id, uevent_t *event, unsigned long timeout_msecs)
[in] handle_id
: যে কোনো হ্যান্ডেল API কলগুলির একটি দ্বারা ফেরত দেওয়া হয়
[আউট] event
: এই হ্যান্ডেলটিতে ঘটে যাওয়া একটি ইভেন্টের প্রতিনিধিত্বকারী কাঠামোর একটি পয়েন্টার
[in] timeout_msecs
: মিলিসেকেন্ডে একটি টাইমআউট মান; -1 এর মান একটি অসীম সময়সীমা
[retval]: NO_ERROR
যদি একটি বৈধ ইভেন্ট একটি নির্দিষ্ট সময়সীমার মধ্যে ঘটে থাকে; ERR_TIMED_OUT
যদি একটি নির্দিষ্ট সময় শেষ হয়ে যায় কিন্তু কোনো ইভেন্ট না ঘটে; অন্যান্য ত্রুটির জন্য < 0
সফল হলে ( retval == NO_ERROR
), wait()
কল একটি নির্দিষ্ট uevent_t
স্ট্রাকচারকে পূর্ণ করে যে ঘটনাটি ঘটেছে।
typedef struct uevent { uint32_t handle; /* handle this event is related to */ uint32_t event; /* combination of IPC_HANDLE_POLL_XXX flags */ void *cookie; /* cookie associated with this handle */ } uevent_t;
event
ফিল্ডে নিম্নলিখিত মানগুলির সংমিশ্রণ রয়েছে:
enum { IPC_HANDLE_POLL_NONE = 0x0, IPC_HANDLE_POLL_READY = 0x1, IPC_HANDLE_POLL_ERROR = 0x2, IPC_HANDLE_POLL_HUP = 0x4, IPC_HANDLE_POLL_MSG = 0x8, IPC_HANDLE_POLL_SEND_UNBLOCKED = 0x10, … more values[TBD] };
IPC_HANDLE_POLL_NONE
- কোনো ইভেন্ট আসলে মুলতুবি নেই, কলারের অপেক্ষা পুনরায় আরম্ভ করা উচিত
IPC_HANDLE_POLL_ERROR
- একটি অনির্দিষ্ট অভ্যন্তরীণ ত্রুটি ঘটেছে৷
IPC_HANDLE_POLL_READY
- হ্যান্ডেল ধরনের উপর নির্ভর করে, নিম্নরূপ:
- পোর্টের জন্য, এই মানটি নির্দেশ করে যে একটি মুলতুবি সংযোগ আছে
- চ্যানেলগুলির জন্য, এই মানটি নির্দেশ করে যে একটি অ্যাসিঙ্ক্রোনাস সংযোগ (
connect()
) প্রতিষ্ঠিত হয়েছিল
নিম্নলিখিত ইভেন্টগুলি শুধুমাত্র চ্যানেলগুলির জন্য প্রাসঙ্গিক:
-
IPC_HANDLE_POLL_HUP
- নির্দেশ করে যে একটি চ্যানেল একজন সহকর্মী দ্বারা বন্ধ করা হয়েছে৷ -
IPC_HANDLE_POLL_MSG
- নির্দেশ করে যে এই চ্যানেলের জন্য একটি মুলতুবি বার্তা রয়েছে৷ -
IPC_HANDLE_POLL_SEND_UNBLOCKED
- নির্দেশ করে যে পূর্বে পাঠানো-অবরুদ্ধ একজন কলার আবার একটি বার্তা পাঠানোর চেষ্টা করতে পারে (বিস্তারিত জানার জন্যsend_msg()
এর বিবরণ দেখুন)
একটি ইভেন্ট হ্যান্ডলারকে নির্দিষ্ট ইভেন্টগুলির সংমিশ্রণ পরিচালনা করার জন্য প্রস্তুত করা উচিত, কারণ একই সময়ে একাধিক বিট সেট করা যেতে পারে। উদাহরণস্বরূপ, একটি চ্যানেলের জন্য, মুলতুবি থাকা বার্তাগুলি এবং একই সময়ে একজন সহকর্মীর দ্বারা একটি সংযোগ বন্ধ করা সম্ভব।
বেশিরভাগ ঘটনাই স্টিকি। যতক্ষণ অন্তর্নিহিত অবস্থা বজায় থাকে ততক্ষণ পর্যন্ত তারা টিকে থাকে (উদাহরণস্বরূপ সমস্ত মুলতুবি বার্তাগুলি প্রাপ্ত হয় এবং মুলতুবি সংযোগ অনুরোধগুলি পরিচালনা করা হয়)। ব্যতিক্রম হল IPC_HANDLE_POLL_SEND_UNBLOCKED
ইভেন্টের ক্ষেত্রে, যেটি পড়ার পরে সাফ হয়ে যায় এবং অ্যাপটির এটি পরিচালনা করার শুধুমাত্র একটি সুযোগ রয়েছে।
close()
পদ্ধতিতে কল করে হ্যান্ডেলগুলি ধ্বংস করা যেতে পারে।
বন্ধ ()
নির্দিষ্ট হ্যান্ডেলের সাথে যুক্ত সংস্থানকে ধ্বংস করে এবং হ্যান্ডেল টেবিল থেকে সরিয়ে দেয়।
long close(uint32_t handle_id);
[in] handle_id
: ধ্বংস করতে হ্যান্ডেল
[retval]: 0 যদি সফল হয়; অন্যথায় একটি নেতিবাচক ত্রুটি
সার্ভার API
একটি সার্ভার তার পরিষেবার শেষ-পয়েন্টগুলির প্রতিনিধিত্ব করে এক বা একাধিক নামযুক্ত পোর্ট তৈরি করে শুরু হয়। প্রতিটি পোর্ট একটি হ্যান্ডেল দ্বারা প্রতিনিধিত্ব করা হয়.
সার্ভার API-এ পদ্ধতি
port_create()
একটি নামযুক্ত পরিষেবা পোর্ট তৈরি করে।
long port_create (const char *path, uint num_recv_bufs, size_t recv_buf_size, uint32_t flags)
[in] path
: পোর্টের স্ট্রিং নাম (উপরে বর্ণিত)। এই নামটি সিস্টেম জুড়ে অনন্য হওয়া উচিত; একটি ডুপ্লিকেট তৈরি করার প্রচেষ্টা ব্যর্থ হয়।
[in] num_recv_bufs
: ক্লায়েন্টের সাথে ডেটা আদান-প্রদানের সুবিধার্থে এই পোর্টে একটি চ্যানেল প্রাক-বরাদ্দ করতে পারে এমন বাফারের সর্বাধিক সংখ্যা। উভয় দিকের ডেটার জন্য বাফারগুলিকে আলাদাভাবে গণনা করা হয়, তাই এখানে 1 উল্লেখ করার অর্থ হল 1টি পাঠান এবং 1টি প্রাপ্ত বাফার আগে থেকে বরাদ্দ করা হয়েছে৷ সাধারণভাবে, প্রয়োজনীয় বাফারের সংখ্যা ক্লায়েন্ট এবং সার্ভারের মধ্যে উচ্চ-স্তরের প্রোটোকল চুক্তির উপর নির্ভর করে। খুব সিঙ্ক্রোনাস প্রোটোকলের ক্ষেত্রে সংখ্যাটি 1 এর মতো কম হতে পারে (বার্তা পাঠান, অন্য পাঠানোর আগে উত্তর গ্রহণ করুন)। তবে সংখ্যাটি আরও বেশি হতে পারে যদি ক্লায়েন্ট একটি উত্তর উপস্থিত হওয়ার আগে একাধিক বার্তা প্রেরণের আশা করে (যেমন, একটি বার্তা একটি প্রস্তাবনা হিসাবে এবং অন্যটি প্রকৃত কমান্ড হিসাবে)। বরাদ্দকৃত বাফার সেটগুলি প্রতি চ্যানেল, তাই দুটি পৃথক সংযোগের (চ্যানেল) পৃথক বাফার সেট থাকবে।
[in] recv_buf_size
: উপরের বাফার সেটে প্রতিটি পৃথক বাফারের সর্বোচ্চ আকার। এই মানটি প্রোটোকল-নির্ভর এবং কার্যকরভাবে সর্বাধিক বার্তা আকারকে সীমিত করে যা আপনি পিয়ারের সাথে বিনিময় করতে পারেন
[in] flags
: পতাকাগুলির একটি সংমিশ্রণ যা অতিরিক্ত পোর্ট আচরণ নির্দিষ্ট করে
এই মানটি নিম্নলিখিত মানগুলির সংমিশ্রণ হওয়া উচিত:
IPC_PORT_ALLOW_TA_CONNECT
- অন্যান্য সুরক্ষিত অ্যাপ থেকে সংযোগের অনুমতি দেয়
IPC_PORT_ALLOW_NS_CONNECT
- অ-সুরক্ষিত বিশ্ব থেকে একটি সংযোগের অনুমতি দেয়
[retval]: নন-নেগেটিভ হলে বা নেতিবাচক হলে একটি নির্দিষ্ট ত্রুটি তৈরি করা পোর্টে হ্যান্ডেল করুন
সার্ভার তারপর wait()
কল ব্যবহার করে ইনকামিং সংযোগের জন্য পোর্ট হ্যান্ডেলের তালিকা পোল করে। uevent_t
স্ট্রাকচারের event
ফিল্ডে সেট করা IPC_HANDLE_POLL_READY
বিট দ্বারা নির্দেশিত একটি সংযোগের অনুরোধ পাওয়ার পরে, সার্ভারের উচিত একটি সংযোগ স্থাপন শেষ করার জন্য accept()
কল করা এবং একটি চ্যানেল (অন্য হ্যান্ডেল দ্বারা প্রতিনিধিত্ব করা) তৈরি করা উচিত যা আগত বার্তাগুলির জন্য পোল করা যেতে পারে। .
গ্রহণ করুন()
একটি ইনকামিং সংযোগ গ্রহণ করে এবং একটি চ্যানেলে একটি হ্যান্ডেল পায়৷
long accept(uint32_t handle_id, uuid_t *peer_uuid);
[in] handle_id
: হ্যান্ডেল যে পোর্টের সাথে একটি ক্লায়েন্ট সংযোগ করেছে তার প্রতিনিধিত্ব করে
[out] peer_uuid
: সংযোগকারী ক্লায়েন্ট অ্যাপের UUID দিয়ে পূরণ করার জন্য একটি uuid_t
কাঠামোর দিকে নির্দেশক। এটি সমস্ত শূন্যে সেট করা হয় যদি সংযোগটি অরক্ষিত বিশ্ব থেকে উদ্ভূত হয়
[retval]: একটি চ্যানেল হ্যান্ডেল (যদি অ-নেতিবাচক) যেখানে সার্ভার ক্লায়েন্টের সাথে বার্তা বিনিময় করতে পারে (বা অন্যথায় একটি ত্রুটি কোড)
ক্লায়েন্ট API
এই বিভাগে ক্লায়েন্ট API-এর পদ্ধতি রয়েছে।
ক্লায়েন্ট API-এ পদ্ধতি
সংযোগ ()
নামের দ্বারা নির্দিষ্ট একটি পোর্টের সাথে একটি সংযোগ শুরু করে।
long connect(const char *path, uint flags);
[in] path
: একটি বিশ্বস্ত অ্যাপ দ্বারা প্রকাশিত একটি পোর্টের নাম
[in] flags
: অতিরিক্ত, ঐচ্ছিক আচরণ নির্দিষ্ট করে
[retval]: সার্ভারের সাথে বার্তা আদান-প্রদান করা যেতে পারে এমন একটি চ্যানেলে হ্যান্ডেল; নেতিবাচক হলে ত্রুটি
যদি কোনো flags
নির্দিষ্ট করা না থাকে ( flags
প্যারামিটারটি 0 এ সেট করা থাকে), কলিং connect()
একটি নির্দিষ্ট পোর্টে একটি সিঙ্ক্রোনাস সংযোগ শুরু করে যা পোর্টটি না থাকলে অবিলম্বে একটি ত্রুটি ফেরত দেয় এবং সার্ভার অন্যথায় একটি গ্রহণ না করা পর্যন্ত একটি ব্লক তৈরি করে। সংযোগ
নিচে বর্ণিত দুটি মানের সংমিশ্রণ উল্লেখ করে এই আচরণটি পরিবর্তন করা যেতে পারে:
enum { IPC_CONNECT_WAIT_FOR_PORT = 0x1, IPC_CONNECT_ASYNC = 0x2, };
IPC_CONNECT_WAIT_FOR_PORT
- অবিলম্বে ব্যর্থ হওয়ার পরিবর্তে নির্দিষ্ট পোর্টটি কার্যকর করার সময় অবিলম্বে উপস্থিত না থাকলে অপেক্ষা করতে একটি connect()
কলকে বাধ্য করে৷
IPC_CONNECT_ASYNC
- সেট করা হলে, একটি অ্যাসিঙ্ক্রোনাস সংযোগ শুরু করে। স্বাভাবিক ক্রিয়াকলাপ শুরু করার আগে uevent_t
কাঠামোর ইভেন্ট ফিল্ডে IPC_HANDLE_POLL_READY
বিট সেট দ্বারা নির্দেশিত একটি সংযোগ সমাপ্তির ইভেন্টের জন্য wait()
কল করে একটি অ্যাপকে ফিরে আসা হ্যান্ডেলের জন্য পোল করতে হবে।
মেসেজিং API
মেসেজিং এপিআই কলগুলি পূর্বে প্রতিষ্ঠিত সংযোগ (চ্যানেল) এর মাধ্যমে বার্তা পাঠানো এবং পড়া সক্ষম করে। মেসেজিং API কল সার্ভার এবং ক্লায়েন্টদের জন্য একই।
একটি ক্লায়েন্ট একটি connect()
কল ইস্যু করে একটি চ্যানেলে একটি হ্যান্ডেল পায় এবং একটি সার্ভার উপরে বর্ণিত একটি accept()
কল থেকে একটি চ্যানেল হ্যান্ডেল পায়।
একটি বিশ্বস্ত বার্তার কাঠামো
নিম্নলিখিত হিসাবে দেখানো হয়েছে, বিশ্বস্ত API দ্বারা আদান-প্রদান করা বার্তাগুলির একটি ন্যূনতম কাঠামো থাকে, এটি সার্ভার এবং ক্লায়েন্টকে প্রকৃত বিষয়বস্তুর শব্দার্থবিদ্যার সাথে একমত হওয়ার জন্য ছেড়ে দেয়:
/* * IPC message */ typedef struct iovec { void *base; size_t len; } iovec_t; typedef struct ipc_msg { uint num_iov; /* number of iovs in this message */ iovec_t *iov; /* pointer to iov array */ uint num_handles; /* reserved, currently not supported */ handle_t *handles; /* reserved, currently not supported */ } ipc_msg_t;
একটি বার্তা iovec_t
কাঠামোর একটি অ্যারে দ্বারা উপস্থাপিত এক বা একাধিক অ-সংলগ্ন বাফারের সমন্বয়ে গঠিত হতে পারে। ট্রাস্টি iov
অ্যারে ব্যবহার করে এই ব্লকগুলিতে স্ক্যাটার-গেদার রিড এবং লেখে। বাফারের বিষয়বস্তু যা iov
অ্যারে দ্বারা বর্ণনা করা যেতে পারে সম্পূর্ণ নির্বিচারে।
মেসেজিং API-এ পদ্ধতি
send_msg()
একটি নির্দিষ্ট চ্যানেলে একটি বার্তা পাঠায়।
long send_msg(uint32_t handle, ipc_msg_t *msg);
[in] handle
: যে চ্যানেলে বার্তা পাঠাতে হবে সেটিকে হ্যান্ডেল করুন
[in] msg
: বার্তাটি বর্ণনাকারী ipc_msg_t structure
দিকে নির্দেশক
[retval]: সাফল্যে পাঠানো মোট বাইট সংখ্যা; অন্যথায় একটি নেতিবাচক ত্রুটি
যদি ক্লায়েন্ট (বা সার্ভার) চ্যানেলের মাধ্যমে একটি বার্তা পাঠানোর চেষ্টা করে এবং গন্তব্য পিয়ার বার্তা সারিতে কোনও স্থান না থাকে, তাহলে চ্যানেলটি একটি প্রেরণ-অবরুদ্ধ অবস্থায় প্রবেশ করতে পারে (এটি একটি সাধারণ সিঙ্ক্রোনাস অনুরোধ/উত্তর প্রোটোকলের জন্য কখনই ঘটবে না কিন্তু আরও জটিল ক্ষেত্রে ঘটতে পারে) যা একটি ERR_NOT_ENOUGH_BUFFER
ত্রুটি কোড ফেরত দিয়ে নির্দেশিত হয়। এই ধরনের ক্ষেত্রে কলকারীকে অপেক্ষা করতে হবে যতক্ষণ না পিয়ার তার রিসিভ সারিতে কিছু জায়গা খালি করে হ্যান্ডলিং এবং রিটায়ারিং বার্তাগুলি পুনরুদ্ধার করে, wait()
কলের মাধ্যমে ফিরে আসা uevent_t
কাঠামোর event
ফিল্ডে IPC_HANDLE_POLL_SEND_UNBLOCKED
বিট সেট দ্বারা নির্দেশিত।
get_msg()
একটি ইনকামিং বার্তা সারিতে পরবর্তী বার্তা সম্পর্কে মেটা-তথ্য পায়৷
একটি নির্দিষ্ট চ্যানেলের।
long get_msg(uint32_t handle, ipc_msg_info_t *msg_info);
[in] handle
: চ্যানেলের হ্যান্ডেল যেখানে একটি নতুন বার্তা পুনরুদ্ধার করতে হবে
[out] msg_info
: বার্তা তথ্য কাঠামো নিম্নরূপ বর্ণিত:
typedef struct ipc_msg_info { size_t len; /* total message length */ uint32_t id; /* message id */ } ipc_msg_info_t;
প্রতিটি বার্তাকে অসামান্য বার্তাগুলির সেট জুড়ে একটি অনন্য আইডি বরাদ্দ করা হয় এবং প্রতিটি বার্তার মোট দৈর্ঘ্য পূরণ করা হয়৷ যদি কনফিগার করা হয় এবং প্রোটোকল দ্বারা অনুমোদিত হয়, তবে একটি নির্দিষ্ট চ্যানেলের জন্য একবারে একাধিক অসামান্য (খোলা) বার্তা থাকতে পারে৷
[retval]: সাফল্যের উপর NO_ERROR
; অন্যথায় একটি নেতিবাচক ত্রুটি
read_msg()
নির্দিষ্ট অফসেট থেকে শুরু করে নির্দিষ্ট আইডি সহ বার্তার বিষয়বস্তু পড়ে।
long read_msg(uint32_t handle, uint32_t msg_id, uint32_t offset, ipc_msg_t *msg);
[in] handle
: যে চ্যানেল থেকে বার্তা পড়তে হবে তার হ্যান্ডেল
[in] msg_id
: পড়ার জন্য বার্তাটির আইডি
[in] offset
: বার্তার মধ্যে অফসেট যা থেকে পড়া শুরু করতে হবে
[আউট] msg
: ipc_msg_t
কাঠামোর দিকে নির্দেশক যা বাফারগুলির একটি সেট বর্ণনা করে যাতে আগত বার্তার ডেটা সংরক্ষণ করা যায়
[retval]: সফলতার উপর msg
বাফারে সংরক্ষিত মোট বাইট সংখ্যা; অন্যথায় একটি নেতিবাচক ত্রুটি
read_msg
পদ্ধতিটি প্রয়োজন অনুসারে একটি ভিন্ন (অবশ্যই অনুক্রমিক) অফসেট থেকে শুরু করে একাধিকবার কল করা যেতে পারে।
put_msg()
একটি নির্দিষ্ট আইডি সহ একটি বার্তা অবসর দেয়।
long put_msg(uint32_t handle, uint32_t msg_id);
[in] handle
: যে চ্যানেলে বার্তাটি এসেছে তার হ্যান্ডেল
[in] msg_id
: বার্তার আইডি অবসর নেওয়া হচ্ছে
[retval]: সাফল্যের উপর NO_ERROR
; অন্যথায় একটি নেতিবাচক ত্রুটি
একটি বার্তা অবসর হয়ে যাওয়ার পরে এবং এটি দখল করা বাফারটি মুক্ত করার পরে বার্তা সামগ্রী অ্যাক্সেস করা যাবে না৷
ফাইল বর্ণনাকারী API
ফাইল বর্ণনাকারী API-তে read()
, write()
, এবং ioctl()
কল রয়েছে। এই সমস্ত কলগুলি পূর্বনির্ধারিত (স্ট্যাটিক) ফাইল বর্ণনাকারীর সেটে কাজ করতে পারে যা ঐতিহ্যগতভাবে ছোট সংখ্যা দ্বারা উপস্থাপিত হয়। বর্তমান বাস্তবায়নে, ফাইল বর্ণনাকারী স্থানটি IPC হ্যান্ডেল স্থান থেকে পৃথক। ট্রাস্টিতে ফাইল বর্ণনাকারী API একটি প্রথাগত ফাইল বর্ণনাকারী-ভিত্তিক API-এর মতো।
ডিফল্টরূপে, 3টি পূর্বনির্ধারিত (স্ট্যান্ডার্ড এবং সুপরিচিত) ফাইল বর্ণনাকারী রয়েছে:
- 0 - স্ট্যান্ডার্ড ইনপুট। স্ট্যান্ডার্ড ইনপুট
fd
এর ডিফল্ট বাস্তবায়ন একটি নো-অপ (যেহেতু বিশ্বস্ত অ্যাপগুলির একটি ইন্টারেক্টিভ কনসোল থাকবে বলে আশা করা হয় না) তাইfd
0-এioctl()
পড়া, লেখা বা আহ্বান করলে একটিERR_NOT_SUPPORTED
ত্রুটি ফিরে আসবে৷ - 1 - স্ট্যান্ডার্ড আউটপুট। স্ট্যান্ডার্ড আউটপুটে লেখা ডেটা প্ল্যাটফর্ম এবং কনফিগারেশনের উপর নির্ভর করে UART এবং/অথবা অ-সুরক্ষিত দিকে উপলব্ধ একটি মেমরি লগ (LK ডিবাগ স্তরের উপর নির্ভর করে) রুট করা যেতে পারে। অ-গুরুত্বপূর্ণ ডিবাগ লগ এবং বার্তাগুলি আদর্শ আউটপুটে যাওয়া উচিত।
read()
এবংioctl()
পদ্ধতি নো-অপস এবং একটিERR_NOT_SUPPORTED
ত্রুটি ফেরত দেওয়া উচিত। - 2 - স্ট্যান্ডার্ড ত্রুটি। স্ট্যান্ডার্ড ত্রুটিতে লেখা ডেটা প্ল্যাটফর্ম এবং কনফিগারেশনের উপর নির্ভর করে, অ-সুরক্ষিত দিকে উপলব্ধ UART বা মেমরি লগে রুট করা উচিত। স্ট্যান্ডার্ড ত্রুটির জন্য শুধুমাত্র সমালোচনামূলক বার্তাগুলি লেখার সুপারিশ করা হয়, কারণ এই স্ট্রিমটি নিরবচ্ছিন্ন হওয়ার সম্ভাবনা খুব বেশি।
read()
এবংioctl()
পদ্ধতি নো-অপস এবং একটিERR_NOT_SUPPORTED
ত্রুটি ফেরত দেওয়া উচিত।
যদিও ফাইল বর্ণনাকারীর এই সেটটি আরও fds
(প্ল্যাটফর্ম-নির্দিষ্ট এক্সটেনশনগুলি বাস্তবায়নের জন্য) বাস্তবায়নের জন্য প্রসারিত করা যেতে পারে, তবে ফাইল বর্ণনাকারীদের প্রসারিত করা সতর্কতার সাথে ব্যবহার করা প্রয়োজন। ফাইল বর্ণনাকারীকে প্রসারিত করা দ্বন্দ্ব তৈরির প্রবণ এবং সাধারণত সুপারিশ করা হয় না।
ফাইল বর্ণনাকারী API-এ পদ্ধতি
পড়ুন()
একটি নির্দিষ্ট ফাইল বর্ণনাকারী থেকে ডেটা বাইট count
জন্য পড়ার চেষ্টা করে।
long read(uint32_t fd, void *buf, uint32_t count);
[in] fd
: ফাইল বর্ণনাকারী যা থেকে পড়তে হবে
[আউট] buf
: একটি বাফারের নির্দেশক যেখানে ডেটা সংরক্ষণ করা যায়
[in] count
: পড়ার জন্য সর্বাধিক বাইট সংখ্যা
[retval]: পড়া বাইট সংখ্যা ফেরত; অন্যথায় একটি নেতিবাচক ত্রুটি
লিখুন()
নির্দিষ্ট ফাইল বর্ণনাকারীতে ডেটার বাইট count
পর্যন্ত লেখে।
long write(uint32_t fd, void *buf, uint32_t count);
[in] fd
: ফাইল বর্ণনাকারী যা লিখতে হবে
[আউট] buf
: লেখার জন্য ডেটা পয়েন্টার
[in] count
: লেখার জন্য সর্বাধিক বাইট সংখ্যা
[retval]: লেখা বাইট সংখ্যা ফেরত; অন্যথায় একটি নেতিবাচক ত্রুটি
ioctl()
একটি প্রদত্ত ফাইল বর্ণনাকারীর জন্য একটি নির্দিষ্ট ioctl
কমান্ড আহ্বান করে।
long ioctl(uint32_t fd, uint32_t cmd, void *args);
[in] fd
: ফাইল বর্ণনাকারী যার উপর ioctl()
চালু করতে হবে
[in] cmd
: ioctl
কমান্ড
[in/out] args
: ioctl()
আর্গুমেন্টের নির্দেশক
বিবিধ API
বিবিধ API-এ পদ্ধতি
gettime()
বর্তমান সিস্টেম সময় প্রদান করে (ন্যানোসেকেন্ডে)।
long gettime(uint32_t clock_id, uint32_t flags, int64_t *time);
[in] clock_id
: প্ল্যাটফর্ম-নির্ভর; ডিফল্টের জন্য শূন্য পাস
[in] flags
: সংরক্ষিত, শূন্য হওয়া উচিত
[আউট] time
: একটি int64_t
মান নির্দেশক যা বর্তমান সময় সংরক্ষণ করতে হবে
[retval]: সাফল্যের উপর NO_ERROR
; অন্যথায় একটি নেতিবাচক ত্রুটি
ন্যানোস্লিপ()
একটি নির্দিষ্ট সময়ের জন্য কলিং অ্যাপের কার্য সম্পাদন স্থগিত করে এবং সেই সময়ের পরে এটি পুনরায় চালু করে।
long nanosleep(uint32_t clock_id, uint32_t flags, uint64_t sleep_time)
[in] clock_id
: সংরক্ষিত, শূন্য হওয়া উচিত
[in] flags
: সংরক্ষিত, শূন্য হওয়া উচিত
[in] sleep_time
: ঘুমের সময় ন্যানোসেকেন্ডে
[retval]: সাফল্যের উপর NO_ERROR
; অন্যথায় একটি নেতিবাচক ত্রুটি
একটি বিশ্বস্ত অ্যাপ সার্ভারের উদাহরণ
নিম্নলিখিত নমুনা অ্যাপটি উপরের API-এর ব্যবহার দেখায়। নমুনাটি একটি "ইকো" পরিষেবা তৈরি করে যা একাধিক ইনকামিং সংযোগ পরিচালনা করে এবং নিরাপদ বা অ-সুরক্ষিত দিক থেকে উদ্ভূত ক্লায়েন্টদের কাছ থেকে প্রাপ্ত সমস্ত বার্তা কলারকে প্রতিফলিত করে।
#include <uapi/err.h> #include <stdbool.h> #include <stddef.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <trusty_ipc.h> #define LOG_TAG "echo_srv" #define TLOGE(fmt, ...) \ fprintf(stderr, "%s: %d: " fmt, LOG_TAG, __LINE__, ##__VA_ARGS__) # define MAX_ECHO_MSG_SIZE 64 static const char * srv_name = "com.android.echo.srv.echo"; static uint8_t msg_buf[MAX_ECHO_MSG_SIZE]; /* * Message handler */ static int handle_msg(handle_t chan) { int rc; struct iovec iov; ipc_msg_t msg; ipc_msg_info_t msg_inf; iov.iov_base = msg_buf; iov.iov_len = sizeof(msg_buf); msg.num_iov = 1; msg.iov = &iov; msg.num_handles = 0; msg.handles = NULL; /* get message info */ rc = get_msg(chan, &msg_inf); if (rc == ERR_NO_MSG) return NO_ERROR; /* no new messages */ if (rc != NO_ERROR) { TLOGE("failed (%d) to get_msg for chan (%d)\n", rc, chan); return rc; } /* read msg content */ rc = read_msg(chan, msg_inf.id, 0, &msg); if (rc < 0) { TLOGE("failed (%d) to read_msg for chan (%d)\n", rc, chan); return rc; } /* update number of bytes received */ iov.iov_len = (size_t) rc; /* send message back to the caller */ rc = send_msg(chan, &msg); if (rc < 0) { TLOGE("failed (%d) to send_msg for chan (%d)\n", rc, chan); return rc; } /* retire message */ rc = put_msg(chan, msg_inf.id); if (rc != NO_ERROR) { TLOGE("failed (%d) to put_msg for chan (%d)\n", rc, chan); return rc; } return NO_ERROR; } /* * Channel event handler */ static void handle_channel_event(const uevent_t * ev) { int rc; if (ev->event & IPC_HANDLE_POLL_MSG) { rc = handle_msg(ev->handle); if (rc != NO_ERROR) { /* report an error and close channel */ TLOGE("failed (%d) to handle event on channel %d\n", rc, ev->handle); close(ev->handle); } return; } if (ev->event & IPC_HANDLE_POLL_HUP) { /* closed by peer. */ close(ev->handle); return; } } /* * Port event handler */ static void handle_port_event(const uevent_t * ev) { uuid_t peer_uuid; if ((ev->event & IPC_HANDLE_POLL_ERROR) || (ev->event & IPC_HANDLE_POLL_HUP) || (ev->event & IPC_HANDLE_POLL_MSG) || (ev->event & IPC_HANDLE_POLL_SEND_UNBLOCKED)) { /* should never happen with port handles */ TLOGE("error event (0x%x) for port (%d)\n", ev->event, ev->handle); abort(); } if (ev->event & IPC_HANDLE_POLL_READY) { /* incoming connection: accept it */ int rc = accept(ev->handle, &peer_uuid); if (rc < 0) { TLOGE("failed (%d) to accept on port %d\n", rc, ev->handle); return; } handle_t chan = rc; while (true){ struct uevent cev; rc = wait(chan, &cev, INFINITE_TIME); if (rc < 0) { TLOGE("wait returned (%d)\n", rc); abort(); } handle_channel_event(&cev); if (cev.event & IPC_HANDLE_POLL_HUP) { return; } } } } /* * Main app entry point */ int main(void) { int rc; handle_t port; /* Initialize service */ rc = port_create(srv_name, 1, MAX_ECHO_MSG_SIZE, IPC_PORT_ALLOW_NS_CONNECT | IPC_PORT_ALLOW_TA_CONNECT); if (rc < 0) { TLOGE("Failed (%d) to create port %s\n", rc, srv_name); abort(); } port = (handle_t) rc; /* enter main event loop */ while (true) { uevent_t ev; ev.handle = INVALID_IPC_HANDLE; ev.event = 0; ev.cookie = NULL; /* wait forever */ rc = wait(port, &ev, INFINITE_TIME); if (rc == NO_ERROR) { /* got an event */ handle_port_event(&ev); } else { TLOGE("wait returned (%d)\n", rc); abort(); } } return 0; }
run_end_to_end_msg_test()
পদ্ধতিটি "ইকো" পরিষেবাতে অসিঙ্ক্রোনাসভাবে 10,000 বার্তা পাঠায় এবং উত্তরগুলি পরিচালনা করে।
static int run_echo_test(void) { int rc; handle_t chan; uevent_t uevt; uint8_t tx_buf[64]; uint8_t rx_buf[64]; ipc_msg_info_t inf; ipc_msg_t tx_msg; iovec_t tx_iov; ipc_msg_t rx_msg; iovec_t rx_iov; /* prepare tx message buffer */ tx_iov.base = tx_buf; tx_iov.len = sizeof(tx_buf); tx_msg.num_iov = 1; tx_msg.iov = &tx_iov; tx_msg.num_handles = 0; tx_msg.handles = NULL; memset (tx_buf, 0x55, sizeof(tx_buf)); /* prepare rx message buffer */ rx_iov.base = rx_buf; rx_iov.len = sizeof(rx_buf); rx_msg.num_iov = 1; rx_msg.iov = &rx_iov; rx_msg.num_handles = 0; rx_msg.handles = NULL; /* open connection to echo service */ rc = sync_connect(srv_name, 1000); if(rc < 0) return rc; /* got channel */ chan = (handle_t)rc; /* send/receive 10000 messages asynchronously. */ uint tx_cnt = 10000; uint rx_cnt = 10000; while (tx_cnt || rx_cnt) { /* send messages until all buffers are full */ while (tx_cnt) { rc = send_msg(chan, &tx_msg); if (rc == ERR_NOT_ENOUGH_BUFFER) break; /* no more space */ if (rc != 64) { if (rc > 0) { /* incomplete send */ rc = ERR_NOT_VALID; } goto abort_test; } tx_cnt--; } /* wait for reply msg or room */ rc = wait(chan, &uevt, 1000); if (rc != NO_ERROR) goto abort_test; /* drain all messages */ while (rx_cnt) { /* get a reply */ rc = get_msg(chan, &inf); if (rc == ERR_NO_MSG) break; /* no more messages */ if (rc != NO_ERROR) goto abort_test; /* read reply data */ rc = read_msg(chan, inf.id, 0, &rx_msg); if (rc != 64) { /* unexpected reply length */ rc = ERR_NOT_VALID; goto abort_test; } /* discard reply */ rc = put_msg(chan, inf.id); if (rc != NO_ERROR) goto abort_test; rx_cnt--; } } abort_test: close(chan); return rc; }
অ-সুরক্ষিত বিশ্ব API এবং অ্যাপ
বিশ্বস্ত পরিষেবাগুলির একটি সেট, সুরক্ষিত দিক থেকে প্রকাশিত এবং IPC_PORT_ALLOW_NS_CONNECT
অ্যাট্রিবিউট দিয়ে চিহ্নিত, অ-সুরক্ষিত দিকে চলমান কার্নেল এবং ব্যবহারকারী স্পেস প্রোগ্রামগুলিতে অ্যাক্সেসযোগ্য।
নন-সিকিউর সাইডে এক্সিকিউশন এনভায়রনমেন্ট (কার্নেল এবং ইউজার স্পেস) সিকিউর সাইডের এক্সিকিউশন এনভায়রনমেন্ট থেকে একেবারে আলাদা। অতএব, উভয় পরিবেশের জন্য একটি একক লাইব্রেরির পরিবর্তে, API-এর দুটি ভিন্ন সেট রয়েছে। কার্নেলে, ক্লায়েন্ট এপিআই বিশ্বস্ত-আইপিসি কার্নেল ড্রাইভার দ্বারা সরবরাহ করা হয় এবং একটি অক্ষর ডিভাইস নোড নিবন্ধন করে যা ব্যবহারকারীর স্থান প্রক্রিয়া দ্বারা নিরাপদ দিকে চলমান পরিষেবাগুলির সাথে যোগাযোগ করতে ব্যবহার করা যেতে পারে।
ব্যবহারকারী স্থান বিশ্বস্ত IPC ক্লায়েন্ট API
ব্যবহারকারী স্থান বিশ্বস্ত IPC ক্লায়েন্ট API লাইব্রেরি হল ডিভাইস নোড fd
এর উপরে একটি পাতলা স্তর।
একটি ব্যবহারকারী স্থান প্রোগ্রাম একটি নির্দিষ্ট বিশ্বস্ত পরিষেবার সাথে একটি সংযোগ শুরু করে, tipc_connect()
কল করে একটি যোগাযোগ সেশন শুরু করে। অভ্যন্তরীণভাবে, tipc_connect()
কল একটি ফাইল বর্ণনাকারী প্রাপ্ত করার জন্য একটি নির্দিষ্ট ডিভাইস নোড খোলে এবং একটি TIPC_IOC_CONNECT ioctl()
কল আহ্বান করে argp
প্যারামিটার সহ একটি স্ট্রিংকে নির্দেশ করে যেখানে একটি পরিষেবার নাম রয়েছে যার সাথে সংযোগ করতে হবে।
#define TIPC_IOC_MAGIC 'r' #define TIPC_IOC_CONNECT _IOW(TIPC_IOC_MAGIC, 0x80, char *)
ফলস্বরূপ ফাইল বর্ণনাকারী শুধুমাত্র পরিষেবার সাথে যোগাযোগ করতে ব্যবহার করা যেতে পারে যার জন্য এটি তৈরি করা হয়েছিল। যখন সংযোগের আর প্রয়োজন হয় না তখন tipc_close()
কল করে ফাইল বর্ণনাকারী বন্ধ করা উচিত।
tipc_connect()
কল দ্বারা প্রাপ্ত ফাইল বর্ণনাকারী একটি সাধারণ অক্ষর ডিভাইস নোড হিসাবে আচরণ করে; ফাইল বর্ণনাকারী:
- প্রয়োজনে নন-ব্লকিং মোডে স্যুইচ করা যেতে পারে
- অন্য দিকে বার্তা পাঠাতে একটি স্ট্যান্ডার্ড
write()
কল ব্যবহার করে লেখা যেতে পারে - নিয়মিত ফাইল বর্ণনাকারী হিসাবে ইনকামিং বার্তাগুলির প্রাপ্যতার জন্য পোল করা যেতে পারে (
poll()
কল ব্যবহার করে বাselect()
কল ব্যবহার করে - ইনকামিং বার্তা পুনরুদ্ধার করতে পড়া যাবে
একজন কলার নির্দিষ্ট fd
জন্য একটি লিখিত কল সম্পাদন করে বিশ্বস্ত পরিষেবাতে একটি বার্তা পাঠান। উপরের write()
কলে পাস করা সমস্ত ডেটা বিশ্বস্ত-আইপিসি ড্রাইভার দ্বারা একটি বার্তায় রূপান্তরিত হয়। বার্তাটি নিরাপদ দিকে বিতরণ করা হয় যেখানে ট্রাস্টি কার্নেলে IPC সাবসিস্টেম দ্বারা ডেটা পরিচালনা করা হয় এবং সঠিক গন্তব্যে রুট করা হয় এবং একটি নির্দিষ্ট চ্যানেল হ্যান্ডেলে IPC_HANDLE_POLL_MSG
ইভেন্ট হিসাবে একটি অ্যাপ ইভেন্ট লুপে বিতরণ করা হয়। নির্দিষ্ট, পরিষেবা-নির্দিষ্ট প্রোটোকলের উপর নির্ভর করে, বিশ্বস্ত পরিষেবা এক বা একাধিক উত্তর বার্তা পাঠাতে পারে যেগুলি অ-সুরক্ষিত দিকে ফিরিয়ে দেওয়া হয় এবং ব্যবহারকারী স্পেস অ্যাপ read()
কল।
tipc_connect()
একটি নির্দিষ্ট tipc
ডিভাইস নোড খোলে এবং একটি নির্দিষ্ট বিশ্বস্ত পরিষেবার সাথে একটি সংযোগ শুরু করে।
int tipc_connect(const char *dev_name, const char *srv_name);
[in] dev_name
: খোলার জন্য বিশ্বস্ত IPC ডিভাইস নোডের পথ
[in] srv_name
: একটি প্রকাশিত বিশ্বস্ত পরিষেবার নাম যার সাথে সংযোগ করতে হবে
[retval]: সফলতার উপর বৈধ ফাইল বর্ণনাকারী, -1 অন্যথায়।
tipc_close()
একটি ফাইল বর্ণনাকারী দ্বারা নির্দিষ্ট বিশ্বস্ত পরিষেবার সংযোগ বন্ধ করে৷
int tipc_close(int fd);
[in] fd
: ফাইল বর্ণনাকারী আগে একটি tipc_connect()
কল দ্বারা খোলা হয়েছিল
কার্নেল বিশ্বস্ত IPC ক্লায়েন্ট API
কার্নেল ট্রাস্টি IPC ক্লায়েন্ট API কার্নেল ড্রাইভারদের জন্য উপলব্ধ। ব্যবহারকারী স্থান বিশ্বস্ত IPC API এই API এর উপরে প্রয়োগ করা হয়েছে।
সাধারণভাবে, এই API-এর সাধারণ ব্যবহারে একজন কলার একটি struct tipc_chan
অবজেক্ট তৈরি করে tipc_create_channel()
ফাংশন ব্যবহার করে এবং তারপর নিরাপদ দিকে চলমান বিশ্বস্ত IPC পরিষেবার সাথে সংযোগ শুরু করতে tipc_chan_connect()
কল ব্যবহার করে। রিমোট সাইডের সাথে সংযোগটি বন্ধ করা যেতে পারে tipc_chan_shutdown()
কল করে তারপর tipc_chan_destroy()
রিসোর্স পরিষ্কার করার জন্য।
একটি বিজ্ঞপ্তি ( handle_event()
কলব্যাকের মাধ্যমে) পাওয়ার পরে যে একটি সংযোগ সফলভাবে প্রতিষ্ঠিত হয়েছে, একজন কলার নিম্নলিখিতগুলি করে:
-
tipc_chan_get_txbuf_timeout()
কল ব্যবহার করে একটি বার্তা বাফার পায় - একটি বার্তা রচনা করে, এবং
- একটি বিশ্বস্ত পরিষেবাতে (নিরাপদ দিকে) সরবরাহের জন্য
tipc_chan_queue_msg()
পদ্ধতি ব্যবহার করে বার্তাটিকে সারিবদ্ধ করে, যার সাথে চ্যানেলটি সংযুক্ত রয়েছে
সারিবদ্ধ সফল হওয়ার পরে, কলারের বার্তা বাফারটি ভুলে যাওয়া উচিত কারণ বার্তা বাফারটি রিমোট সাইড দ্বারা প্রক্রিয়াকরণের পরে শেষ পর্যন্ত ফ্রি বাফার পুলে ফিরে আসে (পরে পুনরায় ব্যবহারের জন্য, অন্যান্য বার্তাগুলির জন্য)। ব্যবহারকারীকে শুধুমাত্র tipc_chan_put_txbuf()
কল করতে হবে যদি এটি এই ধরনের বাফার সারিবদ্ধ করতে ব্যর্থ হয় বা এটি আর প্রয়োজন হয় না।
একজন API ব্যবহারকারী একটি handle_msg()
বিজ্ঞপ্তি কলব্যাক (যাকে বিশ্বস্ত-ipc rx
ওয়ার্ককিউর প্রসঙ্গে বলা হয়) পরিচালনা করে দূরবর্তী দিক থেকে বার্তাগুলি গ্রহণ করে যা পরিচালনা করার জন্য একটি ইনকামিং বার্তা ধারণকারী একটি rx
বাফারে একটি পয়েন্টার প্রদান করে।
এটা প্রত্যাশিত যে handle_msg()
কলব্যাক বাস্তবায়ন একটি বৈধ struct tipc_msg_buf
এ একটি পয়েন্টার প্রদান করে। এটি আগত বার্তা বাফারের মতোই হতে পারে যদি এটি স্থানীয়ভাবে পরিচালনা করা হয় এবং আর প্রয়োজন না হয়। বিকল্পভাবে, এটি একটি নতুন বাফার হতে পারে যা একটি tipc_chan_get_rxbuf()
কল দ্বারা প্রাপ্ত হয় যদি ইনকামিং বাফারটি আরও প্রক্রিয়াকরণের জন্য সারিবদ্ধ থাকে। একটি বিচ্ছিন্ন rx
বাফার ট্র্যাক করতে হবে এবং শেষ পর্যন্ত একটি tipc_chan_put_rxbuf()
কল ব্যবহার করে ছেড়ে দিতে হবে যখন এটির আর প্রয়োজন নেই৷
কার্নেল ট্রাস্টি আইপিসি ক্লায়েন্ট API-এ পদ্ধতি
tipc_create_channel()
একটি নির্দিষ্ট বিশ্বস্ত-ipc ডিভাইসের জন্য একটি বিশ্বস্ত IPC চ্যানেলের একটি উদাহরণ তৈরি এবং কনফিগার করে।
struct tipc_chan *tipc_create_channel(struct device *dev, const struct tipc_chan_ops *ops, void *cb_arg);
[in] dev
: বিশ্বস্ত-আইপিসির নির্দেশক যার জন্য ডিভাইস চ্যানেল তৈরি করা হয়েছে
[in] ops
: একটি struct tipc_chan_ops
এর দিকে নির্দেশক, যেখানে কলার-নির্দিষ্ট কলব্যাক পূরণ করা হয়েছে
[in] cb_arg
: তথ্যের প্রতি নির্দেশক যা tipc_chan_ops
কলব্যাকে পাস করা হয়
[retval]: সাফল্যের উপর struct tipc_chan
এর একটি নতুন-তৈরি উদাহরণের নির্দেশক, অন্যথায় ERR_PTR(err)
সাধারণভাবে, একজন কলারকে অবশ্যই দুটি কলব্যাক প্রদান করতে হবে যেগুলি অ্যাসিঙ্ক্রোনাসভাবে আহ্বান করা হয় যখন সংশ্লিষ্ট কার্যকলাপ ঘটছে।
void (*handle_event)(void *cb_arg, int event)
ইভেন্টটি একটি চ্যানেলের অবস্থার পরিবর্তন সম্পর্কে একজন কলারকে অবহিত করার জন্য আহ্বান করা হয়।
[in] cb_arg
: একটি tipc_create_channel()
কলে পাঠানো ডেটার প্রতি নির্দেশক
[in] event
: একটি ইভেন্ট যা নিম্নলিখিত মানগুলির মধ্যে একটি হতে পারে:
-
TIPC_CHANNEL_CONNECTED
- দূরবর্তী দিকে একটি সফল সংযোগ নির্দেশ করে৷ -
TIPC_CHANNEL_DISCONNECTED
- নির্দেশ করে যে দূরবর্তী দিকটি নতুন সংযোগের অনুরোধ অস্বীকার করেছে বা পূর্বে সংযুক্ত চ্যানেলের জন্য সংযোগ বিচ্ছিন্ন করার অনুরোধ করেছে -
TIPC_CHANNEL_SHUTDOWN
- নির্দেশ করে যে দূরবর্তী দিকটি বন্ধ হয়ে যাচ্ছে, স্থায়ীভাবে সমস্ত সংযোগ বন্ধ করে দিচ্ছে
struct tipc_msg_buf *(*handle_msg)(void *cb_arg, struct tipc_msg_buf *mb)
কলব্যাক একটি নির্দিষ্ট চ্যানেলে একটি নতুন বার্তা গৃহীত হয়েছে তা বিজ্ঞপ্তি দেওয়ার জন্য আহ্বান করা হয়েছে:
- [in]
cb_arg
:tipc_create_channel()
কলে পাঠানো ডেটার প্রতি নির্দেশক - [in]
mb
: একটি ইনকামিং বার্তা বর্ণনা করে একটিstruct tipc_msg_buf
নির্দেশক - [retval]: কলব্যাক বাস্তবায়ন একটি
struct tipc_msg_buf
এ একটি পয়েন্টার ফেরত দেবে বলে আশা করা হচ্ছে যেটি একটিmb
প্যারামিটার হিসাবে প্রাপ্ত একই পয়েন্টার হতে পারে যদি বার্তাটি স্থানীয়ভাবে পরিচালনা করা হয় এবং এর আর প্রয়োজন হয় না (বা এটি একটি নতুন বাফার হতে পারেtipc_chan_get_rxbuf()
কল)
tipc_chan_connect()
নির্দিষ্ট বিশ্বস্ত IPC পরিষেবার সাথে একটি সংযোগ শুরু করে৷
int tipc_chan_connect(struct tipc_chan *chan, const char *port);
[in] chan
: tipc_create_chan()
কল দ্বারা ফিরে আসা একটি চ্যানেলের দিকে নির্দেশক
[in] port
: সংযোগ করার জন্য পরিষেবার নাম ধারণকারী একটি স্ট্রিং নির্দেশক
[retval]: সাফল্যের উপর 0, অন্যথায় একটি নেতিবাচক ত্রুটি
একটি handle_event
কলব্যাক পেয়ে একটি সংযোগ স্থাপন করা হলে কলকারীকে অবহিত করা হয়।
tipc_chan_sutdown()
একটি tipc_chan_connect()
কলের মাধ্যমে পূর্বে শুরু করা বিশ্বস্ত IPC পরিষেবার একটি সংযোগ বন্ধ করে।
int tipc_chan_shutdown(struct tipc_chan *chan);
[in] chan
: tipc_create_chan()
কলের মাধ্যমে ফিরে আসা একটি চ্যানেলের দিকে নির্দেশক
tipc_chan_destroy()
একটি নির্দিষ্ট বিশ্বস্ত IPC চ্যানেল ধ্বংস করে।
void tipc_chan_destroy(struct tipc_chan *chan);
[in] chan
: tipc_create_chan()
কল দ্বারা ফিরে আসা একটি চ্যানেলের দিকে নির্দেশক
tipc_chan_get_txbuf_timeout()
একটি বার্তা বাফার পায় যা একটি নির্দিষ্ট চ্যানেলে ডেটা পাঠাতে ব্যবহার করা যেতে পারে। যদি বাফার অবিলম্বে উপলব্ধ না হয় তবে নির্দিষ্ট সময়সীমার জন্য (মিলিসেকেন্ডে) কলকারীকে অবরুদ্ধ করা হতে পারে৷
struct tipc_msg_buf * tipc_chan_get_txbuf_timeout(struct tipc_chan *chan, long timeout);
[in] chan
: একটি বার্তা সারিবদ্ধ চ্যানেলের দিকে নির্দেশক
[in] chan
: tx
বাফার উপলব্ধ না হওয়া পর্যন্ত অপেক্ষা করার জন্য সর্বাধিক সময়সীমা
[retval]: সফলতার উপর একটি বৈধ বার্তা বাফার, ত্রুটিতে ERR_PTR(err)
tipc_chan_queue_msg()
নির্দিষ্ট বিশ্বস্ত IPC চ্যানেলে পাঠানোর জন্য একটি বার্তা সারিবদ্ধ করে।
int tipc_chan_queue_msg(struct tipc_chan *chan, struct tipc_msg_buf *mb);
[in] chan
: যে চ্যানেলে বার্তাটি সারিবদ্ধ করতে হবে তার নির্দেশক
[in] mb:
বার্তার সারিতে নির্দেশক (একটি tipc_chan_get_txbuf_timeout()
কল দ্বারা প্রাপ্ত)
[retval]: সাফল্যের উপর 0, অন্যথায় একটি নেতিবাচক ত্রুটি
tipc_chan_put_txbuf()
একটি tipc_chan_get_txbuf_timeout()
কল দ্বারা পূর্বে প্রাপ্ত নির্দিষ্ট Tx
বার্তা বাফার রিলিজ করে।
void tipc_chan_put_txbuf(struct tipc_chan *chan, struct tipc_msg_buf *mb);
[in] chan
: এই বার্তা বাফারটি যে চ্যানেলের সাথে সম্পর্কিত তার নির্দেশক
[in] mb
: রিলিজ করার জন্য বার্তা বাফারের দিকে নির্দেশক
[retval]: কিছুই না
tipc_chan_get_rxbuf()
একটি নতুন বার্তা বাফার প্রাপ্ত করে যা নির্দিষ্ট চ্যানেলে বার্তা গ্রহণ করতে ব্যবহার করা যেতে পারে।
struct tipc_msg_buf *tipc_chan_get_rxbuf(struct tipc_chan *chan);
[in] chan
: এই বার্তা বাফারের অন্তর্গত একটি চ্যানেলের নির্দেশক
[retval]: সফলতার উপর একটি বৈধ বার্তা বাফার, ত্রুটিতে ERR_PTR(err)
tipc_chan_put_rxbuf()
পূর্বে একটি tipc_chan_get_rxbuf()
কল দ্বারা প্রাপ্ত একটি নির্দিষ্ট বার্তা বাফার প্রকাশ করে।
void tipc_chan_put_rxbuf(struct tipc_chan *chan, struct tipc_msg_buf *mb);
[in] chan
: এই বার্তা বাফারের অন্তর্গত একটি চ্যানেলের নির্দেশক
[in] mb
: প্রকাশের জন্য একটি বার্তা বাফারের দিকে নির্দেশক
[retval]: কিছুই না
,ট্রাস্টি দুটি শ্রেণীর অ্যাপ এবং পরিষেবা বিকাশের জন্য API প্রদান করে:
- বিশ্বস্ত অ্যাপ এবং পরিষেবা যা TEE প্রসেসরে চলে
- সাধারণ এবং অবিশ্বস্ত অ্যাপগুলি যেগুলি প্রধান প্রসেসরে চলে এবং বিশ্বস্ত অ্যাপগুলির দ্বারা প্রদত্ত পরিষেবাগুলি ব্যবহার করে৷
ট্রাস্টি এপিআই সাধারণত বিশ্বস্ত আন্তঃপ্রক্রিয়া যোগাযোগ (আইপিসি) সিস্টেমকে বর্ণনা করে, যার মধ্যে অ-নিরাপদ বিশ্বের সাথে যোগাযোগ রয়েছে। প্রধান প্রসেসরে চলমান সফ্টওয়্যার বিশ্বস্ত অ্যাপস এবং পরিষেবাগুলির সাথে সংযোগ করতে বিশ্বস্ত API ব্যবহার করতে পারে এবং আইপি-তে একটি নেটওয়ার্ক পরিষেবার মতোই তাদের সাথে নির্বিচারে বার্তা বিনিময় করতে পারে। একটি অ্যাপ-স্তরের প্রোটোকল ব্যবহার করে এই বার্তাগুলির ডেটা বিন্যাস এবং শব্দার্থবিদ্যা নির্ধারণ করা অ্যাপের উপর নির্ভর করে। বার্তাগুলির নির্ভরযোগ্য ডেলিভারি অন্তর্নিহিত বিশ্বস্ত পরিকাঠামো (প্রধান প্রসেসরে চালিত ড্রাইভারের আকারে) দ্বারা নিশ্চিত করা হয় এবং যোগাযোগ সম্পূর্ণরূপে অসিঙ্ক্রোনাস।
বন্দর এবং চ্যানেল
পোর্টগুলি বিশ্বস্ত অ্যাপগুলি দ্বারা পরিষেবার শেষ-পয়েন্টগুলিকে একটি নামযুক্ত পথের আকারে প্রকাশ করতে ব্যবহৃত হয় যার সাথে ক্লায়েন্টরা সংযোগ করে৷ এটি ক্লায়েন্টদের ব্যবহারের জন্য একটি সাধারণ, স্ট্রিং-ভিত্তিক পরিষেবা আইডি দেয়। নামকরণের নিয়ম হল বিপরীত-DNS-শৈলীর নামকরণ, যেমন com.google.servicename
।
যখন একটি ক্লায়েন্ট একটি পোর্টের সাথে সংযোগ করে, ক্লায়েন্ট একটি পরিষেবার সাথে ইন্টারঅ্যাক্ট করার জন্য একটি চ্যানেল পায়। পরিষেবাটিকে অবশ্যই একটি ইনকামিং সংযোগ গ্রহণ করতে হবে, এবং যখন এটি করে, এটিও একটি চ্যানেল গ্রহণ করে৷ সংক্ষেপে, পোর্টগুলি পরিষেবাগুলি সন্ধান করার জন্য ব্যবহৃত হয় এবং তারপরে এক জোড়া সংযুক্ত চ্যানেলের মাধ্যমে যোগাযোগ ঘটে (অর্থাৎ, একটি বন্দরে সংযোগের উদাহরণ)। যখন একটি ক্লায়েন্ট একটি পোর্টের সাথে সংযোগ করে, একটি প্রতিসম, দ্বি-দিকনির্দেশক সংযোগ স্থাপন করা হয়। এই পূর্ণ-দ্বৈত পথটি ব্যবহার করে, ক্লায়েন্ট এবং সার্ভার উভয় পক্ষই সংযোগটি ছিন্ন করার সিদ্ধান্ত না নেওয়া পর্যন্ত নির্বিচারে বার্তা বিনিময় করতে পারে।
শুধুমাত্র নিরাপদ-সাইড বিশ্বস্ত অ্যাপ বা বিশ্বস্ত কার্নেল মডিউল পোর্ট তৈরি করতে পারে। অ-সুরক্ষিত দিকে (সাধারণ বিশ্বে) চলমান অ্যাপগুলি শুধুমাত্র নিরাপদ দিক দ্বারা প্রকাশিত পরিষেবাগুলির সাথে সংযোগ করতে পারে৷
প্রয়োজনীয়তার উপর নির্ভর করে, একটি বিশ্বস্ত অ্যাপ একই সময়ে ক্লায়েন্ট এবং সার্ভার উভয়ই হতে পারে। একটি বিশ্বস্ত অ্যাপ যা একটি পরিষেবা প্রকাশ করে (একটি সার্ভার হিসাবে) অন্য পরিষেবাগুলির সাথে সংযোগ করতে হতে পারে (ক্লায়েন্ট হিসাবে)৷
হ্যান্ডেল API
হ্যান্ডলগুলি হল স্বাক্ষরবিহীন পূর্ণসংখ্যা যা পোর্ট এবং চ্যানেলের মতো সংস্থানগুলিকে প্রতিনিধিত্ব করে, যা UNIX-এর ফাইল বর্ণনাকারীর মতো। হ্যান্ডেলগুলি তৈরি হওয়ার পরে, সেগুলি একটি অ্যাপ-নির্দিষ্ট হ্যান্ডেল টেবিলে স্থাপন করা হয় এবং পরে উল্লেখ করা যেতে পারে।
একজন কলার set_cookie()
পদ্ধতি ব্যবহার করে একটি হ্যান্ডেলের সাথে ব্যক্তিগত ডেটা সংযুক্ত করতে পারেন।
হ্যান্ডেল API-এ পদ্ধতি
হ্যান্ডলগুলি শুধুমাত্র একটি অ্যাপের প্রসঙ্গে বৈধ৷ স্পষ্টভাবে নির্দিষ্ট না করা পর্যন্ত একটি অ্যাপের অন্য অ্যাপে হ্যান্ডেলের মান দেওয়া উচিত নয়। একটি হ্যান্ডেল মান শুধুমাত্র INVALID_IPC_HANDLE #define,
যেটি একটি অ্যাপ ব্যবহার করতে পারে একটি হ্যান্ডেল অবৈধ বা সেট করা না হওয়ার ইঙ্গিত হিসেবে।
সেট_কুকি()
একটি নির্দিষ্ট হ্যান্ডেলের সাথে কলার-প্রদত্ত ব্যক্তিগত ডেটা সংযুক্ত করে।
long set_cookie(uint32_t handle, void *cookie)
[in] handle
: API কলগুলির একটি দ্বারা যে কোনো হ্যান্ডেল ফেরত দেওয়া হয়
[in] cookie
: বিশ্বস্ত অ্যাপে নির্বিচারে ব্যবহারকারী-স্পেস ডেটার নির্দেশক
[retval]: সাফল্যে NO_ERROR
, < 0
ত্রুটি কোড অন্যথায়
এই কলটি হ্যান্ডেল তৈরি হওয়ার পরে পরবর্তী সময়ে ঘটলে ঘটনাগুলি পরিচালনার জন্য কার্যকর। ইভেন্ট-হ্যান্ডলিং মেকানিজম হ্যান্ডেল এবং এর কুকি ইভেন্ট হ্যান্ডলারকে ফেরত সরবরাহ করে।
wait()
কল ব্যবহার করে ইভেন্টের জন্য হ্যান্ডেলগুলি অপেক্ষা করা যেতে পারে।
অপেক্ষা করুন()
নির্দিষ্ট সময়ের জন্য একটি প্রদত্ত হ্যান্ডেলে একটি ইভেন্ট হওয়ার জন্য অপেক্ষা করে।
long wait(uint32_t handle_id, uevent_t *event, unsigned long timeout_msecs)
[in] handle_id
: যে কোনো হ্যান্ডেল API কলগুলির একটি দ্বারা ফেরত দেওয়া হয়
[আউট] event
: এই হ্যান্ডেলটিতে ঘটে যাওয়া একটি ইভেন্টের প্রতিনিধিত্বকারী কাঠামোর একটি পয়েন্টার
[in] timeout_msecs
: মিলিসেকেন্ডে একটি টাইমআউট মান; -1 এর মান একটি অসীম সময়সীমা
[retval]: NO_ERROR
যদি একটি বৈধ ইভেন্ট একটি নির্দিষ্ট সময়সীমার মধ্যে ঘটে থাকে; ERR_TIMED_OUT
যদি একটি নির্দিষ্ট সময় শেষ হয়ে যায় কিন্তু কোনো ইভেন্ট না ঘটে; অন্যান্য ত্রুটির জন্য < 0
সফল হলে ( retval == NO_ERROR
), wait()
কল একটি নির্দিষ্ট uevent_t
স্ট্রাকচারকে পূর্ণ করে যে ঘটনাটি ঘটেছে।
typedef struct uevent { uint32_t handle; /* handle this event is related to */ uint32_t event; /* combination of IPC_HANDLE_POLL_XXX flags */ void *cookie; /* cookie associated with this handle */ } uevent_t;
event
ফিল্ডে নিম্নলিখিত মানগুলির সংমিশ্রণ রয়েছে:
enum { IPC_HANDLE_POLL_NONE = 0x0, IPC_HANDLE_POLL_READY = 0x1, IPC_HANDLE_POLL_ERROR = 0x2, IPC_HANDLE_POLL_HUP = 0x4, IPC_HANDLE_POLL_MSG = 0x8, IPC_HANDLE_POLL_SEND_UNBLOCKED = 0x10, … more values[TBD] };
IPC_HANDLE_POLL_NONE
- কোনো ইভেন্ট আসলে মুলতুবি নেই, কলারের অপেক্ষা পুনরায় আরম্ভ করা উচিত
IPC_HANDLE_POLL_ERROR
- একটি অনির্দিষ্ট অভ্যন্তরীণ ত্রুটি ঘটেছে৷
IPC_HANDLE_POLL_READY
- হ্যান্ডেল ধরনের উপর নির্ভর করে, নিম্নরূপ:
- পোর্টের জন্য, এই মানটি নির্দেশ করে যে একটি মুলতুবি সংযোগ আছে
- চ্যানেলগুলির জন্য, এই মানটি নির্দেশ করে যে একটি অ্যাসিঙ্ক্রোনাস সংযোগ (
connect()
) প্রতিষ্ঠিত হয়েছিল
নিম্নলিখিত ইভেন্টগুলি শুধুমাত্র চ্যানেলগুলির জন্য প্রাসঙ্গিক:
-
IPC_HANDLE_POLL_HUP
- নির্দেশ করে যে একটি চ্যানেল একজন সহকর্মী দ্বারা বন্ধ করা হয়েছে৷ -
IPC_HANDLE_POLL_MSG
- নির্দেশ করে যে এই চ্যানেলের জন্য একটি মুলতুবি বার্তা রয়েছে৷ -
IPC_HANDLE_POLL_SEND_UNBLOCKED
- নির্দেশ করে যে পূর্বে পাঠানো-অবরুদ্ধ একজন কলার আবার একটি বার্তা পাঠানোর চেষ্টা করতে পারে (বিস্তারিত জানার জন্যsend_msg()
এর বিবরণ দেখুন)
একটি ইভেন্ট হ্যান্ডলারকে নির্দিষ্ট ইভেন্টগুলির সংমিশ্রণ পরিচালনা করার জন্য প্রস্তুত করা উচিত, কারণ একই সময়ে একাধিক বিট সেট করা যেতে পারে। উদাহরণস্বরূপ, একটি চ্যানেলের জন্য, মুলতুবি থাকা বার্তাগুলি এবং একই সময়ে একজন সহকর্মীর দ্বারা একটি সংযোগ বন্ধ করা সম্ভব।
বেশিরভাগ ঘটনাই স্টিকি। যতক্ষণ অন্তর্নিহিত অবস্থা বজায় থাকে ততক্ষণ পর্যন্ত তারা টিকে থাকে (উদাহরণস্বরূপ সমস্ত মুলতুবি বার্তাগুলি প্রাপ্ত হয় এবং মুলতুবি সংযোগ অনুরোধগুলি পরিচালনা করা হয়)। ব্যতিক্রম হল IPC_HANDLE_POLL_SEND_UNBLOCKED
ইভেন্টের ক্ষেত্রে, যেটি পড়ার পরে সাফ হয়ে যায় এবং অ্যাপটির এটি পরিচালনা করার শুধুমাত্র একটি সুযোগ রয়েছে।
close()
পদ্ধতিতে কল করে হ্যান্ডেলগুলি ধ্বংস করা যেতে পারে।
বন্ধ ()
নির্দিষ্ট হ্যান্ডেলের সাথে যুক্ত সংস্থানকে ধ্বংস করে এবং হ্যান্ডেল টেবিল থেকে সরিয়ে দেয়।
long close(uint32_t handle_id);
[in] handle_id
: ধ্বংস করতে হ্যান্ডেল
[retval]: 0 যদি সফল হয়; অন্যথায় একটি নেতিবাচক ত্রুটি
সার্ভার API
একটি সার্ভার তার পরিষেবার শেষ-পয়েন্টগুলির প্রতিনিধিত্ব করে এক বা একাধিক নামযুক্ত পোর্ট তৈরি করে শুরু হয়। প্রতিটি পোর্ট একটি হ্যান্ডেল দ্বারা প্রতিনিধিত্ব করা হয়.
সার্ভার API-এ পদ্ধতি
port_create()
একটি নামযুক্ত পরিষেবা পোর্ট তৈরি করে।
long port_create (const char *path, uint num_recv_bufs, size_t recv_buf_size, uint32_t flags)
[in] path
: পোর্টের স্ট্রিং নাম (উপরে বর্ণিত)। এই নামটি সিস্টেম জুড়ে অনন্য হওয়া উচিত; একটি ডুপ্লিকেট তৈরি করার প্রচেষ্টা ব্যর্থ হয়।
[in] num_recv_bufs
: ক্লায়েন্টের সাথে ডেটা আদান-প্রদানের সুবিধার্থে এই পোর্টে একটি চ্যানেল প্রাক-বরাদ্দ করতে পারে এমন বাফারের সর্বাধিক সংখ্যা। উভয় দিকের ডেটা যাওয়ার জন্য বাফারগুলি পৃথকভাবে গণনা করা হয়, সুতরাং 1 এখানে নির্দিষ্ট করার অর্থ 1 টি প্রেরণ এবং 1 টি রিসিভ বাফারকে পূর্বনির্ধারিত করা হয়। সাধারণভাবে, প্রয়োজনীয় বাফারগুলির সংখ্যা ক্লায়েন্ট এবং সার্ভারের মধ্যে উচ্চ-স্তরের প্রোটোকল চুক্তির উপর নির্ভর করে। খুব সিঙ্ক্রোনাস প্রোটোকলের ক্ষেত্রে সংখ্যাটি 1 হিসাবে কম হতে পারে (বার্তা প্রেরণ করুন, অন্য পাঠানোর আগে উত্তর পান)। তবে ক্লায়েন্টটি যদি কোনও উত্তর উপস্থিত হওয়ার আগে একাধিক বার্তা প্রেরণের প্রত্যাশা করে তবে সংখ্যাটি আরও বেশি হতে পারে (উদাহরণস্বরূপ, একটি উপস্থাপনা হিসাবে একটি বার্তা এবং অন্যটি আসল কমান্ড হিসাবে)। বরাদ্দকৃত বাফার সেটগুলি প্রতি চ্যানেল হয়, সুতরাং দুটি পৃথক সংযোগ (চ্যানেল) পৃথক বাফার সেট থাকবে।
[ইন] recv_buf_size
: উপরের বাফার সেটে প্রতিটি পৃথক বাফারের সর্বাধিক আকার। এই মানটি প্রোটোকল-নির্ভর এবং কার্যকরভাবে সর্বাধিক বার্তার আকারকে সীমাবদ্ধ করে আপনি পিয়ারের সাথে বিনিময় করতে পারেন
[ইন] flags
: পতাকাগুলির সংমিশ্রণ যা অতিরিক্ত পোর্ট আচরণ নির্দিষ্ট করে
এই মানটি নিম্নলিখিত মানগুলির সংমিশ্রণ হওয়া উচিত:
IPC_PORT_ALLOW_TA_CONNECT
- অন্যান্য সুরক্ষিত অ্যাপ্লিকেশনগুলির সংযোগের অনুমতি দেয়
IPC_PORT_ALLOW_NS_CONNECT
- অ -সুরক্ষিত জগত থেকে একটি সংযোগের অনুমতি দেয়
[retval]: অ-নেতিবাচক বা নির্দিষ্ট ত্রুটি যদি নেতিবাচক হয় তবে তৈরি করা বন্দরটি হ্যান্ডেল করুন
সার্ভার তারপরে wait()
কল ব্যবহার করে আগত সংযোগগুলির জন্য পোর্ট হ্যান্ডলগুলির তালিকাটি পোল করে। IPC_HANDLE_POLL_READY
বিট সেট দ্বারা নির্দেশিত একটি সংযোগ অনুরোধ পাওয়ার পরে uevent_t
কাঠামোর event
ক্ষেত্রে সেট করুন, সার্ভারটি একটি সংযোগ স্থাপন শেষ করতে এবং একটি চ্যানেল তৈরি করতে (অন্য হ্যান্ডেল দ্বারা প্রতিনিধিত্ব করা) accept()
করতে পারে যা আগত বার্তাগুলির জন্য পোল করা যেতে পারে .
গ্রহণ ()
একটি আগত সংযোগ গ্রহণ করে এবং একটি চ্যানেলে একটি হ্যান্ডেল পায়।
long accept(uint32_t handle_id, uuid_t *peer_uuid);
[ইন] handle_id
: কোনও ক্লায়েন্ট সংযুক্ত বন্দরটির প্রতিনিধিত্ব করে হ্যান্ডেল
[আউট] peer_uuid
: সংযোগকারী ক্লায়েন্ট অ্যাপ্লিকেশনটির ইউইআইডি দিয়ে ভরাট করার জন্য একটি uuid_t
কাঠামোর পয়েন্টার। সংযোগটি যদি ননসেকার ওয়ার্ল্ড থেকে উদ্ভূত হয় তবে এটি সমস্ত জিরোতে সেট করা আছে
[retval]: একটি চ্যানেলে হ্যান্ডেল করুন (যদি অ-নেতিবাচক) যার উপর সার্ভার ক্লায়েন্টের সাথে বার্তা বিনিময় করতে পারে (বা অন্যথায় একটি ত্রুটি কোড)
ক্লায়েন্ট API
এই বিভাগে ক্লায়েন্ট এপিআইতে পদ্ধতি রয়েছে।
ক্লায়েন্ট এপিআই পদ্ধতি
সংযোগ ()
নাম দ্বারা নির্দিষ্ট একটি বন্দরের সাথে একটি সংযোগ শুরু করে।
long connect(const char *path, uint flags);
[ইন] path
: একটি বিশ্বস্ত অ্যাপ্লিকেশন দ্বারা প্রকাশিত একটি বন্দরের নাম
[ইন] flags
: অতিরিক্ত, al চ্ছিক আচরণ নির্দিষ্ট করে
[রেটভাল]: এমন একটি চ্যানেলকে হ্যান্ডেল করুন যার উপরে বার্তাগুলি সার্ভারের সাথে বিনিময় করা যেতে পারে; নেতিবাচক হলে ত্রুটি
যদি কোনও flags
নির্দিষ্ট না করা হয় ( flags
প্যারামিটারটি 0 এ সেট করা থাকে), কলিং connect()
একটি নির্দিষ্ট পোর্টের সাথে একটি সিঙ্ক্রোনাস সংযোগ শুরু করে যা বন্দরটি না থাকলে অবিলম্বে একটি ত্রুটি ফেরত দেয় এবং সার্ভার অন্যথায় গ্রহণ না করা পর্যন্ত একটি ব্লক তৈরি করে সংযোগ
এই আচরণটি নীচে বর্ণিত দুটি মানের সংমিশ্রণ নির্দিষ্ট করে পরিবর্তন করা যেতে পারে:
enum { IPC_CONNECT_WAIT_FOR_PORT = 0x1, IPC_CONNECT_ASYNC = 0x2, };
IPC_CONNECT_WAIT_FOR_PORT
- তাত্ক্ষণিকভাবে ব্যর্থ হওয়ার পরিবর্তে নির্দিষ্ট পোর্টটি তাত্ক্ষণিকভাবে কার্যকর করার সময় না থাকলে অপেক্ষা করতে একটি connect()
কলকে বাধ্য করে।
IPC_CONNECT_ASYNC
- যদি সেট করা হয় তবে একটি অ্যাসিঙ্ক্রোনাস সংযোগ শুরু করে। সাধারণ অপারেশন শুরু করার আগে uevent_t
কাঠামোর ইভেন্ট ক্ষেত্রে IPC_HANDLE_POLL_READY
বিট সেট দ্বারা নির্দেশিত সংযোগ সমাপ্তির ইভেন্টের জন্য wait()
কল করে ফিরে আসা হ্যান্ডেলটির জন্য একটি অ্যাপ্লিকেশনকে পোল করতে হবে।
মেসেজিং API
মেসেজিং এপিআই কলগুলি পূর্বে প্রতিষ্ঠিত সংযোগ (চ্যানেল) এর মাধ্যমে বার্তা প্রেরণ এবং পড়া সক্ষম করে। মেসেজিং এপিআই কলগুলি সার্ভার এবং ক্লায়েন্টদের জন্য একই।
একজন ক্লায়েন্ট একটি connect()
কল জারি করে একটি চ্যানেলে একটি হ্যান্ডেল গ্রহণ করে এবং একটি সার্ভার উপরে বর্ণিত একটি accept()
কল থেকে একটি চ্যানেল হ্যান্ডেল পায়।
একটি বিশ্বস্ত বার্তা কাঠামো
নিম্নলিখিতগুলিতে দেখানো হয়েছে, বিশ্বস্ত এপিআই দ্বারা বিনিময় করা বার্তাগুলির একটি ন্যূনতম কাঠামো রয়েছে, এটি সার্ভার এবং ক্লায়েন্টের কাছে প্রকৃত বিষয়বস্তুর শব্দার্থবিজ্ঞানের সাথে একমত হতে রেখে দেয়:
/* * IPC message */ typedef struct iovec { void *base; size_t len; } iovec_t; typedef struct ipc_msg { uint num_iov; /* number of iovs in this message */ iovec_t *iov; /* pointer to iov array */ uint num_handles; /* reserved, currently not supported */ handle_t *handles; /* reserved, currently not supported */ } ipc_msg_t;
একটি বার্তা iovec_t
কাঠামোর একটি অ্যারে দ্বারা প্রতিনিধিত্ব করা এক বা একাধিক অ-স্বচ্ছল বাফারগুলির সমন্বয়ে গঠিত হতে পারে। বিশ্বস্ত iov
অ্যারে ব্যবহার করে এই ব্লকগুলিতে স্ক্র্যাটার-ব্র্যাথের পড়া এবং লেখেন। iov
অ্যারে দ্বারা বর্ণনা করা যেতে পারে এমন বাফারগুলির সামগ্রী সম্পূর্ণ স্বেচ্ছাসেবী।
মেসেজিং এপিআই পদ্ধতি
send_msg ()
একটি নির্দিষ্ট চ্যানেলে একটি বার্তা প্রেরণ করে।
long send_msg(uint32_t handle, ipc_msg_t *msg);
[ইন] handle
: বার্তাটি পাঠানোর জন্য চ্যানেলটি হ্যান্ডেল করুন
[ইন] msg
: বার্তাটি বর্ণনা করে ipc_msg_t structure
পয়েন্টার
[retval]: সাফল্যের জন্য প্রেরিত মোট বাইটের সংখ্যা; অন্যথায় একটি নেতিবাচক ত্রুটি
যদি ক্লায়েন্ট (বা সার্ভার) চ্যানেলের উপরে কোনও বার্তা প্রেরণের চেষ্টা করছে এবং গন্তব্য পিয়ার বার্তার সারিতে কোনও স্থান না থাকে তবে চ্যানেলটি একটি প্রেরণ-ব্লকড অবস্থায় প্রবেশ করতে পারে (এটি কোনও সাধারণ সিঙ্ক্রোনাস অনুরোধ/উত্তর প্রোটোকলের জন্য কখনও হওয়া উচিত নয় তবে আরও জটিল ক্ষেত্রে ঘটতে পারে) যা কোনও ERR_NOT_ENOUGH_BUFFER
ত্রুটি কোডটি ফিরিয়ে দিয়ে নির্দেশিত হয়। এই জাতীয় ক্ষেত্রে কলারকে অবশ্যই অপেক্ষা করতে হবে যতক্ষণ না পিয়ার তার হ্যান্ডলিং এবং অবসর গ্রহণকারী বার্তাগুলি পুনরুদ্ধার করে তার প্রাপ্তি সারিটিতে কিছু জায়গা মুক্ত করে, IPC_HANDLE_POLL_SEND_UNBLOCKED
বিট সেটটি uevent_t
কাঠামোর event
ফিল্ডে wait()
কল দ্বারা ফিরে ফিরে এসে সেট করে।
get_msg ()
আগত বার্তা সারিটিতে পরবর্তী বার্তা সম্পর্কে মেটা-তথ্য পান
একটি নির্দিষ্ট চ্যানেলের।
long get_msg(uint32_t handle, ipc_msg_info_t *msg_info);
[ইন] handle
: চ্যানেলের হ্যান্ডেল যার উপর একটি নতুন বার্তা অবশ্যই পুনরুদ্ধার করতে হবে
[আউট] msg_info
: বার্তা সম্পর্কিত তথ্য কাঠামো নিম্নলিখিত হিসাবে বর্ণিত:
typedef struct ipc_msg_info { size_t len; /* total message length */ uint32_t id; /* message id */ } ipc_msg_info_t;
প্রতিটি বার্তা অসামান্য বার্তাগুলির সেট জুড়ে একটি অনন্য আইডি বরাদ্দ করা হয়, এবং প্রতিটি বার্তার মোট দৈর্ঘ্য পূরণ করা হয় Prot প্রোটোকল দ্বারা কনফিগার করা এবং অনুমোদিত হলে, একটি নির্দিষ্ট চ্যানেলের জন্য একবারে একাধিক বকেয়া (খোলা) বার্তা থাকতে পারে।
[retval]: সাফল্যের উপর NO_ERROR
; অন্যথায় একটি নেতিবাচক ত্রুটি
Read_msg ()
নির্দিষ্ট অফসেট থেকে শুরু করে নির্দিষ্ট আইডি দিয়ে বার্তার সামগ্রীটি পড়ে।
long read_msg(uint32_t handle, uint32_t msg_id, uint32_t offset, ipc_msg_t *msg);
[ইন] handle
: চ্যানেলের হ্যান্ডেল যা থেকে বার্তাটি পড়তে হবে
[ইন] msg_id
: পড়ার বার্তার আইডি
[ইন] offset
: যা থেকে পড়া শুরু করা বার্তায় অফসেট
[আউট] msg
: ipc_msg_t
কাঠামোর পয়েন্টারটি বাফারগুলির একটি সেট বর্ণনা করে যা আগত বার্তা ডেটা সঞ্চয় করতে পারে
[রেটভাল]: সাফল্যের উপর msg
বাফারগুলিতে সঞ্চিত মোট বাইটের সংখ্যা; অন্যথায় একটি নেতিবাচক ত্রুটি
read_msg
পদ্ধতিটিকে প্রয়োজন অনুসারে অফসেট থেকে শুরু করে একাধিকবার বলা যেতে পারে।
put_msg ()
একটি নির্দিষ্ট আইডি সহ একটি বার্তা অবসর গ্রহণ করে।
long put_msg(uint32_t handle, uint32_t msg_id);
[ইন] handle
: চ্যানেলের হ্যান্ডেল যার উপর বার্তাটি এসেছে
[ইন] msg_id
: বার্তার আইডি অবসরপ্রাপ্ত হচ্ছে
[retval]: সাফল্যের উপর NO_ERROR
; অন্যথায় একটি নেতিবাচক ত্রুটি
কোনও বার্তা অবসর নেওয়ার পরে এবং এটি দখল করা বাফারটি মুক্ত করার পরে বার্তার বিষয়বস্তু অ্যাক্সেস করা যাবে না।
ফাইল বর্ণনাকারী এপিআই
ফাইল বর্ণনাকারী এপিআইতে read()
, write()
এবং ioctl()
কল অন্তর্ভুক্ত রয়েছে। এই সমস্ত কলগুলি ফাইল বর্ণনাকারীদের একটি পূর্বনির্ধারিত (স্ট্যাটিক) সেটে চালিত করতে পারে tradition তিহ্যগতভাবে ছোট সংখ্যার দ্বারা প্রতিনিধিত্ব করা। বর্তমান বাস্তবায়নে, ফাইল বর্ণনাকারী স্থান আইপিসি হ্যান্ডেল স্পেস থেকে পৃথক। ট্রাস্টে ফাইল বর্ণনাকারী এপিআই একটি traditional তিহ্যবাহী ফাইল বর্ণনাকারী-ভিত্তিক এপিআইয়ের অনুরূপ।
ডিফল্টরূপে, 3 টি পূর্বনির্ধারিত (মানক এবং সুপরিচিত) ফাইল বর্ণনাকারী রয়েছে:
- 0 - স্ট্যান্ডার্ড ইনপুট। স্ট্যান্ডার্ড ইনপুট
fd
এর ডিফল্ট বাস্তবায়ন একটি নো-ওপ (যেমন বিশ্বস্ত অ্যাপ্লিকেশনগুলির ইন্টারেক্টিভ কনসোল থাকবে বলে আশা করা যায় না) তাইfd
0 এioctl()
পড়া, লেখা বা আহ্বান করা একটিERR_NOT_SUPPORTED
ত্রুটি ফিরিয়ে দেওয়া উচিত। - 1 - স্ট্যান্ডার্ড আউটপুট। স্ট্যান্ডার্ড আউটপুটে লিখিত ডেটা প্ল্যাটফর্ম এবং কনফিগারেশনের উপর নির্ভর করে অ-সুরক্ষিত দিকে উপলব্ধ একটি মেমরি লগকে (এলকে ডিবাগ স্তরের উপর নির্ভর করে) রুট করা যেতে পারে। অ-সমালোচনামূলক ডিবাগ লগ এবং বার্তাগুলি স্ট্যান্ডার্ড আউটপুটে যাওয়া উচিত।
read()
এবংioctl()
পদ্ধতিগুলি NO-NO-OP এবং একটিERR_NOT_SUPPORTED
ত্রুটি ফিরিয়ে দেওয়া উচিত। - 2 - স্ট্যান্ডার্ড ত্রুটি। স্ট্যান্ডার্ড ত্রুটির জন্য লিখিত ডেটা প্ল্যাটফর্ম এবং কনফিগারেশনের উপর নির্ভর করে অ-সুরক্ষিত দিকে উপলব্ধ ইউআরটি বা মেমরি লগের কাছে যেতে হবে। স্ট্যান্ডার্ড ত্রুটির জন্য কেবল সমালোচনামূলক বার্তা লেখার পরামর্শ দেওয়া হয়, কারণ এই স্ট্রিমটি খুব কমে যাওয়ার সম্ভাবনা রয়েছে।
read()
এবংioctl()
পদ্ধতিগুলি NO-NO-OP এবং একটিERR_NOT_SUPPORTED
ত্রুটি ফিরিয়ে দেওয়া উচিত।
যদিও ফাইল বর্ণনাকারীদের এই সেটটি আরও fds
বাস্তবায়নের জন্য বাড়ানো যেতে পারে (প্ল্যাটফর্ম-নির্দিষ্ট এক্সটেনশনগুলি প্রয়োগ করতে), ফাইল বর্ণনাকারীদের প্রসারিত করার জন্য সাবধানতার সাথে ব্যবহার করা দরকার। ফাইল বর্ণনাকারী প্রসারিত করা দ্বন্দ্ব তৈরি করার প্রবণ এবং সাধারণত সুপারিশ করা হয় না।
ফাইল বর্ণনাকারী এপিআই পদ্ধতি
পড়ুন()
একটি নির্দিষ্ট ফাইল বর্ণনাকারী থেকে ডেটা বাইট count
করার চেষ্টা।
long read(uint32_t fd, void *buf, uint32_t count);
[ইন] fd
: ফাইল বর্ণনাকারী যা থেকে পড়তে হবে
[আউট] buf
: ডেটা সঞ্চয় করার জন্য একটি বাফারের পয়েন্টার
[ইন] count
: পড়ার জন্য সর্বাধিক সংখ্যক বাইট
[retval]: বাইট পড়ার সংখ্যা ফিরে; অন্যথায় একটি নেতিবাচক ত্রুটি
লিখুন()
নির্দিষ্ট ফাইল বর্ণনাকারীর কাছে ডেটা বাইট count
পর্যন্ত লিখেছেন।
long write(uint32_t fd, void *buf, uint32_t count);
[ইন] fd
: ফাইল বর্ণনাকারী যা লিখতে হবে
[আউট] buf
: লেখার জন্য ডেটা পয়েন্টার
[ইন] count
: লেখার জন্য সর্বাধিক সংখ্যক বাইট
[retval]: লিখিত বাইটের সংখ্যা ফিরে; অন্যথায় একটি নেতিবাচক ত্রুটি
ioctl()
প্রদত্ত ফাইল বর্ণনাকারীর জন্য একটি নির্দিষ্ট ioctl
কমান্ডের আহ্বান জানায়।
long ioctl(uint32_t fd, uint32_t cmd, void *args);
[ইন] fd
: ফাইল বর্ণনাকারী যার উপর ioctl()
অনুরোধ করবেন
[ইন] cmd
: ioctl
কমান্ড
[ইন/আউট] args
: ioctl()
আর্গুমেন্টের পয়েন্টার
বিবিধ এপিআই
বিবিধ এপিআই পদ্ধতি
গেটটাইম ()
বর্তমান সিস্টেমের সময়টি (ন্যানোসেকেন্ডে) প্রদান করে।
long gettime(uint32_t clock_id, uint32_t flags, int64_t *time);
[ইন] clock_id
: প্ল্যাটফর্ম-নির্ভর; ডিফল্ট জন্য শূন্য পাস
[ইন] flags
: সংরক্ষিত, শূন্য হওয়া উচিত
[আউট] time
: বর্তমান সময়টি সঞ্চয় করার জন্য একটি int64_t
মান পয়েন্টার
[retval]: সাফল্যের উপর NO_ERROR
; অন্যথায় একটি নেতিবাচক ত্রুটি
ন্যানোস্লিপ ()
নির্দিষ্ট সময়ের জন্য কলিং অ্যাপটির কার্যকরকরণ স্থগিত করে এবং সেই সময়ের পরে এটি পুনরায় শুরু করে।
long nanosleep(uint32_t clock_id, uint32_t flags, uint64_t sleep_time)
[ইন] clock_id
: সংরক্ষিত, শূন্য হওয়া উচিত
[ইন] flags
: সংরক্ষিত, শূন্য হওয়া উচিত
[ইন] sleep_time
: ন্যানোসেকেন্ডে ঘুমের সময়
[retval]: সাফল্যের উপর NO_ERROR
; অন্যথায় একটি নেতিবাচক ত্রুটি
একটি বিশ্বস্ত অ্যাপ্লিকেশন সার্ভারের উদাহরণ
নিম্নলিখিত নমুনা অ্যাপটি উপরের এপিআইগুলির ব্যবহার দেখায়। নমুনাটি একটি "প্রতিধ্বনি" পরিষেবা তৈরি করে যা একাধিক আগত সংযোগগুলি পরিচালনা করে এবং কলারের কাছে প্রতিফলিত করে যা এটি সুরক্ষিত বা অ-সুরক্ষিত দিক থেকে উদ্ভূত ক্লায়েন্টদের কাছ থেকে প্রাপ্ত সমস্ত বার্তা।
#include <uapi/err.h> #include <stdbool.h> #include <stddef.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <trusty_ipc.h> #define LOG_TAG "echo_srv" #define TLOGE(fmt, ...) \ fprintf(stderr, "%s: %d: " fmt, LOG_TAG, __LINE__, ##__VA_ARGS__) # define MAX_ECHO_MSG_SIZE 64 static const char * srv_name = "com.android.echo.srv.echo"; static uint8_t msg_buf[MAX_ECHO_MSG_SIZE]; /* * Message handler */ static int handle_msg(handle_t chan) { int rc; struct iovec iov; ipc_msg_t msg; ipc_msg_info_t msg_inf; iov.iov_base = msg_buf; iov.iov_len = sizeof(msg_buf); msg.num_iov = 1; msg.iov = &iov; msg.num_handles = 0; msg.handles = NULL; /* get message info */ rc = get_msg(chan, &msg_inf); if (rc == ERR_NO_MSG) return NO_ERROR; /* no new messages */ if (rc != NO_ERROR) { TLOGE("failed (%d) to get_msg for chan (%d)\n", rc, chan); return rc; } /* read msg content */ rc = read_msg(chan, msg_inf.id, 0, &msg); if (rc < 0) { TLOGE("failed (%d) to read_msg for chan (%d)\n", rc, chan); return rc; } /* update number of bytes received */ iov.iov_len = (size_t) rc; /* send message back to the caller */ rc = send_msg(chan, &msg); if (rc < 0) { TLOGE("failed (%d) to send_msg for chan (%d)\n", rc, chan); return rc; } /* retire message */ rc = put_msg(chan, msg_inf.id); if (rc != NO_ERROR) { TLOGE("failed (%d) to put_msg for chan (%d)\n", rc, chan); return rc; } return NO_ERROR; } /* * Channel event handler */ static void handle_channel_event(const uevent_t * ev) { int rc; if (ev->event & IPC_HANDLE_POLL_MSG) { rc = handle_msg(ev->handle); if (rc != NO_ERROR) { /* report an error and close channel */ TLOGE("failed (%d) to handle event on channel %d\n", rc, ev->handle); close(ev->handle); } return; } if (ev->event & IPC_HANDLE_POLL_HUP) { /* closed by peer. */ close(ev->handle); return; } } /* * Port event handler */ static void handle_port_event(const uevent_t * ev) { uuid_t peer_uuid; if ((ev->event & IPC_HANDLE_POLL_ERROR) || (ev->event & IPC_HANDLE_POLL_HUP) || (ev->event & IPC_HANDLE_POLL_MSG) || (ev->event & IPC_HANDLE_POLL_SEND_UNBLOCKED)) { /* should never happen with port handles */ TLOGE("error event (0x%x) for port (%d)\n", ev->event, ev->handle); abort(); } if (ev->event & IPC_HANDLE_POLL_READY) { /* incoming connection: accept it */ int rc = accept(ev->handle, &peer_uuid); if (rc < 0) { TLOGE("failed (%d) to accept on port %d\n", rc, ev->handle); return; } handle_t chan = rc; while (true){ struct uevent cev; rc = wait(chan, &cev, INFINITE_TIME); if (rc < 0) { TLOGE("wait returned (%d)\n", rc); abort(); } handle_channel_event(&cev); if (cev.event & IPC_HANDLE_POLL_HUP) { return; } } } } /* * Main app entry point */ int main(void) { int rc; handle_t port; /* Initialize service */ rc = port_create(srv_name, 1, MAX_ECHO_MSG_SIZE, IPC_PORT_ALLOW_NS_CONNECT | IPC_PORT_ALLOW_TA_CONNECT); if (rc < 0) { TLOGE("Failed (%d) to create port %s\n", rc, srv_name); abort(); } port = (handle_t) rc; /* enter main event loop */ while (true) { uevent_t ev; ev.handle = INVALID_IPC_HANDLE; ev.event = 0; ev.cookie = NULL; /* wait forever */ rc = wait(port, &ev, INFINITE_TIME); if (rc == NO_ERROR) { /* got an event */ handle_port_event(&ev); } else { TLOGE("wait returned (%d)\n", rc); abort(); } } return 0; }
run_end_to_end_msg_test()
পদ্ধতিটি "প্রতিধ্বনি" পরিষেবাটিতে 10,000 বার্তা প্রেরণ করে এবং উত্তরগুলি পরিচালনা করে।
static int run_echo_test(void) { int rc; handle_t chan; uevent_t uevt; uint8_t tx_buf[64]; uint8_t rx_buf[64]; ipc_msg_info_t inf; ipc_msg_t tx_msg; iovec_t tx_iov; ipc_msg_t rx_msg; iovec_t rx_iov; /* prepare tx message buffer */ tx_iov.base = tx_buf; tx_iov.len = sizeof(tx_buf); tx_msg.num_iov = 1; tx_msg.iov = &tx_iov; tx_msg.num_handles = 0; tx_msg.handles = NULL; memset (tx_buf, 0x55, sizeof(tx_buf)); /* prepare rx message buffer */ rx_iov.base = rx_buf; rx_iov.len = sizeof(rx_buf); rx_msg.num_iov = 1; rx_msg.iov = &rx_iov; rx_msg.num_handles = 0; rx_msg.handles = NULL; /* open connection to echo service */ rc = sync_connect(srv_name, 1000); if(rc < 0) return rc; /* got channel */ chan = (handle_t)rc; /* send/receive 10000 messages asynchronously. */ uint tx_cnt = 10000; uint rx_cnt = 10000; while (tx_cnt || rx_cnt) { /* send messages until all buffers are full */ while (tx_cnt) { rc = send_msg(chan, &tx_msg); if (rc == ERR_NOT_ENOUGH_BUFFER) break; /* no more space */ if (rc != 64) { if (rc > 0) { /* incomplete send */ rc = ERR_NOT_VALID; } goto abort_test; } tx_cnt--; } /* wait for reply msg or room */ rc = wait(chan, &uevt, 1000); if (rc != NO_ERROR) goto abort_test; /* drain all messages */ while (rx_cnt) { /* get a reply */ rc = get_msg(chan, &inf); if (rc == ERR_NO_MSG) break; /* no more messages */ if (rc != NO_ERROR) goto abort_test; /* read reply data */ rc = read_msg(chan, inf.id, 0, &rx_msg); if (rc != 64) { /* unexpected reply length */ rc = ERR_NOT_VALID; goto abort_test; } /* discard reply */ rc = put_msg(chan, inf.id); if (rc != NO_ERROR) goto abort_test; rx_cnt--; } } abort_test: close(chan); return rc; }
অ-সুরক্ষিত ওয়ার্ল্ড এপিআই এবং অ্যাপস
সিকিউর সাইড থেকে প্রকাশিত এবং IPC_PORT_ALLOW_NS_CONNECT
অ্যাট্রিবিউটের সাথে চিহ্নিত বিশ্বস্ত পরিষেবাগুলির একটি সেট, কার্নেল এবং ব্যবহারকারী স্পেস প্রোগ্রামগুলিতে অ-সুরক্ষিত দিকে চলমান অ্যাক্সেসযোগ্য।
সুরক্ষিত দিকের (কার্নেল এবং ব্যবহারকারীর স্থান) কার্যকর করার পরিবেশটি সুরক্ষিত-পক্ষের কার্যকরকরণের পরিবেশের থেকে মারাত্মকভাবে পৃথক। অতএব, উভয় পরিবেশের জন্য একটি একক লাইব্রেরির পরিবর্তে, এপিআইগুলির দুটি পৃথক সেট রয়েছে। কার্নেলে, ক্লায়েন্ট এপিআই বিশ্বস্ত-আইপিসি কার্নেল ড্রাইভার দ্বারা সরবরাহ করা হয় এবং একটি চরিত্র ডিভাইস নোড নিবন্ধন করে যা ব্যবহারকারী স্পেস প্রক্রিয়াগুলি সুরক্ষিত পাশে চলমান পরিষেবাগুলির সাথে যোগাযোগের জন্য ব্যবহার করা যেতে পারে।
ব্যবহারকারী স্পেস ট্রাডি আইপিসি ক্লায়েন্ট এপিআই
ব্যবহারকারী স্পেস ট্রাস্টি আইপিসি ক্লায়েন্ট এপিআই লাইব্রেরি ডিভাইস নোড fd
এর শীর্ষে একটি পাতলা স্তর।
একটি ব্যবহারকারী স্পেস প্রোগ্রাম একটি নির্দিষ্ট বিশ্বস্ত পরিষেবার সাথে সংযোগ শুরু করে tipc_connect()
কল করে একটি যোগাযোগ অধিবেশন শুরু করে। অভ্যন্তরীণভাবে, tipc_connect()
কলটি একটি ফাইল বর্ণনাকারী পেতে একটি নির্দিষ্ট ডিভাইস নোড খোলে এবং একটি TIPC_IOC_CONNECT ioctl()
argp
প্যারামিটারের সাথে কল করে একটি পরিষেবা নামযুক্ত একটি স্ট্রিংকে নির্দেশ করে যার সাথে সংযোগ স্থাপন করা হয়।
#define TIPC_IOC_MAGIC 'r' #define TIPC_IOC_CONNECT _IOW(TIPC_IOC_MAGIC, 0x80, char *)
ফলস্বরূপ ফাইল বর্ণনাকারী কেবল যে পরিষেবার জন্য এটি তৈরি করা হয়েছিল তার সাথে যোগাযোগ করতে ব্যবহার করা যেতে পারে। যখন সংযোগটি আর প্রয়োজন হয় না তখন ফাইলের বর্ণনাকারী tipc_close()
কল করে বন্ধ করা উচিত।
tipc_connect()
কল দ্বারা প্রাপ্ত ফাইল বর্ণনাকারী একটি সাধারণ চরিত্র ডিভাইস নোড হিসাবে আচরণ করে; ফাইল বর্ণনাকারী:
- প্রয়োজনে নন-ব্লকিং মোডে স্যুইচ করা যেতে পারে
- অন্যদিকে বার্তা প্রেরণের জন্য একটি স্ট্যান্ডার্ড
write()
কল ব্যবহার করে লেখা যেতে পারে - নিয়মিত ফাইল বর্ণনাকারী হিসাবে আগত বার্তাগুলির প্রাপ্যতার জন্য পোল করা (
poll()
কল বাselect()
কলগুলি) ব্যবহার করা যেতে পারে - আগত বার্তাগুলি পুনরুদ্ধার করতে পড়া যেতে পারে
একজন কলার নির্দিষ্ট fd
জন্য একটি রাইটিং কল কার্যকর করে বিশ্বস্ত পরিষেবাতে একটি বার্তা প্রেরণ করে। উপরের write()
কলটিতে পাস করা সমস্ত ডেটা বিশ্বস্ত-আইপিসি ড্রাইভার দ্বারা একটি বার্তায় রূপান্তরিত হয়। বার্তাটি সুরক্ষিত পাশে সরবরাহ করা হয় যেখানে ডেটা ট্রাস্টি কার্নেলের আইপিসি সাবসিস্টেম দ্বারা পরিচালিত হয় এবং যথাযথ গন্তব্যে পৌঁছানো হয় এবং একটি নির্দিষ্ট চ্যানেল হ্যান্ডেলে IPC_HANDLE_POLL_MSG
ইভেন্ট হিসাবে একটি অ্যাপ্লিকেশন ইভেন্ট লুপে সরবরাহ করা হয়। নির্দিষ্ট, পরিষেবা-নির্দিষ্ট প্রোটোকলের উপর নির্ভর করে, বিশ্বস্ত পরিষেবাটি এক বা একাধিক উত্তর বার্তা প্রেরণ করতে পারে যা অ-সুরক্ষিত দিকে ফিরে পৌঁছে দেওয়া হয় এবং ব্যবহারকারী স্পেস অ্যাপ read()
কল।
টিপসি_কনেক্ট ()
একটি নির্দিষ্ট tipc
ডিভাইস নোড খোলে এবং একটি নির্দিষ্ট বিশ্বস্ত পরিষেবার সাথে একটি সংযোগ শুরু করে।
int tipc_connect(const char *dev_name, const char *srv_name);
[ইন] dev_name
: বিশ্বস্ত আইপিসি ডিভাইস নোড খোলার পথ
[ইন] srv_name
: সংযোগ স্থাপনের জন্য প্রকাশিত একটি বিশ্বস্ত পরিষেবাটির নাম
[retval]: সাফল্যের উপর বৈধ ফাইল বর্ণনাকারী, -1 অন্যথায়।
টিপসি_ক্লোজ ()
একটি ফাইল বর্ণনাকারী দ্বারা নির্দিষ্ট করা বিশ্বস্ত পরিষেবার সাথে সংযোগ বন্ধ করে দেয়।
int tipc_close(int fd);
[ইন] fd
: ফাইল বর্ণনাকারী পূর্বে একটি tipc_connect()
কল দ্বারা খোলা
কার্নেল ট্রাস্টি আইপিসি ক্লায়েন্ট এপিআই
কার্নেল ট্রাস্টি আইপিসি ক্লায়েন্ট এপিআই কার্নেল ড্রাইভারদের জন্য উপলব্ধ। ব্যবহারকারী স্পেস ট্রাস্টি আইপিসি এপিআই এই এপিআইয়ের শীর্ষে প্রয়োগ করা হয়েছে।
সাধারণভাবে, এই এপিআইয়ের সাধারণ ব্যবহারের মধ্যে একটি কলার থাকে যা tipc_create_channel()
ফাংশনটি ব্যবহার করে একটি struct tipc_chan
অবজেক্ট তৈরি করে এবং তারপরে tipc_chan_connect()
কলটি ব্যবহার করে সুরক্ষিত পাশে চলমান বিশ্বস্ত আইপিসি পরিষেবার সাথে সংযোগ শুরু করার জন্য কল করে। রিমোট সাইডের সাথে সংযোগটি tipc_chan_shutdown()
এর পরে tipc_chan_destroy()
দ্বারা সংস্থানগুলি পরিষ্কার করার জন্য কল করে বন্ধ করা যেতে পারে।
একটি সংযোগ সফলভাবে প্রতিষ্ঠিত হয়েছে এমন একটি বিজ্ঞপ্তি ( handle_event()
কলব্যাকের মাধ্যমে) পাওয়ার পরে, একজন কলার নিম্নলিখিতটি করেন:
-
tipc_chan_get_txbuf_timeout()
কল ব্যবহার করে একটি বার্তা বাফার প্রাপ্ত করে - একটি বার্তা রচনা, এবং
- একটি বিশ্বস্ত পরিষেবা (সুরক্ষিত দিকে) সরবরাহের জন্য
tipc_chan_queue_msg()
পদ্ধতিটি ব্যবহার করে বার্তাটি সারি করে, যার সাথে চ্যানেলটি সংযুক্ত রয়েছে
সারি সফল হওয়ার পরে, কলারটি বার্তা বাফারটি ভুলে যাওয়া উচিত কারণ বার্তা বাফারটি অবশেষে দূরবর্তী পক্ষের প্রক্রিয়াজাতকরণের পরে ফ্রি বাফার পুলে ফিরে আসে (পরে পুনরায় ব্যবহারের জন্য, অন্যান্য বার্তাগুলির জন্য)। ব্যবহারকারীকে কেবল tipc_chan_put_txbuf()
কল করতে হবে যদি এটি এই জাতীয় বাফারটি সারিবদ্ধ করতে ব্যর্থ হয় বা এটির আর প্রয়োজন হয় না।
একজন এপিআই ব্যবহারকারী একটি handle_msg()
বিজ্ঞপ্তি কলব্যাক (যা বিশ্বস্ত-আইপিসি rx
ওয়ার্ককিউয়ের প্রসঙ্গে বলা হয়) পরিচালনা করে দূরবর্তী পক্ষের বার্তাগুলি গ্রহণ করে যা একটি rx
বাফারের জন্য একটি পয়েন্টার সরবরাহ করে যা একটি আগত বার্তা পরিচালনা করতে পারে।
আশা করা যায় যে handle_msg()
কলব্যাক বাস্তবায়ন একটি বৈধ struct tipc_msg_buf
একটি পয়েন্টার দেয়। এটি স্থানীয়ভাবে পরিচালিত হয় এবং আর প্রয়োজন না হলে এটি আগত বার্তা বাফারের মতো হতে পারে। বিকল্পভাবে, এটি একটি নতুন বাফার হতে পারে একটি tipc_chan_get_rxbuf()
দ্বারা প্রাপ্ত যদি আগত বাফারটি আরও প্রক্রিয়াজাতকরণের জন্য সারি করা হয়। একটি বিচ্ছিন্ন rx
বাফার অবশ্যই ট্র্যাক করা উচিত এবং শেষ পর্যন্ত একটি tipc_chan_put_rxbuf()
কল ব্যবহার করে প্রকাশ করা উচিত যখন এটির আর প্রয়োজন হয় না।
কার্নেল ট্রাস্টি আইপিসি ক্লায়েন্ট এপিআই পদ্ধতি
টিপসি_ক্রিয়েট_চ্যানেল ()
একটি নির্দিষ্ট বিশ্বস্ত-আইপিসি ডিভাইসের জন্য একটি বিশ্বস্ত আইপিসি চ্যানেলের একটি উদাহরণ তৈরি এবং কনফিগার করে।
struct tipc_chan *tipc_create_channel(struct device *dev, const struct tipc_chan_ops *ops, void *cb_arg);
[ইন] dev
: বিশ্বস্ত-আইপিসির জন্য পয়েন্টার যার জন্য ডিভাইস চ্যানেল তৈরি করা হয়েছে
[ইন] ops
: কলার-নির্দিষ্ট কলব্যাকগুলি ভরাট সহ একটি struct tipc_chan_ops
এর পয়েন্টার
[ইন] cb_arg
: tipc_chan_ops
কলব্যাকগুলিতে পাস করা ডেটা পয়েন্টার
[retval]: সাফল্যের উপর struct tipc_chan
একটি নতুন-নির্মিত উদাহরণের জন্য পয়েন্টার, অন্যথায় ERR_PTR(err)
অন্যথায়
সাধারণভাবে, একজন কলারকে অবশ্যই দুটি কলব্যাক সরবরাহ করতে হবে যা সংশ্লিষ্ট ক্রিয়াকলাপটি ঘটলে asynchronsically অনুরোধ করা হয়।
void (*handle_event)(void *cb_arg, int event)
ইভেন্টটি চ্যানেল রাষ্ট্রের পরিবর্তন সম্পর্কে একজন কলকারীকে অবহিত করার জন্য অনুরোধ করা হয়।
[ইন] cb_arg
: একটি tipc_create_channel()
কলটিতে পাস করার জন্য পয়েন্টার
[ইন] event
: এমন একটি ইভেন্ট যা নিম্নলিখিত মানগুলির মধ্যে একটি হতে পারে:
-
TIPC_CHANNEL_CONNECTED
- দূরবর্তী দিকে একটি সফল সংযোগ নির্দেশ করে -
TIPC_CHANNEL_DISCONNECTED
- রিমোট সাইডটি নতুন সংযোগের অনুরোধটি অস্বীকার করেছে বা পূর্বে সংযুক্ত চ্যানেলের জন্য সংযোগ বিচ্ছিন্ন করার জন্য অনুরোধ করেছে -
TIPC_CHANNEL_SHUTDOWN
- প্রত্যন্ত দিকটি বন্ধ হয়ে যাচ্ছে তা নির্দেশ করে, স্থায়ীভাবে সমস্ত সংযোগগুলি সমাপ্ত করে
struct tipc_msg_buf *(*handle_msg)(void *cb_arg, struct tipc_msg_buf *mb)
কলব্যাককে একটি নির্দিষ্ট চ্যানেলের উপর একটি নতুন বার্তা প্রাপ্ত হয়েছে এমন বিজ্ঞপ্তি দেওয়ার জন্য অনুরোধ করা হয়েছে:
- [ইন]
cb_arg
:tipc_create_channel()
কলটিতে পাস করা ডেটা পয়েন্টার - [ইন]
mb
: একটিstruct tipc_msg_buf
পয়েন্টার একটি আগত বার্তা বর্ণনা করে - [retval]: কলব্যাক বাস্তবায়ন একটি
struct tipc_msg_buf
একটি পয়েন্টার ফিরিয়ে দেবে বলে আশা করা হচ্ছে যা যদি বার্তাটি স্থানীয়ভাবে পরিচালনা করা হয় এবং এটি আর প্রয়োজন হয় না (বা এটি একটি নতুন বাফার হতে পারে তবেmb
প্যারামিটার হিসাবে প্রাপ্ত একই পয়েন্টার হতে পারে (বা এটি একটি নতুন বাফার হতে পারেtipc_chan_get_rxbuf()
কল)
টিপসি_চান_কনেক্ট ()
নির্দিষ্ট বিশ্বস্ত আইপিসি পরিষেবার সাথে একটি সংযোগ শুরু করে।
int tipc_chan_connect(struct tipc_chan *chan, const char *port);
[ইন] chan
: tipc_create_chan()
কল দ্বারা ফিরে আসা একটি চ্যানেলের পয়েন্টার
[ইন] port
: সংযোগের জন্য পরিষেবার নাম সম্বলিত একটি স্ট্রিংয়ের পয়েন্টার
[retval]: 0 সাফল্যের উপর, অন্যথায় একটি নেতিবাচক ত্রুটি
handle_event
কলব্যাক পেয়ে কোনও সংযোগ স্থাপন করা হলে কলারকে অবহিত করা হয়।
টিপসি_চান_শুটডাউন ()
পূর্বে tipc_chan_connect()
কল দ্বারা শুরু করা বিশ্বস্ত আইপিসি পরিষেবার সাথে একটি সংযোগ বন্ধ করে দেয়।
int tipc_chan_shutdown(struct tipc_chan *chan);
[ইন] chan
: একটি tipc_create_chan()
কল দ্বারা ফিরে আসা একটি চ্যানেলের পয়েন্টার
টিপসি_চান_ডেস্ট্রয় ()
একটি নির্দিষ্ট বিশ্বস্ত আইপিসি চ্যানেল ধ্বংস করে।
void tipc_chan_destroy(struct tipc_chan *chan);
[ইন] chan
: tipc_create_chan()
কল দ্বারা ফিরে আসা একটি চ্যানেলের পয়েন্টার
TIPC_CHAN_GET_TXBUF_TIMEOUT ()
একটি বার্তা বাফার প্রাপ্ত করে যা নির্দিষ্ট চ্যানেলের মাধ্যমে ডেটা প্রেরণে ব্যবহার করা যেতে পারে। যদি বাফারটি তাত্ক্ষণিকভাবে উপলভ্য না হয় তবে কলার নির্দিষ্ট সময়সীমা (মিলিসেকেন্ডে) এর জন্য অবরুদ্ধ করা যেতে পারে।
struct tipc_msg_buf * tipc_chan_get_txbuf_timeout(struct tipc_chan *chan, long timeout);
[ইন] chan
: চ্যানেলটিতে পয়েন্টার যা একটি বার্তা সারি করতে হবে
[ইন] chan
: tx
বাফার উপলব্ধ না হওয়া পর্যন্ত অপেক্ষা করার সর্বাধিক সময়সীমা
[retval]: সাফল্যের উপর একটি বৈধ বার্তা বাফার, ত্রুটিতে ERR_PTR(err)
টিপসি_চান_কিউ_এমএসজি ()
নির্দিষ্ট বিশ্বস্ত আইপিসি চ্যানেলগুলির উপরে পাঠানোর জন্য একটি বার্তা সারি করে।
int tipc_chan_queue_msg(struct tipc_chan *chan, struct tipc_msg_buf *mb);
[ইন] chan
: বার্তাটি সারি করার জন্য চ্যানেলের পয়েন্টার
[ইন] mb:
কাতারে বার্তায় পয়েন্টার (একটি tipc_chan_get_txbuf_timeout()
কল) দ্বারা প্রাপ্ত
[retval]: 0 সাফল্যের উপর, অন্যথায় একটি নেতিবাচক ত্রুটি
TIPC_CHAN_PUT_TXBUF ()
পূর্বে একটি tipc_chan_get_txbuf_timeout()
কল দ্বারা প্রাপ্ত নির্দিষ্ট Tx
বার্তা বাফার প্রকাশ করে।
void tipc_chan_put_txbuf(struct tipc_chan *chan, struct tipc_msg_buf *mb);
[ইন] chan
: এই বার্তার বাফারটি যে চ্যানেলের সাথে রয়েছে তার পয়েন্টার
[ইন] mb
: মুক্তি পাওয়ার জন্য বার্তা বাফারের পয়েন্টার
[retval]: কিছুই নয়
টিপসি_চান_গেট_আরএক্সবিউফ ()
একটি নতুন বার্তা বাফার প্রাপ্ত করে যা নির্দিষ্ট চ্যানেলের মাধ্যমে বার্তাগুলি পেতে ব্যবহার করা যেতে পারে।
struct tipc_msg_buf *tipc_chan_get_rxbuf(struct tipc_chan *chan);
[ইন] chan
: একটি চ্যানেলের পয়েন্টার যার সাথে এই বার্তা বাফার অন্তর্ভুক্ত
[retval]: সাফল্যের উপর একটি বৈধ বার্তা বাফার, ত্রুটিতে ERR_PTR(err)
TIPC_CHAN_PUT_RXBUF ()
পূর্বে একটি tipc_chan_get_rxbuf()
কল দ্বারা প্রাপ্ত একটি নির্দিষ্ট বার্তা বাফার প্রকাশ করে।
void tipc_chan_put_rxbuf(struct tipc_chan *chan, struct tipc_msg_buf *mb);
[ইন] chan
: একটি চ্যানেলের পয়েন্টার যার সাথে এই বার্তা বাফার অন্তর্ভুক্ত
[ইন] mb
: প্রকাশের জন্য একটি বার্তা বাফারের পয়েন্টার
[retval]: কিছুই নয়