diff options
Diffstat (limited to 'isi/client.c')
-rw-r--r-- | isi/client.c | 360 |
1 files changed, 0 insertions, 360 deletions
diff --git a/isi/client.c b/isi/client.c deleted file mode 100644 index f8f01711..00000000 --- a/isi/client.c +++ /dev/null @@ -1,360 +0,0 @@ -/* - * This file is part of oFono - Open Source Telephony - * - * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). - * - * Contact: Rémi Denis-Courmont <remi.denis-courmont@nokia.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * 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 St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#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 <errno.h> -#include <glib.h> - -#include "socket.h" -#include "client.h" - -struct isi_client { - uint8_t resource; - - /* Requests */ - int fd; - guint source; - uint8_t prev[256], next[256]; - guint timeout[256]; - isi_client_cb_t func[256]; - void *data[256]; - - /* Indications */ - struct { - int fd; - guint source; - uint16_t count; - isi_ind_cb_t func[256]; - void *data[256]; - } ind; -}; - -static gboolean isi_callback(GIOChannel *, GIOCondition, gpointer); -static gboolean isi_timeout(gpointer); - -static inline struct isi_request *isi_req(struct isi_client *cl, uint8_t id) -{ - return (struct isi_request *)(((uint8_t *)(void *)cl) + id); -} - -static inline uint8_t isi_id(void *ptr) -{ - return ((uintptr_t)ptr) & 255; -} - -static inline struct isi_client *isi_cl(void *ptr) -{ - return (struct isi_client *)(((uintptr_t)ptr) & ~255); -} - -/** - * Create an ISI client. - * @param resource Phonet resource ID for the client - * @return NULL on error (see errno), an isi_client pointer on success, - */ -struct isi_client *isi_client_create(uint8_t resource) -{ - void *ptr; - struct isi_client *cl; - GIOChannel *channel; - unsigned i; - - if (G_UNLIKELY(posix_memalign(&ptr, 256, sizeof(*cl)))) - abort(); - cl = ptr; - cl->resource = resource; - memset(cl->timeout, 0, sizeof(cl->timeout)); - for (i = 0; i < 256; i++) { - cl->data[i] = cl->ind.data[i] = NULL; - cl->func[i] = NULL; - cl->ind.func[i] = NULL; - } - cl->ind.count = 0; - - /* Reserve 0 as head of available IDs, and 255 as head of busy ones */ - cl->prev[0] = 254; - for (i = 0; i < 254; i++) { - cl->next[i] = i + 1; - cl->prev[i + 1] = i; - } - cl->next[254] = 0; - cl->prev[255] = cl->next[255] = 255; - - channel = phonet_new(resource); - if (channel == NULL) { - free(cl); - return NULL; - } - cl->fd = g_io_channel_unix_get_fd(channel); - cl->source = g_io_add_watch(channel, - G_IO_IN|G_IO_ERR|G_IO_HUP|G_IO_NVAL, - isi_callback, cl); - g_io_channel_unref(channel); - return cl; -} - -/** - * Destroys an ISI client, cancels all pending transactions and subscriptions. - * @param client client to destroy - */ -void isi_client_destroy(struct isi_client *client) -{ - unsigned id; - - g_source_remove(client->source); - for (id = 0; id < 256; id++) - if (client->timeout[id] > 0) - g_source_remove(client->timeout[id]); - if (client->ind.count > 0) - g_source_remove(client->ind.source); - free(client); -} - -/** - * Make an ISI request and register a callback to process the response(s) to - * the resulting transaction. - * @param cl ISI client (from isi_client_create()) - * @param buf pointer to request payload - * @param len request payload byte length - * @param cb callback to process response(s) - * @param opaque data for the callback - */ -struct isi_request *isi_request_make(struct isi_client *cl, - const void *__restrict buf, size_t len, - unsigned timeout, - isi_client_cb_t cb, void *opaque) -{ - struct iovec iov[2]; - ssize_t ret; - uint8_t id = cl->next[0]; - - if (id == 0) { - errno = EBUSY; - return NULL; - } - if (cb == NULL) { - errno = EINVAL; - return NULL; - } - iov[0].iov_base = &id; - iov[0].iov_len = 1; - iov[1].iov_base = (void *)buf; - iov[1].iov_len = len; - ret = writev(cl->fd, iov, sizeof(iov) / sizeof(iov[0])); - if (ret == -1) - return NULL; - if (ret != (ssize_t)(len + 2)) { - errno = EMSGSIZE; - return NULL; - } - - cl->func[id] = cb; - cl->data[id] = opaque; - - /* Remove transaction from available list */ - cl->next[0] = cl->next[id]; - cl->prev[cl->next[id]] = 0; - /* Insert into busy list */ - cl->next[id] = cl->next[255]; - cl->prev[cl->next[id]] = id; - cl->next[255] = id; - cl->prev[id] = 255; - - if (timeout > 0) - cl->timeout[id] = g_timeout_add_seconds(timeout, - isi_timeout, cl); - else - cl->timeout[id] = 0; - return isi_req(cl, id); -} - -/** - * Cancels a pending request, i.e. stop waiting for responses and cancels the - * timeout. - * @param req request to cancel - */ -void isi_request_cancel(struct isi_request *req) -{ - struct isi_client *cl = isi_cl(req); - uint8_t id = isi_id(req); - - cl->func[id] = NULL; - cl->data[id] = NULL; - - /* Remove transaction from pending circular list */ - cl->prev[cl->next[id]] = cl->prev[id]; - cl->next[cl->prev[id]] = cl->next[id]; - /* Insert transaction into available circular list */ - cl->prev[id] = cl->prev[0]; - cl->prev[0] = id; - cl->next[id] = 0; - cl->next[cl->prev[id]] = id; - - if (cl->timeout[id] > 0) { - g_source_remove(cl->timeout[id]); - cl->timeout[id] = 0; - } -} - -#define PN_COMMGR 0x10 -#define PNS_SUBSCRIBED_RESOURCES_IND 0x10 - -static int isi_indication_init(struct isi_client *cl) -{ - uint8_t msg[] = { - 0, PNS_SUBSCRIBED_RESOURCES_IND, 1, cl->resource, - }; - GIOChannel *channel = phonet_new(PN_COMMGR); - - if (channel == NULL) - return errno; - /* Send subscribe indication */ - cl->ind.fd = g_io_channel_unix_get_fd(channel); - send(cl->ind.fd, msg, 4, 0); - cl->ind.source = g_io_add_watch(channel, - G_IO_IN|G_IO_ERR|G_IO_HUP|G_IO_NVAL, - isi_callback, cl); - return 0; -} - -static void isi_indication_deinit(struct isi_client *client) -{ - uint8_t msg[] = { - 0, PNS_SUBSCRIBED_RESOURCES_IND, 0, - }; - - /* Send empty subscribe indication */ - send(client->ind.fd, msg, 3, 0); - g_source_remove(client->ind.source); -} - -/** - * Subscribe to a given indication type for the resource that an ISI client - * is associated with. If the same type was already subscrived, the old - * subscription is overriden. - * @param cl ISI client (fomr isi_client_create()) - * @param type indication type - * @param cb callback to process received indications - * @param data data for the callback - * @return 0 on success, a system error code otherwise. - */ -int isi_subscribe(struct isi_client *cl, uint8_t type, - isi_ind_cb_t cb, void *data) -{ - if (cb == NULL) - return EINVAL; - - if (cl->ind.func[type] == NULL) { - if (cl->ind.count == 0) { - int ret = isi_indication_init(cl); - if (ret) - return ret; - } - cl->ind.count++; - } - cl->ind.func[type] = cb; - cl->ind.data[type] = data; - return 0; -} - -/** - * Unsubscribe from a given indication type. - * @param client ISI client (from isi_client_create()) - * @param type indication type. - */ -void isi_unsubscribe(struct isi_client *client, uint8_t type) -{ - /* Unsubscribe */ - if (client->ind.func[type] == NULL) - return; - client->ind.func[type] = NULL; - if (--client->ind.count == 0) - isi_indication_deinit(client); -} - -/* Data callback for both responses and indications */ -static gboolean isi_callback(GIOChannel *channel, GIOCondition cond, - gpointer data) -{ - struct isi_client *cl = data; - int fd = g_io_channel_unix_get_fd(channel); - bool indication = (fd != cl->fd); - int len; - - if (cond & (G_IO_NVAL|G_IO_HUP)) { - g_warning("Unexpected event on Phonet channel %p", channel); - return FALSE; - } - - len = phonet_peek_length(channel); - { - uint32_t buf[(len + 3) / 4]; - uint16_t obj; - uint8_t res, id; - - len = phonet_read(channel, buf, len, &obj, &res); - if (len < 2 || res != cl->resource) - return TRUE; - memcpy(&id, buf, 1); /* Transaction ID or indication type */ - if (indication) { - if (cl->ind.func[id] == NULL) - return TRUE; /* Unsubscribed indication */ - cl->ind.func[id](cl, buf + 1, len - 1, obj, - cl->ind.data[id]); - } else { - if (cl->func[id] == NULL) - return TRUE; /* Bad transaction ID */ - if ((cl->func[id])(cl, buf + 1, len - 1, obj, - cl->data[id])) - isi_request_cancel(isi_req(cl, id)); - } - } - return TRUE; -} - -static gboolean isi_timeout(gpointer data) -{ - struct isi_request *req = data; - struct isi_client *cl = isi_cl(req); - uint8_t id = isi_id(req); - - assert(cl->func[id]); - (cl->func[id])(cl, NULL, 0, 0, cl->data[id]); - isi_request_cancel(req); - return FALSE; -} - -int isi_client_error(const struct isi_client *client) -{ /* The only possible error at the moment */ - return ETIMEDOUT; -} |