Added preliminary Symbian support.
[silc.git] / lib / silcutil / unix / silcunixnet.c
index c6a020d7961948fa742d74905d4f8536f00ece47..1ce203811c0c249b5a8baa33915391abac663d8a 100644 (file)
@@ -112,7 +112,8 @@ SILC_TASK_CALLBACK(silc_net_accept)
   silc_net_set_socket_opt(sock, SOL_SOCKET, SO_REUSEADDR, 1);
 
   /* Create socket stream */
-  silc_socket_tcp_stream_create(sock, TRUE, listener->require_fqdn, schedule,
+  silc_socket_tcp_stream_create(sock, listener->lookup,
+                               listener->require_fqdn, schedule,
                                silc_net_accept_stream, listener);
 }
 
@@ -120,8 +121,8 @@ SILC_TASK_CALLBACK(silc_net_accept)
 
 SilcNetListener
 silc_net_tcp_create_listener(const char **local_ip_addr,
-                            SilcUInt32 local_ip_count,
-                            int port, SilcBool require_fqdn,
+                            SilcUInt32 local_ip_count, int port,
+                            SilcBool lookup, SilcBool require_fqdn,
                             SilcSchedule schedule,
                             SilcNetCallback callback, void *context)
 {
@@ -132,7 +133,7 @@ silc_net_tcp_create_listener(const char **local_ip_addr,
 
   SILC_LOG_DEBUG(("Creating TCP listener"));
 
-  if (port < 1 || !schedule || !callback)
+  if (port < 0 || !schedule || !callback)
     goto err;
 
   listener = silc_calloc(1, sizeof(*listener));
@@ -143,6 +144,8 @@ silc_net_tcp_create_listener(const char **local_ip_addr,
   listener->schedule = schedule;
   listener->callback = callback;
   listener->context = context;
+  listener->require_fqdn = require_fqdn;
+  listener->lookup = lookup;
 
   if (local_ip_count > 0) {
     listener->socks = silc_calloc(local_ip_count, sizeof(*listener->socks));
@@ -193,7 +196,7 @@ silc_net_tcp_create_listener(const char **local_ip_addr,
     }
 
     /* Specify that we are listenning */
-    rval = listen(sock, 5);
+    rval = listen(sock, 64);
     if (rval < 0) {
       SILC_LOG_ERROR(("Cannot set socket listenning: %s", strerror(errno)));
       goto err;
@@ -252,7 +255,7 @@ silc_net_udp_connect(const char *local_ip_addr, int local_port,
 
   SILC_LOG_DEBUG(("Creating UDP stream"));
 
-  if (local_port < 1 || !schedule)
+  if (!schedule)
     goto err;
 
   /* Bind to local addresses */
@@ -327,7 +330,7 @@ silc_net_udp_connect(const char *local_ip_addr, int local_port,
   stream =
     silc_socket_udp_stream_create(sock, local_ip_addr ?
                                  silc_net_is_ip6(local_ip_addr) : FALSE,
-                                 schedule);
+                                 remote_ip_addr ? TRUE : FALSE, schedule);
   if (!stream)
     goto err;
 
@@ -395,6 +398,8 @@ int silc_net_udp_receive(SilcStream stream, char *remote_ip_addr,
       inet_ntop(AF_INET, &s.sin.sin_addr, remote_ip_addr,
                remote_ip_addr_size);
     }
+
+    SILC_LOG_DEBUG(("UDP packet from %s:%d", remote_ip_addr, *remote_port));
   }
 
   return len;
@@ -402,21 +407,43 @@ int silc_net_udp_receive(SilcStream stream, char *remote_ip_addr,
 
 /* Send UDP packet */
 
-void silc_net_udp_send(SilcStream stream,
-                      const char *remote_ip_addr, int remote_port,
-                      const unsigned char *data, SilcUInt32 data_len)
+int silc_net_udp_send(SilcStream stream,
+                     const char *remote_ip_addr, int remote_port,
+                     const unsigned char *data, SilcUInt32 data_len)
 {
   SilcSocketStream sock = stream;
   SilcSockaddr remote;
+  int ret;
 
-  SILC_LOG_DEBUG(("Writing data to UDP socket %d", sock->sock));
+  SILC_LOG_DEBUG(("Sending data to UDP socket %d", sock->sock));
 
-  /* Set sockaddr for server */
+  /* Set sockaddr */
   if (!silc_net_set_sockaddr(&remote, remote_ip_addr, remote_port))
-    return;
+    return -2;
 
   /* Send */
-  sendto(sock->sock, data, data_len, 0, &remote.sa, SIZEOF_SOCKADDR(remote));
+  ret = sendto(sock->sock, data, data_len, 0, &remote.sa,
+              SIZEOF_SOCKADDR(remote));
+  if (ret < 0) {
+    if (errno == EAGAIN || errno == EINTR) {
+      SILC_LOG_DEBUG(("Could not send immediately, will do it later"));
+      silc_schedule_set_listen_fd(sock->schedule, sock->sock,
+                                 SILC_TASK_READ | SILC_TASK_WRITE, FALSE);
+      return -1;
+    }
+    SILC_LOG_DEBUG(("Cannot send to UDP socket: %s", strerror(errno)));
+    silc_schedule_unset_listen_fd(sock->schedule, sock->sock);
+    sock->sock_error = errno;
+    return -2;
+  }
+
+  SILC_LOG_DEBUG(("Sent data %d bytes", ret));
+  if (silc_schedule_get_fd_events(sock->schedule, sock->sock) &
+      SILC_TASK_WRITE)
+    silc_schedule_set_listen_fd(sock->schedule, sock->sock,
+                               SILC_TASK_READ, FALSE);
+
+  return ret;
 }
 
 /* Asynchronous TCP/IP connecting */
@@ -426,7 +453,7 @@ typedef struct {
   SilcSocketStreamStatus stream_status;
   SilcStream stream;
   SilcFSMStruct fsm;
-  SilcFSMSemaStruct sema;
+  SilcFSMEventStruct event;
   SilcAsyncOperation op;
   SilcAsyncOperation sop;
   char *local_ip;
@@ -448,7 +475,8 @@ SILC_FSM_STATE(silc_net_connect_st_finish);
 SILC_TASK_CALLBACK(silc_net_connect_wait)
 {
   SilcNetConnect conn = context;
-  SILC_FSM_SEMA_POST(&conn->sema);
+  SILC_FSM_EVENT_SIGNAL(&conn->event);
+  silc_schedule_task_del_by_fd(schedule, conn->sock);
 }
 
 SILC_FSM_STATE(silc_net_connect_st_start)
@@ -461,7 +489,7 @@ SILC_FSM_STATE(silc_net_connect_st_start)
   if (conn->aborted) {
     /** Aborted */
     silc_fsm_next(fsm, silc_net_connect_st_finish);
-    return SILC_FSM_CONTINUE;
+    SILC_FSM_CONTINUE;
   }
 
   /* Do host lookup */
@@ -474,14 +502,14 @@ SILC_FSM_STATE(silc_net_connect_st_start)
     /** Network unreachable */
     conn->status = SILC_NET_HOST_UNREACHABLE;
     silc_fsm_next(fsm, silc_net_connect_st_finish);
-    return SILC_FSM_CONTINUE;
+    SILC_FSM_CONTINUE;
   }
 
   /* Set sockaddr for this connection */
   if (!silc_net_set_sockaddr(&desthost, conn->ip_addr, conn->port)) {
     /** Sockaddr failed */
     silc_fsm_next(fsm, silc_net_connect_st_finish);
-    return SILC_FSM_CONTINUE;
+    SILC_FSM_CONTINUE;
   }
 
   /* Create the connection socket */
@@ -497,7 +525,7 @@ SILC_FSM_STATE(silc_net_connect_st_start)
     /** Cannot create socket */
     SILC_LOG_ERROR(("Cannot create socket: %s", strerror(errno)));
     silc_fsm_next(fsm, silc_net_connect_st_finish);
-    return SILC_FSM_CONTINUE;
+    SILC_FSM_CONTINUE;
   }
 
   /* Bind to the local address if provided */
@@ -531,7 +559,7 @@ SILC_FSM_STATE(silc_net_connect_st_start)
       /** Cannot connect to remote host */
       SILC_LOG_ERROR(("Cannot connect to remote host: %s", strerror(errno)));
       silc_fsm_next(fsm, silc_net_connect_st_finish);
-      return SILC_FSM_CONTINUE;
+      SILC_FSM_CONTINUE;
     }
   }
 
@@ -547,13 +575,13 @@ SILC_FSM_STATE(silc_net_connect_st_start)
 
   /** Wait for connection */
   silc_fsm_next(fsm, silc_net_connect_st_connected);
-  silc_fsm_sema_init(&conn->sema, fsm, 0);
+  silc_fsm_event_init(&conn->event, fsm);
   silc_schedule_task_add_fd(silc_fsm_get_schedule(fsm), sock,
                            silc_net_connect_wait, conn);
   silc_schedule_set_listen_fd(silc_fsm_get_schedule(fsm), sock,
                              SILC_TASK_WRITE, FALSE);
-  SILC_FSM_SEMA_WAIT(&conn->sema);
-  return SILC_FSM_CONTINUE;
+  SILC_FSM_EVENT_WAIT(&conn->event);
+  SILC_FSM_CONTINUE;
 }
 
 static void silc_net_connect_wait_stream(SilcSocketStreamStatus status,
@@ -574,7 +602,7 @@ SILC_FSM_STATE(silc_net_connect_st_connected)
   if (conn->aborted) {
     /** Aborted */
     silc_fsm_next(fsm, silc_net_connect_st_finish);
-    return SILC_FSM_CONTINUE;
+    SILC_FSM_CONTINUE;
   }
 
   ret = silc_net_get_socket_opt(conn->sock, SOL_SOCKET, SO_ERROR,
@@ -590,7 +618,7 @@ SILC_FSM_STATE(silc_net_connect_st_connected)
       conn->retry--;
       silc_net_close_connection(conn->sock);
       silc_fsm_next(fsm, silc_net_connect_st_start);
-      return SILC_FSM_CONTINUE;
+      SILC_FSM_CONTINUE;
     }
 
 #if defined(ECONNREFUSED)
@@ -609,7 +637,7 @@ SILC_FSM_STATE(silc_net_connect_st_connected)
     /** Connecting failed */
     SILC_LOG_DEBUG(("Connecting failed"));
     silc_fsm_next(fsm, silc_net_connect_st_finish);
-    return SILC_FSM_CONTINUE;
+    SILC_FSM_CONTINUE;
   }
 
   /** Connection created */
@@ -627,7 +655,7 @@ SILC_FSM_STATE(silc_net_connect_st_stream)
   if (conn->aborted) {
     /** Aborted */
     silc_fsm_next(fsm, silc_net_connect_st_finish);
-    return SILC_FSM_CONTINUE;
+    SILC_FSM_CONTINUE;
   }
 
   if (conn->stream_status != SILC_SOCKET_OK) {
@@ -639,7 +667,7 @@ SILC_FSM_STATE(silc_net_connect_st_stream)
     else
       conn->status = SILC_NET_ERROR;
     silc_fsm_next(fsm, silc_net_connect_st_finish);
-    return SILC_FSM_CONTINUE;
+    SILC_FSM_CONTINUE;
   }
 
   /* Set stream information */
@@ -651,7 +679,7 @@ SILC_FSM_STATE(silc_net_connect_st_stream)
   SILC_LOG_DEBUG(("Connected successfully"));
   conn->status = SILC_NET_OK;
   silc_fsm_next(fsm, silc_net_connect_st_finish);
-  return SILC_FSM_CONTINUE;
+  SILC_FSM_CONTINUE;
 }
 
 SILC_FSM_STATE(silc_net_connect_st_finish)
@@ -667,7 +695,7 @@ SILC_FSM_STATE(silc_net_connect_st_finish)
       silc_async_free(conn->sop);
   }
 
