/* raw request payload echoed in response */ void rpctest_rawecho_cb (flux_t *h, flux_msg_handler_t *w, const flux_msg_t *msg, void *arg) { int errnum = 0; void *d = NULL; int l = 0; if (flux_request_decode_raw (msg, NULL, &d, &l) < 0) { errnum = errno; goto done; } done: (void)flux_respond_raw (h, msg, errnum, d, l); }
void store_cb (flux_t *h, flux_msg_handler_t *mh, const flux_msg_t *msg, void *arg) { sqlite_ctx_t *ctx = arg; const void *data; int size, hash_len; uint8_t hash[BLOBREF_MAX_DIGEST_SIZE]; char blobref[BLOBREF_MAX_STRING_SIZE] = "-"; int uncompressed_size = -1; int rc = -1; int old_state; //delay cancellation to ensure lock-correctness in sqlite pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &old_state); if (flux_request_decode_raw (msg, NULL, &data, &size) < 0) { flux_log_error (h, "store: request decode failed"); goto done; } if (size > ctx->blob_size_limit) { errno = EFBIG; goto done; } if (blobref_hash (ctx->hashfun, (uint8_t *)data, size, blobref, sizeof (blobref)) < 0) goto done; if ((hash_len = blobref_strtohash (blobref, hash, sizeof (hash))) < 0) goto done; if (size >= compression_threshold) { int r; int out_len = LZ4_compressBound(size); if (ctx->lzo_bufsize < out_len && grow_lzo_buf (ctx, out_len) < 0) goto done; r = LZ4_compress_default (data, ctx->lzo_buf, size, out_len); if (r == 0) { errno = EINVAL; goto done; } uncompressed_size = size; size = r; data = ctx->lzo_buf; } if (sqlite3_bind_text (ctx->store_stmt, 1, (char *)hash, hash_len, SQLITE_STATIC) != SQLITE_OK) { log_sqlite_error (ctx, "store: binding key"); set_errno_from_sqlite_error (ctx); goto done; } if (sqlite3_bind_int (ctx->store_stmt, 2, uncompressed_size) != SQLITE_OK) { log_sqlite_error (ctx, "store: binding size"); set_errno_from_sqlite_error (ctx); goto done; } if (sqlite3_bind_blob (ctx->store_stmt, 3, data, size, SQLITE_STATIC) != SQLITE_OK) { log_sqlite_error (ctx, "store: binding data"); set_errno_from_sqlite_error (ctx); goto done; } if (sqlite3_step (ctx->store_stmt) != SQLITE_DONE && sqlite3_errcode (ctx->db) != SQLITE_CONSTRAINT) { log_sqlite_error (ctx, "store: executing stmt"); set_errno_from_sqlite_error (ctx); goto done; } rc = 0; done: if (rc < 0) { if (flux_respond_error (h, msg, errno, NULL) < 0) flux_log_error (h, "store: flux_respond_error"); } else { if (flux_respond_raw (h, msg, blobref, strlen (blobref) + 1) < 0) flux_log_error (h, "store: flux_respond_raw"); } (void) sqlite3_reset (ctx->store_stmt); pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &old_state); }
void load_cb (flux_t *h, flux_msg_handler_t *mh, const flux_msg_t *msg, void *arg) { sqlite_ctx_t *ctx = arg; const char *blobref = "-"; int blobref_size; uint8_t hash[BLOBREF_MAX_DIGEST_SIZE]; int hash_len; const void *data = NULL; int size = 0; int uncompressed_size; int rc = -1; int old_state; //delay cancellation to ensure lock-correctness in sqlite pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &old_state); if (flux_request_decode_raw (msg, NULL, (const void **)&blobref, &blobref_size) < 0) { flux_log_error (h, "load: request decode failed"); goto done; } if (!blobref || blobref[blobref_size - 1] != '\0') { errno = EPROTO; flux_log_error (h, "load: malformed blobref"); goto done; } if ((hash_len = blobref_strtohash (blobref, hash, sizeof (hash))) < 0) { errno = ENOENT; flux_log_error (h, "load: unexpected foreign blobref"); goto done; } if (sqlite3_bind_text (ctx->load_stmt, 1, (char *)hash, hash_len, SQLITE_STATIC) != SQLITE_OK) { log_sqlite_error (ctx, "load: binding key"); set_errno_from_sqlite_error (ctx); goto done; } if (sqlite3_step (ctx->load_stmt) != SQLITE_ROW) { //log_sqlite_error (ctx, "load: executing stmt"); errno = ENOENT; goto done; } size = sqlite3_column_bytes (ctx->load_stmt, 0); if (sqlite3_column_type (ctx->load_stmt, 0) != SQLITE_BLOB && size > 0) { flux_log (h, LOG_ERR, "load: selected value is not a blob"); errno = EINVAL; goto done; } data = sqlite3_column_blob (ctx->load_stmt, 0); if (sqlite3_column_type (ctx->load_stmt, 1) != SQLITE_INTEGER) { flux_log (h, LOG_ERR, "load: selected value is not an integer"); errno = EINVAL; goto done; } uncompressed_size = sqlite3_column_int (ctx->load_stmt, 1); if (uncompressed_size != -1) { if (ctx->lzo_bufsize < uncompressed_size && grow_lzo_buf (ctx, uncompressed_size) < 0) goto done; int r = LZ4_decompress_safe (data, ctx->lzo_buf, size, uncompressed_size); if (r < 0) { errno = EINVAL; goto done; } if (r != uncompressed_size) { flux_log (h, LOG_ERR, "load: blob size mismatch"); errno = EINVAL; goto done; } data = ctx->lzo_buf; size = uncompressed_size; } rc = 0; done: if (rc < 0) { if (flux_respond_error (h, msg, errno, NULL) < 0) flux_log_error (h, "load: flux_respond_error"); } else { if (flux_respond_raw (h, msg, data, size) < 0) flux_log_error (h, "load: flux_respond_raw"); } (void )sqlite3_reset (ctx->load_stmt); pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &old_state); }
int main (int argc, char *argv[]) { flux_msg_t *msg; const char *topic, *s; const char *json_str = "{\"a\":42}"; const void *d; const char data[] = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; int i, l, len = strlen (data); plan (NO_PLAN); /* no topic is an error */ errno = 0; ok ((msg = flux_request_encode (NULL, json_str)) == NULL && errno == EINVAL, "flux_request_encode returns EINVAL with no topic string"); ok ((msg = flux_request_encode_raw (NULL, data, strlen (data))) == NULL && errno == EINVAL, "flux_request_encode_raw returns EINVAL with no topic string"); /* without payload */ ok ((msg = flux_request_encode ("foo.bar", NULL)) != NULL, "flux_request_encode works with NULL payload"); topic = NULL; ok (flux_request_decode (msg, &topic, NULL) == 0 && topic != NULL && !strcmp (topic, "foo.bar"), "flux_request_decode returns encoded topic"); ok (flux_request_decode (msg, NULL, NULL) == 0, "flux_request_decode topic is optional"); errno = 0; ok (flux_request_decode (msg, NULL, &s) == 0 && s == NULL, "flux_request_decode returns s = NULL when expected payload is missing"); flux_msg_destroy(msg); /* with JSON payload */ ok ((msg = flux_request_encode ("foo.bar", json_str)) != NULL, "flux_request_encode works with payload"); s = NULL; ok (flux_request_decode (msg, NULL, &s) == 0 && s != NULL && !strcmp (s, json_str), "flux_request_decode returns encoded payload"); topic = NULL; i = 0; ok (flux_request_unpack (msg, &topic, "{s:i}", "a", &i) == 0 && i == 42 && topic != NULL && !strcmp (topic, "foo.bar"), "flux_request_unpack returns encoded payload"); errno = 0; ok (flux_request_decode (msg, NULL, NULL) == 0, "flux_request_decode works with payload but don't want the payload"); flux_msg_destroy(msg); /* without payload (raw) */ ok ((msg = flux_request_encode_raw ("foo.bar", NULL, 0)) != NULL, "flux_request_encode_raw works with NULL payload"); topic = NULL; ok (flux_request_decode_raw (msg, &topic, &d, &l) == 0 && topic != NULL && !strcmp (topic, "foo.bar"), "flux_request_decode_raw returns encoded topic"); ok (flux_request_decode_raw (msg, NULL, &d, &l) == 0, "flux_request_decode_raw topic is optional"); d = (char *)&d; l = 1; ok (flux_request_decode_raw (msg, NULL, &d, &l) == 0 && l == 0 && d == NULL, "flux_request_decode_raw returned NULL payload"); flux_msg_destroy(msg); /* with raw payload */ ok ((msg = flux_request_encode_raw ("foo.bar", data, len)) != NULL, "flux_request_encode_raw works with payload"); d = NULL; l = 0; ok (flux_request_decode_raw (msg, NULL, &d, &l) == 0 && d != NULL && l == len && memcmp (d, data, len) == 0, "flux_request_decode_raw returns encoded payload"); flux_msg_destroy(msg); done_testing(); return (0); }