diff options
Diffstat (limited to 'gisi')
-rw-r--r-- | gisi/Makefile.am | 10 | ||||
-rw-r--r-- | gisi/client.c | 360 | ||||
-rw-r--r-- | gisi/client.h | 69 | ||||
-rw-r--r-- | gisi/netlink.c | 197 | ||||
-rw-r--r-- | gisi/netlink.h | 47 | ||||
-rw-r--r-- | gisi/socket.c | 93 | ||||
-rw-r--r-- | gisi/socket.h | 27 |
7 files changed, 803 insertions, 0 deletions
diff --git a/gisi/Makefile.am b/gisi/Makefile.am new file mode 100644 index 00000000..10b325c8 --- /dev/null +++ b/gisi/Makefile.am @@ -0,0 +1,10 @@ +AM_CFLAGS = @GLIB_CFLAGS@ + +noinst_LTLIBRARIES = libgisi.la +MAINTAINERCLEANFILES = Makefile.in + +libgisi_la_SOURCES = \ + netlink.h netlink.c \ + socket.h socket.c \ + client.h client.c +libgisi_la_LIBADD = @GLIB_LIBS@ diff --git a/gisi/client.c b/gisi/client.c new file mode 100644 index 00000000..24b89ecd --- /dev/null +++ b/gisi/client.c @@ -0,0 +1,360 @@ +/* + * 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 _GIsiClient { + uint8_t resource; + + /* Requests */ + int fd; + guint source; + uint8_t prev[256], next[256]; + guint timeout[256]; + GIsiResponseFunc func[256]; + void *data[256]; + + /* Indications */ + struct { + int fd; + guint source; + uint16_t count; + GIsiIndicationFunc func[256]; + void *data[256]; + } ind; +}; + +static gboolean g_isi_callback(GIOChannel *channel, GIOCondition cond, + gpointer data); +static gboolean g_isi_timeout(gpointer data); + +static inline GIsiRequest *g_isi_req(GIsiClient *cl, uint8_t id) +{ + return (GIsiRequest *)(((uint8_t *)(void *)cl) + id); +} + +static inline uint8_t g_isi_id(void *ptr) +{ + return ((uintptr_t)ptr) & 255; +} + +static inline GIsiClient *g_isi_cl(void *ptr) +{ + return (GIsiClient *)(((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, + */ +GIsiClient *g_isi_client_create(uint8_t resource) +{ + void *ptr; + GIsiClient *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, + g_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 g_isi_client_destroy(GIsiClient *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 g_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 + */ +GIsiRequest *g_isi_request_make(GIsiClient *cl, const void *__restrict buf, + size_t len, unsigned timeout, + GIsiResponseFunc 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, + g_isi_timeout, cl); + else + cl->timeout[id] = 0; + return g_isi_req(cl, id); +} + +/** + * Cancels a pending request, i.e. stop waiting for responses and cancels the + * timeout. + * @param req request to cancel + */ +void g_isi_request_cancel(GIsiRequest *req) +{ + GIsiClient *cl = g_isi_cl(req); + uint8_t id = g_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 g_isi_indication_init(GIsiClient *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, + g_isi_callback, cl); + return 0; +} + +static void g_isi_indication_deinit(GIsiClient *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 g_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 g_isi_subscribe(GIsiClient *cl, uint8_t type, + GIsiIndicationFunc cb, void *data) +{ + if (cb == NULL) + return EINVAL; + + if (cl->ind.func[type] == NULL) { + if (cl->ind.count == 0) { + int ret = g_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 g_isi_client_create()) + * @param type indication type. + */ +void g_isi_unsubscribe(GIsiClient *client, uint8_t type) +{ + /* Unsubscribe */ + if (client->ind.func[type] == NULL) + return; + client->ind.func[type] = NULL; + if (--client->ind.count == 0) + g_isi_indication_deinit(client); +} + +/* Data callback for both responses and indications */ +static gboolean g_isi_callback(GIOChannel *channel, GIOCondition cond, + gpointer data) +{ + GIsiClient *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])) + g_isi_request_cancel(g_isi_req(cl, id)); + } + } + return TRUE; +} + +static gboolean g_isi_timeout(gpointer data) +{ + GIsiRequest *req = data; + GIsiClient *cl = g_isi_cl(req); + uint8_t id = g_isi_id(req); + + assert(cl->func[id]); + (cl->func[id])(cl, NULL, 0, 0, cl->data[id]); + g_isi_request_cancel(req); + return FALSE; +} + +int g_isi_client_error(const GIsiClient *client) +{ /* The only possible error at the moment */ + return ETIMEDOUT; +} diff --git a/gisi/client.h b/gisi/client.h new file mode 100644 index 00000000..b8cde37f --- /dev/null +++ b/gisi/client.h @@ -0,0 +1,69 @@ +/* + * 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 + * + */ + +#ifndef __GISI_CLIENT_H +#define __GISI_CLIENT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <stdint.h> +#include <stdbool.h> + +struct _GIsiClient; +typedef struct _GIsiClient GIsiClient; + +struct _GIsiRequest; +typedef struct _GIsiRequest GIsiRequest; + +typedef bool (*GIsiResponseFunc)(GIsiClient *client, + const void *restrict data, size_t len, + uint16_t object, void *opaque); + +typedef void (*GIsiIndicationFunc) (GIsiClient *client, + const void *restrict data, size_t len, + uint16_t object, void *opaque); + +GIsiClient *g_isi_client_create(uint8_t resource); + +void g_isi_client_destroy(GIsiClient *client); + +int g_isi_client_error(const GIsiClient *client); + +GIsiRequest *g_isi_request_make(GIsiClient *client, const void *data, + size_t len, unsigned timeout, + GIsiResponseFunc func, void *opaque); + +void g_isi_request_cancel(GIsiRequest *req); + +int g_isi_subscribe(GIsiClient *client, uint8_t type, + GIsiIndicationFunc func, void *opaque); + +void g_isi_unsubscribe(GIsiClient *client, uint8_t type); + +#ifdef __cplusplus +} +#endif + +#endif /* __GISI_CLIENT_H */ diff --git a/gisi/netlink.c b/gisi/netlink.c new file mode 100644 index 00000000..efe1109e --- /dev/null +++ b/gisi/netlink.c @@ -0,0 +1,197 @@ +/* + * 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 <stdbool.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <unistd.h> +#include <fcntl.h> +#include <sys/socket.h> +#ifndef SOL_NETLINK +#define SOL_NETLINK 270 /* libc!? */ +#endif +#ifndef AF_PHONET +#define AF_PHONET 35 +#endif +#include <linux/rtnetlink.h> +#include <linux/phonet.h> +#include <glib.h> + +#include "netlink.h" + +struct _GPhonetNetlink { + GPhonetNetlinkFunc callback; + void *opaque; + guint watch; +}; + +/* Parser Netlink messages */ +static gboolean g_pn_nl_process(GIOChannel *channel, GIOCondition cond, + gpointer data) +{ + struct { + struct nlmsghdr nlh; + struct rtmsg rtm; + char buf[1024]; + } req; + struct iovec iov = { &req, sizeof(req), }; + struct msghdr msg = { .msg_iov = &iov, .msg_iovlen = 1, }; + ssize_t ret; + struct nlmsghdr *nlh; + int fd = g_io_channel_unix_get_fd(channel); + GPhonetNetlink *self = data; + + if (cond & (G_IO_NVAL|G_IO_HUP)) + return FALSE; + + ret = recvmsg(fd, &msg, 0); + if (ret == -1 || (msg.msg_flags & MSG_TRUNC)) + return TRUE; + + for (nlh = (struct nlmsghdr *)&req; NLMSG_OK(nlh, (size_t)ret); + nlh = NLMSG_NEXT(nlh, ret)) { + const struct ifaddrmsg *ifa; + const struct rtattr *rta; + int len; + bool up; + uint8_t addr = 0; + + if (nlh->nlmsg_type == NLMSG_DONE) + break; + switch (nlh->nlmsg_type) { + case NLMSG_ERROR: { + const struct nlmsgerr *err; + err = (struct nlmsgerr *)NLMSG_DATA(nlh); + g_critical("Netlink error: %s", strerror(-err->error)); + return FALSE; + } + case RTM_NEWADDR: + up = true; + break; + case RTM_DELADDR: + up = false; + break; + default: + continue; + } + /* We have a route message */ + ifa = NLMSG_DATA(nlh); + len = RTM_PAYLOAD(nlh); + + /* If Phonet is absent, kernel transmits other families... */ + if (ifa->ifa_family != AF_PHONET) + continue; + for (rta = IFA_RTA(ifa); RTA_OK(rta, len); + rta = RTA_NEXT(rta, len)) + if (rta->rta_type == IFA_LOCAL) + memcpy(&addr, RTA_DATA(rta), 1); + self->callback(up, addr, ifa->ifa_index, self->opaque); + } + return TRUE; +} + +/* Dump current Phonet address table */ +static int g_pn_netlink_query(int fd) +{ + struct { + struct nlmsghdr nlh; + struct rtmsg rtm; + } req; + struct sockaddr_nl addr = { .nl_family = AF_NETLINK, }; + + req.nlh.nlmsg_type = RTM_GETADDR; + req.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(req.rtm)); + req.nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT; + req.nlh.nlmsg_seq = 0; + req.nlh.nlmsg_pid = getpid(); + + req.rtm.rtm_family = AF_PHONET; + req.rtm.rtm_dst_len = 6; + req.rtm.rtm_src_len = 0; + req.rtm.rtm_tos = 0; + + req.rtm.rtm_table = RT_TABLE_MAIN; + req.rtm.rtm_protocol = RTPROT_STATIC; + req.rtm.rtm_scope = RT_SCOPE_UNIVERSE; + req.rtm.rtm_type = RTN_UNICAST; + req.rtm.rtm_flags = 0; + + if (sendto(fd, &req, req.nlh.nlmsg_len, 0, + (struct sockaddr *)&addr, sizeof(addr)) == -1) + return -1; + return 0; +} + +GPhonetNetlink *g_pn_netlink_start(GPhonetNetlinkFunc cb, void *opaque) +{ + GIOChannel *chan; + GPhonetNetlink *self; + unsigned group = RTNLGRP_PHONET_IFADDR; + int fd; + + self = malloc(sizeof(*self)); + if (self == NULL) + return NULL; + + fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE); + if (fd == -1) + goto error; + + fcntl(fd, F_SETFL, O_NONBLOCK | fcntl(fd, F_GETFL)); + if (setsockopt(fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, + &group, sizeof(group))) + goto error; + g_pn_netlink_query(fd); + + chan = g_io_channel_unix_new(fd); + if (chan == NULL) + goto error; + g_io_channel_set_close_on_unref(chan, TRUE); + g_io_channel_set_encoding(chan, NULL, NULL); + g_io_channel_set_buffered(chan, FALSE); + + self->callback = cb; + self->opaque = opaque; + self->watch = g_io_add_watch(chan, G_IO_IN|G_IO_ERR|G_IO_HUP, + g_pn_nl_process, self); + g_io_channel_unref(chan); + return 0; + +error: + if (fd != -1) + close(fd); + free(self); + return NULL; +} + +void g_pn_netlink_stop(GPhonetNetlink *self) +{ + g_source_remove(self->watch); + g_free(self); +} diff --git a/gisi/netlink.h b/gisi/netlink.h new file mode 100644 index 00000000..8ea0607a --- /dev/null +++ b/gisi/netlink.h @@ -0,0 +1,47 @@ +/* + * 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 + * + */ + +#include <stdbool.h> +#include <stdint.h> + +#ifndef __GPHONET_NETLINK_H +#define __GPHONET_NETLINK_H + +#ifdef __cplusplus +extern "C" { +#endif + +struct _GPhonetNetlink; +typedef struct _GPhonetNetlink GPhonetNetlink; + +typedef void (*GPhonetNetlinkFunc)(bool up, uint8_t addr, unsigned idx, + void *data); + +GPhonetNetlink *g_pn_netlink_start(GPhonetNetlinkFunc func, void *data); +void g_pn_netlink_stop(GPhonetNetlink *self); + +#ifdef __cplusplus +} +#endif + +#endif /* __GPHONET_NETLINK_H */ diff --git a/gisi/socket.c b/gisi/socket.c new file mode 100644 index 00000000..6f72120e --- /dev/null +++ b/gisi/socket.c @@ -0,0 +1,93 @@ +/* + * 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 <sys/types.h> +#include <sys/socket.h> +#include <sys/ioctl.h> +#include <unistd.h> +#include <fcntl.h> +#include <linux/types.h> +#include <linux/phonet.h> +#include <glib.h> + +#ifndef AF_PHONET +#define AF_PHONET 35 +#define PF_PHONET AF_PHONET +#endif +#include "socket.h" + +GIOChannel *phonet_new(uint8_t resource) +{ + GIOChannel *channel; + struct sockaddr_pn addr = { + .spn_family = AF_PHONET, + .spn_resource = resource, + }; + + int fd = socket(PF_PHONET, SOCK_DGRAM, 0); + if (fd == -1) + return NULL; + fcntl(fd, F_SETFD, FD_CLOEXEC); + /* Use blocking mode on purpose. */ + if (bind(fd, (struct sockaddr *)&addr, sizeof(addr))) { + close(fd); + return NULL; + } + + channel = g_io_channel_unix_new(fd); + g_io_channel_set_close_on_unref(channel, TRUE); + g_io_channel_set_encoding(channel, NULL, NULL); + g_io_channel_set_buffered(channel, FALSE); + return channel; +} + +size_t phonet_peek_length(GIOChannel *channel) +{ + int len; + int fd = g_io_channel_unix_get_fd(channel); + return ioctl(fd, FIONREAD, &len) ? 0 : len; +} + +ssize_t phonet_read(GIOChannel *channel, void *restrict buf, size_t len, + uint16_t *restrict obj, uint8_t *restrict res) +{ + struct sockaddr_pn addr; + socklen_t addrlen = sizeof(addr); + ssize_t ret; + + ret = recvfrom(g_io_channel_unix_get_fd(channel), buf, len, + MSG_DONTWAIT, (struct sockaddr *)&addr, &addrlen); + if (ret == -1) + return -1; + + if (obj != NULL) + *obj = pn_sockaddr_get_object(&addr); + if (res != NULL) + *res = addr.spn_resource; + return ret; +} diff --git a/gisi/socket.h b/gisi/socket.h new file mode 100644 index 00000000..b95a4d78 --- /dev/null +++ b/gisi/socket.h @@ -0,0 +1,27 @@ +/* + * 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 + * + */ + +GIOChannel *phonet_new(uint8_t resource); +size_t phonet_peek_length(GIOChannel *io); +ssize_t phonet_read(GIOChannel *io, void *restrict buf, size_t len, + uint16_t *restrict obj, uint8_t *restrict res); |