SlideShare a Scribd company logo
1 of 37
Download to read offline
Abstract
The purpose of this project was to create a peer to peer server that was capable of
registering content, deregistering content, and downloading content from a peer that is able to be
both a server and a peer at the same time. The motivation for the implementation of this project
was to familiarize with socket programming and TCP communication channels. The approach
towards this project was to first create and implement a working server, then to create and
implement a working client that was able to connect and send requests to the server. The results
obtained was that when the server used processes, although nothing was shared between the
clients or processes, the server and client was able to execute and handle all required commands.
But when the server implemented threads, the connection between the server and client causes
the server to reach a segmentation fault and crash, where this was fixed by using a function from
a separate C library to allocate the index integer. From the results shown, it can be seen that
processes can be implemented easily, but processes lack utilities. On the other hand threads are
more complex to implement, but thread contain much more utilities than processes.
1. Introduction
What is a socket? A socket is one of the end points in a peer to peer server connection,
this connection is also known as a point to point server connection. The socket allows programs
to have a two way connection with another program running on a network connection. The
process of programming a socket to establish a two way connection between two programs on a
network is known as socket programming. There are two main types of connections, or
communication channels, in existence today, one is known as TCP, the other is known as UDP.
The TCP connection allows and provides a reliable communication channel that allows a peer to
peer or point to point connection over a network, such as the internet. The TCP connection is set
up by having each program, which wants to communicate through a network, bind a socket to the
end of their connection, then read and write from the bound socket to communicate with other
programs. In this project, the TCP connection type was used to establish the connections between
the peers and the server.
The objective of this project was to implement a peer to peer server connection between
at least two peers and a central server. The central server was required to be able to accept
content registration requests from the peers and register the peers’ requested contents into a
central storage of addresses and content names. The server was also required to be able to accept
content search requests, content de-registration requests, and list of online registration content
requests. These commands from the peer to the server are given in the form of PDUs. PDUs are a
byte of data that was concatenated to the front of the content data. This byte of data is known as
the header, this header was used to differentiate the different types of data being sent to and from
the server. These different data types are defined and shown in table 1.
Table 1: PDU Types
2. Implementation and Specifications
The specifications for this project were to have a working peer to peer server that was
composed of a central server, and at least two working clients. The server required for this
project was required to be able to remain open and wait for clients or peers to connect. After a
client or peer connects, the server was required to be able to listen for input commands from the
clients or peers. The commands that the server is required to listen for are the register content
command, content search command, content de-register command, list of online registration
content command, and the content download command. These commands each have a type
header that is one byte long in size and concatenated to the beginning of each data word being
sent over the network. These data type headers are shown in table 1, the server must be able to
decode these data types and perform the required action to the attached data according to the
command specified by the header byte. When the “R” PDU type is received, the server was
required to register the content name, which was given together with the “R” PDU type, and the
contents’ address, which was also given together with the “R” PDU type. When the server
receives the “D” PDU type, the server was required to first conduct a search through the
registered contents, then upon finding the registered content requested by the name given with
the “D” type, the server will then send back the address and port number of the requested
contents back to the client or peer that requested for it. When the server receives the “S” PDU
type, the server was required to conduct a search through the contents register with the given
name and sends back information stating if the content exists or not back to the client or peer that
requested the search. When the server receives the “T” PDU type, the server was required to de-
register, or delete, all contents requested to be erased by the client or peer. When the server
receives the “O” PDU type, the server was required to send back a list of all the registered
contents back to the client or peer that requested such an item.
The client required for this project was required to have the ability to both be a server and
a client simultaneously. The client is doubled as a server for the client is responsible for their
own data contents and must be able to handle download requests from other peers. The client
must be able to allow the user of the client program to be able to register data contents, de-
register data contents, request for registered contents list, search for requested content, and to
download contents from another peer. When the user of the client program requests for content
registration, the client program must be able to concatenate the “R” PDU type as the header of
the data containing the content name and send the whole data to the server for processing. When
the user requests for a de-register of content, the client program must be able to concatenate the
“T” PDU type to the header of the content name and send the data with the header to the server
to complete the request. When the user requests for the registered contents list, the client
program must be able to concatenate the “O” PDU type to the data to be sent to the server as the
header, then send the data to the server to complete the request given by the user. When the user
uses the search command, the client program must be able to concatenate the “S” PDU type to
the data containing the requested content name as header, then send the data to the server to
determine if the requested content exists or not. When the user requests for a download, the
client program must first send a search request to the server using the search command to
determine the existence of the request contents, then after receiving the address and port number
of the location of the contents back from server, the client program must be able to establish a
connection with the peer that holds the content. After the client establishes the connection with
the peer that holds the requested contents, the client program must then send data with the header
PDU type “D” to begin the download process. The peer then must send back the content data
with the “D” header as well, to specify that the content being sent back is the actual content data
of the requested file.
The way that was used to implement the peer to peer server was to use socket
programming. The type of socket programming used was the TCP type. In the server program,
the server binds a socket to the local host IP address at either a predefined port number or a user
defined port number at the start of the program. The server program used threads to handle all
incoming client connections. The server was set to be able to handle five clients at a time.
The client program was programmed to have both the server code and the client code, for
the client needs to have the ability to be both the server and the peer. The peer was programmed
to use processes to handle the different sockets that exist in the peer program. The peer was
programmed to have a process handle the socket bound for server, another process to handle the
connection to the register server, and the last process to handle the socket bound for client to
client communication.
3. Observations and Analysis
From observing the code, the peer to peer server has troubles clearing the buffer used to
transfer the data and command headers. Where the buffer would not clear itself, even though it
was programmed to do so at the end of every command. The problem with the buffer not
clearing was that occasionally, the buffer would save a newline character and not erase it, thus all
new commands that arrives afterwards would be treated as invalid. The way found to bypass this
was to program the client to continuously inquire for a command while the buffer contained a
newline character. Another observation observed was that when the server was programmed
using processes, the content list between each processes was not shared. This was a problem
because when a peer registers a content, it was required for all the peers to be able to see the
registered content on the content list. But since processes do not share any variables or
structures, the content list for all processes were different, thus not shared and this was
absolutely not acceptable. The solution found to fix the unshared contents list was to introduce
threads to the program. Where instead of using processes to handle new connections in the
server, threads were used instead. This was mainly due to the fact that threads share global
variables of the parent, where processes do not.
From analyzing the implemented code, it was found that whenever the client requests for
a connection with the server, the server would accept the request, but due to an unknown error,
the server would reach a segmentation fault and shut down. It was speculated that one of the
variables created was reaching outside its boundaries, but the source has not yet been found. This
problem was introduced when threads were used for the server, thus it was believed that one of
the thread arrays were causing the segmentation fault. After strenuous research, it was found that
the index value used for the thread array was not allocated properly in the format that was
acceptable for the threads to use, thus resulting in the segmentation faults. The way used to fix
this error was to use the malloc() function on the integer used for the index of the threads array.
Another analysis made reviled that the buffer contained an unwanted newline character. This was
easily fixed by making adjustments to the while loop condition that the buffer was located in.
4. Conclusions
The current code now meets the specifications. The peers connected to the register server
are able to register their own files for other peers to download. When the peers request for the
registered contents list, all peers will see the same registered contents list which shows the names
of the contents and which peer registered the content. The peers are also able to download
contents from each other, and each peer is able to de-register the contents the said peer
registered. The client program also contains a quit command where the end user may close the
peer to his or her discretion as specified in the specifications. The server, once run, will stay
running forever until it is force closed, and the server is able to connect to peers, handle the
registration command, handle the de-registration command, and handle the registered contents
list command according to specifications. Thus both the client and server codes are working up
to specifications.
5. References
[1] Docs.oracle.com, (2014). Lesson: All About Sockets (The Java™ Tutorials > Custom
Networking). [online] Available at: https://docs.oracle.com/javase/tutorial/networking/sockets/
[Accessed 14 Nov. 2014].
6. Appendix
A. Client and Server Program Demo
first start server
izb@crunchbang:~/Dropbox/U/COE 768/lab6 File transfer project/project
final$ ./server 20000
then peer1
izb@crunchbang:~/Dropbox/U/COE 768/lab6 File transfer project/project
final/peer1$ ls
client o_canada
izb@crunchbang:~/Dropbox/U/COE 768/lab6 File transfer project/project
final/peer1$ cat o_canada
O Canada!
Our home and native land!
True patriot love in all thy sons command.
With glowing hearts we see thee rise,
The True North strong and free!
From far and wide,
O Canada, we stand on guard for thee.
God keep our land glorious and free!
O Canada, we stand on guard for thee.
O Canada, we stand on guard for thee.
izb@crunchbang:~/Dropbox/U/COE 768/lab6 File transfer project/project
final/peer1$ ./client localhost 20000
Enter name: peer1
Initializing P2P server.
'R' to register file.
'T' to deregister.
'D' to download.
'O' to list files available.
'Q' to exit.
>r
Enter file name to register: o_canada
File 'o_canada' registered.
'R' to register file.
'T' to deregister.
'D' to download.
'O' to list files available.
'Q' to exit.
>
then peer 2
izb@crunchbang:~/Dropbox/U/COE 768/lab6 File transfer project/project
final/peer2$ ls
client
izb@crunchbang:~/Dropbox/U/COE 768/lab6 File transfer project/project
final/peer2$ ./client localhost 20000
Enter name: peer2
Initializing P2P server.
'R' to register file.
'T' to deregister.
'D' to download.
'O' to list files available.
'Q' to exit.
>o
List:
o_canada by: peer1
'R' to register file.
'T' to deregister.
'D' to download.
'O' to list files available.
'Q' to exit.
>d
Enter file name to download: sassadf
File unavailable!
'R' to register file.
'T' to deregister.
'D' to download.
'O' to list files available.
'Q' to exit.
>d
Enter file name to download: o_canada
100 B of data received
100 B of data received
100 B of data received
23 B of data received
File 'o_canada' downloaded.
'R' to register file.
'T' to deregister.
'D' to download.
'O' to list files available.
'Q' to exit.
>
back to peer1
>
100 B of data sent
100 B of data sent
100 B of data sent
23 B of data sent
>t
Enter file name to de-register: o_canada
'R' to register file.
'T' to deregister.
'D' to download.
'O' to list files available.
'Q' to exit.
>
back to peer2
'R' to register file.
'T' to deregister.
'D' to download.
'O' to list files available.
'Q' to exit.
>o
List:
'R' to register file.
'T' to deregister.
'D' to download.
'O' to list files available.
'Q' to exit.
>q
izb@crunchbang:~/Dropbox/U/COE 768/lab6 File transfer project/project
final/peer2$ ls
client o_canada
izb@crunchbang:~/Dropbox/U/COE 768/lab6 File transfer project/project
final/peer2$ cat o_canada
O Canada!
Our home and native land!
True patriot love in all thy sons command.
With glowing hearts we see thee rise,
The True North strong and free!
From far and wide,
O Canada, we stand on guard for thee.
God keep our land glorious and free!
O Canada, we stand on guard for thee.
O Canada, we stand on guard for thee.
izb@crunchbang:~/Dropbox/U/COE 768/lab6 File transfer project/project
final/peer2$
B. Client Code
/* client.c
COE768 P2P project by Ionathan Zauritz and Yuming Guo */
#include <stdio.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/signal.h>
#include <stdlib.h>
#include <strings.h>
#include <arpa/inet.h>
#include <ifaddrs.h>
#include <unistd.h>
#define SERVER_TCP_PORT 18000 /* default port */
#define BUFLEN 101 /* buffer length */
#define MAX_PEERS 15 //max # of peers to download at the same time.
int clientToServer(int sd);
int download(char contName[], char ip[]);
int upload(int sd);
int getIp();
int p2pServer();
void r(char s[]);
void reaper(int sig);
char name[20];
char localIP[NI_MAXHOST];
int main(int argc, char **argv)
{
int n, i, bytes_to_read;
int sd, port;
struct hostent *hp;
struct sockaddr_in server;
char *host, *bp, rbuf[BUFLEN], sbuf[BUFLEN];
switch(argc){
case 2:
host = argv[1];
port = SERVER_TCP_PORT;
break;
case 3:
host = argv[1];
port = atoi(argv[2]);
break;
default:
fprintf(stderr, "Usage: %s host [port]n", argv[0]);
exit(1);
}
/* Create a stream socket */
if ((sd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
fprintf(stderr, "Can't creat a socketn");
exit(1);
}
bzero((char *)&server, sizeof(struct sockaddr_in));
server.sin_family = AF_INET;
server.sin_port = htons(port);
if (hp = gethostbyname(host))
bcopy(hp->h_addr, (char *)&server.sin_addr, hp->h_length);
else if ( inet_aton(host, (struct in_addr *) &server.sin_addr) ){
fprintf(stderr, "Can't get server's addressn");
exit(1);
}
/* Connecting to the server */
if (connect(sd, (struct sockaddr *)&server, sizeof(server)) == -1){
fprintf(stderr, "Can't connect n");
exit(1);
}
printf("Enter name: "); //as user for name
r(name); //reads name
for(i=0; i<20; i++){
if(name[i] == 'n'){
name[i] = '0';
break;
}
}
int pid = fork();
if(pid == 0){ //child
p2pServer();
}
else{ //parent
usleep(250000); //wait 0.25 seconds for p2p to initialize
clientToServer(sd);
close(sd);
}
return(0);
}
int clientToServer(int sd)//function for client to server
{
char sbuf[BUFLEN];
char option, opStr[20];
char contName[20];
int n, i;
while(1){
printf("nt'R' to register file.nt'T' to deregister.nt'D' to
download.nt'O' to list files available.nt'Q' to exit.nnt>");
do{
r(opStr);
option = opStr[0];
} while (option == 'n' || option == '0');
if(option == 'R' || option == 'r'){
do{
printf("Enter file name to register: ");
r(contName);
} while(contName[0] == 'n' || contName[0] == '0');
for(i=0; i<20; i++){
if(contName[i] == 'n'){
contName[i] = '0';
}
}
//check if file exists
FILE *p;
p=fopen(contName, "r");
if(p==NULL){
printf("File '%s' doesnt exist!n", contName);
fclose(p);
continue;
}
fclose(p);
getIp(); //gets local IP to send to server
//clear buffer
for(i=0; i<BUFLEN; i++){
sbuf[i] = '0';
}
sbuf[0] = 'R';
for(i=1; i<21; i++){
sbuf[i] = name[i-1];
sbuf[i+20] = contName[i-1];
sbuf[i+40] = localIP[i-1];
}
write(sd, sbuf, BUFLEN); /* send it out */
read(sd,sbuf, BUFLEN);
if(sbuf[0] == 'A'){printf("File '%s' registered.n",
contName);}
else if(sbuf[0] == 'E'){
char msg[BUFLEN-1];
for(i=0; i<BUFLEN-1; i++){
msg[i] = sbuf[i+1];
}
printf("Error! File '%s' not registered.n%sn", contName,
msg);
}
}
else if(option == 'T' || option == 't'){
do{
printf("Enter file name to de-register: ");
r(contName);
} while(contName[0] == 'n' || contName[0] == '0');
for(i=0; i<20; i++){
if(contName[i] == 'n'){
contName[i] = '0';
break;
}
}
//clear buffer
for(i=0; i<BUFLEN; i++){
sbuf[i] = '0';
}
sbuf[0] = 'T';
for(i=1; i<21; i++){
sbuf[i] = contName[i-1];
}
write(sd, sbuf, BUFLEN); /* send it out */
}
else if(option == 'D' || option == 'd'){
do{
printf("Enter file name to download: ");
r(contName);
} while(contName[0] == 'n' || contName[0] == '0');
for(i=0; i<20; i++){
if(contName[i] == 'n'){
contName[i] = '0';
break;
}
}
//clear buffer
for(i=0; i<BUFLEN; i++){
sbuf[i] = '0';
}
sbuf[0] = 'S';
for(i=0; i<20; i++){
sbuf[i+1] = contName[i];
}
write(sd, sbuf, BUFLEN); /* send it out */
read(sd,sbuf, BUFLEN);
if(sbuf[0] == 'S'){
char peerIp[20];
for(i=0; i<20; i++){
peerIp[i] = sbuf[i+1];
}
download(contName, peerIp);
}
else if(sbuf[0] == 'E'){
printf("File unavailable!n");
}
else{
printf("Unknown error!");
}
}
else if(option == 'O' || option == 'o'){
write(sd, "O", 2); /* send it out */
read(sd,sbuf, BUFLEN);
if(sbuf[0] == 'O'){
char list[BUFLEN-1];
for(i=0; i<BUFLEN-1; i++){
list[i] = sbuf[i+1];
}
printf("nList:n%sn", list);
}
else{printf("Error retriving list!");}
}
else if(option == 'Q' || option == 'q'){
close(sd);
return 0;
}
else{
printf("Invalid request!n");
}
}
close(sd);
return 0;
}
int download(char contName[], char ip[]){
int n, i, bytes_to_read;
int sd, port;
struct hostent *hp;
struct sockaddr_in server;
char *host, *bp, rbuf[BUFLEN], sbuf[BUFLEN];
host = ip;
port = SERVER_TCP_PORT; //atoi(argv[2]);
/* Create a stream socket */
if ((sd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
fprintf(stderr, "Can't creat a socketn");
exit(1);
}
bzero((char *)&server, sizeof(struct sockaddr_in));
server.sin_family = AF_INET;
server.sin_port = htons(port);
if (hp = gethostbyname(host))
bcopy(hp->h_addr, (char *)&server.sin_addr, hp->h_length);
else if ( inet_aton(host, (struct in_addr *) &server.sin_addr) ){
fprintf(stderr, "Can't get server's addressn");
exit(1);
}
/* Connecting to the server */
if (connect(sd, (struct sockaddr *)&server, sizeof(server)) == -1){
fprintf(stderr, "Can't connect n");
exit(1);
}
//clear buffer
for(i=0; i<BUFLEN; i++){
sbuf[i] = '0';
}
sbuf[0] = 'D';
strcat(sbuf, contName);
write(sd, sbuf, BUFLEN); // send file name/* send it out */
FILE *pk;
int k;
pk=fopen(contName,"w");
if(pk==NULL)
{
printf("error openning file");
return 1;
}
//clear buffer
for(i=0; i<BUFLEN; i++){
sbuf[i] = '0';
}
int rData = 0;
while(n=read(sd, sbuf, BUFLEN)){
if(sbuf[0] != 'C'){
printf("Download failed!nData received contains incorrect PDU
type!n");
fclose(pk);
close(sd);
return(1);
}
printf("%d B of data receivedn",strlen(sbuf));
for(i=1; i<strlen(sbuf); i++){
fprintf(pk, "%c", sbuf[i]);;
}
//clear buffer
for(i=0; i<BUFLEN; i++){
sbuf[i] = '0';
}
}
if(rData > 0){
printf("%d B of data receivedn",rData);
}
printf("File '%s' downloaded.n", contName);
fclose(pk);
close(sd);
return 0;
}
int p2pServer(){
printf("Initializing P2P server.n");
int sd, new_sd, client_len, port;
struct sockaddr_in server, client;
port = SERVER_TCP_PORT;
/* Create a stream socket */
if ((sd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
fprintf(stderr, "p2p server can't creat a socketn");
exit(1);
}
/* Bind an address to the socket */
bzero((char *)&server, sizeof(struct sockaddr_in));
server.sin_family = AF_INET;
server.sin_port = htons(port);
server.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(sd, (struct sockaddr *)&server, sizeof(server)) == -1){
fprintf(stderr, "p2p server can't bind name to socketn");
exit(1);
}
/* queue up to MAX_PEERS connect requests */
listen(sd, MAX_PEERS);
(void) signal(SIGCHLD, reaper);
printf("P2P server ready.n");
while(1) {
client_len = sizeof(client);
new_sd = accept(sd, (struct sockaddr *)&client, &client_len);
if(new_sd < 0){
fprintf(stderr, "p2p server can't accept client n");
exit(1);
}
switch (fork()){
case 0: /* child */
(void) close(sd);
exit(upload(new_sd));
default: /* parent */
(void) close(new_sd);
break;
case -1:
fprintf(stderr, "fork: error in p2p server.n");
}
}
}
/* upload - sends file*/
int upload(int sd)
{
char *bp, buf[BUFLEN];
int n, bytes_to_read;
//clear buffer
int i;
for(i=0; i<BUFLEN; i++){
buf[i] = '0';
}
n = read(sd, buf, BUFLEN); //buf is name of file
if(buf[0] != 'D'){
write(sd, "EInvalid PDU type!", 19); //send E
printf("Invalid PDU type!n");
return 1;
}
char fileName[20];
for(i=0; i<20; i++){
fileName[i] = buf[i+1];
}
FILE *t;
t=fopen(fileName, "r");
if(t==NULL){
printf("file open error");
write(sd, "EFile not found!n", BUFLEN);
fclose(t);
return 1;
}
char tmp = 'n';
unsigned char data[BUFLEN-1]={0};
int nread = -1;
while(nread != 0){
nread = 0;
//clear buffer
for(i=0; i<BUFLEN-1; i++){
buf[i+1] = '0';
data[i] = '0';
}
buf[0] = 'C';
//scan 100B from file
nread = fread(data,1,BUFLEN-2,t);
strcat(buf,data);
data[nread] = 'n';
for(i=0; i<nread; i++){
buf[i+1] = data[i];
}
if(nread < 1){break;}
write(sd, buf, BUFLEN);
printf("n%d B of data sent", nread+1);
}
fclose(t);
close(sd);
printf("nnt>");
return(0);
}
int getIp(){
struct ifaddrs *ifaddr, *ifa;
int family, s;
char host[NI_MAXHOST];
if (getifaddrs(&ifaddr) == -1) {
perror("getifaddrs");
exit(EXIT_FAILURE);
}
for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
family = ifa->ifa_addr->sa_family;
if (family == AF_INET) {
s = getnameinfo(ifa->ifa_addr, sizeof(struct sockaddr_in),
host, NI_MAXHOST, NULL, 0,
NI_NUMERICHOST);
if (s != 0) {
printf("getnameinfo() failed: %sn",
gai_strerror(s));
exit(EXIT_FAILURE);
}
// printf("<Interface>: %s t <Address> %sn", ifa-
>ifa_name, host); //this prints local ip addresses
}
}
int i;
for (i=0; i<NI_MAXHOST; i++){
localIP[i] = host[i];
}
return 0;
}
/* I created this function because I was having problems with the input
buffer */
void r(char s[]){
int s_size = 20;
char tmp = '0';
int i = 0;
while(tmp != 'n'){
tmp = getchar();
s[i] = tmp;
if(s[i] == 'n' || i >= s_size-1){
s[i] = '0';
return;
}
i++;
}
}
/* reaper */
void reaper(int sig)
{
int status;
while(wait3(&status, WNOHANG, (struct rusage *)0) >= 0);
}
C. Server Code
/* server.c - compile with -lpthread
COE768 P2P project by Ionathan Zauritz and Yuming Guo */
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/signal.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <strings.h>
#define SERVER_TCP_PORT 18000 /* default port */
#define BUFLEN 101 /* buffer length */
#define MAX_CONT 100 //max # of contents
#define MAX_PEERS 10 //max # of peers
void *connection(void *sdd);
void clearContent();
void reaper(int);
pthread_mutex_t mutex;// = PTHREAD_MUTEX_INITIALIZER;
char content[MAX_CONT][3][20]; //list of content 0-content name, 1-
address, 2-peer name. 20 char each.
int sdIndex[MAX_CONT]; //stores sd for connections
int main(int argc, char **argv)
{
int sd, new_sd, client_len, port;
struct sockaddr_in server, client;
switch(argc){
case 1:
port = SERVER_TCP_PORT;
break;
case 2:
port = atoi(argv[1]);
break;
default:
fprintf(stderr, "Usage: %d [port]n", argv[0]);
exit(1);
}
/* Create a stream socket */
if ((sd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
fprintf(stderr, "Can't creat a socketn");
exit(1);
}
/* Bind an address to the socket */
bzero((char *)&server, sizeof(struct sockaddr_in));
server.sin_family = AF_INET;
server.sin_port = htons(port);
server.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(sd, (struct sockaddr *)&server, sizeof(server)) == -1){
fprintf(stderr, "Can't bind name to socketn");
exit(1);
}
/* queue up to MAX_PEERS connect requests */
listen(sd, MAX_PEERS);
int iret[MAX_PEERS];
pthread_t thread[MAX_PEERS];
(void) signal(SIGCHLD, reaper);
clearContent(); //this clears content list
int i = 0;
while(1) {
if(i>=MAX_PEERS){break;}
client_len = sizeof(client);
new_sd = accept(sd, (struct sockaddr *)&client, &client_len);
if(new_sd < 0){
fprintf(stderr, "Can't accept client n");
exit(1);
}
//this fixes segmentation fault caused by passing "(void*) new_sd"
to thread
int* new_sdp = malloc( sizeof( *new_sdp )) ;
*new_sdp = new_sd ;
//create thread
iret[i] = pthread_create(&thread[i], NULL, connection, new_sdp);
if(iret[i] != 0){
printf("thread[%d] not generated!n", i);
}
i++;
}
}
void *connection(void *sdd)
{
int sd =* (int *) sdd;
char *bp, buf[BUFLEN];
int i, n, bytes_to_read;
char type; //stores PDU type
char data[BUFLEN-1]; //stores data
while(1){
//clear buffer
for(i=0; i<BUFLEN; i++){
buf[i] = '0';
}
n = read(sd, buf, BUFLEN); //receive request
if(n <= 0){break;} //exits loop if n == 0(disconnect), or n <
0(error)
type = buf[0]; //save PDU type requested
for(i=0; i<BUFLEN-1; i++){ //save data
data[i] = buf[i+1];
}
// options
//Content Registration
pthread_mutex_lock(&mutex);
if(type == 'R' || type == 'r'){
char tmpName[20];
int z = 0;
for(i=0; i<20; i++){
tmpName[i] = data[i+20];
}
for(i=0; i<MAX_CONT; i++){
if(strcmp(tmpName, content[i][0]) == 0){
z =1;
}
}
if(z == 0){
int x = -1; //for content index available
for(i=0; i<MAX_CONT; i++){ //find content index available
if(content[i][0][0] == '0'){
x = i;
break;
}
}
for(i=0; i<20; i++){ //load content list
if(x == -1){break;}//if list is full, exit loop
content[x][2][i] = data[i]; //name of peer
content[x][0][i] = data[i+20]; //name of content
content[x][1][i] = data[i+40]; //address
}
sdIndex[x] = sd;
//A/E
if(x == -1){ //content list is full
printf("Content list is full!n");
write(sd, "EContent list is full!", 23); //send E
}
else{ //if no error
write(sd, "A", 2); //send A
}
}
else{
printf("A file with this name is already registered!n");
write(sd, "EA file with this name is already registered!",
46); //send E
}
}
//Content Download
else if(type == 'D' || type == 'd'){
printf("Server doesn't send files!n");
continue; //jump to start of loop
}
//Search Content Server
else if(type == 'S' || type == 's'){
int ind = -1; //stores index
for(i=0; i<MAX_CONT; i++){ //to find index
if(strcmp(content[i][0], data) == 0){
ind = i;
break;
}
}
if(ind == -1){ //not found
printf("File requested not in list!n");
write(sd, "EFile requested not in list!", 29); //send E
}
else{
//clear buffer
for(i=0; i<BUFLEN; i++){
buf[i] = '0';
}
buf[0] = 'S';
strcat(buf, content[ind][1]);
write(sd, buf, BUFLEN);
}
}
//Content De-Registration
else if(type == 'T' || type == 't'){
for(i=0; i<MAX_CONT; i++){
if(strcmp(data,content[i][0]) == 0){
content[i][0][0] = '0';
sdIndex[i] = 0;
break;
}
}
}
//Content Data
else if(type == 'C' || type == 'c'){
printf("Server doesn't send data!n");
continue; //jump to start of loop
}
//List of On-Line Registration Content
else if(type == 'O' || type == 'o'){
for(i=0; i<BUFLEN; i++){
buf[i] = '0';
}
buf[0] = 'O';
for(i=0; i<MAX_CONT; i++){
if(content[i][0][0] == '0'){continue;} //skips if empty
strcat(buf, content[i][0]);
strcat(buf, "tby: ");
strcat(buf, content[i][2]);
if(i >= MAX_CONT-1){break;} // to skip the last 'n'
strcat(buf,"n");
}
write(sd, buf, BUFLEN);
}
//Acknowledgement
else if(type == 'A' || type == 'a'){
printf("Server should not receive acknowledgement!n");
}
//Error
else if(type == 'E' || type == 'e'){
printf("Error received!n");
}
else{
printf("Invalid PDU type!n");
write(sd, "EInvalid PDU type!", 19); //send E
}
pthread_mutex_unlock(&mutex);
} // loop ends here
pthread_mutex_lock(&mutex);
close(sd);
// this deletes from list every index that that was registered by this
sd
for(i=0; i<MAX_CONT; i++){
if(sdIndex[i] == sd){
content[i][0][0] = '0';
sdIndex[i] = 0;
}
}
pthread_mutex_unlock(&mutex);
}
void clearContent(){
int i;
for(i=0; i<MAX_CONT; i++){
content[i][0][0] = '0';
}
}
/* reaper */
void reaper(int sig)
{
int status;
while(wait3(&status, WNOHANG, (struct rusage *)0) >= 0);
}

More Related Content

What's hot

Vehicle monitoring and surveillance
Vehicle monitoring and surveillanceVehicle monitoring and surveillance
Vehicle monitoring and surveillance
jiju7172
 
Biometric Authentication Technology - Report
Biometric Authentication Technology - ReportBiometric Authentication Technology - Report
Biometric Authentication Technology - Report
Navin Kumar
 
Anti drowsy alarm for drivers
Anti drowsy alarm for driversAnti drowsy alarm for drivers
Anti drowsy alarm for drivers
Duc Nguyen Van
 
RFID Based Rotary Car Parking System
RFID Based Rotary Car Parking SystemRFID Based Rotary Car Parking System
RFID Based Rotary Car Parking System
ijtsrd
 
RFID based car parking system-final ver
RFID based car parking system-final verRFID based car parking system-final ver
RFID based car parking system-final ver
Debasis Nayak
 
rfid based traffic control system by using gsm
rfid based traffic control system by using gsmrfid based traffic control system by using gsm
rfid based traffic control system by using gsm
ramesh chatty
 

What's hot (20)

an atm with an eye
an atm with an eyean atm with an eye
an atm with an eye
 
IOT Based Smart Parking and Damage Detection Using RFID
IOT Based Smart Parking and Damage Detection Using RFIDIOT Based Smart Parking and Damage Detection Using RFID
IOT Based Smart Parking and Damage Detection Using RFID
 
Automatic engine locking system for drunken driver
Automatic engine locking system for drunken driverAutomatic engine locking system for drunken driver
Automatic engine locking system for drunken driver
 
Vehicle monitoring and surveillance
Vehicle monitoring and surveillanceVehicle monitoring and surveillance
Vehicle monitoring and surveillance
 
Biometric Authentication Technology - Report
Biometric Authentication Technology - ReportBiometric Authentication Technology - Report
Biometric Authentication Technology - Report
 
IoT based smart grid FYP for students
IoT based smart grid FYP for studentsIoT based smart grid FYP for students
IoT based smart grid FYP for students
 
Anti drowsy alarm for drivers
Anti drowsy alarm for driversAnti drowsy alarm for drivers
Anti drowsy alarm for drivers
 
EYE TRACKING BASED DRIVER DROWSINESS MONITORING AND WARNING SYSTEM
EYE TRACKING BASED DRIVER DROWSINESS MONITORING AND WARNING SYSTEMEYE TRACKING BASED DRIVER DROWSINESS MONITORING AND WARNING SYSTEM
EYE TRACKING BASED DRIVER DROWSINESS MONITORING AND WARNING SYSTEM
 
Report of Advance car security system major project
Report of Advance car security system major projectReport of Advance car security system major project
Report of Advance car security system major project
 
Face Detection Attendance System By Arjun Sharma
Face Detection Attendance System By Arjun SharmaFace Detection Attendance System By Arjun Sharma
Face Detection Attendance System By Arjun Sharma
 
RFID Based Rotary Car Parking System
RFID Based Rotary Car Parking SystemRFID Based Rotary Car Parking System
RFID Based Rotary Car Parking System
 
Online car parking reservation system ppt 9160262550 dinesh
Online car parking reservation system ppt   9160262550 dineshOnline car parking reservation system ppt   9160262550 dinesh
Online car parking reservation system ppt 9160262550 dinesh
 
Smart surveillance
Smart surveillanceSmart surveillance
Smart surveillance
 
Smart Street System
Smart Street SystemSmart Street System
Smart Street System
 
Intelligent Automatic Plant Irrigation System
Intelligent Automatic Plant Irrigation SystemIntelligent Automatic Plant Irrigation System
Intelligent Automatic Plant Irrigation System
 
Accident detection
Accident detection Accident detection
Accident detection
 
Automated Face Recognition System for Office Door Access Control Application
Automated Face Recognition System for Office Door Access Control Application Automated Face Recognition System for Office Door Access Control Application
Automated Face Recognition System for Office Door Access Control Application
 
High protection ATM system with fingerprint identification technology
High protection ATM system with fingerprint identification technologyHigh protection ATM system with fingerprint identification technology
High protection ATM system with fingerprint identification technology
 
RFID based car parking system-final ver
RFID based car parking system-final verRFID based car parking system-final ver
RFID based car parking system-final ver
 
rfid based traffic control system by using gsm
rfid based traffic control system by using gsmrfid based traffic control system by using gsm
rfid based traffic control system by using gsm
 

Similar to p2p project report

Web Technologies Notes - TutorialsDuniya.pdf
Web Technologies Notes - TutorialsDuniya.pdfWeb Technologies Notes - TutorialsDuniya.pdf
Web Technologies Notes - TutorialsDuniya.pdf
Raghunathan52
 
Web Technologies Notes - TutorialsDuniya.pdf
Web Technologies Notes - TutorialsDuniya.pdfWeb Technologies Notes - TutorialsDuniya.pdf
Web Technologies Notes - TutorialsDuniya.pdf
Raghunathan52
 
How a network connection is created A network connection is initi.pdf
How a network connection is created A network connection is initi.pdfHow a network connection is created A network connection is initi.pdf
How a network connection is created A network connection is initi.pdf
arccreation001
 
Pinterest like site using REST and Bottle
Pinterest like site using REST and Bottle Pinterest like site using REST and Bottle
Pinterest like site using REST and Bottle
Gaurav Bhardwaj
 

Similar to p2p project report (20)

CN UNIT V.pptx
CN UNIT V.pptxCN UNIT V.pptx
CN UNIT V.pptx
 
Lecture5 architecture styles.pdf
Lecture5 architecture styles.pdfLecture5 architecture styles.pdf
Lecture5 architecture styles.pdf
 
Www and http
Www and httpWww and http
Www and http
 
Web Technologies Notes - TutorialsDuniya.pdf
Web Technologies Notes - TutorialsDuniya.pdfWeb Technologies Notes - TutorialsDuniya.pdf
Web Technologies Notes - TutorialsDuniya.pdf
 
Web Technologies Notes - TutorialsDuniya.pdf
Web Technologies Notes - TutorialsDuniya.pdfWeb Technologies Notes - TutorialsDuniya.pdf
Web Technologies Notes - TutorialsDuniya.pdf
 
Web-Server & It's Architecture.pptx
Web-Server & It's Architecture.pptxWeb-Server & It's Architecture.pptx
Web-Server & It's Architecture.pptx
 
How a network connection is created A network connection is initi.pdf
How a network connection is created A network connection is initi.pdfHow a network connection is created A network connection is initi.pdf
How a network connection is created A network connection is initi.pdf
 
Advanced Web Design And Development BIT 3207
Advanced Web Design And Development BIT 3207Advanced Web Design And Development BIT 3207
Advanced Web Design And Development BIT 3207
 
Web technology
Web technologyWeb technology
Web technology
 
Webbasics
WebbasicsWebbasics
Webbasics
 
Chapter 3-Processes.ppt
Chapter 3-Processes.pptChapter 3-Processes.ppt
Chapter 3-Processes.ppt
 
Application layer protocols
Application layer protocolsApplication layer protocols
Application layer protocols
 
Web server
Web serverWeb server
Web server
 
0130225347
01302253470130225347
0130225347
 
Internet
InternetInternet
Internet
 
Application_layer.pdf
Application_layer.pdfApplication_layer.pdf
Application_layer.pdf
 
Advanced Java Topics
Advanced Java TopicsAdvanced Java Topics
Advanced Java Topics
 
Restful web services
Restful web servicesRestful web services
Restful web services
 
Pinterest like site using REST and Bottle
Pinterest like site using REST and Bottle Pinterest like site using REST and Bottle
Pinterest like site using REST and Bottle
 
Ch-1_.ppt
Ch-1_.pptCh-1_.ppt
Ch-1_.ppt
 

p2p project report

  • 1.
  • 2. Abstract The purpose of this project was to create a peer to peer server that was capable of registering content, deregistering content, and downloading content from a peer that is able to be both a server and a peer at the same time. The motivation for the implementation of this project was to familiarize with socket programming and TCP communication channels. The approach towards this project was to first create and implement a working server, then to create and implement a working client that was able to connect and send requests to the server. The results obtained was that when the server used processes, although nothing was shared between the clients or processes, the server and client was able to execute and handle all required commands. But when the server implemented threads, the connection between the server and client causes the server to reach a segmentation fault and crash, where this was fixed by using a function from a separate C library to allocate the index integer. From the results shown, it can be seen that processes can be implemented easily, but processes lack utilities. On the other hand threads are more complex to implement, but thread contain much more utilities than processes.
  • 3. 1. Introduction What is a socket? A socket is one of the end points in a peer to peer server connection, this connection is also known as a point to point server connection. The socket allows programs to have a two way connection with another program running on a network connection. The process of programming a socket to establish a two way connection between two programs on a network is known as socket programming. There are two main types of connections, or communication channels, in existence today, one is known as TCP, the other is known as UDP. The TCP connection allows and provides a reliable communication channel that allows a peer to peer or point to point connection over a network, such as the internet. The TCP connection is set up by having each program, which wants to communicate through a network, bind a socket to the end of their connection, then read and write from the bound socket to communicate with other programs. In this project, the TCP connection type was used to establish the connections between the peers and the server. The objective of this project was to implement a peer to peer server connection between at least two peers and a central server. The central server was required to be able to accept content registration requests from the peers and register the peers’ requested contents into a central storage of addresses and content names. The server was also required to be able to accept content search requests, content de-registration requests, and list of online registration content requests. These commands from the peer to the server are given in the form of PDUs. PDUs are a byte of data that was concatenated to the front of the content data. This byte of data is known as the header, this header was used to differentiate the different types of data being sent to and from the server. These different data types are defined and shown in table 1. Table 1: PDU Types 2. Implementation and Specifications The specifications for this project were to have a working peer to peer server that was composed of a central server, and at least two working clients. The server required for this project was required to be able to remain open and wait for clients or peers to connect. After a client or peer connects, the server was required to be able to listen for input commands from the clients or peers. The commands that the server is required to listen for are the register content command, content search command, content de-register command, list of online registration content command, and the content download command. These commands each have a type header that is one byte long in size and concatenated to the beginning of each data word being
  • 4. sent over the network. These data type headers are shown in table 1, the server must be able to decode these data types and perform the required action to the attached data according to the command specified by the header byte. When the “R” PDU type is received, the server was required to register the content name, which was given together with the “R” PDU type, and the contents’ address, which was also given together with the “R” PDU type. When the server receives the “D” PDU type, the server was required to first conduct a search through the registered contents, then upon finding the registered content requested by the name given with the “D” type, the server will then send back the address and port number of the requested contents back to the client or peer that requested for it. When the server receives the “S” PDU type, the server was required to conduct a search through the contents register with the given name and sends back information stating if the content exists or not back to the client or peer that requested the search. When the server receives the “T” PDU type, the server was required to de- register, or delete, all contents requested to be erased by the client or peer. When the server receives the “O” PDU type, the server was required to send back a list of all the registered contents back to the client or peer that requested such an item. The client required for this project was required to have the ability to both be a server and a client simultaneously. The client is doubled as a server for the client is responsible for their own data contents and must be able to handle download requests from other peers. The client must be able to allow the user of the client program to be able to register data contents, de- register data contents, request for registered contents list, search for requested content, and to download contents from another peer. When the user of the client program requests for content registration, the client program must be able to concatenate the “R” PDU type as the header of the data containing the content name and send the whole data to the server for processing. When the user requests for a de-register of content, the client program must be able to concatenate the “T” PDU type to the header of the content name and send the data with the header to the server to complete the request. When the user requests for the registered contents list, the client program must be able to concatenate the “O” PDU type to the data to be sent to the server as the header, then send the data to the server to complete the request given by the user. When the user uses the search command, the client program must be able to concatenate the “S” PDU type to the data containing the requested content name as header, then send the data to the server to determine if the requested content exists or not. When the user requests for a download, the client program must first send a search request to the server using the search command to determine the existence of the request contents, then after receiving the address and port number of the location of the contents back from server, the client program must be able to establish a connection with the peer that holds the content. After the client establishes the connection with the peer that holds the requested contents, the client program must then send data with the header PDU type “D” to begin the download process. The peer then must send back the content data with the “D” header as well, to specify that the content being sent back is the actual content data of the requested file. The way that was used to implement the peer to peer server was to use socket programming. The type of socket programming used was the TCP type. In the server program, the server binds a socket to the local host IP address at either a predefined port number or a user defined port number at the start of the program. The server program used threads to handle all incoming client connections. The server was set to be able to handle five clients at a time.
  • 5. The client program was programmed to have both the server code and the client code, for the client needs to have the ability to be both the server and the peer. The peer was programmed to use processes to handle the different sockets that exist in the peer program. The peer was programmed to have a process handle the socket bound for server, another process to handle the connection to the register server, and the last process to handle the socket bound for client to client communication. 3. Observations and Analysis From observing the code, the peer to peer server has troubles clearing the buffer used to transfer the data and command headers. Where the buffer would not clear itself, even though it was programmed to do so at the end of every command. The problem with the buffer not clearing was that occasionally, the buffer would save a newline character and not erase it, thus all new commands that arrives afterwards would be treated as invalid. The way found to bypass this was to program the client to continuously inquire for a command while the buffer contained a newline character. Another observation observed was that when the server was programmed using processes, the content list between each processes was not shared. This was a problem because when a peer registers a content, it was required for all the peers to be able to see the registered content on the content list. But since processes do not share any variables or structures, the content list for all processes were different, thus not shared and this was absolutely not acceptable. The solution found to fix the unshared contents list was to introduce threads to the program. Where instead of using processes to handle new connections in the server, threads were used instead. This was mainly due to the fact that threads share global variables of the parent, where processes do not. From analyzing the implemented code, it was found that whenever the client requests for a connection with the server, the server would accept the request, but due to an unknown error, the server would reach a segmentation fault and shut down. It was speculated that one of the variables created was reaching outside its boundaries, but the source has not yet been found. This problem was introduced when threads were used for the server, thus it was believed that one of the thread arrays were causing the segmentation fault. After strenuous research, it was found that the index value used for the thread array was not allocated properly in the format that was acceptable for the threads to use, thus resulting in the segmentation faults. The way used to fix this error was to use the malloc() function on the integer used for the index of the threads array. Another analysis made reviled that the buffer contained an unwanted newline character. This was easily fixed by making adjustments to the while loop condition that the buffer was located in. 4. Conclusions The current code now meets the specifications. The peers connected to the register server are able to register their own files for other peers to download. When the peers request for the registered contents list, all peers will see the same registered contents list which shows the names of the contents and which peer registered the content. The peers are also able to download contents from each other, and each peer is able to de-register the contents the said peer registered. The client program also contains a quit command where the end user may close the peer to his or her discretion as specified in the specifications. The server, once run, will stay running forever until it is force closed, and the server is able to connect to peers, handle the registration command, handle the de-registration command, and handle the registered contents
  • 6. list command according to specifications. Thus both the client and server codes are working up to specifications.
  • 7. 5. References [1] Docs.oracle.com, (2014). Lesson: All About Sockets (The Java™ Tutorials > Custom Networking). [online] Available at: https://docs.oracle.com/javase/tutorial/networking/sockets/ [Accessed 14 Nov. 2014].
  • 8. 6. Appendix A. Client and Server Program Demo first start server izb@crunchbang:~/Dropbox/U/COE 768/lab6 File transfer project/project final$ ./server 20000 then peer1 izb@crunchbang:~/Dropbox/U/COE 768/lab6 File transfer project/project final/peer1$ ls client o_canada izb@crunchbang:~/Dropbox/U/COE 768/lab6 File transfer project/project final/peer1$ cat o_canada O Canada! Our home and native land! True patriot love in all thy sons command. With glowing hearts we see thee rise, The True North strong and free! From far and wide, O Canada, we stand on guard for thee. God keep our land glorious and free! O Canada, we stand on guard for thee. O Canada, we stand on guard for thee. izb@crunchbang:~/Dropbox/U/COE 768/lab6 File transfer project/project final/peer1$ ./client localhost 20000 Enter name: peer1 Initializing P2P server. 'R' to register file. 'T' to deregister. 'D' to download. 'O' to list files available. 'Q' to exit.
  • 9. >r Enter file name to register: o_canada File 'o_canada' registered. 'R' to register file. 'T' to deregister. 'D' to download. 'O' to list files available. 'Q' to exit. > then peer 2 izb@crunchbang:~/Dropbox/U/COE 768/lab6 File transfer project/project final/peer2$ ls client izb@crunchbang:~/Dropbox/U/COE 768/lab6 File transfer project/project final/peer2$ ./client localhost 20000 Enter name: peer2 Initializing P2P server. 'R' to register file. 'T' to deregister. 'D' to download. 'O' to list files available. 'Q' to exit. >o List: o_canada by: peer1 'R' to register file. 'T' to deregister. 'D' to download. 'O' to list files available. 'Q' to exit.
  • 10. >d Enter file name to download: sassadf File unavailable! 'R' to register file. 'T' to deregister. 'D' to download. 'O' to list files available. 'Q' to exit. >d Enter file name to download: o_canada 100 B of data received 100 B of data received 100 B of data received 23 B of data received File 'o_canada' downloaded. 'R' to register file. 'T' to deregister. 'D' to download. 'O' to list files available. 'Q' to exit. > back to peer1 > 100 B of data sent 100 B of data sent 100 B of data sent 23 B of data sent >t Enter file name to de-register: o_canada 'R' to register file.
  • 11. 'T' to deregister. 'D' to download. 'O' to list files available. 'Q' to exit. > back to peer2 'R' to register file. 'T' to deregister. 'D' to download. 'O' to list files available. 'Q' to exit. >o List: 'R' to register file. 'T' to deregister. 'D' to download. 'O' to list files available. 'Q' to exit. >q izb@crunchbang:~/Dropbox/U/COE 768/lab6 File transfer project/project final/peer2$ ls client o_canada izb@crunchbang:~/Dropbox/U/COE 768/lab6 File transfer project/project final/peer2$ cat o_canada O Canada! Our home and native land! True patriot love in all thy sons command. With glowing hearts we see thee rise, The True North strong and free! From far and wide, O Canada, we stand on guard for thee.
  • 12. God keep our land glorious and free! O Canada, we stand on guard for thee. O Canada, we stand on guard for thee. izb@crunchbang:~/Dropbox/U/COE 768/lab6 File transfer project/project final/peer2$
  • 13. B. Client Code /* client.c COE768 P2P project by Ionathan Zauritz and Yuming Guo */ #include <stdio.h> #include <netdb.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <sys/signal.h> #include <stdlib.h> #include <strings.h> #include <arpa/inet.h> #include <ifaddrs.h> #include <unistd.h> #define SERVER_TCP_PORT 18000 /* default port */ #define BUFLEN 101 /* buffer length */ #define MAX_PEERS 15 //max # of peers to download at the same time. int clientToServer(int sd); int download(char contName[], char ip[]); int upload(int sd); int getIp(); int p2pServer(); void r(char s[]); void reaper(int sig); char name[20]; char localIP[NI_MAXHOST]; int main(int argc, char **argv)
  • 14. { int n, i, bytes_to_read; int sd, port; struct hostent *hp; struct sockaddr_in server; char *host, *bp, rbuf[BUFLEN], sbuf[BUFLEN]; switch(argc){ case 2: host = argv[1]; port = SERVER_TCP_PORT; break; case 3: host = argv[1]; port = atoi(argv[2]); break; default: fprintf(stderr, "Usage: %s host [port]n", argv[0]); exit(1); } /* Create a stream socket */ if ((sd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { fprintf(stderr, "Can't creat a socketn"); exit(1); } bzero((char *)&server, sizeof(struct sockaddr_in)); server.sin_family = AF_INET; server.sin_port = htons(port); if (hp = gethostbyname(host))
  • 15. bcopy(hp->h_addr, (char *)&server.sin_addr, hp->h_length); else if ( inet_aton(host, (struct in_addr *) &server.sin_addr) ){ fprintf(stderr, "Can't get server's addressn"); exit(1); } /* Connecting to the server */ if (connect(sd, (struct sockaddr *)&server, sizeof(server)) == -1){ fprintf(stderr, "Can't connect n"); exit(1); } printf("Enter name: "); //as user for name r(name); //reads name for(i=0; i<20; i++){ if(name[i] == 'n'){ name[i] = '0'; break; } } int pid = fork(); if(pid == 0){ //child p2pServer(); } else{ //parent usleep(250000); //wait 0.25 seconds for p2p to initialize clientToServer(sd); close(sd); }
  • 16. return(0); } int clientToServer(int sd)//function for client to server { char sbuf[BUFLEN]; char option, opStr[20]; char contName[20]; int n, i; while(1){ printf("nt'R' to register file.nt'T' to deregister.nt'D' to download.nt'O' to list files available.nt'Q' to exit.nnt>"); do{ r(opStr); option = opStr[0]; } while (option == 'n' || option == '0'); if(option == 'R' || option == 'r'){ do{ printf("Enter file name to register: "); r(contName); } while(contName[0] == 'n' || contName[0] == '0'); for(i=0; i<20; i++){ if(contName[i] == 'n'){ contName[i] = '0'; } } //check if file exists FILE *p; p=fopen(contName, "r");
  • 17. if(p==NULL){ printf("File '%s' doesnt exist!n", contName); fclose(p); continue; } fclose(p); getIp(); //gets local IP to send to server //clear buffer for(i=0; i<BUFLEN; i++){ sbuf[i] = '0'; } sbuf[0] = 'R'; for(i=1; i<21; i++){ sbuf[i] = name[i-1]; sbuf[i+20] = contName[i-1]; sbuf[i+40] = localIP[i-1]; } write(sd, sbuf, BUFLEN); /* send it out */ read(sd,sbuf, BUFLEN); if(sbuf[0] == 'A'){printf("File '%s' registered.n", contName);} else if(sbuf[0] == 'E'){ char msg[BUFLEN-1]; for(i=0; i<BUFLEN-1; i++){ msg[i] = sbuf[i+1]; } printf("Error! File '%s' not registered.n%sn", contName, msg); }
  • 18. } else if(option == 'T' || option == 't'){ do{ printf("Enter file name to de-register: "); r(contName); } while(contName[0] == 'n' || contName[0] == '0'); for(i=0; i<20; i++){ if(contName[i] == 'n'){ contName[i] = '0'; break; } } //clear buffer for(i=0; i<BUFLEN; i++){ sbuf[i] = '0'; } sbuf[0] = 'T'; for(i=1; i<21; i++){ sbuf[i] = contName[i-1]; } write(sd, sbuf, BUFLEN); /* send it out */ } else if(option == 'D' || option == 'd'){ do{ printf("Enter file name to download: "); r(contName); } while(contName[0] == 'n' || contName[0] == '0'); for(i=0; i<20; i++){ if(contName[i] == 'n'){
  • 19. contName[i] = '0'; break; } } //clear buffer for(i=0; i<BUFLEN; i++){ sbuf[i] = '0'; } sbuf[0] = 'S'; for(i=0; i<20; i++){ sbuf[i+1] = contName[i]; } write(sd, sbuf, BUFLEN); /* send it out */ read(sd,sbuf, BUFLEN); if(sbuf[0] == 'S'){ char peerIp[20]; for(i=0; i<20; i++){ peerIp[i] = sbuf[i+1]; } download(contName, peerIp); } else if(sbuf[0] == 'E'){ printf("File unavailable!n"); } else{ printf("Unknown error!"); } } else if(option == 'O' || option == 'o'){
  • 20. write(sd, "O", 2); /* send it out */ read(sd,sbuf, BUFLEN); if(sbuf[0] == 'O'){ char list[BUFLEN-1]; for(i=0; i<BUFLEN-1; i++){ list[i] = sbuf[i+1]; } printf("nList:n%sn", list); } else{printf("Error retriving list!");} } else if(option == 'Q' || option == 'q'){ close(sd); return 0; } else{ printf("Invalid request!n"); } } close(sd); return 0; } int download(char contName[], char ip[]){ int n, i, bytes_to_read; int sd, port; struct hostent *hp; struct sockaddr_in server; char *host, *bp, rbuf[BUFLEN], sbuf[BUFLEN];
  • 21. host = ip; port = SERVER_TCP_PORT; //atoi(argv[2]); /* Create a stream socket */ if ((sd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { fprintf(stderr, "Can't creat a socketn"); exit(1); } bzero((char *)&server, sizeof(struct sockaddr_in)); server.sin_family = AF_INET; server.sin_port = htons(port); if (hp = gethostbyname(host)) bcopy(hp->h_addr, (char *)&server.sin_addr, hp->h_length); else if ( inet_aton(host, (struct in_addr *) &server.sin_addr) ){ fprintf(stderr, "Can't get server's addressn"); exit(1); } /* Connecting to the server */ if (connect(sd, (struct sockaddr *)&server, sizeof(server)) == -1){ fprintf(stderr, "Can't connect n"); exit(1); } //clear buffer for(i=0; i<BUFLEN; i++){ sbuf[i] = '0'; } sbuf[0] = 'D';
  • 22. strcat(sbuf, contName); write(sd, sbuf, BUFLEN); // send file name/* send it out */ FILE *pk; int k; pk=fopen(contName,"w"); if(pk==NULL) { printf("error openning file"); return 1; } //clear buffer for(i=0; i<BUFLEN; i++){ sbuf[i] = '0'; } int rData = 0; while(n=read(sd, sbuf, BUFLEN)){ if(sbuf[0] != 'C'){ printf("Download failed!nData received contains incorrect PDU type!n"); fclose(pk); close(sd); return(1); } printf("%d B of data receivedn",strlen(sbuf)); for(i=1; i<strlen(sbuf); i++){ fprintf(pk, "%c", sbuf[i]);; } //clear buffer for(i=0; i<BUFLEN; i++){ sbuf[i] = '0';
  • 23. } } if(rData > 0){ printf("%d B of data receivedn",rData); } printf("File '%s' downloaded.n", contName); fclose(pk); close(sd); return 0; } int p2pServer(){ printf("Initializing P2P server.n"); int sd, new_sd, client_len, port; struct sockaddr_in server, client; port = SERVER_TCP_PORT; /* Create a stream socket */ if ((sd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { fprintf(stderr, "p2p server can't creat a socketn"); exit(1); } /* Bind an address to the socket */ bzero((char *)&server, sizeof(struct sockaddr_in)); server.sin_family = AF_INET; server.sin_port = htons(port); server.sin_addr.s_addr = htonl(INADDR_ANY); if (bind(sd, (struct sockaddr *)&server, sizeof(server)) == -1){
  • 24. fprintf(stderr, "p2p server can't bind name to socketn"); exit(1); } /* queue up to MAX_PEERS connect requests */ listen(sd, MAX_PEERS); (void) signal(SIGCHLD, reaper); printf("P2P server ready.n"); while(1) { client_len = sizeof(client); new_sd = accept(sd, (struct sockaddr *)&client, &client_len); if(new_sd < 0){ fprintf(stderr, "p2p server can't accept client n"); exit(1); } switch (fork()){ case 0: /* child */ (void) close(sd); exit(upload(new_sd)); default: /* parent */ (void) close(new_sd); break; case -1: fprintf(stderr, "fork: error in p2p server.n"); } } } /* upload - sends file*/ int upload(int sd)
  • 25. { char *bp, buf[BUFLEN]; int n, bytes_to_read; //clear buffer int i; for(i=0; i<BUFLEN; i++){ buf[i] = '0'; } n = read(sd, buf, BUFLEN); //buf is name of file if(buf[0] != 'D'){ write(sd, "EInvalid PDU type!", 19); //send E printf("Invalid PDU type!n"); return 1; } char fileName[20]; for(i=0; i<20; i++){ fileName[i] = buf[i+1]; } FILE *t; t=fopen(fileName, "r"); if(t==NULL){ printf("file open error"); write(sd, "EFile not found!n", BUFLEN); fclose(t);
  • 26. return 1; } char tmp = 'n'; unsigned char data[BUFLEN-1]={0}; int nread = -1; while(nread != 0){ nread = 0; //clear buffer for(i=0; i<BUFLEN-1; i++){ buf[i+1] = '0'; data[i] = '0'; } buf[0] = 'C'; //scan 100B from file nread = fread(data,1,BUFLEN-2,t); strcat(buf,data); data[nread] = 'n'; for(i=0; i<nread; i++){ buf[i+1] = data[i]; } if(nread < 1){break;} write(sd, buf, BUFLEN); printf("n%d B of data sent", nread+1); } fclose(t); close(sd); printf("nnt>");
  • 27. return(0); } int getIp(){ struct ifaddrs *ifaddr, *ifa; int family, s; char host[NI_MAXHOST]; if (getifaddrs(&ifaddr) == -1) { perror("getifaddrs"); exit(EXIT_FAILURE); } for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) { family = ifa->ifa_addr->sa_family; if (family == AF_INET) { s = getnameinfo(ifa->ifa_addr, sizeof(struct sockaddr_in), host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST); if (s != 0) { printf("getnameinfo() failed: %sn", gai_strerror(s)); exit(EXIT_FAILURE); } // printf("<Interface>: %s t <Address> %sn", ifa- >ifa_name, host); //this prints local ip addresses } } int i; for (i=0; i<NI_MAXHOST; i++){
  • 28. localIP[i] = host[i]; } return 0; } /* I created this function because I was having problems with the input buffer */ void r(char s[]){ int s_size = 20; char tmp = '0'; int i = 0; while(tmp != 'n'){ tmp = getchar(); s[i] = tmp; if(s[i] == 'n' || i >= s_size-1){ s[i] = '0'; return; } i++; } } /* reaper */ void reaper(int sig) { int status; while(wait3(&status, WNOHANG, (struct rusage *)0) >= 0); }
  • 29. C. Server Code /* server.c - compile with -lpthread COE768 P2P project by Ionathan Zauritz and Yuming Guo */ #include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <sys/signal.h> #include <sys/wait.h> #include <stdlib.h> #include <strings.h> #define SERVER_TCP_PORT 18000 /* default port */ #define BUFLEN 101 /* buffer length */ #define MAX_CONT 100 //max # of contents #define MAX_PEERS 10 //max # of peers void *connection(void *sdd); void clearContent(); void reaper(int); pthread_mutex_t mutex;// = PTHREAD_MUTEX_INITIALIZER; char content[MAX_CONT][3][20]; //list of content 0-content name, 1- address, 2-peer name. 20 char each. int sdIndex[MAX_CONT]; //stores sd for connections int main(int argc, char **argv) {
  • 30. int sd, new_sd, client_len, port; struct sockaddr_in server, client; switch(argc){ case 1: port = SERVER_TCP_PORT; break; case 2: port = atoi(argv[1]); break; default: fprintf(stderr, "Usage: %d [port]n", argv[0]); exit(1); } /* Create a stream socket */ if ((sd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { fprintf(stderr, "Can't creat a socketn"); exit(1); } /* Bind an address to the socket */ bzero((char *)&server, sizeof(struct sockaddr_in)); server.sin_family = AF_INET; server.sin_port = htons(port); server.sin_addr.s_addr = htonl(INADDR_ANY); if (bind(sd, (struct sockaddr *)&server, sizeof(server)) == -1){ fprintf(stderr, "Can't bind name to socketn"); exit(1); }
  • 31. /* queue up to MAX_PEERS connect requests */ listen(sd, MAX_PEERS); int iret[MAX_PEERS]; pthread_t thread[MAX_PEERS]; (void) signal(SIGCHLD, reaper); clearContent(); //this clears content list int i = 0; while(1) { if(i>=MAX_PEERS){break;} client_len = sizeof(client); new_sd = accept(sd, (struct sockaddr *)&client, &client_len); if(new_sd < 0){ fprintf(stderr, "Can't accept client n"); exit(1); } //this fixes segmentation fault caused by passing "(void*) new_sd" to thread int* new_sdp = malloc( sizeof( *new_sdp )) ; *new_sdp = new_sd ; //create thread iret[i] = pthread_create(&thread[i], NULL, connection, new_sdp); if(iret[i] != 0){ printf("thread[%d] not generated!n", i);
  • 32. } i++; } } void *connection(void *sdd) { int sd =* (int *) sdd; char *bp, buf[BUFLEN]; int i, n, bytes_to_read; char type; //stores PDU type char data[BUFLEN-1]; //stores data while(1){ //clear buffer for(i=0; i<BUFLEN; i++){ buf[i] = '0'; } n = read(sd, buf, BUFLEN); //receive request if(n <= 0){break;} //exits loop if n == 0(disconnect), or n < 0(error) type = buf[0]; //save PDU type requested for(i=0; i<BUFLEN-1; i++){ //save data data[i] = buf[i+1]; } // options //Content Registration pthread_mutex_lock(&mutex);
  • 33. if(type == 'R' || type == 'r'){ char tmpName[20]; int z = 0; for(i=0; i<20; i++){ tmpName[i] = data[i+20]; } for(i=0; i<MAX_CONT; i++){ if(strcmp(tmpName, content[i][0]) == 0){ z =1; } } if(z == 0){ int x = -1; //for content index available for(i=0; i<MAX_CONT; i++){ //find content index available if(content[i][0][0] == '0'){ x = i; break; } } for(i=0; i<20; i++){ //load content list if(x == -1){break;}//if list is full, exit loop content[x][2][i] = data[i]; //name of peer content[x][0][i] = data[i+20]; //name of content content[x][1][i] = data[i+40]; //address } sdIndex[x] = sd; //A/E if(x == -1){ //content list is full printf("Content list is full!n"); write(sd, "EContent list is full!", 23); //send E }
  • 34. else{ //if no error write(sd, "A", 2); //send A } } else{ printf("A file with this name is already registered!n"); write(sd, "EA file with this name is already registered!", 46); //send E } } //Content Download else if(type == 'D' || type == 'd'){ printf("Server doesn't send files!n"); continue; //jump to start of loop } //Search Content Server else if(type == 'S' || type == 's'){ int ind = -1; //stores index for(i=0; i<MAX_CONT; i++){ //to find index if(strcmp(content[i][0], data) == 0){ ind = i; break; } } if(ind == -1){ //not found printf("File requested not in list!n"); write(sd, "EFile requested not in list!", 29); //send E } else{ //clear buffer for(i=0; i<BUFLEN; i++){
  • 35. buf[i] = '0'; } buf[0] = 'S'; strcat(buf, content[ind][1]); write(sd, buf, BUFLEN); } } //Content De-Registration else if(type == 'T' || type == 't'){ for(i=0; i<MAX_CONT; i++){ if(strcmp(data,content[i][0]) == 0){ content[i][0][0] = '0'; sdIndex[i] = 0; break; } } } //Content Data else if(type == 'C' || type == 'c'){ printf("Server doesn't send data!n"); continue; //jump to start of loop } //List of On-Line Registration Content else if(type == 'O' || type == 'o'){ for(i=0; i<BUFLEN; i++){ buf[i] = '0'; } buf[0] = 'O'; for(i=0; i<MAX_CONT; i++){ if(content[i][0][0] == '0'){continue;} //skips if empty strcat(buf, content[i][0]);
  • 36. strcat(buf, "tby: "); strcat(buf, content[i][2]); if(i >= MAX_CONT-1){break;} // to skip the last 'n' strcat(buf,"n"); } write(sd, buf, BUFLEN); } //Acknowledgement else if(type == 'A' || type == 'a'){ printf("Server should not receive acknowledgement!n"); } //Error else if(type == 'E' || type == 'e'){ printf("Error received!n"); } else{ printf("Invalid PDU type!n"); write(sd, "EInvalid PDU type!", 19); //send E } pthread_mutex_unlock(&mutex); } // loop ends here pthread_mutex_lock(&mutex); close(sd); // this deletes from list every index that that was registered by this sd for(i=0; i<MAX_CONT; i++){ if(sdIndex[i] == sd){ content[i][0][0] = '0';
  • 37. sdIndex[i] = 0; } } pthread_mutex_unlock(&mutex); } void clearContent(){ int i; for(i=0; i<MAX_CONT; i++){ content[i][0][0] = '0'; } } /* reaper */ void reaper(int sig) { int status; while(wait3(&status, WNOHANG, (struct rusage *)0) >= 0); }