#include<net.h>
-static uint32_t net_expected_length(int);
static int send_remaining(int,struct peer*);
-static uint32_t net_expected_length(int sock) {
- unsigned char buf[4];
- uint32_t len;
- ssize_t i;
-
- i = recv(sock,buf,4,MSG_PEEK);
- if(-1==i) {
- if(!((errno==EAGAIN)||(errno==EWOULDBLOCK))) {
- perror("recv");
- return -1;
- }
-
- // 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) { return 0; }
-
- len = 0;
- for(size_t j=0;j<4;j++) {
- len <<= 1;
- len += buf[j];
- }
-
- return i;
-}
void net_handler(int epoll_fd, int sock, struct peer *info) {
+ enum peer_message type;
uint32_t i;
+ if(epoll_fd<0) { return; }
+ if(sock<0) { return; }
+ if(NULL==info) { goto close; }
+
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
+ if((i = net_expected(sock,&type))<0) { goto close; }
- switch(0) {
+ switch(type) {
+ /* these are ordered based on enum peer_message */
+ case PEER_MESSAGE_KEEPALIVE:
+ if(peer_keepalive(sock,info)<0) { goto close; }
+ break;
case PEER_MESSAGE_CHOKE:
+ if(peer_choke(sock,info)<0) { goto close; }
break;
case PEER_MESSAGE_UNCHOKE:
+ if(peer_unchoke(sock,info)<0) { goto close; }
break;
case PEER_MESSAGE_INTERESTED:
+ if(peer_interested(sock,info)<0) { goto close; }
break;
case PEER_MESSAGE_NOT_INTERESTED:
+ if(peer_not_interested(sock,info)<0) { goto close; }
break;
case PEER_MESSAGE_HAVE:
+ if(peer_have(sock,info)<0) { goto close; }
break;
case PEER_MESSAGE_BITFIELD:
+ if(peer_bitfield(sock,info)<0) { goto close; }
break;
case PEER_MESSAGE_REQUEST:
+ if(peer_request(sock,info)<0) { goto close; }
break;
case PEER_MESSAGE_PIECE:
+ if(peer_piece(sock,info)<0) { goto close; }
break;
case PEER_MESSAGE_CANCEL:
+ if(peer_cancel(sock,info)<0) { goto close; }
break;
case PEER_MESSAGE_REJECT:
+ if(peer_reject(sock,info)<0) { goto close; }
break;
case PEER_MESSAGE_HASH_REQUEST:
+ if(peer_hash_request(sock,info)<0) { goto close; }
break;
case PEER_MESSAGE_HASHES:
+ if(peer_hashes(sock,info)<0) { goto close; }
break;
case PEER_MESSAGE_HASH_REJECT:
+ if(peer_hash_reject(sock,info)<0) { goto close; }
break;
default:
- break;
+ goto close;
}
- return;
+ goto queue;
remaining:
if(send_remaining(sock,info)<0) { goto close; }
goto queue;
int main();
static void setup_sockets();
static void net_cache_basic_test();
+static void net_expected_basic_test();
+static void net_handler_basic_test();
+static void net_handler_invalid_message_test();
static void net_queue_basic_test();
static void net_send_basic_test();
static void net_wait_basic_test();
+/* dummy functions (and array) used to test net_handler */
+int message_count[25];
+int peer_bitfield(int sock,struct peer *info) { message_count[PEER_MESSAGE_BITFIELD+1]++; return 0; }
+int peer_cancel(int sock,struct peer *info) { message_count[PEER_MESSAGE_CANCEL+1]++; return 0; }
+int peer_choke(int sock,struct peer *info) { message_count[PEER_MESSAGE_CHOKE+1]++; return 0; }
+int peer_handshake(int sock,struct peer *info) { return 0; }
+int peer_hash_reject(int sock,struct peer *info) { message_count[PEER_MESSAGE_HASH_REJECT+1]++; return 0; }
+int peer_hash_request(int sock,struct peer *info) { message_count[PEER_MESSAGE_HASH_REQUEST+1]++; return 0; }
+int peer_hashes(int sock,struct peer *info) { message_count[PEER_MESSAGE_HASHES+1]++; return 0; }
+int peer_have(int sock,struct peer *info) { message_count[PEER_MESSAGE_HAVE+1]++; return 0; }
+int peer_interested(int sock,struct peer *info) { message_count[PEER_MESSAGE_INTERESTED+1]++; return 0; }
+int peer_keepalive(int sock,struct peer *info) { message_count[PEER_MESSAGE_KEEPALIVE+1]++; return 0; }
+int peer_not_interested(int sock,struct peer *info) { message_count[PEER_MESSAGE_NOT_INTERESTED+1]++; return 0; }
+int peer_piece(int sock,struct peer *info) { message_count[PEER_MESSAGE_PIECE+1]++; return 0; }
+int peer_reject(int sock,struct peer *info) { message_count[PEER_MESSAGE_REJECT+1]++; return 0; }
+int peer_request(int sock,struct peer *info) { message_count[PEER_MESSAGE_REQUEST+1]++; return 0; }
+int peer_unchoke(int sock,struct peer *info) { message_count[PEER_MESSAGE_UNCHOKE+1]++; return 0; }
+/* end dummy functions */
+
static int read_sock;
static int write_sock;
setup_env();
net_cache_basic_test();
+ net_expected_basic_test();
+ net_handler_basic_test();
+ net_handler_invalid_message_test();
net_queue_basic_test();
net_send_basic_test();
net_wait_basic_test();
free(p1);
}
+static void net_expected_basic_test() {
+ struct peer *info;
+ enum peer_message type;
+ unsigned char buf[10];
+
+ assert(1==peer_init(&info));
+
+ setup_sockets();
+
+ /* verify messages with <4 bytes returns keepalive */
+ unsigned char expected1[4] = "\x00\x00\x00\x00";
+ assert(3==write(write_sock,expected1,3));
+
+ assert(0==net_expected(read_sock,&type));
+ assert(PEER_MESSAGE_KEEPALIVE==type);
+ assert(3==read(read_sock,buf,sizeof(buf)));
+
+ /* verify keepalive returns as expected */
+ assert(4==write(write_sock,expected1,4));
+
+ assert(0==net_expected(read_sock,&type));
+ assert(PEER_MESSAGE_KEEPALIVE==type);
+ assert(4==read(read_sock,buf,sizeof(buf)));
+
+ unsigned char expected2[5] = "\x00\x00\x01\x00";
+ expected2[4] = PEER_MESSAGE_CHOKE;
+ assert(5==write(write_sock,expected2,5));
+
+ assert(256==net_expected(read_sock,&type));
+ assert(PEER_MESSAGE_CHOKE==type);
+ assert(5==read(read_sock,buf,sizeof(buf)));
+
+ unsigned char expected3[5] = "\x00\x10\x01\x00";
+ expected3[4] = PEER_MESSAGE_HASHES;
+ assert(5==write(write_sock,expected3,5));
+
+ assert(1048832==net_expected(read_sock,&type));
+ assert(PEER_MESSAGE_HASHES==type);
+ assert(5==read(read_sock,buf,sizeof(buf)));
+
+ unsigned char expected4[5] = "\xf0\x10\x01\x00";
+ expected4[4] = PEER_MESSAGE_UNCHOKE;
+ assert(5==write(write_sock,expected4,5));
+
+ assert(4027580672==net_expected(read_sock,&type));
+ assert(PEER_MESSAGE_UNCHOKE==type);
+ assert(5==read(read_sock,buf,sizeof(buf)));
+
+ peer_free(info);
+ close(read_sock);
+ close(write_sock);
+}
+
+/* Parameters:
+ * unsigned char *message
+ * enum peer_message type
+ */
+#define NET_HANDLER_HELPER(message,type) { \
+ assert(sizeof(message)==write(write_sock,message,sizeof(message))); \
+\
+ net_handler(epoll_fd,read_sock,info); \
+ assert(0==epoll_ctl(epoll_fd,EPOLL_CTL_DEL,read_sock,NULL)); \
+ assert(sizeof(message)==read(read_sock,buf,sizeof(buf))); \
+\
+ assert(1==message_count[type+1]); \
+}
+
+static void net_handler_invalid_message_test() {
+ struct peer *info;
+ int epoll_fd;
+
+ assert(1==peer_init(&info));
+ info->handshake = 1;
+
+ epoll_fd = epoll_create1(0);
+ assert(epoll_fd!=-1);
+
+ setup_sockets();
+
+ memset(message_count, 0, sizeof(message_count));
+
+ unsigned char invalid_message_type[5] = "\x00\x00\x00\x01\xff";
+ assert(5==write(write_sock,invalid_message_type,5));
+ net_handler(epoll_fd,read_sock,info);
+
+ for(size_t i=0;i<25;i++) {
+ assert(0==message_count[i]);
+ }
+
+ close(epoll_fd);
+}
+
+static void net_handler_basic_test() {
+ struct peer *info;
+ unsigned char buf[10];
+ int epoll_fd;
+
+ memset(message_count, 0, sizeof(message_count));
+
+ assert(1==peer_init(&info));
+ info->handshake = 1;
+
+ epoll_fd = epoll_create1(0);
+ assert(epoll_fd!=-1);
+
+ setup_sockets();
+
+ /* all peer_message enums indexes are +1 in message_count */
+ unsigned char keepalive_message[4] = "\x00\x00\x00\x00";
+ NET_HANDLER_HELPER(keepalive_message,PEER_MESSAGE_KEEPALIVE);
+
+ unsigned char choke_message[5] = "\x00\x00\x00\x01\x00";
+ NET_HANDLER_HELPER(choke_message,PEER_MESSAGE_CHOKE);
+
+ unsigned char unchoke_message[5] = "\x00\x00\x00\x01\x01";
+ NET_HANDLER_HELPER(unchoke_message,PEER_MESSAGE_UNCHOKE);
+
+ unsigned char interested_message[5] = "\x00\x00\x00\x01\x02";
+ NET_HANDLER_HELPER(interested_message,PEER_MESSAGE_INTERESTED);
+
+ unsigned char not_interested_message[5] = "\x00\x00\x00\x01\x03";
+ NET_HANDLER_HELPER(not_interested_message,PEER_MESSAGE_NOT_INTERESTED);
+
+ unsigned char have_message[5] = "\x00\x00\x00\x01\x04";
+ NET_HANDLER_HELPER(have_message,PEER_MESSAGE_HAVE);
+
+ unsigned char bitfield_message[5] = "\x00\x00\x00\x01\x05";
+ NET_HANDLER_HELPER(bitfield_message,PEER_MESSAGE_BITFIELD);
+
+ unsigned char request_message[5] = "\x00\x00\x00\x01\x06";
+ NET_HANDLER_HELPER(request_message,PEER_MESSAGE_REQUEST);
+
+ unsigned char piece_message[5] = "\x00\x00\x00\x01\x07";
+ NET_HANDLER_HELPER(piece_message,PEER_MESSAGE_PIECE);
+
+ unsigned char cancel_message[5] = "\x00\x00\x00\x01\x08";
+ NET_HANDLER_HELPER(cancel_message,PEER_MESSAGE_CANCEL);
+
+ unsigned char reject_message[5] = "\x00\x00\x00\x01\x10";
+ NET_HANDLER_HELPER(reject_message,PEER_MESSAGE_REJECT);
+
+ unsigned char hash_request_message[5] = "\x00\x00\x00\x01\x15";
+ NET_HANDLER_HELPER(hash_request_message,PEER_MESSAGE_HASH_REQUEST);
+
+ unsigned char hashes_message[5] = "\x00\x00\x00\x01\x16";
+ NET_HANDLER_HELPER(hashes_message,PEER_MESSAGE_HASHES);
+
+ unsigned char hash_reject_message[5] = "\x00\x00\x00\x01\x17";
+ NET_HANDLER_HELPER(hash_reject_message,PEER_MESSAGE_HASH_REJECT);
+
+ peer_free(info);
+ close(read_sock);
+ close(write_sock);
+}
+
static void net_queue_basic_test() {
int epoll_fd;
int sock;