#include #include #include #include "sockets/tcpsocket.h" #include "util/process.h" // device tries to connect to a dhcp server // pc sends {0x7f} pkts to udp:5679 // device tries to connect to tcp:7438 // device tries to connect to tcp:990 // // old phones also send data to tcp port 5721 class rapiping : public process { udpsocket_ptr _to5679; tcpaddress _addr; public: rapiping(const tcpaddress& addr) : _addr(addr) { start(); } virtual ~rapiping() { stop(); } virtual const char*name() { return "rapiping"; } virtual void service() { uint8_t byte= 0x7f; _to5679->write(_addr, &byte, 1); HiresTimer::usleep(1000000); } }; class rapistream { // requests a stream, // // todo: implement methods for all rapi functions }; class devicestream : public process { tcpsocket_ptr _tcp; std::string _name; boost::condition _cond; boost::mutex _mtx; public: devicestream(uint32_t cookie) { _name= stringformat("devicestream[%d]", cookie); } virtual const char*name() { return _name.c_str(); } virtual void processstop() { _tcp->shutdown(); _cond.notify_one(); } virtual void service() { boost::mutex::scoped_lock lock(_mtx); if (!_tcp) { while (!_tcp && !isterminating()) _cond.wait(lock); } else { uint32_t len= readdword(); if (len>0x100000) throw "len too large"; ByteVector reply(len); _tcp->read(&reply.front(), reply.size()); } } void addsocket(tcpsocket_ptr tcp) { _tcp= tcp; _cond.notify_one(); } void send_command(int cmd) { writedword(sizeof(uint32_t)); writedword(cmd); } void CeGetSystemInfo() { send_command(0x3d); } void CeGetVersionEx() { send_command(0x43); } void CeGetStoreInformation() { send_command(0x39); } void CeGetGlobalMemoryStatus() { send_command(0x48); } void GetSystemMemoryDivision() { send_command(0x08); } void GetPasswordActive() { send_command(0x05); } private: uint32_t readdword() { uint8_t b[sizeof(uint32_t)]; _tcp->read(b, sizeof(b)); return b[0]+(b[1]<<8)+(b[2]<<16)+(b[3]<<24); } void writedword(uint32_t dw) { uint8_t b[sizeof(uint32_t)]; b[0]= dw&255; dw>>=8; b[1]= dw&255; dw>>=8; b[2]= dw&255; dw>>=8; b[3]= dw&255; _tcp->write(b, sizeof(b)); } }; typedef boost::shared_ptr devicestream_ptr; class deviceserver : public process { tcpsocket_ptr _cmd; std::string _name; uint32_t _curcookie; typedef std::map cookie_stream_map; cookie_stream_map _streammap; // keep track of streams public: deviceserver(tcpsocket_ptr tcp) : _cmd(tcp), _curcookie(1) { _name= std::string("deviceserver[")+_cmd->getpeername()+"]"; } virtual const char*name() { return _name.c_str(); } virtual void processstop() { _cmd.reset(); } virtual void service() { uint32_t req= readdword(); if (req==0) { writedword(3); // -> device will respond with 6 } else if (req==6) { // respond with activesync version writedata(7, bufpack("VV", 4, 5)); // -> device will respond with 4: infopkt } else if (req==4) { // decode info packet // // optionally respond with password // // -> then ready to open streams } else if (req==2) { // response to '1' - keep alive?? } } uint32_t readdword() { uint8_t b[sizeof(uint32_t)]; _cmd->read(b, sizeof(b)); return b[0]+(b[1]<<8)+(b[2]<<16)+(b[3]<<24); } void writedword(uint32_t dw) { uint8_t b[sizeof(uint32_t)]; b[0]= dw&255; dw>>=8; b[1]= dw&255; dw>>=8; b[2]= dw&255; dw>>=8; b[3]= dw&255; _cmd->write(b, sizeof(b)); } void writedata(uint32_t cmd, const ByteVector&v) { writedword(cmd); writedword(v.size()); _cmd->write(&v.front(), v.size()); } // called by the devicestream, to notify the command object // that a stream is no longer active. void delstream(uint32_t cookie) { _streammap.erase(cookie); } // device callback -> stream active void addstream(tcpsocket_ptr tcp) { uint32_t cookie; tcp->read((uint8_t*)&cookie, sizeof(uint32_t)); // invoke callback for the corresponding request cookie_stream_map::iterator i= _streammap.find(cookie); if (i==_streammap.end()) { logmsg("unknown cookie\n"); tcp->shutdown(); return; } (*i).second->addsocket(tcp); } devicestream_ptr requeststream() { uint32_t cookie= generate_cookie(); devicestream_ptr str= devicestream_ptr(new devicestream(cookie)); _streammap.insert(cookie_stream_map::value_type(cookie, str)); // requests a stream on the cmd socket writedata(5, bufpack("N", cookie)); return str; } uint32_t generate_cookie() { return _curcookie++; } }; typedef boost::shared_ptr deviceserver_ptr; // dispatches incoming connections on port 990 to deviceserver objects. class rapiserver : public process { tcpsocket_ptr _port990; typedef std::map devicemap_t; devicemap_t _devices; public: rapiserver() { _port990= tcpsocket_ptr(new tcpsocket()); _port990->listen(tcpaddress(990)); start(); } virtual ~rapiserver() { stop(); } virtual const char*name() { return "rapiserver"; } virtual void processstop() { _port990.reset(); _devices.clear(); } virtual void service() { tcpsocket_ptr tcp= _port990->accept(); if (isterminating()) return; uint32_t peeraddr= tcp->getpeer().addr(); devicemap_t::iterator i= _devices.find(peeraddr); if (i==_devices.end()) { _devices.insert(devicemap_t::value_type(peeraddr, deviceserver_ptr(new deviceserver(tcp)))); } else { (*i).second->addstream(tcp); } } };