networking project

profilefanbu
project_1.zip

project 1/.DS_Store

__MACOSX/project 1/._.DS_Store

project 1/as1-crawler-grading.pdf

1

CPS 470/570: Computer Networks Assignment #1 Notes on Grading

Requirements for the implementation:

1. Must be able to connect to a GWebCache (specified at the command prompt using a URL

string host[:port][/path] where parts in [] are optional) and download a list of

active seed ultrapeers. Make sure to check that the status code of the response is 200 OK

and the protocol type in the first line of the response is indeed HTTP.

2. Must be able to use BFS to crawl the entire Gnutella network of ultrapeers starting from the seed list (each ultrapeer must be contacted no more than once, leaf nodes must not be

contacted at all). Make sure to check that the response begins with the correct string

compliant with the protocol (i.e., GNUTELLA/version statusCode statusText).

3. During the crawl, the program must record all found ultrapeers and their leaves into a set and then write it on disk at the end of the crawl (this set needs to contain unique elements

only).

4. The final version must support operation with N threads and crawls up to M contacted ul- trapeers, where both N and M are specified by the user in the command prompt (e.g. yao-

crawler.exe gwc1c.olden.ch.3557.nyud.net:8080/gwc/ 200 300000). For sim-

plicity, count each ultrapeer pulled from the BFS queue as “contacted.”

To avoid swapping to disk and showing unacceptably low performance in your report, check

that the total memory usage in Task Manager is well below your physical RAM size. You can

notice that something is wrong when increasing the number of threads beyond some threshold

(such as 2500) leads to significantly lower performance.

Requirements for the report:

1. Explain the structure of your code and what the crawler does. Document the various statistics of your crawl – the total number of ultrapeers found, how many of them were

responsive (accepted a connection), how many leaves were found, how long it took to

perform the crawl, the average rate of crawling responsive ultrapeers per second.

2. Experiment with 10-5000 threads and document performance improvement arising from using multiple threads (e.g., using such metrics as the delay needed to crawl a certain

number of ultrapeers or the average number of peers found per second).

3. Perform reverse DNS lookups on all obtained IP addresses and build a distribution of the number of users per domain (e.g., the domain of host.network.cox.com is cox.com;

that of network.amazon.co.uk is amazon.co.uk). The distribution should be sorted

from the most popular to the least popular domain. Discuss how many domains you ob-

served, list several top domains, and show the number of users in each. If there are many

domains, you can assign sequence numbers in the plot instead of using their full names.

See Figure 1(a) for an example.

4. Map all users to their countries (e.g., domain blah.fr belongs to France) and build a dis- tribution of how many users from each country are represented in your crawl. See

http://www.iana.org/cctld/cctld-whois.htm for a list of all valid country codes. Sort the

2

countries by the number of found peers. See Figure 1(b) for an example. Note: you can

treat 3-letter and 4-letter domains (e.g., .com, .net, .edu, .biz, .info) as country codes.

5. Plot the distribution of user-agents used by the contacted ultrapeers using a pie-chart. You should treat different versions of the same agent (e.g., LimeWire 5.22 and 5.21) as

different agents. Figure 1(c) serves as a general guideline.

0

20000

40000

60000

80000

100000

120000

140000

fr de be us pl ru

country code

u s e rs

f o

u n

d

BearShare

LimeWire

Morph

Gnucleous

Figure 1. Sample homework graphs.

The complete project includes: a complete multithreaded implementation accompanied by a

report. Submit the ZIP file (including the entire solution, readme file, and report) at isi-

dore.udayton.edu. Submit the hardcopy of your report.

Notes on grading:

a) If you copy any piece of code from other students, receive 0 points.

b) If your code does not compile, you will receive 0 points.

c) Final deductions: 1. (5 pts) Your program assumes a hard-coded IP address or host name of the cache. The

code must accept user-specified arguments “host:port/directory” in the command line,

where both port and directory are optional. The default port number is 80 and the default

directory is “/”. 2. (5 pts) Incorrect socket operations (e.g., problems with sin_addr, port number, recv()

loop, requests to Gnutella, NULL-termination of buffer – whatever has not been fixed

from part 1).

3. (10 pts) Incorrect identification of ultrapeers to be inserted into the BFS queue (e.g., incorrect parsing of response lists, no check for uniqueness), attempts to connect to

leaves, incorrect operations on queues (front, push, pop).

4. (15 pts) Your code does not check for status code 200 OK in the receive buffer when connecting to cache nodes or does not check for the correct format of Gnutella re-

sponses (i.e., the status line of the response must be compliant with Gnutella). The

parser must also accept Gnutella fields in any order, skip over extra spaces between

words, and ignore unknown/irrelevant fields.

5. (5 pts) Missing printout of debugging information, discovered peers are not saved in- to a file, saved peers do not include leaves, or there is repetition in the list of saved

users.

0

10000

20000

30000

40000

50000

60000

70000

80000

90000

100000

1 2 3 4 5

domain sequence number

u s

e rs

f o

u n

d

coxcable.com 90000

verizon.net 87000

sbc.com 46700

att.com 22000

tamu.edu 1800

3

6. (20 pts) Incorrect mutex synchronization, incorrect multi-threaded BFS logic, prob- lems with program termination (e.g., not all threads quit), infinite loops, deadlocks on

recv().

