00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00041 #include <global.h>
00042 #ifndef __CEXTRACT__
00043 #include <sproto.h>
00044 #include <sockproto.h>
00045 #endif
00046
00047 #ifndef WIN32
00048 #include <sys/types.h>
00049 #include <sys/time.h>
00050 #include <sys/socket.h>
00051 #include <netinet/in.h>
00052 #include <netdb.h>
00053 #endif
00054
00055 #ifdef HAVE_UNISTD_H
00056 #include <unistd.h>
00057 #endif
00058
00059 #ifdef HAVE_ARPA_INET_H
00060 #include <arpa/inet.h>
00061 #endif
00062
00063 #include <loader.h>
00064 #include <newserver.h>
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00080 typedef void (*func_uint8_int_ns)(char *, int, socket_struct *);
00081
00083 struct client_cmd_mapping {
00084 const char *cmdname;
00085 const func_uint8_int_ns cmdproc;
00086 };
00087
00089 typedef void (*func_uint8_int_pl)(char *, int, player *);
00091 struct player_cmd_mapping {
00092 const char *cmdname;
00093 const func_uint8_int_pl cmdproc;
00094 const uint8 flag;
00095 };
00096
00112 static const struct player_cmd_mapping player_commands[] = {
00113 { "examine", examine_cmd, 1 },
00114 { "apply", apply_cmd, 1 },
00115 { "move", move_cmd, 1 },
00116 { "reply", reply_cmd, 0 },
00117 { "ncom", (func_uint8_int_pl)new_player_cmd, 1 },
00118 { "lookat", look_at_cmd, 1 },
00119 { "lock", (func_uint8_int_pl)lock_item_cmd, 1 },
00120 { "mark", (func_uint8_int_pl)mark_item_cmd, 1 },
00121 { "mapredraw", map_redraw_cmd, 0 },
00122 { "inscribe", inscribe_scroll_cmd, 0 },
00123 { NULL, NULL, 0 }
00124 };
00125
00127 static const struct client_cmd_mapping client_commands[] = {
00128 { "addme", add_me_cmd },
00129 { "askface", send_face_cmd },
00130 { "requestinfo", request_info_cmd },
00131 { "setfacemode", set_face_mode_cmd },
00132 { "setsound", set_sound_cmd },
00133 { "setup", set_up_cmd },
00134 { "version", version_cmd },
00135 { "toggleextendedinfos", toggle_extended_infos_cmd },
00136 { "toggleextendedtext", toggle_extended_text_cmd },
00137 { "asksmooth", ask_smooth_cmd },
00138 { NULL, NULL }
00139 };
00140
00146 void request_info_cmd(char *buf, int len, socket_struct *ns) {
00147 char *params = NULL, *cp;
00148
00149 SockList sl;
00150
00151
00152
00153
00154 SockList_Init(&sl);
00155 SockList_AddString(&sl, "replyinfo ");
00156 SockList_AddString(&sl, buf);
00157
00158
00159
00160
00161 for (cp = buf; *cp != '\0'; cp++)
00162 if (*cp == ' ') {
00163 *cp = '\0';
00164 params = cp+1;
00165 break;
00166 }
00167 if (!strcmp(buf, "image_info"))
00168 send_image_info(ns, params);
00169 else if (!strcmp(buf, "image_sums"))
00170 send_image_sums(ns, params);
00171 else if (!strcmp(buf, "skill_info"))
00172 send_skill_info(ns, params);
00173 else if (!strcmp(buf, "spell_paths"))
00174 send_spell_paths(ns, params);
00175 else if (!strcmp(buf, "exp_table"))
00176 send_exp_table(ns, params);
00177 else if (!strcmp(buf, "race_list"))
00178 send_race_list(ns, params);
00179 else if (!strcmp(buf, "race_info"))
00180 send_race_info(ns, params);
00181 else if (!strcmp(buf, "class_list"))
00182 send_class_list(ns, params);
00183 else if (!strcmp(buf, "class_info"))
00184 send_class_info(ns, params);
00185 else
00186 Send_With_Handling(ns, &sl);
00187 SockList_Term(&sl);
00188 }
00189
00200 void handle_client(socket_struct *ns, player *pl) {
00201 int len, i;
00202 unsigned char *data;
00203
00204
00205 while (1) {
00206
00207
00208
00209 if (pl && pl->state == ST_PLAYING && pl->ob != NULL && pl->ob->speed_left < 0) {
00210 return;
00211 }
00212
00213 i = SockList_ReadPacket(ns->fd, &ns->inbuf, sizeof(ns->inbuf.buf)-1);
00214 if (i < 0) {
00215 #ifdef ESRV_DEBUG
00216 LOG(llevDebug, "handle_client: Read error on connection player %s\n", (pl ? pl->ob->name : "None"));
00217 #endif
00218
00219 ns->status = Ns_Dead;
00220 return;
00221 }
00222
00223 if (i == 0)
00224 return;
00225
00226 SockList_NullTerminate(&ns->inbuf);
00227
00228
00229
00230
00231
00232
00233 data = (unsigned char *)strchr((char *)ns->inbuf.buf+2, ' ');
00234 if (data) {
00235 *data = '\0';
00236 data++;
00237 len = ns->inbuf.len-(data-ns->inbuf.buf);
00238 } else
00239 len = 0;
00240
00241 for (i = 0; client_commands[i].cmdname != NULL; i++) {
00242 if (strcmp((char *)ns->inbuf.buf+2, client_commands[i].cmdname) == 0) {
00243 client_commands[i].cmdproc((char *)data, len, ns);
00244 SockList_ResetRead(&ns->inbuf);
00245 return;
00246 }
00247 }
00248
00249
00250
00251
00252
00253
00254
00255 if (pl)
00256 for (i = 0; player_commands[i].cmdname != NULL; i++) {
00257 if (strcmp((char *)ns->inbuf.buf+2, player_commands[i].cmdname) == 0) {
00258 if (pl->state == ST_PLAYING || player_commands[i].flag == 0)
00259 player_commands[i].cmdproc((char *)data, len, pl);
00260 SockList_ResetRead(&ns->inbuf);
00261 return;
00262 }
00263 }
00264
00265
00266
00267
00268 LOG(llevDebug, "Bad command from client (%s)\n", ns->inbuf.buf+2);
00269 SockList_ResetRead(&ns->inbuf);
00270 }
00271 }
00272
00273
00274
00275
00276
00277
00278
00279
00280 #ifdef WATCHDOG
00281
00287 void watchdog(void) {
00288 static int fd = -1;
00289 static struct sockaddr_in insock;
00290
00291 if (fd == -1) {
00292 struct protoent *protoent;
00293
00294 if ((protoent = getprotobyname("udp")) == NULL
00295 || (fd = socket(PF_INET, SOCK_DGRAM, protoent->p_proto)) == -1) {
00296 return;
00297 }
00298 insock.sin_family = AF_INET;
00299 insock.sin_port = htons((unsigned short)13325);
00300 insock.sin_addr.s_addr = inet_addr("127.0.0.1");
00301 }
00302 sendto(fd, (void *)&fd, 1, 0, (struct sockaddr *)&insock, sizeof(insock));
00303 }
00304 #endif
00305
00306 extern unsigned long todtick;
00307
00309 static void block_until_new_connection(void) {
00310 struct timeval Timeout;
00311 fd_set readfs;
00312 int cycles;
00313
00314 LOG(llevInfo, "Waiting for connections...\n");
00315
00316 cycles = 1;
00317 do {
00318
00319
00320
00321 cycles++;
00322 if (cycles%2 == 0)
00323 tick_the_clock();
00324
00325 FD_ZERO(&readfs);
00326 FD_SET((uint32)init_sockets[0].fd, &readfs);
00327
00328
00329
00330
00331
00332
00333 if (settings.fastclock > 0) {
00334 #ifdef WATCHDOG
00335 if (cycles%120000 == 0) {
00336 watchdog();
00337 flush_old_maps();
00338 }
00339 #endif
00340 if (cycles == 720000) {
00341 metaserver_update();
00342 cycles = 1;
00343 }
00344 Timeout.tv_sec = 0;
00345 Timeout.tv_usec = 50;
00346 } else {
00347 Timeout.tv_sec = 60;
00348 Timeout.tv_usec = 0;
00349 if (cycles == 7) {
00350 metaserver_update();
00351 cycles = 1;
00352 }
00353 flush_old_maps();
00354 }
00355 } while (select(socket_info.max_filedescriptor, &readfs, NULL, NULL, &Timeout) == 0);
00356
00357 reset_sleep();
00358 }
00359
00368 static int is_fd_valid(int fd) {
00369 #ifndef WIN32
00370 return fcntl(fd, F_GETFL) != -1 || errno != EBADF;
00371 #else
00372 return 1;
00373 #endif
00374 }
00375
00383 void do_server(void) {
00384 int i, pollret;
00385 fd_set tmp_read, tmp_exceptions, tmp_write;
00386 struct sockaddr_in addr;
00387 socklen_t addrlen = sizeof(struct sockaddr);
00388 player *pl, *next;
00389 char err[MAX_BUF];
00390
00391 #ifdef CS_LOGSTATS
00392 if ((time(NULL)-cst_lst.time_start) >= CS_LOGTIME)
00393 write_cs_stats();
00394 #endif
00395
00396 FD_ZERO(&tmp_read);
00397 FD_ZERO(&tmp_write);
00398 FD_ZERO(&tmp_exceptions);
00399
00400 for (i = 0; i < socket_info.allocated_sockets; i++) {
00401 if (init_sockets[i].status == Ns_Add && !is_fd_valid(init_sockets[i].fd)) {
00402 LOG(llevError, "do_server: invalid waiting fd %d\n", i);
00403 init_sockets[i].status = Ns_Dead;
00404 }
00405 if (init_sockets[i].status == Ns_Dead) {
00406 free_newsocket(&init_sockets[i]);
00407 init_sockets[i].status = Ns_Avail;
00408 socket_info.nconns--;
00409 } else if (init_sockets[i].status != Ns_Avail) {
00410 FD_SET((uint32)init_sockets[i].fd, &tmp_read);
00411 FD_SET((uint32)init_sockets[i].fd, &tmp_write);
00412 FD_SET((uint32)init_sockets[i].fd, &tmp_exceptions);
00413 }
00414 }
00415
00416
00417
00418
00419 for (pl = first_player; pl != NULL; ) {
00420 if (pl->socket.status != Ns_Dead && !is_fd_valid(pl->socket.fd)) {
00421 LOG(llevError, "do_server: invalid file descriptor for player %s [%s]: %d\n", (pl->ob && pl->ob->name) ? pl->ob->name : "(unnamed player?)", (pl->socket.host) ? pl->socket.host : "(unknown ip?)", pl->socket.fd);
00422 pl->socket.status = Ns_Dead;
00423 }
00424
00425 if (pl->socket.status == Ns_Dead) {
00426 player *npl = pl->next;
00427
00428 save_player(pl->ob, 0);
00429 if (!QUERY_FLAG(pl->ob, FLAG_REMOVED)) {
00430 terminate_all_pets(pl->ob);
00431 remove_ob(pl->ob);
00432 }
00433 leave(pl, 1);
00434 final_free_player(pl);
00435 pl = npl;
00436 } else {
00437 FD_SET((uint32)pl->socket.fd, &tmp_read);
00438 FD_SET((uint32)pl->socket.fd, &tmp_write);
00439 FD_SET((uint32)pl->socket.fd, &tmp_exceptions);
00440 pl = pl->next;
00441 }
00442 }
00443
00444 if (socket_info.nconns == 1 && first_player == NULL)
00445 block_until_new_connection();
00446
00447
00448
00449
00450 socket_info.timeout.tv_sec = 0;
00451 socket_info.timeout.tv_usec = 0;
00452
00453 pollret = select(socket_info.max_filedescriptor, &tmp_read, &tmp_write, &tmp_exceptions, &socket_info.timeout);
00454
00455 if (pollret == -1) {
00456 LOG(llevError, "select failed: %s\n", strerror_local(errno, err, sizeof(err)));
00457 return;
00458 }
00459
00460
00461
00462
00463
00464 if (pollret && FD_ISSET(init_sockets[0].fd, &tmp_read)) {
00465 int newsocknum = 0;
00466
00467 #ifdef ESRV_DEBUG
00468 LOG(llevDebug, "do_server: New Connection\n");
00469 #endif
00470
00471 if (socket_info.allocated_sockets <= socket_info.nconns) {
00472 init_sockets = realloc(init_sockets, sizeof(socket_struct)*(socket_info.nconns+1));
00473 if (!init_sockets)
00474 fatal(OUT_OF_MEMORY);
00475 newsocknum = socket_info.allocated_sockets;
00476 socket_info.allocated_sockets++;
00477 init_sockets[newsocknum].faces_sent_len = nrofpixmaps;
00478 init_sockets[newsocknum].faces_sent = calloc(1, nrofpixmaps*sizeof(*init_sockets[newsocknum].faces_sent));
00479 if (!init_sockets[newsocknum].faces_sent)
00480 fatal(OUT_OF_MEMORY);
00481 init_sockets[newsocknum].status = Ns_Avail;
00482 } else {
00483 int j;
00484
00485 for (j = 1; j < socket_info.allocated_sockets; j++)
00486 if (init_sockets[j].status == Ns_Avail) {
00487 newsocknum = j;
00488 break;
00489 }
00490 }
00491 init_sockets[newsocknum].fd = accept(init_sockets[0].fd, (struct sockaddr *)&addr, &addrlen);
00492 if (init_sockets[newsocknum].fd == -1) {
00493 LOG(llevError, "accept failed: %s\n", strerror_local(errno, err, sizeof(err)));
00494 } else {
00495 char buf[MAX_BUF];
00496 long ip;
00497 socket_struct *ns;
00498
00499 ns = &init_sockets[newsocknum];
00500
00501 ip = ntohl(addr.sin_addr.s_addr);
00502 snprintf(buf, sizeof(buf), "%ld.%ld.%ld.%ld", (ip>>24)&255, (ip>>16)&255, (ip>>8)&255, ip&255);
00503
00504 if (checkbanned(NULL, buf)) {
00505 LOG(llevInfo, "Banned host tried to connect: [%s]\n", buf);
00506 close(init_sockets[newsocknum].fd);
00507 init_sockets[newsocknum].fd = -1;
00508 } else {
00509 init_connection(ns, buf);
00510 socket_info.nconns++;
00511 }
00512 }
00513 }
00514
00515
00516 if (pollret)
00517 for (i = 1; i < socket_info.allocated_sockets; i++) {
00518 if (init_sockets[i].status == Ns_Avail)
00519 continue;
00520 if (FD_ISSET(init_sockets[i].fd, &tmp_exceptions)) {
00521 free_newsocket(&init_sockets[i]);
00522 init_sockets[i].status = Ns_Avail;
00523 socket_info.nconns--;
00524 continue;
00525 }
00526 if (FD_ISSET(init_sockets[i].fd, &tmp_read)) {
00527 handle_client(&init_sockets[i], NULL);
00528 }
00529 if (FD_ISSET(init_sockets[i].fd, &tmp_write)) {
00530 init_sockets[i].can_write = 1;
00531 }
00532 }
00533
00534
00535 for (pl = first_player; pl != NULL; pl = next) {
00536 next = pl->next;
00537 if (pl->socket.status == Ns_Dead)
00538 continue;
00539
00540 if (FD_ISSET(pl->socket.fd, &tmp_write)) {
00541 if (!pl->socket.can_write) {
00542 pl->socket.can_write = 1;
00543 write_socket_buffer(&pl->socket);
00544 }
00545
00546
00547
00548 if (pl->socket.status == Ns_Dead)
00549 continue;
00550 } else
00551 pl->socket.can_write = 0;
00552
00553 if (FD_ISSET(pl->socket.fd, &tmp_exceptions)) {
00554 save_player(pl->ob, 0);
00555 if (!QUERY_FLAG(pl->ob, FLAG_REMOVED)) {
00556 terminate_all_pets(pl->ob);
00557 remove_ob(pl->ob);
00558 }
00559 leave(pl, 1);
00560 final_free_player(pl);
00561 } else {
00562 handle_client(&pl->socket, pl);
00563
00564
00565
00566
00567
00568
00569
00570
00571
00572 next = pl->next;
00573
00574
00575
00576
00577
00578
00579
00580 if (pl->socket.status == Ns_Dead) {
00581 save_player(pl->ob, 0);
00582 if (!QUERY_FLAG(pl->ob, FLAG_REMOVED)) {
00583 terminate_all_pets(pl->ob);
00584 remove_ob(pl->ob);
00585 }
00586 leave(pl, 1);
00587 final_free_player(pl);
00588 } else {
00589
00590
00591
00592 esrv_update_stats(pl);
00593 if (pl->last_weight != -1 && pl->last_weight != WEIGHT(pl->ob)) {
00594 esrv_update_item(UPD_WEIGHT, pl->ob, pl->ob);
00595 if (pl->last_weight != WEIGHT(pl->ob))
00596 LOG(llevError, "esrv_update_item(UPD_WEIGHT) did not set player weight: is %lu, should be %lu\n", (unsigned long)pl->last_weight, (unsigned long)WEIGHT(pl->ob));
00597 }
00598
00599
00600
00601 draw_client_map(pl->ob);
00602 if (pl->socket.update_look)
00603 esrv_draw_look(pl->ob);
00604 if (pl->socket.tick)
00605 send_tick(pl);
00606
00607 }
00608 }
00609 }
00610 }