DHTXMLRealworldApp Class Reference

#include <DHTXMLRealworldApp.h>

Inheritance diagram for DHTXMLRealworldApp:

BaseApp XmlRpc::XmlRpcServer BaseRpc XmlRpc::XmlRpcSource RpcListener List of all members.

Detailed Description

Applicaton that communicates with a realword application via a socket.


Public Member Functions

virtual int numInitStages () const
 method to set InitStage
virtual void initialize (int stage)
 Initialization of the module.
virtual void handleMessage (cMessage *msg)
 The "main loop".
void localLookup (XmlRpc::XmlRpcValue &params, XmlRpc::XmlRpcValue &result)
void put (XmlRpc::XmlRpcValue &params, XmlRpc::XmlRpcValue &result)
void get (XmlRpc::XmlRpcValue &params, XmlRpc::XmlRpcValue &result)
void joinOverlay (XmlRpc::XmlRpcValue &params, XmlRpc::XmlRpcValue &result)

Protected Types

enum  ServerConnectionState { READ_HEADER, READ_REQUEST, EXECUTE_REQUEST, WRITE_RESPONSE }
 Possible IO states for the connection. More...

Protected Member Functions

bool readHeader (char *buf, uint32_t length)
 Reads the http header.
bool readRequest (char *buf, uint32_t length)
 Reads the request (based on the content-length header value).
bool writeResponse ()
 Executes the request and writes the resulting response.
void handleRealworldPacket (char *buf, uint32_t len)
void handleCommonAPIPacket (cMessage *msg)
void handleRpcResponse (BaseResponseMessage *msg, int rpcId, simtime_t rtt)
 This method is called if an RPC response has been received.

Protected Attributes

unsigned int mtu
int gateIndexNetwOut
cMessage * timeout_msg
BaseOverlayoverlay
 pointer to the overlay module of this node
cMessage * packetNotification
RealtimeScheduler::PacketBuffer packetBuffer
RealtimeSchedulerscheduler
ServerConnectionState _connectionState
 Current IO state for the connection.
std::string _header
 Request headers.
int _contentLength
 Number of bytes expected in the request body (parsed from header).
std::string _request
 Request body.
std::string _response
 Response.
int _bytesWritten
 Number of bytes of the response written so far.
bool _keepAlive
 Whether to keep the current client connection open for further requests.
XmlRpc::XmlRpcServerMethod_localLookup
XmlRpc::XmlRpcServerMethod_put
XmlRpc::XmlRpcServerMethod_get
XmlRpc::XmlRpcServerMethod_joinOverlay


Member Enumeration Documentation

enum DHTXMLRealworldApp::ServerConnectionState [protected]

Possible IO states for the connection.

Enumerator:
READ_HEADER 
READ_REQUEST 
EXECUTE_REQUEST 
WRITE_RESPONSE 


Member Function Documentation

bool DHTXMLRealworldApp::readHeader ( char *  buf,
uint32_t  length 
) [protected]

Reads the http header.

