plibsys 0.0.5
|
Socket implementation. More...
Go to the source code of this file.
Typedefs | |
typedef enum PSocketProtocol_ | PSocketProtocol |
Socket protocols specified by the IANA. | |
typedef enum PSocketType_ | PSocketType |
Socket types. | |
typedef enum PSocketDirection_ | PSocketDirection |
Socket direction for data operations. | |
typedef enum PSocketIOCondition_ | PSocketIOCondition |
Socket IO waiting (polling) conditions. | |
typedef struct PSocket_ | PSocket |
Socket opaque structure. | |
Enumerations | |
enum | PSocketProtocol_ { P_SOCKET_PROTOCOL_UNKNOWN = -1 , P_SOCKET_PROTOCOL_DEFAULT = 0 , P_SOCKET_PROTOCOL_TCP = 6 , P_SOCKET_PROTOCOL_UDP = 17 , P_SOCKET_PROTOCOL_SCTP = 132 } |
Socket protocols specified by the IANA. More... | |
enum | PSocketType_ { P_SOCKET_TYPE_UNKNOWN = 0 , P_SOCKET_TYPE_STREAM = 1 , P_SOCKET_TYPE_DATAGRAM = 2 , P_SOCKET_TYPE_SEQPACKET = 3 } |
Socket types. More... | |
enum | PSocketDirection_ { P_SOCKET_DIRECTION_SND = 0 , P_SOCKET_DIRECTION_RCV = 1 } |
Socket direction for data operations. More... | |
enum | PSocketIOCondition_ { P_SOCKET_IO_CONDITION_POLLIN = 1 , P_SOCKET_IO_CONDITION_POLLOUT = 2 } |
Socket IO waiting (polling) conditions. More... | |
Functions | |
P_LIB_API PSocket * | p_socket_new_from_fd (pint fd, PError **error) |
Creates a new PSocket object from a file descriptor. | |
P_LIB_API PSocket * | p_socket_new (PSocketFamily family, PSocketType type, PSocketProtocol protocol, PError **error) |
Creates a new PSocket object. | |
P_LIB_API pint | p_socket_get_fd (const PSocket *socket) |
Gets an underlying file descriptor of a socket. | |
P_LIB_API PSocketFamily | p_socket_get_family (const PSocket *socket) |
Gets a socket address family. | |
P_LIB_API PSocketType | p_socket_get_type (const PSocket *socket) |
Gets a socket type. | |
P_LIB_API PSocketProtocol | p_socket_get_protocol (const PSocket *socket) |
Gets a socket data transfer protocol. | |
P_LIB_API pboolean | p_socket_get_keepalive (const PSocket *socket) |
Checks whether the SO_KEEPALIVE flag is enabled. | |
P_LIB_API pboolean | p_socket_get_blocking (PSocket *socket) |
Checks whether socket is used in a blocking mode. | |
P_LIB_API pint | p_socket_get_listen_backlog (const PSocket *socket) |
Gets a socket listen backlog parameter. | |
P_LIB_API pint | p_socket_get_timeout (const PSocket *socket) |
Gets a socket timeout for blocking I/O operations. | |
P_LIB_API PSocketAddress * | p_socket_get_local_address (const PSocket *socket, PError **error) |
Gets a socket local (bound) address. | |
P_LIB_API PSocketAddress * | p_socket_get_remote_address (const PSocket *socket, PError **error) |
Gets a socket remote endpoint address. | |
P_LIB_API pboolean | p_socket_is_connected (const PSocket *socket) |
Checks whether a socket is connected. | |
P_LIB_API pboolean | p_socket_is_closed (const PSocket *socket) |
Checks whether a socket is closed. | |
P_LIB_API pboolean | p_socket_check_connect_result (PSocket *socket, PError **error) |
Checks a connection state after calling p_socket_connect(). | |
P_LIB_API void | p_socket_set_keepalive (PSocket *socket, pboolean keepalive) |
Sets the socket SO_KEEPALIVE flag. | |
P_LIB_API void | p_socket_set_blocking (PSocket *socket, pboolean blocking) |
Sets a socket blocking mode. | |
P_LIB_API void | p_socket_set_listen_backlog (PSocket *socket, pint backlog) |
Sets a socket listen backlog parameter. | |
P_LIB_API void | p_socket_set_timeout (PSocket *socket, pint timeout) |
Sets a socket timeout value for blocking I/O operations. | |
P_LIB_API pboolean | p_socket_bind (const PSocket *socket, PSocketAddress *address, pboolean allow_reuse, PError **error) |
Binds a socket to a given local address. | |
P_LIB_API pboolean | p_socket_connect (PSocket *socket, PSocketAddress *address, PError **error) |
Connects a socket to a given remote address. | |
P_LIB_API pboolean | p_socket_listen (PSocket *socket, PError **error) |
Puts a socket into a listening state. | |
P_LIB_API PSocket * | p_socket_accept (const PSocket *socket, PError **error) |
Accepts a socket incoming connection. | |
P_LIB_API pssize | p_socket_receive (const PSocket *socket, pchar *buffer, psize buflen, PError **error) |
Receives data from a given socket. | |
P_LIB_API pssize | p_socket_receive_from (const PSocket *socket, PSocketAddress **address, pchar *buffer, psize buflen, PError **error) |
Receives data from a given socket and saves a remote address. | |
P_LIB_API pssize | p_socket_send (const PSocket *socket, const pchar *buffer, psize buflen, PError **error) |
Sends data through a given socket. | |
P_LIB_API pssize | p_socket_send_to (const PSocket *socket, PSocketAddress *address, const pchar *buffer, psize buflen, PError **error) |
Sends data through a given socket to a given address. | |
P_LIB_API pboolean | p_socket_close (PSocket *socket, PError **error) |
Closes a socket. | |
P_LIB_API pboolean | p_socket_shutdown (PSocket *socket, pboolean shutdown_read, pboolean shutdown_write, PError **error) |
Shutdowns a full-duplex socket data transfer link. | |
P_LIB_API void | p_socket_free (PSocket *socket) |
Closes a socket (if not closed yet) and frees its resources. | |
P_LIB_API pboolean | p_socket_set_buffer_size (const PSocket *socket, PSocketDirection dir, psize size, PError **error) |
Sets the socket buffer size for a given data transfer direction. | |
P_LIB_API pboolean | p_socket_io_condition_wait (const PSocket *socket, PSocketIOCondition condition, PError **error) |
Waits for a specified I/O condition on socket. | |
Socket implementation.
A socket is a communication primitive usually working over a network. You can send data to someone's socket by its address and receive data as well through the same socket. This is one of the most popular and standardizated way for network communication supported by vast majority of all the modern operating systems. It also hides all the details of underlying networking protocols and other layers, providing a unified and transparent approach for communication.
There are two kinds of socket:
Connection oriented sockets work with data in a stream, connection-less sockets work with data using independent packets (datagrams). The former guarantees delivery, while the latter doesn't (actually some connection-less protocols provide delivery quarantee, i.e. SCTP).
PSocket supports INET and INET6 address families which specify network communication addresses used by created sockets: IPv4 and IPv6, correspondingly. INET6 family is not supported on all platforms, refer to documentation for a particular target platform.
PSocket supports different underlying data transfer protocols: TCP, UDP and others. Note that not all protocols can be used with any socket type, i.e. you can use the TCP protocol with a stream socket, but you can't use the UDP protocol with the stream socket. You can specify P_SOCKET_PROTOCOL_DEFAULT protocol when creating a socket and appropriate the best matching socket type will be selected.
In a common socket communication case server and client sides are involved. Depending on whether sockets are connection oriented, there are slightly different action sequences for data exchanging.
For connection oriented sockets the server side acts as following:
The client side acts as following:
After the connection was successfully established, both the sides can send and receive data from each other using p_socket_send() and p_socket_receive(). Binding of the client socket is actually optional.
When using connection-less sockets, all is a bit simpler. There is no server side or client side - anyone can send and receive data without establishing a connection. Just create a socket, bind it to a local address and send/receive data using p_socket_send_to() and p_socket_receive(). You can also call p_socket_connect() on a connection-less socket to prevent passing the target address each time when sending data and then use p_socket_send() instead of p_socket_send_to(). This time binding is required.
PSocket can operate in blocking and non-blocking (async) modes. By default it is in the blocking mode. When using PSocket in the blocking mode each non-immediate call on it will block a caller thread until an I/O operation will be completed. For example, the p_socket_accept() call can wait for an incoming connection for some time, and calling it on a blocking socket will prevent the caller thread from further execution until it receives a new incoming connection. In the non-blocking mode any call will return immediately and you must check its result. You can set the socket mode using p_socket_set_blocking().
PSocket always puts a socket descriptor (or SOCKET handle on Windows) into the non-blocking mode and emulates the blocking mode if required. If you need to perform some hacks and need blocking behavior from the descriptor for some reason, use p_socket_get_fd() to get an internal socket descriptor (SOCKET handle on Windows).
The close-on-exec flag is always set on the socket desciptor. Use p_socket_get_fd() to overwrite this behavior.
PSocket ignores the SIGPIPE signal on UNIX systems if possible. Take it into account if you want to handle this signal.
Note that before using the PSocket API you must call p_libsys_init() in order to initialize system resources (on UNIX this will do nothing, but on Windows this routine is required). Usually this routine should be called on a program's start.
Here is an example of PSocket usage:
Here a UDP socket was created, bound to the localhost address and the port 5432. Do not forget to close the socket and free memory after its usage.
Definition in file psocket.h.
typedef enum PSocketProtocol_ PSocketProtocol |
Socket protocols specified by the IANA.
enum PSocketDirection_ |
enum PSocketIOCondition_ |
enum PSocketProtocol_ |
enum PSocketType_ |
Socket types.
Accepts a socket incoming connection.
socket | PSocket to accept the incoming connection from. | |
[out] | error | Error report object, NULL to ignore. |
This call has meaning only for connection oriented sockets. The socket can accept new incoming connections only after calling p_socket_bind() and p_socket_listen().
P_LIB_API pboolean p_socket_bind | ( | const PSocket * | socket, |
PSocketAddress * | address, | ||
pboolean | allow_reuse, | ||
PError ** | error ) |
Binds a socket to a given local address.
socket | PSocket to bind. | |
address | PSocketAddress to bind the given socket to. | |
allow_reuse | Whether to allow socket's address reusing. | |
[out] | error | Error report object, NULL to ignore. |
The allow_reuse option allows to resolve address conflicts for several bound sockets. It controls the SO_REUSEADDR socket flag.
In a common case two or more sockets can't be bound to the same address (a network address and a port) for the same data transfer protocol (i.e. TCP or UDP) because they will be in a conflicted state for data receiving. But the socket can be also bound for the any network interface (i.e. 0.0.0.0 network address) and a particular port. If you will try to bind another socket without the allow_reuse option to a particular network address (i.e. 127.0.0.1) and the same port, the p_socket_bind() call will fail.
With the allow_reuse option the system will resolve this conflict: the socket will be bound to the particular address and port (and will receive data targeted to this particular address) while the first socket will be receiving all other data matching the bound address.
This option is system dependent, some systems do not support it. Also some systems have option to reuse the address port (SO_REUSEPORT) in the same way, too.
Connection oriented sockets have another problem - the so called linger time. It is a time required by the system to properly close a socket connection (and this process can be quite complicated). This time can be measured from several minutes to several hours (!). The socket in such a state is half-dead, but it holds the bound address and attempt to bind another socket on this address will fail. The allow_reuse option allows to bind another socket on such a half-dead address, but behavior can be unexpected, it's better to refer to the system documentation for that.
In general case, a server socket should be bound with the allow_reuse set to TRUE, while a client socket shouldn't set this option to TRUE. If you restart the client quickly with the same address it can fail to bind.
Checks a connection state after calling p_socket_connect().
socket | PSocket to check the connection state for. | |
[out] | error | Error report object, NULL to ignore. |
Usually this call is used after calling p_socket_connect() on a socket in a non-blocking mode to check the connection state. If call returns the FALSE result then the connection checking call has failed or there was an error during the connection and you should check the last error using an error object.
If the socket is still pending for the connection you will get the P_ERROR_IO_IN_PROGRESS error code.
After calling p_socket_connect() on a non-blocking socket, you can wait for a connection operation to be finished using p_socket_io_condition_wait() with the P_SOCKET_IO_CONDITION_POLLOUT option.
Closes a socket.
socket | PSocket to close. | |
[out] | error | Error report object, NULL to ignore. |
For connection oriented sockets some time is required to completely close a socket connection. See documentation for p_socket_bind() for more information.
P_LIB_API pboolean p_socket_connect | ( | PSocket * | socket, |
PSocketAddress * | address, | ||
PError ** | error ) |
Connects a socket to a given remote address.
socket | PSocket to connect. | |
address | PSocketAddress to connect the socket to. | |
[out] | error | Error report object, NULL to ignore. |
Calling this method on the connection-less socket will bind it to the remote address and the p_socket_send() method can be used instead of p_socket_send_to(), so you do not need to specify the remote (target) address each time you need to send data. The socket will also discard incoming data from other addresses. The same call again will re-bind it to another remote address.
For the connection oriented socket it tries to establish a connection with a listening remote socket. The same call again will have no effect and will fail.
If the socket is in a non-blocking mode, then you can wait for the connection using p_socket_io_condition_wait() with the P_SOCKET_IO_CONDITION_POLLOUT parameter. You should check the connection result after that using p_socket_check_connect_result().
Closes a socket (if not closed yet) and frees its resources.
socket | PSocket to free resources from. |
Checks whether socket is used in a blocking mode.
socket | PSocket to check the blocking mode for. |
The underlying socket descriptor is always set to the non-blocking mode by default and PSocket emulates the blocking mode if required.
P_LIB_API PSocketFamily p_socket_get_family | ( | const PSocket * | socket | ) |
Gets a socket address family.
socket | PSocket to get the address family for. |
The socket address family specifies address space which will be used to communicate with other sockets. For now, the INET and INET6 families are supported. The INET6 family is available only if the operating system supports it.
Gets an underlying file descriptor of a socket.
socket | PSocket to get the file descriptor for. |
Checks whether the SO_KEEPALIVE flag is enabled.
socket | PSocket to check the SO_KEEPALIVE flag for. |
This option only has effect for connection oriented sockets. After a connection has been established between two sockets, they periodically send ping packets to each other to make sure that the connection is alive. A time interval between alive packets is system dependent and varies from several minutes to several hours.
The main usage of this option is to detect dead clients on a server side and close such the broken sockets to free resources for the actual clients which may want to connect to the server. Some servers may let clients to be idle for a long time, so such an option helps to detect died clients faster without sending them real data. It's some kind of garbage collecting.
Gets a socket listen backlog parameter.
socket | PSocket to get the listen backlog parameter for. |
This parameter only has meaning for the connection oriented sockets. The backlog parameter specifies how much pending connections from other clients can be stored in the internal (system) queue. If the socket has already the number of pending connections equal to the backlog parameter, and another client attempts to connect on that time, it (client) will either be refused or retransmitted. This behavior is system and protocol dependent.
Some systems may not allow to set it to high values. By default PSocket attempts to set it to 5.
P_LIB_API PSocketAddress * p_socket_get_local_address | ( | const PSocket * | socket, |
PError ** | error ) |
Gets a socket local (bound) address.
socket | PSocket to get the local address for. | |
[out] | error | Error report object, NULL to ignore. |
If the socket was not bound explicitly with p_socket_bind() or implicitly with p_socket_connect(), the call will fail.
P_LIB_API PSocketProtocol p_socket_get_protocol | ( | const PSocket * | socket | ) |
Gets a socket data transfer protocol.
socket | PSocket to get the data transfer protocol for. |
P_LIB_API PSocketAddress * p_socket_get_remote_address | ( | const PSocket * | socket, |
PError ** | error ) |
Gets a socket remote endpoint address.
socket | PSocket to get the remote endpoint address for. | |
[out] | error | Error report object, NULL to ignore. |
If the socket was not connected to the endpoint address with p_socket_connect(), the call will fail.
Gets a socket timeout for blocking I/O operations.
socket | PSocket to get the timeout for. |
For a blocking socket a timeout value means maximum amount of time for which a blocking call will wait until a newtwork I/O operation completes. If the operation is not finished after the timeout, the blocking call returns with the error set to P_ERROR_IO_TIMED_OUT.
For a non-blocking socket the timeout affects only on the p_socket_io_condition_wait() maximum waiting time.
Zero timeout means that the operation which requires a time to complete network I/O will be blocked until the operation finishes or error occurres.
P_LIB_API PSocketType p_socket_get_type | ( | const PSocket * | socket | ) |
Gets a socket type.
socket | PSocket to get the type for. |
P_LIB_API pboolean p_socket_io_condition_wait | ( | const PSocket * | socket, |
PSocketIOCondition | condition, | ||
PError ** | error ) |
Waits for a specified I/O condition on socket.
socket | PSocket to wait for condition on. | |
condition | An I/O condition to wait for on socket. | |
[out] | error | Error report object, NULL to ignore. |
Waits until condition will be met on socket or an error occurred. If timeout was set using p_socket_set_timeout() and a network I/O operation doesn't finish until timeout expired, call will fail with P_ERROR_IO_TIMED_OUT error code.
Checks whether a socket is closed.
socket | PSocket to check a closed state. |
If the socket is in a non-blocking mode this call will not return TRUE until p_socket_check_connect_result() is called. The socket will be closed if p_socket_shutdown() is called for both the directions.
Checks whether a socket is connected.
socket | PSocket to check a connection for. |
This function doesn't check if the socket is still connected, it only checks whether the p_socket_connect() call was successfully performed on the socket.
Puts a socket into a listening state.
socket | PSocket to start listening. | |
[out] | error | Error report object, NULL to ignore. |
This call has meaning only for connection oriented sockets. Before starting to accept incoming connections, the socket must be put into the passive mode using p_socket_listen(). After that p_socket_accept() can be used to accept incoming connections.
Maximum number of pending connections is defined by the backlog parameter, see p_socket_get_listen_backlog() documentation for more information. The backlog parameter must be set before calling p_socket_listen() to take effect.
P_LIB_API PSocket * p_socket_new | ( | PSocketFamily | family, |
PSocketType | type, | ||
PSocketProtocol | protocol, | ||
PError ** | error ) |
Creates a new PSocket object.
family | Socket family. | |
type | Socket type. | |
protocol | Socket data transfer protocol. | |
[out] | error | Error report object, NULL to ignore. |
The protocol is passed directly to the operating system socket() call, PSocketProtocol has the same values as the system definitions. You can pass any existing protocol value to this call if you know it exactly.
Creates a new PSocket object from a file descriptor.
fd | File descriptor to create the socket from. | |
[out] | error | Error report object, NULL to ignore. |
The given file descriptor fd will be put in a non-blocking mode. PSocket will emulate a blocking mode if required.
If the socket was not bound yet then on some systems (i.e. Windows) call may fail to get a socket family from the descriptor thus failing to construct the PSocket object.
P_LIB_API pssize p_socket_receive | ( | const PSocket * | socket, |
pchar * | buffer, | ||
psize | buflen, | ||
PError ** | error ) |
Receives data from a given socket.
socket | PSocket to receive data from. | |
buffer | Buffer to write received data in. | |
buflen | Length of buffer. | |
[out] | error | Error report object, NULL to ignore. |
If the buflen is less than the received data size, only buflen bytes of data will be written to the buffer, and excess bytes may be discarded depending on a socket message type.
This call is normally used only with the a connected socket, see p_socket_connect().
P_LIB_API pssize p_socket_receive_from | ( | const PSocket * | socket, |
PSocketAddress ** | address, | ||
pchar * | buffer, | ||
psize | buflen, | ||
PError ** | error ) |
Receives data from a given socket and saves a remote address.
socket | PSocket to receive data from. | |
[out] | address | Pointer to store the remote address in case of success, may be NULL. The caller is responsible to free it after usage. |
buffer | Buffer to write received data in. | |
buflen | Length of buffer. | |
[out] | error | Error report object, NULL to ignore. |
If the buflen is less than the received data size, only buflen bytes of data will be written to the buffer, and excess bytes may be discarded depending on a socket message type.
This call is normally used only with a connection-less socket.
P_LIB_API pssize p_socket_send | ( | const PSocket * | socket, |
const pchar * | buffer, | ||
psize | buflen, | ||
PError ** | error ) |
Sends data through a given socket.
socket | PSocket to send data through. | |
buffer | Buffer with data to send. | |
buflen | Length of buffer. | |
[out] | error | Error report object, NULL to ignore. |
Do not use this call for connection-less sockets which are not connected to a remote address using p_socket_connect() because it will always fail, use p_socket_send_to() instead.
P_LIB_API pssize p_socket_send_to | ( | const PSocket * | socket, |
PSocketAddress * | address, | ||
const pchar * | buffer, | ||
psize | buflen, | ||
PError ** | error ) |
Sends data through a given socket to a given address.
socket | PSocket to send data through. | |
address | PSocketAddress to send data to. | |
buffer | Buffer with data to send. | |
buflen | Length of buffer. | |
[out] | error | Error report object, NULL to ignore. |
This call is used when dealing with connection-less sockets. You can bind such a socket to a remote address using p_socket_connect() and use p_socket_send() instead. If you are working with connection oriented sockets then use p_socket_send() after establishing a connection.
Sets a socket blocking mode.
socket | PSocket to set the blocking mode for. |
blocking | Whether to set the socket into the blocking mode. |
P_LIB_API pboolean p_socket_set_buffer_size | ( | const PSocket * | socket, |
PSocketDirection | dir, | ||
psize | size, | ||
PError ** | error ) |
Sets the socket buffer size for a given data transfer direction.
socket | PSocket to set the buffer size for. | |
dir | Direction to set the buffer size on. | |
size | Size of the buffer to set, in bytes. | |
[out] | error | Error report object, NULL to ignore. |
Sets the socket SO_KEEPALIVE flag.
socket | PSocket to set the SO_KEEPALIVE flag for. |
keepalive | Value for the SO_KEEPALIVE flag. |
See p_socket_get_keepalive() documentation for a description of this option.
Sets a socket listen backlog parameter.
socket | PSocket to set the listen backlog parameter for. |
backlog | Value for the listen backlog parameter. |
See p_socket_get_listen_backlog() documentation for a description of this option.
Sets a socket timeout value for blocking I/O operations.
socket | PSocket to set the timeout for. |
timeout | Timeout value in milliseconds. |
See p_socket_get_timeout() documentation for a description of this option.
P_LIB_API pboolean p_socket_shutdown | ( | PSocket * | socket, |
pboolean | shutdown_read, | ||
pboolean | shutdown_write, | ||
PError ** | error ) |
Shutdowns a full-duplex socket data transfer link.
socket | PSocket to shutdown link. | |
shutdown_read | Whether to shutdown the incoming data transfer link. | |
shutdown_write | Whether to shutdown the outcoming data transfer link. | |
[out] | error | Error report object, NULL to ignore. |
After shutdowning the data transfer link couldn't be restored in any direction. It is often used to gracefully close a connection for a connection oriented socket.