-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathenc_server.c
More file actions
240 lines (228 loc) · 8.63 KB
/
Copy pathenc_server.c
File metadata and controls
240 lines (228 loc) · 8.63 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
#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 <sys/wait.h>
#define BUFFER_CAPACITY 1000
#define MAX_CHILDREN 5
// From server.c
// Print formatted error message and exit with status code
void error(int exitCode, const char *message) {
fprintf(stderr, "Client error: %s\n", message);
exit(exitCode);
}
// From server.c
// Set up the address struct
void setupAddressStruct(struct sockaddr_in* address, int portNumber){
// Clear out the address struct
memset((char*) address, '\0', sizeof(*address));
// The address should be network capable
address->sin_family = AF_INET;
// Store the port number
address->sin_port = htons(portNumber);
// Allow a client at any address to connect to this server
address->sin_addr.s_addr = INADDR_ANY;
}
// Code adapted from the code in Server Program section
// https://canvas.oregonstate.edu/courses/1999732/pages/exploration-client-server-communication-via-sockets?module_item_id=25329397
void sendData(int connectionSocket, char* data) {
// Calculate the number of characters
int len = (int)strlen(data);
// Sends the length of the data
int charsWritten = send(connectionSocket, &len, sizeof(len), 0);
// If negative, error occurred
if (charsWritten < 0) {
error(1, "CLIENT: ERROR writing to socket");
}
// Track how many bytes already sent
int totalSent = 0;
// Loop until the total number of bytes sent is equal to the length
while (totalSent < len) {
// Determine how many bytes to send
int bytesToSend;
if (len - totalSent < BUFFER_CAPACITY) {
bytesToSend = len - totalSent;
} else {
bytesToSend = BUFFER_CAPACITY;
}
// Send message through the socket
charsWritten = send(connectionSocket, data + totalSent, bytesToSend, 0);
if (charsWritten < 0) {
error(1, "CLIENT: WARNING: Not all data written to socket!");
}
// Updates how many bytes were successfully sent
totalSent += charsWritten;
}
}
// Code adapted from the code in Server Program section
// https://canvas.oregonstate.edu/courses/1999732/pages/exploration-client-server-communication-via-sockets?module_item_id=25329397
char* receiveData(int connectionSocket) {
int len;
// Receive the length of the incoming message
int charsRead = recv(connectionSocket, &len, sizeof(len), 0);
// If negative value then error occurred
if (charsRead < 0) {
error(1, "CLIENT: ERROR reading message length from socket");
}
// Allocate memory for the message (+1 for null terminator)
char* result = malloc(len + 1);
if (!result) {
error(1, "CLIENT: ERROR allocating memory");
}
// Track how many bytes have been read
int totalRead = 0;
// Loop until all expected bytes are received
while (totalRead < len) {
int bytesToRead;
if (len - totalRead < BUFFER_CAPACITY) {
bytesToRead = len - totalRead;
} else {
bytesToRead = BUFFER_CAPACITY;
}
charsRead = recv(connectionSocket, result + totalRead, bytesToRead, 0);
if (charsRead < 0) {
error(1, "CLIENT: ERROR reading from socket");
}
// Updates how many bytes were successfully read
totalRead += charsRead;
}
result[len] = '\0';
return result;
}
// Adapted code for the validation logic
// https://github.com/CS-344-nilsstreedain/program4/blob/main/enc_server.c
// Verify the client
void verifyClient(int connectionSocket) {
char client[4], server[4] = "enc";
memset(client, '\0', sizeof(client));
// Receives a message up to 4 bytes from the client through the socket
int charsRead = recv(connectionSocket, client, sizeof(client), 0);
if (charsRead < 0){
error(1, "CLIENT: ERROR reading from socket");
}
// Sends back to client
// Handshake message to verify client
int charsWritten = send(connectionSocket, server, sizeof(server), 0);
if (charsWritten < 0) {
error(1, "CLIENT: ERROR writing to socket");
}
// Compares the received client string to the expected "enc" string
if (strcmp(client, server) != 0) {
// If strings do not match, close socket
close(connectionSocket);
error(2, "CLIENT: Rejected connection: Client not validated");
}
}
// https://en.wikipedia.org/wiki/One-time_pad
// After verifying the connection to enc_server is coming from enc_client
// Then this child receives plaintext and a key from enc_client via the connected socket
void otpEncryption(int connectionSocket) {
// Read a plaintext message from the client
char* plaintext = receiveData(connectionSocket);
char* key = receiveData(connectionSocket);
// Calculates the length of the plaintext message
// Key pased in must be at least as big as the plaintext
int len = (int)strlen(plaintext);
char* result = (char*) malloc(len + 1);
for (int i = 0; i < len; i++) {
// Converts the text into a number between 0 and 26
int text;
if (plaintext[i] == ' ') {
text = 26;
} else {
text = plaintext[i] - 'A';
}
// Converts the character into a number between 0 and 26
int keyValue;
if (key[i] == ' ') {
keyValue = 26;
} else {
keyValue = key[i] - 'A';
}
// Wrap around if the result is over 26
int encryptValue = (text + keyValue) % 27;
// If 26 then result is a space
if (encryptValue == 26) {
result[i] = ' ';
} else {
result[i] = encryptValue + 'A';
}
}
// Adds a null terminator to the end of the encrypted string
result[len] = '\0';
// Sends the encrypted message back to the client
sendData(connectionSocket, result);
free(result);
free(plaintext);
free(key);
close(connectionSocket);
}
// https://canvas.oregonstate.edu/courses/1999732/pages/exploration-client-server-communication-via-sockets?module_item_id=25329397
int main(int argc, const char * argv[]) {
// Checks if the user provided a port number
if (argc < 2) {
fprintf(stderr, "USAGE: %s port\n", argv[0]);
exit(1);
}
// From server.c
// Create the socket that will listen for connections
int listenSocket = socket(AF_INET, SOCK_STREAM, 0);
if (listenSocket < 0)
error(1, "ERROR opening socket");
struct sockaddr_in serverAddress, clientAddress;
socklen_t sizeOfClientInfo = sizeof(clientAddress);
// Set up the address struct for the server socket
setupAddressStruct(&serverAddress, atoi(argv[1]));
// Associate the socket to the port
if (bind(listenSocket,
(struct sockaddr *)&serverAddress,
sizeof(serverAddress)) < 0){
error(1, "ERROR on binding");
}
// From server.c
// Start listening for connections
listen(listenSocket, 5);
// Tracks the number of active child processes
int childCount = 0;
while (1) {
// https://canvas.oregonstate.edu/courses/1999732/pages/exploration-process-api-monitoring-child-processes?module_item_id=25329381
// Checks for any child process that has exited
// WNOHANG specified. If the child hasn't termianted,
// waitpid will immediately return the value 0
while (waitpid(-1, NULL, WNOHANG) > 0) {
childCount = childCount -1;
}
// Accept new copnnections if the current number of child processes is less than 5
if (childCount < MAX_CHILDREN) {
int connectionSocket = accept(listenSocket,
(struct sockaddr *)&clientAddress,
&sizeOfClientInfo);
if (connectionSocket < 0) {
error(1, "ERROR on accept");
}
// Adapted from example code
// https://canvas.oregonstate.edu/courses/1999732/pages/exploration-process-api-monitoring-child-processes?module_item_id=25329381
// Fork a child process
int spawnpid = fork();
switch (spawnpid) {
case -1:
error(1, "Fork failed");
break;
case 0:
// Child process
verifyClient(connectionSocket);
otpEncryption(connectionSocket);
exit(0);
default:
// Parent process
childCount = childCount + 1;
close(connectionSocket);
}
}
}
close(listenSocket);
return 0;
}