Include and link physfs properly.
[tuxanci.git] / src / client / client.c
blob054b3ea67eb4ed2daf7e8a70211e36ddcc418f5a
1 #include <assert.h>
2 #include <stdio.h>
3 #include <stdlib.h>
5 #include <fcntl.h>
6 #include <sys/types.h>
7 #include <sys/time.h>
9 #ifndef __WIN32__
10 #include <sys/ioctl.h>
11 #include <sys/socket.h>
12 #include <sys/select.h>
13 #else /* __WIN32__ */
14 #include <io.h>
15 #include <winsock2.h>
16 #endif /* __WIN32__ */
18 #include "main.h"
19 #include "list.h"
20 #include "tux.h"
21 #include "proto.h"
23 #include "client.h"
25 #include "analyze.h"
26 #include "world.h"
27 #include "buffer.h"
29 #include "udp.h"
31 static sock_udp_t *sock_server_udp;
33 static list_t *listRecvMsg;
35 static buffer_t *clientRecvBuffer;
36 static buffer_t *clientSendBuffer;
38 static my_time_t lastPing;
39 static my_time_t lastPingServerAlive;
41 #ifdef SUPPORT_TRAFFIC
42 static my_time_t lastTraffic;
43 static int traffic_down;
44 static int traffic_up;
45 #endif /* SUPPORT_TRAFFIC */
47 typedef struct proto_cmd_client_struct {
48 char *name;
49 int len;
50 void (*fce_proto) (char *msg);
51 } proto_cmd_client_t;
53 static proto_cmd_client_t proto_cmd_list[] = {
54 {.name = "error",.len = 5,.fce_proto = proto_recv_error_client},
55 {.name = "init",.len = 4,.fce_proto = proto_recv_init_client},
56 {.name = "event",.len = 5,.fce_proto = proto_recv_event_client},
57 {.name = "newtux",.len = 6,.fce_proto = proto_recv_newtux_client},
58 {.name = "del",.len = 3,.fce_proto = proto_recv_del_client},
59 {.name = "additem",.len = 7,.fce_proto = proto_recv_additem_client},
60 {.name = "shot",.len = 4,.fce_proto = proto_recv_shot_client},
61 {.name = "kill",.len = 4,.fce_proto = proto_recv_kill_client},
62 {.name = "module",.len = 6,.fce_proto = proto_recv_module_client},
63 {.name = "chat",.len = 4,.fce_proto = proto_recv_chat_client},
64 {.name = "ping",.len = 4,.fce_proto = proto_recv_ping_client},
65 {.name = "end",.len = 3,.fce_proto = proto_recv_end_client},
66 {.name = "",.len = 0,.fce_proto = NULL}
69 static proto_cmd_client_t *findCmdProto(char *msg)
71 int len;
72 int i;
74 len = strlen(msg);
76 for (i = 0; proto_cmd_list[i].len != 0; i++) {
77 proto_cmd_client_t *thisCmd;
79 thisCmd = &proto_cmd_list[i];
81 if (len >= thisCmd->len &&
82 strncmp(msg, thisCmd->name, thisCmd->len) == 0) {
83 return thisCmd;
87 return NULL;
90 static int initUdpClient(char *ip, int port)
92 sock_server_udp = sock_udp_connect(ip, port);
94 if (sock_server_udp == NULL) {
95 return -1;
98 debug("Connected to game server [%s]:[%d]", ip, port);
100 return 0;
103 int client_init(char *ip, int port)
105 char name[STR_NAME_SIZE];
106 int ret;
108 listRecvMsg = list_new();
109 lastPing = timer_get_current_time();
110 lastPingServerAlive = timer_get_current_time();
112 #ifdef SUPPORT_TRAFFIC
113 lastTraffic = timer_get_current_time();
114 traffic_down = 0;
115 traffic_up = 0;
116 #endif /* SUPPORT_TRAFFIC */
118 clientRecvBuffer = buffer_new(CLIENT_BUFFER_LIMIT);
119 clientSendBuffer = buffer_new(CLIENT_BUFFER_LIMIT);
121 ret = initUdpClient(ip, port);
123 if (ret < 0) {
124 return -1;
127 public_server_get_setting_name_right(name);
128 proto_send_hello_client(name);
130 return 0;
133 static void errorWithServer()
135 error("Game server is not responding");
136 analyze_set_msg(_("Unable to connect to the game server"));
137 world_do_end();
140 void client_send(char *msg)
142 int ret;
144 assert(msg != NULL);
146 ret = -1;
148 if (isParamFlag("--send")) {
149 debug("Sending data: %s", msg);
152 #ifdef SUPPORT_TRAFFIC
153 traffic_up += strlen(msg);
154 #endif /* SUPPORT_TRAFFIC */
156 if (sock_server_udp != NULL) {
157 ret = sock_udp_write(sock_server_udp, sock_server_udp, msg, strlen(msg));
160 if (ret < 0) {
161 errorWithServer();
162 return;
166 static int server_eventSelect()
168 char buffer[STR_PROTO_SIZE];
169 int ret;
171 memset(buffer, 0, STR_PROTO_SIZE);
172 ret = -1;
174 if (sock_server_udp != NULL) {
175 ret = sock_udp_read(sock_server_udp, sock_server_udp, buffer, STR_PROTO_SIZE - 1);
178 if (ret < 0) {
179 errorWithServer();
180 return ret;
183 #ifdef SUPPORT_TRAFFIC
184 traffic_down += ret;
185 #endif /* SUPPORT_TRAFFIC */
187 list_add(listRecvMsg, strdup(buffer));
189 return ret;
192 static void client_eventWorkRecvList()
194 proto_cmd_client_t *protoCmd;
195 char *line;
196 int i;
198 /* processing of an event received from a game server */
200 assert(listRecvMsg != NULL);
202 for (i = 0; i < listRecvMsg->count; i++) {
203 line = (char *) listRecvMsg->list[i];
204 protoCmd = findCmdProto(line);
206 if (isParamFlag("--recv")) {
207 debug("Recieved data: %s", line);
210 if (protoCmd != NULL) {
211 protoCmd->fce_proto(line);
212 lastPingServerAlive = timer_get_current_time();
216 list_destroy_item(listRecvMsg, free);
217 listRecvMsg = list_new();
220 static void eventPingServer()
222 my_time_t currentTime;
224 currentTime = timer_get_current_time();
226 if (currentTime - lastPing > CLIENT_TIMEOUT) {
227 proto_send_ping_client();
228 lastPing = timer_get_current_time();
232 static bool_t isServerAlive()
234 my_time_t currentTime;
236 currentTime = timer_get_current_time();
238 if (currentTime - lastPingServerAlive > SERVER_TIMEOUT_ALIVE) {
239 return FALSE;
242 return TRUE;
245 static void selectClientSocket()
247 fd_set readfds;
248 struct timeval tv;
249 int max_fd;
250 int sock;
251 bool_t isNext;
253 max_fd = 0;
254 sock = 0;
256 if (sock_server_udp != NULL) {
257 if (isServerAlive() == FALSE) {
258 errorWithServer();
259 return;
263 do {
264 isNext = FALSE;
266 tv.tv_sec = 0;
267 tv.tv_usec = 0;
269 FD_ZERO(&readfds);
271 if (sock_server_udp != NULL) {
272 sock = sock_server_udp->sock;
275 FD_SET(sock, &readfds);
276 max_fd = sock;
277 select(max_fd + 1, &readfds, (fd_set *) NULL, (fd_set *) NULL, &tv);
279 if (FD_ISSET(sock, &readfds)) {
280 if (server_eventSelect() > 0) {
281 isNext = TRUE;
285 } while (isNext == TRUE);
288 #ifdef SUPPORT_TRAFFIC
289 static void eventTraffic()
291 my_time_t currentTime;
293 currentTime = timer_get_current_time();
295 if (currentTime - lastTraffic > 5000) {
296 lastTraffic = currentTime;
298 debug("Traffic: down [%d]/up [%d]", traffic_down, traffic_up);
300 traffic_down = 0;
301 traffic_up = 0;
304 #endif /* SUPPORT_TRAFFIC */
306 void client_event()
308 #ifdef SUPPORT_TRAFFIC
309 eventTraffic();
310 #endif /* SUPPORT_TRAFFIC */
312 eventPingServer();
313 selectClientSocket();
314 client_eventWorkRecvList();
317 static void quitUdpClient()
319 assert(sock_server_udp != NULL);
320 sock_udp_close(sock_server_udp);
322 debug("Closing connection to game server");
325 void client_quit()
327 proto_send_end_client();
329 assert(listRecvMsg != NULL);
331 list_destroy_item(listRecvMsg, free);
332 buffer_destroy(clientRecvBuffer);
333 buffer_destroy(clientSendBuffer);
335 if (sock_server_udp != NULL) {
336 quitUdpClient();