tmcc.c 8.16 KB
Newer Older
Leigh B. Stoller's avatar
Leigh B. Stoller committed
1 2 3 4 5 6
/*
 * EMULAB-COPYRIGHT
 * Copyright (c) 2000-2002 University of Utah and the Flux Group.
 * All rights reserved.
 */

7 8 9 10 11 12 13 14 15
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <errno.h>
#include <syslog.h>
#include <unistd.h>
#include <signal.h>
#include <stdarg.h>
Mike Hibler's avatar
Mike Hibler committed
16 17
#include <stdlib.h>
#include <string.h>
18 19 20
#include <sys/time.h>
#include <time.h>
#include <assert.h>
21 22 23 24
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
25
#include "decls.h"
26
#include "ssl.h"
27 28 29
#ifndef STANDALONE
#include "config.h"
#endif
30

31 32 33
#undef  BOSSNODE
#ifndef KEYFILE
#define KEYFILE		"/etc/emulab.pkey"
34
#endif
35

36 37 38 39 40 41 42 43 44 45 46
/*
 * We search a couple of dirs for the bossnode file.
 */
static char *bossnodedirs[] = {
	"/etc/testbed",
	"/etc/rc.d/testbed",
	"/usr/local/etc/testbed",
	"/usr/local/etc/emulab",
	0
};

47 48 49 50 51 52 53 54 55
/*
 * Need to try several ports cause of firewalling. 
 */
static int portlist[] = {
	TBSERVER_PORT,
	TBSERVER_PORT2,
};
static int numports = sizeof(portlist)/sizeof(int);

56
void		sigcatcher(int foo);
57
char		*getbossnode(void);
58
#ifdef UDP
59
void		doudp(int, char **, int, struct in_addr, int, char *, int);
60 61
#endif

62
char *usagestr = 
63
 "usage: tmcc [-u] [-v versnum] [-p #] [-s server] <command>\n"
64
 " -s server	   Specify a tmcd server to connect to\n"
65
 " -p portnum	   Specify a port number to connect to\n"
66
 " -v versnum	   Specify a version number for tmcd\n"
67
 " -n vnodeid	   Specify the vnodeid\n"
68
 " -k keyfile	   Specify the private keyfile\n"
69
 " -u		   Use UDP instead of TCP\n"
70
 " -t timeout	   Timeout waiting for the controller.\n"
71 72 73 74 75 76 77 78 79 80
 "\n";

void
usage()
{
	fprintf(stderr, usagestr);
	exit(1);
}


