added verse library (release r6) to extern directory
[blender.git] / extern / verse / dist / v_connection.c
1 /*
2 **
3 */
4
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <string.h>
8
9 #include "v_cmd_buf.h"
10 #include "v_network_in_que.h"
11 #include "v_network_out_que.h"
12 #include "v_cmd_gen.h"
13 #include "v_connection.h"
14 #include "v_encryption.h"
15 #include "v_util.h"
16
17 #if !defined(V_GENERATE_FUNC_MODE)
18 #include "verse.h"
19
20 #define CONNECTION_CHUNK_SIZE   16
21 #define V_MAX_CONNECT_PACKET_SIZE       1500
22 #define V_CON_MAX_MICROSECOND_BETWEEN_SENDS     100
23 #define V_RE_CONNECTON_TIME_OUT 4
24 #define V_CONNECTON_TIME_OUT 30
25
26 typedef struct {
27         VNetOutQueue    *out_queue;
28         VNetInQueue             in_queue;
29         VNetworkAddress network_address;
30         boolean                 connected;
31         unsigned int    avatar;
32 /*      unsigned int    packet_id;*/
33         int32                   timedelta_s;
34         uint32                  timedelta_f;
35         boolean                 destroy_flag;
36         void                    *ordered_storage;
37         char                    name[V_ENCRYPTION_LOGIN_KEY_SIZE / 2];
38         char                    pass[V_ENCRYPTION_LOGIN_KEY_SIZE / 2];
39         VConnectStage   connect_stage;
40         unsigned int    stage_atempts;
41         uint8                   key_my[V_ENCRYPTION_LOGIN_KEY_FULL_SIZE];
42         uint8                   key_other[V_ENCRYPTION_LOGIN_KEY_FULL_SIZE];
43         uint8                   key_data[V_ENCRYPTION_DATA_KEY_SIZE];
44         uint8                   *expected_key;
45 } VConnection;
46
47 static struct {
48         VConnection             *con;
49         unsigned int    con_count;
50         unsigned int    current_connection;
51         VNetworkAddress *connect_address;
52         void                    *unified_func_storage;
53         uint16                  connect_port;
54         unsigned int    pending_packets;
55         uint8                   host_id[V_ENCRYPTION_LOGIN_KEY_FULL_SIZE];
56 } VConData;
57
58 extern void cmd_buf_init(void);
59
60 void v_con_init(void) /* since verse doesnt have an init function this function is runned over an ove ard starts whit a check it it has run before */
61 {
62         static boolean v_con_initialized = FALSE;
63
64         if(v_con_initialized)
65                 return;
66         cmd_buf_init();
67         v_con_initialized = TRUE;
68         VConData.con = malloc(CONNECTION_CHUNK_SIZE * sizeof *VConData.con);
69         memset(VConData.con, 0, CONNECTION_CHUNK_SIZE * sizeof *VConData.con);  /* Clear the memory. */
70         VConData.con_count = 0;
71         VConData.pending_packets = 0;
72 /*      v_e_connect_create_key(&VConData.host_id[V_ENCRYPTION_LOGIN_PRIVATE_START],
73                        &VConData.host_id[V_ENCRYPTION_LOGIN_PUBLIC_START],
74                        &VConData.host_id[V_ENCRYPTION_LOGIN_N_START]);*/ /* default host id if none is set by user */
75 }
76
77 void verse_set_port(uint16 port)
78 {
79         v_n_set_port(port);
80 }
81
82 void verse_host_id_create(uint8 *id)
83 {
84         v_e_connect_create_key(&id[V_ENCRYPTION_LOGIN_PRIVATE_START],
85                                &id[V_ENCRYPTION_LOGIN_PUBLIC_START], &id[V_ENCRYPTION_LOGIN_N_START]);
86 }
87
88 void verse_host_id_set(uint8 *id)
89 {
90         memcpy(VConData.host_id, id, V_ENCRYPTION_LOGIN_KEY_FULL_SIZE);
91 }
92
93 extern void *v_fs_create_func_storage(void);
94 extern void *v_create_ordered_storage(void);
95 extern void v_destroy_ordered_storage(void *data);
96
97 void *v_con_connect(uint32 ip, uint16 port, VConnectStage stage) /* creates a new connection slot */
98 {
99         v_con_init(); /* init connections, if not done yet */
100         if((VConData.con_count - 1) % CONNECTION_CHUNK_SIZE == 0) /* do we need more slots for connections, then reallocate more space */
101                 VConData.con = realloc(VConData.con, (sizeof *VConData.con) * (VConData.con_count + CONNECTION_CHUNK_SIZE));
102         VConData.con[VConData.con_count].out_queue = v_noq_create_network_queue(); /* create a out queue fo all out going commands */
103         v_niq_clear(&VConData.con[VConData.con_count].in_queue); /* clear and init the que of incomming packets.*/
104         VConData.con[VConData.con_count].connected = FALSE; /* not yet propperly connected and should not accept commands yet */
105         VConData.con[VConData.con_count].network_address.ip = ip; /* ip address of other side */
106         VConData.con[VConData.con_count].network_address.port = port; /* port used by other side */
107         VConData.con[VConData.con_count].avatar = 0; /* no avatar set yet*/
108 /*      VConData.con[VConData.con_count].packet_id = 2;*/
109         VConData.con[VConData.con_count].destroy_flag = FALSE; /* this is a flag that is set once the connection is about to be destroyed.*/
110         VConData.con[VConData.con_count].ordered_storage = v_create_ordered_storage();
111         VConData.con[VConData.con_count].name[0] = 0; /* nouser name set yet */
112         VConData.con[VConData.con_count].pass[0] = 0; /* no password set yet */
113         VConData.con[VConData.con_count].connect_stage = stage; /* this is the stage of the connection, it show if the connection is ready, the init state depends if this is a client or host */
114         VConData.con[VConData.con_count].stage_atempts = 0; /* each stage in the connection prosess is atempted multiple times to avoid failiure if packets get lost*/
115         VConData.con[VConData.con_count].timedelta_s = 0; /* number of seconds since last incomming packet to the connection*/
116         VConData.con[VConData.con_count].timedelta_f = 0; /* number of fractions of a second since last incomming packet to the connection*/
117         VConData.con[VConData.con_count].expected_key = NULL; /* expected hist id if this is a client */
118         VConData.current_connection = VConData.con_count; /* set the new connection to the current*/
119         ++VConData.con_count; /* add one to the number of connections*/
120         return VConData.con[VConData.current_connection].out_queue;
121 }
122
123 void verse_session_destroy(VSession session) /* a session can not be destroyed right away, because this function might be called inside a call back from the session it tryes tpo destroy, therfor it only markes it*/
124 {
125         unsigned int i;
126         for(i = 0; i < VConData.con_count && VConData.con[i].out_queue != session; i++);
127         if(i < VConData.con_count)
128         {
129                 VConData.con[i].destroy_flag = TRUE;
130         }
131 }
132
133 void verse_session_set(VSession session) /* find a session and make it the current*/
134 {
135         unsigned int i;
136         for(i = 0; i < VConData.con_count && session != VConData.con[i].out_queue; i++);
137         if(i < VConData.con_count)
138                 VConData.current_connection = i;
139 }
140
141 VSession verse_session_get(void)
142 {
143         if(VConData.current_connection < VConData.con_count)
144                 return VConData.con[VConData.current_connection].out_queue;
145         return NULL;
146 }
147
148 uint32 v_co_find_connection(uint32 ip, uint16 port) /* if a packet comes form a ip address what connection does it belong to? */
149 {
150         unsigned int i;
151
152         for(i = 0; i < VConData.con_count; i++)
153         {
154                 if(ip == VConData.con[i].network_address.ip &&
155                    port == VConData.con[i].network_address.port &&
156                    VConData.con[i].destroy_flag == 0)
157                 {
158                         return i;
159                 }
160         }
161         return -1;
162 }
163
164 boolean v_co_switch_connection(uint32 ip, uint16 port) /* switches to the current connection to one ip address if it exists */
165 {
166         unsigned int i;
167         for(i = 0; i < VConData.con_count; i++)
168         {
169                 if(ip == VConData.con[i].network_address.ip && port == VConData.con[i].network_address.port)
170                 {
171                         VConData.current_connection = i;
172                         return TRUE;
173                 }
174         }
175         return FALSE;
176 }
177
178 void v_con_inqueue_timer_update(void)
179 {
180         if(VConData.current_connection < VConData.con_count)
181         {
182                 v_niq_timer_update(&VConData.con[VConData.current_connection].in_queue);
183         }
184 }
185
186 /*
187 extern void     v_fs_buf_unpack(const uint8 *data, unsigned int length);
188 extern void     v_fs_buf_store_pack(uint8 *data, unsigned int length);
189 extern boolean  v_fs_buf_unpack_stored(void);
190 */
191 extern void v_unpack_connection(const char *buf, unsigned int buffer_length);
192
193 extern void     verse_send_packet_nak(uint32 packet_id);
194 extern void     v_callback_connect_terminate(const char *bye);
195 extern boolean  v_connect_unpack_ping(const char *buf, size_t buffer_length, uint32 ip, uint16 port);
196 extern void     v_ping_update(void);
197 void v_fs_unpack_beginning(uint8 *data, unsigned int length);
198
199 /* Main function that receives and distributes all incoming packets. */
200 boolean v_con_network_listen(void)
201 {
202         VNetworkAddress address;
203         uint8 buf[V_MAX_CONNECT_PACKET_SIZE], *store;
204         int size = 0;
205         unsigned int connection;
206         uint32 packet_id;
207         boolean ret = FALSE;
208
209         v_con_init(); /* Init if needed. */
210         connection = VConData.current_connection; /* Store current connection in a local variable so that we can restore it later. */
211         size = v_n_receive_data(&address, buf, sizeof buf); /* Ask for incoming data from the network. */
212         while(size != -1 && size != 0) /* Did we get any data? */
213         {
214                 VConData.current_connection = v_co_find_connection(address.ip, address.port); /* Is there a connection matching the IP and port? */
215                 vnp_raw_unpack_uint32(buf, &packet_id); /* Unpack the ID of the packet. */
216 /*              printf("got packet ID %u, %d bytes, connection %u\n", packet_id, size, VConData.current_connection);*/
217                 if(VConData.current_connection < VConData.con_count &&
218                    !(VConData.con[VConData.current_connection].connect_stage == V_CS_CONNECTED && packet_id == 0)) /* If this isn't a packet from an existing connection, disregard it. */
219                 {
220                         if(VConData.con[VConData.current_connection].connect_stage == V_CS_CONNECTED) /* Is this connection initialized? */
221                         {
222                                 store = v_niq_store(&VConData.con[VConData.current_connection].in_queue, size, packet_id); /* Store the packet. */
223                                 if(store != NULL)
224                                 {
225                                         VConData.pending_packets++; /* We now have one more packet pending unpack. */
226                                         v_e_data_decrypt_packet(store, buf, size, VConData.con[VConData.current_connection].key_data); /* Decrypt the packet. */
227                                         v_fs_unpack_beginning(store, size);
228                                 }
229                         }
230                         else
231                         {
232                                 v_unpack_connection(buf, size); /* This is an ongoing connecton-attempt. */
233                                 v_niq_timer_update(&VConData.con[VConData.current_connection].in_queue);
234                         }
235                 }
236                 else if(v_connect_unpack_ping(buf, size, address.ip, address.port))     /* Ping handled. */
237                         ;
238                 else if(v_fs_func_accept_connections()) /* Do we accept connection-attempts? */
239                 {
240                         if(VConData.current_connection >= VConData.con_count ||
241                            V_RE_CONNECTON_TIME_OUT < v_niq_time_out(&VConData.con[VConData.current_connection].in_queue)) /* Is it a new client, or an old client that we haven't heard form in some time? */
242                         {
243                                 if(VConData.current_connection < VConData.con_count)
244                                 {
245                                         VConData.con[VConData.current_connection].network_address.ip = 0;
246                                         VConData.con[VConData.current_connection].destroy_flag = TRUE; /* Destroy old connection if there is one. */
247                                 }
248                                 v_con_connect(address.ip, address.port, V_CS_IDLE); /* Create a new connection. */
249                                 v_unpack_connection(buf, size); /* Unpack the connection-attempt. */
250                         }
251                 }
252                 else
253                 {
254                         fprintf(stderr, __FILE__ ": Unhandled packet--dropping\n");
255                         fprintf(stderr, __FILE__ ": State: current=%u count=%u stage=%d id=%u\n",
256                                VConData.current_connection,
257                                VConData.con_count,
258                                VConData.con[VConData.current_connection].connect_stage,
259                                packet_id);
260                 }
261                 size = v_n_receive_data(&address, buf, sizeof buf); /* See if there are more incoming packets. */
262                 ret = TRUE;
263         }
264         VConData.current_connection = connection; /* Reset the current connection. */
265
266         return ret;
267 }
268
269 extern void     v_update_connection_pending(boolean resend);
270
271 boolean v_con_callback_update(void)
272 {
273         static unsigned int seconds;
274         boolean output = FALSE;
275         unsigned int    size, connection, s;
276         VNetInPacked    *p;
277
278         v_n_get_current_time(&s, NULL);
279         connection = VConData.current_connection;
280         for(VConData.current_connection = 0; VConData.current_connection < VConData.con_count; VConData.current_connection++)
281                 if(VConData.con[VConData.current_connection].connect_stage != V_CS_CONNECTED)
282                         v_update_connection_pending(s != seconds);
283         seconds = s;
284         VConData.current_connection = connection;
285         if(VConData.pending_packets == 0)
286                 return FALSE;
287         if(VConData.con[VConData.current_connection].connect_stage == V_CS_CONNECTED)
288         {
289                 while((p = v_niq_get(&VConData.con[VConData.current_connection].in_queue, &size)) != NULL)
290                 {
291                         VConData.pending_packets--;
292                         v_fs_unpack(p->data, size);
293                         v_niq_release(&VConData.con[VConData.current_connection].in_queue, p);
294                         output = TRUE;
295                 }
296                 v_con_network_listen();
297         }
298         return output;
299 }
300
301 void verse_callback_update(unsigned int microseconds)
302 {
303         unsigned int connection, passed;
304
305         v_ping_update();        /* Deliver any pending pings. */
306         connection = VConData.current_connection;
307         for(VConData.current_connection = 0; VConData.current_connection < VConData.con_count; VConData.current_connection++)
308         {
309                 if(VConData.con[VConData.current_connection].connect_stage == V_CS_CONNECTED)
310                         v_noq_send_queue(VConData.con[VConData.current_connection].out_queue, &VConData.con[VConData.current_connection].network_address);
311                 if(VConData.con[VConData.current_connection].destroy_flag == TRUE)
312                 {
313                         v_noq_destroy_network_queue(VConData.con[VConData.current_connection].out_queue);
314                         VConData.pending_packets -= v_niq_free(&VConData.con[VConData.current_connection].in_queue);
315                         v_destroy_ordered_storage(VConData.con[VConData.current_connection].ordered_storage);
316                         if(VConData.con[VConData.current_connection].expected_key != NULL)
317                                 free(VConData.con[VConData.current_connection].expected_key);
318                         VConData.con[VConData.current_connection] = VConData.con[--VConData.con_count];
319                         if(connection >= VConData.con_count)
320                                 VConData.current_connection = 0;
321                         return;
322                 }
323         }
324         VConData.current_connection = connection;
325
326         if(VConData.con_count > 0)
327         {
328 /*              printf("checking timeout of stage %d connection %u\n",
329                        VConData.con[VConData.current_connection].connect_stage, VConData.current_connection);
330 */              if(V_CONNECTON_TIME_OUT < v_niq_time_out(&VConData.con[VConData.current_connection].in_queue))
331                 {
332                         if(VConData.con[VConData.current_connection].connect_stage != V_CS_CONNECTED)
333                         {
334                                 VConData.con[VConData.current_connection].destroy_flag = TRUE;
335                         }
336                         else
337                                 v_callback_connect_terminate("connection timed out");
338                 }
339         }
340
341         v_con_network_listen();
342         if(VConData.con_count > 0)
343                 if(v_con_callback_update())
344                         return;
345         for(passed = 0; passed < microseconds && VConData.pending_packets == 0;)
346         {
347                 boolean update;
348                 if(microseconds - passed > V_CON_MAX_MICROSECOND_BETWEEN_SENDS) /* Still a long way to go? */
349                         passed += v_n_wait_for_incoming(V_CON_MAX_MICROSECOND_BETWEEN_SENDS);
350                 else
351                         passed += v_n_wait_for_incoming(microseconds - passed);
352                 do
353                 {
354                         update = v_con_network_listen();
355                         connection = VConData.current_connection;
356                         for(VConData.current_connection = 0; VConData.current_connection < VConData.con_count; VConData.current_connection++)
357                         {
358                                 if(VConData.con[VConData.current_connection].connect_stage == V_CS_CONNECTED)
359                                 {
360                                         if(v_noq_send_queue(VConData.con[VConData.current_connection].out_queue, &VConData.con[VConData.current_connection].network_address))
361                                                 update = TRUE;
362                                 }
363                         }
364                         VConData.current_connection = connection;
365                 } while(update);
366         }
367         if(VConData.con_count > 0)
368                 v_con_callback_update();
369 }
370
371 void v_con_set_name_pass(const char *name, const char *pass)
372 {
373         v_strlcpy(VConData.con[VConData.current_connection].name, name, sizeof VConData.con[VConData.current_connection].name);
374         v_strlcpy(VConData.con[VConData.current_connection].pass, pass, sizeof VConData.con[VConData.current_connection].pass);
375 }
376
377 const char * v_con_get_name(void)
378 {
379         return VConData.con[VConData.current_connection].name;
380 }
381
382 const char * v_con_get_pass(void)
383 {
384         return VConData.con[VConData.current_connection].pass;
385 }
386
387 void v_con_set_connect_stage(VConnectStage stage)
388 {
389         VConData.con[VConData.current_connection].connect_stage = stage;
390         VConData.con[VConData.current_connection].stage_atempts = 0;
391 }
392
393 VConnectStage v_con_get_connect_stage(void)
394 {
395         return VConData.con[VConData.current_connection].connect_stage;
396 }
397
398 uint8 *v_con_get_my_key(void)
399 {
400         return VConData.con[VConData.current_connection].key_my;
401 }
402
403 uint8 *v_con_get_other_key(void)
404 {
405         return VConData.con[VConData.current_connection].key_other;
406 }
407
408 uint8 **v_con_get_expected_key(void)
409 {
410         return &VConData.con[VConData.current_connection].expected_key;
411 }
412
413 uint8 * v_con_get_host_id(void)
414 {
415         return VConData.host_id;
416 }
417
418 void v_con_set_data_key(const uint8 *key)
419 {
420         memcpy(VConData.con[VConData.current_connection].key_data, key, V_ENCRYPTION_DATA_KEY_SIZE);
421 }
422
423 const uint8 * v_con_get_data_key(void)
424 {
425         return VConData.con[VConData.current_connection].key_data;
426 }
427
428 void * v_con_get_network_queue(void)
429 {
430         return VConData.con[VConData.current_connection].out_queue;
431 }
432
433 VNetworkAddress * v_con_get_network_address(void)
434 {
435         return &VConData.con[VConData.current_connection].network_address;
436 }
437
438 void * v_con_get_ordered_storage(void)
439 {
440         return VConData.con[VConData.current_connection].ordered_storage;
441 }
442
443 void v_con_set_avatar(uint32 avatar)
444 {
445         VConData.con[VConData.current_connection].avatar = avatar;
446 }
447
448 uint32 verse_session_get_avatar(void)
449 {
450         return VConData.con[VConData.current_connection].avatar;
451 }
452
453 void verse_session_get_time(uint32 *seconds, uint32 *fractions)
454 {
455         uint32 s, f;
456         v_n_get_current_time(&s, &f);
457         if((uint32)~0 - f < VConData.con[VConData.current_connection].timedelta_f)
458                 s++;
459         if(seconds != NULL) 
460         {
461                 if(VConData.con[VConData.current_connection].timedelta_s < 0)
462                         *seconds = s - (uint32)(-VConData.con[VConData.current_connection].timedelta_s);
463                 else
464                         *seconds = s + VConData.con[VConData.current_connection].timedelta_s;
465         }
466         if(fractions != NULL)
467                 *fractions = f + VConData.con[VConData.current_connection].timedelta_f;
468 }
469
470 void v_con_set_time(uint32 seconds, uint32 fractions)
471 {
472         uint32 s, f;
473         v_n_get_current_time(&s, &f);
474
475         if(f < fractions)
476                 s--;
477         if (s < seconds)
478                 VConData.con[VConData.current_connection].timedelta_s = -(int)(seconds - s);
479         else
480                 VConData.con[VConData.current_connection].timedelta_s = (int)(s - seconds);
481         VConData.con[VConData.current_connection].timedelta_f = f - fractions;
482 }
483
484 #endif