GCC Code Coverage Report


Directory: src/gate/
File: src/gate/tech/microservices/procrunner_service.c
Date: 2026-02-03 22:06:38
Exec Total Coverage
Lines: 72 81 88.9%
Functions: 6 8 75.0%
Branches: 9 16 56.2%

Line Branch Exec Source
1 /* GATE PROJECT LICENSE:
2 +----------------------------------------------------------------------------+
3 | Copyright(c) 2018-2026, Stefan Meislinger |
4 | All rights reserved. |
5 | |
6 | Redistribution and use in source and binary forms, with or without |
7 | modification, are permitted provided that the following conditions are met:|
8 | |
9 | 1. Redistributions of source code must retain the above copyright notice, |
10 | this list of conditions and the following disclaimer. |
11 | 2. Redistributions in binary form must reproduce the above copyright |
12 | notice, this list of conditions and the following disclaimer in the |
13 | documentation and/or other materials provided with the distribution. |
14 | |
15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"|
16 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
17 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
18 | ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
19 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
20 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
21 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
22 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
23 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
24 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
25 | THE POSSIBILITY OF SUCH DAMAGE. |
26 +----------------------------------------------------------------------------+
27 */
28 #include "gate/tech/microservices/procrunner_service.h"
29 #include "gate/processes.h"
30 #include "gate/applications.h"
31 #include "gate/results.h"
32
33 typedef struct procrunner_config_class
34 {
35 gate_struct_t struct_base;
36
37 gate_bool_t autostart; /* start executable on service startup */
38 gate_string_t start_on_msg_id; /* start executable when a specific message is received */
39 gate_bool_t append_msg_to_arguments; /* append received message content to process arguments */
40
41 gate_string_t executable; /* path to process executable */
42 gate_string_t arguments; /* process arguments */
43 gate_string_t working_directory; /* process working directory */
44 gate_string_t location; /* system location (e.g. session) where process is started */
45 gate_uint32_t flags; /* process creation flags */
46
47 } procrunner_config_t;
48
49
50 #define PROCRUNNER_ROOT_NAME "procrunner_service"
51
52 #define PROCRUNNER_CONFIG_NAME GATE_STRUCT_ROOT_NAME GATE_STRUCT_SEPARATOR PROCRUNNER_ROOT_NAME GATE_STRUCT_SEPARATOR "config"
53
54 static gate_struct_item_t const procrunner_config_members[] =
55 {
56 GATE_STRUCT_ITEM(procrunner_config_t, GATE_TYPE_BOOL, autostart),
57 GATE_STRUCT_ITEM(procrunner_config_t, GATE_TYPE_STRING, start_on_msg_id),
58 GATE_STRUCT_ITEM(procrunner_config_t, GATE_TYPE_BOOL, append_msg_to_arguments),
59
60 GATE_STRUCT_ITEM(procrunner_config_t, GATE_TYPE_STRING, executable),
61 GATE_STRUCT_ITEM(procrunner_config_t, GATE_TYPE_STRING, arguments),
62 GATE_STRUCT_ITEM(procrunner_config_t, GATE_TYPE_STRING, working_directory),
63 GATE_STRUCT_ITEM(procrunner_config_t, GATE_TYPE_STRING, location),
64 GATE_STRUCT_ITEM(procrunner_config_t, GATE_TYPE_UI32, flags)
65 };
66
67 static gate_struct_descriptor_t const procrunner_config_descriptor =
68 {
69 PROCRUNNER_CONFIG_NAME,
70 procrunner_config_members,
71 sizeof(procrunner_config_members) / sizeof(procrunner_config_members[0]),
72 sizeof(procrunner_config_t)
73 };
74
75
76 typedef struct gate_procrunner_service_data_class
77 {
78 procrunner_config_t config;
79 } gate_procrunner_service_data_t;
80
81
82 1 static void procrunner_on_release(gate_microservice_base_t* self)
83 {
84 1 gate_procrunner_service_data_t* data = (gate_procrunner_service_data_t*)self->data_ptr;
85 1 gate_struct_release(&data->config.struct_base);
86 1 }
87
88 1 static void procrunner_execute_process(gate_microservice_base_t* self, gate_string_t const* arg_update)
89 {
90 char buffer[4096];
91 1 gate_strbuilder_t arg_builder = GATE_INIT_EMPTY;
92 1 gate_strbuilder_t log_builder = GATE_INIT_EMPTY;
93 1 gate_string_t args = GATE_STRING_INIT_EMPTY;
94 1 gate_string_t logmsg = GATE_STRING_INIT_EMPTY;
95 1 gate_procrunner_service_data_t* data = (gate_procrunner_service_data_t*)self->data_ptr;
96 gate_string_t arg_items[256];
97 1 gate_size_t arg_count = 0;
98 gate_result_t res;
99 1 gate_uint32_t flags = 0;
100 gate_size_t index;
101
102 do
103 {
104 1 gate_mem_clear(&arg_items[0], sizeof(arg_items));
105 1 gate_strbuilder_create_static(&arg_builder, buffer, sizeof(buffer), 0);
106
107
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 if (!gate_string_is_empty(&data->config.arguments))
108 {
109 1 gate_strbuilder_append_string(&arg_builder, &data->config.arguments);
110 }
111
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if (!gate_string_is_empty(arg_update))
112 {
113 gate_strbuilder_append_string(&arg_builder, arg_update);
114 }
115 1 gate_strbuilder_to_string(&arg_builder, &args);
116
117 1 arg_count = gate_app_parse_args(&args, arg_items, sizeof(arg_items) / sizeof(arg_items[0]));
118
119 1 flags = data->config.flags;
120 1 flags |= GATE_PROCESS_START_NEWSESSION;
121 1 flags |= GATE_PROCESS_START_NOINHERIT;
122 1 flags |= GATE_PROCESS_START_PRIVILEGED;
123
124 2 res = gate_process_start(&data->config.executable, &arg_items[0], arg_count,
125 1 &data->config.working_directory, NULL, 0, flags,
126 NULL, NULL, NULL);
127
128
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (index = 0; index != arg_count; ++index)
129 {
130 2 gate_string_release(&arg_items[index]);
131 }
132
133 1 gate_string_release(&args);
134 1 gate_strbuilder_release(&arg_builder);
135
136 1 gate_strbuilder_create_static(&log_builder, buffer, sizeof(buffer), 0);
137
138
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (GATE_SUCCEEDED(res))
139 {
140 gate_strbuilder_append(&log_builder,
141 GATE_PRINT_CSTR, "Process started: ",
142 GATE_PRINT_STRING, &data->config.executable,
143 GATE_PRINT_END);
144 gate_strbuilder_to_string(&log_builder, &logmsg);
145
146 gate_microhost_log(self->host, GATE_MICROSERVICE_LOGTYPE_STATUS, 0, 0,
147 &self->address, &logmsg);
148 }
149 else
150 {
151 1 gate_strbuilder_append(&log_builder,
152 GATE_PRINT_CSTR, "Process start failed: ",
153 GATE_PRINT_STRING, &data->config.executable,
154 GATE_PRINT_END);
155 1 gate_strbuilder_to_string(&log_builder, &logmsg);
156
157 1 gate_microhost_log(self->host, GATE_MICROSERVICE_LOGTYPE_ERROR, res, 0,
158 &self->address, &logmsg);
159 }
160
161 } while (0);
162
163 1 gate_string_release(&logmsg);
164 1 gate_string_release(&args);
165 1 gate_strbuilder_release(&log_builder);
166 1 gate_strbuilder_release(&arg_builder);
167
168 1 }
169
170 1 static gate_result_t procrunner_on_start(gate_microservice_base_t* self)
171 {
172 1 gate_result_t ret = GATE_RESULT_OK;
173 1 gate_procrunner_service_data_t* data = (gate_procrunner_service_data_t*)self->data_ptr;
174
175 /* export parameters from property storage to native config struct */
176 1 gate_property_export(&self->parameters, GATE_TYPE_STRUCT, &data->config.struct_base);
177
178
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (data->config.autostart)
179 {
180 procrunner_execute_process(self, NULL);
181 }
182
183 1 return ret;
184 }
185 1 static gate_result_t procrunner_on_stop(gate_microservice_base_t* self)
186 {
187 1 gate_result_t ret = GATE_RESULT_OK;
188 1 gate_procrunner_service_data_t* data = (gate_procrunner_service_data_t*)self->data_ptr;
189
190 1 gate_struct_release(&data->config.struct_base);
191
192 1 return ret;
193 }
194 1 static gate_result_t procrunner_on_message_received(gate_microservice_base_t* self,
195 gate_string_t const* source, gate_string_t const* destination,
196 gate_string_t const* msg_id, gate_string_t const* message)
197 {
198 1 gate_result_t ret = GATE_RESULT_OK;
199 1 gate_procrunner_service_data_t* data = (gate_procrunner_service_data_t*)self->data_ptr;
200
201 GATE_UNUSED_ARG(source);
202 GATE_UNUSED_ARG(destination);
203
204
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 if (!gate_string_is_empty(&data->config.start_on_msg_id))
205 {
206
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 if (gate_string_equals(msg_id, &data->config.start_on_msg_id))
207 {
208 1 procrunner_execute_process(self, message);
209 }
210 }
211
212 1 return ret;
213 }
214 static gate_result_t procrunner_on_object_received(gate_microservice_base_t* self,
215 gate_string_t const* source, gate_string_t const* destination,
216 gate_string_t const* obj_id, gate_object_t* obj)
217 {
218 GATE_UNUSED_ARG(self);
219 GATE_UNUSED_ARG(source);
220 GATE_UNUSED_ARG(destination);
221 GATE_UNUSED_ARG(obj_id);
222 GATE_UNUSED_ARG(obj);
223 return GATE_RESULT_NOTSUPPORTED;
224 }
225 static gate_result_t procrunner_on_invoke(gate_microservice_base_t* self, gate_string_t const* method,
226 gate_struct_t const* request, gate_struct_t* response)
227 {
228 GATE_UNUSED_ARG(self);
229 GATE_UNUSED_ARG(method);
230 GATE_UNUSED_ARG(request);
231 GATE_UNUSED_ARG(response);
232 return GATE_RESULT_NOTSUPPORTED;
233 }
234
235
236 1 gate_microservice_t* gate_microservice_procrunner_create(void)
237 {
238 1 gate_microservice_base_t* procrunner_service = gate_microservice_base_create(sizeof(gate_procrunner_service_data_t), NULL);
239 gate_procrunner_service_data_t* procrunner_data;
240
241
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (procrunner_service)
242 {
243 1 procrunner_service->on_start = &procrunner_on_start;
244 1 procrunner_service->on_stop = &procrunner_on_stop;
245 1 procrunner_service->on_release = &procrunner_on_release;
246 1 procrunner_service->on_message_received = &procrunner_on_message_received;
247 1 procrunner_service->on_object_received = &procrunner_on_object_received;
248 1 procrunner_service->on_invoke = procrunner_on_invoke;
249
250 1 procrunner_data = (gate_procrunner_service_data_t*)procrunner_service->data_ptr;
251 1 gate_struct_init(&procrunner_data->config.struct_base, &procrunner_config_descriptor);
252 1 gate_property_create_object(&procrunner_service->parameters);
253 1 gate_property_import(&procrunner_service->parameters, GATE_TYPE_STRUCT, &procrunner_data->config.struct_base);
254 1 procrunner_service->ptr_parameters = &procrunner_data->config.struct_base;
255
256 }
257 1 return (gate_microservice_t*)procrunner_service;
258 }
259
260