Trusty จัดเตรียม API สำหรับการพัฒนาแอปพลิเคชัน/บริการสองคลาส:
- แอปพลิเคชันหรือบริการที่เชื่อถือได้ซึ่งทำงานบนโปรเซสเซอร์ TEE
- แอปพลิเคชันปกติ/ที่ไม่น่าเชื่อถือซึ่งทำงานบนโปรเซสเซอร์หลักและใช้บริการจากแอปพลิเคชันที่เชื่อถือได้
โดยทั่วไป Trusty API จะอธิบายระบบการสื่อสารระหว่างกระบวนการ (IPC) ของ Trusty รวมถึงการสื่อสารกับโลกที่ไม่ปลอดภัย ซอฟต์แวร์ที่ทำงานบนโปรเซสเซอร์หลักสามารถใช้ Trusty API เพื่อเชื่อมต่อกับแอปพลิเคชัน/บริการที่เชื่อถือได้ และแลกเปลี่ยนข้อความตามอำเภอใจกับแอปพลิเคชันเหล่านั้น เช่นเดียวกับบริการเครือข่ายผ่าน IP ขึ้นอยู่กับแอปพลิเคชันในการกำหนดรูปแบบข้อมูลและความหมายของข้อความเหล่านี้โดยใช้โปรโตคอลระดับแอป การส่งข้อความที่เชื่อถือได้รับประกันโดยโครงสร้างพื้นฐาน Trusty พื้นฐาน (ในรูปแบบของไดรเวอร์ที่ทำงานบนโปรเซสเซอร์หลัก) และการสื่อสารเป็นแบบอะซิงโครนัสโดยสมบูรณ์
พอร์ตและช่องต่างๆ
แอปพลิเคชัน Trusty ใช้พอร์ตเพื่อแสดงจุดสิ้นสุดของบริการในรูปแบบของเส้นทางที่มีชื่อซึ่งไคลเอนต์เชื่อมต่อ ซึ่งให้รหัสบริการแบบสตริงที่เรียบง่ายเพื่อให้ไคลเอ็นต์ใช้งานได้ รูปแบบการตั้งชื่อเป็นแบบ Reverse-DNS เช่น com.google.servicename
เมื่อไคลเอนต์เชื่อมต่อกับพอร์ต ไคลเอนต์จะได้รับช่องทางในการโต้ตอบกับบริการ บริการจะต้องยอมรับการเชื่อมต่อขาเข้า และเมื่อรับแล้ว ก็จะได้รับช่องสัญญาณด้วย โดยพื้นฐานแล้ว พอร์ตต่างๆ จะถูกใช้เพื่อค้นหาบริการ จากนั้นการสื่อสารจะเกิดขึ้นผ่านช่องทางที่เชื่อมต่อกัน (เช่น อินสแตนซ์การเชื่อมต่อบนพอร์ต) เมื่อไคลเอนต์เชื่อมต่อกับพอร์ต การเชื่อมต่อแบบสองทิศทางแบบสมมาตรจะถูกสร้างขึ้น การใช้เส้นทางฟูลดูเพล็กซ์นี้ ไคลเอ็นต์และเซิร์ฟเวอร์สามารถแลกเปลี่ยนข้อความได้ตามใจชอบจนกว่าฝ่ายใดฝ่ายหนึ่งจะตัดสินใจยุติการเชื่อมต่อ
เฉพาะแอปพลิเคชันที่เชื่อถือได้ฝั่งปลอดภัยหรือโมดูลเคอร์เนล Trusty เท่านั้นที่สามารถสร้างพอร์ตได้ แอปพลิเคชันที่ทำงานบนฝั่งที่ไม่ปลอดภัย (ในโลกปกติ) สามารถเชื่อมต่อกับบริการที่เผยแพร่โดยฝั่งที่ปลอดภัยเท่านั้น
แอปพลิเคชันที่เชื่อถือได้สามารถเป็นทั้งไคลเอ็นต์และเซิร์ฟเวอร์พร้อมกันได้ ทั้งนี้ขึ้นอยู่กับข้อกำหนด แอปพลิเคชันที่เชื่อถือได้ซึ่งเผยแพร่บริการ (ในฐานะเซิร์ฟเวอร์) อาจจำเป็นต้องเชื่อมต่อกับบริการอื่น ๆ (ในฐานะไคลเอนต์)
จัดการ API
หมายเลขอ้างอิงเป็นจำนวนเต็มที่ไม่ได้ลงนามซึ่งแสดงถึงทรัพยากร เช่น พอร์ตและช่องสัญญาณ คล้ายกับตัวอธิบายไฟล์ใน UNIX หลังจากสร้างจุดจับแล้ว จะวางลงในตารางจุดจับเฉพาะแอปพลิเคชันและสามารถอ้างอิงได้ในภายหลัง
ผู้เรียกสามารถเชื่อมโยงข้อมูลส่วนตัวกับหมายเลขอ้างอิงได้โดยใช้เมธอด set_cookie()
วิธีการใน Handle API
หมายเลขอ้างอิงใช้ได้เฉพาะในบริบทของแอปพลิเคชันเท่านั้น แอปพลิเคชันไม่ควรส่งค่าของตัวจัดการไปยังแอปพลิเคชันอื่นเว้นแต่จะระบุไว้อย่างชัดเจน ควรตีความค่าที่จับเท่านั้นโดยเปรียบเทียบกับ INVALID_IPC_HANDLE #define,
ซึ่งแอปพลิเคชันสามารถใช้เป็นข้อบ่งชี้ว่าหมายเลขอ้างอิงไม่ถูกต้องหรือไม่ได้ตั้งค่า
set_cookie()
เชื่อมโยงข้อมูลส่วนตัวของผู้โทรกับหมายเลขอ้างอิงที่ระบุ
long set_cookie(uint32_t handle, void *cookie)
[in] handle
: หมายเลขอ้างอิงใด ๆ ที่ส่งคืนโดยการเรียก API รายการใดรายการหนึ่ง
cookie
[ใน] : ตัวชี้ไปยังข้อมูลพื้นที่ผู้ใช้ที่กำหนดเองในแอปพลิเคชัน Trusty
[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);
[ใน] handle_id
: จัดการเพื่อทำลาย
[retval]: 0 ถ้าสำเร็จ; ข้อผิดพลาดเชิงลบเป็นอย่างอื่น
เซิร์ฟเวอร์ API
เซิร์ฟเวอร์เริ่มต้นด้วยการสร้าง พอร์ตที่มีชื่อ ตั้งแต่หนึ่งพอร์ตขึ้นไปซึ่งแสดงถึงจุดสิ้นสุดการบริการ แต่ละพอร์ตจะแสดงด้วยหมายเลขอ้างอิง
วิธีการใน Server API
พอร์ต_สร้าง()
สร้างพอร์ตบริการที่มีชื่อ
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()
เมื่อได้รับการร้องขอการเชื่อมต่อที่ระบุโดยบิต IPC_HANDLE_POLL_READY
ที่ตั้งค่าไว้ในฟิลด์ event
ของโครงสร้าง uevent_t
เซิร์ฟเวอร์ควรเรียก accept()
เพื่อเสร็จสิ้นการสร้างการเชื่อมต่อและสร้างช่องทาง (แสดงโดยหมายเลขอ้างอิงอื่น) ที่สามารถสำรวจข้อความขาเข้าได้ .
ยอมรับ()
ยอมรับการเชื่อมต่อขาเข้าและได้รับการจัดการกับช่องสัญญาณ
long accept(uint32_t handle_id, uuid_t *peer_uuid);
[ใน] handle_id
: หมายเลขอ้างอิงที่แสดงถึงพอร์ตที่ไคลเอ็นต์เชื่อมต่ออยู่
[ออก] peer_uuid
: ตัวชี้ไปยังโครงสร้าง uuid_t
ที่จะเต็มไปด้วย UUID ของแอปพลิเคชันไคลเอนต์ที่เชื่อมต่อ มันจะถูกตั้งค่าเป็นศูนย์ทั้งหมดหากการเชื่อมต่อมาจากโลกที่ไม่ปลอดภัย
[retval]: จัดการกับช่องทาง (หากไม่เป็นลบ) ซึ่งเซิร์ฟเวอร์สามารถแลกเปลี่ยนข้อความกับไคลเอนต์ (หรือรหัสข้อผิดพลาดอย่างอื่น)
API ของไคลเอ็นต์
ส่วนนี้ประกอบด้วยวิธีการใน Client API
วิธีการใน Client API
เชื่อมต่อ()
เริ่มต้นการเชื่อมต่อกับพอร์ตที่ระบุตามชื่อ
long connect(const char *path, uint flags);
[ใน] path
: ชื่อของพอร์ตที่เผยแพร่โดยแอปพลิเคชัน Trusty
[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
- หากตั้งค่าไว้ ให้เริ่มการเชื่อมต่อแบบอะซิงโครนัส แอปพลิเคชันต้องสำรวจหาหมายเลขอ้างอิงที่ส่งคืน (โดยการเรียก wait()
สำหรับเหตุการณ์การเชื่อมต่อเสร็จสมบูรณ์ที่ระบุโดยบิต IPC_HANDLE_POLL_READY
ที่ตั้งค่าไว้ในฟิลด์เหตุการณ์ของโครงสร้าง uevent_t
ก่อนที่จะเริ่มการทำงานตามปกติ
API การส่งข้อความ
การเรียก Messaging API ช่วยให้สามารถส่งและอ่านข้อความผ่านการเชื่อมต่อ (ช่องทาง) ที่สร้างไว้ก่อนหน้านี้ การเรียก Messaging API จะเหมือนกันสำหรับเซิร์ฟเวอร์และไคลเอนต์
ลูกค้าได้รับหมายเลขอ้างอิงของช่องสัญญาณโดยการโทร connect()
และเซิร์ฟเวอร์ได้รับหมายเลขอ้างอิงช่องสัญญาณจากการโทร accept()
ตามที่อธิบายไว้ข้างต้น
โครงสร้างของข้อความที่เชื่อถือได้
ดังที่แสดงไว้ต่อไปนี้ ข้อความที่แลกเปลี่ยนโดย Trusty 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
Trusty ดำเนินการอ่านและเขียนแบบกระจายรวบรวมลงในบล็อกเหล่านี้โดยใช้อาร์เรย์ iov
เนื้อหาของบัฟเฟอร์ที่สามารถอธิบายได้โดยอาร์เรย์ iov
นั้นขึ้นอยู่กับอำเภอใจโดยสมบูรณ์
วิธีการใน Messaging 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
ในกรณีเช่นนี้ ผู้เรียกต้องรอจนกว่าเพียร์จะมีพื้นที่ว่างในคิวการรับโดยการเรียกข้อมูลการจัดการและการยกเลิกข้อความ ซึ่งระบุโดยบิต IPC_HANDLE_POLL_SEND_UNBLOCKED
ที่ตั้งค่าไว้ในฟิลด์ event
ของโครงสร้าง uevent_t
ที่ส่งคืนโดยการเรียก wait()
get_msg()
รับข้อมูลเมตาเกี่ยวกับข้อความถัดไปในคิวข้อความขาเข้า
ของช่องที่กำหนด
long get_msg(uint32_t handle, ipc_msg_info_t *msg_info);
[in] handle
: หมายเลขอ้างอิงของช่องสัญญาณที่ต้องดึงข้อความใหม่
[ออก] msg_info
: โครงสร้างข้อมูลข้อความอธิบายดังนี้:
typedef struct ipc_msg_info { size_t len; /* total message length */ uint32_t id; /* message id */ } ipc_msg_info_t;
แต่ละข้อความจะได้รับการกำหนด ID ที่ไม่ซ้ำกันให้กับชุดข้อความที่ค้างอยู่ และความยาวรวมของแต่ละข้อความจะถูกกรอก หากโปรโตคอลกำหนดค่าและอนุญาต อาจมีข้อความที่ค้างอยู่ (เปิด) หลายข้อความพร้อมกันสำหรับช่องใดช่องหนึ่งโดยเฉพาะ
[retval]: NO_ERROR
เมื่อสำเร็จ ข้อผิดพลาดเชิงลบเป็นอย่างอื่น
read_msg()
อ่านเนื้อหาของข้อความด้วย ID ที่ระบุโดยเริ่มจากออฟเซ็ตที่ระบุ
long read_msg(uint32_t handle, uint32_t msg_id, uint32_t offset, ipc_msg_t *msg);
[in] handle
: จัดการกับช่องทางที่จะอ่านข้อความ
[ใน] msg_id
: ID ของข้อความที่จะอ่าน
[in] offset
: ชดเชยข้อความที่จะเริ่มอ่าน
[ออก] msg
: ตัวชี้ไปยังโครงสร้าง ipc_msg_t
ที่อธิบายชุดบัฟเฟอร์ที่ใช้เก็บข้อมูลข้อความขาเข้า
[retval]: จำนวนไบต์ทั้งหมดที่จัดเก็บไว้ในบัฟเฟอร์ msg
เมื่อสำเร็จ ข้อผิดพลาดเชิงลบเป็นอย่างอื่น
สามารถเรียกเมธอด read_msg
ได้หลายครั้ง โดยเริ่มต้นที่ออฟเซ็ตอื่น (ไม่จำเป็นต้องเรียงลำดับ) ตามความต้องการ
put_msg()
เลิกใช้ข้อความที่มี ID ที่ระบุ
long put_msg(uint32_t handle, uint32_t msg_id);
[in] handle
: หมายเลขอ้างอิงของช่องทางที่ข้อความมาถึง
[ใน] msg_id
: ID ของข้อความที่ถูกยกเลิก
[retval]: NO_ERROR
เมื่อสำเร็จ ข้อผิดพลาดเชิงลบเป็นอย่างอื่น
ไม่สามารถเข้าถึงเนื้อหาข้อความได้หลังจากที่ข้อความถูกยกเลิกและบัฟเฟอร์ที่ครอบครองถูกปลดปล่อยแล้ว
API ตัวอธิบายไฟล์
File Descriptor API ประกอบด้วยการเรียก read()
, write()
และ ioctl()
การเรียกทั้งหมดนี้สามารถดำเนินการกับชุดตัวอธิบายไฟล์ที่กำหนดไว้ล่วงหน้า (คงที่) ซึ่งโดยปกติแล้วจะแสดงด้วยตัวเลขขนาดเล็ก ในการใช้งานปัจจุบัน พื้นที่ตัวอธิบายไฟล์จะแยกจากพื้นที่การจัดการ IPC File Descriptor API ใน Trusty นั้นคล้ายคลึงกับ API ที่ใช้ file descriptor แบบดั้งเดิม
ตามค่าเริ่มต้น จะมีตัวอธิบายไฟล์ที่กำหนดไว้ล่วงหน้า 3 ตัว (มาตรฐานและเป็นที่รู้จัก):
- 0 - อินพุตมาตรฐาน การใช้งานค่าเริ่มต้นของอินพุตมาตรฐาน
fd
คือ no-op (เนื่องจากแอปพลิเคชันที่เชื่อถือได้ไม่คาดว่าจะมีคอนโซลแบบโต้ตอบ) ดังนั้นการอ่าน การเขียน หรือการเรียกใช้ioctl()
บนfd
0 ควรส่งคืนข้อผิดพลาดERR_NOT_SUPPORTED
- 1 - เอาต์พุตมาตรฐาน ข้อมูลที่เขียนไปยังเอาต์พุตมาตรฐานสามารถกำหนดเส้นทางได้ (ขึ้นอยู่กับระดับการดีบัก LK) ไปยัง UART และ/หรือบันทึกหน่วยความจำที่มีอยู่บนฝั่งที่ไม่ปลอดภัย ขึ้นอยู่กับแพลตฟอร์มและการกำหนดค่า บันทึกและข้อความการแก้ไขข้อบกพร่องที่ไม่สำคัญควรอยู่ในเอาต์พุตมาตรฐาน เมธอด
read()
และioctl()
เป็นแบบ no-ops และควรส่งคืนข้อผิดพลาดERR_NOT_SUPPORTED
- 2 - ข้อผิดพลาดมาตรฐาน ข้อมูลที่เขียนไปยังข้อผิดพลาดมาตรฐานควรถูกกำหนดเส้นทางไปยัง UART หรือบันทึกหน่วยความจำที่มีอยู่ในด้านที่ไม่ปลอดภัย ขึ้นอยู่กับแพลตฟอร์มและการกำหนดค่า ขอแนะนำให้เขียนเฉพาะข้อความสำคัญถึงข้อผิดพลาดมาตรฐาน เนื่องจากสตรีมนี้มีแนวโน้มที่จะไม่ถูกควบคุม เมธอด
read()
และioctl()
เป็นแบบ no-ops และควรส่งคืนข้อผิดพลาดERR_NOT_SUPPORTED
แม้ว่าชุดคำอธิบายไฟล์นี้สามารถขยายเพื่อใช้ fds
ได้มากขึ้น (เพื่อใช้ส่วนขยายเฉพาะแพลตฟอร์ม แต่การขยายคำอธิบายไฟล์จำเป็นต้องใช้ด้วยความระมัดระวัง การขยายคำอธิบายไฟล์มีแนวโน้มที่จะสร้างข้อขัดแย้ง และไม่แนะนำโดยทั่วไป
วิธีการใน File Descriptor API
อ่าน()
พยายามอ่านข้อมูลจน count
จำนวนไบต์จากตัวอธิบายไฟล์ที่ระบุ
long read(uint32_t fd, void *buf, uint32_t count);
[in] fd
: File descriptor ที่จะอ่าน
[ออก] buf
: ตัวชี้ไปยังบัฟเฟอร์ที่จะจัดเก็บข้อมูล
[in] count
: จำนวนไบต์สูงสุดที่จะอ่าน
[retval]: ส่งกลับจำนวนไบต์ที่อ่าน; ข้อผิดพลาดเชิงลบเป็นอย่างอื่น
เขียน()
เขียนข้อมูลได้ถึง count
ไบต์ไปยังตัวอธิบายไฟล์ที่ระบุ
long write(uint32_t fd, void *buf, uint32_t count);
[in] fd
: File descriptor ที่จะเขียน
[out] buf
: ตัวชี้ไปยังข้อมูลที่จะเขียน
[in] count
: จำนวนไบต์สูงสุดที่จะเขียน
[retval]: ส่งกลับจำนวนไบต์ที่เขียน; ข้อผิดพลาดเชิงลบเป็นอย่างอื่น
ioctl()
เรียกใช้คำสั่ง ioctl
ที่ระบุสำหรับตัวอธิบายไฟล์ที่กำหนด
long ioctl(uint32_t fd, uint32_t cmd, void *args);
[in] fd
: ตัวอธิบายไฟล์ที่จะเรียกใช้ ioctl()
[ใน] cmd
: คำสั่ง ioctl
[in/out] args
: ตัวชี้ไปยังอาร์กิวเมนต์ ioctl()
API เบ็ดเตล็ด
วิธีการในเบ็ดเตล็ด API
เวลาที่ได้รับ()
ส่งกลับเวลาระบบปัจจุบัน (เป็นนาโนวินาที)
long gettime(uint32_t clock_id, uint32_t flags, int64_t *time);
[ใน] clock_id
: ขึ้นอยู่กับแพลตฟอร์ม; ผ่านศูนย์สำหรับค่าเริ่มต้น
[in] flags
: สงวนไว้ ควรเป็นศูนย์
time
[ออก] : ตัวชี้ไปที่ค่า int64_t
ที่จะจัดเก็บเวลาปัจจุบัน
[retval]: NO_ERROR
เมื่อสำเร็จ ข้อผิดพลาดเชิงลบเป็นอย่างอื่น
นาโนสลีป()
ระงับการดำเนินการแอปพลิเคชันที่เรียกในช่วงระยะเวลาที่กำหนดและดำเนินการต่อหลังจากช่วงระยะเวลานั้น
long nanosleep(uint32_t clock_id, uint32_t flags, uint64_t sleep_time)
[ใน] clock_id
: สงวนไว้ ควรเป็นศูนย์
[in] flags
: สงวนไว้ ควรเป็นศูนย์
[ใน] sleep_time
: เวลาพักเครื่องในหน่วยนาโนวินาที
[retval]: NO_ERROR
เมื่อสำเร็จ ข้อผิดพลาดเชิงลบเป็นอย่างอื่น
ตัวอย่างของแอปพลิเคชันเซิร์ฟเวอร์ที่เชื่อถือได้
แอปพลิเคชันตัวอย่างต่อไปนี้แสดงการใช้งาน API ข้างต้น ตัวอย่างจะสร้างบริการ "echo" ที่จัดการการเชื่อมต่อขาเข้าหลายรายการ และสะท้อนกลับไปยังผู้โทร ข้อความทั้งหมดที่ได้รับจากไคลเอ็นต์ที่มาจากฝั่งที่ปลอดภัยหรือไม่ปลอดภัย
#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 application 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 ข้อความแบบอะซิงโครนัสไปยังบริการ "echo" และจัดการการตอบกลับ
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 และแอปพลิเคชันโลกที่ไม่ปลอดภัย
ชุดบริการ Trusty ที่เผยแพร่จากฝั่งที่ปลอดภัยและทำเครื่องหมายด้วยแอตทริบิวต์ IPC_PORT_ALLOW_NS_CONNECT
สามารถเข้าถึงได้โดยเคอร์เนลและโปรแกรมพื้นที่ผู้ใช้ที่ทำงานบนฝั่งที่ไม่ปลอดภัย
สภาพแวดล้อมการดำเนินการบนฝั่งที่ไม่ปลอดภัย (เคอร์เนลและพื้นที่ผู้ใช้) แตกต่างอย่างมากจากสภาพแวดล้อมการดำเนินการบนฝั่งที่ปลอดภัย ดังนั้น แทนที่จะเป็นไลบรารีเดียวสำหรับทั้งสองสภาพแวดล้อม มีชุด API สองชุดที่แตกต่างกัน ในเคอร์เนล Client API จัดทำโดยไดรเวอร์เคอร์เนล trusty-ipc และลงทะเบียนโหนดอุปกรณ์แบบอักขระที่กระบวนการพื้นที่ผู้ใช้สามารถใช้เพื่อสื่อสารกับบริการที่ทำงานบนฝั่งที่ปลอดภัย
พื้นที่ผู้ใช้ Trusty IPC Client API
ไลบรารี Trusty IPC Client API ของพื้นที่ผู้ใช้เป็นชั้นบางๆ ที่ด้านบนของโหนดอุปกรณ์ fd
โปรแกรมพื้นที่ผู้ใช้เริ่มต้นเซสชันการสื่อสารโดยการเรียก tipc_connect()
เพื่อเริ่มต้นการเชื่อมต่อกับบริการ Trusty ที่ระบุ ภายใน การเรียก 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()
เพื่อความพร้อมใช้งานของข้อความขาเข้าในฐานะตัวอธิบายไฟล์ปกติ - สามารถอ่านเพื่อดึงข้อความที่เข้ามาได้
ผู้โทรส่งข้อความไปยังบริการ Trusty โดยดำเนินการเขียนการโทรสำหรับ fd
ที่ระบุ ข้อมูลทั้งหมดที่ส่งผ่านไปยังการเรียก write()
ข้างต้นจะถูกแปลงเป็นข้อความโดยไดรเวอร์ trusty-ipc ข้อความจะถูกส่งไปยังฝั่งที่ปลอดภัยโดยที่ข้อมูลได้รับการจัดการโดยระบบย่อย IPC ในเคอร์เนล Trusty และกำหนดเส้นทางไปยังปลายทางที่เหมาะสม และส่งไปยังลูปเหตุการณ์ของแอพเป็นเหตุการณ์ IPC_HANDLE_POLL_MSG
บนตัวจัดการช่องทางเฉพาะ ขึ้นอยู่กับโปรโตคอลเฉพาะบริการเฉพาะ บริการ Trusty อาจส่งข้อความตอบกลับอย่างน้อยหนึ่งข้อความที่ส่งกลับไปยังฝั่งที่ไม่ปลอดภัยและวางไว้ในคิวข้อความตัวอธิบายไฟล์ช่องสัญญาณที่เหมาะสมเพื่อดึงข้อมูลโดยแอปพลิเคชันพื้นที่ผู้ใช้ read()
เรียก.
tipc_connect()
เปิดโหนดอุปกรณ์ tipc
ที่ระบุ และเริ่มการเชื่อมต่อกับบริการ Trusty ที่ระบุ
int tipc_connect(const char *dev_name, const char *srv_name);
[ใน] dev_name
: เส้นทางไปยังโหนดอุปกรณ์ Trusty IPC ที่จะเปิด
[ใน] srv_name
: ชื่อของบริการ Trusty ที่เผยแพร่เพื่อเชื่อมต่อ
[retval]: ตัวอธิบายไฟล์ที่ถูกต้องเมื่อสำเร็จ -1 มิฉะนั้น
tipc_close()
ปิดการเชื่อมต่อกับบริการ Trusty ที่ระบุโดยตัวอธิบายไฟล์
int tipc_close(int fd);
[in] fd
: ตัวอธิบายไฟล์ที่เปิดก่อนหน้านี้โดยการเรียก tipc_connect()
API ไคลเอ็นต์ IPC ของเคอร์เนล Trusty
เคอร์เนล Trusty IPC Client API พร้อมใช้งานสำหรับไดรเวอร์เคอร์เนล พื้นที่ผู้ใช้ Trusty IPC API ถูกนำมาใช้ที่ด้านบนของ API นี้
โดยทั่วไป การใช้งาน API นี้โดยทั่วไปประกอบด้วยผู้เรียกที่สร้างอ็อบเจ็กต์ struct tipc_chan
โดยใช้ฟังก์ชัน tipc_create_channel()
จากนั้นใช้การเรียก tipc_chan_connect()
เพื่อเริ่มต้นการเชื่อมต่อกับบริการ Trusty IPC ที่ทำงานบนฝั่งที่ปลอดภัย การเชื่อมต่อกับฝั่งระยะไกลสามารถยุติได้โดยการเรียก tipc_chan_shutdown()
ตามด้วย tipc_chan_destroy()
เพื่อล้างข้อมูลทรัพยากร
เมื่อได้รับการแจ้งเตือน (ผ่านทาง handle_event()
โทรกลับ) ว่าการเชื่อมต่อได้สำเร็จแล้ว ผู้โทรจะดำเนินการดังต่อไปนี้:
- รับบัฟเฟอร์ข้อความโดยใช้การเรียก
tipc_chan_get_txbuf_timeout()
- เขียนข้อความและ
- จัดคิวข้อความโดยใช้เมธอด
tipc_chan_queue_msg()
เพื่อส่งไปยังบริการ Trusty (ในฝั่งที่ปลอดภัย) ซึ่งมีการเชื่อมต่อช่องสัญญาณอยู่
หลังจากการเข้าคิวสำเร็จ ผู้โทรควรลืมบัฟเฟอร์ข้อความ เนื่องจากในที่สุดบัฟเฟอร์ข้อความจะกลับสู่พูลบัฟเฟอร์ว่างหลังจากประมวลผลโดยฝั่งรีโมต (สำหรับการใช้ซ้ำในภายหลัง สำหรับข้อความอื่น) ผู้ใช้จำเป็นต้องเรียก tipc_chan_put_txbuf()
เท่านั้น หากไม่สามารถจัดคิวบัฟเฟอร์ดังกล่าวได้ หรือไม่จำเป็นอีกต่อไป
ผู้ใช้ API ได้รับข้อความจากระยะไกลโดยจัดการการเรียกกลับการแจ้งเตือน handle_msg()
(ซึ่งถูกเรียกในบริบทของคิวงาน trusty-ipc rx
) ที่ให้ตัวชี้ไปยังบัฟเฟอร์ rx
ที่มีข้อความขาเข้าที่จะจัดการ
คาดว่าการใช้งานการเรียกกลับ handle_msg()
จะส่งคืนตัวชี้ไปยัง struct tipc_msg_buf
ที่ถูกต้อง อาจเหมือนกับบัฟเฟอร์ข้อความขาเข้าหากมีการจัดการภายในเครื่องและไม่จำเป็นต้องใช้อีกต่อไป อีกทางหนึ่ง อาจเป็นบัฟเฟอร์ใหม่ที่ได้รับจากการเรียก tipc_chan_get_rxbuf()
หากบัฟเฟอร์ขาเข้าถูกเข้าคิวเพื่อการประมวลผลเพิ่มเติม บัฟเฟอร์ rx
ที่แยกออกจะต้องถูกติดตามและปล่อยออกมาในที่สุดโดยใช้การเรียก tipc_chan_put_rxbuf()
เมื่อไม่ต้องการอีกต่อไป
วิธีการใน Kernel Trusty IPC Client API
tipc_create_channel()
สร้างและกำหนดค่าอินสแตนซ์ของช่อง Trusty IPC สำหรับอุปกรณ์ trusty-ipc โดยเฉพาะ
struct tipc_chan *tipc_create_channel(struct device *dev, const struct tipc_chan_ops *ops, void *cb_arg);
[in] dev
: ตัวชี้ไปที่ trusty-ipc ที่สร้างช่องอุปกรณ์
[in] ops
: ตัวชี้ไปที่ struct tipc_chan_ops
โดยกรอกการโทรกลับเฉพาะผู้โทร
[ใน] 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()
เริ่มต้นการเชื่อมต่อกับบริการ Trusty IPC ที่ระบุ
int tipc_chan_connect(struct tipc_chan *chan, const char *port);
[in] chan
: ตัวชี้ไปยังช่องที่ส่งคืนโดยการเรียก tipc_create_chan()
port
[ใน] : ตัวชี้ไปยังสตริงที่มีชื่อบริการที่จะเชื่อมต่อ
[retval]: 0 เมื่อสำเร็จ มิฉะนั้นจะเกิดข้อผิดพลาดเชิงลบ
ผู้โทรจะได้รับแจ้งเมื่อมีการเชื่อมต่อโดยรับการเรียกกลับ handle_event
tipc_chan_shutdown()
ยุติการเชื่อมต่อกับบริการ Trusty IPC ที่เริ่มต้นก่อนหน้านี้โดยการเรียก tipc_chan_connect()
int tipc_chan_shutdown(struct tipc_chan *chan);
[in] chan
: ตัวชี้ไปยังช่องที่ส่งคืนโดยการเรียก tipc_create_chan()
tipc_chan_destroy()
ทำลายช่อง Trusty 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()
จัดคิวข้อความที่จะส่งผ่านช่องทาง Trusty IPC ที่ระบุ
int tipc_chan_queue_msg(struct tipc_chan *chan, struct tipc_msg_buf *mb);
[in] chan
: ตัวชี้ไปยังช่องทางที่จะจัดคิวข้อความ
[ใน] mb:
ตัวชี้ไปยังข้อความไปยังคิว (ได้รับจากการโทร tipc_chan_get_txbuf_timeout()
)
[retval]: 0 เมื่อสำเร็จ มิฉะนั้นจะเกิดข้อผิดพลาดเชิงลบ
tipc_chan_put_txbuf()
เผยแพร่บัฟเฟอร์ข้อความ Tx
ที่ระบุซึ่งได้รับก่อนหน้านี้โดยการเรียก tipc_chan_get_txbuf_timeout()
void tipc_chan_put_txbuf(struct tipc_chan *chan, struct tipc_msg_buf *mb);
[in] chan
: ชี้ไปยังช่องสัญญาณที่มีบัฟเฟอร์ข้อความนี้อยู่
[in] mb
: ชี้ไปที่บัฟเฟอร์ข้อความที่จะปล่อย
[การกลับรายการ]: ไม่มี
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
: ชี้ไปที่บัฟเฟอร์ข้อความที่จะปล่อย
[การกลับรายการ]: ไม่มี