| 1 |
//-*-c++-*-
|
| 2 |
#ifndef Wireless_h_DEFINED
|
| 3 |
#define Wireless_h_DEFINED
|
| 4 |
|
| 5 |
#ifdef PLATFORM_APERIOS
|
| 6 |
# include <OPENR/OObject.h>
|
| 7 |
# include <OPENR/OSubject.h>
|
| 8 |
# include <OPENR/OObserver.h>
|
| 9 |
# include <ant.h>
|
| 10 |
#else
|
| 11 |
# include "IPC/Thread.h"
|
| 12 |
typedef unsigned int uint32;
|
| 13 |
#endif
|
| 14 |
#include "Socket.h"
|
| 15 |
#include "DummySocket.h"
|
| 16 |
#include <list>
|
| 17 |
|
| 18 |
using namespace SocketNS;
|
| 19 |
using namespace __gnu_cxx;
|
| 20 |
|
| 21 |
//! Tekkotsu wireless class
|
| 22 |
/*!
|
| 23 |
* For more information on using wireless, please read the following tutorials:
|
| 24 |
* - <a href="../TekkotsuMon.html">TekkotsuMon</a>
|
| 25 |
* - <a href="../Wireless.html">TCP/IP</a>
|
| 26 |
*
|
| 27 |
* The networking interface needs more documentation. It also needs a
|
| 28 |
* cleanup. In the mean time, take a look at the TekkotsuMon objects
|
| 29 |
* in <i>Tekkotsu</i><tt>/Behaviors/Mon</tt>. They all listen for new
|
| 30 |
* connections. Unfortunately, at the momement there are no examples
|
| 31 |
* of outgoing connections, but it should give you a pretty good idea
|
| 32 |
* how to start moving.
|
| 33 |
*/
|
| 34 |
class Wireless {
|
| 35 |
public:
|
| 36 |
//! Maximum number of sockets which can be created
|
| 37 |
static const int WIRELESS_MAX_SOCKETS=100;
|
| 38 |
|
| 39 |
//! Default number of bytes to use for receive buffers (overridden by value passed to socket())
|
| 40 |
static const int WIRELESS_DEF_RECV_SIZE=1024;
|
| 41 |
|
| 42 |
//! Default number of bytes to use for send buffers (overridden by value passed to socket())
|
| 43 |
static const int WIRELESS_DEF_SEND_SIZE=1024;
|
| 44 |
|
| 45 |
//! constructor - only one wireless object is required per Aperios process.
|
| 46 |
/*! MMCombo already creates one. The (global) instance is called wireless,
|
| 47 |
* and you can access it by including Wireless/Wireless.h (this file) in
|
| 48 |
* your code
|
| 49 |
*/
|
| 50 |
Wireless();
|
| 51 |
~Wireless(); //!< destructor
|
| 52 |
|
| 53 |
//@{
|
| 54 |
//! Creates a new socket
|
| 55 |
/*! @return pointer to Socket object created
|
| 56 |
* @param ttype selects between TCP and UDP
|
| 57 |
* @see WIRELESS_DEF_RECV_SIZE, WIRELESS_DEF_SEND_SIZE */
|
| 58 |
Socket* socket(TransportType_t ttype);
|
| 59 |
/*!@param ttype selects between TCP and UDP
|
| 60 |
* @param recvsize size of input buffer
|
| 61 |
* @param sendsize size of output buffer
|
| 62 |
*/
|
| 63 |
Socket* socket(TransportType_t ttype, int recvsize, int sendsize);
|
| 64 |
//@}
|
| 65 |
|
| 66 |
//! The socket waits for incoming connections.
|
| 67 |
/*! That is, it acts like a server. If a connection is established and
|
| 68 |
* later broken, it resumes waiting for new connections if the
|
| 69 |
* socket's daemon flag is set.
|
| 70 |
*/
|
| 71 |
int listen(int sock, int port);
|
| 72 |
|
| 73 |
//! The socket tries to connect to a specific
|
| 74 |
int connect(int sock, const char* ipaddr, int port);
|
| 75 |
//! sets receiver callback for a socket
|
| 76 |
void setReceiver(int sock, int (*rcvcbckfn) (char*, int) );
|
| 77 |
//! sets the socket to be a daemon (recycles on close)
|
| 78 |
void setDaemon(int sock, bool val=true) { sockets[sock]->daemon=val; }
|
| 79 |
//! sets the socket to be a daemon (recycles on close)
|
| 80 |
bool getDaemon(int sock) { return sockets[sock]->daemon; }
|
| 81 |
//! closes and destroys non server, daemon sockets
|
| 82 |
void close(int sock);
|
| 83 |
|
| 84 |
//@{
|
| 85 |
//! utility function that you can use if you're curious about the state of the socket.
|
| 86 |
/*! You shouldn't need to use it, since asking sockets for write
|
| 87 |
* and read buffers does the necessary sanity checks
|
| 88 |
*/
|
| 89 |
bool isConnected(int sock) {
|
| 90 |
return sockets[sock]==NULL ? false : sockets[sock]->state==CONNECTION_CONNECTED;
|
| 91 |
}
|
| 92 |
bool isError(int sock) {
|
| 93 |
return sockets[sock]==NULL ? false : sockets[sock]->state==CONNECTION_ERROR;
|
| 94 |
}
|
| 95 |
|
| 96 |
bool isReady(int sock) { return !sockets[sock]->tx; }
|
| 97 |
bool hasData(int sock) { return !sockets[sock]->rx; }
|
| 98 |
//@}
|
| 99 |
|
| 100 |
//@{
|
| 101 |
//! helper function for the function with the same name that takes a socket descriptor (int)
|
| 102 |
void setReceiver(Socket &sobj, int (*rcvcbckfn) (char*, int) )
|
| 103 |
{ setReceiver(sobj.sock, rcvcbckfn); }
|
| 104 |
void setReceiver(Socket *sobj, int (*rcvcbckfn) (char*, int) )
|
| 105 |
{ setReceiver(sobj->sock, rcvcbckfn); }
|
| 106 |
void setDaemon(Socket &sobj, bool val=true) { setDaemon(sobj.sock, val); }
|
| 107 |
void setDaemon(Socket *sobj, bool val=true) { setDaemon(sobj->sock, val); }
|
| 108 |
bool getDaemon(Socket &sobj) { return getDaemon(sobj.sock); }
|
| 109 |
bool getDaemon(Socket *sobj) { return getDaemon(sobj->sock); }
|
| 110 |
int listen(Socket &sobj, int port) { return listen(sobj.sock, port); }
|
| 111 |
int listen(Socket *sobj, int port) { return listen(sobj->sock, port); }
|
| 112 |
int connect(Socket &sobj, const char* ipaddr, int port)
|
| 113 |
{ return connect (sobj.sock, ipaddr, port); }
|
| 114 |
int connect(Socket *sobj, const char* ipaddr, int port)
|
| 115 |
{ return connect (sobj->sock, ipaddr, port); }
|
| 116 |
void close(Socket &sobj) { close(sobj.sock); }
|
| 117 |
void close(Socket *sobj) { close(sobj->sock); }
|
| 118 |
unsigned int getNumInterfaces() { return 1; }
|
| 119 |
uint32 getIPAddress(unsigned int idx=0);
|
| 120 |
//@}
|
| 121 |
|
| 122 |
//@{
|
| 123 |
//! function for internal and Socket use. You should not call this
|
| 124 |
void receive(int sock, int (*rcvcbckfn) (char*, int) );
|
| 125 |
void receive(int sock);
|
| 126 |
//@}
|
| 127 |
|
| 128 |
//@{
|
| 129 |
//! function called by the Socket objects to actually write
|
| 130 |
//! data to the network. You should not call this.
|
| 131 |
void send(int sock);
|
| 132 |
void blockingSend(int sock);
|
| 133 |
//@}
|
| 134 |
|
| 135 |
#ifdef PLATFORM_APERIOS
|
| 136 |
//@{
|
| 137 |
//! callback function for communicating
|
| 138 |
//! with Aperios Networking Toolkit. You should not call this.
|
| 139 |
void ListenCont (void* msg);
|
| 140 |
void BindCont (void* msg);
|
| 141 |
void ConnectCont(void* msg);
|
| 142 |
void SendCont (void* msg);
|
| 143 |
void ReceiveCont(void* msg);
|
| 144 |
void CloseCont (void* msg);
|
| 145 |
//@}
|
| 146 |
|
| 147 |
#else
|
| 148 |
void pollSetup(); //!< on non-aperios, set up structures to be checked in pollTest()
|
| 149 |
bool pollTest(struct timeval* tv); //!< on non-aperios, check to see any network communication has occurred
|
| 150 |
void pollProcess(); //!< on non-aperios, process callbacks and state changes as signaled in pollTest()
|
| 151 |
void wakeup(Socket * del=NULL); //!< writes @a del on #interruptCtl, breaking out of a pending pollTest() and thus giving an opportunity to change the contents of the FD sets being used;
|
| 152 |
|
| 153 |
void setCallbackLock(const ThreadNS::Lock& l); //!< sets #callbackLock, can be NULL if you don't want to use a callback lock
|
| 154 |
void clearCallbackLock(); //!< resets #callbackLock to a self-defined lock, which you can request from getCallbackLock() (there's always a callbackLock, the only question is it internally or externally instantiated)
|
| 155 |
const ThreadNS::Lock& getCallbackLock() const { return callbackLock; } //!< returns #callbackLock
|
| 156 |
#endif
|
| 157 |
|
| 158 |
protected:
|
| 159 |
friend class Socket; //so socket can lock as well
|
| 160 |
static const int MAXCONNECTIONS = 5; //!< the maximum number of connections which can be queued when listening
|
| 161 |
|
| 162 |
//@{
|
| 163 |
//!private ALOKL_TODO
|
| 164 |
#ifdef PLATFORM_APERIOS
|
| 165 |
antStackRef ipstackRef;
|
| 166 |
OID myOID;
|
| 167 |
#else
|
| 168 |
static ThreadNS::Lock& getLock(); //!< returns the lock to use during @e all wireless operations (not just callbacks, this is more general)
|
| 169 |
ThreadNS::Lock callbackLock; //!< this lock will be aquired during any callbacks which might occur during pollProcess()
|
| 170 |
int interruptChk; //!< a socket, connected to #interruptCtl, which allows pollTest() to be interrupted if new sockets need to be polled
|
| 171 |
int interruptCtl; //!< a socket, connected to #interruptChk, which allows pollTest() to be interrupted if new sockets need to be polled
|
| 172 |
fd_set rfds; //!< a set of file descriptors which should be polled for readable data; set up by pollSetup(), watched (blocking) by pollTest(), and processed by pollProcess()
|
| 173 |
fd_set wfds; //!< a set of file descriptors which should be polled for write-complete; set up by pollSetup(), watched (blocking) by pollTest(), and processed by pollProcess()
|
| 174 |
fd_set efds; //!< a set of file descriptors which should be polled for errors; set up by pollSetup(), watched (blocking) by pollTest(), and processed by pollProcess()
|
| 175 |
int fdsMax; //!< maximum file descriptor value in the #rfds, #wfds, #efds fd_set's
|
| 176 |
#endif
|
| 177 |
Socket* sockets[WIRELESS_MAX_SOCKETS];
|
| 178 |
std::list<int> freeSockets;
|
| 179 |
std::list<int> usedSockets;
|
| 180 |
//@}
|
| 181 |
|
| 182 |
private:
|
| 183 |
Wireless(const Wireless&); //!< don't call
|
| 184 |
Wireless& operator= (const Wireless&); //!< don't call
|
| 185 |
};
|
| 186 |
|
| 187 |
//! the global wireless object - you'll want to make your function calls on this
|
| 188 |
extern Wireless* wireless;
|
| 189 |
|
| 190 |
/*! @file
|
| 191 |
* @brief Interacts with the system to provide networking services
|
| 192 |
* @author alokl (Creator)
|
| 193 |
*
|
| 194 |
* @verbinclude CMPack_license.txt
|
| 195 |
*
|
| 196 |
* $Author: ejt $
|
| 197 |
* $Name: $
|
| 198 |
* $Revision: 1.24 $
|
| 199 |
* $State: Exp $
|
| 200 |
* $Date: 2006/03/16 20:24:25 $
|
| 201 |
*/
|
| 202 |
|
| 203 |
#endif // Wireless_h_DEFINED
|