main

mattermost/focalboard

Last updated at: 29/12/2023 09:46

PortUtils.swift

TLDR

This file contains a class called PortUtils that provides methods for checking if a port is free and getting a free port.

Methods

isPortFree

This method takes a port number as input and checks if the port is available for use. It creates a socket file descriptor and sets up a socket address structure. It then attempts to bind the socket to the given port and if successful, it listens on the socket for incoming connections. If any of these steps fail, the socket is released and the method returns false. If all steps are successful, the method returns true.

getFreePort

This method iterates through a range of port numbers from 50000 to 65000 and calls the isPortFree method for each port to check if it is available. It returns the first free port it finds, or 0 if no free port is found.

// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.

import Foundation

class PortUtils {
	static func isPortFree(_ port: in_port_t) -> Bool {
		let socketFileDescriptor = socket(AF_INET, SOCK_STREAM, 0)
		if socketFileDescriptor == -1 {
			return false
		}

		var addr = sockaddr_in()
		let sizeOfSockkAddr = MemoryLayout<sockaddr_in>.size
		addr.sin_len = __uint8_t(sizeOfSockkAddr)
		addr.sin_family = sa_family_t(AF_INET)
		addr.sin_port = Int(OSHostByteOrder()) == OSLittleEndian ? _OSSwapInt16(port) : port
		addr.sin_addr = in_addr(s_addr: inet_addr("127.0.0.1"))
		addr.sin_zero = (0, 0, 0, 0, 0, 0, 0, 0)
		var bind_addr = sockaddr()
		memcpy(&bind_addr, &addr, Int(sizeOfSockkAddr))

		if Darwin.bind(socketFileDescriptor, &bind_addr, socklen_t(sizeOfSockkAddr)) == -1 {
			release(socket: socketFileDescriptor)
			return false
		}
		if listen(socketFileDescriptor, SOMAXCONN ) == -1 {
			release(socket: socketFileDescriptor)
			return false
		}
		release(socket: socketFileDescriptor)
		return true
	}

	private static func release(socket: Int32) {
		Darwin.shutdown(socket, SHUT_RDWR)
		close(socket)
	}

	static func getFreePort() -> in_port_t {
		var portNum: in_port_t = 0
		for i in 50000..<65000 {
			let isFree = isPortFree(in_port_t(i))
			if isFree {
				portNum = in_port_t(i)
				return portNum
			}
		}

		return in_port_t(0)
	}
}