Socket, accept() function, Invalid argument - c

I am getting an error "Invalid argument" when i call the accept() function on the server side of a client-server application. I don't get what is wrong and if you see what is wrong let me know please. Thanks.
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
int main(int argc, char* argv[])
{
int sockfd, newsockfd, portno, len;
struct sockaddr_in server, client;
if(argc < 2){
perror("Add more arguments");
}
sockfd = socket(AF_UNIX,SOCK_STREAM,0);
if(sockfd < 0){
perror("Error at socket()");
}
printf("Socketfd: %d\n",sockfd);
bzero((char *)&server, sizeof(server));
portno = atoi(argv[1]);
server.sin_family = AF_UNIX;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons(portno);
if(bind (sockfd, (struct sockaddr *)&server, sizeof(server)) <0){
perror("Error at bind ()-server");
}
listen(sockfd,5);
int readval;
char buffer[256];
for(;;){
len = sizeof(client);
newsockfd = accept (sockfd, (struct sockaddr *)&server,&len);
if (newsockfd == -1){
perror("Erroare at accept()");
}
else do{
readval = (sockfd,buffer,sizeof(buffer));
if (readval < 0 ){
perror("Error at reading()");
}
else if (readval == 0){
printf("End conection");
}
else{
printf("Mesage is: %s\n", buffer);
}
}while (readval > 0);
close(newsockfd);
}
return 0;
}

You have to use sockaddr_un instead of sockaddr_in for Unix domain sockets OR substitute AF_UNIX with AF_INET.
Plus, check the return of listen.
Plus change this line
readval = (sockfd,buffer,sizeof(buffer));
with
readval = read(newsockfd,buffer,sizeof(buffer));
because data is going to be sent through the newly created socket and not on the listening one
Plus, as mentioned by #trojanfoe, subst the server with the client structure into the accept() call

This line:
newsockfd = accept (sockfd, (struct sockaddr *)&server, &len);
Should be:
newsockfd = accept (sockfd, (struct sockaddr *)&client, &len);
From the manpage:
The argument addr is a pointer to a sockaddr structure. This structure
is filled in with the address of the peer socket, as known to the
communications layer. The exact format of the address returned addr is
determined by the socket's address family (see socket(2) and the
respective protocol man pages). When addr is NULL, nothing is filled
in; in this case, addrlen is not used, and should also be NULL.
Also check the return value from listen().

I ran into a similar issue before and it was due to not having the read function in a loop. Here is an example I did before.
while (1) {
new_sockfd = accept(sockfd, (struct sockaddr *) &client_addr,
&sin_size);
if (new_sockfd == -1)
perror("accepting connection");
printf("server: got connection from %s port %d\n",
inet_ntoa(client_addr.sin_addr),
ntohs(client_addr.sin_port));
recv_length = recv(new_sockfd, &buffer, DATA, 0);
while (recv_length > 0) {
printf("RECV: %d bytes\n", recv_length);
dump(buffer, recv_length);
recv_length = recv(new_sockfd, &buffer, DATA, 0);
}
close(new_sockfd);
}

Related

how to check if a TCP port is available in c socket?

