dslinux/user/pixil/sys/ipc/server Makefile app.c list.c log.c message.c network.c packet.c queue.c server.c server.h
amadeus
dslinux_amadeus at user.in-berlin.de
Tue Oct 3 13:27:10 CEST 2006
Update of /cvsroot/dslinux/dslinux/user/pixil/sys/ipc/server
In directory antilope:/tmp/cvs-serv11916/sys/ipc/server
Added Files:
Makefile app.c list.c log.c message.c network.c packet.c
queue.c server.c server.h
Log Message:
adding pristine copy of pixil to HEAD so I can branch from it
--- NEW FILE: message.c ---
/*
* Copyright (c) 2003 Century Software, Inc. All Rights Reserved.
*
* This file is part of the PIXIL Operating Environment
*
* The use, copying and distribution of this file is governed by one
* of two licenses, the PIXIL Commercial License, or the GNU General
* Public License, version 2.
*
* Licensees holding a valid PIXIL Commercial License may use this file
* in accordance with the PIXIL Commercial License Agreement provided
* with the Software. Others are governed under the terms of the GNU
* General Public License version 2.
*
* This file may be distributed and/or modified under the terms of the
* GNU General Public License version 2 as published by the Free
* Software Foundation and appearing in the file LICENSE.GPL included
* in the packaging of this file.
*
* This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING
* THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE.
*
* RESTRICTED RIGHTS LEGEND
*
* Use, duplication, or disclosure by the government is subject to
* restriction as set forth in paragraph (b)(3)(b) of the Rights in
* Technical Data and Computer Software clause in DAR 7-104.9(a).
*
* See http://www.pixil.org/gpl/ for GPL licensing
* information.
*
* See http://www.pixil.org/license.html or
* email cetsales at centurysoftware.com for information about the PIXIL
* Commercial License Agreement, or if any conditions of this licensing
* are not clear to you.
*/
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <ipc/colosseum.h>
#include "server.h"
extern int cl_chatty;
int
handle_server_message(cl_app_struct * app, cl_pkt_message * msg)
{
return (0);
}
static int
deliver_message(cl_app_struct * dest, cl_pkt_buff * pkt)
{
if (!pkt || !dest)
return (-1);
if (!data_in_queue(dest)) {
int ret = cl_ClientWrite(dest->cl_socket, pkt->data, pkt->len);
/* If the write was blocked, then queue the packet for later */
if (ret == 1) {
queue_add_packet(dest, pkt);
dest->cl_flags |= CL_F_QUEUE_MSG;
return (1);
}
return (0); /* Tell the calling function to free the buffer */
}
queue_add_packet(dest, pkt);
return (1);
}
/* Try to send as many queued messages as possible */
int
cl_HandleQueuedMessages(cl_app_struct * app)
{
cl_pkt_buff *pkt;
if (!app)
return (-1);
/* Temporary clear the block */
app->cl_flags &= ~CL_F_QUEUE_MSG;
while ((pkt = queue_peek_packet(app))) {
int ret = cl_ClientWrite(app->cl_socket, pkt->data, pkt->len);
/* If there is an error, then reinstate the block and bail */
if (ret == 1) {
app->cl_flags |= CL_F_QUEUE_MSG;
return (0);
}
/* If it sent succesfully, then actually pull the packet */
/* and free it */
pkt = queue_get_packet(app);
pkt_buff_free(pkt);
}
return (0);
}
int
cl_SendMessage(cl_app_struct * req, cl_pkt_buff * pkt)
{
int stored = 0;
int ret = 0;
cl_app_struct *dest;
cl_pkt_message *msg = pkt->data;
cl_pkt_msg_response response;
bzero(&response, sizeof(response));
response.header.type = CL_PKT_MSG_RESPONSE;
response.header.len = sizeof(cl_pkt_msg_response);
if (msg->dest == CL_MSG_SERVER_ID) {
if (cl_chatty)
DO_LOG(CL_LOG_DEBUG, "SERVER MSG [%s]", req->cl_name);
handle_server_message(req, msg);
/* It is important to send *something* back to the client. */
cl_SendPacket(req, (cl_packet *) & response,
sizeof(cl_pkt_msg_response));
return (0);
}
/* Broadcast */
if (msg->dest == CL_MSG_BROADCAST_ID) {
if (cl_chatty)
DO_LOG(CL_LOG_DEBUG, "BROADCAST MSG [%s]\n", req->cl_name);
dest = get_first_app();
while (dest) {
if (dest != req && ISSET_FLAG(dest->cl_flags, CL_F_ACTIVE)) {
if (deliver_message(dest, pkt) == 1) {
stored++;
PKT_BUFF_ADD_OWNER(pkt);
}
}
dest = get_next_app(dest);
}
/* It is important to send *something* back to the client. */
cl_SendPacket(req, (cl_packet *) & response,
sizeof(cl_pkt_msg_response));
return ((stored ? 1 : 0));
}
/* Regular delivery */
dest = get_app_by_id(msg->dest);
if (!dest) {
DO_LOG(CL_LOG_ERROR, "WARNING: IPC id [%d] doesn't exist!",
msg->dest);
/* On a bad destination, we inform the source. This is used to detect
clients that may have gone away. This is also why we send a dummy
response on all the other paths - the client is waiting for a response
*/
printf("Seending a CL_E_NODEST to the client\n");
CL_ERROR(req, CL_E_NODEST, &response);
return (-1);
}
DO_LOG(CL_LOG_DEBUG, "MSG [%s] to [%d]\n", req->cl_name, msg->dest);
msg->src = req->cl_id;
ret = deliver_message(dest, pkt);
/* It is important to send *something* back to the client. */
cl_SendPacket(req, (cl_packet *) & response, sizeof(cl_pkt_msg_response));
return (ret);
}
--- NEW FILE: network.c ---
/*
* Copyright (c) 2003 Century Software, Inc. All Rights Reserved.
*
* This file is part of the PIXIL Operating Environment
*
* The use, copying and distribution of this file is governed by one
* of two licenses, the PIXIL Commercial License, or the GNU General
* Public License, version 2.
*
* Licensees holding a valid PIXIL Commercial License may use this file
* in accordance with the PIXIL Commercial License Agreement provided
* with the Software. Others are governed under the terms of the GNU
* General Public License version 2.
*
* This file may be distributed and/or modified under the terms of the
* GNU General Public License version 2 as published by the Free
* Software Foundation and appearing in the file LICENSE.GPL included
* in the packaging of this file.
*
* This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING
* THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE.
*
* RESTRICTED RIGHTS LEGEND
*
* Use, duplication, or disclosure by the government is subject to
* restriction as set forth in paragraph (b)(3)(b) of the Rights in
* Technical Data and Computer Software clause in DAR 7-104.9(a).
*
* See http://www.pixil.org/gpl/ for GPL licensing
* information.
*
* See http://www.pixil.org/license.html or
* email cetsales at centurysoftware.com for information about the PIXIL
* Commercial License Agreement, or if any conditions of this licensing
* are not clear to you.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <ipc/colosseum.h>
#include "server.h"
/* This is a wrapper that handles any exceptions */
void
cl_CloseClient(int sock)
{
cl_CloseApp(get_app_by_socket(sock));
close(sock);
}
int
cl_ClientWrite(int fd, unsigned char *buffer, int len)
{
int out = len;
while (out) {
int ret = write(fd, buffer, len);
if (ret <= 0) {
if (errno == EAGAIN || errno == EINTR)
continue;
/* Invalid agument messages are expected when clients go away */
/* Don't log the message (or we'll see tons of messages) */
if (errno != EINVAL) {
DO_LOG(CL_LOG_ERROR, "Linux error [%s] while writing [%d]\n",
strerror(errno), fd);
}
cl_CloseClient(fd);
return (-1);
}
out -= ret;
}
return (0);
}
int
cl_ClientRead(int fd, cl_pkt_buff ** pkt)
{
cl_pkt_header header;
unsigned char *buffer = 0;
int ret;
int dsize = 0;
/* Read the header first to get the size */
ret = read(fd, &header, sizeof(header));
if (ret <= 0) {
switch (errno) {
case EAGAIN:
return -1; /* Dont do anything rash, just try to read again */
/* Normally, this is due to a SIGPIPE. */
/* Note: We could do a fancy signal handler scheme to verify
that this EINTR was due to a "bad" signal, but I'm going
to go ahead and assume that any EINTR at this point is
not good. I am going to stick a debug message in though,
so we can determine what is happening */
case EINTR:
printf
("Got an EINTR. This is probably a SIGPIPE. Closing client.\n");
break;
case EINVAL:
case EBADF:
case ECONNRESET:
/* Common messages when a client disapears */
break;
default:
DO_LOG(CL_LOG_ERROR, "Linux error [%d] [%s] while reading [%d]\n",
errno, strerror(errno), fd);
}
cl_CloseClient(fd);
*pkt = 0;
return -1;
}
/* Now, allocate enough temporary room to hold the whole packet */
buffer = (unsigned char *) malloc(header.len);
if (!buffer) {
DO_LOG(CL_LOG_ERROR, "Out of memory in cl_ClientRead\n");
return (-1);
}
dsize = header.len - sizeof(header);
/* Copy the header over */
memcpy(buffer, (void *) &header, sizeof(header));
/* And read the rest of the packet */
ret = read(fd, (void *) buffer + sizeof(header), dsize);
if (ret != dsize) {
if (ret < 0)
DO_LOG(CL_LOG_ERROR, "Error %d on read. Shutting down fd %d.\n",
errno, fd);
else
DO_LOG(CL_LOG_ERROR, "Bad packet size (got %d, expected %d).\n",
ret, dsize);
free(buffer);
cl_CloseClient(fd);
return (-1);
}
*pkt = pkt_buff_alloc(buffer, header.len);
free(buffer);
return (0);
}
int
cl_InitServerSocket(void)
{
int lsock;
struct sockaddr_un saddr;
/* Check if the temporary file already exists. */
if (!access(CL_NAMED_SOCKET, F_OK))
if (unlink(CL_NAMED_SOCKET))
return (-1);
if ((lsock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
perror("create socket");
return (-1);
}
saddr.sun_family = AF_UNIX;
strncpy(saddr.sun_path, CL_NAMED_SOCKET, sizeof(saddr.sun_path));
if (bind(lsock, (struct sockaddr *) &saddr, SUN_LEN(&saddr)) < 0) {
perror("bind socket");
goto exit_init;
}
if (listen(lsock, 5) == -1) {
perror("listen socket");
goto exit_init;
}
return (lsock);
exit_init:
if (lsock)
close(lsock);
return (-1);
}
int
cl_HandleNewClient(int srvsock)
{
struct sockaddr_un saddr;
int slen = sizeof(saddr);
int clsock = 0;
if ((clsock = accept(srvsock, (struct sockaddr *) &saddr, &slen)) == -1) {
perror("accept");
return (-1);
}
/* Allocate the application structure */
if (!cl_AllocNewApp(clsock))
return (-1);
return (0);
}
--- NEW FILE: app.c ---
/*
* Copyright (c) 2003 Century Software, Inc. All Rights Reserved.
*
* This file is part of the PIXIL Operating Environment
*
* The use, copying and distribution of this file is governed by one
* of two licenses, the PIXIL Commercial License, or the GNU General
* Public License, version 2.
*
* Licensees holding a valid PIXIL Commercial License may use this file
* in accordance with the PIXIL Commercial License Agreement provided
* with the Software. Others are governed under the terms of the GNU
* General Public License version 2.
*
* This file may be distributed and/or modified under the terms of the
* GNU General Public License version 2 as published by the Free
* Software Foundation and appearing in the file LICENSE.GPL included
* in the packaging of this file.
*
* This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING
* THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE.
*
* RESTRICTED RIGHTS LEGEND
*
* Use, duplication, or disclosure by the government is subject to
* restriction as set forth in paragraph (b)(3)(b) of the Rights in
* Technical Data and Computer Software clause in DAR 7-104.9(a).
*
* See http://www.pixil.org/gpl/ for GPL licensing
* information.
*
* See http://www.pixil.org/license.html or
* email cetsales at centurysoftware.com for information about the PIXIL
* Commercial License Agreement, or if any conditions of this licensing
* are not clear to you.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/wait.h>
#include <pixil_config.h>
extern int cl_chatty;
#ifdef CONFIG_PAR
#include <par/par.h>
extern db_handle *parDB;
extern db_handle *cl_openDatabase(void);
static int local_spawnApp(char *name, char *args);
#endif
#include <ipc/colosseum.h>
#include "server.h"
/* Pulled directly out of ol' nxscrtop */
#ifdef CONFIG_PAR
static int
local_parseArgs(char *name, char *argstr, char ***argv)
{
char **argvptr = 0;
char *h = argstr;
char *t = 0;
int argc = 1;
int index = 0;
/* If there are arguments, then count them */
if (argstr) {
while ((t = strchr(h, ' '))) {
/* Skip to the next empty space */
for (; *t == ' ' && *t != 0; t++);
if (*t == 0)
break;
argc++;
h = t;
}
}
/* Now, allocate the required room */
*argv = (char **) malloc((argc + 2) * sizeof(char *));
if (!*argv)
return (0);
argvptr = *argv;
/* First step, add the program name */
argvptr[0] = (char *) calloc(1, strlen(name) + 1);
strcpy(argvptr[0], name);
if (!argstr || !strlen(argstr)) {
argvptr[1] = (char *) 0;
return (1);
}
/* Now add any args (if they exist) */
h = argstr;
while (index < argc) {
int slen = 0;
t = strchr(h, ' ');
if (t)
slen = (int) (t - h);
else
slen = strlen(argstr) - (int) (h - argstr);
argvptr[++index] = (char *) calloc(1, slen + 1);
/* If there was an error, skip to the next one */
if (!argvptr[index]) {
index--;
if (!t)
break;
/* Skip to the next word */
for (; *t == ' ' && *t != 0; t++);
if (*t == 0)
break;
h = t;
continue;
}
if (t)
strncpy(argvptr[index], h, slen);
else
strcpy(argvptr[index], h);
if (!t)
break;
/* Skip to the next word */
for (; *t == ' ' && *t != 0; t++);
if (*t == 0)
break;
h = t;
continue;
}
/* Add a null pointer to the end */
argvptr[++index] = (char *) 0;
return (index);
}
#endif
/* This child handler grabs a closed pid and removes it from the list */
void
cl_childHandler(int id)
{
cl_pid_t *pid;
int status;
int ret = waitpid(-1, &status, WNOHANG);
pid = cl_findPid(ret);
if (!pid)
return; /* Unknown pid.. no harm no foul, I guess */
cl_removePid(ret);
}
#ifdef CONFIG_PAR
static int
local_ForkApp(char *exec, char *astr, char *workdir)
{
int pid = 0;
char **argv = 0;
local_parseArgs(exec, astr, &argv);
if (!(pid = fork())) {
char *path = 0;
/* If a work dir was specified, use that one */
if (strlen(workdir))
path = workdir;
else {
char *p = strrchr(exec, '/');
/* otherwise, try to determine a path from the exec string */
if (p) {
path = alloca((int) (p - exec) + 2);
strncpy(path, exec, (int) (p - exec));
path[(int) (p - exec)] = 0;
}
}
if (path)
if (chdir(path))
DO_LOG(CL_LOG_ERROR,
"Unable to switch to the working directory %s\n",
path);
/* Start the desired app */
execvp(exec, argv);
exit(0);
}
return (pid);
}
#endif
cl_pending_struct *
cl_AddPending(cl_app_struct * parent,
unsigned char *name, int flags, int timeout, cl_pkt_start * req)
{
cl_pending_struct *pend = cl_AllocPending();
if (!pend)
return (0);
strcpy(pend->name, name);
pend->parent = parent;
pend->flags = flags;
pend->timeout = timeout;
memcpy(&pend->request, req, sizeof(cl_pkt_start));
/* Add it to the pending list */
return (pend);
}
/* This spawns an given application from the PAR database */
/* For safety, we can only spawn apps that come from the PAR */
#ifdef CONFIG_PAR
static int
local_spawnApp(char *name, char *args)
{
par_app_t parapp;
int pid;
if (!parDB)
parDB = cl_openDatabase();
if (!parDB) {
DO_LOG(CL_LOG_ERROR, "Unable to load the PAR database\n");
return (-1);
}
memset(¶pp, 0, sizeof(parapp));
if (par_getApplication(parDB, name, ¶pp) == -1)
return (-1);
if (!args)
pid = local_ForkApp(parapp.path, parapp.defargs, parapp.workdir);
else
pid = local_ForkApp(parapp.path, args, parapp.workdir);
/* Error - bail out! */
if (pid == -1)
return (-1);
/* Add the pid to the pid list */
cl_addPid(name, pid);
/* Return the pid for fun */
return (pid);
}
#endif /* CONFIG_PAR */
int
cl_HandleAppInfo(cl_app_struct * req, cl_pkt_appinfo * pkt)
{
cl_pid_t *pid;
switch (pkt->flags) {
case CL_APP_INFO_PID:
pid = cl_findNameByPid(pkt->processid);
if (!pid)
goto send_error;
strncpy(pkt->name, pid->name, sizeof(pkt->name));
break;
case CL_APP_INFO_NAME:
pid = cl_findPidByName(pkt->name);
if (!pid)
goto send_error;
pkt->processid = pid->pid;
break;
default:
DO_LOG(CL_LOG_MESSAGE, "Warning - Unknown flag [%x]\n", pkt->flags);
break;
}
if (cl_chatty)
DO_LOG(CL_LOG_MESSAGE, "APPINFO [%s]\n", req->cl_name, pkt->name);
cl_SendPacket(req, (cl_packet *) pkt, sizeof(cl_pkt_appinfo));
return (0);
send_error:
CL_ERROR(req, CL_E_NOSUCHAPP, pkt);
return (-1);
}
/* This will return the PID of the spawned app */
int
cl_HandleSpawnApp(cl_app_struct * req, cl_pkt_spawn * pkt)
{
#ifdef CONFIG_PAR
int res;
#endif
/* See if the app is already started */
cl_pid_t *pid = cl_findPidByName(pkt->name);
if (pid) {
pkt->pid = pid->pid;
cl_SendPacket(req, (cl_packet *) pkt, sizeof(cl_pkt_spawn));
return (0);
}
/* A quick check for par support */
#ifndef CONFIG_PAR
DO_LOG(CL_LOG_MESSAGE, "SpawnApp requires the PAR database.\n");
CL_ERROR(req, CL_E_NOTIMPLEMENT, pkt);
return (-1);
#else
if (cl_chatty)
DO_LOG(CL_LOG_MESSAGE, "SPAWN [%s]: Application [%s]\n", req->cl_name,
pkt->name);
if (strlen(pkt->argstr))
res = local_spawnApp(pkt->name, pkt->argstr);
else
res = local_spawnApp(pkt->name, 0);
if (res > 0) {
pkt->pid = res;
cl_SendPacket(req, (cl_packet *) pkt, sizeof(cl_pkt_spawn));
return (0);
} else {
CL_ERROR(req, CL_E_SPAWNERR, pkt);
return (-1);
}
#endif /* CONFIG_PAR */
}
int
cl_HandleStartApp(cl_app_struct * req, cl_pkt_start * pkt)
{
cl_app_struct *app;
#ifdef CONFIG_PAR
int result;
cl_pending_struct *pending = 0;
#endif
/* First, look for the app locally to see if it is available */
app = get_app_by_name(pkt->name);
if (app) {
pkt->ipc_id = app->cl_id;
cl_SendPacket(req, (cl_packet *) pkt, sizeof(cl_pkt_start));
return (0);
}
/* Next, check to see if this app name is in the PID list. */
/* if it is, then send an error back, because it should */
/* have been flagged above. */
if (cl_findPidByName(pkt->name)) {
DO_LOG(CL_LOG_MESSAGE,
"Application [%s] exists, but Colosseum is not available.\n",
pkt->name);
CL_ERROR(req, CL_E_SPAWNERR, pkt);
return (-1);
}
#ifndef CONFIG_PAR
DO_LOG(CL_LOG_ERROR, "PAR support is required for StartApp.\n");
CL_ERROR(req, CL_E_NOTIMPLEMENT, pkt);
return (-1);
#else
/* Add this to the pending list (Doing this here first avoids any timing issues with the fork) */
if (pkt->timeout >= 0) {
int to = 0;
if (pkt->timeout == 0)
to = -1;
else
to = pkt->timeout * 1000000;
pending = cl_AddPending(req, pkt->name, pkt->start_flags, to, pkt);
if (!pending) {
CL_ERROR(req, CL_E_APPERR, pkt);
return (-1);
}
SET_FLAG(req->cl_flags, CL_F_WAITING);
}
if (cl_chatty)
DO_LOG(CL_LOG_MESSAGE, "START [%s]: Application [%s]\n", req->cl_name,
pkt->name);
if (strlen(pkt->argstr))
result = local_spawnApp(pkt->name, pkt->argstr);
else
result = local_spawnApp(pkt->name, 0);
if (result == -1) {
if (pending)
cl_FreePending(pending);
CL_ERROR(req, CL_E_APPERR, pkt);
return (-1);
}
return (0);
#endif /* CONFIG_PAR */
}
int
cl_HandleFindApp(cl_app_struct * req, cl_pkt_findapp * pkt)
{
cl_app_struct *app = get_app_by_name(pkt->name);
if (cl_chatty)
DO_LOG(CL_LOG_MESSAGE, "FIND [%s]: Application [%s]\n", req->cl_name,
pkt->name);
if (app) {
pkt->ipc_id = app->cl_id;
cl_SendPacket(req, (cl_packet *) pkt, sizeof(cl_pkt_findapp));
return (0);
}
CL_ERROR(req, CL_E_NOAPP, pkt);
return (-1);
}
int
cl_HandleRegisterApp(cl_app_struct * req, cl_pkt_reg * pkt)
{
unsigned short flags = 0;
cl_pending_struct *pend;
cl_app_struct *old;
if ((old = get_app_by_name(pkt->name))) {
/* Ok, so thats a little strange. Either we */
/* have a stupid program that re-registered */
/* or the app crashed and we didn't know about it */
/* Send the error packet to the old socket. */
/* if it is successful, then we have a supid program */
/* otherwise, the socket is invalid, and we'll kill */
/* it automagically */
if (CL_ERROR(old, CL_E_APPEXISTS, pkt) == 0) {
CL_ERROR(req, CL_E_APPEXISTS, pkt);
return (-1);
}
/* The old client was removed, long live the new client */
}
/* Register the client and store the values */
cl_RegisterApp(req, pkt);
if (pkt->start_flags == CL_NORMAL_CLIENT)
SET_STATE(req->cl_flags, CL_F_ACTIVE);
else
SET_STATE(req->cl_flags, CL_F_RESTRICTED);
/* Now, check the pending list and see if we have been */
/* waiting for this app */
printf("CLSERVER: Registered [%s] as [%d]\n", pkt->name, req->cl_id);
pend = cl_SearchPending(pkt->name);
if (pend) {
pend->request.ipc_id = req->cl_id;
cl_SendPacket(pend->parent, (cl_packet *) & pend->request,
sizeof(cl_pkt_start));
flags = pend->flags;
cl_FreePending(pend);
}
pkt->ipc_id = req->cl_id;
pkt->start_flags = flags;
if (cl_chatty)
DO_LOG(CL_LOG_MESSAGE, "OPEN [%s]: IPC id [%d]\n", req->cl_name,
req->cl_id);
cl_SendPacket(req, (cl_packet *) pkt, sizeof(cl_pkt_reg));
return (0);
}
void
cl_CloseApp(cl_app_struct * app)
{
if (cl_chatty)
DO_LOG(CL_LOG_MESSAGE, "CLOSE [%s]: IPC id [%d]\n", app->cl_name,
app->cl_id);
if (app)
cl_FreeAppStruct(app);
}
--- NEW FILE: server.c ---
/*
* Copyright (c) 2003 Century Software, Inc. All Rights Reserved.
*
* This file is part of the PIXIL Operating Environment
*
* The use, copying and distribution of this file is governed by one
* of two licenses, the PIXIL Commercial License, or the GNU General
* Public License, version 2.
*
* Licensees holding a valid PIXIL Commercial License may use this file
* in accordance with the PIXIL Commercial License Agreement provided
* with the Software. Others are governed under the terms of the GNU
* General Public License version 2.
*
* This file may be distributed and/or modified under the terms of the
* GNU General Public License version 2 as published by the Free
* Software Foundation and appearing in the file LICENSE.GPL included
* in the packaging of this file.
*
* This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING
* THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE.
*
* RESTRICTED RIGHTS LEGEND
*
* Use, duplication, or disclosure by the government is subject to
* restriction as set forth in paragraph (b)(3)(b) of the Rights in
* Technical Data and Computer Software clause in DAR 7-104.9(a).
*
* See http://www.pixil.org/gpl/ for GPL licensing
* information.
*
* See http://www.pixil.org/license.html or
* email cetsales at centurysoftware.com for information about the PIXIL
* Commercial License Agreement, or if any conditions of this licensing
* are not clear to you.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>
#include <fcntl.h>
#include <syslog.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/un.h>
#include <pixil_config.h>
#include <ipc/colosseum.h>
#include "server.h"
#ifdef CONFIG_PAR
#include <par/par.h>
#endif
int cl_daemon = 0;
int cl_chatty = 0;
static int g_named_socket = 0;
static int g_ipc_id = 1;
#ifdef CONFIG_PAR
db_handle *parDB = 0;
db_handle *
cl_openDatabase(void)
{
db_handle *local = db_openDB(db_getDefaultDB(), PAR_DB_MODE_RDONLY);
return (local);
}
#endif
int
cl_GetNextId(void)
{
return (g_ipc_id++);
}
void
handleError(void)
{
int i;
char ch;
fd_set iset, oset, eset;
int ret = cl_GetClientSockets(&iset, &oset, &eset);
for (i = 0; i < ret + 1; i++) {
if (FD_ISSET(i, &iset)) {
if (read(i, &ch, 0) == -1)
DO_LOG(CL_LOG_ERROR, "Linux error [%s] on fd [%d]\n",
strerror(errno), i);
}
}
}
/* The critical loop */
int
local_DoServerLoop(void)
{
fd_set iset, oset, eset;
int i;
while (1) {
struct timeval slice, pre, post;
int maxfd = g_named_socket;
int ret = 0;
int timed = 0;
FD_ZERO(&iset);
FD_ZERO(&oset);
FD_ZERO(&eset);
/* Always watch the named socket */
FD_SET(g_named_socket, &iset);
ret = cl_GetClientSockets(&iset, &oset, &eset);
if (ret && ret > maxfd)
maxfd = ret;
/* Set the size of the timeslice */
if (cl_havePending()) {
timed = 1;
slice.tv_sec = 1;
slice.tv_usec = 0;
gettimeofday(&pre, 0);
ret = select(maxfd + 1, &iset, &oset, &eset, &slice);
gettimeofday(&post, 0);
} else {
ret = select(maxfd + 1, &iset, &oset, &eset, 0);
}
if (ret == -1) {
/* An EAGAIN or EINTR just forces an continue */
if (errno == EAGAIN || errno == EINTR)
continue;
perror("select");
handleError();
return (-1);
}
if (ret) {
/* First, check the server socket */
if (FD_ISSET(g_named_socket, &iset)) {
cl_HandleNewClient(g_named_socket);
}
/* Now process all of the client sockets */
for (i = 0; i <= maxfd; i++) {
if (i == g_named_socket)
continue;
/* Exception */
if (FD_ISSET(i, &eset)) {
cl_CloseClient(i);
continue; /* Nothing more to see here */
}
/* Read */
if (FD_ISSET(i, &iset)) {
if (cl_HandleClientReq(get_app_by_socket(i)))
continue;
}
/* Write */
if (FD_ISSET(i, &oset)) {
cl_HandleQueuedMessages(get_app_by_socket(i));
}
}
#ifdef NOTUSED
/* ** Exception handling ** */
/* An exception on any socket is grounds for explusion */
for (i = 0; i < maxfd; i++)
if (i != g_named_socket && FD_ISSET(i, &eset)) {
unregister_client(get_app_by_socket(i));
/* Make sure we don't try to read or write it */
FD_CLR(i, &iset);
FD_CLR(i, &oset);
}
/* ** Read handling ** */
for (i = 0; i <= maxfd; i++)
if (i != g_named_socket && FD_ISSET(i, &iset))
handle_client_request(get_app_by_socket(i));
/* ** Write handling ** */
for (i = 0; i <= maxfd; i++)
if (FD_ISSET(i, &oset))
cl_HandleQueuedMessages(get_app_by_socket(i));
#endif
}
if (timed && cl_havePending()) {
int lapsed = ((post.tv_sec - pre.tv_sec) * 1000000)
+ (post.tv_usec - pre.tv_usec);
cl_UpdatePending(lapsed);
}
}
}
void
handle_server_error(int signal)
{
if (signal < 0) {
DO_LOG(CL_LOG_ERROR, "Got internal error %d. Exiting.", signal);
} else {
DO_LOG(CL_LOG_MESSAGE, "Got signal %d. Exiting.", signal);
}
/* Try to gracefully leave */
cl_FreeAllApps();
#ifdef HAVE_LOGGING
cl_closeLog();
#endif
#ifdef CONFIG_PAR
if (parDB)
db_closeDB(parDB);
#endif
if (cl_daemon)
closelog();
close(g_named_socket);
/* 02/26/02 - Get rid of the named socket */
/* No reason to keep it around, right? */
unlink(CL_NAMED_SOCKET);
exit(0);
}
int
main(int argc, char **argv)
{
#ifdef HAVE_LOGGING
int loglevel = -1;
int temp = 0;
#endif
extern void cl_childHandler(int);
/* Set up the signals */
signal(SIGINT, handle_server_error);
signal(SIGQUIT, handle_server_error);
signal(SIGKILL, handle_server_error);
signal(SIGTERM, handle_server_error);
/* Handle the child */
signal(SIGCHLD, cl_childHandler);
signal(SIGPIPE, SIG_IGN);
while (1) {
signed char ch;
extern int optind, opterr;
extern char *optarg;
ch = getopt(argc, argv, "vhlcd::");
if (ch == -1)
break;
switch (ch) {
case 'v':
printf("Colosseum server version %s\n", CL_VERSION);
break;
case 'h':
printf("Usage:./clserver -[vh]\n");
printf("[-l #] start logging with optional threshold\n");
printf("[-h] Display this help\n");
printf("[-v] Print the version\n");
printf("[-d] Daemon mode - Run as a daemon\n");
printf
("[-c] Chatty mode - Show clients as they join and leave\n");
break;
case 'l':
#ifdef HAVE_LOGGING
/* Turn logging on */
loglevel = 2;
if (optarg)
temp = atoi(optarg);
if (temp != 0)
loglevel = temp;
printf("Starting system logging at level %d.\n", loglevel);
#else
fprintf(stderr,
"System logging is not compiled in. Ignoring!\n");
#endif
break;
case 'd':
cl_daemon = 1;
/* Fork us away - This will esentially make a connectionless client */
if (fork())
return (0);
/* Redirect the terminal */
close(0);
open("/dev/null", O_RDWR);
dup2(0, 1);
dup2(0, 2);
openlog("clserver", LOG_CONS, LOG_DAEMON);
break;
case 'c':
cl_chatty = 1;
break;
}
}
/* Start the server */
if ((g_named_socket = cl_InitServerSocket()) == -1) {
fprintf(stderr, "Error! Unable to bind to the socket\n");
handle_server_error(-1);
}
#ifdef HAVE_LOGGING
if (loglevel != -1) {
#ifdef CONFIG_PAR
parDB = cl_openDatabase();
#endif
cl_initLog(loglevel);
}
#endif
/* Finally, start the process loop. */
if (local_DoServerLoop()) {
fprintf(stderr, "local_DoServerLoop() returned unexpectedly\n");
handle_server_error(-1);
}
cl_FreeAllApps();
#ifdef HAVE_LOGGING
cl_closeLog();
#endif
#ifdef CONFIG_PAR
if (parDB)
db_closeDB(parDB);
#endif
if (cl_daemon)
closelog();
close(g_named_socket);
unlink(CL_NAMED_SOCKET);
exit(0);
}
--- NEW FILE: queue.c ---
/*
* Copyright (c) 2003 Century Software, Inc. All Rights Reserved.
*
* This file is part of the PIXIL Operating Environment
*
* The use, copying and distribution of this file is governed by one
* of two licenses, the PIXIL Commercial License, or the GNU General
* Public License, version 2.
*
* Licensees holding a valid PIXIL Commercial License may use this file
* in accordance with the PIXIL Commercial License Agreement provided
* with the Software. Others are governed under the terms of the GNU
* General Public License version 2.
*
* This file may be distributed and/or modified under the terms of the
* GNU General Public License version 2 as published by the Free
* Software Foundation and appearing in the file LICENSE.GPL included
* in the packaging of this file.
*
* This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING
* THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE.
*
* RESTRICTED RIGHTS LEGEND
*
* Use, duplication, or disclosure by the government is subject to
* restriction as set forth in paragraph (b)(3)(b) of the Rights in
* Technical Data and Computer Software clause in DAR 7-104.9(a).
*
* See http://www.pixil.org/gpl/ for GPL licensing
* information.
*
* See http://www.pixil.org/license.html or
* email cetsales at centurysoftware.com for information about the PIXIL
* Commercial License Agreement, or if any conditions of this licensing
* are not clear to you.
*/
#include <stdlib.h>
#include <ipc/colosseum.h>
#include "server.h"
int
queue_add_packet(cl_app_struct * app, cl_pkt_buff * pkt)
{
/* If the queue is full, then bail */
if (app->cl_queue.head == app->cl_queue.tail)
return (-1);
app->cl_queue.ring[app->cl_queue.head] = pkt;
app->cl_queue.head = (app->cl_queue.head + 1) % app->cl_queue.size;
return (0);
}
cl_pkt_buff *
queue_get_packet(cl_app_struct * app)
{
int next = (app->cl_queue.tail + 1) % app->cl_queue.size;
if (next == app->cl_queue.head)
return (0);
app->cl_queue.tail = next;
return (app->cl_queue.ring[next]);
}
cl_pkt_buff *
queue_peek_packet(cl_app_struct * app)
{
int next = (app->cl_queue.tail + 1) % app->cl_queue.size;
if (next == app->cl_queue.head)
return (0);
return (app->cl_queue.ring[next]);
}
int
data_in_queue(cl_app_struct * app)
{
int next = (app->cl_queue.tail + 1) % app->cl_queue.size;
if (next == app->cl_queue.head)
return (0);
else
return (1);
}
--- NEW FILE: packet.c ---
/*
* Copyright (c) 2003 Century Software, Inc. All Rights Reserved.
*
* This file is part of the PIXIL Operating Environment
*
* The use, copying and distribution of this file is governed by one
* of two licenses, the PIXIL Commercial License, or the GNU General
* Public License, version 2.
*
* Licensees holding a valid PIXIL Commercial License may use this file
* in accordance with the PIXIL Commercial License Agreement provided
* with the Software. Others are governed under the terms of the GNU
* General Public License version 2.
*
* This file may be distributed and/or modified under the terms of the
* GNU General Public License version 2 as published by the Free
* Software Foundation and appearing in the file LICENSE.GPL included
* in the packaging of this file.
*
* This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING
* THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE.
*
* RESTRICTED RIGHTS LEGEND
*
* Use, duplication, or disclosure by the government is subject to
* restriction as set forth in paragraph (b)(3)(b) of the Rights in
* Technical Data and Computer Software clause in DAR 7-104.9(a).
*
* See http://www.pixil.org/gpl/ for GPL licensing
* information.
*
* See http://www.pixil.org/license.html or
* email cetsales at centurysoftware.com for information about the PIXIL
* Commercial License Agreement, or if any conditions of this licensing
* are not clear to you.
*/
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <ipc/colosseum.h>
#include "server.h"
/* Actually write a packet out to the socket */
int
cl_SendError(cl_app_struct * app, int err, cl_packet * pkt, int len)
{
cl_pkt_header *head = &pkt->header;
head->resp = err;
return (cl_ClientWrite(app->cl_socket, (unsigned char *) pkt, len));
}
int
cl_SendPacket(cl_app_struct * app, cl_packet * pkt, int len)
{
cl_pkt_header *head = &pkt->header;
head->resp = 0;
return (cl_ClientWrite(app->cl_socket, (unsigned char *) pkt, len));
}
int
cl_HandleClientReq(cl_app_struct * app)
{
int result = -1;
cl_pkt_buff *data;
cl_packet *pkt;
if (!app)
return (-1);
if (cl_ClientRead(app->cl_socket, &data))
return (-1);
if (!data) {
DO_LOG(CL_LOG_ERROR, "Error - Bad cl_clientRead\n");
return (-1);
}
pkt = (cl_packet *) data->data;
DPRINT("IN (%s): Size [%d] Type [%d]\n", app->cl_name, pkt->header.len,
pkt->header.type);
switch (pkt->header.type) {
case CL_PKT_MESSAGE:
/* No error messages on send message for now */
#ifdef NOTUSED
if (!ISSET_FLAG(app->cl_flags, CL_F_ACTIVE))
CL_ERROR(app, CL_E_APPUNKWN, (cl_pkt_message *) & pkt->message);
else
#endif
result = cl_SendMessage(app, data);
break;
case CL_PKT_REGISTER:
/* This packet is an error if it is already active */
if (ISSET_FLAG(app->cl_flags, CL_F_ACTIVE))
CL_ERROR(app, CL_E_APPACTIVE, (cl_pkt_reg *) & pkt->reg);
else
result = cl_HandleRegisterApp(app, (cl_pkt_reg *) & pkt->reg);
break;
case CL_PKT_STARTAPP:
if (!ISSET_FLAG(app->cl_flags, CL_F_ACTIVE))
CL_ERROR(app, CL_E_APPUNKWN, (cl_pkt_start *) & pkt->start);
else
result = cl_HandleStartApp(app, (cl_pkt_start *) & pkt->start);
break;
case CL_PKT_SPAWNAPP:
result = cl_HandleSpawnApp(app, (cl_pkt_spawn *) & pkt->spawn);
break;
case CL_PKT_APP_INFO:
result = cl_HandleAppInfo(app, (cl_pkt_appinfo *) & pkt->appinfo);
break;
case CL_PKT_FINDAPP:
if (!ISSET_FLAG(app->cl_flags, CL_F_ACTIVE))
CL_ERROR(app, CL_E_APPUNKWN, (cl_pkt_findapp *) & pkt->findapp);
else
result = cl_HandleFindApp(app, (cl_pkt_findapp *) & pkt->findapp);
break;
#ifdef HAVE_LOGGING
case CL_PKT_LOG:{
cl_pkt_log *log = &pkt->log;
cl_doLog(log->level, app->cl_name, log->message);
}
break;
#endif
default:
DO_LOG(CL_LOG_MESSAGE, "Unknown IPC packet %d\n", pkt->header.type);
CL_ERROR(app, CL_E_BADCMD, pkt);
break;
}
if (result != 1)
pkt_buff_free(data);
return (0); /* No fatal errors, so return 0 */
}
--- NEW FILE: list.c ---
/*
* Copyright (c) 2003 Century Software, Inc. All Rights Reserved.
*
* This file is part of the PIXIL Operating Environment
*
* The use, copying and distribution of this file is governed by one
* of two licenses, the PIXIL Commercial License, or the GNU General
* Public License, version 2.
*
* Licensees holding a valid PIXIL Commercial License may use this file
* in accordance with the PIXIL Commercial License Agreement provided
* with the Software. Others are governed under the terms of the GNU
* General Public License version 2.
*
* This file may be distributed and/or modified under the terms of the
* GNU General Public License version 2 as published by the Free
* Software Foundation and appearing in the file LICENSE.GPL included
* in the packaging of this file.
*
* This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING
* THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE.
*
* RESTRICTED RIGHTS LEGEND
*
* Use, duplication, or disclosure by the government is subject to
* restriction as set forth in paragraph (b)(3)(b) of the Rights in
* Technical Data and Computer Software clause in DAR 7-104.9(a).
*
* See http://www.pixil.org/gpl/ for GPL licensing
* information.
*
* See http://www.pixil.org/license.html or
* email cetsales at centurysoftware.com for information about the PIXIL
* Commercial License Agreement, or if any conditions of this licensing
* are not clear to you.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <ipc/colosseum.h>
#include "server.h"
/* The master list of application structures */
static cl_app_struct *cl_main_list = 0;
/* A table hashed against the socket number */
static cl_app_struct *cl_socket_hash[CL_HASH_SIZE];
/* A table hashed against the IPC id */
static cl_app_struct *cl_id_hash[CL_HASH_SIZE];
/* A table hashed against the checksum of the name */
static cl_app_struct *cl_name_hash[CL_HASH_SIZE];
/* The pool of currently allocated packet buffers */
static cl_pkt_buff *cl_pkt_pool = 0;
/* The list of currently allocated pids */
static cl_pid_t *pidList = 0;
/* A local function that "checksums" the name */
/* for hashing purposes */
static int
encode_name(unsigned char *name)
{
unsigned char *ptr = name;
unsigned char ch = 0;
while (*ptr)
ch += *ptr++;
return (ch);
}
/* Given a list head and a index, add the specified item to the list */
static void
add_to_list(cl_app_struct ** head, int lindex, cl_app_struct * item)
{
if (!*head) {
*head = item;
item->listptr[lindex] = 0;
} else {
cl_app_struct *ptr = *head;
while (ptr->listptr[lindex])
ptr = ptr->listptr[lindex];
ptr->listptr[lindex] = item;
item->listptr[lindex] = 0;
}
}
static void
remove_from_list(cl_app_struct ** head, int lindex, cl_app_struct * item)
{
cl_app_struct *ptr = *head;
cl_app_struct *prev = 0;
while (ptr) {
if (ptr == item) {
if (!prev)
*head = ptr->listptr[lindex];
else
prev->listptr[lindex] = ptr->listptr[lindex];
return;
}
prev = ptr;
ptr = ptr->listptr[lindex];
}
}
/* These small functions add a new item to the specified list/hash */
static void
add_to_socket(cl_app_struct * item)
{
int index = item->cl_socket % CL_HASH_SIZE;
add_to_list(&cl_socket_hash[index], CL_LIST_SOCKET, item);
}
static void
add_to_id(cl_app_struct * item)
{
int index = item->cl_id % CL_HASH_SIZE;
add_to_list(&cl_id_hash[index], CL_LIST_ID, item);
}
static void
add_to_name(cl_app_struct * item)
{
int index = encode_name(item->cl_name) % CL_HASH_SIZE;
add_to_list(&cl_name_hash[index], CL_LIST_NAME, item);
}
/* Thse small functions remove a item from the specified hash/list */
static void
remove_from_socket(cl_app_struct * item)
{
int index = item->cl_socket % CL_HASH_SIZE;
remove_from_list(&cl_socket_hash[index], CL_LIST_SOCKET, item);
}
static void
remove_from_id(cl_app_struct * item)
{
int index = item->cl_id % CL_HASH_SIZE;
remove_from_list(&cl_id_hash[index], CL_LIST_ID, item);
}
static void
remove_from_name(cl_app_struct * item)
{
int index = encode_name(item->cl_name) % CL_HASH_SIZE;
remove_from_list(&cl_name_hash[index], CL_LIST_NAME, item);
}
/* Allocate a brand new client structure in all its glory */
static cl_app_struct *
local_AllocAppStruct(void)
{
cl_app_struct *head = cl_main_list;
cl_app_struct *ptr;
/* Allocate it (zeroed out) */
if (!head)
ptr = cl_main_list =
(cl_app_struct *) calloc(sizeof(cl_app_struct), 1);
else {
while (head->listptr[CL_LIST_MAIN])
head = head->listptr[CL_LIST_MAIN];
ptr = head->listptr[CL_LIST_MAIN] =
(cl_app_struct *) calloc(sizeof(cl_app_struct), 1);
}
ptr->cl_queue.head = 1;
ptr->cl_queue.size = CL_QUEUE_SIZE;
return (ptr);
}
void
cl_FreeAppStruct(cl_app_struct * app)
{
cl_app_struct *ptr = cl_main_list;
cl_app_struct *prev = 0;
cl_pkt_buff *pkt;
/* First, make sure it is removed from all of the lists */
remove_from_socket(app);
remove_from_name(app);
remove_from_id(app);
/* Make sure that the queue is freed */
while ((pkt = queue_get_packet(app)))
pkt_buff_free(pkt);
/* Now remove it from the main list */
while (ptr) {
if (ptr == app) {
if (!prev)
cl_main_list = ptr->listptr[CL_LIST_MAIN];
else
prev->listptr[CL_LIST_MAIN] = ptr->listptr[CL_LIST_MAIN];
free(app);
return;
}
prev = ptr;
ptr = ptr->listptr[CL_LIST_MAIN];
}
}
/* This function fills a number of FD sets with the appropriate */
/* socket numbers, returning the highest FD found */
int
cl_GetClientSockets(fd_set * in, fd_set * out, fd_set * exp)
{
int max = 0;
cl_app_struct *head = cl_main_list;
if (!cl_main_list)
return (0);
while (head) {
FD_SET(head->cl_socket, in); /* Listen on all incoming ports */
FD_SET(head->cl_socket, exp); /* Look for exceptions on all ports */
if (head->cl_flags & CL_F_QUEUE_MSG)
FD_SET(head->cl_socket, out);
if (head->cl_socket > max)
max = head->cl_socket;
head = head->listptr[CL_LIST_MAIN];
}
return (max);
}
cl_app_struct *
cl_AllocNewApp(int sock)
{
cl_app_struct *app = local_AllocAppStruct();
if (!app)
return (0);
app->cl_socket = sock;
SET_STATE(app->cl_flags, CL_F_NEW);
/* Add it to the socket hash table (for easy search) */
add_to_socket(app);
return (app);
}
void
cl_RegisterApp(cl_app_struct * app, cl_pkt_reg * data)
{
/* Store all the approprate data */
strcpy(app->cl_name, data->name);
app->cl_id = cl_GetNextId();
/* Insert the new item into the two main hash tables */
add_to_id(app);
add_to_name(app);
}
void
cl_FreeAllApps(void)
{
cl_app_struct *lhead = cl_main_list;
cl_pkt_buff *phead = cl_pkt_pool;
/* Unregister all of the apps */
while (lhead) {
cl_app_struct *next = lhead->listptr[CL_LIST_MAIN];
cl_CloseClient(lhead->cl_socket);
lhead = next;
}
/* Make sure any pending buffers are freed */
while (phead) {
cl_pkt_buff *next = phead->next;
pkt_buff_free(phead);
phead = next;
}
}
cl_app_struct *
get_first_app(void)
{
return (cl_main_list);
}
cl_app_struct *
get_next_app(cl_app_struct * prev)
{
if (prev)
return (prev->listptr[CL_LIST_MAIN]);
else
return (0);
}
cl_app_struct *
get_app_by_name(unsigned char *name)
{
int index = encode_name(name) % CL_HASH_SIZE;
cl_app_struct *head = cl_name_hash[index];
while (head) {
if (!strcmp(head->cl_name, name))
return (head);
head = head->listptr[CL_LIST_NAME];
}
return (0);
}
cl_app_struct *
get_app_by_socket(int sock)
{
int index = sock % CL_HASH_SIZE;
cl_app_struct *head = cl_socket_hash[index];
while (head) {
if (head->cl_socket == sock)
return (head);
head = head->listptr[CL_LIST_SOCKET];
}
return (0);
}
cl_app_struct *
get_app_by_id(int id)
{
int index = id % CL_HASH_SIZE;
cl_app_struct *head = cl_id_hash[index];
while (head) {
if (head->cl_id == id)
return (head);
head = head->listptr[CL_LIST_ID];
}
return (0);
}
cl_pkt_buff *
pkt_buff_alloc(void *data, int len)
{
cl_pkt_buff *head = cl_pkt_pool;
cl_pkt_buff *ptr;
if (!head)
ptr = cl_pkt_pool = (cl_pkt_buff *) malloc(sizeof(cl_pkt_buff));
else {
while (head->next)
head = head->next;
ptr = head->next = (cl_pkt_buff *) malloc(sizeof(cl_pkt_buff));
}
if (!ptr)
return (0);
if (!(ptr->data = (void *) malloc(len))) {
free(ptr);
return (0);
}
memcpy(ptr->data, data, len);
ptr->len = len;
ptr->next = 0;
/* Owners keeps track of how many entities are holding */
/* this structure */
ptr->owners = 0;
return (ptr);
}
void
pkt_buff_free(cl_pkt_buff * pkt)
{
cl_pkt_buff *head = cl_pkt_pool;
cl_pkt_buff *prev = 0;
if (--pkt->owners > 1)
return; /* Don't free it until everyone has signed off */
while (head) {
if (head == pkt) {
if (prev == 0)
cl_pkt_pool = head->next;
else
prev->next = head->next;
if (head->data)
free(head->data);
free(head);
return;
}
head = head->next;
}
}
/* These functions help manage pending lists */
static cl_pending_struct *cl_pending_list = 0;
cl_pending_struct *
cl_AllocPending(void)
{
cl_pending_struct *head = cl_pending_list;
cl_pending_struct *ptr = 0;
if (!head)
ptr = cl_pending_list = calloc(sizeof(cl_pending_struct), 1);
else {
while (head->next)
head = head->next;
ptr = head->next = calloc(sizeof(cl_pending_struct), 1);
}
return (ptr);
}
int
cl_havePending(void)
{
return ((cl_pending_list == 0) ? 0 : 1);
}
#ifdef NOTUSED
int
cl_havePending(void)
{
return (0);
}
#endif
void
cl_FreePending(cl_pending_struct * pend)
{
cl_pending_struct *head = cl_pending_list;
cl_pending_struct *prev = 0;
while (head) {
if (head == pend) {
if (!prev)
cl_pending_list = head->next;
else
prev->next = head->next;
free(head);
return;
}
head = head->next;
}
}
/* Update each pending app */
void
cl_UpdatePending(int elapsed)
{
cl_pending_struct *ptr = cl_pending_list;
while (ptr) {
cl_pending_struct *next = ptr->next;
if (ptr->timeout != -1) {
ptr->timeout = ptr->timeout - elapsed;
if (ptr->timeout <= 0) {
CL_ERROR(ptr->parent, CL_E_TIMEOUT, &ptr->request);
cl_FreePending(ptr);
}
}
ptr = next;
}
}
cl_pending_struct *
cl_SearchPending(unsigned char *name)
{
cl_pending_struct *head = cl_pending_list;
while (head) {
if (!strcmp(head->name, name))
return (head);
head = head->next;
}
return (0);
}
void
cl_printAppList(void)
{
cl_app_struct *head = cl_main_list;
while (head) {
head = head->listptr[CL_LIST_MAIN];
}
}
/* The pid list is maintained both on disk and in RAM */
/* this is just an easy way see if we have an app already running */
cl_pid_t *
cl_addPid(char *name, int pidnum)
{
/* Allocate a structure for RAM */
cl_pid_t *pid = (cl_pid_t *) calloc(sizeof(cl_pid_t), 1);
if (!pid)
return (0);
if (!pidList)
pidList = pid;
else {
cl_pid_t *p = pidList;
while (p->next)
p = p->next;
p->next = pid;
}
strncpy(pid->name, name, sizeof(pid->name));
pid->pid = pidnum;
#ifdef DEBUG
fprintf(stderr,
"DEBUG: Added pid %d (%s) to the list...\n", pidnum, pid->name);
#endif
return (pid);
}
cl_pid_t *
cl_findPid(int pidnum)
{
cl_pid_t *pid = pidList;
#ifdef DEBUG
fprintf(stderr, "DEBUG: Looking for pid %d...", pidnum);
#endif
while (pid) {
if (pid->pid == pidnum) {
#ifdef DEBUG
fprintf(stderr, "DEBUG: pid %d found\n", pidnum);
#endif
return (pid);
}
pid = pid->next;
}
#ifdef DEBUG
fprintf(stderr, "DEBUG: pid %d not found\n", pidnum);
#endif
return (0);
}
void
cl_removePid(int pidnum)
{
cl_pid_t *prev = 0, *pid = pidList;
/* Remove it from the list */
while (pid) {
if (pid->pid == pidnum) {
if (prev)
prev->next = pid->next;
else
pidList = pid->next;
break;
}
prev = pid;
pid = pid->next;
}
#ifdef DEBUG
fprintf(stderr,
"DEBUG: Removed pid %d (%s) from the list...\n", pidnum,
pid->name);
#endif
if (pid)
free(pid);
}
cl_pid_t *
cl_findPidByName(char *app)
{
cl_pid_t *pid = pidList;
if (!app)
return (0);
#ifdef DEBUG
fprintf(stderr, "DEBUG: Looking for app %s...", app);
#endif
while (pid) {
if (strcmp(app, pid->name) == 0) {
#ifdef DEBUG
fprintf(stderr, "DEBUG: App %s is found\n", app);
#endif
return (pid);
}
pid = pid->next;
}
#ifdef DEBUG
fprintf(stderr, "DEBUG: App %s not found\n", app);
#endif
return (0);
}
cl_pid_t *
cl_findNameByPid(int pidnum)
{
cl_pid_t *pid = pidList;
if (!pidnum)
return (0);
while (pid) {
if (pid->pid == pidnum)
return (pid);
pid = pid->next;
}
return (0);
}
--- NEW FILE: Makefile ---
#ipc/server/Makefile
TARGET=clserver
INSTALL_BINDIR=$(INSTALL_DIR)/sbin
SRC=${shell ls *.c}
OBJS=${SRC:.c=.o}
LIBS=
ifeq ($(CONFIG_PAR),y)
LIBS+=-lpar
endif
include $(BASE_DIR)/Rules.make
--- NEW FILE: log.c ---
/*
* Copyright (c) 2003 Century Software, Inc. All Rights Reserved.
*
* This file is part of the PIXIL Operating Environment
*
* The use, copying and distribution of this file is governed by one
* of two licenses, the PIXIL Commercial License, or the GNU General
* Public License, version 2.
*
* Licensees holding a valid PIXIL Commercial License may use this file
* in accordance with the PIXIL Commercial License Agreement provided
* with the Software. Others are governed under the terms of the GNU
* General Public License version 2.
*
* This file may be distributed and/or modified under the terms of the
* GNU General Public License version 2 as published by the Free
* Software Foundation and appearing in the file LICENSE.GPL included
* in the packaging of this file.
*
* This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING
* THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE.
*
* RESTRICTED RIGHTS LEGEND
*
* Use, duplication, or disclosure by the government is subject to
* restriction as set forth in paragraph (b)(3)(b) of the Rights in
* Technical Data and Computer Software clause in DAR 7-104.9(a).
*
* See http://www.pixil.org/gpl/ for GPL licensing
* information.
*
* See http://www.pixil.org/license.html or
* email cetsales at centurysoftware.com for information about the PIXIL
* Commercial License Agreement, or if any conditions of this licensing
* are not clear to you.
*/
#include <syslog.h>
#include <string.h>
#include <ipc/colosseum.h>
#include "server.h"
extern int cl_daemon;
#ifdef HAVE_LOGGING
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#ifdef CONFIG_PAR
#include <par/par.h>
extern db_handle *parDB;
#endif
static int cl_logLevel = 0;
static FILE *cl_logArray[CL_LEVEL_COUNT] = { 0, 0, 0, 0 };
/* Given a level and a filename, open a stream to that log */
/* If multiple files try to open the same filename, this may */
/* be inefficient, but I believe it still works */
static char *cl_defLogFiles[] = { "/var/log/pixil_critical.log",
"/var/log/pixil_error.log",
"/var/log/pixil_message.log",
"/var/log/pixil_debug.log"
};
#ifdef CONFIG_PAR
static char *cl_levelNames[] = { "critical", "error", "message", "debug" };
#endif
static int
local_openLogFile(int level)
{
char filename[512];
#ifdef CONFIG_PAR
if (!parDB)
strcpy(filename, cl_defLogFiles[level]);
else {
if (par_getGlobalPref(parDB, "syslog", cl_levelNames[level],
PAR_TEXT, filename, sizeof(filename)) == -1)
strcpy(filename, cl_defLogFiles[level]);
}
#else
strcpy(filename, cl_defLogFiles[level]);
#endif
if (level >= CL_LEVEL_COUNT)
return (-1);
if (cl_logArray[level]) {
fprintf(stderr, "Warning - Log file %s already opened\n", filename);
return (-1);
}
cl_logArray[level] = fopen(filename, "a");
if (cl_logArray[level] == 0)
fprintf(stderr, "Unable to open the log file!\n");
return ((cl_logArray[level] == 0) ? -1 : 0);
}
static int
local_closeLogFile(int level)
{
if (cl_logArray[level])
fclose(cl_logArray[level]);
cl_logArray[level] = 0;
return (0);
}
int
cl_initLog(int level)
{
int i;
/* Establish the new level */
cl_logLevel = level;
for (i = 0; i < CL_LEVEL_COUNT; i++) {
if (i > cl_logLevel)
break;
local_openLogFile(i);
}
return (0);
}
int
cl_changeLevel(int new)
{
int i;
if (new == cl_logLevel)
return (0);
/* If the new level is lower than the previous level */
/* close the files that are no longer needed */
/* Otherwise, open up any new files that are needed */
if (new < cl_logLevel) {
for (i = new; i <= cl_logLevel; i++)
local_closeLogFile(i);
} else {
for (i = cl_logLevel; i <= new; i++)
local_openLogFile(i);
}
cl_logLevel = new;
return (0);
}
/* Format: MM/DD HH:MM LEV <message> */
int
cl_doLog(int level, char *app, char *message, ...)
{
va_list ap;
time_t t;
struct tm *tv;
if (level >= CL_LEVEL_COUNT)
return (-1);
if (!cl_logArray[level])
return (-1);
/* Thresholding */
if (level >= cl_logLevel)
return (0);
/* First, print out the time/date */
t = time(0);
tv = localtime(&t);
fprintf(cl_logArray[level], "%2.2d/%2.2d %2.2d:%2.2d ",
tv->tm_mon, tv->tm_mday, tv->tm_hour, tv->tm_min);
/* Next, print out the log level of this message */
switch (level) {
case CL_LOG_CRITICAL:
fprintf(cl_logArray[level], "CRI ");
break;
case CL_LOG_ERROR:
fprintf(cl_logArray[level], "ERR ");
break;
case CL_LOG_MESSAGE:
fprintf(cl_logArray[level], "MSG ");
break;
case CL_LOG_DEBUG:
fprintf(cl_logArray[level], "DBG ");
break;
}
/* Next, print the application name */
fprintf(cl_logArray[level], "%5s: ", app);
/* lastly, print the message */
va_start(ap, message);
vfprintf(cl_logArray[level], message, ap);
va_end(ap);
/* Add a carrige return at the end */
fprintf(cl_logArray[level], "\n");
/* If we got an error at all, then close the log */
if (ferror(cl_logArray[level])) {
fclose(cl_logArray[level]);
cl_logArray[level] = 0;
}
return (0);
}
void
cl_closeLog(void)
{
int i;
for (i = 0; i < CL_LEVEL_COUNT; i++)
local_closeLogFile(i);
}
#else /* HAVE_LOGGING */
#include <stdarg.h>
#include <stdio.h>
#ifdef DEBUG
static int cl_logLevel = CL_LOG_DEBUG;
#else
static int cl_logLevel = CL_LOG_MESSAGE;
#endif
int
cl_initLog(void)
{
return (0);
}
void
cl_closeLog(void)
{
}
int
cl_doLog(int level, char *app, char *message, ...)
{
va_list ap;
if (level > cl_logLevel)
return (0);
/* If we are in daemon mode, then we have no controlling deamon */
/* Redirect our stuff to syslog instead */
/* ARGH! */
va_start(ap, message);
if (cl_daemon) {
char str[255];
vsnprintf(str, 255, message, ap);
switch (level) {
case CL_LOG_CRITICAL:
case CL_LOG_ERROR:
syslog(LOG_ERR, str);
break;
case CL_LOG_MESSAGE:
syslog(LOG_INFO, str);
break;
case CL_LOG_DEBUG:
syslog(LOG_DEBUG, str);
break;
}
} else {
printf("%s:", app);
vprintf(message, ap);
if (message[strlen(message) - 1] != '\n')
printf("\n");
}
va_end(ap);
return (0);
}
#endif /* HAVE_LOGGING */
--- NEW FILE: server.h ---
/*
* Copyright (c) 2003 Century Software, Inc. All Rights Reserved.
*
* This file is part of the PIXIL Operating Environment
*
* The use, copying and distribution of this file is governed by one
* of two licenses, the PIXIL Commercial License, or the GNU General
* Public License, version 2.
*
* Licensees holding a valid PIXIL Commercial License may use this file
* in accordance with the PIXIL Commercial License Agreement provided
* with the Software. Others are governed under the terms of the GNU
* General Public License version 2.
*
* This file may be distributed and/or modified under the terms of the
* GNU General Public License version 2 as published by the Free
* Software Foundation and appearing in the file LICENSE.GPL included
* in the packaging of this file.
*
* This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING
* THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE.
*
* RESTRICTED RIGHTS LEGEND
*
* Use, duplication, or disclosure by the government is subject to
* restriction as set forth in paragraph (b)(3)(b) of the Rights in
* Technical Data and Computer Software clause in DAR 7-104.9(a).
*
* See http://www.pixil.org/gpl/ for GPL licensing
* information.
*
* See http://www.pixil.org/license.html or
* email cetsales at centurysoftware.com for information about the PIXIL
* Commercial License Agreement, or if any conditions of this licensing
* are not clear to you.
*/
#ifndef _SERVER_H_
#define _SERVER_H_
#include <sys/time.h>
#ifdef DEBUG
#define DPRINT(str, args...) printf("DEBUG: " str, ## args)
#else
#define DPRINT(str, args...)
#endif
#define CL_HASH_SIZE 256
#define CL_QUEUE_SIZE 5
/* This is a pkt buff that we use to shuttle packets around
internally
*/
typedef struct cl_pkt_t
{
unsigned short len;
void *data;
int owners;
struct cl_pkt_t *next;
}
cl_pkt_buff;
/* Copious notes follow */
typedef struct cl_app_t
{
unsigned char cl_name[CL_MAX_NAME_LEN + 1]; /* The unique name of the app */
unsigned short cl_socket; /* The socket the app is attached to */
unsigned short cl_id; /* The ipc ID assigned to the app */
unsigned char cl_flags; /* Various flags */
/* every app can have a queue of waiting packets */
struct
{
unsigned char head; /* Head of the ring queue */
unsigned char tail; /* Tail of the ring queue */
unsigned char size; /* Size of the queue */
/* I am anticipating a day when the size of the queue */
/* will be dynamic */
cl_pkt_buff *ring[CL_QUEUE_SIZE];
}
cl_queue;
/* Because we use the same structure in several different */
/* lists and hashes, I thought it would just be easier to */
/* have an array with the pointers here instead of */
/* allocating tiny structures for each list. This is */
/* either genius or stupidity. You decide. */
struct cl_app_t *listptr[4];
}
cl_app_struct;
typedef struct cl_pending_t
{
cl_app_struct *parent;
unsigned char flags;
int timeout;
struct cl_pending_t *next;
unsigned char name[CL_MAX_NAME_LEN + 1];
cl_pkt_start request;
}
cl_pending_struct;
typedef struct cl_pid
{
unsigned char name[CL_MAX_NAME_LEN + 1];
int pid;
struct cl_pid *next;
}
cl_pid_t;
/* These are the names for each of the lists that the cl_app_struct */
/* cal be a part of */
#define CL_LIST_MAIN 0
#define CL_LIST_SOCKET 1
#define CL_LIST_NAME 2
#define CL_LIST_ID 3
/* Status flags */
#define CL_F_STATE_MASK 0x0F
#define CL_F_NEW 0x01
#define CL_F_ACTIVE 0x02
#define CL_F_PENDING 0x04
#define CL_F_QUEUE_MSG 0x10
#define CL_F_WAITING 0x12
#define CL_F_RESTRICTED 0x14
#define SET_STATE(flags, state) (flags = (flags & ~CL_F_STATE_MASK) | state)
#define SET_FLAG(flags, state) (flags |= state)
#define CLEAR_FLAG(flags, state) (flags &= ~state)
#define ISSET_FLAG(flags, state) (flags & state)
/* Prototypes */
/* Socket / Client functions */
int cl_InitServerSocket(void);
int cl_HandleNewClient(int);
int cl_ClientWrite(int, unsigned char *, int);
int cl_ClientRead(int, cl_pkt_buff **);
int cl_GetClientSockets(fd_set *, fd_set *, fd_set *);
void cl_CloseClient(int);
/* Packet functions */
int cl_SendError(cl_app_struct *, int, cl_packet *, int);
int cl_SendPacket(cl_app_struct *, cl_packet *, int);
int cl_SendMessage(cl_app_struct *, cl_pkt_buff *);
/* Searching functions */
cl_app_struct *get_app_by_name(unsigned char *);
cl_app_struct *get_app_by_id(int);
cl_app_struct *get_app_by_socket(int);
cl_app_struct *get_first_app(void);
cl_app_struct *get_next_app(cl_app_struct *);
/* Queue functions */
int queue_add_packet(cl_app_struct *, cl_pkt_buff *);
cl_pkt_buff *queue_get_packet(cl_app_struct *);
cl_pkt_buff *queue_peek_packet(cl_app_struct * app);
int data_in_queue(cl_app_struct * app);
/* Packet buffer functions */
cl_pkt_buff *pkt_buff_alloc(void *, int);
void pkt_buff_free(cl_pkt_buff *);
/* Application structure functions */
cl_app_struct *cl_AllocNewApp(int);
void cl_RegisterApp(cl_app_struct * app, cl_pkt_reg * data);
void cl_FreeAppStruct(cl_app_struct *);
void cl_FreeAllApps(void);
void cl_CloseApp(cl_app_struct * app);
/* Pending structure functions */
cl_pending_struct *cl_AllocPending(void);
void cl_FreePending(cl_pending_struct *);
void cl_UpdatePending(int);
cl_pending_struct *cl_SearchPending(unsigned char *);
int cl_havePending(void);
/* Packet handling functions */
/* FIXME: In the future, we should move to a structure better */
/* suited for handling lots of different kinds of packets */
int cl_HandleClientReq(cl_app_struct *);
int cl_HandleRegisterApp(cl_app_struct *, cl_pkt_reg *);
int cl_HandleStartApp(cl_app_struct *, cl_pkt_start *);
int cl_HandleFindApp(cl_app_struct *, cl_pkt_findapp *);
int cl_HandleSpawnApp(cl_app_struct * req, cl_pkt_spawn * pkt);
int cl_HandleAppInfo(cl_app_struct * req, cl_pkt_appinfo * pkt);
int cl_HandleQueuedMessages(cl_app_struct *);
/* PID functions */
cl_pid_t *cl_addPid(char *name, int pidnum);
cl_pid_t *cl_findPid(int pidnum);
void cl_removePid(int pidnum);
cl_pid_t *cl_findPidByName(char *app);
cl_pid_t *cl_findNameByPid(int pidnum);
/* Misc functions */
int cl_GetNextId(void);
int cl_doLog(int level, char *app, char *message, ...);
#ifdef HAVE_LOGGING
int cl_initLog(int level);
int cl_changeLevel(int new);
void cl_closeLog(void);
#endif
#define DO_LOG(level, message, args...) cl_doLog(level, "clserver", message, ## args)
/* Several assistance macros to make life easier */
#define CL_ERROR(app, err, pkt) (cl_SendError(app, err, (cl_packet *) pkt, sizeof(*pkt)))
#define PKT_BUFF_ADD_OWNER(pkt) (pkt->owners++)
#endif /* _SERVER_H_ */
More information about the dslinux-commit
mailing list