-  return SILC_FSM_FINISH;
+  SILC_FSM_FINISH;
 }
 
 static void silc_net_connect_abort(SilcAsyncOperation op, void *context)
@@ -715,6 +743,7 @@ SilcAsyncOperation silc_net_tcp_connect(const char *local_ip_addr,
   /* Start async operation */
   conn->op = silc_async_alloc(silc_net_connect_abort, NULL, conn);
   if (!conn->op) {
+    silc_free(conn);
     callback(SILC_NET_NO_MEMORY, NULL, context);
     return NULL;
   }
@@ -723,6 +752,9 @@ SilcAsyncOperation silc_net_tcp_connect(const char *local_ip_addr,
     conn->local_ip = strdup(local_ip_addr);
   conn->remote = strdup(remote_ip_addr);
   if (!conn->remote) {
+    silc_async_free(conn->op);
+    silc_free(conn->local_ip);
+    silc_free(conn);
     callback(SILC_NET_NO_MEMORY, NULL, context);
     return NULL;
   }
@@ -747,9 +779,9 @@ void silc_net_close_connection(int sock)
 
 /* Set's the socket to non-blocking mode. */
 
-int silc_net_set_socket_nonblock(int sock)
+int silc_net_set_socket_nonblock(SilcSocket sock)
 {
-  return fcntl(sock, F_SETFL, fcntl(sock, F_GETFL, 0) | O_NONBLOCK);
+  return fcntl((int)sock, F_SETFL, fcntl(sock, F_GETFL, 0) | O_NONBLOCK);
 }
 
 /* Converts the IP number string from numbers-and-dots notation to