BlueSocket icon indicating copy to clipboard operation
BlueSocket copied to clipboard

socket.read() freezes when 4096 or multiple of 4096 bytes in socket for readout

Open wojruc opened this issue 6 years ago • 1 comments

Tested on Linux and MacOS and manifests on both.

Below is the reproduction pattern. Just copy/paste to SocketsTests.swift and run tests.

`

    func testReadX4096BytesIssue() {
	
	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)
		
		for count in [4095, 4097, 4096]
		{
			let hello = String(repeating: "a", count: count)
			let bytesWritten = try socket.write(from: hello)
			
			print("Wrote '\(bytesWritten)' bytes 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),
	("testReadWriteUnix", testReadX4096BytesIssue),
]

} `

wojruc avatar Dec 06 '19 12:12 wojruc

Just discovered this issue, too. It is a rather annoying blocker. My solution was to increase the readBufferSize to 5 MB, since none of my packets will be bigger and I am using Unix domain sockets, but it would be much better to use a timeout and let not block the application.

Pegolon avatar Sep 15 '20 13:09 Pegolon