void do_copyover(void) { LIST_ITERATOR *sock_i = newListIterator(socket_list); SOCKET_DATA *sock = NULL; FILE *fp; char buf[100]; char control_buf[20]; char port_buf[20]; if ((fp = fopen(COPYOVER_FILE, "w+")) == NULL) return; sprintf(buf, "\n\r <*> The world starts spinning <*>\n\r"); // For each playing descriptor, save its character and account ITERATE_LIST(sock, sock_i) { compressEnd(sock, sock->compressing, FALSE); // kick off anyone who hasn't yet logged in a character if (!socketGetChar(sock) || !socketGetAccount(sock) || !charGetRoom(socketGetChar(sock))) { text_to_socket(sock, "\r\nSorry, we are rebooting. Come back in a few minutes.\r\n"); close_socket(sock, FALSE); } // save account and player info to file else { fprintf(fp, "%d %s %s %s\n", sock->control, accountGetName(sock->account), charGetName(sock->player), sock->hostname); // save the player save_player(sock->player); save_account(sock->account); text_to_socket(sock, buf); } } deleteListIterator(sock_i);
/* * Close_socket() * * Will close one socket directly, freeing all * resources and making the socket availably on * the socket free_list. */ void close_socket(SOCKET_DATA *dsock, bool reconnect) { if (dsock->lookup_status > TSTATE_DONE) return; dsock->lookup_status += 2; /* remove the socket from the polling list */ FD_CLR(dsock->control, &fSet); /* remove ourself from the list */ // // NO! We don't want to remove ourself from the list just yet. // We will do that the next time we show up in the game_loop. // removing now will not close the socket completely. Why, I'm not // entirely sure... but it doesn't ;) // - Geoff, Dec26/04 // // listRemove(socket_list, dsock); // // we have a character, and it's one that's // not in the process of being created if (dsock->player && charGetUID(dsock->player) != NOBODY) { if (reconnect) text_to_socket(dsock, "This connection has been taken over.\r\n"); else { charSetSocket(dsock->player, NULL); log_string("Closing link to %s", charGetName(dsock->player)); } } else if(dsock->player) { charSetSocket(dsock->player, NULL); extract_mobile(dsock->player); } if(dsock->account) { if(account_exists(accountGetName(dsock->account))) unreference_account(dsock->account); else deleteAccount(dsock->account); } /* set the closed state */ dsock->closed = TRUE; // dsock->state = STATE_CLOSED; }
/* * Read_from_socket() * * Reads one line from the socket, storing it * in a buffer for later use. Will also close * the socket if it tries a buffer overflow. */ bool read_from_socket(SOCKET_DATA *dsock) { int size; extern int errno; /* check for buffer overflows, and drop connection in that case */ size = strlen(dsock->inbuf); if (size >= sizeof(dsock->inbuf) - 2) { text_to_socket(dsock, "\n\r!!!! Input Overflow !!!!\n\r"); return FALSE; } /* start reading from the socket */ for (;;) { int sInput; int wanted = sizeof(dsock->inbuf) - 2 - size; sInput = read(dsock->control, dsock->inbuf + size, wanted); if (sInput > 0) { size += sInput; if (dsock->inbuf[size-1] == '\n' || dsock->inbuf[size-1] == '\r') break; } else if (sInput == 0) { log_string("Read_from_socket: EOF"); return FALSE; } else if (errno == EAGAIN || sInput == wanted) break; else { perror("Read_from_socket"); return FALSE; } } dsock->inbuf[size] = '\0'; return TRUE; }
bool flush_output(SOCKET_DATA *dsock) { bool success = TRUE; BUFFER *buf = NULL; // run any hooks prior to flushing our text hookRun("flush", hookBuildInfo("sk", dsock)); // quit if we have no output and don't need/can't have a prompt if(bufferLength(dsock->outbuf) <= 0 && (!dsock->bust_prompt || !socketHasPrompt(dsock))) return success; buf = newBuffer(1); // send our outbound text if(bufferLength(dsock->outbuf) > 0) { hookRun("process_outbound_text", hookBuildInfo("sk", dsock)); hookRun("finalize_outbound_text", hookBuildInfo("sk", dsock)); //success = text_to_socket(dsock, bufferString(dsock->outbuf)); bufferCat(buf, bufferString(dsock->outbuf)); bufferClear(dsock->outbuf); } // send our prompt if(dsock->bust_prompt && success) { socketShowPrompt(dsock); hookRun("process_outbound_prompt", hookBuildInfo("sk", dsock)); hookRun("finalize_outbound_prompt", hookBuildInfo("sk", dsock)); //success = text_to_socket(dsock, bufferString(dsock->outbuf)); bufferCat(buf, bufferString(dsock->outbuf)); bufferClear(dsock->outbuf); dsock->bust_prompt = FALSE; } success = text_to_socket(dsock, bufferString(buf)); deleteBuffer(buf); // return our success return success; }
bool event_socket_idle(EVENT_DATA *event) { D_SOCKET *dSock; /* Check to see if there is an owner of this event. * If there is no owner, we return TRUE, because * it's the safest - and post a bug message. */ if ((dSock = event->owner.dSock) == NULL) { bug("event_socket_idle: no owner."); return TRUE; } /* tell the socket that it has idled out, and close it */ text_to_socket(dSock, "You have idled out...\n\n\r"); close_socket(dSock, FALSE); /* since we closed the socket, all events owned * by that socket has been dequeued, and we need * to return TRUE, so the caller knows this. */ return TRUE; }
/* Recover from a copyover - load players */ void copyover_recover() { CHAR_DATA *dMob; ACCOUNT_DATA *account; SOCKET_DATA *dsock; FILE *fp; char acct[100]; char name[100]; char host[MAX_BUFFER]; int desc; log_string("Copyover recovery initiated"); if ((fp = fopen(COPYOVER_FILE, "r")) == NULL) { log_string("Copyover file not found. Exitting."); exit (1); } /* In case something crashes - doesn't prevent reading */ unlink(COPYOVER_FILE); for (;;) { fscanf(fp, "%d %s %s %s\n", &desc, acct, name, host); if (desc == -1) break; // Many thanks to Rhaelar for the help in finding this bug; clear_socket // does not like receiving freshly malloc'd data. We have to make sure // everything is zeroed before we pass it to clear_socket // dsock = malloc(sizeof(*dsock)); dsock = calloc(1, sizeof(*dsock)); clear_socket(dsock, desc); dsock->hostname = strdup(host); listPut(socket_list, dsock); propertyTablePut(sock_table, dsock); // load account data if((account = get_account(acct)) != NULL) socketSetAccount(dsock, account); // no luck! else { close_socket(dsock, FALSE); continue; } // load player data if ((dMob = get_player(name)) != NULL) { // attach to socket charSetSocket(dMob, dsock); socketSetChar(dsock, dMob); // try putting the character into the game // close the socket if we fail. if(!try_enter_game(dMob)) { // do not bother extracting, since we haven't entered the game yet unreference_player(socketGetChar(dsock)); socketSetChar(dsock, NULL); close_socket(dsock, FALSE); continue; } } // no luck else { close_socket(dsock, FALSE); continue; } // Write something, and check if it goes error-free if (!text_to_socket(dsock, "\n\r <*> And before you know it, everything has changed <*>\n\r")) { close_socket(dsock, FALSE); continue; } // make sure the socket can be used dsock->bust_prompt = TRUE; dsock->lookup_status = TSTATE_DONE; // let our modules know we've finished copying over a socket hookRun("copyover_complete", hookBuildInfo("sk", dsock)); // negotiate compression text_to_buffer(dsock, (char *) compress_will2); text_to_buffer(dsock, (char *) compress_will); } fclose(fp); // now, set all of the sockets' control to the new fSet reconnect_copyover_sockets(); }