Generated on for Gecode by doxygen 1.17.0
connector.hpp
Go to the documentation of this file.
1/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */
2/*
3 * Main authors:
4 * Maxim Shishmarev <maxim.shishmarev@monash.edu>
5 *
6 * Contributing authors:
7 * Kevin Leo <kevin.leo@monash.edu>
8 * Christian Schulte <schulte@gecode.dev>
9 *
10 * Copyright:
11 * Kevin Leo, 2017
12 * Christian Schulte, 2017
13 * Maxim Shishmarev, 2017
14 *
15 * This file is part of Gecode, the generic constraint
16 * development environment:
17 * http://www.gecode.dev
18 *
19 * Permission is hereby granted, free of charge, to any person obtaining
20 * a copy of this software and associated documentation files (the
21 * "Software"), to deal in the Software without restriction, including
22 * without limitation the rights to use, copy, modify, merge, publish,
23 * distribute, sublicense, and/or sell copies of the Software, and to
24 * permit persons to whom the Software is furnished to do so, subject to
25 * the following conditions:
26 *
27 * The above copyright notice and this permission notice shall be
28 * included in all copies or substantial portions of the Software.
29 *
30 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
31 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
32 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
33 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
34 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
35 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
36 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
37 *
38 */
39
40#include <iostream>
41#include <sstream>
42#include <vector>
43#include <cstring>
44
45#if defined(_WIN32)
46
47#include <winsock2.h>
48#include <ws2tcpip.h>
49#if defined(_MSC_VER)
50#pragma comment(lib, "Ws2_32.lib")
51#pragma comment(lib, "Mswsock.lib")
52#pragma comment(lib, "AdvApi32.lib")
53#endif
54
55#include <basetsd.h>
56typedef SSIZE_T ssize_t;
57
58#else
59
60#include <netdb.h>
61#include <unistd.h>
62#include <sys/socket.h>
63
64#endif
65
66namespace Gecode { namespace CPProfiler {
67
68 class Node {
69 NodeUID node_;
70 NodeUID parent_;
71 int alt_;
72 int kids_;
73
74 NodeStatus status_;
75
77 Option<std::string> nogood_;
79
80 public:
81 Node(NodeUID node, NodeUID parent,
82 int alt, int kids, NodeStatus status);
83 Node& set_node_thread_id(int tid);
84 const Option<std::string>& label() const;
85 Node& set_label(const std::string& label);
86 const Option<std::string>& nogood() const;
87 Node& set_nogood(const std::string& nogood);
88 const Option<std::string>& info() const;
89 Node& set_info(const std::string& info);
90 int alt() const;
91 int kids() const;
92 NodeStatus status() const;
93 NodeUID nodeUID() const;
94 NodeUID parentUID() const;
95 int node_id() const;
96 int parent_id() const;
97 int node_thread_id() const;
98 int node_restart_id() const;
99 int parent_thread_id() const;
100 int parent_restart_id() const;
101 };
102
103 class Connector {
104 private:
105 MessageMarshalling marshalling;
106
107 const unsigned int port;
108
109 int sockfd;
110 bool _connected;
111#if defined(_WIN32)
112 bool _winsock_started;
113#endif
114
115 static int sendall(int s, const char* buf, int* len);
116 void sendOverSocket(void);
117 void sendRawMsg(const std::vector<char>& buf);
118 public:
119 Connector(unsigned int port);
120
121 bool connected() const;
122
125 void connect(void);
126
127 // sends START_SENDING message to the Profiler with a model name
128 void start(const std::string& file_path = "",
129 int execution_id = -1, bool has_restarts = false);
130 void restart(int restart_id = -1);
131 void done();
132
134 void disconnect(void);
135
136 void sendNode(const Node& node);
137 Node createNode(NodeUID node, NodeUID parent,
138 int alt, int kids, NodeStatus status);
139 };
140
141
142 /*
143 * Nodes
144 */
145 inline
147 int alt, int kids, NodeStatus status)
148 : node_{node}, parent_{parent},
149 alt_(alt), kids_(kids), status_(status) {}
150
151 inline Node&
153 node_.tid = tid;
154 return *this;
155 }
156
157 inline const Option<std::string>&
158 Node::label() const { return label_; }
159
160 inline Node&
161 Node::set_label(const std::string& label) {
162 label_.set(label);
163 return *this;
164 }
165
166 inline const Option<std::string>&
167 Node::nogood() const {
168 return nogood_;
169 }
170
171 inline Node&
172 Node::set_nogood(const std::string& nogood) {
173 nogood_.set(nogood);
174 return *this;
175 }
176
177 inline const Option<std::string>&
178 Node::info() const { return info_; }
179
180 inline Node&
181 Node::set_info(const std::string& info) {
182 info_.set(info);
183 return *this;
184 }
185
186 inline int
187 Node::alt() const { return alt_; }
188 inline int
189 Node::kids() const { return kids_; }
190
191 inline NodeStatus
192 Node::status() const { return status_; }
193
194 inline NodeUID
195 Node::nodeUID() const { return node_; }
196 inline NodeUID
197 Node::parentUID() const { return parent_; }
198
199 inline int
200 Node::node_id() const { return node_.nid; }
201 inline int
202 Node::parent_id() const { return parent_.nid; }
203 inline int
204 Node::node_thread_id() const { return node_.tid; }
205 inline int
206 Node::node_restart_id() const { return node_.rid; }
207 inline int
208 Node::parent_thread_id() const { return parent_.tid; }
209 inline int
210 Node::parent_restart_id() const { return parent_.rid; }
211
212
213 /*
214 * Connector
215 */
216 inline
217 Connector::Connector(unsigned int port)
218 : port(port), sockfd(-1), _connected(false)
219#if defined(_WIN32)
220 , _winsock_started(false)
221#endif
222 {}
223
224 inline bool Connector::connected() const { return _connected; }
225
226
227 /*
228 * The following code is taken from:
229 * Beej's Guide to Network Programming
230 * http://beej.us/guide/bgnet/
231 * with the following license:
232 *
233 * Beej's Guide to Network Programming is Copyright © 2015 Brian "Beej Jorgensen" Hall.
234 * 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.
235 * 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.
236 * The C source code presented in this document is hereby granted to the public domain, and is completely free of any license restriction.
237 * Educators are freely encouraged to recommend or supply copies of this guide to their students.
238 * Contact beej@beej.us for more information.
239 */
240 inline int
241 Connector::sendall(int s, const char* buf, int* len) {
242 int total = 0; // how many bytes we've sent
243 int bytesleft = *len; // how many we have left to send
244 ssize_t n;
245
246 while (total < *len) {
247 n = send(s, buf + total, static_cast<size_t>(bytesleft), 0);
248 if (n == -1) {
249 break;
250 }
251 total += static_cast<int>(n);
252 bytesleft -= static_cast<int>(n);
253 }
254
255 *len = static_cast<int>(total); // return number actually sent here
256
257 return (n == -1) ? -1 : 0; // return -1 on failure, 0 on success
258 }
259
260 inline void
261 Connector::sendRawMsg(const std::vector<char>& buf) {
262 uint32_t bufSize = static_cast<uint32_t>(buf.size());
263 int bufSizeLen = sizeof(uint32_t);
264 sendall(sockfd, reinterpret_cast<char*>(&bufSize), &bufSizeLen);
265 int bufSizeInt = static_cast<int>(bufSize);
266 sendall(sockfd, reinterpret_cast<const char*>(buf.data()), &bufSizeInt);
267 }
268
269 inline void
270 Connector::sendOverSocket(void) {
271 if (!_connected) return;
272
273 std::vector<char> buf = marshalling.serialize();
274
275 sendRawMsg(buf);
276 }
277
278 inline void
280 struct addrinfo hints, *servinfo, *p;
281 int rv;
282
283#if defined(_WIN32)
284 // Initialise Winsock.
285 WSADATA wsaData;
286 int startupResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
287 if (startupResult != 0) {
288 printf("WSAStartup failed with error: %d\n", startupResult);
289 goto giveup;
290 }
291 _winsock_started = true;
292#endif
293
294 memset(&hints, 0, sizeof hints);
295 hints.ai_family = AF_UNSPEC;
296 hints.ai_socktype = SOCK_STREAM;
297
298 if ((rv = getaddrinfo("localhost", std::to_string(port).c_str(), &hints,
299 &servinfo)) != 0) {
300 std::cerr << "getaddrinfo: " << gai_strerror(rv) << "\n";
301 goto giveup;
302 }
303
304 // loop through all the results and connect to the first we can
305 for (p = servinfo; p != nullptr; p = p->ai_next) {
306 if ((sockfd = static_cast<int>(socket(p->ai_family, p->ai_socktype, p->ai_protocol))) == -1) {
307 // errno is set here, but we don't examine it.
308 continue;
309 }
310
311 if (::connect(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
312#if defined(_WIN32)
313 closesocket(sockfd);
314#else
315 close(sockfd);
316#endif
317 sockfd = -1;
318 // errno is set here, but we don't examine it.
319 continue;
320 }
321
322 break;
323 }
324
325 // Connection failed; give up.
326 if (p == nullptr) {
327 freeaddrinfo(servinfo);
328 goto giveup;
329 }
330
331 freeaddrinfo(servinfo); // all done with this structure
332
333 _connected = true;
334
335 return;
336 giveup:
337 _connected = false;
338#if defined(_WIN32)
339 if (_winsock_started) {
340 WSACleanup();
341 _winsock_started = false;
342 }
343#endif
344 return;
345
346 }
347
348 inline void
349 Connector::start(const std::string& file_path,
350 int execution_id, bool has_restarts) {
352 std::string base_name(file_path);
353 {
354 size_t pos = base_name.find_last_of('/');
355 if (pos != static_cast<size_t>(-1)) {
356 base_name = base_name.substr(pos + 1, base_name.length() - pos - 1);
357 }
358 }
359
360 std::string info{""};
361 {
362 std::stringstream ss;
363 ss << "{";
364 ss << "\"has_restarts\": " << (has_restarts ? "true" : "false") << "\n";
365 ss << ",\"name\": " << "\"" << base_name << "\"" << "\n";
366 if (execution_id != -1) {
367 ss << ",\"execution_id\": " << execution_id;
368 }
369 ss << "}";
370 info = ss.str();
371 }
372
373 marshalling.makeStart(info);
374 sendOverSocket();
375 }
376
377 inline void
378 Connector::restart(int restart_id) {
379
380 std::string info{""};
381 {
382 std::stringstream ss;
383 ss << "{";
384 ss << "\"restart_id\": " << restart_id << "\n";
385 ss << "}";
386 info = ss.str();
387 }
388
389 marshalling.makeRestart(info);
390 sendOverSocket();
391 }
392
393 inline void
395 marshalling.makeDone();
396 sendOverSocket();
397 }
398
399 inline void
401 if (sockfd != -1) {
402#if defined(_WIN32)
403 closesocket(sockfd);
404#else
405 close(sockfd);
406#endif
407 sockfd = -1;
408 }
409 _connected = false;
410#if defined(_WIN32)
411 if (_winsock_started) {
412 WSACleanup();
413 _winsock_started = false;
414 }
415#endif
416 }
417
418 inline void
420 if (!_connected) return;
421
422 auto& msg = marshalling.makeNode(node.nodeUID(), node.parentUID(),
423 node.alt(), node.kids(), node.status());
424
425 if (node.label().valid()) msg.set_label(node.label().value());
426 if (node.nogood().valid()) msg.set_nogood(node.nogood().value());
427 if (node.info().valid()) msg.set_info(node.info().value());
428
429 sendOverSocket();
430 }
431
432 inline Node
434 int alt, int kids, NodeStatus status) {
435 return Node(node, parent, alt, kids, status);
436 }
437
438}}
439
440// STATISTICS: search-trace
Node createNode(NodeUID node, NodeUID parent, int alt, int kids, NodeStatus status)
void sendNode(const Node &node)
void start(const std::string &file_path="", int execution_id=-1, bool has_restarts=false)
void disconnect(void)
disconnect from a socket
Connector(unsigned int port)
void connect(void)
connect to a socket via port specified in the construction (6565 by default)
void restart(int restart_id=-1)
Node & set_nogood(const std::string &nogood)
NodeUID nodeUID() const
const Option< std::string > & nogood() const
Node(NodeUID node, NodeUID parent, int alt, int kids, NodeStatus status)
int parent_restart_id() const
Node & set_info(const std::string &info)
const Option< std::string > & info() const
const Option< std::string > & label() const
NodeUID parentUID() const
NodeStatus status() const
Node & set_node_thread_id(int tid)
Node & set_label(const std::string &label)
Optional value class.
Definition message.hpp:68
bool valid(void) const
Check whether value is present.
Definition message.hpp:89
const T & value(void) const
Access value.
Definition message.hpp:104
Code that is specific to the CPProfiler.
Definition search.hh:410
NodeStatus
Types of nodes for CP Profiler.
Definition message.hpp:51
Gecode toplevel namespace
Unique identifier for a node.
Definition message.hpp:114
int32_t nid
Node number.
Definition message.hpp:116