Skip to content

Commit

Permalink
Merge pull request #28 from kshitizsaini113/Coding
Browse files Browse the repository at this point in the history
Coding
  • Loading branch information
kshitizsaini113 authored Oct 26, 2020
2 parents aaeaf98 + 11eb2af commit 68328f4
Show file tree
Hide file tree
Showing 8 changed files with 333 additions and 5 deletions.
6 changes: 5 additions & 1 deletion Project_Implementation/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ OBJECT_FILES=linkedlist/linkedlist.o \
networkgraph.o \
network_topology.o \
network.o \
cli_module.o
cli_module.o \
communication.o

main.sh:main.o ${OBJECT_FILES} LibCli/libcli.a
${COMPILER} ${COMPILER_FLAGS} main.o ${OBJECT_FILES} -o main.sh ${LIBS}
Expand All @@ -31,6 +32,9 @@ network.o:network.c
cli_module.o:cli_module.c
${CC} ${CFLAGS} -c -I . cli_module.c -o cli_module.o

communication.o:communication.c
${CC} ${CFLAGS} -c -I . communication.c -o communication.o

LibCli/libcli.a:
(cd LibCli; make)

Expand Down
12 changes: 8 additions & 4 deletions Project_Implementation/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,17 @@ Here, we are focusing on implementation of network graph and its functions in th

4) The file [network.c](network.c) contains the functional definations for the functions defined in [network.h](network.h) to assign network properties to our network. *Network constrains like IP, MAC and Loopback.*

5) The file [network_topology.c](network_topology.c) is used for creating network topologies.
5) The file [communication.h](communication.h) contains the public API defined to be used in the project.

6) The file [utils.h](utils.h) is used to define various structures.
6) The file [communication.c](communication.c) contains the functional definations for the functions defined in [communication.h](communication.h) to assign communication properties to our project.

7) The file [main.c](main.c) is used to call the functions.
7) The file [network_topology.c](network_topology.c) is used for creating network topologies.

8) Makefile is created to make the project compilation easy.
8) The file [utils.h](utils.h) is used to define various structures.

9) The file [main.c](main.c) is used to call the functions.

10) [Makefile](Makefile) is created to make the project compilation easy.

> LibCli - An external library is used to add the functionality of Command Line to the project and make the project more interactive. We often use Menu-driven programs but they fails when we have a huge functionality to implement. To overcome the challenge, we are using LibCli.
Expand Down
261 changes: 261 additions & 0 deletions Project_Implementation/communication.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,261 @@
#include "communication.h"
#include "networkgraph.h"
#include <sys/socket.h>
#include <pthread.h>
#include <netinet/in.h>
#include <memory.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <netdb.h>
#include <unistd.h>

static int _send_packet_out(int socket_file_descriptor, char *packet_data, unsigned int packet_size, unsigned int destignation_udp_port_number)
{
// Sends the packet to the specified IP and port.

int r_bytes;
struct sockaddr_in destignation_address;

struct hostent *host = (struct hostent *) gethostbyname("127.0.0.1");
// Search the host by the name 127.0.0.1
destignation_address.sin_family = AF_INET;
destignation_address.sin_port = destignation_udp_port_number;
destignation_address.sin_addr = *((struct in_addr *)host->h_addr);

r_bytes = sendto(socket_file_descriptor, packet_data, packet_size, 0, (struct sockaddr *)&destignation_address, sizeof(struct sockaddr));
// Sends the packet using sendto system API and returns the number of bytes sent.

return r_bytes;
}

static unsigned int udp_port_number = 40000;

static unsigned int get_next_udp_port_number()
{
// Returns a unique udp port number.

return udp_port_number++;
}

void initialize_udp_port_socket(network_node_t *network_node)
{
// Initializes the udp port socket for the network node.

network_node->udp_port_number = get_next_udp_port_number();
// Fetches a unique UDP port number.

int udp_socket_file_descriptor = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
// Creating a unique UDP Socket.
//
// AF_INET is an address family that is used to designate the type of addresses that
// socket can communicate with (in this case, Internet Protocol v4 addresses)
//
// SOCK_DGRAM is a datagram-based protocol.
// We send one datagram and get one reply and then the connection terminates.
//
// IPPROTO_UDP defined the protocols to be used for the UDP programming.

struct sockaddr_in node_address;
// The SOCKADDR_IN structure specifies a transport address and port for the AF_INET address family.

node_address.sin_family = AF_INET;
node_address.sin_port = network_node->udp_port_number;
node_address.sin_addr.s_addr = INADDR_ANY;
// INADDR_ANY is used when we don't need to bind a socket to a specific IP.
// When we use this value as the address when calling bind(),
// the socket accepts connections to all the IPs of the machine.

if(bind(udp_socket_file_descriptor, (struct sockaddr *)&node_address, sizeof(struct sockaddr)) == -1)
{
printf("ERROR: Socket binding failed for the network node %s\n", network_node->network_node_name);
return;
}
// bind function binds the socket to the address and port number specified in addr.

network_node->udp_socket_file_descriptor = udp_socket_file_descriptor;
// Assigns the created UDP file descriptor.
}


