ij-16.png   inspectorJ -- JavaTM Profiler
sf project site browse source checkout source
SourceForge.net Logo



src/inspectorj/client/clientpackethandler.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002  *   inspectorJ - java profiler                                            *
00003  *   Copyright (C) 2006 by James May
00004  *                                                                         *
00005  *   This program is free software; you can redistribute it and/or modify  *
00006  *   it under the terms of the GNU General Public License as published by  *
00007  *   the Free Software Foundation; either version 2 of the License, or     *
00008  *   (at your option) any later version.                                   *
00009  *                                                                         *
00010  *   This program is distributed in the hope that it will be useful,       *
00011  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00012  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00013  *   GNU General Public License for more details.                          *
00014  *                                                                         *
00015  *   You should have received a copy of the GNU General Public License     *
00016  *   along with this program; if not, write to the                         *
00017  *   Free Software Foundation, Inc.,                                       *
00018  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
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     // store the replyPacket callback actions
00058     for (int i = 0; i < actions.size(); ++i) {
00059         replyCallbackMap.insert(cmd->getId(), actions[i]);
00060     }
00061 
00062     // send the command
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         // Get the size of the next packet
00093         if (packetSize == 0) {
00094             if (tcpSocket.bytesAvailable() < sizeof(jint)) {
00095                 return;
00096             }
00097             in >> packetSize;
00098         }    
00099         
00100         // Wait until we have all the bytes
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         // Check to see if this is a reply packet or a command packet
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             // read reply data if any
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             //read cmd data if any
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             // Check to see if the handshake succeeded
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         // initialize the ID JDWPPacket id sizes
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     //get the JDWP string length
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 }

Generated on Sun Aug 19 17:07:53 2007 for inspectorJ by  doxygen 1.5.1