[or-cvs] Start implementing control interface.
Nick Mathewson
nickm at seul.org
Wed Nov 3 01:32:28 UTC 2004
Update of /home/or/cvsroot/src/or
In directory moria.mit.edu:/tmp/cvs-serv26883/src/or
Modified Files:
Makefile.am buffers.c connection.c or.h
Added Files:
control.c
Log Message:
Start implementing control interface.
Index: Makefile.am
===================================================================
RCS file: /home/or/cvsroot/src/or/Makefile.am,v
retrieving revision 1.37
retrieving revision 1.38
diff -u -d -r1.37 -r1.38
--- Makefile.am 31 Oct 2004 20:28:41 -0000 1.37
+++ Makefile.am 3 Nov 2004 01:32:26 -0000 1.38
@@ -6,7 +6,7 @@
tor_SOURCES = buffers.c circuitbuild.c circuitlist.c \
circuituse.c command.c config.c \
- connection.c connection_edge.c connection_or.c \
+ connection.c connection_edge.c connection_or.c control.c \
cpuworker.c directory.c dirserv.c dns.c hibernate.c main.c \
onion.c relay.c rendcommon.c rendclient.c rendmid.c \
rendservice.c rephist.c router.c routerlist.c routerparse.c \
@@ -16,7 +16,7 @@
test_SOURCES = buffers.c circuitbuild.c circuitlist.c \
circuituse.c command.c config.c \
- connection.c connection_edge.c connection_or.c \
+ connection.c connection_edge.c connection_or.c control.c \
cpuworker.c directory.c dirserv.c dns.c hibernate.c main.c \
onion.c relay.c rendcommon.c rendclient.c rendmid.c \
rendservice.c rephist.c router.c routerlist.c routerparse.c \
Index: buffers.c
===================================================================
RCS file: /home/or/cvsroot/src/or/buffers.c,v
retrieving revision 1.109
retrieving revision 1.110
diff -u -d -r1.109 -r1.110
--- buffers.c 27 Oct 2004 06:48:16 -0000 1.109
+++ buffers.c 3 Nov 2004 01:32:26 -0000 1.110
@@ -636,6 +636,38 @@
}
}
+/* DOCDOC: 1 if complete, 0 if pending, -1 on error. */
+int fetch_from_buf_control(buf_t *buf, uint16_t *len_out, uint16_t *type_out,
+ char **body_out)
+{
+ uint16_t len;
+
+ tor_assert(buf);
+ tor_assert(len_out);
+ tor_assert(type_out);
+ tor_assert(body_out);
+
+ if (buf->datalen < 4)
+ return 0;
+
+ len = ntohs(get_uint16(buf->mem));
+ if (buf->datalen < 4 + (unsigned)len)
+ return 0;
+
+ *len_out = len;
+ *type_out = ntohs(get_uint16(buf->mem+2));
+ if (len) {
+ *body_out = tor_malloc(len);
+ memcpy(*body_out, buf->mem+4, len);
+ } else {
+ *body_out = NULL;
+ }
+
+ buf_remove_from_front(buf, 4+len);
+
+ return 1;
+}
+
/** Log an error and exit if <b>buf</b> is corrupted.
*/
void assert_buf_ok(buf_t *buf)
Index: connection.c
===================================================================
RCS file: /home/or/cvsroot/src/or/connection.c,v
retrieving revision 1.275
retrieving revision 1.276
diff -u -d -r1.275 -r1.276
--- connection.c 2 Nov 2004 23:47:32 -0000 1.275
+++ connection.c 3 Nov 2004 01:32:26 -0000 1.276
@@ -28,6 +28,8 @@
"Dir", /* 9 */
"DNS worker", /* 10 */
"CPU worker", /* 11 */
+ "Control listener", /* 12 */
+ "Control", /* 13 */
};
/** Array of string arrays to make {conn-\>type,conn-\>state} human-readable. */
@@ -70,6 +72,10 @@
"idle", /* 1 */
"busy with onion", /* 2 */
"busy with handshake" }, /* 3 */
+ { "ready" }, /* control listener, 0 */
+ { "", /* control, 0 */
+ "ready", /* 1 */
+ "waiting for authentication", }, /* 2 */
};
/********* END VARIABLES ************/
@@ -326,7 +332,7 @@
log_fn(LOG_WARN, "Error parsing/resolving BindAddress %s",bindaddress);
return -1;
}
-
+
if (usePort==0)
usePort = bindport;
bindaddr.sin_addr.s_addr = htonl(addr);
@@ -459,6 +465,9 @@
conn->purpose = DIR_PURPOSE_SERVER;
conn->state = DIR_CONN_STATE_SERVER_COMMAND_WAIT;
break;
+ case CONN_TYPE_CONTROL:
+ /* XXXX009 NM control */
+ break;
}
return 0;
}
@@ -543,7 +552,8 @@
int i,n;
tor_assert(type == CONN_TYPE_OR_LISTENER ||
type == CONN_TYPE_AP_LISTENER ||
- type == CONN_TYPE_DIR_LISTENER);
+ type == CONN_TYPE_DIR_LISTENER ||
+ type == CONN_TYPE_CONTROL_LISTENER);
get_connection_array(&carray,&n);
for(i=0;i<n;i++) {
conn = carray[i];
@@ -585,7 +595,7 @@
want = 0;
}
- /* How many are there actually? */
+ /* How many are there actually? */
have = 0;
get_connection_array(&carray,&n_conn);
for(i=0;i<n_conn;i++) {
@@ -602,7 +612,7 @@
log_fn(LOG_WARN,"We have %d %s(s) open, but we want %d; relaunching.",
have, conn_type_to_string[type], want);
}
-
+
listener_close_if_present(type);
if (port_option) {
if (!cfg) {
@@ -636,6 +646,7 @@
if (retry_listeners(CONN_TYPE_AP_LISTENER, options.SocksBindAddress,
options.SocksPort, "127.0.0.1", force)<0)
return -1;
+ /* XXXX009 control NM */
return 0;
}
@@ -787,6 +798,8 @@
return connection_handle_listener_read(conn, CONN_TYPE_AP);
case CONN_TYPE_DIR_LISTENER:
return connection_handle_listener_read(conn, CONN_TYPE_DIR);
+ case CONN_TYPE_CONTROL_LISTENER:
+ return connection_handle_listener_read(conn, CONN_TYPE_CONTROL);
}
if(connection_read_to_buf(conn) < 0) {
@@ -1151,7 +1164,8 @@
int connection_is_listener(connection_t *conn) {
if(conn->type == CONN_TYPE_OR_LISTENER ||
conn->type == CONN_TYPE_AP_LISTENER ||
- conn->type == CONN_TYPE_DIR_LISTENER)
+ conn->type == CONN_TYPE_DIR_LISTENER ||
+ conn->type == CONN_TYPE_CONTROL_LISTENER)
return 1;
return 0;
}
@@ -1167,7 +1181,8 @@
if((conn->type == CONN_TYPE_OR && conn->state == OR_CONN_STATE_OPEN) ||
(conn->type == CONN_TYPE_AP && conn->state == AP_CONN_STATE_OPEN) ||
- (conn->type == CONN_TYPE_EXIT && conn->state == EXIT_CONN_STATE_OPEN))
+ (conn->type == CONN_TYPE_EXIT && conn->state == EXIT_CONN_STATE_OPEN) ||
+ (conn->type == CONN_TYPE_CONTROL && conn->state ==CONTROL_CONN_STATE_OPEN))
return 1;
return 0;
@@ -1232,6 +1247,8 @@
return connection_dns_process_inbuf(conn);
case CONN_TYPE_CPUWORKER:
return connection_cpu_process_inbuf(conn);
+ case CONN_TYPE_CONTROL:
+ return connection_control_process_inbuf(conn);
default:
log_fn(LOG_WARN,"got unexpected conn->type %d.", conn->type);
return -1;
@@ -1262,6 +1279,8 @@
return connection_dns_finished_flushing(conn);
case CONN_TYPE_CPUWORKER:
return connection_cpu_finished_flushing(conn);
+ case CONN_TYPE_CONTROL:
+ return connection_control_finished_flushing(conn);
default:
log_fn(LOG_WARN,"got unexpected conn->type %d.", conn->type);
return -1;
@@ -1384,6 +1403,7 @@
case CONN_TYPE_OR_LISTENER:
case CONN_TYPE_AP_LISTENER:
case CONN_TYPE_DIR_LISTENER:
+ case CONN_TYPE_CONTROL_LISTENER:
tor_assert(conn->state == LISTENER_STATE_READY);
break;
case CONN_TYPE_OR:
@@ -1413,6 +1433,11 @@
tor_assert(conn->state >= _CPUWORKER_STATE_MIN);
tor_assert(conn->state <= _CPUWORKER_STATE_MAX);
break;
+ case CONN_TYPE_CONTROL:
+ tor_assert(conn->state >= _CONTROL_CONN_STATE_MIN);
+ tor_assert(conn->state <= _CONTROL_CONN_STATE_MAX);
+ /* XXXX009 NM */
+ break;
default:
tor_assert(0);
}
--- NEW FILE: control.c ---
/* Copyright 2004 Nick Mathewson */
/* See LICENSE for licensing information */
/* $Id: control.c,v 1.1 2004/11/03 01:32:26 nickm Exp $ */
#include "or.h"
#define CONTROL_CMD_ERROR 0x0000
#define CONTROL_CMD_DONE 0x0001
#define CONTROL_CMD_SETCONF 0x0002
#define CONTROL_CMD_GETCONF 0x0003
#define CONTROL_CMD_CONFVALUE 0x0004
#define CONTROL_CMD_SETEVENTS 0x0005
#define CONTROL_CMD_EVENT 0x0006
#define CONTROL_CMD_AUTHENTICATE 0x0007
#define _CONTROL_CMD_MAX_RECOGNIZED 0x0007
#define ERR_UNSPECIFIED 0x0000
#define ERR_UNRECOGNIZED_TYPE 0x0001
#define ERR_UNRECOGNIZED_CONFIG_KEY 0x0002
#define ERR_INVALID_CONFIG_VALUE 0x0003
#define ERR_UNRECOGNIZED_EVENT_CODE 0x0004
#define ERR_UNAUTHORIZED_USER 0x0005
#define ERR_FAILED_AUTHENTICATION 0x0006
#define _EVENT_MIN 0x0001
#define EVENT_CIRCUIT_STATUS 0x0001
#define EVENT_STREAM_STATUS 0x0002
#define EVENT_OR_CONN_STATUS 0x0003
#define EVENT_BANDWIDTH_USED 0x0004
#define EVENT_WARNING 0x0005
#define _EVENT_MAX 0x0005
#define EVENT_IS_INTERESTING(e) (global_event_mask & (1<<(e)))
static const char *CONTROL_COMMANDS[] = {
"error",
"done",
"setconf",
"getconf",
"confvalue",
"setevents",
"events",
"authenticate",
};
static uint32_t global_event_mask = 0;
static void update_global_event_mask(void);
static void send_control_message(connection_t *conn, uint16_t type,
uint16_t len, const char *body);
static void send_control_done(connection_t *conn);
static void send_control_error(connection_t *conn, uint16_t error,
const char *message);
static void send_control_event(uint16_t event, uint16_t len, const char *body);
static int handle_control_setconf(connection_t *conn, uint16_t len,
const char *body);
static int handle_control_getconf(connection_t *conn, uint16_t len,
const char *body);
static int handle_control_setevents(connection_t *conn, uint16_t len,
const char *body);
static int handle_control_authenticate(connection_t *conn, uint16_t len,
const char *body);
static INLINE const char *
control_cmd_to_string(uint16_t cmd)
{
return (cmd<=_CONTROL_CMD_MAX_RECOGNIZED) ? CONTROL_COMMANDS[cmd] : "Unknown";
}
static void update_global_event_mask(void)
{
connection_t **conns;
int n_conns, i;
global_event_mask = 0;
get_connection_array(&conns, &n_conns);
for (i = 0; i < n_conns; ++i) {
if (conns[i]->type == CONN_TYPE_CONTROL &&
conns[i]->state == CONTROL_CONN_STATE_OPEN) {
global_event_mask |= conns[i]->event_mask;
}
}
}
static void
send_control_message(connection_t *conn, uint16_t type, uint16_t len,
const char *body)
{
char buf[4];
tor_assert(conn);
tor_assert(len || !body);
tor_assert(type <= _CONTROL_CMD_MAX_RECOGNIZED);
set_uint32(buf, htons(len));
set_uint32(buf+2, htons(type));
connection_write_to_buf(buf, 4, conn);
if (len)
connection_write_to_buf(body, len, conn);
}
static void
send_control_done(connection_t *conn)
{
send_control_message(conn, CONTROL_CMD_DONE, 0, NULL);
}
static void
send_control_error(connection_t *conn, uint16_t error, const char *message)
{
char buf[256];
size_t len;
set_uint16(buf, htons(error));
len = strlen(message);
tor_assert(len < (256-2));
memcpy(buf+2, message, len);
send_control_message(conn, CONTROL_CMD_ERROR, len+2, buf);
}
static void
send_control_event(uint16_t event, uint16_t len, const char *body)
{
connection_t **conns;
int n_conns, i;
get_connection_array(&conns, &n_conns);
for (i = 0; i < n_conns; ++i) {
if (conns[i]->type == CONN_TYPE_CONTROL &&
conns[i]->state == CONTROL_CONN_STATE_OPEN &&
conns[i]->event_mask & (1<<event)) {
send_control_message(conns[i], CONTROL_CMD_EVENT, len, body);
}
}
}
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,
const char *body)
{
/* XXXX009 NM */
return 0;
}
static int handle_control_setevents(connection_t *conn, uint16_t len,
const char *body)
{
uint16_t event_code;
uint32_t event_mask = 0;
if (len % 2) {
send_control_error(conn, ERR_UNSPECIFIED,
"Odd number of bytes in setevents message");
return 0;
}
for (; len; len -= 2, body += 2) {
event_code = ntohs(get_uint16(body));
if (event_code < _EVENT_MIN || event_code > _EVENT_MAX) {
send_control_error(conn, ERR_UNRECOGNIZED_EVENT_CODE,
"Unrecognized event code");
return 0;
}
event_mask |= (1 << event_code);
}
conn->event_mask = event_mask;
update_global_event_mask();
send_control_done(conn);
return 0;
}
static int handle_control_authenticate(connection_t *conn, uint16_t len,
const char *body)
{
if (0/* XXXX009 NM */) {
send_control_done(conn);
conn->state = CONTROL_CONN_STATE_OPEN;
} else {
send_control_error(conn, ERR_FAILED_AUTHENTICATION,"Authentication failed");
}
return 0;
}
int connection_control_finished_flushing(connection_t *conn) {
tor_assert(conn);
tor_assert(conn->type == CONN_TYPE_CONTROL);
connection_stop_writing(conn);
return 0;
}
int connection_control_process_inbuf(connection_t *conn) {
uint16_t body_len, command_type;
char *body;
tor_assert(conn);
tor_assert(conn->type == CONN_TYPE_CONTROL);
again:
switch(fetch_from_buf_control(conn->inbuf, &body_len, &command_type, &body))
{
case -1:
log_fn(LOG_WARN, "Error in control command. Failing.");
return -1;
case 0:
/* Control command not all here yet. Wait. */
return 0;
case 1:
/* We got a command. Process it. */
break;
default:
tor_assert(0);
}
/* We got a command. If we need authentication, only authentication
* commands will be considered. */
if (conn->state == CONTROL_CONN_STATE_NEEDAUTH &&
command_type != CONTROL_CMD_AUTHENTICATE) {
log_fn(LOG_WARN, "Rejecting '%s' command; authentication needed.",
control_cmd_to_string(command_type));
send_control_error(conn, ERR_UNAUTHORIZED_USER, "Authentication required");
tor_free(body);
goto again;
}
switch(command_type)
{
case CONTROL_CMD_SETCONF:
if (handle_control_setconf(conn, body_len, body))
return -1;
break;
case CONTROL_CMD_GETCONF:
if (handle_control_getconf(conn, body_len, body))
return -1;
break;
case CONTROL_CMD_SETEVENTS:
if (handle_control_setevents(conn, body_len, body))
return -1;
break;
case CONTROL_CMD_AUTHENTICATE:
if (handle_control_authenticate(conn, body_len, body))
return -1;
break;
case CONTROL_CMD_ERROR:
case CONTROL_CMD_DONE:
case CONTROL_CMD_CONFVALUE:
case CONTROL_CMD_EVENT:
log_fn(LOG_WARN, "Received client-only '%s' command; ignoring.",
control_cmd_to_string(command_type));
send_control_error(conn, ERR_UNRECOGNIZED_TYPE,
"Command type only valid from server tor client");
break;
default:
log_fn(LOG_WARN, "Received unrecognized command type %d; ignoring.",
(int)command_type);
send_control_error(conn, ERR_UNRECOGNIZED_TYPE,
"Unrecognized command type");
break;
}
tor_free(body);
goto again; /* There might be more data. */
}
int control_event_circuit_status(circuit_t *circ)
{
if (!EVENT_IS_INTERESTING(EVENT_CIRCUIT_STATUS))
return 0;
/* XXXXX009 NM */
return 0;
}
int control_event_stream_status(connection_t *conn)
{
tor_assert(conn->type == CONN_TYPE_AP);
if (!EVENT_IS_INTERESTING(EVENT_STREAM_STATUS))
return 0;
/* XXXXX009 NM */
return 0;
}
int control_event_or_conn_status(connection_t *conn)
{
tor_assert(conn->type == CONN_TYPE_OR);
if (!EVENT_IS_INTERESTING(EVENT_OR_CONN_STATUS))
return 0;
/* XXXXX009 NM */
return 0;
}
int control_event_bandwidth_used(uint32_t n_read, uint32_t n_written)
{
char buf[8];
if (!EVENT_IS_INTERESTING(EVENT_BANDWIDTH_USED))
return 0;
set_uint32(buf, htonl(n_read));
set_uint32(buf+4, htonl(n_read));
send_control_event(EVENT_BANDWIDTH_USED, 8, buf);
return 0;
}
int control_event_warning(const char *msg)
{
size_t len;
if (!EVENT_IS_INTERESTING(EVENT_WARNING))
return 0;
len = strlen(msg);
send_control_event(EVENT_WARNING, len+1, msg);
return 0;
}
/*
Local Variabls:
mode:c
indent-tabs-mode:nil
c-basic-offset:2
End:
*/
Index: or.h
===================================================================
RCS file: /home/or/cvsroot/src/or/or.h,v
retrieving revision 1.454
retrieving revision 1.455
diff -u -d -r1.454 -r1.455
--- or.h 2 Nov 2004 23:47:32 -0000 1.454
+++ or.h 3 Nov 2004 01:32:26 -0000 1.455
@@ -171,7 +171,11 @@
#define CONN_TYPE_DNSWORKER 10
/** Type for connections to local cpuworker processes. */
#define CONN_TYPE_CPUWORKER 11
-#define _CONN_TYPE_MAX 11
+/** Type for listenting for connections from user interface process */
+#define CONN_TYPE_CONTROL_LISTENER 12
+/** Type for connections from user interface process */
+#define CONN_TYPE_CONTROL 13
+#define _CONN_TYPE_MAX 13
/** State for any listener connection. */
#define LISTENER_STATE_READY 0
@@ -247,6 +251,11 @@
#define DIR_CONN_STATE_SERVER_WRITING 5
#define _DIR_CONN_STATE_MAX 5
+#define _CONTROL_CONN_STATE_MIN 1
+#define CONTROL_CONN_STATE_OPEN 1
+#define CONTROL_CONN_STATE_NEEDAUTH 2
+#define _CONTROL_CONN_STATE_MAX 2
+
#define _DIR_PURPOSE_MIN 1
/** Purpose for connection to directory server: download a directory. */
#define DIR_PURPOSE_FETCH_DIR 1
@@ -546,6 +555,9 @@
/* Used only by AP connections */
socks_request_t *socks_request; /**< SOCKS structure describing request (AP
* only.) */
+
+ /* Used only by control connections */
+ uint32_t event_mask;
};
typedef struct connection_t connection_t;
@@ -981,6 +993,8 @@
char **headers_out, size_t max_headerlen,
char **body_out, size_t *body_used, size_t max_bodylen);
int fetch_from_buf_socks(buf_t *buf, socks_request_t *req);
+int fetch_from_buf_control(buf_t *buf, uint16_t *len_out, uint16_t *type_out,
+ char **body_out);
void assert_buf_ok(buf_t *buf);
@@ -1186,6 +1200,16 @@
void connection_or_write_cell_to_buf(const cell_t *cell, connection_t *conn);
void connection_or_update_nickname(connection_t *conn);
+/********************************* control.c ***************************/
+
+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_bandwidth_used(uint32_t n_read, uint32_t n_written);
+int control_event_warning(const char *msg);
/********************************* cpuworker.c *****************************/
More information about the tor-commits
mailing list