How to receive and send in different threads with C sockets - c

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.

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.

Binding a socket: SIGSEGV

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.

client server socket programming c-linux

I'm writing a chat room program that communicates over network using TCP. If user provide ip address as a command line argument, the program would attempt to connect to that address. If not, server will wait for others to connect.
The server has no problem receiving whatever text message the client send. However, the client side only receives text messages from server only when it sends its own message. How do I fix that so that client side receives messages right away? This is my code
Server code:
#define MAX_CLIENTS 100
static unsigned int cli_count = 0;
static int uid = 10;
typedef struct {
struct sockaddr_in addr;
int connfd;
int uid;
char name[32];
} client_t;
client_t *clients[MAX_CLIENTS];
void queue_add(client_t *cl)
{
int i;
for(i=0;i<MAX_CLIENTS;i++)
{
if(!clients[i])
{
clients[i] = cl;
return;
}
}
}
void queue_delete(int uid)
{
int i;
for(i=0;i<MAX_CLIENTS;i++)
{
if(clients[i])
{
if(clients[i]->uid == uid)
{
clients[i] = NULL;
return;
}
}
}
}
void send_message_all(char *s)
{
int i;
for(i=0;i<MAX_CLIENTS;i++)
{
if(clients[i])
{
write(clients[i]->connfd, s, strlen(s));
}
}
}
void *hanle_client(void *arg)
{
char buff_in[256];
char buff_out[256];
int rlen;
cli_count++;
client_t *cli = (client_t *)arg;
sprintf(buff_out, "<<JOIN, HELLO %s\r\n", cli->name);
send_message_all(buff_out);
bzero(buff_in,sizeof(buff_in));
while((rlen = read( cli->connfd,buff_in,sizeof(buff_in)-1))>0)
{
sprintf(buff_out, "[%s] %s\r\n", cli->name, buff_in);
send_message_all(buff_out);
}
close(cli->connfd);
/* Delete client from queue and yeild thread */
queue_delete(cli->uid);
free(cli);
cli_count--;
pthread_detach(pthread_self());
return NULL;
}
int main(int argc, char *argv[])
{
int listenfd = 0, connfd = 0, portno;
struct sockaddr_in serv_addr;
struct sockaddr_in cli_addr;
pthread_t tid;
if (argc < 2) {
printf("ERROR, no port provided\n");
exit(1);
}
//Create socket
listenfd= socket(AF_INET , SOCK_STREAM , 0);
if (listenfd == -1)
{
printf("Could not create socket");
}
bzero((char *) &serv_addr, sizeof(serv_addr));
portno = atoi(argv[1]);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(portno);
/* Bind */
if(bind(listenfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0)
{
perror("Socket binding failed");
return 1;
}
/* Listen */
if(listen(listenfd, 10) < 0)
{
perror("Socket listening failed");
return 1;
}
printf("<[SERVER STARTED]>\n");
socklen_t clilen = sizeof(cli_addr);
/* Accept clients */
while( (connfd = accept(listenfd, (struct sockaddr *)&cli_addr, (socklen_t*)&clilen)))
{
/* Client settings */
client_t *cli = (client_t *)malloc(sizeof(client_t));
cli->addr = cli_addr;
cli->connfd = connfd;
cli->uid = uid++;
sprintf(cli->name, "%d", cli->uid);
/* Add client to the queue and fork thread */
queue_add(cli);
pthread_create(&tid, NULL, &hanle_client, (void*)cli);
}
}
Client code:
int main(int argc , char *argv[])
{
int sockfd, portno ;
struct sockaddr_in serv_addr;
struct hostent *server;
char message[2000],server_reply[2000];
if (argc <3)
{
fprintf(stderr,"usage %s hostname port\n", argv[0]);
exit(1);
}
portno = atoi(argv[2]);
//Create socket
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
{
perror("ERROR opening socket");
exit(1);
}
server = gethostbyname(argv[1]);
if (server == NULL) {
fprintf(stderr,"ERROR, no such host\n");
exit(1);
}
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
bcopy((char *)server->h_addr, (char *)&serv_addr.sin_addr.s_addr, server->h_length);
serv_addr.sin_port = htons(portno);
//Connect to remote server
if (connect(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0)
{
perror("ERROR connecting");
exit(1);
}
puts("Connected\n");
//keep communicating with server
while(1)
{
//Receive a reply from the server
bzero(server_reply,2000);
if( recv(sockfd , server_reply , 2000,0) < 0)
{
puts("recv failed");
break;
}
printf("%s", server_reply);
server_reply[0]='\0';
//Send Message to server
printf("Enter Message:");
bzero(message,2000);
fgets(message, sizeof(message),stdin);
if(send(sockfd , message , strlen(message),0) < 0)
{
puts("Send failed");
return 0;
}
}
close(sockfd);
return 0;
}
I am not sure if I understood your problem correctly. But at a high level, I noticed that your hanleClient method calls close(cli->connfd) on the clients socket after calling sendall. After calling close, you are deleting the client details from the queue. This way, the client being deleted will never receive any future messages. Are you sure this is what you want?
Try removing these lines and check if that is what you want -
close(cli->connfd);
/* Delete client from queue and yeild thread */
queue_delete(cli->uid);
free(cli);
cli_count--;
This way, whenever the server receives a message, it will try to send it to all clients that are connected to the server.
Note: Your code is not thread safe and will result in unexpected behaviour since you are accessing global data from within threads without using mutexes.

C Linux Sockets( Server Client Synchronization issue )

I have written a sample socket program in C on Linux.
The server is single process server.
The program is simple where the server is running and the client connects to the server waiting on accept() call.
When the server accepts the client request it sends some string to the client using write call.
Server Code:
#define MAXHOSTNAME 256
#define MAX_CONN 10
void single_process_server(unsigned int portNumber)
{
int listenSockFd, acceptSockFd, portNo;
socklen_t clilen;
char buffer[256] = "Connected";
struct sockaddr_in srvInfo;
int n;
char sysHost[MAXHOSTNAME+1]; // Hostname of this computer we are running on
if((listenSockFd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
close(listenSockFd);
error("ERROR opening socket");
}
bzero((char *) &srvInfo, sizeof(srvInfo));
portNo = portNumber;
srvInfo.sin_family = AF_INET;
srvInfo.sin_addr.s_addr = htonl(INADDR_ANY);
srvInfo.sin_port = htons(portNo);
if (bind(listenSockFd, (struct sockaddr *) &srvInfo, sizeof(srvInfo)) < 0)
{
close(listenSockFd);
error("ERROR on binding");
}
listen(listenSockFd,5);
while(1)
{
clilen = sizeof(srvInfo);
if((acceptSockFd = accept(listenSockFd, (struct sockaddr *) &srvInfo, &clilen)) < 0)
{
error("ERROR on accept");
}
if((n = write(acceptSockFd,buffer,255)) < 0)
{
error("ERROR writing to socket");
}
close(acceptSockFd);
}
close(listenSockFd);
}
int main(int argc, char* argv[])
{
unsigned int portNo= 0;
portNo = 444;
single_process_server(portNo);
return(0);
}
The client receives the string using read call.
Client Code:
void simple_internet_client(char hostip[], unsigned int portNo)
{
int sockFd, portno, n;
struct sockaddr_in srvInfo;
struct hostent *server;
char buffer[256];
portno = portNo;
if((sockFd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
error("ERROR opening socket");
}
if((server = gethostbyname(hostip)) == NULL)
{
fprintf(stderr,"ERROR, no such host\n");
exit(0);
}
bzero((char *) &srvInfo, sizeof(srvInfo));
srvInfo.sin_family = AF_INET;
bcopy((char *)server->h_addr, (char *)&srvInfo.sin_addr.s_addr, server->h_length);
srvInfo.sin_port = htons(portno);
if(connect(sockFd,(struct sockaddr *) &srvInfo,sizeof(srvInfo)) < 0)
error("ERROR connecting");
{
bzero(buffer,256);
if((n = read(sockFd,buffer,255)) < 0)
error("ERROR reading from socket");
printf("Socket read = %s\n", buffer);
}
close(sockFd);
}
main(int argc, char* argv[])
{
char hostip[50] = {0};
unsigned int portNo= 444;
printf("B. Provide the host name or IP:\n");
scanf("%s",&hostip);
simple_internet_client(hostip, portNo);
return(0);
}
When I run the client(./clientdemo) at some intervals then the client receives whatever string the server sends.
But when I run the client multiple times through some script then the client remains stuck up at read() call and does not receive what the server has sent.
Simply speaking when the client connects to the server at faster rate then the server writes to the socket at same rate.But the client is not able to read the data written on the socket and remains stuck up on the read() call.
What may be the cause of this and why client is not able to read data from socket at same rate as server writes to it?

bind() returning permission denied C [duplicate]

This question already has answers here:
Socket programing Permission denied
(3 answers)
Closed 7 years ago.
I'm trying to write a program that receive the port number as a command-line argument and start an HTTP server. I'm passing a listenfd to accept() to do this. However, I'm getting a permission denied from my open_listenfd() then a bad descriptor error from Accept().
The open_listenfd() and Accept() functions are copied from
http://csapp.cs.cmu.edu/2e/ics2/code/src/csapp.c
I'm passing port 100 to the program:
int open_listenfd(int port)
{
int listenfd, optval=1;
struct sockaddr_in serveraddr;
/* Create a socket descriptor */
if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
return -1;
/* Eliminates "Address already in use" error from bind */
if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, (const void *)&optval , sizeof(int)) < 0)
return -1;
/* Listenfd will be an endpoint for all requests to port on any IP address for this host */
bzero((char *) &serveraddr, sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
serveraddr.sin_port = htons((unsigned short)port);
if (bind(listenfd, (SA *)&serveraddr, sizeof(serveraddr)) < 0)
return -1;
/* Make it a listening socket
* ready to accept connection
* requests */
if (listen(listenfd, LISTENQ) < 0)
return -1;
return listenfd;
}
int Open_listenfd(int port)
{
int rc;
if ((rc = open_listenfd(port)) < 0)
unix_error("Open_listenfd error");
return rc;
}
int Accept(int s, struct sockaddr *addr, socklen_t *addrlen)
{
int rc;
if ((rc = accept(s, addr, addrlen)) < 0)
unix_error("Accept error");
return rc;
}
int main(int argc, char **argv) {
int listenfd, connfd, port, clientlen;
struct sockaddr_in clientaddr;
struct hostent *phost;
char *phostaddr;
port = atoi(argv[1]);
listenfd = Open_listenfd(port);
clientlen = sizeof(clientaddr);
connfd = Accept(listenfd, (SA *)&clientaddr, &clientlen);
printf("%d\n", connfd);
printf("%s\n", strerror(errno));
return 0;
}
Another question is that if I want to the server to constantly accept() connections, read requests of the form
GET /path HTTP/1.1\r\n\r\n
How do I do this?
Ports below 1024 are considered to be privileged in Linux, so you're going to need be the root user to open a socket on a ports < 1024

Resources