1 Star 0 Fork 1

upczap/vrpn

forked from ianaxe/vrpn 
加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
vrpn_Connection.h 45.04 KB
一键复制 编辑 原始数据 按行查看 历史
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183
#ifndef VRPN_CONNECTION_H
#define VRPN_CONNECTION_H
#include <stdio.h> // for NULL, sprintf
#include "vrpn_Configure.h" // for VRPN_API, VRPN_CALLBACK, etc
#include "vrpn_Shared.h" // for SOCKET, timeval
#include "vrpn_Types.h" // for vrpn_int32, vrpn_uint32, etc
#include "vrpn_EndpointContainer.h"
#if !(defined(_WIN32) && defined(VRPN_USE_WINSOCK_SOCKETS))
#include <sys/select.h> // for fd_set
#endif
struct timeval;
// Don't complain about using sprintf() when using Visual Studio.
#ifdef _MSC_VER
#pragma warning(disable : 4995 4996)
#endif
/// This is the list of states that a connection can be in
/// (possible values for status). doing_okay() returns VRPN_TRUE
/// for connections > BROKEN.
enum vrpn_ConnectionStatus {
LISTEN = (1),
CONNECTED = (0),
COOKIE_PENDING = (-1),
TRYING_TO_CONNECT = (-2),
BROKEN = (-3),
LOGGING = (-4)
};
class VRPN_API
vrpn_File_Connection; // Forward declaration for get_File_Connection()
/// @brief This structure is what is passed to a vrpn_Connection message
/// callback.
///
/// It is used by objects, but not normally by user code.
struct vrpn_HANDLERPARAM {
vrpn_int32 type;
vrpn_int32 sender;
struct timeval msg_time;
vrpn_int32 payload_len;
const char *buffer;
};
/// @brief Type of a message handler for vrpn_Connection messages.
typedef int(VRPN_CALLBACK *vrpn_MESSAGEHANDLER)(void *userdata,
vrpn_HANDLERPARAM p);
/// @brief Type of handler for filters on logfiles is the same as connection
/// handler
typedef vrpn_MESSAGEHANDLER vrpn_LOGFILTER;
/// VRPN buffers are aligned on 8 byte boundaries so that we can pack and
/// unpack doubles into them on architectures that cannot handle unaligned
/// access.
const unsigned vrpn_ALIGN = 8;
/// Types now have their storage dynamically allocated, so we can afford
/// to have large tables. We need at least 150-200 for the microscope
/// project as of Jan 98, and will eventually need two to three times that
/// number.
/// @{
const int vrpn_CONNECTION_MAX_SENDERS = 2000;
const int vrpn_CONNECTION_MAX_TYPES = 2000;
/// @}
/// @brief vrpn_ANY_SENDER can be used to register callbacks on a given message
/// type from any sender.
const int vrpn_ANY_SENDER = -1;
/// @brief vrpn_ANY_TYPE can be used to register callbacks for any USER type of
/// message from a given sender. System messages are handled separately.
const int vrpn_ANY_TYPE = -1;
/// @name Buffer lengths for TCP and UDP.
///
/// TCP is an arbitrary number but it must match the receiver's buffer
/// size so it needs to remain the same for a given major VRPN version
/// number.
/// UDP is set based on Ethernet maximum transmission size; trying
/// to send a message via UDP which is longer than the MTU of any
/// intervening physical network may cause untraceable failures,
/// so for now we do not expose any way to change the UDP output
/// buffer size. (MTU = 1500 bytes, - 28 bytes of IP+UDP header)
/// @{
const int vrpn_CONNECTION_TCP_BUFLEN = 64000;
const int vrpn_CONNECTION_UDP_BUFLEN = 1472;
/// @}
/// @brief Number of endpoints that a server connection can have. Arbitrary
/// limit.
const int vrpn_MAX_ENDPOINTS = 256;
/// @name System message types
/// @{
const vrpn_int32 vrpn_CONNECTION_SENDER_DESCRIPTION = (-1);
const vrpn_int32 vrpn_CONNECTION_TYPE_DESCRIPTION = (-2);
const vrpn_int32 vrpn_CONNECTION_UDP_DESCRIPTION = (-3);
const vrpn_int32 vrpn_CONNECTION_LOG_DESCRIPTION = (-4);
const vrpn_int32 vrpn_CONNECTION_DISCONNECT_MESSAGE = (-5);
/// @}
/// Classes of service for messages, specify multiple by ORing them together
/// Priority of satisfying these should go from the top down (RELIABLE will
/// override all others).
/// Most of these flags may be ignored, but RELIABLE is guaranteed
/// to be available.
/// @{
const vrpn_uint32 vrpn_CONNECTION_RELIABLE = (1 << 0);
const vrpn_uint32 vrpn_CONNECTION_FIXED_LATENCY = (1 << 1);
const vrpn_uint32 vrpn_CONNECTION_LOW_LATENCY = (1 << 2);
const vrpn_uint32 vrpn_CONNECTION_FIXED_THROUGHPUT = (1 << 3);
const vrpn_uint32 vrpn_CONNECTION_HIGH_THROUGHPUT = (1 << 4);
/// @}
/// @name What to log
/// @{
const long vrpn_LOG_NONE = (0);
const long vrpn_LOG_INCOMING = (1 << 0);
const long vrpn_LOG_OUTGOING = (1 << 1);
/// @}
// If defined, will filter out messages: if the remote side hasn't
// registered a type, messages of that type won't be sent over the
// link. WARNING: auto-type-registration breaks this.
//#define vrpn_FILTER_MESSAGES
/// These are the strings that define the system-generated message
/// types that tell when connections are received and dropped.
/// @{
extern VRPN_API const char *vrpn_got_first_connection;
extern VRPN_API const char *vrpn_got_connection;
extern VRPN_API const char *vrpn_dropped_connection;
extern VRPN_API const char *vrpn_dropped_last_connection;
/// @}
/// @brief vrpn_CONTROL is the sender used for notification messages sent to the
/// user
/// from the local VRPN implementation (got_first_connection, etc.)
/// and for control messages sent by auxiliary services. (Such as
/// class vrpn_Controller, which will be introduced in a future revision.)
extern VRPN_API const char *vrpn_CONTROL;
/// @brief Length of names within VRPN
typedef char cName[100];
/// Placed here so vrpn_FileConnection can use it too.
struct VRPN_API vrpn_LOGLIST {
vrpn_HANDLERPARAM data;
vrpn_LOGLIST *next;
vrpn_LOGLIST *prev;
};
class VRPN_API vrpn_Endpoint_IP;
class VRPN_API vrpn_Connection;
/// @brief Function pointer to an endpoint allocator.
typedef vrpn_Endpoint_IP *(*vrpn_EndpointAllocator)(
vrpn_Connection *connection, vrpn_int32 *numActiveConnections);
namespace vrpn {
/// @brief Combines the function pointer for an Endpoint Allocator with its
/// two arguments into a single callable object, with the ability to
/// override the last parameter at call time.
class BoundEndpointAllocator {
public:
BoundEndpointAllocator()
: epa_(NULL)
, conn_(NULL)
, numActiveEndpoints_(NULL)
{
}
BoundEndpointAllocator(vrpn_EndpointAllocator epa,
vrpn_Connection *conn,
vrpn_int32 *numActiveEndpoints = NULL)
: epa_(epa)
, conn_(conn)
, numActiveEndpoints_(numActiveEndpoints)
{
}
typedef vrpn_Endpoint_IP *return_type;
/// @brief Default, fully pre-bound
return_type operator()() const
{
if (!epa_) {
return NULL;
}
return (*epa_)(conn_, numActiveEndpoints_);
}
/// @brief Overload, with alternate num active connnection pointer.
return_type operator()(vrpn_int32 *alternateNumActiveEndpoints) const
{
if (!epa_) {
return NULL;
}
return (*epa_)(conn_, alternateNumActiveEndpoints);
}
private:
vrpn_EndpointAllocator epa_;
vrpn_Connection *conn_;
vrpn_int32 *numActiveEndpoints_;
};
} // namespace vrpn
/// @todo HACK
/// These structs must be declared outside of vrpn_Connection
/// (although we'd like to make them protected/private members)
/// because aCC on PixelFlow doesn't handle nested classes correctly.
/// @{
/// @brief Description of a callback entry for a user type.
struct vrpnMsgCallbackEntry {
vrpn_MESSAGEHANDLER handler; ///< Routine to call
void *userdata; ///< Passed along
vrpn_int32 sender; ///< Only if from sender
vrpnMsgCallbackEntry *next; ///< Next handler
};
struct vrpnLogFilterEntry {
vrpn_LOGFILTER filter; ///< routine to call
void *userdata; ///< passed along
vrpnLogFilterEntry *next;
};
/// @}
class VRPN_API vrpn_Connection;
class VRPN_API vrpn_Log;
class VRPN_API vrpn_TranslationTable;
class VRPN_API vrpn_TypeDispatcher;
/// @brief Encapsulation of the data and methods for a single generic connection
/// to take care of one part of many clients talking to a single server.
///
/// This will only be used from within the vrpn_Connection class; it should
/// not be instantiated by users or devices.
/// Should not be visible!
class VRPN_API vrpn_Endpoint {
public:
vrpn_Endpoint(vrpn_TypeDispatcher *dispatcher,
vrpn_int32 *connectedEndpointCounter);
virtual ~vrpn_Endpoint(void);
/// @name Accessors
/// @{
/// Returns the local mapping for the remote type (-1 if none).
int local_type_id(vrpn_int32 remote_type) const;
/// Returns the local mapping for the remote sender (-1 if none).
int local_sender_id(vrpn_int32 remote_sender) const;
virtual vrpn_bool doing_okay(void) const = 0;
/// @}
/// @name Manipulators
/// @{
void init(void);
virtual int mainloop(timeval *timeout) = 0;
/// Clear out the remote mapping list. This is done when a
/// connection is dropped and we want to try and re-establish
/// it.
void clear_other_senders_and_types(void);
/// A new local sender or type has been established; set
/// the local type for it if the other side has declared it.
/// Return 1 if the other side has one, 0 if not.
int newLocalSender(const char *name, vrpn_int32 which);
int newLocalType(const char *name, vrpn_int32 which);
/// Adds a new remote type/sender and returns its index.
/// Returns -1 on error.
/// @{
int newRemoteType(cName type_name, vrpn_int32 remote_id,
vrpn_int32 local_id);
int newRemoteSender(cName sender_name, vrpn_int32 remote_id,
vrpn_int32 local_id);
/// @}
/// Pack a message that will be sent the next time mainloop() is called.
/// Turn off the RELIABLE flag if you want low-latency (UDP) send.
virtual int pack_message(vrpn_uint32 len, struct timeval time,
vrpn_int32 type, vrpn_int32 sender,
const char *buffer,
vrpn_uint32 class_of_service) = 0;
/// send pending report, clear the buffer.
/// This function was protected, now is public, so we can use it
/// to send out intermediate results without calling mainloop
virtual int send_pending_reports(void) = 0;
int pack_log_description(void);
///< Packs the log description set by setup_new_connection().
virtual int setup_new_connection(void) = 0;
///< Sends the magic cookie and other information to its
///< peer. It is called by both the client and server setup routines.
virtual void poll_for_cookie(const timeval *timeout = NULL) = 0;
virtual int finish_new_connection_setup(void) = 0;
virtual void drop_connection(void) = 0;
///< Should only be called by vrpn_Connection::drop_connection(),
///< since there's more housecleaning to do at that level. I suppose
///< that argues against separating this function out.
virtual void clearBuffers(void) = 0;
///< Empties out the TCP and UDP send buffers.
///< Needed by vrpn_FileConnection to get at {udp,tcp}NumOut.
int pack_sender_description(vrpn_int32 which);
///< Packs a sender description over our socket.
int pack_type_description(vrpn_int32 which);
///< Packs a type description.
/// @}
int status;
/// @todo XXX These should be protected; making them so will lead to making
/// the code split the functions between Endpoint and Connection
/// protected:
long d_remoteLogMode; ///< Mode to put the remote logging in
char *d_remoteInLogName; ///< Name of the remote log file
char *d_remoteOutLogName; ///< Name of the remote log file
///< Name of the remote host we are connected to. This is kept for
///< informational purposes. It is printed by the ceiling server,
///< for example.
char rhostname[150];
/// @name Logging
///
/// TCH 19 April 00; changed into two logs 16 Feb 01
/// @{
vrpn_Log *d_inLog;
vrpn_Log *d_outLog;
void setLogNames(const char *inName, const char *outName);
int openLogs(void);
/// @}
/// @name Routines that handle system messages
///
/// Visible so that vrpn_Connection can pass them to the Dispatcher
/// @{
static int VRPN_CALLBACK
handle_sender_message(void *userdata, vrpn_HANDLERPARAM p);
static int VRPN_CALLBACK
handle_type_message(void *userdata, vrpn_HANDLERPARAM p);
/// @}
/// @name Routines to inform the endpoint of the connection of
/// which it is a part.
/// @{
void setConnection(vrpn_Connection *conn) { d_parent = conn; }
vrpn_Connection *getConnection() { return d_parent; }
/// @}
protected:
virtual int dispatch(vrpn_int32 type, vrpn_int32 sender, timeval time,
vrpn_uint32 payload_len, char *bufptr);
int tryToMarshall(char *outbuf, vrpn_int32 &buflen, vrpn_int32 &numOut,
vrpn_uint32 len, timeval time, vrpn_int32 type,
vrpn_int32 sender, const char *buffer,
vrpn_uint32 classOfService);
///< Calls marshall_message(); if that fails, calls
///< send_pending_reports() and then marshalls again.
///< Returns the number of characters successfully marshalled.
int marshall_message(char *outbuf, vrpn_uint32 outbuf_size,
vrpn_uint32 initial_out, vrpn_uint32 len,
struct timeval time, vrpn_int32 type,
vrpn_int32 sender, const char *buffer,
vrpn_uint32 sequenceNumber);
// The senders and types we know about that have been described by
// the other end of the connection. Also, record the local mapping
// for ones that have been described with the same name locally.
// The arrays are indexed by the ID from the other side, and store
// the name and local ID that corresponds to each.
vrpn_TranslationTable *d_senders;
vrpn_TranslationTable *d_types;
vrpn_TypeDispatcher *d_dispatcher;
vrpn_int32 *d_connectionCounter;
vrpn_Connection *d_parent;
};
/// @brief Encapsulation of the data and methods for a single IP-based
/// connection
/// to take care of one part of many clients talking to a single server.
///
/// This will only be used from within the vrpn_Connection_IP class; it should
/// not be instantiated by users or devices.
/// Should not be visible!
class VRPN_API vrpn_Endpoint_IP : public vrpn_Endpoint {
public:
vrpn_Endpoint_IP(vrpn_TypeDispatcher *dispatcher,
vrpn_int32 *connectedEndpointCounter);
virtual ~vrpn_Endpoint_IP(void);
/// @name Accessors
/// @{
virtual vrpn_bool doing_okay(void) const;
/// True if the UDP outbound is open, False if not.
vrpn_bool outbound_udp_open(void) const;
vrpn_int32 tcp_outbuf_size(void) const;
vrpn_int32 udp_outbuf_size(void) const;
/// @}
/// @name Manipulators
/// @{
void init(void);
int mainloop(timeval *timeout);
/// @brief Pack a message that will be sent the next time mainloop() is
/// called.
///
/// Turn off the RELIABLE flag if you want low-latency (UDP) send.
int pack_message(vrpn_uint32 len, struct timeval time, vrpn_int32 type,
vrpn_int32 sender, const char *buffer,
vrpn_uint32 class_of_service);
/// @brief send pending report, clear the buffer.
///
/// This function was protected, now is public, so we can use it
/// to send out intermediate results without calling mainloop
virtual int send_pending_reports(void);
int pack_udp_description(int portno);
int handle_tcp_messages(const timeval *timeout);
int handle_udp_messages(const timeval *timeout);
int connect_tcp_to(const char *msg);
int connect_tcp_to(const char *addr, int port);
///< Connects d_tcpSocket to the specified address (msg = "IP port");
///< sets status to COOKIE_PENDING; returns 0 on success, -1 on failure
int connect_udp_to(const char *addr, int port);
///< Connects d_udpSocket to the specified address and port;
///< returns 0 on success, sets status to BROKEN and returns -1
///< on failure.
int setup_new_connection(void);
///< Sends the magic cookie and other information to its
///< peer. It is called by both the client and server setup routines.
void poll_for_cookie(const timeval *timeout = NULL);
int finish_new_connection_setup(void);
void drop_connection(void);
///< Should only be called by vrpn_Connection::drop_connection(),
///< since there's more housecleaning to do at that level. I suppose
///< that argues against separating this function out.
void clearBuffers(void);
///< Empties out the TCP and UDP send buffers.
///< Needed by vrpn_FileConnection to get at {udp,tcp}NumOut.
void setNICaddress(const char *);
/// @todo XXX These should be protected; making them so will lead to making
/// the code split the functions between Endpoint and Connection
/// protected:
SOCKET d_tcpSocket;
/// This section deals with when a client connection is trying to
/// establish (or re-establish) a connection with its server. It
/// keeps track of what we need to know to make this happen.
SOCKET d_tcpListenSocket;
int d_tcpListenPort;
///< Socket and port that the client listens on
///< when lobbing datagrams at the server and
///< waiting for it to call back.
/// Socket to use to lob UDP requests asking for the server to
/// call us back.
SOCKET d_udpLobSocket;
char *d_remote_machine_name; ///< Machine to call
int d_remote_port_number; ///< Port to connect to on remote machine
timeval d_last_connect_attempt; ///< When the last UDP lob occurred
vrpn_bool d_tcp_only;
///< For connections made through firewalls or NAT with the
///< tcp: URL, we do not want to allow the endpoints on either
///< end to open a UDP link to their counterparts. If this is
///< the case, then this flag should be set to true.
protected:
int getOneTCPMessage(int fd, char *buf, size_t buflen);
int getOneUDPMessage(char *buf, size_t buflen);
SOCKET d_udpOutboundSocket;
SOCKET d_udpInboundSocket;
///< Inbound unreliable messages come here.
///< Need one for each due to different
///< clock synchronization for each; we
///< need to know which server each message is from.
///< @todo XXX Now that we don't need multiple clocks, can we collapse this?
char *d_tcpOutbuf;
char *d_udpOutbuf;
vrpn_int32 d_tcpBuflen;
vrpn_int32 d_udpBuflen;
vrpn_int32 d_tcpNumOut;
vrpn_int32 d_udpNumOut;
vrpn_int32 d_tcpSequenceNumber;
vrpn_int32 d_udpSequenceNumber;
vrpn_float64
d_tcpAlignedInbuf[vrpn_CONNECTION_TCP_BUFLEN / sizeof(vrpn_float64) +
1];
vrpn_float64
d_udpAlignedInbuf[vrpn_CONNECTION_UDP_BUFLEN / sizeof(vrpn_float64) +
1];
char *d_tcpInbuf;
char *d_udpInbuf;
char *d_NICaddress;
};
/// @brief Generic connection class not specific to the transport mechanism.
///
/// It abstracts all of the common functions. Specific implementations
/// for IP, MPI, and other transport mechanisms follow.
class VRPN_API vrpn_Connection {
protected:
/// Constructor for server connection. This cannot be called
/// directly any more because vrpn_Connection is an abstract base
/// class. Call vrpn_create_server_connection() to make a server
/// of arbitrary type based on a name.
vrpn_Connection(const char *local_in_logfile_name,
const char *local_out_logfile_name,
vrpn_EndpointAllocator epa = allocateEndpoint);
/// Constructor for client connection. This cannot be called
/// directly because vrpn_Connection is an abstract base class.
/// Call vrpn_get_connection_by_name() to create a client connection.
vrpn_Connection(const char *local_in_logfile_name,
const char *local_out_logfile_name,
const char *remote_in_logfile_name,
const char *remote_out_logfile_name,
vrpn_EndpointAllocator epa = allocateEndpoint);
public:
virtual ~vrpn_Connection(void);
/// Returns vrpn_true if the connection is okay, vrpn_false if not
virtual vrpn_bool doing_okay(void) const;
/// Returns vrpn_true if the connection has been established, vrpn_false if
/// not
/// (For a networkless connection, this is equivalent to doing_okay()).
virtual vrpn_bool connected(void) const;
/// This function returns the logfile names of this connection in
/// the parameters. It will allocate memory for the name of each
/// log file in use. If no logging of a particular type is happening,
/// then *(X_Y_logname) will be set to NULL.
/// IMPORTANT: code calling this function is responsible for freeing
/// the memory allocated for these strings.
void get_log_names(char **local_in_logname, char **local_out_logname,
char **remote_in_logname, char **remote_out_logname);
/// Call each time through program main loop to handle receiving any
/// incoming messages and sending any packed messages.
/// Returns -1 when connection dropped due to error, 0 otherwise.
/// (only returns -1 once per connection drop).
/// Optional argument is TOTAL time to block on select() calls;
/// there may be multiple calls to select() per call to mainloop(),
/// and this timeout will be divided evenly between them.
virtual int mainloop(const struct timeval *timeout = NULL) = 0;
/// Get a token to use for the string name of the sender or type.
/// Remember to check for -1 meaning failure.
virtual vrpn_int32 register_sender(const char *name);
virtual vrpn_int32 register_message_type(const char *name);
/// Set up (or remove) a handler for a message of a given type.
/// Optionally, specify which sender to handle messages from.
/// Handlers will be called during mainloop().
/// Your handler should return 0 or a communication error is assumed
/// and the connection will be shut down.
virtual int register_handler(vrpn_int32 type, vrpn_MESSAGEHANDLER handler,
void *userdata,
vrpn_int32 sender = vrpn_ANY_SENDER);
virtual int unregister_handler(vrpn_int32 type, vrpn_MESSAGEHANDLER handler,
void *userdata,
vrpn_int32 sender = vrpn_ANY_SENDER);
/// Pack a message that will be sent the next time mainloop() is called.
/// Turn off the RELIABLE flag if you want low-latency (UDP) send.
virtual int pack_message(vrpn_uint32 len, struct timeval time,
vrpn_int32 type, vrpn_int32 sender,
const char *buffer, vrpn_uint32 class_of_service);
/// send pending report, clear the buffer.
/// This function was protected, now is public, so we can use it
/// to send out intermediate results without calling mainloop
virtual int send_pending_reports(void) = 0;
/// Returns the time since the connection opened.
/// Some subclasses may redefine time.
virtual int time_since_connection_open(struct timeval *elapsed_time);
/// returns the current time in the connection (since the epoch -- UTC
/// time).
virtual timeval get_time();
/// Returns the name of the specified sender/type, or NULL
/// if the parameter is invalid. Only works for user
/// messages (type >= 0).
virtual const char *sender_name(vrpn_int32 sender);
virtual const char *message_type_name(vrpn_int32 type);
/// @brief Sets up a filter function for logging.
/// Any user message to be logged is first passed to this function,
/// and will only be logged if the function returns zero (XXX).
/// NOTE: this only affects local logging - remote logging
/// is unfiltered! Only user messages are filtered; all system
/// messages are logged.
/// Returns nonzero on failure.
virtual int register_log_filter(vrpn_LOGFILTER filter, void *userdata);
/// Save any messages on any endpoints which have been logged so far.
virtual int save_log_so_far();
/// vrpn_File_Connection implements this as "return this" so it
/// can be used to detect a File_Connection and get the pointer for it
virtual vrpn_File_Connection *get_File_Connection(void);
/// This function should be seldom used. It is here for the case of
/// the vrpn_Imager, whose servers do not follow "The VRPN Way" because
/// they try to jam more data into the network than there is bandwidth
/// to support it. As a result, a client may call mainloop() on the
/// connection and have it never return -- there is always more data
/// in the network to read, so we never hand control back to the main
/// program. The reason for the name comes from an old U.S. cartoon
/// called "The Jetsons". In it, George Jetson is running on a
/// treadmill when it goes out of control and starts spinning so fast
/// that he can't even run fast enough to reach the controls and turn
/// it off. He cries out to his wife, "Jane! Stop this crazy thing!"
/// The parameter specifies a trigger: if more than the specified number
/// of messages come in on a given input channel during one mainloop()
/// call, the connection should stop looking for more messages. NOTE:
/// this does not guarantee that only this many messages will be received,
/// only that the connection will stop looking for new ones on a given
/// channel once that many have been received (for example, UDP channels
/// will parse all the rest of the messages in a packet before stopping).
/// A value of 0 turns off the limit, and will cause all incoming messages
/// to be handled before returning.
void Jane_stop_this_crazy_thing(vrpn_uint32 stop_looking_after)
{
d_stop_processing_messages_after = stop_looking_after;
};
vrpn_uint32 get_Jane_value(void)
{
return d_stop_processing_messages_after;
};
protected:
/// If this value is greater than zero, the connection should stop
/// looking for new messages on a given endpoint after this many
/// are found.
vrpn_uint32 d_stop_processing_messages_after;
int connectionStatus; ///< Status of the connection
/// Redefining this and passing it to constructors
/// allows a subclass to use a different subclass of Endpoint.
/// It should do NOTHING but return an endpoint
/// of the appropriate class; it may not access subclass data,
/// since it'll be called from a constructor
static vrpn_Endpoint_IP *allocateEndpoint(vrpn_Connection *,
vrpn_int32 *connectedEC);
#ifdef _MSC_VER
#pragma warning(push)
// Disable "need dll interface" warning on these members
#pragma warning(disable : 4251)
#endif
/// Function object wrapping an endpoint allocator and binding its
/// arguments.
vrpn::BoundEndpointAllocator d_boundEndpointAllocator;
/// Sockets used to talk to remote Connection(s)
/// and other information needed on a per-connection basis
vrpn::EndpointContainer d_endpoints;
#ifdef _MSC_VER
#pragma warning(pop)
#endif
vrpn_int32 d_numConnectedEndpoints;
///< We need to track the number of connected endpoints separately
///< to properly send out got-first-connection/dropped-last-connection
///< messages. This value is *managed* by the Endpoints, but we
///< need exactly one copy per Connection, so it's on the Connection.
/// @brief Routines that handle system messages
/// @{
static int VRPN_CALLBACK
handle_log_message(void *userdata, vrpn_HANDLERPARAM p);
static int VRPN_CALLBACK
handle_disconnect_message(void *userdata, vrpn_HANDLERPARAM p);
/// @}
private:
void init(vrpn_EndpointAllocator
epa); ///< Base initialization for all constructors.
protected:
int delete_endpoint(vrpn_Endpoint *endpoint);
int compact_endpoints(void);
virtual int pack_sender_description(vrpn_int32 which);
///< Send the sender description to ALL endpoints.
virtual int pack_type_description(vrpn_int32 which);
///< Send the type description to ALL endpoints.
virtual int do_callbacks_for(vrpn_int32 type, vrpn_int32 sender,
struct timeval time, vrpn_uint32 len,
const char *buffer);
/// Returns message type ID, or -1 if unregistered
int message_type_is_registered(const char *) const;
/// Timekeeping - TCH 30 June 98
timeval start_time;
//
/// Counting references to this connection.
public:
void addReference();
void removeReference();
private:
int d_references;
//
/// Specify whether this connection should be deleted automatically when
/// it is no longer need (reference count reaches zero).
/// For connections created by the VRPN code (as is done in
/// get_connection_by_name) these should be auto-deleted.
/// Connections created by user code should not be auto-deleted;
/// that is up to the user to decide when finished.
/// By default, the constructor sets this to FALSE.
/// VRPN code (or user code) can set this to TRUE if it wants the
/// connection to be deleted automatically when the last service on it
/// is deleted
public:
void setAutoDeleteStatus(bool setvalue) { d_autoDeleteStatus = setvalue; }
private:
bool d_autoDeleteStatus; ///< FALSE by default.
public:
/// Derived classes need access to d_dispatcher in their
/// allocateEndpoint() routine. Several compilers won't give it to
/// them, even if they do inherit publicly. Until we figure that
/// out, d_dispatcher needs to be public.
vrpn_TypeDispatcher *d_dispatcher;
protected:
int doSystemCallbacksFor(vrpn_HANDLERPARAM, void *);
/// Server logging w. multiconnection - TCH July 00
/// Use one "hidden" endpoint for outgoing logs (?),
/// standard per-endpoint logs with augmented names for incoming.
/// To make a hidden endpoint we create d_endpoints[0] and increment
/// the d_numEndpoints, but DON'T pass it d_numConnectedEndpoints
/// (although it should be safe to do so, since it should never truly
/// become connected, but we might have to "fake" it to get it to log
/// correctly).
// vrpn_Endpoint * d_serverLogEndpoint;
int d_serverLogCount;
vrpn_int32 d_serverLogMode;
char *d_serverLogName;
vrpn_bool d_updateEndpoint;
virtual void updateEndpoints(void);
///< This function will be called on the mainloop() iteration
///< after *d_endpointAllocator is called, which lets subclasses
///< do initialization. (They can't do so during allocateEndpoint
///< because it's called during the Connection constructor when
///< their constructors haven't executed yet.)
};
class VRPN_API vrpn_Connection_IP : public vrpn_Connection {
protected:
/// Make a client connection. To access this from user code,
/// call vrpn_get_connection_by_name().
/// Create a connection - if server_name is not a file: name,
/// makes an SDI-like connection to the named remote server
/// (otherwise functions as a non-networked messaging hub).
/// Port less than zero forces default.
/// Currently, server_name is an extended URL that defaults
/// to VRPN connections at the port, but can be file:: to read
/// from a file. Other extensions should maintain this, so
/// that VRPN uses URLs to name things that are to be connected
/// to.
vrpn_Connection_IP(const char *server_name,
int port = vrpn_DEFAULT_LISTEN_PORT_NO,
const char *local_in_logfile_name = NULL,
const char *local_out_logfile_name = NULL,
const char *remote_in_logfile_name = NULL,
const char *remote_out_logfile_name = NULL,
const char *NIC_IPaddress = NULL,
vrpn_EndpointAllocator epa = allocateEndpoint);
public:
/// Make a server that listens for client connections.
/// DEPRECATED: Call vrpn_create_server_connection() with the
/// NIC name and port number you want.
vrpn_Connection_IP(
unsigned short listen_port_no = vrpn_DEFAULT_LISTEN_PORT_NO,
const char *local_in_logfile_name = NULL,
const char *local_out_logfile_name = NULL,
const char *NIC_IPaddress = NULL,
vrpn_Endpoint_IP *(*epa)(vrpn_Connection *,
vrpn_int32 *) = allocateEndpoint);
virtual ~vrpn_Connection_IP(void);
/// This is similar to check connection except that it can be
/// used to receive requests from before a server starts up
virtual int connect_to_client(const char *machine, int port);
/// Call each time through program main loop to handle receiving any
/// incoming messages and sending any packed messages.
/// Returns -1 when connection dropped due to error, 0 otherwise.
/// (only returns -1 once per connection drop).
/// Optional argument is TOTAL time to block on select() calls;
/// there may be multiple calls to select() per call to mainloop(),
/// and this timeout will be divided evenly between them.
virtual int mainloop(const struct timeval *timeout = NULL);
protected:
/// If this value is greater than zero, the connection should stop
/// looking for new messages on a given endpoint after this many
/// are found.
vrpn_uint32 d_stop_processing_messages_after;
friend VRPN_API vrpn_Connection *vrpn_get_connection_by_name(
const char *cname, const char *local_in_logfile_name,
const char *local_out_logfile_name, const char *remote_in_logfile_name,
const char *remote_out_logfile_name, const char *NIC_IPaddress,
bool force_connection);
friend VRPN_API vrpn_Connection *
vrpn_create_server_connection(const char *cname,
const char *local_in_logfile_name,
const char *local_out_logfile_name);
/// @name Only used for a vrpn_Connection that awaits incoming connections
/// @{
SOCKET listen_udp_sock; ///< UDP Connect requests come here
SOCKET listen_tcp_sock; ///< TCP Connection requests come here
/// @}
/// Routines that handle system messages
static int VRPN_CALLBACK
handle_UDP_message(void *userdata, vrpn_HANDLERPARAM p);
/// @brief Called by all constructors
void init(void);
/// @brief send pending report, clear the buffer.
///
/// This function was protected, now is public, so we can use it
/// to send out intermediate results without calling mainloop
virtual int send_pending_reports(void);
//// This is called by a server-side process to see if there have
//// been any UDP packets come in asking for a connection. If there
//// are, it connects the TCP port and then calls handle_connection().
virtual void
server_check_for_incoming_connections(const struct timeval *timeout = NULL);
/// This routine is called by a server-side connection when a
/// new connection has just been established, and the tcp port
/// has been connected to it.
virtual void handle_connection(vrpn_Endpoint *endpoint);
/// Drops the connection with the given, non-NULL endpoint. Depending on if
/// we're a server or a client, this may result in the endpoints needing
/// compacting once you're no longer iterating on the endpoint container.
virtual void drop_connection(vrpn_Endpoint *endpoint);
/// Like drop_connection, except it includes the call to compact the
/// endpoints. Only safe to call if you can guarantee no iterators are open
/// to the container, since compact invalidates them.
void drop_connection_and_compact(vrpn_Endpoint *endpoint);
char *d_NIC_IP;
};
/// @brief Constructor for a Loopback connection that will basically just
/// pass messages between objects that are connected to it. It offers no
/// external connections, via IP or any other mechanism. It is useful
/// if you want to make the client and server in the same connection and
/// you don't need to have anything else connect.
class VRPN_API vrpn_Connection_Loopback : public vrpn_Connection {
protected:
/// Make a client connection. To access this from user code,
/// call vrpn_create_server_connection() with a service name
/// of 'loopback:'.
/// For now, we don't enable logging on a Loopback connection.
vrpn_Connection_Loopback();
public:
virtual ~vrpn_Connection_Loopback(void);
/// Call each time through program main loop to handle receiving any
/// incoming messages and sending any packed messages.
/// Returns -1 on error, 0 otherwise.
/// Optional argument is TOTAL time to block on select() calls;
/// there may be multiple calls to select() per call to mainloop(),
/// and this timeout will be divided evenly between them.
virtual int mainloop(const struct timeval *timeout = NULL);
/// Returns vrpn_true if the connection is okay, vrpn_false if not
virtual vrpn_bool doing_okay(void) const { return vrpn_true; }
/// Returns vrpn_true if the connection has been established, vrpn_false if
/// not
/// (For a networkless connection, this is equivalent to doing_okay()).
virtual vrpn_bool connected(void) const { return vrpn_true; }
protected:
friend VRPN_API vrpn_Connection *
vrpn_create_server_connection(const char *cname,
const char *local_in_logfile_name,
const char *local_out_logfile_name);
/// @brief send pending report, clear the buffer.
///
/// This function was protected, now is public, so we can use it
/// to send out intermediate results without calling mainloop
virtual int send_pending_reports(void) { return 0; }
};
/// @brief Create a client connection of arbitrary type (VRPN UDP/TCP, TCP,
/// File, Loopback, MPI).
///
/// WARNING: May not be thread safe.
/// If no IP address for the NIC to use is specified, uses the default
/// NIC. If the force_reopen flag is set, a new connection will be
/// made even if there was already one to that server.
/// When done with the object, call removeReference() on it (which will
/// delete it if there are no other references).
VRPN_API vrpn_Connection *vrpn_get_connection_by_name(
const char *cname, const char *local_in_logfile_name = NULL,
const char *local_out_logfile_name = NULL,
const char *remote_in_logfile_name = NULL,
const char *remote_out_logfile_name = NULL,
const char *NIC_IPaddress = NULL, bool force_reopen = false);
/// @brief Create a server connection of arbitrary type (VRPN UDP/TCP,
/// TCP, File, Loopback, MPI).
///
/// Returns NULL if the name is not understood or the connection cannot
/// be created.
/// WARNING: May not be thread safe.
/// To create a VRPN TCP/UDP server, use a name like:
/// vrpn:machine_name_or_ip:port
/// machine_name_or_ip:port
/// machine_name_or_ip
/// :port (This port on any network card.)
/// To create an MPI server, use a name like:
/// mpi:MPI_COMM_WORLD
/// mpi:comm_number
/// When done with the object, call removeReference() on it (which will
/// delete it if there are no other references).
VRPN_API vrpn_Connection *
vrpn_create_server_connection(const char *cname,
const char *local_in_logfile_name = NULL,
const char *local_out_logfile_name = NULL);
/// Lets you make one with the default settings, or just ask for a specific
/// port number on the default NIC on this machine. This matches the
/// signature on the old constructor to make it easier to port existing
/// servers.
inline VRPN_API vrpn_Connection *
vrpn_create_server_connection(int port = vrpn_DEFAULT_LISTEN_PORT_NO,
const char *local_in_logfile_name = NULL,
const char *local_out_logfile_name = NULL,
const char *NIC_NAME = NULL)
{
char name[256];
if (NIC_NAME == NULL) {
sprintf(name, ":%d", port);
}
else {
sprintf(name, "%s:%d", NIC_NAME, port);
}
return vrpn_create_server_connection(name, local_in_logfile_name,
local_out_logfile_name);
}
/// @name Utility routines to parse names (<service>@<location specifier>)
/// Both return new char [], and it is the caller's responsibility
/// to delete this memory!
/// @{
VRPN_API char *vrpn_copy_service_name(const char *fullname);
VRPN_API char *vrpn_copy_service_location(const char *fullname);
/// @}
/// @brief Utility routines to parse file specifiers FROM service locations
///
/// file:<filename>
///
/// file://<hostname>/<filename>
///
/// file:///<filename>
VRPN_API char *vrpn_copy_file_name(const char *filespecifier);
/// @name Utility routines to parse host specifiers FROM service locations
///
/// <hostname>
///
/// <hostname>:<port number>
///
/// x-vrpn://<hostname>
///
/// x-vrpn://<hostname>:<port number>
///
/// x-vrsh://<hostname>/<server program>,<comma-separated server arguments>
///
/// The caller is responsible for calling delete [] on the returned character
/// pointer if it is not NULL.
/// @{
VRPN_API char *vrpn_copy_machine_name(const char *hostspecifier);
VRPN_API int vrpn_get_port_number(const char *hostspecifier);
VRPN_API char *vrpn_copy_rsh_program(const char *hostspecifier);
VRPN_API char *vrpn_copy_rsh_arguments(const char *hostspecifier);
/// @}
/// @brief Utility routine to rename the service name of a given host specifier.
char *vrpn_set_service_name(const char *specifier, const char *newServiceName);
/// Checks the buffer to see if it is a valid VRPN header cookie.
/// Returns -1 on total mismatch,
/// 1 on minor version mismatch or other acceptable difference,
/// and 0 on exact match.
/// @{
VRPN_API int check_vrpn_cookie(const char *buffer);
VRPN_API int check_vrpn_file_cookie(const char *buffer);
/// @}
/// @brief Returns the size of the magic cookie buffer, plus any alignment
/// overhead.
VRPN_API size_t vrpn_cookie_size(void);
VRPN_API int write_vrpn_cookie(char *buffer, size_t length,
long remote_log_mode);
/// @name Utility routines for reading from and writing to sockets/file
/// descriptors
/// @{
#ifndef VRPN_USE_WINSOCK_SOCKETS
int VRPN_API
vrpn_noint_block_write(int outfile, const char buffer[], size_t length);
int VRPN_API vrpn_noint_block_read(int infile, char buffer[], size_t length);
int VRPN_API vrpn_noint_select(int width, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, struct timeval *timeout);
#else /* winsock sockets */
int VRPN_API
vrpn_noint_block_write(SOCKET outsock, char *buffer, size_t length);
int VRPN_API vrpn_noint_block_read(SOCKET insock, char *buffer, size_t length);
#endif /* VRPN_USE_WINSOCK_SOCKETS */
/// @}
/**
* @brief Singleton class that keeps track of all known VRPN connections
* and makes sure they're deleted on shutdown.
*
* We make it static to guarantee that the destructor is called
* on program close so that the destructors of all the vrpn_Connections
* that have been allocated are called so that all open logs are flushed
* to disk. Each connection should add itself to this list in its
* constructor and should remove itself from this list in its
* destructor.
*/
// This section holds data structures and functions to open
// connections by name.
// The intention of this section is that it can open connections for
// objects that are in different libraries (trackers, buttons and sound),
// even if they all refer to the same connection.
// Even though each individual vrpn_Connection class is not yet thread
// safe, so should only have its methods called from a single thread,
// the vrpn_ConnectionManager should be thread safe to allow connections
// to be created and destroyed by different threads.
class VRPN_API vrpn_ConnectionManager {
public:
~vrpn_ConnectionManager(void);
/// @brief The only way to get access to an instance of this class.
/// Guarantees that there is only one, global object.
/// Also guarantees that it will be constructed the first time
/// this function is called, and (hopefully?) destructed when
/// the program terminates.
static vrpn_ConnectionManager &instance(void);
/// NB implementation is not particularly efficient; we expect
/// to have O(10) connections, not O(1000).
/// @{
void addConnection(vrpn_Connection *, const char *name);
void deleteConnection(vrpn_Connection *);
/// @}
/// Searches through d_kcList but NOT d_anonList
/// (Connections constructed with no name)
vrpn_Connection *getByName(const char *name);
private:
/// Mutex to ensure thread safety;
vrpn_Semaphore d_semaphore;
struct knownConnection {
char name[1000];
vrpn_Connection *connection;
knownConnection *next;
};
/// @brief named connections
knownConnection *d_kcList;
/// @brief unnamed (server) connections
knownConnection *d_anonList;
vrpn_ConnectionManager(void);
// @brief copy constructor undefined to prevent instantiations
vrpn_ConnectionManager(const vrpn_ConnectionManager &);
void deleteConnection(vrpn_Connection *, knownConnection **);
};
#endif // VRPN_CONNECTION_H
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
C
1
https://gitee.com/jari/vrpn.git
[email protected]:jari/vrpn.git
jari
vrpn
vrpn
master

搜索帮助