7. (5 pts) Memory problems (e.g., memory leaks, heap corruption, bad_alloc() debug as- sertions, overwriting of shared data structures).

8. (5 pts) Crashing or strange behavior when running with many threads or on multi- CPU computers. Be sure to test your submission with a wide set of GWebCaches.

9. (30 pts) Report does not discuss the requested topics or adequately explain collected statistics.

Common problems:

1. Submitted ZIP file does not contain a Visual Studio solution or some files are missing that prevent its compilation "as is."

2. Your full name is not present at the beginning of each .cpp and .h file. 3. Files do not start with your last name. 4. There is no README file describing how to run the code.

__MACOSX/project 1/._as1-crawler-grading.pdf

project 1/as1-crawler.pdf

1

CPS 470/570: Computer Networks Project #1 due 11:55 pm, 2/13/2017 (100 pts)

No late submission will be accepted

Receive 5 bonus points if turn in the complete work without errors at least one day before deadline

Receive an F for this course if any academic dishonesty occurs

1. Purpose This homework builds an understanding of the Application Layer, Winsock programming,

and multithreaded programming.

2. Description Using Winsock and Visual Studio .NET 2013, your goal is to create a Gnutella crawler that

discovers all currently present peers in the system. Your program will first contact a seed web-

server to acquire a set of initial ultrapeers, traverse the entire Gnutella network in the BFS order,

and then record the identities of found ultrapeers and their children (i.e., leaf nodes) in some text

file. Using this information, you will then analyze the collected data to answer several questions

about geographic and domain diversity of peers as well as popularity of individual user agents

(i.e., client software).

Requirements for the implementation:

1. Must be able to connect to a GWebCache (specified at the command prompt using a URL

string host[:port][/path] where parts in [] are optional) and download a list of

active seed ultrapeers. Make sure to check that the status code of the response is 200 OK

and the protocol type in the first line of the response is indeed HTTP.

2. Must be able to use BFS to crawl the entire Gnutella network of ultrapeers starting from the seed list (each ultrapeer must be contacted no more than once, leaf nodes must not be

contacted at all). Make sure to check that the response begins with the correct string

compliant with the protocol (i.e., GNUTELLA/version statusCode statusText).

3. During the crawl, the program must record all found ultrapeers and their leaves into a set and then write it on disk at the end of the crawl (this set needs to contain unique elements

only).

4. The final version must support operation with N threads and crawls up to M contacted ul- trapeers, where both N and M are specified by the user in the command prompt (e.g.,

crawler.exe gwc1c.olden.ch.3557.nyud.net:8080/gwc/ 200 300000). For sim-

plicity, count each ultrapeer pulled from the BFS queue as “contacted.”

Requirements for the report:

1. Explain the structure of your code and what the crawler does. Document the various sta- tistics of your crawl – the total number of ultrapeers found, how many of them were re-

sponsive (accepted a connection), how many leaves were found, how long it took to per-

form the crawl, the average rate of crawling responsive ultrapeers per second.

2. Experiment with 10-5000 threads and document performance improvement arising from using multiple threads (e.g., using such metrics as the delay needed to crawl a certain

number of ultrapeers or the average number of peers found per second).

2

3. Perform reverse DNS lookups on all obtained IP addresses and build a distribution of the number of users per domain (e.g., the domain of host.network.cox.com is cox.com;

that of network.amazon.co.uk is amazon.co.uk). The distribution should be sorted

from the most popular to the least popular domain. Discuss how many domains you ob-

served, list several top domains, and show the number of users in each. If there are many

domains, you can assign sequence numbers in the plot instead of using their full names.

See Figure 1(a) for an example.

4. Map all users to their countries (e.g., domain blah.fr belongs to France) and build a dis- tribution of how many users from each country are represented in your crawl. See

http://www.iana.org/cctld/cctld-whois.htm for a list of all valid country codes. Sort the

countries by the number of found peers. See Figure 1(b) for an example. Note: you can

treat 3-letter and 4-letter domains (e.g., .com, .net, .edu, .biz, .info) as country codes.

5. Plot the distribution of user-agents used by the contacted ultrapeers using a pie-chart. You should treat different versions of the same agent (e.g., LimeWire 5.22 and 5.21) as

different agents. Figure 1(c) serves as a general guideline.

0

20000

40000

60000

80000

100000

120000

140000

fr de be us pl ru

country code

u s e rs

f o

u n

d

BearShare

LimeWire

Morph

Gnucleous

Figure 1. Sample homework graphs.

Delivery schedule:

1. The first part is due on1/24/17, Tuesday: your code must be able to connect to Gnutella cache webservers specified in the command line, download the initial seed, parse it, and

print the entire seed list on the screen.

2. The second part is due on 2/7/17, Tuesday: your code must be able to crawl the network using N (as least 50) threads. You must have all proper data structures in place (i.e., the

BFS queue, the set of all found peers, and the set of visited ultrapeers) and be able to

write the results into a file. Print all debugging information on screen: where you are

sending connection requests, entire response headers, what you have parsed from the re-

sponse and action taken for each returned peer.

3. The third part is due on 2/13/17, 11:55PM, Monday: do DNS lookups and write the re- port.

3. Details The current Gnutella network has a two-tier structure briefly explained in class. Ultrapeers

are long-lived (i.e., reliable) nodes that form a communication network (i.e., graph) among them-

selves for routing requests and aggregating information about the files shared by their children.

