blob: 7be99e4379d1277cd0a27ee1ece3b5943d03fd61 [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;
Jae Hyun Yoo7dfac9f2019-01-15 10:14:59 -080042 server->cursor = rfbMakeXCursor(cursorWidth, cursorHeight, (char*)cursor,
43 (char*)cursorMask);
44 server->cursor->xhot = 1;
45 server->cursor->yhot = 1;
Eddie James29f775a2018-12-11 13:22:54 -060046
47 rfbStringToAddr(&ip[0], &server->listenInterface);
48
49 rfbInitServer(server);
50
51 rfbMarkRectAsModified(server, 0, 0, video.getWidth(), video.getHeight());
52
53 server->kbdAddEvent = Input::keyEvent;
54 server->ptrAddEvent = Input::pointerEvent;
55
56 processTime = (1000000 / video.getFrameRate()) - 100;
Eddie James21b177e2018-12-11 13:14:46 -060057}
58
59Server::~Server()
60{
Eddie James29f775a2018-12-11 13:22:54 -060061 rfbScreenCleanup(server);
62}
63
64void Server::resize()
65{
66 if (frameCounter > video.getFrameRate())
67 {
68 doResize();
69 }
70 else
71 {
72 pendingResize = true;
73 }
74}
75
76void Server::run()
77{
78 rfbProcessEvents(server, processTime);
79
80 if (server->clientHead)
81 {
Eddie James29f775a2018-12-11 13:22:54 -060082 frameCounter++;
83 if (pendingResize && frameCounter > video.getFrameRate())
84 {
85 doResize();
86 pendingResize = false;
87 }
88 }
89}
90
91void Server::sendFrame()
92{
93 char* data = video.getData();
94 rfbClientIteratorPtr it;
95 rfbClientPtr cl;
96
97 if (!data || pendingResize)
98 {
99 return;
100 }
101
102 it = rfbGetClientIterator(server);
103
104 while ((cl = rfbClientIteratorNext(it)))
105 {
106 ClientData* cd = (ClientData*)cl->clientData;
107 rfbFramebufferUpdateMsg* fu = (rfbFramebufferUpdateMsg*)cl->updateBuf;
108
109 if (!cd)
110 {
111 continue;
112 }
113
114 if (cd->skipFrame)
115 {
116 cd->skipFrame--;
117 continue;
118 }
119
Jae Hyun Yoo85d04552019-05-09 16:26:53 -0700120 if (!cd->needUpdate)
121 {
122 continue;
123 }
124 cd->needUpdate = false;
125
Eddie James29f775a2018-12-11 13:22:54 -0600126 if (cl->enableLastRectEncoding)
127 {
128 fu->nRects = 0xFFFF;
129 }
130 else
131 {
132 fu->nRects = Swap16IfLE(1);
133 }
134
135 fu->type = rfbFramebufferUpdate;
136 cl->ublen = sz_rfbFramebufferUpdateMsg;
137 rfbSendUpdateBuf(cl);
138
139 cl->tightEncoding = rfbEncodingTight;
140 rfbSendTightHeader(cl, 0, 0, video.getWidth(), video.getHeight());
141
142 cl->updateBuf[cl->ublen++] = (char)(rfbTightJpeg << 4);
143 rfbSendCompressedDataTight(cl, data, video.getFrameSize());
144
145 if (cl->enableLastRectEncoding)
146 {
147 rfbSendLastRectMarker(cl);
148 }
149
150 rfbSendUpdateBuf(cl);
151 }
152
153 rfbReleaseClientIterator(it);
154}
155
Jae Hyun Yoo85d04552019-05-09 16:26:53 -0700156void Server::clientFramebufferUpdateRequest(
157 rfbClientPtr cl, rfbFramebufferUpdateRequestMsg *furMsg)
158{
159 ClientData *cd = (ClientData *)cl->clientData;
160
161 if (!cd)
162 return;
163
164 // Ignore the furMsg info. This service uses full frame update always.
165 (void)furMsg;
166
167 cd->needUpdate = true;
168}
169
Eddie James29f775a2018-12-11 13:22:54 -0600170void Server::clientGone(rfbClientPtr cl)
171{
172 Server* server = (Server*)cl->screen->screenData;
173
174 delete (ClientData*)cl->clientData;
Jae Hyun Yoo0049bfa2019-03-06 15:39:58 -0800175 cl->clientData = nullptr;
Eddie James29f775a2018-12-11 13:22:54 -0600176
177 if (server->numClients-- == 1)
178 {
Jae Hyun Yooc11257d2020-07-22 23:39:18 -0700179 server->input.disconnect();
Eddie James29f775a2018-12-11 13:22:54 -0600180 rfbMarkRectAsModified(server->server, 0, 0, server->video.getWidth(),
181 server->video.getHeight());
182 }
183}
184
185enum rfbNewClientAction Server::newClient(rfbClientPtr cl)
186{
187 Server* server = (Server*)cl->screen->screenData;
188
189 cl->clientData =
190 new ClientData(server->video.getFrameRate(), &server->input);
191 cl->clientGoneHook = clientGone;
Jae Hyun Yoo85d04552019-05-09 16:26:53 -0700192 cl->clientFramebufferUpdateRequestHook = clientFramebufferUpdateRequest;
Eddie James29f775a2018-12-11 13:22:54 -0600193 if (!server->numClients++)
194 {
Jae Hyun Yooc11257d2020-07-22 23:39:18 -0700195 server->input.connect();
Eddie James29f775a2018-12-11 13:22:54 -0600196 server->pendingResize = false;
197 server->frameCounter = 0;
Eddie James29f775a2018-12-11 13:22:54 -0600198 }
199
200 return RFB_CLIENT_ACCEPT;
201}
202
203void Server::doResize()
204{
205 rfbClientIteratorPtr it;
206 rfbClientPtr cl;
207
208 framebuffer.resize(
209 video.getHeight() * video.getWidth() * Video::bytesPerPixel, 0);
210
211 rfbNewFramebuffer(server, framebuffer.data(), video.getWidth(),
212 video.getHeight(), Video::bitsPerSample,
213 Video::samplesPerPixel, Video::bytesPerPixel);
214 rfbMarkRectAsModified(server, 0, 0, video.getWidth(), video.getHeight());
215
216 it = rfbGetClientIterator(server);
217
218 while ((cl = rfbClientIteratorNext(it)))
219 {
220 ClientData* cd = (ClientData*)cl->clientData;
221
222 if (!cd)
223 {
224 continue;
225 }
226
227 // delay video updates to give the client time to resize
228 cd->skipFrame = video.getFrameRate();
229 }
230
231 rfbReleaseClientIterator(it);
Eddie James21b177e2018-12-11 13:14:46 -0600232}
233
234} // namespace ikvm