<commit_before><?php

namespace Kelunik\Ping;

use Amp\CoroutineResult;
use Amp\Deferred;
use Amp\Dns\Record;
use Amp\Failure;
use Amp\Pause;

class Ping {
    public function ping($host, $sequenceNumber = 1) {
        $fn = function () use ($host, $sequenceNumber) {
            $deferred = new Deferred;
            $start = microtime(1);
            $readBuffer = "";

            $resolved = false;

            $socket = socket_create(AF_INET, SOCK_RAW, getprotobyname("icmp"));

            if (!$socket) {
                $error = socket_last_error();
                yield new CoroutineResult(new Failure(new PingException("Unable to create socket ({$error}): " . socket_strerror($error))));
                return;
            }

            if ($inAddr = @\inet_pton($host)) {
                $isIpv6 = isset($inAddr[15]);
            } else {
                $records = (yield \Amp\Dns\resolve($host));
                list($host, $mode) = $records[0];
                $isIpv6 = $mode === Record::AAAA;
            }

            $package = $this->buildPingRequest($sequenceNumber);

            socket_connect($socket, $isIpv6 ? "[{$host}]" : $host, null);
            socket_set_nonblock($socket);
            socket_send($socket, $package, strlen($package), 0);

            $watcher = \Amp\repeat(function () use ($socket, $start, $deferred, &$readBuffer) {
                $read = socket_read($socket, 255);

                if ($read != "") {
                    list($source) = array_values(unpack("N*", substr($read, 12, 4)));
                    list($dest) = array_values(unpack("N*", substr($read, 16, 4)));

                    $type = ord($read[20]);
                    $code = ord($read[21]);

                    $checksum = substr($read, 22, 2);

                    list($identifier) = array_values(unpack("n*", substr($read, 24, 2)));
                    list($sequence) = array_values(unpack("n*", substr($read, 26, 2)));

                    $data = substr($read, 28);

                    $package = chr($type) . chr($code) . "\0\0" . pack("n", $identifier) . pack("n", $sequence) . $data;
                    $calculatedChecksum = $this->calculateChecksum($package);

                    if ($checksum !== $calculatedChecksum) {
                        $deferred->fail(new PingException("Wrong checksum, got " . bin2hex($checksum) . " but expected " . bin2hex($calculatedChecksum)));
                        return;
                    }

                    if ($type === 8) {
                        return;
                    } else if ($type === 0) {
                        $response = new Response(
                            long2ip($source),
                            long2ip($dest),
                            $sequence,
                            microtime(1) - $start
                        );

                        $deferred->succeed($response);
                    } else if ($type === 3) {
                        $deferred->fail(new PingException("Destination unreachable", $code));
                    } else {
                        $deferred->fail(new PingException("Unexpected response type: " . $type));
                    }
                } elseif (!is_resource($socket) || @feof($socket)) {
                    $deferred->fail(new PingException("Stream closed unexpectedly."));
                }
            }, 50);

            (new Pause(5000))->when(function () use ($watcher, $socket, $deferred, &$resolved) {
                if ($resolved) {
                    return;
                }

                $deferred->fail(new PingException("Timeout, didn't receive a response fast enough."));
            });

            $promise = $deferred->promise();

            $promise->when(function () use ($watcher, $socket, &$resolved) {
                \Amp\cancel($watcher);
                @socket_close($socket);

                $resolved = true;
            });

            yield new CoroutineResult($promise);
            return;
        };

        yield new CoroutineResult(\Amp\resolve($fn()));
    }

    private function buildPingRequest($sequenceNumber) {<commit_msg>Fix Ping::ping<commit_after><?php

namespace Kelunik\Ping;

use Amp\CoroutineResult;
use Amp\Deferred;
use Amp\Dns\Record;
use Amp\Failure;
use Amp\Pause;

class Ping {
    public function ping($host, $sequenceNumber = 1) {
        $fn = function () use ($host, $sequenceNumber) {
            $deferred = new Deferred;
            $start = microtime(1);
            $readBuffer = "";

            $resolved = false;

            $socket = socket_create(AF_INET, SOCK_RAW, getprotobyname("icmp"));

            if (!$socket) {
                $error = socket_last_error();
                yield new CoroutineResult(new Failure(new PingException("Unable to create socket ({$error}): " . socket_strerror($error))));
                return;
            }

            if ($inAddr = @\inet_pton($host)) {
                $isIpv6 = isset($inAddr[15]);
            } else {
                $records = (yield \Amp\Dns\resolve($host));
                list($host, $mode) = $records[0];
                $isIpv6 = $mode === Record::AAAA;
            }

            $package = $this->buildPingRequest($sequenceNumber);

            socket_connect($socket, $isIpv6 ? "[{$host}]" : $host, null);
            socket_set_nonblock($socket);
            socket_send($socket, $package, strlen($package), 0);

            $watcher = \Amp\repeat(function () use ($socket, $start, $deferred, &$readBuffer) {
                $read = socket_read($socket, 255);

                if ($read != "") {
                    list($source) = array_values(unpack("N*", substr($read, 12, 4)));
                    list($dest) = array_values(unpack("N*", substr($read, 16, 4)));

                    $type = ord($read[20]);
                    $code = ord($read[21]);

                    $checksum = substr($read, 22, 2);

                    list($identifier) = array_values(unpack("n*", substr($read, 24, 2)));
                    list($sequence) = array_values(unpack("n*", substr($read, 26, 2)));

                    $data = substr($read, 28);

                    $package = chr($type) . chr($code) . "\0\0" . pack("n", $identifier) . pack("n", $sequence) . $data;
                    $calculatedChecksum = $this->calculateChecksum($package);

                    if ($checksum !== $calculatedChecksum) {
                        $deferred->fail(new PingException("Wrong checksum, got " . bin2hex($checksum) . " but expected " . bin2hex($calculatedChecksum)));
                        return;
                    }

                    if ($type === 8) {
                        return;
                    } else if ($type === 0) {
                        $response = new Response(
                            long2ip($source),
                            long2ip($dest),
                            $sequence,
                            microtime(1) - $start
                        );

                        $deferred->succeed($response);
                    } else if ($type === 3) {
                        $deferred->fail(new PingException("Destination unreachable", $code));
                    } else {
                        $deferred->fail(new PingException("Unexpected response type: " . $type));
                    }
                } elseif (!is_resource($socket) || @feof($socket)) {
                    $deferred->fail(new PingException("Stream closed unexpectedly."));
                }
            }, 50);

            (new Pause(5000))->when(function () use ($watcher, $socket, $deferred, &$resolved) {
                if ($resolved) {
                    return;
                }

                $deferred->fail(new PingException("Timeout, didn't receive a response fast enough."));
            });

            $promise = $deferred->promise();

            $promise->when(function () use ($watcher, $socket, &$resolved) {
                \Amp\cancel($watcher);
                @socket_close($socket);

                $resolved = true;
            });

            yield new CoroutineResult($promise);
            return;
        };

        return \Amp\resolve($fn());
    }

    private function buildPingRequest($sequenceNumber) {
{'fraction_non_alphanumeric': 0.14639449208841648, 'fraction_numerical': 0.011837178403188792, 'mean_word_length': 1.5007550588945937, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 25, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1943099', 'n_tokens_mistral': 2367, 'n_tokens_neox': 2165, 'n_words': 446}