Ultrapeers usually maintain up to 30 neighbors and up to 30 children. Leaves on the other hand

only attach to 1-2 ultrapeers and do not allow search requests originating from other nodes to

0

10000

20000

30000

40000

50000

60000

70000

80000

90000

100000

1 2 3 4 5

domain sequence number

u s

e rs

f o

u n

d

coxcable.com 90000

verizon.net 87000

sbc.com 46700

att.com 22000

udayton.edu 1800

3

pass through them. For more information, see http://en.wikipedia.org/wiki/Gnutella or section

2.6 of the textbook.

Gnutella peers communicate with each other using standardized handshake messages de-

scribed in http://rfc-gnutella.sourceforge.net/src/rfc-0_6-draft.html. A summary of relevant sec-

tions of the protocol are provided below.

3.1. Seed File

For BFS search, your program must initially know at least one ultrapeer that is currently alive

in the system. This information can be downloaded from certain web caches that record the ad-

dresses of well-know users. These caches, called GWebCaches, collect identities of certain

Gnutella ultrapeers and make them available to external clients through a web interface.

To collect bootstrap information, send an HTTP request (you can do this manually using any

browser) to a GWebCache such as http://gwebcaches.pongwar.com/gnutella.html. This page

contains URLs of GWebCaches such as

gwcrab.sarcastro.com:8001/

grant1026.dyndns.ws/skulls0.2.8/skulls.php

gwc1c.olden.ch.3557.nyud.net:8080/gwc/

where, for example, the first URL decodes as following: gwcrab.sarcastro.com is the

hostname, 8001 is the port number on which the server is listening, and / is the directory. To re-

trieve lists of ultrapeers from GWebCaches, you must append a special string to the server's URL

that specifies the name of your client and the required action. Examples:

gwcrab.sarcastro.com:8001/?client=udayton0.1&hostfile=1

grant1026.dyndns.ws/skulls0.2.8/skulls.php?client=udayton0.1&hostfile=1

gwc1c.olden.ch.3557.nyud.net:8080/gwc/?client=udayton0.1&hostfile=1

where client=udayton0.1 specifies the name of your P2P client (in this example uday-

ton0.1 is being used) and hostfile=1 requests that a list of online peers be provided in the re-

sponse. Replies from web caches are composed of tuples IP:port separated by line breaks \r\n:

86.17.112.42:23694\r\n

67.180.41.229:6346\r\n

where 86.17.112.42 is the IP address and 23694 is the decimal port number of the first peer.

To communicate with a GWebCache node, you first need to resolve its hostname to an IP

address and then initiate a TCP connection on the corresponding port (if no port is provided, the

default HTTP port is 80). After establishing a connection, you need to send a GET request for

the directory in question. For gwcrab.sarcastro.com:

GET /?client=udayton0.1&hostfile=1 HTTP/1.0\n

Host: gwcrab.sarcastro.com\n \n

and wait for a reply. Standard HTTP response headers will follow from the server:

HTTP/1.1 200 OK\n

4

Connection: close\n

Date: Thu, 1 Sep 2006 12:00:15\n

Server: Apache/1.3.0\n

Content-type: text/html\n

Content-length: 456\n

\n

86.17.112.42:23694\n

67.180.41.229:6346\n

See section 2.2.3 of the textbook for a detailed description of HTTP messages.

Notes: 1) new line character \n is sometimes accompanied by carriage return \r as in \r\n,

which depends on the server you contact; 2) some GWebCaches rate limit requests and will not

respond if contacted too frequently. For more details about bootstrapping in Gnutella, see

http://www.pam2004.org/papers/247.pdf.

3.2. Neighbor Lists

The latest Gnutella protocol provides a convenient interface for crawling. Each alive peer

must accept crawl requests and reply with a list of its neighbors' IDs. After a connection to a

Gnutella user is established, you can send a crawl request to the peer using a standard Gnutella

handshake:

GNUTELLA CONNECT/0.6\r\n

User-Agent: UDAYTON_CS_CRAWLER/1.0\r\n

X-Ultrapeer: False\r\n

Crawler: 0.1\r\n\r\n

Here, GNUTELLA CONNECT/0.6 is the Gnutella connection request specifying protocol version

0.6, User-Agent: UDAYTON_CS_CRAWLER/1.0 is the name of your client (can be an arbitrary

string in place of UDAYTON_CS_CRAWLER/1.0), X-Ultrapeer: False indicates that your client

wants to be viewed as a leaf node, and Crawler: 0.1 marks this message as a crawl request of

version 0.1.

Each field ends with a Windows-style line break \r\n and the whole message ends with an

empty line (i.e., double break \r\n\r\n). After sending a crawl request, your code needs to wait

for a reply from the crawled peer and then parse this response to find new peers.

3.3. Parsing Replies

Replies to Gnutella crawl requests are similar to requests you transmit:

GNUTELLA/0.6 200 OK\r\n

User-Agent: BearShare 5.2.1.2\r\n

Peers: 66.171.38.246:6346,70.61.68.76:6346\r\n

Leaves: 128.108.111.162:3559,128.108.111.148:2679\r\n

X-Try-Ultrapeers:72.199.169.34:6346,71.160.45.142:6346\r\n\r\n

In the first line, the peer replies with its Gnutella protocol version number and status code,

where 200 means OK, 503 means busy, and 593 means OK to be crawled. Each line of the re-

5

