source: abuse/trunk/src/net/gserver.cpp @ 2

Last change on this file since 2 was 2, checked in by Sam Hocevar, 14 years ago
  • imported original 0.7.0 tarball
File size: 10.9 KB
Line 
1#include "system.h"
2#include "macs.hpp"
3#include "gserver.hpp"
4#include "netface.hpp"
5#include "timing.hpp"
6#include "netcfg.hpp"
7#include "id.hpp"
8#include "jwindow.hpp"
9#include "input.hpp"
10
11extern base_memory_struct *base;
12extern net_socket *comm_sock,*game_sock;
13extern int registered;
14
15extern net_protocol *prot;
16extern join_struct *join_array;
17extern window_manager *eh;
18extern char *symbol_str(char *name);
19extern void service_net_request();
20
21#include <stdio.h>
22#include <stdlib.h>
23#include <fcntl.h>
24#include <unistd.h>
25#include <sys/stat.h>
26#include <sys/types.h>
27#include <string.h>
28#include <signal.h>
29
30
31game_server::game_server()
32{
33        player_list = NULL;
34        waiting_server_input = 1;
35        reload_state = 0;
36}
37
38int game_server::total_players()
39{
40        player_client *fl = player_list;
41        int total = 1;
42        for( ; fl; fl = fl->next)
43        {
44                total++;
45        }
46        return total;
47}
48
49void game_server::game_start_wait()
50{
51  int last_count=0;
52  jwindow *stat=NULL;
53  event ev;
54  int abort=0;
55  while (!abort && total_players()<main_net_cfg->min_players)
56  {
57    if (last_count!=total_players())
58    {
59      if (stat) eh->close_window(stat);
60      char msg[100];
61      sprintf(msg,symbol_str("min_wait"),main_net_cfg->min_players-total_players());
62      stat=eh->new_window(100,50,-1,-1,new info_field(WINDOW_FRAME_LEFT,WINDOW_FRAME_TOP,ID_NULL,msg,
63                                       new button(WINDOW_FRAME_LEFT,WINDOW_FRAME_TOP+eh->font()->height()*2,
64                                                  ID_CANCEL,symbol_str("cancel_button"),NULL)  ));
65      eh->flush_screen();
66      last_count=total_players();
67    }
68
69    if (eh->event_waiting())
70    {
71      do { eh->get_event(ev); }  while (ev.type==EV_MOUSE_MOVE && eh->event_waiting());
72      eh->flush_screen();
73      if (ev.type==EV_MESSAGE && ev.message.id==ID_CANCEL)
74        abort=1;
75    }
76   
77    service_net_request();
78  }
79  if (stat)
80  {
81    eh->close_window(stat);
82    eh->flush_screen(); 
83  }
84}
85 
86game_server::player_client::~player_client()
87{
88  delete comm;
89  delete data_address;
90}
91
92void game_server::check_collection_complete()
93{
94  player_client *c;
95  int got_all=waiting_server_input==0;
96  int add_deletes=0;
97  for (c=player_list;c && got_all;c=c->next)
98  {
99    if (c->delete_me())
100      add_deletes=1;
101    else if (c->has_joined() && c->wait_input())
102      got_all=0;
103  }
104
105  if (add_deletes)
106  {
107    player_client *last=NULL;
108    for (c=player_list;c;)
109    {
110      if (c->delete_me())
111      {
112        base->packet.write_byte(SCMD_DELETE_CLIENT);
113        base->packet.write_byte(c->client_id);
114        if (c->wait_reload())
115        {
116          c->set_wait_reload(0);
117          check_reload_wait();
118        }
119
120        if (last) last->next=c->next;
121        else player_list=c->next;
122        player_client *d=c;
123        c=c->next;
124        delete d;
125      } else
126      {
127        last=c;
128        c=c->next;
129      }
130    }
131  }
132
133  if (got_all)    // see if we have input from everyone, if so send it out
134  {   
135    base->packet.calc_checksum();
136
137    for (c=player_list;c;c=c->next)      // setup for next time, wait for all the input
138    {
139      if (c->has_joined())
140      {
141        c->set_wait_input(1);     
142        game_sock->write(base->packet.data,base->packet.packet_size()+base->packet.packet_prefix_size(),c->data_address);
143
144      }
145    }
146
147    base->input_state=INPUT_PROCESSING; // tell engine to start processing
148    game_sock->read_unselectable();    // don't listen to this socket until we are prepared to read next tick's game data
149    waiting_server_input=1;
150  } 
151}
152
153void game_server::add_engine_input()
154{
155  waiting_server_input=0;
156  base->input_state=INPUT_COLLECTING;
157  base->packet.set_tick_received(base->current_tick);
158  game_sock->read_selectable();    // we can listen for game data now that we have server input
159  check_collection_complete();
160}
161
162void game_server::add_client_input(char *buf, int size, player_client *c)
163{
164  if (c->wait_input())  // don't add if we already have it
165  {
166    base->packet.add_to_packet(buf,size);
167    c->set_wait_input(0);
168    check_collection_complete();
169  }
170}
171
172void game_server::check_reload_wait()
173{
174  player_client *d=player_list;
175  for (;d;d=d->next)
176   if (d->wait_reload()) return ;    // we are still waiting for someone to reload the game
177  base->wait_reload=0;
178}
179
180int game_server::process_client_command(player_client *c)
181{
182  uchar cmd;
183  if (c->comm->read(&cmd,1)!=1) return 0;
184  switch (cmd)
185  {
186    case CLCMD_REQUEST_RESEND :
187    {
188      uchar tick;
189      if (c->comm->read(&tick,1)!=1) return 0;
190
191      fprintf(stderr,"request for resend tick %d (game cur=%d, pack=%d, last=%d)\n",
192              tick,base->current_tick,base->packet.tick_received(),base->last_packet.tick_received());
193
194      if (tick==base->last_packet.tick_received())
195      {
196        net_packet *pack=&base->last_packet;     
197        game_sock->write(pack->data,pack->packet_size()+pack->packet_prefix_size(),c->data_address);
198      }
199      return 1;
200    } break;
201    case CLCMD_RELOAD_START :
202    {
203      if (reload_state)   // already in reload state, notify client ok to start reloading
204      {
205        if (c->comm->write(&cmd,1)!=1)
206          c->set_delete_me(1);
207      } else c->set_need_reload_start_ok(1);
208      return 1;
209    } break;
210
211    case CLCMD_RELOAD_END :
212    {
213      c->set_wait_reload(0);
214      return 1;
215    } break;
216    case CLCMD_UNJOIN :
217    {
218      c->comm->write(&cmd,1);        // don't care weither this works or not
219      c->set_delete_me(1);
220      if (base->input_state==INPUT_COLLECTING)
221        check_collection_complete();
222    } break;
223  }
224  return 0;
225}
226
227
228int game_server::process_net()
229{
230  int ret=0;
231  /**************************       Any game data waiting?       **************************/
232  if ((base->input_state==INPUT_COLLECTING ||
233       base->input_state==INPUT_RELOAD)
234       && game_sock->ready_to_read())
235  {
236    net_packet tmp;
237    net_packet *use=&tmp;
238    net_address *from;
239    int bytes_received=game_sock->read(use->data,PACKET_MAX_SIZE,&from);
240
241    if (from && bytes_received)
242    {
243      // make sure we got a complete packet and the packet was not a previous game tick packet
244      if (bytes_received==use->packet_size()+use->packet_prefix_size())
245      {
246        unsigned short rec_crc=use->get_checksum();
247        if (rec_crc==use->calc_checksum())
248        {
249          player_client *f=player_list,*found=NULL;
250          for (;!found &&f;f=f->next)
251          if (f->has_joined() && from->equal(f->data_address))
252            found=f;
253          if (found)
254          {
255            if (base->current_tick==use->tick_received())           
256            {
257              if (prot->debug_level(net_protocol::DB_MINOR_EVENT))
258                fprintf(stderr,"(got data from %d)",found->client_id);
259
260//            fprintf(stderr,"(got packet %d)\n",use->tick_received());
261//            { time_marker now,start; while (now.diff_time(&start)<5.0) now.get_time(); }
262
263              if (base->input_state!=INPUT_RELOAD)
264                add_client_input((char *)use->packet_data(),use->packet_size(),found);
265
266            }
267            else if (use->tick_received()==base->last_packet.tick_received())
268            {
269              if (prot->debug_level(net_protocol::DB_IMPORTANT_EVENT))
270                fprintf(stderr,"(sending old %d)\n",use->tick_received());           
271
272              // if they are sending stale data we need to send them the last packet so they can catchup
273              net_packet *pack=&base->last_packet;     
274              game_sock->write(pack->data,pack->packet_size()+pack->packet_prefix_size(),found->data_address);
275
276            } else if (prot->debug_level(net_protocol::DB_MAJOR_EVENT))
277              fprintf(stderr,"received stale packet (got %d, expected %d)\n",use->tick_received(),base->current_tick);
278
279          } else
280          {
281            if (prot->debug_level(net_protocol::DB_MAJOR_EVENT))
282            {
283              fprintf(stderr,"received data from unknown client\n");
284              printf("from address "); from->print();
285              printf(" first addr "); player_list->data_address->print(); printf("\n");
286            }
287          }
288
289        } else fprintf(stderr,"received packet with bad checksum\n");
290      } else fprintf(stderr,"received incomplete packet\n");
291    } else if (!from)
292      fprintf(stderr,"received data and no from\n");
293    else if (!bytes_received)
294      fprintf(stderr,"received 0 byte data\n");
295    ret=1;
296    if (from) delete from;
297
298  }
299
300
301  /**************************       Any client with commands?       **************************/
302  player_client *c;
303  for (c=player_list;c;c=c->next) 
304    if (c->comm->error() || (c->comm->ready_to_read() && !process_client_command(c)))
305    {
306      c->set_delete_me(1);
307      check_collection_complete();
308    }
309    else ret=1;
310 
311  return 1;
312}
313
314
315int game_server::input_missing()
316{
317
318  return 1;
319}
320
321
322
323int game_server::end_reload(int disconnect)  // notify evryone you've reloaded the level (at server request)
324
325  player_client *c=player_list;
326  prot->select(0);
327
328  for (;c;c=c->next)
329    if (!c->delete_me() && c->wait_reload())
330    {
331      if (disconnect)
332        c->set_delete_me(1);
333      else return 0;
334    }
335
336  for (c=player_list;c;c=c->next)   
337    c->set_has_joined(1);
338  reload_state=0;
339 
340  return 1;
341}
342
343int game_server::start_reload()
344{
345  player_client *c=player_list;
346  reload_state=1;
347  prot->select(0);
348
349  for (;c;c=c->next)
350  {
351    if (!c->delete_me() && c->need_reload_start_ok())    // if the client is already waiting for reload state to start, send ok
352    {
353      uchar cmd=CLCMD_RELOAD_START;
354      if (c->comm->write(&cmd,1)!=1) { c->set_delete_me(1); }
355      c->set_need_reload_start_ok(0);
356    }
357    c->set_wait_reload(1);
358  }
359  return 1;
360}
361
362
363int game_server::isa_client(int client_id)
364{
365  player_client *c=player_list;
366  if (!client_id) return 1;
367  for (;c;c=c->next) if (c->client_id==client_id) return 1;
368  return 0;   
369}
370
371int game_server::add_client(int type, net_socket *sock, net_address *from)
372{
373        if( type == CLIENT_ABUSE )
374        {
375                if( total_players() >= main_net_cfg->max_players )
376                {
377                        uchar too_many = 2;
378                        sock->write( &too_many, 1 );
379                        return 0;
380                }
381
382                uchar reg = registered ? 1 : 0;
383                if( sock->write( &reg, 1 ) != 1 )
384                        return 0;
385
386                ushort our_port = lstl( main_net_cfg->port + 1 ), cport;
387                char name[256];
388                uchar len;
389                short nkills=lstl(main_net_cfg->kills);
390
391                if( sock->read(&len,1)!=1 ||
392                        sock->read(name,len)!=len ||
393                        sock->read(&cport,2)!=2 ||
394                        sock->write(&our_port,2)!=2 ||
395                        sock->write(&nkills,2)!=2)
396                {
397                        return 0;
398                }
399
400                cport=lstl(cport);
401
402                int f = -1, i;
403                for( i = 0; f == -1 && i < MAX_JOINERS; i++ )
404                {
405                        if( !isa_client(i) )
406                        {
407                                f = i;
408                                join_struct *j=base->join_list;
409                                for( ; j; j = j->next )
410                                {
411                                        if( j->client_id == i )
412                                                f = -1;
413                                }
414                        }
415                }
416
417                if( f == -1 )
418                        return 0;
419
420                from->set_port( cport );
421
422                ushort client_id = lstl( f );
423                if( sock->write( &client_id, 2 ) != 2 )
424                {
425                        return 0;
426                }
427                client_id=f;
428
429                join_array[client_id].next = base->join_list;
430                base->join_list = &join_array[client_id];
431                join_array[client_id].client_id = client_id;
432                strcpy( join_array[client_id].name, name );
433                player_list = new player_client( f, sock, from, player_list );
434
435                return 1;
436        }
437        else
438        {
439                return 0;
440        }
441}
442
443int game_server::kill_slackers()
444{
445  player_client *c=player_list;
446  for (;c;c=c->next)
447    if (c->wait_input())
448      c->set_delete_me(1);
449  check_collection_complete(); 
450  return 1;
451}
452
453int game_server::quit()
454{
455  player_client *c=player_list;
456  while (c)
457  {
458    player_client *d=c;
459    c=c->next;
460    delete c;
461  }
462  player_list=NULL;
463  return 1;
464}
465
466
467game_server::~game_server()
468{
469        quit();
470}
471
Note: See TracBrowser for help on using the repository browser.