Nilorea Library
C utilities for networking, threading, graphics
Loading...
Searching...
No Matches
ex_network.c
Go to the documentation of this file.
1
9#include <stdio.h>
10#include <errno.h>
11
12#include "ex_network.h"
13
14#define SERVER 0
15#define CLIENT 1
16
18
20 *netw = NULL;
23
24static pthread_t netw_thr;
25
26void usage(void) {
27 fprintf(stderr,
28 " -a 'serveur address name/ip to bind (server mode) (optionnal)\n"
29 " -s 'serveur address name/ip to connect (client mode)\n"
30 " -p 'port': TCP port to use, server or client\n"
31 " -c 'SSL certificate file': optional, certificale file to enable SSL encryption\n"
32 " -k 'SSL key file': optional, key file to enable SSL encrpytion\n"
33 " -i 'ipmode': optional, ip version to use. Default support both ipv4 and ipv6. Values: ipv4, ipv6\n"
34 " -h: show that help file\n"
35 " -v: show the program version\n"
36 " -V 'log level': optional, set the log level. Default: LOG_ERR, values: LOG_INFO, LOG_NOTICE, LOG_ERR, LOG_DEBUG\n");
37}
38
39void 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) {
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 fprintf(stderr, "No arguments given, help:\n");
55 usage();
56 exit(1);
57 }
58 while ((getoptret = getopt(argc, argv, "hvs:V:p:n:i:a:c:k:")) != EOF) {
59 switch (getoptret) {
60 case 'i':
61 if (!strcmp("v4", optarg)) {
62 (*ip_version) = NETWORK_IPV4;
63 n_log(LOG_NOTICE, "IPV4 selected");
64 } else if (!strcmp("v6", optarg)) {
65 (*ip_version) = NETWORK_IPV6;
66 n_log(LOG_NOTICE, "IPV6 selected");
67 } else {
68 n_log(LOG_NOTICE, "IPV4/6 selected");
69 }
70 break;
71 case 'v':
72 fprintf(stderr, "Date de compilation : %s a %s.\n", __DATE__, __TIME__);
73 exit(1);
74 case 'V':
75 if (!strncmp("LOG_NULL", optarg, 8)) {
77 } else {
78 if (!strncmp("LOG_NOTICE", optarg, 10)) {
80 } else {
81 if (!strncmp("LOG_INFO", optarg, 8)) {
83 } else {
84 if (!strncmp("LOG_ERR", optarg, 7)) {
86 } else {
87 if (!strncmp("LOG_DEBUG", optarg, 9)) {
89 } else {
90 fprintf(stderr, "%s n'est pas un niveau de log valide.\n", optarg);
91 exit(-1);
92 }
93 }
94 }
95 }
96 }
97 break;
98 case 'k':
99 (*ssl_key_file) = strdup(optarg);
100 break;
101 case 'c':
102 (*ssl_cert_file) = strdup(optarg);
103 break;
104 case 's':
105 (*server) = strdup(optarg);
106 break;
107 case 'a':
108 (*address) = strdup(optarg);
109 break;
110 case 'n':
111 (*nb) = atoi(optarg);
112 break;
113 case 'p':
114 (*port) = strdup(optarg);
115 break;
116 default:
117 case '?': {
118 usage();
119 exit(1);
120 }
121 case 'h': {
122 usage();
123 exit(1);
124 }
125 }
126 }
128} /* void process_args( ... ) */
129
130int main(int argc, char** argv) {
131 char* addr = NULL;
132 char* srv = NULL;
133 char* port = NULL;
134 char* ssl_key_file = NULL;
135 char* ssl_cert_file = NULL;
136
138
139 /* processing args and set log_level */
140 process_args(argc, argv, &addr, &srv, &port, &NB_ATTEMPTS, &ip_mode, &ssl_key_file, &ssl_cert_file);
141
142 if (!port) {
143 n_log(LOG_ERR, "No port given. Exiting.");
144 exit(-1);
145 }
146
147 if (srv && addr) {
148 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)");
149 }
150
151 if (srv) {
152 n_log(LOG_INFO, "Client mode, connecting to %s:%s", srv, port);
153 mode = CLIENT;
154 } else {
155 n_log(LOG_INFO, "Server mode , waiting client on port %s", port);
156 mode = SERVER;
157 }
158
159#ifdef __linux__
160 if (sigchld_handler_installer() == FALSE) {
161 exit(-1);
162 }
163#endif
164 if (mode == SERVER) {
165 n_log(LOG_INFO, "Creating listening network for %s:%s %d", _str(addr), _str(port), ip_mode);
166 /* create listening network */
167 if (netw_make_listening(&netw_server, addr, port, 10, ip_mode) == FALSE) {
168 n_log(LOG_ERR, "Fatal error with network initialization");
169 netw_unload();
170 exit(-1);
171 }
172
173#ifdef HAVE_OPENSSL
174 if (ssl_key_file && ssl_cert_file) {
175 netw_set_crypto(netw_server, ssl_key_file, ssl_cert_file);
176 }
177#endif
178
179 int it = 0;
180 for (it = 0; it < NB_ATTEMPTS / 2; it++) {
181 n_log(LOG_INFO, "Blocking on accept...");
182 /* get any accepted client on a network */
184 n_log(LOG_ERR, "Error on accept");
185 } else {
186 /* someone is connected. starting some dialog */
187 int error = 0;
188 int pthread_error = 0;
189 errno = 0;
190 pthread_error = pthread_create(&netw_thr, NULL, &manage_client, (void*)netw);
191 error = errno;
192 if (pthread_error != 0) {
193 n_log(LOG_ERR, "Error creating client management pthread:%d , error: %s", pthread_error, strerror(error));
194 netw_unload();
195 exit(-1);
196 }
197 pthread_join(netw_thr, NULL);
198 }
199 }
200 /* testing with thread pool && non blocking */
201 int error = 0;
203 while (it < NB_ATTEMPTS) {
204 /* get any accepted client on a network */
205 if ((netw = netw_accept_from_ex(netw_server, 0, 0, 0, &error))) {
206 /* someone is connected. starting some dialog */
208 n_log(LOG_ERR, "Error adding client management to thread pool");
209 }
210 it++;
211 } else {
212 n_log(LOG_DEBUG, "Waiting connections...");
213 u_sleep(250000);
214 }
216 }
217 n_log(LOG_NOTICE, "Waiting thread_pool...");
219 n_log(LOG_NOTICE, "Destroying thread_pool...");
221 n_log(LOG_NOTICE, "Wait client close ack to close server");
222 // setting a 30s wait close timeout to wait for last datas to be received by peer (optional)
225 } else if (mode == CLIENT) {
226 for (int it = 1; it <= NB_ATTEMPTS; it++) {
227 if (ssl_key_file && ssl_cert_file) {
228#ifdef HAVE_OPENSSL
229 if (netw_ssl_connect(&netw, srv, port, ip_mode, ssl_key_file, ssl_cert_file) != TRUE) {
230 /* there were some error when trying to connect */
231 n_log(LOG_ERR, "Unable to connect to %s:%s", srv, port);
232 netw_unload();
233 exit(1);
234 } else {
235 n_log(LOG_NOTICE, "SSL Attempt %d: Connected to %s:%s", it, srv, port);
236 }
237#else
238 n_log(LOG_ERR, "trying to use SSL with %s:%s, but program was compiled without OpenSSL support !!!");
239 n_log(LOG_ERR, "ENCRYPTION IS DISABLED !!!");
240 n_log(LOG_ERR, "EXITING !!!");
241 netw_unload();
242 exit(1);
243#endif
244 } else {
245 if (netw_connect(&netw, srv, port, ip_mode) != TRUE) {
246 /* there were some error when trying to connect */
247 n_log(LOG_ERR, "Unable to connect to %s:%s", srv, port);
248 netw_unload();
249 exit(1);
250 }
251 n_log(LOG_NOTICE, "Attempt %d: Connected to %s:%s", it, srv, port);
252 }
253
254 /* backgrounding network send / recv */
256
257 N_STR *sended_data = NULL, *recved_data = NULL, *hostname = NULL, *tmpstr = NULL;
258
259 sended_data = char_to_nstr("SENDING DATAS...");
260 send_net_datas(netw, sended_data);
261
262 free_nstr(&sended_data);
263
264 /* let's check for an answer: test each 250000 usec, with
265 * a limit of 1000000 usec */
266 n_log(LOG_INFO, "waiting for datas back from server...");
267 tmpstr = netw_wait_msg(netw, 25000, 10000000);
268
269 if (tmpstr) {
270 get_net_datas(tmpstr, &hostname, &recved_data);
271 n_log(LOG_NOTICE, "RECEIVED DATAS: %s - %s", recved_data->data, hostname->data);
272 free_nstr(&tmpstr);
273 free_nstr(&recved_data);
274 free_nstr(&hostname);
275 } else {
276 n_log(LOG_ERR, "Error getting back answer from server");
277 }
278 n_log(LOG_NOTICE, "Closing client in 3 seconds. See synchronisation on server side...");
279 sleep(3);
281 }
282 }
283
284 FreeNoLog(srv);
287
288 netw_unload();
289
290 n_log(LOG_INFO, "Exiting network example");
291
292 exit(0);
293} /* END_OF_MAIN() */
void usage(void)
Definition ex_common.c:22
void process_args(int argc, char **argv)
Definition ex_common.c:29
int main(void)
THREAD_POOL * thread_pool
Definition ex_fluid.c:59
int getoptret
Definition ex_fluid.c:42
int log_level
Definition ex_fluid.c:43
NETWORK * netw_server
Definition ex_network.c:19
int mode
Network for managing conenctions.
Definition ex_network.c:22
#define SERVER
Definition ex_network.c:14
static pthread_t netw_thr
Definition ex_network.c:24
int NB_ATTEMPTS
Definition ex_network.c:17
NETWORK * netw
Network for server mode, accepting incomming.
Definition ex_network.c:20
int ip_mode
Definition ex_network.c:22
#define CLIENT
Definition ex_network.c:15
void * manage_client(void *ptr)
recv/send datas if any for the client
Definition ex_network.h:116
int get_net_datas(N_STR *str, N_STR **hostname, N_STR **data)
decode data we got from network
Definition ex_network.h:81
int send_net_datas(NETWORK *netw, N_STR *data)
send data to specified network
Definition ex_network.h:32
NETWORK * server
int ip_version
char * addr
char * port
#define FreeNoLog(__ptr)
Free Handler without log.
Definition n_common.h:249
#define _str(__PTR)
define true
Definition n_common.h:174
int sigchld_handler_installer()
install signal SIGCHLD handler to reap zombie processes
Definition n_common.c:227
#define n_log(__LEVEL__,...)
Logging function wrapper to get line and func.
Definition n_log.h:70
#define LOG_DEBUG
debug-level messages
Definition n_log.h:65
#define LOG_ERR
error conditions
Definition n_log.h:57
void set_log_level(const int log_level)
Set the global log level value ( static int LOG_LEVEL )
Definition n_log.c:104
#define LOG_NOTICE
normal but significant condition
Definition n_log.h:61
#define LOG_NULL
no log output
Definition n_log.h:27
#define LOG_INFO
informational
Definition n_log.h:63
#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: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:1644
int netw_start_thr_engine(NETWORK *netw)
Start the NETWORK netw Threaded Engine.
Definition n_network.c:2069
#define NETWORK_IPV4
Flag to force IPV4
Definition n_network.h:29
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:27
#define NETWORK_WAIT_CLOSE_TIMEOUT
Flag to set network closing wait timeout.
Definition n_network.h:39
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:1910
int netw_close(NETWORK **netw)
Closing a specified Network, destroy queues, free the structure.
Definition n_network.c:1503
N_STR * netw_wait_msg(NETWORK *netw, unsigned int refresh, size_t timeout)
Wait a message from aimed NETWORK.
Definition n_network.c:2018
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:239
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, not queued
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.