/* * * AMX Mod X Module * Basic Socket Functions * * Codebase from Ivan, -g-s-ivan@web.de (AMX 0.9.3) * Modification by Olaf Reusch, kenterfie@hlsw.de (AMXX 0.16, AMX 0.96) * Modification by David Anderson, dvander@tcwonline.org (AMXx 0.20) * * Bugs/Fixes * * v0.1 * - code structure renewed */ #include #include #include #include #ifdef _WIN32 /* Windows */ #include #include #define socklen_t int #else /* Unix/Linux */ #include #include #include #include #include #include #define closesocket(s) close(s) #endif // AMX Headers #include "amxxmodule.h" #define SOCKET_TCP 1 #define SOCKET_UDP 2 // And global Variables: // native socket_open(_hostname[], _port, _protocol = SOCKET_TCP, &_error); static cell AMX_NATIVE_CALL socket_open(AMX *amx, cell *params) /* 2 param */ { unsigned int port = params[2]; int len; char* hostname = MF_GetAmxString(amx,params[1],0,&len); // Get the hostname from AMX if(len == 0) { // just to prevent to work with a nonset hostname params[4] = 2; // server unknown return -1; } params[4] = 0; // params[4] is error backchannel struct sockaddr_in server; struct hostent *host_info; unsigned long addr; int sock=-1; int contr; // Create a Socket sock = socket(AF_INET, params[3]==SOCKET_TCP?SOCK_STREAM:SOCK_DGRAM, 0); if (sock < 0) { // Error, couldn't create a socket, so set an error and return. params[4] = 1; return -1; } // Clear the server structure (set everything to 0) memset( &server, 0, sizeof (server)); // Test the hostname, and resolve if needed if ((addr = inet_addr(hostname)) != INADDR_NONE) { // seems like hostname is a numeric ip, so put it into the structure memcpy( (char *)&server.sin_addr, &addr, sizeof(addr)); } else { // hostname is a domain, so resolve it to an ip host_info = gethostbyname(hostname); if (host_info == NULL) { // an error occured, the hostname is unknown params[4] = 2; // server unknown return -1; } // If not, put it in the Server structure memcpy( (char *)&server.sin_addr, host_info->h_addr, host_info->h_length); } // Set the type of the Socket server.sin_family = AF_INET; // Change the port to network byte order, and put it into the structure server.sin_port = htons(port); // Not, let's try to open a connection to the server contr = connect(sock, (struct sockaddr*)&server, sizeof( server)); if (contr < 0) { // If an error occured cancel params[4] = 3; //error while connecting return -1; } // Everything went well, so return the socket return sock; } // native socket_close(_socket); static cell AMX_NATIVE_CALL socket_close(AMX *amx, cell *params) /* 2 param */ { int socket = params[1]; //PRINT_CONSOLE("Function: Close | Socket: %i\n", socket); #ifdef _WIN32 // On windows, check whether the sockets are initialized correctly closesocket(socket); #else // Close the socket (linux/unix styled systems) close(socket); #endif return 0; } // native socket_change(_socket, _timeout=100000); // 1 sec =1000000 usec static cell AMX_NATIVE_CALL socket_change(AMX *amx, cell *params) /* 2 param */ { int socket = params[1]; unsigned int timeout = params[2]; //PRINT_CONSOLE("Function: Change | Socket: %i | Timeout: %i\n", socket, timeout); // We need both a timeout structure and a fdset for our filedescriptor fd_set rfds; struct timeval tv; // Fill in ... FD_ZERO(&rfds); FD_SET(socket, &rfds); tv.tv_sec = 0; tv.tv_usec = timeout; // Now we "select", which will show us if new data is waiting in the socket's buffer if (select(socket+1, &rfds, NULL, NULL, &tv)) return 1; // Ok, new data, return it else return 0; // No new data, return it } // native socket_recv(_socket, _data[], _length); static cell AMX_NATIVE_CALL socket_recv(AMX *amx, cell *params) /* 2 param */ { int socket = params[1]; int length = params[3]; int tmp = -1; // First we dynamicly allocate a block of heap memory for recieving our data char *tmpchar = new char[length]; if(tmpchar == NULL) return -1; // If we didn't got a block, we have to quit here to avoid sigsegv // And set it all to 0, because the memory could contain old trash memset(tmpchar, 0, length); // Now we recieve tmp = recv(socket, tmpchar, length-1, 0); if (tmp == SOCKET_ERROR) { delete [] tmpchar; return SOCKET_ERROR; } // And put a copy of our recieved data into amx's string tmpchar[tmp]='\0'; int nlen = 0; //int max = params[3]; int max = length-1; const char* src = tmpchar; cell* dest = MF_GetAmxAddr(amx,params[2]); while(max--&&nlen