Generated on Tue Feb 11 2025 17:33:26 for Gecode by doxygen 1.12.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.org>
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.org
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#ifdef WIN32
46
47#include <winsock2.h>
48#include <ws2tcpip.h>
49#pragma comment(lib, "Ws2_32.lib")
50#pragma comment(lib, "Mswsock.lib")
51#pragma comment(lib, "AdvApi32.lib")
52
53#include <basetsd.h>
54typedef SSIZE_T ssize_t;
55
56#else
57
58#include <netdb.h>
59#include <unistd.h>
60
61#endif
62
63namespace Gecode { namespace CPProfiler {
64
65 class Node {
66 NodeUID node_;
67 NodeUID parent_;
68 int alt_;
69 int kids_;
70
71 NodeStatus status_;
72
74 Option<std::string> nogood_;
76
77 public:
78 Node(NodeUID node, NodeUID parent,
79 int alt, int kids, NodeStatus status);
80 Node& set_node_thread_id(int tid);
81 const Option<std::string>& label() const;
82 Node& set_label(const std::string& label);
83 const Option<std::string>& nogood() const;
84 Node& set_nogood(const std::string& nogood);
85 const Option<std::string>& info() const;
86 Node& set_info(const std::string& info);
87 int alt() const;
88 int kids() const;
89 NodeStatus status() const;
90 NodeUID nodeUID() const;
91 NodeUID parentUID() const;
92 int node_id() const;
93 int parent_id() const;
94 int node_thread_id() const;
95 int node_restart_id() const;
96 int parent_thread_id() const;
97 int parent_restart_id() const;
98 };
99
100 class Connector {
101 private:
102 MessageMarshalling marshalling;
103
104 const unsigned int port;
105
106 int sockfd;
107 bool _connected;
108
109 static int sendall(int s, const char* buf, int* len);
110 void sendOverSocket(void);
111 void sendRawMsg(const std::vector<char>& buf);
112 public:
113 Connector(unsigned int port);
114
115 bool connected() const;
116
119 void connect(void);
120
121 // sends START_SENDING message to the Profiler with a model name
122 void start(const std::string& file_path = "",
123 int execution_id = -1, bool has_restarts = false);
124 void restart(int restart_id = -1);
125 void done();
126
128 void disconnect(void);
129
130 void sendNode(const Node& node);
131 Node createNode(NodeUID node, NodeUID parent,
132 int alt, int kids, NodeStatus status);
133 };
134
135
136 /*
137 * Nodes
138 */
139 inline
141 int alt, int kids, NodeStatus status)
142 : node_{node}, parent_{parent},
143 alt_(alt), kids_(kids), status_(status) {}
144
145 inline Node&
147 node_.tid = tid;
148 return *this;
149 }
150
151 inline const Option<std::string>&
152 Node::label() const { return label_; }
153
154 inline Node&
155 Node::set_label(const std::string& label) {
156 label_.set(label);
157 return *this;
158 }
159
160 inline const Option<std::string>&
161 Node::nogood() const {
162 return nogood_;
163 }
164
165 inline Node&
166 Node::set_nogood(const std::string& nogood) {
167 nogood_.set(nogood);
168 return *this;
169 }
170
171 inline const Option<std::string>&
172 Node::info() const { return info_; }
173
174 inline Node&
175 Node::set_info(const std::string& info) {
176 info_.set(info);
177 return *this;
178 }
179
180 inline int
181 Node::alt() const { return alt_; }
182 inline int
183 Node::kids() const { return kids_; }
184
185 inline NodeStatus
186 Node::status() const { return status_; }
187
188 inline NodeUID
189 Node::nodeUID() const { return node_; }
190 inline NodeUID
191 Node::parentUID() const { return parent_; }
192
193 inline int
194 Node::node_id() const { return node_.nid; }
195 inline int
196 Node::parent_id() const { return parent_.nid; }
197 inline int
198 Node::node_thread_id() const { return node_.tid; }
199 inline int
200 Node::node_restart_id() const { return node_.rid; }
201 inline int
202 Node::parent_thread_id() const { return parent_.tid; }
203 inline int
204 Node::parent_restart_id() const { return parent_.rid; }
205
206
207 /*
208 * Connector
209 */
210 inline
211 Connector::Connector(unsigned int port) : port(port), _connected(false) {}
212
213 inline bool Connector::connected() const { return _connected; }
214
215
216 /*
217 * The following code is taken from:
218 * Beej's Guide to Network Programming
219 * http://beej.us/guide/bgnet/
220 * with the folloiwng license:
221 *
222 * Beej's Guide to Network Programming is Copyright © 2015 Brian "Beej Jorgensen" Hall.
223 * 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.
224 * 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.
225 * The C source code presented in this document is hereby granted to the public domain, and is completely free of any license restriction.
226 * Educators are freely encouraged to recommend or supply copies of this guide to their students.
227 * Contact beej@beej.us for more information.
228 */
229 inline int
230 Connector::sendall(int s, const char* buf, int* len) {
231 int total = 0; // how many bytes we've sent
232 int bytesleft = *len; // how many we have left to send
233 ssize_t n;
234
235 while (total < *len) {
236 n = send(s, buf + total, static_cast<size_t>(bytesleft), 0);
237 if (n == -1) {
238 break;
239 }
240 total += static_cast<int>(n);
241 bytesleft -= static_cast<int>(n);
242 }
243
244 *len = static_cast<int>(total); // return number actually sent here
245
246 return (n == -1) ? -1 : 0; // return -1 on failure, 0 on success
247 }
248
249 inline void
250 Connector::sendRawMsg(const std::vector<char>& buf) {
251 uint32_t bufSize = static_cast<uint32_t>(buf.size());
252 int bufSizeLen = sizeof(uint32_t);
253 sendall(sockfd, reinterpret_cast<char*>(&bufSize), &bufSizeLen);
254 int bufSizeInt = static_cast<int>(bufSize);
255 sendall(sockfd, reinterpret_cast<const char*>(buf.data()), &bufSizeInt);
256 }
257
258 inline void
259 Connector::sendOverSocket(void) {
260 if (!_connected) return;
261
262 std::vector<char> buf = marshalling.serialize();
263
264 sendRawMsg(buf);
265 }
266
267 inline void
269 struct addrinfo hints, *servinfo, *p;
270 int rv;
271
272#ifdef WIN32
273 // Initialise Winsock.
274 WSADATA wsaData;
275 int startupResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
276 if (startupResult != 0) {
277 printf("WSAStartup failed with error: %d\n", startupResult);
278 }
279#endif
280
281 memset(&hints, 0, sizeof hints);
282 hints.ai_family = AF_UNSPEC;
283 hints.ai_socktype = SOCK_STREAM;
284
285 if ((rv = getaddrinfo("localhost", std::to_string(port).c_str(), &hints,
286 &servinfo)) != 0) {
287 std::cerr << "getaddrinfo: " << gai_strerror(rv) << "\n";
288 goto giveup;
289 }
290
291 // loop through all the results and connect to the first we can
292 for (p = servinfo; p != NULL; p = p->ai_next) {
293 if ((sockfd = static_cast<int>(socket(p->ai_family, p->ai_socktype, p->ai_protocol))) == -1) {
294 // errno is set here, but we don't examine it.
295 continue;
296 }
297
298 if (::connect(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
299#ifdef WIN32
300 closesocket(sockfd);
301#else
302 close(sockfd);
303#endif
304 // errno is set here, but we don't examine it.
305 continue;
306 }
307
308 break;
309 }
310
311 // Connection failed; give up.
312 if (p == NULL) {
313 goto giveup;
314 }
315
316 freeaddrinfo(servinfo); // all done with this structure
317
318 _connected = true;
319
320 return;
321 giveup:
322 _connected = false;
323 return;
324
325 }
326
327 inline void
328 Connector::start(const std::string& file_path,
329 int execution_id, bool has_restarts) {
331 std::string base_name(file_path);
332 {
333 size_t pos = base_name.find_last_of('/');
334 if (pos != static_cast<size_t>(-1)) {
335 base_name = base_name.substr(pos + 1, base_name.length() - pos - 1);
336 }
337 }
338
339 std::string info{""};
340 {
341 std::stringstream ss;
342 ss << "{";
343 ss << "\"has_restarts\": " << (has_restarts ? "true" : "false") << "\n";
344 ss << ",\"name\": " << "\"" << base_name << "\"" << "\n";
345 if (execution_id != -1) {
346 ss << ",\"execution_id\": " << execution_id;
347 }
348 ss << "}";
349 info = ss.str();
350 }
351
352 marshalling.makeStart(info);
353 sendOverSocket();
354 }
355
356 inline void
357 Connector::restart(int restart_id) {
358
359 std::string info{""};
360 {
361 std::stringstream ss;
362 ss << "{";
363 ss << "\"restart_id\": " << restart_id << "\n";
364 ss << "}";
365 info = ss.str();
366 }
367
368 marshalling.makeRestart(info);
369 sendOverSocket();
370 }
371
372 inline void
374 marshalling.makeDone();
375 sendOverSocket();
376 }
377
378 inline void
380#ifdef WIN32
381 closesocket(sockfd);
382#else
383 close(sockfd);
384#endif
385 }
386
387 inline void
389 if (!_connected) return;
390
391 auto& msg = marshalling.makeNode(node.nodeUID(), node.parentUID(),
392 node.alt(), node.kids(), node.status());
393
394 if (node.label().valid()) msg.set_label(node.label().value());
395 if (node.nogood().valid()) msg.set_nogood(node.nogood().value());
396 if (node.info().valid()) msg.set_info(node.info().value());
397
398 sendOverSocket();
399 }
400
401 inline Node
403 int alt, int kids, NodeStatus status) {
404 return Node(node, parent, alt, kids, status);
405 }
406
407}}
408
409// STATISTICS: search-trace
int p
Number of positive literals for node type.
int n
Number of negative literals for node type.
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)
Message & makeNode(NodeUID node, NodeUID parent, int32_t alt, int32_t kids, NodeStatus status)
Definition message.hpp:291
void makeStart(const std::string &info)
Definition message.hpp:306
void makeRestart(const std::string &info)
Definition message.hpp:313
void set_label(const std::string &label)
Definition message.hpp:167
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
void set(const T &t)
Set value to t.
Definition message.hpp:94
const T & value(void) const
Access value.
Definition message.hpp:104
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
int32_t rid
Restart id.
Definition message.hpp:118
int32_t tid
Thread id.
Definition message.hpp:120