Correct me if I'm wrong, but my understanding of sending a raw packet inevitably is defined as buffering an array of bytes in an array, and writing it to a socket. However, most example code I've seen so far tend towards sendto, rarely is send used, and I've never seen code other than my own use write. Am I missing something? What is with this apparent preoccupation with complicating code like this?
Why use send and sendto when write seems to me to be the obvious choice when dealing with raw sockets?
sendto is typically used with unconnected UDP sockets or raw sockets. It takes a parameter specifying the destination address/port of the packet. send and write don't have this parameter, so there's no way to tell the data where to go.
send is used with TCP sockets and connected UDP sockets. Since a connection has been established, a destination does not need to be specified, and in fact this function doesn't have a parameter for one.
While the write function can be used in places where send can be used, it lacks the flags parameter which can enable certain behaviors on TCP sockets. It also doesn't return the same set of error codes as send, so if things go wrong you might not get a meaningful error code. In theory you could also use write on a raw socket if the IP_HDRINCL socket option is set, but again it's not preferable since it doesn't support the same error codes as send.
Related
I am writing an application that needs to get access to TCP header fields, for example, a sequence number or a TCP timestamp field.
Is it possible to get sequence numbers (or other header fields) by operating at the socket API without listening on a raw socket? (I want to avoid filtering out all the packets).
I am looking at the TCP_INFO but it has a limited information.
For example, after calling a recvmsg() and getting a data buffer, is it possible to know the sequence number of the segment that delivered the last byte in that received data buffer?
Thanks
You can try to use libpcap to capture packets. This lib allows to specify packet filter using the same syntax as in Wireshark, so you could limit captured packets to one connection only. One downside is that you would have to receive packets in normal way too, what complicated things a bit and is an additional performance overhead.
Update: you can also open raw socket and set Berkeley Packet Filter on it using socket option SO_ATTACH_FILTER. More details are here: https://www.kernel.org/doc/Documentation/networking/filter.txt . However you would have to implement TCP part of IP stack in your code too.
I'm supposed to make a communicator in C, based on dgrams. I don't know what arguments should I pass to bind() function. I skimmed through most UDP-chat questions & codes here on StackOverflow but I still can't find any specific information on the issue.
What type of address structure should I use?
What port can I use? Any number bigger than 1024 ?
What IP adress do I bind my socket with? (most of people put INADDR_ANY but isn't it for receiving only?)
Also, do I need multiple sockets? One for receiving & another for sending messages.
What type of address structure should I use?
If you are using IPv4, use a sockaddr_in. If you want to use IPv6 instead, use a sockaddr_in6.
What port can I use? Any number bigger than 1024 ?
Yes, assuming no other program is already using that port number for its own UDP socket. (If another program is using the port number you chose, it will cause bind() to fail with errno EADDRINUSE)
What IP adress do I bind my socket with? (most of people put
INADDR_ANY but isn't it for receiving only?)
INADDR_ANY is what you generally want to use. It tells the OS that you want to receive incoming UDP packets on any of the computers network interfaces. (If you only wanted to receive UDP packets from a particular network interface, OTOH, e.g. only on WiFi, you could specify that network interface's IP address instead)
Also, do I need multiple sockets? One for receiving & another for
sending messages.
You can have multiple sockets if you want, but it's not necessary to do it that way. You can instead use a single socket for both sending and receiving UDP packets. One common pattern is to use a single socket, set to non-blocking mode, and something like select() or poll() to multiplex the input and output needs of your program. An alternative pattern would be to use two threads (one for sending and one for receiving), blocking I/O, and either one or two sockets (depending on whether you prefer to have the two threads share a socket, or give each thread its own socket). I prefer the single-threaded/single-socket/select() solution myself, as I think it is the least error-prone approach.
I have an application that sends data point to point from a sender to the receiver over an link that can operate in simplex (one way transmission) or duplex modes (two way). In simplex mode, the application sends data using UDP, and in duplex it uses TCP. Since a write on TCP socket may block, we are using Non Blocking IO (ioctl with FIONBIO - O_NONBLOCK and fcntl are not supported on this distribution) and the select() system call to determine when data can be written. NIO is used so that we can abort out of send early after a timeout if needed should network conditions deteriorate. I'd like to use the same basic code to do the sending but instead change between TCP/UDP at a higher abstraction. This works great for TCP.
However I am concerned about how Non Blocking IO works for a UDP socket. I may be reading the man pages incorrectly, but since write() may return indicating fewer bytes sent than requested, does that mean that a client will receive fewer bytes in its datagram? To send a given buffer of data, multiple writes may be needed, which may be the case since I am using non blocking IO. I am concerned that this will translate into multiple UDP datagrams received by the client.
I am fairly new to socket programming so please forgive me if have some misconceptions here. Thank you.
Assuming a correct (not broken) UDP implementation, then each send/sendmsg/sendto will correspond to exactly one whole datagram sent and each recv/recvmsg/recvfrom will correspond to exactly one whole datagram received.
If a UDP message cannot be transmitted in its entirety, you should receive an EMSGSIZE error. A sent message might still fail due to size at some point in the network, in which case it will simply not arrive. But it will not be delivered in pieces (unless the IP stack is severely buggy).
A good rule of thumb is to keep your UDP payload size to at most 1400 bytes. That is very approximate and leaves a lot of room for various forms of tunneling so as to avoid fragmentation.
I want to pass message between two devices, for an example devices are PCs. Currently I am using UDPServer.c and UDPClient.c for reference. By using this reference, I can pass messages, now I want to implement both side listen and send, also I want to create an API for sending message, that API can be used by other functions. May I need to use two different port for sending message and receiving message?? what is the best way to set up UDP socket programming for message passing??
From your description, it doesn't look like you need any more than what sendto()/recvfrom() already do. You might as well treat them as your "API" for message passing. Once you set up/open the socket, just send/recv as needed. You don't need to worry about different ports for sending/receiving; your example is fine. FYI, you can sendto/recvfrom on the same socket.
I am working on a client-server application in C and on Linux platform. What I am trying to achieve is to change the socket id over a TCP connection on both client and server without data loss where in the client sends the data from a file to the server in the main thread. The application is multithreaded where the other threads change the socket id based on some global flags set.
Problem: The application has two TCP socket connections established, over both IPv4 and IPv6 paths. I am transferring a file over the TCP-IPv4 connection first in the main thread. The other thread is checking on some global flags and has access to/share the socket IDs created for each protocol in the main thread. The send and recv use a pointer variable in its call to point to the socket ID to be used for the data transfer. The data is transferred initially over TCP-Ipv4. Once the global flags are set and few other checks are made the other thread changes the socket ID used in send call to point to IPv6 socket. This thread also takes care of communicating the change between the two hosts.I am getting all the data over IPv4 sent completely before switching. Also I am getting data sent over Ipv6 after the socket ID is just switched. But down the transfer there is loss of data over IPv6 connection.(I am using a pointer variable in send function on server side send(*p_dataSocket.socket_id,sentence,p_size,0); to change the pointer to IPv6 socket ID on the fly)
The error after recv and send call on both side respectively is says ESPIPE:Illegal seek, but this error exists even before switching. So I am pretty much sure this is nothing to do with the data loss
I am using pselect() to check for the available data for each socket. I can somehow understand the data loss while switching(if not properly handled) but I am not able to figure out why the data loss is occurring down the transfer after switching. I hope I am clear on what the issue is. I have also checked to send the data individually over each protocol without switching and there is no data loss.It I initially transfer the data over Ipv6 and then switch to IPv4, there is no data loss. Also would really appreciate to know to how to investigate in this issue apart from using errno or netstat.
When you are using TCP to send data you just can't loose a part of the information in between. You either receive the byte stream the way it was sent or receive nothing at all - provided that you are using the socket-related functions correctly.
There are several points you may want to investigate.
First of all you must make sure that you are really sending the data which is lost. Add some logging on the server side application: dump anything that you transmit witn send() into some file. Include some extra info as well, like:
Data packet no.==1234, *p_dataSocket.socket_id==11, Data=="data_contents_here", 22 bytes total; send() return==22
The important thing here is to watch the contents of *p_dataSocket.socket_id. Make sure that you are using mutex or something like that cause you have a thread which regularly reads socket_id contents and another thread which occasionally changes it. You are not guranteed against the getting of a wrong value from that address unless your threads have monopoly access to it while reading/writing. It is important both for normal program operation and for the debugging information generation.
Another possible problem here is the logic which selects sentence to send. Corruption of this variable may be hard to track in multithreaded program. The logging of transmitted information will help you here too.
Use any TCP sniffer to check what TCP stack really transmits. Are there packets with lost data? If there are no those packets, try to find out which send() call was responsible for sending that data. If those packets exist, check the receiving side for bugs.
errno value should not be used alone. Its value has meaning only when you get an erroneous return from a function. Try to find out when exactly errno becomes ESPIPE That may happen when any of API functions return something like -1 (depends on function). When you find out where it happens you should find out what is wrong in that particular piece of code (debugger is your friend). Have in mind that errno behavior in multithreaded environment depends on your system implementation. Make sure that you use -pthread option (gcc) or at least compile with -D_REENTRANT to minimize the risks.
Check this question for some info about the possible cause of your situation with errno==ESPIPE. Try some debuggin techniques, as suggested there. Errno value of ESPIPE gives a hint that you are using file descriptors incorrectly somewhere in your program. Maybe somewhere you are using a socket fd as regular file or something like that. This may be caused by some race condition (simultaneous access to one object from several threads).