IPV6 connection to IPV4 TOS option - ios

could you help me?
So problem is QOS On IPV6 socket when it connect to IPV4 server
I can't set transport options on package
self.socket = socket(PF_INET6, SOCK_DGRAM, 0); // Create UDP Socket
int on = 1;
setsockopt(self.socket, SOL_SOCKET, SO_NOSIGPIPE, (void *)&on, sizeof(int));
int off = 0;
setsockopt(self.socket, IPPROTO_IPV6, IPV6_V6ONLY, (void *)(&off), sizeof(off)); // Disable IPV6 Only
int option = 46;
// set QOS option
setsockopt(self.socket, IPPROTO_IP, IP_TOS, (void *)(&option),sizeof(option)); // IPV4
setsockopt(self.socket, IPPROTO_IPV6, IPV6_TCLASS, (void *)(&option),sizeof(option)); //IPV6
But when i see packages to IPV4 DSCP is 0
Server send me correct DSCP

It seems like your kernel doesn't implement the mapping of IPv6 TCLASS to IPv4 DSCP.
The V6ONLY=0 option is mostly a hack to allow servers to accept both IPv4 and IPv6 connections on a single socket. I'm not surprised that only the bare minimum of options is implemented.
Your best option is probably to contact the kernel developers to see if they want to implement the mapping...

Related

How To Disable Nagle on iOS POSIX Socket

I'll start by saying that I definitely want to disable Nagle's Algorithm. The application that I am testing for is a real time P2P app in which packets are small and extremely time sensitive. This test also serves to compare UDP and TCP for possible networking solutions.
I am able to open the TCP socket and send messages back and forth, but I have not been able to disable Nagle's Algorithm. I have tried:
static const int yes = 1;
if (setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, &yes, sizeof(yes))) {
fprintf(stderr, "Error setting tcp nodelay\n");
return -2;
}
on both the listening and connecting sockets. This does not fail. I also elevated the priority of the receiving thread to DISPATCH_QUEUE_PRIORITY_HIGH.
The test I am running starts with a packet that contains "start", followed by numerous packets that contain "data" and one final packet containing "stop". These packets are almost always combined into one or few packets, such as:
Received Peer Message: startdatadatadatadatadatadatastop
or
Received Peer Message: startdatadatadata
Received Peer Message: datadatadatastop
Is there a difference in the way that TCP_NODELAY is set on iOS? I was able to set it on Linux with the above code successfully.

kCFSocketAcceptCallBack not being called for WIFI connection with static IP

I will try to be as detailed as I can. I am trying to connect to an acquisition unit from my iPhone in my app. We are using IP4 and the acquisition unit doesn't support DHCP so its always scanning for device with a specific static IP and port no.
Before I tested the connection between the unit and my iPhone, I created an adhoc network using my desktop and try it out with my iPhone. This is part of my code.
CFSocketContext CTX = { 0, description, NULL, NULL, NULL };
/* Create the server socket as a TCP IPv4 socket and set a callback */
/* for calls to the socket's lower-level accept() function */
TCPServer = CFSocketCreate(NULL, PF_INET, SOCK_STREAM, IPPROTO_TCP,
kCFSocketAcceptCallBack
, (CFSocketCallBack)WiFiCallBack, &CTX);
/* Set the port and address we want to listen on */
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_len = sizeof(addr);
addr.sin_family = AF_INET;
addr.sin_port = htons(PORT);
addr.sin_addr.s_addr = htonl(INADDR_ANY);
CFDataRef addressData = CFDataCreate( NULL, (UInt8*)(&addr), sizeof( struct sockaddr_in ) );
CFSocketSetAddress(TCPServer, addressData);
It works and I can do data transfer between my desktop and iPhone if I feed in the IP that was assigned to iPhone to the PC app on my desktop. However if I set a static IP for iPhone and try to get the PC app to connect to any device with that IP it doesn't work.
Same goes with my acquisition unit. The call back function is not called at all.
I am in desperate need of help so any form of help is welcomed. Thanks.
I'm sorry, but your post is not very clear.
Are you are trying to establish a server socket on the iPhone, and connect to it from elsewhere?
This is going to be problematic for many reasons.
First is that your ip is not going to be the same. When connected to WIFI, you will have an ip that is routable at least on the current network.
But when connected to 3g (or lte, etc), you will likely not be able to route to the ip given at all.
Even if you did have a fully routable ip address on some interface that existed long enough, iOS is not designed for this. Your application will not be able to run efficiently in the background and listen to a server socket. You can simulate this with persistent sockets and voip background mode. However that requires a separate server component.
You could also try polling from the iPhone, that may satisfy your requirements.

How to send data immediately in epoll ET mode when connect established

