14a49301eSmrg/*
24a49301eSmrg * Copyright 2009 VMware, Inc.
34a49301eSmrg * All Rights Reserved.
44a49301eSmrg *
54a49301eSmrg * Permission is hereby granted, free of charge, to any person obtaining a
64a49301eSmrg * copy of this software and associated documentation files (the "Software"),
74a49301eSmrg * to deal in the Software without restriction, including without limitation
84a49301eSmrg * on the rights to use, copy, modify, merge, publish, distribute, sub
94a49301eSmrg * license, and/or sell copies of the Software, and to permit persons to whom
104a49301eSmrg * the Software is furnished to do so, subject to the following conditions:
114a49301eSmrg *
124a49301eSmrg * The above copyright notice and this permission notice (including the next
134a49301eSmrg * paragraph) shall be included in all copies or substantial portions of the
144a49301eSmrg * Software.
154a49301eSmrg *
164a49301eSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
174a49301eSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
184a49301eSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.  IN NO EVENT SHALL
194a49301eSmrg * VMWARE AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
204a49301eSmrg * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
214a49301eSmrg * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
224a49301eSmrg * USE OR OTHER DEALINGS IN THE SOFTWARE.
234a49301eSmrg */
244a49301eSmrg
25af69d88dSmrg#include "rbug.h"
26af69d88dSmrg#include "rbug_internal.h"
274a49301eSmrg
284a49301eSmrg#include "util/u_network.h"
294a49301eSmrg
304a49301eSmrgstruct rbug_connection
314a49301eSmrg{
324a49301eSmrg   int socket;
334a49301eSmrg   uint32_t send_serial;
344a49301eSmrg   uint32_t recv_serial;
354a49301eSmrg   enum rbug_opcode opcode;
364a49301eSmrg};
374a49301eSmrg
384a49301eSmrg/**
394a49301eSmrg * Create a rbug connection from a socket created with u_socket.
404a49301eSmrg *
414a49301eSmrg * Result:
424a49301eSmrg *    A new allocated connection using socket as communication path
434a49301eSmrg */
444a49301eSmrgstruct rbug_connection *
454a49301eSmrgrbug_from_socket(int socket)
464a49301eSmrg{
474a49301eSmrg   struct rbug_connection *c = CALLOC_STRUCT(rbug_connection);
484a49301eSmrg   c->socket = socket;
494a49301eSmrg   return c;
504a49301eSmrg}
514a49301eSmrg
524a49301eSmrg/**
534a49301eSmrg * Free a connection, also closes socket.
544a49301eSmrg */
554a49301eSmrgvoid
564a49301eSmrgrbug_disconnect(struct rbug_connection *c)
574a49301eSmrg{
584a49301eSmrg   u_socket_close(c->socket);
594a49301eSmrg   FREE(c);
604a49301eSmrg}
614a49301eSmrg
624a49301eSmrg/**
634a49301eSmrg * Waits for a message to be fully received.
644a49301eSmrg * Also returns the serial for the message, serial is not touched for replys.
654a49301eSmrg *
664a49301eSmrg * Result:
674a49301eSmrg *    demarshaled message on success, NULL on connection error
684a49301eSmrg */
694a49301eSmrgstruct rbug_header *
704a49301eSmrgrbug_get_message(struct rbug_connection *c, uint32_t *serial)
714a49301eSmrg{
724a49301eSmrg   struct rbug_proto_header header;
734a49301eSmrg   struct rbug_header *out;
744a49301eSmrg   struct rbug_proto_header *data;
754a49301eSmrg   size_t length = 0;
764a49301eSmrg   size_t read = 0;
774a49301eSmrg   int ret;
784a49301eSmrg
794a49301eSmrg
804a49301eSmrg   ret = u_socket_peek(c->socket, &header, sizeof(header));
814a49301eSmrg   if (ret <= 0) {
824a49301eSmrg      return NULL;
834a49301eSmrg   }
844a49301eSmrg
854a49301eSmrg   length = (size_t)header.length * 4;
864a49301eSmrg   data = MALLOC(length);
874a49301eSmrg   if (!data) {
884a49301eSmrg      return NULL;
894a49301eSmrg   }
904a49301eSmrg   data->opcode = 0;
914a49301eSmrg
924a49301eSmrg   do {
934a49301eSmrg      uint8_t *ptr = ((uint8_t*)data) + read;
944a49301eSmrg      ret = u_socket_recv(c->socket, ptr, length - read);
954a49301eSmrg
964a49301eSmrg      if (ret <= 0) {
974a49301eSmrg         FREE(data);
984a49301eSmrg         return NULL;
994a49301eSmrg      }
1004a49301eSmrg
1014a49301eSmrg      read += ret;
1024a49301eSmrg   } while(read < length);
1034a49301eSmrg
1044a49301eSmrg   out = rbug_demarshal(data);
1054a49301eSmrg   if (!out)
1064a49301eSmrg      FREE(data);
1074a49301eSmrg   else if (serial)
1084a49301eSmrg      *serial = c->recv_serial++;
1094a49301eSmrg   else
1104a49301eSmrg      c->recv_serial++;
1114a49301eSmrg
1124a49301eSmrg   return out;
1134a49301eSmrg}
1144a49301eSmrg
1154a49301eSmrg/**
1164a49301eSmrg * Frees a message and associated data.
1174a49301eSmrg */
1184a49301eSmrgvoid
1194a49301eSmrgrbug_free_header(struct rbug_header *header)
1204a49301eSmrg{
1214a49301eSmrg   if (!header)
1224a49301eSmrg      return;
1234a49301eSmrg
1244a49301eSmrg   FREE(header->__message);
1254a49301eSmrg   FREE(header);
1264a49301eSmrg}
1274a49301eSmrg
1284a49301eSmrg/**
1294a49301eSmrg * Internal function used by rbug_send_* functions.
1304a49301eSmrg *
1314a49301eSmrg * Start sending a message.
1324a49301eSmrg */
1334a49301eSmrgint
1344a49301eSmrgrbug_connection_send_start(struct rbug_connection *c, enum rbug_opcode opcode, uint32_t length)
1354a49301eSmrg{
1364a49301eSmrg   c->opcode = opcode;
1374a49301eSmrg   return 0;
1384a49301eSmrg}
1394a49301eSmrg
1404a49301eSmrg/**
1414a49301eSmrg * Internal function used by rbug_send_* functions.
1424a49301eSmrg *
1434a49301eSmrg * Write data to the socket.
1444a49301eSmrg */
1454a49301eSmrgint
1464a49301eSmrgrbug_connection_write(struct rbug_connection *c, void *to, uint32_t size)
1474a49301eSmrg{
1484a49301eSmrg   int ret = u_socket_send(c->socket, to, size);
1494a49301eSmrg   return ret;
1504a49301eSmrg}
1514a49301eSmrg
1524a49301eSmrg/**
1534a49301eSmrg * Internal function used by rbug_send_* functions.
1544a49301eSmrg *
15501e04c3fSmrg * Finish writing data to the socket.
1564a49301eSmrg * Ups the send_serial and sets the serial argument if supplied.
1574a49301eSmrg */
1584a49301eSmrgint rbug_connection_send_finish(struct rbug_connection *c, uint32_t *serial)
1594a49301eSmrg{
1604a49301eSmrg   if (c->opcode < 0)
1614a49301eSmrg      return 0;
1624a49301eSmrg   else if (serial)
1634a49301eSmrg      *serial = c->send_serial++;
1644a49301eSmrg   else
1654a49301eSmrg      c->send_serial++;
1664a49301eSmrg
1674a49301eSmrg   return 0;
1684a49301eSmrg}
169