Nilorea Library
C utilities for networking, threading, graphics
Loading...
Searching...
No Matches
ex_network.c
1
7#include <stdio.h>
8#include <errno.h>
9
10#include "ex_network.h"
11
12#define SERVER 0
13#define CLIENT 1
14
15int NB_ATTEMPTS= 3 ;
16
17NETWORK *server = NULL,
18 *netw = NULL ;
20int mode = -1, ip_version = NETWORK_IPALL ;
21
22static pthread_t netw_thr ;
23
24void usage(void)
25{
26 fprintf( stderr,
27 " -a 'serveur address name/ip to bind (server mode) (optionnal)\n"
28 " -s 'serveur address name/ip to connect (client mode)\n"
29 " -p 'port': TCP port to use, server or client\n"
30 " -c 'SSL certificate file': optional, certificale file to enable SSL encryption\n"
31 " -k 'SSL key file': optional, key file to enable SSL encrpytion\n"
32 " -i 'ipmode': optional, ip version to use. Default support both ipv4 and ipv6. Values: ipv4, ipv6\n"
33 " -h: show that help file\n"
34 " -v: show the program version\n"
35 " -V 'log level': optional, set the log level. Default: LOG_ERR, values: LOG_INFO, LOG_NOTICE, LOG_ERR, LOG_DEBUG\n" );
36}
37
38void process_args( int argc, char **argv, char **address, char **server, char **port, int *nb, int *ip_version , char **ssl_key_file , char **ssl_cert_file )
39{
40 int getoptret = 0,
41 log_level = LOG_ERR; /* default log level */
42
43 /* Arguments optionnels */
44 /* -v version
45 * -V log level
46 * -h help
47 * -a address name/ip to bind to (server mode, NULL if not specified)
48 * -s serveur address name/ip to connect (client mode)
49 * -p port
50 * -i v4 ip version (default support both ipv4 and ipv6 )
51 * -i v6 ip version ( " " " " " " )
52 */
53 if( argc == 1 )
54 {
55 fprintf( stderr, "No arguments given, help:\n" );
56 usage();
57 exit( 1 );
58 }
59 while( ( getoptret = getopt( argc, argv, "hvs:V:p:n:i:a:c:k:" ) ) != EOF)
60 {
61 switch( getoptret )
62 {
63 case 'i' :
64 if( !strcmp( "v4", optarg ) )
65 {
66 (*ip_version) = NETWORK_IPV4 ;
67 n_log( LOG_NOTICE, "IPV4 selected" );
68 }
69 else if( !strcmp( "v6", optarg ) )
70 {
71 (*ip_version) = NETWORK_IPV6 ;
72 n_log( LOG_NOTICE, "IPV6 selected" );
73 }
74 else
75 {
76 n_log( LOG_NOTICE, "IPV4/6 selected" );
77 }
78 break;
79 case 'v' :
80 fprintf( stderr, "Date de compilation : %s a %s.\n", __DATE__, __TIME__ );
81 exit( 1 );
82 case 'V' :
83 if( !strncmp( "LOG_NULL", optarg, 8 ) )
84 {
85 log_level = LOG_NULL ;
86 }
87 else
88 {
89 if( !strncmp( "LOG_NOTICE", optarg, 10 ) )
90 {
91 log_level = LOG_NOTICE;
92 }
93 else
94 {
95 if( !strncmp( "LOG_INFO", optarg, 8 ) )
96 {
97 log_level = LOG_INFO;
98 }
99 else
100 {
101 if( !strncmp( "LOG_ERR", optarg, 7 ) )
102 {
103 log_level = LOG_ERR;
104 }
105 else
106 {
107 if( !strncmp( "LOG_DEBUG", optarg, 9 ) )
108 {
109 log_level = LOG_DEBUG;
110 }
111 else
112 {
113 fprintf( stderr, "%s n'est pas un niveau de log valide.\n", optarg );
114 exit( -1 );
115 }
116 }
117 }
118 }
119 }
120 break;
121 case 'k' :
122 (*ssl_key_file) = strdup( optarg );
123 break ;
124 case 'c' :
125 (*ssl_cert_file) = strdup( optarg );
126 break ;
127 case 's' :
128 (*server) = strdup( optarg );
129 break ;
130 case 'a' :
131 (*address) = strdup( optarg );
132 break ;
133 case 'n' :
134 (*nb) = atoi( optarg );
135 break ;
136 case 'p' :
137 (*port) = strdup( optarg );
138 break ;
139 default :
140 case '?' :
141 {
142 usage();
143 exit( 1 );
144 }
145 case 'h' :
146 {
147 usage();
148 exit( 1 );
149 }
150 }
151 }
152 set_log_level( log_level );
153} /* void process_args( ... ) */
154
155
156
157
158int main(int argc, char **argv)
159{
160
161 char *addr = NULL ;
162 char *srv = NULL ;
163 char *port = NULL ;
164 char *ssl_key_file = NULL ;
165 char *ssl_cert_file = NULL ;
166
168
169 /* processing args and set log_level */
170 process_args( argc, argv, &addr, &srv, &port,&NB_ATTEMPTS, &ip_version, &ssl_key_file, &ssl_cert_file );
171
172 if( !port )
173 {
174 n_log( LOG_ERR, "No port given. Exiting." );
175 exit( -1 );
176 }
177
178 if( srv && addr )
179 {
180 n_log( LOG_ERR, "Please specify only one of the following options: -a (server, addr to bind to) or -s (server on which to connect to)" );
181 }
182
183 if( srv )
184 {
185 n_log( LOG_INFO, "Client mode, connecting to %s:%s", srv, port );
186 mode = CLIENT ;
187 }
188 else
189 {
190 n_log( LOG_INFO, "Server mode , waiting client on port %s", port );
191 mode = SERVER ;
192 }
193
194#ifdef __linux__
195 if( sigchld_handler_installer() == FALSE )
196 {
197 exit( -1 );
198 }
199#endif
200 if( mode == SERVER )
201 {
202 n_log( LOG_INFO, "Creating listening network for %s:%s %d", _str( addr ), _str( port ), ip_version );
203 /* create listening network */
204 if( netw_make_listening( &server, addr, port, 10, ip_version ) == FALSE )
205 {
206 n_log( LOG_ERR, "Fatal error with network initialization" );
207 netw_unload();
208 exit( -1 );
209 }
210
211#ifdef HAVE_OPENSSL
212 if( ssl_key_file && ssl_cert_file )
213 {
214 netw_set_crypto( server , ssl_key_file , ssl_cert_file );
215 }
216#endif
217
218 int it = 0 ;
219 for( it = 0 ; it < NB_ATTEMPTS/2 ; it ++ )
220 {
221
222 n_log( LOG_INFO, "Blocking on accept..." );
223 /* get any accepted client on a network */
224 if ( !( netw = netw_accept_from( server ) ) )
225 {
226 n_log( LOG_ERR, "Error on accept" );
227 }
228 else
229 {
230 /* someone is connected. starting some dialog */
231 int error = 0 ;
232 int pthread_error = 0 ;
233 errno = 0 ;
234 pthread_error = pthread_create ( &netw_thr, NULL, &manage_client, (void *)netw );
235 error = errno ;
236 if( pthread_error != 0 )
237 {
238 n_log( LOG_ERR, "Error creating client management pthread:%d , error: %s", pthread_error, strerror( error ) );
239 netw_unload();
240 exit( -1 );
241 }
242 pthread_join( netw_thr, NULL );
243 }
244 }
245 /* testing with thread pool && non blocking */
246 int error = 0 ;
247 THREAD_POOL *thread_pool = new_thread_pool( 2, 128 );
248 while( it < NB_ATTEMPTS )
249 {
250 /* get any accepted client on a network */
251 if ( ( netw = netw_accept_from_ex( server, 0, 0, 0, &error ) ) )
252 {
253 /* someone is connected. starting some dialog */
254 if( add_threaded_process( thread_pool, &manage_client, (void *)netw, DIRECT_PROC ) == FALSE )
255 {
256 n_log( LOG_ERR, "Error ading client management to thread pool" );
257 }
258 it ++ ;
259 }
260 else
261 {
262 n_log( LOG_DEBUG, "Waiting connections..." );
263 u_sleep( 250000 );
264 }
265 refresh_thread_pool( thread_pool );
266 }
267 n_log( LOG_NOTICE, "Waiting thread_pool..." );
268 wait_for_threaded_pool( thread_pool, 500000 );
269 n_log( LOG_NOTICE, "Destroying thread_pool..." );
270 destroy_threaded_pool( &thread_pool, 500000 );
271 n_log( LOG_NOTICE, "Close waiting server" );
272 netw_close( &server );
273 }
274 else if( mode == CLIENT )
275 {
276 for( int it = 1 ; it <= NB_ATTEMPTS ; it ++ )
277 {
278 if( ssl_key_file && ssl_cert_file )
279 {
280#ifdef HAVE_OPENSSL
281 if( netw_ssl_connect( &netw, srv, port, ip_version, ssl_key_file, ssl_cert_file ) != TRUE )
282 {
283 /* there were some error when trying to connect */
284 n_log( LOG_ERR, "Unable to connect to %s:%s", srv, port );
285 netw_unload();
286 exit( 1 );
287 }
288 else
289 {
290 n_log( LOG_NOTICE, "SSL Attempt %d: Connected to %s:%s", it, srv, port );
291 }
292#else
293 n_log( LOG_ERR , "trying to use SSL with %s:%s, but program was compiled without OpenSSL support !!!");
294 n_log( LOG_ERR , "ENCRYPTION IS DISABLED !!!" );
295 n_log( LOG_ERR , "EXITING !!!" );
296 netw_unload();
297 exit( 1 );
298#endif
299 }
300 else
301 {
302 if( netw_connect( &netw, srv, port, ip_version ) != TRUE )
303 {
304 /* there were some error when trying to connect */
305 n_log( LOG_ERR, "Unable to connect to %s:%s", srv, port );
306 netw_unload();
307 exit( 1 );
308 }
309 n_log( LOG_NOTICE, "Attempt %d: Connected to %s:%s", it, srv, port );
310 }
311
312 /* backgrounding network send / recv */
313 netw_start_thr_engine( netw );
314
315 N_STR *sended_data = NULL, *recved_data = NULL, *hostname = NULL, *tmpstr = NULL ;
316
317 sended_data = char_to_nstr( "SENDING DATAS..." );
318 send_net_datas( netw, sended_data );
319
320 free_nstr( &sended_data );
321
322 /* let's check for an answer: test each 250000 usec, with
323 * a limit of 1000000 usec */
324 n_log( LOG_INFO, "waiting for datas back from server..." );
325 tmpstr = netw_wait_msg( netw, 25000, 10000000 );
326
327 if( tmpstr )
328 {
329 get_net_datas( tmpstr, &hostname, &recved_data );
330 n_log( LOG_NOTICE, "RECEIVED DATAS: %s - %s", recved_data ->data, hostname ->data );
331 free_nstr( &tmpstr );
332 free_nstr( &recved_data );
333 free_nstr( &hostname );
334 }
335 else
336 {
337 n_log( LOG_ERR, "Error getting back answer from server" );
338 }
339 n_log( LOG_NOTICE, "Closing client in 5 seconds. See synchronisation on server side..." );
340 netw_close( &netw );
341 }
342 }
343
344 FreeNoLog( srv );
345 FreeNoLog( addr );
346 FreeNoLog( port )
347
348 netw_unload();
349
350 n_log( LOG_INFO, "Exiting network example" );
351
352 exit( 0 );
353} /* END_OF_MAIN() */
Nilorea Library n_network api test.
void * manage_client(void *ptr)
recv/send datas if any for the client
Definition ex_network.h:125
int get_net_datas(N_STR *str, N_STR **hostname, N_STR **data)
decode data we got from network
Definition ex_network.h:84
int send_net_datas(NETWORK *netw, N_STR *data)
send data to specified network
Definition ex_network.h:31
#define FreeNoLog(__ptr)
Free Handler without log.
Definition n_common.h:276
#define _str(__PTR)
define true
Definition n_common.h:180
int sigchld_handler_installer()
install signal SIGCHLD handler to reap zombie processes
Definition n_common.c:253
#define n_log(__LEVEL__,...)
Logging function wrapper to get line and func.
Definition n_log.h:74
#define LOG_DEBUG
debug-level messages
Definition n_log.h:66
#define LOG_ERR
error conditions
Definition n_log.h:58
void set_log_level(const int log_level)
Set the global log level value ( static int LOG_LEVEL )
Definition n_log.c:97
#define LOG_NOTICE
normal but significant condition
Definition n_log.h:62
#define LOG_NULL
no log output
Definition n_log.h:27
#define LOG_INFO
informational
Definition n_log.h:64
#define free_nstr(__ptr)
free a N_STR structure and set the pointer to NULL
Definition n_str.h:222
N_STR * char_to_nstr(const char *src)
Convert a char into a N_STR, short version.
Definition n_str.c:273
A box including a string and his lenght.
Definition n_str.h:173
void u_sleep(unsigned int usec)
wrapper around usleep for API consistency
Definition n_time.c:38
N_STR * netw_wait_msg(NETWORK *netw, size_t refresh, size_t timeout)
Wait a message from aimed NETWORK.
Definition n_network.c:2221
NETWORK * netw_accept_from_ex(NETWORK *from, int send_list_limit, int recv_list_limit, int blocking, int *retval)
make a normal 'accept' .
Definition n_network.c:1923
#define NETWORK_IPV6
Flag to force IPV6
Definition n_network.h:31
int netw_make_listening(NETWORK **netw, char *addr, char *port, int nbpending, int ip_version)
Make a NETWORK be a Listening network.
Definition n_network.c:1797
int netw_start_thr_engine(NETWORK *netw)
Start the NETWORK netw Threaded Engine.
Definition n_network.c:2278
#define NETWORK_IPV4
Flag to force IPV4
Definition n_network.h:29
#define NETWORK_IPALL
Flag for auto detection by OS of ip version to use.
Definition n_network.h:27
NETWORK * netw_accept_from(NETWORK *from)
make a normal blocking 'accept' .
Definition n_network.c:2093
int netw_close(NETWORK **netw)
Closing a specified Network, destroy queues, free the structure.
Definition n_network.c:1588
int netw_connect(NETWORK **netw, char *host, char *port, int ip_version)
Use this to connect a NETWORK to any listening one, unrestricted send/recv lists.
Definition n_network.c:1449
Structure of a NETWORK.
Definition n_network.h:233
int destroy_threaded_pool(THREAD_POOL **pool, int delay)
delete a thread_pool, exit the threads and free the structs
int add_threaded_process(THREAD_POOL *thread_pool, void *(*func_ptr)(void *param), void *param, int mode)
add a function and params to a thread pool
int refresh_thread_pool(THREAD_POOL *thread_pool)
try to add some waiting DIRECT_PROCs on some free thread slots, else do nothing
#define DIRECT_PROC
processing mode for added func, direct start
int wait_for_threaded_pool(THREAD_POOL *thread_pool, int delay)
Wait for all the launched process in the thread pool to terminate.
THREAD_POOL * new_thread_pool(int nbmaxthr, int nb_max_waiting)
Create a new pool of nbmaxthr threads.
Structure of a trhead pool.