SocketCAN how to send messages as soon as possible without data loss - c

I want to measure the maximum speed at which I can send messages via SocketCan from one Raspberry Pi (sender) using PiCan2 to another Raspberry Pi (recipient). The sender reads a 20KiB file, then each byte is sent separately via CAN. The recipient reads the message and saves it on their side to a file. Then I compare if both files are the same.
Initially, I used sleep () and typed the delay from sending each frame.
Then I sent a message and waited for a reply in the form of an empty frame, after which I sent another message.
Now I wanted to use the msg_flags flag and read MSG_CONFIRM to check if the message was delivered, but it doesn't work properly.
How can I read the MSG_CONFIRM flag? Is there another way to send messages as quickly as possible without taking up all of the buffer space and without losing some of the messages?
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <net/if.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <linux/can.h>
#include <linux/can/raw.h>
#include <unistd.h>
main(void)
{
int i = 0;
int recv_own_msgs = 1;
int flags =0;
int s;
struct msghdr msg;
struct sockaddr_can addr;
struct can_frame frame;
struct ifreq ifr;
char ch;
FILE *fpbr;
ssize_t len;
const char *ifname = "can0";
// *************** read file to send
fpbr = fopen("/home/pi/Desktop/file_to_send.txt", "rb");
if((s = socket(PF_CAN, SOCK_RAW, CAN_RAW)) == -1)
{
perror("Error while opening socket");
return -1;
}
// *******************enable retransmission
setsockopt(s, SOL_CAN_RAW, CAN_RAW_RECV_OWN_MSGS, &recv_own_msgs, sizeof(recv_own_msgs));
strcpy(ifr.ifr_name, ifname);
ioctl(s, SIOCGIFINDEX, &ifr);
addr.can_family = AF_CAN;
addr.can_ifindex = ifr.ifr_ifindex;
if(bind(s, (struct sockaddr *)&addr, sizeof(addr)) == -1)
{
perror("Error in socket bind");
return -2;
}
msg.msg_flags = 0;
while(1)
{
++i;
// read from file to variable
ch = fgetc(fpbr);
frame.can_id = i;
frame.can_dlc = 1;
frame.data[0] = ch;
//send message
write(s, &frame, sizeof(struct can_frame));
//Here I would like to receive msg_flags after each message is sent and read and use MSG_CONFIRM
// to check if the message was correctly received by the other device to be able to send another message
len = recvmsg(s, &msg, flags);
if (msg.msg_flags==MSG_CONFIRM) // msg_flags is 0, not MSG_CONFIRM
{
printf("yes");
}
if (i > 1000)
{
break;
}
}
fclose(fpbr);
return 0;
}

Related

UDP File Transfer Program in C, While loops won't do anything

