summaryrefslogtreecommitdiff
path: root/tests/network/test_proactor.c
blob: 0722fe25b3d619972b62c3e604004a7e772ca6d7 (plain)
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
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
/*
    Copyright (C) 2008 Andreas Baumann <abaumann@yahoo.com>

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

/* Trying to implement a simplistic asynch I/O system using the Proactor
   Connector/Acceptor pattern. Unix-only at the moment. Trying to get the
   C APIs right
 */

/* INTERFACE */

#include "errors.h"

#include "port/unused.h"
#include "network/network.h"

#include <sys/types.h>			/* for size_t */

typedef struct wolf_asio_proc_t *wolf_asio_proc_p;
typedef struct wolf_asio_completion_dispatcher_t *wolf_asio_completion_dispatcher_p;

/* Completion Handler: they are implemented in the Proactive Initiator, in
 * this case:
 * - the Acceptor: accepts new connections arsynchronously
 * - the Protocol Handler: handles all the communication with the
 *   other peer, it should never do long synchronous work!
 * - per operation there is one specialized handler, so we can pass
 *   aynchronous request data to it
 */
typedef void(*wolf_asio_write_completion_handler_f)( void );
typedef void(*wolf_asio_read_completion_handler_f)( void );
typedef void(*wolf_asio_accept_completion_handler_f)( void );
typedef void(*wolf_asio_connect_completion_handler_f)( void );

/* Asynchronous Operation Processor (asio_proc):
 * - performs the asynchronous opreation on behalf of the application,
 *   usually with a lot of help from the operating system
 * - must NOT seize control of the callers thread!
 * - if we miss asynchronous OS calls, we must emulate them with a
 *   pool of dedicated threads which poll the OS
 */

typedef struct wolf_asio_proc_t {
	wolf_asio_completion_dispatcher_p completion_dispatcher;
} wolf_asio_proc_t;

wolf_asio_proc_p wolf_asio_proc_new(		wolf_asio_completion_dispatcher_p completion_dispatcher,
						wolf_error_t *error );

wolf_error_t wolf_asio_proc_free(		wolf_asio_proc_p proc );

/*
 * The main event loop of the asio processor. We can run it were we want, even with
 * a dedicated pool of threads, if we like
 */
wolf_error_t wolf_asio_proc_event_loop(		wolf_asio_proc_p proc );

/*
 * Asynchronous Operations:
 * - the asynchronous operation must be performed without using
 *   the applications thread!
 * - when an asynchronous operations completes (as compared to the
 *   reactor pattern, where the actual OS operation is still done
 *   by the application!), the asio_proc deletegates the notification
 *   of the appliation to the Completion Distpatcher
 */

wolf_error_t wolf_asio_proc_write(		wolf_asio_proc_p proc,
						char *buf,
						size_t buflen,
						wolf_asio_write_completion_handler_f completion_handler );

wolf_error_t wolf_asio_proc_read(		wolf_asio_proc_p proc,
						char *buf,
						size_t buflen,
						wolf_asio_read_completion_handler_f completion_handler );

wolf_error_t wolf_asio_proc_accept(		wolf_asio_proc_p proc,
						wolf_asio_accept_completion_handler_f completion_handler );

wolf_error_t wolf_asio_proc_connect(		wolf_asio_proc_p proc,
						wolf_asio_connect_completion_handler_f completion_handler );

/**
 * Acceptor
 * - decouples normal operation in active connections from new
 *   connections
 * - asks the async operation processor
 */
						
/* Asynchronous Completion Token:
 * - stores state information to complete the asynchronous request, partial
 *   reads/writes (filehandle, position)
 */

/* TODO: opening files and pipes should be immediate, what about connect/accept? */

/* Completion Dispatcher:
 * - on completion it has to call the registerd completion_handler
 * - dispatch concurrency strategy:
 *   - signal the completion as conditional/event to the rendevous point of the
 *     application thread
 *   - borrow the thread
 *   - pool of dedicated threads
 * - there is a notification queue which gets processed by the completion
 *   dispatcher
 */

typedef struct wolf_asio_completion_dispatcher_t {
	int dummy;
} wolf_asio_completion_dispatcher_t;

