// This file written completely by Tim Johnson (Tim@TimMUD) static void close_callback(int fd){ string mudname; debug("close_callback: fd="+fd+"\n"); foreach(mudname in keys(muds_on_this_fd(fd))){ debug("Removing mud from connected_muds list: "+mudname); mudinfo[mudname]["disconnect_time"] = time(); map_delete(connected_muds, mudname); broadcast_mudlist(mudname); } close_connection(fd); } static void listen_callback(int fd){ int nfd; debug("listen_callback: fd="+fd+"\n"); if ((nfd = socket_accept(fd, "read_callback", "write_callback")) < 0) { log_file("server", "listen_callback: socket_accept failed.\n"); return; } } void write_callback(int fd) { if (sockets[fd]["write_status"] == EEALREADY) { write_data(fd, sockets[fd]["pending"]); map_delete(sockets[fd], "pending"); } else { sockets[fd]["write_status"] = EESUCCESS; #if 0 close_connection(fd); #endif } } static void write_data_retry(int fd, mixed data, int counter){ int rc; if (counter == MAXIMUM_RETRIES) { close_connection(fd); return; } rc = socket_write(fd, data); if(!sockets[fd]) sockets[fd]=([]); // Tim sockets[fd]["write_status"] = rc; switch (rc) { case EESUCCESS: // we're finished with this fd. // Oops, Leto :) close_connection(fd); //close_connection(fd); break; case EEALREADY: // driver must have set the socket marked as BLOCKED when // it was created by socket_accept(). Just wait for // write_callback to be called so that we can write out the // pending data. sockets[fd]["pending"] = data; break; case EECALLBACK: // wait for write_callback before accessing socket fd again. break; case EEWOULDBLOCK: case EESEND: // try again in two seconds if (counter < MAXIMUM_RETRIES) { call_out("retry_write", 2, ({fd, data, counter + 1})); return; } // fall through to the default case and write an error. default: log_file("server", "write_data_retry: " + socket_error(rc) + "\n"); close_connection(fd); break; } } static void close_connection(int fd){ int errcode; debug("Attempting to close socket\n"); // The code below caused sockets to linger after a "quit" command. -- Leto #if 0 if (sockets[fd]["write_status"] == EECALLBACK) { // write_callback() will call close_connection() when socket fd // is drained. debug("write_callback() will call close_connection() when socket fd"+ "is drained.\n"); return; } #endif map_delete(sockets, fd); errcode = socket_close(fd); debug("Socket closed with code:"+errcode+".\n"); } static void write_data(int fd, mixed data){ debug("Sending to fd="+fd+":\n"+dump_variable(data),DEB_OUT); write_data_retry(fd, data, 0); } static void broadcast_data(mapping targets, mixed data){ int fd; int *arr; // Unique_array was way too complicated to figure out. // What this does is take the values for all the connected_muds, // get rid of duplicates (so that if 2 muds are on the same fd // then it doesn't re-send messages to the fd) foreach(arr in unique_array(values(targets), (: $1 :))){ write_data(arr[0], data); } }