blob: 2d7095bb48f3b892a440ae99c89844adbfcc7fd8 [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,
29 FATAL,
30};
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);
168 }
169 LOG(FATAL, "Unknown network device.");
170 return NULL;
171}
172
brians2fdfc072013-02-26 05:35:15 +0000173namespace {
174const char *DoGetRootDirectory() {
175#ifdef __VXWORKS__
176 return "/";
177#else
178 ssize_t size = 0;
179 char *r = NULL;
180 while (true) {
181 if (r != NULL) delete r;
182 size += 256;
183 r = new char[size];
184
185 ssize_t ret = readlink("/proc/self/exe", r, size);
186 if (ret < 0) {
187 if (ret != -1) {
188 LOG(WARNING, "it returned %zd, not -1\n", ret);
189 }
190 LOG(FATAL, "readlink(\"/proc/self/exe\", %p, %zu) failed with %d: %s\n",
191 r, size, errno, strerror(errno));
192 }
193 if (ret < size) {
194 void *last_slash = memrchr(r, '/', size);
195 if (last_slash == NULL) {
196 r[ret] = '\0';
197 LOG(FATAL, "couldn't find a '/' in \"%s\"\n", r);
198 }
199 *static_cast<char *>(last_slash) = '\0';
200 LOG(INFO, "got a root dir of \"%s\"\n", r);
201 return r;
202 }
203 }
204#endif
205}
206
207const char *DoGetLoggingDirectory() {
208 static const char kSuffix[] = "/../../tmp/robot_logs";
209 const char *root = GetRootDirectory();
210 char *r = new char[strlen(root) + sizeof(kSuffix)];
211 strcpy(r, root);
212 strcat(r, kSuffix);
213 return r;
214}
215} // namespace
216
217const char *GetRootDirectory() {
218 static aos::Once<const char> once(DoGetRootDirectory);
219 return once.Get();
220}
221
222const char *GetLoggingDirectory() {
223 static aos::Once<const char> once(DoGetLoggingDirectory);
224 return once.Get();
225}
226
brians343bc112013-02-10 01:53:46 +0000227} // namespace configuration
228} // namespace aos