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.
20 #include <sys/types.h>
21 #include <sys/socket.h>
22 #include <netinet/in.h>
23 #include <arpa/inet.h>
27 #include "receiver_internal.h"
29 #define RECEIVER_UDP_PORT 57984
30 #define RECEIVER_UDP_WAIT_TIMEOUT 3
32 typedef enum __receiver_udp_state_e {
33 RECEIVER_UDP_STATE_NONE,
34 RECEIVER_UDP_STATE_READY,
35 RECEIVER_UDP_STATE_CONNECTED,
36 } receiver_udp_state_e;
38 typedef struct __receiver_udp_h {
41 receiver_udp_state_e state;
45 static receiver_udp_h *udp_handle = NULL;
47 static gchar *__socket_address_to_string(GSocketAddress *address)
49 GInetAddress *inet_address = NULL;
54 g_inet_socket_address_get_address(G_INET_SOCKET_ADDRESS(address));
56 str = g_inet_address_to_string(inet_address);
57 port = g_inet_socket_address_get_port(G_INET_SOCKET_ADDRESS(address));
59 res = g_strdup_printf("%s:%d", str, port);
65 int __receiver_udp_init(void)
68 _E("receiver udp is already initialized");
72 udp_handle = malloc(sizeof(receiver_udp_h));
74 _E("failed to alloc receiver udp handle");
78 udp_handle->state = RECEIVER_UDP_STATE_NONE;
79 udp_handle->io_watch_id = 0;
80 udp_handle->wait_timer_id = 0;
81 udp_handle->socket = NULL;
86 int __receiver_udp_fini(void)
89 if (udp_handle->io_watch_id)
90 g_source_remove(udp_handle->io_watch_id);
92 if (udp_handle->wait_timer_id)
93 g_source_remove(udp_handle->wait_timer_id);
95 if (udp_handle->socket) {
96 g_socket_close(udp_handle->socket, NULL);
97 g_object_unref(udp_handle->socket);
107 /* Uses system call, because glib socket API doesn't support unset connect
108 * Please carefully use this function, and after use this function,
109 * DO NOT use g_socket_is_connected().
111 static int __receiver_udp_unset_connection(void)
113 struct sockaddr addr;
116 retvm_if(!udp_handle, -1, "handle is not created");
117 retvm_if(!udp_handle->socket, -1, "socket is not created");
119 s_fd = g_socket_get_fd(udp_handle->socket);
120 bzero((char *)&addr, sizeof(addr));
121 addr.sa_family = AF_UNSPEC;
123 if (connect(s_fd, &addr, sizeof(addr))) {
124 _E("failed to unset connect - %s\n", strerror(errno));
125 /* re-create socket or not ??? */
128 udp_handle->state = RECEIVER_UDP_STATE_READY;
129 _D("unset connection");
134 static int __receiver_udp_set_connection(GSocketAddress *sender_a)
136 GError *error = NULL;
138 retv_if(!sender_a, -1);
139 retvm_if(!udp_handle, -1, "handle is not created");
140 retvm_if(!udp_handle->socket, -1, "socket is not created");
142 if (udp_handle->state != RECEIVER_UDP_STATE_READY) {
143 _E("check state %d", udp_handle->state);
147 /* use connect() to specify sender address and reject other sender */
148 if (!g_socket_connect(udp_handle->socket, sender_a, NULL, &error)) {
149 _E("failed to connect - %s", error->message);
153 udp_handle->state = RECEIVER_UDP_STATE_CONNECTED;
154 _D("set connection");
159 static gboolean __wait_time_out(gpointer user_data)
161 __receiver_udp_unset_connection();
166 static void __receiver_udp_update_wait_timer(void)
169 if (udp_handle->wait_timer_id) {
170 g_source_remove(udp_handle->wait_timer_id);
171 udp_handle->wait_timer_id = 0;
173 udp_handle->wait_timer_id =
174 g_timeout_add_seconds(RECEIVER_UDP_WAIT_TIMEOUT,
175 (GSourceFunc)__wait_time_out, NULL);
180 static gboolean __read_socket(GIOChannel *channel,
181 GIOCondition condition,
185 receiver_udp_h *handle = (receiver_udp_h *)data;
186 GError *error = NULL;
188 char buf[1024] = {0, }; /* temp */
190 retv_if(!handle, TRUE);
191 retv_if(!handle->socket, TRUE);
193 if (handle->state == RECEIVER_UDP_STATE_NONE) {
194 _E("receiver udp is not ready yet");
198 if (handle->state == RECEIVER_UDP_STATE_READY) {
200 GSocketAddress *address = NULL;
202 size = g_socket_receive_from(handle->socket, &address,
203 buf, sizeof(buf), NULL, &error);
206 _D("Error receiving from socket: %s", error->message);
210 s_addr = __socket_address_to_string(address);
211 _D("received first data from [%s]", s_addr);
214 if (!__receiver_udp_set_connection(address))
215 __receiver_udp_update_wait_timer();
217 _E("failed to set connection with [%s]", s_addr);
220 g_object_unref(address);
221 } else { /* state is RECEIVER_UDP_STATE_CONNECTED */
222 size = g_socket_receive(handle->socket,
223 buf, sizeof(buf), NULL, &error);
226 _D("Error receiving from socket: %s", error->message);
230 __receiver_udp_update_wait_timer();
233 /* TODO : what should I do after receiveing some data? */
238 int receiver_udp_start(void)
240 GError *error = NULL;
241 GSocketAddress *address = NULL;
242 GInetAddress *i_addr = NULL;
244 GIOChannel *ch = NULL;
248 ret = __receiver_udp_init();
253 if (udp_handle->state >= RECEIVER_UDP_STATE_READY) {
254 _W("receivet udp is already started");
258 udp_handle->socket = g_socket_new(G_SOCKET_FAMILY_IPV4,
259 G_SOCKET_TYPE_DATAGRAM, G_SOCKET_PROTOCOL_UDP, &error);
261 if (udp_handle->socket == NULL) {
262 _E("failed to get new socket - %s", error->message);
266 /* set non-blocking mode */
267 g_socket_set_blocking(udp_handle->socket, FALSE);
269 i_addr = g_inet_address_new_any(G_SOCKET_FAMILY_IPV4);
271 _E("failed to get inet any address");
274 address = g_inet_socket_address_new(i_addr, RECEIVER_UDP_PORT);
275 g_object_unref(i_addr);
279 _E("failed to get socket address");
283 if (!g_socket_bind(udp_handle->socket, address, TRUE, &error)) {
284 _E("Can't bind socket: %s\n", error->message);
287 g_object_unref(address);
290 socket_fd = g_socket_get_fd(udp_handle->socket);
291 ch = g_io_channel_unix_new(socket_fd);
292 udp_handle->io_watch_id =
293 g_io_add_watch(ch, G_IO_IN, __read_socket, udp_handle);
294 g_io_channel_unref(ch);
297 udp_handle->state = RECEIVER_UDP_STATE_READY;
298 _D("receiver udp started");
307 g_object_unref(address);
310 g_object_unref(i_addr);
312 __receiver_udp_fini();
317 int receiver_udp_stop(void)
319 __receiver_udp_fini();
320 _D("receiver udp stopped");