1 /*
2 ** Copyright 2011, The Android Open Source Project
3 **
4 ** Licensed under the Apache License, Version 2.0 (the "License");
5 ** you may not use this file except in compliance with the License.
6 ** You may obtain a copy of the License at
7 **
8 ** http://www.apache.org/licenses/LICENSE-2.0
9 **
10 ** Unless required by applicable law or agreed to in writing, software
11 ** distributed under the License is distributed on an "AS IS" BASIS,
12 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 ** See the License for the specific language governing permissions and
14 ** limitations under the License.
15 */
16
17 #include <sys/ioctl.h>
18 #include <unistd.h>
19 #include <sys/socket.h>
20 #include <fcntl.h>
21 #include <netinet/in.h>
22 #include <arpa/inet.h>
23 #include <pthread.h>
24
25 #include "header.h"
26
27 namespace android
28 {
29
30 int serverSock = -1, clientSock = -1;
31 FILE * file = NULL;
32 unsigned int MAX_FILE_SIZE = 0;
33 int timeMode = SYSTEM_TIME_THREAD;
34
Die(const char * msg)35 static void Die(const char * msg)
36 {
37 LOGD("\n*\n*\n* GLESv2_dbg: Die: %s \n*\n*", msg);
38 StopDebugServer();
39 exit(1);
40 }
41
StartDebugServer(const unsigned short port,const bool forceUseFile,const unsigned int maxFileSize,const char * const filePath)42 void StartDebugServer(const unsigned short port, const bool forceUseFile,
43 const unsigned int maxFileSize, const char * const filePath)
44 {
45 MAX_FILE_SIZE = maxFileSize;
46
47 LOGD("GLESv2_dbg: StartDebugServer");
48 if (serverSock >= 0 || file)
49 return;
50
51 LOGD("GLESv2_dbg: StartDebugServer create socket");
52 struct sockaddr_in server = {}, client = {};
53
54 /* Create the TCP socket */
55 if (forceUseFile || (serverSock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
56 file = fopen(filePath, "wb");
57 if (!file)
58 Die("Failed to create socket and file");
59 else
60 return;
61 }
62 /* Construct the server sockaddr_in structure */
63 server.sin_family = AF_INET; /* Internet/IP */
64 server.sin_addr.s_addr = htonl(INADDR_LOOPBACK); /* Incoming addr */
65 server.sin_port = htons(port); /* server port */
66
67 /* Bind the server socket */
68 socklen_t sizeofSockaddr_in = sizeof(sockaddr_in);
69 if (bind(serverSock, (struct sockaddr *) &server,
70 sizeof(server)) < 0) {
71 Die("Failed to bind the server socket");
72 }
73 /* Listen on the server socket */
74 if (listen(serverSock, 1) < 0) {
75 Die("Failed to listen on server socket");
76 }
77
78 LOGD("server started on %d \n", server.sin_port);
79
80
81 /* Wait for client connection */
82 if ((clientSock =
83 accept(serverSock, (struct sockaddr *) &client,
84 &sizeofSockaddr_in)) < 0) {
85 Die("Failed to accept client connection");
86 }
87
88 LOGD("Client connected: %s\n", inet_ntoa(client.sin_addr));
89 // fcntl(clientSock, F_SETFL, O_NONBLOCK);
90 }
91
StopDebugServer()92 void StopDebugServer()
93 {
94 LOGD("GLESv2_dbg: StopDebugServer");
95 if (clientSock > 0) {
96 close(clientSock);
97 clientSock = -1;
98 }
99 if (serverSock > 0) {
100 close(serverSock);
101 serverSock = -1;
102 }
103 if (file) {
104 fclose(file);
105 file = NULL;
106 }
107 }
108
Receive(glesv2debugger::Message & cmd)109 void Receive(glesv2debugger::Message & cmd)
110 {
111 if (clientSock < 0)
112 return;
113 unsigned len = 0;
114 int received = recv(clientSock, &len, 4, MSG_WAITALL);
115 if (received < 0)
116 Die("Failed to receive response length");
117 else if (4 != received) {
118 LOGD("received %dB: %.8X", received, len);
119 Die("Received length mismatch, expected 4");
120 }
121 static void * buffer = NULL;
122 static unsigned bufferSize = 0;
123 if (bufferSize < len) {
124 buffer = realloc(buffer, len);
125 assert(buffer);
126 bufferSize = len;
127 }
128 received = recv(clientSock, buffer, len, MSG_WAITALL);
129 if (received < 0)
130 Die("Failed to receive response");
131 else if (len != received)
132 Die("Received length mismatch");
133 cmd.Clear();
134 cmd.ParseFromArray(buffer, len);
135 }
136
TryReceive(glesv2debugger::Message & cmd)137 bool TryReceive(glesv2debugger::Message & cmd)
138 {
139 if (clientSock < 0)
140 return false;
141 fd_set readSet;
142 FD_ZERO(&readSet);
143 FD_SET(clientSock, &readSet);
144 timeval timeout;
145 timeout.tv_sec = timeout.tv_usec = 0;
146
147 int rc = select(clientSock + 1, &readSet, NULL, NULL, &timeout);
148 if (rc < 0)
149 Die("failed to select clientSock");
150
151 bool received = false;
152 if (FD_ISSET(clientSock, &readSet)) {
153 LOGD("TryReceive: avaiable for read");
154 Receive(cmd);
155 return true;
156 }
157 return false;
158 }
159
Send(const glesv2debugger::Message & msg,glesv2debugger::Message & cmd)160 float Send(const glesv2debugger::Message & msg, glesv2debugger::Message & cmd)
161 {
162 // TODO: use per DbgContext send/receive buffer and async socket
163 // instead of mutex and blocking io; watch out for large messages
164 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
165 struct Autolock {
166 Autolock() {
167 pthread_mutex_lock(&mutex);
168 }
169 ~Autolock() {
170 pthread_mutex_unlock(&mutex);
171 }
172 } autolock;
173
174 if (msg.function() != glesv2debugger::Message_Function_ACK)
175 assert(msg.has_context_id() && msg.context_id() != 0);
176 static std::string str;
177 msg.SerializeToString(&str);
178 const uint32_t len = str.length();
179 if (clientSock < 0) {
180 if (file) {
181 fwrite(&len, sizeof(len), 1, file);
182 fwrite(str.data(), len, 1, file);
183 if (ftell(file) >= MAX_FILE_SIZE) {
184 fclose(file);
185 Die("MAX_FILE_SIZE reached");
186 }
187 }
188 return 0;
189 }
190 int sent = -1;
191 sent = send(clientSock, &len, sizeof(len), 0);
192 if (sent != sizeof(len)) {
193 LOGD("actual sent=%d expected=%d clientSock=%d", sent, sizeof(len), clientSock);
194 Die("Failed to send message length");
195 }
196 nsecs_t c0 = systemTime(timeMode);
197 sent = send(clientSock, str.data(), str.length(), 0);
198 float t = (float)ns2ms(systemTime(timeMode) - c0);
199 if (sent != str.length()) {
200 LOGD("actual sent=%d expected=%d clientSock=%d", sent, str.length(), clientSock);
201 Die("Failed to send message");
202 }
203 // TODO: factor Receive & TryReceive out and into MessageLoop, or add control argument.
204 // mean while, if server is sending a SETPROP then don't try to receive,
205 // because server will not be processing received command
206 if (msg.function() == msg.SETPROP)
207 return t;
208 // try to receive commands even though not expecting response,
209 // since client can send SETPROP and other commands anytime
210 if (!msg.expect_response()) {
211 if (TryReceive(cmd)) {
212 if (glesv2debugger::Message_Function_SETPROP == cmd.function())
213 LOGD("Send: TryReceived SETPROP");
214 else
215 LOGD("Send: TryReceived %u", cmd.function());
216 }
217 } else
218 Receive(cmd);
219 return t;
220 }
221
SetProp(DbgContext * const dbg,const glesv2debugger::Message & cmd)222 void SetProp(DbgContext * const dbg, const glesv2debugger::Message & cmd)
223 {
224 switch (cmd.prop()) {
225 case glesv2debugger::Message_Prop_CaptureDraw:
226 LOGD("SetProp Message_Prop_CaptureDraw %d", cmd.arg0());
227 dbg->captureDraw = cmd.arg0();
228 break;
229 case glesv2debugger::Message_Prop_TimeMode:
230 LOGD("SetProp Message_Prop_TimeMode %d", cmd.arg0());
231 timeMode = cmd.arg0();
232 break;
233 case glesv2debugger::Message_Prop_ExpectResponse:
234 LOGD("SetProp Message_Prop_ExpectResponse %d=%d", cmd.arg0(), cmd.arg1());
235 dbg->expectResponse.Bit((glesv2debugger::Message_Function)cmd.arg0(), cmd.arg1());
236 break;
237 case glesv2debugger::Message_Prop_CaptureSwap:
238 LOGD("SetProp CaptureSwap %d", cmd.arg0());
239 dbg->captureSwap = cmd.arg0();
240 break;
241 default:
242 assert(0);
243 }
244 }
245
MessageLoop(FunctionCall & functionCall,glesv2debugger::Message & msg,const glesv2debugger::Message_Function function)246 int * MessageLoop(FunctionCall & functionCall, glesv2debugger::Message & msg,
247 const glesv2debugger::Message_Function function)
248 {
249 DbgContext * const dbg = getDbgContextThreadSpecific();
250 const int * ret = 0;
251 glesv2debugger::Message cmd;
252 msg.set_context_id(reinterpret_cast<int>(dbg));
253 msg.set_type(glesv2debugger::Message_Type_BeforeCall);
254 bool expectResponse = dbg->expectResponse.Bit(function);
255 msg.set_expect_response(expectResponse);
256 msg.set_function(function);
257
258 // when not exectResponse, set cmd to CONTINUE then SKIP
259 // cmd will be overwritten by received command
260 cmd.set_function(glesv2debugger::Message_Function_CONTINUE);
261 cmd.set_expect_response(expectResponse);
262 glesv2debugger::Message_Function oldCmd = cmd.function();
263 Send(msg, cmd);
264 expectResponse = cmd.expect_response();
265 while (true) {
266 msg.Clear();
267 nsecs_t c0 = systemTime(timeMode);
268 switch (cmd.function()) {
269 case glesv2debugger::Message_Function_CONTINUE:
270 ret = functionCall(&dbg->hooks->gl, msg);
271 while (GLenum error = dbg->hooks->gl.glGetError())
272 LOGD("Function=%u glGetError() = 0x%.4X", function, error);
273 if (!msg.has_time()) // some has output data copy, so time inside call
274 msg.set_time((systemTime(timeMode) - c0) * 1e-6f);
275 msg.set_context_id(reinterpret_cast<int>(dbg));
276 msg.set_function(function);
277 msg.set_type(glesv2debugger::Message_Type_AfterCall);
278 msg.set_expect_response(expectResponse);
279 if (!expectResponse) {
280 cmd.set_function(glesv2debugger::Message_Function_SKIP);
281 cmd.set_expect_response(false);
282 }
283 oldCmd = cmd.function();
284 Send(msg, cmd);
285 expectResponse = cmd.expect_response();
286 break;
287 case glesv2debugger::Message_Function_SKIP:
288 return const_cast<int *>(ret);
289 case glesv2debugger::Message_Function_SETPROP:
290 SetProp(dbg, cmd);
291 expectResponse = cmd.expect_response();
292 if (!expectResponse) // SETPROP is "out of band"
293 cmd.set_function(oldCmd);
294 else
295 Receive(cmd);
296 break;
297 default:
298 ret = GenerateCall(dbg, cmd, msg, ret);
299 msg.set_expect_response(expectResponse);
300 if (!expectResponse) {
301 cmd.set_function(cmd.SKIP);
302 cmd.set_expect_response(expectResponse);
303 }
304 oldCmd = cmd.function();
305 Send(msg, cmd);
306 expectResponse = cmd.expect_response();
307 break;
308 }
309 }
310 return 0;
311 }
312 }; // namespace android {
313