tmi2_fluffos_v2/
tmi2_fluffos_v2/bin/
tmi2_fluffos_v2/etc/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/ChangeLog.old/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/Win32/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/compat/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/compat/simuls/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/include/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/clone/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/command/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/data/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/etc/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/include/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/inherit/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/inherit/master/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/log/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/single/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/single/tests/compiler/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/single/tests/efuns/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/single/tests/operators/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/u/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/tmp/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/windows/
tmi2_fluffos_v2/lib/
tmi2_fluffos_v2/lib/adm/
tmi2_fluffos_v2/lib/adm/daemons/languages/
tmi2_fluffos_v2/lib/adm/daemons/network/I3/
tmi2_fluffos_v2/lib/adm/daemons/virtual/
tmi2_fluffos_v2/lib/adm/daemons/virtual/template/
tmi2_fluffos_v2/lib/adm/news/
tmi2_fluffos_v2/lib/adm/obj/
tmi2_fluffos_v2/lib/adm/obj/master/
tmi2_fluffos_v2/lib/adm/priv/
tmi2_fluffos_v2/lib/adm/shell/
tmi2_fluffos_v2/lib/adm/tmp/
tmi2_fluffos_v2/lib/cmds/
tmi2_fluffos_v2/lib/d/
tmi2_fluffos_v2/lib/d/Conf/
tmi2_fluffos_v2/lib/d/Conf/adm/
tmi2_fluffos_v2/lib/d/Conf/boards/
tmi2_fluffos_v2/lib/d/Conf/cmds/
tmi2_fluffos_v2/lib/d/Conf/data/
tmi2_fluffos_v2/lib/d/Conf/logs/
tmi2_fluffos_v2/lib/d/Conf/obj/
tmi2_fluffos_v2/lib/d/Conf/text/help/
tmi2_fluffos_v2/lib/d/Fooland/adm/
tmi2_fluffos_v2/lib/d/Fooland/data/
tmi2_fluffos_v2/lib/d/Fooland/data/attic/
tmi2_fluffos_v2/lib/d/Fooland/items/
tmi2_fluffos_v2/lib/d/TMI/
tmi2_fluffos_v2/lib/d/TMI/adm/
tmi2_fluffos_v2/lib/d/TMI/boards/
tmi2_fluffos_v2/lib/d/TMI/data/
tmi2_fluffos_v2/lib/d/TMI/rooms/
tmi2_fluffos_v2/lib/d/grid/
tmi2_fluffos_v2/lib/d/grid/adm/
tmi2_fluffos_v2/lib/d/grid/data/
tmi2_fluffos_v2/lib/d/std/
tmi2_fluffos_v2/lib/d/std/adm/
tmi2_fluffos_v2/lib/data/adm/
tmi2_fluffos_v2/lib/data/adm/daemons/
tmi2_fluffos_v2/lib/data/adm/daemons/doc_d/
tmi2_fluffos_v2/lib/data/adm/daemons/emoted/
tmi2_fluffos_v2/lib/data/adm/daemons/network/http/
tmi2_fluffos_v2/lib/data/adm/daemons/network/services/mail_q/
tmi2_fluffos_v2/lib/data/adm/daemons/network/smtp/
tmi2_fluffos_v2/lib/data/adm/daemons/news/archives/
tmi2_fluffos_v2/lib/data/attic/connection/
tmi2_fluffos_v2/lib/data/attic/user/
tmi2_fluffos_v2/lib/data/std/connection/b/
tmi2_fluffos_v2/lib/data/std/connection/l/
tmi2_fluffos_v2/lib/data/std/user/a/
tmi2_fluffos_v2/lib/data/std/user/b/
tmi2_fluffos_v2/lib/data/std/user/d/
tmi2_fluffos_v2/lib/data/std/user/f/
tmi2_fluffos_v2/lib/data/std/user/l/
tmi2_fluffos_v2/lib/data/std/user/x/
tmi2_fluffos_v2/lib/data/u/d/dm/working/doc_d/
tmi2_fluffos_v2/lib/data/u/l/leto/doc_d/
tmi2_fluffos_v2/lib/data/u/l/leto/smtp/
tmi2_fluffos_v2/lib/doc/
tmi2_fluffos_v2/lib/doc/driverdoc/applies/
tmi2_fluffos_v2/lib/doc/driverdoc/applies/interactive/
tmi2_fluffos_v2/lib/doc/driverdoc/concepts/
tmi2_fluffos_v2/lib/doc/driverdoc/driver/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/arrays/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/buffers/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/compile/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/ed/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/filesystem/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/floats/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/functions/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/general/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/mappings/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/numbers/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/parsing/
tmi2_fluffos_v2/lib/doc/driverdoc/lpc/constructs/
tmi2_fluffos_v2/lib/doc/driverdoc/lpc/preprocessor/
tmi2_fluffos_v2/lib/doc/driverdoc/lpc/types/
tmi2_fluffos_v2/lib/doc/driverdoc/platforms/
tmi2_fluffos_v2/lib/doc/mudlib/
tmi2_fluffos_v2/lib/ftp/
tmi2_fluffos_v2/lib/include/driver/
tmi2_fluffos_v2/lib/log/
tmi2_fluffos_v2/lib/log/driver/
tmi2_fluffos_v2/lib/obj/net/
tmi2_fluffos_v2/lib/obj/shells/
tmi2_fluffos_v2/lib/obj/tools/
tmi2_fluffos_v2/lib/std/adt/
tmi2_fluffos_v2/lib/std/board/
tmi2_fluffos_v2/lib/std/body/
tmi2_fluffos_v2/lib/std/fun/
tmi2_fluffos_v2/lib/std/living/
tmi2_fluffos_v2/lib/std/object/
tmi2_fluffos_v2/lib/std/shop/
tmi2_fluffos_v2/lib/std/socket/
tmi2_fluffos_v2/lib/std/user/
tmi2_fluffos_v2/lib/std/virtual/
tmi2_fluffos_v2/lib/student/
tmi2_fluffos_v2/lib/student/kalypso/
tmi2_fluffos_v2/lib/student/kalypso/armor/
tmi2_fluffos_v2/lib/student/kalypso/rooms/
tmi2_fluffos_v2/lib/student/kalypso/weapons/
tmi2_fluffos_v2/lib/u/l/leto/
tmi2_fluffos_v2/lib/u/l/leto/cmds/
tmi2_fluffos_v2/lib/www/errors/
tmi2_fluffos_v2/lib/www/gateways/
tmi2_fluffos_v2/lib/www/images/
tmi2_fluffos_v2/old/
tmi2_fluffos_v2/win32/
/*
** socket.c
**
** This object represents an open UDP/TCP socket using the MudOS
** socket facilities.
**
** 09-Feb-95. Deathblade. Created.
*/

