2 * author: rofl0r (C) 2011-2013
3 * License: LGPL 2.1+ with static linking exception
7 * recognized defines: USE_SSL, ROCKSOCK_FILENAME, NO_DNS_SUPPORT, NO_STRDUP
10 #undef _POSIX_C_SOURCE
11 #define _POSIX_C_SOURCE 200809L
21 #include <sys/select.h>
22 #include <netinet/in.h>
25 #include "rocksock_internal.h"
26 #include "../lib/include/strlib.h"
28 #ifndef ROCKSOCK_FILENAME
29 #define ROCKSOCK_FILENAME __FILE__
33 #define MSG_NOSIGNAL 0
37 #include "rocksock_ssl_internal.h"
40 int rocksock_seterror(rocksock
* sock
, rs_errorType errortype
, int error
, const char* file
, int line
) {
41 if (!sock
) return RS_E_NULL
;
42 sock
->lasterror
.errortype
= errortype
;
43 sock
->lasterror
.error
= error
;
44 sock
->lasterror
.line
= line
;
45 sock
->lasterror
.file
= file
;
46 sock
->lasterror
.failedProxy
= -1;
48 #ifndef NO_DNS_SUPPORT
50 sock
->lasterror
.errormsg
= (char*) gai_strerror(error
);
54 if (error
< RS_E_MAX_ERROR
)
55 sock
->lasterror
.errormsg
= (char*) rs_errorMap
[error
];
57 sock
->lasterror
.errormsg
= NULL
;
60 sock
->lasterror
.errormsg
= strerror(error
);
64 sock
->lasterror
.errormsg
= (char*) rocksock_ssl_strerror(sock
, error
);
68 sock
->lasterror
.errormsg
= NULL
;
73 //#define NO_DNS_SUPPORT
74 static int rocksock_resolve_host(rocksock
* sock
, rs_hostInfo
* hostinfo
) {
75 #ifndef NO_DNS_SUPPORT
76 struct addrinfo hints
;
79 if (!sock
) return RS_E_NULL
;
80 if (!hostinfo
|| !hostinfo
->host
|| !hostinfo
->port
) return rocksock_seterror(sock
, RS_ET_OWN
, RS_E_NULL
, ROCKSOCK_FILENAME
, __LINE__
);;
81 #ifndef NO_DNS_SUPPORT
82 memset(&hints
, 0, sizeof(hints
));
83 hints
.ai_family
= AF_UNSPEC
;
84 hints
.ai_socktype
= SOCK_STREAM
;
85 ret
= getaddrinfo(hostinfo
->host
, NULL
, &hints
, &hostinfo
->hostaddr
);
87 if(hostinfo
->hostaddr
->ai_addr
->sa_family
== AF_INET
)
88 ((struct sockaddr_in
*) hostinfo
->hostaddr
->ai_addr
)->sin_port
= htons(hostinfo
->port
);
90 ((struct sockaddr_in6
*) hostinfo
->hostaddr
->ai_addr
)->sin6_port
= htons(hostinfo
->port
);
93 return rocksock_seterror(sock
, RS_ET_GAI
, ret
, ROCKSOCK_FILENAME
, __LINE__
);
95 hostinfo
->hostaddr
= &(hostinfo
->hostaddr_buf
);
96 hostinfo
->hostaddr
->ai_addr
= (struct sockaddr
*) &(hostinfo
->hostaddr_aiaddr_buf
);
97 ((struct sockaddr_in
*) hostinfo
->hostaddr
->ai_addr
)->sin_port
= htons(hostinfo
->port
);
98 ((struct sockaddr_in
*) hostinfo
->hostaddr
->ai_addr
)->sin_family
= AF_INET
;
99 hostinfo
->hostaddr
->ai_addr
->sa_family
= AF_INET
;
100 hostinfo
->hostaddr
->ai_addrlen
= sizeof(struct sockaddr_in
);
101 ipv4fromstring(hostinfo
->host
, (unsigned char*) &((struct sockaddr_in
*) hostinfo
->hostaddr
->ai_addr
)->sin_addr
);
107 int rocksock_set_timeout(rocksock
* sock
, unsigned long timeout_millisec
) {
108 if (!sock
) return RS_E_NULL
;
109 sock
->timeout
= timeout_millisec
;
110 return rocksock_seterror(sock
, RS_ET_NO_ERROR
, 0, NULL
, 0);
113 int rocksock_init(rocksock
* sock
) {
114 if (!sock
) return RS_E_NULL
;
115 memset(sock
, 0, sizeof(rocksock
));
116 sock
->lastproxy
= -1;
117 sock
->timeout
= 60*1000;
118 return rocksock_seterror(sock
, RS_ET_NO_ERROR
, 0, NULL
, 0);
121 static struct timeval
* make_timeval(struct timeval
* tv
, unsigned long timeout
) {
123 tv
->tv_sec
= timeout
/ 1000;
124 tv
->tv_usec
= 1000 * (timeout
% 1000);
128 static int do_connect(rocksock
* sock
, rs_hostInfo
* hostinfo
, unsigned long timeout
) {
133 socklen_t optlen
= sizeof(optval
);
135 sock
->socket
= socket(hostinfo
->hostaddr
->ai_family
, SOCK_STREAM
, 0);
136 if(sock
->socket
== -1) return rocksock_seterror(sock
, RS_ET_SYS
, errno
, ROCKSOCK_FILENAME
, __LINE__
);
138 flags
= fcntl(sock
->socket
, F_GETFL
);
139 if(flags
== -1) return rocksock_seterror(sock
, RS_ET_SYS
, errno
, ROCKSOCK_FILENAME
, __LINE__
);
141 if(fcntl(sock
->socket
, F_SETFL
, flags
| O_NONBLOCK
) == -1) return errno
;
143 ret
= connect(sock
->socket
, hostinfo
->hostaddr
->ai_addr
, hostinfo
->hostaddr
->ai_addrlen
);
146 if (!(ret
== EINPROGRESS
|| ret
== EWOULDBLOCK
)) return rocksock_seterror(sock
, RS_ET_SYS
, ret
, ROCKSOCK_FILENAME
, __LINE__
);
149 if(fcntl(sock
->socket
, F_SETFL
, flags
) == -1) return rocksock_seterror(sock
, RS_ET_SYS
, errno
, ROCKSOCK_FILENAME
, __LINE__
);
152 FD_SET(sock
->socket
, &wset
);
154 ret
= select(sock
->socket
+1, NULL
, &wset
, NULL
, timeout
? make_timeval(&tv
, timeout
) : NULL
);
156 if(ret
== 1 && FD_ISSET(sock
->socket
, &wset
)) {
157 ret
= getsockopt(sock
->socket
, SOL_SOCKET
, SO_ERROR
, &optval
,&optlen
);
158 if(ret
== -1) return rocksock_seterror(sock
, RS_ET_SYS
, errno
, ROCKSOCK_FILENAME
, __LINE__
);
159 else if(optval
) return rocksock_seterror(sock
, RS_ET_SYS
, optval
, ROCKSOCK_FILENAME
, __LINE__
);
161 } else if(ret
== 0) return rocksock_seterror(sock
, RS_ET_OWN
, RS_E_HIT_CONNECTTIMEOUT
, ROCKSOCK_FILENAME
, __LINE__
);
163 return rocksock_seterror(sock
, RS_ET_SYS
, errno
, ROCKSOCK_FILENAME
, __LINE__
);
166 static int rocksock_setup_socks4_header(rocksock
* sock
, int is4a
, char* buffer
, size_t bufsize
, rs_proxy
* proxy
, size_t* bytesused
) {
170 buffer
[2] = proxy
->hostinfo
.port
/ 256;
171 buffer
[3] = proxy
->hostinfo
.port
% 256;
179 ret
= rocksock_resolve_host(sock
, &proxy
->hostinfo
);
181 if(proxy
->hostinfo
.hostaddr
->ai_family
!= AF_INET
)
182 return rocksock_seterror(sock
, RS_ET_OWN
, RS_E_SOCKS4_NO_IP6
, ROCKSOCK_FILENAME
, __LINE__
);
183 buffer
[4] = ((char*) &(((struct sockaddr_in
*) proxy
->hostinfo
.hostaddr
->ai_addr
)->sin_addr
.s_addr
))[0];
184 buffer
[5] = ((char*) &(((struct sockaddr_in
*) proxy
->hostinfo
.hostaddr
->ai_addr
)->sin_addr
.s_addr
))[1];
185 buffer
[6] = ((char*) &(((struct sockaddr_in
*) proxy
->hostinfo
.hostaddr
->ai_addr
)->sin_addr
.s_addr
))[2];
186 buffer
[7] = ((char*) &(((struct sockaddr_in
*) proxy
->hostinfo
.hostaddr
->ai_addr
)->sin_addr
.s_addr
))[3];
190 if(is4a
) *bytesused
+= strlen(strncpy(buffer
+ *bytesused
, proxy
->hostinfo
.host
, bufsize
- *bytesused
))+1;
192 return rocksock_seterror(sock
, RS_ET_NO_ERROR
, 0, NULL
, 0);
195 int rocksock_connect(rocksock
* sock
, char* host
, unsigned short port
, int useSSL
) {
197 int ret
, trysocksv4a
;
198 rs_hostInfo
* connector
;
200 rs_proxy
* targetproxy
;
203 size_t socksused
= 0, bytes
;
204 if (!sock
) return RS_E_NULL
;
206 return rocksock_seterror(sock
, RS_ET_OWN
, RS_E_NULL
, ROCKSOCK_FILENAME
, __LINE__
);
208 if (useSSL
) return rocksock_seterror(sock
, RS_ET_OWN
, RS_E_NO_SSL
, ROCKSOCK_FILENAME
, __LINE__
);
211 sock
->hostinfo
.host
= host
;
213 sock
->hostinfo
.host
= strdup(host
);
215 sock
->hostinfo
.port
= port
;
217 if(sock
->lastproxy
>= 0)
218 connector
= &sock
->proxies
[0].hostinfo
;
220 connector
= &sock
->hostinfo
;
222 ret
= rocksock_resolve_host(sock
, connector
);
224 check_proxy0_failure
:
225 if(sock
->lastproxy
>= 0) sock
->lasterror
.failedProxy
= 0;
229 ret
= do_connect(sock
, connector
, sock
->timeout
);
230 if(ret
) goto check_proxy0_failure
;
232 if(sock
->lastproxy
>= 0) {
233 dummy
.hostinfo
= sock
->hostinfo
;
234 dummy
.password
= NULL
;
235 dummy
.username
= NULL
;
236 dummy
.proxytype
= RS_PT_NONE
;
237 for(i
=1;i
<=sock
->lastproxy
+1;i
++) {
238 if(i
> sock
->lastproxy
)
239 targetproxy
= &dummy
;
241 targetproxy
= &sock
->proxies
[i
];
242 // send socks connection data
243 switch(sock
->proxies
[i
-1].proxytype
) {
247 ret
= rocksock_setup_socks4_header(sock
, trysocksv4a
, socksdata
, sizeof(socksdata
), targetproxy
, &socksused
);
250 sock
->lasterror
.failedProxy
= i
- 1;
253 ret
= rocksock_send(sock
, socksdata
, socksused
, 0, &bytes
);
254 if(ret
) goto proxyfailure
;
255 ret
= rocksock_recv(sock
, socksdata
, 8, 8, &bytes
);
256 if(ret
) goto proxyfailure
;
257 if(bytes
< 8 || socksdata
[0] != 0) {
258 ret
= rocksock_seterror(sock
, RS_ET_OWN
, RS_E_PROXY_UNEXPECTED_RESPONSE
, ROCKSOCK_FILENAME
, __LINE__
);
261 switch(socksdata
[1]) {
269 ret
= rocksock_seterror(sock
, RS_ET_OWN
, RS_E_TARGETPROXY_CONNECT_FAILED
, ROCKSOCK_FILENAME
, __LINE__
);
271 case 0x5c: case 0x5d:
272 ret
= rocksock_seterror(sock
, RS_ET_OWN
, RS_E_PROXY_AUTH_FAILED
, ROCKSOCK_FILENAME
, __LINE__
);
275 ret
= rocksock_seterror(sock
, RS_ET_OWN
, RS_E_PROXY_UNEXPECTED_RESPONSE
, ROCKSOCK_FILENAME
, __LINE__
);
282 if(sock
->proxies
[i
-1].username
&& sock
->proxies
[i
-1].password
) {
290 bytes
= p
- socksdata
;
291 ret
= rocksock_send(sock
, socksdata
, bytes
, bytes
, &bytes
);
292 if(ret
) goto proxyfailure
;
293 ret
= rocksock_recv(sock
, socksdata
, 2, 2, &bytes
);
294 if(ret
) goto proxyfailure
;
295 if(bytes
< 2 || socksdata
[0] != 5) {
296 ret
= rocksock_seterror(sock
, RS_ET_OWN
, RS_E_PROXY_UNEXPECTED_RESPONSE
, ROCKSOCK_FILENAME
, __LINE__
);
299 if(socksdata
[1] == '\xff') {
300 ret
= rocksock_seterror(sock
, RS_ET_OWN
, RS_E_PROXY_AUTH_FAILED
, ROCKSOCK_FILENAME
, __LINE__
);
302 } else if (socksdata
[1] == 2) {
303 if( sock
->proxies
[i
-1].username
&& sock
->proxies
[i
-1].password
&&
304 *sock
->proxies
[i
-1].username
&& *sock
->proxies
[i
-1].password
) {
306 +----+------+----------+------+----------+
307 |VER | ULEN | UNAME | PLEN | PASSWD |
308 +----+------+----------+------+----------+
309 | 1 | 1 | 1 to 255 | 1 | 1 to 255 |
310 +----+------+----------+------+----------+
314 bytes
= strlen(sock
->proxies
[i
-1].username
) & 0xFF;
316 memcpy(p
, sock
->proxies
[i
-1].username
, bytes
);
318 bytes
= strlen(sock
->proxies
[i
-1].password
) & 0xFF;
320 memcpy(p
, sock
->proxies
[i
-1].password
, bytes
);
322 bytes
= p
- socksdata
;
323 ret
= rocksock_send(sock
, socksdata
, bytes
, bytes
, &bytes
);
324 if(ret
) goto proxyfailure
;
325 ret
= rocksock_recv(sock
, socksdata
, 2, 2, &bytes
);
326 if(ret
) goto proxyfailure
;
328 ret
= rocksock_seterror(sock
, RS_ET_OWN
, RS_E_PROXY_UNEXPECTED_RESPONSE
, ROCKSOCK_FILENAME
, __LINE__
);
330 } else if(socksdata
[1] != 0) {
331 ret
= rocksock_seterror(sock
, RS_ET_OWN
, RS_E_PROXY_AUTH_FAILED
, ROCKSOCK_FILENAME
, __LINE__
);
335 ret
= rocksock_seterror(sock
, RS_ET_OWN
, RS_E_PROXY_AUTH_FAILED
, ROCKSOCK_FILENAME
, __LINE__
);
343 if(isnumericipv4(targetproxy
->hostinfo
.host
)) {
344 *p
++ = 1; // ipv4 method
346 ipv4fromstring(targetproxy
->hostinfo
.host
, (unsigned char*) p
);
348 *p
++ = 3; //hostname method, requires the server to do dns lookups.
349 bytes
= strlen(targetproxy
->hostinfo
.host
);
351 return rocksock_seterror(sock
, RS_ET_OWN
, RS_E_SOCKS5_AUTH_EXCEEDSIZE
, ROCKSOCK_FILENAME
, __LINE__
);
353 memcpy(p
, targetproxy
->hostinfo
.host
, bytes
);
356 *p
++ = targetproxy
->hostinfo
.port
/ 256;
357 *p
++ = targetproxy
->hostinfo
.port
% 256;
358 bytes
= p
- socksdata
;
359 ret
= rocksock_send(sock
, socksdata
, bytes
, bytes
, &bytes
);
360 if(ret
) goto proxyfailure
;
361 ret
= rocksock_recv(sock
, socksdata
, sizeof(socksdata
), sizeof(socksdata
), &bytes
);
362 if(ret
) goto proxyfailure
;
364 ret
= rocksock_seterror(sock
, RS_ET_OWN
, RS_E_PROXY_UNEXPECTED_RESPONSE
, ROCKSOCK_FILENAME
, __LINE__
);
367 switch(socksdata
[1]) {
371 ret
= rocksock_seterror(sock
, RS_ET_OWN
, RS_E_PROXY_GENERAL_FAILURE
, ROCKSOCK_FILENAME
, __LINE__
);
374 ret
= rocksock_seterror(sock
, RS_ET_OWN
, RS_E_PROXY_AUTH_FAILED
, ROCKSOCK_FILENAME
, __LINE__
);
377 ret
= rocksock_seterror(sock
, RS_ET_OWN
, RS_E_TARGETPROXY_NET_UNREACHABLE
, ROCKSOCK_FILENAME
, __LINE__
);
380 ret
= rocksock_seterror(sock
, RS_ET_OWN
, RS_E_TARGETPROXY_HOST_UNREACHABLE
, ROCKSOCK_FILENAME
, __LINE__
);
383 ret
= rocksock_seterror(sock
, RS_ET_OWN
, RS_E_TARGETPROXY_CONN_REFUSED
, ROCKSOCK_FILENAME
, __LINE__
);
386 ret
= rocksock_seterror(sock
, RS_ET_OWN
, RS_E_TARGETPROXY_TTL_EXPIRED
, ROCKSOCK_FILENAME
, __LINE__
);
389 ret
= rocksock_seterror(sock
, RS_ET_OWN
, RS_E_PROXY_COMMAND_NOT_SUPPORTED
, ROCKSOCK_FILENAME
, __LINE__
);
392 ret
= rocksock_seterror(sock
, RS_ET_OWN
, RS_E_PROXY_ADDRESSTYPE_NOT_SUPPORTED
, ROCKSOCK_FILENAME
, __LINE__
);
395 ret
= rocksock_seterror(sock
, RS_ET_OWN
, RS_E_PROXY_UNEXPECTED_RESPONSE
, ROCKSOCK_FILENAME
, __LINE__
);
400 bytes
= ulz_snprintf(socksdata
, sizeof(socksdata
), "CONNECT %s:%d HTTP/1.1\r\n\r\n", targetproxy
->hostinfo
.host
, targetproxy
->hostinfo
.port
);
401 ret
= rocksock_send(sock
, socksdata
, bytes
, bytes
, &bytes
);
402 if(ret
) goto proxyfailure
;
403 ret
= rocksock_recv(sock
, socksdata
, sizeof(socksdata
), sizeof(socksdata
), &bytes
);
404 if(ret
) goto proxyfailure
;
406 ret
= rocksock_seterror(sock
, RS_ET_OWN
, RS_E_PROXY_UNEXPECTED_RESPONSE
, ROCKSOCK_FILENAME
, __LINE__
);
409 if(socksdata
[9] != '2') {
410 ret
= rocksock_seterror(sock
, RS_ET_OWN
, RS_E_TARGETPROXY_CONNECT_FAILED
, ROCKSOCK_FILENAME
, __LINE__
);
421 ret
= rocksock_ssl_connect_fd(sock
);
425 return rocksock_seterror(sock
, RS_ET_NO_ERROR
, 0, NULL
, 0);
433 static int rocksock_operation(rocksock
* sock
, rs_operationType operation
, char* buffer
, size_t bufsize
, size_t chunksize
, size_t* bytes
) {
434 if (!sock
) return RS_E_NULL
;
435 if (!buffer
|| !bytes
|| (!bufsize
&& operation
== RS_OT_READ
)) return rocksock_seterror(sock
, RS_ET_OWN
, RS_E_NULL
, ROCKSOCK_FILENAME
, __LINE__
);
442 size_t bytesleft
= bufsize
? bufsize
: strlen(buffer
);
444 char* bufptr
= buffer
;
446 if (!sock
->socket
) return rocksock_seterror(sock
, RS_ET_OWN
, RS_E_NO_SOCKET
, ROCKSOCK_FILENAME
, __LINE__
);
447 if(operation
== RS_OT_SEND
) wfd
= &fd
;
451 if(operation
== RS_OT_SEND
)
452 ret
= setsockopt(sock
->socket
, SOL_SOCKET
, SO_SNDTIMEO
, (void*) make_timeval(&tv
, sock
->timeout
), sizeof(tv
));
454 ret
= setsockopt(sock
->socket
, SOL_SOCKET
, SO_RCVTIMEO
, (void*) make_timeval(&tv
, sock
->timeout
), sizeof(tv
));
457 if (ret
== -1) return rocksock_seterror(sock
, RS_ET_SYS
, errno
, ROCKSOCK_FILENAME
, __LINE__
);
460 FD_SET(sock
->socket
, &fd
);
461 ret
=select(sock
->socket
+1, rfd
, wfd
, NULL
, sock
->timeout
? make_timeval(&tv
, sock
->timeout
) : NULL
);
462 if(!FD_ISSET(sock
->socket
, &fd
)) rocksock_seterror(sock
, RS_ET_OWN
, RS_E_NULL
, ROCKSOCK_FILENAME
, __LINE__
); // temp test
464 //printf("h: %s, skt: %d, to: %d:%d\n", sock->hostinfo.host, sock->socket, tv.tv_sec, tv.tv_usec);
465 return rocksock_seterror(sock
, RS_ET_SYS
, errno
, ROCKSOCK_FILENAME
, __LINE__
);
467 else if(!ret
) return rocksock_seterror(sock
, RS_ET_OWN
, RS_OT_READ
? RS_E_HIT_READTIMEOUT
: RS_E_HIT_WRITETIMEOUT
, ROCKSOCK_FILENAME
, __LINE__
);
468 byteswanted
= (chunksize
&& chunksize
< bytesleft
) ? chunksize
: bytesleft
;
471 if(operation
== RS_OT_SEND
)
472 ret
= rocksock_ssl_send(sock
, bufptr
, byteswanted
);
474 ret
= rocksock_ssl_recv(sock
, bufptr
, byteswanted
);
478 if(operation
== RS_OT_SEND
)
479 ret
= send(sock
->socket
, bufptr
, byteswanted
, MSG_NOSIGNAL
);
481 ret
= recv(sock
->socket
, bufptr
, byteswanted
, 0);
483 if(!ret
) // The return value will be 0 when the peer has performed an orderly shutdown.
484 //return rocksock_seterror(sock, RS_ET_SYS, errno, ROCKSOCK_FILENAME, __LINE__);
488 if(ret
== EWOULDBLOCK
|| ret
== EINPROGRESS
) return rocksock_seterror(sock
, RS_ET_OWN
, RS_OT_READ
? RS_E_HIT_READTIMEOUT
: RS_E_HIT_WRITETIMEOUT
, ROCKSOCK_FILENAME
, __LINE__
);
489 return rocksock_seterror(sock
, RS_ET_SYS
, errno
, ROCKSOCK_FILENAME
, __LINE__
);
495 if(operation
== RS_OT_READ
&& (size_t) ret
< byteswanted
) break;
497 return rocksock_seterror(sock
, RS_ET_NO_ERROR
, 0, NULL
, 0);
500 int rocksock_send(rocksock
* sock
, char* buffer
, size_t bufsize
, size_t chunksize
, size_t* byteswritten
) {
501 return rocksock_operation(sock
, RS_OT_SEND
, buffer
, bufsize
, chunksize
, byteswritten
);
504 int rocksock_recv(rocksock
* sock
, char* buffer
, size_t bufsize
, size_t chunksize
, size_t* bytesread
) {
505 return rocksock_operation(sock
, RS_OT_READ
, buffer
, bufsize
, chunksize
, bytesread
);
508 int rocksock_disconnect(rocksock
* sock
) {
509 if (!sock
) return RS_E_NULL
;
511 rocksock_ssl_free_context(sock
);
513 if(sock
->socket
) close(sock
->socket
);
515 return rocksock_seterror(sock
, RS_ET_NO_ERROR
, 0, NULL
, 0);
518 int rocksock_clear(rocksock
* sock
) {
519 if (!sock
) return RS_E_NULL
;
521 if(sock
->lastproxy
>= 0) {
522 for (i
=0;i
<=sock
->lastproxy
;i
++) {
524 if(sock
->proxies
[i
].username
)
525 free(sock
->proxies
[i
].username
);
526 if(sock
->proxies
[i
].password
)
527 free(sock
->proxies
[i
].password
);
528 if(sock
->proxies
[i
].hostinfo
.host
)
529 free(sock
->proxies
[i
].hostinfo
.host
);
531 sock
->proxies
[i
].username
= NULL
;
532 sock
->proxies
[i
].password
= NULL
;
533 sock
->proxies
[i
].hostinfo
.host
= NULL
;
534 #ifndef NO_DNS_SUPPORT
535 if(sock
->proxies
[i
].hostinfo
.hostaddr
)
536 freeaddrinfo(sock
->proxies
[i
].hostinfo
.hostaddr
);
538 sock
->proxies
[i
].hostinfo
.hostaddr
= NULL
;
542 if(sock
->hostinfo
.host
)
543 free(sock
->hostinfo
.host
);
545 sock
->hostinfo
.host
= NULL
;
546 #ifndef NO_DNS_SUPPORT
547 if(sock
->hostinfo
.hostaddr
)
548 freeaddrinfo(sock
->hostinfo
.hostaddr
);
550 sock
->hostinfo
.hostaddr
= NULL
;
552 return rocksock_seterror(sock
, RS_ET_NO_ERROR
, 0, NULL
, 0);