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