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