summaryrefslogtreecommitdiffstats
path: root/btime.c
diff options
context:
space:
mode:
Diffstat (limited to 'btime.c')
-rw-r--r--btime.c111
1 files changed, 111 insertions, 0 deletions
diff --git a/btime.c b/btime.c
new file mode 100644
index 0000000..f22c08b
--- /dev/null
+++ b/btime.c
@@ -0,0 +1,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;
+}