i am writing a program that 2 players wants to connect to the server to play rock, paper and scissors.The first player connects to the port 60000 and when the second player want to connect it tries to connect to port 60000. if it fails, it will connect to port 60001. At this moment i am not sure how to implement the second player.
Client:
int sock = 0;
char *hostname = "127.0.0.1";
struct sockaddr_in serv_addr;
char buffer[1024] = {0};
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
printf("\n Socket creation error \n");
return -1;
}
memset(&serv_addr, '0', sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
// Clear this field; sin_zero is used for padding for the struct.
memset(&(serv_addr.sin_zero), 0, 8);
// Lookup host IP address.
struct hostent *hp = gethostbyname(hostname);
if (hp == NULL) {
fprintf(stderr, "unknown host %s\n", hostname);
exit(1);
}
serv_addr.sin_addr = *((struct in_addr *) hp->h_addr);
serv_addr.sin_port = htons(PORT);
if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0)
{
printf("\nConnection Failed \n");
return -1;
}
//getting the user name
printf("please enter your name:");
scanf("%s",buffer);
send(sock , buffer , strlen(buffer) , 0 );
//initializing the game
read( sock , buffer, 1024);
//playing the game until the user enters e
do{
printf("%s",buffer);
memset(buffer,0,sizeof(buffer));
scanf("%s",buffer);
while(check_input(buffer)==0){
printf("wrong input,try again:");
memset(buffer,0,sizeof(buffer));
scanf("%s",buffer);
}
send(sock , buffer , strlen(buffer) , 0 );//sending the input to the server
printf("client:sent %s\n",buffer);
read( sock , buffer, 1024);
printf("client:received %s\n",buffer);
}while(is_over(buffer)==2);
return 0;
in server:
char player1Name[1024];
char player2Name[1024];
int p1_score = 0;
int p2_score = 0;
char buffer[1024] = {0};
int server_fd;
int server_fd2;
int player1_socket;
int player2_socket;
struct sockaddr_in player1;
struct sockaddr_in player2;
int opt = 1;
int opt2=1;
int player1len = sizeof(player1);
int player2len = sizeof(player2);
// Creating socket file descriptor for player 1
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0){
perror("socket failed");
exit(EXIT_FAILURE);
}
// Creating socket file descriptor for player 2
if ((server_fd2 = socket(AF_INET, SOCK_STREAM, 0)) == 0){
perror("socket failed");
exit(EXIT_FAILURE);
}
// making the first socket reusable
if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT,&opt, sizeof(opt))){
perror("setsockopt");
exit(EXIT_FAILURE);
}
// making the second socket reusable
if (setsockopt(server_fd2, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT,&opt2, sizeof(opt2))){
perror("setsockopt");
exit(EXIT_FAILURE);
}
//specifying the address of the first player
player1.sin_family = AF_INET;
player1.sin_addr.s_addr = INADDR_ANY;
player1.sin_port = htons( PORT1 );
//specifying the address of the second player
player2.sin_family = AF_INET;
player2.sin_addr.s_addr = INADDR_ANY;
player2.sin_port = htons( PORT2 );
// Forcefully attaching socket to the port 6000
if (bind(server_fd, (struct sockaddr *)&player1, sizeof(player1))<0){
perror("bind failed");
exit(EXIT_FAILURE);
}
if (listen(server_fd, 1) < 0){
perror("listen");
exit(EXIT_FAILURE);
}
if ((player1_socket = accept(server_fd, (struct sockaddr *)&player1,(socklen_t*)&player1len))<0){
perror("accept");
exit(EXIT_FAILURE);
}
get_playerName(player1Name,&player1_socket);
// Forcefully attaching socket to the port 6001
if (bind(server_fd2, (struct sockaddr *)&player2, sizeof(player2))<0){
perror("bind failed");
exit(EXIT_FAILURE);
}
if (listen(server_fd2, 1) < 0){
perror("listen");
exit(EXIT_FAILURE);
}
if ((player2_socket = accept(server_fd2, (struct sockaddr *)&player2,(socklen_t*)&player2len))<0){
perror("accept");
exit(EXIT_FAILURE);
}
get_playerName(player2Name,&player2_socket);
char input1;
char input2;
do{
input1=get_nextMoves(player1Name,buffer,&player1_socket);
printf("%c\n",input1);
input2=get_nextMoves(player2Name,buffer,&player2_socket);
printf("%c\n",input2);
evaluate(input1,input2,&p1_score,&p2_score);
}while(input1!='e' && input2!='e');
strcpy(buffer,result(1,p1_score,p2_score));
send(player1_socket , buffer , strlen(buffer) , 0 );
strcpy(buffer,result(2,p1_score,p2_score));
send(player2_socket , buffer , strlen(buffer) , 0 );
return 0;
At this moment, i am running this code for both the player 1 and player 2 for the sake of experiment.When i run player 2 code, it just get stuck.
I was hoping for an error(EADDRINUSE more specifically).What is going on? how can i go further with my code?
In order for you to get an error, the server has to close the socket that's listening on port 6000 when the first client connects. Otherwise, your connection will succeed, but hang because the server doesn't call accept() a second time.
If the server does this, then the second client should get the error ECONNREFUSED, and it can try the second port.
if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0)
{
if (errno == ECONNREFUSED) {
serv_addr.sin_port = htons(PORT + 1);
if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0)
{
printf("\nConnection Failed \n");
return -1;
}
} else {
printf("\nConnection Failed \n");
return -1;
}
}
Note, however, that this has a potential failure mode due to a timing window. If both clients try to connect at about the same time, the second client's connection request might arrive before the server has closed the listening socket, so the call to connect() will still succeed, even though the server never processes that connection.
The solution to that requires a more elaborate server design, where it accepts the second connection and returns a response saying that the port is already being used. Although if it could do this, you wouldn't need two ports in the first place.

