1
0
mirror of https://github.com/haiwen/libsearpc.git synced 2025-04-28 02:30:08 +00:00
libsearpc/lib/searpc-server.c

453 lines
11 KiB
C
Raw Normal View History

2011-04-08 12:58:15 +00:00
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
2013-08-08 08:24:20 +00:00
#include <jansson.h>
2011-04-08 12:58:15 +00:00
#include "searpc-server.h"
#include "searpc-utils.h"
2018-12-21 10:29:58 +00:00
#ifdef __linux__
#include <sys/time.h>
#include <sys/errno.h>
#include <pthread.h>
#endif
2011-04-08 12:58:15 +00:00
struct FuncItem;
typedef struct MarshalItem {
SearpcMarshalFunc mfunc;
2011-11-13 06:09:58 +00:00
gchar *signature;
2011-04-08 12:58:15 +00:00
} MarshalItem;
typedef struct FuncItem {
void *func;
2011-11-13 06:09:58 +00:00
gchar *fname;
2011-04-08 12:58:15 +00:00
MarshalItem *marshal;
} FuncItem;
typedef struct {
char *name;
GHashTable *func_table;
} SearpcService;
static GHashTable *marshal_table;
static GHashTable *service_table;
2011-11-13 06:09:58 +00:00
2018-12-21 10:29:58 +00:00
#ifdef __linux__
static FILE *slow_log_fp = NULL;
static gint64 slow_threshold;
static GList *filtered_funcs;
2018-12-21 10:29:58 +00:00
static pthread_mutex_t slow_log_lock;
static gboolean log_to_stdout = FALSE;
2018-12-21 10:29:58 +00:00
#endif
2011-11-13 06:09:58 +00:00
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);
}
2011-04-08 12:58:15 +00:00
void
searpc_remove_service (const char *svc_name)
{
if (!svc_name)
return;
g_hash_table_remove (service_table, svc_name);
}
2011-04-08 12:58:15 +00:00
/* Marshal functions */
2012-06-20 12:24:49 +00:00
void
2013-08-08 08:24:20 +00:00
searpc_set_string_to_ret_object (json_t *object, char *ret)
2011-04-08 12:58:15 +00:00
{
if (ret == NULL)
2013-08-08 08:24:20 +00:00
json_object_set_new (object, "ret", json_null ());
2011-04-08 12:58:15 +00:00
else {
2013-08-08 08:24:20 +00:00
json_object_set_new (object, "ret", json_string (ret));
2011-04-08 12:58:15 +00:00
g_free (ret);
}
}
2012-06-20 12:24:49 +00:00
void
2013-08-08 08:24:20 +00:00
searpc_set_int_to_ret_object (json_t *object, json_int_t ret)
2011-04-08 12:58:15 +00:00
{
2013-08-08 08:24:20 +00:00
json_object_set_new (object, "ret", json_integer (ret));
2011-04-08 12:58:15 +00:00
}
2012-06-20 12:24:49 +00:00
void
2013-08-08 08:24:20 +00:00
searpc_set_object_to_ret_object (json_t *object, GObject *ret)
2011-04-08 12:58:15 +00:00
{
if (ret == NULL)
2013-08-08 08:24:20 +00:00
json_object_set_new (object, "ret", json_null ());
2011-04-08 12:58:15 +00:00
else {
2013-08-08 08:24:20 +00:00
json_object_set_new (object, "ret", json_gobject_serialize (ret));
2011-04-08 12:58:15 +00:00
g_object_unref (ret);
}
}
2012-06-20 12:24:49 +00:00
void
2013-08-08 08:24:20 +00:00
searpc_set_objlist_to_ret_object (json_t *object, GList *ret)
2011-04-08 12:58:15 +00:00
{
GList *ptr;
if (ret == NULL)
2013-08-08 08:24:20 +00:00
json_object_set_new (object, "ret", json_null ());
2011-04-08 12:58:15 +00:00
else {
2013-08-08 08:24:20 +00:00
json_t *array = json_array ();
2011-04-08 12:58:15 +00:00
for (ptr = ret; ptr; ptr = ptr->next)
2013-08-08 08:24:20 +00:00
json_array_append_new (array, json_gobject_serialize (ptr->data));
json_object_set_new (object, "ret", array);
2011-04-08 12:58:15 +00:00
for (ptr = ret; ptr; ptr = ptr->next)
g_object_unref (ptr->data);
g_list_free (ret);
}
}
2016-06-28 02:46:17 +00:00
void
searpc_set_json_to_ret_object (json_t *object, json_t *ret)
{
2019-09-10 02:48:10 +00:00
if (ret == NULL)
json_object_set_new(object, "ret", json_null ());
else
json_object_set_new (object, "ret", ret);
2016-06-28 02:46:17 +00:00
}
2013-08-08 08:24:20 +00:00
char *
2013-08-09 06:24:12 +00:00
searpc_marshal_set_ret_common (json_t *object, gsize *len, GError *error)
2011-04-08 12:58:15 +00:00
{
2013-08-08 08:24:20 +00:00
char *data;
2011-04-08 12:58:15 +00:00
if (error) {
2013-08-08 08:24:20 +00:00
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));
2011-04-08 12:58:15 +00:00
g_error_free (error);
}
2013-08-08 08:24:20 +00:00
data=json_dumps(object,JSON_COMPACT);
*len=strlen(data);
json_decref(object);
2011-04-08 12:58:15 +00:00
return data;
}
2013-08-08 08:24:20 +00:00
char *
2013-08-09 06:30:18 +00:00
error_to_json (int code, const char *msg, gsize *len)
2012-06-03 16:19:16 +00:00
{
2013-08-08 08:24:20 +00:00
json_t *object = json_object ();
char *data;
2012-06-03 16:19:16 +00:00
2013-08-08 08:24:20 +00:00
json_object_set_new (object, "err_code", json_integer((json_int_t)code));
json_object_set_string_or_null_member(object, "err_msg", msg);
2012-06-03 16:19:16 +00:00
2013-08-08 08:24:20 +00:00
data=json_dumps(object,JSON_COMPACT);
*len=strlen(data);
json_decref(object);
2012-06-03 16:19:16 +00:00
return data;
}
2011-04-08 12:58:15 +00:00
void
2012-06-20 12:24:49 +00:00
searpc_server_init (RegisterMarshalFunc register_func)
2011-04-08 12:58:15 +00:00
{
2011-11-13 06:09:58 +00:00
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);
2011-04-08 12:58:15 +00:00
2012-06-20 12:24:49 +00:00
register_func ();
2011-04-08 12:58:15 +00:00
}
2018-12-21 10:29:58 +00:00
#ifdef __linux__
int
searpc_server_init_with_slow_log (RegisterMarshalFunc register_func,
const char *slow_log_path,
gint64 slow_threshold_in,
GList *filtered_funcs_in)
2018-12-21 10:29:58 +00:00
{
const char *log_to_stdout_env = g_getenv("SEAFILE_LOG_TO_STDOUT");
if (g_strcmp0(log_to_stdout_env, "true") == 0) {
slow_log_fp = stdout;
log_to_stdout = TRUE;
} else if (slow_log_path) {
2018-12-21 10:29:58 +00:00
slow_log_fp = fopen (slow_log_path, "a+");
if (!slow_log_fp) {
g_warning ("Failed to open RPC slow log file %s: %s\n", slow_log_path, strerror(errno));
return -1;
}
}
slow_threshold = slow_threshold_in;
filtered_funcs = filtered_funcs_in;
pthread_mutex_init (&slow_log_lock, NULL);
2018-12-21 10:29:58 +00:00
searpc_server_init (register_func);
return 0;
}
int
searpc_server_reopen_slow_log (const char *slow_log_path)
{
FILE *fp, *oldfp;
if (log_to_stdout) {
return 0;
}
2018-12-21 10:29:58 +00:00
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
2011-11-13 06:09:58 +00:00
void
2023-04-08 23:53:07 +00:00
searpc_server_final(void)
2011-11-13 06:09:58 +00:00
{
g_hash_table_destroy (service_table);
2011-11-13 06:09:58 +00:00
g_hash_table_destroy (marshal_table);
}
2011-04-08 12:58:15 +00:00
gboolean
2011-11-13 06:09:58 +00:00
searpc_server_register_marshal (gchar *signature, SearpcMarshalFunc marshal)
2011-04-08 12:58:15 +00:00
{
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");
2011-11-13 06:09:58 +00:00
g_free (signature);
2011-04-08 12:58:15 +00:00
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)
2011-04-08 12:58:15 +00:00
{
SearpcService *service;
2011-04-08 12:58:15 +00:00
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;
2011-04-08 12:58:15 +00:00
mitem = g_hash_table_lookup (marshal_table, signature);
2011-11-13 06:09:58 +00:00
if (!mitem) {
g_free (signature);
2011-04-08 12:58:15 +00:00
return FALSE;
2011-11-13 06:09:58 +00:00
}
2011-04-08 12:58:15 +00:00
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);
2011-04-08 12:58:15 +00:00
2011-11-13 06:09:58 +00:00
g_free (signature);
2011-04-08 12:58:15 +00:00
return TRUE;
}
2018-12-21 10:29:58 +00:00
#ifdef __linux__
static gboolean
rpc_include_passwd (const char *fname) {
GList *ptr;
char *rpc_name;
for (ptr = filtered_funcs; ptr; ptr = ptr->next) {
rpc_name = ptr->data;
if (g_strcmp0 (fname, rpc_name) == 0) {
return TRUE;
}
}
return FALSE;
}
2018-12-21 10:29:58 +00:00
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];
2018-12-25 02:44:41 +00:00
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;
2018-12-21 10:29:58 +00:00
2021-10-08 08:29:52 +00:00
strftime(time_buf, 64, "%Y/%m/%d %H:%M:%S", localtime(&start->tv_sec));
2018-12-21 10:29:58 +00:00
pthread_mutex_lock (&slow_log_lock);
if (log_to_stdout) {
fprintf (slow_log_fp, "[seafile-slow-rpc] ");
}
fprintf (slow_log_fp, "[%s] \"%s\" %.*s %.3f\n",
2018-12-25 02:44:41 +00:00
time_buf, svc_name, (int)len, func, intv_in_sec);
2018-12-21 10:29:58 +00:00
fflush (slow_log_fp);
pthread_mutex_unlock (&slow_log_lock);
}
#endif
2011-04-08 12:58:15 +00:00
/* Called by RPC transport. */
2013-08-08 08:24:20 +00:00
char*
searpc_server_call_function (const char *svc_name,
2012-06-03 16:19:16 +00:00
gchar *func, gsize len, gsize *ret_len)
2011-04-08 12:58:15 +00:00
{
SearpcService *service;
2013-08-08 08:24:20 +00:00
json_t *array;
char* ret;
json_error_t jerror;
2012-06-03 16:19:16 +00:00
GError *error = NULL;
2013-08-08 08:24:20 +00:00
2018-12-21 10:29:58 +00:00
#ifdef __linux__
struct timeval start, end, intv;
2018-12-21 10:29:58 +00:00
if (slow_log_fp) {
gettimeofday(&start, NULL);
}
#endif
service = g_hash_table_lookup (service_table, svc_name);
if (!service) {
2012-06-03 16:19:16 +00:00
char buf[256];
snprintf (buf, 255, "cannot find service %s.", svc_name);
return error_to_json (501, buf, ret_len);
}
2011-04-08 12:58:15 +00:00
2013-08-08 08:24:20 +00:00
array = json_loadb (func, len, 0 ,&jerror);
if (!array) {
2012-06-03 16:19:16 +00:00
char buf[512];
2014-08-14 15:48:58 +00:00
setjetoge(&jerror,&error);
2013-08-08 08:24:20 +00:00
snprintf (buf, 511, "failed to load RPC call: %s\n", error->message);
json_decref (array);
2014-08-14 15:48:58 +00:00
g_error_free(error);
2012-06-03 16:19:16 +00:00
return error_to_json (511, buf, ret_len);
2011-04-08 12:58:15 +00:00
}
2013-08-08 08:24:20 +00:00
const char *fname = json_string_value (json_array_get(array, 0));
FuncItem *fitem = g_hash_table_lookup(service->func_table, fname);
2011-04-08 12:58:15 +00:00
if (!fitem) {
2012-06-03 16:19:16 +00:00
char buf[256];
snprintf (buf, 255, "cannot find function %s.", fname);
2013-08-08 08:24:20 +00:00
json_decref (array);
2012-06-03 16:19:16 +00:00
return error_to_json (500, buf, ret_len);
2011-04-08 12:58:15 +00:00
}
2012-06-03 16:19:16 +00:00
ret = fitem->marshal->mfunc (fitem->func, array, ret_len);
2011-04-08 12:58:15 +00:00
2018-12-21 10:29:58 +00:00
#ifdef __linux__
if (slow_log_fp) {
if (!filtered_funcs || !rpc_include_passwd (fitem->fname)) {
gettimeofday(&end, NULL);
timersub(&end, &start, &intv);
print_slow_log_if_necessary (svc_name, func, len, &start, &intv);
}
2018-12-21 10:29:58 +00:00
}
#endif
2013-08-08 08:24:20 +00:00
json_decref(array);
2011-04-08 12:58:15 +00:00
return ret;
}
char*
2018-06-21 02:49:32 +00:00
searpc_compute_signature(const gchar *ret_type, int pnum, ...)
2011-04-08 12:58:15 +00:00
{
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<pnum; i++) {
char *ptype = va_arg (ap, char *);
g_checksum_update (cksum, (const guchar*)":", -1);
g_checksum_update (cksum, (const guchar*)ptype, -1);
}
va_end(ap);
ret = g_strdup (g_checksum_get_string (cksum));
g_checksum_free (cksum);
return ret;
}