My server needs to send data when client connects to it. I am using Epoll ET mode.
But how to do it? Could any one give me a simple example for me?
Assuming you are listening on your socket (socket, bind, listen), and have added it's descriptor to epoll (epoll_create and epoll_ctl), then epoll_wait will tell you when there is a new connection to accept.
First you accept the connection (sockfd is descriptor of socket you're listening on, efd is epoll instance) and add it to your epoll instance:
int connfd = accept4(sockfd, NULL, 0, SOCK_NONBLOCK);
struct epoll_event ev;
ev.events = EPOLLOUT | EPOLLET;
ev.data.fd = connfd;
epoll_ctl(efd, EPOLL_CTL_ADD, connfd, &ev)
Then you go back to your main loop and call epoll_wait again. It will tell you when the socket is ready for writing, and you just happily write or sendfile away.
Add lots of error checking, and probably TCP_CORK and you're done. There's a working example on github.com/grahamking/netshare/.
I hope this gives you enough information to get started.

iOS - Getting CFReadStream/CFWriteStream from a socket

I'm trying to add some simple peer-to-peer connection functionality to an iOS library. Coding for outgoing connections was simple enough; a call to CFStreamCreatePairWithSocketToHost connects to a remote host and sets up streams for reading/writing from/to it. Simple enough.
However, I couldn't find an equivalently easy way to set up a socket to listen for/accept incoming connections. So I went back to basics and used socket(), bind(), listen(), and accept() to implement low-level connection handling, patterned largely after the example here:
http://www.pcs.cnu.edu/~dgame/sockets/server.c
That's all fine, but now that I'm able to accept incoming connections I'm wondering how to go about creating CFReadStream and CFWriteStream instances to manage them. Is there a straightforward way of doing so?
As an aside, I'm aware that a CocoaAsyncSocket library exists that supports asynchronous server sockets, but I'm really not interested in an async solution.
Okay, turns out that the answer was actually fairly simple. You can use:
void CFStreamCreatePairWithSocket (
CFAllocatorRef alloc,
CFSocketNativeHandle sock,
CFReadStreamRef *readStream,
CFWriteStreamRef *writeStream
);
...to bind a CFReadStream and CFWriteStream to an already connected socket. That flow seems a little backwards to me (i.e. what if bytes have already been read from the socket, etc., and why isn't it possible to just bind something to the listening/server socket such that every time a new connection is accepted corresponding CFReadStream and CFWriteStream instances are automatically set up?), but whatever.
The code goes like:
int connectedSocketId = accept(socketId, (struct sockaddr *)&clientSocket, &addrlen);
if (connectedSocketId != -1) {
//successful connection
CFReadStreamRef clientInput = NULL;
CFWriteStreamRef clientOutput = NULL;
CFStreamCreatePairWithSocket(kCFAllocatorDefault, connectedSocketId, &clientInput, &clientOutput);
if (clientInput && clientOutput) {
CFReadStreamSetProperty(clientInput, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue);
CFWriteStreamSetProperty(clientOutput, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue);
if (! CFReadStreamOpen(clientInput) || ! CFWriteStreamOpen(clientOutput)) {
NSLog(#"Could not initialize streams!");
}
else {
//use the streams
}
}
}
So the important things to realize were:
It's not necessary to bind anything to the socket you are listening on; instead it's possible to bind CFReadStream and CFWriteStream instances arbitrarily to any already connected socket, even if you've already read/written data from/to it.
For all its fancy verboseness, a CFSocketNativeHandle is just an int. Oh how I loathe unnecessary aliasing of primitive types to things that sound like they aren't primitive types.

Non blocking connect to loopback address (127.0.0.1 or localhost)

When I do a non blocking connect to the loopback address from the iOS Simulator (which probably uses the same TCP stack as the Mac and FreeBSD), I see that connect always succeeds, even when the server process isn't running.
I detect that connect succeeded by using select() with zero timeout. So, as long as select() returns 0, I assume that the connection is in progress, if it returns -1 I fail with an error and if it returns 1, the socket is ready for reading (as the server must have responded), and I begin reading after reporting that the connect succeeded.
This works well for all addresses except the loopback. On the loopback select() always returns 1, even when there is no server running. So, I begin reading, which fails and I handle it. But I should have detected this through select()!
You are getting the error before that, right on connect().
Before going to proceed with select(), check that errno is EINPROGRESS and not something else. In *BSD, connections to a non-listening port on a localhost error out (or may error out) immediately.
I just ran a very simple test like this (headers skipped):
int
main(void)
{
int fd;
int r;
struct sockaddr_in remote;
struct hostent *he;
he = gethostbyname("localhost");
if (he == NULL)
return -1;
memcpy(&remote.sin_addr, he->h_addr, sizeof(remote.sin_addr));
remote.sin_port = htons(9671);
remote.sin_family = AF_INET;
fd = socket(PF_INET, SOCK_STREAM, 0);
fcntl(fd, F_SETFL, O_NONBLOCK);
r = connect(fd, (struct sockaddr *)&remote, sizeof remote);
if (r < 0) {
perror("connect");
}
return 0;
}
With nothing listening on port 9671, I got:
on Linux: connect: Operation now in progress
on FreeBSD: connect: Connection refused
Of course, it is always a good idea to check the error codes of all syscalls (something the example above does not do for simplicity's sake - it's just an illustration, after all).
The problem was that I was relying on select() to tell me if the connect was successful. Select only tells you if something changed on that fd. I should've actually called connect() again on the socket and verify that the if it fails, errno is either EINPROGRESS, ECONN or EALREADY. Except for ECONN, all the other values mean that we should retry; ECONN means it's already connected. Any other errno value means we failed to connect.

Resources