Connection to socket refused

I have simple TCP server program. After I close it with CTRL+C and restart again in some cases telnet client report me "connection refused". Why it happens not always, but just in some cases? Command ps shows nothing regarding my programm.
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <stdio.h>
#include<string.h>
void printHex(char *bts);
int main() {
char str[100];
int listen_fd, comm_fd;
struct sockaddr_in servaddr;
listen_fd = socket(AF_INET, SOCK_STREAM, 0);
bzero( &servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htons(INADDR_ANY);
servaddr.sin_port = htons(22000);
printf("binding\n");
bind(listen_fd, (struct sockaddr *) &servaddr, sizeof(servaddr));
printf("listening\n");
listen(listen_fd, 10);
printf("accepting\n");
comm_fd = accept(listen_fd, (struct sockaddr*) NULL, NULL);
printf("accep done\n");
int cn = 0;
while(1) {
bzero(str, 100);
printf("will read\n");
int br = read(comm_fd, str, 100);
printf("read done\n");
if (br > 0) {
printHex(str);
} else if (br <= 0) {
comm_fd = accept(listen_fd, (struct sockaddr*) NULL, NULL);
printf("accep done\n");
}
printf("error %d \n", br);
}
}
void printHex(char *bts) {
char *s = bts;
int i = 0;
do {
printf("%02X ", (unsigned char) *bts);
} while (*++bts !=0);
printf("%s\n",s);
}
You should check all return values from system calls:
int res;
res = bind(listen_fd, (struct sockaddr *) &servaddr, sizeof(servaddr));
if (res == -1)
// handle error
listen_fd = socket(AF_INET, SOCK_STREAM, 0);
if (listed_fd == -1)
// handle error
Most likely you will find then that your code fails on a bind system call, which means you can't reuse socket on same IP address, protocol and port. You can change this using setsockopt call:
// allow to rebind
int reuseaddr_on = 1;
res = setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR,
&reuseaddr_on, sizeof(reuseaddr_on));
if (res < 0)
{
stderr("Setting of SO_REUSEADDR on server's"
"socket failed");
}
You should also close a socket when you are done with it.
while(1)
{
// your loop
}
res = close(comm_fd);
if (res == -1)
// handle error
As Linux Programmer's Manual says on pages devoted to close call:
NOTES
Not checking the return value of close() is a common but nevertheless serious programming error. It is quite possible that
errors on a previous write(2) operation are first reported at the final close(). Not checking the return value when closing the file may lead to silent
loss of
data.
Always check the return values of your syscalls.
In this case,
bind(listen_fd, (struct sockaddr *) &servaddr, sizeof(servaddr));
fails with EADDRINUSE, because you didn't set SO_REUSEADDR on the socket before binding.
When you do CTRL-C and restart again, is the bind sucessful?
bind(listen_fd, (struct sockaddr *) &servaddr, sizeof(servaddr));
You need to check the status of the bind call. In all likelihood, this has failed due to connection having moved to TIME_WAIT state in server. And from this follows the error "connection refused" in client.
Far the bind to be successful when the server is run immediately after CTRL-C, use the SO_REUSEADDR in your socket option. With this bind will be successful, as long as there isn't another program bound to the port.

first client request not being served in sockets in c

