[Go back to Index]
TCP state machine diagram allows that TCP client can establish connection with connect() to itself. Focus on Simultaneous Open on that diagram.
Following conditions are mandatory on TCP Client for possibility of such case:
Above two rules doesn't assure of such situation, it is necessary that ephemeral port of TCP Client is actually that port which connects to.
Valid written TCP application should not use the ports within that range, because there is chance it MAY establish unwanted connection to itself.
Depends on OS ephemeral port assigment policy and how TCP client constructs sockets, but probability increases:
/*
* Try establish connection with 127.0.0.1:33333
* THIS IS BAD EXAMPLE because it behaves like infinite loop at various
* conditions
*/
do {
socket = getSockFromSystem(); /* it may use always different ephemeral port */
connectTo(socket, 127.0.0.1, 33333); /* it may connect to itself if ephemeral port == 33333 */
} while(isNotConnected(socket));
/* ... continue with established connection ... */
For the details read article describing them, basically on linux they can be displayed using:
$ cat /proc/sys/net/ipv4/ip_local_port_range
32768 61000
It means that I should not use as TCP Listen port on given machine any port from this range.
Compile as gcc -o tcploop tcploop.c
/* tcploop.c */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <netdb.h>
#include <string.h>
int main(int argc, char *argv[])
{
int port = 0;
int sckfd = 0;
int opt = 1;
struct sockaddr_in *remote;
char *ip = "127.0.0.1";
int rc;
long n = 0;
if(argc != 2){
printf("Usage: %s <listen port>\n", argv[0]);
exit(1);
}
port = atoi(argv[1]);
/* Set to Localhost:Port */
remote = (struct sockaddr_in *)malloc(sizeof(struct sockaddr_in *));
remote->sin_family = AF_INET;
assert(inet_pton(AF_INET, ip, (void *)(&(remote->sin_addr.s_addr))) > 0);
remote->sin_port = htons(port);
/* create socket */
assert((sckfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) > 0);
assert(setsockopt(sckfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) >= 0);
printf("Trying to connect..."); fflush(stdout);
while(1) {
n++;
rc = connect(sckfd, (struct sockaddr *)remote, sizeof(struct sockaddr));
if(rc < 0){
if(n % 1000 == 0) { printf("."); fflush(stdout); }
continue;
}
else {
printf("Connected after %ld tries\n", n);
break;
}
}
/* Wait for Enter */
printf("Press Enter to Continue...\n");
getchar();
close(sckfd);
return 0;
}
Here are three commands output:
lsof output for port 33333$ cat /proc/sys/net/ipv4/ip_local_port_range
32768 61000
$ ./tcploop 33333
Trying to connect..............Connected after 11263 tries
Press Enter to Continue...
$ lsof -n | grep 33333
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
tcploop 3440 dixie 3u IPv4 163396 0t0 TCP 127.0.0.1:33333->127.0.0.1:33333 (ESTABLISHED)