refactored the IP address handling code

It is now split up much more cleanly, has less stuff running on the
cRIO, and doesn't do as much of the stuff with string manipulation.

Before, it was kind of ridicilous how many times the code converted IP
addresses back and forth between 32-bit ints and strings to do various
manipulations and pass them around. Also, there was various junk that
the cRIO code did that it did not need to be doing.
diff --git a/aos/atom_code/atom_code.gyp b/aos/atom_code/atom_code.gyp
index 8253588..37caccd 100644
--- a/aos/atom_code/atom_code.gyp
+++ b/aos/atom_code/atom_code.gyp
@@ -12,5 +12,16 @@
         '<(AOS)/build/aos.gyp:logging',
       ],
     },
+    {
+      'target_name': 'configuration',
+      'type': 'static_library',
+      'sources': [
+        'configuration.cc',
+      ],
+      'dependencies': [
+        '<(AOS)/common/common.gyp:once',
+        '<(AOS)/build/aos.gyp:logging',
+      ],
+    },
   ],
 }
diff --git a/aos/atom_code/camera/HTTPStreamer.cpp b/aos/atom_code/camera/HTTPStreamer.cpp
index 8a896c5..5a9a405 100644
--- a/aos/atom_code/camera/HTTPStreamer.cpp
+++ b/aos/atom_code/camera/HTTPStreamer.cpp
@@ -15,7 +15,7 @@
 
 #include <vector>
 
-#include "aos/common/Configuration.h"
+#include "aos/common/network_port.h"
 #include "aos/atom_code/init.h"
 #include "aos/atom_code/camera/Buffers.h"
 #include "aos/common/logging/logging.h"
diff --git a/aos/atom_code/configuration.cc b/aos/atom_code/configuration.cc
new file mode 100644
index 0000000..a5dd4ee
--- /dev/null
+++ b/aos/atom_code/configuration.cc
@@ -0,0 +1,103 @@
+#include "aos/atom_code/configuration.h"
+
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <ifaddrs.h>
+#include <unistd.h>
+
+#include "aos/common/logging/logging.h"
+#include "aos/common/unique_malloc_ptr.h"
+#include "aos/common/once.h"
+
+namespace aos {
+namespace configuration {
+namespace {
+
+// Including the terminating '\0'.
+const size_t kMaxAddrLength = 18;
+
+const char *const kAtomNetInterface = "eth0";
+const in_addr *DoGetOwnIPAddress() {
+  ifaddrs *addrs;
+  if (getifaddrs(&addrs) != 0) {
+    LOG(FATAL, "getifaddrs(%p) failed with %d: %s\n", &addrs,
+        errno, strerror(errno));
+  }
+  // Smart pointers don't work very well for iterating through a linked list,
+  // but it does do a very nice job of making sure that addrs gets freed.
+  unique_c_ptr<ifaddrs, freeifaddrs> addrs_deleter(addrs);
+
+  for (; addrs != NULL; addrs = addrs->ifa_next) {
+    if (addrs->ifa_addr->sa_family == AF_INET) {
+      if (strcmp(kAtomNetInterface, addrs->ifa_name) == 0) {
+        static const in_addr r =
+            reinterpret_cast<sockaddr_in *>(addrs->ifa_addr)->sin_addr;
+        return &r;
+      }
+    }
+  }
+  LOG(FATAL, "couldn't find an AF_INET interface named \"%s\"\n",
+      kAtomNetInterface);
+}
+
+const char *DoGetRootDirectory() {
+  ssize_t size = 0;
+  char *r = NULL;
+  while (true) {
+    if (r != NULL) delete r;
+    size += 256;
+    r = new char[size];
+
+    ssize_t ret = readlink("/proc/self/exe", r, size);
+    if (ret < 0) {
+      if (ret != -1) {
+        LOG(WARNING, "it returned %zd, not -1\n", ret);
+      }
+      LOG(FATAL, "readlink(\"/proc/self/exe\", %p, %zu) failed with %d: %s\n",
+          r, size, errno, strerror(errno));
+    }
+    if (ret < size) {
+      void *last_slash = memrchr(r, '/', size);
+      if (last_slash == NULL) {
+        r[ret] = '\0';
+        LOG(FATAL, "couldn't find a '/' in \"%s\"\n", r);
+      }
+      *static_cast<char *>(last_slash) = '\0';
+      LOG(INFO, "got a root dir of \"%s\"\n", r);
+      return r;
+    }
+  }
+}
+
+const char *DoGetLoggingDirectory() {
+  static const char kSuffix[] = "/../../tmp/robot_logs";
+  const char *root = GetRootDirectory();
+  char *r = new char[strlen(root) + sizeof(kSuffix)];
+  strcpy(r, root);
+  strcat(r, kSuffix);
+  return r;
+}
+
+}  // namespace
+
+const char *GetRootDirectory() {
+  static aos::Once<const char> once(DoGetRootDirectory);
+  return once.Get();
+}
+
+const char *GetLoggingDirectory() {
+  static aos::Once<const char> once(DoGetLoggingDirectory);
+  return once.Get();
+}
+
+const in_addr &GetOwnIPAddress() {
+  static aos::Once<const in_addr> once(DoGetOwnIPAddress);
+  return *once.Get();
+}
+
+}  // namespace configuration
+}  // namespace aos
diff --git a/aos/atom_code/configuration.h b/aos/atom_code/configuration.h
new file mode 100644
index 0000000..a3917cc
--- /dev/null
+++ b/aos/atom_code/configuration.h
@@ -0,0 +1,31 @@
+#ifndef AOS_ATOM_CODE_CONFIGURATION_H_
+#define AOS_ATOM_CODE_CONFIGURATION_H_
+
+#include <stdint.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+namespace aos {
+
+// Holds global configuration data. All of the functions are safe to call
+// from wherever.
+namespace configuration {
+
+// Returns "our" IP address.
+const in_addr &GetOwnIPAddress();
+
+// Returns the "root directory" for this run. Under linux, this is the
+// directory where the executable is located (from /proc/self/exe)
+// The return value will always be to a static string, so no freeing is
+// necessary.
+const char *GetRootDirectory();
+// Returns the directory where logs get written. Relative to GetRootDirectory().
+// The return value will always be to a static string, so no freeing is
+// necessary.
+const char *GetLoggingDirectory();
+
+}  // namespace configuration
+}  // namespace aos
+
+#endif  // AOS_ATOM_CODE_CONFIGURATION_H_
diff --git a/aos/atom_code/core/BinaryLogReader.cpp b/aos/atom_code/core/BinaryLogReader.cpp
index e266f24..9451fd1 100644
--- a/aos/atom_code/core/BinaryLogReader.cpp
+++ b/aos/atom_code/core/BinaryLogReader.cpp
@@ -13,8 +13,8 @@
 
 #include "aos/atom_code/logging/atom_logging.h"
 #include "aos/atom_code/core/LogFileCommon.h"
