Binding a socket: SIGSEGV - c

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.

Related

Strange behaviour while sending broadcast message

I have two programs: client and server. They're trying to find themselves in local network using broadcast.
Client sends simple packet on broadcast with SERVER_PORT (known before) and server prints info about connection, but when i tried this solution I found some strange behavaiour, when I uncomment last two lines of server.c server prints (one custom struct)
Connection from: 0.0.0.0 on port: 0
after commenting those lines everything works properly, am I missing something?
server.c
int broadcast_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
struct sockaddr_in broadcast_addr;
broadcast_addr.sin_addr.s_addr = INADDR_ANY;
broadcast_addr.sin_port = htons(SERVER_PORT);
broadcast_addr.sin_family = AF_INET;
if (bind(broadcast_socket, (struct sockaddr *)&broadcast_addr,
sizeof(broadcast_addr))) {
perror("bind");
}
struct sockaddr_in recv_addr;
char buf[MAX_PACKET_SIZE];
socklen_t len;
if (recvfrom(broadcast_socket, buf, MAX_PACKET_SIZE, 0,
(struct sockaddr *)&recv_addr, &len) < 0) {
perror("recvfrom");
}
printf("Connection from: %s on port: %d\nMessage: %s\n",
inet_ntoa(recv_addr.sin_addr), ntohs(recv_addr.sin_port), buf);
/* struct network_packet packet; */
/* struct sockaddr_in my_addr; */
client.c
int find_server(struct sockaddr_in *out) {
struct sockaddr_in broadcast;
struct network_packet packet;
int yes = 1;
socklen_t len;
broadcast.sin_addr.s_addr = INADDR_ANY;
broadcast.sin_port = htons(CLIENT_PORT);
broadcast.sin_family = AF_INET;
int socket_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (bind(socket_fd, (struct sockaddr *)&broadcast, sizeof(broadcast))) {
perror("bind");
}
if (get_broadcast_addr(&broadcast.sin_addr)) {
return -1;
}
printf("Target address: %s\n", inet_ntoa(broadcast.sin_addr));
broadcast.sin_port = htons(SERVER_PORT);
broadcast.sin_family = AF_INET;
setsockopt(socket_fd, SOL_SOCKET, SO_BROADCAST, &yes, sizeof(yes));
char buf[10] = "test";
sendto(socket_fd, buf, strlen(buf), 0, (struct sockaddr *)&broadcast,
sizeof(broadcast));
if (recvfrom(socket_fd, &packet, sizeof(packet), 0,
(struct sockaddr *)&broadcast, &len) < 0) {
perror("recvfrom");
}
struct sockaddr_in *sa = (struct sockaddr_in *)packet.data;
memcpy(out, sa, packet.header.packet_length);
return 0;
}
struct network_packet_header {
enum network_packet_type type;
int packet_length;
};
struct network_packet {
struct network_packet_header header;
unsigned char data[MAX_DATA_LENGTH];
};
You have to initialize the variable you pass as recvfrom's addrlen to the size of the address struct.

C - Create a sockaddr struct

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.

How to receive and send in different threads with C sockets

I am trying to send and receive in different threads. When I use the code below I get a bad address error, I guess because my server address could not be properly passed to the thread function.
Code:
#include "client.h"
struct global_table{
struct sockaddr_in *serveraddr;
int sockID;
};
void *recvFromServer(struct global_table *rec){
char recBuf[RECVBUFSIZE];
int serverSize = sizeof(rec->serveraddr);
while(1)
{
int n = recvfrom(rec->sockID, recBuf, RECVBUFSIZE, 0, &rec->serveraddr, &serverSize);
if (n < 0)
perror("ERROR in recvfrom");
decryptData(recBuf);
printf("Recieved: %s\n", recBuf);
pthread_exit(NULL);
}
}
void pingServer(char *hostname, int portno)
{
int sockfd, n, serverlen;
struct sockaddr_in serveraddr;
struct sockaddr_in client_addr;
struct hostent *server;
char *buf;
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0)
perror("ERROR opening socket");
server = gethostbyname(hostname);
if (server == NULL)
perror("ERROR, no host found");
bzero((char *) &serveraddr, sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
bcopy((char *)server->h_addr, (char *)&serveraddr.sin_addr.s_addr, server->h_length);
serveraddr.sin_port = htons(portno);
client_addr.sin_family = AF_INET;
client_addr.sin_addr.s_addr = htonl(INADDR_ANY);
client_addr.sin_port = htons(5500);
if (bind(sockfd,(struct sockaddr *)&client_addr, sizeof(struct sockaddr)) == -1)
perror("Socket could not be binded");
if(setsockopt(sockfd,IPPROTO_IP,IP_TOS,&tos,sizeof(tos)))
perror("Could not set socket option");
pthread_t threads[2];
serverlen = sizeof(serveraddr);
struct global_table server_info;
server_info.sockID = sockfd;
server_info.serveraddr = &serveraddr;
pthread_create(&threads[0],NULL,recvFromServer, &server_info); // Trying to recv on a different thread
pthread_join(threads[0],NULL);
}
int main(int argc, char **argv) {
char *hostname;
int portno;
if (argc != 3)
perror("usage: <hostname> <port>\n");
hostname = argv[1];
portno = atoi(argv[2]);
pingServer(hostname, portno);
return 0;
}
How can I fix the problem?
In addition to the problems noted in the comments (and by now, this problem is also noted in the comments...), this line
struct global_table server_info;
creates a local variable in your pingServer() function.
This line
pthread_create(&threads[0],NULL,recvFromServer, &server_info); // Trying to recv on a different thread
of code passes the address of that variable to the recvFromServer() function, which will run in a different thread. But then pingServer() immediately returns and the local server_info variable ceases to exist.
One fix is to define the server_info and serveraddr variable as static:
static struct global_table server_info;
static struct sockaddr_in serveraddr;
That will create one copy of the server_info variable that will be shared by every invocation of pingServer(), but that one copy will exist for the lifetime of your program.

Opening a socket using a function in C

I'm trying to open a socket in UDP and subsequently send a message using it. This is the code that opens the socket.
sockfd = startServer(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.s_addr);
server.sin_port= htons(port);
if((bind(sockfd, (struct sockaddr*)&server, len)) < 0){
perror("Bind failed: ");
exit(-1);
}
return sockfd;
}
Now to send a message on this socket. I use this function.
void sendMessage(char* msg, int sockfd, struct sockaddr_in client, int len){
int sbytes = 0;
sbytes = sendto(sockfd, msg, strlen(msg), 0, (struct sockaddr*)&client, len);
if(sbytes < 0){
perror("Error sending message: ");
}
printf("Routing vector sent to %s\n", inet_ntoa(client.sin_addr));
}
I keep getting the following error.
error: incompatible pointer types passing 'in_addr_t *' (aka 'unsigned int *') to parameter of type 'struct in_addr *' [-Wincompatible-pointer-types]
inet_aton(ip_addr, &server.sin_addr.s_addr);
^~~~~~~~~~~~~~~~~~~~~~~
Any help appreciated.
The second parameter to inet_aton expects a struct in_addr *. You're passing in &server.sin_addr.s_addr, which is an in_addr_t *.
What you want is this:
inet_aton(ip_addr, &server.sin_addr);
Since server.sin_addr is a struct in_addr.

Simple UDP server reply not working

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.

Resources