How to implement socket connect() when the server is not running? - c

The following TCP/IP client code works as expected if the server is running before I call this function. If the server is not running, connect() returns immediately and prints errno = 111, connection refused. I ended up placing the call to connect() in an infinite while-loop with a 1-second delay between calls. When the server is up, the code connects and exits the loop. Q: Is this how connect() in blocking mode supposed to work? If so, is there a way to configure connect() to wait until the server is running before returning?
int socket_connect(const char *host, int port, int timeout)
{
struct sockaddr_in sa;
struct hostent *hp;
int sockfd = -1;
hp = gethostbyname(host);
if (hp == NULL)
{
return -1;
}
sa.sin_family = AF_INET;
sa.sin_port = htons(port);
sockfd = socket(AF_INET, SOCK_STREAM, 0);
int status = connect(sockfd, (struct sockaddr *)&sa, sizeof(sa));
if (status != 0)
{
close(sockfd);
printf("errno = %d\n",errno);
return -2;
}
...

connect has a single task - establish a connection to a (remote) server socket. This server socket is expected to exist for this, i.e. the server application holding this socket is expected to be running. And the server system is expected to be reachable. connect is just doing internally the TCP handshake, i.e. it sends a SYN packet and wait for the SYN+ACK for the server.
If the server application is running and listening on the server socket and if the server system is reachable (i.e. no connectivity loss or firewall blocking connection) then the server system will respond quickly with SYN+ACK and connect will succeed in a short time.
If the server application is not running or not (yet) listening on the server socket, then the server system will explicitly reject the connection attempt - resulting in connect returning with "connection refused". This is also the case if there is a firewall explicitly rejecting the connection or if the server is running out of resources, like if the listen queue for the server socket is full.
If instead there is a loss of connectivity or if there is a firewall which will block connections attempts by simply dropping the packets before they reach the server system, then connect will internally try to reach the server by repeatedly retrying sending the SYN to get a response back. After a while connect will give up and consider the connection attempt failed with "timed out".

Related

AF_UNIX socket server write to itself in C

Can a socket server created with socket(AF_UNIX, SOCK_STREAM, 0) write to itself?
I'm asking this becouse the first send is ignored if it was from the same server to the same server, but if it a client is the one who sent it then it not ignored.
why does that happen and how to not ignore the first send from server?

connect() to external IP not working

I'm writing a simple server/client program in C. I'm trying to open a port on an IP that can be accessed from anywhere. Currently, my server does not work for anything but 127.0.0.1 (local machine) and 0.0.0.0 (I don't know). I've specified the IP_TRANSPARENT option and all that but the client still fails at connect.
server:
// definitions, everything
struct addrinfo hints, *res;
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
getaddrinfo("192.168.1.1","4001",&hints,&res);
sockfd = socket(res->ai_family,res->ai_socktype,res->ai_protocol);
setsockopt(sockfd,IPPROTO_IP,IP_TRANSPARENT,(void*)&sockopt,sizeof(sockopt));
bind(sockfd,res->ai_addr,res->ai_addrlen);
listen(sockfd,0);
addr_size = sizeof(ext_addr);
extfd = accept(sockfd,(struct sockaddr *)&ext_addr,&addr_size);
write(extfd,"Success",7);
// cleanup
client:
// definitions, everything
struct sockaddr_in serv_addr;
sockfd = socket(AF_INET,SOCK_STREAM,0);
setsockopt(sockfd,IPPROTO_IP,IP_TRANSPARENT,(void*)&sockopt,sizeof(sockopt));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(4001);
inet_pton(AF_INET,"192.168.1.1",&serv_addr.sin_addr);
connect(sockfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr)); // fails here
read(sockfd,rcvBuf,sizeof(rcvBuf)-1);
// clean up
What's my issue? I have taken out the error checking for the sake of convenience. The server runs fine, I am sure of that. The client runs fine with 127.0.0.1.
Typically, you cannot bind() to an IP that does not belong to the local machine. However, per the IP_TRANSPARENT documentation:
IP_TRANSPARENT (since Linux 2.6.24)
Setting this boolean option enables transparent proxying on this socket. This socket option allows the calling application to bind to a nonlocal IP address and operate both as a client and a server with the foreign address as the local endpoint. NOTE: this requires that routing be set up in a way that packets going to the foreign address are routed through the TProxy box (i.e., the system hosting the application that employs the IP_TRANSPARENT socket option). Enabling this socket option requires superuser privileges (the CAP_NET_ADMIN capability).
TProxy redirection with the iptables TPROXY target also requires that this option be set on the redirected socket.
Have you configured the necessary proxying on your network to facilitate IP_TRANSPARENT?
Let's ignore IP_TRANSPARENT for a moment, pretend it does not exist, as it is not commonly used.
127.0.0.1 is the IPv4 loopback address. If you bind your server to this, only local IPv4 clients that connect to 127.0.0.1 will be able to connect.
0.0.0.0 is an IPv4 wildcard address. If you bind your server to this, the socket will listen on all local IPv4 addresses. Any client on the local machine or network can connect to any IPv4 address that belongs to the server machine.
192.168.1.1 is a specific IPv4 address. If you bind your server to this, the socket will listen on that IPv4 address only. Any client on the local machine or network can connect to only that IPv4 address.
If your client and server are on the same machine, the client can connect to any local IP that the server is bound to.
If your client and server are not on the same machine, bur are on the same network, the client can connect to the server if the server is bound to an IP that is accessible to that network. That means binding to 0.0.0.0 or 192.168.1.1, and then connecting to 192.168.1.1.
If your client and server are not on the same network, the client can connect to the server only if the server is behind a router with a public IP. The server must be bound to a local network IP that is accessible to the router, and the router must be configured to forward inbound connections on a given port on its public IP to the server's internal IP. That means binding the server to 0.0.0.0 or 192.168.1.1, forwarding connections to the server's internal IP, and then connecting to the router's public IP.

Bsd socket how can I find server port number for connection?

I have a server:
./server portNumber
I have a client:
./client serverIpAddress
I have only server Ip Address in the client. I want to connect to Server socket. But every time Server Port Number is different. How Can I connect to server socket with BSD Socket in the client? Is it impossible? Do I have to know server port number?
Simple Usage BSD Socket:
int socket_desc;
struct sockaddr_in server;
//Create socket
socket_desc = socket(AF_INET , SOCK_STREAM , 0);
if (socket_desc == -1)
{
printf("Could not create socket");
}
server.sin_addr.s_addr = inet_addr(ipAddress);
server.sin_family = AF_INET;
server.sin_port = htons( ThisIsServerPortNumber );
//Connect to remote server
if (connect(socket_desc , (struct sockaddr *)&server , sizeof(server)) < 0)
{
puts("connect error");
return 1;
}
Pick a port number between 49152 and 65535 for development. If your idea is successful, you'll want to register a port number between 1024 and 49151. Port numbers from 0 to 1023 are well-known ports, e.g. port 80 is for HTTP servers.
The TCP Port Service Multiplexer protocol was intended to allow discovery of port numbers for TCP servers, but it's seldom used due to security concerns.
The bind(2) system call is used to select a port number in a server. It has to be called before the listen(2) system call and after the socket(2) call.
It allows to specify, not only the port number the server is going to listen for connections, but also the ip address in case the host has several interfaces and you want only to accept connections in one of the interfaces.
But every time Server Port Number is different. How Can I connect to
server socket with BSD Socket in the client? … Do I have to know
server port number?
Yes, you have to know it. Think: There can be many different server programs running on the server host, bound to many different ports. A client computer has no simple insight into the server host to see to which port the desired server program is bound. Thus, it is usual to use a preassigned port number in the server as well as in the client.

FTP clients cannot talk to TCP server I have implemented

I'm implementing my own TCP server. So far I can make a connection, that works fine, I can connect to any client. However when I want to send or receive messages from the client it goes wrong. The following is a snippet of the last part of my server, where I want to send the message WeLcOmE to my client (I'm using C programming language & Linux as the OS):
// Accept a connection request
int clientAddress = sizeof(client_address);
int new_socket = accept(door_socket, (struct sockaddr *) &client_address,
&clientAddress);
if (new_socket < 0)
perror("ERROR on accept");
// Receive data from socket, send data to socket
char buff[8] = "WeLcOmE";
send(new_socket, buff, sizeof(buff), 0);
// Close socket
close(new_socket);
close(door_socket);
return 0;
Running my server with a Filezilla Client this is what I get:
Status: Resolving address of ubuntu
Status: Connecting to 127.0.1.1:3471...
Status: Connection established, waiting for welcome message...
Response: WeLcOmE
Error: Could not connect to server
Status: Waiting to retry...
Status: Resolving address of ubuntu
Status: Connecting to 127.0.1.1:3471...
Status: Connection attempt failed with "ECONNREFUSED - Connection
refused by server".
Error: Could not connect to server
Running my server with the ftp Linux built-in client I get:
ftp> WeLcOmE421 service not available remote server has closed connection
I don't understand why is this happening. Any help is appreciated.
As you have yourself stated, you have implemented a "TCP" server. All the server does is that it sends the "WeLcOmE" string to any TCP client that connects to the server.
If you connect with an FTP client to the server, the client gets the "WeLcOmE" string, and as that does not conform to the FTP protocol specification, the client errors.
The same would happen, if you connect with any other client that uses a specific protocol, e.g. a web browser [HTTP], a terminal client [SSH or Telnet], etc.
Now the question is, what you are trying to achieve:
Either you want to implement an FTP server. For that you need to read the FTP specification and implement your server according to it. That's an immense task and in general you do not want to do that. You better take an existing implementation. Either an FTP server library and build your custom FTP server on it. Or take a complete open source FTP server and customize it to your needs.
Or you just play with your toy TCP server and you want to test it. For that use any TCP client that can work in "raw" mode by reading from the socket and just displaying what it gets, without trying to interpret the data in any way. You can use PuTTY in a "raw" connection mode. See section Making raw TCP connections in PuTTY documentation.

how to assign a local port number to a socket?

I create a server at port 1234 of localhost. In the client code, I initiated a struct sockaddr_in server_addr and filled it with the server's IP address and port number. When I try to connect a client to the server, I get "Address already in use":
bind(client_sockfd, server_addr, sizeof server_addr)
So the OS thinks that I was trying to create another server socket with the same address and port number. In this case, how can I tell the OS that server_addr is the other endpoint I want to connect to and that it finds another port number for the client's socket?
You need to use bind() only for the server and in the client use
int connect(int socket, const struct sockaddr *address,
socklen_t address_len);.
See this tutorial for information about sockets in Linux:
http://www.linuxhowtos.org/C_C++/socket.htm
you use connect(client_sockfd, server_addr, sizeof(..)) to tell OS that my client socket should connect to this server address.
If it is UDP socket, you can also use sendto(client_sockfd, ... server_addr) call to specify that the packet should go to this server address.

Resources