mbb.c revision 3f54fd611f536639ec30dd53c48e5ec1897cc7d9
/***********************************************************************
* *
* This software is part of the ast package *
* Copyright (c) 1990-2011 AT&T Intellectual Property *
* and is licensed under the *
* Eclipse Public License, Version 1.0 *
* by AT&T Intellectual Property *
* *
* A copy of the License is available at *
* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
* *
* Information and Software Systems Research *
* AT&T Research *
* Florham Park NJ *
* *
* Glenn Fowler <gsf@research.att.com> *
* *
***********************************************************************/
#pragma prototyped
/*
* Glenn Fowler
* AT&T Research
*/
static const char usage[] =
"[-?\n@(#)$Id: mbb (AT&T Research) 2000-05-09 $\n]"
"[+NAME?mbb - message bulletin board server]"
"[+DESCRIPTION?\bmbb\b is a message bulletin board server. Each \bmbb\b"
" instance is a session. Each session supports up to 64 message"
" channels, labeled from 0 to 63. A client connects to \bmbb\b and"
" provides a mask of channels that it is interested in. All subsequent"
" messages in the mask are sent to the client. Channel 0 is reserved"
" for service control messages.]"
"[+?A message is a newline terminated line with length 8K bytes max"
" that does not contain the ASCII NUL character. A message must"
" be prefixed by its channel number. The server changes this to"
" \achannel\a.\aid\a where \aid\a is the server assigned client"
" identification number. Messages with invalid or missing channel"
" numbers are silently rejected.]"
"[b:backlog?Every \an\ath client message with length > 1 will be treated as"
" if only half the data were sent. This should kick in the message"
" backlog logic.]#[n]"
"[d:debug?Set the debug trace level to \alevel\a. Higher levels produce more"
" output.]#[level]"
"[t:timeout?The service will exit after a \atime\a period of client"
" inactivity. The default is to run until the system crashes.]:[time]"
"\n"
"\nconnect-stream\n"
"\n"
"[+PROTOCOL?Channel 0 is for service control messages. The server and clients"
" may send messages on channel 0, with the exception that client"
" messages on channel 0 are not sent to the other clients. The control"
" messages are:]{"
" [+0 listen \amask\a?[client]] The client is interested in"
" channel numbers in the bitmask \amask\a. The default"
" \amask\a is \b0xfffffffffffffffe\b; i.e., all but"
" channel 0.]"
" [+0 join \aid\a?[server]] Client with server assigned id"
" number \aid\a has joined the session.]"
" [+0 drop \aid\a?[server]] Client with server assigned id"
" number \aid\a has dropped from the session.]"
" }"
"[+SEE ALSO?\bcoshell\b(1), \bcs\b(1), \bss\b(1), \bcs\b(3)]"
;
#include <css.h>
#include <ctype.h>
#include <debug.h>
#include <error.h>
#include <ls.h>
#include <stdarg.h>
typedef struct Log_s
{
} Log_t;
typedef struct Connection_s
{
struct Connection_s* next;
} Connection_t;
typedef struct State_s
{
int backlog;
int count;
int log;
int logged;
} State_t;
#define ALL (-1)
#define CHAN_VALID(c) ((c)>=0&&(c)<=63)
static ssize_t
{
{
n /= 2;
}
}
static int
{
ssize_t z;
{
{
{
}
}
{
}
message((-1, "[%d] %s: %d offset %I*d", __LINE__, state->logs[log].name, to->fp->fd, sizeof(to->blocked[log]), to->blocked[log]));
return 0;
}
{
{
}
}
return 1;
}
static int
{
char* s;
size_t n;
int r;
if (n > CHUNK)
n = CHUNK;
error(ERROR_SYSTEM|3, "%s: cannot seek to %I*d", state->logs[log].name, sizeof(con->blocked[log]), con->blocked[log]);
message((-1, "[%d] %s reserve n %I*d offset %I*d", __LINE__, state->logs[log].name, sizeof(n), n, sizeof(con->blocked[log]), con->blocked[log]));
error(ERROR_SYSTEM|3, "%s: cannot reserve %d at %I*d", state->logs[log].name, sizeof(n), n, sizeof(con->blocked[log]), con->blocked[log]);
if (state->logs[log].sp && sfseek(state->logs[log].sp, state->logs[log].offset, SEEK_SET) != state->logs[log].offset)
error(ERROR_SYSTEM|3, "%s: cannot seek to %I*d", state->logs[log].name, sizeof(state->logs[log].offset), state->logs[log].offset);
return r;
}
static int
post(Css_t* css, Cssdisc_t* disc, Connection_t* from, register Connection_t* to, int channel, const char* format, ...)
{
char* s;
ssize_t n;
Sfulong_t m;
if (from)
if (!to)
{
}
return 0;
}
static void
{
register Connection_t* cp;
register Connection_t* pp;
pp = 0;
{
if (pp)
else
break;
}
}
static int
{
register Connection_t* con;
int i;
return -1;
}
static int
{
register Connection_t* con;
register char* s;
char* e;
int n;
int c;
Sfulong_t m;
Sfulong_t o;
{
case CS_POLL_CLOSE:
return -1;
return 0;
case CS_POLL_READ:
return -1;
{
return -1;
}
n--;
buf[n] = 0;
c = (int)strtol(s, &e, 0);
if (CHAN_VALID(c) && e > s)
{
s = e;
if (*s == '.')
while (isdigit(*++s));
for (; isspace(*s); s++);
if (c == 0)
{
for (e = s; *s && !isspace(*s); s++);
if (*s)
for (*s++ = 0; isspace(*s); s++);
switch (*e)
{
case 'm':
if (!strcmp(e, "mask"))
{
if (*s)
{
m = strtoull(s, &e, 0);
if (e > s)
}
}
break;
case 'q':
/* might want privilege check here */
if (!strcmp(e, "quit"))
exit(0);
break;
}
}
else
}
return 1;
case CS_POLL_WRITE:
return -1;
if ((con->blocked[!state->log] < 0 || dump(css, con, !state->log, disc)) && con->blocked[state->log] >= 0)
return 1;
}
return 0;
}
static int
{
switch (op)
{
case CSS_INTERRUPT:
return 0;
case CSS_DORMANT:
exit(0);
}
return -1;
}
int
{
char* e;
for (;;)
{
{
case 'b':
continue;
case 'd':
continue;
case 't':
if (*e)
continue;
case '?':
continue;
case ':':
continue;
}
break;
}
return 1;
return 1;
}