Nilorea Library
C utilities for networking, threading, graphics
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, " -v version\n"
27 " -V log level: LOG_INFO, LOG_NOTICE, LOG_ERR, LOG_DEBUG\n"
28 " -h help\n"
29 " -a serveur address name/ip to bind (server mode) (optionnal)\n"
30 " -s serveur address name/ip to connect (client mode)\n"
31 " -p port\n"
32 " -i [v4,v6] ip version (default support both ipv4 and ipv6 )\n" );
33}
34
35void process_args( int argc, char **argv, char **address, char **server, char **port, int *nb, int *ip_version )
36{
37 int getoptret = 0,
38 log_level = LOG_ERR; /* default log level */
39
40 /* Arguments optionnels */
41 /* -v version
42 * -V log level
43 * -h help
44 * -a address name/ip to bind to (server mode, NULL if not specified)
45 * -s serveur address name/ip to connect (client mode)
46 * -p port
47 * -i v4 ip version (default support both ipv4 and ipv6 )
48 * -i v6 ip version ( " " " " " " )
49 */
50 if( argc == 1 )
51 {
52 fprintf( stderr, "No arguments given, help:\n" );
53 usage();
54 exit( 1 );
55 }
56 while( ( getoptret = getopt( argc, argv, "hvs:V:p:n:i:a:" ) ) != EOF)
57 {
58 switch( getoptret )
59 {
60 case 'i' :
61 if( !strcmp( "v4", optarg ) )
62 {
63 (*ip_version) = NETWORK_IPV4 ;
64 n_log( LOG_NOTICE, "IPV4 selected" );
65 }
66 else if( !strcmp( "v6", optarg ) )
67 {
68 (*ip_version) = NETWORK_IPV6 ;
69 n_log( LOG_NOTICE, "IPV6 selected" );
70 }
71 else
72 {
73 n_log( LOG_NOTICE, "IPV4/6 selected" );
74 }
75 break;
76 case 'v' :
77 fprintf( stderr, "Date de compilation : %s a %s.\n", __DATE__, __TIME__ );
78 exit( 1 );
79 case 'V' :
80 if( !strncmp( "LOG_NULL", optarg, 8 ) )
81 {
82 log_level = LOG_NULL ;
83 }
84 else
85 {
86 if( !strncmp( "LOG_NOTICE", optarg, 10 ) )
87 {
88 log_level = LOG_NOTICE;
89 }
90 else
91 {
92 if( !strncmp( "LOG_INFO", optarg, 8 ) )
93 {
94 log_level = LOG_INFO;
95 }
96 else
97 {
98 if( !strncmp( "LOG_ERR", optarg, 7 ) )
99 {
100 log_level = LOG_ERR;
101 }
102 else
103 {
104 if( !strncmp( "LOG_DEBUG", optarg, 9 ) )
105 {
106 log_level = LOG_DEBUG;
107 }
108 else
109 {
110 fprintf( stderr, "%s n'est pas un niveau de log valide.\n", optarg );
111 exit( -1 );
112 }
113 }
114 }
115 }
116 }
117 break;
118 case 's' :
119 (*server) = strdup( optarg );
120 break ;
121 case 'a' :
122 (*address) = strdup( optarg );
123 break ;
124 case 'n' :
125 (*nb) = atoi( optarg );
126 break ;
127 case 'p' :
128 (*port) = strdup( optarg );
129 break ;
130 default :
131 case '?' :
132 {
133 if( optopt == 'V' )
134 {
135 fprintf( stderr, "\n Missing log level\n" );
136 }
137 else if( optopt == 'p' )
138 {
139 fprintf( stderr, "\n Missing port\n" );
140 }
141 else if( optopt != 's' )
142 {
143 fprintf( stderr, "\n Unknow missing option %c\n", optopt );
144 }
145 usage();
146 exit( 1 );
147 }
148
149 case 'h' :
150 {
151 usage();
152 exit( 1 );
153 }
154 }
155 }
156 set_log_level( log_level );
157} /* void process_args( ... ) */
158
159
160
161
162int main(int argc, char **argv)
163{
164
165 char *addr = NULL ;
166 char *srv = NULL ;
167 char *port = NULL ;
168
170
171 /* processing args and set log_level */
172 process_args( argc, argv, &addr, &srv, &port,&NB_ATTEMPTS, &ip_version );
173
174 if( !port )
175 {
176 n_log( LOG_ERR, "No port given. Exiting." );
177 exit( -1 );
178 }
179
180 if( srv && addr )
181 {
182 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)" );
183 }
184
185 if( srv )
186 {
187 n_log( LOG_INFO, "Client mode, connecting to %s:%s", srv, port );
188 mode = CLIENT ;
189 }
190 else
191 {
192 n_log( LOG_INFO, "Server mode , waiting client on port %s", port );
193 mode = SERVER ;
194 }
195
196#ifdef __linux__
197 struct sigaction sa;
198 sa.sa_handler = sigchld_handler; // reap all dead processes
199 sigemptyset(&sa.sa_mask);
200 sa.sa_flags = SA_RESTART;
201 if (sigaction(SIGCHLD, &sa, NULL) == -1)
202 {
203 perror("sigaction");
204 exit(1);
205 }
206#endif
207 if( mode == SERVER )
208 {
209 n_log( LOG_INFO, "Creating listening network for %s:%s %d", _str( addr ), _str( port ), ip_version );
210 /* create listening network */
211 if( netw_make_listening( &server, addr, port, 10, ip_version ) == FALSE )
212 {
213 n_log( LOG_ERR, "Fatal error with network initialization" );
214 netw_unload();
215 exit( -1 );
216 }
217 int it = 0 ;
218 for( it = 0 ; it < NB_ATTEMPTS/2 ; it ++ )
219 {
220
221 n_log( LOG_INFO, "Blocking on accept..." );
222 /* get any accepted client on a network */
223 if ( !( netw = netw_accept_from( server ) ) )
224 {
225 n_log( LOG_ERR, "Error on accept" );
226 }
227 else
228 {
229 /* someone is connected. starting some dialog */
230 int error = 0 ;
231 int pthread_error = 0 ;
232 errno = 0 ;
233 pthread_error = pthread_create ( &netw_thr, NULL, &manage_client, (void *)netw );
234 error = errno ;
235 if( pthread_error != 0 )
236 {
237 n_log( LOG_ERR, "Error creating client management pthread:%d , error: %s", pthread_error, strerror( error ) );
238 netw_unload();
239 exit( -1 );
240 }
241 pthread_join( netw_thr, NULL );
242 }
243 }
244 /* testing with thread pool && non blocking */
245 int error = 0 ;
246 THREAD_POOL *thread_pool = new_thread_pool( 2, 128 );
247 while( it < NB_ATTEMPTS )
248 {
249 /* get any accepted client on a network */
250 if ( ( netw = netw_accept_from_ex( server, 0, 0, 0, &error ) ) )
251 {
252 /* someone is connected. starting some dialog */
253 if( add_threaded_process( thread_pool, &manage_client, (void *)netw, DIRECT_PROC ) == FALSE )
254 {
255 n_log( LOG_ERR, "Error ading client management to thread pool" );
256 }
257 it ++ ;
258 }
259 else
260 {
261 n_log( LOG_DEBUG, "Waiting connections..." );
262 u_sleep( 250000 );
263 }
264 refresh_thread_pool( thread_pool );
265 }
266 n_log( LOG_NOTICE, "Waiting thread_pool..." );
267 wait_for_threaded_pool( thread_pool, 500000 );
268 n_log( LOG_NOTICE, "Destroying thread_pool..." );
269 destroy_threaded_pool( &thread_pool, 500000 );
270 n_log( LOG_NOTICE, "Close waiting server" );
271 netw_close( &server );
272 }
273 else if( mode == CLIENT )
274 {
275 for( int it = 1 ; it <= NB_ATTEMPTS ; it ++ )
276 {
277 if( netw_connect( &netw, srv, port, ip_version ) != TRUE )
278 {
279 /* there were some error when trying to connect */
280 n_log( LOG_ERR, "Unable to connect to %s:%s", srv, port );
281 netw_unload();
282 exit( 1 );
283 }
284 n_log( LOG_NOTICE, "Attempt %d: Connected to %s:%s", it, srv, port );
285
286 /* backgrounding network send / recv */
287 netw_start_thr_engine( netw );
288
289 N_STR *sended_data = NULL, *recved_data = NULL, *hostname = NULL, *tmpstr = NULL ;
290
291 sended_data = char_to_nstr( "SENDING DATAS..." );
292 send_net_datas( netw, sended_data );
293
294 free_nstr( &sended_data );
295
296 /* let's check for an answer: test each 250000 usec, with
297 * a limit of 1000000 usec */
298 n_log( LOG_INFO, "waiting for datas back from server..." );
299 tmpstr = netw_wait_msg( netw, 25000, 10000000 );
300
301 if( tmpstr )
302 {
303 get_net_datas( tmpstr, &hostname, &recved_data );
304 n_log( LOG_NOTICE, "RECEIVED DATAS: %s - %s", recved_data ->data, hostname ->data );
305 free_nstr( &tmpstr );
306 free_nstr( &recved_data );
307 free_nstr( &hostname );
308 }
309 else
310 {
311 n_log( LOG_ERR, "Error getting back answer from server" );
312 }
313 n_log( LOG_NOTICE, "Closing client in 5 seconds. See synchronisation on server side..." );
314 netw_close( &netw );
315 }
316 }
317
318 FreeNoLog( srv );
319 FreeNoLog( addr );
320 FreeNoLog( port )
321
322 netw_unload();
323
324 n_log( LOG_INFO, "Exiting network example" );
325
326 exit( 0 );
327} /* 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:139
int get_net_datas(N_STR *str, N_STR **hostname, N_STR **data)
decode data we got from network
Definition: ex_network.h:98
int send_net_datas(NETWORK *netw, N_STR *data)
send data to specified network
Definition: ex_network.h:45
#define FreeNoLog(__ptr)
Free Handler without log.
Definition: n_common.h:268
#define _str(__PTR)
define true
Definition: n_common.h:172
#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:2068
#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:1665
int netw_start_thr_engine(NETWORK *netw)
Start the NETWORK netw Threaded Engine.
Definition: n_network.c:2125
#define NETWORK_IPV4
Flag to force IPV4
Definition: n_network.h:29
NETWORK * netw_accept_from_ex(NETWORK *from, int send_list_limit, int recv_list_limit, int non_blocking, int *retval)
make a normal 'accept' .
Definition: n_network.c:1791
#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:1940
int netw_close(NETWORK **netw)
Closing a specified Network, destroy queues, free the structure.
Definition: n_network.c:1480
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:1361
Structure of a NETWORK.
Definition: n_network.h:252
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
Definition: n_thread_pool.h:29
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.
Definition: n_thread_pool.h:81