/* Chrysalide - Outil d'analyse de fichiers binaires
* tcp.c - gestion des connexions TCP aux serveurs GDB.
*
* Copyright (C) 2009-2017 Cyrille Bagard
*
* This file is part of Chrysalide.
*
* Chrysalide is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* Chrysalide is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Chrysalide. If not, see .
*/
#include "tcp.h"
#include
#include
#include
#include
#include
#include
#include "stream-int.h"
#include "../../common/net.h"
/* Flux de communication TCP avec un serveur GDB (instance) */
struct _GGdbTcpClient
{
GGdbStream parent; /* A laisser en premier */
};
/* Flux de communication TCP avec un serveur GDB (classe) */
struct _GGdbTcpClientClass
{
GGdbStreamClass parent; /* A laisser en premier */
};
/* Initialise la classe des flux de communication TCP avec GDB. */
static void g_gdb_tcp_client_class_init(GGdbTcpClientClass *);
/* Initialise une instance de flux de communication avec GDB. */
static void g_gdb_tcp_client_init(GGdbTcpClient *);
/* Ouvre une connexion TCP à un serveur GDB. */
//static int connect_via_tcp(const char *, const char *);
/* Envoie des données à un serveur GDB. */
static bool g_gdb_tcp_client_send_data(GGdbTcpClient *, const char *, size_t);
/* Réceptionne un octet de donnée d'un serveur GDB. */
static bool g_gdb_tcp_client_recv_byte(GGdbTcpClient *, char *);
/* Indique le type défini pour un flux de communication TCP avec un serveur GDB. */
G_DEFINE_TYPE(GGdbTcpClient, g_gdb_tcp_client, G_TYPE_GDB_STREAM);
/******************************************************************************
* *
* Paramètres : klass = classe à initialiser. *
* *
* Description : Initialise la classe des flux de communication TCP avec GDB. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_gdb_tcp_client_class_init(GGdbTcpClientClass *klass)
{
}
/******************************************************************************
* *
* Paramètres : client = instance à initialiser. *
* *
* Description : Initialise une instance de flux de communication avec GDB. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_gdb_tcp_client_init(GGdbTcpClient *client)
{
GGdbStream *stream; /* Version parente */
stream = G_GDB_STREAM(client);
stream->send_data = (send_gdb_data_fc)g_gdb_tcp_client_send_data;
stream->recv_byte = (recv_gdb_byte_fc)g_gdb_tcp_client_recv_byte;
}
/******************************************************************************
* *
* Paramètres : server = nom ou adresse du serveur à contacter. *
* port = port de connexion. *
* *
* Description : Ouvre une connexion TCP à un serveur GDB. *
* *
* Retour : Flux ouvert en lecture/écriture ou -1 en cas d'échec. *
* *
* Remarques : - *
* *
******************************************************************************/
#if 0
static int connect_via_tcp(const char *server, const char *port)
{
int result; /* Bilan à retourner */
struct addrinfo hints; /* Type de connexion souhaitée */
struct addrinfo *infos; /* Informations disponibles */
int ret; /* Bilan d'un appel */
struct addrinfo *iter; /* Boucle de parcours */
struct sockaddr_in addr; /* Infos de connexion distante */
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_UNSPEC; /* IPv4 ou IPv6 */
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = 0;
hints.ai_protocol = 0; /* N'importe quel protocole */
ret = getaddrinfo(server, port, &hints, &infos);
if (ret != 0)
{
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(ret));
return -1;
}
for (iter = infos; iter != NULL; iter = iter->ai_next)
{
result = socket(iter->ai_family, iter->ai_socktype, iter->ai_protocol);
if (result == -1) continue;
ret = connect(result, iter->ai_addr, iter->ai_addrlen);
if (ret == 0) break;
perror("connect");
close(result);
}
freeaddrinfo(infos);
if (iter == NULL) return -1;
ret = getpeername(result, (struct sockaddr *)&addr, (socklen_t []){ sizeof(struct sockaddr_in) });
if (ret == -1)
{
perror("getpeername");
close(result);
return -1;
}
printf("Connecté à %s:%hd\n", server, ntohs(addr.sin_port));
return result;
}
#endif
/******************************************************************************
* *
* Paramètres : server = nom ou adresse du serveur à contacter. *
* port = port de connexion. *
* owner = débogueur tributaire du canal de communication. *
* *
* Description : Crée une nouvelle connexion TCP à un serveur GDB. *
* *
* Retour : Adresse de la structure mise en place. *
* *
* Remarques : - *
* *
******************************************************************************/
GGdbStream *g_gdb_tcp_client_new(const char *server, const char *port, GGdbDebugger *owner)
{
GGdbTcpClient *result; /* Structure à retourner */
int sock; /* Flux ouvert à construire */
sock = connect_via_tcp(server, port, NULL);
if (sock == -1) return NULL;
result = g_object_new(G_TYPE_GDB_TCP_CLIENT, NULL);
G_GDB_STREAM(result)->fd = sock;
G_GDB_STREAM(result)->owner = owner;
g_object_ref(G_OBJECT(owner));
if (!g_gdb_stream_listen(G_GDB_STREAM(result)))
goto ggtcn_error;
return G_GDB_STREAM(result);
ggtcn_error:
return NULL;
}
/******************************************************************************
* *
* Paramètres : client = flux ouvert en écriture à utiliser. *
* data = données à envoyer. *
* len = quantité de ces données. *
* *
* Description : Envoie des données à un serveur GDB. *
* *
* Retour : Bilan de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
static bool g_gdb_tcp_client_send_data(GGdbTcpClient *client, const char *data, size_t len)
{
ssize_t sent; /* Quantité de données envoyée */
sent = send(G_GDB_STREAM(client)->fd, data, len, 0);
//printf(" sent '%s'\n", data);
//printf(" sent ? %d vs %d\n", (int)sent, (int)len);
return (sent == len);
}
/******************************************************************************
* *
* Paramètres : client = flux ouvert en lecture à utiliser. *
* data = donnée à recevoir. *
* *
* Description : Réceptionne un octet de donnée d'un serveur GDB. *
* *
* Retour : Bilan de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
static bool g_gdb_tcp_client_recv_byte(GGdbTcpClient *client, char *data)
{
ssize_t got; /* Quantité de données reçue */
got = recv(G_GDB_STREAM(client)->fd, data, 1, 0);
//printf(" got ? %d vs %d -> %c (0x%02hhx\n", (int)got, (int)1, *data, *data);
return (got == 1);
}