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 #warning compiling without SOCK_CLOEXEC support
26 #define SOCK_CLOEXEC 0
30 #include "rocksock_internal.h"
32 //RcB: SKIPUON "USE_LIBULZ"
33 #include <ulz/strlib.h>
34 #include <ulz/stdio-repl.h>
35 //RcB: SKIPUOFF "USE_LIBULZ"
37 /* this version of ipv4fromstring was taken from libulz and tuned to be
38 more pedantic than the libulz version, so it can be used for isnumericipv4()
39 as well, as it strictly checks the input for correctness. */
40 static int ipv4fromstring(const char* ipstring
, unsigned char* fourbytesptr
) {
41 const char* start
= ipstring
;
44 if(*ipstring
== '.' || !*ipstring
) {
45 fourbytesptr
[outbyte
] = 0;
48 switch(ipstring
- start
) {
50 tmp
= (start
[b
++]-'0')*100;
51 if(tmp
> 200) return 0;
52 fourbytesptr
[outbyte
] += tmp
;
54 fourbytesptr
[outbyte
] += (start
[b
++]-'0')*10;
56 fourbytesptr
[outbyte
] += (start
[b
++]-'0');
64 if(*ipstring
< '0' || *ipstring
> '9') return 0;
66 if(!*ipstring
&& outbyte
< 4) return 0;
69 if(ipstring
[-1]) return 0;
73 static int isnumericipv4(const char* ipstring
) {
75 return ipv4fromstring(ipstring
, ip
);
79 #ifndef ROCKSOCK_FILENAME
80 #define ROCKSOCK_FILENAME __FILE__
84 #define MSG_NOSIGNAL 0
88 #include "rocksock_ssl_internal.h"
91 int rocksock_seterror(rocksock
* sock
, rs_errorType errortype
, int error
, const char* file
, int line
) {
92 if (!sock
) return RS_E_NULL
;
93 sock
->lasterror
.errortype
= errortype
;
94 sock
->lasterror
.error
= error
;
95 sock
->lasterror
.line
= line
;
96 sock
->lasterror
.file
= file
;
97 sock
->lasterror
.failedProxy
= -1;
100 //#define NO_DNS_SUPPORT
101 static int rocksock_resolve_host(rocksock
* sock
, rs_hostInfo
* hostinfo
, rs_resolveStorage
* result
) {
102 if (!sock
) return RS_E_NULL
;
103 if (!hostinfo
|| !hostinfo
->host
|| !hostinfo
->port
) return rocksock_seterror(sock
, RS_ET_OWN
, RS_E_NULL
, ROCKSOCK_FILENAME
, __LINE__
);;
105 result
->hostaddr
= &(result
->hostaddr_buf
);
107 #ifndef NO_DNS_SUPPORT
108 struct addrinfo hints
= {.ai_family
= AF_UNSPEC
, .ai_socktype
= SOCK_STREAM
, .ai_flags
= AI_ADDRCONFIG
};
110 struct addrinfo
*best
, *save
;
111 ret
= getaddrinfo(hostinfo
->host
, NULL
, &hints
, &save
);
114 while(best
->ai_addr
->sa_family
== AF_INET6
&& best
->ai_next
) best
= best
->ai_next
;
115 *result
->hostaddr
= *best
;
116 result
->hostaddr
->ai_addr
= (struct sockaddr
*) &(result
->hostaddr_aiaddr_buf
);
117 result
->hostaddr
->ai_next
= 0;
118 *result
->hostaddr
->ai_addr
= *best
->ai_addr
;
120 if(result
->hostaddr
->ai_addr
->sa_family
== AF_INET
)
121 ((struct sockaddr_in
*) result
->hostaddr
->ai_addr
)->sin_port
= htons(hostinfo
->port
);
123 ((struct sockaddr_in6
*) result
->hostaddr
->ai_addr
)->sin6_port
= htons(hostinfo
->port
);
127 return rocksock_seterror(sock
, RS_ET_GAI
, ret
, ROCKSOCK_FILENAME
, __LINE__
);
129 result
->hostaddr
->ai_addr
= (struct sockaddr
*) &(result
->hostaddr_aiaddr_buf
);
131 ((struct sockaddr_in
*) result
->hostaddr
->ai_addr
)->sin_port
= htons(hostinfo
->port
);
132 ((struct sockaddr_in
*) result
->hostaddr
->ai_addr
)->sin_family
= AF_INET
;
133 result
->hostaddr
->ai_addr
->sa_family
= AF_INET
;
134 result
->hostaddr
->ai_addrlen
= sizeof(struct sockaddr_in
);
135 ipv4fromstring(hostinfo
->host
, (unsigned char*) &((struct sockaddr_in
*) result
->hostaddr
->ai_addr
)->sin_addr
);
141 int rocksock_set_timeout(rocksock
* sock
, unsigned long timeout_millisec
) {
142 if (!sock
) return RS_E_NULL
;
143 sock
->timeout
= timeout_millisec
;
144 return rocksock_seterror(sock
, RS_ET_OWN
, 0, NULL
, 0);
147 int rocksock_init(rocksock
* sock
) {
148 if (!sock
) return RS_E_NULL
;
149 memset(sock
, 0, sizeof(rocksock
));
150 sock
->lastproxy
= -1;
151 sock
->timeout
= 60*1000;
152 return rocksock_seterror(sock
, RS_ET_OWN
, 0, NULL
, 0);
155 static struct timeval
* make_timeval(struct timeval
* tv
, unsigned long timeout
) {
157 tv
->tv_sec
= timeout
/ 1000;
158 tv
->tv_usec
= 1000 * (timeout
% 1000);
162 static int do_connect(rocksock
* sock
, rs_resolveStorage
* hostinfo
, unsigned long timeout
) {
167 socklen_t optlen
= sizeof(optval
);
169 sock
->socket
= socket(hostinfo
->hostaddr
->ai_family
, SOCK_STREAM
| SOCK_CLOEXEC
, 0);
170 if(sock
->socket
== -1) return rocksock_seterror(sock
, RS_ET_SYS
, errno
, ROCKSOCK_FILENAME
, __LINE__
);
172 /* the socket has to be made non-blocking temporarily so we can enforce a connect timeout */
173 flags
= fcntl(sock
->socket
, F_GETFL
);
174 if(flags
== -1) return rocksock_seterror(sock
, RS_ET_SYS
, errno
, ROCKSOCK_FILENAME
, __LINE__
);
176 if(fcntl(sock
->socket
, F_SETFL
, flags
| O_NONBLOCK
) == -1) return errno
;
178 ret
= connect(sock
->socket
, hostinfo
->hostaddr
->ai_addr
, hostinfo
->hostaddr
->ai_addrlen
);
181 if (!(ret
== EINPROGRESS
|| ret
== EWOULDBLOCK
)) return rocksock_seterror(sock
, RS_ET_SYS
, ret
, ROCKSOCK_FILENAME
, __LINE__
);
184 if(fcntl(sock
->socket
, F_SETFL
, flags
) == -1) return rocksock_seterror(sock
, RS_ET_SYS
, errno
, ROCKSOCK_FILENAME
, __LINE__
);
187 FD_SET(sock
->socket
, &wset
);
189 ret
= select(sock
->socket
+1, NULL
, &wset
, NULL
, timeout
? make_timeval(&tv
, timeout
) : NULL
);
191 if(ret
== 1 && FD_ISSET(sock
->socket
, &wset
)) {
192 ret
= getsockopt(sock
->socket
, SOL_SOCKET
, SO_ERROR
, &optval
,&optlen
);
193 if(ret
== -1) return rocksock_seterror(sock
, RS_ET_SYS
, errno
, ROCKSOCK_FILENAME
, __LINE__
);
194 else if(optval
) return rocksock_seterror(sock
, RS_ET_SYS
, optval
, ROCKSOCK_FILENAME
, __LINE__
);
196 } else if(ret
== 0) return rocksock_seterror(sock
, RS_ET_OWN
, RS_E_HIT_CONNECTTIMEOUT
, ROCKSOCK_FILENAME
, __LINE__
);
198 return rocksock_seterror(sock
, RS_ET_SYS
, errno
, ROCKSOCK_FILENAME
, __LINE__
);
201 static int rocksock_setup_socks4_header(rocksock
* sock
, int is4a
, char* buffer
, size_t bufsize
, rs_proxy
* proxy
, size_t* bytesused
) {
205 buffer
[2] = proxy
->hostinfo
.port
/ 256;
206 buffer
[3] = proxy
->hostinfo
.port
% 256;
214 rs_resolveStorage stor
;
215 ret
= rocksock_resolve_host(sock
, &proxy
->hostinfo
, &stor
);
217 if(stor
.hostaddr
->ai_family
!= AF_INET
)
218 return rocksock_seterror(sock
, RS_ET_OWN
, RS_E_SOCKS4_NO_IP6
, ROCKSOCK_FILENAME
, __LINE__
);
219 buffer
[4] = ((char*) &(((struct sockaddr_in
*) stor
.hostaddr
->ai_addr
)->sin_addr
.s_addr
))[0];
220 buffer
[5] = ((char*) &(((struct sockaddr_in
*) stor
.hostaddr
->ai_addr
)->sin_addr
.s_addr
))[1];
221 buffer
[6] = ((char*) &(((struct sockaddr_in
*) stor
.hostaddr
->ai_addr
)->sin_addr
.s_addr
))[2];
222 buffer
[7] = ((char*) &(((struct sockaddr_in
*) stor
.hostaddr
->ai_addr
)->sin_addr
.s_addr
))[3];
226 if(is4a
) *bytesused
+= strlen(strncpy(buffer
+ *bytesused
, proxy
->hostinfo
.host
, bufsize
- *bytesused
))+1;
228 return rocksock_seterror(sock
, RS_ET_OWN
, 0, NULL
, 0);
231 int rocksock_connect(rocksock
* sock
, char* host
, unsigned short port
, int useSSL
) {
233 int ret
, trysocksv4a
;
234 rs_hostInfo
* connector
;
236 rs_proxy
* targetproxy
;
239 size_t socksused
= 0, bytes
;
240 if (!sock
) return RS_E_NULL
;
242 return rocksock_seterror(sock
, RS_ET_OWN
, RS_E_NULL
, ROCKSOCK_FILENAME
, __LINE__
);
244 if (useSSL
) return rocksock_seterror(sock
, RS_ET_OWN
, RS_E_NO_SSL
, ROCKSOCK_FILENAME
, __LINE__
);
247 sock
->hostinfo
.host
= host
;
249 sock
->hostinfo
.host
= strdup(host
);
251 sock
->hostinfo
.port
= port
;
253 if(sock
->lastproxy
>= 0)
254 connector
= &sock
->proxies
[0].hostinfo
;
256 connector
= &sock
->hostinfo
;
258 rs_resolveStorage stor
;
260 ret
= rocksock_resolve_host(sock
, connector
, &stor
);
262 check_proxy0_failure
:
263 if(sock
->lastproxy
>= 0) sock
->lasterror
.failedProxy
= 0;
267 ret
= do_connect(sock
, &stor
, sock
->timeout
);
268 if(ret
) goto check_proxy0_failure
;
270 if(sock
->lastproxy
>= 0) {
271 dummy
.hostinfo
= sock
->hostinfo
;
272 dummy
.password
= NULL
;
273 dummy
.username
= NULL
;
274 dummy
.proxytype
= RS_PT_NONE
;
275 for(px
= 0; px
<= sock
->lastproxy
; px
++) {
276 if(px
== sock
->lastproxy
)
277 targetproxy
= &dummy
;
279 targetproxy
= &sock
->proxies
[px
+ 1];
280 // send socks connection data
281 switch(sock
->proxies
[px
].proxytype
) {
285 ret
= rocksock_setup_socks4_header(sock
, trysocksv4a
, socksdata
, sizeof(socksdata
), targetproxy
, &socksused
);
288 sock
->lasterror
.failedProxy
= px
;
291 ret
= rocksock_send(sock
, socksdata
, socksused
, 0, &bytes
);
292 if(ret
) goto proxyfailure
;
293 ret
= rocksock_recv(sock
, socksdata
, 8, 8, &bytes
);
294 if(ret
) goto proxyfailure
;
295 if(bytes
< 8 || socksdata
[0] != 0) {
296 ret
= rocksock_seterror(sock
, RS_ET_OWN
, RS_E_PROXY_UNEXPECTED_RESPONSE
, ROCKSOCK_FILENAME
, __LINE__
);
299 switch(socksdata
[1]) {
307 ret
= rocksock_seterror(sock
, RS_ET_OWN
, RS_E_TARGETPROXY_CONNECT_FAILED
, ROCKSOCK_FILENAME
, __LINE__
);
309 case 0x5c: case 0x5d:
310 ret
= rocksock_seterror(sock
, RS_ET_OWN
, RS_E_PROXY_AUTH_FAILED
, ROCKSOCK_FILENAME
, __LINE__
);
313 ret
= rocksock_seterror(sock
, RS_ET_OWN
, RS_E_PROXY_UNEXPECTED_RESPONSE
, ROCKSOCK_FILENAME
, __LINE__
);
320 if(sock
->proxies
[px
].username
&& sock
->proxies
[px
].password
) {
328 bytes
= p
- socksdata
;
329 ret
= rocksock_send(sock
, socksdata
, bytes
, bytes
, &bytes
);
330 if(ret
) goto proxyfailure
;
331 ret
= rocksock_recv(sock
, socksdata
, 2, 2, &bytes
);
332 if(ret
) goto proxyfailure
;
333 if(bytes
< 2 || socksdata
[0] != 5) {
334 ret
= rocksock_seterror(sock
, RS_ET_OWN
, RS_E_PROXY_UNEXPECTED_RESPONSE
, ROCKSOCK_FILENAME
, __LINE__
);
337 if(socksdata
[1] == '\xff') {
338 ret
= rocksock_seterror(sock
, RS_ET_OWN
, RS_E_PROXY_AUTH_FAILED
, ROCKSOCK_FILENAME
, __LINE__
);
340 } else if (socksdata
[1] == 2) {
341 if( sock
->proxies
[px
].username
&& sock
->proxies
[px
].password
&&
342 *sock
->proxies
[px
].username
&& *sock
->proxies
[px
].password
) {
344 +----+------+----------+------+----------+
345 |VER | ULEN | UNAME | PLEN | PASSWD |
346 +----+------+----------+------+----------+
347 | 1 | 1 | 1 to 255 | 1 | 1 to 255 |
348 +----+------+----------+------+----------+
352 bytes
= strlen(sock
->proxies
[px
].username
) & 0xFF;
354 memcpy(p
, sock
->proxies
[px
].username
, bytes
);
356 bytes
= strlen(sock
->proxies
[px
].password
) & 0xFF;
358 memcpy(p
, sock
->proxies
[px
].password
, bytes
);
360 bytes
= p
- socksdata
;
361 ret
= rocksock_send(sock
, socksdata
, bytes
, bytes
, &bytes
);
362 if(ret
) goto proxyfailure
;
363 ret
= rocksock_recv(sock
, socksdata
, 2, 2, &bytes
);
364 if(ret
) goto proxyfailure
;
366 ret
= rocksock_seterror(sock
, RS_ET_OWN
, RS_E_PROXY_UNEXPECTED_RESPONSE
, ROCKSOCK_FILENAME
, __LINE__
);
368 } else if(socksdata
[1] != 0) {
369 ret
= rocksock_seterror(sock
, RS_ET_OWN
, RS_E_PROXY_AUTH_FAILED
, ROCKSOCK_FILENAME
, __LINE__
);
373 ret
= rocksock_seterror(sock
, RS_ET_OWN
, RS_E_PROXY_AUTH_FAILED
, ROCKSOCK_FILENAME
, __LINE__
);
381 if(isnumericipv4(targetproxy
->hostinfo
.host
)) {
382 *p
++ = 1; // ipv4 method
384 ipv4fromstring(targetproxy
->hostinfo
.host
, (unsigned char*) p
);
386 *p
++ = 3; //hostname method, requires the server to do dns lookups.
387 bytes
= strlen(targetproxy
->hostinfo
.host
);
389 return rocksock_seterror(sock
, RS_ET_OWN
, RS_E_SOCKS5_AUTH_EXCEEDSIZE
, ROCKSOCK_FILENAME
, __LINE__
);
391 memcpy(p
, targetproxy
->hostinfo
.host
, bytes
);
394 *p
++ = targetproxy
->hostinfo
.port
/ 256;
395 *p
++ = targetproxy
->hostinfo
.port
% 256;
396 bytes
= p
- socksdata
;
397 ret
= rocksock_send(sock
, socksdata
, bytes
, bytes
, &bytes
);
398 if(ret
) goto proxyfailure
;
399 ret
= rocksock_recv(sock
, socksdata
, sizeof(socksdata
), sizeof(socksdata
), &bytes
);
400 if(ret
) goto proxyfailure
;
402 ret
= rocksock_seterror(sock
, RS_ET_OWN
, RS_E_PROXY_UNEXPECTED_RESPONSE
, ROCKSOCK_FILENAME
, __LINE__
);
405 switch(socksdata
[1]) {
409 ret
= rocksock_seterror(sock
, RS_ET_OWN
, RS_E_PROXY_GENERAL_FAILURE
, ROCKSOCK_FILENAME
, __LINE__
);
412 ret
= rocksock_seterror(sock
, RS_ET_OWN
, RS_E_PROXY_AUTH_FAILED
, ROCKSOCK_FILENAME
, __LINE__
);
415 ret
= rocksock_seterror(sock
, RS_ET_OWN
, RS_E_TARGETPROXY_NET_UNREACHABLE
, ROCKSOCK_FILENAME
, __LINE__
);
418 ret
= rocksock_seterror(sock
, RS_ET_OWN
, RS_E_TARGETPROXY_HOST_UNREACHABLE
, ROCKSOCK_FILENAME
, __LINE__
);
421 ret
= rocksock_seterror(sock
, RS_ET_OWN
, RS_E_TARGETPROXY_CONN_REFUSED
, ROCKSOCK_FILENAME
, __LINE__
);
424 ret
= rocksock_seterror(sock
, RS_ET_OWN
, RS_E_TARGETPROXY_TTL_EXPIRED
, ROCKSOCK_FILENAME
, __LINE__
);
427 ret
= rocksock_seterror(sock
, RS_ET_OWN
, RS_E_PROXY_COMMAND_NOT_SUPPORTED
, ROCKSOCK_FILENAME
, __LINE__
);
430 ret
= rocksock_seterror(sock
, RS_ET_OWN
, RS_E_PROXY_ADDRESSTYPE_NOT_SUPPORTED
, ROCKSOCK_FILENAME
, __LINE__
);
433 ret
= rocksock_seterror(sock
, RS_ET_OWN
, RS_E_PROXY_UNEXPECTED_RESPONSE
, ROCKSOCK_FILENAME
, __LINE__
);
438 bytes
= snprintf(socksdata
, sizeof(socksdata
), "CONNECT %s:%d HTTP/1.1\r\n\r\n", targetproxy
->hostinfo
.host
, targetproxy
->hostinfo
.port
);
439 ret
= rocksock_send(sock
, socksdata
, bytes
, bytes
, &bytes
);
440 if(ret
) goto proxyfailure
;
441 ret
= rocksock_recv(sock
, socksdata
, sizeof(socksdata
), sizeof(socksdata
), &bytes
);
442 if(ret
) goto proxyfailure
;
444 ret
= rocksock_seterror(sock
, RS_ET_OWN
, RS_E_PROXY_UNEXPECTED_RESPONSE
, ROCKSOCK_FILENAME
, __LINE__
);
447 if(socksdata
[9] != '2') {
448 ret
= rocksock_seterror(sock
, RS_ET_OWN
, RS_E_TARGETPROXY_CONNECT_FAILED
, ROCKSOCK_FILENAME
, __LINE__
);
459 ret
= rocksock_ssl_connect_fd(sock
);
463 return rocksock_seterror(sock
, RS_ET_OWN
, 0, NULL
, 0);
471 static int rocksock_operation(rocksock
* sock
, rs_operationType operation
, char* buffer
, size_t bufsize
, size_t chunksize
, size_t* bytes
) {
472 if (!sock
) return RS_E_NULL
;
473 if (!buffer
|| !bytes
|| (!bufsize
&& operation
== RS_OT_READ
)) return rocksock_seterror(sock
, RS_ET_OWN
, RS_E_NULL
, ROCKSOCK_FILENAME
, __LINE__
);
480 size_t bytesleft
= bufsize
? bufsize
: strlen(buffer
);
482 char* bufptr
= buffer
;
484 if (!sock
->socket
) return rocksock_seterror(sock
, RS_ET_OWN
, RS_E_NO_SOCKET
, ROCKSOCK_FILENAME
, __LINE__
);
485 if(operation
== RS_OT_SEND
) wfd
= &fd
;
489 if(operation
== RS_OT_SEND
)
490 ret
= setsockopt(sock
->socket
, SOL_SOCKET
, SO_SNDTIMEO
, (void*) make_timeval(&tv
, sock
->timeout
), sizeof(tv
));
492 ret
= setsockopt(sock
->socket
, SOL_SOCKET
, SO_RCVTIMEO
, (void*) make_timeval(&tv
, sock
->timeout
), sizeof(tv
));
495 if (ret
== -1) return rocksock_seterror(sock
, RS_ET_SYS
, errno
, ROCKSOCK_FILENAME
, __LINE__
);
498 byteswanted
= (chunksize
&& chunksize
< bytesleft
) ? chunksize
: bytesleft
;
501 if(operation
== RS_OT_SEND
)
502 ret
= rocksock_ssl_send(sock
, bufptr
, byteswanted
);
504 ret
= rocksock_ssl_recv(sock
, bufptr
, byteswanted
);
508 /* enforce the timeout by using select() before doing the actual recv/send */
509 FD_SET(sock
->socket
, &fd
);
510 ret
=select(sock
->socket
+1, rfd
, wfd
, NULL
, sock
->timeout
? make_timeval(&tv
, sock
->timeout
) : NULL
);
511 if(!FD_ISSET(sock
->socket
, &fd
)) rocksock_seterror(sock
, RS_ET_OWN
, RS_E_NULL
, ROCKSOCK_FILENAME
, __LINE__
); // temp test
513 //printf("h: %s, skt: %d, to: %d:%d\n", sock->hostinfo.host, sock->socket, tv.tv_sec, tv.tv_usec);
514 return rocksock_seterror(sock
, RS_ET_SYS
, errno
, ROCKSOCK_FILENAME
, __LINE__
);
516 else if(!ret
) return rocksock_seterror(sock
, RS_ET_OWN
, RS_OT_READ
? RS_E_HIT_READTIMEOUT
: RS_E_HIT_WRITETIMEOUT
, ROCKSOCK_FILENAME
, __LINE__
);
518 if(operation
== RS_OT_SEND
)
519 ret
= send(sock
->socket
, bufptr
, byteswanted
, MSG_NOSIGNAL
);
521 ret
= recv(sock
->socket
, bufptr
, byteswanted
, 0);
527 if(!ret
) // The return value will be 0 when the peer has performed an orderly shutdown.
528 return rocksock_seterror(sock
, RS_ET_OWN
, RS_E_REMOTE_DISCONNECTED
, ROCKSOCK_FILENAME
, __LINE__
);
531 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__
);
532 return rocksock_seterror(sock
, RS_ET_SYS
, errno
, ROCKSOCK_FILENAME
, __LINE__
);
538 if(operation
== RS_OT_READ
&& (size_t) ret
< byteswanted
) break;
540 return rocksock_seterror(sock
, RS_ET_OWN
, 0, NULL
, 0);
543 int rocksock_send(rocksock
* sock
, char* buffer
, size_t bufsize
, size_t chunksize
, size_t* byteswritten
) {
544 return rocksock_operation(sock
, RS_OT_SEND
, buffer
, bufsize
, chunksize
, byteswritten
);
547 int rocksock_recv(rocksock
* sock
, char* buffer
, size_t bufsize
, size_t chunksize
, size_t* bytesread
) {
548 return rocksock_operation(sock
, RS_OT_READ
, buffer
, bufsize
, chunksize
, bytesread
);
551 int rocksock_disconnect(rocksock
* sock
) {
552 if (!sock
) return RS_E_NULL
;
554 rocksock_ssl_free_context(sock
);
556 if(sock
->socket
) close(sock
->socket
);
558 return rocksock_seterror(sock
, RS_ET_OWN
, 0, NULL
, 0);
561 int rocksock_clear(rocksock
* sock
) {
562 if (!sock
) return RS_E_NULL
;
564 if(sock
->lastproxy
>= 0) {
565 for (i
=0;i
<=sock
->lastproxy
;i
++) {
567 if(sock
->proxies
[i
].username
)
568 free(sock
->proxies
[i
].username
);
569 if(sock
->proxies
[i
].password
)
570 free(sock
->proxies
[i
].password
);
571 if(sock
->proxies
[i
].hostinfo
.host
)
572 free(sock
->proxies
[i
].hostinfo
.host
);
574 sock
->proxies
[i
].username
= NULL
;
575 sock
->proxies
[i
].password
= NULL
;
576 sock
->proxies
[i
].hostinfo
.host
= NULL
;
580 if(sock
->hostinfo
.host
)
581 free(sock
->hostinfo
.host
);
583 sock
->hostinfo
.host
= NULL
;
585 return rocksock_seterror(sock
, RS_ET_OWN
, 0, NULL
, 0);