blob: 024f99a0567f9cd5d9a6a56b7c71a787d9ba4877 [file] [log] [blame]
Daogao Xu8c513c12019-05-22 10:51:06 +08001/*
2 * Copyright (C) 2014-2019 Amlogic, Inc. All rights reserved.
3 *
4 * All information contained herein is Amlogic confidential.
5 *
6 * This software is provided to you pursuant to Software License Agreement
7 * (SLA) with Amlogic Inc ("Amlogic"). This software may be used
8 * only in accordance with the terms of this agreement.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification is strictly prohibited without prior written permission from
12 * Amlogic.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
17 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
18 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
19 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
20 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
Daogao Xuf5aa4ad2019-05-16 16:05:56 +080027#include <stdio.h>
28#include <stdlib.h>
29#include <string.h>
30#include <errno.h>
31#include <unistd.h>
32#include <sys/socket.h>
33#include <sys/un.h>
34#include <sys/types.h>
35#include <arpa/inet.h>
36
37#ifndef SOCKETIPC_H
38
39#define SOCKETIPC_H
40
41#include <stdarg.h>
42#include <stdint.h>
Daogao Xua0c9ee62019-07-30 17:20:51 +080043#include <stddef.h>
Daogao Xuf5aa4ad2019-05-16 16:05:56 +080044
45#ifdef __cplusplus
46extern "C" {
47#endif
48
49/*
50 * a lightweight IPC API implemented in a signel header file
51 *
52 * use DECLARE_IPC_FUNCTION to define the IPC function prototype and IPC stub
53 * code i.e. below code will define an IPC call "foo" which takes two parameters
54 * typed as int32_t and int64_t:
55 * DECLARE_IPC_FUNCTION(foo,int32_t, int64_t)
56 *
57 * internally it will declare "call_foo" C API so you can call this function on
58 * an opened IPC channel, The stub code is generated when SIPC_IMPLEMENTATION is
59 * defined, SIPC_IMPLEMENTATION shall be defined in one of your C code before
60 * including this file
61 *
62 * On the peer side, use EXPORT_IPC_FUNCTION to generate stub code for the IPC
63 * call handle:
64 * EXPORT_IPC_FUNCTION(foo,int32_t, int64_t)
65 *
66 * IPC calls are asynchronous, calls can be make on any thread, the IPC stub
67 * code will place an dgram on the socket, the data will transfer to peer, and
68 * received by ipc_socket_handle in peer application, it then dispatch the call
69 * and call "on_foo"
70 *
71 */
72
73/*
74 * define the IPC type and C type mapping
75 * this IPC library is UDP/unix socket based, it is meant to communicate
76 * accross different host, so don't use those types whose length depends on ARCH
77 * and compiler, such as int, long, use int32_t, int64_t instead
78 */
79// build-in types
Daogao Xua0c9ee62019-07-30 17:20:51 +080080#define SIPC_DEFINE_TYPE_i8 (int),0x01
81#define SIPC_DEFINE_TYPE_u8 (int),0x02
82#define SIPC_DEFINE_TYPE_i16 (int),0x03
83#define SIPC_DEFINE_TYPE_u16 (int),0x04
84#define SIPC_DEFINE_TYPE_i32 (int32_t),0x05
85#define SIPC_DEFINE_TYPE_u32 (uint32_t),0x06
86#define SIPC_DEFINE_TYPE_i64 (int64_t),0x07
87#define SIPC_DEFINE_TYPE_u64 (uint64_t),0x08
88#define SIPC_DEFINE_TYPE_str (char*),0x09
89#define SIPC_DEFINE_TYPE_ptr (void*,int32_t),0x0a
Daogao Xuf5aa4ad2019-05-16 16:05:56 +080090
91// type alias
92#define SIPC_DEFINE_TYPE_int8_t SIPC_DEFINE_TYPE_i8
93#define SIPC_DEFINE_TYPE_char SIPC_DEFINE_TYPE_i8
94#define SIPC_DEFINE_TYPE_uint8_t SIPC_DEFINE_TYPE_u8
95#define SIPC_DEFINE_TYPE_uchar SIPC_DEFINE_TYPE_u8
96#define SIPC_DEFINE_TYPE_byte SIPC_DEFINE_TYPE_u8
97#define SIPC_DEFINE_TYPE_int32_t SIPC_DEFINE_TYPE_i32
98#define SIPC_DEFINE_TYPE_uint32_t SIPC_DEFINE_TYPE_u32
99#define SIPC_DEFINE_TYPE_int64_t SIPC_DEFINE_TYPE_i64
100#define SIPC_DEFINE_TYPE_uint64_t SIPC_DEFINE_TYPE_u64
101
102
103#define MACRO_CAT(a,...) a ## __VA_ARGS__
104#define MACRO_CAT2(a,...) MACRO_CAT(a,__VA_ARGS__)
105#define MACRO_EMPTY(...)
106#define MACRO_CALL(M,...) M(__VA_ARGS__)
107#define EXPR(...) __VA_ARGS__
108
109#define MACRO_GET_16(dummy,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,...) _16
110#define MACRO_NARG(...) MACRO_GET_16(dummy,##__VA_ARGS__,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0)
111
112#define SIPC_TYPE_CTYPE(t) MACRO_CALL(MACRO_GET_16,dummy,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,SIPC_DEFINE_TYPE_##t)
113#define SIPC_TYPE_ID(t) MACRO_CALL(MACRO_GET_16,dummy,1,2,3,4,5,6,7,8,9,10,11,12,13,14,SIPC_DEFINE_TYPE_##t)
Daogao Xuf5aa4ad2019-05-16 16:05:56 +0800114
115#define MACRO_RECURSE_0(I,E,...)
116#define MACRO_RECURSE_1(I,E,_1,...) E(_1)
117#define MACRO_RECURSE_2(I,E,_1,...) I(_1,##__VA_ARGS__) MACRO_RECURSE_1(I,E,##__VA_ARGS__)
118#define MACRO_RECURSE_3(I,E,_1,...) I(_1,##__VA_ARGS__) MACRO_RECURSE_2(I,E,##__VA_ARGS__)
119#define MACRO_RECURSE_4(I,E,_1,...) I(_1,##__VA_ARGS__) MACRO_RECURSE_3(I,E,##__VA_ARGS__)
120#define MACRO_RECURSE_5(I,E,_1,...) I(_1,##__VA_ARGS__) MACRO_RECURSE_4(I,E,##__VA_ARGS__)
121#define MACRO_RECURSE_6(I,E,_1,...) I(_1,##__VA_ARGS__) MACRO_RECURSE_5(I,E,##__VA_ARGS__)
122#define MACRO_RECURSE_7(I,E,_1,...) I(_1,##__VA_ARGS__) MACRO_RECURSE_6(I,E,##__VA_ARGS__)
123#define MACRO_RECURSE_8(I,E,_1,...) I(_1,##__VA_ARGS__) MACRO_RECURSE_7(I,E,##__VA_ARGS__)
124#define MACRO_RECURSE_9(I,E,_1,...) I(_1,##__VA_ARGS__) MACRO_RECURSE_8(I,E,##__VA_ARGS__)
125#define MACRO_RECURSE_10(I,E,_1,...) I(_1,##__VA_ARGS__) MACRO_RECURSE_9(I,E,##__VA_ARGS__)
126#define MACRO_RECURSE_11(I,E,_1,...) I(_1,##__VA_ARGS__) MACRO_RECURSE_10(I,E,##__VA_ARGS__)
127#define MACRO_RECURSE_12(I,E,_1,...) I(_1,##__VA_ARGS__) MACRO_RECURSE_11(I,E,##__VA_ARGS__)
128#define MACRO_RECURSE_13(I,E,_1,...) I(_1,##__VA_ARGS__) MACRO_RECURSE_12(I,E,##__VA_ARGS__)
129#define MACRO_RECURSE_14(I,E,_1,...) I(_1,##__VA_ARGS__) MACRO_RECURSE_13(I,E,##__VA_ARGS__)
130#define MACRO_RECURSE_15(I,E,_1,...) I(_1,##__VA_ARGS__) MACRO_RECURSE_14(I,E,##__VA_ARGS__)
131#define MACRO_RECURSE_16(I,E,_1,...) I(_1,##__VA_ARGS__) MACRO_RECURSE_15(I,E,##__VA_ARGS__)
132#define MACRO_RECURSE_17(I,E,_1,...) I(_1,##__VA_ARGS__) MACRO_RECURSE_16(I,E,##__VA_ARGS__)
133
134#define MACRO_MAP(M,...) MACRO_CAT2(MACRO_RECURSE_,MACRO_NARG(__VA_ARGS__))(M,M,##__VA_ARGS__)
135
136#define SIPC_GEN_CTYPE_EXPR1(...) __VA_ARGS__
137#define SIPC_GEN_CTYPE_EXPR2(...) __VA_ARGS__
138#define SIPC_GEN_CTYPE_E(a,...) SIPC_GEN_CTYPE_EXPR2(SIPC_GEN_CTYPE_EXPR1 SIPC_TYPE_CTYPE(a))
139#define SIPC_GEN_CTYPE_I(a,...) SIPC_GEN_CTYPE_EXPR2(SIPC_GEN_CTYPE_EXPR1 SIPC_TYPE_CTYPE(a)),
140#define SIPC_EXPAND_CTYPE_LIST(...) MACRO_CAT2(MACRO_RECURSE_,MACRO_NARG(__VA_ARGS__))(SIPC_GEN_CTYPE_I,SIPC_GEN_CTYPE_E,##__VA_ARGS__)
141
142#define SIPC_GEN_ARG_LIST(a,...) ,a MACRO_CAT2(_,MACRO_NARG(__VA_ARGS__))
143#define SIPC_GEN_PARAM_LIST(a,...) ,MACRO_CAT2(_,MACRO_NARG(__VA_ARGS__))
144#define SIPC_GEN_PARAM_REF_LIST(a,...) ,&MACRO_CAT2(_,MACRO_NARG(__VA_ARGS__))
Daogao Xua0c9ee62019-07-30 17:20:51 +0800145#define SIPC_GEN_PARAM_TYPEID(a,...) SIPC_TYPE_ID(a),
Daogao Xuf5aa4ad2019-05-16 16:05:56 +0800146#define SIPC_GEN_DECLARE_LIST(a,...) a MACRO_CAT2(_,MACRO_NARG(__VA_ARGS__));
Daogao Xua0c9ee62019-07-30 17:20:51 +0800147#define SIPC_GEN_ARG_PLIST(a,...) ,a * MACRO_CAT2(_p,MACRO_NARG(__VA_ARGS__))
148#define SIPC_GEN_PARAM_PLIST(a,...) ,MACRO_CAT2(_p,MACRO_NARG(__VA_ARGS__))
Daogao Xuf5aa4ad2019-05-16 16:05:56 +0800149// generate parameter-list: a,b -> , ctype_a _1 ,ctype_b _2
150#define SIPC_EXPAND_ARG_LIST(...) MACRO_CALL(MACRO_MAP,SIPC_GEN_ARG_LIST,SIPC_EXPAND_CTYPE_LIST(__VA_ARGS__))
151// generate list of declarator: a,b -> , _1 , _2
152#define SIPC_EXPAND_PARAM_LIST(...) MACRO_CALL(MACRO_MAP,SIPC_GEN_PARAM_LIST,SIPC_EXPAND_CTYPE_LIST(__VA_ARGS__))
153// generate address of declarator list: a,b -> , &_1 , &_2
154#define SIPC_EXPAND_PARAM_REF_LIST(...) MACRO_CALL(MACRO_MAP,SIPC_GEN_PARAM_REF_LIST,SIPC_EXPAND_CTYPE_LIST(__VA_ARGS__))
Daogao Xua0c9ee62019-07-30 17:20:51 +0800155// generate typeid array: a,b -> SIPC_TYPE_ID_a, SIPC_TYPE_ID_b,
156#define SIPC_EXPAND_PARAM_TYPEID(...) MACRO_MAP(SIPC_GEN_PARAM_TYPEID,##__VA_ARGS__)
Daogao Xuf5aa4ad2019-05-16 16:05:56 +0800157// generate declaration-list: a,b -> SIPC_a _1; SIPC_b _2;
158#define SIPC_EXPAND_PARAM_DECLARE_LIST(...) MACRO_CALL(MACRO_MAP,SIPC_GEN_DECLARE_LIST,SIPC_EXPAND_CTYPE_LIST(__VA_ARGS__))
Daogao Xua0c9ee62019-07-30 17:20:51 +0800159// generate parameter-pointer list: a,b -> , ctype_a * _1 ,ctype_b * _2
160#define SIPC_EXPAND_ARG_PLIST(...) MACRO_CALL(MACRO_MAP,SIPC_GEN_ARG_PLIST,SIPC_EXPAND_CTYPE_LIST(__VA_ARGS__))
161// generate list of declarator: a,b -> , _p1 , _p2
162#define SIPC_EXPAND_PARAM_PLIST(...) MACRO_CALL(MACRO_MAP,SIPC_GEN_PARAM_PLIST,SIPC_EXPAND_CTYPE_LIST(__VA_ARGS__))
Daogao Xuf5aa4ad2019-05-16 16:05:56 +0800163
164#define SIPC_FUNCTION(n) g_ipc_func_##n
165
Daogao Xua0c9ee62019-07-30 17:20:51 +0800166#define _DECLARE_IPC_FUNCTION(handle,...)\
167 extern SIPC_Function * g_ipc_func_##handle;\
168 extern int32_t call_##handle(SIPC_Peer ipc SIPC_EXPAND_ARG_LIST(__VA_ARGS__));
169#define _DECLARE_IPC_FUNCTION_SYNC(handle,argfmt,retfmt)\
170 extern SIPC_Function * g_ipc_func_##handle;\
171 extern int32_t call_##handle(SIPC_Peer ipc SIPC_EXPAND_ARG_LIST argfmt SIPC_EXPAND_ARG_PLIST retfmt);
172#define _DECLARE_IPC_EXPORT(handle,...)\
Daogao Xuf5aa4ad2019-05-16 16:05:56 +0800173 extern SIPC_Function * g_ipc_func_##handle;\
174 extern int32_t call_##handle(SIPC_Peer ipc SIPC_EXPAND_ARG_LIST(__VA_ARGS__));\
Daogao Xua0c9ee62019-07-30 17:20:51 +0800175 extern int32_t on_##handle(SIPC_Peer ipc SIPC_EXPAND_ARG_LIST(__VA_ARGS__));
176#define _DECLARE_IPC_EXPORT_SYNC(handle,argfmt,retfmt)\
177 extern SIPC_Function * g_ipc_func_##handle;\
178 extern int32_t call_##handle(SIPC_Peer ipc SIPC_EXPAND_ARG_LIST argfmt SIPC_EXPAND_ARG_PLIST retfmt);\
179 extern int32_t on_##handle(SIPC_Peer ipc SIPC_EXPAND_ARG_LIST argfmt);\
180 extern int32_t resp_##handle(SIPC_Peer ipc SIPC_EXPAND_ARG_LIST retfmt);
181
182#define _IMPLEMENT_IPC_FUNCTION(handle,...) \
183 _DECLARE_IPC_FUNCTION(handle,##__VA_ARGS__)\
184 static int32_t _typeid_call_##handle[] = {SIPC_EXPAND_PARAM_TYPEID(__VA_ARGS__) 0};\
Yeping Miao1b888a92020-04-21 17:32:26 +0800185 static SIPC_Function _ipc_imp_func_##handle = {#handle, (void*)0, _typeid_call_##handle, NULL, 0, NULL};\
Daogao Xuf5aa4ad2019-05-16 16:05:56 +0800186 SIPC_Function *g_ipc_func_##handle __attribute__((section("ipc_function_import_table"))) = &_ipc_imp_func_##handle;\
187 int32_t call_##handle(SIPC_Peer ipc SIPC_EXPAND_ARG_LIST(__VA_ARGS__)) {\
188 return ipc_call_fmt(ipc, SIPC_FUNCTION(handle) SIPC_EXPAND_PARAM_LIST(__VA_ARGS__));\
189 }
Daogao Xua0c9ee62019-07-30 17:20:51 +0800190#define _IMPLEMENT_IPC_FUNCTION_SYNC(handle,argfmt,retfmt)\
191 _DECLARE_IPC_FUNCTION_SYNC(handle,argfmt,retfmt)\
192 static int32_t _typeid_call_##handle[] = {SIPC_EXPAND_PARAM_TYPEID argfmt 0};\
193 static int32_t _typeid_ret_##handle[] = {SIPC_EXPAND_PARAM_TYPEID retfmt 0};\
Yeping Miao1b888a92020-04-21 17:32:26 +0800194 static SIPC_Function _ipc_imp_func_##handle = {#handle, (void*)0, _typeid_call_##handle, _typeid_ret_##handle, 0, NULL};\
Daogao Xua0c9ee62019-07-30 17:20:51 +0800195 SIPC_Function *g_ipc_func_##handle __attribute__((section("ipc_function_import_table"))) = &_ipc_imp_func_##handle;\
196 int32_t call_##handle(SIPC_Peer ipc SIPC_EXPAND_ARG_LIST argfmt SIPC_EXPAND_ARG_PLIST retfmt) {\
197 return ipc_call_fmt(ipc, SIPC_FUNCTION(handle) SIPC_EXPAND_PARAM_LIST argfmt SIPC_EXPAND_PARAM_PLIST retfmt);\
198 }
Daogao Xuf5aa4ad2019-05-16 16:05:56 +0800199
Daogao Xua0c9ee62019-07-30 17:20:51 +0800200#define _IMPLEMENT_IPC_EXPORT(handle,...) \
201 _DECLARE_IPC_EXPORT(handle,##__VA_ARGS__)\
202 static int32_t _typeid_call_##handle[] = {SIPC_EXPAND_PARAM_TYPEID(__VA_ARGS__) 0};\
Daogao Xuf5aa4ad2019-05-16 16:05:56 +0800203 static int32_t _ipc_handle_##handle(SIPC_Peer ipc, void * buf, int len) {\
204 SIPC_EXPAND_PARAM_DECLARE_LIST(__VA_ARGS__) \
Daogao Xua0c9ee62019-07-30 17:20:51 +0800205 int32_t r = ipc_upack_args(buf,len,_typeid_call_##handle SIPC_EXPAND_PARAM_REF_LIST(__VA_ARGS__));\
Daogao Xuf5aa4ad2019-05-16 16:05:56 +0800206 if (r >= 0) \
207 r = on_##handle(ipc SIPC_EXPAND_PARAM_LIST(__VA_ARGS__)); \
208 return r;\
209 }\
Yeping Miao1b888a92020-04-21 17:32:26 +0800210 static SIPC_Function _ipc_exp_func_##handle = {#handle, _ipc_handle_##handle, _typeid_call_##handle, NULL, 0, NULL};\
Daogao Xua0c9ee62019-07-30 17:20:51 +0800211 SIPC_Function *g_ipc_func_##handle __attribute__((section("ipc_function_export_table"))) = &_ipc_exp_func_##handle;\
212 int32_t call_##handle(SIPC_Peer ipc SIPC_EXPAND_ARG_LIST(__VA_ARGS__)) {\
213 return ipc_call_fmt(ipc, SIPC_FUNCTION(handle) SIPC_EXPAND_PARAM_LIST(__VA_ARGS__));\
214 }
215#define _IMPLEMENT_IPC_EXPORT_SYNC(handle,argfmt,retfmt) \
216 _DECLARE_IPC_EXPORT_SYNC(handle,argfmt,retfmt)\
217 static int32_t _typeid_call_##handle[] = {SIPC_EXPAND_PARAM_TYPEID argfmt 0};\
218 static int32_t _typeid_ret_##handle[] = {SIPC_EXPAND_PARAM_TYPEID retfmt 0};\
219 static int32_t _ipc_handle_##handle(SIPC_Peer ipc, void * buf, int len) {\
220 SIPC_EXPAND_PARAM_DECLARE_LIST argfmt \
221 int32_t r = ipc_upack_args(buf,len,_typeid_call_##handle SIPC_EXPAND_PARAM_REF_LIST argfmt);\
222 if (r >= 0) \
223 r = on_##handle(ipc SIPC_EXPAND_PARAM_LIST argfmt);\
224 if (r != SIPC_NO_ERR) { \
225 r = ipc_resp_fmt(ipc, NULL, r);\
226 } \
227 return r;\
228 }\
229 int32_t resp_##handle(SIPC_Peer ipc SIPC_EXPAND_ARG_LIST retfmt) {\
230 return ipc_resp_fmt(ipc, _typeid_ret_##handle, SIPC_NO_ERR SIPC_EXPAND_PARAM_LIST retfmt);\
231 }\
Yeping Miao1b888a92020-04-21 17:32:26 +0800232 static SIPC_Function _ipc_exp_func_##handle = {#handle, _ipc_handle_##handle, _typeid_call_##handle, _typeid_ret_##handle, 0, NULL};\
Daogao Xua0c9ee62019-07-30 17:20:51 +0800233 SIPC_Function *g_ipc_func_##handle __attribute__((section("ipc_function_export_table"))) = &_ipc_exp_func_##handle;\
234 int32_t call_##handle(SIPC_Peer ipc SIPC_EXPAND_ARG_LIST argfmt SIPC_EXPAND_ARG_PLIST retfmt) {\
235 return ipc_call_fmt(ipc, SIPC_FUNCTION(handle) SIPC_EXPAND_PARAM_LIST argfmt SIPC_EXPAND_PARAM_PLIST retfmt);\
236 }
Daogao Xuf5aa4ad2019-05-16 16:05:56 +0800237
Daogao Xua0c9ee62019-07-30 17:20:51 +0800238#if defined(SIPC_IMPLEMENTATION)
239#define DECLARE_IPC_FUNCTION _IMPLEMENT_IPC_FUNCTION
240#define DECLARE_IPC_FUNCTION_SYNC _IMPLEMENT_IPC_FUNCTION_SYNC
241#define EXPORT_IPC_FUNCTION _IMPLEMENT_IPC_EXPORT
242#define EXPORT_IPC_FUNCTION_SYNC _IMPLEMENT_IPC_EXPORT_SYNC
243#else // SIPC_IMPLEMENTATION
244#define DECLARE_IPC_FUNCTION _DECLARE_IPC_FUNCTION
245#define DECLARE_IPC_FUNCTION_SYNC _DECLARE_IPC_FUNCTION_SYNC
246#define EXPORT_IPC_FUNCTION _DECLARE_IPC_EXPORT
247#define EXPORT_IPC_FUNCTION_SYNC _DECLARE_IPC_EXPORT_SYNC
248#endif // SIPC_IMPLEMENTATION
249
250#define IPC_CALL(ipc,handle,...) call_##handle(ipc,##__VA_ARGS__)
251#define IPC_RESP(ipc,handle,...) resp_##handle(ipc,##__VA_ARGS__)
Daogao Xuf5aa4ad2019-05-16 16:05:56 +0800252
253typedef struct SIPC_HandleInternal* SIPC_Handle;
Daogao Xua0c9ee62019-07-30 17:20:51 +0800254typedef struct SIPC_HandleInternal* SIPC_Peer;
Daogao Xuf5aa4ad2019-05-16 16:05:56 +0800255typedef struct _SIPC_Function SIPC_Function;
256
257struct _SIPC_Function {
258 const char * name;
259 int32_t (*handle)(SIPC_Peer , void *, int );
Daogao Xua0c9ee62019-07-30 17:20:51 +0800260 int32_t * argfmt;
261 int32_t * retfmt;
262 int32_t call_id;
Daogao Xuf5aa4ad2019-05-16 16:05:56 +0800263 struct _SIPC_Function * next;
264};
265
266// user data type can be registered
267struct SIPC_DataType {
268 int type_id;
269 int len;
270 int32_t (*pack)(struct SIPC_DataType*, void *, int , va_list *);
271 int32_t (*upack)(struct SIPC_DataType*, void *, int , va_list *);
272 void (*free)(void *obj);
273};
274
275#define SIPC_NO_ERR 0
276#define SIPC_ERR_PARAM -1
277#define SIPC_ERR_IO -2
278#define SIPC_ERR_DATA -3
279#define SIPC_ERR_NO_FUNC -4
280#define SIPC_ERR_DUP_FUNC -5
281#define SIPC_ERR_NO_IMPL -6
Daogao Xua0c9ee62019-07-30 17:20:51 +0800282#define SIPC_ERR_TIMEOUT -7
283#define SIPC_ERR_UNKNOWN -8
Daogao Xuf5aa4ad2019-05-16 16:05:56 +0800284
Daogao Xua0c9ee62019-07-30 17:20:51 +0800285// default timeout for IPC call
286#define SIPC_DEFAULT_TIMEOUT 1000000*3
287// IPC message buffer size
288#define SIPC_MAX_MESSAGE_SIZE 1024*8
289
290// create an ipc channel that listen on bindaddr for incoming calls
Daogao Xuf5aa4ad2019-05-16 16:05:56 +0800291SIPC_Handle ipc_create_channel(const char * bindaddr);
Daogao Xua0c9ee62019-07-30 17:20:51 +0800292void ipc_close_channel(SIPC_Handle serv);
Daogao Xuf5aa4ad2019-05-16 16:05:56 +0800293// open a peer channel to make IPC call
294SIPC_Peer ipc_open_peer(SIPC_Handle serv, const char * remoteaddr);
295void ipc_close_peer(SIPC_Peer ipc);
296// run the main loop, it will not return
297int32_t ipc_run_loop(SIPC_Handle serv);
298// exit the most inner loop, return loop level
299int32_t ipc_exit_inner_loop(SIPC_Handle serv);
300// get the socket fd which can be used in select/poll
301// this makes it possible to avoid a dedicate thread to run ipc_run_loop
302int ipc_socket_getfd(SIPC_Handle serv);
303// call this function if select/poll success on the socket fd
304int32_t ipc_socket_handle(SIPC_Handle serv);
Daogao Xua0c9ee62019-07-30 17:20:51 +0800305// register function calls, the memory of SIPC_Function shall keep valid and untouched until ipc_close_channel
Daogao Xuf5aa4ad2019-05-16 16:05:56 +0800306int32_t ipc_register_call(SIPC_Handle serv, SIPC_Function * func);
Daogao Xua0c9ee62019-07-30 17:20:51 +0800307// set synchronous IPC call timeout, return previous timeout, default timeout is SIPC_DEFAULT_TIMEOUT
308int ipc_set_timeout(SIPC_Peer ipc, int us);
Daogao Xuf5aa4ad2019-05-16 16:05:56 +0800309// call IPC function with parameters
Daogao Xua0c9ee62019-07-30 17:20:51 +0800310int32_t ipc_call_va(SIPC_Peer ipc, SIPC_Function * func, va_list* va);
Daogao Xuf5aa4ad2019-05-16 16:05:56 +0800311int32_t ipc_call_fmt(SIPC_Peer ipc, SIPC_Function * func, ...);
Daogao Xua0c9ee62019-07-30 17:20:51 +0800312// answer an IPC call
313int32_t ipc_resp_va(SIPC_Peer ipc, int32_t * fmt, va_list* va);
314int32_t ipc_resp_fmt(SIPC_Peer ipc, int32_t * fmt, ...);
Daogao Xuf5aa4ad2019-05-16 16:05:56 +0800315// pack and unpack IPC parameters
Daogao Xua0c9ee62019-07-30 17:20:51 +0800316int32_t ipc_pack_va(void * buf, int len, int32_t * fmt, va_list* va);
317int32_t ipc_pack_args(void * buf, int len, int32_t * fmt, ...);
318int32_t ipc_upack_va(void * buf, int len, int32_t * fmt, va_list* va);
319int32_t ipc_upack_args(void * buf, int len, int32_t * fmt, ...);
Daogao Xuf5aa4ad2019-05-16 16:05:56 +0800320
Daogao Xua0c9ee62019-07-30 17:20:51 +0800321DECLARE_IPC_FUNCTION_SYNC(_call,(i32,i32,str),(i32));
322EXPORT_IPC_FUNCTION(_local,i32,ptr);
Daogao Xuf5aa4ad2019-05-16 16:05:56 +0800323
Daogao Xua0c9ee62019-07-30 17:20:51 +0800324#if defined(SIPC_IMPLEMENTATION)
Daogao Xuf5aa4ad2019-05-16 16:05:56 +0800325static int SIPC_LOG_LEVEL = -1;
326#define SIPC_LOG(lev,fmt, ...) do {\
Daogao Xua0c9ee62019-07-30 17:20:51 +0800327 if (SIPC_LOG_LEVEL < 0) {\
Daogao Xuf5aa4ad2019-05-16 16:05:56 +0800328 const char * level = getenv("SIPC_LOG_LEVEL");\
329 SIPC_LOG_LEVEL= level?atoi(level):2;\
330 }\
Daogao Xua0c9ee62019-07-30 17:20:51 +0800331 if (lev<SIPC_LOG_LEVEL)\
332 printf(fmt "\n", ## __VA_ARGS__);\
Daogao Xuf5aa4ad2019-05-16 16:05:56 +0800333} while (0)
334#define SIPC_LOG0(fmt, ...) SIPC_LOG(0, fmt, ## __VA_ARGS__)
335#define SIPC_LOG1(fmt, ...) SIPC_LOG(1, fmt, ## __VA_ARGS__)
336#define SIPC_LOG2(fmt, ...) SIPC_LOG(2, fmt, ## __VA_ARGS__)
337#define SIPC_LOG3(fmt, ...) SIPC_LOG(3, fmt, ## __VA_ARGS__)
338#define SIPC_LOG4(fmt, ...) SIPC_LOG(4, fmt, ## __VA_ARGS__)
339
Daogao Xuf5aa4ad2019-05-16 16:05:56 +0800340struct SIPC_HandleInternal {
Daogao Xua0c9ee62019-07-30 17:20:51 +0800341 char buffer[SIPC_MAX_MESSAGE_SIZE];
342 struct sockaddr_un addr;
343 socklen_t addrlen;
344 int32_t ipc_id;
Daogao Xuf5aa4ad2019-05-16 16:05:56 +0800345 int sockfd;
Daogao Xuf5aa4ad2019-05-16 16:05:56 +0800346 int loop_level;
Daogao Xua0c9ee62019-07-30 17:20:51 +0800347 int timeout_us;
348 SIPC_Function * func_table;
349 SIPC_Peer next;
350 SIPC_Handle serv;
Daogao Xuf5aa4ad2019-05-16 16:05:56 +0800351};
352
353static int32_t _ipc_pack_number(struct SIPC_DataType * type, void * buf, int len, va_list * va) {
354 if (len < type->len)
355 return SIPC_ERR_PARAM;
356 uint64_t val64 = (type->len == 8)?va_arg(*va, uint64_t):va_arg(*va, uint32_t);
357 uint8_t * p = (uint8_t*)&val64;
358 for (int n = type->len; n--; ) {
359 ((uint8_t*)buf)[n] = *p++;
360 }
361 return type->len;
362}
363
364static int32_t _ipc_upack_number(struct SIPC_DataType * type, void * buf, int len, va_list *va) {
365 if (len < type->len)
366 return SIPC_ERR_PARAM;
367 uint8_t * pval = va_arg(*va, void*);
368 for (int n = type->len; n--; ) {
369 *pval++ = ((uint8_t*)buf)[n];
370 }
371 return type->len;
372}
373
Daogao Xuf5aa4ad2019-05-16 16:05:56 +0800374static int32_t _ipc_pack_pointer(struct SIPC_DataType * type, void * buf, int len, va_list *va) {
Daogao Xuf5aa4ad2019-05-16 16:05:56 +0800375 void* ptr = va_arg(*va, void*);
Daogao Xu8c513c12019-05-22 10:51:06 +0800376 int32_t tlen = type->type_id == SIPC_TYPE_ID(str) ? (ptr ? strlen(ptr) + 1 : 0) : va_arg(*va, int32_t);
Daogao Xuf5aa4ad2019-05-16 16:05:56 +0800377 if ((tlen<0) || (len < tlen+4))
378 return SIPC_ERR_PARAM;
379 ((uint8_t*)buf)[0] = ((uint8_t*)&tlen)[3];
380 ((uint8_t*)buf)[1] = ((uint8_t*)&tlen)[2];
381 ((uint8_t*)buf)[2] = ((uint8_t*)&tlen)[1];
382 ((uint8_t*)buf)[3] = ((uint8_t*)&tlen)[0];
Daogao Xu8c513c12019-05-22 10:51:06 +0800383 if (tlen) memcpy((uint8_t *)buf + 4, ptr, tlen);
Daogao Xuf5aa4ad2019-05-16 16:05:56 +0800384 return tlen+4;
385}
386
387static int32_t _ipc_upack_pointer(struct SIPC_DataType * type, void * buf, int len, va_list *va) {
Daogao Xuf5aa4ad2019-05-16 16:05:56 +0800388 int32_t tlen = ((uint32_t)((uint8_t*)buf)[0] << 24) | ((uint32_t)((uint8_t*)buf)[1] << 16) | ((uint32_t)((uint8_t*)buf)[2] << 8) | ((uint32_t)((uint8_t*)buf)[3]);
389 if ((tlen<0) && (len < tlen+4))
390 return SIPC_ERR_PARAM;
391 void ** ptr = va_arg(*va, void**);
Daogao Xuf5aa4ad2019-05-16 16:05:56 +0800392 *ptr = tlen ? buf + 4 : NULL;
Daogao Xu8c513c12019-05-22 10:51:06 +0800393 if (type->type_id == SIPC_TYPE_ID(ptr)) {
394 int32_t * plen = va_arg(*va, int32_t*);
395 *plen = tlen;
396 }
Daogao Xuf5aa4ad2019-05-16 16:05:56 +0800397 return tlen+4;
398}
399
400static struct SIPC_DataType g_ipc_buildin_types[] = {
401 {0},
402 {SIPC_TYPE_ID(i8),1,_ipc_pack_number,_ipc_upack_number,0},
403 {SIPC_TYPE_ID(u8),1,_ipc_pack_number,_ipc_upack_number,0},
404 {SIPC_TYPE_ID(i16),2,_ipc_pack_number,_ipc_upack_number,0},
405 {SIPC_TYPE_ID(u16),2,_ipc_pack_number,_ipc_upack_number,0},
406 {SIPC_TYPE_ID(i32),4,_ipc_pack_number,_ipc_upack_number,0},
407 {SIPC_TYPE_ID(u32),4,_ipc_pack_number,_ipc_upack_number,0},
408 {SIPC_TYPE_ID(i64),8,_ipc_pack_number,_ipc_upack_number,0},
409 {SIPC_TYPE_ID(u64),8,_ipc_pack_number,_ipc_upack_number,0},
Daogao Xu8c513c12019-05-22 10:51:06 +0800410 {SIPC_TYPE_ID(str),4,_ipc_pack_pointer,_ipc_upack_pointer,0},
Daogao Xuf5aa4ad2019-05-16 16:05:56 +0800411 {SIPC_TYPE_ID(ptr),4,_ipc_pack_pointer,_ipc_upack_pointer,0},
412};
413
Daogao Xua0c9ee62019-07-30 17:20:51 +0800414int32_t ipc_pack_args(void * buf, int len, int32_t * fmt, ...) {
Daogao Xuf5aa4ad2019-05-16 16:05:56 +0800415 va_list ap;
416 va_start(ap, fmt);
Daogao Xua0c9ee62019-07-30 17:20:51 +0800417 int32_t r = ipc_pack_va(buf,len,fmt,&ap);
Daogao Xuf5aa4ad2019-05-16 16:05:56 +0800418 va_end(ap);
419 return r;
420}
421
Daogao Xua0c9ee62019-07-30 17:20:51 +0800422int32_t ipc_pack_va(void * buf, int len, int32_t * fmt, va_list* va)
Daogao Xuf5aa4ad2019-05-16 16:05:56 +0800423{
424 int tlen = 0;
425 int32_t ret = 0;
Daogao Xua0c9ee62019-07-30 17:20:51 +0800426 int32_t ch;
427 while ((ch=*fmt++)!=0) {
Daogao Xuf5aa4ad2019-05-16 16:05:56 +0800428 if ((ch >= SIPC_TYPE_ID(i8)) && (ch <= SIPC_TYPE_ID(ptr))) {
Daogao Xua0c9ee62019-07-30 17:20:51 +0800429 tlen = g_ipc_buildin_types[ch].pack(&g_ipc_buildin_types[ch], buf, len, va);
Daogao Xuf5aa4ad2019-05-16 16:05:56 +0800430 } else {
431 SIPC_LOG1("TODO: customer type");
432 tlen = SIPC_ERR_NO_IMPL;
433 }
434 if (tlen <= 0)
435 break;
436 len -= tlen;
437 buf += tlen;
438 ret += tlen;
439 }
440 return ret;
441}
442
Daogao Xua0c9ee62019-07-30 17:20:51 +0800443int32_t ipc_upack_args(void * buf, int len, int32_t * fmt, ...) {
Daogao Xuf5aa4ad2019-05-16 16:05:56 +0800444 va_list ap;
445 va_start(ap, fmt);
Daogao Xua0c9ee62019-07-30 17:20:51 +0800446 int32_t r = ipc_upack_va(buf,len,fmt,&ap);
Daogao Xuf5aa4ad2019-05-16 16:05:56 +0800447 va_end(ap);
448 return r;
449}
450
Daogao Xua0c9ee62019-07-30 17:20:51 +0800451int32_t ipc_upack_va(void * buf, int len, int32_t * fmt, va_list* va)
Daogao Xuf5aa4ad2019-05-16 16:05:56 +0800452{
453 int ch;
454 int tlen = 0;
455 int32_t ret = 0;
Daogao Xua0c9ee62019-07-30 17:20:51 +0800456 while ((ch=*fmt++)!=0) {
Daogao Xuf5aa4ad2019-05-16 16:05:56 +0800457 if ((ch >= SIPC_TYPE_ID(i8)) && (ch <= SIPC_TYPE_ID(ptr))) {
Daogao Xua0c9ee62019-07-30 17:20:51 +0800458 tlen = g_ipc_buildin_types[ch].upack(&g_ipc_buildin_types[ch], buf, len,va);
Daogao Xuf5aa4ad2019-05-16 16:05:56 +0800459 } else {
460 SIPC_LOG1("TODO: customer type");
461 tlen = SIPC_ERR_NO_IMPL;
462 }
463 if (tlen <= 0)
464 break;
465 len -= tlen;
466 buf += tlen;
467 ret += tlen;
468 }
469 return ret;
470}
471
472SIPC_Handle ipc_create_channel(const char * bindaddr)
473{
474 int unix_socket = socket(AF_UNIX, SOCK_DGRAM, 0);
475 if (unix_socket < 0) {
476 SIPC_LOG1("failed to open socket %d %s", errno, strerror(errno));
477 goto error;
478 }
479 struct sockaddr_un addr;
Daogao Xua0c9ee62019-07-30 17:20:51 +0800480 socklen_t addrlen;
Daogao Xuf5aa4ad2019-05-16 16:05:56 +0800481 addr.sun_family = AF_UNIX;
482 if (bindaddr) {
Daogao Xuf5aa4ad2019-05-16 16:05:56 +0800483 unlink(bindaddr);
Daogao Xua0c9ee62019-07-30 17:20:51 +0800484 addrlen = snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", bindaddr) + 1 + offsetof(struct sockaddr_un, sun_path);
485 } else {
486 addrlen = sizeof(sa_family_t);
487 }
488 if (bind(unix_socket, (struct sockaddr *)&addr, addrlen) < 0) {
489 SIPC_LOG1("bind to %s fail %d %s", bindaddr, errno, strerror(errno));
490 goto error;
Daogao Xuf5aa4ad2019-05-16 16:05:56 +0800491 }
492 struct SIPC_HandleInternal * serv = malloc(sizeof(*serv));
493 memset(serv, 0, sizeof(*serv));
Daogao Xuf5aa4ad2019-05-16 16:05:56 +0800494 serv->sockfd = unix_socket;
Daogao Xua0c9ee62019-07-30 17:20:51 +0800495 serv->timeout_us = SIPC_DEFAULT_TIMEOUT;
496 serv->addrlen = sizeof(serv->addr);
497 if (getsockname(unix_socket, (struct sockaddr *)&serv->addr, &serv->addrlen)) {
498 SIPC_LOG1("getsockname fail %d %s", errno, strerror(errno));
499 } else {
500 SIPC_LOG1("bind to addr %.*s addrlen %d", serv->addrlen-3, &serv->addr.sun_path[1], serv->addrlen);
501 }
Daogao Xuf5aa4ad2019-05-16 16:05:56 +0800502
503 return serv;
504
505error:
506 if (unix_socket >= 0) {
507 close(unix_socket);
508 }
509 return NULL;
510}
511
512SIPC_Peer ipc_open_peer(SIPC_Handle serv, const char * remoteaddr)
513{
Daogao Xua0c9ee62019-07-30 17:20:51 +0800514 SIPC_Peer ipc;
515 if (serv) {
516 for (ipc=serv->next; ipc; ipc=ipc->next) {
517 if (strcmp(ipc->addr.sun_path, remoteaddr) == 0)
518 return ipc;
519 }
Daogao Xuf5aa4ad2019-05-16 16:05:56 +0800520 }
Daogao Xua0c9ee62019-07-30 17:20:51 +0800521 ipc = ipc_create_channel(NULL);
522 ipc->addr.sun_family = AF_UNIX;
523 ipc->addrlen = snprintf(ipc->addr.sun_path, sizeof(ipc->addr.sun_path), "%s", remoteaddr) + 1 + offsetof(struct sockaddr_un, sun_path);
524 if (serv) {
525 ipc->serv = serv;
526 ipc->next = serv->next;
527 serv->next = ipc;
528 }
Daogao Xuf5aa4ad2019-05-16 16:05:56 +0800529 return ipc;
530}
531
532void ipc_close_peer(SIPC_Peer ipc)
533{
Daogao Xua0c9ee62019-07-30 17:20:51 +0800534 if (ipc->serv) {
535 SIPC_Handle ch = ipc->serv->next;
536 if (ch == ipc)
537 ipc->serv->next = ch->next;
538 else if (ch) {
539 for (; ch->next; ch=ch->next) {
540 if (ch->next == ipc) {
541 ch->next = ipc->next;
542 break;
543 }
Daogao Xuf5aa4ad2019-05-16 16:05:56 +0800544 }
545 }
546 }
Daogao Xua0c9ee62019-07-30 17:20:51 +0800547 if (ipc->sockfd >= 0) {
548 close(ipc->sockfd);
549 }
Daogao Xuf5aa4ad2019-05-16 16:05:56 +0800550 free(ipc);
551}
552
Daogao Xua0c9ee62019-07-30 17:20:51 +0800553void ipc_close_channel(SIPC_Handle serv)
Daogao Xuf5aa4ad2019-05-16 16:05:56 +0800554{
555 if (serv->sockfd >= 0) {
556 close(serv->sockfd);
557 serv->sockfd = -1;
558 }
Daogao Xua0c9ee62019-07-30 17:20:51 +0800559 while (serv->next) {
560 SIPC_Peer ipc = serv->next;
561 serv->next = ipc->next;
Daogao Xuf5aa4ad2019-05-16 16:05:56 +0800562 ipc_close_peer(ipc);
563 }
564}
565
566int32_t ipc_run_loop(SIPC_Handle serv)
567{
568 int cur_loop = serv->loop_level++;
569 while (cur_loop < serv->loop_level) {
570 int r = ipc_socket_handle(serv);
571 (void)r;
572 }
573 return 0;
574}
575
576int32_t ipc_exit_inner_loop(SIPC_Handle serv)
577{
578 serv->loop_level--;
Daogao Xua0c9ee62019-07-30 17:20:51 +0800579 call__local(serv,0,NULL,0);
Daogao Xuf5aa4ad2019-05-16 16:05:56 +0800580 return 0;
581}
582
Daogao Xua0c9ee62019-07-30 17:20:51 +0800583int ipc_socket_getfd(SIPC_Handle serv) { return serv->sockfd; }
Daogao Xuf5aa4ad2019-05-16 16:05:56 +0800584
585// clientid,callid,name
586int32_t ipc_socket_handle(SIPC_Handle serv)
587{
Daogao Xua0c9ee62019-07-30 17:20:51 +0800588 char * buf = serv->buffer;
589 struct SIPC_HandleInternal tempChannel;
590 tempChannel.addrlen = sizeof(tempChannel.addr);
591 tempChannel.sockfd = serv->sockfd;
592 tempChannel.serv = serv;
593 int len = recvfrom(serv->sockfd, buf, SIPC_MAX_MESSAGE_SIZE, MSG_NOSIGNAL, (struct sockaddr *)&tempChannel.addr, &tempChannel.addrlen);
Daogao Xuf5aa4ad2019-05-16 16:05:56 +0800594 int32_t client_id;
595 int32_t call_id;
596 char * name;
597 int len1 = ipc_upack_args(buf, len, SIPC_FUNCTION(_call)->argfmt, &client_id, &call_id, &name);
598 if (len1 <= 0) {
599 SIPC_LOG2("data format error");
600 return SIPC_ERR_DATA;
601 }
Daogao Xua0c9ee62019-07-30 17:20:51 +0800602 SIPC_LOG3("received call %s %d bytes from %.*s", name, len, tempChannel.addrlen-3, &tempChannel.addr.sun_path[1]);
Daogao Xuf5aa4ad2019-05-16 16:05:56 +0800603 if (SIPC_LOG_LEVEL > 3) {
604 int i;
605 char msg[len*3 + 1], *p = msg;
606 for (i=0; i<len; ++i) {
607 p += sprintf(p, "%02x ", (uint8_t)buf[i]);
608 }
609 SIPC_LOG4("%s",msg);
610 }
611 SIPC_Peer ipc = NULL;
612 if (client_id == 0) {
613 ipc = &tempChannel;
614 ipc->serv = serv;
615 ipc->next = NULL;
Daogao Xua0c9ee62019-07-30 17:20:51 +0800616 ipc->ipc_id = 0;
Daogao Xuf5aa4ad2019-05-16 16:05:56 +0800617 ipc->func_table = NULL;
618 } else {
Daogao Xua0c9ee62019-07-30 17:20:51 +0800619 for (ipc=serv->next; ipc; ipc=ipc->next) {
620 if (ipc->ipc_id == client_id)
Daogao Xuf5aa4ad2019-05-16 16:05:56 +0800621 break;
622 }
623 }
624 if (ipc == NULL) {
625 SIPC_LOG2("client_id %d not found", client_id);
626 }
627 extern SIPC_Function *__start_ipc_function_export_table;
628 extern SIPC_Function *__stop_ipc_function_export_table;
629 //extern SIPC_Function *__start_ipc_function_import_table;
630 //extern SIPC_Function *__stop_ipc_function_import_table;
631 SIPC_Function * f = NULL;
632 SIPC_Function ** ppfunc = &__start_ipc_function_export_table;
633 for (;ppfunc<&__stop_ipc_function_export_table;++ppfunc) {
634 if (strcmp((*ppfunc)->name, name) == 0) {
635 f = *ppfunc;
636 break;
637 }
638 }
639 if (f == NULL) {
640 for (f=serv->func_table; f; f=f->next) {
641 if (strcmp(f->name, name) == 0) {
642 break;
643 }
644 }
645 }
646 if (f == NULL) {
647 SIPC_LOG2("can't find function %s", (char*)name);
648 return SIPC_ERR_NO_FUNC;
649 }
650 return f->handle(ipc, buf+len1, len-len1);
651}
652
653int32_t ipc_register_call(SIPC_Handle serv, SIPC_Function * func)
654{
655 SIPC_Function *f;
656 for (f=serv->func_table; f != NULL; f = f->next) {
657 if ((f == func) || (strcmp(f->name, func->name)==0)) {
658 SIPC_LOG1("try to register IPC function %s multiple time, %p %p\n", func->name, f, func);
659 return SIPC_ERR_DUP_FUNC;
660 }
661 }
662 func->next = serv->func_table;
663 serv->func_table = func;
664 return 0;
665}
666
Daogao Xua0c9ee62019-07-30 17:20:51 +0800667static int socket_have_data_to_read(int sockfd, int us)
Daogao Xuf5aa4ad2019-05-16 16:05:56 +0800668{
Daogao Xua0c9ee62019-07-30 17:20:51 +0800669 struct timeval tv, *ptv;
670 fd_set rfds;
671 FD_ZERO(&rfds);
672 FD_SET(sockfd, &rfds);
673 if (us == -1) {
674 ptv = NULL;
675 } else {
676 ptv = &tv;
677 ptv->tv_sec = us / 1000000;
678 ptv->tv_usec = us % 1000000;
679 }
680 int retval;
681 do {
682 retval = select(sockfd+1, &rfds, NULL, NULL, ptv);
683 } while ((retval==-1) && (errno==EINTR));
684 return retval;
685}
686
687int32_t ipc_call_va(SIPC_Peer ipc, SIPC_Function * func, va_list* va)
688{
689#if 0
690 if (func->retfmt) {
691 struct sockaddr_un addr;
692 socklen_t addrlen = sizeof(addr);
693 // flush the socket
694 while (socket_have_data_to_read(ipc->sockfd, 0) > 0) {
695 int rlen = recvfrom(ipc->sockfd, ipc->buffer, sizeof(ipc->buffer), MSG_NOSIGNAL, (struct sockaddr *)&addr, &addrlen);
696 if (rlen > 0) {
697 SIPC_LOG1("drop %d bytes from %.*s", rlen, addrlen-3, &addr.sun_path[1]);
698 }
699 }
700 }
701#endif
702 char *buf = ipc->buffer;
703 int len = sizeof(ipc->buffer);
704 int len1 = ipc_pack_args(buf, len, SIPC_FUNCTION(_call)->argfmt, ipc->ipc_id, func->call_id, func->name);
Daogao Xuf5aa4ad2019-05-16 16:05:56 +0800705 if (len1 <= 0) {
706 SIPC_LOG2("call ipc_pack_args header failed");
707 return len1;
708 }
709 int len2 = ipc_pack_va(buf+len1, len-len1, func->argfmt, va);
710 if (len2 < 0) {
711 SIPC_LOG2("call ipc_pack_args params failed");
712 return len2;
713 }
Daogao Xua0c9ee62019-07-30 17:20:51 +0800714 int wlen = sendto(ipc->sockfd, buf, len1+len2, MSG_NOSIGNAL, (struct sockaddr *)&ipc->addr, ipc->addrlen);
715 SIPC_LOG3("call %s, send %d bytes to %.*s, return %d", func->name, len1+len2, ipc->addrlen-3, &ipc->addr.sun_path[1], wlen);
Daogao Xuf5aa4ad2019-05-16 16:05:56 +0800716 if (SIPC_LOG_LEVEL > 3) {
717 int i = len1+len2;
718 char msg[i*3 + 1], *p = msg;
719 for (i=0; i<len1+len2; ++i) {
720 p += sprintf(p, "%02x ", (uint8_t)buf[i]);
721 }
722 SIPC_LOG4("%s",msg);
723 }
724 if (wlen != len1+len2) {
725 SIPC_LOG2("send data fail %d != %d + %d, err %d %s", wlen, len1, len2, errno, strerror(errno));
726 return SIPC_ERR_IO;
727 }
Daogao Xua0c9ee62019-07-30 17:20:51 +0800728 if (func->retfmt == NULL)
729 return SIPC_NO_ERR;
730 int r = socket_have_data_to_read(ipc->sockfd, ipc->timeout_us);
731 if (r > 0) {
732 struct sockaddr_un addr;
733 socklen_t addrlen = sizeof(addr);
734 int rlen = recvfrom(ipc->sockfd, ipc->buffer, sizeof(ipc->buffer), MSG_NOSIGNAL, (struct sockaddr *)&addr, &addrlen);
735 if (rlen <= 0) {
736 SIPC_LOG2("call %s, response len %d", func->name, rlen);
737 r = SIPC_ERR_IO;
738 } else {
739 SIPC_LOG3("receive %d bytes from %.*s", rlen, addrlen-3, &addr.sun_path[1]);
740 if (SIPC_LOG_LEVEL > 3) {
741 int i = rlen;
742 char msg[i*3 + 1], *p = msg;
743 for (i=0; i<rlen; ++i) {
744 p += sprintf(p, "%02x ", (uint8_t)ipc->buffer[i]);
745 }
746 SIPC_LOG4("%s",msg);
747 }
748 len1 = ipc_upack_args(ipc->buffer, rlen, SIPC_FUNCTION(_call)->retfmt, &r);
749 if (r == SIPC_NO_ERR) {
750 len2 = ipc_upack_va(ipc->buffer+len1, rlen-len1, func->retfmt, va);
751 }
752 SIPC_LOG3("call %s return %d", func->name, r);
753 }
754 } else if (r == 0) {
755 SIPC_LOG2("call %s response timeout", func->name);
756 r = SIPC_ERR_TIMEOUT;
757 } else {
758 SIPC_LOG2("call %s, failed to get response", func->name);
759 r = SIPC_ERR_UNKNOWN;
760 }
761 return r;
Daogao Xuf5aa4ad2019-05-16 16:05:56 +0800762}
763
764int32_t ipc_call_fmt(SIPC_Peer ipc, SIPC_Function * func, ...) {
765 va_list ap;
766 va_start(ap, func);
Daogao Xua0c9ee62019-07-30 17:20:51 +0800767 int32_t r = ipc_call_va(ipc,func,&ap);
Daogao Xuf5aa4ad2019-05-16 16:05:56 +0800768 va_end(ap);
769 return r;
770}
771
Daogao Xua0c9ee62019-07-30 17:20:51 +0800772int32_t ipc_resp_va(SIPC_Peer ipc, int32_t * fmt, va_list* va) {
773 int len1 = ipc_pack_va(ipc->buffer, sizeof(ipc->buffer), SIPC_FUNCTION(_call)->retfmt, va);
774 if (len1 <= 0) {
775 SIPC_LOG2("call ipc_pack_args header failed");
776 return len1;
777 }
778 int len2 = fmt ? ipc_pack_va(ipc->buffer + len1, sizeof(ipc->buffer) - len1, fmt, va) : 0;
779 if (len2 < 0) {
780 SIPC_LOG2("call ipc_pack_args params failed");
781 return len2;
782 }
783 int wlen = sendto(ipc->sockfd, ipc->buffer, len1+len2, MSG_NOSIGNAL, (struct sockaddr *)&ipc->addr, ipc->addrlen);
784 SIPC_LOG3("send %d bytes to %.*s, return %d", len1+len2, ipc->addrlen-3, &ipc->addr.sun_path[1], wlen);
785 if (SIPC_LOG_LEVEL > 3) {
786 int i = len1+len2;
787 char msg[i*3 + 1], *p = msg;
788 for (i=0; i<len1+len2; ++i) {
789 p += sprintf(p, "%02x ", (uint8_t)ipc->buffer[i]);
790 }
791 SIPC_LOG4("%s",msg);
792 }
793 if (wlen != len1+len2) {
794 SIPC_LOG2("send data fail %d != %d + %d, err %d %s", wlen, len1, len2, errno, strerror(errno));
795 return SIPC_ERR_IO;
796 }
797 return SIPC_NO_ERR;
Daogao Xuf5aa4ad2019-05-16 16:05:56 +0800798}
799
Daogao Xua0c9ee62019-07-30 17:20:51 +0800800int32_t ipc_resp_fmt(SIPC_Peer ipc, int32_t * fmt, ...) {
801 va_list ap;
802 va_start(ap, fmt);
803 int32_t r = ipc_resp_va(ipc,fmt,&ap);
804 va_end(ap);
805 return r;
Daogao Xuf5aa4ad2019-05-16 16:05:56 +0800806}
807
808int32_t on__local(SIPC_Peer ipc, int32_t cmd, void * data, int32_t len)
809{
810 SIPC_LOG3("client %p call local %d %p %d", ipc, cmd, data, len);
811 return 0;
812}
813
Daogao Xua0c9ee62019-07-30 17:20:51 +0800814int ipc_set_timeout(SIPC_Peer ipc, int us) {
815 int old = ipc->timeout_us;
816 ipc->timeout_us = us;
817 return old;
818}
Daogao Xuf5aa4ad2019-05-16 16:05:56 +0800819
820#endif
821
822#ifdef __cplusplus
823} /* extern "C" */
824#endif
825
826#endif /* end of include guard: SOCKETIPC_H */