2
This file is part of GNUnet.
3
(C) 2003, 2004 Christian Grothoff (and other contributing authors)
5
GNUnet is free software; you can redistribute it and/or modify
6
it under the terms of the GNU General Public License as published
7
by the Free Software Foundation; either version 2, or (at your
8
option) any later version.
10
GNUnet is distributed in the hope that it will be useful, but
11
WITHOUT ANY WARRANTY; without even the implied warranty of
12
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
General Public License for more details.
15
You should have received a copy of the GNU General Public License
16
along with GNUnet; see the file COPYING. If not, write to the
17
Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18
Boston, MA 02111-1307, USA.
22
* @file applications/testbed/commands.c
23
* @brief the commands available in the testbed
24
* @author Ronaldo Alves Ferreira
25
* @author Christian Grothoff
26
* @author Murali Krishan Ramanathan
30
* - implement shutdown (in particular, kill ssh connections / processes!)
31
* - design and implement better topology management
36
#include "gnunet_protocols.h"
37
#include "gnunet_getoption_lib.h"
38
#include "gnunet_stats_lib.h"
44
* @brief struct keeping per-peer information for the testbed
47
/** IP address of the peer */
49
/** CS port of the peer */
51
/** string describing the peer address */
53
/** socket to communicate with the peer */
54
GNUNET_TCP_SOCKET sock;
55
/** hello message identifying the peer in the network */
56
P2P_hello_MESSAGE * helo;
57
/** if we're using ssh, what is the PID of the
58
ssh process? (-1 for unencrypted direct connections) */
63
* List of nodes known to the testbed.
65
static NODE_INFO * nodes = NULL;
68
* Number of known nodes, size of the nodes array.
70
static unsigned int nnodes = 0;
73
* Should the driver exit?
78
* Convert the strings ss and ds to peer-identifiers (ints) s and d
79
* respectively. Aborts the method containing the macro with an error
80
* message if the peer-IDs are not within range.
82
#define CHECK_SRC_DST(s, d, ss, ds) \
85
if (s < 0 || s >= nnodes || d < 0 || d >= nnodes) { \
86
XPRINTF("Invalid src (%s) or dst (%s)\n", ss, ds); \
91
* Convert the string ps to a peer-id p and abort the current method
92
* with an error message if ps is not a valid peer-id.
94
#define CHECK_PEER(p, ps) \
96
if (p < 0 || p >= nnodes) { \
97
XPRINTF("Invalid peer value %s\n", ps); \
102
* Send a message to peer 'peer' of type 'msgType'
103
* the given size and data.
105
static int sendMessage(unsigned msgType,
107
unsigned short argSize,
109
TESTBED_CS_MESSAGE * msg;
112
/* Assume peer value is valid. */
113
if (argSize + sizeof(TESTBED_CS_MESSAGE) > 65535)
114
errexit("Message body too big for sendMessage: %s\n",
117
msgsz = sizeof(TESTBED_CS_MESSAGE)+argSize;
122
= htons(CS_PROTO_testbed_REQUEST);
125
memcpy(&((TESTBED_CS_MESSAGE_GENERIC*)msg)->data[0],
128
msgsz = writeToSocket(&nodes[peer].sock,
131
if (msgsz == SYSERR) {
132
XPRINTF(" Could not send message to peer %s.\n",
140
* Read a result from the given peer. Print
141
* an error message if the peer fails to respond.
143
* @return OK on success, SYSERR on error
145
static int readResult(int peer,
147
if (OK != readTCPResult(&nodes[peer].sock,
149
XPRINTF(" peer %s is not responding.\n",
156
/* ****************** individual commands ********** */
160
* Add a node to the configuration.
161
* Arguments must be IP PORT of the peer.
163
static int addNode(int argc, char * argv[]) {
165
TESTBED_hello_MESSAGE * hdr;
166
TESTBED_GET_hello_MESSAGE req;
171
XPRINTF("Syntax: add-node IP PORT.\n");
174
port = atoi(argv[1]);
175
for (i=0;i<nnodes;i++) {
176
if ( (0 == strcmp(argv[0],
178
(port == nodes[i].port) ) {
179
XPRINTF("Node already in use!\n");
189
GROW(nodes, nnodes, nnodes+1);
190
nodes[currindex].ips = STRDUP(argv[0]);
191
nodes[currindex].port = atoi(argv[1]);
192
nodes[currindex].ssh = -1;
194
inet_aton(argv[0], (struct in_addr*) &nodes[currindex].ip);
196
nodes[currindex].ip.addr.S_un.S_addr = inet_addr(argv[0]);
199
if (SYSERR == initGNUnetClientSocket(nodes[currindex].port,
200
nodes[currindex].ips,
201
&nodes[currindex].sock)) {
202
XPRINTF(" could not connect to %s:%d.\n",
203
nodes[currindex].ips,
204
nodes[currindex].port);
209
if (OK != sendMessage(TESTBED_GET_hello,
211
sizeof(TESTBED_GET_hello_MESSAGE)-sizeof(TESTBED_CS_MESSAGE),
213
/* send message already printed an error message */
214
destroySocket(&nodes[currindex].sock);
215
FREE(nodes[currindex].ips);
223
if (SYSERR == readFromSocket(&nodes[currindex].sock,
224
(CS_MESSAGE_HEADER**)&hdr)) {
225
XPRINTF(" peer %s is not responding.\n",
226
nodes[currindex].ips);
227
destroySocket(&nodes[currindex].sock);
228
FREE(nodes[currindex].ips);
229
GROW(nodes, nnodes, nnodes-1);
232
if ( (ntohs(hdr->header.header.type) == CS_PROTO_testbed_REPLY) &&
233
(ntohs(hdr->header.header.size) >= sizeof(TESTBED_hello_MESSAGE)) &&
234
(ntohl(hdr->header.msgType) == TESTBED_hello_RESPONSE) &&
235
(ntohs(hdr->header.header.size) - sizeof(TESTBED_CS_MESSAGE) >= sizeof(P2P_hello_MESSAGE)) &&
236
(ntohs(hdr->header.header.size) - sizeof(TESTBED_CS_MESSAGE) == P2P_hello_MESSAGE_size(&hdr->helo)) ) {
237
nodes[currindex].helo
238
= MALLOC(P2P_hello_MESSAGE_size(&hdr->helo));
239
memcpy(nodes[currindex].helo,
241
P2P_hello_MESSAGE_size(&hdr->helo));
244
destroySocket(&nodes[currindex].sock);
245
XPRINTF(" peer %s did not respond with proper hello.\n",
246
nodes[currindex].ips);
247
FREE(nodes[currindex].ips);
248
GROW(nodes, nnodes, nnodes-1);
260
* Add an node reachable via ssh-tunnel to the configuration.
261
* Arguments must be LOGIN, IP PORT of the peer. Sshd must
262
* be running on the default port.
264
static int addSshNode(int argc, char * argv[]) {
266
TESTBED_hello_MESSAGE * hdr;
267
TESTBED_GET_hello_MESSAGE req;
271
unsigned short lport;
277
XPRINTF("Syntax: add-ssh-node LOGIN IP PORT.\n");
280
port = atoi(argv[2]);
281
for (i=0;i<nnodes;i++) {
282
if ( (0 == strcmp(argv[1],
284
(port == nodes[i].port) ) {
285
XPRINTF("Node already in use!\n");
290
/* find available local port to bind to */
291
for (lport=10000;lport<65535;lport++) {
292
struct sockaddr_in addr;
296
s = SOCKET(PF_INET, SOCK_STREAM, 0);
298
XPRINTF("Cannot open socket: %s\n",
305
&on, sizeof(on)) < 0 )
306
perror("setsockopt");
317
(const struct sockaddr *) &addr,
318
sizeof(struct sockaddr_in))) {
320
break; /* found port! */
322
closefile(s); /* not available, try another one... */
325
if (lport == 65535) {
326
XPRINTF(" Cannot find available local port!\n");
336
sargv[2] = argv[0]; /* login */
341
lport, /* local port */
342
"localhost", /* loopback on remote host */
343
port /* remote port */);
345
sargv[5] = argv[1]; /* remote hostname */
346
sargv[6] = NULL; /* last argument */
350
" execvp failed: %s\n",
355
XPRINTF("Failed to fork: %s\n",
365
GROW(nodes, nnodes, nnodes+1);
366
nodes[currindex].ips = STRDUP("localhost");
367
nodes[currindex].port = lport;
368
nodes[currindex].ssh = pid;
370
inet_aton(argv[0], (struct in_addr*) &nodes[currindex].ip);
372
nodes[currindex].ip.addr.S_un.S_addr = inet_addr(argv[0]);
375
/* FIXME: wait a bit to give ssh a chance to connect... */
376
rtc = 0; /* number of retries */
378
ret = initGNUnetClientSocket(nodes[currindex].port,
379
nodes[currindex].ips,
380
&nodes[currindex].sock);
384
gnunet_util_sleep(cronSECONDS);
387
XPRINTF(" could not connect to %s:%d.\n",
388
nodes[currindex].ips,
389
nodes[currindex].port);
390
kill(nodes[currindex].ssh,
392
waitpid(nodes[currindex].ssh,
395
GROW(nodes, nnodes, nnodes-1);
400
if (OK != sendMessage(TESTBED_GET_hello,
402
sizeof(TESTBED_GET_hello_MESSAGE)-sizeof(TESTBED_CS_MESSAGE),
404
/* send message already printed an error message */
405
destroySocket(&nodes[currindex].sock);
406
FREE(nodes[currindex].ips);
407
/* fixme: check error conditions on kill/waidpid! */
408
kill(nodes[currindex].ssh,
410
waitpid(nodes[currindex].ssh,
420
if (SYSERR == readFromSocket(&nodes[currindex].sock,
421
(CS_MESSAGE_HEADER**)&hdr)) {
422
XPRINTF(" peer %s is not responding.\n",
423
nodes[currindex].ips);
424
destroySocket(&nodes[currindex].sock);
425
FREE(nodes[currindex].ips);
426
/* fixme: check error conditions on kill/waidpid! */
427
kill(nodes[currindex].ssh,
429
waitpid(nodes[currindex].ssh,
432
GROW(nodes, nnodes, nnodes-1);
435
if ( (ntohs(hdr->header.header.type) == CS_PROTO_testbed_REPLY) &&
436
(ntohs(hdr->header.header.size) >= sizeof(TESTBED_hello_MESSAGE)) &&
437
(ntohl(hdr->header.msgType) == TESTBED_hello_RESPONSE) &&
438
(ntohs(hdr->header.header.size) - sizeof(TESTBED_CS_MESSAGE) >= sizeof(P2P_hello_MESSAGE)) &&
439
(ntohs(hdr->header.header.size) - sizeof(TESTBED_CS_MESSAGE) == P2P_hello_MESSAGE_size(&hdr->helo)) ) {
440
nodes[currindex].helo
441
= MALLOC(P2P_hello_MESSAGE_size(&hdr->helo));
442
memcpy(nodes[currindex].helo,
444
P2P_hello_MESSAGE_size(&hdr->helo));
447
destroySocket(&nodes[currindex].sock);
448
XPRINTF(" peer %s did not respond with proper hello.\n",
449
nodes[currindex].ips);
450
FREE(nodes[currindex].ips);
451
/* fixme: check error conditions on kill/waidpid! */
452
kill(nodes[currindex].ssh,
454
waitpid(nodes[currindex].ssh,
457
GROW(nodes, nnodes, nnodes-1);
468
* Tear down the connection between two peers.
470
static int delConnection(int argc,
475
XPRINTF("Syntax: disconnect PEERID PEERID\n");
478
CHECK_SRC_DST(src, dst, argv[0], argv[1]);
479
if (OK != sendMessage(TESTBED_DEL_PEER,
481
sizeof(PeerIdentity),
482
&nodes[dst].helo->senderIdentity))
484
if (OK != readResult(src,
491
XPRINTF(" Connection NOT deleted.\n");
497
* Tear down all connections of a peer.
499
static int delAllConnections(int argc,
504
XPRINTF("Syntax: disconnect-all PEERID\n");
507
CHECK_PEER(dst, argv[0]);
508
if (OK != sendMessage(TESTBED_DEL_ALL_PEERS,
513
if (OK != readResult(dst,
520
XPRINTF(" Connections NOT deleted.\n");
526
* Add a connection between two peers.
528
static int addConnection(int argc,
533
XPRINTF("Syntax: connect PEERID PEERID\n");
536
CHECK_SRC_DST(src, dst, argv[0], argv[1]);
537
if (SYSERR == sendMessage(TESTBED_ADD_PEER,
539
P2P_hello_MESSAGE_size(nodes[dst].helo),
542
if (OK != readResult(src,
549
XPRINTF(" peer cannot connect.\n");
555
* Set the level of trust that one peer has in
558
static int setTrust(int argc, char * argv[]) {
559
int src, dst, value, ack;
560
TESTBED_SET_TVALUE_MESSAGE msg;
563
XPRINTF("Syntax: set-trust PEERID PEERID TRUST\n");
566
CHECK_SRC_DST(src, dst, argv[0], argv[1]);
567
value = atoi(argv[2]);
568
msg.trust = htonl(value);
569
memcpy(&msg.otherPeer,
570
&nodes[dst].helo->senderIdentity,
571
sizeof(PeerIdentity));
572
if (SYSERR == sendMessage(TESTBED_SET_TVALUE,
574
sizeof(PeerIdentity)+sizeof(unsigned int),
577
if (OK != readResult(src,
580
if (htonl(ack) != OK) {
581
XPRINTF(" peer could not set trust value.\n");
590
* Get the amount of trust that A has in B.
592
static int getTrust(int argc, char *argv[]) {
596
XPRINTF("Syntax: get-trust PEERID PEERID\n");
599
CHECK_SRC_DST(src, dst, argv[0], argv[1]);
600
if (SYSERR == sendMessage(TESTBED_GET_TVALUE,
602
sizeof(PeerIdentity),
603
&nodes[dst].helo->senderIdentity))
605
if (SYSERR == readResult(src, &value))
608
XPRINTF(" could not get trust value.\n");
618
* Disable hello at a peer.
620
static int disablehello(int argc, char *argv[]) {
624
XPRINTF("Syntax: helo-disable PEERID\n");
627
CHECK_PEER(dst, argv[0]);
628
if (SYSERR == sendMessage(TESTBED_DISABLE_hello,
633
if (SYSERR == readResult(dst, &value))
636
XPRINTF(" could disable hello\n");
645
* Enable hello at a peer.
647
static int enablehello(int argc, char *argv[]) {
651
XPRINTF("Syntax: helo-enable PEERID\n");
654
CHECK_PEER(dst, argv[0]);
655
if (SYSERR == sendMessage(TESTBED_ENABLE_hello,
660
if (SYSERR == readResult(dst, &value))
663
XPRINTF(" could enable hello\n");
672
* Disable AUTOCONNECT at a peer.
674
static int disableAUTOCONNECT(int argc, char *argv[]) {
678
XPRINTF("Syntax: autoconnect-disable PEERID\n");
681
CHECK_PEER(dst, argv[0]);
682
if (SYSERR == sendMessage(TESTBED_DISABLE_AUTOCONNECT,
687
if (SYSERR == readResult(dst, &value))
690
XPRINTF(" could disable AUTOCONNECT\n");
699
* Enable AUTOCONNECT at a peer.
701
static int enableAUTOCONNECT(int argc, char *argv[]) {
705
XPRINTF("Syntax: autoconnect-enable PEERID\n");
708
CHECK_PEER(dst, argv[0]);
709
if (SYSERR == sendMessage(TESTBED_ENABLE_AUTOCONNECT,
714
if (SYSERR == readResult(dst, &value))
717
XPRINTF(" could enable AUTOCONNECT\n");
726
static int allowDenyConnectHelper(unsigned int argc,
734
CHECK_PEER(dst, argv[0]);
735
if (argc > (65532 - sizeof(TESTBED_CS_MESSAGE)) / sizeof(PeerIdentity)) {
736
XPRINTF("Too many peers specified. Ask a wizard to enlarge limit.\n");
742
CHECK_PEER(idx, argv[i]); /* may return, do before MALLOC! */
744
list = MALLOC(sizeof(PeerIdentity)*(argc-1));
745
for (i=1;i<argc;i++) {
746
CHECK_PEER(idx, argv[i]);
748
&nodes[idx].helo->senderIdentity,
749
sizeof(PeerIdentity));
751
if (SYSERR == sendMessage(type,
753
sizeof(PeerIdentity)*(argc-1),
759
if (SYSERR == readResult(dst, &value))
762
XPRINTF(" could change setting.\n");
771
* Deny connections to certain peers at a peer.
773
static int denyConnect(int argc, char *argv[]) {
775
XPRINTF("Syntax: connect-deny PEERID [PEERID]*\n");
778
return allowDenyConnectHelper(argc, argv,
779
TESTBED_DENY_CONNECT);
783
* Allow connections to certain peers at a peer.
785
static int allowConnect(int argc, char *argv[]) {
787
XPRINTF("Syntax: connect-allow PEERID [PEERID]*\n");
790
return allowDenyConnectHelper(argc, argv,
791
TESTBED_ALLOW_CONNECT);
795
* Helper function for (un)loadModule.
796
* @param type load or unload requested?
798
static int loadModuleHelper(unsigned short type,
803
CHECK_PEER(dst, peerId);
804
if (OK != sendMessage(type,
809
if (OK != readResult(dst,
813
XPRINTF(" peer %s refused.\n",
822
* Load an application module at the given peer.
824
static int loadModule(int argc, char *argv[]) {
826
XPRINTF("Syntax: load-module PEERID MODULENAME\n");
829
return loadModuleHelper(TESTBED_LOAD_MODULE,
835
* Unload an application module.
837
static int unloadModule(int argc, char *argv[]) {
839
XPRINTF("Syntax: unload-module PEERID MODULENAME\n");
842
return loadModuleHelper(TESTBED_UNLOAD_MODULE,
848
* Fork a client process. Captures the output and makes it
849
* available via process-output. The client can be killed
850
* using process-signal. The process identifier is printed.
852
static int startProcess(int argc,
862
XPRINTF("Syntax: process-start PEERID COMMAND [ARGUMENTS]\n");
865
CHECK_PEER(dst, argv[0]);
868
size += 1 + strlen(argv[i]);
869
cmdLine = MALLOC(size);
871
for (i=1;i<argc;i++) {
872
memcpy(&cmdLine[pos],
875
pos += strlen(argv[i])+1;
878
if (OK != sendMessage(TESTBED_EXEC,
886
if (OK != readResult(dst,
894
XPRINTF(" Peer could not fork process.\n");
900
* Send a signal to a client process. Use signal
901
* 0 to test if the process is still live. Use
902
* -1 to obtain the return value from a dead
903
* process and to free all associated resources.
904
* For -1 the return value is printed, otherwise OK.
905
* Note that if the signal is -1 and the process
906
* is still running, -1 is returned (which can then
907
* NOT be distinguished from the process returning -1)
909
static int signalProcess(int argc, char *argv[]) {
912
TESTBED_SIGNAL_MESSAGE msg;
915
XPRINTF("Syntax: process-signal PEERID PROCESSID SIGNAL\n");
918
CHECK_PEER(dst, argv[0]);
919
msg.pid = htonl(atoi(argv[1]));
920
msg.signal = htonl(atoi(argv[2]));
921
if (OK != sendMessage(TESTBED_SIGNAL,
923
sizeof(TESTBED_SIGNAL_MESSAGE) - sizeof(TESTBED_CS_MESSAGE),
926
if (OK != readResult(dst,
929
if (ntohl(msg.signal) == -1) {
930
XPRINTF("%d\n", ack);
937
XPRINTF(" Peer could not signal process.\n");
943
* Get the recorded output of a process.
945
static int dumpProcessOutput(int argc,
952
XPRINTF("Syntax: process-output PEERID PROCESSID\n");
955
CHECK_PEER(dst, argv[0]);
956
pid = htonl(atoi(argv[1]));
957
if (OK != sendMessage(TESTBED_GET_OUTPUT,
962
if (OK != readResult(dst,
967
unsigned int pos = 0;
970
TESTBED_OUTPUT_REPLY_MESSAGE * reply;
973
if (SYSERR == readFromSocket(&nodes[dst].sock,
974
(CS_MESSAGE_HEADER**)&reply)) {
975
XPRINTF(" peer %s is not responding after %d of %d bytes.\n",
981
/* FIXME: check that this is the correct reply format */
982
size = ntohs(reply->header.header.size) - sizeof(TESTBED_OUTPUT_REPLY_MESSAGE);
983
tmp = MALLOC(size+1);
985
&((TESTBED_OUTPUT_REPLY_MESSAGE_GENERIC*)reply)->data[0],
996
XPRINTF(" Peer could not return process output.\n");
1002
* Set bandwidth limitations for a peer.
1004
static int setBW(int argc, char * argv[]) {
1005
TESTBED_SET_BW_MESSAGE msg;
1006
int dst, in, out, ack;
1009
XPRINTF("Syntax: set-bw PEERID DOWN-BPS UP-BPS\n");
1012
CHECK_PEER(dst, argv[0]);
1014
out = atoi(argv[2]);
1015
if ((in < 0) || (out < 0)) {
1016
XPRINTF(" Invalid bandwidth specification.\n");
1019
msg.in_bw = htonl(in);
1020
msg.out_bw = htonl(out);
1021
if (SYSERR == sendMessage(TESTBED_SET_BW,
1023
sizeof(TESTBED_SET_BW_MESSAGE) - sizeof(TESTBED_CS_MESSAGE),
1026
if (OK != readResult(dst, &ack))
1029
XPRINTF(" peer could not set the specified bandwith.\n");
1038
* Set artifical message loss rates for a peer.
1040
static int setLoss(int argc, char * argv[]) {
1043
TESTBED_SET_LOSS_RATE_MESSAGE msg;
1046
XPRINTF("Syntax: set-loss PEERID DOWN-LOSS UP-LOSS\n");
1049
CHECK_PEER(dst, argv[0]);
1050
msg.percentageLossInbound
1051
= htonl(atoi(argv[1]));
1052
msg.percentageLossOutbound
1053
= htonl(atoi(argv[2]));
1055
if (SYSERR == sendMessage(TESTBED_SET_LOSS_RATE,
1057
sizeof(TESTBED_SET_LOSS_RATE_MESSAGE) - sizeof(TESTBED_CS_MESSAGE),
1058
&msg.percentageLossInbound))
1060
if (OK != readResult(dst, &ack))
1063
XPRINTF(" peer could not set the specified loss rates.\n");
1071
static int printStatistic(const char * name,
1072
unsigned long long value,
1074
if (0 == strcmp(name,
1082
* Obtain statistics from a peer.
1084
* @param argc number of arguments from the command line
1085
* @param argv command line arguments
1086
* @return 0 ok, 1 on error
1088
static int getStat(int argc, char ** argv) {
1089
int res, peer, printProtocols;
1091
printProtocols = NO;
1093
XPRINTF("Syntax: get-stat PEERID STATID\n");
1096
CHECK_PEER(peer, argv[0]);
1097
res = requestStatistics(&nodes[peer].sock,
1098
(StatisticsProcessor) &printStatistic,
1107
* Print statistics received.
1109
* @param stream where to print the statistics
1110
* @return OK on success, SYSERR on error
1112
static int printStatistics(const char * name,
1113
unsigned long long value,
1115
XPRINTF("%-60s: %16llu\n",
1121
static int lastIp2p;
1123
static int printProtocols(unsigned short type,
1126
const char *name = NULL;
1128
if (isP2P != lastIp2p) {
1130
XPRINTF(_("Supported peer-to-peer messages:\n"));
1132
XPRINTF(_("Supported client-server messages:\n"));
1136
name = p2pMessageName(type);
1138
name = csMessageName(type);
1143
XPRINTF("\t%d\t(%s)\n",
1150
* Obtain statistics from a peer.
1152
* @param argc number of arguments from the command line
1153
* @param argv command line arguments
1154
* @return 0 ok, 1 on error
1156
static int getStats(int argc, char ** argv) {
1157
int res, peer, printProtocolsOpt;
1159
printProtocolsOpt = NO;
1161
if (strcmp(argv[0], "-P")) {
1162
XPRINTF("Syntax: get-stats [-P] PEERID\n");
1165
printProtocolsOpt = YES;
1166
CHECK_PEER(peer, argv[1]);
1167
} else if (argc != 1) {
1168
XPRINTF("Syntax: get-stats [-P] PEERID\n");
1171
CHECK_PEER(peer, argv[0]);
1172
res = requestStatistics(&nodes[peer].sock,
1173
(StatisticsProcessor) &printStatistics,
1175
if ( (printProtocolsOpt == YES) &&
1177
lastIp2p = 42; /* not YES or NO */
1178
res = requestAvailableProtocols(&nodes[peer].sock,
1179
(ProtocolProcessor) &printProtocols,
1190
* Obtain option from a peer.
1192
* @param argc number of arguments from the command line
1193
* @param argv command line arguments
1194
* @return 0 ok, 1 on error
1196
static int getOption(int argc, char ** argv) {
1201
XPRINTF("Syntax: get-option PEERID SECTION OPTION\n");
1204
CHECK_PEER(peer, argv[0]);
1205
opt = getConfigurationOptionValue(&nodes[peer].sock,
1209
XPRINTF("Error sending request to peer %d\n",
1221
* Upload a file to a peer.
1223
static int uploadFile(int argc,
1225
int peer, nbytes, flen, ack;
1228
TESTBED_UPLOAD_FILE_MESSAGE * msg;
1231
XPRINTF("Syntax: load-file PEERID LOCAL_FILENAME DEST_FILENAME\n");
1234
CHECK_PEER(peer, argv[0]);
1235
infile = FOPEN(argv[1], "r");
1236
if (infile == NULL) {
1237
XPRINTF(" Could not open file %s\n",
1241
flen = strlen(argv[2]) + 1; /* '\0' added in the flen */
1242
if (flen > TESTBED_FILE_BLK_SIZE) {
1243
XPRINTF(" destination file name too long (%d characters, limit %d).\n",
1245
TESTBED_FILE_BLK_SIZE);
1249
msg = MALLOC(sizeof(TESTBED_UPLOAD_FILE_MESSAGE) + TESTBED_FILE_BLK_SIZE);
1250
msg->header.header.size
1251
= htons(sizeof(TESTBED_UPLOAD_FILE_MESSAGE)+flen);
1252
msg->header.header.type
1253
= htons(CS_PROTO_testbed_REQUEST);
1255
= htonl(TESTBED_UPLOAD_FILE);
1257
= htonl(TESTBED_FILE_DELETE);
1258
memcpy(((TESTBED_UPLOAD_FILE_MESSAGE_GENERIC*)msg)->buf, argv[2], flen);
1260
if (SYSERR == writeToSocket(&nodes[peer].sock,
1261
&msg->header.header)) {
1264
XPRINTF(" Could not send message to peer %s.\n",
1268
/* Read ack from the peer */
1269
if (OK != readTCPResult(&nodes[peer].sock, &ack)) {
1272
XPRINTF("Peer is not responding\n");
1278
XPRINTF(" Peer returned error (delete existing file).\n");
1281
msg->type = htonl(TESTBED_FILE_APPEND);
1282
buf = ((TESTBED_UPLOAD_FILE_MESSAGE_GENERIC*)msg)->buf + flen;
1283
while ((nbytes = GN_FREAD(buf, 1,
1284
(TESTBED_FILE_BLK_SIZE -
1285
sizeof(TESTBED_UPLOAD_FILE_MESSAGE) - flen),
1289
msg->header.header.size = htons(sizeof(TESTBED_UPLOAD_FILE_MESSAGE) +
1291
if (SYSERR == writeToSocket(&nodes[peer].sock, &msg->header.header)) {
1294
XPRINTF(" could not send file to node %s.\n",
1298
if (OK != readResult(peer, &ack)) {
1306
XPRINTF(" peer returned error.\n");
1310
if (ferror(infile)) {
1313
XPRINTF(" could not read source file. Transmission aborted.\n");
1323
* Print the list of commands.
1325
static int printOnlineHelp(int argc,
1329
while (commands[i].command != NULL) {
1330
XPRINTF("%-30s%s\n",
1331
commands[i].command,
1338
static int processCommands(char * buffer,
1339
unsigned int * available) {
1350
while (end < *available) {
1351
while ( (buffer[end] != '\n') &&
1352
(end < *available) )
1354
if (buffer[end] != '\n') {
1356
XPRINTF("Received invalid response from HTTP server!\n");
1361
*available - start);
1362
*available -= start;
1366
up = MALLOC(end-start+1);
1370
up[end-start] = '\0';
1371
port = 2087; /* default port */
1373
"add-node %d %d %d %d %d",
1395
if (0 != addNode(2, argv))
1401
"add-node %63s %d %d %d %d %d",
1425
if (0 != addSshNode(3, argv))
1438
#define GET_COMMAND "GET %s/display.php3 HTTP/1.0\r\n\r\n"
1439
#define HTTP_URL "http://"
1442
* add-nodes that are listed as available at the
1443
* TESTBED-HTTP registry. Optional argument:
1444
* URL of the registry (by default we use the
1445
* value from the configuration file value).
1447
static int addAvailable(int argc,
1452
unsigned int curpos;
1453
struct sockaddr_in soaddr;
1463
struct sockaddr_in theProxy;
1464
char *proxy, *proxyPort;
1469
reg = getConfigurationString("GNUNET-TESTBED",
1472
XPRINTF(" no testbed registration URL given.\n");
1476
reg = STRDUP(argv[0]);
1480
proxy = getConfigurationString("GNUNETD",
1482
if (proxy != NULL) {
1483
if (OK != GN_getHostByName(proxy,
1485
XPRINTF(" Couldn't resolve name of HTTP proxy '%s'\n",
1487
theProxy.sin_addr.s_addr = 0;
1489
memcpy(&theProxy.sin_addr.s_addr,
1492
proxyPort = getConfigurationString("GNUNETD",
1494
if (proxyPort == NULL) {
1495
theProxy.sin_port = htons(8080);
1497
theProxy.sin_port = htons(atoi(proxyPort));
1503
theProxy.sin_addr.s_addr = 0;
1506
if (0 != strncmp(HTTP_URL,
1508
strlen(HTTP_URL)) ) {
1509
XPRINTF(" invalid URL %s (must begin with %s)\n",
1514
port = 80; /* default http port */
1516
hostname = STRDUP(®[strlen(HTTP_URL)]);
1520
for (i=0;i<strlen(hostname);i++) {
1521
if (hostname[i] == ':')
1523
if (hostname[i] == '/') {
1530
if ( (j != -1) && (j < k) ) {
1533
pstring = MALLOC(strlen(hostname)-j+1);
1536
strlen(hostname)-j+1);
1537
pstring[strlen(hostname)-j] = '\0';
1539
pstring = MALLOC(k-j+1);
1543
pstring[k-j] = '\0';
1545
port = strtol(pstring, &buffer, 10);
1546
if ( (port < 0) || (port > 65536) ) {
1547
XPRINTF(" malformed http URL: %s at %s.\n",
1561
" Trying to download a hostlist from %s\n",
1567
sock = SOCKET(PF_INET,
1571
XPRINTF(" could not open socket for hostlist download (%s).\n",
1578
/* Do we need to connect through a proxy? */
1579
if (theProxy.sin_addr.s_addr == 0) {
1581
if (OK != GN_getHostByName(hostname,
1583
XPRINTF(" could not download hostlist, host '%s' unknown\n",
1589
memcpy(&soaddr.sin_addr.s_addr,
1593
= htons((unsigned short)port);
1596
soaddr.sin_addr.s_addr
1597
= theProxy.sin_addr.s_addr;
1599
= theProxy.sin_port;
1601
soaddr.sin_family = AF_INET;
1603
(struct sockaddr*)&soaddr,
1604
sizeof(soaddr)) < 0) {
1605
XPRINTF(" failed to send HTTP request to host %s: %s\n",
1614
n = strlen(GET_COMMAND) + strlen(reg);
1615
command = MALLOC(n);
1621
curpos = strlen(command)+1;
1622
curpos = SEND_BLOCKING_ALL(sock,
1625
if (SYSERR == (int)curpos) {
1626
XPRINTF(" failed so send HTTP request %s to host %s (%u - %d) - %s\n",
1641
/* we first have to read out the http_response*/
1642
/* it ends with four line delimiters: "\r\n\r\n" */
1644
while (curpos < 4) {
1647
if (start + 5 * cronMINUTES < cronTime(NULL))
1648
break; /* exit after 5m */
1649
success = RECV_NONBLOCKING(sock,
1653
if ( success == NO ) {
1654
gnunet_util_sleep(100 * cronMILLIS);
1657
if ( (ret == 0) || (ret == (size_t)-1) )
1658
break; /* end of transmission or error */
1659
if ((c=='\r') || (c=='\n'))
1664
if (curpos < 4) { /* invalid response */
1665
XPRINTF(" exit register (error: no http response read)\n");
1670
/* now read peer list */
1671
buffer = MALLOC(65536);
1677
if (start + 300 * cronSECONDS < cronTime(NULL))
1678
break; /* exit after 300s */
1680
while (curpos < 65536) {
1681
if (start + 300 * cronSECONDS < cronTime(NULL))
1682
break; /* exit after 300s */
1683
success = RECV_NONBLOCKING(sock,
1687
if ( success == NO ) {
1688
gnunet_util_sleep(20);
1691
if ( (ret == 0) || (ret == (size_t)-1) )
1692
break; /* end of file or error*/
1695
if (0 != processCommands(buffer, &curpos)) {
1702
if (0 != processCommands(buffer, &curpos)) {
1713
* Print the list of available peers.
1715
static int listPeers(int argc, char * argv[]) {
1717
for (i=0;i<nnodes;i++)
1718
XPRINTF("%4d - %s:%d\n",
1726
* Exit gnunet-testbed shell.
1728
static int doExit(int argc, char * argv[]) {
1733
/* ****************** command set ****************** */
1735
CMD_ENTRY commands[] = {
1737
"print this help text",
1749
"add node to testbed, arguments: IP PORT",
1752
"add node to testbed, arguments: LOGIN IP PORT",
1755
"connect two peers",
1758
"disconnect two peers",
1761
"destroy all connections between peers",
1762
&delAllConnections },
1764
"disable hello advertisements",
1767
"enable hello advertisements",
1769
{ "autoconnect-disable", "", &disableAUTOCONNECT },
1770
{ "autoconnect-enable", "", &enableAUTOCONNECT },
1772
"Start a process on a given peer. Prints the process-ID on success.",
1775
"Send a signal to a process running at a peer. Use signal 0 to test if the process is still running. Use -1 to obtain the exit code of a process that terminated.",
1778
"Obtain the process output from a process at a peer.",
1779
&dumpProcessOutput },
1781
"exit the testbed shell",
1783
{ "list-peers", "", &listPeers},
1784
{ "set-loss", "", &setLoss} ,
1786
"get all stats values from peer",
1789
"get one specific stats value from peer",
1792
"Get configuration value from peer.",
1794
{ "load-module", "", &loadModule },
1795
{ "unload-module", "", &unloadModule },
1797
"Check http server for available testbed peers and add"
1798
" all available nodes. An optional argument can be"
1799
" passed to specify the URL of the http server.",
1804
{ "connect-deny", "", &denyConnect },
1805
{ "connect-allow", "", &allowConnect },
1806
{ NULL, NULL }, /* termination */
1810
/* end of commands.c */