Mike Hibler's avatar
Mike Hibler committed
81
int
82 83
main(int argc, char **argv)
{
84
	int			sock, data, n, cc, ch;
Mike Hibler's avatar
Mike Hibler committed
85
	struct sockaddr_in	name;
86 87
	struct hostent		*he;
	struct in_addr		serverip;
Mike Hibler's avatar
Mike Hibler committed
88
	char			buf[MYBUFSIZE], *bp, *response = "";
89
	char			*bossnode = NULL;
90
	int			version = CURRENT_VERSION;
91
	char			*vnodeid = NULL;
92 93
	char			*keyfile = NULL;
	char			*privkey = NULL;
94
	int			waitfor = 0;
95
	FILE			*fp;
96
#ifdef UDP
97
	int			useudp  = 0;
Mike Hibler's avatar
Mike Hibler committed
98
#endif
99

100
	while ((ch = getopt(argc, argv, "v:s:p:un:t:")) != -1)
101 102
		switch(ch) {
		case 'p':
103 104
			portlist[0] = atoi(optarg);
			numports    = 1;
105
			break;
106 107 108
		case 's':
			bossnode = optarg;
			break;
109 110 111
		case 'n':
			vnodeid = optarg;
			break;
112 113 114
		case 'k':
			keyfile = optarg;
			break;
115 116 117
		case 'v':
			version = atoi(optarg);
			break;
118 119 120
		case 't':
			waitfor = atoi(optarg);
			break;
121
#ifdef UDP
122 123 124 125
		case 'u':
			useudp = 1;
			break;
#endif
126 127 128 129 130
		default:
			usage();
		}

	argc -= optind;
131
	if (argc < 1 || argc > 5) {
132
		usage();
133
	}
134
	argv += optind;
135

136 137 138 139
	/*
	 * How do we find our bossnode?
	 *
	 * 1. Command line.
140 141
	 * 2. From a file in the list above.
	 * 3. nameserver goo below.
142 143
	 */
	if (!bossnode) {
144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162
		/*
		 * Search for the file.
		 */
		char **cp = bossnodedirs;
		while (*cp) {
			sprintf(buf, "%s/%s", *cp, BOSSNODE_FILENAME);

			if (access(buf, R_OK) == 0)
				break;
			cp++;
		}
		if (*cp) {
			if ((fp = fopen(buf, "r")) != NULL) {
				if (fgets(buf, sizeof(buf), fp)) {
					if ((bp = strchr(buf, '\n')))
						*bp = (char) NULL;
					bossnode = strdup(buf);
				}
				fclose(fp);
163 164 165
			}
		}
	}
166 167
	if (!bossnode)
		bossnode = getbossnode();
168 169 170 171 172 173 174 175
	he = gethostbyname(bossnode);
	if (he)
		memcpy((char *)&serverip, he->h_addr, he->h_length);
	else {
		fprintf(stderr, "gethostbyname(%s) failed\n", bossnode); 
		exit(1);
	}

176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197
	/*
	 * Grab the key. Its not an error if we do not find it.
	 */
	if (keyfile) {
		/* Well, if one was specifed it has to exist. */
		if (access(keyfile, R_OK) < 0) {
			perror("keyfile"); 
			exit(1);
		}
	}
	else
		keyfile = KEYFILE;

	if ((fp = fopen(keyfile, "r")) != NULL) {
	    if (fgets(buf, sizeof(buf), fp)) {
		if ((bp = strchr(buf, '\n')))
		    *bp = (char) NULL;
		privkey = strdup(buf);
	    }
	    fclose(fp);
	}

198 199 200 201
	if (waitfor) {
		alarm(waitfor);
	}

202 203 204 205 206 207 208 209
	/*
	 * Handle built-in "bossinfo" command
	 */
	if (strcmp(argv[0], "bossinfo") == 0) {
		printf("%s %s\n", bossnode, inet_ntoa(serverip));
		exit(0);
	}

210 211
#ifdef UDP
	if (useudp) {
212 213
		doudp(argc, argv, version, serverip,
		      portlist[0], vnodeid, waitfor);
214 215 216 217 218 219
		/*
		 * Never returns.
		 */
		abort();
	}
#endif
220 221 222 223 224 225
#ifdef  WITHSSL
	if (tmcd_client_sslinit()) {
		printf("SSL initialization failed!\n");
		exit(1);
	}
#endif
226
	while (1) {
227 228 229 230 231 232 233
		for (n = 0; n < numports; n++) {
			/* Create socket from which to read. */
			sock = socket(AF_INET, SOCK_STREAM, 0);
			if (sock < 0) {
				perror("creating stream socket:");
				exit(1);
			}
234

235 236 237 238
			/* Create name. */
			name.sin_family = AF_INET;
			name.sin_addr   = serverip;
			name.sin_port   = htons(portlist[n]);
239

240 241 242 243 244 245 246 247 248
			if (CONNECT(sock, (struct sockaddr *) &name,
				    sizeof(name)) == 0) {
				goto foundit;
			}
			if (errno != ECONNREFUSED) {
				perror("connecting stream socket");
				CLOSE(sock);
				exit(1);
			}
249
			CLOSE(sock);
250
		}
251 252 253
		fprintf(stderr,
			"Connection to TMCD refused. Waiting a bit ...\n");
		sleep(10);
254
	}
255
 foundit:
256 257 258 259 260

	data = 1;
	if (setsockopt(sock, SOL_SOCKET,
		       SO_KEEPALIVE, &data, sizeof(data)) < 0) {
		perror("setsockopt SO_KEEPALIVE");
261
		goto bad;
262
	}
263 264 265 266

	/* Start with version number */
	sprintf(buf, "VERSION=%d ", version);

267 268 269 270 271
	/* Tack on vnodeid */
	if (vnodeid) {
		sprintf(&buf[strlen(buf)], "VNODEID=%s ", vnodeid);
	}

272 273 274 275 276
	/* Tack on privkey */
	if (privkey) {
		sprintf(&buf[strlen(buf)], "PRIVKEY=%s ", privkey);
	}

277 278 279 280
	/*
	 * Since we've gone through a getopt() pass, argv[0] is now the
	 * first argument
	 */
281 282 283 284 285
	n = strlen(buf);
	while (argc && n < sizeof(buf)) {
		n += snprintf(&buf[n], sizeof(buf) - n, "%s ", argv[0]);
		argc--;
		argv++;
286
	}
287
	if (n >= sizeof(buf)) {
Mike Hibler's avatar
Mike Hibler committed
288
		fprintf(stderr, "Command too large!\n");
289
		goto bad;
290 291 292 293 294 295 296
	}

	/*
	 * Write the command to the socket and wait for the response
	 */
	bp = buf;
	while (n) {
297
		if ((cc = WRITE(sock, bp, n)) <= 0) {
298 299
			if (cc < 0) {
				perror("Writing to socket:");
300
				goto bad;
301 302
			}
			fprintf(stderr, "write aborted");
303
			goto bad;
304 305 306 307 308 309
		}
		bp += cc;
		n  -= cc;
	}

	while (1) {
310
		if ((cc = READ(sock, buf, sizeof(buf))) <= 0) {
311 312
			if (cc < 0) {
				perror("Reading from socket:");
313
				goto bad;
314 315 316 317 318 319 320 321 322 323 324 325
			}
			break;
		}
		buf[cc] = '\0';
		bp = (char *) malloc(strlen(response) + cc + 1);
		assert(bp);
		strcpy(bp, response);
		strcat(bp, buf);
		response = bp;
	}
	printf("%s", response);

326
	CLOSE(sock);
327
	exit(0);
328 329 330
 bad:
	CLOSE(sock);
	exit(1);
331 332 333 334 335 336 337
}

