Fixed all gcc 4 warnings in blenkernel. Found 2 potentially harmful
[blender.git] / source / blender / blenkernel / intern / verse_session.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version. The Blender
10  * Foundation also sells licenses for use in proprietary software under
11  * the Blender License.  See http://www.blender.org/BL/ for information
12  * about this.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software Foundation,
21  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22  *
23  * Contributor(s): Jiri Hnidek.
24  *
25  * ***** END GPL/BL DUAL LICENSE BLOCK *****
26  */
27
28 #ifdef WITH_VERSE
29
30 #include <string.h>
31
32 #include "MEM_guardedalloc.h"
33
34 #include "DNA_mesh_types.h"     /* temp */
35 #include "DNA_listBase.h"
36 #include "DNA_screen_types.h"
37 #include "DNA_userdef_types.h"
38
39 #include "BLI_dynamiclist.h"
40 #include "BLI_blenlib.h"
41
42 #include "BIF_verse.h"
43
44 #include "BKE_global.h" 
45 #include "BKE_verse.h"
46
47 struct ListBase session_list={NULL, NULL};
48 struct ListBase server_list={NULL, NULL};
49
50 static int cb_ping_registered = 0;
51
52 /* list of static function prototypes */
53 static void cb_connect_terminate(const char *address, const char *bye);
54 static void cb_connect_accept(void *user_data, uint32 avatar, void *address, void *connection, const uint8 *host_id);
55 static void set_all_callbacks(void);
56 static void free_verse_session_data(struct VerseSession *session);
57 static void add_verse_server(VMSServer *server);
58 static void check_connection_state(struct VerseServer *server);
59
60 static void check_connection_state(struct VerseServer *server)
61 {
62         struct VerseSession *session;
63         session = session_list.first;
64         while(session) {
65                 if(strcmp(server->ip,session->address)==0) {
66                         server->flag = session->flag;
67                         return;
68                 }
69                 session = session->next;
70         }
71 }
72 /*
73  * add verse server to server_list. Prevents duplicate
74  * entries
75  */
76 static void add_verse_server(VMSServer *server)
77 {
78         struct VerseServer *iter, *niter;
79         VerseServer *newserver;
80         const char *name = verse_ms_field_value(server, "DE");
81         iter = server_list.first;
82
83         while(iter) {
84                 niter = iter->next;
85                 if(strcmp(iter->ip, server->ip)==0) {
86                         return;
87                 }
88                 iter = niter;
89         }
90
91         newserver = (VerseServer *)MEM_mallocN(sizeof(VerseServer), "VerseServer");
92         newserver->ip = (char *)MEM_mallocN(sizeof(char)*(strlen(server->ip)+1), "VerseServer ip");
93         strcpy(newserver->ip, server->ip);
94
95         if(name) {
96                 newserver->name = (char *)MEM_mallocN(sizeof(char)*(strlen(name)+strlen(newserver->ip)+4), "VerseServer name");
97                 strcpy(newserver->name, name);
98                 strcat(newserver->name, " (");
99                 strcat(newserver->name, newserver->ip);
100                 strcat(newserver->name, ")");
101         }
102
103         newserver->flag = 0;
104         check_connection_state(newserver);
105
106         printf("Adding new verse server: %s at %s\n", newserver->name, newserver->ip);
107
108         BLI_addtail(&server_list, newserver);
109         post_server_add();
110 }
111
112 /*
113  * callback function for ping
114  */
115 static void cb_ping(void *user, const char *address, const char *message)
116 {
117         VMSServer       **servers = verse_ms_list_parse(message);
118         if(servers != NULL)
119         {
120                 int     i;
121
122                 for(i = 0; servers[i] != NULL; i++)
123                         add_verse_server(servers[i]);
124
125                 free(servers);
126         }
127 }
128
129 /*
130  * callback function for connection terminated
131  */
132 static void cb_connect_terminate(const char *address, const char *bye)
133 {
134         VerseSession *session = (VerseSession*)current_verse_session();
135
136         if(!session) return;
137
138         /* remove session from list of session */
139         BLI_remlink(&session_list, session);
140         /* do post connect operations */
141         session->post_connect_terminated(session);
142         /* free session data */
143         free_verse_session_data(session);
144         /* free session */
145         MEM_freeN(session);
146 }
147
148 /*
149  * callback function for accepted connection to verse server
150  */
151 static void cb_connect_accept(
152                 void *user_data,
153                 uint32 avatar,
154                 void *address,
155                 void *connection,
156                 const uint8 *host_id)
157 {
158         struct VerseSession *session = (VerseSession*)current_verse_session();
159         struct VerseServer *server = server_list.first;
160         uint32 i, mask=0;
161
162         if(!session) return;
163
164         session->flag |= VERSE_CONNECTED;
165         session->flag &= ~VERSE_CONNECTING;
166
167         while(server) {
168                 if(strcmp(session->address, server->ip)==0) {
169                         server->flag |= VERSE_CONNECTED;
170                         server->flag &= ~VERSE_CONNECTING;
171                         server->session = session;
172                         break;
173                 }
174                 server = server->next;
175         }
176
177         printf("\tBlender is connected to verse server: %s\n", (char*)address);
178         printf("\tVerseSession->counter: %d\n", session->counter);
179
180         session->avatar = avatar;
181
182         session->post_connect_accept(session);
183
184         for(i = 0; i < V_NT_NUM_TYPES; i++)
185                 mask = mask | (1 << i);
186         verse_send_node_index_subscribe(mask);
187 }
188
189 /*
190  * set up all callbacks for sessions
191  */
192 void set_verse_session_callbacks(void)
193 {
194         /* connection */
195         verse_callback_set(verse_send_connect_accept, cb_connect_accept, NULL);
196         /* connection was terminated */
197         verse_callback_set(verse_send_connect_terminate, cb_connect_terminate, NULL);
198
199 }
200
201 /*
202  * set all callbacks used in Blender
203  */
204 static void set_all_callbacks(void)
205 {
206         /* set up all callbacks for sessions */
207         set_verse_session_callbacks();
208
209         /* set up callbacks for nodes */
210         set_node_callbacks();
211
212         /* set up all callbacks for object nodes */
213         set_object_callbacks();
214
215         /* set up all callbacks for geometry nodes */
216         set_geometry_callbacks();
217
218         /* set up all callbacks for bitmap nodes */
219         set_bitmap_callbacks();
220 }
221
222 /*
223  * this function sends and receive all packets for all sessions
224  */
225 void b_verse_update(void)
226 {
227         VerseSession *session, *next_session;
228
229         session = session_list.first;
230         while(session){
231                 next_session = session->next;
232                 verse_session_set(session->vsession);
233                 if((session->flag & VERSE_CONNECTED) || (session->flag & VERSE_CONNECTING)) {
234                         verse_callback_update(10);
235                         session->post_connect_update(session);
236                 }
237                 session = next_session;
238         }
239         if(cb_ping_registered>0) {
240                         verse_callback_update(10);
241         }
242 }
243
244 /*
245  * returns VerseSession coresponding to vsession pointer
246  */
247 VerseSession *versesession_from_vsession(VSession *vsession)
248 {
249         struct VerseSession *session;
250
251         session = session_list.first;
252
253         while(session) {
254                 if(session->vsession==vsession) return session;
255                 session = session->next;
256         }
257         
258         return session;
259 }
260
261 /*
262  * returns pointer at current VerseSession
263  */
264 VerseSession *current_verse_session(void)
265 {
266         struct VerseSession *session;
267         VSession vsession = verse_session_get();
268
269         session = session_list.first;
270
271         while(session){
272                 if(session->vsession == vsession)
273                         return session;
274                 session = session->next;
275         }
276
277         printf("error: non-existing SESSION occured!\n");
278         return NULL;
279 }
280
281 /*
282  * free VerseSession
283  */
284 static void free_verse_session_data(VerseSession *session)
285 {
286         struct VNode *vnode;
287
288         /* free data of all nodes */
289         vnode = session->nodes.lb.first;
290         while(vnode){
291                 free_verse_node_data(vnode);
292                 vnode = vnode->next;
293         }
294
295         /* free data of nodes waiting in queue */
296         vnode = session->queue.first;
297         while(vnode){
298                 free_verse_node_data(vnode);
299                 vnode = vnode->next;
300         }
301
302         /* free all VerseNodes */
303         BLI_dlist_destroy(&(session->nodes));
304         /* free all VerseNodes waiting in queque */
305         BLI_freelistN(&(session->queue));
306
307         /* free name of verse host for this session */
308         MEM_freeN(session->address);
309 }
310
311 /*
312  * free VerseSession
313  */
314 void free_verse_session(VerseSession *session)
315 {
316         /* remove session from session list*/
317         BLI_remlink(&session_list, session);
318         /* do post terminated operations */
319         session->post_connect_terminated(session);
320         /* free session data (nodes, layers) */
321         free_verse_session_data(session);
322         /* free session */
323         MEM_freeN(session);
324 }
325
326 /*
327  * create new verse session and return coresponding data structure
328  */
329 VerseSession *create_verse_session(
330                 const char *name,
331                 const char *pass,
332                 const char *address,
333                 uint8 *expected_key)
334 {
335         struct VerseSession *session;
336         VSession *vsession;
337         
338         vsession = verse_send_connect(name, pass, address, expected_key);
339
340         if(!vsession) return NULL;
341
342         session = (VerseSession*)MEM_mallocN(sizeof(VerseSession), "VerseSession");
343
344         session->flag = VERSE_CONNECTING;
345
346         session->vsession = vsession;
347         session->avatar = -1;
348
349         session->address = (char*)MEM_mallocN(sizeof(char)*(strlen(address)+1),"session adress name");
350         strcpy(session->address, address);
351
352         session->connection = NULL;
353         session->host_id = NULL;
354         session->counter = 0;
355
356         /* initialize dynamic list of nodes and node queue */
357         BLI_dlist_init(&(session->nodes));
358         session->queue.first = session->queue.last = NULL;
359
360         /* set up all client dependent functions */
361         session->post_connect_accept = post_connect_accept;
362         session->post_connect_terminated = post_connect_terminated;
363         session->post_connect_update = post_connect_update;
364
365         post_server_add();
366
367         return session;
368 }
369
370 /*
371  * end verse session and free all session data
372  */
373 void end_verse_session(VerseSession *session)
374 {
375         /* send terminate command to verse server */
376         verse_send_connect_terminate(session->address, "blender: bye bye");
377         /* update callbacks */
378         verse_callback_update(1000);
379         /* send destroy session command to verse server */
380         verse_session_destroy(session->vsession);
381         /* set up flag of verse session */
382         session->flag &= ~VERSE_CONNECTED;
383         /* do post connect operations */
384         session->post_connect_terminated(session);
385         /* free structure of verse session */
386         free_verse_session(session);
387 }
388
389 void free_all_servers(void)
390 {
391         VerseServer *server, *nextserver;
392
393         server = server_list.first;
394
395         while(server) {
396                 nextserver = server->next;
397                 BLI_remlink(&server_list, server);
398                 MEM_freeN(server->name);
399                 MEM_freeN(server->ip);
400                 MEM_freeN(server);
401                 server = nextserver;
402         }
403         
404         BLI_freelistN(&server_list);
405 }
406
407 /*
408  * end connection to all verse hosts (servers) ... free all VerseSessions
409  * free all VerseServers
410  */
411 void end_all_verse_sessions(void)
412 {
413         VerseSession *session,*nextsession;
414
415         session = session_list.first;
416
417         while(session) {
418                 nextsession= session->next;
419                 end_verse_session(session);
420                 /* end next session */
421                 session = nextsession;
422         }
423
424         BLI_freelistN(&session_list);
425
426         free_all_servers();
427 }
428
429 /*
430  * do a get from ms
431  */
432 void b_verse_ms_get(void)
433 {
434         if(cb_ping_registered==0) {
435                 /* handle ping messages (for master server) */
436                 verse_callback_set(verse_send_ping, cb_ping, NULL);
437                 add_screenhandler(G.curscreen, SCREEN_HANDLER_VERSE, 1);
438                 cb_ping_registered++;
439         }
440         free_all_servers();
441
442         verse_ms_get_send(U.versemaster, VERSE_MS_FIELD_DESCRIPTION, NULL);
443         verse_callback_update(10);
444 }
445
446 /*
447  * connect to verse host, set up all callbacks, create session
448  */
449 void b_verse_connect(char *address)
450 {
451         VerseSession *session = NULL;
452
453         /* if no session was created before, then set up all callbacks */
454         if((session_list.first==NULL) && (session_list.last==NULL))
455                 set_all_callbacks();
456
457         /* create new session */
458         if(address)
459                 session = create_verse_session("Blender", "pass", address, NULL);
460
461         if(session) {
462                 /* add new session to the list of sessions */
463                 BLI_addtail(&session_list, session);
464
465                 /* add verse handler if this is first session */
466                 if(session_list.first == session_list.last)
467                         add_screenhandler(G.curscreen, SCREEN_HANDLER_VERSE, 1);
468
469         }
470 }
471
472 #endif