Create disc_handle for each ip_resolving operation
[platform/core/api/vine.git] / src / vine-session.cpp
1 /*
2  * Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.0 (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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 #include <map>
18
19 #include "vine.h"
20 #include "vine-disc.h"
21 #include "vine-event-loop.h"
22 #include "vine-session.h"
23 #include "vine-service.h"
24 #include "vine-log.h"
25 #include "vine-utils.h"
26
27 using namespace std;
28
29 typedef struct {
30         vine_event_queue_h event_fd;
31
32         vine_discovery_method_e disc_method;
33         vine_disc_h disc_handle;
34
35         vine_session_registered_cb registered_cb;
36         void *registered_cb_data;
37         vine_session_discovered_cb discovered_cb;
38         void *discovered_cb_data;
39
40         bool is_running;
41         bool registered;
42         bool discovered;
43 } vine_session_s;
44
45 static void __vine_session_set_is_running(vine_session_h session, bool is_running)
46 {
47         vine_session_s *s = (vine_session_s *)session;
48         s->is_running = is_running;
49 }
50
51 static bool __vine_session_is_running(vine_session_h session)
52 {
53         vine_session_s *s = (vine_session_s *)session;
54         return s->is_running;
55 }
56
57 static bool __vine_session_is_registered(vine_session_h session)
58 {
59         vine_session_s *s = (vine_session_s *)session;
60         return s->registered;
61 }
62
63 static bool __vine_session_is_discovered(vine_session_h session)
64 {
65         vine_session_s *s = (vine_session_s *)session;
66         return s->discovered;
67 }
68
69 static void __vine_session_set_registered(vine_session_h session, bool registered)
70 {
71         vine_session_s *s = (vine_session_s *)session;
72         s->registered = registered;
73 }
74
75 static void __vine_session_set_discovered(vine_session_h session, bool discovered)
76 {
77         vine_session_s *s = (vine_session_s *)session;
78         s->discovered = discovered;
79 }
80
81 int _vine_session_create(vine_session_h *session)
82 {
83         RET_VAL_IF(session == NULL, VINE_ERROR_INVALID_PARAMETER, "session is NULL");
84
85         vine_session_s *s =
86                 (vine_session_s *)calloc(1, sizeof(vine_session_s));
87         RET_VAL_IF(s == NULL, VINE_ERROR_OUT_OF_MEMORY, "Out of memory");
88
89         VINE_LOGD("New Session. session[%p]", s);
90         *session = s;
91         s->is_running = false;
92         s->registered = false;
93         s->discovered = false;
94         s->disc_handle = NULL;
95
96         int ret = vine_event_queue_create(&(s->event_fd));
97         if (ret != VINE_ERROR_NONE) {
98                 VINE_LOGE("Fail to create eventfd %d", ret);
99                 free(*session);
100                 return ret;
101         }
102
103         return VINE_ERROR_NONE;
104 }
105
106 int _vine_session_destroy(vine_session_h session)
107 {
108         RET_VAL_IF(session == NULL, VINE_ERROR_INVALID_PARAMETER, "session is NULL");
109         vine_session_s *s = (vine_session_s *)session;
110
111         VINE_LOGD("Destroy Session. session[%p]", session);
112         vine_event_queue_destroy(s->event_fd);
113         vine_disc_destroy(s->disc_handle);
114         s->disc_handle = NULL;
115         free(session);
116         return VINE_ERROR_NONE;
117 }
118
119 int _vine_session_set_registered_cb(vine_session_h session,
120                 vine_session_registered_cb callback, void *user_data)
121 {
122         RET_VAL_IF(session == NULL, VINE_ERROR_INVALID_PARAMETER, "session is NULL");
123         RET_VAL_IF(callback == NULL, VINE_ERROR_INVALID_PARAMETER, "callback is NULL");
124
125         VINE_LOGD("Set registered callback. session[%p]", session);
126         vine_session_s *s = (vine_session_s *)session;
127         s->registered_cb = callback;
128         s->registered_cb_data = user_data;
129         return VINE_ERROR_NONE;
130 }
131
132 int _vine_session_unset_registered_cb(vine_session_h session)
133 {
134         RET_VAL_IF(session == NULL, VINE_ERROR_INVALID_PARAMETER, "session is NULL");
135
136         VINE_LOGD("Unset registered callback. session[%p]", session);
137         vine_session_s *s = (vine_session_s *)session;
138         s->registered_cb = NULL;
139         s->registered_cb_data = NULL;
140         return VINE_ERROR_NONE;
141 }
142
143 int _vine_session_set_discovered_cb(vine_session_h session,
144                 vine_session_discovered_cb callback, void *user_data)
145 {
146         RET_VAL_IF(session == NULL, VINE_ERROR_INVALID_PARAMETER, "session is NULL");
147         RET_VAL_IF(callback == NULL, VINE_ERROR_INVALID_PARAMETER, "callback is NULL");
148
149         VINE_LOGD("Set discovered callback. session[%p]", session);
150         vine_session_s *s = (vine_session_s *)session;
151         s->discovered_cb = callback;
152         s->discovered_cb_data = user_data;
153         return VINE_ERROR_NONE;
154 }
155
156 int _vine_session_unset_discovered_cb(vine_session_h session)
157 {
158         RET_VAL_IF(session == NULL, VINE_ERROR_INVALID_PARAMETER, "session is NULL");
159
160         VINE_LOGD("Unset discovered callback. session[%p]", session);
161         vine_session_s *s = (vine_session_s *)session;
162         s->discovered_cb = NULL;
163         s->discovered_cb_data = NULL;
164         return VINE_ERROR_NONE;
165 }
166
167 static bool __check_disc_method(vine_discovery_method_e method)
168 {
169         return method == VINE_DISCOVERY_METHOD_DNS_SD;
170 }
171
172 int _vine_session_set_discovery_method(vine_session_h session, vine_discovery_method_e method)
173 {
174         RET_VAL_IF(session == NULL, VINE_ERROR_INVALID_PARAMETER, "session is NULL");
175         RET_VAL_IF(__check_disc_method(method) == false, VINE_ERROR_INVALID_PARAMETER,
176                 "invalid service discovery method");
177
178         VINE_LOGD("Set service discovery method. session[%p] method[%d]", session, method);
179         vine_session_s *s = (vine_session_s *)session;
180         s->disc_method = method;
181
182         return VINE_ERROR_NONE;
183 }
184
185 static void __published_cb(vine_disc_h disc,
186                 const char *service_name, vine_error_e error, void *user_data)
187 {
188         VINE_LOGD("Service is published");
189
190         vine_session_s *s = (vine_session_s *)user_data;
191         VINE_LOGD("session[%p] service_name[%s], error[%d]", s, service_name, error);
192
193         if (error != VINE_ERROR_NONE && error != VINE_ERROR_NAME_CONFLICT) {
194                 VINE_LOGE("Fail to publish");
195                 __vine_session_set_is_running(s, false);
196         } else {
197                 __vine_session_set_registered(s, true);
198         }
199
200         if (s->registered_cb)
201                 s->registered_cb(s, service_name, error, s->registered_cb_data);
202 }
203
204 int _vine_session_register(vine_session_h session,
205         vine_service_h service, const char *iface_name)
206 {
207         RET_VAL_IF(session == NULL, VINE_ERROR_INVALID_PARAMETER, "session is NULL");
208         RET_VAL_IF(service == NULL, VINE_ERROR_INVALID_PARAMETER, "service is NULL");
209         RET_VAL_IF(__vine_session_is_running(session), VINE_ERROR_INVALID_OPERATION,
210                 "session is already running");
211
212         VINE_LOGD("Register a service. session[%p]", session);
213
214         int ret = VINE_ERROR_NONE;
215         vine_session_s *s = (vine_session_s *)session;
216
217         if (s->disc_handle == NULL) {
218                 ret = vine_disc_create(s->disc_method, &s->disc_handle);
219                 RET_VAL_IF(ret != VINE_ERROR_NONE, ret, "Fail to vine_disc_create");
220         }
221
222         ret = vine_disc_publish(s->disc_handle, service, iface_name,
223                         __published_cb, session,
224                         s->event_fd);
225         if (ret != VINE_ERROR_NONE) {
226                 VINE_LOGE("Fail to vine_disc_publish");
227                 vine_disc_destroy(s->disc_handle);
228                 s->disc_handle = NULL;
229                 return ret;
230         }
231
232         __vine_session_set_is_running(session, true);
233         return VINE_ERROR_NONE;
234 }
235
236 int _vine_session_unregister(vine_session_h session)
237 {
238         RET_VAL_IF(session == NULL, VINE_ERROR_INVALID_PARAMETER, "session is NULL");
239         RET_VAL_IF(!__vine_session_is_running(session), VINE_ERROR_INVALID_OPERATION,
240                 "session is not running");
241         RET_VAL_IF(!__vine_session_is_registered(session), VINE_ERROR_INVALID_OPERATION,
242                 "session is not registered");
243
244         int ret = VINE_ERROR_NONE;
245         vine_session_s *s = (vine_session_s *)session;
246
247         ret = vine_disc_stop_publish(s->disc_handle);
248         RET_VAL_IF(ret != VINE_ERROR_NONE, ret, "Fail to vine_disc_stop_publish");
249
250         __vine_session_set_is_running(session, false);
251         __vine_session_set_registered(session, false);
252
253         return VINE_ERROR_NONE;
254 }
255
256 static int __vine_set_discovered_service(vine_service_h service,
257                 const char *service_type, const char *service_name,
258                 const char *host_name, int port, const map<string, string> &attr,
259                 const char *iface_name)
260 {
261         int ret = VINE_ERROR_NONE;
262         ret = _vine_service_set_type(service, service_type);
263         RET_VAL_IF(ret != VINE_ERROR_NONE, ret, "Fail to set service type");
264         ret = _vine_service_set_name(service, service_name);
265         RET_VAL_IF(ret != VINE_ERROR_NONE, ret, "Fail to set service name");
266         ret = _vine_service_set_host_name(service, host_name);
267         RET_VAL_IF(ret != VINE_ERROR_NONE, ret, "Fail to set host name");
268         ret = _vine_service_set_port(service, port);
269         RET_VAL_IF(ret != VINE_ERROR_NONE, ret, "Fail to set port");
270
271         for (const auto &kv : attr)
272                 _vine_service_add_attribute(service, kv.first.c_str(), kv.second.c_str());
273
274         ret = _vine_service_set_iface_name(service, iface_name);
275         RET_VAL_IF(ret != VINE_ERROR_NONE, ret, "Fail to set iface_name");
276
277         return VINE_ERROR_NONE;
278 }
279
280 static void __discovered_cb(vine_disc_h disc, bool available,
281                 const char *service_type, const char *service_name,
282                 const char *host_name, int port, const map<string, string> &attr,
283                 const char *iface_name, int more_coming, void *user_data)
284 {
285         VINE_LOGD("Service is discovered. Available[%d]", available);
286         int ret = VINE_ERROR_NONE;
287
288         vine_session_s *s = (vine_session_s *)user_data;
289         VINE_LOGD("session[%p] service_name[%s], host_name[%s], port[%d], iface[%s]",
290                         s, service_name, host_name, port, iface_name);
291
292         vine_service_h discovered_service;
293         ret = _vine_service_create(&discovered_service, false);
294         RET_IF(ret != VINE_ERROR_NONE, "Fail to create a service");
295
296         ret = __vine_set_discovered_service(discovered_service,
297                         service_type, service_name, host_name, port, attr, iface_name);
298         if (ret != VINE_ERROR_NONE) {
299                 VINE_LOGE("Fail to set a service. error(%d)", ret);
300                 _vine_service_destroy(discovered_service);
301                 return;
302         }
303
304         vine_service_state_e state = available ? VINE_SERVICE_AVAILABLE
305                                                                                         : VINE_SERVICE_UNAVAILABLE;
306         _vine_service_set_state(discovered_service, state);
307
308         if (s->discovered_cb)
309                 s->discovered_cb(s, discovered_service, state, s->discovered_cb_data);
310
311         _vine_service_destroy(discovered_service);
312 }
313
314 int _vine_session_start_discovery(vine_session_h session,
315         const char *service_type, const char *iface_name)
316 {
317         RET_VAL_IF(session == NULL, VINE_ERROR_INVALID_PARAMETER, "session is NULL");
318         RET_VAL_IF(_vine_service_check_service_type(service_type) == false,
319                 VINE_ERROR_INVALID_PARAMETER, "invalid length of service_type");
320         RET_VAL_IF(__vine_session_is_running(session), VINE_ERROR_INVALID_OPERATION,
321                 "session is already running");
322
323         VINE_LOGD("Subscribe a service. session[%p] service_type[%s]", session, service_type);
324         int ret = VINE_ERROR_NONE;
325         vine_session_s *s = (vine_session_s *)session;
326
327         if (s->disc_handle == NULL) {
328                 ret = vine_disc_create(s->disc_method, &s->disc_handle);
329                 RET_VAL_IF(ret != VINE_ERROR_NONE, ret, "Fail to vine_disc_create");
330         }
331
332         ret = vine_disc_subscribe(s->disc_handle, service_type, iface_name,
333                         __discovered_cb, session,
334                         s->event_fd);
335         if (ret != VINE_ERROR_NONE) {
336                 VINE_LOGE("Fail to vine_disc_subscribe");
337                 vine_disc_destroy(s->disc_handle);
338                 s->disc_handle = NULL;
339                 return ret;
340         }
341
342         __vine_session_set_is_running(session, true);
343         __vine_session_set_discovered(s, true);
344
345         return VINE_ERROR_NONE;
346 }
347
348 int _vine_session_stop_discovery(vine_session_h session)
349 {
350         RET_VAL_IF(session == NULL, VINE_ERROR_INVALID_PARAMETER, "session is NULL");
351         RET_VAL_IF(!__vine_session_is_running(session), VINE_ERROR_INVALID_OPERATION,
352                 "session is not running");
353         RET_VAL_IF(!__vine_session_is_discovered(session), VINE_ERROR_INVALID_OPERATION,
354                 "session doesn't start discovery");
355
356         int ret = VINE_ERROR_NONE;
357         vine_session_s *s = (vine_session_s *)session;
358
359         ret = vine_disc_stop_subscribe(s->disc_handle);
360         RET_VAL_IF(ret != VINE_ERROR_NONE, ret, "Fail to vine_disc_stop_subscribe");
361
362         __vine_session_set_is_running(session, false);
363         __vine_session_set_discovered(session, false);
364
365         return VINE_ERROR_NONE;
366 }
367
368 static void __ip_resolved_cb(vine_disc_h disc, vine_service_h service, bool add,
369                                 const char *ip, vine_address_family_e address_family, void *user_data)
370 {
371         VINE_LOGD("IP is resolved");
372
373         vine_session_s *s = (vine_session_s *)user_data;
374         VINE_LOGD("session[%p] service[%p]", s, service);
375         VINE_LOGD("IP[%s], address family[%d] %s", ip, address_family,
376                 add ? "Add" : "Remove");
377
378         vine_session_ip_resolved_cb cb = _vine_service_ip_resolved_cb(service);
379         void *cb_data = _vine_service_ip_resolved_cb_data(service);
380         if (cb && add)
381                 cb(s, service, ip, address_family, cb_data);
382 }
383
384 int _vine_session_set_ip_resolved_cb(vine_session_h session,
385         vine_service_h service, vine_session_ip_resolved_cb callback, void *user_data)
386 {
387         RET_VAL_IF(session == NULL, VINE_ERROR_INVALID_PARAMETER, "session is NULL");
388         RET_VAL_IF(service == NULL, VINE_ERROR_INVALID_PARAMETER, "service is NULL");
389
390         VINE_LOGD("Resolve IP address for a service[%p]. session[%p]", service, session);
391
392         int ret = VINE_ERROR_NONE;
393         vine_session_s *s = (vine_session_s *)session;
394
395         vine_disc_h disc_handle;
396         ret = vine_disc_create(s->disc_method, &disc_handle);
397         RET_VAL_IF(ret != VINE_ERROR_NONE, ret, "Fail to vine_disc_create");
398
399         ret = _vine_service_set_disc_handle(service, disc_handle);
400         RET_VAL_IF(ret != VINE_ERROR_NONE, ret, "Fail to set disc_handle");
401
402         _vine_service_set_ip_resolved_cb(service, callback, user_data);
403
404         ret = vine_disc_resolve_ip(disc_handle, service,
405                         __ip_resolved_cb, session,
406                         s->event_fd);
407         RET_VAL_IF(ret != VINE_ERROR_NONE, ret, "Fail to vine_disc_resolve_ip");
408
409         return VINE_ERROR_NONE;
410 }
411
412 int _vine_session_unset_ip_resolved_cb(vine_session_h session,
413         vine_service_h service)
414 {
415         RET_VAL_IF(session == NULL, VINE_ERROR_INVALID_PARAMETER, "session is NULL");
416         RET_VAL_IF(service == NULL, VINE_ERROR_INVALID_PARAMETER, "service is NULL");
417
418         VINE_LOGD("Cancel resolving IP address for a service[%p]. session[%p]", service, session);
419
420         int ret = VINE_ERROR_NONE;
421         vine_disc_h disc_handle = NULL;
422         ret = _vine_service_get_disc_handle(service, VINE_DISCOVERY_METHOD_DNS_SD, &disc_handle);
423         RET_VAL_IF(ret != VINE_ERROR_NONE, ret, "Fail to _vine_service_get_disc_handle");
424
425         _vine_service_set_ip_resolved_cb(service, NULL, NULL);
426
427         ret = vine_disc_cancel_resolve_ip(disc_handle, service);
428         RET_VAL_IF(ret != VINE_ERROR_NONE, ret, "Fail to vine_disc_cancel_resolve_ip");
429
430         return VINE_ERROR_NONE;
431 }
432
433 int _vine_session_get_event_queue(vine_session_h session, vine_event_queue_h *eq)
434 {
435         RET_VAL_IF(session == NULL, VINE_ERROR_INVALID_PARAMETER, "session is NULL");
436
437         vine_session_s *s = (vine_session_s *)session;
438         *eq = s->event_fd;
439         return VINE_ERROR_NONE;
440 }
441
442 int _vine_session_get_event_fd(vine_session_h session, int *fd)
443 {
444         RET_VAL_IF(session == NULL, VINE_ERROR_INVALID_PARAMETER, "session is NULL");
445
446         vine_session_s *s = (vine_session_s *)session;
447         vine_event_loop_get_eventfd(s->event_fd, fd);
448         return VINE_ERROR_NONE;
449 }
450
451 int _vine_session_process_event(vine_session_h session)
452 {
453         RET_VAL_IF(session == NULL, VINE_ERROR_INVALID_PARAMETER, "session is NULL");
454
455         VINE_LOGD("Process event. session[%p]", session);
456         vine_session_s *s = (vine_session_s *)session;
457         return vine_event_loop_process(s->event_fd);
458 }