00340 {
00341   // Read available data
00342   bool eof = false;
00343 
00344   _header.append(std::string(buf, length));
00345 
00346   if ( length <= 0 ) {
00347     // Its only an error if we already have read some data
00348     if (_header.length() > 0)
00349       XmlRpcUtil::error("XmlRpcServerConnection::readHeader: error "
00350                         "while reading header.");
00351     return false;
00352   }
00353 
00354   XmlRpcUtil::log(4, "XmlRpcServerConnection::readHeader: read %d bytes.", _header.length());
00355   char *hp = (char*)_header.c_str();  // Start of header
00356   char *ep = hp + _header.length();   // End of string
00357   char *bp = 0;                       // Start of body
00358   char *lp = 0;                       // Start of content-length value
00359   char *kp = 0;                       // Start of connection value
00360 
00361   for (char *cp = hp; (bp == 0) && (cp < ep); ++cp) {
00362         if ((ep - cp > 16) && (strncasecmp(cp, "Content-length: ", 16) == 0))
00363           lp = cp + 16;
00364         else if ((ep - cp > 12) && (strncasecmp(cp, "Connection: ", 12) == 0))
00365           kp = cp + 12;
00366         else if ((ep - cp > 4) && (strncmp(cp, "\r\n\r\n", 4) == 0))
00367           bp = cp + 4;
00368         else if ((ep - cp > 2) && (strncmp(cp, "\n\n", 2) == 0))
00369           bp = cp + 2;
00370   }
00371 
00372   // If we haven't gotten the entire header yet, return (keep reading)
00373   if (bp == 0) {
00374     // EOF in the middle of a request is an error, otherwise its ok
00375     if (eof) {
00376       XmlRpcUtil::log(4, "XmlRpcServerConnection::readHeader: EOF");
00377       if (_header.length() > 0)
00378         XmlRpcUtil::error("XmlRpcServerConnection::readHeader: EOF while reading header");
00379       return false;   // Either way we close the connection
00380     }
00381     
00382     return true;  // Keep reading
00383   }
00384 
00385   // Decode content length
00386   if (lp == 0) {
00387     XmlRpcUtil::error("XmlRpcServerConnection::readHeader: No Content-length specified");
00388     return false;   // We could try to figure it out by parsing as we read, but for now...
00389   }
00390 
00391   _contentLength = atoi(lp);
00392   if (_contentLength <= 0) {
00393     XmlRpcUtil::error("XmlRpcServerConnection::readHeader: Invalid Content-length specified (%d).", _contentLength);
00394     return false;
00395   }
00396         
00397   XmlRpcUtil::log(3, "XmlRpcServerConnection::readHeader: specified content length is %d.", _contentLength);
00398 
00399   // Otherwise copy non-header data to request buffer and set state to read request.
00400   _request = bp;
00401 
00402   // Parse out any interesting bits from the header (HTTP version, connection)
00403   _keepAlive = true;
00404   if (_header.find("HTTP/1.0") != std::string::npos) {
00405     if (kp == 0 || strncasecmp(kp, "keep-alive", 10) != 0)
00406       _keepAlive = false;           // Default for HTTP 1.0 is to close the connection
00407   } else {
00408     if (kp != 0 && strncasecmp(kp, "close", 5) == 0)
00409       _keepAlive = false;
00410   }
00411   XmlRpcUtil::log(3, "KeepAlive: %d", _keepAlive);
00412 
00413 
00414   _header = ""; 
00415   _connectionState = READ_REQUEST;
00416   return true;    // Continue monitoring this source
00417 }

bool DHTXMLRealworldApp::readRequest ( char *  buf,
uint32_t  length 
) [protected]

Reads the request (based on the content-length header value).

00422 {
00423   // If we dont have the entire request yet, read available data
00424   if (int(_request.length()) < _contentLength) {
00425     bool eof = false;
00426 
00427     _request.append(std::string(buf, length));
00428 
00429     if ( length <= 0 ) {
00430         XmlRpcUtil::error("XmlRpcServerConnection::readRequest: read error.");
00431       return false;
00432     }
00433 
00434     // If we haven't gotten the entire request yet, return (keep reading)
00435     if (int(_request.length()) < _contentLength) {
00436       if (eof) {
00437         XmlRpcUtil::error("XmlRpcServerConnection::readRequest: EOF while reading request");
00438         return false;   // Either way we close the connection
00439       }
00440       return true;
00441     }
00442   }
00443 
00444   // Otherwise, parse and dispatch the request
00445   XmlRpcUtil::log(3, "XmlRpcServerConnection::readRequest read %d bytes.", _request.length());
00446   //XmlRpcUtil::log(5, "XmlRpcServerConnection::readRequest:\n%s\n", _request.c_str());
00447 
00448   _connectionState = WRITE_RESPONSE;
00449 
00450   return true;    // Continue monitoring this source
00451 }

bool DHTXMLRealworldApp::writeResponse (  )  [protected]

Executes the request and writes the resulting response.

00456 {
00457     cancelEvent(timeout_msg);
00458 
00459   if (_response.length() == 0) {
00460       _response = executeRequest(_request);
00461     _bytesWritten = 0;
00462 
00463     if (_connectionState == EXECUTE_REQUEST)
00464         return true;
00465 
00466     if (_response.length() == 0) {
00467       XmlRpcUtil::error("XmlRpcServerConnection::writeResponse: empty response.");
00468       return false;
00469     }
00470   }
00471 
00472   // Try to write the response
00473   int curBytesWritten = scheduler->sendBytes(_response.c_str(),
00474                                              _response.length(), 0, 0, true);
00475 
00476   if (curBytesWritten <= 0) {
00477       XmlRpcUtil::error("XmlRpcServerConnection::writeResponse: write error.");
00478     return false;
00479   } else {
00480       _bytesWritten += curBytesWritten;
00481   }
00482 
00483   XmlRpcUtil::log(3, "XmlRpcServerConnection::writeResponse: wrote %d of %d bytes.", _bytesWritten, _response.length());
00484 
00485   // Prepare to read the next request
00486   if (_bytesWritten == int(_response.length())) {
00487     _header = "";
00488     _request = "";
00489     _response = "";
00490     _connectionState = READ_HEADER;
00491   }
00492 
00493   return _keepAlive;    // Continue monitoring this source if true
00494 }

