tmcc.c 7.28 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
#ifndef STANDALONE
32
#undef BOSSNODE
33
#endif
34 35 36 37 38
#ifdef BOSSNODE
#define DEFAULT_BOSSNODE BOSSNODE
#else
#define DEFAULT_BOSSNODE NULL
#endif
39 40 41
#ifndef BOSSNODEFILE
#define BOSSNODEFILE	 "/usr/local/etc/testbed/bossnode"
#endif
42

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

52
void		sigcatcher(int foo);
53
char		*getbossnode(void);
54
#ifdef UDP
55
void		doudp(int, char **, int, struct in_addr, int, char *, int);
56 57
#endif

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

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


Mike Hibler's avatar
Mike Hibler committed
76
int
77 78
main(int argc, char **argv)
{
79
	int			sock, data, n, cc, ch;
Mike Hibler's avatar
Mike Hibler committed
80
	struct sockaddr_in	name;
81 82
	struct hostent		*he;
	struct in_addr		serverip;
Mike Hibler's avatar
Mike Hibler committed
83
	char			buf[MYBUFSIZE], *bp, *response = "";
84
	char			*bossnode = DEFAULT_BOSSNODE;
85
	int			version = CURRENT_VERSION;
86
	char			*vnodeid = NULL;
87
	int			waitfor = 0;
88
#ifdef UDP
89
	int			useudp  = 0;
Mike Hibler's avatar
Mike Hibler committed
90
#endif
91

92
	while ((ch = getopt(argc, argv, "v:s:p:un:t:")) != -1)
93 94
		switch(ch) {
		case 'p':
95 96
			portlist[0] = atoi(optarg);
			numports    = 1;
97
			break;
98 99 100
		case 's':
			bossnode = optarg;
			break;
101 102 103
		case 'n':
			vnodeid = optarg;
			break;
104 105 106
		case 'v':
			version = atoi(optarg);
			break;
107 108 109
		case 't':
			waitfor = atoi(optarg);
			break;
110
#ifdef UDP
111 112 113 114
		case 'u':
			useudp = 1;
			break;
#endif
115 116 117 118 119
		default:
			usage();
		}

	argc -= optind;
120
	if (argc < 1 || argc > 5) {
121
		usage();
122
	}
123
	argv += optind;
124

125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
	/*
	 * How do we find our bossnode?
	 *
	 * 1. Command line.
	 * 2. Compiled in.
	 * 3. /usr/local/etc/bossnode
	 * 4. nameserver goo below.
	 */
	if (!bossnode) {
		FILE	*fp;
		
		if ((fp = fopen(BOSSNODEFILE, "r")) != NULL) {
			if (fgets(buf, sizeof(buf), fp)) {
				if ((bp = strchr(buf, '\n')))
					*bp = (char) NULL;
				bossnode = strdup(buf);
			}
			fclose(fp);
		}
	}
145 146
	if (!bossnode)
		bossnode = getbossnode();
147 148 149 150 151 152 153 154
	he = gethostbyname(bossnode);
	if (he)
		memcpy((char *)&serverip, he->h_addr, he->h_length);
	else {
		fprintf(stderr, "gethostbyname(%s) failed\n", bossnode); 
		exit(1);
	}

155 156 157 158
	if (waitfor) {
		alarm(waitfor);
	}

159 160 161 162 163 164 165 166
	/*
	 * Handle built-in "bossinfo" command
	 */
	if (strcmp(argv[0], "bossinfo") == 0) {
		printf("%s %s\n", bossnode, inet_ntoa(serverip));
		exit(0);
	}

167 168
#ifdef UDP
	if (useudp) {
169 170
		doudp(argc, argv, version, serverip,
		      portlist[0], vnodeid, waitfor);
171 172 173 174 175 176
		/*
		 * Never returns.
		 */
		abort();
	}
#endif
177 178 179 180 181 182
#ifdef  WITHSSL
	if (tmcd_client_sslinit()) {
		printf("SSL initialization failed!\n");
		exit(1);
	}
#endif
183
	while (1) {
184 185 186 187 188 189 190
		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);
			}
191

192 193 194 195
			/* Create name. */
			name.sin_family = AF_INET;
			name.sin_addr   = serverip;
			name.sin_port   = htons(portlist[n]);
196

