1
0
mirror of https://github.com/haiwen/libsearpc.git synced 2025-08-21 13:53:03 +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
language: python
python:
- "2.7"
- "3.5"
- "3.6"
compiler:
- gcc
- clang
@ -7,6 +11,8 @@ addons:
apt:
packages:
- libjansson-dev
install:
- pip install future
before_install:
- git clean -x -f
- ./autogen.sh

View File

@ -18,12 +18,5 @@ endif
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:
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]),
[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.
AC_MSG_CHECKING(for WIN32)
@ -69,6 +78,23 @@ fi
AM_CONDITIONAL([MACOS], [test "$bmac" = "yes"])
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.
GLIB_REQUIRED=2.26.0
@ -84,7 +110,12 @@ PKG_CHECK_MODULES(JANSSON, [jansson >= $JANSSON_REQUIRED])
AC_SUBST(JANSSON_CFLAGS)
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 x$PYTHON_DIR != x; then
# 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
* new upstream release

7
debian/control vendored
View File

@ -4,10 +4,11 @@ Priority: extra
Maintainer: m.eik michalke <meik.michalke@hhu.de>
Build-Depends:
debhelper (>= 7),
dh-python,
autotools-dev,
intltool,
libglib2.0-dev,
python,
python3 (>= 3.5),
libtool,
libjansson-dev
Standards-Version: 3.9.5
@ -30,7 +31,7 @@ Section: libdevel
Architecture: any
Depends:
${misc:Depends},
python (>= 2.7),
python3 (>= 3.5),
libsearpc1 (= ${binary:Version})
Conflicts: seafile
Description: Development files for the libsearpc1 package.
@ -49,7 +50,7 @@ Package: python-searpc
Section: python
Multi-Arch: foreign
Architecture: all
Depends: ${python:Depends},
Depends: ${python3:Depends},
${shlibs:Depends},
${misc:Depends}
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 -*-
%:
dh $@ --with python2 --with autotools_dev --builddirectory=build
dh $@ --with python3 --with autotools_dev --builddirectory=build
override_dh_auto_configure:
./autogen.sh
dh_auto_configure -- --disable-compile-demo
dh_auto_configure -- --disable-compile-demo --with-python3
override_dh_strip:
# emptying the dependency_libs field in .la files

View File

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

View File

@ -4,6 +4,8 @@
#include <glib.h>
#include <glib-object.h>
GType test_object_get_type (void);
#define TEST_OBJECT_TYPE (test_object_get_type())
#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))

View File

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

View File

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

View File

@ -5,6 +5,16 @@
#include <glib-object.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
#define DFT_DOMAIN g_quark_from_string(G_LOG_DOMAIN)
#endif
@ -31,85 +41,88 @@ struct _SearpcClient {
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,
const char *ret_type, GType gobject_type,
void *ret_ptr, GError **error,
int n_params, ...);
int
LIBSEARPC_API int
searpc_client_call__int (SearpcClient *client, const char *fname,
GError **error, int n_params, ...);
gint64
LIBSEARPC_API gint64
searpc_client_call__int64 (SearpcClient *client, const char *fname,
GError **error, int n_params, ...);
char *
LIBSEARPC_API char *
searpc_client_call__string (SearpcClient *client, const char *fname,
GError **error, int n_params, ...);
GObject *
LIBSEARPC_API GObject *
searpc_client_call__object (SearpcClient *client, const char *fname,
GType object_type,
GError **error, int n_params, ...);
GList*
LIBSEARPC_API GList*
searpc_client_call__objlist (SearpcClient *client, const char *fname,
GType object_type,
GError **error, int n_params, ...);
json_t *
LIBSEARPC_API json_t *
searpc_client_call__json (SearpcClient *client, const char *fname,
GError **error, int n_params, ...);
char* searpc_client_transport_send (SearpcClient *client,
const gchar *fcall_str,
size_t fcall_len,
size_t *ret_len);
LIBSEARPC_API char*
searpc_client_transport_send (SearpcClient *client,
const gchar *fcall_str,
size_t fcall_len,
size_t *ret_len);
int
LIBSEARPC_API int
searpc_client_async_call__int (SearpcClient *client,
const char *fname,
AsyncCallback callback, void *cbdata,
int n_params, ...);
int
LIBSEARPC_API int
searpc_client_async_call__int64 (SearpcClient *client,
const char *fname,
AsyncCallback callback, void *cbdata,
int n_params, ...);
int
LIBSEARPC_API int
searpc_client_async_call__string (SearpcClient *client,
const char *fname,
AsyncCallback callback, void *cbdata,
int n_params, ...);
int
LIBSEARPC_API int
searpc_client_async_call__object (SearpcClient *client,
const char *fname,
AsyncCallback callback,
GType object_type, void *cbdata,
int n_params, ...);
int
LIBSEARPC_API int
searpc_client_async_call__objlist (SearpcClient *client,
const char *fname,
AsyncCallback callback,
GType object_type, void *cbdata,
int n_params, ...);
int
LIBSEARPC_API int
searpc_client_async_call__json (SearpcClient *client,
const char *fname,
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
* modify the str, but not take ownership of it */
int
LIBSEARPC_API int
searpc_client_generic_callback (char *retstr, size_t len,
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_CODE 500
#ifdef __cplusplus
}
#endif
#endif

View File

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

View File

@ -8,8 +8,13 @@
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#ifdef __linux__
#include <fcntl.h>
#include <sys/epoll.h>
#endif
#endif // !defined(WIN32)
#include <glib.h>
#include <glib/gstdio.h>
#include <jansson.h>
@ -32,7 +37,9 @@ static char* formatErrorMessage();
#endif // defined(WIN32)
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 * 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 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 ssize_t pipe_read_n(SearpcNamedPipe fd, void *vptr, size_t n);
static gssize pipe_write_n(SearpcNamedPipe fd, const void *vptr, size_t n);
static gssize pipe_read_n(SearpcNamedPipe fd, void *vptr, size_t n);
typedef struct {
SearpcNamedPipeClient* client;
@ -74,6 +81,33 @@ SearpcNamedPipeServer* searpc_create_named_pipe_server(const char *path)
{
SearpcNamedPipeServer *server = g_malloc0(sizeof(SearpcNamedPipeServer));
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;
}
@ -99,7 +133,7 @@ int searpc_named_pipe_server_start(SearpcNamedPipeServer *server)
}
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) {
g_warning ("delete socket file failed : %s\n", strerror(errno));
goto failed;
@ -124,6 +158,28 @@ int searpc_named_pipe_server_start(SearpcNamedPipeServer *server)
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;
#endif // !defined(WIN32)
@ -140,26 +196,187 @@ failed:
}
typedef struct {
SearpcNamedPipeServer *server;
SearpcNamedPipe connfd;
SearpcNamedPipeServer *server;
gboolean use_epoll;
} 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)
{
SearpcNamedPipeServer *server = arg;
#if !defined(WIN32)
#ifdef __linux__
if (server->use_epoll) {
epoll_listen (server);
return NULL;
}
#endif
while (1) {
int connfd = accept (server->pipe_fd, NULL, 0);
pthread_t *handler = g_malloc(sizeof(pthread_t));
ServerHandlerData *data = g_malloc(sizeof(ServerHandlerData));
data->server = server;
data->connfd = connfd;
// TODO(low priority): Instead of using a thread to handle each client,
// use select(unix)/iocp(windows) to do it.
pthread_create(handler, NULL, named_pipe_client_handler, data);
server->handlers = g_list_append(server->handlers, handler);
data->use_epoll = FALSE;
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);
}
}
#else // !defined(WIN32)
while (1) {
HANDLE connfd = INVALID_HANDLE_VALUE;
@ -192,53 +409,79 @@ static void* named_pipe_listen(void *arg)
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));
data->server = server;
data->connfd = connfd;
// TODO(low priority): Instead of using a thread to handle each client,
// use select(unix)/iocp(windows) to do it.
pthread_create(handler, NULL, named_pipe_client_handler, data);
server->handlers = g_list_append(server->handlers, handler);
data->use_epoll = FALSE;
if (server->named_pipe_server_thread_pool)
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 // !defined(WIN32)
return NULL;
}
static void* named_pipe_client_handler(void *arg)
static void* handle_named_pipe_client_with_thread(void *arg)
{
ServerHandlerData *data = arg;
// SearpcNamedPipeServer *server = data->server;
SearpcNamedPipe connfd = data->connfd;
#ifdef __linux__
ServerHandlerData *handler_data = arg;
if (handler_data->use_epoll) {
epoll_handler (arg);
return NULL;
}
#endif
named_pipe_client_handler(arg);
size_t len;
size_t bufsize = 4096;
return NULL;
}
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);
g_debug ("start to serve on pipe client\n");
while (1) {
len = 0;
if (pipe_read_n(connfd, &len, sizeof(uint32_t)) < 0) {
g_warning("failed to read rpc request size: %s", strerror(errno));
if (pipe_read_n(connfd, &len, sizeof(guint32)) < 0) {
g_warning("failed to read rpc request size: %s\n", strerror(errno));
break;
}
if (len == 0) {
g_debug("EOF reached, pipe connection lost");
/* g_debug("EOF reached, pipe connection lost"); */
break;
}
while (bufsize < len) {
bufsize *= 2;
buf = realloc(buf, bufsize);
buf = g_realloc(buf, bufsize);
}
if (pipe_read_n(connfd, buf, len) < 0 || len == 0) {
g_warning("failed to read rpc request: %s", strerror(errno));
g_free (buf);
g_warning("failed to read rpc request: %s\n", strerror(errno));
break;
}
@ -247,19 +490,20 @@ static void* named_pipe_client_handler(void *arg)
break;
}
size_t ret_len;
gsize ret_len;
char *ret_str = searpc_server_call_function (service, body, strlen(body), &ret_len);
g_free (service);
g_free (body);
if (pipe_write_n(connfd, &ret_len, sizeof(uint32_t)) < 0) {
g_warning("failed to send rpc response(%s): %s", ret_str, strerror(errno));
len = (guint32)ret_len;
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);
break;
}
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);
break;
}
@ -273,11 +517,10 @@ static void* named_pipe_client_handler(void *arg)
DisconnectNamedPipe(connfd);
CloseHandle(connfd);
#endif // !defined(WIN32)
return NULL;
g_free (data);
g_free (buf);
}
int searpc_named_pipe_client_connect(SearpcNamedPipeClient *client)
{
#if !defined(WIN32)
@ -288,29 +531,39 @@ int searpc_named_pipe_client_connect(SearpcNamedPipeClient *client)
g_strlcpy (servaddr.sun_path, client->path, sizeof(servaddr.sun_path));
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));
close(client->pipe_fd);
return -1;
}
#else // !defined(WIN32)
SearpcNamedPipe pipe_fd;
pipe_fd = CreateFile(
client->path, // pipe name
GENERIC_READ | // read and write access
GENERIC_WRITE,
0, // no sharing
NULL, // default security attributes
OPEN_EXISTING, // opens existing pipe
0, // default attributes
NULL); // no template file
if (pipe_fd == INVALID_HANDLE_VALUE) {
G_WARNING_WITH_LAST_ERROR("Failed to connect to named pipe");
return -1;
for (;;) {
pipe_fd = CreateFile(
client->path, // pipe name
GENERIC_READ | // read and write access
GENERIC_WRITE,
0, // no sharing
NULL, // default security attributes
OPEN_EXISTING, // opens existing pipe
0, // default attributes
NULL); // no template file
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");
return -1;
}
}
DWORD mode = PIPE_READMODE_MESSAGE;
if (!SetNamedPipeHandleState(pipe_fd, &mode, NULL, NULL)) {
G_WARNING_WITH_LAST_ERROR("Failed to set named pipe mode");
CloseHandle (pipe_fd);
return -1;
}
@ -318,7 +571,7 @@ int searpc_named_pipe_client_connect(SearpcNamedPipeClient *client)
#endif // !defined(WIN32)
g_debug ("pipe client connected to server\n");
/* g_debug ("pipe client connected to server\n"); */
return 0;
}
@ -332,6 +585,7 @@ void searpc_free_client_with_pipe_transport (SearpcClient *client)
close(pipe_client->pipe_fd);
#endif
g_free (pipe_client);
g_free (data->service);
g_free (data);
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,
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;
SearpcNamedPipeClient *client = data->client;
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(uint32_t)) < 0) {
g_warning("failed to send rpc call: %s", strerror(errno));
if (pipe_write_n(client->pipe_fd, &len, sizeof(guint32)) < 0) {
g_warning("failed to send rpc call: %s\n", strerror(errno));
free (json_str);
return NULL;
}
if (pipe_write_n(client->pipe_fd, json_str, json_len) < 0) {
g_warning("failed to send rpc call: %s", strerror(errno));
if (pipe_write_n(client->pipe_fd, json_str, len) < 0) {
g_warning("failed to send rpc call: %s\n", strerror(errno));
free (json_str);
return NULL;
}
free (json_str);
if (pipe_read_n(client->pipe_fd, &len, sizeof(uint32_t)) < 0) {
g_warning("failed to read rpc response: %s", strerror(errno));
if (pipe_read_n(client->pipe_fd, &len, sizeof(guint32)) < 0) {
g_warning("failed to read rpc response: %s\n", strerror(errno));
return NULL;
}
char *buf = g_malloc(len);
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);
return NULL;
}
@ -437,11 +690,11 @@ json_object_get_string_member (json_t *object, const char *key)
#if !defined(WIN32)
// Write "n" bytes to a descriptor.
ssize_t
gssize
pipe_write_n(int fd, const void *vptr, size_t n)
{
size_t nleft;
ssize_t nwritten;
gssize nwritten;
const char *ptr;
ptr = vptr;
@ -462,11 +715,11 @@ pipe_write_n(int fd, const void *vptr, size_t n)
}
// Read "n" bytes from a descriptor.
ssize_t
gssize
pipe_read_n(int fd, void *vptr, size_t n)
{
size_t nleft;
ssize_t nread;
gssize nread;
char *ptr;
ptr = vptr;
@ -488,7 +741,7 @@ pipe_read_n(int fd, void *vptr, size_t n)
#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;
BOOL success = ReadFile(
@ -509,7 +762,7 @@ ssize_t pipe_read_n (SearpcNamedPipe fd, void *vptr, size_t 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;
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
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);
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
// The caller is responsible to free the returned message.
char* formatErrorMessage()
@ -564,11 +793,12 @@ char* formatErrorMessage()
FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
error_code,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
/* EN_US */
MAKELANGID(LANG_ENGLISH, 0x01),
buf,
sizeof(buf) - 1,
NULL);
return locale_to_utf8(buf);
return g_strdup(buf);
}
#endif // !defined(WIN32)

View File

@ -10,6 +10,16 @@
#include <windows.h>
#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
// sockets on linux/osx, and named pipes on windows.
//
@ -30,14 +40,22 @@ typedef int SearpcNamedPipe;
struct _SearpcNamedPipeServer {
char path[4096];
pthread_t listener_thread;
GList *handlers;
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);
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);
// Client side interface.
@ -47,14 +65,22 @@ struct _SearpcNamedPipeClient {
SearpcNamedPipe pipe_fd;
};
typedef struct _SearpcNamedPipeClient SearpcNamedPipeClient;
typedef struct _SearpcNamedPipeClient LIBSEARPC_API SearpcNamedPipeClient;
LIBSEARPC_API
SearpcNamedPipeClient* searpc_create_named_pipe_client(const char *path);
LIBSEARPC_API
SearpcClient * searpc_client_with_named_pipe_transport(SearpcNamedPipeClient *client, const char *service);
LIBSEARPC_API
int searpc_named_pipe_client_connect(SearpcNamedPipeClient *client);
LIBSEARPC_API
void searpc_free_client_with_pipe_transport (SearpcClient *client);
#ifdef __cplusplus
}
#endif
#endif // SEARPC_NAMED_PIPE_TRANSPORT_H

