121b177e0SEddie James #include "ikvm_server.hpp" 221b177e0SEddie James 3*29f775abSEddie James #include <rfb/rfbproto.h> 4*29f775abSEddie James 5*29f775abSEddie James #include <phosphor-logging/elog-errors.hpp> 6*29f775abSEddie James #include <phosphor-logging/elog.hpp> 7*29f775abSEddie James #include <phosphor-logging/log.hpp> 8*29f775abSEddie James #include <xyz/openbmc_project/Common/error.hpp> 9*29f775abSEddie James 1021b177e0SEddie James namespace ikvm 1121b177e0SEddie James { 1221b177e0SEddie James 13*29f775abSEddie James using namespace phosphor::logging; 14*29f775abSEddie James using namespace sdbusplus::xyz::openbmc_project::Common::Error; 15*29f775abSEddie James 1621b177e0SEddie James Server::Server(const Args& args, Input& i, Video& v) : 17*29f775abSEddie James pendingResize(false), frameCounter(0), numClients(0), input(i), video(v) 1821b177e0SEddie James { 19*29f775abSEddie James std::string ip("localhost"); 20*29f775abSEddie James const Args::CommandLine& commandLine = args.getCommandLine(); 21*29f775abSEddie James int argc = commandLine.argc; 22*29f775abSEddie James 23*29f775abSEddie James server = rfbGetScreen(&argc, commandLine.argv, video.getWidth(), 24*29f775abSEddie James video.getHeight(), Video::bitsPerSample, 25*29f775abSEddie James Video::samplesPerPixel, Video::bytesPerPixel); 26*29f775abSEddie James 27*29f775abSEddie James if (!server) 28*29f775abSEddie James { 29*29f775abSEddie James log<level::ERR>("Failed to get VNC screen due to invalid arguments"); 30*29f775abSEddie James elog<InvalidArgument>( 31*29f775abSEddie James xyz::openbmc_project::Common::InvalidArgument::ARGUMENT_NAME(""), 32*29f775abSEddie James xyz::openbmc_project::Common::InvalidArgument::ARGUMENT_VALUE("")); 33*29f775abSEddie James } 34*29f775abSEddie James 35*29f775abSEddie James framebuffer.resize( 36*29f775abSEddie James video.getHeight() * video.getWidth() * Video::bytesPerPixel, 0); 37*29f775abSEddie James 38*29f775abSEddie James server->screenData = this; 39*29f775abSEddie James server->desktopName = "OpenBMC IKVM"; 40*29f775abSEddie James server->frameBuffer = framebuffer.data(); 41*29f775abSEddie James server->newClientHook = newClient; 42*29f775abSEddie James 43*29f775abSEddie James rfbStringToAddr(&ip[0], &server->listenInterface); 44*29f775abSEddie James 45*29f775abSEddie James rfbInitServer(server); 46*29f775abSEddie James 47*29f775abSEddie James rfbMarkRectAsModified(server, 0, 0, video.getWidth(), video.getHeight()); 48*29f775abSEddie James 49*29f775abSEddie James server->kbdAddEvent = Input::keyEvent; 50*29f775abSEddie James server->ptrAddEvent = Input::pointerEvent; 51*29f775abSEddie James 52*29f775abSEddie James processTime = (1000000 / video.getFrameRate()) - 100; 5321b177e0SEddie James } 5421b177e0SEddie James 5521b177e0SEddie James Server::~Server() 5621b177e0SEddie James { 57*29f775abSEddie James rfbScreenCleanup(server); 58*29f775abSEddie James } 59*29f775abSEddie James 60*29f775abSEddie James void Server::resize() 61*29f775abSEddie James { 62*29f775abSEddie James if (frameCounter > video.getFrameRate()) 63*29f775abSEddie James { 64*29f775abSEddie James doResize(); 65*29f775abSEddie James } 66*29f775abSEddie James else 67*29f775abSEddie James { 68*29f775abSEddie James pendingResize = true; 69*29f775abSEddie James } 70*29f775abSEddie James } 71*29f775abSEddie James 72*29f775abSEddie James void Server::run() 73*29f775abSEddie James { 74*29f775abSEddie James rfbProcessEvents(server, processTime); 75*29f775abSEddie James 76*29f775abSEddie James if (server->clientHead) 77*29f775abSEddie James { 78*29f775abSEddie James input.sendReport(); 79*29f775abSEddie James 80*29f775abSEddie James frameCounter++; 81*29f775abSEddie James if (pendingResize && frameCounter > video.getFrameRate()) 82*29f775abSEddie James { 83*29f775abSEddie James doResize(); 84*29f775abSEddie James pendingResize = false; 85*29f775abSEddie James } 86*29f775abSEddie James } 87*29f775abSEddie James } 88*29f775abSEddie James 89*29f775abSEddie James void Server::sendFrame() 90*29f775abSEddie James { 91*29f775abSEddie James char* data = video.getData(); 92*29f775abSEddie James rfbClientIteratorPtr it; 93*29f775abSEddie James rfbClientPtr cl; 94*29f775abSEddie James 95*29f775abSEddie James if (!data || pendingResize) 96*29f775abSEddie James { 97*29f775abSEddie James return; 98*29f775abSEddie James } 99*29f775abSEddie James 100*29f775abSEddie James it = rfbGetClientIterator(server); 101*29f775abSEddie James 102*29f775abSEddie James while ((cl = rfbClientIteratorNext(it))) 103*29f775abSEddie James { 104*29f775abSEddie James ClientData* cd = (ClientData*)cl->clientData; 105*29f775abSEddie James rfbFramebufferUpdateMsg* fu = (rfbFramebufferUpdateMsg*)cl->updateBuf; 106*29f775abSEddie James 107*29f775abSEddie James if (!cd) 108*29f775abSEddie James { 109*29f775abSEddie James continue; 110*29f775abSEddie James } 111*29f775abSEddie James 112*29f775abSEddie James if (cd->skipFrame) 113*29f775abSEddie James { 114*29f775abSEddie James cd->skipFrame--; 115*29f775abSEddie James continue; 116*29f775abSEddie James } 117*29f775abSEddie James 118*29f775abSEddie James if (cl->enableLastRectEncoding) 119*29f775abSEddie James { 120*29f775abSEddie James fu->nRects = 0xFFFF; 121*29f775abSEddie James } 122*29f775abSEddie James else 123*29f775abSEddie James { 124*29f775abSEddie James fu->nRects = Swap16IfLE(1); 125*29f775abSEddie James } 126*29f775abSEddie James 127*29f775abSEddie James fu->type = rfbFramebufferUpdate; 128*29f775abSEddie James cl->ublen = sz_rfbFramebufferUpdateMsg; 129*29f775abSEddie James rfbSendUpdateBuf(cl); 130*29f775abSEddie James 131*29f775abSEddie James cl->tightEncoding = rfbEncodingTight; 132*29f775abSEddie James rfbSendTightHeader(cl, 0, 0, video.getWidth(), video.getHeight()); 133*29f775abSEddie James 134*29f775abSEddie James cl->updateBuf[cl->ublen++] = (char)(rfbTightJpeg << 4); 135*29f775abSEddie James rfbSendCompressedDataTight(cl, data, video.getFrameSize()); 136*29f775abSEddie James 137*29f775abSEddie James if (cl->enableLastRectEncoding) 138*29f775abSEddie James { 139*29f775abSEddie James rfbSendLastRectMarker(cl); 140*29f775abSEddie James } 141*29f775abSEddie James 142*29f775abSEddie James rfbSendUpdateBuf(cl); 143*29f775abSEddie James } 144*29f775abSEddie James 145*29f775abSEddie James rfbReleaseClientIterator(it); 146*29f775abSEddie James } 147*29f775abSEddie James 148*29f775abSEddie James void Server::clientGone(rfbClientPtr cl) 149*29f775abSEddie James { 150*29f775abSEddie James Server* server = (Server*)cl->screen->screenData; 151*29f775abSEddie James 152*29f775abSEddie James delete (ClientData*)cl->clientData; 153*29f775abSEddie James 154*29f775abSEddie James if (server->numClients-- == 1) 155*29f775abSEddie James { 156*29f775abSEddie James rfbMarkRectAsModified(server->server, 0, 0, server->video.getWidth(), 157*29f775abSEddie James server->video.getHeight()); 158*29f775abSEddie James } 159*29f775abSEddie James } 160*29f775abSEddie James 161*29f775abSEddie James enum rfbNewClientAction Server::newClient(rfbClientPtr cl) 162*29f775abSEddie James { 163*29f775abSEddie James Server* server = (Server*)cl->screen->screenData; 164*29f775abSEddie James 165*29f775abSEddie James cl->clientData = 166*29f775abSEddie James new ClientData(server->video.getFrameRate(), &server->input); 167*29f775abSEddie James cl->clientGoneHook = clientGone; 168*29f775abSEddie James if (!server->numClients++) 169*29f775abSEddie James { 170*29f775abSEddie James server->pendingResize = false; 171*29f775abSEddie James server->frameCounter = 0; 172*29f775abSEddie James server->video.start(); 173*29f775abSEddie James } 174*29f775abSEddie James 175*29f775abSEddie James return RFB_CLIENT_ACCEPT; 176*29f775abSEddie James } 177*29f775abSEddie James 178*29f775abSEddie James void Server::doResize() 179*29f775abSEddie James { 180*29f775abSEddie James rfbClientIteratorPtr it; 181*29f775abSEddie James rfbClientPtr cl; 182*29f775abSEddie James 183*29f775abSEddie James framebuffer.resize( 184*29f775abSEddie James video.getHeight() * video.getWidth() * Video::bytesPerPixel, 0); 185*29f775abSEddie James 186*29f775abSEddie James rfbNewFramebuffer(server, framebuffer.data(), video.getWidth(), 187*29f775abSEddie James video.getHeight(), Video::bitsPerSample, 188*29f775abSEddie James Video::samplesPerPixel, Video::bytesPerPixel); 189*29f775abSEddie James rfbMarkRectAsModified(server, 0, 0, video.getWidth(), video.getHeight()); 190*29f775abSEddie James 191*29f775abSEddie James it = rfbGetClientIterator(server); 192*29f775abSEddie James 193*29f775abSEddie James while ((cl = rfbClientIteratorNext(it))) 194*29f775abSEddie James { 195*29f775abSEddie James ClientData* cd = (ClientData*)cl->clientData; 196*29f775abSEddie James 197*29f775abSEddie James if (!cd) 198*29f775abSEddie James { 199*29f775abSEddie James continue; 200*29f775abSEddie James } 201*29f775abSEddie James 202*29f775abSEddie James // delay video updates to give the client time to resize 203*29f775abSEddie James cd->skipFrame = video.getFrameRate(); 204*29f775abSEddie James } 205*29f775abSEddie James 206*29f775abSEddie James rfbReleaseClientIterator(it); 20721b177e0SEddie James } 20821b177e0SEddie James 20921b177e0SEddie James } // namespace ikvm 210