void DHTXMLRealworldApp::handleRealworldPacket ( char *  buf,
uint32_t  len 
) [protected]

00272 {
00273     if (_connectionState == READ_HEADER) {
00274         if (! readHeader(buf, length)) {
00275             // discard data, if the header is invalid
00276             _header = "";
00277             _request = "";
00278             _response = "";
00279             _connectionState = READ_HEADER;
00280             return;
00281         }
00282     }
00283 
00284     if (_connectionState == READ_REQUEST)
00285         if (! readRequest(buf, length)) return;
00286 
00287     if (_connectionState == WRITE_RESPONSE)
00288         if (! writeResponse() ) {
00289             scheduler->closeAppSocket();
00290             return;
00291         }
00292 
00293     return;
00294 }

void DHTXMLRealworldApp::handleCommonAPIPacket ( cMessage *  msg  )  [protected]

00335 {
00336         error("DHTXMLRealworldApp::handleCommonAPIPacket(): Unknown Packet!");
00337 }

void DHTXMLRealworldApp::handleRpcResponse ( BaseResponseMessage *  msg,
int  rpcId,
simtime_t  rtt 
) [protected, virtual]

This method is called if an RPC response has been received.

Parameters:
msg The response message.
rpcId The RPC id.
rtt The Round-Trip-Time of this RPC

Reimplemented from RpcListener.

00298 {
00299     RPC_SWITCH_START(msg)
00300     RPC_ON_RESPONSE( DHTputCAPI ) {
00301         if (_connectionState != EXECUTE_REQUEST) break;
00302 
00303         XmlRpcValue resultValue;
00304 
00305         resultValue = 0;
00306         _response = generateResponse(resultValue.toXml());
00307         _connectionState = WRITE_RESPONSE;
00308         if (! writeResponse() ) {
00309             scheduler->closeAppSocket();
00310         }
00311         break;
00312     }
00313     RPC_ON_RESPONSE( DHTgetCAPI ) {
00314         if (_connectionState != EXECUTE_REQUEST) break;
00315 
00316         XmlRpcValue resultValue;
00317         resultValue.setSize(2);
00318         resultValue[0].setSize(1);
00319 
00320         resultValue[0][0] = XmlRpcValue(&(*(_DHTgetCAPIResponse->getValue().begin())),
00321                 _DHTgetCAPIResponse->getValue().size());
00322         resultValue[1] = std::string();
00323         _response = generateResponse(resultValue.toXml());
00324         _connectionState = WRITE_RESPONSE;
00325         if (! writeResponse() ) {
00326             scheduler->closeAppSocket();
00327         }
00328         break;
00329     }
00330     RPC_SWITCH_END( )
00331 }

virtual int DHTXMLRealworldApp::numInitStages (  )  const [inline, virtual]

method to set InitStage

Reimplemented from BaseApp.

00084     {
00085         return 4;
00086     }

void DHTXMLRealworldApp::initialize ( int  stage  )  [virtual]

Initialization of the module.

Registers the device at the scheduler and searches for the appropriate payload-parser Will be called automatically at startup

Reimplemented from BaseApp.

00183 {
00184     // all initialization is done in the first stage
00185     if (stage!=0)
00186         return;
00187 
00188     packetNotification = new cMessage("packetNotification");
00189     mtu = par("mtu");
00190 
00191     scheduler = check_and_cast<RealtimeScheduler *>(simulation.scheduler());
00192     scheduler->setInterfaceModule(this, packetNotification,
00193                                   &packetBuffer, mtu, true);
00194 
00195     gateIndexNetwOut = gate("to_lowerTier")->id();
00196 
00197     overlay = check_and_cast<BaseOverlay*>
00198         (gate("to_lowerTier")->destinationGate()->ownerModule()
00199          ->gate("to_lowerTier")->destinationGate()->ownerModule());
00200 
00201     if (overlay == NULL) {
00202         opp_error("DHTXMLRealworldApp::initialize(): Can't get pointer "
00203                   "to overlay module!");
00204     }
00205 
00206     XmlRpc::setVerbosity(5);
00207 
00208     _localLookup = new LocalLookup(this);
00209     _put = new Put(this);
00210     _get = new Get(this);
00211     _joinOverlay = new JoinOverlay(this);
00212 
00213     enableIntrospection(true);
00214 
00215     _connectionState = READ_HEADER;
00216     _keepAlive = true;
00217 
00218     initRpcs();
00219 
00220     timeout_msg = new cMessage("timeout_msg");
00221 }