static char recieved_buffer[MAXIMUM_PACKET_BUFFER_SIZE];
static char send_buffer[MAXIMUM_PACKET_BUFFER_SIZE];

static void _packet_recieve(network_node_t *recieving_node, char *packet_with_aux_data, unsigned int packet_size)
{
// Used to segrigate header and the payload in the packet recieved.

char *recieving_interface_name = packet_with_aux_data;
network_interface_t *recieving_interface = get_network_node_interface_by_name(recieving_node, recieving_interface_name);

if(!recieving_interface)
{
printf("ERROR : Packet recieved on unknown network interface %s on network node %s\n", recieving_interface->interface_name, recieving_node->network_node_name);
return;
}

packet_recieve(recieving_node, recieving_interface, packet_with_aux_data + NETWORK_INTERFACE_NAME_SIZE, packet_size - NETWORK_INTERFACE_NAME_SIZE);
// Third argument is the actual data.
}


static void * _network_start_packet_reciever_thread(void *argument)
{
// The defined function will be executed by thread.
// Based on destignation port number, number in the echoed data recieved by our application,
// application hand over the data to destignation node.

network_node_t *network_node;
doublylinkedlist_t *current;

fd_set active_socket_file_descriptor, backup_socket_file_descriptor;
// Defining variables to store udp socket file descriptors.

int socket_max_file_descriptor = 0;
int bytes_recieved = 0;

network_graph_t *topology = (void *)argument;

int address_length = sizeof(struct sockaddr);

FD_ZERO(&active_socket_file_descriptor);
FD_ZERO(&backup_socket_file_descriptor);

struct sockaddr_in sender_Address;

ITERATE_DOUBLY_LINKED_LIST_BEGINING(&topology->network_node_list, current)
{
network_node = graph_glue_to_node(current);

if(!network_node->udp_socket_file_descriptor)
{
continue;
}
// Skips the node for which the file descriptor is not defined.

if(network_node->udp_socket_file_descriptor > socket_max_file_descriptor)
{
socket_max_file_descriptor = network_node->udp_socket_file_descriptor;
}
// Assigns the maximum file descriptor to another variable.

FD_SET(network_node->udp_socket_file_descriptor, &backup_socket_file_descriptor);

} ITERATE_DOUBLY_LINKED_LIST_END(&topology->network_node_list, current)
// Iterating over each node of the topology and add add each udp file descriptor of each node
// to the backup file descriptor in orfer to monitor them.

while(1)
{
// We need to listen for infinite time as the user can recieve the packet anytime.
memcpy(&active_socket_file_descriptor, &backup_socket_file_descriptor, sizeof(fd_set));
// Copying all the backup file descriptor to active.
select(socket_max_file_descriptor+1, &active_socket_file_descriptor, NULL, NULL, NULL);
// Select is a blocking system call.
// For all the present file descriptor, unless one is activated the system call will
// remain blocked.

// When the data is recieved we need to iterate over all of the data and process it.
ITERATE_DOUBLY_LINKED_LIST_BEGINING(&topology->network_node_list, current)
{
network_node = graph_glue_to_node(current);
// We will fetch a particular node from the graph.

if(FD_ISSET(network_node->udp_socket_file_descriptor, &active_socket_file_descriptor))
{
// Cecking if the file descriptor of the current node is active or not.
// If activated, we need to recieve the data on the specified node.
memset(recieved_buffer, 0, MAXIMUM_PACKET_BUFFER_SIZE);
bytes_recieved = recvfrom(network_node->udp_socket_file_descriptor, (char *)recieved_buffer, MAXIMUM_PACKET_BUFFER_SIZE, 0, (struct sockaddr *)&sender_Address, &address_length);
// Recieving the data from recvfrom API.

_packet_recieve(network_node, recieved_buffer, bytes_recieved);
// Processing the recieved packet.
}
} ITERATE_DOUBLY_LINKED_LIST_END(&topology->network_node_list, current)

}
}


void network_start_packet_reciever_thread(network_graph_t *network_topology)
{
// We will do this process using threads as we are required to listen to all the nodes
// of the network simultaneously. (Multithreading)
//
// pthread library is being used for multithreading support.
pthread_attr_t attribute;
pthread_t recieve_packet_thread;

pthread_attr_init(&attribute);
// Initialising pthread attribute.
pthread_attr_setdetachstate(&attribute, PTHREAD_CREATE_DETACHED);
// When a thread is created detached (PTHREAD_CREATE_DETACHED), its thread ID and
// other resources can be reused as soon as the thread terminates.

pthread_create(&recieve_packet_thread, &attribute, _network_start_packet_reciever_thread, (void *)network_topology);
// Creates a thread and uses the followinf function on thread creation.
}