maining reply is in the form of field_name: field_value\r\n. Field User-Agent: specifies

the name and version of the client software (which is BearShare 5.2.1.2 in this case). Field

Peers: provides a list of neighboring ultrapeers, which are separated by commas (the same sepa-

rator applies to fields Leaves and X-Try-Ultrapeers). Field Leaves: contains a list of children

attached to this peer, which may be an empty set if the crawled peer is a leaf, and field X-Try-

Ultrapeers: is an optional field that contains additional ultrapeers that may be contacted (in-

clude these in your crawl).

Note that usually there is a space after the colon, but this is not always the case (e.g., in the

above example, X-Try-Ultrapeers: is not followed by a space). To accommodate multiple

spaces and other random formats, it is recommended that you skip all spaces and possibly tabs

following the colon. Also note that field names may be capitalized or occur in a different order

from the one shown above. Similarly, the reply message may contain fields unrelated to your

crawl, which you should simply ignore. To illustrate these points, additional examples follow

below. The first one is from a LimeWire ultrapeer:

GNUTELLA/0.6 593 Hi\r\n

User-Agent: LimeWire/4.9.23 (Pro)\r\n

X-Ultrapeer: true\r\n

Peers: 68.52.201.178:9812,69.244.250.162:6346\r\n

Leaves: 216.218.168.49:6346,128.108.151.7:6346\r\n

Here is a response from a LimeWire leaf:

GNUTELLA/0.6 593 Hi\r\n

User-Agent: LimeWire/4.9.7\r\n

X-Ultrapeer: false\r\n

Peers: 128.108.151.7:6346\r\n

Leaves:\r\n

It is also possible to receive the following reply with timestamps appended to each X-Try-

Hub ultrapeer:

GNUTELLA/0.6 503 Crawling a Leaf\r\n

User-Agent: morph500 5.2.2.1015 (GnucDNA 1.1.1.4)\r\n

Remote-IP: 128.194.135.83\r\n

X-Try-Ultrapeers: 24.124.51.119:3047\r\n

X-Try-Hubs: 81.248.122.225:20805 2006-08-24T13:33Z,81.242.228.37:5835

2006-08-24T13:33Z\r\n

Note that you should parse all responses (including the busy code) and use the returned list of

Peers and X-Try-Ultrapeers. If you intend to parse X-Try-Hubs: or other user-agent specific

fields, document the details of this step in your report.

3.4. Performance Issues

You may soon find that some peers are dead or behind firewalls, in which case your connec-

tion will fail after a lengthy timeout. To speed up the crawl, this homework requires that you use

multiple threads to work on the BFS queue. Each thread will pull one IP:port pair from the queue

and attempt to crawl the corresponding peer. After obtaining its neighbors and children, the

6

thread will have to check uniqueness of the found ultrapeers and then insert those that are unique

(i.e., not seen before) back in the BFS queue. You will thus need to use mutexes to synchronize

on updating shared data structures. The isidore.udayton.edu contains a sample file that uses two

threads and inter-thread synchronization during access to a shared array. Here is an example of

creating and using mutexes/semaphores:

#include <windows.h>

HANDLE mutex, semaphore;

// create a mutex not initially owned by anyone

mutex = CreateMutex (NULL, false, NULL);

// create a semaphore counting to 5 (allowing up to 5 concurrent events)

semaphore = CreateSemaphore (NULL, 0, 5, NULL);

// lock mutex

WaitForSingleObject (mutex, INFINITE);

<critical section>

// release mutex

ReleaseMutex (mutex);

// lock semaphore

WaitForSingleObject(semaphore, INFINITE);

<critical section>

// release semaphore by 1

ReleaseSemaphore (semaphore, 1, NULL); // release 1 thread

In addition, to avoid slowing down the user-interaction response time of your computer, you

should set all your threads to the lowest priority:

SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_LOWEST);

3.5. BFS Termination Issues

The BFS queue is a shared object that is written to by many threads and read from my many

threads as well. This is the classical producer-consumer problem in synchronization. The solu-

tion is outlined below using a combination of C++ and pseudo code. It uses a counting sema-

phore semaQ that is incremented each time an item is placed in the queue and locked before an

access to the queue is attempted. After the access is granted, all threads synchronize on a BFS

mutex before they modify the queue. Termination is signaled when the queue becomes empty

and no other thread is working:

HANDLE arr[] = {eventQuit, semaQ};

if (WaitForMultipleObjects (2, arr, false, INFINITE) == WAIT_OBJECT_0+1){

BFSmutex.lock();

active_threads ++; peer = Q.extract();

BFSmutex.unlock();

// crawl peer ... large delay here

BFSmutex.lock();

for (each new peer){

Q.insert(peer); visited.insert(peer);

ReleaseSemaphore(semaQ);

}

7

active_threads--;

if (Q.size() == 0 && active_threads == 0)

SetEvent (eventQuit);

BFSmutex.unlock();

}

else // quit event has been signaled

return;

3.6. Socket Issues

By default, Windows XP SP2 does not allow more than 5000 open sockets. If you experience

a problem with opening new sockets (i.e., calls to socket() fail), you can increase this limit using

the registry. There is a link on the course webpage to the documentation from Microsoft. Note:

this issue does not arise in Windows 2003 Server.

Another feature of Windows XP SP2 is that it limits the number of outbound connections to

