static Pipe* pipe_load( PipeDevice* dev, QEMUFile* file, int version_id ) { Pipe* pipe; const PipeService* service = NULL; int state = qemu_get_byte(file); uint64_t channel; if (state != 0) { /* Pipe is associated with a service. */ char* name = qemu_get_string(file); if (name == NULL) return NULL; service = goldfish_pipe_find_type(name); if (service == NULL) { D("No QEMU pipe service named '%s'", name); AFREE(name); return NULL; } } if (version_id == GOLDFISH_PIPE_SAVE_VERSION_LEGACY) { channel = qemu_get_be32(file); } else { channel = qemu_get_be64(file); } pipe = pipe_new(channel, dev); pipe->wanted = qemu_get_byte(file); pipe->closed = qemu_get_byte(file); if (qemu_get_byte(file) != 0) { pipe->args = qemu_get_string(file); } pipe->service = service; if (service != NULL) { pipe->funcs = &service->funcs; } if (pipe->funcs->load) { pipe->opaque = pipe->funcs->load(pipe, service ? service->opaque : NULL, pipe->args, file); if (pipe->opaque == NULL) { AFREE(pipe); return NULL; } } else { /* Force-close the pipe on load */ pipe->closed = 1; } return pipe; }
static Pipe* pipe_load( PipeDevice* dev, QEMUFile* file ) { Pipe* pipe; const PipeService* service = NULL; int state = qemu_get_byte(file); uint32_t channel; if (state != 0) { char* name = qemu_get_string(file); if (name == NULL) return NULL; service = goldfish_pipe_find_type(name); if (service == NULL) { D("No QEMU pipe service named '%s'", name); AFREE(name); return NULL; } } channel = qemu_get_be32(file); pipe = pipe_new(channel, dev); pipe->wanted = qemu_get_byte(file); pipe->closed = qemu_get_byte(file); if (qemu_get_byte(file) != 0) { pipe->args = qemu_get_string(file); } pipe->service = service; if (service != NULL) { pipe->funcs = &service->funcs; } if (pipe->funcs->load) { pipe->opaque = pipe->funcs->load(pipe, service ? service->opaque : NULL, pipe->args, file); if (pipe->opaque == NULL) { AFREE(pipe); return NULL; } } else { pipe->closed = 1; } return pipe; }
static int pipeConnector_sendBuffers( void* opaque, const GoldfishPipeBuffer* buffers, int numBuffers ) { PipeConnector* pcon = opaque; const GoldfishPipeBuffer* buffers_limit = buffers + numBuffers; int ret = 0; DD("%s: channel=0x%x numBuffers=%d", __FUNCTION__, pcon->pipe->channel, numBuffers); while (buffers < buffers_limit) { int avail; DD("%s: buffer data (%3d bytes): '%.*s'", __FUNCTION__, buffers[0].size, buffers[0].size, buffers[0].data); if (buffers[0].size == 0) { buffers++; continue; } avail = sizeof(pcon->buffer) - pcon->buffpos; if (avail > buffers[0].size) avail = buffers[0].size; if (avail > 0) { memcpy(pcon->buffer + pcon->buffpos, buffers[0].data, avail); pcon->buffpos += avail; ret += avail; } buffers++; } if (memchr(pcon->buffer, '\0', pcon->buffpos) != NULL) { char* pipeName; char* pipeArgs; D("%s: connector: '%s'", __FUNCTION__, pcon->buffer); if (memcmp(pcon->buffer, "pipe:", 5) != 0) { D("%s: Unknown pipe connection: '%s'", __FUNCTION__, pcon->buffer); return PIPE_ERROR_INVAL; } pipeName = pcon->buffer + 5; pipeArgs = strchr(pipeName, ':'); if (pipeArgs != NULL) { *pipeArgs++ = '\0'; if (!*pipeArgs) pipeArgs = NULL; } Pipe* pipe = pcon->pipe; const PipeService* svc = goldfish_pipe_find_type(pipeName); if (svc == NULL) { D("%s: Unknown server!", __FUNCTION__); return PIPE_ERROR_INVAL; } void* peer = svc->funcs.init(pipe, svc->opaque, pipeArgs); if (peer == NULL) { D("%s: Initialization failed!", __FUNCTION__); return PIPE_ERROR_INVAL; } pipe->opaque = peer; pipe->service = svc; pipe->funcs = &svc->funcs; pipe->args = ASTRDUP(pipeArgs); AFREE(pcon); } return ret; }
static int pipeConnector_sendBuffers( void* opaque, const GoldfishPipeBuffer* buffers, int numBuffers ) { PipeConnector* pcon = opaque; const GoldfishPipeBuffer* buffers_limit = buffers + numBuffers; int ret = 0; DD("%s: channel=0x%llx numBuffers=%d", __FUNCTION__, (unsigned long long)pcon->pipe->channel, numBuffers); while (buffers < buffers_limit) { int avail; DD("%s: buffer data (%3d bytes): '%.*s'", __FUNCTION__, buffers[0].size, buffers[0].size, buffers[0].data); if (buffers[0].size == 0) { buffers++; continue; } avail = sizeof(pcon->buffer) - pcon->buffpos; if (avail > buffers[0].size) avail = buffers[0].size; if (avail > 0) { memcpy(pcon->buffer + pcon->buffpos, buffers[0].data, avail); pcon->buffpos += avail; ret += avail; } buffers++; } /* Now check that our buffer contains a zero-terminated string */ if (memchr(pcon->buffer, '\0', pcon->buffpos) != NULL) { /* Acceptable formats for the connection string are: * * pipe:<name> * pipe:<name>:<arguments> */ char* pipeName; char* pipeArgs; D("%s: connector: '%s'", __FUNCTION__, pcon->buffer); if (memcmp(pcon->buffer, "pipe:", 5) != 0) { /* Nope, we don't handle these for now. */ D("%s: Unknown pipe connection: '%s'", __FUNCTION__, pcon->buffer); return PIPE_ERROR_INVAL; } pipeName = pcon->buffer + 5; pipeArgs = strchr(pipeName, ':'); if (pipeArgs != NULL) { *pipeArgs++ = '\0'; if (!*pipeArgs) pipeArgs = NULL; } Pipe* pipe = pcon->pipe; const PipeService* svc = goldfish_pipe_find_type(pipeName); if (svc == NULL) { D("%s: Unknown server!", __FUNCTION__); return PIPE_ERROR_INVAL; } void* peer = svc->funcs.init(pipe, svc->opaque, pipeArgs); if (peer == NULL) { D("%s: Initialization failed!", __FUNCTION__); return PIPE_ERROR_INVAL; } /* Do the evil switch now */ pipe->opaque = peer; pipe->service = svc; pipe->funcs = &svc->funcs; pipe->args = ASTRDUP(pipeArgs); AFREE(pcon); } return ret; }