From: Pekka Riikonen Date: Tue, 6 Nov 2007 15:30:31 +0000 (+0000) Subject: Added silc_net_tcp_create_listener2 X-Git-Tag: 1.2.beta1~88 X-Git-Url: http://git.silcnet.org/gitweb/?p=crypto.git;a=commitdiff_plain;h=42cc827e60ddf50ea201e8984f8dd0e57372170e Added silc_net_tcp_create_listener2 --- diff --git a/lib/silcutil/silcnet.h b/lib/silcutil/silcnet.h index f2e040b6..ffd5bfc3 100644 --- a/lib/silcutil/silcnet.h +++ b/lib/silcutil/silcnet.h @@ -133,6 +133,45 @@ silc_net_tcp_create_listener(const char **local_ip_addr, SilcSchedule schedule, SilcNetCallback callback, void *context); +/****f* silcutil/SilcNetAPI/silc_net_tcp_create_listener2 + * + * SYNOPSIS + * + * SilcNetListener + * silc_net_tcp_create_listener2(const char *local_ip_addr, int *ports, + * SilcUInt32 port_count, + * SilcBool ignore_port_error, + * SilcBool lookup, SilcBool require_fqdn, + * SilcSchedule schedule, + * SilcNetCallback callback, void *context); + * + * DESCRIPTION + * + * This function creates TCP listener. 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 `ports' is NULL or it contains a zero (0) port, + * operating system will define it automatically. This function can be + * used to bind to many ports at the same time. If `ignore_port_error' + * is TRUE this won't return NULL if at least one of the ports could + * be bound. Otherwise, NULL will be returned on error. + * + * If `require_fqdn' is TRUE the listener will require that the incoming + * connection has FQDN to be able to connect. If the `lookup' is TRUE + * then the incoming connection hostname will be resolved. + * + * The `callback' always delivers valid new stream. It is not called + * with an error status. + * + ***/ +SilcNetListener +silc_net_tcp_create_listener2(const char *local_ip_addr, int *ports, + SilcUInt32 port_count, + SilcBool ignore_port_error, + SilcBool lookup, SilcBool require_fqdn, + SilcSchedule schedule, + SilcNetCallback callback, void *context); + /****f* silcutil/SilcNetAPI/silc_net_listener_get_port * * SYNOPSIS @@ -145,7 +184,8 @@ silc_net_tcp_create_listener(const char **local_ip_addr, * to get the port if none was specified in silc_net_tcp_create_listener. * Returns an array of ports of size of `port_count'. The caller must * free the array with silc_free. There are as many ports in the array - * as there were IP addresses provided in silc_net_tcp_create_listener. + * as there were IP addresses provided in silc_net_tcp_create_listener, + * as there were ports provided in silc_net_tcp_create_listener2. * ***/ SilcUInt16 *silc_net_listener_get_port(SilcNetListener listener, diff --git a/lib/silcutil/symbian/silcsymbiannet.cpp b/lib/silcutil/symbian/silcsymbiannet.cpp index 69fba82e..2c2fea50 100644 --- a/lib/silcutil/symbian/silcsymbiannet.cpp +++ b/lib/silcutil/symbian/silcsymbiannet.cpp @@ -283,6 +283,153 @@ silc_net_tcp_create_listener(const char **local_ip_addr, return NULL; } +/* Create TCP listener, multiple ports */ + +SilcNetListener +silc_net_tcp_create_listener2(const char *local_ip_addr, int *ports, + SilcUInt32 port_count, + SilcBool ignore_port_error, + SilcBool lookup, SilcBool require_fqdn, + SilcSchedule schedule, + SilcNetCallback callback, void *context) +{ + SilcNetListener listener = NULL; + SilcSymbianTCPListener *l = NULL; + TInetAddr server; + TInt ret; + int i; + + SILC_LOG_DEBUG(("Creating TCP listener")); + + if (!schedule || !callback) + goto err; + + listener = (SilcNetListener)silc_calloc(1, sizeof(*listener)); + if (!listener) { + callback(SILC_NET_NO_MEMORY, NULL, context); + return NULL; + } + listener->schedule = schedule; + listener->callback = callback; + listener->context = context; + listener->require_fqdn = require_fqdn; + listener->lookup = lookup; + + if (port_count > 0) { + listener->socks = (SilcSocket *)silc_calloc(port_count, + sizeof(*listener->socks)); + if (!listener->socks) { + callback(SILC_NET_NO_MEMORY, NULL, context); + return NULL; + } + } else { + listener->socks = (SilcSocket *)silc_calloc(1, sizeof(*listener->socks)); + if (!listener->socks) { + callback(SILC_NET_NO_MEMORY, NULL, context); + return NULL; + } + + port_count = 1; + } + + /* Bind to ports */ + for (i = 0; i < port_count; i++) { + SILC_LOG_DEBUG(("Binding to local address %s:%d", + local_ip_addr ? local_ip_addr : "0.0.0.0", + ports ? ports[i] : 0)); + + l = new SilcSymbianTCPListener; + if (!l) + goto err; + + /* Connect to socket server */ + ret = l->ss.Connect(); + if (ret != KErrNone) + goto err; + +#ifdef SILC_THREADS + /* Make our socket shareable between threads */ + l->ss.ShareAuto(); +#endif /* SILC_THREADS */ + + /* Set listener address */ + if (!silc_net_set_sockaddr(&server, local_ip_addr, ports ? ports[i] : 0)) { + if (ignore_port_error) { + delete l; + continue; + } + goto err; + } + + /* Create the socket */ + ret = l->sock.Open(l->ss, KAfInet, KSockStream, KProtocolInetTcp); + if (ret != KErrNone) { + if (ignore_port_error) { + delete l; + continue; + } + SILC_LOG_ERROR(("Cannot create socket, error %d", ret)); + goto err; + } + + /* Set the socket options */ + ret = l->sock.SetOpt(KSoReuseAddr, KSolInetIp, 1); + if (ret != KErrNone) { + if (ignore_port_error) { + delete l; + continue; + } + SILC_LOG_ERROR(("Cannot set socket options, error %d", ret)); + goto err; + } + + /* Bind the listener socket */ + ret = l->sock.Bind(server); + if (ret != KErrNone) { + if (ignore_port_error) { + delete l; + continue; + } + SILC_LOG_DEBUG(("Cannot bind socket, error %d", ret)); + goto err; + } + + /* Specify that we are listenning */ + ret = l->sock.Listen(5); + if (ret != KErrNone) { + if (ignore_port_error) { + delete l; + continue; + } + SILC_LOG_ERROR(("Cannot set socket listenning, error %d", ret)); + goto err; + } + l->Listen(); + + l->listener = listener; + listener->socks[i] = (SilcSocket)l; + listener->socks_count++; + } + + if (ignore_port_error && !listener->socks_count) { + l = NULL; + goto err; + } + + SILC_LOG_DEBUG(("TCP listener created")); + + return listener; + + err: + if (l) + delete l; + if (callback) + callback(SILC_NET_ERROR, NULL, context); + if (listener) + silc_net_close_listener(listener); + return NULL; +} + /* Close network listener */ void silc_net_close_listener(SilcNetListener listener) diff --git a/lib/silcutil/tests/test_silcnet.c b/lib/silcutil/tests/test_silcnet.c index 1c7a9851..29748619 100644 --- a/lib/silcutil/tests/test_silcnet.c +++ b/lib/silcutil/tests/test_silcnet.c @@ -78,9 +78,40 @@ SILC_FSM_STATE(test_st_connected) SILC_FSM_STATE(test_st_start) { Foo f = fsm_context; + int ports[3]; + SilcUInt16 *ret_ports; + SilcUInt32 port_count; SILC_LOG_DEBUG(("test_st_start")); + SILC_LOG_DEBUG(("Creating network listener to ports 2000, 3000 and 4000")); + ports[0] = 2000; + ports[1] = 3000; + ports[2] = 4000; + f->server = silc_net_tcp_create_listener2(NULL, ports, 3, FALSE, TRUE, TRUE, + silc_fsm_get_schedule(fsm), + test_accept_connection, f); + if (!f->server) { + /** Creating network listener failed */ + SILC_LOG_DEBUG(("Listener creation failed")); + silc_fsm_next(fsm, test_st_finish); + return SILC_FSM_CONTINUE; + } + + ret_ports = silc_net_listener_get_port(f->server, &port_count); + if (!ret_ports) { + SILC_LOG_DEBUG(("Listener does not work")); + silc_fsm_next(fsm, test_st_finish); + return SILC_FSM_CONTINUE; + } + SILC_LOG_DEBUG(("Bound to port %d", ret_ports[0])); + SILC_LOG_DEBUG(("Bound to port %d", ret_ports[1])); + SILC_LOG_DEBUG(("Bound to port %d", ret_ports[2])); + silc_free(ret_ports); + + /* Close this listener and create new one */ + silc_net_close_listener(f->server); + SILC_LOG_DEBUG(("Creating network listener")); f->server = silc_net_tcp_create_listener(NULL, 0, 5000, TRUE, TRUE, silc_fsm_get_schedule(fsm), diff --git a/lib/silcutil/tests/test_silcstrutil.c b/lib/silcutil/tests/test_silcstrutil.c index d8bef756..c0235eea 100644 --- a/lib/silcutil/tests/test_silcstrutil.c +++ b/lib/silcutil/tests/test_silcstrutil.c @@ -49,12 +49,18 @@ utf8fail(28, "\xfc\x20\xfd\x20", 4); utf8fail(29, "\xf8\xf9\xfa\xfb", 4); utf8fail(30, "\xf0\x20\xf9\x20\xfa\x20\xfb\x20", 8); +char *render(void *data) +{ + char *buf = data; + return strdup(buf); +} + int main(int argc, char **argv) { SilcBool success = FALSE; unsigned char *s1, *s2, *s3, *s4; unsigned char t[16]; - char h[32 + 1]; + char h[32 + 1], str[40]; int l, opt, i; SilcUInt32 len; @@ -174,6 +180,12 @@ int main(int argc, char **argv) silc_hex2data(h, t, sizeof(t), &len); silc_data2hex(t, sizeof(t), h, sizeof(h)); + /* snprintf test */ + silc_snprintf(str, sizeof(str), "This is %@ rendered\n", + render, "automatically"); + SILC_LOG_DEBUG((str)); + SILC_LOG_DEBUG(("This too %@ rendered", render, "is automatically")); + success = TRUE; err: diff --git a/lib/silcutil/unix/silcunixnet.c b/lib/silcutil/unix/silcunixnet.c index e0befdc1..cffa2cee8 100644 --- a/lib/silcutil/unix/silcunixnet.c +++ b/lib/silcutil/unix/silcunixnet.c @@ -223,6 +223,123 @@ silc_net_tcp_create_listener(const char **local_ip_addr, return NULL; } +/* Create TCP listener, multiple ports */ + +SilcNetListener +silc_net_tcp_create_listener2(const char *local_ip_addr, int *ports, + SilcUInt32 port_count, + SilcBool ignore_port_error, + SilcBool lookup, SilcBool require_fqdn, + SilcSchedule schedule, + SilcNetCallback callback, void *context) +{ + SilcNetListener listener = NULL; + SilcSockaddr server; + int i, sock, rval; + const char *ipany = "0.0.0.0"; + + SILC_LOG_DEBUG(("Creating TCP listener")); + + if (!schedule || !callback) + goto err; + + listener = silc_calloc(1, sizeof(*listener)); + if (!listener) + return NULL; + listener->schedule = schedule; + listener->callback = callback; + listener->context = context; + listener->require_fqdn = require_fqdn; + listener->lookup = lookup; + + if (port_count > 0) { + listener->socks = silc_calloc(port_count, sizeof(*listener->socks)); + if (!listener->socks) + return NULL; + } else { + listener->socks = silc_calloc(1, sizeof(*listener->socks)); + if (!listener->socks) + return NULL; + + port_count = 1; + } + + /* Bind to ports */ + for (i = 0; i < port_count; i++) { + SILC_LOG_DEBUG(("Binding to local address %s:%d", + local_ip_addr ? local_ip_addr : ipany, + ports ? ports[i] : 0)); + + /* Set sockaddr for server */ + if (!silc_net_set_sockaddr(&server, + local_ip_addr ? local_ip_addr : ipany, + ports ? ports[i] : 0)) { + if (ignore_port_error) + continue; + goto err; + } + + /* Create the socket */ + sock = socket(server.sin.sin_family, SOCK_STREAM, 0); + if (sock < 0) { + if (ignore_port_error) + continue; + 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) { + close(sock); + if (ignore_port_error) + continue; + SILC_LOG_ERROR(("Cannot set socket options: %s", strerror(errno))); + goto err; + } + + /* Bind the listener socket */ + rval = bind(sock, &server.sa, SIZEOF_SOCKADDR(server)); + if (rval < 0) { + close(sock); + if (ignore_port_error) + continue; + SILC_LOG_ERROR(("Cannot bind socket: %s", strerror(errno))); + goto err; + } + + /* Specify that we are listenning */ + rval = listen(sock, 64); + if (rval < 0) { + close(sock); + SILC_LOG_ERROR(("Cannot set socket listenning: %s", strerror(errno))); + if (ignore_port_error) + continue; + goto err; + } + + /* Set the server socket to non-blocking mode */ + silc_net_set_socket_nonblock(sock); + + /* Schedule for incoming connections */ + silc_schedule_task_add_fd(schedule, sock, silc_net_accept, listener); + + SILC_LOG_DEBUG(("TCP listener created, fd=%d", sock)); + listener->socks[i] = sock; + listener->socks_count++; + } + + if (ignore_port_error && !listener->socks_count) + goto err; + + return listener; + + err: + if (listener) + silc_net_close_listener(listener); + return NULL; +} + /* Close network listener */ void silc_net_close_listener(SilcNetListener listener) @@ -363,8 +480,10 @@ int silc_net_udp_receive(SilcStream stream, char *remote_ip_addr, if (remote_ip_addr && remote_port) { if (sock->ipv6) { +#ifdef HAVE_IPV6 from = (struct sockaddr *)&s.sin6; flen = sizeof(s.sin6); +#endif /* HAVE_IPV6 */ } else { from = (struct sockaddr *)&s.sin; flen = sizeof(s.sin); @@ -395,9 +514,13 @@ int silc_net_udp_receive(SilcStream stream, char *remote_ip_addr, /* Return remote address */ if (remote_ip_addr && remote_port) { if (sock->ipv6) { +#ifdef HAVE_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 = 0; +#endif /* HAVE_IPV6 */ } else { *remote_port = ntohs(s.sin.sin_port); inet_ntop(AF_INET, &s.sin.sin_addr, remote_ip_addr, diff --git a/lib/silcutil/win32/silcwin32net.c b/lib/silcutil/win32/silcwin32net.c index 7d4e7339..5c4181f6 100644 --- a/lib/silcutil/win32/silcwin32net.c +++ b/lib/silcutil/win32/silcwin32net.c @@ -227,6 +227,123 @@ silc_net_tcp_create_listener(const char **local_ip_addr, return NULL; } +/* Create TCP network, multiple ports */ + +SilcNetListener +silc_net_tcp_create_listener2(const char *local_ip_addr, int *ports, + SilcUInt32 port_count, + SilcBool ignore_port_error, + SilcBool lookup, SilcBool require_fqdn, + SilcSchedule schedule, + SilcNetCallback callback, void *context) +{ + SilcNetListener listener = NULL; + SOCKET sock; + SilcSockaddr server; + int i, rval; + const char *ipany = "0.0.0.0"; + + SILC_LOG_DEBUG(("Creating TCP listener")); + + if (!schedule || !callback) + goto err; + + listener = silc_calloc(1, sizeof(*listener)); + if (!listener) + return NULL; + listener->schedule = schedule; + listener->callback = callback; + listener->context = context; + listener->require_fqdn = require_fqdn; + listener->lookup = lookup; + + if (port_count > 0) { + listener->socks = silc_calloc(port_count, sizeof(*listener->socks)); + if (!listener->socks) + return NULL; + } else { + listener->socks = silc_calloc(1, sizeof(*listener->socks)); + if (!listener->socks) + return NULL; + + port_count = 1; + } + + /* Bind to local addresses */ + for (i = 0; i < local_ip_count; i++) { + SILC_LOG_DEBUG(("Binding to local address %s:%d", + local_ip_addr ? local_ip_addr : ipany, + ports ? ports[i] : 0)); + + /* Set sockaddr for server */ + if (!silc_net_set_sockaddr(&server, + local_ip_addr ? local_ip_addr : ipany, + ports ? ports[i] : 0)) { + if (ignore_port_error) + continue; + goto err; + } + + /* Create the socket */ + sock = socket(server.sin.sin_family, SOCK_STREAM, 0); + if (sock == INVALID_SOCKET) { + if (ignore_port_error) + continue; + SILC_LOG_ERROR(("Cannot create socket, error %d", WSAGetLastError())); + goto err; + } + + /* Set the socket options */ + rval = silc_net_set_socket_opt(sock, SOL_SOCKET, SO_REUSEADDR, 1); + if (rval == SOCKET_ERROR) { + closesocket(sock); + if (ignore_port_error) + continue; + SILC_LOG_ERROR(("Cannot set socket options, error %d", + WSAGetLastError())); + goto err; + } + + /* Bind the listener socket */ + rval = bind(sock, &server.sa, SIZEOF_SOCKADDR(server)); + if (rval == SOCKET_ERROR) { + closesocket(sock); + if (ignore_port_error) + continue; + SILC_LOG_ERROR(("Cannot bind socket, error %d", WSAGetLastError())); + goto err; + } + + /* Specify that we are listenning */ + rval = listen(sock, SOMAXCONN); + if (rval == SOCKET_ERROR) { + closesocket(sock); + if (ignore_port_error) + continue; + SILC_LOG_ERROR(("Cannot set socket listenning, error %d", + WSAGetLastError())); + goto err; + } + + /* Schedule for incoming connections */ + silc_schedule_task_add_fd(schedule, sock, silc_net_accept, listener); + + SILC_LOG_DEBUG(("TCP listener created, fd=%d", sock)); + listener->socks[i] = sock; + listener->socks_count++; + } + + if (ignore_port_error && !listener->socks_count) + goto err; + + return listener; + + err: + if (listener) + silc_net_close_listener(listener); + return NULL; +} + /* Close network listener */ void silc_net_close_listener(SilcNetListener listener)