blob: 5da391852a74a5f555061eadf8143c7a16f76a6d [file] [log] [blame]
David 'Digit' Turnerd4d688e2011-04-26 18:09:17 +02001/*
2 * Copyright (C) 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/* This file implements the 'tcp:' goldfish pipe type which allows
18 * guest clients to directly connect to a TCP port through /dev/qemu_pipe.
19 */
20
David 'Digit' Turnercc330d42013-12-14 23:26:42 +010021#include "android/sockets.h"
David 'Digit' Turnerd4d688e2011-04-26 18:09:17 +020022#include "android/utils/assert.h"
23#include "android/utils/panic.h"
24#include "android/utils/system.h"
25#include "android/async-utils.h"
David 'Digit' Turnercb88e792011-08-26 01:35:14 +020026#include "android/opengles.h"
David 'Digit' Turnerd4d688e2011-04-26 18:09:17 +020027#include "android/looper.h"
David 'Digit' Turnerf5bc01c2013-12-17 10:33:07 +010028#include "hw/android/goldfish/pipe.h"
David 'Digit' Turnerd4d688e2011-04-26 18:09:17 +020029
30/* Implement the OpenGL fast-pipe */
31
32/* Set to 1 or 2 for debug traces */
Jesse Hall6b32ee52011-12-16 10:39:05 -080033// #define DEBUG 1
David 'Digit' Turnerd4d688e2011-04-26 18:09:17 +020034
35#if DEBUG >= 1
36# define D(...) printf(__VA_ARGS__), printf("\n")
37#else
38# define D(...) ((void)0)
39#endif
40
41#if DEBUG >= 2
42# define DD(...) printf(__VA_ARGS__), printf("\n")
43# define DDASSERT(cond) _ANDROID_ASSERT(cond, "Assertion failure: ", #cond)
44# define DDASSERT_INT_OP(cond,val,op) _ANDROID_ASSERT_INT_OP(cond,val,op)
45#else
46# define DD(...) ((void)0)
47# define DDASSERT(cond) ((void)0)
48# define DDASSERT_INT_OP(cond,val,op) ((void)0)
49#endif
50
51#define DDASSERT_INT_LT(cond,val) DDASSERT_INT_OP(cond,val,<)
52#define DDASSERT_INT_LTE(cond,val) DDASSERT_INT_OP(cond,val,<=)
53#define DDASSERT_INT_GT(cond,val) DDASSERT_INT_OP(cond,val,>)
54#define DDASSERT_INT_GTE(cond,val) DDASSERT_INT_OP(cond,val,>=)
55#define DDASSERT_INT_EQ(cond,val) DDASSERT_INT_OP(cond,val,==)
56#define DDASSERT_INT_NEQ(cond,val) DDASSERT_INT_OP(cond,val,!=)
57
58enum {
59 STATE_INIT,
60 STATE_CONNECTING,
61 STATE_CONNECTED,
62 STATE_CLOSING_GUEST,
63 STATE_CLOSING_SOCKET
64};
65
66typedef struct {
67 void* hwpipe;
68 int state;
69 int wakeWanted;
70 LoopIo io[1];
71 AsyncConnector connector[1];
David 'Digit' Turnerd4d688e2011-04-26 18:09:17 +020072} NetPipe;
73
74static void
75netPipe_free( NetPipe* pipe )
76{
77 int fd;
78
79 /* Close the socket */
80 fd = pipe->io->fd;
81 loopIo_done(pipe->io);
82 socket_close(fd);
83
84 /* Release the pipe object */
85 AFREE(pipe);
86}
87
88
89static void
90netPipe_resetState( NetPipe* pipe )
91{
92 if ((pipe->wakeWanted & PIPE_WAKE_WRITE) != 0) {
93 loopIo_wantWrite(pipe->io);
94 } else {
95 loopIo_dontWantWrite(pipe->io);
96 }
97
98 if (pipe->state == STATE_CONNECTED && (pipe->wakeWanted & PIPE_WAKE_READ) != 0) {
99 loopIo_wantRead(pipe->io);
100 } else {
101 loopIo_dontWantRead(pipe->io);
102 }
103}
104
105
106/* This function is only called when the socket is disconnected.
107 * See netPipe_closeFromGuest() for the case when the guest requires
108 * the disconnection. */
109static void
110netPipe_closeFromSocket( void* opaque )
111{
112 NetPipe* pipe = opaque;
113
114 D("%s", __FUNCTION__);
115
116 /* If the guest already ordered the pipe to be closed, delete immediately */
117 if (pipe->state == STATE_CLOSING_GUEST) {
118 netPipe_free(pipe);
119 return;
120 }
121
122 /* Force the closure of the QEMUD channel - if a guest is blocked
123 * waiting for a wake signal, it will receive an error. */
124 if (pipe->hwpipe != NULL) {
125 goldfish_pipe_close(pipe->hwpipe);
126 pipe->hwpipe = NULL;
127 }
128
129 pipe->state = STATE_CLOSING_SOCKET;
130 netPipe_resetState(pipe);
131}
132
133
134/* This is the function that gets called each time there is an asynchronous
135 * event on the network pipe.
136 */
137static void
138netPipe_io_func( void* opaque, int fd, unsigned events )
139{
140 NetPipe* pipe = opaque;
141 int wakeFlags = 0;
142
143 /* Run the connector if we are in the CONNECTING state */
144 /* TODO: Add some sort of time-out, to deal with the case */
145 /* when the server is wedged. */
146 if (pipe->state == STATE_CONNECTING) {
147 AsyncStatus status = asyncConnector_run(pipe->connector);
148 if (status == ASYNC_NEED_MORE) {
149 return;
150 }
151 else if (status == ASYNC_ERROR) {
152 /* Could not connect, tell our client by closing the channel. */
153
154 netPipe_closeFromSocket(pipe);
155 return;
156 }
157 pipe->state = STATE_CONNECTED;
158 netPipe_resetState(pipe);
159 return;
160 }
161
162 /* Otherwise, accept incoming data */
163 if ((events & LOOP_IO_READ) != 0) {
164 if ((pipe->wakeWanted & PIPE_WAKE_READ) != 0) {
165 wakeFlags |= PIPE_WAKE_READ;
166 }
167 }
168
169 if ((events & LOOP_IO_WRITE) != 0) {
170 if ((pipe->wakeWanted & PIPE_WAKE_WRITE) != 0) {
171 wakeFlags |= PIPE_WAKE_WRITE;
172 }
173 }
174
175 /* Send wake signal to the guest if needed */
176 if (wakeFlags != 0) {
177 goldfish_pipe_wake(pipe->hwpipe, wakeFlags);
178 pipe->wakeWanted &= ~wakeFlags;
179 }
180
181 /* Reset state */
182 netPipe_resetState(pipe);
183}
184
185
186void*
187netPipe_initFromAddress( void* hwpipe, const SockAddress* address, Looper* looper )
188{
189 NetPipe* pipe;
190
191 ANEW0(pipe);
192
193 pipe->hwpipe = hwpipe;
194 pipe->state = STATE_INIT;
195
196 {
197 AsyncStatus status;
198
199 int fd = socket_create( sock_address_get_family(address), SOCKET_STREAM );
200 if (fd < 0) {
201 D("%s: Could create socket from address family!", __FUNCTION__);
202 netPipe_free(pipe);
203 return NULL;
204 }
205
206 loopIo_init(pipe->io, looper, fd, netPipe_io_func, pipe);
Jiang, Yunhong33f5c652012-04-29 03:46:19 +0800207 status = asyncConnector_init(pipe->connector, address, pipe->io);
David 'Digit' Turnerd4d688e2011-04-26 18:09:17 +0200208 pipe->state = STATE_CONNECTING;
209
David 'Digit' Turnerd4d688e2011-04-26 18:09:17 +0200210 if (status == ASYNC_ERROR) {
211 D("%s: Could not connect to socket: %s",
212 __FUNCTION__, errno_str);
213 netPipe_free(pipe);
214 return NULL;
215 }
216 if (status == ASYNC_COMPLETE) {
217 pipe->state = STATE_CONNECTED;
218 netPipe_resetState(pipe);
219 }
220 }
221
222 return pipe;
223}
224
225
226/* Called when the guest wants to close the channel. This is different
227 * from netPipe_closeFromSocket() which is called when the socket is
228 * disconnected. */
229static void
230netPipe_closeFromGuest( void* opaque )
231{
232 NetPipe* pipe = opaque;
233 netPipe_free(pipe);
234}
235
Jiang, Yunhong33f5c652012-04-29 03:46:19 +0800236static int netPipeReadySend(NetPipe *pipe)
237{
238 if (pipe->state == STATE_CONNECTED)
239 return 0;
240 else if (pipe->state == STATE_CONNECTING)
241 return PIPE_ERROR_AGAIN;
242 else if (pipe->hwpipe == NULL)
243 return PIPE_ERROR_INVAL;
244 else
245 return PIPE_ERROR_IO;
246}
David 'Digit' Turnerd4d688e2011-04-26 18:09:17 +0200247
248static int
249netPipe_sendBuffers( void* opaque, const GoldfishPipeBuffer* buffers, int numBuffers )
250{
251 NetPipe* pipe = opaque;
252 int count = 0;
253 int ret = 0;
254 int buffStart = 0;
255 const GoldfishPipeBuffer* buff = buffers;
256 const GoldfishPipeBuffer* buffEnd = buff + numBuffers;
257
Jiang, Yunhong33f5c652012-04-29 03:46:19 +0800258 ret = netPipeReadySend(pipe);
259 if (ret != 0)
260 return ret;
261
David 'Digit' Turnerd4d688e2011-04-26 18:09:17 +0200262 for (; buff < buffEnd; buff++)
263 count += buff->size;
264
265 buff = buffers;
266 while (count > 0) {
267 int avail = buff->size - buffStart;
David 'Digit' Turner82e62772011-06-21 10:01:01 +0200268 int len = socket_send(pipe->io->fd, buff->data + buffStart, avail);
David 'Digit' Turnerd4d688e2011-04-26 18:09:17 +0200269
270 /* the write succeeded */
271 if (len > 0) {
272 buffStart += len;
273 if (buffStart >= buff->size) {
274 buff++;
275 buffStart = 0;
276 }
277 count -= len;
278 ret += len;
279 continue;
280 }
281
282 /* we reached the end of stream? */
283 if (len == 0) {
284 if (ret == 0)
285 ret = PIPE_ERROR_IO;
286 break;
287 }
288
David 'Digit' Turnerd4d688e2011-04-26 18:09:17 +0200289 /* if we already wrote some stuff, simply return */
290 if (ret > 0) {
291 break;
292 }
293
294 /* need to return an appropriate error code */
295 if (errno == EAGAIN || errno == EWOULDBLOCK) {
296 ret = PIPE_ERROR_AGAIN;
297 } else {
298 ret = PIPE_ERROR_IO;
299 }
300 break;
301 }
302
303 return ret;
304}
305
306static int
307netPipe_recvBuffers( void* opaque, GoldfishPipeBuffer* buffers, int numBuffers )
308{
309 NetPipe* pipe = opaque;
310 int count = 0;
311 int ret = 0;
312 int buffStart = 0;
313 GoldfishPipeBuffer* buff = buffers;
314 GoldfishPipeBuffer* buffEnd = buff + numBuffers;
315
316 for (; buff < buffEnd; buff++)
317 count += buff->size;
318
319 buff = buffers;
320 while (count > 0) {
321 int avail = buff->size - buffStart;
David 'Digit' Turner82e62772011-06-21 10:01:01 +0200322 int len = socket_recv(pipe->io->fd, buff->data + buffStart, avail);
David 'Digit' Turnerd4d688e2011-04-26 18:09:17 +0200323
324 /* the read succeeded */
325 if (len > 0) {
326 buffStart += len;
327 if (buffStart >= buff->size) {
328 buff++;
329 buffStart = 0;
330 }
331 count -= len;
332 ret += len;
333 continue;
334 }
335
336 /* we reached the end of stream? */
337 if (len == 0) {
338 if (ret == 0)
339 ret = PIPE_ERROR_IO;
340 break;
341 }
342
David 'Digit' Turnerd4d688e2011-04-26 18:09:17 +0200343 /* if we already read some stuff, simply return */
344 if (ret > 0) {
345 break;
346 }
347
348 /* need to return an appropriate error code */
349 if (errno == EAGAIN || errno == EWOULDBLOCK) {
350 ret = PIPE_ERROR_AGAIN;
351 } else {
352 ret = PIPE_ERROR_IO;
353 }
354 break;
355 }
356 return ret;
357}
358
359static unsigned
360netPipe_poll( void* opaque )
361{
362 NetPipe* pipe = opaque;
363 unsigned mask = loopIo_poll(pipe->io);
364 unsigned ret = 0;
365
366 if (mask & LOOP_IO_READ)
Vladimir Chtchetkinefd165052011-08-25 08:06:26 -0700367 ret |= PIPE_POLL_IN;
David 'Digit' Turnerd4d688e2011-04-26 18:09:17 +0200368 if (mask & LOOP_IO_WRITE)
Vladimir Chtchetkinefd165052011-08-25 08:06:26 -0700369 ret |= PIPE_POLL_OUT;
David 'Digit' Turnerd4d688e2011-04-26 18:09:17 +0200370
371 return ret;
372}
373
374static void
375netPipe_wakeOn( void* opaque, int flags )
376{
377 NetPipe* pipe = opaque;
378
379 DD("%s: flags=%d", __FUNCTION__, flags);
380
381 pipe->wakeWanted |= flags;
382 netPipe_resetState(pipe);
383}
384
385
386void*
387netPipe_initTcp( void* hwpipe, void* _looper, const char* args )
388{
389 /* Build SockAddress from arguments. Acceptable formats are:
David 'Digit' Turnerd4d688e2011-04-26 18:09:17 +0200390 * <port>
David 'Digit' Turnerd4d688e2011-04-26 18:09:17 +0200391 */
392 SockAddress address;
David 'Digit' Turnerafe299d2011-07-07 04:46:27 +0200393 uint16_t port;
David 'Digit' Turnerd4d688e2011-04-26 18:09:17 +0200394 void* ret;
395
396 if (args == NULL) {
397 D("%s: Missing address!", __FUNCTION__);
398 return NULL;
399 }
David 'Digit' Turnerafe299d2011-07-07 04:46:27 +0200400 D("%s: Port is '%s'", __FUNCTION__, args);
David 'Digit' Turnerd4d688e2011-04-26 18:09:17 +0200401
402 /* Now, look at the port number */
403 {
404 char* end;
405 long val = strtol(args, &end, 10);
406 if (end == NULL || *end != '\0' || val <= 0 || val > 65535) {
407 D("%s: Invalid port number: '%s'", __FUNCTION__, args);
408 }
David 'Digit' Turnerafe299d2011-07-07 04:46:27 +0200409 port = (uint16_t)val;
David 'Digit' Turnerd4d688e2011-04-26 18:09:17 +0200410 }
David 'Digit' Turnerafe299d2011-07-07 04:46:27 +0200411 sock_address_init_inet(&address, SOCK_ADDRESS_INET_LOOPBACK, port);
David 'Digit' Turnerd4d688e2011-04-26 18:09:17 +0200412
413 ret = netPipe_initFromAddress(hwpipe, &address, _looper);
414
415 sock_address_done(&address);
416 return ret;
417}
418
David 'Digit' Turner82e62772011-06-21 10:01:01 +0200419#ifndef _WIN32
David 'Digit' Turnerd4d688e2011-04-26 18:09:17 +0200420void*
421netPipe_initUnix( void* hwpipe, void* _looper, const char* args )
422{
423 /* Build SockAddress from arguments. Acceptable formats are:
424 *
425 * <path>
426 */
427 SockAddress address;
428 void* ret;
429
430 if (args == NULL || args[0] == '\0') {
431 D("%s: Missing address!", __FUNCTION__);
432 return NULL;
433 }
434 D("%s: Address is '%s'", __FUNCTION__, args);
435
436 sock_address_init_unix(&address, args);
437
438 ret = netPipe_initFromAddress(hwpipe, &address, _looper);
439
440 sock_address_done(&address);
441 return ret;
442}
David 'Digit' Turner82e62772011-06-21 10:01:01 +0200443#endif
David 'Digit' Turnerd4d688e2011-04-26 18:09:17 +0200444
445/**********************************************************************
446 **********************************************************************
447 *****
448 ***** N E T W O R K P I P E M E S S A G E S
449 *****
450 *****/
451
452static const GoldfishPipeFuncs netPipeTcp_funcs = {
453 netPipe_initTcp,
454 netPipe_closeFromGuest,
455 netPipe_sendBuffers,
456 netPipe_recvBuffers,
457 netPipe_poll,
458 netPipe_wakeOn,
David 'Digit' Turner3e92c2d2011-10-11 03:02:41 +0200459 NULL, /* we can't save these */
460 NULL, /* we can't load these */
David 'Digit' Turnerd4d688e2011-04-26 18:09:17 +0200461};
462
David 'Digit' Turner82e62772011-06-21 10:01:01 +0200463#ifndef _WIN32
David 'Digit' Turnerd4d688e2011-04-26 18:09:17 +0200464static const GoldfishPipeFuncs netPipeUnix_funcs = {
465 netPipe_initUnix,
466 netPipe_closeFromGuest,
467 netPipe_sendBuffers,
468 netPipe_recvBuffers,
469 netPipe_poll,
470 netPipe_wakeOn,
David 'Digit' Turner3e92c2d2011-10-11 03:02:41 +0200471 NULL, /* we can't save these */
472 NULL, /* we can't load these */
David 'Digit' Turnerd4d688e2011-04-26 18:09:17 +0200473};
David 'Digit' Turner82e62772011-06-21 10:01:01 +0200474#endif
David 'Digit' Turnerd4d688e2011-04-26 18:09:17 +0200475
David 'Digit' Turnercb88e792011-08-26 01:35:14 +0200476/* This is set to 1 in android_init_opengles() below, and tested
477 * by openglesPipe_init() to refuse a pipe connection if the function
478 * was never called.
479 */
480static int _opengles_init;
David 'Digit' Turnerd4d688e2011-04-26 18:09:17 +0200481
482static void*
483openglesPipe_init( void* hwpipe, void* _looper, const char* args )
484{
Guy Zadickarioe2790e02011-07-08 22:25:44 +0300485 NetPipe *pipe;
David 'Digit' Turnerd4d688e2011-04-26 18:09:17 +0200486
David 'Digit' Turnercb88e792011-08-26 01:35:14 +0200487 if (!_opengles_init) {
488 /* This should never happen, unless there is a bug in the
489 * emulator's initialization, or the system image. */
490 D("Trying to open the OpenGLES pipe without GPU emulation!");
491 return NULL;
492 }
493
Jesse Hall055adab2012-07-11 16:48:28 -0700494 char server_addr[PATH_MAX];
495 android_gles_server_path(server_addr, sizeof(server_addr));
David Turner7b56a4a2011-09-12 18:21:58 +0200496#ifndef _WIN32
497 if (android_gles_fast_pipes) {
Jesse Hall055adab2012-07-11 16:48:28 -0700498 pipe = (NetPipe *)netPipe_initUnix(hwpipe, _looper, server_addr);
499 D("Creating Unix OpenGLES pipe for GPU emulation: %s", server_addr);
David Turner7b56a4a2011-09-12 18:21:58 +0200500 } else {
501#else /* _WIN32 */
502 {
503#endif
504 /* Connect through TCP as a fallback */
Jesse Hall055adab2012-07-11 16:48:28 -0700505 pipe = (NetPipe *)netPipe_initTcp(hwpipe, _looper, server_addr);
David Turner7b56a4a2011-09-12 18:21:58 +0200506 D("Creating TCP OpenGLES pipe for GPU emulation!");
507 }
David 'Digit' Turner6a8b6982011-08-26 15:19:25 +0200508 if (pipe != NULL) {
509 // Disable TCP nagle algorithm to improve throughput of small packets
510 socket_set_nodelay(pipe->io->fd);
David Turner6d02d6c2011-08-15 23:07:03 +0200511
512 // On Win32, adjust buffer sizes
513#ifdef _WIN32
David 'Digit' Turner6a8b6982011-08-26 15:19:25 +0200514 {
515 int sndbuf = 128 * 1024;
516 int len = sizeof(sndbuf);
517 if (setsockopt(pipe->io->fd, SOL_SOCKET, SO_SNDBUF,
518 (char*)&sndbuf, len) == SOCKET_ERROR) {
519 D("Failed to set SO_SNDBUF to %d error=0x%x\n",
520 sndbuf, WSAGetLastError());
521 }
David Turner6d02d6c2011-08-15 23:07:03 +0200522 }
David Turner6d02d6c2011-08-15 23:07:03 +0200523#endif /* _WIN32 */
David 'Digit' Turner6a8b6982011-08-26 15:19:25 +0200524 }
Guy Zadickarioe2790e02011-07-08 22:25:44 +0300525
526 return pipe;
David 'Digit' Turnerd4d688e2011-04-26 18:09:17 +0200527}
528
529static const GoldfishPipeFuncs openglesPipe_funcs = {
530 openglesPipe_init,
531 netPipe_closeFromGuest,
532 netPipe_sendBuffers,
533 netPipe_recvBuffers,
534 netPipe_poll,
535 netPipe_wakeOn,
David 'Digit' Turner3e92c2d2011-10-11 03:02:41 +0200536 NULL, /* we can't save these */
537 NULL, /* we can't load these */
David 'Digit' Turnerd4d688e2011-04-26 18:09:17 +0200538};
539
David 'Digit' Turnerd4d688e2011-04-26 18:09:17 +0200540void
541android_net_pipes_init(void)
542{
543 Looper* looper = looper_newCore();
544
545 goldfish_pipe_add_type( "tcp", looper, &netPipeTcp_funcs );
David 'Digit' Turner82e62772011-06-21 10:01:01 +0200546#ifndef _WIN32
David 'Digit' Turnerd4d688e2011-04-26 18:09:17 +0200547 goldfish_pipe_add_type( "unix", looper, &netPipeUnix_funcs );
David 'Digit' Turner82e62772011-06-21 10:01:01 +0200548#endif
David 'Digit' Turnerd4d688e2011-04-26 18:09:17 +0200549 goldfish_pipe_add_type( "opengles", looper, &openglesPipe_funcs );
550}
David 'Digit' Turnercb88e792011-08-26 01:35:14 +0200551
552int
553android_init_opengles_pipes(void)
554{
555 /* TODO: Check that we can load and initialize the host emulation
556 * libraries, and return -1 in case of error.
557 */
558 _opengles_init = 1;
559 return 0;
560}