diff --git a/README.md b/README.md index 2404d7b..b63a16a 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,15 @@ -# KQUEUE Utilization +# Kernel Queue (kqueue) Utilization This is your lame attempt to understand how those Network Virtual Functions sofware works as well to sharpen your understanding on C++ and C programming language. +## Why not [epoll]() or [select]() + +Using epoll or select would make your system spend most of its time looking at and fiddling sith the data structures and has very little time for anything else. + + +## Notes + -## Hints - Compile using `g++` for the file watcher @@ -13,8 +19,8 @@ The `kqueue_socket.c` is my attempt on create a socket watcher timer program usi - [KQUEUE NETBSD GUIDE](https://wiki.netbsd.org/tutorials/kqueue_tutorial/) -``` - +```C + // -------------------------------------------- struct kevent my_event; struct kevent my_change; @@ -23,13 +29,20 @@ The `kqueue_socket.c` is my attempt on create a socket watcher timer program usi for(;;){ ...; - } - ``` +### TCP 01 + +- Pointer of kevent + +### TCP 02 + +- Array of kevent + ## Goal + - Understand the difference between c++ and C - Understand how strcuct works and the difference between it on c++ and C - Understand diff --git a/bin/tcp_sock b/bin/tcp_sock new file mode 100755 index 0000000..cd692d8 Binary files /dev/null and b/bin/tcp_sock differ diff --git a/bin/wtf b/bin/wtf new file mode 100755 index 0000000..718c598 Binary files /dev/null and b/bin/wtf differ diff --git a/kqueue_file_watch.cpp b/src/kqueue_file_watch.cpp similarity index 100% rename from kqueue_file_watch.cpp rename to src/kqueue_file_watch.cpp diff --git a/kqueue_socket.c b/src/kqueue_ktimer.c similarity index 100% rename from kqueue_socket.c rename to src/kqueue_ktimer.c diff --git a/src/ktcp_socket_01.c b/src/ktcp_socket_01.c new file mode 100644 index 0000000..2405080 --- /dev/null +++ b/src/ktcp_socket_01.c @@ -0,0 +1,106 @@ +#include +#include +#include +#include +#include +#include +#include + +int main() { + int socket_listen_fd, + port_num = 1339, + client_len, + socket_connection_fd, + kq, + new_events; + + struct kevent change_event[4], event[4]; + struct kevent evList[32]; + + struct sockaddr_in serv_addr, client_addr; + + if (((socket_listen_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)) + { + perror("Failed creating socket"); + exit(1); + } + + bzero((char *)&serv_addr, sizeof(serv_addr)); + serv_addr.sin_family = AF_INET; + serv_addr.sin_addr.s_addr = INADDR_ANY; + serv_addr.sin_port = htons(port_num); + + if (bind(socket_listen_fd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) + { + perror("Failed binding socket"); + exit(1); + } + + listen(socket_listen_fd, 3); + client_len = sizeof(client_addr); + + // kqueue SETUP + + kq = kqueue(); + + EV_SET(change_event, socket_listen_fd, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, 0); + if (kevent(kq, change_event, 1, NULL, 0, NULL) == -1) + { + perror("Failed create kevent"); + exit(1); + } + + for (;;) + { + + new_events = kevent(kq, NULL, 0, event, 1, NULL); + + // printf("New events -> %d\n", new_events); + + if (new_events == -1) + { + perror("Failed create new kevent"); + exit(1); + } + + for (int i = 0; new_events > i; i++) + { + printf("Amount of new events : %d\n", new_events); + int event_fd = event[i].ident; + + if (event[i].flags & EV_EOF) + { + printf("Client disconnected...\n"); + close(event_fd); + } + + else if (event_fd == socket_listen_fd) + { + printf("New connection coming in...\n"); + + socket_connection_fd = accept(event_fd, (struct sockaddr *)&client_addr, (socklen_t *)&client_len); + if (socket_connection_fd == -1) + { + perror("Failed to accept connection..."); + } + + EV_SET(change_event, socket_connection_fd, EVFILT_READ, EV_ADD, 0, 0, NULL); + if (kevent(kq, change_event, 1, NULL, 0, NULL) < 0) + { + perror("Kevent failed to maintain connection"); + } + + } + + else if (event[i].filter == EVFILT_READ) + { + char buf[1024]; + size_t bytes_read = recv(event_fd, buf, sizeof(buf), 0); + printf("Reading %zu bytes\n", bytes_read); + } + } + } + + return 0; + +} diff --git a/src/ktcp_socket_02.c b/src/ktcp_socket_02.c new file mode 100644 index 0000000..cd36ef0 --- /dev/null +++ b/src/ktcp_socket_02.c @@ -0,0 +1,116 @@ +#include +#include +#include +#include +#include +#include +#include + +int main() { + int socket_listen_fd, + port_num = 2339, + client_len, + socket_connection_fd, + kq, + new_events; + +struct kevent change_event, event; + struct kevent evList[32]; + + struct sockaddr_in serv_addr, client_addr; + + if (((socket_listen_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)) + { + perror("Failed creating socket"); + exit(1); + } + + bzero((char *)&serv_addr, sizeof(serv_addr)); + serv_addr.sin_family = AF_INET; + serv_addr.sin_addr.s_addr = INADDR_ANY; + serv_addr.sin_port = htons(port_num); + + if (bind(socket_listen_fd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) + { perror("Failed binding socket"); exit(1); + } + + listen(socket_listen_fd, 3); + client_len = sizeof(client_addr); + + // kqueue SETUP + + kq = kqueue(); + + EV_SET(&change_event, socket_listen_fd, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, 0); + if (kevent(kq, &change_event, 1, NULL, 0, NULL) == -1) + { + perror("Failed create kevent"); + exit(1); + } + + for (;;) + { + + new_events = kevent(kq, NULL, 0, evList, 1, NULL); + + // printf("New events -> %d\n", new_events); + + if (new_events == -1) + { + perror("Failed create new kevent"); + exit(1); + } + + for (int i = 0; new_events > i; i++) + { + printf("Amount of new events : %d\n", new_events); + int event_fd = evList[i].ident; + + if (evList[i].flags & EV_EOF) + { + printf("Client disconnected...\n"); + close(event_fd); + } + + else if (event_fd == socket_listen_fd) + { + printf("New connection coming in...\n"); + + socket_connection_fd = accept(event_fd, (struct sockaddr *)&client_addr, (socklen_t *)&client_len); + if (socket_connection_fd == -1) + { + perror("Failed to accept connection..."); + } + + EV_SET(&change_event, socket_connection_fd, EVFILT_READ, EV_ADD, 0, 0, NULL); + if (kevent(kq, &change_event, 1, NULL, 0, NULL) < 0) + { + perror("Kevent failed to maintain connection"); + } + + } + + else if (evList[i].filter == EVFILT_READ) + { + char buf[1024]; + size_t bytes_read = recv(event_fd, buf, sizeof(buf), 0); + printf("--------------------------------------------------\n"); + printf("Reading %zu bytes\n", bytes_read); + printf("Incoming msg : %s", buf); + printf("--------------------------------------------------\n"); + + char s_buf[1024]; + int len; + char *message = "[+] Hello from kTCP\n"; + + strcpy(s_buf, message); + + send(event_fd, s_buf, strlen(s_buf), 0); + + } + } + } + + return 0; + +} diff --git a/src/wtf.c b/src/wtf.c new file mode 100644 index 0000000..9a6fff8 --- /dev/null +++ b/src/wtf.c @@ -0,0 +1,125 @@ +#include +#include +#include +#include +#include +#include +#include + +int main() +{ + // All needed variables. + int socket_listen_fd, + portno = 1815, + client_len, + socket_connection_fd, + kq, + new_events; + struct kevent change_event[4], + event[4]; + struct sockaddr_in serv_addr, + client_addr; + + // Create socket. + if (((socket_listen_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)) + { + perror("ERROR opening socket"); + exit(1); + } + + // Create socket structure and bind to ip address. + bzero((char *)&serv_addr, sizeof(serv_addr)); + serv_addr.sin_family = AF_INET; + serv_addr.sin_addr.s_addr = INADDR_ANY; + serv_addr.sin_port = htons(portno); + + if (bind(socket_listen_fd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) + { + perror("Error binding socket"); + exit(1); + } + + // Start listening. + listen(socket_listen_fd, 3); + client_len = sizeof(client_addr); + + // Prepare the kqueue. + kq = kqueue(); + + // Create event 'filter', these are the events we want to monitor. + // Here we want to monitor: socket_listen_fd, for the events: EVFILT_READ + // (when there is data to be read on the socket), and perform the following + // actions on this kevent: EV_ADD and EV_ENABLE (add the event to the kqueue + // and enable it). + EV_SET(change_event, socket_listen_fd, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, 0); + + // Register kevent with the kqueue. + if (kevent(kq, change_event, 1, NULL, 0, NULL) == -1) + { + perror("kevent"); + exit(1); + } + + // Actual event loop. + for (;;) + { + // Check for new events, but do not register new events with + // the kqueue. Hence the 2nd and 3rd arguments are NULL, 0. + // Only handle 1 new event per iteration in the loop; 5th + // argument is 1. + new_events = kevent(kq, NULL, 0, event, 1, NULL); + if (new_events == -1) + { + perror("kevent"); + exit(1); + } + + for (int i = 0; new_events > i; i++) + { + printf("amount of new events: %d\n", new_events); + int event_fd = event[i].ident; + + // When the client disconnects an EOF is sent. By closing the file + // descriptor the event is automatically removed from the kqueue. + if (event[i].flags & EV_EOF) + { + printf("Client has disconnected\n"); + close(event_fd); + } + // If the new event's file descriptor is the same as the listening + // socket's file descriptor, we are sure that a new client wants + // to connect to our socket. + else if (event_fd == socket_listen_fd) + { + printf("New connection coming in...\n"); + + // Incoming socket connection on the listening socket. + // Create a new socket for the actual connection to client. + socket_connection_fd = accept(event_fd, (struct sockaddr *)&client_addr, (socklen_t *)&client_len); + if (socket_connection_fd == -1) + { + perror("Accept socket error"); + } + + // Put this new socket connection also as a 'filter' event + // to watch in kqueue, so we can now watch for events on this + // new socket. + EV_SET(change_event, socket_connection_fd, EVFILT_READ, EV_ADD, 0, 0, NULL); + if (kevent(kq, change_event, 1, NULL, 0, NULL) < 0) + { + perror("kevent error"); + } + } + + else if (event[i].filter & EVFILT_READ) + { + // Read bytes from socket + char buf[1024]; + size_t bytes_read = recv(event_fd, buf, sizeof(buf), 0); + printf("read %zu bytes\n", bytes_read); + } + } + } + + return 0; +}