xref: /aosp_15_r20/external/mbedtls/tests/scripts/tcp_client.pl (revision 62c56f9862f102b96d72393aff6076c951fb8148)
1*62c56f98SSadaf Ebrahimi#!/usr/bin/env perl
2*62c56f98SSadaf Ebrahimi
3*62c56f98SSadaf Ebrahimi# A simple TCP client that sends some data and expects a response.
4*62c56f98SSadaf Ebrahimi# Usage: tcp_client.pl HOSTNAME PORT DATA1 RESPONSE1
5*62c56f98SSadaf Ebrahimi#   DATA: hex-encoded data to send to the server
6*62c56f98SSadaf Ebrahimi#   RESPONSE: regexp that must match the server's response
7*62c56f98SSadaf Ebrahimi#
8*62c56f98SSadaf Ebrahimi# Copyright The Mbed TLS Contributors
9*62c56f98SSadaf Ebrahimi# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
10*62c56f98SSadaf Ebrahimi
11*62c56f98SSadaf Ebrahimiuse warnings;
12*62c56f98SSadaf Ebrahimiuse strict;
13*62c56f98SSadaf Ebrahimiuse IO::Socket::INET;
14*62c56f98SSadaf Ebrahimi
15*62c56f98SSadaf Ebrahimi# Pack hex digits into a binary string, ignoring whitespace.
16*62c56f98SSadaf Ebrahimisub parse_hex {
17*62c56f98SSadaf Ebrahimi    my ($hex) = @_;
18*62c56f98SSadaf Ebrahimi    $hex =~ s/\s+//g;
19*62c56f98SSadaf Ebrahimi    return pack('H*', $hex);
20*62c56f98SSadaf Ebrahimi}
21*62c56f98SSadaf Ebrahimi
22*62c56f98SSadaf Ebrahimi## Open a TCP connection to the specified host and port.
23*62c56f98SSadaf Ebrahimisub open_connection {
24*62c56f98SSadaf Ebrahimi    my ($host, $port) = @_;
25*62c56f98SSadaf Ebrahimi    my $socket = IO::Socket::INET->new(PeerAddr => $host,
26*62c56f98SSadaf Ebrahimi                                       PeerPort => $port,
27*62c56f98SSadaf Ebrahimi                                       Proto => 'tcp',
28*62c56f98SSadaf Ebrahimi                                       Timeout => 1);
29*62c56f98SSadaf Ebrahimi    die "Cannot connect to $host:$port: $!" unless $socket;
30*62c56f98SSadaf Ebrahimi    return $socket;
31*62c56f98SSadaf Ebrahimi}
32*62c56f98SSadaf Ebrahimi
33*62c56f98SSadaf Ebrahimi## Close the TCP connection.
34*62c56f98SSadaf Ebrahimisub close_connection {
35*62c56f98SSadaf Ebrahimi    my ($connection) = @_;
36*62c56f98SSadaf Ebrahimi    $connection->shutdown(2);
37*62c56f98SSadaf Ebrahimi    # Ignore shutdown failures (at least for now)
38*62c56f98SSadaf Ebrahimi    return 1;
39*62c56f98SSadaf Ebrahimi}
40*62c56f98SSadaf Ebrahimi
41*62c56f98SSadaf Ebrahimi## Write the given data, expressed as hexadecimal
42*62c56f98SSadaf Ebrahimisub write_data {
43*62c56f98SSadaf Ebrahimi    my ($connection, $hexdata) = @_;
44*62c56f98SSadaf Ebrahimi    my $data = parse_hex($hexdata);
45*62c56f98SSadaf Ebrahimi    my $total_sent = 0;
46*62c56f98SSadaf Ebrahimi    while ($total_sent < length($data)) {
47*62c56f98SSadaf Ebrahimi        my $sent = $connection->send($data, 0);
48*62c56f98SSadaf Ebrahimi        if (!defined $sent) {
49*62c56f98SSadaf Ebrahimi            die "Unable to send data: $!";
50*62c56f98SSadaf Ebrahimi        }
51*62c56f98SSadaf Ebrahimi        $total_sent += $sent;
52*62c56f98SSadaf Ebrahimi    }
53*62c56f98SSadaf Ebrahimi    return 1;
54*62c56f98SSadaf Ebrahimi}
55*62c56f98SSadaf Ebrahimi
56*62c56f98SSadaf Ebrahimi## Read a response and check it against an expected prefix
57*62c56f98SSadaf Ebrahimisub read_response {
58*62c56f98SSadaf Ebrahimi    my ($connection, $expected_hex) = @_;
59*62c56f98SSadaf Ebrahimi    my $expected_data = parse_hex($expected_hex);
60*62c56f98SSadaf Ebrahimi    my $start_offset = 0;
61*62c56f98SSadaf Ebrahimi    while ($start_offset < length($expected_data)) {
62*62c56f98SSadaf Ebrahimi        my $actual_data;
63*62c56f98SSadaf Ebrahimi        my $ok = $connection->recv($actual_data, length($expected_data));
64*62c56f98SSadaf Ebrahimi        if (!defined $ok) {
65*62c56f98SSadaf Ebrahimi            die "Unable to receive data: $!";
66*62c56f98SSadaf Ebrahimi        }
67*62c56f98SSadaf Ebrahimi        if (($actual_data ^ substr($expected_data, $start_offset)) =~ /[^\000]/) {
68*62c56f98SSadaf Ebrahimi            printf STDERR ("Received \\x%02x instead of \\x%02x at offset %d\n",
69*62c56f98SSadaf Ebrahimi                           ord(substr($actual_data, $-[0], 1)),
70*62c56f98SSadaf Ebrahimi                           ord(substr($expected_data, $start_offset + $-[0], 1)),
71*62c56f98SSadaf Ebrahimi                           $start_offset + $-[0]);
72*62c56f98SSadaf Ebrahimi            return 0;
73*62c56f98SSadaf Ebrahimi        }
74*62c56f98SSadaf Ebrahimi        $start_offset += length($actual_data);
75*62c56f98SSadaf Ebrahimi    }
76*62c56f98SSadaf Ebrahimi    return 1;
77*62c56f98SSadaf Ebrahimi}
78*62c56f98SSadaf Ebrahimi
79*62c56f98SSadaf Ebrahimiif (@ARGV != 4) {
80*62c56f98SSadaf Ebrahimi    print STDERR "Usage: $0 HOSTNAME PORT DATA1 RESPONSE1\n";
81*62c56f98SSadaf Ebrahimi    exit(3);
82*62c56f98SSadaf Ebrahimi}
83*62c56f98SSadaf Ebrahimimy ($host, $port, $data1, $response1) = @ARGV;
84*62c56f98SSadaf Ebrahimimy $connection = open_connection($host, $port);
85*62c56f98SSadaf Ebrahimiwrite_data($connection, $data1);
86*62c56f98SSadaf Ebrahimiif (!read_response($connection, $response1)) {
87*62c56f98SSadaf Ebrahimi    exit(1);
88*62c56f98SSadaf Ebrahimi}
89*62c56f98SSadaf Ebrahimiclose_connection($connection);
90