pax_global_header00006660000000000000000000000064136725570370014531gustar00rootroot0000000000000052 comment=50ff08b03c7cec8e10b35ba438633b9fe08a8d90 libsearpc-3.2-latest/000077500000000000000000000000001367255703700146335ustar00rootroot00000000000000libsearpc-3.2-latest/.gitignore000066400000000000000000000013321367255703700166220ustar00rootroot00000000000000*~ *.pyc *.o *.lo *.la *.defs *.log .deps *.db *.gz compile config.* autom4te.cache/* aclocal.m4 config.* configure Makefile */Makefile Makefile.in */Makefile.in .libs/ */.libs/ stamp-h1 searpc-demo-server searpc-demo-client searpc-async-client pysearpc/fcallfret.h m4/l* depcomp install-sh libtool ltmain.sh missing py-compile cscope.files cscope.out lib/fcall-impr.h lib/marshal.h lib/searpc-dfun.h lib/searpc-fcall.h lib/searpc-signature.h tests/test-searpc cscope* pysearpc/rpc_table.py *.pc demo/searpc-marshal.h demo/searpc-signature.h demo/rpc_table.stamp demo/rpc_table.tmp tests/searpc-marshal.h tests/searpc-signature.h tests/rpc_table.stamp tests/rpc_table.tmp tests/clar.suite tests/.clarcache tests/*.trs test-driver libsearpc-3.2-latest/.travis.yml000066400000000000000000000005341367255703700167460ustar00rootroot00000000000000sudo: false language: python python: - "2.7" - "3.5" - "3.6" compiler: - gcc - clang addons: apt: packages: - libjansson-dev install: - pip install future before_install: - git clean -x -f - ./autogen.sh script: - ./configure - make -j4 - make check -j4 - python pysearpc/test_pysearpc.py notifications: email: false libsearpc-3.2-latest/AUTHORS000066400000000000000000000001361367255703700157030ustar00rootroot00000000000000Lingtao Pan Zheng Liu Shuai Lin libsearpc-3.2-latest/ChangeLog000066400000000000000000000000001367255703700163730ustar00rootroot00000000000000libsearpc-3.2-latest/INSTALL000066400000000000000000000031101367255703700156570ustar00rootroot00000000000000Basic Installation ================== Libsearpc requires several other packages to be built. Before installing, read the `README` file and MAKE SURE the required packages have been installed in your system. 1. If you downladed a tarball. Extract it to some path like `~/dev`, and cd ~/dev/libsearpc-1.0 If you git-cloned it from the repo, just cd into the directory. 2. run the following commands sequentially: ./autogen.sh ./configure make make install Note that `make install` requires root privilege, for example `sudo make install` in Debian distribution. Optionally compile pysearpc =========================== By default, Pysearpc are compiled. If you'd like to not compile pysearpc, use the following command: ./configure --enable-compile-python=no In this way, Pysearpc would not be compiled or installed. In MacOs, if you want to use py2app, you would better run the following commnads: ./configure LDFLAGS="-Xlinker -headerpad_max_install_names" In this way, the following error will be avoided: raise ValueError("New Mach-O header is too large to relocate") Optionally compile demos ======================== By default, a pair of client/server demo programs are compiled. If you'd like to disable this, use the following command: ./configure --enable-compile-demo=no Note that whatever your choice is, the demos would never be installed. They just stay in the source directory. Other options ============= Other options provided by Autoconf can be found in the manual of GNU Autoconf. http://www.gnu.org/software/autoconf/manual/autoconf.html libsearpc-3.2-latest/LICENSE.txt000066400000000000000000000010741367255703700164600ustar00rootroot00000000000000 Copyright (C) 2012-2016 Seafile Ltd. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. libsearpc-3.2-latest/Makefile.am000066400000000000000000000011731367255703700166710ustar00rootroot00000000000000AM_CPPFLAGS = -I$(top_srcdir)/lib ACLOCAL_AMFLAGS = -I m4 GNU_STANDARD_FILES = README.markdown AUTHORS ChangeLog NEWS pcfiles = libsearpc.pc pkgconfig_DATA = $(pcfiles) pkgconfigdir = $(libdir)/pkgconfig EXTRA_DIST = $(GNU_STANDARD_FILES) LICENSE.txt EXTRA_DIST += libsearpc.pc.in if COMPILE_DEMO MAKE_DEMO = demo endif SUBDIRS = lib pysearpc ${MAKE_DEMO} tests install-data-local: if MACOS sed -i '' -e "s|(DESTDIR)|${DESTDIR}|g" $(pcfiles) else if FBSD sed -i '' -e "s|(DESTDIR)|${DESTDIR}|g" $(pcfiles) else ${SED} -i "s|(DESTDIR)|${DESTDIR}|g" $(pcfiles) endif endif dist-hook: git log -1 > $(distdir)/latest_commit libsearpc-3.2-latest/NEWS000066400000000000000000000000001367255703700153200ustar00rootroot00000000000000libsearpc-3.2-latest/README.markdown000066400000000000000000000231701367255703700173370ustar00rootroot00000000000000Introduction [![Build Status](https://secure.travis-ci.org/haiwen/libsearpc.png?branch=master)](http://travis-ci.org/haiwen/libsearpc) ============ Searpc is a simple C language RPC framework based on GObject system. Searpc handles the serialization/deserialization part of RPC, the transport part is left to users. The serialization/deserialization uses JSON format via json-glib library. A serialized json object is returned from server to client after executing the RPC function. Each RPC function defined in the server side should take an extra GError argument to report error. The returned json object contains three fields: * **ret**: the return value of the RPC function * **err_code**: error code. This field is only set if the RPC function reports an error. * **err_msg**: error message. This field is only set if the RPC function reports an error. Compile ======= Just ./autogen.sh; ./configure; make; make install To enable profile, Use CFLAGS="-DPROFILE" ./configure When profile is enabled, the time spend in each rpc call will be printed. Example ======= Client ------ In the client side, you need to: * Create a rpc_client and supply the transport function. * write code to send the request to server and get the resonpse from it. ### Create rpc_client ### The client needs to create a SearpcClient object and supply a transport function. For example: /* create an rpc_client and supply the transport function. */ SearpcClient *rpc_client; rpc_client = searpc_client_new(); rpc_client->transport = transport_callback; rpc_client->arg = &sockfd; Suppose we have a `get_substring` function defined in server as follows: gchar *get_substring (const gchar *orig_str, int sub_len, GError **error) To call this function, we type: gchar* result; GError *error = NULL; result = searpc_client_call__string (client, "get_substring", &error, 2, "string", "hello", "int", 2); `string` in `searpc_client_call__string` specify the return type. "get_substring" is the function name. The remain parameters specify the number of parameters the rpc function took and the type of each parameter and its value. So 2, "string", "hello", "int", 2 means "get_substring" takes 2 parameters, the first is of type "string", the value is "hello", the second is of type "int", the value is 2. ### Transport function ### When the client-side function is called, Searpc does the following work: * Pack the function name and the params into JSON data format. * Call your transport function to send the JSON data to the server, and get the returned data from the server. * Unpack the returned JSON data and return the value as the return value of the client-side function. Your transport function is supposed to: * Send the request data to the server. * Receive the returned data from the server. The prototype of the transport function is: /* * arg: rpc_client->arg. Normally a socket number. * fcall_str: the JSON data stream generated by Searpc. * fcall_len: the length of `fcall_str`. * ret_len: place to get the length of the returned json data stream. * Returns: A newly allocated string stores the JSON data stream. */ static char *transport_callback (void *arg, const char *fcall_str, size_t fcall_len, size_t *ret_len); Server ------ In the server side, you need to: * Init searpc server * Create services and register your functions * write code to receive the request and send the result And Searpc handles the others for you. ### Concepts ### * **Marshal**: The process of unpacking the function arguments from JSON data, call the RPC function and packing the result into JSON data format is called marshalling. The function used to pack the result is called a **marshal**. * **Signature**: Every function has a signature determined by its return type and parameter types. Knowning a function's signature enable us to use a corresponding marshal to call it and convert the result into json string. ### Init Searpc Server ### First write rpc_table.py to contain the rpc function signatures as follows: # [ , [] ] func_table = [ [ "int", ["string"] ], [ "string", ["int", "string"] ], ] Add makefile rule: searpc-signature.h searpc-marshal.h: rpc_table.py python searpc-codegen.py rpc_table.py `searpc-signature.h` and `searpc-marshal.h` will be created containing the function signatures and corresponding marshals. `searpc-marshal.h` also contains a function called `register_marshals`. Then we init the server as follows: #include "searpc-signature.h" #include "searpc-marshal.h" static void init_rpc_service(void) { /* register_marshals is defined in searpc-marshal.h */ searpc_server_init(register_marshals); } ### Register Functions ### To register a function we first need to create a service. A service is a set of functions. Suppose we want to make `searpc_strlen` callable from some network clients, we can do this by putting the following code somewhere: static int searpc_strlen(const char *str) { if (str == NULL) return -1; else return strlen(str); } static void register_functions() { searpc_create_service("searpc-demo"); /* The first parameter is the implementation function. * The second parameter is the name of the rpc function the * client would call. * The third parameter is the signature. */ searpc_server_register_function("searpc-demo", searpc_strlen, "searpc_strlen", searpc_signature_int__string()); } The `seaprc_server_register_function` routine registers a function as a RPC function. The prototype of this function is: /* * service: the name of the service * func: pointer to the function you want to register * fname: the name of the function. It would be the key of your * function in the fucntion hash table. * signature: the identifier used to get the corresponding marshal. * Returns: a gboolean value indicating success or failure */ gboolean searpc_server_register_function (const char *service, void* func, const gchar *fname, gchar *signature); ### Call the RPC fucntion ### After the registration, you should listen to the socket and wait for the incoming request data stream. Once you get a valid request, call the `searpc_server_call_function()` routine, which will automatically do the following work for you: * Parse the JSON data stream to resolve the function name and the data. * Lookup the function in internal function table according to the funcname. * If a proper function is found, call the function with the given params. * Packing the result into a JSON data string. The prototype of `searpc_server_call_function` is: /* * service: Service name. * data: The incoming JSON data stream. * len: The length of **`data`**. * ret_len: Place to hold the length of the JSON data stream to be returned * Returns: The JSON data containing the result of the RPC */ gchar* searpc_server_call_function (const char *service, gchar *data, gsize len, gsize *ret_len) The value returned by `searpc_server_call_function()` is the JSON data ready to send back to the client. Note, the JSON data stream from client does not contain the service name, it's left to the transport layer to solve the problem. There are several ways, for example: 1. You may listen on different sockets and determine the service by the incoming socket. 2. The client transport function prepend the service name into the request before the json data, and the server transport function first read the service name and read the json data. Pysearpc ======== **Pysearpc** is the Python binding of **Searpc**. Only the client side function is supported. To use it, simply define a class which inherits **SearpcClient**, and provide a `call_remote_func_sync` method, which is equivalent to the `transport_callback`. To define your RPC funtion, use the `@searpc_func` decorator. It is equivalent to `SEARPC_CLIENT_DEFUN_XXX__YYY` macro. To define a RPC function which accepts multiple params, here is an example: class SampeSearpcClient(SearpcClient): def call_remote_func_sync(self, fcall_str): # your transport code here ... @searpc_func("int", ["string", "string"]) def searpc_demo_func(self): # this is enough for the client side pass See the demo program for a more detailed example. Demos ===== There are well-commented demos in both C and Python. * **searpc-demo-server.c**: The server side demo program * **searpc-demo-client.c**: The client side demo in C * **pysearpc-demo-client.py**: The client side demo in Python To run the demo, run the server demo in a shell, and run the client demo in another. To run the python demo, you should first install the package and setup the **PYTHONPATH** appropriately. Dependency ========== The following packages are required to build libsearpc: * glib-2.0 >= 2.26.0 * gobject-2.0 >= 2.26.0 * jansson >= 2.2.1 * python simplejson (for pysearpc) libsearpc-3.2-latest/autogen.sh000077500000000000000000000042101367255703700166310ustar00rootroot00000000000000#!/bin/bash # Run this to generate all the initial makefiles, etc. : ${AUTOCONF=autoconf} : ${AUTOHEADER=autoheader} : ${AUTOMAKE=automake} : ${ACLOCAL=aclocal} if test "$(uname)" != "Darwin"; then : ${LIBTOOLIZE=libtoolize} else : ${LIBTOOLIZE=glibtoolize} fi : ${LIBTOOL=libtool} srcdir=`dirname $0` test -z "$srcdir" && srcdir=. cd $srcdir PROJECT=libsearpc CONFIGURE=configure.ac DIE=0 ($AUTOCONF --version) < /dev/null > /dev/null 2>&1 || { echo echo "You must have autoconf installed to compile $PROJECT." echo "Download the appropriate package for your distribution," echo "or get the source tarball at ftp://ftp.gnu.org/pub/gnu/" DIE=1 } ($AUTOMAKE --version) < /dev/null > /dev/null 2>&1 || { echo echo "You must have automake installed to compile $PROJECT." echo "Get ftp://sourceware.cygnus.com/pub/automake/automake-1.7.tar.gz" echo "(or a newer version if it is available)" DIE=1 } if test "$(uname)" != "Darwin"; then (grep "^AC_PROG_LIBTOOL" $CONFIGURE >/dev/null) && { ($LIBTOOL --version) < /dev/null > /dev/null 2>&1 || { echo echo "**Error**: You must have \`libtool' installed to compile $PROJECT." echo "Get ftp://ftp.gnu.org/pub/gnu/libtool-1.4.tar.gz" echo "(or a newer version if it is available)" DIE=1 } } fi if test "$DIE" -eq 1; then exit 1 fi dr=`dirname .` echo processing $dr aclocalinclude="$aclocalinclude -I m4" if test x"$MSYSTEM" = x"MINGW32"; then aclocalinclude="$aclocalinclude -I /mingw32/share/aclocal" elif test "$(uname)" = "Darwin"; then aclocalinclude="$aclocalinclude -I /opt/local/share/aclocal" fi echo "Creating $dr/aclocal.m4 ..." test -r $dr/aclocal.m4 || touch $dr/aclocal.m4 echo "Running glib-gettextize... Ignore non-fatal messages." echo "no" | glib-gettextize --force --copy echo "Making $dr/aclocal.m4 writable ..." test -r $dr/aclocal.m4 && chmod u+w $dr/aclocal.m4 echo "Running $LIBTOOLIZE..." $LIBTOOLIZE --force --copy echo "Running $ACLOCAL $aclocalinclude ..." $ACLOCAL $aclocalinclude echo "Running $AUTOHEADER..." $AUTOHEADER echo "Running $AUTOMAKE --gnu $am_opt ..." $AUTOMAKE --add-missing --gnu $am_opt echo "Running $AUTOCONF ..." $AUTOCONF libsearpc-3.2-latest/configure.ac000066400000000000000000000056541367255703700171330ustar00rootroot00000000000000# -*- Autoconf -*- # Process this file with autoconf to produce a configure script. AC_PREREQ([2.61]) AC_INIT([libsearpc], [3.1.0], [info@seafile.com]) AC_CONFIG_SRCDIR([lib/searpc-server.c]) AC_CONFIG_HEADERS([config.h]) AC_CONFIG_MACRO_DIR([m4]) AM_INIT_AUTOMAKE([1.9 foreign]) #AC_MINGW32 AC_CANONICAL_BUILD # Checks for programs. AC_PROG_CC LT_INIT # Checks for header files. #AC_CHECK_HEADERS([arpa/inet.h netinet/in.h stdint.h stdlib.h string.h sys/socket.h sys/time.h unistd.h]) # Checks for typedefs, structures, and compiler characteristics. #AC_C_INLINE #AC_TYPE_SIZE_T #AC_TYPE_SSIZE_T #AC_TYPE_UINT16_T # Checks for library functions. #AC_CHECK_FUNCS([memset socket strerror strndup]) # Options about demos and pysearpc # option: compile-demo # default: yes AC_ARG_ENABLE([compile-demo], [AS_HELP_STRING([--enable-compile-demo], [compile demo programs @<:@default: yes@:>@])], [compile_demo=${enableval}], [compile_demo=yes]) AM_CONDITIONAL([COMPILE_DEMO], [test x${compile_demo} = xyes]) AC_ARG_ENABLE(server-pkg, AC_HELP_STRING([--enable-server-pkg], [enable static compile]), [server_pkg=$enableval],[server_pkg="no"]) dnl - check if the macro WIN32 is defined on this compiler. AC_MSG_CHECKING(for WIN32) if test "$build_os" = "mingw32" -o "$build_os" = "mingw64"; then bwin32=true LIB_WS32=-lws2_32 AC_SUBST(LIB_WS32) AC_MSG_RESULT(compile in mingw) fi AM_CONDITIONAL([WIN32], [test "$MINGW32" = "yes"]) AC_SUBST(WIN32) AC_MSG_CHECKING(for Mac) if test "$(uname -s)" = "Darwin"; then bmac=yes fi if test x$bmac = "xyes"; then server_pkg=no AC_MSG_RESULT(compile in mac) 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 # check and subst gobject PKG_CHECK_MODULES(GLIB, [gobject-2.0 >= $GLIB_REQUIRED]) AC_SUBST(GLIB_CFLAGS) AC_SUBST(GLIB_LIBS) JANSSON_REQUIRED=2.2.1 PKG_CHECK_MODULES(JANSSON, [jansson >= $JANSSON_REQUIRED]) AC_SUBST(JANSSON_CFLAGS) AC_SUBST(JANSSON_LIBS) 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 pyexecdir=${PYTHON_DIR}/Lib/site-packages pythondir=${pyexecdir} pkgpyexecdir=${pyexecdir}/${PACKAGE} pkgpythondir=${pythondir}/${PACKAGE} fi fi AC_CONFIG_FILES([Makefile lib/Makefile demo/Makefile pysearpc/Makefile libsearpc.pc tests/Makefile]) AC_OUTPUT libsearpc-3.2-latest/debian/000077500000000000000000000000001367255703700160555ustar00rootroot00000000000000libsearpc-3.2-latest/debian/README.Debian000066400000000000000000000002271367255703700201170ustar00rootroot00000000000000Seafile ------- For more information about Seafile, please visit http://seafile.com -- plt Fri, 30 March 2012 16:43:10 +0800 libsearpc-3.2-latest/debian/changelog000066400000000000000000000023641367255703700177340ustar00rootroot00000000000000libsearpc1 (3.2.0) unstable; urgency=low * new upstream release -- Jonathan Xu Thu, 24 Oct 2019 11:05:10 +0800 libsearpc1 (3.1.0) unstable; urgency=low * new upstream release -- Jonathan Xu Fri, 16 Aug 2018 16:42:40 +0800 libsearpc1 (3.0.8.3) unstable; urgency=low * new upstream release -- Jonathan Xu Wed, 15 Mar 2017 16:42:40 +0800 libsearpc1 (3.0.8-2) unstable; urgency=low * new upstream release -- Jonathan Xu Fri, 24 Jan 2017 11:38:45 +0800 libsearpc1 (3.0.8) unstable; urgency=low * new upstream release -- Jonathan Xu Thu, 5 Jan 2017 14:12:05 +0800 libsearpc1 (3.0.7-5ubuntu1) UNRELEASED; urgency=medium * repackaging with cleaned up orig.tar.xz archives * added symbol file -- m.eik michalke Fri, 17 Jun 2016 12:09:14 +0200 libsearpc1 (3.0.7-4) unstable; urgency=medium * split package libsearpc1 and libsearpc-dev * updated the debian/copyright notice so people know who's responisble for the packaging * rewrote the rules file, much simpler now * prep for release on github -- m.eik michalke Wed, 15 Jun 2016 22:16:03 +0200 libsearpc-3.2-latest/debian/compat000066400000000000000000000000021367255703700172530ustar00rootroot000000000000007 libsearpc-3.2-latest/debian/control000066400000000000000000000030441367255703700174610ustar00rootroot00000000000000Source: libsearpc1 Section: net Priority: extra Maintainer: m.eik michalke Build-Depends: debhelper (>= 7), dh-python, autotools-dev, intltool, libglib2.0-dev, python3 (>= 3.5), libtool, libjansson-dev Standards-Version: 3.9.5 Homepage: http://seafile.com Package: libsearpc1 Section: libs Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends}, Conflicts: seafile Description: SeaRPC library for Seafile client SeaRPC is a simple C language RPC framework based on GObject system. SeaRPC handles the serialization/deserialization part of RPC, the transport part is left to users. Package: libsearpc-dev Section: libdevel Architecture: any Depends: ${misc:Depends}, python3 (>= 3.5), libsearpc1 (= ${binary:Version}) Conflicts: seafile Description: Development files for the libsearpc1 package. This package contains the development files for the libsearpc1 package. Package: libsearpc-dbg Section: debug Architecture: any Depends: libsearpc1 (= ${binary:Version}), ${misc:Depends}, Description: Debugging symbols for the libsearpc1 package. This package contains the debugging symbols for the libsearpc1 package. Package: python-searpc Section: python Multi-Arch: foreign Architecture: all Depends: ${python3:Depends}, ${shlibs:Depends}, ${misc:Depends} Description: simple and easy-to-use C language RPC framework Searpc handles the serialization/deserialization part of RPC, the transport part is left to users. . This package contains Python bindings to Searpc. libsearpc-3.2-latest/debian/copyright000066400000000000000000000030511367255703700200070ustar00rootroot00000000000000Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Name: libsearpc Upstream-Contact: Lingtao Pan Source: https://github.com/haiwen/libsearpc Files: * Copyright: 2016 plt License: LGPL-3 + Apache This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. . This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. . You should have received a copy of the license with your Debian system, in the file /usr/share/common-licenses/LGPL-3, or with the source package as the file COPYING or LICENSE. Files: debian/* Copyright: 2016 m.eik michalke License: GPL-2 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. . This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. . You should have received a copy of the license with your Debian system, in the file /usr/share/common-licenses/GPL-2, or with the source package as the file COPYING or LICENSE. libsearpc-3.2-latest/debian/libsearpc-dev.install000066400000000000000000000001661367255703700221700ustar00rootroot00000000000000usr/include usr/lib/pkgconfig usr/lib/libsearpc.a usr/lib/libsearpc.la usr/lib/libsearpc.so usr/bin/searpc-codegen.py libsearpc-3.2-latest/debian/libsearpc1.install000066400000000000000000000000171367255703700214700ustar00rootroot00000000000000usr/lib/*.so.* libsearpc-3.2-latest/debian/libsearpc1.symbols000066400000000000000000000023711367255703700215170ustar00rootroot00000000000000libsearpc.so.1 libsearpc1 #MINVER# error_to_json@Base 3.0.7 json_gobject_deserialize@Base 3.0.7 json_gobject_serialize@Base 3.0.7 searpc_client_async_call__int64@Base 3.0.7 searpc_client_async_call__int@Base 3.0.7 searpc_client_async_call__object@Base 3.0.7 searpc_client_async_call__objlist@Base 3.0.7 searpc_client_async_call__string@Base 3.0.7 searpc_client_async_call_v@Base 3.0.7 searpc_client_call@Base 3.0.7 searpc_client_call__int64@Base 3.0.7 searpc_client_call__int@Base 3.0.7 searpc_client_call__object@Base 3.0.7 searpc_client_call__objlist@Base 3.0.7 searpc_client_call__string@Base 3.0.7 searpc_client_free@Base 3.0.7 searpc_client_generic_callback@Base 3.0.7 searpc_client_new@Base 3.0.7 searpc_client_transport_send@Base 3.0.7 searpc_compute_signature@Base 3.0.7 searpc_create_service@Base 3.0.7 searpc_marshal_set_ret_common@Base 3.0.7 searpc_remove_service@Base 3.0.7 searpc_server_call_function@Base 3.0.7 searpc_server_final@Base 3.0.7 searpc_server_init@Base 3.0.7 searpc_server_register_function@Base 3.0.7 searpc_server_register_marshal@Base 3.0.7 searpc_set_int_to_ret_object@Base 3.0.7 searpc_set_object_to_ret_object@Base 3.0.7 searpc_set_objlist_to_ret_object@Base 3.0.7 searpc_set_string_to_ret_object@Base 3.0.7 libsearpc-3.2-latest/debian/patches/000077500000000000000000000000001367255703700175045ustar00rootroot00000000000000libsearpc-3.2-latest/debian/patches/fix-pkgconfig-paths.patch000066400000000000000000000010501367255703700243710ustar00rootroot00000000000000The original packaging script installed relative to itself, not needed here. --- a/libsearpc.pc.in +++ b/libsearpc.pc.in @@ -1,4 +1,4 @@ -prefix=(DESTDIR)@prefix@ +prefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ --- a/Makefile.am +++ b/Makefile.am @@ -18,12 +18,5 @@ 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 libsearpc-3.2-latest/debian/patches/series000066400000000000000000000000321367255703700207140ustar00rootroot00000000000000fix-pkgconfig-paths.patch libsearpc-3.2-latest/debian/python-searpc.install000066400000000000000000000001241367255703700222360ustar00rootroot00000000000000usr/lib/python3*/site-packages/pysearpc/*.py usr/lib/python3/dist-packages/pysearpc libsearpc-3.2-latest/debian/rules000077500000000000000000000006201367255703700171330ustar00rootroot00000000000000#!/usr/bin/make -f # -*- makefile -*- %: dh $@ --with python3 --with autotools_dev --builddirectory=build override_dh_auto_configure: ./autogen.sh dh_auto_configure -- --disable-compile-demo --with-python3 override_dh_strip: # emptying the dependency_libs field in .la files sed -i "/dependency_libs/ s/'.*'/''/" `find debian/ -name '*.la'` dh_strip -plibsearpc1 --dbg-package=libsearpc-dbg libsearpc-3.2-latest/debian/source/000077500000000000000000000000001367255703700173555ustar00rootroot00000000000000libsearpc-3.2-latest/debian/source/format000066400000000000000000000000141367255703700205630ustar00rootroot000000000000003.0 (quilt) libsearpc-3.2-latest/demo/000077500000000000000000000000001367255703700155575ustar00rootroot00000000000000libsearpc-3.2-latest/demo/Makefile.am000066400000000000000000000024761367255703700176240ustar00rootroot00000000000000generated_sources = searpc-signature.h searpc-marshal.h AM_CFLAGS = @GLIB_CFLAGS@ \ -I${top_srcdir}/lib # we need to generate the first BUILT_SOURCES = gensource noinst_PROGRAMS = searpc-demo-server searpc-demo-client searpc-async-client searpc_demo_server_SOURCES = test-object.c searpc-demo-server.c searpc-demo-packet.h noinst_HEADERS = test-object.h searpc_demo_server_LDADD = ${top_builddir}/lib/libsearpc.la @LIB_WS32@ \ @GLIB_LIBS@ @JANSSON_LIBS@ searpc_demo_client_SOURCES = test-object.c searpc-demo-client.c searpc-demo-packet.h searpc_demo_client_LDADD = ${top_builddir}/lib/libsearpc.la @LIB_WS32@ \ @GLIB_LIBS@ @JANSSON_LIBS@ searpc_async_client_SOURCES = demo-async-client.c searpc-demo-packet.h searpc_async_client_LDADD = ${top_builddir}/lib/libsearpc.la @LIB_WS32@ \ @GLIB_LIBS@ @JANSSON_LIBS@ EXTRA_DIST = rpc_table.py gensource: ${generated_sources} rpc_table.stamp: ${top_srcdir}/demo/rpc_table.py ${top_srcdir}/lib/searpc-codegen.py @rm -f rpc_table.tmp @touch rpc_table.tmp @echo "[libsearpc]: generating rpc header files" @PYTHON@ ${top_srcdir}/lib/searpc-codegen.py ${top_srcdir}/demo/rpc_table.py @echo "[libsearpc]: done" @mv -f rpc_table.tmp $@ ${generated_sources}: rpc_table.stamp clean-local: rm -f ${generated_sources} rm -f rpc_table.pyc rm -f rpc_table.stamp rm -f rpc_table.tmp libsearpc-3.2-latest/demo/demo-async-client.c000066400000000000000000000072351367255703700212450ustar00rootroot00000000000000#include #include #include #include #include #include #include #include "searpc-demo-packet.h" #ifdef WIN32 #include #include typedef int socklen_t; #else #include #include #include #include #endif #define BUFLEN 256 #define MAGIC_STRING "ABCD" typedef struct { int fd; void *rpc_priv; } TcpTransport; /* rpc_priv is used by the rpc_client to store information related to * this rpc call. */ static int transport_send(void *arg, char *fcall_str, size_t fcall_len, void *rpc_priv) { TcpTransport *trans = arg; int fd, ret; char buf[BUFLEN]; packet *pac, *pac_ret; pac = (packet *)buf; /* construct the packet */ pac->length = htons((uint16_t)fcall_len); memcpy(pac->data, fcall_str, fcall_len); /* send the packet */ if ( writen (trans->fd, buf, PACKET_HEADER_LENGTH + fcall_len) == -1) { fprintf (stderr, "write failed: %s\n", strerror(errno)); exit(-1); } trans->rpc_priv = rpc_priv; g_free (fcall_str); return 0; } static void transport_read(TcpTransport *trans) { packet *pac; int ret_len; char buf[BUFLEN]; /* read the returned packet */ pac = read_packet(trans->fd, buf); if (pac == NULL) { fprintf(stderr, "read packet failed: %s\n", strerror(errno)); exit(-1); } ret_len = ntohs(pac->length); searpc_client_generic_callback (pac->data, ret_len, trans->rpc_priv, NULL); trans->rpc_priv = NULL; } static void strlen_callback(void *vresult, void *user_data, GError *error) { const char *str = user_data; int len = *((int *)vresult); g_assert (strcmp(str, "user data") == 0); printf("the length of string 'hello searpc' is %d.\n", len); } int main(int argc, char *argv[]) { int sockfd, ret; char *ret_str; struct sockaddr_in servaddr; SearpcClient *rpc_client; GError *error = NULL; TcpTransport *transport; #if !GLIB_CHECK_VERSION(2, 36, 0) g_type_init(); #endif #ifdef WIN32 WSADATA wsadata; WSAStartup(0x0101, &wsadata); #endif ret = sockfd = socket(AF_INET, SOCK_STREAM, 0); if (ret < 0) { fprintf(stderr, "socket failed: %s\n", strerror(errno)); exit(-1); } int on = 1; if (setsockopt (sockfd, SOL_SOCKET, SO_REUSEADDR, (char*)&on, sizeof(on)) < 0) { fprintf (stderr, "setsockopt of SO_REUSEADDR error: %s\n", strerror(errno)); exit(-1); } memset(&servaddr, 0, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(12345); inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr); ret = connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)); if (ret < 0) { fprintf(stderr, "connect failed: %s\n", strerror(errno)); exit(-1); } transport = g_new0 (TcpTransport, 1); transport->fd = sockfd; /* create an rpc_client and supply the transport function. */ rpc_client = searpc_client_new(); rpc_client->async_send = transport_send; rpc_client->async_arg = (void *)(long)transport; /* call the client-side funcion */ searpc_client_async_call__int(rpc_client, "searpc_strlen", strlen_callback, "user data", 1, "string", "hello searpc"); /* call the transport to receive response */ transport_read (transport); if (error != NULL) { fprintf(stderr, "error: %s\n", error->message); exit(-1); } close(sockfd); return 0; } libsearpc-3.2-latest/demo/pysearpc-demo-client.py000066400000000000000000000027661367255703700221700ustar00rootroot00000000000000 import sys import socket from struct import pack, unpack sys.path += ['..'] from pysearpc import SearpcClient, searpc_func SERVER_ADDR = '127.0.0.1' SERVER_PORT = 12345 def recv_all(sock, length): """ read all n bytes of data from sock """ data = '' while len(data) < length: more = sock.recv(length - len(data)) if not more: raise EOFError('socket closed %d bytes into a %d-byte message' % (len(data), length)) data += more return data class SampleRpcClient(SearpcClient): def call_remote_func_sync(self, fcall_str): """ called by searpc_func to send the request and receive the result """ s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # connect to server s.connect((SERVER_ADDR, SERVER_PORT)) # send the header header = pack('!h', len(fcall_str)); s.sendall(header) # send the JSON data s.sendall(fcall_str) # read the returned header header_r = recv_all(s, 2) #read the result ret_len = list(unpack('!h', header_r))[0] if ret_len <= 0: raise AssertionError, "returned data length <= 0" ret_str = recv_all(s, ret_len) return ret_str @searpc_func("int", ["string"]) def searpc_strlen(self): pass client = SampleRpcClient() res = client.searpc_strlen("hello world") print 'result from server:', res libsearpc-3.2-latest/demo/rpc_table.py000066400000000000000000000002511367255703700200620ustar00rootroot00000000000000""" Define RPC functions needed to generate """ # [ , [] ] func_table = [ [ "int", ["string"] ], [ "objlist", ["int", "int", "string"] ] ] libsearpc-3.2-latest/demo/searpc-demo-client.c000066400000000000000000000131031367255703700213740ustar00rootroot00000000000000#include #include #include #include #include #include #include #include "searpc-demo-packet.h" #include "test-object.h" #define BUFLEN 256 #define MAGIC_STRING "ABCD" #ifdef WIN32 #include #include typedef int socklen_t; #else #include #include #include #include #endif static char *transport_callback(void *arg, const char *fcall_str, size_t fcall_len, size_t *ret_len) { int fd, ret; char buf[BUFLEN]; packet *pac, *pac_ret; fd = (int)(long) arg; pac = (packet *)buf; /* construct the packet */ pac->length = htons((uint16_t)fcall_len); memcpy(pac->data, fcall_str, fcall_len); /* send the packet */ if ( writen (fd, buf, PACKET_HEADER_LENGTH + fcall_len) == -1) { fprintf (stderr, "write failed: %s\n", strerror(errno)); exit(-1); } /* read the returned packet */ pac_ret = read_packet(fd, buf); if (pac_ret == NULL) { fprintf(stderr, "read packet failed: %s\n", strerror(errno)); exit(-1); } *ret_len = ntohs(pac_ret->length); return g_strndup(pac_ret->data, *ret_len); } /*The function is copied from searpc-server.c for convience*/ void searpc_set_objlist_to_ret_object (json_t *object, GList *ret) { GList *ptr; if (ret == NULL) json_object_set_new (object, "ret", json_null ()); else { json_t *array = json_array (); for (ptr = ret; ptr; ptr = ptr->next) json_array_append_new (array, json_gobject_serialize (ptr->data)); json_object_set_new (object, "ret", array); for (ptr = ret; ptr; ptr = ptr->next) g_object_unref (ptr->data); g_list_free (ret); } } int connection_init(int *sockfd, struct sockaddr_in *servaddr) { int ret; ret = *sockfd = socket(AF_INET, SOCK_STREAM, 0); if (ret < 0) { fprintf(stderr, "socket failed: %s\n", strerror(errno)); return -1; } int on = 1; if (setsockopt (*sockfd, SOL_SOCKET, SO_REUSEADDR, (char*)&on, sizeof(on)) < 0) { fprintf (stderr, "setsockopt of SO_REUSEADDR error: %s\n", strerror(errno)); return -1; } ret = connect(*sockfd, (struct sockaddr *)servaddr, sizeof(*servaddr)); if (ret < 0) { fprintf(stderr, "connect failed: %s\n", strerror(errno)); return -1; } return 0; } void rpc_string_test(int sockfd, struct sockaddr_in *servaddr, SearpcClient *rpc_client, GError *error) { int ret; char str[16] = "hello searpc"; /* call the client-side funcion */ ret = searpc_client_call__int(rpc_client, "searpc_strlen", &error, 1, "string", str); if (error != NULL) { fprintf(stderr, "error: %s\n", error->message); exit(-1); } else printf("the length of string %s is %d.\n", str, ret); if (ret == strlen(str)) printf("String test succeed.\n"); else printf("String test fail.\n"); close(sockfd); } void rpc_glist_test(int sockfd, struct sockaddr_in *servaddr, SearpcClient *rpc_client, GError *error) { int count = 4, len = 11; char str[16] = "A rpc test."; GList *ans=searpc_client_call__objlist(rpc_client, "searpc_objlisttest", TEST_OBJECT_TYPE, &error, 3, "int", count, "int", len, "string", str); json_t *object=json_object(); searpc_set_objlist_to_ret_object (object,ans); if (error != NULL) { fprintf(stderr, "error: %s\n", error->message); exit(-1); } else printf("%s\n", json_dumps (object, JSON_INDENT(2))); json_t *array = json_object_get (object, "ret"); if (json_array_size(array) != count) { printf("Glisttest fail.\n"); return; } int i; for (i = 0; i != count; ++i) { json_t *member = json_array_get(array, i); if (json_integer_value (json_object_get (member, "len"))!=len) { printf("Glisttest fail.\n"); return; } if (strcmp (json_string_value (json_object_get (member, "str")), str)) { printf("Glisttest fail.\n"); return; } if ((json_is_false (json_object_get (member, "equal"))) == (strlen(str)==len)) { printf("Glisttest fail.\n"); return; } } json_decref(object); printf("Glisttest succeed.\n"); close(sockfd); } int main(int argc, char *argv[]) { int sockfd; char *ret_str; struct sockaddr_in servaddr; SearpcClient *rpc_client; GError *error = NULL; #if !GLIB_CHECK_VERSION(2, 36, 0) g_type_init(); #endif #ifdef WIN32 WSADATA wsadata; WSAStartup(0x0101, &wsadata); #endif memset(&servaddr, 0, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(12345); inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr); if (connection_init(&sockfd, &servaddr)<0) exit(-1); /* create an rpc_client and supply the transport function. */ rpc_client = searpc_client_new(); rpc_client->send = transport_callback; rpc_client->arg = (void *)(long)sockfd; rpc_string_test(sockfd, &servaddr, rpc_client, error); if (connection_init(&sockfd, &servaddr)<0) exit(-1); rpc_client->arg = (void *)(long)sockfd; rpc_glist_test(sockfd, &servaddr, rpc_client, error); return 0; } libsearpc-3.2-latest/demo/searpc-demo-packet.h000066400000000000000000000217421367255703700214020ustar00rootroot00000000000000 #ifndef _PACKET_H #define _PACKET_H #include #include #include #ifdef WIN32 #include #include #include #include #include #define UNUSED #else #include #endif typedef struct packet { uint16_t length; char data[0]; } packet; # define PACKET_HEADER_LENGTH sizeof(packet) static ssize_t /* Write "n" bytes to a descriptor. */ writen(int fd, const void *vptr, size_t n) { size_t nleft; ssize_t nwritten; const char *ptr; ptr = vptr; nleft = n; while (nleft > 0) { #ifdef WIN32 if ( (nwritten = send(fd, ptr, nleft,0)) <= 0) { #else if ( (nwritten = write(fd, ptr, nleft)) <= 0) { #endif if (nwritten < 0 && errno == EINTR) nwritten = 0; /* and call write() again */ else return(-1); /* error */ } nleft -= nwritten; ptr += nwritten; } return(n); } static ssize_t /* Read "n" bytes from a descriptor. */ readn(int fd, char *buf, size_t n) { size_t nleft; ssize_t nread; nleft = n; while (nleft > 0) { #ifdef WIN32 if ( (nread = recv(fd, buf, nleft, 0)) < 0) { #else if ( (nread = read(fd, buf, nleft)) < 0) { #endif if (errno == EINTR) nread = 0; /* and call read() again */ else return(-1); } else if (nread == 0) break; /* EOF */ nleft -= nread; buf += nread; } return(n - nleft); /* return >= 0 */ } /* read a packet into a buffer, and return the pacet pointer */ packet * read_packet(int sockfd, char *buf) { packet *pac; int len; /* read the length part */ if (readn (sockfd, buf, PACKET_HEADER_LENGTH) != PACKET_HEADER_LENGTH) { fprintf(stderr, "read header error: %s\n", strerror(errno)); exit(-1); } pac = (packet *)buf; len = ntohs(pac->length); /* read the data */ if (len <= 0) return NULL; else if (readn (sockfd, buf + PACKET_HEADER_LENGTH, len) != len) return NULL; return pac; } #endif #ifdef WIN32 #ifndef EAFNOSUPPORT #define EAFNOSUPPORT WSAEAFNOSUPPORT #endif #ifndef IN6ADDRSZ #define IN6ADDRSZ 16 #endif #ifndef INT16SZ #define INT16SZ 2 #endif #ifndef INADDRSZ #define INADDRSZ 4 #endif /* * Don't even consider trying to compile this on a system where * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX. */ /* int * inet_pton4(src, dst, pton) * when last arg is 0: inet_aton(). with hexadecimal, octal and shorthand. * when last arg is 1: inet_pton(). decimal dotted-quad only. * return: * 1 if `src' is a valid input, else 0. * notice: * does not touch `dst' unless it's returning 1. * author: * Paul Vixie, 1996. */ int inet_pton4(const char *src, u_char *dst, int pton) { u_int val; u_int digit; int base, n; unsigned char c; u_int parts[4]; register u_int *pp = parts; c = *src; for (;;) { /* * Collect number up to ``.''. * Values are specified as for C: * 0x=hex, 0=octal, isdigit=decimal. */ if (!isdigit(c)) return (0); val = 0; base = 10; if (c == '0') { c = *++src; if (c == 'x' || c == 'X') base = 16, c = *++src; else if (isdigit(c) && c != '9') base = 8; } /* inet_pton() takes decimal only */ if (pton && base != 10) return (0); for (;;) { if (isdigit(c)) { digit = c - '0'; if (digit >= base) break; val = (val * base) + digit; c = *++src; } else if (base == 16 && isxdigit(c)) { digit = c + 10 - (islower(c) ? 'a' : 'A'); if (digit >= 16) break; val = (val << 4) | digit; c = *++src; } else break; } if (c == '.') { /* * Internet format: * a.b.c.d * a.b.c (with c treated as 16 bits) * a.b (with b treated as 24 bits) * a (with a treated as 32 bits) */ if (pp >= parts + 3) return (0); *pp++ = val; c = *++src; } else break; } /* * Check for trailing characters. */ if (c != '\0' && !isspace(c)) return (0); /* * Concoct the address according to * the number of parts specified. */ n = pp - parts + 1; /* inet_pton() takes dotted-quad only. it does not take shorthand. */ if (pton && n != 4) return (0); switch (n) { case 0: return (0); /* initial nondigit */ case 1: /* a -- 32 bits */ break; case 2: /* a.b -- 8.24 bits */ if (parts[0] > 0xff || val > 0xffffff) return (0); val |= parts[0] << 24; break; case 3: /* a.b.c -- 8.8.16 bits */ if ((parts[0] | parts[1]) > 0xff || val > 0xffff) return (0); val |= (parts[0] << 24) | (parts[1] << 16); break; case 4: /* a.b.c.d -- 8.8.8.8 bits */ if ((parts[0] | parts[1] | parts[2] | val) > 0xff) return (0); val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8); break; } if (dst) { val = htonl(val); memcpy(dst, &val, INADDRSZ); } return (1); } /* int * inet_pton6(src, dst) * convert presentation level address to network order binary form. * return: * 1 if `src' is a valid [RFC1884 2.2] address, else 0. * notice: * (1) does not touch `dst' unless it's returning 1. * (2) :: in a full address is silently ignored. * credit: * inspired by Mark Andrews. * author: * Paul Vixie, 1996. */ int inet_pton6(const char *src, u_char *dst) { static const char xdigits_l[] = "0123456789abcdef", xdigits_u[] = "0123456789ABCDEF"; u_char tmp[IN6ADDRSZ], *tp, *endp, *colonp; const char *xdigits, *curtok; int ch, saw_xdigit; u_int val; memset((tp = tmp), '\0', IN6ADDRSZ); endp = tp + IN6ADDRSZ; colonp = NULL; /* Leading :: requires some special handling. */ if (*src == ':') if (*++src != ':') return (0); curtok = src; saw_xdigit = 0; val = 0; while ((ch = *src++) != '\0') { const char *pch; if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL) pch = strchr((xdigits = xdigits_u), ch); if (pch != NULL) { val <<= 4; val |= (pch - xdigits); if (val > 0xffff) return (0); saw_xdigit = 1; continue; } if (ch == ':') { curtok = src; if (!saw_xdigit) { if (colonp) return (0); colonp = tp; continue; } else if (*src == '\0') return (0); if (tp + INT16SZ > endp) return (0); *tp++ = (u_char) (val >> 8) & 0xff; *tp++ = (u_char) val & 0xff; saw_xdigit = 0; val = 0; continue; } if (ch == '.' && ((tp + INADDRSZ) <= endp) && inet_pton4(curtok, tp, 1) > 0) { tp += INADDRSZ; saw_xdigit = 0; break; /* '\0' was seen by inet_pton4(). */ } return (0); } if (saw_xdigit) { if (tp + INT16SZ > endp) return (0); *tp++ = (u_char) (val >> 8) & 0xff; *tp++ = (u_char) val & 0xff; } if (colonp != NULL) { /* * Since some memmove()'s erroneously fail to handle * overlapping regions, we'll do the shift by hand. */ const int n = tp - colonp; int i; if (tp == endp) return (0); for (i = 1; i <= n; i++) { endp[- i] = colonp[n - i]; colonp[n - i] = 0; } tp = endp; } if (tp != endp) return (0); memcpy(dst, tmp, IN6ADDRSZ); return (1); } /* int * inet_pton(af, src, dst) * convert from presentation format (which usually means ASCII printable) * to network format (which is usually some kind of binary format). * return: * 1 if the address was valid for the specified address family * 0 if the address wasn't valid (`dst' is untouched in this case) * -1 if some other error occurred (`dst' is untouched in this case, too) * author: * Paul Vixie, 1996. */ int inet_pton(int af, const char *src, void *dst) { switch (af) { case AF_INET: return (inet_pton4(src, dst, 1)); case AF_INET6: return (inet_pton6(src, dst)); default: errno = EAFNOSUPPORT; return (-1); } /* NOTREACHED */ } #endif /* WIN32 */ libsearpc-3.2-latest/demo/searpc-demo-server.c000066400000000000000000000102621367255703700214270ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include "test-object.h" #include "searpc-demo-packet.h" #define BUFLEN 256 #ifdef WIN32 #include #include typedef int socklen_t; #else #include #include #include #include #endif static int searpc_strlen(const char *str) { if (str == NULL) return -1; else return strlen(str); } static GList * searpc_objlisttest(int count, int len, const char *str) { GList *ret=NULL; int i; for (i=0; i!=count; ++i) { TestObject *obj=g_object_new (TEST_OBJECT_TYPE, NULL); obj->len = len; g_free (obj->str); obj->str = g_strdup(str); if (len == strlen(str)) obj->equal = TRUE; ret = g_list_prepend (ret, obj); } return ret; } #include "searpc-signature.h" #include "searpc-marshal.h" static void start_rpc_service(void) { searpc_server_init(register_marshals); searpc_create_service("searpc-demo"); /* The first parameter is the implementation function. * The second parameter is the name of the rpc function the * client would call. * The third parameter is the signature. */ searpc_server_register_function("searpc-demo", searpc_strlen, "searpc_strlen", searpc_signature_int__string()); searpc_server_register_function("searpc-demo", searpc_objlisttest, "searpc_objlisttest", searpc_signature_objlist__int_int_string()); } int main(int argc, char *argv[]) { int listenfd, connfd; int ret; struct sockaddr_in client_addr, server_addr; socklen_t clilen; char buf[BUFLEN]; packet *pac, *pac_ret; #if !GLIB_CHECK_VERSION(2, 36, 0) g_type_init(); #endif #ifdef WIN32 WSADATA wsadata; WSAStartup(0x0101, &wsadata); #endif start_rpc_service(); listenfd = socket(AF_INET, SOCK_STREAM, 0); if (listenfd < 0) { fprintf(stderr, "socket failed: %s\n", strerror(errno)); exit(-1); } int on = 1; if (setsockopt (listenfd, SOL_SOCKET, SO_REUSEADDR, (char*)&on, sizeof(on)) < 0) { fprintf (stderr, "setsockopt of SO_REUSEADDR error: %s\n", strerror(errno)); exit(-1); } memset(&server_addr, 0, sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_addr.s_addr = htonl(INADDR_ANY); server_addr.sin_port = htons(12345); ret = bind(listenfd, (struct sockaddr *)&server_addr, sizeof(server_addr)); if (ret < 0) { fprintf(stderr, "bind failed: %s\n", strerror(errno)); exit(-1); } ret = listen(listenfd, 5); if (ret < 0) { fprintf(stderr, "listen failed: %s\n", strerror(errno)); exit(-1); } while (1) { GError *error = NULL; clilen = sizeof(client_addr); connfd = accept(listenfd, (struct sockaddr *)&client_addr, &clilen); if (connfd < 0) { fprintf(stderr, "accept failed: %s\n", strerror(errno)); continue; } /* read the header packet */ pac = read_packet(connfd, buf); if (pac == NULL) { fprintf(stderr, "read packet failed: %s\n", strerror(errno)); exit(-1); } gsize ret_len; int fcall_len = ntohs(pac->length); /* Execute the RPC function */ char *res = searpc_server_call_function ("searpc-demo", pac->data, fcall_len, &ret_len); pac_ret = (packet *)buf; pac_ret->length = htons((uint16_t)ret_len); memcpy(pac_ret->data, res, ret_len); /* send the ret packet */ if (writen (connfd, buf, PACKET_HEADER_LENGTH + ret_len) == -1) { fprintf (stderr, "write packet failed: %s\n", strerror(errno)); exit(-1); } } return 0; } libsearpc-3.2-latest/demo/test-object.c000066400000000000000000000050061367255703700201470ustar00rootroot00000000000000#include "test-object.h" G_DEFINE_TYPE (TestObject, test_object, G_TYPE_OBJECT); enum { PROP_0, PROP_LEN, PROP_STR, PROP_EQU, N_PROPERTIES }; static GParamSpec *obj_properties[N_PROPERTIES] = { NULL, }; static void test_object_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) { TestObject *self = TEST_OBJECT (object); switch (property_id) { case PROP_LEN: self->len = g_value_get_int (value); break; case PROP_STR: g_free (self->str); self->str = g_value_dup_string (value); break; case PROP_EQU: self->equal = g_value_get_boolean (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); } } static void test_object_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) { TestObject *self = TEST_OBJECT (object); switch (property_id) { case PROP_LEN: g_value_set_int (value, self->len); break; case PROP_STR: g_value_set_string (value, self->str); break; case PROP_EQU: g_value_set_boolean (value, self->equal); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); } } static void test_object_dispose (GObject *object) { G_OBJECT_CLASS (test_object_parent_class)->dispose(object); } static void test_object_finalize (GObject *object) { TestObject *self = TEST_OBJECT (object); g_free(self->str); G_OBJECT_CLASS (test_object_parent_class)->finalize(object); } static void test_object_class_init(TestObjectClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); gobject_class->set_property = test_object_set_property; gobject_class->get_property = test_object_get_property; gobject_class->dispose = test_object_dispose; gobject_class->finalize = test_object_finalize; obj_properties[PROP_LEN] = g_param_spec_int ("len", "", "", -1, 256, 0, G_PARAM_READWRITE); obj_properties[PROP_STR] = g_param_spec_string ("str", "", "", "Hello world!", G_PARAM_READWRITE); obj_properties[PROP_EQU] = g_param_spec_boolean ("equal", "", "", FALSE, G_PARAM_READWRITE); g_object_class_install_properties (gobject_class, N_PROPERTIES, obj_properties); } static void test_object_init(TestObject *self) { self->len = 0; self->str = g_strdup("Hello world!"); self->equal = FALSE; } libsearpc-3.2-latest/demo/test-object.h000066400000000000000000000016111367255703700201520ustar00rootroot00000000000000#ifndef TEST_OBJECT_H #define TEST_OBJECT_H #include #include #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)) #define TEST_OBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TEST_OBJECT_TYPE, TestObjectClass)) #define IS_TEST_OBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TEST_OBJECT_TYPE)) #define TEST_OBJECT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TEST_OBJECT_TYPE, TestObjectClass)) typedef struct _TestObject TestObject; typedef struct _TestObjectClass TestObjectClass; struct _TestObject { GObject parent; int len; gchar *str; gboolean equal; }; struct _TestObjectClass { GObjectClass parent_class; }; #endif libsearpc-3.2-latest/lib/000077500000000000000000000000001367255703700154015ustar00rootroot00000000000000libsearpc-3.2-latest/lib/Makefile.am000066400000000000000000000007521367255703700174410ustar00rootroot00000000000000 AM_CFLAGS = @GLIB_CFLAGS@ \ @JANSSON_CFLAGS@ \ -I${top_builddir}/lib \ -I${top_srcdir}/lib lib_LTLIBRARIES = libsearpc.la include_HEADERS = searpc-client.h searpc-server.h searpc-utils.h searpc.h searpc-named-pipe-transport.h libsearpc_la_SOURCES = searpc-client.c searpc-server.c searpc-utils.c searpc-named-pipe-transport.c libsearpc_la_LDFLAGS = -version-info 1:2:0 -no-undefined libsearpc_la_LIBADD = @GLIB_LIBS@ @JANSSON_LIBS@ -lpthread dist_bin_SCRIPTS = searpc-codegen.py libsearpc-3.2-latest/lib/searpc-client.c000066400000000000000000000465341367255703700203120ustar00rootroot00000000000000#include #include #include #include "searpc-client.h" #include "searpc-utils.h" static char* searpc_client_fret__string (char *data, size_t len, GError **error); static int searpc_client_fret__int (char *data, size_t len, GError **error); static gint64 searpc_client_fret__int64 (char *data, size_t len, GError **error); static GObject* searpc_client_fret__object (GType gtype, char *data, size_t len, GError **error); static GList* searpc_client_fret__objlist (GType gtype, char *data, size_t len, GError **error); static json_t * searpc_client_fret__json (char *data, size_t len, GError **error); static void clean_objlist(GList *list) { GList *ptr; for (ptr = list; ptr; ptr = ptr->next) g_object_unref(ptr->data); g_list_free (list); } SearpcClient * searpc_client_new () { return g_new0 (SearpcClient, 1); } void searpc_client_free (SearpcClient *client) { if (!client) return; g_free (client); } char * searpc_client_transport_send (SearpcClient *client, const gchar *fcall_str, size_t fcall_len, size_t *ret_len) { return client->send(client->arg, fcall_str, fcall_len, ret_len); } static char * fcall_to_str (const char *fname, int n_params, va_list args, gsize *len) { json_t *array; array = json_array (); json_array_append_new (array, json_string(fname)); int i = 0; for (; i < n_params; i++) { const char *type = va_arg(args, const char *); void *value = va_arg(args, void *); if (strcmp(type, "int") == 0) json_array_append_new (array, json_integer ((int)(long)value)); else if (strcmp(type, "int64") == 0) json_array_append_new (array, json_integer (*((gint64 *)value))); else if (strcmp(type, "string") == 0) json_array_add_string_or_null_element (array, (char *)value); else if (strcmp(type, "json") == 0) json_array_add_json_or_null_element (array, (const json_t *)value); else { g_warning ("unrecognized parameter type %s\n", type); return NULL; } } char *data = json_dumps (array,JSON_COMPACT); *len = strlen (data); json_decref(array); return data; } void searpc_client_call (SearpcClient *client, const char *fname, const char *ret_type, GType gobject_type, void *ret_ptr, GError **error, int n_params, ...) { g_return_if_fail (fname != NULL); g_return_if_fail (ret_type != NULL); va_list args; gsize len, ret_len; char *fstr; va_start (args, n_params); fstr = fcall_to_str (fname, n_params, args, &len); va_end (args); if (!fstr) { g_set_error (error, DFT_DOMAIN, 0, "Invalid Parameter"); return; } char *fret = searpc_client_transport_send (client, fstr, len, &ret_len); if (!fret) { g_free (fstr); g_set_error (error, DFT_DOMAIN, TRANSPORT_ERROR_CODE, TRANSPORT_ERROR); return; } if (strcmp(ret_type, "int") == 0) *((int *)ret_ptr) = searpc_client_fret__int (fret, ret_len, error); else if (strcmp(ret_type, "int64") == 0) *((gint64 *)ret_ptr) = searpc_client_fret__int64 (fret, ret_len, error); else if (strcmp(ret_type, "string") == 0) *((char **)ret_ptr) = searpc_client_fret__string (fret, len, error); else if (strcmp(ret_type, "object") == 0) *((GObject **)ret_ptr) = searpc_client_fret__object (gobject_type, fret, ret_len, error); else if (strcmp(ret_type, "objlist") == 0) *((GList **)ret_ptr) = searpc_client_fret__objlist (gobject_type, fret, ret_len, error); else if (strcmp(ret_type, "json") == 0) *((json_t **)ret_ptr) = searpc_client_fret__json(fret, ret_len, error); else g_warning ("unrecognized return type %s\n", ret_type); g_free (fstr); g_free (fret); } int searpc_client_call__int (SearpcClient *client, const char *fname, GError **error, int n_params, ...) { g_return_val_if_fail (fname != NULL, 0); va_list args; gsize len, ret_len; char *fstr; va_start (args, n_params); fstr = fcall_to_str (fname, n_params, args, &len); va_end (args); if (!fstr) { g_set_error (error, DFT_DOMAIN, 0, "Invalid Parameter"); return 0; } char *fret = searpc_client_transport_send (client, fstr, len, &ret_len); if (!fret) { g_free (fstr); g_set_error (error, DFT_DOMAIN, TRANSPORT_ERROR_CODE, TRANSPORT_ERROR); return 0; } int ret = searpc_client_fret__int (fret, ret_len, error); g_free (fstr); g_free (fret); return ret; } gint64 searpc_client_call__int64 (SearpcClient *client, const char *fname, GError **error, int n_params, ...) { g_return_val_if_fail (fname != NULL, 0); va_list args; gsize len, ret_len; char *fstr; va_start (args, n_params); fstr = fcall_to_str (fname, n_params, args, &len); va_end (args); if (!fstr) { g_set_error (error, DFT_DOMAIN, 0, "Invalid Parameter"); return 0; } char *fret = searpc_client_transport_send (client, fstr, len, &ret_len); if (!fret) { g_free (fstr); g_set_error (error, DFT_DOMAIN, TRANSPORT_ERROR_CODE, TRANSPORT_ERROR); return 0; } gint64 ret = searpc_client_fret__int64 (fret, ret_len, error); g_free (fstr); g_free (fret); return ret; } char * searpc_client_call__string (SearpcClient *client, const char *fname, GError **error, int n_params, ...) { g_return_val_if_fail (fname != NULL, NULL); va_list args; gsize len, ret_len; char *fstr; va_start (args, n_params); fstr = fcall_to_str (fname, n_params, args, &len); va_end (args); if (!fstr) { g_set_error (error, DFT_DOMAIN, 0, "Invalid Parameter"); return NULL; } char *fret = searpc_client_transport_send (client, fstr, len, &ret_len); if (!fret) { g_free (fstr); g_set_error (error, DFT_DOMAIN, TRANSPORT_ERROR_CODE, TRANSPORT_ERROR); return NULL; } char *ret = searpc_client_fret__string (fret, ret_len, error); g_free (fstr); g_free (fret); return ret; } GObject * searpc_client_call__object (SearpcClient *client, const char *fname, GType object_type, GError **error, int n_params, ...) { g_return_val_if_fail (fname != NULL, NULL); g_return_val_if_fail (object_type != 0, NULL); va_list args; gsize len, ret_len; char *fstr; va_start (args, n_params); fstr = fcall_to_str (fname, n_params, args, &len); va_end (args); if (!fstr) { g_set_error (error, DFT_DOMAIN, 0, "Invalid Parameter"); return NULL; } char *fret = searpc_client_transport_send (client, fstr, len, &ret_len); if (!fret) { g_free (fstr); g_set_error (error, DFT_DOMAIN, TRANSPORT_ERROR_CODE, TRANSPORT_ERROR); return NULL; } GObject *ret = searpc_client_fret__object (object_type, fret, ret_len, error); g_free (fstr); g_free (fret); return ret; } GList* searpc_client_call__objlist (SearpcClient *client, const char *fname, GType object_type, GError **error, int n_params, ...) { g_return_val_if_fail (fname != NULL, NULL); g_return_val_if_fail (object_type != 0, NULL); va_list args; gsize len, ret_len; char *fstr; va_start (args, n_params); fstr = fcall_to_str (fname, n_params, args, &len); va_end (args); if (!fstr) { g_set_error (error, DFT_DOMAIN, 0, "Invalid Parameter"); return NULL; } char *fret = searpc_client_transport_send (client, fstr, len, &ret_len); if (!fret) { g_free (fstr); g_set_error (error, DFT_DOMAIN, TRANSPORT_ERROR_CODE, TRANSPORT_ERROR); return NULL; } GList *ret = searpc_client_fret__objlist (object_type, fret, ret_len, error); g_free (fstr); g_free (fret); return ret; } json_t * searpc_client_call__json (SearpcClient *client, const char *fname, GError **error, int n_params, ...) { g_return_val_if_fail (fname != NULL, NULL); va_list args; gsize len, ret_len; char *fstr; va_start (args, n_params); fstr = fcall_to_str (fname, n_params, args, &len); va_end (args); if (!fstr) { g_set_error (error, DFT_DOMAIN, 0, "Invalid Parameter"); return NULL; } char *fret = searpc_client_transport_send (client, fstr, len, &ret_len); if (!fret) { g_free (fstr); g_set_error (error, DFT_DOMAIN, TRANSPORT_ERROR_CODE, TRANSPORT_ERROR); return NULL; } json_t *ret = searpc_client_fret__json (fret, ret_len, error); g_free (fstr); g_free (fret); return ret; } typedef struct { SearpcClient *client; AsyncCallback callback; const gchar *ret_type; GType gtype; /* to specify the specific gobject type if ret_type is object or objlist */ void *cbdata; } AsyncCallData; int searpc_client_generic_callback (char *retstr, size_t len, void *vdata, const char *errstr) { AsyncCallData *data = vdata; GError *error = NULL; void *result = NULL; int ret; gint64 ret64; if (errstr) { g_set_error (&error, DFT_DOMAIN, 500, "Transport error: %s", errstr); data->callback (NULL, data->cbdata, error); g_error_free (error); } else { /* parse result and call the callback */ if (strcmp(data->ret_type, "int") == 0) { ret = searpc_client_fret__int (retstr, len, &error); result = (void *)&ret; } if (strcmp(data->ret_type, "int64") == 0) { ret64 = searpc_client_fret__int64 (retstr, len, &error); result = (void *)&ret64; } else if (strcmp(data->ret_type, "string") == 0) { result = (void *)searpc_client_fret__string (retstr, len, &error); } else if (strcmp(data->ret_type, "object") == 0) { result = (void *)searpc_client_fret__object ( data->gtype, retstr, len, &error); } else if (strcmp(data->ret_type, "objlist") == 0) { result = (void *)searpc_client_fret__objlist ( data->gtype, retstr, len, &error); } else if (strcmp(data->ret_type, "json") == 0) { result = (void *)searpc_client_fret__json (retstr, len, &error); } data->callback (result, data->cbdata, error); if (strcmp(data->ret_type, "string") == 0) { g_free ((char *)result); } else if (strcmp(data->ret_type, "object") == 0) { if (result) g_object_unref ((GObject*)result); } else if (strcmp(data->ret_type, "objlist") == 0) { clean_objlist ((GList *)result); } else if (strcmp(data->ret_type, "json") == 0) { json_decref ((json_t *)result); } } // g_free (data); return 0; } int searpc_client_async_call_v (SearpcClient *client, const char *fname, AsyncCallback callback, const gchar *ret_type, GType gtype, void *cbdata, int n_params, va_list args) { gsize len, ret_len; char *fstr; fstr = fcall_to_str (fname, n_params, args, &len); if (!fstr) return -1; int ret; AsyncCallData *data = g_new0(AsyncCallData, 1); data->client = client; data->callback = callback; data->ret_type = ret_type; data->gtype = gtype; data->cbdata = cbdata; ret = client->async_send (client->async_arg, fstr, len, data); g_free(data); g_free(fstr); return ret; } int searpc_client_async_call__int (SearpcClient *client, const char *fname, AsyncCallback callback, void *cbdata, int n_params, ...) { g_return_val_if_fail (fname != NULL, -1); va_list args; int ret; va_start (args, n_params); ret = searpc_client_async_call_v (client, fname, callback, "int", 0, cbdata, n_params, args); va_end (args); return ret; } int searpc_client_async_call__int64 (SearpcClient *client, const char *fname, AsyncCallback callback, void *cbdata, int n_params, ...) { g_return_val_if_fail (fname != NULL, -1); va_list args; int ret; va_start (args, n_params); ret = searpc_client_async_call_v (client, fname, callback, "int64", 0, cbdata, n_params, args); va_end (args); return ret; } int searpc_client_async_call__string (SearpcClient *client, const char *fname, AsyncCallback callback, void *cbdata, int n_params, ...) { g_return_val_if_fail (fname != NULL, -1); va_list args; int ret; va_start (args, n_params); ret = searpc_client_async_call_v (client, fname, callback, "string", 0, cbdata, n_params, args); va_end (args); return ret; } int searpc_client_async_call__object (SearpcClient *client, const char *fname, AsyncCallback callback, GType object_type, void *cbdata, int n_params, ...) { g_return_val_if_fail (fname != NULL, -1); va_list args; int ret; va_start (args, n_params); ret = searpc_client_async_call_v (client, fname, callback, "object", object_type, cbdata, n_params, args); va_end (args); return ret; } int searpc_client_async_call__objlist (SearpcClient *client, const char *fname, AsyncCallback callback, GType object_type, void *cbdata, int n_params, ...) { g_return_val_if_fail (fname != NULL, -1); va_list args; int ret; va_start (args, n_params); ret = searpc_client_async_call_v (client, fname, callback, "objlist", object_type, cbdata, n_params, args); va_end (args); return ret; } int searpc_client_async_call__json (SearpcClient *client, const char *fname, AsyncCallback callback, void *cbdata, int n_params, ...) { g_return_val_if_fail (fname != NULL, -1); va_list args; int ret; va_start (args, n_params); ret = searpc_client_async_call_v (client, fname, callback, "json", 0, cbdata, n_params, args); va_end (args); return ret; } /* * Returns -1 if error happens in parsing data or data contains error * message. In this case, the calling function should simply return * to up layer. * * Returns 0 otherwise, and root is set to the root node, object set * to the root node's containing object. */ static int handle_ret_common (char *data, size_t len, json_t **object, GError **error) { int err_code; const char *err_msg; json_error_t jerror; g_return_val_if_fail (object != 0, -1); *object=json_loadb(data,len,0,&jerror); if (*object == NULL) { setjetoge(&jerror,error); json_decref (*object); return -1; } if (json_object_get (*object, "err_code")) { err_code = json_integer_value(json_object_get (*object, "err_code")); err_msg = json_string_value(json_object_get (*object, "err_msg")); g_set_error (error, DFT_DOMAIN, err_code, "%s", err_msg); json_decref (*object); return -1; } return 0; } char * searpc_client_fret__string (char *data, size_t len, GError **error) { json_t *object = NULL; gchar *ret_str = NULL; if (handle_ret_common(data, len, &object, error) == 0) { ret_str = g_strdup ( json_object_get_string_or_null_member (object, "ret")); json_decref (object); return ret_str; } return NULL; } int searpc_client_fret__int (char *data, size_t len, GError **error) { json_t *object = NULL; int ret; if (handle_ret_common(data, len, &object, error) == 0) { ret = json_integer_value (json_object_get(object, "ret")); json_decref(object); return ret; } return -1; } gint64 searpc_client_fret__int64 (char *data, size_t len, GError **error) { json_t *object = NULL; gint64 ret; if (handle_ret_common(data, len, &object, error) == 0) { ret = json_integer_value (json_object_get(object, "ret")); json_decref(object); return ret; } return -1; } GObject* searpc_client_fret__object (GType gtype, char *data, size_t len, GError **error) { json_t *object = NULL; GObject *ret = NULL; json_t *member; if (handle_ret_common(data, len, &object, error) == 0) { member = json_object_get (object, "ret"); if (json_is_null(member)) { json_decref(object); return NULL; } ret = json_gobject_deserialize(gtype, member); json_decref(object); return ret; } return NULL; } GList* searpc_client_fret__objlist (GType gtype, char *data, size_t len, GError **error) { json_t *object = NULL; GList *ret = NULL; if (handle_ret_common(data, len, &object, error) == 0) { const json_t *array = json_object_get (object, "ret"); if (json_is_null(array)) { json_decref(object); return NULL; } g_assert (array); int i; for (i = 0; i < json_array_size(array); i++) { json_t *member = json_array_get (array, i); GObject *obj = json_gobject_deserialize(gtype, member); if (obj == NULL) { g_set_error (error, DFT_DOMAIN, 503, "Invalid data: object list contains null"); clean_objlist(ret); json_decref(object); return NULL; } ret = g_list_prepend (ret, obj); } json_decref(object); return g_list_reverse(ret); } return NULL; } json_t * searpc_client_fret__json (char *data, size_t len, GError **error) { json_t *object = NULL; if (handle_ret_common(data, len, &object, error) == 0) { const json_t *ret_obj = json_object_get (object, "ret"); if (!ret_obj || json_is_null(ret_obj)) { json_decref(object); return NULL; } g_assert (ret_obj); json_t *ret = json_deep_copy(ret_obj); json_decref(object); return ret; } return NULL; } libsearpc-3.2-latest/lib/searpc-client.h000066400000000000000000000110521367255703700203020ustar00rootroot00000000000000#ifndef SEARPC_CLIENT_H #define SEARPC_CLIENT_H #ifdef LIBSEARPC_EXPORTS #define LIBSEARPC_API __declspec(dllexport) #else #define LIBSEARPC_API #endif #include #include #include #ifndef DFT_DOMAIN #define DFT_DOMAIN g_quark_from_string(G_LOG_DOMAIN) #endif typedef char *(*TransportCB)(void *arg, const gchar *fcall_str, size_t fcall_len, size_t *ret_len); /** * @rpc_priv is used by the rpc_client to store information related to * this rpc call. * @fcall_str is an allocated string, and the sender should free it * when not needed. */ typedef int (*AsyncTransportSend)(void *arg, gchar *fcall_str, size_t fcall_len, void *rpc_priv); typedef void (*AsyncCallback) (void *result, void *user_data, GError *error); struct _SearpcClient { TransportCB send; void *arg; AsyncTransportSend async_send; void *async_arg; }; typedef struct _SearpcClient LIBSEARPC_API SearpcClient; LIBSEARPC_API SearpcClient *searpc_client_new (); LIBSEARPC_API void searpc_client_free (SearpcClient *client); 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, ...); LIBSEARPC_API int searpc_client_call__int (SearpcClient *client, const char *fname, GError **error, int n_params, ...); LIBSEARPC_API gint64 searpc_client_call__int64 (SearpcClient *client, const char *fname, GError **error, int n_params, ...); LIBSEARPC_API char * searpc_client_call__string (SearpcClient *client, const char *fname, GError **error, int n_params, ...); LIBSEARPC_API GObject * searpc_client_call__object (SearpcClient *client, const char *fname, GType object_type, GError **error, int n_params, ...); LIBSEARPC_API GList* searpc_client_call__objlist (SearpcClient *client, const char *fname, GType object_type, GError **error, int n_params, ...); LIBSEARPC_API json_t * searpc_client_call__json (SearpcClient *client, const char *fname, GError **error, int n_params, ...); LIBSEARPC_API char* searpc_client_transport_send (SearpcClient *client, const gchar *fcall_str, size_t fcall_len, size_t *ret_len); LIBSEARPC_API int searpc_client_async_call__int (SearpcClient *client, const char *fname, AsyncCallback callback, void *cbdata, int n_params, ...); LIBSEARPC_API int searpc_client_async_call__int64 (SearpcClient *client, const char *fname, AsyncCallback callback, void *cbdata, int n_params, ...); LIBSEARPC_API int searpc_client_async_call__string (SearpcClient *client, const char *fname, AsyncCallback callback, void *cbdata, int n_params, ...); LIBSEARPC_API int searpc_client_async_call__object (SearpcClient *client, const char *fname, AsyncCallback callback, GType object_type, void *cbdata, int n_params, ...); LIBSEARPC_API int searpc_client_async_call__objlist (SearpcClient *client, const char *fname, AsyncCallback callback, GType object_type, void *cbdata, int n_params, ...); LIBSEARPC_API int searpc_client_async_call__json (SearpcClient *client, const char *fname, AsyncCallback callback, void *cbdata, int n_params, ...); /* called by the transport layer, the rpc layer should be able to * modify the str, but not take ownership of it */ LIBSEARPC_API int searpc_client_generic_callback (char *retstr, size_t len, void *vdata, const char *errstr); /* in case of transport error, the following code and message will be * set in GError */ #define TRANSPORT_ERROR "Transport Error" #define TRANSPORT_ERROR_CODE 500 #endif libsearpc-3.2-latest/lib/searpc-codegen.py000066400000000000000000000133351367255703700206370ustar00rootroot00000000000000#!/usr/bin/env python """ Generate function define macros. """ from __future__ import print_function import string import sys import os # type -> (, , # , # , # , # ) type_table = { "string": ("const char*", "char*", "json_array_get_string_or_null_element", "searpc_set_string_to_ret_object", "json_array_add_string_or_null_element", "NULL"), "int": ("int", "int", "json_array_get_int_element", "searpc_set_int_to_ret_object", "json_array_add_int_element", "-1"), "int64": ("gint64", "gint64", "json_array_get_int_element", "searpc_set_int_to_ret_object", "json_array_add_int_element", "-1"), "object": ("GObject*", "GObject*", "", "searpc_set_object_to_ret_object", "", "NULL"), "objlist": ("GList*", "GList*", "", "searpc_set_objlist_to_ret_object", "", "NULL"), "json": ("const json_t*", "json_t*", "json_array_get_json_or_null_element", "searpc_set_json_to_ret_object", "json_array_add_json_or_null_element", "NULL"), } marshal_template = r""" static char * ${marshal_name} (void *func, json_t *param_array, gsize *ret_len) { GError *error = NULL; ${get_parameters} ${func_call} json_t *object = json_object (); ${convert_ret} return searpc_marshal_set_ret_common (object, ret_len, error); } """ def generate_marshal(ret_type, arg_types): ret_type_item = type_table[ret_type] ret_type_in_c = ret_type_item[1] template = string.Template(marshal_template) if len(arg_types) == 0: marshal_name = "marshal_" + ret_type + "__void" else: marshal_name = "marshal_" + ret_type + "__" + ('_'.join(arg_types)) get_parameters = "" for i, arg_type in enumerate(arg_types): type_item = type_table[arg_type] stmt = " %s param%d = %s (param_array, %d);\n" %( type_item[0], i+1, type_item[2], i+1) get_parameters += stmt # func_prototype should be something like # GList* (*)(const char*, int, GError **) func_prototype = ret_type_in_c + " (*)(" for arg_type in arg_types: func_prototype += type_table[arg_type][0] + ", " func_prototype += "GError **)" func_args = "" for i in range(1, len(arg_types)+1): func_args += "param%d, " % (i) func_args += "&error" func_call = "%s ret = ((%s)func) (%s);" % (ret_type_in_c, func_prototype, func_args) convert_ret = "%s (object, ret);" % ret_type_item[3] return template.substitute(marshal_name=marshal_name, get_parameters=get_parameters, func_call=func_call, convert_ret=convert_ret) def write_file(f, s): f.write(s) f.write('\n') def gen_marshal_functions(f): for item in func_table: write_file(f, generate_marshal(item[0], item[1])) marshal_register_item = r""" { searpc_server_register_marshal (${signature_name}(), ${marshal_name}); } """ def generate_marshal_register_item(ret_type, arg_types): if len(arg_types) == 0: marshal_name = "marshal_" + ret_type + "__void" else: marshal_name = "marshal_" + ret_type + "__" + ('_'.join(arg_types)) if len(arg_types) == 0: signature_name = "searpc_signature_" + ret_type + "__void" else: signature_name = "searpc_signature_" + ret_type + "__" + ( '_'.join(arg_types)) return string.Template(marshal_register_item).substitute( marshal_name=marshal_name, signature_name=signature_name) def gen_marshal_register_function(f): write_file(f, "static void register_marshals()""") write_file(f, "{") for item in func_table: write_file(f, generate_marshal_register_item(item[0], item[1])) write_file(f, "}") signature_template = r""" inline static gchar * ${signature_name}() { return searpc_compute_signature (${args}); } """ def generate_signature(ret_type, arg_types): ret_type_item = type_table[ret_type] ret_type_in_c = ret_type_item[1] if len(arg_types) == 0: signature_name = "searpc_signature_" + ret_type + "__void" else: signature_name = "searpc_signature_" + ret_type + "__" + ( '_'.join(arg_types)) args = "\"" + ret_type + "\"" + ", " + str(len(arg_types)) for arg_type in arg_types: args += ", " + "\"" + arg_type + "\"" template = string.Template(signature_template) return template.substitute(signature_name=signature_name, args=args) def gen_signature_list(): with open('searpc-signature.h', 'w') as f: for item in func_table: write_file(f, generate_signature(item[0], item[1])) if __name__ == "__main__": sys.path.append(os.getcwd()) # load function table if len(sys.argv) == 2: abspath = os.path.abspath(sys.argv[1]) with open(abspath, 'r') as fp: exec(fp.read()) print("loaded func_table from %s" % abspath) else: # load from default rpc_table.py from rpc_table import func_table # gen code with open('searpc-marshal.h', 'w') as marshal: gen_marshal_functions(marshal) gen_marshal_register_function(marshal) gen_signature_list() libsearpc-3.2-latest/lib/searpc-named-pipe-transport.c000066400000000000000000000427141367255703700231010ustar00rootroot00000000000000#include #include #include #include #if !defined(WIN32) #include #include #include #include #endif // !defined(WIN32) #include #include #include #include "searpc-utils.h" #include "searpc-client.h" #include "searpc-server.h" #include "searpc-named-pipe-transport.h" #if defined(WIN32) static const int kPipeBufSize = 1024; static char* formatErrorMessage(); #define G_WARNING_WITH_LAST_ERROR(fmt) \ do { \ char *error_msg__ = formatErrorMessage(); \ g_warning(fmt ": %s\n", error_msg__); \ g_free (error_msg__); \ } while(0); #endif // defined(WIN32) static void* named_pipe_listen(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); static int request_from_json (const char *content, size_t len, char **service, char **fcall_str); 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 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; char *service; } ClientTransportData; SearpcClient* searpc_client_with_named_pipe_transport(SearpcNamedPipeClient *pipe_client, const char *service) { SearpcClient *client= searpc_client_new(); client->send = searpc_named_pipe_send; ClientTransportData *data = g_malloc(sizeof(ClientTransportData)); data->client = pipe_client; data->service = g_strdup(service); client->arg = data; return client; } SearpcNamedPipeClient* searpc_create_named_pipe_client(const char *path) { SearpcNamedPipeClient *client = g_malloc0(sizeof(SearpcNamedPipeClient)); memcpy(client->path, path, strlen(path) + 1); return client; } 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->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; } int searpc_named_pipe_server_start(SearpcNamedPipeServer *server) { #if !defined(WIN32) int pipe_fd = socket (AF_UNIX, SOCK_STREAM, 0); const char *un_path = server->path; if (pipe_fd < 0) { g_warning ("Failed to create unix socket fd : %s\n", strerror(errno)); return -1; } struct sockaddr_un saddr; saddr.sun_family = AF_UNIX; if (strlen(server->path) > sizeof(saddr.sun_path)-1) { g_warning ("Unix socket path %s is too long." "Please set or modify UNIX_SOCKET option in ccnet.conf.\n", un_path); goto failed; } if (g_file_test (un_path, G_FILE_TEST_EXISTS)) { 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; } } g_strlcpy (saddr.sun_path, un_path, sizeof(saddr.sun_path)); if (bind(pipe_fd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) { g_warning ("failed to bind unix socket fd to %s : %s\n", un_path, strerror(errno)); goto failed; } if (listen(pipe_fd, 10) < 0) { g_warning ("failed to listen to unix socket: %s\n", strerror(errno)); goto failed; } if (chmod(un_path, 0700) < 0) { g_warning ("failed to set permisson for unix socket %s: %s\n", un_path, strerror(errno)); goto failed; } server->pipe_fd = pipe_fd; #endif // !defined(WIN32) /* TODO: use glib thread pool */ pthread_create(&server->listener_thread, NULL, named_pipe_listen, server); return 0; #if !defined(WIN32) failed: close(pipe_fd); return -1; #endif } typedef struct { SearpcNamedPipe connfd; } ServerHandlerData; static void* named_pipe_listen(void *arg) { SearpcNamedPipeServer *server = arg; #if !defined(WIN32) while (1) { int connfd = accept (server->pipe_fd, NULL, 0); ServerHandlerData *data = g_malloc(sizeof(ServerHandlerData)); data->connfd = connfd; 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); } } #else // !defined(WIN32) while (1) { HANDLE connfd = INVALID_HANDLE_VALUE; BOOL connected = FALSE; connfd = CreateNamedPipe( server->path, // pipe name PIPE_ACCESS_DUPLEX, // read/write access PIPE_TYPE_MESSAGE | // message type pipe PIPE_READMODE_MESSAGE | // message-read mode PIPE_WAIT, // blocking mode PIPE_UNLIMITED_INSTANCES, // max. instances kPipeBufSize, // output buffer size kPipeBufSize, // input buffer size 0, // client time-out NULL); // default security attribute if (connfd == INVALID_HANDLE_VALUE) { G_WARNING_WITH_LAST_ERROR ("Failed to create named pipe"); break; } /* listening on this pipe */ connected = ConnectNamedPipe(connfd, NULL) ? TRUE : (GetLastError() == ERROR_PIPE_CONNECTED); if (!connected) { G_WARNING_WITH_LAST_ERROR ("failed to ConnectNamedPipe()"); CloseHandle(connfd); break; } /* g_debug ("Accepted a named pipe client\n"); */ ServerHandlerData *data = g_malloc(sizeof(ServerHandlerData)); data->connfd = connfd; 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* handle_named_pipe_client_with_thread(void *arg) { named_pipe_client_handler(arg); return NULL; } static void handle_named_pipe_client_with_threadpool(void *data, void *user_data) { 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_message ("start to serve on pipe client\n"); while (1) { len = 0; 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"); */ break; } while (bufsize < len) { bufsize *= 2; buf = realloc(buf, bufsize); } if (pipe_read_n(connfd, buf, len) < 0 || len == 0) { g_warning("failed to read rpc request: %s\n", strerror(errno)); break; } char *service, *body; if (request_from_json (buf, len, &service, &body) < 0) { break; } gsize ret_len; char *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) { 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\n", strerror(errno)); g_free (ret_str); break; } g_free (ret_str); } #if !defined(WIN32) close(connfd); #else // !defined(WIN32) DisconnectNamedPipe(connfd); CloseHandle(connfd); #endif // !defined(WIN32) g_free (data); g_free (buf); } int searpc_named_pipe_client_connect(SearpcNamedPipeClient *client) { #if !defined(WIN32) client->pipe_fd = socket(AF_UNIX, SOCK_STREAM, 0); struct sockaddr_un servaddr; servaddr.sun_family = AF_UNIX; 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)); 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; } DWORD mode = PIPE_READMODE_MESSAGE; if (!SetNamedPipeHandleState(pipe_fd, &mode, NULL, NULL)) { G_WARNING_WITH_LAST_ERROR("Failed to set named pipe mode"); return -1; } client->pipe_fd = pipe_fd; #endif // !defined(WIN32) /* g_debug ("pipe client connected to server\n"); */ return 0; } void searpc_free_client_with_pipe_transport (SearpcClient *client) { ClientTransportData *data = (ClientTransportData *)(client->arg); SearpcNamedPipeClient *pipe_client = data->client; #if defined(WIN32) CloseHandle(pipe_client->pipe_fd); #else close(pipe_client->pipe_fd); #endif g_free (pipe_client); g_free (data->service); g_free (data); searpc_client_free (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"); */ ClientTransportData *data = arg; SearpcNamedPipeClient *client = data->client; char *json_str = request_to_json(data->service, fcall_str, fcall_len); guint32 len = (guint32)strlen(json_str); 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, 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(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\n", strerror(errno)); g_free (buf); return NULL; } *ret_len = len; return buf; } static char * request_to_json (const char *service, const char *fcall_str, size_t fcall_len) { json_t *object = json_object (); char *temp_request = g_malloc0(fcall_len + 1); memcpy(temp_request, fcall_str, fcall_len); json_object_set_string_member (object, "service", service); json_object_set_string_member (object, "request", temp_request); g_free (temp_request); char *str = json_dumps (object, 0); json_decref (object); return str; } static int request_from_json (const char *content, size_t len, char **service, char **fcall_str) { json_error_t jerror; json_t *object = json_loadb(content, len, 0, &jerror); if (!object) { g_warning ("Failed to parse request body: %s.\n", strlen(jerror.text) > 0 ? jerror.text : ""); return -1; } *service = g_strdup(json_object_get_string_member (object, "service")); *fcall_str = g_strdup(json_object_get_string_member(object, "request")); json_decref (object); if (!*service || !*fcall_str) { g_free (*service); g_free (*fcall_str); return -1; } return 0; } static void json_object_set_string_member (json_t *object, const char *key, const char *value) { json_object_set_new (object, key, json_string (value)); } static const char * json_object_get_string_member (json_t *object, const char *key) { json_t *string = json_object_get (object, key); if (!string) return NULL; return json_string_value (string); } #if !defined(WIN32) // Write "n" bytes to a descriptor. gssize pipe_write_n(int fd, const void *vptr, size_t n) { size_t nleft; gssize nwritten; const char *ptr; ptr = vptr; nleft = n; while (nleft > 0) { if ( (nwritten = write(fd, ptr, nleft)) <= 0) { if (nwritten < 0 && errno == EINTR) nwritten = 0; /* and call write() again */ else return(-1); /* error */ } nleft -= nwritten; ptr += nwritten; } return(n); } // Read "n" bytes from a descriptor. gssize pipe_read_n(int fd, void *vptr, size_t n) { size_t nleft; gssize nread; char *ptr; ptr = vptr; nleft = n; while (nleft > 0) { if ( (nread = read(fd, ptr, nleft)) < 0) { if (errno == EINTR) nread = 0; /* and call read() again */ else return(-1); } else if (nread == 0) break; /* EOF */ nleft -= nread; ptr += nread; } return(n - nleft); /* return >= 0 */ } #else // !defined(WIN32) gssize pipe_read_n (SearpcNamedPipe fd, void *vptr, size_t n) { DWORD bytes_read; BOOL success = ReadFile( fd, // handle to pipe vptr, // buffer to receive data (DWORD)n, // size of buffer &bytes_read, // number of bytes read NULL); // not overlapped I/O if (!success || bytes_read != (DWORD)n) { if (GetLastError() == ERROR_BROKEN_PIPE) { return 0; } G_WARNING_WITH_LAST_ERROR("failed to read from pipe"); return -1; } return n; } gssize pipe_write_n(SearpcNamedPipe fd, const void *vptr, size_t n) { DWORD bytes_written; BOOL success = WriteFile( fd, // handle to pipe vptr, // buffer to receive data (DWORD)n, // size of buffer &bytes_written, // number of bytes written NULL); // not overlapped I/O if (!success || bytes_written != (DWORD)n) { G_WARNING_WITH_LAST_ERROR("failed to write to named pipe"); return -1; } FlushFileBuffers(fd); return 0; } // 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() { DWORD error_code = GetLastError(); if (error_code == 0) { return g_strdup("no error"); } char buf[256] = {0}; FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, error_code, /* EN_US */ MAKELANGID(LANG_ENGLISH, 0x01), buf, sizeof(buf) - 1, NULL); return g_strdup(buf); } #endif // !defined(WIN32) libsearpc-3.2-latest/lib/searpc-named-pipe-transport.h000066400000000000000000000040611367255703700230770ustar00rootroot00000000000000#ifndef SEARPC_NAMED_PIPE_TRANSPORT_H #define SEARPC_NAMED_PIPE_TRANSPORT_H #ifdef LIBSEARPC_EXPORTS #define LIBSEARPC_API __declspec(dllexport) #else #define LIBSEARPC_API #endif #include #include #include #include #if defined(WIN32) #include #endif // Implementatin of a searpc transport based on named pipe. It uses unix domain // sockets on linux/osx, and named pipes on windows. // // On the server side, there is a thread that listens for incoming connections, // and it would create a new thread to handle each connection. Thus the RPC // functions on the server side may be called from different threads, and it's // the RPC functions implementation's responsibility to guarantee thread safety // of the RPC calls. (e.g. using mutexes). #if defined(WIN32) typedef HANDLE SearpcNamedPipe; #else typedef int SearpcNamedPipe; #endif // Server side interface. struct _SearpcNamedPipeServer { char path[4096]; pthread_t listener_thread; SearpcNamedPipe pipe_fd; GThreadPool *named_pipe_server_thread_pool; }; 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. struct _SearpcNamedPipeClient { char path[4096]; SearpcNamedPipe pipe_fd; }; 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); #endif // SEARPC_NAMED_PIPE_TRANSPORT_H libsearpc-3.2-latest/lib/searpc-server.c000066400000000000000000000235101367255703700203270ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ #include #include #include #include #include #include "searpc-server.h" #include "searpc-utils.h" #ifdef __linux__ #include #include #include #endif struct FuncItem; typedef struct MarshalItem { SearpcMarshalFunc mfunc; gchar *signature; } MarshalItem; typedef struct FuncItem { void *func; gchar *fname; MarshalItem *marshal; } FuncItem; typedef struct { char *name; GHashTable *func_table; } SearpcService; static GHashTable *marshal_table; static GHashTable *service_table; #ifdef __linux__ static FILE *slow_log_fp = NULL; static gint64 slow_threshold; static pthread_mutex_t slow_log_lock; #endif static void func_item_free (FuncItem *item) { g_free (item->fname); g_free (item); } static void marshal_item_free (MarshalItem *item) { g_free (item->signature); g_free (item); } int searpc_create_service (const char *svc_name) { SearpcService *service; if (!svc_name) return -1; if (g_hash_table_lookup (service_table, svc_name) != NULL) return 0; service = g_new0 (SearpcService, 1); service->name = g_strdup(svc_name); service->func_table = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, (GDestroyNotify)func_item_free); g_hash_table_insert (service_table, service->name, service); return 0; } static void service_free (SearpcService *service) { g_free (service->name); g_hash_table_destroy (service->func_table); g_free (service); } void searpc_remove_service (const char *svc_name) { if (!svc_name) return; g_hash_table_remove (service_table, svc_name); } /* Marshal functions */ void searpc_set_string_to_ret_object (json_t *object, char *ret) { if (ret == NULL) json_object_set_new (object, "ret", json_null ()); else { json_object_set_new (object, "ret", json_string (ret)); g_free (ret); } } void searpc_set_int_to_ret_object (json_t *object, json_int_t ret) { json_object_set_new (object, "ret", json_integer (ret)); } void searpc_set_object_to_ret_object (json_t *object, GObject *ret) { if (ret == NULL) json_object_set_new (object, "ret", json_null ()); else { json_object_set_new (object, "ret", json_gobject_serialize (ret)); g_object_unref (ret); } } void searpc_set_objlist_to_ret_object (json_t *object, GList *ret) { GList *ptr; if (ret == NULL) json_object_set_new (object, "ret", json_null ()); else { json_t *array = json_array (); for (ptr = ret; ptr; ptr = ptr->next) json_array_append_new (array, json_gobject_serialize (ptr->data)); json_object_set_new (object, "ret", array); for (ptr = ret; ptr; ptr = ptr->next) g_object_unref (ptr->data); g_list_free (ret); } } void searpc_set_json_to_ret_object (json_t *object, json_t *ret) { if (ret == NULL) json_object_set_new(object, "ret", json_null ()); else json_object_set_new (object, "ret", ret); } char * searpc_marshal_set_ret_common (json_t *object, gsize *len, GError *error) { char *data; if (error) { json_object_set_new (object, "err_code", json_integer((json_int_t)error->code)); json_object_set_new (object, "err_msg", json_string(error->message)); g_error_free (error); } data=json_dumps(object,JSON_COMPACT); *len=strlen(data); json_decref(object); return data; } char * error_to_json (int code, const char *msg, gsize *len) { json_t *object = json_object (); char *data; json_object_set_new (object, "err_code", json_integer((json_int_t)code)); json_object_set_string_or_null_member(object, "err_msg", msg); data=json_dumps(object,JSON_COMPACT); *len=strlen(data); json_decref(object); return data; } void searpc_server_init (RegisterMarshalFunc register_func) { marshal_table = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, (GDestroyNotify)marshal_item_free); service_table = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, (GDestroyNotify)service_free); register_func (); } #ifdef __linux__ int searpc_server_init_with_slow_log (RegisterMarshalFunc register_func, const char *slow_log_path, gint64 slow_threshold_in) { 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; 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 ((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() { g_hash_table_destroy (service_table); g_hash_table_destroy (marshal_table); } gboolean searpc_server_register_marshal (gchar *signature, SearpcMarshalFunc marshal) { MarshalItem *mitem; g_assert (signature != NULL && marshal != NULL); if (g_hash_table_lookup (marshal_table, signature) != NULL) { g_warning ("[Sea RPC] cannot register duplicate marshal.\n"); g_free (signature); return FALSE; } mitem = g_new0 (MarshalItem, 1); mitem->mfunc = marshal; mitem->signature = signature; g_hash_table_insert (marshal_table, (gpointer)mitem->signature, mitem); return TRUE; } gboolean searpc_server_register_function (const char *svc_name, void *func, const gchar *fname, gchar *signature) { SearpcService *service; FuncItem *item; MarshalItem *mitem; g_assert (svc_name != NULL && func != NULL && fname != NULL && signature != NULL); service = g_hash_table_lookup (service_table, svc_name); if (!service) return FALSE; mitem = g_hash_table_lookup (marshal_table, signature); if (!mitem) { g_free (signature); return FALSE; } item = g_new0 (FuncItem, 1); item->marshal = mitem; item->fname = g_strdup(fname); item->func = func; g_hash_table_insert (service->func_table, (gpointer)item->fname, item); g_free (signature); return TRUE; } #ifdef __linux__ 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); 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, gchar *func, gsize len, gsize *ret_len) { SearpcService *service; json_t *array; char* ret; json_error_t jerror; GError *error = NULL; #ifdef __linux__ struct timeval start, end, intv; if (slow_log_fp) { gettimeofday(&start, NULL); } #endif service = g_hash_table_lookup (service_table, svc_name); if (!service) { char buf[256]; snprintf (buf, 255, "cannot find service %s.", svc_name); return error_to_json (501, buf, ret_len); } array = json_loadb (func, len, 0 ,&jerror); if (!array) { char buf[512]; setjetoge(&jerror,&error); snprintf (buf, 511, "failed to load RPC call: %s\n", error->message); json_decref (array); g_error_free(error); return error_to_json (511, buf, ret_len); } const char *fname = json_string_value (json_array_get(array, 0)); FuncItem *fitem = g_hash_table_lookup(service->func_table, fname); if (!fitem) { char buf[256]; snprintf (buf, 255, "cannot find function %s.", fname); json_decref (array); return error_to_json (500, buf, ret_len); } ret = fitem->marshal->mfunc (fitem->func, array, ret_len); #ifdef __linux__ if (slow_log_fp) { gettimeofday(&end, NULL); timersub(&end, &start, &intv); print_slow_log_if_necessary (svc_name, func, len, &start, &intv); } #endif json_decref(array); return ret; } char* searpc_compute_signature(const gchar *ret_type, int pnum, ...) { va_list ap; int i = 0; char *ret; GChecksum *cksum = g_checksum_new (G_CHECKSUM_MD5); g_checksum_update (cksum, (const guchar*)ret_type, -1); va_start(ap, pnum); for (; i #include #include #ifndef DFT_DOMAIN #define DFT_DOMAIN g_quark_from_string(G_LOG_DOMAIN) #endif 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); /** * searpc_server_init: * * 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); /** * Used in log rotate. */ LIBSEARPC_API int searpc_server_reopen_slow_log (const char *slow_log_path); /** * searpc_server_final: * * Free the server structure. */ LIBSEARPC_API void searpc_server_final (); /** * searpc_create_service: * * Create a new service. Service is a set of functions. * The new service will be registered to the server. * * @svc_name: Service name. */ LIBSEARPC_API int searpc_create_service (const char *svc_name); /** * searpc_remove_service: * * Remove the service from the server. */ LIBSEARPC_API void searpc_remove_service (const char *svc_name); /** * searpc_server_register_marshal: * * For user to extend marshal functions. * * @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); /** * searpc_server_register_function: * * Register a rpc function with given signature to a service. * * @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, gchar *signature); /** * searpc_server_call_function: * @service: service name. * @func: the serialized representation of the function to call. * @len: length of @func. * @ret_len: the length of the returned string. * * Call a registered function @func of a 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); /** * searpc_compute_signature: * @ret_type: the return type of the function. * @pnum: number of parameters of the function. * * Compute function signature. */ LIBSEARPC_API char* searpc_compute_signature (const gchar *ret_type, int pnum, ...); #endif libsearpc-3.2-latest/lib/searpc-utils.c000066400000000000000000000175271367255703700201740ustar00rootroot00000000000000#include #include #include #include #include "searpc-utils.h" #if !GLIB_CHECK_VERSION(2, 32, 0) #define g_value_set_schar g_value_set_char #define g_value_get_schar g_value_get_char #endif static json_t *json_serialize_pspec (const GValue *value) { /* Only types in json-glib but G_TYPE_BOXED */ switch (G_TYPE_FUNDAMENTAL (G_VALUE_TYPE (value))) { case G_TYPE_STRING: if (!g_value_get_string (value)) break; else return json_string (g_value_get_string (value)); case G_TYPE_BOOLEAN: if (g_value_get_boolean (value)) return json_true (); else return json_false (); case G_TYPE_INT: return json_integer (g_value_get_int (value)); case G_TYPE_UINT: return json_integer (g_value_get_uint (value)); case G_TYPE_LONG: return json_integer (g_value_get_long (value)); case G_TYPE_ULONG: return json_integer (g_value_get_ulong (value)); case G_TYPE_INT64: return json_integer (g_value_get_int64 (value)); case G_TYPE_FLOAT: return json_real (g_value_get_float (value)); case G_TYPE_DOUBLE: return json_real (g_value_get_double (value)); case G_TYPE_CHAR: return json_integer (g_value_get_schar (value)); case G_TYPE_UCHAR: return json_integer (g_value_get_uchar (value)); case G_TYPE_ENUM: return json_integer (g_value_get_enum (value)); case G_TYPE_FLAGS: return json_integer (g_value_get_flags (value)); case G_TYPE_NONE: break; case G_TYPE_OBJECT: { GObject *object = g_value_get_object (value); if (object) return json_gobject_serialize (object); } break; default: g_warning("Unsuppoted type `%s'",g_type_name (G_VALUE_TYPE (value))); } return json_null(); } json_t *json_gobject_serialize (GObject *gobject) { json_t *object = json_object(); GParamSpec **pspecs; guint n_pspecs, i; pspecs = g_object_class_list_properties (G_OBJECT_GET_CLASS (gobject), &n_pspecs); for (i=0; i!=n_pspecs; ++i) { json_t *node; GParamSpec *pspec = pspecs[i]; GValue value = { 0, }; g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec)); g_object_get_property(gobject, pspec->name, &value); node=json_serialize_pspec (&value); if (node) json_object_set_new (object, pspec->name, node); g_value_unset (&value); } g_free (pspecs); return object; } static gboolean json_deserialize_pspec (GValue *value, GParamSpec *pspec, json_t *node) { switch (json_typeof(node)) { case JSON_OBJECT: if (g_type_is_a (G_VALUE_TYPE (value), G_TYPE_OBJECT)) { GObject *object; object = json_gobject_deserialize (G_VALUE_TYPE (value), node); if (object) g_value_take_object (value, object); else g_value_set_object (value, NULL); return TRUE; } break; case JSON_STRING: if (G_TYPE_FUNDAMENTAL (G_VALUE_TYPE (value)) == G_TYPE_STRING) { g_value_set_string(value, json_string_value(node)); return TRUE; } break; case JSON_INTEGER: { json_int_t int_value = json_integer_value (node); switch (G_TYPE_FUNDAMENTAL (G_VALUE_TYPE (value))) { case G_TYPE_CHAR: g_value_set_schar(value, (gchar)int_value); return TRUE; case G_TYPE_UCHAR: g_value_set_uchar (value, (guchar)int_value); return TRUE; case G_TYPE_INT: g_value_set_int (value, (gint)int_value); return TRUE; case G_TYPE_UINT: g_value_set_uint(value, (guint)int_value); return TRUE; case G_TYPE_LONG: g_value_set_long(value, (glong)int_value); return TRUE; case G_TYPE_ULONG: g_value_set_ulong(value, (gulong)int_value); return TRUE; case G_TYPE_INT64: g_value_set_int64(value,(gint64)int_value); return TRUE; case G_TYPE_ENUM: g_value_set_enum(value,(gint64)int_value); return TRUE; case G_TYPE_FLAGS: g_value_set_flags(value,(gint64)int_value); return TRUE; } } break; case JSON_REAL: { double real_value = json_real_value(node); switch (G_TYPE_FUNDAMENTAL (G_VALUE_TYPE (value))) { case G_TYPE_FLOAT: g_value_set_float(value,(gfloat)real_value); return TRUE; case G_TYPE_DOUBLE: g_value_set_double(value,(gdouble)real_value); return TRUE; } } break; case JSON_TRUE: case JSON_FALSE: if (G_TYPE_FUNDAMENTAL (G_VALUE_TYPE (value)) == G_TYPE_BOOLEAN) { g_value_set_boolean(value,(gboolean)json_is_true(node)); return TRUE; } break; case JSON_NULL: if (G_TYPE_FUNDAMENTAL (G_VALUE_TYPE (value)) == G_TYPE_STRING) { g_value_set_string (value, NULL); return TRUE; } else if (G_TYPE_FUNDAMENTAL (G_VALUE_TYPE (value)) == G_TYPE_OBJECT) { g_value_set_object (value, NULL); return TRUE; } break; case JSON_ARRAY: return FALSE; break; default: return FALSE; } return FALSE; } GObject *json_gobject_deserialize (GType gtype, json_t *object) { GObjectClass *klass; GObject *ret; guint n_members, i; json_t *head, *member; const char *member_name; GArray *construct_params; klass = g_type_class_ref (gtype); n_members = json_object_size (object); construct_params = g_array_sized_new (FALSE, FALSE, sizeof (GParameter), n_members); head = json_object_iter (object); for (member=head; member; member=json_object_iter_next (object, member)) { GParamSpec *pspec; GParameter param = { NULL, }; const char *member_name = json_object_iter_key (member); json_t *val = json_object_iter_value(member); pspec = g_object_class_find_property (klass, member_name); if (!pspec) continue; if (pspec->flags & G_PARAM_CONSTRUCT_ONLY) continue; if (!(pspec->flags & G_PARAM_WRITABLE)) continue; g_value_init(¶m.value, G_PARAM_SPEC_VALUE_TYPE (pspec)); if (json_deserialize_pspec (¶m.value, pspec, val)) { param.name = g_strdup (pspec->name); g_array_append_val (construct_params, param); } else g_warning ("Failed to deserialize \"%s\" property of type \"%s\" for an object of type \"%s\"", pspec->name, g_type_name (G_VALUE_TYPE (¶m.value)), g_type_name (gtype)); } ret = g_object_newv (gtype, construct_params->len, (GParameter *) construct_params->data); for (i=0; i!= construct_params->len; ++i) { GParameter *param = &g_array_index (construct_params, GParameter, i); g_free ((gchar *) param->name); g_value_unset (¶m->value); } g_array_free(construct_params, TRUE); g_type_class_unref(klass); return ret; } libsearpc-3.2-latest/lib/searpc-utils.h000066400000000000000000000043331367255703700201700ustar00rootroot00000000000000#include #include #include #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 } 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) { /* Load is the only function I use which reports errors */ g_set_error(error, SEARPC_JSON_DOMAIN, SEARPC_JSON_ERROR_LOAD, "%s", jerror->text); } inline static const char *json_object_get_string_or_null_member (json_t *object,const char *member_name) { json_t *ret = json_object_get (object, member_name); if (ret) return json_string_value(ret); else return NULL; } inline static void json_object_set_string_or_null_member (json_t *object,const char *member_name,const char *value) { if (value) json_object_set_new(object,member_name, json_string(value)); else json_object_set_new(object,member_name, json_null()); } inline static const char *json_array_get_string_or_null_element (json_t *array, size_t index) { json_t *ret=json_array_get (array,index); if (ret) return json_string_value (ret); else return NULL; } inline static void json_array_add_string_or_null_element (json_t *array, const char *value) { if (value) json_array_append_new (array, json_string (value)); else json_array_append_new (array, json_null ()); } inline static json_int_t json_array_get_int_element (json_t *array, size_t index) { return json_integer_value (json_array_get (array, index)); } inline static const json_t *json_array_get_json_or_null_element (json_t *array, size_t index) { return json_array_get (array, index); } inline static void json_array_add_json_or_null_element (json_t *array, const json_t *value) { if (value) { json_t *obj = json_deep_copy((json_t*)value); json_array_append_new (array, obj); } else { json_array_append_new (array, json_null ()); } } libsearpc-3.2-latest/lib/searpc.h000066400000000000000000000003121367255703700170230ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ #ifndef SEARPC_H #define SEARPC_H #include #include #include #endif libsearpc-3.2-latest/libsearpc.pc.in000066400000000000000000000004211367255703700175250ustar00rootroot00000000000000prefix=(DESTDIR)@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ Name: libsearpc 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 libsearpc-3.2-latest/libsearpc.sln000066400000000000000000000025771367255703700173300ustar00rootroot00000000000000 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 libsearpc-3.2-latest/libsearpc.vcxproj000066400000000000000000000147421367255703700202240ustar00rootroot00000000000000 Debug Win32 Release Win32 Debug x64 Release x64 16.0 {7E7BDAA2-D61E-466D-B138-CC2454CAB1D3} Win32Proj 10.0 DynamicLibrary true v142 Application false v142 DynamicLibrary true v142 DynamicLibrary false v142 true true $(ProjectDir)$(Platform)\$(Configuration)\ WIN32;_DEBUG;_WINDOWS;LIBSEARPC_EXPORTS;%(PreprocessorDefinitions) MultiThreadedDebugDLL Level3 ProgramDatabase Disabled MachineX86 true Windows WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) MultiThreadedDLL Level3 ProgramDatabase MachineX86 true Windows true true LIBSEARPC_EXPORTS;WIN32 LIBSEARPC_EXPORTS;WIN32 libsearpc-3.2-latest/m4/000077500000000000000000000000001367255703700151535ustar00rootroot00000000000000libsearpc-3.2-latest/m4/python.m4000066400000000000000000000036141367255703700167420ustar00rootroot00000000000000## this one is commonly used with AM_PATH_PYTHONDIR ... dnl AM_CHECK_PYMOD(MODNAME [,SYMBOL [,ACTION-IF-FOUND [,ACTION-IF-NOT-FOUND]]]) dnl Check if a module containing a given symbol is visible to python. AC_DEFUN([AM_CHECK_PYMOD], [AC_REQUIRE([AM_PATH_PYTHON]) py_mod_var=`echo $1['_']$2 | sed 'y%./+-%__p_%'` AC_MSG_CHECKING(for ifelse([$2],[],,[$2 in ])python module $1) AC_CACHE_VAL(py_cv_mod_$py_mod_var, [ ifelse([$2],[], [prog=" import sys try: import $1 except ImportError: sys.exit(1) except: sys.exit(0) sys.exit(0)"], [prog=" import $1 $1.$2"]) if $PYTHON -c "$prog" 1>&AC_FD_CC 2>&AC_FD_CC then eval "py_cv_mod_$py_mod_var=yes" else eval "py_cv_mod_$py_mod_var=no" fi ]) py_val=`eval "echo \`echo '$py_cv_mod_'$py_mod_var\`"` if test "x$py_val" != xno; then AC_MSG_RESULT(yes) ifelse([$3], [],, [$3 ])dnl else AC_MSG_RESULT(no) ifelse([$4], [],, [$4 ])dnl fi ]) dnl a macro to check for ability to create python extensions dnl AM_CHECK_PYTHON_HEADERS([ACTION-IF-POSSIBLE], [ACTION-IF-NOT-POSSIBLE]) dnl function also defines PYTHON_INCLUDES AC_DEFUN([AM_CHECK_PYTHON_HEADERS], [AC_REQUIRE([AM_PATH_PYTHON]) AC_MSG_CHECKING(for headers required to compile python extensions) dnl deduce PYTHON_INCLUDES py_prefix=`$PYTHON -c "import sys; print sys.prefix"` py_exec_prefix=`$PYTHON -c "import sys; print sys.exec_prefix"` if test -x "$PYTHON-config"; then PYTHON_INCLUDES=`$PYTHON-config --includes 2>/dev/null` else PYTHON_INCLUDES="-I${py_prefix}/include/python${PYTHON_VERSION}" if test "$py_prefix" != "$py_exec_prefix"; then PYTHON_INCLUDES="$PYTHON_INCLUDES -I${py_exec_prefix}/include/python${PYTHON_VERSION}" fi fi AC_SUBST(PYTHON_INCLUDES) dnl check if the headers exist: save_CPPFLAGS="$CPPFLAGS" CPPFLAGS="$CPPFLAGS $PYTHON_INCLUDES" AC_TRY_CPP([#include ],dnl [AC_MSG_RESULT(found) $1],dnl [AC_MSG_RESULT(not found) $2]) CPPFLAGS="$save_CPPFLAGS" ]) libsearpc-3.2-latest/pysearpc/000077500000000000000000000000001367255703700164615ustar00rootroot00000000000000libsearpc-3.2-latest/pysearpc/Makefile.am000066400000000000000000000002161367255703700205140ustar00rootroot00000000000000 pysearpcdir=${pyexecdir}/pysearpc pysearpc_PYTHON = __init__.py client.py common.py errors.py named_pipe.py server.py transport.py utils.py libsearpc-3.2-latest/pysearpc/__init__.py000066400000000000000000000003421367255703700205710ustar00rootroot00000000000000from .common import SearpcError from .client import SearpcClient, searpc_func, SearpcObjEncoder from .server import searpc_server from .transport import SearpcTransport from .named_pipe import NamedPipeServer, NamedPipeClient libsearpc-3.2-latest/pysearpc/client.py000066400000000000000000000064321367255703700203160ustar00rootroot00000000000000import json from .common import SearpcError def _fret_int(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 'ret' in dicts: return dicts['ret'] else: raise SearpcError('Invalid response format') def _fret_string(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 'ret' in dicts: return dicts['ret'] else: raise SearpcError('Invalid response format') class _SearpcObj(object): '''A compact class to emulate gobject.GObject ''' def __init__(self, dicts): new_dict = {} for key in dicts: value = dicts[key] # replace hyphen with with underline new_key = key.replace('-', '_') new_dict[new_key] = value # For compatibility with old usage peer.props.name self.props = self self._dict = new_dict def __getattr__(self, key): try: return self._dict[key] except: return None class SearpcObjEncoder(json.JSONEncoder): def default(self, obj): if not isinstance(obj, _SearpcObj): return super(SearpcObjEncoder, self).default(obj) return obj._dict def _fret_obj(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 _SearpcObj(dicts['ret']) else: return None def _fret_objlist(ret_str): try: dicts = json.loads(ret_str) except: raise SearpcError('Invalid response format') if 'err_code' in dicts: raise SearpcError(dicts['err_msg']) l = [] if dicts['ret']: for elt in dicts['ret']: l.append(_SearpcObj(elt)) return l def _fret_json(ret_str): try: dicts = json.loads(ret_str) except: raise SearpcError('Invalid response format') if 'err_code' in dicts: raise SearpcError(dicts['err_msg']) if dicts['ret']: return dicts['ret'] else: return None def searpc_func(ret_type, param_types): def decorate(func): if ret_type == "void": fret = None elif ret_type == "object": fret = _fret_obj elif ret_type == "objlist": fret = _fret_objlist elif ret_type == "int": fret = _fret_int elif ret_type == "int64": fret = _fret_int elif ret_type == "string": fret = _fret_string elif ret_type == "json": fret = _fret_json else: raise SearpcError('Invial return type') def newfunc(self, *args): array = [func.__name__] + list(args) fcall_str = json.dumps(array) ret_str = self.call_remote_func_sync(fcall_str) if fret: return fret(ret_str) return newfunc return decorate class SearpcClient(object): def call_remote_func_sync(self, fcall_str): raise NotImplementedError() libsearpc-3.2-latest/pysearpc/common.py000066400000000000000000000002031367255703700203160ustar00rootroot00000000000000class SearpcError(Exception): def __init__(self, msg): self.msg = msg def __str__(self): return self.msg libsearpc-3.2-latest/pysearpc/errors.py000066400000000000000000000002441367255703700203470ustar00rootroot00000000000000class NetworkError(Exception): def __init__(self, msg): Exception.__init__(self) self.msg = msg def __str__(self): return self.msg libsearpc-3.2-latest/pysearpc/named_pipe.py000066400000000000000000000115241367255703700211370ustar00rootroot00000000000000""" RPC client/server implementation based on named pipe transport. """ import json import logging import os import socket import struct from threading import Thread import queue from .client import SearpcClient from .server import searpc_server from .transport import SearpcTransport from .utils import make_socket_closeonexec, recvall, sendall logger = logging.getLogger(__name__) class NamedPipeException(Exception): pass class NamedPipeTransport(SearpcTransport): """ This transport uses named pipes on windows and unix domain socket on linux/mac. It's compatible with the c implementation of named pipe transport. in lib/searpc-named-pipe-transport.[ch] files. The protocol is: - request: <32b length header> - response: <32b length header> """ def __init__(self, socket_path): self.socket_path = socket_path self.pipe = None def connect(self): self.pipe = socket.socket(socket.AF_UNIX) self.pipe.connect(self.socket_path) def stop(self): 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_utf8)) sendall(self.pipe, header) sendall(self.pipe, body_utf8) resp_header = recvall(self.pipe, 4) # logger.info('resp_header is %s', resp_header) resp_size, = struct.unpack('=I', resp_header) # logger.info('resp_size is %s', resp_size) resp = recvall(self.pipe, resp_size) # logger.info('resp is %s', resp) return resp.decode(encoding='utf-8') class NamedPipeClient(SearpcClient): def __init__(self, socket_path, service_name, pool_size=5): self.socket_path = socket_path self.service_name = service_name self.pool_size = pool_size self._pool = queue.Queue(pool_size) 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): transport = self._get_transport() ret_str = transport.send(self.service_name, fcall_str) self._return_transport(transport) return ret_str class NamedPipeServer(object): """ Searpc server based on named pipe transport. Note this server is very basic and is written for testing purpose only. """ def __init__(self, socket_path): self.socket_path = socket_path self.pipe = None self.thread = Thread(target=self.accept_loop) self.thread.setDaemon(True) def start(self): self.init_socket() self.thread.start() def stop(self): pass def init_socket(self): if os.path.exists(self.socket_path): try: os.unlink(self.socket_path) except OSError: raise NamedPipeException( 'Failed to remove existing unix socket {}'. format(self.socket_path) ) 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.accept() logger.info('New pip client') t = PipeHandlerThread(connfd) t.start() class PipeHandlerThread(Thread): def __init__(self, pipe): Thread.__init__(self) self.setDaemon(True) self.pipe = pipe def run(self): while True: 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, req_size) # logger.info('req is %s', 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, resp_header) sendall(self.pipe, resp.encode(encoding='utf-8')) libsearpc-3.2-latest/pysearpc/pygencode.py000066400000000000000000000101661367255703700210140ustar00rootroot00000000000000#!/usr/bin/python import string import sys sys.path += ['../'] module_func_array_template = r""" static PyMethodDef SearpcClientModule_Functions[] = { ${array} {NULL, NULL, 0, NULL}, }; """ func_item_template = r""" {"${pyfuncname}", (PyCFunction)${cfuncname}, METH_VARARGS, "" },""" def gen_fcall_funcs_array(arg_types): fcall_array = "" if len(arg_types) == 0: pyfuncname = "fcall__void" cfuncname = "SearpcClient_Fcall__Void" else: pyfuncname = "fcall__" + "_".join(arg_types) tmplist = [] for arg in arg_types: tmplist.append(arg.capitalize()) cfuncname = "SearpcClient_Fcall__" + "_".join(tmplist) return string.Template(func_item_template)\ .substitute(pyfuncname=pyfuncname, cfuncname=cfuncname) def gen_fret_funcs_array(ret_type): fret_array = "" if ret_type is None: pyfuncname = "fret__void" cfuncname = "SearpcClient_Fret__Void" else: pyfuncname = "fret__" + ret_type cfuncname = "SearpcClient_Fret__" + ret_type.capitalize() return string.Template(func_item_template)\ .substitute(pyfuncname=pyfuncname, cfuncname=cfuncname) def gen_module_funcs_array(): """ Generate static PyMethodDef SearpcClientModule_Functions[] """ from rpc_table import func_table # generate fcall methods array fcall_array = "" arg_types_list = [] for item in func_table: if item[1] not in arg_types_list: arg_types_list.append(item[1]) for item in arg_types_list: fcall_array += gen_fcall_funcs_array(item) # generate fret methods array fret_array = "" ret_types_list = ["int", "int64", "string"] for item in ret_types_list: fret_array += gen_fret_funcs_array(item) array = fcall_array array += fret_array print(string.Template(module_func_array_template)\ .substitute(array=array)) type_table = { "string" : ("char *", "z"), "int" : ("int", "i"), "int64" : ("gint64", "L"), "object" : ("GObject *", "O"), } fcall_template = r""" static PyObject * SearpcClient_Fcall__${Suffix}(PyObject *self, PyObject *args) { char *fname; ${def_args} char *fcall; gsize len; if (!PyArg_ParseTuple(args, "${fmt}", ${args_addr})) return NULL; fcall = searpc_client_fcall__${suffix}(${args}); return PyString_FromString(fcall); } """ def gen_fcall_func(arg_types): if len(arg_types) == 0: Suffix = "Void" suffix = "void" def_args = "" kwargs_str = "NULL" fmt = "s" args_addr = "&fname" args = "fname, &len" return string.Template(fcall_template)\ .substitute(Suffix=Suffix, suffix=suffix, def_args=def_args, kwargs_str=kwargs_str, fmt=fmt, args_addr=args_addr, args=args) tmplist = [] for arg in arg_types: tmplist.append(arg.capitalize()) Suffix = "_".join(tmplist) suffix = "_".join(arg_types) def_args = "" kwargs_str = "" fmt = "s" args_addr = "&fname" args = "fname" for i, arg_type in enumerate(arg_types): def_args += " " + type_table[arg_type][0] + " param" + \ str(i + 1) + ";\n" kwargs_str += '"param' + str(i + 1) + '", ' fmt += type_table[arg_type][1] args_addr += ", ¶m" + str(i + 1) args += ", param" + str(i + 1) kwargs_str += "NULL" args += ", &len" return string.Template(fcall_template)\ .substitute(Suffix=Suffix, suffix=suffix, def_args=def_args, kwargs_str=kwargs_str, fmt=fmt, args_addr=args_addr, args=args) def gen_fcall_list(): from rpc_table import func_table arg_types_list = [] for item in func_table: if item[1] not in arg_types_list: arg_types_list.append(item[1]) for item in arg_types_list: print(gen_fcall_func(item)) if __name__ == "__main__": gen_fcall_list() gen_module_funcs_array() libsearpc-3.2-latest/pysearpc/server.py000066400000000000000000000025121367255703700203410ustar00rootroot00000000000000import json from .common import SearpcError class SearpcService(object): def __init__(self, name): self.name = name self.func_table = {} class SearpcServer(object): def __init__(self): self.services = {} def create_service(self, svcname): service = SearpcService(svcname) self.services[svcname] = service def register_function(self, svcname, fn, fname=None): service = self.services[svcname] if fname == None: fname = fn.__name__ service.func_table[fname] = fn def _call_function(self, svcname, fcallstr): """input str -> output str""" try: argv = json.loads(fcallstr) except Exception as e: raise SearpcError('bad call str: ' + str(e)) service = self.services[svcname] fname = argv[0] fn = service.func_table.get(fname, None) if fn is None: raise SearpcError('No such funtion %s' % fname) ret = fn(*argv[1:]) return ret def call_function(self, svcname, fcallstr): try: retVal = self._call_function(svcname, fcallstr) except Exception as e: ret = {'err_code': 555, 'err_msg': str(e)} else: ret = {'ret': retVal} return json.dumps(ret) searpc_server = SearpcServer() libsearpc-3.2-latest/pysearpc/test_pysearpc.py000077500000000000000000000057061367255703700217330ustar00rootroot00000000000000#!/usr/bin/env python #coding: UTF-8 import json import logging import os import sys import unittest from operator import add, mul os.chdir(os.path.dirname(os.path.abspath(__file__))) sys.path.insert(0, '..') from pysearpc import ( NamedPipeClient, NamedPipeServer, SearpcClient, SearpcError, SearpcTransport, searpc_func, searpc_server ) SVCNAME = 'test-service' 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): def connect(self): pass def send(self, service, fcall_str): return searpc_server.call_function(service, fcall_str) class RpcMixin(object): @searpc_func("int", ["int", "int"]) def add(self, x, y): pass @searpc_func("string", ["string", "int"]) 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() def call_remote_func_sync(self, fcall_str): return self.transport.send(SVCNAME, fcall_str) class NamedPipeClientForTest(NamedPipeClient, RpcMixin): pass SOCKET_PATH = '/tmp/libsearpc-test.sock' class SearpcTest(unittest.TestCase): @classmethod def setUpClass(cls): init_server() cls.client = DummyRpcClient() cls.named_pipe_server = NamedPipeServer(SOCKET_PATH) cls.named_pipe_server.start() cls.named_pipe_client = NamedPipeClientForTest(SOCKET_PATH, SVCNAME) @classmethod def tearDownClass(cls): cls.named_pipe_server.stop() def test_normal_transport(self): self.run_common(self.client) # @unittest.skip('not implemented yet') def test_pipe_transport(self): self.run_common(self.named_pipe_client) def run_common(self, client): v = client.add(1, 2) self.assertEqual(v, 3) v = client.multi(1, 2) self.assertEqual(v, 2) 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', 'format': '[%(asctime)s][%(module)s]: %(message)s', 'datefmt': '%m/%d/%Y %H:%M:%S', 'level': level, 'stream': sys.stdout } logging.basicConfig(**kw) if __name__ == '__main__': setup_logging() unittest.main() libsearpc-3.2-latest/pysearpc/transport.py000066400000000000000000000004721367255703700210720ustar00rootroot00000000000000class SearpcTransport(object): """ A transport is repsonsible to send the serialized request to the server, and get back the raw response from the server. """ def connect(self): raise NotImplementedError def send(self, service_name, request_str): raise NotImplementedError libsearpc-3.2-latest/pysearpc/utils.py000066400000000000000000000021131367255703700201700ustar00rootroot00000000000000import os import socket from pysearpc.errors import NetworkError def recvall(fd, total): remain = total data = bytearray() while remain > 0: try: new = fd.recv(remain) except socket.error as e: raise NetworkError('Failed to read from socket: %s' % e) n = len(new) if n <= 0: raise NetworkError("Failed to read from socket") else: data.extend(new) remain -= n return bytes(data) def sendall(fd, data): total = len(data) offset = 0 while offset < total: try: n = fd.send(data[offset:]) except socket.error as e: raise NetworkError('Failed to write to socket: %s' % e) if n <= 0: raise NetworkError('Failed to write to socket') else: offset += n def is_win32(): return os.name == 'nt' def make_socket_closeonexec(fd): if not is_win32(): import fcntl old_flags = fcntl.fcntl(fd, fcntl.F_GETFD) fcntl.fcntl(fd, fcntl.F_SETFD, old_flags | fcntl.FD_CLOEXEC) libsearpc-3.2-latest/tests/000077500000000000000000000000001367255703700157755ustar00rootroot00000000000000libsearpc-3.2-latest/tests/Makefile.am000066400000000000000000000021241367255703700200300ustar00rootroot00000000000000generated_sources = searpc-signature.h searpc-marshal.h clar_suite_sources = clar.suite AM_CFLAGS = @GLIB_CFLAGS@ \ @JANSSON_CFLAGS@ \ -I${top_srcdir}/lib # we need to generate the first BUILT_SOURCES = gensource check_PROGRAMS = test-searpc test_searpc_SOURCES = searpc.c clar.c main.c test_searpc_LDADD = @GLIB_LIBS@ \ @JANSSON_LIBS@ \ $(top_builddir)/lib/libsearpc.la test_searpc_LDFLAGS = -static TESTS = test-searpc EXTRA_DIST = rpc_table.py generate.py gensource: ${generated_sources} ${clar_suite_sources} rpc_table.stamp: ${top_srcdir}/tests/rpc_table.py ${top_srcdir}/lib/searpc-codegen.py @rm -f rpc_table.tmp @touch rpc_table.tmp @echo "[libsearpc]: generating rpc header files" @PYTHON@ ${top_srcdir}/lib/searpc-codegen.py ${top_srcdir}/tests/rpc_table.py @echo "[libsearpc]: done" @mv -f rpc_table.tmp $@ ${generated_sources}: rpc_table.stamp ${clar_suite_sources}: $(top_srcdir)/tests/generate.py @PYTHON@ $(top_srcdir)/tests/generate.py clean-local: rm -f ${generated_sources} rm -f rpc_table.pyc rm -f rpc_table.stamp rm -f rpc_table.tmp rm -f generate.pyc libsearpc-3.2-latest/tests/clar.c000066400000000000000000000271231367255703700170670ustar00rootroot00000000000000/* * Copyright (c) Vicent Marti. All rights reserved. * * This file is part of clar, distributed under the ISC license. * For full terms see the included COPYING file. */ #include #include #include #include #include #include #include /* required for sandboxing */ #include #include #ifdef _WIN32 # include # include # include # include # define _MAIN_CC __cdecl # ifndef stat # define stat(path, st) _stat(path, st) # endif # ifndef mkdir # define mkdir(path, mode) _mkdir(path) # endif # ifndef chdir # define chdir(path) _chdir(path) # endif # ifndef access # define access(path, mode) _access(path, mode) # endif # ifndef strdup # define strdup(str) _strdup(str) # endif # ifndef strcasecmp # define strcasecmp(a,b) _stricmp(a,b) # endif # ifndef __MINGW32__ # pragma comment(lib, "shell32") # ifndef strncpy # define strncpy(to, from, to_size) strncpy_s(to, to_size, from, _TRUNCATE) # endif # ifndef W_OK # define W_OK 02 # endif # ifndef S_ISDIR # define S_ISDIR(x) ((x & _S_IFDIR) != 0) # endif # define p_snprintf(buf,sz,fmt,...) _snprintf_s(buf,sz,_TRUNCATE,fmt,__VA_ARGS__) # else # define p_snprintf snprintf # endif # ifndef PRIuZ # define PRIuZ "Iu" # endif # ifndef PRIxZ # define PRIxZ "Ix" # endif # ifdef _MSC_VER typedef struct stat STAT_T; # else typedef struct _stat STAT_T; # endif #else # include /* waitpid(2) */ # include # define _MAIN_CC # define p_snprintf snprintf # ifndef PRIuZ # define PRIuZ "zu" # endif # ifndef PRIxZ # define PRIxZ "zx" # endif typedef struct stat STAT_T; #endif #include "clar.h" static void fs_rm(const char *_source); static void fs_copy(const char *_source, const char *dest); static const char * fixture_path(const char *base, const char *fixture_name); struct clar_error { const char *test; int test_number; const char *suite; const char *file; int line_number; const char *error_msg; char *description; struct clar_error *next; }; static struct { int argc; char **argv; enum cl_test_status test_status; const char *active_test; const char *active_suite; int total_skipped; int total_errors; int tests_ran; int suites_ran; int report_errors_only; int exit_on_error; int report_suite_names; struct clar_error *errors; struct clar_error *last_error; void (*local_cleanup)(void *); void *local_cleanup_payload; jmp_buf trampoline; int trampoline_enabled; } _clar; struct clar_func { const char *name; void (*ptr)(void); }; struct clar_suite { const char *name; struct clar_func initialize; struct clar_func cleanup; const struct clar_func *tests; size_t test_count; int enabled; }; /* From clar_print_*.c */ static void clar_print_init(int test_count, int suite_count, const char *suite_names); static void clar_print_shutdown(int test_count, int suite_count, int error_count); static void clar_print_error(int num, const struct clar_error *error); static void clar_print_ontest(const char *test_name, int test_number, enum cl_test_status failed); static void clar_print_onsuite(const char *suite_name, int suite_index); static void clar_print_onabort(const char *msg, ...); /* From clar_sandbox.c */ static void clar_unsandbox(void); static int clar_sandbox(void); /* Load the declarations for the test suite */ #include "clar.suite" /* Core test functions */ static void clar_report_errors(void) { int i = 1; struct clar_error *error, *next; error = _clar.errors; while (error != NULL) { next = error->next; clar_print_error(i++, error); free(error->description); free(error); error = next; } _clar.errors = _clar.last_error = NULL; } static void clar_run_test( const struct clar_func *test, const struct clar_func *initialize, const struct clar_func *cleanup) { _clar.test_status = CL_TEST_OK; _clar.trampoline_enabled = 1; if (setjmp(_clar.trampoline) == 0) { if (initialize->ptr != NULL) initialize->ptr(); test->ptr(); } _clar.trampoline_enabled = 0; if (_clar.local_cleanup != NULL) _clar.local_cleanup(_clar.local_cleanup_payload); if (cleanup->ptr != NULL) cleanup->ptr(); _clar.tests_ran++; /* remove any local-set cleanup methods */ _clar.local_cleanup = NULL; _clar.local_cleanup_payload = NULL; if (_clar.report_errors_only) { clar_report_errors(); } else { clar_print_ontest(test->name, _clar.tests_ran, _clar.test_status); } } static void clar_run_suite(const struct clar_suite *suite, const char *filter) { const struct clar_func *test = suite->tests; size_t i, matchlen; if (!suite->enabled) return; if (_clar.exit_on_error && _clar.total_errors) return; if (!_clar.report_errors_only) clar_print_onsuite(suite->name, ++_clar.suites_ran); _clar.active_suite = suite->name; if (filter) { size_t suitelen = strlen(suite->name); matchlen = strlen(filter); if (matchlen <= suitelen) { filter = NULL; } else { filter += suitelen; while (*filter == ':') ++filter; matchlen = strlen(filter); } } for (i = 0; i < suite->test_count; ++i) { if (filter && strncmp(test[i].name, filter, matchlen)) continue; _clar.active_test = test[i].name; clar_run_test(&test[i], &suite->initialize, &suite->cleanup); if (_clar.exit_on_error && _clar.total_errors) return; } } static void clar_usage(const char *arg) { printf("Usage: %s [options]\n\n", arg); printf("Options:\n"); printf(" -sname\tRun only the suite with `name` (can go to individual test name)\n"); printf(" -iname\tInclude the suite with `name`\n"); printf(" -xname\tExclude the suite with `name`\n"); printf(" -q \tOnly report tests that had an error\n"); printf(" -Q \tQuit as soon as a test fails\n"); printf(" -l \tPrint suite names\n"); exit(-1); } static void clar_parse_args(int argc, char **argv) { int i; for (i = 1; i < argc; ++i) { char *argument = argv[i]; if (argument[0] != '-') clar_usage(argv[0]); switch (argument[1]) { case 's': case 'i': case 'x': { /* given suite name */ int offset = (argument[2] == '=') ? 3 : 2, found = 0; char action = argument[1]; size_t j, arglen, suitelen, cmplen; argument += offset; arglen = strlen(argument); if (arglen == 0) clar_usage(argv[0]); for (j = 0; j < _clar_suite_count; ++j) { suitelen = strlen(_clar_suites[j].name); cmplen = (arglen < suitelen) ? arglen : suitelen; if (strncmp(argument, _clar_suites[j].name, cmplen) == 0) { int exact = (arglen >= suitelen); ++found; if (!exact) _clar.report_suite_names = 1; switch (action) { case 's': clar_run_suite(&_clar_suites[j], argument); break; case 'i': _clar_suites[j].enabled = 1; break; case 'x': _clar_suites[j].enabled = 0; break; } if (exact) break; } } if (!found) { clar_print_onabort("No suite matching '%s' found.\n", argument); exit(-1); } break; } case 'q': _clar.report_errors_only = 1; break; case 'Q': _clar.exit_on_error = 1; break; case 'l': { size_t j; printf("Test suites (use -s to run just one):\n"); for (j = 0; j < _clar_suite_count; ++j) printf(" %3d: %s\n", (int)j, _clar_suites[j].name); exit(0); } default: clar_usage(argv[0]); } } } void clar_test_init(int argc, char **argv) { clar_print_init( (int)_clar_callback_count, (int)_clar_suite_count, "" ); if (clar_sandbox() < 0) { clar_print_onabort("Failed to sandbox the test runner.\n"); exit(-1); } _clar.argc = argc; _clar.argv = argv; } int clar_test_run() { if (_clar.argc > 1) clar_parse_args(_clar.argc, _clar.argv); if (!_clar.suites_ran) { size_t i; for (i = 0; i < _clar_suite_count; ++i) clar_run_suite(&_clar_suites[i], NULL); } return _clar.total_errors; } void clar_test_shutdown() { clar_print_shutdown( _clar.tests_ran, (int)_clar_suite_count, _clar.total_errors ); clar_unsandbox(); } int clar_test(int argc, char **argv) { int errors; clar_test_init(argc, argv); errors = clar_test_run(); clar_test_shutdown(); return errors; } static void abort_test(void) { if (!_clar.trampoline_enabled) { clar_print_onabort( "Fatal error: a cleanup method raised an exception."); clar_report_errors(); exit(-1); } longjmp(_clar.trampoline, -1); } void clar__skip(void) { _clar.test_status = CL_TEST_SKIP; _clar.total_skipped++; abort_test(); } void clar__fail( const char *file, int line, const char *error_msg, const char *description, int should_abort) { struct clar_error *error = calloc(1, sizeof(struct clar_error)); if (_clar.errors == NULL) _clar.errors = error; if (_clar.last_error != NULL) _clar.last_error->next = error; _clar.last_error = error; error->test = _clar.active_test; error->test_number = _clar.tests_ran; error->suite = _clar.active_suite; error->file = file; error->line_number = line; error->error_msg = error_msg; if (description != NULL) error->description = strdup(description); _clar.total_errors++; _clar.test_status = CL_TEST_FAILURE; if (should_abort) abort_test(); } void clar__assert( int condition, const char *file, int line, const char *error_msg, const char *description, int should_abort) { if (condition) return; clar__fail(file, line, error_msg, description, should_abort); } void clar__assert_equal( const char *file, int line, const char *err, int should_abort, const char *fmt, ...) { va_list args; char buf[4096]; int is_equal = 1; va_start(args, fmt); if (!strcmp("%s", fmt)) { const char *s1 = va_arg(args, const char *); const char *s2 = va_arg(args, const char *); is_equal = (!s1 || !s2) ? (s1 == s2) : !strcmp(s1, s2); if (!is_equal) { if (s1 && s2) { int pos; for (pos = 0; s1[pos] == s2[pos] && s1[pos] && s2[pos]; ++pos) /* find differing byte offset */; p_snprintf(buf, sizeof(buf), "'%s' != '%s' (at byte %d)", s1, s2, pos); } else { p_snprintf(buf, sizeof(buf), "'%s' != '%s'", s1, s2); } } } else if(!strcmp("%.*s", fmt)) { const char *s1 = va_arg(args, const char *); const char *s2 = va_arg(args, const char *); int len = va_arg(args, int); is_equal = (!s1 || !s2) ? (s1 == s2) : !strncmp(s1, s2, len); if (!is_equal) { if (s1 && s2) { int pos; for (pos = 0; s1[pos] == s2[pos] && pos < len; ++pos) /* find differing byte offset */; p_snprintf(buf, sizeof(buf), "'%.*s' != '%.*s' (at byte %d)", len, s1, len, s2, pos); } else { p_snprintf(buf, sizeof(buf), "'%.*s' != '%.*s'", len, s1, len, s2); } } } else if (!strcmp("%"PRIuZ, fmt) || !strcmp("%"PRIxZ, fmt)) { size_t sz1 = va_arg(args, size_t), sz2 = va_arg(args, size_t); is_equal = (sz1 == sz2); if (!is_equal) { int offset = p_snprintf(buf, sizeof(buf), fmt, sz1); strncat(buf, " != ", sizeof(buf) - offset); p_snprintf(buf + offset + 4, sizeof(buf) - offset - 4, fmt, sz2); } } else if (!strcmp("%p", fmt)) { void *p1 = va_arg(args, void *), *p2 = va_arg(args, void *); is_equal = (p1 == p2); if (!is_equal) p_snprintf(buf, sizeof(buf), "%p != %p", p1, p2); } else { int i1 = va_arg(args, int), i2 = va_arg(args, int); is_equal = (i1 == i2); if (!is_equal) { int offset = p_snprintf(buf, sizeof(buf), fmt, i1); strncat(buf, " != ", sizeof(buf) - offset); p_snprintf(buf + offset + 4, sizeof(buf) - offset - 4, fmt, i2); } } va_end(args); if (!is_equal) clar__fail(file, line, err, buf, should_abort); } void cl_set_cleanup(void (*cleanup)(void *), void *opaque) { _clar.local_cleanup = cleanup; _clar.local_cleanup_payload = opaque; } #include "clar/sandbox.h" #include "clar/fixtures.h" #include "clar/fs.h" #include "clar/print.h" libsearpc-3.2-latest/tests/clar.h000066400000000000000000000075271367255703700171020ustar00rootroot00000000000000/* * Copyright (c) Vicent Marti. All rights reserved. * * This file is part of clar, distributed under the ISC license. * For full terms see the included COPYING file. */ #ifndef __CLAR_TEST_H__ #define __CLAR_TEST_H__ #include enum cl_test_status { CL_TEST_OK, CL_TEST_FAILURE, CL_TEST_SKIP }; void clar_test_init(int argc, char *argv[]); int clar_test_run(void); void clar_test_shutdown(void); int clar_test(int argc, char *argv[]); const char *clar_sandbox_path(void); void cl_set_cleanup(void (*cleanup)(void *), void *opaque); void cl_fs_cleanup(void); #ifdef CLAR_FIXTURE_PATH const char *cl_fixture(const char *fixture_name); void cl_fixture_sandbox(const char *fixture_name); void cl_fixture_cleanup(const char *fixture_name); #endif /** * Assertion macros with explicit error message */ #define cl_must_pass_(expr, desc) clar__assert((expr) >= 0, __FILE__, __LINE__, "Function call failed: " #expr, desc, 1) #define cl_must_fail_(expr, desc) clar__assert((expr) < 0, __FILE__, __LINE__, "Expected function call to fail: " #expr, desc, 1) #define cl_assert_(expr, desc) clar__assert((expr) != 0, __FILE__, __LINE__, "Expression is not true: " #expr, desc, 1) /** * Check macros with explicit error message */ #define cl_check_pass_(expr, desc) clar__assert((expr) >= 0, __FILE__, __LINE__, "Function call failed: " #expr, desc, 0) #define cl_check_fail_(expr, desc) clar__assert((expr) < 0, __FILE__, __LINE__, "Expected function call to fail: " #expr, desc, 0) #define cl_check_(expr, desc) clar__assert((expr) != 0, __FILE__, __LINE__, "Expression is not true: " #expr, desc, 0) /** * Assertion macros with no error message */ #define cl_must_pass(expr) cl_must_pass_(expr, NULL) #define cl_must_fail(expr) cl_must_fail_(expr, NULL) #define cl_assert(expr) cl_assert_(expr, NULL) /** * Check macros with no error message */ #define cl_check_pass(expr) cl_check_pass_(expr, NULL) #define cl_check_fail(expr) cl_check_fail_(expr, NULL) #define cl_check(expr) cl_check_(expr, NULL) /** * Forced failure/warning */ #define cl_fail(desc) clar__fail(__FILE__, __LINE__, "Test failed.", desc, 1) #define cl_warning(desc) clar__fail(__FILE__, __LINE__, "Warning during test execution:", desc, 0) #define cl_skip() clar__skip() /** * Typed assertion macros */ #define cl_assert_equal_s(s1,s2) clar__assert_equal(__FILE__,__LINE__,"String mismatch: " #s1 " != " #s2, 1, "%s", (s1), (s2)) #define cl_assert_equal_s_(s1,s2,note) clar__assert_equal(__FILE__,__LINE__,"String mismatch: " #s1 " != " #s2 " (" #note ")", 1, "%s", (s1), (s2)) #define cl_assert_equal_strn(s1,s2,len) clar__assert_equal(__FILE__,__LINE__,"String mismatch: " #s1 " != " #s2, 1, "%.*s", (s1), (s2), (int)(len)) #define cl_assert_equal_strn_(s1,s2,len,note) clar__assert_equal(__FILE__,__LINE__,"String mismatch: " #s1 " != " #s2 " (" #note ")", 1, "%.*s", (s1), (s2), (int)(len)) #define cl_assert_equal_i(i1,i2) clar__assert_equal(__FILE__,__LINE__,#i1 " != " #i2, 1, "%d", (int)(i1), (int)(i2)) #define cl_assert_equal_i_(i1,i2,note) clar__assert_equal(__FILE__,__LINE__,#i1 " != " #i2 " (" #note ")", 1, "%d", (i1), (i2)) #define cl_assert_equal_i_fmt(i1,i2,fmt) clar__assert_equal(__FILE__,__LINE__,#i1 " != " #i2, 1, (fmt), (int)(i1), (int)(i2)) #define cl_assert_equal_b(b1,b2) clar__assert_equal(__FILE__,__LINE__,#b1 " != " #b2, 1, "%d", (int)((b1) != 0),(int)((b2) != 0)) #define cl_assert_equal_p(p1,p2) clar__assert_equal(__FILE__,__LINE__,"Pointer mismatch: " #p1 " != " #p2, 1, "%p", (p1), (p2)) void clar__skip(void); void clar__fail( const char *file, int line, const char *error, const char *description, int should_abort); void clar__assert( int condition, const char *file, int line, const char *error, const char *description, int should_abort); void clar__assert_equal( const char *file, int line, const char *err, int should_abort, const char *fmt, ...); #endif libsearpc-3.2-latest/tests/clar/000077500000000000000000000000001367255703700167165ustar00rootroot00000000000000libsearpc-3.2-latest/tests/clar/fixtures.h000066400000000000000000000013371367255703700207440ustar00rootroot00000000000000static const char * fixture_path(const char *base, const char *fixture_name) { static char _path[4096]; size_t root_len; root_len = strlen(base); strncpy(_path, base, sizeof(_path)); if (_path[root_len - 1] != '/') _path[root_len++] = '/'; if (fixture_name[0] == '/') fixture_name++; strncpy(_path + root_len, fixture_name, sizeof(_path) - root_len); return _path; } #ifdef CLAR_FIXTURE_PATH const char *cl_fixture(const char *fixture_name) { return fixture_path(CLAR_FIXTURE_PATH, fixture_name); } void cl_fixture_sandbox(const char *fixture_name) { fs_copy(cl_fixture(fixture_name), _clar_path); } void cl_fixture_cleanup(const char *fixture_name) { fs_rm(fixture_path(_clar_path, fixture_name)); } #endif libsearpc-3.2-latest/tests/clar/fs.h000066400000000000000000000170721367255703700175060ustar00rootroot00000000000000#ifdef _WIN32 #define RM_RETRY_COUNT 5 #define RM_RETRY_DELAY 10 #ifdef __MINGW32__ /* These security-enhanced functions are not available * in MinGW, so just use the vanilla ones */ #define wcscpy_s(a, b, c) wcscpy((a), (c)) #define wcscat_s(a, b, c) wcscat((a), (c)) #endif /* __MINGW32__ */ static int fs__dotordotdot(WCHAR *_tocheck) { return _tocheck[0] == '.' && (_tocheck[1] == '\0' || (_tocheck[1] == '.' && _tocheck[2] == '\0')); } static int fs_rmdir_rmdir(WCHAR *_wpath) { unsigned retries = 1; while (!RemoveDirectoryW(_wpath)) { /* Only retry when we have retries remaining, and the * error was ERROR_DIR_NOT_EMPTY. */ if (retries++ > RM_RETRY_COUNT || ERROR_DIR_NOT_EMPTY != GetLastError()) return -1; /* Give whatever has a handle to a child item some time * to release it before trying again */ Sleep(RM_RETRY_DELAY * retries * retries); } return 0; } static void fs_rmdir_helper(WCHAR *_wsource) { WCHAR buffer[MAX_PATH]; HANDLE find_handle; WIN32_FIND_DATAW find_data; size_t buffer_prefix_len; /* Set up the buffer and capture the length */ wcscpy_s(buffer, MAX_PATH, _wsource); wcscat_s(buffer, MAX_PATH, L"\\"); buffer_prefix_len = wcslen(buffer); /* FindFirstFile needs a wildcard to match multiple items */ wcscat_s(buffer, MAX_PATH, L"*"); find_handle = FindFirstFileW(buffer, &find_data); cl_assert(INVALID_HANDLE_VALUE != find_handle); do { /* FindFirstFile/FindNextFile gives back . and .. * entries at the beginning */ if (fs__dotordotdot(find_data.cFileName)) continue; wcscpy_s(buffer + buffer_prefix_len, MAX_PATH - buffer_prefix_len, find_data.cFileName); if (FILE_ATTRIBUTE_DIRECTORY & find_data.dwFileAttributes) fs_rmdir_helper(buffer); else { /* If set, the +R bit must be cleared before deleting */ if (FILE_ATTRIBUTE_READONLY & find_data.dwFileAttributes) cl_assert(SetFileAttributesW(buffer, find_data.dwFileAttributes & ~FILE_ATTRIBUTE_READONLY)); cl_assert(DeleteFileW(buffer)); } } while (FindNextFileW(find_handle, &find_data)); /* Ensure that we successfully completed the enumeration */ cl_assert(ERROR_NO_MORE_FILES == GetLastError()); /* Close the find handle */ FindClose(find_handle); /* Now that the directory is empty, remove it */ cl_assert(0 == fs_rmdir_rmdir(_wsource)); } static int fs_rm_wait(WCHAR *_wpath) { unsigned retries = 1; DWORD last_error; do { if (INVALID_FILE_ATTRIBUTES == GetFileAttributesW(_wpath)) last_error = GetLastError(); else last_error = ERROR_SUCCESS; /* Is the item gone? */ if (ERROR_FILE_NOT_FOUND == last_error || ERROR_PATH_NOT_FOUND == last_error) return 0; Sleep(RM_RETRY_DELAY * retries * retries); } while (retries++ <= RM_RETRY_COUNT); return -1; } static void fs_rm(const char *_source) { WCHAR wsource[MAX_PATH]; DWORD attrs; /* The input path is UTF-8. Convert it to wide characters * for use with the Windows API */ cl_assert(MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, _source, -1, /* Indicates NULL termination */ wsource, MAX_PATH)); /* Does the item exist? If not, we have no work to do */ attrs = GetFileAttributesW(wsource); if (INVALID_FILE_ATTRIBUTES == attrs) return; if (FILE_ATTRIBUTE_DIRECTORY & attrs) fs_rmdir_helper(wsource); else { /* The item is a file. Strip the +R bit */ if (FILE_ATTRIBUTE_READONLY & attrs) cl_assert(SetFileAttributesW(wsource, attrs & ~FILE_ATTRIBUTE_READONLY)); cl_assert(DeleteFileW(wsource)); } /* Wait for the DeleteFile or RemoveDirectory call to complete */ cl_assert(0 == fs_rm_wait(wsource)); } static void fs_copydir_helper(WCHAR *_wsource, WCHAR *_wdest) { WCHAR buf_source[MAX_PATH], buf_dest[MAX_PATH]; HANDLE find_handle; WIN32_FIND_DATAW find_data; size_t buf_source_prefix_len, buf_dest_prefix_len; wcscpy_s(buf_source, MAX_PATH, _wsource); wcscat_s(buf_source, MAX_PATH, L"\\"); buf_source_prefix_len = wcslen(buf_source); wcscpy_s(buf_dest, MAX_PATH, _wdest); wcscat_s(buf_dest, MAX_PATH, L"\\"); buf_dest_prefix_len = wcslen(buf_dest); /* Get an enumerator for the items in the source. */ wcscat_s(buf_source, MAX_PATH, L"*"); find_handle = FindFirstFileW(buf_source, &find_data); cl_assert(INVALID_HANDLE_VALUE != find_handle); /* Create the target directory. */ cl_assert(CreateDirectoryW(_wdest, NULL)); do { /* FindFirstFile/FindNextFile gives back . and .. * entries at the beginning */ if (fs__dotordotdot(find_data.cFileName)) continue; wcscpy_s(buf_source + buf_source_prefix_len, MAX_PATH - buf_source_prefix_len, find_data.cFileName); wcscpy_s(buf_dest + buf_dest_prefix_len, MAX_PATH - buf_dest_prefix_len, find_data.cFileName); if (FILE_ATTRIBUTE_DIRECTORY & find_data.dwFileAttributes) fs_copydir_helper(buf_source, buf_dest); else cl_assert(CopyFileW(buf_source, buf_dest, TRUE)); } while (FindNextFileW(find_handle, &find_data)); /* Ensure that we successfully completed the enumeration */ cl_assert(ERROR_NO_MORE_FILES == GetLastError()); /* Close the find handle */ FindClose(find_handle); } static void fs_copy(const char *_source, const char *_dest) { WCHAR wsource[MAX_PATH], wdest[MAX_PATH]; DWORD source_attrs, dest_attrs; HANDLE find_handle; WIN32_FIND_DATAW find_data; /* The input paths are UTF-8. Convert them to wide characters * for use with the Windows API. */ cl_assert(MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, _source, -1, wsource, MAX_PATH)); cl_assert(MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, _dest, -1, wdest, MAX_PATH)); /* Check the source for existence */ source_attrs = GetFileAttributesW(wsource); cl_assert(INVALID_FILE_ATTRIBUTES != source_attrs); /* Check the target for existence */ dest_attrs = GetFileAttributesW(wdest); if (INVALID_FILE_ATTRIBUTES != dest_attrs) { /* Target exists; append last path part of source to target. * Use FindFirstFile to parse the path */ find_handle = FindFirstFileW(wsource, &find_data); cl_assert(INVALID_HANDLE_VALUE != find_handle); wcscat_s(wdest, MAX_PATH, L"\\"); wcscat_s(wdest, MAX_PATH, find_data.cFileName); FindClose(find_handle); /* Check the new target for existence */ cl_assert(INVALID_FILE_ATTRIBUTES == GetFileAttributesW(wdest)); } if (FILE_ATTRIBUTE_DIRECTORY & source_attrs) fs_copydir_helper(wsource, wdest); else cl_assert(CopyFileW(wsource, wdest, TRUE)); } void cl_fs_cleanup(void) { fs_rm(fixture_path(_clar_path, "*")); } #else #include #include static int shell_out(char * const argv[]) { int status, piderr; pid_t pid; pid = fork(); if (pid < 0) { fprintf(stderr, "System error: `fork()` call failed (%d) - %s\n", errno, strerror(errno)); exit(-1); } if (pid == 0) { execv(argv[0], argv); } do { piderr = waitpid(pid, &status, WUNTRACED); } while (piderr < 0 && (errno == EAGAIN || errno == EINTR)); return WEXITSTATUS(status); } static void fs_copy(const char *_source, const char *dest) { char *argv[5]; char *source; size_t source_len; source = strdup(_source); source_len = strlen(source); if (source[source_len - 1] == '/') source[source_len - 1] = 0; argv[0] = "/bin/cp"; argv[1] = "-R"; argv[2] = source; argv[3] = (char *)dest; argv[4] = NULL; cl_must_pass_( shell_out(argv), "Failed to copy test fixtures to sandbox" ); free(source); } static void fs_rm(const char *source) { char *argv[4]; argv[0] = "/bin/rm"; argv[1] = "-Rf"; argv[2] = (char *)source; argv[3] = NULL; cl_must_pass_( shell_out(argv), "Failed to cleanup the sandbox" ); } void cl_fs_cleanup(void) { clar_unsandbox(); clar_sandbox(); } #endif libsearpc-3.2-latest/tests/clar/print.h000066400000000000000000000024721367255703700202300ustar00rootroot00000000000000 static void clar_print_init(int test_count, int suite_count, const char *suite_names) { (void)test_count; printf("Loaded %d suites: %s\n", (int)suite_count, suite_names); printf("Started\n"); } static void clar_print_shutdown(int test_count, int suite_count, int error_count) { (void)test_count; (void)suite_count; (void)error_count; printf("\n\n"); clar_report_errors(); } static void clar_print_error(int num, const struct clar_error *error) { printf(" %d) Failure:\n", num); printf("%s::%s [%s:%d]\n", error->suite, error->test, error->file, error->line_number); printf(" %s\n", error->error_msg); if (error->description != NULL) printf(" %s\n", error->description); printf("\n"); fflush(stdout); } static void clar_print_ontest(const char *test_name, int test_number, enum cl_test_status status) { (void)test_name; (void)test_number; switch(status) { case CL_TEST_OK: printf("."); break; case CL_TEST_FAILURE: printf("F"); break; case CL_TEST_SKIP: printf("S"); break; } fflush(stdout); } static void clar_print_onsuite(const char *suite_name, int suite_index) { if (_clar.report_suite_names) printf("\n%s", suite_name); (void)suite_index; } static void clar_print_onabort(const char *msg, ...) { va_list argp; va_start(argp, msg); vfprintf(stderr, msg, argp); va_end(argp); } libsearpc-3.2-latest/tests/clar/sandbox.h000066400000000000000000000043651367255703700205350ustar00rootroot00000000000000static char _clar_path[4096]; static int is_valid_tmp_path(const char *path) { STAT_T st; if (stat(path, &st) != 0) return 0; if (!S_ISDIR(st.st_mode)) return 0; return (access(path, W_OK) == 0); } static int find_tmp_path(char *buffer, size_t length) { #ifndef _WIN32 static const size_t var_count = 5; static const char *env_vars[] = { "CLAR_TMP", "TMPDIR", "TMP", "TEMP", "USERPROFILE" }; size_t i; for (i = 0; i < var_count; ++i) { const char *env = getenv(env_vars[i]); if (!env) continue; if (is_valid_tmp_path(env)) { strncpy(buffer, env, length); return 0; } } /* If the environment doesn't say anything, try to use /tmp */ if (is_valid_tmp_path("/tmp")) { strncpy(buffer, "/tmp", length); return 0; } #else DWORD env_len = GetEnvironmentVariable("CLAR_TMP", buffer, (DWORD)length); if (env_len > 0 && env_len < (DWORD)length) return 0; if (GetTempPath((DWORD)length, buffer)) return 0; #endif /* This system doesn't like us, try to use the current directory */ if (is_valid_tmp_path(".")) { strncpy(buffer, ".", length); return 0; } return -1; } static void clar_unsandbox(void) { if (_clar_path[0] == '\0') return; chdir(".."); fs_rm(_clar_path); } static int build_sandbox_path(void) { const char path_tail[] = "clar_tmp_XXXXXX"; size_t len; if (find_tmp_path(_clar_path, sizeof(_clar_path)) < 0) return -1; len = strlen(_clar_path); #ifdef _WIN32 { /* normalize path to POSIX forward slashes */ size_t i; for (i = 0; i < len; ++i) { if (_clar_path[i] == '\\') _clar_path[i] = '/'; } } #endif if (_clar_path[len - 1] != '/') { _clar_path[len++] = '/'; } strncpy(_clar_path + len, path_tail, sizeof(_clar_path) - len); #if defined(__MINGW32__) if (_mktemp(_clar_path) == NULL) return -1; if (mkdir(_clar_path, 0700) != 0) return -1; #elif defined(_WIN32) if (_mktemp_s(_clar_path, sizeof(_clar_path)) != 0) return -1; if (mkdir(_clar_path, 0700) != 0) return -1; #else if (mkdtemp(_clar_path) == NULL) return -1; #endif return 0; } static int clar_sandbox(void) { if (_clar_path[0] == '\0' && build_sandbox_path() < 0) return -1; if (chdir(_clar_path) != 0) return -1; return 0; } const char *clar_sandbox_path(void) { return _clar_path; } libsearpc-3.2-latest/tests/clar_test.h000066400000000000000000000005711367255703700201310ustar00rootroot00000000000000/* * Copyright (c) Vicent Marti. All rights reserved. * * This file is part of clar, distributed under the ISC license. * For full terms see the included COPYING file. */ #ifndef __CLAR_TEST__ #define __CLAR_TEST__ /* Import the standard clar helper functions */ #include "clar.h" /* Your custom shared includes / defines here */ extern int global_test_counter; #endif libsearpc-3.2-latest/tests/generate.py000077500000000000000000000164521367255703700201540ustar00rootroot00000000000000#!/usr/bin/env python # # Copyright (c) Vicent Marti. All rights reserved. # # This file is part of clar, distributed under the ISC license. # For full terms see the included COPYING file. # from __future__ import with_statement from string import Template import re, fnmatch, os, codecs, pickle class Module(object): class Template(object): def __init__(self, module): self.module = module def _render_callback(self, cb): if not cb: return ' { NULL, NULL }' return ' { "%s", &%s }' % (cb['short_name'], cb['symbol']) class DeclarationTemplate(Template): def render(self): out = "\n".join("extern %s;" % cb['declaration'] for cb in self.module.callbacks) + "\n" if self.module.initialize: out += "extern %s;\n" % self.module.initialize['declaration'] if self.module.cleanup: out += "extern %s;\n" % self.module.cleanup['declaration'] return out class CallbacksTemplate(Template): def render(self): out = "static const struct clar_func _clar_cb_%s[] = {\n" % self.module.name out += ",\n".join(self._render_callback(cb) for cb in self.module.callbacks) out += "\n};\n" return out class InfoTemplate(Template): def render(self): return Template( r""" { "${clean_name}", ${initialize}, ${cleanup}, ${cb_ptr}, ${cb_count}, ${enabled} }""" ).substitute( clean_name = self.module.clean_name(), initialize = self._render_callback(self.module.initialize), cleanup = self._render_callback(self.module.cleanup), cb_ptr = "_clar_cb_%s" % self.module.name, cb_count = len(self.module.callbacks), enabled = int(self.module.enabled) ) def __init__(self, name): self.name = name self.mtime = 0 self.enabled = True self.modified = False def clean_name(self): return self.name.replace("_", "::") def _skip_comments(self, text): SKIP_COMMENTS_REGEX = re.compile( r'//.*?$|/\*.*?\*/|\'(?:\\.|[^\\\'])*\'|"(?:\\.|[^\\"])*"', re.DOTALL | re.MULTILINE) def _replacer(match): s = match.group(0) return "" if s.startswith('/') else s return re.sub(SKIP_COMMENTS_REGEX, _replacer, text) def parse(self, contents): TEST_FUNC_REGEX = r"^(void\s+(test_%s__(\w+))\s*\(\s*void\s*\))\s*\{" contents = self._skip_comments(contents) regex = re.compile(TEST_FUNC_REGEX % self.name, re.MULTILINE) self.callbacks = [] self.initialize = None self.cleanup = None for (declaration, symbol, short_name) in regex.findall(contents): data = { "short_name" : short_name, "declaration" : declaration, "symbol" : symbol } if short_name == 'initialize': self.initialize = data elif short_name == 'cleanup': self.cleanup = data else: self.callbacks.append(data) return self.callbacks != [] def refresh(self, path): self.modified = False try: st = os.stat(path) # Not modified if st.st_mtime == self.mtime: return True self.modified = True self.mtime = st.st_mtime with codecs.open(path, encoding='utf-8') as fp: raw_content = fp.read() except IOError: return False return self.parse(raw_content) class TestSuite(object): def __init__(self, path): self.path = path def should_generate(self, path): if not os.path.isfile(path): return True if any(module.modified for module in self.modules.values()): return True return False def find_modules(self): modules = [] for root, _, files in os.walk(self.path): module_root = root[len(self.path):] module_root = [c for c in module_root.split(os.sep) if c] tests_in_module = fnmatch.filter(files, "*.c") for test_file in tests_in_module: full_path = os.path.join(root, test_file) module_name = "_".join(module_root + [test_file[:-2]]) modules.append((full_path, module_name)) return modules def load_cache(self): path = os.path.join(self.path, '.clarcache') cache = {} try: fp = open(path, 'rb') cache = pickle.load(fp) fp.close() except (IOError, ValueError): pass return cache def save_cache(self): path = os.path.join(self.path, '.clarcache') with open(path, 'wb') as cache: pickle.dump(self.modules, cache) def load(self, force = False): module_data = self.find_modules() self.modules = {} if force else self.load_cache() for path, name in module_data: if name not in self.modules: self.modules[name] = Module(name) if not self.modules[name].refresh(path): del self.modules[name] def disable(self, excluded): for exclude in excluded: for module in self.modules.values(): name = module.clean_name() if name.startswith(exclude): module.enabled = False module.modified = True def suite_count(self): return len(self.modules) def callback_count(self): return sum(len(module.callbacks) for module in self.modules.values()) def write(self): output = os.path.join(self.path, 'clar.suite') if not self.should_generate(output): return False with open(output, 'w') as data: for module in self.modules.values(): t = Module.DeclarationTemplate(module) data.write(t.render()) for module in self.modules.values(): t = Module.CallbacksTemplate(module) data.write(t.render()) suites = "static struct clar_suite _clar_suites[] = {" + ','.join( Module.InfoTemplate(module).render() for module in sorted(self.modules.values(), key=lambda module: module.name) ) + "\n};\n" data.write(suites) data.write("static const size_t _clar_suite_count = %d;\n" % self.suite_count()) data.write("static const size_t _clar_callback_count = %d;\n" % self.callback_count()) self.save_cache() return True if __name__ == '__main__': from optparse import OptionParser parser = OptionParser() parser.add_option('-f', '--force', action="store_true", dest='force', default=False) parser.add_option('-x', '--exclude', dest='excluded', action='append', default=[]) options, args = parser.parse_args() for path in args or ['.']: suite = TestSuite(path) suite.load(options.force) suite.disable(options.excluded) if suite.write(): print("Written `clar.suite` (%d tests in %d suites)" % (suite.callback_count(), suite.suite_count())) libsearpc-3.2-latest/tests/main.c000066400000000000000000000015541367255703700170720ustar00rootroot00000000000000/* * Copyright (c) Vicent Marti. All rights reserved. * * This file is part of clar, distributed under the ISC license. * For full terms see the included COPYING file. */ #include #include #include "clar_test.h" /* * Minimal main() for clar tests. * * Modify this with any application specific setup or teardown that you need. * The only required line is the call to `clar_test(argc, argv)`, which will * execute the test suite. If you want to check the return value of the test * application, main() should return the same value returned by clar_test(). */ #ifdef _WIN32 int __cdecl main(int argc, char *argv[]) #else int main(int argc, char *argv[]) #endif { #if !GLIB_CHECK_VERSION(2, 36, 0) g_type_init (); #endif #ifndef WIN32 signal (SIGPIPE, SIG_IGN); #endif /* Run the test suite */ return clar_test(argc, argv); } libsearpc-3.2-latest/tests/rpc_table.py000066400000000000000000000004071367255703700203030ustar00rootroot00000000000000""" Define RPC functions needed to generate """ # [ , [] ] func_table = [ [ "string", ["string", "int"] ], [ "object", ["string"] ], [ "objlist", ["string", "int"] ], [ "json", ["string", "int"] ], [ "json", ["json"]], ] libsearpc-3.2-latest/tests/searpc.c000066400000000000000000000400531367255703700174200ustar00rootroot00000000000000#include #include #include #include #define DFT_DOMAIN g_quark_from_string("TEST") #include #include "searpc-server.h" #include "searpc-client.h" #include "searpc-named-pipe-transport.h" #include "clar.h" #if !defined(WIN32) static const char *pipe_path = "/tmp/.searpc-test"; #else static const char *pipe_path = "\\\\.\\pipe\\libsearpc-test"; #endif /* sample class */ #define MAMAN_TYPE_BAR (maman_bar_get_type ()) #define MAMAN_BAR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MAMAN_TYPE_BAR, MamanBar)) #define MAMAN_IS_BAR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MAMAN_TYPE_BAR)) #define MAMAN_BAR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MAMAN_TYPE_BAR, MamanBarClass)) #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; struct _MamanBar { GObject parent_instance; gchar *name; int papa_number; }; struct _MamanBarClass { GObjectClass parent_class; }; G_DEFINE_TYPE (MamanBar, maman_bar, G_TYPE_OBJECT); enum { PROP_0, PROP_MAMAN_NAME, PROP_PAPA_NUMBER }; static void maman_bar_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) { MamanBar *self = MAMAN_BAR (object); switch (property_id) { case PROP_MAMAN_NAME: g_free (self->name); self->name = g_value_dup_string (value); break; case PROP_PAPA_NUMBER: self->papa_number = g_value_get_uchar (value); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } } static void maman_bar_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) { MamanBar *self = MAMAN_BAR (object); switch (property_id) { case PROP_MAMAN_NAME: g_value_set_string (value, self->name); break; case PROP_PAPA_NUMBER: g_value_set_uchar (value, self->papa_number); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } } static void maman_bar_finalize (GObject *gobject) { MamanBar *self = MAMAN_BAR (gobject); g_free (self->name); /* Chain up to the parent class */ G_OBJECT_CLASS (maman_bar_parent_class)->finalize (gobject); } static void maman_bar_class_init (MamanBarClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); GParamSpec *pspec; gobject_class->set_property = maman_bar_set_property; gobject_class->get_property = maman_bar_get_property; gobject_class->finalize = maman_bar_finalize; pspec = g_param_spec_string ("name", "Maman name", "Set maman's name", "no-name-set" /* default value */, G_PARAM_READWRITE); g_object_class_install_property (gobject_class, PROP_MAMAN_NAME, pspec); pspec = g_param_spec_uchar ("papa-number", "Number of current Papa", "Set/Get papa's number", 0 /* minimum value */, 10 /* maximum value */, 2 /* default value */, G_PARAM_READWRITE); g_object_class_install_property (gobject_class, PROP_PAPA_NUMBER, pspec); } static void maman_bar_init (MamanBar *self) { } /* sample client */ static SearpcClient *client; /* sample client with named pipe as transport */ static SearpcClient *client_with_pipe_transport; char * sample_send(void *arg, const gchar *fcall_str, size_t fcall_len, size_t *ret_len) { cl_assert_ (strcmp(arg, "test") == 0, arg); char *ret; /* directly call in memory, instead of send via network */ gchar *temp = g_strdup(fcall_str); ret = searpc_server_call_function ("test", temp, fcall_len, ret_len); g_free (temp); return ret; } int sample_async_send (void *arg, gchar *fcall_str, size_t fcall_len, void *rpc_priv) { cl_assert (strcmp(arg, "test_async") == 0); char *ret; size_t ret_len; gchar *temp = g_strdup(fcall_str); ret = searpc_server_call_function ("test", temp, fcall_len, &ret_len); g_free (temp); searpc_client_generic_callback (ret, ret_len, rpc_priv, NULL); g_free (ret); return 0; } gchar * get_substring (const gchar *orig_str, int sub_len, GError **error) { if (sub_len > strlen(orig_str)) { g_set_error (error, DFT_DOMAIN, 100, "Substring length larger than the length of origin string"); return NULL; } gchar *ret = g_malloc0(sub_len+1); memcpy(ret, orig_str, sub_len); ret[sub_len] = '\0'; return ret; } static SearpcClient * do_create_client_with_pipe_transport() { 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"); return searpc_client_with_named_pipe_transport(pipe_client, "test"); } void test_searpc__simple_call (void) { gchar* result; GError *error = NULL; result = searpc_client_call__string (client, "get_substring", &error, 2, "string", "hello", "int", 2); cl_assert (error == NULL); cl_assert (strcmp(result, "he") == 0); g_free (result); /* error should return */ result = NULL; result = searpc_client_call__string (client, "get_substring", &error, 2, "string", "hello", "int", 10); cl_assert (error->message); g_free (result); g_error_free(error); } void test_searpc__invalid_call (void) { gchar* result; GError *error = NULL; result = searpc_client_call__string (client, "nonexist_func", &error, 2, "string", "hello", "int", 2); cl_assert (error != NULL); g_free (result); g_error_free (error); } GObject * get_maman_bar(const char *name, GError **error) { return g_object_new(MAMAN_TYPE_BAR, "name", name, NULL); } void test_searpc__object_call (void) { GObject *result; GError *error = NULL; result = searpc_client_call__object (client, "get_maman_bar", MAMAN_TYPE_BAR, &error, 1, "string", "kitty"); cl_assert (error == NULL); g_object_unref (result); } GList * get_maman_bar_list (const char *name, int num, GError **error) { char buf[256]; GList *ret = 0; int i; GObject *obj; if (num < 0) { g_set_error (error, DFT_DOMAIN, 100, "num must be positive."); return NULL; } if (num > 1000) { g_set_error (error, DFT_DOMAIN, 100, "num must no larger than 1000."); return NULL; } for (i = 0; i < num; i++) { sprintf (buf, "%s%d", name, i); obj = g_object_new(MAMAN_TYPE_BAR, "name", buf, NULL); ret = g_list_prepend (ret, obj); } ret = g_list_reverse (ret); return ret; } void test_searpc__objlist_call (void) { GList *result, *ptr; GError *error = NULL; result = searpc_client_call__objlist (client, "get_maman_bar_list", MAMAN_TYPE_BAR, &error, 2, "string", "kitty", "int", 10); cl_assert (error == NULL); for (ptr = result; ptr; ptr = ptr->next) g_object_unref (ptr->data); g_list_free (result); result = searpc_client_call__objlist (client, "get_maman_bar_list", MAMAN_TYPE_BAR, &error, 2, "string", "kitty", "int", 0); cl_assert (error == NULL); for (ptr = result; ptr; ptr = ptr->next) g_object_unref (ptr->data); g_list_free (result); } json_t * simple_json_rpc (const char *name, int num, GError **error) { json_t * ret = json_object(); json_object_set_new (ret, name, json_integer (num)); return ret; } void test_searpc__json_return_type (void) { json_t *result; GError *error = NULL; result = searpc_client_call__json (client, "simple_json_rpc", &error, 2, "string", "year", "int", 2016); cl_assert (error == NULL); cl_assert (json_integer_value(json_object_get(result, "year")) == 2016); json_decref(result); } json_t * count_json_kvs (const json_t *obj, GError **error) { int count = 0; json_t *member; member = json_object_iter ((json_t*)obj); while (member != NULL) { member = json_object_iter_next ((json_t*)obj, member); count++; } json_t * ret = json_object(); json_object_set_new (ret, "number_of_kvs", json_integer (count)); return ret; } void test_searpc__json_param_type (void) { json_t *result; GError *error = NULL; json_t *param = json_object(); json_object_set_new (param, "a", json_integer (1)); json_object_set_new (param, "b", json_integer (2)); result = searpc_client_call__json (client, "count_json_kvs", &error, 1, "json", param); cl_assert_ (error == NULL, error ? error->message : ""); int count = json_integer_value(json_object_get((json_t*)result, "number_of_kvs")); char *msg = json_dumps(result, JSON_INDENT(2)); cl_assert_(count == 2, msg); free (msg); json_decref(param); json_decref(result); } void simple_callback (void *result, void *user_data, GError *error) { char *res = (char *)result; cl_assert (strcmp(res, "he") == 0); } void simple_callback_error (void *result, void *user_data, GError *error) { cl_assert (result == NULL); cl_assert (error != NULL); g_error_free (error); } void test_searpc__simple_call_async (void) { searpc_client_async_call__string (client, "get_substring", simple_callback, NULL, 2, "string", "hello", "int", 2); searpc_client_async_call__string (client, "get_substring", simple_callback_error, NULL, 2, "string", "hello", "int", 10); } void async_callback_json (void *result, void *user_data, GError *error) { cl_assert(json_integer_value(json_object_get((json_t*)result, "hello")) == 10); } void test_searpc__simple_call_async_json (void) { searpc_client_async_call__json (client, "simple_json_rpc", async_callback_json, NULL, 2, "string", "hello", "int", 10); } void test_searpc__pipe_simple_call (void) { gchar* result; GError *error = NULL; result = searpc_client_call__string (client_with_pipe_transport, "get_substring", &error, 2, "string", "hello", "int", 2); cl_assert_ (error == NULL, error ? error->message : ""); cl_assert (strcmp(result, "he") == 0); g_free (result); /* error should return */ result = searpc_client_call__string (client_with_pipe_transport, "get_substring", &error, 2, "string", "hello", "int", 10); cl_assert (error->message); g_free (result); } void test_searpc__pipe_large_request (void) { gchar* result; GError *error = NULL; // 10MB int size = 10 * 1024 * 1024; GString *large_string = g_string_sized_new(size); while (large_string->len < size) { g_string_append(large_string, "aaaa"); } // Large request result = searpc_client_call__string (client_with_pipe_transport, "get_substring", &error, 2, "string", large_string->str, "int", 2); cl_assert_ (error == NULL, error ? error->message : ""); cl_assert_ (strcmp(result, "aa") == 0, result); g_free (result); // Large request & Large response result = searpc_client_call__string (client_with_pipe_transport, "get_substring", &error, 2, "string", large_string->str, "int", size - 2); cl_assert_ (error == NULL, error ? error->message : ""); // cl_assert (strcmp(result, "aa") == 0); g_free (result); g_string_free (large_string, TRUE); } static void * do_pipe_connect_and_request(void *arg) { SearpcClient *client = do_create_client_with_pipe_transport(); // 100KB int size = 100 * 1024; GString *large_string = g_string_sized_new(size); while (large_string->len < size) { g_string_append(large_string, "aaaa"); } gchar* result; GError *error = NULL; result = searpc_client_call__string (client, "get_substring", &error, 2, "string", large_string->str, "int", 2); cl_assert_ (error == NULL, error ? error->message : ""); cl_assert_ (strcmp(result, "aa") == 0, result); g_free (result); g_string_free (large_string, TRUE); searpc_free_client_with_pipe_transport(client); return NULL; } // Simulate the situation that the server can handle multiple clients connecting // at the same time. void test_searpc__pipe_concurrent_clients (void) { // M concurrent clients, and run the test for N times. int m_clients = 5; int n_times = 20; int i; for (i = 0; i < n_times; i++) { g_usleep(100000); pthread_t *threads = g_new0(pthread_t, m_clients); int j; for (j = 0; j < m_clients; j++) { pthread_create(&threads[j], NULL, do_pipe_connect_and_request, NULL); } void *ret; for (j = 0; j < m_clients; j++) { pthread_join(threads[j], &ret); } g_free (threads); } } #include "searpc-signature.h" #include "searpc-marshal.h" void test_searpc__initialize (void) { searpc_server_init (register_marshals); searpc_create_service ("test"); searpc_server_register_function ("test", get_substring, "get_substring", searpc_signature_string__string_int()); searpc_server_register_function ("test", get_maman_bar, "get_maman_bar", searpc_signature_object__string()); searpc_server_register_function ("test", get_maman_bar_list, "get_maman_bar_list", searpc_signature_objlist__string_int()); searpc_server_register_function ("test", simple_json_rpc, "simple_json_rpc", searpc_signature_json__string_int()); searpc_server_register_function ("test", count_json_kvs, "count_json_kvs", searpc_signature_json__json()); /* sample client */ client = searpc_client_new(); client->send = sample_send; client->arg = "test"; client->async_send = sample_async_send; client->async_arg = "test_async"; 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 Sleep(1000); #endif client_with_pipe_transport = do_create_client_with_pipe_transport(); } void test_searpc__cleanup (void) { searpc_free_client_with_pipe_transport(client_with_pipe_transport); /* free memory for memory debug with valgrind */ searpc_server_final(); }