Related
I have a code which runs two threads,
The first thread waits on the sender for data using recv() and then forwards the data to the receiver using send.
The second thread waits on the receiver for data using recv() and then forwards the data to the sender using send.
It is important that both of these work parallelly.
Suppose the sender disconnects, the first thread detects this and closes the connection.
How do I tell the second thread which is still waiting on the receiver that the connection has been closed and no further communication is required?
recieve_packet has been implemented using recv().
send_packet has been implemented using send().
sender_fd is the socket file descriptor of the sender.
reciever_fd is the socket file descriptor of the receiver.
void* sender_to_reciever(){
int t1;packet* p = malloc(sizeof(packet));
while((t1=recieve_packet(sender_fd,&p))!=0){
send_packet(reciever_fd,p);
}
close(sender_fd);
}
void* reciever_to_sender(){
int t1;packet* p = malloc(sizeof(packet));
while((t1=recieve_packet(reciever_fd,&p))!=0){
send_packet(sender_fd,p);
}
close(reciever_fd);
}
I don't want to change the implementation of the send_packet and recieve_packet function calls.
I tried closing both sender_fd and reciever_d if either while loop exits. It did not work, however.
Code for channel.c which handles both the sender and the reciever :-
#include "packets.c"
#define SERVER_PORT "8642"
#define QUEUE_LENGTH 10
void handle_connection(int);
void* sender_to_receiver();
void* receiver_to_sender();
int open_outgoing_connection(char*, char*);
int sender_fd;
int receiver_fd;
int main(int argc, char* argv[]){
int sock_fd,new_fd,rv,yes;yes=1;
struct addrinfo hints,*res;
struct sockaddr_storage client_addr;
socklen_t addr_size;
char client_details[INET6_ADDRSTRLEN];
struct sigaction sa;
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
if((rv=getaddrinfo(NULL, SERVER_PORT, &hints, &res))!=0){
printf("Error getaddrinfo : %s\n",gai_strerror(rv));
return 1;
}
if((sock_fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol))==-1){
printf("Error socket file descriptor\n");
return 1;
}
if(setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1){
printf("Error setsockopt\n");
return 1;
}
if(bind(sock_fd,res->ai_addr,res->ai_addrlen)==-1){
close(sock_fd);
printf("Error bind\n");
return 1;
}
if(listen(sock_fd, QUEUE_LENGTH)==-1){
printf("Error listen\n");
return 1;
}
freeaddrinfo(res);
sa.sa_handler = sigchld_handler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART;
if(sigaction(SIGCHLD,&sa,NULL) == -1){
printf("Error sigaction\n");
return 1;
}
// Now we have prepared the socket(ip+port) for accepting incoming connections.
printf("Server PID : %d\n",getpid());
while(1){
addr_size = sizeof client_addr;
new_fd = accept(sock_fd,(struct sockaddr*)&client_addr, &addr_size);
if(new_fd==-1){
printf("Error Accepting Request %d\n",getpid());
return 1;
}
inet_ntop(client_addr.ss_family,get_in_addr((struct sockaddr*)&client_addr),client_details,sizeof client_details);
if(!fork()){ // Child Process
close(sock_fd);
printf("Connection Accepted From : %s by PID:%d\n",client_details,getpid());
handle_connection(new_fd);
exit(0);
}
}
return 1;
}
void handle_connection(int socket_sender){
packet* p = malloc(sizeof(packet));
int t1;
if((t1=receive_packet(socket_sender, &p))==0){
printf("Closed Connection\n");
}else{
int socket_receiver;
if((socket_receiver=open_outgoing_connection(p->destination_ip,p->destination_port))!=-1){
sender_fd = socket_sender;
receiver_fd = socket_receiver;
pthread_t str,rts;
str = pthread_self();
rts = pthread_self();
pthread_create(&str,NULL,sender_to_receiver,NULL);
pthread_create(&rts,NULL,receiver_to_sender,NULL);
pthread_join(str,NULL);
pthread_join(rts,NULL);
}else{
printf("Error Connecting to receiver\n");
}
}
}
void* sender_to_receiver(){
int t1;packet* p = malloc(sizeof(packet));
while((t1=receive_packet(sender_fd,&p))!=0){
printf("SENDER\n");
display_packet(p);
send_packet(receiver_fd,p);
}
printf("Sender Disconnected\n");
close(sender_fd);close(receiver_fd);
}
void* receiver_to_sender(){
int t1;packet* p = malloc(sizeof(packet));
while((t1=receive_packet(receiver_fd,&p))!=0){
printf("Receiver\n");
display_packet(p);
send_packet(sender_fd,p);
}
printf("Receiver Disconnected\n");
close(receiver_fd);close(sender_fd);
}
int open_outgoing_connection(char* ip, char* port){
int gai;
char server_ip[100];memset(server_ip,'\0',sizeof(server_ip));
struct addrinfo hints,*server;
memset(&hints,0,sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
int socket_fd;
if((gai=getaddrinfo(ip,port,&hints,&server)) != 0){
printf("GetAddrInfo Error: %s\n",gai_strerror(gai));
return -1;
}
if((socket_fd = socket(server->ai_family, server->ai_socktype, server->ai_protocol)) == -1){
printf("Socket Error\n");
return -1;
}
if(connect(socket_fd,server->ai_addr,server->ai_addrlen) == -1){
printf("Connect Error\n");
return -1;
}
freeaddrinfo(server);
inet_ntop(server->ai_family, get_in_addr((struct sockaddr*)server->ai_addr), server_ip, sizeof(server_ip));
printf("Connected to: %s\n",server_ip);
return socket_fd;
}
Code for reciver:-
#include "packets.c"
#define QUEUE_LENGTH 10
void handle_connection(int);
int main(int argc, char* argv[]){
if(argc!=2){
printf("Enter PORT\n");
return 1;
}
int sock_fd,new_fd,rv,yes;yes=1;
struct addrinfo hints,*res;
struct sockaddr_storage client_addr;
socklen_t addr_size;
char client_details[INET6_ADDRSTRLEN];
struct sigaction sa;
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
if((rv=getaddrinfo(NULL, argv[1], &hints, &res))!=0){
printf("Error getaddrinfo : %s\n",gai_strerror(rv));
return 1;
}
if((sock_fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol))==-1){
printf("Error socket file descriptor\n");
return 1;
}
if(setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1){
printf("Error setsockopt\n");
return 1;
}
if(bind(sock_fd,res->ai_addr,res->ai_addrlen)==-1){
close(sock_fd);
printf("Error bind\n");
return 1;
}
if(listen(sock_fd, QUEUE_LENGTH)==-1){
printf("Error listen\n");
return 1;
}
freeaddrinfo(res);
sa.sa_handler = sigchld_handler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART;
if(sigaction(SIGCHLD,&sa,NULL) == -1){
printf("Error sigaction\n");
return 1;
}
// Now we have prepared the socket(ip+port) for accepting incoming connections.
printf("Server PID : %d\n",getpid());
while(1){
addr_size = sizeof client_addr;
new_fd = accept(sock_fd,(struct sockaddr*)&client_addr, &addr_size);
if(new_fd==-1){
printf("Error Accepting Request %d\n",getpid());
return 1;
}
inet_ntop(client_addr.ss_family,get_in_addr((struct sockaddr*)&client_addr),client_details,sizeof client_details);
if(!fork()){ // Child Process
close(sock_fd);
printf("Connection Accepted From : %s by PID:%d\n",client_details,getpid());
handle_connection(new_fd);
exit(0);
}
close(new_fd);
}
return 1;
}
void handle_connection(int socket_fd){
int t1;packet* p = malloc(sizeof(packet));
while((t1=receive_packet(socket_fd,&p))!=0){
display_packet(p);
p->message = "ACK";
p->timestamp = get_time_in_ns();
send_packet(socket_fd,p);
}
printf("Sender Disconnected\n");
}
Code for Sender:-
#include "packets.c"
#define CHANNEL_PORT "8642"
#define CHANNEL_IP "127.0.0.1"
int socket_fd;
char* destination_ip;
char* destination_port;
int number_of_packets;
char message[MESSAGE_BUFFER_LEN];
void prepare_packet_header(packet *p){
p->destination_ip=destination_ip;
p->destination_port=destination_port;
p->timestamp = get_time_in_ns();
p->length=0;
}
void divide_message_and_send_packets(){
if(number_of_packets>strlen(message)){
number_of_packets = strlen(message);
}
int indi_len = strlen(message)/number_of_packets;
int lm = 0;int i,j;
packet* all_packets[number_of_packets];
for(i=0;i<number_of_packets;i+=1)all_packets[i]=malloc(sizeof(packet));
// HANDSHAKE
prepare_packet_header(all_packets[0]);
all_packets[0]->message="SYN";
all_packets[0]->uid=-1;
send_packet(socket_fd,all_packets[0]);
// HANDSHAKE OVER
for(i=0;i<number_of_packets;i+=1){
// printf("Processing Packet: %d with message[%d:%d]\n",i,lm,lm+indi_len);
if(i!=number_of_packets-1){
char temp[indi_len+1];memset(temp,'\0', sizeof temp);
for(j=lm;j<lm+indi_len;j+=1)temp[j-lm]=message[j];
all_packets[i]->message = malloc(sizeof temp);
strcpy(all_packets[i]->message, temp);
all_packets[i]->uid = i;
}else{
char temp[strlen(message)-lm+1];memset(temp,'\0', sizeof temp);
for(j=lm;j<strlen(message);j+=1)temp[j-lm]=message[j];
all_packets[i]->message = malloc(sizeof temp);
strcpy(all_packets[i]->message, temp);
all_packets[i]->uid = i;
}
prepare_packet_header(all_packets[i]);lm+=indi_len;
display_packet(all_packets[i]);
send_packet(socket_fd,all_packets[i]);
}
}
void main(int argc,char* argv[]){
if(argc!=5){
printf("Enter DESTINATION_IP DESTINATION_PORT NUMBER_OF_PACKETS MESSAGE\n");
return;
}
strcpy(message,argv[4]);
number_of_packets=atoi(argv[3]);
destination_ip=malloc(sizeof argv[1] + 1);memset(destination_ip,'\0', sizeof destination_ip);
destination_port=malloc(sizeof argv[2] + 1);memset(destination_port,'\0', sizeof destination_port);
strcpy(destination_ip,argv[1]);
strcpy(destination_port,argv[2]);
int gai;
char server_ip[100];memset(server_ip,'\0',sizeof(server_ip));
struct addrinfo hints,*server;
memset(&hints,0,sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
if((gai=getaddrinfo(CHANNEL_IP,CHANNEL_PORT,&hints,&server)) != 0){
printf("GetAddrInfo Error: %s\n",gai_strerror(gai));
return;
}
if((socket_fd = socket(server->ai_family, server->ai_socktype, server->ai_protocol)) == -1){
printf("Socket Error\n");
}
if(connect(socket_fd,server->ai_addr,server->ai_addrlen) == -1){
printf("Connect Error\n");
}
freeaddrinfo(server);
inet_ntop(server->ai_family, get_in_addr((struct sockaddr*)server->ai_addr), server_ip, sizeof(server_ip));
printf("Connected to: %s\n",server_ip);
divide_message_and_send_packets();
while(1){} // busy wait taht simulates future work
}
Code for packets.c (Contains functions related to the packets):-
#include "helper.c"
typedef struct StupidAssignment{
long length;
char* destination_ip;
char* destination_port;
long timestamp;
long uid;
char* message;
}packet;
int receive_packet(int socket,packet** p1){
packet* p = *p1;
int remaining=0;int i;
int received=0;
long content_length=0;
remaining=11;
char buffer[MESSAGE_BUFFER_LEN];memset(buffer,'\0',sizeof(buffer));
while(remaining>0){
int t1 = recv(socket, buffer+received, remaining, 0);
if(t1==0)return 0;
remaining-=t1;
received+=t1;
}
content_length = read_long(buffer, received);
received=0;
remaining=content_length;p->length=content_length;
memset(buffer,'\0',sizeof(buffer));
while(remaining>0){
int t1 = recv(socket, buffer+received, remaining, 0);
if(t1==0)return 0;
remaining-=t1;
received+=t1;
}
char part[MESSAGE_BUFFER_LEN];memset(part,'\0',sizeof(part));int part_len=0;int nlmkr=0;
for(i=0;i<=content_length;i+=1){
if(buffer[i]=='\n' || i==content_length){
nlmkr+=1;
if(nlmkr==1) read_char(&(p->destination_ip), part, part_len);
else if(nlmkr==2) read_char(&(p->destination_port), part, part_len);
else if(nlmkr==3) p->timestamp = read_long(part, part_len);
else if(nlmkr==4) p->uid = read_long(part, part_len);
else if(nlmkr==6) read_char(&(p->message), part, part_len);
part_len=0;memset(part, '\0', sizeof part);
}else{
part[part_len++]=buffer[i];
}
}
return 1;
}
void send_packet(int socket,packet *p){
char temp[MESSAGE_BUFFER_LEN];memset(temp,'\0',sizeof temp);
strcat(temp,p->destination_ip);strcat(temp,"\n");
strcat(temp,p->destination_port);strcat(temp,"\n");
snprintf(temp+strlen(temp),100,"%ld\n",p->timestamp);
snprintf(temp+strlen(temp),100,"%ld\n",p->uid);
// write_long(p->timestamp,temp);strcat(temp,"\n");
// write_long(p->uid,temp);strcat(temp,"\n");
strcat(temp,"\n");
strcat(temp,p->message);
char buffer[MESSAGE_BUFFER_LEN];memset(buffer, '\0', sizeof buffer);
p->length = strlen(temp);
snprintf(buffer,100,"%10ld\n",strlen(temp));
strcat(buffer, temp);
sendAll(buffer,socket);
}
void display_packet(packet* p){
printf("----PACKET START----\n");
printf("%ld\n",p->length);
printf("%s\n",p->destination_ip);
printf("%s\n",p->destination_port);
printf("%ld\n",p->timestamp);
printf("%ld\n",p->uid);
printf("%s\n",p->message);
printf("----PACKET END-----\n");
}
Code for helper.c (Some functions used by all the other codes):-
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <poll.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <signal.h>
#include <time.h>
#include <sys/stat.h>
#include <ctype.h>
#include <fcntl.h>
#include <pthread.h>
#define MESSAGE_BUFFER_LEN 20480
void read_char(char** into, char* from, int length){
*into = malloc(length+1);memset(*into, '\0', sizeof *into);
strcpy(*into, from);
// printf("%s\n",into);
}
long read_long(char* from, int length){
int i;long temp=0;
for(i=0;i<length;i+=1){
if(isdigit(*(from+i))){
temp=temp*10;temp+=(long)(*(from+i) - '0');
}
}
return temp;
}
void write_long(long t1,char* m){
int mkr=0;
char temp[100];memset(temp,'\0',sizeof temp);
while(t1!=0){
temp[mkr] = ((int)(t1%10)) + '0';
t1 = t1/10;
}
for(mkr=strlen(temp)-1;mkr>=0;mkr-=1){
*(m+strlen(m))=temp[mkr];
}
}
void *get_in_addr(struct sockaddr* sa){
if(sa->sa_family == AF_INET){
return &(((struct sockaddr_in *)sa)->sin_addr);
}else{
return &(((struct sockaddr_in6*)sa)->sin6_addr);
}
}
void sigchld_handler(int s){
int saved_errno=errno;
while(waitpid(-1, NULL, WNOHANG) > 0);
errno = saved_errno;
}
int sendAll(char* data_to_send,int socket_fd){
int bytesleft = strlen(data_to_send);
int total=0;int n;
while(bytesleft>0){
n = send(socket_fd,data_to_send + total, bytesleft, 0);
if(n==-1)break;
total+=n;
bytesleft-=n;
}
return n==-1?-1:0;
}
long get_time_in_ns(){
struct timespec start;clock_gettime(CLOCK_REALTIME,&start);
long ct = ((long)start.tv_sec)*1e9 + ((long)start.tv_nsec);
return ct;
}
The code isn't documented at all.
For TCP, call shutdown on the socket. To be more complete:
Set some flag that the thread will check so it will know that a shutdown is in process when it becomes unblocked.
Do whatever you need to do to shut the connection down, ultimately calling shutdown on the socket when you're done. If you need to call shutdown as part of your teardown process, do it. If not, when you're done with your teardown process (if any) shutdown the connection in both directions.
Do not, under any circumstances, call close on the socket until you can 100% confirm that no thread is, or might be, trying to access the socket. This is extremely important.
For UDP, send a datagram to the socket. That will unblock the thread as it receives the dummy datagram.
I am trying to receive an updated message over the socket and unpack the
data. I want to use the update_client function to update the server's
internal representation of the client co-ordinates and respond to the
client with the required value.
I think I should use recv to read the full message (of length UPDATE_CMD_LEN) into buffer.
Then unpack data having message in the following format:
U<id><fields of gpscoords>
Character 'U' (meaning update), followed by ID of the client (unsigned char)
and then the gpscoord structure in network format.
This is a rough idea of how to do it but I don't know how:
[1] Unpack ID
[2] Unpack coordinates with int update_client(unsigned char id, gpscoords *pos
which takes ID and pointer to position struct, returns -1 on error and 0 on success
The server should then respond to client using sendto function and reply
NO_RES on error and SUCC_RES on success.
void do_update(int sockfd, struct sockaddr_in *clientaddr) {
char msg[UPDATE_CMD_LEN];
recv(sockfd, msg, UPDATE_CMD_LEN, flags);
fprintf(stderr, "do_update not implemented!\n");
exit(-1);
}
client.c
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include "gps.h"
#define CMD_LEN 10
#define LINE_LEN NAME_LEN + 15
#define FIREFOX "/usr/bin/firefox"
void make_route_url(char *url, gpscoords *pos, gpscoords *target) {
char pos_sign_n;
char pos_sign_e;
char tar_sign_n;
char tar_sign_e;
pos_sign_n = pos->north ? '+' : '-';
pos_sign_e = pos->east ? '+' : '-';
tar_sign_n = target->north ? '+' : '-';
tar_sign_e = target->east ? '+' : '-';
sprintf(url,
"http://map.project-osrm.org/?z=13&loc=%c%u.%u,%c%u.%u&loc=%c%u.%u,%c%u.%u",
pos_sign_n, pos->lat, pos->lat_frac,
pos_sign_e, pos->lon, pos->lon_frac,
tar_sign_n, target->lat, target->lat_frac,
tar_sign_e, target->lon, target->lon_frac);
}
void show_route(gpscoords *pos, gpscoords *target) {
// char url[75];
fprintf(stderr, "show_route not implemented!\n");
exit(-1);
}
int run_client(char *name, char *serverip) {
char *cmdline;
size_t line_len;
char cmd[11];
gpsinfo info;
gpscoords pos, targetpos;
char targetname[NAME_LEN];
bzero(targetname, NAME_LEN);
bzero(&info, sizeof(info));
bzero(&pos, sizeof(pos));
bzero(&targetpos, sizeof(targetpos));
if (register_client(serverip, name, &info) == -1) {
perror("Error registering client.");
return -1;
}
find_self(&pos);
if (update_position(&info, &pos) == -1) {
printf("Failed to send initial position to server.\n");
exit(-1);
}
for (;;) {
printf("Command: ");
line_len = 0;
cmdline = NULL;
getline(&cmdline, &line_len, stdin);
if (strncmp(cmdline, "update", 3) == 0) {
find_self(&pos);
if (update_position(&info, &pos) == -1) {
printf("Failed to update.\n");
}
} else if (strncmp(cmdline, "find", 3) == 0) {
sscanf(cmdline, "%10s %25s", cmd, targetname);
if (get_position(&info, targetname, &targetpos) == -1) {
printf("Couldn't find target.\n");
} else {
show_route(&pos, &targetpos);
}
} else if (strncmp(cmdline, "quit", 4) == 0) {
free(cmdline);
break;
}
free(cmdline);
}
if (unregister_client(&info) == -1) {
perror("Error unregistering client.");
return -1;
}
return 0;
}
int main(int argc, char **argv) {
if (argc < 2) {
printf("Usage: ./client <client name> <server_ip>\n");
return 0;
}
return run_client(argv[1], argv[2]);
}
socket.c
#include <sys/socket.h>
#include <stdint.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include "sockets.h"
int create_dg_socket(in_port_t port) {
// Create the socket
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd == -1) {
printf("create_dg_socket cannot create socket!");
return -1;
}
// Bind the socket port
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) != 0) {
printf("create_dg_socket cannot bind socket!");
close(sockfd);
return -1;
}
return sockfd;
}
int open_dg_socket(char *ipaddr, in_port_t port, struct sockaddr_in *addr) {
// Create the socket
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd == -1) {
return -1;
}
// Setup
addr->sin_family = AF_INET;
addr->sin_port = htons(port);
addr->sin_addr.s_addr = inet_addr(ipaddr);
return sockfd;
}
int dg_sendrecv(int sockfd,
struct sockaddr_in *addr,
char *message, size_t out_len,
char *response, size_t in_len) {
if (sendto(sockfd, message, out_len, 0, (struct sockaddr *)&addr, sizeof(*addr)) == -1) {
printf("dg_sendrecv cannot send data!");
return -1;
}
int ret = recvfrom(sockfd, response, in_len, 0, NULL, NULL);
if (ret == -1) {
printf("dg_sendrecv cannot read data!");
return -1;
}
return ret;
}
/*
int dg_sendrecv(int sockfd,
struct sockaddr_in *addr,
char *message, size_t out_len,
char *response, size_t in_len) {
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = inet_addr(ipaddr);
return dg_sendrecv_addr(sockfd, &addr, message, out_len, response, in_len);
}
*/
server.c
#include <stdio.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <string.h>
#include "sockets.h"
#include "gps.h"
#include "server.h"
#define NUM_CLIENTS 5
char clients[NUM_CLIENTS][NAME_LEN];
gpscoords coords[NUM_CLIENTS];
void do_register(int sockfd, struct sockaddr_in *clientaddr) {
char msg[REGISTER_CMD_LEN];
char *name;
unsigned char id, i;
if (recv(sockfd, msg, REGISTER_CMD_LEN, 0) == -1) {
perror("Error receiving register command.");
exit(-1);
}
// first byte is server command, rest is name
name = &msg[1];
id = NO_RES;
for (i = 0; i < NUM_CLIENTS; ++i) {
if (clients[i][0] == '\0') {
strncpy(clients[i], name, NAME_LEN);
clients[i][NAME_LEN - 1] = '\0';
bzero(&coords[i], sizeof(coords[i]));
id = i + 1;
break;
}
}
if (sendto(sockfd,
&id, sizeof(id),
0,
(struct sockaddr *)clientaddr, sizeof(*clientaddr)) == -1) {
perror("Error replying to client.");
exit(-1);
}
}
void do_unregister(int sockfd, struct sockaddr_in *clientaddr) {
unsigned char msg[UNREGISTER_CMD_LEN];
unsigned char id;
char res = NO_RES;
if (recv(sockfd, &msg, UNREGISTER_CMD_LEN, 0) == -1) {
perror("Error receiving unregister command.");
exit(-1);
}
id = msg[1] - 1;
if (id < NUM_CLIENTS) {
clients[id][0] = '\0';
res = SUCC_RES;
}
if (sendto(sockfd,
&res, sizeof(res),
0,
(struct sockaddr *)clientaddr, sizeof(*clientaddr)) == -1) {
perror("Error responding to client.");
exit(-1);
}
}
int update_client(unsigned char id, gpscoords *pos) {
id -= 1;
if (id >= NUM_CLIENTS)
return -1;
memcpy(&coords[id], pos, sizeof(coords[id]));
return 0;
}
void do_update(int sockfd, struct sockaddr_in *clientaddr) {
/**
* Receive an update message over the socket and unpack the
* data. Then use the update_client function to update the server's
* internal representation of the client co-ordinates. Then respond to the
* client with the required value.
* Use recv to read the full message (of length UPDATE_CMD_LEN) into buffer.
* Unpack data, message of following format:
* U<id><fields of gpscoords>
* Character 'U' (meaning update), followed by ID of the client (unsigned char)
* and then the gpscoord structure in network format.
*
* 1. Unpack ID
* 2. Unpack coordinates with (int update_client(unsigned char id, gpscoords *pos)
* which takes ID and pointer to position struct, returns -1 on error and 0 on success
* Server should then respond to client using sendto function and reply
* NO_RES on error and SUCC_RES on success.
*/
char msg[UPDATE_CMD_LEN];
recv(sockfd, msg, UPDATE_CMD_LEN, flags);
fprintf(stderr, "do_update not implemented!\n");
exit(-1);
}
static gpscoords *get_client(char *name) {
for (int i = 0; i < NUM_CLIENTS; ++i) {
if (strcmp(name, clients[i]) == 0) {
return &coords[i];
break;
}
}
return NULL;
}
void do_get(int sockfd, struct sockaddr_in *clientaddr) {
char msg[GET_CMD_LEN];
char res[GET_RES_LEN];
char *name;
if (recv(sockfd, msg, GET_CMD_LEN, 0) == -1) {
perror("Error receiving get command.");
exit(-1);
}
name = &msg[1];
name[NAME_LEN - 1] = '\0';
gpscoords *pos = get_client(name);
if (pos == NULL) {
res[0] = NO_RES;
} else {
res[0] = SUCC_RES;
pack_gpscoords(pos, &res[1]);
}
if (sendto(sockfd,
&res, GET_RES_LEN,
0,
(struct sockaddr *)clientaddr, sizeof(*clientaddr)) == -1) {
perror("Error sending result to client.");
exit(-1);
}
}
int serve(int sockfd) {
char cmd;
struct sockaddr_in clientaddr;
socklen_t clientaddrlen = sizeof(clientaddr);
for (;;) {
if (recvfrom(sockfd,
&cmd, sizeof(cmd),
MSG_PEEK,
(struct sockaddr *)&clientaddr, &clientaddrlen) == -1) {
exit(-1);
}
switch (cmd) {
case CMD_REGISTER:
do_register(sockfd, &clientaddr);
break;
case CMD_UNREGISTER:
do_unregister(sockfd, &clientaddr);
break;
case CMD_UPDATE:
do_update(sockfd, &clientaddr);
break;
case CMD_GET:
do_get(sockfd, &clientaddr);
break;
default:
break;
}
}
}
void init_info() {
int i;
for (i = 0; i < NUM_CLIENTS; ++i) {
clients[i][0] = '\0';
}
}
int main(int argc, char **argv) {
int sockfd = create_dg_socket(SERVER_PORT);
if (sockfd == -1) {
fprintf(stderr, "Error creating socket!\n");
return -1;
}
init_info();
printf("Server ready.\n");
serve(sockfd);
// Note: server never terminates, we're relying on the system to clean up
// our open socket file descriptor (and shut it down)
return 0;
}
If you are looking for a way to safe and read data from char arrays that maybe will help you:
char buffer[5+sizeof(gpscoords)];
int *int_pointer;
gpscoords *gps_pointer;
int id=1;
gpscoords gps="some gps contend";
int id_frombuffer;
gpscoords gps_frombuffer;
char c_frombuffer;
buffer[0]='U';
int_pointer=(int*)&buffer;
int_pointer+=1;
*int_pointer=id;
gps_pointer=(gpscoords*)&buffer;
gps_pointer+=5;
*gpspointer=gps;
//send buffer
c_frombuffer=buffer[0];//c_frombuffer now contains 'U'
int_pointer=(int*)&buffer;
int_pointer+=1;
id_frombuffer=*int_pointer;//id_frombuffer now contains 1
gps_pointer=(gpscoords*)&buffer;
gpscoords+=5;
gps_frombuffer=*pointer;//gps_frombuffer now contains "some gps contend"
As an example if your client code looks like that:
void sendupdate(unsigned char id,gpscoords gps)
{
char buffer[2+sizeof(gpscoords)];
gpscoords *gps_pointer;
buffer[0]='U';
buffer[1]=id;
gps_pointer=(gpscoords*)&buffer;
gps_pointer+=2;
*gpspointer=gps;
send(socket, buffer, 2+sizeof(gpscoords), flags);
}
your server function should look like that:
void do_update(int sockfd, struct sockaddr_in *clientaddr)
{
char buffer[2+sizeof(gpscoords)];
recv(sockfd, buffer, 2+sizeof(gpscoords), flags);
unsigned char id_frombuffer=buffer[1];
gpscoords *gpspointer=(gpscoords*)&buffer;
gpspointer+=2;
update_client(id_frombuffer, gpspointer);
}
I write a program which needs to get notified if the network interfaces have changed, in particular new one appeared or existed one gone. My research brought to the netlink and its RTMGRP_LINK signal. This manpage gives an example which is not clear for me yet.
It has this code:
memset(&sa, 0, sizeof(sa));
snl.nl_family = AF_NETLINK;
snl.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR;
fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
bind(fd, (struct sockaddr*)&sa, sizeof(sa));
My understading is this is an initialization part to enable some signals. I guess there must be a handler subroutine which processes the event.
My questions are:
Is this a correct code snippet for enabling the event?
How to process the event: do I need to have some handler?
What are the data structures that contains a relevant information (about network interfaces and their changes)?
Thanks for any help.
The following code has been taken from here and I have added the logic to get the name of the concerned interface.
#include <asm/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <net/if.h>
#include <netinet/in.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#define MYPROTO NETLINK_ROUTE
#define MYMGRP RTMGRP_IPV4_ROUTE
int open_netlink()
{
int sock = socket(AF_NETLINK,SOCK_RAW,MYPROTO);
struct sockaddr_nl addr;
memset((void *)&addr, 0, sizeof(addr));
if (sock<0)
return sock;
addr.nl_family = AF_NETLINK;
addr.nl_pid = getpid();
addr.nl_groups = RTMGRP_LINK|RTMGRP_IPV4_IFADDR|RTMGRP_IPV6_IFADDR;
if (bind(sock,(struct sockaddr *)&addr,sizeof(addr))<0)
return -1;
return sock;
}
int read_event(int sockint, int (*msg_handler)(struct sockaddr_nl *,
struct nlmsghdr *))
{
int status;
int ret = 0;
char buf[4096];
struct iovec iov = { buf, sizeof buf };
struct sockaddr_nl snl;
struct msghdr msg = { (void*)&snl, sizeof snl, &iov, 1, NULL, 0, 0};
struct nlmsghdr *h;
status = recvmsg(sockint, &msg, 0);
if(status < 0)
{
/* Socket non-blocking so bail out once we have read everything */
if (errno == EWOULDBLOCK || errno == EAGAIN)
return ret;
/* Anything else is an error */
printf("read_netlink: Error recvmsg: %d\n", status);
perror("read_netlink: Error: ");
return status;
}
if(status == 0)
{
printf("read_netlink: EOF\n");
}
/* We need to handle more than one message per 'recvmsg' */
for(h = (struct nlmsghdr *) buf; NLMSG_OK (h, (unsigned int)status);
h = NLMSG_NEXT (h, status))
{
/* Finish reading */
if (h->nlmsg_type == NLMSG_DONE)
return ret;
/* Message is some kind of error */
if (h->nlmsg_type == NLMSG_ERROR)
{
printf("read_netlink: Message is an error - decode TBD\n");
return -1; // Error
}
/* Call message handler */
if(msg_handler)
{
ret = (*msg_handler)(&snl, h);
if(ret < 0)
{
printf("read_netlink: Message hander error %d\n", ret);
return ret;
}
}
else
{
printf("read_netlink: Error NULL message handler\n");
return -1;
}
}
return ret;
}
static int netlink_link_state(struct sockaddr_nl *nl, struct nlmsghdr *msg)
{
int len;
struct ifinfomsg *ifi;
nl = nl;
ifi = NLMSG_DATA(msg);
char ifname[1024];if_indextoname(ifi->ifi_index,ifname);
printf("netlink_link_state: Link %s %s\n",
/*(ifi->ifi_flags & IFF_RUNNING)?"Up":"Down");*/
ifname,(ifi->ifi_flags & IFF_UP)?"Up":"Down");
return 0;
}
static int msg_handler(struct sockaddr_nl *nl, struct nlmsghdr *msg)
{
struct ifinfomsg *ifi=NLMSG_DATA(msg); /* for RTM_{NEW,DEL}ADDR */
struct ifaddrmsg *ifa=NLMSG_DATA(msg); /* for RTM_{NEW,DEL}LINK */
char ifname[1024];
switch (msg->nlmsg_type)
{
case RTM_NEWADDR:
if_indextoname(ifa->ifa_index,ifname);
printf("msg_handler: RTM_NEWADDR : %s\n",ifname);
break;
case RTM_DELADDR:
if_indextoname(ifa->ifa_index,ifname);
printf("msg_handler: RTM_DELADDR : %s\n",ifname);
break;
case RTM_NEWLINK:
if_indextoname(ifi->ifi_index,ifname);
printf("msg_handler: RTM_NEWLINK\n");
netlink_link_state(nl, msg);
break;
case RTM_DELLINK:
if_indextoname(ifi->ifi_index,ifname);
printf("msg_handler: RTM_DELLINK : %s\n",ifname);
break;
default:
printf("msg_handler: Unknown netlink nlmsg_type %d\n",
msg->nlmsg_type);
break;
}
return 0;
}
int main(int argc, char *argv[])
{
int nls = open_netlink();
printf("Started watching:\n");
if (nls<0) {
printf("Open Error!");
}
while (1)
read_event(nls, msg_handler);
return 0;
}
#include<stdio.h>
#include <asm/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <net/if.h>
#include <netinet/in.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
static void network_loop(void *data)
{
struct sockaddr_nl addr;
int nls, len, rtl;
char buffer[4096];
struct nlmsghdr *nlh;
struct ifaddrmsg *ifa;
struct rtattr *rth;
if ((nls = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) == -1)
printf("MY_PROG: socket failure\n");
memset (&addr,0,sizeof(addr));
addr.nl_family = AF_NETLINK;
addr.nl_groups = RTMGRP_IPV4_IFADDR;
if (bind(nls, (struct sockaddr *)&addr, sizeof(addr)) == -1)
printf("MY_PROG:network_loop bind failure\n");
nlh = (struct nlmsghdr *)buffer;
while ((len = recv(nls,nlh,4096,0)) > 0)
{
for (; (NLMSG_OK (nlh, len)) && (nlh->nlmsg_type != NLMSG_DONE); nlh = NLMSG_NEXT(nlh, len))
{
if (nlh->nlmsg_type == RTM_NEWADDR)
printf("MY_PROG:network_loop RTM_NEWADDR\n");
else if (nlh->nlmsg_type == RTM_DELADDR)
printf("MY_PROG:network_loop RTM_DELADDR\n");
else
printf("MY_PROG:network_loop nlmsg_type=%d\n", nlh->nlmsg_type);
if ((nlh->nlmsg_type != RTM_NEWADDR) && (nlh->nlmsg_type != RTM_DELADDR)) continue; /* some other kind of announcement */
ifa = (struct ifaddrmsg *) NLMSG_DATA (nlh);
rth = IFA_RTA (ifa);
rtl = IFA_PAYLOAD (nlh);
for (; rtl && RTA_OK (rth, rtl); rth = RTA_NEXT (rth,rtl))
{
char name[IFNAMSIZ];
uint32_t ipaddr;
if (rth->rta_type != IFA_LOCAL) continue;
ipaddr = * ((uint32_t *)RTA_DATA(rth));
ipaddr = htonl(ipaddr);
printf("MY_PROG:network_loop %s is now %X\n",if_indextoname(ifa->ifa_index,name),ipaddr);
}
}
}
}
main()
{
network_loop("MYPROG");
printf("EXIT main()\n");
}
Simple program to know network change notification in Linux system and tested.
For a class my group has been assigned to write a program that has two thread, where one thread sends 20 UDP messages to the other thread. The IP address, port numbers, and rate at which the transmit thread sends messages is passed in as command line arguments. When we try to run the program we get the error "sendto failed: Bad Address". We've been trying to figure out why, but we're stumped. We think it has something to do with the recAddr struct. Does anyone have any ideas?
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <unistd.h>
#include <netinet/in.h>
#include <pthread.h>
#include <sys/time.h>
const int ipTx = 1, ipRx = 2, portTx = 3, portRx = 4, TxRate = 5;
const int wait_five = 5, num_msgs = 20, wait_ten = 10, wait_twenty = 20;
const int SEC_TO_MILLI = 1000;
int *message;
void *send_msg( void * );
void *receive_msg( void * );
int main( int argc, char *argv[] )
{
message = 0;
pthread_t sendThread, recieveThread;
int sendFail, recFail;
sendFail = pthread_create(&sendThread, NULL, send_msg, (void*) argv);
if(sendFail)
{
printf("Error creating send thread\n");
}
recFail = pthread_create(&recieveThread, NULL, receive_msg, (void*) argv);
if(recFail)
{
printf("Error creating receive thread\n");
}
pthread_join( sendThread, NULL);
pthread_join( recieveThread, NULL);
printf("Send thread and receive thread done. Program terminating.\n");
return 0;
}
void *send_msg( void *argv)
{
char **args = (char **)argv;
int sendSocket;
if((sendSocket = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
{
perror("cannot create send socket");
return;
}
struct sockaddr_in myAddr;
memset((char *)&myAddr, 0, sizeof(myAddr));
myAddr.sin_family = AF_INET;
myAddr.sin_addr.s_addr = inet_addr(args[ipTx]);
int port = htons(atoi(args[portTx]));
myAddr.sin_port = htons(port);
if (bind(sendSocket, (struct sockaddr *)&myAddr, sizeof(myAddr)) < 0)
{
perror("send socket bind failed");
return;
}
struct sockaddr_in recAddr;
memset((char*)&recAddr, 0, sizeof(recAddr));
recAddr.sin_family = AF_INET;
recAddr.sin_port = htons(atoi(args[portRx]));
recAddr.sin_addr.s_addr = inet_addr(args[ipRx]);
printf("Sleeping for 5 seconds\n");
sleep(wait_five);
int sendRate = (intptr_t) args[TxRate];
sendRate /= SEC_TO_MILLI;
int i;
for(i = 0; i < num_msgs; i++)
{
printf("I am TX and I am going to send a %i\n", message);
if(sendto(sendSocket, message, sizeof(message), 0, (struct sockaddr *)&recAddr, sizeof(recAddr) ) < 0)
{
perror("sendto failed");
return;
}
*message++;
sleep(sendRate);
}
printf("Sleeping for 10 seconds\n");
sleep(wait_ten);
}
void *receive_msg( void *argv)
{
const int BUFF_SIZE = 2048;
char **args = (char **)argv;
struct sockaddr_in myAddress;
struct sockaddr_in remoteAddress;
socklen_t addressLength = sizeof(myAddress);
int recvLength;
int receiveSocket;
unsigned int buf[BUFF_SIZE];
if((receiveSocket = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
{
perror("cannot create receive socket\n");
return;
}
memset((char*)&myAddress, 0, sizeof(myAddress));
myAddress.sin_family = AF_INET;
myAddress.sin_addr.s_addr = inet_addr(args[ipRx]);;
myAddress.sin_port = htons(atoi(args[portRx]));
struct timeval rec_timeout;
rec_timeout.tv_sec = wait_twenty;
rec_timeout.tv_usec = 0;
if(setsockopt(receiveSocket, SOL_SOCKET, SO_RCVTIMEO, (const void *)&rec_timeout, sizeof(rec_timeout)) < 0)
{
perror("cannot set timeout option\n");
return;
}
if(bind(receiveSocket, (const struct sockaddr *)&myAddress, sizeof(myAddress)) < 0)
{
perror("cannot bind receive socket\n");
return;
}
for(;;)
{
printf("waiting on port %d\n", atoi(args[portRx]));
recvLength = recvfrom(receiveSocket, buf, BUFF_SIZE, 0, (struct sockaddr*)&remoteAddress, &addressLength);
printf("received %d bytes\n", recvLength);
if (recvLength > 0)
{
buf[recvLength] = 0;
printf("I am RX and I got a \"%d\"\n", buf);
}
}
}
Here's the code in script file we use:
#!/bin/bash
gcc -pthread -o prototype1.out prototype1.c
./prototype1.out 137.104.21.4 137.104.21.4 7084 7085 50
Thank you!
sendto(sendSocket, message, sizeof(message), 0, (struct sockaddr *)&recAddr, sizeof(recAddr) )
The problem here is that message is NULL.
This pointer is
1) Initialized to a NULL. The second argument to sendto() should point to valid memory at least the size given by the third argument.
2) The code assumes that this pointer is initialized to at least sizeof(message) bytes worth of memory.
I've made a message queue for my fileserver (runs on linux) and it all seems to go well when I upload (from windows client) a file to the the server through the client. Once the file is uploaded though I get all these vague symbols on the serverside.
I've got the following code on the client side
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <stddef.h>
#include "mailbox.h"
#define MAXCLIENTS 5
#define PORTNR 5002
#define MAXUSERS 1024
/*
int inet_aton(const char *cp, struct in_addr *inp);
char *inet_ntoa(struct in_addr in);
void *memset(void *s, int c, size_t n);
int close(int fd);
*/
//Prototyping van de functies
void *childThread(void *ad);
void uploadFile(int nsockfd);
void downloadFile(int nsockfd);
void establishConnection();
int login(char *username, char *password);
int get_queue_ds( int qid, struct msqid_ds *qbuf);
int change_queue_mode(int qid, char *mode);
//Upload files= 0, Download files= 1
int serverState = 0;
int numberLoggedInUsers = 0;
struct sockaddr_in client; // Struct for Server addr
struct message req;
struct msqid_ds mq_id = {0};
int clientUpload;
ssize_t msgLen;
char *username;
char *password;
int main(int argc, char** argv) {
// create message queue key
key_t key;
if((key = ftok("/home/MtFS/Iteraties/ftokDing", 13)) < 0) {
perror("ftok");
exit(1);
}
// create queue, if not succesfull, remove old queue
// and try to make a new one.
while ((clientUpload = msgget(key, 0666 | IPC_CREAT| IPC_EXCL)) < 0) { //| S_IRGRP | S_IWUSR
perror("msgget");
// delete message queue if it exists
if (msgctl(clientUpload, IPC_RMID, &mq_id) == -1) {
perror("msgctl1");
exit(1);
}
}
change_queue_mode(clientUpload, "0666");
/*
if (msgctl(clientUpload, IPC_STAT, &mq_id) == -1) {
perror("msgctl2");
exit(1);
}
if (msgctl(clientUpload, IPC_SET, &mq_id) == -1) {
perror("msgctl3");
exit(1);
}
*/
establishConnection();
return 0;
}
int get_queue_ds(int qid, struct msqid_ds *qbuf) {
if (msgctl(qid, IPC_STAT, qbuf) == -1) {
perror("msgctl IPC_STAT");
exit(1);
}
return 0;
}
int change_queue_mode(int qid, char *mode) {
struct msqid_ds tmpbuf;
/* Retrieve a current copy of the internal data structure */
get_queue_ds(qid, &tmpbuf);
/* Change the permissions using an old trick */
sscanf(mode, "%ho", &tmpbuf.msg_perm.mode);
/* Update the internal data structure */
if (msgctl(qid, IPC_SET, &tmpbuf) == -1) {
perror("msgctl IPC_SET");
exit(1);
}
return (0);
}
void establishConnection() {
pthread_t child; //Thread ID of created thread
int sockfd; //Integer for socket
int nsockfd; //Integer for client socket
socklen_t sizeAddr; //Length of socket
struct sockaddr_in addr; //Struct for client addr
int optValue = 1; //Int for setsockoptions
char ipAdres[32] = "192.168.80.2"; //IP-adres of server
sizeAddr = sizeof (struct sockaddr_in);
// create socket and errorhandling if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("[socket()]");
exit(1);
} else {
printf("================================================================\n\n");
printf("Socket created succesfully.\n\n");
}
// Fill socket with portno and ip address
addr.sin_family = AF_INET; // Protocol Family
addr.sin_port = htons(PORTNR); // Portnumber
inet_aton(ipAdres, &addr.sin_addr); // Local IP- adres
bzero(&(addr.sin_zero), 8); // empty rest of struct
// int setsockopt (int fd, int level, int optname, const void *optval, socklen_t optlen)
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &optValue, sizeof (int)) == -1) {
perror("[setsockopt()]");
exit(1);
}
// Fil socket with portnr and ip adress, also implemented error handling
if (bind(sockfd, (struct sockaddr*) &addr, sizeof (struct sockaddr)) == -1) {
perror("[bind()]");
exit(1);
} else {
printf("================================================================\n\n");
printf("Portnr %d is succesfully connected %s to.\n\n", PORTNR, ipAdres);
}
// Listen to incoming connections and errorhandling
if (listen(sockfd, MAXCLIENTS) == -1) {
perror("[listen()]");
exit(1);
} else {
printf("================================================================\n\n");
printf("Listen to port %d successfull.\n\n", PORTNR);
}
//Connectionloop to process connection requests from clients
while (1) {
//Accept incoming clients with error handling.
if ((nsockfd = accept(sockfd, (struct sockaddr *) &client, &sizeAddr)) == -1) {
perror("[accept()]");
exit(1);
} else {
//create child thread
pthread_create(&child, NULL, childThread, (void *) nsockfd);
/*
// wait untill other child is ready
pthread_join(child, &status);
*/
}
}
}
void *childThread(void *nsockfd) {
int sizeReceivedFile = 0;
char receiveBuffer[PACKETSIZE]; //Buffer voor de ontvangen bestanden
//char sendBuffer[PACKETSIZE]; //Buffer voor de te zenden bestanden
//int sizeSendFile = 0; //Grootte van het te zenden bestand
//char yolocol[PACKETSIZE];
char *clientRequest; //Char pointer voor het type request client, permissie en bestandsnaam
int loginStatus = 0; // 0 = uitgelogd, 1 = ingelogd
char *loggedInAs;
printf("================================================================\n\n");
printf("Connected with a client on IP-Adres: %s.\n\n", inet_ntoa(client.sin_addr));
bzero(receiveBuffer, PACKETSIZE);
while ((sizeReceivedFile = recv((int) nsockfd, receiveBuffer, PACKETSIZE, 0)) > 0) {
// receive from client
printf("Ontvangen buffer: %s\n",receiveBuffer);
if (sizeReceivedFile == 0) {
break;
}
// flags
// retreive flag with strtok
clientRequest = strtok(receiveBuffer, "#");
printf("packet type: %s\n", clientRequest);
// 2 = list
// 3 = download
// 4 = upload
// 5 = login
// 6 = logout
if (strcmp(clientRequest, "2") == 0) {
printf("execute list on current directory!\n");
} else if (strcmp(clientRequest, "3") == 0) {
downloadFile((int) nsockfd);
} else if (strcmp(clientRequest, "4") == 0) {
uploadFile((int) nsockfd);
} else if (strcmp(clientRequest, "5") == 0){
username = strtok(NULL,"#");
password = strtok(NULL,"#");
printf("Username = %s \n password = %s \n",username,password);
int test;
if((test= login(username,password))== 1){
printf("login success, %i\n", test);
loginStatus = 1;
}
else{
printf("Inloggen mislukt, %i\n", test);
loginStatus = 0;
}
} else if (strcmp(clientRequest, "6")== 0) {
loginStatus = 0;
printf("%s logged out\n", loggedInAs);
loggedInAs = "";
}
}
return 0;
}
void uploadFile(int nsockfd) {
/*
printf("execute download!\n");
fileToDownload = strtok(NULL,"#");
printf("%s",fileToDownload);
int sizeReceivedFile = 0;
// if relcv() returns 0 then the connection is gone
while (sizeReceivedFile != 0) {
//Upload of files
if (serverState == 0) {
sizeReceivedFile = recv((int) nsockfd, req.pakket.buffer, PACKETSIZE, 0);
if (sizeReceivedFile < 0) {
perror("[receive()]");
exit(0);
} else if (sizeReceivedFile == 0) {
printf("The client has dropped the connection \n");
close((int) nsockfd);
pthread_exit(NULL);
}
// put the packet in the mailbox
req.mtype = RESP_MT_DATA; // has to be positive
req.pakket.clientID = clientUpload;
if (msgsnd(clientUpload, &req, PACKETSIZE, 0) == -1) {
perror("msgsnd");
}
}
}
req.mtype = RESP_MT_END;
msgsnd(clientUpload, &req, 0, 0);
close((int) nsockfd);
printf("================================================================\n\n");
printf("Connection with client has been lost. Server is waiting for new clients clients...\n\n");
}
void downloadFile(int nsockfd) {
/*
printf("execute download!\n");
fileToDownload = strtok(NULL,"#");
printf("%s",fileToDownload);
*/
char sendBuffer[PACKETSIZE];
int sizeSendFile = 0;
if (send((int) nsockfd, sendBuffer, sizeSendFile, 0) < 0) {
perror("[send()]");
//exit(1);
}
bzero(sendBuffer, PACKETSIZE);
}
And this is the server side. I made one process for handling the connection, which transfers all incoming packets that say 'upload' in one of my custom made protocol flags to a message queue. This is the code:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <stddef.h>
#include "mailbox.h" // self made header file
#define MAXCLIENTS 5
#define PORT 5002
#define MAXUSERS 1024
//Prototyping
void *childThread(void *ad);
void uploadFile(int nSockfd);
void buildConnection();
int get_queue_ds( int qid, struct msqid_ds *qbuf);
int change_queue_mode(int qid, char *mode);
// Upload files= 0, Download files= 1
int serverState = 0;
struct sockaddr_in client;
struct bericht req;
struct msqid_ds mq_id = {0};
int messageQueue;
ssize_t msgLen;
int main(int argc, char** argv) {
// message queue key aanmaken
key_t key;
if((key = ftok("/home/file", 13)) < 0) {
perror("ftok");
exit(1);
}
// queue aanmaken, als dit niet lukt de eventueel oude queue verwijderen
// en queue opnieuw proberen aan te maken.
while ((messageQueue = msgget(key, 0666 | IPC_CREAT| IPC_EXCL)) < 0) {
perror("msgget");
// message queue verwijderen als deze al bestaat
if (msgctl(messageQueue, IPC_RMID, &mq_id) == -1) {
perror("msgctl1");
exit(1);
}
}
change_queue_mode(messageQueue, "0666");
buildConnection();
return 0;
}
int get_queue_ds(int qid, struct msqid_ds *qbuf) {
if (msgctl(qid, IPC_STAT, qbuf) == -1) {
perror("msgctl IPC_STAT");
exit(1);
}
return 0;
}
int change_queue_mode(int qid, char *mode) {
struct msqid_ds tmpbuf;
// Retrieve a current copy of the internal data structure
get_queue_ds(qid, &tmpbuf);
// Change the permissions using an old trick
sscanf(mode, "%ho", &tmpbuf.msg_perm.mode);
// Update the internal data structure
if (msgctl(qid, IPC_SET, &tmpbuf) == -1) {
perror("msgctl IPC_SET");
exit(1);
}
return (0);
}
void buildConnection() {
pthread_t child;
int sockfd;
int nSockfd;
socklen_t sockaddrSize;
struct sockaddr_in addr;
int optValue = 1;
char ipAdres[32] = "192.168.80.2";
sockaddrSize = sizeof (struct sockaddr_in);
// create socket
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("[socket()]");
exit(1);
} else {
printf("================================================================\n\n");
printf("Socket is succesfully created.\n\n");
}
// fill dat socket
addr.sin_family = AF_INET;
addr.sin_port = htons(PORT);
inet_aton(ipAdres, &addr.sin_addr);
bzero(&(addr.sin_zero), 8);
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &optValue, sizeof (int)) == -1) {
perror("[setsockopt()]");
exit(1);
}
if (bind(sockfd, (struct sockaddr*) &addr, sizeof (struct sockaddr)) == -1) {
perror("[bind()]");
exit(1);
} else {
printf("================================================================\n\n");
printf("bind succesful");
}
if (listen(sockfd, MAXCLIENTS) == -1) {
perror("[listen()]");
exit(1);
} else {
printf("================================================================\n\n");
printf("Listening on port %d\n\n", PORT);
}
// Connection loop
while (1) {
// accept incoming clients
if ((nSockfd = accept(sockfd, (struct sockaddr *) &client, &sockaddrSize)) == -1) {
perror("[accept()]");
exit(1);
} else {
pthread_create(&child, NULL, childThread, (void *) nSockfd);
}
}
}
void *childThread(void *nSockfd) {
int sizeOfRecvFile = 0;
char recvBuffer[PACKETSIZE];
char *clientCommand; // request type
printf("================================================================\n\n");
printf("connected to client with IP: %s.\n\n", inet_ntoa(client.sin_addr));
bzero(recvBuffer, PACKETSIZE);
// get dem datas
while ((sizeOfRecvFile = recv((int) nSockfd, recvBuffer, PACKETSIZE, 0)) > 0) {
if (sizeOfRecvFile == 0) {
break;
}
printf("received buffer: %s\n", recvBuffer);
// handle protocol flag
// chop protocol into pieces to check packet data and flags
clientCommand = strtok(recvBuffer, "#");
printf("packet type: %s\n", clientCommand);
// if clientCommand == 4
// incoming file!
if (strcmp(clientCommand, "4") == 0) {
uploadFile((int) nSockfd);
}
}
return 0;
}
void uploadFile(int nSockfd) {
int sizeOfRecvFile = 0;
// if recv() is 0 close connection
while (sizeOfRecvFile != 0) {
if (serverStaat == 0) {
sizeOfRecvFile = recv((int) nSockfd, req.pakket.buffer, PACKETSIZE, 0);
if (sizeOfRecvFile < 0) {
perror("[receive()]");
exit(0);
} else if (sizeOfRecvFile == 0) {
printf("Client disconnected\n");
close((int) nSockfd);
pthread_exit(NULL);
}
// send packet to message queue
req.mtype = RESP_MT_DATA;
req.pakket.clientID = messageQueue;
if (msgsnd(messageQueue, &req, PACKETSIZE, 0) == -1) {
perror("msgsnd");
}
}
}
req.mtype = RESP_MT_END;
msgsnd(messageQueue, &req, 0, 0);
close((int) nSockfd);
printf("================================================================\n\n");
printf("Disconnected, now waiting for other clients...\n\n");
}
The above program uses a custom made header file:
#include <sys/types.h>
#include <sys/msg.h>
#include <sys/stat.h>
#include <stddef.h>
#include <limits.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/wait.h>
#define PACKETSIZE 65535
struct message {
long mtype;
struct packet {
int clientID;
char buffer[PACKETSIZE];
} packet;
};
#define REQ_MSG_SIZE (offsetof(struct message.pakket, buffer) - \
offsetof(struct message.pakket, clientID) - PACKETSIZE)
struct responseMsg { // Responses (server to client)
long mtype; // One of RESP_MT_* values below
char data[PACKETSIZE]; // File content / response message
};
// Types for response messages sent from server to client
#define RESP_MT_FAILURE 1 // File couldn't be opened
#define RESP_MT_DATA 2 // Message contains file data
#define RESP_MT_END 3 // File data complete
I also made a process which writes the uploaded files to the hdd. This process gets data from the message queue that was created in the connection process. The code:
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <signal.h>
#include <ctype.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <unistd.h>
#include "/home/CommProces/mailbox.h"
#define POORTNR 5002
#define MAXCLIENTS 5
// prototyping
void writeFiles();
struct message resp;
int uploadMessage;
ssize_t msgLen;
int main () {
key_t key;
if(key = ftok("/home/CommProces/ftokDing", 13) < 0) {
perror("ftok");
exit(1);
}
uploadMessage = msgget(key, 0666);
if (uploadMessage == -1) {
perror("msgget");
exit(1);
}
while(1) {
writeFiles();
}
}
void writeFiles() {
char recvBuffer[PACKETSIZE];
char *rights, *pathname, *filename, *temp;
char *pathOfRecvFile; // received files will go here
FILE* theFile;
bzero(recvBuffer, PACKETSIZE);
int numMsgs, totBytes;
int sizeOfRecvFile = 0;
int nBytesToDisk = 0;
totBytes = msgLen; // Count first message
for (numMsgs = 1; resp.mtype == RESP_MT_DATA; numMsgs++) {
msgLen = msgrcv(uploadMessage, &resp, PACKETSIZE, 0, 0);
if (msgLen == -1) {
perror("msgrcv");
totBytes += msgLen;
}
*recvBuffer = *resp.pakket.buffer;
//temp = strtok(recvBuffer,"#");
rights = strtok(NULL,"#");
if(strcmp(rights, "private") == 0) {
temp = strtok(NULL,"#");
pathname = strcat("/home/MtFS/UploadedFiles/private/", temp);
} else {
pathname = "/home/MtFS/UploadedFiles/public";
}
filename = strcat("/", strtok(NULL,"#"));
pathOfRecvFile = strcat(filename, pathname);
theFile = fopen(pathOfRecvFile, "wb");
if(theFile == NULL) {
printf("[Open_File] unable to create file %s\n", pathOfRecvFile);
} else {
nBytesToDisk = fwrite(recvBuffer, sizeof(char), sizeOfRecvFile, theFile);
if(nBytesToDisk < sizeOfRecvFile) {
perror("fwrite");
}
printf("=============================================================================================================================\n\n");
printf("Files received and placed on HDD\n\n");
bzero(recvBuffer, PACKETSIZE);
}
if (resp.mtype == RESP_MT_FAILURE) {
printf("mtype = fail");
} else if(resp.mtype == RESP_MT_END) {
printf("mtype = end of data");
fclose(theFile);
}
}
}
I've been sifting through breakpoints with the debugger but I can't lay my finger on what's causing the problem :(
For starters, the 3rd parameter to msgrcv() gives the size of the message's payload.
So this line
msgLen = msgrcv(uploadMessage, &resp, PACKETSIZE, 0, 0);
should be
msgLen = msgrcv(uploadMessage, &resp, sizeof(resp)-sizeof(resp.mtype), 0, 0);
or
msgLen = msgrcv(uploadMessage, &resp, sizeof(resp.packet), 0, 0);
Also calling strtok() with the 1st argument set to NULL, does not make sense. It initialy needs to be called with the 1st agrment pointing to some 0 -terminated char-array.
Also^2: Trying to concatenate to a string literal uinsg strcat() like here:
pathname = strcat("/home/MtFS/UploadedFiles/private/", temp);
invokes undefined behaviour.
To fix this make pathname a buffer, instead of a pointer:
char pathname[PATHMAX] = "";
...
if(strcmp(rights, "private") == 0) {
temp = strtok(NULL,"#");
strcpy(pathname, "/home/MtFS/UploadedFiles/private/");
strcat(pathname, temp);
} else {
strcpy(pathname, "/home/MtFS/UploadedFiles/public");
}
The code you posted is describing a non-trivial system, involving a tcp-to-mq proxy (the client) and a mq-server. I strongly advise to debug those compoments separately.