ed7818c57ab8f467a44b034d9b9fd6427de8077b
[silc.git] / lib / silcutil / win32 / silcwin32net.c
1 /*
2
3   silcwin32net.c
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 1997 - 2001 Pekka Riikonen
8
9   This program is free software; you can redistribute it and/or modify
10   it under the terms of the GNU General Public License as published by
11   the Free Software Foundation; either version 2 of the License, or
12   (at your option) any later version.
13   
14   This program is distributed in the hope that it will be useful,
15   but WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   GNU General Public License for more details.
18
19 */
20 /* $Id$ */
21
22 #include "silcincludes.h"
23 #include "silcnet.h"
24
25 /* This function creates server or daemon or listener or what ever. This
26    does not fork a new process, it must be done by the caller if caller
27    wants to create a child process. This is used by the SILC server. 
28    If argument `ip_addr' is NULL `any' address will be used. Returns 
29    the created socket or -1 on error. */
30
31 int silc_net_create_server(int port, const char *ip_addr)
32 {
33   SOCKET sock;
34   int rval;
35   struct sockaddr_in server;
36   int len = sizeof(server.sin_addr);
37
38   SILC_LOG_DEBUG(("Creating a new server listener"));
39
40   /* Create the socket */
41   sock = socket(PF_INET, SOCK_STREAM, 0);
42   if (sock == INVALID_SOCKET) {
43     SILC_LOG_ERROR(("Cannot create socket"));
44     return -1;
45   }
46
47   /* Set the socket options */
48   rval = silc_net_set_socket_opt(sock, SOL_SOCKET, SO_REUSEADDR, 1);
49   if (rval != 0) {
50     SILC_LOG_ERROR(("Cannot set socket options"));
51     closesocket(sock);
52     return -1;
53   }
54
55   /* Set the socket information for bind() */
56   memset(&server, 0, sizeof(server));
57   server.sin_family = AF_INET;
58   if (port)
59     server.sin_port = htons(port);
60
61   /* Convert IP address to network byte order */
62   if (ip_addr)
63     silc_net_addr2bin(ip_addr, (unsigned char *)&server.sin_addr.s_addr, len);
64   else
65     server.sin_addr.s_addr = INADDR_ANY;
66
67   /* Bind the server socket */
68   rval = bind(sock, (struct sockaddr *)&server, sizeof(server));
69   if (rval != 0) {
70     SILC_LOG_ERROR(("Cannot bind socket"));
71     closesocket(sock);
72     return -1;
73   }
74
75   /* Specify that we are listenning */
76   rval = listen(sock, 5);
77   if (rval != 0) {
78     SILC_LOG_ERROR(("Cannot set socket listenning"));
79     closesocket(sock);
80     return -1;
81   }
82
83   SILC_LOG_DEBUG(("Server listener created, fd=%d", sock));
84
85   return sock;
86 }
87
88 /* Closes the server by closing the socket connection. */
89
90 void silc_net_close_server(int sock)
91 {
92   shutdown(sock, 2);
93   closesocket(sock);
94
95   SILC_LOG_DEBUG(("Server socket closed"));
96 }
97
98 /* Creates a connection (TCP/IP) to a remote host. Returns the connection
99    socket or -1 on error. This blocks the process while trying to create
100    the connection. */
101
102 int silc_net_create_connection(const char *local_ip, int port, 
103                                const char *host)
104 {
105   SOCKET sock;
106   int rval, err;
107   struct hostent *dest;
108   struct sockaddr_in desthost;
109
110   SILC_LOG_DEBUG(("Creating connection to host %s port %d", host, port));
111
112   /* Do host lookup */
113   dest = gethostbyname(host);
114   if (!dest) {
115     SILC_LOG_ERROR(("Network (%s) unreachable: could not resolve the "
116                     "IP address", host));
117     return -1;
118   }
119
120   /* Set socket information */
121   memset(&desthost, 0, sizeof(desthost));
122   desthost.sin_port = htons(port);
123   desthost.sin_family = AF_INET;
124   memcpy(&desthost.sin_addr, dest->h_addr_list[0], sizeof(desthost.sin_addr));
125
126   /* Create the connection socket */
127   sock = socket(AF_INET, SOCK_STREAM, 0);
128   if (sock == INVALID_SOCKET) {
129     SILC_LOG_ERROR(("Cannot create socket"));
130     return -1;
131   }
132
133   /* Connect to the host */
134   rval = connect(sock, (struct sockaddr *)&desthost, sizeof(desthost));
135   err = WSAGetLastError();
136   if (rval == SOCKET_ERROR && err != WSAEWOULDBLOCK) {
137     SILC_LOG_ERROR(("Cannot connect to remote host"));
138     shutdown(sock, 2);
139     closesocket(sock);
140     return -1;
141   }
142
143   /* Set appropriate options */
144 #if defined(TCP_NODELAY)
145   silc_net_set_socket_opt(sock, IPPROTO_TCP, TCP_NODELAY, 1);
146 #endif
147   silc_net_set_socket_opt(sock, SOL_SOCKET, SO_KEEPALIVE, 1);
148
149   SILC_LOG_DEBUG(("Connection created"));
150
151   return sock;
152 }
153
154 /* Creates a connection (TCP/IP) to a remote host. Returns the connection
155    socket or -1 on error. This creates non-blocking socket hence the
156    connection returns directly. To get the result of the connect() one
157    must select() the socket and read the result after it's ready. */
158
159 int silc_net_create_connection_async(const char *local_ip, int port, 
160                                      const char *host)
161 {
162   SOCKET sock;
163   int rval, err;
164   struct hostent *dest;
165   struct sockaddr_in desthost;
166
167   SILC_LOG_DEBUG(("Creating connection (async) to host %s port %d", 
168                   host, port));
169
170   /* Do host lookup */
171   dest = gethostbyname(host);
172   if (!dest) {
173     SILC_LOG_ERROR(("Network (%s) unreachable: could not resolve the "
174                     "IP address", host));
175     return -1;
176   }
177
178   /* Set socket information */
179   memset(&desthost, 0, sizeof(desthost));
180   desthost.sin_port = htons(port);
181   desthost.sin_family = AF_INET;
182   memcpy(&desthost.sin_addr, dest->h_addr_list[0], sizeof(desthost.sin_addr));
183
184   /* Create the connection socket */
185   sock = socket(AF_INET, SOCK_STREAM, 0);
186   if (sock == INVALID_SOCKET) {
187     SILC_LOG_ERROR(("Cannot create socket"));
188     return -1;
189   }
190
191   /* Connect to the host */
192   rval = connect(sock, (struct sockaddr *)&desthost, sizeof(desthost));
193   err = WSAGetLastError();
194   if (rval == SOCKET_ERROR && err != WSAEWOULDBLOCK) {
195     SILC_LOG_ERROR(("Cannot connect to remote host"));
196     shutdown(sock, 2);
197     closesocket(sock);
198     return -1;
199   }
200
201   /* Set socket to nonblocking mode */
202   silc_net_set_socket_nonblock(sock);
203
204   /* Set appropriate options */
205 #if defined(TCP_NODELAY)
206   silc_net_set_socket_opt(sock, IPPROTO_TCP, TCP_NODELAY, 1);
207 #endif
208   silc_net_set_socket_opt(sock, SOL_SOCKET, SO_KEEPALIVE, 1);
209
210   SILC_LOG_DEBUG(("Connection created"));
211
212   return sock;
213 }
214
215 /* Closes the connection by closing the socket connection. */
216
217 void silc_net_close_connection(int sock)
218 {
219   closesocket(sock);
220 }
221
222 /* Converts the IP number string from numbers-and-dots notation to
223    binary form. */
224
225 bool silc_net_addr2bin(const char *addr, void *bin, uint32 bin_len);
226 {
227   unsigned long ret;
228
229   ret = inet_addr(addr);
230
231   if (bin_len < 4)
232     return FALSE;
233
234   memcpy(bin, (unsigned char *)&tmp.s_addr, 4);
235   return ret != INADDR_NONE;
236 }
237
238 /* Set socket to non-blocking mode. */
239
240 int silc_net_set_socket_nonblock(int sock)
241 {
242   unsigned long on = 1;
243   return ioctlsocket(sock, FIONBIO, &on);
244 }
245
246 /* Init Winsock2. */
247
248 bool silc_net_win32_init(void)
249 {
250   int ret, sopt = SO_SYNCHRONOUS_NONALERT;
251   WSADATA wdata;
252   WORD ver = MAKEWORD(1, 1);
253
254   ret = WSAStartup(ver, &wdata);
255   if (ret)
256     return FALSE;
257
258   /* Allow using the SOCKET's as file descriptors so that we can poll
259      them with SILC Scheduler. */
260   ret = setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, (char *)&sopt,
261                    sizeof(sopt));
262   if (ret)
263     return FALSE;
264
265   return TRUE;
266 }
267
268 /* Uninit Winsock2 */
269
270 void silc_net_win32_uninit(void)
271 {
272   WSACleanup();
273 }