This is a simple iterative client-server program. Where the server prints out "Received request" on successful establishment of connection.
server side
#define LENGTH 256
#define SERV_PORT 4000
#define LISTENQ 8
int main()
{
int listenfd, connfd, n;
socklen_t clilen;
char buf[LENGTH];
struct sockaddr_in cliaddr, servaddr;
//creation of socket
listenfd = socket (AF_INET, SOCK_STREAM, 0);
//creating socket address
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(SERV_PORT);
bind (listenfd, (struct sockaddr *) &servaddr, sizeof(servaddr));
// printf("\nServer running.. waiting for connections");
// listen(listenfd, LISTENQ);
for(; ;)
{
clilen = sizeof(cliaddr);
connfd = accept(listenfd, (struct sockaddr *) &cliaddr, &clilen);
printf("\nReceived request");
//sleep(5);
}
return 0;
}
client side
#define LENGTH 256
#define SERV_PORT 4000
int main( int argc, char *argv[])
{
int sock;
struct sockaddr_in server;
struct hostent *hp;
char buff[256];
sock = socket(AF_INET, SOCK_STREAM, 0);
if(sock < 0)
{
perror("socket failed");
exit(1);
}
server.sin_family = AF_INET;
hp = gethostbyname(argv[1]);
if(hp == 0)
{
perror("gethost by name failed");
exit(1);
}
memcpy(&server.sin_addr, hp->h_addr, hp->h_length);
server.sin_port = htons(4000);
if(connect(sock, (struct sockaddr *) &server, sizeof(server)) < 0)
{
perror("\nconnect failed");
exit(1);
}
return 0;
}
When I run this multiple client-server code, the output for first client is different from the preceding clients. I need the first client to output like others. Can someone help?
When the first client establishes a connection with the server, the server doesn't output "Received request", where as, for the other clients do output "Received request".
You need to restore the listen() call. – EJP

UDP Sockets in C - Sendto() Send failed : invalid arguments

I am trying to implement UDP sockets in C in a very simple/basic fashion. My programs are meant to send/receive files between terminals with one program running on each. I am having a problem with the sendto() function in my client code. Here is my code:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<arpa/inet.h>
#include<sys/socket.h>
#include <errno.h>
#define BUFFER_SIZE 512
int main(int argc, char *argv[])
{
struct sockaddr_in client;
int sockfd, bytes, errno, slen = sizeof(client);
char buffer[BUFFER_SIZE];
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if(sockfd == -1)
{
perror("Socket creation failed.");
return 0;
}
client.sin_addr.s_addr = INADDR_ANY;
client.sin_family = AF_INET;
client.sin_port = htons( 0 );
if( bind(sockfd, (struct sockaddr *)&client, sizeof(client)) == -1)
{
perror("Bind call failed.");
return 0;
}
while(1)
{
printf("Enter message : ");
fgets(buffer, BUFFER_SIZE, stdin);
printf("Message: %s\n", buffer);
bytes = sendto(sockfd, buffer, strlen(buffer), 0, (struct sockaddr *)&client, sizeof(client));
printf("Bytes: %d\n", bytes);
if(bytes == -1)
{
printf("Error number: %d", errno);
perror("Send failed.");
return 0;
}
memset(buffer,'\0', BUFFER_SIZE);
if( recvfrom(sockfd, buffer, BUFFER_SIZE, 0, (struct sockaddr *)&client, &slen) == -1)
{
perror("Recieve failed.");
return 0;
}
puts(buffer);
}
close(sockfd);
return 0;
}
No matter what I enter into the buffer, I always get error number 22 from sendto() for invalid arguments. I have tried every solution or tweak I have come across but nothing seems to work.
Just add this piece of code after bind()
getsockname(sockfd, (struct sockaddr *)&client, &slen);
man page
DESCRIPTION
The getsockname() function returns the current address for the specified
socket.
The address_len parameter should be initialized to indicate the amount of
space pointed to by address. On return it contains the actual size of
the address returned (in bytes).
The address is truncated if the buffer provided is too small.
RETURN VALUES
The getsockname() function returns the value 0 if successful; otherwise
the value -1 is returned and the global variable errno is set to indicate
the error.

Need multiple connections in C socket

