tmcc.c 7.07 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
void		sigcatcher(int foo);
44
char		*getbossnode(void);
45
#ifdef UDP
46
void		doudp(int, char **, int, struct in_addr, int, char *, int);
47 48
#endif

49
char *usagestr = 
50
 "usage: tmcc [-u] [-v versnum] [-p #] [-s server] <command>\n"
51
 " -s server	   Specify a tmcd server to connect to\n"
52
 " -p portnum	   Specify a port number to connect to\n"
53
 " -v versnum	   Specify a version number for tmcd\n"
54
 " -n vnodeid	   Specify the vnodeid\n"
55
 " -u		   Use UDP instead of TCP\n"
56
 " -t timeout	   Timeout waiting for the controller.\n"
57 58 59 60 61 62 63 64 65 66
 "\n";

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


Mike Hibler's avatar
Mike Hibler committed
67
int
68 69
main(int argc, char **argv)
{
70
	int			sock, data, n, cc, ch, portnum;
Mike Hibler's avatar
Mike Hibler committed
71
	struct sockaddr_in	name;
72 73
	struct hostent		*he;
	struct in_addr		serverip;
Mike Hibler's avatar
Mike Hibler committed
74
	char			buf[MYBUFSIZE], *bp, *response = "";
75
	char			*bossnode = DEFAULT_BOSSNODE;
76
	int			version = CURRENT_VERSION;
77
	char			*vnodeid = NULL;
78
	int			waitfor = 0;
79
#ifdef UDP
80
	int			useudp  = 0;
Mike Hibler's avatar
Mike Hibler committed
81
#endif
82

83 84
	portnum = TBSERVER_PORT;

85
	while ((ch = getopt(argc, argv, "v:s:p:un:t:")) != -1)
86 87 88 89
		switch(ch) {
		case 'p':
			portnum = atoi(optarg);
			break;
90 91 92
		case 's':
			bossnode = optarg;
			break;
93 94 95
		case 'n':
			vnodeid = optarg;
			break;
96 97 98
		case 'v':
			version = atoi(optarg);
			break;
99 100 101
		case 't':
			waitfor = atoi(optarg);
			break;
102
#ifdef UDP
103 104 105 106
		case 'u':
			useudp = 1;
			break;
#endif
107 108 109 110 111
		default:
			usage();
		}

	argc -= optind;
112
	if (argc < 1 || argc > 5) {
113
		usage();
114
	}
115
	argv += optind;
116

117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
	/*
	 * 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);
		}
	}
137 138
	if (!bossnode)
		bossnode = getbossnode();
139 140 141 142 143 144 145 146
	he = gethostbyname(bossnode);
	if (he)
		memcpy((char *)&serverip, he->h_addr, he->h_length);
	else {
		fprintf(stderr, "gethostbyname(%s) failed\n", bossnode); 
		exit(1);
	}

147 148 149 150
	if (waitfor) {
		alarm(waitfor);
	}

151 152 153 154 155 156 157 158
	/*
	 * Handle built-in "bossinfo" command
	 */
	if (strcmp(argv[0], "bossinfo") == 0) {
		printf("%s %s\n", bossnode, inet_ntoa(serverip));
		exit(0);
	}

159 160
#ifdef UDP
	if (useudp) {
161 162
		doudp(argc, argv,
		      version, serverip, portnum, vnodeid, waitfor);
163 164 165 166 167 168
		/*
		 * Never returns.
		 */
		abort();
	}
#endif
169 170 171 172 173 174
#ifdef  WITHSSL
	if (tmcd_client_sslinit()) {
		printf("SSL initialization failed!\n");
		exit(1);
	}
#endif
175 176 177 178 179 180 181 182 183 184
	while (1) {
		/* Create socket from which to read. */
		sock = socket(AF_INET, SOCK_STREAM, 0);
		if (sock < 0) {
			perror("creating stream socket:");
			exit(1);
		}

		/* Create name. */
		name.sin_family = AF_INET;
185
		name.sin_addr   = serverip;
186
		name.sin_port = htons(portnum);
187

188
		if (CONNECT(sock,
189 190 191 192 193 194 195 196 197 198
			    (struct sockaddr *) &name, sizeof(name)) == 0) {
			break;
		}
		if (errno == ECONNREFUSED) {
			fprintf(stderr, "Connection to TMCD refused "
				"Sleeping a little while ...\n");
			sleep(10);
		}
		else {
			perror("connecting stream socket");
199
			CLOSE(sock);
200 201
			exit(1);
		}
202
		CLOSE(sock);
203 204 205 206 207 208
	}

	data = 1;
	if (setsockopt(sock, SOL_SOCKET,
		       SO_KEEPALIVE, &data, sizeof(data)) < 0) {
		perror("setsockopt SO_KEEPALIVE");
209
		goto bad;
210
	}
211 212 213 214

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

215 216 217 218 219
	/* Tack on vnodeid */
	if (vnodeid) {
		sprintf(&buf[strlen(buf)], "VNODEID=%s ", vnodeid);
	}

220 221 222 223
	/*
	 * Since we've gone through a getopt() pass, argv[0] is now the
	 * first argument
	 */
224 225 226 227 228
	n = strlen(buf);
	while (argc && n < sizeof(buf)) {
		n += snprintf(&buf[n], sizeof(buf) - n, "%s ", argv[0]);
		argc--;
		argv++;
229
	}
230
	if (n >= sizeof(buf)) {
Mike Hibler's avatar
Mike Hibler committed
231
		fprintf(stderr, "Command too large!\n");
232
		goto bad;
233 234 235 236 237 238 239
	}

	/*
	 * Write the command to the socket and wait for the response
	 */
	bp = buf;
	while (n) {
240
		if ((cc = WRITE(sock, bp, n)) <= 0) {
241 242
			if (cc < 0) {
				perror("Writing to socket:");
243
				goto bad;
244 245
			}
			fprintf(stderr, "write aborted");
246
			goto bad;
247 248 249 250 251 252
		}
		bp += cc;
		n  -= cc;
	}

	while (1) {
253
		if ((cc = READ(sock, buf, sizeof(buf))) <= 0) {
254 255
			if (cc < 0) {
				perror("Reading from socket:");
256
				goto bad;
257 258 259 260 261 262 263 264 265 266 267 268
			}
			break;
		}
		buf[cc] = '\0';
		bp = (char *) malloc(strlen(response) + cc + 1);
		assert(bp);
		strcpy(bp, response);
		strcat(bp, buf);
		response = bp;
	}
	printf("%s", response);

269
	CLOSE(sock);
270
	exit(0);
271 272 273
 bad:
	CLOSE(sock);
	exit(1);
274 275 276 277 278 279 280
}

void
sigcatcher(int foo)
{
}

281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301
#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
}

302
#ifdef UDP
Mike Hibler's avatar
Mike Hibler committed
303 304 305 306
/*
 * Not very robust, send a single request, read a single reply. 
 */
void
307
doudp(int argc, char **argv,
308 309
      int vers, struct in_addr serverip, int portnum, char *vnodeid,
      int waitfor)
Mike Hibler's avatar
Mike Hibler committed
310 311 312
{
	int			sock, length, n, cc;
	struct sockaddr_in	name, client;
Mike Hibler's avatar
Mike Hibler committed
313
	char			buf[MYBUFSIZE], *bp, *response = "";
Mike Hibler's avatar
Mike Hibler committed
314 315 316 317 318 319 320 321 322 323 324

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

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

330 331 332 333 334
	/* Tack on vnodeid */
	if (vnodeid) {
		sprintf(&buf[strlen(buf)], "VNODEID=%s ", vnodeid);
	}

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

Mike Hibler's avatar
Mike Hibler committed
366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381
	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