#define PEER_PEER_ID_SIZE 20
struct peer {
+ unsigned int handshake : 1;
unsigned int choked : 1;
unsigned int interested: 1;
extern struct session session;
void session_clean();
+struct torrent *session_find_torrent(uint8_t*,size_t);
int session_init();
int session_torrent_add(struct torrent*);
#include<net.h>
-void net_handler(int epoll_fd, int sock, struct peer *peer_info) {
- struct epoll_event ev;
+static ssize_t net_expected_length(int);
+static void send_remaining(int,struct peer*);
+
+static ssize_t net_expected_length(int sock) {
unsigned char buf[4];
ssize_t i;
- unsigned int len;
-
- if(NULL==peer_info) {
- if(peer_handshake(sock,peer_info)<0) { goto close; }
- return;
- }
-
+
i = recv(sock,buf,4,MSG_PEEK);
if(-1==i) {
if(!((errno==EAGAIN)||(errno==EWOULDBLOCK))) {
perror("recv");
- return;
+ return -1;
}
- goto epoll;
- }
+ // returning 0 here won't affect anything,
+ // will be treated as a keep alive (although
+ // message is still coming in, but since MSG_PEEK
+ // flag is used no data will have been consumed)
+ // and sock will be returned to epoll
+ return 0;
+ }
+
/*
* message should at least have 4 bytes (length prefix of
* the following message)
*/
- if(i<4) { goto epoll; }
+ if(i<4) { return 0; }
- len = 0;
- for(size_t i=0;i<4;i++) {
- len <<= 1;
- len += buf[i];
+ i = 0;
+ for(size_t j=0;j<4;j++) {
+ i <<= 1;
+ i += buf[j];
}
- if(0==len) { return; } // message of length 0 == keep-alive
+ return i;
+}
+
+void net_handler(int epoll_fd, int sock, struct peer *peer_info) {
+ struct epoll_event ev;
+ ssize_t i;
+ unsigned int len;
+
+ if(info->out!=NULL) { goto remaining; }
+
+ if(!info->handshake) { goto handshake; }
+
+ if((i = net_expected_length(sock))<0) { goto close; }
+ if(0==i) { goto queue; } // message of length 0 == keep-alive
switch(buf[4]) {
case PEER_MESSAGE_CHOKE:
break;
}
+ return;
+remaining:
+ if(send_remaining(sock,peer_info)<0) { goto close; }
+ goto queue;
+handshake:
+ if(peer_handshake(sock,peer_info)<0) { goto close; }
+ goto queue;
+queue:
+ if(net_queue(sock,info,NULL,0)<0) { goto close; }
return;
close:
- if(peer_info!=NULL) { peer_free(peer_info); }
+ peer_free(peer_info);
close(sock);
return;
-epoll:
- ev.events = EPOLLIN | EPOLLET;
- ev.data.ptr = peer_info;
- ev.data.fd = sock;
+}
- if(-1==epoll_ctl(epoll_fd,EPOLL_CTL_ADD,sock,&ev)) {
- perror("epoll_ctl");
- return;
- }
+static int send_remaining(int sock, struct peer *info) {
+ if(net_send(sock,peer_info->out,peer_info->out_size)<0) { return -1; }
+
+ free(info->out);
+ info->out = NULL;
+ return 1;
}
setnonblocking(conn_sock);
ev.events = EPOLLIN | EPOLLET;
- ev.data.ptr = NULL;
ev.data.fd = conn_sock;
+ if(peer_init((struct peer*)&(ev.data.ptr))<0) {
+ return;
+ }
+
if(-1==epoll_ctl(info->epoll_fd,EPOLL_CTL_ADD,conn_sock,&ev)) {
perror("epoll_ctl");
return;
int net_queue(int sock, struct peer *info, void *p, size_t size) {
struct epoll_event ev;
- info->data = malloc(size);
- if(NULL==info->data) { return -1; }
+ if((p!=NULL)&&(size>0)) {
+ info->data = malloc(size);
+ if(NULL==info->data) { return -1; }
- memcpy(info->data,p,size);
+ memcpy(info->data,p,size);
+ }
- ev.events = EPOLLOUT;
+ ev.events = EPOLLIN | EPOLLOUT | EPOLLET;
ev.data.ptr = info;
ev.data.fd = sock;
--- /dev/null
+#include<net.h>
+
+int net_send(int sock, struct peer *info, void *p, size_t size) {
+ ssize_t i;
+
+ i = send(sock,p,size,0);
+ if(i<size) {
+ if(i<0) {
+ perror("send");
+ return -1;
+ }
+
+ info->out = malloc(size-i);
+ if(NULL==info->out) {
+ perror("malloc");
+ return -1;
+ }
+
+ memcpy(info->out,p,size);
+ info->out_size = size;
+ return 0;
+ }
+
+ return 1;
+}
#include<net.h>
-int net_wait(int sock, struct peer *info, size_t size) {
+int net_wait(int sock, struct peer *info, void *p, size_t size) {
return -1;
+ /*if(-1==i) {
+ if(!((errno==EAGAIN)||(errno==EWOULDBLOCK))) {
+ perror("recv");
+ return -1;
+ }*/
}
static int peer_handshake_receive(int);
-int peer_handshake(int sock) {
- struct peer *info;
+int peer_handshake(int sock, struct peer *info) {
char header[HEADER_LENGTH] = HANDSHAKE_STRING;
- ssize_t i;
+ int i;
if(sock<0) { return -1; }
- if(peer_init(&info)<0) { return -1; }
-
if(peer_handshake_receive(sock)<0) { return -1; }
+ if(!info->handshake) { return 0; }
// copy infohash to buffer
memcpy(
info->peer_id,
PEER_PEER_ID_SIZE);
- // send header
- i = send(sock,header,HEADER_LENGTH,0);
- if(i<HEADER_LENGTH) {
- if(i<0) {
- perror("send");
- return -1;
- }
- goto epoll;
- }
+ if(net_send(sock,info,header,HEADER_LENGTH)<0) { return -1; }
return 1;
-epoll:
- if(net_queue(sock,info,&(header[i]),HEADER_LENGTH-i)<0) { return -1; }
- return 0;
}
static int peer_handshake_receive(int sock, struct peer *info) {
char header[HEADER_LENGTH];
+ struct torrent *p;
ssize_t i;
- i = recv(sock,header,HEADER_LENGTH);
- if(-1==i) {
- if(!((errno==EAGAIN)||(errno==EWOULDBLOCK))) {
- perror("recv");
- return;
- }
- goto wait;
- }
+ if(net_wait(sock,info,header,HEADER_LENGTH)<0) { return -1; }
- return -1;
+ memcpy(
+ info->infohash,
+ &(header[HANDSHAKE_STRING_LENGTH]),
+ PEER_INFOHASH_SIZE);
+ memcpy(
+ info->peer_id,
+ &(header[HANDSHAKE_STRING_LENGTH+PEER_INFOHASH_SIZE]),
+ PEER_INFOHASH_SIZE);
+
+ p = session_find_torrent(info->infohash,PEER_INFOHASH_SIZE);
+ if(NULL==p) { return -1; }
+
+ return 1;
wait:
- if(net_wait(sock,info,
+ if(net_wait(sock,info,header,i)<0) { return -1; }
+ return 0;
}