blob: 37a927b9d418103a2ea0939cd4c60a985931821c [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 {
82 input.sendReport();
83
84 frameCounter++;
85 if (pendingResize && frameCounter > video.getFrameRate())
86 {
87 doResize();
88 pendingResize = false;
89 }
90 }
91}
92
93void Server::sendFrame()
94{
95 char* data = video.getData();
96 rfbClientIteratorPtr it;
97 rfbClientPtr cl;
98
99 if (!data || pendingResize)
100 {
101 return;
102 }
103
104 it = rfbGetClientIterator(server);
105
106 while ((cl = rfbClientIteratorNext(it)))
107 {
108 ClientData* cd = (ClientData*)cl->clientData;
109 rfbFramebufferUpdateMsg* fu = (rfbFramebufferUpdateMsg*)cl->updateBuf;
110
111 if (!cd)
112 {
113 continue;
114 }
115
116 if (cd->skipFrame)
117 {
118 cd->skipFrame--;
119 continue;
120 }
121
122 if (cl->enableLastRectEncoding)
123 {
124 fu->nRects = 0xFFFF;
125 }
126 else
127 {
128 fu->nRects = Swap16IfLE(1);
129 }
130
131 fu->type = rfbFramebufferUpdate;
132 cl->ublen = sz_rfbFramebufferUpdateMsg;
133 rfbSendUpdateBuf(cl);
134
135 cl->tightEncoding = rfbEncodingTight;
136 rfbSendTightHeader(cl, 0, 0, video.getWidth(), video.getHeight());
137
138 cl->updateBuf[cl->ublen++] = (char)(rfbTightJpeg << 4);
139 rfbSendCompressedDataTight(cl, data, video.getFrameSize());
140
141 if (cl->enableLastRectEncoding)
142 {
143 rfbSendLastRectMarker(cl);
144 }
145
146 rfbSendUpdateBuf(cl);
147 }
148
149 rfbReleaseClientIterator(it);
150}
151
152void Server::clientGone(rfbClientPtr cl)
153{
154 Server* server = (Server*)cl->screen->screenData;
155
156 delete (ClientData*)cl->clientData;
157
158 if (server->numClients-- == 1)
159 {
160 rfbMarkRectAsModified(server->server, 0, 0, server->video.getWidth(),
161 server->video.getHeight());
162 }
163}
164
165enum rfbNewClientAction Server::newClient(rfbClientPtr cl)
166{
167 Server* server = (Server*)cl->screen->screenData;
168
169 cl->clientData =
170 new ClientData(server->video.getFrameRate(), &server->input);
171 cl->clientGoneHook = clientGone;
172 if (!server->numClients++)
173 {
174 server->pendingResize = false;
175 server->frameCounter = 0;
176 server->video.start();
177 }
178
179 return RFB_CLIENT_ACCEPT;
180}
181
182void Server::doResize()
183{
184 rfbClientIteratorPtr it;
185 rfbClientPtr cl;
186
187 framebuffer.resize(
188 video.getHeight() * video.getWidth() * Video::bytesPerPixel, 0);
189
190 rfbNewFramebuffer(server, framebuffer.data(), video.getWidth(),
191 video.getHeight(), Video::bitsPerSample,
192 Video::samplesPerPixel, Video::bytesPerPixel);
193 rfbMarkRectAsModified(server, 0, 0, video.getWidth(), video.getHeight());
194
195 it = rfbGetClientIterator(server);
196
197 while ((cl = rfbClientIteratorNext(it)))
198 {
199 ClientData* cd = (ClientData*)cl->clientData;
200
201 if (!cd)
202 {
203 continue;
204 }
205
206 // delay video updates to give the client time to resize
207 cd->skipFrame = video.getFrameRate();
208 }
209
210 rfbReleaseClientIterator(it);
Eddie James21b177e2018-12-11 13:14:46 -0600211}
212
213} // namespace ikvm