10/second. There is a fix that modifies tcpip.sys to allow more connections per second (the link

is also provided on the course website). To achieve good performance, you will need to raise this

limit to about 500/second or more depending on how fast your code runs. Note: this issue does

not arise in Windows 2003 Server.

Reading from sockets is accomplished using this general algorithm:

char buf [512];

string s = ""; // empty initial string

do {

// wait to see if the socket has any data (see MSDN for description)

// set the timeout to 30 seconds

if (select (sock, ..., timeout) > 0) {

// leave one byte for NULL termination and get the data

bytes = recv(s, buf, 511, 0);

if (bytes == 0) // connection closed, all data received

break;

if (bytes == SOCKET_ERROR) {

closesocket(sock);

continue to the next peer;

}

buf[bytes] = 0; // NULL terminate buffer

s += buf; // append to the string

}

} while (true);

Finally, you may experience deadlocks inside recv() when the peer would not provide any

data and would not close the connection in response to your request. To avoid this possibility,

always use select() before attempting to read from a socket. See MSDN or a winsock tutorial on

the usage of this function.

8

3.7. Thread Issues

Starting too many threads may be difficult in 32-bit operating systems due to the large space

needed in the kernel to handle thread control data. It is recommended that you use a system with

at least 2 GB of RAM and a 64-bit operating system.

Here are several suggestions that will overcome problems with running out of thread memory

in the kernel (which usually manifests itself in calls to bad_alloc() with out-of-memory errors in

Debug mode). First, reduce the reserve stack size in the project using Visual Studio .NET 2005:

Project Properties->Linker->System->Stack Reserve Size = 65536

Second, use Windows Task Manager to see the number of threads actually running and make

your code report any errors returned from CreateThread to the user. To see the thread count per

process, use View->Select Columns in Task Manager.

3.8. Helpful Commands

For debugging purposes, use telnet <host> <port> to establish a TCP connection and test

HTTP or Gnutella commands manually. For example: telnet www.google.com 80

opens an HTTP connection to www.google.com on port 80. You can use a similar technique

to connect to Gnutella peers if their IP address and port number are known. To see what you are

typing on the screen, set the local echo to true by pressing Ctrl-] and typing set localecho fol-

lowed by two ENTER keys.

For information about your network configuration, use ipconfig at the command prompt (to

see the DNS servers, use ipconfig /all). To manually perform DNS lookups, use nslookup

host or nslookup IP at the command prompt.

3.9. Visual Studio STL

Learn how to use sets and queues in STL using MSDN. For example, you can use sets as an

easy way of storing unique elements and verifying whether additional elements belong to a set

(e.g., based on the observation that new elements increase set size, while duplicates do not):

#include <set>

using namespace std;

// Create an empty set s0 of key type integer

set <int> s0;

s0.insert(10); // set size 1

s0.insert(20); // set size 2

s0.insert(30); // set size 3

s0.insert(10); // set size 3, contains (10, 20, 30)

STL queues are similar:

9

#include <queue>

using namespace std;

queue<int> q;

q.push(10);

q.push(20);

q.push(30);

while (!q.empty())

{

int x = q.front();

printf("x = %d\n", x);

q.pop();

}

While the above examples store only elements of type int, your specific application will re-

quire elements that are classes of type Peer:

#pragma pack(push) // save current struct packing

#pragma pack(1) // align to 1-byte boundary

class Peer{

public:

DWORD IP; // 4-byte unsigned int defined in <windows.h>

unsigned short port;

};

#pragma pack(pop) // restore old packing

queue<Peer> q;

// inet_addr converts strings to 4-byte IP representations

Peer x = {inet_addr("128.194.135.100"), 2001},

y = {inet_addr("128.194.5.20"), 4089};

q.push(x);

q.push(y);

A similar approach applies to the set; however, you will need to define a comparison function

for class Peer so that STL can detect insertion of duplicate elements:

#pragma pack(push) // save current struct packing

#pragma pack(1) // align to 1-byte boundary

class Peer{

public:

DWORD IP; // 4-byte unsigned int defined in <windows.h>

unsigned short port;

// comparison operator for testing uniqueness

bool operator ()(Peer x, Peer y) {

return memcmp(&x, &y, sizeof(Peer))<0;

}

};

#pragma pack(pop) // restore old packing

set<Peer, Peer> s;

Peer x = {100, 200}, y = {200, 200}, *z = new Peer;

z->IP = 200; z->port = 200;

s.insert (x);

s.insert (y);

10

s.insert (*z);

s.insert (x); // set contains two elements (x,y)

delete z;

Repacking to 1 byte is mandatory for this code to work. Note: you cannot add STL structures

to the above class Peer since memcmp only works with scalar object types (you can write your

own comparison function, however).

3.10. DNS Lookup Issues

During the final phase of converting IPs into hostnames (by using standard getnamein-

fo() or gethostbyname() Winsock calls – getnameinfo is recommended), you may

generate a huge amount of traffic to your local DNS server (the default DNS server at my com-

puter is ns3.udayton.edu) and potentially crash it. This may lead to suspicion that you are per-

forming malicious activity and purposely trying to compromise network security. To find out

your local DNS server, go to the command prompt and type nslookup without any arguments.

To avoid complications, you should reset the DNS server of your own computer using one of

the following methods. You need administrator privileges to switch the DNS server.

