file_http.cpp revision 1.11.2.2 1 1.11.2.2 uwe /* $NetBSD: file_http.cpp,v 1.11.2.2 2006/03/05 04:05:40 uwe Exp $ */
2 1.11.2.2 uwe
3 1.11.2.2 uwe /*-
4 1.11.2.2 uwe * Copyright (c) 2001, 2002, 2004 The NetBSD Foundation, Inc.
5 1.11.2.2 uwe * All rights reserved.
6 1.11.2.2 uwe *
7 1.11.2.2 uwe * This code is derived from software contributed to The NetBSD Foundation
8 1.11.2.2 uwe * by UCHIYAMA Yasushi.
9 1.11.2.2 uwe *
10 1.11.2.2 uwe * Redistribution and use in source and binary forms, with or without
11 1.11.2.2 uwe * modification, are permitted provided that the following conditions
12 1.11.2.2 uwe * are met:
13 1.11.2.2 uwe * 1. Redistributions of source code must retain the above copyright
14 1.11.2.2 uwe * notice, this list of conditions and the following disclaimer.
15 1.11.2.2 uwe * 2. Redistributions in binary form must reproduce the above copyright
16 1.11.2.2 uwe * notice, this list of conditions and the following disclaimer in the
17 1.11.2.2 uwe * documentation and/or other materials provided with the distribution.
18 1.11.2.2 uwe * 3. All advertising materials mentioning features or use of this software
19 1.11.2.2 uwe * must display the following acknowledgement:
20 1.11.2.2 uwe * This product includes software developed by the NetBSD
21 1.11.2.2 uwe * Foundation, Inc. and its contributors.
22 1.11.2.2 uwe * 4. Neither the name of The NetBSD Foundation nor the names of its
23 1.11.2.2 uwe * contributors may be used to endorse or promote products derived
24 1.11.2.2 uwe * from this software without specific prior written permission.
25 1.11.2.2 uwe *
26 1.11.2.2 uwe * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 1.11.2.2 uwe * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 1.11.2.2 uwe * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 1.11.2.2 uwe * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 1.11.2.2 uwe * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 1.11.2.2 uwe * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 1.11.2.2 uwe * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 1.11.2.2 uwe * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 1.11.2.2 uwe * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 1.11.2.2 uwe * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 1.11.2.2 uwe * POSSIBILITY OF SUCH DAMAGE.
37 1.11.2.2 uwe */
38 1.11.2.2 uwe
39 1.11.2.2 uwe #include <file.h>
40 1.11.2.2 uwe #include <file_http.h>
41 1.11.2.2 uwe #include <console.h>
42 1.11.2.2 uwe #include <libsa_string.h>
43 1.11.2.2 uwe
44 1.11.2.2 uwe #define wcsicmp _wcsicmp
45 1.11.2.2 uwe static int WCE210_WSAStartup(WORD, LPWSADATA);
46 1.11.2.2 uwe static int WCE210_WSACleanup(void);
47 1.11.2.2 uwe
48 1.11.2.2 uwe HttpFile::HttpFile(Console *&cons)
49 1.11.2.2 uwe : File(cons),
50 1.11.2.2 uwe _req_get("GET "),
51 1.11.2.2 uwe _req_head("HEAD "),
52 1.11.2.2 uwe _req_host(" HTTP/1.0\r\nHOST: "),
53 1.11.2.2 uwe _req_ua("\r\nUser-Agent: HPCBOOT/ZERO(1st impact; Windows CE; "
54 1.11.2.2 uwe #if defined MIPS
55 1.11.2.2 uwe "MIPS"
56 1.11.2.2 uwe #elif defined ARM
57 1.11.2.2 uwe "ARM"
58 1.11.2.2 uwe #elif defined SH3
59 1.11.2.2 uwe "SH3"
60 1.11.2.2 uwe #elif defined SH4
61 1.11.2.2 uwe "SH4"
62 1.11.2.2 uwe #else
63 1.11.2.2 uwe "Unknown"
64 1.11.2.2 uwe #endif
65 1.11.2.2 uwe ")\r\n\r\n")
66 1.11.2.2 uwe {
67 1.11.2.2 uwe
68 1.11.2.2 uwe _server_name[0] = '\0';
69 1.11.2.2 uwe _debug = 1;
70 1.11.2.2 uwe _memory_cache = TRUE;
71 1.11.2.2 uwe // _memory_cache = FALSE; // not recomended.
72 1.11.2.2 uwe _buffer = 0;
73 1.11.2.2 uwe _reset_state();
74 1.11.2.2 uwe DPRINTF((TEXT("FileManager: HTTP\n")));
75 1.11.2.2 uwe
76 1.11.2.2 uwe #if _WIN32_WCE <= 200
77 1.11.2.2 uwe _wsa_startup = WCE210_WSAStartup;
78 1.11.2.2 uwe _wsa_cleanup = WCE210_WSACleanup;
79 1.11.2.2 uwe #else
80 1.11.2.2 uwe if (WinCEVersion.dwMajorVersion > 3 ||
81 1.11.2.2 uwe (WinCEVersion.dwMajorVersion > 2) &&
82 1.11.2.2 uwe (WinCEVersion.dwMinorVersion >= 11)) {
83 1.11.2.2 uwe _wsa_startup = WSAStartup;
84 1.11.2.2 uwe _wsa_cleanup = WSACleanup;
85 1.11.2.2 uwe } else {
86 1.11.2.2 uwe _wsa_startup = WCE210_WSAStartup;
87 1.11.2.2 uwe _wsa_cleanup = WCE210_WSACleanup;
88 1.11.2.2 uwe }
89 1.11.2.2 uwe #endif
90 1.11.2.2 uwe }
91 1.11.2.2 uwe
92 1.11.2.2 uwe int
93 1.11.2.2 uwe WCE210_WSAStartup(WORD ver, LPWSADATA data)
94 1.11.2.2 uwe {
95 1.11.2.2 uwe
96 1.11.2.2 uwe data->wVersion = ver;
97 1.11.2.2 uwe data->wHighVersion = ver;
98 1.11.2.2 uwe data->szDescription[0] = '\0';
99 1.11.2.2 uwe data->szSystemStatus[0] = '\0';
100 1.11.2.2 uwe data->iMaxSockets = 10;
101 1.11.2.2 uwe data->iMaxUdpDg = 0;
102 1.11.2.2 uwe data->lpVendorInfo = NULL;
103 1.11.2.2 uwe
104 1.11.2.2 uwe return (0);
105 1.11.2.2 uwe }
106 1.11.2.2 uwe
107 1.11.2.2 uwe int
108 1.11.2.2 uwe WCE210_WSACleanup()
109 1.11.2.2 uwe {
110 1.11.2.2 uwe
111 1.11.2.2 uwe return (0);
112 1.11.2.2 uwe }
113 1.11.2.2 uwe
114 1.11.2.2 uwe HttpFile::~HttpFile(void)
115 1.11.2.2 uwe {
116 1.11.2.2 uwe if (_buffer)
117 1.11.2.2 uwe free(_buffer);
118 1.11.2.2 uwe _wsa_cleanup();
119 1.11.2.2 uwe }
120 1.11.2.2 uwe
121 1.11.2.2 uwe void
122 1.11.2.2 uwe HttpFile::_reset_state(void)
123 1.11.2.2 uwe {
124 1.11.2.2 uwe _ascii_filename[0] = '\0';
125 1.11.2.2 uwe _cached = FALSE;
126 1.11.2.2 uwe if (_buffer)
127 1.11.2.2 uwe free(_buffer);
128 1.11.2.2 uwe _buffer = 0;
129 1.11.2.2 uwe _header_size = 0;
130 1.11.2.2 uwe _cur_pos = 0;
131 1.11.2.2 uwe }
132 1.11.2.2 uwe
133 1.11.2.2 uwe BOOL
134 1.11.2.2 uwe HttpFile::setRoot(TCHAR *server)
135 1.11.2.2 uwe {
136 1.11.2.2 uwe SOCKET h;
137 1.11.2.2 uwe int ret, port;
138 1.11.2.2 uwe
139 1.11.2.2 uwe // parse server name and its port #
140 1.11.2.2 uwe TCHAR sep[] = TEXT(":/");
141 1.11.2.2 uwe
142 1.11.2.2 uwe TCHAR *token = wcstok(server, sep);
143 1.11.2.2 uwe for (int i = 0; i < 3 && token; i++, token = wcstok(0, sep)) {
144 1.11.2.2 uwe switch(i) {
145 1.11.2.2 uwe case 0:
146 1.11.2.2 uwe if (wcsicmp(token, TEXT("http"))) {
147 1.11.2.2 uwe return FALSE;
148 1.11.2.2 uwe }
149 1.11.2.2 uwe break;
150 1.11.2.2 uwe case 1:
151 1.11.2.2 uwe if (!_to_ascii(_server_name, token, MAX_PATH))
152 1.11.2.2 uwe return FALSE;
153 1.11.2.2 uwe port = 80;
154 1.11.2.2 uwe break;
155 1.11.2.2 uwe case 2:
156 1.11.2.2 uwe port = _wtoi(token);
157 1.11.2.2 uwe break;
158 1.11.2.2 uwe }
159 1.11.2.2 uwe }
160 1.11.2.2 uwe
161 1.11.2.2 uwe WORD version = MAKEWORD(1, 1);
162 1.11.2.2 uwe ret = _wsa_startup(version, &_winsock);
163 1.11.2.2 uwe if (ret != 0) {
164 1.11.2.2 uwe DPRINTF((TEXT("WinSock initialize failed.\n")));
165 1.11.2.2 uwe return FALSE;
166 1.11.2.2 uwe }
167 1.11.2.2 uwe if (LOBYTE(_winsock.wVersion) != 1 ||
168 1.11.2.2 uwe HIBYTE(_winsock.wVersion) != 1) {
169 1.11.2.2 uwe DPRINTF((TEXT("can't use WinSock DLL.\n")));
170 1.11.2.2 uwe return FALSE;
171 1.11.2.2 uwe }
172 1.11.2.2 uwe
173 1.11.2.2 uwe h = socket(AF_INET, SOCK_STREAM, 0);
174 1.11.2.2 uwe if (h == INVALID_SOCKET) {
175 1.11.2.2 uwe DPRINTF((TEXT("can't open socket. cause=%d\n"),
176 1.11.2.2 uwe WSAGetLastError()));
177 1.11.2.2 uwe return FALSE;
178 1.11.2.2 uwe }
179 1.11.2.2 uwe
180 1.11.2.2 uwe memset(&_sockaddr, 0, sizeof(sockaddr_in));
181 1.11.2.2 uwe _sockaddr.sin_family = AF_INET;
182 1.11.2.2 uwe _sockaddr.sin_port = htons(port);
183 1.11.2.2 uwe
184 1.11.2.2 uwe struct hostent *entry = gethostbyname(_server_name);
185 1.11.2.2 uwe if (entry == 0) {
186 1.11.2.2 uwe _sockaddr.sin_addr.S_un.S_addr = inet_addr(_server_name);
187 1.11.2.2 uwe if (_sockaddr.sin_addr.S_un.S_addr == INADDR_NONE) {
188 1.11.2.2 uwe DPRINTF((TEXT("can't get host by name.\n")));
189 1.11.2.2 uwe return FALSE;
190 1.11.2.2 uwe }
191 1.11.2.2 uwe uint8_t *b = &_sockaddr.sin_addr.S_un.S_un_b.s_b1;
192 1.11.2.2 uwe DPRINTF((TEXT("%d.%d.%d.%d "), b[0], b[1], b[2], b[3]));
193 1.11.2.2 uwe if (connect(h,(const struct sockaddr *)&_sockaddr,
194 1.11.2.2 uwe sizeof(struct sockaddr_in)) == 0)
195 1.11.2.2 uwe goto connected;
196 1.11.2.2 uwe } else {
197 1.11.2.2 uwe for (uint8_t **addr_list =(uint8_t **)entry->h_addr_list;
198 1.11.2.2 uwe *addr_list; addr_list++) {
199 1.11.2.2 uwe uint8_t *b = &_sockaddr.sin_addr.S_un.S_un_b.s_b1;
200 1.11.2.2 uwe for (int i = 0; i < 4; i++)
201 1.11.2.2 uwe b[i] = addr_list[0][i];
202 1.11.2.2 uwe
203 1.11.2.2 uwe DPRINTF((TEXT("%d.%d.%d.%d "), b[0], b[1], b[2],b[3]));
204 1.11.2.2 uwe if (connect(h,(const struct sockaddr *)&_sockaddr,
205 1.11.2.2 uwe sizeof(struct sockaddr_in)) == 0)
206 1.11.2.2 uwe goto connected;
207 1.11.2.2 uwe }
208 1.11.2.2 uwe }
209 1.11.2.2 uwe DPRINTF((TEXT("can't connect server.\n")));
210 1.11.2.2 uwe return FALSE;
211 1.11.2.2 uwe
212 1.11.2.2 uwe connected:
213 1.11.2.2 uwe DPRINTF((TEXT("(%S) connected.\n"), _server_name));
214 1.11.2.2 uwe closesocket(h);
215 1.11.2.2 uwe
216 1.11.2.2 uwe return TRUE;
217 1.11.2.2 uwe }
218 1.11.2.2 uwe
219 1.11.2.2 uwe BOOL
220 1.11.2.2 uwe HttpFile::open(const TCHAR *name, uint32_t flag)
221 1.11.2.2 uwe {
222 1.11.2.2 uwe
223 1.11.2.2 uwe _reset_state();
224 1.11.2.2 uwe
225 1.11.2.2 uwe return _to_ascii(_ascii_filename, name, MAX_PATH);
226 1.11.2.2 uwe }
227 1.11.2.2 uwe
228 1.11.2.2 uwe size_t
229 1.11.2.2 uwe HttpFile::_read_from_cache(void *buf, size_t bytes, off_t ofs)
230 1.11.2.2 uwe {
231 1.11.2.2 uwe size_t transfer;
232 1.11.2.2 uwe
233 1.11.2.2 uwe if (ofs >= _buffer_size)
234 1.11.2.2 uwe return 0;
235 1.11.2.2 uwe
236 1.11.2.2 uwe transfer = ofs + bytes > _buffer_size ? _buffer_size - ofs : bytes;
237 1.11.2.2 uwe
238 1.11.2.2 uwe memcpy(buf, &_buffer[ofs], transfer);
239 1.11.2.2 uwe
240 1.11.2.2 uwe return transfer;
241 1.11.2.2 uwe }
242 1.11.2.2 uwe
243 1.11.2.2 uwe BOOL
244 1.11.2.2 uwe HttpFile::seek(off_t offset)
245 1.11.2.2 uwe {
246 1.11.2.2 uwe _cur_pos = offset;
247 1.11.2.2 uwe
248 1.11.2.2 uwe return TRUE;
249 1.11.2.2 uwe }
250 1.11.2.2 uwe
251 1.11.2.2 uwe size_t
252 1.11.2.2 uwe HttpFile::read(void *buf, size_t bytes, off_t offset)
253 1.11.2.2 uwe {
254 1.11.2.2 uwe char *b;
255 1.11.2.2 uwe off_t ofs;
256 1.11.2.2 uwe
257 1.11.2.2 uwe if (offset != -1) {
258 1.11.2.2 uwe ofs = offset;
259 1.11.2.2 uwe } else {
260 1.11.2.2 uwe ofs = _cur_pos;
261 1.11.2.2 uwe _cur_pos += bytes;
262 1.11.2.2 uwe }
263 1.11.2.2 uwe
264 1.11.2.2 uwe if (_memory_cache && _cached)
265 1.11.2.2 uwe return _read_from_cache(buf, bytes, ofs);
266 1.11.2.2 uwe
267 1.11.2.2 uwe // HEAD request(get header size).
268 1.11.2.2 uwe if (_header_size == 0)
269 1.11.2.2 uwe _buffer_size = _parse_header(_header_size);
270 1.11.2.2 uwe
271 1.11.2.2 uwe // reconnect
272 1.11.2.2 uwe Socket sock(_sockaddr);
273 1.11.2.2 uwe SOCKET h;
274 1.11.2.2 uwe if ((h = sock) == INVALID_SOCKET)
275 1.11.2.2 uwe return 0;
276 1.11.2.2 uwe
277 1.11.2.2 uwe // GET request
278 1.11.2.2 uwe strcpy(_request, _req_get);
279 1.11.2.2 uwe _set_request();
280 1.11.2.2 uwe send(h, _request, strlen(_request), 0);
281 1.11.2.2 uwe
282 1.11.2.2 uwe // skip header.
283 1.11.2.2 uwe b = static_cast <char *>(malloc(_header_size));
284 1.11.2.2 uwe _recv_buffer(h, b, _header_size);
285 1.11.2.2 uwe free(b);
286 1.11.2.2 uwe
287 1.11.2.2 uwe // read contents.
288 1.11.2.2 uwe size_t readed;
289 1.11.2.2 uwe if (_memory_cache) {
290 1.11.2.2 uwe _buffer = static_cast <char *>(malloc(_buffer_size));
291 1.11.2.2 uwe _recv_buffer(h, _buffer, _buffer_size);
292 1.11.2.2 uwe _cached = TRUE;
293 1.11.2.2 uwe return _read_from_cache(buf, bytes, ofs);
294 1.11.2.2 uwe } else {
295 1.11.2.2 uwe int i, n = ofs / bytes;
296 1.11.2.2 uwe b = static_cast <char *>(buf);
297 1.11.2.2 uwe
298 1.11.2.2 uwe for (readed = 0, i = 0; i < n; i++)
299 1.11.2.2 uwe readed += _recv_buffer(h, b, bytes);
300 1.11.2.2 uwe if ((n =(ofs % bytes)))
301 1.11.2.2 uwe readed += _recv_buffer(h, b, n);
302 1.11.2.2 uwe DPRINTF((TEXT("skip contents %d byte.\n"), readed));
303 1.11.2.2 uwe
304 1.11.2.2 uwe readed = _recv_buffer(h, b, bytes);
305 1.11.2.2 uwe }
306 1.11.2.2 uwe return readed;
307 1.11.2.2 uwe }
308 1.11.2.2 uwe
309 1.11.2.2 uwe size_t
310 1.11.2.2 uwe HttpFile::_parse_header(size_t &header_size)
311 1.11.2.2 uwe {
312 1.11.2.2 uwe int cnt, ret;
313 1.11.2.2 uwe char *buf;
314 1.11.2.2 uwe size_t sz = 0;
315 1.11.2.2 uwe
316 1.11.2.2 uwe // reconnect.
317 1.11.2.2 uwe Socket sock(_sockaddr);
318 1.11.2.2 uwe SOCKET h;
319 1.11.2.2 uwe if ((h = sock) == INVALID_SOCKET) {
320 1.11.2.2 uwe DPRINTF((TEXT("can't open socket.\n")));
321 1.11.2.2 uwe return 0;
322 1.11.2.2 uwe }
323 1.11.2.2 uwe
324 1.11.2.2 uwe // HEAD request
325 1.11.2.2 uwe strcpy(_request, _req_head);
326 1.11.2.2 uwe _set_request();
327 1.11.2.2 uwe send(h, _request, strlen(_request), 0);
328 1.11.2.2 uwe
329 1.11.2.2 uwe // Receive and search Content-Length: field.
330 1.11.2.2 uwe if ((buf = static_cast<char *>(malloc(TMP_BUFFER_SIZE))) == 0) {
331 1.11.2.2 uwe DPRINTF((TEXT("can't allocate receive buffer.\n")));
332 1.11.2.2 uwe return 0;
333 1.11.2.2 uwe }
334 1.11.2.2 uwe
335 1.11.2.2 uwe BOOL found = FALSE;
336 1.11.2.2 uwe for (cnt = 0; ret = _recv_buffer(h, buf, TMP_BUFFER_SIZE - 1);
337 1.11.2.2 uwe cnt += ret) {
338 1.11.2.2 uwe buf[ret] = '\0';
339 1.11.2.2 uwe char sep[] = " :\r\n";
340 1.11.2.2 uwe char *token = libsa::strtok(buf, sep);
341 1.11.2.2 uwe while (token) {
342 1.11.2.2 uwe DPRINTFN(2, (TEXT("+token: %S\n"), token));
343 1.11.2.2 uwe if (libsa::stricmp(token, "content-length") == 0) {
344 1.11.2.2 uwe DPRINTFN(2, (TEXT("*token: %S\n"), token));
345 1.11.2.2 uwe token = libsa::strtok(0, sep);
346 1.11.2.2 uwe sz = atoi(token);
347 1.11.2.2 uwe found = TRUE;
348 1.11.2.2 uwe DPRINTFN(2, (TEXT("*content-length=%d\n"), sz));
349 1.11.2.2 uwe } else {
350 1.11.2.2 uwe token = libsa::strtok(0, sep);
351 1.11.2.2 uwe }
352 1.11.2.2 uwe }
353 1.11.2.2 uwe }
354 1.11.2.2 uwe header_size = cnt;
355 1.11.2.2 uwe
356 1.11.2.2 uwe if (!found) {
357 1.11.2.2 uwe DPRINTF((TEXT("No Content-Length.\n")));
358 1.11.2.2 uwe } else {
359 1.11.2.2 uwe DPRINTF((TEXT
360 1.11.2.2 uwe ("open http://%S%S - header %d byte contents %d byte\n"),
361 1.11.2.2 uwe _server_name, _ascii_filename, header_size, sz));
362 1.11.2.2 uwe }
363 1.11.2.2 uwe free(buf);
364 1.11.2.2 uwe
365 1.11.2.2 uwe return sz;
366 1.11.2.2 uwe }
367 1.11.2.2 uwe
368 1.11.2.2 uwe size_t
369 1.11.2.2 uwe HttpFile::_recv_buffer(SOCKET h, char *buf, size_t size)
370 1.11.2.2 uwe {
371 1.11.2.2 uwe size_t cnt, total = 0;
372 1.11.2.2 uwe
373 1.11.2.2 uwe do {
374 1.11.2.2 uwe cnt = recv(h, buf + total, size - total, 0);
375 1.11.2.2 uwe total += cnt;
376 1.11.2.2 uwe DPRINTFN(2,(TEXT("size %d readed %d byte(+%d)\n"),
377 1.11.2.2 uwe size, total, cnt));
378 1.11.2.2 uwe } while (total < size && cnt > 0);
379 1.11.2.2 uwe
380 1.11.2.2 uwe DPRINTFN(1,(TEXT("total read %d byte\n"), total));
381 1.11.2.2 uwe return total;
382 1.11.2.2 uwe }
383 1.11.2.2 uwe
384 1.11.2.2 uwe void
385 1.11.2.2 uwe HttpFile::_set_request(void)
386 1.11.2.2 uwe {
387 1.11.2.2 uwe
388 1.11.2.2 uwe strcat(_request, _ascii_filename);
389 1.11.2.2 uwe strcat(_request, _req_host);
390 1.11.2.2 uwe strcat(_request, _server_name);
391 1.11.2.2 uwe strcat(_request, _req_ua);
392 1.11.2.2 uwe }
393 1.11.2.2 uwe
394 1.11.2.2 uwe Socket::Socket(struct sockaddr_in &sock)
395 1.11.2.2 uwe : _sockaddr(sock)
396 1.11.2.2 uwe {
397 1.11.2.2 uwe
398 1.11.2.2 uwe _socket = socket(AF_INET, SOCK_STREAM, 0);
399 1.11.2.2 uwe if (_socket != INVALID_SOCKET)
400 1.11.2.2 uwe connect(_socket,
401 1.11.2.2 uwe reinterpret_cast <const struct sockaddr *>(&_sockaddr),
402 1.11.2.2 uwe sizeof(struct sockaddr_in));
403 1.11.2.2 uwe }
404 1.11.2.2 uwe
405 1.11.2.2 uwe Socket::~Socket(void)
406 1.11.2.2 uwe {
407 1.11.2.2 uwe
408 1.11.2.2 uwe if (_socket != INVALID_SOCKET)
409 1.11.2.2 uwe closesocket(_socket);
410 1.11.2.2 uwe }
411