[or-cvs] Implement all of control interface except authentication, s...

Nick Mathewson nickm at seul.org
Wed Nov 3 18:33:10 UTC 2004


Update of /home/or/cvsroot/src/or
In directory moria.mit.edu:/tmp/cvs-serv12980/src/or

Modified Files:
	circuitbuild.c circuitlist.c circuituse.c connection.c 
	connection_edge.c connection_or.c control.c dirserv.c main.c 
	or.h router.c routerlist.c test.c 
Log Message:
- Implement all of control interface except authentication, setconfig,
  and actually making the sockets.
- Make sure that identity-based nicknames start with $.
- Use new string_join interface.


Index: circuitbuild.c
===================================================================
RCS file: /home/or/cvsroot/src/or/circuitbuild.c,v
retrieving revision 1.47
retrieving revision 1.48
diff -u -d -r1.47 -r1.48
--- circuitbuild.c	3 Nov 2004 10:08:44 -0000	1.47
+++ circuitbuild.c	3 Nov 2004 18:33:06 -0000	1.48
@@ -63,6 +63,40 @@
   return test_circ_id;
 }
 
+/** Allocate and return a comma-separated list of the currently built
+ * elements of circuit_t.
+ */
+char *circuit_list_path(circuit_t *circ)
+{
+  struct crypt_path_t *hop;
+  routerinfo_t *r;
+  smartlist_t *elements;
+  char *s;
+  tor_assert(CIRCUIT_IS_ORIGIN(circ));
+  tor_assert(circ->cpath);
+
+  elements = smartlist_create();
+
+  for (hop = circ->cpath; hop; hop = hop->next) {
+    if (hop->state != CPATH_STATE_OPEN)
+      break;
+    if ((r = router_get_by_digest(hop->identity_digest))) {
+      smartlist_add(elements, tor_strdup(r->nickname));
+    } else if (circ->purpose == CIRCUIT_PURPOSE_C_REND_JOINED) {
+      smartlist_add(elements, tor_strdup("<rendezvous splice>"));
+    } else {
+      s = tor_malloc(HEX_DIGEST_LEN+2);
+      s[0]='$';
+      base16_encode(s+1,HEX_DIGEST_LEN+1,hop->identity_digest,DIGEST_LEN);
+      smartlist_add(elements, s);
+    }
+  }
+
+  s = smartlist_join_strings(elements, ",", 0, NULL);
+  SMARTLIST_FOREACH(elements, char*, cp, tor_free(cp));
+  return s;
+}
+
 /** Log, at severity <b>severity</b>, the nicknames of each router in
  * circ's cpath. Also log the length of the cpath, and the intended
  * exit point.
@@ -220,6 +254,8 @@
     return NULL;
   }
 
+  control_event_circuit_status(circ, CIRC_EVENT_LAUNCHED);
+
   /* now see if we're already connected to the first OR in 'route' */
 
   tor_assert(firsthop);
@@ -604,6 +640,8 @@
   hop->state = CPATH_STATE_OPEN;
   log_fn(LOG_INFO,"finished");
   circuit_log_path(LOG_INFO,circ);
+  control_event_circuit_status(circ, CIRC_EVENT_EXTENDED);
+
   return 0;
 }
 

