📄 control.c
字号:
*outp++ = '\n';
}
*outp = '\0';
return outp - *out;
}
/** If the first <b>in_len_max</b> characters in <b>start<b> contain a
* double-quoted string with escaped characters, return the length of that
* string (as encoded, including quotes). Otherwise return -1. */
static INLINE int
get_escaped_string_length(const char *start, size_t in_len_max,
int *chars_out)
{
const char *cp, *end;
int chars = 0;
if (*start != '\"')
return -1;
cp = start+1;
end = start+in_len_max;
/* Calculate length. */
while (1) {
if (cp >= end) {
return -1; /* Too long. */
} else if (*cp == '\\') {
if (++cp == end)
return -1; /* Can't escape EOS. */
++cp;
++chars;
} else if (*cp == '\"') {
break;
} else {
++cp;
++chars;
}
}
if (chars_out)
*chars_out = chars;
return (int)(cp - start+1);
}
/** As decode_escaped_string, but does not decode the string: copies the
* entire thing, including quotation marks. */
static const char *
extract_escaped_string(const char *start, size_t in_len_max,
char **out, size_t *out_len)
{
int length = get_escaped_string_length(start, in_len_max, NULL);
if (length<0)
return NULL;
*out_len = length;
*out = tor_strndup(start, *out_len);
return start+length;
}
/** Given a pointer to a string starting at <b>start</b> containing
* <b>in_len_max</b> characters, decode a string beginning with one double
* quote, containing any number of non-quote characters or characters escaped
* with a backslash, and ending with a final double quote. Place the resulting
* string (unquoted, unescaped) into a newly allocated string in *<b>out</b>;
* store its length in <b>out_len</b>. On success, return a pointer to the
* character immediately following the escaped string. On failure, return
* NULL. */
static const char *
decode_escaped_string(const char *start, size_t in_len_max,
char **out, size_t *out_len)
{
const char *cp, *end;
char *outp;
int len, n_chars = 0;
len = get_escaped_string_length(start, in_len_max, &n_chars);
if (len<0)
return NULL;
end = start+len-1; /* Index of last quote. */
tor_assert(*end == '\"');
outp = *out = tor_malloc(len+1);
*out_len = n_chars;
cp = start+1;
while (cp < end) {
if (*cp == '\\')
++cp;
*outp++ = *cp++;
}
*outp = '\0';
tor_assert((outp - *out) == (int)*out_len);
return end+1;
}
/** Acts like sprintf, but writes its formatted string to the end of
* <b>conn</b>-\>outbuf. The message may be truncated if it is too long,
* but it will always end with a CRLF sequence.
*
* Currently the length of the message is limited to 1024 (including the
* ending \r\n\0. */
static void
connection_printf_to_buf(control_connection_t *conn, const char *format, ...)
{
#define CONNECTION_PRINTF_TO_BUF_BUFFERSIZE 1024
va_list ap;
char buf[CONNECTION_PRINTF_TO_BUF_BUFFERSIZE];
int r;
size_t len;
va_start(ap,format);
r = tor_vsnprintf(buf, sizeof(buf), format, ap);
va_end(ap);
if (r<0) {
log_warn(LD_BUG, "Unable to format string for controller.");
return;
}
len = strlen(buf);
if (memcmp("\r\n\0", buf+len-2, 3)) {
buf[CONNECTION_PRINTF_TO_BUF_BUFFERSIZE-1] = '\0';
buf[CONNECTION_PRINTF_TO_BUF_BUFFERSIZE-2] = '\n';
buf[CONNECTION_PRINTF_TO_BUF_BUFFERSIZE-3] = '\r';
}
connection_write_to_buf(buf, len, TO_CONN(conn));
}
/** Send a "DONE" message down the control connection <b>conn</b>. */
static void
send_control_done(control_connection_t *conn)
{
connection_write_str_to_buf("250 OK\r\n", conn);
}
/* Send an event to all v1 controllers that are listening for code
* <b>event</b>. The event's body is given by <b>msg</b>.
*
* If <b>which</b> & SHORT_NAMES, the event contains short-format names: send
* it to controllers that haven't enabled the VERBOSE_NAMES feature. If
* <b>which</b> & LONG_NAMES, the event contains long-format names: send it
* to contollers that <em>have</em> enabled VERBOSE_NAMES.
*
* The EXTENDED_FORMAT and NONEXTENDED_FORMAT flags behave similarly with
* respect to the EXTENDED_EVENTS feature. */
static void
send_control_event_string(uint16_t event, event_format_t which,
const char *msg)
{
smartlist_t *conns = get_connection_array();
tor_assert(event >= _EVENT_MIN && event <= _EVENT_MAX);
SMARTLIST_FOREACH(conns, connection_t *, conn,
{
if (conn->type == CONN_TYPE_CONTROL &&
!conn->marked_for_close &&
conn->state == CONTROL_CONN_STATE_OPEN) {
control_connection_t *control_conn = TO_CONTROL_CONN(conn);
if (control_conn->use_long_names) {
if (!(which & LONG_NAMES))
continue;
} else {
if (!(which & SHORT_NAMES))
continue;
}
if (control_conn->use_extended_events) {
if (!(which & EXTENDED_FORMAT))
continue;
} else {
if (!(which & NONEXTENDED_FORMAT))
continue;
}
if (control_conn->event_mask & (1<<event)) {
int is_err = 0;
connection_write_to_buf(msg, strlen(msg), TO_CONN(control_conn));
if (event == EVENT_ERR_MSG)
is_err = 1;
else if (event == EVENT_STATUS_GENERAL)
is_err = !strcmpstart(msg, "STATUS_GENERAL ERR ");
else if (event == EVENT_STATUS_CLIENT)
is_err = !strcmpstart(msg, "STATUS_CLIENT ERR ");
else if (event == EVENT_STATUS_SERVER)
is_err = !strcmpstart(msg, "STATUS_SERVER ERR ");
if (is_err)
connection_handle_write(TO_CONN(control_conn), 1);
}
}
});
}
/** Helper for send_control1_event and send_control1_event_extended:
* Send an event to all v1 controllers that are listening for code
* <b>event</b>. The event's body is created by the printf-style format in
* <b>format</b>, and other arguments as provided.
*
* If <b>extended</b> is true, and the format contains a single '@' character,
* it will be replaced with a space and all text after that character will be
* sent only to controllers that have enabled extended events.
*
* Currently the length of the message is limited to 1024 (including the
* ending \n\r\0). */
static void
send_control_event_impl(uint16_t event, event_format_t which, int extended,
const char *format, va_list ap)
{
/* This is just a little longer than the longest allowed log message */
#define SEND_CONTROL1_EVENT_BUFFERSIZE 10064
int r;
char buf[SEND_CONTROL1_EVENT_BUFFERSIZE];
size_t len;
char *cp;
r = tor_vsnprintf(buf, sizeof(buf), format, ap);
if (r<0) {
log_warn(LD_BUG, "Unable to format event for controller.");
return;
}
len = strlen(buf);
if (memcmp("\r\n\0", buf+len-2, 3)) {
/* if it is not properly terminated, do it now */
buf[SEND_CONTROL1_EVENT_BUFFERSIZE-1] = '\0';
buf[SEND_CONTROL1_EVENT_BUFFERSIZE-2] = '\n';
buf[SEND_CONTROL1_EVENT_BUFFERSIZE-3] = '\r';
}
if (extended && (cp = strchr(buf, '@'))) {
which &= ~ALL_FORMATS;
*cp = ' ';
send_control_event_string(event, which|EXTENDED_FORMAT, buf);
memcpy(cp, "\r\n\0", 3);
send_control_event_string(event, which|NONEXTENDED_FORMAT, buf);
} else {
send_control_event_string(event, which|ALL_FORMATS, buf);
}
}
/* Send an event to all v1 controllers that are listening for code
* <b>event</b>. The event's body is created by the printf-style format in
* <b>format</b>, and other arguments as provided.
*
* Currently the length of the message is limited to 1024 (including the
* ending \n\r\0. */
static void
send_control_event(uint16_t event, event_format_t which,
const char *format, ...)
{
va_list ap;
va_start(ap, format);
send_control_event_impl(event, which, 0, format, ap);
va_end(ap);
}
/* Send an event to all v1 controllers that are listening for code
* <b>event</b>. The event's body is created by the printf-style format in
* <b>format</b>, and other arguments as provided.
*
* If the format contains a single '@' character, it will be replaced with a
* space and all text after that character will be sent only to controllers
* that have enabled extended events.
*
* Currently the length of the message is limited to 1024 (including the
* ending \n\r\0. */
static void
send_control_event_extended(uint16_t event, event_format_t which,
const char *format, ...)
{
va_list ap;
va_start(ap, format);
send_control_event_impl(event, which, 1, format, ap);
va_end(ap);
}
/** Given a text circuit <b>id</b>, return the corresponding circuit. */
static origin_circuit_t *
get_circ(const char *id)
{
uint32_t n_id;
int ok;
n_id = (uint32_t) tor_parse_ulong(id, 10, 0, UINT32_MAX, &ok, NULL);
if (!ok)
return NULL;
return circuit_get_by_global_id(n_id);
}
/** Given a text stream <b>id</b>, return the corresponding AP connection. */
static edge_connection_t *
get_stream(const char *id)
{
uint32_t n_id;
int ok;
edge_connection_t *conn;
n_id = (uint32_t) tor_parse_ulong(id, 10, 0, UINT32_MAX, &ok, NULL);
if (!ok)
return NULL;
conn = connection_get_by_global_id(n_id);
if (!conn || conn->_base.type != CONN_TYPE_AP)
return NULL;
return conn;
}
/** Helper for setconf and resetconf. Acts like setconf, except
* it passes <b>use_defaults</b> on to options_trial_assign(). Modifies the
* contents of body.
*/
static int
control_setconf_helper(control_connection_t *conn, uint32_t len, char *body,
int use_defaults)
{
setopt_err_t opt_err;
config_line_t *lines=NULL;
char *start = body;
char *errstring = NULL;
const int clear_first = 1;
char *config;
smartlist_t *entries = smartlist_create();
/* We have a string, "body", of the format '(key(=val|="val")?)' entries
* separated by space. break it into a list of configuration entries. */
while (*body) {
char *eq = body;
char *key;
char *entry;
while (!TOR_ISSPACE(*eq) && *eq != '=')
++eq;
key = tor_strndup(body, eq-body);
body = eq+1;
if (*eq == '=') {
char *val=NULL;
size_t val_len=0;
size_t ent_len;
if (*body != '\"') {
char *val_start = body;
while (!TOR_ISSPACE(*body))
body++;
val = tor_strndup(val_start, body-val_start);
val_len = strlen(val);
} else {
body = (char*)extract_escaped_string(body, (len - (body-start)),
&val, &val_len);
if (!body) {
connection_write_str_to_buf("551 Couldn't parse string\r\n", conn);
SMARTLIST_FOREACH(entries, char *, cp, tor_free(cp));
smartlist_free(entries);
tor_free(key);
return 0;
}
}
ent_len = strlen(key)+val_len+3;
entry = tor_malloc(ent_len+1);
tor_snprintf(entry, ent_len, "%s %s", key, val);
tor_free(key);
tor_free(val);
} else {
entry = key;
}
smartlist_add(entries, entry);
while (TOR_ISSPACE(*body))
++body;
}
smartlist_add(entries, tor_strdup(""));
config = smartlist_join_strings(entries, "\n", 0, NULL);
SMARTLIST_FOREACH(entries, char *, cp, tor_free(cp));
smartlist_free(entries);
if (config_get_lines(config, &lines) < 0) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -