Example #1
0
static void _sput( T _this_, OEK_Context *context ) {

    Oek_Impl_ *client = (Oek_Impl_*) OEK_get_client(_this_);
    OeStore store = client->store;

    Arena_T arena = context->arena;

    OekMsg msg = context->cmd_msg;
    oe_id corid = OekMsg_get_cid(msg);
    oe_id txnid = OekMsg_get_tid(msg);
    PutCmd cmd = OekMsg_get_put_cmd(msg);

    //build the db entry
    DataObject values = PutCmd_get_data(cmd);
    assert(values);
    OeStoreHolder holder = OeStoreHolder_new_with_data(arena, values);

    OeStoreHolder_set_txn_id           (holder, txnid);
    oe_time exptime;
    oe_time dur = PutCmd_get_dur(cmd);
    if (dur == OEC_FOREVER) {
        exptime = OEC_FOREVER;
    } else {
        exptime = oec_get_time_milliseconds() + dur;
    }
    OeStoreHolder_set_lease_expire_time(holder, exptime);
    OeStoreHolder_set_lock             (holder, txnid == 0 ? OESTORE_UNLOCKED : OESTORE_WRITE_LOCK );
    OeStoreHolder_set_tuple            (holder, PutCmd_is_tuple(cmd));

    int ret;
    for ( int i = 0 ; i < OEK_MAX_DB_DEADLOCKS ; i++ ) {
        ret = OeStore_put(store, holder, arena);
        if ( ret != OE_STORE_PLEASE_RETRY ) break;
        OE_DLOG(NULL,OEK_STR_PUT_DL_RETRY, i + 1);
    }

    if ( ret ) {

        OE_ERR( NULL, "%s: %s", OEK_STR_PUT_FAILED, OeStore_strerror(store, ret) );

        _send_error(context, 104, OEK_STR_CAN_NOT_STORE);

    } else {

        OekMsg res_msg = OekMsg_new(PUT_RES, arena);
        PutRes res = OekMsg_get_put_res(res_msg);
        OekMsg_set_cid(res_msg, corid);
        OekMsg_set_tid(res_msg, txnid);
        //PutRes_set_expiretime(res, OeStoreHolder_get_lease_expire_time( holder ) );
        PutRes_set_lease_id(res, OeStoreHolder_get_lease_id(holder) );
        context->res_msgs = Oec_AList_list(arena, res_msg, NULL);
        _default_write_to_client(context);
    }
}
Example #2
0
static bool _handle_request(const char *path,
                            const char *mode,
                            const uint16_t opcode,
                            const struct addrinfo *local_address,
                            const struct sockaddr *client_address,
                            const socklen_t address_size) {
	/* the socket */
	int s = (-1);

	/* the source address */
	struct sockaddr source = {0};

	/* the return value */
	bool result = false;

	/* the transaction ID */
	short tid = 0;

	assert(NULL != path);
	assert((PACKET_TYPE_RRQ == opcode) || (PACKET_TYPE_WRQ == opcode));
	assert(0 < address_size);
	assert(NULL != local_address);
	assert(NULL != client_address);
	assert(0 < address_size);

	/* get the transaction ID */
	switch (client_address->sa_family) {
		case AF_INET:
			tid = ((struct sockaddr_in *) client_address)->sin_port;
			break;

		case AF_INET6:
			tid = ((struct sockaddr_in6 *) client_address)->sin6_port;
			break;

		default:
			goto end;
	}

	/* create a socket */
	s = socket(local_address->ai_family,
	           local_address->ai_socktype,
	           local_address->ai_protocol);
	if (-1 == s) {
		goto end;
	}

	/* set the socket timeout */
	if (false == _set_timeout(s)) {
		goto end;
	}

	/* pick a unique source port and bind the socket on it */
	(void) memcpy(&source, local_address->ai_addr, local_address->ai_addrlen);
	if (false == _pick_tid(s, &source, local_address->ai_addrlen)) {
		goto close_socket;
	}

	/* make sure the transfer mode is "octet" */
	if (0 != strcmp("octet", mode)) {
		_send_error(s, ERROR_ILLEGAL_OPERATION, client_address, address_size);
		goto close_socket;
	}

	/* make sure the file doesn't contain a sub-director */
	if (NULL != strchr(path, '/')) {
		_send_error(s, ERROR_ACCESS_VIOLATION, client_address, address_size);
		goto close_socket;
	}

	/* handle the request */
	switch (opcode) {
		case PACKET_TYPE_RRQ:
			_log_request("GET", path, client_address, address_size);
			result = _handle_rrq(s, path, client_address, address_size, tid);
			break;

		case PACKET_TYPE_WRQ:
			_log_request("PUT", path, client_address, address_size);
			result = _handle_wrq(s, path, client_address, address_size, tid);
			break;

		default:
			_send_error(s,
			            ERROR_ILLEGAL_OPERATION,
			            client_address,
			            address_size);
			goto close_socket;
	}

close_socket:
	/* close the socket */
	(void) close(s);

end:
	return result;
}
Example #3
0
static bool _handle_rrq(const int s,
                        const char *path,
                        const struct sockaddr *address,
                        const socklen_t address_size,
                        const short tid) {
	/* a data chunk */
	data_t chunk = {{0}};

	/* the address the acknowledgement was received from */
	struct sockaddr ack_source = {0};

	/* the chunk size */
	ssize_t size = 0;

	/* the source address size */
	socklen_t source_address_size = 0;

	/* the input file */
	int file = (-1);

	/* an acknowledment message */
	ack_t ack = {0};

	/* chunk ID */
	uint16_t id = 0;

	/* the acknowledgement transaction ID */
	short ack_tid = 0;

	/* the return value */
	bool result = false;

	assert(STDERR_FILENO < s);
	assert(NULL != path);
	assert(NULL != address);
	assert(0 < address_size);
	assert(0 != tid);

	/* create the file */
	file = open(path, O_RDONLY);
	if (-1 == file) {
		switch (errno) {
			case ENOENT:
				_send_error(s, ERROR_FILE_NOT_FOUND, address, address_size);
				break;

			case EPERM:
			case EACCES:
			case EROFS:
				_send_error(s, ERROR_ACCESS_VIOLATION, address, address_size);
		}

		goto end;
	}

	chunk.header.opcode = htons(PACKET_TYPE_DATA);
	do {
		/* read a data chunk */
		size = read(file, (void *) &chunk.data, sizeof(chunk.data));
		if (-1 == size) {
			goto close_file;
		}

		/* send the chunk */
		++id;
		chunk.header.id = htons(id);
		size += sizeof(chunk.header);
		if (size != sendto(s,
		                   (const void *) &chunk,
		                   size,
		                   0,
		                   address,
		                   address_size)) {
			goto end;
		}

		/* wait for an acknowledgment message */
		source_address_size = sizeof(ack_source);
		if (sizeof(ack) != recvfrom(s,
		                            (void *) &ack,
		                            sizeof(ack),
		                            0,
		                            &ack_source,
		                            &source_address_size)) {
			goto close_file;
		}

		/* make sure the acknowledgment is an acknowledgment packet */
		if (htons(PACKET_TYPE_ACK) != ack.opcode) {
			goto close_file;
		}

		/* make sure the acknowledgment message has the right chunk number */
		if (chunk.header.id != ack.id) {
			goto close_file;
		}

		/* make sure the acknowledgment message has the right transaction ID */
		switch (ack_source.sa_family) {
			case AF_INET:
				ack_tid = ((struct sockaddr_in *) &ack_source)->sin_port;
				break;

			case AF_INET6:
				ack_tid = ((struct sockaddr_in6 *) &ack_source)->sin6_port;
				break;
		}
		if (tid != ack_tid) {
			_send_error(s, ERROR_UNKNOWN_TID, address, address_size);
			goto close_file;
		}

	/* stop once a small or empty chunk is sent */
	} while (sizeof(chunk) == size);

	/* report success */
	result = true;

close_file:
	/* close the file */
	(void) close(file);

end:
	return result;
}
Example #4
0
static bool _handle_wrq(const int s,
                        const char *path,
                        const struct sockaddr *address,
                        const socklen_t address_size,
                        const short tid) {
	/* a data chunk */
	data_t chunk = {{0}};

	/* the address the chunk was received from */
	struct sockaddr chunk_source = {0};

	/* the chunk size */
	ssize_t size = 0;

	/* the source address size */
	socklen_t source_address_size = 0;

	/* the output file */
	int file = (-1);

	/* an acknowledgment packet */
	ack_t ack = {0};

	/* the chunk transaction ID */
	short chunk_tid = 0;

	/* the return value */
	bool result = false;

	assert(STDERR_FILENO < s);
	assert(NULL != path);
	assert(NULL != address);
	assert(0 < address_size);
	assert(0 != tid);

	/* create the file */
	file = open(path, O_WRONLY | O_CREAT | O_EXCL, 0666);
	if (-1 == file) {
		switch (errno) {
			case EEXIST:
				_send_error(s, ERROR_FILE_EXISTS, address, address_size);
				break;

			case EPERM:
			case EACCES:
				_send_error(s, ERROR_ACCESS_VIOLATION, address, address_size);
		}

		goto end;
	}

	/* send an acknowledgment message, to indicate the request is valid */
	ack.opcode = htons(PACKET_TYPE_ACK);
	if (sizeof(ack) != sendto(s,
	                          (const void *) &ack,
	                          sizeof(ack),
	                          0,
	                          address,
	                          address_size)) {
		goto end;
	}

	do {
		/* receive a data chunk */
		source_address_size = sizeof(chunk_source);
		size = recvfrom(s,
		                (void *) &chunk,
		                sizeof(chunk),
		                0,
		                &chunk_source,
		                &source_address_size);
		if (-1 == size) {
			goto close_file;
		}

		/* make sure the chunk is a data packet */
		if (htons(PACKET_TYPE_DATA) != chunk.header.opcode) {
			goto close_file;
		}

		/* make sure the chunk was sent with the right transaction ID */
		switch (chunk_source.sa_family) {
			case AF_INET:
				chunk_tid = ((struct sockaddr_in *) &chunk_source)->sin_port;
				break;

			case AF_INET6:
				chunk_tid = ((struct sockaddr_in6 *) &chunk_source)->sin6_port;
				break;
		}
		if (tid != chunk_tid) {
			_send_error(s, ERROR_UNKNOWN_TID, address, address_size);
			goto close_file;
		}

		/* write the chunk to the file */
		size -= sizeof(chunk.header);
		if (size != write(file, (const void *) &chunk.data, (size_t) size)) {
			if (ENOSPC == errno) {
				_send_error(s, ERROR_DISK_FULL, address, address_size);
			}
			goto close_file;
		}

		/* send an acknowledgment message, to indicate the chunk was received */
		ack.id = chunk.header.id;
		if (sizeof(ack) != sendto(s,
		                          (const void *) &ack,
		                          sizeof(ack),
		                          0,
		                          address,
		                          address_size)) {
			goto close_file;
		}

	/* stop once a small or empty chunk is received */
	} while (sizeof(chunk.data) == size);

	/* report success */
	result = true;

close_file:
	/* close the file */
	(void) close(file);

	/* upon failure, also delete it */
	if (false == result) {
		(void) unlink(path);
	}

end:
	return result;
}