121b177e0SEddie James #include "ikvm_server.hpp" 221b177e0SEddie James 329f775abSEddie James #include <rfb/rfbproto.h> 429f775abSEddie James 529f775abSEddie James #include <phosphor-logging/elog-errors.hpp> 629f775abSEddie James #include <phosphor-logging/elog.hpp> 729f775abSEddie James #include <phosphor-logging/log.hpp> 829f775abSEddie James #include <xyz/openbmc_project/Common/error.hpp> 929f775abSEddie James 1021b177e0SEddie James namespace ikvm 1121b177e0SEddie James { 1221b177e0SEddie James 1329f775abSEddie James using namespace phosphor::logging; 1429f775abSEddie James using namespace sdbusplus::xyz::openbmc_project::Common::Error; 1529f775abSEddie James 1621b177e0SEddie James Server::Server(const Args& args, Input& i, Video& v) : 1729f775abSEddie James pendingResize(false), frameCounter(0), numClients(0), input(i), video(v) 1821b177e0SEddie James { 1929f775abSEddie James std::string ip("localhost"); 2029f775abSEddie James const Args::CommandLine& commandLine = args.getCommandLine(); 2129f775abSEddie James int argc = commandLine.argc; 2229f775abSEddie James 2329f775abSEddie James server = rfbGetScreen(&argc, commandLine.argv, video.getWidth(), 2429f775abSEddie James video.getHeight(), Video::bitsPerSample, 2529f775abSEddie James Video::samplesPerPixel, Video::bytesPerPixel); 2629f775abSEddie James 2729f775abSEddie James if (!server) 2829f775abSEddie James { 2929f775abSEddie James log<level::ERR>("Failed to get VNC screen due to invalid arguments"); 3029f775abSEddie James elog<InvalidArgument>( 3129f775abSEddie James xyz::openbmc_project::Common::InvalidArgument::ARGUMENT_NAME(""), 3229f775abSEddie James xyz::openbmc_project::Common::InvalidArgument::ARGUMENT_VALUE("")); 3329f775abSEddie James } 3429f775abSEddie James 3529f775abSEddie James framebuffer.resize( 3629f775abSEddie James video.getHeight() * video.getWidth() * Video::bytesPerPixel, 0); 3729f775abSEddie James 3829f775abSEddie James server->screenData = this; 3929f775abSEddie James server->desktopName = "OpenBMC IKVM"; 4029f775abSEddie James server->frameBuffer = framebuffer.data(); 4129f775abSEddie James server->newClientHook = newClient; 427dfac9ffSJae Hyun Yoo server->cursor = rfbMakeXCursor(cursorWidth, cursorHeight, (char*)cursor, 437dfac9ffSJae Hyun Yoo (char*)cursorMask); 447dfac9ffSJae Hyun Yoo server->cursor->xhot = 1; 457dfac9ffSJae Hyun Yoo server->cursor->yhot = 1; 4629f775abSEddie James 4729f775abSEddie James rfbStringToAddr(&ip[0], &server->listenInterface); 4829f775abSEddie James 4929f775abSEddie James rfbInitServer(server); 5029f775abSEddie James 5129f775abSEddie James rfbMarkRectAsModified(server, 0, 0, video.getWidth(), video.getHeight()); 5229f775abSEddie James 5329f775abSEddie James server->kbdAddEvent = Input::keyEvent; 5429f775abSEddie James server->ptrAddEvent = Input::pointerEvent; 5529f775abSEddie James 5629f775abSEddie James processTime = (1000000 / video.getFrameRate()) - 100; 5721b177e0SEddie James } 5821b177e0SEddie James 5921b177e0SEddie James Server::~Server() 6021b177e0SEddie James { 6129f775abSEddie James rfbScreenCleanup(server); 6229f775abSEddie James } 6329f775abSEddie James 6429f775abSEddie James void Server::resize() 6529f775abSEddie James { 6629f775abSEddie James if (frameCounter > video.getFrameRate()) 6729f775abSEddie James { 6829f775abSEddie James doResize(); 6929f775abSEddie James } 7029f775abSEddie James else 7129f775abSEddie James { 7229f775abSEddie James pendingResize = true; 7329f775abSEddie James } 7429f775abSEddie James } 7529f775abSEddie James 7629f775abSEddie James void Server::run() 7729f775abSEddie James { 7829f775abSEddie James rfbProcessEvents(server, processTime); 7929f775abSEddie James 8029f775abSEddie James if (server->clientHead) 8129f775abSEddie James { 8229f775abSEddie James input.sendReport(); 8329f775abSEddie James 8429f775abSEddie James frameCounter++; 8529f775abSEddie James if (pendingResize && frameCounter > video.getFrameRate()) 8629f775abSEddie James { 8729f775abSEddie James doResize(); 8829f775abSEddie James pendingResize = false; 8929f775abSEddie James } 9029f775abSEddie James } 9129f775abSEddie James } 9229f775abSEddie James 9329f775abSEddie James void Server::sendFrame() 9429f775abSEddie James { 9529f775abSEddie James char* data = video.getData(); 9629f775abSEddie James rfbClientIteratorPtr it; 9729f775abSEddie James rfbClientPtr cl; 9829f775abSEddie James 9929f775abSEddie James if (!data || pendingResize) 10029f775abSEddie James { 10129f775abSEddie James return; 10229f775abSEddie James } 10329f775abSEddie James 10429f775abSEddie James it = rfbGetClientIterator(server); 10529f775abSEddie James 10629f775abSEddie James while ((cl = rfbClientIteratorNext(it))) 10729f775abSEddie James { 10829f775abSEddie James ClientData* cd = (ClientData*)cl->clientData; 10929f775abSEddie James rfbFramebufferUpdateMsg* fu = (rfbFramebufferUpdateMsg*)cl->updateBuf; 11029f775abSEddie James 11129f775abSEddie James if (!cd) 11229f775abSEddie James { 11329f775abSEddie James continue; 11429f775abSEddie James } 11529f775abSEddie James 11629f775abSEddie James if (cd->skipFrame) 11729f775abSEddie James { 11829f775abSEddie James cd->skipFrame--; 11929f775abSEddie James continue; 12029f775abSEddie James } 12129f775abSEddie James 12285d04552SJae Hyun Yoo if (!cd->needUpdate) 12385d04552SJae Hyun Yoo { 12485d04552SJae Hyun Yoo continue; 12585d04552SJae Hyun Yoo } 12685d04552SJae Hyun Yoo cd->needUpdate = false; 12785d04552SJae Hyun Yoo 12829f775abSEddie James if (cl->enableLastRectEncoding) 12929f775abSEddie James { 13029f775abSEddie James fu->nRects = 0xFFFF; 13129f775abSEddie James } 13229f775abSEddie James else 13329f775abSEddie James { 13429f775abSEddie James fu->nRects = Swap16IfLE(1); 13529f775abSEddie James } 13629f775abSEddie James 13729f775abSEddie James fu->type = rfbFramebufferUpdate; 13829f775abSEddie James cl->ublen = sz_rfbFramebufferUpdateMsg; 13929f775abSEddie James rfbSendUpdateBuf(cl); 14029f775abSEddie James 14129f775abSEddie James cl->tightEncoding = rfbEncodingTight; 14229f775abSEddie James rfbSendTightHeader(cl, 0, 0, video.getWidth(), video.getHeight()); 14329f775abSEddie James 14429f775abSEddie James cl->updateBuf[cl->ublen++] = (char)(rfbTightJpeg << 4); 14529f775abSEddie James rfbSendCompressedDataTight(cl, data, video.getFrameSize()); 14629f775abSEddie James 14729f775abSEddie James if (cl->enableLastRectEncoding) 14829f775abSEddie James { 14929f775abSEddie James rfbSendLastRectMarker(cl); 15029f775abSEddie James } 15129f775abSEddie James 15229f775abSEddie James rfbSendUpdateBuf(cl); 15329f775abSEddie James } 15429f775abSEddie James 15529f775abSEddie James rfbReleaseClientIterator(it); 15629f775abSEddie James } 15729f775abSEddie James 15885d04552SJae Hyun Yoo void Server::clientFramebufferUpdateRequest( 15985d04552SJae Hyun Yoo rfbClientPtr cl, rfbFramebufferUpdateRequestMsg *furMsg) 16085d04552SJae Hyun Yoo { 16185d04552SJae Hyun Yoo ClientData *cd = (ClientData *)cl->clientData; 16285d04552SJae Hyun Yoo 16385d04552SJae Hyun Yoo if (!cd) 16485d04552SJae Hyun Yoo return; 16585d04552SJae Hyun Yoo 16685d04552SJae Hyun Yoo // Ignore the furMsg info. This service uses full frame update always. 16785d04552SJae Hyun Yoo (void)furMsg; 16885d04552SJae Hyun Yoo 16985d04552SJae Hyun Yoo cd->needUpdate = true; 17085d04552SJae Hyun Yoo } 17185d04552SJae Hyun Yoo 17229f775abSEddie James void Server::clientGone(rfbClientPtr cl) 17329f775abSEddie James { 17429f775abSEddie James Server* server = (Server*)cl->screen->screenData; 17529f775abSEddie James 17629f775abSEddie James delete (ClientData*)cl->clientData; 1770049bfacSJae Hyun Yoo cl->clientData = nullptr; 17829f775abSEddie James 17929f775abSEddie James if (server->numClients-- == 1) 18029f775abSEddie James { 181*c11257d8SJae Hyun Yoo server->input.disconnect(); 18229f775abSEddie James rfbMarkRectAsModified(server->server, 0, 0, server->video.getWidth(), 18329f775abSEddie James server->video.getHeight()); 18429f775abSEddie James } 18529f775abSEddie James } 18629f775abSEddie James 18729f775abSEddie James enum rfbNewClientAction Server::newClient(rfbClientPtr cl) 18829f775abSEddie James { 18929f775abSEddie James Server* server = (Server*)cl->screen->screenData; 19029f775abSEddie James 19129f775abSEddie James cl->clientData = 19229f775abSEddie James new ClientData(server->video.getFrameRate(), &server->input); 19329f775abSEddie James cl->clientGoneHook = clientGone; 19485d04552SJae Hyun Yoo cl->clientFramebufferUpdateRequestHook = clientFramebufferUpdateRequest; 19529f775abSEddie James if (!server->numClients++) 19629f775abSEddie James { 197*c11257d8SJae Hyun Yoo server->input.connect(); 19829f775abSEddie James server->pendingResize = false; 19929f775abSEddie James server->frameCounter = 0; 20029f775abSEddie James } 20129f775abSEddie James 20229f775abSEddie James return RFB_CLIENT_ACCEPT; 20329f775abSEddie James } 20429f775abSEddie James 20529f775abSEddie James void Server::doResize() 20629f775abSEddie James { 20729f775abSEddie James rfbClientIteratorPtr it; 20829f775abSEddie James rfbClientPtr cl; 20929f775abSEddie James 21029f775abSEddie James framebuffer.resize( 21129f775abSEddie James video.getHeight() * video.getWidth() * Video::bytesPerPixel, 0); 21229f775abSEddie James 21329f775abSEddie James rfbNewFramebuffer(server, framebuffer.data(), video.getWidth(), 21429f775abSEddie James video.getHeight(), Video::bitsPerSample, 21529f775abSEddie James Video::samplesPerPixel, Video::bytesPerPixel); 21629f775abSEddie James rfbMarkRectAsModified(server, 0, 0, video.getWidth(), video.getHeight()); 21729f775abSEddie James 21829f775abSEddie James it = rfbGetClientIterator(server); 21929f775abSEddie James 22029f775abSEddie James while ((cl = rfbClientIteratorNext(it))) 22129f775abSEddie James { 22229f775abSEddie James ClientData* cd = (ClientData*)cl->clientData; 22329f775abSEddie James 22429f775abSEddie James if (!cd) 22529f775abSEddie James { 22629f775abSEddie James continue; 22729f775abSEddie James } 22829f775abSEddie James 22929f775abSEddie James // delay video updates to give the client time to resize 23029f775abSEddie James cd->skipFrame = video.getFrameRate(); 23129f775abSEddie James } 23229f775abSEddie James 23329f775abSEddie James rfbReleaseClientIterator(it); 23421b177e0SEddie James } 23521b177e0SEddie James 23621b177e0SEddie James } // namespace ikvm 237