Skip to content

GSoC:2007 Service Clients Design

Erik Massop edited this page Nov 4, 2017 · 1 revision

Data Structures

Server side

The service object keeps a registry of available services on the server. The registry structure is as following:

    Registry                   Entry          +---------------+      +--------------------+ | key1 | entry1------->| name               | | key2 | entry2 |      | description        | | key3 | entry3 |      | major version      | |  .   |   .    |      | minor version      | |  .   |   .    |      | methods            | |  .   |   .    |      |--------------------|            Method +---------------+      | service client fd  |      +----------------+                        | +----------------+ |      | name           |                        | | key1 | method1 | |      | description    |                        | | key2 | method2--------->| return types   |                        | | key3 | method3 | |      | arg types      |                        | |  .   |    .    | |      |----------------|                        | |  .   |    .    | |      | cookie         |                        | |  .   |    .    | |      +----------------+                        | +----------------+ |                        +--------------------+

The key in Registry is calculated using each service's interface name (e.g. "se.xmms.sc.lastfm"). And the key in Entry which corresponds to each method is calculated using method's name (e.g. "fetch").

Normal updates that don't change the method signatures are reflected by "minor version", otherwise "major version" should be changed. For example, there is a service called "lastfm" which provides a method "fetch" with two string type arguments, and this is marked as major version 1. If later on, the author decides that method "fetch" needs an additional int type argument, then the major version number should be changed to a number other than 1. This scheme is used for clients to decide whether they can correctly use a method or not.

"service client fd" is the IPC fd created for a service client when it initially connects to the server. It is used to uniquely identify a service client. Along with "cookie" in Method structure, IPC can uniquely locate a method in a service client.

"cookie" field in Method structure is the message cookie which the service client uses to register the method, and subsequently subscribes the callback function to the the broadcast using the result returned. It helps IPC to locate which service client to send messages to, and also makes sure that the correct service methods are being invoked on service client when the messages arrive.

"return types" and "arg types" fields store the information about types of the variables being returned from and passed to the method, respectively. Each argument stores the name of the argument, the type and optionality information of the argument. If an argument is optional, it is not necessary to provide this argument when a client is trying to call the method.

So this two level hierarchical structure groups all the methods a service provides together. Thus easier for locating and categorizing.

Client side

typedef struct xmmsc_service_method_St xmmsc_service_method_t; typedef void (*xmmsc_service_notifier_t) (xmmsc_connection_t *conn, xmmsc_result_t *res,               xmmsc_service_method_t *method, void *user_data);

The reason that there is no xmmsc_service_t structure is because that it is not needed for any other operations than service registration. The only thing that will be used in subsequent function calls after service registration is service ID. On the other hand, xmmsc_service_method_t structure is quite necessary. It is used in a lot of places like method registration, calling a method, returning from a method, etc. Besides the normal information of a method, it also contains error messages if there is any during a service client related function call. You do not need to free this structure manually, it will be freed automatically when it is no longer needed.

All service method callbacks should be of type xmmsc_service_notifier_t.

Functions

Server side

Functions below are separated into four groups.

Public functions:

xmms_service_t *xmms_service_init (void); gboolean xmms_service_handle (xmms_object_t *obj, xmms_ipc_msg_t *msg, uint32_t cmdid,                               xmms_socket_t client, xmms_object_cmd_arg_t *arg);

xmms_service_init() is the initialization function of service object. All it does is to create the first level registry structure and initialize an empty registry. Then simply registers XMMS_IPC_SIGNAL_SERVICE broadcast to IPC core.

Different from other server-side objects, service object has a central entry point, namely xmms_service_handle(). All service related calls will end up here in the first place. The reason of having it is because that service related calls sometimes involve not only one action like subscribing to a signal or execute a command, but also some manipulations on the registry. Besides, service calls may have more than 6 arguments, which exceeds current IPC limit. So it has to take care of arguments parsing by itself. Once the entry function is called, it will delegate the task to the corresponding worker functions. And then decides whether or not it should subscribe the calling client to XMMS_IPC_SIGNAL_SERVICE broadcast.

Registry creation/deletion:

static xmms_service_entry_t *xmms_service_entry_new (xmms_service_t *obj,                                                      gchar *name,                                                      gchar *description,                                                      guint major, guint minor,                                                      xmms_socket_t client); static xmms_service_method_t *xmms_service_method_new (xmms_service_t *obj,                                                        gchar *service,                                                        gchar *name,                                                        gchar *description,                                                        guint cookie,                                                        GHashTable *rets,                                                        GHashTable *args); static void xmms_service_destroy (xmms_object_t *object); static void xmms_service_registry_destroy (gpointer value); static void xmms_service_request_client_destroy (gpointer value); static void xmms_service_method_destroy (gpointer value);

