blob: edf5212ffcf7eb3a40c8ec2b5934bb7084942ac8 [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
Brian Silverman8efe23e2013-07-07 23:31:37 -070017#include <unistd.h>
brians343bc112013-02-10 01:53:46 +000018
brians343bc112013-02-10 01:53:46 +000019#ifndef __VXWORKS__
Brian Silvermane8598722013-04-10 17:09:14 -070020#include "aos/common/logging/logging.h"
brians343bc112013-02-10 01:53:46 +000021#include "aos/common/unique_malloc_ptr.h"
Brian Silvermane8598722013-04-10 17:09:14 -070022#else
23#include <taskLib.h>
24#undef ERROR
25enum LogLevel {
26 DEBUG,
27 INFO,
28 WARNING,
29 ERROR = -1,
Brian Silverman3d4b8972013-05-15 20:35:33 -070030 FATAL = 4,
Brian Silvermane8598722013-04-10 17:09:14 -070031};
32#define LOG(level, format, args...) do { \
33 fprintf(stderr, #level ": " format, ##args); \
34 if (level == FATAL) { \
35 printf("I am 0x%x suspending for debugging purposes.\n", taskIdSelf()); \
36 printf("\t`tt 0x%x` will give you a stack trace.\n", taskIdSelf()); \
37 fputs("\t`lkAddr` will reverse lookup a symbol for you.\n", stdout); \
38 fputs("\t`dbgHelp` and `help` have some useful commands in them.\n", stdout); \
39 taskSuspend(0); \
40 printf("You weren't supposed to resume 0x%x!!. Going to really die now.\n", \
41 taskIdSelf()); \
42 abort(); \
43 } \
44} while (0)
brians343bc112013-02-10 01:53:46 +000045#endif
brians2fdfc072013-02-26 05:35:15 +000046#include "aos/common/once.h"
brians343bc112013-02-10 01:53:46 +000047
48namespace aos {
49namespace configuration {
50
51namespace {
52
53#ifdef __VXWORKS__
54const size_t kMaxAddrLength = INET_ADDR_LEN;
55#else
56// Including the terminating '\0'.
57const size_t kMaxAddrLength = 18;
58#endif
59// Returns whether or not the current IP address is in ownIPAddress.
60bool GetOwnIPAddress();
61
62#ifdef __VXWORKS__
63// vxworks doesn't have real asprintf.......
64static inline int aos_asprintf(size_t max_len, char **strp, const char *fmt, ...) {
65 *strp = static_cast<char *>(malloc(max_len));
66 if (*strp == NULL) {
67 return -1;
68 }
69 va_list argp;
70 va_start(argp, fmt);
71 const int r = vsnprintf(*strp, max_len, fmt, argp);
72 va_end(argp);
73 if (static_cast<uintmax_t>(r) >= max_len) {
74 errno = EOVERFLOW;
75 free(*strp);
76 return -1;
77 }
78 return r;
79}
80
81// 4-slot cRIO: motfec0
82// 8-slot cRIO port 1: fec0
83// ifShow will show you all of the ones on a cRIO
84const char *const kCrioNetInterfaces[] = {"fec0", "motfec0"};
85bool GetOwnIPAddress(char *buffer, size_t bufferSize) {
86 if (bufferSize < INET_ADDR_LEN) {
87 LOG(ERROR, "bufferSize(%jd) isn't >= INET_ADDR_LEN(%jd)\n",
88 static_cast<intmax_t>(bufferSize),
89 static_cast<intmax_t>(INET_ADDR_LEN));
90 return false;
91 }
92 for (size_t i = 0;
93 i < sizeof(kCrioNetInterfaces) / sizeof(kCrioNetInterfaces[0]); ++i) {
94 if (ifAddrGet(const_cast<char *>(kCrioNetInterfaces[i]), buffer) != OK) {
95 LOG(DEBUG, "ifAddrGet(\"%s\", %p) failed with %d: %s\n",
96 kCrioNetInterfaces[i], buffer, errno, strerror(errno));
97 } else {
98 return true;
99 }
100 }
101 LOG(ERROR, "couldn't get the cRIO's IP address\n");
102 return false;
103}
104#else
105static inline int aos_asprintf(size_t, char **strp, const char *fmt, ...) {
106 va_list argp;
107 va_start(argp, fmt);
108 const int r = vasprintf(strp, fmt, argp);
109 va_end(argp);
110 return r;
111}
112
113const char *const kAtomNetInterface = "eth0";
114bool GetOwnIPAddress(char *buffer, size_t bufferSize) {
115 ifaddrs *addrs;
116 if (getifaddrs(&addrs) != 0) {
117 LOG(ERROR, "getifaddrs(%p) failed with %d: %s\n", &addrs,
118 errno, strerror(errno));
119 return false;
120 }
121 // Smart pointers don't work very well for iterating through a linked list,
122 // but it does do a very nice job of making sure that addrs gets freed.
123 unique_c_ptr<ifaddrs, freeifaddrs> addrs_deleter(addrs);
124
125 for (; addrs != NULL; addrs = addrs->ifa_next) {
126 if (addrs->ifa_addr->sa_family == AF_INET) {
127 if (strcmp(kAtomNetInterface, addrs->ifa_name) == 0) {
128 const char *ipAddress = inet_ntoa(
129 reinterpret_cast<sockaddr_in *>(addrs->ifa_addr)->sin_addr);
130 strncpy(buffer, ipAddress, bufferSize);
131 return true;
132 }
133 }
134 }
135 LOG(ERROR, "couldn't find an AF_INET interface named \"%s\"\n",
136 kAtomNetInterface);
137 return false;
138}
139#endif
140
141const char *RawIPAddress(uint8_t last_part) {
142 char ownIPAddress[kMaxAddrLength];
143 if (!GetOwnIPAddress(ownIPAddress, sizeof(ownIPAddress))) {
144 return NULL;
145 }
146 char *last_dot = strrchr(ownIPAddress, '.');
147 if (last_dot == NULL) {
148 LOG(ERROR, "can't find any '.'s in \"%s\"\n", ownIPAddress);
149 return NULL;
150 }
151 *last_dot = '\0';
152
153 char *r;
154 if (aos_asprintf(kMaxAddrLength, &r, "%s.%hhu",
155 ownIPAddress, last_part) == -1) {
156 return NULL;
157 }
158 return r;
159}
160
161} // namespace
162
163const char *GetIPAddress(NetworkDevice device) {
164 switch (device) {
165 case NetworkDevice::kAtom:
166 return RawIPAddress(179);
167 case NetworkDevice::kCRIO:
168 return RawIPAddress(2);
Brian Silvermane1514fc2013-04-13 14:57:35 -0700169 case NetworkDevice::kSelf:
170 char *ret = static_cast<char *>(malloc(kMaxAddrLength));
171 if (!GetOwnIPAddress(ret, kMaxAddrLength)) return NULL;
172 return ret;
brians343bc112013-02-10 01:53:46 +0000173 }
174 LOG(FATAL, "Unknown network device.");
175 return NULL;
176}
177
brians2fdfc072013-02-26 05:35:15 +0000178namespace {
179const char *DoGetRootDirectory() {
180#ifdef __VXWORKS__
181 return "/";
182#else
183 ssize_t size = 0;
184 char *r = NULL;
185 while (true) {
186 if (r != NULL) delete r;
187 size += 256;
188 r = new char[size];
189
190 ssize_t ret = readlink("/proc/self/exe", r, size);
191 if (ret < 0) {
192 if (ret != -1) {
193 LOG(WARNING, "it returned %zd, not -1\n", ret);
194 }
195 LOG(FATAL, "readlink(\"/proc/self/exe\", %p, %zu) failed with %d: %s\n",
196 r, size, errno, strerror(errno));
197 }
198 if (ret < size) {
199 void *last_slash = memrchr(r, '/', size);
200 if (last_slash == NULL) {
201 r[ret] = '\0';
202 LOG(FATAL, "couldn't find a '/' in \"%s\"\n", r);
203 }
204 *static_cast<char *>(last_slash) = '\0';
205 LOG(INFO, "got a root dir of \"%s\"\n", r);
206 return r;
207 }
208 }
209#endif
210}
211
212const char *DoGetLoggingDirectory() {
213 static const char kSuffix[] = "/../../tmp/robot_logs";
214 const char *root = GetRootDirectory();
215 char *r = new char[strlen(root) + sizeof(kSuffix)];
216 strcpy(r, root);
217 strcat(r, kSuffix);
218 return r;
219}
220} // namespace
221
222const char *GetRootDirectory() {
223 static aos::Once<const char> once(DoGetRootDirectory);
224 return once.Get();
225}
226
227const char *GetLoggingDirectory() {
228 static aos::Once<const char> once(DoGetLoggingDirectory);
229 return once.Get();
230}
231
brians343bc112013-02-10 01:53:46 +0000232} // namespace configuration
233} // namespace aos