Method 1 (the only choice for students who live on campus): go into Network Connec- tions->Local Area Connection (Properties)->Internet Protocol (TCP/IP) (Prop-

erties) and modify the field called “Preferred DNS server.” If you are using DHCP, move the

radio button from “Obtain DNS server address automatically” to “Use the following DNS server

addresses.” Set Preferred DNS server to 131.238.252.51. The UD helpdesk authorizes students in

CPS 470/570 to use this DNS server. Run the lookups slowly (space them out over a 2-day period).

The instructions of setting DNS servers for Windows Vista are slightly different. Check this

website https://www.opendns.com/start/device/windows-vista, or search Google to find out.

Method 2 (recommended for students who live off campus): you can install a free trial ver-

sion of Simple DNS Plus (http://www.simpledns.com). After you install the DNS server locally

at your computer and reset (see above) the DNS server to 127.0.0.1, getnameinfo will send

all lookup requests to your local server.

Method 3 (not recommended for students who live off campus, but a working method): you

can use the DNS servers at OpenDNS (http://www.opendns.com/) and set Preferred DNS server

to 208.67.222.222. In this case, you do not need to install any DNS server at your computer, but run the lookups slowly (space them out over a 2-day period).

Note: Do not run your code at CPS labs when you convert IPs into hostnames (Part 3).

To verify that DNS is working as intended, run nslookup at the command prompt.

3.11. Wireshark

Wireshark (http://www.wireshark.org/) is a software package that allows you to intercept all

packets sent and received by your computer. Wireshark allows you to diagnose implementation

problems encountered in this and other homework.

3.12. Debug vs. Release Mode

When using a large number of threads, always run your code in Release mode as it runs 50

times faster in STL functions and occupies 50% less memory. For scalar classes inserted into

11

STL sets, you can roughly estimate 60 bytes per entry in Debug mode and 30 bytes in Release

mode. If you insert other STL objects (such as strings) into a set, then count a minimum of 90

bytes per entry plus the length of the string in Debug mode and 55 bytes in Release mode.

Furthermore, to avoid swapping to disk and showing unacceptably low performance in your

report, check that the total memory usage in Task Manager is well below your physical RAM

size. You can notice that something is wrong when increasing the number of threads beyond

some threshold (such as 2500) leads to significantly lower performance.

__MACOSX/project 1/._as1-crawler.pdf

project 1/as1-helper-wireshark.pdf

1

CPS 470/570 Introduction to Wireshark

1. Purpose The goal of this lab is primarily to introduce you to Wireshark.

2. Description

2.1. Overview

In this lab, you will connect to our course website and observe the network protocols in your

computer “in action,” interacting and exchanging messages with protocol entities executing

elsewhere in the Internet. You will observe, and you will learn, by doing.

2.2. Details

a) Getting Wireshark

The basic tool for observing the messages exchanged between executing protocol entities is

called a packet sniffer. As the name suggests, a packet sniffer captures (“sniffs”) messages

being sent/received from/by your computer; it will also typically store and/or display the

contents of the various protocol fields in these captured messages. A packet sniffer itself is

passive. It observes messages being sent and received by applications and protocols running

on your computer, but never sends packets itself. Similarly, received packets are never

explicitly addressed to the packet sniffer. Instead, a packet sniffer receives a copy of packets

that are sent/received from/by application and protocols executing on your machine.

Figure 1 shows the structure of a packet sniffer. At the right of Figure 1 are the protocols (in

this case, Internet protocols) and applications (such as a web browser or ftp client) that

normally run on your computer. The packet sniffer, shown within the dashed rectangle in

Figure 1 is an addition to the usual software in your computer, and consists of two parts. The

packet capture library receives a copy of every packet that is sent from or received by your

computer. Recall from the discussion from section 1.5 in the text (Figure 1.24) that messages

exchanged by higher layer protocols such as HTTP, FTP, TCP, UDP, DNS, or IP all are

eventually encapsulated in link-layer frames that are transmitted over physical media such as

an Ethernet cable. In Figure 1, the assumed physical media is an Ethernet, and so all upper

layer protocols are eventually encapsulated within an Ethernet frame. Capturing all link-layer

frames thus gives you all messages sent/received from/by all protocols and applications

executing in your computer. The second component of a packet sniffer is the packet

analyzer, which displays the contents of all fields within a protocol message.

2

Figure 1. Packet sniffer structure

You will be using the Wireshark packet sniffer [http://www.wireshark.org/] for this lab,

allowing you to display the contents of messages being sent/received from/by protocols at

different levels of the protocol stack. In order to run Wireshark, you will go to

http://www.wireshark.org/download.html and download/install the Wireshark binary for your

computer. The Wireshark FAQ has a number of helpful hints and interesting tidbits of

information, particularly if you have trouble installing or running Wireshark.

b) Running Wireshark When you run the Wireshark program, the Wireshark graphical user interface shown in

Figure 2 will be displayed. Initially, no data will be displayed in the various windows.

Figure 2. Wireshark Graphical User Interface

3

The best way to learn about any new piece of software is to try it out! We’ll assume that

your computer is connected to the Internet via a wired Ethernet interface. Do the following

1. Start up your favorite web browser, which will display your selected homepage.

2. Start up the Wireshark software. You will initially see a window similar to that shown in Figure 2.

3. To begin packet capture, select Capture Options under Capture (see Figure 2). This will cause the “Wireshark: Capture Options” window to be displayed, as shown in Figure 3.

Figure 3. Wireshark Capture Options Window

4. You can use most of the default values in this window, but uncheck “Hide capture info

dialog” under Display Options. In case your computer has more than one active network

interface (e.g., if you have both a wireless and a wired Ethernet connection), you will

need to select an interface that is being used to send and receive packets (mostly likely

the wired interface). After selecting the network interface (or using the default interface

chosen by Wireshark), click Start. Packet capture will now begin - all packets being

sent/received from/by your computer are now being captured by Wireshark!

5. Once you begin packet capture, a packet capture summary window will appear, as shown in Figure 4. This window summarizes the number of packets of various types that are

being captured, and (importantly!) contains the Stop button that will allow you to stop

packet capture. Don’t stop packet capture yet.

4

Figure 4. Wireshark Packet Capture Window

6. While Wireshark is running, enter the URL in your browser: http://academic.udayton.edu/zhongmeiyao/470.html and have that page displayed in your

browser. In order to display this page, your browser will contact the HTTP server at

academic.udayton.edu and exchange HTTP messages with the server in order to

download this page. The Ethernet frames containing these HTTP messages will be

captured by Wireshark.

7. After your browser has displayed the course web page, stop Wireshark packet capture by selecting stop in the Wireshark capture window (see Figure 4). This will cause the

Wireshark capture window to disappear and the main Wireshark window to display all

packets captured since you began packet capture. The main Wireshark window should

now look similar to Figure 5. You now have live packet data that contains all protocol

messages exchanged between your computer and other network entities! The HTTP

message exchanges with the academic.udayton.edu web server should appear somewhere

in the listing of packets captured. But there will be many other types of packets displayed

as well (see, e.g., the many different protocol types shown in the Protocol column in

Figure 5). Even though the only action you took was to download a web page, there were

evidently many other protocols running on your computer that are unseen by the user.

We’ll learn much more about these protocols as we progress through the textbook! For

now, you should just be aware that there is often much more going on than “meet’s the

eye”!

5

Figure 5. A snapshot of Wireshark lab

8. As shown in Figure 6, type in “http” (without the quotes, and in lower case – all protocol names are in lower case in Wireshark) into the display filter specification window at the

top of the main Wireshark window. Then select Apply (to the right of where you entered

“http”). This will cause only HTTP message to be displayed in the packet-listing window.

Figure 6. Wireshark display after step 8

listing of

captured

packets

details of

Frame 14’s

header

packet

content in

hexadecimal

and ASCII

6

9. Select the first http message shown in the packet-listing window. This should be the HTTP GET message that was sent from your computer to the academic.udayton.edu

HTTP server. When you select the HTTP GET message, the Ethernet frame, IP datagram,

TCP segment, and HTTP message header information will be displayed in the packet-

header window. By clicking on right-pointing and down-pointing arrowsheads to the left

side of the packet details window, minimize the amount of Frame, Ethernet, Internet

Protocol, and Transmission Control Protocol information displayed. Maximize the

amount information displayed about the HTTP protocol. (Note, in particular, the

minimized amount of protocol information for all protocols except HTTP, and the

maximized amount of protocol information for HTTP in the packet-header window).

10. Exit Wireshark

Congratulations! You’ve now completed the first lab.

2.3. Questions

The following questions will demonstrate that you’ve been able to get Wireshark up and running,

and have explored some of its capabilities. Answer the following questions, based on your

Wireshark experimentation:

1. List the different protocols that appear in the protocol column in the unfiltered packet- listing window in step 7 above.

2. How long did it take from when the HTTP GET message was sent until the HTTP OK reply was received? (By default, the value of the Time column in the packetlisting

window is the amount of time, in seconds, since Wireshark tracing began. To display the

Time field in time-of-day format, select the Wireshark View pull down menu, then select

Time Display Format, then select Time-of-day.)

3. What is the Internet address of the academic.udayton.edu? What is the Internet address of your computer?

4. Print the two HTTP messages displayed in step 9 above. To do so, select Print from the Wireshark File command menu, and select “Selected Packet Only” and “Print as

displayed” and then click OK.

__MACOSX/project 1/._as1-helper-wireshark.pdf

project 1/header.(h).rtf

/* * yao-as1-header.h */ // header files every .cpp needs #pragma once #include <windows.h> #include <stdio.h> #include <iostream> #include <mmsystem.h> #include <queue> #include <set> #include <string> using namespace std; // if you're planning to use STL #define THREAD_COUNT 10 // number of threads created in main #define MAX_SEM_COUNT 10000000 // the maximum queue size

__MACOSX/project 1/._header.(h).rtf

project 1/main.(cpp).rtf

/* yao-as1-main.cpp */ #pragma once #include "yao-as1-header.h" #include "yao-as1-winsock.h" #include "yao-as1-parameters.h" // this function is where the thread starts UINT thread(LPVOID pParam) { Parameters *p = ((Parameters*)pParam); // declare local variables, i.e., variables used by this thread only // e.g.: Winsock ws; // so that you can use OpenTCPsocket(), Connect(), Send(), ... functions defined in class Winsock // wait for mutex, then print and sleep inside the critical section WaitForSingleObject(p->mutex, INFINITE); // lock mutex p->count++; // only after obtain mutex, this thread can modify shared parameters printf("Thread %d started\n", GetCurrentThreadId()); printf("count = %d\n", p->count); // always print inside critical section to avoid screen garbage Sleep(1000); // for debugging purpose, let this thread sleep for 1 sec before return the mutex ReleaseMutex(p->mutex); // release critical section; i.e., return mutex // signal that this thread has done its work, exiting this function ... ReleaseSemaphore(p->finished, 1, NULL); return 0; } int main(int argc, const char* argv[]) { // receive argument from command line: string website = ""; if (argc > 1) { website = argv[1]; cout << "URL Entered: " << website << endl << endl; } else website = "www.yahoo.com"; // for testing purpose, give it a default website // get current time DWORD t = timeGetTime(); /* ----------- test winsock functions ----------------------------------*/ WSADATA wsaData; //Initialize WinSock; once per program run WORD wVersionRequested = MAKEWORD(2, 2); if (WSAStartup(wVersionRequested, &wsaData) != 0) { printf("Exit: WSAStartup error %d\n", WSAGetLastError()); WSACleanup(); exit(-1); } Winsock ws; ws.OpenTCPsocket(); ws.Connect(website.c_str(), 80); printf("finished connecting to server\n\n"); /*------------ create multiple threads, each thread increases count by 1 in Paramaters --------------------------------------------*/ // p is the shared parameters between the threads Parameters p; p.count = 0; // create a mutex for accessing critical sections (including printf) p.mutex = CreateMutex(NULL, 0, NULL); // create a semaphore that counts the number of active threads p.finished = CreateSemaphore(NULL, 0, THREAD_COUNT, NULL); p.eventQuit = CreateEvent(NULL, true, false, NULL); printf("----------- creating threads -----\n"); // thread handles are stored here; they can be used to check status of threads, or kill them HANDLE *aThread = new HANDLE[THREAD_COUNT]; for(int i = 0; i < THREAD_COUNT; i++) { aThread[i] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)thread, &p, 0, NULL); // pass Parameters to each thread if( aThread[i] == NULL){ printf("Exit: CreateThread error: %d\n", GetLastError()); exit(-1); } } /* make sure this main thread hangs hereuntil all threads are done with crawling otherwise, the program will terminate prematurely */ for(int i = 1; i <= THREAD_COUNT; ++i) { WaitForSingleObject(p.finished, INFINITE); printf("%d thread finished in main() function --------------\n", i); } printf("Terminating main(), completion time %d ms\n", timeGetTime() - t); WSACleanup(); }

__MACOSX/project 1/._main.(cpp).rtf

project 1/parameters.(h).rtf

/* yao-as1-parameters.h * winsock sample code */ #pragma once #include "yao-as1-header.h" // this class is passed to all threads, acts as shared memory class Parameters{ public: HANDLE mutex; HANDLE finished; HANDLE eventQuit; int count; };

__MACOSX/project 1/._parameters.(h).rtf

project 1/winsock.h).rtf

/* yao-as1-winsock.h * winsock sample code */ #pragma once #include <stdio.h> class Winsock{ public: Winsock() { } ~Winsock() { } SOCKET sock; // precondition: Winsock has been initialized // quit program on errors void OpenTCPsocket(void) { // open a TCP socket sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (sock == INVALID_SOCKET) { printf("socket() generated error %d\n", WSAGetLastError()); WSACleanup(); return; } else printf("Created a TCP socket\n"); } // str could be an IP address (a string of numbers and dots such as "193.23.12.1"), or a domain name (a string of chars such as "www.udayton.edu") // port: port number where the remote server uses (e.g., port number is 80 for a web server) bool Connect(const char *str, unsigned short port) { // structure for connecting to server struct sockaddr_in server; // structure used in DNS lookups struct hostent *remote; // first assume that the string is an IP address DWORD IP = inet_addr(str); if (IP == INADDR_NONE) { // if not a valid IP, then do a DNS lookup if ((remote = gethostbyname(str)) == NULL) { printf("Invalid string: neither FQDN, nor IP address\n"); return false; } else // take the first IP address and copy into sin_addr memcpy((char *)&(server.sin_addr), remote->h_addr, remote->h_length); } else { // if a valid IP, directly drop its binary version into sin_addr server.sin_addr.S_un.S_addr = IP; } // setup the port # and protocol type server.sin_family = AF_INET; server.sin_port = htons(port); // host-to-network flips the byte order // connect to the server on port 80 if (connect(this->sock, (struct sockaddr*) &server, sizeof(struct sockaddr_in)) == SOCKET_ERROR) { printf("connect() error: %d\n", WSAGetLastError()); return false; } printf("Successfully connected to %s (%s) on port %d\n", str, inet_ntoa(server.sin_addr), htons(server.sin_port)); return true; } // connect sock to a remote server based on its IP address of type DWORD and port # bool Connect(DWORD IP, unsigned short port) { // structure for connecting to server struct sockaddr_in server; // if a valid IP, directly drop its binary version into sin_addr server.sin_addr.S_un.S_addr = IP; server.sin_family = AF_INET; server.sin_port = htons(port); // host-to-network flips the byte order // connect to the server on port 80 if (connect(this->sock, (struct sockaddr*) &server, sizeof(struct sockaddr_in)) == SOCKET_ERROR) { printf("connect() error: %d\n", WSAGetLastError()); return false; } printf("Successfully connected to %s on port %d\n", inet_ntoa(server.sin_addr), htons(server.sin_port)); return true; } // write your own send(), receive() functions };

__MACOSX/project 1/._winsock.h).rtf