wolf_asio_completion_dispatcher_p wolf_asio_completion_dispatcher_new(		wolf_error_t *error );

wolf_error_t wolf_asio_completion_dispatcher_free(				wolf_asio_completion_dispatcher_p dispatcher );

wolf_error_t wolf_asio_completion_dispatcher_dispatch(				wolf_asio_completion_dispatcher_p dispatcher );

/* IMPLEMENTATION */

#include "port/stdlib.h"		/* for EXIT_XX, NULL, malloc, free */

wolf_asio_proc_p wolf_asio_proc_new(		wolf_asio_completion_dispatcher_p completion_dispatcher,
						wolf_error_t *error ) {
	wolf_asio_proc_p proc;

	proc = (wolf_asio_proc_p)malloc( sizeof( struct wolf_asio_proc_t ) );
	if( proc == NULL ) {
		*error = WOLF_ERR_OUT_OF_MEMORY;
		return NULL;
	}

	proc->completion_dispatcher = completion_dispatcher;
	return proc;
}

wolf_error_t wolf_asio_proc_free(		wolf_asio_proc_p proc ) {
	if( proc == NULL ) {
		return WOLF_ERR_INVALID_STATE;
	}

	free( proc );
	proc = NULL;

	return WOLF_OK;
}

wolf_error_t wolf_asio_proc_accept(		wolf_asio_proc_p proc,
						wolf_asio_accept_completion_handler_f completion_handler ) {
	WOLF_UNUSED( proc );
	WOLF_UNUSED( completion_handler );

	/* start an aynchronous accept */
	/* call completion_handler in the contect of the completion_dispatcher on completion */

	return WOLF_OK;
}

wolf_error_t wolf_asio_proc_event_loop(		wolf_asio_proc_p proc ) {
	WOLF_UNUSED( proc );
	return WOLF_OK;
}

wolf_asio_completion_dispatcher_p wolf_asio_completion_dispatcher_new(		wolf_error_t *error ) {
	wolf_asio_completion_dispatcher_p dispatcher;

	dispatcher = (wolf_asio_completion_dispatcher_p)malloc( sizeof( struct wolf_asio_completion_dispatcher_t ) );
	if( dispatcher == NULL ) {
		*error = WOLF_ERR_OUT_OF_MEMORY;
		return NULL;
	}

	return dispatcher;
}

wolf_error_t wolf_asio_completion_dispatcher_free(				wolf_asio_completion_dispatcher_p dispatcher ) {
	if( dispatcher == NULL ) {
		return WOLF_ERR_INVALID_STATE;
	}

	free( dispatcher );
	dispatcher = NULL;

	return WOLF_OK;
}

/* completion handlers */

static void accept_handler( void ) {
}

/* MAIN, the proactive initiator
 * 
 */

int main( void ) {
	wolf_asio_proc_p proc;
	wolf_asio_completion_dispatcher_p dispatcher;
	wolf_error_t error;

	dispatcher = wolf_asio_completion_dispatcher_new( &error );
	if( dispatcher == NULL ) {
		return EXIT_FAILURE;
	}

	proc = wolf_asio_proc_new( dispatcher, &error );
	if( proc == NULL ) {
		(void)wolf_asio_completion_dispatcher_free( dispatcher );
		return EXIT_FAILURE;
	}

	error = wolf_asio_proc_accept( proc, accept_handler );
	if( error != WOLF_OK ) {
		(void)wolf_asio_completion_dispatcher_free( dispatcher );
		(void)wolf_asio_proc_free( proc );
		return EXIT_FAILURE;
	}

	/* loop and wait for clients connecting */
	while( 1 ) {
		error = wolf_asio_proc_event_loop( proc );
		if( error != WOLF_OK ) {
			(void)wolf_asio_completion_dispatcher_free( dispatcher );
			(void)wolf_asio_proc_free( proc );
			return EXIT_FAILURE;
		}
	}

	if( wolf_asio_proc_free( proc ) != WOLF_OK ) {
		return EXIT_FAILURE;
	}
	if( wolf_asio_completion_dispatcher_free( dispatcher ) != WOLF_OK ) {
		return EXIT_FAILURE;
	}

	return EXIT_SUCCESS;
}