00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00027 #include <iostream>
00028 #include "inspectorj/client/clientpackethandler.h"
00029
00030 using namespace inspectorj::client;
00031 using namespace inspectorj::jdwp;
00032
00039 ClientPacketHandler::ClientPacketHandler(QTcpSocket &socket)
00040 : tcpSocket(socket), packetSize(0)
00041 {
00042 initIdSizesAction = new JDWPAction(this);
00043 connect (initIdSizesAction, SIGNAL (triggered(JDWPPacket&)), this, SLOT (initIdSizes(JDWPPacket&)));
00044 }
00045
00055 void ClientPacketHandler::sendJDWPCommand(JDWPCommand* cmd, QList<JDWPAction*>& actions)
00056 {
00057
00058 for (int i = 0; i < actions.size(); ++i) {
00059 replyCallbackMap.insert(cmd->getId(), actions[i]);
00060 }
00061
00062
00063 QByteArray block;
00064 QDataStream out(&block, QIODevice::WriteOnly);
00065 out << cmd->getLength();
00066 out << cmd->getId();
00067 out << cmd->getPacketType();
00068 out << cmd->getCmdSet();
00069 out << cmd->getCmd();
00070
00071 if (cmd->getLength() > JDWP_HEADER_LENGTH) {
00072 out.writeRawData(cmd->getDataBytes(), cmd->getLength() - JDWP_HEADER_LENGTH);
00073 }
00074
00075 tcpSocket.write(block);
00076 delete cmd;
00077 cmd = 0;
00078 }
00079
00085 void ClientPacketHandler::readJDWPPacket()
00086 {
00087 QDataStream in(&tcpSocket);
00088 in.setVersion(QDataStream::Qt_4_1);
00089
00090 while (tcpSocket.bytesAvailable()) {
00091
00092
00093 if (packetSize == 0) {
00094 if (tcpSocket.bytesAvailable() < sizeof(jint)) {
00095 return;
00096 }
00097 in >> packetSize;
00098 }
00099
00100
00101 if (tcpSocket.bytesAvailable() < packetSize - sizeof(jint)) {
00102 return;
00103 }
00104 int dataSize = packetSize - JDWP_HEADER_LENGTH;
00105 qint32 id;
00106 jbyte flags;
00107
00108 in >> id;
00109 in >> flags;
00110
00111
00112 if (flags == (jbyte) JDWPTRANSPORT_FLAGS_REPLY) {
00113
00114 jdwpReplyPacket replyPacket;
00115 replyPacket.len = packetSize;
00116 replyPacket.id = id;
00117 replyPacket.flags = flags;
00118 in >> replyPacket.errorCode;
00119
00120 if ( dataSize > 0 ) {
00121 replyPacket.data = new jbyte[dataSize];
00122 tcpSocket.read((char *)replyPacket.data, (qint64) dataSize);
00123 } else {
00124 replyPacket.data = NULL;
00125 }
00126
00127 JDWPReply reply = JDWPReply(replyPacket);
00128 handleResponse(reply);
00129
00130 } else {
00131
00132 jdwpCmdPacket cmdPacket;
00133 cmdPacket.len = packetSize;
00134 cmdPacket.id = id;
00135 cmdPacket.flags = flags;
00136 in >> cmdPacket.cmdSet;
00137 in >> cmdPacket.cmd;
00138
00139
00140 if ( dataSize > 0 ) {
00141 cmdPacket.data = new jbyte[dataSize];
00142 tcpSocket.read((char*)cmdPacket.data, (qint64) dataSize);
00143 } else {
00144 cmdPacket.data = NULL;
00145 }
00146
00147 JDWPCommand cmd = JDWPCommand(cmdPacket);
00148 handleResponse(cmd);
00149 }
00150 packetSize = 0;
00151 }
00152 }
00153
00160 void ClientPacketHandler::handleResponse(JDWPPacket &reply)
00161 {
00162 int id = reply.getId();
00163 QList<JDWPAction*> actions = replyCallbackMap.values(id);
00164 replyCallbackMap.remove(id);
00165
00166 for (int i = 0; i < actions.size(); ++i)
00167 {
00168 JDWPAction *action = actions[i];
00169 action->trigger(reply);
00170 }
00171 }
00172
00180 void ClientPacketHandler::getHandshake(bool &attached, QString &msg)
00181 {
00182 QDataStream in(&tcpSocket);
00183 in.setVersion(QDataStream::Qt_4_2);
00184
00185 while (true) {
00186 if (tcpSocket.bytesAvailable() < JDWP_HANDSHAKE_LENGTH)
00187 {
00188 break;
00189 }
00190
00191 char* resp = new char[JDWP_HANDSHAKE_LENGTH + 1];
00192 tcpSocket.read(resp, (qint64) JDWP_HANDSHAKE_LENGTH);
00193 resp[14] = 0;
00194
00195
00196 if (strcmp(resp, JDWP_HANDSHAKE) != 0)
00197 {
00198 msg = QString("Error: handshake failed.");
00199 delete[] resp;
00200 resp = 0;
00201 tcpSocket.close();
00202 break;
00203 } else {
00204 QString peerName = tcpSocket.peerName();
00205 QString peerPort;
00206 peerPort.setNum(tcpSocket.peerPort());
00207 msg = QString("Connected to ").append(peerName).append(":").append(peerPort);
00208 }
00209
00210 attached = true;
00211
00212
00213 JDWPCommand *cmd = JDWPCommand::newCommand(VM_CMD_ID_SIZES);
00214 QList<JDWPAction*> actions;
00215 actions << initIdSizesAction;
00216 sendJDWPCommand(cmd, actions);
00217
00218 delete[] resp;
00219 resp = 0;
00220 break;
00221 }
00222 }
00223
00228 void ClientPacketHandler::initIdSizes(JDWPPacket& reply)
00229 {
00230 JDWPPacket::initIDSizes(reply);
00231 }
00232
00239 void ClientPacketHandler::operator>>(QString &s)
00240 {
00241
00242 int len;
00243 char *p = (char *)(&len);
00244 char b[4];
00245 tcpSocket.read(b,4);
00246 *p++ = b[3];
00247 *p++ = b[2];
00248 *p++ = b[1];
00249 *p = b[0];
00250
00251 char * tmp = new char[len];
00252 tcpSocket.read(tmp, (qint64) len);
00253 s = QString(tmp);
00254 delete [] tmp;
00255 tmp = 0;
00256 }
00257
00265 void ClientPacketHandler::getSocketError(QAbstractSocket::SocketError error, QString &errMsg)
00266 {
00267 switch (error)
00268 {
00269 case QAbstractSocket::ConnectionRefusedError : errMsg = "The connection was refused by the peer (or timed out)."; break;
00270 case QAbstractSocket::RemoteHostClosedError : errMsg = "The remote host closed the connection."; break;
00271 case QAbstractSocket::HostNotFoundError : errMsg = "The host address was not found."; break;
00272 case QAbstractSocket::SocketAccessError : errMsg = "The socket operation failed because the application lacked the required privileges."; break;
00273 case QAbstractSocket::SocketResourceError : errMsg = "The local system ran out of resources (e.g., too many sockets)."; break;
00274 case QAbstractSocket::SocketTimeoutError : errMsg = "The socket operation timed out."; break;
00275 case QAbstractSocket::DatagramTooLargeError : errMsg = "The datagram was larger than the operating system's limit (which can be as low as 8192 bytes)."; break;
00276 case QAbstractSocket::NetworkError : errMsg = "An error occurred with the network (e.g., the network cable was accidentally plugged out)."; break;
00277 case QAbstractSocket::AddressInUseError : errMsg = "The address specified to QUdpSocket::bind() is already in use and was set to be exclusive."; break;
00278 case QAbstractSocket::SocketAddressNotAvailableError : errMsg = "The address specified to QUdpSocket::bind() does not belong to the host."; break;
00279 case QAbstractSocket::UnsupportedSocketOperationError : errMsg = "The requested socket operation is not supported by the local operating system."; break;
00280 case QAbstractSocket::UnknownSocketError : errMsg = "An unidentified socket error has occurred.";
00281 }
00282 }
00283
00288 bool ClientPacketHandler::handleJDWPError(JDWPPacket &packet)
00289 {
00290
00291 jint errCode = packet.getErrorCode();
00292 bool hasError = (errCode != (jint)ERR_NONE);
00293 if (hasError) {
00294 QString msg;
00295 ClientPacketHandler::getJDWPError(errCode, msg);
00296 QMessageBox::warning( 0, "inspectorJ Error", msg,
00297 QMessageBox::Ok | QMessageBox::Default);
00298 }
00299 return hasError;
00300 }
00310 void ClientPacketHandler::getJDWPError(int errCode, QString &s)
00311 {
00312 switch (errCode)
00313 {
00314 case ERR_NONE : s = "No error has occurred."; break;
00315 case ERR_INVALID_THREAD : s = "Passed thread is null, is not a valid thread or has exited."; break;
00316 case ERR_INVALID_THREAD_GROUP : s = "Thread group invalid."; break;
00317 case ERR_INVALID_PRIORITY : s = "Invalid priority."; break;
00318 case ERR_THREAD_NOT_SUSPENDED : s = "If the specified thread has not been suspended by an event."; break;
00319 case ERR_THREAD_SUSPENDED : s = "Thread already suspended."; break;
00320 case ERR_INVALID_OBJECT : s = "If this reference type has been unloaded and garbage collected."; break;
00321 case ERR_INVALID_CLASS : s = "Invalid class."; break;
00322 case ERR_CLASS_NOT_PREPARED : s = "Class has been loaded but not yet prepared."; break;
00323 case ERR_INVALID_METHODID : s = "Invalid method."; break;
00324 case ERR_INVALID_LOCATION : s = "Invalid location."; break;
00325 case ERR_INVALID_FIELDID : s = "Invalid field."; break;
00326 case ERR_INVALID_FRAMEID : s = "Invalid jframeID."; break;
00327 case ERR_NO_MORE_FRAMES : s = "There are no more Java or JNI frames on the call stack."; break;
00328 case ERR_OPAQUE_FRAME : s = "Information about the frame is not available."; break;
00329 case ERR_NOT_CURRENT_FRAME : s = "Operation can only be performed on current frame."; break;
00330 case ERR_TYPE_MISMATCH : s = "The variable is not an appropriate type for the function used."; break;
00331 case ERR_INVALID_SLOT : s = "Invalid slot."; break;
00332 case ERR_DUPLICATE : s = "Item already set."; break;
00333 case ERR_NOT_FOUND : s = "Desired element not found."; break;
00334 case ERR_INVALID_MONITOR : s = "Invalid monitor."; break;
00335 case ERR_NOT_MONITOR_OWNER : s = "This thread doesn't own the monitor."; break;
00336 case ERR_INTERRUPT : s = "The call has been interrupted before completion."; break;
00337 case ERR_INVALID_CLASS_FORMAT : s = "The virtual machine attempted to read a class file and determined that the file is malformed or otherwise cannot be interpreted as a class file."; break;
00338 case ERR_CIRCULAR_CLASS_DEFINITION : s = "A circularity has been detected while initializing a class."; break;
00339 case ERR_FAILS_VERIFICATION : s = "The verifier detected that a class file, though well formed, contained some sort of internal inconsistency or security problem."; break;
00340 case ERR_ADD_METHOD_NOT_IMPLEMENTED : s = "Adding methods has not been implemented."; break;
00341 case ERR_SCHEMA_CHANGE_NOT_IMPLEMENTED : s = "Schema change has not been implemented."; break;
00342 case ERR_INVALID_TYPESTATE : s = "The state of the thread has been modified, and is now inconsistent."; break;
00343 case ERR_HIERARCHY_CHANGE_NOT_IMPLEMENTED : s = "A direct superclass is different for the new class version, or the set of directly implemented interfaces is different and canUnrestrictedlyRedefineClasses is false."; break;
00344 case ERR_DELETE_METHOD_NOT_IMPLEMENTED : s = "The new class version does not declare a method declared in the old class version and canUnrestrictedlyRedefineClasses is false."; break;
00345 case ERR_UNSUPPORTED_VERSION : s = "A class file has a version number not supported by this VM."; break;
00346 case ERR_NAMES_DONT_MATCH : s = "The class name defined in the new class file is different from the name in the old class object."; break;
00347 case ERR_CLASS_MODIFIERS_CHANGE_NOT_IMPLEMENTED : s = "The new class version has different modifiers and and canUnrestrictedlyRedefineClasses is false."; break;
00348 case ERR_METHOD_MODIFIERS_CHANGE_NOT_IMPLEMENTED : s = "A method in the new class version has different modifiers than its counterpart in the old class version and and canUnrestrictedlyRedefineClasses is false."; break;
00349 case ERR_NOT_IMPLEMENTED : s = "The functionality requested is not implemented by this agent."; break;
00350 case ERR_NULL_POINTER : s = "Invalid pointer."; break;
00351 case ERR_ABSENT_INFORMATION : s = "Desired information is not available."; break;
00352 case ERR_INVALID_EVENT_TYPE : s = "The specified event type id is not recognized."; break;
00353 case ERR_ILLEGAL_ARGUMENT : s = "Illegal argument."; break;
00354 case ERR_OUT_OF_MEMORY : s = "The function needed to allocate memory and no more memory was available for allocation."; break;
00355 case ERR_ACCESS_DENIED : s = "Debugging has not been enabled in this virtual machine. JVMDI cannot be used."; break;
00356 case ERR_VM_DEAD : s = "The virtual machine is not running."; break;
00357 case ERR_INTERNAL : s = "An unexpected internal error has occurred."; break;
00358 case ERR_UNATTACHED_THREAD : s = "The thread being used to call this function is not attached to the virtual machine. Calls must be made from attached threads."; break;
00359 case ERR_INVALID_TAG : s = "object type id or class tag."; break;
00360 case ERR_ALREADY_INVOKING : s = "Previous invoke not complete."; break;
00361 case ERR_INVALID_INDEX : s = "Index is invalid."; break;
00362 case ERR_INVALID_LENGTH : s = "The length is invalid."; break;
00363 case ERR_INVALID_STRING : s = "The string is invalid."; break;
00364 case ERR_INVALID_CLASS_LOADER : s = "The class loader is invalid."; break;
00365 case ERR_INVALID_ARRAY : s = "The array is invalid."; break;
00366 case ERR_TRANSPORT_LOAD : s = "Unable to load the transport."; break;
00367 case ERR_TRANSPORT_INIT : s = "Unable to initialize the transport."; break;
00368 case ERR_NATIVE_METHOD : s = " Native method error."; break;
00369 case ERR_INVALID_COUNT : s = "The count is invalid.";
00370 }
00371 }