as_status as_key_set_digest(as_error* err, as_key* key) { if (key->digest.init) { return AEROSPIKE_OK; } size_t set_len = strlen(key->set); size_t size; as_val* val = (as_val*)key->valuep; uint8_t* buf; switch (val->type) { case AS_INTEGER: { as_integer* v = as_integer_fromval(val); size = 9; buf = alloca(size); buf[0] = AS_BYTES_INTEGER; *(uint64_t*)&buf[1] = cf_swap_to_be64(v->value); break; } case AS_DOUBLE: { as_double* v = as_double_fromval(val); size = 9; buf = alloca(size); buf[0] = AS_BYTES_DOUBLE; *(double*)&buf[1] = cf_swap_to_big_float64(v->value); break; } case AS_STRING: { as_string* v = as_string_fromval(val); size_t len = as_string_len(v); size = len + 1; buf = alloca(size); buf[0] = AS_BYTES_STRING; memcpy(&buf[1], v->value, len); break; } case AS_BYTES: { as_bytes* v = as_bytes_fromval(val); size = v->size + 1; buf = alloca(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. buf[0] = v->type; memcpy(&buf[1], v->value, v->size); break; } default: { return as_error_update(err, AEROSPIKE_ERR_PARAM, "Invalid key type: %d", val->type); } } cf_digest_compute2(key->set, set_len, buf, size, (cf_digest*)key->digest.value); key->digest.init = true; return AEROSPIKE_OK; }
static as_status as_admin_send(as_error* err, int fd, uint8_t* buffer, uint8_t* end, uint64_t deadline_ms) { uint64_t len = end - buffer; uint64_t proto = (len - 8) | (MSG_VERSION << 56) | (MSG_TYPE << 48); *(uint64_t*)buffer = cf_swap_to_be64(proto); return as_socket_write_deadline(err, fd, buffer, len, deadline_ms); }
static int as_send(int fd, uint8_t* buffer, uint8_t* end, uint64_t deadline_ms, int timeout_ms) { uint64_t len = end - buffer; uint64_t proto = (len - 8) | (MSG_VERSION << 56) | (MSG_TYPE << 48); *(uint64_t*)buffer = cf_swap_to_be64(proto); return cf_socket_write_timeout(fd, buffer, len, deadline_ms, timeout_ms); }
// Byte swap proto from current machine byte order to network byte order (big endian). void as_proto_swap_to_be(as_proto *p) { uint8_t version = p->version; uint8_t type = p->type; p->version = p->type = 0; p->sz = cf_swap_to_be64(*(uint64_t*)p); p->version = version; p->type = type; }
static uint8_t* as_command_write_user_key(uint8_t* begin, const as_key* key) { uint8_t* p = begin + AS_FIELD_HEADER_SIZE; as_val* val = (as_val*)key->valuep; uint32_t len; // Key must not be list or map. switch (val->type) { default: case AS_NIL: { *p++ = AS_BYTES_UNDEF; len = 0; break; } case AS_INTEGER: { as_integer* v = as_integer_fromval(val); *p++ = AS_BYTES_INTEGER; *(uint64_t*)p = cf_swap_to_be64(v->value); p += 8; len = 8; break; } case AS_DOUBLE: { as_double* v = as_double_fromval(val); *p++ = AS_BYTES_DOUBLE; *(double*)p = cf_swap_to_big_float64(v->value); p += 8; len = 8; break; } case AS_STRING: { as_string* v = as_string_fromval(val); *p++ = AS_BYTES_STRING; // v->len should have been already set when calculating the digest. memcpy(p, v->value, v->len); p += v->len; len = (uint32_t)v->len; break; } case AS_BYTES: { as_bytes* v = as_bytes_fromval(val); // 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. *p++ = v->type; memcpy(p, v->value, v->size); p += v->size; len = v->size; break; } } as_command_write_field_header(begin, AS_FIELD_KEY, ++len); return p; }
uint32_t as_authenticate_set(const char* user, const char* credential, uint8_t* buffer) { uint8_t* p = buffer + 8; p = as_admin_write_header(p, AUTHENTICATE, 2); p = as_admin_write_field_string(p, USER, user); p = as_admin_write_field_string(p, CREDENTIAL, credential); uint64_t len = p - buffer; uint64_t proto = (len - 8) | (MSG_VERSION << 56) | (MSG_TYPE << 48); *(uint64_t*)buffer = cf_swap_to_be64(proto); return (uint32_t)len; }
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; }
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_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; break; } case AS_MAP: { memcpy(p, buffer->data, buffer->size); p += buffer->size; val_len = buffer->size; val_type = AS_BYTES_MAP; 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; }
cl_msg * as_msg_make_response_msg(uint32_t result_code, uint32_t generation, uint32_t void_time, as_msg_op **ops, as_bin **bins, uint16_t bin_count, as_namespace *ns, cl_msg *msgp_in, size_t *msg_sz_in, uint64_t trid, const char *setname) { size_t msg_sz = sizeof(cl_msg); msg_sz += sizeof(as_msg_op) * bin_count; for (uint16_t i = 0; i < bin_count; i++) { if (ops) { msg_sz += ops[i]->name_sz; } else if (bins[i]) { msg_sz += ns->single_bin ? 0 : strlen(as_bin_get_name_from_id(ns, bins[i]->id)); } else { cf_crash(AS_PROTO, "making response message with null bin and op"); } if (bins[i]) { msg_sz += as_bin_particle_client_value_size(bins[i]); } } if (trid != 0) { msg_sz += sizeof(as_msg_field) + sizeof(trid); } uint32_t setname_len = 0; if (setname) { setname_len = strlen(setname); msg_sz += sizeof(as_msg_field) + setname_len; } uint8_t *b; if (! msgp_in || *msg_sz_in < msg_sz) { b = cf_malloc(msg_sz); if (! b) { return NULL; } } else { b = (uint8_t *)msgp_in; } *msg_sz_in = msg_sz; uint8_t *buf = b; cl_msg *msgp = (cl_msg *)buf; msgp->proto.version = PROTO_VERSION; msgp->proto.type = PROTO_TYPE_AS_MSG; msgp->proto.sz = msg_sz - sizeof(as_proto); as_proto_swap(&msgp->proto); as_msg *m = &msgp->msg; m->header_sz = sizeof(as_msg); m->info1 = 0; m->info2 = 0; m->info3 = 0; m->unused = 0; m->result_code = result_code; m->generation = generation; m->record_ttl = void_time; m->transaction_ttl = 0; m->n_ops = bin_count; m->n_fields = 0; buf += sizeof(cl_msg); if (trid != 0) { m->n_fields++; as_msg_field *trfield = (as_msg_field *)buf; trfield->field_sz = 1 + sizeof(uint64_t); trfield->type = AS_MSG_FIELD_TYPE_TRID; *(uint64_t *)trfield->data = cf_swap_to_be64(trid); buf += sizeof(as_msg_field) + sizeof(uint64_t); as_msg_swap_field(trfield); } if (setname) { m->n_fields++; as_msg_field *trfield = (as_msg_field *)buf; trfield->field_sz = 1 + setname_len; trfield->type = AS_MSG_FIELD_TYPE_SET; memcpy(trfield->data, setname, setname_len); buf += sizeof(as_msg_field) + setname_len; as_msg_swap_field(trfield); } as_msg_swap_header(m); for (uint16_t i = 0; i < bin_count; i++) { as_msg_op *op = (as_msg_op *)buf; op->version = 0; if (ops) { op->op = ops[i]->op; memcpy(op->name, ops[i]->name, ops[i]->name_sz); op->name_sz = ops[i]->name_sz; } else { op->op = AS_MSG_OP_READ; op->name_sz = as_bin_memcpy_name(ns, op->name, bins[i]); } op->op_sz = 4 + op->name_sz; buf += sizeof(as_msg_op) + op->name_sz; buf += as_bin_particle_to_client(bins[i], op); as_msg_swap_op(op); } return (cl_msg *)b; }
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; }