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