some improvements and fixed intendations

This commit is contained in:
Benedikt Galbavy 2023-10-20 21:56:39 +02:00
parent ddef20a8e7
commit c4a3ddae50

View File

@ -17,213 +17,215 @@
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
int create_socket; int create_socket;
char buffer[BUF]; char buffer[BUF];
struct sockaddr_in address; struct sockaddr_in address;
int size; int size;
int isQuit; int isQuit;
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
// CREATE A SOCKET // CREATE A SOCKET
// https://man7.org/linux/man-pages/man2/socket.2.html // https://man7.org/linux/man-pages/man2/socket.2.html
// https://man7.org/linux/man-pages/man7/ip.7.html // https://man7.org/linux/man-pages/man7/ip.7.html
// https://man7.org/linux/man-pages/man7/tcp.7.html // https://man7.org/linux/man-pages/man7/tcp.7.html
// IPv4, TCP (connection oriented), IP (same as server) // IPv4, TCP (connection oriented), IP (same as server)
if ((create_socket = socket(AF_INET, SOCK_STREAM, 0)) == -1) if ((create_socket = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{ {
perror("Socket error"); perror("Socket error");
return EXIT_FAILURE; return EXIT_FAILURE;
} }
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
// INIT ADDRESS // INIT ADDRESS
// Attention: network byte order => big endian // Attention: network byte order => big endian
memset(&address, 0, sizeof(address)); // init storage with 0 memset(&address, 0, sizeof(address)); // init storage with 0
address.sin_family = AF_INET; // IPv4 address.sin_family = AF_INET; // IPv4
// https://man7.org/linux/man-pages/man3/htons.3.html // https://man7.org/linux/man-pages/man3/htons.3.html
address.sin_port = htons(PORT); address.sin_port = htons(PORT);
// https://man7.org/linux/man-pages/man3/inet_aton.3.html // https://man7.org/linux/man-pages/man3/inet_aton.3.html
if (argc < 2) if (argc < 2)
{ {
inet_aton("127.0.0.1", &address.sin_addr); inet_aton("127.0.0.1", &address.sin_addr);
} }
else else
{ {
inet_aton(argv[1], &address.sin_addr); inet_aton(argv[1], &address.sin_addr);
} }
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
// CREATE A CONNECTION // CREATE A CONNECTION
// https://man7.org/linux/man-pages/man2/connect.2.html // https://man7.org/linux/man-pages/man2/connect.2.html
if (connect(create_socket, if (connect(create_socket,
(struct sockaddr *)&address, (struct sockaddr *)&address,
sizeof(address)) == -1) sizeof(address)) == -1)
{ {
// https://man7.org/linux/man-pages/man3/perror.3.html // https://man7.org/linux/man-pages/man3/perror.3.html
perror("Connect error - no server available"); perror("Connect error - no server available");
return EXIT_FAILURE; return EXIT_FAILURE;
} }
// ignore return value of printf // ignore return value of printf
printf("Connection with server (%s) established\n", printf("Connection with server (%s) established\n",
inet_ntoa(address.sin_addr)); inet_ntoa(address.sin_addr));
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
// RECEIVE DATA // RECEIVE DATA
// https://man7.org/linux/man-pages/man2/recv.2.html // https://man7.org/linux/man-pages/man2/recv.2.html
size = recv(create_socket, buffer, BUF - 1, 0); /*
if (size == -1) size = recv(create_socket, buffer, BUF - 1, 0);
{ if (size == -1)
perror("recv error"); {
} perror("recv error");
else if (size == 0) }
{ else if (size == 0)
printf("Server closed remote socket\n"); // ignore error {
} printf("Server closed remote socket\n"); // ignore error
else }
{ else
buffer[size] = '\0'; {
printf("%s", buffer); // ignore error buffer[size] = '\0';
} printf("%s", buffer); // ignore error
}
*/
do { do {
printf("Please specify a command (SEND, LIST, READ, DEL, QUIT): "); printf("Please specify a command (SEND, LIST, READ, DEL, QUIT): ");
if (fgets(buffer, BUF - 1, stdin) != NULL) if (fgets(buffer, BUF - 1, stdin) != NULL)
{ {
size = strlen(buffer); size = strlen(buffer);
if (buffer[size - 2] == '\r' && buffer[size - 1] == '\n') if (buffer[size - 2] == '\r' && buffer[size - 1] == '\n')
{ {
size -= 2; size -= 2;
buffer[size] = 0; buffer[size] = 0;
} }
else if (buffer[size - 1] == '\n') else if (buffer[size - 1] == '\n')
{ {
--size; --size;
buffer[size] = 0; buffer[size] = 0;
} }
isQuit = strcmp(buffer, "QUIT") == 0; isQuit = strcmp(buffer, "QUIT") == 0;
if (strcmp(buffer, "SEND") == 0) if (strcmp(buffer, "SEND") == 0)
{ {
char sender[BUF], receiver[BUF], subject[81], message[BUF * 10]; char sender[BUF], receiver[BUF], subject[81], message[BUF * 10];
printf("Sender: "); printf("Sender: ");
fgets(sender, BUF - 1, stdin); fgets(sender, BUF - 1, stdin);
printf("Receiver: "); printf("Receiver: ");
fgets(receiver, BUF - 1, stdin); fgets(receiver, BUF - 1, stdin);
printf("Subject: "); printf("Subject: ");
fgets(subject, 80, stdin); fgets(subject, 80, stdin);
printf("Message: \n"); printf("Message: ");
char line[BUF]; char line[BUF];
message[0] = '\0'; message[0] = '\0';
while (true) while (true)
{ {
fgets(line, BUF - 1, stdin); fgets(line, BUF - 1, stdin);
if (strcmp(line, ".\n") == 0) if (strcmp(line, ".\n") == 0)
break; break;
strcat(message, line); strcat(message, line);
} }
snprintf(buffer, sizeof(buffer), "SEND\n%s%s%s%s.\n", sender, receiver, subject, message); snprintf(buffer, sizeof(buffer), "SEND\n%s%s%s%s.\n", sender, receiver, subject, message);
} }
else if (strcmp(buffer, "LIST") == 0) else if (strcmp(buffer, "LIST") == 0)
{ {
char username[BUF]; char username[BUF];
printf("Username: "); printf("Username: ");
fgets(username, BUF - 1, stdin); fgets(username, BUF - 1, stdin);
snprintf(buffer, sizeof(buffer), "LIST\n%s", username); snprintf(buffer, sizeof(buffer), "LIST\n%s", username);
} }
else if (strcmp(buffer, "READ") == 0) else if (strcmp(buffer, "READ") == 0)
{ {
char username[BUF], msgNum[10]; char username[BUF], msgNum[10];
printf("Username: "); printf("Username: ");
fgets(username, BUF - 1, stdin); fgets(username, BUF - 1, stdin);
printf("Message Number: "); printf("Message Number: ");
fgets(msgNum, 9, stdin); fgets(msgNum, 9, stdin);
snprintf(buffer, sizeof(buffer), "READ\n%s%s", username, msgNum); snprintf(buffer, sizeof(buffer), "READ\n%s%s", username, msgNum);
} }
else if (strcmp(buffer, "DEL") == 0) else if (strcmp(buffer, "DEL") == 0)
{ {
char username[BUF], msgNum[10]; char username[BUF], msgNum[10];
printf("Username: "); printf("Username: ");
fgets(username, BUF - 1, stdin); fgets(username, BUF - 1, stdin);
printf("Message Number: "); printf("Message Number: ");
fgets(msgNum, 9, stdin); fgets(msgNum, 9, stdin);
snprintf(buffer, sizeof(buffer), "DEL\n%s%s", username, msgNum); snprintf(buffer, sizeof(buffer), "DEL\n%s%s", username, msgNum);
} }
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
// SEND DATA // SEND DATA
// https://man7.org/linux/man-pages/man2/send.2.html // https://man7.org/linux/man-pages/man2/send.2.html
// send will fail if connection is closed, but does not set // send will fail if connection is closed, but does not set
// the error of send, but still the count of bytes sent // the error of send, but still the count of bytes sent
int size = strlen(buffer); int size = strlen(buffer);
if ((send(create_socket, buffer, size + 1, 0)) == -1) if ((send(create_socket, buffer, size + 1, 0)) == -1)
{ {
// in case the server is gone offline we will still not enter // in case the server is gone offline we will still not enter
// this part of code: see docs: https://linux.die.net/man/3/send // this part of code: see docs: https://linux.die.net/man/3/send
// >> Successful completion of a call to send() does not guarantee // >> Successful completion of a call to send() does not guarantee
// >> delivery of the message. A return value of -1 indicates only // >> delivery of the message. A return value of -1 indicates only
// >> locally-detected errors. // >> locally-detected errors.
// ... but // ... but
// to check the connection before send is sense-less because // to check the connection before send is sense-less because
// after checking the communication can fail (so we would need // after checking the communication can fail (so we would need
// to have 1 atomic operation to check...) // to have 1 atomic operation to check...)
perror("send error"); perror("send error");
break; break;
} }
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
// RECEIVE FEEDBACK // RECEIVE FEEDBACK
// consider: reconnect handling might be appropriate in somes cases // consider: reconnect handling might be appropriate in somes cases
// How can we determine that the command sent was received // How can we determine that the command sent was received
// or not? // or not?
// - Resend, might change state too often. // - Resend, might change state too often.
// - Else a command might have been lost. // - Else a command might have been lost.
// //
// solution 1: adding meta-data (unique command id) and check on the // solution 1: adding meta-data (unique command id) and check on the
// server if already processed. // server if already processed.
// solution 2: add an infrastructure component for messaging (broker) // solution 2: add an infrastructure component for messaging (broker)
// //
size = recv(create_socket, buffer, BUF - 1, 0); size = recv(create_socket, buffer, BUF - 1, 0);
if (size == -1) if (size == -1)
{ {
perror("recv error"); perror("recv error");
break; break;
} }
else if (size == 0) else if (size == 0)
{ {
printf("Server closed remote socket\n"); // ignore error printf("Server closed remote socket\n"); // ignore error
break; break;
} }
else else
{ {
buffer[size] = '\0'; buffer[size] = '\0';
printf("<< %s\n", buffer); // ignore error printf("<< %s\n", buffer); // ignore error
if (strcmp("OK", buffer) != 0) /*if (strcmp("OK", buffer) != 0) // needs proper verification, since responses vary between commands
{ {
fprintf(stderr, "<< Server error occured, abort\n"); fprintf(stderr, "<< Server error occured, abort\n");
break; break;
} }*/
} }
} }
} while (!isQuit); } while (!isQuit);
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
// CLOSES THE DESCRIPTOR // CLOSES THE DESCRIPTOR
if (create_socket != -1) if (create_socket != -1)
{ {
if (shutdown(create_socket, SHUT_RDWR) == -1) if (shutdown(create_socket, SHUT_RDWR) == -1)
{ {
// invalid in case the server is gone already // invalid in case the server is gone already
perror("shutdown create_socket"); perror("shutdown create_socket");
} }
if (close(create_socket) == -1) if (close(create_socket) == -1)
{ {
perror("close create_socket"); perror("close create_socket");
} }
create_socket = -1; create_socket = -1;
} }
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }