Related
I've read many threads about problems similar to mine, i've studied from 'Advanced programming in Unix environment', but can't solve this problem. I'm sure it is a simple error in my thinking, and I need a look from someone more advanced than me.
I'm creating a chatroom in C, for a university project. The idea is that the server sends every client a list of rooms, than a client chooses the room he wants to join, and he can chat when someone else joins. Every client, when chatting, can type 'exit' to quit the program, or 'menu' to go back to the room selection. When a client does this, the other client receives a message saying 'other client disconnected, going back to menu in 3, 2, 1', then goes back.
Here comes the problem. Everything works, but the client who automatically disconnected (because the other client did) prints a lot of garbage characters, thus everything breaks (for him).
I tried everything. I think it's something regarding the buffer's sizes and the amount of bytes I send, but it works in every case except this. I changed my code so many times that i'm losing control, that's why i'm asking here.
Here's the code.
#ifndef PROTO
#define PROTO
#define NAME_LENGTH 31
#define LENGTH_MSG 200
#define LENGTH_SEND 300
#define ROOM_CHOICE 5
#define MAX_CLIENTS 50
#define MAX_ROOM_WAITLIST 5
#endif // PROTO
Server
#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>
#include "proto.h"
#include "server.h"
// Variabili Globali
int server_sockfd = 0, client_sockfd = 0;
int leave_flag = 0; // flag to make a client disconnect
Client* clientList[MAX_CLIENTS] = {}; // clients connected to the server
char chosenRoom[ROOM_CHOICE] = {}; // contains the room chosen by the client
char recv_buffer[LENGTH_MSG] = {};
char send_buffer[LENGTH_SEND] = {};
Room* room1;
Room* room2;
Room* room3;
Room* room4;
Room* room5; // rooms
int clientsInRoom[ROOM_CHOICE] = {0}; // how many people are in rooms
pthread_mutex_t globalMutex = PTHREAD_MUTEX_INITIALIZER; // mutex to manage the connection to clients
// Metodi
void catch_ctrl_c_and_exit(int sig) {
for (int i = 0; i<MAX_CLIENTS; i++){
if (clientList[i]){
printf("\nClose socketfd: %d\n", clientList[i]->socket);
close(clientList[i]->socket);
free(clientList[i]);
}
}
printf("Bye\n");
exit(EXIT_SUCCESS);
}
void send_to_other_client(Client* client, char tmp_buffer[]) {
printf("Sockfd: %d sends to Sockfd %d: \"%s\" \n", client->socket, client->pairSock, tmp_buffer);
send(client->pairSock, tmp_buffer, LENGTH_SEND, 0);
memset(send_buffer, '\0', LENGTH_SEND);
}
void pairing_with_client(Client *client){
for (int i = 0; i < MAX_ROOM_WAITLIST; i++){
if (client->room->waitList[i]){
if (client->socket != client->room->waitList[i]->socket && client->room->waitList[i]->paired == 0 && client->room->waitList[i]->socket != client->pairSock && client->room->waitList[i]->pairSock != client->socket){
client->pairSock = client->room->waitList[i]->socket;
client->room->waitList[i]->pairSock = client->socket;
client->paired = 1;
client->room->waitList[i]->paired = 1;
strncpy(client->pairName, client->room->waitList[i]->name, NAME_LENGTH);
strncpy(client->room->waitList[i]->pairName, client->name, NAME_LENGTH);
pthread_cond_broadcast(&client->room->cond);
printf("The socket: %d woke up the waiting socket: %d.\n", client->socket, client->pairSock);
memset(send_buffer, '\0', LENGTH_SEND);
sprintf(send_buffer, "User found!\nBegin conversation with %s:\n", client->pairName);
send(client->socket, send_buffer, LENGTH_SEND, 0);
memset(send_buffer, '\0', LENGTH_SEND);
return;
}
}
}
// Didn't find anyone, putting the client in wait
add_to_waiting_list(client);
memset(send_buffer, '\0', LENGTH_SEND);
sprintf(send_buffer, "No user found. Waiting...\n");
send(client->socket, send_buffer, LENGTH_SEND, 0);
memset(send_buffer, '\0', LENGTH_SEND);
pthread_cond_wait(&client->room->cond, &client->room->mutex);
memset(send_buffer, '\0', LENGTH_SEND);
sprintf(send_buffer, "User foubd!\nBegin conversation with %s:\n", client->pairName);
send(client->socket, send_buffer, LENGTH_SEND, 0);
memset(send_buffer, '\0', LENGTH_SEND);
remove_from_waiting_list(client);
return;
}
void client_handler(void *p_client) {
char nickname[NAME_LENGTH] = {};
Client *client = (Client *)p_client;
// Naming
memset(nickname, '\0', NAME_LENGTH);
if (recv(client->socket, nickname, NAME_LENGTH, 0) <= 0) {
printf("%s didn't insert a nickname.\n", client->ip);
leave_flag = 1;
} else {
strncpy(client->name, nickname, NAME_LENGTH);
printf("%s(%s)(%d) joins the chatroom.\n", client->name, client->ip, client->socket);
sprintf(send_buffer, "%s joins the chatroom.", client->name);
}
while (1){
memset(send_buffer, '\0', LENGTH_SEND);
sprintf(send_buffer, "\nWelcome to RandomChat!\nChoose your room.\n\n1 - Politics [%d/10]\n2 - Computers [%d/10]\n", room1->howmany, room2->howmany);
send(client->socket, send_buffer, LENGTH_SEND, 0);
memset(send_buffer, '\0', LENGTH_SEND);
while (1){
// Choosing room
memset(chosenRoom, '\0', ROOM_CHOICE);
int receive = recv(client->socket, chosenRoom, ROOM_CHOICE, 0);
if (receive <= 0) {
printf("%s didn't choice a room.\n", client->ip);
leave_flag = 1;
} else {
if (strcmp(chosenRoom, "1") == 0){
client->room = room1;
pthread_mutex_lock(&client->room->mutex);
client->room->howmany++;
pthread_mutex_unlock(&client->room->mutex);
} else if (strcmp(chosenRoom, "2") == 0){
client->room = room2;
pthread_mutex_lock(&client->room->mutex);
client->room->howmany++;
pthread_mutex_unlock(&client->room->mutex);
} else {
printf("Received %d byte\n", receive);
printf("Wrong choice. You chose: %s\n", chosenRoom);
memset(send_buffer, '\0', LENGTH_SEND);
sprintf(send_buffer, "Wrong choice. Try again\n");
send(client->socket, send_buffer, LENGTH_SEND, 0);
memset(send_buffer, '\0', LENGTH_SEND);
continue;
}
}
printf("%s(%s)(%d) chose room %s.\n", client->name, client->ip, client->socket, chosenRoom);
memset(send_buffer, '\0', LENGTH_SEND);
sprintf(send_buffer,"\nYou chose room %s\n", chosenRoom);
send(client->socket, send_buffer, LENGTH_SEND, 0);
memset(send_buffer, '\0', LENGTH_SEND);
break;
}
// Pairing
pairing_with_client(client);
// Conversation
printf("Conversation begins between socket: %d and socket:%d\n", client->socket, client->pairSock);
while (1) {
if (leave_flag == 1 || leave_flag == 2) {
break;
}
memset(recv_buffer, '\0', LENGTH_MSG);
int receive = recv(client->socket, recv_buffer, LENGTH_MSG, 0);
if (receive > 0) {
if (strlen(recv_buffer) == 0) {
continue;
}
if (strcmp(recv_buffer, "menu") == 0){
memset(send_buffer, '\0', LENGTH_SEND);
sprintf(send_buffer, "backToMenu");
leave_flag = 2;
} else if (strcmp(recv_buffer, "makeMeGoBack") == 0){
memset(send_buffer, '\0', LENGTH_SEND);
sprintf(send_buffer, "\nThe user you were talking to quitted the chatroom.\n\nGoing back to menu in...");
send(client->socket, send_buffer, LENGTH_SEND, 0);
memset(send_buffer, '\0', LENGTH_SEND);
for (int i = 3; i>0; i--){
memset(send_buffer, '\0', LENGTH_SEND);
sprintf(send_buffer, "%d", i);
send(client->socket, send_buffer, LENGTH_SEND, 0);
sleep(1);
}
memset(send_buffer, '\0', LENGTH_SEND);
sprintf(send_buffer, "ricomincia");
send(client->socket, send_buffer, LENGTH_SEND, 0);
memset(send_buffer, '\0', LENGTH_SEND);
leave_flag = 2;
break;
} else {
memset(send_buffer, '\0', LENGTH_SEND);
sprintf(send_buffer, "%s:%s", client->name, recv_buffer);
}
} else if (receive == 0 || strcmp(recv_buffer, "exit") == 0) {
printf("%s(%s)(%d) quitted the chatroom.\n", client->name, client->ip, client->socket);
memset(send_buffer, '\0', LENGTH_SEND);
sprintf(send_buffer, "backToMenu");
leave_flag = 1;
} else {
printf("Fatal Error: -1\n");
leave_flag = 1;
}
send_to_other_client(client, send_buffer);
}
if (leave_flag == 1){ // the client wrote 'exit'. He wants to close the program.
client->room->howmany--;
close(client->socket);
free(client);
printf("LEAVE FLAG 1\n");
break;
} else if (leave_flag == 2){ // The client wrote 'menu'. He wants to tell the other clients he is going back to menu
client->room->howmany--;
client->room = NULL;
client->paired = 0;
leave_flag = 0;
printf("LEAVE FLAG 2\n");
}
}
}
int main(int argc, char *argv[])
{
signal(SIGINT, catch_ctrl_c_and_exit);
// Creating socket
server_sockfd = socket(AF_INET , SOCK_STREAM , 0);
if (server_sockfd == -1) {
printf("Failed socket creation.\n");
exit(EXIT_FAILURE);
}
// Informations
struct sockaddr_in server_info, client_info;
int s_addrlen = sizeof(server_info);
int c_addrlen = sizeof(client_info);
memset(&server_info, 0, s_addrlen);
memset(&client_info, 0, c_addrlen);
server_info.sin_family = PF_INET;
server_info.sin_addr.s_addr = INADDR_ANY;
server_info.sin_port = htons(8888);
// Bind e Listen
int opt = 1;
setsockopt(server_sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
bind(server_sockfd, (struct sockaddr *)&server_info, s_addrlen);
listen(server_sockfd, 50);
// Stampa Server IP
getsockname(server_sockfd, (struct sockaddr*) &server_info, (socklen_t*) &s_addrlen);
printf("Server started: %s:%d\n", inet_ntoa(server_info.sin_addr), ntohs(server_info.sin_port));
// Allocating rooms
room1 = (Room*) malloc(sizeof(Room));
room2 = (Room*) malloc(sizeof(Room));
room3 = (Room*) malloc(sizeof(Room));
room4 = (Room*) malloc(sizeof(Room));
room5 = (Room*) malloc(sizeof(Room));
room1->howmany = 0;
room2->howmany = 0;
room3->howmany = 0;
room4->howmany = 0;
room5->howmany = 0;
pthread_mutex_init(&room1->mutex, NULL);
pthread_mutex_init(&room2->mutex, NULL);
pthread_mutex_init(&room3->mutex, NULL);
pthread_mutex_init(&room4->mutex, NULL);
pthread_mutex_init(&room5->mutex, NULL);
pthread_cond_init(&room1->cond, NULL);
pthread_cond_init(&room2->cond, NULL);
pthread_cond_init(&room3->cond, NULL);
pthread_cond_init(&room4->cond, NULL);
pthread_cond_init(&room5->cond, NULL);
while (1) {
client_sockfd = accept(server_sockfd, (struct sockaddr*) &client_info, (socklen_t*) &c_addrlen);
// Print Client IP
getpeername(client_sockfd, (struct sockaddr*) &client_info, (socklen_t*) &c_addrlen);
printf("Client %s:%d come in.\n", inet_ntoa(client_info.sin_addr), ntohs(client_info.sin_port));
// Append nexted list for clients
Client *c = newNode(client_sockfd, inet_ntoa(client_info.sin_addr));
int i = 0;
pthread_mutex_lock(&globalMutex);
while (i < MAX_CLIENTS){
if (!clientList[i]){
clientList[i] = c;
break;
} else {
i++;
}
}
pthread_mutex_unlock(&globalMutex);
pthread_t id;
if (pthread_create(&id, NULL, (void *)client_handler, (void *)c) != 0) {
perror("Create pthread error!\n");
exit(EXIT_FAILURE);
}
}
return 0;
}
Server.h
#ifndef LIST
#define LIST
typedef struct Room_Chat {
struct ClientNode* waitList[MAX_ROOM_WAITLIST];
pthread_mutex_t mutex;
pthread_cond_t cond;
int howmany;
} Room;
typedef struct ClientNode {
int socket; // client's file descriptor
char ip[16]; // client's ip
char name[NAME_LENGTH]; // client's nickname
Room* room;
int pairSock;
char pairName[NAME_LENGTH]; // name of the client you're paired with
int paired; // if you're paired with someone or not
} Client;
Client *newNode(int sockfd, char* ip) {
Client *np = (Client *)malloc( sizeof(Client) );
np->socket = sockfd;
strncpy(np->ip, ip, 16);
strncpy(np->name, "NULL", 5);
strncpy(np->pairName, "NULL", 5);
np->paired = 0;
np->pairSock = 0;
return np;
}
Client *copyNode(Client* np){
Client* node = (Client* )malloc(sizeof(Client));
node->socket = np->socket;
strncpy(node->ip, np->ip, 16);
strncpy(node->name, np->ip, NAME_LENGTH);
strncpy(node->pairName, np->ip, 5);
node->paired = np->paired;
node->pairSock = np->pairSock;
return node;
}
void add_to_waiting_list(Client* client){
for (int i = 0; i < MAX_ROOM_WAITLIST; i++){
if (!client->room->waitList[i]){
client->room->waitList[i] = client;
break;
}
}
return;
}
void remove_from_waiting_list(Client* client){
for (int i = 0; i < MAX_ROOM_WAITLIST; i++){
if (client->room->waitList[i] && client->room->waitList[i]->socket == client->socket){
client->room->waitList[i] = NULL;
break;
}
}
return;
}
#endif // LIST
Client:
#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>
#include "proto.h"
// Variabili globali
int sockfd = 0;
char nickname[NAME_LENGTH] = "";
char choiceRoom[ROOM_CHOICE] = ""; // here i save the room i chose, so i can send it to the server
char choiceRoom_buffer[LENGTH_SEND] = {}; // buffer where i receive the list of rooms from the server
char okChoice[LENGTH_SEND] = {}; // a flag buffer. If the server tells me my choice was invalid, i save here the message
volatile sig_atomic_t flag = 0;
void string_trim(char* arr, int length) {
// This function trims the nickname, so if i write 'Alex ', it becomes 'Alex'
int i;
for (i = 0; i < length; i++) {
if (arr[i] == '\n') {
arr[i] = '\0';
break;
}
}
}
void overwrite_stdout() {
// This function puts '>' before every message i write
printf("\r%s", "> ");
fflush(stdout);
}
void exit_from_client(int sig) {
flag = 1;
}
void back_to_menu(int sig){
flag = 2;
}
void send_msg_handler() {
// Function for the sender thread
char message[LENGTH_MSG] = {};
while (1) {
overwrite_stdout();
memset(message, '\0', LENGTH_MSG);
while (fgets(message, LENGTH_MSG, stdin) != NULL) {
string_trim(message, LENGTH_MSG);
if (strlen(message) == 0) {
overwrite_stdout();
} else {
break;
}
}
send(sockfd, message, LENGTH_MSG, 0);
memset(message, '\0', LENGTH_MSG);
if (strcmp(message, "exit") == 0) {
exit_from_client(2);
break;
}
if (strcmp(message, "menu") == 0){
back_to_menu(2);
break;
}
}
}
void recv_msg_handler() {
// Function for receiver thread
char receiveMessage[LENGTH_SEND] = {};
while (1) {
memset(receiveMessage, '\0', LENGTH_SEND);
int receive = recv(sockfd, receiveMessage, LENGTH_SEND, 0);
if (receive > 0) {
if (strcmp(receiveMessage, "backToMenu") == 0){
send(sockfd, "makeMeGoBack", LENGTH_SEND, 0);
memset(receiveMessage, '\0', LENGTH_SEND);
} else if (strcmp(receiveMessage, "ricomincia") == 0) {
back_to_menu(2);
break;
} else {
printf("\r%s\n", receiveMessage);
overwrite_stdout();
}
} else if (receive == 0) {
break;
} else {
// -1
}
}
}
int main(int argc, char *argv[]){
signal(SIGINT, exit_from_client);
// Creating socket
sockfd = socket(AF_INET , SOCK_STREAM , 0);
if (sockfd == -1) {
printf("Failed socket creation.");
exit(EXIT_FAILURE);
}
// Socket info
struct sockaddr_in server_info, client_info;
int s_addrlen = sizeof(server_info);
int c_addrlen = sizeof(client_info);
memset(&server_info, 0, s_addrlen);
memset(&client_info, 0, c_addrlen);
server_info.sin_family = PF_INET;
server_info.sin_addr.s_addr = inet_addr("127.0.0.1");
server_info.sin_port = htons(8888);
// Connection to server
int err = connect(sockfd, (struct sockaddr *)&server_info, s_addrlen);
if (err == -1) {
printf("Connessione al server fallita.\n");
exit(EXIT_FAILURE);
}
// Getting the info to print
getsockname(sockfd, (struct sockaddr*) &client_info, (socklen_t*) &c_addrlen);
getpeername(sockfd, (struct sockaddr*) &server_info, (socklen_t*) &s_addrlen);
printf("Connected to Server: %s:%d\n", inet_ntoa(server_info.sin_addr), ntohs(server_info.sin_port));
printf("Your IP address is: %s:%d\n", inet_ntoa(client_info.sin_addr), ntohs(client_info.sin_port));
// Choose Nickname
while (strlen(nickname) == 0 || strlen(nickname) >= NAME_LENGTH-1){
printf("\nInsert your nickname: ");
if (fgets(nickname, NAME_LENGTH, stdin) != NULL) {
string_trim(nickname, NAME_LENGTH);
}
if (strlen(nickname) == 0){
printf("\nCannot insert an empty nickname. Try again.\n");
} else if (strlen(nickname) >= NAME_LENGTH-1){
printf("\nCannot insert a nickname that long. Try again.\n");
}
}
// Send the nickname to server
send(sockfd, nickname, NAME_LENGTH, 0);
memset(nickname, '\0', NAME_LENGTH);
// The server sends me the rooms
memset(choiceRoom_buffer, '\0', LENGTH_SEND);
if (recv(sockfd, choiceRoom_buffer, LENGTH_SEND, 0) <= 0) {
printf("***Error. Cannot receive rooms.***");
exit(EXIT_FAILURE);
}
while (1){
// Choosing room
while (1){
printf("%s\n", choiceRoom_buffer);
memset(choiceRoom, '\0', ROOM_CHOICE);
scanf("%s", choiceRoom);
send(sockfd, choiceRoom, ROOM_CHOICE, 0);
memset(choiceRoom, '\0', ROOM_CHOICE);
memset(okChoice, '\0', LENGTH_SEND);
if (recv(sockfd, okChoice, LENGTH_SEND, 0) <=0) {
printf("**Errore**\n");
continue;
} else {
if (strcmp(okChoice, "Invalid choice.\n") == 0){
printf("%s\n", okChoice);
continue;
} else {
printf("%s\n", okChoice);
break;
}
}
}
pthread_t send_msg_thread;
if (pthread_create(&send_msg_thread, NULL, (void *) send_msg_handler, NULL) != 0) {
printf ("Create pthread error!\n");
exit(EXIT_FAILURE);
}
pthread_t recv_msg_thread;
if (pthread_create(&recv_msg_thread, NULL, (void *) recv_msg_handler, NULL) != 0) {
printf ("Create pthread error!\n");
exit(EXIT_FAILURE);
}
while (1) {
if(flag == 1) { // exit
printf("\nBye\n");
close(sockfd);
return 0;
} else if (flag == 2){ // menu
// if (pthread_cancel(tid_sender) != 0){
// printf("Failure closing thread sendern");
// }
// if (pthread_cancel(tid_receiver) != 0){
// printf("Failure closing thread receiver\n");
// }
// This part is a work in progress. I want to close these threads, so when i choose a room, they start again.
break;
}
}
}
return 0;
}
This is what my output looks like, server and client.
As soon as the second client goes automatically back to menu, everything hangs. If a client selects a room, nothing happens.
Any help? Sorry for the long post and for all of this code, but i tried to give you every possible helpful information.
Im trying to make a distributed client / server application for file sharing. I firstly made a LIST_FILES function which reads and prints all the files of your directory, but Im having trouble deleting and renaming .txt files. If I manually use the name of the .txt in the functions, it works for both, but I dont know how to properly read from the server which file I want to use. Im using cygwin, C code and Windows.
Example: ./server.exe --> ./client.exe 127.0.0.1 DELETE_FILE test.txt or MOVE_FILE test.txt newtest.txt
SERVER
#include <stdio.h>
#include <string.h> //strlen
#include <sys/socket.h>
#include <arpa/inet.h> //inet_addr
#include <unistd.h> // Close sockets
#include <dirent.h>
#define MAXDATASIZE 5000
#define _BUFFER_SIZE 2000
#define ECHO_PORT 5675
#define FAIL "SEND_FAILED"
long fileSize(const char fileNom[]);
int getFiles(char *cadena, int longitud);
int main(int argc, char *argv[])
{
char *namefile;
int i, del, ren, leng, length2, length3;
int socket_desc, accepted_socket, connfd = 0;
struct sockaddr_in server_addr; // Direccion del servidor
char down[_BUFFER_SIZE];
char response[_BUFFER_SIZE];
char reply[_BUFFER_SIZE] = "SUCCESS";
char reply2[_BUFFER_SIZE] = "ERROR";
char buffer[_BUFFER_SIZE];
char buffer2[_BUFFER_SIZE];
char buffer3[_BUFFER_SIZE];
char ack[_BUFFER_SIZE] = "ACK";
printf("Initializing echo server\n");
//Create socket
socket_desc = socket(AF_INET, SOCK_STREAM, 0); // Sock stream --> SOCKET TCP
if (socket_desc < 0)
{
printf("Could not create socket");
return 0;
}
printf("Socket created.\n");
char *address = "0.0.0.0"; // Accept connections from the whole Internet
if (argc > 1)
address = argv[1];
server_addr.sin_addr.s_addr = inet_addr(address);
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(ECHO_PORT);
bind(socket_desc, (struct sockaddr *)&server_addr, sizeof(server_addr));
listen(socket_desc, 10);
int exit = 0;
while (!exit)
{
printf("Echo server. Waiting for incoming connections from clients.\n");
accepted_socket = accept(socket_desc, (struct sockaddr *)NULL, NULL);
printf("Accepted a connection from client\n");
// First wait for the command of the client
ssize_t len = recv(accepted_socket, buffer, _BUFFER_SIZE, 0);
// If the client sends two or more arguments, the second is the file's name
if (len < 0)
{
printf("recv failed\n");
}
else
{
char fileName[_BUFFER_SIZE];
char command[_BUFFER_SIZE];
char command2[_BUFFER_SIZE];
printf("Received command from client: %s\n", buffer); // TODO: If the message is too long --> may print garbage
/*
We check the length of buffer2 and buffer3, if the length is
>= 1, it means that the client sent those
*/
length2 = strlen(buffer2);
if (length2 >= 1)
printf("Received file's name from client: %s\n", buffer2);
length3 = strlen(buffer3);
if (length3 >= 1)
printf("Received new file's name from client: %s\n", buffer3);
if (strcmp(buffer, "LIST_FILES") == 0)
{
printf("Received LIST_FILES command --> stopping server\n");
getFiles(buffer, _BUFFER_SIZE);
printf("Directory list: \n %s", buffer);
len = strlen(buffer);
if (send(accepted_socket, buffer, len, 0) < 0)
{
printf("Send failed\n");
return 1;
}
}
else if (strcmp(buffer, "DOWNLOAD_FILE") == 0)
{
i = 10;
long length = 0;
length = fileSize(buffer2);
printf("Received DOWNLOAD_FILE command %s, size: %ld \n", buffer2, length);
if (length >= 0)
{
//We enter in the If command just in case the size of the file is positive
sprintf(down, "%ld", length);
send(accepted_socket, down, _BUFFER_SIZE, 0);
recv(accepted_socket, ack, _BUFFER_SIZE, 0);
if (strcmp(ack, "ACK") == 0) //Checking the ACK message from the client
{
printf("ACK RECEIVED \n");
/* Open the file that we wish to transfer */
FILE *fp = fopen(buffer2, "rb");
if (fp == NULL)
{
printf("Error opening the file");
return 1;
}
else
{
while (1)
{
//Reading and sending the file the client wants to download
unsigned char buff[_BUFFER_SIZE] = {0};
int nread = fread(buff, 1, _BUFFER_SIZE, fp);
printf("Bytes read %d \n", nread);
if (nread > 0)
{
printf("Sending \n");
write(accepted_socket, buff, nread);
}
if (nread < _BUFFER_SIZE)
{
if (feof(fp))
printf("\nEnd of file\n");
if (ferror(fp))
printf("\nError reading\n");
break;
}
}
}
}
}
else
{
strcpy(buffer, reply2); //If ack doesn't is received, we send ERROR
printf("Error: unable to download the file\n");
send(accepted_socket, reply2, len, 0);
}
}
else if (strcmp(buffer, "DELETE_FILE") == 0)
{
del = remove(buffer2);
if (del == 0)
{
strcpy(buffer, reply);
printf("File deleted sucessfully\n");
send(accepted_socket, reply, len, 0);
}
else
{
strcpy(buffer, reply2);
printf("Error: unable to delete the file\n");
send(accepted_socket, reply2, len, 0);
}
}
else if (strcmp(buffer, "MOVE_FILE") == 0)
{
ren = rename("prueba.txt", "nuevaprueba.txt");
if (ren == 0)
{
strcpy(buffer, reply);
printf("File renamed successfully\n");
send(accepted_socket, reply, len, 0);
}
else
{
strcpy(buffer, reply2);
printf("Error: unable to rename the file\n");
send(accepted_socket, reply2, len, 0);
}
}
close(accepted_socket);
printf("Accepted connection closed.\n");
sleep(1);
}
}
printf("Closing binded socket\n");
close(socket_desc);
return 0;
}
int getFiles(char *cadena, int longitud)
{
int cont = 0;
DIR *d;
struct dirent *dir;
d = opendir(".");
if (d)
{
while ((dir = readdir(d)) != NULL)
{
cont += sprintf(cadena + cont, "%s\n", dir->d_name); // ¿Cuántos caracteres escribe la función? Contador, salir
}
closedir(d);
}
else
{
return -1;
}
return cont;
}
long fileSize(const char fileNom[])
{
long size = -1;
FILE *fich;
fich = fopen(fileNom, "rb");
if (fich != NULL)
{
fseek(fich, 0L, SEEK_END);
size = ftell(fich);
fclose(fich);
}
return size;
}
CLIENT
#include <stdio.h>
#include <string.h> //strlen
#include <sys/socket.h>
#include <arpa/inet.h> //inet_addr
#include <unistd.h>
#include <stdlib.h>
#define ECHO_PORT 5675
#define _BUFFER_SIZE 20000
int main(int argc, char *argv[])
{
int len = 0, len2 = 0, bytesReceived = 0;
int socket_desc;
struct sockaddr_in server;
char received[_BUFFER_SIZE];
char *message, server_reply[_BUFFER_SIZE], server_status[_BUFFER_SIZE], file_size[_BUFFER_SIZE];
char *newNameOfFile = "";
char *nameOfFile = "";
char *comp;
char *ack = "ACK";
printf("Initializing socket\n");
//Create socket
socket_desc = socket(AF_INET, SOCK_STREAM, 0);
if (socket_desc == -1)
{
printf("Could not create socket");
}
char *address = "127.0.0.1";
if (argc > 1)
address = argv[1]; // Si existe, el primer argumento es la IP
server.sin_addr.s_addr = inet_addr(address);
server.sin_family = AF_INET;
server.sin_port = htons(ECHO_PORT);
printf("Trying to connect to address: %s\n", address);
//Connect to remote server
if (connect(socket_desc, (struct sockaddr *)&server, sizeof(server)) < 0)
{
printf("Connect error\n");
return 1;
}
printf("Connected Successfully\n");
//Send some data
message = "ECHO";
if (argc > 2)
message = argv[2]; // If exists, the second argument is the message
if (send(socket_desc, message, strlen(message) + 1, 0) < 0) // Importante el +1 para enviar el finalizador de cadena!!
{
printf("Send failed\n");
return 1;
}
printf("Message sent: %s\n", message);
//Send the file we want to
if (argc > 3)
nameOfFile = argv[3]; // If exists, the third argument is the file name
if (send(socket_desc, nameOfFile, strlen(nameOfFile) + 1, 0) < 0)
{
printf("Send failed\n");
return 1;
}
//We check if NameOfFile's size is >= 1
len = strlen(nameOfFile);
if (len >= 1)
printf("File name sent: %s\n", nameOfFile);
//Send the new file's name
if (argc > 4)
newNameOfFile = argv[4]; // If exists, the fourth argument is the new file's name
//Sending data to the server
if (send(socket_desc, newNameOfFile, strlen(newNameOfFile) + 1, 0) < 0)
{
printf("Send failed\n");
return 1;
}
//We check if newNameOfFile's size is >= 1
len2 = strlen(newNameOfFile);
if (len2 >= 1)
printf("New file's name sent: %s\n", newNameOfFile);
//Receive a reply from the server
if (recv(socket_desc, server_status, _BUFFER_SIZE, 0) >= 1)
{
printf("%s\n", server_status);
}
//We change the type of the data
long size = strtol(server_status, &comp, 10);
if (size >= 1)
{
send(socket_desc, ack, _BUFFER_SIZE, 0);
}
/*If our order is DOWNLOAD_FILE, its create the file
where we are storing the data*/
if ((strcmp(message, "DOWNLOAD_FILE") == 0) && size >= 1)
{
FILE *fp;
fp = fopen(nameOfFile, "wb");
if (NULL == fp)
{
printf("Error opening file");
return 1;
}
/* Receive data in chunks of 2000 bytes */
while ((bytesReceived = read(socket_desc, received, _BUFFER_SIZE)) > 0)
{
printf("Bytes received %d\n", bytesReceived);
fwrite(received, 1, bytesReceived, fp);
}
if (bytesReceived < 0)
{
printf("\n Read Error \n");
}
else
{
printf("SUCCESS");
}
}
//Help Command, general and particullary for each command
if (strcmp(message, "HELP") == 0)
{
printf("List of available commands: \n-LIST_FILES\n-DOWNLOAD_FILE <filename>\n-DELETE_FILE <filename>\n-MOVE_FILE <old_filename> <new_filename>\n \n \n For more help, type 'HELP_command'\n");
}
else if (strcmp(message, "HELP_LIST_FILES") == 0)
{
printf("Command: LIST_FILES \n");
printf("-Shows every existing file in the folder. \n");
}
else if (strcmp(message, "HELP_DOWNLOAD_FILE") == 0)
{
printf("Command: DOWNLOAD_FILES <filename> \n");
printf("-Downloads the requested file. \n");
}
else if (strcmp(message, "HELP_DELETE_FILE") == 0)
{
printf("Command: DELETE_FILE <filename> \n");
printf("-Deletes the requested file. \n");
}
else if (strcmp(message, "HELP_MOVE_FILE") == 0)
{
printf("Command: MOVE_FILE <old_filename> <new_filename> \n");
printf("-Renames the old_filename for the new_filename. \n");
}
close(socket_desc);
return 0;
}
I created my own ftp server/client (a very simple version) using TCP. There are 5 possible commands: ls-remote, ls-local, get , put and exit. Also, I am using multiprocessing in my server code, to be able to handle multiple clients simultaneously by using fork(). Everything is working perfectly except for one thing that I am noticing: I am having a problem handling broken server connect correctly. For example, if something were to go wrong while the server sends a message, I check if the return value from the send call is less than 0, and then I close the socket, and call exit(-1) to terminate the process; however, this causes my client to hang...
my client:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <dirent.h>
#include <stdio.h>
void readDirectory();
void syserr(char* msg)
{ perror(msg);
exit(-1);
}
int main(int argc, char* argv[])
{
int sockfd, portno, n;
struct hostent* server;
struct sockaddr_in serv_addr;
char buffer[256], temp[256];
if(argc < 3) {
fprintf(stderr, "Usage: %s <hostname> <port>\n", argv[0]);
return 1;
}
portno = atoi(argv[2]);
server = gethostbyname(argv[1]);
if(!server) {
fprintf(stderr, "ERROR: no such host: %s\n", argv[1]);
return 2;
}
sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(sockfd < 0) syserr("can't open socket");
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr = *((struct in_addr*)server->h_addr);
serv_addr.sin_port = htons(portno);
if(connect(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0)
syserr("can't connect to server");
printf("Connection to %s:%s established. Now awaiting commands...\n\n\n", argv[1], argv[2]);
do{
printf("%s:%s> ", argv[1], argv[2]); //prompt user for command
fgets(buffer, 255, stdin);
n = strlen(buffer);
if(n>0 && buffer[n-1] == '\n')
buffer[n-1] = '\0';
if(strcmp(buffer, "ls-remote") == 0){ //display files from server directory
uint32_t size;
uint32_t commandSize = strlen(buffer);
//convert to network form
commandSize = htonl(commandSize);
n = send(sockfd, &commandSize, sizeof(commandSize), 0); // send size of command to server
if(n < 0) syserr("can't send to server");
n = send(sockfd, buffer, strlen(buffer), 0); // send command to server
if(n < 0) syserr("can't send to server");
n = recv(sockfd, &size, sizeof(size), 0); // recieve the size of the directory
if(n < 0) syserr("can't receive from server");
size = ntohl(size);
int currentSize = 0;
printf("Files at the server: %s\n", argv[1]);
while(currentSize < size){
memset(&buffer[0], 0, sizeof(buffer));
n = recv(sockfd, buffer, 255, 0); // recieve directory from server
if(n < 0) syserr("can't recieve server");
currentSize = currentSize + n;
printf("%s", buffer);
}
}
else if(strcmp(buffer, "ls-local") == 0){ //display files from local directory
printf("Files at the client: \n");
readDirectory();
}
else if(strncmp(buffer, "get ", 4) == 0){ //downlaod file from server
if(strlen(buffer) < 5){ // no file was entered
printf("%s\n", "ERROR...missing filename: get <filename>");
}
else{
uint32_t fileSize;
uint32_t commandSize = strlen(buffer);
//convert to network form
commandSize = htonl(commandSize);
n = send(sockfd, &commandSize, sizeof(commandSize), 0); // send size of command to server
if(n < 0) syserr("can't send to server");
n = send(sockfd, buffer, strlen(buffer), 0); // send command to server
if(n < 0) syserr("can't send to server");
n = recv(sockfd, &fileSize, sizeof(fileSize), 0); // get size of file
if(n < 0) syserr("can't receive from server");
fileSize = ntohl(fileSize);
if(fileSize == -1){
printf("%s\n", "File does not exist");
}
else{ // file exists
int totalBytes = 0;
int bytesWritten = 0;
// get file name
char *fileName = strtok(buffer, " ");
fileName = strtok(NULL, " ");
memcpy(temp, fileName, strlen(fileName)); //copy filename into temp
temp[strlen(fileName)] = '\0';
//create new file with given name
FILE *fpNew = fopen(fileName, "w");
if(fpNew){
while(totalBytes < fileSize){
//receieve the bytes
n = recv(sockfd, buffer, sizeof(buffer), 0);
if(n < 0) syserr("can't receive from server");
//write the bytes
int b = fwrite(buffer, 1, n, fpNew);
if (b < 0)
syserr("error writing file");
if(n == 0){ // error reading on server side
break;
}
totalBytes = n + totalBytes;
bytesWritten = b + bytesWritten;
}
fclose(fpNew);
if(bytesWritten == fileSize) // all bytes read/written to file successfully
printf("Retrieval of file %s: successful.\n", temp);
else
printf("Retrieval of file %s: unsuccessful.\n", temp);
}
else{
syserr("couldnt open file for writing.");
}
}
}
}
else if(strncmp(buffer, "put ", 4) == 0){ // upload file to server
if(strlen(buffer) < 5){
printf("%s\n", "ERROR...missing filename: get <filename>");
}
else{
uint32_t commandSize = strlen(buffer);
uint32_t status;
memcpy(temp, buffer, strlen(buffer)); //copy buffer into temp
temp[strlen(buffer)] = '\0';
// get name of file
char *fileName = strtok(temp, " ");
fileName = strtok(NULL, " ");
int bytes;
FILE *fp = fopen(fileName, "r"); // open the file
if(fp){ // file exists and opened
int totalBytes = 0;
//convert to network form
commandSize = htonl(commandSize);
n = send(sockfd, &commandSize, sizeof(commandSize), 0); // send size of command to server
if(n < 0) syserr("can't send to server");
n = send(sockfd, buffer, strlen(buffer), 0); // send command to server
if(n < 0) syserr("can't send to server");
// get file size
fseek(fp, 0L, SEEK_END);
int fileSize = ftell(fp);
// send the file size
uint32_t size = htonl(fileSize);
n = send(sockfd, &size, sizeof(size), 0);
if(n < 0) syserr("can't send to server");
//go back to beginning of file
fseek(fp, 0, SEEK_SET);
while(totalBytes < fileSize){ // while there are more bytes...
bytes = fread(buffer, 1, sizeof(buffer), fp); // read bytes fromt he file
if(bytes < 0){
syserr("Error reading the file.");
}
totalBytes = totalBytes + bytes;
//send the bytes
n = send(sockfd, buffer, bytes, 0);
if(n < 0) syserr("can't send to server");
if(bytes == 0){ //error reading
break;
}
}
fclose(fp);
//recieve the final status
n = recv(sockfd, &status, sizeof(status), 0);
if(n < 0) syserr("can't receive from server");
status = ntohl(status);
if(totalBytes == fileSize && status == 1){ // successful on both ends
printf("Upload of file %s: successful.\n", fileName);
}
else{
printf("Upload of file %s: unsuccessful.\n", fileName);
}
}
else{
printf("%s\n", "File does not exist");
}
}
}else if(strcmp(buffer, "exit") == 0){
uint32_t commandSize = strlen(buffer);
//convert to network form
commandSize = htonl(commandSize);
n = send(sockfd, &commandSize, sizeof(commandSize), 0); // send size of command to server
if(n < 0) syserr("can't send to server");
n = send(sockfd, buffer, strlen(buffer), 0); // send command to server
if(n < 0) syserr("can't send to server");
}
else{
if(strcmp(buffer, "exit") != 0)
printf("Error...invalid command.\nValid commands: ls-remote, ls-local, get <filename>, put <filename>, exit\n");
}
}while (strcmp(buffer, "exit") != 0);
printf("Connection to server %s:%s terminated, BYE now!\n", argv[1], argv[2]);
close(sockfd);
return 0;
}
void readDirectory(){
DIR *d = opendir(".");
struct dirent *dir;
if (d)
{
while((dir = readdir(d))!= NULL)
{
printf("%s\n", dir->d_name);
}
closedir(d);
}
else{
syserr("Error...could not get files from directory.");
}
}
my server:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <dirent.h>
void syserr(char *msg){
perror(msg); exit(-1);
}
void errorHandling(char *msg, int newsockfd){
close(newsockfd);
perror(msg); exit(-1);
}
uint32_t directorySize();
void handle_client(int newsockfd);
int main(int argc, char *argv[])
{
int sockfd, newsockfd, portno;
struct sockaddr_in serv_addr, clt_addr;
socklen_t addrlen;
if(argc < 1) {
fprintf(stderr,"Usage: %s <port>\n", argv[0]);
return 1;
}
if(argc == 1){
argv[1] = "5555";
}
portno = atoi(argv[1]);
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd < 0) syserr("can't open socket");
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
if(bind(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0)
syserr("can't bind");
printf("bind socket to port %d...\n", portno);
listen(sockfd, 5);
for(;;){
printf("wait on port %d...\n", portno);
addrlen = sizeof(clt_addr);
newsockfd = accept(sockfd, (struct sockaddr*)&clt_addr, &addrlen);
if(newsockfd < 0) syserr("can't accept");
pid_t pid = fork();
if(pid < 0){
syserr("Error can't fork");
}
else if(pid == 0){ // child process
close(sockfd);
handle_client(newsockfd);
close(newsockfd);
break;
}
else{ // parent
close(newsockfd);
continue;
}
}
return 0;
}
uint32_t directorySize(int newsockfd){
DIR *d = opendir(".");
struct dirent *dir;
uint32_t count = 0;
if (d)
{
while((dir = readdir(d))!= NULL)
{
//count++;
count = strlen(dir->d_name) + count + 1;
}
closedir(d);
}
else{
errorHandling("Error...could not get files from directory.", newsockfd);
}
return count;
}
void handle_client(int newsockfd){
// receieve command size from client
uint32_t commandSize;
int n;
char buffer[256];
while(1){
n = recv(newsockfd, &commandSize, sizeof(commandSize), 0); // receive size of command
if(n < 0) errorHandling("can't receive from client", newsockfd);
commandSize = ntohl(commandSize);
//recieve command
n = recv(newsockfd, buffer, commandSize, 0);
if(n < 0) errorHandling("can't receive from client", newsockfd);
else buffer[n] = '\0';
if(strcmp(buffer, "ls-remote") == 0){ //display files from server directory
// get the size of the directory
uint32_t size = htonl(directorySize(newsockfd));
n = send(newsockfd, &size, sizeof(size), 0); // send size of directory
if(n < 0) errorHandling("can't send to client", newsockfd);
DIR *d = opendir(".");
struct dirent *dir;
if(d){
while((dir = readdir(d))!= NULL){
memset(&buffer[0], 0, sizeof(buffer));
strcpy(buffer, dir->d_name);
buffer[strlen(buffer)] = '\n';
// send file/folder names
n = send(newsockfd, buffer, strlen(buffer), 0);
if(n < 0)
errorHandling("can't receive from client", newsockfd);
}
closedir(d);
}
else{
errorHandling("Error...could not get files from directory.", newsockfd);
}
}
else if (strncmp(buffer, "get", 3) == 0){ // if command is get
char *fileName = strtok(buffer, " "); // "get"
fileName = strtok(NULL, " "); // the name of the file
FILE *fp = fopen(fileName, "r");
if(fp){ // if file exists
int totalBytes = 0;
int bytes;
// get the size of the file
fseek(fp, 0L, SEEK_END);
int fileSize = ftell(fp);
// send the file size
uint32_t size = htonl(fileSize);
n = send(newsockfd, &size, sizeof(size), 0);
if(n < 0) errorHandling("can't send to client", newsockfd);
//go back to beginning of file
fseek(fp, 0, SEEK_SET);
while(totalBytes < fileSize){ // while there are more bytes to read...
// read the bytes into the buffer
bytes = fread(buffer, 1, sizeof(buffer), fp);
if(bytes < 0){
errorHandling("Eorror reading bytes on server side", newsockfd);
}
//send the bytes
n = send(newsockfd, buffer, bytes, 0);
if(n < 0) errorHandling("can't send to client", newsockfd);
if(bytes == 0) // error reading file; bytes should have been > 0
break;
totalBytes = totalBytes + bytes;
}
fclose(fp);
}
else{
// tell client file doesnt exist by sending -1
uint32_t dne = htonl(-1);
n = send(newsockfd, &dne, sizeof(dne), 0);
if(n < 0) errorHandling("can't send to client", newsockfd);
}
}
else if (strncmp(buffer, "put", 3) == 0){ // upload a file
int totalBytes = 0;
int bytesWritten = 0;
int b = 0;
uint32_t fileSize, status;
n = recv(newsockfd, &fileSize, sizeof(fileSize), 0);// receive the size of file
if(n < 0) errorHandling("can't receive from client", newsockfd);
fileSize = ntohl(fileSize);
// get file name
char *fileName = strtok(buffer, " ");
fileName = strtok(NULL, " ");
//create new file with given name
FILE *fpNew = fopen(fileName, "w");
if(fpNew){
while(totalBytes < fileSize){
n = recv(newsockfd, buffer, sizeof(buffer), 0);
if(n < 0) errorHandling("can't receive from client", newsockfd);
if(n == 0){ //bad file transfer on client side
break;
}
//write the bytes
b = fwrite(buffer, 1, n, fpNew);
if(b < n){ // error writing to file
break;
}
totalBytes = totalBytes + n; // bytes recived
bytesWritten = bytesWritten + b; //bytes written
}
fclose(fpNew);
if(bytesWritten != fileSize){ // not all bytes written
status = htonl(-1);
}
else{
status = htonl(1);
}
// send the status
n = send(newsockfd, &status, sizeof(status), 0);
if(n < 0) errorHandling("can't send client", newsockfd);
}
else{
errorHandling("could not open file for writing.", newsockfd);
}
}
else{ // command is exit
printf("%s\n", "closing connection");
close(newsockfd); // close the connection
break;
}
}
}
n = recv(sockfd, &size, sizeof(size), 0); // recieve the size of the directory
if(n < 0) syserr("can't receive from server");
That's not sufficient. If n == 0 the peer has closed the connection: you must do likewise and exit the read loop, or indeed possibly the entire process in your case.
I built very basic UDP chat using C language and Fedora 16 OS.
When my server connect, he got 5 ports and listen to them.
My problem is: when I'm trying to connect to the server with new client but gives him port that my server don't know, I want him to exit Immediately.
I don't know how to check the "MSG_DONTWAIT" flag.
Here is my code:
Server side:
#define MAX_MESSAGE_SIZE 1024
#define SERVER_CONNECTIONS 5
// Implementation of server that manages a chat.
#include "server.h"
int main(int argc,char* argv[])
{
if(argc != 2) //check if user insert more then one argument to the program
{
printf("Usage server <port>\n");
fflush(stdout);
exit (-1);
}
/*!
========Server creation flow:========
1) create the socket
2) bind the socket to a port
3) recvfrom (read from socket)
4) sendto (close the socket)
5) close the socket
*/
//!------------------------------------- 1) create the socket-------------------------------------
//!------------------------------- 2) bind the socket to a port-----------------------------------
int fd[SERVER_CONNECTIONS]; //socket descriptor
int port[SERVER_CONNECTIONS]; //socket fd port
int i=0;
for(i=0; i<SERVER_CONNECTIONS; i++)
{
port[i] = atoi(argv[1])+i;
}
create_sockets(fd, port);
char buf[MAX_MESSAGE_SIZE]; //used by read() & write()
int maxfd = find_maxfd(fd);
struct sockaddr_in cli; //used by read() & write()
int cli_len = sizeof(cli); //used by read() & write()
fd_set readfds;
fd_set writefds;
struct timeval timeout;
timeout.tv_sec = 1;
int nbytes=0;
while(1)
{
FD_ZERO(&readfds);
FD_ZERO(&writefds);
for(i=0; i<SERVER_CONNECTIONS; i++)
{
FD_SET(fd[i], &readfds);
FD_SET(fd[i], &writefds);
}
/* Now use FD_SET to initialize other fd’s that have already been returned by accept() */
if (select(maxfd+1, &readfds, 0, 0, 0) < 0)
{
perror("select");
exit(1);
}
for(i=0; i<SERVER_CONNECTIONS; i++)
{
//!------------------------------- recvfrom (read from socket)-----------------------------------
if(FD_ISSET(fd[i], &readfds))
{
fprintf(stderr, "ready to read from %d\n", fd[i]);
memset(&buf, 0, sizeof(buf)); //init buf
if((nbytes = recvfrom(fd[i], buf, sizeof(buf), 0 /* flags */, (struct sockaddr*) &cli, (socklen_t*)&cli_len)) < 0)
{
perror("recvfrom");
exit(1);
}
//!------------------------------- sendto (close the socket)-----------------------------------
FD_ZERO(&writefds);
FD_SET(fd[i], &writefds);
if (select(maxfd+1, 0, &writefds, 0, &timeout) < 0)
{
perror("select");
exit(1);
}
if(FD_ISSET(fd[i], &writefds))
{
fprintf(stderr, "ready to write to %d\n", fd[i]);
string_to_hex(buf);
if ((nbytes = sendto(fd[i], buf, strlen(buf), 0 /* flags */, (struct sockaddr*) &cli, sizeof(cli))) < 0)
{
perror("sendto");
exit(1);
}
}
}
}
}
return 0;
}
void create_sockets(int fd[], int port[])
{
int i=0;
for(i=0; i<SERVER_CONNECTIONS; i++)
{
//!------------------------------------- 1) create the socket-------------------------------------
if((fd[i] = socket(PF_INET, SOCK_DGRAM, 0)) < 0)
{
perror("socket");
exit(1);
}
//!------------------------------- 2) bind the socket to a port-----------------------------------
struct sockaddr_in srv; //used by bind()
srv.sin_family = AF_INET; //use the Internet address family
srv.sin_port = htons(port[i]); //socket ‘fd’ to port
srv.sin_addr.s_addr = htonl(INADDR_ANY); //a client may connect to any of my addresses
if(bind(fd[i], (struct sockaddr*) &srv, sizeof(srv)) < 0)
{
perror("bind");
exit(1);
}
}
}
int find_maxfd(int fd[])
{
int i=0;
int res=fd[0];
for(i=1; i<SERVER_CONNECTIONS; i++)
{
if(fd[i]>res)
{
res = fd[i];
}
}
return res;
}
void string_to_hex(char buf[])
{
int buf_size = strlen(buf);
char result[buf_size*3+1];
memset(&result, 0, sizeof(result));
char temp[4];
int i=0;
for (i=0; i<buf_size-1; i++)
{
memset(&temp, 0, sizeof(temp));
sprintf(temp, "%X:", (int)buf[i]);
strcat(result, temp);
}
memset(&temp, 0, sizeof(temp));
sprintf(temp, "%X", (int)buf[i]);
strcat(result, temp);
strcpy(buf, result);
}
Client side:
#define MAX_MESSAGE_SIZE 1024
// Implementation of client that will use the chat.
#include "client.h"
int main(int argc,char* argv[])
{
if(argc != 3) //check if user insert more then one argument to the program
{
printf("Usage client <host name> <port>\n");
fflush(stdout);
exit(-1);
}
/*!
========Client creation flow:========
1) create the socket
2) sendto (close the socket)
3) recvfrom (read from socket)
4) close the socket
*/
fprintf(stderr, "please enter something: \n");
//!------------------------------------- 1) create the socket-------------------------------------
int fd; //socket descriptor
if((fd = socket(PF_INET, SOCK_DGRAM, 0)) < 0)
{
perror("socket");
exit(1);
}
struct sockaddr_in srv; //used by sendto()
srv.sin_family = AF_INET;
srand ( time(NULL) ); //new random seed
int rand_num = (rand() % 5) + atoi(argv[2]); //
srv.sin_port = htons(rand_num);
char *srv_name = argv[1];
struct hostent *hp; //ptr to host info for remote
hp = gethostbyname(srv_name);
if( hp == NULL)
{
herror("gethostbyname");
exit(-1);
}
srv.sin_addr.s_addr = ((struct in_addr*)(hp->h_addr))->s_addr; //set IP Address to "srv_name"
char buf[MAX_MESSAGE_SIZE]; //used by read() & write()
int nbytes=0;
while(1)
{
//!------------------------------------- 2) sendto (close the socket)-------------------------------------
memset(&buf, 0, sizeof(buf)); //init buf
fgets(buf, sizeof(buf), stdin); //get input from user
if(strcmp(buf, "quit\n") == 0)
{
break;
}
if(!((strlen(buf) == 1) && (buf[1] == '\n')))
{
buf[strlen(buf)-1] = '\0';
}
//write_to_server(fd, buf, srv);
if ((nbytes = sendto(fd, buf, strlen(buf), MSG_DONTWAIT /* flags */, (struct sockaddr*) &srv, sizeof(srv)) < 0))
{
perror("sendto");
exit(1);
}
//!------------------------------------- 3) recvfrom (read from socket)-------------------------------------
memset(&buf, 0, sizeof(buf)); //init read_buf
//read_from_server(fd, buf);
if((nbytes = recvfrom(fd, buf, sizeof(buf), 0 /* flags */, 0, 0) < 0))
{
perror("recvfrom");
exit(1);
}
if( (errno == EAGAIN) || (errno == EWOULDBLOCK ) )
{
perror("EWOULDBLOCK");
exit(1);
}
printf("%s\n", buf); //print result to client
fflush(stdout);
}
//!------------------------------------- close the socket-------------------------------------
close(fd);
return 0;
}
I got it..
You need to use connect function from client and the "MSG_DONTWAIT" flag.
then when the client connect and you type anything he exit right away..
//!--------------- 2) connect to the server--------------------------
if(connect(fd, (struct sockaddr*) &srv, sizeof(srv)) < 0) //connect to server "srv_name"
{
perror("connect");
exit(-1);
}
I am working on a client server program , that uses select() calls to listen to multiple sockets. But my select call gets blocked, although I have a message in one of those sockets , select() call doesn't recognize it and it's still waits there indefinetly.
There are 2 entities in the program , a master and a client.
The master knows the number of clients it will handle and waits for the clients to connect to it. Once it receives a client acknowledgement, it stores its information. Once all the clients are connected, it then sends its neighboring client's information to every client so it can form a network. It is here, I use the select() to monitor many sockets,
master has a socket to every child tat is connected to it
client has 3 main sockets
s1-to speak with master
s2-child listens for connection on this socket
neighbour-the socket on which its neighbour wait for a connection.(i.e S2 in a neighbour)
p- the socket that is results of connection from its neighbour ( accept of s2 - returns ths)
I use select to listen to server, its own socket for incoming connections and once.
Initially my server sends a string "hello" to one of the client, which receives this message and passes it on to the neighbour, in this way when the string reaches back to the first child that has received this message from server , it passes it on to its neighbour. But all though all child are in select() waiting for an input. What could cause this ??
void main(int argc, char **argv) {
int s1, s2, n, server_port, sc1, sc2, rv, rc, left_peer_port;
int peer_port;
fd_set writefds, readfds;
struct timeval tv;
struct hostent *server_info, *child_info, *left_peer_info;
int start_flag = 0;
struct sockaddr_in server, peer, incoming;
char host_child[64];
char *left_host = malloc(1);
char *right_host = malloc(1);
char buf1[256];
char buf2[256];
server_port = atoi(argv[2]);
//speak to peer using this
s2 = socket(AF_INET, SOCK_STREAM, 0);
if (s2 < 0) {
perror("socket:");
exit(s2);
}
peer_port = server_port + 1;
gethostname(host_child, sizeof host_child);
child_info = gethostbyname(host_child);
if (child_info == NULL) {
fprintf(stderr, "%s: host not found (%s)\n", argv[0], host_child);
exit(1);
}
peer.sin_family = AF_INET;
memcpy(&peer.sin_addr, child_info->h_addr_list[0], child_info->h_length);
int changeport = 0;
do {
peer.sin_port = htons(peer_port);
rc = bind(s2, (struct sockaddr *) &peer, sizeof(peer));
if (rc < 0) {
//perror("bind:");
peer_port++;
changeport = 1;
//exit(rc);
} else {
changeport = 0;
}
} while (changeport == 1);
if (listen(s2, 100) == -1) {
perror("listen");
exit(3);
}
//Now talk to server
server_info = gethostbyname(argv[1]);
if (server_info == NULL) {
fprintf(stderr, "%s: host not found\n", argv[0]);
exit(1);
}
// pretend we've connected both to a server at this point
//speak to server using this
s1 = socket(AF_INET, SOCK_STREAM, 0);
if (s1 < 0) {
perror("socket:");
exit(s1);
}
server.sin_family = AF_INET;
server.sin_port = htons(server_port);
memcpy(&server.sin_addr, server_info->h_addr_list[0], server_info->h_length);
//To talk to the server
sc1 = connect(s1, (struct sockaddr *) &server, sizeof(server));
if (sc1 < 0) {
perror("connect:");
exit(sc1);
}
int send_len;
char *str = malloc(1);
sprintf(str, "%d", peer_port);
printf("\nport-here=%s\n", str);
send_len = send(s1, str, strlen(str), 0);
if (send_len != strlen(str)) {
perror("send");
exit(1);
}
int recv_len;
char buf[100];
int ref = 0;
int recv_stage = 0;
int start_id;
recv_len = recv(s1, buf, 34, 0);
if (recv_len < 0) {
perror("recv");
exit(1);
}
buf[recv_len] = '\0';
char *temp_port;
if (!strcmp("close", buf))
printf("%s", buf);
//break;
else {
char *temp_buffer = malloc(1);
char *id = malloc(100);
char *pp = malloc(1);
strcpy(temp_buffer, buf);
char *search = ":";
temp_port = strtok(temp_buffer, search);
strcpy(buf, temp_port);
printf("temp_name%s", temp_port);
temp_port = strtok(NULL, search);
strcpy(pp, temp_port);
printf("temp_port%s", temp_port);
temp_port = strtok(NULL, search);
strcpy(id, temp_port);
printf("id%s", temp_port);
strcpy(temp_port, pp);
printf("\nbuf=%s\n", buf);
printf("\nport=%s\n", temp_port);
printf("\nid=%s\n", id);
start_id = atoi(id);
}
//To send packet to its neighbour
left_peer_info = gethostbyname(buf);
printf("\nleft host=%s\n", buf);
if (left_peer_info == NULL) {
fprintf(stderr, "%s: host not found\n", left_host);
exit(1);
}
left_peer_port = atoi(temp_port);
int neighbour_socket;
struct hostent *neighbour_info;
struct sockaddr_in neighbour;
neighbour_socket = socket(AF_INET, SOCK_STREAM, 0);
if (neighbour_socket < 0) {
perror("socket:");
exit(neighbour_socket);
}
neighbour_info = left_peer_info;
neighbour.sin_family = AF_INET;
neighbour.sin_port = htons(left_peer_port);
memcpy(&neighbour.sin_addr, neighbour_info->h_addr_list[0], neighbour_info->h_length);
printf("\nconnected to port %d\n", left_peer_port);
//To talk to the neighbour
printf("\ncomes here\n");
//Listen on this socket connection for potato
int send_peer_len;
int nfds;
nfds = MAX(MAX(neighbour_socket, s2), s1);
// clear the set ahead of time
FD_ZERO(&writefds);
// add our descriptors to the set
FD_SET(neighbour_socket, &writefds);
FD_SET(s1, &writefds);
FD_SET(s2, &writefds);
//FD_SET(s2, &writefds);
FD_ZERO(&readfds);
FD_SET(neighbour_socket, &readfds);
FD_SET(s1, &readfds);
FD_SET(s2, &readfds);
//select()
// since we got s2 second, it's the "greater", so we use that for
// the n param in select()
//n = s1 + 1;
// wait until either socket has data ready to be recv()d (timeout 10.5 secs)
tv.tv_sec = 10;
tv.tv_usec = 500000;
int fds[3];
fds[0] = s1;
fds[1] = s2;
fds[2] = neighbour_socket;
int p = 0;
int p_flag = 0;
while (1) {
printf("\n nfds = %d , p = %d \n", nfds, p);
char buf_msg[64];
//This is where the error occurs //
rv = select(nfds, &readfds, NULL, NULL, 0);
//This is where the error occurs //
if (rv == -1) {
perror("select"); // error occurred in select()
} else if (rv == 0) {
printf("Timeout occurred! No data after 10.5 seconds.\n");
} else {
// one or both of the descriptors have data
//reading message from server
int select_fd;
for (select_fd = 0; select_fd <= nfds; select_fd++) {
if (FD_ISSET(select_fd, &readfds) != 0) {
if (select_fd == s1) {
recv_len = 0;
recv_len = recv(s1, buf_msg, 34, 0);
if (recv_len < 0) {
perror("recv");
exit(1);
}
buf_msg[recv_len] = '\0';
printf("\nreceived from server = %s\n", buf_msg);
//send to neighbour
int sc3;
sc3 = connect(neighbour_socket, (struct sockaddr *) &neighbour, sizeof(neighbour));
if (sc3 < 0) {
perror("connect:");
exit(sc3);
}
str = malloc(1);
strcpy(str, buf_msg);
send_len = send(neighbour_socket, str, strlen(str), 0);
printf("\n send - len - s1 - %d\n", send_len);
if (send_len != strlen(str)) {
perror("send");
exit(1);
}
start_flag = 1;
//FD_CLR(s1, &readfds);
printf("\ncrossed server\n");
} else if (select_fd == s2) {
int list_len = sizeof incoming;
printf("\ninside client\n");
printf("\nWaiting for accept in S2\n");
if (p_flag == 0) {
p_flag = 1;
p = accept(s2, (struct sockaddr *) &incoming, &list_len);
printf("\nConnection accepted in S2\n");
if (p < 0) {
perror("bind:");
exit(rc);
}
}
nfds = MAX(nfds, p);
recv_len = 0;
buf_msg[recv_len] = '\0';
recv_len = recv(p, buf_msg, 34, 0);
if (recv_len < 0) {
perror("recv");
exit(1);
}
buf_msg[recv_len] = '\0';
printf("\nreceived from client = %s\n", buf_msg);
//send to neighbour
//if(start_id!=1){
int sc3;
sc3 = connect(neighbour_socket, (struct sockaddr *) &neighbour, sizeof(neighbour));
if (sc3 < 0) {
perror("connect:");
//exit(sc3);
}
//}
str = malloc(1);
strcpy(str, buf_msg);
send_len = send(neighbour_socket, str, strlen(str), 0);
printf("\n send - len - s2 - %d\n", send_len);
if (send_len != strlen(str)) {
perror("send");
exit(1);
}
} else if (select_fd == neighbour_socket) {
printf("\ncomes in\n");
} else if (select_fd == p && p != 0) {
int list_len = sizeof incoming;
printf("\ninside p\n");
recv_len = 0;
buf_msg[recv_len] = '\0';
printf("\nwaiting at recv in P\n");
recv_len = recv(p, buf_msg, 34, 0);
printf("\ncrossed at recv in P\n");
if (recv_len < 0) {
perror("recv");
exit(1);
}
buf_msg[recv_len] = '\0';
printf("\nreceived from client = %s\n", buf_msg);
//send to neighbour
str = malloc(1);
strcpy(str, buf_msg);
send_len = send(neighbour_socket, str, strlen(str), 0);
printf("\n send - len - neighbour - %d\n", send_len);
if (send_len != strlen(str)) {
perror("send");
exit(1);
}
}
}
}
FD_ZERO(&readfds);
//FD_SET(neighbour_socket,&readfds);
FD_SET(s1, &readfds);
FD_SET(neighbour_socket, &readfds);
if (p_flag == 1) {
printf("\nsetting P\n");
FD_SET(p, &readfds);
FD_SET(s2, &readfds);
p_flag = 0;
} else {
printf("\nNot setting P\n");
FD_SET(s2, &readfds);
}
}
}
close(s1);
close(s2);
}
Thanks in advance.
The first parameter to select must be the maximum file descriptor plus one. As far as I can tell in that huge lump of code you posted, you forgot that "plus one".
I believe Mat has found the underlying problem. But I think there is a much larger problem here:
int send_len;
char *str=malloc(1);
sprintf(str,"%d",peer_port);
printf("\nport-here=%s\n",str);
You have corrupted your heap with your sprintf(3) call. Maybe it isn't important data you've overwritten, and maybe malloc(3) won't ever actually allocate one byte, but that is a bad assumption to make. You need to allocate at least six bytes for a port number: five for the digits in 65535 and one for the trailing ASCII NUL \0 byte.
buf[recv_len] = '\0';
char *temp_port;
//printf("\n-%s\n",buf);
if ( !strcmp("close", buf) )
printf("%s",buf);
//break;
else{
char *temp_buffer=malloc(1);
char *id=malloc(100);
char *pp=malloc(1);
strcpy(temp_buffer,buf);
In the preceding selection, you have stored a \0 into the end of buf, so you're presumably working with a string of some sort. But in a few lines, you allocate a single byte and then proceed to copy the contents of buf into that single byte. The ASCII NUL will use that byte entirely, leaving no space for the string you received. But strcpy(3) doesn't work that way -- it will copy the contents of buf, until that '\0' character, into the memory starting with your single byte. You've again destroyed your heap. But this time it can overwrite significantly more than five bytes -- and all under the control of the remote peer.
Heap overflows are extremely dangerous. I found over 350 references to exploitable bugs in programs that derive directly from heap overflows in an old archive I have from the Common Vulnerabilities and Exposures project.
Do not deploy this program on publicly-accessible machines until you have fixed these problems. It represents a significant security flaw. Find every instance of malloc(1) and replace it with the correct amount of memory that must be allocated. Once you've done this, please run your program with MALLOC_CHECK_=1 or under control of valgrind(1) to help you find further memory allocation problems.
Have you considered using poll() instead of select()? It's easier to debug and scales elegantly to however many you need.