简体   繁体   中英

Strange Linux socket protocols behaviour

I'm a little confused about the difference between the definitions of protocols on Linux when using socket() . I am attempting to listen for connections over TCP using socket(PF_INET, SOCK_STREAM, proto) , where proto is (in my mind) disputed, or at least seems odd.

From <netinet/in.h> :

...
IPPROTO_IP = 0,    /* Dummy protocol for TCP.  */
...
IPPROTO_TCP = 6,       /* Transmission Control Protocol.  */
...

Agreed with by /etc/protocols :

ip      0       IP              # internet protocol, pseudo protocol number
hopopt  0       HOPOPT          # hop-by-hop options for ipv6
...
tcp     6       TCP             # transmission control protocol
...

I learned from an online tutorial, and also from the man page tcp(7) that you initialise a TCP socket using

tcp_socket = socket(AF_INET, SOCK_STREAM, 0);

which works absolutely fine, and certainly is a TCP socket. One thing about using the above arguments to initialise a socket is that the code

struct timeval timeout = {1, 0};
setsockopt(tcp_socket, 0, SO_RCVTIMEO, &timeout, sizeof(timeout); // 1s timeout
// Exactly the same for SO_SNDTIMEO here

works absolutely fine, but not after replacing all protocol arguments (including in socket() ) with IPPROTO_TCP , as opposed to IPPROTO_IP which they have, as above.

So after experimenting with the difference, I've needed to ask a few searching questions:

  1. Why, when I replace all protocol arguments with IPPROTO_TCP , do I get error 92 ("Protocol not available") when setting timeouts, when protocol 0 is apparently just a 'dummy' TCP?
  2. Why does socket() require the information of whether it should be a stream, datagram or raw socket when that information is (always?) implicitly known from the protocol, and vice versa? (ie TCP is a stream protocol, UDP is a datagram protocol, ...)
  3. What could be meant by "dummy TCP"?
  4. What is hopopt , and why does it have the same protocol number as 'ip'?

Many thanks.

Giving 0 as protocol to socket just means that you want to use the default protocol for the family/socktype pair. In this case that is TCP, and thus you get the same result as with IPPROTO_TCP .

Your error is in the setsockopt call. The correct one would be

setsockopt(tcp_socket, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)); // 1s timeout

the 0 there is not for protocol, but for option level. IPPROTO_TCP is another option level, but you can't combine that with SO_RCVTIMEO . It can only be used together with SOL_SOCKET . The ones you use with IPPROTO_TCP are the ones listed in tcp(7), eg TCP_NODELAY .

socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); should work fine.

Passing 0 as the protocol just means, give me the default. Which on every system is TCP for stream sockets and UDP for datagram sockets, when dealing with IP. But socket() can be used for many other things bar giving you a TCP or UDP socket.

socket() is quite general in nature. socket(AF_INET, SOCK_STREAM, 0); just reads as; "give me a streaming socket within the IP protocol family". Passing 0 means you have no preferences over which protocol - though TCP is the obvious choice for any system. But theoretically, it could have given you eg an SCTP socket.

Whether you want datagram or streaming sockets is not implicit for protocols. There are many more protocols bar IP based protocols, and many can be used in either datagram or streaming mode such as SCCP used in SS7 networks.

For IP based protocols, SCTP can be used in a datagram based, or streaming fashion. Thus socket(AF_INET,IPPROTO_SCTP); would be ambiguous. And for datagram sockets, there's other choices as well, UDP, DCCP, UDPlite.

socket(AF_INET,SOCK_SEQPACKET,0); is another interesting choice. It cannot return a TCP socket, TCP is not packet based. It cannot return and UDP socket, UDP gives no guarantee of sequential delivery. But an SCTP socket would do, if the system supports it.

I have no explanation for why someone made the comment "dummy TCP" in that the linux netinet/in.h

hopopt is the IPv6 HOP by hop option. In IPv6, the protocol discriminator field is also used as an extension mechanism. In IPv4 packets there is a protocol field which is the protocol discriminator, it'll be set to IPPROTO_TCP if that IPv4 datagram carries TCP. If that IPv4 packet also carries some additional info(options), they are coded by other mechanisms.

IPv6 does this differently, if there is an extension(option), that extension is coded in the protocol field. So if the IPv6 packet needs the hop-by-hop option, IPPROTO_HOPOPTS is placed in the protocol field. The actual hop-by-hop option also have a protocol discriminator, which signals what the next protocol is - which might be IPPROTO_TCP, or yet another option.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM