1546 lines
36 KiB
Swift
1546 lines
36 KiB
Swift
//
|
|
// SocketTests.swift
|
|
// BlueSocket
|
|
//
|
|
// Created by Bill Abt on 3/15/16.
|
|
// Copyright © 2016 IBM. All rights reserved.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
//
|
|
|
|
import XCTest
|
|
import Foundation
|
|
import Dispatch
|
|
|
|
#if os(Linux)
|
|
import Glibc
|
|
#endif
|
|
|
|
@testable import Socket
|
|
|
|
class SocketTests: XCTestCase {
|
|
|
|
let QUIT: String = "QUIT"
|
|
let port: Int32 = 1337
|
|
let host: String = "127.0.0.1"
|
|
let path: String = "/tmp/server.test.socket"
|
|
|
|
|
|
override func setUp() {
|
|
|
|
super.setUp()
|
|
}
|
|
|
|
override func tearDown() {
|
|
|
|
super.tearDown()
|
|
}
|
|
|
|
func createHelper(family: Socket.ProtocolFamily = .inet) throws -> Socket {
|
|
|
|
let socket = try Socket.create(family: family)
|
|
XCTAssertNotNil(socket)
|
|
XCTAssertFalse(socket.isConnected)
|
|
XCTAssertTrue(socket.isBlocking)
|
|
|
|
return socket
|
|
}
|
|
|
|
func createUDPHelper(family: Socket.ProtocolFamily = .inet) throws -> Socket {
|
|
|
|
let socket = try Socket.create(family: family, type: .datagram, proto: .udp)
|
|
XCTAssertNotNil(socket)
|
|
XCTAssertFalse(socket.isConnected)
|
|
XCTAssertTrue(socket.isBlocking)
|
|
|
|
return socket
|
|
}
|
|
|
|
func launchServerHelper(family: Socket.ProtocolFamily = .inet) {
|
|
|
|
let queue: DispatchQueue? = DispatchQueue.global(qos: .userInteractive)
|
|
guard let pQueue = queue else {
|
|
|
|
print("Unable to access global interactive QOS queue")
|
|
XCTFail()
|
|
return
|
|
}
|
|
|
|
pQueue.async { [unowned self] in
|
|
|
|
do {
|
|
|
|
try self.serverHelper(family: family)
|
|
|
|
} catch let error {
|
|
|
|
guard let socketError = error as? Socket.Error else {
|
|
|
|
print("Unexpected error...")
|
|
XCTFail()
|
|
return
|
|
}
|
|
|
|
print("launchServerHelper Error reported:\n \(socketError.description)")
|
|
XCTFail()
|
|
}
|
|
}
|
|
}
|
|
|
|
func serverHelper(family: Socket.ProtocolFamily = .inet) throws {
|
|
|
|
var keepRunning: Bool = true
|
|
var listenSocket: Socket? = nil
|
|
|
|
do {
|
|
|
|
try listenSocket = Socket.create(family: family)
|
|
|
|
guard let listener = listenSocket else {
|
|
|
|
print("Unable to unwrap socket...")
|
|
XCTFail()
|
|
return
|
|
}
|
|
|
|
var socket: Socket
|
|
|
|
// Are we setting uo a TCP or UNIX based server?
|
|
if family == .inet || family == .inet6 {
|
|
|
|
// Setting up TCP...
|
|
try listener.listen(on: Int(port), maxBacklogSize: 10)
|
|
|
|
print("Listening on port: \(port)")
|
|
|
|
socket = try listener.acceptClientConnection()
|
|
|
|
print("Accepted connection from: \(socket.remoteHostname) on port \(socket.remotePort), Secure? \(socket.signature!.isSecure)")
|
|
|
|
} else {
|
|
|
|
// Setting up UNIX...
|
|
try listener.listen(on: path, maxBacklogSize: 10)
|
|
|
|
print("Listening on path: \(path)")
|
|
|
|
socket = try listener.acceptClientConnection()
|
|
|
|
print("Accepted connection from: \(socket.remotePath!), Secure? \(socket.signature!.isSecure)")
|
|
|
|
}
|
|
|
|
try socket.write(from: "Hello, type 'QUIT' to end session\n")
|
|
|
|
var bytesRead = 0
|
|
repeat {
|
|
|
|
var readData = Data()
|
|
bytesRead = try socket.read(into: &readData)
|
|
|
|
if bytesRead > 0 {
|
|
|
|
guard let response = NSString(data: readData, encoding: String.Encoding.utf8.rawValue) else {
|
|
|
|
print("Error decoding response...")
|
|
readData.count = 0
|
|
XCTFail()
|
|
break
|
|
}
|
|
|
|
if response.hasPrefix(QUIT) {
|
|
|
|
keepRunning = false
|
|
}
|
|
|
|
// TCP or UNIX?
|
|
if family == .inet || family == .inet6 {
|
|
print("Server received from connection at \(socket.remoteHostname):\(socket.remotePort): \(response) ")
|
|
} else {
|
|
print("Server received from connection at \(socket.remotePath!): \(response) ")
|
|
}
|
|
|
|
let reply = "Server response: \n\(response)\n"
|
|
try socket.write(from: reply)
|
|
|
|
}
|
|
|
|
if bytesRead == 0 {
|
|
|
|
break
|
|
}
|
|
|
|
} while keepRunning
|
|
|
|
socket.close()
|
|
XCTAssertFalse(socket.isActive)
|
|
|
|
} catch let error {
|
|
|
|
guard let socketError = error as? Socket.Error else {
|
|
|
|
print("Unexpected error...")
|
|
XCTFail()
|
|
return
|
|
}
|
|
|
|
// This error is expected when we're shutting it down...
|
|
if socketError.errorCode == Int32(Socket.SOCKET_ERR_WRITE_FAILED) {
|
|
return
|
|
}
|
|
print("serverHelper Error reported: \(socketError.description)")
|
|
XCTFail()
|
|
}
|
|
}
|
|
|
|
func launchUDPHelper(family: Socket.ProtocolFamily = .inet) {
|
|
|
|
let queue: DispatchQueue? = DispatchQueue.global(qos: .userInteractive)
|
|
guard let pQueue = queue else {
|
|
|
|
print("Unable to access global interactive QOS queue")
|
|
XCTFail()
|
|
return
|
|
}
|
|
|
|
pQueue.async { [unowned self] in
|
|
|
|
do {
|
|
|
|
try self.udpHelper(family: family)
|
|
|
|
} catch let error {
|
|
|
|
guard let socketError = error as? Socket.Error else {
|
|
|
|
print("Unexpected error...")
|
|
XCTFail()
|
|
return
|
|
}
|
|
|
|
print("launchUDPHelper Error reported:\n \(socketError.description)")
|
|
XCTFail()
|
|
}
|
|
}
|
|
}
|
|
|
|
func udpHelper(family: Socket.ProtocolFamily) throws {
|
|
|
|
var keepRunning = true
|
|
do {
|
|
let socket = try createUDPHelper()
|
|
try socket.listen(on: Int(port))
|
|
|
|
repeat {
|
|
|
|
var data = Data()
|
|
|
|
let (bytesRead, address) = try socket.readDatagram(into: &data)
|
|
|
|
guard let response = NSString(data: data, encoding: String.Encoding.utf8.rawValue) else {
|
|
|
|
print("Error decoding response...")
|
|
data.count = 0
|
|
XCTFail()
|
|
return
|
|
}
|
|
|
|
if response.hasPrefix(QUIT) {
|
|
keepRunning = false
|
|
}
|
|
|
|
let (remoteHost, remotePort) = Socket.hostnameAndPort(from: address!)!
|
|
print("Received \(bytesRead) bytes from \(remoteHost):\(remotePort): \(response)\n")
|
|
print("Sending response")
|
|
let responseString: String = "Server response: \n\(response)\n"
|
|
try socket.write(from: responseString.data(using: String.Encoding.utf8)!, to: address!)
|
|
|
|
} while keepRunning
|
|
|
|
} catch let error {
|
|
|
|
guard let socketError = error as? Socket.Error else {
|
|
|
|
print("Unexpected error...")
|
|
XCTFail()
|
|
return
|
|
}
|
|
|
|
// This error is expected when we're shutting it down...
|
|
if socketError.errorCode == Int32(Socket.SOCKET_ERR_WRITE_FAILED) {
|
|
return
|
|
}
|
|
print("udpHelper Error reported: \(socketError.description)")
|
|
XCTFail()
|
|
}
|
|
}
|
|
|
|
func readAndPrint(socket: Socket, data: inout Data) throws -> String? {
|
|
|
|
data.count = 0
|
|
let bytesRead = try socket.read(into: &data)
|
|
if bytesRead > 0 {
|
|
|
|
print("Read \(bytesRead) from socket...")
|
|
|
|
guard let response = NSString(data: data as Data, encoding: String.Encoding.utf8.rawValue) else {
|
|
|
|
print("Error accessing received data...")
|
|
XCTFail()
|
|
return nil
|
|
}
|
|
|
|
print("Response:\n\(response)")
|
|
return String(describing: response)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func testDefaultCreate() {
|
|
|
|
do {
|
|
|
|
// Create the socket...
|
|
let socket = try createHelper()
|
|
|
|
// Get the Signature...
|
|
let sig = socket.signature
|
|
XCTAssertNotNil(sig)
|
|
|
|
// Check to ensure the family, type and protocol are correct...
|
|
XCTAssertEqual(sig!.protocolFamily, Socket.ProtocolFamily.inet)
|
|
XCTAssertEqual(sig!.socketType, Socket.SocketType.stream)
|
|
XCTAssertEqual(sig!.proto, Socket.SocketProtocol.tcp)
|
|
|
|
socket.close()
|
|
XCTAssertFalse(socket.isActive)
|
|
|
|
} catch let error {
|
|
|
|
// See if it's a socket error or something else...
|
|
guard let socketError = error as? Socket.Error else {
|
|
|
|
print("Unexpected error...")
|
|
XCTFail()
|
|
return
|
|
}
|
|
|
|
print("testDefaultCreate Error reported: \(socketError.description)")
|
|
XCTFail()
|
|
}
|
|
}
|
|
|
|
func testCreateIPV6() {
|
|
|
|
do {
|
|
|
|
// Create the socket...
|
|
let socket = try createHelper(family: .inet6)
|
|
|
|
// Get the Signature...
|
|
let sig = socket.signature
|
|
XCTAssertNotNil(sig)
|
|
|
|
// Check to ensure the family, type and protocol are correct...
|
|
XCTAssertEqual(sig!.protocolFamily, Socket.ProtocolFamily.inet6)
|
|
XCTAssertEqual(sig!.socketType, Socket.SocketType.stream)
|
|
XCTAssertEqual(sig!.proto, Socket.SocketProtocol.tcp)
|
|
|
|
socket.close()
|
|
XCTAssertFalse(socket.isActive)
|
|
|
|
} catch let error {
|
|
|
|
// See if it's a socket error or something else...
|
|
guard let socketError = error as? Socket.Error else {
|
|
|
|
print("Unexpected error...")
|
|
XCTFail()
|
|
return
|
|
}
|
|
|
|
print("testCreateIPV6 Error reported: \(socketError.description)")
|
|
XCTFail()
|
|
}
|
|
}
|
|
|
|
func testCreateUnix() {
|
|
|
|
do {
|
|
|
|
// Create the socket...
|
|
let socket = try createHelper(family: .unix)
|
|
|
|
// Get the Signature...
|
|
let sig = socket.signature
|
|
XCTAssertNotNil(sig)
|
|
|
|
// Check to ensure the family, type and protocol are correct...
|
|
XCTAssertEqual(sig!.protocolFamily, Socket.ProtocolFamily.unix)
|
|
XCTAssertEqual(sig!.socketType, Socket.SocketType.stream)
|
|
XCTAssertEqual(sig!.proto, Socket.SocketProtocol.unix)
|
|
|
|
socket.close()
|
|
XCTAssertFalse(socket.isActive)
|
|
|
|
} catch let error {
|
|
|
|
// See if it's a socket error or something else...
|
|
guard let socketError = error as? Socket.Error else {
|
|
|
|
print("Unexpected error...")
|
|
XCTFail()
|
|
return
|
|
}
|
|
|
|
print("testCreateUnix Error reported: \(socketError.description)")
|
|
XCTFail()
|
|
}
|
|
}
|
|
|
|
func testCreateUDP() {
|
|
|
|
do {
|
|
|
|
// Create the socket...
|
|
let socket = try createUDPHelper()
|
|
|
|
// Get the Signature...
|
|
let sig = socket.signature
|
|
XCTAssertNotNil(sig)
|
|
|
|
// Check to ensure the family, type and protocol are correct...
|
|
XCTAssertEqual(sig!.protocolFamily, Socket.ProtocolFamily.inet)
|
|
XCTAssertEqual(sig!.socketType, Socket.SocketType.datagram)
|
|
XCTAssertEqual(sig!.proto, Socket.SocketProtocol.udp)
|
|
|
|
socket.close()
|
|
XCTAssertFalse(socket.isActive)
|
|
|
|
} catch let error {
|
|
|
|
// See if it's a socket error or something else...
|
|
guard let socketError = error as? Socket.Error else {
|
|
|
|
print("Unexpected error...")
|
|
XCTFail()
|
|
return
|
|
}
|
|
|
|
print("testCreateUnix Error reported: \(socketError.description)")
|
|
XCTFail()
|
|
}
|
|
}
|
|
|
|
func testListen() {
|
|
|
|
do {
|
|
|
|
// Create the socket..
|
|
let socket = try createHelper()
|
|
|
|
// Listen on the port...
|
|
try socket.listen(on: Int(port), maxBacklogSize: 10)
|
|
XCTAssertTrue(socket.isListening)
|
|
XCTAssertEqual(socket.listeningPort, port)
|
|
|
|
// Close the socket...
|
|
socket.close()
|
|
XCTAssertFalse(socket.isActive)
|
|
|
|
} catch let error {
|
|
|
|
// See if it's a socket error or something else...
|
|
guard let socketError = error as? Socket.Error else {
|
|
|
|
print("Unexpected error...")
|
|
XCTFail()
|
|
return
|
|
}
|
|
|
|
print("testListen Error reported: \(socketError.description)")
|
|
XCTFail()
|
|
}
|
|
}
|
|
|
|
func testListenPort0() {
|
|
|
|
do {
|
|
|
|
// Create the socket..
|
|
let socket = try createHelper()
|
|
|
|
// Listen on the port...
|
|
try socket.listen(on: Int(0), maxBacklogSize: 10)
|
|
XCTAssertTrue(socket.isListening)
|
|
XCTAssertGreaterThan(socket.listeningPort, 0)
|
|
print("Listening port: \(socket.listeningPort)")
|
|
|
|
// Close the socket...
|
|
socket.close()
|
|
XCTAssertFalse(socket.isActive)
|
|
|
|
} catch let error {
|
|
|
|
// See if it's a socket error or something else...
|
|
guard let socketError = error as? Socket.Error else {
|
|
|
|
print("Unexpected error...")
|
|
XCTFail()
|
|
return
|
|
}
|
|
|
|
print("testListenPort0 Error reported: \(socketError.description)")
|
|
XCTFail()
|
|
}
|
|
}
|
|
|
|
func testListenUnix() {
|
|
|
|
do {
|
|
|
|
// Create the socket..
|
|
let socket = try createHelper(family: .unix)
|
|
|
|
// Listen on the port...
|
|
try socket.listen(on: path, maxBacklogSize: 10)
|
|
XCTAssertTrue(socket.isListening)
|
|
XCTAssertEqual(socket.remotePath, path)
|
|
|
|
// Close the socket...
|
|
socket.close()
|
|
XCTAssertFalse(socket.isActive)
|
|
|
|
} catch let error {
|
|
|
|
// See if it's a socket error or something else...
|
|
guard let socketError = error as? Socket.Error else {
|
|
|
|
print("Unexpected error...")
|
|
XCTFail()
|
|
return
|
|
}
|
|
|
|
print("testListenUnix Error reported: \(socketError.description)")
|
|
XCTFail()
|
|
}
|
|
}
|
|
|
|
func testListenUDP() {
|
|
|
|
let queue: DispatchQueue? = DispatchQueue.global(qos: .userInteractive)
|
|
guard let pQueue = queue else {
|
|
|
|
print("Unable to access global interactive QOS queue")
|
|
XCTFail()
|
|
return
|
|
}
|
|
|
|
do {
|
|
|
|
// Create the socket..
|
|
let socket = try createUDPHelper()
|
|
|
|
pQueue.async { [unowned self, socket] in
|
|
|
|
do {
|
|
// Listen on the port...
|
|
var data = Data()
|
|
_ = try socket.listen(forMessage: &data, on: Int(self.port))
|
|
|
|
} catch let error {
|
|
|
|
// See if it's a socket error or something else...
|
|
guard let socketError = error as? Socket.Error else {
|
|
|
|
print("Unexpected error...")
|
|
XCTFail()
|
|
return
|
|
}
|
|
|
|
if socketError.errorCode != Int32(Socket.SOCKET_ERR_RECV_FAILED) {
|
|
print("testListenUDP Error reported: \(socketError.description)")
|
|
XCTFail()
|
|
}
|
|
}
|
|
}
|
|
|
|
// Give the thread time to start...
|
|
#if os(Linux)
|
|
_ = Glibc.sleep(1)
|
|
#else
|
|
_ = Darwin.sleep(1)
|
|
#endif
|
|
|
|
XCTAssertTrue(socket.isListening)
|
|
XCTAssertEqual(socket.listeningPort, port)
|
|
|
|
// Close the socket...
|
|
socket.close()
|
|
XCTAssertFalse(socket.isActive)
|
|
|
|
} catch let error {
|
|
|
|
// See if it's a socket error or something else...
|
|
guard let socketError = error as? Socket.Error else {
|
|
|
|
print("Unexpected error...")
|
|
XCTFail()
|
|
return
|
|
}
|
|
|
|
print("testListenUDP Error reported: \(socketError.description)")
|
|
XCTFail()
|
|
}
|
|
}
|
|
|
|
func testListenPort0UDP() {
|
|
|
|
let queue: DispatchQueue? = DispatchQueue.global(qos: .userInteractive)
|
|
guard let pQueue = queue else {
|
|
|
|
print("Unable to access global interactive QOS queue")
|
|
XCTFail()
|
|
return
|
|
}
|
|
|
|
do {
|
|
|
|
// Create the socket..
|
|
let socket = try createUDPHelper()
|
|
|
|
pQueue.async { [unowned socket] in
|
|
|
|
do {
|
|
// Listen on the port...
|
|
var data = Data()
|
|
_ = try socket.listen(forMessage: &data, on: Int(0))
|
|
|
|
} catch let error {
|
|
|
|
// See if it's a socket error or something else...
|
|
guard let socketError = error as? Socket.Error else {
|
|
|
|
print("Unexpected error...")
|
|
XCTFail()
|
|
return
|
|
}
|
|
|
|
if socketError.errorCode != Int32(Socket.SOCKET_ERR_RECV_FAILED) {
|
|
print("testListenPort0UDP Error reported: \(socketError.description)")
|
|
XCTFail()
|
|
}
|
|
}
|
|
}
|
|
|
|
// Give the thread time to start...
|
|
#if os(Linux)
|
|
_ = Glibc.sleep(1)
|
|
#else
|
|
_ = Darwin.sleep(1)
|
|
#endif
|
|
|
|
XCTAssertTrue(socket.isListening)
|
|
XCTAssertGreaterThan(socket.listeningPort, 0)
|
|
print("Listening port: \(socket.listeningPort)")
|
|
|
|
// Close the socket...
|
|
socket.close()
|
|
XCTAssertFalse(socket.isActive)
|
|
|
|
} catch let error {
|
|
|
|
// See if it's a socket error or something else...
|
|
guard let socketError = error as? Socket.Error else {
|
|
|
|
print("Unexpected error...")
|
|
XCTFail()
|
|
return
|
|
}
|
|
|
|
print("testListenPort0UDP Error reported: \(socketError.description)")
|
|
XCTFail()
|
|
}
|
|
}
|
|
|
|
func testConnect() {
|
|
|
|
do {
|
|
|
|
// Create the socket..
|
|
let socket = try createHelper()
|
|
|
|
// Listen on the port...
|
|
try socket.listen(on: Int(port), maxBacklogSize: 10)
|
|
XCTAssertTrue(socket.isListening)
|
|
XCTAssertEqual(socket.listeningPort, port)
|
|
|
|
// Create a signature...
|
|
let signature = try Socket.Signature(protocolFamily: .inet, socketType: .stream, proto: .tcp, hostname: host, port: port)
|
|
XCTAssertNotNil(signature)
|
|
|
|
// Create a connected socket using the signature...
|
|
let socket2 = try Socket.create(connectedUsing: signature!)
|
|
XCTAssertNotNil(socket2)
|
|
XCTAssertTrue(socket2.isConnected)
|
|
|
|
// Close the socket...
|
|
socket.close()
|
|
XCTAssertFalse(socket.isActive)
|
|
socket2.close()
|
|
XCTAssertFalse(socket2.isActive)
|
|
|
|
} catch let error {
|
|
|
|
// See if it's a socket error or something else...
|
|
guard let socketError = error as? Socket.Error else {
|
|
|
|
print("Unexpected error...")
|
|
XCTFail()
|
|
return
|
|
}
|
|
|
|
print("testConnect Error reported: \(socketError.description)")
|
|
XCTFail()
|
|
}
|
|
}
|
|
|
|
func testConnectTo() {
|
|
|
|
do {
|
|
|
|
// Create the socket..
|
|
let socket = try createHelper()
|
|
|
|
// Listen on the port...
|
|
try socket.listen(on: Int(port), maxBacklogSize: 10)
|
|
XCTAssertTrue(socket.isListening)
|
|
XCTAssertEqual(socket.listeningPort, port)
|
|
|
|
// Create a second socket...
|
|
let socket2 = try createHelper()
|
|
XCTAssertNotNil(socket2)
|
|
|
|
// Now attempt to connect to the listening socket...
|
|
try socket2.connect(to: host, port: port)
|
|
XCTAssertTrue(socket2.isConnected)
|
|
|
|
// Close the socket...
|
|
socket.close()
|
|
XCTAssertFalse(socket.isActive)
|
|
socket2.close()
|
|
XCTAssertFalse(socket2.isActive)
|
|
|
|
} catch let error {
|
|
|
|
// See if it's a socket error or something else...
|
|
guard let socketError = error as? Socket.Error else {
|
|
|
|
print("Unexpected error...")
|
|
XCTFail()
|
|
return
|
|
}
|
|
|
|
print("testConnectTo Error reported: \(socketError.description)")
|
|
XCTFail()
|
|
}
|
|
}
|
|
|
|
func testConnectToWithTimeout() {
|
|
|
|
do {
|
|
|
|
// Create the socket..
|
|
let socket = try createHelper()
|
|
|
|
// Listen on the port...
|
|
try socket.listen(on: Int(port), maxBacklogSize: 10)
|
|
XCTAssertTrue(socket.isListening)
|
|
XCTAssertEqual(socket.listeningPort, port)
|
|
|
|
// Create a second socket...
|
|
let socket2 = try createHelper()
|
|
XCTAssertNotNil(socket2)
|
|
|
|
// Now attempt to connect to the listening socket...
|
|
try socket2.connect(to: host, port: port, timeout: 1)
|
|
XCTAssertTrue(socket2.isConnected)
|
|
|
|
// Close the socket...
|
|
socket.close()
|
|
XCTAssertFalse(socket.isActive)
|
|
socket2.close()
|
|
XCTAssertFalse(socket2.isActive)
|
|
|
|
} catch let error {
|
|
|
|
// See if it's a socket error or something else...
|
|
guard let socketError = error as? Socket.Error else {
|
|
|
|
print("Unexpected error...")
|
|
XCTFail()
|
|
return
|
|
}
|
|
|
|
print("testConnectTo Error reported: \(socketError.description)")
|
|
XCTFail()
|
|
}
|
|
}
|
|
|
|
func testConnectToPath() {
|
|
|
|
do {
|
|
|
|
// Create the socket..
|
|
let socket = try createHelper(family: .unix)
|
|
|
|
// Listen on the port...
|
|
try socket.listen(on: path, maxBacklogSize: 10)
|
|
XCTAssertTrue(socket.isListening)
|
|
|
|
// Create a second socket...
|
|
let socket2 = try createHelper(family: .unix)
|
|
XCTAssertNotNil(socket2)
|
|
|
|
// Now attempt to connect to the listening socket...
|
|
try socket2.connect(to: path)
|
|
XCTAssertTrue(socket2.isConnected)
|
|
|
|
// Close the socket...
|
|
socket.close()
|
|
XCTAssertFalse(socket.isActive)
|
|
socket2.close()
|
|
XCTAssertFalse(socket2.isActive)
|
|
|
|
} catch let error {
|
|
|
|
// See if it's a socket error or something else...
|
|
guard let socketError = error as? Socket.Error else {
|
|
|
|
print("Unexpected error...")
|
|
XCTFail()
|
|
return
|
|
}
|
|
|
|
print("testConnectToPath Error reported: \(socketError.description)")
|
|
XCTFail()
|
|
}
|
|
}
|
|
|
|
func testConnectPort0() {
|
|
|
|
do {
|
|
|
|
// Create the socket..
|
|
let socket = try createHelper()
|
|
|
|
// Listen on the port...
|
|
try socket.listen(on: Int(0), maxBacklogSize: 10)
|
|
XCTAssertTrue(socket.isListening)
|
|
XCTAssertGreaterThan(socket.listeningPort, 0)
|
|
print("Listener signature: \(socket.signature?.description as String?)")
|
|
|
|
// Create a signature...
|
|
let signature = try Socket.Signature(protocolFamily: .inet, socketType: .stream, proto: .tcp, hostname: socket.remoteHostname, port: socket.remotePort)
|
|
XCTAssertNotNil(signature)
|
|
|
|
// Create a connected socket using the signature...
|
|
let socket2 = try Socket.create(connectedUsing: signature!)
|
|
XCTAssertNotNil(socket2)
|
|
XCTAssertTrue(socket2.isConnected)
|
|
print("Connect signature: \(socket2.signature?.description as String?)")
|
|
|
|
// Close the socket...
|
|
socket.close()
|
|
XCTAssertFalse(socket.isActive)
|
|
socket2.close()
|
|
XCTAssertFalse(socket2.isActive)
|
|
|
|
} catch let error {
|
|
|
|
// See if it's a socket error or something else...
|
|
guard let socketError = error as? Socket.Error else {
|
|
|
|
print("Unexpected error...")
|
|
XCTFail()
|
|
return
|
|
}
|
|
|
|
print("testConnectPort0 Error reported: \(socketError.description)")
|
|
XCTFail()
|
|
}
|
|
}
|
|
|
|
func testHostnameAndPort() {
|
|
|
|
do {
|
|
|
|
// Create the socket..
|
|
let socket = try createHelper()
|
|
|
|
// Listen on the port...
|
|
try socket.listen(on: Int(port), maxBacklogSize: 10)
|
|
XCTAssertTrue(socket.isListening)
|
|
XCTAssertEqual(socket.listeningPort, port)
|
|
|
|
// Create a signature...
|
|
let signature = try Socket.Signature(protocolFamily: .inet, socketType: .stream, proto: .tcp, hostname: host, port: port)
|
|
XCTAssertNotNil(signature)
|
|
|
|
// Create a connected socket using the signature...
|
|
let socket2 = try Socket.create(connectedUsing: signature!)
|
|
XCTAssertNotNil(socket2)
|
|
XCTAssertTrue(socket2.isConnected)
|
|
|
|
let address = socket2.signature?.address
|
|
XCTAssertNotNil(address)
|
|
|
|
let (theHost, thePort) = Socket.hostnameAndPort(from: address!)!
|
|
XCTAssertEqual(host, theHost)
|
|
XCTAssertEqual(port, thePort)
|
|
|
|
// Close the socket...
|
|
socket.close()
|
|
XCTAssertFalse(socket.isActive)
|
|
socket2.close()
|
|
XCTAssertFalse(socket2.isActive)
|
|
|
|
} catch let error {
|
|
|
|
// See if it's a socket error or something else...
|
|
guard let socketError = error as? Socket.Error else {
|
|
|
|
print("Unexpected error...")
|
|
XCTFail()
|
|
return
|
|
}
|
|
|
|
print("testHostnameAndPort Error reported: \(socketError.description)")
|
|
XCTFail()
|
|
}
|
|
}
|
|
|
|
func testBlocking() {
|
|
|
|
do {
|
|
|
|
// Create the socket...
|
|
let socket = try createHelper()
|
|
|
|
// Should be blocking...
|
|
XCTAssertTrue(socket.isBlocking)
|
|
|
|
// Set to non-blocking...
|
|
try socket.setBlocking(mode: false)
|
|
XCTAssertFalse(socket.isBlocking)
|
|
|
|
// Now back to blocking...
|
|
try socket.setBlocking(mode: true)
|
|
XCTAssertTrue(socket.isBlocking)
|
|
|
|
// Close the socket...
|
|
socket.close()
|
|
XCTAssertFalse(socket.isActive)
|
|
|
|
} catch let error {
|
|
|
|
// See if it's a socket error or something else...
|
|
guard let socketError = error as? Socket.Error else {
|
|
|
|
print("Unexpected error...")
|
|
XCTFail()
|
|
return
|
|
}
|
|
|
|
print("testBlocking Error reported: \(socketError.description)")
|
|
XCTFail()
|
|
}
|
|
}
|
|
|
|
func testSetReadTimeout() {
|
|
|
|
do {
|
|
|
|
// Create the socket...
|
|
let socket = try createUDPHelper()
|
|
|
|
// Set a timeout of 300 ms...
|
|
try socket.setReadTimeout(value: UInt(300))
|
|
|
|
// Try a read with nobody listening...
|
|
var data: Data = Data()
|
|
let (bytes, addr) = try socket.readDatagram(into: &data)
|
|
XCTAssertEqual(bytes, 0)
|
|
XCTAssertNil(addr)
|
|
XCTAssertEqual(errno, EAGAIN)
|
|
|
|
// Close the socket...
|
|
socket.close()
|
|
XCTAssertFalse(socket.isActive)
|
|
|
|
} catch let error {
|
|
|
|
// See if it's a socket error or something else...
|
|
guard let socketError = error as? Socket.Error else {
|
|
|
|
print("Unexpected error...")
|
|
XCTFail()
|
|
return
|
|
}
|
|
|
|
print("testSetReadTimeout Error reported: \(socketError.description)")
|
|
XCTFail()
|
|
}
|
|
}
|
|
|
|
func testSetWriteTimeout() {
|
|
|
|
do {
|
|
|
|
// Create the socket...
|
|
let socket = try createUDPHelper()
|
|
|
|
// Set a timeout of 300 ms...
|
|
try socket.setWriteTimeout(value: UInt(300))
|
|
|
|
// Try a write to a `bogus` address...
|
|
let addr = Socket.createAddress(for: "foobar.org", on: 2142)
|
|
XCTAssertNotNil(addr)
|
|
|
|
// It should be noted that this write should succeed...
|
|
// If this was a TCP socket, the results would be different...
|
|
let bytesWritten = try socket.write(from: "Hello from UDP".data(using: .utf8)!, to: addr!)
|
|
XCTAssertEqual(bytesWritten, 14)
|
|
|
|
// Close the socket...
|
|
socket.close()
|
|
XCTAssertFalse(socket.isActive)
|
|
|
|
} catch let error {
|
|
|
|
// See if it's a socket error or something else...
|
|
guard let socketError = error as? Socket.Error else {
|
|
|
|
print("Unexpected error...")
|
|
XCTFail()
|
|
return
|
|
}
|
|
|
|
print("testSetWriteTimeout Error reported: \(socketError.description)")
|
|
XCTFail()
|
|
}
|
|
}
|
|
|
|
func testIsReadableWritableFail() {
|
|
|
|
do {
|
|
|
|
// Create the socket...
|
|
let socket = try createHelper()
|
|
|
|
defer {
|
|
// Close the socket...
|
|
socket.close()
|
|
XCTAssertFalse(socket.isActive)
|
|
}
|
|
|
|
// Expect this to fail with Socket.SOCKET_ERR_NOT_CONNECTED exception...
|
|
_ = try socket.isReadableOrWritable()
|
|
XCTFail()
|
|
|
|
} catch let error {
|
|
|
|
// See if it's a socket error or something else...
|
|
guard let socketError = error as? Socket.Error else {
|
|
|
|
print("Unexpected error...")
|
|
XCTFail()
|
|
return
|
|
}
|
|
|
|
print("testIsReadableWritableFail Error reported: \(socketError.description)")
|
|
XCTAssertEqual(socketError.errorCode, Int32(Socket.SOCKET_ERR_NOT_CONNECTED))
|
|
}
|
|
}
|
|
|
|
func testIsReadableWritable() {
|
|
|
|
do {
|
|
|
|
// Create the socket..
|
|
let socket = try createHelper()
|
|
|
|
// Listen on the port...
|
|
try socket.listen(on: Int(port), maxBacklogSize: 10)
|
|
XCTAssertTrue(socket.isListening)
|
|
XCTAssertEqual(socket.listeningPort, port)
|
|
|
|
// Create a second socket...
|
|
let socket2 = try createHelper()
|
|
XCTAssertNotNil(socket2)
|
|
|
|
// Now attempt to connect to the listening socket...
|
|
try socket2.connect(to: host, port: port)
|
|
XCTAssertTrue(socket2.isConnected)
|
|
|
|
// Test to see if it's readable or writable...
|
|
var readable: Bool = false
|
|
var writable: Bool = false
|
|
(readable, writable) = try socket2.isReadableOrWritable()
|
|
print("Socket2 is readable: \(readable), writable: \(writable)")
|
|
|
|
// Socket should be writable but NOT readable...
|
|
XCTAssertTrue(writable, "Socket 2 is not writable but should be...")
|
|
XCTAssertFalse(readable, "Socket 2 is readable and shouldn't be...")
|
|
|
|
// Close the socket...
|
|
socket.close()
|
|
XCTAssertFalse(socket.isActive)
|
|
socket2.close()
|
|
XCTAssertFalse(socket2.isActive)
|
|
|
|
} catch let error {
|
|
|
|
// See if it's a socket error or something else...
|
|
guard let socketError = error as? Socket.Error else {
|
|
|
|
print("Unexpected error...")
|
|
XCTFail()
|
|
return
|
|
}
|
|
|
|
print("testConnectTo Error reported: \(socketError.description)")
|
|
XCTFail()
|
|
}
|
|
}
|
|
|
|
func testFDSetBitFields() {
|
|
var fdSet = fd_set()
|
|
fdSet.zero()
|
|
|
|
// The default number of max open file descriptors on Linux is 1024. On macOS,
|
|
// the default is unlimited. I think checking for 1024 should be enough...
|
|
for i: Int32 in 0...1024 {
|
|
fdSet.set(i)
|
|
XCTAssertTrue(fdSet.isSet(i))
|
|
fdSet.clear(i)
|
|
XCTAssertFalse(fdSet.isSet(i))
|
|
}
|
|
}
|
|
|
|
func testDomainSocketPath() {
|
|
|
|
do {
|
|
let okPath = "111111111111111111111111111111111"
|
|
assert(okPath.utf8.count == 33)
|
|
var sig = try Socket.Signature(socketType: .stream, proto: .unix, path: okPath)
|
|
XCTAssertNotNil(sig)
|
|
|
|
let problematicPath = okPath + "1"
|
|
assert(problematicPath.utf8.count > 33)
|
|
sig = try Socket.Signature(socketType: .stream, proto: .unix, path: problematicPath)
|
|
XCTAssertNotNil(sig)
|
|
|
|
} catch {
|
|
|
|
print("Unexpected error...")
|
|
XCTFail()
|
|
}
|
|
}
|
|
|
|
func testReadWrite() {
|
|
|
|
let hostname = "127.0.0.1"
|
|
let port: Int32 = 1337
|
|
|
|
var data = Data()
|
|
|
|
do {
|
|
|
|
// Launch the server helper...
|
|
launchServerHelper()
|
|
|
|
// Need to wait for the server to come up...
|
|
#if os(Linux)
|
|
_ = Glibc.sleep(2)
|
|
#else
|
|
_ = Darwin.sleep(2)
|
|
#endif
|
|
|
|
// Create the signature...
|
|
let signature = try Socket.Signature(protocolFamily: .inet, socketType: .stream, proto: .tcp, hostname: hostname, port: port)!
|
|
|
|
// Create the socket...
|
|
let socket = try createHelper()
|
|
|
|
// Defer cleanup...
|
|
defer {
|
|
// Close the socket...
|
|
socket.close()
|
|
XCTAssertFalse(socket.isActive)
|
|
}
|
|
|
|
// Connect to the server helper...
|
|
try socket.connect(using: signature)
|
|
if !socket.isConnected {
|
|
|
|
fatalError("Failed to connect to the server...")
|
|
}
|
|
|
|
print("\nConnected to host: \(hostname):\(port)")
|
|
print("\tSocket signature: \(socket.signature!.description)\n")
|
|
|
|
_ = try readAndPrint(socket: socket, data: &data)
|
|
|
|
let hello = "Hello from client..."
|
|
try socket.write(from: hello)
|
|
|
|
print("Wrote '\(hello)' to socket...")
|
|
|
|
let response = try readAndPrint(socket: socket, data: &data)
|
|
|
|
XCTAssertNotNil(response)
|
|
XCTAssertEqual(response, "Server response: \n\(hello)\n")
|
|
|
|
try socket.write(from: "QUIT")
|
|
|
|
print("Sent quit to server...")
|
|
|
|
// Need to wait for the server to go down before continuing...
|
|
#if os(Linux)
|
|
_ = Glibc.sleep(1)
|
|
#else
|
|
_ = Darwin.sleep(1)
|
|
#endif
|
|
|
|
} catch let error {
|
|
|
|
// See if it's a socket error or something else...
|
|
guard let socketError = error as? Socket.Error else {
|
|
|
|
print("Unexpected error...")
|
|
XCTFail()
|
|
return
|
|
}
|
|
|
|
print("testReadWrite Error reported: \(socketError.description)")
|
|
XCTFail()
|
|
}
|
|
|
|
}
|
|
|
|
func testTruncateTCP() {
|
|
|
|
let hostname = "127.0.0.1"
|
|
let port: Int32 = 1337
|
|
|
|
var data = Data()
|
|
|
|
do {
|
|
|
|
// Launch the server helper...
|
|
launchServerHelper()
|
|
|
|
// Need to wait for the server to come up...
|
|
#if os(Linux)
|
|
_ = Glibc.sleep(2)
|
|
#else
|
|
_ = Darwin.sleep(2)
|
|
#endif
|
|
|
|
// Create the signature...
|
|
let signature = try Socket.Signature(protocolFamily: .inet, socketType: .stream, proto: .tcp, hostname: hostname, port: port)!
|
|
|
|
// Create the socket...
|
|
let socket = try createHelper()
|
|
|
|
// Defer cleanup...
|
|
defer {
|
|
// Close the socket...
|
|
socket.close()
|
|
XCTAssertFalse(socket.isActive)
|
|
}
|
|
|
|
// Connect to the server helper...
|
|
try socket.connect(using: signature)
|
|
if !socket.isConnected {
|
|
|
|
fatalError("Failed to connect to the server...")
|
|
}
|
|
|
|
print("\nConnected to host: \(hostname):\(port)")
|
|
print("\tSocket signature: \(socket.signature!.description)\n")
|
|
|
|
_ = try readAndPrint(socket: socket, data: &data)
|
|
|
|
let hello = "Hello from client..."
|
|
try socket.write(from: hello)
|
|
|
|
print("Wrote '\(hello)' to socket...")
|
|
|
|
let buf = UnsafeMutablePointer<CChar>.allocate(capacity: 19)
|
|
#if swift(>=4.1)
|
|
buf.initialize(repeating: 0, count: 19)
|
|
#else
|
|
buf.initialize(to: 0, count: 19)
|
|
#endif
|
|
|
|
defer {
|
|
#if swift(>=4.1)
|
|
buf.deinitialize(count: 19)
|
|
buf.deallocate()
|
|
#else
|
|
buf.deinitialize()
|
|
buf.deallocate(capacity: 19)
|
|
#endif
|
|
}
|
|
|
|
// Save room for a null character...
|
|
_ = try socket.read(into: buf, bufSize: 18, truncate: true)
|
|
let response = String(cString: buf)
|
|
|
|
XCTAssertEqual(response, "Server response: \n")
|
|
|
|
let response2 = try readAndPrint(socket: socket, data: &data)
|
|
|
|
XCTAssertEqual(response2, "\(hello)\n")
|
|
|
|
try socket.write(from: "QUIT")
|
|
|
|
print("Sent quit to server...")
|
|
|
|
// Need to wait for the server to go down before continuing...
|
|
#if os(Linux)
|
|
_ = Glibc.sleep(1)
|
|
#else
|
|
_ = Darwin.sleep(1)
|
|
#endif
|
|
|
|
} catch let error {
|
|
|
|
// See if it's a socket error or something else...
|
|
guard let socketError = error as? Socket.Error else {
|
|
|
|
print("Unexpected error...")
|
|
XCTFail()
|
|
return
|
|
}
|
|
|
|
print("testTruncateTCP Error reported: \(socketError.description)")
|
|
XCTFail()
|
|
}
|
|
|
|
}
|
|
|
|
func testReadWriteUDP() {
|
|
|
|
let hostname = "127.0.0.1"
|
|
let port: Int32 = 1337
|
|
|
|
do {
|
|
|
|
self.launchUDPHelper()
|
|
|
|
// Need to wait for the helper to come up...
|
|
#if os(Linux)
|
|
_ = Glibc.sleep(2)
|
|
#else
|
|
_ = Darwin.sleep(2)
|
|
#endif
|
|
|
|
let socket = try self.createUDPHelper()
|
|
|
|
// Defer cleanup...
|
|
defer {
|
|
// Close the socket...
|
|
socket.close()
|
|
XCTAssertFalse(socket.isActive)
|
|
}
|
|
|
|
let addr = Socket.createAddress(for: hostname, on: port)
|
|
|
|
XCTAssertNotNil(addr)
|
|
try socket.write(from: "Hello from UDP".data(using: .utf8)!, to: addr!)
|
|
|
|
var data = Data()
|
|
var (_, address) = try socket.readDatagram(into: &data)
|
|
|
|
guard let response = NSString(data: data, encoding: String.Encoding.utf8.rawValue) else {
|
|
|
|
print("Error decoding response...")
|
|
data.count = 0
|
|
XCTFail()
|
|
return
|
|
}
|
|
|
|
var (remoteHost, remotePort) = Socket.hostnameAndPort(from: address!)!
|
|
print("Received from \(remoteHost):\(remotePort): \(response)\n")
|
|
|
|
try socket.write(from: "Hello again".data(using: .utf8)!, to: addr!)
|
|
|
|
let buf = UnsafeMutablePointer<CChar>.allocate(capacity: 10)
|
|
#if swift(>=4.1)
|
|
buf.initialize(repeating: 0, count: 10)
|
|
#else
|
|
buf.initialize(to: 0, count: 10)
|
|
#endif
|
|
|
|
defer {
|
|
#if swift(>=4.1)
|
|
buf.deinitialize(count: 10)
|
|
buf.deallocate()
|
|
#else
|
|
buf.deinitialize()
|
|
buf.deallocate(capacity: 10)
|
|
#endif
|
|
}
|
|
|
|
// Save room for a null character...
|
|
(_, address) = try socket.readDatagram(into: buf, bufSize: 9)
|
|
|
|
let response2 = String(cString: buf)
|
|
(remoteHost, remotePort) = Socket.hostnameAndPort(from: address!)!
|
|
print("Received from \(remoteHost):\(remotePort): \(response2)\n")
|
|
|
|
print("Sending quit to server...")
|
|
try socket.write(from: "QUIT".data(using: .utf8)!, to: addr!)
|
|
|
|
// Need to wait for the server to go down before continuing...
|
|
#if os(Linux)
|
|
_ = Glibc.sleep(1)
|
|
#else
|
|
_ = Darwin.sleep(1)
|
|
#endif
|
|
|
|
} catch let error {
|
|
// See if it's a socket error or something else...
|
|
guard let socketError = error as? Socket.Error else {
|
|
|
|
print("Unexpected error...")
|
|
XCTFail()
|
|
return
|
|
}
|
|
|
|
print("testReadWriteUDP Error reported: \(socketError.description)")
|
|
XCTFail()
|
|
}
|
|
}
|
|
|
|
func testReadWriteUnix() {
|
|
|
|
var data = Data()
|
|
|
|
do {
|
|
|
|
// Launch the server helper...
|
|
launchServerHelper(family: .unix)
|
|
|
|
// Need to wait for the server to come up...
|
|
#if os(Linux)
|
|
_ = Glibc.sleep(2)
|
|
#else
|
|
_ = Darwin.sleep(2)
|
|
#endif
|
|
|
|
// Create the signature...
|
|
let signature = try Socket.Signature(socketType: .stream, proto: .unix, path: path)!
|
|
|
|
// Create the socket...
|
|
let socket = try createHelper(family: .unix)
|
|
|
|
// Defer cleanup...
|
|
defer {
|
|
// Close the socket...
|
|
socket.close()
|
|
XCTAssertFalse(socket.isActive)
|
|
}
|
|
|
|
// Connect to the server helper...
|
|
try socket.connect(using: signature)
|
|
if !socket.isConnected {
|
|
|
|
fatalError("Failed to connect to the server...")
|
|
}
|
|
|
|
print("\nConnected to path: \(path)")
|
|
print("\tSocket signature: \(socket.signature!.description)\n")
|
|
|
|
_ = try readAndPrint(socket: socket, data: &data)
|
|
|
|
let hello = "Hello from client..."
|
|
try socket.write(from: hello)
|
|
|
|
print("Wrote '\(hello)' to socket...")
|
|
|
|
let response = try readAndPrint(socket: socket, data: &data)
|
|
|
|
XCTAssertNotNil(response)
|
|
XCTAssertEqual(response!, "Server response: \n\(hello)\n")
|
|
|
|
try socket.write(from: "QUIT")
|
|
|
|
print("Sent quit to server...")
|
|
|
|
// Need to wait for the server to go down before continuing...
|
|
#if os(Linux)
|
|
_ = Glibc.sleep(1)
|
|
#else
|
|
_ = Darwin.sleep(1)
|
|
#endif
|
|
|
|
} catch let error {
|
|
|
|
// See if it's a socket error or something else...
|
|
guard let socketError = error as? Socket.Error else {
|
|
|
|
print("Unexpected error...")
|
|
XCTFail()
|
|
return
|
|
}
|
|
|
|
print("testReadWriteUnix Error reported: \(socketError.description)")
|
|
XCTFail()
|
|
}
|
|
}
|
|
|
|
static var allTests = [
|
|
("testDefaultCreate", testDefaultCreate),
|
|
("testCreateIPV6", testCreateIPV6),
|
|
("testCreateUnix", testCreateUnix),
|
|
("testCreateUDP", testCreateUDP),
|
|
("testListen", testListen),
|
|
("testListenPort0", testListenPort0),
|
|
("testListenUnix", testListenUnix),
|
|
("testListenUDP", testListenUDP),
|
|
("testListenPort0UDP", testListenPort0UDP),
|
|
("testConnect", testConnect),
|
|
("testConnectTo", testConnectTo),
|
|
("testConnectToWithTimeout", testConnectToWithTimeout),
|
|
("testConnectToPath", testConnectToPath),
|
|
("testConnectPort0", testConnectPort0),
|
|
("testHostnameAndPort", testHostnameAndPort),
|
|
("testBlocking", testBlocking),
|
|
("testSetReadTimeout", testSetReadTimeout),
|
|
("testSetWriteTimeout", testSetWriteTimeout),
|
|
("testIsReadableWritableFail", testIsReadableWritableFail),
|
|
("testIsReadableWritable", testIsReadableWritable),
|
|
("testFDSetBitFields", testFDSetBitFields),
|
|
("testDomainSocketPath", testDomainSocketPath),
|
|
("testReadWrite", testReadWrite),
|
|
("testTruncateTCP", testTruncateTCP),
|
|
("testReadWriteUDP", testReadWriteUDP),
|
|
("testReadWriteUnix", testReadWriteUnix),
|
|
]
|
|
}
|