1 /* Copyright 2001 Matej Pfajfar.
2 * Copyright 2001-2004 Roger Dingledine.
3 * Copyright 2004-2005 Roger Dingledine, Nick Mathewson. */
4 /* See LICENSE for licensing information */
6 const char buffers_c_id
[] = "$Id$";
10 * \brief Abstractions for buffered IO.
15 #define BUFFER_MAGIC 0xB0FFF312u
17 uint32_t magic
; /**< Magic cookie for debugging: Must be set to BUFFER_MAGIC */
18 char *mem
; /**< Storage for data in the buffer */
19 size_t len
; /**< Maximum amount of data that <b>mem</b> can hold. */
20 size_t datalen
; /**< Number of bytes currently in <b>mem</b>. */
23 /** Size, in bytes, for newly allocated buffers. Should be a power of 2. */
24 #define INITIAL_BUF_SIZE (4*1024)
25 /** Size, in bytes, for minimum 'shrink' size for buffers. Buffers may start
26 * out smaller than this, but they will never autoshrink to less
28 #define MIN_BUF_SHRINK_SIZE (16*1024)
30 /** Change a buffer's capacity. <b>new_capacity</b> must be \<= buf->datalen. */
31 static INLINE
void buf_resize(buf_t
*buf
, size_t new_capacity
)
33 tor_assert(buf
->datalen
<= new_capacity
);
34 tor_assert(new_capacity
);
35 buf
->mem
= tor_realloc(buf
->mem
, new_capacity
);
36 buf
->len
= new_capacity
;
39 /** If the buffer is not large enough to hold <b>capacity</b> bytes, resize
40 * it so that it can. (The new size will be a power of 2 times the old
43 static INLINE
int buf_ensure_capacity(buf_t
*buf
, size_t capacity
)
46 if (buf
->len
>= capacity
) /* Don't grow if we're already big enough. */
48 if (capacity
> MAX_BUF_SIZE
) /* Don't grow past the maximum. */
50 /* Find the smallest new_len equal to (2**X)*len for some X; such that
51 * new_len is at least capacity.
54 while (new_len
< capacity
)
56 /* Resize the buffer. */
57 log_fn(LOG_DEBUG
,"Growing buffer from %d to %d bytes.",
58 (int)buf
->len
, (int)new_len
);
59 buf_resize(buf
,new_len
);
63 /** If the buffer is at least 2*MIN_BUF_SHRINK_SIZE bytes in capacity,
64 * and if the buffer is less than 1/4 full, shrink the buffer until
65 * one of the above no longer holds. (We shrink the buffer by
66 * dividing by powers of 2.)
68 static INLINE
void buf_shrink_if_underfull(buf_t
*buf
) {
70 /* If the buffer is at least .25 full, or if shrinking the buffer would
71 * put it under MIN_BUF_SHRINK_SIZE, don't do it. */
72 if (buf
->datalen
>= buf
->len
/4 || buf
->len
< 2*MIN_BUF_SHRINK_SIZE
)
74 /* Shrink new_len by powers of 2 until: datalen is at least 1/4 of
75 * new_len, OR shrinking new_len more would put it under
76 * MIN_BUF_SHRINK_SIZE.
78 new_len
= buf
->len
/ 2;
79 while (buf
->datalen
< new_len
/4 && new_len
/2 > MIN_BUF_SHRINK_SIZE
)
81 log_fn(LOG_DEBUG
,"Shrinking buffer from %d to %d bytes.",
82 (int)buf
->len
, (int)new_len
);
83 buf_resize(buf
, new_len
);
86 /** Remove the first <b>n</b> bytes from buf.
88 static INLINE
void buf_remove_from_front(buf_t
*buf
, size_t n
) {
89 tor_assert(buf
->datalen
>= n
);
91 memmove(buf
->mem
, buf
->mem
+n
, buf
->datalen
);
92 buf_shrink_if_underfull(buf
);
95 /** Make sure that the memory in buf ends with a zero byte. */
96 static INLINE
int buf_nul_terminate(buf_t
*buf
)
98 if (buf_ensure_capacity(buf
,buf
->datalen
+1)<0)
100 buf
->mem
[buf
->datalen
] = '\0';
104 /** Create and return a new buf with capacity <b>size</b>.
106 buf_t
*buf_new_with_capacity(size_t size
) {
108 buf
= tor_malloc(sizeof(buf_t
));
109 buf
->magic
= BUFFER_MAGIC
;
110 buf
->mem
= tor_malloc(size
);
113 // memset(buf->mem,0,size);
119 /** Allocate and return a new buffer with default capacity. */
122 return buf_new_with_capacity(INITIAL_BUF_SIZE
);
125 /** Remove all data from <b>buf</b> */
126 void buf_clear(buf_t
*buf
)
131 /** Return the number of bytes stored in <b>buf</b> */
132 size_t buf_datalen(const buf_t
*buf
)
137 /** Return the maximum bytes that can be stored in <b>buf</b> before buf
138 * needs to resize. */
139 size_t buf_capacity(const buf_t
*buf
)
144 /** For testing only: Return a pointer to the raw memory stored in <b>buf</b>.
146 const char *_buf_peek_raw_buffer(const buf_t
*buf
)
151 /** Release storage held by <b>buf</b>.
153 void buf_free(buf_t
*buf
) {
155 buf
->magic
= 0xDEADBEEF;
160 /** Read from socket <b>s</b>, writing onto end of <b>buf</b>. Read at most
161 * <b>at_most</b> bytes, resizing the buffer as necessary. If recv()
162 * returns 0, set <b>*reached_eof</b> to 1 and return 0. Return -1 on error;
163 * else return the number of bytes read. Return 0 if recv() would
166 int read_to_buf(int s
, size_t at_most
, buf_t
*buf
, int *reached_eof
) {
171 tor_assert(reached_eof
);
174 if (buf_ensure_capacity(buf
,buf
->datalen
+at_most
))
177 if (at_most
+ buf
->datalen
> buf
->len
)
178 at_most
= buf
->len
- buf
->datalen
; /* take the min of the two */
181 return 0; /* we shouldn't read anything */
183 // log_fn(LOG_DEBUG,"reading at most %d bytes.",at_most);
184 read_result
= recv(s
, buf
->mem
+buf
->datalen
, at_most
, 0);
185 if (read_result
< 0) {
186 int e
= tor_socket_errno(s
);
187 if (!ERRNO_IS_EAGAIN(e
)) { /* it's a real error */
190 return 0; /* would block. */
191 } else if (read_result
== 0) {
192 log_fn(LOG_DEBUG
,"Encountered eof");
195 } else { /* we read some bytes */
196 buf
->datalen
+= read_result
;
197 log_fn(LOG_DEBUG
,"Read %d bytes. %d on inbuf.",read_result
,
203 /** As read_to_buf, but reads from a TLS connection.
205 int read_to_buf_tls(tor_tls
*tls
, size_t at_most
, buf_t
*buf
) {
210 log_fn(LOG_DEBUG
,"start: %d on buf, %d pending, at_most %d.",
211 (int)buf_datalen(buf
), (int)tor_tls_get_pending_bytes(tls
),
214 if (buf_ensure_capacity(buf
, at_most
+buf
->datalen
))
215 return TOR_TLS_ERROR
;
217 if (at_most
+ buf
->datalen
> buf
->len
)
218 at_most
= buf
->len
- buf
->datalen
;
223 log_fn(LOG_DEBUG
,"before: %d on buf, %d pending, at_most %d.",
224 (int)buf_datalen(buf
), (int)tor_tls_get_pending_bytes(tls
),
227 check_no_tls_errors();
228 r
= tor_tls_read(tls
, buf
->mem
+buf
->datalen
, at_most
);
232 log_fn(LOG_DEBUG
,"Read %d bytes. %d on inbuf; %d pending",r
,
233 (int)buf
->datalen
,(int)tor_tls_get_pending_bytes(tls
));
237 /** Write data from <b>buf</b> to the socket <b>s</b>. Write at most
238 * <b>*buf_flushlen</b> bytes, decrement <b>*buf_flushlen</b> by
239 * the number of bytes actually written, and remove the written bytes
240 * from the buffer. Return the number of bytes written on success,
241 * -1 on failure. Return 0 if write() would block.
243 int flush_buf(int s
, buf_t
*buf
, size_t *buf_flushlen
)
248 tor_assert(buf_flushlen
);
250 tor_assert(*buf_flushlen
<= buf
->datalen
);
252 if (*buf_flushlen
== 0) /* nothing to flush */
255 write_result
= send(s
, buf
->mem
, *buf_flushlen
, 0);
256 if (write_result
< 0) {
257 int e
= tor_socket_errno(s
);
258 if (!ERRNO_IS_EAGAIN(e
)) { /* it's a real error */
261 log_fn(LOG_DEBUG
,"write() would block, returning.");
264 *buf_flushlen
-= write_result
;
265 log_fn(LOG_DEBUG
,"%d: flushed %d bytes, %d ready to flush, %d remain.",
266 s
,write_result
,(int)*buf_flushlen
,(int)buf
->datalen
);
267 buf_remove_from_front(buf
, write_result
);
273 /** As flush_buf, but writes data to a TLS connection.
275 int flush_buf_tls(tor_tls
*tls
, buf_t
*buf
, size_t *buf_flushlen
)
280 tor_assert(buf_flushlen
);
282 /* we want to let tls write even if flushlen is zero, because it might
283 * have a partial record pending */
284 check_no_tls_errors();
285 r
= tor_tls_write(tls
, buf
->mem
, *buf_flushlen
);
290 buf_remove_from_front(buf
, r
);
291 log_fn(LOG_DEBUG
,"flushed %d bytes, %d ready to flush, %d remain.",
292 r
,(int)*buf_flushlen
,(int)buf
->datalen
);
296 /** Append <b>string_len</b> bytes from <b>string</b> to the end of
299 * Return the new length of the buffer on success, -1 on failure.
301 int write_to_buf(const char *string
, size_t string_len
, buf_t
*buf
) {
303 /* append string to buf (growing as needed, return -1 if "too big")
304 * return total number of bytes on the buf
310 if (buf_ensure_capacity(buf
, buf
->datalen
+string_len
)) {
311 log_fn(LOG_WARN
, "buflen too small, can't hold %d bytes.", (int)(buf
->datalen
+string_len
));
315 memcpy(buf
->mem
+buf
->datalen
, string
, string_len
);
316 buf
->datalen
+= string_len
;
317 log_fn(LOG_DEBUG
,"added %d bytes to buf (now %d total).",(int)string_len
, (int)buf
->datalen
);
321 /** Remove <b>string_len</b> bytes from the front of <b>buf</b>, and store them
322 * into <b>string</b>. Return the new buffer size. <b>string_len</b> must be \<=
323 * the number of bytes on the buffer.
325 int fetch_from_buf(char *string
, size_t string_len
, buf_t
*buf
) {
327 /* There must be string_len bytes in buf; write them onto string,
328 * then memmove buf back (that is, remove them from buf).
330 * Return the number of bytes still on the buffer. */
333 tor_assert(string_len
<= buf
->datalen
); /* make sure we don't ask for too much */
336 memcpy(string
,buf
->mem
,string_len
);
337 buf_remove_from_front(buf
, string_len
);
341 /** There is a (possibly incomplete) http statement on <b>buf</b>, of the
342 * form "\%s\\r\\n\\r\\n\%s", headers, body. (body may contain nuls.)
343 * If a) the headers include a Content-Length field and all bytes in
344 * the body are present, or b) there's no Content-Length field and
345 * all headers are present, then:
347 * - strdup headers into <b>*headers_out</b>, and nul-terminate it.
348 * - memdup body into <b>*body_out</b>, and nul-terminate it.
349 * - Then remove them from <b>buf</b>, and return 1.
351 * - If headers or body is NULL, discard that part of the buf.
352 * - If a headers or body doesn't fit in the arg, return -1.
353 * (We ensure that the headers or body don't exceed max len,
354 * _even if_ we're planning to discard them.)
356 * Else, change nothing and return 0.
358 int fetch_from_buf_http(buf_t
*buf
,
359 char **headers_out
, size_t max_headerlen
,
360 char **body_out
, size_t *body_used
, size_t max_bodylen
) {
361 char *headers
, *body
, *p
;
362 size_t headerlen
, bodylen
, contentlen
;
367 if (buf_nul_terminate(buf
)<0) {
368 log_fn(LOG_WARN
,"Couldn't nul-terminate buffer");
371 body
= strstr(headers
,"\r\n\r\n");
373 log_fn(LOG_DEBUG
,"headers not all here yet.");
376 body
+= 4; /* Skip the the CRLFCRLF */
377 headerlen
= body
-headers
; /* includes the CRLFCRLF */
378 bodylen
= buf
->datalen
- headerlen
;
379 log_fn(LOG_DEBUG
,"headerlen %d, bodylen %d.", (int)headerlen
, (int)bodylen
);
381 if (max_headerlen
<= headerlen
) {
382 log_fn(LOG_WARN
,"headerlen %d larger than %d. Failing.", (int)headerlen
,
383 (int)max_headerlen
-1);
386 if (max_bodylen
<= bodylen
) {
387 log_fn(LOG_WARN
,"bodylen %d larger than %d. Failing.", (int)bodylen
, (int)max_bodylen
-1);
391 #define CONTENT_LENGTH "\r\nContent-Length: "
392 p
= strstr(headers
, CONTENT_LENGTH
);
395 i
= atoi(p
+strlen(CONTENT_LENGTH
));
397 log_fn(LOG_WARN
, "Content-Length is less than zero; it looks like someone is trying to crash us.");
401 /* if content-length is malformed, then our body length is 0. fine. */
402 log_fn(LOG_DEBUG
,"Got a contentlen of %d.",(int)contentlen
);
403 if (bodylen
< contentlen
) {
404 log_fn(LOG_DEBUG
,"body not all here yet.");
405 return 0; /* not all there yet */
407 if (bodylen
> contentlen
) {
408 bodylen
= contentlen
;
409 log_fn(LOG_DEBUG
,"bodylen reduced to %d.",(int)bodylen
);
412 /* all happy. copy into the appropriate places, and return 1 */
414 *headers_out
= tor_malloc(headerlen
+1);
415 memcpy(*headers_out
,buf
->mem
,headerlen
);
416 (*headers_out
)[headerlen
] = 0; /* null terminate it */
419 tor_assert(body_used
);
420 *body_used
= bodylen
;
421 *body_out
= tor_malloc(bodylen
+1);
422 memcpy(*body_out
,buf
->mem
+headerlen
,bodylen
);
423 (*body_out
)[bodylen
] = 0; /* null terminate it */
425 buf_remove_from_front(buf
, headerlen
+bodylen
);
429 /** There is a (possibly incomplete) socks handshake on <b>buf</b>, of one
431 * - socks4: "socksheader username\\0"
432 * - socks4a: "socksheader username\\0 destaddr\\0"
433 * - socks5 phase one: "version #methods methods"
434 * - socks5 phase two: "version command 0 addresstype..."
435 * If it's a complete and valid handshake, and destaddr fits in
436 * MAX_SOCKS_ADDR_LEN bytes, then pull the handshake off the buf,
437 * assign to <b>req</b>, and return 1.
439 * If it's invalid or too big, return -1.
441 * Else it's not all there yet, leave buf alone and return 0.
443 * If you want to specify the socks reply, write it into <b>req->reply</b>
444 * and set <b>req->replylen</b>, else leave <b>req->replylen</b> alone.
446 * If returning 0 or -1, <b>req->address</b> and <b>req->port</b> are undefined.
448 int fetch_from_buf_socks(buf_t
*buf
, socks_request_t
*req
) {
450 char tmpbuf
[INET_NTOA_BUF_LEN
];
452 enum {socks4
, socks4a
} socks4_prot
= socks4a
;
453 char *next
, *startaddr
;
456 /* If the user connects with socks4 or the wrong variant of socks5,
457 * then log a warning to let him know that it might be unwise. */
458 static int have_warned_about_unsafe_socks
= 0;
460 if (buf
->datalen
< 2) /* version and another byte */
462 switch (*(buf
->mem
)) { /* which version of socks? */
466 if (req
->socks_version
!= 5) { /* we need to negotiate a method */
467 unsigned char nummethods
= (unsigned char)*(buf
->mem
+1);
468 tor_assert(!req
->socks_version
);
469 if (buf
->datalen
< 2u+nummethods
)
471 if (!nummethods
|| !memchr(buf
->mem
+2, 0, nummethods
)) {
472 log_fn(LOG_WARN
,"socks5: offered methods don't include 'no auth'. Rejecting.");
473 req
->replylen
= 2; /* 2 bytes of response */
475 req
->reply
[1] = '\xFF'; /* reject all methods */
478 buf_remove_from_front(buf
,2+nummethods
);/* remove packet from buf */
480 req
->replylen
= 2; /* 2 bytes of response */
481 req
->reply
[0] = 5; /* socks5 reply */
482 req
->reply
[1] = SOCKS5_SUCCEEDED
;
483 req
->socks_version
= 5; /* remember that we've already negotiated auth */
484 log_fn(LOG_DEBUG
,"socks5: accepted method 0");
487 /* we know the method; read in the request */
488 log_fn(LOG_DEBUG
,"socks5: checking request");
489 if (buf
->datalen
< 8) /* basic info plus >=2 for addr plus 2 for port */
490 return 0; /* not yet */
491 req
->command
= (unsigned char) *(buf
->mem
+1);
492 if (req
->command
!= SOCKS_COMMAND_CONNECT
&&
493 req
->command
!= SOCKS_COMMAND_RESOLVE
) {
494 /* not a connect or resolve? we don't support it. */
495 log_fn(LOG_WARN
,"socks5: command %d not recognized. Rejecting.",
499 switch (*(buf
->mem
+3)) { /* address type */
500 case 1: /* IPv4 address */
501 log_fn(LOG_DEBUG
,"socks5: ipv4 address type");
502 if (buf
->datalen
< 10) /* ip/port there? */
503 return 0; /* not yet */
505 destip
= ntohl(*(uint32_t*)(buf
->mem
+4));
506 in
.s_addr
= htonl(destip
);
507 tor_inet_ntoa(&in
,tmpbuf
,sizeof(tmpbuf
));
508 if (strlen(tmpbuf
)+1 > MAX_SOCKS_ADDR_LEN
) {
509 log_fn(LOG_WARN
,"socks5 IP takes %d bytes, which doesn't fit in %d. Rejecting.",
510 (int)strlen(tmpbuf
)+1,(int)MAX_SOCKS_ADDR_LEN
);
513 strlcpy(req
->address
,tmpbuf
,sizeof(req
->address
));
514 req
->port
= ntohs(*(uint16_t*)(buf
->mem
+8));
515 buf_remove_from_front(buf
, 10);
516 if (!have_warned_about_unsafe_socks
) {
517 log_fn(LOG_WARN
,"Your application (using socks5 on port %d) is giving Tor only an IP address. Applications that do DNS resolves themselves may leak information. Consider using Socks4A (e.g. via privoxy or socat) instead.", req
->port
);
518 // have_warned_about_unsafe_socks = 1; // (for now, warn every time)
522 log_fn(LOG_DEBUG
,"socks5: fqdn address type");
523 len
= (unsigned char)*(buf
->mem
+4);
524 if (buf
->datalen
< 7u+len
) /* addr/port there? */
525 return 0; /* not yet */
526 if (len
+1 > MAX_SOCKS_ADDR_LEN
) {
527 log_fn(LOG_WARN
,"socks5 hostname is %d bytes, which doesn't fit in %d. Rejecting.",
528 len
+1,MAX_SOCKS_ADDR_LEN
);
531 memcpy(req
->address
,buf
->mem
+5,len
);
532 req
->address
[len
] = 0;
533 req
->port
= ntohs(get_uint16(buf
->mem
+5+len
));
534 buf_remove_from_front(buf
, 5+len
+2);
536 default: /* unsupported */
537 log_fn(LOG_WARN
,"socks5: unsupported address type %d. Rejecting.",*(buf
->mem
+3));
542 /* http://archive.socks.permeo.com/protocol/socks4.protocol */
543 /* http://archive.socks.permeo.com/protocol/socks4a.protocol */
545 req
->socks_version
= 4;
546 if (buf
->datalen
< SOCKS4_NETWORK_LEN
) /* basic info available? */
547 return 0; /* not yet */
549 req
->command
= (unsigned char) *(buf
->mem
+1);
550 if (req
->command
!= SOCKS_COMMAND_CONNECT
&&
551 req
->command
!= SOCKS_COMMAND_RESOLVE
) {
552 /* not a connect or resolve? we don't support it. */
553 log_fn(LOG_WARN
,"socks4: command %d not recognized. Rejecting.",
558 req
->port
= ntohs(*(uint16_t*)(buf
->mem
+2));
559 destip
= ntohl(*(uint32_t*)(buf
->mem
+4));
560 if ((!req
->port
&& req
->command
!=SOCKS_COMMAND_RESOLVE
) || !destip
) {
561 log_fn(LOG_WARN
,"socks4: Port or DestIP is zero. Rejecting.");
565 log_fn(LOG_DEBUG
,"socks4: destip not in form 0.0.0.x.");
566 in
.s_addr
= htonl(destip
);
567 tor_inet_ntoa(&in
,tmpbuf
,sizeof(tmpbuf
));
568 if (strlen(tmpbuf
)+1 > MAX_SOCKS_ADDR_LEN
) {
569 log_fn(LOG_WARN
,"socks4 addr (%d bytes) too long. Rejecting.",
570 (int)strlen(tmpbuf
));
573 log_fn(LOG_DEBUG
,"socks4: successfully read destip (%s)", tmpbuf
);
574 socks4_prot
= socks4
;
577 next
= memchr(buf
->mem
+SOCKS4_NETWORK_LEN
, 0,
578 buf
->datalen
-SOCKS4_NETWORK_LEN
);
580 log_fn(LOG_DEBUG
,"socks4: Username not here yet.");
583 tor_assert(next
< buf
->mem
+buf
->datalen
);
586 if (socks4_prot
!= socks4a
&& !have_warned_about_unsafe_socks
) {
587 log_fn(LOG_WARN
,"Your application (using socks4 on port %d) is giving Tor only an IP address. Applications that do DNS resolves themselves may leak information. Consider using Socks4A (e.g. via privoxy or socat) instead.", req
->port
);
588 // have_warned_about_unsafe_socks = 1; // (for now, warn every time)
590 if (socks4_prot
== socks4a
) {
591 if (next
+1 == buf
->mem
+buf
->datalen
) {
592 log_fn(LOG_DEBUG
,"socks4: No part of destaddr here yet.");
596 next
= memchr(startaddr
, 0, buf
->mem
+buf
->datalen
-startaddr
);
598 log_fn(LOG_DEBUG
,"socks4: Destaddr not all here yet.");
601 if (MAX_SOCKS_ADDR_LEN
<= next
-startaddr
) {
602 log_fn(LOG_WARN
,"socks4: Destaddr too long. Rejecting.");
605 tor_assert(next
< buf
->mem
+buf
->datalen
);
607 log_fn(LOG_DEBUG
,"socks4: Everything is here. Success.");
608 strlcpy(req
->address
, startaddr
? startaddr
: tmpbuf
,
609 sizeof(req
->address
));
610 buf_remove_from_front(buf
, next
-buf
->mem
+1); /* next points to the final \0 on inbuf */
615 case 'P': /* put/post */
616 case 'C': /* connect */
618 "HTTP/1.0 501 Tor is not an HTTP Proxy\r\n"
619 "Content-Type: text/html; charset=iso-8859-1\r\n\r\n"
622 "<title>Tor is not an HTTP Proxy</title>\n"
625 "<h1>Tor is not an HTTP Proxy</h1>\n"
627 "It appears you have configured your web browser to use Tor as an HTTP Proxy.\n"
628 "This is not correct: Tor provides a SOCKS proxy. Please configure your\n"
629 "client accordingly.\n"
632 "See <a href=\"http://tor.eff.org/doc/tor-doc.html#installing\">http://tor.eff.org/doc/tor-doc.html#installing</a> for more information.\n"
633 "<!-- Plus this comment, to make the body response more than 512 bytes, so IE will be willing to display it. Comment comment comment comment comment comment comment comment comment comment comment comment.-->\n"
637 , MAX_SOCKS_REPLY_LEN
);
638 req
->replylen
= strlen(req
->reply
)+1;
640 default: /* version is not socks4 or socks5 */
641 log_fn(LOG_WARN
,"Socks version %d not recognized. (Tor is not an http proxy.)",
647 #define CONTROL_CMD_FRAGMENTHEADER 0x0010
648 #define CONTROL_CMD_FRAGMENT 0x0011
649 /** If there is a complete control message waiting on buf, then store
650 * its contents into *<b>type_out</b>, store its body's length into
651 * *<b>len_out</b>, allocate and store a string for its body into
652 * *<b>body_out</b>, and return 1. (body_out will always be NUL-terminated,
653 * even if the control message body doesn't end with NUL.)
655 * If there is not a complete control message waiting, return 0.
657 * Return -1 on error.
659 int fetch_from_buf_control(buf_t
*buf
, uint32_t *len_out
, uint16_t *type_out
,
667 tor_assert(type_out
);
668 tor_assert(body_out
);
670 if (buf
->datalen
< 4)
673 msglen
= ntohs(get_uint16(buf
->mem
));
674 if (buf
->datalen
< 4 + (unsigned)msglen
)
677 type
= ntohs(get_uint16(buf
->mem
+2));
678 if (type
!= CONTROL_CMD_FRAGMENTHEADER
) {
682 *body_out
= tor_malloc(msglen
+1);
683 memcpy(*body_out
, buf
->mem
+4, msglen
);
684 (*body_out
)[msglen
] = '\0';
688 buf_remove_from_front(buf
, 4+msglen
);
692 uint32_t totallen
, sofar
;
693 char *cp
, *endp
, *outp
;
695 /* Okay, we have a fragmented message. Is it all here? */
698 type
= htons(get_uint16(buf
->mem
+4));
699 totallen
= htonl(get_uint32(buf
->mem
+6));
700 if (totallen
< 65536)
703 if (buf
->datalen
<4+6+totallen
)
704 /* The data can't possibly be here yet, no matter how well it's packed.*/
707 /* Count how much data is really here. */
709 cp
= buf
->mem
+4+msglen
;
710 endp
= buf
->mem
+buf
->datalen
;
711 while (sofar
< totallen
) {
713 return 0; /* Fragment header not all here. */
714 msglen
= ntohs(get_uint16(cp
));
715 if (ntohs(get_uint16(cp
+2) != CONTROL_CMD_FRAGMENT
))
716 return -1; /* Missing fragment message; error. */
717 if ((endp
-cp
) < (int)(4+msglen
))
718 return 0; /* Fragment not all here. */
722 if (sofar
> totallen
)
723 return -1; /* Fragments add to more than expected; error. */
725 /* Okay, everything is here. */
728 *body_out
= tor_malloc(totallen
+1);
730 /* copy FRAGMENTED packet contents. */
731 msglen
= ntohs(get_uint16(buf
->mem
));
733 memcpy(*body_out
,buf
->mem
+4+6,msglen
-6);
735 outp
= *body_out
+sofar
;
736 cp
= buf
->mem
+4+msglen
;
737 while (sofar
< totallen
) {
738 msglen
= ntohs(get_uint16(cp
));
739 memcpy(outp
,cp
+4,msglen
);
744 (*body_out
)[totallen
]='\0';
751 /** Log an error and exit if <b>buf</b> is corrupted.
753 void assert_buf_ok(buf_t
*buf
)
756 tor_assert(buf
->magic
== BUFFER_MAGIC
);
757 tor_assert(buf
->mem
);
758 tor_assert(buf
->datalen
<= buf
->len
);