blob: 6e576d63f74718d1e4276e7f891cc9c3c6f7b4ba [file] [log] [blame]
Gilles Peskined50177f2017-05-16 17:53:03 +02001#!/usr/bin/env perl
2
3# A simple TCP client that sends some data and expects a response.
4# Usage: tcp_client.pl HOSTNAME PORT DATA1 RESPONSE1
5# DATA: hex-encoded data to send to the server
6# RESPONSE: regexp that must match the server's response
Bence Szépkúti700ee442020-05-26 00:33:31 +02007#
8# Copyright (C) 2017, Arm Limited, All Rights Reserved
Bence Szépkútic7da1fe2020-05-26 01:54:15 +02009# SPDX-License-Identifier: Apache-2.0
10#
11# Licensed under the Apache License, Version 2.0 (the "License"); you may
12# not use this file except in compliance with the License.
13# You may obtain a copy of the License at
14#
15# http://www.apache.org/licenses/LICENSE-2.0
16#
17# Unless required by applicable law or agreed to in writing, software
18# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
19# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20# See the License for the specific language governing permissions and
21# limitations under the License.
Bence Szépkúti700ee442020-05-26 00:33:31 +020022#
23# This file is part of Mbed TLS (https://tls.mbed.org)
Gilles Peskined50177f2017-05-16 17:53:03 +020024
25use warnings;
26use strict;
27use IO::Socket::INET;
28
29# Pack hex digits into a binary string, ignoring whitespace.
30sub parse_hex {
31 my ($hex) = @_;
32 $hex =~ s/\s+//g;
33 return pack('H*', $hex);
34}
35
36## Open a TCP connection to the specified host and port.
37sub open_connection {
38 my ($host, $port) = @_;
39 my $socket = IO::Socket::INET->new(PeerAddr => $host,
40 PeerPort => $port,
41 Proto => 'tcp',
42 Timeout => 1);
43 die "Cannot connect to $host:$port: $!" unless $socket;
44 return $socket;
45}
46
47## Close the TCP connection.
48sub close_connection {
49 my ($connection) = @_;
50 $connection->shutdown(2);
51 # Ignore shutdown failures (at least for now)
52 return 1;
53}
54
55## Write the given data, expressed as hexadecimal
56sub write_data {
57 my ($connection, $hexdata) = @_;
58 my $data = parse_hex($hexdata);
59 my $total_sent = 0;
60 while ($total_sent < length($data)) {
61 my $sent = $connection->send($data, 0);
62 if (!defined $sent) {
63 die "Unable to send data: $!";
64 }
65 $total_sent += $sent;
66 }
67 return 1;
68}
69
70## Read a response and check it against an expected prefix
71sub read_response {
72 my ($connection, $expected_hex) = @_;
73 my $expected_data = parse_hex($expected_hex);
74 my $start_offset = 0;
75 while ($start_offset < length($expected_data)) {
76 my $actual_data;
77 my $ok = $connection->recv($actual_data, length($expected_data));
78 if (!defined $ok) {
79 die "Unable to receive data: $!";
80 }
81 if (($actual_data ^ substr($expected_data, $start_offset)) =~ /[^\000]/) {
82 printf STDERR ("Received \\x%02x instead of \\x%02x at offset %d\n",
83 ord(substr($actual_data, $-[0], 1)),
84 ord(substr($expected_data, $start_offset + $-[0], 1)),
85 $start_offset + $-[0]);
86 return 0;
87 }
88 $start_offset += length($actual_data);
89 }
90 return 1;
91}
92
93if (@ARGV != 4) {
94 print STDERR "Usage: $0 HOSTNAME PORT DATA1 RESPONSE1\n";
95 exit(3);
96}
97my ($host, $port, $data1, $response1) = @ARGV;
98my $connection = open_connection($host, $port);
99write_data($connection, $data1);
100if (!read_response($connection, $response1)) {
101 exit(1);
102}
103close_connection($connection);