Added UDP network support.
authorPekka Riikonen <priikone@silcnet.org>
Tue, 18 Jul 2006 17:07:28 +0000 (17:07 +0000)
committerPekka Riikonen <priikone@silcnet.org>
Tue, 18 Jul 2006 17:07:28 +0000 (17:07 +0000)
lib/silcutil/silcnet.h
lib/silcutil/silcnet_i.h
lib/silcutil/silcsocketstream.c
lib/silcutil/silcsocketstream.h
lib/silcutil/silcsocketstream_i.h
lib/silcutil/unix/silcunixnet.c
lib/silcutil/unix/silcunixsocketstream.c

index 08168fa31f794e90b6ffcec3e4dafcf09d175798..41a357e9217c4228014198c7d2dcf0f0c9708f60 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1997 - 2005 Pekka Riikonen
+  Copyright (C) 1997 - 2006 Pekka Riikonen
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
@@ -22,8 +22,9 @@
  * DESCRIPTION
  *
  * SILC Net API provides various network routines for applications. It
- * can be used to create TCP/IP connections and servers. Various utility
- * functions for resolving various information is also provided.
+ * can be used to create TCP/IP and UDP/IP connections and listeners.
+ * Various utility functions for resolving various information is also
+ * provided.
  *
  * On WIN32 systems the SILC Net API must initialized by calling the
  * silc_net_win32_init and uninitialized when the application ends by
 
 /* Prototypes */
 
-/****s* silcutil/SilcNetAPI/SilcNetServer
+/****s* silcutil/SilcNetAPI/SilcNetListener
  *
  * NAME
  *
- *    typedef struct SilcNetServerStruct *SilcNetServer;
+ *    typedef struct SilcNetListenerStruct *SilcNetListener;
  *
  * DESCRIPTION
  *
- *    The network server (daemon, listener, etc.) context.  This context
- *    is created with the silc_net_create_server function and destroyed
- *    with silc_net_close_server function.
+ *    The network listenr context.  This context is created with the
+ *    silc_net_create_listener function and destroyed with
+ *    silc_net_close_listener function.
  *
  ***/
-typedef struct SilcNetServerStruct *SilcNetServer;
+typedef struct SilcNetListenerStruct *SilcNetListener;
 
 /****d* silcutil/SilcNetAPI/SilcNetStatus
  *
@@ -86,64 +87,68 @@ typedef enum {
  *
  * DESCRIPTION
  *
- *    A callback function of this type is returned by silc_net_create_server
- *    and silc_net_connect_async functions.  For silc_net_create_server this
- *    callback means that new incoming connection was accepted, and the
- *    `stream' is the socket stream representing the socket connection.
+ *    A callback of this type is returned by silc_net_tcp_create_listener,
+ *    silc_net_udp_create_listener, silc_net_tcp_connect and
+ *    silc_net_udp_connect functions.  For silc_net_tcp_create_listener
+ *    and silc_net_udp_create_listener this callback means that new incoming
+ *    connection was accepted, and the `stream' is the socket stream
+ *    representing the socket connection.
  *
- *    For silc_net_connect_async this means that we have connected to the
- *    remote host and the `stream' is the socket stream for the socket
- *    connection.  The SILC Stream API (such as silc_stream_read, etc.)
- *    can be used to read and write to the stream.  The created stream
- *    is socket stream so various SilcSocketStream API functions can be
- *    used with the `stream'.
+ *    For silc_net_tcp_connect and silc_net_udp_connect this means that we
+ *    have connected to the remote host and the `stream' is the socket
+ *    stream for the socket connection.  The SILC Stream API (such as
+ *    silc_stream_read, etc.) can be used to read and write to the stream.
+ *    The created stream is socket stream so various SilcSocketStream API
+ *    functions can be used with the `stream'.
  *
  ***/
 typedef void (*SilcNetCallback)(SilcNetStatus status,
                                SilcStream stream, void *context);
 
