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