tmcc.c 7.02 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 "config.h"
27
#include "ssl.h"
28

29
#undef BOSSNODE
30 31 32 33 34
#ifdef BOSSNODE
#define DEFAULT_BOSSNODE BOSSNODE
#else
#define DEFAULT_BOSSNODE NULL
#endif
35 36 37
#ifndef BOSSNODEFILE
#define BOSSNODEFILE	 "/usr/local/etc/testbed/bossnode"
#endif
38

39
void		sigcatcher(int foo);
40
char		*getbossnode(void);
41
#ifdef UDP
42
void		doudp(int, char **, int, struct in_addr, int, char *, int);
43 44
#endif

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

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


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

79 80
	portnum = TBSERVER_PORT;

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

	argc -= optind;
108
	if (argc < 1 || argc > 5) {
109
		usage();
110
	}
111
	argv += optind;
112

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

143 144 145 146
	if (waitfor) {
		alarm(waitfor);
	}

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

155 156
#ifdef UDP
	if (useudp) {
157 158
		doudp(argc, argv,
		      version, serverip, portnum, vnodeid, waitfor);
159 160 161 162 163 164
		/*
		 * Never returns.
		 */
		abort();
	}
#endif
165 166 167 168 169 170
#ifdef  WITHSSL
	if (tmcd_client_sslinit()) {
		printf("SSL initialization failed!\n");
		exit(1);
	}
#endif
171 172 173 174 175 176 177 178 179 180
	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;
181
		name.sin_addr   = serverip;
182
		name.sin_port = htons(portnum);
183

184
		if (CONNECT(sock,
185 186 187 188 189 190 191 192 193 194
			    (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");
195
			CLOSE(sock);
196 197
			exit(1);
		}
198
		CLOSE(sock);
199 200 201 202 203 204
	}

	data = 1;
	if (setsockopt(sock, SOL_SOCKET,
		       SO_KEEPALIVE, &data, sizeof(data)) < 0) {
		perror("setsockopt SO_KEEPALIVE");
205
		goto bad;
206
	}
207 208 209 210

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

211 212 213 214 215
	/* Tack on vnodeid */
	if (vnodeid) {
		sprintf(&buf[strlen(buf)], "VNODEID=%s ", vnodeid);
	}

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

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

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

265
	CLOSE(sock);
266
	exit(0);
267 268 269
 bad:
	CLOSE(sock);
	exit(1);
270 271 272 273 274 275 276
}

void
sigcatcher(int foo)
{
}

277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297
#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
}

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

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

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

326 327 328 329 330
	/* Tack on vnodeid */
	if (vnodeid) {
		sprintf(&buf[strlen(buf)], "VNODEID=%s ", vnodeid);
	}

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

Mike Hibler's avatar
Mike Hibler committed
362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377
	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