github.com/emc-advanced-dev/unik@v0.0.0-20190717152701-a58d3e8e33b7/containers/compilers/includeos/cpp/patches/src/platforms/unik.cpp (about)

     1  // This file is a part of the IncludeOS unikernel - www.includeos.org
     2  //
     3  // Copyright 2015-2016 Oslo and Akershus University College of Applied Sciences
     4  // and Alfred Bratterud
     5  //
     6  // Licensed under the Apache License, Version 2.0 (the "License");
     7  // you may not use this file except in compliance with the License.
     8  // You may obtain a copy of the License at
     9  //
    10  //     http://www.apache.org/licenses/LICENSE-2.0
    11  //
    12  // Unless required by applicable law or agreed to in writing, software
    13  // distributed under the License is distributed on an "AS IS" BASIS,
    14  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    15  // See the License for the specific language governing permissions and
    16  // limitations under the License.
    17  
    18  
    19  #include <os>
    20  #include <platforms/unik.hpp>
    21  #include <rapidjson/document.h>
    22  #include <net/inet4>
    23  #include <regex>
    24  #include <info>
    25  
    26  using namespace rapidjson;
    27  
    28  unik::Client::Registered_event unik::Client::on_registered_{nullptr};
    29  
    30  /**
    31   * UniK instance listener hearbeat / http registration
    32   **/
    33  void unik::Client::register_instance(net::Inet4 &inet, const net::UDP::port_t port) {
    34  
    35  //    let OS::start know it shouldn't start service yet
    36  //    OS::ready_ = false;
    37      INFO("Unik client", "Turned off OS::ready_: %d", OS::ready_);
    38  
    39      INFO("Unik client", "Initializing Unik registration service");
    40      INFO("Unik client", "Listening for UDP hearbeat on %s:%i", inet.ip_addr().str().c_str(), port);
    41      INFO("Unik client", "IP is attached to interface %s ", inet.link_addr().str().c_str());
    42  
    43      // Set up an UDP port for receiving UniK heartbeat
    44      auto &sock = inet.udp().bind(port);
    45      CHECK(net::Inet4::stack<0>().udp().is_bound(port), "Unik UDP port is bound as expected");
    46      sock.on_read([&sock, &inet](auto addr, auto port, const char *data, size_t len) {
    47  
    48          static bool registered_with_unik = false;
    49          static const int max_attempts = 5;
    50          static int attempts_left = max_attempts;
    51  
    52          if (registered_with_unik or not attempts_left)
    53              return;
    54  
    55          std::string strdata(data, len);
    56          INFO("Unik client", "received UDP data from %s:%i: %s ", addr.str().c_str(), port, strdata.c_str());
    57  
    58          auto dotloc = strdata.find(":");
    59  
    60          if (dotloc == std::string::npos) {
    61              INFO("Unik client", "Unexpected UDP data format - no ':' in string.");
    62              return;
    63          }
    64  
    65          std::string prefix = strdata.substr(0, dotloc);
    66          std::string ip_str = strdata.substr(dotloc + 1);
    67  
    68          INFO("Unik client", "Prefix: %s , IP: '%s' \n", prefix.c_str(), ip_str.c_str());
    69  
    70          net::IP4::addr ip{ip_str};
    71          net::tcp::Socket unik_instance_listener{ip, 3000};
    72  
    73          attempts_left--;
    74          INFO("Unik client", "Connecting to UniK instance listener %s:%i (attempt %i / %i) ",
    75               ip.str().c_str(), 3000, max_attempts - attempts_left, max_attempts);
    76  
    77          // Connect to the instance listener
    78          auto http = inet.tcp().connect(unik_instance_listener);
    79  
    80          http->on_connect([&http, &inet](auto unik) {
    81  
    82              // Get our mac address
    83              auto mac_str = inet.link_addr().str();
    84  
    85              // Construct a HTTP request to the Unik instance listener, providing our mac-address in the query string
    86              std::string http_request = "POST /register?mac_address=" + std::string(mac_str) + " HTTP/1.1\r\n\n";
    87              INFO("Unik client", "Connected to UniK instance listener. Sending HTTP request: %s ", http_request.c_str());
    88  
    89              unik->write(http_request.c_str(), http_request.size());
    90  
    91              // Expect a response with meta data (which we ignore)
    92              unik->on_read(1024, [&http](auto buf, size_t n) {
    93                  std::string response((char *) buf.get(), n);
    94                  INFO("Unik client", "Unik reply: %s \n", response.c_str());
    95  
    96                  if (response.find("200 OK") != std::string::npos) {
    97                      registered_with_unik = true;
    98  
    99                      size_t json_start = response.find_first_of("{");
   100                      std::string json_data = response.substr(json_start);
   101                      INFO("Unik Client", "json data: %s \n", json_data.c_str());
   102  
   103                      Document document;
   104                      document.Parse(json_data.c_str());
   105                      for (Value::ConstMemberIterator itr = document.MemberBegin(); itr != document.MemberEnd(); ++itr) {
   106                          printf("setting env %s=%s\n", itr->name.GetString(), itr->value.GetString());
   107                          setenv(itr->name.GetString(), itr->value.GetString(), 1);
   108                      }
   109  
   110                      // Call the optional user callback if any
   111                      if (on_registered_)
   112                          on_registered_();
   113  
   114                      //unblock OS::start()
   115                      OS::ready_ = true;
   116  
   117                      return;
   118                  }
   119  
   120                  http->close();
   121  
   122              });
   123          });
   124      });
   125  } // register_instance
   126  
   127  
   128  void unik::Client::register_instance_dhcp() {
   129      // Bring up a network device using DHCP
   130      static auto &&inet = net::Inet4::stack<0>();
   131  
   132      net::Inet4::ifconfig<0>(10.0, [](bool timeout) {
   133          if (timeout) {
   134              INFO("Unik client", "DHCP request timed out. Nothing to do.");
   135              return;
   136          }
   137          INFO("Unik client", "IP address updated: %s", inet.ip_addr().str().c_str());
   138          register_instance(inet);
   139      });
   140  }
   141  
   142  __attribute__((constructor))
   143  void register_platform_unik() {
   144      OS::register_custom_init(unik::Client::register_instance_dhcp, "Unik register instance");
   145  }