Ejemplo n.º 1
0
*/	RL_API int RL_Start(REBYTE *bin, REBINT len, REBCNT flags)
/*
**	Evaluate the default boot function.
**
**	Returns:
**		Zero on success, otherwise indicates an error occurred.
**	Arguments:
**		bin - optional startup code (compressed), can be null
**		len - length of above bin
**		flags - special flags
**	Notes:
**		This function completes the startup sequence by calling
**		the sys/start function.
**
***********************************************************************/
{
	REBVAL *val;
	REBSER spec = {0};
	REBSER *ser;

	if (bin) {
		spec.data = bin;
		spec.tail = len;
		ser = Decompress(&spec, 0, -1, 10000000, 0);
		if (!ser) return 1;

		val = BLK_SKIP(Sys_Context, SYS_CTX_BOOT_HOST);
		Set_Binary(val, ser);
	}

	return Init_Mezz(0);
}
Ejemplo n.º 2
0
*/	RL_API void *RL_Extend(REBYTE *source, RXICAL call)
/*
**	Appends embedded extension to system/catalog/boot-exts.
**
**	Returns:
**		A pointer to the REBOL library (see reb-lib.h).
**	Arguments:
**		source - A pointer to a UTF-8 (or ASCII) string that provides
**			extension module header, function definitions, and other
**			related functions and data.
**		call - A pointer to the extension's command dispatcher.
**	Notes:
**		This function simply adds the embedded extension to the
**		boot-exts list. All other processing and initialization
**		happens later during startup. Each embedded extension is
**		queried and init using LOAD-EXTENSION system native.
**		See c:extensions-embedded
**
***********************************************************************/
{
	REBVAL *value;
	REBSER *ser;

	value = BLK_SKIP(Sys_Context, SYS_CTX_BOOT_EXTS);
	if (IS_BLOCK(value)) ser = VAL_SERIES(value);
	else {
		ser = Make_Block(2);
		Set_Block(value, ser);
	}
	value = Append_Value(ser);
	Set_Binary(value, Copy_Bytes(source, -1)); // UTF-8
	value = Append_Value(ser);
	SET_HANDLE(value, call);

	return Extension_Lib();
}
Ejemplo n.º 3
0
*/	static REB_R Console_Actor(struct Reb_Call *call_, REBSER *port, REBCNT action)
/*
***********************************************************************/
{
	REBREQ *req;
	REBINT result;
	REBVAL *arg = D_ARG(2);
	REBSER *ser;

	Validate_Port(port, action);

	arg = D_ARG(2);
	*D_OUT = *D_ARG(1);

	req = cast(REBREQ*, Use_Port_State(port, RDI_STDIO, sizeof(REBREQ)));

	switch (action) {

	case A_READ:

		// If not open, open it:
		if (!IS_OPEN(req)) {
			if (OS_DO_DEVICE(req, RDC_OPEN)) Trap_Port_DEAD_END(RE_CANNOT_OPEN, port, req->error);
		}

		// If no buffer, create a buffer:
		arg = OFV(port, STD_PORT_DATA);
		if (!IS_STRING(arg) && !IS_BINARY(arg)) {
			Set_Binary(arg, MAKE_OS_BUFFER(OUT_BUF_SIZE));
		}
		ser = VAL_SERIES(arg);
		RESET_SERIES(ser);

		req->common.data = BIN_HEAD(ser);
		req->length = SERIES_AVAIL(ser);

#ifdef nono
		// Is the buffer large enough?
		req->length = SERIES_AVAIL(ser); // space available
		if (req->length < OUT_BUF_SIZE/2) Extend_Series(ser, OUT_BUF_SIZE);
		req->length = SERIES_AVAIL(ser);

		// Don't make buffer too large:  Bug #174   ?????
		if (req->length > 1024) req->length = 1024;  //???
		req->common.data = STR_TAIL(ser); // write at tail  //???
		if (SERIES_TAIL(ser) == 0) req->actual = 0;  //???
#endif

		result = OS_DO_DEVICE(req, RDC_READ);
		if (result < 0) Trap_Port_DEAD_END(RE_READ_ERROR, port, req->error);

#ifdef nono
		// Does not belong here!!
		// Remove or replace CRs:
		result = 0;
		for (n = 0; n < req->actual; n++) {
			chr = GET_ANY_CHAR(ser, n);
			if (chr == CR) {
				chr = LF;
				// Skip LF if it follows:
				if ((n+1) < req->actual &&
					LF == GET_ANY_CHAR(ser, n+1)) n++;
			}
			SET_ANY_CHAR(ser, result, chr);
			result++;
		}
#endif
		// !!! Among many confusions in this file, it said "Another copy???"
		//Set_String(D_OUT, Copy_OS_Str(ser->data, result));
		Set_Binary(D_OUT, Copy_Bytes(req->common.data, req->actual));
		break;

	case A_OPEN:
		// ?? why???
		//if (OS_DO_DEVICE(req, RDC_OPEN)) Trap_Port_DEAD_END(RE_CANNOT_OPEN, port);
		SET_OPEN(req);
		break;

	case A_CLOSE:
		SET_CLOSED(req);
		//OS_DO_DEVICE(req, RDC_CLOSE);
		break;

	case A_OPENQ:
		if (IS_OPEN(req)) return R_TRUE;
		return R_FALSE;

	default:
		Trap_Action_DEAD_END(REB_PORT, action);
	}

	return R_OUT;
}
Ejemplo n.º 4
0
*/	static int Transport_Actor(REBVAL *ds, REBSER *port, REBCNT action, enum Transport_Types proto)
/*
***********************************************************************/
{
	REBREQ *sock;	// IO request
	REBVAL *spec;	// port spec
	REBVAL *arg;	// action argument value
	REBVAL *val;	// e.g. port number value
	REBINT result;	// IO result
	REBCNT refs;	// refinement argument flags
	REBCNT len;		// generic length
	REBSER *ser;	// simplifier

	Validate_Port(port, action);

	*D_OUT = *D_ARG(1);
	arg = D_ARG(2);
	refs = 0;

	sock = cast(REBREQ*, Use_Port_State(port, RDI_NET, sizeof(*sock)));
	if (proto == TRANSPORT_UDP) {
		SET_FLAG(sock->modes, RST_UDP);
	}
	//Debug_Fmt("Sock: %x", sock);
	spec = OFV(port, STD_PORT_SPEC);
	if (!IS_OBJECT(spec)) Trap_DEAD_END(RE_INVALID_PORT);

	// sock->timeout = 4000; // where does this go? !!!

	// HOW TO PREVENT OVERWRITE DURING BUSY OPERATION!!!
	// Should it just ignore it or cause an error?

	// Actions for an unopened socket:
	if (!IS_OPEN(sock)) {

		switch (action) {	// Ordered by frequency

		case A_OPEN:

			arg = Obj_Value(spec, STD_PORT_SPEC_NET_HOST);
			val = Obj_Value(spec, STD_PORT_SPEC_NET_PORT_ID);

			if (OS_DO_DEVICE(sock, RDC_OPEN)) Trap_Port_DEAD_END(RE_CANNOT_OPEN, port, -12);
			SET_OPEN(sock);

			// Lookup host name (an extra TCP device step):
			if (IS_STRING(arg)) {
				sock->common.data = VAL_BIN(arg);
				sock->special.net.remote_port = IS_INTEGER(val) ? VAL_INT32(val) : 80;
				result = OS_DO_DEVICE(sock, RDC_LOOKUP);  // sets remote_ip field
				if (result < 0) Trap_Port_DEAD_END(RE_NO_CONNECT, port, sock->error);
				return R_OUT;
			}

			// Host IP specified:
			else if (IS_TUPLE(arg)) {
				sock->special.net.remote_port = IS_INTEGER(val) ? VAL_INT32(val) : 80;
				memcpy(&sock->special.net.remote_ip, VAL_TUPLE(arg), 4);
				break;
			}

			// No host, must be a LISTEN socket:
			else if (IS_NONE(arg)) {
				SET_FLAG(sock->modes, RST_LISTEN);
				sock->common.data = 0; // where ACCEPT requests are queued
				sock->special.net.local_port = IS_INTEGER(val) ? VAL_INT32(val) : 8000;
				break;
			}
			else Trap_Port_DEAD_END(RE_INVALID_SPEC, port, -10);

		case A_CLOSE:
			return R_OUT;

		case A_OPENQ:
			return R_FALSE;

		case A_UPDATE:	// allowed after a close
			break;

		default:
			Trap_Port_DEAD_END(RE_NOT_OPEN, port, -12);
		}
	}

	// Actions for an open socket:
	switch (action) {	// Ordered by frequency

	case A_UPDATE:
		// Update the port object after a READ or WRITE operation.
		// This is normally called by the WAKE-UP function.
		arg = OFV(port, STD_PORT_DATA);
		if (sock->command == RDC_READ) {
			if (ANY_BINSTR(arg)) VAL_TAIL(arg) += sock->actual;
		}
		else if (sock->command == RDC_WRITE) {
			SET_NONE(arg);  // Write is done.
		}
		return R_NONE;

	case A_READ:
		// Read data into a buffer, expanding the buffer if needed.
		// If no length is given, program must stop it at some point.
		refs = Find_Refines(ds, ALL_READ_REFS);
		if (!GET_FLAG(sock->modes, RST_UDP)
			&& !GET_FLAG(sock->state, RSM_CONNECT))
			Trap_Port_DEAD_END(RE_NOT_CONNECTED, port, -15);

		// Setup the read buffer (allocate a buffer if needed):
		arg = OFV(port, STD_PORT_DATA);
		if (!IS_STRING(arg) && !IS_BINARY(arg)) {
			Set_Binary(arg, Make_Binary(NET_BUF_SIZE));
		}
		ser = VAL_SERIES(arg);
		sock->length = SERIES_AVAIL(ser); // space available
		if (sock->length < NET_BUF_SIZE/2) Extend_Series(ser, NET_BUF_SIZE);
		sock->length = SERIES_AVAIL(ser);
		sock->common.data = STR_TAIL(ser); // write at tail
		//if (SERIES_TAIL(ser) == 0)
		sock->actual = 0;  // Actual for THIS read, not for total.

		//Print("(max read length %d)", sock->length);
		result = OS_DO_DEVICE(sock, RDC_READ); // recv can happen immediately
		if (result < 0) Trap_Port_DEAD_END(RE_READ_ERROR, port, sock->error);
		break;

	case A_WRITE:
		// Write the entire argument string to the network.
		// The lower level write code continues until done.

		refs = Find_Refines(ds, ALL_WRITE_REFS);
		if (!GET_FLAG(sock->modes, RST_UDP)
			&& !GET_FLAG(sock->state, RSM_CONNECT))
			Trap_Port_DEAD_END(RE_NOT_CONNECTED, port, -15);

		// Determine length. Clip /PART to size of string if needed.
		spec = D_ARG(2);
		len = VAL_LEN(spec);
		if (refs & AM_WRITE_PART) {
			REBCNT n = Int32s(D_ARG(ARG_WRITE_LENGTH), 0);
			if (n <= len) len = n;
		}

		// Setup the write:
		*OFV(port, STD_PORT_DATA) = *spec;	// keep it GC safe
		sock->length = len;
		sock->common.data = VAL_BIN_DATA(spec);
		sock->actual = 0;

		//Print("(write length %d)", len);
		result = OS_DO_DEVICE(sock, RDC_WRITE); // send can happen immediately
		if (result < 0) Trap_Port_DEAD_END(RE_WRITE_ERROR, port, sock->error);
		if (result == DR_DONE) SET_NONE(OFV(port, STD_PORT_DATA));
		break;

	case A_PICK:
		// FIRST server-port returns new port connection.
		len = Get_Num_Arg(arg); // Position
		if (len == 1 && GET_FLAG(sock->modes, RST_LISTEN) && sock->common.data)
			Accept_New_Port(ds, port, sock); // sets D_OUT
		else
			Trap_Range_DEAD_END(arg);
		break;

	case A_QUERY:
		// Get specific information - the scheme's info object.
		// Special notation allows just getting part of the info.
		Ret_Query_Net(port, sock, D_OUT);
		break;

	case A_OPENQ:
		// Connect for clients, bind for servers:
		if (sock->state & ((1<<RSM_CONNECT) | (1<<RSM_BIND))) return R_TRUE;
		return R_FALSE;

	case A_CLOSE:
		if (IS_OPEN(sock)) {
			OS_DO_DEVICE(sock, RDC_CLOSE);
			SET_CLOSED(sock);
		}
		break;

	case A_LENGTHQ:
		arg = OFV(port, STD_PORT_DATA);
		len = ANY_SERIES(arg) ? VAL_TAIL(arg) : 0;
		SET_INTEGER(D_OUT, len);
		break;

	case A_OPEN:
		result = OS_DO_DEVICE(sock, RDC_CONNECT);
		if (result < 0) Trap_Port_DEAD_END(RE_NO_CONNECT, port, sock->error);
		break;
		//Trap_Port_DEAD_END(RE_ALREADY_OPEN, port);

	case A_DELETE: // Temporary to TEST error handler!
		{
			REBVAL *event = Append_Event();		// sets signal
			VAL_SET(event, REB_EVENT);		// (has more space, if we need it)
			VAL_EVENT_TYPE(event) = EVT_ERROR;
			VAL_EVENT_DATA(event) = 101;
			VAL_EVENT_REQ(event) = sock;
		}
		break;

	default:
		Trap_Action_DEAD_END(REB_PORT, action);
	}

	return R_OUT;
}