blob: ddd7300fb92913db9609a12f6e892ff63d207969 [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);
Brian Silvermane1514fc2013-04-13 14:57:35 -0700145 case NetworkDevice::kSelf:
146 char *ret = static_cast<char *>(malloc(kMaxAddrLength));
147 if (!GetOwnIPAddress(ret, kMaxAddrLength)) return NULL;
148 return ret;
brians343bc112013-02-10 01:53:46 +0000149 }
150 LOG(FATAL, "Unknown network device.");
151 return NULL;
152}
153
brians2fdfc072013-02-26 05:35:15 +0000154namespace {
155const char *DoGetRootDirectory() {
156#ifdef __VXWORKS__
157 return "/";
158#else
159 ssize_t size = 0;
160 char *r = NULL;
161 while (true) {
162 if (r != NULL) delete r;
163 size += 256;
164 r = new char[size];
165
166 ssize_t ret = readlink("/proc/self/exe", r, size);
167 if (ret < 0) {
168 if (ret != -1) {
169 LOG(WARNING, "it returned %zd, not -1\n", ret);
170 }
171 LOG(FATAL, "readlink(\"/proc/self/exe\", %p, %zu) failed with %d: %s\n",
172 r, size, errno, strerror(errno));
173 }
174 if (ret < size) {
175 void *last_slash = memrchr(r, '/', size);
176 if (last_slash == NULL) {
177 r[ret] = '\0';
178 LOG(FATAL, "couldn't find a '/' in \"%s\"\n", r);
179 }
180 *static_cast<char *>(last_slash) = '\0';
181 LOG(INFO, "got a root dir of \"%s\"\n", r);
182 return r;
183 }
184 }
185#endif
186}
187
188const char *DoGetLoggingDirectory() {
189 static const char kSuffix[] = "/../../tmp/robot_logs";
190 const char *root = GetRootDirectory();
191 char *r = new char[strlen(root) + sizeof(kSuffix)];
192 strcpy(r, root);
193 strcat(r, kSuffix);
194 return r;
195}
196} // namespace
197
198const char *GetRootDirectory() {
199 static aos::Once<const char> once(DoGetRootDirectory);
200 return once.Get();
201}
202
203const char *GetLoggingDirectory() {
204 static aos::Once<const char> once(DoGetLoggingDirectory);
205 return once.Get();
206}
207
brians343bc112013-02-10 01:53:46 +0000208} // namespace configuration
209} // namespace aos