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
* 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
*
*
* 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
*
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
*
* 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
*
* 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
*
*
* 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
*
*
* 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
*
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
#error "Do not include this header directly"
#endif
-/* Net server context */
-struct SilcNetServerStruct {
+/* Net listenrr context */
+struct SilcNetListenerStruct {
SilcSchedule schedule;
SilcNetCallback callback;
void *context;
#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,
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 {
/******************************* 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;
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;
}
}
+/* 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,
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,
+};
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
*
***/
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
*
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
SilcSocketQos qos;
SilcStreamNotifier notifier;
void *notifier_context;
+ unsigned int ipv6 : 1;
};
#endif /* SILCSOCKETSTREAM_I_H */
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
} SilcSockaddr;
static SilcBool silc_net_set_sockaddr(SilcSockaddr *addr, const char *ip_addr,
- int port)
+ int port)
{
int len;
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"));
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;
}
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)));
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 */
/** 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)));
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
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;