/*
// 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);
}