Пример #1
0
*/	DEVICE_CMD Write_Serial(REBREQ *req)
/*
***********************************************************************/
{
    DWORD result = 0;
    DWORD len = req->length - req->actual;
	if (!req->requestee.handle) {
		req->error = -RFE_NO_HANDLE;
		return DR_ERROR;
	}

	if (len <= 0) return DR_DONE;

	if (!WriteFile(
		req->requestee.handle, req->common.data, len, &result, NULL
    )) {
        req->error = -RFE_BAD_WRITE;
        Signal_Device(req, EVT_ERROR);
        return DR_ERROR;
    }

#ifdef DEBUG_SERIAL
	printf("write %d ret: %d\n", req->length, req->actual);
#endif

	req->actual += result;
	req->common.data += result;
	if (req->actual >= req->length) {
		Signal_Device(req, EVT_WROTE);
		return DR_DONE;
	} else {
		SET_FLAG(req->flags, RRF_ACTIVE); /* notify OS_WAIT of activity */
		return DR_PEND;
	}
}
Пример #2
0
//
//  Read_Signal: C
//
DEVICE_CMD Read_Signal(REBREQ *req)
{
    struct timespec timeout = {0, 0};
    unsigned int i = 0;

    errno = 0;

    for (i = 0; i < req->length; i ++) {
        int result = sigtimedwait(
            &req->special.signal.mask,
            &(cast(siginfo_t*, req->common.data)[i]),
            &timeout
        );

        if (result < 0) {
            if (errno != EAGAIN && i == 0) {
                Signal_Device(req, EVT_ERROR);
                return DR_ERROR;
            } else {
                break;
            }
        }
    }

    req->actual = i;
    if (i > 0) {
    //printf("read %d signals\n", req->actual);
        Signal_Device(req, EVT_READ);
        return DR_DONE;
    } else {
        return DR_PEND;
    }
}
Пример #3
0
*/	DEVICE_CMD Read_Serial(REBREQ *req)
/*
***********************************************************************/
{
    DWORD result = 0;
	if (!req->requestee.handle) {
		req->error = -RFE_NO_HANDLE;
		return DR_ERROR;
	}

	//RL_Print("reading %d bytes\n", req->length);
    if (!ReadFile(req->requestee.handle, req->common.data, req->length, &result, 0)) {
		req->error = -RFE_BAD_READ;
		Signal_Device(req, EVT_ERROR);
		return DR_ERROR;
	} else {
		if (result == 0) {
			return DR_PEND;
		} else if (result > 0){
			//RL_Print("read %d bytes\n", req->actual);
			req->actual = result;
			Signal_Device(req, EVT_READ);
		}
	}

#ifdef DEBUG_SERIAL
	printf("read %d ret: %d\n", req->length, req->actual);
#endif

	return DR_DONE;
}
Пример #4
0
//
//  Open_Signal: C
//
DEVICE_CMD Open_Signal(REBREQ *req)
{
    //RL_Print("Open_Signal\n");

    sigset_t mask;
    sigset_t overlap;

#ifdef CHECK_MASK_OVERLAP //doesn't work yet
    if (sigprocmask(SIG_BLOCK, NULL, &mask) < 0) {
        goto error;
    }
    if (sigandset(&overlap, &mask, &req->special.signal.mask) < 0) {
        goto error;
    }
    if (!sigisemptyset(&overlap)) {
        req->error = EBUSY;
        return DR_ERROR;
    }
#endif

    if (sigprocmask(SIG_BLOCK, &req->special.signal.mask, NULL) < 0) {
        goto error;
    }

    SET_OPEN(req);
    Signal_Device(req, EVT_OPEN);

    return DR_DONE;

error:
    req->error = errno;
    return DR_ERROR;
}
Пример #5
0
*/	 DEVICE_CMD Accept_Socket(REBREQ *sock)
/*
**		Accept an inbound connection on a TCP listen socket.
**
**		The function will return:
**			=0: succeeded
**			>0: in-progress, still trying
**		    <0: error occurred, no longer trying
**
**		Before usage:
**			Open_Socket();
**			Set local_port to desired port number.
**			Listen_Socket();
**
***********************************************************************/
{
	SOCKAI sa;
	REBREQ *news;
	int len = sizeof(sa);
	int result;
	extern void Attach_Request(REBREQ **prior, REBREQ *req);

	// Accept a new socket, if there is one:
	result = accept(sock->socket, (struct sockaddr *)&sa, &len);

	if (result == BAD_SOCKET) {
		result = GET_ERROR;
		if (result == NE_WOULDBLOCK) return DR_PEND;
		sock->error = result;
		//Signal_Device(sock, EVT_ERROR);
		return DR_ERROR;
	}

	// To report the new socket, the code here creates a temporary
	// request and copies the listen request to it. Then, it stores
	// the new values for IP and ports and links this request to the
	// original via the sock->data.
	news = MAKE_NEW(*news);	// Be sure to deallocate it
	CLEARS(news);
//	*news = *sock;
	news->device = sock->device;

	SET_OPEN(news);
	SET_FLAG(news->state, RSM_OPEN);
	SET_FLAG(news->state, RSM_CONNECT);

	news->socket = result;
	news->net.remote_ip   = sa.sin_addr.s_addr; //htonl(ip); NOTE: REBOL stays in network byte order
	news->net.remote_port = ntohs(sa.sin_port);
	Get_Local_IP(news);

	//Nonblocking_Mode(news->socket);  ???Needed?

	Attach_Request((REBREQ**)&sock->data, news);
	Signal_Device(sock, EVT_ACCEPT);

	// Even though we signalled, we keep the listen pending to
	// accept additional connections.
	return DR_PEND;
}
Пример #6
0
*/	int OS_Do_Device(REBREQ *req, REBCNT command)
/*
**		Tell a device to perform a command. Non-blocking in many
**		cases and will attach the request for polling.
**
**		Returns:
**			=0: for command success
**			>0: for command still pending
**			<0: for command error
**
***********************************************************************/
{
	REBDEV *dev;
	REBINT result;

	req->error = 0; // A94 - be sure its cleared

	// Validate device:
	if (req->device >= RDI_MAX || !(dev = Devices[req->device])) {
		req->error = RDE_NO_DEVICE;
		return -1;
	}

	// Confirm device is initialized. If not, return an error or init
	// it if auto init option is set.
	if (!GET_FLAG(dev->flags, RDF_INIT)) {
		if (GET_FLAG(dev->flags, RDO_MUST_INIT)) {
			req->error = RDE_NO_INIT;
			return -1;
		}
		if (!dev->commands[RDC_INIT] || !dev->commands[RDC_INIT]((REBREQ*)dev))
		SET_FLAG(dev->flags, RDF_INIT);
	}

	// Validate command:
	if (command > dev->max_command || dev->commands[command] == 0) {
		req->error = RDE_NO_COMMAND;
		return -1;
	}

	// Do the command:
	req->command = command;
	result = dev->commands[command](req);

	// If request is pending, attach it to device for polling:
	if (result > 0) Attach_Request(&dev->pending, req);
	else if (dev->pending) {
		Detach_Request(&dev->pending, req); // often a no-op
		if (result == DR_ERROR && GET_FLAG(req->flags, RRF_ALLOC)) { // not on stack
			Signal_Device(req, EVT_ERROR);
		}
	}

	return result;
}
Пример #7
0
*/	DEVICE_CMD Poll_DNS(REBREQ *dr)
/*
**		Check for completed DNS requests. These are marked with
**		RRF_DONE by the windows message event handler (dev-event.c).
**		Completed requests are removed from the pending queue and
**		event is signalled (for awake dispatch).
**
***********************************************************************/
{
	REBDEV *dev = (REBDEV*)dr;  // to keep compiler happy
	REBREQ **prior = &dev->pending;
	REBREQ *req;
	BOOL change = FALSE;
	HOSTENT *host;

	// Scan the pending request list:
	for (req = *prior; req; req = *prior) {

		// If done or error, remove command from list:
		if (GET_FLAG(req->flags, RRF_DONE)) { // req->error may be set
			*prior = req->next;
			req->next = 0;
			CLR_FLAG(req->flags, RRF_PENDING);

			if (!req->error) { // success!
				host = (HOSTENT*)req->net.host_info;
				if (GET_FLAG(req->modes, RST_REVERSE))
					req->data = host->h_name;
				else
					COPY_MEM((char*)&(req->net.remote_ip), (char *)(*host->h_addr_list), 4); //he->h_length);
				Signal_Device(req, EVT_READ);
			}
			else
				Signal_Device(req, EVT_ERROR);
			change = TRUE;
		}
		else prior = &req->next;
	}

	return change;
}
Пример #8
0
*/	DEVICE_CMD Transfer_Socket(REBREQ *sock)
/*
**		Write or read a socket (for connection-based protocols).
**
**		This function is asynchronous. It will return immediately.
**		You can call this function again to check the pending connection.
**
**		The mode is RSM_RECEIVE or RSM_SEND.
**
**		The function will return:
**			=0: succeeded
**			>0: in-progress, still trying
**		    <0: error occurred, no longer trying
**
**		Before usage:
**			Open_Socket()
**			Connect_Socket()
**			Verify that RSM_CONNECT is true
**			Setup the sock->data and sock->length
**
**		Note that the mode flag is cleared by the caller, not here.
**
***********************************************************************/
{
	int result;
	long len;
	int mode = (sock->command == RDC_READ ? RSM_RECEIVE : RSM_SEND);

	if (!GET_FLAG(sock->state, RSM_CONNECT)) {
		sock->error = -18;
		return DR_ERROR;
	}

	SET_FLAG(sock->state, mode);

	// Limit size of transfer:
	len = MIN(sock->length, MAX_TRANSFER);

	if (mode == RSM_SEND) {
		// If host is no longer connected:
		result = send(sock->socket, sock->data, len, 0);
		WATCH2("send() len: %d actual: %d\n", len, result);

		if (result >= 0) {
			sock->data += result;
			sock->actual += result;
			if (sock->actual >= sock->length) {
				Signal_Device(sock, EVT_WROTE);
				return DR_DONE;
			}
			return DR_PEND;
		}
		// if (result < 0) ...
	}
	else {
		result = recv(sock->socket, sock->data, len, 0);
		WATCH2("recv() len: %d result: %d\n", len, result);

		if (result > 0) {
			sock->actual = result;
			Signal_Device(sock, EVT_READ);
			return DR_DONE;
		}
		if (result == 0) {		// The socket gracefully closed.
			sock->actual = 0;
			CLR_FLAG(sock->state, RSM_CONNECT); // But, keep RRF_OPEN true
			Signal_Device(sock, EVT_CLOSE);
			return DR_DONE;
		}
		// if (result < 0) ...
	}

	// Check error code:
	result = GET_ERROR;
	WATCH2("get error: %d %s\n", result, strerror(result));
	if (result == NE_WOULDBLOCK) return DR_PEND; // still waiting

	WATCH4("ERROR: recv(%d %x) len: %d error: %d\n", sock->socket, sock->data, len, result);
	// A nasty error happened:
	sock->error = result;
	//Signal_Device(sock, EVT_ERROR);
	return DR_ERROR;
}
Пример #9
0
*/	DEVICE_CMD Connect_Socket(REBREQ *sock)
/*
**		Connect a socket to a service.
**		Only required for connection-based protocols (e.g. not UDP).
**		The IP address must already be resolved before calling.
**
**		This function is asynchronous. It will return immediately.
**		You can call this function again to check the pending connection.
**
**		The function will return:
**			=0: connection succeeded (or already is connected)
**			>0: in-progress, still trying
**		    <0: error occurred, no longer trying
**
**		Before usage:
**			Open_Socket() -- to allocate the socket
**
***********************************************************************/
{
	int result;
	SOCKAI sa;

	if (GET_FLAG(sock->modes, RST_LISTEN))
		return Listen_Socket(sock);

	if (GET_FLAG(sock->state, RSM_CONNECT)) return DR_DONE; // already connected

	Set_Addr(&sa, sock->net.remote_ip, sock->net.remote_port);
	result = connect(sock->socket, (struct sockaddr *)&sa, sizeof(sa));

	if (result != 0) result = GET_ERROR;

	WATCH2("connect() error: %d - %s\n", result, strerror(result));

	switch (result) {

	case 0: // no error
	case NE_ISCONN:
		// Connected, set state:
		CLR_FLAG(sock->state, RSM_ATTEMPT);
		SET_FLAG(sock->state, RSM_CONNECT);
		Get_Local_IP(sock);
		Signal_Device(sock, EVT_CONNECT);
		return DR_DONE; // done

#ifdef TO_WIN32
	case NE_INVALID:	// Corrects for Microsoft bug
#endif
	case NE_WOULDBLOCK:
	case NE_INPROGRESS:
	case NE_ALREADY:
		// Still trying:
		SET_FLAG(sock->state, RSM_ATTEMPT);
		return DR_PEND;

	default:
		// An error happened:
		CLR_FLAG(sock->state, RSM_ATTEMPT);
		sock->error = result;
		//Signal_Device(sock, EVT_ERROR);
		return DR_ERROR;
	}
}
Пример #10
0
*/	DEVICE_CMD Lookup_Socket(REBREQ *sock)
/*
**		Initiate the GetHost request and return immediately.
**		This is very similar to the DNS device.
**		The request will pend until the main event handler gets WM_DNS.
**		Note the temporary results buffer (must be freed later).
**		Note we use the sock->handle for the DNS handle. During use,
**		we store the TCP socket in the length field.
**
***********************************************************************/
{
#ifdef TO_WIN32
	HANDLE handle;
#endif
	HOSTENT *host;

#ifdef HAS_ASYNC_DNS
	// Check if we are polling for completion:
	if (host = (HOSTENT*)(sock->net.host_info)) {
		// The windows main event handler will change this when it gets WM_DNS event:
		if (!GET_FLAG(sock->flags, RRF_DONE)) return DR_PEND; // still waiting
		CLR_FLAG(sock->flags, RRF_DONE);
		if (!sock->error) { // Success!
			host = (HOSTENT*)sock->net.host_info;
			COPY_MEM((char*)&(sock->net.remote_ip), (char *)(*host->h_addr_list), 4); //he->h_length);
			Signal_Device(sock, EVT_LOOKUP);
		}
		else
			Signal_Device(sock, EVT_ERROR);
		OS_Free(host);	// free what we allocated earlier
		sock->socket = sock->length; // Restore TCP socket saved below
		sock->net.host_info = 0;
		return DR_DONE;
	}

	// Else, make the lookup request:
	host = OS_Make(MAXGETHOSTSTRUCT); // be sure to free it
	handle = WSAAsyncGetHostByName(Event_Handle, WM_DNS, sock->data, (char*)host, MAXGETHOSTSTRUCT);
	if (handle != 0) {
		sock->net.host_info = host;
		sock->length = sock->socket; // save TCP socket temporarily
		sock->handle = handle;
		return DR_PEND; // keep it on pending list
	}
	OS_Free(host);
#else
	// Use old-style blocking DNS (mainly for testing purposes):
	host = gethostbyname(sock->data);
	sock->net.host_info = 0; // no allocated data

	if (host) {
		COPY_MEM((char*)&(sock->net.remote_ip), (char *)(*host->h_addr_list), 4); //he->h_length);
		CLR_FLAG(sock->flags, RRF_DONE);
		Signal_Device(sock, EVT_LOOKUP);
		return DR_DONE;
	}
#endif

	sock->error = GET_ERROR;
	//Signal_Device(sock, EVT_ERROR);
	return DR_ERROR; // Remove it from pending list
}