ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/socket/init.C
Revision: 1.3
Committed: Fri Aug 18 02:06:58 2006 UTC (17 years, 10 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.2: +2 -1 lines
Log Message:
support health stats in an extensible way in map1

File Contents

# User Rev Content
1 elmex 1.1 /*
2     * static char *rcsid_init_c =
3 root 1.3 * "$Id: init.C,v 1.2 2006-08-17 20:23:32 root Exp $";
4 elmex 1.1 */
5    
6     /*
7     CrossFire, A Multiplayer game for X-windows
8    
9     Copyright (C) 2001 Mark Wedel
10     Copyright (C) 1992 Frank Tore Johansen
11    
12     This program is free software; you can redistribute it and/or modify
13     it under the terms of the GNU General Public License as published by
14     the Free Software Foundation; either version 2 of the License, or
15     (at your option) any later version.
16    
17     This program is distributed in the hope that it will be useful,
18     but WITHOUT ANY WARRANTY; without even the implied warranty of
19     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20     GNU General Public License for more details.
21    
22     You should have received a copy of the GNU General Public License
23     along with this program; if not, write to the Free Software
24     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25    
26     The author can be reached via e-mail to crossfire-devel@real-time.com
27     */
28    
29     /**
30     * \file
31     * Socket general functions
32     *
33     * \date 2003-12-02
34     *
35     * Mainly deals with initialization and higher level socket
36     * maintenance (checking for lost connections and if data has arrived.)
37     * The reading of data is handled in ericserver.c
38     */
39    
40    
41     #include <global.h>
42     #ifndef __CEXTRACT__
43     #include <sproto.h>
44     #endif
45     #ifndef WIN32 /* ---win32 exclude include files */
46     #include <sys/types.h>
47     #include <sys/time.h>
48     #include <sys/socket.h>
49     #include <netinet/in.h>
50     #include <netdb.h>
51     #endif /* win32 */
52    
53     #ifdef HAVE_UNISTD_H
54     #include <unistd.h>
55     #endif
56    
57     #ifdef HAVE_ARPA_INET_H
58     #include <arpa/inet.h>
59     #endif
60     #include <newserver.h>
61    
62     Socket_Info socket_info;
63     NewSocket *init_sockets;
64    
65     /**
66     * Initializes a connection. Really, it just sets up the data structure,
67     * socket setup is handled elsewhere. We do send a version to the
68     * client.
69     */
70     void InitConnection(NewSocket *ns, const char *from_ip)
71     {
72     SockList sl;
73     char buf[256];
74     int bufsize=65535; /*Supposed absolute upper limit */
75     int oldbufsize;
76     int buflen=sizeof(int);
77    
78     #ifdef WIN32 /* ***WIN32 SOCKET: init win32 non blocking socket */
79     int temp = 1;
80    
81     if(ioctlsocket(ns->fd, FIONBIO , &temp) == -1)
82     LOG(llevError,"InitConnection: Error on ioctlsocket.\n");
83     #else
84     if (fcntl(ns->fd, F_SETFL, O_NONBLOCK)==-1) {
85     LOG(llevError,"InitConnection: Error on fcntl.\n");
86     }
87     #endif /* end win32 */
88    
89     if (getsockopt(ns->fd,SOL_SOCKET,SO_SNDBUF, (char*)&oldbufsize, (socklen_t*) &buflen)==-1)
90     oldbufsize=0;
91     if (oldbufsize<bufsize) {
92     #ifdef ESRV_DEBUG
93     LOG(llevDebug, "Default buffer size was %d bytes, will reset it to %d\n", oldbufsize, bufsize);
94     #endif
95     if(setsockopt(ns->fd,SOL_SOCKET,SO_SNDBUF, (char*)&bufsize, sizeof(&bufsize))) {
96     LOG(llevError,"InitConnection: setsockopt unable to set output buf size to %d\n", bufsize);
97     }
98     }
99     buflen=sizeof(oldbufsize);
100     getsockopt(ns->fd,SOL_SOCKET,SO_SNDBUF, (char*)&oldbufsize, (socklen_t*) &buflen);
101     #ifdef ESRV_DEBUG
102     LOG(llevDebug, "Socket buffer size now %d bytes\n", oldbufsize);
103     #endif
104    
105     ns->faceset = 0;
106     ns->facecache = 0;
107     ns->image2 = 0;
108     ns->sound = 0;
109     ns->exp64 = 0;
110     ns->monitor_spells = 0;
111     ns->mapmode = Map0Cmd;
112     ns->darkness = 1;
113     ns->status = Ns_Add;
114     ns->comment = NULL;
115     ns->old_mode = (Old_Mode) 0;
116     ns->mapx = 11;
117     ns->mapy = 11;
118     ns->newmapcmd= 0;
119     ns->itemcmd = 1; /* Default is version item1 command*/
120     ns->ext_mapinfos=0; /*extendedmapinfo datas*/
121     ns->EMI_smooth=0;
122     ns->look_position = 0;
123     ns->update_look = 0;
124     ns->has_readable_type = 0;
125     ns->supported_readables = 0;
126     ns->monitor_spells = 0;
127     ns->mapinfocmd = 0;
128     ns->extcmd = 0;
129 root 1.3 ns->extmap = 0;
130 elmex 1.1
131     /* we should really do some checking here - if total clients overflows
132     * we need to do something more intelligent, because client id's will start
133     * duplicating (not likely in normal cases, but malicous attacks that
134     * just open and close connections could get this total up.
135     */
136     ns->inbuf.len=0;
137     ns->inbuf.buf= (unsigned char*) malloc( sizeof( unsigned char ) * MAXSOCKBUF );
138     /* Basic initialization. Needed because we do a check in
139     * HandleClient for oldsocketmode without checking the
140     * length of data.
141     */
142     memset( ns->inbuf.buf, 0, sizeof( unsigned char ) * MAXSOCKBUF );
143     memset(&ns->lastmap,0,sizeof(struct Map));
144     memset(ns->faces_sent, 0, ns->faces_sent_len*sizeof(*ns->faces_sent));
145     memset(&ns->anims_sent,0,sizeof(ns->anims_sent));
146     memset(&ns->stats,0,sizeof(struct statsinfo));
147     /* Do this so we don't send a face command for the client for
148     * this face. Face 0 is sent to the client to say clear
149     * face information.
150     */
151     ns->faces_sent[0] = NS_FACESENT_FACE;
152    
153     ns->outputbuffer.start=0;
154     ns->outputbuffer.len=0;
155     ns->can_write=1;
156     ns->password_fails = 0;
157    
158     ns->current_map = 0;
159 root 1.2 ns->current_x = 0;
160     ns->current_y = 0;
161 elmex 1.1
162     ns->sent_scroll=0;
163     ns->host=strdup_local(from_ip);
164     sprintf((char*)buf, "version %d %d %s\n", VERSION_CS,VERSION_SC, VERSION_INFO);
165     sl.buf=(unsigned char*)buf;
166     sl.len=strlen((char*)buf);
167     Send_With_Handling(ns, &sl);
168     #ifdef CS_LOGSTATS
169     if (socket_info.nconns>cst_tot.max_conn)
170     cst_tot.max_conn = socket_info.nconns;
171     if (socket_info.nconns>cst_lst.max_conn)
172     cst_lst.max_conn = socket_info.nconns;
173     #endif
174     }
175    
176    
177     /** This sets up the socket and reads all the image information into memory. */
178     void init_ericserver(void)
179     {
180     struct sockaddr_in insock;
181     struct protoent *protox;
182     struct linger linger_opt;
183    
184     #ifdef WIN32 /* ***win32 - we init a windows socket */
185     WSADATA w;
186    
187     socket_info.max_filedescriptor = 1; /* used in select, ignored in winsockets */
188     WSAStartup (0x0101,&w); /* this setup all socket stuff */
189     /* ill include no error tests here, winsocket 1.1 should always work */
190     /* except some old win95 versions without tcp/ip stack */
191     #else /* non windows */
192    
193     #ifdef HAVE_SYSCONF
194     socket_info.max_filedescriptor = sysconf(_SC_OPEN_MAX);
195     #else
196     # ifdef HAVE_GETDTABLESIZE
197     socket_info.max_filedescriptor = getdtablesize();
198     # else
199     "Unable to find usable function to get max filedescriptors";
200     # endif
201     #endif
202     #endif /* win32 */
203    
204     socket_info.timeout.tv_sec = 0;
205     socket_info.timeout.tv_usec = 0;
206     socket_info.nconns=0;
207    
208     #ifdef CS_LOGSTATS
209     memset(&cst_tot, 0, sizeof(CS_Stats));
210     memset(&cst_lst, 0, sizeof(CS_Stats));
211     cst_tot.time_start=time(NULL);
212     cst_lst.time_start=time(NULL);
213     #endif
214    
215     LOG(llevDebug,"Initialize new client/server data\n");
216     socket_info.nconns = 1;
217     init_sockets = (NewSocket *) malloc(sizeof(NewSocket));
218     init_sockets[0].faces_sent = NULL; /* unused */
219     socket_info.allocated_sockets=1;
220    
221     protox = getprotobyname("tcp");
222     if (protox==NULL) {
223     LOG(llevError,"init_ericserver: Error getting protox\n");
224     return;
225     }
226     init_sockets[0].fd = socket(PF_INET, SOCK_STREAM, protox->p_proto);
227     if (init_sockets[0].fd == -1) {
228     LOG(llevError, "Cannot create socket: %s\n", strerror_local(errno));
229     exit(-1);
230     }
231     insock.sin_family = AF_INET;
232     insock.sin_port = htons(settings.csport);
233     insock.sin_addr.s_addr = htonl(INADDR_ANY);
234    
235     linger_opt.l_onoff = 0;
236     linger_opt.l_linger = 0;
237     if(setsockopt(init_sockets[0].fd,SOL_SOCKET,SO_LINGER,(char *) &linger_opt,
238     sizeof(struct linger))) {
239     LOG(llevError, "Cannot setsockopt(SO_LINGER): %s\n", strerror_local(errno));
240     }
241     /* Would be nice to have an autoconf check for this. It appears that
242     * these functions are both using the same calling syntax, just one
243     * of them needs extra valus passed.
244     */
245     #if defined(__osf__) || defined(hpux) || defined(sgi) || defined(NeXT) || \
246     defined(__sun__) || defined(__linux__) || defined(SVR4) || \
247     defined(__FreeBSD__) || defined(__OpenBSD__) || \
248     defined(WIN32) /* ---win32 add this here */ || \
249     defined(__GNU__) /* HURD */
250     {
251     #ifdef WIN32
252     char tmp = 1;
253     #else
254     int tmp =1;
255     #endif
256    
257     if(setsockopt(init_sockets[0].fd,SOL_SOCKET,SO_REUSEADDR, &tmp, sizeof(tmp))) {
258     LOG(llevError, "Cannot setsockopt(SO_REUSEADDR): %s\n", strerror_local(errno));
259     }
260     }
261     #else
262     if(setsockopt(init_sockets[0].fd,SOL_SOCKET,SO_REUSEADDR,(char *)NULL,0)) {
263     LOG(llevError, "Cannot setsockopt(SO_REUSEADDR): %s\n", strerror_local(errno));
264     }
265     #endif
266    
267     if (bind(init_sockets[0].fd,(struct sockaddr *)&insock,sizeof(insock)) == (-1)) {
268     LOG(llevError, "Cannot bind socket to port %d: %s\n", ntohs(insock.sin_port), strerror_local(errno));
269     #ifdef WIN32 /* ***win32: close() -> closesocket() */
270     shutdown(init_sockets[0].fd,SD_BOTH);
271     closesocket(init_sockets[0].fd);
272     #else
273     close(init_sockets[0].fd);
274     #endif /* win32 */
275     exit(-1);
276     }
277     if (listen(init_sockets[0].fd,5) == (-1)) {
278     LOG(llevError, "Cannot listen on socket: %s\n", strerror_local(errno));
279     #ifdef WIN32 /* ***win32: close() -> closesocket() */
280     shutdown(init_sockets[0].fd,SD_BOTH);
281     closesocket(init_sockets[0].fd);
282     #else
283     close(init_sockets[0].fd);
284     #endif /* win32 */
285     exit(-1);
286     }
287     init_sockets[0].status=Ns_Add;
288     read_client_images();
289     }
290    
291    
292     /*******************************************************************************
293     *
294     * Start of functions dealing with freeing of the data.
295     *
296     ******************************************************************************/
297    
298     /** Free's all the memory that ericserver allocates. */
299     void free_all_newserver(void)
300     {
301     LOG(llevDebug,"Freeing all new client/server information.\n");
302     free_socket_images();
303     free(init_sockets);
304     }
305    
306     /**
307     * Frees a socket.
308     * Basically, all we need to do here is free all data structures that
309     * might be associated with the socket. It is up to the caller to
310     * update the list
311     */
312    
313     void free_newsocket(NewSocket *ns)
314     {
315     #ifdef WIN32 /* ***win32: closesocket in windows style */
316     shutdown(ns->fd,SD_BOTH);
317     if (closesocket(ns->fd)) {
318     #else
319     if (close(ns->fd)) {
320     #endif /* win32 */
321    
322     #ifdef ESRV_DEBUG
323     LOG(llevDebug,"Error closing socket %d\n", ns->fd);
324     #endif
325     }
326     if (ns->stats.range)
327     free(ns->stats.range);
328     if (ns->stats.title)
329     free(ns->stats.title);
330     if (ns->comment)
331     free(ns->comment);
332     free(ns->host);
333     free(ns->inbuf.buf);
334     }
335    
336     /** Sends the 'goodbye' command to the player, and closes connection. */
337     void final_free_player(player *pl)
338     {
339     cs_write_string(&pl->socket, "goodbye", 8);
340     free_newsocket(&pl->socket);
341     free_player(pl);
342     }
343