330 lines
7.8 KiB
C
330 lines
7.8 KiB
C
/*
|
|
* test-rpc-common.c - Common RPC test code
|
|
*
|
|
* nspluginwrapper (C) 2005-2009 Gwenole Beauchesne
|
|
*
|
|
* 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 program 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. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*/
|
|
|
|
#include "sysdeps.h"
|
|
#include "test-rpc-common.h"
|
|
#include <signal.h>
|
|
|
|
#define DEBUG 1
|
|
#include "debug.h"
|
|
|
|
#ifdef BUILD_WRAPPER
|
|
#define BUILD_CLIENT 1
|
|
#endif
|
|
|
|
#ifdef BUILD_VIEWER
|
|
#define BUILD_SERVER 1
|
|
#endif
|
|
|
|
typedef struct _RPCTest RPCTest;
|
|
struct _RPCTest
|
|
{
|
|
RPCTestFuncs funcs;
|
|
gpointer user_data;
|
|
};
|
|
|
|
static RPCTest g_test;
|
|
static rpc_connection_t *g_connection;
|
|
static const gchar *g_connection_path;
|
|
static GMainLoop *g_main_loop;
|
|
#ifdef BUILD_CLIENT
|
|
static GPid g_child_pid;
|
|
static guint g_child_watch_id;
|
|
#endif
|
|
static gint g_exit_status;
|
|
|
|
void
|
|
rpc_test_set_funcs (const RPCTestFuncs *funcs, gpointer user_data)
|
|
{
|
|
g_test.user_data = user_data;
|
|
if (funcs && funcs->pre_dispatch_hook)
|
|
g_test.funcs.pre_dispatch_hook = funcs->pre_dispatch_hook;
|
|
if (funcs && funcs->post_dispatch_hook)
|
|
g_test.funcs.post_dispatch_hook = funcs->post_dispatch_hook;
|
|
}
|
|
|
|
rpc_connection_t *
|
|
rpc_test_get_connection (void)
|
|
{
|
|
return g_connection;
|
|
}
|
|
|
|
#ifdef BUILD_CLIENT
|
|
static void
|
|
child_exited_cb (GPid pid, gint status, gpointer user_data)
|
|
{
|
|
g_print ("child_exited_cb(), pid %d, status %d\n", pid, status);
|
|
if (status)
|
|
g_exit_status = status;
|
|
g_main_loop_quit (g_main_loop);
|
|
if (g_child_watch_id)
|
|
g_source_remove (g_child_watch_id);
|
|
g_spawn_close_pid (pid);
|
|
}
|
|
|
|
static void
|
|
kill_child_now (void)
|
|
{
|
|
if (g_child_watch_id)
|
|
g_source_remove (g_child_watch_id);
|
|
if (g_child_pid)
|
|
{
|
|
g_spawn_close_pid (g_child_pid);
|
|
kill (g_child_pid, SIGTERM);
|
|
}
|
|
}
|
|
|
|
static void
|
|
urgent_exit_sig (int sig)
|
|
{
|
|
kill_child_now ();
|
|
}
|
|
#endif
|
|
|
|
static gboolean
|
|
rpc_event_prepare (GSource *source, gint *timeout)
|
|
{
|
|
*timeout = -1;
|
|
return FALSE;
|
|
}
|
|
|
|
static gboolean
|
|
rpc_event_check (GSource *source)
|
|
{
|
|
return rpc_wait_dispatch (g_connection, 0) > 0;
|
|
}
|
|
|
|
static gboolean
|
|
rpc_event_dispatch (GSource *source, GSourceFunc callback, gpointer user_data)
|
|
{
|
|
gint rc;
|
|
|
|
if (g_test.funcs.pre_dispatch_hook)
|
|
{
|
|
if (!g_test.funcs.pre_dispatch_hook (g_test.user_data))
|
|
return TRUE;
|
|
}
|
|
|
|
rc = rpc_dispatch (g_connection);
|
|
|
|
if (g_test.funcs.post_dispatch_hook)
|
|
g_test.funcs.post_dispatch_hook (g_test.user_data);
|
|
|
|
return rc != RPC_ERROR_CONNECTION_CLOSED;
|
|
}
|
|
|
|
typedef gboolean (*GSourcePrepare) (GSource *, gint *);
|
|
typedef gboolean (*GSourceCheckFunc) (GSource *);
|
|
typedef gboolean (*GSourceDispatchFunc) (GSource *, GSourceFunc, gpointer);
|
|
typedef void (*GSourceFinalizeFunc) (GSource *);
|
|
|
|
static GSourceFuncs rpc_event_funcs =
|
|
{
|
|
rpc_event_prepare,
|
|
rpc_event_check,
|
|
rpc_event_dispatch,
|
|
(GSourceFinalizeFunc)g_free,
|
|
(GSourceFunc)NULL,
|
|
(GSourceDummyMarshal)NULL
|
|
};
|
|
|
|
static gboolean
|
|
rpc_test_execute_cb (gpointer user_data)
|
|
{
|
|
int rc = RPC_TEST_EXECUTE_SUCCESS;
|
|
|
|
if (rpc_test_execute)
|
|
rc = rpc_test_execute (g_test.user_data);
|
|
RPC_TEST_ENSURE ((rc & ~RPC_TEST_EXECUTE_DONT_QUIT) == RPC_TEST_EXECUTE_SUCCESS);
|
|
|
|
#ifdef BUILD_CLIENT
|
|
if ((rc & RPC_TEST_EXECUTE_DONT_QUIT) == 0)
|
|
rpc_test_exit_full (0);
|
|
#endif
|
|
return FALSE;
|
|
}
|
|
|
|
static gchar **
|
|
clone_args (gchar **args)
|
|
{
|
|
gchar **new_args;
|
|
#ifdef BUILD_CLIENT
|
|
gint i, n = 0;
|
|
#endif
|
|
|
|
if ((new_args = g_strdupv (args)) == NULL)
|
|
g_error ("could not duplicate the program arguments");
|
|
|
|
#ifdef BUILD_CLIENT
|
|
n = g_strv_length (new_args);
|
|
/* first arg was path to server program, skip it */
|
|
RPC_TEST_ENSURE (n >= 2);
|
|
g_free (new_args[1]);
|
|
for (i = 1; i < n - 1; i++)
|
|
new_args[i] = new_args[i + 1];
|
|
new_args[i] = NULL;
|
|
#endif
|
|
|
|
return new_args;
|
|
}
|
|
|
|
static void
|
|
rpc_test_init_invoke (gchar **program_args)
|
|
{
|
|
gchar **args = NULL;
|
|
gint n, rc = 0;
|
|
|
|
if ((args = clone_args (program_args)) == NULL)
|
|
g_error ("could not clone program arguments");
|
|
n = g_strv_length (args);
|
|
|
|
if (rpc_test_init)
|
|
rc = rpc_test_init (n, args);
|
|
g_strfreev (args);
|
|
RPC_TEST_ENSURE (rc == 0);
|
|
|
|
g_timeout_add (0, rpc_test_execute_cb, NULL);
|
|
}
|
|
|
|
void
|
|
rpc_test_exit (int status)
|
|
{
|
|
if (status)
|
|
g_exit_status = status;
|
|
g_main_loop_quit (g_main_loop);
|
|
}
|
|
|
|
void
|
|
rpc_test_exit_full (int status)
|
|
{
|
|
#ifdef BUILD_CLIENT
|
|
/* Tell server to quit, don't expect any reply from him */
|
|
rpc_method_invoke (g_connection,
|
|
RPC_TEST_METHOD_EXIT,
|
|
RPC_TYPE_INT32, status,
|
|
RPC_TYPE_INVALID);
|
|
#endif
|
|
|
|
rpc_test_exit (status);
|
|
}
|
|
|
|
static int
|
|
handle_rpc_test_exit (rpc_connection_t *connection)
|
|
{
|
|
int error;
|
|
gint32 status;
|
|
|
|
error = rpc_method_get_args (connection,
|
|
RPC_TYPE_INT32, &status,
|
|
RPC_TYPE_INVALID);
|
|
|
|
if (error == RPC_ERROR_NO_ERROR)
|
|
rpc_test_exit (status);
|
|
|
|
return error;
|
|
}
|
|
|
|
int
|
|
main (int argc, char *argv[])
|
|
{
|
|
if (rpc_test_get_connection_path)
|
|
g_connection_path = rpc_test_get_connection_path ();
|
|
else
|
|
g_connection_path = NPW_CONNECTION_PATH "/Test.RPC";
|
|
|
|
#ifdef BUILD_CLIENT
|
|
gchar **child_args;
|
|
|
|
if (argc < 2)
|
|
g_error ("no server program provided on command line");
|
|
|
|
signal (SIGSEGV, urgent_exit_sig);
|
|
signal (SIGBUS, urgent_exit_sig);
|
|
signal (SIGINT, urgent_exit_sig);
|
|
signal (SIGABRT, urgent_exit_sig);
|
|
|
|
if ((child_args = clone_args (argv)) == NULL)
|
|
g_error ("could not create server program arguments\n");
|
|
g_free (child_args[0]);
|
|
child_args[0] = g_strdup (argv[1]);
|
|
|
|
if (!g_spawn_async (NULL,
|
|
child_args,
|
|
NULL,
|
|
G_SPAWN_DO_NOT_REAP_CHILD,
|
|
NULL,
|
|
NULL,
|
|
&g_child_pid,
|
|
NULL))
|
|
g_error ("could not start server program '%s'", child_args[0]);
|
|
|
|
g_strfreev (child_args);
|
|
|
|
if ((g_connection = rpc_init_client (g_connection_path)) == NULL)
|
|
g_error ("failed to initialize RPC client connection");
|
|
#endif
|
|
|
|
#ifdef BUILD_SERVER
|
|
if ((g_connection = rpc_init_server (g_connection_path)) == NULL)
|
|
g_error ("failed to initialize RPC server connection");
|
|
#endif
|
|
|
|
int fd = -1;
|
|
GSource *rpc_source = NULL;
|
|
guint rpc_source_id = 0;
|
|
GPollFD rpc_event_poll_fd;
|
|
|
|
#ifdef BUILD_CLIENT
|
|
fd = rpc_socket (g_connection);
|
|
#endif
|
|
#ifdef BUILD_SERVER
|
|
fd = rpc_listen_socket (g_connection);
|
|
#endif
|
|
RPC_TEST_ENSURE (fd >= 0);
|
|
|
|
if ((rpc_source = g_source_new (&rpc_event_funcs, sizeof (GSource))) == NULL)
|
|
g_error ("failed to initialize RPC source");
|
|
|
|
rpc_source_id = g_source_attach (rpc_source, NULL);
|
|
memset (&rpc_event_poll_fd, 0, sizeof (rpc_event_poll_fd));
|
|
rpc_event_poll_fd.fd = fd;
|
|
rpc_event_poll_fd.events = G_IO_IN;
|
|
rpc_event_poll_fd.revents = 0;
|
|
g_source_add_poll (rpc_source, &rpc_event_poll_fd);
|
|
|
|
static const rpc_method_descriptor_t vtable[] = {
|
|
{ RPC_TEST_METHOD_EXIT, handle_rpc_test_exit }
|
|
};
|
|
if (rpc_connection_add_method_descriptor (g_connection, &vtable[0]) < 0)
|
|
g_error ("could not add method descriptor for TEST_RPC_METHOD_EXIT");
|
|
|
|
g_main_loop = g_main_loop_new (NULL, TRUE);
|
|
#ifdef BUILD_CLIENT
|
|
g_child_watch_id = g_child_watch_add (g_child_pid, child_exited_cb, NULL);
|
|
#endif
|
|
rpc_test_init_invoke (argv);
|
|
g_main_loop_run (g_main_loop);
|
|
if (rpc_source_id)
|
|
g_source_remove (rpc_source_id);
|
|
if (g_connection)
|
|
rpc_exit (g_connection);
|
|
return g_exit_status;
|
|
}
|