#include <mudlib.h>
#include <socket.h>
#include <driver/socket_err.h>
#include <net/i3.h>

#define MUSTLOG(x,y)	write_file("/open/sktlog",sprintf("%s: %O\n",x,y))
//#define SKTLOG(x,y)	MUSTLOG(x,y)
#define SKTLOG(x,y)

static int	style;
static int	fdOwned = -1;	/* no socket yet */
static function	read_func;
static function	close_func;

static mixed *	write_queue = ({ });
static int	blocked;

/* For debug purposes only */
static mixed addr;
int stat_me()
{
    switch ( style )
    {
    case SKT_STYLE_LISTEN:
	printf("%O: listening at %O\n", this_object(), addr);
	printf("    read_func=%O  close_func=%O\n", read_func, close_func);
	break;

    case SKT_STYLE_CONNECT:
	printf("%O: connected to %O\n", this_object(), addr);
	printf("    read_func=%O  close_func=%O\n", read_func, close_func);
	break;

    case SKT_STYLE_UDP:
	printf("%O: UDP at %O\n", this_object(), addr);
	printf("    read_func=%O\n", read_func);
	break;

    case SKT_STYLE_LISTEN_M:
	printf("%O: (mud) listening at %O\n", this_object(), addr);
	printf("    read_func=%O  close_func=%O\n", read_func, close_func);
	break;

    case SKT_STYLE_CONNECT_M:
	printf("%O: (mud) connected to %O\n", this_object(), addr);
	printf("    read_func=%O  close_func=%O\n", read_func, close_func);
	break;

    case SKT_STYLE_INT_ACQUIRE:
	printf("%O: accepted connection from %s\n", this_object(),
	       socket_address(fdOwned));
	printf("    read_func=%O  close_func=%O\n", read_func, close_func);
	break;
    }

    if ( sizeof(write_queue) )
	printf("queue: %O\n", write_queue);

    return 1;
}


