summaryrefslogtreecommitdiffstats
path: root/btime.c
blob: f22c08b0168fbe6845f2fdfbee18033b5c7d4f9f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include "btime_int.h"

/*
 * btime --
 * 
 *	Return the boot time of a remote host if that host is running the
 *	btimed deamon.
 *
 * Returns:
 *	btime, or 0 on failure.
 */

unsigned int
btime(const char *host)
{
	int sd;
	char msg[BTIME_MSGLEN];
	struct sockaddr_in serv_addr;
	struct sockaddr_in my_addr;
	int serv_addr_len;
	struct hostent *hostent;
	in_addr_t inaddr;
	unsigned int btime;
	ssize_t nbytes;	
	int retry;

	if ((sd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
		fprintf(stderr, "Could not create socket: %s\n", 
		        strerror(errno));
		return 0;
	}

	memset(&serv_addr, 0, sizeof serv_addr);
	serv_addr.sin_family = AF_INET;
	serv_addr.sin_port = htons(BTIME_PORT);

	if ((inaddr = inet_addr(host)) != INADDR_NONE) {
		memcpy(&serv_addr.sin_addr, &inaddr, sizeof inaddr);
	} else {
		if ((hostent = gethostbyname(host)) == NULL) {
			return 0;
		}

		memcpy(&serv_addr.sin_addr, hostent->h_addr, hostent->h_length);
	}

	memset(&my_addr, 0, sizeof my_addr);
	my_addr.sin_family = AF_INET;
	my_addr.sin_addr.s_addr = htonl(INADDR_ANY);
	my_addr.sin_port = htons(0);
	if (bind(sd, (struct sockaddr *)&my_addr, sizeof my_addr) < 0) {
		fprintf(stderr, "Could not bind to local address: %s\n", 
		        strerror(errno));
		return 0;
	}

	memset(msg, 0, BTIME_MSGLEN);
	for (retry = 0; retry < MAX_RETRY; retry++) {
		serv_addr_len = sizeof serv_addr;
		if ((nbytes = sendto(sd, &msg, BTIME_MSGLEN, MSG_DONTWAIT,
	       	 (struct sockaddr *)&serv_addr, serv_addr_len)) < 0) {
			if (errno == EAGAIN) {
				usleep(retry * 100);
			} else {
				/* Non EAGAIN error... */
				break;
			}
		} else {
			break;
		}
	}
	

	memset(msg, 0, BTIME_MSGLEN);
	for (retry = 0; retry < MAX_RETRY; retry++) {
		serv_addr_len = sizeof serv_addr;
		if ((nbytes = recvfrom(sd, &msg, BTIME_MSGLEN, MSG_DONTWAIT, 
	         (struct sockaddr *)&serv_addr, &serv_addr_len)) < 0) {
			if (errno == EAGAIN) {
				usleep(retry * 100);
			} else {
				/* Non EAGAIN error... */
				break;
			}
		} else {
			break;
		}
	}

	if (nbytes == 0) {
		btime = 0;
	} else {
		btime = strtoul(msg, (char **)NULL, 10);
	}

	close(sd);

	return btime;
}