2 * Copyright (c) 2017 Samsung Electronics Co., Ltd.
4 * Licensed under the Flora License, Version 1.1 (the License);
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://floralicense.org/license/
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an AS IS BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 #include <sys/types.h>
22 #include <gio/gunixsocketaddress.h>
23 #include <app_common.h>
24 #include "log-private.h"
25 #include "things-service.h"
26 #include "common-app-inf.h"
27 #include "common-util.h"
37 GThread *accept_thread;
38 int accept_thread_running;
41 static void __quit_n_join_accept_thread(ts_handle handle);
42 static int _create_accept_thread(ts_handle handle);
44 static char *_get_socket_addr_name(const char *appID, const char *token)
46 return common_make_socket_addr_name(token, appID, (guint)getpid());
49 static char *_get_app_id(void)
57 static char *_get_token(const char *appID)
59 char *checksum = NULL;
62 key = g_strdup_printf("%s-%u-%llu",
63 appID, getpid(), common_get_monotonic_coarse_time());
64 checksum = g_compute_checksum_for_string (G_CHECKSUM_MD5, key, -1);
71 __on_disconnect(GIOChannel *ch, GIOCondition cond, gpointer data)
73 ts_handle handle = data;
74 gboolean connected = FALSE;
76 connected = g_socket_is_connected(handle->cl_socket);
78 _E("client socket is disconnected");
81 _E("connection has error");
84 _E("connection has been broken");
86 g_socket_shutdown(handle->cl_socket, FALSE, TRUE, NULL);
87 g_socket_close(handle->cl_socket, NULL);
88 g_object_unref(handle->cl_socket);
90 handle->cl_socket = NULL;
92 _create_accept_thread(handle);
97 static void _ts_handle_free(ts_handle handle)
101 __quit_n_join_accept_thread(handle);
104 g_free(handle->app_id);
107 g_free(handle->token);
109 if (handle->socket) {
110 g_socket_close(handle->socket, NULL);
111 g_object_unref(handle->socket);
115 g_object_unref(handle->addr);
118 g_object_unref(handle->bus);
121 g_object_unref(handle->proxy);
126 static void __quit_n_join_accept_thread(ts_handle handle)
128 if (handle->accept_thread) {
129 g_atomic_int_set(&(handle->accept_thread_running), 0);
130 g_thread_join(handle->accept_thread);
131 handle->accept_thread = NULL;
135 static gpointer accept_thread(gpointer data)
137 ts_handle handle = data;
138 retv_if(!handle, NULL);
141 GSocket *new_socket = NULL;
142 GIOChannel *new_ch = NULL;
144 GError *error = NULL;
146 if (!g_atomic_int_get(&(handle->accept_thread_running)))
149 new_socket = g_socket_accept(handle->socket, NULL, &error);
152 if (error->code != G_IO_ERROR_WOULD_BLOCK)
153 _E("err on g_socket_accept() - %s", error->message);
160 _D("accepted new socket[%p]", new_socket);
161 fd = g_socket_get_fd(new_socket);
162 new_ch = g_io_channel_unix_new(fd);
163 g_io_add_watch(new_ch, (GIOCondition) (G_IO_ERR | G_IO_HUP),
164 __on_disconnect, handle);
165 handle->cl_socket = new_socket;
166 break; /* accept and exit thread */
168 _D("exiting accept thread");
173 static int _create_accept_thread(ts_handle handle)
175 GThread *new_thread = NULL;
176 GError *error = NULL;
178 retv_if(!handle, -1);
180 if (handle->accept_thread)
181 __quit_n_join_accept_thread(handle);
183 g_atomic_int_set(&(handle->accept_thread_running), 1);
184 new_thread = g_thread_try_new(NULL, accept_thread, handle, &error);
186 _E("failed to create accept thread - %s", error->message);
194 static int __client_method_call(const char *method, ts_handle handle)
196 GVariant *response = NULL;
198 GError *error = NULL;
200 _D("call method [%s]", method);
201 response = g_dbus_proxy_call_sync(handle->proxy,
203 g_variant_new("(ssu)", handle->token, handle->app_id, (guint)getpid()),
204 G_DBUS_CALL_FLAGS_NONE,
205 -1, /* The timeout in milliseconds or -1 to use the proxy default timeout. */
206 NULL, /* cancellable */
209 _E("failed to g_dbus_proxy_call_sync() - %s", error->message);
213 g_variant_get(response, "(i)", ret);
214 _D("method[%s] get response ret[%d]", method, ret);
215 g_variant_unref(response);
220 static int _client_call_register(ts_handle handle)
222 return __client_method_call(TTD_APP_INF_METHOD_REG, handle);
225 static int _client_call_unregister(ts_handle handle)
227 return __client_method_call(TTD_APP_INF_METHOD_UNREG, handle);
230 int things_service_init(ts_handle *handle)
232 ts_handle _handle = NULL;
233 GError *error = NULL;
234 char *socket_name = NULL;
236 retv_if(!handle, -1);
238 _handle = g_try_malloc0(sizeof(ts_handle));
239 _handle->app_id = _get_app_id();
240 if (!_handle->app_id) {
241 _E("failed to get app id");
242 _ts_handle_free(_handle);
245 _D("libthings_service with - %s", _handle->app_id);
247 _handle->token = _get_token(_handle->app_id);
248 if (!_handle->token) {
249 _E("failed to get token");
250 _ts_handle_free(_handle);
253 _D("get token - %s", _handle->token);
254 _handle->cl_socket = NULL;
255 _handle->socket = g_socket_new(G_SOCKET_FAMILY_UNIX,
256 G_SOCKET_TYPE_STREAM,
257 G_SOCKET_PROTOCOL_DEFAULT,
259 if (!_handle->socket) {
260 _E("failed to create socket - %s", error->message);
262 _ts_handle_free(_handle);
265 g_socket_set_blocking(_handle->socket, FALSE);
267 socket_name = _get_socket_addr_name(_handle->app_id, _handle->token);
269 _E("failed to get socket_name");
270 _ts_handle_free(_handle);
273 _handle->addr = g_unix_socket_address_new_with_type(
274 socket_name, -1, G_UNIX_SOCKET_ADDRESS_ABSTRACT);
275 _D("got socket addr - [%s]", socket_name);
278 g_socket_bind(_handle->socket, _handle->addr, TRUE, &error);
280 _E("failed to g_socket_bind() - %s", error->message);
282 _ts_handle_free(_handle);
286 g_socket_listen(_handle->socket, &error);
288 _E("failed to g_socket_listen() - %s", error->message);
290 _ts_handle_free(_handle);
295 g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error);
297 _E("failed to g_bus_get_sync() - %s", error->message);
299 _ts_handle_free(_handle);
303 _handle->proxy = g_dbus_proxy_new_sync(_handle->bus,
304 G_DBUS_PROXY_FLAGS_NONE,
305 NULL, /* GDBusInterfaceInfo */
306 TTD_APP_INF_BUS_NAME,
307 TTD_APP_INF_OBJECT_PATH,
309 NULL, /* cancellable */
311 if (!_handle->proxy) {
312 _E("failed to g_dbus_proxy_new_sync() - %s",
313 error ? error->message : "error not set");
314 _ts_handle_free(_handle);
318 if (_create_accept_thread(_handle)) {
319 _E("failed to _create_accept_thread()");
320 _ts_handle_free(_handle);
324 if (_client_call_register(_handle)) {
325 _E("failed to call register");
326 _ts_handle_free(_handle);
335 int things_service_fini(ts_handle handle)
337 retv_if(!handle, -1);
339 _client_call_unregister(handle);
340 _ts_handle_free(handle);
345 int things_service_send_data(ts_handle handle, const char *json_data)
347 gboolean connected = FALSE;
349 GError *error = NULL;
351 retv_if(!handle, -1);
352 retv_if(!handle->socket, -1);
353 retv_if(!handle->cl_socket, -1);
354 retv_if(!json_data, -1);
356 connected = g_socket_is_connected(handle->cl_socket);
357 retv_if(!connected, -1);
359 msg = g_strdup_printf("%s %s", json_data, TTD_APP_MSG_DELIMITER);
360 g_socket_send(handle->cl_socket, msg, strlen(msg), NULL, &error);
362 _E("failed to g_socket_send() - %s", error->message);
366 _D("msg is sent - %s", msg);