RetroShare/libretroshare/src/tcponudp/pair_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

492 lines
10 KiB
C++

/*
* "$Id: pair_tou.cc,v 1.3 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".
*
*/
#include <iostream>
//#define USE_TCP_SOCKET
// for printing sockaddr
#include "udplayer.h"
#ifndef USE_TCP_SOCKET
#include "tou.h"
#endif
#include "tou_net.h"
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
/* This is a simple test to ensure that the tou behaviour
* is almost identical to a standard tcp socket.
*
* In this version we open 2 sockets, and attempt to
* communicate with ourselves....
*
*/
int Check_Socket(int fd);
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 totalwbytes = 0;
int totalrbytes = 0;
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]);
}
laddr.sin_port = htons(atoi(argv[optind+1]));
raddr.sin_port = htons(atoi(argv[optind+3]));
std::cerr << "Local Address: " << laddr << std::endl;
std::cerr << "Remote Address: " << raddr << std::endl;
#ifdef USE_TCP_SOCKET
int sockfd = socket(PF_INET, SOCK_STREAM, 0);
int sockfd2 = socket(PF_INET, SOCK_STREAM, 0);
#else
int sockfd = tou_socket(PF_INET, SOCK_STREAM, 0);
int sockfd2 = tou_socket(PF_INET, SOCK_STREAM, 0);
#endif
if ((sockfd <= 0) || (sockfd2 <= 0))
{
std::cerr << "Failed to open socket!: ";
#ifdef USE_TCP_SOCKET
std::cerr << "Socket Error:" << errno << std::endl;
#else
std::cerr << "Socket Error:" << tou_errno(sockfd) << std::endl;
std::cerr << "Socket Error:" << tou_errno(sockfd2) << std::endl;
#endif
return -1;
}
std::cerr << "Sockets Created: " << sockfd << " & " << sockfd2 << std::endl;
/* make nonblocking */
#ifdef USE_TCP_SOCKET
int err = fcntl(sockfd,F_SETFD,O_NONBLOCK);
int err2 = fcntl(sockfd2,F_SETFD,O_NONBLOCK);
#else
int err = 0;
int err2 = 0;
#endif
if ((err < 0) || (err2 < 0))
{
std::cerr << "Error: Cannot make socket NON-Blocking: ";
std::cerr << err << std::endl;
return -1;
}
std::cerr << "Socket Non-Blocking" << std::endl;
#ifdef USE_TCP_SOCKET
err = bind(sockfd, (struct sockaddr *) &laddr, sizeof(laddr));
err2 = bind(sockfd2, (struct sockaddr *) &raddr, sizeof(raddr));
#else
err = tou_bind(sockfd, (struct sockaddr *) &laddr, sizeof(laddr));
err2 = tou_bind(sockfd2, (struct sockaddr *) &raddr, sizeof(raddr));
#endif
if ((err < 0) || (err2 < 0))
{
std::cerr << "Error: Cannot bind socket: ";
std::cerr << err << std::endl;
return -1;
}
std::cerr << "Socket1 Bound to: " << laddr << std::endl;
std::cerr << "Socket2 Bound to: " << raddr << std::endl;
// listening.
if (1) // socket2.
{
std::cerr << "Socket2 Listening " << std::endl;
/* listen */
#ifdef USE_TCP_SOCKET
err = listen(sockfd2, 1);
#else
err = tou_listenfor(sockfd2,
(struct sockaddr *) &laddr, sizeof(laddr));
#endif
}
if (1) // only one program.
{
std::cerr << "Socket1 Connecting to: " << raddr << std::endl;
#ifdef USE_TCP_SOCKET
err = connect(sockfd, (struct sockaddr *) &raddr, sizeof(raddr));
#else
err = tou_connect(sockfd, (struct sockaddr *) &raddr, sizeof(raddr), 30);
#endif
if (err < 0)
{
#ifndef USE_TCP_SOCKET
errno = tou_errno(sockfd);
#endif
if (errno != EINPROGRESS)
{
std::cerr << "Cannot Connect!: " << errno << std::endl;
return 1;
}
}
}
bool sock1Connected = false;
bool sock2Connected = false;
while((!sock1Connected) || (!sock2Connected))
{
sleep(1);
/* sock1 */
#ifdef USE_TCP_SOCKET
if((!sock1Connected) && (0 == (err = Check_Socket(sockfd))))
#else
if((!sock1Connected) && (0 == (err = tou_connected(sockfd))))
#endif
{
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;
#ifdef USE_TCP_SOCKET
if ((!sock2Connected) && (0 > (nsock = accept(sockfd2,
(struct sockaddr *) &inaddr, &addrlen))))
#else
if ((!sock2Connected) && (0 > (nsock = tou_accept(sockfd2,
(struct sockaddr *) &inaddr, &addrlen))))
#endif
{
#ifndef USE_TCP_SOCKET
errno = tou_errno(sockfd2);
#endif
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;
sockfd2 = nsock;
std::cerr << "Socket Accepted from: " << inaddr << std::endl;
}
}
std::cerr << "Socket Connected" << std::endl;
/* send data */
int bufsize = 1511;
char buffer[bufsize];
char data[bufsize];
int readsize = 0;
tounet_fcntl(0, F_SETFL, O_NONBLOCK);
tounet_fcntl(1,F_SETFL,O_NONBLOCK);
bool doneWrite = false;
bool doneRead = false;
bool blockread = false;
while((!doneWrite) || (!doneRead))
{
/* read -> write_socket... */
sleep(1);
if (blockread != true)
{
readsize = read(0, buffer, bufsize);
}
if (readsize == 0)
{
/* eof */
doneWrite = true;
}
/* now we write */
#ifdef USE_TCP_SOCKET
if ((readsize > 0) && (-1 == write(sockfd, buffer, readsize)))
#else
if ((readsize > 0) && (-1 == tou_write(sockfd, buffer, readsize)))
#endif
{
//std::cerr << "Blocked Write!" << std::endl;
#ifndef USE_TCP_SOCKET
//std::cerr << "Error: " << tou_errno(sockfd) << std::endl;
#endif
blockread = true;
}
else
{
blockread = false;
totalwbytes += readsize;
}
int ret = 0;
#ifdef USE_TCP_SOCKET
if (0 < (ret = read(sockfd2, data, bufsize)))
#else
if (0 < (ret = tou_read(sockfd2, data, bufsize)))
#endif
{
std::cerr << "TF(" << ret << ")" << std::endl;
write(1, data, ret);
totalrbytes += ret;
}
else if (ret == 0)
{
doneRead = true;
}
else
{
//std::cerr << "Blocked Read!" << std::endl;
#ifndef USE_TCP_SOCKET
//std::cerr << "Error: " << tou_errno(sockfd) << std::endl;
#endif
}
}
#ifdef USE_TCP_SOCKET
close(sockfd);
close(sockfd2);
#else
/* this is blocking??? */
tou_close(sockfd);
tou_close(sockfd2);
#endif
std::cerr << "Transfer Complete: " << totalwbytes << " bytes";
std::cerr << std::endl;
return 1;
}
#ifdef USE_TCP_SOCKET
int Check_Socket(int fd)
{
std::cerr << "Check_Socket()" << std::endl;
std::cerr << "1) Checking with Select()" << std::endl;
fd_set ReadFDs, WriteFDs, ExceptFDs;
FD_ZERO(&ReadFDs);
FD_ZERO(&WriteFDs);
FD_ZERO(&ExceptFDs);
FD_SET(fd, &ReadFDs);
FD_SET(fd, &WriteFDs);
FD_SET(fd, &ExceptFDs);
struct timeval timeout;
timeout.tv_sec = 0;
timeout.tv_usec = 0;
int sr = 0;
if (0 > (sr = select(fd + 1,
&ReadFDs, &WriteFDs, &ExceptFDs, &timeout)))
{
std::cerr << "Check_Socket() Select ERROR: " << sr << std::endl;
return -1;
}
if (FD_ISSET(fd, &ExceptFDs))
{
std::cerr << "Check_Socket() Exception on socket!" << std::endl;
return -1;
}
if (FD_ISSET(fd, &WriteFDs))
{
std::cerr << "Check_Socket() Can Write!" << std::endl;
}
else
{
// not ready return 0;
std::cerr << "Check_Socket() Cannot Write!" << std::endl;
std::cerr << "Check_Socket() Socket Not Ready!" << std::endl;
return 0;
}
if (FD_ISSET(fd, &ReadFDs))
{
std::cerr << "Check_Socket() Can Read!" << std::endl;
}
else
{
std::cerr << "Check_Socket() Cannot Read!" << std::endl;
std::cerr << "Check_Socket() Socket Not Ready!" << std::endl;
return 0;
}
std::cerr << "Select() Tests indicate Socket Good!" << std::endl;
std::cerr << "2) Checking with getsockopt()" << std::endl;
int err = 1;
socklen_t optlen = 4;
if (0==getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &optlen))
{
std::cerr << "Check_Socket() getsockopt returned :" << err;
std::cerr << ", optlen:" << optlen;
std::cerr << std::endl;
if (err == 0)
{
std::cerr << "Check_Socket() getsockopt";
std::cerr << " Indicates TCP Connection Complete:";
std::cerr << std::endl;
return 1;
}
else if (err == EINPROGRESS)
{
std::cerr << "Check_Socket() getsockopt";
std::cerr << " Indicates TCP Connection INPROGRESS";
std::cerr << std::endl;
return 0;
}
else if ((err == ENETUNREACH) || (err == ETIMEDOUT))
{
std::cerr << "Check_Socket() getsockopt";
std::cerr << " Indicates TCP Connection ENETUNREACH/ETIMEDOUT";
std::cerr << std::endl;
return -1;
}
else if ((err == EHOSTUNREACH) || (err == EHOSTDOWN))
{
std::cerr << "Check_Socket() getsockopt";
std::cerr << " Indicates TCP Connection ENETUNREACH/ETIMEDOUT";
std::cerr << std::endl;
return -1;
}
else
{
std::cerr << "Check_Socket() getsockopt";
std::cerr << " Indicates Other Error: " << err;
std::cerr << std::endl;
return -1;
}
}
else
{
std::cerr << "Check_Socket() getsockopt";
std::cerr << " FAILED ";
std::cerr << std::endl;
return -1;
}
}
#else
int Check_Socket(int fd)
{
return 0;
}
#endif