-/****f* silcutil/SilcNetAPI/silc_net_create_server
+/****f* silcutil/SilcNetAPI/silc_net_tcp_create_listener
  *
  * SYNOPSIS
  *
- *    SilcNetServer
- *    silc_net_create_server(const char **local_ip_addr,
- *                           SilcUInt32 local_ip_count,
- *                           int port, SilcBool require_fqdn,
- *                           SilcSchedule schedule,
- *                           SilcNetCallback callback, void *context);
+ *    SilcNetListener
+ *    silc_net_tcp_create_listener(const char **local_ip_addr,
+ *                                 SilcUInt32 local_ip_count,
+ *                                 int port, SilcBool require_fqdn,
+ *                                 SilcSchedule schedule,
+ *                                 SilcNetCallback callback, void *context);
  *
  * DESCRIPTION
  *
- *    This function creates server or daemon or listener etc.  This is used
- *    to create network listener for incoming connections, and `callback'
- *    will be called everytime new connection is received.  If `local_ip_addr'
- *    is NULL any address is used.  If provided it can be used bind the
- *    server to `local_ip_count' many IP addresses provided in `local_ip_addr'
- *    table.  On success returns the SilcNetServer context, or NULL on error.
- *    If `require_fqdn' is TRUE the server will require that the incoming
+ *    This function creates TCP listener etc.  This is used to create network
+ *    listener for incoming connections, and `callback' will be called
+ *    everytime new connection is received.  If `local_ip_addr' is NULL any
+ *    address is used.  If provided it can be used bind the listener to
+ *    `local_ip_count' many IP addresses provided in `local_ip_addr' table.
+ *    On success returns the SilcNetListener context, or NULL on error.
+ *    If `require_fqdn' is TRUE the listener will require that the incoming
  *    connection has FQDN to be able to connect.
  *
  ***/
-SilcNetServer
-silc_net_create_server(const char **local_ip_addr, SilcUInt32 local_ip_count,
-                      int port, SilcBool require_fqdn, SilcSchedule schedule,
-                      SilcNetCallback callback, void *context);
+SilcNetListener
+silc_net_tcp_create_listener(const char **local_ip_addr,
+                            SilcUInt32 local_ip_count,
+                            int port, SilcBool require_fqdn,
+                            SilcSchedule schedule,
+                            SilcNetCallback callback, void *context);
 
-/****f* silcutil/SilcNetAPI/silc_net_close_server
+/****f* silcutil/SilcNetAPI/silc_net_close_listener
  *
  * SYNOPSIS
  *
- *    void silc_net_close_server(SilcNetServer server);
+ *    void silc_net_close_listener(SilcNetListener listener);
  *
  * DESCRIPTION
  *
- *    Closes the network server listener indicated by `server'.
+ *    Closes the network listener indicated by `listener'.
  *
  ***/
-void silc_net_close_server(SilcNetServer server);
+void silc_net_close_listener(SilcNetListener listener);
 
-/****f* silcutil/SilcNetAPI/silc_net_connect
+/****f* silcutil/SilcNetAPI/silc_net_tcp_connect
  *
  * SYNOPSIS
  *
@@ -179,12 +184,96 @@ SilcAsyncOperation silc_net_tcp_connect(const char *local_ip_addr,
                                        SilcNetCallback callback,
                                        void *context);
 
-SilcAsyncOperation silc_net_udp_connect(const char *local_ip_addr,
-                                       const char *remote_ip_addr,
-                                       int remote_port,
-                                       SilcSchedule schedule,
-                                       SilcNetCallback callback,
-                                       void *context);
+/****f* silcutil/SilcNetAPI/silc_net_udp_connect
+ *
+ * SYNOPSIS
+ *
+ *    SilcStream
+ *    silc_net_udp_connect(const char *local_ip_addr, int local_port,
+ *                         const char *remote_ip_addr, int remote_port,
+ *                         SilcSchedule schedule);
+ *
+ * DESCRIPTION
+ *
+ *    This function creates UDP stream.  The UDP stream is bound to the
+ *    `local_ip_addr' if it is specified.  The `local_port' must always be
+ *    specified.  If the `remote_ip_addr' and `remote_port' is also provided,
+ *    packets may be sent to that address using silc_stream_write function
+ *    and packets may be received using silc_stream_read function.
+ *
+ *    If the remote address is not provided then packets may only be received
+ *    by using silc_net_udp_receive and sent only by using the function
+ *    silc_net_udp_send.
+ *
+ *    To receive packets the silc_stream_set_notifier must be called for the
+ *    returned SilcStream.  The packets are always received in the notifier
+ *    callback when the SILC_STREAM_CAN_READ is returned to the callback
+ *    To read the packet use silc_stream_read if the remote address was
+ *    provided, and silc_net_udp_receive if it was not.
+ *
+ * EXAMPLE
+ *
+ *    SilcStream udpstream;
+ *
+ *    // Create UDP stream and prepare to receive packets
+ *    udpstream = silc_net_udp_connect("10.2.1.7", 5000,
+ *                                     "10.2.1.100, 5000, schedule);
+ *    silc_stream_set_notifier(udpstream, schedule, receive_callback, context);
+ *
+ *    // Send packet to remote host
+ *    silc_stream_write(udpstream, data, data_len);
+ *
+ ***/
+SilcStream
+silc_net_udp_connect(const char *local_ip_addr, int local_port,
+                    const char *remote_ip_addr, int remote_port,
+                    SilcSchedule schedule);
+
+/****f* silcutil/SilcNetAPI/silc_net_udp_receive
+ *
+ * SYNOPSIS
+ *
+ *    int
+ *    silc_net_udp_receive(SilcStream stream, char *remote_ip_addr,
+ *                         SilcUInt32 remote_ip_addr_size, int *remote_port,
+ *                         unsigned char *ret_data, SilcUInt32 data_size)
+ *
+ * DESCRIPTION
+ *
+ *    Receive a UDP packet from the `stream'.  The IP address and port of
+ *    the sender is returned into `remote_ip_addr' buffer and `remote_port'
+ *    pointer.  The packet data is returned into the `ret_data' buffer.
+ *
+ *    Returns the length of the packet, or -1 on error or 0 in case of EOF.
+ *
+ ***/
+int silc_net_udp_receive(SilcStream stream, char *remote_ip_addr,
+                        SilcUInt32 remote_ip_addr_size, int *remote_port,
+                        unsigned char *ret_data, SilcUInt32 data_size);
+
+/****f* silcutil/SilcNetAPI/silc_net_udp_send
+ *
+ * SYNOPSIS
+ *
+ *    void silc_net_udp_send(SilcStream stream,
+ *                           const char *remote_ip_addr, int remote_port,
+ *                           const unsigned char *data, SilcUInt32 data_len);
+ *
+ * DESCRIPTION
+ *
+ *    Sends an UDP packet to remote host `remote_ip_addr' on `remote_port'.
+ *    This may be used with UDP streams that are not connected to any
+ *    specific remote host.  With those stream silc_stream_write cannot be
+ *    used.  In those cases, this function must be used.  This may also be
+ *    used even if the stream is connected.
+ *
+ *    This function always succeeds, however there is no guarantee that the
+ *    packet is delivered, as UDP is unreliable transport protocol.
+ *
+ ***/
+void silc_net_udp_send(SilcStream stream,
+                      const char *remote_ip_addr, int remote_port,
+                      const unsigned char *data, SilcUInt32 data_len);
 
 /****f* silcutil/SilcNetAPI/silc_net_close_connection
  *
@@ -344,8 +433,8 @@ typedef void (*SilcNetResolveCallback)(const char *result, void *context);
  *    address also.
  *
  ***/
