/* * Copyright (C) 2003 Tim Martin * * 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 of the License, 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include #include #include #include #include #include #include #include #include "connections.h" #include "protocol.h" #include "player.h" #include "map.h" #include "senkenconfig.h" typedef struct txn_op_s { struct txn_op_s *next; void *op; } txn_op_t; struct connection_s { int fd; FILE *stream; player_t *player; struct connection_s *next; struct connection_s *prev; int active_txn; txn_op_t *txn_op_list; }; connection_t *connectionlist = NULL; FILE *logfile = NULL; extern map_t *map; /* forward declarations */ static void connections_remove(connection_t *conn); int connections_setlogging(const char *file) { if (logfile) { fclose(logfile); } logfile = fopen(file,"w+"); if (!logfile) return -1; return 0; } void connection_setfd(connection_t *conn, player_t *player, void *rock) { fd_set *fds = (fd_set *)rock; FD_SET(conn->fd, fds); } void connection_checkfd(connection_t *conn, player_t *player, void *rock) { fd_set *fds = (fd_set *)rock; if (FD_ISSET(conn->fd, fds)) { char line[1024]; if (fgets(line, sizeof(line)-1, conn->stream)) { if (logfile) { fprintf(logfile,"C: %s",line); fflush(logfile); } protocol_handle_line(conn, line); } else { connections_remove(conn); } } } void connections_enumerate(connection_enumerate_func *func, void *rock) { connection_t *c = connectionlist; while (c) { connection_t *next; /* get next first since func() might remove our current one */ next = c->next; func(c, c->player, rock); c = next; } } static void connections_remove(connection_t *conn) { close(conn->fd); if (conn == connectionlist) { connectionlist = connectionlist->next; } else { connection_t *prev = conn->prev; connection_t *next = conn->next; if (prev) prev->next = next; if (next) next->prev = prev; } /* xxx free everything else too */ if (conn->player) { if (map) { map_player_quit(map, conn->player); } player_delete(conn->player); /* xxx remove player's possessions too */ } free(conn); } int connections_add(int newsock) { connection_t *connection; /* * Allocate and fill in a new connection structure */ connection = calloc(sizeof(connection_t), 1); if (!connection) { printf(_("memory allocation failure\n")); return -1; } connection->fd = newsock; connection->stream = fdopen(newsock, "w+"); /* * Now add it to the list */ connection->next = NULL; connection->prev = NULL; if (!connectionlist) { connectionlist = connection; } else { connection->next = connectionlist; connectionlist->prev = connection; connectionlist = connection; } return 0; } static void send_to_one(connection_t *conn, player_t *player, void *rock) { char *data = (char *)rock; connection_write(conn, 0, data); } void connections_send_to_all(char *msg, ...) { char str[4096]; va_list ap; va_start(ap, msg); vsnprintf(str, sizeof(str)-1, msg, ap); va_end(ap); connections_enumerate(&send_to_one, (void *)str); } void connection_write(connection_t *conn, int flush, char *msg, ...) { char str[4096]; va_list ap; int len; int wrote; va_start(ap, msg); len = vsnprintf(str, sizeof(str)-1, msg, ap); wrote = fwrite(str, 1, len, conn->stream); if (wrote != len) { printf("wrote %d when should have written %d\n", wrote, len); } if (flush) { if (fflush(conn->stream)) { printf(_("Flush error: %s\n"), strerror(errno)); } } if (logfile) { fprintf(logfile,"S: %s",str); } va_end(ap); } static void flush_one(connection_t *conn, player_t *player, void *rock) { fflush(conn->stream); } void connections_flush_all(void) { connections_enumerate(&flush_one, NULL); } void connection_close(connection_t *conn) { fclose(conn->stream); close(conn->fd); conn->fd = -1; } player_t * connection_getplayer(connection_t *conn) { return conn->player; } int connection_setplayer(connection_t *conn, const char *name) { int r; r = player_new((char *)name, &conn->player); if (r) return r; r =player_setopennumber(conn->player); if (r) return r; return 0; } connection_t *connections_getconnection(player_t *player) { connection_t *c = connectionlist; while (c) { if (c->player == player) return c; c = c->next; } return NULL; } int connection_txn_start(connection_t *conn) { if (conn->active_txn) return -1; conn->active_txn = 1; return 0; } int connection_txn_add(connection_t *conn, void *op) { txn_op_t *tail; txn_op_t *new_op = malloc(sizeof(txn_op_t)); if (!new_op) return -1; new_op->op = op; new_op->next = NULL; tail = conn->txn_op_list; if (tail) { while (tail->next) { tail = tail->next; } tail->next = new_op; } else { conn->txn_op_list = new_op; } return 0; } int connection_txn_enumerate(connection_t *conn, connection_txn_enumerate_func *func, void *rock) { txn_op_t *op = conn->txn_op_list; while (op) { func(op->op, rock); op = op->next; } return 0; } int connection_txn_clear(connection_t *conn) { txn_op_t *op = conn->txn_op_list; while (op) { txn_op_t *next = op->next; free(op->op); free(op); op = next; } conn->txn_op_list = NULL; conn->active_txn = 0; return 0; } int connection_txn_active(connection_t *conn) { return conn->active_txn; }