[or-cvs] Implement even more control functionality

Nick Mathewson nickm at seul.org
Sat Jun 18 02:39:27 UTC 2005


Update of /home/or/cvsroot/tor/src/or
In directory moria:/tmp/cvs-serv21202/src/or

Modified Files:
	control.c 
Log Message:
Implement even more control functionality

Index: control.c
===================================================================
RCS file: /home/or/cvsroot/tor/src/or/control.c,v
retrieving revision 1.90
retrieving revision 1.91
diff -u -d -r1.90 -r1.91
--- control.c	17 Jun 2005 20:37:21 -0000	1.90
+++ control.c	18 Jun 2005 02:39:25 -0000	1.91
@@ -257,6 +257,116 @@
   connection_write_to_buf(s, len, conn);
 }
 
+static size_t
+write_escaped_data(const char *data, size_t len, int translate_newlines,
+                   char **out)
+{
+  size_t sz_out = len+8;
+  char *outp;
+  const char *end;
+  int i;
+  int start_of_line;
+  for (i=0; i<len; ++i) {
+    if (data[i]== '\n')
+      ++sz_out;
+  }
+  *out = outp = tor_malloc(sz_out+1);
+  end = data+len;
+  start_of_line = 1;
+  while (data < end) {
+    if (*data == '\n') {
+      if (translate_newlines)
+        *outp++ = '\r';
+      start_of_line = 1;
+    } else if (*data == '.') {
+      if (start_of_line) {
+        start_of_line = 0;
+        *outp++ = '.';
+      }
+    } else {
+      start_of_line = 0;
+    }
+    *outp++ = *data++;
+  }
+  *outp++ = '\r';
+  *outp++ = '\n';
+  *outp++ = '.';
+  *outp++ = '\r';
+  *outp++ = '\n';
+  return outp - *out;
+}
+
+#if 0
+static void
+connection_write_escaped_data_to_buf(const char *data, size_t len,
+                                     int translate_newlines,
+                                     connection_t *conn)
+{
+  const char *next;
+
+  while (len) {
+    if (*data == '.')
+      connection_write_to_buf(".", 1, conn);
+
+    if (translate_newlines)
+      next = tor_memmem(data, len, "\r\n", 2);
+    else
+      next = tor_memmem(data, len, "\r\n.", 3);
+
+    if (next) {
+      if (translate_newlines) {
+        connection_write_to_buf(data, next-data, conn);
+        connection_write_to_buf("\n", 1, conn);
+        len -= (next-data+2);
+      } else {
+        connection_write_to_buf(data, next-data+2, conn);
+        len -= (next-data+2);
+      }
+      data = next + 2;
+    } else {
+      connection_write_to_buf(data, len, conn);
+      break;
+    }
+  }
+  connection_write_to_buf(".\r\n", 3, conn);
+}
+#endif
+
+static size_t
+read_escaped_data(const char *data, size_t len, int translate_newlines,
+                  char **out)
+{
+  char *outp;
+  const char *next;
+
+  *out = outp = tor_malloc(len);
+
+  while (len) {
+    if (*data == '.')
+      ++data;
+    if (translate_newlines)
+      next = tor_memmem(data, len, "\r\n", 2);
+    else
+      next = tor_memmem(data, len, "\r\n.", 3);
+    if (next) {
+      memcpy(outp, data, next-data);
+      outp += (next-data);
+      data = next+2;
+    } else {
+      memcpy(outp, data, len);
+      outp += len;
+      return outp - *out;
+    }
+    if (translate_newlines) {
+      *outp++ = '\n';
+    } else {
+      *outp++ = '\r';
+      *outp++ = '\n';
+    }
+  }
+
+  return outp - *out;
+}
 
 
 static void
@@ -441,6 +551,32 @@
   }
 }
 