int send_packet_out(char *packet, unsigned int packet_size, network_interface_t *network_interface)
{
// Node communicates by sending data to Node's port number with IP=127.0.0.1
int r_bytes=0;

network_node_t *sending_node = network_interface->attached_node;
network_node_t *neighbour_node = get_neighbour_node(network_interface);

if(!neighbour_node)
{
// Returns -1 in case no node is found to avoid errors as data can only be transfered
// between connecting nodes.
return -1;
}

unsigned int destignation_udp_port_number = neighbour_node->udp_port_number;

int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
// Creating a network udp socket.

if(sock < 0)
{
printf("ERROR : Sending Socket Creation failed, errorno = %d", errno);
return -1;
}

network_interface_t *other_interface = &network_interface->attached_link->interface1== \
network_interface?&network_interface->attached_link->interface2:&network_interface->attached_link->interface1;
// Checking which interface to send data to by checking the connected interface.

memset(send_buffer, 0, MAXIMUM_PACKET_BUFFER_SIZE);
// Clears the memory (removes garbage) from the send_buffer

char *packet_with_auxilarry_data = send_buffer;

strncpy(packet_with_auxilarry_data, other_interface->interface_name, NETWORK_INTERFACE_NAME_SIZE);
// Assigns header to the packet.

packet_with_auxilarry_data[NETWORK_INTERFACE_NAME_SIZE] = '\0';
// Terminates the packet header.

memcpy(packet_with_auxilarry_data + NETWORK_INTERFACE_NAME_SIZE, packet, packet_size);
// Assigns data to the packet.

r_bytes = _send_packet_out(sock, packet_with_auxilarry_data, packet_size + NETWORK_INTERFACE_NAME_SIZE, destignation_udp_port_number);
// Send the packet to the destignation.

close(sock);
// Closes the socket created.

return r_bytes;
}

int packet_recieve(network_node_t *network_node, network_interface_t *network_interface, char *packet, unsigned int packet_size)
{
// Entry point into data link layer from physical layer
// Represent the start of ingress journey of the packet start from here in TCP/IP Stack

printf("Message Recieved : %s, on node : %s, IIF: %s\n", packet, network_node->network_node_name, network_interface->interface_name);

return 0;
}
16 changes: 16 additions & 0 deletions Project_Implementation/communication.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#ifndef __COMMUNICATION__
#define __COMMUNICATION__

#define MAXIMUM_PACKET_BUFFER_SIZE 2048

typedef struct network_node_ network_node_t;
typedef struct network_interface_ network_interface_t;

int send_packet_out(char *packet, unsigned int packet_size, network_interface_t *network_interface);
// Defining API to send the network packet out of the interface.
// Accepting the packet is dependent on reciever end.

int packet_recieve(network_node_t *network_node, network_interface_t *network_interface, char *packet, unsigned int packet_size);
// Defining API used to recieve packet from the reciever.

#endif
11 changes: 11 additions & 0 deletions Project_Implementation/main.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#include "networkgraph.h"
#include "communication.h"
#include "LibCli/libcli.h"
#include <unistd.h>

extern network_graph_t *build_first_network_topology();
extern void initialize_network_cli();
Expand All @@ -9,6 +11,15 @@ int main(int argc, char **argv)
{
initialize_network_cli();
network_topology = build_first_network_topology();

sleep(3);

network_node_t *snode = get_network_node_by_node_name(network_topology, "router_0");
network_interface_t *oif = get_network_node_interface_by_name(snode, "eth0/0");

char msg[]="Hello, from Minor 1 project.";
send_packet_out(msg, strlen(msg), oif);

start_shell();
return 0;
}
4 changes: 4 additions & 0 deletions Project_Implementation/network_topology.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#include "networkgraph.h"
#include "communication.h"

extern void network_start_packet_reciever_thread(network_graph_t *network_topology);

network_graph_t * build_first_network_topology()
{
Expand Down Expand Up @@ -27,6 +29,8 @@ network_graph_t * build_first_network_topology()
network_node_set_interface_ip_address(router_2, "eth0/3", "30.1.1.1", 24);
network_node_set_interface_ip_address(router_2, "eth0/5", "40.1.1.1", 24);

network_start_packet_reciever_thread(network_topology_1);
// We will be iterating over UDP file descriptors of each node and we will listen on them.

return network_topology_1;
}
Expand Down
4 changes: 4 additions & 0 deletions Project_Implementation/networkgraph.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <memory.h>
// Including the required header files.

extern int initialize_udp_port_socket(network_node_t *network_node);

void insert_link_between_two_network_nodes(network_node_t *network_node1,
network_node_t *network_node2,
Expand Down Expand Up @@ -76,6 +77,9 @@ network_node_t * create_network_graph_node(network_graph_t *network_graph,
network_node->network_node_name[NETWORK_NODE_NAME_SIZE] = '\0';
// Assigns memory and name to the newly created node

initialize_udp_port_socket(network_node);
// Initialising the port setting on the time of graph creation.

initialize_node_network_properties(&network_node->node_network_properties);

initialize_doubly_linkedlist(&network_node->graph_glue);
Expand Down
Loading

0 comments on commit 68328f4

Please sign in to comment.