Difference between Unix domain SOCK_DGRAM and SOCK_SEQPACKET? - c

According to the Linux man pages for Unix sockets, "Valid socket types in the UNIX domain are . . . SOCK_DGRAM, for a datagram-oriented socket that preserves message boundaries (as on most UNIX implementations, UNIX domain datagram sockets are always reliable and don't reorder datagrams); and (since Linux 2.6.4) SOCK_SEQPACKET, for a sequenced-packet socket that is connection-oriented, preserves message boundaries, and delivers messages in the order that they were sent." (http://man7.org/linux/man-pages/man7/unix.7.html).
I thought "always reliable and don't reorder datagrams" is the same as "delivers messages in the order that they were sent."
What's the practical difference between SOCK_DGRAM and SOCK_SEQPACKET?

In the context of UNIX domain sockets, the main difference between two is "datagram-oriented" vs "connection-oriented".
In case of SOCK_DGRAM you don't create a connection (to a server, for example), you just send packets to the server socket. And if server needs to reply, you need to create your own socket, make server aware of this socket and then server can send a reply to it. Very inconvenient, if you really need a connection, but can be useful when you just need one-way communication, i.e. to send some notifies.
SOCK_SEQPACKET is the way to go, when you need connection-oriented approach.

The difference is better understood by the help of UDP and TCP.
A protocol like UDP(connection-less) uses SOCK_DGRAM, implementation
A protocol like TCP(connection-oriented) uses SOCK_STREAM. However, even SOCK_SEQPACKET can be used. The difference between the two is very minimal, TCP can be implemented using the latter as well. In fact, SOCK_SEQPACKET is somewhat a hybrid of both.
STCP is a use case for SOCK_SEQPACKET. Explained in this article: http://urchin.earth.li/~twic/Sequenced_Packets_Over_Ordinary_TCP.html
Here's a post that has discussed this in detail.

Related

difference between send() and sendTo() in C for a UDP network implementation

I'm trying to implement a UDP network between a client and a server but in many implementations, they use either send() or sendTo() I tried looking in the man pages but I didn't really understand the difference other than that the sendTo() takes in more arguments which makes it look rather useless compared to send(). If you could bring any clarity on this matter I would be happy to hear :)
The sendto function is the one that's generally used for UDP sockets. As UDP is connectionless, this function allows you to specify the IP and port that each outgoing packet is sent to.
You can however also use send if you first use connect. The connect function can be used to specify the destination IP and port for all packets sent using send. It also restricts the packets you receive to just those from that IP/port. The connect function may be called multiple times to change the associated remote IP/port, or to remove the association.
In general, I would recommend sticking with sendto as it gives you more flexibility over who you're sending to.

UDP - Multi-server single client

I have a linux computer with a code in C that must communicate in UDP with 4 differents equipments. The computer sends differents commands to each equipment and receives responses, sometimes in parallel ...
I am a perfect beginner, and managed to communicate with one equipment using UDP socket. But now, i'm looking for a way to communicate with all these equipments, what i would like to call "multiple socket", but i don't know where to look/ what word to search to find a way ...
My linux computer is the client and all the equipment servers. I only have one eth port on the computer and will have to use a switch to have access to all the equipment. I would like to create functions like :
sendcmd(IPnumber, PORTnumber, cmd , ...)
readbuff(IPnumber, PORTnumber, buff, ...)
so i can choose which IP will received cmd ... i don't know if it's possible or if i need to open the socket, then close and redo the operation with another IP ...
So, if I ever managed to make myself understood, where should I look for a solution to my problem?
Thank you !
You can use a single UDP socket for your scenario. You can keep the socket open for the lifetime of your application.
UDP is not connection oriented. UDP sockets are also not classified into client sockets and server sockets. UDP sockets are always bound to a local port, either implicitly (typically for pure clients) or explicitly (which is usually the case for servers). In your case you do not care about the port for your UDP client.
To send to your four UDP server you can use sendto(). This lets you specify the destination IP address and port the UDP packet gets sent to.
To receive from your four UDP servers you can use recvfrom(). This will tell the IP address and port where the UDP packet came from.
You most likely want to have a receive loop of some kind. If you want to do anything else in your application you most likely want to either make recvfrom() non-blocking or you want to have the receive loop in its own thread. But this goes beyond your question.
The most important aspect of UDP is that it is not a protocol (despite its name which is misleading). It is one puzzle piece for a protocol. It is a tool to develop your own protocol. But I assume you already have a specific protocol at hand defined by your peripherals.

When using PF_PACKET type of socket, what does PACKET_ADD_MEMBERSHIP?

