Socket server, working on specific network interface address - c

I have a simple tcp client server program. Client sends text, server prints it ito terminal. I need to make it so client can connect to server by ip address, no just a port. Tried changing something in my localhost server, but it only broke it and it doesn't work anymore. What's whong in it?
Here's the server code:
int server(int port)
{
int fd;
struct ifreq ifr;
char * addres;
fd = socket(AF_INET, SOCK_STREAM, 0);
/* I want to get an IPv4 IP address */
ifr.ifr_addr.sa_family = AF_INET;
/* I want IP address attached to "eth0" */
strncpy(ifr.ifr_name, "em0", IFNAMSIZ-1);
ioctl(fd, SIOCGIFADDR, &ifr);
close(fd);
addres=inet_ntoa(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr);
//until this part, i'm getting my em0 address to a variable which I want to use later
//to specify on which address I want my server to be
int s, s2, t, len;
int z;
struct sockaddr_in local, remote;
char str[100];
if ((s = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("socket");
exit(1);
}
local.sin_family = AF_INET;
local.sin_addr.s_addr = inet_addr(addres); //inet_addr(inet_ntoa(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr));
printf("binder");
if (bind(s, (struct sockaddr *)&local, sizeof(local)) == -1) {
perror("bind");
exit(1);
}
if (listen(s, 5) == -1) {
perror("listen");
exit(1);
}
for(;;) {
int done, n;
printf("Waiting for a connection...\n");
t = sizeof(remote);
if ((s2 = accept(s, (struct sockaddr *) &remote, (socklen_t *) &t)) == -1) {
perror("accept");
exit(1);
}
printf("Connected...\n");
done = 0;
do {
n = recv(s2, str, 100, 0);
if (n <= 0) {
if (n < 0) perror("recv");
done = 1;
}
if (!done)
printf("%s", str);
fflush(stdout);
sleep(1);
} while (!done);
close(s2);
}
return 0;
}
It should start listening at given port, and on em0 interface address, but it seems to be doing nothing at all. In driver function I just pass the int representing port which I want to use.
Can I connect my client with that server using ip address?
My driver funtion chooses if I want to start a server or a client, it's all in one file.
To start a server i use:
./main.o -l [port]
and to start a client I'd want to use:
./main.o [address] [port]
Client seems to be working fine, just refuses to connect, only problem (as far as I'm aware) is a server. Maybe you'll catch what am I doing wrong, I'm sitting with it for couple of hours basically hopeless.

Related

Socket in c TCP how do i test connection?

For a school project I have to use sockets to create a server, I think I managed to do it but I am supposed to use Telnet to test it, and whenever I try I get
telnet: connect to address 0.0.0.0: Connection refused
So i guess it is with the IP that I'm wrong.
The simplified version of my code that should still work for one connection is
int main(int argc , char *argv[])
{
int sock;
int fd = 0;
int err = 0;
struct sockaddr_in sock_data;
socklen_t addr_size;
char *path;
path = get_current_dir_name();
if (argc == 2)
printf("%s", Usage);
sock = socket(AF_INET , SOCK_STREAM , 0);
if (sock == -1) {
printf("Could not create socket");
return (84);
}
memset(&sock_data, 0, sizeof(struct sockaddr_in));
sock_data.sin_family = AF_INET;
sock_data.sin_port = htons(5133);
sock_data.sin_addr.s_addr = htonl(INADDR_ANY);
printf("%s, %s, %s\n", path, sock_data.sin_addr, inet_ntoa(sock_data.sin_addr));
if (bind(sock, (const struct sockaddr *) &sock_data, sizeof(sock_data)) == -1)
printf("Error with binding\n");
if (listen(sock, LISTEN_BACKLOG) == -1)
printf("Error with listen");
addr_size = sizeof(struct sockaddr_in);
err = accept(sock, (struct sockaddr *) &sock_data, &addr_size);
while ((sock = accept(sock, NULL, NULL)) < 0)
err = 0;
return 84;
}
I saw this link: TCP sockets in c
that was quite clear but I still don't get how I am supposed to test my program
And the more I work on it the more I am convinced that I must have made a stupid mistake.
So do you know where I went wrong?
In your Telnet command you missed a port. The commamd should be like a
telnet system_ip port
For example
telnet 192.168.1.1 5631

Can reach my server with telnet but not with my client

I am currently coding a small chat application in C for learning network.
I develop using the Transmission Control Protocol with socket in C. I was able to connect to my server with a client not coded by myself (on local network). Now telnet succeed to connect to my chat server(so with server and telnet client on the same computer) and I can send and receive message BUT my very simple client cannot connect to it.
Since the begining I use port 9002 and right now I am trying to connect with IPv6 address ::1.
Here the "accept client" code of my server:
int main(void)
{
//Create the socket
int sock = socket(AF_INET6, SOCK_STREAM, 0);
printf("Socket créer\n");
//Set up the socket interface
struct sockaddr_in6 sin6 = { 0 };
sin6.sin6_family = AF_INET6;
sin6.sin6_port = htons(PORT);
sin6.sin6_addr = in6addr_any;
//Bind the socket on the port
if(bind(sock, (struct sockaddr *) &sin6, sizeof(struct sockaddr_in6)) == SO_ERROR)
{
perror("bind()");
errx(EXIT_FAILURE, "Fail to bind");
}
//Make the sockey listen the port
if(listen(sock, MAX_CLIENT) == SO_ERROR)
{
perror("listen()");
errx(EXIT_FAILURE, "Fail to listen");
}
printf("Socket listening\n");
int csock;
size_t clientID = 0;
--snip--
while(1)
{
struct sockaddr_in6 csin6;
memset(&csin6, 0, sizeof(struct sockaddr_in6));
int sin6size = sizeof(struct sockaddr_in6);
//Accept a communication
printf("Wait for communication\n");
csock = accept(sock, (struct sockaddr *) &csin6, &sin6size);
printf("Connection accepted\n");
char msg[16];
sprintf(msg, "CONNECTED - %zu\n", clientID);
send(csock, msg, sizeof(msg), 0);
printf("Client %zu connected\n", clientID);
//Handle client
--snip--
}
So this is a basic connection with socket using connected communication. The server handle several client in the while loop thanks to threading.
Here the code of the client:
void *sender(void *arg)
{
int socket = (int)(long)arg;
char buffer[BUFF_SIZE];
while(1)
{
scanf("%s", buffer);
send(socket, buffer, strlen(buffer), 0);
bzero(buffer, BUFF_SIZE);
}
}
int main(int argc, char *argv[])
{
if(argc < 2)
errx(EXIT_FAILURE, "Usage: ./client <server ip>\n");
//Create the socket
int sock = socket(AF_INET6, SOCK_STREAM, 0);
struct hostent *hostinfo = NULL;
hostinfo = gethostbyname2(argv[1], AF_INET6);
if(hostinfo == NULL)
errx(EXIT_FAILURE, "Can't connect to the server\n");
//Set up the socket interface
struct sockaddr_in6 sin6 = { 0 };
sin6.sin6_family = AF_INET6;
sin6.sin6_port = htons(PORT);
sin6.sin6_addr = *(struct in6_addr *)hostinfo->h_addr;
if(connect(sock, (struct sockaddr *) &sin6, sizeof(struct sockaddr)) == SO_ERROR)
{
perror("connect()");
errx(EXIT_FAILURE, "Fail to connect");
}
printf("Connection established\n");
pthread_t sending;
if(pthread_create(&sending, NULL, sender, (void *)(long)sock) != 0)
printf("Fail to create a thread\n");
//Handle reception
char buffer[BUFF_SIZE];
int n;
while((n = recv(sock, buffer, BUFF_SIZE - 1, 0)) >= 0)
{
buffer[n] = '\0';
printf("%s", buffer);
}
printf("Erreur: %d\nConnection broken\n", n);
pthread_cancel(sending);
close(sock);
return EXIT_SUCCESS;
}
So I start the client with:
~ ./client ::1
The output is the following:
Connection established
Error: -1
Connection broken
While the server is still "Waiting for communication". This means that the server do not accept the connection but the client succeed to connect.
Thank you for you help.
It is probably already the connect(), which fails here:
if(connect(sock, (struct sockaddr *) &sin6, sizeof(struct sockaddr)) == SO_ERROR)
SO_ERROR is not meant to be used here, but as a socket option when retrieving the error when an asynchronous connect fails. A (synchronous) connect() returns -1 on error and sets errno, so do
if(connect(sock, (struct sockaddr *) &sin6, sizeof(struct sockaddr)) == -1) {
...
Later, the recv here:
while((n = recv(sock, buffer, BUFF_SIZE - 1, 0)) >= 0)
fails with errno ENOTCONN, since the connection failed beforehand.
The same SO_ERROR mistake is present at various locations in your server code; it is possible, that already the bind() there fails! The call to listen() will then autobind it to a free ephemereal port, so the call as well as the call to accept() will succeed.
Why can the call to bind() fail? You might have to set the socket option SO_REUSEADDR when (re-)starting the server, otherwise it might refuse to use a recently bound port if connections are still in TIME_WAIT state. Place this directly before the bind() call:
int one = 1;
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
This might help.

Connecting a Linux-client to MacOS-server with C

I study sockets and try to write a very simple application. The client sends the string "Hello there!", the server accepts it, displays at itself and sends back. Wrote the client (Linux Ubuntu 18.04), and the server (macOS 10.14.2, IP: 217.144.173.149):
server:
int main()
{
int sock, listener;
struct sockaddr_in addr;
char buf[1024];
int bytes_read;
listener = socket(AF_INET, SOCK_STREAM, 0);
if(listener < 0)
{
perror("socket");
exit(1);
}
addr.sin_family = AF_INET;
addr.sin_port = htons(3425);
addr.sin_addr.s_addr = htonl(INADDR_ANY);
if(bind(listener, (struct sockaddr *)&addr, sizeof(addr)) < 0)
{
perror("bind");
exit(2);
}
listen(listener, 1);
while(1)
{
sock = accept(listener, 0, 0);
if(sock < 0)
{
perror("accept");
exit(3);
}
while(1)
{
bytes_read = recv(sock, buf, 1024, 0);
if (bytes_read <= 0) break;
printf(buf);
send(sock, buf, bytes_read, 0);
}
close(sock);
}
return 0;
}
client:
int main()
{
char message[] = "Hello there!\n";
char buf[sizeof(message)];
int sock;
struct sockaddr_in addr;
sock = socket(AF_INET, SOCK_STREAM, 0);
if(sock < 0)
{
perror("socket");
exit(1);
}
addr.sin_family = AF_INET;
addr.sin_port = htons(3425);
addr.sin_addr.s_addr = inet_addr("217.144.173.149");
if(connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0)
{
perror("connect");
exit(2);
}
send(sock, message, sizeof(message), 0);
recv(sock, buf, sizeof(message), 0);
printf(buf);
close(sock);
return 0;
}
However, after starting the client, it just hangs and after a while gives an error: connect: Connection timed out. The server at the same time, of course, works. Google search gave no results (maybe I was looking for). What I did wrong?
The problem is in the way you are converting the IP address from presentation type to network type.
You should use the IP address if it is static instead of INADDR_ANY.
If the problem stays try using a different function to convert the IP.
For further reference go here.
As other answers suggested , please check if your server is listening on properly using netstat command in server
From the server , check if firewalld or anyfirewall specific software is running
Try using different port to bind on server , may be 8080 or something else .
I also suggest you to read the excellent guide (beejs network programming guide)
https://beej.us/guide/bgnet/
Check server's ipfw IP Firewall. (Open port 3425 , which is the server port listen on)
Server's IP address must be public IP. Or the server and client in the same local area network.
If you just want to test your code. You can run server and client in the same computer. Open two terminal and the one run server , the other run client. And client change the connect ip 217.144.173.149 to 127.0.0.1
127.0.0.1 mean localhost.

C TCP Socket recv return -1 on Server-Server communication

I am building a client-server socket simulation to emulate DHCP. I have a client that receives input from the user, then sends a request via UDP to Server1. If Server1 does not hold the requested information, it contacts Server2 via TCP. If Server2 does not hold the information, it contacts Server3. Server3 then sends information to Server2 then Server1 then on to the Client
My code works for Client --> Server1 --> Server2 --> Server1 --> Client, but it fails when I try to add Server3.
Server3 successfully receives the connection and data from Server2, and the send is successful I believe. However, the recv on server 2 returns -1.
Here is my Server3 send code:
while ((rqst = accept(svc,(struct sockaddr *) &client_addr, &alen)) < 0) {
/* we may break out of accept if the system call */
/* was interrupted. In this case, loop back and */
/* try again */
}
inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
recvlen = recv(rqst, buf, BUFSIZE - 1, 0);
if (send(rqst, "Hello Server2!\0", BUFSIZE, 0) < 0) { /* Not real message, but this works */
perror("sendto");
}
My Server2 recv code is here
int port = SERVICE_PORT3; /* default: whatever is in port.h */
char *host = "localhost"; /* default: this host */
if (!conn_and_send(host, port, buf, fd3)) { /* connect fd3 is global int */
exit(1); /* something went wrong */
}
else {
char serv3_buf[BUFSIZE];
int serv3_recvlen = recv(fd3, serv3_buf, BUFSIZE - 1, 0);
printf("The recv length from serv3 is: %d\n", serv3_recvlen); /* prints -1*/
}
This is my conn_and_send function
int conn_and_send(char *host, int port, char* request, int fd_sock)
{
struct hostent *hp; /* host information */
unsigned int alen; /* address length when we get the port number */
struct sockaddr_in myaddr; /* our address */
struct sockaddr_in servaddr; /* server address */
printf("conn(host=\"%s\", port=\"%d\")\n", host, port);
if ((fd_sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
perror("cannot create socket");
return 0;
}
memset((char *)&myaddr, 0, sizeof(myaddr));
myaddr.sin_family = AF_INET;
myaddr.sin_addr.s_addr = htonl(INADDR_ANY);
myaddr.sin_port = htons(0);
if (bind(fd_sock, (struct sockaddr *)&myaddr, sizeof(myaddr)) < 0) {
perror("bind failed");
return 0;
}
alen = sizeof(myaddr);
if (getsockname(fd_sock, (struct sockaddr *)&myaddr, &alen) < 0) {
perror("getsockname failed");
return 0;
}
printf("local port number = %d\n", ntohs(myaddr.sin_port));
memset((char*)&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(port);
hp = gethostbyname(host);
if (!hp) {
fprintf(stderr, "could not obtain address of %s\n", host);
return 0;
}
memcpy((void *)&servaddr.sin_addr, hp->h_addr_list[0], hp->h_length);
if (connect(fd_sock, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) {
perror("connect failed");
return 0;
}
printf("Getting ready to send: %s\n", request);
if (send(fd_sock, request, strlen(request), 0) < 0) {
perror("sendto");
exit(1);
}
return 1;
}
Sorry to post so much code. I tried to include only relevant snippets.
What am I doing wrong, and if you can see no problems besides my poor C coding, why does C hate me?! :P

How to get the ip address of the accepted in-bound socket?

My question is:
Server will create a socket, bind to a given port and with address = INADDR_ANY.
listen() & accept() the new connection. Then, we can get the client's ip-address
from accept().
Now, I want to know the ip-address of the Server, since the host of the server has
multiple NIC on it.
How to know the ip-address of the network interface with which the accepted in-bound socket is from?
I tried getsockname, it gave me the port number, but the ip is all-zero.
Update: Here is the code:
Server.c (header files are removed)
int main(void)
{
struct sockaddr_in stSockAddr;
int res, addr_len, SocketFD, ConnectFD;
struct sockaddr_in addr;
SocketFD = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
if(-1 == SocketFD)
{
perror("can not create socket");
//exit(EXIT_FAILURE);
return -1;
}
memset(&stSockAddr, 0, sizeof stSockAddr);
stSockAddr.sin_family = AF_INET;
stSockAddr.sin_port = htons(49335);
stSockAddr.sin_addr.s_addr = INADDR_ANY;
if(-1 == bind(SocketFD,(struct sockaddr *)&stSockAddr, sizeof stSockAddr))
{
perror("error bind failed");
close(SocketFD);
return -1;
}
printf("going to listen!\n");
if(-1 == listen(SocketFD, 10))
{
perror("error listen failed");
close(SocketFD);
//exit(EXIT_FAILURE);
return -1;
}
ConnectFD = accept(SocketFD, NULL, NULL);
if(0 > ConnectFD)
{
perror("error accept failed");
close(SocketFD);
//exit(EXIT_FAILURE);
return -1;
}
addr.sin_family = AF_INET;
res = getsockname (ConnectFD, (struct sockaddr *)&addr, &addr_len);
// if you remove the following comment, that means, if you call
// two times of getsockname, the result will be correct.
//res = getsockname (ConnectFD, (struct sockaddr *)&addr, &addr_len);
printf("addr:%x\n", addr.sin_addr.s_addr);
while(1) {
if (getchar() == 'q')
break;
}
close(ConnectFD);
close(SocketFD);
return 0;
}
Below is client.c:
int main(void)
{
struct sockaddr_in stSockAddr;
int Res;
int SocketFD = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
if (-1 == SocketFD)
{
perror("cannot create socket");
exit(EXIT_FAILURE);
}
memset(&stSockAddr, 0, sizeof stSockAddr);
stSockAddr.sin_family = AF_INET;
stSockAddr.sin_port = htons(49335);
Res = inet_pton(AF_INET, "192.168.1.102", &stSockAddr.sin_addr);
if (0 > Res)
{
perror("error: first parameter is not a valid address family");
close(SocketFD);
exit(EXIT_FAILURE);
}
else if (0 == Res)
{
perror("char string (second parameter does not contain valid ipaddress");
close(SocketFD);
exit(EXIT_FAILURE);
}
if (-1 == connect(SocketFD, (struct sockaddr *)&stSockAddr, sizeof stSockAddr))
{
perror("connect failed");
close(SocketFD);
exit(EXIT_FAILURE);
}
/* perform read write operations ... */
printf("client sockfd is successful\n");
while(1) {
if (getchar() == 'q')
break;
}
shutdown(SocketFD, SHUT_RDWR);
close(SocketFD);
return 0;
}
Use getsockname(2) on the socket returned from accept(2), not the socket returned from bind(2).
getsockname() gets name of passed socket.
in this example, you pass the socket which is created by
accept function in server.
this socket is in server side, so it's name & address is
related to server side.
if you want to know "who was connected to me"
you must use getpeername() instead of getsockname.
good luck
if you remove the following comment, that means, if you call
two times of getsockname, the result will be correct.
res = getsockname (ConnectFD, (struct sockaddr *)&addr, &addr_len);
you must init addr_len.
addr_len = sizeof(addr);

Resources