blob: 49fe0232d4ebdf62ac27e4490b56d49f0daa1a80 [file] [log] [blame]
Benny Prijono9033e312005-11-21 02:08:39 +00001/* $Id$ */
2/*
3 * Copyright (C)2003-2006 Benny Prijono <benny@prijono.org>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19#include <pj/sock.h>
20#include <pj/os.h>
21#include <pj/assert.h>
22#include <pj/string.h>
23#include <pj/compat/socket.h>
24#include <pj/addr_resolv.h>
25#include <pj/errno.h>
26
27/*
28 * Address families conversion.
Benny Prijono42c5b9e2006-05-10 19:24:40 +000029 * The values here are indexed based on pj_addr_family.
Benny Prijono9033e312005-11-21 02:08:39 +000030 */
31const pj_uint16_t PJ_AF_UNIX = AF_UNIX;
32const pj_uint16_t PJ_AF_INET = AF_INET;
33const pj_uint16_t PJ_AF_INET6 = AF_INET6;
34#ifdef AF_PACKET
35const pj_uint16_t PJ_AF_PACKET = AF_PACKET;
36#else
37const pj_uint16_t PJ_AF_PACKET = 0xFFFF;
38#endif
39#ifdef AF_IRDA
40const pj_uint16_t PJ_AF_IRDA = AF_IRDA;
41#else
42const pj_uint16_t PJ_AF_IRDA = 0xFFFF;
43#endif
44
45/*
46 * Socket types conversion.
Benny Prijono42c5b9e2006-05-10 19:24:40 +000047 * The values here are indexed based on pj_sock_type
Benny Prijono9033e312005-11-21 02:08:39 +000048 */
49const pj_uint16_t PJ_SOCK_STREAM = SOCK_STREAM;
50const pj_uint16_t PJ_SOCK_DGRAM = SOCK_DGRAM;
51const pj_uint16_t PJ_SOCK_RAW = SOCK_RAW;
52const pj_uint16_t PJ_SOCK_RDM = SOCK_RDM;
53
54/*
55 * Socket level values.
56 */
57const pj_uint16_t PJ_SOL_SOCKET = SOL_SOCKET;
58#ifdef SOL_IP
59const pj_uint16_t PJ_SOL_IP = SOL_IP;
60#else
61const pj_uint16_t PJ_SOL_IP = 0xFFFF;
62#endif /* SOL_IP */
63#if defined(SOL_TCP)
64const pj_uint16_t PJ_SOL_TCP = SOL_TCP;
65#elif defined(IPPROTO_TCP)
66const pj_uint16_t PJ_SOL_TCP = IPPROTO_TCP;
67#endif /* SOL_TCP */
68#ifdef SOL_UDP
69const pj_uint16_t PJ_SOL_UDP = SOL_UDP;
70#else
71const pj_uint16_t PJ_SOL_UDP = 0xFFFF;
72#endif
73#ifdef SOL_IPV6
74const pj_uint16_t PJ_SOL_IPV6 = SOL_IPV6;
75#else
76const pj_uint16_t PJ_SOL_IPV6 = 0xFFFF;
77#endif
78
79/* optname values. */
80const pj_uint16_t PJ_SO_TYPE = SO_TYPE;
81const pj_uint16_t PJ_SO_RCVBUF = SO_RCVBUF;
82const pj_uint16_t PJ_SO_SNDBUF = SO_SNDBUF;
83
84
Benny Prijonoe67d99a2006-03-20 12:39:24 +000085#if defined(PJ_SOCKADDR_HAS_LEN) && PJ_SOCKADDR_HAS_LEN!=0
86# define SET_LEN(addr,len) (((pj_sockaddr*)(addr))->sa_zero_len=(len))
87# define RESET_LEN(addr) (((pj_sockaddr*)(addr))->sa_zero_len=0)
88#else
89# define SET_LEN(addr,len)
90# define RESET_LEN(addr)
91#endif
92
93
Benny Prijono9033e312005-11-21 02:08:39 +000094/*
95 * Convert 16-bit value from network byte order to host byte order.
96 */
97PJ_DEF(pj_uint16_t) pj_ntohs(pj_uint16_t netshort)
98{
99 return ntohs(netshort);
100}
101
102/*
103 * Convert 16-bit value from host byte order to network byte order.
104 */
105PJ_DEF(pj_uint16_t) pj_htons(pj_uint16_t hostshort)
106{
107 return htons(hostshort);
108}
109
110/*
111 * Convert 32-bit value from network byte order to host byte order.
112 */
113PJ_DEF(pj_uint32_t) pj_ntohl(pj_uint32_t netlong)
114{
115 return ntohl(netlong);
116}
117
118/*
119 * Convert 32-bit value from host byte order to network byte order.
120 */
121PJ_DEF(pj_uint32_t) pj_htonl(pj_uint32_t hostlong)
122{
123 return htonl(hostlong);
124}
125
126/*
127 * Convert an Internet host address given in network byte order
128 * to string in standard numbers and dots notation.
129 */
130PJ_DEF(char*) pj_inet_ntoa(pj_in_addr inaddr)
131{
132#if !defined(PJ_LINUX) && !defined(PJ_LINUX_KERNEL)
133 return inet_ntoa(*(struct in_addr*)&inaddr);
134#else
135 struct in_addr addr;
136 addr.s_addr = inaddr.s_addr;
137 return inet_ntoa(addr);
138#endif
139}
140
141/*
142 * This function converts the Internet host address cp from the standard
143 * numbers-and-dots notation into binary data and stores it in the structure
144 * that inp points to.
145 */
146PJ_DEF(int) pj_inet_aton(const pj_str_t *cp, struct pj_in_addr *inp)
147{
148 char tempaddr[16];
149
150 /* Initialize output with PJ_INADDR_NONE.
151 * Some apps relies on this instead of the return value
152 * (and anyway the return value is quite confusing!)
153 */
154 inp->s_addr = PJ_INADDR_NONE;
155
156 /* Caution:
157 * this function might be called with cp->slen >= 16
158 * (i.e. when called with hostname to check if it's an IP addr).
159 */
160 PJ_ASSERT_RETURN(cp && cp->slen && inp, 0);
161 if (cp->slen >= 16) {
162 return 0;
163 }
164
165 pj_memcpy(tempaddr, cp->ptr, cp->slen);
166 tempaddr[cp->slen] = '\0';
167
168#if defined(PJ_SOCK_HAS_INET_ATON) && PJ_SOCK_HAS_INET_ATON != 0
169 return inet_aton(tempaddr, (struct in_addr*)inp);
170#else
171 inp->s_addr = inet_addr(tempaddr);
172 return inp->s_addr == PJ_INADDR_NONE ? 0 : 1;
173#endif
174}
175
176/*
177 * Convert address string with numbers and dots to binary IP address.
178 */
179PJ_DEF(pj_in_addr) pj_inet_addr(const pj_str_t *cp)
180{
181 pj_in_addr addr;
182
183 pj_inet_aton(cp, &addr);
184 return addr;
185}
186
187/*
Benny Prijono7a4cf152006-03-22 11:48:33 +0000188 * Convert address string with numbers and dots to binary IP address.
189 */
190PJ_DEF(pj_in_addr) pj_inet_addr2(const char *cp)
191{
192 pj_str_t str = pj_str((char*)cp);
193 return pj_inet_addr(&str);
194}
195
196/*
Benny Prijono9033e312005-11-21 02:08:39 +0000197 * Set the IP address of an IP socket address from string address,
198 * with resolving the host if necessary. The string address may be in a
199 * standard numbers and dots notation or may be a hostname. If hostname
200 * is specified, then the function will resolve the host into the IP
201 * address.
202 */
203PJ_DEF(pj_status_t) pj_sockaddr_in_set_str_addr( pj_sockaddr_in *addr,
204 const pj_str_t *str_addr)
205{
206 PJ_CHECK_STACK();
207
Benny Prijono0ca04b62005-12-30 23:50:15 +0000208 PJ_ASSERT_RETURN(!str_addr || str_addr->slen < PJ_MAX_HOSTNAME,
Benny Prijono9033e312005-11-21 02:08:39 +0000209 (addr->sin_addr.s_addr=PJ_INADDR_NONE, PJ_EINVAL));
210
Benny Prijonoe67d99a2006-03-20 12:39:24 +0000211 RESET_LEN(addr);
Benny Prijono9033e312005-11-21 02:08:39 +0000212 addr->sin_family = AF_INET;
Benny Prijonoac623b32006-07-03 15:19:31 +0000213 pj_bzero(addr->sin_zero, sizeof(addr->sin_zero));
Benny Prijono9033e312005-11-21 02:08:39 +0000214
215 if (str_addr && str_addr->slen) {
216 addr->sin_addr = pj_inet_addr(str_addr);
217 if (addr->sin_addr.s_addr == PJ_INADDR_NONE) {
218 pj_hostent he;
219 pj_status_t rc;
220
221 rc = pj_gethostbyname(str_addr, &he);
222 if (rc == 0) {
223 addr->sin_addr.s_addr = *(pj_uint32_t*)he.h_addr;
224 } else {
225 addr->sin_addr.s_addr = PJ_INADDR_NONE;
226 return rc;
227 }
228 }
229
230 } else {
231 addr->sin_addr.s_addr = 0;
232 }
233
234 return PJ_SUCCESS;
235}
236
237/*
238 * Set the IP address and port of an IP socket address.
239 * The string address may be in a standard numbers and dots notation or
240 * may be a hostname. If hostname is specified, then the function will
241 * resolve the host into the IP address.
242 */
243PJ_DEF(pj_status_t) pj_sockaddr_in_init( pj_sockaddr_in *addr,
244 const pj_str_t *str_addr,
245 pj_uint16_t port)
246{
Benny Prijono0ca04b62005-12-30 23:50:15 +0000247 PJ_ASSERT_RETURN(addr, (addr->sin_addr.s_addr=PJ_INADDR_NONE, PJ_EINVAL));
Benny Prijono9033e312005-11-21 02:08:39 +0000248
Benny Prijonoe67d99a2006-03-20 12:39:24 +0000249 RESET_LEN(addr);
Benny Prijono9033e312005-11-21 02:08:39 +0000250 addr->sin_family = PJ_AF_INET;
Benny Prijonoac623b32006-07-03 15:19:31 +0000251 pj_bzero(addr->sin_zero, sizeof(addr->sin_zero));
Benny Prijono9033e312005-11-21 02:08:39 +0000252 pj_sockaddr_in_set_port(addr, port);
253 return pj_sockaddr_in_set_str_addr(addr, str_addr);
254}
255
256
257/*
258 * Get hostname.
259 */
260PJ_DEF(const pj_str_t*) pj_gethostname(void)
261{
262 static char buf[PJ_MAX_HOSTNAME];
263 static pj_str_t hostname;
264
265 PJ_CHECK_STACK();
266
267 if (hostname.ptr == NULL) {
268 hostname.ptr = buf;
269 if (gethostname(buf, sizeof(buf)) != 0) {
270 hostname.ptr[0] = '\0';
271 hostname.slen = 0;
272 } else {
273 hostname.slen = strlen(buf);
274 }
275 }
276 return &hostname;
277}
278
279/*
280 * Get first IP address associated with the hostname.
281 */
282PJ_DEF(pj_in_addr) pj_gethostaddr(void)
283{
284 pj_sockaddr_in addr;
285 const pj_str_t *hostname = pj_gethostname();
286
287 pj_sockaddr_in_set_str_addr(&addr, hostname);
288 return addr.sin_addr;
289}
290
291
292#if defined(PJ_WIN32)
293/*
294 * Create new socket/endpoint for communication and returns a descriptor.
295 */
296PJ_DEF(pj_status_t) pj_sock_socket(int af,
297 int type,
298 int proto,
299 pj_sock_t *sock)
300{
301 PJ_CHECK_STACK();
302
303 /* Sanity checks. */
304 PJ_ASSERT_RETURN(sock!=NULL, PJ_EINVAL);
305 PJ_ASSERT_RETURN((unsigned)PJ_INVALID_SOCKET==INVALID_SOCKET,
306 (*sock=PJ_INVALID_SOCKET, PJ_EINVAL));
307
308 *sock = WSASocket(af, type, proto, NULL, 0, WSA_FLAG_OVERLAPPED);
309
310 if (*sock == PJ_INVALID_SOCKET)
311 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
312 else
313 return PJ_SUCCESS;
314}
315
316#else
317/*
318 * Create new socket/endpoint for communication and returns a descriptor.
319 */
320PJ_DEF(pj_status_t) pj_sock_socket(int af,
321 int type,
322 int proto,
323 pj_sock_t *sock)
324{
325
326 PJ_CHECK_STACK();
327
328 /* Sanity checks. */
329 PJ_ASSERT_RETURN(sock!=NULL, PJ_EINVAL);
330 PJ_ASSERT_RETURN(PJ_INVALID_SOCKET==-1,
331 (*sock=PJ_INVALID_SOCKET, PJ_EINVAL));
332
333 *sock = socket(af, type, proto);
334 if (*sock == PJ_INVALID_SOCKET)
335 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
336 else
337 return PJ_SUCCESS;
338}
339#endif
340
341
342/*
343 * Bind socket.
344 */
345PJ_DEF(pj_status_t) pj_sock_bind( pj_sock_t sock,
346 const pj_sockaddr_t *addr,
347 int len)
348{
349 PJ_CHECK_STACK();
350
Benny Prijono42c5b9e2006-05-10 19:24:40 +0000351 PJ_ASSERT_RETURN(addr && len >= sizeof(struct sockaddr_in), PJ_EINVAL);
Benny Prijono9033e312005-11-21 02:08:39 +0000352
353 if (bind(sock, (struct sockaddr*)addr, len) != 0)
354 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
355 else
356 return PJ_SUCCESS;
357}
358
359
360/*
361 * Bind socket.
362 */
363PJ_DEF(pj_status_t) pj_sock_bind_in( pj_sock_t sock,
364 pj_uint32_t addr32,
365 pj_uint16_t port)
366{
367 pj_sockaddr_in addr;
368
369 PJ_CHECK_STACK();
370
Benny Prijonoe67d99a2006-03-20 12:39:24 +0000371 SET_LEN(&addr, sizeof(pj_sockaddr_in));
Benny Prijono9033e312005-11-21 02:08:39 +0000372 addr.sin_family = PJ_AF_INET;
Benny Prijonoac623b32006-07-03 15:19:31 +0000373 pj_bzero(addr.sin_zero, sizeof(addr.sin_zero));
Benny Prijono9033e312005-11-21 02:08:39 +0000374 addr.sin_addr.s_addr = pj_htonl(addr32);
375 addr.sin_port = pj_htons(port);
376
377 return pj_sock_bind(sock, &addr, sizeof(pj_sockaddr_in));
378}
379
380
381/*
382 * Close socket.
383 */
384PJ_DEF(pj_status_t) pj_sock_close(pj_sock_t sock)
385{
386 int rc;
387
388 PJ_CHECK_STACK();
Benny Prijono9cf138e2006-01-19 03:58:29 +0000389#if defined(PJ_WIN32) && PJ_WIN32!=0 || \
390 defined(PJ_WIN32_WINCE) && PJ_WIN32_WINCE!=0
Benny Prijono9033e312005-11-21 02:08:39 +0000391 rc = closesocket(sock);
392#else
393 rc = close(sock);
394#endif
395
396 if (rc != 0)
397 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
398 else
399 return PJ_SUCCESS;
400}
401
402/*
403 * Get remote's name.
404 */
405PJ_DEF(pj_status_t) pj_sock_getpeername( pj_sock_t sock,
406 pj_sockaddr_t *addr,
407 int *namelen)
408{
409 PJ_CHECK_STACK();
410 if (getpeername(sock, (struct sockaddr*)addr, (socklen_t*)namelen) != 0)
411 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
Benny Prijonoe67d99a2006-03-20 12:39:24 +0000412 else {
413 RESET_LEN(addr);
Benny Prijono9033e312005-11-21 02:08:39 +0000414 return PJ_SUCCESS;
Benny Prijonoe67d99a2006-03-20 12:39:24 +0000415 }
Benny Prijono9033e312005-11-21 02:08:39 +0000416}
417
418/*
419 * Get socket name.
420 */
421PJ_DEF(pj_status_t) pj_sock_getsockname( pj_sock_t sock,
422 pj_sockaddr_t *addr,
423 int *namelen)
424{
425 PJ_CHECK_STACK();
426 if (getsockname(sock, (struct sockaddr*)addr, (socklen_t*)namelen) != 0)
427 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
Benny Prijonoe67d99a2006-03-20 12:39:24 +0000428 else {
429 RESET_LEN(addr);
Benny Prijono9033e312005-11-21 02:08:39 +0000430 return PJ_SUCCESS;
Benny Prijonoe67d99a2006-03-20 12:39:24 +0000431 }
Benny Prijono9033e312005-11-21 02:08:39 +0000432}
433
434/*
435 * Send data
436 */
437PJ_DEF(pj_status_t) pj_sock_send(pj_sock_t sock,
438 const void *buf,
439 pj_ssize_t *len,
440 unsigned flags)
441{
442 PJ_CHECK_STACK();
443 PJ_ASSERT_RETURN(len, PJ_EINVAL);
444
445 *len = send(sock, (const char*)buf, *len, flags);
446
447 if (*len < 0)
448 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
449 else
450 return PJ_SUCCESS;
451}
452
453
454/*
455 * Send data.
456 */
457PJ_DEF(pj_status_t) pj_sock_sendto(pj_sock_t sock,
458 const void *buf,
459 pj_ssize_t *len,
460 unsigned flags,
461 const pj_sockaddr_t *to,
462 int tolen)
463{
464 PJ_CHECK_STACK();
465 PJ_ASSERT_RETURN(len, PJ_EINVAL);
466
467 *len = sendto(sock, (const char*)buf, *len, flags,
468 (const struct sockaddr*)to, tolen);
469
470 if (*len < 0)
471 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
472 else
473 return PJ_SUCCESS;
474}
475
476/*
477 * Receive data.
478 */
479PJ_DEF(pj_status_t) pj_sock_recv(pj_sock_t sock,
480 void *buf,
481 pj_ssize_t *len,
482 unsigned flags)
483{
484 PJ_CHECK_STACK();
485 PJ_ASSERT_RETURN(buf && len, PJ_EINVAL);
486
487 *len = recv(sock, (char*)buf, *len, flags);
488
489 if (*len < 0)
490 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
491 else
492 return PJ_SUCCESS;
493}
494
495/*
496 * Receive data.
497 */
498PJ_DEF(pj_status_t) pj_sock_recvfrom(pj_sock_t sock,
499 void *buf,
500 pj_ssize_t *len,
501 unsigned flags,
502 pj_sockaddr_t *from,
503 int *fromlen)
504{
505 PJ_CHECK_STACK();
506 PJ_ASSERT_RETURN(buf && len, PJ_EINVAL);
507 PJ_ASSERT_RETURN(from && fromlen, (*len=-1, PJ_EINVAL));
508
509 *len = recvfrom(sock, (char*)buf, *len, flags,
510 (struct sockaddr*)from, (socklen_t*)fromlen);
511
512 if (*len < 0)
513 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
Benny Prijonoe67d99a2006-03-20 12:39:24 +0000514 else {
515 RESET_LEN(from);
Benny Prijono9033e312005-11-21 02:08:39 +0000516 return PJ_SUCCESS;
Benny Prijonoe67d99a2006-03-20 12:39:24 +0000517 }
Benny Prijono9033e312005-11-21 02:08:39 +0000518}
519
520/*
521 * Get socket option.
522 */
523PJ_DEF(pj_status_t) pj_sock_getsockopt( pj_sock_t sock,
524 pj_uint16_t level,
525 pj_uint16_t optname,
526 void *optval,
527 int *optlen)
528{
529 PJ_CHECK_STACK();
530 PJ_ASSERT_RETURN(optval && optlen, PJ_EINVAL);
531
532 if (getsockopt(sock, level, optname, (char*)optval, (socklen_t*)optlen)!=0)
533 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
534 else
535 return PJ_SUCCESS;
536}
537
538/*
539 * Set socket option.
540 */
541PJ_DEF(pj_status_t) pj_sock_setsockopt( pj_sock_t sock,
542 pj_uint16_t level,
543 pj_uint16_t optname,
544 const void *optval,
545 int optlen)
546{
547 PJ_CHECK_STACK();
548 if (setsockopt(sock, level, optname, (const char*)optval, optlen) != 0)
549 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
550 else
551 return PJ_SUCCESS;
552}
553
554/*
Benny Prijono3d327302006-02-08 11:14:03 +0000555 * Connect socket.
556 */
557PJ_DEF(pj_status_t) pj_sock_connect( pj_sock_t sock,
558 const pj_sockaddr_t *addr,
559 int namelen)
560{
561 PJ_CHECK_STACK();
562 if (connect(sock, (struct sockaddr*)addr, namelen) != 0)
563 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
564 else
565 return PJ_SUCCESS;
566}
567
568
569/*
Benny Prijono9033e312005-11-21 02:08:39 +0000570 * Shutdown socket.
571 */
572#if PJ_HAS_TCP
573PJ_DEF(pj_status_t) pj_sock_shutdown( pj_sock_t sock,
574 int how)
575{
576 PJ_CHECK_STACK();
577 if (shutdown(sock, how) != 0)
578 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
579 else
580 return PJ_SUCCESS;
581}
582
583/*
584 * Start listening to incoming connections.
585 */
586PJ_DEF(pj_status_t) pj_sock_listen( pj_sock_t sock,
587 int backlog)
588{
589 PJ_CHECK_STACK();
590 if (listen(sock, backlog) != 0)
591 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
592 else
593 return PJ_SUCCESS;
594}
595
596/*
Benny Prijono9033e312005-11-21 02:08:39 +0000597 * Accept incoming connections
598 */
599PJ_DEF(pj_status_t) pj_sock_accept( pj_sock_t serverfd,
600 pj_sock_t *newsock,
601 pj_sockaddr_t *addr,
602 int *addrlen)
603{
604 PJ_CHECK_STACK();
605 PJ_ASSERT_RETURN(newsock != NULL, PJ_EINVAL);
606
Benny Prijonoe67d99a2006-03-20 12:39:24 +0000607#if defined(PJ_SOCKADDR_HAS_LEN) && PJ_SOCKADDR_HAS_LEN!=0
608 if (addr) {
609 SET_LEN(addr, *addrlen);
610 }
611#endif
612
Benny Prijono9033e312005-11-21 02:08:39 +0000613 *newsock = accept(serverfd, (struct sockaddr*)addr, (socklen_t*)addrlen);
614 if (*newsock==PJ_INVALID_SOCKET)
615 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
Benny Prijonoe67d99a2006-03-20 12:39:24 +0000616 else {
617
618#if defined(PJ_SOCKADDR_HAS_LEN) && PJ_SOCKADDR_HAS_LEN!=0
619 if (addr) {
620 RESET_LEN(addr);
621 }
622#endif
623
Benny Prijono9033e312005-11-21 02:08:39 +0000624 return PJ_SUCCESS;
Benny Prijonoe67d99a2006-03-20 12:39:24 +0000625 }
Benny Prijono9033e312005-11-21 02:08:39 +0000626}
627#endif /* PJ_HAS_TCP */
628
629