void create(int skt_style, mixed p1, mixed p2, mixed p3)
{
    int err;

    if ( !clonep() )
	return;

seteuid(getuid(previous_object()));

SKTLOG("create: self",this_object());
    style = skt_style;
    addr = p1;

    switch ( style )
    {
    case SKT_STYLE_LISTEN:
	read_func = p2;
	close_func = p3;
	fdOwned = socket_create(1 /* STREAM */,
				"read_callback",
				"close_callback");
	if ( fdOwned < 0 )
	    error("could not create socket: " + socket_error(fdOwned) + "\n");
	if ( (err = socket_bind(fdOwned, p1)) < 0 )
	    error("could not bind socket: " + socket_error(err) + "\n");
	if ( (err = socket_listen(fdOwned, "listen_callback")) < 0 )
	    error("could not listen to socket: " + socket_error(err) + "\n");
SKTLOG("create: SKT_STYLE_LISTEN",fdOwned);
	break;

    case SKT_STYLE_CONNECT:
	read_func = p2;
	close_func = p3;
	fdOwned = socket_create(1 /* STREAM */,
				"read_callback",
				"close_callback");
	if ( fdOwned < 0 )
	    error("could not create socket: " + socket_error(fdOwned) + "\n");
	err = socket_connect(fdOwned, p1, "read_callback", "write_callback");
	if ( err < 0 )
	    error("could not listen to socket: " + socket_error(err) + "\n");
SKTLOG("create: SKT_STYLE_CONNECT",fdOwned);
SKTLOG("create: close_func",close_func);
	break;

    case SKT_STYLE_UDP:
	read_func = p2;
	fdOwned = socket_create(2 /* DATAGRAM */, "read_udp_callback");
	if ( fdOwned < 0 )
	    error("could not create socket: " + socket_error(fdOwned) + "\n");
	if ( (err = socket_bind(fdOwned, p1)) < 0 )
	    error("could not bind socket: " + socket_error(err) + "\n");
SKTLOG("create: SKT_STYLE_UDP",fdOwned);
	break;

    case SKT_STYLE_LISTEN_M:
	read_func = p2;
	close_func = p3;
	fdOwned = socket_create(0 /* MUD */,
				"read_callback",
				"close_callback");
	if ( fdOwned < 0 )
	    error("could not create socket: " + socket_error(fdOwned) + "\n");
	if ( (err = socket_bind(fdOwned, p1)) < 0 )
	    error("could not bind socket: " + socket_error(err) + "\n");
	if ( (err = socket_listen(fdOwned, "listen_callback")) < 0 )
	    error("could not listen to socket: " + socket_error(err) + "\n");
SKTLOG("create: SKT_STYLE_LISTEN_M",fdOwned);
	break;

    case SKT_STYLE_CONNECT_M:
	read_func = p2;
	close_func = p3;
	fdOwned = socket_create(0 /* MUD */,
				"read_callback",
				"close_callback");
	if ( fdOwned < 0 )
	    error("could not create socket: " + socket_error(fdOwned) + "\n");
	err = socket_connect(fdOwned, p1, "read_callback", "write_callback");
	if ( err < 0 )
	    error("could not listen to socket: " + socket_error(err) + "\n");
SKTLOG("create: SKT_STYLE_CONNECT_M",fdOwned);
SKTLOG("create: close_func",close_func);
	break;

    case SKT_STYLE_INT_ACQUIRE:
	read_func	= p1;
	close_func	= p2;
	break;
    }
}

nomask void listen_callback(int fd)
{
    object	s;
    int		err;

SKTLOG("listen_callback: self",this_object());
SKTLOG("listen_callback: fd",fd);
    fd = socket_accept(fd, "read_callback", "write_callback");
    s = clone_object(SOCKET, SKT_STYLE_INT_ACQUIRE,
		     read_func,
		     close_func);
SKTLOG("listen_callback: new sock",s);
    err = socket_release(fd, s, "release_callback");
SKTLOG("listen_callback: err",err);
    if ( err < 0 )
	error("could not release: " + socket_error(err) + "\n");
}

nomask void release_callback(int fdToAcquire)
{
    int err;

SKTLOG("release_callback: self",this_object());
    fdOwned = fdToAcquire;
SKTLOG("release_callback: fdOwned",fdOwned);
    err = socket_acquire(fdOwned,
			 "read_callback",
			 "write_callback",
			 "close_callback");
SKTLOG("release_callback: err",err);

    if ( err < 0 )
	error("could not release: " + socket_error(err) + "\n");

    /*
    ** Deliver a 0 indicating a new connection (and providing self)
    */
    catch(evaluate(read_func, this_object(), 0));
}

