1 | |
1 | |
2 | /* |
2 | /* |
3 | * static char *rcsid_loop_c = |
3 | * static char *rcsid_loop_c = |
4 | * "$Id: loop.C,v 1.4 2006/08/30 16:30:37 root Exp $"; |
4 | * "$Id: loop.C,v 1.5 2006/09/09 21:48:29 root Exp $"; |
5 | */ |
5 | */ |
6 | |
6 | |
7 | /* |
7 | /* |
8 | CrossFire, A Multiplayer game for X-windows |
8 | CrossFire, A Multiplayer game for X-windows |
9 | |
9 | |
… | |
… | |
169 | else if (!strcmp(buf,"spell_paths")) send_spell_paths(ns, params); |
169 | else if (!strcmp(buf,"spell_paths")) send_spell_paths(ns, params); |
170 | else Write_String_To_Socket(ns, bigbuf, len); |
170 | else Write_String_To_Socket(ns, bigbuf, len); |
171 | } |
171 | } |
172 | |
172 | |
173 | /** |
173 | /** |
174 | * Handles old socket format. |
|
|
175 | */ |
|
|
176 | void Handle_Oldsocket(NewSocket *ns) |
|
|
177 | { |
|
|
178 | int stat,i; |
|
|
179 | CommFunc command; |
|
|
180 | char buf[MAX_BUF],*cp; |
|
|
181 | object ob; |
|
|
182 | player pl; |
|
|
183 | |
|
|
184 | /* This is not the most efficient block, but keeps the code simpler - |
|
|
185 | * we basically read a byte at a time until we get a newline, error, |
|
|
186 | * or no more characters to read. |
|
|
187 | */ |
|
|
188 | do { |
|
|
189 | /* hack to disable old socket mode without creating too many conflicts */ |
|
|
190 | if (1 || ns->inbuf.len >= MAXSOCKBUF-1) { |
|
|
191 | ns->status = Ns_Dead; |
|
|
192 | LOG(llevDebug, "Old input socket sent too much data without newline\n"); |
|
|
193 | return; |
|
|
194 | } |
|
|
195 | #ifdef WIN32 /* ***win32: change oldsocket read() to recv() */ |
|
|
196 | stat = recv(ns->fd, ns->inbuf.buf + ns->inbuf.len, 1,0); |
|
|
197 | |
|
|
198 | if (stat==-1 && WSAGetLastError() !=WSAEWOULDBLOCK) { |
|
|
199 | #else |
|
|
200 | do { |
|
|
201 | stat = read(ns->fd, ns->inbuf.buf + ns->inbuf.len, 1); |
|
|
202 | } while ((stat<0) && (errno == EINTR)); |
|
|
203 | |
|
|
204 | if (stat<0 && errno != EAGAIN && errno !=EWOULDBLOCK) { |
|
|
205 | #endif |
|
|
206 | LOG(llevError, "Cannot read from socket: %s\n", strerror(errno)); |
|
|
207 | ns->status = Ns_Dead; |
|
|
208 | return; |
|
|
209 | } |
|
|
210 | if (stat == 0) return; |
|
|
211 | } while (ns->inbuf.buf[ns->inbuf.len++]!='\n'); |
|
|
212 | |
|
|
213 | ns->inbuf.buf[ns->inbuf.len]=0; |
|
|
214 | |
|
|
215 | cp = strchr((const char*)ns->inbuf.buf, ' '); |
|
|
216 | if (cp) { |
|
|
217 | /* Replace the space with a null, skip any more spaces */ |
|
|
218 | *cp++=0; |
|
|
219 | while (isspace(*cp)) cp++; |
|
|
220 | } |
|
|
221 | |
|
|
222 | /* Strip off all spaces and control characters from end of line */ |
|
|
223 | for (i=ns->inbuf.len-1; i>=0; i--) { |
|
|
224 | if (ns->inbuf.buf[i]<=32) ns->inbuf.buf[i]=0; |
|
|
225 | else break; |
|
|
226 | } |
|
|
227 | ns->inbuf.len=0; /* reset for next read */ |
|
|
228 | |
|
|
229 | /* If just a return, don't do anything */ |
|
|
230 | if (ns->inbuf.buf[0] == 0) return; |
|
|
231 | if (!strcasecmp((const char*)ns->inbuf.buf,"quit")) { |
|
|
232 | ns->status = Ns_Dead; |
|
|
233 | return; |
|
|
234 | } |
|
|
235 | if (!strcasecmp((const char*)ns->inbuf.buf, "listen")) { |
|
|
236 | if (cp) { |
|
|
237 | char *buf="Socket switched to listen mode\n"; |
|
|
238 | |
|
|
239 | free(ns->comment); |
|
|
240 | ns->comment = strdup_local(cp); |
|
|
241 | ns->old_mode = Old_Listen; |
|
|
242 | cs_write_string(ns, buf, strlen(buf)); |
|
|
243 | } else { |
|
|
244 | char *buf="Need to supply a comment/url to listen\n"; |
|
|
245 | cs_write_string(ns, buf, strlen(buf)); |
|
|
246 | } |
|
|
247 | return; |
|
|
248 | } |
|
|
249 | if (!strcasecmp((const char*)ns->inbuf.buf, "name")) { |
|
|
250 | char *cp1=NULL; |
|
|
251 | if (cp) cp1= strchr(cp, ' '); |
|
|
252 | if (cp1) { |
|
|
253 | *cp1++ = 0; |
|
|
254 | while (isspace(*cp1)) cp1++; |
|
|
255 | } |
|
|
256 | if (!cp || !cp1) { |
|
|
257 | char *buf="Need to provide a name/password to name\n"; |
|
|
258 | cs_write_string(ns, buf, strlen(buf)); |
|
|
259 | return; |
|
|
260 | } |
|
|
261 | |
|
|
262 | if (verify_player(cp, cp1)==0) { |
|
|
263 | char *buf="Welcome back\n"; |
|
|
264 | free(ns->comment); |
|
|
265 | ns->comment = strdup_local(cp); |
|
|
266 | ns->old_mode = Old_Player; |
|
|
267 | cs_write_string(ns, buf, strlen(buf)); |
|
|
268 | } |
|
|
269 | else if (verify_player(cp, cp1)==2) { |
|
|
270 | ns->password_fails++; |
|
|
271 | if (ns->password_fails >= MAX_PASSWORD_FAILURES) { |
|
|
272 | char *buf="You failed to log in too many times, you will now be kicked.\n"; |
|
|
273 | LOG(llevInfo, "A player connecting from %s in oldsocketmode has been dropped for password failure\n", |
|
|
274 | ns->host); |
|
|
275 | cs_write_string(ns, buf, strlen(buf)); |
|
|
276 | ns->status = Ns_Dead; |
|
|
277 | } |
|
|
278 | else { |
|
|
279 | char *buf="Could not login you in. Check your name and password.\n"; |
|
|
280 | cs_write_string(ns, buf, strlen(buf)); |
|
|
281 | } |
|
|
282 | } |
|
|
283 | else { |
|
|
284 | char *buf="Could not login you in. Check your name and password.\n"; |
|
|
285 | cs_write_string(ns, buf, strlen(buf)); |
|
|
286 | } |
|
|
287 | return; |
|
|
288 | } |
|
|
289 | |
|
|
290 | command = find_oldsocket_command((char*)ns->inbuf.buf); |
|
|
291 | if (!command && ns->old_mode==Old_Player) { |
|
|
292 | command = find_oldsocket_command2((char*)ns->inbuf.buf); |
|
|
293 | } |
|
|
294 | if (!command) { |
|
|
295 | snprintf(buf, sizeof(buf), "Could not find command: %s\n", ns->inbuf.buf); |
|
|
296 | cs_write_string(ns, buf, strlen(buf)); |
|
|
297 | return; |
|
|
298 | } |
|
|
299 | |
|
|
300 | /* This is a bit of a hack, but works. Basically, we make some |
|
|
301 | * fake object and player pointers and give at it. |
|
|
302 | * This works as long as the functions we are calling don't need |
|
|
303 | * to do anything to the object structure (ie, they are only |
|
|
304 | * outputting information and not actually updating anything much.) |
|
|
305 | */ |
|
|
306 | ob.contr = &pl; |
|
|
307 | pl.ob = &ob; |
|
|
308 | ob.type = PLAYER; |
|
|
309 | pl.listening = 10; |
|
|
310 | pl.socket = *ns; |
|
|
311 | pl.outputs_count = 1; |
|
|
312 | ob.name = ns->comment; |
|
|
313 | |
|
|
314 | command(&ob, cp); |
|
|
315 | } |
|
|
316 | |
|
|
317 | |
|
|
318 | /** |
|
|
319 | * Handle client input. |
174 | * Handle client input. |
320 | * |
175 | * |
321 | * HandleClient is actually not named really well - we only get here once |
176 | * HandleClient is actually not named really well - we only get here once |
322 | * there is input, so we don't do exception or other stuff here. |
177 | * there is input, so we don't do exception or other stuff here. |
323 | * sock is the output socket information. pl is the player associated |
178 | * sock is the output socket information. pl is the player associated |
… | |
… | |
338 | */ |
193 | */ |
339 | if (pl && pl->state==ST_PLAYING && pl->ob != NULL && pl->ob->speed_left < 0) { |
194 | if (pl && pl->state==ST_PLAYING && pl->ob != NULL && pl->ob->speed_left < 0) { |
340 | return; |
195 | return; |
341 | } |
196 | } |
342 | |
197 | |
343 | if (ns->status == Ns_Old) { |
|
|
344 | Handle_Oldsocket(ns); |
|
|
345 | return; |
|
|
346 | } |
|
|
347 | i=SockList_ReadPacket(ns->fd, &ns->inbuf, MAXSOCKBUF-1); |
198 | i=SockList_ReadPacket(ns->fd, &ns->inbuf, MAXSOCKBUF-1); |
348 | /* Special hack - let the user switch to old mode if in the Ns_Add |
|
|
349 | * phase. Don't demand they add in the special length bytes |
|
|
350 | */ |
|
|
351 | if (ns->status == Ns_Add) { |
|
|
352 | if (!strncasecmp((const char*)ns->inbuf.buf,"oldsocketmode", 13)) { |
|
|
353 | ns->status = Ns_Old; |
|
|
354 | ns->inbuf.len=0; |
|
|
355 | cs_write_string(ns, "Switched to old socket mode\n", 28); |
|
|
356 | LOG(llevDebug,"Switched socket to old socket mode\n"); |
|
|
357 | return; |
|
|
358 | } |
|
|
359 | } |
|
|
360 | |
199 | |
361 | if (i<0) { |
200 | if (i<0) { |
362 | #ifdef ESRV_DEBUG |
201 | #ifdef ESRV_DEBUG |
363 | LOG(llevDebug,"HandleClient: Read error on connection player %s\n", (pl?pl->ob->name:"None")); |
202 | LOG(llevDebug,"HandleClient: Read error on connection player %s\n", (pl?pl->ob->name:"None")); |
364 | #endif |
203 | #endif |