1848b8605Smrg/*
2848b8605Smrg * Copyright 2009 VMware, Inc.
3848b8605Smrg * All Rights Reserved.
4848b8605Smrg *
5848b8605Smrg * Permission is hereby granted, free of charge, to any person obtaining a
6848b8605Smrg * copy of this software and associated documentation files (the "Software"),
7848b8605Smrg * to deal in the Software without restriction, including without limitation
8848b8605Smrg * on the rights to use, copy, modify, merge, publish, distribute, sub
9848b8605Smrg * license, and/or sell copies of the Software, and to permit persons to whom
10848b8605Smrg * the Software is furnished to do so, subject to the following conditions:
11848b8605Smrg *
12848b8605Smrg * The above copyright notice and this permission notice (including the next
13848b8605Smrg * paragraph) shall be included in all copies or substantial portions of the
14848b8605Smrg * Software.
15848b8605Smrg *
16848b8605Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17848b8605Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18848b8605Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.  IN NO EVENT SHALL
19848b8605Smrg * VMWARE AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
20848b8605Smrg * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
21848b8605Smrg * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
22848b8605Smrg * USE OR OTHER DEALINGS IN THE SOFTWARE.
23848b8605Smrg */
24848b8605Smrg
25848b8605Smrg#include "rbug.h"
26848b8605Smrg#include "rbug_internal.h"
27848b8605Smrg
28848b8605Smrg#include "util/u_network.h"
29848b8605Smrg
30848b8605Smrgstruct rbug_connection
31848b8605Smrg{
32848b8605Smrg   int socket;
33848b8605Smrg   uint32_t send_serial;
34848b8605Smrg   uint32_t recv_serial;
35848b8605Smrg   enum rbug_opcode opcode;
36848b8605Smrg};
37848b8605Smrg
38848b8605Smrg/**
39848b8605Smrg * Create a rbug connection from a socket created with u_socket.
40848b8605Smrg *
41848b8605Smrg * Result:
42848b8605Smrg *    A new allocated connection using socket as communication path
43848b8605Smrg */
44848b8605Smrgstruct rbug_connection *
45848b8605Smrgrbug_from_socket(int socket)
46848b8605Smrg{
47848b8605Smrg   struct rbug_connection *c = CALLOC_STRUCT(rbug_connection);
48848b8605Smrg   c->socket = socket;
49848b8605Smrg   return c;
50848b8605Smrg}
51848b8605Smrg
52848b8605Smrg/**
53848b8605Smrg * Free a connection, also closes socket.
54848b8605Smrg */
55848b8605Smrgvoid
56848b8605Smrgrbug_disconnect(struct rbug_connection *c)
57848b8605Smrg{
58848b8605Smrg   u_socket_close(c->socket);
59848b8605Smrg   FREE(c);
60848b8605Smrg}
61848b8605Smrg
62848b8605Smrg/**
63848b8605Smrg * Waits for a message to be fully received.
64848b8605Smrg * Also returns the serial for the message, serial is not touched for replys.
65848b8605Smrg *
66848b8605Smrg * Result:
67848b8605Smrg *    demarshaled message on success, NULL on connection error
68848b8605Smrg */
69848b8605Smrgstruct rbug_header *
70848b8605Smrgrbug_get_message(struct rbug_connection *c, uint32_t *serial)
71848b8605Smrg{
72848b8605Smrg   struct rbug_proto_header header;
73848b8605Smrg   struct rbug_header *out;
74848b8605Smrg   struct rbug_proto_header *data;
75848b8605Smrg   size_t length = 0;
76848b8605Smrg   size_t read = 0;
77848b8605Smrg   int ret;
78848b8605Smrg
79848b8605Smrg
80848b8605Smrg   ret = u_socket_peek(c->socket, &header, sizeof(header));
81848b8605Smrg   if (ret <= 0) {
82848b8605Smrg      return NULL;
83848b8605Smrg   }
84848b8605Smrg
85848b8605Smrg   length = (size_t)header.length * 4;
86848b8605Smrg   data = MALLOC(length);
87848b8605Smrg   if (!data) {
88848b8605Smrg      return NULL;
89848b8605Smrg   }
90848b8605Smrg   data->opcode = 0;
91848b8605Smrg
92848b8605Smrg   do {
93848b8605Smrg      uint8_t *ptr = ((uint8_t*)data) + read;
94848b8605Smrg      ret = u_socket_recv(c->socket, ptr, length - read);
95848b8605Smrg
96848b8605Smrg      if (ret <= 0) {
97848b8605Smrg         FREE(data);
98848b8605Smrg         return NULL;
99848b8605Smrg      }
100848b8605Smrg
101848b8605Smrg      read += ret;
102848b8605Smrg   } while(read < length);
103848b8605Smrg
104848b8605Smrg   out = rbug_demarshal(data);
105848b8605Smrg   if (!out)
106848b8605Smrg      FREE(data);
107848b8605Smrg   else if (serial)
108848b8605Smrg      *serial = c->recv_serial++;
109848b8605Smrg   else
110848b8605Smrg      c->recv_serial++;
111848b8605Smrg
112848b8605Smrg   return out;
113848b8605Smrg}
114848b8605Smrg
115848b8605Smrg/**
116848b8605Smrg * Frees a message and associated data.
117848b8605Smrg */
118848b8605Smrgvoid
119848b8605Smrgrbug_free_header(struct rbug_header *header)
120848b8605Smrg{
121848b8605Smrg   if (!header)
122848b8605Smrg      return;
123848b8605Smrg
124848b8605Smrg   FREE(header->__message);
125848b8605Smrg   FREE(header);
126848b8605Smrg}
127848b8605Smrg
128848b8605Smrg/**
129848b8605Smrg * Internal function used by rbug_send_* functions.
130848b8605Smrg *
131848b8605Smrg * Start sending a message.
132848b8605Smrg */
133848b8605Smrgint
134848b8605Smrgrbug_connection_send_start(struct rbug_connection *c, enum rbug_opcode opcode, uint32_t length)
135848b8605Smrg{
136848b8605Smrg   c->opcode = opcode;
137848b8605Smrg   return 0;
138848b8605Smrg}
139848b8605Smrg
140848b8605Smrg/**
141848b8605Smrg * Internal function used by rbug_send_* functions.
142848b8605Smrg *
143848b8605Smrg * Write data to the socket.
144848b8605Smrg */
145848b8605Smrgint
146848b8605Smrgrbug_connection_write(struct rbug_connection *c, void *to, uint32_t size)
147848b8605Smrg{
148848b8605Smrg   int ret = u_socket_send(c->socket, to, size);
149848b8605Smrg   return ret;
150848b8605Smrg}
151848b8605Smrg
152848b8605Smrg/**
153848b8605Smrg * Internal function used by rbug_send_* functions.
154848b8605Smrg *
155b8e80941Smrg * Finish writing data to the socket.
156848b8605Smrg * Ups the send_serial and sets the serial argument if supplied.
157848b8605Smrg */
158848b8605Smrgint rbug_connection_send_finish(struct rbug_connection *c, uint32_t *serial)
159848b8605Smrg{
160848b8605Smrg   if (c->opcode < 0)
161848b8605Smrg      return 0;
162848b8605Smrg   else if (serial)
163848b8605Smrg      *serial = c->send_serial++;
164848b8605Smrg   else
165848b8605Smrg      c->send_serial++;
166848b8605Smrg
167848b8605Smrg   return 0;
168848b8605Smrg}
169