Registry management:

static void xmms_service_register (xmms_service_t *service,                                    xmms_ipc_msg_t *msg, xmms_socket_t client,                                    xmms_error_t *err); static gboolean xmms_service_method_register (xmms_service_t *xmms_service,                                               xmms_ipc_msg_t *msg,                                               xmms_socket_t client,                                               xmms_error_t *err); static void xmms_service_unregister (xmms_service_t *xmms_service,                                      xmms_ipc_msg_t *msg,                                      xmms_socket_t client,                                      xmms_error_t *err); static gboolean xmms_service_method_unregister (xmms_service_t *xmms_service,                                                 xmms_ipc_msg_t *msg,                                                 xmms_service_entry_t *entry,                                                 xmms_error_t *err); static void xmms_service_list (xmms_service_t *xmms_service,                                xmms_object_cmd_arg_t *arg); static void xmms_service_info_list (xmms_service_t *xmms_service,                                     xmms_ipc_msg_t *msg,                                     xmms_object_cmd_arg_t *arg); static void xmms_service_method_list (xmms_service_t *xmms_service,                                       xmms_ipc_msg_t *msg,                                       xmms_object_cmd_arg_t *arg); static void xmms_service_method_info_list (xmms_service_t *xmms_service,                                            xmms_ipc_msg_t *msg,                                            xmms_object_cmd_arg_t *arg); static gboolean xmms_service_request (xmms_service_t *xmms_service,                                       xmms_ipc_msg_t *msg,                                       xmms_socket_t client,                                       xmms_error_t *err); static void xmms_service_return (xmms_service_t *xmms_service,                                  xmms_ipc_msg_t *msg,                                  xmms_socket_t client,                                  xmms_error_t *err); static void xmms_service_shutdown (xmms_service_t *xmms_service,                                    xmms_ipc_msg_t *msg, xmms_error_t *err);

Helper functions:

static xmms_service_entry_t * xmms_service_is_registered (xmms_service_t *xmms_service, const gchar *name); static xmms_service_method_t * xmms_service_method_is_registered (xmms_service_entry_t *entry,                                    const gchar *name); static gboolean xmms_service_matchsc (gpointer key, gpointer value,                                       gpointer data); static gboolean xmms_service_method_request_matchfd (gpointer key,                                                      gpointer value,                                                      gpointer data); static gboolean xmms_service_method_request_matchmethod (gpointer key,                                                          gpointer value,                                                          gpointer data); static void xmms_service_key_insert (gpointer key, gpointer value,                                      gpointer data); static inline guint xmms_service_next_id (void); static xmms_service_entry_t *xmms_service_get (xmms_service_t *xmms_service,                                                xmms_ipc_msg_t *msg, gchar **name,                                                xmms_error_t *err); static xmms_service_method_t * xmms_service_method_get (xmms_ipc_msg_t *msg, xmms_service_entry_t *entry,                          gchar **name, xmms_error_t *err); static GHashTable *xmms_service_arg_types_parse (xmms_ipc_msg_t *msg,                                                  xmms_error_t *err); static GHashTable *xmms_service_args_parse (xmms_ipc_msg_t *msg,                                             GHashTable *args, xmms_error_t *err); static gboolean xmms_service_args_is_error (xmms_ipc_msg_t *msg); static gboolean xmms_service_args_error_parse (xmms_ipc_msg_t *msg,                                                gchar **error, xmms_error_t *err); static GHashTable * xmms_service_changed_msg_new (gchar *service, gchar *method,                               xmms_service_changed_actions_t type);

Client side

The following functions interacts with the server. Due to the reason that nested dictionaries are not supported by IPC, method describing functions are seperated into two. xmmsc_service_method_describe() gives the details of a method other than its argument information. And xmmsc_service_method_describe_args() gives the rest. When using xmmsc_service_shutdown() to request a service client to shutdown, it is not guaranteed that the service client will do exactly as asked, since the service client may not listening to XMMS_IPC_SIGNAL_SERVICE_SHUTDOWN broadcast or event if it does it may decide to ignore it. So for service clients installed on the same machine as the server does, it is recommended that you make this request through service client manager. Details on the manager are discussed here.

