Generated on Sun Feb 17 15:24:28 2019 for Gecode by doxygen 1.6.3

connector.hpp

Go to the documentation of this file.
00001 /* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */
00002 /*
00003  *  Main authors:
00004  *     Maxim Shishmarev <maxim.shishmarev@monash.edu>
00005  *
00006  *  Contributing authors:
00007  *     Kevin Leo <kevin.leo@monash.edu>
00008  *     Christian Schulte <schulte@gecode.org>
00009  *
00010  *  Copyright:
00011  *     Kevin Leo, 2017
00012  *     Christian Schulte, 2017
00013  *     Maxim Shishmarev, 2017
00014  *
00015  *  This file is part of Gecode, the generic constraint
00016  *  development environment:
00017  *     http://www.gecode.org
00018  *
00019  *  Permission is hereby granted, free of charge, to any person obtaining
00020  *  a copy of this software and associated documentation files (the
00021  *  "Software"), to deal in the Software without restriction, including
00022  *  without limitation the rights to use, copy, modify, merge, publish,
00023  *  distribute, sublicense, and/or sell copies of the Software, and to
00024  *  permit persons to whom the Software is furnished to do so, subject to
00025  *  the following conditions:
00026  *
00027  *  The above copyright notice and this permission notice shall be
00028  *  included in all copies or substantial portions of the Software.
00029  *
00030  *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
00031  *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
00032  *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
00033  *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
00034  *  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
00035  *  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
00036  *  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00037  *
00038  */
00039 
00040 #include <iostream>
00041 #include <sstream>
00042 #include <vector>
00043 #include <cstring>
00044 
00045 #ifdef WIN32
00046 
00047 #include <winsock2.h>
00048 #include <ws2tcpip.h>
00049 #pragma comment(lib, "Ws2_32.lib")
00050 #pragma comment(lib, "Mswsock.lib")
00051 #pragma comment(lib, "AdvApi32.lib")
00052 
00053 #include <basetsd.h>
00054 typedef SSIZE_T ssize_t;
00055 
00056 #else
00057 
00058 #include <netdb.h>
00059 #include <unistd.h>
00060 
00061 #endif
00062 
00063 namespace Gecode { namespace CPProfiler {
00064 
00065   class Node {
00066     NodeUID node_;
00067     NodeUID parent_;
00068     int alt_;
00069     int kids_;
00070     
00071     NodeStatus status_;
00072     
00073     Option<std::string> label_;
00074     Option<std::string> nogood_;
00075     Option<std::string> info_;
00076     
00077   public:
00078     Node(NodeUID node, NodeUID parent,
00079          int alt, int kids, NodeStatus status);
00080     Node& set_node_thread_id(int tid);
00081     const Option<std::string>& label() const;
00082     Node& set_label(const std::string& label);
00083     const Option<std::string>& nogood() const;
00084     Node& set_nogood(const std::string& nogood);
00085     const Option<std::string>& info() const;
00086     Node& set_info(const std::string& info);
00087     int alt() const;
00088     int kids() const;
00089     NodeStatus status() const;
00090     NodeUID nodeUID() const;
00091     NodeUID parentUID() const;
00092     int node_id() const;
00093     int parent_id() const;
00094     int node_thread_id() const;
00095     int node_restart_id() const;
00096     int parent_thread_id() const;
00097     int parent_restart_id() const;
00098   };
00099 
00100   class Connector {
00101   private:
00102     MessageMarshalling marshalling;
00103     
00104     const unsigned int port;
00105     
00106     int sockfd;
00107     bool _connected;
00108     
00109     static int sendall(int s, const char* buf, int* len);
00110     void sendOverSocket(void);
00111     void sendRawMsg(const std::vector<char>& buf);
00112   public:    
00113     Connector(unsigned int port);
00114     
00115     bool connected() const;
00116     
00119     void connect(void);
00120     
00121     // sends START_SENDING message to the Profiler with a model name
00122     void start(const std::string& file_path = "",
00123                int execution_id = -1, bool has_restarts = false);
00124     void restart(int restart_id = -1);
00125     void done();
00126     
00128     void disconnect(void);
00129     
00130     void sendNode(const Node& node);
00131     Node createNode(NodeUID node, NodeUID parent,
00132                     int alt, int kids, NodeStatus status);
00133   };
00134   
00135 
00136   /*
00137    * Nodes
00138    */
00139   inline
00140   Node::Node(NodeUID node, NodeUID parent,
00141              int alt, int kids, NodeStatus status)
00142     : node_{node}, parent_{parent},
00143     alt_(alt), kids_(kids), status_(status) {}
00144     
00145   inline Node&
00146   Node::set_node_thread_id(int tid) {
00147     node_.tid = tid;
00148     return *this;
00149   }
00150     
00151   inline const Option<std::string>&
00152   Node::label() const { return label_; }
00153     
00154   inline Node&
00155   Node::set_label(const std::string& label) {
00156     label_.set(label);
00157     return *this;
00158   }
00159     
00160   inline const Option<std::string>&
00161   Node::nogood() const { 
00162     return nogood_;
00163   }
00164     
00165   inline Node&
00166   Node::set_nogood(const std::string& nogood) {
00167     nogood_.set(nogood);
00168     return *this;
00169   }
00170     
00171   inline const Option<std::string>&
00172   Node::info() const { return info_; }
00173 
00174   inline Node&
00175   Node::set_info(const std::string& info) {
00176     info_.set(info);
00177     return *this;
00178   }
00179     
00180   inline int
00181   Node::alt() const { return alt_; }
00182   inline int
00183   Node::kids() const { return kids_; }
00184     
00185   inline NodeStatus
00186   Node::status() const { return status_; }
00187     
00188   inline NodeUID
00189   Node::nodeUID() const { return node_; }
00190   inline NodeUID
00191   Node::parentUID() const { return parent_; }
00192     
00193   inline int
00194   Node::node_id() const { return node_.nid; }
00195   inline int
00196   Node::parent_id() const { return parent_.nid; }
00197   inline int
00198   Node::node_thread_id() const {  return node_.tid; }
00199   inline int
00200   Node::node_restart_id() const { return node_.rid; }
00201   inline int
00202   Node::parent_thread_id() const {  return parent_.tid; }
00203   inline int
00204   Node::parent_restart_id() const { return parent_.rid; }
00205 
00206   
00207   /*
00208    * Connector
00209    */
00210   inline
00211   Connector::Connector(unsigned int port) : port(port), _connected(false) {}
00212 
00213   inline bool Connector::connected() const { return _connected; }
00214 
00215 
00216   /*
00217    * The following code is taken from:
00218    *   Beej's Guide to Network Programming
00219    *   http://beej.us/guide/bgnet/
00220    * with the folloiwng license:
00221    *
00222    * Beej's Guide to Network Programming is Copyright © 2015 Brian "Beej Jorgensen" Hall.
00223    * With specific exceptions for source code and translations, below, this work is licensed under the Creative Commons Attribution- Noncommercial- No Derivative Works 3.0 License. To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/ or send a letter to Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA.
00224    * One specific exception to the "No Derivative Works" portion of the license is as follows: this guide may be freely translated into any language, provided the translation is accurate, and the guide is reprinted in its entirety. The same license restrictions apply to the translation as to the original guide. The translation may also include the name and contact information for the translator.
00225    * The C source code presented in this document is hereby granted to the public domain, and is completely free of any license restriction.
00226    * Educators are freely encouraged to recommend or supply copies of this guide to their students.
00227    * Contact beej@beej.us for more information. 
00228    */
00229   inline int
00230   Connector::sendall(int s, const char* buf, int* len) {
00231     int total = 0;         // how many bytes we've sent
00232     int bytesleft = *len;  // how many we have left to send
00233     ssize_t n;
00234     
00235     while (total < *len) {
00236       n = send(s, buf + total, static_cast<size_t>(bytesleft), 0);
00237       if (n == -1) {
00238         break;
00239       }
00240       total += static_cast<int>(n);
00241       bytesleft -= static_cast<int>(n);
00242     }
00243 
00244     *len = static_cast<int>(total);  // return number actually sent here
00245     
00246     return (n == -1) ? -1 : 0;  // return -1 on failure, 0 on success
00247   }
00248 
00249   inline void
00250   Connector::sendRawMsg(const std::vector<char>& buf) {
00251     uint32_t bufSize = static_cast<uint32_t>(buf.size());
00252     int bufSizeLen = sizeof(uint32_t);
00253     sendall(sockfd, reinterpret_cast<char*>(&bufSize), &bufSizeLen);
00254     int bufSizeInt = static_cast<int>(bufSize);
00255     sendall(sockfd, reinterpret_cast<const char*>(buf.data()), &bufSizeInt);
00256   }
00257     
00258   inline void
00259   Connector::sendOverSocket(void) {
00260     if (!_connected) return;
00261       
00262     std::vector<char> buf = marshalling.serialize();
00263       
00264     sendRawMsg(buf);
00265   }
00266     
00267   inline void
00268   Connector::connect(void) {
00269     struct addrinfo hints, *servinfo, *p;
00270     int rv;
00271       
00272 #ifdef WIN32
00273     // Initialise Winsock.
00274     WSADATA wsaData;
00275     int startupResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
00276     if (startupResult != 0) {
00277       printf("WSAStartup failed with error: %d\n", startupResult);
00278     }
00279 #endif
00280     
00281     memset(&hints, 0, sizeof hints);
00282     hints.ai_family = AF_UNSPEC;
00283     hints.ai_socktype = SOCK_STREAM;
00284     
00285     if ((rv = getaddrinfo("localhost", std::to_string(port).c_str(), &hints,
00286                           &servinfo)) != 0) {
00287       std::cerr << "getaddrinfo: " << gai_strerror(rv) << "\n";
00288       goto giveup;
00289     }
00290     
00291     // loop through all the results and connect to the first we can
00292     for (p = servinfo; p != NULL; p = p->ai_next) {
00293       if ((sockfd = static_cast<int>(socket(p->ai_family, p->ai_socktype, p->ai_protocol))) == -1) {
00294         // errno is set here, but we don't examine it.
00295         continue;
00296       }
00297       
00298       if (::connect(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
00299 #ifdef WIN32
00300         closesocket(sockfd);
00301 #else
00302         close(sockfd);
00303 #endif
00304         // errno is set here, but we don't examine it.
00305         continue;
00306       }
00307       
00308       break;
00309     }
00310     
00311     // Connection failed; give up.
00312     if (p == NULL) {
00313       goto giveup;
00314     }
00315       
00316     freeaddrinfo(servinfo);  // all done with this structure
00317     
00318     _connected = true;
00319     
00320     return;
00321   giveup:
00322     _connected = false;
00323     return;
00324     
00325   }
00326   
00327   inline void
00328   Connector::start(const std::string& file_path,
00329                    int execution_id, bool has_restarts) {
00331     std::string base_name(file_path);
00332     {
00333       size_t pos = base_name.find_last_of('/');
00334       if (pos != static_cast<size_t>(-1)) {
00335         base_name = base_name.substr(pos + 1, base_name.length() - pos - 1);
00336       }
00337     }
00338     
00339     std::string info{""};
00340     {
00341       std::stringstream ss;
00342       ss << "{";
00343       ss << "\"has_restarts\": " << (has_restarts ? "true" : "false")  << "\n";
00344       ss << ",\"name\": " << "\"" << base_name << "\"" << "\n";
00345       if (execution_id != -1) {
00346         ss << ",\"execution_id\": " << execution_id;
00347       }
00348       ss << "}";
00349       info = ss.str();
00350     }
00351     
00352     marshalling.makeStart(info);
00353     sendOverSocket();
00354   }
00355 
00356   inline void
00357   Connector::restart(int restart_id) {
00358       
00359     std::string info{""};
00360     {
00361       std::stringstream ss;
00362       ss << "{";
00363       ss << "\"restart_id\": " << restart_id << "\n";
00364       ss << "}";
00365       info = ss.str();
00366     }
00367     
00368     marshalling.makeRestart(info);
00369     sendOverSocket();
00370   }
00371   
00372   inline void
00373   Connector::done() {
00374     marshalling.makeDone();
00375     sendOverSocket();
00376   }
00377   
00378   inline void
00379   Connector::disconnect() {
00380 #ifdef WIN32
00381     closesocket(sockfd);
00382 #else
00383     close(sockfd);
00384 #endif
00385   }
00386   
00387   inline void
00388   Connector::sendNode(const Node& node) {
00389     if (!_connected) return;
00390     
00391     auto& msg = marshalling.makeNode(node.nodeUID(), node.parentUID(),
00392                                      node.alt(), node.kids(), node.status());
00393     
00394     if (node.label().valid()) msg.set_label(node.label().value());
00395     if (node.nogood().valid()) msg.set_nogood(node.nogood().value());
00396     if (node.info().valid()) msg.set_info(node.info().value());
00397     
00398     sendOverSocket();
00399   }
00400 
00401   inline Node
00402   Connector::createNode(NodeUID node, NodeUID parent,
00403                         int alt, int kids, NodeStatus status) {
00404     return Node(node, parent, alt, kids, status);
00405   }
00406   
00407 }}
00408 
00409 // STATISTICS: search-trace