Index: circuitlist.c
===================================================================
RCS file: /home/or/cvsroot/src/or/circuitlist.c,v
retrieving revision 1.14
retrieving revision 1.15
diff -u -d -r1.14 -r1.15
--- circuitlist.c	27 Oct 2004 21:14:10 -0000	1.14
+++ circuitlist.c	3 Nov 2004 18:33:06 -0000	1.15
@@ -74,6 +74,7 @@
  */
 circuit_t *circuit_new(uint16_t p_circ_id, connection_t *p_conn) {
   circuit_t *circ;
+  static uint32_t n_circuits_allocated = 0;
 
   circ = tor_malloc_zero(sizeof(circuit_t));
   circ->magic = CIRCUIT_MAGIC;
@@ -93,6 +94,7 @@
   circ->deliver_window = CIRCWINDOW_START;
 
   circ->next_stream_id = crypto_pseudo_rand_int(1<<16);
+  circ->global_identifier = n_circuits_allocated++;
 
   circuit_add(circ);
 
@@ -353,10 +355,15 @@
    * links worked and which didn't.
    */
   if (circ->state != CIRCUIT_STATE_OPEN) {
-    if(CIRCUIT_IS_ORIGIN(circ))
+    if(CIRCUIT_IS_ORIGIN(circ)) {
       circuit_build_failed(circ); /* take actions if necessary */
+    }
     circuit_rep_hist_note_result(circ);
   }
+  if (CIRCUIT_IS_ORIGIN(circ)) {
+    control_event_circuit_status(circ,
+     (circ->state == CIRCUIT_STATE_OPEN)?CIRC_EVENT_CLOSED:CIRC_EVENT_FAILED);
+  }
   if (circ->purpose == CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT) {
     tor_assert(circ->state == CIRCUIT_STATE_OPEN);
     /* treat this like getting a nack from it */

Index: circuituse.c
===================================================================
RCS file: /home/or/cvsroot/src/or/circuituse.c,v
retrieving revision 1.19
retrieving revision 1.20
diff -u -d -r1.19 -r1.20
--- circuituse.c	27 Oct 2004 06:48:16 -0000	1.19
+++ circuituse.c	3 Nov 2004 18:33:06 -0000	1.20
@@ -489,6 +489,8 @@
  */
 void circuit_has_opened(circuit_t *circ) {
 
+  control_event_circuit_status(circ, CIRC_EVENT_BUILT);
+
   switch(circ->purpose) {
     case CIRCUIT_PURPOSE_C_ESTABLISH_REND:
       rend_client_rendcirc_has_opened(circ);

Index: connection.c
===================================================================
RCS file: /home/or/cvsroot/src/or/connection.c,v
retrieving revision 1.278
retrieving revision 1.279
diff -u -d -r1.278 -r1.279
--- connection.c	3 Nov 2004 16:38:04 -0000	1.278
+++ connection.c	3 Nov 2004 18:33:06 -0000	1.279
@@ -198,12 +198,15 @@
     case CONN_TYPE_OR:
       /* Remember why we're closing this connection. */
       if (conn->state != OR_CONN_STATE_OPEN) {
-        if(connection_or_nonopen_was_started_here(conn))
+        if(connection_or_nonopen_was_started_here(conn)) {
           rep_hist_note_connect_failed(conn->identity_digest, time(NULL));
+          control_event_or_conn_status(conn, OR_CONN_EVENT_FAILED);
+        }
       } else if (0) { // XXX reason == CLOSE_REASON_UNUSED_OR_CONN) {
         rep_hist_note_disconnect(conn->identity_digest, time(NULL));
       } else if(conn->identity_digest) {
         rep_hist_note_connection_died(conn->identity_digest, time(NULL));
+        control_event_or_conn_status(conn, OR_CONN_EVENT_CLOSED);
       }
       break;
     case CONN_TYPE_AP:
@@ -212,6 +215,8 @@
         connection_ap_handshake_socks_reply(conn, NULL, 0, 0);
         conn->socks_request->has_finished = 1;
         conn->hold_open_until_flushed = 1;
+      } else {
+        control_event_stream_status(conn, STREAM_EVENT_CLOSED);
       }
       break;
     case CONN_TYPE_EXIT:

Index: connection_edge.c
===================================================================
RCS file: /home/or/cvsroot/src/or/connection_edge.c,v
retrieving revision 1.222
retrieving revision 1.223
diff -u -d -r1.222 -r1.223
--- connection_edge.c	31 Oct 2004 20:28:41 -0000	1.222
+++ connection_edge.c	3 Nov 2004 18:33:07 -0000	1.223
@@ -521,6 +521,7 @@
   ap_conn->deliver_window = STREAMWINDOW_START;
   ap_conn->state = AP_CONN_STATE_CONNECT_WAIT;
   log_fn(LOG_INFO,"Address/port sent, ap socket %d, n_circ_id %d",ap_conn->s,circ->n_circ_id);
+  control_event_stream_status(ap_conn, STREAM_EVENT_SENT_CONNECT);
   return 0;
 }
 
@@ -561,6 +562,7 @@
 
   ap_conn->state = AP_CONN_STATE_RESOLVE_WAIT;
   log_fn(LOG_INFO,"Address sent for resolve, ap socket %d, n_circ_id %d",ap_conn->s,circ->n_circ_id);
+  control_event_stream_status(ap_conn, STREAM_EVENT_SENT_RESOLVE);
   return 0;
 }
 
@@ -689,6 +691,9 @@
                                          size_t replylen, int success) {
   char buf[256];
 
+  control_event_stream_status(conn,
+                       success ? STREAM_EVENT_SUCCEEDED : STREAM_EVENT_FAILED);
+
   if(replylen) { /* we already have a reply in mind */
     connection_write_to_buf(reply, replylen, conn);
     return;

Index: connection_or.c
===================================================================
RCS file: /home/or/cvsroot/src/or/connection_or.c,v
retrieving revision 1.131
retrieving revision 1.132
diff -u -d -r1.131 -r1.132
--- connection_or.c	17 Oct 2004 21:51:20 -0000	1.131
+++ connection_or.c	3 Nov 2004 18:33:07 -0000	1.132
@@ -140,8 +140,9 @@
   if (n) {
     conn->nickname = tor_strdup(n);
   } else {
-    conn->nickname = tor_malloc(HEX_DIGEST_LEN+1);
-    base16_encode(conn->nickname, HEX_DIGEST_LEN+1,
+    conn->nickname = tor_malloc(HEX_DIGEST_LEN+2);
+    conn->nickname[0] = '$';
+    base16_encode(conn->nickname+1, HEX_DIGEST_LEN+1,
                   conn->identity_digest, DIGEST_LEN);
   }
   tor_free(conn->address);
@@ -223,10 +224,12 @@
   /* set up conn so it's got all the data we need to remember */
   connection_or_init_conn_from_address(conn, addr, port, id_digest);
   conn->state = OR_CONN_STATE_CONNECTING;
+  control_event_or_conn_status(conn, OR_CONN_EVENT_LAUNCHED);
 
   switch(connection_connect(conn, conn->address, addr, port)) {
     case -1:
       router_mark_as_down(conn->identity_digest);
+      control_event_or_conn_status(conn, OR_CONN_EVENT_FAILED);
       connection_free(conn);
       return NULL;
     case 0:
@@ -376,6 +379,7 @@
       log_fn(options.DirPort ? LOG_WARN : LOG_INFO,
              "Other side (%s:%d) is '%s', but we tried to connect to '%s'",
              conn->address, conn->port, nickname, conn->nickname);
+      control_event_or_conn_status(conn, OR_CONN_EVENT_FAILED);
       return -1;
     }
   } else {
@@ -393,6 +397,7 @@
   circuit_n_conn_done(conn, 1); /* send the pending creates, if any. */
   /* Note the success */
   rep_hist_note_connect_succeeded(conn->identity_digest, time(NULL));
+  control_event_or_conn_status(conn, OR_CONN_EVENT_CONNECTED);
   return 0;
 }
 

Index: control.c
===================================================================
RCS file: /home/or/cvsroot/src/or/control.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -d -r1.2 -r1.3
--- control.c	3 Nov 2004 10:08:44 -0000	1.2
+++ control.c	3 Nov 2004 18:33:07 -0000	1.3
@@ -43,6 +43,8 @@
   "authenticate",
 };
 
+extern or_options_t options;
+
 static uint32_t global_event_mask = 0;
 
 static void update_global_event_mask(void);
@@ -131,17 +133,57 @@
   }
 }
 
