RetroShare/libretroshare/src/tcponudp/largefile_tou.cc
drbob 8b230a55cf Significant changes to aid UDP connections.
* Added Period and Delay parameters to connections.
   - Delay is used to avoid simultaneous TCP connections.
   - Period is used to regulate UDP connections.
 * added Delay code to pqissl.
 * added Period code to tcponudp / pqissludp.
 * modified TTL modification code.
 * increased SynPktRetransmit value.
 * fixed retrans() timeout (one reason code wasn't working before!)
 * fixed tou_close() SEGV bug.
 * modified pqissludp tou_socket creation. (non permanent now).
 * Modified format of peerConnectRequest() CB to make it more useful and rewrote function.
 * Enabled pqissludp NetInterface.
 * using Id comparision to determine Active/Passive UDP connection state.
 * added #def to disable TCP connections. (for testing)
 * enabled UDP connections from retryConnect() function.
 * corrected EXT check in retryConnect() function.
 * + lots of debug output and other stuff.



git-svn-id: http://svn.code.sf.net/p/retroshare/code/trunk@358 b45a01b8-16f6-495d-af2f-9b41ad6348cc
2008-02-27 02:32:20 +00:00

503 lines
11 KiB
C++

/*
* "$Id: largefile_tou.cc,v 1.2 2007-02-18 21:46:50 rmf24 Exp $"
*
* TCP-on-UDP (tou) network interface for RetroShare.
*
* Copyright 2004-2006 by Robert Fernie.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License Version 2 as published by the Free Software Foundation.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA.
*
* Please report all bugs and problems to "retroshare@lunamutt.com".
*
*/
/**********************************************************
* This test is designed to test large data blocks/files
* running to tou. Currently we see occasional errors
* every 1/2 -> 1 MB of transfer....
*
* This test will continually fill the output buffer,
* and then empty the receive one. To ensure the
* whole system gets a good workout.
*
*/
#include <iostream>
// for printing sockaddr
#include "udplayer.h"
#include "tou.h"
#include "tou_net.h"
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
int setup_socket(struct sockaddr_in addr);
int connect_socket_pair(int fd1, int fd2,
struct sockaddr_in addr1, struct sockaddr_in addr2);
int send_data_via_pair(int sockfd1, int sockfd2, char *data, int size);
void usage(char *name)
{
std::cerr << "Usage: " << name;
std::cerr << " [-pco] <laddr> <lport> ";
std::cerr << " <raddr> <rport> ";
std::cerr << std::endl;
exit(1);
return;
}
int main(int argc, char **argv)
{
int c;
bool isProxy = false;
bool toConnect = false;
bool stayOpen = false;
int i,j;
while(-1 != (c = getopt(argc, argv, "pco")))
{
switch (c)
{
case 'p':
isProxy = true;
break;
case 'c':
toConnect = true;
break;
case 'o':
stayOpen = true;
break;
default:
usage(argv[0]);
break;
}
}
if (argc-optind < 4)
{
usage(argv[0]);
return 1;
}
tounet_init();
/* setup the local/remote addresses.
*/
struct sockaddr_in laddr;
struct sockaddr_in raddr;
laddr.sin_family = AF_INET;
raddr.sin_family = AF_INET;
if ((!tounet_inet_aton(argv[optind], &(laddr.sin_addr))) ||
(!tounet_inet_aton(argv[optind+2], &(raddr.sin_addr))))
{
std::cerr << "Invalid addresses!" << std::endl;
usage(argv[0]);
}
unsigned short laddr_port = atoi(argv[optind+1]);
unsigned short raddr_port = atoi(argv[optind+3]);
for(i = 0; i < 10; i++)
{
laddr.sin_port = htons(laddr_port);
raddr.sin_port = htons(raddr_port);
//laddr.sin_port = htons(laddr_port + i);
//raddr.sin_port = htons(raddr_port + i);
std::cerr << "Interation: " << i << std::endl;
/* setup the sockets */
int sockfd1 = setup_socket(laddr);
int sockfd2 = setup_socket(raddr);
if ((sockfd1 < 0) || (sockfd2 < 0))
{
std::cerr << "Failed to setup sockets!";
std::cerr << std::endl;
return -1;
}
std::cerr << "Local Address: " << laddr;
std::cerr << " fd: " << sockfd1 << std::endl;
std::cerr << "Remote Address: " << raddr;
std::cerr << " fd: " << sockfd2 << std::endl;
/* connect */
int err = connect_socket_pair(sockfd1, sockfd2, laddr, raddr);
if (err < 0)
{
std::cerr << "Failed to connect sockets!";
std::cerr << std::endl;
return -1;
}
/* send the data */
int size = 3093237;
char rnddata[size];
int data_loops = (i+1) * (i+1);
for(int k = 0; k < data_loops; k++)
{
std::cerr << "Send Iteration: " << k+1 << " of " << data_loops << std::endl;
for(j = 0; j < size; j++)
{
rnddata[j] = (unsigned char) (255.0 *
rand() / (RAND_MAX + 1.0));
}
send_data_via_pair(sockfd1, sockfd2, rnddata, size);
std::cerr << "Send Iteration: " << k+1 << " of " << data_loops << std::endl;
sleep(2);
}
std::cerr << "Completed Successful transfer of " << size * data_loops << " bytes";
std::cerr << std::endl;
sleep(10);
std::cerr << "closing sockfd1: " << sockfd1 << std::endl;
tou_close(sockfd1);
std::cerr << "closing sockfd2: " << sockfd2 << std::endl;
tou_close(sockfd2);
}
return 1;
}
int setup_socket(struct sockaddr_in addr)
{
int sockfd = tou_socket(PF_INET, SOCK_STREAM, 0);
if (sockfd <= 0)
{
std::cerr << "Failed to open socket!: ";
std::cerr << "Socket Error:" << tou_errno(sockfd) << std::endl;
return -1;
}
std::cerr << "Socket Created: " << sockfd << std::endl;
int err = tou_bind(sockfd, (struct sockaddr *) &addr, sizeof(addr));
if (err < 0)
{
std::cerr << "Error: Cannot bind socket: ";
std::cerr << err << std::endl;
return -1;
}
std::cerr << "Socket1 Bound to: " << addr << std::endl;
return sockfd;
}
int connect_socket_pair(int fd1, int fd2,
struct sockaddr_in addr1, struct sockaddr_in addr2)
{
std::cerr << "Socket2 Listening " << std::endl;
/* listen */
int err = tou_listenfor(fd2, (struct sockaddr *) &addr1, sizeof(addr1));
int err_num;
if (err < 0)
{
err_num = tou_errno(fd2);
if (err_num != EINPROGRESS)
{
std::cerr << "Cannot Listen!: " << err_num << std::endl;
return -1;
}
}
std::cerr << "Socket1 Connecting to: " << addr2 << std::endl;
err = tou_connect(fd1, (struct sockaddr *) &addr2, sizeof(addr2), 30);
if (err < 0)
{
err_num = tou_errno(fd1);
if (err_num != EINPROGRESS)
{
std::cerr << "Cannot Connect!: " << err_num << std::endl;
return -1;
}
}
bool sock1Connected = false;
bool sock2Connected = false;
while((!sock1Connected) || (!sock2Connected))
{
sleep(1);
/* sock1 */
if((!sock1Connected) && (0 == (err = tou_connected(fd1))))
{
std::cerr << "Waiting for Connect (Sock1)!" << std::endl;
}
if ((!sock1Connected) && (err < 0))
{
std::cerr << "Connect Failed" << std::endl;
return 1;
}
else if (!sock1Connected)
{
// else connected!
sock1Connected = true;
}
/* accept - sock2 */
struct sockaddr_in inaddr;
socklen_t addrlen = sizeof(inaddr);
int nsock = -1;
if ((!sock2Connected) && (0 > (nsock = tou_accept(fd2,
(struct sockaddr *) &inaddr, &addrlen))))
{
errno = tou_errno(fd2);
if (errno != EAGAIN)
{
std::cerr << "Cannot Connect!: " << errno << std::endl;
return 1;
}
else
{
std::cerr << "Waiting for Connect (Sock2)!" << std::endl;
}
}
else if (nsock > 0)
{
/* connected */
sock2Connected = true;
fd2 = nsock;
std::cerr << "Socket Accepted from: " << inaddr << std::endl;
}
}
std::cerr << "Socket Connected" << std::endl;
return 1;
}
/* This transmits into sockfd1, and check to see that we recv
* it back from sockfd2
*/
int send_data_via_pair(int sockfd1, int sockfd2, char *data, int size)
{
/* what we recvd */
char *recvd = (char *) malloc(size * 2);
int recvdsize = 0;
int sent = 0;
int sendsize = 0;
int ts_start = time(NULL);
int minsends = 100; /* min of 100 sends to complete all data */
/* ensure we don't end up sending nothing */
if (minsends * 10 > size)
{
minsends = size / 10;
}
bool doneWrite = false;
bool doneRead = false;
int maxtransfer = (int) (size / minsends) + (int) (((float) (size / minsends)) *
(rand() / (RAND_MAX + 1.0)));
/* allow the transfer ratio read/write to vary between 0.4->1,5. */
double tf_ratio = 0.4 + 1.1 * (rand() / (RAND_MAX + 1.0));
while((!doneWrite) || (!doneRead))
{
/* have a little break */
//usleep(10000); /* 0.01 sec */
usleep(20000); /* 0.02 sec */
//usleep(250000); /* 0.25 sec */
//usleep(500000); /* 0.50 sec */
/* decide how much to send */
sendsize = (int) (((float) (maxtransfer)) *
(rand() / (RAND_MAX + 1.0)));
/* limit send */
if (sent + sendsize > size)
{
std::cerr << "Last WRITE!" << std::endl;
sendsize = size - sent;
}
/* if we've finished */
if (sent == size)
{
/* eof */
std::cerr << "Write Done!" << std::endl;
doneWrite = true;
sendsize = 0;
}
/* now we write */
if ((sendsize > 0)&&(-1==tou_write(sockfd1,&(data[sent]),sendsize)))
{
std::cerr << "Write Error: " << tou_errno(sockfd1) << std::endl;
if (tou_errno(sockfd1) != EAGAIN)
{
std::cerr << "FATAL ERROR ending transfer" << std::endl;
doneRead = true;
doneWrite = true;
}
}
else
{
sent += sendsize;
}
int ret = 0;
// read size about 1/4 of write to exercise the buffers.
int readsize = (int) (((float) (maxtransfer)) * tf_ratio *
(rand() / (RAND_MAX + 1.0)));
if (readsize > size - recvdsize)
{
std::cerr << "Last READ!" << std::endl;
readsize = size - recvdsize;
}
if (0 < (ret = tou_read(sockfd2, &(recvd[recvdsize]), readsize)))
{
std::cerr << "TF(" << ret << ")" << std::endl;
/* check the data at this point */
int i;
int diffCount = 0;
int init_err = 0;
for(i = 0; i < ret; i++)
{
if (recvd[recvdsize + i] != data[recvdsize + i])
{
if (!diffCount)
{
init_err = i;
}
diffCount++;
if (diffCount < 10)
{
std::cerr << "Error Byte:" << recvdsize + i << " is different";
std::cerr << std::endl;
}
}
}
if (diffCount)
{
std::cerr << "Errors (" << diffCount << "/" << ret << ") in read, ";
std::cerr << std::endl;
std::cerr << " At Blk Start: " << recvdsize << " offset: " << init_err;
std::cerr << " ==> At index: " << recvdsize + init_err << "... Exiting!";
std::cerr << std::endl;
exit(1);
}
else
{
std::cerr << "Checked (" << recvdsize << "+ 0 => " << ret << ") Okay" << std::endl;
}
recvdsize += ret;
}
else if (ret == 0)
{
//doneRead = true;
std::cerr << "Read Done? (ret:0)" << std::endl;
}
else
{
std::cerr << "Read Error: " << tou_errno(sockfd2) << std::endl;
std::cerr << "Read " << recvdsize << "/" << size;
std::cerr << " attempted: " << readsize << std::endl;
if (tou_errno(sockfd2) != EAGAIN)
{
std::cerr << "FATAL ERROR ending transfer" << std::endl;
doneRead = true;
doneWrite = true;
}
}
if (recvdsize == size)
{
doneRead = true;
std::cerr << "Read Done!" << std::endl;
}
}
/* we have transmitted it all, so
* check the data
*/
int i;
int diffCount = 0;
for(i = 0; i < size; i++)
{
if (recvd[i] != data[i])
{
diffCount++;
if (diffCount < 10)
{
std::cerr << "Error Byte:" << i << " is different";
std::cerr << std::endl;
}
}
}
if (diffCount)
{
std::cerr << "Errors (" << diffCount << "/" << size << ") in tranmission ... Exiting!";
std::cerr << std::endl;
exit(1);
}
int ts_end = time(NULL);
double rough_rate = size / (double) (ts_end - ts_start);
std::cerr << "Successful Data Tranmission: " << size << " in " << ts_end-ts_start << " secs";
std::cerr << std::endl;
std::cerr << "Approximate Rate: " << rough_rate / 1000.0 << " kbytes/sec";
std::cerr << std::endl;
std::cerr << "Transfer Ratio: " << tf_ratio;
std::cerr << std::endl;
free(recvd);
return 1;
}