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