-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathotp_enc_d.c
524 lines (475 loc) · 35.4 KB
/
otp_enc_d.c
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
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
/*******************************************************************************
** Author: James Hippler (HipplerJ)
** Oregon State University
** CS 344-400 (Spring 2018)
** Operating Systems I
**
** Description: Program 4 - OTP (Block 4)
** Due: Sunday, June 10, 2018
**
** Filename: otp_enc_d.c
**
** OBJECTIVES:
** In this assignment, you will be creating five small programs that encrypt
** and decrypt information using a one-time pad-like system. I believe that
** you will find the topic quite fascinating: one of your challenges will be
** to pull yourself away from the stories of real-world espionage and tradecraft
** that have used the techniques you will be implementing.
**
** These programs serve as a capstone to what you have been learning in this
** course, and will combine the multi-processing code you have been learning
** with socket-based inter-process communication. Your programs will also
** accessible from the command line using standard UNIX features like
** input/output redirection, and job control. Finally, you will write a
** short compilation script.
**
** otp_enc_d: This program will run in the background as a daemon. Upon
** execution, otp_enc_d must output an error if it cannot be run due to a
** network error, such as the ports being unavailable. Its function is to
** perform the actual encoding, as described above in the Wikipedia quote. This
** program will listen on a particular port/socket, assigned when it is first
** ran (see syntax below). When a connection is made, otp_enc_d must call
** accept() to generate the socket used for actual communication, and then use a
** separate process to handle the rest of the transaction (see below), which
** will occur on the newly accepted socket.
**
** This child process of otp_enc_d must first check to make sure it is
** communicating with otp_enc (see otp_enc, below). After verifying that the
** connection to otp_enc_d is coming from otp_enc, then this child receives from
** otp_enc plaintext and a key via the communication socket (not the original
** listen socket). The otp_enc_d child will then write back the ciphertext to
** the otp_enc process that it is connected to via the same communication
** socket. Note that the key passed in must be at least as big as the plaintext.
**
** Your version of otp_enc_d must support up to five concurrent socket
** connections running at the same time; this is different than the number of
** processes that could queue up on your listening socket (which is specified in
** the second parameter of the listen() call). Again, only in the child process
** will the actual encryption take place, and the ciphertext be written back:
** the original server daemon process continues listening for new connections,
** not encrypting data.
**
** In terms of creating that child process as described above, you may either
** create with fork() a new process every time a connection is made, or set up a
** pool of five processes at the beginning of the program, before connections
** are allowed, to handle your encryption tasks. As above, your system must be
** able to do five separate encryptions at once, using either method you choose.
**
** Use this syntax for otp_enc_d:
** otp_enc_d listening_port
**
** listening_port is the port that otp_enc_d should listen on. You will always
** start otp_enc_d in the background, as follows (the port 57171 is just an
** example; yours should be able to use any port):
** $ otp_enc_d 57171 &
**
** In all error situations, this program must output errors to stderr as
** appropriate (see grading script below for details), but should not crash or
** otherwise exit, unless the errors happen when the program is starting up
** (i.e. are part of the networking start up protocols like bind()). If given
** bad input, once running, otp_enc_d should recognize the bad input, report an
** error to stderr, and continue to run. Generally speaking, though, this daemon
** shouldn't receive bad input, since that should be discovered and handled in
** the client first. All error text must be output to stderr.
**
** This program, and the other 3 network programs, should use "localhost" as
** the target IP address/host. This makes them use the actual computer they
** all share as the target for the networking connections.
*******************************************************************************/
/*******************************************************************************
** PREPROCESSOR DIRECTIVES
*******************************************************************************/
#include <stdio.h> // Include the stdio.h library
#include <stdlib.h> // Include the stdlib.h library
#include <string.h> // Include the string.h library
#include <unistd.h> // Include the unistd.h library
#include <sys/types.h> // Include the sys/types.h library
#include <sys/socket.h> // Include the sys/socket.h library
#include <netinet/in.h> // Include the netinet/in.h library
#include <stdbool.h> // Include the stdbool.h library
/*******************************************************************************
** GLOBAL CONSTANT DECLARATIONS
*******************************************************************************/
#define OTP_ENC "otp_enc" // Declare global constant for the process name "otp_enc"
#define OTP_ENC_D "otp_enc_d" // Declare global constant for the process name "otp_enc_d"
#define TERM_SIG "!!" // Declare global constatn for the transmission termination signal
#define MSG_BUFFER 1000 // Declare global constant for total message transmission size
#define MAX_MSG_SIZE 75000 // Declare global constant for maximum size of total message
#define MAX_PROCESSES 5 // Declare global constant for total number of available processes
/*******************************************************************************
** STRUCTURE DECLARATIONS
*******************************************************************************/
// Establishes a struct to store process information
struct process_info{
pid_t processes[MAX_PROCESSES]; // Holds the child process id's that are forked
int active; // Manages the number of active processes
};
/*******************************************************************************
** FUNCTION DECLARATIONS
*******************************************************************************/
void confirm_arguments(int, char**); // Declare function to confirm user input
void set_address_struct(struct sockaddr_in*, char**); // Declare function to set the address structure
void set_socket(int*); // Declare function to establish the connection socket
void enable_socket(struct sockaddr_in, int); // Declare function to enable the socket
void accept_connection(struct sockaddr_in*, int*, int); // Declare function to accept the connection from the client
void check_availability(int, struct process_info); // Declare function to check if the server is busy or available
void introduction(int); // Declare function to introduce the client and the server process information
void check_processes(pid_t, int, struct process_info*); // Declare function to check on background process information
void receive_file_text(int, char*); // Declare function to receive the plain and key files from the client
char* receive_message(int); // Declare function to receive messages from client
void send_message(int, char*); // Declare function to send messages from client
void encryption(int, char*, char*); // Declare function to encrypt the plain text file using the key
void send_encryption(int, char*); // Declare function to send the encrypted ciphertext to the client
void add_process(pid_t, struct process_info*); // Declare function to add the new child process that was forked
void remove_process(pid_t, struct process_info*); // Declare function to remove the terminated child process
void close_connection(int*); // Declare function to close connections with the client
void close_listen_socket(int*); // Declare function to close the listen socket for the server
void error(const char*); // Declare function to output error messages and terminate the program
/*******************************************************************************
* Description: main function
* This is the main function where the program begins (and hopefully ends).
* It receives the total number of arguments and an array with the actual
* arguments received. It calls the appropriate functions in the correct order
* to communicate with the client.
*******************************************************************************/
int main(int argc, char *argv[]) {
pid_t child_id = 0; // Establish a pid_t function to hold child ids
int listenSocketFD, // Establish an integer variable to store socket information
establishedConnectionFD, // Establish an integer variable to store socket information
child_exit = -5; // Establish an integer variable to store child exit status
char plain[MAX_MSG_SIZE], // Establish character array to store the plain text file
key[MAX_MSG_SIZE]; // Establish character array to store the key text file
struct sockaddr_in serverAddress, // Establish a structure instance for sockaddr_in called serverAddress
clientAddress; // Establish a structure instance for sockaddr_in called clientAddress
struct process_info process; // Establish a structure instance for process_info called process
process.active = 0; // Initialize active processes to zero
memset(process.processes, '\0', MAX_PROCESSES); // Clear the process array and set elements to null
memset(plain, '\0', MAX_MSG_SIZE); // Clear the plain text array and set elements to null
memset(key, '\0', MAX_MSG_SIZE); // Clear the key text array and set elements to null
confirm_arguments(argc, argv); // Call function to confirm user input
set_address_struct(&serverAddress, argv); // Call function to build server address structure
set_socket(&listenSocketFD); // Call function to set the listen socket
enable_socket(serverAddress, listenSocketFD); // Call function to enable the listen socket
while(true) { // Establish loop to run forever (while true)
accept_connection(&clientAddress, &establishedConnectionFD, // Call function to accept client connections
listenSocketFD);
check_processes(child_id, child_exit, &process); // Check the background processes for termination
child_id = fork(); // Fork a child process and store the retuned process id
if (child_id < 0){ // If there was an error forking
fprintf(stderr, "ERROR: Unable to create new process\n"); // Print and error message to stderr but continue running the program
} else if (child_id == 0) { // If the process id is zero then we are operating in the child
check_availability(establishedConnectionFD, process); // Call function to determine if the server is available
introduction(establishedConnectionFD); // Call function to introduce the server and the client process information
receive_file_text(establishedConnectionFD, plain); // Call function to receive the plain text file
receive_file_text(establishedConnectionFD, key); // Call function to receive the key text file
encryption(establishedConnectionFD, plain, key); // Call function to create ciphertext with plain and key information
close_connection(&establishedConnectionFD); // Close the socket where the server is communicating with clients
exit(EXIT_SUCCESS); // Exit the child process with a success status
} else { // Otherwise, we're operating in the parent process
add_process(child_id, &process); // Add the new child process to the structure tracking that information
}
}
close_listen_socket(&listenSocketFD); // Close the socket where the server is listening for communication
return 0; // Exit program successfully after all process are complete
}
/*******************************************************************************
* Description: confirm_arguments function
* Function confirms that the user input the appropriate number of arguments
* when executing the program from the command line.
*******************************************************************************/
void confirm_arguments(int argc, char** argv) {
if (argc != 2) { // Check for correct number of arguments (2 total)
fprintf(stderr,"USAGE: %s port\n", argv[0]); // Output error message to stderr with correct program usage
exit(EXIT_FAILURE); // Exit the program with a failure status
}
}
/*******************************************************************************
* Description: set_address_struct function
* Function is called to built the sockadd_in structure. It receives a pointer
* to the sockaddr_in structure and a pointer to the user's command line
* arguments. Most of this code was obtained from the server.c file
*******************************************************************************/
void set_address_struct(struct sockaddr_in* serverAddress, char** argv) {
int portNumber = 0; // Establish an integer variable to store port number
// Set up the address struct for this process (the server)
memset((char *)serverAddress, '\0', sizeof(serverAddress)); // Clear out the address struct
portNumber = atoi(argv[1]); // Get the port number, convert to an integer from a string
serverAddress->sin_family = AF_INET; // Create a network-capable socket
serverAddress->sin_port = htons(portNumber); // Store the port number
serverAddress->sin_addr.s_addr = INADDR_ANY; // Any address is allowed for connection to this process
}
/*******************************************************************************
* Description: set_socket function
* Function creates a socket that will be used to list for incoming traffic on
* the network. Most of this code was obtained from the server.c file
*******************************************************************************/
void set_socket(int* listenSocketFD) {
// Set up the socket
*listenSocketFD = socket(AF_INET, SOCK_STREAM, 0); // Create the socket
if (listenSocketFD < 0) { // If socket not successfully created
error("ERROR opening socket"); // Output error message to stderr and exit program
}
}
/*******************************************************************************
* Description: enable_socket function
* Function is used to bind and enable the socket and port information. It
* receive the sockaddr_in structure and the cosket information. Most of this
* code was obtained from the server.c file.
*******************************************************************************/
void enable_socket(struct sockaddr_in serverAddress, int listenSocketFD) {
// Enable the socket to begin listening
if (bind(listenSocketFD, (struct sockaddr *)&serverAddress,
sizeof(serverAddress)) < 0) { // Connect socket to port
error("ERROR on binding"); // If binding failed, output error message to stderr and exit program
}
listen(listenSocketFD, 5); // Flip the socket on - it can now receive up to 5 connections
}
/*******************************************************************************
* Description: accept_connection function
* Function accepts the incoming communication from the client and moves the
* connection from the listening port to another communication port. Most of
* this code was obtained from the server.c file
*******************************************************************************/
void accept_connection(struct sockaddr_in* clientAddress, int* establishedConnectionFD, int listenSocketFD) {
socklen_t sizeOfClientInfo; // Establish a socklen_t variable to store size of client information.
// Accept a connection, blocking if one is not available until one connects
sizeOfClientInfo = sizeof(clientAddress); // Get the size of the address for the client that will connect
*establishedConnectionFD = accept(listenSocketFD, // Call accept function to establish communication socket with the client
(struct sockaddr *)clientAddress, &sizeOfClientInfo);
if (establishedConnectionFD < 0) { // If there was an error while creating the connection socket
fprintf(stderr, "ERROR: on accept with client\n"); // Print an error to stderr on the server
}
}
/*******************************************************************************
* Description: check_availability function
* Function check the total number of running processes and either approves
* or rejects the clients connection. The server can only manage a total of
* five individual processes.
*******************************************************************************/
void check_availability(int ecFD, struct process_info proc) {
receive_message(ecFD); // Call function to receive message from client
if(proc.active < MAX_PROCESSES){ // Check if active process are less than maximum (5)
send_message(ecFD, "AVAILABLE"); // Let the client know that the server is available
} else {
send_message(ecFD, "OCCUPIED"); // Let the client know that the server is at capacity
close_connection(&ecFD); // Call the function to close the connection with the client
exit(EXIT_FAILURE); // Exit from the child process and return to the parent
}
}
/*******************************************************************************
* Description: introduction function
* Function is called for the server and the client to send their process
* information and determine if they've connected to a legal process. The
* function receives an integer variable containing the socket information.
* No return variables.
*******************************************************************************/
void introduction(int establishedConnectionFD) {
char process_name[MSG_BUFFER]; // Establish a character array to store the process name
memset(process_name, '\0', MSG_BUFFER); // Clear the character array and set all elements to null
char approved[MSG_BUFFER]; // Establish a character array to store approval status
memset(approved, '\0', MSG_BUFFER); // Clear the character array and set all elements to null
strncpy(process_name, receive_message(establishedConnectionFD), MSG_BUFFER); // Copy the received message to the process_name buffer
send_message(establishedConnectionFD, OTP_ENC_D); // Send a confirmation to the client
strncpy(approved, receive_message(establishedConnectionFD), MSG_BUFFER);
if((strcmp(process_name, OTP_ENC) == 0) && (strcmp(approved, "APPROVED") // If the process name is correct and the client has approved
== 0)) {
send_message(establishedConnectionFD, "APPROVED"); // Send approved message to the client
} else { // Otherwise
// fprintf(stderr, "Connection Refused: Illegal Process %s\n", process_name); // Print an error message to stderr
send_message(establishedConnectionFD, "REJECTED"); // Send a rejected message to the client
close_connection(&establishedConnectionFD); // Close the connection with the client
exit(EXIT_FAILURE); // Exit the client process with an failure status and return to the parent
}
}
/*******************************************************************************
* Description: receive_file_text function
* Function receives the socket information (int) and either the file character
* arrays of plain or key files. It loads the content information onto a
* character array 1000 characters and appends that information to the end of the
* final text character array.
*******************************************************************************/
void receive_file_text(int establishedConnectionFD, char* file){
char text[MAX_MSG_SIZE]; // Establish a character array to store the fill Message
memset(text, '\0', MAX_MSG_SIZE); // Clear the array and set all elements to null
char tmp_buffer[MSG_BUFFER]; // Establish a character array to store temporary messages segements
do { // While we have not received the termination signal
memset(tmp_buffer, '\0', MSG_BUFFER); // Clear the array for the temporary message buffer and set all elements to null
strncpy(tmp_buffer, receive_message(establishedConnectionFD), MSG_BUFFER); // Copy the received message into the temporary message buffer
if(strcmp(tmp_buffer, TERM_SIG) != 0) { // If the message was not the termination signal
strcat(text, tmp_buffer); // Append the temp buffer to the end of the full text character array
send_message(establishedConnectionFD, "Message was RECEIVED"); // Send confirmation to the client that message was received
} else { // Otherwise
send_message(establishedConnectionFD, "TERM_SIG was RECEIVED"); // Send message to client that the termination signal was received
}
} while(strcmp(tmp_buffer, TERM_SIG) != 0); // Continue until we have received the termination signal
strncpy(file, text, MAX_MSG_SIZE); // Copy the final string to the passed file character array
}
/*******************************************************************************
* Description: encryption function
* Function receives the key and plain text information to create an encrypted
* ciphertext. The ciphertext is sent to the client over the network.
*******************************************************************************/
void encryption(int establishedConnectionFD, char* plain, char* key) {
int i = 0, // Establish an integer variable for loop counter
number = 0, // Establish an integer variable to store the number
plain_encryption = 0, // Establish an integer variable to store the plain text encryption value
key_encryption = 0; // Establish an integer variable to store the key text encryption value
char ciphertext[strlen(plain) + 1]; // Establish a character array to store the ciphertext
memset(ciphertext, '\0', strlen(plain) + 1); // Initialize the ciphertext array and set all elements to null
for(i = 0; i < strlen(plain); i++) { // Loop through each character in the key an plain text array
plain_encryption = (int)plain[i]; // the ascii integer value of the current plain text array element is stored
key_encryption = (int)key[i]; // the ascii integer value of the current key text array element is stored
if(plain_encryption == 32) { // If plain text character is a space (ASCII: 32)
plain_encryption = 64; // Reassign it to the lower bounds of the uppercase alphabet (ASCII: 64)
}
if(key_encryption == 32) { // If key text character is a space (ASCII: 32)
key_encryption = 91; // Reassign it to the upper bounds of the uppercase alphabet (ASCII: 91)
}
key_encryption -= 65; // Move Number back to standard alphabet values including space (1 - 27)
plain_encryption -= 65; // Move Number back to standard alphabet values including space (1 - 27)
number = plain_encryption + key_encryption; // Add the key and plain text values together and store
number %= 27; // Take the remainder of the number divided by the set value (27)
number += 65; // Move the number back to the ASCII range for capitalized letters
if (number == 91 || number == 64) { // Reconvert plain and key space values (ASCII: 91 and 64)
number = 32; // Back to the a space character (ASCII 32)
}
ciphertext[i] = (char)number; // Assign character value of the number to the current element in the ciphertext array
}
send_encryption(establishedConnectionFD, ciphertext); // Call function to send the ciphertext to the client
}
/*******************************************************************************
* Description: send_encryption function
* Function sends the encrypted ciphertext to the client. It will
* continually loop and send 1000 character messages until it reaches the end of
* the message string. Once finished, the function will send the termination
* characters of '!!'.
*******************************************************************************/
void send_encryption(int establishedConnectionFD, char* ciphertext) {
int sent = 0, // Establish an integer variable to store the total number of sent characters
i = 0; // Establish an integer variable to store the counter for the 1000 character message
char tmp_buffer[MSG_BUFFER]; // Establish a character array to store the 1000 character message segments
receive_message(establishedConnectionFD); // Receive message from client letting you know we can proceed sending file
while(sent < strlen(ciphertext)) { // While we have not sent all characters from the message string
i = 0; // Reset counter variable to zero
memset(tmp_buffer, '\0', sizeof(tmp_buffer)); // Reset the temporary message buffer and assign all element to null
while((i < MSG_BUFFER - 1) && (sent < strlen(ciphertext))) { // While we're less than the message buffer and have not reached the end of the message string
tmp_buffer[i] = ciphertext[sent]; // add the character to the temporary array from the original message
sent ++; // Increment the total number of sent characters
i ++; // Increment the counter toward the 1000 character limit
}
send_message(establishedConnectionFD, tmp_buffer); // Send the temporary message
receive_message(establishedConnectionFD); // Receive confirmation from the client
}
send_message(establishedConnectionFD, TERM_SIG); // Send termination signal to the client
receive_message(establishedConnectionFD); // Receive confirmation from the client
}
/*******************************************************************************
* Description: receive_message function
* Function is called to receive messages from the client. It receives the
* integer variable with the socket information. It has a buffer that stores
* the string produced from the recv() function. The buffer value is returned
* to the calling function.
*******************************************************************************/
char* receive_message(int establishedConnectionFD){
static char buffer[MSG_BUFFER]; // Establish a character string to capture received messages (1000 character capacity)
int charsRead = 0; // Establish an integer variable for storing the number of characters read
// Get the message from the client and display it
memset(buffer, '\0', MSG_BUFFER); // Clear the character array and set all elements to null
charsRead = recv(establishedConnectionFD, buffer, MSG_BUFFER, 0); // Read the client's message from the socket
if (charsRead < 0) { // If there was an error receiving the messages
fprintf(stderr, "ERROR: Failed reading from socket\n"); // Print an error message to stderr
close_connection(&establishedConnectionFD); // Close connection with the client
exit(EXIT_FAILURE); // Exit the client process with an failure status and return to parent
}
return buffer; // Return the received message to the calling function
}
/*******************************************************************************
* Description: send_message function
* Function is called to send messages to the client. It receives an integer
* variable containing the scoket infromation and a string containing the
* message. No returned variables
*******************************************************************************/
void send_message(int establishedConnectionFD, char* message) {
int charsRead = 0; // Establish an integer variable for storing the number of characters read
charsRead = send(establishedConnectionFD, message, strlen(message), 0); // Send the passed message to the client
if (charsRead < 0) { // If there was an error sending information
fprintf(stderr, "ERROR: Failed writing to socket\n"); // Print and error message to stderr
close_connection(&establishedConnectionFD); // Close the connection with the client
exit(EXIT_FAILURE); // Exit the child process with a failure status
}
if (charsRead < strlen(message)) { // If the number of characters sent was less than the received string length
fprintf(stderr, "WARNING: Not all data written to sockets\n"); // Print a warning to stderr but continue operations
}
}
/*******************************************************************************
* Description: check_processes function
* Funtion is called to check for processes that were forked off from the parent.
* When it finds a child pid that has terminated, it calls another function, to
* remove that process from the array and decrement the total number of running
* processes.
*******************************************************************************/
void check_processes(pid_t child_id, int child_exit, struct process_info* proc) {
while ((child_id = waitpid(-1, &child_exit, WNOHANG)) > 0) { // Call waipid function without hanging parent. Check for terminated background processes
remove_process(child_id, proc); // Call function to remove process from tracking structure
}
}
/*******************************************************************************
* Description: add_process function
* Function receives the process_info structure and a child_id pid. It searches
* the pid array for the matching child_id and adds that child id to the first
* available (null) element in the process array. Function also increments total
* number of processes once complete.
*******************************************************************************/
void add_process(pid_t child_id, struct process_info* proc) {
int i = 0; // Establishes integer variable for counter
for(i = 0; i < MAX_PROCESSES; i ++) { // Loops through each element of the structure process array
if(proc->processes[i] == '\0'){ // If the current element in the array matches the received child id
proc->processes[i] = child_id; // Assign the child id to that element in the array
proc->active ++; // Increment the total number of processes that are running
break; // Break the loop once we've found what we're looking for
}
}
}
/*******************************************************************************
* Description: remove_process function
* Function receives the process_info structure and a child_id pid. It searches
* the pid array for the matching child_id and removes that element (replaces
* with a null value). Function also decrements total number of processes once
* complete.
*******************************************************************************/
void remove_process(pid_t child_id, struct process_info* proc) {
int i = 0; // Establishes integer variable for counter
for(i = 0; i < MAX_PROCESSES; i ++) { // Loops through each element of the structure process array
if(proc->processes[i] == child_id){ // If the current element in the array matches the received child id
proc->processes[i] = '\0'; // Remove that child id and reassign the element to null
proc->active --; // Decrement the total number of processes that are running
break; // Break the loop once we've found what we're looking for
}
}
}
/*******************************************************************************
* Description: close_connection function
* Function is called to closed the connection with the client. It receives
* an integer pointer to the socket information.
*******************************************************************************/
void close_connection(int* establishedConnectionFD) {
close(*establishedConnectionFD); // Close the existing socket which is connected to the client
}
/*******************************************************************************
* Description: close_listen_socket function
* Function receives an integer pointer to the listening socket information and
* passes it to the close() function to terminate the socket.
*******************************************************************************/
void close_listen_socket(int* listenSocketFD) {
close(*listenSocketFD); // Close the listening socket
}
/*******************************************************************************
* Description: error function
* Error function is used to write messages to perror and terminate the program.
* It receives a character array containing the message to pass to the perror
* function.
*******************************************************************************/
void error(const char *msg) {
perror(msg); // Error function used for reporting issues
exit(EXIT_FAILURE); // Exit Program with failure status
}