From ddcf7e8460618f3cc9c1da3a09a3a1ff647a0aba Mon Sep 17 00:00:00 2001 From: Pekka Riikonen Date: Tue, 1 May 2007 11:21:29 +0000 Subject: [PATCH] Ported SILC Net API (TCP & UDP), SILC Socket Stream API, SILC Schedule API and others to WIN32. --- CHANGES | 9 + TODO | 44 +- lib/silcutil/win32/silcwin32net.c | 779 +++++++++++++++++---- lib/silcutil/win32/silcwin32schedule.c | 43 +- lib/silcutil/win32/silcwin32sockconn.c | 137 ---- lib/silcutil/win32/silcwin32socketstream.c | 232 ++++++ lib/silcutil/win32/silcwin32util.c | 23 +- 7 files changed, 937 insertions(+), 330 deletions(-) delete mode 100644 lib/silcutil/win32/silcwin32sockconn.c create mode 100644 lib/silcutil/win32/silcwin32socketstream.c diff --git a/CHANGES b/CHANGES index 7b574738..93de8a54 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,12 @@ +Tue May 1 14:17:06 EEST 2007 Pekka Riikonen + + * Ported SILC Socket Stream API, SILC Net API, SILC Schedule API, + and other smaller APIs to WIN32. Affected files are in + lib/silcutil/win32/. + + * Changed the various regex APIs as generic code in util library. + Affected files are lib/silcutil/silcstrutil.[ch]. + Sat Apr 28 13:47:47 EEST 2007 Pekka Riikonen * Ported SILC Server to the new Toolkit API, working towards diff --git a/TODO b/TODO index f9d76e22..afad8364 100644 --- a/TODO +++ b/TODO @@ -17,9 +17,9 @@ apps/silcd, The SILC Server ****PARTLY DONE**** o Remove protocol.[ch]. ***DONE - o Rewrite connecting accepting. + o Rewrite connecting accepting. (***TESTING NEEDED) - o Rewrite async connecting. + o Rewrite async connecting. (***TESTING NEEDED) o Connecting from SILC router to SILC server. @@ -128,21 +128,15 @@ lib/silcsftp ****DONE**** lib/silccore/silcpacket.[ch] ****PARTLY DONE**** ============================ - o Implement silc_packet_engine_stop and silc_packet_stream_destroy. - - o Implement ACK packet and packet payload. - o SilcPacketEngine. (***DONE) o New SILC Packet API. (***DONE) - -lib/silccore/silcpacket.[ch] ****PARTLY DONE**** -============================ + o Implement silc_packet_engine_stop and silc_packet_stream_destroy. (***DONE) o IV Included flag support, UDP transport support (***TESTING NEEDED) - o SILC_PACKET_FLAG_ACK support. + o SILC_PACKET_FLAG_ACK support. Implement ACK packet and packet payload. lib/silccore/silcid.[ch] ****DONE**** @@ -161,15 +155,13 @@ lib/silcskr ****PARTLY DONE**** o Removing key from the repository is not possible currently. It should be. (***DONE) - o Add fingerprint as search constraint. + o Add fingerprint as search constraint. (1.2) lib/silcske/silcske.[ch] ***PARTLY DONE**** ======================== - o Responder rekey - - o Ratelimit to UDP/IP transport for incoming packets. + o Responder rekey (***TESTING NEEDED) o IV Included flag support in SKE (***DONE) @@ -178,17 +170,19 @@ lib/silcske/silcske.[ch] ***PARTLY DONE**** o SilcConnAuth header file documentation. (***DONE) + o Ratelimit to UDP/IP transport for incoming packets. (1.2) + lib/silccrypt ****PARTLY DONE**** ============= + o Implement PKCS #1 sign/verify with hash OID. (***TESTING NEEDED) + o Implement SILC Public Key Version 2 handling in sign/verify. Implement Version (V) identifier (***DONE) o Add fingerprint to SilcSILCPublicKey and retrieval to silcpk.h. - o Implement PKCS #1 sign/verify with hash OID. (***TESTING NEEDED) - o SILC PKCS (silcpkcs.h) reorganizing when other PK supports added. Move the SILC Public Key routines away from the crypto library into the core library (silccore). silc_pkcs_public/private_key_* routines @@ -216,14 +210,10 @@ lib/silcutil ****PARTLY DONE**** o The regex code from lib/contrib might compile fine on all platforms. No need to make it silcutil/unix/ specific. Add them to generic - silcutil.c. + silcutil.c. (***TESTNG NEEDED) o silc_stringprep to non-allocating version. - o Compression routines are missing. The protocol supports packet - compression thus it must be implemented. SILC Zip API must be - defined. - o bool -> SilcBool (***DONE) o Silc FD Stream to WIN32 (lib/silcutil/silcfdstream.h) @@ -232,6 +222,10 @@ lib/silcutil ****PARTLY DONE**** SILC currently supports SOCKS4 and SOCKS5 but it needs to be compiled in separately. (1.2) + o Compression routines are missing. The protocol supports packet + compression thus it must be implemented. SILC Zip API must be + defined. (1.2) + lib/silcutil/silcbuffer.h ****DONE**** ========================= @@ -274,9 +268,7 @@ lib/silcutil/silcsocketstream.[ch] ****PARTY DONE**** o Add SilcSocketStream (***DONE) - o Add SilcSocketStream for WIN32 - - o Handle EOS sending to upper layer properly + o Add SilcSocketStream for WIN32 (***TESTING NEEDED) o Test QoS after the changes made to socket stream @@ -309,7 +301,7 @@ lib/silcutil/silcschedule*.[ch] ****PARTLY DONE**** o Change SILC_TASK_CALLBACK to non-static, and remove the macro SILC_TASK_CALLBACK_GLOBAL. (***DONE) - o SILC Schedule API changes to WIN32. + o SILC Schedule API changes to WIN32. (***TESTING NEEDED) lib/silcutil/silcasync.[ch] ****DONE**** @@ -341,7 +333,7 @@ lib/silcutil/silcnet*, lib/silcutil/*/silc*net* ****PARTLY DONE**** o Add UDP interface (***DONE) - o Add UDP interface for WIN32 + o Add UDP interface for WIN32 (***TESTING NEEDED) o New network interfaces (***DONE) diff --git a/lib/silcutil/win32/silcwin32net.c b/lib/silcutil/win32/silcwin32net.c index 818945e0..8cf1dd0e 100644 --- a/lib/silcutil/win32/silcwin32net.c +++ b/lib/silcutil/win32/silcwin32net.c @@ -4,12 +4,12 @@ Author: Pekka Riikonen - Copyright (C) 1997 - 2005 Pekka Riikonen + Copyright (C) 1997 - 2005, 2007 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 the Free Software Foundation; version 2 of the License. - + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the @@ -18,205 +18,707 @@ */ /* $Id$ */ -/* XXX IPv6 support missing */ - #include "silc.h" -#include "silcnet.h" -/* This function creates server or daemon or listener or what ever. This - does not fork a new process, it must be done by the caller if caller - wants to create a child process. This is used by the SILC server. - If argument `ip_addr' is NULL `any' address will be used. Returns - the created socket or -1 on error. */ +/************************** Types and definitions ***************************/ + +#ifdef HAVE_IPV6 +#define SIZEOF_SOCKADDR(so) ((so).sa.sa_family == AF_INET6 ? \ + sizeof(so.sin6) : sizeof(so.sin)) +#else +#define SIZEOF_SOCKADDR(so) (sizeof(so.sin)) +#endif + +typedef union { + struct sockaddr sa; + struct sockaddr_in sin; +#ifdef HAVE_IPV6 + struct sockaddr_in6 sin6; +#endif +} SilcSockaddr; + + +/************************ Static utility functions **************************/ + +static SilcBool silc_net_set_sockaddr(SilcSockaddr *addr, const char *ip_addr, + int port) +{ + int len; + + memset(addr, 0, sizeof(*addr)); + + /* Check for IPv4 and IPv6 addresses */ + if (ip_addr) { + if (!silc_net_is_ip(ip_addr)) { + SILC_LOG_ERROR(("%s is not IP address", ip_addr)); + return FALSE; + } + + if (silc_net_is_ip4(ip_addr)) { + /* IPv4 address */ + len = sizeof(addr->sin.sin_addr); + silc_net_addr2bin(ip_addr, + (unsigned char *)&addr->sin.sin_addr.s_addr, len); + addr->sin.sin_family = AF_INET; + addr->sin.sin_port = port ? htons(port) : 0; + } else { +#ifdef HAVE_IPV6 + /* IPv6 address */ + len = sizeof(addr->sin6.sin6_addr); + silc_net_addr2bin(ip_addr, + (unsigned char *)&addr->sin6.sin6_addr, len); + addr->sin6.sin6_family = AF_INET6; + addr->sin6.sin6_port = port ? htons(port) : 0; +#else + SILC_LOG_ERROR(("Operating System does not support IPv6")); + return FALSE; +#endif + } + } else { + /* Any address */ + addr->sin.sin_family = AF_INET; + addr->sin.sin_addr.s_addr = INADDR_ANY; + if (port) + addr->sin.sin_port = htons(port); + } + + return TRUE; +} + + +/****************************** TCP Listener ********************************/ + +/* Deliver new stream to upper layer */ + +static void silc_net_accept_stream(SilcSocketStreamStatus status, + SilcStream stream, void *context) +{ + SilcNetListener listener = context; + + if (status != SILC_SOCKET_OK) + return; + + listener->callback(SILC_NET_OK, stream, listener->context); +} + +/* Accept incoming connection and notify upper layer */ + +SILC_TASK_CALLBACK(silc_net_accept) +{ + SilcNetListener listener = context; + int sock; + + SILC_LOG_DEBUG(("Accepting new connection")); + + sock = silc_net_accept_connection(fd); + if (sock == INVALID_SOCKET) + return; + + /* Set socket options */ + silc_net_set_socket_nonblock(sock); + silc_net_set_socket_opt(sock, SOL_SOCKET, SO_REUSEADDR, 1); + + /* Create socket stream */ + silc_socket_tcp_stream_create(sock, listener->lookup, + listener->require_fqdn, schedule, + silc_net_accept_stream, listener); +} + +/* Create TCP network listener */ -int silc_net_create_server(int port, const char *ip_addr) +SilcNetListener +silc_net_tcp_create_listener(const char **local_ip_addr, + SilcUInt32 local_ip_count, int port, + SilcBool lookup, SilcBool require_fqdn, + SilcSchedule schedule, + SilcNetCallback callback, void *context) { + SilcNetListener listener = NULL; + SOCKET sock; + SilcSockaddr server; + int i, sock, rval; + const char *ipany = "0.0.0.0"; + + SILC_LOG_DEBUG(("Creating TCP listener")); + + if (port < 0 || !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 (local_ip_count > 0) { + listener->socks = silc_calloc(local_ip_count, sizeof(*listener->socks)); + if (!listener->socks) + return NULL; + } else { + listener->socks = silc_calloc(1, sizeof(*listener->socks)); + if (!listener->socks) + return NULL; + + local_ip_count = 1; + } + + /* Bind to local addresses */ + for (i = 0; i < local_ip_count; i++) { + SILC_LOG_DEBUG(("Binding to local address %s", + local_ip_addr ? local_ip_addr[i] : ipany)); + + /* Set sockaddr for server */ + if (!silc_net_set_sockaddr(&server, + local_ip_addr ? local_ip_addr[i] : ipany, + port)) + goto err; + + /* Create the socket */ + sock = socket(server.sin.sin_family, SOCK_STREAM, 0); + if (sock == INVALID_SOCKET) { + SILC_LOG_ERROR(("Cannot create socket")); + goto err; + } + + /* Set the socket options */ + rval = silc_net_set_socket_opt(sock, SOL_SOCKET, SO_REUSEADDR, 1); + if (rval == SOCKET_ERROR) { + SILC_LOG_ERROR(("Cannot set socket options")); + closesocket(sock); + goto err; + } + + /* Bind the listener socket */ + rval = bind(sock, &server.sa, SIZEOF_SOCKADDR(server)); + if (rval == SOCKET_ERROR) { + SILC_LOG_ERROR(("Cannot bind socket")); + closesocket(sock); + goto err; + } + + /* Specify that we are listenning */ + rval = listen(sock, SOMAXCONN); + if (rval == SOCKET_ERROR) { + SILC_LOG_ERROR(("Cannot set socket listenning")); + closesocket(sock); + goto err; + } + + /* Set the server socket to non-blocking mode. Dunno if this works. */ + 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++; + } + + return listener; + + err: + if (listener) + silc_net_close_listener(listener); + return NULL; +} + +/* Close network listener */ + +void silc_net_close_listener(SilcNetListener listener) +{ + int i; + + SILC_LOG_DEBUG(("Closing network listener")); + + for (i = 0; i < listener->socks_count; i++) { + silc_schedule_task_del_by_fd(listener->schedule, listener->socks[i]); + shutdown(listener->socks[i], 2); + closesocket(listener->socks[i]); + } + + silc_free(listener->socks); + silc_free(listener); +} + +/******************************* UDP Stream *********************************/ + +/* 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; SOCKET sock; int rval; - struct sockaddr_in server; - int len = sizeof(server.sin_addr); + const char *ipany = "0.0.0.0"; + + SILC_LOG_DEBUG(("Creating UDP stream")); + + if (!schedule) + goto err; - SILC_LOG_DEBUG(("Creating a new server listener")); + /* 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(PF_INET, SOCK_STREAM, 0); + sock = socket(server.sin.sin_family, SOCK_DGRAM, 0); if (sock == INVALID_SOCKET) { SILC_LOG_ERROR(("Cannot create socket")); - return -1; + goto err; } /* Set the socket options */ rval = silc_net_set_socket_opt(sock, SOL_SOCKET, SO_REUSEADDR, 1); - if (rval != 0) { + if (rval == SOCKET_ERROR) { + SILC_LOG_ERROR(("Cannot set socket options")); + goto err; + } +#ifdef SO_REUSEPORT + rval = silc_net_set_socket_opt(sock, SOL_SOCKET, SO_REUSEPORT, 1); + if (rval == SOCKET_ERROR) { SILC_LOG_ERROR(("Cannot set socket options")); - closesocket(sock); - return -1; + goto err; + } +#endif /* SO_REUSEPORT */ + + /* Bind the listener socket */ + rval = bind(sock, &server.sa, SIZEOF_SOCKADDR(server)); + if (rval == SOCKET_ERROR) { + SILC_LOG_DEBUG(("Cannot bind socket")); + goto err; } - /* Set the socket information for bind() */ - memset(&server, 0, sizeof(server)); - server.sin_family = AF_INET; - if (port) - server.sin_port = htons(port); - - /* Convert IP address to network byte order */ - if (ip_addr) - silc_net_addr2bin(ip_addr, (unsigned char *)&server.sin_addr.s_addr, len); - else - server.sin_addr.s_addr = INADDR_ANY; - - /* Bind the server socket */ - rval = bind(sock, (struct sockaddr *)&server, sizeof(server)); - if (rval != 0) { - SILC_LOG_ERROR(("Cannot bind socket")); - closesocket(sock); - return -1; + /* 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 == SOCKET_ERROR) { + SILC_LOG_DEBUG(("Cannot connect UDP stream")); + goto err; + } } - /* Specify that we are listenning */ - rval = listen(sock, 5); - if (rval != 0) { - SILC_LOG_ERROR(("Cannot set socket listenning")); - closesocket(sock); - return -1; + /* Encapsulate into socket stream */ + stream = + silc_socket_udp_stream_create(sock, local_ip_addr ? + silc_net_is_ip6(local_ip_addr) : FALSE, + remote_ip_addr ? TRUE : 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, err; + + 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 == SOCKET_ERROR) { + err = WSAGetLastError(); + if (err == WSAEWOULDBLOCK) { + 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", sock->sock)); + silc_schedule_unset_listen_fd(sock->schedule, sock->sock); + sock->sock_error = err; + return -2; } - SILC_LOG_DEBUG(("Server listener created, fd=%d", sock)); + SILC_LOG_DEBUG(("Read %d bytes", len)); - return sock; + 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); + } + + SILC_LOG_DEBUG(("UDP packet from %s:%d", remote_ip_addr, *remote_port)); + } + + return len; } -/* Closes the server by closing the socket connection. */ +/* Send UDP packet */ -void silc_net_close_server(int sock) +int silc_net_udp_send(SilcStream stream, + const char *remote_ip_addr, int remote_port, + const unsigned char *data, SilcUInt32 data_len) { - shutdown(sock, 2); - closesocket(sock); + SilcSocketStream sock = stream; + SilcSockaddr remote; + int ret, err; + + SILC_LOG_DEBUG(("Sending data to UDP socket %d", sock->sock)); + + /* Set sockaddr */ + if (!silc_net_set_sockaddr(&remote, remote_ip_addr, remote_port)) + return -2; + + /* Send */ + ret = sendto(sock->sock, data, data_len, 0, &remote.sa, + SIZEOF_SOCKADDR(remote)); + if (ret == SOCKET_ERROR) { + err = WSAGetLastError(); + if (err == WSAEWOULDBLOCK) { + 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 = err; + 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; +} + + +/******************************* TCP Stream *********************************/ + +typedef struct { + SilcNetStatus status; + SilcSocketStreamStatus stream_status; + SilcStream stream; + SilcFSMStruct fsm; + SilcFSMThreadStruct thread; + SilcAsyncOperation op; + SilcAsyncOperation sop; + char *local_ip; + char *remote; + char ip_addr[64]; + int sock; + SilcNetCallback callback; + void *context; + unsigned int port : 24; + unsigned int retry : 7; + unsigned int aborted : 1; +} *SilcNetConnect; + +SILC_FSM_STATE(silc_net_connect_st_start); +SILC_FSM_STATE(silc_net_connect_st_stream); +SILC_FSM_STATE(silc_net_connect_st_finish); + +static void silc_net_connect_wait_stream(SilcSocketStreamStatus status, + SilcStream stream, void *context) +{ + SilcNetConnect conn = context; + conn->stream_status = status; + conn->stream = stream; + SILC_FSM_CALL_CONTINUE(&conn->fsm); +} + +/* Start connecting. Create a real thread where we connect. */ + +SILC_FSM_STATE(silc_net_connect_st_thread) +{ + SilcNetConnect conn = context; + + /* Connect in real thread as as to not block the application. */ + silc_fsm_thread_init(&conn->thread, conn, NULL, NULL, TRUE); + silc_fsm_start(&conn->thread, silc_net_connect_st_start); - SILC_LOG_DEBUG(("Server socket closed")); + /* Wait for the thread to finish */ + silc_fsm_next(fsm, silc_net_connect_st_finish); + SILC_FSM_THREAD_WAIT(&conn->thread); } -/* Creates a connection (TCP/IP) to a remote host. Returns the connection - socket or -1 on error. This blocks the process while trying to create - the connection. */ +/* Connecting thread */ -int silc_net_create_connection(const char *local_ip, int port, - const char *host) +SILC_FSM_STATE(silc_net_connect_st_start) { + SilcNetConnect conn = fsm_context; SOCKET sock; int rval, err; - struct hostent *dest; - struct sockaddr_in desthost; + SilcSockaddr desthost; + SilcBool prefer_ipv6 = TRUE; - SILC_LOG_DEBUG(("Creating connection to host %s port %d", host, port)); + if (conn->aborted) + return SILC_FSM_FINISH; /* Do host lookup */ - dest = gethostbyname(host); - if (!dest) { + retry: + if (!silc_net_gethostbyname(conn->remote, prefer_ipv6, + conn->ip_addr, sizeof(conn->ip_addr))) { SILC_LOG_ERROR(("Network (%s) unreachable: could not resolve the " - "IP address", host)); - return -1; + "host", conn->remote)); + + /** Network unreachable */ + conn->status = SILC_NET_HOST_UNREACHABLE; + return SILC_FSM_FINISH; } - /* Set socket information */ - memset(&desthost, 0, sizeof(desthost)); - desthost.sin_port = htons(port); - desthost.sin_family = AF_INET; - memcpy(&desthost.sin_addr, dest->h_addr_list[0], sizeof(desthost.sin_addr)); + /* Set sockaddr for this connection */ + if (!silc_net_set_sockaddr(&desthost, conn->ip_addr, conn->port)) + return SILC_FSM_FINISH; /* Create the connection socket */ - sock = socket(AF_INET, SOCK_STREAM, 0); + sock = socket(desthost.sin.sin_family, SOCK_STREAM, 0); if (sock == INVALID_SOCKET) { + /* If address is IPv6, then fallback to IPv4 and see whether we can do + better with that on socket creation. */ + if (prefer_ipv6 && silc_net_is_ip6(conn->ip_addr)) { + prefer_ipv6 = FALSE; + goto retry; + } + + /** Cannot create socket */ SILC_LOG_ERROR(("Cannot create socket")); - return -1; + return SILC_FSM_FINISH; + } + + /* Bind to the local address if provided */ + if (conn->local_ip) { + SilcSockaddr local; + + /* Set sockaddr for local listener, and try to bind it. */ + if (silc_net_set_sockaddr(&local, conn->local_ip, 0)) + bind(sock, &local.sa, SIZEOF_SOCKADDR(local)); } /* Connect to the host */ - rval = connect(sock, (struct sockaddr *)&desthost, sizeof(desthost)); + rval = connect(sock, &desthost.sa, SIZEOF_SOCKADDR(desthost)); err = WSAGetLastError(); - if (rval == SOCKET_ERROR && err != WSAEWOULDBLOCK) { - SILC_LOG_ERROR(("Cannot connect to remote host")); - shutdown(sock, 2); - closesocket(sock); - return -1; + if (rval == SOCKET_ERROR) { + if (err != WSAEWOULDBLOCK) { + shutdown(sock, 2); + closesocket(sock); + + /* Retry using an IPv4 adress, if IPv6 didn't work */ + if (prefer_ipv6 && silc_net_is_ip6(conn->ip_addr)) { + prefer_ipv6 = FALSE; + goto retry; + } + + switch (err) { + case WSAETIMEDOUT: + conn->status = SILC_NET_CONNECTION_TIMEOUT; + break; + case WSAECONNREFUSED: + conn->status = SILC_NET_CONNECTION_REFUSED; + break; + case WSAEHOSTUNREACH: + conn->status = SILC_NET_HOST_UNREACHABLE; + break; + default: + break; + } + + SILC_LOG_ERROR(("Cannot connect to remote host")); + return SILC_FSM_FINISH; + } } + /* Set the socket to non-blocking mode */ + silc_net_set_socket_nonblock(sock); + /* Set appropriate options */ #if defined(TCP_NODELAY) silc_net_set_socket_opt(sock, IPPROTO_TCP, TCP_NODELAY, 1); #endif silc_net_set_socket_opt(sock, SOL_SOCKET, SO_KEEPALIVE, 1); - SILC_LOG_DEBUG(("Connection created")); + SILC_LOG_DEBUG(("TCP connection established")); - return sock; + conn->sock = sock; + + /** Connection created */ + silc_fsm_next(fsm, silc_net_connect_st_stream); + SILC_FSM_CALL((conn->sop = silc_socket_tcp_stream_create( + conn->sock, FALSE, FALSE, + schedule, + silc_net_connect_wait_stream, conn))); } -/* Creates a connection (TCP/IP) to a remote host. Returns the connection - socket or -1 on error. This creates non-blocking socket hence the - connection returns directly. To get the result of the connect() one - must select() the socket and read the result after it's ready. */ +/* TCP socket stream created */ -int silc_net_create_connection_async(const char *local_ip, int port, - const char *host) +SILC_FSM_STATE(silc_net_connect_st_stream) { - SOCKET sock; - int rval, err; - struct hostent *dest; - struct sockaddr_in desthost; + SilcNetConnect conn = fsm_context; - SILC_LOG_DEBUG(("Creating connection (async) to host %s port %d", - host, port)); + if (conn->aborted) + return SILC_FSM_FINISH; - /* Do host lookup */ - dest = gethostbyname(host); - if (!dest) { - SILC_LOG_ERROR(("Network (%s) unreachable: could not resolve the " - "IP address", host)); - return -1; + if (conn->stream_status != SILC_SOCKET_OK) { + /** Stream creation failed */ + if (conn->stream_status == SILC_SOCKET_UNKNOWN_IP) + conn->status = SILC_NET_UNKNOWN_IP; + else if (conn->stream_status == SILC_SOCKET_UNKNOWN_HOST) + conn->status = SILC_NET_UNKNOWN_HOST; + else + conn->status = SILC_NET_ERROR; + + return SILC_FSM_FINISH; } - /* Set socket information */ - memset(&desthost, 0, sizeof(desthost)); - desthost.sin_port = htons(port); - desthost.sin_family = AF_INET; - memcpy(&desthost.sin_addr, dest->h_addr_list[0], sizeof(desthost.sin_addr)); + /* Set stream information */ + silc_socket_stream_set_info(conn->stream, + !silc_net_is_ip(conn->remote) ? conn->remote : + conn->ip_addr, conn->ip_addr, conn->port); - /* Create the connection socket */ - sock = socket(AF_INET, SOCK_STREAM, 0); - if (sock == INVALID_SOCKET) { - SILC_LOG_ERROR(("Cannot create socket")); - return -1; + /** Stream created successfully */ + SILC_LOG_DEBUG(("Connected successfully, sock %d", conn->sock)); + conn->status = SILC_NET_OK; + return SILC_FSM_FINISH; +} + +SILC_FSM_STATE(silc_net_connect_st_finish) +{ + SilcNetConnect conn = fsm_context; + + /* Deliver error or new stream */ + if (!conn->aborted) { + conn->callback(conn->status, conn->stream, conn->context); + if (conn->op) + silc_async_free(conn->op); + if (conn->sop) + silc_async_free(conn->sop); } - /* Connect to the host */ - rval = connect(sock, (struct sockaddr *)&desthost, sizeof(desthost)); - err = WSAGetLastError(); - if (rval == SOCKET_ERROR && err != WSAEWOULDBLOCK) { - SILC_LOG_ERROR(("Cannot connect to remote host")); - shutdown(sock, 2); - closesocket(sock); - return -1; + return SILC_FSM_FINISH; +} + +static void silc_net_connect_abort(SilcAsyncOperation op, void *context) +{ + SilcNetConnect conn = context; + conn->aborted = TRUE; + + /* Abort underlaying stream creation too */ + if (conn->sop) + silc_async_abort(conn->sop, NULL, NULL); +} + +static void silc_net_connect_destructor(SilcFSM fsm, void *fsm_context, + void *destructor_context) +{ + SilcNetConnect conn = fsm_context; + silc_free(conn->local_ip); + silc_free(conn->remote); + silc_free(conn); +} + +/* Create asynchronous TCP/IP connection. */ + +SilcAsyncOperation silc_net_tcp_connect(const char *local_ip_addr, + const char *remote_ip_addr, + int remote_port, + SilcSchedule schedule, + SilcNetCallback callback, + void *context) +{ + SilcNetConnect conn; + + if (!remote_ip_addr || remote_port < 1 || !schedule || !callback) + return NULL; + + SILC_LOG_DEBUG(("Creating connection to host %s port %d", + remote_ip_addr, remote_port)); + + conn = silc_calloc(1, sizeof(*conn)); + if (!conn) { + callback(SILC_NET_NO_MEMORY, NULL, context); + return NULL; } - /* Set socket to nonblocking mode */ - silc_net_set_socket_nonblock(sock); + /* 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; + } - /* Set appropriate options */ -#if defined(TCP_NODELAY) - silc_net_set_socket_opt(sock, IPPROTO_TCP, TCP_NODELAY, 1); -#endif - silc_net_set_socket_opt(sock, SOL_SOCKET, SO_KEEPALIVE, 1); + if (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; + } + conn->port = remote_port; + conn->callback = callback; + conn->context = context; + conn->retry = 1; + conn->status = SILC_NET_ERROR; - SILC_LOG_DEBUG(("Connection created")); + silc_fsm_init(&conn->fsm, conn, silc_net_connect_destructor, NULL, schedule); + silc_fsm_start(&conn->fsm, silc_net_connect_st_thread); - return sock; + return conn->op; } /* Closes the connection by closing the socket connection. */ void silc_net_close_connection(int sock) { + SILC_LOG_DEBUG(("Closing sock %d", sock)); closesocket(sock); } @@ -227,13 +729,36 @@ SilcBool silc_net_addr2bin(const char *addr, void *bin, SilcUInt32 bin_len) { unsigned long ret; - ret = inet_addr(addr); + if (silc_net_is_ip4(addr)) { + /* IPv4 address */ + ret = inet_addr(addr); - if (bin_len < 4) - return FALSE; + if (bin_len < 4) + return FALSE; + + memcpy(bin, (unsigned char *)&ret, 4); + return ret != INADDR_NONE; + } else { + struct addrinfo hints, *ai; + SilcSockaddr *s; - memcpy(bin, (unsigned char *)&ret, 4); - return ret != INADDR_NONE; + /* IPv6 address */ + if (bin_len < 16) + return FALSE; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET6; + if (getaddrinfo(addr, NULL, &hints, &ai)) + return FALSE; + + if (ai) { + s = (SilcSockaddr *)ai->ai_addr; + memcpy(bin, &s->sin6.sin6_addr, sizeof(s->sin6.sin6_addr)); + freeaddrinfo(ai); + } + + return TRUE; + } } /* Set socket to non-blocking mode. */ diff --git a/lib/silcutil/win32/silcwin32schedule.c b/lib/silcutil/win32/silcwin32schedule.c index aa2cd254..126f18b2 100644 --- a/lib/silcutil/win32/silcwin32schedule.c +++ b/lib/silcutil/win32/silcwin32schedule.c @@ -4,7 +4,7 @@ Author: Pekka Riikonen - Copyright (C) 2001 - 2006 Pekka Riikonen + Copyright (C) 2001 - 2007 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 @@ -56,7 +56,7 @@ int silc_select(SilcSchedule schedule, void *context); DWORD ready, curtime; LONG timeo; MSG msg; - int nhandles = 0, i, fd; + int nhandles = 0, fd; silc_hash_table_list(schedule->fd_queue, &htl); while (silc_hash_table_get(&htl, (void **)&fd, (void **)&task)) { @@ -77,6 +77,7 @@ int silc_select(SilcSchedule schedule, void *context); task->revents = 0; } silc_hash_table_list_reset(&htl); + silc_list_init(schedule->fd_dispatch, struct SilcTaskStruct, next); timeo = (schedule->has_timeout ? ((schedule->timeout.tv_sec * 1000) + (schedule->timeout.tv_usec / 1000)) @@ -153,7 +154,7 @@ int silc_select(SilcSchedule schedule, void *context); } /* Give the wait another try */ - goto retry; + goto retry; } else if (ready >= WAIT_OBJECT_0 && ready < WAIT_OBJECT_0 + nhandles) { /* Some other event, like SOCKET or something. */ @@ -162,19 +163,15 @@ int silc_select(SilcSchedule schedule, void *context); nhandles = silc_hash_table_count(schedule->fd_queue); ready -= WAIT_OBJECT_0; do { - i = 0; - silc_hash_table_list(schedule->fd_queue, &htl); - while (silc_hash_table_get(&htl, (void **)&fd, (void **)&task)) { - if (!task->events) - continue; - - if (fd == (int)handles[ready]) { - i++; - task->revents |= SILC_TASK_READ; - break; - } + if (!silc_hash_table_find(schedule->fd_queue, + SILC_32_TO_PTR((SilcUInt32)handles[ready]), + NULL, (void *)&task)) + break; + + if (task->header.valid && task->events) { + task->revents |= SILC_TASK_READ; + silc_list_add(schedule->fd_dispatch, task); } - silc_hash_table_list_reset(&htl); /* Check the status of the next handle and set its fd to the fd set if data is available. */ @@ -185,7 +182,7 @@ int silc_select(SilcSchedule schedule, void *context); SILC_SCHEDULE_LOCK(schedule); } while (ready < nhandles); - return i + 1; + return silc_list_count(schedule->fd_dispatch); } return -1; @@ -261,6 +258,16 @@ void silc_schedule_internal_uninit(SilcSchedule schedule, void *context) #endif } +/* Schedule `task' with events `event_mask'. Zero `event_mask' unschedules. */ + +SilcBool silc_schedule_internal_schedule_fd(SilcSchedule schedule, + void *context, + SilcTaskFd task, + SilcTaskEvent event_mask) +{ + return TRUE; +} + /* Wakes up the scheduler */ void silc_schedule_internal_wakeup(SilcSchedule schedule, void *context) @@ -298,8 +305,7 @@ void silc_schedule_internal_signal_unregister(SilcSchedule schedule, /* Call all signals */ void silc_schedule_internal_signals_call(SilcSchedule schedule, - void *context, - SilcSchedule schedule) + void *context) { } @@ -325,6 +331,7 @@ const SilcScheduleOps schedule_ops = silc_schedule_internal_init, silc_schedule_internal_uninit, silc_select, + silc_schedule_internal_schedule_fd, silc_schedule_internal_wakeup, silc_schedule_internal_signal_register, silc_schedule_internal_signal_unregister, diff --git a/lib/silcutil/win32/silcwin32sockconn.c b/lib/silcutil/win32/silcwin32sockconn.c deleted file mode 100644 index 31f702f4..00000000 --- a/lib/silcutil/win32/silcwin32sockconn.c +++ /dev/null @@ -1,137 +0,0 @@ -/* - - silcwin32sockconn.c - - Author: Pekka Riikonen - - Copyright (C) 1997 - 2005 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 - the Free Software Foundation; version 2 of the License. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - -*/ -/* $Id$ */ - -#include "silc.h" - -/* Writes data from encrypted buffer to the socket connection. If the - data cannot be written at once, it will be written later with a timeout. - The data is written from the data section of the buffer, not from head - or tail section. This automatically pulls the data section towards end - after writing the data. */ - -int silc_socket_write(SilcSocketConnection sock) -{ - int ret = 0, err; - SOCKET fd = sock->sock; - SilcBuffer src = sock->outbuf; - - if (!src) - return -2; - if (SILC_IS_DISABLED(sock)) - return -1; - - SILC_LOG_DEBUG(("Writing data to socket %d", fd)); - - if (src->len > 0) { - ret = send(fd, src->data, src->len, 0); - if (ret == SOCKET_ERROR) { - err = WSAGetLastError(); - if (err == WSAEWOULDBLOCK) { - SILC_LOG_DEBUG(("Could not write immediately, will do it later")); - return -2; - } - SILC_LOG_ERROR(("Cannot write to socket: %d", (int)fd)); - sock->sock_error = err; - return -1; - } - - if (ret < src->len) { - SILC_LOG_DEBUG(("Wrote data %d of %d bytes, will write rest later", - ret, src->len)); - silc_buffer_pull(src, ret); - return -2; - } - - silc_buffer_pull(src, ret); - } - - SILC_LOG_DEBUG(("Wrote data %d bytes", ret)); - - return ret; -} - -/* Reads data from the socket connection into the incoming data buffer. - It reads as much as possible from the socket connection. This returns - amount of bytes read or -1 on error or -2 on case where all of the - data could not be read at once. */ - -int silc_socket_read(SilcSocketConnection sock) -{ - int len = 0, err; - unsigned char buf[SILC_SOCKET_READ_SIZE]; - SOCKET fd = sock->sock; - int argp; - - if (SILC_IS_DISABLED(sock)) - return -1; - - SILC_LOG_DEBUG(("Reading data from socket %d", fd)); - - /* Check whether there is data available, without calling recv(). */ - ioctlsocket(fd, FIONREAD, (unsigned long *)&argp); - if (argp == 0) { - /* Is this kludge or what? Without this thing this contraption - does not work at all!?. */ - SleepEx(1, TRUE); - SILC_LOG_DEBUG(("Could not read immediately, will do it later")); - return -2; - } - - /* Read the data from the socket. */ - len = recv(fd, buf, sizeof(buf), 0); - if (len == SOCKET_ERROR) { - err = WSAGetLastError(); - if (err == WSAEWOULDBLOCK || err == WSAEINTR) { - SILC_LOG_DEBUG(("Could not read immediately, will do it later")); - return -2; - } - SILC_LOG_ERROR(("Cannot read from socket: %d", (int)fd)); - sock->sock_error = err; - return -1; - } - - if (!len) - return 0; - - /* Insert the data to the buffer. */ - - if (!sock->inbuf) - sock->inbuf = silc_buffer_alloc(SILC_SOCKET_BUF_SIZE); - - /* If the data does not fit to the buffer reallocate it */ - if ((sock->inbuf->end - sock->inbuf->tail) < len) - sock->inbuf = silc_buffer_realloc(sock->inbuf, sock->inbuf->truelen + - (len * 2)); - silc_buffer_put_tail(sock->inbuf, buf, len); - silc_buffer_pull_tail(sock->inbuf, len); - - SILC_LOG_DEBUG(("Read %d bytes", len)); - - return len; -} - -/* Returns human readable socket error message */ - -SilcBool silc_socket_get_error(SilcSocketConnection sock, char *error, - SilcUInt32 error_len) -{ - /* XXX TODO */ - return FALSE; -} diff --git a/lib/silcutil/win32/silcwin32socketstream.c b/lib/silcutil/win32/silcwin32socketstream.c new file mode 100644 index 00000000..ac12c82c --- /dev/null +++ b/lib/silcutil/win32/silcwin32socketstream.c @@ -0,0 +1,232 @@ +/* + + silcwin32socketstream.c + + Author: Pekka Riikonen + + Copyright (C) 2007 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 + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + +*/ + +#include "silc.h" + +/************************ Static utility functions **************************/ + +/* The IO process callback that calls the notifier callback to upper layer. */ + +SILC_TASK_CALLBACK(silc_socket_stream_io) +{ + SilcSocketStream stream = context; + + if (!stream->notifier) + return; + + switch (type) { + case SILC_TASK_READ: + stream->notifier(stream, SILC_STREAM_CAN_READ, stream->notifier_context); + break; + + case SILC_TASK_WRITE: + stream->notifier(stream, SILC_STREAM_CAN_WRITE, stream->notifier_context); + break; + + default: + break; + } +} + +/**************************** Stream Operations *****************************/ + +/* Stream read operation */ + +int silc_socket_stream_read(SilcStream stream, unsigned char *buf, + SilcUInt32 buf_len) +{ + SilcSocketStream sock = stream; + SOCKET fd = sock->sock; + int len, argp; + + SILC_LOG_DEBUG(("Reading data from socket %d", fd)); + + /* Check whether there is data available, without calling recv(). */ + ioctlsocket(fd, FIONREAD, (unsigned long *)&argp); + if (argp == 0) { + /* Is this kludge or what? Without this thing this contraption + does not work at all!?. */ + SleepEx(1, TRUE); + SILC_LOG_DEBUG(("Could not read immediately, will do it later")); + silc_schedule_set_listen_fd(sock->schedule, sock->sock, + silc_schedule_get_fd_events(sock->schedule, + sock->sock) | + SILC_TASK_READ, FALSE); + return -1; + } + + /* Read the data from the socket. */ + len = recv(fd, buf, buf_len, 0); + if (len == SOCKET_ERROR) { + len = WSAGetLastError(); + if (len == WSAEWOULDBLOCK || len == WSAEINTR) { + SILC_LOG_DEBUG(("Could not read immediately, will do it later")); + silc_schedule_set_listen_fd(sock->schedule, sock->sock, + silc_schedule_get_fd_events(sock->schedule, + sock->sock) | + SILC_TASK_READ, FALSE); + return -1; + } + SILC_LOG_DEBUG(("Cannot read from socket: %d", sock->sock)); + silc_schedule_unset_listen_fd(sock->schedule, sock->sock); + sock->sock_error = len; + return -2; + } + + SILC_LOG_DEBUG(("Read %d bytes", len)); + + if (!len) + silc_schedule_unset_listen_fd(sock->schedule, sock->sock); + + return len; +} + +/* Stream write operation */ + +int silc_socket_stream_write(SilcStream stream, const unsigned char *data, + SilcUInt32 data_len) +{ + SilcSocketStream sock = stream; + SOCKET fd = sock->sock; + int ret; + + SILC_LOG_DEBUG(("Writing data to socket %d", fd)); + + ret = send(fd, data, data_len, 0); + if (ret == SOCKET_ERROR) { + ret = WSAGetLastError(); + if (ret == WSAEWOULDBLOCK) { + SILC_LOG_DEBUG(("Could not write 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 write to socket")); + silc_schedule_unset_listen_fd(sock->schedule, sock->sock); + sock->sock_error = ret; + return -2; + } + + SILC_LOG_DEBUG(("Wrote 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; +} + +/* 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; + + /* In connectionless state check if remote IP and port is provided */ + if (!sock->connected && sock->ip && sock->port) + return silc_net_udp_send(stream, sock->ip, sock->port, data, data_len); + + /* In connected state use normal writing to socket. */ + return silc_socket_stream_write(stream, data, data_len); +} + +/* Closes socket */ + +SilcBool silc_socket_stream_close(SilcStream stream) +{ + SilcSocketStream socket_stream = stream; + + if (socket_stream->schedule) { + silc_schedule_unset_listen_fd(socket_stream->schedule, + socket_stream->sock); + silc_schedule_task_del_by_fd(socket_stream->schedule, + socket_stream->sock); + } + silc_net_close_connection(socket_stream->sock); + + return TRUE; +} + +/* Destroys the stream */ + +void silc_socket_stream_destroy(SilcStream stream) +{ + SilcSocketStream socket_stream = stream; + + silc_socket_stream_close(socket_stream); + silc_free(socket_stream->ip); + silc_free(socket_stream->hostname); + if (socket_stream->schedule) + silc_schedule_task_del_by_fd(socket_stream->schedule, socket_stream->sock); + + if (socket_stream->schedule) + silc_schedule_wakeup(socket_stream->schedule); + + silc_free(socket_stream); +} + +/* Sets stream notification callback for the stream */ + +SilcBool silc_socket_stream_notifier(SilcStream stream, + SilcSchedule schedule, + SilcStreamNotifier callback, + void *context) +{ + SilcSocketStream socket_stream = stream; + + SILC_LOG_DEBUG(("Setting stream notifier callback")); + + socket_stream->notifier = callback; + socket_stream->notifier_context = context; + socket_stream->schedule = schedule; + + if (socket_stream->notifier && socket_stream->schedule) { + /* Add the socket to scheduler. Safe to call if already added. */ + if (!silc_schedule_task_add_fd(socket_stream->schedule, + socket_stream->sock, + silc_socket_stream_io, socket_stream)) + return FALSE; + + /* Initially set socket for reading */ + if (!silc_schedule_set_listen_fd(socket_stream->schedule, + socket_stream->sock, + SILC_TASK_READ, FALSE)) + return FALSE; + } else if (socket_stream->schedule) { + /* Unschedule the socket */ + silc_schedule_unset_listen_fd(socket_stream->schedule, + socket_stream->sock); + silc_schedule_task_del_by_fd(socket_stream->schedule, + socket_stream->sock); + } + + if (socket_stream->schedule) + silc_schedule_wakeup(socket_stream->schedule); + + return TRUE; +} diff --git a/lib/silcutil/win32/silcwin32util.c b/lib/silcutil/win32/silcwin32util.c index 3f5a38aa..2a4fa83d 100644 --- a/lib/silcutil/win32/silcwin32util.c +++ b/lib/silcutil/win32/silcwin32util.c @@ -4,7 +4,7 @@ Author: Pekka Riikonen - Copyright (C) 2001 - 2006 Pekka Riikonen + Copyright (C) 2001 - 2007 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 @@ -20,27 +20,6 @@ #include "silc.h" -/* XXX GNU regex may work on Win32 too!! */ -char *silc_string_regexify(const char *string) -{ - return strdup(string); -} - -char *silc_string_regex_combine(const char *string1, const char *string2) -{ - return strdup(string1); -} - -int silc_string_regex_match(const char *regex, const char *string) -{ - return TRUE; -} - -int silc_string_match(const char *string1, const char *string2) -{ - return TRUE; -} - #define FILETIME_1970 0x019db1ded53e8000 const BYTE DWLEN = sizeof(DWORD) * 8; -- 2.24.0