void
sigcatcher(int foo)
{
}

338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358
#ifndef BOSSNODE
#include <resolv.h>
#endif

char *
getbossnode(void)
{
#ifdef BOSSNODE
	return strdup(BOSSNODE);
#else
	struct hostent *he;

	res_init();
	he = gethostbyaddr((char *)&_res.nsaddr.sin_addr,
			   sizeof(struct in_addr), AF_INET);
	if (he && he->h_name)
		return strdup(he->h_name);
	return("UNKNOWN");
#endif
}

359
#ifdef UDP
Mike Hibler's avatar
Mike Hibler committed
360 361 362 363
/*
 * Not very robust, send a single request, read a single reply. 
 */
void
364
doudp(int argc, char **argv,
365 366
      int vers, struct in_addr serverip, int portnum, char *vnodeid,
      int waitfor)
Mike Hibler's avatar
Mike Hibler committed
367 368 369
{
	int			sock, length, n, cc;
	struct sockaddr_in	name, client;
Mike Hibler's avatar
Mike Hibler committed
370
	char			buf[MYBUFSIZE], *bp, *response = "";
Mike Hibler's avatar
Mike Hibler committed
371 372 373 374 375 376 377 378 379 380 381

	/* Create socket from which to read. */
	sock = socket(AF_INET, SOCK_DGRAM, 0);
	if (sock < 0) {
		perror("creating dgram socket:");
		exit(1);
	}

	/* Create name. */
	name.sin_family = AF_INET;
	name.sin_addr   = serverip;
382
	name.sin_port = htons(portnum);
Mike Hibler's avatar
Mike Hibler committed
383

384
	/* Start with version number */
385 386
	sprintf(buf, "VERSION=%d ", vers);

387 388 389 390 391
	/* Tack on vnodeid */
	if (vnodeid) {
		sprintf(&buf[strlen(buf)], "VNODEID=%s ", vnodeid);
	}

392 393 394 395
	/*
	 * Since we've gone through a getopt() pass, argv[0] is now the
	 * first argument
	 */
396 397 398 399 400
	n = strlen(buf);
	while (argc && n < sizeof(buf)) {
		n += snprintf(&buf[n], sizeof(buf) - n, "%s ", argv[0]);
		argc--;
		argv++;
401
	}
Mike Hibler's avatar
Mike Hibler committed
402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421
	if (n >= sizeof(buf)) {
		fprintf(stderr, "Command too large!\n");
		exit(1);
	}

	/*
	 * Write the command to the socket and wait for the response
	 */
	cc = sendto(sock, buf, n, 0, (struct sockaddr *)&name, sizeof(name));
	if (cc != n) {
		if (cc < 0) {
			perror("Writing to socket:");
			exit(1);
		}
		fprintf(stderr, "short write (%d != %d)\n", cc, n);
		exit(1);
	}

	cc = recvfrom(sock, buf, sizeof(buf), 0,
		      (struct sockaddr *)&client, &length);
422

Mike Hibler's avatar
Mike Hibler committed
423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438
	if (cc < 0) {
		perror("Reading from socket:");
		exit(1);
	}
	buf[cc] = '\0';
	bp = (char *) malloc(strlen(response) + cc + 1);
	assert(bp);
	strcpy(bp, response);
	strcat(bp, buf);
	response = bp;
	printf("%s", response);

	close(sock);
	exit(0);
}
#endif