/* Chrysalide - Outil d'analyse de fichiers binaires * tcp.c - gestion des connexions TCP aux serveurs JDWP. * * Copyright (C) 2010-2012 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 Foobar. If not, see . */ #include "tcp.h" #include #include #include #include #include #include #include #include "packet.h" #include "misc/header.h" #include "sets/list.h" #include "../stream-int.h" #include "../../common/net.h" #include "../../gui/panels/log.h" /* Flux de communication TCP avec un serveur JDWP (instance) */ struct _GJdwpTcpClient { GDebugStream parent; /* A laisser en premier */ char *server; /* Serveur à contacter */ char *port; /* Port de connexion */ int fd; /* Flux ouvert en L./E. */ }; /* Flux de communication TCP avec un serveur JDWP (classe) */ struct _GJdwpTcpClientClass { GDebugStreamClass parent; /* A laisser en premier */ }; /* Initialise la classe des flux de communication JDWP over TCP. */ static void g_jdwp_tcp_client_class_init(GJdwpTcpClientClass *); /* Initialise une instance de flux de communication avec JDWP. */ static void g_jdwp_tcp_client_init(GJdwpTcpClient *); /* Etablit de façon effective une connexion à la cible. */ static bool g_jdwp_tcp_client_connect(GJdwpTcpClient *); /* Attend le signalement de données à traiter. */ static bool g_jdwp_tcp_client_poll(GJdwpTcpClient *); /* Envoie un paquet de données à un serveur de débogage. */ static bool g_jdwp_tcp_client_send_packet(GJdwpTcpClient *, const GJdwpPacket *); /* Réceptionne un paquet de données d'un serveur de débogage. */ static bool g_jdwp_tcp_client_recv_packet(GJdwpTcpClient *, GJdwpPacket *); /* Libère le contenu alloué d'un paquet de débogage. */ static void g_jdwp_tcp_client_free_packet(GJdwpTcpClient *, GJdwpPacket *); /* Indique le type défini pour un flux de communication TCP avec un serveur JDWP. */ G_DEFINE_TYPE(GJdwpTcpClient, g_jdwp_tcp_client, G_TYPE_DEBUG_STREAM); /****************************************************************************** * * * Paramètres : klass = classe à initialiser. * * * * Description : Initialise la classe des flux de communication JVDP over TCP.* * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_jdwp_tcp_client_class_init(GJdwpTcpClientClass *klass) { } /****************************************************************************** * * * Paramètres : client = instance à initialiser. * * * * Description : Initialise une instance de flux de communication avec JDWP. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_jdwp_tcp_client_init(GJdwpTcpClient *client) { GDebugStream *stream; /* Version parente */ stream = G_DEBUG_STREAM(client); stream->connect = (debug_connect_fc)g_jdwp_tcp_client_connect; stream->poll = (debug_poll_fc)g_jdwp_tcp_client_poll; stream->send_packet = (debug_pkt_op_fc)g_jdwp_tcp_client_send_packet; stream->recv_packet = (debug_pkt_op_fc)g_jdwp_tcp_client_recv_packet; stream->free_packet = (debug_free_pkt_fc)g_jdwp_tcp_client_free_packet; stream->pkt_type = G_TYPE_JDWP_PACKET; } /****************************************************************************** * * * Paramètres : server = nom ou adresse du serveur à contacter. * * port = port de connexion. * * * * Description : Crée une nouvelle connexion TCP à un serveur JDWP. * * * * Retour : Adresse de la structure mise en place. * * * * Remarques : - * * * ******************************************************************************/ GDebugStream *g_jdwp_tcp_client_new(const char *server, const char *port) { GJdwpTcpClient *result; /* Structure à retourner */ result = g_object_new(G_TYPE_JDWP_TCP_CLIENT, NULL); result->server = strdup(server); result->port = strdup(port); result->fd = -1; return G_DEBUG_STREAM(result); } /****************************************************************************** * * * Paramètres : client = paramètres de connexion au serveur JDWP. * * * * Description : Etablit de façon effective une connexion à la cible. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ static bool g_jdwp_tcp_client_connect(GJdwpTcpClient *client) { struct sockaddr_in addr; /* Infos de connexion distante */ int sock; /* Flux ouvert à construire */ char handshake[15]; /* Poignée de main chaleureuse */ sock = connect_via_tcp(client->server, client->port, &addr); if (sock == -1) { log_variadic_message(LMT_ERROR, _("Error while connecting to the JDWP server at %s:%s."), //printf("Echec de connexion au serveur JDWP sur %s:%s\n", client->server, client->port); return false; } log_variadic_message(LMT_PROCESS, _("Connected to %s:%hd."), client->server, ntohs(addr.sin_port)); if (send(sock, "JDWP-Handshake", 14, 0) != 14) goto gjtcc_error; if (recv(sock, handshake, 14, 0) != 14) goto gjtcc_error; if (strncmp(handshake, "JDWP-Handshake", 14) != 0) goto gjtcc_error; client->fd = sock; return true; gjtcc_error: log_simple_message(LMT_ERROR, _("Failure in the first JDWP handshake.")); close(sock); return false; } /****************************************************************************** * * * Paramètres : client = paramètres de connexion au serveur JDWP. * * * * Description : Attend le signalement de données à traiter. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ static bool g_jdwp_tcp_client_poll(GJdwpTcpClient *client) { bool result; /* Statut à faire remonter */ fd_set rfds; /* Liste des flux à surveiller */ int ret; /* Bilan d'un appel */ result = false; FD_ZERO(&rfds); FD_SET(client->fd, &rfds); ret = select(client->fd + 1, &rfds, NULL, NULL, NULL); switch (ret) { case -1: perror("select()"); break; case 0: /* ?! */ break; default: result = true; break; } return true; } /****************************************************************************** * * * Paramètres : client = flux ouvert en écriture à utiliser. * * packet = zone mémoire à parcourir. * * * * Description : Envoie un paquet de données à un serveur de débogage. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ static bool g_jdwp_tcp_client_send_packet(GJdwpTcpClient *client, const GJdwpPacket *packet) { struct iovec iov[UIO_MAXIOV]; /* Table de vecteurs à écrire */ int iovcnt; /* Quantité de champs valides */ int i; /* Boucle de parcours */ #if 0 jdwp_header *header; /* En-tête à reconstituer */ header = g_jdwp_packet_get_header(packet); printf(" send %p :: %u / %hhu.%hhu (%u)\n", packet, header->id, header->set, header->command, header->length); #endif g_debug_packet_vectorize(G_DEBUG_PACKET(packet), iov, &iovcnt); for (i = 0; i < iovcnt; i++) if (send(client->fd, iov[i].iov_base, iov[i].iov_len, 0) != iov[i].iov_len) return false; return true; } /****************************************************************************** * * * Paramètres : client = flux ouvert en lecture à utiliser. * * packet = zone mémoire à remplir. [OUT] * * * * Description : Réceptionne un paquet de données d'un serveur de débogage. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ static bool g_jdwp_tcp_client_recv_packet(GJdwpTcpClient *client, GJdwpPacket *packet) { bin_t *hblob; /* Contenu encodé en B.E. */ jdwp_header *header; /* En-tête à reconstituer */ uint32_t length; /* Taille de la charge utile */ bin_t *pblob; /* Contenu encodé en B.E. */ hblob = g_jdwp_packet_get_hblob(packet); if (recv(client->fd, hblob, sizeof(jdwp_header), 0) != sizeof(jdwp_header)) return false; if (!g_jdwp_packet_parse_header(packet)) return false; header = g_jdwp_packet_get_header(packet); length = header->length - sizeof(jdwp_header); //printf(" recv %p :: %u / %hu (%u)\n", packet, header->id, header->error, header->length); pblob = g_jdwp_packet_get_pblob(packet); if (recv(client->fd, pblob, length, 0) != length) return false; return true; } /****************************************************************************** * * * Paramètres : client = flux ouvert inutile. * * packet = zone mémoire à libérer. * * * * Description : Libère le contenu alloué d'un paquet de débogage. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_jdwp_tcp_client_free_packet(GJdwpTcpClient *client, GJdwpPacket *packet) { g_jdwp_packet_free_payload(packet); }