// TCP base client with multiple socket support; Galileo, 11-30-98 #include <network.h> #define OPEN 1 #define BLOCKED 2 class socket { int desc; // Identification for the socket int mode; // Mode the port was opened for int state; // Port state, OPEN/BLOCKED mixed *buff; // Pending port data } /* class client */ class server { int desc; // Identification for the server class socket accept; // Accepting socket class socket *sockets; // Connected sockets } /* class server */ int close_sockets(); int close_socket(int); private nosave class socket *sockets; protected void mudlib_setup() { sockets = ({ }); } /* mudlib_setup() */ protected void dest_me() { close_sockets(); } /* dest_me() */ int valid_index(mixed *array, int index) { if ((index < 0) || (index >= sizeof(array))) return 0; return 1; } /* valid_index() */ int socket_index(int fd) { for (int i = 0; i < sizeof(sockets); i++) if (sockets[i] -> desc == fd) return i; return -1; } /* socket_index() */ class socket *query_sockets() { return sockets; } class socket query_socket(int index) { if (!valid_index(sockets, index)) return 0; return sockets[index]; } /* query_socket() */ int query_state(int index) { if (!valid_index(sockets, index)) return 0; return sockets[index] -> mode; } /* query_state() */ protected int set_state(int index, int mode) { if (!valid_index(sockets, index)) return 0; return (sockets[index] -> mode = mode); } /* set_state() */ mixed *query_buffer(int index) { if (!valid_index(sockets, index)) return 0; return sockets[index] -> buff; } /* query_buffer() */ protected int set_buffer(int index, mixed *buff) { if (!valid_index(sockets, index)) return 0; sockets[index] -> buff = buff; return 1; } /* set_buffer() */ protected int add_buffer(int index, mixed elem) { if (!valid_index(sockets, index)) return 0; sockets[index] -> buff += ({ elem }); return 1; } /* add_buffer() */ protected int remove_buffer(int index, int elem) { if (!valid_index(sockets, index)) return 0; if (!valid_index(sockets[index] -> buff, elem)) return 0; sockets[index] -> buff = delete(sockets[index] -> buff, elem, 1); return 1; } /* remove_buffer() */ protected int send_buffer(int index) { if (!valid_index(sockets, index)) return 0; TO -> client_write_callback(sockets[index] -> desc); return 1; } /* send_buffer() */ protected int open_socket(string host, int port, int mode) { class socket sock = new(class socket); int err; if ((err = socket_create(mode, "client_read_callback", "client_close_callback")) < 0) error("Error creating socket.\n"); sock -> desc = err; if ((err = socket_bind(sock -> desc, 0)) != EESUCCESS) { socket_close(sock -> desc); error("Error binding socket.\n"); } if ((err = socket_connect(sock -> desc, host + " " + port, "client_read_callback", "client_write_callback")) != EESUCCESS) { socket_close(sock -> desc); error("Error connecting socket.\n"); } sock -> mode = mode; sock -> state = OPEN; sock -> buff = ({ }); sockets += ({ sock }); return (sizeof(sockets) - 1); } /* open_socket() */ protected int close_sockets() { while (sizeof(sockets)) if (!close_socket(0)); return 0; return 1; } /* reset_sockets() */ protected int close_socket(int index) { if (!valid_index(sockets, index)) return 0; if (socket_close(sockets[index] -> desc) != EESUCCESS) return 0; sockets = delete(sockets, index, 1); return 1; } /* close_socket() */ protected void client_close_callback(int fd) { socket_close(fd); sockets = delete(sockets, socket_index(fd), 1); return; } /* close_callback() */ protected void client_read_callback(int /* fd */, mixed /* val */) { return; } /* read_callback() */ protected void client_write_callback(int fd) { int index, err = EESUCCESS; if (!sizeof(sockets)) return; for (index = 0; index < sizeof(sockets); index++) if ((sockets[index] -> desc) == fd) break; if (!sizeof(sockets[index] -> buff)) return; switch (err = socket_write(sockets[index] -> desc, sockets[index] -> buff[0])) { case EESUCCESS: sockets[index] -> buff = delete(sockets[index] -> buff, 0, 1); sockets[index] -> state = OPEN; break; case EECALLBACK: case EEALREADY: sockets[index] -> state = BLOCKED; return; case EEWOULDBLOCK: sockets[index] -> state = BLOCKED; call_out((: client_write_callback($(fd)) :), 1); return; default: error("Error writing to socket.\n"); return; } if (sizeof(sockets[index] -> buff)) call_out((: client_write_callback($(fd)) :), 1); return; } /* write_callback() */