accept() function implementation in Unix - sockets

I have looked up in BSD code but got lost somewhere :(
the reason I want to check is this:
TCP RFC (http://www.ietf.org/rfc/rfc793.txt) sec 2.7 states:
"To provide for unique addresses within each TCP, we concatenate an internet address identifying the TCP with a port identifier to create a socket which will be unique throughout all networks connected together. A connection is fully specified by the pair of sockets at the ends."
Does this mean: socket = local (ip + port) ?
If yes, then the accept function of Unix returns a new socket descriptor. Will it mean that a new socket is created (in turn a new port is created) for responding to client requests?
PS: I am a novice in network programming.
[UPDATE] I understood what I read # How does the socket API accept() function work?.
My only doubt is: if socket = (local port +local ip), then a new socket would mean a new port for the same IP. going by this logic, accept returns a new socket (thus a new port is created). so all sending should occur through this new port.
Is what I understand here correct?

You are mostly correct. When you accept(), a new socket is created and the listening socket stays open to allow more incoming connections but the new socket uses the same local port number as the listening socket.
A connection is defined by a 5-tuple: protocol, local-addr, local-port, remote-addr, remote-port.
Therefore, each accepted connection is unique even though they all share the same local port number because the remote ip/port is always different. The listening socket has no remote ip/port and so is also unique.

Related

Using SO_REUSEPORT to simulate stateful UDP

I am building a p2p application in which every peer can maintain a connection with multiple other peers.
Maintaining a connection is easy with TCP. I have a server listening on a specific port on every node. Whenver peerA wants to connect to peerB, it creates a socket and makes a connect call to the listening port of peerB. This creates a new socket on which both the peers can do all their subsequent conversation on.
I want to simulate the same concept of workflow in UDP. Something similar to this question The traditional way of conversing with multiple peers on UDP from what I found is that every peer is listening on a predefined port. Every sendTo call specifies the ip and port of the peer we want to connect to and on the receiver side, we use recvFrom to handle it based on which peer it is coming from (e.g. passing the msg to a thread which handles messages from that specific peer).
However, I wanted to know if there is any way of doing the same without the need to demultiplex at the receiver. I found the SO_REUSEPORT flag can be used to implement this http://man7.org/linux/man-pages/man7/socket.7.html
https://lwn.net/Articles/542629/.
Basically, SO_REUSEPORT allows multiple sockets call bind on the same port. So, I bind a server port similarly as before. However, when I get a connection from a new peer, I bind a new socket to the same port and call connect on the sender's address. Then I pass this new socket to a thread which listens to messages from the sender.
makeListeningSocket ip port = do
sock <- socket ip port
setSocketOption sock ReusePort 1
bind sock
return sock
runUDPServer sock = do
(receivedMessage, peerAddr) <- recvFrom sock 4096
newSock <- makeListeningSocket "0.0.0.0" 3001
connect newSock peerAddr
async (readMessagesFromSock newSock)
runUDPServer sock
I was able to make this approach work. However, SO_REUSEPORT option doesn't seem to be created with this specific use case in mind. So my question is, is there anything horribly wrong with using SO_REUSEPORT in this manner which I am not able to see? Are there better ways of doing this?

What things are exactly happening when server socket accept client sockets?

I'm studying socket programming, and the server socket accept() is confusing me. I wrote two scenarios for server socket accept(), please take a look:
When the server socket does accept(), it creates a new (client) socket that is bound to a port that is different from the port the server socket is bound. So socket communication is done via newly bound port, and the server socket (for accept() only) is waiting for another client connection on the originally bound port.
I think this is not quite correct, because (1) a port matches to a single process and (2) socket accept is inside-process matter and single process can have multiple sockets. So thought of a second scenario, based on some of stackoverflow answers:
When a server socket does accept(), it creates a new (client) socket that is not bound to any specific port. When a client communicates with the server, it uses the port that is bound to the server socket (who accept()s connections) and which client socket to actually communicate is resolved by (sourceIP, sourcePort, destIP, destPort) tuple from TCP header(?) at Transmission level (this is also suspicious because I thought socket is somewhat of an application-level object)
This scenario also raises some questions. If the socket communications still use server socket's port, i.e. client sends some messages to the server socket port, doesn't it use the server socket's backlog queue? I mean, how can messages from a client be distinguished between connect() and read() or write()? And how can they be resolved to each client socket in the server, without any port binding?
If one of my scenarios is correct, would that answer to the questions following? Or perhaps, both of my scenarios are wrong. I'd be very thankful if you could guide me to correct answers, or at least, towards some relevant texts to study.
When you create a socket and do a bind on that socket and then a listen, what you have is what is called a listening socket.
When a connection is establised this socket is basically cloned to a new socket, and this socket is called the servicing socket the port to which it bound is still the same as the original port.
But there is an important distinction between this socket and the listening socket from before. Namely it is part of a socket pair.
It is the socket pair that uniquely identifies the connection. so as there are 2 sockets in the picture for a socket pair, there are 2 IP adresses and 2 ports for both ends of the TCP communication channel. During the cloning of the servicing socket, the TCP kernel will allocate what is called a TCB and in it it will store those 2 IP# and 2 ports. The TCB also contains the socket number that belongs to the TCB.
Each time a TCP segment comes in , the TCP header is checked and whether or not it is a SYN, for a SYN you would have connection establishment so that you passed already, but then the kernel is going through its list of listening sockets. If it is a normal TCP packet, not a SYN, both port numbers are in the TCP header and the IP# are part of the IP header, so using this information the kernel is able to find the TCP that belongs to this TCP connection. (For a SYN, this information is also there, but as I said, for a SYN you have to process only the listening sockets)
That is in a nutshell how it works.
This information can be found in UNIX Network Programming: the sockets networking API. In there the link to the sockets is described whereas in other reference material it is usually not described that much in detail, rather the nitty grits of TCP are usually highlighted.
When server socket do accept(), it creates a new (client) socket that is bind to port that is different from the port server socket is bind. So socket communication is done via newly bind port, and server socket (for accept() only) is waiting for another client connection on originally bind port.
No.
I think this is not quite proper answer
It is a wrong answer.
because (1) port matches to a single process
That doesn't mean anything relevant.
and (2) socket accept is inside-process matters
Nor does that. It doesn't appear to mean anything at all actually.
and single process can have multiple sockets.
That's true but it doesn't have any bearing on why your answer is wrong. The reason your answer is wrong is because no second port is used.
When server socket do accept(), it creates a new (client) socket that is not bind to any specific port
No. It creates a second socket that inherits everything from the server socket: port number, buffer sizes, socket options, ... everything except the file descriptor and the LISTENING state, and maybe I forgot something else. It then sets the remote IP:port of the socket to that of the client and puts the socket into ESTABLISHED state.
and when client communicates with the server
The client has already communicated with the server. That's why we are creating this socket.
it uses the port that is bind to server socket (who accept()s connections) and which client socket to actually communicate is resolved by (sourceIP, sourcePort, destIP, destPort) tuple from TCP header(?) at Transmission level
This has already happened.
This is also suspicious because I thought socket is somewhat application-level object)
No it isn't. A socket is a kernel-level object with an application-level file descriptor to identity it.
If the socket communications still use server socket's port, i.e. client sends some messages to server socket port, doesn't it uses server socket's backlog queue?
No. The backlog queue is for incoming connect requests, not for data. Incoming data goes into the socket receive buffer.
I mean, how can messages from client be distinguished between connect() and read() or write()?
Because a connect() request sets special bits in the TCP header. The final part of it can be combined with data.
And how can they be resolved to each client sockets in server, WITHOUT any port binding?
Port binding happens the moment the socket is created in the call to accept(). You invented this difficulty yourself. It isn't real.
If one of my scenario is correct, would answer to the questions following?
Neither of them is correct.
Or possibly I'm making two wrong scenarios, so it would be very thankful for you to provide right answers, or at least some relevant texts to study.
Surely you already have relevant texts to study? If you don't, you should read RFC 793 or W.R. Stevens, TCP/IP Illustrated, volume I, relevant chapters. You have several major misunderstandings here.
From the Linux programmer's manual, as found via man 2 accept. Link
The accept() system call is used with connection-based socket
types (SOCK_STREAM, SOCK_SEQPACKET). It extracts the first connection
request on the queue of pending connections for the listening socket,
sockfd, creates a new connected socket, and returns a new file
descriptor referring to that socket. The newly created socket is not
in the listening state. The original socket sockfd is unaffected by
this call.
So what happens is that you have a listening TCP socket. Someone requests to connect().
You then call accept(). The old listening socket remains in listening mode, while a new socket is created in connected mode. Port is the original listening port.
That does not interfere with the listening socket, because the new socket does not listen for incoming connections.

socket programming - why web server still using listen port 80 to communicate with client even after they accepted the connection?

Usually a web server is listening to any incoming connection through port 80. So, my question is that shouldn't it be that in general concept of socket programming is that port 80 is for listen for incoming connection. But then after the server accepted the connection, it will use another port e.g port 12345 to communicate with the client. But, when I look into the wireshark, the server is always using port 80 during the communication. I am confused here.
So what if https://www.facebook.com:443, it has hundreds of thousands of connection to the it at a second. Is it possible for a single port to handle such a large amount of traffic?
A particular socket is uniquely identified by a 5-tuple (i.e. a list of 5 particular properties.) Those properties are:
Source IP Address
Destination IP Address
Source Port Number
Destination Port Number
Transport Protocol (usually TCP or UDP)
These parameters must be unique for sockets that are open at the same time. Where you're probably getting confused here is what happens on the client side vs. what happens on the server side in TCP. Regardless of the application protocol in question (HTTP, FTP, SMTP, whatever,) TCP behaves the same way.
When you open a socket on the client side, it will select a random high-number port for the new outgoing connection. This is required, otherwise you would be unable to open two separate sockets on the same computer to the same server. Since it's entirely reasonable to want to do that (and it's very common in the case of web servers, such as having stackoverflow.com open in two separate tabs) and the 5-tuple for each socket must be unique, a random high-number port is used as the source port. However, each of those sockets will connect to port 80 at stackoverflow.com's webserver.
On the server side of things, stackoverflow.com can already distinguish between those two different sockets from your client, again, because they already have different client-side port numbers. When it sees an incoming request packet from your browser, it knows which of the sockets it has open with you to respond to because of the different source port number. Similarly, when it wants to send a response packet to you, it can send it to the correct endpoint on your side by setting the destination port number to the client-side port number it got the request from.
The bottom line is that it's unnecessary for each client connection to have a separate port number on the server's side because the server can already uniquely identify each client connection by its client IP address and client-side port number. This is the way TCP (and UDP) sockets work regardless of application-layer protocol.
shouldn't it be that in general concept of socket programming is that port 80 is for listen for incoming connection. But then after the server accepted the connection, it will use another port e.g port 12345 to communicate with the client.
No.
But, when I look into the wireshark, the server is always using port 80 during the communication.
Yes.
I am confused here.
Only because your 'general concept' isn't correct. An accepted socket uses the same local port as the listening socket.
So what if https://www.facebook.com:443, it has hundreds of thousands of connection to the it at a second. Is it possible for a single port to handle such a large amount of traffic?
A port is only a number. It isn't a physical thing. It isn't handling anything. TCP is identifying connections based on the tuple {source IP, source port, target IP, target port}. There's no problem as long as the entire tuple is unique.
Ports are a virtual concept, not a hardware ressource, it's no harder to handle 10 000 connection on 1 port than 1 connection each on 10 000 port (it's probably much faster even)
Not all servers are web servers listening on port 80, nor do all servers maintain lasting connections. Web servers in particular are stateless.
Your suggestion to open a new port for further communication is exactly what happens when using the FTP protocol, but as you have seen this is not necessary.
Ports are not a physical concept, they exist in a standardised form to allow multiple servers to be reachable on the same host without specialised multiplexing software. Such software does still exist, but for entirely different reasons (see: sshttp). What you see as a response from the server on port 80, the server sees as a reply to you on a not-so-random port the OS assigned your connection.
When a server listening socket accepts a TCP request in the first time ,the function such as Socket java.net.ServerSocket.accept() will return a new communication socket whoes port number is the same as the port from java.net.ServerSocket.ServerSocket(int port).
Here are the screen shots.

