-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathDiagnosticsServer.c
More file actions
218 lines (169 loc) · 6.49 KB
/
DiagnosticsServer.c
File metadata and controls
218 lines (169 loc) · 6.49 KB
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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
/********************************************************************
* (C) Adam Petersen 2005
*
* This code accompanies the article "Patterns in C, part 5: REACTOR".
* The article is available as PDF from www.adampetersen.se
*
* The code is intended as a illustration of the Reactor at work and
* is not suitable for use in production code (in order to keep this
* example as short as possible, the error handling has been strongly
* simplified).
*
********************************************************************/
/******************************************************************************
* A simulation of a diagnostics server.
*
* A client that wants to log a diagnostic connects to this server using TCP/IP.
* The server gets notified about a connecting client through the Reactor.
* Upon such a notification, the server creates a client representation.
*******************************************************************************/
#include "DiagnosticsServer.h"
#include "DiagnosticsClient.h"
#include "EventHandler.h"
#include "ServerEventNotifier.h"
#include "Reactor.h"
#include "Error.h"
#include "TcpServer.h"
#include <stdlib.h>
#include <stdio.h>
#define MAX_NO_OF_CLIENTS 10
struct DiagnosticsServer
{
Handle listeningSocket;
EventHandler eventHandler;
/* All connected clients able to send diagnostics messages. */
DiagnosticsClientPtr clients[MAX_NO_OF_CLIENTS];
};
/************************************************************
* Function declarations.
************************************************************/
static void deleteAllClients(DiagnosticsServerPtr server);
static int matchControlledClientByPointer(const DiagnosticsServerPtr server,
const DiagnosticsClientPtr clientToMatch);
static int findFreeClientSlot(const DiagnosticsServerPtr server);
static int findMatchingClientSlot(const DiagnosticsServerPtr server,
const DiagnosticsClientPtr client);
static Handle getServerSocket(void* instance);
static void handleConnectRequest(void* instance);
static void onClientClosed(void* server,
void* closedClient);
/************************************************************
* Implementation of the EventHandler interface.
************************************************************/
static Handle getServerSocket(void* instance)
{
const DiagnosticsServerPtr server = instance;
return server->listeningSocket;
}
static void handleConnectRequest(void* instance)
{
DiagnosticsServerPtr server = instance;
const int freeSlot = findFreeClientSlot(server);
if(0 <= freeSlot) {
/* Define a callback for events requiring the actions of the server (for example
a closed connection). */
ServerEventNotifier eventNotifier = {0};
eventNotifier.server = server;
eventNotifier.onClientClosed = onClientClosed;
server->clients[freeSlot] = createClient(server->listeningSocket, &eventNotifier);
(void) printf("Server: Incoming connect request accepted\n");
}
else {
(void) printf("Server: Not space for more clients\n");
}
}
/************************************************************
* Implementation of the ServerEventNotifier interface.
************************************************************/
/**
* This function is invoked as a callback from the client representation
* in case it detects a disconnect on TCP level.
*/
static void onClientClosed(void* server,
void* closedClient)
{
DiagnosticsServerPtr serverInstance = server;
DiagnosticsClientPtr clientInstance = closedClient;
const int clientSlot = findMatchingClientSlot(serverInstance, clientInstance);
if(0 > clientSlot) {
error("Phantom client detected");
}
destroyClient(clientInstance);
serverInstance->clients[clientSlot] = NULL;
}
/************************************************************
* Implementation of the ADT functions of the server.
************************************************************/
/**
* Creates a server listening for connect requests on the given port.
* The server registers itself at the Reactor upon creation.
*/
DiagnosticsServerPtr createServer(unsigned int tcpPort)
{
DiagnosticsServerPtr newServer = malloc(sizeof *newServer);
if(NULL != newServer) {
int i = 0;
for(i = 0; i < MAX_NO_OF_CLIENTS; ++i) {
newServer->clients[i] = NULL;
}
newServer->listeningSocket = createServerSocket(tcpPort);
/* Successfully created -> register the listening socket. */
newServer->eventHandler.instance = newServer;
newServer->eventHandler.getHandle = getServerSocket;
newServer->eventHandler.handleEvent = handleConnectRequest;
Register(&newServer->eventHandler);
}
return newServer;
}
/**
* Unregisters at the Reactor and deletes all connected clients
* before the server itself is disposed.
* After completion of this function, the server-handle is invalid.
*/
void destroyServer(DiagnosticsServerPtr server)
{
deleteAllClients(server);
/* Before deleting the server we have to unregister at the Reactor. */
Unregister(&server->eventHandler);
disposeServerSocket(server->listeningSocket);
free(server);
}
/************************************************************
* Definition of the local utility functions.
************************************************************/
static void deleteAllClients(DiagnosticsServerPtr server)
{
int i = 0;
for(i = 0; i < MAX_NO_OF_CLIENTS; ++i) {
if(NULL != server->clients[i]) {
destroyClient(server->clients[i]);
}
}
}
/**
* Returns the index where a client matching the given pointer is found.
* Returns -1 if no match was found.
*/
static int matchControlledClientByPointer(const DiagnosticsServerPtr server,
const DiagnosticsClientPtr clientToMatch)
{
int clientSlot = -1;
int slotFound = 0;
int i = 0;
for(i = 0; (i < MAX_NO_OF_CLIENTS) && (0 == slotFound); ++i) {
if(clientToMatch == server->clients[i]) {
clientSlot = i;
slotFound = 1;
}
}
return clientSlot;
}
static int findFreeClientSlot(const DiagnosticsServerPtr server)
{
return matchControlledClientByPointer(server, NULL);
}
static int findMatchingClientSlot(const DiagnosticsServerPtr server,
const DiagnosticsClientPtr client)
{
return matchControlledClientByPointer(server, client);
}