1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
|
/* See LICENSE file for copyright and license details. */
#include "common.h"
/**
* Check whether the server sent an error, if so copy it to `ctx`
*
* This function will also reports EBADMSG if the message ID
* that the message is a response to does not match the request
* information, or if it is missing
*
* @param ctx The state of the library, must be connected
* @param async Information about the request
* @return 1 if the server sent an error (even indicating success),
* 0 on success, -1 on failure. Information about failure
* is copied `ctx`.
*/
int
libcoopgamma_check_error__(libcoopgamma_context_t *restrict ctx, libcoopgamma_async_context_t *restrict async)
{
char temp[3 * sizeof(uint64_t) + 1];
size_t old_tail = ctx->inbound_tail;
char *line;
char *value;
int command_ok = 0;
int have_in_response_to = 0;
int have_error = 0;
int bad = 0;
char *payload;
size_t n;
for (;;) {
line = libcoopgamma_next_header__(ctx);
value = &strchr(line, ':')[2U];
if (!*line) {
break;
} else if (!strcmp(line, "Command: error")) {
command_ok = 1;
} else if (strstr(line, "In response to: ") == line) {
uint32_t id = (uint32_t)atol(value);
have_in_response_to = 1 + !!have_in_response_to;
if (id != async->message_id) {
bad = 1;
} else {
sprintf(temp, "%" PRIu32, id);
if (strcmp(value, temp))
bad = 1;
}
} else if (strstr(line, "Error: ") == line) {
have_error = 1 + !!have_error;
ctx->error.server_side = 1;
ctx->error.custom = (strstr(value, "custom") == value);
if (ctx->error.custom) {
if (value[6] == '\0') {
ctx->error.number = 0;
continue;
} else if (value[6] != ' ') {
bad = 1;
continue;
}
value += 7;
}
ctx->error.number = (uint64_t)atoll(value);
sprintf(temp, "%" PRIu64, ctx->error.number);
if (strcmp(value, temp))
bad = 1;
}
}
if (!command_ok) {
ctx->inbound_tail = old_tail;
return 0;
}
payload = libcoopgamma_next_payload__(ctx, &n);
if (payload) {
if (memchr(payload, '\0', n) || payload[n - 1U] != '\n')
goto badmsg;
ctx->error.description = malloc(n);
if (ctx->error.description == NULL)
goto fail;
memcpy(ctx->error.description, payload, n - 1U);
ctx->error.description[n - 1U] = '\0';
}
if (bad || have_in_response_to != 1 || have_error != 1)
goto badmsg;
return 1;
badmsg:
errno = EBADMSG;
fail:
copy_errno(ctx);
return -1;
}
|