void DHTXMLRealworldApp::handleMessage ( cMessage *  msg  )  [virtual]

The "main loop".

Every message that is received or send is handled by this method

Reimplemented from BaseApp.

00225 {
00226     // Packet from the application...
00227     if (msg==packetNotification) {
00228         EV << "DHTXMLRealworldApp: Message from application. Queue length = "
00229            << packetBuffer.size() << ".\n";
00230         while( packetBuffer.size() > 0 ) {
00231             // get packet from buffer and parse it
00232             RealtimeScheduler::PacketBufferEntry packet =
00233                                                  *(packetBuffer.begin());
00234             packetBuffer.pop_front();
00235             handleRealworldPacket(packet.data, packet.length);
00236             delete packet.data;
00237         }
00238     } else if(msg->isSelfMessage()) {
00239         // process rpc self-messages
00240         BaseRpcMessage* rpcMessage = dynamic_cast<BaseRpcMessage*>(msg);
00241         if (rpcMessage!=NULL) {
00242             internalHandleRpcMessage(rpcMessage);
00243             return;
00244         }
00245         // process all other self-messages
00246         if (msg == timeout_msg) {
00247             _response = generateFaultResponse("XML-RPC timeout", 22);
00248             _connectionState = WRITE_RESPONSE;
00249             if (! writeResponse() ) {
00250                 scheduler->closeAppSocket();
00251             }
00252             return;
00253         }
00254     } else {
00255         // RPCs
00256         BaseRpcMessage* rpcMessage = dynamic_cast<BaseRpcMessage*>(msg);
00257         if (rpcMessage!=NULL) {
00258             internalHandleRpcMessage(rpcMessage);
00259             return;
00260         }
00261         // common API
00262         CommonAPIMessage* commonAPIMsg = dynamic_cast<CommonAPIMessage*>(msg);
00263         if(commonAPIMsg != NULL)
00264             handleCommonAPIPacket(commonAPIMsg);
00265 
00266         delete msg;
00267     }
00268 
00269 }

void DHTXMLRealworldApp::localLookup ( XmlRpc::XmlRpcValue params,
XmlRpc::XmlRpcValue result 
)

00091 {
00092       if ((params.size() != 3) ||
00093           (params[0].getType() != XmlRpcValue::TypeBase64) ||
00094           (params[1].getType() != XmlRpcValue::TypeInt) ||
00095           (params[2].getType() != XmlRpcValue::TypeBoolean)
00096           )
00097           throw XmlRpcException("local_lookup(base64 key, int num, "
00098                                 "boolean safe): Invalid argument type");
00099 
00100       BinaryValue keyString = (const XmlRpcValue::BinaryData&)params[0];
00101       
00102       NodeVector* nextHops = overlay->local_lookup(
00103                        OverlayKey::sha1(keyString),
00104                        params[1], params[2]);
00105 
00106       for (uint i=0; i < nextHops->size(); i++) {
00107           result[i][0] = (*nextHops)[0].ip.str();
00108           result[i][1] = (*nextHops)[0].port;
00109           result[i][2] = (*nextHops)[0].key.toString(16);
00110       }
00111 
00112       delete nextHops;
00113 }

void DHTXMLRealworldApp::put ( XmlRpc::XmlRpcValue params,
XmlRpc::XmlRpcValue result 
)

00129 {
00130     if ((params.size() != 4) ||
00131         (params[0].getType() != XmlRpcValue::TypeBase64) ||
00132         (params[1].getType() != XmlRpcValue::TypeBase64) ||
00133         (params[2].getType() != XmlRpcValue::TypeInt) ||
00134         (params[3].getType() != XmlRpcValue::TypeString))
00135         throw XmlRpcException("put(base64 key, base64 value, int ttl "
00136             ", string application): Invalid argument type");
00137     
00138     _connectionState = EXECUTE_REQUEST;
00139     
00140     DHTputCAPICall* dhtPutMsg = new DHTputCAPICall();
00141 
00142 
00143     BinaryValue keyString = (const XmlRpcValue::BinaryData&)params[0];
00144 
00145     dhtPutMsg->setKey(OverlayKey::sha1(keyString));
00146     dhtPutMsg->setValue(((const XmlRpcValue::BinaryData&)params[1]));
00147     dhtPutMsg->setTtl(params[2]);
00148     dhtPutMsg->setIsModifiable(true);
00149 
00150     sendRpcMessage(RPC_TO_LOWERTIER, NodeHandle::UNSPECIFIED_NODE, dhtPutMsg, NULL, OverlayKey::UNSPECIFIED_KEY, -1, 0);
00151 
00152     cancelEvent(timeout_msg);
00153     scheduleAt(simulation.simTime() + XMLRPC_TIMEOUT, timeout_msg);
00154 }

