Always return a claim code after uploads
This commit is contained in:
@@ -83,12 +83,10 @@ By default, fossbench samples system activity for ten seconds before a run. It
|
|||||||
reports background CPU use, available memory, process count, and the OS kernel
|
reports background CPU use, available memory, process count, and the OS kernel
|
||||||
or build. It does not collect process names or command lines.
|
or build. It does not collect process names or command lines.
|
||||||
|
|
||||||
Uploads are optional. They are anonymous without an API token. To attach a
|
Uploads are optional and anonymous. Every successful upload prints a claim
|
||||||
result to a fossbench.net account, create a benchmark client token and export
|
code and link that can be used to attach the result to a fossbench.net account:
|
||||||
it:
|
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
export FOSSBENCH_TOKEN=fb_your_token_here
|
|
||||||
./dist/fossbench-linux-amd64 --upload
|
./dist/fossbench-linux-amd64 --upload
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
+2
-10
@@ -836,13 +836,8 @@ int fossbench_run(int verbose, int upload_mode, int system_check)
|
|||||||
teardown();
|
teardown();
|
||||||
|
|
||||||
{
|
{
|
||||||
/* Read the token from the environment. */
|
|
||||||
const char *token = getenv("FOSSBENCH_TOKEN");
|
|
||||||
int do_upload;
|
int do_upload;
|
||||||
|
|
||||||
if (token && token[0] == '\0')
|
|
||||||
token = NULL;
|
|
||||||
|
|
||||||
if (upload_mode == 1) {
|
if (upload_mode == 1) {
|
||||||
do_upload = 1;
|
do_upload = 1;
|
||||||
} else if (upload_mode == 2) {
|
} else if (upload_mode == 2) {
|
||||||
@@ -850,10 +845,7 @@ int fossbench_run(int verbose, int upload_mode, int system_check)
|
|||||||
printf(" Result was not uploaded.\n");
|
printf(" Result was not uploaded.\n");
|
||||||
} else {
|
} else {
|
||||||
char answer[16];
|
char answer[16];
|
||||||
if (token)
|
printf(" Upload this result to %s? [y/N] ", FB_API_BASE_URL);
|
||||||
printf(" Upload this result to %s using your API token? [y/N] ", FB_API_BASE_URL);
|
|
||||||
else
|
|
||||||
printf(" Upload this result to %s? [y/N] ", FB_API_BASE_URL);
|
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
do_upload = fgets(answer, sizeof(answer), stdin) &&
|
do_upload = fgets(answer, sizeof(answer), stdin) &&
|
||||||
(answer[0] == 'y' || answer[0] == 'Y');
|
(answer[0] == 'y' || answer[0] == 'Y');
|
||||||
@@ -866,7 +858,7 @@ int fossbench_run(int verbose, int upload_mode, int system_check)
|
|||||||
fprintf(stderr, " Upload support is disabled in this build.\n");
|
fprintf(stderr, " Upload support is disabled in this build.\n");
|
||||||
#else
|
#else
|
||||||
upload_results(&system_info, multicore_score, singlecore_score,
|
upload_results(&system_info, multicore_score, singlecore_score,
|
||||||
multi, single, duration_ms, &background, token);
|
multi, single, duration_ms, &background);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+70
-21
@@ -19,6 +19,30 @@ static void json_escape(const char *src, char *dst, size_t cap)
|
|||||||
dst[used] = '\0';
|
dst[used] = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Extract a simple JSON string field from the upload response. */
|
||||||
|
static int json_string_field(const char *json, const char *field, char *dst, size_t cap)
|
||||||
|
{
|
||||||
|
char key[64];
|
||||||
|
const char *p;
|
||||||
|
size_t used = 0;
|
||||||
|
|
||||||
|
if (cap == 0 || snprintf(key, sizeof(key), "\"%s\"", field) < 0)
|
||||||
|
return 0;
|
||||||
|
p = strstr(json, key);
|
||||||
|
if (!p) return 0;
|
||||||
|
p += strlen(key);
|
||||||
|
while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') p++;
|
||||||
|
if (*p++ != ':') return 0;
|
||||||
|
while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') p++;
|
||||||
|
if (*p++ != '"') return 0;
|
||||||
|
while (*p && *p != '"' && used + 1 < cap) {
|
||||||
|
if (*p == '\\' && p[1]) p++;
|
||||||
|
dst[used++] = *p++;
|
||||||
|
}
|
||||||
|
dst[used] = '\0';
|
||||||
|
return *p == '"' && used > 0;
|
||||||
|
}
|
||||||
|
|
||||||
#if !defined(_WIN32)
|
#if !defined(_WIN32)
|
||||||
/* Load the certificates included with the program. */
|
/* Load the certificates included with the program. */
|
||||||
static int load_embedded_ca_bundle(SSL_CTX *ctx)
|
static int load_embedded_ca_bundle(SSL_CTX *ctx)
|
||||||
@@ -63,7 +87,8 @@ static int is_winhttp_secure_error(DWORD err)
|
|||||||
/* Send the request with Windows networking. */
|
/* Send the request with Windows networking. */
|
||||||
static int winhttp_post(const char *host, const char *port, const char *path,
|
static int winhttp_post(const char *host, const char *port, const char *path,
|
||||||
int use_tls, const char *payload, int payload_len,
|
int use_tls, const char *payload, int payload_len,
|
||||||
const char *auth_header, int *out_status)
|
const char *auth_header, int *out_status,
|
||||||
|
char *response, size_t response_cap)
|
||||||
{
|
{
|
||||||
wchar_t whost[256], wpath[512], wheaders[700];
|
wchar_t whost[256], wpath[512], wheaders[700];
|
||||||
char header_buf[700];
|
char header_buf[700];
|
||||||
@@ -119,6 +144,20 @@ static int winhttp_post(const char *host, const char *port, const char *path,
|
|||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
*out_status = (int)status;
|
*out_status = (int)status;
|
||||||
|
if (response_cap > 0) {
|
||||||
|
size_t used = 0;
|
||||||
|
while (used + 1 < response_cap) {
|
||||||
|
DWORD available = 0, got = 0;
|
||||||
|
DWORD room = (DWORD)(response_cap - used - 1);
|
||||||
|
if (!WinHttpQueryDataAvailable(hrequest, &available) || available == 0)
|
||||||
|
break;
|
||||||
|
if (available > room) available = room;
|
||||||
|
if (!WinHttpReadData(hrequest, response + used, available, &got) || got == 0)
|
||||||
|
break;
|
||||||
|
used += got;
|
||||||
|
}
|
||||||
|
response[used] = '\0';
|
||||||
|
}
|
||||||
ok = 1;
|
ok = 1;
|
||||||
done:
|
done:
|
||||||
if (hrequest) WinHttpCloseHandle(hrequest);
|
if (hrequest) WinHttpCloseHandle(hrequest);
|
||||||
@@ -131,15 +170,15 @@ done:
|
|||||||
static int upload_results(const struct system_info *info, double score,
|
static int upload_results(const struct system_info *info, double score,
|
||||||
double singlecore_score, const struct result *multi,
|
double singlecore_score, const struct result *multi,
|
||||||
const struct result *single, uint64_t duration_ms,
|
const struct result *single, uint64_t duration_ms,
|
||||||
const struct background_metrics *background, const char *token)
|
const struct background_metrics *background)
|
||||||
{
|
{
|
||||||
char host[256], port[16], path[512], payload[16384];
|
char host[256], port[16], path[512], payload[16384];
|
||||||
char auth_header[600];
|
char auth_header[600], response_body[2048], claim_url[1024];
|
||||||
char cpu[512], model[512], os[512], compiler[256], kernel[256];
|
char cpu[512], model[512], os[512], compiler[256], kernel[256];
|
||||||
const char *base = FB_API_BASE_URL, *p, *slash, *colon;
|
const char *base = FB_API_BASE_URL, *p, *slash, *colon;
|
||||||
int use_tls, status = 0, payload_len;
|
int use_tls, status = 0, payload_len;
|
||||||
#if !defined(_WIN32)
|
#if !defined(_WIN32)
|
||||||
char request[20000], response[512];
|
char request[20000], response[4096];
|
||||||
struct addrinfo hints, *addresses = NULL, *a;
|
struct addrinfo hints, *addresses = NULL, *a;
|
||||||
SSL_CTX *tls_ctx = NULL;
|
SSL_CTX *tls_ctx = NULL;
|
||||||
SSL *tls = NULL;
|
SSL *tls = NULL;
|
||||||
@@ -222,15 +261,9 @@ static int upload_results(const struct system_info *info, double score,
|
|||||||
payload_len = (int)(used + 3);
|
payload_len = (int)(used + 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Every upload is anonymous and claim-based. */
|
||||||
auth_header[0] = '\0';
|
auth_header[0] = '\0';
|
||||||
if (token && token[0]) {
|
response_body[0] = '\0';
|
||||||
int n = snprintf(auth_header, sizeof(auth_header),
|
|
||||||
"Authorization: Bearer %s\r\n", token);
|
|
||||||
if (n < 0 || (size_t)n >= sizeof(auth_header)) {
|
|
||||||
fprintf(stderr, " upload error: API token too long\n");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#if !defined(_WIN32)
|
#if !defined(_WIN32)
|
||||||
request_len = snprintf(request, sizeof(request),
|
request_len = snprintf(request, sizeof(request),
|
||||||
"POST %s HTTP/1.1\r\nHost: %s:%s\r\nContent-Type: application/json\r\n"
|
"POST %s HTTP/1.1\r\nHost: %s:%s\r\nContent-Type: application/json\r\n"
|
||||||
@@ -278,17 +311,27 @@ static int upload_results(const struct system_info *info, double score,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
int n = use_tls ? SSL_read(tls, response, sizeof(response) - 1) :
|
size_t used = 0;
|
||||||
(int)recv(fd, response, sizeof(response) - 1, 0);
|
int n;
|
||||||
if (n <= 0) { fprintf(stderr, " upload error: no server response\n"); goto upload_failed; }
|
do {
|
||||||
response[n] = '\0';
|
n = use_tls ? SSL_read(tls, response + used, (int)(sizeof(response) - used - 1)) :
|
||||||
|
(int)recv(fd, response + used, sizeof(response) - used - 1, 0);
|
||||||
|
if (n > 0) used += (size_t)n;
|
||||||
|
} while (n > 0 && used + 1 < sizeof(response));
|
||||||
|
if (used == 0) { fprintf(stderr, " upload error: no server response\n"); goto upload_failed; }
|
||||||
|
response[used] = '\0';
|
||||||
if (sscanf(response, "HTTP/%*s %d", &status) != 1) status = 0;
|
if (sscanf(response, "HTTP/%*s %d", &status) != 1) status = 0;
|
||||||
|
{
|
||||||
|
char *body = strstr(response, "\r\n\r\n");
|
||||||
|
if (body) snprintf(response_body, sizeof(response_body), "%s", body + 4);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (tls) { SSL_shutdown(tls); SSL_free(tls); }
|
if (tls) { SSL_shutdown(tls); SSL_free(tls); }
|
||||||
if (tls_ctx) SSL_CTX_free(tls_ctx);
|
if (tls_ctx) SSL_CTX_free(tls_ctx);
|
||||||
close(fd);
|
close(fd);
|
||||||
#else
|
#else
|
||||||
if (!winhttp_post(host, port, path, use_tls, payload, payload_len, auth_header, &status))
|
if (!winhttp_post(host, port, path, use_tls, payload, payload_len, auth_header,
|
||||||
|
&status, response_body, sizeof(response_body)))
|
||||||
return 0;
|
return 0;
|
||||||
#endif
|
#endif
|
||||||
if (status == 401) {
|
if (status == 401) {
|
||||||
@@ -300,10 +343,16 @@ static int upload_results(const struct system_info *info, double score,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (status < 200 || status >= 300) { fprintf(stderr, " upload failed: server returned HTTP %d\n", status); return 0; }
|
if (status < 200 || status >= 300) { fprintf(stderr, " upload failed: server returned HTTP %d\n", status); return 0; }
|
||||||
if (token)
|
if (!json_string_field(response_body, "claim_url", claim_url, sizeof(claim_url))) {
|
||||||
printf(" Results uploaded and published to your profile (HTTP %d).\n", status);
|
fprintf(stderr, " upload failed: server did not return a claim link\n");
|
||||||
else
|
return 0;
|
||||||
printf(" Results uploaded, pending administrator review (HTTP %d).\n", status);
|
}
|
||||||
|
printf(" Results uploaded (HTTP %d).\n", status);
|
||||||
|
{
|
||||||
|
const char *claim_code = strrchr(claim_url, '/');
|
||||||
|
printf(" Claim code: %s\n", claim_code && claim_code[1] ? claim_code + 1 : claim_url);
|
||||||
|
}
|
||||||
|
printf(" Claim your result: %s\n", claim_url);
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
#if !defined(_WIN32)
|
#if !defined(_WIN32)
|
||||||
|
|||||||
Reference in New Issue
Block a user