Question
In this lab, you will create a collection of three UDP programs, source.c, sink.c and gateway.c, so that the source sends a message of certain
In this lab, you will create a collection of three UDP programs, source.c, sink.c and gateway.c, so that the source sends a message of certain length along with a CRC to the gateway, which in turn forwards data to the sink. The gateway can randomly alter the message with certain probability. The sink will be responsible for checking the errors in the message using CRC. The sink simply prints the result to its screen, reporting either an error, or the message is received correctly. I list the tasks as multiple problems to help you solve the problem in pieces. You could do it in one step if you feel comfortable about your solution.
Create the trio source.c, gateway.c and sink.c so that the message is sent from the source to the sink, via the gateway. For now each of the three programs can print a simple message such as Message sent in xxx bytes. or Message received in xxx bytes.. Use UDP sockets so the programs don't have to be connection based. Use your assigned port numbers for the first two programs, and use port + 1000 for your third program.
source.c: sends a message of arbitrary, but valid length to a recipient.
source [gateway host name] [gateway port number], where
gateway host name is the symbolic name of the host where the gateway resides. gateway port number indicates the port where the receiver expects to receive datagrams.
gateway.c: receives a message from the source and forwards it to the sink. The gateway randomly alters a byte in the message with a given probability (e.g., 20 percent, or 0.2.)
gateway [gateway port number] [sink host] [sink port number], where gateway port number is the port number at which the gateway waits for client messages. sink host is the symbolic name of the sink host. sink port number is the port number at which the sink waits for messages from the gateway.
sink.c -- receives a message from the gateway and prints the length of the message.
sink [port number] where port number indicates the port where the receiver expects to receive data. The order of running the program should be sink first, then the gateway, then the source.
You can run all three programs on the same terminal by putting the first two programs to the background. In this part of the lab, no error checking is used, though you could have the sink to print the message, or the length of the message, or both to indicate the programs are working fine.
Sample Codes: client.c
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define MAXLINE 1024
int main(int argc,char **argv)
{
char *servInetAddr = "127.0.0.1";
int socketfd;
struct sockaddr_in sockaddr;
char recvline[MAXLINE], sendline[MAXLINE];
int n;
fd_set read_fds;
if(argc != 2)
{
printf("client
exit(0);
}
socketfd = socket(AF_INET,SOCK_STREAM,0);
// initial memory space for socketaddr struct
memset(&sockaddr,0,sizeof(sockaddr));
sockaddr.sin_family = AF_INET;
sockaddr.sin_port = htons(1091);
// Convert Internet address format from text to binary
inet_pton(AF_INET,servInetAddr,&sockaddr.sin_addr);
if((connect(socketfd,(struct sockaddr*)&sockaddr,sizeof(sockaddr))) < 0 )
{
printf("connect error %s errno: %d ",strerror(errno),errno);
exit(0);
}
/*
while (1){
printf("send message to server ");
// reads a line from the specified stream and stores it into the string pointed to by str.
fgets(sendline,1024,stdin);
if((send(socketfd,sendline,strlen(sendline),0)) < 0)
{
printf("send mes error: %s errno : %d",strerror(errno),errno);
exit(0);
}
else{
printf("success in sending message: %s", sendline);
recv(socketfd, recvline, MAXLINE, 0);
puts("Reply received ");
puts(recvline);
}
}
*/
while(1){
int fd_max = STDIN_FILENO;
/* Set the bits for the file descriptors you want to wait on. */
FD_ZERO(&read_fds);
FD_SET(STDIN_FILENO, &read_fds);
FD_SET(socketfd, &read_fds);
/* The select call needs to know the highest bit you set. */
if( socketfd > fd_max ) { fd_max = socketfd; }
/* Wait for any of the file descriptors to have data. */
if (select(fd_max + 1, &read_fds, NULL, NULL, NULL) == -1)
{
perror("select:");
exit(1);
}
/* After select, if an fd's bit is set, then there is data to read. */
if(FD_ISSET(socketfd, &read_fds))
{
/* There is data waiting on your socket. Read it with recv(). */
memset(recvline, 0, sizeof(recvline));
recv(socketfd, recvline, MAXLINE, 0);
puts("Reply received: ");
puts(recvline);
char command[] = "Goodbye";
if(strncmp(strtok(recvline, " "), command, strlen(command)) == 0){
close(socketfd);
exit(0);
}
}
if(FD_ISSET(STDIN_FILENO, &read_fds))
{
/* The user typed something. Read it fgets or something.
Then send the data to the server. */
fgets(sendline,1024,stdin);
if((send(socketfd,sendline,strlen(sendline),0)) < 0)
{
printf("send mes error: %s errno : %d",strerror(errno),errno);
exit(0);
}
}
}
}
Sample Code: server.c
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define MYPORT 1091 // the port users will be connecting to
#define BACKLOG 5 // how many pending connections queue will hold
#define BUF_SIZE 200
int fd_A[BACKLOG]; // accepted connection fd
int conn_amount; // current connection amount
//A structure which represents the messages to be stored for history. The struct is used here only
//to reduce the complexity of nesting a character array within a two-dimensional array and serves
//no further practical function.
struct mesString{
//An arbitrarily chosen maximum value of 1024 is set for the total length of all messages
//from a single given sender. The size of the strings must be dictated now so that an array
//of these objects can be created later.
char message[1024];
};
//Creates an array of message objects. The first axis represents the index of the source ID of a
//message, the second indicates the index of its destination.
struct mesString messageArr[5][5];
//Initializes the 2D array of messages.
void initialize(){
for(int i = 0; i < 5; i++)
for(int j = 0; j < 5; j++)
strcat(messageArr[i][j].message, "\0");
}
//A function which displays on the server-side the number of active clients and which indices they
//occupy.
void showclient(){
int i;
printf("client amount: %d ", conn_amount);
for (i = 0; i < BACKLOG; i++) {
printf("[%d]:%d ", i, fd_A[i]);
}
printf(" ");
}
//A function which fetches the ID in the input string, converts it to a long, and compares it
//against the active sockets to determine whether or not it is a
//valid recipient for the message. Returns the index of the correct file descriptor if it is valid,
//or -1 to signify it is invalid.
int checkMsg(char* token){
//Obtain the second piece of the message, the recipient ID.
token = strtok(NULL, " ");
char *ptr;
//Converts a string to a long, allowing for comparison between the string input and the int
//file descriptors.
long ret = strtol(token, &ptr, 10);
for(int i = 0; i < 5; i++)
if(fd_A[i] == ret)
return i;
//If the ID was not found, it must be invalid.
return -1;
}
//A function which fetches the message in the input string and directs it toward the recipient
//identified in checkMsg(char*).
void sendMsg(char* token, int index, int source, int recipient){
char* badID = "The specified ID is not valid. Use to find valid IDs.";
char* del = "The message has been successfully delivered.";
if(recipient != -1){
//Fetches the actual massage to be delivered, using newline as the delimiter to
//allow for spaces in the message.
token = strtok(NULL, " ");
//Adds the message to be sent to the running string in the message history array. A
//marker is added to the end of the string to signify where each message concludes.
strcat(messageArr[index][recipient].message, token);
strcat(messageArr[index][recipient].message, "---");
//Determines the size of string necesssary to hold the converted integer and
//converts the ID int into a string.
int size = snprintf(NULL, 0, "%d", source);
char* payload = malloc(size + strlen(token));
snprintf(payload, size + strlen(token), "%d", source);
//Formats the string as ID: message
strcat(payload, ": ");
strcat(payload, token);
//Sends the finished message to the specified recipient.
send(fd_A[recipient], payload, strlen(payload), 0);
//Reply to the sender to confirm delivery.
send(fd_A[index], del, strlen(del), 0);
}
//If the recipient is -1, the ID was not valid, and the sender must be notified.
else
send(fd_A[index], badID, strlen(badID), 0);
}
//A function which sends the message history between the given source client and the given
//destination client.
void history(int source, int destination){
//Create a string to hold all of the messages from the source to the destination ID.
char ret[1024] = "Messages from you: ";
//If either of the necessary message members is empty the program will crash if it attempts
//to use strtok() on it, thus the message members are checked before they are accessed.
if(strcmp(messageArr[source][destination].message, "\0") != 0){
char sourceStr[1024];
strcpy(sourceStr, messageArr[source][destination].message);
char* token = strtok(sourceStr, "---");
//Populate ret with the individual tokens
while(token != NULL){
strcat(ret, token);
strcat(ret, " ");
token = strtok(NULL, "---");
}
}
//Create a string to hold all of the messages from the destination ID to the source
char ret2[1024] = "Messages from destination: ";
if(strcmp(messageArr[destination][source].message, "\0") != 0){
char destStr[1024];
strcpy(destStr, messageArr[destination][source].message);
char* destToken = strtok(destStr, "---");
while(destToken != NULL){
strcat(ret2, destToken);
strcat(ret2, " ");
destToken = strtok(NULL, "---");
}
}
//Concatenate the two strings
strcat(ret, ret2);
//Send the finished string to the client
send(fd_A[source], ret, sizeof(ret), 0);
}
int main(void){
int sock_fd, new_fd; // listen on sock_fd, new connection on new_fd
struct sockaddr_in server_addr; // server address information
struct sockaddr_in client_addr; // connector's address information
socklen_t sin_size;
int yes = 1;
char buf[BUF_SIZE];
char buf_list[BUF_SIZE];
int ret;
int i,j;
char command1[] = "list";
char command2[] = "history";
char command3[] = "exit";
char command4[] = "msg";
initialize();
if ((sock_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("socket");
exit(1);
}
if (setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) {
perror("setsockopt");
exit(1);
}
server_addr.sin_family = AF_INET; // host byte order
server_addr.sin_port = htons(MYPORT); // short, network byte order
server_addr.sin_addr.s_addr = INADDR_ANY; // automatically fill with my IP
memset(server_addr.sin_zero, '\0', sizeof(server_addr.sin_zero));
if (bind(sock_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) {
perror("bind");
exit(1);
}
if (listen(sock_fd, BACKLOG) == -1) {
perror("listen");
exit(1);
}
printf("listen port %d ", MYPORT);
fd_set fdsr;
int maxsock;
struct timeval tv;
conn_amount = 0;
sin_size = sizeof(client_addr);
maxsock = sock_fd;
while (1) {
// initialize file descriptor set
FD_ZERO(&fdsr);
FD_SET(sock_fd, &fdsr);
// timeout setting
//tv.tv_sec = 30;
//tv.tv_usec = 0;
// add active connection to fd set
for (i = 0; i < BACKLOG; i++)
if (fd_A[i] != 0)
FD_SET(fd_A[i], &fdsr);
ret = select(maxsock + 1, &fdsr, NULL, NULL, &tv);
if (ret < 0) {
perror("select");
break;
} /*else if (ret == 0) {
printf("timeout ");
continue;
}*/
// check every fd in the set
for (i = 0; i < conn_amount; i++) {
if (FD_ISSET(fd_A[i], &fdsr)) {
ret = recv(fd_A[i], buf, sizeof(buf), 0);
if (ret <= 0) { // client close
printf("client[%d] close ", i);
close(fd_A[i]);
FD_CLR(fd_A[i], &fdsr);
fd_A[i] = 0;
} else { // receive data
if (ret < BUF_SIZE)
memset(&buf[ret], '\0', 1);
printf("client[%d] send:%s ", i, buf);
//Obtains the first piece of the transmission, the command.
char* token = strtok(buf, " ");
if(strncmp(token, command1, strlen(command1)) == 0){
strcpy(buf_list, "The active IDs are --- ");
for (j = 0; j < conn_amount; j++)
if(fd_A[j] != 0){
char c[4];
sprintf(c, "%d\t", fd_A[j]);
strcat(buf_list, c);
}
//Converts the file descriptor for the user's socket
//into a string, which is then sent with the ID list
//to indicate the user's ID.
char* mess = "Your socket ID: ";
strcat(buf_list, mess);
int size = snprintf(NULL, 0, "%d", fd_A[i]);
char* payload = malloc(size + strlen(buf_list));
snprintf(payload, size + strlen(buf_list), "%d", fd_A[i]);
strcat(buf_list, payload);
strcat(buf_list, " END");
send(fd_A[i], buf_list, strlen(buf_list), 0);
}
else if(strncmp(token, command2, strlen(command2)) == 0){
int destination;
token = strtok(NULL, " ");
char* ptr;
long ret = strtol(token, &ptr, 10);
bool found = 0;
for(int j = 0; j < 5; j++){
//if the given ID matches a flie descriptor
//and the user has not requested history
//with itself, the destination index has
//been found.
if(fd_A[j] == ret && fd_A[i] != ret){
destination = j;
found = 1;
break;
}
}
if(found == 1)
history(i, destination);
else if(found == 0){
char* invalID = "That is not a valid ID";
send(fd_A[i], invalID, strlen(invalID), 0);
}
}
//If the user wishes to quit, the appropriate socket must be
//closed.
else if(strncmp(token, command3, strlen(command3)) == 0){
strcpy(buf_list, "Goodbye");
send(fd_A[i], buf_list, strlen(buf_list), 0);
close(fd_A[i]);
FD_CLR(fd_A[i], &fdsr);
fd_A[i] = 0;
}
else if(strncmp(token, command4, strlen(command4)) == 0){
int recipient = checkMsg(token);
sendMsg(token, i, fd_A[i], recipient);
}
//If the command given did not match any of the correct
//strings, send the user a notice and list the valid
//commands.
else{
strcpy(buf_list, "Not a valid command. Commands are:
strcat(buf_list, " END");
send(fd_A[i], buf_list, strlen(buf_list), 0);
}
}
}
}
// check whether a new connection comes
if (FD_ISSET(sock_fd, &fdsr)) {
new_fd = accept(sock_fd, (struct sockaddr *)&client_addr, &sin_size);
if (new_fd <= 0) {
perror("accept");
continue;
}
// add to fd queue
if (conn_amount < BACKLOG) {
fd_A[conn_amount++] = new_fd;
printf("new connection client[%d] %s:%d ", conn_amount,
inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
if (new_fd > maxsock)
maxsock = new_fd;
}
else {
printf("max connections arrive, exit ");
send(new_fd, "bye", 4, 0);
close(new_fd);
break;
}
}
showclient();
}
// close other connections
for (i = 0; i < BACKLOG; i++)
if (fd_A[i] != 0)
close(fd_A[i]);
exit(0);
}
Step by Step Solution
There are 3 Steps involved in it
Step: 1
Get Instant Access to Expert-Tailored Solutions
See step-by-step solutions with expert insights and AI powered tools for academic success
Step: 2
Step: 3
Ace Your Homework with AI
Get the answers you need in no time with our AI-driven, step-by-step assistance
Get Started