Show usfusd.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.
*
*/
/*
* usFUSD: the User-Space Framework for User-Space Devices
*
* NOTE: Though it probably ought to be independent, this daemon depends
* on CENS utility libraries. It was just a pain to reimplement
* everything.
*
*/
#include <fusd.h>
#include <fusd_msg.h>
#include <usfusd_msg.h>
#include "usfusd_i.h"
#include <libdev/glib_dev.h>
#include <libmisc/misc.h>
QUEUE_FUNCTION_INSTANTIATIONS(usfusd_clients,_,clients,struct client,usfusd_t);
QUEUE_FUNCTION_INSTANTIATIONS(usfusd_devices,_,devices,struct device,usfusd_t);
usfusd_t state = {};
/*
* destructors...
*/
static
void usfusd_device_destroy(device_t *d)
{
if (d && !d->destroying) {
client_t *c;
/* set destroying bit */
d->destroying = 1;
/* free name */
if (d->devname)
free(d->devname);
/* remove */
usfusd_devices_remove(&state, d);
/* kill server if any */
if (d->server)
usfusd_client_destroy(d->server);
/* kill any clients of this device */
for (c = usfusd_clients_top(&state); c; ) {
client_t *tmp = c;
c = usfusd_clients_next(c);
if (tmp->usfusd_device == d)
usfusd_client_destroy(tmp);
}
/* free device */
free(d);
}
}
static
void usfusd_client_destroy(client_t *c)
{
if (c && !c->destroying)
usfusd_proto_destroy(c->proto);
}
/*
* protocol handlers
*/
static
void usfusd_handle_close(void *data)
{
client_t *c = (client_t *)data;
if (c && !c->destroying) {
device_t *dev;
/* set destroying bit */
c->destroying = 1;
/* if open, fake a close to device */
if (c->usfusd_device && !c->defunct) {
/* fake a close */
/* $$$$ */
}
#if 0
/* close */
if (c->local_fd >= 0)
close(c->local_fd);
for (i=0; i<BLOCK_MAX; i++)
g_event_destroy(c->local_event[i]);
g_event_destroy(c->poll_event);
#endif
/* remove */
usfusd_clients_remove(&state, c);
/* kill device if any */
for (dev = usfusd_devices_top(&state); dev; ) {
device_t *tmp = dev;
dev = usfusd_devices_next(dev);
if (tmp->server == c)
usfusd_device_destroy(tmp);
}
/* close the socket */
__close(c->socket);
/* free client struct */
free(c);
}
}
static
void usfusd_handle_input(usfusd_msg_t *msg, char *data_buf, void *data)
{
client_t *c = (client_t *)data;
/* ignore defunct conns */
if (c->defunct) {
elog(LOG_WARNING, "Recieved message on defunct connection?");
return;
}
/* ignore blocked conns */
if (c->blocked && (msg->subcmd != FUSD_CLOSE)) {
elog(LOG_WARNING, "Recieved message on blocked connection?");
return;
}
switch (msg->cmd) {
case USFUSD_CLIENT_OPEN:
usfusd_open(c, msg, data_buf);
break;
case USFUSD_CLIENT_DUP:
usfusd_dup(c, msg);
break;
case USFUSD_CLIENT_OP:
switch (msg->subcmd) {
case FUSD_READ:
usfusd_read(conn, msg);
break;
case FUSD_WRITE:
usfusd_write(conn, msg, data_buf);
break;
case FUSD_IOCTL:
usfusd_ioctl(conn, msg, data_buf);
break;
case USFUSD_POLL:
usfusd_poll(conn, msg, 0);
break;
case FUSD_POLL_DIFF:
usfusd_poll(conn, msg, 1);
break;
case USFUSD_FCNTL:
usfusd_fcntl(conn, msg);
break;
case FUSD_CLOSE:
/* set this conn to defunct */
conn->defunct = 1;
/* if this conn was blocking, unblock */
usfusd_unblock_if(conn);
/* drop this connection and close only if arg is set */
if (msg->arg) usufsd_conn_close(conn);
break;
default:
break;
}
break;
default:
break;
}
}
/*
* accept handler
*/
int usfusd_handle_accept(void *data, int fd, int cond, g_event_t *event)
{
usfusd_t *state = (usfusd_t *)data;
struct sockaddr_in saddr;
client_t *c;
client_conn_t *conn;
usfusd_proto_opts_t popts = {
input: usfusd_handle_input,
close: usfusd_handle_close
};
/* accept new connection */
int status = accept(fd, &saddr, sizeof(saddr));
if (status < 0) {
elog(LOG_CRIT, "Accept returned error: %m");
exit(1);
}
/* create new client state */
c = malloc(sizeof(client_t));
conn = malloc(sizeof(client_conn_t));
if ((c == NULL) || (conn == NULL)) {
elog(LOG_CRIT, "Unable to alloc new client: %m\n");
exit(1);
}
/* init */
memset(c, 0, sizeof(client_t));
memset(conn, 0, sizeof(client_conn_t));
conn->socket = status;
conn->parent = c;
c->saddr = saddr;
usfusd_conns_push(c, conn);
usfusd_clients_push(&state, c);
/* register an event.. */
popts.private_data = conn;
popts.socket = conn->socket;
if (usfusd_proto_new(&popts, &(conn->proto)) < 0) {
elog(LOG_CRIT, "Unable to create event for new connection: %m");
exit(1);
}
return EVENT_RENEW;
}
/*
* init and bind
*/
void usfusd_init()
{
struct sockaddr_in saddr = {
sin_family: AF_INET,
sin_port: htons(USFUSD_PORT),
sin_addr: {
s_addr: INADDR_ANY
}
};
/* get a socket */
state.usfusd_socket = socket(PF_INET, SOL_STREAM, IPPROTO_TCP);
if (state.usfusd_socket < 0) {
elog(LOG_CRIT, "Socket call failed: %m");
exit(1);
}
/* try to bind */
status = bind(state.usfusd_socket, &saddr, sizeof(struct sockaddr_in));
if (status < 0) {
elog(LOG_CRIT, "Unable to bind to usfusd server socket! %m\n");
exit(1);
}
/* register an event.. */
if (g_event_add(state.usfusd_socket, FUSD_NOTIFY_INPUT, usfusd_handle_accept, &state,
NULL, NULL) < 0) {
elog(LOG_CRIT, "Failed to create event for accept socket: %m\n");
exit(1);
}
}
/*
* main
*/
int main(int argc, char **argv)
{
/* process args? */
/* initialize and bind */
usfusd_init();
/* run */
g_main();
return 0;
}
See more files for this project here