tmcc.c 6.9 KB
Newer Older
1 2 3 4 5 6 7 8 9
#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
10 11
#include <stdlib.h>
#include <string.h>
12 13 14
#include <sys/time.h>
#include <time.h>
#include <assert.h>
15 16 17 18
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
19
#include "decls.h"
20
#include "config.h"
21
#include "ssl.h"
22

23
#undef BOSSNODE
24 25 26 27 28
#ifdef BOSSNODE
#define DEFAULT_BOSSNODE BOSSNODE
#else
#define DEFAULT_BOSSNODE NULL
#endif
29 30 31
#ifndef BOSSNODEFILE
#define BOSSNODEFILE	 "/usr/local/etc/testbed/bossnode"
#endif
32

33
void		sigcatcher(int foo);
34
char		*getbossnode(void);
35
#ifdef UDP
36
void		doudp(int, char **, int, struct in_addr, int, char *, int);
37 38
#endif

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

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


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

73 74
	portnum = TBSERVER_PORT;

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

	argc -= optind;
102
	if (argc < 1 || argc > 5) {
103
		usage();
104
	}
105
	argv += optind;
106

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

137 138 139 140
	if (waitfor) {
		alarm(waitfor);
	}

141 142 143 144 145 146 147 148
	/*
	 * Handle built-in "bossinfo" command
	 */
	if (strcmp(argv[0], "bossinfo") == 0) {
		printf("%s %s\n", bossnode, inet_ntoa(serverip));
		exit(0);
	}

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

178
		if (CONNECT(sock,
179 180 181 182 183 184 185 186 187 188
			    (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");
189
			CLOSE(sock);
190 191
			exit(1);
		}
192
		CLOSE(sock);
193 194 195 196 197 198
	}

	data = 1;
	if (setsockopt(sock, SOL_SOCKET,
		       SO_KEEPALIVE, &data, sizeof(data)) < 0) {
		perror("setsockopt SO_KEEPALIVE");
199
		goto bad;
200
	}
201 202 203 204

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

205 206 207 208 209
	/* Tack on vnodeid */
	if (vnodeid) {
		sprintf(&buf[strlen(buf)], "VNODEID=%s ", vnodeid);
	}

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

	/*
	 * Write the command to the socket and wait for the response
	 */
	bp = buf;
	while (n) {
230
		if ((cc = WRITE(sock, bp, n)) <= 0) {
231 232
			if (cc < 0) {
				perror("Writing to socket:");
233
				goto bad;
234 235
			}
			fprintf(stderr, "write aborted");
236
			goto bad;
237 238 239 240 241 242
		}
		bp += cc;
		n  -= cc;
	}

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

259
	CLOSE(sock);
260
	exit(0);
261 262 263
 bad:
	CLOSE(sock);
	exit(1);
264 265 266 267 268 269 270
}

void
sigcatcher(int foo)
{
}

271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291
#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
}

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

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

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

320 321 322 323 324
	/* Tack on vnodeid */
	if (vnodeid) {
		sprintf(&buf[strlen(buf)], "VNODEID=%s ", vnodeid);
	}

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

Mike Hibler's avatar
Mike Hibler committed
356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371
	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