I am trying to make a file transfer program with UDP, using a stop and wait protocol. The client prompts user to enter the text file to transfer and if exist, the server will find it and send it back in packets (80 char at a time). The part where the client sends the file name and the server receives it works, but once I get into the while(1) loop for the file transfer, nothing happens. Not sure why this is the case, any help will be great! thanks!
Client.c
`#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <libgen.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netdb.h>
#include <errno.h>
/*This source file lies the client side of the file transfer. Its job is to open a
socket and ask to connect with server
It should then ask user for input of the text file they wish to transfer.
Once server sends out the file in packets, the client will then place this data in an
output.txt file, viewable for the user*/
typedef struct packet{
char pktData[80]; //data in each packet
}Packet;
typedef struct frame{
int frame_kind; //ACK:0, SEQ:1 FIN:2
int countOfChar; //count of characters in a packet
int sq_no;
int ack;
Packet packet;
}Frame;
int offset = 4;
int main(){
int sockfd = 0; //socket descriptor
int countOfChar = 0; //count of characters in a packet
char buffer[80]; //data in each packet
char fileName[20];
char pktData[80];
//socklen_t addr_size;
int frame_id = 0;
int frame_id2 = 0;
Frame frame_send; //frame being sent to server (for the filename)
Frame frame_recv; //frame being received from the server (for the data)
Frame name_send;
Frame name_recv;
int ack_recv = 1;
struct sockaddr_in serv_addr;
struct sockaddr_in new_addr;
memset(&serv_addr, '0', sizeof(serv_addr));
// Open a socket
if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0){
printf("Error creating socket");
return 1;
}
// Server address structure
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(20000);
serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
socklen_t addr_size = sizeof(serv_addr);
//Sending File name
printf("\nConnected to server successfully!\nEnter the file name: ");
scanf("%[^\n]%*c",fileName);
printf("\n");
char buff[20];
strcpy(buff, fileName);
sendto(sockfd, &buff, sizeof(buff), 0, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
int new_addr_size = sizeof(new_addr);
//int addr_size = sizeof(serv_addr);
//writing file into output.txt
FILE *fp = fopen("output.txt", "ab");
//loop until theres no more to read
while(1){
int f_recv_size = recvfrom(sockfd, &frame_recv, sizeof(Frame), 0, (struct sockaddr*)&serv_addr, &addr_size);
if (f_recv_size > 0 && frame_recv.frame_kind == 1 && frame_recv.sq_no == frame_id){
fwrite(frame_recv.packet.pktData, 1, sizeof(frame_recv.packet.pktData), fp);
//printf("[+]Frame %d received with %lu data bytes\n",frame_recv.sq_no, sizeof(frame_recv.packet.pktData));
printf("Frame Received");
frame_send.sq_no = 0;
frame_send.frame_kind = 0;
frame_send.ack = frame_recv.sq_no + 1;
sendto(sockfd, &frame_send, sizeof(frame_send), 0, (struct sockaddr*)&serv_addr, addr_size);
printf("[+]Ack Sent\n");
}else{
printf("[+]Frame Not Received\n");
}
frame_id++;
}
close(sockfd);
return 0;
}
Server.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
/*This source file lies the server side of the file transfer. Its job is to listen
for a connection and connect with client when prompted.
It should then read the file with the txt file name and start sending out packets of
80 bytes each with the data of the given file name.*/
typedef struct packet{
char pktData[80]; //data in each packet
}Packet;
typedef struct frame{
int frame_kind; //ACK:0, SEQ:1 FIN:2
int countOfChar; //count of characters in a packet
int sq_no;
int ack;
Packet packet;
}Frame;
int main(){
unsigned int size = 0;
int listenfd = 0;
int connfd = 0;
char file_buff[20];
char buffer[80];
char FLAG[] = "NF"; //No file flag
int frame_id = 0;
int frame_id2 = 0;
Frame name_recv;
Frame name_send;
Frame frame_recv;
Frame frame_send;
int ack_recv;
struct sockaddr_in server_addr, client_addr;
char sendBuff[1025];
size = sizeof(client_addr);
listenfd = socket(AF_INET, SOCK_DGRAM, 0); //listening descriptor
printf("Server initiated...\n");
memset(&server_addr, '0', sizeof(server_addr));
memset(sendBuff, '0', sizeof(sendBuff));
//Local address structure
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
server_addr.sin_port = htons(20000);
//bind to local address
bind(listenfd, (struct sockaddr*)&server_addr, sizeof(server_addr));
// Receiving File Name
recvfrom(listenfd, &file_buff, sizeof(file_buff), 0, (struct sockaddr*)&client_addr, &size);
printf("Filename requested by client = %s\n",file_buff);
if (access(file_buff, F_OK) != -1 ) {
printf("File exist!\n");
FILE *fp = fopen(file_buff,"rb");
while(1){
if(ack_recv == 1){
frame_send.sq_no = frame_id;
frame_send.frame_kind = 1;
frame_send.ack = 0;
fscanf(fp, "%s ", buffer);
strcpy(frame_send.packet.pktData, buffer);
sendto(listenfd, &frame_send, sizeof(Frame), 0, (struct sockaddr*)&client_addr, sizeof(client_addr));
//printf("[+]Frame %d Sent with %lu data bytes\n",frame_send.sq_no, strlen(frame_send.packet.pktData));
printf("Frame Sent");
}
int addr_size = sizeof(server_addr);
int f_recv_size = recvfrom(listenfd, &frame_recv, sizeof(frame_recv), 0 ,(struct sockaddr*)&client_addr, &size);
if( f_recv_size > 0 && frame_recv.sq_no == 0 && frame_recv.ack == frame_id+1){
printf("[+]Ack Received\n");
ack_recv = 1;
}
else{
printf("[-]Ack Not Received\n");
ack_recv = 0;
}
frame_id++;
}
}
else {
printf("File doesn't exist\n");
write(listenfd, FLAG, sizeof(FLAG));
close(listenfd);
return 0;
}
close(listenfd);
return 0;
}
Sorry for all the clutter and unnecessary variables in advanced, I've been trying so many options but nothing's working.
Server's response in terminal
Client's response in terminal
The first problem is that you never initialize ack_recv in the server program before attempting to read it. Reading an uninitialized variable that hasn't had its address taken triggers undefined behavior.
At the very least, a value besides 1 was read so the server is waiting on a read from the client which never comes because the client is waiting on the server. You need to initialize ack_recv to 1 so that the server sends the first part of the file.
The code has more problems than this, however.
The main problem is it assumes that no packets get lost. UDP doesn't guarantee delivery. So if a packet does get lost, one side will be stuck forever waiting for a packet that doesn't arrive. When reading, each side should use select to allow for a timeout while waiting. If the timeout triggers, it should assume that the last packet sent was lost and resend it.
For the client, this also means that it can get multiple copies of a given sequence number from the server if an ACK gets lost. So it should not increment frame_id until it receives that sequence number.
There's also an infinite loop on both sides, as there is a while (1) loop with no break, return, or exit inside. The server needs to know when to stop sending, and it needs some way to let the client know when it's done.
Also, as a general rule, when debugging network programs you should use tcpdump or wireshark to trace the packets traveling in both directions.

I am unable to print message recived from client side in c server using socket?

In debugging I can see that values of rx_buffer changes to what is send from client but printf function and even fputs function is not printng the value on terminal or updating the output file
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <unistd.h>
// Constants defined
#define SERVER_PORT 3333
#define RX_BUFFER_SIZE 1024
#define TX_BUFFER_SIZE 1024
#define MAXCHAR 1000 // max characters to read from txt file
// Global variables
struct sockaddr_in dest_addr;
struct sockaddr_in source_addr;
char rx_buffer[RX_BUFFER_SIZE]; // buffer to store data from client
char tx_buffer[RX_BUFFER_SIZE]; // buffer to store data to be sent to client
char ipv4_addr_str[128]; // buffer to store IPv4 addresses as string
char ipv4_addr_str_client[128]; // buffer to store IPv4 addresses as string
int listen_sock;
char line_data[MAXCHAR];
FILE *input_fp, *output_fp;
int socket_create(struct sockaddr_in dest_addr, struct sockaddr_in source_addr){
int addr_family;
int ip_protocol;
dest_addr.sin_addr.s_addr = htonl(INADDR_ANY);
dest_addr.sin_family = AF_INET;
dest_addr.sin_port = htons(SERVER_PORT);
addr_family = AF_INET;
ip_protocol = IPPROTO_IP;
int sock,p;
printf("Create the socket\n");
sock=socket(addr_family , SOCK_STREAM , 0);
if((bind(sock, (struct sockaddr *)&dest_addr, sizeof(dest_addr)))<0){
perror("Bind failed.");
}
else{
printf("bind done");
}
char client[100];
listen(sock,1);
printf("Waiting for incoming connections...\n");
p = accept(sock, (struct sockaddr *)&source_addr, (socklen_t*)&source_addr);
if(p<0){ perror("accept failed");} printf("Client Address=%s\n",inet_ntop(AF_INET,&source_addr.sin_addr,client,sizeof(client)));
return p;
}
int receive_from_send_to_client(int sock){
char mess[10]="hello";
int len;
len=recv(sock , rx_buffer, sizeof(rx_buffer),0);
send(sock , mess , 5,0);
return 0;
}
int main() {
char *output_file_name = "data_from_client.txt";
// Create socket and accept connection from client
int sock = socket_create(dest_addr, source_addr);
output_fp = fopen(output_file_name, "w");
if (output_fp == NULL){
printf("Could not open file %s\n",output_file_name);
return 1;
}
while (1) {
receive_from_send_to_client(sock);
printf("%s",rx_buffer);
fputs(rx_buffer, output_fp);
fputs("\n", output_fp);
}
return 0;
}
In debugging I can see that values of rx_buffer are changing but not able to put that in file or print the message.
Note:- I am sending message from a python client.
in while ,you should open your file always and after putting data into the file close file descriptor properly.
see this code in main(),
int main() {
char *output_file_name = "data_from_client.txt";
// Create socket and accept connection from client
int sock = socket_create(dest_addr, source_addr);
while (1) {
output_fp = fopen(output_file_name, "a+");
if (output_fp == NULL){
printf("Could not open file %s\n",output_file_name);
return 1;
}
receive_from_send_to_client(sock);
printf("%s",rx_buffer);
fprintf(output_fp,"%s",rx_buffer);
fclose(output_fp);
}
return 0;
}

Simple echo program using sockets in C echoing incorrect message after the first run

I am trying to learn the basic of network communication using sockets in C. My client program takes in a message from the user, echoes it server side and back, and prints out the received message. When I fire both of them up for the first time, they both work exactly as expected. However, if I quit the client side and then fire it up again while keeping the server program running, my echoed messages become off by one.
I assumed it was because the last message is getting caught in the pipe or something, and after poking around, I saw that someone suggested to use shutdown() to flush out the pipe, but that doesn't seem to be working. I also tried to zero out the buffers wherever I thought they may be lingering, but that didn't seem to help, either.
server.c
#include <stdio.h>
#include <errno.h>
#include <sys/socket.h>
#include <resolv.h>
#include <arpa/inet.h>
#include <errno.h>
#include <stdlib.h>
#include <strings.h>
#include <unistd.h>
#define PORT 12403
#define BUFFER_MAX 1024
#define BACKLOG_MAX 1024
int clientSocket;
int serverSocket;
void listening()
{
while (1)
{
struct sockaddr_in clientAddress;
socklen_t addressLength = sizeof(clientAddress);
/*---accept a connection (creating a data pipe)---*/
clientSocket = accept(serverSocket, (struct sockaddr*)&clientAddress, &addressLength);
if (clientSocket > -1)
{
printf("%s:%d connected\n", inet_ntoa(clientAddress.sin_addr), ntohs(clientAddress.sin_port));
break;
}
}
}
int main(int Count, char *Strings[])
{
struct sockaddr_in socketInfo;
char buffer[BUFFER_MAX];
//Create socket
if ((serverSocket = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
perror("Error creating socket");
exit(errno);
}
//Setting the linger option to off and resuse address option to on for testing
int option = 0;
setsockopt(serverSocket, SOL_SOCKET, SO_LINGER, &option, sizeof(option));
option = 1;
setsockopt(serverSocket, SOL_SOCKET, SO_REUSEADDR, &option, sizeof(option));
//Initialize socket information
bzero(&socketInfo, sizeof(socketInfo));
socketInfo.sin_family = AF_INET;
socketInfo.sin_port = htons(PORT);
socketInfo.sin_addr.s_addr = INADDR_ANY;
//Assign a port number to the socket
if (bind(serverSocket, (struct sockaddr*)&socketInfo, sizeof(socketInfo)) != 0)
{
perror("Error binding socket");
exit(errno);
}
//Set socket to listen
if (listen(serverSocket, BACKLOG_MAX) != 0)
{
perror("Error setting socket to listen");
exit(errno);
}
listening();
//Once first socket has been connected, begin echoing process
int i = 0;
while (1)
{
//Clear the buffer
bzero(buffer, BUFFER_MAX);
//Echo back anything sent
//Close connection and begin listening process again if the client disconnects
int sendCheck;
int readCheck;
readCheck = recv(clientSocket, buffer, BUFFER_MAX, 0);
if (readCheck <= 0)
{
shutdown(clientSocket, SHUT_WR);
close(clientSocket);
sleep(1);
listening();
}
sendCheck = send(clientSocket, buffer, BUFFER_MAX, 0);
if (sendCheck <= 0)
{
shutdown(clientSocket, SHUT_WR);
close(clientSocket);
sleep(1);
listening();
}
i++;
}
close(serverSocket);
return 0;
}
client.c
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
#include <stdlib.h>
#include <resolv.h>
#include <netdb.h>
#define PORT 12403
#define LOCALHOST "127.0.0.1"
#define BUFFER_MAX 1024
int socketStatus = 0;
void sigpipeHandler()
{
perror("Connection to server terminated\n");
socketStatus = 0;
}
int main()
{
int mySocket;
struct sockaddr_in socketInfo;
char buffer[BUFFER_MAX];
int count = 0;
//Create socket
if ((mySocket = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
perror("Error creating socket");
exit(errno);
}
//Get IP address of required host machine
char* hostName = "<host name removed>";
int portNumber = PORT;
char* ipAddr = NULL;
struct hostent* host = NULL;
host = gethostbyname(hostName);
ipAddr = inet_ntoa(*((struct in_addr*) host->h_addr_list[0]));
//Initialize server information
bzero(&socketInfo, sizeof(socketInfo));
socketInfo.sin_family = AF_INET;
socketInfo.sin_port = htons(portNumber);
if (inet_aton(ipAddr, (struct in_addr *)&socketInfo.sin_addr.s_addr) == 0)
{
perror("Error assigning IP address");
exit(errno);
}
//Set up sigpipe handler
signal(SIGPIPE, sigpipeHandler);
//Connect to server
if (connect(mySocket, (struct sockaddr*)&socketInfo, sizeof(socketInfo)) != 0)
{
perror("Error connecting");
exit(errno);
}
//Indicate that socket is OK
socketStatus = 1;
while(1)
{
if(!socketStatus) {shutdown(mySocket, SHUT_WR); break;}
printf("Please enter a command.\n");
char command[BUFFER_MAX];
bzero(command, BUFFER_MAX);
fgets(command, sizeof(command), stdin);
send(mySocket, command, BUFFER_MAX, 0);
//Get echoed message
bzero(buffer, BUFFER_MAX);
recv(mySocket, buffer, sizeof(buffer), 0);
printf("Echo [%d]:%s\n", ++count, buffer);
}
//Close socket
close(mySocket);
return 0;
}
I did some cleanup on your server code and this seems to work.
For my testing, the client code is unchanged. But, as others have suggested, you should check the error codes from send and recv. Also, note that if you ctrl-c the server, the client will hang in the fgets, so it won't detect the server abort until you hit return after the prompt. Not a big deal, but I thought I'd mention it.
I also added a fork so you can have multiple clients talking to the same server instance simultaneously.
I tested this with two clients [in two xterm windows] talking with the single server instance.
I moved your echo code into a new function docomm. A small difference from your code is that any error from either recv or send breaks out of the loop and closes the connection. All connections from new clients are guaranteed to start with a recv call.
In your code, you would not always break out of the loop, but close the connection and call listening again. This would happen for either send or recv. If it happened on the wrong one, this might be the source of the problem you were having because you could do a send before a recv to a new client initially.
#include <stdio.h>
#include <errno.h>
#include <sys/socket.h>
#include <resolv.h>
#include <arpa/inet.h>
#include <errno.h>
#include <stdlib.h>
#include <strings.h>
#include <unistd.h>
#include <sys/wait.h>
#define PORT 12403
#define BUFFER_MAX 1024
#define BACKLOG_MAX 1024
int clientSocket;
int serverSocket;
int forkflg = 1;
void listening()
{
while (1)
{
struct sockaddr_in clientAddress;
socklen_t addressLength = sizeof(clientAddress);
/*---accept a connection (creating a data pipe)---*/
clientSocket = accept(serverSocket, (struct sockaddr*)&clientAddress, &addressLength);
if (clientSocket > -1)
{
printf("%s:%d connected\n", inet_ntoa(clientAddress.sin_addr), ntohs(clientAddress.sin_port));
break;
}
}
}
void
docomm(void)
{
char buffer[BUFFER_MAX];
//Once first socket has been connected, begin echoing process
int i = 0;
while (1) {
//Clear the buffer
bzero(buffer, BUFFER_MAX);
//Echo back anything sent
//Close connection and begin listening process again if the client disconnects
int sendCheck;
int readCheck;
readCheck = recv(clientSocket, buffer, BUFFER_MAX, 0);
if (readCheck <= 0)
break;
sendCheck = send(clientSocket, buffer, BUFFER_MAX, 0);
if (sendCheck <= 0)
break;
i++;
}
printf("close\n");
shutdown(clientSocket, SHUT_WR);
close(clientSocket);
}
int main(int Count, char *Strings[])
{
struct sockaddr_in socketInfo;
//Create socket
if ((serverSocket = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
perror("Error creating socket");
exit(errno);
}
//Setting the linger option to off and resuse address option to on for testing
int option = 0;
setsockopt(serverSocket, SOL_SOCKET, SO_LINGER, &option, sizeof(option));
option = 1;
setsockopt(serverSocket, SOL_SOCKET, SO_REUSEADDR, &option, sizeof(option));
//Initialize socket information
bzero(&socketInfo, sizeof(socketInfo));
socketInfo.sin_family = AF_INET;
socketInfo.sin_port = htons(PORT);
socketInfo.sin_addr.s_addr = INADDR_ANY;
//Assign a port number to the socket
if (bind(serverSocket, (struct sockaddr*)&socketInfo, sizeof(socketInfo)) != 0)
{
perror("Error binding socket");
exit(errno);
}
//Set socket to listen
if (listen(serverSocket, BACKLOG_MAX) != 0)
{
perror("Error setting socket to listen");
exit(errno);
}
while (1) {
listening();
if (! forkflg) {
docomm();
continue;
}
pid_t pid = fork();
if (pid == 0) {
docomm();
exit(0);
}
while (waitpid(0,NULL,WNOHANG) > 0);
}
close(serverSocket);
return 0;
}
UPDATE:
Just from a glance: 1) Can I ask why you created a fork flag if you never change the value of it? Should it be changed somewhere?
I used forkflg so you can set it to zero (e.g. int forkflg = 0;) to run sequentially. Or, you could add some code and parse argv looking for an option (e.g. -f) to set/clear it [for testing/debug purposes]. For production code, you'd want forkflg to be set and could remove the flag and just do the fork case always [adjusting the code to match].
Just tracing through the program mentally, it seems like the forking section will never be executed. Correct me where I'm wrong: after initially setting the socket to listen, the while loop will enter, and listening() will be called. Execution will halt in listening() until a connection is accepted.
Yes, that's true.
Control will return to main, where docomm() gets called. Control stays in docomm() until the connection breaks, at which point it returns to main and continue gets called, skipping the fork stuff and starting the process over again. So does the fork stuff ever get executed?
What you're describing is the behavior if forkflg is zero.
The fork is called if forkflg is set. Note that, in that case, docomm is called in the child and not the parent (because fork returned 0). So, the parent will not be blocked while the child does the echoing.
Thus, the parent returns immediately and is free to do the waitpid loop to reap any old children and restart the main/outer loop.
The waitpid loop only happens when a new connection comes in, so several children may have already terminated and will stay in zombie state until the waitpid loop gets executed [which will reap any/multiple pending children].
A cleaner way to reap the children might be to set up a signal handler for SIGCHLD and have it do the waitpid loop. This would reap all spent children immediately, without having to wait for a new connection to roll in.
Or, with the signal handler, add the waitpid loop to listening [inside the current loop] because if a SIGCHLD signal comes in, accept will return immediately with errno set to EINTR

global table of clients C : Chatroom

I created a client/server chatroom in C. I need to put in a global table of all clients connected so that I can send every message the server receives to all the clients connected. I can't figure out how to do this. I assume I have to create a struct of some sort and add every specific socket descriptor for each thread I spawn. Then I have to send my message to every specific SD in that struct.
I don't know how to code this and wanted to see if anyone could show me some example code of what I have to write after every connection is made and what I have to write to then send my messages to every thread. My server code is below if needed.
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <sys/socket.h>
#include <unistd.h>
#include <string.h>
#include <malloc.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <errno.h>
#include <netdb.h>
#include <sys/stat.h>
#include <fcntl.h>
void *
client_session_thread(void * arg)
{
int SD;
char request[2048];
char message[2048] = "server receives input: ";
int chatfile;
char msgr[50000];
SD = *(int *)arg;
free (arg);
pthread_detach(pthread_self());
chatfile = open("chathistory.txt", O_RDWR|O_CREAT|O_EXCL,0666);
close(chatfile);
chatfile = open("chathistory.txt", O_RDWR | O_APPEND);
read(chatfile,msgr,sizeof(msgr));
write(SD, msgr, strlen(msgr));
while (read(SD, request, sizeof(request)))
{
strcat(message, request);
strcat(message,"\n");
fprintf(stdout, message);
write(SD,request,strlen(request));
write(chatfile,request,strlen(request));
strcpy(request,"");
strcpy(message, "server receives input: ");
bzero(request, sizeof(request));
bzero(message,sizeof(message));
}
close(SD);
close(chatfile);
return 0;
}
int main(int argc, char *argv[])
{
//create a socket. SD is my socket.
struct addrinfo addrinfo;
struct addrinfo * result;
char message[256];
int SD;
int FD;
pthread_t ignore;
int * FDpntr;
int on = 1;
addrinfo.ai_flags = 0;
addrinfo.ai_family = AF_INET; // IPv4 only
addrinfo.ai_socktype = SOCK_STREAM; // Want TCP/IP
addrinfo.ai_protocol = 0; // Any protocol
addrinfo.ai_addrlen = 0;
addrinfo.ai_addr = NULL;
addrinfo.ai_canonname = NULL;
addrinfo.ai_next = NULL;
if (getaddrinfo("clamshell.rutgers.edu", "5700", &addrinfo, &result) !=0)
{
printf("\x1b[1;31mProblem with getaddrinfo\x1b[0m\n");
}
//Create socket
SD = socket(AF_INET, SOCK_STREAM, 0);
if (SD == -1)
{
printf("\x1b[1;31mProblem creating socket\x1b[0m\n");
}
//Bind the socket to our specified IP and port
if (setsockopt(SD, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) ==-1)
{
printf("\x1b[1;31mProblem with sockopt\x1b[0m\n");
freeaddrinfo(result);
return -1;
}
if (bind(SD, result->ai_addr, result->ai_addrlen) != 0)
{
printf("\x1b[1;31mProblem binding socket\x1b[0m\n");
}
//first we bind our socket and then recast our address just like in client
//Listen function listens for connections
if (listen(SD, 20) == -1)
{
printf("\x1b[1;31mProblem with listen\x1b[0m\n");
close(SD);
return 0;
}
else
{
//Accept function for accepting incoming connection
//sos = sizeof(struct sockaddr_in);
//while (FD = accept(SD, (struct sockaddr *)&client, (socklen_t*)&sos))
while ((FD = accept(SD,0,0)) != -1)
{
FDpntr = (int *)malloc(sizeof(int));
*FDpntr = FD;
if (pthread_create(&ignore, NULL, client_session_thread, FDpntr) != 0)
{
printf("\x1b[1;31mProblem creating thread\x1b[0m\n");
}
else
{
continue;
}
}
close(SD);
return 0;
}
}
suggest implement a separate file.
That file would have entry points:
initializeClientTable()
destroyClientTable()
addClient()
deleteClient(),
getClient()
The getClient() function would return a client.
it would have a parameter that (probably an enum value) that indicates to get the first client or get the next client from the ClientTable
When at the end of the ClientTable, return an indication of such event.
The ClientTable could easily be implemented as a linked list.

socket error when using SOCK_RAW and how to accept multiple client with layer 2 communication

soc = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); in client side, when run, get == -1 error
if accept function can only use with UDP and TCP higher protocol, how to accept multiple client with layer 2 communication?
where can find the code of accept function, i would like to rewrite it for layer 2.
Updated :
After tried soc = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
also == -1 , get this error
server side and client side both are the same computer, local one
strange is that running server side, it do not have this error, but running client program got error
//#include "stdafx.h"
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/nameser.h>
#include <resolv.h>
#include <net/if.h>
#include <netinet/if_ether.h>
#include <netpacket/packet.h>
#include <net/ethernet.h>
#include <netinet/ether.h>
//#include "sock.h"
#define MAX_MESSAGE 21000
#define FD_NUM 5
#define tcp_port 5009
//#pragma comment(lib, "ws2_32.lib")
//#include <winsock2.h>
char host_ip[16] = "127.0.0.1";
void task()
{
struct sockaddr_in local;
int opt;
int soc;
//soc = socket(AF_INET,SOCK_STREAM,0);
soc = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if (soc==-1) {
printf("socket error\n");
}
// determine ethernet number
/*
struct ifreq ifr;
size_t if_name_len=strlen(if_name);
if (if_name_len<sizeof(ifr.ifr_name)) {
memcpy(ifr.ifr_name,if_name,if_name_len);
ifr.ifr_name[if_name_len]=0;
} else {
printf("interface name is too long");
}
if (ioctl(fd,SIOCGIFINDEX,&ifr)==-1) {
printf("determine ethernet number error\n");
}
int ifindex=ifr.ifr_ifindex;
*/
// mac address
/*target address*/
struct sockaddr_ll socket_address;
/*buffer for ethernet frame*/
void* buffer = (void*)malloc(ETH_FRAME_LEN);
/*pointer to ethenet header*/
unsigned char* etherhead = (unsigned char*)buffer;
/*userdata in ethernet frame*/
unsigned char* data = (unsigned char*)buffer + 14;
/*another pointer to ethernet header*/
struct ethhdr *eh = (struct ethhdr *)etherhead;
int send_result = 0;
/*our MAC address*/
//10:78:d2:ad:90:cb
//0x10,0x78,0xD2,0xAD,0x90,0xCB
unsigned char src_mac[6] = {0x10,0x78,0xD2,0xAD,0x90,0xCB};
/*other host MAC address*/
unsigned char dest_mac[6] = {0x10,0x78,0xD2,0xAD,0x90,0xCB};
/*prepare sockaddr_ll*/
/*RAW communication*/
socket_address.sll_family = PF_PACKET;
/*we don't use a protocoll above ethernet layer
->just use anything here*/
socket_address.sll_protocol = htons(ETH_P_IP);
/*index of the network device
see full code later how to retrieve it*/
socket_address.sll_ifindex = 0;
/*ARP hardware identifier is ethernet*/
socket_address.sll_hatype = ARPHRD_ETHER;
/*target is another host*/
socket_address.sll_pkttype = PACKET_OTHERHOST;
/*address length*/
socket_address.sll_halen = ETH_ALEN;
/*MAC - begin*/
socket_address.sll_addr[0] = 0x10;
socket_address.sll_addr[1] = 0x78;
socket_address.sll_addr[2] = 0xD2;
socket_address.sll_addr[3] = 0xAD;
socket_address.sll_addr[4] = 0x90;
socket_address.sll_addr[5] = 0xCB;
/*MAC - end*/
socket_address.sll_addr[6] = 0x00;/*not used*/
socket_address.sll_addr[7] = 0x00;/*not used*/
memcpy((void*)buffer, (void*)dest_mac, ETH_ALEN);
memcpy((void*)(buffer+ETH_ALEN), (void*)src_mac, ETH_ALEN);
eh->h_proto = 0x00;
int j = 0;
for (j = 46; --j; data[j] = (unsigned char)((int) (255.0*rand()/(RAND_MAX+1.0))));
/*
struct sockaddr_in server;
int len = sizeof(server);
server.sin_family=AF_INET;
server.sin_port=htons(5008);
server.sin_addr.s_addr=inet_addr(host_ip);
int CONN_SOCK = InitSocketTcp(tcp_port);
if(connect(CONN_SOCK, (struct sockaddr*)&server, sizeof(server)) == -1)
{
printf("connection failed\n");
}
else
{
printf("connection ok!\n");
}
*/
while(1)
{
char buff[492] = "\0";
printf("input: ");
scanf("%s", buff);
//send(CONN_SOCK,buff,strlen(buff),0);
/*send the packet*/
send_result = sendto(soc, buff, ETH_FRAME_LEN, 0, (struct sockaddr*)&socket_address, sizeof(socket_address));
send_result == -1?printf("send error"):0;
if(buff[0] == 'q')
{
//shutdown(CONN_SOCK, SD_SEND);
//closesocket(CONN_SOCK);
//WSACleanup();
close(soc);
exit(0);
}
}
}
int main()
{
//for(int i=10; i!=0; --i)
//pthread_create();
task();
return 0;
}
Accept() is only used for TCP or UDP (practically it's main use is in tcp), because it establishes a connection. A connection does 3 way handshake in case of tcp and exchanges information such as sequence numbers etc. and is completely identified by a socket (port plus ip address)
In contrast to that you can simply use sendto and receivefrom api's as normally used in case of udp, where each packet may follow a different path to reach destination. You do not require an accept in case of udp communication. The same can be extended to link layer (L2) frames i.e. each side can send or receive at will without actually establishing a connection first.
This should be done using root

Resources