When using a PF_PACKET type of socket with protocol type ETH_P_IP, the man packet documentation talks about a socket option for multicast. The socket option is PACKET_ADD_MEMBERSHIP.
Assuming you use PACKET_ADD_MEMBERSHIP socket option on a PF_PACKET socket correctly, what features and benefits and use cases is this socket option for?
Right now I receive all incoming IP packets so I look at each packet to see if it has the correct IP dst-address and UDP dst-port and I skip over all the other packets. Would using PACKET_ADD_MEMBERSHIP socket option mean I don't need to do my own filter because the kernel or driver would filter for me?
I dug into the linux-kernel source and traced down the code a little bit. I found that the ethernet-mac-address you pass in via setsockopt() is added to a list of ethernet-mac-addresses. And then the list is sent to the network-device hardware to do something... but I can't find any authoritative documentation telling me what happens next.
My educated guess is that the ethernet-mac-address list is used by the hardware to filter at the layer-2 ethernet protocol (i.e. the hardware only accepts packets that have a destination ethernet-address that matches one on the list). If there is some good documentation I would welcome that.
(I'm more familiar with TCP/UDP sockets and so this looks very similar to AF_INET type of socket's IP_ADD_MEMBERSHIP socket option... so I was expecting IGMP reports to be generated which would start multicast traffic from the router... but I found out experimentally that no IGMP reports are generated when you use this socket option.)
Your guess is correct. PACKET_ADD_MEMBERSHIP should add addresses to the NIC's hardware filter. As you've surmised, it's intended to allow you to receive multicasts for a number of different addresses without incurring the load(*) of full promiscuous mode.
(* With modern full duplex ethernet, there's generally not a lot of traffic coming to the NIC that it wouldn't want to receive anyway, unless it's in a virtualized environment.)
Note that there is also a separate PACKET_MR_UNICAST which does not appear in the packet(7) man page but works analogously. I would use the appropriate one (unicast vs multicast) for the type of address you're filtering on, as it's conceivable (though unlikely) that a driver would refuse to put a unicast address into the multicast filtering table.
All that being said, you'll still need to keep your software filtering as backup. There are some older drivers that don't implement MAC filtering at all (particularly for multiple unicast addresses). The core kernel or the driver handles this by simply turning on promiscuous mode if the feature isn't available.
As for the relationship with IP_ADD_MEMBERSHIP, the IP_ADD_MEMBERSHIP code will automatically construct the appropriate multicast MAC address and add it to the interface. See ip_mc_filter_add.

How to bind a Raw Socket to a specific port?

I am currently working on a programming assignment. The assignment is to implement a client,network emulator, and server. The client passes packets to a network emulator, and the network emulator passes to the server. Vice-versa applies as well. The prerequisite for the assignment is that I may only use raw sockets. So I will create my own IP and UDP headers. I have tested my packets with wireshark. They are all correct and in the proper format(it reads them properly).
Another requirement is that the emulator, client and server all have specific ports they must be bound to. Now, I do not understand how to bind a raw socket to a specific port. All my raw sockets receive all traffic on the host address they are bound to. According to man pages, and everywhere else on the internet, including "Unix Network Programming" by Richard Stevens, this is how they are supposed to work. My teacher has not responded to any of my emails and I probably will not be able to ask him until Tuesday.I see two options in front of me. First I can use libpcap to filter from a specific device and then output to my raw socket. I feel this is way out of scope for our assignment though. Or I can filter them after I receive them from the socket. This apparently has a lot of overhead because all the packets are being copied/moved through the kernel. At least, that is my understanding(please feel free to correct me if i'm wrong).
So my question is:
Is their an option or something I can set for this? Where the raw socket will bind to a port? Have I missed something obvious?
Thank you for your time.
--
The man page for raw(7) says:
A raw socket can be bound to a specific local address using the bind(2) call. If it isn't bound all packets with the specified IP protocol are received. In addition a RAW socket can be bound to a specific network device using SO_BINDTODEVICE; see socket(7).
Edit: You cannot bind a raw socket to a specific port because "port" is a concept in TCP and UDP, not IP. Look at the header diagrams for those three protocols and it should become obvious: you are working at a lower level, where the concept of port is not known.
I would think you're expected to filter the packets in your software. It sounds like the exercise is to learn what the different components of the IP stack do by recreating a simplified piece of it in user space. Normally in the kernel, the IP code would process all packets, verify the IP headers, reassemble fragments, and check the protocol field. If the protocol field is 17 (udp), then it passes it to the UDP code (every UDP packet). It's up to the UDP code to then validate the UDP header and determine if any applications are interested in them based on the destination port.
I imagine your project is expected to more or less mimic this process. Obviously none of it will be as efficient as doing it in the kernel, but since the assignment is to write (part of) an IP stack in user-space, I'd guess efficiency isn't the point of the exercise.

Need to have non-blocking named pipes capable of two way communication in c on Linux

I want to create one server and one client(two separate programs) where in server creates
two named pipes(i guess thats the minimum required for bidirectional flow of traffic) and then
the client is started,and Client and server should be able to send and recieve data both ways
all the time(full duplex types).I think that would require me to have non-blocking named pipes.Would like some help as i have been able to create half duplex type of communication
but struggling to make a contineous seamless transfer of data between client and server happen.
Thanks
Possible options:
Local domain sockets: AF_LOCAL family with SOCK_STREAM, SOCK_DGRAM, SOCK_SEQPACKET type. The socket can be "in-memory", meaning you connect to it using a unique string, or it can be a socket file in the filesystem. It works just like any network socket, full-duplex.
Two pipes: one for reading, one for writing (vice versa for the other process). Might be a bit more complicated keeping track of two pipes, as opposed to the local domain socket.
Helpful link Check out the part on Pipes and the one on Unix Sockets.
Have you considered using select() to handle the reading named pipe?

Resources