void DHTXMLRealworldApp::get ( XmlRpc::XmlRpcValue params,
XmlRpc::XmlRpcValue result 
)

00157 {
00158     if ((params.size() != 4) ||
00159         (params[0].getType() != XmlRpcValue::TypeBase64) ||
00160         (params[1].getType() != XmlRpcValue::TypeInt) ||
00161         (params[2].getType() != XmlRpcValue::TypeBase64) ||
00162         (params[3].getType() != XmlRpcValue::TypeString))
00163         throw XmlRpcException("get(base64 key, int num, base64 placemark "
00164             ", string application): Invalid argument type");
00165     
00166     _connectionState = EXECUTE_REQUEST;
00167 
00168     DHTgetCAPICall* dhtGetMsg = new DHTgetCAPICall();
00169 
00170 
00171     BinaryValue keyString = (const XmlRpcValue::BinaryData&)params[0];
00172     dhtGetMsg->setKey(OverlayKey::sha1(keyString));
00173    
00174     sendRpcMessage(RPC_TO_LOWERTIER, NodeHandle::UNSPECIFIED_NODE, dhtGetMsg, NULL, OverlayKey::UNSPECIFIED_KEY, -1, 0);
00175 
00176 
00177     cancelEvent(timeout_msg);
00178     scheduleAt(simulation.simTime() + XMLRPC_TIMEOUT, timeout_msg);
00179 }

void DHTXMLRealworldApp::joinOverlay ( XmlRpc::XmlRpcValue params,
XmlRpc::XmlRpcValue result 
)

00116 {
00117       if ((params.size() != 1) ||
00118           (params[0].getType() != XmlRpcValue::TypeBase64))
00119           throw XmlRpcException("join(base64 nodeID): Invalid argument type");
00120 
00121       BinaryValue nodeID = (const XmlRpcValue::BinaryData&)params[0];
00122 
00123       overlay->join(OverlayKey::sha1(nodeID));
00124 
00125       result[0] = 0;
00126 }


Member Data Documentation

unsigned int DHTXMLRealworldApp::mtu [protected]

int DHTXMLRealworldApp::gateIndexNetwOut [protected]

cMessage* DHTXMLRealworldApp::timeout_msg [protected]

BaseOverlay* DHTXMLRealworldApp::overlay [protected]

pointer to the overlay module of this node

Reimplemented from BaseApp.

cMessage* DHTXMLRealworldApp::packetNotification [protected]

RealtimeScheduler::PacketBuffer DHTXMLRealworldApp::packetBuffer [protected]

RealtimeScheduler* DHTXMLRealworldApp::scheduler [protected]

ServerConnectionState DHTXMLRealworldApp::_connectionState [protected]

Current IO state for the connection.

std::string DHTXMLRealworldApp::_header [protected]

Request headers.

int DHTXMLRealworldApp::_contentLength [protected]

Number of bytes expected in the request body (parsed from header).

std::string DHTXMLRealworldApp::_request [protected]

Request body.

std::string DHTXMLRealworldApp::_response [protected]

Response.

int DHTXMLRealworldApp::_bytesWritten [protected]

Number of bytes of the response written so far.

bool DHTXMLRealworldApp::_keepAlive [protected]

Whether to keep the current client connection open for further requests.

XmlRpc::XmlRpcServerMethod* DHTXMLRealworldApp::_localLookup [protected]

XmlRpc::XmlRpcServerMethod* DHTXMLRealworldApp::_put [protected]

XmlRpc::XmlRpcServerMethod* DHTXMLRealworldApp::_get [protected]

XmlRpc::XmlRpcServerMethod* DHTXMLRealworldApp::_joinOverlay [protected]


The documentation for this class was generated from the following files:
Generated on Tue Jul 24 16:51:18 2007 for ITM OverSim by  doxygen 1.5.1