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(&parapp, 0, sizeof(parapp));

    if (par_getApplication(parDB, name, &parapp) == -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