diff options
author | Aki Niemi <aki.niemi@nokia.com> | 2010-11-14 18:26:42 +0200 |
---|---|---|
committer | Aki Niemi <aki.niemi@nokia.com> | 2010-12-22 17:13:46 +0200 |
commit | ee2a8bbc694103c1e63f148974f5424037ba5397 (patch) | |
tree | ffb55593dd4e9092e1c853058f99f6c8aa649d6f | |
parent | 325e555092762577864e2772af3f49931dbfc3f9 (diff) | |
download | ofono-ee2a8bbc694103c1e63f148974f5424037ba5397.tar.bz2 |
gisi: Refactor the server API
The new server API is a convenience wrapper on the modem API for
servers.
-rw-r--r-- | gisi/server.c | 349 | ||||
-rw-r--r-- | gisi/server.h | 38 |
2 files changed, 103 insertions, 284 deletions
diff --git a/gisi/server.c b/gisi/server.c index 3d96e2d9..45c523d8 100644 --- a/gisi/server.c +++ b/gisi/server.c @@ -26,320 +26,153 @@ #include <stdint.h> #include <string.h> #include <stdlib.h> -#include <assert.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <sys/uio.h> -#include <sys/ioctl.h> #include <errno.h> -#include "phonet.h" #include <glib.h> +#include "phonet.h" -#include "socket.h" #include "server.h" -#define PN_NAMESERVICE 0xDB -#define PNS_NAME_ADD_REQ 0x05 - -struct _GIsiIncoming { - struct sockaddr_pn spn; - uint8_t trans_id; +struct pending_data { + GIsiServer *server; + GIsiNotifyFunc notify; + void *data; }; struct _GIsiServer { GIsiModem *modem; + GIsiVersion version; uint8_t resource; - struct { - int major; - int minor; - } version; - - /* Callbacks */ - int fd; - guint source; - GIsiRequestFunc func[256]; - void *data[256]; - - /* Debugging */ - GIsiDebugFunc debug_func; - void *debug_data; + GSList *pending; }; -static gboolean g_isi_server_callback(GIOChannel *channel, GIOCondition cond, - gpointer data); - -/** - * Create an ISI server. - * @param resource PhoNet resource ID for the server - * @return NULL on error (see errno), a GIsiServer pointer on success, - */ -GIsiServer *g_isi_server_create(GIsiModem *modem, uint8_t resource, - uint8_t major, uint8_t minor) +static void pending_notify(const GIsiMessage *msg, void *data) { - void *ptr; - GIsiServer *self; - GIOChannel *channel; - - if (G_UNLIKELY(posix_memalign(&ptr, 256, sizeof(*self)))) - abort(); - - self = ptr; - memset(self, 0, sizeof(*self)); - self->resource = resource; - self->version.major = major; - self->version.minor = minor; - self->modem = modem; - self->debug_func = NULL; - - channel = phonet_new(modem, resource); - if (channel == NULL) { - free(self); - return NULL; - } + struct pending_data *pd = data; - self->fd = g_io_channel_unix_get_fd(channel); - self->source = g_io_add_watch(channel, - G_IO_IN|G_IO_ERR|G_IO_HUP|G_IO_NVAL, - g_isi_server_callback, self); - g_io_channel_unref(channel); - return self; -} - -/** - * Returns the resource associated with @a server - * @param server server for the resource - * @return PhoNet resource ID for the server - */ -uint8_t g_isi_server_resource(GIsiServer *server) -{ - return server->resource; -} - -/** - * Set a debugging function for @a server. This function will be - * called whenever an ISI protocol message is sent or received. - * @param server server to debug - * @param func debug function - * @param opaque user data - */ -void g_isi_server_set_debug(GIsiServer *server, GIsiDebugFunc func, - void *opaque) -{ - if (server == NULL) - return; - - server->debug_func = func; - server->debug_data = opaque; -} - -/** - * Destroys an ISI server, cancels all pending transactions and subscriptions. - * @param server server to destroy - */ -void g_isi_server_destroy(GIsiServer *server) -{ - if (server == NULL) + if (!pd) return; - g_source_remove(server->source); - free(server); + if (pd->notify) + pd->notify(msg, pd->data); } -/** - * Request the server name from the name server. - */ -void -g_isi_server_add_name(GIsiServer *self) +uint8_t g_isi_server_resource(GIsiServer *server) { - uint16_t object = 0; - - if (self == NULL) - return; - - if (ioctl(self->fd, SIOCPNGETOBJECT, &object) < 0) { - g_warning("%s: %s", "ioctl(SIOCPNGETOBJECT)", strerror(errno)); - } else { - struct sockaddr_pn spn = { - .spn_family = PF_PHONET, - .spn_dev = 0, /* PN_DEV_HOST */ - .spn_resource = PN_NAMESERVICE, - }; - uint8_t req[] = { - 0, PNS_NAME_ADD_REQ, 0, 0, - 0, 0, 0, self->resource, /* name */ - object >> 8, object & 0xff, /* device/object */ - 0, 0, - }; - - if (sendto(self->fd, req, sizeof(req), 0, - (void *)&spn, sizeof(spn)) != sizeof(req)) { - g_warning("%s: %s", "sendto(PN_NAMESERVICE)", - strerror(errno)); - } - } + return server ? server->resource : 0; } -/** - * Make an ISI request and register a callback to process the response(s) to - * the resulting transaction. - * @param self ISI server (from g_isi_server_create()) - * @param buf pointer to request payload - * @param len request payload byte length - * @param irq information from incoming request - */ -int g_isi_respond(GIsiServer *self, const void *data, size_t len, - GIsiIncoming *irq) +GIsiModem *g_isi_server_modem(GIsiServer *server) { - const struct iovec iov = { - .iov_base = (void *)data, - .iov_len = len, - }; - - if (self->debug_func) - self->debug_func(data, len, self->debug_data); - - return g_isi_vrespond(self, &iov, 1, irq); + return server ? server->modem : 0; } -/** - * Make an ISI request and register a callback to process the response(s) to - * the resulting transaction. - * @param self ISI server (from g_isi_server_create()) - * @param iov scatter-gather array to the request payload - * @param iovlen number of vectors in the scatter-gather array - * @param irq information from incoming request - */ -int g_isi_vrespond(GIsiServer *self, const struct iovec *iov, size_t iovlen, - GIsiIncoming *irq) +GIsiServer *g_isi_server_create(GIsiModem *modem, uint8_t resource, + GIsiVersion *version) { - struct iovec _iov[1 + iovlen]; - const struct msghdr msg = { - .msg_name = (void *)&irq->spn, - .msg_namelen = sizeof(irq->spn), - .msg_iov = (struct iovec *)_iov, - .msg_iovlen = 1 + iovlen, - .msg_control = NULL, - .msg_controllen = 0, - .msg_flags = 0, - }; - ssize_t ret; - size_t i, len; - - if (self == NULL) { - errno = EINVAL; - return -1; - } + GIsiServer *server; - if (irq == NULL) { + if (!modem) { errno = EINVAL; - return -1; + return NULL; } - _iov[0].iov_base = &irq->trans_id; - _iov[0].iov_len = 1; - for (i = 0, len = 1; i < iovlen; i++) { - _iov[1 + i] = iov[i]; - len += iov[i].iov_len; + server = g_try_new0(GIsiServer, 1); + if (!server) { + errno = ENOMEM; + return NULL; } - ret = sendmsg(self->fd, &msg, MSG_NOSIGNAL); + if (version) + memcpy(&server->version, version, sizeof(GIsiVersion)); - g_free(irq); + server->resource = resource; + server->modem = modem; + server->pending = NULL; - return ret; + return server; } -/** - * Prepare to handle given request type for the resource that an ISI server - * is associated with. If the same type was already handled, the old - * handler is overriden. - * @param self ISI server (from g_isi_server_create()) - * @param type request message type - * @param cb callback to process received requests - * @param data data for the callback - * @return 0 on success, -1 upon an error. - */ -int g_isi_server_handle(GIsiServer *self, uint8_t type, - GIsiRequestFunc cb, void *data) +static void foreach_destroy(gpointer value, gpointer user) { - if (self == NULL || cb == NULL) { - errno = EINVAL; - return -1; - } + GIsiPending *op = value; + GIsiServer *server = user; - self->func[type] = cb; - self->data[type] = data; - return 0; -} + if (!op || !server) + return; -/** - * Remove handler from a given request type. - * @param server ISI server (from g_isi_server_create()) - * @param type indication type. - */ -void g_isi_server_unhandle(GIsiServer *self, uint8_t type) -{ - if (self) - self->func[type] = NULL; + server->pending = g_slist_remove(server->pending, op); + g_isi_pending_remove(op); } - -static void generic_error_response(GIsiServer *self, - uint8_t trans_id, uint8_t error, uint8_t message_id, - void *addr, socklen_t addrlen) +void g_isi_server_destroy(GIsiServer *server) { - uint8_t common[] = { trans_id, 0xF0, error, message_id }; + if (!server) + return; - sendto(self->fd, common, sizeof(common), MSG_NOSIGNAL, addr, addrlen); + g_slist_foreach(server->pending, foreach_destroy, server); + g_slist_free(server->pending); + g_free(server); } -static void process_message(GIsiServer *self, int len) +int g_isi_server_send(GIsiServer *server, const GIsiMessage *req, + const void *__restrict buf, size_t len) { - uint8_t msg[len + 1]; - struct sockaddr_pn addr; - socklen_t addrlen = sizeof(addr); - uint8_t message_id; - GIsiRequestFunc func; - void *data; + if (!server) + return -EINVAL; - len = recvfrom(self->fd, msg, sizeof(msg), MSG_DONTWAIT, - (void *)&addr, &addrlen); + return g_isi_response_send(server->modem, req, buf, len); +} - if (len < 2 || addr.spn_resource != self->resource) - return; +int g_isi_server_vsend(GIsiServer *server, const GIsiMessage *req, + const struct iovec *iov, size_t iovlen) +{ + if (!server) + return -EINVAL; - if (self->debug_func) - self->debug_func(msg + 1, len - 1, self->debug_data); + return g_isi_response_vsend(server->modem, req, iov, iovlen); +} - message_id = msg[1]; - func = self->func[message_id]; - data = self->data[message_id]; +static struct pending_data *pending_data_create(GIsiServer *server, + GIsiNotifyFunc notify, + void *data) +{ + struct pending_data *pd; - if (func) { - GIsiIncoming *irq = g_new0(GIsiIncoming, 1); + if (!server) { + errno = EINVAL; + return NULL; + } - if (irq) { - irq->spn = addr; - irq->trans_id = msg[0]; - func(self, msg + 1, len - 1, irq, data); - return; - } + pd = g_try_new0(struct pending_data, 1); + if (!pd) { + errno = ENOMEM; + return NULL; } - /* Respond with COMMON MESSAGE COMM_SERVICE_NOT_AUTHENTICATED_RESP */ - generic_error_response(self, msg[0], 0x17, msg[1], &addr, addrlen); + pd->server = server; + pd->notify = notify; + pd->data = data; + + return pd; } -/* Data callback */ -static gboolean g_isi_server_callback(GIOChannel *channel, GIOCondition cond, - gpointer opaque) +GIsiPending *g_isi_server_handle(GIsiServer *server, uint8_t type, + GIsiNotifyFunc notify, void *data) { - if (cond & (G_IO_NVAL|G_IO_HUP)) { - g_warning("Unexpected event on Phonet channel %p", channel); - return FALSE; - } + struct pending_data *pd; + GIsiPending *op; - process_message(opaque, phonet_peek_length(channel)); + pd = pending_data_create(server, notify, data); + if (!pd) + return NULL; + + op = g_isi_service_bind(server->modem, server->resource, type, + pending_notify, pd, g_free); + if (!op) { + g_free(pd); + return NULL; + } - return TRUE; + server->pending = g_slist_append(server->pending, op); + return op; } diff --git a/gisi/server.h b/gisi/server.h index f22214f3..8f3ac659 100644 --- a/gisi/server.h +++ b/gisi/server.h @@ -27,42 +27,28 @@ extern "C" { #endif #include <stdint.h> -#include <gisi/modem.h> +#include <sys/uio.h> + +#include "message.h" +#include "modem.h" struct _GIsiServer; typedef struct _GIsiServer GIsiServer; -struct _GIsiIncoming; -typedef struct _GIsiIncoming GIsiIncoming; - -typedef gboolean (*GIsiRequestFunc)(GIsiServer *server, - const void *restrict data, size_t len, - GIsiIncoming *, void *opaque); - GIsiServer *g_isi_server_create(GIsiModem *modem, uint8_t resource, - uint8_t major, uint8_t minor); - + GIsiVersion *version); uint8_t g_isi_server_resource(GIsiServer *server); - -void g_isi_server_set_debug(GIsiServer *server, GIsiDebugFunc func, - void *opaque); - +GIsiModem *g_isi_server_modem(GIsiServer *server); void g_isi_server_destroy(GIsiServer *server); -void g_isi_server_add_name(GIsiServer *self); - -int g_isi_respond(GIsiServer *server, const void *data, size_t len, - GIsiIncoming *irq); - -struct iovec; - -int g_isi_vrespond(GIsiServer *server, const struct iovec *iov, - size_t iovlen, GIsiIncoming *irq); +int g_isi_server_send(GIsiServer *server, const GIsiMessage *req, + const void *__restrict data, size_t len); -int g_isi_server_handle(GIsiServer *server, uint8_t type, - GIsiRequestFunc func, void *opaque); +int g_isi_server_vsend(GIsiServer *server, const GIsiMessage *req, + const struct iovec *iov, size_t iovlen); -void g_isi_server_unhandle(GIsiServer *server, uint8_t type); +GIsiPending *g_isi_server_handle(GIsiServer *server, uint8_t type, + GIsiNotifyFunc notify, void *data); #ifdef __cplusplus } |