Пример #1
0
static as_node*
as_cluster_find_node(as_cluster* cluster, in_addr_t addr, in_port_t port)
{
	as_nodes* nodes = (as_nodes*)cluster->nodes;
	as_node* node;
	as_vector* addresses;
	as_address* address;
	struct sockaddr_in* sockaddr;
	in_port_t port_be = cf_swap_to_be16(port);
	
	for (uint32_t i = 0; i < nodes->size; i++) {
		node = nodes->array[i];
		addresses = &node->addresses;
		
		for (uint32_t j = 0; j < addresses->size; j++) {
			address = as_vector_get(addresses, j);
			sockaddr = &address->addr;
			
			if (sockaddr->sin_addr.s_addr == addr && sockaddr->sin_port == port_be) {
				return node;
			}
		}
	}
	return 0;
}
Пример #2
0
bool
as_lookup(as_cluster* cluster, char* hostname, uint16_t port, bool enable_warning, as_vector* /*<struct sockaddr_in>*/ addresses)
{
	// Check if there is an alternate address that should be used for this hostname.
	if (cluster && cluster->ip_map) {
		as_addr_map* entry = cluster->ip_map;
		
		for (uint32_t i = 0; i < cluster->ip_map_size; i++) {
			if (strcmp(entry->orig, hostname) == 0) {
				// Found mapping for this address.  Use alternate.
				cf_debug("Using %s instead of %s", entry->alt, hostname);
				hostname = entry->alt;
				break;
			}
			entry++;
		}
	}
	
	// Lookup TCP addresses.
	struct addrinfo hints;
	memset(&hints, 0, sizeof(hints));
	hints.ai_family = AF_INET;
	
	struct addrinfo* results = 0;
	int ret = getaddrinfo(hostname, 0, &hints, &results);
	
	if (ret) {
		if (enable_warning) {
			cf_warn("Invalid hostname %s: %s", hostname, gai_strerror(ret));
		}
		return false;
	}
	
	// Add addresses to vector if it exists.
	if (addresses) {
		uint16_t port_be = cf_swap_to_be16(port);
		
		for (struct addrinfo* r = results; r; r = r->ai_next) {
			struct sockaddr_in* addr = (struct sockaddr_in*)r->ai_addr;
			addr->sin_port = port_be;
			as_vector_append_unique(addresses, addr);
		}
	}
	
	freeaddrinfo(results);
	return true;
}
Пример #3
0
// TODO - old pickle - remove in "six months".
// Flatten record's bins into "pickle" format for fabric.
uint8_t *
as_record_pickle(as_storage_rd *rd, size_t *len_r)
{
	as_namespace *ns = rd->ns;

	uint32_t sz = 2; // always 2 bytes for number of bins
	uint16_t n_bins_in_use;

	for (n_bins_in_use = 0; n_bins_in_use < rd->n_bins; n_bins_in_use++) {
		as_bin *b = &rd->bins[n_bins_in_use];

		if (! as_bin_inuse(b)) {
			break;
		}

		sz += 1; // for bin name length
		sz += ns->single_bin ?
				0 : strlen(as_bin_get_name_from_id(ns, b->id)); // for bin name
		sz += 1; // was for version - currently not used

		sz += as_bin_particle_pickled_size(b);
	}

	uint8_t *pickle = cf_malloc(sz);
	uint8_t *buf = pickle;

	(*(uint16_t *)buf) = cf_swap_to_be16(n_bins_in_use); // number of bins
	buf += 2;

	for (uint16_t i = 0; i < n_bins_in_use; i++) {
		as_bin *b = &rd->bins[i];

		// Copy bin name, skipping a byte for name length.
		uint8_t name_len = (uint8_t)as_bin_memcpy_name(ns, buf + 1, b);

		*buf++ = name_len; // fill in bin name length
		buf += name_len; // skip past bin name
		*buf++ = 0; // was version - currently not used

		buf += as_bin_particle_to_pickled(b, buf);
	}

	*len_r = sz;

	return pickle;
}
uint32_t
geojson_asval_to_wire(const as_val *val, uint8_t *wire)
{
	as_geojson *pg = as_geojson_fromval(val);
	size_t jsz = as_geojson_len(pg);

	uint8_t *p8 = wire;

	*p8++ = 0;						// flags

	uint16_t *p16 = (uint16_t *)p8;

	*p16++ = cf_swap_to_be16(0);	// no cells on output to client
	p8 = (uint8_t *)p16;
	memcpy(p8, as_geojson_get(pg), jsz);

	return geojson_size(0, jsz);
}
uint32_t
geojson_to_wire(const as_particle *p, uint8_t *wire)
{
	// Use blob routine first.
	uint32_t sz = blob_to_wire(p, wire);

	// Swap ncells.
	uint16_t *p_ncells = (uint16_t *)(wire + sizeof(uint8_t));
	uint16_t ncells = *p_ncells;

	*p_ncells = cf_swap_to_be16(*p_ncells);
	++p_ncells;

	// Swap the cells.
	uint64_t *p_cell_begin = (uint64_t *)p_ncells;
	uint64_t *p_cell_end = p_cell_begin + ncells;

	for (uint64_t *p_cell = p_cell_begin; p_cell < p_cell_end; ++p_cell) {
		*p_cell = cf_swap_to_be64(*p_cell);
	}

	return sz;
}
Пример #6
0
uint8_t*
as_command_write_header(uint8_t* cmd, uint8_t read_attr, uint8_t write_attr,
                        as_policy_commit_level commit_level, as_policy_consistency_level consistency,
                        as_policy_exists exists, as_policy_gen gen_policy, uint32_t gen, uint32_t ttl,
                        uint32_t timeout_ms, uint16_t n_fields, uint16_t n_bins)
{
    uint32_t generation = 0;
    uint8_t info_attr = 0;

    switch (exists) {
    case AS_POLICY_EXISTS_IGNORE:
        break;

    case AS_POLICY_EXISTS_UPDATE:
        info_attr |= AS_MSG_INFO3_UPDATE_ONLY;
        break;

    case AS_POLICY_EXISTS_CREATE_OR_REPLACE:
        info_attr |= AS_MSG_INFO3_CREATE_OR_REPLACE;
        break;

    case AS_POLICY_EXISTS_REPLACE:
        info_attr |= AS_MSG_INFO3_REPLACE_ONLY;
        break;

    case AS_POLICY_EXISTS_CREATE:
        write_attr |= AS_MSG_INFO2_CREATE_ONLY;
        break;
    }

    switch (gen_policy) {
    case AS_POLICY_GEN_IGNORE:
        break;

    case AS_POLICY_GEN_EQ:
        generation = gen;
        write_attr |= AS_MSG_INFO2_GENERATION;
        break;

    case AS_POLICY_GEN_GT:
        generation = gen;
        write_attr |= AS_MSG_INFO2_GENERATION_GT;
        break;

    default:
        break;
    }

    if (commit_level == AS_POLICY_COMMIT_LEVEL_MASTER) {
        info_attr |= AS_MSG_INFO3_COMMIT_MASTER;
    }

    if (consistency == AS_POLICY_CONSISTENCY_LEVEL_ALL) {
        read_attr |= AS_MSG_INFO1_CONSISTENCY_ALL;
    }

    cmd[8] = 22;
    cmd[9] = read_attr;
    cmd[10] = write_attr;
    cmd[11] = info_attr;
    *(uint16_t*)&cmd[12] = 0;
    *(uint32_t*)&cmd[14] = cf_swap_to_be32(generation);
    *(uint32_t*)&cmd[18] = cf_swap_to_be32(ttl);
    *(uint32_t*)&cmd[22] = cf_swap_to_be32(timeout_ms);
    *(uint16_t*)&cmd[26] = cf_swap_to_be16(n_fields);
    *(uint16_t*)&cmd[28] = cf_swap_to_be16(n_bins);
    return cmd + AS_HEADER_SIZE;
}
Пример #7
0
int
cl_lookup(cl_cluster *asc, char *hostname, short port, cf_vector *sockaddr_in_v)
{
	// do the gethostbyname to find the IP address
	size_t hstbuflen = 1024;
	uint8_t	stack_hstbuf[hstbuflen];
	void *tmphstbuf = stack_hstbuf;
	int rv, herr, addrmapsz;
	struct hostent *hp;
	cl_addrmap *map;
	int retry = 0;
	//Find if there is an alternate address that should be used for this hostname.
	if (asc && (asc->host_addr_map_v.len > 0)) {
		addrmapsz = asc->host_addr_map_v.len;
		for (int i=0; i<addrmapsz; i++) {
			map = cf_vector_pointer_get(&asc->host_addr_map_v, i);
			if (map && strcmp(map->orig, hostname) == 0) {
				//found a mapping for this address. Use the alternate one.
				cf_debug("Using %s instead of %s", map->alt, hostname);
				hostname = map->alt;
				break;
			}
		}
	}

	do {
#ifdef __APPLE__
		// on OSX, gethostbyname is thread safe and there is no '_r' version
		hp = gethostbyname2(hostname, AF_INET);
		rv = 0;
		if(hp == NULL){
			herr = h_errno; // I'm hoping this is thread-safe too, in the Mac world...
		}
#else
		struct hostent hostbuf;
		rv = gethostbyname2_r(hostname, AF_INET, &hostbuf, tmphstbuf, hstbuflen,
				&hp, &herr);
#endif
		/* TRY_AGAIN for a maximun of 3 times, after which throw an error */
		if(retry > 2) {
			cf_error("gethostbyname of %s - maxmimum retries failed", hostname);
			retry = 0;
			return -1;
		}
		if (hp == NULL) {
			hostname = hostname ? hostname : "NONAME";
			switch(herr) {
				case HOST_NOT_FOUND:
					cf_error("gethostbyname says no host at %s", hostname);
					break;
				case NO_ADDRESS:
					cf_error("gethostbyname of %s says invalid address (errno %d)", hostname, herr);
					break;
				case NO_RECOVERY:
					cf_error("gethostbyname of %s says form error (errno %d)", hostname, herr);
					break;
				case TRY_AGAIN:
					cf_error("gethostbyname of %s returned TRY_AGAIN, try again (rv=%d)", hostname, rv);
					retry++;
					continue;
				default:
					cf_error("gethostbyname of %s returned an unknown error (errno %d)", hostname, herr);
					break;
			}
			if (tmphstbuf != stack_hstbuf)		free(tmphstbuf);
			return(-1);
		}
		else if (rv != 0) {
			if (rv == ERANGE) {
				hstbuflen *= 2;
				if (tmphstbuf == stack_hstbuf)
					tmphstbuf = malloc(hstbuflen);
				else
					tmphstbuf = realloc (tmphstbuf, hstbuflen);
				if (!tmphstbuf) {
					cf_error("malloc fail");
					return(-1);
				}
			}
			else if (rv == EAGAIN || herr == TRY_AGAIN) {
				cf_error("gethostbyname returned EAGAIN, try again");
				retry++;
			}
			else if (rv == ETIMEDOUT) {
				cf_error("gethostbyname for %s timed out", hostname ? (hostname): "NONAME");
				if (tmphstbuf != stack_hstbuf)		free(tmphstbuf);
				return(-1);
			}
			else {
				cf_error("gethostbyname returned an unknown error %d %d (errno %d)",rv,herr, errno);
				if (tmphstbuf != stack_hstbuf)		free(tmphstbuf);
				return(-1);
			}
		}
	} while ((rv != 0) || (hp == NULL));

#ifdef DEBUG
	cf_debug("host lookup: %s canonical: %s addrtype %d length: %d",
		hostname, hp->h_name, hp->h_addrtype, hp->h_length);

	for (int i=0;hp->h_aliases[i];i++) {
		cf_debug("  alias %d: %s",i, hp->h_aliases[i]);
	}
	for (int i=0;hp->h_addr_list[i];i++) {
		// todo: print something about the actual address
		cf_debug("  address %d: %x",i,*(uint32_t *) hp->h_addr_list[i]);
	}
#endif

	if (hp->h_addrtype != AF_INET) {
		cf_error("unknown address type %d", hp->h_addrtype);
		if (tmphstbuf != stack_hstbuf)		free(tmphstbuf);
		return(-1);
	}
	
	// sockaddr_in_v is passed as NULL from caller which needs
	// to only check if lookup succeeds. If reach here it is 
	// a successful lookup. 
	if (sockaddr_in_v == NULL) {
		goto ret_success;
	}
	
	// Move into vector
	for (int i=0;hp->h_addr_list[i];i++) {
		struct sockaddr_in 	addr;
		memset(&addr,0,sizeof(addr));
		addr.sin_family = hp->h_addrtype;
		addr.sin_addr.s_addr = *(uint32_t *) hp->h_addr_list[i];
		addr.sin_port = (in_port_t)cf_swap_to_be16(port);
		
		cf_vector_append_unique(sockaddr_in_v, &addr);
	}

ret_success:
	if (tmphstbuf != stack_hstbuf)		free(tmphstbuf);
	
	return(0);
}	
Пример #8
0
uint8_t*
as_command_write_bin(uint8_t* begin, uint8_t operation_type, const as_bin* bin, as_buffer* buffer)
{
	uint8_t* p = begin + AS_OPERATION_HEADER_SIZE;
	const char* name = bin->name;

	// Copy string, but do not transfer null byte.
	while (*name) {
		*p++ = *name++;
	}
	uint8_t name_len = p - begin - AS_OPERATION_HEADER_SIZE;
	as_val* val = (as_val*)bin->valuep;
	uint32_t val_len;
	uint8_t val_type;
	
	switch (val->type) {
		default:
		case AS_NIL: {
			val_len = 0;
			val_type = AS_BYTES_UNDEF;
			break;
		}
		case AS_INTEGER: {
			as_integer* v = as_integer_fromval(val);
			*(uint64_t*)p = cf_swap_to_be64(v->value);
			p += 8;
			val_len = 8;
			val_type = AS_BYTES_INTEGER;
			break;
		}
		case AS_DOUBLE: {
			as_double* v = as_double_fromval(val);
			*(double*)p = cf_swap_to_big_float64(v->value);
			p += 8;
			val_len = 8;
			val_type = AS_BYTES_DOUBLE;
			break;
		}
		case AS_STRING: {
			as_string* v = as_string_fromval(val);
			// v->len should have been already set by as_command_value_size().
			memcpy(p, v->value, v->len);
			p += v->len;
			val_len = (uint32_t)v->len;
			val_type = AS_BYTES_STRING;
			break;
		}
		case AS_GEOJSON: {
			// We send a cellid placeholder so we can fill in points
			// in place on the server w/o changing object size.

			as_geojson* v = as_geojson_fromval(val);
			// v->len should have been already set by as_command_value_size().

			// as_particle_geojson_mem::flags
			*p++ = 0;

			// as_particle_geojson_mem::ncells
			*(uint16_t *) p = cf_swap_to_be16(0);
			p += sizeof(uint16_t);
			
			// placeholder cellid
			// THIS LOOP EXECUTES 0 TIMES (still, it belongs here ...)
			for (int ii = 0; ii < 0; ++ii) {
				*(uint64_t *) p = cf_swap_to_be64(0);
				p += sizeof(uint64_t);
			}

			// json data itself
			memcpy(p, v->value, v->len);
			p += v->len;

			val_len = (uint32_t)(1 + 2 + (0 * 8) + v->len);
			val_type = AS_BYTES_GEOJSON;
			break;
		}
		case AS_BYTES: {
			as_bytes* v = as_bytes_fromval(val);
			memcpy(p, v->value, v->size);
			p += v->size;
			val_len = v->size;
			// Note: v->type must be a blob type (AS_BYTES_BLOB, AS_BYTES_JAVA, AS_BYTES_PYTHON ...).
			// Otherwise, the particle type will be reassigned to a non-blob which causes a
			// mismatch between type and value.
			val_type = v->type;
			break;
		}
		case AS_LIST: {
			memcpy(p, buffer->data, buffer->size);
			p += buffer->size;
			val_len = buffer->size;
			val_type = AS_BYTES_LIST;
			cf_free(buffer->data);
			break;
		}
		case AS_MAP: {
			memcpy(p, buffer->data, buffer->size);
			p += buffer->size;
			val_len = buffer->size;
			val_type = AS_BYTES_MAP;
			cf_free(buffer->data);
			break;
		}
	}
	*(uint32_t*)begin = cf_swap_to_be32(name_len + val_len + 4);
	begin += 4;
	*begin++ = operation_type;
	*begin++ = val_type;
	*begin++ = 0;
	*begin++ = name_len;
	return p;
}
Пример #9
0
/**
 * Call with AS_OPERATIONS_CDT_OP only.
 */