-static int 
+static int
 handle_control_setconf(connection_t *conn, uint16_t len,
                                   const char *body)
 {
   /* XXXX009 NM */
   return 0;
 }
-static int handle_control_getconf(connection_t *conn, uint16_t len,
+
+static int handle_control_getconf(connection_t *conn, uint16_t body_len,
                                   const char *body)
 {
-  /* XXXX009 NM */
+  smartlist_t *answer_elements = NULL;
+  char *msg = NULL;
+  size_t msg_len;
+
+  if (body[body_len-1] != '\0') {
+    send_control_error(conn, ERR_UNSPECIFIED,
+                       "getconf message body not nul-terminated.");
+    return 0;
+  }
+  /* Now we can be sure that body will end in a nul-terminated string. */
+
+  answer_elements = smartlist_create();
+  while (body_len) {
+    size_t question_len = strlen(body);
+    struct config_line_t *answer = config_get_assigned_option(&options,body);
+    if (!answer) {
+      send_control_error(conn, ERR_UNRECOGNIZED_CONFIG_KEY, body);
+      goto done;
+    } else {
+      while (answer) {
+        struct config_line_t *next;
+        smartlist_add(answer_elements, answer->key);
+        smartlist_add(answer_elements, answer->value);
+        next = answer->next;
+        tor_free(answer);
+        answer = next;
+      }
+    }
+    body += question_len+1;
+    body_len -= question_len+1;
+  }
+
+  msg = smartlist_join_strings2(answer_elements, "\0", 1, 0, &msg_len);
+  send_control_message(conn, CONTROL_CMD_CONFVALUE, msg_len, msg);
+
+ done:
+  SMARTLIST_FOREACH(answer_elements, char *, cp, tor_free(cp));
+  smartlist_free(answer_elements);
+  tor_free(msg);
+
   return 0;
 }
 static int handle_control_setevents(connection_t *conn, uint16_t len,
@@ -263,37 +305,63 @@
   goto again; /* There might be more data. */
 }
 
-int control_event_circuit_status(circuit_t *circ)
+int control_event_circuit_status(circuit_t *circ, circuit_status_event_t tp)
 {
+  char *path, *msg;
+  size_t path_len;
   if (!EVENT_IS_INTERESTING(EVENT_CIRCUIT_STATUS))
     return 0;
+  tor_assert(circ);
+  tor_assert(CIRCUIT_IS_ORIGIN(circ));
 
-  /* XXXXX009 NM */
+  path = circuit_list_path(circ);
+  path_len = strlen(path);
+  msg = tor_malloc(1+4+path_len+1); /* event, circid, path, NUL. */
+  msg[0] = (uint8_t) tp;
+  set_uint32(msg+1, htonl(circ->global_identifier));
+  strlcpy(msg+5,path,path_len+1);
 
+  send_control_event(EVENT_STREAM_STATUS, (uint16_t)(path_len+6), msg);
+  tor_free(path);
+  tor_free(msg);
   return 0;
 }
 
-int control_event_stream_status(connection_t *conn)
+int control_event_stream_status(connection_t *conn, stream_status_event_t tp)
 {
+  char *msg;
+  size_t len;
   tor_assert(conn->type == CONN_TYPE_AP);
+  tor_assert(conn->socks_request);
 
   if (!EVENT_IS_INTERESTING(EVENT_STREAM_STATUS))
     return 0;
 
-  /* XXXXX009 NM */
+  len = strlen(conn->socks_request->address);
+  msg = tor_malloc(5+len+1);
+  msg[0] = (uint8_t) tp;
+  set_uint32(msg+1, htonl(conn->s)); /* ???? Is this a security problem? */
+  strlcpy(msg+5, conn->socks_request->address, len+1);
 
+  send_control_event(EVENT_STREAM_STATUS, (uint16_t)(5+len+1), msg);
+  tor_free(msg);
   return 0;
 }
 
-int control_event_or_conn_status(connection_t *conn)
+int control_event_or_conn_status(connection_t *conn,or_conn_status_event_t tp)
 {
+  char buf[HEX_DIGEST_LEN+3]; /* status, dollar, identity, NUL */
+  size_t len;
+
   tor_assert(conn->type == CONN_TYPE_OR);
 
   if (!EVENT_IS_INTERESTING(EVENT_OR_CONN_STATUS))
     return 0;
 
-  /* XXXXX009 NM */
-
+  buf[0] = (uint8_t)tp;
+  strlcpy(buf+1,conn->nickname,sizeof(buf)-1);
+  len = strlen(buf+1);
+  send_control_event(EVENT_OR_CONN_STATUS, (uint16_t)(len+1), buf);
   return 0;
 }
 
@@ -311,19 +379,18 @@
   return 0;
 }
 
