mirror of
https://github.com/RetroShare/RetroShare.git
synced 2025-06-23 05:44:45 -04:00
Created V0.3.x branch and moved the head into the trunk directory.
git-svn-id: http://svn.code.sf.net/p/retroshare/code/trunk@246 b45a01b8-16f6-495d-af2f-9b41ad6348cc
This commit is contained in:
commit
935745a08e
1318 changed files with 348809 additions and 0 deletions
60
libretroshare/src/tcponudp/Makefile
Normal file
60
libretroshare/src/tcponudp/Makefile
Normal file
|
@ -0,0 +1,60 @@
|
|||
|
||||
RS_TOP_DIR=..
|
||||
|
||||
include $(RS_TOP_DIR)/make.opt
|
||||
|
||||
EXECS = librs udp_server test_tou pair_tou reset_tou internal_tou largefile_tou
|
||||
|
||||
OBJ = tcpstream.o tcppacket.o udplayer.o tou_net.o tou.o
|
||||
|
||||
all : $(OBJ) $(EXECS)
|
||||
|
||||
.cc.o:
|
||||
$(CC) $(CFLAGS) -c $<
|
||||
|
||||
udp_server: $(OBJ) udp_server.o
|
||||
$(CC) $(CFLAGS) -o udp_server $(OBJ) udp_server.o $(LIBS)
|
||||
|
||||
clean:
|
||||
-$(RM) $(OBJ) $(BIOOBJ) test_tou.o pair_tou.o udp_server.o reset_tou.o internal_tou.o largefile_tou.o
|
||||
|
||||
clobber: clean
|
||||
-$(RM) udp_server test_tou pair_tou reset_tou internal_tou largefile_tou libtou.so ../lib/libtou.a
|
||||
|
||||
test_tou : $(OBJ) test_tou.o
|
||||
$(CC) $(CFLAGS) -o test_tou $(OBJ) test_tou.o $(LIBS)
|
||||
|
||||
pair_tou : $(OBJ) pair_tou.o
|
||||
$(CC) $(CFLAGS) -o pair_tou $(OBJ) pair_tou.o $(LIBS)
|
||||
|
||||
reset_tou : $(OBJ) reset_tou.o
|
||||
$(CC) $(CFLAGS) -o reset_tou $(OBJ) reset_tou.o $(LIBS)
|
||||
|
||||
internal_tou : $(OBJ) internal_tou.o
|
||||
$(CC) $(CFLAGS) -o internal_tou $(OBJ) internal_tou.o $(LIBS)
|
||||
|
||||
largefile_tou : $(OBJ) largefile_tou.o
|
||||
$(CC) $(CFLAGS) -o largefile_tou $(OBJ) largefile_tou.o $(LIBS)
|
||||
|
||||
|
||||
|
||||
# For BIO Compilation.... SSL Interface.
|
||||
#
|
||||
|
||||
|
||||
BIOOBJ = bss_tou.o
|
||||
BIOCC = gcc
|
||||
BIOCFLAGS = -I $(SSL_DIR)/include -DOPENSSL_THREADS -D_REENTRANT -DDSO_DLFCN -DHAVE_DLFCN_H -DOPENSSL_NO_KRB5 -DL_ENDIAN -DTERMIO -O3 -fomit-frame-pointer -m486 -Wall -DSHA1_ASM -DMD5_ASM -DRMD160_ASM
|
||||
|
||||
|
||||
libtou.a: $(BIOOBJ) $(OBJ)
|
||||
ar rc ../lib/libtou.a $(BIOOBJ) $(OBJ)
|
||||
|
||||
libtou.so: $(BIOOBJ) $(OBJ)
|
||||
$(CC) -o libtou.so -shared $(BIOOBJ) $(OBJ)
|
||||
|
||||
librs: $(BIOOBJ) $(OBJ)
|
||||
ar r ../lib/libretroshare.a $(BIOOBJ) $(OBJ)
|
||||
|
||||
.c.o:
|
||||
$(BIOCC) $(BIOCFLAGS) -c $<
|
46
libretroshare/src/tcponudp/bio_tou.h
Normal file
46
libretroshare/src/tcponudp/bio_tou.h
Normal file
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* "$Id: bio_tou.h,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".
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef BIO_TCPONUDP_H
|
||||
#define BIO_TCPONUDP_H
|
||||
|
||||
#include <openssl/bio.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
int BIO_tou_socket_should_retry(int s, int e);
|
||||
int BIO_tou_socket_non_fatal_error(int error);
|
||||
|
||||
#define BIO_TYPE_TOU_SOCKET (30|0x0400|0x0100) /* NEW rmfern type */
|
||||
|
||||
BIO_METHOD *BIO_s_tou_socket(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
392
libretroshare/src/tcponudp/bss_tou.c
Normal file
392
libretroshare/src/tcponudp/bss_tou.c
Normal file
|
@ -0,0 +1,392 @@
|
|||
/*
|
||||
* bss_tou.c Based on bss_*.c from OpenSSL Library....
|
||||
* Therefore - released under their licence.
|
||||
* Copyright 2004-2006 by Robert Fernie. (retroshare@lunamutt.com)
|
||||
*/
|
||||
|
||||
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
|
||||
* All rights reserved.
|
||||
*
|
||||
* This package is an SSL implementation written
|
||||
* by Eric Young (eay@cryptsoft.com).
|
||||
* The implementation was written so as to conform with Netscapes SSL.
|
||||
*
|
||||
* This library is free for commercial and non-commercial use as long as
|
||||
* the following conditions are aheared to. The following conditions
|
||||
* apply to all code found in this distribution, be it the RC4, RSA,
|
||||
* lhash, DES, etc., code; not just the SSL code. The SSL documentation
|
||||
* included with this distribution is covered by the same copyright terms
|
||||
* except that the holder is Tim Hudson (tjh@cryptsoft.com).
|
||||
*
|
||||
* Copyright remains Eric Young's, and as such any Copyright notices in
|
||||
* the code are not to be removed.
|
||||
* If this package is used in a product, Eric Young should be given attribution
|
||||
* as the author of the parts of the library used.
|
||||
* This can be in the form of a textual message at program startup or
|
||||
* in documentation (online or textual) provided with the package.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* "This product includes cryptographic software written by
|
||||
* Eric Young (eay@cryptsoft.com)"
|
||||
* The word 'cryptographic' can be left out if the rouines from the library
|
||||
* being used are not cryptographic related :-).
|
||||
* 4. If you include any Windows specific code (or a derivative thereof) from
|
||||
* the apps directory (application code) you must include an acknowledgement:
|
||||
* "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* The licence and distribution terms for any publically available version or
|
||||
* derivative of this code cannot be changed. i.e. this code cannot simply be
|
||||
* copied and put under another distribution licence
|
||||
* [including the GNU Public Licence.]
|
||||
*/
|
||||
|
||||
#ifndef OPENSSL_NO_SOCK
|
||||
|
||||
#include "bio_tou.h"
|
||||
|
||||
// STUFF defined in the header.......
|
||||
//int BIO_tou_socket_should_retry(int s, int e);
|
||||
//int BIO_tou_socket_non_fatal_error(int error);
|
||||
//#define BIO_TYPE_TOU_SOCKET (30|0x0400|0x0100) /* NEW rmfern type */
|
||||
//BIO_METHOD *BIO_s_tou_socket(void);
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#define USE_SOCKETS
|
||||
//#include "cryptlib.h"
|
||||
#include <openssl/bio.h>
|
||||
#include <string.h> /* for strlen() */
|
||||
|
||||
|
||||
static int tou_socket_write(BIO *h, const char *buf, int num);
|
||||
static int tou_socket_read(BIO *h, char *buf, int size);
|
||||
static int tou_socket_puts(BIO *h, const char *str);
|
||||
static long tou_socket_ctrl(BIO *h, int cmd, long arg1, void *arg2);
|
||||
static int tou_socket_new(BIO *h);
|
||||
static int tou_socket_free(BIO *data);
|
||||
static int get_last_tou_socket_error(int s);
|
||||
static int clear_tou_socket_error(int s);
|
||||
|
||||
#include "tou.h"
|
||||
|
||||
|
||||
|
||||
static BIO_METHOD methods_tou_sockp=
|
||||
{
|
||||
BIO_TYPE_TOU_SOCKET,
|
||||
"tou_socket",
|
||||
tou_socket_write,
|
||||
tou_socket_read,
|
||||
tou_socket_puts,
|
||||
NULL, /* tou_gets, */
|
||||
tou_socket_ctrl,
|
||||
tou_socket_new,
|
||||
tou_socket_free,
|
||||
NULL,
|
||||
};
|
||||
|
||||
BIO_METHOD *BIO_s_tou_socket(void)
|
||||
{
|
||||
#ifdef DEBUG_TOU_BIO
|
||||
fprintf(stderr, "BIO_s_tou_socket(void)\n");
|
||||
#endif
|
||||
return(&methods_tou_sockp);
|
||||
}
|
||||
|
||||
BIO *BIO_new_tou_socket(int fd, int close_flag)
|
||||
{
|
||||
BIO *ret;
|
||||
#ifdef DEBUG_TOU_BIO
|
||||
fprintf(stderr, "BIO_new_tou_socket(%d)\n", fd);
|
||||
#endif
|
||||
|
||||
ret=BIO_new(BIO_s_tou_socket());
|
||||
if (ret == NULL) return(NULL);
|
||||
BIO_set_fd(ret,fd,close_flag);
|
||||
return(ret);
|
||||
}
|
||||
|
||||
static int tou_socket_new(BIO *bi)
|
||||
{
|
||||
#ifdef DEBUG_TOU_BIO
|
||||
fprintf(stderr, "tou_socket_new()\n");
|
||||
#endif
|
||||
bi->init=0;
|
||||
bi->num=0;
|
||||
bi->ptr=NULL;
|
||||
bi->flags=0;
|
||||
return(1);
|
||||
}
|
||||
|
||||
static int tou_socket_free(BIO *a)
|
||||
{
|
||||
#ifdef DEBUG_TOU_BIO
|
||||
fprintf(stderr, "tou_socket_free()\n");
|
||||
#endif
|
||||
if (a == NULL) return(0);
|
||||
if (a->shutdown)
|
||||
{
|
||||
if (a->init)
|
||||
{
|
||||
tou_close(a->num);
|
||||
}
|
||||
a->init=0;
|
||||
a->flags=0;
|
||||
}
|
||||
return(1);
|
||||
}
|
||||
|
||||
static int tou_socket_read(BIO *b, char *out, int outl)
|
||||
{
|
||||
int ret=0;
|
||||
#ifdef DEBUG_TOU_BIO
|
||||
fprintf(stderr, "tou_socket_read(%p,%p,%d)\n",b,out,outl);
|
||||
#endif
|
||||
|
||||
if (out != NULL)
|
||||
{
|
||||
clear_tou_socket_error(b->num);
|
||||
/* call tou library */
|
||||
ret=tou_read(b->num,out,outl);
|
||||
BIO_clear_retry_flags(b);
|
||||
if (ret <= 0)
|
||||
{
|
||||
if (BIO_tou_socket_should_retry(b->num, ret))
|
||||
BIO_set_retry_read(b);
|
||||
}
|
||||
}
|
||||
#ifdef DEBUG_TOU_BIO
|
||||
fprintf(stderr, "tou_socket_read() = %d\n", ret);
|
||||
#endif
|
||||
return(ret);
|
||||
}
|
||||
|
||||
static int tou_socket_write(BIO *b, const char *in, int inl)
|
||||
{
|
||||
int ret;
|
||||
#ifdef DEBUG_TOU_BIO
|
||||
fprintf(stderr, "tou_socket_write(%p,%p,%d)\n",b,in,inl);
|
||||
#endif
|
||||
|
||||
clear_tou_socket_error(b->num);
|
||||
/* call tou library */
|
||||
ret=tou_write(b->num,in,inl);
|
||||
BIO_clear_retry_flags(b);
|
||||
if (ret <= 0)
|
||||
{
|
||||
if (BIO_tou_socket_should_retry(b->num,ret))
|
||||
{
|
||||
BIO_set_retry_write(b);
|
||||
#ifdef DEBUG_TOU_BIO
|
||||
fprintf(stderr, "tou_socket_write() setting retry flag\n");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#ifdef DEBUG_TOU_BIO
|
||||
fprintf(stderr, "tou_socket_write() = %d\n", ret);
|
||||
#endif
|
||||
return(ret);
|
||||
}
|
||||
|
||||
static long tou_socket_ctrl(BIO *b, int cmd, long num, void *ptr)
|
||||
{
|
||||
long ret=1;
|
||||
int *ip;
|
||||
#ifdef DEBUG_TOU_BIO
|
||||
fprintf(stderr, "tou_socket_ctrl(%p,%d,%ld)\n", b, cmd, num);
|
||||
#endif
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
case BIO_CTRL_RESET:
|
||||
num=0;
|
||||
case BIO_C_FILE_SEEK:
|
||||
ret=0;
|
||||
break;
|
||||
case BIO_C_FILE_TELL:
|
||||
case BIO_CTRL_INFO:
|
||||
ret=0;
|
||||
break;
|
||||
case BIO_C_SET_FD:
|
||||
tou_socket_free(b);
|
||||
b->num= *((int *)ptr);
|
||||
b->shutdown=(int)num;
|
||||
b->init=1;
|
||||
break;
|
||||
case BIO_C_GET_FD:
|
||||
if (b->init)
|
||||
{
|
||||
ip=(int *)ptr;
|
||||
if (ip != NULL) *ip=b->num;
|
||||
ret=b->num;
|
||||
}
|
||||
else
|
||||
ret= -1;
|
||||
break;
|
||||
case BIO_CTRL_GET_CLOSE:
|
||||
ret=b->shutdown;
|
||||
break;
|
||||
case BIO_CTRL_SET_CLOSE:
|
||||
b->shutdown=(int)num;
|
||||
break;
|
||||
case BIO_CTRL_PENDING:
|
||||
ret = tou_maxread(b->num);
|
||||
#ifdef DEBUG_TOU_BIO
|
||||
fprintf(stderr, "tou_pending = %ld\n", ret);
|
||||
#endif
|
||||
break;
|
||||
case BIO_CTRL_WPENDING:
|
||||
ret = tou_maxwrite(b->num);
|
||||
#ifdef DEBUG_TOU_BIO
|
||||
fprintf(stderr, "tou_wpending = %ld\n", ret);
|
||||
#endif
|
||||
break;
|
||||
case BIO_CTRL_DUP:
|
||||
case BIO_CTRL_FLUSH:
|
||||
ret=1;
|
||||
break;
|
||||
default:
|
||||
ret=0;
|
||||
break;
|
||||
}
|
||||
return(ret);
|
||||
}
|
||||
|
||||
static int tou_socket_puts(BIO *bp, const char *str)
|
||||
{
|
||||
int n,ret;
|
||||
|
||||
#ifdef DEBUG_TOU_BIO
|
||||
fprintf(stderr, "tou_socket_puts()\n");
|
||||
#endif
|
||||
|
||||
n=strlen(str);
|
||||
ret=tou_socket_write(bp,str,n);
|
||||
return(ret);
|
||||
}
|
||||
|
||||
static int clear_tou_socket_error(int fd)
|
||||
{
|
||||
#ifdef DEBUG_TOU_BIO
|
||||
fprintf(stderr, "clear_tou_socket_error()\n");
|
||||
#endif
|
||||
return tou_clear_error(fd);
|
||||
}
|
||||
|
||||
static int get_last_tou_socket_error(int s)
|
||||
{
|
||||
#ifdef DEBUG_TOU_BIO
|
||||
fprintf(stderr, "get_last_tou_socket_error()\n");
|
||||
#endif
|
||||
return tou_errno(s);
|
||||
}
|
||||
|
||||
int BIO_tou_socket_should_retry(int s, int i)
|
||||
{
|
||||
int err;
|
||||
#ifdef DEBUG_TOU_BIO
|
||||
fprintf(stderr, "BIO_tou_socket_should_retry()\n");
|
||||
#endif
|
||||
|
||||
if ((i == 0) || (i == -1))
|
||||
{
|
||||
err=get_last_tou_socket_error(s);
|
||||
|
||||
#if defined(OPENSSL_SYS_WINDOWS) && 0 /* more microsoft stupidity? perhaps not? Ben 4/1/99 */
|
||||
if ((i == -1) && (err == 0))
|
||||
return(1);
|
||||
#endif
|
||||
|
||||
return(BIO_tou_socket_non_fatal_error(err));
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
int BIO_tou_socket_non_fatal_error(int err)
|
||||
{
|
||||
switch (err)
|
||||
{
|
||||
#if defined(OPENSSL_SYS_WINDOWS)
|
||||
# if defined(WSAEWOULDBLOCK)
|
||||
case WSAEWOULDBLOCK:
|
||||
# endif
|
||||
|
||||
# if 0 /* This appears to always be an error */
|
||||
# if defined(WSAENOTCONN)
|
||||
case WSAENOTCONN:
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef EWOULDBLOCK
|
||||
# ifdef WSAEWOULDBLOCK
|
||||
# if WSAEWOULDBLOCK != EWOULDBLOCK
|
||||
case EWOULDBLOCK:
|
||||
# endif
|
||||
# else
|
||||
case EWOULDBLOCK:
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(ENOTCONN)
|
||||
case ENOTCONN:
|
||||
#endif
|
||||
|
||||
#ifdef EINTR
|
||||
case EINTR:
|
||||
#endif
|
||||
|
||||
#ifdef EAGAIN
|
||||
#if EWOULDBLOCK != EAGAIN
|
||||
case EAGAIN:
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef EPROTO
|
||||
case EPROTO:
|
||||
#endif
|
||||
|
||||
#ifdef EINPROGRESS
|
||||
case EINPROGRESS:
|
||||
#endif
|
||||
|
||||
#ifdef EALREADY
|
||||
case EALREADY:
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef DEBUG_TOU_BIO
|
||||
fprintf(stderr, "BIO_tou_socket_non_fatal_error(%d) = 1\n", err);
|
||||
#endif
|
||||
return(1);
|
||||
/* break; */
|
||||
default:
|
||||
break;
|
||||
}
|
||||
#ifdef DEBUG_TOU_BIO
|
||||
fprintf(stderr, "BIO_tou_socket_non_fatal_error(%d) = 0\n", err);
|
||||
#endif
|
||||
return(0);
|
||||
}
|
||||
#endif
|
632
libretroshare/src/tcponudp/internal_tou.cc
Normal file
632
libretroshare/src/tcponudp/internal_tou.cc
Normal file
|
@ -0,0 +1,632 @@
|
|||
/*
|
||||
* "$Id: internal_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".
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/**********************************************************
|
||||
* There appears (was) to be an elusive bug in the tou internals.
|
||||
* most likely to be in the packing and unpacking of the
|
||||
* data queues.
|
||||
*
|
||||
* This test is designed to load the queues up and then
|
||||
* transfer the data, repeatly with different size packets.
|
||||
*
|
||||
* to do this effectively we need to access the TcpStream
|
||||
* objects, instead of the tou.h interface.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
|
||||
// for printing sockaddr
|
||||
#include "udplayer.h"
|
||||
#include "tcpstream.h"
|
||||
|
||||
#include "tou.h"
|
||||
#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 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]);
|
||||
|
||||
laddr.sin_port = htons(laddr_port);
|
||||
raddr.sin_port = htons(raddr_port);
|
||||
|
||||
/* so create the Udp/Tcp components */
|
||||
//UdpLayer udp1(laddr);
|
||||
//UdpLayer udp2(raddr);
|
||||
LossyUdpLayer udp1(laddr, 0.10);
|
||||
LossyUdpLayer udp2(raddr, 0.10);
|
||||
|
||||
/* check that they are okay */
|
||||
if ((!udp1.okay()) || (!udp2.okay()))
|
||||
{
|
||||
std::cerr << "Trouble opening udp ports!";
|
||||
std::cerr << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
TcpStream tcp1(&udp1);
|
||||
TcpStream tcp2(&udp2);
|
||||
|
||||
udp1.setRemoteAddr(raddr);
|
||||
udp2.setRemoteAddr(laddr);
|
||||
tcp1.connect(); // start the connection.
|
||||
|
||||
/* now connect them */
|
||||
while ((!tcp1.isConnected()) || (!tcp2.isConnected()))
|
||||
{
|
||||
usleep(10000); /* 10 ms */
|
||||
tcp1.tick();
|
||||
tcp2.tick();
|
||||
}
|
||||
|
||||
std::cerr << "Connection Established!" << std::endl;
|
||||
|
||||
for(i = 0; i < 10; i++)
|
||||
{
|
||||
|
||||
int size = 1024000;
|
||||
char rnddata1[size];
|
||||
char rnddata2[size];
|
||||
|
||||
for(j = 0; j < size; j++)
|
||||
{
|
||||
rnddata1[j] = (unsigned char) (255.0 *
|
||||
rand() / (RAND_MAX + 1.0));
|
||||
|
||||
rnddata2[j] = (unsigned char) (255.0 *
|
||||
rand() / (RAND_MAX + 1.0));
|
||||
}
|
||||
|
||||
/* for each iteration, we want to
|
||||
* (1) fill up the outgoing buffers with stuff
|
||||
*/
|
||||
|
||||
int sent1 = 0;
|
||||
int sent2 = 0;
|
||||
int fill1, fill2;
|
||||
int MaxSend = 1000000;
|
||||
|
||||
while((fill1 = tcp1.write_allowed()) && (sent1 < MaxSend))
|
||||
{
|
||||
/* fill with a random little bit more */
|
||||
int psize = (int) ((i + 1.0) * 255.0 *
|
||||
rand() / (RAND_MAX + 1.0));
|
||||
|
||||
/* don't overload */
|
||||
if (psize > fill1)
|
||||
{
|
||||
std::cerr << "LAST FILL1" << std::endl;
|
||||
psize = fill1;
|
||||
}
|
||||
|
||||
int ret = tcp1.write(&(rnddata1[sent1]), psize);
|
||||
|
||||
if (ret)
|
||||
{
|
||||
sent1 += ret;
|
||||
std::cerr << "Filled tcp1 with " << ret << " more bytes, total:";
|
||||
std::cerr << sent1 << " was allowed: " << fill1;
|
||||
std::cerr << std::endl;
|
||||
}
|
||||
|
||||
//tcp1.status(std::cerr);
|
||||
|
||||
}
|
||||
std::cerr << "Tcp1 full with " << sent1 << " bytes ";
|
||||
std::cerr << std::endl;
|
||||
|
||||
while((fill2 = tcp2.write_allowed()) && (sent2 < MaxSend))
|
||||
{
|
||||
/* fill with a random little bit more */
|
||||
/* slightly larger sizes */
|
||||
int psize = (int) ((i + 1.0) * 1255.0 *
|
||||
rand() / (RAND_MAX + 1.0));
|
||||
|
||||
/* don't overload */
|
||||
if (psize > fill2)
|
||||
{
|
||||
std::cerr << "LAST FILL2" << std::endl;
|
||||
psize = fill2;
|
||||
}
|
||||
|
||||
int ret = tcp2.write(&(rnddata2[sent2]), psize);
|
||||
|
||||
if (ret)
|
||||
{
|
||||
sent2 += ret;
|
||||
std::cerr << "Filled tcp2 with " << ret << " more bytes, total:";
|
||||
std::cerr << sent2 << " was allowed: " << fill2;
|
||||
std::cerr << std::endl;
|
||||
}
|
||||
|
||||
//tcp2.status(std::cerr);
|
||||
|
||||
}
|
||||
std::cerr << "Tcp2 full with " << sent2 << " bytes ";
|
||||
std::cerr << std::endl;
|
||||
|
||||
/* for every second iteration, fill up the read buffer before starting */
|
||||
if (i % 2 == 0)
|
||||
{
|
||||
for(j = 0; j < 100; j++)
|
||||
{
|
||||
tcp1.tick();
|
||||
tcp2.tick();
|
||||
}
|
||||
}
|
||||
|
||||
/* now we read/tick and empty */
|
||||
int read1 = 0;
|
||||
int read2 = 0;
|
||||
|
||||
while(read1 < sent2)
|
||||
{
|
||||
tcp1.tick();
|
||||
tcp2.tick();
|
||||
|
||||
/* fill with a random little bit more */
|
||||
/* This one has a small read, while tcp2 has a large read */
|
||||
int psize = (int) ((i + 1.0) * 100.0 *
|
||||
rand() / (RAND_MAX + 1.0));
|
||||
|
||||
/* limit to what we have! */
|
||||
if (psize > sent2 - read1)
|
||||
{
|
||||
std::cerr << "LAST READ1" << std::endl;
|
||||
psize = sent2 - read1;
|
||||
}
|
||||
|
||||
char rbuf[psize];
|
||||
int rsize = psize;
|
||||
|
||||
int ret = tcp1.read(rbuf, rsize);
|
||||
if (0 < ret)
|
||||
{
|
||||
/* check the data */
|
||||
for(j = 0; j < ret; j++)
|
||||
{
|
||||
if (rnddata2[read1 + j] != rbuf[j])
|
||||
{
|
||||
std::cerr << "Error Data Mismatch @ read1:" << read1;
|
||||
std::cerr << " + j:" << j << " rsize: " << rsize;
|
||||
std::cerr << " Index: " << read1 + j;
|
||||
std::cerr << std::endl;
|
||||
|
||||
int badoffset = read1 + j;
|
||||
for(int k = -10; k < 10; k++)
|
||||
{
|
||||
printf("Orig: %02x, Trans: %02x\n",
|
||||
(unsigned char) rnddata2[badoffset+k],
|
||||
(unsigned char) rbuf[j + k]);
|
||||
}
|
||||
|
||||
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
read1 += ret;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "Read Error: " << ret << std::endl;
|
||||
}
|
||||
std::cerr << "Requested " << psize << ", got " << ret << " bytes" << std::endl;
|
||||
std::cerr << "Read " << read1 << " of " << sent2 << " bytes" << std::endl;
|
||||
}
|
||||
|
||||
sleep(2);
|
||||
|
||||
|
||||
while(read2 < sent1)
|
||||
{
|
||||
tcp1.tick();
|
||||
tcp2.tick();
|
||||
|
||||
/* fill with a random little bit more */
|
||||
int psize = (int) ((i + 1.0) * 10000.0 *
|
||||
rand() / (RAND_MAX + 1.0));
|
||||
|
||||
/* limit to what we have! */
|
||||
if (psize > sent1 - read2)
|
||||
{
|
||||
std::cerr << "LAST READ2" << std::endl;
|
||||
psize = sent1 - read2;
|
||||
}
|
||||
|
||||
char rbuf[psize];
|
||||
int rsize = psize;
|
||||
|
||||
int ret = tcp2.read(rbuf, rsize);
|
||||
if (0 < ret)
|
||||
{
|
||||
/* check the data */
|
||||
for(j = 0; j < ret; j++)
|
||||
{
|
||||
if (rnddata1[read2 + j] != rbuf[j])
|
||||
{
|
||||
std::cerr << "Error Data Mismatch @ read2:" << read2;
|
||||
std::cerr << " + j:" << j << " rsize: " << rsize;
|
||||
std::cerr << " Index: " << read2 + j;
|
||||
std::cerr << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
read2 += ret;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "Read Error: " << ret << std::endl;
|
||||
}
|
||||
std::cerr << "Requested " << psize << ", got " << ret << " bytes" << std::endl;
|
||||
std::cerr << "Read " << read2 << " of " << sent1 << " bytes" << std::endl;
|
||||
}
|
||||
|
||||
std::cerr << "Iteration " << i + 1 << " finished correctly!" << std::endl;
|
||||
sleep(5);
|
||||
|
||||
}
|
||||
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));
|
||||
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;
|
||||
while((!doneWrite) || (!doneRead))
|
||||
{
|
||||
/* have a little break */
|
||||
//usleep(10000); /* 0.01 sec */
|
||||
//usleep(250000); /* 0.25 sec */
|
||||
usleep(500000); /* 0.50 sec */
|
||||
/* decide how much to send */
|
||||
sendsize = (int) (((float) (size / minsends)) *
|
||||
(rand() / (RAND_MAX + 1.0)));
|
||||
|
||||
/* limit send */
|
||||
if (sent + sendsize > size)
|
||||
{
|
||||
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;
|
||||
int readsize = (int) (((float) (size / minsends)) *
|
||||
(rand() / (RAND_MAX + 1.0)));
|
||||
|
||||
if (readsize > size - recvdsize)
|
||||
readsize = size - recvdsize;
|
||||
|
||||
if (0 < (ret = tou_read(sockfd2, &(recvd[recvdsize]), readsize)))
|
||||
{
|
||||
std::cerr << "TF(" << ret << ")" << 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;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
502
libretroshare/src/tcponudp/largefile_tou.cc
Normal file
502
libretroshare/src/tcponudp/largefile_tou.cc
Normal file
|
@ -0,0 +1,502 @@
|
|||
/*
|
||||
* "$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));
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
491
libretroshare/src/tcponudp/pair_tou.cc
Normal file
491
libretroshare/src/tcponudp/pair_tou.cc
Normal file
|
@ -0,0 +1,491 @@
|
|||
/*
|
||||
* "$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));
|
||||
#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
|
453
libretroshare/src/tcponudp/reset_tou.cc
Normal file
453
libretroshare/src/tcponudp/reset_tou.cc
Normal file
|
@ -0,0 +1,453 @@
|
|||
/*
|
||||
* "$Id: reset_tou.cc,v 1.4 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 ensure that tou networking
|
||||
* can be reset, and restarted.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
|
||||
// for printing sockaddr
|
||||
#include "udplayer.h"
|
||||
|
||||
#include "tou.h"
|
||||
#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 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 = 102400;
|
||||
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));
|
||||
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;
|
||||
while((!doneWrite) || (!doneRead))
|
||||
{
|
||||
/* have a little break */
|
||||
//usleep(10000); /* 0.01 sec */
|
||||
//usleep(250000); /* 0.25 sec */
|
||||
usleep(500000); /* 0.50 sec */
|
||||
/* decide how much to send */
|
||||
sendsize = (int) (((float) (size / minsends)) *
|
||||
(rand() / (RAND_MAX + 1.0)));
|
||||
|
||||
/* limit send */
|
||||
if (sent + sendsize > size)
|
||||
{
|
||||
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;
|
||||
int readsize = (int) (((float) (size / minsends)) *
|
||||
(rand() / (RAND_MAX + 1.0)));
|
||||
|
||||
if (readsize > size - recvdsize)
|
||||
readsize = size - recvdsize;
|
||||
|
||||
if (0 < (ret = tou_read(sockfd2, &(recvd[recvdsize]), readsize)))
|
||||
{
|
||||
std::cerr << "TF(" << ret << ")" << 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;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
249
libretroshare/src/tcponudp/tcppacket.cc
Normal file
249
libretroshare/src/tcponudp/tcppacket.cc
Normal file
|
@ -0,0 +1,249 @@
|
|||
/*
|
||||
* "$Id: tcppacket.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 "tcppacket.h"
|
||||
|
||||
/*
|
||||
* #include <arpa/inet.h>
|
||||
*/
|
||||
|
||||
#include "tou_net.h" /* for winsock.h -> htons etc */
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
/* NOTE That these BIT #defines will only
|
||||
* work on little endian machines....
|
||||
* due to the ntohs ...
|
||||
*/
|
||||
|
||||
/* flags 16bit is:
|
||||
*
|
||||
* || 0 1 2 3 | 4 5 6 7 || 8 9 | 10 11 12 13 14 15 ||
|
||||
* <- HLen -> <--- unused ---> <---- flags ------->
|
||||
* URG PSH SYN
|
||||
* ACK RST FIN
|
||||
*
|
||||
*
|
||||
* So in little endian world.
|
||||
* 0 & 1 -> unused...
|
||||
* URG -> bit 2 => 0x0004
|
||||
* ACK -> bit 3 => 0x0008
|
||||
* PSH -> bit 4 => 0x0010
|
||||
* RST -> bit 5 => 0x0020
|
||||
* SYN -> bit 6 => 0x0040
|
||||
* FIN -> bit 7 => 0x0080
|
||||
*
|
||||
* and second byte 0-3 -> hlen, 4-7 unused.
|
||||
*/
|
||||
|
||||
#define TCP_URG_BIT 0x0004
|
||||
#define TCP_ACK_BIT 0x0008
|
||||
#define TCP_PSH_BIT 0x0010
|
||||
#define TCP_RST_BIT 0x0020
|
||||
#define TCP_SYN_BIT 0x0040
|
||||
#define TCP_FIN_BIT 0x0080
|
||||
|
||||
|
||||
TcpPacket::TcpPacket(uint8 *ptr, int size)
|
||||
:data(0), datasize(0), seqno(0), ackno(0), hlen_flags(0),
|
||||
winsize(0), ts(0), retrans(0)
|
||||
{
|
||||
if (size > 0)
|
||||
{
|
||||
datasize = size;
|
||||
data = (uint8 *) malloc(datasize);
|
||||
memcpy(data, (void *) ptr, size);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
TcpPacket::TcpPacket() /* likely control packet */
|
||||
:data(0), datasize(0), seqno(0), ackno(0), hlen_flags(0),
|
||||
winsize(0), ts(0), retrans(0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
TcpPacket::~TcpPacket()
|
||||
{
|
||||
if (data)
|
||||
free(data);
|
||||
}
|
||||
|
||||
|
||||
int TcpPacket::writePacket(void *buf, int &size)
|
||||
{
|
||||
if (size < TCP_PSEUDO_HDR_SIZE + datasize)
|
||||
{
|
||||
size = 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* byte: 0 => uint16 srcport = 0 */
|
||||
*((uint16 *) &(((uint8 *) buf)[0])) = htons(0);
|
||||
|
||||
/* byte: 2 => uint16 destport = 0 */
|
||||
*((uint16 *) &(((uint8 *) buf)[2])) = htons(0);
|
||||
|
||||
/* byte: 4 => uint32 seqno */
|
||||
*((uint32 *) &(((uint8 *) buf)[4])) = htonl(seqno);
|
||||
|
||||
/* byte: 8 => uint32 ackno */
|
||||
*((uint32 *) &(((uint8 *) buf)[8])) = htonl(ackno);
|
||||
|
||||
/* byte: 12 => uint16 len + flags */
|
||||
*((uint16 *) &(((uint8 *) buf)[12])) = htons(hlen_flags);
|
||||
|
||||
/* byte: 14 => uint16 winsize */
|
||||
*((uint16 *) &(((uint8 *) buf)[14])) = htons(winsize);
|
||||
|
||||
/* byte: 16 => uint16 chksum */
|
||||
*((uint16 *) &(((uint8 *) buf)[16])) = htons(0);
|
||||
|
||||
/* byte: 18 => uint16 urgptr */
|
||||
*((uint16 *) &(((uint8 *) buf)[18])) = htons(0);
|
||||
|
||||
/* total 20 bytes */
|
||||
|
||||
/* now the data */
|
||||
memcpy((void *) &(((uint8 *) buf)[20]), data, datasize);
|
||||
|
||||
return size = TCP_PSEUDO_HDR_SIZE + datasize;
|
||||
}
|
||||
|
||||
|
||||
int TcpPacket::readPacket(void *buf, int size)
|
||||
{
|
||||
if (size < TCP_PSEUDO_HDR_SIZE)
|
||||
{
|
||||
std::cerr << "TcpPacket::readPacket() Failed Too Small!";
|
||||
std::cerr << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* byte: 0 => uint16 srcport = 0 *******************
|
||||
*((uint16 *) &(((uint8 *) buf)[0])) = htons(0);
|
||||
***********/
|
||||
|
||||
/* byte: 2 => uint16 destport = 0 ******************
|
||||
*((uint16 *) &(((uint8 *) buf)[2])) = htons(0);
|
||||
***********/
|
||||
|
||||
/* byte: 4 => uint32 seqno */
|
||||
seqno = ntohl( *((uint32 *) &(((uint8 *) buf)[4])) );
|
||||
|
||||
/* byte: 8 => uint32 ackno */
|
||||
ackno = ntohl( *((uint32 *) &(((uint8 *) buf)[8])) );
|
||||
|
||||
/* byte: 12 => uint16 len + flags */
|
||||
hlen_flags = ntohs( *((uint16 *) &(((uint8 *) buf)[12])) );
|
||||
|
||||
/* byte: 14 => uint16 winsize */
|
||||
winsize = ntohs( *((uint16 *) &(((uint8 *) buf)[14])) );
|
||||
|
||||
/* byte: 16 => uint16 chksum *************************
|
||||
*((uint16 *) &(((uint8 *) buf)[16])) = htons(0);
|
||||
***********/
|
||||
|
||||
/* byte: 18 => uint16 urgptr *************************
|
||||
*((uint16 *) &(((uint8 *) buf)[18])) = htons(0);
|
||||
***********/
|
||||
|
||||
/* total 20 bytes */
|
||||
|
||||
if (data)
|
||||
{
|
||||
free(data);
|
||||
}
|
||||
datasize = size - TCP_PSEUDO_HDR_SIZE;
|
||||
data = (uint8 *) malloc(datasize);
|
||||
|
||||
/* now the data */
|
||||
memcpy(data, (void *) &(((uint8 *) buf)[20]), datasize);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
/* flags */
|
||||
bool TcpPacket::hasSyn()
|
||||
{
|
||||
return (hlen_flags & TCP_SYN_BIT);
|
||||
}
|
||||
|
||||
bool TcpPacket::hasFin()
|
||||
{
|
||||
return (hlen_flags & TCP_FIN_BIT);
|
||||
}
|
||||
|
||||
bool TcpPacket::hasAck()
|
||||
{
|
||||
return (hlen_flags & TCP_ACK_BIT);
|
||||
}
|
||||
|
||||
bool TcpPacket::hasRst()
|
||||
{
|
||||
return (hlen_flags & TCP_RST_BIT);
|
||||
}
|
||||
|
||||
|
||||
void TcpPacket::setSyn()
|
||||
{
|
||||
hlen_flags |= TCP_SYN_BIT;
|
||||
}
|
||||
|
||||
void TcpPacket::setFin()
|
||||
{
|
||||
hlen_flags |= TCP_FIN_BIT;
|
||||
}
|
||||
|
||||
void TcpPacket::setRst()
|
||||
{
|
||||
hlen_flags |= TCP_RST_BIT;
|
||||
}
|
||||
|
||||
void TcpPacket::setAckFlag()
|
||||
{
|
||||
hlen_flags |= TCP_ACK_BIT;
|
||||
}
|
||||
|
||||
void TcpPacket::setAck(uint32 val)
|
||||
{
|
||||
setAckFlag();
|
||||
ackno = val;
|
||||
}
|
||||
|
||||
uint32 TcpPacket::getAck()
|
||||
{
|
||||
return ackno;
|
||||
}
|
||||
|
||||
|
97
libretroshare/src/tcponudp/tcppacket.h
Normal file
97
libretroshare/src/tcponudp/tcppacket.h
Normal file
|
@ -0,0 +1,97 @@
|
|||
/*
|
||||
* "$Id: tcppacket.h,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".
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#ifndef TOU_TCP_PACKET_H
|
||||
#define TOU_TCP_PACKET_H
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
|
||||
typedef unsigned int uint32;
|
||||
typedef unsigned short uint16;
|
||||
typedef unsigned char uint8;
|
||||
|
||||
#define TCP_PSEUDO_HDR_SIZE 20
|
||||
|
||||
class TcpPacket
|
||||
{
|
||||
public:
|
||||
|
||||
uint8 *data;
|
||||
int datasize;
|
||||
|
||||
|
||||
/* ports aren't needed -> in udp
|
||||
* uint16 srcport, destport
|
||||
**************************/
|
||||
uint32 seqno, ackno;
|
||||
uint16 hlen_flags;
|
||||
uint16 winsize;
|
||||
/* don't need these -> in udp + not supported
|
||||
uint16 chksum, urgptr;
|
||||
**************************/
|
||||
/* no options.
|
||||
**************************/
|
||||
|
||||
|
||||
/* other variables */
|
||||
double ts; /* transmit time */
|
||||
uint8 retrans; /* retransmit counter */
|
||||
|
||||
TcpPacket(uint8 *ptr, int size);
|
||||
TcpPacket(); /* likely control packet */
|
||||
~TcpPacket();
|
||||
|
||||
int writePacket(void *buf, int &size);
|
||||
int readPacket(void *buf, int size);
|
||||
|
||||
void *getData();
|
||||
void *releaseData();
|
||||
|
||||
void *setData(void *data, int size);
|
||||
int getDataSize();
|
||||
|
||||
/* flags */
|
||||
bool hasSyn();
|
||||
bool hasFin();
|
||||
bool hasAck();
|
||||
bool hasRst();
|
||||
|
||||
void setSyn();
|
||||
void setFin();
|
||||
void setRst();
|
||||
void setAckFlag();
|
||||
|
||||
void setAck(uint32 val);
|
||||
uint32 getAck();
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
2133
libretroshare/src/tcponudp/tcpstream.cc
Normal file
2133
libretroshare/src/tcponudp/tcpstream.cc
Normal file
File diff suppressed because it is too large
Load diff
213
libretroshare/src/tcponudp/tcpstream.h
Normal file
213
libretroshare/src/tcponudp/tcpstream.h
Normal file
|
@ -0,0 +1,213 @@
|
|||
/*
|
||||
* "$Id: tcpstream.h,v 1.5 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".
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#ifndef TOU_TCP_PROTO_H
|
||||
#define TOU_TCP_PROTO_H
|
||||
|
||||
|
||||
/* so the packet will contain
|
||||
* a tcp header + data.
|
||||
*
|
||||
* This is done simplistically for speed.
|
||||
*/
|
||||
|
||||
#include "tcppacket.h"
|
||||
#include "udplayer.h"
|
||||
|
||||
#define MAX_SEG 1500
|
||||
#define TCP_MAX_SEQ UINT_MAX
|
||||
#define TCP_MAX_WIN 65500
|
||||
#define TCP_ALIVE_TIMEOUT 20 /* 20 sec */
|
||||
#define TCP_RETRANS_TIMEOUT 1 /* 1 sec (Initial value) */
|
||||
#define kNoPktTimeout 60 /* 1 min */
|
||||
|
||||
|
||||
#define TCP_CLOSED 0
|
||||
#define TCP_LISTEN 1
|
||||
#define TCP_SYN_SENT 2
|
||||
#define TCP_SYN_RCVD 3
|
||||
#define TCP_ESTABLISHED 4
|
||||
#define TCP_FIN_WAIT_1 5
|
||||
#define TCP_FIN_WAIT_2 6
|
||||
#define TCP_TIMED_WAIT 7
|
||||
#define TCP_CLOSING 8
|
||||
#define TCP_CLOSE_WAIT 9
|
||||
#define TCP_LAST_ACK 10
|
||||
|
||||
class dataBuffer
|
||||
{
|
||||
public:
|
||||
uint8 data[MAX_SEG];
|
||||
};
|
||||
|
||||
#include <list>
|
||||
#include <deque>
|
||||
|
||||
|
||||
class TcpStream
|
||||
{
|
||||
public:
|
||||
|
||||
TcpStream(UdpLayer *lyr);
|
||||
|
||||
/* user interface */
|
||||
int status(std::ostream &out);
|
||||
int connect();
|
||||
bool isConnected();
|
||||
|
||||
bool widle(); /* write idle */
|
||||
bool ridle(); /* read idle */
|
||||
uint32 wbytes();
|
||||
uint32 rbytes();
|
||||
|
||||
/* network interface (unreliable) */
|
||||
int receivePkt(void *dta, int size);
|
||||
int sendPkt(void *dta, int *size);
|
||||
|
||||
/* stream Interface */
|
||||
int write(char *dta, int size); /* write -> pkt -> net */
|
||||
int read(char *dta, int size); /* net -> pkt -> read */
|
||||
|
||||
/* check ahead for allowed bytes */
|
||||
int write_allowed();
|
||||
int read_pending();
|
||||
|
||||
int closeWrite(); /* non-standard, but for clean exit */
|
||||
int close(); /* standard unix behaviour */
|
||||
|
||||
int tick(); /* check iface etc */
|
||||
/* internal */
|
||||
|
||||
int cleanup();
|
||||
|
||||
/* incoming data */
|
||||
int recv();
|
||||
int handleIncoming(TcpPacket *pkt);
|
||||
int incoming_Closed(TcpPacket *pkt);
|
||||
int incoming_SynSent(TcpPacket *pkt);
|
||||
int incoming_SynRcvd(TcpPacket *pkt);
|
||||
int incoming_Established(TcpPacket *pkt);
|
||||
int incoming_FinWait1(TcpPacket *pkt);
|
||||
int incoming_FinWait2(TcpPacket *pkt);
|
||||
int incoming_TimedWait(TcpPacket *pkt);
|
||||
int incoming_Closing(TcpPacket *pkt);
|
||||
int incoming_CloseWait(TcpPacket *pkt);
|
||||
int incoming_LastAck(TcpPacket *pkt);
|
||||
|
||||
int check_InPkts();
|
||||
int UpdateInWinSize();
|
||||
|
||||
/* outgoing data */
|
||||
int toSend(TcpPacket *pkt, bool retrans = true);
|
||||
void acknowledge();
|
||||
void calcWinSize();
|
||||
int send();
|
||||
int retrans();
|
||||
|
||||
int sendAck();
|
||||
|
||||
|
||||
uint32 genSequenceNo();
|
||||
bool isOldSequence(uint32 tst, uint32 curr);
|
||||
|
||||
/* data (in -> pkts) && (pkts -> out) */
|
||||
|
||||
/* for small amounts of data */
|
||||
uint8 inData[MAX_SEG];
|
||||
uint32 inSize;
|
||||
|
||||
|
||||
/* two variable sized buffers required here */
|
||||
uint8 outDataRead[MAX_SEG];
|
||||
uint32 outSizeRead;
|
||||
uint8 outDataNet[MAX_SEG];
|
||||
uint32 outSizeNet;
|
||||
|
||||
/* get packed into here as size increases */
|
||||
std::deque<dataBuffer *> inQueue, outQueue;
|
||||
|
||||
/* packets waiting for acks */
|
||||
std::list<TcpPacket *> inPkt, outPkt;
|
||||
|
||||
|
||||
uint8 state; /* stream state */
|
||||
bool inStreamActive;
|
||||
bool outStreamActive;
|
||||
|
||||
uint32 outSeqno; /* next out */
|
||||
uint32 outAcked; /* other size has received */
|
||||
uint32 outWinSize; /* we allowed to send */
|
||||
|
||||
uint32 inAckno; /* next expected */
|
||||
uint32 inWinSize; /* allowing other to send */
|
||||
uint32 rrt;
|
||||
|
||||
/* some (initially) consts */
|
||||
uint32 maxWinSize;
|
||||
uint32 keepAliveTimeout;
|
||||
double retransTimeout;
|
||||
|
||||
/* some timers */
|
||||
double keepAliveTimer;
|
||||
double lastIncomingPkt;
|
||||
|
||||
/* tracking */
|
||||
uint32 lastSentAck;
|
||||
uint32 lastSentWinSize;
|
||||
uint32 initOurSeqno;
|
||||
uint32 initPeerSeqno;
|
||||
|
||||
uint32 lastWriteTF,lastReadTF;
|
||||
uint16 wcount, rcount;
|
||||
|
||||
int errorState;
|
||||
|
||||
/* RoundTripTime estimations */
|
||||
double rtt_est;
|
||||
double rtt_dev;
|
||||
|
||||
/* congestion limits */
|
||||
uint32 congestThreshold;
|
||||
uint32 congestWinSize;
|
||||
uint32 congestUpdate;
|
||||
|
||||
|
||||
/* UdpLayer */
|
||||
UdpLayer *udp;
|
||||
};
|
||||
|
||||
|
||||
/* for debugging */
|
||||
|
||||
#ifdef TCP_DEBUG_STREAM_EXTRA /* for extra checking! */
|
||||
int setupBinaryCheck(std::string fname);
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
500
libretroshare/src/tcponudp/test_tou.cc
Normal file
500
libretroshare/src/tcponudp/test_tou.cc
Normal file
|
@ -0,0 +1,500 @@
|
|||
/*
|
||||
* "$Id: test_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
|
||||
|
||||
/* shouldn't do this - but for convenience
|
||||
* using tou_net.h for universal fns
|
||||
* generally this should be only internal to libtou.h
|
||||
*
|
||||
* This includes the whole networking interface
|
||||
*/
|
||||
|
||||
#include "tou_net.h"
|
||||
|
||||
/* These three includes appear to work in both W & L.
|
||||
* and they shouldn't!!!! maybe cygwin is allowing it...
|
||||
* will only use them for tou test fns.
|
||||
*
|
||||
* they appear to provide getopt + read/write in windows.
|
||||
*/
|
||||
|
||||
#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.
|
||||
*
|
||||
*/
|
||||
|
||||
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);
|
||||
#else
|
||||
int sockfd = tou_socket(PF_INET, SOCK_STREAM, 0);
|
||||
#endif
|
||||
if (sockfd < 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;
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
std::cerr << "Socket Created" << std::endl;
|
||||
|
||||
|
||||
/* make nonblocking */
|
||||
#ifdef USE_TCP_SOCKET
|
||||
int err = tounet_fcntl(sockfd,F_SETFL,O_NONBLOCK);
|
||||
#else
|
||||
int err = 0;
|
||||
#endif
|
||||
if (err < 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));
|
||||
#else
|
||||
err = tou_bind(sockfd, (struct sockaddr *) &laddr, sizeof(laddr));
|
||||
#endif
|
||||
if (err < 0)
|
||||
{
|
||||
std::cerr << "Error: Cannot bind socket: ";
|
||||
std::cerr << err << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::cerr << "Socket Bound to: " << laddr << std::endl;
|
||||
|
||||
if (toConnect)
|
||||
{
|
||||
std::cerr << "Socket 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));
|
||||
#endif
|
||||
if (err < 0)
|
||||
{
|
||||
#ifndef USE_TCP_SOCKET
|
||||
errno = tou_errno(sockfd);
|
||||
#endif
|
||||
if (errno != EINPROGRESS)
|
||||
{
|
||||
std::cerr << "Cannot Connect!" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
#ifdef USE_TCP_SOCKET
|
||||
while(0 == (err = Check_Socket(sockfd)))
|
||||
#else
|
||||
while(0 == (err = tou_connected(sockfd)))
|
||||
#endif
|
||||
{
|
||||
std::cerr << "Waiting for Connect!" << std::endl;
|
||||
sleep(1);
|
||||
}
|
||||
if (err < 0)
|
||||
{
|
||||
std::cerr << "Connect Failed" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
// else connected!
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "Socket Listening " << std::endl;
|
||||
/* listen */
|
||||
#ifdef USE_TCP_SOCKET
|
||||
err = listen(sockfd, 1);
|
||||
#else
|
||||
//err = tou_listen(sockfd, 1);
|
||||
err = tou_listenfor(sockfd,
|
||||
(struct sockaddr *) &raddr, sizeof(raddr));
|
||||
#endif
|
||||
|
||||
/* accept */
|
||||
struct sockaddr_in inaddr;
|
||||
socklen_t addrlen = sizeof(inaddr);
|
||||
int nsock;
|
||||
|
||||
#ifdef USE_TCP_SOCKET
|
||||
while(0 > (nsock = accept(sockfd,
|
||||
(struct sockaddr *) &inaddr, &addrlen)))
|
||||
#else
|
||||
while(0 > (nsock = tou_accept(sockfd,
|
||||
(struct sockaddr *) &inaddr, &addrlen)))
|
||||
#endif
|
||||
{
|
||||
#ifndef USE_TCP_SOCKET
|
||||
errno = tou_errno(sockfd);
|
||||
#endif
|
||||
if (errno != EAGAIN)
|
||||
{
|
||||
std::cerr << "Cannot Connect!" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
sleep(1);
|
||||
}
|
||||
/* changed sockfd */
|
||||
sockfd = nsock;
|
||||
std::cerr << "Socket Accepted from: " << inaddr << std::endl;
|
||||
}
|
||||
|
||||
std::cerr << "Socket Connected" << std::endl;
|
||||
|
||||
if (toConnect)
|
||||
{
|
||||
/* send data */
|
||||
int bufsize = 15011;
|
||||
char buffer[bufsize];
|
||||
int readsize = 0;
|
||||
|
||||
tounet_fcntl(0, F_SETFL, O_NONBLOCK);
|
||||
|
||||
bool done = false;
|
||||
bool blockread = false;
|
||||
while(!done)
|
||||
{
|
||||
sleep(1);
|
||||
//usleep(10000);
|
||||
//usleep(1000);
|
||||
if (blockread != true)
|
||||
{
|
||||
readsize = read(0, buffer, bufsize);
|
||||
}
|
||||
if (readsize == 0)
|
||||
{
|
||||
/* eof */
|
||||
done = true;
|
||||
}
|
||||
else if ((readsize == -1) && ( EAGAIN == errno ))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
/* now we write */
|
||||
#ifdef USE_TCP_SOCKET
|
||||
if (-1 == write(sockfd, buffer, readsize))
|
||||
#else
|
||||
if (-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;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USE_TCP_SOCKET
|
||||
close(sockfd);
|
||||
#else
|
||||
/* this is blocking??? */
|
||||
tou_close(sockfd);
|
||||
#endif
|
||||
|
||||
std::cerr << "Transfer Complete: " << totalwbytes << " bytes";
|
||||
std::cerr << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* recv data */
|
||||
int bufsize = 1523;
|
||||
char data[bufsize];
|
||||
tounet_fcntl(1,F_SETFL,O_NONBLOCK);
|
||||
while(1)
|
||||
{
|
||||
sleep(1);
|
||||
//usleep(10000);
|
||||
//usleep(1000);
|
||||
int writesize = bufsize;
|
||||
int ret;
|
||||
|
||||
#ifdef USE_TCP_SOCKET
|
||||
if (0 < (ret = read(sockfd, data, writesize)))
|
||||
#else
|
||||
if (0 < (ret = tou_read(sockfd, data, writesize)))
|
||||
#endif
|
||||
|
||||
{
|
||||
std::cerr << "TF(" << ret << ")" << std::endl;
|
||||
write(1, data, ret);
|
||||
totalrbytes += ret;
|
||||
}
|
||||
else if (ret == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
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);
|
||||
#else
|
||||
tou_close(sockfd);
|
||||
#endif
|
||||
|
||||
std::cerr << "Transfer complete :" << totalrbytes;
|
||||
std::cerr << " bytes" << std::endl;
|
||||
close(1);
|
||||
|
||||
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
|
601
libretroshare/src/tcponudp/tou.cc
Normal file
601
libretroshare/src/tcponudp/tou.cc
Normal file
|
@ -0,0 +1,601 @@
|
|||
/*
|
||||
* "$Id: tou.cc,v 1.7 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 "tou.h"
|
||||
|
||||
static const int kInitStreamTable = 5;
|
||||
|
||||
#include "udplayer.h"
|
||||
#include "tcpstream.h"
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#define DEBUG_TOU_INTERFACE 1
|
||||
|
||||
struct TcpOnUdp_t
|
||||
{
|
||||
int tou_fd;
|
||||
int lasterrno;
|
||||
UdpLayer *udp;
|
||||
TcpStream *tcp;
|
||||
bool know_eaddr;
|
||||
struct sockaddr_in extaddr;
|
||||
bool idle;
|
||||
};
|
||||
|
||||
typedef struct TcpOnUdp_t TcpOnUdp;
|
||||
|
||||
static std::vector<TcpOnUdp *> tou_streams;
|
||||
|
||||
static int tou_inited = 0;
|
||||
|
||||
static int tou_tick_all();
|
||||
static int tou_init()
|
||||
{
|
||||
if (tou_inited)
|
||||
return 1;
|
||||
|
||||
tou_streams.resize(kInitStreamTable);
|
||||
|
||||
tou_inited = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* open - which does nothing */
|
||||
int tou_socket(int /*domain*/, int /*type*/, int /*protocol*/)
|
||||
{
|
||||
tou_init();
|
||||
for(unsigned int i = 1; i < tou_streams.size(); i++)
|
||||
{
|
||||
if (tou_streams[i] == NULL)
|
||||
{
|
||||
tou_streams[i] = new TcpOnUdp();
|
||||
tou_streams[i] -> tou_fd = i;
|
||||
tou_streams[i] -> know_eaddr = false;
|
||||
tou_streams[i] -> udp = NULL;
|
||||
tou_streams[i] -> tcp = NULL;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
TcpOnUdp *tou = new TcpOnUdp();
|
||||
|
||||
tou_streams.push_back(tou);
|
||||
|
||||
if (tou == tou_streams[tou_streams.size() -1])
|
||||
{
|
||||
tou -> tou_fd = tou_streams.size() -1;
|
||||
tou -> know_eaddr = false;
|
||||
tou -> udp = NULL;
|
||||
tou -> tcp = NULL;
|
||||
return tou->tou_fd;
|
||||
}
|
||||
|
||||
tou -> lasterrno = EUSERS;
|
||||
|
||||
return -1;
|
||||
|
||||
#ifdef DEBUG_TOU_INTERFACE
|
||||
std::cerr << "tou_socket() FAILED" << std::endl;
|
||||
exit(1);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* bind - opens the udp port */
|
||||
int tou_bind(int sockfd, const struct sockaddr *my_addr,
|
||||
socklen_t addrlen)
|
||||
{
|
||||
if (tou_streams[sockfd] == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
TcpOnUdp *tous = tou_streams[sockfd];
|
||||
|
||||
if (tous->udp)
|
||||
{
|
||||
tous -> lasterrno = EADDRINUSE;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (tous->tcp)
|
||||
{
|
||||
tous -> lasterrno = EADDRINUSE;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (addrlen != sizeof(struct sockaddr_in))
|
||||
{
|
||||
tous -> lasterrno = EADDRNOTAVAIL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* tous->udp = new UdpLayer( *((struct sockaddr_in *) my_addr));
|
||||
*/
|
||||
// for testing - drop 5% of packets... */
|
||||
//tous->udp = new LossyUdpLayer( *((struct sockaddr_in *) my_addr), 0.05);
|
||||
tous->udp = new UdpLayer( *((struct sockaddr_in *) my_addr));
|
||||
/* check the bind succeeded */
|
||||
if (!(tous->udp->okay()))
|
||||
{
|
||||
delete (tous->udp);
|
||||
tous->udp = NULL;
|
||||
tous -> lasterrno = EADDRINUSE;
|
||||
return -1;
|
||||
}
|
||||
|
||||
tous->tcp = new TcpStream(tous->udp);
|
||||
|
||||
tous->tcp->tick();
|
||||
tou_tick_all();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* records peers address, and sends syn pkt
|
||||
* the timeout is very slow initially - to give
|
||||
* the peer a chance to startup
|
||||
*
|
||||
* - like a tcp/ip connection, the connect
|
||||
* will return -1 EAGAIN, until connection complete.
|
||||
* - always non blocking.
|
||||
*/
|
||||
int tou_connect(int sockfd, const struct sockaddr *serv_addr,
|
||||
socklen_t addrlen)
|
||||
{
|
||||
if (tou_streams[sockfd] == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
TcpOnUdp *tous = tou_streams[sockfd];
|
||||
|
||||
|
||||
if (addrlen != sizeof(struct sockaddr_in))
|
||||
{
|
||||
tous -> lasterrno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (tous->tcp->state == 0)
|
||||
{
|
||||
tous->udp->setRemoteAddr(*((struct sockaddr_in *) serv_addr));
|
||||
}
|
||||
|
||||
tous->tcp->connect();
|
||||
tous->tcp->tick();
|
||||
tou_tick_all();
|
||||
if (tous->tcp->isConnected())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
tous -> lasterrno = EINPROGRESS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int tou_listen(int sockfd, int backlog)
|
||||
{
|
||||
tou_tick_all();
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* slightly different - returns sockfd on connection */
|
||||
int tou_accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen)
|
||||
{
|
||||
if (tou_streams[sockfd] == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
TcpOnUdp *tous = tou_streams[sockfd];
|
||||
|
||||
if (*addrlen != sizeof(struct sockaddr_in))
|
||||
{
|
||||
tous -> lasterrno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
//tous->tcp->connect();
|
||||
tous->tcp->tick();
|
||||
tou_tick_all();
|
||||
if (tous->tcp->isConnected())
|
||||
{
|
||||
// should get remote address
|
||||
tous->udp->getRemoteAddr(*((struct sockaddr_in *) addr));
|
||||
return sockfd;
|
||||
}
|
||||
|
||||
tous -> lasterrno = EAGAIN;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int tou_listenfor(int sockfd, const struct sockaddr *serv_addr,
|
||||
socklen_t addrlen)
|
||||
{
|
||||
if (tou_streams[sockfd] == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
TcpOnUdp *tous = tou_streams[sockfd];
|
||||
|
||||
if (addrlen != sizeof(struct sockaddr_in))
|
||||
{
|
||||
tous -> lasterrno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (tous->tcp->state == 0)
|
||||
{
|
||||
tous->udp->setRemoteAddr(*((struct sockaddr_in *) serv_addr));
|
||||
}
|
||||
|
||||
tous->tcp->tick();
|
||||
tou_tick_all();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This is a udp socket - after all
|
||||
* independent operation from all of the
|
||||
* stream stuff.
|
||||
*/
|
||||
int tou_extudp(const struct sockaddr *ext, socklen_t tolen)
|
||||
{
|
||||
/* request a udp to listen on, in a leachy kinda way */
|
||||
std::vector<TcpOnUdp *>::iterator it;
|
||||
for(it = tou_streams.begin(); it != tou_streams.end(); it++)
|
||||
{
|
||||
if ((*it) && ((*it)->udp))
|
||||
{
|
||||
if ((*it)->know_eaddr)
|
||||
{
|
||||
*((struct sockaddr_in *) ext) = (*it)->extaddr;
|
||||
return (*it)->tou_fd;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int tou_extaddr(int sockfd, const struct sockaddr *ext, socklen_t tolen)
|
||||
{
|
||||
if (tou_streams[sockfd] == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
TcpOnUdp *tous = tou_streams[sockfd];
|
||||
tous -> know_eaddr = true;
|
||||
tous -> extaddr = *((struct sockaddr_in *) ext);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
ssize_t tou_recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen)
|
||||
{
|
||||
if (tou_streams[sockfd] == NULL)
|
||||
{
|
||||
std::cerr << "tou_recvfrom() Invalid sockfd:" << sockfd;
|
||||
std::cerr << std::endl;
|
||||
return -1;
|
||||
}
|
||||
TcpOnUdp *tous = tou_streams[sockfd];
|
||||
|
||||
if (*fromlen != sizeof(struct sockaddr_in))
|
||||
{
|
||||
std::cerr << "tou_recvfrom() Invalid addr size";
|
||||
std::cerr << std::endl;
|
||||
tous -> lasterrno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* extra checks */
|
||||
if ((!tous->tcp) || (!tous->udp))
|
||||
{
|
||||
std::cerr << "tou_recvfrom() Bad sockfd (!udp) || (!tcp) :" << sockfd;
|
||||
std::cerr << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (tous->tcp->state == 0)
|
||||
{
|
||||
//std::cerr << "tou_recvfrom() State = 0 .... Allow??";
|
||||
//std::cerr << std::endl;
|
||||
}
|
||||
|
||||
|
||||
if (tous->udp->okay())
|
||||
{
|
||||
int ret = tous->udp->recvRndPktfrom(buf,len,flags, from, fromlen);
|
||||
if (ret < 0)
|
||||
{
|
||||
//std::cerr << "tou_recvfrom() Sock Ok, Try Again later";
|
||||
//std::cerr << std::endl;
|
||||
tous -> lasterrno = EAGAIN;
|
||||
return -1;
|
||||
}
|
||||
std::cerr << "tou_recvfrom() Got a Packet on: " << sockfd;
|
||||
std::cerr << std::endl;
|
||||
tous -> lasterrno = 0;
|
||||
return ret;
|
||||
}
|
||||
std::cerr << "tou_recvfrom() Socket Not Okay:" << sockfd;
|
||||
std::cerr << std::endl;
|
||||
|
||||
tous -> lasterrno = EAGAIN;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
ssize_t tou_sendto(int sockfd, const void *buf, size_t len, int flags, const struct
|
||||
sockaddr *to, socklen_t tolen)
|
||||
{
|
||||
if (tou_streams[sockfd] == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
TcpOnUdp *tous = tou_streams[sockfd];
|
||||
|
||||
if (tolen != sizeof(struct sockaddr_in))
|
||||
{
|
||||
tous -> lasterrno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (tous->tcp->state == 0)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
if (tous->udp->okay())
|
||||
{
|
||||
tous->udp->sendToProxy(*((struct sockaddr_in *) to),
|
||||
buf, len);
|
||||
return len;
|
||||
}
|
||||
|
||||
tous -> lasterrno = EAGAIN;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int tou_connected(int sockfd)
|
||||
{
|
||||
if (tou_streams[sockfd] == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
TcpOnUdp *tous = tou_streams[sockfd];
|
||||
|
||||
tous->tcp->tick();
|
||||
tou_tick_all();
|
||||
|
||||
return (tous->tcp->state == 4);
|
||||
}
|
||||
|
||||
|
||||
/* standard stream read/write non-blocking of course
|
||||
*/
|
||||
|
||||
ssize_t tou_read(int sockfd, void *buf, size_t count)
|
||||
{
|
||||
if (tou_streams[sockfd] == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
TcpOnUdp *tous = tou_streams[sockfd];
|
||||
|
||||
tous->tcp->tick();
|
||||
tou_tick_all();
|
||||
|
||||
int err = tous->tcp->read((char *) buf, count);
|
||||
if (err < 0)
|
||||
{
|
||||
tous->lasterrno = tous->tcp->errorState;
|
||||
return -1;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
ssize_t tou_write(int sockfd, const void *buf, size_t count)
|
||||
{
|
||||
if (tou_streams[sockfd] == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
TcpOnUdp *tous = tou_streams[sockfd];
|
||||
|
||||
|
||||
int err = tous->tcp->write((char *) buf, count);
|
||||
if (err < 0)
|
||||
{
|
||||
tous->lasterrno = tous->tcp->errorState;
|
||||
tous->tcp->tick();
|
||||
tou_tick_all();
|
||||
return -1;
|
||||
}
|
||||
tous->tcp->tick();
|
||||
tou_tick_all();
|
||||
return err;
|
||||
}
|
||||
|
||||
/* check stream */
|
||||
int tou_maxread(int sockfd)
|
||||
{
|
||||
if (tou_streams[sockfd] == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
TcpOnUdp *tous = tou_streams[sockfd];
|
||||
tous->tcp->tick();
|
||||
tou_tick_all();
|
||||
|
||||
int ret = tous->tcp->read_pending();
|
||||
if (ret < 0)
|
||||
{
|
||||
tous->lasterrno = tous->tcp->errorState;
|
||||
return 0; // error detected next time.
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int tou_maxwrite(int sockfd)
|
||||
{
|
||||
if (tou_streams[sockfd] == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
TcpOnUdp *tous = tou_streams[sockfd];
|
||||
tous->tcp->tick();
|
||||
tou_tick_all();
|
||||
|
||||
int ret = tous->tcp->write_allowed();
|
||||
if (ret < 0)
|
||||
{
|
||||
tous->lasterrno = tous->tcp->errorState;
|
||||
return 0; // error detected next time?
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* close down the tcp over udp connection */
|
||||
int tou_close(int sockfd)
|
||||
{
|
||||
if (tou_streams[sockfd] == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
TcpOnUdp *tous = tou_streams[sockfd];
|
||||
|
||||
tous->tcp->tick();
|
||||
tou_tick_all();
|
||||
|
||||
/* shut it down */
|
||||
tous->tcp->close();
|
||||
tous->udp->close();
|
||||
delete tous->tcp;
|
||||
delete tous->udp;
|
||||
delete tous;
|
||||
tou_streams[sockfd] = NULL;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* get an error number */
|
||||
int tou_errno(int sockfd)
|
||||
{
|
||||
if (tou_streams[sockfd] == NULL)
|
||||
{
|
||||
return ENOTSOCK;
|
||||
}
|
||||
TcpOnUdp *tous = tou_streams[sockfd];
|
||||
return tous->lasterrno;
|
||||
}
|
||||
|
||||
int tou_clear_error(int sockfd)
|
||||
{
|
||||
if (tou_streams[sockfd] == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
TcpOnUdp *tous = tou_streams[sockfd];
|
||||
tous->lasterrno = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* unfortuately the library needs to be ticked. (not running a thread)
|
||||
* you can put it in a thread!
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Some helper functions for stuff.
|
||||
*
|
||||
*/
|
||||
|
||||
static int tou_passall();
|
||||
static int tou_active_rw();
|
||||
|
||||
static int nextActiveCycle;
|
||||
static int nextIdleCheck;
|
||||
static const int kActiveCycleStep = 1;
|
||||
static const int kIdleCheckStep = 5;
|
||||
|
||||
static int tou_tick_all()
|
||||
{
|
||||
tou_passall();
|
||||
return 1;
|
||||
|
||||
/* check timer */
|
||||
int ts = time(NULL);
|
||||
if (ts > nextActiveCycle)
|
||||
{
|
||||
tou_active_rw();
|
||||
nextActiveCycle += kActiveCycleStep;
|
||||
}
|
||||
if (ts > nextIdleCheck)
|
||||
{
|
||||
tou_passall();
|
||||
nextIdleCheck += kIdleCheckStep;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int tou_passall()
|
||||
{
|
||||
/* iterate through all and clean up old sockets.
|
||||
* check if idle are still idle.
|
||||
*/
|
||||
std::vector<TcpOnUdp *>::iterator it;
|
||||
for(it = tou_streams.begin(); it != tou_streams.end(); it++)
|
||||
{
|
||||
if ((*it) && ((*it)->tcp))
|
||||
{
|
||||
(*it)->tcp->tick();
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int tou_active_rw()
|
||||
{
|
||||
/* iterate through actives and tick
|
||||
*/
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
94
libretroshare/src/tcponudp/tou.h
Normal file
94
libretroshare/src/tcponudp/tou.h
Normal file
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
* "$Id: tou.h,v 1.4 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".
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#ifndef TOU_C_HEADER_H
|
||||
#define TOU_C_HEADER_H
|
||||
|
||||
|
||||
/* get OS-specific definitions for:
|
||||
* struct sockaddr, socklen_t, ssize_t
|
||||
*/
|
||||
|
||||
#ifndef WINDOWS_SYS
|
||||
#include <netinet/in.h>
|
||||
#else
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#include <stdio.h>
|
||||
typedef int socklen_t;
|
||||
#endif
|
||||
|
||||
|
||||
/* standard C interface (as Unix-like as possible)
|
||||
* for the tou (Tcp On Udp) library
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* UNIX interface: minimum for the SSL BIO interface */
|
||||
ssize_t tou_read(int sockfd, void *buf, size_t count);
|
||||
ssize_t tou_write(int sockfd, const void *buf, size_t count);
|
||||
int tou_close(int sockfd);
|
||||
|
||||
/* non-standard */
|
||||
int tou_errno(int sockfd);
|
||||
int tou_clear_error(int sockfd);
|
||||
|
||||
/* check stream */
|
||||
int tou_maxread(int sockfd);
|
||||
int tou_maxwrite(int sockfd);
|
||||
|
||||
|
||||
/* creation/connections */
|
||||
int tou_socket(int domain, int type, int protocol);
|
||||
int tou_bind(int sockfd, const struct sockaddr *my_addr, socklen_t addrlen);
|
||||
int tou_connect(int sockfd, const struct sockaddr *serv_addr, socklen_t addrlen);
|
||||
int tou_listen(int sockfd, int backlog);
|
||||
int tou_accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
|
||||
|
||||
/* udp interface */
|
||||
/* request an external udp port to use - returns sockfd */
|
||||
int tou_extudp(const struct sockaddr *ext, socklen_t tolen);
|
||||
int tou_extaddr(int sockfd, const struct sockaddr *to, socklen_t tolen);
|
||||
|
||||
ssize_t tou_recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen);
|
||||
ssize_t tou_sendto(int s, const void *buf, size_t len, int flags, const struct
|
||||
sockaddr *to, socklen_t tolen);
|
||||
|
||||
|
||||
/* non-standard bonuses */
|
||||
int tou_connected(int sockfd);
|
||||
int tou_listenfor(int sockfd, const struct sockaddr *serv_addr,
|
||||
socklen_t addrlen);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
75
libretroshare/src/tcponudp/tou_errno.h
Normal file
75
libretroshare/src/tcponudp/tou_errno.h
Normal file
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* "$Id: tou_errno.h,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".
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#ifndef TOU_ERRNO_HEADER
|
||||
#define TOU_ERRNO_HEADER
|
||||
|
||||
/* C Interface */
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*******
|
||||
* This defines the unix errno's for windows, these are
|
||||
* needed to determine error types, these are defined
|
||||
* to be the same as the unix ones.
|
||||
*/
|
||||
|
||||
/********************************** WINDOWS/UNIX SPECIFIC PART ******************/
|
||||
#ifdef WINDOWS_SYS
|
||||
|
||||
#define EAGAIN 11
|
||||
#define EWOULDBLOCK EAGAIN
|
||||
|
||||
#define EUSERS 87
|
||||
#define ENOTSOCK 88
|
||||
|
||||
#define EOPNOTSUPP 95
|
||||
|
||||
#define EADDRINUSE 98
|
||||
#define EADDRNOTAVAIL 99
|
||||
#define ENETDOWN 100
|
||||
#define ENETUNREACH 101
|
||||
|
||||
#define ECONNRESET 104
|
||||
|
||||
#define ETIMEDOUT 110
|
||||
#define ECONNREFUSED 111
|
||||
#define EHOSTDOWN 112
|
||||
#define EHOSTUNREACH 113
|
||||
#define EALREADY 114
|
||||
#define EINPROGRESS 115
|
||||
|
||||
|
||||
#endif
|
||||
/********************************** WINDOWS/UNIX SPECIFIC PART ******************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* C Interface */
|
||||
#endif
|
||||
|
||||
#endif /* TOU_ERRNO_HEADER */
|
346
libretroshare/src/tcponudp/tou_net.cc
Normal file
346
libretroshare/src/tcponudp/tou_net.cc
Normal file
|
@ -0,0 +1,346 @@
|
|||
/*
|
||||
* "$Id: tou_net.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 "tou_net.h"
|
||||
|
||||
|
||||
/********************************** WINDOWS/UNIX SPECIFIC PART ******************/
|
||||
#ifndef WINDOWS_SYS
|
||||
|
||||
/* Unix Version is easy -> just call the unix fn
|
||||
*/
|
||||
|
||||
#include <unistd.h> /* for close definition */
|
||||
|
||||
/* the universal interface */
|
||||
int tounet_init() { return 0; }
|
||||
int tounet_errno() { return errno; }
|
||||
|
||||
|
||||
/* check if we can modify the TTL on a UDP packet */
|
||||
int tounet_checkTTL(int fd) { return 1;}
|
||||
|
||||
|
||||
int tounet_inet_aton(const char *name, struct in_addr *addr)
|
||||
{
|
||||
return inet_aton(name, addr);
|
||||
}
|
||||
|
||||
int tounet_close(int fd) { return close(fd); }
|
||||
|
||||
int tounet_socket(int domain, int type, int protocol)
|
||||
{
|
||||
return socket(domain, type, protocol);
|
||||
}
|
||||
|
||||
int tounet_bind(int sockfd, const struct sockaddr *my_addr, socklen_t addrlen)
|
||||
{
|
||||
return bind(sockfd,my_addr,addrlen);
|
||||
}
|
||||
|
||||
int tounet_fcntl(int fd, int cmd, long arg)
|
||||
{
|
||||
return fcntl(fd, cmd, arg);
|
||||
}
|
||||
|
||||
int tounet_setsockopt(int s, int level, int optname,
|
||||
const void *optval, socklen_t optlen)
|
||||
{
|
||||
return setsockopt(s, level, optname, optval, optlen);
|
||||
}
|
||||
|
||||
ssize_t tounet_recvfrom(int s, void *buf, size_t len, int flags,
|
||||
struct sockaddr *from, socklen_t *fromlen)
|
||||
{
|
||||
return recvfrom(s, buf, len, flags, from, fromlen);
|
||||
}
|
||||
|
||||
ssize_t tounet_sendto(int s, const void *buf, size_t len, int flags,
|
||||
const struct sockaddr *to, socklen_t tolen)
|
||||
{
|
||||
return sendto(s, buf, len, flags, to, tolen);
|
||||
}
|
||||
|
||||
|
||||
/********************************** WINDOWS/UNIX SPECIFIC PART ******************/
|
||||
#else /* WINDOWS OS */
|
||||
|
||||
#include <iostream>
|
||||
|
||||
/* error handling */
|
||||
int tounet_int_errno;
|
||||
|
||||
int tounet_errno()
|
||||
{
|
||||
return tounet_int_errno;
|
||||
}
|
||||
|
||||
int tounet_init()
|
||||
{
|
||||
std::cerr << "tounet_init()" << std::endl;
|
||||
tounet_int_errno = 0;
|
||||
|
||||
// Windows Networking Init.
|
||||
WORD wVerReq = MAKEWORD(2,2);
|
||||
WSADATA wsaData;
|
||||
|
||||
if (0 != WSAStartup(wVerReq, &wsaData))
|
||||
{
|
||||
std::cerr << "Failed to Startup Windows Networking";
|
||||
std::cerr << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "Started Windows Networking";
|
||||
std::cerr << std::endl;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* check if we can modify the TTL on a UDP packet */
|
||||
int tounet_checkTTL(int fd)
|
||||
{
|
||||
std::cerr << "tounet_checkTTL()" << std::endl;
|
||||
int optlen = 4;
|
||||
char optval[optlen];
|
||||
|
||||
int ret = getsockopt(fd, IPPROTO_IP, IP_TTL, optval, &optlen);
|
||||
//int ret = getsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL, optval, &optlen);
|
||||
if (ret == SOCKET_ERROR)
|
||||
{
|
||||
ret = -1;
|
||||
tounet_int_errno = tounet_w2u_errno(WSAGetLastError());
|
||||
std::cerr << "tounet_checkTTL() Failed!";
|
||||
std::cerr << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "tounet_checkTTL() :";
|
||||
std::cerr << (int) optval[0] << ":";
|
||||
std::cerr << (int) optval[1] << ":";
|
||||
std::cerr << (int) optval[2] << ":";
|
||||
std::cerr << (int) optval[3] << ": RET: ";
|
||||
std::cerr << ret << ":";
|
||||
std::cerr << std::endl;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int tounet_close(int fd)
|
||||
{
|
||||
std::cerr << "tounet_close()" << std::endl;
|
||||
return closesocket(fd);
|
||||
}
|
||||
|
||||
int tounet_socket(int domain, int type, int protocol)
|
||||
{
|
||||
int osock = socket(domain, type, protocol);
|
||||
std::cerr << "tounet_socket()" << std::endl;
|
||||
|
||||
if ((unsigned) osock == INVALID_SOCKET)
|
||||
{
|
||||
// Invalidate socket Unix style.
|
||||
osock = -1;
|
||||
tounet_int_errno = tounet_w2u_errno(WSAGetLastError());
|
||||
}
|
||||
tounet_checkTTL(osock);
|
||||
return osock;
|
||||
}
|
||||
|
||||
int tounet_bind(int sockfd, const struct sockaddr *my_addr, socklen_t addrlen)
|
||||
{
|
||||
std::cerr << "tounet_bind()" << std::endl;
|
||||
int ret = bind(sockfd,my_addr,addrlen);
|
||||
if (ret != 0)
|
||||
{
|
||||
/* store unix-style error
|
||||
*/
|
||||
|
||||
ret = -1;
|
||||
tounet_int_errno = tounet_w2u_errno(WSAGetLastError());
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int tounet_fcntl(int fd, int cmd, long arg)
|
||||
{
|
||||
int ret;
|
||||
|
||||
unsigned long int on = 1;
|
||||
std::cerr << "tounet_fcntl()" << std::endl;
|
||||
|
||||
/* can only do NONBLOCK at the moment */
|
||||
if ((cmd != F_SETFL) || (arg != O_NONBLOCK))
|
||||
{
|
||||
std::cerr << "tounet_fcntl() limited to fcntl(fd, F_SETFL, O_NONBLOCK)";
|
||||
std::cerr << std::endl;
|
||||
tounet_int_errno = EOPNOTSUPP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = ioctlsocket(fd, FIONBIO, &on);
|
||||
|
||||
if (ret != 0)
|
||||
{
|
||||
/* store unix-style error
|
||||
*/
|
||||
|
||||
ret = -1;
|
||||
tounet_int_errno = tounet_w2u_errno(WSAGetLastError());
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int tounet_setsockopt(int s, int level, int optname,
|
||||
const void *optval, socklen_t optlen)
|
||||
{
|
||||
std::cerr << "tounet_setsockopt() val:" << *((int *) optval) << std::endl;
|
||||
std::cerr << "tounet_setsockopt() len:" << optlen << std::endl;
|
||||
if ((level != IPPROTO_IP) || (optname != IP_TTL))
|
||||
{
|
||||
std::cerr << "tounet_setsockopt() limited to ";
|
||||
std::cerr << "setsockopt(fd, IPPROTO_IP, IP_TTL, ....)";
|
||||
std::cerr << std::endl;
|
||||
tounet_int_errno = EOPNOTSUPP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int ret = setsockopt(s, level, optname, (const char *) optval, optlen);
|
||||
//int ret = setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL, (const char *) optval, optlen);
|
||||
if (ret == SOCKET_ERROR)
|
||||
{
|
||||
ret = -1;
|
||||
tounet_int_errno = tounet_w2u_errno(WSAGetLastError());
|
||||
}
|
||||
tounet_checkTTL(s);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ssize_t tounet_recvfrom(int s, void *buf, size_t len, int flags,
|
||||
struct sockaddr *from, socklen_t *fromlen)
|
||||
{
|
||||
std::cerr << "tounet_recvfrom()" << std::endl;
|
||||
int ret = recvfrom(s, (char *) buf, len, flags, from, fromlen);
|
||||
if (ret == SOCKET_ERROR)
|
||||
{
|
||||
ret = -1;
|
||||
tounet_int_errno = tounet_w2u_errno(WSAGetLastError());
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
ssize_t tounet_sendto(int s, const void *buf, size_t len, int flags,
|
||||
const struct sockaddr *to, socklen_t tolen)
|
||||
{
|
||||
std::cerr << "tounet_sendto()" << std::endl;
|
||||
int ret = sendto(s, (const char *) buf, len, flags, to, tolen);
|
||||
if (ret == SOCKET_ERROR)
|
||||
{
|
||||
ret = -1;
|
||||
tounet_int_errno = tounet_w2u_errno(WSAGetLastError());
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int tounet_w2u_errno(int err)
|
||||
{
|
||||
/* switch */
|
||||
std::cerr << "tou_net_w2u_errno(" << err << ")" << std::endl;
|
||||
switch(err)
|
||||
{
|
||||
case WSAEINPROGRESS:
|
||||
return EINPROGRESS;
|
||||
break;
|
||||
case WSAEWOULDBLOCK:
|
||||
return EINPROGRESS;
|
||||
break;
|
||||
case WSAENETUNREACH:
|
||||
return ENETUNREACH;
|
||||
break;
|
||||
case WSAETIMEDOUT:
|
||||
return ETIMEDOUT;
|
||||
break;
|
||||
case WSAEHOSTDOWN:
|
||||
return EHOSTDOWN;
|
||||
break;
|
||||
case WSAECONNREFUSED:
|
||||
return ECONNREFUSED;
|
||||
break;
|
||||
case WSAEADDRINUSE:
|
||||
return EADDRINUSE;
|
||||
break;
|
||||
case WSAEUSERS:
|
||||
return EUSERS;
|
||||
break;
|
||||
/* This one is returned for UDP recvfrom, when nothing there
|
||||
* but not a real error... translate into EINPROGRESS
|
||||
*/
|
||||
case WSAECONNRESET:
|
||||
std::cerr << "tou_net_w2u_errno(" << err << ")";
|
||||
std::cerr << " = WSAECONNRESET ---> EINPROGRESS";
|
||||
std::cerr << std::endl;
|
||||
return EINPROGRESS;
|
||||
break;
|
||||
/***
|
||||
*
|
||||
case WSAECONNRESET:
|
||||
return ECONNRESET;
|
||||
break;
|
||||
*
|
||||
***/
|
||||
|
||||
default:
|
||||
std::cerr << "tou_net_w2u_errno(" << err << ") Unknown";
|
||||
std::cerr << std::endl;
|
||||
break;
|
||||
}
|
||||
|
||||
return ECONNREFUSED; /* sensible default? */
|
||||
}
|
||||
|
||||
int tounet_inet_aton(const char *name, struct in_addr *addr)
|
||||
{
|
||||
return (((*addr).s_addr = inet_addr(name)) != INADDR_NONE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void sleep(int sec)
|
||||
{
|
||||
Sleep(sec * 1000);
|
||||
}
|
||||
|
||||
void usleep(int usec)
|
||||
{
|
||||
Sleep(usec / 1000);
|
||||
}
|
||||
|
||||
#endif
|
||||
/********************************** WINDOWS/UNIX SPECIFIC PART ******************/
|
||||
|
150
libretroshare/src/tcponudp/tou_net.h
Normal file
150
libretroshare/src/tcponudp/tou_net.h
Normal file
|
@ -0,0 +1,150 @@
|
|||
/*
|
||||
* "$Id: tou_net.h,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".
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#ifndef TOU_UNIVERSAL_NETWORK_HEADER
|
||||
#define TOU_UNIVERSAL_NETWORK_HEADER
|
||||
|
||||
/* C Interface */
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*******
|
||||
* This defines a (unix-like) universal networking layer
|
||||
* that should function on both windows and unix. (C - interface)
|
||||
*
|
||||
* This is of course only a subset of the full interface.
|
||||
* functions required are:
|
||||
*
|
||||
* int tounet_close(int fd);
|
||||
* int tounet_socket(int domain, int type, int protocol);
|
||||
* int tounet_bind(int sockfd, const struct sockaddr *my_addr,
|
||||
* socklen_t addrlen);
|
||||
* int tounet_fcntl(int fd, int cmd, long arg);
|
||||
* int tounet_setsockopt(int s, int level, int optname,
|
||||
* const void *optval, socklen_t optlen);
|
||||
* ssize_t tounet_recvfrom(int s, void *buf, size_t len, int flags,
|
||||
* struct sockaddr *from, socklen_t *fromlen);
|
||||
* ssize_t tounet_sendto(int s, const void *buf, size_t len, int flags,
|
||||
* const struct sockaddr *to, socklen_t tolen);
|
||||
*
|
||||
* There are some non-standard ones as well:
|
||||
* int tounet_errno(); for internal networking errors
|
||||
* int tounet_init(); required for windows
|
||||
* int tounet_checkTTL(); a check if we can modify the ttl
|
||||
*/
|
||||
|
||||
/* Some Types need to be defined before the interface can be declared
|
||||
*/
|
||||
/********************************** WINDOWS/UNIX SPECIFIC PART ******************/
|
||||
#ifndef WINDOWS_SYS
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
#else
|
||||
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
|
||||
#include <stdio.h> /* for ssize_t */
|
||||
typedef int socklen_t;
|
||||
typedef unsigned long in_addr_t;
|
||||
|
||||
#endif
|
||||
/********************************** WINDOWS/UNIX SPECIFIC PART ******************/
|
||||
|
||||
|
||||
/* the universal interface */
|
||||
int tounet_errno(); /* for internal networking errors */
|
||||
int tounet_init(); /* required for windows */
|
||||
int tounet_close(int fd);
|
||||
int tounet_socket(int domain, int type, int protocol);
|
||||
int tounet_bind(int sockfd, const struct sockaddr *my_addr, socklen_t addrlen);
|
||||
int tounet_fcntl(int fd, int cmd, long arg);
|
||||
int tounet_setsockopt(int s, int level, int optname,
|
||||
const void *optval, socklen_t optlen);
|
||||
ssize_t tounet_recvfrom(int s, void *buf, size_t len, int flags,
|
||||
struct sockaddr *from, socklen_t *fromlen);
|
||||
ssize_t tounet_sendto(int s, const void *buf, size_t len, int flags,
|
||||
const struct sockaddr *to, socklen_t tolen);
|
||||
|
||||
/* address filling */
|
||||
int tounet_inet_aton(const char *name, struct in_addr *addr);
|
||||
/* check if we can modify the TTL on a UDP packet */
|
||||
int tounet_checkTTL(int fd);
|
||||
|
||||
|
||||
|
||||
/* Extra stuff to declare for windows error handling (mimics unix errno)
|
||||
*/
|
||||
|
||||
/********************************** WINDOWS/UNIX SPECIFIC PART ******************/
|
||||
#ifdef WINDOWS_SYS
|
||||
|
||||
// Some Network functions that are missing from windows.
|
||||
//in_addr_t inet_netof(struct in_addr addr);
|
||||
//in_addr_t inet_network(char *inet_name);
|
||||
//int inet_aton(const char *name, struct in_addr *addr);
|
||||
|
||||
|
||||
// definitions for fcntl (NON_BLOCK) (random?)
|
||||
#define F_SETFL 0x1010
|
||||
#define O_NONBLOCK 0x0100
|
||||
|
||||
// definitions for setsockopt (TTL) (random?)
|
||||
//#define IPPROTO_IP 0x0011
|
||||
//#define IP_TTL 0x0110
|
||||
|
||||
/* define the Unix Error Codes that we use...
|
||||
* NB. we should make the same, but not necessary
|
||||
*/
|
||||
|
||||
#include "tou_errno.h"
|
||||
|
||||
int tounet_w2u_errno(int error);
|
||||
|
||||
/* also put the sleep commands in here (where else to go)
|
||||
* ms uses millisecs.
|
||||
* void Sleep(int ms);
|
||||
*/
|
||||
void sleep(int sec);
|
||||
void usleep(int usec);
|
||||
|
||||
#endif
|
||||
/********************************** WINDOWS/UNIX SPECIFIC PART ******************/
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* C Interface */
|
||||
#endif
|
||||
|
||||
#endif /* TOU_UNIVERSAL_NETWORK_HEADER */
|
284
libretroshare/src/tcponudp/udp_server.cc
Normal file
284
libretroshare/src/tcponudp/udp_server.cc
Normal file
|
@ -0,0 +1,284 @@
|
|||
/*
|
||||
* "$Id: udp_server.cc,v 1.4 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 "udplayer.h"
|
||||
#include "tcpstream.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
/* unix only
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
*/
|
||||
|
||||
#include "tou_net.h"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
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;
|
||||
|
||||
while(-1 != (c = getopt(argc, argv, "f:pco")))
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case 'p':
|
||||
isProxy = true;
|
||||
break;
|
||||
case 'c':
|
||||
toConnect = true;
|
||||
break;
|
||||
case 'o':
|
||||
stayOpen = true;
|
||||
break;
|
||||
case 'f':
|
||||
/* this can only work when the define below exists in tcpstream */
|
||||
#ifdef DEBUG_TCP_STREAM_EXTRA
|
||||
setupBinaryCheck(std::string(optarg));
|
||||
#else
|
||||
std::cerr << "Binary Check no Enabled!" << std::endl;
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
usage(argv[0]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (argc-optind < 4)
|
||||
{
|
||||
usage(argv[0]);
|
||||
return 1;
|
||||
}
|
||||
/* setup the local/remote addresses.
|
||||
*/
|
||||
|
||||
tounet_init();
|
||||
|
||||
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;
|
||||
|
||||
//LossyUdpLayer udpl(laddr, 0.01);
|
||||
UdpLayer udpl(laddr);
|
||||
if (!udpl.openSocket())
|
||||
{
|
||||
std::cerr << "Cannot Open Local Address: " << laddr << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
udpl.setRemoteAddr(raddr);
|
||||
|
||||
TcpStream tcp(&udpl);
|
||||
|
||||
if (toConnect)
|
||||
{
|
||||
tcp.connect();
|
||||
}
|
||||
|
||||
while(!tcp.isConnected())
|
||||
{
|
||||
sleep(1);
|
||||
std::cerr << "Waiting for TCP to Connect!" << std::endl;
|
||||
udpl.status(std::cerr);
|
||||
tcp.status(std::cerr);
|
||||
tcp.tick();
|
||||
}
|
||||
std::cerr << "TCP Connected***************************" << std::endl;
|
||||
udpl.status(std::cerr);
|
||||
tcp.status(std::cerr);
|
||||
std::cerr << "TCP Connected***************************" << std::endl;
|
||||
|
||||
int count = 1;
|
||||
|
||||
if (toConnect)
|
||||
{
|
||||
/* send data */
|
||||
int bufsize = 51;
|
||||
char buffer[bufsize];
|
||||
int readsize = 0;
|
||||
|
||||
tounet_fcntl(0, F_SETFL, O_NONBLOCK);
|
||||
|
||||
bool done = false;
|
||||
bool blockread = false;
|
||||
while(!done)
|
||||
{
|
||||
//sleep(1);
|
||||
usleep(10000);
|
||||
//usleep(1000);
|
||||
if (blockread != true)
|
||||
{
|
||||
readsize = read(0, buffer, bufsize);
|
||||
}
|
||||
if (readsize == 0)
|
||||
{
|
||||
/* eof */
|
||||
done = true;
|
||||
}
|
||||
else if ((readsize == -1) && ( EAGAIN == errno ))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
/* now we write */
|
||||
if (-1 == tcp.write(buffer, readsize))
|
||||
blockread = true;
|
||||
else
|
||||
blockread = false;
|
||||
|
||||
|
||||
tcp.tick();
|
||||
if (count++ % 10 == 0)
|
||||
{
|
||||
std::cerr << "******************************************" << std::endl;
|
||||
tcp.status(std::cerr);
|
||||
}
|
||||
}
|
||||
|
||||
tcp.closeWrite();
|
||||
|
||||
while(!tcp.widle())
|
||||
{
|
||||
sleep(1);
|
||||
//usleep(10000);
|
||||
//usleep(1000);
|
||||
tcp.tick();
|
||||
if (count++ % 10 == 0)
|
||||
{
|
||||
std::cerr << "Waiting for Idle()" << std::endl;
|
||||
std::cerr << "******************************************" << std::endl;
|
||||
tcp.status(std::cerr);
|
||||
}
|
||||
}
|
||||
|
||||
std::cerr << "Transfer Complete: " << tcp.wbytes() << " bytes";
|
||||
std::cerr << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* recv data */
|
||||
int bufsize = 1523;
|
||||
char data[bufsize];
|
||||
tounet_fcntl(1,F_SETFL,O_NONBLOCK);
|
||||
while(1)
|
||||
{
|
||||
//sleep(1);
|
||||
usleep(10000);
|
||||
//usleep(1000);
|
||||
//int writesize = bufsize;
|
||||
int ret;
|
||||
if (0 < (ret = tcp.read(data, bufsize)))
|
||||
{
|
||||
std::cerr << "TF(" << ret << ")" << std::endl;
|
||||
write(1, data, ret);
|
||||
}
|
||||
else if (ret == 0)
|
||||
{
|
||||
/* completed transfer */
|
||||
std::cerr << "Transfer complete :" << tcp.rbytes();
|
||||
std::cerr << " bytes" << std::endl;
|
||||
break;
|
||||
}
|
||||
|
||||
tcp.tick();
|
||||
if (count++ % 10 == 0)
|
||||
{
|
||||
std::cerr << "******************************************" << std::endl;
|
||||
tcp.status(std::cerr);
|
||||
}
|
||||
if ((!stayOpen) && tcp.ridle())
|
||||
{
|
||||
std::cerr << "Transfer Idle after " << tcp.rbytes();
|
||||
std::cerr << " bytes" << std::endl;
|
||||
close(1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
tcp.closeWrite();
|
||||
|
||||
/* tick for a bit */
|
||||
while((stayOpen) || (!tcp.ridle()))
|
||||
{
|
||||
tcp.tick();
|
||||
sleep(1);
|
||||
if (count++ % 10 == 0)
|
||||
{
|
||||
std::cerr << "Waiting for Idle()" << std::endl;
|
||||
std::cerr << "******************************************" << std::endl;
|
||||
tcp.status(std::cerr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ((!stayOpen) && tcp.ridle())
|
||||
{
|
||||
//std::cerr << "Transfer complete :" << tcp.rbytes();
|
||||
//std::cerr << " bytes" << std::endl;
|
||||
close(1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
472
libretroshare/src/tcponudp/udplayer.cc
Normal file
472
libretroshare/src/tcponudp/udplayer.cc
Normal file
|
@ -0,0 +1,472 @@
|
|||
/*
|
||||
* "$Id: udplayer.cc,v 1.8 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 "udplayer.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
|
||||
/*
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
*/
|
||||
|
||||
/*
|
||||
* #define DEBUG_UDP_LAYER 1
|
||||
*/
|
||||
|
||||
static const int UDP_DEF_TTL = 64;
|
||||
|
||||
class udpPacket
|
||||
{
|
||||
public:
|
||||
udpPacket(struct sockaddr_in *addr, void *dta, int dlen)
|
||||
:raddr(*addr), len(dlen)
|
||||
{
|
||||
data = malloc(len);
|
||||
memcpy(data, dta, len);
|
||||
}
|
||||
|
||||
~udpPacket()
|
||||
{
|
||||
if (data)
|
||||
{
|
||||
free(data);
|
||||
data = NULL;
|
||||
len = 0;
|
||||
}
|
||||
}
|
||||
|
||||
struct sockaddr_in raddr;
|
||||
void *data;
|
||||
int len;
|
||||
};
|
||||
|
||||
|
||||
std::ostream &operator<<(std::ostream &out, struct sockaddr_in &addr)
|
||||
{
|
||||
out << "[" << inet_ntoa(addr.sin_addr) << ":";
|
||||
out << htons(addr.sin_port) << "]";
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
bool operator==(struct sockaddr_in &addr, struct sockaddr_in &addr2)
|
||||
{
|
||||
if (addr.sin_family != addr2.sin_family)
|
||||
return false;
|
||||
if (addr.sin_addr.s_addr != addr2.sin_addr.s_addr)
|
||||
return false;
|
||||
if (addr.sin_port != addr2.sin_port)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string printPkt(void *d, int size)
|
||||
{
|
||||
std::ostringstream out;
|
||||
out << "Packet:" << "**********************";
|
||||
for(int i = 0; i < size; i++)
|
||||
{
|
||||
if (i % 16 == 0)
|
||||
out << std::endl;
|
||||
out << std::hex << std::setw(2) << (unsigned int) ((unsigned char *) d)[i] << " ";
|
||||
}
|
||||
out << std::endl << "**********************";
|
||||
out << std::endl;
|
||||
return out.str();
|
||||
}
|
||||
|
||||
|
||||
std::string printPktOffset(unsigned int offset, void *d, unsigned int size)
|
||||
{
|
||||
std::ostringstream out;
|
||||
out << "Packet:" << "**********************";
|
||||
out << std::endl;
|
||||
out << "Offset: " << std::hex << offset << " -> " << offset + size;
|
||||
out << std::endl;
|
||||
out << "Packet:" << "**********************";
|
||||
|
||||
unsigned int j = offset % 16;
|
||||
if (j != 0)
|
||||
{
|
||||
out << std::endl;
|
||||
out << std::hex << std::setw(6) << (unsigned int) offset - j;
|
||||
out << ": ";
|
||||
for(unsigned int i = 0; i < j; i++)
|
||||
{
|
||||
out << "xx ";
|
||||
}
|
||||
}
|
||||
for(unsigned int i = offset; i < offset + size; i++)
|
||||
{
|
||||
if (i % 16 == 0)
|
||||
{
|
||||
out << std::endl;
|
||||
out << std::hex << std::setw(6) << (unsigned int) i;
|
||||
out << ": ";
|
||||
}
|
||||
out << std::hex << std::setw(2) << (unsigned int) ((unsigned char *) d)[i-offset] << " ";
|
||||
}
|
||||
out << std::endl << "**********************";
|
||||
out << std::endl;
|
||||
return out.str();
|
||||
}
|
||||
|
||||
|
||||
|
||||
UdpLayer::UdpLayer(struct sockaddr_in &local)
|
||||
:laddr(local), raddrKnown(false), errorState(0), ttl(UDP_DEF_TTL)
|
||||
{
|
||||
openSocket();
|
||||
return;
|
||||
}
|
||||
|
||||
int UdpLayer::status(std::ostream &out)
|
||||
{
|
||||
out << "UdpLayer::status()" << std::endl;
|
||||
out << "localaddr: " << laddr << std::endl;
|
||||
if (raddrKnown)
|
||||
{
|
||||
out << "remoteaddr: " << raddr << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
out << "remoteaddr unKnown!" << std::endl;
|
||||
}
|
||||
out << "sockfd: " << sockfd << std::endl;
|
||||
out << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int UdpLayer::close()
|
||||
{
|
||||
/* close socket if open */
|
||||
if (sockfd > 0)
|
||||
{
|
||||
tounet_close(sockfd);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* higher level interface */
|
||||
int UdpLayer::readPkt(void *data, int *size)
|
||||
{
|
||||
int nsize = *size;
|
||||
struct sockaddr_in from;
|
||||
if (0 >= receiveUdpPacket(data, &nsize, from))
|
||||
{
|
||||
#ifdef DEBUG_UDP_LAYER
|
||||
//std::cerr << "UdpLayer::readPkt() not ready" << from;
|
||||
//std::cerr << std::endl;
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_UDP_LAYER
|
||||
//std::cerr << "UdpLayer::readPkt() from : " << from << std::endl;
|
||||
//std::cerr << printPkt(data, nsize);
|
||||
#endif
|
||||
|
||||
if ((raddrKnown) && (from == raddr))
|
||||
{
|
||||
#ifdef DEBUG_UDP_LAYER
|
||||
std::cerr << "UdpLayer::readPkt() from RemoteAddr: " << from;
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
*size = nsize;
|
||||
return nsize;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_UDP_LAYER
|
||||
std::cerr << "UdpLayer::readPkt() from unknown remote addr: " << from;
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
std::cerr << "UdpLayer::readPkt() storing Random packet from: " << from;
|
||||
std::cerr << std::endl;
|
||||
randomPkts.push_back(new udpPacket(&from,data, nsize));
|
||||
return -1;
|
||||
}
|
||||
|
||||
int UdpLayer::sendPkt(void *data, int size)
|
||||
{
|
||||
if (raddrKnown)
|
||||
{
|
||||
#ifdef DEBUG_UDP_LAYER
|
||||
std::cerr << "UdpLayer::sendPkt() to: " << raddr << std::endl;
|
||||
//std::cerr << printPkt(data, size);
|
||||
#endif
|
||||
sendUdpPacket(data, size, raddr);
|
||||
return size;
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef DEBUG_UDP_LAYER
|
||||
std::cerr << "UdpLayer::sendPacket() unknown remote addr!";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* setup connections */
|
||||
int UdpLayer::openSocket()
|
||||
{
|
||||
/* make a socket */
|
||||
sockfd = tounet_socket(PF_INET, SOCK_DGRAM, 0);
|
||||
#ifdef DEBUG_UDP_LAYER
|
||||
std::cerr << "UpdStreamer::openSocket()" << std::endl;
|
||||
#endif
|
||||
/* bind to address */
|
||||
if (0 != tounet_bind(sockfd, (struct sockaddr *) (&laddr), sizeof(laddr)))
|
||||
{
|
||||
#ifdef DEBUG_UDP_LAYER
|
||||
std::cerr << "Socket Failed to Bind to : " << laddr << std::endl;
|
||||
std::cerr << "Error: " << tounet_errno() << std::endl;
|
||||
#endif
|
||||
errorState = EADDRINUSE;
|
||||
//exit(1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (-1 == tounet_fcntl(sockfd, F_SETFL, O_NONBLOCK))
|
||||
{
|
||||
#ifdef DEBUG_UDP_LAYER
|
||||
std::cerr << "Failed to Make Non-Blocking" << std::endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef DEBUG_UDP_LAYER
|
||||
std::cerr << "Socket Bound to : " << laddr << std::endl;
|
||||
#endif
|
||||
#ifdef DEBUG_UDP_LAYER
|
||||
std::cerr << "Setting TTL to " << UDP_DEF_TTL << std::endl;
|
||||
#endif
|
||||
setTTL(UDP_DEF_TTL);
|
||||
|
||||
errorState = 0;
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
int UdpLayer::setTTL(int t)
|
||||
{
|
||||
int err = tounet_setsockopt(sockfd, IPPROTO_IP, IP_TTL, &t, sizeof(int));
|
||||
ttl = t;
|
||||
|
||||
#ifdef DEBUG_UDP_LAYER
|
||||
std::cerr << "UdpLayer::setTTL(" << t << ") returned: " << err;
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int UdpLayer::getTTL()
|
||||
{
|
||||
return ttl;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int UdpLayer::sendToProxy(struct sockaddr_in &proxy, const void *data, int size)
|
||||
{
|
||||
sendUdpPacket(data, size, proxy);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int UdpLayer::setRemoteAddr(struct sockaddr_in &remote)
|
||||
{
|
||||
raddr = remote;
|
||||
raddrKnown = true;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int UdpLayer::getRemoteAddr(struct sockaddr_in &remote)
|
||||
{
|
||||
if (raddrKnown)
|
||||
{
|
||||
remote = raddr;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* monitoring / updates */
|
||||
int UdpLayer::okay()
|
||||
{
|
||||
bool nonFatalError = ((errorState == 0) ||
|
||||
(errorState == EAGAIN) ||
|
||||
(errorState == EINPROGRESS));
|
||||
|
||||
#ifdef DEBUG_UDP_LAYER
|
||||
if (!nonFatalError)
|
||||
{
|
||||
std::cerr << "UdpLayer::NOT okay(): Error: " << errorState << std::endl;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
return nonFatalError;
|
||||
}
|
||||
|
||||
int UdpLayer::tick()
|
||||
{
|
||||
#ifdef DEBUG_UDP_LAYER
|
||||
std::cerr << "UdpLayer::tick()" << std::endl;
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
/******************* Internals *************************************/
|
||||
|
||||
|
||||
ssize_t UdpLayer::recvRndPktfrom(void *buf, size_t len, int flags,
|
||||
struct sockaddr *from, socklen_t *fromlen)
|
||||
{
|
||||
#ifdef DEBUG_UDP_LAYER
|
||||
std::cerr << "UdpLayer::recvRndPktfrom()" << std::endl;
|
||||
#endif
|
||||
|
||||
if (*fromlen != sizeof(struct sockaddr_in))
|
||||
{
|
||||
|
||||
#ifdef DEBUG_UDP_LAYER
|
||||
std::cerr << "UdpLayer::recvRndPktfrom() bad address length" << std::endl;
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* if raddr not known -> then we're not connected
|
||||
* at a higher level and therefore our queue
|
||||
* will not be filled (no ticking)....
|
||||
* so feel free the get data.
|
||||
*/
|
||||
|
||||
if (randomPkts.size() == 0)
|
||||
{
|
||||
if (!raddrKnown)
|
||||
{
|
||||
#ifdef DEBUG_UDP_LAYER
|
||||
std::cerr << "UdpLayer::recvRndPktfrom() Checking Directly" << std::endl;
|
||||
#endif
|
||||
int size = len;
|
||||
int ret = receiveUdpPacket(buf, &size, *((struct sockaddr_in *) from));
|
||||
if (ret > 0)
|
||||
{
|
||||
#ifdef DEBUG_UDP_LAYER
|
||||
std::cerr << "UdpLayer::recvRndPktfrom() Got Pkt directly" << std::endl;
|
||||
std::cerr << "Pkt from:" << inet_ntoa(((struct sockaddr_in *) from)->sin_addr);
|
||||
std::cerr << ":" << ntohs(((struct sockaddr_in *) from)->sin_port) << std::endl;
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG_UDP_LAYER
|
||||
std::cerr << "UdpLayer::recvRndPktfrom() Nothing in the Queue" << std::endl;
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
udpPacket *pkt = randomPkts.front();
|
||||
randomPkts.pop_front();
|
||||
|
||||
*((struct sockaddr_in *) from) = pkt->raddr;
|
||||
unsigned int size = pkt->len;
|
||||
if (len < size)
|
||||
{
|
||||
size = len;
|
||||
}
|
||||
|
||||
memcpy(buf, pkt->data, size);
|
||||
*((struct sockaddr_in *) from) = pkt->raddr;
|
||||
|
||||
#ifdef DEBUG_UDP_LAYER
|
||||
std::cerr << "UdpLayer::recvRndPktfrom() returning stored Pkt" << std::endl;
|
||||
std::cerr << "Pkt from:" << inet_ntoa(pkt->raddr.sin_addr);
|
||||
std::cerr << ":" << ntohs(pkt->raddr.sin_port) << std::endl;
|
||||
std::cerr << "Length: " << pkt->len << std::endl;
|
||||
#endif
|
||||
|
||||
delete pkt;
|
||||
return size;
|
||||
}
|
||||
|
||||
/******************* Internals *************************************/
|
||||
|
||||
|
||||
int UdpLayer::receiveUdpPacket(void *data, int *size, struct sockaddr_in &from)
|
||||
{
|
||||
struct sockaddr_in fromaddr;
|
||||
socklen_t fromsize = sizeof(fromaddr);
|
||||
int insize = *size;
|
||||
if (0<(insize=tounet_recvfrom(sockfd,data,insize,0,
|
||||
(struct sockaddr*)&fromaddr,&fromsize)))
|
||||
{
|
||||
#ifdef DEBUG_UDP_LAYER
|
||||
std::cerr << "receiveUdpPacket() from: " << fromaddr;
|
||||
std::cerr << " Size: " << insize;
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
*size = insize;
|
||||
from = fromaddr;
|
||||
return insize;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int UdpLayer::sendUdpPacket(const void *data, int size, struct sockaddr_in &to)
|
||||
{
|
||||
/* send out */
|
||||
#ifdef DEBUG_UDP_LAYER
|
||||
std::cerr << "UdpLayer::sendUdpPacket(): size: " << size;
|
||||
std::cerr << " To: " << to << std::endl;
|
||||
#endif
|
||||
struct sockaddr_in toaddr = to;
|
||||
|
||||
tounet_sendto(sockfd, data, size, 0,
|
||||
(struct sockaddr *) &(toaddr),
|
||||
sizeof(toaddr));
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
190
libretroshare/src/tcponudp/udplayer.h
Normal file
190
libretroshare/src/tcponudp/udplayer.h
Normal file
|
@ -0,0 +1,190 @@
|
|||
/*
|
||||
* "$Id: udplayer.h,v 1.5 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".
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#ifndef TOU_UDP_LAYER_H
|
||||
#define TOU_UDP_LAYER_H
|
||||
|
||||
|
||||
/*
|
||||
#include <netinet/in.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
*/
|
||||
|
||||
/* universal networking functions */
|
||||
#include "tou_net.h"
|
||||
|
||||
#include <iosfwd>
|
||||
#include <list>
|
||||
#include <deque>
|
||||
|
||||
std::ostream &operator<<(std::ostream &out, struct sockaddr_in &addr);
|
||||
bool operator==(struct sockaddr_in &addr, struct sockaddr_in &addr2);
|
||||
std::string printPkt(void *d, int size);
|
||||
std::string printPktOffset(unsigned int offset, void *d, unsigned int size);
|
||||
|
||||
|
||||
/* So the UdpLayer ..... has a couple of roles
|
||||
*
|
||||
* Firstly Send Proxy Packet() (for address determination).
|
||||
* all the rest of this functionality is handled elsewhere.
|
||||
*
|
||||
* Secondly support TcpStreamer....
|
||||
*/
|
||||
|
||||
class udpPacket;
|
||||
|
||||
class UdpLayer
|
||||
{
|
||||
public:
|
||||
|
||||
UdpLayer(struct sockaddr_in &local);
|
||||
virtual ~UdpLayer() { return; }
|
||||
|
||||
int status(std::ostream &out);
|
||||
|
||||
/* setup connections */
|
||||
int openSocket();
|
||||
int setTTL(int t);
|
||||
int getTTL();
|
||||
|
||||
int sendToProxy(struct sockaddr_in &proxy, const void *data, int size);
|
||||
int setRemoteAddr(struct sockaddr_in &remote);
|
||||
int getRemoteAddr(struct sockaddr_in &remote);
|
||||
|
||||
/* Higher Level Interface */
|
||||
int readPkt(void *data, int *size);
|
||||
int sendPkt(void *data, int size);
|
||||
|
||||
/* monitoring / updates */
|
||||
int okay();
|
||||
int tick();
|
||||
|
||||
int close();
|
||||
|
||||
/* unix like interface for recving packets not part
|
||||
* of the tcp stream
|
||||
*/
|
||||
ssize_t recvRndPktfrom(void *buf, size_t len, int flags,
|
||||
struct sockaddr *from, socklen_t *fromlen);
|
||||
|
||||
/* data */
|
||||
/* internals */
|
||||
protected:
|
||||
|
||||
virtual int receiveUdpPacket(void *data, int *size, struct sockaddr_in &from);
|
||||
virtual int sendUdpPacket(const void *data, int size, struct sockaddr_in &to);
|
||||
|
||||
/* low level */
|
||||
/*
|
||||
* int rwSocket();
|
||||
*/
|
||||
private:
|
||||
|
||||
|
||||
struct sockaddr_in paddr; /* proxy addr */
|
||||
struct sockaddr_in raddr; /* remote addr */
|
||||
struct sockaddr_in laddr; /* local addr */
|
||||
|
||||
bool raddrKnown;
|
||||
int errorState;
|
||||
int sockfd;
|
||||
|
||||
int ttl;
|
||||
|
||||
std::deque<udpPacket * > randomPkts;
|
||||
|
||||
};
|
||||
|
||||
#include <iostream>
|
||||
|
||||
class LossyUdpLayer: public UdpLayer
|
||||
{
|
||||
public:
|
||||
|
||||
LossyUdpLayer(struct sockaddr_in &local, double frac)
|
||||
:UdpLayer(local), lossFraction(frac)
|
||||
{
|
||||
return;
|
||||
}
|
||||
virtual ~LossyUdpLayer() { return; }
|
||||
|
||||
protected:
|
||||
|
||||
virtual int receiveUdpPacket(void *data, int *size, struct sockaddr_in &from)
|
||||
{
|
||||
double prob = (1.0 * (rand() / (RAND_MAX + 1.0)));
|
||||
|
||||
if (prob < lossFraction)
|
||||
{
|
||||
/* but discard */
|
||||
if (0 < UdpLayer::receiveUdpPacket(data, size, from))
|
||||
{
|
||||
std::cerr << "LossyUdpLayer::receiveUdpPacket() Dropping packet!";
|
||||
std::cerr << std::endl;
|
||||
std::cerr << printPkt(data, *size);
|
||||
std::cerr << std::endl;
|
||||
std::cerr << "LossyUdpLayer::receiveUdpPacket() Packet Dropped!";
|
||||
std::cerr << std::endl;
|
||||
}
|
||||
|
||||
size = 0;
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
// otherwise read normally;
|
||||
return UdpLayer::receiveUdpPacket(data, size, from);
|
||||
}
|
||||
|
||||
|
||||
virtual int sendUdpPacket(const void *data, int size, struct sockaddr_in &to)
|
||||
{
|
||||
double prob = (1.0 * (rand() / (RAND_MAX + 1.0)));
|
||||
|
||||
if (prob < lossFraction)
|
||||
{
|
||||
/* discard */
|
||||
|
||||
std::cerr << "LossyUdpLayer::sendUdpPacket() Dropping packet!";
|
||||
std::cerr << std::endl;
|
||||
std::cerr << printPkt((void *) data, size);
|
||||
std::cerr << std::endl;
|
||||
std::cerr << "LossyUdpLayer::sendUdpPacket() Packet Dropped!";
|
||||
std::cerr << std::endl;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
// otherwise read normally;
|
||||
return UdpLayer::sendUdpPacket(data, size, to);
|
||||
}
|
||||
|
||||
double lossFraction;
|
||||
};
|
||||
|
||||
#endif
|
Loading…
Add table
Add a link
Reference in a new issue