View File

@ -9,8 +9,10 @@
#include "searpc-server.h"
#include "searpc-utils.h"
#ifdef PROFILE
#include <sys/time.h>
#ifdef __linux__
#include <sys/time.h>
#include <sys/errno.h>
#include <pthread.h>
#endif
struct FuncItem;
@ -34,6 +36,14 @@ typedef struct {
static GHashTable *marshal_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
func_item_free (FuncItem *item)
{
@ -136,7 +146,10 @@ searpc_set_objlist_to_ret_object (json_t *object, GList *ret)
void
searpc_set_json_to_ret_object (json_t *object, json_t *ret)
{
json_object_set_new (object, "ret", ret);
if (ret == NULL)
json_object_set_new(object, "ret", json_null ());
else
json_object_set_new (object, "ret", ret);
}
char *
@ -185,8 +198,67 @@ searpc_server_init (RegisterMarshalFunc 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
searpc_server_final()
searpc_server_final(void)
{
g_hash_table_destroy (service_table);
g_hash_table_destroy (marshal_table);
@ -244,6 +316,53 @@ searpc_server_register_function (const char *svc_name,
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. */
char*
searpc_server_call_function (const char *svc_name,
@ -255,10 +374,12 @@ searpc_server_call_function (const char *svc_name,
json_error_t jerror;
GError *error = NULL;
#ifdef PROFILE
#ifdef __linux__
struct timeval start, end, intv;
gettimeofday(&start, NULL);
if (slow_log_fp) {
gettimeofday(&start, NULL);
}
#endif
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);
#ifdef PROFILE
gettimeofday(&end, NULL);
timersub(&end, &start, &intv);
g_debug ("[searpc] Time spend in call %s: %ds %dus\n",
fname, intv.tv_sec, intv.tv_usec);
#ifdef __linux__
if (slow_log_fp) {
if (!filtered_funcs || !rpc_include_passwd (fitem->fname)) {
gettimeofday(&end, NULL);
timersub(&end, &start, &intv);
print_slow_log_if_necessary (svc_name, func, len, &start, &intv);
}
}
#endif
json_decref(array);

View File

@ -5,6 +5,16 @@
#include <glib-object.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
#define DFT_DOMAIN g_quark_from_string(G_LOG_DOMAIN)
#endif
@ -13,11 +23,17 @@ typedef gchar* (*SearpcMarshalFunc) (void *func, json_t *param_array,
gsize *ret_len);
typedef void (*RegisterMarshalFunc) (void);
LIBSEARPC_API
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);
LIBSEARPC_API
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);
LIBSEARPC_API
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);
/**
@ -25,14 +41,33 @@ char *searpc_marshal_set_ret_common (json_t *object, gsize *len, GError *error);
*
* Inititalize searpc server.
*/
LIBSEARPC_API
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:
*
* Free the server structure.
*/
void searpc_server_final ();
LIBSEARPC_API
void searpc_server_final (void);
/**
* searpc_create_service:
@ -42,6 +77,7 @@ void searpc_server_final ();
*
* @svc_name: Service name.
*/
LIBSEARPC_API
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.
*/
LIBSEARPC_API
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
* owner of this string.
*/
LIBSEARPC_API
gboolean searpc_server_register_marshal (gchar *signature,
SearpcMarshalFunc marshal);
@ -70,6 +108,7 @@ gboolean searpc_server_register_marshal (gchar *signature,
* @signature: the signature of the function, register_function() will take
* owner of this string.
*/
LIBSEARPC_API
gboolean searpc_server_register_function (const char *service,
void* func,
const gchar *fname,
@ -86,6 +125,7 @@ gboolean searpc_server_register_function (const char *service,
*
* Returns the serialized representatio of the returned value.
*/
LIBSEARPC_API
gchar *searpc_server_call_function (const char *service,
gchar *func, gsize len, gsize *ret_len);
@ -96,6 +136,11 @@ gchar *searpc_server_call_function (const char *service,
*
* Compute function signature.
*/
LIBSEARPC_API
char* searpc_compute_signature (const gchar *ret_type, int pnum, ...);
#ifdef __cplusplus
}
#endif
#endif

View File

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

View File

@ -2,15 +2,23 @@
#include <glib-object.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")
typedef enum {
SEARPC_JSON_ERROR_LOAD,
SEARPC_JSON_ERROR_PACK,
SEARPC_JSON_ERROR_UPACK
} SEARPCJSONERROR;
} LIBSEARPC_API SEARPCJSONERROR;
LIBSEARPC_API
json_t *json_gobject_serialize (GObject *);
LIBSEARPC_API
GObject *json_gobject_deserialize (GType , json_t *);
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@
libdir=@libdir@
includedir=@includedir@
@ -8,4 +8,4 @@ Description: Simple C rpc library
Version: @VERSION@
Libs: -L${libdir} -lsearpc
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
from common import SearpcError
from .common import SearpcError
def _fret_int(ret_str):
try:
@ -7,10 +7,10 @@ def _fret_int(ret_str):
except:
raise SearpcError('Invalid response format')
if dicts.has_key('err_code'):
if 'err_code' in dicts:
raise SearpcError(dicts['err_msg'])
if dicts.has_key('ret'):
if 'ret' in dicts:
return dicts['ret']
else:
raise SearpcError('Invalid response format')
@ -21,10 +21,10 @@ def _fret_string(ret_str):
except:
raise SearpcError('Invalid response format')
if dicts.has_key('err_code'):
if 'err_code' in dicts:
raise SearpcError(dicts['err_msg'])
if dicts.has_key('ret'):
if 'ret' in dicts:
return dicts['ret']
else:
raise SearpcError('Invalid response format')
@ -61,7 +61,7 @@ def _fret_obj(ret_str):
except:
raise SearpcError('Invalid response format')
if dicts.has_key('err_code'):
if 'err_code' in dicts:
raise SearpcError(dicts['err_msg'])
if dicts['ret']:
@ -75,7 +75,7 @@ def _fret_objlist(ret_str):
except:
raise SearpcError('Invalid response format')
if dicts.has_key('err_code'):
if 'err_code' in dicts:
raise SearpcError(dicts['err_msg'])
l = []
@ -85,6 +85,19 @@ def _fret_objlist(ret_str):
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):
@ -101,6 +114,8 @@ def searpc_func(ret_type, param_types):
fret = _fret_int
elif ret_type == "string":
fret = _fret_string
elif ret_type == "json":
fret = _fret_json
else:
raise SearpcError('Invial return type')

View File

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

View File

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

View File

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

View File

@ -22,6 +22,14 @@ def init_server():
searpc_server.create_service(SVCNAME)
searpc_server.register_function(SVCNAME, add, 'add')
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):
@ -40,6 +48,14 @@ class RpcMixin(object):
def multi(self, x, y):
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):
def __init__(self):
self.transport = DummyTransport()
@ -66,7 +82,6 @@ class SearpcTest(unittest.TestCase):
@classmethod
def tearDownClass(cls):
cls.named_pipe_client.stop()
cls.named_pipe_server.stop()
def test_normal_transport(self):
@ -86,6 +101,12 @@ class SearpcTest(unittest.TestCase):
v = client.multi('abc', 2)
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):
kw = {
# 'format': '[%(asctime)s][%(pathname)s]: %(message)s',

View File

@ -1,4 +1,3 @@
class SearpcTransport(object):
"""
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):
remain = total
data = ''
data = bytearray()
while remain > 0:
try:
new = fd.recv(remain)
@ -16,10 +16,10 @@ def recvall(fd, total):
if n <= 0:
raise NetworkError("Failed to read from socket")
else:
data += new
data.extend(new)
remain -= n
return data
return bytes(data)
def sendall(fd, data):
total = len(data)

View File

@ -371,7 +371,7 @@ clar_test_init(int argc, char **argv)
}
int
clar_test_run()
clar_test_run(void)
{
if (_clar.argc > 1)
clar_parse_args(_clar.argc, _clar.argv);
@ -386,7 +386,7 @@ clar_test_run()
}
void
clar_test_shutdown()
clar_test_shutdown(void)
{
clar_print_shutdown(
_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_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 _MamanBarClass MamanBarClass;
@ -202,7 +204,7 @@ get_substring (const gchar *orig_str, int sub_len, GError **error)
}
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);
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_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");
#if defined(WIN32)
// 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"
}
]
}