2007-11-14 22:18:48 -05:00
|
|
|
/*
|
|
|
|
* "$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;
|
|
|
|
|
2008-05-31 09:31:11 -04:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
2010-07-31 14:14:10 -04:00
|
|
|
#include "udp/udpstack.h"
|
2007-11-14 22:18:48 -05:00
|
|
|
#include "tcpstream.h"
|
|
|
|
#include <vector>
|
|
|
|
#include <iostream>
|
|
|
|
|
|
|
|
#include <errno.h>
|
|
|
|
|
|
|
|
#define DEBUG_TOU_INTERFACE 1
|
|
|
|
|
|
|
|
struct TcpOnUdp_t
|
|
|
|
{
|
|
|
|
int tou_fd;
|
|
|
|
int lasterrno;
|
|
|
|
TcpStream *tcp;
|
|
|
|
bool idle;
|
|
|
|
};
|
|
|
|
|
|
|
|
typedef struct TcpOnUdp_t TcpOnUdp;
|
|
|
|
|
|
|
|
static std::vector<TcpOnUdp *> tou_streams;
|
|
|
|
|
|
|
|
static int tou_inited = 0;
|
2010-07-31 14:14:10 -04:00
|
|
|
|
|
|
|
|
|
|
|
#include "udp/udpstack.h"
|
|
|
|
#include "tcponudp/udppeer.h"
|
|
|
|
|
|
|
|
static UdpStack *udpstack = NULL;
|
|
|
|
static UdpPeerReceiver *udps = NULL;
|
2007-11-14 22:18:48 -05:00
|
|
|
|
|
|
|
static int tou_tick_all();
|
2008-01-25 01:11:39 -05:00
|
|
|
|
|
|
|
/* tou_init - opens the udp port (universal bind) */
|
2010-08-02 19:21:59 -04:00
|
|
|
int tou_init(void *in_udpstack)
|
2007-11-14 22:18:48 -05:00
|
|
|
{
|
2010-08-02 19:21:59 -04:00
|
|
|
UdpStack *stack = (UdpStack *) in_udpstack;
|
2007-11-14 22:18:48 -05:00
|
|
|
if (tou_inited)
|
2009-08-04 19:22:44 -04:00
|
|
|
{
|
2007-11-14 22:18:48 -05:00
|
|
|
return 1;
|
2009-08-04 19:22:44 -04:00
|
|
|
}
|
2007-11-14 22:18:48 -05:00
|
|
|
|
|
|
|
tou_streams.resize(kInitStreamTable);
|
|
|
|
|
2010-07-31 14:14:10 -04:00
|
|
|
udpstack = stack;
|
|
|
|
udps = new UdpPeerReceiver(stack);
|
|
|
|
stack->addReceiver(udps);
|
2008-01-25 01:11:39 -05:00
|
|
|
|
2007-11-14 22:18:48 -05:00
|
|
|
tou_inited = 1;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* open - which does nothing */
|
|
|
|
int tou_socket(int /*domain*/, int /*type*/, int /*protocol*/)
|
|
|
|
{
|
2008-01-25 01:11:39 -05:00
|
|
|
if (!tou_inited)
|
|
|
|
{
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2007-11-14 22:18:48 -05:00
|
|
|
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] -> 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 -> tcp = NULL;
|
|
|
|
return tou->tou_fd;
|
|
|
|
}
|
|
|
|
|
|
|
|
tou -> lasterrno = EUSERS;
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* bind - opens the udp port */
|
2010-08-01 14:22:37 -04:00
|
|
|
int tou_bind(int sockfd, const struct sockaddr * /* my_addr */, socklen_t /* addrlen */ )
|
2007-11-14 22:18:48 -05:00
|
|
|
{
|
|
|
|
if (tou_streams[sockfd] == NULL)
|
|
|
|
{
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
TcpOnUdp *tous = tou_streams[sockfd];
|
|
|
|
|
2008-01-25 01:11:39 -05:00
|
|
|
/* this now always returns an error! */
|
|
|
|
tous -> lasterrno = EADDRINUSE;
|
|
|
|
return -1;
|
2007-11-14 22:18:48 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
/* 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,
|
2008-02-26 21:32:20 -05:00
|
|
|
socklen_t addrlen, uint32_t conn_period)
|
2007-11-14 22:18:48 -05:00
|
|
|
{
|
|
|
|
if (tou_streams[sockfd] == NULL)
|
|
|
|
{
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
TcpOnUdp *tous = tou_streams[sockfd];
|
|
|
|
|
|
|
|
|
|
|
|
if (addrlen != sizeof(struct sockaddr_in))
|
|
|
|
{
|
|
|
|
tous -> lasterrno = EINVAL;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2008-01-25 01:11:39 -05:00
|
|
|
/* create a TCP stream to connect with. */
|
|
|
|
if (!tous->tcp)
|
2007-11-14 22:18:48 -05:00
|
|
|
{
|
2008-01-25 01:11:39 -05:00
|
|
|
tous->tcp = new TcpStream(udps);
|
|
|
|
udps->addUdpPeer(tous->tcp,
|
|
|
|
*((const struct sockaddr_in *) serv_addr));
|
2007-11-14 22:18:48 -05:00
|
|
|
}
|
|
|
|
|
2008-02-26 21:32:20 -05:00
|
|
|
tous->tcp->connect(*(const struct sockaddr_in *) serv_addr, conn_period);
|
2007-11-14 22:18:48 -05:00
|
|
|
tous->tcp->tick();
|
|
|
|
tou_tick_all();
|
|
|
|
if (tous->tcp->isConnected())
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
tous -> lasterrno = EINPROGRESS;
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2008-01-25 01:11:39 -05:00
|
|
|
/* create a TCP stream to connect with. */
|
|
|
|
if (!tous->tcp)
|
2007-11-14 22:18:48 -05:00
|
|
|
{
|
2008-01-25 01:11:39 -05:00
|
|
|
tous->tcp = new TcpStream(udps);
|
|
|
|
udps->addUdpPeer(tous->tcp,
|
|
|
|
*((const struct sockaddr_in *) serv_addr));
|
2007-11-14 22:18:48 -05:00
|
|
|
}
|
|
|
|
|
2008-01-25 01:11:39 -05:00
|
|
|
tous->tcp->listenfor(*((struct sockaddr_in *) serv_addr));
|
2007-11-14 22:18:48 -05:00
|
|
|
tous->tcp->tick();
|
|
|
|
tou_tick_all();
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-08-01 14:22:37 -04:00
|
|
|
int tou_listen(int /* sockfd */ , int /* backlog */ )
|
2007-11-14 22:18:48 -05:00
|
|
|
{
|
2008-01-25 01:11:39 -05:00
|
|
|
tou_tick_all();
|
|
|
|
return 1;
|
2007-11-14 22:18:48 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-01-25 01:11:39 -05:00
|
|
|
/* slightly different - returns sockfd on connection */
|
|
|
|
int tou_accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen)
|
2007-11-14 22:18:48 -05:00
|
|
|
{
|
|
|
|
if (tou_streams[sockfd] == NULL)
|
|
|
|
{
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
TcpOnUdp *tous = tou_streams[sockfd];
|
|
|
|
|
2008-01-25 01:11:39 -05:00
|
|
|
if (*addrlen != sizeof(struct sockaddr_in))
|
2007-11-14 22:18:48 -05:00
|
|
|
{
|
|
|
|
tous -> lasterrno = EINVAL;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2008-01-25 01:11:39 -05:00
|
|
|
//tous->tcp->connect();
|
|
|
|
tous->tcp->tick();
|
|
|
|
tou_tick_all();
|
|
|
|
if (tous->tcp->isConnected())
|
2007-11-14 22:18:48 -05:00
|
|
|
{
|
2008-01-25 01:11:39 -05:00
|
|
|
// should get remote address
|
|
|
|
tous->tcp->getRemoteAddress(*((struct sockaddr_in *) addr));
|
|
|
|
return sockfd;
|
2007-11-14 22:18:48 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
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();
|
|
|
|
|
2008-01-25 01:11:39 -05:00
|
|
|
return (tous->tcp->TcpState() == 4);
|
2007-11-14 22:18:48 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 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)
|
|
|
|
{
|
2008-01-25 01:11:39 -05:00
|
|
|
tous->lasterrno = tous->tcp->TcpErrorState();
|
2007-11-14 22:18:48 -05:00
|
|
|
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)
|
|
|
|
{
|
2008-01-25 01:11:39 -05:00
|
|
|
tous->lasterrno = tous->tcp->TcpErrorState();
|
2007-11-14 22:18:48 -05:00
|
|
|
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)
|
|
|
|
{
|
2008-01-25 01:11:39 -05:00
|
|
|
tous->lasterrno = tous->tcp->TcpErrorState();
|
2007-11-14 22:18:48 -05:00
|
|
|
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)
|
|
|
|
{
|
2008-01-25 01:11:39 -05:00
|
|
|
tous->lasterrno = tous->tcp->TcpErrorState();
|
2007-11-14 22:18:48 -05:00
|
|
|
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];
|
|
|
|
|
|
|
|
tou_tick_all();
|
|
|
|
|
2008-02-26 21:32:20 -05:00
|
|
|
if (tous->tcp)
|
|
|
|
{
|
|
|
|
tous->tcp->tick();
|
|
|
|
|
|
|
|
/* shut it down */
|
|
|
|
tous->tcp->close();
|
2008-03-02 09:25:59 -05:00
|
|
|
udps->removeUdpPeer(tous->tcp);
|
2008-02-26 21:32:20 -05:00
|
|
|
delete tous->tcp;
|
|
|
|
}
|
|
|
|
|
2007-11-14 22:18:48 -05:00
|
|
|
delete tous;
|
|
|
|
tou_streams[sockfd] = NULL;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* get an error number */
|
|
|
|
int tou_errno(int sockfd)
|
|
|
|
{
|
2008-01-25 01:11:39 -05:00
|
|
|
if (!udps)
|
|
|
|
{
|
|
|
|
return ENOTSOCK;
|
|
|
|
}
|
2007-11-14 22:18:48 -05:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|