forked from frevib/kqueue-tcp-server
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtcpserver_kqueue_callback.c
138 lines (115 loc) · 3.93 KB
/
tcpserver_kqueue_callback.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
#include <stdio.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/event.h>
#include <string.h>
#include <unistd.h>
#define ERROR_EXIT(...) { fprintf(stderr, "ERROR: " __VA_ARGS__); exit(EXIT_FAILURE); }
typedef void (*IntIntFunc)(int, int);
// Function that takes two int arguments and prints them
void printSum(int a, int b) {
int sum = a +b;
printf("sum of %d + %d = %d\n", a, b, sum);
}
void printMultiplication(int a, int b) {
int multi = a * b;
printf("product of %d * %d = %d\n", a, b, multi);
}
int main()
{
// Initialise all needed variables.
int socket_listen_fd,
portno = 1816,
client_len,
socket_connection_fd,
kq,
new_events,
callbacks_len = 2;
struct kevent change_event[4],
event[4];
struct sockaddr_in serv_addr,
client_addr;
// initialise our callback functions
IntIntFunc* callbacks = malloc(callbacks_len * sizeof(IntIntFunc)); // 8
callbacks[0] = &printSum;
callbacks[1] = &printMultiplication;
// Create socket
if (((socket_listen_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0))
{
ERROR_EXIT("Error creating socket");
}
// 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)
{
ERROR_EXIT("Error binding socket");
}
// Mark socket as passive and start listening
listen(socket_listen_fd, 3);
client_len = sizeof(client_addr);
// Create kqueue
kq = kqueue();
// Create filter for events that we want to monitor on given fd
// one the EVFILT_READ event has occured, we add it to the event queue.
EV_SET(change_event, socket_listen_fd, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, 0);
// Register events
if (kevent(kq, change_event, 1, NULL, 0, NULL) == -1)
{
ERROR_EXIT("kevent: register socket_listen_fd");
}
// Event Loop ⚛️
printf("Event loop up and running!🚀⚛️\nCallbacks registered!⚡️\nWaiting for incoming events📡...\n");
for (;;)
{
// Poll for new events
new_events = kevent(kq, NULL, 0, event, 1, NULL);
if (new_events == -1)
{
ERROR_EXIT("kevent: poll for events");
}
for (int i = 0; new_events > i; i++)
{
int event_fd = event[i].ident;
// Close fd when client disconnects
if (event[i].flags & EV_EOF)
{
close(event_fd);
}
// In case the events fd is the same as our listening fd
// we have an incoming connection
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)
{
ERROR_EXIT("accept socket");
}
// Add the new connection to our interest list
EV_SET(change_event, socket_connection_fd, EVFILT_READ, EV_ADD, 0, 0, NULL);
if (kevent(kq, change_event, 1, NULL, 0, NULL) < 0)
{
ERROR_EXIT("kevent: register socket_connection_fd");
}
}
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);
int a = 0;
int b = 0;
sscanf(buf, "%d %d", &a, &b);
// execute 'callbacks'
for(int l = 0; l < callbacks_len; l++) {
callbacks[l](a, b);
}
}
}
}
return 0;
}