Invalid argument when trying to accept connections from socket in C [duplicate] - c

In the next code, while I try to connect a client the server shows the following error:
"invalid argument", I can't see the error.
if((l_sock=socket(AF_INET,SOCK_STREAM,0))!=-1)
{
struct sockaddr_in srv_dir;
srv_dir.sin_family=AF_INET;
srv_dir.sin_port=8500;
srv_dir.sin_addr.s_addr=INADDR_ANY;
if((bind(l_sock,(struct sockaddr *)&srv_dir,sizeof(struct sockaddr_in)))!=-1)
{
if(!(listen(l_sock,5)))
{
signal(SIGINT,cerraje);
int t_sock;
struct sockaddr_in cli_dir;
socklen_t tam;
time_t tstmp;
struct tm * res;
res=(struct tm *)malloc(sizeof(struct tm));
while(!key)
{
if((t_sock=accept(l_sock,(struct sockaddr *)&cli_dir,&tam))!=-1)
{
tstmp=time(&tstmp);
res=gmtime(&tstmp);
send(t_sock,res,sizeof(struct tm),0);
wr_hora(*res,cli_dir.sin_addr);
}
else
perror("PeticiĆ³n no atendida");//The error is printed here.

Read the documentation on accept(2):
The addrlen argument is a value-result argument: it should initially contain the size of the structure pointed to by addr; on return it will contain the actual length (in bytes) of the address returned. When addr is NULL nothing is filled in.
So you need to initialize the value of tam passed into accept with sizeof(cli_dir). You're fortunate that the socket library was able to catch your error, because you're passing in uninitialized memory, which results in undefined behavior.

Related

Saving and accessing field from a custom struct

I defined a struct like this (and other fields but they are not relevant with the question)
typedef struct {
struct sockaddr_in addr_destination;
}MY_PACKET;
The main call a function send_command
struct sockaddr_in *addr_server;
socklen_t addr_server_lenght;
MY_PACKET command_packet;
void send_command(char *comm, int socket_file_descriptor, struct sockaddr_in *server_address) {
addr_server = server_address;
addr_server_lenght = sizeof(*addr_server);
printf("Server address: %s\n", inet_ntoa(addr_server->sin_addr));
command_packet.addr_destination = *addr_server;
printf("Server address: %s\n", inet_ntoa(command_packet.addr_destination.sin_addr));
}
so the first printf prints "127.0.0.1" correctly
the second prints "0.0.0.0"
The rest of the program consists on a thread that send this packet to a server and wait for ack (so i must be able to access all the fields of command_packet from the thread function), but I'm stuck saving the server address in the packet correctly, what am I doing wrong? Thanks

Invalid argument when using sendto

I am trying to send a buffer via UDP sockets in C but I always get an invalid argument error in sendto. I just don't find the error. Could anyone maybe help me. Thanks in advance.
Here's my code:
/**/ void IPCSend(char *pazClientAddress, int iClientPort, char *pazBuffer )
{
int iSocket;
/* */
if ((iSocket = socket(AF_INET, SOCK_DGRAM, 0)) != -1)
{
int iSendToReturn;
struct sockaddr_in sinServerAddress;
struct hostent *pstHost;
/* */
pstHost = (struct hostent *)gethostbyname((char *)pazClientAddress);
/* */
sinServerAddress.sin_family = AF_INET;
sinServerAddress.sin_addr = *((struct in_addr *)pstHost->h_addr);
sinServerAddress.sin_port = iPortNumber;
bzero(&(sinServerAddress.sin_zero),8);
/* */
fprintf(stdout,"sending '%s' to client '%s:%d'\n",pazBuffer,pazClientAddress,iClientPort);
iSendToReturn = sendto(iSocket, pazBuffer, sizeof(pazBuffer), 0, (struct sockaddr *)&sinServerAddress, sizeof(sinServerAddress));
/* */
if(iSendToReturn != -1)
fprintf(stdout,"%d bytes sent\n",iSendToReturn);
else
perror("SendTo");
/* */
close(iSocket);
}
else
fprintf(stdout,"could not connect to server\n");
}
Firstly, you're making the perennial error of novice C programmers: using sizeof to get the size of a pointer. The variable pazBuffer is a pointer, not an array, so the sizeof operator will not return the array length, which is what you want. Your IPCSend function needs to take in the length of pazBuffer as a separate parameter:
void IPCSend(char *pazClientAddress, int iClientPort, char *pazBuffer, size_t len)
As for the error you're getting - it might be related to something else. Invalid argument means that one of the parameters you're passing to sendto is somehow invalid. Since I see that you are properly initializing the socket descriptor, the problem might be that the send buffer is somehow not valid - possibly a null pointer or bad address. This means that the problem is not apparent from the code you posted, and is likely in some code that is calling IPCSend.

Passing structures using UDP

I have been trying to send and receive structures on the same machine using UDP and the server and client in this case run on the same machine and share common structure definitions (using a header file).
Hostent structure defn(UNIX built-in type) :
struct hostent{
char *h_name;
char **h_aliases;
int h_addrtype;
int h_length;
char **h_addr_list;
}
Server Code snippet follows :
struct hostent* resolved_host = DNS_translate(DNSname);
if((numbytes = sendto(sockfd, (void*)&resolved_host, sizeof(struct hostent), 0, (struct sockaddr *)&client_addr, sizeof(struct sockaddr))) == -1)
{
perror("sendto failed");
exit(EXIT_FAILURE);
}
Client Code snippet follows:
struct hostent resolved_host;
int addr_len = sizeof(struct sockaddr);
if((numbytes = recvfrom(sockfd, (void*)&resolved_host, sizeof(struct hostent), 0, (struct sockaddr *)&server_addr, &addr_len)) == -1)
{
perror("recvfrom failed");
exit(EXIT_FAILURE);
}
The server sends and the client receives as normal (no error raised).
The *resolved_host* structure is filled in the server and all its data can be accessed with no problem.
However, if I now try to use the *resolved_host* structure in the client, I get a seg fault. For example:
printf("Name : %s\n", resolved_host.h_name);
raises a seg fault. (but works in the server)
Your struct is full of pointers. When you send it over the network, you send the actual addresses, not the data pointed to by those pointers.
Those addresses are invalid in the target process.
You will need to serialize the data yourself. See for examples:
Serialization/Deserialization of a struct to a char* in C
Serialization techniques
The structure contains pointers - so when you copy the structure over UDP you're only copying the values of those pointers (i.e. the addresses of some other pieces of data) and not the actual data itself.
When you receive those pointers in the server they no longer mean anything - those pointer addresses are meaningless to the other program.
You are sending pointers. Even on the same machine these are not valid in different address spaces.

Why am I having "Invalid argument" while trying to accept connections?

In the next code, while I try to connect a client the server shows the following error:
"invalid argument", I can't see the error.
if((l_sock=socket(AF_INET,SOCK_STREAM,0))!=-1)
{
struct sockaddr_in srv_dir;
srv_dir.sin_family=AF_INET;
srv_dir.sin_port=8500;
srv_dir.sin_addr.s_addr=INADDR_ANY;
if((bind(l_sock,(struct sockaddr *)&srv_dir,sizeof(struct sockaddr_in)))!=-1)
{
if(!(listen(l_sock,5)))
{
signal(SIGINT,cerraje);
int t_sock;
struct sockaddr_in cli_dir;
socklen_t tam;
time_t tstmp;
struct tm * res;
res=(struct tm *)malloc(sizeof(struct tm));
while(!key)
{
if((t_sock=accept(l_sock,(struct sockaddr *)&cli_dir,&tam))!=-1)
{
tstmp=time(&tstmp);
res=gmtime(&tstmp);
send(t_sock,res,sizeof(struct tm),0);
wr_hora(*res,cli_dir.sin_addr);
}
else
perror("PeticiĆ³n no atendida");//The error is printed here.
Read the documentation on accept(2):
The addrlen argument is a value-result argument: it should initially contain the size of the structure pointed to by addr; on return it will contain the actual length (in bytes) of the address returned. When addr is NULL nothing is filled in.
So you need to initialize the value of tam passed into accept with sizeof(cli_dir). You're fortunate that the socket library was able to catch your error, because you're passing in uninitialized memory, which results in undefined behavior.

getpeername() Returns Wrong Data

I am writing my first sockets program on Linux and am trying to print the IP address and port of the peer I have connected to. I use getpeername() along with inet_ntop() and ntohs() to get the data out of the sockaddr_in struct. When I look at the results, I get an IP address that does not go to any server that I know of (ping fails) and says that I am listening to a port that netstat says is not being used.
What am I doing wrong? I should be getting 130.215.28.181:39000, but instead I am getting 209.94.72.137:18825 every time I run the program. Looking at netstat shows that I am indeed listening on port 39000.
Here is a snippet from my client program:
connect(sockfd,&serv_addr,sizeof(serv_addr))
// print welcome message
char ipstr[INET6_ADDRSTRLEN];
bzero(ipstr, 50);
struct sockaddr_in *address;
socklen_t address_len = sizeof(*address);
getpeername(sockfd, (struct sockaddr *) address, &address_len);
inet_ntop(AF_INET, &address->sin_addr, ipstr, sizeof(ipstr));
printf("Connection established successfully with %s:%i!\n", ipstr, ntohs(address->sin_port));
You're not allocating any memory for your sockaddr_in structure, you's just passing a pointer to some random memory location. Instead, allocate the address structure on the stack:
struct sockaddr_in addr;
socklen_t addr_len = sizeof(addr);
int err = getpeername(sockfd, (struct sockaddr *) &addr, &addr_len);
if (err != 0) {
// error
}
You should also be checking the return value of every function that is documented to return an error code. In particular, both connect and getpeername return error codes that you should be checking.

Resources