-
Notifications
You must be signed in to change notification settings - Fork 0
/
DiagnosticsClient.c
154 lines (119 loc) · 5.03 KB
/
DiagnosticsClient.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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
/********************************************************************
* (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).
*
********************************************************************/
/*********************************************************************************
*
* The server side representation of a client sending diagnostic messages to the log.
*
* An instance of this client ADT is created as the server detects a connect request.
* Upon creation, the instance registers itself at the Reactor. The Reactor will notify
* this client representation as an incoming diagnostics message is pending.
* This client representation simply reads the message and prints it to stdout.
**********************************************************************************/
#include "DiagnosticsClient.h"
#include "DiagnosticsServer.h"
#include "EventHandler.h"
#include "Reactor.h"
#include "Error.h"
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
struct DiagnosticsClient
{
Handle clientSocket;
EventHandler eventHandler;
ServerEventNotifier eventNotifier;
};
#define MAX_MESSAGE_SIZE 1024
/************************************************************
* Function declarations.
************************************************************/
static Handle acceptClientConnection(int serverHandle);
static Handle getClientSocket(void* instance);
static void handleReadEvent(void* instance);
/************************************************************
* Implementation of the EventHandler interface.
************************************************************/
static Handle getClientSocket(void* instance)
{
const DiagnosticsClientPtr client = instance;
return client->clientSocket;
}
static void handleReadEvent(void* instance)
{
const DiagnosticsClientPtr client = instance;
char diagnosticMessage[MAX_MESSAGE_SIZE] = {0};
const ssize_t receiveResult = recv(client->clientSocket, diagnosticMessage, sizeof diagnosticMessage, 0);
if(0 < receiveResult) {
/* In the real world, we would probably put a protocol on top of TCP/IP in
order to be able to restore the message out of the byte stream (it is no
guarantee that the complete message is received in one recv(). */
(void) printf("Client: Diagnostics received - %s\n", diagnosticMessage);
}
else {
client->eventNotifier.onClientClosed(client->eventNotifier.server, client);
}
}
/************************************************************
* Implementation of the ADT functions of the client.
************************************************************/
/**
* Creates a representation of the client used to send diagnostic messages.
* The given handle must refer to a valid socket signalled for a pending connect request.
* The created client representation registers itself as the Reactor.
*/
DiagnosticsClientPtr createClient(Handle serverHandle,
const ServerEventNotifier* eventNotifier)
{
DiagnosticsClientPtr client = malloc(sizeof *client);
if(NULL != client) {
client->clientSocket = acceptClientConnection(serverHandle);
/* Successfully created -> register the client at the Reactor. */
client->eventHandler.instance = client;
client->eventHandler.getHandle = getClientSocket;
client->eventHandler.handleEvent = handleReadEvent;
Register(&client->eventHandler);
assert(NULL != eventNotifier);
client->eventNotifier = *eventNotifier;
}
return client;
}
/**
* Unregisters the given client at the Reactor and releases all associated resources.
* After completion of this function, the client-handle is invalid.
*/
void destroyClient(DiagnosticsClientPtr client)
{
/* Before deleting the client we have to unregister at the Reactor. */
Unregister(&client->eventHandler);
(void) close(client->clientSocket);
free(client);
}
/************************************************************
* Definition of the local utility function.
************************************************************/
static Handle acceptClientConnection(int serverHandle)
{
struct sockaddr_in clientAddress = {0};
socklen_t addressSize = sizeof clientAddress;
const Handle clientHandle = accept(serverHandle, (struct sockaddr*) &clientAddress, &addressSize);
if(0 > clientHandle) {
/* NOTE: In the real world, this function should be more forgiving.
For example, the client should be allowed to abort the connection request. */
error("Failed to accept client connection");
}
(void) printf("Client: New connection created on IP-address %X\n", ntohl(clientAddress.sin_addr.s_addr));
return clientHandle;
}