Laboratoare
Programarea folosind BSD Sockets
Part 1. BSD Sockets
The first assignment deals with the implementation of a small TCP application using BSD sockets. The application must consist as a server and at least one client that use the services provided by the server. Teams will propose specifications for the application by sending them by e-mail to the lab supervisor. Examples below.
The following tasks must be accomplished:
An application-level communication protocol
A server and at least a client that closesly follow the protocol. The programs must be written in C, using BSD sockets on Linux or UNIX.
[Optional] The project can be hosted on a public code repository (git or svn), or on the CS Department's Git server
The deadline for submitting the project is Week 3 of the semester (CTI-EN), and Week 5 (CTI-RO).
Examples of projects [RO]
Part 2. Distributed application
This part focuses on building from scratch a distributed application on Java EE or another platform of choice. The platform and the actual specification of the assignment must be negotiated/discussed with the lab coordinator.
The application consists of several distributed, interconnected software components, that work together for a common goal. There are a minimum of two types of components that must be implemented:
Servers, that maintain the global status of the application and provides its main functionality. Servers may serve a different geographical area, and/or follow a specific purpose within the application. Servers communicate with each other in order to update the status, maintain consistency, syncronize data, and so on.
Clients. They provide the users with a lightweight and possibly mobile interface, and communicate with the servers. There can be several types of clients: standard standalone applications featuring a platform-specific UI, Web applications, mobile, etc.
Clients and servers may communicate through technologies and techniques of choice, such as: HTTP, REST, RMI, etc.
Requirements that must be met:
CTI-RO: minimum 2 different types of servers AND 2 different types of clients
CTI-EN: minimum 2 different types of servers OR 2 different types of clients
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <string.h>
#include <errno.h>
#include <dirent.h>
#include <unistd.h>
#include <sys/stat.h>
#include <limits.h>
int paths_count=0;
char paths[255][PATH_MAX];
void myErorr(char *msg){
fprintf(stderr,"%s:%s\n",msg,strerror(errno));
exit(errno);
}
int isDirectoryEmpty(char *dirPath)
{
char cmd[1024];
int status, exitcode;
snprintf(cmd, 1024, "test $(ls -A \"%s\" 2>/dev/null | wc -l) -ne 0", dirPath);
status = system(cmd);
exitcode = WEXITSTATUS(status);
return exitcode;
}
void getAllFilesPaths(char *dirPath)
{
DIR *dir;
struct dirent *in;
char *name;
struct stat info;
char cale[PATH_MAX], cale_link[PATH_MAX + 1];
int n;
char errorMessage[PATH_MAX+100];
if(!(dir = opendir(dirPath)))
{
snprintf(errorMessage, sizeof(errorMessage), "Error while openning directory:%s\n",dirPath);
myErorr(errorMessage);
}
errno=0;
while((in = readdir(dir))>0)
{
name = in->d_name;
if(strcmp(name, ".") == 0 || strcmp(name, "..")==0)
continue;
snprintf(cale, sizeof(cale), "%s/%s", dirPath, name);
if(lstat(cale, &info)<0)
{
snprintf(errorMessage, sizeof(errorMessage), "Error at lstat:%s\n",cale);
myErorr(errorMessage);
}
if(S_ISDIR(info.st_mode)){
getAllFilesPaths(cale);
if(isDirectoryEmpty(cale)){
printf("%s\n", cale);
}
}
else
if(S_ISLNK(info.st_mode))
{
n = readlink(cale, cale_link, sizeof(cale_link));
cale_link[n]='\0';
printf("%s\n",cale_link);
}
else
{
printf("%s\n", cale);
}
}
if(errno){
snprintf(errorMessage, sizeof(errorMessage), "Error reading directory:%s\n",dirPath);
myErorr(errorMessage);
}
if(closedir(dir)){
snprintf(errorMessage, sizeof(errorMessage), "Error closing directory:%s\n",dirPath);
myErorr(errorMessage);
}
}
int main(int argc, char *argv[])
{
if(argc != 2)
{
printf("Mod de utilizare: %s director\n", argv[0]);
exit(1);
}
getAllFilesPaths(argv[1]);
return 0;
}
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <string.h>
#include <errno.h>
#include <dirent.h>
#include <unistd.h>
#include <sys/stat.h>
#include <limits.h>
int paths_count=0;
char paths[255][PATH_MAX];
void myErorr(char *msg){
fprintf(stderr,"%s:%s\n",msg,strerror(errno));
exit(errno);
}
int isEmptyDirectory(char *dirPath)
{
char cmd[1024];
int status, exitcode;
snprintf(cmd, 1024, "test $(ls -A \"%s\" 2>/dev/null | wc -l) -ne 0", dirPath);
status = system(cmd);
exitcode = WEXITSTATUS(status);
return exitcode;
}
void getFilesPaths(char *dirPath)
{
DIR *dir;
struct dirent *in;
char *name;
struct stat info;
char cale[PATH_MAX], cale_link[PATH_MAX + 1];
int n;
char errorMessage[PATH_MAX+100];
if(!(dir = opendir(dirPath)))
{
snprintf(errorMessage, sizeof(errorMessage), "Error while openning directory:%s\n",dirPath);
myErorr(errorMessage);
}
errno=0;
while((in = readdir(dir))>0)
{
name = in->d_name;
if(strcmp(name, ".") == 0 || strcmp(name, "..")==0)
continue;
snprintf(cale, sizeof(cale), "%s/%s", dirPath, name);
if(lstat(cale, &info)<0)
{
snprintf(errorMessage, sizeof(errorMessage), "Error at lstat:%s\n",cale);
myErorr(errorMessage);
}
if(S_ISDIR(info.st_mode)){
getFilesPaths(cale);
if(isEmptyDirectory(cale)){
strcpy(paths[paths_count++], cale);
}
}
else
if(S_ISLNK(info.st_mode))
{
n = readlink(cale, cale_link, sizeof(cale_link));
cale_link[n]='\0';
strcpy(paths[paths_count++], cale_link);
}
else
{
strcpy(paths[paths_count++], cale);
}
}
if(errno){
snprintf(errorMessage, sizeof(errorMessage), "Error reading directory:%s\n",dirPath);
myErorr(errorMessage);
}
if(closedir(dir)){
snprintf(errorMessage, sizeof(errorMessage), "Error closing directory:%s\n",dirPath);
myErorr(errorMessage);
}
}
void getAllFilesPaths(char *dirPath)
{
getFilesPaths(dirPath);
paths_count--;
strcpy(paths[paths_count],"");
}
int main(int argc, char *argv[])
{
if(argc != 2)
{
printf("Usage: %s director\n", argv[0]);
exit(1);
}
getAllFilesPaths(argv[1]);
for(int i=0;i<paths_count;i++){
printf("%s\n",paths[i]);
}
return 0;
}
client.c
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "client.h"
char *ip;
int port;
int socketFileDescriptor;
struct sockaddr_in serverAddress;
char *root;
char errorMessage[PATH_MAX + 100];
char *formatdate(time_t val) {
char *str;
if ((str = (char *) malloc(48)) == NULL)
displayError("malloc() error.");
strftime(str, 48, "%Y%m%d%H%M.%S", localtime(&val));
return str;
}
int adjustTimestamp(char *filepath, char *timestamp) {
char cmd[PATH_MAX + 32];
int status, exitcode;
snprintf(cmd, sizeof(cmd), "touch -a -m -t %s \"%s\"", timestamp, filepath);
status = system(cmd);
exitcode = WEXITSTATUS(status);
return exitcode;
}
int getIndexFromServerFiles(FileMetadata *serverFiles, int count, char *path) {
int i;
for (i = 0; i < count; i++) {
if (!strcmp(serverFiles[i].path, path))
return i;
}
return -1;
}
int removeDirectory(char *directoryPath) {
char cmd[PATH_MAX + 64];
int status, exitcode;
snprintf(cmd, sizeof(cmd), "rm -rf \"%s\"", directoryPath);
status = system(cmd);
exitcode = WEXITSTATUS(status);
return exitcode;
}
int removeFile(char *path) {
char cmd[PATH_MAX + 64];
int status, exitcode;
snprintf(cmd, sizeof(cmd), "rm \"%s\"", path);
status = system(cmd);
exitcode = WEXITSTATUS(status);
return exitcode;
}
void getFilesToDelete(FileMetadata *serverFiles, int serverFilesCount) {
filesToDelete = (FileMetadata *) malloc(sizeof(FileMetadata));
for (int i = 0; i < pathsCount; i++) {
int toDelete = 1;
for (int j = 0; j < serverFilesCount; j++) {
if (!strcmp(ownFiles[i].path, serverFiles[j].path)) {
toDelete = 0;
break;
}
}
if (toDelete) {
filesToDelete = (FileMetadata *) realloc(filesToDelete, sizeof(FileMetadata) * (++fileToDeleteCount));
filesToDelete[fileToDeleteCount - 1] = ownFiles[i];
}
}
}
void getFilesToUpdate(FileMetadata *serverFiles, int serverFilesCount) {
filesToUpdate = (FileMetadata *) malloc(sizeof(FileMetadata));
for (int i = 0; i < serverFilesCount; i++) {
int different = 0;
int found = 0;
for (int j = 0; j < pathsCount; j++) {
if (!strcmp(serverFiles[i].path, filesToUpdate[j].path)) {
found = 1;
if (serverFiles[i].size != filesToUpdate[j].size ||
serverFiles[i].timeStamp != filesToUpdate[j].timeStamp ||
serverFiles[i].isRegularFile != filesToUpdate[j].isRegularFile) {
different = 1;
break;
}
}
}
if (different || !found) {
filesToUpdate = (FileMetadata *) realloc(filesToUpdate, sizeof(FileMetadata) * (++filesToUpdateCount));
filesToUpdate[filesToUpdateCount - 1] = serverFiles[i];
}
}
}
void handle() {
char buff[1024];
char newPath[PATH_MAX];
FileMetadata *serverFiles;
int serverFilesCount;
int n = 0, i, size;
/*
* Receiving files count from the server.
*/
n = read(socketFileDescriptor, buff, 10);
if (n < 0) {
snprintf(errorMessage, sizeof(errorMessage), "\nError reading from socketFileDescriptor in clint.c :\n");
displayError(errorMessage);
}
buff[n] = 0;
serverFilesCount = atoi(buff);
#if defined DEBUG_MODE
printf("[debug - client]: server tells that are %d files there\n", serverFilesCount);
#endif
/*
* Allocate memory for the server files to check if there are outdated/files that need to be deleted.
*/
if ((serverFiles = (FileMetadata *) malloc(serverFilesCount * sizeof(FileMetadata))) == NULL) {
snprintf(errorMessage, sizeof(errorMessage), "\nError allocating memory for server file :\n");
displayError(errorMessage);
}
/*
* Reading them from the socket.
*/
for (i = 0; i < serverFilesCount; i++) {
if (read(socketFileDescriptor, &serverFiles[i], sizeof(FileMetadata)) < 0) {
snprintf(errorMessage, sizeof(errorMessage), "\nError reading server files in client.c :\n");
displayError(errorMessage);
}
}
/*
* Getting files that need to be updated/deleted.
*/
getFilesToUpdate(serverFiles, serverFilesCount);
getFilesToDelete(serverFiles, serverFilesCount);
/*
* Telling the server how many files need updated by the client.
*/
#if defined DEBUG_MODE
printf("[debug - client]: %d files need updated/added\n", filesToUpdateCount);
#endif
snprintf(buff, 10, "%d", filesToUpdateCount);
if (write(socketFileDescriptor, buff, 10) < 0) {
snprintf(errorMessage, sizeof(errorMessage), "\nError writing file to update count :\n");
displayError(errorMessage);
}
for (i = 0; i < filesToUpdateCount; i++) {
#if defined DEBUG_MODE
printf("[debug - client]: sending '%s' to server\n", filesToUpdate[i].path);
#endif
if (write(socketFileDescriptor, filesToUpdate[i].path, PATH_MAX)) {
snprintf(errorMessage, sizeof(errorMessage), "\nError writing file to update :\n");
displayError(errorMessage);
}
}
/*
* Updating the files from the server.
*/
for (i = 0; i < filesToUpdateCount; i++) {
int idx;
int serverFileIdx = getIndexFromServerFiles(serverFiles, serverFilesCount, filesToUpdate[i].path);
/*
* Building the absolute path.
*/
snprintf(newPath, PATH_MAX, "%s/%s", root, filesToUpdate[i].path);
#if defined DEBUG_MODE
printf("[debug - client]: file '%s' is being updated.\n", newPath);
#endif
if (!filesToUpdate[i].isRegularFile) // is a directory
{
mkdir(newPath, ACCESSPERMS);
}
else // is a file, get data from socket and write into it
{
int fd = open(newPath, O_CREAT | O_TRUNC | O_WRONLY, 0744);
off_t size;
if (fd < 0) {
snprintf(errorMessage, sizeof(errorMessage), "\nError opening file: %s \n", newPath);
displayError(errorMessage);
}
if(read(socketFileDescriptor, buff, 12)<0){
snprintf(errorMessage, sizeof(errorMessage), "\nError reading from file in client.c: %s :\n", newPath);
displayError(errorMessage);
}
size = strtol(buff, NULL, 10);
if(read(socketFileDescriptor, buff, size)<0){
snprintf(errorMessage, sizeof(errorMessage), "\nError reading from file in client.c: %s :\n", newPath);
displayError(errorMessage);
}
if(write(fd, buff, size)<0){
snprintf(errorMessage, sizeof(errorMessage), "\nError writing from file in client.c: %s :\n", newPath);
displayError(errorMessage);
}
if (close(fd) < 0) {
snprintf(errorMessage, sizeof(errorMessage), "\nError closing file in client.c: %s :\n", newPath);
displayError(errorMessage);
}
}
char *date = formatdate(serverFiles[serverFileIdx].timeStamp);
adjustTimestamp(newPath, date);
#if defined DEBUG_MODE
printf("[debug - client]: timestamp=%s for file %s\n", date, filesToUpdate[i].path);
#endif
if ((idx = getPathIndex(newPath)) == -1) // file/dir does not exists in the list => add it
{
strcpy(ownFiles[pathsCount].path, newPath);
ownFiles[pathsCount].size = serverFiles[serverFileIdx].size;
ownFiles[pathsCount].timeStamp = serverFiles[serverFileIdx].timeStamp;
pathsCount ++;
}
else // update its stats
{
ownFiles[idx].size = serverFiles[serverFileIdx].size;
ownFiles[idx].timeStamp = serverFiles[serverFileIdx].timeStamp;
}
#if defined DEBUG_MODE
printf("[debug - client]: file '%s' successfully updated.\n", newPath);
#endif
if (date) {
free(date);
}
}
/*
* Deleting the files that are on the clients' machine but not on the server.
*/
for (i = 0; i < fileToDeleteCount; i++)
{
int idx, j;
snprintf(newPath, PATH_MAX, "%s/%s", root, filesToDelete[i].path);
#if defined DEBUG_MODE
printf("[debug - client]: file '%s' is being deleted.\n", newPath);
#endif
if (!filesToDelete[i].isRegularFile) // is a directory
{
removeDirectory(newPath);
}
else // is a file, remove it
{
if (strlen(newPath) == strlen(root) + strlen(filesToDelete[i].path) + 1)
removeFile(newPath);
}
if ((idx = getPathIndex(newPath)) != -1)
{
for (j = idx; j < pathsCount - 1; j++)
ownFiles[j] = ownFiles[j + 1];
ownFiles --;
}
#if defined DEBUG_MODE
printf("[debug - client]: file '%s' successfully deleted.\n", newPath);
#endif
}
if (serverFiles) {
free(serverFiles);
}
}
void clientSetup() {
if ((socketFileDescriptor = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
exit(EXIT_FAILURE);
}
serverAddress.sin_family = AF_INET;
serverAddress.sin_addr.s_addr = inet_addr(ip);
serverAddress.sin_port = htons(port);
if (connect(socketFileDescriptor, (struct sockaddr *) &serverAddress, sizeof(serverAddress)) < 0) {
exit(EXIT_FAILURE);
}
getAllFilesPaths(root);
getAllFilesMetadata(root);
handle();
}
int main(int argc, char *argv[]) {
if (argc != 3) {
printf("USAGE: %s <config_file_path> <root>.\n", argv[0]);
exit(1);
}
if (argv[2][strlen(argv[2]) - 1] == '/') {
printf("[ERROR]: Root shouldn't end with the '/' character.\n");
exit(1);
}
readConfigurationParameters(argv[1]);
root = argv[2];
clientSetup();
return 0;
}
client.h
#ifndef CLIENT_H
#define CLIENT_H
#include "../Common/common.h"
#ifndef ACCESSPERMS
#define ACCESSPERMS(S_IRWXU | S_IRWXG | S_IRWXO
#endif
FileMetadata *filesToDelete;
FileMetadata *filesToUpdate;
int filesToUpdateCount;
int fileToDeleteCount;
char *formatdate(time_t val);
int adjustTimestamp(char *filepath, char *timestamp);
int getIndexFromServerFiles(FileMetadata *serverFiles, int count, char *path);
int removeDirectory(char *directoryPath);
int removeFile(char *path);
void getFilesToDelete(FileMetadata *serverFiles, int serverFilesCount;
void getFilesToUpdate(FileMetadata *serverFiles, int serverFilesCount);
#endif //COMMON_H
common.c
#include "common.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <dirent.h>
#include <sys/stat.h>
int pathsCount=0;
void displayError(char *msg) {
fprintf(stderr, "%s:%s\n", msg, strerror(errno));
exit(errno);
}
int isEmptyDirectory(char *directoryPath) {
char cmd[1024];
int status, exitcode;
snprintf(cmd, 1024, "test $(ls -A \"%s\" 2>/dev/null | wc -l) -ne 0", directoryPath);
status = system(cmd);
exitcode = WEXITSTATUS(status);
return exitcode;
}
int getPathIndex(char *path) {
for (int i = 0; i < pathsCount; i++) {
if (!strcmp(ownFiles[i].path, path)) {
return i;
}
}
return -1;
}
void readConfigurationParameters(char *path) {
char errorMessage[PATH_MAX + 100];
FILE *f = fopen(path, "r");
if (NULL == f) {
snprintf(errorMessage, sizeof(errorMessage), "Error opening configuration file: %s\n", path);
displayError(errorMessage);
}
ip = (char *) malloc(20);
if (NULL == ip) {
snprintf(errorMessage, sizeof(errorMessage), "Configuration file: error at memory allocation for ip: %s\n", path);
displayError(errorMessage);
}
char *s_port = (char *) malloc(20);
if (NULL == s_port) {
snprintf(errorMessage, sizeof(errorMessage), "Configuration file: error at memory allocation for port: %s\n", path);
displayError(errorMessage);
}
errno = 0;
fscanf(f, "ip=%s\nport=%s", ip, s_port);
if (errno) {
snprintf(errorMessage, sizeof(errorMessage), "Error while reading from configuration file: %s\n", path);
displayError(errorMessage);
}
if (fclose(f)) {
snprintf(errorMessage, sizeof(errorMessage), "Error at closing configuration file: %s\n", path);
displayError(errorMessage);
}
port = atoi(s_port);
printf("[loaded] ip: %s, port: %d\n", ip, port);
}
void printPaths() {
for (int i = 0; i < pathsCount; i++)
printf("%s\n", paths[i]);
}
void getAllFilesPaths(char *directoryPath) {
getFilesPaths(directoryPath, strlen(directoryPath) + 1);
strcpy(paths[pathsCount], "");
}
void getFilesPaths(char *directoryPath, int length) {
DIR *currentDirectory;
struct dirent *currentEntrance;
char *entranceName;
struct stat entranceInfo;
char path[PATH_MAX];
char errorMessage[PATH_MAX + 100];
if (!(currentDirectory = opendir(directoryPath))) {
snprintf(errorMessage, sizeof(errorMessage), "Error while opening directory: %s\n", directoryPath);
displayError(errorMessage);
}
errno = 0;
while ((currentEntrance = readdir(currentDirectory)) > 0) {
entranceName = currentEntrance->d_name;
if (strcmp(entranceName, ".") == 0 || strcmp(entranceName, "..") == 0)
continue;
snprintf(path, sizeof(path), "%s/%s", directoryPath, entranceName);
if (lstat(path, &entranceInfo) < 0) {
snprintf(errorMessage, sizeof(errorMessage), "Error at lstat: %s\n", path);
displayError(errorMessage);
}
strcpy(paths[pathsCount++], path + length);
if (S_ISDIR(entranceInfo.st_mode) && !isEmptyDirectory(path)) {
getFilesPaths(path, length);
}
}
if (errno) {
snprintf(errorMessage, sizeof(errorMessage), "Error while reading from directory: %s\n", directoryPath);
displayError(errorMessage);
}
if (closedir(currentDirectory)) {
snprintf(errorMessage, sizeof(errorMessage), "Error at closing directory: %s\n", directoryPath);
displayError(errorMessage);
}
}
void getAllFilesMetadata(char *root) {
char errorMessage[PATH_MAX + 100];
ownFiles = (FileMetadata *) malloc(pathsCount * sizeof(FileMetadata));
//pentru fiecare path din paths, creaza un nou obiect file_metadata,
//populeaza-l cu date apeland lstat SI adauga-l la own_files_metadata
if (NULL == ownFiles) {
displayError("Error at memory allocation for ownFiles");
}
struct stat entranceInfo;
for (int i = 0; i < pathsCount; i++) {
char *fullPath = (char *) malloc(strlen(root) + strlen(paths[i]) + 10);
if (NULL == fullPath) {
snprintf(errorMessage, sizeof(errorMessage), "Error at memory allocation for fullPath:");
displayError(errorMessage);
}
snprintf(fullPath, PATH_MAX, "%s/%s", root, paths[i]);
strcpy(ownFiles[i].path, paths[i]);
if (stat(fullPath, &entranceInfo) < 0) {
snprintf(errorMessage, sizeof(errorMessage), "Error at stat: %s\n", fullPath);
displayError(errorMessage);
}
ownFiles[i].size = entranceInfo.st_size;
ownFiles[i].timeStamp = entranceInfo.st_mtime;
ownFiles[i].isRegularFile = S_ISDIR(entranceInfo.st_mode) ? 0 : 1;
if (fullPath) {
free(fullPath);
}
}
}
common.h
#ifndef COMMON_H
#define COMMON_H
#define DEBUG_MODE
#include <limits.h>
typedef struct FileMetadata {
char path[PATH_MAX];
unsigned int size;
unsigned long timeStamp;
short isRegularFile; // 1 if regular file; 0 if directory
} FileMetadata;
extern int pathsCount;
char paths[1024][PATH_MAX];
FileMetadata *ownFiles;
char *ip;
int port;
void displayError(char *msg);
int isEmptyDirectory(char *directoryPath);
int getPathIndex(char *path);
void readConfigurationParameters(char *path);
void printPaths();
void getAllFilesPaths(char *directoryPath);
void getFilesPaths(char *directoryPath, int length);
void getAllFilesMetadata(char *root);
#endif //COMMON_H
server.config
ip=127.0.0.1
port=9002
server.c
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include "../Common/common.h"
#include "server.h"
int socketFileDescriptor;
struct sockaddr_in serverAddress, remoteAddress;
socklen_t len;
char *root;
char errorMessage[PATH_MAX + 100];
off_t getFileSize(char *path) {
struct stat entranceInfo;
if (lstat(path, &entranceInfo) < 0) {
snprintf(errorMessage, sizeof(errorMessage), "\nError at lstat: %s\n", path);
displayError(errorMessage);
}
return entranceInfo.st_size;
}
void handleRequest(int connectionFileDescriptor) {
char buff[PATH_MAX], newPath[PATH_MAX];
int n;
int filesToUpdateCount;
FileMetadata *filesToUpdate;
/*
Telling the client how many files are ready to be synchronized.
Then sending their files to check which of them needs sync.
*/
snprintf(buff, 10, "%d", pathsCount);
if (write(connectionFileDescriptor, buff, 10) < 0) {
snprintf(errorMessage, sizeof(errorMessage), "\nError while writing path count from the server:\n");
displayError(errorMessage);
}
for (int i = 0; i < pathsCount; i++) {
if (write(connectionFileDescriptor, &ownFiles[i], sizeof(FileMetadata)) < 0) {
snprintf(errorMessage, sizeof(errorMessage), "\nError while writing some FileMetadata from the server :\n");
displayError(errorMessage);
}
}
/*
Receiving the number of files that need updated on clients' computer.
*/
n = read(connectionFileDescriptor, buff, 10);
if (n < 0) {
snprintf(errorMessage, sizeof(errorMessage), "\nError while reading from connectionFileDescriptor");
displayError(errorMessage);
}
buff[n] = 0;
filesToUpdateCount = atoi(buff);
#if defined DEBUG_MODE
printf("[debug - server]: client needs %d files updated.\n", filesToUpdateCount);
#endif
/*
Allocate enough memory for the files.
*/
if ((filesToUpdate = (FileMetadata *) malloc(filesToUpdateCount * sizeof(FileMetadata))) == NULL) {
snprintf(errorMessage, sizeof(errorMessage), "\nError while allocating memory to filesToUpdate :\n");
displayError(errorMessage);
}
/*
Store the files into an array.
*/
for (int i = 0; i < filesToUpdateCount; i++) {
n = read(connectionFileDescriptor, buff, PATH_MAX);
if (n < 0) {
snprintf(errorMessage, sizeof(errorMessage), "\nError while reading filesToUpdate");
displayError(errorMessage);
}
buff[n] = 0;
#if defined DEBUG_MODE
printf("[debug - server]: client needs file '%s' updated.\n", buff);
#endif
filesToUpdate[i] = ownFiles[getPathIndex(buff)];
}
/*
Building absolute path + transfer non-updated files to the client.
*/
for (int i = 0; i < filesToUpdateCount; i++) {
snprintf(newPath, PATH_MAX, "%s/%s", root, filesToUpdate[i].path);
#if defined DEBUG_MODE
printf("[debug - server]: file '%s' is updating to client.\n", newPath);
#endif
if (filesToUpdate[i].isRegularFile) // is not a directory
{
int fd;
int n;
if ((fd = open(newPath, O_RDONLY)) == -1) {
snprintf(errorMessage, sizeof(errorMessage), "\nError while opening file :%s\n", newPath);
displayError(errorMessage);
}
off_t size = getFileSize(newPath);
#if defined DEBUG_MODE
printf("[debug - server]: file '%s', size=%ld\n", newPath, size);
#endif
snprintf(buff, 12, "%ld", size);
if(write(connectionFileDescriptor, buff, 12)<0){
snprintf(errorMessage, sizeof(errorMessage), "\nError while writing filesToUpdate stuff 2");
displayError(errorMessage);
}
n=read(fd, buff, size);
if(n<0){
snprintf(errorMessage, sizeof(errorMessage), "\nError while reading filesToUpdate stuff 2");
displayError(errorMessage);
}
if(write(connectionFileDescriptor, buff, size)<0){
snprintf(errorMessage, sizeof(errorMessage), "\nError while writing filesToUpdate stuff 3");
displayError(errorMessage);
}
if (close(fd) < 0) {
snprintf(errorMessage, sizeof(errorMessage), "\nError while closing update file:%s\n",newPath);
displayError(errorMessage);
}
#if defined DEBUG_MODE
printf("[debug - server]: file '%s' successfully updated.\n", filesToUpdate[i].path);
#endif
}
}
// if(close(connectionFileDescriptor)<0){
// snprintf(errorMessage, sizeof(errorMessage), "\nError while closing connection file descriptor");
// displayError(errorMessage);
// }
exit(0);
}
void acc() {
int connfd;
pid_t wpid, pid;
int status;
len = sizeof(remoteAddress);
while ((connfd = accept(socketFileDescriptor, (struct sockaddr *) &remoteAddress, &len)) >= 0)
{
if ((pid = fork()) == 0)
handleRequest(connfd);
close(connfd);
while ((wpid = wait(&status)) > 0);
}
}
void serverSetup() {
if ((socketFileDescriptor = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
snprintf(errorMessage, sizeof(errorMessage), "\nError while server setup :\n");
displayError(errorMessage);
}
serverAddress.sin_family = AF_INET;
serverAddress.sin_addr.s_addr = inet_addr(ip);
serverAddress.sin_port = htons(port);
if (bind(socketFileDescriptor, (struct sockaddr *) &serverAddress, sizeof(serverAddress)) < 0) {
snprintf(errorMessage, sizeof(errorMessage), "\nBinding failure :\n");
displayError(errorMessage);
}
listen(socketFileDescriptor, 5);
getAllFilesPaths(root);
getAllFilesMetadata(root);
acc();
}
int main(int argc, char *args[]) {
if (argc != 3) {
printf("Usage %s <config_file_path> <root>.\n", args[0]);
exit(1);
}
// signal(SIGCHLD, SIG_IGN);
readConfigurationParameters(args[1]);
root = args[2];
serverSetup();
return 0;
}
server.h
#ifndef SERVER_H
#define SERVER_H
void handleRequest(int connectionFileDescriptor);
void acc();
void serverSetup();
#endif //SERVER_H