static bool as_operations_cdt_op(as_operations *ops, const as_bin_name name, as_cdt_optype op, size_t n, ...)
{
	if (op >= cdt_op_table_size) {
		return false;
	}

	const cdt_op_table_entry *entry = &cdt_op_table[op];
	if (n < entry->count - entry->opt_args || n > entry->count) {
		return false;
	}

	va_list vl;
	if (n > 0) {
		va_start(vl, n);
	}

	as_arraylist list;
	as_arraylist_inita(&list, (uint32_t)n + 1); // +1 to avoid alloca(0) undefined behavior

	for (size_t i = 0; i < n; i++) {
		as_cdt_paramtype type = entry->args[i];
		switch (type) {
		case AS_CDT_PARAM_PAYLOAD: {
			as_val *arg = va_arg(vl, as_val *);

			if (as_arraylist_append(&list, arg) != AS_ARRAYLIST_OK) {
				va_end(vl);
				as_arraylist_destroy(&list);
				return false;
			}
			break;
		}
		case AS_CDT_PARAM_COUNT: {
			uint64_t arg = va_arg(vl, uint64_t);

			if (as_arraylist_append(&list, (as_val *)as_integer_new(arg)) != AS_ARRAYLIST_OK) {
				va_end(vl);
				as_arraylist_destroy(&list);
				return false;
			}
			break;
		}
		case AS_CDT_PARAM_INDEX: {
			int64_t arg = va_arg(vl, int64_t);

			if (as_arraylist_append(&list, (as_val *)as_integer_new(arg)) != AS_ARRAYLIST_OK) {
				va_end(vl);
				as_arraylist_destroy(&list);
				return false;
			}
			break;
		}
		default:
			break;
		}
	}

	if (n > 0) {
		va_end(vl);
	}

	as_serializer ser;
	as_msgpack_init(&ser);

	uint32_t list_size = as_serializer_serialize_getsize(&ser, (as_val *) &list);
	as_bytes *bytes = as_bytes_new(sizeof(uint16_t) + list_size);
	uint8_t *list_write = as_bytes_get(bytes);
	uint16_t *list_write_op = (uint16_t *)list_write;

	*list_write_op = cf_swap_to_be16(op);
	list_write += sizeof(uint16_t);

	as_serializer_serialize_presized(&ser, (const as_val *) &list, list_write);
	as_serializer_destroy(&ser);
	as_arraylist_destroy(&list);
	bytes->size = bytes->capacity;
	// as_bytes->type default to AS_BYTES_BLOB

	if (entry->rw_type == CDT_RW_TYPE_MODIFY) {
		return as_operations_add_cdt_modify(ops, name, (as_bin_value *) bytes);
	}

	return as_operations_add_cdt_read(ops, name, (as_bin_value *) bytes);
}