updates.
[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, 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(int port, char *host)
103 {
104   SOCKET sock;
105   int rval, err;
106   struct hostent *dest;
107   struct sockaddr_in desthost;
108
109   SILC_LOG_DEBUG(("Creating connection to host %s port %d", host, port));
110
111   /* Do host lookup */
112   dest = gethostbyname(host);
113   if (!dest) {
114     SILC_LOG_ERROR(("Network (%s) unreachable", host));
115     return -1;
116   }
117
118   /* Set socket information */
119   memset(&desthost, 0, sizeof(desthost));
120   desthost.sin_port = htons(port);
121   desthost.sin_family = AF_INET;
122   memcpy(&desthost.sin_addr, dest->h_addr_list[0], sizeof(desthost.sin_addr));
123
124   /* Create the connection socket */
125   sock = socket(AF_INET, SOCK_STREAM, 0);
126   if (sock == INVALID_SOCKET) {
127     SILC_LOG_ERROR(("Cannot create socket"));
128     return -1;
129   }
130
131   /* Connect to the host */
132   rval = connect(sock, (struct sockaddr *)&desthost, sizeof(desthost));
133   err = WSAGetLastError();
134   if (rval == SOCKET_ERROR && err != WSAEWOULDBLOCK) {
135     SILC_LOG_ERROR(("Cannot connect to remote host"));
136     shutdown(sock, 2);
137     closesocket(sock);
138     return -1;
139   }
140
141   /* Set appropriate options */
142   silc_net_set_socket_opt(sock, IPPROTO_TCP, TCP_NODELAY, 1);
143   silc_net_set_socket_opt(sock, SOL_SOCKET, SO_KEEPALIVE, 1);
144
145   SILC_LOG_DEBUG(("Connection created"));
146
147   return sock;
148 }
149
150 /* Creates a connection (TCP/IP) to a remote host. Returns the connection
151    socket or -1 on error. This creates non-blocking socket hence the
152    connection returns directly. To get the result of the connect() one
153    must select() the socket and read the result after it's ready. */
154
155 int silc_net_create_connection_async(int port, char *host)
156 {
157   SOCKET sock;
158   int rval, err;
159   struct hostent *dest;
160   struct sockaddr_in desthost;
161
162   SILC_LOG_DEBUG(("Creating connection (async) to host %s port %d", 
163                   host, port));
164
165   /* Do host lookup */
166   dest = gethostbyname(host);
167   if (!dest) {
168     SILC_LOG_ERROR(("Network (%s) unreachable", host));
169     return -1;
170   }
171
172   /* Set socket information */
173   memset(&desthost, 0, sizeof(desthost));
174   desthost.sin_port = htons(port);
175   desthost.sin_family = AF_INET;
176   memcpy(&desthost.sin_addr, dest->h_addr_list[0], sizeof(desthost.sin_addr));
177
178   /* Create the connection socket */
179   sock = socket(AF_INET, SOCK_STREAM, 0);
180   if (sock == INVALID_SOCKET) {
181     SILC_LOG_ERROR(("Cannot create socket"));
182     return -1;
183   }
184
185   /* Connect to the host */
186   rval = connect(sock, (struct sockaddr *)&desthost, sizeof(desthost));
187   err = WSAGetLastError();
188   if (rval == SOCKET_ERROR && err != WSAEWOULDBLOCK) {
189     SILC_LOG_ERROR(("Cannot connect to remote host"));
190     shutdown(sock, 2);
191     closesocket(sock);
192     return -1;
193   }
194
195   /* Set socket to nonblocking mode */
196   silc_net_set_socket_nonblock(sock);
197
198   /* Set appropriate options */
199   silc_net_set_socket_opt(sock, IPPROTO_TCP, TCP_NODELAY, 1);
200   silc_net_set_socket_opt(sock, SOL_SOCKET, SO_KEEPALIVE, 1);
201
202   SILC_LOG_DEBUG(("Connection created"));
203
204   return sock;
205 }
206
207 /* Closes the connection by closing the socket connection. */
208
209 void silc_net_close_connection(int sock)
210 {
211   closesocket(sock);
212 }
213
214 /* Converts the IP number string from numbers-and-dots notation to
215    binary form. */
216
217 bool silc_net_addr2bin(const char *addr, unsigned char *bin,
218                        uint32 bin_len)
219 {
220   unsigned long ret;
221
222   ret = inet_addr(addr);
223
224   if (bin_len < 4)
225     return FALSE;
226
227   SILC_PUT32_LSB(ret, bin);
228
229   return ret != INADDR_NONE;
230 }
231
232 /* Set socket to non-blocking mode. */
233
234 int silc_net_set_socket_nonblock(int sock)
235 {
236   unsigned long on = 1;
237   return ioctlsocket(sock, FIONBIO, &on);
238 }
239
240 /* Init Winsock2. */
241
242 bool silc_net_win32_init(void)
243 {
244   int ret, sopt = SO_SYNCHRONOUS_NONALERT;
245   WSADATA wdata;
246   WORD ver = MAKEWORD(1, 1);
247
248   ret = WSAStartup(ver, &wdata);
249   if (ret)
250     return FALSE;
251
252   /* Allow using the SOCKET's as file descriptors so that we can poll
253      them with SILC Scheduler. */
254   ret = setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, (char *)&sopt,
255                    sizeof(sopt));
256   if (ret)
257     return FALSE;
258
259   return TRUE;
260 }
261
262 /* Uninit Winsock2 */
263
264 void silc_net_win32_uninit(void)
265 {
266   WSACleanup();
267 }