int server_post_peer_list() { // <horrible workaround> std::string peer_list_str = "TT;"; peer_list_str[0] = S_PEER_LIST; peer_list_str[1] = (char)clients.size(); // </horrible workaround> id_client_map::iterator iter = clients.begin(); while (true) { struct client &itclient = (*iter).second; peer_list_str = peer_list_str + int_to_string(itclient.id) + ":" + itclient.name + ":" + itclient.ip_string; ++iter; if (iter != clients.end()) { peer_list_str = peer_list_str + ';'; } else { break; } } iter = clients.begin(); while (iter != clients.end()) { std::cerr << "server_post_peer_list: peer_list_str = \"" << peer_list_str << "\"\n"; server_send_packet((unsigned char*)peer_list_str.c_str(), peer_list_str.length(), &(*iter).second); ++iter; } return 1; }
int server_post_quit_message() { interm_buf[0] = S_QUIT; interm_buf[1] = '\0'; id_client_map::iterator iter = clients.begin(); while (iter != clients.end()) { server_send_packet(interm_buf, 1, &(*iter).second); ++iter; } return 1; }
static void initial_update(client_t *client) { // Protokoll Version senden packet_t packet; packet_init(&packet, PACKET_HANDSHAKE); packet_write08(&packet, PROTOCOL_VERSION); server_send_packet(&packet, client); server_start_compression(client); game_send_initial_update(client); world_send_initial_update(client); player_send_initial_update(client); creature_send_initial_update(client); }
int server_process_packet(struct sockaddr_in *from) { unsigned int from_address = ntohl(from->sin_addr.s_addr); unsigned short from_port = ntohs(from->sin_port); char *inet_addr = inet_ntoa(from->sin_addr); if (packet_data[0] == C_HANDSHAKE) { std::cerr << "client @ " << inet_addr << ":" << from_port << " :handshake request\n"; int newclient_id = server_add_client(from); if (newclient_id < 0) { std::cerr << "server_add_client: error.\n"; return -1; } interm_buf[0] = S_HANDSHAKE_OK; interm_buf[1] = newclient_id; interm_buf[2] = 0; struct client *newclient = get_client_by_id(newclient_id); server_send_packet(interm_buf, 2, newclient); server_post_peer_list(); } else if (packet_data[0] == C_QUIT) { unsigned short id = packet_data[1]; struct client *quitting_client = get_client_by_id(id); if (quitting_client) { std::cerr << "Client " << quitting_client->name << " with id " << quitting_client->id << " quitting.\n"; server_remove_client(id); } else { std::cerr << "client with id " << id << "not found.\n"; } } else if (packet_data[0] == C_KEYSTATE) { unsigned short id = packet_data[1]; client *c = get_client_by_id(id); if (c) { c->keystate = packet_data[2]; server_update_client_status(c); server_post_position_update(c); } } else { return 0; } }
int server_post_position_update(client *c) { //time_t ms = timer.get_ms(); //std::cerr << "time since last pupd: " << ms << " ms.\n"; //timer.begin(); //memset(posupd_packet_buffer, 0, maximum_packet_size); *** interm_buf[0] = S_PUPD; interm_buf[1] = c->id; struct car_serialized cs = c->lcar.serialize(); memcpy(&interm_buf[2], (const void*)&cs, sizeof(cs)); size_t total_packet_size = 2 + sizeof(cs); interm_buf[total_packet_size] = '\0'; id_client_map::iterator iter = clients.begin(); while (iter != clients.end()) { server_send_packet(interm_buf, total_packet_size, &(*iter).second); ++iter; } }
void server_start_compression(client_t *client) { // Kompression bereits aktiviert? if (client->compress) return; // Demos sind immer unkomprimiert. Eine Kompression ueber // die erstellte Datei macht wesentlich mehr Sinn. if (client->is_file_writer) return; client->strm.zalloc = Z_NULL; client->strm.zfree = Z_NULL; client->strm.opaque = NULL; if (deflateInit(&client->strm, 9) != Z_OK) { fprintf(stderr, "cannot alloc new zstream\n"); return; } packet_t packet; packet_init(&packet, PACKET_START_COMPRESS); server_send_packet(&packet, client); client->compress = 1; }
static void server_mainloop(void) { atexit(server_atexit_handler); fd_set new_readfds, new_writefds; FD_ZERO(&new_readfds); FD_ZERO(&new_writefds); FD_SET(server.socket, &new_readfds); int new_fdmax = server.socket; bool exit_packet_delivered = false; if (server.read_pty) FD_SET_MAX(server.pty, &new_readfds, new_fdmax); while (server.clients || !exit_packet_delivered) { int fdmax = new_fdmax; fd_set readfds = new_readfds; fd_set writefds = new_writefds; FD_SET_MAX(server.socket, &readfds, fdmax); if (select(fdmax+1, &readfds, &writefds, NULL, NULL) == -1) { if (errno == EINTR) continue; die("server-mainloop"); } FD_ZERO(&new_readfds); FD_ZERO(&new_writefds); new_fdmax = server.socket; bool pty_data = false; Packet server_packet, client_packet; if (FD_ISSET(server.socket, &readfds)) server_accept_client(); if (FD_ISSET(server.pty, &readfds)) pty_data = server_read_pty(&server_packet); for (Client **prev_next = &server.clients, *c = server.clients; c;) { if (FD_ISSET(c->socket, &readfds) && server_recv_packet(c, &client_packet)) { switch (client_packet.type) { case MSG_CONTENT: server_write_pty(&client_packet); break; case MSG_ATTACH: c->flags = client_packet.u.i; if (c->flags & CLIENT_LOWPRIORITY) server_sink_client(); break; case MSG_RESIZE: c->state = STATE_ATTACHED; case MSG_REDRAW: if (!(c->flags & CLIENT_READONLY) && (client_packet.type == MSG_REDRAW || c == server.clients)) { debug("server-ioct: TIOCSWINSZ\n"); ioctl(server.pty, TIOCSWINSZ, &client_packet.u.ws); } kill(-server.pid, SIGWINCH); break; case MSG_EXIT: exit_packet_delivered = true; /* fall through */ case MSG_DETACH: c->state = STATE_DISCONNECTED; break; default: /* ignore package */ break; } } if (c->state == STATE_DISCONNECTED) { bool first = (c == server.clients); Client *t = c->next; client_free(c); *prev_next = c = t; if (first && server.clients) { Packet pkt = { .type = MSG_RESIZE, .len = 0, }; server_send_packet(server.clients, &pkt); } else if (!server.clients) { server_mark_socket_exec(false, true); } continue; } FD_SET_MAX(c->socket, &new_readfds, new_fdmax); if (pty_data) server_send_packet(c, &server_packet); if (!server.running) { if (server.exit_status != -1) { Packet pkt = { .type = MSG_EXIT, .u.i = server.exit_status, .len = sizeof(pkt.u.i), }; if (!server_send_packet(c, &pkt)) FD_SET_MAX(c->socket, &new_writefds, new_fdmax); } else { FD_SET_MAX(c->socket, &new_writefds, new_fdmax); } }
void game_send_intermission(client_t *client) { packet_t packet; packet_init(&packet, PACKET_INTERMISSION); packet_writeXX(&packet, intermission, strlen(intermission)); server_send_packet(&packet, client); }
void game_send_round_info(client_t *client, int delta) { packet_t packet; packet_init(&packet, PACKET_ROUND); packet_write08(&packet, delta); server_send_packet(&packet, client); }
void game_send_info(client_t *client) { packet_t packet; packet_init(&packet, PACKET_GAME_INFO); packet_write32(&packet, game_time); server_send_packet(&packet, client); }
void server_destroy(client_t *client, const char *reason) { lua_pushliteral(L, "on_client_close"); lua_rawget(L, LUA_GLOBALSINDEX); lua_pushnumber(L, client_num(client)); lua_pushstring(L, reason); if (lua_pcall(L, 2, 0, 0) != 0) { fprintf(stderr, "error calling on_client_close: %s\n", lua_tostring(L, -1)); lua_pop(L, 1); } // Quitmeldung senden if (client->is_gui_client) { packet_t packet; packet_init(&packet, PACKET_QUIT_MSG); packet_writeXX(&packet, reason, strlen(reason)); server_send_packet(&packet, client); } else { server_writeto(client, "connection terminated: ", 23); server_writeto(client, reason, strlen(reason)); server_writeto(client, "\r\n", 2); } // Kompressionsrest flushen server_flush_compression(client); // Rest rausschreiben (hier keine Fehlerbehandlung mehr, da eh egal). // Bei Filewritern muss nichts geschrieben werden, da deren Daten // immer direkt rausgeschrieben werden. if (!client->is_file_writer) evbuffer_write(client->out_buf, client->fd); evbuffer_free(client->in_buf); evbuffer_free(client->out_buf); free(client->kill_me); if (client->compress) deflateEnd(&client->strm); event_del(&client->rd_event); event_del(&client->wr_event); client->in_buf = NULL; client->out_buf = NULL; if (client->player) player_detach_client(client, client->player); assert(client->next == NULL); assert(client->prev == NULL); if (client->is_gui_client) { if (client->next_gui == client) { assert(client->prev_gui == client); guiclients = NULL; } else { client->next_gui->prev_gui = client->prev_gui; client->prev_gui->next_gui = client->next_gui; guiclients = client->next_gui; } } num_clients--; #ifndef NO_CONSOLE_CLIENT if (client->fd != STDIN_FILENO) #endif #ifdef WIN32 if (client->is_file_writer) { close(client->fd); } else { closesocket(client->fd); } #else close(client->fd); #endif }