/* -*- LPC -*- */
/*
* $Locker: $
* $Id: server.c,v 1.1 1998/01/06 05:19:01 ceres Exp $
* $Log: server.c,v $
* Revision 1.1 1998/01/06 05:19:01 ceres
* Initial revision
*
*/
/* /lib/server.c
* from the Nightmare IV LPC Library
* a TCP server object
* created by Descartes of Borg 950429
* Hacked for Discworld by Turrican, 21-3-96.
* Modified by Turrican to allow files to be sent over, 23-4-96.
* Modified by Turrican to allow files to be partly sent over, 2-7-97.
*/
#include <network.h>
#include <server.h>
private nosave int DestructOnClose, SocketType = -1;
private nosave function Read;
private nosave class server Listen;
private nosave mapping Sockets;
protected void create() {
seteuid(getuid());
Sockets = ([]);
} /* create() */
int eventCreateSocket(int port) {
int x;
if (SocketType == -1)
SocketType = STREAM;
x = socket_create(SocketType, "eventServerReadCallback",
"eventServerAbortCallback");
if( x < 0 ) {
eventSocketError("Error in socket_create().", x);
return x;
}
Listen = new(class server);
Listen->Blocking = 0; /* servers are not blocking to start */
Listen->Descriptor = x;
x = socket_bind(Listen->Descriptor, port);
if (x != EESUCCESS) {
eventClose(Listen);
eventSocketError("Error in socket_bind().", x);
return x;
}
x = socket_listen(Listen->Descriptor, "eventServerListenCallback");
if (x != EESUCCESS) {
eventClose(Listen);
eventSocketError("Error in socket_listen().", x);
return x;
}
return x;
} /* eventCreateSocket */
protected void eventServerListenCallback(int fd) {
int x;
x = socket_accept(fd, "eventServerReadCallback",
"eventServerWriteCallback");
if (x < 0) {
eventSocketError("Error in socket_accept().", x);
return;
}
eventNewConnection(x);
} /* eventServerListenCallback() */
void eventServerAbortCallback(int fd) {
if (Listen && Listen->Descriptor == fd)
eventClose(Listen);
else if (Sockets[fd])
eventClose(Sockets[fd]);
} /* eventServerAbortCallback() */
protected void eventServerReadCallback(int fd, mixed val) {
if (functionp(Read))
evaluate(Read, fd, val);
else
eventRead(fd, val);
} /* eventServerReadCallback() */
protected void eventRead(int fd, mixed val) {
} /* eventRead() */
protected void eventServerWriteCallback(int fd) {
class server sock;
class buff t;
int x;
if (Listen && Listen->Descriptor == fd)
sock = Listen;
else if (Sockets[fd])
sock = (class server)Sockets[fd];
else
return;
sock->Blocking = 0;
if (!sock->Buffer && sock->Closing) {
eventClose(sock);
return;
}
x = EESUCCESS;
while (sock->Buffer && x == EESUCCESS) {
t = sock->Buffer[0];
if (t->Type == FILE) {
if (t->Size < (t->Pos+BLOCK_SIZE))
t->Value = read_buffer(t->Filename, t->Pos, t->Size - t->Pos);
else
t->Value = read_buffer(t->Filename, t->Pos, BLOCK_SIZE);
t->Pos += BLOCK_SIZE;
}
switch (x = socket_write(sock->Descriptor, t->Value)) {
case EESUCCESS:
break;
case EECALLBACK:
sock->Blocking = 1;
break;
case EEWOULDBLOCK:
if (t->Pos)
t->Pos -= BLOCK_SIZE;
call_out( (: eventServerWriteCallback :), 1, fd);
return;
case EEALREADY:
sock->Blocking = 1;
return;
default:
eventClose(sock);
eventSocketError("Error in socket_write().", x);
return;
}
if (t->Type == STRING || t->Pos > t->Size) {
if (sizeof(sock->Buffer) == 1) {
sock->Buffer = 0;
if (sock->Closing && !sock->Blocking)
eventClose(sock);
} else
sock->Buffer = sock->Buffer[1..];
}
}
} /* eventServerWriteCallback() */
varargs void eventWrite(int fd, mixed val, int close, int type, int pos,
int size) {
class server sock;
class buff t;
if (Listen && Listen->Descriptor == fd)
sock = Listen;
else if (Sockets[fd])
sock = (class server)Sockets[fd];
else
return;
if (val) {
t = new(class buff);
t->Type = type;
if (type == FILE) {
t->Filename = val;
if (size)
t->Size = size;
else
t->Size = file_size(val);
t->Pos = pos;
} else
t->Value = val;
if (sock->Buffer)
sock->Buffer += ({ t });
else
sock->Buffer = ({ t });
}
sock->Closing = close;
if (sock->Blocking)
return;
else
eventServerWriteCallback(sock->Descriptor);
} /* eventWrite() */
protected void eventClose(class server sock) {
if (!sock)
return;
if (Sockets[sock->Descriptor])
map_delete(Sockets, sock->Descriptor);
socket_close(sock->Descriptor);
eventSocketClosed(sock->Descriptor);
sock = 0;
if (DestructOnClose && sock == Listen)
destruct(this_object());
} /* eventClose() */
protected void eventSocketClosed(int fd) {
} /* eventSocketClosed() */
int dest_me() {
eventClose(Listen);
if (this_object())
destruct(this_object());
return 1;
} /* dest_me() */
protected void eventNewConnection(int fd) {
Sockets[fd] = new(class server, Descriptor : fd);
} /* eventNewConnection() */
protected void eventSocketError(string str, int x) {
} /* eventSocketError() */
function SetRead(function f) {
return (Read = f);
} /* SetRead() */
int SetSocketType(int type) {
return (SocketType = type);
} /* SetSocketType() */
int SetDestructOnClose(int x) {
return (DestructOnClose = x);
} /* SetDestructOnClose() */