summaryrefslogtreecommitdiff
path: root/src/receiver_udp.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/receiver_udp.c')
-rw-r--r--src/receiver_udp.c477
1 files changed, 477 insertions, 0 deletions
diff --git a/src/receiver_udp.c b/src/receiver_udp.c
new file mode 100644
index 0000000..07c2028
--- /dev/null
+++ b/src/receiver_udp.c
@@ -0,0 +1,477 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Flora License, Version 1.1 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://floralicense.org/license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdlib.h>
+#include <glib.h>
+#include <gio/gio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <errno.h>
+
+#include "log.h"
+#include "receiver_internal.h"
+#include "message.h"
+
+#define RECEIVER_UDP_PORT 57984
+#define RECEIVER_UDP_WAIT_TIMEOUT 3
+
+typedef enum __receiver_udp_state_e {
+ RECEIVER_UDP_STATE_NONE,
+ RECEIVER_UDP_STATE_INIT,
+ RECEIVER_UDP_STATE_READY,
+ RECEIVER_UDP_STATE_CONNECTED,
+} receiver_udp_state_e;
+
+typedef struct __receiver_udp_h {
+ guint io_watch_id;
+ guint wait_timer_id;
+ receiver_udp_state_e state;
+ GSocket *socket;
+} receiver_udp_h;
+
+// static receiver_udp_h *udp_handle = NULL;
+
+static gchar *__socket_address_to_string(GSocketAddress *address)
+{
+ GInetAddress *inet_address = NULL;
+ char *str, *res;
+ int port;
+
+ inet_address =
+ g_inet_socket_address_get_address(G_INET_SOCKET_ADDRESS(address));
+
+ str = g_inet_address_to_string(inet_address);
+ port = g_inet_socket_address_get_port(G_INET_SOCKET_ADDRESS(address));
+
+ res = g_strdup_printf("%s:%d", str, port);
+ g_free(str);
+
+ return res;
+}
+
+static receiver_state_e ___state_convert(receiver_udp_state_e state)
+{
+ receiver_state_e r_state = RECEIVER_STATE_NONE;
+
+ switch (state) {
+ case RECEIVER_UDP_STATE_NONE:
+ r_state = RECEIVER_STATE_NONE;
+ break;
+ case RECEIVER_UDP_STATE_INIT:
+ r_state = RECEIVER_STATE_INIT;
+ break;
+ case RECEIVER_UDP_STATE_READY:
+ r_state = RECEIVER_STATE_READY;
+ break;
+ case RECEIVER_UDP_STATE_CONNECTED:
+ r_state = RECEIVER_STATE_CONNECTED;
+ break;
+ }
+ return r_state;
+}
+
+static void __receiver_udp_state_set(
+ receiver_module_h *handle, receiver_udp_state_e state)
+{
+ receiver_udp_h *udp_handle = NULL;
+
+ ret_if(!handle);
+
+ udp_handle = receiver_get_module_data(handle);
+ ret_if(!udp_handle);
+
+ udp_handle->state = state;
+
+ receiver_module_state_changed(handle, ___state_convert(state));
+
+ return;
+}
+
+/* Uses system call, because glib socket API doesn't support unset connect
+ * Please carefully use this function, and after use this function,
+ * DO NOT use g_socket_is_connected().
+ */
+static int __receiver_udp_unset_connection(receiver_module_h *handle)
+{
+ receiver_udp_h *udp_handle = NULL;
+ struct sockaddr addr;
+ int s_fd = 0;
+
+ retv_if(!handle, -1);
+
+ udp_handle = receiver_get_module_data(handle);
+
+ retvm_if(!udp_handle, -1, "handle is not created");
+ retvm_if(!udp_handle->socket, -1, "socket is not created");
+
+ s_fd = g_socket_get_fd(udp_handle->socket);
+ bzero((char *)&addr, sizeof(addr));
+ addr.sa_family = AF_UNSPEC;
+
+ if (connect(s_fd, &addr, sizeof(addr))) {
+ _E("failed to unset connect - %s\n", strerror(errno));
+ /* re-create socket or not ??? */
+ return -1;
+ }
+
+ __receiver_udp_state_set(handle, RECEIVER_UDP_STATE_READY);
+
+ return 0;
+}
+
+static int __receiver_udp_set_connection(
+ receiver_module_h *handle, GSocketAddress *sender_a)
+{
+ GError *error = NULL;
+ receiver_udp_h *udp_handle = NULL;
+
+ retv_if(!handle, -1);
+ retv_if(!sender_a, -1);
+
+ udp_handle = receiver_get_module_data(handle);
+
+ retvm_if(!udp_handle, -1, "handle is not created");
+ retvm_if(!udp_handle->socket, -1, "socket is not created");
+
+ if (udp_handle->state != RECEIVER_UDP_STATE_READY) {
+ _E("check state %d", udp_handle->state);
+ return -1;
+ }
+
+ /* use connect() to specify sender address and reject other sender */
+ if (!g_socket_connect(udp_handle->socket, sender_a, NULL, &error)) {
+ _E("failed to connect - %s", error->message);
+ g_error_free(error);
+ return -1;
+ }
+
+ __receiver_udp_state_set(handle, RECEIVER_UDP_STATE_CONNECTED);
+
+ return 0;
+}
+
+static gboolean __wait_time_out(gpointer user_data)
+{
+ receiver_module_h *handle = user_data;
+
+ retv_if(!handle, FALSE);
+
+ __receiver_udp_unset_connection(handle);
+
+ return FALSE;
+}
+
+static void __receiver_udp_update_wait_timer(receiver_module_h *handle)
+{
+ receiver_udp_h *udp_handle = NULL;
+
+ ret_if(!handle);
+
+ udp_handle = receiver_get_module_data(handle);
+
+ if (udp_handle) {
+ if (udp_handle->wait_timer_id) {
+ g_source_remove(udp_handle->wait_timer_id);
+ udp_handle->wait_timer_id = 0;
+ }
+ udp_handle->wait_timer_id =
+ g_timeout_add_seconds(RECEIVER_UDP_WAIT_TIMEOUT,
+ (GSourceFunc)__wait_time_out, handle);
+ }
+
+ return;
+}
+
+static gboolean __read_socket(GIOChannel *channel,
+ GIOCondition condition,
+ gpointer data)
+{
+ receiver_module_h *handle = data;
+ receiver_udp_h *udp_handle = NULL;
+ GError *error = NULL;
+ message_s *r_msg = NULL;
+ gssize size = 0;
+
+ retv_if(!handle, TRUE);
+
+ udp_handle = receiver_get_module_data(handle);
+
+ retv_if(!udp_handle, TRUE);
+ retv_if(!udp_handle->socket, TRUE);
+
+ if (udp_handle->state < RECEIVER_UDP_STATE_READY) {
+ _E("receiver udp is not ready yet");
+ return TRUE;
+ }
+
+ r_msg = malloc(sizeof(message_s));
+ retv_if(!r_msg, TRUE);
+
+ if (udp_handle->state == RECEIVER_UDP_STATE_READY) {
+ char *s_addr = NULL;
+ GSocketAddress *address = NULL;
+
+ size = g_socket_receive_from(udp_handle->socket, &address,
+ (gchar *)r_msg, sizeof(message_s), NULL, &error);
+
+ if (size < 0) {
+ _D("Error receiving from socket: %s", error->message);
+ g_error_free(error);
+ free(r_msg);
+ r_msg = NULL;
+ }
+
+ s_addr = __socket_address_to_string(address);
+ _D("received first data from [%s]", s_addr);
+
+ message_push_to_inqueue(r_msg);
+
+ if (!__receiver_udp_set_connection(handle, address))
+ __receiver_udp_update_wait_timer(handle);
+ else
+ _E("failed to set connection with [%s]", s_addr);
+
+ free(s_addr);
+ g_object_unref(address);
+ } else { /* state is RECEIVER_UDP_STATE_CONNECTED */
+ size = g_socket_receive(udp_handle->socket,
+ (gchar *)r_msg, sizeof(message_s), NULL, &error);
+
+ if (size < 0) {
+ _D("Error receiving from socket: %s", error->message);
+ g_error_free(error);
+ free(r_msg);
+ r_msg = NULL;
+ }
+ _D("received data");
+ message_push_to_inqueue(r_msg);
+
+ __receiver_udp_update_wait_timer(handle);
+ }
+
+ /* TODO : what should I do after receiveing some data? */
+
+ return TRUE;
+}
+
+static int _receiver_udp_start(void *data)
+{
+ receiver_module_h *handle = data;
+ receiver_udp_h *udp_handle = NULL;
+ int socket_fd = 0;
+ GIOChannel *ch = NULL;
+
+ retv_if(!handle, -1);
+
+ udp_handle = receiver_get_module_data(handle);
+
+ retv_if(!udp_handle, -1);
+ retv_if(!udp_handle->socket, -1);
+
+ if (udp_handle->state != RECEIVER_UDP_STATE_INIT) {
+ if (udp_handle->state == RECEIVER_UDP_STATE_READY) {
+ _E("receiver udp is already started");
+ return 0;
+ } else {
+ _E("receiver udp is invalid state [%d]", udp_handle->state);
+ return -1;
+ }
+ }
+
+ socket_fd = g_socket_get_fd(udp_handle->socket);
+ ch = g_io_channel_unix_new(socket_fd);
+ udp_handle->io_watch_id =
+ g_io_add_watch(ch, G_IO_IN, __read_socket, handle);
+ g_io_channel_unref(ch);
+ ch = NULL;
+
+ __receiver_udp_state_set(handle, RECEIVER_UDP_STATE_READY);
+
+ return 0;
+}
+
+static int _receiver_udp_stop(void *data)
+{
+ receiver_module_h *handle = data;
+ receiver_udp_h *udp_handle = NULL;
+
+ retv_if(!handle, -1);
+
+ udp_handle = receiver_get_module_data(handle);
+
+ retv_if(!udp_handle, -1);
+ retv_if(!udp_handle->socket, -1);
+
+ if (udp_handle->state < RECEIVER_UDP_STATE_READY) {
+ _E("receiver udp is invalid state [%d]", udp_handle->state);
+ return -1;
+ }
+
+ if (udp_handle->wait_timer_id) {
+ g_source_remove(udp_handle->wait_timer_id);
+ udp_handle->wait_timer_id = 0;
+ }
+
+ if (udp_handle->io_watch_id) {
+ g_source_remove(udp_handle->io_watch_id);
+ udp_handle->io_watch_id = 0;
+ }
+
+ __receiver_udp_state_set(handle, RECEIVER_UDP_STATE_INIT);
+
+ return 0;
+}
+
+static int _receiver_udp_init(void *data)
+{
+ receiver_module_h *handle = data;
+ receiver_udp_h *udp_handle = NULL;
+ GError *error = NULL;
+ GSocketAddress *address = NULL;
+ GInetAddress *i_addr = NULL;
+
+ retv_if(!handle, -1);
+
+ udp_handle = receiver_get_module_data(handle);
+ retv_if(!udp_handle, -1);
+
+ if (udp_handle->state != RECEIVER_UDP_STATE_NONE) {
+ _E("receiver udp is invalid state [%d]", udp_handle->state);
+ return -1;
+ }
+
+ udp_handle->socket = g_socket_new(G_SOCKET_FAMILY_IPV4,
+ G_SOCKET_TYPE_DATAGRAM, G_SOCKET_PROTOCOL_UDP, &error);
+
+ if (udp_handle->socket == NULL) {
+ _E("failed to get new socket - %s", error->message);
+ goto ERROR;
+ }
+
+ /* set non-blocking mode */
+ g_socket_set_blocking(udp_handle->socket, FALSE);
+
+ i_addr = g_inet_address_new_any(G_SOCKET_FAMILY_IPV4);
+ if (!i_addr) {
+ _E("failed to get inet any address");
+ goto ERROR;
+ }
+ address = g_inet_socket_address_new(i_addr, RECEIVER_UDP_PORT);
+ g_object_unref(i_addr);
+ i_addr = NULL;
+
+ if (!address) {
+ _E("failed to get socket address");
+ goto ERROR;
+ }
+
+ if (!g_socket_bind(udp_handle->socket, address, TRUE, &error)) {
+ _E("Can't bind socket: %s\n", error->message);
+ goto ERROR;
+ }
+ g_object_unref(address);
+ address = NULL;
+
+ __receiver_udp_state_set(handle, RECEIVER_UDP_STATE_INIT);
+
+ return 0;
+
+ERROR:
+ if (error)
+ g_error_free(error);
+
+ if (address)
+ g_object_unref(address);
+
+ if (i_addr)
+ g_object_unref(i_addr);
+
+ return -1;
+}
+
+static int _receiver_udp_fini(void *data)
+{
+ receiver_module_h *handle = data;
+ receiver_udp_h *udp_handle = NULL;
+
+ retv_if(!handle, -1);
+
+ udp_handle = receiver_get_module_data(handle);
+ retv_if(!udp_handle, -1);
+
+ if (udp_handle) {
+ if (udp_handle->io_watch_id)
+ g_source_remove(udp_handle->io_watch_id);
+
+ if (udp_handle->wait_timer_id)
+ g_source_remove(udp_handle->wait_timer_id);
+
+ if (udp_handle->socket) {
+ g_socket_close(udp_handle->socket, NULL);
+ g_object_unref(udp_handle->socket);
+ }
+
+ __receiver_udp_state_set(handle, RECEIVER_UDP_STATE_NONE);
+
+ free(udp_handle);
+ udp_handle = NULL;
+ }
+
+ return 0;
+}
+
+static receiver_state_e _receiver_udp_get_state(void *data)
+{
+ receiver_module_h *handle = data;
+ receiver_udp_h *udp_handle = NULL;
+
+ retv_if(!handle, RECEIVER_STATE_NONE);
+
+ udp_handle = receiver_get_module_data(handle);
+ retv_if(!udp_handle, RECEIVER_STATE_NONE);
+
+ return ___state_convert(udp_handle->state);
+}
+
+/* Keep it here??? or move to new file??? */
+int receiver_udp_module_register(receiver_module_h *handle)
+{
+ receiver_udp_h *udp_handle = NULL;
+
+ retv_if(!handle, -1);
+
+ udp_handle = malloc(sizeof(receiver_udp_h));
+ if (!udp_handle) {
+ _E("failed to alloc receiver udp handle");
+ return -1;
+ }
+
+ udp_handle->state = RECEIVER_UDP_STATE_NONE;
+ udp_handle->io_watch_id = 0;
+ udp_handle->wait_timer_id = 0;
+ udp_handle->socket = NULL;
+
+ receiver_set_module_data(handle, udp_handle);
+ receiver_set_module_init_function(handle, _receiver_udp_init);
+ receiver_set_module_fini_function(handle, _receiver_udp_fini);
+ receiver_set_module_start_function(handle, _receiver_udp_start);
+ receiver_set_module_stop_function(handle, _receiver_udp_stop);
+ receiver_set_module_get_state_function(handle, _receiver_udp_get_state);
+
+ return 0;
+}