I am writing a C HTTP server for a class. I have a rough implementation working, but I am stuck on this issue. I am trying to multi-thread the GET requests sent from a browser, but the server is just closing the connection after ~10 requests.
Here is the code:
#include <sys/types.h>
#include <sys/socket.h>
#include <time.h>
#include <sys/resource.h>
#include <sys/wait.h>
#include <sys/errno.h>
#include <sys/stat.h>
#include <netinet/in.h>
#include <netdb.h>
#include <pthread.h>
#include <stdarg.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#define SERVPORT 5004
#define BUFSIZE 4096
#define MAXCONNECT 3
#define MAX_THREADS 8
struct data
{
int i;
};
void * clientHandler(void *info);
void sendError(char *msg);
char * getDate();
int sendall(int send_socket, char *buf, int *len);
int parseSrc(char src[]);
char *get_ip_str(const struct sockaddr *sa, char *s, size_t maxlen);
char date[100];
char http200[50] = "HTTP/1.1 200 OK\n";
char http400[50] = "HTTP/1.1 400 Bad Request\n";
char http404[50] = "HTTP/1.1 404 Not Found\n";
int main()
{
printf("Starting server..\n");
int servSock, clntSock, fd;
struct sockaddr_in server, client;
unsigned int len, clntSize;
fd_set master;
fd_set read_fds;
int fdmax;
int i;
if( (servSock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1)
sendError("socket");
FD_ZERO(&master);
FD_ZERO(&read_fds);
memset(&server, 0, sizeof(server));
server.sin_family = AF_INET;
server.sin_port = htons(SERVPORT);
server.sin_addr.s_addr = htonl(INADDR_ANY);
for(i=0; i<=10; i++)
{
printf("Trying port %d...\n", (ntohs(server.sin_port) + i));
if( bind(servSock, (struct sockaddr *)&server, sizeof(server)) == -1)
server.sin_port = htons(SERVPORT + i);
else if(i < 10)
break; //socket connected succesfully
else
sendError("bind");
}
printf("Successfully bound to port %d!\n", ntohs(server.sin_port));
if( listen(servSock, MAXCONNECT) == -1)
sendError("listen");
printf("Listening...\n");
FD_SET(servSock, &master);
fdmax = servSock;
pthread_t threads[MAX_THREADS];
while(1)
{
read_fds = master;
int num_threads = 0;
if( select(fdmax + 1, &read_fds, NULL, NULL, NULL) == -1)
sendError("select");
for(i = 0; i <= fdmax; i++)
{
if(FD_ISSET(i, &read_fds))
{
if(i == servSock)
{
clntSize = sizeof(client);
if( (clntSock = accept(servSock, (struct sockaddr *)&client, &clntSize)) == -1)
sendError("accept");
FD_SET(clntSock, &master);
if(clntSock > fdmax)
fdmax = clntSock;
char s[50];
printf("Connected to %s\n", get_ip_str((struct sockaddr *)&client, s, sizeof(s)));
}
else
{
//clientHandler(i);
struct data *info;
info = malloc(sizeof(struct data));
info->i = i;
if(pthread_create(&threads[i], NULL, (void *)clientHandler, (void *)info))
sendError("pthread");
num_threads++;
}
}
}
if(num_threads > MAX_THREADS)
{
num_threads = 0;
pthread_join(threads[num_threads], NULL);
}
}
for(i = 0; i < MAX_THREADS; i++)
{
pthread_join(threads[i], NULL);
}
}
void *clientHandler(void *info)
{
struct data *myinfo = (struct data*) info;
int clntSock = myinfo->i;
char buf[BUFSIZE];
int recd;
if( (recd = recv(clntSock, buf, BUFSIZE, 0)) == -1)
sendError("recieve1");
while(recd > 0)
{
char cmd[5] = "/0";
char src[100] = "/0";
char prt[100] = "/0";
memset(&cmd, 0, sizeof(cmd));
memset(&src, 0, sizeof(src));
memset(&prt, 0, sizeof(prt));
sscanf(buf, "%4s%99s%99s", cmd, src, prt);
char cmdget[5] = "GET";
if(strcmp(cmd, cmdget) == 0) //GET command
{
int len;
if(src[0] == '/')
memmove(src, src+1, strlen(src));
if(strlen(src) == 0)
strcpy(src, "index.html");
FILE *fp;
fp = fopen(src, "r");
if(fp == NULL)
{
len = strlen(http404);
if(sendall(clntSock, http404, &len) == -1)
sendError("send 404");
break;
}
struct stat buf;
fstat(fileno(fp), &buf);
char contLen[50] = "Content-Length: ";
sprintf(contLen, "%s%d\n", contLen, (int)buf.st_size);
char contType[100] = "Content-Type: ";
char *tempType;
tempType = strrchr(src, '.');
if(strcmp(tempType, ".html") == 0) //.html
strcat(contType, "text/html\n");
else if(strcmp(tempType, ".txt") == 0) //.txt
strcat(contType, "text/txt\n");
else if(strcmp(tempType, ".css") == 0) //.css
strcat(contType, "text/css\n");
else if(strcmp(tempType, ".jpg") == 0) //.jpg
strcat(contType, "image/jpg\n");
else if(strcmp(tempType, ".png") == 0) //.png
strcat(contType, "image/png\n");
else if(strcmp(tempType, ".gif") == 0) //.gif
strcat(contType, "image/gif\n");
else if(strcmp(tempType, ".js") == 0) //.js
strcat(contType, "application/javascript\n");
else
{
char fileErrorTemp[50] = "Unknown filetype: ";
strcat(fileErrorTemp, tempType);
sendError(fileErrorTemp);
}
char tempDate[100] = "";
strcpy(tempDate, getDate());
char tempMsg[500] = "";
strcat(tempMsg, http200);
strcat(tempMsg, tempDate);
strcat(tempMsg, contType);
strcat(tempMsg, contLen);
strcat(tempMsg, "\n");
len = strlen(tempMsg);
if( sendall(clntSock, tempMsg, &len) == -1)
sendError("send 200");
printf("Sent client: %s # %s", http200, tempDate);
printf(" Sending %s\n", src);
if( sendfile(fp, clntSock) == -1)
sendError("file send");
}
else //Unknown or bad command
{
int http400len = strlen(http400);
if( send(clntSock, http400, strlen(http400), 0) == -1)
sendError("send 400");
}
printf("Waiting to receive...\n");
if( (recd = recv(clntSock,buf, BUFSIZE, 0)) == -1)
sendError("recieve1");
//printf("%d\n", recd);
}
close(clntSock);
return;
}
void sendError(char *msg)
{
perror(msg);
exit(-1);
}
char * getDate() //return date in "Date: Tue, 16 Feb 2010 19:21:24 GMT" format
{
memset(&date, 0, sizeof(date));
strcpy(date, "Date: ");
time_t rawtime = time(0);
struct tm * info;
time(&rawtime);
info = gmtime(&rawtime);
char wday[5];
char mon[5];
switch(info->tm_wday){
case 0: strcpy(wday, "Mon");
case 1: strcpy(wday, "Tue");
case 2: strcpy(wday, "Wed");
case 3: strcpy(wday, "Thu");
case 4: strcpy(wday, "Fri");
case 5: strcpy(wday, "Sat");
case 6: strcpy(wday, "Sun");
}
switch(info->tm_mon){
case 0: strcpy(mon, "Jan");
case 1: strcpy(mon, "Feb");
case 2: strcpy(mon, "Mar");
case 3: strcpy(mon, "Apr");
case 4: strcpy(mon, "May");
case 5: strcpy(mon, "Jun");
case 6: strcpy(mon, "Jul");
case 7: strcpy(mon, "Aug");
case 8: strcpy(mon, "Sep");
case 9: strcpy(mon, "Oct");
case 10: strcpy(mon, "Nov");
case 11: strcpy(mon, "Dec");
}
char temp[5];
strcat(date, wday);
strcat(date, ", ");
sprintf(temp, "%2d", info->tm_mday);
strcat(date, temp);
strcat(date, " ");
strcat(date, mon);
sprintf(temp, " %4d ", (info->tm_year + 1900));
strcat(date, temp);
sprintf(temp, "%d:", info->tm_hour);
strcat(date, temp);
sprintf(temp, "%.2d:", info->tm_min);
strcat(date, temp);
sprintf(temp, "%.2d", info->tm_sec);
strcat(date, temp);
strcat(date, " UTC\n");
return date;
}
int sendall(int send_socket, char *buf, int *len)
{
int total = 0;
int bytesleft = *len;
int n;
while(total < *len)
{
n = send(send_socket, (buf + total), bytesleft, 0);
if(n == -1)
break;
total += n;
bytesleft -= n;
}
*len = total;
if(n==-1)
return -1;
else
return 0;
}
int sendfile(FILE* fp, int clntSock)
{
while(1)
{
unsigned char buff[256]={0};
int nread = fread(buff, 1, 256, fp);
if(nread > 0)
write(clntSock, buff, nread);
if(nread < 256)
{
if(feof(fp))
break; //eof
if(ferror(fp))
return -1;
}
}
return 0;
}
int parseSrc(char src[])
{
printf("%s", src);
if(src[0] == '/')
{
printf("SLASH");
src++;
return 2;
}
printf("%s", src);
return 1;
}
char *get_ip_str(const struct sockaddr *sa, char *s, size_t maxlen)
{
switch(sa->sa_family)
{
case AF_INET:
inet_ntop(AF_INET, &(((struct sockaddr_in *)sa)->sin_addr), s, maxlen);
break;
case AF_INET6:
inet_ntop(AF_INET6, &(((struct sockaddr_in6 *)sa)->sin6_addr), s, maxlen);
break;
default:
strncpy(s, "Unknown AF", maxlen);
return NULL;
}
return s;
}
I am really stuck. Any help would be greatly appreciated!
Related
There are two clients and a server in the application. The two clients communicate with each other via the server. When one client sends a message to the server, the server stores the message as a text file in the server, where file name is clientid_timestamp.txt. The server then sends the file to the other client that reads the file and displays its content on its terminal.
I have written the code for the client and the server given below.The issue that I am facing is that the client is not able to get the file from the server print it's contents.It doesn't show an output in the terminal.
Server side image in terminal
client side image in terminal
Server code:
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <pthread.h>
#include <sys/types.h>
#include <signal.h>
#define MAX_CLIENTS 3
#define BUFFER_SZ 2048
#define SIZE 1024
static _Atomic unsigned int cli_count = 0;
static int uid = 10;
/* Client structure */
typedef struct{
struct sockaddr_in address;
int sockfd;
int uid;
char name[32];
} client_t;
client_t *clients[MAX_CLIENTS];
pthread_mutex_t clients_mutex = PTHREAD_MUTEX_INITIALIZER;
void str_overwrite_stdout() {
printf("\r%s", "> ");
fflush(stdout);
}
void print_client_addr(struct sockaddr_in addr){
printf("%d.%d.%d.%d",
addr.sin_addr.s_addr & 0xff,
(addr.sin_addr.s_addr & 0xff00) >> 8,
(addr.sin_addr.s_addr & 0xff0000) >> 16,
(addr.sin_addr.s_addr & 0xff000000) >> 24);
}
/* Add clients to queue */
void queue_add(client_t *cl){
pthread_mutex_lock(&clients_mutex);
for(int i=0; i < MAX_CLIENTS; ++i){
if(!clients[i]){
clients[i] = cl;
break;
}
}
pthread_mutex_unlock(&clients_mutex);
}
/* Remove clients to queue */
void queue_remove(int uid){
pthread_mutex_lock(&clients_mutex);
for(int i=0; i < MAX_CLIENTS; ++i){
if(clients[i]){
if(clients[i]->uid == uid){
clients[i] = NULL;
break;
}
}
}
pthread_mutex_unlock(&clients_mutex);
}
void send_file(int sockfd){
int n;
char data[SIZE] = {0};
FILE *fp = fopen("clientid_timestamp.txt", "r");
if (fp == NULL){
printf("Error opening file!\n");
exit(1);
}
while(fgets(data, SIZE, fp) != NULL) {
if (send(sockfd, data, sizeof(data), 0) == -1) {
perror("[-]Error in sending file.");
exit(1);
}
printf("hello");
bzero(data, SIZE);
}
}
/* Send message to all clients except sender */
void send_message(char *s, int uid){
pthread_mutex_lock(&clients_mutex);
for(int i=0; i<MAX_CLIENTS; ++i){
if(clients[i]){
if(clients[i]->uid != uid){
printf("MESSAGE SENT TO %s:%d \n",inet_ntoa(clients[i]->address.sin_addr),ntohs(clients[i]->address.sin_port));
send_file(clients[i]->uid);
}
}
}
pthread_mutex_unlock(&clients_mutex);
}
/* Handle all communication with the client */
void *handle_client(void *arg){
char buff_out[BUFFER_SZ];
char name[32];
int leave_flag = 0;
cli_count++;
client_t *cli = (client_t *)arg;
// Name
bzero(buff_out, BUFFER_SZ);
while(1){
if (leave_flag) {
break;
}
int receive = recv(cli->sockfd, buff_out, BUFFER_SZ, 0);
if (receive > 0){
if(strlen(buff_out) > 0){
FILE *f = fopen("clientid_timestamp.txt", "w");
if (f == NULL){
printf("Error opening file!\n");
exit(1);
}
/* print some text */
fprintf(f, "%s", buff_out);
send_message(buff_out, cli->uid);
fclose(f);
printf("\n");
}
}
else {
printf("ERROR: -1\n");
leave_flag = 1;
}
bzero(buff_out, BUFFER_SZ);
}
/* Delete client from queue and yield thread */
close(cli->sockfd);
queue_remove(cli->uid);
free(cli);
cli_count--;
pthread_detach(pthread_self());
return NULL;
}
int main(int argc, char **argv){
if(argc != 2){
printf("Usage: %s <port>\n", argv[0]);
return EXIT_FAILURE;
}
char *ip = "127.0.0.1";
int port = atoi(argv[1]);
int option = 1;
int listenfd = 0, connfd = 0;
struct sockaddr_in serv_addr;
struct sockaddr_in cli_addr;
pthread_t tid;
/* Socket settings */
listenfd = socket(AF_INET, SOCK_STREAM, 0);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = inet_addr(ip);
serv_addr.sin_port = htons(port);
/* Ignore pipe signals */
signal(SIGPIPE, SIG_IGN);
if(setsockopt(listenfd, SOL_SOCKET,(SO_REUSEPORT | SO_REUSEADDR),(char*)&option,sizeof(option)) < 0){
perror("ERROR: setsockopt failed");
return EXIT_FAILURE;
}
/* Bind */
if(bind(listenfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) {
perror("ERROR: Socket binding failed");
return EXIT_FAILURE;
}
/* Listen */
if (listen(listenfd, 10) < 0) {
perror("ERROR: Socket listening failed");
return EXIT_FAILURE;
}
printf("=== WELCOME TO THE CHATROOM ===\n");
char exit[] = "exit_client";
char accepted[] = "accept_client";
while(1){
socklen_t clilen = sizeof(cli_addr);
connfd = accept(listenfd, (struct sockaddr*)&cli_addr, &clilen);
/* Check if max clients is reached */
if((cli_count) == MAX_CLIENTS){
printf("Max clients reached. Rejected: ");
print_client_addr(cli_addr);
printf(":%d\n", cli_addr.sin_port);
send(connfd, exit, strlen(exit), 0);
close(connfd);
continue;
}
else{
send(connfd, accepted, strlen(accepted), 0);
client_t *cli = (client_t *)malloc(sizeof(client_t));
cli->address = cli_addr;
cli->sockfd = connfd;
cli->uid = uid++;
printf("Client Connected : ");
printf("%s:%d \n",inet_ntoa(cli->address.sin_addr),ntohs(cli->address.sin_port));
/* Add client to the queue and fork thread */
queue_add(cli);
pthread_create(&tid, NULL, &handle_client, (void*)cli);
/* Reduce CPU usage */
sleep(1);
}
/* Client settings */
}
return EXIT_SUCCESS;
}
Client Code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
#define LENGTH 2048
#define MAX 10000
// Global variables
volatile sig_atomic_t flag = 0;
int sockfd = 0;
char name[32];
void str_overwrite_stdout() {
printf("%s", "> ");
fflush(stdout);
}
void str_trim_lf (char* arr, int length) {
int i;
for (i = 0; i < length; i++) { // trim \n
if (arr[i] == '\n') {
arr[i] = '\0';
break;
}
}
}
void catch_ctrl_c_and_exit(int sig) {
flag = 1;
}
void send_msg_handler() {
char message[LENGTH] = {};
char buffer[LENGTH + 32] = {};
while(1) {
str_overwrite_stdout();
fgets(message, LENGTH, stdin);
//str_trim_lf(message, LENGTH);
if (strcmp(message, "exit") == 0) {
break;
} else {
sprintf(buffer, "%s\n", message);
send(sockfd, buffer, strlen(buffer), 0);
}
bzero(message, LENGTH);
bzero(buffer, LENGTH + 32);
}
catch_ctrl_c_and_exit(2);
}
void recv_msg_handler() {
while (1) {
int n;
FILE *fp;
char buff[1024]="",*ptr=buff;
int bytes=0,bytes_received;
while(bytes_received = recv(sockfd,ptr, 1, 0)){
printf("%s\n",ptr);
if(bytes_received==-1){
perror("recieve");
exit(3);
}
if(*ptr=='\n' ) break;
ptr++; //each times we increment it it points to the buffer element
}
*ptr=0;
ptr=buff;
printf("%s\n",ptr);
str_overwrite_stdout();
}
}
int main(int argc, char **argv){
if(argc != 2){
printf("Usage: %s <port>\n", argv[0]);
return EXIT_FAILURE;
}
char *ip = "127.0.0.1";
int port = atoi(argv[1]);
signal(SIGINT, catch_ctrl_c_and_exit);
struct sockaddr_in server_addr;
/* Socket settings */
sockfd = socket(AF_INET, SOCK_STREAM, 0);
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = inet_addr(ip);
server_addr.sin_port = htons(port);
// Connect to Server
int err = connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr));
if (err == -1) {
printf("ERROR: connect\n");
return EXIT_FAILURE;
}
char exit_client[] = "exit_client";
char buff[MAX];
bzero(buff, sizeof(buff));
recv(sockfd, buff, 1024, 0);
if((strcmp(buff, exit_client) == 0)){
printf("limit exceeded , closing the client \n");
close(sockfd);
return EXIT_SUCCESS;
}
else{
printf("client accepted by the server and limit not exceeded \n");
}
printf("=== WELCOME TO THE CHATROOM ===\n");
pthread_t send_msg_thread;
if(pthread_create(&send_msg_thread, NULL, (void *) send_msg_handler, NULL) != 0){
printf("ERROR: pthread\n");
return EXIT_FAILURE;
}
pthread_t recv_msg_thread;
if(pthread_create(&recv_msg_thread, NULL, (void *) recv_msg_handler, NULL) != 0){
printf("ERROR: pthread\n");
return EXIT_FAILURE;
}
while (1){
if(flag){
printf("\nBye\n");
break;
}
}
close(sockfd);
return EXIT_SUCCESS;
}
EDIT-1
I have made the changes suggested by the user stackinside and the code now works , but I have being facing a new issue for the past few hours and I am not able to wrap my head around it as what could the reason for it.
The issue that arises now is that the client is only able to send the message once to other client and vice versa and then it is not able to send any more messages except a new line.The updated code based on the changes I made
client side image in terminal
server side image in terminal
Server code :
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <pthread.h>
#include <sys/types.h>
#include <signal.h>
#define MAX_CLIENTS 3
#define BUFFER_SZ 2048
#define SIZE 1024
static _Atomic unsigned int cli_count = 0;
static int uid = 10;
/* Client structure */
typedef struct{
struct sockaddr_in address;
int sockfd;
int uid;
char name[32];
} client_t;
client_t *clients[MAX_CLIENTS];
void str_trim_lf (char* arr, int length) {
int i;
for (i = 0; i < length; i++) { // trim \n
if (arr[i] == '\n') {
arr[i] = '\0';
break;
}
}
}
pthread_mutex_t clients_mutex = PTHREAD_MUTEX_INITIALIZER;
void str_overwrite_stdout() {
printf("\r%s", "> ");
fflush(stdout);
}
void print_client_addr(struct sockaddr_in addr){
printf("%d.%d.%d.%d",
addr.sin_addr.s_addr & 0xff,
(addr.sin_addr.s_addr & 0xff00) >> 8,
(addr.sin_addr.s_addr & 0xff0000) >> 16,
(addr.sin_addr.s_addr & 0xff000000) >> 24);
}
/* Add clients to queue */
void queue_add(client_t *cl){
pthread_mutex_lock(&clients_mutex);
for(int i=0; i < MAX_CLIENTS; ++i){
if(!clients[i]){
clients[i] = cl;
break;
}
}
pthread_mutex_unlock(&clients_mutex);
}
/* Remove clients to queue */
void queue_remove(int uid){
pthread_mutex_lock(&clients_mutex);
for(int i=0; i < MAX_CLIENTS; ++i){
if(clients[i]){
if(clients[i]->uid == uid){
clients[i] = NULL;
break;
}
}
}
pthread_mutex_unlock(&clients_mutex);
}
void send_file(int sockfd){
int n;
char data[SIZE] = {0};
FILE *fp = fopen("clientid_timestamp.txt", "r");
if (fp == NULL){
printf("Error opening file!\n");
exit(1);
}
while(fgets(data, SIZE, fp) != NULL) {
if (send(sockfd, data, sizeof(data), 0) == -1) {
perror("[-]Error in sending file.");
exit(1);
}
bzero(data, SIZE);
}
}
/* Send message to all clients except sender */
void send_message(char *s, int uid){
pthread_mutex_lock(&clients_mutex);
for(int i=0; i<MAX_CLIENTS; ++i){
if(clients[i]){
if(clients[i]->uid != uid){
printf("MESSAGE SENT TO %s:%d \n",inet_ntoa(clients[i]->address.sin_addr),ntohs(clients[i]->address.sin_port));
send_file(clients[i]->sockfd);
}
}
}
pthread_mutex_unlock(&clients_mutex);
}
/* Handle all communication with the client */
void *handle_client(void *arg){
char buff_out[BUFFER_SZ];
char name[32];
int leave_flag = 0;
cli_count++;
client_t *cli = (client_t *)arg;
// Name
bzero(buff_out, BUFFER_SZ);
while(1){
if (leave_flag) {
break;
}
int receive = recv(cli->sockfd, buff_out, BUFFER_SZ, 0);
if (receive > 0){
if(strlen(buff_out) > 0){
FILE *f = fopen("clientid_timestamp.txt", "w");
if (f == NULL){
printf("Error opening file!\n");
exit(1);
}
/* print some text */
fprintf(f, "%s", buff_out);
fclose(f);
send_message(buff_out, cli->uid);
printf("\n");
}
}
else {
printf("ERROR: -1\n");
leave_flag = 1;
}
bzero(buff_out, BUFFER_SZ);
}
/* Delete client from queue and yield thread */
close(cli->sockfd);
queue_remove(cli->uid);
free(cli);
cli_count--;
pthread_detach(pthread_self());
return NULL;
}
int main(int argc, char **argv){
if(argc != 2){
printf("Usage: %s <port>\n", argv[0]);
return EXIT_FAILURE;
}
char *ip = "127.0.0.1";
int port = atoi(argv[1]);
int option = 1;
int listenfd = 0, connfd = 0;
struct sockaddr_in serv_addr;
struct sockaddr_in cli_addr;
pthread_t tid;
/* Socket settings */
listenfd = socket(AF_INET, SOCK_STREAM, 0);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = inet_addr(ip);
serv_addr.sin_port = htons(port);
/* Ignore pipe signals */
signal(SIGPIPE, SIG_IGN);
if(setsockopt(listenfd, SOL_SOCKET,(SO_REUSEPORT | SO_REUSEADDR),(char*)&option,sizeof(option)) < 0){
perror("ERROR: setsockopt failed");
return EXIT_FAILURE;
}
/* Bind */
if(bind(listenfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) {
perror("ERROR: Socket binding failed");
return EXIT_FAILURE;
}
/* Listen */
if (listen(listenfd, 10) < 0) {
perror("ERROR: Socket listening failed");
return EXIT_FAILURE;
}
printf("=== WELCOME TO THE CHATROOM ===\n");
char exit[] = "exit_client";
char accepted[] = "accept_client";
while(1){
socklen_t clilen = sizeof(cli_addr);
connfd = accept(listenfd, (struct sockaddr*)&cli_addr, &clilen);
/* Check if max clients is reached */
if((cli_count) == MAX_CLIENTS){
printf("Max clients reached. Rejected: ");
print_client_addr(cli_addr);
printf(":%d\n", cli_addr.sin_port);
send(connfd, exit, strlen(exit), 0);
close(connfd);
continue;
}
else{
send(connfd, accepted, strlen(accepted), 0);
client_t *cli = (client_t *)malloc(sizeof(client_t));
cli->address = cli_addr;
cli->sockfd = connfd;
cli->uid = uid++;
printf("Client Connected : ");
printf("%s:%d \n",inet_ntoa(cli->address.sin_addr),ntohs(cli->address.sin_port));
/* Add client to the queue and fork thread */
queue_add(cli);
pthread_create(&tid, NULL, &handle_client, (void*)cli);
/* Reduce CPU usage */
sleep(1);
}
/* Client settings */
}
return EXIT_SUCCESS;
}
Client code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
#define LENGTH 2048
#define MAX 10000
// Global variables
volatile sig_atomic_t flag = 0;
int sockfd = 0;
char name[32];
void str_overwrite_stdout() {
printf("%s", "> ");
fflush(stdout);
}
void str_trim_lf (char* arr, int length) {
int i;
for (i = 0; i < length; i++) { // trim \n
if (arr[i] == '\n') {
arr[i] = '\0';
break;
}
}
}
void catch_ctrl_c_and_exit(int sig) {
flag = 1;
}
void send_msg_handler() {
char message[LENGTH] = {};
char buffer[LENGTH + 32] = {};
while(1) {
str_overwrite_stdout();
fgets(message, LENGTH, stdin);
str_trim_lf(message, LENGTH);
if (strcmp(message, "exit") == 0) {
break;
} else {
sprintf(buffer, "%s\n", message);
send(sockfd, buffer, strlen(buffer), 0);
}
bzero(message, LENGTH);
bzero(buffer, LENGTH + 32);
}
catch_ctrl_c_and_exit(2);
}
void recv_msg_handler() {
int n;
FILE *fp;
char buff[1024]="",*ptr=buff;
int bytes=0,bytes_received;
while (1) {
while(bytes_received = recv(sockfd,ptr, 1, 0)){
if(bytes_received==-1){
perror("recieve");
exit(3);
}
if(*ptr=='\n' ) break;
ptr++; //each times we increment it it points to the buffer element
}
*ptr=0;
str_trim_lf(buff, strlen(buff));
ptr=buff;
printf("%s \n",ptr);
str_overwrite_stdout();
}
}
int main(int argc, char **argv){
if(argc != 2){
printf("Usage: %s <port>\n", argv[0]);
return EXIT_FAILURE;
}
char *ip = "127.0.0.1";
int port = atoi(argv[1]);
signal(SIGINT, catch_ctrl_c_and_exit);
struct sockaddr_in server_addr;
/* Socket settings */
sockfd = socket(AF_INET, SOCK_STREAM, 0);
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = inet_addr(ip);
server_addr.sin_port = htons(port);
// Connect to Server
int err = connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr));
if (err == -1) {
printf("ERROR: connect\n");
return EXIT_FAILURE;
}
char exit_client[] = "exit_client";
char buff[MAX];
bzero(buff, sizeof(buff));
recv(sockfd, buff, 1024, 0);
if((strcmp(buff, exit_client) == 0)){
printf("limit exceeded , closing the client \n");
close(sockfd);
return EXIT_SUCCESS;
}
else{
printf("client accepted by the server and limit not exceeded \n");
}
printf("=== WELCOME TO THE CHATROOM ===\n");
pthread_t send_msg_thread;
if(pthread_create(&send_msg_thread, NULL, (void *) send_msg_handler, NULL) != 0){
printf("ERROR: pthread\n");
return EXIT_FAILURE;
}
pthread_t recv_msg_thread;
if(pthread_create(&recv_msg_thread, NULL, (void *) recv_msg_handler, NULL) != 0){
printf("ERROR: pthread\n");
return EXIT_FAILURE;
}
while (1){
if(flag){
printf("\nBye\n");
break;
}
}
close(sockfd);
return EXIT_SUCCESS;
}
EDIT-2
So now I changed the fgets to freads and removed all the unnecessary bzero and changed the strlen to sizeof as suggested by the comments of user207421 , Martin James and stackinside .It finally works , I agree there is still a lot of room for optimisation , but it works for now and thanks for the effort.
client side image in terminal
Server side image in terminal
Client side code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
#define LENGTH 2048
#define MAX 10000
#define CHUNK_SIZE 512
// Global variables
volatile sig_atomic_t flag = 0;
int sockfd = 0;
char name[32];
void str_overwrite_stdout() {
printf("%s", "> ");
fflush(stdout);
}
void str_trim_lf (char* arr, int length) {
int i;
for (i = 0; i < length; i++) { // trim \n
if (arr[i] == '\n') {
arr[i] = '\0';
break;
}
}
}
void catch_ctrl_c_and_exit(int sig) {
flag = 1;
}
void send_msg_handler() {
char message[LENGTH] = {};
char buffer[LENGTH + 32] = {};
while(1) {
str_overwrite_stdout();
fgets(message, LENGTH, stdin);
str_trim_lf(message, LENGTH);
if (strcmp(message, "exit") == 0) {
break;
}
else {
sprintf(buffer, "%s\n", message);
send(sockfd, buffer, sizeof(buffer), 0);
}
bzero(message, LENGTH);
bzero(buffer, LENGTH + 32);
}
catch_ctrl_c_and_exit(2);
}
void recv_msg_handler() {
while (1) {
int n;
FILE *fp;
char buff[1024],*ptr=buff;
int bytes=0,bytes_received;
int file_size;
recv(sockfd, buff, CHUNK_SIZE, 0);
file_size = atoi(buff);
str_trim_lf(buff, sizeof(buff));
printf("%s \n",buff);
str_overwrite_stdout();
}
}
int main(int argc, char **argv){
if(argc != 2){
printf("Usage: %s <port>\n", argv[0]);
return EXIT_FAILURE;
}
char *ip = "127.0.0.1";
int port = atoi(argv[1]);
signal(SIGINT, catch_ctrl_c_and_exit);
struct sockaddr_in server_addr;
/* Socket settings */
sockfd = socket(AF_INET, SOCK_STREAM, 0);
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = inet_addr(ip);
server_addr.sin_port = htons(port);
// Connect to Server
int err = connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr));
if (err == -1) {
printf("ERROR: connect\n");
return EXIT_FAILURE;
}
char exit_client[] = "exit_client";
char buff[MAX];
bzero(buff, sizeof(buff));
recv(sockfd, buff, 1024, 0);
if((strcmp(buff, exit_client) == 0)){
printf("limit exceeded , closing the client \n");
close(sockfd);
return EXIT_SUCCESS;
}
else{
printf("client accepted by the server and limit not exceeded \n");
}
printf("=== WELCOME TO THE CHATROOM ===\n");
pthread_t send_msg_thread;
if(pthread_create(&send_msg_thread, NULL, (void *) send_msg_handler, NULL) != 0){
printf("ERROR: pthread\n");
return EXIT_FAILURE;
}
pthread_t recv_msg_thread;
if(pthread_create(&recv_msg_thread, NULL, (void *) recv_msg_handler, NULL) != 0){
printf("ERROR: pthread\n");
return EXIT_FAILURE;
}
while (1){
if(flag){
printf("\nBye\n");
break;
}
}
close(sockfd);
return EXIT_SUCCESS;
}
Server side:
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <pthread.h>
#include <sys/types.h>
#include <signal.h>
#define MAX_CLIENTS 3
#define BUFFER_SZ 2048
#define SIZE 1024
#define CHUNK_SIZE 512
static _Atomic unsigned int cli_count = 0;
static int uid = 10;
/* Client structure */
typedef struct{
struct sockaddr_in address;
int sockfd;
int uid;
char name[32];
} client_t;
client_t *clients[MAX_CLIENTS];
void str_trim_lf (char* arr, int length) {
int i;
for (i = 0; i < length; i++) { // trim \n
if (arr[i] == '\n') {
arr[i] = '\0';
break;
}
}
}
pthread_mutex_t clients_mutex = PTHREAD_MUTEX_INITIALIZER;
void str_overwrite_stdout() {
printf("\r%s", "> ");
fflush(stdout);
}
void print_client_addr(struct sockaddr_in addr){
printf("%d.%d.%d.%d",
addr.sin_addr.s_addr & 0xff,
(addr.sin_addr.s_addr & 0xff00) >> 8,
(addr.sin_addr.s_addr & 0xff0000) >> 16,
(addr.sin_addr.s_addr & 0xff000000) >> 24);
}
/* Add clients to queue */
void queue_add(client_t *cl){
pthread_mutex_lock(&clients_mutex);
for(int i=0; i < MAX_CLIENTS; ++i){
if(!clients[i]){
clients[i] = cl;
break;
}
}
pthread_mutex_unlock(&clients_mutex);
}
/* Remove clients to queue */
void queue_remove(int uid){
pthread_mutex_lock(&clients_mutex);
for(int i=0; i < MAX_CLIENTS; ++i){
if(clients[i]){
if(clients[i]->uid == uid){
clients[i] = NULL;
break;
}
}
}
pthread_mutex_unlock(&clients_mutex);
}
void send_file(int sockfd){
int n;
char data[SIZE] = {0};
FILE *fp = fopen("clientid_timestamp.txt", "r");
if (fp == NULL){
printf("Error opening file!\n");
exit(1);
}
char file_data[CHUNK_SIZE];
size_t nbytes = 0;
while ( (nbytes = fread(data, sizeof(char), CHUNK_SIZE,fp)) > 0){
if (send(sockfd, data, nbytes, 0) == -1) {
perror("[-]Error in sending file.");
exit(1);
}
}
}
/* Send message to all clients except sender */
void send_message(char *s, int uid){
pthread_mutex_lock(&clients_mutex);
for(int i=0; i<MAX_CLIENTS; ++i){
if(clients[i]){
if(clients[i]->uid != uid){
printf("MESSAGE SENT TO %s:%d \n",inet_ntoa(clients[i]->address.sin_addr),ntohs(clients[i]->address.sin_port));
send_file(clients[i]->sockfd);
}
}
}
pthread_mutex_unlock(&clients_mutex);
}
/* Handle all communication with the client */
void *handle_client(void *arg){
char buff_out[BUFFER_SZ];
char name[32];
int leave_flag = 0;
cli_count++;
client_t *cli = (client_t *)arg;
// Name
bzero(buff_out, BUFFER_SZ);
while(1){
if (leave_flag) {
break;
}
int receive = recv(cli->sockfd, buff_out, BUFFER_SZ, 0);
if (receive > 0){
if(strlen(buff_out) > 0){
FILE *f = fopen("clientid_timestamp.txt", "w");
if (f == NULL){
printf("Error opening file!\n");
exit(1);
}
/* print some text */
fprintf(f, "%s", buff_out);
fclose(f);
send_message(buff_out, cli->uid);
printf("\n");
}
}
else {
printf("ERROR: -1\n");
leave_flag = 1;
}
}
/* Delete client from queue and yield thread */
close(cli->sockfd);
queue_remove(cli->uid);
free(cli);
cli_count--;
pthread_detach(pthread_self());
return NULL;
}
int main(int argc, char **argv){
if(argc != 2){
printf("Usage: %s <port>\n", argv[0]);
return EXIT_FAILURE;
}
char *ip = "127.0.0.1";
int port = atoi(argv[1]);
int option = 1;
int listenfd = 0, connfd = 0;
struct sockaddr_in serv_addr;
struct sockaddr_in cli_addr;
pthread_t tid;
/* Socket settings */
listenfd = socket(AF_INET, SOCK_STREAM, 0);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = inet_addr(ip);
serv_addr.sin_port = htons(port);
/* Ignore pipe signals */
signal(SIGPIPE, SIG_IGN);
if(setsockopt(listenfd, SOL_SOCKET,(SO_REUSEPORT | SO_REUSEADDR),(char*)&option,sizeof(option)) < 0){
perror("ERROR: setsockopt failed");
return EXIT_FAILURE;
}
/* Bind */
if(bind(listenfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) {
perror("ERROR: Socket binding failed");
return EXIT_FAILURE;
}
/* Listen */
if (listen(listenfd, 10) < 0) {
perror("ERROR: Socket listening failed");
return EXIT_FAILURE;
}
printf("=== WELCOME TO THE CHATROOM ===\n");
char exit[] = "exit_client";
char accepted[] = "accept_client";
while(1){
socklen_t clilen = sizeof(cli_addr);
connfd = accept(listenfd, (struct sockaddr*)&cli_addr, &clilen);
/* Check if max clients is reached */
if((cli_count) == MAX_CLIENTS){
printf("Max clients reached. Rejected: ");
print_client_addr(cli_addr);
printf(":%d\n", cli_addr.sin_port);
send(connfd, exit, sizeof(exit), 0);
close(connfd);
continue;
}
else{
send(connfd, accepted, sizeof(accepted), 0);
client_t *cli = (client_t *)malloc(sizeof(client_t));
cli->address = cli_addr;
cli->sockfd = connfd;
cli->uid = uid++;
printf("Client Connected : ");
printf("%s:%d \n",inet_ntoa(cli->address.sin_addr),ntohs(cli->address.sin_port));
/* Add client to the queue and fork thread */
queue_add(cli);
pthread_create(&tid, NULL, &handle_client, (void*)cli);
/* Reduce CPU usage */
sleep(1);
}
/* Client settings */
}
return EXIT_SUCCESS;
}
Server side:
send_file(clients[i]->uid); ought to be send_file(clients[i]->sockfd);
fclose(f); should probably go before send_message(buff_out, cli->uid);
Client side:
printf("%s\n",ptr); (before if(bytes_received==-1)) ought to be removed
There are other inconsistencies, unused variables, etc. This reivew is very limited.
I wrote a simple protocol in which Im able to exchange files / text messages between client and server. If the client send a text to server, server should simply echo it back. On the other hand, when client send a special command (for example, SEND_TXT_FILE) server should receive a file uploaded by client to the server.
I almost got it work. However, there's still problem with sending files. Sever does not save the whole file, it only creates it and disconnects.
Here's the protocol:
CLIENT ---------- text1 ----------> SERVER
CLIENT <---------- text1 ---------- SERVER
CLIENT ---------- text2 ----------> SERVER
CLIENT <---------- text3 ---------- SERVER
CLIENT ---------- SENDTXTFILE ----------> SERVER
CLIENT <---------- OK ---------- SERVER
CLIENT ---------- FILENAME ----------> SERVER
CLIENT <---------- OK ---------- SERVER
CLIENT ---------- file content ----------> SERVER
CLIENT <--------- FILE_UPLOADED --------- SERVER
CLIENT ---------- text3 ----------> SERVER
CLIENT <---------- text3 ---------- SERVER
How can I solve this?
server.c
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <netdb.h>
#include <string.h>
#define BUFFER_SIZE 1024
int send_all(int sockfd, const char *buf, int len)
{
ssize_t n;
while (len > 0)
{
n = send(sockfd, buf, len, 0);
if (n < 0)
return -1;
buf += n;
len -= n;
}
return 0;
}
int recv_all(int sockfd, char *buf, int len)
{
ssize_t n;
while (len > 0)
{
n = recv(sockfd, buf, len, 0);
if (n <= 0)
return n;
buf += n;
len -= n;
}
return 1;
}
int recv_txt_file(int sockfd, int len, const char *filename)
{
FILE *fp = fopen(filename, "wb");
int total = 0, b = 0;
char buffer[BUFFER_SIZE];
memset(buffer, '\0', BUFFER_SIZE);
if (fp != NULL)
{
while (recv_all(sockfd, buffer, len) != 1)
{
total += b;
fwrite(buffer, 1, b, fp);
}
printf("Received byte: %d\n",total);
if (b < 0)
perror("Receiving");
fclose(fp);
}
else
{
perror("File");
}
close(sockfd);
}
int main()
{
int port = 6666;
int server_fd, client_fd, read;
struct sockaddr_in server, client;
char buffer[BUFFER_SIZE], filename[BUFFER_SIZE];
char remote_ip[16];
int remote_port, res = 0;
server_fd = socket(AF_INET, SOCK_STREAM, 0);
if (server_fd < 0)
{
perror("Could not create socket");
return 1;
}
int optval = 1;
setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, (const void *)&optval, sizeof(int));
memset(&server, '\0', sizeof(server));
server.sin_family = AF_INET;
server.sin_port = htons(port);
server.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(server_fd, (struct sockaddr *)&server, sizeof(server)) < 0)
{
perror("Could not bind socket");
close(server_fd);
return 1;
}
if (listen(server_fd, 1) < 0)
{
perror("Could not listen on socket");
close(server_fd);
return 1;
}
printf("Server TCP is listening on port %d ... \n", port);
socklen_t client_len = sizeof(client);
client_fd = accept(server_fd, (struct sockaddr *)&client, &client_len);
if (client_fd < 0)
{
perror("Could not establish new connection");
close(server_fd);
return 1;
}
remote_port = ntohs(client.sin_port);
inet_ntop(AF_INET, &client.sin_addr, remote_ip, sizeof(remote_ip));
printf("Client IP address: %s, port %d\n", remote_ip, remote_port);
while (1)
{
read = recv_all(client_fd, buffer, BUFFER_SIZE);
if (read <= 0)
{
if (read < 0)
perror("Client read failed");
else
printf("Client disconnected\n");
break;
}
if ((res = strcmp(buffer, "SENDFILE_TXT\n") == 0))
{
printf("-------FROM CLIENT: %s-------\n", buffer);
memset(buffer, BUFFER_SIZE, '\0');
strcpy(buffer, "OK");
if (send_all(client_fd, buffer, BUFFER_SIZE) < 0)
{
perror("Client write failed");
break;
}
read = recv_all(client_fd, buffer, BUFFER_SIZE);
if (read <= 0)
{
if (read < 0)
perror("Client read failed");
else
printf("Client disconnected\n");
break;
}
printf("-------FROM CLIENT: %s-------\n", buffer);
memset(filename, '\0', BUFFER_SIZE);
strcpy(filename, buffer);
memset(buffer, BUFFER_SIZE, '\0');
strcpy(buffer, "OK");
if (send_all(client_fd, buffer, BUFFER_SIZE) < 0)
{
perror("Client write failed");
break;
}
recv_txt_file(client_fd, BUFFER_SIZE, filename);
}
else
{
printf("FROM CLIENT: %.*s\n", BUFFER_SIZE, buffer);
if (send_all(client_fd, buffer, BUFFER_SIZE) < 0)
{
perror("Client write failed");
break;
}
}
}
close(client_fd);
close(server_fd);
return 0;
}
client.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <netdb.h>
#define BUFFER_SIZE 1024
socklen_t hostname_to_ip_port(char *hostname, int port, struct sockaddr_storage *addr)
{
int sockfd;
struct addrinfo hints, *servinfo;
int rv;
char service[20];
sprintf(service, "%d", port);
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
if ((rv = getaddrinfo(hostname, service, &hints, &servinfo)) != 0)
{
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
return 0;
}
socklen_t addrlen = servinfo->ai_addrlen;
memcpy(addr, servinfo->ai_addr, addrlen);
freeaddrinfo(servinfo);
return addrlen;
}
int send_all(int sockfd, const char *buf, size_t len)
{
ssize_t n;
while (len > 0)
{
n = send(sockfd, buf, len, 0);
if (n < 0)
return -1;
buf += n;
len -= n;
}
return 0;
}
int recv_all(int sockfd, char *buf, int len)
{
ssize_t n;
while (len > 0)
{
n = recv(sockfd, buf, len, 0);
if (n <= 0)
return n;
buf += n;
len -= n;
}
return 1;
}
long int get_file_size(char filename[])
{
// opening the file in read mode
FILE *fp = fopen(filename, "r");
// checking if the file exist or not
if (fp == NULL) {
printf("File Not Found!\n");
return -1;
}
fseek(fp, 0L, SEEK_END);
// calculating the size of the file
long int res = ftell(fp);
// closing the file
fclose(fp);
return res;
}
int send_txt_file(int sockfd, int len, const char *filename)
{
FILE *fp = fopen(filename, "r");
int b;
char buffer[BUFFER_SIZE];
memset(buffer, '\0', BUFFER_SIZE);
if (fp == NULL)
{
perror("Error while openning file");
return 0;
}
while ((b = fread(buffer, 1, BUFFER_SIZE, fp)) > 0){
send_all(sockfd, buffer, BUFFER_SIZE);
memset(buffer, '\0', BUFFER_SIZE);
}
fclose(fp);
return 1;
}
int main(int argc, char **argv)
{
char *hostname = "127.0.0.1";
int port = 6666;
char buffer[BUFFER_SIZE], fname[BUFFER_SIZE];
int sockfd, err, res;
struct sockaddr_storage server_addr;
socklen_t server_addr_len;
server_addr_len = hostname_to_ip_port(hostname, port, &server_addr);
if (server_addr_len == 0)
return 1;
sockfd = socket(server_addr.ss_family, SOCK_STREAM, IPPROTO_TCP);
if (sockfd < 0)
{
perror("Could not create socket");
return 1;
}
if (connect(sockfd, (struct sockaddr *)&server_addr, server_addr_len) < 0)
{
perror("Could not connect socket");
return 1;
}
while (1)
{
memset(buffer, BUFFER_SIZE, '\0');
memset(fname, BUFFER_SIZE, '\0');
printf("> ");
if (!fgets(buffer, BUFFER_SIZE, stdin))
break;
if (strstr(buffer, "SENDFILE_TXT") != NULL)
{
if (send_all(sockfd, buffer, BUFFER_SIZE) < 0)
{
perror("Could not send message");
close(sockfd);
return 1;
}
memset(buffer, BUFFER_SIZE, '\0');
err = recv_all(sockfd, buffer, BUFFER_SIZE);
if (err <= 0)
{
if (err < 0)
perror("Could not read message");
else
printf("Server disconnected\n");
break;
}
if ((res = strcmp(buffer, "OK") == 0))
{
printf("-------FROM SERVER: %s-------\n", buffer);
printf("Give filename> ");
memset(fname, BUFFER_SIZE, '\0');
if (!fgets(fname, BUFFER_SIZE, stdin))
break;
if (send_all(sockfd, fname, BUFFER_SIZE) < 0)
{
perror("Could not send message");
close(sockfd);
return 1;
}
}
err = recv_all(sockfd, buffer, BUFFER_SIZE);
if (err <= 0)
{
if (err < 0)
perror("Could not read message");
else
printf("Server disconnected\n");
break;
}
fname[strlen(fname)-1] = 0;
printf("----%s----\n", fname);
send_txt_file(sockfd, BUFFER_SIZE, fname);
printf("FROM SERVER: %.*s\n", BUFFER_SIZE, buffer);
}
else
{
if (send_all(sockfd, buffer, BUFFER_SIZE) < 0)
{
perror("Could not send message");
close(sockfd);
return 1;
}
err = recv_all(sockfd, buffer, BUFFER_SIZE);
if (err <= 0)
{
if (err < 0)
perror("Could not read message");
else
printf("Server disconnected\n");
break;
}
printf("FROM SERVER: %.*s\n", BUFFER_SIZE, buffer);
}
}
close(sockfd);
return 0;
}
The way you are using send_txt_file() and recv_txt_file() to transfer a file is not correct.
On the server side:
When a client connects, the server waits for the client to send exactly BUFFER_SIZE (1024) bytes for each command, no more, no less (which is a waste of bandwidth for short commands). When a SENDFILE_TXT command is received, the server reads the filename from the client (which will cause a buffer overflow if the filename is exactly BUFFER_SIZE bytes in length), and then calls recv_txt_file().
recv_txt_file() attempts to read from the client in a loop, reading in exactly BUFFER_SIZE chunks. However, the while loop being used is coded incorrectly. It is checking the return value of recv_all() for failure, not for success. The != check needs to be changed to == instead. And also, the b variable that is being used to increment total, and tell fwrite() how many bytes to write, is never set to any value other than 0. It needs to be set to BUFFER_SIZE instead, since that is how many bytes have actually been read if recv_all() returns 1.
However, even if the while loop were coded properly, the transfer would still not operate properly, because it requires the file to be sent in even multiples of BUFFER_SIZE. If the file is not an even multiple in size, recv_all() will end up waiting for data that the client does not send, until an error occurs on the socket.
Also, recv_txt_file() is closing the connection after the transfer is finished. It should not do that, as that will prevent the client from being able to send further commands after sending a file. The client is not closing its end of the connection after sending a file, so the server should not be closing its end after receiving a file.
On the client side:
When the client sends a SENDFILE_TXT command and gets an acknowledgement back, it calls send_txt_file(), which reads the file in a loop, sending it to the server in BUFFER_SIZE sized chunks. If the file size is not an even multiple of BUFFER_SIZE, the last block sent will just waste bandwidth and send random garbage to the server. Also, you are ignoring the return value of send_all() to break the loop if an error occurs on the socket.
The client should send the actual file size to the server before sending the file data. The server can then read that size value first so it knows when to stop reading.
That being said, try something more like the following:
server.c
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <netdb.h>
#include <string.h>
#include <stdint.h>
#define BUFFER_SIZE 1024
int send_all(int sockfd, const void *buf, int len)
{
ssize_t n;
const char *pbuf = (const char*) buf;
while (len > 0)
{
n = send(sockfd, pbuf, len, 0);
if (n < 0)
{
perror("Client write failed");
return n;
}
pbuf += n;
len -= n;
}
return 0;
}
int send_uint32(int sockfd, uint32_t value)
{
value = htonl(value);
if (send_all(sockfd, &value, sizeof(value)) < 0)
return -1;
return 0;
}
int send_str(int sockfd, const char *s)
{
uint32_t len = strlen(s);
int res = send_uint32(sockfd, len);
if (res == 0)
res = send_all(sockfd, s, len);
return res;
}
int recv_all(int sockfd, void * buf, int len)
{
ssize_t n;
char *pbuf = (char*) buf;
while (len > 0)
{
n = recv(sockfd, pbuf, len, 0);
if (n <= 0)
{
if (n < 0)
perror("Client read failed");
else
printf("Client disconnected\n");
return n;
}
pbuf += n;
len -= n;
}
return 1;
}
int recv_uint32(int sockfd, uint32_t *value)
{
int res = recv_all(sockfd, value, sizeof(*value));
if (res > 0)
*value = ntohl(*value);
return res;
}
int recv_uint64(int sockfd, uint64_t *value)
{
int res = recv_all(sockfd, value, sizeof(*value));
if (res > 0)
*value = ntohll(*value); // <-- use any implementation of your choosing...
return res;
}
int recv_str(int sockfd, char **str)
{
uint32_t len;
int res = recv_uint32(sockfd, &len);
if (res <= 0)
return res;
*str = (char*) malloc(len + 1);
if (*str == NULL)
{
perror("Could not allocate memory");
return -1;
}
res = recv_all(sockfd, *str, len);
if (res <= 0)
free(*str);
else
(*str)[len] = '\0';
return res;
}
int recv_txt_file(int sockfd)
{
char *filename;
uint64_t filesize;
if (recv_str(sockfd, &filename) <= 0)
return -1;
int res = recv_uint64(sockfd, &filesize);
if (res <= 0)
{
free(filename);
return -1;
}
printf("-------FROM CLIENT: %s-------\n", filename);
FILE* fp = fopen(filename, "wb");
if (fp == NULL)
{
perror("Could not create file");
free(filename);
send_str(sockfd, "NO");
return 0;
}
free(filename);
// optional: pre-size the new file to the specified filesize...
if (send_str(sockfd, "OK") < 0)
return -1;
char buffer[BUFFER_SIZE];
int b;
uint64_t total = 0;
while (filesize > 0)
{
b = (filesize > BUFFER_SIZE) ? BUFFER_SIZE : (int) filesize;
res = recv_all(sockfd, buffer, b);
if (res <= 0)
{
fclose(fp);
return -1;
}
if (fwrite(buffer, b, 1, fp) < 1)
{
perror("Could not write to file");
fclose(fp);
send_str(sockfd, "ERROR");
return -1;
}
total += b;
filesize -= b;
}
fclose(fp);
printf("Received bytes: %lu\n", total);
if (send_str(sockfd, "OK") < 0)
return -1;
return 1;
}
int main()
{
int port = 6666;
int server_fd, client_fd, read;
struct sockaddr_in server, client;
char filename[BUFFER_SIZE], *cmd;
char remote_ip[16];
int remote_port, res = 0;
server_fd = socket(AF_INET, SOCK_STREAM, 0);
if (server_fd < 0)
{
perror("Could not create socket");
return 1;
}
int optval = 1;
setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(int));
memset(&server, '\0', sizeof(server));
server.sin_family = AF_INET;
server.sin_port = htons(port);
server.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(server_fd, (struct sockaddr *) &server, sizeof(server)) < 0)
{
perror("Could not bind socket");
close(server_fd);
return 1;
}
if (listen(server_fd, 1) < 0)
{
perror("Could not listen on socket");
close(server_fd);
return 1;
}
printf("Server TCP is listening on port %d ... \n", port);
socklen_t client_len = sizeof(client);
client_fd = accept(server_fd, (struct sockaddr *) &client, &client_len);
if (client_fd < 0)
{
perror("Could not establish new connection");
close(server_fd);
return 1;
}
remote_port = ntohs(client.sin_port);
inet_ntop(AF_INET, &client.sin_addr, remote_ip, sizeof(remote_ip));
printf("Client IP address: %s, port %d\n", remote_ip, remote_port);
while (recv_str(client_fd, &cmd) > 0)
{
printf("-------FROM CLIENT: %s-------\n", cmd);
if (strcmp(cmd, "SENDFILE_TXT") == 0)
{
if (recv_txt_file(client_fd) < 0)
break;
}
else
{
if (send_str(client_fd, cmd) < 0)
{
free(cmd);
break;
}
}
free(cmd);
}
close(client_fd);
close(server_fd);
return 0;
}
client.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <netdb.h>
#include <stdint.h>
#define BUFFER_SIZE 1024
socklen_t hostname_to_ip_port(char *hostname, int port, struct sockaddr_storage *addr)
{
int sockfd;
struct addrinfo hints, *servinfo;
int rv;
char service[20];
sprintf(service, "%d", port);
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
if ((rv = getaddrinfo(hostname, service, &hints, &servinfo)) != 0)
{
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
return 0;
}
socklen_t addrlen = servinfo->ai_addrlen;
memcpy(addr, servinfo->ai_addr, addrlen);
freeaddrinfo(servinfo);
return addrlen;
}
int send_all(int sockfd, const void *buf, size_t len)
{
ssize_t n;
const char *pbuf = (const char *) buf;
while (len > 0)
{
n = send(sockfd, pbuf, len, 0);
if (n < 0)
{
perror("Server write failed");
return n;
}
pbuf += n;
len -= n;
}
return 0;
}
int send_uint32(int sockfd, uint32_t value)
{
value = htonl(value);
return send_all(sockfd, &value, sizeof(value));
}
int send_uint64(int sockfd, uint64_t value)
{
value = htonll(value); // <-- use any implementation of your choosing...
return send_all(sockfd, &value, sizeof(value));
}
int send_str(int sockfd, const char *s)
{
uint32_t len = strlen(s);
int res = send_uint32(sockfd, len);
if (res == 0)
res = send_all(sockfd, s, len);
return res;
}
int recv_all(int sockfd, void *buf, int len)
{
ssize_t n;
char *pbuf = (char*) buf;
while (len > 0)
{
n = recv(sockfd, pbuf, len, 0);
if (n <= 0)
{
if (n < 0)
perror("Server read failed");
else
printf("Server disconnected\n");
return n;
}
pbuf += n;
len -= n;
}
return 1;
}
int recv_uint32(int sockfd, uint32_t *value)
{
int res = recv_all(sockfd, value, sizeof(*value));
if (res > 0)
*value = ntohl(*value);
return res;
}
int recv_str(int sockfd, char **str)
{
uint32_t len;
int res = recv_uint32(sockfd, &len);
if (res <= 0)
return res;
*str = (char*) malloc(len + 1);
if (*str == NULL)
{
perror("Could not allocate memory");
return -1;
}
res = recv_all(sockfd, *str, len);
if (res <= 0)
free(*str);
else
(*str)[len] = '\0';
return res;
}
int send_txt_file(int sockfd, const char *filename)
{
char *resp;
int res;
long int filesize;
char buffer[BUFFER_SIZE];
int b;
FILE* fp = fopen(filename, "rb");
if (fp == NULL)
{
printf("Could not open file!\n");
return 0;
}
fseek(fp, 0L, SEEK_END);
filesize = ftell(fp);
fseek(fp, 0L, SEEK_SET);
if (filesize < 0)
{
fclose(fp);
return 0;
}
if (send_str(sockfd, "SENDFILE_TXT") < 0)
{
fclose(fp);
return -1;
}
if (send_str(sockfd, filename) < 0)
{
fclose(fp);
return -1;
}
if (send_uint64(sockfd, filesize) < 0)
{
fclose(fp);
return -1;
}
res = recv_str(sockfd, &resp);
if (res <= 0)
return -1;
printf("-------FROM SERVER: %s-------\n", resp);
if (strcmp(resp, "OK") != 0)
{
free(resp);
fclose(fp);
return 0;
}
free(resp);
while (filesize > 0)
{
b = (filesize > BUFFER_SIZE) ? BUFFER_SIZE : (int) filesize;
b = fread(buffer, 1, b, fp);
if (b < 1)
{
fclose(fp);
return -1;
}
if (send_all(sockfd, buffer, b) < 0)
{
fclose(fp);
return -1;
}
filesize -= b;
}
fclose(fp);
res = recv_str(sockfd, &resp);
if (res <= 0)
return -1;
printf("-------FROM SERVER: %s-------\n", resp);
free(resp);
return 0;
}
int prompt(const char *text, char **input)
{
*input = NULL;
size_t size = 0;
printf("%s> ", text);
ssize_t len = getline(input, &size, stdin);
if (len < 0)
return len;
if ((*input)[len-1] == '\n')
{
--len;
(*input)[len] = '\0';
}
return len;
}
int main()
{
char *hostname = "127.0.0.1";
int port = 6666;
char *cmd, *resp, *fname;
size_t size;
ssize_t len;
int sockfd, res;
struct sockaddr_storage server_addr;
socklen_t server_addr_len;
server_addr_len = hostname_to_ip_port(hostname, port, &server_addr);
if (server_addr_len == 0)
return 1;
sockfd = socket(server_addr.ss_family, SOCK_STREAM, IPPROTO_TCP);
if (sockfd < 0)
{
perror("Could not create socket");
return 1;
}
if (connect(sockfd, (struct sockaddr *) &server_addr, server_addr_len) < 0)
{
perror("Could not connect socket");
return 1;
}
while (prompt("", &cmd) >= 0)
{
if (strcmp(cmd, "SENDFILE_TXT") == 0)
{
if (prompt("Give filename", &fname) < 0)
break;
if (send_txt_file(sockfd, fname) < 0)
break;
free(fname);
}
else
{
if (send_str(sockfd, cmd) < 0)
{
free(cmd);
close(sockfd);
return 1;
}
if (recv_str(sockfd, &resp) <= 0)
break;
printf("FROM SERVER: %s\n", resp);
free(resp);
}
free(cmd);
}
close(sockfd);
return 0;
}
regarding:
int total = 0, b = 0;
and
while(recv_all(sockfd, buffer, len) != 1)
{
total += b;
fwrite(buffer, 1, b, fp);
the total and b never move from their initial value of 0. So 0 bytes are written to the output file.
I know this is kinda lame question, but what am I doing wrong in my code ? Basically, I wanna create communication on local IP using UDP, also send some files etc. The problem is, that when I get to freeing my structures after using them/converting them to/from char* the program just crashes. What is even more weird, the program does not crash when debugging and stepping through using CLion debugger. What am I doing wrong? Here is my source code:
The error seems to happen, when I can not allocate more memory (so logically, I need to free some) when sending a file over network. Sending messages works just fine
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
// PKS2Visual.cpp : Defines the entry point for the console application.
//
#include "main.h"
#include <stdio.h>
#include <string.h>
#include <winsock2.h>
#include <windows.h>
#include <time.h>
#define BREAKSOMETHING 0
#pragma comment(lib, "ws2_32.lib")
int fragSize = 1500;
int isInside = 0;
SOCKET s1, s2;
struct sockaddr_in server, myClient, otherClient;
int main() {
char mode;
printf("Enter fragment size:\n");
scanf("%d", &fragSize);
p2pMode();
}
DWORD WINAPI receiveThreadFunc(LPVOID lpParam) {
int slen = sizeof(otherClient);
int doRun = 1;
int sizee;
char msgBuffer[1519];
char fileName[1519];
int receivingFile = 0;
while (doRun) {
printf("Waiting for data...\n\n");
if ((recvfrom(s1, msgBuffer, 1519, 0, (struct sockaddr *) &otherClient,
&slen)) == SOCKET_ERROR) {
printf("recvfrom() failed with error code : %d\n", WSAGetLastError());
continue;
}
//printf("Received packet from %s:%d\n", inet_ntoa(otherClient.sin_addr), ntohs(otherClient.sin_port));
PacketData *packetData = dataToPacket(msgBuffer);
if (packetData == NULL) {
continue;
}
char flag = packetData->flag;
switch (flag) {
case 's': {
PacketData *packetDataAck = createPacket('a');
char *messageToSend2 = packetToData(packetDataAck, &sizee);
if (sendto(s1, messageToSend2, 18, 0, (struct sockaddr *) &otherClient, slen) == SOCKET_ERROR) {
printf("sendto() failed with error code : %d\n", WSAGetLastError());
continue;
}
//free(packetDataAck);
//free(messageToSend2);
break;
}
case 'm': {
if (receivingFile) {
FILE *fptr;
fptr = fopen(fileName, "a");
fprintf(fptr, "%s", packetData->data);
printf("Packet contains data: %s\n", packetData->data);
fclose(fptr);
if(packetData->fragNum == packetData->fragTotal){
receivingFile = 0;
}
} else {
printf("Received packet n. %d\n", packetData->fragNum);
printf("Packet data length: %d\n", packetData->len);
printf("Packet contains data: %s\n", packetData->data);
}
break;
}
case 'f': {
strcpy(fileName, packetData->data);
printf("Receiving file: %s\n", fileName);
printf("Receiving file: %s\n", packetData->data);
receivingFile = 1;
break;
}
default: {
doRun = 0;
break;
}
}
free(packetData);
}
return 0;
}
DWORD WINAPI sendThreadFunc(LPVOID lpParam) {
PacketData **fragments = NULL;
int doRun = 1;
char msgBuffer[1500];
int actualSize = 0;
int slen = sizeof(myClient);
while (1) {
printf("Enter message or -e to end messaging and return to menu:\n");
fflush(stdin);
scanf("%1500[^\n]", msgBuffer);
getc(stdin);
if (strcmp(msgBuffer, "-e") == 0) {
isInside = 0;
return 0;
}
if (strlen(msgBuffer) >= 1499) {
continue;
}
fragments = makeFragments(msgBuffer);
int numFragments = fragments[0]->fragTotal;
printf("Number of fragments: %d\n", numFragments);
PacketData *packetData = createPacket('s');
if (packetData == NULL) {
printf("Could not init packet 's'\n");
continue;
}
char *sync = packetToData(packetData, &actualSize);
if (sendto(s2, sync, 18, 0, (struct sockaddr *) &myClient,
slen) == SOCKET_ERROR) {
printf("sendto() failed with error code : %d\n", WSAGetLastError());
continue;
}
printf("First fragment sent.\n");
free(packetData);
char *ack = (char *) calloc(18, sizeof(char));
if (recvfrom(s2, ack, 18, 0, (struct sockaddr *) &myClient, &slen) ==
SOCKET_ERROR) {
printf("recvfrom() failed with error code : %d\n", WSAGetLastError());
continue;
}
free(ack);
printf("Server confirmed first packet.\n");
for (int i = 0; i < fragments[0]->fragTotal; i++) {
char *msgBuffer2 = packetToData(fragments[i], &actualSize);
if (sendto(s2, msgBuffer2, actualSize + 1, 0, (struct sockaddr *) &myClient,
slen) == SOCKET_ERROR) {
printf("sendto() failed with error code : %d\n", WSAGetLastError());
continue;
}
}
free(fragments);
}
return 0;
}
DWORD WINAPI sendFileFunc(LPVOID lpParam) {
char msgBuffer[1500];
int actualSize = 0;
int slen = sizeof(myClient);
while (1) {
printf("Enter file name or -e to return to menu:\n");
fflush(stdin);
scanf("%1500[^\n]", msgBuffer);
getc(stdin);
if (strcmp(msgBuffer, "-e") == 0) {
isInside = 0;
return 0;
}
if (strlen(msgBuffer) >= 1499) {
continue;
}
//Get file length:
FILE *fl = fopen(msgBuffer, "r");
if (fl == NULL) {
printf("Invalid name, try again\n");
continue;
}
fseek(fl, 0, SEEK_END);
long fileLength = ftell(fl);
fclose(fl);
int numFragments = (fileLength - 1) / fragSize + 2;
printf("Number of fragments: %d\n", numFragments);
PacketData *packetData = createPacket('s');
if (packetData == NULL) {
printf("Could not init packet 's'\n");
continue;
}
char *sync = packetToData(packetData, &actualSize);
if (sendto(s2, sync, 18, 0, (struct sockaddr *) &myClient,
slen) == SOCKET_ERROR) {
printf("sendto() failed with error code : %d\n", WSAGetLastError());
continue;
}
printf("First fragment sent.\n");
free(packetData);
char *ack = (char *) calloc(18, sizeof(char));
if (recvfrom(s2, ack, 18, 0, (struct sockaddr *) &myClient, &slen) ==
SOCKET_ERROR) {
printf("recvfrom() failed with error code : %d\n", WSAGetLastError());
continue;
}
//free(ack);
PacketData *fragments = NULL;
fragments = (PacketData *) malloc(sizeof(PacketData));
fragments->data = (char *) malloc(fragSize * sizeof(char));
strncpy(fragments->data, msgBuffer, strlen(msgBuffer));
fragments->data[strlen(msgBuffer)] = '\0';
fragments->flag = 'f';
fragments->len = strlen(msgBuffer);
fragments->fragNum = (unsigned int) (1);
fragments->fragTotal = (unsigned int) numFragments - 1;
fragments->CRC = (unsigned int) calculate_crc(msgBuffer, strlen(msgBuffer));
//Sending the first fragment with 'f' flag
char *toSend = packetToData(fragments, &actualSize);
if (sendto(s2, toSend, actualSize + 1, 0, (struct sockaddr *) &myClient,
slen) == SOCKET_ERROR) {
printf("sendto() failed with error code : %d\n", WSAGetLastError());
continue;
}
printf("Server confirmed first packet.\n");
size_t n = 0;
int counter = 0;
int fragNum = 2;
int c;
FILE *f2 = fopen(msgBuffer, "r");
if(f2 == NULL){
printf("File was null\n");
continue;
}
while ((c = fgetc(f2)) != EOF) {
msgBuffer[n++] = (char) c;
counter++;
if (counter == fragSize) {
n = 0;
counter = 0;
printf("Allocating fragment number: %d\n", fragNum);
PacketData *fragments2 = NULL;
fragments2 = (PacketData *) malloc(sizeof(PacketData));
if(fragments2 == NULL){
printf("Incorrect malloc\n");
break;
}
fragments2->data = (char *) malloc((fragSize+1) * sizeof(char));
if(fragments2->data == NULL){
printf("Incorrect malloc2\n");
break;
}
strncpy(fragments2->data, msgBuffer, fragSize);
printf("Copying data to fragment number: %d\n", fragNum);
fragments2->data[strlen(msgBuffer)] = '\0';
fragments2->flag = 'm';
fragments2->len = (unsigned int) fragSize;
fragments2->fragNum = (unsigned int) (fragNum);
fragments2->fragTotal = (unsigned int) numFragments - 1;
fragments2->CRC = (unsigned int) calculate_crc(msgBuffer, fragSize);
printf("Allocated fragment number: %d\n", fragNum);
fragNum++;
char *toSend = packetToData(fragments2, &actualSize);
if (sendto(s2, toSend, actualSize + 1, 0, (struct sockaddr *) &myClient,
slen) == SOCKET_ERROR) {
printf("sendto() failed with error code : %d\n", WSAGetLastError());
continue;
}
printf("Sent fragment number: %d\n", fragNum);
}
}
fclose(fl);
}
return 0;
}
void p2pMode() {
int serverPort, clientPort;
char *serverAddr = (char *) malloc(20 * sizeof(char));
WSADATA wsa;
printf("\nInitialising Winsock...");
if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0) {
printf("Failed. Error Code : %d", WSAGetLastError());
getchar();
exit(EXIT_FAILURE);
}
printf("Initialised.\n");
char hostname[128] = "";
char menuBuffer;
gethostname(hostname, sizeof(hostname));
struct hostent *ent = gethostbyname(hostname);
struct in_addr ip_addr = *(struct in_addr *) (ent->h_addr);
printf("Your IP Address: %s\n", inet_ntoa(ip_addr));
printf("Enter other PC IP Address:\n");
scanf("%s", serverAddr);
if (!strcmp(serverAddr, "localhost"))
serverAddr = (char *) "127.0.0.1";
printf("Enter your listening port:\n");
scanf("%d", &clientPort);
printf("Enter other PC's port:\n");
scanf("%d", &serverPort);
if ((s1 = socket(AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET) {
printf("Could not create socket : %d", WSAGetLastError());
}
if ((s2 = socket(AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET) {
printf("Could not create socket : %d", WSAGetLastError());
}
printf("Socket created.\n");
server.sin_family = AF_INET;
server.sin_addr.s_addr = inet_addr(inet_ntoa(ip_addr));
server.sin_port = htons(clientPort);
myClient.sin_family = AF_INET;
myClient.sin_port = htons(serverPort);
myClient.sin_addr.S_un.S_addr = inet_addr(serverAddr);
if (bind(s1, (struct sockaddr *) &server, sizeof(server)) == SOCKET_ERROR) {
printf("Bind failed with error code : %d", WSAGetLastError());
exit(EXIT_FAILURE);
}
free(serverAddr);
DWORD dwThreadId, dwThreadId2, dwThreadId3, dwThrdParam = 1;
CreateThread(
NULL, // default security attributes
10000, // use default stack size
receiveThreadFunc, // thread function
&dwThrdParam, // argument to thread function
0, // use default creation flags
&dwThreadId); // returns the thread identifier
while (1) {
if (!isInside) {
printf("For messages, write 'm', for file 'f'\n");
scanf("%c", &menuBuffer);
switch (menuBuffer) {
case 'm':
CreateThread(
NULL, // default security attributes
10000, // use default stack size
sendThreadFunc, // thread function
&dwThrdParam, // argument to thread function
0, // use default creation flags
&dwThreadId2); // returns the thread identifier
isInside = 1;
break;
case 'f':
CreateThread(
NULL, // default security attributes
10000, // use default stack size
sendFileFunc, // thread function
&dwThrdParam, // argument to thread function
0, // use default creation flags
&dwThreadId3); // returns the thread identifier
isInside = 1;
break;
}
}
}
}
char *packetToData(PacketData *packet, int *size) { // convert packet into sendable data
int sizee = packet->len + 18;
*size = sizee;
char *temp = (char *) calloc(sizee, sizeof(char));
char *out;
if (temp == NULL) {
return NULL;
}
out = temp;
*(temp) = packet->flag;
*(unsigned int *) (temp + 2) = packet->CRC;
*(unsigned int *) (temp + 6) = packet->fragNum;
*(unsigned int *) (temp + 10) = packet->fragTotal;
*(unsigned int *) (temp + 14) = packet->len;
temp = (temp + 18);
int i;
for (i = 0; i < packet->len; i++) { // copy data
temp[i] = packet->data[i];
}
temp[i] = '\0';
return out;
}
PacketData *dataToPacket(char *data) { // convert received data into packet
printf("Data received: %s\n", data);
PacketData *packet = (PacketData *) malloc(sizeof(PacketData));
if (packet == NULL)
return NULL;
packet->flag = *(data);
packet->CRC = *(unsigned int *) (data + 2);
packet->fragNum = *(unsigned int *) (data + 6);
packet->fragTotal = *(unsigned int *) (data + 10);
packet->len = *(unsigned int *) (data + 14);
packet->data = (char *) malloc(packet->len);
char *packetdata = (data + 18);
int i;
for (i = 0; i < packet->len; i++) { // copy data
packet->data[i] = packetdata[i];
}
packet->data[i] = '\0';
return packet;
}
PacketData *createPacket(char flag) {
PacketData *packetData = (PacketData *) malloc(sizeof(PacketData));
packetData->flag = flag;
packetData->len = 0;
packetData->CRC = 0;
packetData->fragNum = 1;
packetData->fragTotal = 1;
return packetData;
}
int calculate_crc(char *buf, int size) {
int crcHash = 10;
for (int i = 0; i < size; i++) {
crcHash += buf[i];
crcHash *= 31;
crcHash %= 30000;
}
return crcHash;
}
struct packetData **makeFragments(char *message) {
int i;
printf("Message length: %d\n", strlen(message));
int fragCount = (strlen(message) - 1) / fragSize + 1;
if (fragCount == 0) {
fragCount++;
}
PacketData **fragments = (PacketData **) malloc((fragCount) * sizeof(PacketData *));
printf("Allocated %d fragments\n", fragCount);
for (i = 0; i < fragCount; i++) {
fragments[i] = (PacketData *) malloc(sizeof(PacketData));
fragments[i]->data = (char *) malloc(fragSize * sizeof(char));
int toCopy = 0;
if (strlen(message) > fragSize) {
toCopy = fragSize;
} else {
toCopy = strlen(message);
}
strncpy(fragments[i]->data, message, toCopy);
fragments[i]->data[toCopy] = '\0';
fragments[i]->flag = 'm';
fragments[i]->len = (unsigned int) toCopy;
fragments[i]->fragNum = (unsigned int) (i + 1);
fragments[i]->fragTotal = (unsigned int) fragCount;
fragments[i]->CRC = (unsigned int) calculate_crc(message, toCopy);
message += fragSize;
}
printf("Fragments needed: %d\n", fragments[0]->fragTotal);
return fragments;
}
and here is my header if someone needed to run it:
//
// Created by lukas on 11/19/2018.
//
#include <winsock2.h>
#include <windows.h>
#ifndef PKS2C_MAIN_H
#define PKS2C_MAIN_H
#endif //PKS2C_MAIN_H
typedef struct packetData {
char flag;
unsigned int CRC;
unsigned int fragNum;
unsigned int fragTotal;
unsigned int len;
char *data;
} PacketData;
struct packetData **makeFragments(char *message);
struct packetData **makeFileFragments(char *message);
char *packetToData(PacketData *packet, int *size);
PacketData *dataToPacket(char *data);
PacketData *createPacket(char flag);
void p2pMode();
int calculate_crc(char *buf, int size);
DWORD WINAPI receiveThread(LPVOID lpParam);
DWORD WINAPI sendThread(LPVOID lpParam);
SOCKET s1, s2;
struct sockaddr_in server, myClient, otherClient;
I got "Conditional jump or move depends on uninitialised value(s)" , and it is coming from function process_server(). I have tried to figure out where it is coming, but to no avail.
Message from valgrind.
==2468== Conditional jump or move depends on uninitialised value(s)
==2468== at 0x402B3D: process_server (in /home/emeka/Desktop/dump/project/serverd)
==2468== by 0x402DB3: main (in /home/emeka/Desktop/dump/project/serverd)
==2468==
#include "signal.h"
#include "string.h"
#include "sys/types.h"
#include "unistd.h"
#include "sys/socket.h"
#include "netinet/in.h"
#include "arpa/inet.h"
#include "netdb.h"
#include "stdlib.h"
#include "ctype.h"
#include "stdio.h"
#include "utility.h"
#include "route.c"
#include "tokenize.c"
#include "bridge.c"
#define PORT 1253
#define ADDRESS "127.0.0.1"
#define START "start"
#define STOP "stop"
#define LISTENQ 4
typedef struct sockaddr SA;
//#define INET6_ADDRSTRLEN 3000
requested_data *re_data;
int switch_ch;
struct sockaddr_in serveraddr;
int start_server(int port){
int listenid;
int optval=1;
typedef struct sockaddr SA;
if((listenid = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
error_message("Error in startServer <Failed to create socket>");
}
if (setsockopt(listenid, SOL_SOCKET, SO_REUSEADDR,
(const void *)&optval , sizeof(int)) < 0)
return -1;
memset(&serveraddr, 0, sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
serveraddr.sin_port = htons((unsigned short)port);
if(bind(listenid, (SA*)&serveraddr, sizeof(serveraddr)) < 0) {
error_message("Error in startServer <Failed to bind socket>");
}
if(listen(listenid, LISTENQ) < 0) {
error_message("Error in startServer <Failed to listen>");
}
return listenid;
}
void *get_in_addr(struct sockaddr *sa)
{
if (sa->sa_family == AF_INET) {
return &(((struct sockaddr_in*)sa)->sin_addr);
}
return &(((struct sockaddr_in6*)sa)->sin6_addr);
}
void process_server(int listenid){
char remoteIP[INET6_ADDRSTRLEN];
int fd, read_size;
const int buffer_size = 1000;
char *client_message = malloc(sizeof(char) * buffer_size);
if(!client_message){
printf("Not enough memory");
abort();
}
struct sockaddr_storage remoteaddr; // client address
socklen_t addrlen;
addrlen = sizeof remoteaddr;
char *gen, gen_int = 0, supplied_answer;
while((fd = accept(listenid, (struct sockaddr *)&remoteaddr, &addrlen))) {
while((read_size = recv(fd, client_message, buffer_size, 0)) > 0) {
printf("%s", client_message);
re_data = router(client_message, read_size);
printf("Method %s --url::%s=+++\n", re_data->method, re_data->url);
switch_ch = 1;
free(client_message);
client_message = malloc(sizeof(char) * buffer_size);
if(!client_message){
printf("Not enough memory");
abort();
}
break;
}
printf("DE server: new connection from %s on "
"socket %d\n",
inet_ntop(remoteaddr.ss_family,
get_in_addr((struct sockaddr*)&remoteaddr),
remoteIP, INET6_ADDRSTRLEN),fd);
str_query *rem_data;
str_query *header_meta = re_data->meta_data;
while(header_meta){
if(strncasecmp(re_data->method, "PUT", 3) == 0){
if(strncasecmp(re_data->url, "/answer", 7) == 0){
if(strlen(re_data->url) == 7){
if(strncasecmp(header_meta->req_name, "question", 8) == 0){
int res_int = parse_input(header_meta->req_value);
if(gen_int == res_int && supplied_answer == res_int){
send(fd, "HTTP status 200 OK" , 18, 0);
} else {
send(fd, "400 Bad Request" , 15, 0);
}
printf("\n Resulted from computation of %s result :: %d\n", header_meta->req_name, res_int);
}
}
}
}
if(switch_ch){
if(strncasecmp(re_data->url, "/question" , 9) == 0){
if(strncasecmp(re_data->method, "GET", 3) == 0){
gen = pmain();
send(fd, gen, strlen(gen), 0);
gen_int = parse_input(gen);
switch_ch = 0;
printf("\n Resulted from generated computation of %s result :: %d\n", header_meta->req_name, gen_int);
free(gen);
}
}
}
if(strncasecmp(header_meta->req_name, "answer", 8) == 0){
supplied_answer = atoi(header_meta->req_value);
}
printf("\nname %s value %s\n", header_meta->req_name, header_meta->req_value);
rem_data = header_meta;
header_meta = header_meta->next;
free(rem_data->req_name);
free(rem_data->req_value);
free(rem_data);
}
if(!client_message){
free(client_message);
}
free(re_data);
close(fd);
}
return;
}
int main(int argc, char **argv) {
int port, pid, server_conn = 1;
int internet_address_len = 15;
char serAdd[internet_address_len];
char strAction[7];
if(argc == 1) {
port = PORT;
strcpy(serAdd, ADDRESS);
} else if(argc == 2){
port = atoi(argv[1]);
strcpy(serAdd, ADDRESS);
} else if(argc == 3) {
port = atoi(argv[1]);
int n = strlen(argv[2]);
strncpy(serAdd, argv[2], n);
if(n >= internet_address_len){
error_message("Internet address is incorrect");
}
serAdd[n] = '\0';
}
printf("\n\tDE is a basic server built to carry out simple things\n"
"\t----- -----\n"
"\t| | |\n"
"\t| | -----\n"
"\t| | |\n"
"\t----- -----\n"
"\tMethods implemented [Get & Put]\n"
"\tTo start type start\n"
"\tTo stop type stop\nDE]");
scanf("%s", strAction);
if (strcmp(strAction, START) == 0){
printf("Server %sed\n", START);
int listenid = start_server(port);
printf("listen on port %d & listening is %d\nDE]", port,listenid);
signal(SIGPIPE, SIG_IGN);
while(server_conn) {
pid =fork();
if(pid == 0) {
process_server(listenid);
break;
}
scanf("%s", strAction);
if (strcmp(strAction, STOP) == 0) {
close(listenid);
return 0;
}
}
}
return 0;
}
I'm writing a multi service server with both UDP and TCP, I'm using writen function to send a struct between the server and the client, as said in the title, in works just fine with the TCP client while it just gets stuck in the writen function after executing this line
printf ("while %lu\n",nleft);
Here's the code:
The server
#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <netinet/tcp.h>
#include <errno.h>
#define MAXLINE 100
struct equation {
float a;
char c;
float b;
};
struct result {
long double res;
};
int MAX (int a,int b){
if (a>b) return a;
return b;
}
int readn(int fd, void *vptr, size_t n)
{
size_t nleft;
ssize_t nread;
char *ptr;
ptr = vptr;
nleft = n;
while (nleft > 0) {
if ( (nread = read(fd, ptr, nleft)) < 0) {
if (errno == EINTR)
nread = 0; /* and call read() again */
else
return (-1);
} else if (nread == 0)
break; /* EOF */
nleft -= nread;
ptr += nread;
}
return (n - nleft); /* return >= 0 */
}
int writen(int fd, const void *vptr, size_t n)
{
size_t nleft;
ssize_t nwritten;
const char *ptr;
// printf ("\nI'm In %lu\n",n);
ptr = vptr;
nleft = n;
// printf ("%lu NNNNN %lu SIZE %lu \n",nleft,n,sizeof(*vptr));
while (nleft > 0) {
printf ("while %lu\n",nleft);
fflush (stdout);
if ( (nwritten = write(fd, ptr, nleft)) <= 0) {
if (nwritten < 0 && errno == EINTR)
nwritten = 0; /* and call write() again */
else
return (-1); /* error */
}
nleft -= nwritten;
ptr += nwritten;
}
printf ("\n 5alawees \n");
// printf ("\n%s\n",vptr);
// ffulsh (stdout);
return (n);
}
void HandleClient(int comm_fd);
void Die (const char * msg)
{
perror(msg);
exit(1);
}
int passiveUDP (short port){
struct sockaddr_in servaddr;
int listen_fd;
if ((listen_fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
{
Die("Falied to create socket");
};
//printf ("%d" ,listen_fd);
memset( &servaddr,0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htons(INADDR_ANY);
servaddr.sin_port = htons(port);
if (bind(listen_fd, (struct sockaddr *) &servaddr, sizeof(servaddr))<0)
{
Die("Failed to bind socket to address");
}
return listen_fd;
}
int passiveTCP (short port){
struct sockaddr_in servaddr;
int listen_fd;
if ((listen_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
Die("Falied to create socket");
};
memset( &servaddr,0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htons(INADDR_ANY);
servaddr.sin_port = htons(port);
if (bind(listen_fd, (struct sockaddr *) &servaddr, sizeof(servaddr))<0)
{
Die("Failed to bind socket to address");
}
if (listen(listen_fd, 10) < 0)
{
Die("Failed to listen on server socket");
}
return listen_fd;
}
int main(int argc, char * argv[])
{
if (argc != 2) {
fprintf(stderr, "USAGE: ./HelloITServer <port>\n");
exit(1);
}
char str[100];
int listen_fd, comm_fd;
int usock = passiveUDP (atoi (argv[1])); /* UDP socket */
int tsock = passiveTCP (atoi (argv[1])); /* TCP master socket */
int nfds;
fd_set rfds; /* readable file descriptors */
struct sockaddr_in fsin; /* the request from address */
nfds = MAX(tsock, usock) + 1;
FD_ZERO(&rfds);
while (1) {
FD_SET(tsock, &rfds);
FD_SET(usock, &rfds);
printf ("HELLO");
if(select(nfds, &rfds, NULL, NULL, NULL) < 0){
printf("select error: %d \n",errno);
exit (1);
}
if(FD_ISSET(tsock, &rfds))
{
/* TCP slave socket */
//printf ("Hello TCP");
int ssock;
//int alen = sizeof(fsin);
ssock = accept(tsock, (struct sockaddr *) NULL, NULL);
if(ssock < 0)
Die("accept failed: jkjkjkjkjkj \n");
HandleClient (ssock);
close (ssock);
}
if(FD_ISSET(usock, &rfds))
{
printf ("Hello UDP\n");
HandleClient (usock);
}
}
}
void HandleClient(int comm_fd)
{
struct equation eq;
struct result rslt;
bzero (&eq,sizeof (eq));
bzero (&rslt, sizeof (rslt));
if ((readn (comm_fd, &eq, sizeof(eq))) == 0){
Die("Failed to receive from client");
}
// printf ("\n%lu %lu\n",sizeof (struct result),sizeof (rslt));
printf ("reciveed %f %c %f\n",eq.a,eq.c,eq.b);
switch (eq.c) {
case '+':
rslt.res = eq.a+eq.b;
break;
case '-':
rslt.res = eq.a-eq.b;
break;
case '*':
rslt.res = eq.a*eq.b;
break;
case '/':
rslt.res = eq.a/eq.b;
break;
case '%':
rslt.res = (int)eq.a% (int)eq.b;
break;
default:
break;
}
// printf ("\n%lu\n",sizeof(rslt));
// printf ("\n%lu\n",sizeof(rslt));
// printf ("\n%lu\n",sizeof(rslt));
writen (comm_fd, &rslt, sizeof (rslt));
//close (comm_fd);
}
The client (just in case u guys need it)
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include<unistd.h>
#include <float.h>
#include <errno.h>
struct equation {
float a;
char c;
float b;
};
struct result {
long double res;
};
int readn(int fd, void *vptr, size_t n)
{
size_t nleft;
ssize_t nread;
char *ptr;
ptr = vptr;
nleft = n;
while (nleft > 0) {
if ( (nread = read(fd, ptr, nleft)) < 0) {
if (errno == EINTR)
nread = 0; /* and call read() again */
else
return (-1);
} else if (nread == 0)
break; /* EOF */
nleft -= nread;
ptr += nread;
}
return (n - nleft); /* return >= 0 */
}
int writen(int fd, const void *vptr, size_t n)
{
size_t nleft;
ssize_t nwritten;
const char *ptr;
ptr = vptr;
nleft = n;
while (nleft > 0) {
if ( (nwritten = write(fd, ptr, nleft)) <= 0) {
if (nwritten < 0 && errno == EINTR)
nwritten = 0; /* and call write() again */
else
return (-1); /* error */
}
nleft -= nwritten;
ptr += nwritten;
}
return (n);
}
int main(int argc,char *argv[])
{
int sockfd,n;
char sendline[100];
char recvline[100];
struct sockaddr_in servaddr;
if (argc != 3) {
fprintf(stderr, "USAGE: ./HelloClient <server_ip> <port>\n");
exit(1);
}
sockfd=socket(AF_INET,SOCK_DGRAM,0);
bzero(&servaddr,sizeof servaddr);
servaddr.sin_family=AF_INET;
servaddr.sin_port= htons(atoi(argv[2]));
inet_pton(AF_INET,argv[1],&(servaddr.sin_addr));
connect(sockfd,(struct sockaddr *)&servaddr,sizeof(servaddr));
struct result rslt;
struct equation eq;
//while(1)
//{
printf ("Accepted values by the program, from %f to %f\n", FLT_MIN, FLT_MAX);
printf ("\n possible operations are addition, substraction, division, multiplication and modulo with operators : +,-,*,/,% respectivly\n");
printf ("\nPlease enter the equation in this form only : \"5.0 + 2.0\" with a single space\n");
scanf ("%f %c %f", &eq.a,&eq.c,&eq.b);
if (eq.c!='+' && eq.c!='-' && eq.c!='*' && eq.c!='/' && eq.c!='%'){
printf ("\n possible operations are addition, substraction, division, multiplication and modulo with operators : +,-,*,/,% respectivly\n");
exit (1);
}
if (eq.c== '%'){
if (!(eq.a == (float) ((int) eq.a) && eq.b == (float) ((int) eq.b))){
printf ("Only integer values are accepted with the % operation, please rerun the program\n");
exit (1);
}
}
//bzero( &eq, sizeof(eq));
bzero( &rslt, sizeof(rslt) );
//fgets(sendline,100,stdin); /*stdin = 0 , for standard input */
writen (sockfd, &eq, sizeof(eq));
readn (sockfd, &rslt, sizeof(rslt));
printf("%Lf\n thank you for using this marvelous calculator!\n",rslt.res);
bzero( &eq, sizeof(eq));
exit (1);
//}
}
I am not seeing where you are adding the IP address. There are a few more steps necessary, even if you're wanting to just use the loopback address for testing purposes.
Check out the Bind() section and see what you're missing. http://www.beej.us/guide/bgnet/output/html/multipage/bindman.html