xref: /openbmc/obmc-ikvm/ikvm_server.cpp (revision c11257d8)
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