From 9a7be19859a285236dd95d4d19ca521d7e3736ff Mon Sep 17 00:00:00 2001 From: alex Date: Mon, 28 Mar 2022 17:07:18 -0700 Subject: [PATCH] ... --- Makefile.am | 12 +++ inc/net.h | 7 +- inc/peer.h | 15 ++++ src/net/expected.c | 39 +++++++++ src/net/handler.c | 66 ++++++---------- src/peer/bitfield.c | 2 +- src/peer/cancel.c | 2 +- src/peer/choke.c | 4 +- src/peer/hash.c | 4 +- src/peer/hashes.c | 5 ++ src/peer/have.c | 2 +- src/peer/interest.c | 4 +- src/peer/keepalive.c | 5 ++ src/peer/piece.c | 5 ++ src/peer/reject.c | 5 ++ src/peer/request.c | 2 +- test/unit/Makefile.am | 2 + test/unit/net.tests.c | 180 ++++++++++++++++++++++++++++++++++++++++++ 18 files changed, 308 insertions(+), 53 deletions(-) create mode 100644 src/net/expected.c create mode 100644 src/peer/hashes.c create mode 100644 src/peer/keepalive.c create mode 100644 src/peer/piece.c create mode 100644 src/peer/reject.c diff --git a/Makefile.am b/Makefile.am index 5c01a31..4d513e6 100644 --- a/Makefile.am +++ b/Makefile.am @@ -34,6 +34,7 @@ seederd_SOURCES = \ src/main.c \ src/meta.c \ src/net/cache.c \ + src/net/expected.c \ src/net/handler.c \ src/net/listen.c \ src/net/loop.c \ @@ -55,9 +56,20 @@ seederd_SOURCES = \ src/opt/set.c \ src/opt/watch.c \ src/opt/worker.c \ + src/peer/bitfield.c \ + src/peer/cancel.c \ + src/peer/choke.c \ src/peer/free.c \ src/peer/handshake.c \ + src/peer/hash.c \ + src/peer/hashes.c \ + src/peer/have.c \ src/peer/init.c \ + src/peer/interest.c \ + src/peer/keepalive.c \ + src/peer/piece.c \ + src/peer/reject.c \ + src/peer/request.c \ src/pqueue.c \ src/rss/entry.c \ src/rss/footer.c \ diff --git a/inc/net.h b/inc/net.h index 9cd57de..d69828f 100644 --- a/inc/net.h +++ b/inc/net.h @@ -1,9 +1,6 @@ #ifndef __NET_H_ #define __NET_H_ -#include -#include - #include #include #include @@ -15,6 +12,9 @@ #include #include +#include +#include + struct net_info { int tcp_socket; int udp_socket; @@ -37,6 +37,7 @@ struct net_info { } int net_cache(void**,size_t*,void*,size_t); +ssize_t net_expected(int,enum peer_message*); void net_handler(int,int,struct peer*); int net_listen_sock(); void net_loop(); diff --git a/inc/peer.h b/inc/peer.h index df2a21f..ccc9ee4 100644 --- a/inc/peer.h +++ b/inc/peer.h @@ -26,6 +26,7 @@ struct peer { }; enum peer_message { + PEER_MESSAGE_KEEPALIVE = -1, PEER_MESSAGE_CHOKE = 0, PEER_MESSAGE_UNCHOKE = 1, PEER_MESSAGE_INTERESTED = 2, @@ -44,8 +45,22 @@ enum peer_message { #include #include +int peer_bitfield(int,struct peer*); +int peer_cancel(int,struct peer*); +int peer_choke(int,struct peer*); void peer_free(struct peer*); int peer_handshake(int,struct peer*); +int peer_hash_reject(int,struct peer*); +int peer_hash_request(int,struct peer*); +int peer_hashes(int,struct peer*); +int peer_have(int,struct peer*); int peer_init(struct peer**); +int peer_interested(int,struct peer*); +int peer_keepalive(int,struct peer*); +int peer_not_interested(int,struct peer*); +int peer_piece(int,struct peer*); +int peer_reject(int,struct peer*); +int peer_request(int,struct peer*); +int peer_unchoke(int,struct peer*); #endif diff --git a/src/net/expected.c b/src/net/expected.c new file mode 100644 index 0000000..87c5518 --- /dev/null +++ b/src/net/expected.c @@ -0,0 +1,39 @@ +#include + +ssize_t net_expected(int sock, enum peer_message *type) { + unsigned char buf[4]; + ssize_t i; + + (*type) = PEER_MESSAGE_KEEPALIVE; + + i = recv(sock,buf,5,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; } + + if(i==5) { (*type) = (uint8_t)buf[4]; } + + i = 0; + for(size_t j=0;j<4;j++) { + i <<= 8; + i += buf[j]; + } + + return i; +} diff --git a/src/net/handler.c b/src/net/handler.c index 15c98ca..71c25fe 100644 --- a/src/net/handler.c +++ b/src/net/handler.c @@ -1,85 +1,71 @@ #include -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; diff --git a/src/peer/bitfield.c b/src/peer/bitfield.c index 9947ff8..3df3b54 100644 --- a/src/peer/bitfield.c +++ b/src/peer/bitfield.c @@ -1,5 +1,5 @@ #include -int peer_bitfield(int sock) { +int peer_bitfield(int sock, struct peer *info) { return -1; } diff --git a/src/peer/cancel.c b/src/peer/cancel.c index 07da8b9..bbb3f4a 100644 --- a/src/peer/cancel.c +++ b/src/peer/cancel.c @@ -1,5 +1,5 @@ #include -int peer_cancel() { +int peer_cancel(int sock, struct peer *info) { return -1; } diff --git a/src/peer/choke.c b/src/peer/choke.c index 99d8423..cded0a3 100644 --- a/src/peer/choke.c +++ b/src/peer/choke.c @@ -1,9 +1,9 @@ #include -int peer_choke(int sock) { +int peer_choke(int sock, struct peer *info) { return -1; } -int peer_unchoke(int sock) { +int peer_unchoke(int sock, struct peer *info) { return -1; } diff --git a/src/peer/hash.c b/src/peer/hash.c index 4f1e067..fe8d77e 100644 --- a/src/peer/hash.c +++ b/src/peer/hash.c @@ -1,9 +1,9 @@ #include -int peer_hash_request() { +int peer_hash_request(int sock, struct peer *info) { return -1; } -int peer_hash_reject() { +int peer_hash_reject(int sock, struct peer *info) { return -1; } diff --git a/src/peer/hashes.c b/src/peer/hashes.c new file mode 100644 index 0000000..323a625 --- /dev/null +++ b/src/peer/hashes.c @@ -0,0 +1,5 @@ +#include + +int peer_hashes(int sock, struct peer *info) { + return -1; +} diff --git a/src/peer/have.c b/src/peer/have.c index 28c14b2..e27f818 100644 --- a/src/peer/have.c +++ b/src/peer/have.c @@ -1,5 +1,5 @@ #include -int peer_have(int sock) { +int peer_have(int sock, struct peer *info) { return -1; } diff --git a/src/peer/interest.c b/src/peer/interest.c index 651704d..e9033c7 100644 --- a/src/peer/interest.c +++ b/src/peer/interest.c @@ -1,9 +1,9 @@ #include -int peer_interested(int sock) { +int peer_interested(int sock, struct peer *info) { return -1; } -int peer_not_interested(int sock) { +int peer_not_interested(int sock, struct peer *info) { return -1; } diff --git a/src/peer/keepalive.c b/src/peer/keepalive.c new file mode 100644 index 0000000..922e979 --- /dev/null +++ b/src/peer/keepalive.c @@ -0,0 +1,5 @@ +#include + +int peer_keepalive(int sock, struct peer *info) { + return -1; +} diff --git a/src/peer/piece.c b/src/peer/piece.c new file mode 100644 index 0000000..92d60ad --- /dev/null +++ b/src/peer/piece.c @@ -0,0 +1,5 @@ +#include + +int peer_piece(int sock, struct peer *info) { + return -1; +} diff --git a/src/peer/reject.c b/src/peer/reject.c new file mode 100644 index 0000000..f3e0153 --- /dev/null +++ b/src/peer/reject.c @@ -0,0 +1,5 @@ +#include + +int peer_reject(int sock, struct peer *info) { + return -1; +} diff --git a/src/peer/request.c b/src/peer/request.c index 371f988..1a42c80 100644 --- a/src/peer/request.c +++ b/src/peer/request.c @@ -1,5 +1,5 @@ #include -int peer_request() { +int peer_request(int sock, struct peer *info) { return -1; } diff --git a/test/unit/Makefile.am b/test/unit/Makefile.am index ea1d39f..fe93e83 100644 --- a/test/unit/Makefile.am +++ b/test/unit/Makefile.am @@ -120,6 +120,8 @@ net_tests_SOURCES = \ $(common_SOURCES) \ net.tests.c \ $(top_srcdir)/src/net/cache.c \ + $(top_srcdir)/src/net/expected.c \ + $(top_srcdir)/src/net/handler.c \ $(top_srcdir)/src/net/queue.c \ $(top_srcdir)/src/net/send.c \ $(top_srcdir)/src/net/wait.c \ diff --git a/test/unit/net.tests.c b/test/unit/net.tests.c index eeb6014..766c20e 100644 --- a/test/unit/net.tests.c +++ b/test/unit/net.tests.c @@ -5,10 +5,32 @@ 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; @@ -16,6 +38,9 @@ int main() { 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(); @@ -68,6 +93,161 @@ static void net_cache_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; -- 2.30.2