/
Genesis-1.0p36-DEV/
Genesis-1.0p36-DEV/bin/
Genesis-1.0p36-DEV/doc/
Genesis-1.0p36-DEV/etc/
Genesis-1.0p36-DEV/src/data/
/*
// Full copyright information is available in the file ../doc/CREDITS
*/

#include "defs.h"

#include <string.h>
#include "execute.h"
#include "net.h"
#include "util.h"
#include "cache.h"

/*
// -----------------------------------------------------------------
//
// If the current object has a connection, it will reassign that
// connection too the specified object.
//
*/

void func_reassign_connection(void) {
    cData       * args;
    Conn * c;
    Obj     * obj;

    /* Accept a objnum. */
    if (!func_init_1(&args, OBJNUM))
        return;

    c = find_connection(cur_frame->object);
    if (c) {
        obj = cache_retrieve(args[0].u.objnum);
        if (!obj)
            THROW((objnf_id, "Object #%l does not exist.", args[0].u.objnum))
        else if (find_connection(obj)) {
            cthrow(perm_id, "Object %O already has a connection.", obj->objnum);
            cache_discard(obj);
            return;
        }
        c->objnum = obj->objnum;
        cache_discard(obj);
        cur_frame->object->conn = NULL;
        pop(1);
        push_int(1);
    } else {
        pop(1);
        push_int(0);
    }
}

/*
// -----------------------------------------------------------------
*/
void func_bind_port(void) {
    cData * args;
    Int     argc;
    Int     port;
    char  * addr;

    /* Accept a port to bind to, and a objnum to handle connections. */
    if (!func_init_1_or_2(&args, &argc, INTEGER, STRING))
        return;

    addr = (argc==2 ? string_chars(STR2) : (char *) NULL);
    port=INT1;

    if (((port >= 0) ? tcp_server(port, addr, cur_frame->object->objnum)
	             : udp_server(-port, addr, cur_frame->object->objnum))) {
        pop(argc);
	push_int(1);
    } else if (server_failure_reason == address_id)
        THROW((address_id, "Invalid bind address: %s", addr))
    else if (server_failure_reason == socket_id)
        THROW((socket_id, "Couldn't create server socket."))
    else if (server_failure_reason == preaddr_id)
        THROW((preaddr_id, 
               "Couldn't bind to port %d: prebound address conflict", INT1))
    else if (server_failure_reason == pretype_id) {
        if (port > 0)
            THROW((pretype_id, 
               "Couldn't bind to TCP port %d: already prebound as UDP", INT1))
        else
            THROW((pretype_id, 
               "Couldn't bind to UDP port %d: already prebound as TCP", INT1))
    } else if (addr)
        THROW((server_failure_reason,
               "Couldn't bind to port %d on address %s", INT1, addr))
    else
        THROW((server_failure_reason, "Couldn't bind to port %d.", INT1))
}

/*
// -----------------------------------------------------------------
*/
void func_unbind_port(void) {
    cData * args;

    /* Accept a port number. */
    if (!func_init_1(&args, INTEGER))
        return;

    if (!remove_server(args[0].u.val))
        THROW((servnf_id, "No server socket on port %d.", args[0].u.val))
    else {
        pop(1);
        push_int(1);
    }
}

/*
// -----------------------------------------------------------------
*/
void func_open_connection(void) {
    cData *args;
    char *address;
    Int port, argc;
    Long r;

    if (!func_init_2_or_3(&args, &argc, STRING, INTEGER, INTEGER))
        return;

    address = string_chars(args[0].u.str);
    port = args[1].u.val;

    if (argc==2)
	r = make_connection(address, port, cur_frame->object->objnum);
    else
	r = make_udp_connection(address, port, cur_frame->object->objnum);
    if (r == address_id)
        THROW((address_id, "Invalid address"))
    else if (r == socket_id)
        THROW((socket_id, "Couldn't create socket for connection"))
    pop(argc);
    push_int(1);
}

/*
// -----------------------------------------------------------------
*/
void func_close_connection(void) {
    /* Accept no arguments. */
    if (!func_init_0())
        return;

    /* Kick off anyone assigned to the current object. */
    push_int(boot(cur_frame->object));
}

/*
// -----------------------------------------------------------------
// Echo a buffer to the connection
*/
void func_cwrite(void) {
    cData *args;
    int rval;

    /* Accept a buffer to write. */
    if (!func_init_1(&args, BUFFER))
        return;

    /* Write the string to any connection associated with this object.  */
    rval = tell(cur_frame->object, args[0].u.buffer) ? 1 : 0;

    pop(1);
    push_int(rval);
}

/*
// -----------------------------------------------------------------
// write a file to the connection
*/
void func_cwritef(void) {
    size_t        block, r;
    cData      * args;
    FILE        * fp;
    cBuf    * buf;
    cStr    * str;
    struct stat   statbuf;
    Int           nargs;

    /* Accept the name of a file to echo */
    if (!func_init_1_or_2(&args, &nargs, STRING, INTEGER))
        return;

    /* Initialize the file */
    str = build_path(args[0].u.str->s, &statbuf, DISALLOW_DIR);
    if (str == NULL)
        return;

    /* Open the file for reading. */
    fp = open_scratch_file(str->s, "rb");
    if (!fp)
        THROW((file_id, "Cannot open file \"%s\" for reading.", str->s))

    /* how big of a chunk do we read at a time? */
    if (nargs == 2) {
        if (args[1].u.val == -1)
            block = statbuf.st_size;
        else
            block = (size_t) args[1].u.val;
    } else
        block = (size_t) DEF_BLOCKSIZE;

    /* Allocate a buffer to hold the block */
    buf = buffer_new(block);

    while (!feof(fp)) {
        r = fread(buf->s, sizeof(unsigned char), block, fp);
        if (r != block) {
            if (!feof(fp)) {
                buffer_discard(buf);
                close_scratch_file(fp);
                cthrow(file_id, "Trouble reading file \"%s\": %s",
                       str->s, strerror(GETERR()));
                return;
            } else {
                buf->len = r;
                tell(cur_frame->object, buf);
            }
        } else
            tell(cur_frame->object, buf);
    }

    /* Discard the buffer and close the file. */
    buffer_discard(buf);
    close_scratch_file(fp);

    pop(nargs);
    push_int((cNum) statbuf.st_size);
}

/*
// -----------------------------------------------------------------
// return random info on the connection
*/
void func_connection(void) {
    cList       * info;
    cData       * list;
    Conn * c;

    if (!func_init_0())
        return;

    c = find_connection(cur_frame->object);
    if (!c)
        THROW((net_id, "No connection established."))

    info = list_new(4);
    list = list_empty_spaces(info, 4);

    list[0].type = INTEGER;
    list[0].u.val = (cNum) (c->flags.readable ? 1 : 0);
    list[1].type = INTEGER;
    list[1].u.val = (cNum) (c->flags.writable ? 1 : 0);
    list[2].type = INTEGER;
    list[2].u.val = (cNum) (c->flags.dead ? 1 : 0);
    list[3].type = INTEGER;
    list[3].u.val = (cNum) (c->fd);

    push_list(info);
    list_discard(info);
}