I had an error with the following code, wherein it would return to me that sendto failed because "Address family not supported by protocol". I realized my mistake on the 3rd line, leaving a semicolon after the for loop declaration. Once I removed this, everything worked fine.
struct sockaddr_in their_addr;
if ((numbytes=recvfrom(sockfd, buf, 512, 0,
(struct sockaddr *)&their_addr, &addr_len)) == -1 ) {
perror("recvfrom") ;
exit(1) ;
}
char thedata[512];
int i;
for (i = 0; i < 512; i++);
{
thedata[i] = 'a';
}
unsigned int addr_len = sizeof(struct sockaddr);
if ((numbytes=sendto(sockfd, thedata, 512, 0, (struct sockaddr *)&their_addr,
addr_len)) == -1 ) {
perror("sendto") ;
exit(1) ;
}
My question is why that message specifically was returned to me. I sent an array with uninitialized values, but my assumption was that because the char array was initialized to have 512 elements, that it would have memory allocated for all 512 elements in a row. Why doesn't it send the garbage values? It's a question of curiosity more than anything, but I'd love to know more about this situation.
Thanks
When your loop exits, i is 512, so thedata[i] points to beyond the end of thedata[]. I am guessing this overwrote their_addr, specifically the protocol which from memory is at the head of the struct.
Please insert the normal warning here about the fact you overwrote memory so behaviour is undefined and anything could have happened.
Related
I'm facing a weird problem when using sendto() in C. I have this code:
struct sockaddr_in currSocket;
int currSocketLength = sizeof(currSocket);
memset((char *)&currSocket, 0, sizeof(currSocket));
currSocket.sin_family = AF_INET;
currSocket.sin_port = htons(serverPortNumber);
// add the server IP address
inet_aton(serverIP, &currSocket.sin_addr);
int send_result = sendto(masterSocket, bufferToSend , 1000, 0, (struct sockaddr *) &currSocket, currSocketLength);
if (send_result < 0) {
perror("Something is wrong");
}
bzero(bufferToSend, 1000);
This works great when I send data the first time in bufferToSend. However, if I want to send data again the exact same way (following the code above - create the socket and send it there), it doesn't get received. Why is this and how can I fix it?
Edit:
After looking into it some more, I've realized it's because my IP address string is wrong because it's being overwritten. It seems to have it's value change after I do a previous read.
// here the IP address is fine
printf("%s\n", ipAddress);
char bufferFromSocket[512];
int amount_read = read(masterSocket, bufferFromSocket, 512);
// here the IP address is overwritten by whatever is in bufferFromSocket
printf("%s\n", ipAddress);
Any ideas why this could be happening?
I hadn't allocated enough space for ipAddress. Had it as a pointer, when it should have been a char[] and I copy to it using strcpy.
I'm seeing strange behavior with the following piece of code:
int len;
ioctl(conn_fd, FIONREAD, &len);
The usual code you might imagine precedes this (it's a toy web server):
...
int sock_fd = socket(AF_INET, SOCK_STREAM, 0);
bind(sock_fd, (struct sockaddr *)&server_addr, sizeof(server_addr));
listen(sock_fd, 5);
int conn_fd = accept(sock_fd, (struct sockaddr *) &client_addr, &client_addr_size);
The unusual behavior is when I use curl to make a request to my toy web server, everything works perfect and len is the exact size of the request. When I use Chrome, Postman, or wget, len is 0. Because len is 0, my code treats it as an empty response and doesn't consume the request.
To verify there is actually data (besides the fact that curl works), I follow the code up with:
char full_request[16384];
int bytes_read = read(conn_fd, full_request, 16383);
To my delight, outputting full_request gives me, well, the full request no matter if it's curl, Chrome, Postman, or wget.
What gives? Is my call to ioctl not to be trusted? Is there a better way to know the size of the data coming in so I can consume it?
EDIT for EJP:
char *full_request = malloc(1 * sizeof(char));
*full_request = '\0';
for (;;) {
char buf[64];
int bytes_read;
int new_len;
bytes_read = recv(conn_fd, buf, 63, 0);
buf[bytes_read] = '\0';
if (bytes_read <= 0) break;
new_len = strlen(full_request) + bytes_read + 1;
full_request = realloc(full_request, new_len * sizeof(char));
strcat(full_request, buf);
}
The problem with your reasoning is that read() blocks until data is available, or end of stream or an error occurs. So the fact that it did return data doesn't indicate that FIONREAD was wrong at the moment you called it. There is rarely a good reason to use FIONREAD.
You also cannot rely on a single read returning the full request. It is only obliged to transfer at least one byte. You have to loop.
This is my server side code for udp
#include"headers.h"
int main(int argc,char **argv)
{
//------------udp server socket connection------//
int sd1;
struct sockaddr_in serveraddr, clientaddr;
char buffer[100];
char *bufptr = buffer;
int cnt=1,ret;
socklen_t clen;
clen=sizeof(clientaddr);
//int buflen = sizeof(buffer);
sd1=socket(AF_INET,SOCK_DGRAM,0);
printf("udp socket id=%d\n",sd1);
printf("socket created for udp..\n");
if(sd1<0)
{
perror("udp_sfd");
exit(0);
}
printf("server socket created..\n");
serveraddr.sin_family=AF_INET;
serveraddr.sin_port=htons(atoi(argv[1]));
serveraddr.sin_addr.s_addr=INADDR_ANY;
if(bind(sd1,(struct sockaddr *)&serveraddr,sizeof(serveraddr))<0)
{
perror("bind\n");
exit(0);
}
else
{
while(1)
{
printf("server accept from client\n");
ret=recvfrom(sd1,(char *)bufptr,strlen(buffer),0,(struct sockaddr *)&clientaddr,&clen);
printf("ret=%d\n",ret);
//printf("hello\n");
if(ret<0)
{
perror("recvfrom");
exit(0);
}
else
{
printf("UDP Server received the following:\n \"%s\" message\n", bufptr);
}
//close(sd1);
}
}
close(sd1);
return 0;
}
I am sending tht buffer from client side... and in server side it is giving me an error like this....
Bad file descriptor .... what should I do...
I also changed the name of file descriptor 2 times... still it is not working...
Your recvfrom is bad. Instead of strlen(buffer), you should use sizeof(buffer). Since buffer is on the stack, you may have a large string in there and then you are overflowing the buffer if the recvfrom gets a large amount of data.
I will studying it up some more if that doesn't help.
The problem is in your call to recvfrom:
ret=recvfrom(sd1,(char *)bufptr,strlen(buffer),0,(struct sockaddr *)&clientaddr,&clen);
The third parameter should be the size of the input buffer. But instead, you're calling strlen on the buffer. Because buffer is uninitialized, calling strlen on it is reading uninitialized data which can cause undefined behavior.
Also, unless the client is sending a null terminated string (i.e. some printer characters followed by a null byte) the call to printf will also invoke undefined behavior since any bytes past what was read will be uninitialized.
Pass in the buffer size minus 1 (to leave space for a null byte) instead of calling strlen, and clear the buffer just beforehand.
memset(buffer, 0, sizeof(buffer));
ret=recvfrom(sd1,(char *)bufptr,sizeof(buffer)-1,0,(struct sockaddr *)&clientaddr,&clen);
I think you are closing the socket some where else in your program.
The Bad file descriptor may refer to an invalid file descriptor or it is closed somewhere else in your code or it is already being used somewhere else. I think you need to debug your code a little bit and then manage your socket well.
It is possible that your socket is being closed somewhere by mistake or being corrupted.
You can try creating the new socket as well with different port number.
I am doing socket programming for achieve communication between different entities in my application. When sending a message, I prefix the message with the length of the message and I terminate it with \0. I have recv() in a loop as follows:
void receive(int socket)
{
int num_of_bytes_read = 0, msg_len;
char *msg = NULL, *msg_p = NULL;
char recv_buf[MAX_LEN];
while(num_of_bytes_read = recv(socket, recv_buf, MAX_LEN, 0))
{
if(msg == NULL)
{
memcpy(&msg_len, message, 4);
msg_len = ntohl(msg_len);
if((msg = (char *)(sizeof(char) * msg_len)) == NULL)
systemError("Could not receive new message\n");
printf("%p\n", msg); /* prints 0xe!! Why is the address not 4B long??*/
msg_p = msg;
}
if(memcpy(&msg_p, recv_buf, num_of_bytes_read) == NULL)
systemError("memcpy failed in receive()\n");
msg_p += num_of_bytes_read;
}
printf("%p\n", msg); /* prints (nil) !!!!!*/
printf("%p\n", msg + sizeof(uint32_t)); /* prints 0x4 */
/* pass the a pointer to the beginning of the message skipping msg_len*/
int res = processMessage(msg + sizeof(uint32_t));
}
When I run the program I obviously get segmentation fault with the following error:
message=0x4
What is wrong with msg?? Can someone please help.
while(num_of_bytes_read = recv(socket, recv_buf, MAX_LEN, 0))
This is already wrong. You should test for > 0. If num_of_bytes is zero you should close the socket, and if it is -1 you should log the associated errno, e.g. with perror(), and close the socket, and in both cases stop reading.
if(msg == NULL)
{
memcpy(&msg_len, message, 4);
As long as message points to four bytes of addressable memory this will succeed. You have provided no information on the point. The purpose remains obscure.
msg_len = ntohl(msg_len);
Here you are assuming that message pointed to four bytes that magically contain an int that has magically been set to a value you are prepared to regard as a message length. Why, I don't know. Again you have provided no information on the point.
if((msg = (char *)(sizeof(char) * msg_len)) == NULL)
This is complete nonsense. Is there a malloc() missing in there somewhere?
systemError("Could not receive new message\n");
A meaningless error message. The problem appears to be about allocating memory, but it's anybody's guess. It certainly has nothing to do with receiving messages.
printf("%p\n", msg); /* prints 0xe!! Why is the address not 4B long??*/
Here you appear to think the address should be 4B long. I don't know why.
if(memcpy(&msg_p, recv_buf, num_of_bytes_read) == NULL)
You are copying data to the address of msg_p. This doesn't make sense. Also, at this point num_of_bytes_read could be -1 due to your incorrect loop condition above, so anything could happen, including trying to copy 0xffffffff bytes.
systemError("memcpy failed in receive()\n");
The only way you can get to this line is if msg_p's address was null, which is impossible. Remove the & from &msg_p in the memcpy() call. Now you can only get to this systemError() call if msg_p was zero, which would already have caused a SEGV, so you still can't get to this line. A bit of preventative coding is indicated here.
msg_p += num_of_bytes_read;
Again num_of_bytes_read could be -1 at this point, sending your pointer backwards instead of forwards.
printf("%p\n", msg); /* prints (nil) !!!!!*/
Nil indicates that msg was zero.
printf("%p\n", msg + sizeof(uint32_t)); /* prints 0x4 */
0x4 again indicates that msg was zero.
You need to improve your code in the areas indicated.
msg = (char *)(sizeof(char) * msg_len)
You are setting msg to some address based on the msg_len. Not actually anything to do with where the msg resides in memory...
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.