Skip to content

Commit 2a57d0c

Browse files
committed
Add SocketAllocationSpec
1 parent 84d64f9 commit 2a57d0c

File tree

2 files changed

+118
-0
lines changed

2 files changed

+118
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package protocbridge.frontend
2+
import org.scalatest.flatspec.AnyFlatSpec
3+
import org.scalatest.matchers.must.Matchers
4+
5+
import java.lang.management.ManagementFactory
6+
import java.net.ServerSocket
7+
import scala.collection.mutable
8+
import scala.sys.process._
9+
import scala.util.{Failure, Success, Try}
10+
11+
class SocketAllocationSpec extends AnyFlatSpec with Matchers {
12+
it must "allocate an unused port" in {
13+
val repeatCount = 100000
14+
15+
val currentPid = getCurrentPid
16+
val portConflictCount = mutable.Map[Int, Int]()
17+
18+
for (i <- 1 to repeatCount) {
19+
if (i % 100 == 1) println(s"Running iteration $i of $repeatCount")
20+
21+
val serverSocket = new ServerSocket(0) // Bind to any available port.
22+
try {
23+
val port = serverSocket.getLocalPort
24+
Try {
25+
s"lsof -i :$port -t".!!.trim
26+
} match {
27+
case Success(output) =>
28+
if (output.nonEmpty) {
29+
val pids = output.split("\n").filterNot(_ == currentPid.toString)
30+
if (pids.nonEmpty) {
31+
System.err.println("Port conflict detected on port " + port + " with PIDs: " + pids.mkString(", "))
32+
portConflictCount(port) = portConflictCount.getOrElse(port, 0) + 1
33+
}
34+
}
35+
case Failure(_) => // Ignore failure and continue
36+
}
37+
} finally {
38+
serverSocket.close()
39+
}
40+
}
41+
42+
assert(portConflictCount.isEmpty, s"Found the following ports in use out of $repeatCount: $portConflictCount")
43+
}
44+
45+
private def getCurrentPid: Int = {
46+
val jvmName = ManagementFactory.getRuntimeMXBean.getName
47+
val pid = jvmName.split("@")(0)
48+
pid.toInt
49+
}
50+
}

port_conflict.py

+68
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import os
2+
import socket
3+
import subprocess
4+
import sys
5+
6+
def is_port_in_use(port, current_pid):
7+
"""
8+
Check if the given port is in use by other processes, excluding the current process.
9+
10+
:param port: Port number to check
11+
:param pid: Current process ID to exclude from the result
12+
:return: True if the port is in use by another process, False otherwise
13+
"""
14+
try:
15+
# Run lsof command to check if any process is using the port
16+
result = subprocess.run(
17+
['lsof', '-i', f':{port}', '-t'],
18+
stdout=subprocess.PIPE,
19+
stderr=subprocess.PIPE,
20+
text=True
21+
)
22+
output = result.stdout.strip()
23+
24+
if output:
25+
# Check if the output contains lines with processes other than the current one
26+
return [
27+
line
28+
for line in output.split('\n')
29+
if line != str(current_pid)
30+
]
31+
return []
32+
except subprocess.CalledProcessError as e:
33+
print(f"Error checking port: {e}", file=sys.stderr)
34+
return []
35+
36+
def main():
37+
repeat_count = 10000
38+
39+
current_pid = os.getpid() # Get the current process ID
40+
port_conflict_count = {}
41+
42+
for i in range(1, repeat_count + 1):
43+
if i % 100 == 1:
44+
print(f"Running iteration {i} of {repeat_count}")
45+
46+
# Bind to an available port (port 0)
47+
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
48+
sock.bind(('', 0)) # Bind to port 0 to get an available port
49+
port = sock.getsockname()[1] # Get the actual port number assigned
50+
51+
# Check if the port is in use by any other process
52+
pids = is_port_in_use(port, current_pid)
53+
if pids:
54+
print(f"Port conflict detected on port {port} with PIDs: {', '.join(pids)}", file=sys.stderr)
55+
port_conflict_count[port] = port_conflict_count.get(port, 0) + 1
56+
57+
# Close the socket after checking
58+
sock.close()
59+
60+
if port_conflict_count:
61+
print("Ports that were found to be in use and their collision counts:")
62+
for port, count in port_conflict_count.items():
63+
print(f"Port {port} was found in use {count} times")
64+
else:
65+
print("No ports were found to be in use.")
66+
67+
if __name__ == '__main__':
68+
main()

0 commit comments

Comments
 (0)