-int control_event_warning(const char *msg)
+void control_event_logmsg(int severity, const char *msg)
 {
   size_t len;
+  if (severity > LOG_WARN) /* Less important than warning? ignore for now. */
+    return;
   if (!EVENT_IS_INTERESTING(EVENT_WARNING))
-    return 0;
+    return;
 
   len = strlen(msg);
-  send_control_event(EVENT_WARNING, len+1, msg);
-
-  return 0;
+  send_control_event(EVENT_WARNING, (uint16_t)(len+1), msg);
 }
 
-
 /*
   Local Variabls:
   mode:c

Index: dirserv.c
===================================================================
RCS file: /home/or/cvsroot/src/or/dirserv.c,v
retrieving revision 1.109
retrieving revision 1.110
diff -u -d -r1.109 -r1.110
--- dirserv.c	2 Nov 2004 03:02:17 -0000	1.109
+++ dirserv.c	3 Nov 2004 18:33:07 -0000	1.110
@@ -523,9 +523,9 @@
   });
 
   if (running_routers_out)
-    *running_routers_out = smartlist_join_strings(rr_entries, " ", 0);
+    *running_routers_out = smartlist_join_strings(rr_entries, " ", 0,NULL);
   if (router_status_out)
-    *router_status_out = smartlist_join_strings(rs_entries, " ", 0);
+    *router_status_out = smartlist_join_strings(rs_entries, " ", 0,NULL);
 
   SMARTLIST_FOREACH(rr_entries, char *, cp, tor_free(cp));
   SMARTLIST_FOREACH(rs_entries, char *, cp, tor_free(cp));
@@ -611,7 +611,7 @@
       smartlist_split_string(versions, ln->value, ",", 
                              SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
     }
-    recommended_versions = smartlist_join_strings(versions,",",0);
+    recommended_versions = smartlist_join_strings(versions,",",0,NULL);
     SMARTLIST_FOREACH(versions,char *,s,tor_free(s));
     smartlist_free(versions);
   }

Index: main.c
===================================================================
RCS file: /home/or/cvsroot/src/or/main.c,v
retrieving revision 1.350
retrieving revision 1.351
diff -u -d -r1.350 -r1.351
--- main.c	3 Nov 2004 16:38:04 -0000	1.350
+++ main.c	3 Nov 2004 18:33:07 -0000	1.351
@@ -971,6 +971,7 @@
   /* Close the temporary log we used while starting up, if it isn't already
    * gone. */
   close_temp_logs();
