|
10 | 10 | import logging
|
11 | 11 | import typing
|
12 | 12 | import copy
|
| 13 | +import re |
13 | 14 |
|
14 | 15 | from ..exceptions import ExecUtilException
|
15 | 16 | from ..exceptions import InvalidOperationException
|
@@ -680,23 +681,45 @@ def get_process_children(self, pid):
|
680 | 681 |
|
681 | 682 | def is_port_free(self, number: int) -> bool:
|
682 | 683 | assert type(number) == int # noqa: E721
|
| 684 | + assert number >= 0 |
| 685 | + assert number <= 65535 # OK? |
683 | 686 |
|
684 |
| - cmd = ["nc", "-w", "5", "-z", "-v", "localhost", str(number)] |
| 687 | + # grep -q returns 0 if a listening socket on that port is found |
| 688 | + port_hex = format(number, '04X') |
685 | 689 |
|
686 |
| - exit_status, output, error = self.exec_command(cmd=cmd, encoding=get_default_encoding(), ignore_errors=True, verbose=True) |
| 690 | + # sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt ... |
| 691 | + # 137: 0A01A8C0:EC08 1DA2A959:01BB 01 00000000:00000000 02:00000000 00000000 ... |
| 692 | + C_REGEXP = r"^\s*[0-9]+:\s*[0-9a-fA-F]{8}:" + re.escape(port_hex) + r"\s+[0-9a-fA-F]{8}:[0-9a-fA-F]{4}\s+" |
687 | 693 |
|
688 |
| - assert type(output) == str # noqa: E721 |
689 |
| - assert type(error) == str # noqa: E721 |
| 694 | + # Search /proc/net/tcp for any entry with this port |
| 695 | + # NOTE: grep requires quote string with regular expression |
| 696 | + # TODO: added a support for tcp/ip v6 |
| 697 | + grep_cmd_s = "grep -q -E \"" + C_REGEXP + "\" /proc/net/tcp" |
| 698 | + |
| 699 | + cmd = [ |
| 700 | + "/bin/bash", |
| 701 | + "-c", |
| 702 | + grep_cmd_s, |
| 703 | + ] |
| 704 | + |
| 705 | + exit_status, output, error = self.exec_command( |
| 706 | + cmd=cmd, |
| 707 | + encoding=get_default_encoding(), |
| 708 | + ignore_errors=True, |
| 709 | + verbose=True |
| 710 | + ) |
690 | 711 |
|
| 712 | + # grep exit 0 -> port is busy |
691 | 713 | if exit_status == 0:
|
692 |
| - return __class__._is_port_free__process_0(error) |
| 714 | + return False |
693 | 715 |
|
| 716 | + # grep exit 1 -> port is free |
694 | 717 | if exit_status == 1:
|
695 |
| - return __class__._is_port_free__process_1(error) |
696 |
| - |
697 |
| - errMsg = "nc returns an unknown result code: {0}".format(exit_status) |
| 718 | + return True |
698 | 719 |
|
699 |
| - RaiseError.CommandExecutionError( |
| 720 | + # any other code is an unexpected error |
| 721 | + errMsg = f"grep returned unexpected exit code: {exit_status}" |
| 722 | + raise RaiseError.CommandExecutionError( |
700 | 723 | cmd=cmd,
|
701 | 724 | exit_code=exit_status,
|
702 | 725 | message=errMsg,
|
@@ -746,12 +769,7 @@ def _is_port_free__process_0(error: str) -> bool:
|
746 | 769 | @staticmethod
|
747 | 770 | def _is_port_free__process_1(error: str) -> bool:
|
748 | 771 | assert type(error) == str # noqa: E721
|
749 |
| - # |
750 |
| - # Example of error text: |
751 |
| - # "nc: connect to localhost (127.0.0.1) port 1024 (tcp) failed: Connection refused\n" |
752 |
| - # |
753 | 772 | # May be here is needed to check error message?
|
754 |
| - # |
755 | 773 | return True
|
756 | 774 |
|
757 | 775 | @staticmethod
|
|
0 commit comments