-SilcBool silc_net_gethostbyname(const char *name, SilcBool prefer_ipv6, char *address,
-                           SilcUInt32 address_len);
+SilcBool silc_net_gethostbyname(const char *name, SilcBool prefer_ipv6,
+                               char *address, SilcUInt32 address_len);
 
 /****f* silcutil/SilcNetAPI/silc_net_gethostbyname_async
  *
@@ -390,7 +479,8 @@ void silc_net_gethostbyname_async(const char *name,
  *    This is synchronous function and will block the calling process.
  *
  ***/
-SilcBool silc_net_gethostbyaddr(const char *addr, char *name, SilcUInt32 name_len);
+SilcBool silc_net_gethostbyaddr(const char *addr, char *name,
+                               SilcUInt32 name_len);
 
 /****f* silcutil/SilcNetAPI/silc_net_gethostbyaddr_async
  *
@@ -418,7 +508,8 @@ void silc_net_gethostbyaddr_async(const char *addr,
  *
  * SYNOPSIS
  *
- *    SilcBool silc_net_check_host_by_sock(int sock, char **hostname, char **ip);
+ *    SilcBool silc_net_check_host_by_sock(int sock, char **hostname,
+ *                                         char **ip);
  *
  * DESCRIPTION
  *
@@ -432,7 +523,8 @@ SilcBool silc_net_check_host_by_sock(int sock, char **hostname, char **ip);
  *
  * SYNOPSIS
  *
- *    SilcBool silc_net_check_local_by_sock(int sock, char **hostname, char **ip);
+ *    SilcBool silc_net_check_local_by_sock(int sock, char **hostname,
+ *                                          char **ip);
  *
  * DESCRIPTION
  *
index 0dce8484989cd9c60cff9f8f21b06c60c8de7bd9..1da16a97e016492b98408163ce2c80419697e4a4 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 2005 Pekka Riikonen
+  Copyright (C) 2005 - 2006 Pekka Riikonen
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
@@ -24,8 +24,8 @@
 #error "Do not include this header directly"
 #endif
 
-/* Net server context */
-struct SilcNetServerStruct {
+/* Net listenrr context */
+struct SilcNetListenerStruct {
   SilcSchedule schedule;
   SilcNetCallback callback;
   void *context;
index 39adeb13c9bffabf91ea19f00934d2e20c156a86..b599dabf732f46664ab32fae32f67f68a864dff5 100644 (file)
@@ -24,6 +24,7 @@
 #define SILC_IS_SOCKET_STREAM(s) (s->ops == &silc_socket_stream_ops)
 
 const SilcStreamOps silc_socket_stream_ops;
+const SilcStreamOps silc_socket_udp_stream_ops;
 
 /* Platform specific functions */
 int silc_socket_stream_read(SilcStream stream, unsigned char *buf,
@@ -32,6 +33,10 @@ int silc_socket_stream_write(SilcStream stream, const unsigned char *data,
                             SilcUInt32 data_len);
 SilcBool silc_socket_stream_close(SilcStream stream);
 void silc_socket_stream_destroy(SilcStream stream);
+int silc_socket_udp_stream_read(SilcStream stream, unsigned char *buf,
+                               SilcUInt32 buf_len);
+int silc_socket_udp_stream_write(SilcStream stream, const unsigned char *data,
+                                SilcUInt32 data_len);
 
 /* Internal async host lookup context. */
 typedef struct {
@@ -161,13 +166,14 @@ static void silc_socket_host_lookup_abort(SilcAsyncOperation op,
 
 /******************************* Public API *********************************/
 
-/* Creates socket stream */
+/* Creates TCP socket stream */
 
 SilcAsyncOperation
-silc_socket_stream_create(int sock, SilcBool lookup, SilcBool require_fqdn,
-                         SilcSchedule schedule,
-                         SilcSocketStreamCallback callback,
-                         void *context)
+silc_socket_tcp_stream_create(int sock, SilcBool lookup,
+                             SilcBool require_fqdn,
+                             SilcSchedule schedule,
+                             SilcSocketStreamCallback callback,
+                             void *context)
 {
   SilcSocketStream stream;
   SilcSocketHostLookup l;
@@ -179,7 +185,7 @@ silc_socket_stream_create(int sock, SilcBool lookup, SilcBool require_fqdn,
     return NULL;
   }
 
-  SILC_LOG_DEBUG(("Creating new socket stream %p", stream));
+  SILC_LOG_DEBUG(("Creating TCP socket stream %p", stream));
 
   stream->ops = &silc_socket_stream_ops;
   stream->sock = sock;
@@ -223,6 +229,27 @@ silc_socket_stream_create(int sock, SilcBool lookup, SilcBool require_fqdn,
   }
 }
 
+/* Creates UDP socket stream */
+
+SilcStream silc_socket_udp_stream_create(int sock, SilcBool ipv6,
+                                        SilcSchedule schedule)
+{
+  SilcSocketStream stream;
+
+  stream = silc_calloc(1, sizeof(*stream));
+  if (!stream)
+    return NULL;
+
+  SILC_LOG_DEBUG(("Creating UDP socket stream %p", stream));
+
+  stream->ops = &silc_socket_udp_stream_ops;
+  stream->sock = sock;
+  stream->schedule = schedule;
+  stream->ipv6 = ipv6;
+
+  return (SilcStream)stream;
+}
+
 /* Returns socket stream information */
 
 SilcBool silc_socket_stream_get_info(SilcStream stream,
@@ -438,3 +465,12 @@ const SilcStreamOps silc_socket_stream_ops =
   silc_socket_stream_notifier,
   silc_socket_stream_get_schedule,
 };
+const SilcStreamOps silc_socket_udp_stream_ops =
+{
+  silc_socket_udp_stream_read,
+  silc_socket_udp_stream_write,
+  silc_socket_stream_close,
+  silc_socket_stream_destroy,
+  silc_socket_stream_notifier,
+  silc_socket_stream_get_schedule,
+};
index 08dbbcc1ebb20b5ac69d5ee305db02c2d1a37223..8aa084d9cfc694a73f6b958808cd9401daa8125e 100644 (file)
@@ -80,20 +80,20 @@ typedef enum {
 typedef void (*SilcSocketStreamCallback)(SilcSocketStreamStatus status,
                                         SilcStream stream, void *context);
 
-/****f* silcutil/SilcSocketStreamAPI/silc_socket_stream_create
+/****f* silcutil/SilcSocketStreamAPI/silc_socket_tcp_stream_create
  *
  * SYNOPSIS
  *
  *    SilcAsyncOperation
- *    silc_socket_stream_create(int sock, SilcBool lookup,
- *                              SilcBool require_fqdn,
- *                              SilcSchedule schedule,
- *                              SilcSocketStreamCallback callback,
- *                              void *context);
+ *    silc_socket_tcp_stream_create(int sock, SilcBool lookup,
+ *                                  SilcBool require_fqdn,
+ *                                  SilcSchedule schedule,
+ *                                  SilcSocketStreamCallback callback,
+ *                                  void *context);
  *
  * DESCRIPTION
  *
- *    Creates new socket stream of the socket connection indicated by `sock'.
+ *    Creates TCP socket stream of the TCP connection indicated by `sock'.
  *    The stream can be destroyed by calling the silc_stream_destroy.  Data
  *    can be sent and received from the stream by calling silc_stream_write
  *    and silc_stream_read.  The creation process is asynchronous since
@@ -111,25 +111,40 @@ typedef void (*SilcSocketStreamCallback)(SilcSocketStreamStatus status,
  *
  ***/
 SilcAsyncOperation
-silc_socket_stream_create(int sock, SilcBool lookup,
-                         SilcBool require_fqdn,
-                         SilcSchedule schedule,
-                         SilcSocketStreamCallback callback,
-                         void *context);
-
-SilcAsyncOperation
 silc_socket_tcp_stream_create(int sock, SilcBool lookup,
                              SilcBool require_fqdn,
                              SilcSchedule schedule,
                              SilcSocketStreamCallback callback,
                              void *context);
 
-SilcAsyncOperation
-silc_socket_udp_stream_create(int sock, SilcBool lookup,
-                             SilcBool require_fqdn,
-                             SilcSchedule schedule,
-                             SilcSocketStreamCallback callback,
-                             void *context);
+/****f* silcutil/SilcSocketStreamAPI/silc_socket_udp_stream_create
+ *
+ * SYNOPSIS
+ *
+ *    SilcStream silc_socket_udp_stream_create(int sock, SilcBool ipv6,
+ *                                             SilcSchedule schedule);
+ *
+ * DESCRIPTION
+ *
+ *    Creates UDP socket stream of the UDP connection indicated by `sock'.
+ *    The stream can be destroyed by calling the silc_stream_destroy.
+ *
+ *    Note that, UDP packets may be read only through the notifier
+ *    callback (see silc_stream_set_notifier), when SILC_STREAM_CAN_READ
+ *    is returned to the callback.  Because of this the notifier callback
+ *    must be set.
+ *
+ *    Note that, UDP packet sending using silc_stream_write and receiving
+ *    with silc_stream_read works only if the `sock' is a UDP socket in a
+ *    connected state.  If it is not the silc_net_udp_send function and
+ *    silc_net_udp_receive functions must be used.  The SILC_STREAM_CAN_WRITE
+ *    is never returned to the notifier callback.
+ *
+ *    This function returns the created SilcStream or NULL on error.
+ *
+ ***/
+SilcStream silc_socket_udp_stream_create(int sock, SilcBool ipv6,
+                                        SilcSchedule schedule);
 
 /****f* silcutil/SilcSocketStreamAPI/silc_socket_stream_get_info
  *
index 7a4998ccfbcf8488224b5c9e4ba592e1d6e60328..46c5ef2921ab8ed2c8db94515e5ce51ebbb7f601 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 2005 Pekka Riikonen
+  Copyright (C) 2005 - 2006 Pekka Riikonen
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
@@ -52,6 +52,7 @@ struct SilcSocketStreamStruct {
   SilcSocketQos qos;
   SilcStreamNotifier notifier;
   void *notifier_context;
+  unsigned int ipv6      : 1;
 };
 
 #endif /* SILCSOCKETSTREAM_I_H */
index 1d3364a5568158ead8997c8a166a5f6ae53d4ab6..c6a020d7961948fa742d74905d4f8536f00ece47 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1997 - 2005 Pekka Riikonen
+  Copyright (C) 1997 - 2006 Pekka Riikonen
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
@@ -37,7 +37,7 @@ typedef union {
 } SilcSockaddr;
 
 static SilcBool silc_net_set_sockaddr(SilcSockaddr *addr, const char *ip_addr,
-                                 int port)
+                                     int port)
 {
   int len;
 
@@ -86,19 +86,19 @@ static SilcBool silc_net_set_sockaddr(SilcSockaddr *addr, const char *ip_addr,
 static void silc_net_accept_stream(SilcSocketStreamStatus status,
                                   SilcStream stream, void *context)
 {
-  SilcNetServer server = context;
+  SilcNetListener listener = context;
 
   if (status != SILC_SOCKET_OK)
     return;
 
-  server->callback(SILC_NET_OK, stream, server->context);
+  listener->callback(SILC_NET_OK, stream, listener->context);
 }
 
 /* Accept incoming connection and notify upper layer */
 
 SILC_TASK_CALLBACK(silc_net_accept)
 {
-  SilcNetServer server = context;
+  SilcNetListener listener = context;
   int sock;
 
   SILC_LOG_DEBUG(("Accepting new connection"));
@@ -112,45 +112,47 @@ SILC_TASK_CALLBACK(silc_net_accept)
   silc_net_set_socket_opt(sock, SOL_SOCKET, SO_REUSEADDR, 1);
 
   /* Create socket stream */
-  silc_socket_stream_create(sock, TRUE, server->require_fqdn, schedule,
-                           silc_net_accept_stream, server);
+  silc_socket_tcp_stream_create(sock, TRUE, listener->require_fqdn, schedule,
+                               silc_net_accept_stream, listener);
 }
 
-/* Create network listener */
+/* Create TCP network listener */
 
-SilcNetServer
-silc_net_create_server(const char **local_ip_addr, SilcUInt32 local_ip_count,
-                      int port, SilcBool require_fqdn, SilcSchedule schedule,
-                      SilcNetCallback callback, void *context)
+SilcNetListener
+silc_net_tcp_create_listener(const char **local_ip_addr,
+                            SilcUInt32 local_ip_count,
+                            int port, SilcBool require_fqdn,
+                            SilcSchedule schedule,
+                            SilcNetCallback callback, void *context)
 {
-  SilcNetServer netserver = NULL;
+  SilcNetListener listener = NULL;
   SilcSockaddr server;
   int i, sock, rval;
   const char *ipany = "0.0.0.0";
 
-  SILC_LOG_DEBUG(("Creating new network listener"));
+  SILC_LOG_DEBUG(("Creating TCP listener"));
 
   if (port < 1 || !schedule || !callback)
     goto err;
 
-  netserver = silc_calloc(1, sizeof(*netserver));
-  if (!netserver) {
+  listener = silc_calloc(1, sizeof(*listener));
+  if (!listener) {
     callback(SILC_NET_NO_MEMORY, NULL, context);
     return NULL;
   }
-  netserver->schedule = schedule;
-  netserver->callback = callback;
-  netserver->context = context;
+  listener->schedule = schedule;
+  listener->callback = callback;
+  listener->context = context;
 
   if (local_ip_count > 0) {
-    netserver->socks = silc_calloc(local_ip_count, sizeof(*netserver->socks));
-    if (!netserver->socks) {
+    listener->socks = silc_calloc(local_ip_count, sizeof(*listener->socks));
+    if (!listener->socks) {
       callback(SILC_NET_NO_MEMORY, NULL, context);
       return NULL;
     }
   } else {
-    netserver->socks = silc_calloc(1, sizeof(*netserver->socks));
-    if (!netserver->socks) {
+    listener->socks = silc_calloc(1, sizeof(*listener->socks));
+    if (!listener->socks) {
       callback(SILC_NET_NO_MEMORY, NULL, context);
       return NULL;
     }
@@ -183,7 +185,7 @@ silc_net_create_server(const char **local_ip_addr, SilcUInt32 local_ip_count,
       goto err;
     }
 
-    /* Bind the server socket */
+    /* Bind the listener socket */
     rval = bind(sock, &server.sa, SIZEOF_SOCKADDR(server));
     if (rval < 0) {
       SILC_LOG_DEBUG(("Cannot bind socket: %s", strerror(errno)));
@@ -201,39 +203,220 @@ silc_net_create_server(const char **local_ip_addr, SilcUInt32 local_ip_count,
     silc_net_set_socket_nonblock(sock);
 
     /* Schedule for incoming connections */
-    silc_schedule_task_add_fd(schedule, sock, silc_net_accept, netserver);
+    silc_schedule_task_add_fd(schedule, sock, silc_net_accept, listener);
 
-    SILC_LOG_DEBUG(("Network listener created, fd=%d", sock));
-    netserver->socks[i] = sock;
-    netserver->socks_count++;
+    SILC_LOG_DEBUG(("TCP listener created, fd=%d", sock));
+    listener->socks[i] = sock;
+    listener->socks_count++;
   }
 
-  return netserver;
+  return listener;
 
  err:
   if (callback)
     callback(SILC_NET_ERROR, NULL, context);
-  if (netserver)
-    silc_net_close_server(netserver);
+  if (listener)
+    silc_net_close_listener(listener);
   return NULL;
 }
 
 /* Close network listener */
 
-void silc_net_close_server(SilcNetServer server)
+void silc_net_close_listener(SilcNetListener listener)
 {
   int i;
 
   SILC_LOG_DEBUG(("Closing network listener"));
 
-  for (i = 0; i < server->socks_count; i++) {
-    silc_schedule_task_del_by_fd(server->schedule, server->socks[i]);
-    shutdown(server->socks[i], 2);
-    close(server->socks[i]);
+  for (i = 0; i < listener->socks_count; i++) {
+    silc_schedule_task_del_by_fd(listener->schedule, listener->socks[i]);
+    shutdown(listener->socks[i], 2);
+    close(listener->socks[i]);
   }
 
-  silc_free(server->socks);
-  silc_free(server);
+  silc_free(listener->socks);
+  silc_free(listener);
+}
+
+/* Create UDP stream */
+
+SilcStream
+silc_net_udp_connect(const char *local_ip_addr, int local_port,
+                    const char *remote_ip_addr, int remote_port,
+                    SilcSchedule schedule)
+{
+  SilcStream stream;
+  SilcSockaddr server;
+  int sock = -1, rval;
+  const char *ipany = "0.0.0.0";
+
+  SILC_LOG_DEBUG(("Creating UDP stream"));
+
+  if (local_port < 1 || !schedule)
+    goto err;
+
+  /* Bind to local addresses */
+  SILC_LOG_DEBUG(("Binding to local address %s",
+                 local_ip_addr ? local_ip_addr : ipany));
+
+  /* Set sockaddr for server */
+  if (!silc_net_set_sockaddr(&server, local_ip_addr ? local_ip_addr : ipany,
+                            local_port))
+    goto err;
+
+  /* Create the socket */
+  sock = socket(server.sin.sin_family, SOCK_DGRAM, 0);
+  if (sock < 0) {
+    SILC_LOG_ERROR(("Cannot create socket: %s", strerror(errno)));
+    goto err;
+  }
+
+  /* Set the socket options */
+  rval = silc_net_set_socket_opt(sock, SOL_SOCKET, SO_REUSEADDR, 1);
+  if (rval < 0) {
+    SILC_LOG_ERROR(("Cannot set socket options: %s", strerror(errno)));
+    goto err;
+  }
+#ifdef SO_REUSEPORT
+  rval = silc_net_set_socket_opt(sock, SOL_SOCKET, SO_REUSEPORT, 1);
+  if (rval < 0) {
+    SILC_LOG_ERROR(("Cannot set socket options: %s", strerror(errno)));
+    goto err;
+  }
+#endif /* SO_REUSEPORT */
+
+  /* Bind the listener socket */
+  rval = bind(sock, &server.sa, SIZEOF_SOCKADDR(server));
+  if (rval < 0) {
+    SILC_LOG_DEBUG(("Cannot bind socket: %s", strerror(errno)));
+    goto err;
+  }
+
+  /* Set socket to non-blocking mode */
+  silc_net_set_socket_nonblock(sock);
+
+  /* Set to connected state if remote address is provided. */
+  if (remote_ip_addr && remote_port) {
+    if (!silc_net_set_sockaddr(&server, remote_ip_addr, remote_port))
+      goto err;
+
+    rval = connect(sock, &server.sa, SIZEOF_SOCKADDR(server));
+    if (rval < 0) {
+      SILC_LOG_DEBUG(("Cannot connect UDP stream: %s", strerror(errno)));
+      goto err;
+    }
+  }
+
+  /* Set send and receive buffer size */
+#ifdef SO_SNDBUF
+  rval = silc_net_set_socket_opt(sock, SOL_SOCKET, SO_SNDBUF, 65535);
+  if (rval < 0) {
+    SILC_LOG_ERROR(("Cannot set socket options: %s", strerror(errno)));
+    goto err;
+  }
+#endif /* SO_SNDBUF */
+#ifdef SO_RCVBUF
+  rval = silc_net_set_socket_opt(sock, SOL_SOCKET, SO_RCVBUF, 65535);
+  if (rval < 0) {
+    SILC_LOG_ERROR(("Cannot set socket options: %s", strerror(errno)));
+    goto err;
+  }
+#endif /* SO_RCVBUF */
+
+  /* Encapsulate into socket stream */
+  stream =
+    silc_socket_udp_stream_create(sock, local_ip_addr ?
+                                 silc_net_is_ip6(local_ip_addr) : FALSE,
+                                 schedule);
+  if (!stream)
+    goto err;
+
+  SILC_LOG_DEBUG(("UDP stream created, fd=%d", sock));
+  return stream;
+
+ err:
+  if (sock != -1)
+    close(sock);
+  return NULL;
+}
+
+/* Receive UDP packet */
+
+int silc_net_udp_receive(SilcStream stream, char *remote_ip_addr,
+                        SilcUInt32 remote_ip_addr_size, int *remote_port,
+                        unsigned char *ret_data, SilcUInt32 data_size)
+{
+  SilcSocketStream sock = stream;
+  SilcSockaddr s;
+  struct sockaddr *from;
+  int len, flen;
+
+  SILC_LOG_DEBUG(("Reading data from UDP socket %d", sock->sock));
+
+  if (remote_ip_addr && remote_port) {
+    if (sock->ipv6) {
+      from = (struct sockaddr *)&s.sin6;
+      flen = sizeof(s.sin6);
+    } else {
+      from = (struct sockaddr *)&s.sin;
+      flen = sizeof(s.sin);
+    }
+    len = recvfrom(sock->sock, ret_data, data_size, 0, from, &flen);
+  } else
+    len = recv(sock->sock, ret_data, data_size, 0);
+
+  if (len < 0) {
+    if (errno == EAGAIN || errno == EINTR) {
+      SILC_LOG_DEBUG(("Could not read immediately, will do it later"));
+      silc_schedule_set_listen_fd(sock->schedule, sock->sock,
+                                 SILC_TASK_READ, FALSE);
+      return -1;
+    }
+    SILC_LOG_DEBUG(("Cannot read from UDP socket: %d:%s",
+                   sock->sock, strerror(errno)));
+    silc_schedule_unset_listen_fd(sock->schedule, sock->sock);
+    sock->sock_error = errno;
+    return -2;
+  }
+
+  SILC_LOG_DEBUG(("Read %d bytes", len));
+
+  if (!len)
+    silc_schedule_unset_listen_fd(sock->schedule, sock->sock);
+
+  /* Return remote address */
+  if (remote_ip_addr && remote_port) {
+    if (sock->ipv6) {
+      *remote_port = ntohs(s.sin6.sin6_port);
+      inet_ntop(AF_INET6, &s.sin6.sin6_addr, remote_ip_addr,
+               remote_ip_addr_size);
+    } else {
+      *remote_port = ntohs(s.sin.sin_port);
+      inet_ntop(AF_INET, &s.sin.sin_addr, remote_ip_addr,
+               remote_ip_addr_size);
+    }
+  }
+
+  return len;
+}
+
+/* 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)
+{
+  SilcSocketStream sock = stream;
+  SilcSockaddr remote;
+
+  SILC_LOG_DEBUG(("Writing data to UDP socket %d", sock->sock));
+
+  /* Set sockaddr for server */
+  if (!silc_net_set_sockaddr(&remote, remote_ip_addr, remote_port))
+    return;
+
+  /* Send */
+  sendto(sock->sock, data, data_len, 0, &remote.sa, SIZEOF_SOCKADDR(remote));
 }
 
 /* Asynchronous TCP/IP connecting */
@@ -431,7 +614,7 @@ SILC_FSM_STATE(silc_net_connect_st_connected)
 
   /** Connection created */
   silc_fsm_next(fsm, silc_net_connect_st_stream);
-  SILC_FSM_CALL((conn->sop = silc_socket_stream_create(
+  SILC_FSM_CALL((conn->sop = silc_socket_tcp_stream_create(
                                     conn->sock, FALSE, FALSE,
                                     schedule,
                                     silc_net_connect_wait_stream, conn)));
index f409689a1ec3cde115e96c21583ae296fb13843a..1eded3d36b351e8a76a0c49f2fc9bd7363ad8b93 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1997 - 2005 Pekka Riikonen
+  Copyright (C) 1997 - 2006 Pekka Riikonen
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
@@ -174,11 +174,40 @@ int silc_socket_stream_write(SilcStream stream, const unsigned char *data,
   return ret;
 }
 
+/* Receive UDP packet.  QoS is not supported. */
+
+int silc_socket_udp_stream_read(SilcStream stream, unsigned char *buf,
+                               SilcUInt32 buf_len)
+{
+  return silc_net_udp_receive(stream, NULL, 0, NULL, buf, buf_len);
+}
+
+/* Send UDP packet.  This always succeeds. */
+
+int silc_socket_udp_stream_write(SilcStream stream, const unsigned char *data,
+                                SilcUInt32 data_len)
+{
+  SilcSocketStream sock = stream;
+  int ret;
+
+  SILC_LOG_DEBUG(("Writing data to UDP socket %d", sock->sock));
+
+  ret = send(sock->sock, data, data_len, 0);
+  if (ret < 0) {
+    /* Ignore error and return success */
+    SILC_LOG_DEBUG(("Cannot write to UDP socket: %s", strerror(errno)));
+    return data_len;
+  }
+
+  SILC_LOG_DEBUG(("Wrote data %d bytes", ret));
+  return ret;
+}
+
 #if 0
 /* Returns human readable socket error message */
 
 SilcBool silc_socket_get_error(SilcStream sock, char *error,
-                          SilcUInt32 error_len)
+                              SilcUInt32 error_len)
 {
   char *err;