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 }