I have a node app that is trying to communicate with a swift application using a unix socket. I am broadcasting a Message ever 3 seconds using the following code with node-ipc:
const ipc = require('node-ipc').default;
// Run IPC server for testing
const first = "FIRST";
const second = "SECOND";
const ipcSocketPath = `/tmp/${ipcAppId}`;
async function setupCoreCommunicationIpc() {
await new Promise((resolve) => {
ipc.serve(ipcSocketPath, () => {
ipc.server.on('ping', (data, socket) => {
ipc.server.emit(socket, 'pong');
});
return resolve(true);
});
ipc.server.start();
});
}
function sendMessage(message, payload = {}) {
ipc.server.broadcast(message, { ...payload, "valueOne": first, "valueTwo": seconds });
}
(async () => {
try {
await setupCoreCommunicationIpc()
} catch (e) {
// Deal with the fact the chain failed
}
// `text` is not available here
})();
setInterval(async () => {
await sendMessage("first:message", {core_id: ipcAppId, app_id: ipcAppId, message_id: 5})
}, 3000);
The code on swift is a bit more complicated. But I am able to connect to the unix socket and receive the message. The Problem is the sending of the AckMessage. I tried different approaches for sending the message but it would not work. Here is the code in swift:
func startSocketStack(valueOne: String, valueTwo: String){
let MTU = 65536
let path = "/tmp/\(valueTwo)"
print("starting socket at: %\(path)%")
let client = socket(AF_UNIX, SOCK_STREAM, 0)
var address = sockaddr_un()
//address.sun_family = UInt8(AF_UNIX)
address.sun_family = sa_family_t(AF_UNIX)
//address.sun_len = UInt8(MemoryLayout<sockaddr_un>.size)
address.sun_len = UInt8(MemoryLayout<UInt8>.size + MemoryLayout<sa_family_t>.size + path.utf8.count + 1)
strlcpy(&address.sun_path.0, path, MemoryLayout.size(ofValue: address.sun_path))
var adressUnwrap = address
withUnsafePointer(to: &adressUnwrap) {
$0.withMemoryRebound(to: sockaddr.self, capacity: 1) {
let connection = connect(client, $0, socklen_t(address.sun_len))
if (connection != 0) {
print("startSocket: could not connect to socket at \(path)")
}
}
}
var buffer = UnsafeMutableRawPointer.allocate(byteCount: MTU,alignment: MemoryLayout<CChar>.size)
while(true) {
let readResult = read(client, &buffer, MTU)
if (readResult == 0) {
break; // end of file
} else if (readResult == -1) {
print("Error reading form client\(client) - \(errno)")
break; // error
} else {
let strResult = withUnsafePointer(to: &buffer) {
$0.withMemoryRebound(to: CChar.self, capacity: MemoryLayout.size(ofValue: readResult)) {
String(cString: $0)
}
}
print("Received form client(\(client)): §\(strResult)§")
print("§\(strResult)§")
let trimmedString = strResult.components(separatedBy: .whitespacesAndNewlines).joined()
print("§\(trimmedString)§")
struct Message: Decodable {
let type: String
let data: MessageData
struct MessageData: Decodable {
var valueOne: String
var valueTwo: String
var message_id: String
}
}
struct AckMessage: Encodable {
let type: String
let data: Bool
}
do {
let jsonMessage = trimmedString.components(separatedBy: "}")[0] + "}" + "}"
let jsonData = jsonMessage.trimmingCharacters(in: CharacterSet.newlines).data(using: .utf8)!
let receivedMessage: Message = try JSONDecoder().decode(Message.self, from: jsonData)
let messageId = receivedMessage.data.message_id
let ackMessage = AckMessage(type: messageId, data: true)
let jsonAckMessage = try JSONEncoder().encode(ackMessage)
let delimiter = #"\f"#.bytes
let jsonAckMessageWithDelimiter = jsonAckMessage + delimiter
print("jsonAckMessageWithDelimiter")
print(jsonAckMessageWithDelimiter)
// first attempt
do {
try jsonAckMessageWithDelimiter.withUnsafeBytes() { [unowned self] (buffer: UnsafeRawBufferPointer) throws -> Int in
let buffer = buffer.baseAddress!
print(buffer)
let bufSize = jsonAckMessageWithDelimiter.count
print(bufSize)
var sent = 0
var sendFlags: Int32 = 0
while sent < bufSize {
var s = 0
s = send(client, buffer.advanced(by: sent), Int(bufSize - sent), sendFlags)
if s <= 0 {
if errno == EAGAIN{
// We have written out as much as we can...
return sent
}
}
sent += s
}
return sent
}
} catch {
print(error)
}
// second attempt
jsonAckMessageWithDelimiter.withUnsafeBytes {
guard let pointer = $0.baseAddress?.assumingMemoryBound(to: UInt8.self) else {
return
}
write(client, pointer, jsonAckMessageWithDelimiter.count)
}
} catch {
print("Error on received message \(error)")
}
}
}
}
In my node application I can not receive the AckMessage because I get the following error:
Messages are large, You may want to consider smaller messages.
Now from my experience from Windows and Linux I know that \f
is the delimiter that should indicate the end of the message. I am sending it at the end of my json but it is somehow not recognized.
What could be the problem? Is the delimiter wrong? Is the buffersize a Problem?
When logging what I send it says that it has sent all 61 bytes as expected.
For anyone having this problem using
"\u{000C}"
instead of"\f"
is the solution.