j_server.cc

Go to the documentation of this file.
00001 ///
00002 /// \file       j_server.cc
00003 ///             Server protocol implementation
00004 ///
00005 
00006 /*
00007     Copyright (C) 2009, Nicolas VIVIEN
00008 
00009     This program is free software; you can redistribute it and/or modify
00010     it under the terms of the GNU General Public License as published by
00011     the Free Software Foundation; either version 2 of the License, or
00012     (at your option) any later version.
00013 
00014     This program is distributed in the hope that it will be useful,
00015     but WITHOUT ANY WARRANTY; without even the implied warranty of
00016     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00017 
00018     See the GNU General Public License in the COPYING file at the
00019     root directory of this project for more details.
00020 */
00021 
00022 #include "j_server.h"
00023 #include "protocol.h"
00024 #include "data.h"
00025 #include "endian.h"
00026 #include "debug.h"
00027 #include "j_message.h"
00028 #include "protostructs.h"
00029 #include "record-internal.h"
00030 #include "error.h"
00031 
00032 #include <unistd.h>
00033 #include <fcntl.h>
00034 #include <sys/types.h>
00035 #include <sys/socket.h>
00036 #include <netinet/in.h>
00037 #include <arpa/inet.h>
00038 #include <netdb.h>
00039 #include <string.h>
00040 #include <errno.h>
00041 
00042 #include <sstream>
00043 #include <algorithm>
00044 
00045 using namespace std;
00046 
00047 namespace Barry { namespace JDWP {
00048 
00049 static void * acceptThread(void *data);
00050 
00051 
00052 JDWServer::JDWServer(Barry::Mode::JVMDebug &device,
00053                         const char *address, int port)
00054         : jvmdebug(&device)
00055         , acceptfd(-1)
00056         , sockfd(-1)
00057         , address(address)
00058         , port(port)
00059         , loop(false)
00060         , targetrunning(false)
00061         , printConsoleMessage(0)
00062 {
00063         SearchDebugFile(debugFileList);
00064 }
00065 
00066 
00067 JDWServer::~JDWServer()
00068 {
00069         Stop();
00070 }
00071 
00072 
00073 void JDWServer::SetPasswordDevice(string password)
00074 {
00075         this->password = password;
00076 }
00077 
00078 
00079 void JDWServer::SetConsoleCallback(ConsoleCallbackType callback)
00080 {
00081         printConsoleMessage = callback;
00082 }
00083 
00084 static const char* h_strerror(int code)
00085 {
00086         // Codes and messages taken from the Linux gethostbyname(3) manpage
00087         switch( code )
00088         {
00089         case HOST_NOT_FOUND:
00090                 return "HOST_NOT_FOUND: The specified host is unknown";
00091 
00092         case NO_ADDRESS:
00093                 return "NO_ADDRESS: The requested name is valid but does not have an IP address";
00094 
00095         case NO_RECOVERY:
00096                 return "NO_RECOVERY: A non-recoverable name server error occurred";
00097 
00098         case TRY_AGAIN:
00099                 return "TRY_AGAIN: A temporary error occurred on an authoritative name server. Try again later.";
00100 
00101         default:
00102                 return "Unknown network error code";
00103         }
00104 }
00105 
00106 bool JDWServer::Start()
00107 {
00108         int rc;
00109 
00110         struct hostent *hp;
00111         struct sockaddr_in sad;
00112 
00113 
00114         memset((char *) &sad, '\0', sizeof(struct sockaddr_in));
00115 
00116         if (!address.size())
00117                 sad.sin_addr.s_addr = INADDR_ANY;
00118         else {
00119                 sad.sin_addr.s_addr = inet_addr(address.c_str());
00120 
00121                 if (sad.sin_addr.s_addr == INADDR_NONE) {
00122                         hp = gethostbyname(address.c_str());
00123 
00124                         if (hp == NULL) {
00125                                 std::ostringstream oss;
00126                                 oss << "JDWServer::Start: " << h_errno << h_strerror(h_errno);
00127                                 throw Barry::Error(oss.str());
00128                         }
00129 
00130                         memcpy((char*) &sad.sin_addr, (char*) hp->h_addr, (size_t) hp->h_length);
00131                 }
00132         }
00133 
00134         sad.sin_family = AF_INET;
00135         sad.sin_port = htons((short) (port & 0xFFFF));
00136 
00137         // Open socket
00138         sockfd = socket(sad.sin_family, SOCK_STREAM, 0);
00139 
00140         if (sockfd < 0) {
00141                 throw Barry::ErrnoError("JDWServer::Start: Cannot open socket.", errno);
00142         }
00143 
00144         // Bind
00145         rc = bind(sockfd, (struct sockaddr *) &sad, sizeof(sad));
00146 
00147         if (rc < 0) {
00148                 int code = errno;
00149 
00150                 close(sockfd);
00151                 sockfd = -1;
00152 
00153                 throw Barry::ErrnoError("JDWServer::Start: Cannot bind socket", code);
00154         }
00155 
00156         // Listen
00157         if (listen(sockfd, SOMAXCONN) < 0) {
00158                 int code = errno;
00159 
00160                 close(sockfd);
00161                 sockfd = -1;
00162 
00163                 throw Barry::ErrnoError("JDWServer::Start: Cannot listen on socket", code);
00164         }
00165 
00166         handler.reset(new Thread(sockfd, acceptThread, (void*) this));
00167 
00168         return true;
00169 }
00170 
00171 
00172 static void * acceptThread(void *data)
00173 {
00174         JDWServer *s;
00175 
00176         pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
00177 
00178         s = (JDWServer *) data;
00179 
00180         while (1) {
00181                 if( s->AcceptConnection() &&
00182                         s->AttachToDevice() &&
00183                         s->InitVisibleClassList() &&
00184                         s->Hello() )
00185                 {
00186                         s->Run();
00187                         s->DetachFromDevice();
00188                 }
00189         }
00190 
00191         return NULL;
00192 }
00193 
00194 
00195 // Returns true if a new connection was accepted and established
00196 bool JDWServer::AcceptConnection()
00197 {
00198         struct sockaddr_in addr;
00199         struct sockaddr *sa = (struct sockaddr*) &addr;
00200         socklen_t addrlen = sizeof(addr);
00201 
00202         acceptfd = accept(sockfd, sa, &addrlen);
00203         if( acceptfd < 0 )
00204                 return false;
00205 
00206         fcntl(acceptfd, F_SETFL, O_NONBLOCK);
00207         return true;
00208 }
00209 
00210 
00211 bool JDWServer::AttachToDevice()
00212 {
00213         targetrunning = false;
00214 
00215         jvmdebug->Open(password.c_str());
00216         jvmdebug->Attach();
00217 
00218         jvmdebug->Unknown01();
00219         jvmdebug->Unknown02();
00220         jvmdebug->Unknown03();
00221         jvmdebug->Unknown04();
00222         jvmdebug->Unknown05();
00223 
00224         jvmdebug->GetModulesList(modulesList);
00225         dout(modulesList);
00226 
00227         // Check debug info for each modules
00228         JVMModulesList::const_iterator b = modulesList.begin();
00229         for ( ; b != modulesList.end(); b++) {
00230                 JDG::CodInfo codInfo;
00231 
00232                 const JVMModulesEntry &entry = *b;
00233 
00234                 bool ret = LoadDebugInfo(debugFileList, entry.UniqueID, entry.Name, codInfo);
00235 
00236                 if (ret == true) {
00237                         appList[entry.UniqueID].Load(codInfo);
00238                 }
00239                 else {
00240                         dout("No debug information found for '" << entry.Name);
00241                         dout("' (" << hex << setfill('0') << setw(8) << entry.UniqueID << ")." << endl)
00242                 }
00243         }
00244 
00245         return true;
00246 }
00247 
00248 
00249 void JDWServer::DetachFromDevice()
00250 {
00251         jvmdebug->Detach();
00252         jvmdebug->Close();
00253 }
00254 
00255 
00256 #define JDWP_HELLO_STRING               "JDWP-Handshake"
00257 
00258 
00259 
00260 bool JDWServer::Hello()
00261 {
00262         bool ret;
00263 
00264         Barry::Data response;
00265 
00266         const size_t len = strlen(JDWP_HELLO_STRING);
00267 
00268         JDWMessage msg(acceptfd);
00269 
00270         do {
00271                 ret = msg.Receive(response);
00272         }
00273         while (!ret);
00274 
00275         size_t size = response.GetSize();
00276         char *str = (char *) response.GetBuffer();
00277 
00278         if (size != len)
00279                 return false;
00280 
00281         if (!strncmp(str, JDWP_HELLO_STRING, len)) {
00282                 Data command(JDWP_HELLO_STRING, len);
00283 
00284                 msg.Send(command);
00285 
00286                 return true;
00287         }
00288 
00289         return false;
00290 }
00291 
00292 
00293 void JDWServer::Run()
00294 {
00295         string str;
00296         JDWMessage msg(acceptfd);
00297 
00298         Barry::Data command;
00299 
00300         MAKE_JDWPPACKET(rpack, command);
00301 
00302         loop = true;
00303 
00304         while (loop) {
00305                 if (targetrunning) {
00306                         // Read JDWP message from device
00307                         int value = jvmdebug->GetConsoleMessage(str);
00308 
00309                         if (value < 0) {
00310                                 bool ret;
00311                                 int status;
00312 
00313                                 ret = jvmdebug->GetStatus(status);
00314 
00315                                 while (!ret) {
00316                                         // Read JDB message from host
00317                                         msg.Receive(command);
00318 
00319                                         if (command.GetSize() > 0) {
00320                                                 // Convert to packet
00321                                                 rpack = (const Barry::Protocol::JDWP::Packet *) command.GetData();
00322 
00323                                                 if (command.GetSize() != be_btohl(rpack->length)) {
00324                                                         dout("Packet size error !!!" << endl);
00325 
00326                                                         // TODO : add throw exception
00327 
00328                                                         continue;
00329                                                 }
00330 
00331                                                 CommandsetProcess(command);
00332 
00333                                                 break;
00334                                         }
00335                                         else
00336                                                 ret = jvmdebug->WaitStatus(status);
00337                                 }
00338                         }
00339                         else {
00340                                 if (printConsoleMessage != NULL)
00341                                         printConsoleMessage(str);
00342                         }
00343                 }
00344                 else {
00345                         // Read JDB message from host
00346                         msg.Receive(command);
00347 
00348                         if (command.GetSize() > 0) {
00349                                 // Convert to packet
00350                                 rpack = (const Barry::Protocol::JDWP::Packet *) command.GetData();
00351 
00352                                 if (command.GetSize() != be_btohl(rpack->length)) {
00353                                         dout("Packet size error !!!" << endl);
00354 
00355                                         // TODO : add throw exception
00356 
00357                                         continue;
00358                                 }
00359 
00360                                 CommandsetProcess(command);
00361                         }
00362 
00363                         usleep(50);
00364                 }
00365         }
00366 }
00367 
00368 
00369 bool JDWServer::Stop()
00370 {
00371         if( handler.get() ) {
00372                 handler->Dispose();
00373                 handler.reset();
00374         }
00375 
00376         if( sockfd >= 0 ) {
00377                 close(sockfd);
00378                 sockfd = -1;
00379         }
00380 
00381         if( acceptfd >= 0 ) {
00382                 close(acceptfd);
00383                 acceptfd = -1;
00384         }
00385 
00386         return true;
00387 }
00388 
00389 
00390 bool JDWServer::InitVisibleClassList()
00391 {
00392         int index;
00393 
00394         // Skip the cell '0'
00395         // it's very ugly, but I want use an index started at '1' inside of '0'
00396         // JDB works from '1' :(
00397         JDG::ClassEntry e;
00398         visibleClassList.push_back(e);
00399 
00400         // Count and index the class (start to '1')
00401         index = 1;
00402         JDWAppList::iterator it;
00403 
00404         for (it = appList.begin(); it != appList.end(); it++) {
00405                 JDWAppInfo &appInfo = it->second;
00406                 JDG::ClassList &list = appInfo.classList;
00407 
00408                 JDG::ClassList::iterator b;
00409 
00410                 for (b = list.begin(); b != list.end(); b++) {
00411                         // FIXME
00412                         // I don't from class field, we have to filter the class view by JDB
00413 //                      if ((b->type != 0x824) && (b->type != 0x64)) {
00414                         if (b->id == 0xffffffff) {
00415                                 b->index = -1;
00416 
00417                                 continue;
00418                         }
00419 
00420                         b->index = index;
00421 
00422                         visibleClassList.push_back(*b);
00423 
00424                         index++;
00425                 }
00426         }
00427 
00428         visibleClassList.CreateDefaultEntries();
00429 
00430         return true;
00431 }
00432 
00433 
00434 void JDWServer::CommandsetProcess(Data &cmd)
00435 {
00436         MAKE_JDWPPACKET(rpack, cmd);
00437 
00438         switch (rpack->u.command.commandset) {
00439                 case JDWP_CMDSET_VIRTUALMACHINE:
00440                         CommandsetVirtualMachineProcess(cmd);
00441                         break;
00442 
00443                 case JDWP_CMDSET_REFERECENTYPE:
00444                         break;
00445 
00446                 case JDWP_CMDSET_CLASSTYPE:
00447                         break;
00448 
00449                 case JDWP_CMDSET_ARRAYTYPE:
00450                         break;
00451 
00452                 case JDWP_CMDSET_INTERFACETYPE:
00453                         break;
00454 
00455                 case JDWP_CMDSET_METHOD:
00456                         break;
00457 
00458                 case JDWP_CMDSET_FIELD:
00459                         break;
00460 
00461                 case JDWP_CMDSET_OBJECTREFERENCE:
00462                         break;
00463 
00464                 case JDWP_CMDSET_STRINGREFERENCE:
00465                         break;
00466 
00467                 case JDWP_CMDSET_THREADREFERENCE:
00468                         break;
00469 
00470                 case JDWP_CMDSET_THREADGROUPREFERENCE:
00471                         break;
00472 
00473                 case JDWP_CMDSET_ARRAYREFERENCE:
00474                         break;
00475 
00476                 case JDWP_CMDSET_CLASSLOADERREFERENCE:
00477                         break;
00478 
00479                 case JDWP_CMDSET_EVENTREQUEST:
00480                         CommandsetEventRequestProcess(cmd);
00481                         break;
00482 
00483                 case JDWP_CMDSET_STACKFRAME:
00484                         break;
00485 
00486                 case JDWP_CMDSET_CLASSOBJECTREFERENCE:
00487                         break;
00488 
00489                 case JDWP_CMDSET_EVENT:
00490                         break;
00491 
00492                 default:
00493                         // TODO : add exception (or alert)
00494                         dout("Commandset unknown !!!" << endl);
00495         }
00496 }
00497 
00498 
00499 void JDWServer::CommandsetVirtualMachineProcess(Data &cmd)
00500 {
00501         MAKE_JDWPPACKET(rpack, cmd);
00502 
00503         switch (rpack->u.command.command) {
00504                 case JDWP_CMD_VERSION:
00505                         CommandVersion(cmd);
00506                         break;
00507 
00508                 case JDWP_CMD_ALLCLASSES:
00509                         CommandAllClasses(cmd);
00510                         break;
00511 
00512                 case JDWP_CMD_ALLTHREADS:
00513                         CommandAllThreads(cmd);
00514                         break;
00515 
00516                 case JDWP_CMD_DISPOSE:
00517                         loop = false;
00518                         targetrunning = false;
00519                         close(acceptfd);
00520                         acceptfd = -1;
00521                         break;
00522 
00523                 case JDWP_CMD_IDSIZES:
00524                         CommandIdSizes(cmd);
00525                         break;
00526 
00527                 case JDWP_CMD_SUSPEND:
00528                         CommandSuspend(cmd);
00529                         targetrunning = false;
00530                         break;
00531 
00532                 case JDWP_CMD_RESUME:
00533                         CommandResume(cmd);
00534                         targetrunning = true;
00535                         break;
00536 
00537                 case JDWP_CMD_CLASSPATHS:
00538                         CommandClassPaths(cmd);
00539                         break;
00540         }
00541 }
00542 
00543 
00544 void JDWServer::CommandsetEventRequestProcess(Data &cmd)
00545 {
00546         MAKE_JDWPPACKET(rpack, cmd);
00547 
00548         switch (rpack->u.command.command) {
00549                 case JDWP_CMD_SET:
00550                         CommandSet(cmd);
00551                         break;
00552         }
00553 }
00554 
00555 
00556 void JDWServer::CommandVersion(Data &cmd)
00557 {
00558         JDWMessage msg(acceptfd);
00559 
00560         // Build packet data
00561         Data response;
00562 
00563         size_t offset = JDWP_PACKET_HEADER_SIZE + JDWP_RESPONSE_HEADER_SIZE;
00564 
00565         AddJDWString(response, offset, string("RIM JVM"));
00566         AddJDWInt(response, offset, be_htobl(1));
00567         AddJDWInt(response, offset, be_htobl(4));
00568         AddJDWString(response, offset, string("1.4"));
00569         AddJDWString(response, offset, string("RIM JVM"));
00570 
00571         response.ReleaseBuffer(offset);
00572 
00573 
00574         size_t total_size = response.GetSize();
00575 
00576         // Fill in the header values
00577         MAKE_JDWPPACKETPTR_BUF(cpack, response.GetBuffer(total_size));
00578         Barry::Protocol::JDWP::Packet &packet = *cpack;
00579 
00580 
00581         MAKE_JDWPPACKET(rpack, cmd);
00582 
00583         packet.length = be_htobl(total_size);
00584         packet.id = rpack->id;
00585         packet.flags = 0x80;
00586         packet.u.response.errorcode = be_htobs(0);
00587 
00588         response.ReleaseBuffer(total_size);
00589         msg.Send(response);
00590 }
00591 
00592 
00593 void JDWServer::CommandAllClasses(Data &cmd)
00594 {
00595         size_t i;
00596         int size;
00597 
00598         JDWMessage msg(acceptfd);
00599 
00600         // Build packet data
00601         Data response;
00602 
00603         size_t offset = JDWP_PACKET_HEADER_SIZE + JDWP_RESPONSE_HEADER_SIZE;
00604 
00605         // Size of known class list
00606         size = visibleClassList.size() - 1;
00607 
00608         AddJDWInt(response, offset, be_htobl(size));
00609 
00610         // Then, write the list of known class
00611         for (i=1; i<visibleClassList.size(); i++) {
00612                 string str = visibleClassList[i].GetFullClassName();
00613 
00614                 str = "L" + str + ";";
00615                 replace_if(str.begin(), str.end(), bind2nd(equal_to<char>(),'.'), '/');
00616 
00617                 AddJDWByte(response, offset, 0x01);
00618                 AddJDWInt(response, offset, i); // Should be equal to visibleClassList[i].index
00619                 AddJDWString(response, offset, str);
00620                 AddJDWInt(response, offset, be_htobl(0x04));
00621         }
00622 
00623         response.ReleaseBuffer(offset);
00624 
00625 
00626         size_t total_size = response.GetSize();
00627 
00628         // Fill in the header values
00629         MAKE_JDWPPACKETPTR_BUF(cpack, response.GetBuffer(total_size));
00630         Barry::Protocol::JDWP::Packet &packet = *cpack;
00631 
00632 
00633         MAKE_JDWPPACKET(rpack, cmd);
00634 
00635         packet.length = be_htobl(total_size);
00636         packet.id = rpack->id;
00637         packet.flags = 0x80;
00638         packet.u.response.errorcode = be_htobs(0);
00639 
00640         response.ReleaseBuffer(total_size);
00641         msg.Send(response);
00642 }
00643 
00644 
00645 void JDWServer::CommandAllThreads(Data &cmd)
00646 {
00647         JDWMessage msg(acceptfd);
00648 
00649         // Get threads list from device
00650         JVMThreadsList list;
00651         jvmdebug->GetThreadsList(list);
00652         dout(list);
00653 
00654         // Build packet data
00655         Data response;
00656 
00657         size_t offset = JDWP_PACKET_HEADER_SIZE + JDWP_RESPONSE_HEADER_SIZE;
00658 
00659         // Indicate the number of element
00660         AddJDWInt(response, offset, be_htobl(list.size()));
00661 
00662         // Send all threads ID
00663         JVMThreadsList::const_iterator b = list.begin();
00664         for( ; b != list.end(); b++ ) {
00665                 const JVMThreadsEntry &entry = *b;
00666 
00667                 AddJDWInt(response, offset, be_htobl(entry.Id));
00668         }
00669 
00670         response.ReleaseBuffer(offset);
00671 
00672 
00673         size_t total_size = response.GetSize();
00674 
00675         // Fill in the header values
00676         MAKE_JDWPPACKETPTR_BUF(cpack, response.GetBuffer(total_size));
00677         Barry::Protocol::JDWP::Packet &packet = *cpack;
00678 
00679 
00680         MAKE_JDWPPACKET(rpack, cmd);
00681 
00682         packet.length = be_htobl(total_size);
00683         packet.id = rpack->id;
00684         packet.flags = 0x80;
00685         packet.u.response.errorcode = be_htobs(0);
00686 
00687         response.ReleaseBuffer(total_size);
00688         msg.Send(response);
00689 }
00690 
00691 
00692 void JDWServer::CommandIdSizes(Data &cmd)
00693 {
00694         JDWMessage msg(acceptfd);
00695 
00696         MAKE_JDWPPACKET(rpack, cmd);
00697 
00698         size_t size;
00699 
00700         Barry::Protocol::JDWP::Packet packet;
00701 
00702         size = JDWP_PACKET_HEADER_SIZE + JDWP_RESPONSE_HEADER_SIZE
00703                 + JDWP_PACKETVIRTUALMACHINEIDSIZES_DATA_SIZE;
00704 
00705         packet.length = be_htobl(size);
00706         packet.id = rpack->id;
00707         packet.flags = 0x80;
00708         packet.u.response.errorcode = be_htobs(0);
00709         packet.u.response.u.virtualMachine.u.IDSizes.fieldIDSize = be_htobl(0x04);
00710         packet.u.response.u.virtualMachine.u.IDSizes.methodIDSize = be_htobl(0x04);
00711         packet.u.response.u.virtualMachine.u.IDSizes.objectIDSize = be_htobl(0x04);
00712         packet.u.response.u.virtualMachine.u.IDSizes.referenceTypeIDSize = be_htobl(0x04);
00713         packet.u.response.u.virtualMachine.u.IDSizes.frameIDSize = be_htobl(0x04);
00714 
00715         Data response(&packet, size);
00716 
00717         msg.Send(response);
00718 }
00719 
00720 
00721 void JDWServer::CommandSuspend(Data &cmd)
00722 {
00723         JDWMessage msg(acceptfd);
00724 
00725 
00726         // Suspend device
00727         jvmdebug->Stop();
00728 
00729         // Notify debugger
00730         MAKE_JDWPPACKET(rpack, cmd);
00731 
00732         size_t size;
00733 
00734         Barry::Protocol::JDWP::Packet packet;
00735 
00736         size = JDWP_PACKET_HEADER_SIZE + JDWP_RESPONSE_HEADER_SIZE;
00737 
00738         packet.length = be_htobl(size);
00739         packet.id = rpack->id;
00740         packet.flags = 0x80;
00741         packet.u.response.errorcode = be_htobs(0);
00742 
00743         Data response(&packet, size);
00744 
00745         msg.Send(response);
00746 }
00747 
00748 
00749 void JDWServer::CommandResume(Data &cmd)
00750 {
00751         JDWMessage msg(acceptfd);
00752 
00753 
00754         // Resume device
00755         jvmdebug->Unknown06();
00756         jvmdebug->Unknown07();
00757         jvmdebug->Unknown08();
00758         jvmdebug->Unknown09();
00759         jvmdebug->Unknown10();
00760         jvmdebug->Go();
00761 
00762         // Notify debugger
00763         MAKE_JDWPPACKET(rpack, cmd);
00764 
00765         size_t size;
00766 
00767         Barry::Protocol::JDWP::Packet packet;
00768 
00769         size = JDWP_PACKET_HEADER_SIZE + JDWP_RESPONSE_HEADER_SIZE;
00770 
00771         packet.length = be_htobl(size);
00772         packet.id = rpack->id;
00773         packet.flags = 0x80;
00774         packet.u.response.errorcode = be_htobs(0);
00775 
00776         Data response(&packet, size);
00777 
00778         msg.Send(response);
00779 }
00780 
00781 
00782 void JDWServer::CommandClassPaths(Data &cmd)
00783 {
00784         JDWMessage msg(acceptfd);
00785 
00786         // Build packet data
00787         Data response;
00788 
00789         size_t offset = JDWP_PACKET_HEADER_SIZE + JDWP_RESPONSE_HEADER_SIZE;
00790 
00791         AddJDWString(response, offset, string(""));
00792         AddJDWInt(response, offset, be_htobl(0));
00793         AddJDWInt(response, offset, be_htobl(0));
00794 
00795         response.ReleaseBuffer(offset);
00796 
00797 
00798         size_t total_size = response.GetSize();
00799 
00800         // Fill in the header values
00801         MAKE_JDWPPACKETPTR_BUF(cpack, response.GetBuffer(total_size));
00802         Barry::Protocol::JDWP::Packet &packet = *cpack;
00803 
00804 
00805         MAKE_JDWPPACKET(rpack, cmd);
00806 
00807         packet.length = be_htobl(total_size);
00808         packet.id = rpack->id;
00809         packet.flags = 0x80;
00810         packet.u.response.errorcode = be_htobs(0);
00811 
00812         response.ReleaseBuffer(total_size);
00813         msg.Send(response);
00814 }
00815 
00816 
00817 
00818 void JDWServer::CommandSet(Data &cmd)
00819 {
00820         static int value = 2;
00821 
00822         JDWMessage msg(acceptfd);
00823 
00824         MAKE_JDWPPACKET(rpack, cmd);
00825 
00826         size_t size;
00827 
00828         Barry::Protocol::JDWP::Packet packet;
00829 
00830         size = JDWP_PACKET_HEADER_SIZE + JDWP_RESPONSE_HEADER_SIZE + sizeof(uint32_t);
00831 
00832         packet.length = be_htobl(size);
00833         packet.id = rpack->id;
00834         packet.flags = 0x80;
00835         packet.u.response.errorcode = be_htobs(0);
00836         packet.u.response.u.value = be_htobl(value);
00837 
00838         Data response(&packet, size);
00839 
00840         msg.Send(response);
00841 
00842         value++;
00843 }
00844 
00845 
00846 }} // namespace Barry::JDWP
00847