#include <DHTXMLRealworldApp.h>
Inheritance diagram for DHTXMLRealworldApp:
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 ¶ms, XmlRpc::XmlRpcValue &result) |
void | put (XmlRpc::XmlRpcValue ¶ms, XmlRpc::XmlRpcValue &result) |
void | get (XmlRpc::XmlRpcValue ¶ms, XmlRpc::XmlRpcValue &result) |
void | joinOverlay (XmlRpc::XmlRpcValue ¶ms, 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 |
BaseOverlay * | overlay |
pointer to the overlay module of this node | |
cMessage * | packetNotification |
RealtimeScheduler::PacketBuffer | packetBuffer |
RealtimeScheduler * | scheduler |
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 |
enum DHTXMLRealworldApp::ServerConnectionState [protected] |
Possible IO states for the connection.
00043 { READ_HEADER, READ_REQUEST, EXECUTE_REQUEST, 00044 WRITE_RESPONSE };
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] |
void DHTXMLRealworldApp::handleRpcResponse | ( | BaseResponseMessage * | msg, | |
int | rpcId, | |||
simtime_t | rtt | |||
) | [protected, virtual] |
This method is called if an RPC response has been received.
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] |
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 }
unsigned int DHTXMLRealworldApp::mtu [protected] |
int DHTXMLRealworldApp::gateIndexNetwOut [protected] |
cMessage* DHTXMLRealworldApp::timeout_msg [protected] |
BaseOverlay* DHTXMLRealworldApp::overlay [protected] |
cMessage* DHTXMLRealworldApp::packetNotification [protected] |
RealtimeScheduler* DHTXMLRealworldApp::scheduler [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::_put [protected] |
XmlRpc::XmlRpcServerMethod* DHTXMLRealworldApp::_get [protected] |