blob: 161559d3869e66aa307b668ea7b9cb41f0afa9b3 [file] [log] [blame]
Daogao Xuf5aa4ad2019-05-16 16:05:56 +08001#include <stdio.h>
2#include <stdlib.h>
3#include <string.h>
4#include <errno.h>
5#include <unistd.h>
6#include <sys/socket.h>
7#include <sys/un.h>
8#include <sys/types.h>
9#include <arpa/inet.h>
10
11#ifndef SOCKETIPC_H
12
13#define SOCKETIPC_H
14
15#include <stdarg.h>
16#include <stdint.h>
17
18#ifdef __cplusplus
19extern "C" {
20#endif
21
22/*
23 * a lightweight IPC API implemented in a signel header file
24 *
25 * use DECLARE_IPC_FUNCTION to define the IPC function prototype and IPC stub
26 * code i.e. below code will define an IPC call "foo" which takes two parameters
27 * typed as int32_t and int64_t:
28 * DECLARE_IPC_FUNCTION(foo,int32_t, int64_t)
29 *
30 * internally it will declare "call_foo" C API so you can call this function on
31 * an opened IPC channel, The stub code is generated when SIPC_IMPLEMENTATION is
32 * defined, SIPC_IMPLEMENTATION shall be defined in one of your C code before
33 * including this file
34 *
35 * On the peer side, use EXPORT_IPC_FUNCTION to generate stub code for the IPC
36 * call handle:
37 * EXPORT_IPC_FUNCTION(foo,int32_t, int64_t)
38 *
39 * IPC calls are asynchronous, calls can be make on any thread, the IPC stub
40 * code will place an dgram on the socket, the data will transfer to peer, and
41 * received by ipc_socket_handle in peer application, it then dispatch the call
42 * and call "on_foo"
43 *
44 */
45
46/*
47 * define the IPC type and C type mapping
48 * this IPC library is UDP/unix socket based, it is meant to communicate
49 * accross different host, so don't use those types whose length depends on ARCH
50 * and compiler, such as int, long, use int32_t, int64_t instead
51 */
52// build-in types
53#define SIPC_DEFINE_TYPE_i8 (int),0x01,"\x01"
54#define SIPC_DEFINE_TYPE_u8 (int),0x02,"\x02"
55#define SIPC_DEFINE_TYPE_i16 (int),0x03,"\x03"
56#define SIPC_DEFINE_TYPE_u16 (int),0x04,"\x04"
57#define SIPC_DEFINE_TYPE_i32 (int32_t),0x05,"\x05"
58#define SIPC_DEFINE_TYPE_u32 (uint32_t),0x06,"\x06"
59#define SIPC_DEFINE_TYPE_i64 (int64_t),0x07,"\x07"
60#define SIPC_DEFINE_TYPE_u64 (uint64_t),0x08,"\x08"
61#define SIPC_DEFINE_TYPE_str (char*),0x09,"\x09"
62#define SIPC_DEFINE_TYPE_ptr (void*,int32_t),0x0a,"\x0a"
63
64// type alias
65#define SIPC_DEFINE_TYPE_int8_t SIPC_DEFINE_TYPE_i8
66#define SIPC_DEFINE_TYPE_char SIPC_DEFINE_TYPE_i8
67#define SIPC_DEFINE_TYPE_uint8_t SIPC_DEFINE_TYPE_u8
68#define SIPC_DEFINE_TYPE_uchar SIPC_DEFINE_TYPE_u8
69#define SIPC_DEFINE_TYPE_byte SIPC_DEFINE_TYPE_u8
70#define SIPC_DEFINE_TYPE_int32_t SIPC_DEFINE_TYPE_i32
71#define SIPC_DEFINE_TYPE_uint32_t SIPC_DEFINE_TYPE_u32
72#define SIPC_DEFINE_TYPE_int64_t SIPC_DEFINE_TYPE_i64
73#define SIPC_DEFINE_TYPE_uint64_t SIPC_DEFINE_TYPE_u64
74
75
76#define MACRO_CAT(a,...) a ## __VA_ARGS__
77#define MACRO_CAT2(a,...) MACRO_CAT(a,__VA_ARGS__)
78#define MACRO_EMPTY(...)
79#define MACRO_CALL(M,...) M(__VA_ARGS__)
80#define EXPR(...) __VA_ARGS__
81
82#define MACRO_GET_16(dummy,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,...) _16
83#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)
84
85#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)
86#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)
87#define SIPC_TYPE_SID(t) MACRO_CALL(MACRO_GET_16,dummy,1,2,3,4,5,6,7,8,9,10,11,12,13,SIPC_DEFINE_TYPE_##t)
88
89#define MACRO_RECURSE_0(I,E,...)
90#define MACRO_RECURSE_1(I,E,_1,...) E(_1)
91#define MACRO_RECURSE_2(I,E,_1,...) I(_1,##__VA_ARGS__) MACRO_RECURSE_1(I,E,##__VA_ARGS__)
92#define MACRO_RECURSE_3(I,E,_1,...) I(_1,##__VA_ARGS__) MACRO_RECURSE_2(I,E,##__VA_ARGS__)
93#define MACRO_RECURSE_4(I,E,_1,...) I(_1,##__VA_ARGS__) MACRO_RECURSE_3(I,E,##__VA_ARGS__)
94#define MACRO_RECURSE_5(I,E,_1,...) I(_1,##__VA_ARGS__) MACRO_RECURSE_4(I,E,##__VA_ARGS__)
95#define MACRO_RECURSE_6(I,E,_1,...) I(_1,##__VA_ARGS__) MACRO_RECURSE_5(I,E,##__VA_ARGS__)
96#define MACRO_RECURSE_7(I,E,_1,...) I(_1,##__VA_ARGS__) MACRO_RECURSE_6(I,E,##__VA_ARGS__)
97#define MACRO_RECURSE_8(I,E,_1,...) I(_1,##__VA_ARGS__) MACRO_RECURSE_7(I,E,##__VA_ARGS__)
98#define MACRO_RECURSE_9(I,E,_1,...) I(_1,##__VA_ARGS__) MACRO_RECURSE_8(I,E,##__VA_ARGS__)
99#define MACRO_RECURSE_10(I,E,_1,...) I(_1,##__VA_ARGS__) MACRO_RECURSE_9(I,E,##__VA_ARGS__)
100#define MACRO_RECURSE_11(I,E,_1,...) I(_1,##__VA_ARGS__) MACRO_RECURSE_10(I,E,##__VA_ARGS__)
101#define MACRO_RECURSE_12(I,E,_1,...) I(_1,##__VA_ARGS__) MACRO_RECURSE_11(I,E,##__VA_ARGS__)
102#define MACRO_RECURSE_13(I,E,_1,...) I(_1,##__VA_ARGS__) MACRO_RECURSE_12(I,E,##__VA_ARGS__)
103#define MACRO_RECURSE_14(I,E,_1,...) I(_1,##__VA_ARGS__) MACRO_RECURSE_13(I,E,##__VA_ARGS__)
104#define MACRO_RECURSE_15(I,E,_1,...) I(_1,##__VA_ARGS__) MACRO_RECURSE_14(I,E,##__VA_ARGS__)
105#define MACRO_RECURSE_16(I,E,_1,...) I(_1,##__VA_ARGS__) MACRO_RECURSE_15(I,E,##__VA_ARGS__)
106#define MACRO_RECURSE_17(I,E,_1,...) I(_1,##__VA_ARGS__) MACRO_RECURSE_16(I,E,##__VA_ARGS__)
107
108#define MACRO_MAP(M,...) MACRO_CAT2(MACRO_RECURSE_,MACRO_NARG(__VA_ARGS__))(M,M,##__VA_ARGS__)
109
110#define SIPC_GEN_CTYPE_EXPR1(...) __VA_ARGS__
111#define SIPC_GEN_CTYPE_EXPR2(...) __VA_ARGS__
112#define SIPC_GEN_CTYPE_E(a,...) SIPC_GEN_CTYPE_EXPR2(SIPC_GEN_CTYPE_EXPR1 SIPC_TYPE_CTYPE(a))
113#define SIPC_GEN_CTYPE_I(a,...) SIPC_GEN_CTYPE_EXPR2(SIPC_GEN_CTYPE_EXPR1 SIPC_TYPE_CTYPE(a)),
114#define SIPC_EXPAND_CTYPE_LIST(...) MACRO_CAT2(MACRO_RECURSE_,MACRO_NARG(__VA_ARGS__))(SIPC_GEN_CTYPE_I,SIPC_GEN_CTYPE_E,##__VA_ARGS__)
115
116#define SIPC_GEN_ARG_LIST(a,...) ,a MACRO_CAT2(_,MACRO_NARG(__VA_ARGS__))
117#define SIPC_GEN_PARAM_LIST(a,...) ,MACRO_CAT2(_,MACRO_NARG(__VA_ARGS__))
118#define SIPC_GEN_PARAM_REF_LIST(a,...) ,&MACRO_CAT2(_,MACRO_NARG(__VA_ARGS__))
119#define SIPC_GEN_PARAM_STRID(a,...) SIPC_TYPE_SID(a)
120#define SIPC_GEN_DECLARE_LIST(a,...) a MACRO_CAT2(_,MACRO_NARG(__VA_ARGS__));
121// generate parameter-list: a,b -> , ctype_a _1 ,ctype_b _2
122#define SIPC_EXPAND_ARG_LIST(...) MACRO_CALL(MACRO_MAP,SIPC_GEN_ARG_LIST,SIPC_EXPAND_CTYPE_LIST(__VA_ARGS__))
123// generate list of declarator: a,b -> , _1 , _2
124#define SIPC_EXPAND_PARAM_LIST(...) MACRO_CALL(MACRO_MAP,SIPC_GEN_PARAM_LIST,SIPC_EXPAND_CTYPE_LIST(__VA_ARGS__))
125// generate address of declarator list: a,b -> , &_1 , &_2
126#define SIPC_EXPAND_PARAM_REF_LIST(...) MACRO_CALL(MACRO_MAP,SIPC_GEN_PARAM_REF_LIST,SIPC_EXPAND_CTYPE_LIST(__VA_ARGS__))
127// generate typeid string: a,b -> SIPC_TYPE_SID_a SIPC_TYPE_SID_b
128#define SIPC_EXPAND_PARAM_STRID(...) MACRO_MAP(SIPC_GEN_PARAM_STRID,##__VA_ARGS__)
129// generate declaration-list: a,b -> SIPC_a _1; SIPC_b _2;
130#define SIPC_EXPAND_PARAM_DECLARE_LIST(...) MACRO_CALL(MACRO_MAP,SIPC_GEN_DECLARE_LIST,SIPC_EXPAND_CTYPE_LIST(__VA_ARGS__))
131
132#define SIPC_FUNCTION(n) g_ipc_func_##n
133
134#ifdef SIPC_IMPLEMENTATION
135#define DECLARE_IPC_FUNCTION(handle,...) \
136 extern SIPC_Function * g_ipc_func_##handle;\
137 extern int32_t call_##handle(SIPC_Peer ipc SIPC_EXPAND_ARG_LIST(__VA_ARGS__));\
138 static SIPC_Function _ipc_imp_func_##handle = {#handle, (void*)0, "" SIPC_EXPAND_PARAM_STRID(__VA_ARGS__)};\
139 SIPC_Function *g_ipc_func_##handle __attribute__((section("ipc_function_import_table"))) = &_ipc_imp_func_##handle;\
140 int32_t call_##handle(SIPC_Peer ipc SIPC_EXPAND_ARG_LIST(__VA_ARGS__)) {\
141 return ipc_call_fmt(ipc, SIPC_FUNCTION(handle) SIPC_EXPAND_PARAM_LIST(__VA_ARGS__));\
142 }
143#else
144#define DECLARE_IPC_FUNCTION(handle,...)\
145 extern SIPC_Function * g_ipc_func_##handle;\
146 extern int32_t call_##handle(SIPC_Peer ipc SIPC_EXPAND_ARG_LIST(__VA_ARGS__));
147#endif
148
149#define EXPORT_IPC_FUNCTION(handle,...) \
150 extern int32_t on_##handle(SIPC_Peer ipc SIPC_EXPAND_ARG_LIST(__VA_ARGS__));\
151 static int32_t _ipc_handle_##handle(SIPC_Peer ipc, void * buf, int len) {\
152 SIPC_EXPAND_PARAM_DECLARE_LIST(__VA_ARGS__) \
153 int32_t r = ipc_upack_args(buf,len,SIPC_EXPAND_PARAM_STRID(__VA_ARGS__) "" SIPC_EXPAND_PARAM_REF_LIST(__VA_ARGS__));\
154 if (r >= 0) \
155 r = on_##handle(ipc SIPC_EXPAND_PARAM_LIST(__VA_ARGS__)); \
156 return r;\
157 }\
158 static SIPC_Function _ipc_exp_func_##handle = {#handle, _ipc_handle_##handle, "" SIPC_EXPAND_PARAM_STRID(__VA_ARGS__)};\
159 SIPC_Function *g_ipc_exp_func_##handle __attribute__((section("ipc_function_export_table"))) = &_ipc_exp_func_##handle;\
160
161
162typedef struct SIPC_HandleInternal* SIPC_Handle;
163typedef struct SIPC_PeerInternal* SIPC_Peer;
164typedef struct _SIPC_Function SIPC_Function;
165
166struct _SIPC_Function {
167 const char * name;
168 int32_t (*handle)(SIPC_Peer , void *, int );
169 const char * argfmt;
170 int call_id;
171 struct _SIPC_Function * next;
172};
173
174// user data type can be registered
175struct SIPC_DataType {
176 int type_id;
177 int len;
178 int32_t (*pack)(struct SIPC_DataType*, void *, int , va_list *);
179 int32_t (*upack)(struct SIPC_DataType*, void *, int , va_list *);
180 void (*free)(void *obj);
181};
182
183#define SIPC_NO_ERR 0
184#define SIPC_ERR_PARAM -1
185#define SIPC_ERR_IO -2
186#define SIPC_ERR_DATA -3
187#define SIPC_ERR_NO_FUNC -4
188#define SIPC_ERR_DUP_FUNC -5
189#define SIPC_ERR_NO_IMPL -6
190
191// create communication channel
192SIPC_Handle ipc_create_channel(const char * bindaddr);
193void ipc_stop_channel(SIPC_Handle serv);
194// open a peer channel to make IPC call
195SIPC_Peer ipc_open_peer(SIPC_Handle serv, const char * remoteaddr);
196void ipc_close_peer(SIPC_Peer ipc);
197// run the main loop, it will not return
198int32_t ipc_run_loop(SIPC_Handle serv);
199// exit the most inner loop, return loop level
200int32_t ipc_exit_inner_loop(SIPC_Handle serv);
201// get the socket fd which can be used in select/poll
202// this makes it possible to avoid a dedicate thread to run ipc_run_loop
203int ipc_socket_getfd(SIPC_Handle serv);
204// call this function if select/poll success on the socket fd
205int32_t ipc_socket_handle(SIPC_Handle serv);
206// register function calls, the memory of SIPC_Function shall keep valid and untouched until ipc_socket_close
207int32_t ipc_register_call(SIPC_Handle serv, SIPC_Function * func);
208// call IPC function with parameters
209int32_t ipc_call_va(SIPC_Peer ipc, SIPC_Function * func, va_list va);
210int32_t ipc_call_fmt(SIPC_Peer ipc, SIPC_Function * func, ...);
211// pack and unpack IPC parameters
212int32_t ipc_pack_va(void * buf, int len, const char * fmt, va_list va);
213int32_t ipc_pack_args(void * buf, int len, const char * fmt, ...);
214int32_t ipc_upack_va(void * buf, int len, const char * fmt, va_list va);
215int32_t ipc_upack_args(void * buf, int len, const char * fmt, ...);
216
217DECLARE_IPC_FUNCTION(_call,i32,i32,str);
218DECLARE_IPC_FUNCTION(_local,i32,ptr);
219DECLARE_IPC_FUNCTION(_ping,ptr);
220DECLARE_IPC_FUNCTION(_ping_back,ptr);
221
222#ifdef SIPC_IMPLEMENTATION
223static int SIPC_LOG_LEVEL = -1;
224#define SIPC_LOG(lev,fmt, ...) do {\
225 if (lev<SIPC_LOG_LEVEL)\
226 printf(fmt "\n", ## __VA_ARGS__);\
227 else if (SIPC_LOG_LEVEL == -1) {\
228 const char * level = getenv("SIPC_LOG_LEVEL");\
229 SIPC_LOG_LEVEL= level?atoi(level):2;\
230 }\
231} while (0)
232#define SIPC_LOG0(fmt, ...) SIPC_LOG(0, fmt, ## __VA_ARGS__)
233#define SIPC_LOG1(fmt, ...) SIPC_LOG(1, fmt, ## __VA_ARGS__)
234#define SIPC_LOG2(fmt, ...) SIPC_LOG(2, fmt, ## __VA_ARGS__)
235#define SIPC_LOG3(fmt, ...) SIPC_LOG(3, fmt, ## __VA_ARGS__)
236#define SIPC_LOG4(fmt, ...) SIPC_LOG(4, fmt, ## __VA_ARGS__)
237
238struct SIPC_PeerInternal {
239 int32_t client_id;
240 SIPC_Handle serv;
241 SIPC_Function * func_table;
242 struct sockaddr_un peer_addr;
243 SIPC_Peer next;
244};
245
246struct SIPC_HandleInternal {
247 int32_t server_id;
248 int sockfd;
249 struct SIPC_PeerInternal self;
250 SIPC_Function * func_table;
251 SIPC_Peer peers;
252 int loop_level;
253};
254
255static int32_t _ipc_pack_number(struct SIPC_DataType * type, void * buf, int len, va_list * va) {
256 if (len < type->len)
257 return SIPC_ERR_PARAM;
258 uint64_t val64 = (type->len == 8)?va_arg(*va, uint64_t):va_arg(*va, uint32_t);
259 uint8_t * p = (uint8_t*)&val64;
260 for (int n = type->len; n--; ) {
261 ((uint8_t*)buf)[n] = *p++;
262 }
263 return type->len;
264}
265
266static int32_t _ipc_upack_number(struct SIPC_DataType * type, void * buf, int len, va_list *va) {
267 if (len < type->len)
268 return SIPC_ERR_PARAM;
269 uint8_t * pval = va_arg(*va, void*);
270 for (int n = type->len; n--; ) {
271 *pval++ = ((uint8_t*)buf)[n];
272 }
273 return type->len;
274}
275
276static int32_t _ipc_pack_str(struct SIPC_DataType * type, void * buf, int len, va_list *va) {
277 (void)type;
278 char* ptr = va_arg(*va, char*);
279 int32_t tlen = snprintf(buf,len,"%s",ptr) + 1;
280 if (len < tlen)
281 tlen= SIPC_ERR_PARAM;
282 return tlen;
283}
284
285static int32_t _ipc_upack_str(struct SIPC_DataType * type, void * buf, int len, va_list *va) {
286 (void)type;
287 int32_t tlen = strnlen(buf,len)+1;
288 if (len < tlen)
289 return SIPC_ERR_PARAM;
290 char **pptr = va_arg(*va, char**);
291 *pptr = buf;
292 return tlen;
293}
294
295static int32_t _ipc_pack_pointer(struct SIPC_DataType * type, void * buf, int len, va_list *va) {
296 (void)type;
297 void* ptr = va_arg(*va, void*);
298 int32_t tlen = va_arg(*va,int32_t);
299 if ((tlen<0) || (len < tlen+4))
300 return SIPC_ERR_PARAM;
301 ((uint8_t*)buf)[0] = ((uint8_t*)&tlen)[3];
302 ((uint8_t*)buf)[1] = ((uint8_t*)&tlen)[2];
303 ((uint8_t*)buf)[2] = ((uint8_t*)&tlen)[1];
304 ((uint8_t*)buf)[3] = ((uint8_t*)&tlen)[0];
305 memcpy((uint8_t*)buf+4,ptr,tlen);
306 return tlen+4;
307}
308
309static int32_t _ipc_upack_pointer(struct SIPC_DataType * type, void * buf, int len, va_list *va) {
310 (void)type;
311 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]);
312 if ((tlen<0) && (len < tlen+4))
313 return SIPC_ERR_PARAM;
314 void ** ptr = va_arg(*va, void**);
315 int32_t * plen = va_arg(*va, int32_t*);
316 *ptr = tlen ? buf + 4 : NULL;
317 *plen = tlen;
318 return tlen+4;
319}
320
321static struct SIPC_DataType g_ipc_buildin_types[] = {
322 {0},
323 {SIPC_TYPE_ID(i8),1,_ipc_pack_number,_ipc_upack_number,0},
324 {SIPC_TYPE_ID(u8),1,_ipc_pack_number,_ipc_upack_number,0},
325 {SIPC_TYPE_ID(i16),2,_ipc_pack_number,_ipc_upack_number,0},
326 {SIPC_TYPE_ID(u16),2,_ipc_pack_number,_ipc_upack_number,0},
327 {SIPC_TYPE_ID(i32),4,_ipc_pack_number,_ipc_upack_number,0},
328 {SIPC_TYPE_ID(u32),4,_ipc_pack_number,_ipc_upack_number,0},
329 {SIPC_TYPE_ID(i64),8,_ipc_pack_number,_ipc_upack_number,0},
330 {SIPC_TYPE_ID(u64),8,_ipc_pack_number,_ipc_upack_number,0},
331 {SIPC_TYPE_ID(str),4,_ipc_pack_str,_ipc_upack_str,0},
332 {SIPC_TYPE_ID(ptr),4,_ipc_pack_pointer,_ipc_upack_pointer,0},
333};
334
335int32_t ipc_pack_args(void * buf, int len, const char * fmt, ...) {
336 va_list ap;
337 va_start(ap, fmt);
338 int32_t r = ipc_pack_va(buf,len,fmt,ap);
339 va_end(ap);
340 return r;
341}
342
343int32_t ipc_pack_va(void * buf, int len, const char * fmt, va_list va)
344{
345 int tlen = 0;
346 int32_t ret = 0;
347 int ch;
348 while ((ch=*fmt++)!='\0') {
349 if ((ch >= SIPC_TYPE_ID(i8)) && (ch <= SIPC_TYPE_ID(ptr))) {
350 tlen = g_ipc_buildin_types[ch].pack(&g_ipc_buildin_types[ch], buf, len,&va);
351 } else {
352 SIPC_LOG1("TODO: customer type");
353 tlen = SIPC_ERR_NO_IMPL;
354 }
355 if (tlen <= 0)
356 break;
357 len -= tlen;
358 buf += tlen;
359 ret += tlen;
360 }
361 return ret;
362}
363
364int32_t ipc_upack_args(void * buf, int len, const char * fmt, ...) {
365 va_list ap;
366 va_start(ap, fmt);
367 int32_t r = ipc_upack_va(buf,len,fmt,ap);
368 va_end(ap);
369 return r;
370}
371
372int32_t ipc_upack_va(void * buf, int len, const char * fmt, va_list va)
373{
374 int ch;
375 int tlen = 0;
376 int32_t ret = 0;
377 while ((ch=*fmt++)!='\0') {
378 if ((ch >= SIPC_TYPE_ID(i8)) && (ch <= SIPC_TYPE_ID(ptr))) {
379 tlen = g_ipc_buildin_types[ch].upack(&g_ipc_buildin_types[ch], buf, len,&va);
380 } else {
381 SIPC_LOG1("TODO: customer type");
382 tlen = SIPC_ERR_NO_IMPL;
383 }
384 if (tlen <= 0)
385 break;
386 len -= tlen;
387 buf += tlen;
388 ret += tlen;
389 }
390 return ret;
391}
392
393SIPC_Handle ipc_create_channel(const char * bindaddr)
394{
395 int unix_socket = socket(AF_UNIX, SOCK_DGRAM, 0);
396 if (unix_socket < 0) {
397 SIPC_LOG1("failed to open socket %d %s", errno, strerror(errno));
398 goto error;
399 }
400 struct sockaddr_un addr;
401 addr.sun_family = AF_UNIX;
402 if (bindaddr) {
403 snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", bindaddr);
404 unlink(bindaddr);
405 if (bind(unix_socket, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
406 SIPC_LOG1("bind to %s fail %d %s", bindaddr, errno, strerror(errno));
407 goto error;
408 }
409 }
410 struct SIPC_HandleInternal * serv = malloc(sizeof(*serv));
411 memset(serv, 0, sizeof(*serv));
412 memcpy(&serv->self.peer_addr, &addr, sizeof(addr));
413 serv->sockfd = unix_socket;
414 serv->peers = NULL;
415 serv->func_table = NULL;
416 serv->self.serv = serv;
417
418 return serv;
419
420error:
421 if (unix_socket >= 0) {
422 close(unix_socket);
423 }
424 return NULL;
425}
426
427SIPC_Peer ipc_open_peer(SIPC_Handle serv, const char * remoteaddr)
428{
429 SIPC_Peer ipc = serv->peers;
430 for (; ipc; ipc=ipc->next) {
431 if (strcmp(ipc->peer_addr.sun_path, remoteaddr) == 0)
432 return ipc;
433 }
434 ipc = malloc(sizeof(*ipc));
435 memset(ipc, 0, sizeof(*ipc));
436 ipc->serv = serv;
437 ipc->next = serv->peers;
438 ipc->peer_addr.sun_family = AF_UNIX;
439 snprintf(ipc->peer_addr.sun_path, sizeof(ipc->peer_addr.sun_path), "%s", remoteaddr);
440 serv->peers = ipc;
441 return ipc;
442}
443
444void ipc_close_peer(SIPC_Peer ipc)
445{
446 SIPC_Peer ch = ipc->serv->peers;
447 if (ch == ipc)
448 ipc->serv->peers = ch->next;
449 else if (ch) {
450 for (; ch->next; ch=ch->next) {
451 if (ch->next == ipc) {
452 ch->next = ipc->next;
453 break;
454 }
455 }
456 }
457 free(ipc);
458}
459
460void ipc_stop_channel(SIPC_Handle serv)
461{
462 if (serv->sockfd >= 0) {
463 close(serv->sockfd);
464 serv->sockfd = -1;
465 }
466 while (serv->peers) {
467 SIPC_Peer ipc = serv->peers;
468 serv->peers = ipc->next;
469 ipc_close_peer(ipc);
470 }
471}
472
473int32_t ipc_run_loop(SIPC_Handle serv)
474{
475 int cur_loop = serv->loop_level++;
476 while (cur_loop < serv->loop_level) {
477 int r = ipc_socket_handle(serv);
478 (void)r;
479 }
480 return 0;
481}
482
483int32_t ipc_exit_inner_loop(SIPC_Handle serv)
484{
485 serv->loop_level--;
486 call__local(&serv->self,0,NULL,0);
487 return 0;
488}
489
490int ipc_socket_getfd(SIPC_Handle serv)
491{
492 return serv->sockfd;
493}
494
495// clientid,callid,name
496int32_t ipc_socket_handle(SIPC_Handle serv)
497{
498 char buf[1024*8];
499 struct SIPC_PeerInternal tempChannel;
500 socklen_t addrlen = sizeof(tempChannel.peer_addr);
501 int len = recvfrom(serv->sockfd, buf, sizeof(buf), MSG_NOSIGNAL, (struct sockaddr *)&tempChannel.peer_addr, &addrlen);
502 int32_t client_id;
503 int32_t call_id;
504 char * name;
505 int len1 = ipc_upack_args(buf, len, SIPC_FUNCTION(_call)->argfmt, &client_id, &call_id, &name);
506 if (len1 <= 0) {
507 SIPC_LOG2("data format error");
508 return SIPC_ERR_DATA;
509 }
510 SIPC_LOG3("received call %s %d bytes from %s", name, len, tempChannel.peer_addr.sun_path);
511 if (SIPC_LOG_LEVEL > 3) {
512 int i;
513 char msg[len*3 + 1], *p = msg;
514 for (i=0; i<len; ++i) {
515 p += sprintf(p, "%02x ", (uint8_t)buf[i]);
516 }
517 SIPC_LOG4("%s",msg);
518 }
519 SIPC_Peer ipc = NULL;
520 if (client_id == 0) {
521 ipc = &tempChannel;
522 ipc->serv = serv;
523 ipc->next = NULL;
524 ipc->client_id = 0;
525 ipc->func_table = NULL;
526 } else {
527 for (ipc=serv->peers; ipc; ipc=ipc->next) {
528 if (ipc->client_id == client_id)
529 break;
530 }
531 }
532 if (ipc == NULL) {
533 SIPC_LOG2("client_id %d not found", client_id);
534 }
535 extern SIPC_Function *__start_ipc_function_export_table;
536 extern SIPC_Function *__stop_ipc_function_export_table;
537 //extern SIPC_Function *__start_ipc_function_import_table;
538 //extern SIPC_Function *__stop_ipc_function_import_table;
539 SIPC_Function * f = NULL;
540 SIPC_Function ** ppfunc = &__start_ipc_function_export_table;
541 for (;ppfunc<&__stop_ipc_function_export_table;++ppfunc) {
542 if (strcmp((*ppfunc)->name, name) == 0) {
543 f = *ppfunc;
544 break;
545 }
546 }
547 if (f == NULL) {
548 for (f=serv->func_table; f; f=f->next) {
549 if (strcmp(f->name, name) == 0) {
550 break;
551 }
552 }
553 }
554 if (f == NULL) {
555 SIPC_LOG2("can't find function %s", (char*)name);
556 return SIPC_ERR_NO_FUNC;
557 }
558 return f->handle(ipc, buf+len1, len-len1);
559}
560
561int32_t ipc_register_call(SIPC_Handle serv, SIPC_Function * func)
562{
563 SIPC_Function *f;
564 for (f=serv->func_table; f != NULL; f = f->next) {
565 if ((f == func) || (strcmp(f->name, func->name)==0)) {
566 SIPC_LOG1("try to register IPC function %s multiple time, %p %p\n", func->name, f, func);
567 return SIPC_ERR_DUP_FUNC;
568 }
569 }
570 func->next = serv->func_table;
571 serv->func_table = func;
572 return 0;
573}
574
575int32_t ipc_call_va(SIPC_Peer ipc, SIPC_Function * func, va_list va)
576{
577 char buf[1024*8];
578 int len = sizeof(buf);
579 int len1 = ipc_pack_args(buf, len, SIPC_FUNCTION(_call)->argfmt, ipc->client_id, func->call_id, func->name);
580 if (len1 <= 0) {
581 SIPC_LOG2("call ipc_pack_args header failed");
582 return len1;
583 }
584 int len2 = ipc_pack_va(buf+len1, len-len1, func->argfmt, va);
585 if (len2 < 0) {
586 SIPC_LOG2("call ipc_pack_args params failed");
587 return len2;
588 }
589 int wlen = sendto(ipc->serv->sockfd, buf, len1+len2, MSG_NOSIGNAL, (struct sockaddr *)&ipc->peer_addr, sizeof(ipc->peer_addr));
590 SIPC_LOG3("call %s, send %d bytes to %s, return %d", func->name, len1+len2, ipc->peer_addr.sun_path, wlen);
591 if (SIPC_LOG_LEVEL > 3) {
592 int i = len1+len2;
593 char msg[i*3 + 1], *p = msg;
594 for (i=0; i<len1+len2; ++i) {
595 p += sprintf(p, "%02x ", (uint8_t)buf[i]);
596 }
597 SIPC_LOG4("%s",msg);
598 }
599 if (wlen != len1+len2) {
600 SIPC_LOG2("send data fail %d != %d + %d, err %d %s", wlen, len1, len2, errno, strerror(errno));
601 return SIPC_ERR_IO;
602 }
603 return 0;
604}
605
606int32_t ipc_call_fmt(SIPC_Peer ipc, SIPC_Function * func, ...) {
607 va_list ap;
608 va_start(ap, func);
609 int32_t r = ipc_call_va(ipc,func,ap);
610 va_end(ap);
611 return r;
612}
613
614EXPORT_IPC_FUNCTION(_local,i32,ptr);
615EXPORT_IPC_FUNCTION(_ping,ptr);
616EXPORT_IPC_FUNCTION(_ping_back,ptr);
617
618int32_t on__ping(SIPC_Peer ipc, void * data, int32_t len)
619{
620 SIPC_LOG3("client %p ping %p %d", ipc, data, len);
621 call__ping_back(ipc, data, len);
622 return 0;
623}
624
625int32_t on__ping_back(SIPC_Peer ipc, void * data, int32_t len)
626{
627 SIPC_LOG3("client %p ping back %p %d", ipc, data, len);
628 return 0;
629}
630
631int32_t on__local(SIPC_Peer ipc, int32_t cmd, void * data, int32_t len)
632{
633 SIPC_LOG3("client %p call local %d %p %d", ipc, cmd, data, len);
634 return 0;
635}
636
637
638
639#endif
640
641#ifdef __cplusplus
642} /* extern "C" */
643#endif
644
645#endif /* end of include guard: SOCKETIPC_H */