8 // - c network routines
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>
18 #include <pthread.h> // posix threads
29 #include "include/msg.h"
30 #include "include/connect.h"
32 #include "../globals.h"
34 #include "../fireants.h"
41 extern char network_str_
[22][80];
45 static ComObj client_obj
;
47 static pthread_t thread_id
[2];
50 struct timespec timeout
;
52 static unsigned long _msg_bytes
= 0;
57 pthread_mutex_t snifferMutex
= PTHREAD_MUTEX_INITIALIZER
;
58 pthread_cond_t snifferCond
= PTHREAD_COND_INITIALIZER
;
61 static int sniffer_flag
= SNIFFER_OFF
;
62 static int sniffer_state
= SNIFFER_OFF
;
67 void Reset_MessageBytes(void)
70 } // end of thef unction
75 int GetMessageCount(void)
79 z
= (_msg_bytes
/ sizeof(Msg
));
88 void Set_RemoteAddr(ComObj
*ptr
, struct sockaddr_in
*c_addr
)
91 memcpy(&ptr
->remote_addr
, c_addr
, sizeof(struct sockaddr_in
));
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
111 void Destroy_Mutex(void)
114 pthread_mutex_destroy(&snifferMutex
);
115 pthread_cond_destroy(&snifferCond
);
117 } // end of the function
123 void WaitThread(void)
130 pthread_attr_destroy(&attr
);
132 for (i
= 0; i
< 2; i
++)
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");
143 } // end of the function
149 static void Lock_Sniffer(void)
151 sniffer_flag
= SNIFFER_ON
;
156 static void Unlock_Sniffer(void)
158 sniffer_flag
= SNIFFER_OFF
;
162 // another thread function
164 void *SnifferThread(void *args
)
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;
191 // sniffer state is going
193 pthread_mutex_lock(&snifferMutex
);
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
219 pthread_mutex_unlock(&snifferMutex
);
221 } // end of if - else
223 // continue with sniffer agent
227 } // end of the function
233 void *WaitMsg(void *args
)
237 struct sockaddr_in from_addr
;
238 unsigned int addr_size
;
245 // get the socket data
246 sock
= ((ComObjPtr
)args
)->sock
;
249 // main thread loop, get messages
256 buf
= GetMsgCluster();
257 addr_size
= sizeof(from_addr
);
262 bytes_recv
= recvfrom(sock
, buf
, MAX_SIZE
, 0,
263 (struct sockaddr
*)&from_addr
, &addr_size
);
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
286 // close the network screen
287 // once we have a server intro
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
305 // once the server sends a start
306 // game, the game begins
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
)
326 // change into running mode
327 // start the network game!
329 client_obj
.activity
= _RUNNING_
;
331 MAX_NETWORK_BOTS
= no_bots
;
332 Set_MsgIndex(no_bots
);
342 // after the blocking call recvfrom
343 // process the message que
345 // this msgindex is flaky....!
346 Set_MsgIndex(no_bots
);
356 } // end of the function
360 // - utility function
361 // not must substance
362 // - you can call this without loading objects
364 void Get_LocalAddress(void)
372 struct sockaddr_in serv_addr
;
373 struct sockaddr_in remote_addr
;
377 #if defined(UDP_PROTOCOL)
378 sock
= socket(PF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
380 // create a socket for incoming connection
381 sock
= socket(PF_INET
, SOCK_STREAM
, IPPROTO_TCP
);
386 printf("socket() failed\n");
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
));
401 printf("bind failed\n");
406 remote_addr
.sin_port
= htons(port
);
407 remote_addr
.sin_family
= AF_INET
;
411 res
= sizeof(remote_addr
);
412 if (connect(sock
, (struct sockaddr
*)&remote_addr
, res
) <0)
414 printf("connect() failed\n");
419 res
= sizeof(serv_addr
);
420 if (getsockname(sock
, (struct sockaddr
*)&serv_addr
, &res
) < 0)
422 printf("getsockname() failed\n");
426 // only for the server
427 buf
= inet_ntoa(serv_addr
.sin_addr
);
431 for (i
= 0; i
< res
; i
++) {
433 network_str_
[SERVER_NET_MENU
+1][text_start
+i
] = *buf
++;
438 network_str_
[SERVER_NET_MENU
+1][text_start
+i
] = '\0';
440 // now close the connection
443 } // end of the function
448 void Build_LoginMsg(MsgPtr ptr
)
458 ptr
->msg_type
= MSG_LOGIN
;
463 for (i
= 0; i
< res
; i
++) {
465 // this may work, but so will final_str
467 c
= network_str_
[CLIENT_NET_MENU
+0][text_start
+i
];
470 if ((c
== '\0') || ( c
== '\n'))
481 sprintf(buffer
, "%s?%d?%s", buf
, __VERSION__
, __OS__
);
482 strcpy(ptr
->msg
, buffer
);
485 } // end of the function
489 // - actually use sendto and send the message to the server
491 void Build_MoveMsg(float x
, float y
, float heading
, int type
)
499 id
= client_obj
.object_id
;
503 msg
.heading
= heading
;
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
520 serv_id
= Get_ServObjID();
521 Msg_AddQueue(MSG_MOVE
, type
, serv_id
, x
, y
, heading
);
525 } // end of the function
532 void Connect(ComObjPtr com_obj
, char *ip
, int port
)
535 struct sockaddr_in serv_addr
;
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");
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,
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
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
586 void Connect_Server(char *buffer
)
588 client_obj
.activity
= _WAITING_
;
589 Connect((ComObjPtr
)&client_obj
, buffer
, CONNECT_PORT
);
591 } // end of the function
597 void Create_Client(void)
599 client_obj
.connect_flag
= _NOT_CONNECTED_
;
602 client_obj
.activity
= _WAITING_
;
604 } // end of thefunction
609 void Kill_Client(void)
612 if (client_obj
.connect_flag
== _CONNECTED_
)
616 close(client_obj
.sock
);
620 } // end of the function
624 void Print_ClientRun(void)
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");
635 Draw_TString(_NET_SCREEN_X
, _NET_SCREEN_Y1
,"Client Waiting");
637 Draw_TString(_NET_SCREEN_X
, _NET_SCREEN_Y2
,buffer
);
641 } // end of the function