/usr/include/dashel/dashel.h is in libdashel-dev 1.3.3-5.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 | /*
Dashel
A cross-platform DAta Stream Helper Encapsulation Library
Copyright (C) 2007 -- 2017:
Stephane Magnenat <stephane at magnenat dot net>
(http://stephane.magnenat.net)
Mobots group - Laboratory of Robotics Systems, EPFL, Lausanne
(http://mobots.epfl.ch)
Sebastian Gerlach
Kenzan Technologies
(http://www.kenzantech.com)
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the names of "Mobots", "Laboratory of Robotics Systems", "EPFL",
"Kenzan Technologies" nor the names of the contributors may be used to
endorse or promote products derived from this software without specific
prior written permission.
THIS SOFTWARE IS PROVIDED BY COPYRIGHT HOLDERS ``AS IS'' AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __Dashel_H
#define __Dashel_H
#include <string>
#include <set>
#include <map>
#include <vector>
#include <deque>
#include <stdexcept>
/*! \file dashel.h
\brief Public interface of Dashel, A cross-platform DAta Stream Helper Encapsulation Library
*/
/**
\mainpage Dashel
[github.com/aseba-community/dashel](https://github.com/aseba-community/dashel)
\section IntroSec Introduction
Dashel is a cross-platform data stream helper encapsulation library.
It provides a unified access to TCP/UDP sockets, serial ports, console, and files streams.
It also allows a server application to wait for any activity on any combination of these streams.
Dashel was originally designed by [Stéphane Magnenat](http://stephane.magnenat.net) and Sebastian Gerlach.
A full list of contributors is available in the [README file](https://github.com/aseba-community/dashel/blob/master/readme.md).
Dashel is licensed under a [modified BSD open-source license](http://en.wikipedia.org/wiki/BSD_licenses).
Source code, compilation instructions, authors and license information are available on [github](https://github.com/aseba-community/dashel).
Feel free to [report bugs](https://github.com/aseba-community/dashel/issues/new), fork Dashel and submit [pull requests](https://github.com/aseba-community/dashel/pulls).
\section Usage
To use Dashel, you have to instantiate a Dashel::Hub.
The Hub is your connection with the data streams.
It is the place where you create, destroy, and synchronize them.
The [`example` directory](https://github.com/aseba-community/dashel/tree/master/examples) in Dashel distribution provides several working examples that
you can read to learn to use Dashel.
\section TargetNamingSec Targets naming
In Dashel, streams connect to targets.
A target is a string that describes a file, a TCP/UDP address/port, or a serial port.
This string consists of the type of the target, a colon, followed by a semicolon separated list of parameters.
This list contains key-values pairs, with a predifined order such that keys can be omitted (but if a key is present, all subsequent entries must have an explicit key).
Its general syntax is thus \c "protocol:[param1key=]param1value;...;[paramNkey=]paramNvalue".
The following protocols are available:
\li \c file : local files
\li \c tcp : TCP/IP client
\li \c tcpin : TCP/IP server
\li \c tcppoll : TCP/IP polling
\li \c udp : UDP/IP
\li \c ser : serial port
\li \c stdin : standard input
\li \c stdout : standard output
The file protocol accepts the following parameters, in this implicit order:
\li \c name : name of the file, including the path
\li \c mode : mode (read, write)
The tcp protocol accepts the following parameters, in this implicit order:
\li \c host : remote host
\li \c port : remote port
\li \c socket : local socket; if a nonegative value is given, host and port are ignored
The tcpin protocol accepts the following parameters, in this implicit order:
\li \c port : port
\li \c address : if the computer possesses multiple network addresses, the one to listen on, default 0.0.0.0 (any)
The tcppoll protocol accepts the following parameters, in this implicit order:
\li \c host : remote host
\li \c port : remote port
\li \c socket : local socket; if a nonegative value is given, host and port are ignored
The udp protocol accepts the following parameters, in this implicit order:
\li \c port : port
\li \c address : if the computer possesses multiple network addresses, the one to connect to, default 0.0.0.0 (any)
The ser protocol accepts the following parameters, in this implicit order:
\li \c device : serial port device name, system specific; either port or device must be given, device has priority if both are given.
\li \c name : select the port by matching part of the serial port "user-friendly" description. The match is case-sensitive. Works on Linux and Windows (note: on Linux, this feature requires libudev).
\li \c port : serial port number, starting from 1, default 1
\li \c baud : baud rate, default 115200
\li \c stop : stop bits count (1 or 2), default 1
\li \c parity : parity type (none, even, odd), default none
\li \c fc : flow control type, (none, hard), default none
\li \c bits : number of bits per character, default 8
\li \c dtr : whether DTR line is enabled, default true
Note that either device, name (on supported platforms), or port must be given.
If more than one is given, device has priority, then name, and port has the lowest priority.
Protocols \c stdin and \c stdout do not take any parameter.
*/
//! Dashel, a cross-platform stream abstraction library
namespace Dashel
{
class Stream;
//! version of the Dashel library as string
#define DASHEL_VERSION "1.3.3"
//! version of the Dashel library as an int
#define DASHEL_VERSION_INT 10303
//! The one size fits all exception for streams.
/*!
The reason of the failure is stored in the runtime error, and is returned by what()
*/
class DashelException: public std::runtime_error
{
public:
//! The different exception causes.
typedef enum {
Unknown, //!< Well, hopefully never used.
SyncError, //!< Some synchronisation error.
InvalidTarget, //!< The target string was bad.
InvalidOperation, //!< The operation is not valid on this stream.
ConnectionLost, //!< The connection was lost.
IOError, //!< Some I/O error.
ConnectionFailed, //!< The connection could not be established.
EnumerationError, //!< Some serial enumeration error
PreviousIncomingDataNotRead //!< The incoming data was not read by the Hub subclass
} Source;
//! The exception cause.
Source source;
//! The reason as an OS error code.
int sysError;
//! The stream that caused the exception to be thrown.
Stream *stream;
public:
//! Construct an stream exception with everything.
/*! \param s Source of failure
\param se System error code.
\param reason The logical reason as a human readable string.
\param stream Stream to which exception applies.
*/
DashelException(Source s, int se, const char *reason, Stream* stream = NULL);
protected:
//! Return a string description of the source error
static std::string sourceToString(Source s);
};
//! Serial port enumerator class.
/*! This class is just a package for one static method.
*/
class SerialPortEnumerator
{
public:
//! Retrieve list of all serial ports available on system.
/*! This function queries the Operating System for all available serial ports.
\return A map where the key is the port number name as passed to the ser: protocol, and
the value is a pair of the system device name and a human readable description
that may be displayed in a user interface.
All strings are encoded in UTF-8.
*/
static std::map<int, std::pair<std::string, std::string> > getPorts();
};
//! A IP version 4 address
class IPV4Address
{
public:
unsigned address; //!< IP host address. Stored in local byte order.
unsigned short port; //!< IP port. Stored in local byte order.
public:
//! Constructor. Numeric argument
IPV4Address(unsigned addr = 0, unsigned short prt = 0);
//! Constructor. String address, do resolution
IPV4Address(const std::string& name, unsigned short port);
//! Equality operator
bool operator==(const IPV4Address& o) const;
//! Less than operator
bool operator<(const IPV4Address& o) const;
//! Return Dashel string form
/*!
@param resolveName whether we should attempt resolving the host name of the address
*/
std::string format(const bool resolveName = true) const;
//! Return the hostname corresponding to the address
std::string hostname() const;
//! Is the address valid?
//bool isValid() const;
};
//! Parameter set.
class ParameterSet
{
private:
std::map<std::string, std::string> values;
std::vector<std::string> params;
public:
//! Add values to set.
void add(const char *line);
//! Add a parameter to a set.
/*!
* @param param name of the parameter
* @param value value of the parameter or NULL (then parameter will default or pre-existing value)
* @param atStart if true, insert parameter at start of the list
*/
void addParam(const char *param, const char *value = NULL, bool atStart = false);
//! Return whether a key is set or not
bool isSet(const char *key) const;
//! Get a parameter value.
//! Explicitely instantiated for int, unsigned, float and double in the library
template<typename T> T get(const char *key) const;
//! Get a parameter value
const std::string& get(const char *key) const;
//! Get the parameters as string.
std::string getString() const;
//! Erase the parameter from the set
void erase(const char *key);
};
//! A data stream, with low-level (not-endian safe) read/write functions
class Stream
{
private:
//! A flag indicating that the stream has failed.
bool failedFlag;
//! The human readable reason describing why the stream has failed.
std::string failReason;
protected:
//! The target description.
ParameterSet target;
//! The protocol name.
std::string protocolName;
protected:
friend class Hub;
//! Constructor.
explicit Stream(const std::string& protocolName) : failedFlag(false), protocolName(protocolName) {}
//! Virtual destructor, to ensure calls to destructors of sub-classes.
virtual ~Stream() { /* intentionally blank */ }
public:
//! Set stream to failed state
/*! \param s Source of failure
\param se System error code
\param reason The logical reason as a human readable string.
*/
void fail(DashelException::Source s, int se, const char* reason);
//! Query failed state of stream.
/*! \return true if stream has failed.
*/
bool failed() const { return failedFlag; }
//! Returns the reason the stream has failed.
/*! \return the reason the stream has failed, or an empty string if fail() is false.
*/
const std::string &getFailReason() const { return failReason; }
//! Returns the protocol name of the stream.
const std::string &getProtocolName() const { return protocolName; }
//! Returns the name of the target.
/*! The name of the target contains all parameters and the protocol name.
\return Name of the target
*/
std::string getTargetName() const { return protocolName + ":" + target.getString(); }
//! Returns the value of a parameter extracted from the target.
/*! \param param the name of the parameter
\return A string containing the parameter.
*/
const std::string &getTargetParameter(const char *param) const { return target.get(param); }
//! Returns the target description.
/*! \return The set of parameters describing this target
*/
const ParameterSet getTarget() const { return target; }
//! Write data to the stream.
/*! Writes all requested data to the stream, blocking until all the data has been written, or
some error occurs. Errors are signaled by throwing a DashelException exception. This function
does not flush devices, therefore the data may not really have been written on return, but only
been buffered. In order to flush the stream, call flush().
\param data Pointer to the data to write.
\param size Amount of data to write in bytes.
*/
virtual void write(const void *data, const size_t size) = 0;
//! Write a variable of basic type to the stream
/*! This function does not perform any endian conversion.
\param v variable to write.
*/
template<typename T> void write(T v)
{
write(&v, sizeof(T));
}
//! Flushes stream.
/*! Calling this function requests the stream to be flushed, this may ensure that data is written
to physical media or actually sent over a wire. The exact performed function depends on the
stream type and operating system.
*/
virtual void flush() = 0;
//! Reads data from the stream.
/*! Reads all requested data from the stream, blocking until all the data has been read, or
some error occurs. Errors are signaled by throwing a DashelException exception, which may
be caused either by device errors or reaching the end of file.
\param data Pointer to the memory where the read data should be stored.
\param size Amount of data to read in bytes.
*/
virtual void read(void *data, size_t size) = 0;
//! Read a variable of basic type from the stream
/*! This function does not perform any endian conversion.
\return variable to read.
*/
template<typename T> T read()
{
T v;
read(&v, sizeof(T));
return v;
}
};
//! A data stream, that can be later send data as at UDP packet or read data from an UDP packet
/*!
You can use PacketStream to write and read data as with normal stream, with the difference
that:
* written byte will be collected in a send buffer until send() is called with the destination
address; if you have written too much byte for send to transmit all of them an exception will occur.
However, the underlying operating system may pretend that all data has been transmitted while discarding some of it anyway. In any case, send less bytes than ethernet MTU minus UDP header.
* you have to call receive() when there are bytes available on the stream to be able to read them; if your read past the received bytes an exception will occur.
*/
class PacketStream: virtual public Stream
{
public:
//! Constructor
explicit PacketStream(const std::string& protocolName) : Stream(protocolName) { }
//! Send all written data to an IP address in a single packet.
/*!
\param dest IP address to send packet to
*/
virtual void send(const IPV4Address& dest) = 0;
//! Receive a packet and make its payload available for reading.
/*!
Block until a packet is available.
\param source IP address from where the packet originates.
*/
virtual void receive(IPV4Address& source) = 0;
};
/**
The central place where to create, destroy, and synchronize streams.
To create a client connection, users of the library have to subclass Hub
and implement connectionCreated(), incomingData(), and connectionClosed().
*/
class Hub
{
public:
//! A list of streams
typedef std::set<Stream*> StreamsSet;
private:
void *hTerminate; //!< Set when this thing goes down.
void *streamsLock; //!< Platform-dependant mutex to protect access to streams
StreamsSet streams; //!< All our streams.
protected:
StreamsSet dataStreams; //!< All our streams that transfer data (in opposition to streams that just listen for data).
public:
const bool resolveIncomingNames; //!< Whether Dashel should try to resolve the peer's hostname of incoming TCP connections
public:
/** Constructor.
\param resolveIncomingNames if true, try to resolve the peer's hostname of incoming TCP connections
*/
explicit Hub(const bool resolveIncomingNames = true);
//! Destructor, closes all connections.
virtual ~Hub();
/**
Listens for incoming connections on a target.
Some targets, such as a serial ports and files may directly generate a new connection;
others, such as network interfaces, will only generate news connections when a peer
connects.
May throw a ConnectionError exception if the target does not exists or is not ready.
\param target destination to listen connections from (see Section \ref TargetNamingSec)
\return the stream we are connected to; if connect was not possible, an exception was throw.
*/
Stream* connect(const std::string &target);
/**
Close a stream, remove it from the Hub, and delete it.
If the stream is not present in the Hub, it is deleted nevertheless.
Note that connectionClosed() is not called by closeStream() and that
you must not call closeStream() from inside connectionCreated(),
connectionClosed() or incomingData().
\param stream stream to remove
*/
void closeStream(Stream* stream);
/** Runs and returns only when an external event requests the application to stop.
*/
void run();
/**
Waits for data from the transfers streams or connections from the listening streams.
Read all available data.
\param timeout if -1, waits until data arrive. If 0, do not wait, just poll for activity. If positive, waits at maximum timeout ms.
\return false if stop() was called or the application was requested to terminate, true otherwise.
*/
bool step(const int timeout = 0);
//! Stops running, subclasses or external code may call this function, that is the only thread-safe function of the Hub
void stop();
/** Block any hub processing so another thread can access the streams safely.
*/
void lock();
/** Release the lock aquired by lock().
*/
void unlock();
protected:
/**
Called when any data connection is created.
It is not called when a listening connection (eg tcpin:) is created.
If the stream is closed during this method, an exception occurs: the caller is responsible to handle it.
The stream is already inserted in the stream list when this function is called.
Subclass can implement this method.
Called with the stream lock held.
\param stream stream to the target
*/
virtual void connectionCreated(Stream * stream) { /* hook for use by derived classes */ }
/**
Called when data is available for reading on the stream.
If the stream is closed during this method, an exception occurs: Hub stops the execution of this
method and calls connectionClosed(); objects dynamically allocated must thus be handled
with auto_ptr.
If step() is used, subclass must implement this method and call read at least once.
Called with the stream lock held.
\param stream stream to the target
*/
virtual void incomingData(Stream * stream) { /* hook for use by derived classes */ }
/**
Called when target closes connection.
The only valid method to call on the stream is getTargetName(), input/output operations are forbidden.
You must not call closeStream(stream) from within this method for the same stream as the
one passed as parameter.
Subclass can implement this method.
Called with the stream lock held.
\param stream stream to the target.
\param abnormal whether the connection was closed during step (abnormal == false) or when an operation was performed (abnormal == true)
*/
virtual void connectionClosed(Stream * stream, bool abnormal) { /* hook for use by derived classes */ }
};
//! Registry of constructors to a stream, to add new stream types dynamically
struct StreamTypeRegistry
{
//! A function which creates an instance of a stream
typedef Stream* (*CreatorFunc)(const std::string& target, const Hub& hub);
//! Register known stream types, implemented in different platform-specific files
StreamTypeRegistry();
//! Register a new stream type
void reg(const std::string& proto, const CreatorFunc func);
//! Create a stream of a given type, return 0 if type does not exist
Stream* create(const std::string& proto, const std::string& target, const Hub& hub) const;
//! Return list of stream types
std::string list() const;
protected:
//! a map of stream type names to constructors and arguments
typedef std::map<std::string, CreatorFunc> CreatorMap;
//! streams that can be created
CreatorMap creators;
};
//! Create an instance of stream type C, passing target to its constructor
template<typename C>
Stream* createInstance(const std::string& target, const Hub& hub)
{
return new C(target);
}
//! Create an instance of stream type C, passing target to its constructor
template<typename C>
Stream* createInstanceWithHub(const std::string& target, const Hub& hub)
{
return new C(target, hub);
}
//! The registry of all known stream types
extern StreamTypeRegistry streamTypeRegistry;
}
#endif
|