#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 | lookup (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 * | _lookup |
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.
00429 { 00430 // Read available data 00431 bool eof = false; 00432 00433 _header.append(std::string(buf, length)); 00434 00435 if ( length <= 0 ) { 00436 // Its only an error if we already have read some data 00437 if (_header.length() > 0) 00438 XmlRpcUtil::error("XmlRpcServerConnection::readHeader: error " 00439 "while reading header."); 00440 return false; 00441 } 00442 00443 XmlRpcUtil::log(4, "XmlRpcServerConnection::readHeader: read %d bytes.", _header.length()); 00444 char *hp = (char*)_header.c_str(); // Start of header 00445 char *ep = hp + _header.length(); // End of string 00446 char *bp = 0; // Start of body 00447 char *lp = 0; // Start of content-length value 00448 char *kp = 0; // Start of connection value 00449 00450 for (char *cp = hp; (bp == 0) && (cp < ep); ++cp) { 00451 if ((ep - cp > 16) && (strncasecmp(cp, "Content-length: ", 16) == 0)) 00452 lp = cp + 16; 00453 else if ((ep - cp > 12) && (strncasecmp(cp, "Connection: ", 12) == 0)) 00454 kp = cp + 12; 00455 else if ((ep - cp > 4) && (strncmp(cp, "\r\n\r\n", 4) == 0)) 00456 bp = cp + 4; 00457 else if ((ep - cp > 2) && (strncmp(cp, "\n\n", 2) == 0)) 00458 bp = cp + 2; 00459 } 00460 00461 // If we haven't gotten the entire header yet, return (keep reading) 00462 if (bp == 0) { 00463 // EOF in the middle of a request is an error, otherwise its ok 00464 if (eof) { 00465 XmlRpcUtil::log(4, "XmlRpcServerConnection::readHeader: EOF"); 00466 if (_header.length() > 0) 00467 XmlRpcUtil::error("XmlRpcServerConnection::readHeader: EOF while reading header"); 00468 return false; // Either way we close the connection 00469 } 00470 00471 return true; // Keep reading 00472 } 00473 00474 // Decode content length 00475 if (lp == 0) { 00476 XmlRpcUtil::error("XmlRpcServerConnection::readHeader: No Content-length specified"); 00477 return false; // We could try to figure it out by parsing as we read, but for now... 00478 } 00479 00480 _contentLength = atoi(lp); 00481 if (_contentLength <= 0) { 00482 XmlRpcUtil::error("XmlRpcServerConnection::readHeader: Invalid Content-length specified (%d).", _contentLength); 00483 return false; 00484 } 00485 00486 XmlRpcUtil::log(3, "XmlRpcServerConnection::readHeader: specified content length is %d.", _contentLength); 00487 00488 // Otherwise copy non-header data to request buffer and set state to read request. 00489 _request = bp; 00490 00491 // Parse out any interesting bits from the header (HTTP version, connection) 00492 _keepAlive = true; 00493 if (_header.find("HTTP/1.0") != std::string::npos) { 00494 if (kp == 0 || strncasecmp(kp, "keep-alive", 10) != 0) 00495 _keepAlive = false; // Default for HTTP 1.0 is to close the connection 00496 } else { 00497 if (kp != 0 && strncasecmp(kp, "close", 5) == 0) 00498 _keepAlive = false; 00499 } 00500 XmlRpcUtil::log(3, "KeepAlive: %d", _keepAlive); 00501 00502 00503 _header = ""; 00504 _connectionState = READ_REQUEST; 00505 return true; // Continue monitoring this source 00506 }
bool DHTXMLRealworldApp::readRequest | ( | char * | buf, | |
uint32_t | length | |||
) | [protected] |
Reads the request (based on the content-length header value).
00511 { 00512 // If we dont have the entire request yet, read available data 00513 if (int(_request.length()) < _contentLength) { 00514 bool eof = false; 00515 00516 _request.append(std::string(buf, length)); 00517 00518 if ( length <= 0 ) { 00519 XmlRpcUtil::error("XmlRpcServerConnection::readRequest: read error."); 00520 return false; 00521 } 00522 00523 // If we haven't gotten the entire request yet, return (keep reading) 00524 if (int(_request.length()) < _contentLength) { 00525 if (eof) { 00526 XmlRpcUtil::error("XmlRpcServerConnection::readRequest: EOF while reading request"); 00527 return false; // Either way we close the connection 00528 } 00529 return true; 00530 } 00531 } 00532 00533 // Otherwise, parse and dispatch the request 00534 XmlRpcUtil::log(3, "XmlRpcServerConnection::readRequest read %d bytes.", _request.length()); 00535 //XmlRpcUtil::log(5, "XmlRpcServerConnection::readRequest:\n%s\n", _request.c_str()); 00536 00537 _connectionState = WRITE_RESPONSE; 00538 00539 return true; // Continue monitoring this source 00540 }
bool DHTXMLRealworldApp::writeResponse | ( | ) | [protected] |
Executes the request and writes the resulting response.
00545 { 00546 cancelEvent(timeout_msg); 00547 00548 if (_response.length() == 0) { 00549 _response = executeRequest(_request); 00550 _bytesWritten = 0; 00551 00552 if (_connectionState == EXECUTE_REQUEST) 00553 return true; 00554 00555 if (_response.length() == 0) { 00556 XmlRpcUtil::error("XmlRpcServerConnection::writeResponse: empty response."); 00557 return false; 00558 } 00559 } 00560 00561 // Try to write the response 00562 int curBytesWritten = scheduler->sendBytes(_response.c_str(), 00563 _response.length(), 0, 0, true); 00564 00565 if (curBytesWritten <= 0) { 00566 XmlRpcUtil::error("XmlRpcServerConnection::writeResponse: write error."); 00567 return false; 00568 } else { 00569 _bytesWritten += curBytesWritten; 00570 } 00571 00572 XmlRpcUtil::log(3, "XmlRpcServerConnection::writeResponse: wrote %d of %d bytes.", _bytesWritten, _response.length()); 00573 00574 // Prepare to read the next request 00575 if (_bytesWritten == int(_response.length())) { 00576 _header = ""; 00577 _request = ""; 00578 _response = ""; 00579 _connectionState = READ_HEADER; 00580 } 00581 00582 return _keepAlive; // Continue monitoring this source if true 00583 }
void DHTXMLRealworldApp::handleRealworldPacket | ( | char * | buf, | |
uint32_t | len | |||
) | [protected] |
00319 { 00320 if (_connectionState == READ_HEADER) { 00321 if (! readHeader(buf, length)) { 00322 // discard data, if the header is invalid 00323 _header = ""; 00324 _request = ""; 00325 _response = ""; 00326 _connectionState = READ_HEADER; 00327 return; 00328 } 00329 } 00330 00331 if (_connectionState == READ_REQUEST) 00332 if (! readRequest(buf, length)) return; 00333 00334 if (_connectionState == WRITE_RESPONSE) 00335 if (! writeResponse() ) { 00336 scheduler->closeAppSocket(); 00337 return; 00338 } 00339 00340 return; 00341 }
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.
00345 { 00346 RPC_SWITCH_START(msg) 00347 RPC_ON_RESPONSE( DHTlookupCAPI ) { 00348 if (_connectionState != EXECUTE_REQUEST) break; 00349 00350 XmlRpcValue resultValue; 00351 resultValue.setSize(_DHTlookupCAPIResponse->getSiblingsArraySize()); 00352 00353 if (_DHTlookupCAPIResponse->getIsValid() == true) { 00354 for (uint i=0; i < _DHTlookupCAPIResponse->getSiblingsArraySize(); 00355 i++) { 00356 resultValue[i].setSize(3); 00357 resultValue[i][0] = 00358 _DHTlookupCAPIResponse->getSiblings(i).ip.str(); 00359 resultValue[i][1] = 00360 _DHTlookupCAPIResponse->getSiblings(i).port; 00361 resultValue[i][2] = 00362 _DHTlookupCAPIResponse->getSiblings(i).key.toString(16); 00363 } 00364 _response = generateResponse(resultValue.toXml()); 00365 } else { 00366 std::cout << "DHTXMLRealworldApp(): lookup() failed!" << endl; 00367 _response = generateFaultResponse("lookup() failed", 22); 00368 } 00369 00370 _connectionState = WRITE_RESPONSE; 00371 if (! writeResponse() ) { 00372 scheduler->closeAppSocket(); 00373 } 00374 break; 00375 } 00376 RPC_ON_RESPONSE( DHTputCAPI ) { 00377 if (_connectionState != EXECUTE_REQUEST) break; 00378 00379 XmlRpcValue resultValue; 00380 00381 if (_DHTputCAPIResponse->getIsSuccess() == true) { 00382 resultValue = 0; 00383 _response = generateResponse(resultValue.toXml()); 00384 } else { 00385 std::cout << "DHTXMLRealworldApp(): put() failed!" << endl; 00386 _response = generateFaultResponse("put() failed", 22); 00387 } 00388 00389 _connectionState = WRITE_RESPONSE; 00390 if (! writeResponse() ) { 00391 scheduler->closeAppSocket(); 00392 } 00393 break; 00394 } 00395 RPC_ON_RESPONSE( DHTgetCAPI ) { 00396 if (_connectionState != EXECUTE_REQUEST) break; 00397 00398 XmlRpcValue resultValue; 00399 resultValue.setSize(2); 00400 resultValue[0].setSize(1); 00401 00402 if (_DHTgetCAPIResponse->getIsSuccess() == true) { 00403 resultValue[0][0] = XmlRpcValue( 00404 &(*(_DHTgetCAPIResponse->getValue().begin())), 00405 _DHTgetCAPIResponse->getValue().size()); 00406 resultValue[1] = std::string(); 00407 _response = generateResponse(resultValue.toXml()); 00408 } else { 00409 std::cout << "DHTXMLRealworldApp(): get() failed!" << endl; 00410 _response = generateFaultResponse("get() failed", 22); 00411 } 00412 00413 _connectionState = WRITE_RESPONSE; 00414 if (! writeResponse() ) { 00415 scheduler->closeAppSocket(); 00416 } 00417 break; 00418 } 00419 RPC_SWITCH_END( ) 00420 }
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.
00226 { 00227 // all initialization is done in the first stage 00228 if (stage!=0) 00229 return; 00230 00231 packetNotification = new cMessage("packetNotification"); 00232 mtu = par("mtu"); 00233 00234 scheduler = check_and_cast<RealtimeScheduler *>(simulation.scheduler()); 00235 scheduler->setInterfaceModule(this, packetNotification, 00236 &packetBuffer, mtu, true); 00237 00238 gateIndexNetwOut = gate("to_lowerTier")->id(); 00239 00240 overlay = check_and_cast<BaseOverlay*> 00241 (gate("to_lowerTier")->destinationGate()->ownerModule() 00242 ->gate("to_lowerTier")->destinationGate()->ownerModule()); 00243 00244 if (overlay == NULL) { 00245 opp_error("DHTXMLRealworldApp::initialize(): Can't get pointer " 00246 "to overlay module!"); 00247 } 00248 00249 XmlRpc::setVerbosity(1); 00250 00251 _localLookup = new LocalLookup(this); 00252 _lookup = new Lookup(this); 00253 _put = new Put(this); 00254 _get = new Get(this); 00255 _joinOverlay = new JoinOverlay(this); 00256 00257 enableIntrospection(true); 00258 00259 _connectionState = READ_HEADER; 00260 _keepAlive = true; 00261 00262 initRpcs(); 00263 00264 timeout_msg = new cMessage("timeout_msg"); 00265 }
void DHTXMLRealworldApp::handleMessage | ( | cMessage * | msg | ) | [virtual] |
The "main loop".
Every message that is received or send is handled by this method
Reimplemented from BaseApp.
00269 { 00270 // Packet from the application... 00271 if (msg==packetNotification) { 00272 EV << "[DHTXMLRealworldApp::handleMessage() @ " << thisNode.ip 00273 << " (" << thisNode.key.toString(16) << ")]\n" 00274 << " Message from application. Queue length = " << packetBuffer.size() 00275 << endl; 00276 while( packetBuffer.size() > 0 ) { 00277 // get packet from buffer and parse it 00278 RealtimeScheduler::PacketBufferEntry packet = 00279 *(packetBuffer.begin()); 00280 packetBuffer.pop_front(); 00281 handleRealworldPacket(packet.data, packet.length); 00282 delete packet.data; 00283 } 00284 } else if(msg->isSelfMessage()) { 00285 // process rpc self-messages 00286 BaseRpcMessage* rpcMessage = dynamic_cast<BaseRpcMessage*>(msg); 00287 if (rpcMessage!=NULL) { 00288 internalHandleRpcMessage(rpcMessage); 00289 return; 00290 } 00291 // process all other self-messages 00292 if (msg == timeout_msg) { 00293 std::cout << "DHTXMLRealworldApp(): XML-RPC failed!" << endl; 00294 _response = generateFaultResponse("XML-RPC timeout", 22); 00295 _connectionState = WRITE_RESPONSE; 00296 if (! writeResponse() ) { 00297 scheduler->closeAppSocket(); 00298 } 00299 return; 00300 } 00301 } else { 00302 // RPCs 00303 BaseRpcMessage* rpcMessage = dynamic_cast<BaseRpcMessage*>(msg); 00304 if (rpcMessage!=NULL) { 00305 internalHandleRpcMessage(rpcMessage); 00306 return; 00307 } 00308 // common API 00309 CommonAPIMessage* commonAPIMsg = dynamic_cast<CommonAPIMessage*>(msg); 00310 if(commonAPIMsg != NULL) 00311 handleCommonAPIPacket(commonAPIMsg); 00312 00313 delete msg; 00314 } 00315 00316 }
void DHTXMLRealworldApp::localLookup | ( | XmlRpc::XmlRpcValue & | params, | |
XmlRpc::XmlRpcValue & | result | |||
) |
00106 { 00107 if ((params.size() != 3) || 00108 (params[0].getType() != XmlRpcValue::TypeBase64) || 00109 (params[1].getType() != XmlRpcValue::TypeInt) || 00110 (params[2].getType() != XmlRpcValue::TypeBoolean) 00111 ) 00112 throw XmlRpcException("local_lookup(base64 key, int num, " 00113 "boolean safe): Invalid argument type"); 00114 00115 BinaryValue keyString = (const XmlRpcValue::BinaryData&)params[0]; 00116 00117 NodeVector* nextHops = overlay->local_lookup( 00118 OverlayKey::sha1(keyString), 00119 params[1], params[2]); 00120 00121 for (uint i=0; i < nextHops->size(); i++) { 00122 result[i][0] = (*nextHops)[0].ip.str(); 00123 result[i][1] = (*nextHops)[0].port; 00124 result[i][2] = (*nextHops)[0].key.toString(16); 00125 } 00126 00127 delete nextHops; 00128 }
void DHTXMLRealworldApp::lookup | ( | XmlRpc::XmlRpcValue & | params, | |
XmlRpc::XmlRpcValue & | result | |||
) |
00131 { 00132 if ((params.size() != 2) || 00133 (params[0].getType() != XmlRpcValue::TypeBase64) || 00134 (params[1].getType() != XmlRpcValue::TypeInt)) 00135 throw XmlRpcException("lookup(base64 key, int numSiblings): " 00136 "Invalid argument type"); 00137 00138 if ((int)params[1] > overlay->getMaxNumSiblings()) 00139 throw XmlRpcException("lookup(base64 key, int numSiblings): " 00140 "numSibling to big"); 00141 00142 _connectionState = EXECUTE_REQUEST; 00143 00144 DHTlookupCAPICall* dhtLookupMsg = new DHTlookupCAPICall(); 00145 00146 BinaryValue keyString = (const XmlRpcValue::BinaryData&)params[0]; 00147 dhtLookupMsg->setKey(OverlayKey::sha1(keyString)); 00148 dhtLookupMsg->setNumSiblings(params[1]); 00149 00150 sendRpcMessage(RPC_TO_LOWERTIER, NodeHandle::UNSPECIFIED_NODE, 00151 dhtLookupMsg, NULL, OverlayKey::UNSPECIFIED_KEY, -1, 0); 00152 00153 cancelEvent(timeout_msg); 00154 scheduleAt(simulation.simTime() + XMLRPC_TIMEOUT, timeout_msg); 00155 }
void DHTXMLRealworldApp::put | ( | XmlRpc::XmlRpcValue & | params, | |
XmlRpc::XmlRpcValue & | result | |||
) |
00172 { 00173 if ((params.size() != 4) || 00174 (params[0].getType() != XmlRpcValue::TypeBase64) || 00175 (params[1].getType() != XmlRpcValue::TypeBase64) || 00176 (params[2].getType() != XmlRpcValue::TypeInt) || 00177 (params[3].getType() != XmlRpcValue::TypeString)) 00178 throw XmlRpcException("put(base64 key, base64 value, int ttl " 00179 ", string application): Invalid argument type"); 00180 00181 _connectionState = EXECUTE_REQUEST; 00182 00183 DHTputCAPICall* dhtPutMsg = new DHTputCAPICall(); 00184 00185 00186 BinaryValue keyString = (const XmlRpcValue::BinaryData&)params[0]; 00187 00188 dhtPutMsg->setKey(OverlayKey::sha1(keyString)); 00189 dhtPutMsg->setValue(((const XmlRpcValue::BinaryData&)params[1])); 00190 dhtPutMsg->setTtl(params[2]); 00191 dhtPutMsg->setIsModifiable(true); 00192 00193 sendRpcMessage(RPC_TO_LOWERTIER, NodeHandle::UNSPECIFIED_NODE, dhtPutMsg, NULL, OverlayKey::UNSPECIFIED_KEY, -1, 0); 00194 00195 cancelEvent(timeout_msg); 00196 scheduleAt(simulation.simTime() + XMLRPC_TIMEOUT, timeout_msg); 00197 }
void DHTXMLRealworldApp::get | ( | XmlRpc::XmlRpcValue & | params, | |
XmlRpc::XmlRpcValue & | result | |||
) |
00200 { 00201 if ((params.size() != 4) || 00202 (params[0].getType() != XmlRpcValue::TypeBase64) || 00203 (params[1].getType() != XmlRpcValue::TypeInt) || 00204 (params[2].getType() != XmlRpcValue::TypeBase64) || 00205 (params[3].getType() != XmlRpcValue::TypeString)) 00206 throw XmlRpcException("get(base64 key, int num, base64 placemark " 00207 ", string application): Invalid argument type"); 00208 00209 _connectionState = EXECUTE_REQUEST; 00210 00211 DHTgetCAPICall* dhtGetMsg = new DHTgetCAPICall(); 00212 00213 00214 BinaryValue keyString = (const XmlRpcValue::BinaryData&)params[0]; 00215 dhtGetMsg->setKey(OverlayKey::sha1(keyString)); 00216 00217 sendRpcMessage(RPC_TO_LOWERTIER, NodeHandle::UNSPECIFIED_NODE, dhtGetMsg, NULL, OverlayKey::UNSPECIFIED_KEY, -1, 0); 00218 00219 00220 cancelEvent(timeout_msg); 00221 scheduleAt(simulation.simTime() + XMLRPC_TIMEOUT, timeout_msg); 00222 }
void DHTXMLRealworldApp::joinOverlay | ( | XmlRpc::XmlRpcValue & | params, | |
XmlRpc::XmlRpcValue & | result | |||
) |
00159 { 00160 if ((params.size() != 1) || 00161 (params[0].getType() != XmlRpcValue::TypeBase64)) 00162 throw XmlRpcException("join(base64 nodeID): Invalid argument type"); 00163 00164 BinaryValue nodeID = (const XmlRpcValue::BinaryData&)params[0]; 00165 00166 overlay->join(OverlayKey::sha1(nodeID)); 00167 00168 result[0] = 0; 00169 }
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::_lookup [protected] |
XmlRpc::XmlRpcServerMethod* DHTXMLRealworldApp::_put [protected] |
XmlRpc::XmlRpcServerMethod* DHTXMLRealworldApp::_get [protected] |