+  add_callback_log(LOG_WARN, LOG_ERR, control_event_logmsg);
 
   /* Start backgrounding the process, if requested. */
   if (options.RunAsDaemon) {

Index: or.h
===================================================================
RCS file: /home/or/cvsroot/src/or/or.h,v
retrieving revision 1.455
retrieving revision 1.456
diff -u -d -r1.455 -r1.456
--- or.h	3 Nov 2004 01:32:26 -0000	1.455
+++ or.h	3 Nov 2004 18:33:07 -0000	1.456
@@ -822,6 +822,10 @@
    * is not marked for close. */
   struct circuit_t *rend_splice;
 
+  /** Quasi-global identifier for this circuit; used for control.c */
+  /* XXXX009 NM This can get re-used after 2**32 circuits. */
+  uint32_t global_identifier;
+
   struct circuit_t *next; /**< Next circuit in linked list. */
 };
 
@@ -1000,6 +1004,7 @@
 
 /********************************* circuitbuild.c **********************/
 
+char *circuit_list_path(circuit_t *circ);
 void circuit_log_path(int severity, circuit_t *circ);
 void circuit_rep_hist_note_result(circuit_t *circ);
 void circuit_dump_by_conn(connection_t *conn, int severity);
@@ -1084,6 +1089,8 @@
                               struct exit_policy_t **dest);
 void exit_policy_free(struct exit_policy_t *p);
 const char *get_data_directory(or_options_t *options);
+struct config_line_t *config_get_assigned_option(or_options_t *options,
+                                                 const char *key);
 
 /********************************* connection.c ***************************/
 
@@ -1202,14 +1209,37 @@
 
 /********************************* control.c ***************************/
 
+typedef enum circuit_status_event_t {
+  CIRC_EVENT_LAUNCHED = 0,
+  CIRC_EVENT_BUILT    = 1,
+  CIRC_EVENT_EXTENDED = 2,
+  CIRC_EVENT_FAILED   = 3,
+  CIRC_EVENT_CLOSED   = 4,
+} circuit_status_event_t;
+
+typedef enum stream_status_event_t {
+  STREAM_EVENT_SENT_CONNECT = 0,
+  STREAM_EVENT_SENT_RESOLVE = 1,
+  STREAM_EVENT_SUCCEEDED    = 2,
+  STREAM_EVENT_FAILED       = 3,
+  STREAM_EVENT_CLOSED       = 4
+} stream_status_event_t;
+
+typedef enum or_conn_status_event_t {
+  OR_CONN_EVENT_LAUNCHED     = 0,
+  OR_CONN_EVENT_CONNECTED    = 1,
+  OR_CONN_EVENT_FAILED       = 2,
+  OR_CONN_EVENT_CLOSED       = 3,
+} or_conn_status_event_t;
+
 int connection_control_finished_flushing(connection_t *conn);
 int connection_control_process_inbuf(connection_t *conn);
 
