/*
* datagram.h
- * serp++
+ * nice IPv4 UDP wrappers
*
- * Created by Victor Grishchenko on 3/9/09.
- * Copyright 2009 Delft Technical University. All rights reserved.
+ * Created by Victor Grishchenko, Arno Bakker on 3/9/09.
+ * Copyright 2009 Delft University of Technology. All rights reserved.
*
*/
#ifndef DATAGRAM_H
#define DATAGRAM_H
-#include <stdint.h>
-#include <stdlib.h>
-#include <fcntl.h>
-#include <sys/select.h>
+
#include <sys/stat.h>
-#include <sys/socket.h>
-#include <sys/time.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-//#include <sys/mman.h>
#include <string.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <string>
#include "hashtree.h"
+#include "compat.h"
+
-namespace p2tp {
+namespace swift {
-typedef int64_t tint;
-#define TINT_SEC ((tint)1000000)
-#define TINT_MSEC ((tint)1000)
-#define TINT_uSEC ((tint)1)
-#define TINT_NEVER ((tint)0x7fffffffffffffffLL)
-#define MAXDGRAMSZ 1400
+#define MAXDGRAMSZ 2800
+#ifndef _WIN32
#define INVALID_SOCKET -1
+#endif
+
+
+/** IPv4 address, just a nice wrapping around struct sockaddr_in. */
+struct Address {
+ struct sockaddr_in addr;
+ static uint32_t LOCALHOST;
+ void set_port (uint16_t port) {
+ addr.sin_port = htons(port);
+ }
+ void set_port (const char* port_str) {
+ int p;
+ if (sscanf(port_str,"%i",&p))
+ set_port(p);
+ }
+ void set_ipv4 (uint32_t ipv4) {
+ addr.sin_addr.s_addr = htonl(ipv4);
+ }
+ void set_ipv4 (const char* ipv4_str) ;
+ //{ inet_aton(ipv4_str,&(addr.sin_addr)); }
+ void clear () {
+ memset(&addr,0,sizeof(struct sockaddr_in));
+ addr.sin_family = AF_INET;
+ }
+ Address() {
+ clear();
+ }
+ Address(const char* ip, uint16_t port) {
+ clear();
+ set_ipv4(ip);
+ set_port(port);
+ }
+ Address(const char* ip_port);
+ Address(uint16_t port) {
+ clear();
+ set_ipv4((uint32_t)INADDR_ANY);
+ set_port(port);
+ }
+ Address(uint32_t ipv4addr, uint16_t port) {
+ clear();
+ set_ipv4(ipv4addr);
+ set_port(port);
+ }
+ Address(const struct sockaddr_in& address) : addr(address) {}
+ uint32_t ipv4 () const { return ntohl(addr.sin_addr.s_addr); }
+ uint16_t port () const { return ntohs(addr.sin_port); }
+ operator sockaddr_in () const {return addr;}
+ bool operator == (const Address& b) const {
+ return addr.sin_family==b.addr.sin_family &&
+ addr.sin_port==b.addr.sin_port &&
+ addr.sin_addr.s_addr==b.addr.sin_addr.s_addr;
+ }
+ const char* str () const {
+ static char rs[4][32];
+ static int i;
+ i = (i+1) & 3;
+ sprintf(rs[i],"%i.%i.%i.%i:%i",ipv4()>>24,(ipv4()>>16)&0xff,
+ (ipv4()>>8)&0xff,ipv4()&0xff,port());
+ return rs[i];
+ }
+ bool operator != (const Address& b) const { return !(*this==b); }
+};
+
+
+typedef void (*sockcb_t) (SOCKET);
+struct sckrwecb_t {
+ sckrwecb_t (SOCKET s=0, sockcb_t mr=NULL, sockcb_t mw=NULL, sockcb_t oe=NULL) :
+ sock(s), may_read(mr), may_write(mw), on_error(oe) {}
+ SOCKET sock;
+ sockcb_t may_read;
+ sockcb_t may_write;
+ sockcb_t on_error;
+};
+
+
+/** UDP datagram class, a nice wrapping around sendto/recvfrom/select.
+ Reading/writing from/to a datagram is done in a FIFO (deque) fashion:
+ written data is appended to the tail (push) while read data is
+ taken from the "head" of the buffer. */
+class Datagram {
+
+ Address addr;
+ SOCKET sock;
+ int offset, length;
+ uint8_t buf[MAXDGRAMSZ*2];
+
+#define DGRAM_MAX_SOCK_OPEN 128
+ static int sock_count;
+ static sckrwecb_t sock_open[DGRAM_MAX_SOCK_OPEN];
+public:
+
+ /** bind to the address */
+ static SOCKET Bind(Address address, sckrwecb_t callbacks=sckrwecb_t());
+
+ /** close the port */
+ static void Close(SOCKET sock);
+
+ /** the current time */
+ static tint Time();
+
+ /** wait till one of the sockets has some io to do; usec is the timeout */
+ static SOCKET Wait (tint usec);
-struct Datagram {
-
- struct Address {
- struct sockaddr_in addr;
- Address() {
- memset(&addr,0,sizeof(struct sockaddr_in));
- }
- Address(const char* ip, uint16_t port) {
- addr.sin_family = AF_INET;
- addr.sin_port = htons(port);
- inet_aton(ip,&(addr.sin_addr));
- }
- Address(uint16_t port) {
- addr.sin_family = AF_INET;
- addr.sin_port = htons(port);
- addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
- }
- Address(const struct sockaddr_in& address) : addr(address) {}
- operator sockaddr_in () {return addr;}
- };
+ static bool Listen3rdPartySocket (sckrwecb_t cb) ;
- Address addr;
- int sock;
- int offset, length;
- uint8_t buf[MAXDGRAMSZ*2];
+ static void Shutdown ();
- static int Bind(int port);
- static void Close(int port);
- static tint Time();
- static int Wait (int sockcnt, int* sockets, tint usec=0);
- static tint now;
-
- Datagram (int socket, const Address addr_) : addr(addr_), offset(0),
- length(0), sock(socket) {}
- Datagram (int socket) : offset(0), length(0), sock(socket) {
- }
-
- int space () const { return MAXDGRAMSZ-length; }
- int size() const { return length-offset; }
- std::string str() const { return std::string((char*)buf+offset,size()); }
+ static SOCKET default_socket()
+ { return sock_count ? sock_open[0].sock : INVALID_SOCKET; }
+
+ static tint now, epoch, start;
+ static uint64_t dgrams_up, dgrams_down, bytes_up, bytes_down;
+
+ /** This constructor is normally used to SEND something to the address. */
+ Datagram (SOCKET socket, const Address addr_) : addr(addr_), offset(0),
+ length(0), sock(socket) {}
+ /** This constructor is normally used to RECEIVE something at the socket. */
+ Datagram (SOCKET socket) : offset(0), length(0), sock(socket) {
+ }
+
+ /** space remaining */
+ int space () const { return MAXDGRAMSZ-length; }
+ /** size of the data (not counting UDP etc headers) */
+ int size() const { return length-offset; }
+ std::string str() const { return std::string((char*)buf+offset,size()); }
const uint8_t* operator * () const { return buf+offset; }
-
- int Push (const uint8_t* data, int l) { // scatter-gather one day
- int toc = l<space() ? l : space();
- memcpy(buf+length,data,toc);
- length += toc;
- return toc;
- }
- int Pull (uint8_t** data, int l) {
- int toc = l<size() ? l : size();
- //memcpy(data,buf+offset,toc);
- *data = buf+offset;
- offset += toc;
- return toc;
- }
-
- int Send ();
- int Recv ();
- const Address& address() const { return addr; }
+ const Address& address () const { return addr; }
+ /** Append some data at the back */
+ int Push (const uint8_t* data, int l) { // scatter-gather one day
+ int toc = l<space() ? l : space();
+ memcpy(buf+length,data,toc);
+ length += toc;
+ return toc;
+ }
+ /** Read something from the front of the datagram */
+ int Pull (uint8_t** data, int l) {
+ int toc = l<size() ? l : size();
+ //memcpy(data,buf+offset,toc);
+ *data = buf+offset;
+ offset += toc;
+ return toc;
+ }
+
+ int Send ();
+ int Recv ();
+
void Clear() { offset=length=0; }
- void PushString (std::string str) {
- Push((uint8_t*)str.c_str(),str.size());
- }
- void Push8 (uint8_t b) {
- buf[length++] = b;
- }
- void Push16 (uint16_t w) {
- *(uint16_t*)(buf+length) = htons(w);
- length+=2;
- }
- void Push32 (uint32_t i) {
- *(uint32_t*)(buf+length) = htonl(i);
- length+=4;
- }
- void Push64 (uint64_t l) {
- *(uint32_t*)(buf+length) = htonl((uint32_t)(l>>32));
- *(uint32_t*)(buf+length+4) = htonl((uint32_t)(l&0xffffffff));
- length+=8;
- }
- void PushHash (const Sha1Hash& hash) {
- Push(hash.bits, Sha1Hash::SIZE);
- }
-
- uint8_t Pull8() {
- if (size()<1) return 0;
- return buf[offset++];
- }
- uint16_t Pull16() {
- if (size()<2) return 0;
- offset+=2;
- return ntohs(*(uint16_t*)(buf+offset-2));
- }
- uint32_t Pull32() {
- if (size()<4) return 0;
- uint32_t i = ntohl(*(uint32_t*)(buf+offset));
- offset+=4;
- return i;
- }
- uint64_t Pull64() {
- if (size()<8) return 0;
- uint64_t l = ntohl(*(uint32_t*)(buf+offset));
- l<<=32;
- l |= ntohl(*(uint32_t*)(buf+offset+4));
- offset+=8;
- return l;
- }
- Sha1Hash PullHash() {
- if (size()<Sha1Hash::SIZE) return Sha1Hash::ZERO;
- offset += Sha1Hash::SIZE;
- return Sha1Hash(false,(char*)buf+offset-Sha1Hash::SIZE);
- }
- //std::string to_string () const ;
-
+ void PushString (std::string str) {
+ Push((uint8_t*)str.c_str(),str.size());
+ }
+ void Push8 (uint8_t b) {
+ buf[length++] = b;
+ }
+ void Push16 (uint16_t w) {
+ *(uint16_t*)(buf+length) = htons(w);
+ length+=2;
+ }
+ void Push32 (uint32_t i) {
+ *(uint32_t*)(buf+length) = htonl(i);
+ length+=4;
+ }
+ void Push64 (uint64_t l) {
+ *(uint32_t*)(buf+length) = htonl((uint32_t)(l>>32));
+ *(uint32_t*)(buf+length+4) = htonl((uint32_t)(l&0xffffffff));
+ length+=8;
+ }
+ void PushHash (const Sha1Hash& hash) {
+ Push((uint8_t*)hash.bits, Sha1Hash::SIZE);
+ }
+
+ uint8_t Pull8() {
+ if (size()<1) return 0;
+ return buf[offset++];
+ }
+ uint16_t Pull16() {
+ if (size()<2) return 0;
+ offset+=2;
+ return ntohs(*(uint16_t*)(buf+offset-2));
+ }
+ uint32_t Pull32() {
+ if (size()<4) return 0;
+ uint32_t i = ntohl(*(uint32_t*)(buf+offset));
+ offset+=4;
+ return i;
+ }
+ uint64_t Pull64() {
+ if (size()<8) return 0;
+ uint64_t l = ntohl(*(uint32_t*)(buf+offset));
+ l<<=32;
+ l |= ntohl(*(uint32_t*)(buf+offset+4));
+ offset+=8;
+ return l;
+ }
+ Sha1Hash PullHash() {
+ if (size()<Sha1Hash::SIZE) return Sha1Hash::ZERO;
+ offset += Sha1Hash::SIZE;
+ return Sha1Hash(false,(char*)buf+offset-Sha1Hash::SIZE);
+ }
+ //std::string to_string () const ;
+
};
+const char* tintstr(tint t=0);
std::string sock2str (struct sockaddr_in addr);
}