|  | @@ -48,7 +48,8 @@ const char control_c_id[] = "$Id$";
 | 
	
		
			
				|  |  |  #define CONTROL_CMD_POSTDESCRIPTOR 0x000F
 | 
	
		
			
				|  |  |  #define CONTROL_CMD_FRAGMENTHEADER 0x0010
 | 
	
		
			
				|  |  |  #define CONTROL_CMD_FRAGMENT       0x0011
 | 
	
		
			
				|  |  | -#define _CONTROL_CMD_MAX_RECOGNIZED 0x0011
 | 
	
		
			
				|  |  | +#define CONTROL_CMD_REDIRECTSTREAM  0x0012
 | 
	
		
			
				|  |  | +#define _CONTROL_CMD_MAX_RECOGNIZED 0x0012
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  /* Recognized error codes. */
 | 
	
		
			
				|  |  |  #define ERR_UNSPECIFIED             0x0000
 | 
	
	
		
			
				|  | @@ -63,6 +64,7 @@ const char control_c_id[] = "$Id$";
 | 
	
		
			
				|  |  |  #define ERR_RESOURCE_EXHAUSETED     0x0009
 | 
	
		
			
				|  |  |  #define ERR_NO_STREAM               0x000A
 | 
	
		
			
				|  |  |  #define ERR_NO_CIRC                 0x000B
 | 
	
		
			
				|  |  | +#define ERR_NO_ROUTER               0x000C
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  /* Recognized asynchronous event types. */
 | 
	
		
			
				|  |  |  #define _EVENT_MIN            0x0001
 | 
	
	
		
			
				|  | @@ -148,6 +150,8 @@ static int handle_control_attachstream(connection_t *conn, uint32_t len,
 | 
	
		
			
				|  |  |                                          const char *body);
 | 
	
		
			
				|  |  |  static int handle_control_postdescriptor(connection_t *conn, uint32_t len,
 | 
	
		
			
				|  |  |                                           const char *body);
 | 
	
		
			
				|  |  | +static int handle_control_redirectstream(connection_t *conn, uint32_t len,
 | 
	
		
			
				|  |  | +                                         const char *body);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  /** Given a possibly invalid message type code <b>cmd</b>, return a
 | 
	
		
			
				|  |  |   * human-readable string equivalent. */
 | 
	
	
		
			
				|  | @@ -631,7 +635,52 @@ static int
 | 
	
		
			
				|  |  |  handle_control_extendcircuit(connection_t *conn, uint32_t len,
 | 
	
		
			
				|  |  |                               const char *body)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  | -  send_control_error(conn,ERR_UNRECOGNIZED_TYPE,"not yet implemented");
 | 
	
		
			
				|  |  | +  smartlist_t *router_nicknames, *routers;
 | 
	
		
			
				|  |  | +  uint32_t circ_id;
 | 
	
		
			
				|  |  | +  circuit_t *circ;
 | 
	
		
			
				|  |  | +  if (len<5) {
 | 
	
		
			
				|  |  | +    send_control_error(conn, ERR_SYNTAX, "extendcircuit message too short");
 | 
	
		
			
				|  |  | +    return 0;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  circ_id = ntohl(get_uint32(body));
 | 
	
		
			
				|  |  | +  if (!(circ = circuit_get_by_global_id(circ_id))) {
 | 
	
		
			
				|  |  | +    send_control_error(conn, ERR_NO_STREAM,
 | 
	
		
			
				|  |  | +                       "No connection found with given ID");
 | 
	
		
			
				|  |  | +    return 0;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  router_nicknames = smartlist_create();
 | 
	
		
			
				|  |  | +  routers = smartlist_create();
 | 
	
		
			
				|  |  | +  smartlist_split_string(router_nicknames, body, ",", 0, 0);
 | 
	
		
			
				|  |  | +  SMARTLIST_FOREACH(router_nicknames, const char *, n,
 | 
	
		
			
				|  |  | +    {
 | 
	
		
			
				|  |  | +      routerinfo_t *r = router_get_by_nickname(n);
 | 
	
		
			
				|  |  | +      if (!r) {
 | 
	
		
			
				|  |  | +        send_control_error(conn, ERR_NO_ROUTER, "Unrecognized router name");
 | 
	
		
			
				|  |  | +        goto done;
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +      smartlist_add(routers, r);
 | 
	
		
			
				|  |  | +    });
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#if 1
 | 
	
		
			
				|  |  | +  /*XXXX RD*/
 | 
	
		
			
				|  |  | +  send_control_error(conn, ERR_INTERNAL, "EXTENDCIRCUIT not implemented.");
 | 
	
		
			
				|  |  | +#else
 | 
	
		
			
				|  |  | +  SMARTLIST_FOREACH(routers, routerinfo_t *, r,
 | 
	
		
			
				|  |  | +    {
 | 
	
		
			
				|  |  | +      /*XXXX RD*/
 | 
	
		
			
				|  |  | +      if (circuit_extend_path(circ, r)<0) {
 | 
	
		
			
				|  |  | +        send_control_error(conn, ERR_INTERNAL, "Unable to extend path.");
 | 
	
		
			
				|  |  | +        goto done;
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +    });
 | 
	
		
			
				|  |  | +#endif
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  send_control_done(conn);
 | 
	
		
			
				|  |  | + done:
 | 
	
		
			
				|  |  | +  SMARTLIST_FOREACH(router_nicknames, char *, n, tor_free(n));
 | 
	
		
			
				|  |  | +  smartlist_free(router_nicknames);
 | 
	
		
			
				|  |  | +  smartlist_free(routers);
 | 
	
		
			
				|  |  |    return 0;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  static int handle_control_attachstream(connection_t *conn, uint32_t len,
 | 
	
	
		
			
				|  | @@ -677,6 +726,7 @@ static int handle_control_attachstream(connection_t *conn, uint32_t len,
 | 
	
		
			
				|  |  |      send_control_error(conn, ERR_INTERNAL, "Unable to attach stream.");
 | 
	
		
			
				|  |  |      return 0;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  | +  send_control_done(conn);
 | 
	
		
			
				|  |  |    return 0;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  static int
 | 
	
	
		
			
				|  | @@ -693,6 +743,32 @@ handle_control_postdescriptor(connection_t *conn, uint32_t len,
 | 
	
		
			
				|  |  |    send_control_done(conn);
 | 
	
		
			
				|  |  |    return 0;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  | +static int
 | 
	
		
			
				|  |  | +handle_control_redirectstream(connection_t *conn, uint32_t len,
 | 
	
		
			
				|  |  | +                              const char *body)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +  connection_t *ap_conn;
 | 
	
		
			
				|  |  | +  uint32_t conn_id;
 | 
	
		
			
				|  |  | +  if (len < 6) {
 | 
	
		
			
				|  |  | +    send_control_error(conn, ERR_SYNTAX, "attachstream 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_control_error(conn, ERR_NO_STREAM,
 | 
	
		
			
				|  |  | +                       "No AP connection found with given ID");
 | 
	
		
			
				|  |  | +    return 0;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  strlcpy(ap_conn->socks_request->address, body+1,
 | 
	
		
			
				|  |  | +          sizeof(ap_conn->socks_request->address));
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  send_control_done(conn);
 | 
	
		
			
				|  |  | +  return 0;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  /** Called when <b>conn</b> has no more bytes left on its outbuf. */
 | 
	
		
			
				|  |  |  int
 | 
	
	
		
			
				|  | @@ -798,6 +874,10 @@ connection_control_process_inbuf(connection_t *conn) {
 | 
	
		
			
				|  |  |        if (handle_control_postdescriptor(conn, body_len, body))
 | 
	
		
			
				|  |  |          return -1;
 | 
	
		
			
				|  |  |        break;
 | 
	
		
			
				|  |  | +    case CONTROL_CMD_REDIRECTSTREAM:
 | 
	
		
			
				|  |  | +      if (handle_control_redirectstream(conn, body_len, body))
 | 
	
		
			
				|  |  | +        return -1;
 | 
	
		
			
				|  |  | +      break;
 | 
	
		
			
				|  |  |      case CONTROL_CMD_ERROR:
 | 
	
		
			
				|  |  |      case CONTROL_CMD_DONE:
 | 
	
		
			
				|  |  |      case CONTROL_CMD_CONFVALUE:
 |