Right now I'm just trying to get my "server" to reply back immediately after receiving a UDP datagram(in preparation for more complicated stuff).
However, I keep getting a Invalid Argument error on the sendTo (at RunTime). Can anyone help point out why? I have written other sendTo's and looked at sample code on the Internet and cannot pinpoint why.
The recvfrom is working fine.
Thanks!
void *receive(void *socket)
{
int* socket_ptr = (int *) socket;
int socket_desc = *socket_ptr;
int recv_length;
socklen_t addrlen = sizeof (struct sockaddr_in);
while(1){
struct Message msg;
struct sockaddr_in * incoming = malloc (sizeof (struct sockaddr_in));
if ((recv_length = recvfrom (socket_desc, &msg, sizeof(msg), 0,
(struct sockaddr *) incoming, &addrlen))
== -1)
{
}else
{
struct CoordMessage * cm = malloc(sizeof (struct CoordMessage));
cm->msgID = BEGINSUCCESS;
cm->tid = msg.tid;
if (sendto(socket_desc, cm, sizeof(struct CoordMessage), 0, (struct sockaddr *) incoming, sizeof(incoming)) < 0){
perror("TEMP Send failed ");
exit(1);
}
}
}
}
sizeof(incoming) in the sendto call is just the size of a pointer, you need to pass the sizeof the struct that you got from the recvfrom call. Also the malloc is causing a memory leak, because you never free the memory.
I suggest declaring the struct as
struct sockaddr_in incoming = {0};
and then passing the address of the struct to recvfrom and sendto, e.g.
if ((recv_length = recvfrom (socket_desc, &msg, sizeof(msg), 0,
(struct sockaddr *) &incoming, &addrlen))
== -1)
and
if (sendto(socket_desc, cm, sizeof(struct CoordMessage), 0, (struct sockaddr *) &incoming, addrlen) < 0)
The same thing applies to the cm variable, if you malloc it, you need to free it. But you could just declare it, and pass the address.
Related
I'm writing a function that is supposed to do some operations and then return (using its arguments) the address of the device that is interacting with (i.e. that used sendto) the recvfrom inside the function.
Here's how I call the function, instantiating cliaddr before.
struct sockaddr_in cliaddr;
memset((void *) &cliaddr, 0, sizeof(cliaddr));
rcv_string(sockfd, &return_string, &cliaddr);
// Here I'll need to use cliaddr, that's why I need it outside too
Here's the implementation of the function:
int rcv_string(int sockfd, char **return_string, struct sockaddr_in *sndaddr) {
// ...
char buff[PACKETSZ + 2];
memset(&buff, 0, sizeof(buff)); // Clean buffer
socklen_t *plen = malloc(sizeof(struct sockaddr *));
if ((recvfrom(sockfd, buff, sizeof(buff), 0, (struct sockaddr *) sndaddr, plen)) < 0) {
perror("recvfrom");
return -1;
}
char *snd_ip = malloc(INET_ADDRSTRLEN * sizeof(char));
if (inet_ntop(AF_INET, &((*sndaddr).sin_addr.s_addr), snd_ip, INET_ADDRSTRLEN * sizeof(char)) == NULL) {
perror("inet_ntop");
return -1;
}
printf("Received '%s' from '%s'.\n", buff, snd_ip);
// ...
}
Now, even if the ip address of the sending device is 192.168.1.251 I get the following output:
Received '0packetx' from '0.0.0.0'.
The received buffer is formatted correctly, but the address is evidently wrong. Why? Does it have to do with the definition of the address variable outside the function?
EDIT
If after the memset of cliaddr I add also those 3 lines:
cliaddr.sin_family = AF_INET;
cliaddr.sin_addr.s_addr = htonl(INADDR_ANY);
cliaddr.sin_port = htons(SERV_PORT);
I get a random behavior. Sometimes I get 0.0.0.0, sometimes 127.0.0.1 and sometimes the correct address (192.168.1.251).
you are passing the wrong length to recvfrom
socklen_t *plen = malloc(sizeof(struct sockaddr *));
if ((recvfrom(sockfd, buff, sizeof(buff), 0, (struct sockaddr *) sndaddr, plen))
Why you malloc is a mystery, but you need
socklen_t *plen = malloc(sizeof(socklen_t));
*plen = sizeof(struct sockaddr_in );
much simpler is
socklen_t plen = sizeof(struct sockaddr_in);
if ((recvfrom(sockfd, buff, sizeof(buff), 0, (struct sockaddr *) sndaddr, &plen))
It should work if you fill plen with valid sizeof data.
*plen = sizeof(struct sockaddr_in);
You can put that right before the recvfrom call.
I am trying to create a void mksockaddr(int af, int proto, char addr[], struct sockaddr* dst) that creates a sockaddr structure, here's what I've done:
void sockaddr(int af, int port, char addr[], struct sockaddr* dst) {
if (af == AF_INET) {
struct sockaddr_in s;
s.sin_family = af;
s.sin_port = htons(port);
inet_pton(af, addr, &s.sin_addr);
memcpy(dst, &s, sizeof(s));
} else {
struct sockaddr_in6 s;
s.sin6_family = af;
s.sin6_port = htons(port);
s.sin6_flowinfo = 0;
inet_pton(af, addr, &s.sin6_addr);
memcpy(dst, &s, sizeof(s));
}
}
This seems to be no problem with AF_INET (IPv4), I can bind() without any problem, but when I try to use AF_INET6, bind() give me Invalid argument.
Here's the code I use to bind():
int sock_fd = socket(AF_INET6, SOCK_RAW, proto);
struct sockaddr sin;
sockaddr(AF_INET6, proto, src, &sin);
if(bind(sock_fd, &sin, sizeof(sin)) < 0) {
fprintf(stderr, "[ERR] can't bind socket: %s\n", strerror(errno));
exit(1);
} // got Invalid argument
However, I can bind() just fine if I construct a sockaddr_in6 myself:
struct sockaddr_in6 sin;
sin.sin6_port = htons(proto);
sin.sin6_family = AF_INET6;
inet_pton(AF_INET6, src, &sin.sin6_addr);
if(bind(sock_fd, (struct sockaddr*) &sin, sizeof(sin)) < 0) {
fprintf(stderr, "[ERR] can't bind socket.\n");
exit(1);
} // work just fine
So I cast the sockaddr created by the function back to sockaddr_in6, and I can see that all the fields are same except sin6_scope_id. To my understanding, sin6_scope_id does not matter unless I'm dealing with a link-local IPv6 address.
Am I missing anything here?
From a C perspective, for your code to be certain to work as intended, the caller must pass a valid pointer to the correct structure type in the dst argument. Your example does not do this. Instead, it declares a struct sockaddr, and passes a pointer to that. Type struct sockaddr itself is never meant to be used as the type of an actual object, and it is not large enough for all possible address types. In particular, it is not large enough for an IPv6 address.
On the other hand, POSIX plays a bit more fast and loose than standard C requires for conforming programs. This is especially evident with socket addresses. It defines a type struct sockaddr_storage to serve exactly your purpose: it is large enough and has appropriate alignment to hold the data of any supported socket address type. The docs specifically mention its use in generically supporting both IPv4 and IPv6. POSIX also sanctions casting among different socket address pointer types, although this leads to violations of C's struct aliasing rule.
Thus, I would rewrite your function to use struct sockaddr_storage explicitly, and I would furthermore simplify my code via appropriate casts. Moreover, I would have my function tell me the usable size of the address structure, which encompasses only that portion that is initialized:
void populate_sockaddr(int af, int port, char addr[],
struct sockaddr_storage *dst, socklent_t *addrlen) {
if (af == AF_INET) {
struct sockaddr_in *dst_in4 = (struct sockaddr_in *) dst;
*addrlen = sizeof(*dst_in4);
memset(dst_in4, 0, *addrlen);
dst_in4->sin_family = af;
dst_in4->sin_port = htons(port);
inet_pton(af, addr, &dst_in4->sin_addr);
} else if (af == AF_INET6) {
struct sockaddr_in6 *dst_in6 = (struct sockaddr_in6 *) dst;
*addrlen = sizeof(*dst_in6);
memset(dst_in6, 0, *addrlen);
dst_in6->sin6_family = af;
dst_in6->sin6_port = htons(port);
// unnecessary because of the memset(): dst_in6->sin6_flowinfo = 0;
inet_pton(af, addr, &dst_in6->sin6_addr);
} // else ...
}
You would then use it like so:
struct sockaddr_strorage addr;
socklen_t addrlen;
populate_sockaddr(af, port, src, &addr, &addrlen);
if (bind(sock_fd, (struct sockaddr *) &addr, addrlen) < 0) {
// ...
}
Note that the cast of &addr to type struct sockaddr * is utterly routine.
I've declared a pointer to the following struct in my main function
struct sockaddr_in* server;
I'm using this struct to a function that returns a socket descriptor bound to this struct.
int openSocket(char* ip_addr, int port, struct sockaddr_in* server){
int sockfd, len;
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if(sockfd < 0){
perror("Failed to open socket: ");
exit(-1);
}
len = sizeof(server);
bzero(&server, len);
server->sin_family= AF_INET;
inet_aton(ip_addr, &server->sin_addr);
server->sin_port= htons(port);
if((bind(sockfd, (struct sockaddr*)&server, len)) < 0){
perror("Bind failed: ");
exit(-1);
}
return sockfd;
}
However when I try to read the individual fields in the struct that was passed into the function, I get a seg fault. That is when I run the following code in my main
sockfd = openSocket(vector->ip_addr, vector->port, server);
printf("%s %d\n", inet_ntoa(server->sin_addr), htons(server->sin_port) );
The values being passed into the openSocket function are correct.
I get a segmentation fault. Any help appreciated.
After I looked through your codes again, I found there are three mistakes.
In main(), you just declared one pointer to struct sockaddr_in, but you didn't assign it, you can define struct sockaddr_in server and pass &server to openSocket().
In openSocket, "server" is declared to pointer, but your statements len = sizeof(server); bzero(&server, len); are not correct, this is where your segmentation violation occurs.
In openSocket(), bind(sockfd, (struct sockaddr*)&server, len) is not correct, you don't need to use &server, just use server.
So you should change your code as below:
len = sizeof(server); ----> len = sizeof(struct sockaddr_in)
bzero(&server, len); ----> bzero(server, len);
if((bind(sockfd, (struct sockaddr*)&server, len)) < 0){ ----->
if((bind(sockfd, (struct sockaddr*)server, len)) < 0){
struct sockaddr_in* server;
sockfd = openSocket(vector->ip_addr, vector->port, server);
printf("%s %d\n", inet_ntoa(server->sin_addr), htons(server->sin_port) );
---->
struct sockaddr_in server;
sockfd = openSocket(vector->ip_addr, vector->port, &server);
printf("%s %d\n", inet_ntoa(server.sin_addr), htons(server.sin_port) );
You just declared "server" as a pointer to struct sockaddr_in, but you didn't assign it. You can do it like below:
struct sockaddr_in server;
sockfd = openSocket(vector->ip_addr, vector->port, &server);
printf("%s %d\n", inet_ntoa(server.sin_addr), htons(server.sin_port) );
bind(sockfd, (struct sockaddr*)&server, len)
The problem is here. server is already a pointer. You should not take its address.
bind(sockfd, (struct sockaddr*)server, len)
And, as pointed out by #nos, you need to initialize it somewhere. There's no reason for the static variable to be a pointer. It can just be a struct sockaddr_in.
Here's my problem:
I'm trying to fill a socket address struct with the appropriate information so that I can use it in a program the handles communication between a server and a client. This is part of the server code. The problem is that it segfaults. When I run gdb, it says that the seg fault occurs when I assign AF_INET to the sin_family attribute for the servaddr struct.
code:
servaddr->sin_family = (short)(AF_INET);
I can't seem to figure out why this occurs.
Here's the full code:
// Function Prototypes
struct sockaddr_in* getServerInfo(char[]);
int main()
{
char hostname[MAXHOSTNAMELEN];
struct sockaddr_in* servaddr = getServerInfo(hostname);
return 0;
} // End main
struct sockaddr_in* getServerInfo(char hostname[])
{
struct sockaddr_in* servaddr = malloc((size_t)sizeof(struct sockaddr_in));
gethostname(hostname, 32);
struct hostent *hostptr;
hostptr = gethostbyname(hostname);
memset((void *) &servaddr, 0, (size_t)sizeof(servaddr));
servaddr->sin_family = (short)(AF_INET);
memcpy((void *)& servaddr->sin_addr, (void *) hostptr->h_addr, hostptr->h_length);
servaddr->sin_port = htons((u_short)8000);
return servaddr;
}
Your bug is here:
memset((void *) &servaddr, 0, (size_t)sizeof(servaddr));
Do this instead:
memset((void *) servaddr, 0, (size_t)sizeof(*servaddr));
Otherwise you're zeroing the pointer for servaddr, (i.e. turning it into NULL). This then explodes when you try and use it.
Similarly you'll need to change your memcpy call.
Hi I have programmed linux daemon who sends files in udp packets.
problem is that in string "abc\0asdf" it sends only abc not null character and asdf (all characters after null symbol),
there is udp client code, which send packets:
int sock;
struct sockaddr_in server_addr;
struct hostent *host;
host= (struct hostent *) gethostbyname((char *)ip);
if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1){
perror("socket");
exit(1);
}
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(port);
server_addr.sin_addr = *((struct in_addr *)host->h_addr);
memset(server_addr.sin_zero,0,8);
and code which send buffer:
if (sendto(sock, buf, sizeof buf, 0, (struct sockaddr *)&server_addr, sizeof(struct sockaddr))==-1)
in serverside I need to receive binary buffer:
defining socket code:
int sock;
int addr_len, bytes_read;
struct sockaddr_in server_addr , client_addr;
if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
perror("Socket");
exit(1);
}
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(port);
server_addr.sin_addr.s_addr = INADDR_ANY;
//bzero(&(server_addr.sin_zero),8);
memset(server_addr.sin_zero,0,8);
if (bind(sock,(struct sockaddr *)&server_addr,
sizeof(struct sockaddr)) == -1){
perror("Bind");
exit(1);
}
addr_len = sizeof(struct sockaddr);
diep("sendto()");
and receive buffer (in big loop):
bytes_read = recvfrom(sock,buf,sizeof (buf),0,
(struct sockaddr *)&client_addr, &addr_len);
does anyone know why I didn't receive full buffer?
By looking at the comments, the error is most likely that you treat the received buffer as a string.
If you want to print/output the buffer, you need to convert the null character into something else first.
You should use a for loop to print your received buffer instead of printf:
for (int i=0; i<bytes_read; i++)
printf("%c",buf[i]);
This is incorrect (formatting changed so it fits on a screen for me):
if (sendto(sock,
buf,
sizeof buf,
0,
(struct sockaddr *)&server_addr,
sizeof(struct sockaddr))==-1)
You want sizeof(server_addr) as the length. This will be larger than sizeof(struct sockaddr).
Also, from the manpage:
Return Value
On success, these calls return the number of characters sent. On error, -1 is returned, and errno is set appropriately.
You haven't accounted for the case where it returns some value less than sizeof(buf). Not sure how that can happen but it seems to be something to handle.
My comment on the overall approach is similar to what #jgauffin says. buf is just bytes. It's only a convention for C strings that '\0' terminates them, not a requirement. Typically when using binary byte buffers you also track the size. You're just assuming that all of sizeof(buf) will be used which doesn't make sense. (Suggestion: Perhaps part of your sendto payload should include the size of the message that follows?)