mirror of
https://github.com/haiwen/libsearpc.git
synced 2025-08-21 13:53:03 +00:00
Compare commits
76 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
d799dff145 | ||
|
6f06843849 | ||
|
255d5dedd2 | ||
|
0deb45d89f | ||
|
36706a9f32 | ||
|
d00c062d76 | ||
|
7f275255f0 | ||
|
c917575246 | ||
|
ed12cfba81 | ||
|
4ccd1988d8 | ||
|
7fd078664b | ||
|
cb1ffb2676 | ||
|
783141fb69 | ||
|
d6ba8f60dc | ||
|
d78aede0e4 | ||
|
ae466d2b3b | ||
|
97e15aa5a9 | ||
|
15f6f0b9f4 | ||
|
54145b03f4 | ||
|
e72c1158c8 | ||
|
e889dbcb50 | ||
|
50ff08b03c | ||
|
29f0c14b37 | ||
|
7e2bcb0991 | ||
|
b0079d2a0c | ||
|
9a307a916c | ||
|
719921a984 | ||
|
c5d031eaa2 | ||
|
d1fd7518a2 | ||
|
9e62d54bcf | ||
|
c206362c99 | ||
|
c72e6b6978 | ||
|
35a19401d6 | ||
|
8b853cf41d | ||
|
3291d04cec | ||
|
9b2e2dc652 | ||
|
23f581b39f | ||
|
501fa31d03 | ||
|
f7c20fa391 | ||
|
fbbdafd2ab | ||
|
f10068c3f6 | ||
|
fb7242cd09 | ||
|
b4b8548368 | ||
|
317877f996 | ||
|
19598f1d9d | ||
|
12d4c33f6e | ||
|
60ba8eca57 | ||
|
5b21fe6e69 | ||
|
1239667823 | ||
|
c137594507 | ||
|
faaff4cf7b | ||
|
c185be9413 | ||
|
2803f8d5cf | ||
|
2e1f32b83a | ||
|
0c26e154cb | ||
|
c161cb90a5 | ||
|
212281a882 | ||
|
361fdf86de | ||
|
e0d45991aa | ||
|
20be6d2edf | ||
|
6c5fea320c | ||
|
bc8f815777 | ||
|
777c9accaa | ||
|
ac0750d058 | ||
|
4f32f8be00 | ||
|
ebe09c82d5 | ||
|
55b97e1849 | ||
|
85127befda | ||
|
474bf337d8 | ||
|
22cfe9adbe | ||
|
041fd68e1c | ||
|
d19a3d1a2c | ||
|
980203eaf7 | ||
|
45bdce573f | ||
|
10e7432cab | ||
|
2021fe4aa8 |
@ -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
|
||||
|
@ -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
|
||||
|
33
configure.ac
33
configure.ac
@ -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
6
debian/changelog
vendored
@ -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
7
debian/control
vendored
@ -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
|
||||
|
2
debian/python-searpc.install
vendored
2
debian/python-searpc.install
vendored
@ -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
4
debian/rules
vendored
@ -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
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
#ifdef WIN32
|
||||
|
@ -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))
|
||||
|
@ -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
|
||||
|
||||
|
@ -36,7 +36,7 @@ static void clean_objlist(GList *list)
|
||||
|
||||
|
||||
SearpcClient *
|
||||
searpc_client_new ()
|
||||
searpc_client_new (void)
|
||||
{
|
||||
return g_new0 (SearpcClient, 1);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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});
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -1,5 +1,4 @@
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <glib.h>
|
||||
#include <glib-object.h>
|
||||
#include <jansson.h>
|
||||
|
@ -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)
|
||||
|
@ -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
31
libsearpc.sln
Normal 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
137
libsearpc.vcxproj
Normal 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>
|
@ -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')
|
||||
|
||||
|
@ -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'))
|
||||
|
@ -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__":
|
||||
|
@ -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}
|
||||
|
@ -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',
|
||||
|
@ -1,4 +1,3 @@
|
||||
|
||||
class SearpcTransport(object):
|
||||
"""
|
||||
A transport is repsonsible to send the serialized request to the
|
||||
|
@ -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)
|
||||
|
@ -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,
|
||||
|
@ -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
18
vcpkg.json
Normal 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"
|
||||
}
|
||||
]
|
||||
}
|
Loading…
Reference in New Issue
Block a user