-#include "aos/common/Configuration.h"
 #include "aos/atom_code/init.h"
+#include "aos/atom_code/configuration.h"
 
 namespace aos {
 namespace logging {
diff --git a/aos/atom_code/core/CRIOLogReader.cpp b/aos/atom_code/core/CRIOLogReader.cpp
index 73a5350..9c4dbd4 100644
--- a/aos/atom_code/core/CRIOLogReader.cpp
+++ b/aos/atom_code/core/CRIOLogReader.cpp
@@ -14,9 +14,9 @@
 
 #include "aos/common/logging/logging_impl.h"
 #include "aos/atom_code/logging/atom_logging.h"
-#include "aos/common/Configuration.h"
 #include "aos/common/byteorder.h"
 #include "aos/atom_code/init.h"
+#include "aos/common/network_port.h"
 
 namespace aos {
 namespace logging {
diff --git a/aos/atom_code/core/core.gyp b/aos/atom_code/core/core.gyp
index 3b327da..74b3232 100644
--- a/aos/atom_code/core/core.gyp
+++ b/aos/atom_code/core/core.gyp
@@ -19,7 +19,7 @@
       'dependencies': [
         '<(AOS)/build/aos.gyp:logging',
         '<(AOS)/atom_code/atom_code.gyp:init',
-        '<(AOS)/common/common.gyp:common',
+        '<(AOS)/atom_code/atom_code.gyp:configuration',
       ],
     },
     {
diff --git a/aos/atom_code/input/input.gyp b/aos/atom_code/input/input.gyp
index 19d0d2f..8aba065 100644
--- a/aos/atom_code/input/input.gyp
+++ b/aos/atom_code/input/input.gyp
@@ -10,7 +10,6 @@
         '<(AOS)/common/input/input.gyp:driver_station_data',
         '<(AOS)/common/messages/messages.gyp:aos_queues',
         '<(AOS)/common/network/network.gyp:socket',
-        '<(AOS)/common/common.gyp:common',
         '<(EXTERNALS):WPILib-NetworkRobotValues',
         '<(AOS)/build/aos.gyp:logging',
       ],
diff --git a/aos/atom_code/input/joystick_input.cc b/aos/atom_code/input/joystick_input.cc
index c2b4d9c..28618ed 100644
--- a/aos/atom_code/input/joystick_input.cc
+++ b/aos/atom_code/input/joystick_input.cc
@@ -4,7 +4,7 @@
 
 #include "aos/externals/WPILib/WPILib/NetworkRobot/NetworkRobotValues.h"
 
-#include "aos/common/Configuration.h"
+#include "aos/common/network_port.h"
 #include "aos/common/network/ReceiveSocket.h"
 #include "aos/common/messages/RobotState.q.h"
 #include "aos/common/logging/logging.h"
diff --git a/aos/atom_code/output/ctemplate_cache.cc b/aos/atom_code/output/ctemplate_cache.cc
index a73e4ad..02c7b2f 100644
--- a/aos/atom_code/output/ctemplate_cache.cc
+++ b/aos/atom_code/output/ctemplate_cache.cc
@@ -1,6 +1,6 @@
 #include "aos/atom_code/output/ctemplate_cache.h"
 
-#include "aos/common/Configuration.h"
+#include "aos/atom_code/configuration.h"
 #include "aos/common/once.h"
 
 namespace aos {
diff --git a/aos/atom_code/output/motor_output.cc b/aos/atom_code/output/motor_output.cc
index d324da1..b68dcad 100644
--- a/aos/atom_code/output/motor_output.cc
+++ b/aos/atom_code/output/motor_output.cc
@@ -2,9 +2,9 @@
 
 #include <math.h>
 
-#include "aos/common/Configuration.h"
 #include "aos/common/control_loop/Timing.h"
 #include "aos/common/logging/logging.h"
+#include "aos/common/network_port.h"
 
 namespace aos {
 
@@ -26,8 +26,9 @@
   }
 }
 
-MotorOutput::MotorOutput() : socket_(NetworkPort::kMotors,
-          configuration::GetIPAddress(configuration::NetworkDevice::kCRIO)) {}
+MotorOutput::MotorOutput()
+  : socket_(NetworkPort::kMotors, ::aos::NetworkAddress::kCRIO) {
+}
 
 void MotorOutput::Run() {
   while (true) {
diff --git a/aos/atom_code/output/output.gyp b/aos/atom_code/output/output.gyp
index 6fb5956..8f0e47d 100644
--- a/aos/atom_code/output/output.gyp
+++ b/aos/atom_code/output/output.gyp
@@ -12,7 +12,6 @@
         '<(EXTERNALS):libevent',
         '<(EXTERNALS):ctemplate',
         '<(AOS)/common/common.gyp:once',
-        '<(AOS)/common/common.gyp:common',
         '<(AOS)/common/common.gyp:scoped_fd',
         '<(AOS)/build/aos.gyp:logging',
       ],
@@ -29,7 +28,6 @@
       ],
       'dependencies': [
         '<(AOS)/common/network/network.gyp:socket',
-        '<(AOS)/common/common.gyp:common',
         '<(AOS)/common/common.gyp:timing',
         '<(EXTERNALS):WPILib-NetworkRobotValues',
         '<(AOS)/build/aos.gyp:logging',
diff --git a/aos/atom_code/starter/netconsole.cc b/aos/atom_code/starter/netconsole.cc
index e2ba2b4..258afd8 100644
--- a/aos/atom_code/starter/netconsole.cc
+++ b/aos/atom_code/starter/netconsole.cc
@@ -10,7 +10,8 @@
 #include <assert.h>
 
 #include "aos/common/logging/logging_impl.h"
-#include "aos/common/Configuration.h"
+#include "aos/common/util.h"
+#include "aos/atom_code/configuration.h"
 
 namespace aos {
 namespace {
@@ -158,6 +159,11 @@
 
   pthread_t input_thread, output_thread;
 
+  address.in.sin_addr = ::aos::configuration::GetOwnIPAddress();
+  ::aos::util::SetLastSegment(&address.in.sin_addr, NetworkAddress::kCRIO);
+  fprintf(stderr, "Using cRIO IP %s.\n",
+          inet_ntoa(address.in.sin_addr));
+
   if (input != -1) {
     int to_crio = socket(AF_INET, SOCK_DGRAM, 0);
     if (to_crio == -1) {
@@ -169,13 +175,6 @@
           on, to_crio, errno, strerror(errno));
     }
     address.in.sin_port = htons(6668);
-    if (inet_aton(
-            configuration::GetIPAddress(configuration::NetworkDevice::kCRIO),
-            &address.in.sin_addr) == 0) {
-      LOG(FATAL, "inet_aton(%s, %p) failed with %d: %s\n",
-          configuration::GetIPAddress(configuration::NetworkDevice::kCRIO),
-          &address.in.sin_addr, errno, strerror(errno));
-    }
     if (connect(to_crio, &address.addr, sizeof(address)) == -1) {
       LOG(FATAL, "connect(%d, %p, %zu) failed with %d: %s\n",
           to_crio, &address.addr, sizeof(address), errno, strerror(errno));
@@ -187,16 +186,7 @@
     }
   }
 
-  fprintf(stderr, "Using cRIO IP %s.\n",
-          configuration::GetIPAddress(configuration::NetworkDevice::kCRIO));
-
-  if (inet_aton(
-          configuration::GetIPAddress(configuration::NetworkDevice::kSelf),
-          &address.in.sin_addr) == 0) {
-    LOG(FATAL, "inet_aton(%s, %p) failed with %d: %s\n",
-        configuration::GetIPAddress(configuration::NetworkDevice::kSelf),
-        &address.in.sin_addr, errno, strerror(errno));
-  }
+  address.in.sin_addr = ::aos::configuration::GetOwnIPAddress();
   FDsToCopy output_fds{from_crio, output, &address.in};
   if (pthread_create(&output_thread, NULL, FDCopyThread, &output_fds) == -1) {
     LOG(FATAL, "pthread_create(%p, NULL, %p, %p) failed with %d: %s\n",
diff --git a/aos/atom_code/starter/starter.gyp b/aos/atom_code/starter/starter.gyp
index 183ec9e..f494993 100644
--- a/aos/atom_code/starter/starter.gyp
+++ b/aos/atom_code/starter/starter.gyp
@@ -8,7 +8,8 @@
       ],
       'dependencies': [
         '<(AOS)/build/aos.gyp:logging',
-        '<(AOS)/common/common.gyp:common',
+        '<(AOS)/atom_code/atom_code.gyp:configuration',
+        '<(AOS)/common/common.gyp:util',
       ],
     },
     {
diff --git a/aos/common/Configuration.cpp b/aos/common/Configuration.cpp
deleted file mode 100644
index edf5212..0000000
--- a/aos/common/Configuration.cpp
+++ /dev/null
@@ -1,233 +0,0 @@
-#include "Configuration.h"
-
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <sys/types.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#ifdef __VXWORKS__
-#include <ifLib.h>
-#include <inetLib.h>
-#else
-#include <ifaddrs.h>
-#endif
-#include <unistd.h>
-
-#ifndef __VXWORKS__
-#include "aos/common/logging/logging.h"
-#include "aos/common/unique_malloc_ptr.h"
-#else
-#include <taskLib.h>
-#undef ERROR
-enum LogLevel {
-  DEBUG,
-  INFO,
-  WARNING,
-  ERROR = -1,
-  FATAL = 4,
-};
-#define LOG(level, format, args...) do { \
-  fprintf(stderr, #level ": " format, ##args); \
-  if (level == FATAL) { \
-    printf("I am 0x%x suspending for debugging purposes.\n", taskIdSelf()); \
-    printf("\t`tt 0x%x` will give you a stack trace.\n", taskIdSelf()); \
-    fputs("\t`lkAddr` will reverse lookup a symbol for you.\n", stdout); \
-    fputs("\t`dbgHelp` and `help` have some useful commands in them.\n", stdout); \
-    taskSuspend(0); \
-    printf("You weren't supposed to resume 0x%x!!. Going to really die now.\n", \
-           taskIdSelf()); \
-    abort(); \
-  } \
-} while (0)
-#endif
-#include "aos/common/once.h"
-
-namespace aos {
-namespace configuration {
-
-namespace {
-
-#ifdef __VXWORKS__
-const size_t kMaxAddrLength = INET_ADDR_LEN;
-#else
-// Including the terminating '\0'.
-const size_t kMaxAddrLength = 18;
-#endif
-// Returns whether or not the current IP address is in ownIPAddress.
-bool GetOwnIPAddress();
-
-#ifdef __VXWORKS__
-// vxworks doesn't have real asprintf.......
-static inline int aos_asprintf(size_t max_len, char **strp, const char *fmt, ...) {
-  *strp = static_cast<char *>(malloc(max_len));
-  if (*strp == NULL) {
-    return -1;
-  }
-  va_list argp;
-  va_start(argp, fmt);
-  const int r = vsnprintf(*strp, max_len, fmt, argp);
-  va_end(argp);
-  if (static_cast<uintmax_t>(r) >= max_len) {
-    errno = EOVERFLOW;
-    free(*strp);
-    return -1;
-  }
-  return r;
-}
-
-// 4-slot cRIO: motfec0
-// 8-slot cRIO port 1: fec0
-// ifShow will show you all of the ones on a cRIO
-const char *const kCrioNetInterfaces[] = {"fec0", "motfec0"};
-bool GetOwnIPAddress(char *buffer, size_t bufferSize) {
-  if (bufferSize < INET_ADDR_LEN) {
-    LOG(ERROR, "bufferSize(%jd) isn't >= INET_ADDR_LEN(%jd)\n",
-        static_cast<intmax_t>(bufferSize),
-        static_cast<intmax_t>(INET_ADDR_LEN));
-    return false;
-  }
-  for (size_t i = 0;
-       i < sizeof(kCrioNetInterfaces) / sizeof(kCrioNetInterfaces[0]); ++i) {
-    if (ifAddrGet(const_cast<char *>(kCrioNetInterfaces[i]), buffer) != OK) {
-      LOG(DEBUG, "ifAddrGet(\"%s\", %p) failed with %d: %s\n",
-          kCrioNetInterfaces[i], buffer, errno, strerror(errno));
-    } else {
-      return true;
-    }
-  }
-  LOG(ERROR, "couldn't get the cRIO's IP address\n");
-  return false;
-}
-#else
-static inline int aos_asprintf(size_t, char **strp, const char *fmt, ...) {
-  va_list argp;
-  va_start(argp, fmt);
-  const int r = vasprintf(strp, fmt, argp);
-  va_end(argp);
-  return r;
-}
-
-const char *const kAtomNetInterface = "eth0";
-bool GetOwnIPAddress(char *buffer, size_t bufferSize) {
-  ifaddrs *addrs;
-  if (getifaddrs(&addrs) != 0) {
-    LOG(ERROR, "getifaddrs(%p) failed with %d: %s\n", &addrs,
-        errno, strerror(errno));
-    return false;
-  }
-  // Smart pointers don't work very well for iterating through a linked list,
-  // but it does do a very nice job of making sure that addrs gets freed.
-  unique_c_ptr<ifaddrs, freeifaddrs> addrs_deleter(addrs);
-
-  for (; addrs != NULL; addrs = addrs->ifa_next) {
-    if (addrs->ifa_addr->sa_family == AF_INET) {
-      if (strcmp(kAtomNetInterface, addrs->ifa_name) == 0) {
-        const char *ipAddress = inet_ntoa(
-            reinterpret_cast<sockaddr_in *>(addrs->ifa_addr)->sin_addr);
-        strncpy(buffer, ipAddress, bufferSize);
-        return true;
-      }
-    }
-  }
-  LOG(ERROR, "couldn't find an AF_INET interface named \"%s\"\n",
-      kAtomNetInterface);
-  return false;
-}
-#endif
-
-const char *RawIPAddress(uint8_t last_part) {
-  char ownIPAddress[kMaxAddrLength];
-  if (!GetOwnIPAddress(ownIPAddress, sizeof(ownIPAddress))) {
-    return NULL;
-  }
-  char *last_dot = strrchr(ownIPAddress, '.');
-  if (last_dot == NULL) {
-    LOG(ERROR, "can't find any '.'s in \"%s\"\n", ownIPAddress);
-    return NULL;
-  }
-  *last_dot = '\0';
-
-  char *r;
-  if (aos_asprintf(kMaxAddrLength, &r, "%s.%hhu",
-                   ownIPAddress, last_part) == -1) {
-    return NULL;
-  }
-  return r;
-}
-
-}  // namespace
-
-const char *GetIPAddress(NetworkDevice device) {
-  switch (device) {
-    case NetworkDevice::kAtom:
-      return RawIPAddress(179);
-    case NetworkDevice::kCRIO:
-      return RawIPAddress(2);
-    case NetworkDevice::kSelf:
-      char *ret = static_cast<char *>(malloc(kMaxAddrLength));
-      if (!GetOwnIPAddress(ret, kMaxAddrLength)) return NULL;
-      return ret;
-  }
-  LOG(FATAL, "Unknown network device.");
-  return NULL;
-}
-
-namespace {
-const char *DoGetRootDirectory() {
-#ifdef __VXWORKS__
-  return "/";
-#else
-  ssize_t size = 0;
-  char *r = NULL;
-  while (true) {
-    if (r != NULL) delete r;
-    size += 256;
-    r = new char[size];
-
-    ssize_t ret = readlink("/proc/self/exe", r, size);
-    if (ret < 0) {
-      if (ret != -1) {
-        LOG(WARNING, "it returned %zd, not -1\n", ret);
-      }
-      LOG(FATAL, "readlink(\"/proc/self/exe\", %p, %zu) failed with %d: %s\n",
-          r, size, errno, strerror(errno));
-    }
-    if (ret < size) {
-      void *last_slash = memrchr(r, '/', size);
-      if (last_slash == NULL) {
-        r[ret] = '\0';
-        LOG(FATAL, "couldn't find a '/' in \"%s\"\n", r);
-      }
-      *static_cast<char *>(last_slash) = '\0';
-      LOG(INFO, "got a root dir of \"%s\"\n", r);
-      return r;
-    }
-  }
-#endif
-}
-
-const char *DoGetLoggingDirectory() {
-  static const char kSuffix[] = "/../../tmp/robot_logs";
-  const char *root = GetRootDirectory();
-  char *r = new char[strlen(root) + sizeof(kSuffix)];
-  strcpy(r, root);
-  strcat(r, kSuffix);
-  return r;
-}
-}  // namespace
-
-const char *GetRootDirectory() {
-  static aos::Once<const char> once(DoGetRootDirectory);
-  return once.Get();
-}
-
-const char *GetLoggingDirectory() {
-  static aos::Once<const char> once(DoGetLoggingDirectory);
-  return once.Get();
-}
-
-}  // namespace configuration
-}  // namespace aos
diff --git a/aos/common/Configuration.h b/aos/common/Configuration.h
deleted file mode 100644
index e1b7ef5..0000000
--- a/aos/common/Configuration.h
+++ /dev/null
@@ -1,55 +0,0 @@
-#ifndef AOS_COMMON_CONFIGURATION_H_
-#define AOS_COMMON_CONFIGURATION_H_
-
-#include "aos/aos_stdint.h"
-
-namespace aos {
-
-// Constants representing the various ports used for communications and some
-// documentation about what each is used for.
-enum class NetworkPort : uint16_t {
-  // UDP socket sending motor values from the atom to the crio.
-  kMotors = 9710,
-  // UDP socket forwarding drivers station packets from the crio to the atom.
-  kDS = 9711,
-  // UDP socket sending sensor values from the crio to the atom.
-  kSensors = 9712,
-  // TCP socket(s) (automatically reconnects) sending logs from the crio to the
-  // atom.
-  kLogs = 9713,
-  // HTTP server that sends out camera feeds in mjpg format.
-  // Should not be changed because this number shows up elsewhere too.
-  kCameraStreamer = 9714,
-};
-
-// Holds global configuration data. All of the functions are safe to call
-// from wherever (the ones that need to create locks on the cRIO).
-namespace configuration {
-
-// Constants indentifying various devices on the network.
-enum class NetworkDevice {
-  // The computer that the cRIO talks to.
-  kAtom,
-  kCRIO,
-  // Whatever device this is being run on.
-  kSelf,
-};
-// Returns the IP address to get to the specified machine.
-// The return value should be passed to free(3) if it is no longer needed.
-const char *GetIPAddress(NetworkDevice device);
-
-// Returns the "root directory" for this run. Under linux, this is the
-// directory where the executable is located (from /proc/self/exe) and under
-// vxworks it is just "/".
-// The return value will always be to a static string, so no freeing is
-// necessary.
-const char *GetRootDirectory();
-// Returns the directory where logs get written. Relative to GetRootDirectory().
-// The return value will always be to a static string, so no freeing is
-// necessary.
-const char *GetLoggingDirectory();
-
-}  // namespace configuration
-}  // namespace aos
-
-#endif
diff --git a/aos/common/common.gyp b/aos/common/common.gyp
index 09dc4a5..442e4ac 100644
--- a/aos/common/common.gyp
+++ b/aos/common/common.gyp
@@ -41,30 +41,6 @@
       ],
     },
     {
-      'target_name': 'common',
-      'type': 'static_library',
-      'sources': [
-        'Configuration.cpp',
-      ],
-      'dependencies': [
-        'once',
-      ],
-      'export_dependent_settings': [
-        'once',
-      ],
-      'conditions': [
-        ['OS=="crio"', {
-          'dependencies': [
-            '<(EXTERNALS):WPILib',
-          ],
-        }, {
-          'dependencies': [
-            '<(AOS)/build/aos.gyp:logging',
-          ],
-        }],
-      ],
-    },
-    {
       'target_name': 'queues',
       'type': 'static_library',
       'sources': [
@@ -86,11 +62,9 @@
         }]
       ],
       'dependencies': [
-        '<(AOS)/common/common.gyp:common',
         'time',
       ],
       'export_dependent_settings': [
-        '<(AOS)/common/common.gyp:common',
         'time',
       ],
     },
@@ -290,5 +264,12 @@
         'die',
       ],
     },
