Communicating between C and NodeJS using node-ipc and unix sockets - node.js

This question follows on from the following:
Communicating between NodeJS and C using node-ipc and unix sockets
In regards to the accepted solution (https://stackoverflow.com/a/39848936/1834057), I was wondering if someone might be able to clarify exactly how to send data from C to Node.js. The solution demonstrates sending data from Node.js to C, but not in reverse. I have an application that requires two-way communications, so the missing component is critical for me.
My understanding of unix sockets that one of either write, send or sendmsg should be able to do the job, however, I am not having any luck. If this understanding is incorrect, please advise.
In order to get a trivial example running, lets say when a message is read in the C code, lets send back a message and try to trigger the ipc.of[socketId].on('message',...) event on the node server.
Which means I am trying to turn this:
while ( (rc=read(cl,buf,sizeof(buf))) > 0) {
printf("read %u bytes: %.*s\n", rc, rc, buf);
}
Into this:
while ( (rc=read(cl,buf,sizeof(buf)) ) > 0) {
printf("read %u bytes: %.*s\n", rc, rc, buf);
//Respond to the node server
int n;
char * msg = "{\"type\":\"message\",\"data\":\"hello response\"}\t";
if((n = write(fd,msg,sizeof(msg))) < 0){
printf("send failed\n");
}else{
printf("sent %d bytes\n", n);
}
}
This would mean that the complete server.c code now becomes:
#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <stdlib.h>
#include <string.h> //Missing from original server.c
char *socket_path = "/tmp/icp-test";
int main(int argc, char *argv[]) {
struct sockaddr_un addr;
char buf[100];
int fd,cl,rc;
if (argc > 1) socket_path=argv[1];
if ( (fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
perror("socket error");
exit(-1);
}
memset(&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;
if (*socket_path == '\0') {
*addr.sun_path = '\0';
strncpy(addr.sun_path+1, socket_path+1, sizeof(addr.sun_path)-2);
} else {
strncpy(addr.sun_path, socket_path, sizeof(addr.sun_path)-1);
unlink(socket_path);
}
if (bind(fd, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
perror("bind error");
exit(-1);
}
if (listen(fd, 5) == -1) {
perror("listen error");
exit(-1);
}
while (1) {
if ( (cl = accept(fd, NULL, NULL)) == -1) {
perror("accept error");
continue;
}
while ( (rc=read(cl,buf,sizeof(buf)) ) > 0) {
printf("read %u bytes: %.*s\n", rc, rc, buf);
//Respond to the node server
int n;
char * msg = "{\"type\":\"message\",\"data\":\"hello response\"}\t";
if((n = write(fd,msg,sizeof(msg))) < 0){
printf("send failed\n");
}else{
printf("sent %d bytes\n", n);
}
}
if (rc == -1) {
perror("read");
exit(-1);
}
else if (rc == 0) {
printf("EOF\n");
close(cl);
}
}
return 0;
}
Now unfortunately, the write message for me returns code -1, and is not received by the node.js server.
The client.js code remains unchanged, and is as provided in the original question.
Can someone please clarify what I am doing wrong?

You have to change
char * msg = "{\"type\":\"message\",\"data\":\"hello response\"}\t";
if((n = write(fd,msg,sizeof(msg))) < 0){
printf("send failed\n");
}else{
printf("sent %d bytes\n", n);
}
to
char * msg = "{\"type\":\"message\",\"data\":\"hello response\"}\f";
if((n = write(cl,msg,strlen(msg))) < 0){
printf("send failed\n");
}else{
printf("sent %d bytes\n", n);
}
The library is waiting for \f at the end of the message :-)
hope the answer is not too late :-)

Related

Linux Socket timeout works on WSL, but not on Ubuntu

I try to run a TCP client without a server. The idea is simply to periodically try to connect.
For this, the client tries to connect to port 1500 on localhost.
Piece of code:
// Create socket
if ((create_socket=socket (AF_INET, SOCK_STREAM, PF_UNSPEC)) > 0)
printf ("Socket created\n");
address.sin_family = AF_INET;
address.sin_port = htons (1500);
inet_aton (argv[1], &address.sin_addr);
// Connect to server
connect ( create_socket,
(struct sockaddr *) &address,
sizeof (address));
FD_ZERO(&fdset);
FD_SET(create_socket, &fdset);
tv.tv_sec = 2; /* 2 seconds timeout */
tv.tv_usec = 0;
rv = select(create_socket + 1, NULL, &fdset, NULL, &tv);
if (rv == 1)
{
int so_error;
socklen_t len = sizeof so_error;
getsockopt(create_socket, SOL_SOCKET, SO_ERROR, &so_error, &len);
if (so_error == 0)
{
printf ("Connection with server (%s) established \n",
inet_ntoa (address.sin_addr));
}
else
{
printf("Error on connect: unsuccessfull\n");
close (create_socket);
continue;
}
}
else if (rv == 0)
{
printf("Timeout on connect\n");
close (create_socket);
continue;
}
else
{
printf("Error on connect\n");
close (create_socket);
continue;
}
I've set it up in Ubuntu 18.04 on WSL. There, the code waits on select for the defined timeout of 2 seconds and returns appropriate return values. (0 on timeout, 1 on connect).
The return value of connect is -1 on WSL and VMware.
In Ubuntu 18 (VMware) there is no pause in that line. In any case, even without any server listening on that port, I get immediately a return value of 1.
Why is there this difference?
There is a similar behavior later on in that code:
tv.tv_sec = 2;
tv.tv_usec = 0;
if (setsockopt(create_socket, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof tv) < 0)
{
printf("Error on setsockopt SO_RCVTIMEO");
exit(EXIT_FAILURE);
}
// INNER LOOP: Receive data
do
{
size = recv(create_socket, buffer, BUF-1, 0);
if( size > 0)
{
buffer[size] = '\0';
printf ("Message received: %s\n", buffer);
}
else if (size == -1)
{
// on VMware, errno is 107 if there is no server, but coming to that line was not intended
printf ("Timeout\n");
}
else //
{
printf("Server offline\n");
// GO BACK TO OUTER LOOP and reconnect
break;
}
Here, in WSL the recv takes up to 2 seconds, while waiting for any incoming data. (But only if the aforementioned block (connect, select) indicates a valid connection)
In VMware I directly get the feedback. (even without connection)
Does it simply work on WSL by chance?
The argument contains the server IP and is 127.0.0.1.
lsof shows no connection.
Update 2020-11-18
Here's the full code as requested by Bodo
#include <iostream>
#include <vector>
#include <string>
#include <sys/types.h>
#include <sys/socket.h>
#include <cstring>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <fcntl.h>
#define BUF 1024
using namespace std;
int main (int argc, char **argv) {
int create_socket;
char *buffer = (char*)malloc(BUF);
struct sockaddr_in address;
int size;
int rv;
struct timeval tv;
fd_set fdset;
// HERE STARTS THE OUTER LOOP - Connect and restart connection
do
{
// Create socket
if ((create_socket=socket (AF_INET, SOCK_STREAM, PF_UNSPEC)) > 0)
printf ("Socket created\n");
address.sin_family = AF_INET;
address.sin_port = htons (15000);
inet_aton ("127.0.0.1", &address.sin_addr);
// Connect to server
int flags = fcntl(create_socket, F_GETFL, 0);
if (flags == -1) return false;
rv = connect ( create_socket,
(struct sockaddr *) &address,
sizeof (address));
printf ("Connect. rv = %i\n", rv);
if (rv == -1)
{
switch (errno)
{
case ECONNREFUSED: printf ("errno = %i (ECONNREFUSED)\n", errno); break;
default: printf ("errno = %i (ECONNREFUSED)\n", errno); break;
}
}
FD_ZERO(&fdset);
FD_SET(create_socket, &fdset);
tv.tv_sec = 2;
tv.tv_usec = 0;
rv = select(create_socket + 1, NULL, &fdset, NULL, &tv);
if (rv == 1)
{
int so_error;
socklen_t len = sizeof so_error;
getsockopt(create_socket, SOL_SOCKET, SO_ERROR, &so_error, &len);
if (so_error == 0)
{
printf ("Connection with server (%s) established \n",
inet_ntoa (address.sin_addr));
}
else
{
printf("Error on connect: unsuccessfull\n");
close (create_socket);
continue;
}
}
else if (rv == 0)
{
printf("Timeout on connect\n");
close (create_socket);
continue;
}
else
{
printf("Error on connect\n");
close (create_socket);
continue;
}
if (setsockopt(create_socket, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof tv) < 0)
{
printf("Error on setsockopt SO_RCVTIMEO");
exit(EXIT_FAILURE);
}
// INNER LOOP: Receive data
do
{
size = recv(create_socket, buffer, BUF-1, 0);
if( size > 0)
{
buffer[size] = '\0';
printf ("Data received: %s\n", buffer);
}
else if (size == -1)
{
printf ("Timeout\n");
}
else //
{
printf("Server offline\n");
// GO BACK TO OUTER LOOP and reconnect
break;
}
} while (strcmp (buffer, "quit\n") != 0);
close (create_socket);
} while (strcmp (buffer, "quit\n") != 0);
return EXIT_SUCCESS;
}
In WSL the output is
Socket created
Connect. rv = -1
errno = 111 (ECONNREFUSED)
then nothing for 2 seconds
afterwards
Timeout on connect
Socket created
Connect. rv = -1
errno = 111 (ECONNREFUSED)
and again nothing for 2 seconds ...
Output in VMware
Socket created
Connect. rv = -1
errno = 111 (ECONNREFUSED)
Connection with server (127.0.0.1) established
Timeout
Timeout
Timeout
Timeout
Where no timeout is fulfilled.
The idea of timeout has been to try to connect on a regular basis, but not as fast as possible.
Obviously there is something wrong when errno = 111 (ECONNREFUSED) is followed by Connection with server (127.0.0.1) established.
When connect returns -1 and errno is NOT EINPROGRESS you should not use selectand getsockopt(...SO_ERROR...). According to https://man7.org/linux/man-pages/man2/connect.2.html, this is only documented for EINPROGRESS.
Both on real Linux and WSL you get errno = 111 (ECONNREFUSED) after a failed connect. I consider the timeout in WSL wrong as the error (conection refused) was already reported, so it does not make sense to wait for a result. But as the behavior is not specified, it may be implementation dependent.
If you want to have a delay before the next connection attempt, you should not use select but for example sleep followed by repeating the loop.
I suggest something like this:
rv = connect ( create_socket,
(struct sockaddr *) &address,
sizeof (address));
printf ("Connect. rv = %i\n", rv);
if (rv == -1)
{
switch (errno)
{
case ECONNREFUSED: printf ("errno = %i (ECONNREFUSED) %s\n", errno, strerror(errno)); break;
default: printf ("errno = %i (other) %s\n", errno, strerror(errno)); break;
}
if(errno != EINPROGRESS)
{
sleep(10); // chose a suitable delay before next connection attempt
continue;
}
}

How to get unbuffered output from popen & fgets

I'm using popen to execute a command and read the output. I'm setting the file descriptor to non-blocking mode so that I can put in my own timeout, as follows:
auto stream = popen(cmd.c_str(), "r");
int fd = fileno(stream);
int flags = fcntl(fd, F_GETFL, 0);
flags |= O_NONBLOCK;
fcntl(fd, F_SETFL, flags);
while(!feof(stream)) {
if(fgets(buffer, MAX_BUF, stream) != NULL) {
// do something with buffer...
}
sleep(10);
}
pclose(stream);
This works just fine, except that fgets keeps returning NULL, until the program has finished executing, at which time it returns all the output as expected.
In other words, even if the program immediately outputs some text and a newline to the stdout, my loop doesn't read it immediately; it only sees it later.
In the documentation for popen I see:
Note that output popen() streams are block buffered by default.
I've tried a few things to turn off buffering (ex. setvbuf(stream, NULL, _IONBF, 0)) , but so far no luck.
How do I turn off buffering so that I can read the output in real-time?
Thank you!
A solution based on something like select() would be more accurate and flexible. Try this :
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <sys/select.h>
void read_cmd(const char *cmd)
{
FILE *stream;
int fd;
int flags;
char buffer[1024];
fd_set fdset;
struct timeval timeout;
int rc;
int eof;
stream = popen(cmd, "r");
fd = fileno(stream);
eof = 0;
while(!eof) {
timeout.tv_sec = 10; // 10 seconds
timeout.tv_usec = 0;
FD_ZERO(&fdset);
FD_SET(fd, &fdset);
rc = select(fd + 1, &fdset, 0, 0, &timeout);
switch(rc) {
case -1: {
// Error
if (errno != EINTR) {
fprintf(stderr, "select(): error '%m' (%d)\n", errno);
}
return;
}
break;
case 0: {
// Timeout
printf("Timeout\n");
}
break;
case 1: {
// Something to read
rc = read(fd, buffer, sizeof(buffer) - 1);
if (rc > 0) {
buffer[rc] = '\0';
printf("%s", buffer);
fflush(stdout);
}
if (rc < 0) {
fprintf(stderr, "read(): error '%m' (%d)\n", errno);
eof = 1;
}
if (0 == rc) {
// End of file
eof = 1;
}
}
break;
} // End switch
} // End while
pclose(stream);
}
int main(int ac, char *av[])
{
read_cmd(av[1]);
return 0;
} // main

Socket Programming Error in Connect

I am trying to do Socket programming. I've google and looked at problems like mine. However, I can't see to figure out my error.
Whenever I run my code, I get an error in connect() in main in client.c. The error is invalid argument.
Server.c
/* chatroom server */
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#include <netdb.h>
#include <pthread.h>
#include <signal.h>
#define MAX_ROOMS 36
#define MAX_NAME_SIZE 56
#define PORT_NUM 12333
#define MSG_SIZE 8
#define MAX_LOAD 246
#define MAX_CRC 64 //max clients
#define MAX_BUF 256
#define SERVER_IP 32
#define DEBUG 0
struct msg {
int type; //create, join, delete
int length; // length or port num
};
struct chat_room {
int socket_d; //socket descriptor
int port;
pthread_t id; //id of chatroom
char name[MAX_NAME_SIZE];
int clients[MAX_ROOMS]; // used to hold the client's master sockets
};
struct chat_room* findRoom(char* name, struct chat_room* chat){
int iterator;
for(iterator = 0; iterator < MAX_ROOMS; iterator++){
if(strcmp(name, chat[iterator].name) && (chat[iterator].port != 0)) {
return &chat[iterator];
}
}
//if room does not exist
return NULL;
}
struct chat_room* joinServer(int chat_socket, char* name, struct chat_room* chat){
struct chat_room* local_chat = findRoom(name, chat);
int i;
if(local_chat != NULL){ //if the chat exists
for(i= 0; i< MAX_CRC; i++){
if(local_chat->clients[i] == 0)
{
local_chat->clients[i] = chat_socket;
}
return local_chat;
}
}
//if server if full or else error
return NULL;
}
int createResponse(int chat_socket, int new_port_num, int type){
struct msg temp;
char temp_buff[MAX_LOAD];
memset(temp_buff, 0, MAX_LOAD);
temp.type = type;
temp.length = new_port_num;
memcpy(temp_buff, &temp, sizeof(temp));
write(chat_socket, temp_buff, MSG_SIZE);
return 0;
}
int joinResponse(int chat_socket, int new_port_num){
struct msg temp;
char temp_buff[MAX_LOAD];
memset(temp_buff, 0, MAX_LOAD);
temp.type = 11;
temp.length = new_port_num;
memcpy(temp_buff, &temp, sizeof(temp));
write(chat_socket, temp_buff, MSG_SIZE);
return 0;
}
int deleteResponse(int chat_socket, struct chat_room* chat){
struct msg temp;
char temp_buff[MAX_LOAD];
int i;
memset(temp_buff, 0, MAX_LOAD);
temp.type = 12;
memcpy(temp_buff, &temp, sizeof(temp));
for(i=0; i<MAX_CRC; i++){
if((chat->clients[i] != chat_socket) && (chat->clients[i] != 0))
write(chat->clients[i],temp_buff, MSG_SIZE);
}
return 0;
}
struct chat_room* addRoom(int chat_socket, char* name, struct chat_room* chat){
int socket_d;
int i;
struct sockaddr_in sock;
static int port = PORT_NUM;
memset(&sock, 0, sizeof(sock));
int temp = -1;
for(i = 0; i<MAX_ROOMS; i++){
if((strcmp(chat[i].name, name) == 0) && (chat[i].port != 0)){
createResponse(chat_socket, chat[i].port, 15);
return NULL;
}
else if((chat[i].port == 0) && (temp== -1)){
temp = i;
}
}
if(temp == -1){
return NULL;
}
socket_d = socket(AF_INET, SOCK_STREAM, 0);
if(socket_d == -1 && DEBUG){
perror("Error creating chatroom socket");
return NULL;
}
sock.sin_family = AF_INET;
port++;
sock.sin_port = htons(port);
if(bind(socket_d, (struct sockaddr*)&sock, sizeof(struct sockaddr_in)) == -1){
perror("error in binding ");
return NULL;
}
chat[temp].socket_d = socket_d;
chat[temp].port = port;
strcpy(chat[temp].name, name);
return &chat[temp];
}
void* chat_room_main(void* chat_room_cluster){
char buf[MAX_LOAD];
int socket_d, chat_socket;
int temp; //temp_fd
int read_val;
int num_clients = 0;
int i;
int clients[MAX_CRC];
fd_set allfd, modfd;
struct chat_room chat_room_para;
memcpy(&chat_room_para, (struct chat_room*)chat_room_cluster, sizeof(struct chat_room));
free(chat_room_cluster);
memset(clients, 0, sizeof(int)*MAX_CRC);
socket_d = chat_room_para.socket_d;
listen(socket_d, 1);
FD_ZERO(&allfd);
FD_SET(socket_d, &allfd);
printf("New Chatroom Started\n");
while(1){
modfd = allfd;
select(FD_SETSIZE, &modfd, NULL, NULL, NULL);
for(temp = 0; temp < FD_SETSIZE; temp++){
if(FD_ISSET(temp, &modfd)){
memset(buf, 0, sizeof(buf));
if(temp == socket_d) {
chat_socket = accept(socket_d, NULL, NULL);
FD_SET(chat_socket, &allfd);
// find an empty spot to add the chat room
for(i = 0; i<MAX_CRC; i++) {
if(clients[i] == 0){
clients[i] = chat_socket;
break;
}
}
sprintf(buf, "Number of people in chatroom: %d", num_clients);
write(chat_socket, buf, strlen(buf));
num_clients++;
}
else{
if(read_val = read(temp, buf, MAX_LOAD) > 0){
for(i = 0; i< MAX_CRC; i++){
if((clients[i] != temp) && (clients[i] != 0)){
write(clients[i], buf, read_val);
}
}
}
else if(read_val <= 0) {
FD_CLR(temp, &allfd);
for(i = 0; i<MAX_CRC; i++){
if(clients[i] == temp)
clients[i] = 0;
}
num_clients--;
close(chat_socket);
}
}
}
}
}
}
int main(int argc, char* argv[]){
int server_socket, chat_socket; //file descriptors for server and chat
int temp; //tempfd
int i, j;
char server_ip[SERVER_IP];
char buf[MAX_BUF];
char msg_buf[MSG_SIZE];
fd_set allfd, modfd;
struct sockaddr_in sock;
struct hostent* host_name;
struct chat_room chatrooms[MAX_ROOMS];
memset(chatrooms, '\0', sizeof(struct chat_room)* MAX_ROOMS);
memset(&sock, '\0', sizeof(sock));
server_socket = socket(AF_INET, SOCK_STREAM, 0);
if(server_socket == -1){
perror("Error creating socket");
return -1;
}
sock.sin_family = AF_INET;
sock.sin_port = htons(PORT_NUM);
sock.sin_addr.s_addr = INADDR_ANY;
if((bind(server_socket, (struct sockaddr*)&sock, sizeof(struct sockaddr_in))) == -1){
perror("Error in bind()");
return -1;
}
listen(server_socket, 1);
FD_ZERO(&allfd);
FD_SET(server_socket, &allfd);
FD_SET(0, &allfd);
printf("\n*******Chatroom Server*******");
while(1){
modfd = allfd;
select(FD_SETSIZE, &modfd, NULL, NULL, NULL);
for(temp = 0; temp < FD_SETSIZE; temp++) {
if(FD_ISSET(temp, &modfd)) {
switch(temp){
case 0:
break;
default:
if(temp == server_socket){
chat_socket = accept(server_socket, NULL, NULL);
}
else{
char msg_buf[MSG_SIZE];
char buf[MAX_LOAD];
char name[MAX_LOAD];
struct msg temp_message;
struct chat_room* local_chat = NULL;
void* (*init_chatroom)() = &chat_room_main;
void* thread_args;
pthread_attr_t attr;
pthread_t tid;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
memset(buf, 0, sizeof(buf));
memset(msg_buf, 0, sizeof(msg_buf));
msg_buf[19]= 0;
int read_val = read(temp, msg_buf, MSG_SIZE);
if(read_val > 0){
memcpy(&temp_message, msg_buf, sizeof(temp_message));
read(temp, buf, temp_message.length - sizeof(temp_message));
memcpy(name, buf, temp_message.length - sizeof(temp_message));
if(temp_message.type == 0) {//if create
local_chat = addRoom(temp, name, chatrooms);
if(local_chat != NULL){
thread_args = (void*)malloc(sizeof(struct chat_room));
memcpy((struct chat_room*) thread_args, local_chat, sizeof(struct chat_room));
pthread_create(&tid, &attr, init_chatroom, thread_args);
local_chat->id = tid;
createResponse(temp, local_chat->port, 10);
}
}
else if(temp_message.type == 1){ //join
local_chat = joinServer(temp, name, chatrooms);
if(local_chat != NULL){
joinResponse(temp, local_chat->port);
}
}
else if(temp_message.type == 2){ //delete
local_chat = findRoom(name, chatrooms);
printf("Deleting Room\n");
if(local_chat != NULL) {
local_chat->port = 0;
close(local_chat->socket_d);
deleteResponse(temp, local_chat);
for(j = 0; j<MAX_CRC; j++){
if(local_chat->clients[j]!=0) {
FD_CLR(local_chat->clients[j], &modfd);
local_chat->clients[j] = 0;
}
}
pthread_cancel(local_chat->id);
}
}
}
else if(read_val <= 0){
FD_CLR(temp, &allfd);
close(temp);
}
}
}
}
}
}
return 0;
}
Client.c
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#include <netdb.h>
#include <pthread.h>
#define PORT_NUM 12333
#define MSG_SIZE 8
#define MAX_LOAD 246
#define MAX_BUF 256
#define SERVER_IP 32
struct msg {
int type;
int length;
};
struct thread_para {
int port;
struct hostent* host_name;
};
int sendCmd(int chat_socket, char* buf, int type){ //function for sending the command
struct msg temp;
char temp_buf[MAX_LOAD];
char name[MAX_LOAD];
int iterator;
if(type == 0){
iterator = 6;
}
else if(type == 1){
iterator = 4;
}
else if(type == 2){
iterator = 6;
}
for(; iterator < strlen(buf); iterator++){
if(buf[iterator] == ' ') {
continue;
}
else{
break;
}
}
strcpy(name, buf+iterator);
memset(temp_buf, 0, MAX_LOAD);
temp.type = type;
temp.length = sizeof(temp)+strlen(name)+1; //for \0
memcpy(temp_buf, &temp, sizeof(temp));
memcpy(temp_buf+sizeof(temp), name, strlen(name)+1);
write(chat_socket, temp_buf, temp.length);
return 0;
}
void* connectChat(int port_num, struct hostent* host_name, int master){
char buf[MAX_BUF];
char temp_buf[MAX_BUF];
int chat_socket;
int i;
int input;
int temp; //temp fd
fd_set allfd, modfd;
struct sockaddr_in sock;
printf("Successfully Joined Room\n");
memset(buf, 0, sizeof(buf));
memset(&sock, 0, sizeof(sock));
sock.sin_family = AF_INET;
sock.sin_port = htons(port_num);
memcpy((char*)&sock.sin_addr.s_addr, host_name->h_addr, host_name->h_length);
chat_socket = socket(AF_INET, SOCK_STREAM, 0);
if(chat_socket == -1){
perror("Error in creation");
return NULL;
}
if(connect(chat_socket, (struct sockaddr*)&sock, sizeof(struct sockaddr)) < 0 ){
perror("Error in connection");
return NULL;
}
FD_ZERO(&allfd);
FD_SET(chat_socket, &allfd);
FD_SET(0, &allfd);
FD_SET(master, &allfd);
while(1) {
modfd = allfd;
select(FD_SETSIZE, &modfd, NULL, NULL, NULL);
for(temp = 0; temp< FD_SETSIZE; temp++){
memset(buf, 0, sizeof(buf));
memset(temp, 0, sizeof(buf));
if(temp == 0) { //reading from standard in
input = read(0, buf, MAX_BUF);
buf[input-1] = '\0'; //add termination to end
write(chat_socket, buf, strlen(buf));
}
else if(temp == chat_socket){
input = read(0, buf, MAX_BUF);
buf[input] = '\0';
memcpy(temp, buf, input);
//display message
printf("%s \n", temp_buf);
}
else if(temp == master){
struct msg temp_message;
input = read(temp, buf, MSG_SIZE);
memcpy(&temp_message, buf, MSG_SIZE);
if(temp_message.type == 12){
printf("Chatroom has been deleted, Shutting down chatroom\n");
return NULL;
}
}
}
}
return 0;
}
int main(int argc, char* argv[]){
char buf[MAX_BUF];
int chat_socket;
int i;
int input;
int temp; //temp fd
int accept_input = 1; // take input for stdin to create a chat thread
fd_set allfd, modfd;
char server_ip[SERVER_IP];
struct hostent* host_name;
struct sockaddr_in sock;
struct msg temp_message;
pthread_attr_t tattr;
pthread_t tid;
if(argc < 2) {
printf("Please try ./crc <server IP> \n");
return -1;
}
pthread_attr_init(&tattr);
pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
memset(&sock, '\0', sizeof(sock));
sock.sin_family = AF_INET;
sock.sin_port = htons(PORT_NUM);
strcpy(server_ip ,argv[1]);
if((host_name = (struct hostent*)gethostbyname(server_ip)) == NULL){
perror("failed to get host name");
return -1;
}
memcpy((char*)&sock.sin_addr.s_addr, host_name->h_addr, host_name->h_length);
chat_socket = socket(AF_INET, SOCK_STREAM, 0);
if(chat_socket == -1){
perror("Error creating socket");
return -1;
}
if((connect(chat_socket, (struct sockaddr*)&sock, sizeof(sock))) < 0) {
perror("Error connecting");
return -1;
}
FD_ZERO(&allfd); /* first, clear the allfd set */
FD_SET(chat_socket, &allfd); /* adding client to the set */
FD_SET(0, &allfd);
printf("*****Welcome to the Chatroom*****\n");
while(1){
modfd = allfd;
select(FD_SETSIZE, &modfd, NULL, NULL, NULL);
for(temp = 0; temp < FD_SETSIZE; temp++){
if(FD_ISSET(temp, &modfd)){
if(temp == 0){
input = read(0, buf, MAX_BUF);
buf[input-1] = '\0'; //remove \n inserts termination
if((strncasecmp(buf, "create ", 7) == 0)) {
sendCmd(chat_socket, buf, 0);
}
else if((strncasecmp(buf, "join ", 5) == 0)) {
sendCmd(chat_socket, buf, 1);
}
else if((strncasecmp(buf, "delete ", 7)==0)){
sendCmd(chat_socket, buf, 2);
}
else
{
printf("Enter a valid command: create <Room_name>, join <Room_name>, delete <Room_name>\n");
}
}
else if(temp == chat_socket){
input = read(temp, buf, MSG_SIZE);
memcpy(&temp_message, buf, sizeof(temp_message));
if(temp_message.type == 10) {
printf("Created Chatroom\n");
}
else if(temp_message.type == 11){
connectChat(temp_message.length, host_name, chat_socket);
fflush(stdin);
}
else if(temp_message.type == 15) {
printf("Chatroom exits. Type join <Room_name> to join\n");
}
}
}
}
}
close(chat_socket);
return 0;
}
I gave both sets of code just in case it was need. The program is designed to create multiple chat rooms.
invalid argument is the EINVAL error code, which in the context of connect() means:
An invalid argument was detected (e.g., address_len is not valid for the address family, the specified address family is invalid).
You have multiple calls to connect() in your client code (why?), but you did not indicate which call is the one that is failing. In connectChat() at least, sizeof(struct sockaddr) should be sizeof(struct sockaddr_in) instead, or better sizeof(sock), like you do in main().
Also, if either connect() fails, you are leaking the socket returned by socket(). You need to close() it.
Also, gethostbyname() is deprecated, you should be using getaddrinfo() instead. You are creating IPv4 sockets, which only work with IPv4 addresses. You are not checking if gethostbyname() actually returns an IPv4 address (host_name->h_addr_type == AF_INET) before copying the address bytes into your sock variable. At least with getaddrinfo(), you can restrict the output to IPv4 addresses only. You don't have that option with gethostbyname().
Since you're looking for a way to figure out your error, I'll suggest you to use the following Makefile:
CFLAGS=-Wall -g -O2
CC=gcc
LDFLAGS=-lpthread
all: Server Client
Server: Server.c
Client: Client.c
After running make command you'll see a lot of warnings. Some of them:
Server.c: In function ‘createResponse’:
Server.c:81:5: warning: ignoring return value of ‘write’, declared with attribute warn_unused_result [-Wunused-result]
write(chat_socket, temp_buff, MSG_SIZE);
^
Server.c: In function ‘chat_room_main’:
Server.c:237:25: warning: ‘chat_socket’ may be used uninitialized in this function [-Wmaybe-uninitialized]
close(chat_socket);
^
Server.c: In function ‘main’:
Server.c:319:36: warning: array subscript is above array bounds [-Warray-bounds]
msg_buf[19]= 0;
Client.c: In function ‘connectChat’:
Client.c:113:20: warning: passing argument 1 of ‘memset’ makes pointer from integer without a cast
memset(temp, 0, sizeof(buf));
^
So just try to fix these warnings. I mean all of them.

Using multi-thread ,Build a simple HTTP server in C

As a school project , i was asked to build a simple HTTP server which can handle and process multiple and simultaneous requests , and to proof that this server will deliver my home page to the internet browser. (Using RFC 1945/HTTP 1.0)
I took a part of my project so you know how it goes
- the server listens to a fixed port. When it receives a TCP connection request, it sets up a TCP connection through another port and services the request in a separate thread. To simplify this programming task, we will develop the code in two stages. In the first stage, you will write a multi-threaded server that simply displays the contents of the HTTP request message that it receives. After this program is running properly, you will add the code required to generate an appropriate response.
Any ideas or samples?
This is a sample of http server with thread pool which I wrote a year ago:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <unistd.h>
#include <pthread.h>
#include <malloc.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/wait.h>
#include <ctype.h>
#include <sys/mman.h>
#include <string.h>
#include <errno.h>
#include <dirent.h>
#include <signal.h>
#define KB 1024
/*function declerations*/
void send_content(int fd, int connfd,int isDir,char* path);
void enqueue(int data);
void* dequeue(void* ptr);
void send_to_client(int connfd, char* line);
/*global vars*/
pthread_mutex_t lock;
pthread_cond_t emp;
int sock =0;
int max_threads =0;
int global_count=0;
int finished =1;
int length=0;
/*Queue*/
struct node{
int info;
struct node *ptr;
}*head,*tail;
struct sigaction ready, last;
int main(int argc, char** argv){
int threads;
int requests;
int port;
int i;
int s;
int len_of_packet=1;
int fd;
int port1;
int file;
char content[16000];
char *fileContent ;
int thrd ;
int rc;
char method[KB];
char path[KB];
int s_len=0;
int r_len=0;
int fileLen;
int parsing;
unsigned int addr_size;
struct sockaddr_in serv_addr, client_addr;
struct stat st;
struct dirent *entry;
DIR *dir;
static fd_set readsocks, socks;
char buf[KB] ;
char Uniform_Resource_Identifier[KB];
int servfd;
int socket_of_accept;
off_t chunk=0;
size_t readData;
int sent;
assert (argc ==3 || argc ==4);
threads = strtol(argv[1], NULL, 10);
if ((errno == ERANGE && (threads == LONG_MAX || threads == LONG_MIN))
|| (errno != 0 && threads == 0)) {
perror("Error: strtol has been failed\n");
exit(0);
}
max_threads = threads;
requests = strtol(argv[2], NULL, 10);
if ((errno == ERANGE && (requests == LONG_MAX || requests == LONG_MIN))
|| (errno != 0 && requests == 0)) {
perror("Error: strtol has been failed\n");
exit(0);
}
port = 80;
if (argc == 4){
port = strtol(argv[3], NULL, 10);
if ((errno == ERANGE && (port == LONG_MAX || port == LONG_MIN))
|| (errno != 0 && port == 0)) {
perror("Error: strtol has been failed\n");
exit(0);
}
}
pthread_t threadsArr[threads];
if(pthread_mutex_init(&lock,NULL)!=0){
printf("Error: failed to init mutex\n");
return 1;
}
pthread_cond_init( &emp, NULL);
head=NULL;
tail=NULL;
/*create threads*/
for (thrd=0; thrd<threads;thrd++){
rc = pthread_create(&threadsArr[thrd], NULL, dequeue, (void*) &thrd);
if (rc){
printf("Error: failed to create thread\n");
return 1;
}
}
/* create socket */
servfd = socket(AF_INET, SOCK_STREAM, 0);
sock = servfd;
if (servfd == -1) {
printf("Error creating socket\n");
exit(1);
}
/* init prepernces */
memset(&serv_addr, '0', sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(port);
/* bind */
setsockopt(servfd, SOL_SOCKET, SO_REUSEADDR, (const char *) &len_of_packet,sizeof(int));
if (bind(servfd, (struct sockaddr*) &serv_addr, sizeof(serv_addr)) == -1) {
printf("Error: Bind has been failed\n");
perror ("Bind: ");
exit(1);
}
/*listen */
if (listen(servfd, requests) == -1) {
printf("Error: Listen has been failed\n");
perror ("Listen: ");
exit(1);
}
FD_ZERO(&socks);
FD_SET(servfd, &socks);
int startLen = strlen("HTTP/1.0 200 OK\r\n"
"Content-Type: text/html; charset=UTF-8\r\n\r\n"
"<doctype !html><html><head><title></title>"
"<style>body"
"h1 { font-size:4cm; text-align: center; color: black;"
"}</style></head>"
"<body><h1>Service Unavailable (HTTP 503)</h1></body></html>\r\n");
int endLen = strlen("</h1></body></html>\r\n");
while(1){
sigfillset(&ready.sa_mask);
ready.sa_handler = SIG_IGN;
ready.sa_flags = 0;
if (sigaction(SIGINT, &ready,&last) || sigaction(SIGINT,&last,NULL)){
finished=0;
for(i=0; i<threads; i++){
rc = pthread_join(threadsArr[i], NULL);
if(rc != 0){
printf("Error: join has been failed\n");
perror("Join: ");
return 1;
}
}
pthread_mutex_destroy(&lock);
close(sock);
}
addr_size = sizeof(client_addr);
socket_of_accept = accept(servfd, (struct sockaddr *) &client_addr, &addr_size);
if (socket_of_accept == -1) {
printf("Error: Accept has been failed\n");
perror ("Accept: ");
exit(1);
}
enqueue(socket_of_accept);
if (length <= requests){
/*recieve message*/
r_len = recv(socket_of_accept, buf, KB,0);
if (r_len == -1){
printf("Error: recieve has been %d\n", socket_of_accept);
close(socket_of_accept);
exit(1);
}
sscanf(buf,"%s %s", method, Uniform_Resource_Identifier);
sscanf(Uniform_Resource_Identifier,"%s", path);
printf("method = %s, path = %s\n", method, path);
/*GET OR POST*/
if(strcmp(method, "GET")!= 0 && strcmp(method, "POST") != 0){
char response[] = "HTTP/1.0 200 OK\r\n"
"Content-Type: text/html; charset=UTF-8\r\n\r\n"
"<doctype !html><html><head><title></title>"
"<style>body"
"h1 { font-size:4cm; text-align: center; color: black;"
"}</style></head>"
"<body><h1>Service Unavailable (HTTP 503)</h1></body></html>\r\n";
s_len = send(socket_of_accept, response, strlen(response), 0);
if (s_len == -1){
printf("Error: failed to send message %s to client %d\n", response, socket_of_accept);
close(socket_of_accept);
exit(1);
}
}
if (stat(path, &st) == -1){ /*file not found*/
char response[] = "HTTP/1.0 200 OK\r\n"
"Content-Type: text/html; charset=UTF-8\r\n\r\n"
"<doctype !html><html><head><title></title>"
"<style>body"
"h1 { font-size:4cm; text-align: center; color: black;"
"}</style></head>"
"<body><h1>Not Found (HTTP 404)</h1></body></html>\r\n";
s_len = send(socket_of_accept, response, strlen(response), 0);
if (s_len == -1){
printf("Error: failed to send message %s to client %d\n", response, socket_of_accept);
close(socket_of_accept);
exit(1);
}
close(socket_of_accept);
}else {
if(S_ISDIR(st.st_mode)){/*directory*/
if((dir = opendir (path)) != NULL){
send_content(fd, socket_of_accept,1,path);
close(socket_of_accept);
}else{
printf("Error: failed to open directory: %s\n", path);
}
}else if(S_ISREG(st.st_mode) && st.st_size != 0){/*regular file*/
fd=open(path,O_RDONLY);
send_content(fd, socket_of_accept,0,path);
close(file);
close(socket_of_accept);
}
else{/*empty file*/
char response[] = "HTTP/1.0 200 OK\r\n"
"Content-Type: text/html; charset=UTF-8\r\n\r\n"
"<doctype !html><html><head><title></title>"
"<style>body"
"h1 { font-size:4cm; text-align: center; color: black;"
"}</style></head>"
"<body><h1> </h1></body></html>\r\n";
s_len = send(socket_of_accept, response, strlen(response), 0);
if (s_len == -1){
printf("Error: failed to send message %s to client %d\n", response, socket_of_accept);
close(socket_of_accept);
exit(1);
}
}
}
}else{/*full queue*/
/*send (HTTP 503)*/
char response[3000] = "HTTP/1.0 200 OK\r\n"
"Content-Type: text/html; charset=UTF-8\r\n\r\n"
"<doctype !html><html><head><title></title>"
"<style>body"
"h1 { font-size:4cm; text-align: center; color: black;"
"}</style></head>"
"<body><h1>Service Unavailable (HTTP 503)</h1></body></html>\r\n";
s_len = send(socket_of_accept, response, strlen(response), 0);
if (s_len == -1){
printf("Error: unable to send a message %s to: %d\n", response, socket_of_accept);
close(socket_of_accept);
exit(1);
}
close(socket_of_accept);
}
}
return 0;
}
void send_content(int fd, int connfd,int isDir,char* path){
char line[KB];
memset(line, 0, sizeof(line));
send_to_client(connfd, "HTTP/1.0 200 OK\r\n\r\n");
int return_value;
if(!isDir){
while ((return_value=read(fd, line, KB)) > 0) {
send_to_client(connfd, line);
memset(line, 0, sizeof(line));
}
if (return_value < 0){
perror("Error read");
send_to_client(connfd, "Error Resorces\n");
return;
}
}
else {
DIR *d;
struct dirent *dir;
d = opendir(path);
if (d)
{
while ((dir = readdir(d)) != NULL)
{
strcpy(line,dir->d_name);
strcat(line,"\n");
send_to_client(connfd,line);
memset(line, 0, sizeof(line));
}
closedir(d);
}
}
}
/*enqueue*/
void enqueue(int data)
{
int rc;
struct node* temp;
temp = (struct node *)malloc(1*sizeof(struct node));
if(temp == NULL){
printf("Error: couldn't allocate memory\n");
exit(1);
}
temp->ptr = NULL;
temp->info = data;
if (pthread_mutex_lock(&lock) !=0){
printf("Error: failed to lock\n");
exit(1);
}
if (length == 0) /*empty queue*/
{
head = temp;
}else
{
tail->ptr = temp;
}
tail = temp;
length++;
rc = pthread_cond_broadcast(&emp);
assert(rc==0);
if (pthread_mutex_unlock(&lock)!=0){
printf("Error: failed to unlock\n");
pthread_exit(0);
}
return;
}
void send_to_client(int connfd, char* line){
int nsent, totalsent;
int notwritten = strlen(line);
/* keep looping until nothing left to write*/
totalsent = 0;
while (notwritten > 0){
/* notwritten = how much we have left to write
totalsent = how much we've written so far
nsent = how much we've written in last write() call */
nsent = write(connfd, line + totalsent, notwritten);
assert(nsent>=0); // check if error occured (client closed connection?)
totalsent += nsent;
notwritten -= nsent;
}
}
/*dequeue*/
void* dequeue(void* ptr)
{
int rc;
int i=0;
int thread = *((int*)ptr);
struct node* temp;
while(finished){
if (pthread_mutex_lock(&lock) !=0){
printf("Error: lock has been failed\n");
pthread_exit(0);
}
while (length == 0)
{
rc = pthread_cond_wait(&emp, &lock);
assert(rc == 0);
}
int info = head->info;
temp = head;
head = head->ptr;
free(temp);
length--;
rc = pthread_cond_broadcast(&emp);
assert(rc==0);
if (pthread_mutex_unlock(&lock)!=0){
printf("Error: unlock has been failed\n");
pthread_exit(0);
}
}
pthread_exit(0);
}

Thread issue in socket Programming

I have the following codes..
server.c
#include <stdio.h>
#include "./../linux.h"
#include "./tcp.h"
#include <pthread.h>
static int clients = 0;
static int* memptr = NULL;
void serve(void*);
int* push(int* memptr, int nsfd) {
clients++;
if (clients == 1)
memptr = (int*)malloc(sizeof(int) * clients);
else
memptr = (int*)realloc(memptr, sizeof(int) * clients);
memptr[clients - 1] = nsfd;
return memptr;
}
int main(int argc, char** argv) {
pthread_t thread[2];
int threadCount = 0;
if (argc != 3){
printf("\nUsage: ./server port_number maximum_clients\n");
return 1;
}
static struct sockaddr_in sock, sock_client;
int len, new_sock_fd;
int sock_fd = socket(PF_INET, SOCK_STREAM, 0);
if (sock_fd == -1){
perror("socket");
exit(1);
}
sock.sin_family = PF_INET;
sock.sin_port = htons(atoi(argv[1]));
sock.sin_addr.s_addr = inet_addr("0.0.0.0");
len = sizeof(sock);
if ( bind(sock_fd, (struct sockaddr *)&sock, len) == -1){
perror("bind");
exit(1);
}
if ( listen(sock_fd, atoi(argv[2])) == -1){
perror("listen");
exit(1);
}
while(1) {
new_sock_fd = accept(sock_fd, (struct sockaddr *)&sock_client, (socklen_t *)&len);
memptr = push(memptr, new_sock_fd);
if (new_sock_fd == -1){
perror("accept");
exit(1);
}
pthread_create(&(thread[threadCount]), NULL, (void*)&serve, (void *)&new_sock_fd);
pthread_join(thread[threadCount++], NULL);
printf("threadCount = %d\n", threadCount);
sleep(1);
}
return 0;
}
void serve(void* fd){
int* new_sock_fd = (int*)fd;
Packet packet;
while(1){
bzero(&packet, sizeof(packet));
read(*new_sock_fd , &packet, sizeof(packet));
printf("%d\n", *new_sock_fd);
//printf("recipientId = %d\n", packet.recipientId);
// printf("message = %s\n", packet.data);
write(memptr[packet.recipientId - 1], packet.data, 1024);
}
pthread_exit(0);
}
and the tcp.h looks like
#ifndef __TCP_H__
# define __TCP_H__
typedef struct {
int recipientId; // this is the reciever ID
char data[1024]; // this is the main data part
}Packet;
#endif /* __TCP_H__ */
and each client.h looks like this
#include <stdio.h>
#include "./../linux.h"
#include "./tcp.h"
#include <pthread.h>
void print(void);
void scan(void);
int sock_fd;
int main(int argc, char** argv) {
if (argc != 3){
printf("\nUsage: ./client port_number server_ip\n");
return 1;
}
static struct sockaddr_in sock;
int len;
pthread_t thread1, thread2;
sock_fd = socket(PF_INET, SOCK_STREAM, 0);
if (sock_fd == -1){
perror("socket");
exit(1);
}
sock.sin_family = PF_INET;
sock.sin_port = htons(atoi(argv[1]));
sock.sin_addr.s_addr = inet_addr(argv[2]);
len = sizeof(sock);
if ( connect(sock_fd, (struct sockaddr *)&sock , len) == -1 ){
perror("connect");
exit(1);
}
pthread_create(&thread1, NULL, (void*)&print, NULL);
pthread_create(&thread2, NULL, (void*)&scan, NULL);
pthread_join(thread1, NULL);
pthread_join(thread2, NULL);
return 0;
}
void print(){
char messege[1024];
while(1){
if (read(sock_fd, messege, 1024) == -1){
perror("read");
return;
}
printf("messege = %s\n", messege);
}
pthread_exit(0);
}
void scan(void){
Packet packet;
while(1){
printf("Enter the reciver ID: ");
scanf("%d", &packet.recipientId);
printf("Enter the data: ");
scanf("%s", packet.data);
if ( write(sock_fd, &packet, sizeof(packet)) == -1) {
perror("read");
return;
}
}
pthread_exit(0);
}
Now the problems are
when I am running the server & the in 2 terminals, 2 clients after each client is accepted threadCount should be printed at the server end but it is not printing. It means the execution stops/skips after the first pthread_join but WHY ??
After connecting two threads, when I sent the data from 1st client to the 1st client itself, it works but not from the 1st client to the 2nd client..rather it is sending to the server terminal window. WHY ??
When sent from the second client nothing works ( sending itself or client 1)..WHY??
Please help..And thanks for patiently reading all the codes above.
TCP is a byte stream protocol, not a message protocol. You are calling TCP functions and expecting them to send or receive messages. They don't. If you want to send or receive messages, you have to implement a message protocol, write functions that send and receive messages, and then call those functions.
if (read(sock_fd, messege, 1024) == -1){
perror("read");
return;
}
printf("messege = %s\n", messege);
This call to printf is a disaster. The %s format specifier is for C-style strings, not arbitrary chunks of bytes received from a byte stream. For the most obvious way to see how bad this is, consider this --- how should printf decide how many bytes to print? You threw away the value read returned after you compared it to -1, so you have no idea how many bytes you received.
I'm sure there are other issues with your code, but the fact that the fundamental design is broken makes it not worth fixing those issues. Instead, design a message protocol and implement that.

Resources