+static circuit_t *
+get_circ(const char *id)
+{
+  unsigned long n_id;
+  int ok;
+  n_id = tor_parse_ulong(id, 10, 0, ULONG_MAX, &ok, NULL);
+  if (!ok)
+    return NULL;
+  return circuit_get_by_global_id(n_id);
+}
+
+static connection_t *
+get_stream(const char *id)
+{
+  unsigned long n_id;
+  int ok;
+  connection_t *conn;
+  n_id = tor_parse_ulong(id, 10, 0, ULONG_MAX, &ok, NULL);
+  if (!ok)
+    return NULL;
+  conn = connection_get_by_global_id(n_id);
+  if (conn->type != CONN_TYPE_AP)
+    return NULL;
+  return conn;
+}
+
 /** Called when we receive a SETCONF message: parse the body and try
  * to update our configuration.  Reply with a DONE or ERROR message. */
 static int
@@ -892,39 +1028,86 @@
 static int
 handle_control_getinfo(connection_t *conn, uint32_t len, const char *body)
 {
-  /* XXXX V1 */
   smartlist_t *questions = NULL;
   smartlist_t *answers = NULL;
+  smartlist_t *unrecognized = NULL;
   char *msg = NULL, *ans;
   size_t msg_len;
+  int v0 = STATE_IS_V0(conn->state);
 
   questions = smartlist_create();
-  smartlist_split_string(questions, body, "\n",
-                         SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
+  if (v0)
+    smartlist_split_string(questions, body, "\n",
+                           SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
+  else
+    smartlist_split_string(questions, body, " ",
+                           SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
   answers = smartlist_create();
+  unrecognized = smartlist_create();
   SMARTLIST_FOREACH(questions, const char *, q,
   {
     if (handle_getinfo_helper(q, &ans) < 0) {
-      send_control0_error(conn, ERR_INTERNAL, body);
-      goto done;
-    } if (!ans) {
-      send_control0_error(conn, ERR_UNRECOGNIZED_CONFIG_KEY, body);
+      if (v0)
+        send_control0_error(conn, ERR_INTERNAL, body);
+      else
+        connection_write_str_to_buf("551 Internal error\r\n", conn);
       goto done;
     }
-    smartlist_add(answers, tor_strdup(q));
-    smartlist_add(answers, ans);
+    if (!ans) {
+      if (v0) {
+        send_control0_error(conn, ERR_UNRECOGNIZED_CONFIG_KEY, body);
+        goto done;
+      } else
+        smartlist_add(unrecognized, (char*)q);
+    } else {
+      smartlist_add(answers, tor_strdup(q));
+      smartlist_add(answers, ans);
+    }
   });
+  if (smartlist_len(unrecognized)) {
+    int i;
+    tor_assert(!v0);
+    for (i=0; i < len-1; ++i)
+      connection_printf_to_buf(conn,
+                               "552-Unrecognized configuration key \"%s\"\r\n",
+                               (char*)smartlist_get(unrecognized, i));
+    connection_printf_to_buf(conn,
+                             "552 Unrecognized configuration key \"%s\"\r\n",
+                             (char*)smartlist_get(unrecognized, len-1));
+    goto done;
+  }
 
-  msg = smartlist_join_strings2(answers, "\0", 1, 1, &msg_len);
-  tor_assert(msg_len > 0); /* it will at least be terminated */
-  send_control0_message(conn, CONTROL0_CMD_INFOVALUE,
-                       msg_len, msg);
+  if (v0) {
+    msg = smartlist_join_strings2(answers, "\0", 1, 1, &msg_len);
+    tor_assert(msg_len > 0); /* it will at least be terminated */
+    send_control0_message(conn, CONTROL0_CMD_INFOVALUE,
+                          msg_len, msg);
+  } else if (smartlist_len(answers)) {
+    int i;
+    for (i = 0; i < smartlist_len(answers); i += 2) {
+      char *k = smartlist_get(answers, i);
+      char *v = smartlist_get(answers, i+1);
+      /*XXXX Not an adequate test! XXXX011 */
+      if (!strchr(v, '\n') && !strchr(v, '\r')) {
+        connection_printf_to_buf(conn, "250-%s=%s\r\n", k, v);
+      } else {
+        char *esc = NULL;
+        size_t len;
+        len = write_escaped_data(v, strlen(v), 1, &esc);
+        connection_printf_to_buf(conn, "250+%s=", k);
+        connection_write_to_buf(esc, len, conn);
+        tor_free(esc);
+      }
+    }
+    connection_write_str_to_buf("250 OK\r\n", conn);
+  }
 
  done:
   if (answers) SMARTLIST_FOREACH(answers, char *, cp, tor_free(cp));
   if (questions) SMARTLIST_FOREACH(questions, char *, cp, tor_free(cp));
   smartlist_free(answers);
   smartlist_free(questions);
+  smartlist_free(unrecognized);
   tor_free(msg);
 
   return 0;
@@ -1069,14 +1252,31 @@
 handle_control_postdescriptor(connection_t *conn, uint32_t len,
                               const char *body)
 {
-  /* XXXX V1 */
+  char *desc;
+  int v0 = STATE_IS_V0(conn->state);
+  if (v0)
+    desc = (char*)body;
+  else {
+    const char *cp = memchr(body, '\n', len);
+    tor_assert(cp);
+    read_escaped_data(cp, len-(cp-body), 1, &desc);
+  }
+
   const char *msg=NULL;
-  switch (router_load_single_router(body, &msg)) {
+  switch (router_load_single_router(desc, &msg)) {
   case -1:
-    send_control0_error(conn,ERR_SYNTAX,msg?msg: "Could not parse descriptor");
+    if (!msg) msg = "Could not parse descriptor";
+    if (v0)
+      send_control0_error(conn,ERR_SYNTAX,msg);
+    else
+      connection_printf_to_buf(conn, "554 %s\r\n", msg);
     break;
   case 0:
-    send_control_done2(conn,msg?msg: "Descriptor not added",0);
+    if (!msg) msg = "Descriptor not added";
+    if (v0)
+      send_control_done2(conn,msg,0);
+    else
+      connection_printf_to_buf(conn, "251 %s\r\n",msg);
     break;
   case 1:
     send_control_done(conn);
@@ -1091,25 +1291,48 @@
 handle_control_redirectstream(connection_t *conn, uint32_t len,
                               const char *body)
 {
-  /* XXXX V1 */
-  connection_t *ap_conn;
+  connection_t *ap_conn = NULL;
   uint32_t conn_id;
-  if (len < 6) {
-    send_control0_error(conn, ERR_SYNTAX, "redirectstream message too short");
-    return 0;
-  }
-  conn_id = ntohl(get_uint32(body));
+  char *new_addr = NULL;
+  if (STATE_IS_V0(conn->state)) {
+    if (len < 6) {
+      send_control0_error(conn, ERR_SYNTAX, "redirectstream message too short");
+      return 0;
+    }
+    conn_id = ntohl(get_uint32(body));
 
-  if (!(ap_conn = connection_get_by_global_id(conn_id))
-      || ap_conn->state != CONN_TYPE_AP
-      || !ap_conn->socks_request) {
-    send_control0_error(conn, ERR_NO_STREAM,
-                       "No AP connection found with given ID");
-    return 0;
+    if (!(ap_conn = connection_get_by_global_id(conn_id))
+        || ap_conn->state != CONN_TYPE_AP
+        || !ap_conn->socks_request) {
+      send_control0_error(conn, ERR_NO_STREAM,
+                          "No AP connection found with given ID");
+      return 0;
+    }
+    new_addr = tor_strdup(body+4);
+  } else {
+    smartlist_t *args;
+    args = smartlist_create();
+    smartlist_split_string(args, body, " ",
+                           SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
+    if (smartlist_len(args)<2)
+      connection_printf_to_buf(conn,"512 Missing argument to REDIRECTSTREAM\r\n");
+    else if (!(ap_conn = get_stream(smartlist_get(args, 0)))
+             || !ap_conn->socks_request) {
+      connection_printf_to_buf(conn, "552 Unknown stream \"%s\"\r\n",
+                               (char*)smartlist_get(args, 0));
+    } else {
+      new_addr = tor_strdup(smartlist_get(args, 1));
+    }
+
+    SMARTLIST_FOREACH(args, char *, cp, tor_free(cp));
+    smartlist_free(args);
+    if (!new_addr)
+      return 0;
   }
-  strlcpy(ap_conn->socks_request->address, body+4,
-          sizeof(ap_conn->socks_request->address));
 
+  strlcpy(ap_conn->socks_request->address, new_addr,
+          sizeof(ap_conn->socks_request->address));
+  tor_free(new_addr);
   send_control_done(conn);
   return 0;
 }
@@ -1119,26 +1342,52 @@
 handle_control_closestream(connection_t *conn, uint32_t len,
                            const char *body)
 {
-  /* XXXX V1 */
-  uint32_t conn_id;
-  connection_t *ap_conn;
-  uint8_t reason;
+  connection_t *ap_conn=NULL;
+  uint8_t reason=0;
 
-  if (len < 6) {
-    send_control0_error(conn, ERR_SYNTAX, "closestream message too short");
-    return 0;
-  }
+  if (STATE_IS_V0(conn->state)) {
+    uint32_t conn_id;
+    if (len < 6) {
+      send_control0_error(conn, ERR_SYNTAX, "closestream message too short");
+      return 0;
+    }
 
-  conn_id = ntohl(get_uint32(body));
-  reason = *(uint8_t*)(body+4);
+    conn_id = ntohl(get_uint32(body));
+    reason = *(uint8_t*)(body+4);
 
-  if (!(ap_conn = connection_get_by_global_id(conn_id))
-      || ap_conn->state != CONN_TYPE_AP
-      || !ap_conn->socks_request) {
-    send_control0_error(conn, ERR_NO_STREAM,
-                       "No AP connection found with given ID");
-    return 0;
+    if (!(ap_conn = connection_get_by_global_id(conn_id))
+        || ap_conn->state != CONN_TYPE_AP
+        || !ap_conn->socks_request) {
+      send_control0_error(conn, ERR_NO_STREAM,
+                          "No AP connection found with given ID");
+      return 0;
+    }
+  } else {
+    smartlist_t *args;
+    int ok;
+    args = smartlist_create();
+    smartlist_split_string(args, body, " ",
+                           SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
+    if (smartlist_len(args)<2)
+      connection_printf_to_buf(conn, "512 Missing argument to CLOSECIRCUIT\r\n");
+    else if (!(ap_conn = get_stream(smartlist_get(args, 0))))
+      connection_printf_to_buf(conn, "552 Unknown stream \"%s\"\r\n",
+                               (char*)smartlist_get(args, 0));
+    else {
+      reason = (uint8_t) tor_parse_ulong(smartlist_get(args,1), 10, 0, 255,
+                                         &ok, NULL);
+      if (!ok) {
+        connection_printf_to_buf(conn, "552 Unrecognized reason \"%s\"\r\n",
+                                 (char*)smartlist_get(args, 1));
+        ap_conn = NULL;
+      }
+    }
+    SMARTLIST_FOREACH(args, char *, cp, tor_free(cp));
+    smartlist_free(args);
+    if (!ap_conn)
+      return 0;
   }
+
   connection_mark_unattached_ap(ap_conn, reason);
   send_control_done(conn);
   return 0;
@@ -1149,22 +1398,47 @@
 handle_control_closecircuit(connection_t *conn, uint32_t len,
                             const char *body)
 {
-  /* XXXX V1 */
-  uint32_t circ_id;
-  circuit_t *circ;
-  int safe;
+  circuit_t *circ = NULL;
+  int safe = 0;
 
-  if (len < 5) {
-    send_control0_error(conn, ERR_SYNTAX, "closecircuit message too short");
-    return 0;
-  }
-  circ_id = ntohl(get_uint32(body));
-  safe = (*(uint8_t*)(body+4)) & 1;
+  if (STATE_IS_V0(conn->state)) {
+    uint32_t circ_id;
+    if (len < 5) {
+      send_control0_error(conn, ERR_SYNTAX, "closecircuit message too short");
+      return 0;
+    }
+    circ_id = ntohl(get_uint32(body));
+    safe = (*(uint8_t*)(body+4)) & 1;
 
-  if (!(circ = circuit_get_by_global_id(circ_id))) {
-    send_control0_error(conn, ERR_NO_CIRC,
-                       "No circuit found with given ID");
-    return 0;
+    if (!(circ = circuit_get_by_global_id(circ_id))) {
+      send_control0_error(conn, ERR_NO_CIRC,
+                          "No circuit found with given ID");
+      return 0;
+    }
+  } else {
+    smartlist_t *args;
+    args = smartlist_create();
+    smartlist_split_string(args, body, " ",
+                           SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
+    if (smartlist_len(args)<1)
+      connection_printf_to_buf(conn, "512 Missing argument to CLOSECIRCUIT\r\n");
+    else if (!(circ=get_circ(smartlist_get(args, 0))))
+      connection_printf_to_buf(conn, "552 Unknown circuit \"%s\"\r\n",
+                               (char*)smartlist_get(args, 0));
+    else {
+      int i;
+      for (i=1; i < smartlist_len(args); ++i) {
+        if (!strcasecmp(smartlist_get(args, i), "IfUnused"))
+          safe = 1;
+        else
+          log_fn(LOG_INFO, "Skipping unknown option %s",
+                 (char*)smartlist_get(args,i));
+      }
+    }
+    SMARTLIST_FOREACH(args, char *, cp, tor_free(cp));
+    smartlist_free(args);
+    if (!circ)
+      return 0;
   }
 
   if (!safe || !circ->p_streams) {
@@ -1693,18 +1967,17 @@
 void
 control_event_logmsg(int severity, const char *msg)
 {
-  /* XXXX V1 */
   static int sending_logmsg=0;
   int oldlog, event;
 
   if (sending_logmsg)
     return;
 
-  oldlog = EVENT_IS_INTERESTING(EVENT_LOG_OBSOLETE) &&
+  oldlog = EVENT_IS_INTERESTING0(EVENT_LOG_OBSOLETE) &&
     (severity == LOG_NOTICE || severity == LOG_WARN || severity == LOG_ERR);
   event = log_severity_to_event(severity);
 
-  if (event<0 || !EVENT_IS_INTERESTING(event))
+  if (event<0 || !EVENT_IS_INTERESTING0(event))
     event = 0;
 
   if (oldlog || event) {
@@ -1716,6 +1989,28 @@
       send_control0_event(EVENT_LOG_OBSOLETE, (uint32_t)(len+1), msg);
     sending_logmsg = 0;
   }
+
+  event = log_severity_to_event(severity);
+  if (event >= 0 && EVENT_IS_INTERESTING1(event)) {
+    char *b = NULL;
+    const char *s;
+    if (strchr(msg, '\n')) {
+      char *cp;
+      b = tor_strdup(msg);
+      for (cp = b; *cp; ++cp)
+        if (*cp == '\r' || *cp == '\n')
+          *cp = ' ';
+    }
+    switch(severity) {
+      case LOG_INFO: s = "INFO"; break;
+      case LOG_NOTICE: s = "NOTICE"; break;
+      case LOG_WARN: s = "WARN"; break;
+      case LOG_ERR: s = "ERR"; break;
+      default: s = "UnknownLogSeverity"; break;
+    }
+    send_control1_event(event, "650 %s %s\r\n", s, b?b:msg);
+    tor_free(b);
+  }
 }
 
 /** Called whenever we receive new router descriptors: tell any



More information about the tor-commits mailing list