Why does GCDAsyncSocket use readSource in unencrypted mode and readStream in SSL mode - sockets

Recently, when I was looking at GCDAsyncSocket, I noticed a phenomenon: In unencrypted circumstances,GCDAsyncSocket use dispatch_source_t *readSource to receive data ([self registerForStreamCallbacksIncludingReadWrite: NO]), The SSL mode, did not use readSource, switch to the kCFStreamEventHasBytesAvailable ([self registerForStreamCallbacksIncludingReadWrite: YES]).
My question is why use different data receiving methods?

Related

Get data from UNIX socket with Swift on MacOS

I want to use a UNIX socket on Macos using Swift to receive some bytes, nothing serious. But I can't get to
to read any data from the socket.
Why UNIX socket? I wanted to have a "simple IPC". I could use TCP/IP, but now I want to make this work.
I did create a socket using SocketPort
SocketPort(protocolFamily: AF_UNIX, socketType: SOCK_STREAM, protocol: 0, address: data)
I did created an input stream with:
(...)
CFStreamCreatePairWithSocket(kCFAllocatorDefault, port.socket, &readStream, nil)
(...)
self.inputStream = readStream!.takeRetainedValue()
self.inputStream?.delegate = self
self.inputStream?.schedule(in: RunLoop.current, forMode: .default)
self.inputStream?.open()
And after running the app, everything seems fine, even the StreamDelegate protocol function 'stream' is called
back with eventCode for 'openCompleted' after openning the input stream.
Then I send some data with 'socat' but can't get those bytes in the swift app.
I'm using XCode, I added the network entitlements as I read somewhere. But I can't debug the socket. I expected
the 'stream' function to get called once I send some data to the socket.
I read other projects like BlueSocket (I'll give a try later but is not simple to add it to my existing XCode proyect),
they seem to go low-level ( calling Darwin.socket, Darwin.connect...).
I can provide more code. I don't know where to look at. Any clue? advice?
Thanks!
I solved this years ago by writing my own implementation of URLProtocol. I was using it for Docker, so I added a URL scheme of "docker". The code has a lot of dependencies, but here is a a working commit where you should be able to get the basic idea.

Monitor TCP/IP stream

I am interested in learning Vapor, so I decided to work on a website that displays government issued weather alerts. Alert distribution is done via a TCP/IP data stream (streaming1.naad-adna.pelmorex.com port 8080).
What I have in mind is to use IBM's BlueSocket (https://github.com/IBM-Swift/BlueSocket) to create a socket, though after this point, I gave it a bit of thought but was unable to come to a conclusion on what the next steps would be.
Alerts are streamed over the data stream, so I am aware the socket would need to be opened and listened on but wasn't able to get to much past that.
A few things with the data stream are that the start and end of an alert is detected using the start and end tags of the XML document (alert and /alert). There are no special or proprietary headers added to the data, it's only raw XML. I know some alerts also include an XML declaration so I assume the encoding should be taken into account if the declaration is available.
I was then thinking of using XMLParser to parse the XML and use the data I am interested in from the alert.
So really, the main thing I am struggling with is, when the socket is open, what would be the method to listen to it, determine the start and end of the alert and then pass that XML alert for processing.
I would appreciate any input, I am also not restricted to BlueSocket so if there is a better option for what I am trying to achieve, I would be more than open to it.
So really, the main thing I am struggling with is, when the socket is
open, what would be the method to listen to it, determine the start
and end of the alert and then pass that XML alert for processing.
The method that you should use is read(into data: inout Data). It stores any available data that the server has sent into data. There are a few reasons for this method to fail, such as the connection disconnecting.
Here's an example of how to use it:
import Foundation
import Socket
let s = try Socket.create()
try s.connect(to: "streaming1.naad-adna.pelmorex.com", port: 8080)
while true {
if try Socket.wait(for: [s], timeout: 0, waitForever: true) != nil {
var alert = Data()
try s.read(into: &alert)
if let message = String(data: alert, encoding: .ascii) {
print(message)
}
}
}
s.close()
First create the socket. The default is what we want, a IPv4 TCP Stream.
Second connect() to the server using the hostname and port. Without this step, the socket isn't connected and cannot receive or send any data.
wait() until hostname has sent us some data. It returns a list of sockets that have data available to read.
read() the data, decode it and print it. By default this call will block if there is no data available on the socket.
close() the socket. This is good practice.
You might also like to consider thinking about:
non blocking sockets
error handling
streaming (a single call to read() might not give a complete alert).
I hope this answers your question.

UDP proxy, how to maintain/reuse/purge pool of connected clients?

I am creating a UDP-proxy in go, but while doing some load test using iperf, I start to get this error:
socket: too many open files
After searching and testing, I found that if I create a pool using a map of opening connections being the key *net.UDPAddr.String() and the value an instance of UDP-proxy containing an *net.UDPConn, I am available to reuse existing connection in case the client address is the same:
var clients map[string]*UDPProxy.UDPProxy = make(map[string]*UDPProxy.UDPProxy)
This block of code looks something like:
// wait for connections
for {
n, clientAddr, err := conn.ReadFromUDP(buffer)
if err != nil {
log.Println(err)
}
counter++
if *d {
log.Printf("new connection from %s", clientAddr.String())
}
fmt.Printf("Connections: %d, clients: %d\n", counter, len(clients))
proxy, found = clients[clientAddr.String()]
if !found {
// make new connection to remote server
proxy = UDPProxy.New(conn, clientAddr, raddr_udp, *d)
clients[clientAddr.String()] = proxy
}
go proxy.Start(buffer[0:n])
}
This seems to be working, but the problem I have now, is that I need find a way of expiring,cleaning the map when the client exists or is not using any more the proxy so that I could avoid having multiple unused connections.
Any idea how of could I improve this or even better, how could I replace totally the map, I don't know if channels could be help full?
Thanks in advance.
Since you are creating UDP proxies, you probably know that you have to come up with your own solution for deciding when to "terminate" the proxy session. The session is just an abstraction when it comes to UDP - unless the UDPProxy package you're using has an established mechanism already.
Depending on why you are creating UDP proxies, it might be easy to arbitrarily cleanup connections ...
So if you know that a client is exiting, call the Close() method on the proxy (assuming there is one) and use delete on the map entry.
How to decide that a client is exiting is up to you. Could use a slice as a FIFO, or pick one randomly, or try setting timers for each.

Can ZeroMQ be used to accept traditional socket requests?

I'm trying to re-write one of our old Servers using ZeroMQ, for now I have the following Server setup, (which works for Zmq requests):
using (var context = ZmqContext.Create())
using (var server = context.CreateSocket(SocketType.REP)) {
server.Bind("tcp://x.x.x.x:5705");
while (true) { ... }
This kind of setup works fine if I use the Zmq client library to connect context.CreateSocket(SocketType.REQ)
But unfortunately we've got a lot of legacy code that needs to connect to this server and the sockets are created using .net socket libs:
Socket = new Socket(ipAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
Socket.Connect(ipAddress, port);
Is there a way to write a ZeroMQ Server to accept these traditional .net socket connections?
You can achieve this using ZMQ_STREAM sockets.
Please note that since zeroMQ 4.x, the RAW router option has been deprecated for a new ZMQ_STREAM socket type, that works the same way as ROUTER + RAW.
It seems it is bound to evolve, though.
I recently tried ZMQ_STREAM sockets in version 4.0.1.
You can open one, use zmq_rcv until you receive the whole message (you have to check it is whole yourself), or zmq_msg_rcv to let ZeroMQ handle it. You will receive an identifier message part, just like the identifier you would find in ROUTER sockets, directly followed by one ONLY body part. There is no empty delimiter between them like there would be using a REQ Socket talking to a ROUTER Socket. So if you route them, be sure to add it yourself.
Beware though: if there is latency on the other end or if your message exceeds ZeroMQ ZMQ_STREAM buffers (mine are 8192 bytes long), your message can be interpreted by zeroMQ as a series of messages.
In that case, you will receive as many different ZeroMQ messages including both the identifier part and the body part, and it is your job to aggregate them, knowing that if several clients are talking to the STREAM socket, they might get mixed up. I personnally use a hash table using the binary identifier as a key, and delete the entry from the table when I know the message is complete and sent to the next node.
Sending through a ZMQ_STREAM with zmq_msg_send or zmq_send works fine as is.
You probably have to use zmq's RAW socket type (instead of REP) to connect with and read client data without zmq-specific framing.
HTTP Server in C (from Pieter's blog)
http://hintjens.com/blog:42
RAW Socket type info
https://github.com/hintjens/libzmq/commit/777c38ae32a5d1799b3275d38ff8d587c885dd55

iPhone Socket fails after a large number of data transfers

I've got an interesting issue with my socket test application.
I've set up a listening socket with an AcceptCallback function. I've connected to the listening socket using :
CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault,
(CFStringRef) self.clientService.hostName,
self.clientService.port,
&myReadStream,
&myWriteStream);
and I've send data back to the listening socket the myReadStream and myWriteStream, both of which I've cast to their NSStream equivalents.
The problem occurs after sending many separate packets of data. The size of the packets do not matter, it's the number of packets (or the number of CFStreamCreatePairWithSocketToHost creations) that seems to introduce the error.
After I send tons of packets (maybe around 100 or 200), when I try to send data over the NSOutputStream I get an error in the NSStreamEvent callback:
Operation could not be completed. (NSUnknownErrorDomain error 8.)
Then, if I try to create a new service and publish it on the network I get an error when I try to resolve the new address. It gives me an error code of 10 in the NSNetService:didNotResolve delegate method (also, the error description is blank here).
It's almost as if the listening socket is "full" but it seems to think it's functioning fine because when I check CFSocketIsValid it returns true.
I'm stumped and have spent several hours trying to debug the situation... Any thoughts anybody? Thanks.
Alright, I figured out the issue.
When connecting to a socket and initializing a read and write stream, as with the following:
CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault, (CFStringRef) self.clientService.hostName, self.clientService.port, &myInputStream, &myWriteStream);
you need to make sure you set the following variable so that the lower level BSD stream closes when you close the CFStream or NSStream (in my case I cast the CFStream to an NSStream type):
CFReadStreamSetProperty(myReadStream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue);
CFWriteStreamSetProperty(myWriteStream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue);
If you don't set this property the BSD stream never actually closes and you hit some sort of max number of socket connections - not sure exactly what the problem is.