1f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org/*
2f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * Copyright 2009 VMware, Inc.
3f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * All Rights Reserved.
4f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org *
5f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * Permission is hereby granted, free of charge, to any person obtaining a
6f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * copy of this software and associated documentation files (the "Software"),
7f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * to deal in the Software without restriction, including without limitation
8f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * on the rights to use, copy, modify, merge, publish, distribute, sub
9f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * license, and/or sell copies of the Software, and to permit persons to whom
10f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * the Software is furnished to do so, subject to the following conditions:
11f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org *
12f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * The above copyright notice and this permission notice (including the next
13f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * paragraph) shall be included in all copies or substantial portions of the
14f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * Software.
15f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org *
16f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.  IN NO EVENT SHALL
19f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * VMWARE AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
20f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
21f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
22f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * USE OR OTHER DEALINGS IN THE SOFTWARE.
23f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org */
24f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
25f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "rbug.h"
26f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "rbug_internal.h"
27f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
28f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "util/u_network.h"
29f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
30f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstruct rbug_connection
31f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
32f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   int socket;
33f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   uint32_t send_serial;
34f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   uint32_t recv_serial;
35f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   enum rbug_opcode opcode;
36f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org};
37f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
38f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org/**
39f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * Create a rbug connection from a socket created with u_socket.
40f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org *
41f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * Result:
42f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org *    A new allocated connection using socket as communication path
43f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org */
44f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstruct rbug_connection *
45f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgrbug_from_socket(int socket)
46f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
47f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   struct rbug_connection *c = CALLOC_STRUCT(rbug_connection);
48f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   c->socket = socket;
49f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   return c;
50f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
51f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
52f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org/**
53f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * Free a connection, also closes socket.
54f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org */
55f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgvoid
56f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgrbug_disconnect(struct rbug_connection *c)
57f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
58f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   u_socket_close(c->socket);
59f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   FREE(c);
60f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
61f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
62f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org/**
63f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * Waits for a message to be fully received.
64f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * Also returns the serial for the message, serial is not touched for replys.
65f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org *
66f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * Result:
67f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org *    demarshaled message on success, NULL on connection error
68f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org */
69f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstruct rbug_header *
70f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgrbug_get_message(struct rbug_connection *c, uint32_t *serial)
71f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
72f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   struct rbug_proto_header header;
73f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   struct rbug_header *out;
74f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   struct rbug_proto_header *data;
75f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   size_t length = 0;
76f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   size_t read = 0;
77f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   int ret;
78f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
79f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
80f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   ret = u_socket_peek(c->socket, &header, sizeof(header));
81f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   if (ret <= 0) {
82f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      return NULL;
83f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   }
84f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
85f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   length = (size_t)header.length * 4;
86f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   data = MALLOC(length);
87f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   if (!data) {
88f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      return NULL;
89f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   }
90f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   data->opcode = 0;
91f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
92f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   do {
93f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      uint8_t *ptr = ((uint8_t*)data) + read;
94f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      ret = u_socket_recv(c->socket, ptr, length - read);
95f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
96f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      if (ret <= 0) {
97f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         FREE(data);
98f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         return NULL;
99f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      }
100f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
101f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      read += ret;
102f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   } while(read < length);
103f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
104f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   out = rbug_demarshal(data);
105f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   if (!out)
106f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      FREE(data);
107f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   else if (serial)
108f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      *serial = c->recv_serial++;
109f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   else
110f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      c->recv_serial++;
111f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
112f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   return out;
113f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
114f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
115f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org/**
116f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * Frees a message and associated data.
117f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org */
118f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgvoid
119f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgrbug_free_header(struct rbug_header *header)
120f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
121f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   if (!header)
122f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      return;
123f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
124f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   FREE(header->__message);
125f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   FREE(header);
126f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
127f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
128f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org/**
129f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * Internal function used by rbug_send_* functions.
130f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org *
131f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * Start sending a message.
132f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org */
133f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgint
134f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgrbug_connection_send_start(struct rbug_connection *c, enum rbug_opcode opcode, uint32_t length)
135f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
136f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   c->opcode = opcode;
137f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   return 0;
138f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
139f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
140f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org/**
141f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * Internal function used by rbug_send_* functions.
142f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org *
143f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * Write data to the socket.
144f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org */
145f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgint
146f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgrbug_connection_write(struct rbug_connection *c, void *to, uint32_t size)
147f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
148f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   int ret = u_socket_send(c->socket, to, size);
149f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   return ret;
150f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
151f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
152f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org/**
153f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * Internal function used by rbug_send_* functions.
154f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org *
155f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * Finish writeing data to the socket.
156f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * Ups the send_serial and sets the serial argument if supplied.
157f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org */
158f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgint rbug_connection_send_finish(struct rbug_connection *c, uint32_t *serial)
159f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
160f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   if (c->opcode < 0)
161f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      return 0;
162f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   else if (serial)
163f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      *serial = c->send_serial++;
164f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   else
165f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      c->send_serial++;
166f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
167f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   return 0;
168f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
169