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