xmmsc_service_register (xmmsc_connection_t *conn, const char *name, const char *description, uint32_t major, uint32_t minor); xmmsc_service_method_register (xmmsc_connection_t *conn, const char *service, xmmsc_service_method_t *method); xmmsc_service_unregister (xmmsc_connection_t *conn, const char *service, xmmsc_service_method_t *method); xmmsc_service_list (xmmsc_connection_t *conn); xmmsc_service_describe (xmmsc_connection_t *conn, const char *service); xmmsc_service_method_list (xmmsc_connection_t *conn, const char *service); xmmsc_service_method_describe (xmmsc_connection_t *conn, const char *service, const char *method); xmmsc_service_request (xmmsc_connection_t *conn, const char *service, xmmsc_service_method_t *method); xmmsc_service_return (xmmsc_connection_t *conn, xmmsc_result_t *res, xmmsc_service_method_t *method); xmmsc_service_shutdown (xmmsc_connection_t *conn, const char *service);

Broadcasts.

xmmsc_broadcast_service_changed (xmmsc_connection_t *c); xmmsc_broadcast_service_method_changed (xmmsc_connection_t *c); xmmsc_broadcast_service_shutdown (xmmsc_connection_t *c);

Helper functions, which do not interacts with the server. Most of the helper functions deal with arguments and return types. After you have created xmmsc_service_method_t structure, you can tell what names and types of arguments or return types the method will use by pushing the types into the structure. The two functions that perform this operation are xmmsc_service_method_arg_type_add() and xmmsc_service_method_ret_type_add(). All those xmmsc_service_method_arg/ret_add_#() functions are used by clients to add different types of values to the arguments or return arguments.

xmmsc_service_method_new (const char *name, const char *description, xmmsc_service_notifier_t func, void *user_data); xmmsc_service_method_new_full (const char *name, const char *description, xmmsc_service_notifier_t func, void *user_data, xmmsc_user_data_free_func_t free_func); void xmmsc_service_method_ref (xmmsc_service_method_t *method); void xmmsc_service_method_unref (xmmsc_service_method_t *method); xmmsc_service_method_attribute_get (xmmsc_service_method_t *method, char **name, char **description); xmmsc_service_method_arg_type_add (xmmsc_service_method_t *method, const char *name, xmmsc_service_arg_type_t type, int32_t optional); xmmsc_service_method_ret_type_add (xmmsc_service_method_t *method, const char *name, xmmsc_service_arg_type_t type, int32_t optional); xmmsc_service_method_arg_add_uint32 (xmmsc_service_method_t *method, const char *name, uint32_t value); xmmsc_service_method_arg_add_int32 (xmmsc_service_method_t *method, const char *name, int32_t value); xmmsc_service_method_arg_add_string (xmmsc_service_method_t *method, const char *name, char *value); xmmsc_service_method_arg_add_stringlist (xmmsc_service_method_t *method, const char *name, char **value); xmmsc_service_method_arg_add_coll (xmmsc_service_method_t *method, const char *name, xmmsc_coll_t *value); xmmsc_service_method_arg_add_bin (xmmsc_service_method_t *method, const char *name, unsigned char *value, uint32_t len); xmmsc_service_method_ret_add_uint32 (xmmsc_service_method_t *method, const char *name, uint32_t value); xmmsc_service_method_ret_add_int32 (xmmsc_service_method_t *method, const char *name, int32_t value); xmmsc_service_method_ret_add_string (xmmsc_service_method_t *method, const char *name, char *value); xmmsc_service_method_ret_add_stringlist (xmmsc_service_method_t *method, const char *name, char **value); xmmsc_service_method_ret_add_coll (xmmsc_service_method_t *method, const char *name, xmmsc_coll_t *value); xmmsc_service_method_ret_add_bin (xmmsc_service_method_t *method, const char *name, unsigned char *value, uint32_t len); xmmsc_service_method_arg_size (xmmsc_service_method_t *method, uint32_t *size); xmmsc_service_method_ret_size (xmmsc_service_method_t *method, uint32_t *size); xmmsc_service_method_arg_attribute_get (xmmsc_service_method_t *method, const char *name, xmmsc_service_arg_type_t *type, uint32_t *optional, uint32_t *none); xmmsc_service_method_ret_attribute_get (xmmsc_service_method_t *method, const char *name, xmmsc_service_arg_type_t *type, uint32_t *optional, uint32_t *none); xmmsc_service_method_arg_remove (xmmsc_service_method_t *method, const char *name); xmmsc_service_method_ret_remove (xmmsc_service_method_t *method, const char *name); xmmsc_service_method_error_get (xmmsc_service_method_t *method); xmmsc_service_method_error_set (xmmsc_service_method_t *method, const char *err); xmmsc_service_method_error_reset (xmmsc_service_method_t *method); xmmsc_service_method_error_isset (xmmsc_service_method_t *method);

This function helps developers extract service client related information from result_t.

xmmsc_result_get_service_method (xmmsc_result_t *res, xmmsc_service_method_t **method);

Go back to Service Client Summary.

Clone this wiki locally