1 /* Copyright 2001 Matej Pfajfar.
2 * Copyright 2001-2004 Roger Dingledine.
3 * Copyright 2004 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 /** Maximum size, in bytes, for resized buffers. */
26 #define MAX_BUF_SIZE (1024*1024*10)
27 /** Size, in bytes, for minimum 'shrink' size for buffers. Buffers may start
28 * out smaller than this, but they will never autoshrink to less
30 #define MIN_BUF_SHRINK_SIZE (16*1024)
32 /** Change a buffer's capacity. <b>new_capacity</b> must be \<= buf->datalen. */
33 static INLINE
void buf_resize(buf_t
*buf
, size_t new_capacity
)
35 tor_assert(buf
->datalen
<= new_capacity
);
36 tor_assert(new_capacity
);
37 buf
->mem
= tor_realloc(buf
->mem
, new_capacity
);
38 buf
->len
= new_capacity
;
41 /** If the buffer is not large enough to hold <b>capacity</b> bytes, resize
42 * it so that it can. (The new size will be a power of 2 times the old
45 static INLINE
int buf_ensure_capacity(buf_t
*buf
, size_t capacity
)
48 if (buf
->len
>= capacity
) /* Don't grow if we're already big enough. */
50 if (capacity
> MAX_BUF_SIZE
) /* Don't grow past the maximum. */
52 /* Find the smallest new_len equal to (2**X)*len for some X; such that
53 * new_len is at least capacity.
56 while (new_len
< capacity
)
58 /* Resize the buffer. */
59 log_fn(LOG_DEBUG
,"Growing buffer from %d to %d bytes.",
60 (int)buf
->len
, (int)new_len
);
61 buf_resize(buf
,new_len
);
65 /** If the buffer is at least 2*MIN_BUF_SHRINK_SIZE bytes in capacity,
66 * and if the buffer is less than 1/4 full, shrink the buffer until
67 * one of the above no longer holds. (We shrink the buffer by
68 * dividing by powers of 2.)
70 static INLINE
void buf_shrink_if_underfull(buf_t
*buf
) {
72 /* If the buffer is at least .25 full, or if shrinking the buffer would
73 * put it under MIN_BUF_SHRINK_SIZE, don't do it. */
74 if (buf
->datalen
>= buf
->len
/4 || buf
->len
< 2*MIN_BUF_SHRINK_SIZE
)
76 /* Shrink new_len by powers of 2 until: datalen is at least 1/4 of
77 * new_len, OR shrinking new_len more would put it under
78 * MIN_BUF_SHRINK_SIZE.
80 new_len
= buf
->len
/ 2;
81 while (buf
->datalen
< new_len
/4 && new_len
/2 > MIN_BUF_SHRINK_SIZE
)
83 log_fn(LOG_DEBUG
,"Shrinking buffer from %d to %d bytes.",
84 (int)buf
->len
, (int)new_len
);
85 buf_resize(buf
, new_len
);
88 /** Remove the first <b>n</b> bytes from buf.
90 static INLINE
void buf_remove_from_front(buf_t
*buf
, size_t n
) {
91 tor_assert(buf
->datalen
>= n
);
93 memmove(buf
->mem
, buf
->mem
+n
, buf
->datalen
);
94 buf_shrink_if_underfull(buf
);
97 /** Make sure that the memory in buf ends with a zero byte. */
98 static INLINE
int buf_nul_terminate(buf_t
*buf
)
100 if (buf_ensure_capacity(buf
,buf
->datalen
+1)<0)
102 buf
->mem
[buf
->datalen
] = '\0';
106 /** Create and return a new buf with capacity <b>size</b>.
108 buf_t
*buf_new_with_capacity(size_t size
) {
110 buf
= tor_malloc(sizeof(buf_t
));
111 buf
->magic
= BUFFER_MAGIC
;
112 buf
->mem
= tor_malloc(size
);
115 // memset(buf->mem,0,size);
121 /** Allocate and return a new buffer with default capacity. */
124 return buf_new_with_capacity(INITIAL_BUF_SIZE
);
127 /** Remove all data from <b>buf</b> */
128 void buf_clear(buf_t
*buf
)
133 /** Return the number of bytes stored in <b>buf</b> */
134 size_t buf_datalen(const buf_t
*buf
)
139 /** Return the maximum bytes that can be stored in <b>buf</b> before buf
140 * needs to resize. */
141 size_t buf_capacity(const buf_t
*buf
)
146 /** For testing only: Return a pointer to the raw memory stored in <b>buf</b>.
148 const char *_buf_peek_raw_buffer(const buf_t
*buf
)
153 /** Release storage held by <b>buf</b>.
155 void buf_free(buf_t
*buf
) {
157 buf
->magic
= 0xDEADBEEF;
162 /** Read from socket <b>s</b>, writing onto end of <b>buf</b>. Read at most
163 * <b>at_most</b> bytes, resizing the buffer as necessary. If recv()
164 * returns 0, set <b>*reached_eof</b> to 1 and return 0. Return -1 on error;
165 * else return the number of bytes read. Return 0 if recv() would
168 int read_to_buf(int s
, size_t at_most
, buf_t
*buf
, int *reached_eof
) {
173 tor_assert(reached_eof
);
176 if (buf_ensure_capacity(buf
,buf
->datalen
+at_most
))
179 if (at_most
+ buf
->datalen
> buf
->len
)
180 at_most
= buf
->len
- buf
->datalen
; /* take the min of the two */
183 return 0; /* we shouldn't read anything */
185 // log_fn(LOG_DEBUG,"reading at most %d bytes.",at_most);
186 read_result
= recv(s
, buf
->mem
+buf
->datalen
, at_most
, 0);
187 if (read_result
< 0) {
188 int e
= tor_socket_errno(s
);
189 if (!ERRNO_IS_EAGAIN(e
)) { /* it's a real error */
192 return 0; /* would block. */
193 } else if (read_result
== 0) {
194 log_fn(LOG_DEBUG
,"Encountered eof");
197 } else { /* we read some bytes */
198 buf
->datalen
+= read_result
;
199 log_fn(LOG_DEBUG
,"Read %d bytes. %d on inbuf.",read_result
,
205 /** As read_to_buf, but reads from a TLS connection.
207 int read_to_buf_tls(tor_tls
*tls
, size_t at_most
, buf_t
*buf
) {
212 log_fn(LOG_DEBUG
,"start: %d on buf, %d pending, at_most %d.",
213 (int)buf_datalen(buf
), (int)tor_tls_get_pending_bytes(tls
),
216 if (buf_ensure_capacity(buf
, at_most
+buf
->datalen
))
217 return TOR_TLS_ERROR
;
219 if (at_most
+ buf
->datalen
> buf
->len
)
220 at_most
= buf
->len
- buf
->datalen
;
225 log_fn(LOG_DEBUG
,"before: %d on buf, %d pending, at_most %d.",
226 (int)buf_datalen(buf
), (int)tor_tls_get_pending_bytes(tls
),
229 assert_no_tls_errors();
230 r
= tor_tls_read(tls
, buf
->mem
+buf
->datalen
, at_most
);
234 log_fn(LOG_DEBUG
,"Read %d bytes. %d on inbuf; %d pending",r
,
235 (int)buf
->datalen
,(int)tor_tls_get_pending_bytes(tls
));
239 /** Write data from <b>buf</b> to the socket <b>s</b>. Write at most
240 * <b>*buf_flushlen</b> bytes, decrement <b>*buf_flushlen</b> by
241 * the number of bytes actually written, and remove the written bytes
242 * from the buffer. Return the number of bytes written on success,
243 * -1 on failure. Return 0 if write() would block.
245 int flush_buf(int s
, buf_t
*buf
, size_t *buf_flushlen
)
250 tor_assert(buf_flushlen
);
252 tor_assert(*buf_flushlen
<= buf
->datalen
);
254 if (*buf_flushlen
== 0) /* nothing to flush */
257 write_result
= send(s
, buf
->mem
, *buf_flushlen
, 0);
258 if (write_result
< 0) {
259 int e
= tor_socket_errno(s
);
260 if (!ERRNO_IS_EAGAIN(e
)) { /* it's a real error */
263 log_fn(LOG_DEBUG
,"write() would block, returning.");
266 *buf_flushlen
-= write_result
;
267 log_fn(LOG_DEBUG
,"%d: flushed %d bytes, %d ready to flush, %d remain.",
268 s
,write_result
,(int)*buf_flushlen
,(int)buf
->datalen
);
269 buf_remove_from_front(buf
, write_result
);
275 /** As flush_buf, but writes data to a TLS connection.
277 int flush_buf_tls(tor_tls
*tls
, buf_t
*buf
, size_t *buf_flushlen
)
282 tor_assert(buf_flushlen
);
284 /* we want to let tls write even if flushlen is zero, because it might
285 * have a partial record pending */
286 r
= tor_tls_write(tls
, buf
->mem
, *buf_flushlen
);
291 buf_remove_from_front(buf
, r
);
292 log_fn(LOG_DEBUG
,"flushed %d bytes, %d ready to flush, %d remain.",
293 r
,(int)*buf_flushlen
,(int)buf
->datalen
);
297 /** Append <b>string_len</b> bytes from <b>string</b> to the end of
300 * Return the new length of the buffer on success, -1 on failure.
302 int write_to_buf(const char *string
, size_t string_len
, buf_t
*buf
) {
304 /* append string to buf (growing as needed, return -1 if "too big")
305 * return total number of bytes on the buf
311 if (buf_ensure_capacity(buf
, buf
->datalen
+string_len
)) {
312 log_fn(LOG_WARN
, "buflen too small, can't hold %d bytes.", (int)(buf
->datalen
+string_len
));
316 memcpy(buf
->mem
+buf
->datalen
, string
, string_len
);
317 buf
->datalen
+= string_len
;
318 log_fn(LOG_DEBUG
,"added %d bytes to buf (now %d total).",(int)string_len
, (int)buf
->datalen
);
322 /** Remove <b>string_len</b> bytes from the front of <b>buf</b>, and store them
323 * into <b>string</b>. Return the new buffer size. <b>string_len</b> must be \<=
324 * the number of bytes on the buffer.
326 int fetch_from_buf(char *string
, size_t string_len
, buf_t
*buf
) {
328 /* There must be string_len bytes in buf; write them onto string,
329 * then memmove buf back (that is, remove them from buf).
331 * Return the number of bytes still on the buffer. */
334 tor_assert(string_len
<= buf
->datalen
); /* make sure we don't ask for too much */
337 memcpy(string
,buf
->mem
,string_len
);
338 buf_remove_from_front(buf
, string_len
);
342 /** There is a (possibly incomplete) http statement on <b>buf</b>, of the
343 * form "\%s\\r\\n\\r\\n\%s", headers, body. (body may contain nuls.)
344 * If a) the headers include a Content-Length field and all bytes in
345 * the body are present, or b) there's no Content-Length field and
346 * all headers are present, then:
348 * - strdup headers into <b>*headers_out</b>, and nul-terminate it.
349 * - memdup body into <b>*body_out</b>, and nul-terminate it.
350 * - Then remove them from <b>buf</b>, and return 1.
352 * - If headers or body is NULL, discard that part of the buf.
353 * - If a headers or body doesn't fit in the arg, return -1.
354 * (We ensure that the headers or body don't exceed max len,
355 * _even if_ we're planning to discard them.)
357 * Else, change nothing and return 0.
359 int fetch_from_buf_http(buf_t
*buf
,
360 char **headers_out
, size_t max_headerlen
,
361 char **body_out
, size_t *body_used
, size_t max_bodylen
) {
362 char *headers
, *body
, *p
;
363 size_t headerlen
, bodylen
, contentlen
;
368 if (buf_nul_terminate(buf
)<0) {
369 log_fn(LOG_WARN
,"Couldn't nul-terminate buffer");
372 body
= strstr(headers
,"\r\n\r\n");
374 log_fn(LOG_DEBUG
,"headers not all here yet.");
377 body
+= 4; /* Skip the the CRLFCRLF */
378 headerlen
= body
-headers
; /* includes the CRLFCRLF */
379 bodylen
= buf
->datalen
- headerlen
;
380 log_fn(LOG_DEBUG
,"headerlen %d, bodylen %d.", (int)headerlen
, (int)bodylen
);
382 if (max_headerlen
<= headerlen
) {
383 log_fn(LOG_WARN
,"headerlen %d larger than %d. Failing.", (int)headerlen
,
384 (int)max_headerlen
-1);
387 if (max_bodylen
<= bodylen
) {
388 log_fn(LOG_WARN
,"bodylen %d larger than %d. Failing.", (int)bodylen
, (int)max_bodylen
-1);
392 #define CONTENT_LENGTH "\r\nContent-Length: "
393 p
= strstr(headers
, CONTENT_LENGTH
);
396 i
= atoi(p
+strlen(CONTENT_LENGTH
));
398 log_fn(LOG_WARN
, "Content-Length is less than zero; it looks like someone is trying to crash us.");
402 /* if content-length is malformed, then our body length is 0. fine. */
403 log_fn(LOG_DEBUG
,"Got a contentlen of %d.",(int)contentlen
);
404 if (bodylen
< contentlen
) {
405 log_fn(LOG_DEBUG
,"body not all here yet.");
406 return 0; /* not all there yet */
408 if (bodylen
> contentlen
) {
409 bodylen
= contentlen
;
410 log_fn(LOG_DEBUG
,"bodylen reduced to %d.",(int)bodylen
);
413 /* all happy. copy into the appropriate places, and return 1 */
415 *headers_out
= tor_malloc(headerlen
+1);
416 memcpy(*headers_out
,buf
->mem
,headerlen
);
417 (*headers_out
)[headerlen
] = 0; /* null terminate it */
420 tor_assert(body_used
);
421 *body_used
= bodylen
;
422 *body_out
= tor_malloc(bodylen
+1);
423 memcpy(*body_out
,buf
->mem
+headerlen
,bodylen
);
424 (*body_out
)[bodylen
] = 0; /* null terminate it */
426 buf_remove_from_front(buf
, headerlen
+bodylen
);
430 /** There is a (possibly incomplete) socks handshake on <b>buf</b>, of one
432 * - socks4: "socksheader username\\0"
433 * - socks4a: "socksheader username\\0 destaddr\\0"
434 * - socks5 phase one: "version #methods methods"
435 * - socks5 phase two: "version command 0 addresstype..."
436 * If it's a complete and valid handshake, and destaddr fits in
437 * MAX_SOCKS_ADDR_LEN bytes, then pull the handshake off the buf,
438 * assign to <b>req</b>, and return 1.
440 * If it's invalid or too big, return -1.
442 * Else it's not all there yet, leave buf alone and return 0.
444 * If you want to specify the socks reply, write it into <b>req->reply</b>
445 * and set <b>req->replylen</b>, else leave <b>req->replylen</b> alone.
447 * If returning 0 or -1, <b>req->address</b> and <b>req->port</b> are undefined.
449 int fetch_from_buf_socks(buf_t
*buf
, socks_request_t
*req
) {
453 enum {socks4
, socks4a
} socks4_prot
= socks4a
;
454 char *next
, *startaddr
;
457 /* If the user connects with socks4 or the wrong variant of socks5,
458 * then log a warning to let him know that it might be unwise. */
459 static int have_warned_about_unsafe_socks
= 0;
461 if (buf
->datalen
< 2) /* version and another byte */
463 switch (*(buf
->mem
)) { /* which version of socks? */
467 if (req
->socks_version
!= 5) { /* we need to negotiate a method */
468 unsigned char nummethods
= (unsigned char)*(buf
->mem
+1);
469 tor_assert(!req
->socks_version
);
470 if (buf
->datalen
< 2u+nummethods
)
472 if (!nummethods
|| !memchr(buf
->mem
+2, 0, nummethods
)) {
473 log_fn(LOG_WARN
,"socks5: offered methods don't include 'no auth'. Rejecting.");
474 req
->replylen
= 2; /* 2 bytes of response */
475 req
->reply
[0] = 5; /* socks5 reply */
476 req
->reply
[1] = '\xFF'; /* reject all methods */
479 buf_remove_from_front(buf
,2+nummethods
);/* remove packet from buf */
481 req
->replylen
= 2; /* 2 bytes of response */
482 req
->reply
[0] = 5; /* socks5 reply */
483 req
->reply
[1] = 0; /* choose the 'no auth' method */
484 req
->socks_version
= 5; /* remember that we've already negotiated auth */
485 log_fn(LOG_DEBUG
,"socks5: accepted method 0");
488 /* we know the method; read in the request */
489 log_fn(LOG_DEBUG
,"socks5: checking request");
490 if (buf
->datalen
< 8) /* basic info plus >=2 for addr plus 2 for port */
491 return 0; /* not yet */
492 req
->command
= (unsigned char) *(buf
->mem
+1);
493 if (req
->command
!= SOCKS_COMMAND_CONNECT
&&
494 req
->command
!= SOCKS_COMMAND_RESOLVE
) {
495 /* not a connect or resolve? we don't support it. */
496 log_fn(LOG_WARN
,"socks5: command %d not recognized. Rejecting.",
500 switch (*(buf
->mem
+3)) { /* address type */
501 case 1: /* IPv4 address */
502 log_fn(LOG_DEBUG
,"socks5: ipv4 address type");
503 if (buf
->datalen
< 10) /* ip/port there? */
504 return 0; /* not yet */
506 destip
= ntohl(*(uint32_t*)(buf
->mem
+4));
507 in
.s_addr
= htonl(destip
);
508 tmpbuf
= inet_ntoa(in
);
509 if (strlen(tmpbuf
)+1 > MAX_SOCKS_ADDR_LEN
) {
510 log_fn(LOG_WARN
,"socks5 IP takes %d bytes, which doesn't fit in %d. Rejecting.",
511 (int)strlen(tmpbuf
)+1,(int)MAX_SOCKS_ADDR_LEN
);
514 strlcpy(req
->address
,tmpbuf
,sizeof(req
->address
));
515 req
->port
= ntohs(*(uint16_t*)(buf
->mem
+8));
516 buf_remove_from_front(buf
, 10);
517 if (!have_warned_about_unsafe_socks
) {
518 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
);
519 // have_warned_about_unsafe_socks = 1; // (for now, warn every time)
523 log_fn(LOG_DEBUG
,"socks5: fqdn address type");
524 len
= (unsigned char)*(buf
->mem
+4);
525 if (buf
->datalen
< 7u+len
) /* addr/port there? */
526 return 0; /* not yet */
527 if (len
+1 > MAX_SOCKS_ADDR_LEN
) {
528 log_fn(LOG_WARN
,"socks5 hostname is %d bytes, which doesn't fit in %d. Rejecting.",
529 len
+1,MAX_SOCKS_ADDR_LEN
);
532 memcpy(req
->address
,buf
->mem
+5,len
);
533 req
->address
[len
] = 0;
534 req
->port
= ntohs(get_uint16(buf
->mem
+5+len
));
535 buf_remove_from_front(buf
, 5+len
+2);
537 default: /* unsupported */
538 log_fn(LOG_WARN
,"socks5: unsupported address type %d. Rejecting.",*(buf
->mem
+3));
543 /* http://archive.socks.permeo.com/protocol/socks4.protocol */
544 /* http://archive.socks.permeo.com/protocol/socks4a.protocol */
546 req
->socks_version
= 4;
547 if (buf
->datalen
< SOCKS4_NETWORK_LEN
) /* basic info available? */
548 return 0; /* not yet */
550 req
->command
= (unsigned char) *(buf
->mem
+1);
551 if (req
->command
!= SOCKS_COMMAND_CONNECT
&&
552 req
->command
!= SOCKS_COMMAND_RESOLVE
) {
553 /* not a connect or resolve? we don't support it. */
554 log_fn(LOG_WARN
,"socks4: command %d not recognized. Rejecting.",
559 req
->port
= ntohs(*(uint16_t*)(buf
->mem
+2));
560 destip
= ntohl(*(uint32_t*)(buf
->mem
+4));
561 if ((!req
->port
&& req
->command
!=SOCKS_COMMAND_RESOLVE
) || !destip
) {
562 log_fn(LOG_WARN
,"socks4: Port or DestIP is zero. Rejecting.");
566 log_fn(LOG_DEBUG
,"socks4: destip not in form 0.0.0.x.");
567 in
.s_addr
= htonl(destip
);
568 tmpbuf
= inet_ntoa(in
);
569 if (strlen(tmpbuf
)+1 > MAX_SOCKS_ADDR_LEN
) {
570 log_fn(LOG_WARN
,"socks4 addr (%d bytes) too long. Rejecting.",
571 (int)strlen(tmpbuf
));
574 log_fn(LOG_DEBUG
,"socks4: successfully read destip (%s)", tmpbuf
);
575 socks4_prot
= socks4
;
578 next
= memchr(buf
->mem
+SOCKS4_NETWORK_LEN
, 0,
579 buf
->datalen
-SOCKS4_NETWORK_LEN
);
581 log_fn(LOG_DEBUG
,"socks4: Username not here yet.");
584 tor_assert(next
< buf
->mem
+buf
->datalen
);
587 if (socks4_prot
!= socks4a
&& !have_warned_about_unsafe_socks
) {
588 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
);
589 // have_warned_about_unsafe_socks = 1; // (for now, warn every time)
591 if (socks4_prot
== socks4a
) {
592 if (next
+1 == buf
->mem
+buf
->datalen
) {
593 log_fn(LOG_DEBUG
,"socks4: No part of destaddr here yet.");
597 next
= memchr(startaddr
, 0, buf
->mem
+buf
->datalen
-startaddr
);
599 log_fn(LOG_DEBUG
,"socks4: Destaddr not all here yet.");
602 if (MAX_SOCKS_ADDR_LEN
<= next
-startaddr
) {
603 log_fn(LOG_WARN
,"socks4: Destaddr too long. Rejecting.");
606 tor_assert(next
< buf
->mem
+buf
->datalen
);
608 log_fn(LOG_DEBUG
,"socks4: Everything is here. Success.");
609 strlcpy(req
->address
, startaddr
? startaddr
: tmpbuf
,
610 sizeof(req
->address
));
611 buf_remove_from_front(buf
, next
-buf
->mem
+1); /* next points to the final \0 on inbuf */
616 case 'P': /* put/post */
617 case 'C': /* connect */
619 "HTTP/1.0 501 Tor is not an HTTP Proxy\r\n"
620 "Content-Type: text/html; charset=iso-8859-1\r\n\r\n"
623 "<title>Tor is not an HTTP Proxy</title>\n"
626 "<h1>Tor is not an HTTP Proxy</h1>\n"
628 "It appears you have configured your web browser to use Tor as an HTTP Proxy.\n"
629 "This is not correct: Tor provides a SOCKS proxy. Please configure your\n"
630 "client accordingly.\n"
633 "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"
634 "<!-- 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"
638 , MAX_SOCKS_REPLY_LEN
);
639 req
->replylen
= strlen(req
->reply
)+1;
641 default: /* version is not socks4 or socks5 */
642 log_fn(LOG_WARN
,"Socks version %d not recognized. (Tor is not an http proxy.)",
648 /** If there is a complete control message waiting on buf, then store
649 * its contents into *<b>type_out</b>, store its body's length into
650 * *<b>len_out</b>, allocate and store a string for its body into
651 * *<b>body_out</b>, and return -1. (body_out will always be NUL-terminated,
652 * even if the control message body doesn't end with NUL.)
654 * If there is not a complete control message waiting, return 0.
656 * Return -1 on error.
658 int fetch_from_buf_control(buf_t
*buf
, uint16_t *len_out
, uint16_t *type_out
,
665 tor_assert(type_out
);
666 tor_assert(body_out
);
668 if (buf
->datalen
< 4)
671 len
= ntohs(get_uint16(buf
->mem
));
672 if (buf
->datalen
< 4 + (unsigned)len
)
676 *type_out
= ntohs(get_uint16(buf
->mem
+2));
678 *body_out
= tor_malloc(len
+1);
679 memcpy(*body_out
, buf
->mem
+4, len
);
680 (*body_out
)[len
] = '\0';
685 buf_remove_from_front(buf
, 4+len
);
690 /** Log an error and exit if <b>buf</b> is corrupted.
692 void assert_buf_ok(buf_t
*buf
)
695 tor_assert(buf
->magic
== BUFFER_MAGIC
);
696 tor_assert(buf
->mem
);
697 tor_assert(buf
->datalen
<= buf
->len
);