static nomask void read_callback(int fd, mixed message)
{
    /* ### workaround an internal driver bug */
    restore_variable("0");

SKTLOG("read_callback: self",this_object());
SKTLOG("read_callback: fd",fd);
    catch(evaluate(read_func, this_object(), message));
}

static nomask void read_udp_callback(int fd, mixed message, string address)
{
SKTLOG("read_udp_callback: self",this_object());
SKTLOG("read_udp_callback: fd",fd);
SKTLOG("read_udp_callback: read_func",read_func);
    catch(evaluate(read_func, this_object(), message, address));
}

static nomask void close_callback(int fd)
{
SKTLOG("close_callback: self",this_object());
SKTLOG("close_callback: fd",fd);
SKTLOG("close_callback: close_func",close_func);
    if ( close_func )
    {
	catch(evaluate(close_func, this_object()));
    }

    destruct(this_object());
}

static nomask void write_callback(int fd)
{
SKTLOG("write_callback: self",this_object());
SKTLOG("write_callback: fd",fd);
SKTLOG("write_callback: # elem",sizeof(write_queue));

    /*
    ** No longer blocked (can accept new data).
    */
    blocked = 0;

    while ( sizeof(write_queue) > 0 )
    {
	int err;

	err = socket_write(fd, write_queue[0]);
SKTLOG("write_callback: err",err);

	/* ### workaround an internal driver bug */
	restore_variable("0");

	/* ### HACK: driver did not write anything, but it won't call again,
	** ### so force it with a call_out()
	*/
	if ( err == EEWOULDBLOCK )
	{
	    blocked = 1;
	    call_out((: write_callback, fd :), 1);
	    return;
	}

	/*
	** Remove the item from the queue.  It has been written.
	*/
	write_queue = write_queue[1..];

	if ( err == EECALLBACK )
	{
	    /* done for now... wait for the next callback */
	    blocked = 1;
	    return;
	}
	if ( err < 0 )
	    error("could not write: " + socket_error(err) + "\n");
    }
}

varargs nomask void send(mixed message, string address)
{
    int	err;

SKTLOG("send: self",this_object());
SKTLOG("send: fd",fdOwned);
SKTLOG("send: # elem",sizeof(write_queue));

    if ( address )
	err = socket_write(fdOwned, message, address);
    else if ( blocked )
    {
	/*
	** If we are blocked, then the socket doesn't want us to send
	** any more.  Place it on our queue for sending later.
	*/
	write_queue += ({ message });
    }
    else
    {
	err = socket_write(fdOwned, message);
SKTLOG("send: err",err);

	/* ### workaround an internal driver bug */
	//restore_variable("0");

	/* ### note: test for EEALREADY for now... need newer driver */
	if ( err == EEALREADY )
	{
	    blocked = 1;
	    write_queue += ({ message });
            //call_out((: write_callback, fdOwned :), 1);
	    return;
	}
	/* ### same for OWB: means the driver hasn't queued it :- */
	/* ### set a call_out() to ensure we're called to deliver it */
	if ( err == EEWOULDBLOCK )
	{
	    blocked = 1;
	    write_queue += ({ message });
	    call_out((: write_callback, fdOwned :), 1);
	    return;
	}
	if ( err == EECALLBACK )
	{
	    /*
	    ** Socket took the message but is blocked until it can
	    ** write it out.  Set a flag so that we don't write any
	    ** more until we get the callback.
	    */
	    blocked = 1;
	    return;
	}
    }

    if ( err < 0 )
	error("could not write: " + socket_error(err) + "\n");
}

void remove()
{
    int err;

    if ( fdOwned >= 0 )
    {
SKTLOG("remove: self",this_object());
SKTLOG("remove: fdOwned",fdOwned);
	err = socket_close(fdOwned);
SKTLOG("remove: err",err);
	if ( err < 0 )
	    error("could not close: " + socket_error(err) + "\n");
    }

    destruct(this_object());
}

nomask mixed *address()
{
    string tmp;
    string host;
    int port;

    tmp = socket_address(fdOwned);
SKTLOG("address: fdOwned", fdOwned);
SKTLOG("address: tmp", tmp);
    sscanf(tmp, "%s %d", host, port);
    return ({ host, port });
}