/* * p2tp.cpp * serp++ * * Created by Victor Grishchenko on 3/6/09. * Copyright 2009 Delft Technical University. All rights reserved. * */ #include #include #include #include #include #include #include #include #include #include #include "p2tp.h" using namespace std; using namespace p2tp; p2tp::tint Channel::now = 0; int Channel::MAX_REORDERING = 4; p2tp::tint Channel::TIMEOUT = TINT_1SEC*60; std::vector Channel::channels(1); std::vector File::files(4); int* Channel::sockets_ = (int*)malloc(40); int Channel::sock_count_ = 0; Channel::Channel (int fd_, int socket, struct sockaddr_in peer_, uint32_t peer_channel_, uint64_t supports_) : fd(fd_), peer(peer_), peer_channel_id(peer_channel_), ack_out(0), peer_status_(File::EMPTY), socket_(socket) { this->id = channels.size(); channels.push_back(this); DLOG(INFO)<<"new channel "<0) ::close(fd); } bool File::OfferHash (bin pos, const Sha1Hash& hash) { HashTree::hashres_t res = hashes.offer(pos,hash); if (res==HashTree::PEAK_ACCEPT) { // file size is finally known ftruncate(fd, size()); LOG(INFO)<::iterator i=files.begin(); i!=files.end(); i++) if (*i && (*i)->hashes.root==hash) return *i; return NULL; } int Channel::DecodeID(int scrambled) { return scrambled; } int Channel::EncodeID(int unscrambled) { return unscrambled; } std::ostream& p2tp::operator << (std::ostream& os, const Channel& ch) { return os<<'{'<'<fd, socket, data.address(), peerch); } else { mych = DecodeID(mych); if (mych>=channels.size()) RETLOG ("invalid channel id"); channel = channels[mych]; id = channel->id; if (channel->peer.sin_addr.s_addr != data.address().sin_addr.s_addr) RETLOG ("invalid peer address"); if (channel->peer.sin_port!=data.address().sin_port) RETLOG ("invalid peer port"); if (!channel->peer_channel_id) { // handshake response if (data.size()<5) RETLOG ("insufficient return handshake length"); type = data.Pull8(); if (type) RETLOG ("it is not a handshake, after all"); channel->peer_channel_id = data.Pull32(); LOG(INFO)<<"out channel is open: "<<*channel; } else if (channel->cc.avg_rtt()==0) { LOG(INFO)<<"in channel is open: "<<*channel; } channel->cc.RttSample(Channel::now - channel->last_send_time + 1); channel->Recv(data); } channel->Send(); } void Channel::Tick () { // choking/unchoking // keepalives // ack timeout // if unchoked: don't bother // whether to unchoke // reevaluate reciprocity // otherwise, send update (if needed) // otherwise, send a keepalive if (last_send_time && now-last_send_time>=TINT_1SEC*60) Send(); } /**

P2TP handshake

Basic rules:
  • to send a datagram, a channel must be created (channels are cheap and easily recycled)
  • a datagram must contain either the receiving channel id (scrambled) or the root hash
  • initially, the control structure (p2tp_channel) is mostly zeroed; intialization happens as conversation progresses
Note: */ void Channel::Loop (tint time) { now = clock(); tint last_tick = 0, untiltime = now+time; for (; now<=untiltime; now = clock()) { tint towait = min(untiltime,now+TINT_1SEC) - now; int rd = Datagram::Wait(sock_count_,sockets_,towait); if (rd!=-1) Recv(rd); if (now-last_tick>TINT_1SEC) { for(int i=0; iTick(); last_tick = now; } } } int p2tp::Open (const char* filename) { int fd = ::open(filename,O_RDONLY); if (fd<0) return -1; if (File::files.size()size(); } void p2tp::Close (int fid) { if (!File::files[fid]) return; delete File::files[fid]; File::files[fid] = NULL; } int p2tp::Connect (int fd, int sock, const struct sockaddr_in& addr, uint32_t peerch) { Channel::now = Channel::clock(); // FIXME: Datagram::now Channel *ch = new Channel(fd,sock,addr,peerch); ch->Send(); return ch->id; } void p2tp::Loop (tint time) { Channel::Loop(time); } int p2tp::Init (int portno) { int sock = Datagram::Bind(portno); if (sock>0) Channel::sockets_[Channel::sock_count_++] = sock; return sock; } void p2tp::Shutdown (int sock) { int i=0; while (i