197 198 199 200 201 202 203 204 205
			if (CONNECT(sock, (struct sockaddr *) &name,
				    sizeof(name)) == 0) {
				goto foundit;
			}
			if (errno != ECONNREFUSED) {
				perror("connecting stream socket");
				CLOSE(sock);
				exit(1);
			}
206
			CLOSE(sock);
207
		}
208 209 210
		fprintf(stderr,
			"Connection to TMCD refused. Waiting a bit ...\n");
		sleep(10);
211
	}
212
 foundit:
213 214 215 216 217

	data = 1;
	if (setsockopt(sock, SOL_SOCKET,
		       SO_KEEPALIVE, &data, sizeof(data)) < 0) {
		perror("setsockopt SO_KEEPALIVE");
218
		goto bad;
219
	}
220 221 222 223

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

224 225 226 227 228
	/* Tack on vnodeid */
	if (vnodeid) {
		sprintf(&buf[strlen(buf)], "VNODEID=%s ", vnodeid);
	}

229 230 231 232
	/*
	 * Since we've gone through a getopt() pass, argv[0] is now the
	 * first argument
	 */
233 234 235 236 237
	n = strlen(buf);
	while (argc && n < sizeof(buf)) {
		n += snprintf(&buf[n], sizeof(buf) - n, "%s ", argv[0]);
		argc--;
		argv++;
238
	}
239
	if (n >= sizeof(buf)) {
Mike Hibler's avatar
Mike Hibler committed
240
		fprintf(stderr, "Command too large!\n");
241
		goto bad;
242 243 244 245 246 247 248
	}

	/*
	 * Write the command to the socket and wait for the response
	 */
	bp = buf;
	while (n) {
249
		if ((cc = WRITE(sock, bp, n)) <= 0) {
250 251
			if (cc < 0) {
				perror("Writing to socket:");
252
				goto bad;
253 254
			}
			fprintf(stderr, "write aborted");
255
			goto bad;
256 257 258 259 260 261
		}
		bp += cc;
		n  -= cc;
	}

	while (1) {
262
		if ((cc = READ(sock, buf, sizeof(buf))) <= 0) {
263 264
			if (cc < 0) {
				perror("Reading from socket:");
265
				goto bad;
266 267 268 269 270 271 272 273 274 275 276 277
			}
			break;
		}
		buf[cc] = '\0';
		bp = (char *) malloc(strlen(response) + cc + 1);
		assert(bp);
		strcpy(bp, response);
		strcat(bp, buf);
		response = bp;
	}
	printf("%s", response);

278
	CLOSE(sock);
279
	exit(0);
280 281 282
 bad:
	CLOSE(sock);
	exit(1);
283 284 285 286 287 288 289
}

void
sigcatcher(int foo)
{
}

290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310
#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
}

311
#ifdef UDP
Mike Hibler's avatar
Mike Hibler committed
312 313 314 315
/*
 * Not very robust, send a single request, read a single reply. 
 */
void
316
doudp(int argc, char **argv,
317 318
      int vers, struct in_addr serverip, int portnum, char *vnodeid,
      int waitfor)
Mike Hibler's avatar
Mike Hibler committed
319 320 321
{
	int			sock, length, n, cc;
	struct sockaddr_in	name, client;
Mike Hibler's avatar
Mike Hibler committed
322
	char			buf[MYBUFSIZE], *bp, *response = "";
Mike Hibler's avatar
Mike Hibler committed
323 324 325 326 327 328 329 330 331 332 333

	/* 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;
334
	name.sin_port = htons(portnum);
Mike Hibler's avatar
Mike Hibler committed
335

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

339 340 341 342 343
	/* Tack on vnodeid */
	if (vnodeid) {
		sprintf(&buf[strlen(buf)], "VNODEID=%s ", vnodeid);
	}

344 345 346 347
	/*
	 * Since we've gone through a getopt() pass, argv[0] is now the
	 * first argument
	 */
348 349 350 351 352
	n = strlen(buf);
	while (argc && n < sizeof(buf)) {
		n += snprintf(&buf[n], sizeof(buf) - n, "%s ", argv[0]);
		argc--;
		argv++;
353
	}
Mike Hibler's avatar
Mike Hibler committed
354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373
	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);
374

Mike Hibler's avatar
Mike Hibler committed
375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390
	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