-int control_event_circuit_status(circuit_t *circ);
-int control_event_stream_status(connection_t *conn);
-int control_event_or_conn_status(connection_t *conn);
+int control_event_circuit_status(circuit_t *circ, circuit_status_event_t e);
+int control_event_stream_status(connection_t *conn, stream_status_event_t e);
+int control_event_or_conn_status(connection_t *conn, or_conn_status_event_t e);
 int control_event_bandwidth_used(uint32_t n_read, uint32_t n_written);
-int control_event_warning(const char *msg);
+void control_event_logmsg(int severity, const char *msg);
 
 /********************************* cpuworker.c *****************************/
 
@@ -1543,7 +1573,7 @@
 int router_parse_list_from_string(const char **s,
                                   routerlist_t **dest,
                                   smartlist_t *good_nickname_list,
-                                  int rr_format,                        
+                                  int rr_format,
                                   time_t published);
 int router_parse_routerlist_from_directory(const char *s,
                                            routerlist_t **dest,

Index: router.c
===================================================================
RCS file: /home/or/cvsroot/src/or/router.c,v
retrieving revision 1.107
retrieving revision 1.108
diff -u -d -r1.107 -r1.108
--- router.c	2 Nov 2004 02:28:51 -0000	1.107
+++ router.c	3 Nov 2004 18:33:07 -0000	1.108
@@ -640,8 +640,9 @@
   bandwidth_usage = rep_hist_get_bandwidth_lines();
 
   if (router->declared_family && smartlist_len(router->declared_family)) {
-    char *s = smartlist_join_strings(router->declared_family, " ", 0);
-    size_t n = strlen(s) + strlen("opt family ") + 2; /* 1 for \n, 1 for \0. */
+    size_t n;
+    char *s = smartlist_join_strings(router->declared_family, " ", 0, &n);
+    n += strlen("opt family ") + 2; /* 1 for \n, 1 for \0. */
     family_line = tor_malloc(n);
     tor_snprintf(family_line, n, "opt family %s\n", s);
     tor_free(s);

Index: routerlist.c
===================================================================
RCS file: /home/or/cvsroot/src/or/routerlist.c,v
retrieving revision 1.173
retrieving revision 1.174
diff -u -d -r1.173 -r1.174
--- routerlist.c	3 Nov 2004 10:08:44 -0000	1.173
+++ routerlist.c	3 Nov 2004 18:33:07 -0000	1.174
@@ -1167,7 +1167,7 @@
         r->status_set_at = time(NULL);
       }
   });
- 
+
   return 0;
 }
 

Index: test.c
===================================================================
RCS file: /home/or/cvsroot/src/or/test.c,v
retrieving revision 1.138
retrieving revision 1.139
diff -u -d -r1.138 -r1.139
--- test.c	2 Nov 2004 03:02:17 -0000	1.138
+++ test.c	3 Nov 2004 18:33:07 -0000	1.139
@@ -566,19 +566,19 @@
   test_streq("a", smartlist_get(sl, 1));
   test_streq("bc", smartlist_get(sl, 2));
   test_streq("", smartlist_get(sl, 3));
-  cp = smartlist_join_strings(sl, "", 0);
+  cp = smartlist_join_strings(sl, "", 0, NULL);
   test_streq(cp, "abcabc");
   tor_free(cp);
-  cp = smartlist_join_strings(sl, "!", 0);
+  cp = smartlist_join_strings(sl, "!", 0, NULL);
   test_streq(cp, "abc!a!bc!");
   tor_free(cp);
-  cp = smartlist_join_strings(sl, "XY", 0);
+  cp = smartlist_join_strings(sl, "XY", 0, NULL);
   test_streq(cp, "abcXYaXYbcXY");
   tor_free(cp);
-  cp = smartlist_join_strings(sl, "XY", 1);
+  cp = smartlist_join_strings(sl, "XY", 1, NULL);
   test_streq(cp, "abcXYaXYbcXYXY");
   tor_free(cp);
-  cp = smartlist_join_strings(sl, "", 1);
+  cp = smartlist_join_strings(sl, "", 1, NULL);
   test_streq(cp, "abcabc");
   tor_free(cp);
 



More information about the tor-commits mailing list