+    {
+      'target_name': 'util',
+      'type': 'static_library',
+      'sources': [
+        'util.cc',
+      ],
+    },
   ],
 }
diff --git a/aos/common/network/SendSocket.h b/aos/common/network/SendSocket.h
index fca904a..9323da8 100644
--- a/aos/common/network/SendSocket.h
+++ b/aos/common/network/SendSocket.h
@@ -3,6 +3,10 @@
 
 #include "Socket.h"
 
+#include "aos/atom_code/configuration.h"
+#include "aos/common/network_port.h"
+#include "aos/common/util.h"
+
 namespace aos {
 
 class SendSocket : public Socket {
@@ -10,8 +14,10 @@
   // Connect must be called before use.
   SendSocket() {}
   // Calls Connect automatically.
-  SendSocket(NetworkPort port, const char *robot_ip) {
-    Connect(port, robot_ip);
+  SendSocket(NetworkPort port, ::aos::NetworkAddress address) {
+    Connect(port,
+            ::aos::util::MakeIPAddress(::aos::configuration::GetOwnIPAddress(),
+                                       address));
   }
   int Connect(NetworkPort port, const char *robot_ip, int type = SOCK_DGRAM);
 };
diff --git a/aos/common/network/Socket.h b/aos/common/network/Socket.h
index 68fd32c..7a20d3e 100644
--- a/aos/common/network/Socket.h
+++ b/aos/common/network/Socket.h
@@ -9,8 +9,8 @@
 #include <unistd.h>
 #include <stdio.h>
 
-#include "aos/common/Configuration.h"
 #include "aos/common/time.h"
+#include "aos/common/network_port.h"
 
 namespace aos {
 
diff --git a/aos/common/network/network.gyp b/aos/common/network/network.gyp
index 4fc3a09..279bb53 100644
--- a/aos/common/network/network.gyp
+++ b/aos/common/network/network.gyp
@@ -37,16 +37,11 @@
         'SendSocket.cpp',
         'Socket.cpp',
       ],
-      'conditions': [
-        ['OS=="crio"', {
-          'dependencies': [
-            '<(EXTERNALS):WPILib',
-          ]}
-        ],
-      ],
       'dependencies': [
         '<(AOS)/build/aos.gyp:logging',
         '<(AOS)/common/common.gyp:time',
+        '<(AOS)/common/common.gyp:util',
+        '<(AOS)/atom_code/atom_code.gyp:configuration',
       ],
       'export_dependent_settings': [
         '<(AOS)/build/aos.gyp:logging',
diff --git a/aos/common/network_port.h b/aos/common/network_port.h
new file mode 100644
index 0000000..a8f2d1d
--- /dev/null
+++ b/aos/common/network_port.h
@@ -0,0 +1,35 @@
+#ifndef AOS_COMMON_NETWORK_PORT_H_
+#define AOS_COMMON_NETWORK_PORT_H_
+
+#include "aos/aos_stdint.h"
+
+namespace aos {
+
+// Constants representing the various ports used for communications and some
+// documentation about what each is used for.
+enum class NetworkPort : uint16_t {
+  // UDP socket sending motor values from the atom to the crio.
+  kMotors = 9710,
+  // UDP socket forwarding drivers station packets from the crio to the atom.
+  kDS = 9711,
+  // UDP socket sending sensor values from the crio to the atom.
+  kSensors = 9712,
+  // TCP socket(s) (automatically reconnects) sending logs from the crio to the
+  // atom.
+  kLogs = 9713,
+  // HTTP server that sends out camera feeds in mjpg format.
+  // Should not be changed because this number shows up elsewhere too.
+  kCameraStreamer = 9714,
+};
+
+// Constants representing the various devices that talk on the network and the
+// last segment of their IP addresses.
+enum class NetworkAddress : uint8_t {
+  // The computer that the cRIO talks to.
+  kAtom = 179,
+  kCRIO = 2,
+};
+
+}  // namespace aos
+
+#endif  // AOS_COMMON_NETWORK_PORT_H_
diff --git a/aos/common/sensors/sensor_receiver-tmpl.h b/aos/common/sensors/sensor_receiver-tmpl.h
index 8ebef22..8fb6cb4 100644
--- a/aos/common/sensors/sensor_receiver-tmpl.h
+++ b/aos/common/sensors/sensor_receiver-tmpl.h
@@ -1,5 +1,5 @@
-#include "aos/common/Configuration.h"
 #include "aos/common/inttypes.h"
+#include "aos/common/network_port.h"
 
 namespace aos {
 namespace sensors {
diff --git a/aos/common/sensors/sensors.gyp b/aos/common/sensors/sensors.gyp
index b73e02b..b8a2092 100644
--- a/aos/common/sensors/sensors.gyp
+++ b/aos/common/sensors/sensors.gyp
@@ -47,14 +47,12 @@
       ],
       'dependencies': [
         '<(AOS)/common/network/network.gyp:socket',
-        '<(AOS)/common/common.gyp:common',
         'sensors',
         '<(AOS)/common/common.gyp:time',
         '<(AOS)/common/common.gyp:gtest_prod',
       ],
       'export_dependent_settings': [
         '<(AOS)/common/network/network.gyp:socket',
-        '<(AOS)/common/common.gyp:common',
         'sensors',
         '<(AOS)/common/common.gyp:time',
         '<(AOS)/common/common.gyp:gtest_prod',
diff --git a/aos/common/util.cc b/aos/common/util.cc
new file mode 100644
index 0000000..1b7ca93
--- /dev/null
+++ b/aos/common/util.cc
@@ -0,0 +1,31 @@
+#include "aos/common/util.h"
+
+#include <stdlib.h>
+#ifndef __VXWORKS__
+#include <string.h>
+#endif
+
+namespace aos {
+namespace util {
+
+const char *MakeIPAddress(const in_addr &base_address,
+                          ::aos::NetworkAddress last_segment) {
+  in_addr address = base_address;
+  SetLastSegment(&address, last_segment);
+
+#ifdef __VXWORKS__
+  char *r = static_cast<char *>(malloc(INET_ADDR_LEN));
+  inet_ntoa_b(address, r);
+  return r;
+#else
+  return strdup(inet_ntoa(address));
+#endif
+}
+
+void SetLastSegment(in_addr *address, ::aos::NetworkAddress last_segment) {
+  address->s_addr &= ~0xFF;
+  address->s_addr |= static_cast<uint8_t>(last_segment);
+}
+
+}  // namespace util
+}  // namespace aos
diff --git a/aos/common/util.h b/aos/common/util.h
new file mode 100644
index 0000000..f41b86e
--- /dev/null
+++ b/aos/common/util.h
@@ -0,0 +1,29 @@
+#ifndef AOS_COMMON_UTIL_H_
+#define AOS_COMMON_UTIL_H_
+
+#ifdef __VXWORKS__
+#include <inetLib.h>
+#else
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#endif
+
+#include "aos/common/network_port.h"
+
+namespace aos {
+namespace util {
+
+// Makes an IP address string from base_address with the last byte set to
+// last_segment.
+// Returns a malloc(3)ed string.
+const char *MakeIPAddress(const in_addr &base_address,
+                          ::aos::NetworkAddress last_segment);
+
+// Sets the last byte of *address to last_segment.
+void SetLastSegment(in_addr *address, ::aos::NetworkAddress last_segment);
+
+}  // namespace util
+}  // namespace aos
+
+#endif  // AOS_COMMON_UTIL_H_
diff --git a/aos/crio/README.txt b/aos/crio/README.txt
index 182b323..98a6782 100644
--- a/aos/crio/README.txt
+++ b/aos/crio/README.txt
@@ -1,5 +1,5 @@
 see ../README.txt for stuff affecting crio and atom code
+There isn't much cRIO code left any more...
 
 [NOTES]
 The assumption that sizeof(pointers) == sizeof(int) == sizeof(UINT32) == sizeof(uint32_t) == 4 is all over the crio code. The vxworks apis use UINT32 to pass user-defined arguments, and just passing pointers through those makes the code a lot simpler.
-
diff --git a/aos/crio/crio.gyp b/aos/crio/crio.gyp
new file mode 100644
index 0000000..9b5d57e
--- /dev/null
+++ b/aos/crio/crio.gyp
@@ -0,0 +1,11 @@
+{
+  'targets': [
+    {
+      'target_name': 'ip',
+      'type': 'static_library',
+      'sources': [
+        'ip.cc',
+      ],
+    },
+  ],
+}
diff --git a/aos/crio/ip.cc b/aos/crio/ip.cc
new file mode 100644
index 0000000..9230365
--- /dev/null
+++ b/aos/crio/ip.cc
@@ -0,0 +1,32 @@
+#include "aos/crio/ip.h"
+
+#include <ifLib.h>
+#include <stdio.h>
+
+namespace aos {
+namespace util {
+
+// 4-slot cRIO: motfec0
+// 8-slot cRIO port 1: fec0
+// `ifShow` will show you all of the ones on a given cRIO
+const char *const kCrioNetInterfaces[] = {"fec0", "motfec0"};
+in_addr GetOwnIPAddress() {
+  char buffer[INET_ADDR_LEN];
+  in_addr r;
+  while (true) {
+    for (size_t i = 0;
+         i < sizeof(kCrioNetInterfaces) / sizeof(kCrioNetInterfaces[0]); ++i) {
+      if (ifAddrGet(const_cast<char *>(kCrioNetInterfaces[i]), buffer) == OK) {
+        if (inet_aton(buffer, &r) == OK) {
+          return r;
+        } else {
+          buffer[sizeof(buffer) - 1] = '\0';
+          printf("inet_aton('%s', %p) failed\n", buffer, &r);
+        }
+      }
+    }
+  }
+}
+
+}  // namespace util
+}  // namespace aos
diff --git a/aos/crio/ip.h b/aos/crio/ip.h
new file mode 100644
index 0000000..c1bc457
--- /dev/null
+++ b/aos/crio/ip.h
@@ -0,0 +1,18 @@
+#ifndef AOS_CRIO_IP_H_
+#define AOS_CRIO_IP_H_
+
+#include <inetLib.h>
+
+#include "aos/aos_stdint.h"
+
+namespace aos {
+namespace util {
+
+// Retrieves the IP address of this cRIO and stores it in *address.
+// Loops infinitely until it succeeds.
+in_addr GetOwnIPAddress();
+
+}  // namespace util
+}  // namespace aos
+
+#endif  // AOS_CRIO_IP_H_