การอ้างอิง API ที่เชื่อถือได้

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, ซึ่งแอปพลิเคชันสามารถใช้เป็นข้อบ่งชี้ว่าหมายเลขอ้างอิงไม่ถูกต้องหรือไม่ได้ตั้งค่า

เชื่อมโยงข้อมูลส่วนตัวของผู้โทรกับหมายเลขอ้างอิงที่ระบุ

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 : ชี้ไปที่บัฟเฟอร์ข้อความที่จะปล่อย

[การกลับรายการ]: ไม่มี