I have written the following code as an intermediate to connect two programs. There is a server program running and a client program on two different systems. This code is expected to act as an intermediate between these two programs.
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
//Connect with program on server side
char * serv_con(char app_data[50])
{
int sock, bytes_recieved;
char send_data[1024];
char *recv_data = malloc(1024);
struct hostent *host;
struct sockaddr_in server_addr;
host = gethostbyname("10.47.3.249");
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
perror("Socket");
exit(1);
}
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(3128);
server_addr.sin_addr = *((struct in_addr *)host->h_addr);
bzero(&(server_addr.sin_zero),8);
if (connect(sock, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1)
{
perror("Connect");
exit(1);
}
bytes_recieved=recv(sock,recv_data,1024,0);
recv_data[bytes_recieved] = '\0';
send(sock, app_data, 50, 0);
return recv_data;
//close(sock);
}
//Connect with client app
char * cli_con(char ser_data[50])
{
int sock, connected, bytes_recieved , true = 1;
char send_data [1024];
char *recv_data = malloc(1024);
struct sockaddr_in server_addr,client_addr;
int sin_size;
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
perror("Socket");
exit(1);
}
if (setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&true,sizeof(int)) == -1)
{
perror("Setsockopt");
exit(1);
}
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(5000);
server_addr.sin_addr.s_addr = INADDR_ANY;
bzero(&(server_addr.sin_zero),8);
if (bind(sock, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1)
{
perror("Unable to bind1");
exit(1);
}
if (listen(sock, 5) == -1)
{
perror("Listen");
exit(1);
}
sin_size = sizeof(struct sockaddr_in);
connected = accept(sock, (struct sockaddr *)&client_addr,&sin_size1);
printf("\n I got a connection from (%s , %d)",inet_ntoa(client_addr.sin_addr),ntohs(client_addr.sin_port));
bytes_recieved = recv(connected,recv_data,1024,0);
recv_data[bytes_recieved] = '\0';
send(connected, ser_data,50, 0);
//close(sock);
}
int main()
{
char *ser_data, *app_data;
int pid = fork();
while(1)
{
if(pid == 0)
app_data = serv_con(ser_data);
else
ser_data = cli_con(app_data);
}
}
It works fine until the client side app runs. But as soon as the client side app runs, the code exit giving the error:
Unable to bind: Address already in use
I got a connection from (192.168.0.3 , 45691)
What modification should I make in the code to rectify this error? I am working on linux. Thanks in advance.
EDIT:
I have removved the comment from close(sock)and added close(connect) in the function cli_con. The code on the client side is given below:
int sock, bytes_recieved;
char send_data[1024],recv_data[1024];
struct hostent *host;
struct sockaddr_in server_addr;
host = gethostbyname("192.168.0.2");
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
perror("Socket");
exit(1);
}
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(5555);
server_addr.sin_addr = *((struct in_addr *)host->h_addr);
bzero(&(server_addr.sin_zero),8);
if (connect(sock, (struct sockaddr *)&server_addr,
sizeof(struct sockaddr)) == -1)
{
perror("Connect");
exit(1);
}
while(1)
{
//necessary codes
if (connect(sock, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1)
{
close(sock);
goto connct;
}
}
But now on running, the first program doesnot exit but doesnot even print
I got a connection from (192.168.0.3 , 45691)
But just keeps on running without printing ANY messages. But on the other hand, the client exits showing the error:
Connect: Connection reset by peer
What should I do now?
When a client disconnects you create a new server socket and bind it to the same port. If the server side socket was not closed the port is still in use, so bind fails.
Usually the server side of a socket program has a loop around accept to allow it process connections from many clients. This way bind and listen are called only once.
while (connected = accept(sock, (struct sockaddr *)&client_addr,&sin_size1)) {
printf("\n I got a connection from (%s , %d)",inet_ntoa(client_addr.sin_addr),ntohs(client_addr.sin_port));
bytes_recieved = recv(connected,recv_data,1024,0);
recv_data[bytes_recieved] = '\0';
send(connected, ser_data,50, 0);
close(connected);
}
It means you're trying to listen on port 5000, but there is already a program listening on that port (possibly an earlier version of your program which didn't close the port properly.) Change the port number to another value, or close any application listening on the port.
Since you're under Linux, you can use "netstat -nlp" as root to see what programs have which ports open.
One pointer for you is that, you should close both the listen socket and the socket which you obtain from the accept call.
close(connected);
close(sock);
Also, the socket takes sometime to be freed by the OS after it's usage and so, it might fail with an "Address already in use" error. You can check again properly in your code if your SO_REUSEADDR part of the code is executing properly.
Also, since you can try to add the listen socket creation code in your main function itself and pass it as an argument to cli_con function. Commonly followed mechanism is to create one listen socket and use it to accept multiple connections from client.
I hope in your original code you have proper memory allocation, initialization etc for ser_data & app_data.

Resources