Initial Import
[glAntsMech.git] / glants_mech / linux / src / network / network.c
blobae2f9875d710739e3696f7c3f0f37814f2196c8e
1 //
2 // Berlin Brown
3 // bigbinc@hotmail.com
4 //
5 // - client code
6 //
7 // network.c
8 // - c network routines
9 //
10 // linux version gcc 2.96/ mandrake 8.2
12 // Note: run /etc/services for empty ports
14 #include <netinet/in.h>
15 #include <sys/socket.h>
16 #include <arpa/inet.h>
17 #include <netdb.h>
18 #include <pthread.h> // posix threads
20 #include <unistd.h>
21 #include <errno.h>
22 #include <time.h>
23 #include <sys/time.h>
24 #include <string.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <unistd.h>
29 #include "include/msg.h"
30 #include "include/connect.h"
31 #include "network.h"
32 #include "../globals.h"
33 #include "../bot.h"
34 #include "../fireants.h"
37 #define SNIFFER_OFF 0
38 #define SNIFFER_ON 1
41 extern char network_str_[22][80];
43 //
44 // main client object
45 static ComObj client_obj;
47 static pthread_t thread_id[2];
49 struct timeval now;
50 struct timespec timeout;
52 static unsigned long _msg_bytes = 0;
56 // sniffer variables
57 pthread_mutex_t snifferMutex = PTHREAD_MUTEX_INITIALIZER;
58 pthread_cond_t snifferCond = PTHREAD_COND_INITIALIZER;
59 pthread_attr_t attr;
61 static int sniffer_flag = SNIFFER_OFF;
62 static int sniffer_state = SNIFFER_OFF;
65 // Reset_MessageCount
67 void Reset_MessageBytes(void)
69 _msg_bytes = 0;
70 } // end of thef unction
73 // GetMessageCount
75 int GetMessageCount(void)
77 int z;
79 z = (_msg_bytes / sizeof(Msg));
81 return z;
83 } // end of func
86 // Set_NetAddr
87 //
88 void Set_RemoteAddr(ComObj *ptr, struct sockaddr_in *c_addr)
91 memcpy(&ptr->remote_addr, c_addr, sizeof(struct sockaddr_in));
93 } // end of the if
96 // Create_Mutex()
97 void Create_Mutex(void)
99 pthread_mutex_init(&snifferMutex,NULL);
101 // also create condition
102 pthread_cond_init(&snifferCond, NULL);
104 pthread_attr_init(&attr);
105 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
107 } // end of the function
110 // Destroy Mutex
111 void Destroy_Mutex(void)
114 pthread_mutex_destroy(&snifferMutex);
115 pthread_cond_destroy(&snifferCond);
117 } // end of the function
121 // WaitThread
123 void WaitThread(void)
126 int status;
127 int i;
128 int res;
130 pthread_attr_destroy(&attr);
132 for (i = 0; i < 2; i++)
134 // blocked call
135 res = pthread_join(thread_id[i],(void **)&status); // Parent waits for
137 pthread_cancel(thread_id[1]);
138 printf("join complete, killing thread 2\n");
139 break;
141 } // end of the for
143 } // end of the function
147 // Lock_Sniffer()
149 static void Lock_Sniffer(void)
151 sniffer_flag = SNIFFER_ON;
152 } // end of func
155 // unlock
156 static void Unlock_Sniffer(void)
158 sniffer_flag = SNIFFER_OFF;
159 } // end of func
162 // another thread function
164 void *SnifferThread(void *args)
166 int res;
167 res = 0;
169 // main while loop
170 while(1) {
172 if (sniffer_state == SNIFFER_OFF) {
174 if (sniffer_flag == SNIFFER_ON)
176 // flag is set restart the timer
177 sniffer_state = SNIFFER_ON;
179 // reset collection flag --
180 sniffer_flag = SNIFFER_OFF;
182 // collect a new timeout
183 gettimeofday(&now, NULL);
184 timeout.tv_sec = now.tv_sec + ALARM_TIMEOUT;
185 timeout.tv_nsec = now.tv_usec * 1000;
187 } // end of the if
189 } else {
191 // sniffer state is going
193 pthread_mutex_lock(&snifferMutex);
194 while(1) {
196 // note, this is another blocked call in addition to recvfrom
198 // res returns zero is based on condition
199 res = pthread_cond_timedwait(&snifferCond, &snifferMutex, &timeout);
200 if (res == ETIMEDOUT) {
202 // kill the other thread
203 sniffer_state = SNIFFER_OFF;
204 pthread_cancel(thread_id[0]);
205 printf("Timer was released, killing thread\n");
207 client_obj.connect_flag = _NOT_CONNECTED_;
208 close(client_obj.sock);
209 Set_NetworkMsg("Connection Timed Out");
211 // unlock the watchdog
212 Unlock_Sniffer();
214 break;
215 } // end of the if
218 } // end of while
219 pthread_mutex_unlock(&snifferMutex);
221 } // end of if - else
223 // continue with sniffer agent
225 } // endof while --
227 } // end of the function
231 // waitmsg
233 void *WaitMsg(void *args)
235 int bytes_recv;
236 int sock;
237 struct sockaddr_in from_addr;
238 unsigned int addr_size;
240 int no_bots;
242 void *buf = NULL;
243 MsgPtr msg = NULL;
245 // get the socket data
246 sock = ((ComObjPtr)args)->sock;
247 bytes_recv = 0;
249 // main thread loop, get messages
250 for (;;)
254 Clear_FirstMsg();
256 buf = GetMsgCluster();
257 addr_size = sizeof(from_addr);
259 if (CHECK_WATCHDOG)
260 Lock_Sniffer();
262 bytes_recv = recvfrom(sock, buf, MAX_SIZE, 0,
263 (struct sockaddr *)&from_addr, &addr_size);
266 if (CHECK_WATCHDOG)
267 Unlock_Sniffer();
269 // we will keep it simple
270 // - if it is a reply message
271 // process just that one
272 msg = Get_FirstMsg();
273 if (msg->msg_type == MSG_REPLY)
275 // copy the message to the display string
276 Set_NetworkMsg(msg->msg);
278 // make sure we are connet
279 client_obj.connect_flag = _CONNECTED_;
281 // no more watchdog, run client
282 // till the server/client quits
283 TURNOFF_WATCHDOG;
285 // and more yet,
286 // close the network screen
287 // once we have a server intro
288 // message
289 // close screen and wait for
290 // user to press new game
291 // and display message
293 client_obj.activity = _READY_;
295 SET_NET_CLIENT; // turn network interface on
297 // get your current id
298 client_obj.object_id = msg->object_id;
300 Set_MsgId(msg->object_id);
302 // Note that the client
303 // cannot start the game at
304 // this point
305 // once the server sends a start
306 // game, the game begins
307 Mode_TitleScreen();
309 } // end of the
310 else {
312 // the first messagse is not a
313 // reply type, so that means
314 // it is a game position
315 _msg_bytes = bytes_recv;
318 // not perfect, but it will speed things up
319 no_bots = _msg_bytes / sizeof(Msg);
321 // check first message
322 switch(msg->msg_type)
324 case MSG_LOAD:
326 // change into running mode
327 // start the network game!
328 Mode_SetRunning();
329 client_obj.activity = _RUNNING_;
331 MAX_NETWORK_BOTS = no_bots;
332 Set_MsgIndex(no_bots);
335 break;
337 default: break;
339 }; // end of switch
342 // after the blocking call recvfrom
343 // process the message que
345 // this msgindex is flaky....!
346 Set_MsgIndex(no_bots);
347 Run_NetworkBots();
350 } // end of if
352 } // end of the for
355 return NULL;
356 } // end of the function
359 // Get_LocalAddress
360 // - utility function
361 // not must substance
362 // - you can call this without loading objects
364 void Get_LocalAddress(void)
366 int res;
367 int i;
368 char *buf = NULL;
369 int text_start = 0;
370 int sock;
371 unsigned short port;
372 struct sockaddr_in serv_addr;
373 struct sockaddr_in remote_addr;
375 port = CONNECT_PORT;
377 #if defined(UDP_PROTOCOL)
378 sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
379 #else
380 // create a socket for incoming connection
381 sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
382 #endif
384 if (sock < 0)
386 printf("socket() failed\n");
387 exit(1);
388 } // end of the if
391 memset(&serv_addr, 0, sizeof(serv_addr));
392 serv_addr.sin_family = AF_INET;
393 serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
394 serv_addr.sin_port = htons(port);
396 // bind to the address
397 res = bind(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
399 if (res < 0)
401 printf("bind failed\n");
402 exit(1);
403 } // end of if
405 #if 1
406 remote_addr.sin_port = htons(port);
407 remote_addr.sin_family = AF_INET;
409 // get local address
411 res = sizeof(remote_addr);
412 if (connect(sock, (struct sockaddr *)&remote_addr, res) <0)
414 printf("connect() failed\n");
416 #endif
419 res = sizeof(serv_addr);
420 if (getsockname(sock, (struct sockaddr *)&serv_addr, &res) < 0)
422 printf("getsockname() failed\n");
423 } // end of the if
425 // copy the address
426 // only for the server
427 buf = inet_ntoa(serv_addr.sin_addr);
428 res = strlen(buf);
429 text_start = 14;
431 for (i = 0; i < res; i++) {
433 network_str_[SERVER_NET_MENU+1][text_start+i] = *buf++;
435 } // end of the for
437 // null-terminate
438 network_str_[SERVER_NET_MENU+1][text_start+i] = '\0';
440 // now close the connection
441 close(sock);
443 } // end of the function
446 // Build_LoginMsg
448 void Build_LoginMsg(MsgPtr ptr)
450 // see include/msg.h
451 char buffer[42];
452 char buf[34];
453 int text_start;
454 int res;
455 char c;
456 int i;
458 ptr->msg_type = MSG_LOGIN;
460 text_start = 15;
461 res = 32;
463 for (i = 0; i < res; i++) {
465 // this may work, but so will final_str
466 // which is safer!
467 c = network_str_[CLIENT_NET_MENU+0][text_start+i];
468 buf[i] = c;
470 if ((c == '\0') || ( c == '\n'))
472 break;
473 } // end of if
475 } // end of the for
477 // null-terminate
478 buf[i] = '\0';
480 // build the message
481 sprintf(buffer, "%s?%d?%s", buf, __VERSION__, __OS__);
482 strcpy(ptr->msg, buffer);
485 } // end of the function
488 // Build_MoveMsg
489 // - actually use sendto and send the message to the server
491 void Build_MoveMsg(float x, float y, float heading, int type)
493 int res;
494 void *buf = NULL;
495 int id;
496 int serv_id;
497 Msg msg;
499 id = client_obj.object_id;
501 msg.pos_x = x;
502 msg.pos_y = y;
503 msg.heading = heading;
504 msg.object_id = id;
505 msg.msg_type = type;
507 buf = (void *)&msg;
508 res = sizeof(Msg);
510 if (CHECK_NET_CLIENT) {
512 res = sendto(client_obj.sock, (MsgPtr)&msg, res, 0,
513 (struct sockaddr *)&client_obj.remote_addr, sizeof(client_obj.remote_addr));
515 } else if (CHECK_NET_SERVER) {
517 // this is server code, so the id will be based on the server obj
518 // skip the sendto and just add to the message queue
519 // to be sent out
520 serv_id = Get_ServObjID();
521 Msg_AddQueue(MSG_MOVE, type, serv_id, x, y, heading);
523 } // end of if-else
525 } // end of the function
530 // Connect
532 void Connect(ComObjPtr com_obj, char *ip, int port)
534 int res;
535 struct sockaddr_in serv_addr;
536 Msg msg;
538 strcpy(com_obj->ipaddress, ip);
539 com_obj->port = port;
541 com_obj->sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
543 if (com_obj->sock < 0)
545 fprintf(stderr, "socket() failed\n");
546 } // end of the if
548 // construct server address
549 memset(&serv_addr, 0, sizeof(serv_addr));
551 serv_addr.sin_family = AF_INET;
552 serv_addr.sin_addr.s_addr = inet_addr(com_obj->ipaddress);
553 serv_addr.sin_port = htons(com_obj->port);
555 // build the message and send it off,
556 res = sizeof(Msg);
558 Build_LoginMsg((MsgPtr)&msg);
560 res = sendto(com_obj->sock, (MsgPtr)&msg, res, 0,
561 (struct sockaddr *)&serv_addr, sizeof(serv_addr));
563 // set remote address --
564 Set_RemoteAddr(com_obj, (struct sockaddr_in *)&serv_addr);
566 // timeout variables and init functions
567 Create_Mutex();
569 // for simplicity, turn on connected, this may need refinement
570 com_obj->connect_flag = _CONNECTED_;
571 com_obj->connect_type = _TYPE_CLIENT_;
572 com_obj->watchdog = _WATCHDOG_ON_;
574 // create a sniffer agent thread also
575 pthread_create(&thread_id[1], &attr, SnifferThread, NULL);
577 // also recv a message
578 // create a thread to wait for messages
579 pthread_create(&thread_id[0], &attr, WaitMsg, (void *)com_obj);
581 } // end of the function
584 // RunTest
586 void Connect_Server(char *buffer)
588 client_obj.activity = _WAITING_;
589 Connect((ComObjPtr)&client_obj, buffer, CONNECT_PORT);
591 } // end of the function
594 // Create_Client
595 // - called at main
597 void Create_Client(void)
599 client_obj.connect_flag = _NOT_CONNECTED_;
600 TURNON_WATCHDOG;
602 client_obj.activity = _WAITING_;
604 } // end of thefunction
607 // Kill_Client
609 void Kill_Client(void)
612 if (client_obj.connect_flag == _CONNECTED_)
615 Destroy_Mutex();
616 close(client_obj.sock);
618 } // end of the if
620 } // end of the function
624 void Print_ClientRun(void)
626 char buffer[80];
628 if ((client_obj.activity == _RUNNING_) || (client_obj.activity == _READY_))
630 sprintf(buffer, "Messages x%d recvd\n",GetMessageCount());
632 if (client_obj.activity == _RUNNING_)
633 Draw_TString(_NET_SCREEN_X, _NET_SCREEN_Y1,"Client Running");
634 else
635 Draw_TString(_NET_SCREEN_X, _NET_SCREEN_Y1,"Client Waiting");
637 Draw_TString(_NET_SCREEN_X, _NET_SCREEN_Y2,buffer);
639 } // end of the if
641 } // end of the function