121b177e0SEddie James #include "ikvm_server.hpp" 221b177e0SEddie James 329f775abSEddie James #include <rfb/rfbproto.h> 429f775abSEddie James 5*f79f6f54SGeorge Liu #include <boost/crc.hpp> 629f775abSEddie James #include <phosphor-logging/elog-errors.hpp> 729f775abSEddie James #include <phosphor-logging/elog.hpp> 829f775abSEddie James #include <phosphor-logging/log.hpp> 929f775abSEddie James #include <xyz/openbmc_project/Common/error.hpp> 1029f775abSEddie James 1121b177e0SEddie James namespace ikvm 1221b177e0SEddie James { 1321b177e0SEddie James 1429f775abSEddie James using namespace phosphor::logging; 1529f775abSEddie James using namespace sdbusplus::xyz::openbmc_project::Common::Error; 1629f775abSEddie James 1721b177e0SEddie James Server::Server(const Args& args, Input& i, Video& v) : 1829f775abSEddie James pendingResize(false), frameCounter(0), numClients(0), input(i), video(v) 1921b177e0SEddie James { 2029f775abSEddie James std::string ip("localhost"); 2129f775abSEddie James const Args::CommandLine& commandLine = args.getCommandLine(); 2229f775abSEddie James int argc = commandLine.argc; 2329f775abSEddie James 2429f775abSEddie James server = rfbGetScreen(&argc, commandLine.argv, video.getWidth(), 2529f775abSEddie James video.getHeight(), Video::bitsPerSample, 2629f775abSEddie James Video::samplesPerPixel, Video::bytesPerPixel); 2729f775abSEddie James 2829f775abSEddie James if (!server) 2929f775abSEddie James { 3029f775abSEddie James log<level::ERR>("Failed to get VNC screen due to invalid arguments"); 3129f775abSEddie James elog<InvalidArgument>( 3229f775abSEddie James xyz::openbmc_project::Common::InvalidArgument::ARGUMENT_NAME(""), 3329f775abSEddie James xyz::openbmc_project::Common::InvalidArgument::ARGUMENT_VALUE("")); 3429f775abSEddie James } 3529f775abSEddie James 3629f775abSEddie James framebuffer.resize( 3729f775abSEddie James video.getHeight() * video.getWidth() * Video::bytesPerPixel, 0); 3829f775abSEddie James 3929f775abSEddie James server->screenData = this; 4029f775abSEddie James server->desktopName = "OpenBMC IKVM"; 4129f775abSEddie James server->frameBuffer = framebuffer.data(); 4229f775abSEddie James server->newClientHook = newClient; 437dfac9ffSJae Hyun Yoo server->cursor = rfbMakeXCursor(cursorWidth, cursorHeight, (char*)cursor, 447dfac9ffSJae Hyun Yoo (char*)cursorMask); 457dfac9ffSJae Hyun Yoo server->cursor->xhot = 1; 467dfac9ffSJae Hyun Yoo server->cursor->yhot = 1; 4729f775abSEddie James 4829f775abSEddie James rfbStringToAddr(&ip[0], &server->listenInterface); 4929f775abSEddie James 5029f775abSEddie James rfbInitServer(server); 5129f775abSEddie James 5229f775abSEddie James rfbMarkRectAsModified(server, 0, 0, video.getWidth(), video.getHeight()); 5329f775abSEddie James 5429f775abSEddie James server->kbdAddEvent = Input::keyEvent; 5529f775abSEddie James server->ptrAddEvent = Input::pointerEvent; 5629f775abSEddie James 5729f775abSEddie James processTime = (1000000 / video.getFrameRate()) - 100; 582d2f3dabSPaul Fertser 592d2f3dabSPaul Fertser calcFrameCRC = args.getCalcFrameCRC(); 6021b177e0SEddie James } 6121b177e0SEddie James 6221b177e0SEddie James Server::~Server() 6321b177e0SEddie James { 6429f775abSEddie James rfbScreenCleanup(server); 6529f775abSEddie James } 6629f775abSEddie James 6729f775abSEddie James void Server::resize() 6829f775abSEddie James { 6929f775abSEddie James if (frameCounter > video.getFrameRate()) 7029f775abSEddie James { 7129f775abSEddie James doResize(); 7229f775abSEddie James } 7329f775abSEddie James else 7429f775abSEddie James { 7529f775abSEddie James pendingResize = true; 7629f775abSEddie James } 7729f775abSEddie James } 7829f775abSEddie James 7929f775abSEddie James void Server::run() 8029f775abSEddie James { 8129f775abSEddie James rfbProcessEvents(server, processTime); 8229f775abSEddie James 8329f775abSEddie James if (server->clientHead) 8429f775abSEddie James { 8529f775abSEddie James frameCounter++; 8629f775abSEddie James if (pendingResize && frameCounter > video.getFrameRate()) 8729f775abSEddie James { 8829f775abSEddie James doResize(); 8929f775abSEddie James pendingResize = false; 9029f775abSEddie James } 9129f775abSEddie James } 9229f775abSEddie James } 9329f775abSEddie James 9429f775abSEddie James void Server::sendFrame() 9529f775abSEddie James { 9629f775abSEddie James char* data = video.getData(); 9729f775abSEddie James rfbClientIteratorPtr it; 9829f775abSEddie James rfbClientPtr cl; 992d2f3dabSPaul Fertser int64_t frame_crc = -1; 10029f775abSEddie James 10129f775abSEddie James if (!data || pendingResize) 10229f775abSEddie James { 10329f775abSEddie James return; 10429f775abSEddie James } 10529f775abSEddie James 10629f775abSEddie James it = rfbGetClientIterator(server); 10729f775abSEddie James 10829f775abSEddie James while ((cl = rfbClientIteratorNext(it))) 10929f775abSEddie James { 11029f775abSEddie James ClientData* cd = (ClientData*)cl->clientData; 11129f775abSEddie James rfbFramebufferUpdateMsg* fu = (rfbFramebufferUpdateMsg*)cl->updateBuf; 11229f775abSEddie James 11329f775abSEddie James if (!cd) 11429f775abSEddie James { 11529f775abSEddie James continue; 11629f775abSEddie James } 11729f775abSEddie James 11829f775abSEddie James if (cd->skipFrame) 11929f775abSEddie James { 12029f775abSEddie James cd->skipFrame--; 12129f775abSEddie James continue; 12229f775abSEddie James } 12329f775abSEddie James 12485d04552SJae Hyun Yoo if (!cd->needUpdate) 12585d04552SJae Hyun Yoo { 12685d04552SJae Hyun Yoo continue; 12785d04552SJae Hyun Yoo } 1282d2f3dabSPaul Fertser 1292d2f3dabSPaul Fertser if (calcFrameCRC) 1302d2f3dabSPaul Fertser { 1312d2f3dabSPaul Fertser if (frame_crc == -1) 1322d2f3dabSPaul Fertser { 1332d2f3dabSPaul Fertser /* JFIF header contains some varying data so skip it for 1342d2f3dabSPaul Fertser * checksum calculation */ 135*f79f6f54SGeorge Liu frame_crc = 136*f79f6f54SGeorge Liu boost::crc<32, 0x04C11DB7, 0xFFFFFFFF, 0xFFFFFFFF, true, 137*f79f6f54SGeorge Liu true>(data + 0x30, video.getFrameSize() - 0x30); 1382d2f3dabSPaul Fertser } 1392d2f3dabSPaul Fertser 1402d2f3dabSPaul Fertser if (cd->last_crc == frame_crc) 1412d2f3dabSPaul Fertser { 1422d2f3dabSPaul Fertser continue; 1432d2f3dabSPaul Fertser } 1442d2f3dabSPaul Fertser 1452d2f3dabSPaul Fertser cd->last_crc = frame_crc; 1462d2f3dabSPaul Fertser } 1472d2f3dabSPaul Fertser 14885d04552SJae Hyun Yoo cd->needUpdate = false; 14985d04552SJae Hyun Yoo 15029f775abSEddie James if (cl->enableLastRectEncoding) 15129f775abSEddie James { 15229f775abSEddie James fu->nRects = 0xFFFF; 15329f775abSEddie James } 15429f775abSEddie James else 15529f775abSEddie James { 15629f775abSEddie James fu->nRects = Swap16IfLE(1); 15729f775abSEddie James } 15829f775abSEddie James 15929f775abSEddie James fu->type = rfbFramebufferUpdate; 16029f775abSEddie James cl->ublen = sz_rfbFramebufferUpdateMsg; 16129f775abSEddie James rfbSendUpdateBuf(cl); 16229f775abSEddie James 16329f775abSEddie James cl->tightEncoding = rfbEncodingTight; 16429f775abSEddie James rfbSendTightHeader(cl, 0, 0, video.getWidth(), video.getHeight()); 16529f775abSEddie James 16629f775abSEddie James cl->updateBuf[cl->ublen++] = (char)(rfbTightJpeg << 4); 16729f775abSEddie James rfbSendCompressedDataTight(cl, data, video.getFrameSize()); 16829f775abSEddie James 16929f775abSEddie James if (cl->enableLastRectEncoding) 17029f775abSEddie James { 17129f775abSEddie James rfbSendLastRectMarker(cl); 17229f775abSEddie James } 17329f775abSEddie James 17429f775abSEddie James rfbSendUpdateBuf(cl); 17529f775abSEddie James } 17629f775abSEddie James 17729f775abSEddie James rfbReleaseClientIterator(it); 17829f775abSEddie James } 17929f775abSEddie James 18085d04552SJae Hyun Yoo void Server::clientFramebufferUpdateRequest( 18185d04552SJae Hyun Yoo rfbClientPtr cl, rfbFramebufferUpdateRequestMsg* furMsg) 18285d04552SJae Hyun Yoo { 18385d04552SJae Hyun Yoo ClientData* cd = (ClientData*)cl->clientData; 18485d04552SJae Hyun Yoo 18585d04552SJae Hyun Yoo if (!cd) 18685d04552SJae Hyun Yoo return; 18785d04552SJae Hyun Yoo 18885d04552SJae Hyun Yoo // Ignore the furMsg info. This service uses full frame update always. 18985d04552SJae Hyun Yoo (void)furMsg; 19085d04552SJae Hyun Yoo 19185d04552SJae Hyun Yoo cd->needUpdate = true; 19285d04552SJae Hyun Yoo } 19385d04552SJae Hyun Yoo 19429f775abSEddie James void Server::clientGone(rfbClientPtr cl) 19529f775abSEddie James { 19629f775abSEddie James Server* server = (Server*)cl->screen->screenData; 19729f775abSEddie James 19829f775abSEddie James delete (ClientData*)cl->clientData; 1990049bfacSJae Hyun Yoo cl->clientData = nullptr; 20029f775abSEddie James 20129f775abSEddie James if (server->numClients-- == 1) 20229f775abSEddie James { 203c11257d8SJae Hyun Yoo server->input.disconnect(); 20429f775abSEddie James rfbMarkRectAsModified(server->server, 0, 0, server->video.getWidth(), 20529f775abSEddie James server->video.getHeight()); 20629f775abSEddie James } 20729f775abSEddie James } 20829f775abSEddie James 20929f775abSEddie James enum rfbNewClientAction Server::newClient(rfbClientPtr cl) 21029f775abSEddie James { 21129f775abSEddie James Server* server = (Server*)cl->screen->screenData; 21229f775abSEddie James 21329f775abSEddie James cl->clientData = 21429f775abSEddie James new ClientData(server->video.getFrameRate(), &server->input); 21529f775abSEddie James cl->clientGoneHook = clientGone; 21685d04552SJae Hyun Yoo cl->clientFramebufferUpdateRequestHook = clientFramebufferUpdateRequest; 21729f775abSEddie James if (!server->numClients++) 21829f775abSEddie James { 219c11257d8SJae Hyun Yoo server->input.connect(); 22029f775abSEddie James server->pendingResize = false; 22129f775abSEddie James server->frameCounter = 0; 22229f775abSEddie James } 22329f775abSEddie James 22429f775abSEddie James return RFB_CLIENT_ACCEPT; 22529f775abSEddie James } 22629f775abSEddie James 22729f775abSEddie James void Server::doResize() 22829f775abSEddie James { 22929f775abSEddie James rfbClientIteratorPtr it; 23029f775abSEddie James rfbClientPtr cl; 23129f775abSEddie James 23229f775abSEddie James framebuffer.resize( 23329f775abSEddie James video.getHeight() * video.getWidth() * Video::bytesPerPixel, 0); 23429f775abSEddie James 23529f775abSEddie James rfbNewFramebuffer(server, framebuffer.data(), video.getWidth(), 23629f775abSEddie James video.getHeight(), Video::bitsPerSample, 23729f775abSEddie James Video::samplesPerPixel, Video::bytesPerPixel); 23829f775abSEddie James rfbMarkRectAsModified(server, 0, 0, video.getWidth(), video.getHeight()); 23929f775abSEddie James 24029f775abSEddie James it = rfbGetClientIterator(server); 24129f775abSEddie James 24229f775abSEddie James while ((cl = rfbClientIteratorNext(it))) 24329f775abSEddie James { 24429f775abSEddie James ClientData* cd = (ClientData*)cl->clientData; 24529f775abSEddie James 24629f775abSEddie James if (!cd) 24729f775abSEddie James { 24829f775abSEddie James continue; 24929f775abSEddie James } 25029f775abSEddie James 25129f775abSEddie James // delay video updates to give the client time to resize 25229f775abSEddie James cd->skipFrame = video.getFrameRate(); 25329f775abSEddie James } 25429f775abSEddie James 25529f775abSEddie James rfbReleaseClientIterator(it); 25621b177e0SEddie James } 25721b177e0SEddie James 25821b177e0SEddie James } // namespace ikvm 259