2009-06-09 13:26:36 +00:00
|
|
|
/*
|
|
|
|
* 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>
|
2009-07-03 15:32:31 +00:00
|
|
|
#include "phonet.h"
|
2009-06-09 13:26:36 +00:00
|
|
|
#include <glib.h>
|
|
|
|
|
|
|
|
#include "socket.h"
|
|
|
|
#include "client.h"
|
|
|
|
|
2009-06-15 08:17:30 +00:00
|
|
|
struct _GIsiClient {
|
2009-06-09 13:26:36 +00:00
|
|
|
uint8_t resource;
|
2009-09-15 12:35:47 +00:00
|
|
|
struct {
|
|
|
|
int major;
|
|
|
|
int minor;
|
|
|
|
} version;
|
2009-08-23 20:19:03 +00:00
|
|
|
GIsiModem *modem;
|
2009-06-09 13:26:36 +00:00
|
|
|
|
|
|
|
/* Requests */
|
|
|
|
int fd;
|
|
|
|
guint source;
|
|
|
|
uint8_t prev[256], next[256];
|
|
|
|
guint timeout[256];
|
2009-06-15 08:17:30 +00:00
|
|
|
GIsiResponseFunc func[256];
|
2009-06-09 13:26:36 +00:00
|
|
|
void *data[256];
|
|
|
|
|
|
|
|
/* Indications */
|
|
|
|
struct {
|
|
|
|
int fd;
|
|
|
|
guint source;
|
|
|
|
uint16_t count;
|
2009-06-15 08:17:30 +00:00
|
|
|
GIsiIndicationFunc func[256];
|
2009-06-09 13:26:36 +00:00
|
|
|
void *data[256];
|
|
|
|
} ind;
|
2009-08-22 15:01:24 +00:00
|
|
|
|
|
|
|
/* Debugging */
|
|
|
|
GIsiDebugFunc debug_func;
|
|
|
|
void *debug_data;
|
2009-06-09 13:26:36 +00:00
|
|
|
};
|
|
|
|
|
2009-06-15 08:17:30 +00:00
|
|
|
static gboolean g_isi_callback(GIOChannel *channel, GIOCondition cond,
|
|
|
|
gpointer data);
|
|
|
|
static gboolean g_isi_timeout(gpointer data);
|
2009-06-09 13:26:36 +00:00
|
|
|
|
2009-06-15 08:17:30 +00:00
|
|
|
static inline GIsiRequest *g_isi_req(GIsiClient *cl, uint8_t id)
|
2009-06-09 13:26:36 +00:00
|
|
|
{
|
2009-06-15 08:17:30 +00:00
|
|
|
return (GIsiRequest *)(((uint8_t *)(void *)cl) + id);
|
2009-06-09 13:26:36 +00:00
|
|
|
}
|
|
|
|
|
2009-06-15 08:17:30 +00:00
|
|
|
static inline uint8_t g_isi_id(void *ptr)
|
2009-06-09 13:26:36 +00:00
|
|
|
{
|
|
|
|
return ((uintptr_t)ptr) & 255;
|
|
|
|
}
|
|
|
|
|
2009-06-15 08:17:30 +00:00
|
|
|
static inline GIsiClient *g_isi_cl(void *ptr)
|
2009-06-09 13:26:36 +00:00
|
|
|
{
|
2009-06-15 08:17:30 +00:00
|
|
|
return (GIsiClient *)(((uintptr_t)ptr) & ~255);
|
2009-06-09 13:26:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Create an ISI client.
|
2009-06-25 06:40:06 +00:00
|
|
|
* @param resource PhoNet resource ID for the client
|
|
|
|
* @return NULL on error (see errno), a GIsiClient pointer on success,
|
2009-06-09 13:26:36 +00:00
|
|
|
*/
|
2009-08-18 11:34:27 +00:00
|
|
|
GIsiClient *g_isi_client_create(GIsiModem *modem, uint8_t resource)
|
2009-06-09 13:26:36 +00:00
|
|
|
{
|
|
|
|
void *ptr;
|
2009-06-15 08:17:30 +00:00
|
|
|
GIsiClient *cl;
|
2009-06-09 13:26:36 +00:00
|
|
|
GIOChannel *channel;
|
|
|
|
unsigned i;
|
|
|
|
|
|
|
|
if (G_UNLIKELY(posix_memalign(&ptr, 256, sizeof(*cl))))
|
|
|
|
abort();
|
|
|
|
cl = ptr;
|
|
|
|
cl->resource = resource;
|
2009-09-15 12:35:47 +00:00
|
|
|
cl->version.major = -1;
|
|
|
|
cl->version.minor = -1;
|
2009-08-23 20:19:03 +00:00
|
|
|
cl->modem = modem;
|
2009-09-09 13:35:44 +00:00
|
|
|
cl->debug_func = NULL;
|
2009-06-09 13:26:36 +00:00
|
|
|
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;
|
|
|
|
|
2009-08-18 11:34:27 +00:00
|
|
|
channel = phonet_new(modem, resource);
|
2009-06-09 13:26:36 +00:00
|
|
|
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,
|
2009-06-15 08:17:30 +00:00
|
|
|
g_isi_callback, cl);
|
2009-06-09 13:26:36 +00:00
|
|
|
g_io_channel_unref(channel);
|
|
|
|
return cl;
|
|
|
|
}
|
|
|
|
|
2009-09-15 12:35:47 +00:00
|
|
|
/**
|
|
|
|
* Set the ISI resource version of @a client.
|
|
|
|
* @param client client for the resource
|
|
|
|
* @param major ISI major version
|
|
|
|
* @param minor ISI minor version
|
|
|
|
*/
|
|
|
|
void g_isi_version_set(GIsiClient *client, int major, int minor)
|
|
|
|
{
|
|
|
|
if (!client)
|
|
|
|
return;
|
|
|
|
|
|
|
|
client->version.major = major;
|
|
|
|
client->version.minor = minor;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the ISI major version of the resource associated with @a
|
|
|
|
* client.
|
|
|
|
* @param client client for the resource
|
|
|
|
* @return major version, -1 if not available
|
|
|
|
*/
|
|
|
|
int g_isi_version_major(GIsiClient *client)
|
|
|
|
{
|
|
|
|
return client->version.major;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the ISI minor version of the resource associated with @a
|
|
|
|
* client.
|
|
|
|
* @param client client for the resource
|
|
|
|
* @return minor version, -1 if not available
|
|
|
|
*/
|
|
|
|
int g_isi_version_minor(GIsiClient *client)
|
|
|
|
{
|
|
|
|
return client->version.minor;
|
|
|
|
}
|
|
|
|
|
2009-06-25 06:40:06 +00:00
|
|
|
/**
|
|
|
|
* Returns the resource associated with @a client
|
|
|
|
* @param client client for the resource
|
|
|
|
* @return PhoNet resource ID for the client
|
|
|
|
*/
|
|
|
|
uint8_t g_isi_client_resource(GIsiClient *client)
|
|
|
|
{
|
|
|
|
return client->resource;
|
|
|
|
}
|
|
|
|
|
2009-08-22 15:01:24 +00:00
|
|
|
/**
|
|
|
|
* Set a debugging function for @a client. This function will be
|
|
|
|
* called whenever an ISI protocol message is sent or received.
|
|
|
|
* @param client client to debug
|
|
|
|
* @param func debug function
|
|
|
|
* @param opaque user data
|
|
|
|
*/
|
|
|
|
void g_isi_client_set_debug(GIsiClient *client, GIsiDebugFunc func,
|
|
|
|
void *opaque)
|
|
|
|
{
|
|
|
|
if (!client)
|
|
|
|
return;
|
|
|
|
|
|
|
|
client->debug_func = func;
|
|
|
|
client->debug_data = opaque;
|
|
|
|
}
|
|
|
|
|
2009-06-09 13:26:36 +00:00
|
|
|
/**
|
|
|
|
* Destroys an ISI client, cancels all pending transactions and subscriptions.
|
|
|
|
* @param client client to destroy
|
|
|
|
*/
|
2009-06-15 08:17:30 +00:00
|
|
|
void g_isi_client_destroy(GIsiClient *client)
|
2009-06-09 13:26:36 +00:00
|
|
|
{
|
|
|
|
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.
|
2009-06-15 08:17:30 +00:00
|
|
|
* @param cl ISI client (from g_isi_client_create())
|
2009-06-09 13:26:36 +00:00
|
|
|
* @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
|
|
|
|
*/
|
2009-06-15 08:17:30 +00:00
|
|
|
GIsiRequest *g_isi_request_make(GIsiClient *cl, const void *__restrict buf,
|
|
|
|
size_t len, unsigned timeout,
|
|
|
|
GIsiResponseFunc cb, void *opaque)
|
2009-06-09 13:26:36 +00:00
|
|
|
{
|
|
|
|
struct iovec iov[2];
|
2009-06-22 14:33:48 +00:00
|
|
|
const struct sockaddr_pn dst = {
|
|
|
|
.spn_family = AF_PHONET,
|
|
|
|
.spn_resource = cl->resource,
|
|
|
|
};
|
|
|
|
const struct msghdr msg = {
|
|
|
|
.msg_name = (struct sockaddr *)&dst,
|
|
|
|
.msg_namelen = sizeof(dst),
|
|
|
|
.msg_iov = (struct iovec *)iov,
|
|
|
|
.msg_iovlen = 2,
|
|
|
|
.msg_control = NULL,
|
|
|
|
.msg_controllen = 0,
|
|
|
|
.msg_flags = 0,
|
|
|
|
};
|
2009-06-09 13:26:36 +00:00
|
|
|
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;
|
2009-06-22 14:33:48 +00:00
|
|
|
ret = sendmsg(cl->fd, &msg, MSG_NOSIGNAL);
|
2009-06-09 13:26:36 +00:00
|
|
|
if (ret == -1)
|
|
|
|
return NULL;
|
2009-06-22 15:15:47 +00:00
|
|
|
if (ret != (ssize_t)(len + 1)) {
|
2009-06-09 13:26:36 +00:00
|
|
|
errno = EMSGSIZE;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2009-08-22 15:01:24 +00:00
|
|
|
if (cl->debug_func)
|
|
|
|
cl->debug_func(buf, len, cl->debug_data);
|
|
|
|
|
2009-06-09 13:26:36 +00:00
|
|
|
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,
|
2009-06-22 15:15:47 +00:00
|
|
|
g_isi_timeout,
|
|
|
|
g_isi_req(cl, id));
|
2009-06-09 13:26:36 +00:00
|
|
|
else
|
|
|
|
cl->timeout[id] = 0;
|
2009-06-15 08:17:30 +00:00
|
|
|
return g_isi_req(cl, id);
|
2009-06-09 13:26:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Cancels a pending request, i.e. stop waiting for responses and cancels the
|
|
|
|
* timeout.
|
|
|
|
* @param req request to cancel
|
|
|
|
*/
|
2009-06-15 08:17:30 +00:00
|
|
|
void g_isi_request_cancel(GIsiRequest *req)
|
2009-06-09 13:26:36 +00:00
|
|
|
{
|
2009-06-15 08:17:30 +00:00
|
|
|
GIsiClient *cl = g_isi_cl(req);
|
|
|
|
uint8_t id = g_isi_id(req);
|
2009-06-09 13:26:36 +00:00
|
|
|
|
|
|
|
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
|
|
|
|
|
2009-06-22 14:33:48 +00:00
|
|
|
static const struct sockaddr_pn commgr = {
|
|
|
|
.spn_family = AF_PHONET,
|
|
|
|
.spn_resource = PN_COMMGR,
|
|
|
|
};
|
|
|
|
|
2009-06-15 08:17:30 +00:00
|
|
|
static int g_isi_indication_init(GIsiClient *cl)
|
2009-06-09 13:26:36 +00:00
|
|
|
{
|
|
|
|
uint8_t msg[] = {
|
|
|
|
0, PNS_SUBSCRIBED_RESOURCES_IND, 1, cl->resource,
|
|
|
|
};
|
2009-08-23 20:19:03 +00:00
|
|
|
GIOChannel *channel = phonet_new(cl->modem, PN_COMMGR);
|
2009-06-09 13:26:36 +00:00
|
|
|
|
|
|
|
if (channel == NULL)
|
|
|
|
return errno;
|
|
|
|
/* Send subscribe indication */
|
|
|
|
cl->ind.fd = g_io_channel_unix_get_fd(channel);
|
2009-06-22 14:33:48 +00:00
|
|
|
sendto(cl->ind.fd, msg, 4, MSG_NOSIGNAL,
|
|
|
|
(const struct sockaddr *)&commgr, sizeof(commgr));
|
2009-06-09 13:26:36 +00:00
|
|
|
cl->ind.source = g_io_add_watch(channel,
|
|
|
|
G_IO_IN|G_IO_ERR|G_IO_HUP|G_IO_NVAL,
|
2009-06-15 08:17:30 +00:00
|
|
|
g_isi_callback, cl);
|
2009-06-09 13:26:36 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-06-15 08:17:30 +00:00
|
|
|
static void g_isi_indication_deinit(GIsiClient *client)
|
2009-06-09 13:26:36 +00:00
|
|
|
{
|
|
|
|
uint8_t msg[] = {
|
|
|
|
0, PNS_SUBSCRIBED_RESOURCES_IND, 0,
|
|
|
|
};
|
|
|
|
|
|
|
|
/* Send empty subscribe indication */
|
2009-06-22 14:33:48 +00:00
|
|
|
sendto(client->ind.fd, msg, 3, MSG_NOSIGNAL,
|
|
|
|
(const struct sockaddr *)&commgr, sizeof(commgr));
|
2009-06-09 13:26:36 +00:00
|
|
|
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.
|
2009-06-15 08:17:30 +00:00
|
|
|
* @param cl ISI client (fomr g_isi_client_create())
|
2009-06-09 13:26:36 +00:00
|
|
|
* @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.
|
|
|
|
*/
|
2009-06-15 08:17:30 +00:00
|
|
|
int g_isi_subscribe(GIsiClient *cl, uint8_t type,
|
|
|
|
GIsiIndicationFunc cb, void *data)
|
2009-06-09 13:26:36 +00:00
|
|
|
{
|
|
|
|
if (cb == NULL)
|
|
|
|
return EINVAL;
|
|
|
|
|
|
|
|
if (cl->ind.func[type] == NULL) {
|
|
|
|
if (cl->ind.count == 0) {
|
2009-06-15 08:17:30 +00:00
|
|
|
int ret = g_isi_indication_init(cl);
|
2009-06-09 13:26:36 +00:00
|
|
|
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.
|
2009-06-15 08:17:30 +00:00
|
|
|
* @param client ISI client (from g_isi_client_create())
|
2009-06-09 13:26:36 +00:00
|
|
|
* @param type indication type.
|
|
|
|
*/
|
2009-06-15 08:17:30 +00:00
|
|
|
void g_isi_unsubscribe(GIsiClient *client, uint8_t type)
|
2009-06-09 13:26:36 +00:00
|
|
|
{
|
|
|
|
/* Unsubscribe */
|
|
|
|
if (client->ind.func[type] == NULL)
|
|
|
|
return;
|
|
|
|
client->ind.func[type] = NULL;
|
|
|
|
if (--client->ind.count == 0)
|
2009-06-15 08:17:30 +00:00
|
|
|
g_isi_indication_deinit(client);
|
2009-06-09 13:26:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Data callback for both responses and indications */
|
2009-06-15 08:17:30 +00:00
|
|
|
static gboolean g_isi_callback(GIOChannel *channel, GIOCondition cond,
|
2009-06-09 13:26:36 +00:00
|
|
|
gpointer data)
|
|
|
|
{
|
2009-06-15 08:17:30 +00:00
|
|
|
GIsiClient *cl = data;
|
2009-06-09 13:26:36 +00:00
|
|
|
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];
|
2009-06-22 15:15:47 +00:00
|
|
|
uint8_t *msg;
|
2009-06-09 13:26:36 +00:00
|
|
|
uint16_t obj;
|
|
|
|
uint8_t res, id;
|
|
|
|
|
|
|
|
len = phonet_read(channel, buf, len, &obj, &res);
|
|
|
|
if (len < 2 || res != cl->resource)
|
|
|
|
return TRUE;
|
2009-06-22 15:15:47 +00:00
|
|
|
|
|
|
|
msg = (uint8_t *)buf;
|
2009-08-22 15:01:24 +00:00
|
|
|
|
2009-10-09 14:45:37 +00:00
|
|
|
if (cl->debug_func)
|
|
|
|
cl->debug_func(msg + 1, len - 1, cl->debug_data);
|
|
|
|
|
2009-06-09 13:26:36 +00:00
|
|
|
if (indication) {
|
2009-06-22 15:15:47 +00:00
|
|
|
/* Message ID at offset 1 */
|
|
|
|
id = msg[1];
|
2009-06-09 13:26:36 +00:00
|
|
|
if (cl->ind.func[id] == NULL)
|
|
|
|
return TRUE; /* Unsubscribed indication */
|
2009-08-25 15:26:24 +00:00
|
|
|
|
2009-06-22 15:15:47 +00:00
|
|
|
cl->ind.func[id](cl, msg + 1, len - 1, obj,
|
2009-06-09 13:26:36 +00:00
|
|
|
cl->ind.data[id]);
|
|
|
|
} else {
|
2009-06-22 15:15:47 +00:00
|
|
|
/* Transaction ID at offset 0 */
|
|
|
|
id = msg[0];
|
2009-06-22 18:40:49 +00:00
|
|
|
if (cl->func[id] == NULL)
|
2009-06-09 13:26:36 +00:00
|
|
|
return TRUE; /* Bad transaction ID */
|
2009-08-25 15:26:24 +00:00
|
|
|
|
2009-06-22 15:15:47 +00:00
|
|
|
if ((cl->func[id])(cl, msg + 1, len - 1, obj,
|
2009-06-09 13:26:36 +00:00
|
|
|
cl->data[id]))
|
2009-06-15 08:17:30 +00:00
|
|
|
g_isi_request_cancel(g_isi_req(cl, id));
|
2009-06-09 13:26:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2009-06-15 08:17:30 +00:00
|
|
|
static gboolean g_isi_timeout(gpointer data)
|
2009-06-09 13:26:36 +00:00
|
|
|
{
|
2009-06-15 08:17:30 +00:00
|
|
|
GIsiRequest *req = data;
|
|
|
|
GIsiClient *cl = g_isi_cl(req);
|
|
|
|
uint8_t id = g_isi_id(req);
|
2009-06-09 13:26:36 +00:00
|
|
|
|
|
|
|
assert(cl->func[id]);
|
|
|
|
(cl->func[id])(cl, NULL, 0, 0, cl->data[id]);
|
2009-06-15 08:17:30 +00:00
|
|
|
g_isi_request_cancel(req);
|
2009-06-09 13:26:36 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2009-06-15 08:17:30 +00:00
|
|
|
int g_isi_client_error(const GIsiClient *client)
|
2009-06-09 13:26:36 +00:00
|
|
|
{ /* The only possible error at the moment */
|
2009-06-15 08:33:16 +00:00
|
|
|
return -ETIMEDOUT;
|
2009-06-09 13:26:36 +00:00
|
|
|
}
|