Esempio n. 1
0
void Connection_handle_event(Connection *connection, EventType event, int ordinal)
{
	if(CS_ABORTED == connection->state) {
		return;
	}

	DEBUG(("con event, fd: %d, state: %d, event: %d, readable: %d, writeable: %d, timeout: %d\n", connection->sockfd,
			connection->state, event, (event & EVENT_READ) ? 1 : 0, (event & EVENT_WRITE) ? 1 : 0, (event & EVENT_TIMEOUT) ? 1 : 0 ));

	if(event & EVENT_ERROR) {
		Connection_abort(connection, "event error");
		return;
	}

	if(event & EVENT_TIMEOUT) {
		if(CS_CONNECTING == connection->state) {
			Connection_abort(connection, "connect timeout");
		}
		else {
			Connection_abort(connection, "read/write timeout");
		}
		return;
	}

	if(event & EVENT_WRITE) {
		Connection_write_data(connection, ordinal);
	}

	if(event & EVENT_READ) {
		Connection_read_data(connection, ordinal);
	}

}
Esempio n. 2
0
int Connection_create_socket(Connection *connection)
{
	assert(connection != NULL);
	assert(CS_CLOSED == connection->state);

	//create socket
	connection->sockfd = socket(AF_INET, SOCK_STREAM, 0);
	if(connection->sockfd == -1) {
		Connection_abort(connection, "could not create socket");
		return -1;
	}

	//set socket in non-blocking mode
	int flags;
	if ((flags = fcntl(connection->sockfd, F_GETFL, 0)) < 0)
	{
		Connection_abort(connection, "could not get socket flags for");
		return -1;
	}
	if (fcntl(connection->sockfd, F_SETFL, flags | O_NONBLOCK) < 0)
	{
		Connection_abort(connection, "could not set socket to non-blocking mode");
		return -1;
	}
	return 0;
}
Esempio n. 3
0
void Connection_read_data(Connection *connection, int ordinal)
{
    if(CS_ABORTED == connection->state) {
        return;
    }

    DEBUG(("connection read data fd: %d\n", connection->sockfd));
    assert(connection->current_batch != NULL);
    assert(connection->current_executor != NULL);
    assert(CS_CONNECTED == connection->state);

    Buffer *buffer = Batch_read_buffer(connection->current_batch);
    assert(buffer != NULL);

    while(Batch_has_command(connection->current_batch)) {
        DEBUG(("exec rp\n"));
        Reply *reply = NULL;
        ReplyParserResult rp_res = ReplyParser_execute(connection->parser, Buffer_data(buffer), Buffer_position(buffer), &reply);
        switch(rp_res) {
        case RPR_ERROR: {
            Connection_abort(connection, "result parse error");
            return;
        }
        case RPR_MORE: {
            DEBUG(("read data RPR_MORE buf recv\n"));
            size_t res = Buffer_recv(buffer, connection->sockfd);
            DEBUG(("read data RPR_MORE res: %d\n", res));
#ifndef NDEBUG
        Buffer_dump(buffer, 128);
#endif
            if(res == -1) {
                if(errno == EAGAIN) {
                     DEBUG(("read data expecting more data in future, adding event\n"));
                    Executor_notify_event(connection->current_executor, connection, EVENT_READ, ordinal);
                    return;
                }
                else {
                    Connection_abort(connection, "read error, errno: [%d] %s", errno, strerror(errno));
                    return;
                }
            }
            else if(res == 0) {
                Connection_abort(connection, "read eof");
                return;
            }
            break;
        }
        case RPR_REPLY: {
            DEBUG(("read data RPR_REPLY batch add reply\n"));
            Batch_add_reply(connection->current_batch, reply);
            break;
        }
        default:
            Connection_abort(connection, "unexpected result parser result, rpres: %d", rp_res);
            return;
        }
    }
}
Esempio n. 4
0
int Connection_create_socket(Connection *connection)
{
	assert(connection != NULL);
	assert(CS_CLOSED == connection->state);

	//resolve address
	struct addrinfo hints;
	memset(&hints, 0, sizeof(hints));
	hints.ai_socktype = SOCK_STREAM;
	hints.ai_flags = AI_ADDRCONFIG;
	if (getaddrinfo(connection->addr, connection->serv, &hints, &connection->addrinfo)) {
		Connection_abort(connection, "could not resolve address");
		return -1;
	}

	//create socket
	struct addrinfo *addrinfo = connection->addrinfo;
	connection->sockfd = socket(addrinfo->ai_family, addrinfo->ai_socktype, addrinfo->ai_protocol);
	if(connection->sockfd == -1) {
		Connection_abort(connection, "could not create socket");
		return -1;
	}

	//set socket in non-blocking mode
	int flags;
	if ((flags = fcntl(connection->sockfd, F_GETFL, 0)) < 0)
	{
		Connection_abort(connection, "could not get socket flags for");
		return -1;
	}
	if (fcntl(connection->sockfd, F_SETFL, flags | O_NONBLOCK) < 0)
	{
		Connection_abort(connection, "could not set socket to non-blocking mode");
		return -1;
	}
	return 0;
}
Esempio n. 5
0
void Connection_write_data(Connection *connection, int ordinal)
{
	DEBUG(("connection write_data fd: %d\n", connection->sockfd));
	assert(connection->current_batch != NULL);
	assert(connection->current_executor != NULL);
	if(CS_ABORTED == connection->state) {
		return;
	}

	if(CS_CLOSED == connection->state) {
		if(-1 == Connection_create_socket(connection)) {
			//already aborted in create_socket
			return;
		}
		//connect the socket
		struct addrinfo *addrinfo = connection->addrinfo;
		if(-1 == connect(connection->sockfd, addrinfo->ai_addr, addrinfo->ai_addrlen)) {
			//open the connection
			if(EINPROGRESS == errno) {
				//normal async connect
				connection->state = CS_CONNECTING;
				DEBUG(("async connecting, adding write event\n"));
				Executor_notify_event(connection->current_executor, connection, EVENT_WRITE, ordinal);
				DEBUG(("write event added, now returning\n"));
				return;
			}
			else {
				Connection_abort(connection, "connect error 1, errno [%d] %s", errno, strerror(errno));
				return;
			}
		}
		else {
			//immediate connect succeeded
			DEBUG(("sync connected\n"));
			connection->state = CS_CONNECTED;
		}
	}

	if(CS_CONNECTING == connection->state) {
		//now check for error to see if we are really connected
		int error;
		socklen_t len = sizeof(int);
		if(-1 == getsockopt(connection->sockfd, SOL_SOCKET, SO_ERROR, &error, &len)) {
			Connection_abort(connection, "getsockopt error for connect result, errno: [%d] %s", errno, strerror(errno));
			return;
		}
		if(error != 0) {
			Connection_abort(connection, "connect error 2, error: [%d] %s", error, strerror(error));
			return;
		}
		else {
			connection->state = CS_CONNECTED;
			Executor_notify_event(connection->current_executor, connection, EVENT_READ, ordinal);
		}
	}

	if(CS_CONNECTED == connection->state) {

		Buffer *buffer = Batch_write_buffer(connection->current_batch);
		assert(buffer != NULL);
		while(Buffer_remaining(buffer)) {
			//still something to write
			size_t res = Buffer_send(buffer, connection->sockfd);
			DEBUG(("bfr send res: %d\n", res));
			if(res == -1) {
				if(errno == EAGAIN) {
					Executor_notify_event(connection->current_executor, connection, EVENT_WRITE, ordinal);
					return;
				}
				else {
					Connection_abort(connection, "write error, errno: [%d] %s", errno, strerror(errno));
					return;
				}
			}
		}
	}
}