// socket extension include file #if defined _socket_included #endinput #endif #define _socket_included #include enum SocketType { SOCKET_TCP = 1, SOCKET_UDP, SOCKET_RAW } enum { EMPTY_HOST = 1, NO_HOST, CONNECT_ERROR, SEND_ERROR, BIND_ERROR, RECV_ERROR, LISTEN_ERROR } /*************************************************************************************************/ /******************************************** options ********************************************/ /*************************************************************************************************/ /** * Options available for SocketSetOption() * * @note modifying these options is not required for normal operation, you can skip the whole * section in most cases. */ enum SocketOption { /** * If this option is set the socket extension will try to concatenate SocketReceive callbacks. * * This will possibly lower the amount of callbacks passed to SourceMod plugins and improve the * performance. The socket extension will preserve the packet order. * * @note this doesn't prevent multiple callbacks, it only reduces them for high load. * @note this will not truncate packets below 4096 bytes, setting it lower will be ignored * @note set this option if you expect lots of data in a short timeframe * @note don't forget to set your buffer sizes at least to the value passed to this function, but * always at least to 4096 * * @param int 0(=default) to disable or max. chunk size including \0 terminator in bytes * @return bool true on success */ ConcatenateCallbacks = 1, /** * If this option is set the socket extension will enforce a mutex lock in the GameFrame() hook. * * This will ensure that callbacks will be processed every gameframe as fast as possible with the * drawback of potentially creating lag. It's not recommended to set this option for most cases. * If this option is not set the gameframe will be skipped if quietly obtaining a lock fails. * * @note combine this with CallbacksPerFrame for best performance * @note this option will affect all sockets from all plugins, use it with caution! * * @param bool whether to force locking or not * @return bool true on success */ ForceFrameLock, /** * This will specify the maximum amount of callbacks processed in every gameframe. * * The default value for this option is 1, setting it higher will possibly increase networking * performance but may cause lag if it's set too high. * The amount of callbacks actually being processed is limited by not being able to quietly obtain * a lock (see ForceFrameLock) and the amount of callbacks in the queue. * * @note this option will affect all sockets from all plugins, use it with caution! * * @param int maximum amount of callbacks per gameframe * @return bool true on success */ CallbacksPerFrame, /** * If this option is set the socket will be allowed to send broadcast messages in case the protocol * supports it. This is a wrapper for setting SO_BROADCAST. * * @param bool whether to allow broadcasting or not * @return bool true on success */ SocketBroadcast, /** * If this option is set SocketBind() will allow reusing local adresses in case the protocol * supports it. This is a wrapper for setting SO_REUSEADDR. * * @param bool whether to allow broadcasting or not * @return bool true on success */ SocketReuseAddr, /** * If this option is set the socket will try to keep the connection alive by periodically sending * messages if the protocol supports it. This is a wrapper for setting SO_KEEPALIVE. * * @param bool whether to allow broadcasting or not * @return bool true on success */ SocketKeepAlive, /** * This option specifies how long a socket will wait if it's being closed and its send buffer is * still filled. This is a wrapper for setting SO_LINGER. * * @param int 0 (=default) to disable or time in s * @return bool true on success */ SocketLinger, /** * If this option is set out-of-band data will be inlined into the normal receive stream. This is a * wrapper for setting SO_OOBINLINE. * * @param bool whether to inline out-of-band data or not * @return bool true on success */ SocketOOBInline, /** * This option specifies how large the send buffer will be. This is a wrapper for setting * SO_SNDBUF. * * @param int size in bytes * @return bool true on success */ SocketSendBuffer, /** * This option specifies how large the receive buffer will be. This is a wrapper for setting * SO_RCVBUF. * * @param int size in bytes * @return bool true on success */ SocketReceiveBuffer, /** * If this option is set outgoing messages will ignore the default routing facilities if the * protocol implementation supports it. The remote site should be directly connected to the sender. * This is a wrapper for setting SO_DONTROUTE. * * @param bool whether to skip default routing or not * @return bool true on success */ SocketDontRoute, /** * This option specifies the minimum amount of data to receive before processing it. This is a * wrapper for setting SO_RCVLOWAT. * * @note this can probably block the extension, use it with caution! * * @param int size in bytes * @return bool true on success */ SocketReceiveLowWatermark, /** * This option specifies how long a socket will try to receive data before it times out and * processes the data. This is a wrapper for setting SO_RCVTIMEO. * * @param int 0 (=default) to disable or time in ms * @return bool true on success */ SocketReceiveTimeout, /** * This option specifies the minimum amount of data required in the send buffer before starting to * send it. This is a wrapper for setting SO_SNDLOWAT. * * @note this can probably block the extension, use it with caution! * * @param int size in bytes * @return bool true on success */ SocketSendLowWatermark, /** * This option specifies how long a socket will try to send data before it times out and * retries it later. This is a wrapper for setting SO_SNDTIMEO. * * @param int 0 (=default) to disable or time in ms * @return bool true on success */ SocketSendTimeout, /** * If this option is set the socket extension will display debugging messages in the server console/logs. * * @param bool whether to enable debugging or not * @return bool true on success */ DebugMode } // Methodmap methodmap Socket < Handle { /** * Creates a new socket. * * @note this function may be relatively expensive, reuse sockets if possible * * @param SocketType protocol The protocol to use, SOCKET_TCP is default * @param SocketErrorCB efunc The error callback * @return Handle The socket handle. Returns INVALID_HANDLE on failure */ public native Socket(SocketType protocol=SOCKET_TCP, SocketErrorCB efunc); /** * Binds the socket to a local address * * @param String hostname The hostname (or IP) to bind the socket to. * @param int port The port to bind the socket to. * @return bool true on success */ public native bool Bind(const char[] hostname, int port); /** * Connects a socket * * @note this native is threaded, it may be still running after it executed, use the connect callback * @note invokes the SocketError callback with errorType = CONNECT_ERROR or EMPTY_HOST if it fails * @note invokes the SocketConnect callback if it succeeds * * @param SocketConnectCB cfunc The connect callback * @param SocketReceiveCB rfunc The receive callback * @param SocketDisconnectCB dfunc The disconnect callback * @param String hostname The hostname (or IP) to connect to. * @param int port The port to connect to. */ public native void Connect(SocketConnectCB cfunc, SocketReceiveCB rfunc, SocketDisconnectCB dfunc, const char[] hostname, int port); /** * Disconnects a socket * * @note this will not close the handle, the socket will be reset to a state similar to after SocketCreate() * @note this won't trigger any disconnect/error callbacks * * @return bool true on success */ public native bool Disconnect(); /** * Makes a socket listen for incoming connections * * @param SocketIncomingCB ifunc The callback for incoming connections * @return bool true on success */ public native bool Listen(SocketIncomingCB ifunc); /** * Sends data through the socket. * * @note specify size for binary safe operation * @note if size is not specified the \0 terminator will not be included * @note This native is threaded, it may be still running after it executed (not atomic). * @note Use the SendqueueEmpty callback to determine when all data has been successfully sent. * @note The socket extension will ensure that the data will be send in the correct order and split * the data if required. * * @param String data The data to send. */ public native void Send(const char[] data, int size = -1); /** * Sends UDP data through the socket to a specific destination. * * @note specify size for binary safe operation * @note if size is not specified the \0 terminator will not be included * @note This native is threaded, it may be still running after it executed (not atomic). * @note Use the SendqueueEmpty callback to determine when all data has been successfully sent. * @note The socket extension will ensure that the data will be send in the correct order and split * the data if required. * * @param String data The data to send. * @param String hostname The hostname (or IP) to send to. * @param int port The port to send to. */ public native void SendTo(const char[] data, int size = -1, const char[] hostname, int port); /** * Set a socket option. * * @param SocketOption option The option to modify (see enum SocketOption for details). * @param int value The value to set the option to. * @return int 1 on success. */ public native int SetOption(SocketOption option, int value); /** * Defines the callback function for when the socket receives data * * @note this is only useful and required for child-sockets spawned by listen-sockets * (otherwise you already set it in SocketConnect()) * * @param SocketReceiveCB rfunc The receive callback */ public native void SetReceiveCallback(SocketReceiveCB rfunc); /** * Defines the callback function for when the socket sent all items in its send queue * * @note this must be called AFTER sending (queueing) the data * @note if no send-data is queued this will fire the callback itself * @note the callback is guaranteed to fire * * @param SocketDisconnectCB dfunc The disconnect callback */ public native void SetSendqueueEmptyCallback(SocketSendqueueEmptyCB sfunc); /** * Defines the callback function for when the socket was properly disconnected by the remote side * * @note this is only useful and required for child-sockets spawned by listen-sockets * (otherwise you already set it in SocketConnect()) * * @param SocketDisconnectCB dfunc The disconnect callback */ public native void SetDisconnectCallback(SocketDisconnectCB dfunc); /** * Defines the callback function for when the socket triggered an error * * @note this is only useful and required for child-sockets spawned by listen-sockets * (otherwise you already set it in SocketCreate()) * * @param SocketErrorCB efunc The error callback */ public native void SetErrorCallback(SocketErrorCB efunc); /** * Sets the argument being passed to callbacks * * @param any arg The argument to set */ public native void SetArg(any arg); /** * Retrieve the local system's hostname as the command "hostname" does. * * @param dest Destination string buffer to copy to. * @param destLen Destination buffer length (includes null terminator). * * @return 1 on success */ public static native int GetHostName(char[] dest, int destLen); /** * Returns whether a socket is connected or not. * * @return bool The connection status */ property bool Connected { public native get(); } } /*************************************************************************************************/ /******************************************* callbacks *******************************************/ /*************************************************************************************************/ /** * triggered if a normal sockets finished connecting and is ready to be used * * @param socket The socket handle pointing to the calling socket * @param arg The argument set by SocketSetArg() * @noreturn */ typedef SocketConnectCB = function void (Socket socket, any arg); /** * triggered if a listening socket received an incoming connection and is ready to be used * * @note The child-socket won't work until receive-, disconnect-, and errorcallback for it are set. * * @param Socket socket The socket handle pointing to the calling listen-socket * @param Socket newSocket The socket handle to the newly spawned child socket * @param String remoteIP The remote IP * @param any arg The argument set by SocketSetArg() for the listen-socket * @noreturn */ typedef SocketIncomingCB = function void (Socket socket, Socket newSocket, const char[] remoteIP, int remotePort, any arg); /** * triggered if a socket receives data * * @note This is binary safe if you always use dataSize for operations on receiveData[] * @note packets may be split up into multiple chunks -> multiple calls to the receive callback * @note if not set otherwise by SocketSetOption(..., ConcatenateCallbacks, ...) receiveData will * never be longer than 4096 characters including \0 terminator * * @param Socket socket The socket handle pointing to the calling socket * @param String receiveData The data which arrived, 0-terminated at receiveData[dataSize] * @param int dataSize The length of the arrived data excluding the 0-termination * @param any arg The argument set by SocketSetArg() for the socket * @noreturn */ typedef SocketReceiveCB = function void (Socket socket, const char[] receiveData, const int dataSize, any arg); /** * called after a socket sent all items in its send queue successfully * * @param Socket socket The socket handle pointing to the calling socket * @param any arg The argument set by SocketSetArg() for the socket * @noreturn */ typedef SocketSendqueueEmptyCB = function void (Socket socket, any arg); /** * called if a socket has been properly disconnected by the remote side * * @note You should call CloseHandle(socket) or reuse the socket before this function ends * * @param Socket socket The socket handle pointing to the calling socket * @param any arg The argument set by SocketSetArg() for the socket * @noreturn */ typedef SocketDisconnectCB = function void (Socket socket, any arg); /** * called if an unrecoverable error occured, close the socket without an additional call to a disconnect callback * * @note You should call CloseHandle(socket) or reuse the socket before this function ends * * @param Socket socket The socket handle pointing to the calling socket * @param int errorType The error type, see defines above * @param int errorNum The errno, see errno.h for details * @param any arg The argument set by SocketSetArg() for the socket * @noreturn */ typedef SocketErrorCB = function void (Socket socket, const int errorType, const int errorNum, any arg); /*************************************************************************************************/ /******************************************** natives ********************************************/ /*************************************************************************************************/ /** * Returns whether a socket is connected or not. * * @param socket Socket handle to check * @return bool The connection status */ native bool SocketIsConnected(Handle socket); /** * Creates a new socket. * * @note this function may be relatively expensive, reuse sockets if possible * * @param SocketType protocol The protocol to use, SOCKET_TCP is default * @param SocketErrorCB efunc The error callback * @return Socket The socket handle. Returns INVALID_HANDLE on failure */ native Socket SocketCreate(SocketType protocol=SOCKET_TCP, SocketErrorCB efunc); /** * Binds the socket to a local address * * @param Handle socket The handle of the socket to be used. * @param String hostname The hostname (or IP) to bind the socket to. * @param int port The port to bind the socket to. * @return bool true on success */ native bool SocketBind(Handle socket, const char[] hostname, int port); /** * Connects a socket * * @note this native is threaded, it may be still running after it executed, use the connect callback * @note invokes the SocketError callback with errorType = CONNECT_ERROR or EMPTY_HOST if it fails * @note invokes the SocketConnect callback if it succeeds * * @param Handle socket The handle of the socket to be used. * @param SocketConnectCB cfunc The connect callback * @param SocketReceiveCB rfunc The receive callback * @param SocketDisconnectCB dfunc The disconnect callback * @param String hostname The hostname (or IP) to connect to. * @param int port The port to connect to. * @noreturn */ native void SocketConnect(Handle socket, SocketConnectCB cfunc, SocketReceiveCB rfunc, SocketDisconnectCB dfunc, const char[] hostname, int port); /** * Disconnects a socket * * @note this will not close the handle, the socket will be reset to a state similar to after SocketCreate() * @note this won't trigger any disconnect/error callbacks * * @noreturn */ native bool SocketDisconnect(Handle socket); /** * Makes a socket listen for incoming connections * * @param Handle socket The handle of the socket to be used. * @param SocketIncomingCB ifunc The callback for incoming connections * @return bool true on success */ native bool SocketListen(Handle socket, SocketIncomingCB ifunc); /** * Sends data through the socket. * * @note specify size for binary safe operation * @note if size is not specified the \0 terminator will not be included * @note This native is threaded, it may be still running after it executed (not atomic). * @note Use the SendqueueEmpty callback to determine when all data has been successfully sent. * @note The socket extension will ensure that the data will be send in the correct order and split * the data if required. * * @param Handle socket The handle of the socket to be used. * @param String data The data to send. * @noreturn */ native void SocketSend(Handle socket, const char[] data, int size=-1); /** * Sends UDP data through the socket to a specific destination. * * @note specify size for binary safe operation * @note if size is not specified the \0 terminator will not be included * @note This native is threaded, it may be still running after it executed (not atomic). * @note Use the SendqueueEmpty callback to determine when all data has been successfully sent. * @note The socket extension will ensure that the data will be send in the correct order and split * the data if required. * * @param Handle socket The handle of the socket to be used. * @param String data The data to send. * @param String hostname The hostname (or IP) to send to. * @param int port The port to send to. * @noreturn */ native void SocketSendTo(Handle socket, const char[] data, int size=-1, const char[] hostname, int port); /** * Set a socket option. * * @param Handle socket The handle of the socket to be used. May be INVALID_HANDLE if not essential. * @param SocketOption option The option to modify (see enum SocketOption for details). * @param cellt_ value The value to set the option to. * @return int 1 on success. */ native int SocketSetOption(Handle socket, SocketOption option, int value); /** * Defines the callback function for when the socket receives data * * @note this is only useful and required for child-sockets spawned by listen-sockets * (otherwise you already set it in SocketConnect()) * * @param Handle socket The handle of the socket to be used. * @param SocketReceiveCB rfunc The receive callback * @noreturn */ native void SocketSetReceiveCallback(Handle socket, SocketReceiveCB rfunc); /** * Defines the callback function for when the socket sent all items in its send queue * * @note this must be called AFTER sending (queueing) the data * @note if no send-data is queued this will fire the callback itself * @note the callback is guaranteed to fire * * @param Handle socket The handle of the socket to be used. * @param SocketDisconnectCB dfunc The disconnect callback * @noreturn */ native void SocketSetSendqueueEmptyCallback(Handle socket, SocketSendqueueEmptyCB sfunc); /** * Defines the callback function for when the socket was properly disconnected by the remote side * * @note this is only useful and required for child-sockets spawned by listen-sockets * (otherwise you already set it in SocketConnect()) * * @param Handle socket The handle of the socket to be used. * @param SocketDisconnectCB dfunc The disconnect callback * @noreturn */ native void SocketSetDisconnectCallback(Handle socket, SocketDisconnectCB dfunc); /** * Defines the callback function for when the socket triggered an error * * @note this is only useful and required for child-sockets spawned by listen-sockets * (otherwise you already set it in SocketCreate()) * * @param Handle socket The handle of the socket to be used. * @param SocketErrorCB efunc The error callback * @noreturn */ native void SocketSetErrorCallback(Handle socket, SocketErrorCB efunc); /** * Sets the argument being passed to callbacks * * @param Handle socket The handle of the socket to be used. * @param any arg The argument to set * @noreturn */ native void SocketSetArg(Handle socket, any arg); /** * Retrieve the local system's hostname as the command "hostname" does. * * @param dest Destination string buffer to copy to. * @param destLen Destination buffer length (includes null terminator). * * @return 1 on success */ native int SocketGetHostName(char[] dest, int destLen); /** * _________________Do not edit below this line!_______________________ */ public Extension __ext_socket = { name = "Socket", file = "socket.ext", #if defined AUTOLOAD_EXTENSIONS autoload = 1, #else autoload = 0, #endif #if defined REQUIRE_EXTENSIONS required = 1, #else required = 0, #endif }; #if !defined REQUIRE_EXTENSIONS public void __ext_socket_SetNTVOptional() { MarkNativeAsOptional("Socket.Socket"); MarkNativeAsOptional("Socket.Bind"); MarkNativeAsOptional("Socket.Connect"); MarkNativeAsOptional("Socket.Disconnect"); MarkNativeAsOptional("Socket.Listen"); MarkNativeAsOptional("Socket.Send"); MarkNativeAsOptional("Socket.SendTo"); MarkNativeAsOptional("Socket.SetOption"); MarkNativeAsOptional("Socket.SetReceiveCallback"); MarkNativeAsOptional("Socket.SetSendqueueEmptyCallback"); MarkNativeAsOptional("Socket.SetDisconnectCallback"); MarkNativeAsOptional("Socket.SetErrorCallback"); MarkNativeAsOptional("Socket.SetArg"); MarkNativeAsOptional("Socket.GetHostName"); MarkNativeAsOptional("Socket.Connected.get"); MarkNativeAsOptional("SocketIsConnected"); MarkNativeAsOptional("SocketCreate"); MarkNativeAsOptional("SocketBind"); MarkNativeAsOptional("SocketConnect"); MarkNativeAsOptional("SocketDisconnect"); MarkNativeAsOptional("SocketListen"); MarkNativeAsOptional("SocketSend"); MarkNativeAsOptional("SocketSendTo"); MarkNativeAsOptional("SocketSetOption"); MarkNativeAsOptional("SocketSetReceiveCallback"); MarkNativeAsOptional("SocketSetSendqueueEmptyCallback"); MarkNativeAsOptional("SocketSetDisconnectCallback"); MarkNativeAsOptional("SocketSetErrorCallback"); MarkNativeAsOptional("SocketSetArg"); MarkNativeAsOptional("SocketGetHostName"); } #endif