blob: 90de05df2d8c51dd19204be6692b8b06803b0b90 [file] [log] [blame]
brians343bc112013-02-10 01:53:46 +00001#include "Configuration.h"
2
3#include <stdio.h>
4#include <string.h>
5#include <errno.h>
6#include <stdlib.h>
7#include <stdarg.h>
8#include <sys/types.h>
9#include <netinet/in.h>
10#include <arpa/inet.h>
11#ifdef __VXWORKS__
12#include <ifLib.h>
13#include <inetLib.h>
14#else
15#include <ifaddrs.h>
16#endif
17
18#include "aos/aos_core.h"
19#ifndef __VXWORKS__
20#include "aos/common/unique_malloc_ptr.h"
21#endif
brians2fdfc072013-02-26 05:35:15 +000022#include "aos/common/once.h"
brians343bc112013-02-10 01:53:46 +000023
24namespace aos {
25namespace configuration {
26
27namespace {
28
29#ifdef __VXWORKS__
30const size_t kMaxAddrLength = INET_ADDR_LEN;
31#else
32// Including the terminating '\0'.
33const size_t kMaxAddrLength = 18;
34#endif
35// Returns whether or not the current IP address is in ownIPAddress.
36bool GetOwnIPAddress();
37
38#ifdef __VXWORKS__
39// vxworks doesn't have real asprintf.......
40static inline int aos_asprintf(size_t max_len, char **strp, const char *fmt, ...) {
41 *strp = static_cast<char *>(malloc(max_len));
42 if (*strp == NULL) {
43 return -1;
44 }
45 va_list argp;
46 va_start(argp, fmt);
47 const int r = vsnprintf(*strp, max_len, fmt, argp);
48 va_end(argp);
49 if (static_cast<uintmax_t>(r) >= max_len) {
50 errno = EOVERFLOW;
51 free(*strp);
52 return -1;
53 }
54 return r;
55}
56
57// 4-slot cRIO: motfec0
58// 8-slot cRIO port 1: fec0
59// ifShow will show you all of the ones on a cRIO
60const char *const kCrioNetInterfaces[] = {"fec0", "motfec0"};
61bool GetOwnIPAddress(char *buffer, size_t bufferSize) {
62 if (bufferSize < INET_ADDR_LEN) {
63 LOG(ERROR, "bufferSize(%jd) isn't >= INET_ADDR_LEN(%jd)\n",
64 static_cast<intmax_t>(bufferSize),
65 static_cast<intmax_t>(INET_ADDR_LEN));
66 return false;
67 }
68 for (size_t i = 0;
69 i < sizeof(kCrioNetInterfaces) / sizeof(kCrioNetInterfaces[0]); ++i) {
70 if (ifAddrGet(const_cast<char *>(kCrioNetInterfaces[i]), buffer) != OK) {
71 LOG(DEBUG, "ifAddrGet(\"%s\", %p) failed with %d: %s\n",
72 kCrioNetInterfaces[i], buffer, errno, strerror(errno));
73 } else {
74 return true;
75 }
76 }
77 LOG(ERROR, "couldn't get the cRIO's IP address\n");
78 return false;
79}
80#else
81static inline int aos_asprintf(size_t, char **strp, const char *fmt, ...) {
82 va_list argp;
83 va_start(argp, fmt);
84 const int r = vasprintf(strp, fmt, argp);
85 va_end(argp);
86 return r;
87}
88
89const char *const kAtomNetInterface = "eth0";
90bool GetOwnIPAddress(char *buffer, size_t bufferSize) {
91 ifaddrs *addrs;
92 if (getifaddrs(&addrs) != 0) {
93 LOG(ERROR, "getifaddrs(%p) failed with %d: %s\n", &addrs,
94 errno, strerror(errno));
95 return false;
96 }
97 // Smart pointers don't work very well for iterating through a linked list,
98 // but it does do a very nice job of making sure that addrs gets freed.
99 unique_c_ptr<ifaddrs, freeifaddrs> addrs_deleter(addrs);
100
101 for (; addrs != NULL; addrs = addrs->ifa_next) {
102 if (addrs->ifa_addr->sa_family == AF_INET) {
103 if (strcmp(kAtomNetInterface, addrs->ifa_name) == 0) {
104 const char *ipAddress = inet_ntoa(
105 reinterpret_cast<sockaddr_in *>(addrs->ifa_addr)->sin_addr);
106 strncpy(buffer, ipAddress, bufferSize);
107 return true;
108 }
109 }
110 }
111 LOG(ERROR, "couldn't find an AF_INET interface named \"%s\"\n",
112 kAtomNetInterface);
113 return false;
114}
115#endif
116
117const char *RawIPAddress(uint8_t last_part) {
118 char ownIPAddress[kMaxAddrLength];
119 if (!GetOwnIPAddress(ownIPAddress, sizeof(ownIPAddress))) {
120 return NULL;
121 }
122 char *last_dot = strrchr(ownIPAddress, '.');
123 if (last_dot == NULL) {
124 LOG(ERROR, "can't find any '.'s in \"%s\"\n", ownIPAddress);
125 return NULL;
126 }
127 *last_dot = '\0';
128
129 char *r;
130 if (aos_asprintf(kMaxAddrLength, &r, "%s.%hhu",
131 ownIPAddress, last_part) == -1) {
132 return NULL;
133 }
134 return r;
135}
136
137} // namespace
138
139const char *GetIPAddress(NetworkDevice device) {
140 switch (device) {
141 case NetworkDevice::kAtom:
142 return RawIPAddress(179);
143 case NetworkDevice::kCRIO:
144 return RawIPAddress(2);
145 }
146 LOG(FATAL, "Unknown network device.");
147 return NULL;
148}
149
brians2fdfc072013-02-26 05:35:15 +0000150namespace {
151const char *DoGetRootDirectory() {
152#ifdef __VXWORKS__
153 return "/";
154#else
155 ssize_t size = 0;
156 char *r = NULL;
157 while (true) {
158 if (r != NULL) delete r;
159 size += 256;
160 r = new char[size];
161
162 ssize_t ret = readlink("/proc/self/exe", r, size);
163 if (ret < 0) {
164 if (ret != -1) {
165 LOG(WARNING, "it returned %zd, not -1\n", ret);
166 }
167 LOG(FATAL, "readlink(\"/proc/self/exe\", %p, %zu) failed with %d: %s\n",
168 r, size, errno, strerror(errno));
169 }
170 if (ret < size) {
171 void *last_slash = memrchr(r, '/', size);
172 if (last_slash == NULL) {
173 r[ret] = '\0';
174 LOG(FATAL, "couldn't find a '/' in \"%s\"\n", r);
175 }
176 *static_cast<char *>(last_slash) = '\0';
177 LOG(INFO, "got a root dir of \"%s\"\n", r);
178 return r;
179 }
180 }
181#endif
182}
183
184const char *DoGetLoggingDirectory() {
185 static const char kSuffix[] = "/../../tmp/robot_logs";
186 const char *root = GetRootDirectory();
187 char *r = new char[strlen(root) + sizeof(kSuffix)];
188 strcpy(r, root);
189 strcat(r, kSuffix);
190 return r;
191}
192} // namespace
193
194const char *GetRootDirectory() {
195 static aos::Once<const char> once(DoGetRootDirectory);
196 return once.Get();
197}
198
199const char *GetLoggingDirectory() {
200 static aos::Once<const char> once(DoGetLoggingDirectory);
201 return once.Get();
202}
203
brians343bc112013-02-10 01:53:46 +0000204} // namespace configuration
205} // namespace aos