#include "sockets.h" #include "signal.h" #include "main.h" extern "C" { #include <errno.h> #include <fcntl.h> #include <sys/time.h> // For timeval and timerclear() #pragma implementation #ifdef _AIX #include <sys/select.h> #define _BSD #else #ifdef LINUX #define FNDELAY O_NDELAY #endif #include <sys/types.h> #include <sys/time.h> #endif char* inet_ntoa (struct in_addr); void bzero (char*, int); int getdtablesize (); } int quitting_object; Socket_Class::Socket_Class (int num_sockets){ size = num_sockets; socketlist = new int [size]; destinations = new unsigned long [size]; lowest_available = 0; for (num_sockets=0 ; num_sockets<size ; num_sockets++) {socketlist[num_sockets] = -1; destinations[num_sockets] = 0;} }; /** grow increases the number of sockets allocated for. **/ void Socket_Class::grow(int by){ int* templist, i; unsigned long* dlist; templist = new int [size + by]; dlist = new unsigned long [size + by]; for (i=0 ; i<size ; i++) {templist[i] = socketlist[i]; dlist[i] = destinations[i];} for ( ; i < (size + by) ; i++) {templist[i] = -1; destinations[i] = 0;} size += by; delete socketlist; delete destinations; socketlist = templist; destinations = dlist; }; int Socket_Class::add_connection (char* address, char* port){ int portnum = -1; sscanf (port , "%i", &portnum); if (portnum < 0) return (-1); return (add_connection (address, portnum)); }; void Socket_Class::next_available (){ for (lowest_available=0 ; lowest_available < size ; lowest_available++) if (socketlist[lowest_available] < 0) return; grow(); return; } int Socket_Class::add_connection (char* address, int port){ long sd, on, index; struct sockaddr_in server; if ((sd = socket (AF_INET , SOCK_STREAM , 0)) < 0) {perror("Socket_Class::add_connection - socket"); return (-1);} server.sin_family = AF_INET; /* server.sin_len = sizeof (server); */ server.sin_port = htons(port); server.sin_addr.s_addr = inet_addr (address); printf ("CONNECTING TO ADDRESS: %s %i\n", address, port); if (connect (sd , (struct sockaddr*) &server , sizeof(server)) < 0) {perror("Socket_Class::add_connection - connect"); return -1;} socketlist[index = lowest_available] = sd; destinations[index] = server.sin_addr.s_addr; #ifdef _AIX ioctl (sd , FIONBIO , (void*)1); /** sets socket non-blocking **/ #else fcntl (sd , F_SETFL, FNDELAY); #endif next_available(); return index; }; /** try to get a new connection -- this machine being the host. **/ int Socket_Class::add_connection (int port){ struct sockaddr_in from; int newsock, from_size, on, index; struct fd_set readers; struct timeval timeout; static long sd = setup_host_socket(port); if (sd < 0) return (-1); // Do a select on the socket with timeout set to 0. // Select returns the number of ready files so if somebody is waiting // then it should return 1. FD_ZERO (&readers); FD_SET (sd, &readers); timerclear(&timeout); if (select (getdtablesize(), &readers, NULL, NULL, &timeout) < 1) return -1; from_size = sizeof(from); newsock = accept (sd , (struct sockaddr*)&from , &from_size); if (newsock < 0) /* no connection there */ {/*perror("Socket_Class::add_connection - accept");*/ return -1;} on = 1; setsockopt (newsock , SOL_SOCKET , SO_REUSEADDR , &on, sizeof (on)); #ifdef _AIX ioctl (newsock , FIONBIO , (void*)1); /** sets socket non-blocking **/ #else fcntl (newsock, F_SETFL, FNDELAY); #endif socketlist[index = lowest_available] = newsock; destinations[index] = from.sin_addr.s_addr; next_available(); return index; } int Socket_Class::setup_host_socket (int portnum){ int sd, on; short sindex; struct sockaddr_in host; if ((sd = socket (AF_INET , SOCK_STREAM , 0)) == -1) {perror("Socket_Class::setup_host_socket - socket"); return -1;} on = 1; setsockopt (sd , SOL_SOCKET , SO_REUSEADDR , &on, sizeof (on)); host.sin_family = AF_INET; /* host.sin_len = sizeof(host); */ host.sin_port = htons(portnum); host.sin_addr.s_addr = INADDR_ANY; if (bind (sd , (struct sockaddr*) &host , sizeof(host))) {perror ("Socket_Class::setup_host_socket - bind"); close (sd); return -1;} if (listen (sd , max_waiting_connections) == -1) {perror("Socket_Class::setup_host_socket - listen"); close(sd); return -1;} ioctl (sd, FIONBIO, (void*)1); return sd; } void Socket_Class::close_connection (int index){ if (index >= 0 && index <= size) {close (socketlist[index]); socketlist[index] = 0; if (index < lowest_available) lowest_available = index; socketlist[index] = -1;} } int Socket_Class::send (int index, char* buffer, int size){ return write(socketlist[index] , buffer , size); }; String* Socket_Class::receive (int index){ int received; static char temp [max_read_chunk]; String* outstring = NULL; String* tempstring; do {received = read (socketlist[index] , temp , max_read_chunk); if (! received) {close_connection (index); quitting_object = index; return NULL;} if (!outstring) {if (received <= 0) return NULL; else outstring = new String (temp , received);} else {tempstring = new String (temp , received); (*outstring) += (*tempstring); delete tempstring; tempstring = NULL;}} while (received == max_read_chunk); return outstring; } String* Socket_Class::wait_receive (int index){ String* tempstring; ioctl (socketlist[index] , FIONBIO , (void*)0); /** sets socket blocking **/ while (! (tempstring = receive (index))); ioctl (socketlist[index] , FIONBIO , (void*)1); /*sets socket non-blocking*/ return tempstring; } int broken_pipe; void socket_sigcatcher (int unused){ broken_pipe = 1; }; Mud_Sockets::Mud_Sockets (int num_sockets) : Socket_Class (num_sockets){ int i; signal ((SIGPIPE), socket_sigcatcher); objectlist = new int [num_sockets]; incoming_data = new String* [num_sockets]; for (i = 0 ; i<num_sockets ; i++) incoming_data[i] = NULL; } Mud_Sockets::~Mud_Sockets (){ int i; delete objectlist; objectlist = NULL; for (i=0 ; i<size ; i++) {if (incoming_data[i]) {delete incoming_data[i]; incoming_data[i] = NULL;}} } void Mud_Sockets::grow (int by){ int i, *newlist = new int [size + by]; String** newdata = new String* [size + by]; for (i = 0; i < size ; i++) {newlist[i] = objectlist[i]; newdata[i] = incoming_data[i];} delete objectlist; delete incoming_data; objectlist = newlist; incoming_data = newdata; Socket_Class::grow (by); } int Mud_Sockets::add_connection (int port){ int i; if ((i = Socket_Class::add_connection(port)) >= 0) {objectlist[i] = 0; incoming_data [i] = new String ("");} return i; } int Mud_Sockets::add_connection (char* address, char* port, int object){ int i; if ((i = Socket_Class::add_connection(address, port)) >= 0) {incoming_data [i] = new String (""); objectlist[i] = object;} return i; } int Mud_Sockets::add_connection (char* address, int port, int object){ int i; if ((i = Socket_Class::add_connection(address, port)) >= 0) {incoming_data [i] = new String (""); objectlist[i] = object;} return i; } int Mud_Sockets::add_connection (String* full_address, int object){ String s1, s2; if ((full_address->freq(" ") != 1) || (full_address->index(" ") > 16) || (full_address->index(" ") < 8)) return -1; s1 = full_address->before(" "); s2 = full_address->after(" "); if (!(s1.length() && s2.length())) return -1; return add_connection ((char*)(s1.chars()), (char*)(s2.chars()), object); } void Mud_Sockets::close_connection (int index){ Socket_Class::close_connection (index); if (index >= 0 && index <= size) {delete incoming_data[index]; incoming_data[index] = NULL; objectlist[index] = -1;} } int Mud_Sockets::break_connection (int o_num){ int i; for (i=0 ; i<size ; i++) if (objectlist[i] == o_num) {close_connection (i); return 1;} return 0; } String* Mud_Sockets::get_destination (int o_num){ int i; struct in_addr ina; struct hostent* dst; char* addrstr; char hex_addr [16]; String* tempstring = NULL; for (i=0 ; i<size ; i++) if (objectlist[i] == o_num) {ina.s_addr = destinations[i]; dst = gethostbyaddr ((void*) &ina, sizeof(ina), AF_INET); if (dst) tempstring = new String (dst->h_name); else {addrstr = inet_ntoa (ina); if (addrstr != (char*)(-1)) tempstring = new String (addrstr);} return tempstring;} return NULL; } int Mud_Sockets::move_connection (int oldobj , int newobj){ int i; for (i=0 ; i<size ; i++) if (objectlist[i] == oldobj) {objectlist[i] = newobj; return 1;} return 0; } String* Mud_Sockets::receive (int index){ String *tempstring; if (socketlist[index] < 0) return NULL; quitting_object = -1; if (!objectlist[index]) // #0 shouldn\'t process any input return NULL; tempstring = Socket_Class::receive (index); if (incoming_data[index]->empty() && !tempstring) return NULL; if (tempstring) {(*incoming_data[index]) += *tempstring; delete tempstring; tempstring = NULL;} if (incoming_data[index]->contains ("\n")) {if (incoming_data[index]->contains("\r")) tempstring = new String (incoming_data[index]->before ("\r")); else tempstring = new String (incoming_data[index]->before ("\n")); *incoming_data[index] = incoming_data[index]->after ("\n");} return tempstring; } String* Mud_Sockets::wait_receive (int index){ String* tempstring; ioctl (socketlist[index] , FIONBIO , (void*)0); /* sets socket blocking */ while (! (tempstring = receive (index))); ioctl (socketlist[index], FIONBIO , (void*)1); /*sets socket non-blocking*/ return tempstring; } int Mud_Sockets::send_line (int objectnum, String* s){ int i; broken_pipe = 0; for (i=0 ; i<size ; i++) if (objectlist[i] == objectnum) {// s->gsub("\n", "\r\n"); // optimize this later. send (i , (char*)s->chars() , s->length()); if (broken_pipe) {close_connection (i); broken_pipe = 0; signal ((SIGPIPE), socket_sigcatcher); return -1;} return 1;} return 0; } input_line Mud_Sockets::receive (){ int i; String* read_string; Value* tempval; static struct One_Line incoming; for (i = 0 ; i < size ; i++) {if (socketlist[i] >= 0) {if (read_string = receive (i)) {incoming.instring = read_string; incoming.object_num = objectlist[i]; return &incoming;} else if (quitting_object >= 0) {tempval = new Value (new String ("quit"), SYM); all_processes.add_process (objectlist[quitting_object] , tempval , NULL); tempval->release();}}} return NULL; };