Sockets TCP server

I have a question about network connection
for instance, A TCP Server support N connections simultaneously, each connection belongs other client host.The question is how many sockets the server needs?
Thanks
I think this is a valid question and do not understand why it has been downvoted.
Before I continue, an important distinction must be made. A socket is a file descriptor, while the port is an "identifier" for a socket. File descriptors/socket are owned by applications, so a port can be viewed as a way to route connections/packets to the correct application.
The way for example a web server works (or any other TCP-based server), is that you have a listen socket that is bound to a port (for example 80). When a client connects to the server, a new socket is automatically created by the operating system (this socket is the one that is returned by for example accept()). This socket is bound to the same local IP and port as the listen socket, but has a different remote IP/port. The operating system stores this mapping and routes packets belonging to this mapping to the new socket.
So the answer to your question is that only one listen socket is needed, but new sockets will be created as clients connect (and removed as they disconnect). The limit of sockets (file descriptors) than an application can create is controlled by the OS.

sockets, its attributes and SO_REUSEADDR option

i have a few basic questions:
1.A socket is represented by a protocol, a local ip, local port, remote ip and remote port. Suppose such a connection exists between a client and a server. Now when i bind another client to same local port and ip, it got bound(i used SO_REUSEADDR) but connect operation by second client to the same remote ip and port failed.So, is there no way a third process can share the same socket?
2.When we call listen() on a socket bound to a local port and ip, it listens for connections. When a client connects, it creates a socket (say A). It completes 3 way handshake and then starts a different socket(say B) and also deletes the socket A (Source) .The new client is taken care of by the new socket B. So, what kind of a socket represents a listening socket i.e. what is the remote ip and port and is socket A different than that socket or just addition of remote ip and port to listening socket forms A?
3.I read that SO_REUSEADDR can establish a listening socket on a port if there is no socket listening on that port and ip and all sockets on that port and ip have SO_REUSEADDR option set.But then i also came across a text which said if a client is bound to a port and ip, another client can't bind to it(even if SO_REUSEADDR is used) unless the first client successfully calls connect(). There was no listening socket(it is a client so we there is no call to connect()) on that port and ip in this example. So, why isn't another client allowed?
Thanks in advance.
Correct: there is no way to create two different sockets with the same protocol, local port, local address, remote port, and remote address. There would be nothing to tell which packets belonged to which socket!
A listening socket does not have a remote address and remote port. That's OK, because there are no packets on the wire associated with this socket (yet). Actually, all sockets start out with neither a local nor remote address or port. These properties are only assigned later when bind() (for local) and connect()/accept() (for remote) are called.
Until you call connect() or listen() on a socket, there isn't any different between a server (listening) or client socket. They're the same thing. So it would be more correct here to say that no two sockets are allowed to share the same protocol, local address, and local port if neither has a remote address or port.
This isn't a problem in practice though, because you usually don't call bind() on a client socket, which means there is an implicit bind() to an ephemeral port at connect() time. These typical client sockets can't conflict with a listening socket because they go from having no addresses associated with them to having both local and remote addresses associated with them, skipping the state where they have only a local one.