emview_device.c from EmStar at Krugle
Show emview_device.c syntax highlighted
/*
*
* Copyright (c) 2003 The Regents of the University of California. All
* rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Neither the name of the University nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "emview_i.h"
#include <time.h>
QUEUE_INST(emview_dnode, ptrs, nodes, emview_dev_node_ext_t, emview_device_t);
QUEUE_INST(emview_device, ptrs, devices, emview_device_t, emview_device_list_t);
/*
* data ID assignment
*/
static
int emview_next_id()
{
static int id = EMVIEW_SIMCONFIG_DATA_ID+1;
return id++;
}
/*
* registering a device (how you get data from the proxy)
*/
emview_device_t *
emview_register_device(emview_device_opts_t *opts)
{
emview_device_t *dev = g_new0(emview_device_t, 1);
/* initialize the device struct */
dev->opts = *opts;
/* copy the strings */
dev->opts.name = strdup(dev->opts.name);
if (dev->opts.proxy_string)
dev->opts.proxy_string = strdup(dev->opts.proxy_string);
/* define an ID */
dev->data_id = emview_next_id();
/* create the per-node hash table */
dev->node_data = g_hash_table_new(g_direct_hash, g_direct_equal);
/* add to the core */
emview_device_push(&(_core.device_list), dev);
return dev;
}
emview_device_opts_t *emview_get_device_opts(emview_device_t *dev)
{
return &(dev->opts);
}
/*
* API call to modify the command string
*/
int emview_update_proxy_string(emview_device_t *dev, char *new_string)
{
if (dev->opts.proxy_string)
free(dev->opts.proxy_string);
dev->opts.proxy_string = NULL;
if (new_string)
dev->opts.proxy_string = strdup(new_string);
/* force resend of new stuff */
emview_device_update_command();
return 0;
}
/*
* device node data accessors
*/
node_id_t emview_dn_get_node_id(emview_dev_node_t *node_data)
{ return ((emview_dev_node_ext_t *)node_data)->node_id; }
emview_dev_node_t *emview_dn_top(emview_device_t *dev)
{ return (emview_dev_node_t *)emview_dnode_top(dev); }
emview_dev_node_t *emview_dn_next(emview_dev_node_t *node_data)
{ return (emview_dev_node_t *)emview_dnode_next((emview_dev_node_ext_t *)node_data); }
/*
* device node lookup/creation
*/
emview_dev_node_t *emview_dev_node_lookup(emview_device_t *dev, node_id_t id)
{
/* look up the per-node data */
emview_dev_node_t *dn =
(emview_dev_node_t *)g_hash_table_lookup(dev->node_data, (void*)id);
/* create if not found */
if (dn == NULL) {
emview_dev_node_ext_t *dne = g_new0(emview_dev_node_ext_t, 1);
dne->node_id = id;
emview_dnode_push(dev, dne);
g_hash_table_insert(dev->node_data, (void *)id, dne);
dn = (emview_dev_node_t *)dne;
}
return dn;
}
/*
* callback functions
*/
static
int emview_device_handle_data(emproxy_reply_hdr_t *reply, void *data)
{
emview_device_t *ptr;
elog(LOG_DEBUG(5), "Got data reply.. id=%d, node=%d", reply->data_id, reply->node_id);
/* if we're logging to the trace.. */
if (_core.trace_path) {
emview_trace_log(reply);
}
/* check for simconfig data */
if (reply->data_id == EMVIEW_SIMCONFIG_DATA_ID) {
emview_node_handle_simconfig(reply);
goto out;
}
/* is this a new node? */
emview_node_heard(reply->node_id, 1);
/* determine module to pass this to */
for (ptr = emview_device_top(&(_core.device_list)); ptr;
ptr = emview_device_next(ptr))
if (ptr->data_id == reply->data_id)
if (ptr->opts.data_handler) {
/* check the data length */
if (ptr->opts.nominal_data_length &&
(ptr->opts.nominal_data_length != reply->data_length)) {
elog(LOG_WARNING, "Got data from %s, wrong length (%d bytes, expected %d bytes)",
ptr->opts.name,
reply->data_length, ptr->opts.nominal_data_length);
}
else {
/* look up the per-node data */
emview_dev_node_t *dn = emview_dev_node_lookup(ptr, reply->node_id);
/* call the callback */
ptr->opts.data_handler(ptr, reply, dn);
}
goto out;
}
elog(LOG_WARNING, "Received data for id %d, no such device registered", reply->data_id);
out:
return EVENT_RENEW;
}
/*
* internal API call to clear and update the emproxy state
*/
void emview_device_update_command()
{
emview_device_t *ptr;
buf_t *buf = buf_new();
/* clear update timer */
g_event_destroy(_core.device_list.device_recompute_timer);
/* construct a new command */
bufprintf(buf, "session=%d:type=request\n", _core.device_list.session_nonce);
bufprintf(buf, "dev=%s:node=-1:id=%d\n", EMSIM_CONFIG_DEVNAME, EMVIEW_SIMCONFIG_DATA_ID);
/* now output each in turn */
for (ptr = emview_device_top(&(_core.device_list)); ptr;
ptr = emview_device_next(ptr))
if (ptr->active) {
elog(LOG_DEBUG(0), "Adding device %s to the command", ptr->opts.proxy_string);
bufprintf(buf, "%s:id=%d\n", ptr->opts.proxy_string, ptr->data_id);
}
/* push it to emproxy */
emproxy_multi_set_command(_core.device_list.emproxy_event, buf->buf);
/* log new request to the trace file */
if (_core.trace_path) {
buf_t *emproxy_cmd = buf_new();
emproxy_reply_hdr_t hdr = {
data_length: buf->len
};
bufcpy(emproxy_cmd, &hdr, sizeof(hdr));
bufcpy(emproxy_cmd, buf->buf, buf->len);
emview_trace_log((emproxy_reply_hdr_t *)emproxy_cmd->buf);
buf_free(emproxy_cmd);
}
/* free the buffer */
buf_free(buf);
}
void emview_device_clear_active_flags()
{
emview_device_t *ptr;
/* clear the active marks on all devices */
for (ptr = emview_device_top(&(_core.device_list)); ptr;
ptr = emview_device_next(ptr))
ptr->active = ptr->opts.always_active;
}
/*
* activates a device and will trigger a recomputation of the request string
*/
static
int emview_device_recompute(void *data, int interval, g_event_t *event)
{
emview_device_update_command();
return TIMER_DONE;
}
/* forces timer set if dev is NULL */
void emview_device_activate(emview_device_t *dev)
{
if (dev)
elog(LOG_DEBUG(0), "Activating device %s (%d)", dev->opts.name, dev->active);
/* skip if already active */
if (dev && dev->active) return;
if (dev) dev->active = 1;
/* set the timer */
if (!g_timer_isset(_core.device_list.device_recompute_timer))
g_timer_add(EMVIEW_DEVICE_RECOMPUTE_DELAY, emview_device_recompute, NULL, NULL,
&(_core.device_list.device_recompute_timer));
}
/*
* calls timeout handlers
*/
void emview_device_note_timeout(node_id_t id)
{
emview_device_t *ptr;
/* call each device's timeout handler */
for (ptr = emview_device_top(&(_core.device_list)); ptr;
ptr = emview_device_next(ptr))
if (ptr->opts.node_timeout) {
/* look up the per-node data */
emview_dev_node_t *dn = emview_dev_node_lookup(ptr, id);
/* call the callback */
ptr->opts.node_timeout(ptr, dn);
}
}
/*
* emview device status
*/
static
int emview_device_status_printable(status_context_t *info, buf_t *buf)
{
//int now = time(0);
emview_device_t *ptr;
bufprintf(buf, "Active Devices:\n");
for (ptr = emview_device_top(&_core.device_list); ptr;
ptr = emview_device_next(ptr)) {
bufprintf(buf, " dev=%s, id=%d, active=%d\n",
ptr->opts.name, ptr->data_id, boolify(ptr->active));
}
bufprintf(buf, "\nCurrent String:\n'%s'\n",
emproxy_multi_get_command(_core.device_list.emproxy_event));
return STATUS_MSG_COMPLETE;
}
/*
* Trace Replay
*/
void emview_trace_log(emproxy_reply_hdr_t *reply)
{
int status;
status = write(_core.trace_fd, "HELO", 4);
status = write(_core.trace_fd, reply, sizeof(*reply)+reply->data_length);
if (status < 0) {
elog(LOG_CRIT, "Unable to write to trace file %s: %m", _core.trace_path);
close(_core.trace_fd);
_core.trace_path = NULL;
}
}
void emview_trace_close()
{
/* close and clean up old */
close(_core.trace_fd);
frame_processor_destroy(_core.de_frame);
if (_core.on_deck) {
free(_core.on_deck);
_core.on_deck = NULL;
}
if (_core.input_trace_path) {
free(_core.input_trace_path);
_core.input_trace_path = NULL;
}
}
static
int emview_trace_packet_handler(frame_context_t *ctx, char *buffer, size_t len)
{
emproxy_reply_hdr_t *hdr = (emproxy_reply_hdr_t *)buffer;
/* time yet? */
/* $$$$$ */
/* is this a emproxy request? */
if (hdr->data_id == 0) {
}
else {
emview_device_handle_data(hdr, NULL);
}
return EVENT_RENEW;
}
int emview_trace_open(char *path)
{
int fd = open(path, O_RDONLY);
if (fd < 0) {
elog(LOG_WARNING, "Unable to open trace file %s: %m", path);
return -1;
}
emview_trace_close();
/* switch to new file */
_core.input_trace_path = strdup(path);
_core.trace_fd = fd;
set_nonblock(_core.trace_fd, 1);
{
frame_opts_t opts = {
frame_type: FRAME_TYPE_LENGTH,
frame_start: "HELO",
length_format: FRAME_LENGTH_INT,
length_offset: offsetof(emproxy_reply_hdr_t, data_length),
length_correction: sizeof(emproxy_reply_hdr_t),
length_valid_max: 65536,
handle_frame: emview_trace_packet_handler,
report_eof: 1,
report_errors: 1
};
if (frame_processor_new(&opts, _core.trace_fd, &(_core.de_frame)) < 0){
elog(LOG_CRIT, "Can't create trace file event: %m");
exit(1);
}
}
return 0;
}
/* we get passed an opts struct with the addresses filled */
void emview_devices_init(emproxy_client_opts_t *opts)
{
char buf[1024];
/* select random nonce */
_core.device_list.session_nonce = random();
/* generate an initial null request */
sprintf(buf, "session=%d:type=request\n", _core.device_list.session_nonce);
/* fill the opts */
opts->handler = emview_device_handle_data;
opts->command = buf;
/* start loading the trace file */
if (_core.input_trace_path) {
char *path = _core.input_trace_path;
_core.input_trace_path = NULL;
_core.trace_fd = -1;
emview_trace_open(path);
}
else {
/* start up request */
if (emproxy_multi_open(opts, &(_core.device_list.emproxy_event)) < 0) {
elog(LOG_CRIT, "Unable to connect to emproxy: %m");
exit(1);
}
}
/* configure (optional) status device */
{
status_dev_opts_t opts = {
device: {
devname: "/dev/emview/devices"
},
printable: emview_device_status_printable
};
g_status_dev(&opts, &(_core.device_list.stat));
}
}
See more files for this project here