Skip to content

Commit a41603e

Browse files
Send server error codes over event stream
This commit however is not complete on it's own. Even though the server is sending the error codes, the client does not yet understand them. There will be a fast follow up PR for updating the client. There are a couple of TODOs added to the code which will be removed once the client starts to process the incoming error codes sent by the IPC server.
1 parent cde4d31 commit a41603e

18 files changed

+347
-82
lines changed

Diff for: bins/ggipcd/src/ipc_dispatch.c

+6-2
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,11 @@ static const size_t SERVICE_COUNT
2323
= sizeof(SERVICE_TABLE) / sizeof(SERVICE_TABLE[0]);
2424

2525
GglError ggl_ipc_handle_operation(
26-
GglBuffer operation, GglMap args, uint32_t handle, int32_t stream_id
26+
GglBuffer operation,
27+
GglMap args,
28+
uint32_t handle,
29+
int32_t stream_id,
30+
GglIpcError *ipc_error
2731
) {
2832
for (size_t i = 0; i < SERVICE_COUNT; i++) {
2933
const GglIpcService *service = SERVICE_TABLE[i];
@@ -71,7 +75,7 @@ GglError ggl_ipc_handle_operation(
7175
GglBumpAlloc balloc = ggl_bump_alloc_init(GGL_BUF(resp_mem));
7276

7377
return service_op->handler(
74-
&info, args, handle, stream_id, &balloc.alloc
78+
&info, args, handle, stream_id, ipc_error, &balloc.alloc
7579
);
7680
}
7781
}

Diff for: bins/ggipcd/src/ipc_dispatch.h

+6-1
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,18 @@
55
#ifndef GGL_IPC_DISPATCH_H
66
#define GGL_IPC_DISPATCH_H
77

8+
#include "ipc_server.h"
89
#include <ggl/buffer.h>
910
#include <ggl/error.h>
1011
#include <ggl/object.h>
1112
#include <stdint.h>
1213

1314
GglError ggl_ipc_handle_operation(
14-
GglBuffer operation, GglMap args, uint32_t handle, int32_t stream_id
15+
GglBuffer operation,
16+
GglMap args,
17+
uint32_t handle,
18+
int32_t stream_id,
19+
GglIpcError *ipc_error
1520
);
1621

1722
#endif

Diff for: bins/ggipcd/src/ipc_server.c

+89-9
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,67 @@ static GglError release_client_subscriptions(uint32_t handle, size_t index) {
7171
return ggl_ipc_release_subscriptions_for_conn(handle);
7272
}
7373

74+
static void get_ipc_err_info(
75+
GglIpcErrorCode error_code,
76+
GglBuffer *err_str,
77+
GglBuffer *service_model_type
78+
) {
79+
switch (error_code) {
80+
case GGL_IPC_ERR_SERVICE_ERROR:
81+
*err_str = GGL_STR("ServiceError");
82+
*service_model_type = GGL_STR("aws.greengrass#ServiceError");
83+
return;
84+
85+
case GGL_IPC_ERR_RESOURCE_NOT_FOUND:
86+
*err_str = GGL_STR("ResourceNotFoundError");
87+
*service_model_type = GGL_STR("aws.greengrass#ResourceNotFoundError");
88+
return;
89+
90+
case GGL_IPC_ERR_INVALID_ARGUMENTS:
91+
*err_str = GGL_STR("InvalidArgumentsError");
92+
*service_model_type = GGL_STR("aws.greengrass#InvalidArgumentsError");
93+
return;
94+
95+
case GGL_IPC_ERR_COMPONENT_NOT_FOUND:
96+
*err_str = GGL_STR("ComponentNotFoundError");
97+
*service_model_type = GGL_STR("aws.greengrass#ComponentNotFoundError");
98+
return;
99+
100+
case GGL_IPC_ERR_UNAUTHORIZED_ERROR:
101+
*err_str = GGL_STR("UnauthorizedError");
102+
*service_model_type = GGL_STR("aws.greengrass#UnauthorizedError");
103+
return;
104+
105+
case GGL_IPC_ERR_CONFLICT_ERROR:
106+
*err_str = GGL_STR("ConflictError");
107+
*service_model_type = GGL_STR("aws.greengrass#ConflictError");
108+
return;
109+
110+
case GGL_IPC_ERR_FAILED_UPDATE_CONDITION_CHECK_ERROR:
111+
*err_str = GGL_STR("FailedUpdateConditionCheckError");
112+
*service_model_type
113+
= GGL_STR("aws.greengrass#FailedUpdateConditionCheckError");
114+
return;
115+
116+
case GGL_IPC_ERR_INVALID_TOKEN_ERROR:
117+
*err_str = GGL_STR("InvalidTokenError");
118+
*service_model_type = GGL_STR("aws.greengrass#InvalidTokenError");
119+
return;
120+
121+
case GGL_IPC_ERR_INVALID_RECIPE_DIRECTORY_PATH_ERROR:
122+
*err_str = GGL_STR("InvalidRecipeDirectoryPathError");
123+
*service_model_type
124+
= GGL_STR("aws.greengrass#InvalidRecipeDirectoryPathError");
125+
return;
126+
127+
case GGL_IPC_ERR_INVALID_ARTIFACTS_DIRECTORY_PATH_ERROR:
128+
*err_str = GGL_STR("InvalidArtifactsDirectoryPathError");
129+
*service_model_type
130+
= GGL_STR("aws.greengrass#InvalidArtifactsDirectoryPathError");
131+
return;
132+
}
133+
}
134+
74135
static GglError deserialize_payload(GglBuffer payload, GglMap *out) {
75136
GglObject obj;
76137

@@ -253,26 +314,41 @@ static GglError handle_conn_init(
253314
);
254315
}
255316

256-
static GglError send_stream_error(uint32_t handle, int32_t stream_id) {
317+
static GglError send_stream_error(
318+
uint32_t handle, int32_t stream_id, GglIpcError ipc_error
319+
) {
257320
GGL_LOGE("Sending error on client %u stream %d.", handle, stream_id);
258321

259322
GGL_MTX_SCOPE_GUARD(&resp_array_mtx);
260323
GglBuffer resp_buffer = GGL_BUF(resp_array);
261324

325+
GglBuffer service_model_type;
326+
GglBuffer error_code;
327+
328+
get_ipc_err_info(ipc_error.error_code, &error_code, &service_model_type);
329+
262330
// TODO: Match classic error response
263331
EventStreamHeader resp_headers[] = {
264332
{ GGL_STR(":message-type"),
265333
{ EVENTSTREAM_INT32, .int32 = EVENTSTREAM_APPLICATION_ERROR } },
266334
{ GGL_STR(":message-flags"),
267335
{ EVENTSTREAM_INT32, .int32 = EVENTSTREAM_TERMINATE_STREAM } },
268336
{ GGL_STR(":stream-id"), { EVENTSTREAM_INT32, .int32 = stream_id } },
269-
337+
{ GGL_STR(":content-json"),
338+
{ EVENTSTREAM_STRING, .string = GGL_STR("application/json") } },
339+
{ GGL_STR("service-model-type"),
340+
{ EVENTSTREAM_STRING, .string = service_model_type } },
270341
};
271-
const size_t RESP_HEADERS_LEN
272-
= sizeof(resp_headers) / sizeof(resp_headers[0]);
342+
size_t resp_headers_len = sizeof(resp_headers) / sizeof(resp_headers[0]);
273343

274344
GglError ret = eventstream_encode(
275-
&resp_buffer, resp_headers, RESP_HEADERS_LEN, GGL_NULL_READER
345+
&resp_buffer,
346+
resp_headers,
347+
resp_headers_len,
348+
ggl_json_reader(&GGL_OBJ_MAP(GGL_MAP(
349+
{ GGL_STR("_message"), GGL_OBJ_BUF(ipc_error.message) },
350+
{ GGL_STR("_errorCode"), GGL_OBJ_BUF(error_code) }
351+
)))
276352
);
277353
if (ret != GGL_ERR_OK) {
278354
return ret;
@@ -284,7 +360,8 @@ static GglError send_stream_error(uint32_t handle, int32_t stream_id) {
284360
static GglError handle_stream_operation(
285361
uint32_t handle,
286362
EventStreamMessage *msg,
287-
EventStreamCommonHeaders common_headers
363+
EventStreamCommonHeaders common_headers,
364+
GglIpcError *ipc_error
288365
) {
289366
if (common_headers.message_type != EVENTSTREAM_APPLICATION_MESSAGE) {
290367
GGL_LOGE("Client sent unhandled message type.");
@@ -326,7 +403,7 @@ static GglError handle_stream_operation(
326403
}
327404

328405
return ggl_ipc_handle_operation(
329-
operation, payload_data, handle, common_headers.stream_id
406+
operation, payload_data, handle, common_headers.stream_id, ipc_error
330407
);
331408
}
332409

@@ -340,13 +417,16 @@ static GglError handle_operation(
340417
return GGL_ERR_INVALID;
341418
}
342419

343-
GglError ret = handle_stream_operation(handle, msg, common_headers);
420+
GglIpcError ipc_error = { 0 };
421+
422+
GglError ret
423+
= handle_stream_operation(handle, msg, common_headers, &ipc_error);
344424
if (ret == GGL_ERR_FATAL) {
345425
return GGL_ERR_FAILURE;
346426
}
347427

348428
if (ret != GGL_ERR_OK) {
349-
return send_stream_error(handle, common_headers.stream_id);
429+
return send_stream_error(handle, common_headers.stream_id, ipc_error);
350430
}
351431

352432
return GGL_ERR_OK;

Diff for: bins/ggipcd/src/ipc_server.h

+18
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,24 @@
1818

1919
#define GGL_IPC_PAYLOAD_MAX_SUBOBJECTS 50
2020

21+
typedef enum {
22+
GGL_IPC_ERR_SERVICE_ERROR = 0,
23+
GGL_IPC_ERR_RESOURCE_NOT_FOUND,
24+
GGL_IPC_ERR_COMPONENT_NOT_FOUND,
25+
GGL_IPC_ERR_INVALID_ARGUMENTS,
26+
GGL_IPC_ERR_UNAUTHORIZED_ERROR,
27+
GGL_IPC_ERR_CONFLICT_ERROR,
28+
GGL_IPC_ERR_FAILED_UPDATE_CONDITION_CHECK_ERROR,
29+
GGL_IPC_ERR_INVALID_TOKEN_ERROR,
30+
GGL_IPC_ERR_INVALID_RECIPE_DIRECTORY_PATH_ERROR,
31+
GGL_IPC_ERR_INVALID_ARTIFACTS_DIRECTORY_PATH_ERROR
32+
} GglIpcErrorCode;
33+
34+
typedef struct {
35+
GglIpcErrorCode error_code;
36+
GglBuffer message;
37+
} GglIpcError;
38+
2139
/// Start the GG-IPC server on a given socket
2240
GglError ggl_ipc_listen(const char *socket_name, const char *socket_path);
2341

Diff for: bins/ggipcd/src/ipc_service.h

+2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#ifndef GGL_IPC_SERVICE_H
66
#define GGL_IPC_SERVICE_H
77

8+
#include "ipc_server.h"
89
#include <ggl/alloc.h>
910
#include <ggl/buffer.h>
1011
#include <ggl/error.h>
@@ -22,6 +23,7 @@ typedef GglError GglIpcOperationHandler(
2223
GglMap args,
2324
uint32_t handle,
2425
int32_t stream_id,
26+
GglIpcError *ipc_error,
2527
GglAlloc *alloc
2628
);
2729

Diff for: bins/ggipcd/src/services/authorizationagent/token_validator.c

+29-10
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ GglError ggl_handle_token_validation(
2020
GglMap args,
2121
uint32_t handle,
2222
int32_t stream_id,
23+
GglIpcError *ipc_error,
2324
GglAlloc *alloc
2425
) {
2526
(void) alloc;
@@ -28,33 +29,51 @@ GglError ggl_handle_token_validation(
2829
)) {
2930
GGL_LOGE(
3031
"Component %.*s does not have access to token verification IPC "
31-
"command",
32+
"command.",
3233
(int) info->component.len,
3334
info->component.data
3435
);
36+
37+
*ipc_error = (GglIpcError
38+
) { .error_code = GGL_IPC_ERR_UNAUTHORIZED_ERROR,
39+
.message = GGL_STR(
40+
"Component does not have access to token verification IPC "
41+
"command."
42+
) };
43+
44+
return GGL_ERR_FAILURE;
3545
}
46+
3647
GglObject *svcuid_obj;
3748
GglError ret = ggl_map_validate(
3849
args,
3950
GGL_MAP_SCHEMA({ GGL_STR("token"), true, GGL_TYPE_BUF, &svcuid_obj }, )
4051
);
4152
if (ret != GGL_ERR_OK) {
42-
GGL_LOGE("Received invalid paramters.");
53+
GGL_LOGE("Received invalid parameters.");
54+
*ipc_error = (GglIpcError
55+
) { .error_code = GGL_IPC_ERR_SERVICE_ERROR,
56+
.message = GGL_STR("Received invalid parameters.") };
4357
return GGL_ERR_INVALID;
4458
}
4559

46-
if (ipc_svcuid_exists(svcuid_obj->buf) == GGL_ERR_OK) {
47-
return ggl_ipc_response_send(
48-
handle,
49-
stream_id,
50-
GGL_STR("aws.greengrass#ValidateAuthorizationTokenResponse"),
51-
GGL_OBJ_MAP(GGL_MAP({ GGL_STR("isValid"), GGL_OBJ_BOOL(true) }))
52-
);
60+
if (ipc_svcuid_exists(svcuid_obj->buf) != GGL_ERR_OK) {
61+
*ipc_error = (GglIpcError
62+
) { .error_code = GGL_IPC_ERR_INVALID_TOKEN_ERROR,
63+
.message = GGL_STR(
64+
"Invalid token used by stream manager when trying to authorize."
65+
) };
66+
67+
// GreenGrass Java returns an error to the caller instead of setting the
68+
// value to 'false'.
69+
// https://github.com/aws-greengrass/aws-greengrass-nucleus/blob/b003cf0db575f546456bef69530126cf3e0b6a68/src/main/java/com/aws/greengrass/authorization/AuthorizationIPCAgent.java#L83
70+
return GGL_ERR_FAILURE;
5371
}
72+
5473
return ggl_ipc_response_send(
5574
handle,
5675
stream_id,
5776
GGL_STR("aws.greengrass#ValidateAuthorizationTokenResponse"),
58-
GGL_OBJ_MAP(GGL_MAP({ GGL_STR("isValid"), GGL_OBJ_BOOL(false) }))
77+
GGL_OBJ_MAP(GGL_MAP({ GGL_STR("isValid"), GGL_OBJ_BOOL(true) }))
5978
);
6079
}

Diff for: bins/ggipcd/src/services/cli/create_local_deployment.c

+10-1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ GglError ggl_handle_create_local_deployment(
2121
GglMap args,
2222
uint32_t handle,
2323
int32_t stream_id,
24+
GglIpcError *ipc_error,
2425
GglAlloc *alloc
2526
) {
2627
GGL_MAP_FOREACH(pair, args) {
@@ -53,6 +54,9 @@ GglError ggl_handle_create_local_deployment(
5354
= ggl_ipc_auth(info, GGL_STR(""), ggl_ipc_default_policy_matcher);
5455
if (ret != GGL_ERR_OK) {
5556
GGL_LOGE("IPC Operation not authorized.");
57+
*ipc_error = (GglIpcError
58+
) { .error_code = GGL_IPC_ERR_SERVICE_ERROR,
59+
.message = GGL_STR("IPC Operation not authorized.") };
5660
return GGL_ERR_INVALID;
5761
}
5862

@@ -68,11 +72,16 @@ GglError ggl_handle_create_local_deployment(
6872

6973
if (ret != GGL_ERR_OK) {
7074
GGL_LOGE("Failed to create local deployment.");
75+
*ipc_error = (GglIpcError
76+
) { .error_code = GGL_IPC_ERR_SERVICE_ERROR,
77+
.message = GGL_STR("Failed to create local deployment.") };
7178
return ret;
7279
}
7380

7481
if (result.type != GGL_TYPE_BUF) {
75-
GGL_LOGE("Response not a string.");
82+
GGL_LOGE("Received deployment ID not a string.");
83+
*ipc_error = (GglIpcError) { .error_code = GGL_IPC_ERR_SERVICE_ERROR,
84+
.message = GGL_STR("Internal error.") };
7685
return GGL_ERR_FAILURE;
7786
}
7887

0 commit comments

Comments
 (0)