Tor 0.4.9.0-alpha-dev
control.c
Go to the documentation of this file.
1/* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
2 * Copyright (c) 2007-2021, The Tor Project, Inc. */
3/* See LICENSE for licensing information */
4
5/**
6 * \file control.c
7 * \brief Implementation for Tor's control-socket interface.
8 *
9 * A "controller" is an external program that monitors and controls a Tor
10 * instance via a text-based protocol. It connects to Tor via a connection
11 * to a local socket.
12 *
13 * The protocol is line-driven. The controller sends commands terminated by a
14 * CRLF. Tor sends lines that are either <em>replies</em> to what the
15 * controller has said, or <em>events</em> that Tor sends to the controller
16 * asynchronously based on occurrences in the Tor network model.
17 *
18 * See the control-spec.txt file in the torspec.git repository for full
19 * details on protocol.
20 *
21 * This module generally has two kinds of entry points: those based on having
22 * received a command on a controller socket, which are handled in
23 * connection_control_process_inbuf(), and dispatched to individual functions
24 * with names like control_handle_COMMANDNAME(); and those based on events
25 * that occur elsewhere in Tor, which are handled by functions with names like
26 * control_event_EVENTTYPE().
27 *
28 * Controller events are not sent immediately; rather, they are inserted into
29 * the queued_control_events array, and flushed later from
30 * flush_queued_events_cb(). Doing this simplifies our callgraph greatly,
31 * by limiting the number of places in Tor that can call back into the network
32 * stack.
33 **/
34
35#define CONTROL_MODULE_PRIVATE
36#define CONTROL_PRIVATE
37
38#include "core/or/or.h"
39#include "app/config/config.h"
40#include "app/main/main.h"
53#include "lib/evloop/procmon.h"
54
56
57#ifdef HAVE_UNISTD_H
58#include <unistd.h>
59#endif
60#ifdef HAVE_SYS_STAT_H
61#include <sys/stat.h>
62#endif
63
64/**
65 * Cast a `connection_t *` to a `control_connection_t *`.
66 *
67 * Exit with an assertion failure if the input is not a
68 * `control_connection_t`.
69 **/
72{
73 tor_assert(c->magic == CONTROL_CONNECTION_MAGIC);
75}
76
77/**
78 * Cast a `const connection_t *` to a `const control_connection_t *`.
79 *
80 * Exit with an assertion failure if the input is not a
81 * `control_connection_t`.
82 **/
85{
86 return TO_CONTROL_CONN((connection_t*)c);
87}
88
89/** Create and add a new controller connection on <b>sock</b>. If
90 * <b>CC_LOCAL_FD_IS_OWNER</b> is set in <b>flags</b>, this Tor process should
91 * exit when the connection closes. If <b>CC_LOCAL_FD_IS_AUTHENTICATED</b>
92 * is set, then the connection does not need to authenticate.
93 */
94int
96{
97 if (BUG(! SOCKET_OK(sock)))
98 return -1;
99 const int is_owner = !!(flags & CC_LOCAL_FD_IS_OWNER);
100 const int is_authenticated = !!(flags & CC_LOCAL_FD_IS_AUTHENTICATED);
101 control_connection_t *control_conn = control_connection_new(AF_UNSPEC);
102 connection_t *conn = TO_CONN(control_conn);
103 conn->s = sock;
105 conn->port = 1;
106 conn->address = tor_strdup("<local socket>");
107
108 /* We take ownership of this socket so that later, when we close it,
109 * we don't freak out. */
111
112 if (set_socket_nonblocking(sock) < 0 ||
113 connection_add(conn) < 0) {
114 connection_free(conn);
115 return -1;
116 }
117
118 control_conn->is_owning_control_connection = is_owner;
119
120 if (connection_init_accepted_conn(conn, NULL) < 0) {
121 connection_mark_for_close(conn);
122 return -1;
123 }
124
125 if (is_authenticated) {
127 }
128
129 return 0;
130}
131
132/** Write all of the open control ports to ControlPortWriteToFile */
133void
135{
136 smartlist_t *lines;
137 char *joined = NULL;
138 const or_options_t *options = get_options();
139
140 if (!options->ControlPortWriteToFile)
141 return;
142
143 lines = smartlist_new();
144
146 if (conn->type != CONN_TYPE_CONTROL_LISTENER || conn->marked_for_close)
147 continue;
148#ifdef AF_UNIX
149 if (conn->socket_family == AF_UNIX) {
150 smartlist_add_asprintf(lines, "UNIX_PORT=%s\n", conn->address);
151 continue;
152 }
153#endif /* defined(AF_UNIX) */
154 smartlist_add_asprintf(lines, "PORT=%s:%d\n", conn->address, conn->port);
155 } SMARTLIST_FOREACH_END(conn);
156
157 joined = smartlist_join_strings(lines, "", 0, NULL);
158
159 if (write_str_to_file(options->ControlPortWriteToFile, joined, 0) < 0) {
160 log_warn(LD_CONTROL, "Writing %s failed: %s",
161 options->ControlPortWriteToFile, strerror(errno));
162 }
163#ifndef _WIN32
164 if (options->ControlPortFileGroupReadable) {
165 if (chmod(options->ControlPortWriteToFile, 0640)) {
166 log_warn(LD_FS,"Unable to make %s group-readable.",
167 options->ControlPortWriteToFile);
168 }
169 }
170#endif /* !defined(_WIN32) */
171 tor_free(joined);
172 SMARTLIST_FOREACH(lines, char *, cp, tor_free(cp));
173 smartlist_free(lines);
174}
175
176const struct signal_name_t signal_table[] = {
177 /* NOTE: this table is used for handling SIGNAL commands and generating
178 * SIGNAL events. Order is significant: if there are two entries for the
179 * same numeric signal, the first one is the canonical name generated
180 * for the events. */
181 { SIGHUP, "RELOAD" },
182 { SIGHUP, "HUP" },
183 { SIGINT, "SHUTDOWN" },
184 { SIGUSR1, "DUMP" },
185 { SIGUSR1, "USR1" },
186 { SIGUSR2, "DEBUG" },
187 { SIGUSR2, "USR2" },
188 { SIGTERM, "HALT" },
189 { SIGTERM, "TERM" },
190 { SIGTERM, "INT" },
191 { SIGNEWNYM, "NEWNYM" },
192 { SIGCLEARDNSCACHE, "CLEARDNSCACHE"},
193 { SIGHEARTBEAT, "HEARTBEAT"},
194 { SIGACTIVE, "ACTIVE" },
195 { SIGDORMANT, "DORMANT" },
196 { 0, NULL },
197};
198
199/** Called when <b>conn</b> has no more bytes left on its outbuf. */
200int
202{
203 tor_assert(conn);
204 return 0;
205}
206
207/** Called when <b>conn</b> has gotten its socket closed. */
208int
210{
211 tor_assert(conn);
212
213 log_info(LD_CONTROL,"Control connection reached EOF. Closing.");
214 connection_mark_for_close(TO_CONN(conn));
215 return 0;
216}
217
218/** Shut down this Tor instance in the same way that SIGINT would, but
219 * with a log message appropriate for the loss of an owning controller. */
220static void
221lost_owning_controller(const char *owner_type, const char *loss_manner)
222{
223 log_notice(LD_CONTROL, "Owning controller %s has %s -- exiting now.",
224 owner_type, loss_manner);
225
226 activate_signal(SIGTERM);
227}
228
229/** Called when <b>conn</b> is being freed. */
230void
232{
233 tor_assert(conn);
234
235 conn->event_mask = 0;
237
238 /* Close all ephemeral Onion Services if any.
239 * The list and it's contents are scrubbed/freed in connection_free_.
240 */
241 if (conn->ephemeral_onion_services) {
243 if (hs_address_is_valid(cp)) {
245 } else {
246 /* An invalid .onion in our list should NEVER happen */
248 }
249 } SMARTLIST_FOREACH_END(cp);
250 }
251
253 lost_owning_controller("connection", "closed");
254 }
255}
256
257/** Return true iff <b>cmd</b> is allowable (or at least forgivable) at this
258 * stage of the protocol. */
259static int
261{
262 if (conn->base_.state == CONTROL_CONN_STATE_OPEN)
263 return 1;
264 if (!strcasecmp(cmd, "PROTOCOLINFO"))
265 return (!conn->have_sent_protocolinfo &&
266 conn->safecookie_client_hash == NULL);
267 if (!strcasecmp(cmd, "AUTHCHALLENGE"))
268 return (conn->safecookie_client_hash == NULL);
269 if (!strcasecmp(cmd, "AUTHENTICATE") ||
270 !strcasecmp(cmd, "QUIT"))
271 return 1;
272 return 0;
273}
274
275/** Do not accept any control command of more than 1MB in length. Anything
276 * that needs to be anywhere near this long probably means that one of our
277 * interfaces is broken. */
278#define MAX_COMMAND_LINE_LENGTH (1024*1024)
279
280/** Wrapper around peek_buf_has_control0 command: presents the same
281 * interface as that underlying functions, but takes a connection_t instead of
282 * a buf_t.
283 */
284static int
286{
288}
289
290static int
291peek_connection_has_http_command(connection_t *conn)
292{
293 return peek_buf_has_http_command(conn->inbuf);
294}
295
296/**
297 * Helper: take a nul-terminated command of given length, and find where the
298 * command starts and the arguments begin. Separate them, allocate a new
299 * string in <b>current_cmd_out</b> for the command, and return a pointer
300 * to the arguments.
301 **/
302STATIC char *
304 size_t *data_len,
305 char **current_cmd_out)
306{
307 const bool is_multiline = *data_len && incoming_cmd[0] == '+';
308 size_t cmd_len = 0;
309 while (cmd_len < *data_len
310 && !TOR_ISSPACE(incoming_cmd[cmd_len]))
311 ++cmd_len;
312
313 *current_cmd_out = tor_memdup_nulterm(incoming_cmd, cmd_len);
314 char *args = incoming_cmd+cmd_len;
315 tor_assert(*data_len>=cmd_len);
316 *data_len -= cmd_len;
317 if (is_multiline) {
318 // Only match horizontal space: any line after the first is data,
319 // not arguments.
320 while ((*args == '\t' || *args == ' ') && *data_len) {
321 ++args;
322 --*data_len;
323 }
324 } else {
325 while (TOR_ISSPACE(*args) && *data_len) {
326 ++args;
327 --*data_len;
328 }
329 }
330
331 return args;
332}
333
334static const char CONTROLPORT_IS_NOT_AN_HTTP_PROXY_MSG[] =
335 "HTTP/1.0 501 Tor ControlPort is not an HTTP proxy"
336 "\r\nContent-Type: text/html; charset=iso-8859-1\r\n\r\n"
337 "<html>\n"
338 "<head>\n"
339 "<title>Tor's ControlPort is not an HTTP proxy</title>\n"
340 "</head>\n"
341 "<body>\n"
342 "<h1>Tor's ControlPort is not an HTTP proxy</h1>\n"
343 "<p>\n"
344 "It appears you have configured your web browser to use Tor's control port"
345 " as an HTTP proxy.\n"
346 "This is not correct: Tor's default SOCKS proxy port is 9050.\n"
347 "Please configure your client accordingly.\n"
348 "</p>\n"
349 "<p>\n"
350 "See <a href=\"https://www.torproject.org/documentation.html\">"
351 "https://www.torproject.org/documentation.html</a> for more "
352 "information.\n"
353 "<!-- Plus this comment, to make the body response more than 512 bytes, so "
354 " IE will be willing to display it. Comment comment comment comment "
355 " comment comment comment comment comment comment comment comment.-->\n"
356 "</p>\n"
357 "</body>\n"
358 "</html>\n";
359
360/** Return an error on a control connection that tried to use the v0 protocol.
361 */
362static void
364{
365 size_t body_len;
366 char buf[128];
367 set_uint16(buf+2, htons(0x0000)); /* type == error */
368 set_uint16(buf+4, htons(0x0001)); /* code == internal error */
369 strlcpy(buf+6, "The v0 control protocol is not supported by Tor 0.1.2.17 "
370 "and later; upgrade your controller.",
371 sizeof(buf)-6);
372 body_len = 2+strlen(buf+6)+2; /* code, msg, nul. */
373 set_uint16(buf+0, htons(body_len));
374 connection_buf_add(buf, 4+body_len, TO_CONN(conn));
375
376 connection_mark_and_flush(TO_CONN(conn));
377}
378
379/** Return an error on a control connection that tried to use HTTP.
380 */
381static void
383{
384 connection_write_str_to_buf(CONTROLPORT_IS_NOT_AN_HTTP_PROXY_MSG, conn);
385 log_notice(LD_CONTROL, "Received HTTP request on ControlPort");
386 connection_mark_and_flush(TO_CONN(conn));
387}
388
389/** Check if a control connection has tried to use a known invalid protocol.
390 * If it has, then:
391 * - send a reject response,
392 * - log a notice-level message, and
393 * - return false. */
394static bool
396{
397 /* Detect v0 commands and send a "no more v0" message. */
398 if (conn->base_.state == CONTROL_CONN_STATE_NEEDAUTH &&
401 return 0;
402 }
403
404 /* If the user has the HTTP proxy port and the control port confused. */
405 if (conn->base_.state == CONTROL_CONN_STATE_NEEDAUTH &&
406 peek_connection_has_http_command(TO_CONN(conn))) {
408 return 0;
409 }
410
411 return 1;
412}
413
414/** Called when data has arrived on a v1 control connection: Try to fetch
415 * commands from conn->inbuf, and execute them.
416 */
417int
419{
420 size_t data_len;
421 uint32_t cmd_data_len;
422 char *args;
423
424 tor_assert(conn);
426 conn->base_.state == CONTROL_CONN_STATE_NEEDAUTH);
427
428 if (!conn->incoming_cmd) {
429 conn->incoming_cmd = tor_malloc(1024);
430 conn->incoming_cmd_len = 1024;
431 conn->incoming_cmd_cur_len = 0;
432 }
433
434 if (!control_protocol_is_valid(conn)) {
435 return 0;
436 }
437
438 again:
439 while (1) {
440 size_t last_idx;
441 int r;
442 /* First, fetch a line. */
443 do {
444 data_len = conn->incoming_cmd_len - conn->incoming_cmd_cur_len;
447 &data_len);
448 if (r == 0)
449 /* Line not all here yet. Wait. */
450 return 0;
451 else if (r == -1) {
452 if (data_len + conn->incoming_cmd_cur_len > MAX_COMMAND_LINE_LENGTH) {
453 control_write_endreply(conn, 500, "Line too long.");
455 connection_mark_and_flush(TO_CONN(conn));
456 }
457 while (conn->incoming_cmd_len < data_len+conn->incoming_cmd_cur_len)
458 conn->incoming_cmd_len *= 2;
459 conn->incoming_cmd = tor_realloc(conn->incoming_cmd,
460 conn->incoming_cmd_len);
461 }
462 } while (r != 1);
463
464 tor_assert(data_len);
465
466 last_idx = conn->incoming_cmd_cur_len;
467 conn->incoming_cmd_cur_len += (int)data_len;
468
469 /* We have appended a line to incoming_cmd. Is the command done? */
470 if (last_idx == 0 && *conn->incoming_cmd != '+')
471 /* One line command, didn't start with '+'. */
472 break;
473 /* XXXX this code duplication is kind of dumb. */
474 if (last_idx+3 == conn->incoming_cmd_cur_len &&
475 tor_memeq(conn->incoming_cmd + last_idx, ".\r\n", 3)) {
476 /* Just appended ".\r\n"; we're done. Remove it. */
477 conn->incoming_cmd[last_idx] = '\0';
478 conn->incoming_cmd_cur_len -= 3;
479 break;
480 } else if (last_idx+2 == conn->incoming_cmd_cur_len &&
481 tor_memeq(conn->incoming_cmd + last_idx, ".\n", 2)) {
482 /* Just appended ".\n"; we're done. Remove it. */
483 conn->incoming_cmd[last_idx] = '\0';
484 conn->incoming_cmd_cur_len -= 2;
485 break;
486 }
487 /* Otherwise, read another line. */
488 }
489 data_len = conn->incoming_cmd_cur_len;
490
491 /* Okay, we now have a command sitting on conn->incoming_cmd. See if we
492 * recognize it.
493 */
494 tor_free(conn->current_cmd);
495 args = control_split_incoming_command(conn->incoming_cmd, &data_len,
496 &conn->current_cmd);
497 if (BUG(!conn->current_cmd))
498 return -1;
499
500 /* If the connection is already closing, ignore further commands */
501 if (TO_CONN(conn)->marked_for_close) {
502 return 0;
503 }
504
505 /* Otherwise, Quit is always valid. */
506 if (!strcasecmp(conn->current_cmd, "QUIT")) {
507 control_write_endreply(conn, 250, "closing connection");
508 connection_mark_and_flush(TO_CONN(conn));
509 return 0;
510 }
511
512 if (conn->base_.state == CONTROL_CONN_STATE_NEEDAUTH &&
514 control_write_endreply(conn, 514, "Authentication required.");
515 connection_mark_for_close(TO_CONN(conn));
516 return 0;
517 }
518
519 if (data_len >= UINT32_MAX) {
520 control_write_endreply(conn, 500, "A 4GB command? Nice try.");
521 connection_mark_for_close(TO_CONN(conn));
522 return 0;
523 }
524
525 cmd_data_len = (uint32_t)data_len;
526 if (handle_control_command(conn, cmd_data_len, args) < 0)
527 return -1;
528
529 conn->incoming_cmd_cur_len = 0;
530 goto again;
531}
532
533/** Cached liveness for network liveness events and GETINFO
534 */
535
536static int network_is_live = 0;
537
538int
539get_cached_network_liveness(void)
540{
541 return network_is_live;
542}
543
544void
545set_cached_network_liveness(int liveness)
546{
547 network_is_live = liveness;
548}
549
550/** A copy of the process specifier of Tor's owning controller, or
551 * NULL if this Tor instance is not currently owned by a process. */
553
554/** A process-termination monitor for Tor's owning controller, or NULL
555 * if this Tor instance is not currently owned by a process. */
557
558/** Process-termination monitor callback for Tor's owning controller
559 * process. */
560static void
562{
563 (void)unused;
564
565 lost_owning_controller("process", "vanished");
566}
567
568/** Set <b>process_spec</b> as Tor's owning controller process.
569 * Exit on failure. */
570void
571monitor_owning_controller_process(const char *process_spec)
572{
573 const char *msg;
574
577
578 if (owning_controller_process_spec != NULL) {
579 if ((process_spec != NULL) && !strcmp(process_spec,
581 /* Same process -- return now, instead of disposing of and
582 * recreating the process-termination monitor. */
583 return;
584 }
585
586 /* We are currently owned by a process, and we should no longer be
587 * owned by it. Free the process-termination monitor. */
588 tor_process_monitor_free(owning_controller_process_monitor);
590
593 }
594
597
598 if (process_spec == NULL)
599 return;
600
601 owning_controller_process_spec = tor_strdup(process_spec);
607 &msg);
608
610 log_err(LD_BUG, "Couldn't create process-termination monitor for "
611 "owning controller: %s. Exiting.",
612 msg);
615 }
616}
617
618/** Free any leftover allocated memory of the control.c subsystem. */
619void
621{
622 control_auth_free_all();
623 control_events_free_all();
624 control_cmd_free_all();
626}
void tor_addr_make_unspec(tor_addr_t *a)
Definition: address.c:225
static void set_uint16(void *cp, uint16_t v)
Definition: bytes.h:78
struct event_base * tor_libevent_get_base(void)
const or_options_t * get_options(void)
Definition: config.c:944
Header file for config.c.
int connection_buf_get_line(connection_t *conn, char *data, size_t *data_len)
Definition: connection.c:4331
int connection_init_accepted_conn(connection_t *conn, const listener_connection_t *listener)
Definition: connection.c:2111
control_connection_t * control_connection_new(int socket_family)
Definition: connection.c:642
Header file for connection.c.
#define CONN_TYPE_CONTROL_LISTENER
Definition: connection.h:58
Header file for connection_or.c.
void control_ports_write_to_file(void)
Definition: control.c:134
static void control_send_http_reject(control_connection_t *conn)
Definition: control.c:382
static int peek_connection_has_control0_command(connection_t *conn)
Definition: control.c:285
int control_connection_add_local_fd(tor_socket_t sock, unsigned flags)
Definition: control.c:95
#define MAX_COMMAND_LINE_LENGTH
Definition: control.c:278
static int is_valid_initial_command(control_connection_t *conn, const char *cmd)
Definition: control.c:260
static char * owning_controller_process_spec
Definition: control.c:552
control_connection_t * TO_CONTROL_CONN(connection_t *c)
Definition: control.c:71
void control_free_all(void)
Definition: control.c:620
STATIC char * control_split_incoming_command(char *incoming_cmd, size_t *data_len, char **current_cmd_out)
Definition: control.c:303
static void lost_owning_controller(const char *owner_type, const char *loss_manner)
Definition: control.c:221
int connection_control_reached_eof(control_connection_t *conn)
Definition: control.c:209
void connection_control_closed(control_connection_t *conn)
Definition: control.c:231
static void owning_controller_procmon_cb(void *unused)
Definition: control.c:561
static tor_process_monitor_t * owning_controller_process_monitor
Definition: control.c:556
const control_connection_t * CONST_TO_CONTROL_CONN(const connection_t *c)
Definition: control.c:84
void monitor_owning_controller_process(const char *process_spec)
Definition: control.c:571
static int network_is_live
Definition: control.c:536
int connection_control_finished_flushing(control_connection_t *conn)
Definition: control.c:201
static void control_send_v0_reject(control_connection_t *conn)
Definition: control.c:363
static bool control_protocol_is_valid(control_connection_t *conn)
Definition: control.c:395
int connection_control_process_inbuf(control_connection_t *conn)
Definition: control.c:418
Header file for control.c.
#define CONTROL_CONN_STATE_OPEN
Definition: control.h:20
#define CONTROL_CONN_STATE_NEEDAUTH
Definition: control.h:23
Header file for control_auth.c.
void control_event_bootstrap_reset(void)
int handle_control_command(control_connection_t *conn, uint32_t cmd_data_len, char *args)
Definition: control_cmd.c:2209
Header file for control_cmd.c.
Controller connection structure.
void control_update_global_event_mask(void)
Header file for control_events.c.
void control_write_endreply(control_connection_t *conn, int code, const char *s)
void connection_write_str_to_buf(const char *s, control_connection_t *conn)
Definition: control_proto.c:32
Header file for control_proto.c.
int tor_memeq(const void *a, const void *b, size_t sz)
Definition: di_ops.c:107
int write_str_to_file(const char *fname, const char *str, int bin)
Definition: files.c:274
int hs_address_is_valid(const char *address)
Definition: hs_common.c:856
Header file containing common data for the whole HS subsystem.
int hs_service_del_ephemeral(const char *address)
Definition: hs_service.c:4154
Header file containing service data for the HS subsystem.
#define LD_FS
Definition: log.h:70
#define LD_BUG
Definition: log.h:86
#define LD_CONTROL
Definition: log.h:80
Header file for main.c.
void connection_stop_reading(connection_t *conn)
Definition: mainloop.c:601
smartlist_t * get_connection_array(void)
Definition: mainloop.c:443
void tor_shutdown_event_loop_and_exit(int exitcode)
Definition: mainloop.c:773
Header file for mainloop.c.
#define tor_free(p)
Definition: malloc.h:56
#define SOCKET_OK(s)
Definition: nettypes.h:39
#define tor_socket_t
Definition: nettypes.h:36
Master header file for Tor-specific functionality.
#define TO_CONN(c)
Definition: or.h:612
#define DOWNCAST(to, ptr)
Definition: or.h:109
tor_process_monitor_t * tor_process_monitor_new(struct event_base *base, const char *process_spec, log_domain_mask_t log_domain, tor_procmon_callback_t cb, void *cb_arg, const char **msg)
Definition: procmon.c:181
Headers for procmon.c.
int peek_buf_has_control0_command(buf_t *buf)
Header for proto_control0.c.
int peek_buf_has_http_command(const buf_t *buf)
Definition: proto_http.c:19
Header for proto_http.c.
void smartlist_add_asprintf(struct smartlist_t *sl, const char *pattern,...)
Definition: smartlist.c:36
char * smartlist_join_strings(smartlist_t *sl, const char *join, int terminate, size_t *len_out)
Definition: smartlist.c:279
smartlist_t * smartlist_new(void)
#define SMARTLIST_FOREACH_BEGIN(sl, type, var)
#define SMARTLIST_FOREACH(sl, type, var, cmd)
int set_socket_nonblocking(tor_socket_t sock)
Definition: socket.c:560
void tor_take_socket_ownership(tor_socket_t s)
Definition: socket.c:334
uint8_t state
Definition: connection_st.h:49
struct buf_t * inbuf
uint32_t magic
Definition: connection_st.h:46
uint16_t port
tor_socket_t s
tor_addr_t addr
smartlist_t * ephemeral_onion_services
unsigned int is_owning_control_connection
unsigned int have_sent_protocolinfo
char * ControlPortWriteToFile
int ControlPortFileGroupReadable
#define STATIC
Definition: testsupport.h:32
#define tor_assert(expr)
Definition: util_bug.h:103
#define tor_fragile_assert()
Definition: util_bug.h:278