Пример #1
0
void db_bind_string_len(DB_val *const val, char const *const str, size_t const len, int const nulterm, DB_txn *const txn) {
	assert(val);
	assert(len == strnlen(str, len) && "Embedded nuls");
	unsigned char *const out = val->data;
	if(0 == len) {
		out[val->size++] = '\0';
		out[val->size++] = str ? 0x01 : 0x00;
		return;
	}
	if(len < DB_INLINE_MAX) {
		memcpy(out+val->size, str, len);
		val->size += len;
		out[val->size++] = '\0';
		if(DB_INLINE_TRUNC != len+1) return;
		out[val->size++] = '\0';
		return;
	}

	memcpy(out+val->size, str, DB_INLINE_TRUNC-1);
	val->size += DB_INLINE_TRUNC-1;
	out[val->size++] = '\0';

	SHA256_CTX algo[1];
	int rc;
	rc = SHA256_Init(algo);
	db_assert(rc >= 0);
	rc = SHA256_Update(algo, str, len);
	db_assert(rc >= 0);
	rc = SHA256_Final(out+val->size, algo);
	db_assert(rc >= 0);
	if(0x00 == out[val->size]) out[val->size] = 0x01;
	val->size += SHA256_DIGEST_LENGTH;

	if(!txn) return;
	unsigned flags = 0;
	rc = db_txn_get_flags(txn, &flags);
	db_assertf(rc >= 0, "Database error %s", db_strerror(rc));
	if(flags & DB_RDONLY) return;

	DB_val key = { DB_INLINE_MAX, out+val->size-DB_INLINE_MAX };
	char *str2 = nulterm ? (char *)str : strndup(str, len);
	DB_val full = { len+1, str2 };
	assert('\0' == str2[full.size-1]);
	rc = db_put(txn, &key, &full, 0);
	if(!nulterm) free(str2);
	str2 = NULL;
	db_assertf(rc >= 0, "Database error %s", db_strerror(rc));
}
Пример #2
0
char const *db_read_string(DB_val *const val, DB_txn *const txn) {
	assert(txn);
	assert(val);
	db_assert(val->size >= 1);
	char const *const str = val->data;
	size_t const len = strnlen(str, MIN(val->size, DB_INLINE_MAX));
	db_assert('\0' == str[len]);
	if(0 == len) {
		db_assert(val->size >= 2);
		val->data += 2;
		val->size -= 2;
		if(0x00 == str[1]) return NULL;
		if(0x01 == str[1]) return "";
		db_assertf(0, "Invalid string type %u\n", str[1]);
		return NULL;
	}
	if(DB_INLINE_TRUNC != len+1) {
		val->data += len+1;
		val->size -= len+1;
		return str;
	}
	db_assert(val->size >= len+2);
	if(0x00 == str[len+1]) {
		val->data += len+2;
		val->size -= len+2;
		return str;
	}

	DB_val key = { DB_INLINE_MAX, (char *)str };
	DB_val full[1];
	int rc = db_get(txn, &key, full);
	db_assertf(rc >= 0, "Database error %s", db_strerror(rc));
	char const *const fstr = full->data;
	db_assert('\0' == fstr[full->size-1]);
	return fstr;
}
Пример #3
0
static int import(SLNPullRef const pull, strarg_t const URI, size_t const pos, HTTPConnectionRef *const conn) {
	if(!pull) return 0;

	// TODO: Even if there's nothing to do, we have to enqueue something to fill up our reserved slots. I guess it's better than doing a lot of work inside the connection lock, but there's got to be a better way.
	SLNSubmissionRef sub = NULL;
	HTTPHeadersRef headers = NULL;

	if(!URI) goto enqueue;

	str_t algo[SLN_ALGO_SIZE];
	str_t hash[SLN_HASH_SIZE];
	if(SLNParseURI(URI, algo, hash) < 0) goto enqueue;

	int rc = SLNSessionGetFileInfo(pull->session, URI, NULL);
	if(rc >= 0) goto enqueue;
	db_assertf(DB_NOTFOUND == rc, "Database error: %s", sln_strerror(rc));

	// TODO: We're logging out of order when we do it like this...
//	alogf("Pulling %s\n", URI);

	if(!*conn) {
		rc = HTTPConnectionCreateOutgoing(pull->host, 0, conn);
		if(rc < 0) {
			alogf("Pull import connection error: %s\n", sln_strerror(rc));
			goto fail;
		}
	}

	str_t *path = aasprintf("/sln/file/%s/%s", algo, hash);
	if(!path) {
		alogf("Pull aasprintf error\n");
		goto fail;
	}
	rc = HTTPConnectionWriteRequest(*conn, HTTP_GET, path, pull->host);
	assert(rc >= 0); // TODO
	FREE(&path);

	HTTPConnectionWriteHeader(*conn, "Cookie", pull->cookie);
	HTTPConnectionBeginBody(*conn);
	rc = HTTPConnectionEnd(*conn);
	if(rc < 0) {
		alogf("Pull import request error: %s\n", sln_strerror(rc));
		goto fail;
	}
	int const status = HTTPConnectionReadResponseStatus(*conn);
	if(status < 0) {
		alogf("Pull import response error: %s\n", sln_strerror(status));
		goto fail;
	}
	if(status < 200 || status >= 300) {
		alogf("Pull import status error: %d\n", status);
		goto fail;
	}

	rc = HTTPHeadersCreateFromConnection(*conn, &headers);
	assert(rc >= 0); // TODO
/*	if(rc < 0) {
		alogf("Pull import headers error %s\n", sln_strerror(rc));
		goto fail;
	}*/
	strarg_t const type = HTTPHeadersGet(headers, "content-type");

	rc = SLNSubmissionCreate(pull->session, URI, &sub);
	if(rc < 0) {
		alogf("Pull submission error: %s\n", sln_strerror(rc));
		goto fail;
	}
	rc = SLNSubmissionSetType(sub, type);
	if(rc < 0) {
		alogf("Pull submission type error: %s\n", sln_strerror(rc));
		goto fail;
	}
	for(;;) {
		if(pull->stop) goto fail;
		uv_buf_t buf[1] = {};
		rc = HTTPConnectionReadBody(*conn, buf);
		if(rc < 0) {
			alogf("Pull download error: %s\n", sln_strerror(rc));
			goto fail;
		}
		if(0 == buf->len) break;
		rc = SLNSubmissionWrite(sub, (byte_t *)buf->base, buf->len);
		if(rc < 0) {
			alogf("Pull write error\n");
			goto fail;
		}
	}
	rc = SLNSubmissionEnd(sub);
	if(rc < 0) {
		alogf("Pull submission error: %s\n", sln_strerror(rc));
		goto fail;
	}

enqueue:
	HTTPHeadersFree(&headers);
	async_mutex_lock(pull->mutex);
	pull->queue[pos] = sub; sub = NULL;
	pull->filled[pos] = true;
	async_cond_broadcast(pull->cond);
	async_mutex_unlock(pull->mutex);
	return 0;

fail:
	HTTPHeadersFree(&headers);
	SLNSubmissionFree(&sub);
	HTTPConnectionFree(conn);
	return -1;
}