home *** CD-ROM | disk | FTP | other *** search
- /**********************************************************************
- Freeciv - Copyright (C) 1996 - A Kjeldberg, L Gregersen, P Unold
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- ***********************************************************************/
- #include <stdio.h>
- #include <stdlib.h>
-
- #include <sys/signal.h>
- #include <sys/types.h>
- #include <time.h>
- #include <sys/time.h>
- #include <unistd.h>
- #include <errno.h>
- #include <pwd.h>
- #include <string.h>
-
- #if defined(AIX) || defined(__EMX__)
- #include <sys/select.h>
- #endif
-
- #include <signal.h>
-
- #include <sys/socket.h>
- #include <netdb.h>
- #include <sys/uio.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
-
- #include <log.h>
- #include <sernet.h>
- #include <shared.h>
- #include <civserver.h>
- #include <packets.h>
-
- #define MY_FD_ZERO(p) memset((void *)(p), 0, sizeof(*(p)))
-
- struct connection connections[MAX_CONNECTIONS];
- int no_active_connections;
- int sock;
- extern int errno;
- extern int port;
- extern int force_end_of_sniff;
-
- extern enum server_states server_state;
-
-
-
- /*****************************************************************************/
- void close_connection(struct connection *pconn)
- {
- close(pconn->sock);
- pconn->used=0;
- }
-
- /*****************************************************************************/
- void close_connections_and_socket(void)
- {
- int i;
- for(i=0; i<MAX_CONNECTIONS; i++)
- if(connections[i].used) {
- close(connections[i].sock);
- connections[i].used=0;
- close(sock);
- }
- }
-
- /*****************************************************************************/
- int sniff_packets(void)
- {
- int i;
- int max_desc;
- fd_set readfs;
- struct timeval tv;
- static time_t time_at_turn_end;
- static int year;
-
- if(year!=game.year) {
- time_at_turn_end = time(NULL) + game.timeout;
- year=game.year;
- }
-
- while(1) {
- if(force_end_of_sniff) {
- force_end_of_sniff=0;
- return 2;
- }
-
- tv.tv_sec=1; tv.tv_usec=0;
-
- MY_FD_ZERO(&readfs);
- FD_SET(0, &readfs);
- FD_SET(sock, &readfs);
- max_desc=sock;
-
- for(i=0; i<MAX_CONNECTIONS; i++) {
- if(connections[i].used) {
- FD_SET(connections[i].sock, &readfs);
- }
- max_desc=MAX(connections[i].sock, max_desc);
- }
-
- if(select(max_desc+1, &readfs, NULL, NULL, &tv)==0) { /* timeout */
- send_server_info_to_metaserver(0);
- if(game.timeout && time(NULL)>time_at_turn_end) {
- return 0;
- }
- continue;
- }
-
- if(FD_ISSET(sock, &readfs)) { /* new players connects */
- log(LOG_DEBUG, "got new connection");
- if(server_accept_connection(sock)==-1)
- log(LOG_NORMAL, "failed accepting connection");
- }
- else if(FD_ISSET(0, &readfs)) { /* input from server operator */
- int didget;
- char buf[BUF_SIZE+1];
-
- if((didget=read(0, buf, BUF_SIZE))==-1) {
- log(LOG_FATAL, "read from stdin failed");
- exit(1);
- }
- *(buf+didget)='\0';
- handle_stdin_input(buf);
- }
- else { /* input from a player */
- for(i=0; i<MAX_CONNECTIONS; i++)
- if(connections[i].used && FD_ISSET(connections[i].sock, &readfs)) {
- if(read_socket_data(connections[i].sock,
- &connections[i].buffer)>0) {
- char *packet;
- int type;
- while((packet=get_packet_from_connection(&connections[i], &type)))
- handle_packet_input(&connections[i], packet, type);
- }
- else {
- lost_connection_to_player(&connections[i]);
- connections[i].used=0;
- close(connections[i].sock);
-
- }
- }
- }
- break;
- }
- if(game.timeout && time(NULL)>time_at_turn_end) return 0;
- return 1;
- }
-
-
- /********************************************************************
- server accepts connections from client
- ********************************************************************/
- int server_accept_connection(int sockfd)
- {
- int fromlen;
- int new_sock;
- struct sockaddr_in fromend;
- struct hostent *from;
-
- fromlen = sizeof fromend;
-
- new_sock = accept(sockfd, (struct sockaddr *) &fromend, &fromlen);
-
- from=gethostbyaddr((char*)&fromend.sin_addr, sizeof(sizeof(fromend.sin_addr)),
- AF_INET);
-
- if(new_sock!=-1) {
- int i;
- for(i=0; i<MAX_CONNECTIONS; i++)
- if(!connections[i].used) {
- connections[i].used=1;
- connections[i].sock=new_sock;
- connections[i].player=NULL;
- connections[i].buffer.ndata=0;
-
- if(from) {
- strncpy(connections[i].addr, from->h_name, ADDR_LENGTH);
- connections[i].addr[ADDR_LENGTH-1]='\0';
- }
- else
- strcpy(connections[i].addr, "unknown");
-
- return 0;
- }
- log(LOG_FATAL, "maximum number of connections reached");
- return -1;
- }
-
- return -1;
- }
-
-
-
- /********************************************************************
- open server socket to be used to accept client connections
- ********************************************************************/
- int server_open_socket(void)
- {
- /* setup socket address */
- struct sockaddr_in src;
- int opt;
-
- src.sin_addr.s_addr = INADDR_ANY;
- src.sin_family = AF_INET;
- src.sin_port = htons(port);
-
-
- /* broken pipes are ignored. */
- signal (SIGPIPE, SIG_IGN);
-
- if((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
- log(LOG_FATAL, "socket failed: %s", strerror(errno));
- exit(1);
- }
-
- opt=1;
- if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
- (char*)&opt, sizeof(opt))) {
- /* (const char*)&opt, sizeof(opt))) { gave me warnings -- Syela */
- log(LOG_FATAL, "setsockopt failed: %s", strerror(errno));
- }
-
- if(bind(sock, (struct sockaddr *) &src, sizeof (src)) < 0) {
- log(LOG_FATAL, "bind failed: %s", strerror(errno));
- exit(1);
- }
-
- if(listen(sock, MAX_CONNECTIONS) < 0) {
- log(LOG_FATAL, "listen failed: %s", strerror(errno));
- exit(1);
- }
-
- return 0;
- }
-
-
- /********************************************************************
- ...
- ********************************************************************/
- void init_connections(void)
- {
- int i;
- for(i=0; i<MAX_CONNECTIONS; i++) {
- connections[i].used=0;
- connections[i].buffer.ndata=0;
- }
- no_active_connections=0;
- }
-