1
0
mirror of https://github.com/haiwen/libsearpc.git synced 2025-08-22 14:15:51 +00:00

Compare commits

...

76 Commits

Author SHA1 Message Date
rumtid
d799dff145
Update build configurations of DEBUG profile (#77) 2025-05-24 12:05:22 +08:00
rumtid
6f06843849
Upgrade vcpkg (#76) 2025-03-03 17:04:23 +08:00
feiniks
255d5dedd2
Modify slow log format (#75)
Co-authored-by: 杨赫然 <heran.yang@seafile.com>
2025-01-22 14:16:31 +08:00
feiniks
0deb45d89f
Set slow threshold when log to stdout (#74)
* Set slow threshold when log to stdout

* Adjust code

---------

Co-authored-by: 杨赫然 <heran.yang@seafile.com>
2025-01-18 14:50:13 +08:00
feiniks
36706a9f32
Clean log (#73)
Co-authored-by: 杨赫然 <heran.yang@seafile.com>
2024-12-31 12:17:10 +08:00
Moritz Schlarb
d00c062d76
Update searpc-named-pipe-transport.c (#68)
Use g_realloc in named_pipe_client_handler
2024-10-31 12:25:46 +08:00
feiniks
7f275255f0
Add log to stdout (#72)
Co-authored-by: 杨赫然 <heran.yang@seafile.com>
2024-10-24 11:08:23 +08:00
feiniks
c917575246
Support write with non-blocking (#71)
* Support write with non-blocking

* Blocking read and write socket

---------

Co-authored-by: 杨赫然 <heran.yang@seafile.com>
2024-09-27 17:18:49 +08:00
feiniks
ed12cfba81
Use epoll to support multiple connections (#70)
* Use epoll to support multiple connections

* Set socket to nonblocking and re-add socket to epoll

* Support reading request length

* Use data->len directly

---------

Co-authored-by: 杨赫然 <heran.yang@seafile.com>
2024-07-26 18:41:39 +08:00
feiniks
4ccd1988d8
Delete DESTDIR in libsearpc.pc (#66)
Co-authored-by: 杨赫然 <heran.yang@seafile.com>
2024-04-19 18:11:58 +08:00
feiniks
7fd078664b
Print log when thread pool is full (#67)
Co-authored-by: 杨赫然 <heran.yang@seafile.com>
2024-04-19 18:03:53 +08:00
feiniks
cb1ffb2676
Merge pull request #63 from orbea/clang
Fix -Werror=strict-prototypes and -Werror=implicit-function-declaration
2023-12-21 11:26:30 +08:00
feiniks
783141fb69
Close socket when failed to connect name pipe (#65)
Co-authored-by: heran yang <heran.yang@seafile.com>
2023-05-27 14:57:05 +08:00
feiniks
d6ba8f60dc
Support compile universal (#64)
Co-authored-by: yangheran <heran.yang@seafile.com>
2023-05-13 17:32:55 +08:00
orbea
d78aede0e4 Fix -Werror=implicit-function-declaration
unistd.h is needed for write, close and read
2023-04-08 17:24:21 -07:00
orbea
ae466d2b3b Fix -Werror=strict-prototypes 2023-04-08 17:22:44 -07:00
Dmitry Bolshakov
97e15aa5a9
Waiting with WaitNamedPipe() if a named pipe is busy (#62)
Co-authored-by: Dmitry Bolshakov <d.bolshakov@bi.zone>
2023-02-24 12:03:43 +08:00
feiniks
15f6f0b9f4
Filter rpc slow log include password (#61)
* Filter rpc slow log include password

* Add filtered funcs list

Co-authored-by: 杨赫然 <heran.yang@seafile.com>
2022-09-02 18:01:40 +08:00
feiniks
54145b03f4
Add support c++ compile (#60) 2022-04-25 11:58:24 +08:00
sun20121818
e72c1158c8
Change slow log format (#58) 2021-10-08 16:29:52 +08:00
sun20121818
e889dbcb50
Configure x64-debug build (#56) 2020-10-26 14:38:58 +08:00
Xiangyue Cai
50ff08b03c
add --with-python3 option (#55)
* add --with-python3 option

* debian package with python3
2020-06-18 11:23:11 +08:00
Xiangyue Cai
29f0c14b37
only use python3 in linux (#54) 2020-06-17 16:56:04 +08:00
caixiangyue
7e2bcb0991 remove python3 future 2020-06-08 15:16:18 +08:00
Xiangyue Cai
b0079d2a0c
configure with python3 (#53)
* configure with python3

* remove future
2020-06-08 15:09:06 +08:00
Xiangyue Cai
9a307a916c
Fixed python-searpc installation place (#52) 2020-06-05 16:56:35 +08:00
Xiangyue Cai
719921a984
use python3 (#51) 2020-06-03 22:10:34 +08:00
caixiangyue
c5d031eaa2 remove dependency: python-future 2020-06-02 16:52:10 +08:00
Jonathan Xu
d1fd7518a2 Merge branch 'portable-vs' 2020-03-20 16:01:27 +08:00
sun
9e62d54bcf Changed the directory of the target file 2019-12-19 11:56:40 +08:00
sun
c206362c99 Configure x64 release 2019-12-17 17:55:48 +08:00
caixiangyue
c72e6b6978 support x64 2019-12-02 16:34:14 +08:00
Jiaqiang Xu
35a19401d6
Merge pull request #48 from haiwen/fix_mem_leak
Fix memory leak.
2019-11-01 18:00:22 +08:00
caixiangyue
8b853cf41d export to generate lib 2019-11-01 15:52:36 +08:00
caixiangyue
3291d04cec libsearpc portable visual studio 2019-11-01 14:58:00 +08:00
ly1217
9b2e2dc652 Fix memory leak. 2019-10-31 00:31:38 -07:00
caixiangyue
23f581b39f Update version to 3.2.0 2019-10-24 11:05:55 +08:00
Jiaqiang Xu
501fa31d03
Merge pull request #47 from haiwen/optimize_named_pipe_server
Optimize name pipe server.
2019-10-19 14:28:44 +08:00
ly1217
f7c20fa391 Optimize name pipe server. 2019-10-18 23:16:32 -07:00
Jiaqiang Xu
fbbdafd2ab
Merge pull request #46 from haiwen/fixed-dependency-relationship
Debian: fixed pysearpc dependency relationship
2019-10-18 11:57:10 +08:00
caixiangyue
f10068c3f6 Debian: fixed pysearpc dependency relationship 2019-10-18 10:37:33 +08:00
Jiaqiang Xu
fb7242cd09
Merge pull request #45 from haiwen/update-dependency
add Build-Depends: python-future
2019-10-17 15:33:14 +08:00
caixiangyue
b4b8548368 add Build-Depends: python-future 2019-10-17 15:12:44 +08:00
Jiaqiang Xu
317877f996
Merge pull request #44 from haiwen/fix_memory_leak
Fix memory leak.
2019-09-25 12:04:37 +08:00
ly1217
19598f1d9d Fix memory leak. 2019-09-24 20:16:38 -07:00
Jiaqiang Xu
12d4c33f6e
Merge pull request #43 from haiwen/fix_test_error
Fix tests error.
2019-09-11 18:01:59 +08:00
ly1217
60ba8eca57 Fix tests error. 2019-09-11 01:48:20 -07:00
Jiaqiang Xu
5b21fe6e69
Merge pull request #41 from haiwen/add_named_pipe_server_thread_pool
Add named pipe server thread pool.
2019-09-11 14:55:28 +08:00
ly1217
1239667823 Add named pipe server thread pool. 2019-09-10 23:48:04 -07:00
Jiaqiang Xu
c137594507
Merge pull request #42 from haiwen/json_t_is_null
handle json is null
2019-09-10 11:09:57 +08:00
Xiangyue Cai
faaff4cf7b handle json is null 2019-09-10 10:48:10 +08:00
Jonathan Xu
c185be9413 Merge branch 'python3' 2019-07-25 12:10:31 +08:00
Jiaqiang Xu
2803f8d5cf
Merge pull request #40 from haiwen/fix-named-pipe-transport
Fix named pipe transport
2019-07-19 15:31:10 +08:00
Jonathan Xu
2e1f32b83a Change system error messages to US English. 2019-07-19 15:27:58 +08:00
Jonathan Xu
0c26e154cb Remove debug messages in named pipe transport. 2019-07-18 10:44:49 +08:00
Jonathan Xu
c161cb90a5 Remove G_LOG_DOMAIN, use default log domain. 2019-07-12 17:03:28 +08:00
Shuai Lin
212281a882 Fixed windows named pipe transport
pipe_write_n should return -1 on error
2019-07-09 15:30:25 +08:00
Jonathan Xu
361fdf86de [pysearpc] Improve code of named_pipe transport. 2019-07-01 15:39:26 +08:00
Jonathan Xu
e0d45991aa [pysearpc] Use connection pool in NamedPipeClient. 2019-06-25 16:42:13 +08:00
Jonathan Xu
20be6d2edf [pysearpc] Add test for unicode string. 2019-06-17 10:40:34 +08:00
Jonathan Xu
6c5fea320c [CI] Pip install future package in travis CI. 2019-06-06 18:28:03 +08:00
Jonathan Xu
bc8f815777 [py] Use bytearray for better performance when recv() from socket. 2019-06-06 18:11:33 +08:00
Shuai Lin
777c9accaa
Updated travis.yml to run for both python 2/3 (#39) 2019-06-06 17:57:53 +08:00
Jonathan Xu
ac0750d058 Support python 3 in pysearpc. 2019-06-06 17:36:19 +08:00
Daniel Pan
4f32f8be00
Merge pull request #37 from esell/master
fix sed in Makefile for FreeBSD
2019-02-28 10:28:28 +08:00
esell
ebe09c82d5
tabs, not spaces :( 2019-02-27 15:52:18 -07:00
esell
55b97e1849
fix sed in Makefile for FreeBSD 2019-02-27 15:27:52 -07:00
Jiaqiang Xu
85127befda
Merge pull request #36 from haiwen/fix_slow_log_unit
Fix the unit of slow log threshold.
2018-12-25 10:50:27 +08:00
ly1217
474bf337d8 Fix the unit of slow log threshold. 2018-12-25 10:44:41 +08:00
Jonathan Xu
22cfe9adbe Add slow log support. 2018-12-21 18:38:38 +08:00
Jonathan Xu
041fd68e1c Fix variable sizes in named pipe transport.
Should use 32-bit integer to store the length header in transport protocol.
2018-11-15 17:50:10 +08:00
Jiaqiang Xu
d19a3d1a2c
Merge pull request #35 from haiwen/revert-30-patch-1
Revert "Fix variable types and pointer sizes"
2018-11-15 14:29:41 +08:00
Jiaqiang Xu
980203eaf7
Revert "Fix variable types and pointer sizes" 2018-11-15 14:29:22 +08:00
Jiaqiang Xu
45bdce573f
Merge pull request #30 from moschlar/patch-1
Fix variable types and pointer sizes
2018-11-09 17:00:48 +08:00
Moritz Schlarb
10e7432cab Fix variable types and pointer sizes
Thanks to Adrian Bunk for pointing these out in
http://bugs.debian.org/895467
2018-10-03 10:27:34 +02:00
Jiaqiang Xu
2021fe4aa8 [pysearpc] Support json return type. (#33)
* [pysearpc] Support json return type.

* Added tests for json return type
2018-08-22 18:24:32 +08:00
32 changed files with 950 additions and 218 deletions

View File

@ -1,5 +1,9 @@
sudo: false sudo: false
language: python language: python
python:
- "2.7"
- "3.5"
- "3.6"
compiler: compiler:
- gcc - gcc
- clang - clang
@ -7,6 +11,8 @@ addons:
apt: apt:
packages: packages:
- libjansson-dev - libjansson-dev
install:
- pip install future
before_install: before_install:
- git clean -x -f - git clean -x -f
- ./autogen.sh - ./autogen.sh

View File

@ -18,12 +18,5 @@ endif
SUBDIRS = lib pysearpc ${MAKE_DEMO} tests SUBDIRS = lib pysearpc ${MAKE_DEMO} tests
install-data-local:
if MACOS
sed -i '' -e "s|(DESTDIR)|${DESTDIR}|g" $(pcfiles)
else
${SED} -i "s|(DESTDIR)|${DESTDIR}|g" $(pcfiles)
endif
dist-hook: dist-hook:
git log -1 > $(distdir)/latest_commit git log -1 > $(distdir)/latest_commit

View File

@ -42,6 +42,15 @@ AC_ARG_ENABLE(server-pkg,
AC_HELP_STRING([--enable-server-pkg], [enable static compile]), AC_HELP_STRING([--enable-server-pkg], [enable static compile]),
[server_pkg=$enableval],[server_pkg="no"]) [server_pkg=$enableval],[server_pkg="no"])
# option: compile-universal
# default: no
AC_ARG_ENABLE([compile-universal],
[AS_HELP_STRING([--enable-compile-universal],
[compile seafile universal @<:@default: no@:>@])],
[compile_universal=${enableval}], [compile_universal=no])
AM_CONDITIONAL([COMPILE_UNIVERSAL], [test x${compile_universal} = xyes])
dnl - check if the macro WIN32 is defined on this compiler. dnl - check if the macro WIN32 is defined on this compiler.
AC_MSG_CHECKING(for WIN32) AC_MSG_CHECKING(for WIN32)
@ -69,6 +78,23 @@ fi
AM_CONDITIONAL([MACOS], [test "$bmac" = "yes"]) AM_CONDITIONAL([MACOS], [test "$bmac" = "yes"])
AC_SUBST(MACOS) AC_SUBST(MACOS)
AC_MSG_CHECKING(for FreeBSD)
if test "$(uname -s)" = "FreeBSD"; then
bfbsd=yes
fi
if test x$bfbsd = "xyes"; then
server_pkg=no
AC_MSG_RESULT(compile in FreeBSD)
fi
AM_CONDITIONAL([FBSD], [test "$bfbsd" = "yes"])
AC_SUBST(FBSD)
AC_ARG_WITH([python3], [AS_HELP_STRING([--with-python3], [use python3])],
[with_python3="yes"],[])
# Checks for libraries. # Checks for libraries.
GLIB_REQUIRED=2.26.0 GLIB_REQUIRED=2.26.0
@ -84,7 +110,12 @@ PKG_CHECK_MODULES(JANSSON, [jansson >= $JANSSON_REQUIRED])
AC_SUBST(JANSSON_CFLAGS) AC_SUBST(JANSSON_CFLAGS)
AC_SUBST(JANSSON_LIBS) AC_SUBST(JANSSON_LIBS)
AM_PATH_PYTHON([2.4]) if test "$with_python3" = "yes"; then
AM_PATH_PYTHON([3.5])
else
AM_PATH_PYTHON([2.7])
fi
if test "$bwin32" = true; then if test "$bwin32" = true; then
if test x$PYTHON_DIR != x; then if test x$PYTHON_DIR != x; then
# set pyexecdir to somewhere like /c/Python26/Lib/site-packages # set pyexecdir to somewhere like /c/Python26/Lib/site-packages

6
debian/changelog vendored
View File

@ -1,3 +1,9 @@
libsearpc1 (3.2.0) unstable; urgency=low
* new upstream release
-- Jonathan Xu <jonathan.xu@seafile.com> Thu, 24 Oct 2019 11:05:10 +0800
libsearpc1 (3.1.0) unstable; urgency=low libsearpc1 (3.1.0) unstable; urgency=low
* new upstream release * new upstream release

7
debian/control vendored
View File

@ -4,10 +4,11 @@ Priority: extra
Maintainer: m.eik michalke <meik.michalke@hhu.de> Maintainer: m.eik michalke <meik.michalke@hhu.de>
Build-Depends: Build-Depends:
debhelper (>= 7), debhelper (>= 7),
dh-python,
autotools-dev, autotools-dev,
intltool, intltool,
libglib2.0-dev, libglib2.0-dev,
python, python3 (>= 3.5),
libtool, libtool,
libjansson-dev libjansson-dev
Standards-Version: 3.9.5 Standards-Version: 3.9.5
@ -30,7 +31,7 @@ Section: libdevel
Architecture: any Architecture: any
Depends: Depends:
${misc:Depends}, ${misc:Depends},
python (>= 2.7), python3 (>= 3.5),
libsearpc1 (= ${binary:Version}) libsearpc1 (= ${binary:Version})
Conflicts: seafile Conflicts: seafile
Description: Development files for the libsearpc1 package. Description: Development files for the libsearpc1 package.
@ -49,7 +50,7 @@ Package: python-searpc
Section: python Section: python
Multi-Arch: foreign Multi-Arch: foreign
Architecture: all Architecture: all
Depends: ${python:Depends}, Depends: ${python3:Depends},
${shlibs:Depends}, ${shlibs:Depends},
${misc:Depends} ${misc:Depends}
Description: simple and easy-to-use C language RPC framework Description: simple and easy-to-use C language RPC framework

View File

@ -1 +1 @@
usr/lib/python*/dist-packages/pysearpc/*.py usr/lib/python3*/site-packages/pysearpc/*.py usr/lib/python3/dist-packages/pysearpc

4
debian/rules vendored
View File

@ -2,11 +2,11 @@
# -*- makefile -*- # -*- makefile -*-
%: %:
dh $@ --with python2 --with autotools_dev --builddirectory=build dh $@ --with python3 --with autotools_dev --builddirectory=build
override_dh_auto_configure: override_dh_auto_configure:
./autogen.sh ./autogen.sh
dh_auto_configure -- --disable-compile-demo dh_auto_configure -- --disable-compile-demo --with-python3
override_dh_strip: override_dh_strip:
# emptying the dependency_libs field in .la files # emptying the dependency_libs field in .la files

View File

@ -4,6 +4,7 @@
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <unistd.h>
#include <errno.h> #include <errno.h>
#ifdef WIN32 #ifdef WIN32

View File

@ -4,6 +4,8 @@
#include <glib.h> #include <glib.h>
#include <glib-object.h> #include <glib-object.h>
GType test_object_get_type (void);
#define TEST_OBJECT_TYPE (test_object_get_type()) #define TEST_OBJECT_TYPE (test_object_get_type())
#define TEST_OBJECT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TEST_OBJECT_TYPE, TestObject)) #define TEST_OBJECT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TEST_OBJECT_TYPE, TestObject))
#define IS_TEST_OBJCET(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TEST_OBJCET_TYPE)) #define IS_TEST_OBJCET(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TEST_OBJCET_TYPE))

View File

@ -2,8 +2,13 @@
AM_CFLAGS = @GLIB_CFLAGS@ \ AM_CFLAGS = @GLIB_CFLAGS@ \
@JANSSON_CFLAGS@ \ @JANSSON_CFLAGS@ \
-I${top_builddir}/lib \ -I${top_builddir}/lib \
-I${top_srcdir}/lib \ -I${top_srcdir}/lib
-DG_LOG_DOMAIN=\"Searpc\"
if MACOS
if COMPILE_UNIVERSAL
AM_CFLAGS += -arch x86_64 -arch arm64
endif
endif
lib_LTLIBRARIES = libsearpc.la lib_LTLIBRARIES = libsearpc.la

View File

@ -36,7 +36,7 @@ static void clean_objlist(GList *list)
SearpcClient * SearpcClient *
searpc_client_new () searpc_client_new (void)
{ {
return g_new0 (SearpcClient, 1); return g_new0 (SearpcClient, 1);
} }

View File

@ -5,6 +5,16 @@
#include <glib-object.h> #include <glib-object.h>
#include <jansson.h> #include <jansson.h>
#ifdef __cplusplus
extern "C" {
#endif
#ifdef LIBSEARPC_EXPORTS
#define LIBSEARPC_API __declspec(dllexport)
#else
#define LIBSEARPC_API
#endif
#ifndef DFT_DOMAIN #ifndef DFT_DOMAIN
#define DFT_DOMAIN g_quark_from_string(G_LOG_DOMAIN) #define DFT_DOMAIN g_quark_from_string(G_LOG_DOMAIN)
#endif #endif
@ -31,85 +41,88 @@ struct _SearpcClient {
void *async_arg; void *async_arg;
}; };
typedef struct _SearpcClient SearpcClient; typedef struct _SearpcClient LIBSEARPC_API SearpcClient;
SearpcClient *searpc_client_new (); LIBSEARPC_API
SearpcClient *searpc_client_new (void);
void searpc_client_free (SearpcClient *client); LIBSEARPC_API void
searpc_client_free (SearpcClient *client);
void LIBSEARPC_API void
searpc_client_call (SearpcClient *client, const char *fname, searpc_client_call (SearpcClient *client, const char *fname,
const char *ret_type, GType gobject_type, const char *ret_type, GType gobject_type,
void *ret_ptr, GError **error, void *ret_ptr, GError **error,
int n_params, ...); int n_params, ...);
int LIBSEARPC_API int
searpc_client_call__int (SearpcClient *client, const char *fname, searpc_client_call__int (SearpcClient *client, const char *fname,
GError **error, int n_params, ...); GError **error, int n_params, ...);
gint64 LIBSEARPC_API gint64
searpc_client_call__int64 (SearpcClient *client, const char *fname, searpc_client_call__int64 (SearpcClient *client, const char *fname,
GError **error, int n_params, ...); GError **error, int n_params, ...);
char * LIBSEARPC_API char *
searpc_client_call__string (SearpcClient *client, const char *fname, searpc_client_call__string (SearpcClient *client, const char *fname,
GError **error, int n_params, ...); GError **error, int n_params, ...);
GObject * LIBSEARPC_API GObject *
searpc_client_call__object (SearpcClient *client, const char *fname, searpc_client_call__object (SearpcClient *client, const char *fname,
GType object_type, GType object_type,
GError **error, int n_params, ...); GError **error, int n_params, ...);
GList* LIBSEARPC_API GList*
searpc_client_call__objlist (SearpcClient *client, const char *fname, searpc_client_call__objlist (SearpcClient *client, const char *fname,
GType object_type, GType object_type,
GError **error, int n_params, ...); GError **error, int n_params, ...);
json_t * LIBSEARPC_API json_t *
searpc_client_call__json (SearpcClient *client, const char *fname, searpc_client_call__json (SearpcClient *client, const char *fname,
GError **error, int n_params, ...); GError **error, int n_params, ...);
char* searpc_client_transport_send (SearpcClient *client, LIBSEARPC_API char*
searpc_client_transport_send (SearpcClient *client,
const gchar *fcall_str, const gchar *fcall_str,
size_t fcall_len, size_t fcall_len,
size_t *ret_len); size_t *ret_len);
int LIBSEARPC_API int
searpc_client_async_call__int (SearpcClient *client, searpc_client_async_call__int (SearpcClient *client,
const char *fname, const char *fname,
AsyncCallback callback, void *cbdata, AsyncCallback callback, void *cbdata,
int n_params, ...); int n_params, ...);
int LIBSEARPC_API int
searpc_client_async_call__int64 (SearpcClient *client, searpc_client_async_call__int64 (SearpcClient *client,
const char *fname, const char *fname,
AsyncCallback callback, void *cbdata, AsyncCallback callback, void *cbdata,
int n_params, ...); int n_params, ...);
int LIBSEARPC_API int
searpc_client_async_call__string (SearpcClient *client, searpc_client_async_call__string (SearpcClient *client,
const char *fname, const char *fname,
AsyncCallback callback, void *cbdata, AsyncCallback callback, void *cbdata,
int n_params, ...); int n_params, ...);
int LIBSEARPC_API int
searpc_client_async_call__object (SearpcClient *client, searpc_client_async_call__object (SearpcClient *client,
const char *fname, const char *fname,
AsyncCallback callback, AsyncCallback callback,
GType object_type, void *cbdata, GType object_type, void *cbdata,
int n_params, ...); int n_params, ...);
int LIBSEARPC_API int
searpc_client_async_call__objlist (SearpcClient *client, searpc_client_async_call__objlist (SearpcClient *client,
const char *fname, const char *fname,
AsyncCallback callback, AsyncCallback callback,
GType object_type, void *cbdata, GType object_type, void *cbdata,
int n_params, ...); int n_params, ...);
int LIBSEARPC_API int
searpc_client_async_call__json (SearpcClient *client, searpc_client_async_call__json (SearpcClient *client,
const char *fname, const char *fname,
AsyncCallback callback, void *cbdata, AsyncCallback callback, void *cbdata,
@ -118,7 +131,7 @@ searpc_client_async_call__json (SearpcClient *client,
/* called by the transport layer, the rpc layer should be able to /* called by the transport layer, the rpc layer should be able to
* modify the str, but not take ownership of it */ * modify the str, but not take ownership of it */
int LIBSEARPC_API int
searpc_client_generic_callback (char *retstr, size_t len, searpc_client_generic_callback (char *retstr, size_t len,
void *vdata, const char *errstr); void *vdata, const char *errstr);
@ -128,5 +141,9 @@ searpc_client_generic_callback (char *retstr, size_t len,
#define TRANSPORT_ERROR "Transport Error" #define TRANSPORT_ERROR "Transport Error"
#define TRANSPORT_ERROR_CODE 500 #define TRANSPORT_ERROR_CODE 500
#ifdef __cplusplus
}
#endif
#endif #endif

View File

@ -139,7 +139,7 @@ def generate_marshal_register_item(ret_type, arg_types):
signature_name=signature_name) signature_name=signature_name)
def gen_marshal_register_function(f): def gen_marshal_register_function(f):
write_file(f, "static void register_marshals()""") write_file(f, "static void register_marshals(void)""")
write_file(f, "{") write_file(f, "{")
for item in func_table: for item in func_table:
write_file(f, generate_marshal_register_item(item[0], item[1])) write_file(f, generate_marshal_register_item(item[0], item[1]))
@ -147,7 +147,7 @@ def gen_marshal_register_function(f):
signature_template = r""" signature_template = r"""
inline static gchar * inline static gchar *
${signature_name}() ${signature_name}(void)
{ {
return searpc_compute_signature (${args}); return searpc_compute_signature (${args});
} }

View File

@ -8,8 +8,13 @@
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/un.h> #include <sys/un.h>
#include <unistd.h> #include <unistd.h>
#ifdef __linux__
#include <fcntl.h>
#include <sys/epoll.h>
#endif
#endif // !defined(WIN32) #endif // !defined(WIN32)
#include <glib.h>
#include <glib/gstdio.h> #include <glib/gstdio.h>
#include <jansson.h> #include <jansson.h>
@ -32,7 +37,9 @@ static char* formatErrorMessage();
#endif // defined(WIN32) #endif // defined(WIN32)
static void* named_pipe_listen(void *arg); static void* named_pipe_listen(void *arg);
static void* named_pipe_client_handler(void *arg); static void* handle_named_pipe_client_with_thread (void *arg);
static void handle_named_pipe_client_with_threadpool(void *data, void *user_data);
static void named_pipe_client_handler (void *data);
static char* searpc_named_pipe_send(void *arg, const gchar *fcall_str, size_t fcall_len, size_t *ret_len); static char* searpc_named_pipe_send(void *arg, const gchar *fcall_str, size_t fcall_len, size_t *ret_len);
static char * request_to_json(const char *service, const char *fcall_str, size_t fcall_len); static char * request_to_json(const char *service, const char *fcall_str, size_t fcall_len);
@ -40,8 +47,8 @@ static int request_from_json (const char *content, size_t len, char **service, c
static void json_object_set_string_member (json_t *object, const char *key, const char *value); static void json_object_set_string_member (json_t *object, const char *key, const char *value);
static const char * json_object_get_string_member (json_t *object, const char *key); static const char * json_object_get_string_member (json_t *object, const char *key);
static ssize_t pipe_write_n(SearpcNamedPipe fd, const void *vptr, size_t n); static gssize pipe_write_n(SearpcNamedPipe fd, const void *vptr, size_t n);
static ssize_t pipe_read_n(SearpcNamedPipe fd, void *vptr, size_t n); static gssize pipe_read_n(SearpcNamedPipe fd, void *vptr, size_t n);
typedef struct { typedef struct {
SearpcNamedPipeClient* client; SearpcNamedPipeClient* client;
@ -74,6 +81,33 @@ SearpcNamedPipeServer* searpc_create_named_pipe_server(const char *path)
{ {
SearpcNamedPipeServer *server = g_malloc0(sizeof(SearpcNamedPipeServer)); SearpcNamedPipeServer *server = g_malloc0(sizeof(SearpcNamedPipeServer));
memcpy(server->path, path, strlen(path) + 1); memcpy(server->path, path, strlen(path) + 1);
return server;
}
SearpcNamedPipeServer* searpc_create_named_pipe_server_with_threadpool (const char *path, int named_pipe_server_thread_pool_size)
{
GError *error = NULL;
SearpcNamedPipeServer *server = g_malloc0(sizeof(SearpcNamedPipeServer));
memcpy(server->path, path, strlen(path) + 1);
server->pool_size = named_pipe_server_thread_pool_size;
server->named_pipe_server_thread_pool = g_thread_pool_new (handle_named_pipe_client_with_threadpool,
NULL,
named_pipe_server_thread_pool_size,
FALSE,
&error);
if (!server->named_pipe_server_thread_pool) {
if (error) {
g_warning ("Falied to create named pipe server thread pool : %s\n", error->message);
g_clear_error (&error);
} else {
g_warning ("Falied to create named pipe server thread pool.\n");
}
g_free (server);
return NULL;
}
return server; return server;
} }
@ -99,7 +133,7 @@ int searpc_named_pipe_server_start(SearpcNamedPipeServer *server)
} }
if (g_file_test (un_path, G_FILE_TEST_EXISTS)) { if (g_file_test (un_path, G_FILE_TEST_EXISTS)) {
g_debug ("socket file exists, delete it anyway\n"); g_message ("socket file exists, delete it anyway\n");
if (g_unlink (un_path) < 0) { if (g_unlink (un_path) < 0) {
g_warning ("delete socket file failed : %s\n", strerror(errno)); g_warning ("delete socket file failed : %s\n", strerror(errno));
goto failed; goto failed;
@ -124,6 +158,28 @@ int searpc_named_pipe_server_start(SearpcNamedPipeServer *server)
goto failed; goto failed;
} }
#ifdef __linux__
if (server->use_epoll) {
int epoll_fd;
struct epoll_event event;
epoll_fd = epoll_create1(0);
if (epoll_fd < 0) {
g_warning ("failed to open an epoll file descriptor: %s\n", strerror(errno));
goto failed;
}
event.events = EPOLLIN;
event.data.fd = pipe_fd;
if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, pipe_fd, &event) == -1) {
g_warning ("failed to add pipe fd to epoll list: %s\n", strerror(errno));
goto failed;
}
server->epoll_fd = epoll_fd;
}
#endif
server->pipe_fd = pipe_fd; server->pipe_fd = pipe_fd;
#endif // !defined(WIN32) #endif // !defined(WIN32)
@ -140,26 +196,187 @@ failed:
} }
typedef struct { typedef struct {
SearpcNamedPipeServer *server;
SearpcNamedPipe connfd; SearpcNamedPipe connfd;
SearpcNamedPipeServer *server;
gboolean use_epoll;
} ServerHandlerData; } ServerHandlerData;
// EPOLL
#ifdef __linux__
static void epoll_handler(void *data)
{
ServerHandlerData *handler_data = data;
SearpcNamedPipe connfd = handler_data->connfd;
SearpcNamedPipeServer *server = handler_data->server;
char *buf = NULL;
guint32 len = 0;
char *ret_str = NULL;
int ret = 0;
int n;
if (pipe_read_n(connfd, &len, sizeof(guint32)) < 0) {
g_warning("failed to read rpc request size: %s\n", strerror(errno));
ret = -1;
goto out;
}
if (len <= 0) {
ret = -1;
goto out;
}
buf = g_new0 (char, len);
n = pipe_read_n (connfd, buf, len);
if (n < 0) {
g_warning ("failed to read rpc request: %s\n", strerror(errno));
ret = -1;
goto out;
}
char *service, *body;
if (request_from_json (buf, len, &service, &body) < 0) {
ret = -1;
goto out;
}
gsize ret_len;
ret_str = searpc_server_call_function (service, body, strlen(body), &ret_len);
g_free (service);
g_free (body);
len = (guint32)ret_len;
if (pipe_write_n (connfd, &len, sizeof(guint32)) < 0) {
ret = -1;
goto out;
}
if (pipe_write_n (connfd, ret_str, ret_len) < 0) {
ret = -1;
goto out;
}
struct epoll_event event;
event.events = EPOLLIN | EPOLLRDHUP;
event.data.ptr = (void *)handler_data;
if (epoll_ctl (server->epoll_fd, EPOLL_CTL_ADD, connfd, &event) == -1) {
ret = -1;
g_warning ("failed to add client fd to epoll list: %s\n", strerror(errno));
goto out;
}
out:
g_free (buf);
if (ret < 0) {
close (connfd);
g_free (handler_data);
}
g_free (ret_str);
}
static void
epoll_listen (SearpcNamedPipeServer *server)
{
#define MAX_EVENTS 1000
struct epoll_event event;
struct epoll_event events[MAX_EVENTS];
int connfd;
int n_events;
int i;
while (1) {
n_events = epoll_wait (server->epoll_fd, events, MAX_EVENTS, 1000);
if (n_events <= 0) {
if (n_events < 0) {
g_warning ("Failed to call waits for events on the epoll: %s\n", strerror(errno));
}
continue;
}
for (i = 0; i < n_events; i++) {
if (events[i].data.fd == server->pipe_fd) {
if (!(events[i].events & EPOLLIN)) {
continue;
}
// new client connection
connfd = accept (server->pipe_fd, NULL, 0);
if (connfd < 0) {
g_warning ("Failed to accept new client connection: %s\n", strerror(errno));
continue;
}
event.events = EPOLLIN | EPOLLRDHUP;
ServerHandlerData *data = g_new0(ServerHandlerData, 1);
data->use_epoll = TRUE;
data->connfd = connfd;
data->server = server;
event.data.ptr = (void *)data;
if (epoll_ctl (server->epoll_fd, EPOLL_CTL_ADD, connfd, &event) == -1) {
g_warning ("Failed to add client fd to epoll list: %s\n", strerror(errno));
epoll_ctl(server->epoll_fd, EPOLL_CTL_DEL, connfd, NULL);
close (connfd);
g_free (data);
continue;
}
} else {
ServerHandlerData *data = (ServerHandlerData *)events[i].data.ptr;
connfd = data->connfd;
if (events[i].events & (EPOLLHUP | EPOLLRDHUP)) {
g_free (data);
epoll_ctl(server->epoll_fd, EPOLL_CTL_DEL, connfd, NULL);
close (connfd);
continue;
}
// After socket is readable, remove the socket from the epoll.
// After the worker finishes processing the current request, we will add the socket back into the epoll.
epoll_ctl(server->epoll_fd, EPOLL_CTL_DEL, connfd, NULL);
if (server->named_pipe_server_thread_pool) {
if (g_thread_pool_get_num_threads (server->named_pipe_server_thread_pool) >= server->pool_size) {
g_warning("The rpc server thread pool is full, the maximum number of threads is %d\n", server->pool_size);
}
g_thread_pool_push (server->named_pipe_server_thread_pool, data, NULL);
} else {
pthread_t handler;
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pthread_create(&handler, &attr, handle_named_pipe_client_with_thread, data);
}
}
}
}
}
#endif
static void* named_pipe_listen(void *arg) static void* named_pipe_listen(void *arg)
{ {
SearpcNamedPipeServer *server = arg; SearpcNamedPipeServer *server = arg;
#if !defined(WIN32) #if !defined(WIN32)
#ifdef __linux__
if (server->use_epoll) {
epoll_listen (server);
return NULL;
}
#endif
while (1) { while (1) {
int connfd = accept (server->pipe_fd, NULL, 0); int connfd = accept (server->pipe_fd, NULL, 0);
pthread_t *handler = g_malloc(sizeof(pthread_t));
ServerHandlerData *data = g_malloc(sizeof(ServerHandlerData)); ServerHandlerData *data = g_malloc(sizeof(ServerHandlerData));
data->server = server;
data->connfd = connfd; data->connfd = connfd;
// TODO(low priority): Instead of using a thread to handle each client, data->use_epoll = FALSE;
// use select(unix)/iocp(windows) to do it. if (server->named_pipe_server_thread_pool) {
pthread_create(handler, NULL, named_pipe_client_handler, data); if (g_thread_pool_get_num_threads (server->named_pipe_server_thread_pool) >= server->pool_size) {
server->handlers = g_list_append(server->handlers, handler); g_warning("The rpc server thread pool is full, the maximum number of threads is %d\n", server->pool_size);
}
g_thread_pool_push (server->named_pipe_server_thread_pool, data, NULL);
} else {
pthread_t handler;
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pthread_create(&handler, &attr, handle_named_pipe_client_with_thread, data);
}
} }
#else // !defined(WIN32) #else // !defined(WIN32)
while (1) { while (1) {
HANDLE connfd = INVALID_HANDLE_VALUE; HANDLE connfd = INVALID_HANDLE_VALUE;
@ -192,53 +409,79 @@ static void* named_pipe_listen(void *arg)
break; break;
} }
g_debug ("Accepted a named pipe client\n"); /* g_debug ("Accepted a named pipe client\n"); */
pthread_t *handler = g_malloc(sizeof(pthread_t));
ServerHandlerData *data = g_malloc(sizeof(ServerHandlerData)); ServerHandlerData *data = g_malloc(sizeof(ServerHandlerData));
data->server = server;
data->connfd = connfd; data->connfd = connfd;
// TODO(low priority): Instead of using a thread to handle each client, data->use_epoll = FALSE;
// use select(unix)/iocp(windows) to do it. if (server->named_pipe_server_thread_pool)
pthread_create(handler, NULL, named_pipe_client_handler, data); g_thread_pool_push (server->named_pipe_server_thread_pool, data, NULL);
server->handlers = g_list_append(server->handlers, handler); else {
pthread_t handler;
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pthread_create(&handler, &attr, handle_named_pipe_client_with_thread, data);
}
} }
#endif // !defined(WIN32) #endif // !defined(WIN32)
return NULL; return NULL;
} }
static void* named_pipe_client_handler(void *arg) static void* handle_named_pipe_client_with_thread(void *arg)
{ {
ServerHandlerData *data = arg; #ifdef __linux__
// SearpcNamedPipeServer *server = data->server; ServerHandlerData *handler_data = arg;
SearpcNamedPipe connfd = data->connfd; if (handler_data->use_epoll) {
epoll_handler (arg);
return NULL;
}
#endif
named_pipe_client_handler(arg);
size_t len; return NULL;
size_t bufsize = 4096; }
static void handle_named_pipe_client_with_threadpool(void *data, void *user_data)
{
#ifdef __linux__
ServerHandlerData *handler_data = data;
if (handler_data->use_epoll) {
epoll_handler (data);
return;
}
#endif
named_pipe_client_handler(data);
}
static void named_pipe_client_handler(void *data)
{
ServerHandlerData *handler_data = data;
SearpcNamedPipe connfd = handler_data->connfd;
guint32 len;
guint32 bufsize = 4096;
char *buf = g_malloc(bufsize); char *buf = g_malloc(bufsize);
g_debug ("start to serve on pipe client\n");
while (1) { while (1) {
len = 0; len = 0;
if (pipe_read_n(connfd, &len, sizeof(uint32_t)) < 0) { if (pipe_read_n(connfd, &len, sizeof(guint32)) < 0) {
g_warning("failed to read rpc request size: %s", strerror(errno)); g_warning("failed to read rpc request size: %s\n", strerror(errno));
break; break;
} }
if (len == 0) { if (len == 0) {
g_debug("EOF reached, pipe connection lost"); /* g_debug("EOF reached, pipe connection lost"); */
break; break;
} }
while (bufsize < len) { while (bufsize < len) {
bufsize *= 2; bufsize *= 2;
buf = realloc(buf, bufsize); buf = g_realloc(buf, bufsize);
} }
if (pipe_read_n(connfd, buf, len) < 0 || len == 0) { if (pipe_read_n(connfd, buf, len) < 0 || len == 0) {
g_warning("failed to read rpc request: %s", strerror(errno)); g_warning("failed to read rpc request: %s\n", strerror(errno));
g_free (buf);
break; break;
} }
@ -247,19 +490,20 @@ static void* named_pipe_client_handler(void *arg)
break; break;
} }
size_t ret_len; gsize ret_len;
char *ret_str = searpc_server_call_function (service, body, strlen(body), &ret_len); char *ret_str = searpc_server_call_function (service, body, strlen(body), &ret_len);
g_free (service); g_free (service);
g_free (body); g_free (body);
if (pipe_write_n(connfd, &ret_len, sizeof(uint32_t)) < 0) { len = (guint32)ret_len;
g_warning("failed to send rpc response(%s): %s", ret_str, strerror(errno)); if (pipe_write_n(connfd, &len, sizeof(guint32)) < 0) {
g_warning("failed to send rpc response(%s): %s\n", ret_str, strerror(errno));
g_free (ret_str); g_free (ret_str);
break; break;
} }
if (pipe_write_n(connfd, ret_str, ret_len) < 0) { if (pipe_write_n(connfd, ret_str, ret_len) < 0) {
g_warning("failed to send rpc response: %s", strerror(errno)); g_warning("failed to send rpc response: %s\n", strerror(errno));
g_free (ret_str); g_free (ret_str);
break; break;
} }
@ -273,11 +517,10 @@ static void* named_pipe_client_handler(void *arg)
DisconnectNamedPipe(connfd); DisconnectNamedPipe(connfd);
CloseHandle(connfd); CloseHandle(connfd);
#endif // !defined(WIN32) #endif // !defined(WIN32)
g_free (data);
return NULL; g_free (buf);
} }
int searpc_named_pipe_client_connect(SearpcNamedPipeClient *client) int searpc_named_pipe_client_connect(SearpcNamedPipeClient *client)
{ {
#if !defined(WIN32) #if !defined(WIN32)
@ -288,11 +531,14 @@ int searpc_named_pipe_client_connect(SearpcNamedPipeClient *client)
g_strlcpy (servaddr.sun_path, client->path, sizeof(servaddr.sun_path)); g_strlcpy (servaddr.sun_path, client->path, sizeof(servaddr.sun_path));
if (connect(client->pipe_fd, (struct sockaddr *)&servaddr, (socklen_t)sizeof(servaddr)) < 0) { if (connect(client->pipe_fd, (struct sockaddr *)&servaddr, (socklen_t)sizeof(servaddr)) < 0) {
g_warning ("pipe client failed to connect to server: %s\n", strerror(errno)); g_warning ("pipe client failed to connect to server: %s\n", strerror(errno));
close(client->pipe_fd);
return -1; return -1;
} }
#else // !defined(WIN32) #else // !defined(WIN32)
SearpcNamedPipe pipe_fd; SearpcNamedPipe pipe_fd;
for (;;) {
pipe_fd = CreateFile( pipe_fd = CreateFile(
client->path, // pipe name client->path, // pipe name
GENERIC_READ | // read and write access GENERIC_READ | // read and write access
@ -303,14 +549,21 @@ int searpc_named_pipe_client_connect(SearpcNamedPipeClient *client)
0, // default attributes 0, // default attributes
NULL); // no template file NULL); // no template file
if (pipe_fd == INVALID_HANDLE_VALUE) { if (pipe_fd != INVALID_HANDLE_VALUE) {
break;
}
/* wait with default timeout (approx. 50ms) */
if (GetLastError() != ERROR_PIPE_BUSY || !WaitNamedPipe(client->path, NMPWAIT_USE_DEFAULT_WAIT)) {
G_WARNING_WITH_LAST_ERROR("Failed to connect to named pipe"); G_WARNING_WITH_LAST_ERROR("Failed to connect to named pipe");
return -1; return -1;
} }
}
DWORD mode = PIPE_READMODE_MESSAGE; DWORD mode = PIPE_READMODE_MESSAGE;
if (!SetNamedPipeHandleState(pipe_fd, &mode, NULL, NULL)) { if (!SetNamedPipeHandleState(pipe_fd, &mode, NULL, NULL)) {
G_WARNING_WITH_LAST_ERROR("Failed to set named pipe mode"); G_WARNING_WITH_LAST_ERROR("Failed to set named pipe mode");
CloseHandle (pipe_fd);
return -1; return -1;
} }
@ -318,7 +571,7 @@ int searpc_named_pipe_client_connect(SearpcNamedPipeClient *client)
#endif // !defined(WIN32) #endif // !defined(WIN32)
g_debug ("pipe client connected to server\n"); /* g_debug ("pipe client connected to server\n"); */
return 0; return 0;
} }
@ -332,6 +585,7 @@ void searpc_free_client_with_pipe_transport (SearpcClient *client)
close(pipe_client->pipe_fd); close(pipe_client->pipe_fd);
#endif #endif
g_free (pipe_client); g_free (pipe_client);
g_free (data->service);
g_free (data); g_free (data);
searpc_client_free (client); searpc_client_free (client);
} }
@ -339,37 +593,36 @@ void searpc_free_client_with_pipe_transport (SearpcClient *client)
char *searpc_named_pipe_send(void *arg, const gchar *fcall_str, char *searpc_named_pipe_send(void *arg, const gchar *fcall_str,
size_t fcall_len, size_t *ret_len) size_t fcall_len, size_t *ret_len)
{ {
g_debug ("searpc_named_pipe_send is called\n"); /* g_debug ("searpc_named_pipe_send is called\n"); */
ClientTransportData *data = arg; ClientTransportData *data = arg;
SearpcNamedPipeClient *client = data->client; SearpcNamedPipeClient *client = data->client;
char *json_str = request_to_json(data->service, fcall_str, fcall_len); char *json_str = request_to_json(data->service, fcall_str, fcall_len);
size_t json_len = strlen(json_str); guint32 len = (guint32)strlen(json_str);
uint32_t len = json_len; if (pipe_write_n(client->pipe_fd, &len, sizeof(guint32)) < 0) {
if (pipe_write_n(client->pipe_fd, &len, sizeof(uint32_t)) < 0) { g_warning("failed to send rpc call: %s\n", strerror(errno));
g_warning("failed to send rpc call: %s", strerror(errno));
free (json_str); free (json_str);
return NULL; return NULL;
} }
if (pipe_write_n(client->pipe_fd, json_str, json_len) < 0) { if (pipe_write_n(client->pipe_fd, json_str, len) < 0) {
g_warning("failed to send rpc call: %s", strerror(errno)); g_warning("failed to send rpc call: %s\n", strerror(errno));
free (json_str); free (json_str);
return NULL; return NULL;
} }
free (json_str); free (json_str);
if (pipe_read_n(client->pipe_fd, &len, sizeof(uint32_t)) < 0) { if (pipe_read_n(client->pipe_fd, &len, sizeof(guint32)) < 0) {
g_warning("failed to read rpc response: %s", strerror(errno)); g_warning("failed to read rpc response: %s\n", strerror(errno));
return NULL; return NULL;
} }
char *buf = g_malloc(len); char *buf = g_malloc(len);
if (pipe_read_n(client->pipe_fd, buf, len) < 0) { if (pipe_read_n(client->pipe_fd, buf, len) < 0) {
g_warning("failed to read rpc response: %s", strerror(errno)); g_warning("failed to read rpc response: %s\n", strerror(errno));
g_free (buf); g_free (buf);
return NULL; return NULL;
} }
@ -437,11 +690,11 @@ json_object_get_string_member (json_t *object, const char *key)
#if !defined(WIN32) #if !defined(WIN32)
// Write "n" bytes to a descriptor. // Write "n" bytes to a descriptor.
ssize_t gssize
pipe_write_n(int fd, const void *vptr, size_t n) pipe_write_n(int fd, const void *vptr, size_t n)
{ {
size_t nleft; size_t nleft;
ssize_t nwritten; gssize nwritten;
const char *ptr; const char *ptr;
ptr = vptr; ptr = vptr;
@ -462,11 +715,11 @@ pipe_write_n(int fd, const void *vptr, size_t n)
} }
// Read "n" bytes from a descriptor. // Read "n" bytes from a descriptor.
ssize_t gssize
pipe_read_n(int fd, void *vptr, size_t n) pipe_read_n(int fd, void *vptr, size_t n)
{ {
size_t nleft; size_t nleft;
ssize_t nread; gssize nread;
char *ptr; char *ptr;
ptr = vptr; ptr = vptr;
@ -488,7 +741,7 @@ pipe_read_n(int fd, void *vptr, size_t n)
#else // !defined(WIN32) #else // !defined(WIN32)
ssize_t pipe_read_n (SearpcNamedPipe fd, void *vptr, size_t n) gssize pipe_read_n (SearpcNamedPipe fd, void *vptr, size_t n)
{ {
DWORD bytes_read; DWORD bytes_read;
BOOL success = ReadFile( BOOL success = ReadFile(
@ -509,7 +762,7 @@ ssize_t pipe_read_n (SearpcNamedPipe fd, void *vptr, size_t n)
return n; return n;
} }
ssize_t pipe_write_n(SearpcNamedPipe fd, const void *vptr, size_t n) gssize pipe_write_n(SearpcNamedPipe fd, const void *vptr, size_t n)
{ {
DWORD bytes_written; DWORD bytes_written;
BOOL success = WriteFile( BOOL success = WriteFile(
@ -520,38 +773,14 @@ ssize_t pipe_write_n(SearpcNamedPipe fd, const void *vptr, size_t n)
NULL); // not overlapped I/O NULL); // not overlapped I/O
if (!success || bytes_written != (DWORD)n) { if (!success || bytes_written != (DWORD)n) {
G_WARNING_WITH_LAST_ERROR("failed to read command from the pipe"); G_WARNING_WITH_LAST_ERROR("failed to write to named pipe");
return -1;
} }
FlushFileBuffers(fd); FlushFileBuffers(fd);
return 0; return 0;
} }
static char *locale_to_utf8 (const gchar *src)
{
if (!src)
return NULL;
gsize bytes_read = 0;
gsize bytes_written = 0;
GError *error = NULL;
gchar *dst = NULL;
dst = g_locale_to_utf8
(src, /* locale specific string */
strlen(src), /* len of src */
&bytes_read, /* length processed */
&bytes_written, /* output length */
&error);
if (error) {
return NULL;
}
return dst;
}
// http://stackoverflow.com/questions/3006229/get-a-text-from-the-error-code-returns-from-the-getlasterror-function // http://stackoverflow.com/questions/3006229/get-a-text-from-the-error-code-returns-from-the-getlasterror-function
// The caller is responsible to free the returned message. // The caller is responsible to free the returned message.
char* formatErrorMessage() char* formatErrorMessage()
@ -564,11 +793,12 @@ char* formatErrorMessage()
FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM,
NULL, NULL,
error_code, error_code,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), /* EN_US */
MAKELANGID(LANG_ENGLISH, 0x01),
buf, buf,
sizeof(buf) - 1, sizeof(buf) - 1,
NULL); NULL);
return locale_to_utf8(buf); return g_strdup(buf);
} }
#endif // !defined(WIN32) #endif // !defined(WIN32)

View File

@ -10,6 +10,16 @@
#include <windows.h> #include <windows.h>
#endif #endif
#ifdef __cplusplus
extern "C" {
#endif
#ifdef LIBSEARPC_EXPORTS
#define LIBSEARPC_API __declspec(dllexport)
#else
#define LIBSEARPC_API
#endif
// Implementatin of a searpc transport based on named pipe. It uses unix domain // Implementatin of a searpc transport based on named pipe. It uses unix domain
// sockets on linux/osx, and named pipes on windows. // sockets on linux/osx, and named pipes on windows.
// //
@ -30,14 +40,22 @@ typedef int SearpcNamedPipe;
struct _SearpcNamedPipeServer { struct _SearpcNamedPipeServer {
char path[4096]; char path[4096];
pthread_t listener_thread; pthread_t listener_thread;
GList *handlers;
SearpcNamedPipe pipe_fd; SearpcNamedPipe pipe_fd;
gboolean use_epoll;
int epoll_fd;
GThreadPool *named_pipe_server_thread_pool;
int pool_size;
}; };
typedef struct _SearpcNamedPipeServer SearpcNamedPipeServer; typedef struct _SearpcNamedPipeServer LIBSEARPC_API SearpcNamedPipeServer;
LIBSEARPC_API
SearpcNamedPipeServer* searpc_create_named_pipe_server(const char *path); SearpcNamedPipeServer* searpc_create_named_pipe_server(const char *path);
LIBSEARPC_API
SearpcNamedPipeServer* searpc_create_named_pipe_server_with_threadpool(const char *path, int named_pipe_server_thread_pool_size);
LIBSEARPC_API
int searpc_named_pipe_server_start(SearpcNamedPipeServer *server); int searpc_named_pipe_server_start(SearpcNamedPipeServer *server);
// Client side interface. // Client side interface.
@ -47,14 +65,22 @@ struct _SearpcNamedPipeClient {
SearpcNamedPipe pipe_fd; SearpcNamedPipe pipe_fd;
}; };
typedef struct _SearpcNamedPipeClient SearpcNamedPipeClient; typedef struct _SearpcNamedPipeClient LIBSEARPC_API SearpcNamedPipeClient;
LIBSEARPC_API
SearpcNamedPipeClient* searpc_create_named_pipe_client(const char *path); SearpcNamedPipeClient* searpc_create_named_pipe_client(const char *path);
LIBSEARPC_API
SearpcClient * searpc_client_with_named_pipe_transport(SearpcNamedPipeClient *client, const char *service); SearpcClient * searpc_client_with_named_pipe_transport(SearpcNamedPipeClient *client, const char *service);
LIBSEARPC_API
int searpc_named_pipe_client_connect(SearpcNamedPipeClient *client); int searpc_named_pipe_client_connect(SearpcNamedPipeClient *client);
LIBSEARPC_API
void searpc_free_client_with_pipe_transport (SearpcClient *client); void searpc_free_client_with_pipe_transport (SearpcClient *client);
#ifdef __cplusplus
}
#endif
#endif // SEARPC_NAMED_PIPE_TRANSPORT_H #endif // SEARPC_NAMED_PIPE_TRANSPORT_H

View File

@ -9,8 +9,10 @@
#include "searpc-server.h" #include "searpc-server.h"
#include "searpc-utils.h" #include "searpc-utils.h"
#ifdef PROFILE #ifdef __linux__
#include <sys/time.h> #include <sys/time.h>
#include <sys/errno.h>
#include <pthread.h>
#endif #endif
struct FuncItem; struct FuncItem;
@ -34,6 +36,14 @@ typedef struct {
static GHashTable *marshal_table; static GHashTable *marshal_table;
static GHashTable *service_table; static GHashTable *service_table;
#ifdef __linux__
static FILE *slow_log_fp = NULL;
static gint64 slow_threshold;
static GList *filtered_funcs;
static pthread_mutex_t slow_log_lock;
static gboolean log_to_stdout = FALSE;
#endif
static void static void
func_item_free (FuncItem *item) func_item_free (FuncItem *item)
{ {
@ -136,6 +146,9 @@ searpc_set_objlist_to_ret_object (json_t *object, GList *ret)
void void
searpc_set_json_to_ret_object (json_t *object, json_t *ret) searpc_set_json_to_ret_object (json_t *object, json_t *ret)
{ {
if (ret == NULL)
json_object_set_new(object, "ret", json_null ());
else
json_object_set_new (object, "ret", ret); json_object_set_new (object, "ret", ret);
} }
@ -185,8 +198,67 @@ searpc_server_init (RegisterMarshalFunc register_func)
register_func (); register_func ();
} }
#ifdef __linux__
int
searpc_server_init_with_slow_log (RegisterMarshalFunc register_func,
const char *slow_log_path,
gint64 slow_threshold_in,
GList *filtered_funcs_in)
{
const char *log_to_stdout_env = g_getenv("SEAFILE_LOG_TO_STDOUT");
if (g_strcmp0(log_to_stdout_env, "true") == 0) {
slow_log_fp = stdout;
log_to_stdout = TRUE;
} else if (slow_log_path) {
slow_log_fp = fopen (slow_log_path, "a+");
if (!slow_log_fp) {
g_warning ("Failed to open RPC slow log file %s: %s\n", slow_log_path, strerror(errno));
return -1;
}
}
slow_threshold = slow_threshold_in;
filtered_funcs = filtered_funcs_in;
pthread_mutex_init (&slow_log_lock, NULL);
searpc_server_init (register_func);
return 0;
}
int
searpc_server_reopen_slow_log (const char *slow_log_path)
{
FILE *fp, *oldfp;
if (log_to_stdout) {
return 0;
}
if ((fp = fopen (slow_log_path, "a+")) == NULL) {
g_warning ("Failed to open RPC slow log file %s\n", slow_log_path);
return -1;
}
pthread_mutex_lock (&slow_log_lock);
oldfp = slow_log_fp;
slow_log_fp = fp;
pthread_mutex_unlock (&slow_log_lock);
if (fclose(oldfp) < 0) {
g_warning ("Failed to close old RPC slow log file\n");
return -1;
}
return 0;
}
#endif
void void
searpc_server_final() searpc_server_final(void)
{ {
g_hash_table_destroy (service_table); g_hash_table_destroy (service_table);
g_hash_table_destroy (marshal_table); g_hash_table_destroy (marshal_table);
@ -244,6 +316,53 @@ searpc_server_register_function (const char *svc_name,
return TRUE; return TRUE;
} }
#ifdef __linux__
static gboolean
rpc_include_passwd (const char *fname) {
GList *ptr;
char *rpc_name;
for (ptr = filtered_funcs; ptr; ptr = ptr->next) {
rpc_name = ptr->data;
if (g_strcmp0 (fname, rpc_name) == 0) {
return TRUE;
}
}
return FALSE;
}
static void
print_slow_log_if_necessary (const char *svc_name, const char *func, gsize len,
const struct timeval *start,
const struct timeval *intv)
{
char time_buf[64];
gint64 intv_in_usec = ((gint64)intv->tv_sec) * G_USEC_PER_SEC + (gint64)intv->tv_usec;
gint64 intv_in_msec = intv_in_usec/1000;
double intv_in_sec = ((double)intv_in_usec)/G_USEC_PER_SEC;
if (intv_in_msec < slow_threshold)
return;
strftime(time_buf, 64, "%Y/%m/%d %H:%M:%S", localtime(&start->tv_sec));
pthread_mutex_lock (&slow_log_lock);
if (log_to_stdout) {
fprintf (slow_log_fp, "[seafile-slow-rpc] ");
}
fprintf (slow_log_fp, "[%s] \"%s\" %.*s %.3f\n",
time_buf, svc_name, (int)len, func, intv_in_sec);
fflush (slow_log_fp);
pthread_mutex_unlock (&slow_log_lock);
}
#endif
/* Called by RPC transport. */ /* Called by RPC transport. */
char* char*
searpc_server_call_function (const char *svc_name, searpc_server_call_function (const char *svc_name,
@ -255,10 +374,12 @@ searpc_server_call_function (const char *svc_name,
json_error_t jerror; json_error_t jerror;
GError *error = NULL; GError *error = NULL;
#ifdef PROFILE #ifdef __linux__
struct timeval start, end, intv; struct timeval start, end, intv;
if (slow_log_fp) {
gettimeofday(&start, NULL); gettimeofday(&start, NULL);
}
#endif #endif
service = g_hash_table_lookup (service_table, svc_name); service = g_hash_table_lookup (service_table, svc_name);
@ -290,11 +411,14 @@ searpc_server_call_function (const char *svc_name,
ret = fitem->marshal->mfunc (fitem->func, array, ret_len); ret = fitem->marshal->mfunc (fitem->func, array, ret_len);
#ifdef PROFILE #ifdef __linux__
if (slow_log_fp) {
if (!filtered_funcs || !rpc_include_passwd (fitem->fname)) {
gettimeofday(&end, NULL); gettimeofday(&end, NULL);
timersub(&end, &start, &intv); timersub(&end, &start, &intv);
g_debug ("[searpc] Time spend in call %s: %ds %dus\n", print_slow_log_if_necessary (svc_name, func, len, &start, &intv);
fname, intv.tv_sec, intv.tv_usec); }
}
#endif #endif
json_decref(array); json_decref(array);

View File

@ -5,6 +5,16 @@
#include <glib-object.h> #include <glib-object.h>
#include <jansson.h> #include <jansson.h>
#ifdef __cplusplus
extern "C" {
#endif
#ifdef LIBSEARPC_EXPORTS
#define LIBSEARPC_API __declspec(dllexport)
#else
#define LIBSEARPC_API
#endif
#ifndef DFT_DOMAIN #ifndef DFT_DOMAIN
#define DFT_DOMAIN g_quark_from_string(G_LOG_DOMAIN) #define DFT_DOMAIN g_quark_from_string(G_LOG_DOMAIN)
#endif #endif
@ -13,11 +23,17 @@ typedef gchar* (*SearpcMarshalFunc) (void *func, json_t *param_array,
gsize *ret_len); gsize *ret_len);
typedef void (*RegisterMarshalFunc) (void); typedef void (*RegisterMarshalFunc) (void);
LIBSEARPC_API
void searpc_set_string_to_ret_object (json_t *object, char *ret); void searpc_set_string_to_ret_object (json_t *object, char *ret);
LIBSEARPC_API
void searpc_set_int_to_ret_object (json_t *object, json_int_t ret); void searpc_set_int_to_ret_object (json_t *object, json_int_t ret);
LIBSEARPC_API
void searpc_set_object_to_ret_object (json_t *object, GObject *ret); void searpc_set_object_to_ret_object (json_t *object, GObject *ret);
LIBSEARPC_API
void searpc_set_objlist_to_ret_object (json_t *object, GList *ret); void searpc_set_objlist_to_ret_object (json_t *object, GList *ret);
LIBSEARPC_API
void searpc_set_json_to_ret_object (json_t *object, json_t *ret); void searpc_set_json_to_ret_object (json_t *object, json_t *ret);
LIBSEARPC_API
char *searpc_marshal_set_ret_common (json_t *object, gsize *len, GError *error); char *searpc_marshal_set_ret_common (json_t *object, gsize *len, GError *error);
/** /**
@ -25,14 +41,33 @@ char *searpc_marshal_set_ret_common (json_t *object, gsize *len, GError *error);
* *
* Inititalize searpc server. * Inititalize searpc server.
*/ */
LIBSEARPC_API
void searpc_server_init (RegisterMarshalFunc register_func); void searpc_server_init (RegisterMarshalFunc register_func);
/**
* searpc_server_init_with_slow_log:
*
* Inititalize searpc server with slow log file.
*/
LIBSEARPC_API int
searpc_server_init_with_slow_log (RegisterMarshalFunc register_func,
const char *slow_log_path,
gint64 slow_threshold_in,
GList *filtered_funcs_in);
/**
* Used in log rotate.
*/
LIBSEARPC_API int
searpc_server_reopen_slow_log (const char *slow_log_path);
/** /**
* searpc_server_final: * searpc_server_final:
* *
* Free the server structure. * Free the server structure.
*/ */
void searpc_server_final (); LIBSEARPC_API
void searpc_server_final (void);
/** /**
* searpc_create_service: * searpc_create_service:
@ -42,6 +77,7 @@ void searpc_server_final ();
* *
* @svc_name: Service name. * @svc_name: Service name.
*/ */
LIBSEARPC_API
int searpc_create_service (const char *svc_name); int searpc_create_service (const char *svc_name);
/** /**
@ -49,6 +85,7 @@ int searpc_create_service (const char *svc_name);
* *
* Remove the service from the server. * Remove the service from the server.
*/ */
LIBSEARPC_API
void searpc_remove_service (const char *svc_name); void searpc_remove_service (const char *svc_name);
/** /**
@ -59,6 +96,7 @@ void searpc_remove_service (const char *svc_name);
* @signature: the signature of the marshal, register_marshal() will take * @signature: the signature of the marshal, register_marshal() will take
* owner of this string. * owner of this string.
*/ */
LIBSEARPC_API
gboolean searpc_server_register_marshal (gchar *signature, gboolean searpc_server_register_marshal (gchar *signature,
SearpcMarshalFunc marshal); SearpcMarshalFunc marshal);
@ -70,6 +108,7 @@ gboolean searpc_server_register_marshal (gchar *signature,
* @signature: the signature of the function, register_function() will take * @signature: the signature of the function, register_function() will take
* owner of this string. * owner of this string.
*/ */
LIBSEARPC_API
gboolean searpc_server_register_function (const char *service, gboolean searpc_server_register_function (const char *service,
void* func, void* func,
const gchar *fname, const gchar *fname,
@ -86,6 +125,7 @@ gboolean searpc_server_register_function (const char *service,
* *
* Returns the serialized representatio of the returned value. * Returns the serialized representatio of the returned value.
*/ */
LIBSEARPC_API
gchar *searpc_server_call_function (const char *service, gchar *searpc_server_call_function (const char *service,
gchar *func, gsize len, gsize *ret_len); gchar *func, gsize len, gsize *ret_len);
@ -96,6 +136,11 @@ gchar *searpc_server_call_function (const char *service,
* *
* Compute function signature. * Compute function signature.
*/ */
LIBSEARPC_API
char* searpc_compute_signature (const gchar *ret_type, int pnum, ...); char* searpc_compute_signature (const gchar *ret_type, int pnum, ...);
#ifdef __cplusplus
}
#endif
#endif #endif

View File

@ -1,5 +1,4 @@
#include <errno.h> #include <errno.h>
#include <unistd.h>
#include <glib.h> #include <glib.h>
#include <glib-object.h> #include <glib-object.h>
#include <jansson.h> #include <jansson.h>

View File

@ -2,15 +2,23 @@
#include <glib-object.h> #include <glib-object.h>
#include <jansson.h> #include <jansson.h>
#ifdef LIBSEARPC_EXPORTS
#define LIBSEARPC_API __declspec(dllexport)
#else
#define LIBSEARPC_API
#endif
#define SEARPC_JSON_DOMAIN g_quark_from_string("SEARPC_JSON") #define SEARPC_JSON_DOMAIN g_quark_from_string("SEARPC_JSON")
typedef enum { typedef enum {
SEARPC_JSON_ERROR_LOAD, SEARPC_JSON_ERROR_LOAD,
SEARPC_JSON_ERROR_PACK, SEARPC_JSON_ERROR_PACK,
SEARPC_JSON_ERROR_UPACK SEARPC_JSON_ERROR_UPACK
} SEARPCJSONERROR; } LIBSEARPC_API SEARPCJSONERROR;
LIBSEARPC_API
json_t *json_gobject_serialize (GObject *); json_t *json_gobject_serialize (GObject *);
LIBSEARPC_API
GObject *json_gobject_deserialize (GType , json_t *); GObject *json_gobject_deserialize (GType , json_t *);
inline static void setjetoge(const json_error_t *jerror, GError **error) inline static void setjetoge(const json_error_t *jerror, GError **error)

View File

@ -1,4 +1,4 @@
prefix=(DESTDIR)@prefix@ prefix=@prefix@
exec_prefix=@exec_prefix@ exec_prefix=@exec_prefix@
libdir=@libdir@ libdir=@libdir@
includedir=@includedir@ includedir=@includedir@
@ -8,4 +8,4 @@ Description: Simple C rpc library
Version: @VERSION@ Version: @VERSION@
Libs: -L${libdir} -lsearpc Libs: -L${libdir} -lsearpc
Cflags: -I${includedir} -I${includedir}/searpc Cflags: -I${includedir} -I${includedir}/searpc
Requires: gobject-2.0 gio-2.0 jansson Requires: gobject-2.0 >= 2.26.0 gio-2.0 jansson >= 2.2.1

31
libsearpc.sln Normal file
View File

@ -0,0 +1,31 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.29215.179
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libsearpc", "libsearpc.vcxproj", "{7E7BDAA2-D61E-466D-B138-CC2454CAB1D3}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{7E7BDAA2-D61E-466D-B138-CC2454CAB1D3}.Debug|x64.ActiveCfg = Debug|x64
{7E7BDAA2-D61E-466D-B138-CC2454CAB1D3}.Debug|x64.Build.0 = Debug|x64
{7E7BDAA2-D61E-466D-B138-CC2454CAB1D3}.Debug|x86.ActiveCfg = Debug|Win32
{7E7BDAA2-D61E-466D-B138-CC2454CAB1D3}.Debug|x86.Build.0 = Debug|Win32
{7E7BDAA2-D61E-466D-B138-CC2454CAB1D3}.Release|x64.ActiveCfg = Release|x64
{7E7BDAA2-D61E-466D-B138-CC2454CAB1D3}.Release|x64.Build.0 = Release|x64
{7E7BDAA2-D61E-466D-B138-CC2454CAB1D3}.Release|x86.ActiveCfg = Release|Win32
{7E7BDAA2-D61E-466D-B138-CC2454CAB1D3}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {393C05AB-0CCA-4180-93EF-57D9CB079042}
EndGlobalSection
EndGlobal

137
libsearpc.vcxproj Normal file
View File

@ -0,0 +1,137 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<ProjectGuid>{7E7BDAA2-D61E-466D-B138-CC2454CAB1D3}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<OutDir>$(ProjectDir)$(Platform)\$(Configuration)\</OutDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" />
<PropertyGroup Label="Vcpkg">
<VcpkgEnableManifest>true</VcpkgEnableManifest>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;LIBSEARPC_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<Optimization>Disabled</Optimization>
</ClCompile>
<Link>
<TargetMachine>MachineX86</TargetMachine>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Windows</SubSystem>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile>
<Link>
<TargetMachine>MachineX86</TargetMachine>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PreprocessorDefinitions>LIBSEARPC_EXPORTS;WIN32</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(ProjectDir)vcpkg_installed\x64-windows\x64-windows\include\glib-2.0;$(ProjectDir)vcpkg_installed\x64-windows\x64-windows\lib\glib-2.0\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<PreprocessorDefinitions>LIBSEARPC_EXPORTS;WIN32</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(ProjectDir)vcpkg_installed\x64-windows\x64-windows\include\glib-2.0;$(ProjectDir)vcpkg_installed\x64-windows\x64-windows\lib\glib-2.0\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="lib\searpc-client.c" />
<ClCompile Include="lib\searpc-named-pipe-transport.c" />
<ClCompile Include="lib\searpc-server.c" />
<ClCompile Include="lib\searpc-utils.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="config.h" />
<ClInclude Include="lib\searpc-client.h" />
<ClInclude Include="lib\searpc-named-pipe-transport.h" />
<ClInclude Include="lib\searpc-server.h" />
<ClInclude Include="lib\searpc-utils.h" />
<ClInclude Include="lib\searpc.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -1,5 +1,5 @@
import json import json
from common import SearpcError from .common import SearpcError
def _fret_int(ret_str): def _fret_int(ret_str):
try: try:
@ -7,10 +7,10 @@ def _fret_int(ret_str):
except: except:
raise SearpcError('Invalid response format') raise SearpcError('Invalid response format')
if dicts.has_key('err_code'): if 'err_code' in dicts:
raise SearpcError(dicts['err_msg']) raise SearpcError(dicts['err_msg'])
if dicts.has_key('ret'): if 'ret' in dicts:
return dicts['ret'] return dicts['ret']
else: else:
raise SearpcError('Invalid response format') raise SearpcError('Invalid response format')
@ -21,10 +21,10 @@ def _fret_string(ret_str):
except: except:
raise SearpcError('Invalid response format') raise SearpcError('Invalid response format')
if dicts.has_key('err_code'): if 'err_code' in dicts:
raise SearpcError(dicts['err_msg']) raise SearpcError(dicts['err_msg'])
if dicts.has_key('ret'): if 'ret' in dicts:
return dicts['ret'] return dicts['ret']
else: else:
raise SearpcError('Invalid response format') raise SearpcError('Invalid response format')
@ -61,7 +61,7 @@ def _fret_obj(ret_str):
except: except:
raise SearpcError('Invalid response format') raise SearpcError('Invalid response format')
if dicts.has_key('err_code'): if 'err_code' in dicts:
raise SearpcError(dicts['err_msg']) raise SearpcError(dicts['err_msg'])
if dicts['ret']: if dicts['ret']:
@ -75,7 +75,7 @@ def _fret_objlist(ret_str):
except: except:
raise SearpcError('Invalid response format') raise SearpcError('Invalid response format')
if dicts.has_key('err_code'): if 'err_code' in dicts:
raise SearpcError(dicts['err_msg']) raise SearpcError(dicts['err_msg'])
l = [] l = []
@ -85,6 +85,19 @@ def _fret_objlist(ret_str):
return l return l
def _fret_json(ret_str):
try:
dicts = json.loads(ret_str)
except:
raise SearpcError('Invalid response format')
if 'err_code' in dicts:
raise SearpcError(dicts['err_msg'])
if dicts['ret']:
return dicts['ret']
else:
return None
def searpc_func(ret_type, param_types): def searpc_func(ret_type, param_types):
@ -101,6 +114,8 @@ def searpc_func(ret_type, param_types):
fret = _fret_int fret = _fret_int
elif ret_type == "string": elif ret_type == "string":
fret = _fret_string fret = _fret_string
elif ret_type == "json":
fret = _fret_json
else: else:
raise SearpcError('Invial return type') raise SearpcError('Invial return type')

View File

@ -8,6 +8,7 @@ import os
import socket import socket
import struct import struct
from threading import Thread from threading import Thread
import queue
from .client import SearpcClient from .client import SearpcClient
from .server import searpc_server from .server import searpc_server
@ -36,52 +37,67 @@ class NamedPipeTransport(SearpcTransport):
def __init__(self, socket_path): def __init__(self, socket_path):
self.socket_path = socket_path self.socket_path = socket_path
self.pipe_fd = None self.pipe = None
def connect(self): def connect(self):
self.pipe_fd = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM, 0) self.pipe = socket.socket(socket.AF_UNIX)
make_socket_closeonexec(self.pipe_fd) self.pipe.connect(self.socket_path)
self.pipe_fd.connect(self.socket_path)
def stop(self): def stop(self):
if self.pipe_fd: if self.pipe:
self.pipe_fd.close() self.pipe.close()
self.pipe_fd = None self.pipe = None
def send(self, service, fcall_str): def send(self, service, fcall_str):
body = json.dumps({ body = json.dumps({
'service': service, 'service': service,
'request': fcall_str, 'request': fcall_str,
}) })
body_utf8 = body.encode(encoding='utf-8')
# "I" for unsiged int # "I" for unsiged int
header = struct.pack('I', len(body)) header = struct.pack('=I', len(body_utf8))
sendall(self.pipe_fd, header) sendall(self.pipe, header)
sendall(self.pipe_fd, body) sendall(self.pipe, body_utf8)
resp_header = recvall(self.pipe_fd, 4) resp_header = recvall(self.pipe, 4)
# logger.info('resp_header is %s', resp_header) # logger.info('resp_header is %s', resp_header)
resp_size, = struct.unpack('I', resp_header) resp_size, = struct.unpack('=I', resp_header)
# logger.info('resp_size is %s', resp_size) # logger.info('resp_size is %s', resp_size)
resp = recvall(self.pipe_fd, resp_size) resp = recvall(self.pipe, resp_size)
# logger.info('resp is %s', resp) # logger.info('resp is %s', resp)
return resp return resp.decode(encoding='utf-8')
class NamedPipeClient(SearpcClient): class NamedPipeClient(SearpcClient):
def __init__(self, socket_path, service_name): def __init__(self, socket_path, service_name, pool_size=5):
self.socket_path = socket_path self.socket_path = socket_path
self.service_name = service_name self.service_name = service_name
self.transport = NamedPipeTransport(socket_path) self.pool_size = pool_size
self.connected = False self._pool = queue.Queue(pool_size)
def stop(self): def _create_transport(self):
self.transport.stop() transport = NamedPipeTransport(self.socket_path)
transport.connect()
return transport
def _get_transport(self):
try:
transport = self._pool.get(False)
except:
transport = self._create_transport()
return transport
def _return_transport(self, transport):
try:
self._pool.put(transport, False)
except queue.Full:
transport.stop()
def call_remote_func_sync(self, fcall_str): def call_remote_func_sync(self, fcall_str):
if not self.connected: transport = self._get_transport()
self.transport.connect() ret_str = transport.send(self.service_name, fcall_str)
self.connected = True self._return_transport(transport)
return self.transport.send(self.service_name, fcall_str) return ret_str
class NamedPipeServer(object): class NamedPipeServer(object):
@ -91,7 +107,7 @@ class NamedPipeServer(object):
""" """
def __init__(self, socket_path): def __init__(self, socket_path):
self.socket_path = socket_path self.socket_path = socket_path
self.pipe_fd = None self.pipe = None
self.thread = Thread(target=self.accept_loop) self.thread = Thread(target=self.accept_loop)
self.thread.setDaemon(True) self.thread.setDaemon(True)
@ -111,40 +127,40 @@ class NamedPipeServer(object):
'Failed to remove existing unix socket {}'. 'Failed to remove existing unix socket {}'.
format(self.socket_path) format(self.socket_path)
) )
self.pipe_fd = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM, 0) self.pipe = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM, 0)
make_socket_closeonexec(self.pipe_fd) make_socket_closeonexec(self.pipe)
self.pipe_fd.bind(self.socket_path) self.pipe.bind(self.socket_path)
self.pipe_fd.listen(10) self.pipe.listen(10)
logger.info('Server now listening at %s', self.socket_path) logger.info('Server now listening at %s', self.socket_path)
def accept_loop(self): def accept_loop(self):
logger.info('Waiting for clients') logger.info('Waiting for clients')
while True: while True:
connfd, _ = self.pipe_fd.accept() connfd, _ = self.pipe.accept()
logger.info('New pip client') logger.info('New pip client')
t = PipeHandlerThread(connfd) t = PipeHandlerThread(connfd)
t.start() t.start()
class PipeHandlerThread(Thread): class PipeHandlerThread(Thread):
def __init__(self, pipe_fd): def __init__(self, pipe):
Thread.__init__(self) Thread.__init__(self)
self.setDaemon(True) self.setDaemon(True)
self.pipe_fd = pipe_fd self.pipe = pipe
def run(self): def run(self):
while True: while True:
req_header = recvall(self.pipe_fd, 4) req_header = recvall(self.pipe, 4)
# logger.info('Got req header %s', req_header) # logger.info('Got req header %s', req_header)
req_size, = struct.unpack('I', req_header) req_size, = struct.unpack('I', req_header)
# logger.info('req size is %s', req_size) # logger.info('req size is %s', req_size)
req = recvall(self.pipe_fd, req_size) req = recvall(self.pipe, req_size)
# logger.info('req is %s', req) # logger.info('req is %s', req)
data = json.loads(req) data = json.loads(req.decode(encoding='utf-8'))
resp = searpc_server.call_function(data['service'], data['request']) resp = searpc_server.call_function(data['service'], data['request'])
# logger.info('resp is %s', resp) # logger.info('resp is %s', resp)
resp_header = struct.pack('I', len(resp)) resp_header = struct.pack('I', len(resp))
sendall(self.pipe_fd, resp_header) sendall(self.pipe, resp_header)
sendall(self.pipe_fd, resp) sendall(self.pipe, resp.encode(encoding='utf-8'))

View File

@ -1,6 +1,5 @@
#!/usr/bin/python #!/usr/bin/python
import string import string
import sys import sys
@ -29,7 +28,7 @@ def gen_fcall_funcs_array(arg_types):
pyfuncname = "fcall__" + "_".join(arg_types) pyfuncname = "fcall__" + "_".join(arg_types)
tmplist = [] tmplist = []
for arg in arg_types: for arg in arg_types:
tmplist.append(string.capitalize(arg)) tmplist.append(arg.capitalize())
cfuncname = "SearpcClient_Fcall__" + "_".join(tmplist) cfuncname = "SearpcClient_Fcall__" + "_".join(tmplist)
@ -47,7 +46,7 @@ def gen_fret_funcs_array(ret_type):
cfuncname = "SearpcClient_Fret__Void" cfuncname = "SearpcClient_Fret__Void"
else: else:
pyfuncname = "fret__" + ret_type pyfuncname = "fret__" + ret_type
cfuncname = "SearpcClient_Fret__" + string.capitalize(ret_type) cfuncname = "SearpcClient_Fret__" + ret_type.capitalize()
return string.Template(func_item_template)\ return string.Template(func_item_template)\
.substitute(pyfuncname=pyfuncname, .substitute(pyfuncname=pyfuncname,
@ -79,8 +78,8 @@ def gen_module_funcs_array():
array = fcall_array array = fcall_array
array += fret_array array += fret_array
print string.Template(module_func_array_template)\ print(string.Template(module_func_array_template)\
.substitute(array=array) .substitute(array=array))
type_table = { type_table = {
@ -128,7 +127,7 @@ def gen_fcall_func(arg_types):
tmplist = [] tmplist = []
for arg in arg_types: for arg in arg_types:
tmplist.append(string.capitalize(arg)) tmplist.append(arg.capitalize())
Suffix = "_".join(tmplist) Suffix = "_".join(tmplist)
suffix = "_".join(arg_types) suffix = "_".join(arg_types)
def_args = "" def_args = ""
@ -161,7 +160,7 @@ def gen_fcall_list():
arg_types_list.append(item[1]) arg_types_list.append(item[1])
for item in arg_types_list: for item in arg_types_list:
print gen_fcall_func(item) print(gen_fcall_func(item))
if __name__ == "__main__": if __name__ == "__main__":

View File

@ -1,6 +1,6 @@
import json import json
from common import SearpcError from .common import SearpcError
class SearpcService(object): class SearpcService(object):
def __init__(self, name): def __init__(self, name):
@ -25,7 +25,7 @@ class SearpcServer(object):
"""input str -> output str""" """input str -> output str"""
try: try:
argv = json.loads(fcallstr) argv = json.loads(fcallstr)
except Exception, e: except Exception as e:
raise SearpcError('bad call str: ' + str(e)) raise SearpcError('bad call str: ' + str(e))
service = self.services[svcname] service = self.services[svcname]
@ -41,7 +41,7 @@ class SearpcServer(object):
def call_function(self, svcname, fcallstr): def call_function(self, svcname, fcallstr):
try: try:
retVal = self._call_function(svcname, fcallstr) retVal = self._call_function(svcname, fcallstr)
except Exception, e: except Exception as e:
ret = {'err_code': 555, 'err_msg': str(e)} ret = {'err_code': 555, 'err_msg': str(e)}
else: else:
ret = {'ret': retVal} ret = {'ret': retVal}

View File

@ -22,6 +22,14 @@ def init_server():
searpc_server.create_service(SVCNAME) searpc_server.create_service(SVCNAME)
searpc_server.register_function(SVCNAME, add, 'add') searpc_server.register_function(SVCNAME, add, 'add')
searpc_server.register_function(SVCNAME, mul, 'multi') searpc_server.register_function(SVCNAME, mul, 'multi')
searpc_server.register_function(SVCNAME, json_func, 'json_func')
searpc_server.register_function(SVCNAME, get_str, 'get_str')
def json_func(a, b):
return {'a': a, 'b': b}
def get_str():
return u'这是一个测试'
class DummyTransport(SearpcTransport): class DummyTransport(SearpcTransport):
@ -40,6 +48,14 @@ class RpcMixin(object):
def multi(self, x, y): def multi(self, x, y):
pass pass
@searpc_func("json", ["string", "int"])
def json_func(self, x, y):
pass
@searpc_func("string", [])
def get_str(self):
pass
class DummyRpcClient(SearpcClient, RpcMixin): class DummyRpcClient(SearpcClient, RpcMixin):
def __init__(self): def __init__(self):
self.transport = DummyTransport() self.transport = DummyTransport()
@ -66,7 +82,6 @@ class SearpcTest(unittest.TestCase):
@classmethod @classmethod
def tearDownClass(cls): def tearDownClass(cls):
cls.named_pipe_client.stop()
cls.named_pipe_server.stop() cls.named_pipe_server.stop()
def test_normal_transport(self): def test_normal_transport(self):
@ -86,6 +101,12 @@ class SearpcTest(unittest.TestCase):
v = client.multi('abc', 2) v = client.multi('abc', 2)
self.assertEqual(v, 'abcabc') self.assertEqual(v, 'abcabc')
v = client.json_func(1, 2)
self.assertEqual(v, json_func(1, 2))
v = client.get_str()
self.assertEqual(v, u'这是一个测试')
def setup_logging(level=logging.INFO): def setup_logging(level=logging.INFO):
kw = { kw = {
# 'format': '[%(asctime)s][%(pathname)s]: %(message)s', # 'format': '[%(asctime)s][%(pathname)s]: %(message)s',

View File

@ -1,4 +1,3 @@
class SearpcTransport(object): class SearpcTransport(object):
""" """
A transport is repsonsible to send the serialized request to the A transport is repsonsible to send the serialized request to the

View File

@ -5,7 +5,7 @@ from pysearpc.errors import NetworkError
def recvall(fd, total): def recvall(fd, total):
remain = total remain = total
data = '' data = bytearray()
while remain > 0: while remain > 0:
try: try:
new = fd.recv(remain) new = fd.recv(remain)
@ -16,10 +16,10 @@ def recvall(fd, total):
if n <= 0: if n <= 0:
raise NetworkError("Failed to read from socket") raise NetworkError("Failed to read from socket")
else: else:
data += new data.extend(new)
remain -= n remain -= n
return data return bytes(data)
def sendall(fd, data): def sendall(fd, data):
total = len(data) total = len(data)

View File

@ -371,7 +371,7 @@ clar_test_init(int argc, char **argv)
} }
int int
clar_test_run() clar_test_run(void)
{ {
if (_clar.argc > 1) if (_clar.argc > 1)
clar_parse_args(_clar.argc, _clar.argv); clar_parse_args(_clar.argc, _clar.argv);
@ -386,7 +386,7 @@ clar_test_run()
} }
void void
clar_test_shutdown() clar_test_shutdown(void)
{ {
clar_print_shutdown( clar_print_shutdown(
_clar.tests_ran, _clar.tests_ran,

View File

@ -27,6 +27,8 @@ static const char *pipe_path = "\\\\.\\pipe\\libsearpc-test";
#define MAMAN_IS_BAR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MAMAN_TYPE_BAR)) #define MAMAN_IS_BAR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MAMAN_TYPE_BAR))
#define MAMAN_BAR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MAMAN_TYPE_BAR, MamanBarClass)) #define MAMAN_BAR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MAMAN_TYPE_BAR, MamanBarClass))
#define NAMED_PIPE_SERVER_THREAD_POOL_SIZE 50
typedef struct _MamanBar MamanBar; typedef struct _MamanBar MamanBar;
typedef struct _MamanBarClass MamanBarClass; typedef struct _MamanBarClass MamanBarClass;
@ -202,7 +204,7 @@ get_substring (const gchar *orig_str, int sub_len, GError **error)
} }
static SearpcClient * static SearpcClient *
do_create_client_with_pipe_transport() do_create_client_with_pipe_transport(void)
{ {
SearpcNamedPipeClient *pipe_client = searpc_create_named_pipe_client(pipe_path); SearpcNamedPipeClient *pipe_client = searpc_create_named_pipe_client(pipe_path);
cl_must_pass_(searpc_named_pipe_client_connect(pipe_client), "named pipe client failed to connect"); cl_must_pass_(searpc_named_pipe_client_connect(pipe_client), "named pipe client failed to connect");
@ -545,7 +547,7 @@ test_searpc__initialize (void)
client->async_send = sample_async_send; client->async_send = sample_async_send;
client->async_arg = "test_async"; client->async_arg = "test_async";
SearpcNamedPipeServer *pipe_server = searpc_create_named_pipe_server(pipe_path); SearpcNamedPipeServer *pipe_server = searpc_create_named_pipe_server_with_threadpool(pipe_path, NAMED_PIPE_SERVER_THREAD_POOL_SIZE);
cl_must_pass_(searpc_named_pipe_server_start(pipe_server), "named pipe server failed to start"); cl_must_pass_(searpc_named_pipe_server_start(pipe_server), "named pipe server failed to start");
#if defined(WIN32) #if defined(WIN32)
// Wait for the server thread to start // Wait for the server thread to start

18
vcpkg.json Normal file
View File

@ -0,0 +1,18 @@
{
"builtin-baseline": "f63682b9182187131b564c1395e4ac8ecb0c5ea8",
"dependencies": [
"glib",
"jansson",
"pthreads"
],
"overrides": [
{
"name": "jansson",
"version": "2.12-1"
},
{
"name": "pthreads",
"version": "3.0.0-4"
}
]
}