summaryrefslogtreecommitdiff
path: root/3rdparty/plibsys/src/psocket.h
blob: 989e707dcf1db1a87dd4eedb72dff843c23b2845 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
/*
 * The MIT License
 *
 * Copyright (C) 2010-2016 Alexander Saprykin <saprykin.spb@gmail.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * 'Software'), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

/**
 * @file psocket.h
 * @brief Socket implementation
 * @author Alexander Saprykin
 *
 * 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 (or stream sockets, i.e. TCP);
 * - connection-less (or datagram sockets, i.e. UDP).
 *
 * 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:
 * - creates a socket using p_socket_new();
 * - binds the socket to a particular local address using p_socket_bind();
 * - starts to listen incoming connections using p_socket_listen();
 * - takes an incoming connection from the internal queue using
 * p_socket_accept().
 *
 * The client side acts as following:
 * - creates a socket using p_socket_new();
 * - binds the socket to a particular local address using p_socket_bind();
 * - connects to the server using p_socket_connect().
 *
 * 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:
 * @code
 * PSocketAddress *addr;
 * PSocket	  *sock;
 *
 * p_libsys_init ();
 * ...
 * if ((addr = p_socket_address_new ("127.0.0.1", 5432)) == NULL) {
 *	...
 * }
 *
 * if ((sock = p_socket_new (P_SOCKET_FAMILY_INET,
 *			     P_SOCKET_TYPE_DATAGRAM,
 *			     P_SOCKET_PROTOCOL_UDP)) == NULL) {
 *	p_socket_address_free (addr);
 *	...
 * }
 *
 * if (!p_socket_bind (sock, addr, FALSE)) {
 *	p_socket_address_free(addr);
 *	p_socket_free(sock);
 *	...
 * }
 *
 * ...
 * p_socket_address_free (addr);
 * p_socket_close (sock);
 * p_socket_free (sock);
 * p_libsys_shutdown ();
 * @endcode
 * Here a UDP socket was created, bound to the localhost address and the port
 * @a 5432. Do not forget to close the socket and free memory after its usage.
 */

#if !defined (PLIBSYS_H_INSIDE) && !defined (PLIBSYS_COMPILATION)
#  error "Header files shouldn't be included directly, consider using <plibsys.h> instead."
#endif

#ifndef PLIBSYS_HEADER_PSOCKET_H
#define PLIBSYS_HEADER_PSOCKET_H

#include <pmacros.h>
#include <psocketaddress.h>
#include <perror.h>

P_BEGIN_DECLS

/** Socket protocols specified by the IANA.  */
typedef enum PSocketProtocol_ {
	P_SOCKET_PROTOCOL_UNKNOWN	= -1,	/**< Unknown protocol.	*/
	P_SOCKET_PROTOCOL_DEFAULT	= 0,	/**< Default protocol.	*/
	P_SOCKET_PROTOCOL_TCP		= 6,	/**< TCP protocol.	*/
	P_SOCKET_PROTOCOL_UDP		= 17,	/**< UDP protocol.	*/
	P_SOCKET_PROTOCOL_SCTP		= 132	/**< SCTP protocol.	*/
} PSocketProtocol;

/** Socket types. */
typedef enum PSocketType_ {
	P_SOCKET_TYPE_UNKNOWN		= 0,	/**< Unknown type.							*/
	P_SOCKET_TYPE_STREAM		= 1,	/**< Connection oritented, reliable, stream of bytes (i.e. TCP).	*/
	P_SOCKET_TYPE_DATAGRAM		= 2,	/**< Connection-less, unreliable, datagram passing (i.e. UDP).		*/
	P_SOCKET_TYPE_SEQPACKET		= 3	/**< Connection-less, reliable, datagram passing (i.e. SCTP).		*/
} PSocketType;

/** Socket direction for data operations. */
typedef enum PSocketDirection_ {
	P_SOCKET_DIRECTION_SND		= 0,	/**< Send direction.	*/
	P_SOCKET_DIRECTION_RCV		= 1	/**< Receive direction.	*/
} PSocketDirection;

/** Socket IO waiting (polling) conditions. */
typedef enum PSocketIOCondition_ {
	P_SOCKET_IO_CONDITION_POLLIN	= 1,	/**< Ready to read.	*/
	P_SOCKET_IO_CONDITION_POLLOUT	= 2	/**< Ready to write.	*/
} PSocketIOCondition;

/** Socket opaque structure. */
typedef struct PSocket_ PSocket;

/**
 * @brief Creates a new #PSocket object from a file descriptor.
 * @param fd File descriptor to create the socket from.
 * @param[out] error Error report object, NULL to ignore.
 * @return Pointer to #PSocket in case of success, NULL otherwise.
 * @since 0.0.1
 * @sa p_socket_new(), p_socket_get_fd()
 *
 * The given file descriptor @a 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 PSocket *		p_socket_new_from_fd		(pint 			fd,
								 PError			**error);

/**
 * @brief Creates a new #PSocket object.
 * @param family Socket family.
 * @param type Socket type.
 * @param protocol Socket data transfer protocol.
 * @param[out] error Error report object, NULL to ignore.
 * @return Pointer to #PSocket in case of success, NULL otherwise.
 * @since 0.0.1
 * @note If all the given parameters are not compatible with each other, then
 * the function will fail. Use #P_SOCKET_PROTOCOL_DEFAULT to automatically
 * match the best protocol for a particular @a type.
 * @sa #PSocketFamily, #PSocketType, #PSocketProtocol, p_socket_new_from_fd()
 *
 * The @a 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.
 */
P_LIB_API PSocket *		p_socket_new 			(PSocketFamily		family,
								 PSocketType		type,
								 PSocketProtocol	protocol,
								 PError			**error);

/**
 * @brief Gets an underlying file descriptor of a @a socket.
 * @param socket #PSocket to get the file descriptor for.
 * @return File descriptor in case of success, -1 otherwise.
 * @since 0.0.1
 * @sa p_socket_new_from_fd()
 */
P_LIB_API pint			p_socket_get_fd 		(const PSocket		*socket);

/**
 * @brief Gets a @a socket address family.
 * @param socket #PSocket to get the address family for.
 * @return #PSocketFamily in case of success, #P_SOCKET_FAMILY_UNKNOWN
 * otherwise.
 * @since 0.0.1
 * @sa #PSocketFamily, p_socket_new()
 *
 * 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.
 */
P_LIB_API PSocketFamily		p_socket_get_family 		(const PSocket		*socket);

/**
 * @brief Gets a @a socket type.
 * @param socket #PSocket to get the type for.
 * @return #PSocketType in case of success, #P_SOCKET_TYPE_UNKNOWN otherwise.
 * @since 0.0.1
 * @sa #PSocketType, p_socket_new()
 */
P_LIB_API PSocketType		p_socket_get_type 		(const PSocket		*socket);

/**
 * @brief Gets a @a socket data transfer protocol.
 * @param socket #PSocket to get the data transfer protocol for.
 * @return #PSocketProtocol in case of success, #P_SOCKET_PROTOCOL_UNKNOWN
 * otherwise.
 * @since 0.0.1
 * @sa #PSocketProtocol, p_socket_new()
 */
P_LIB_API PSocketProtocol	p_socket_get_protocol		(const PSocket		*socket);

/**
 * @brief Checks whether the SO_KEEPALIVE flag is enabled.
 * @param socket #PSocket to check the SO_KEEPALIVE flag for.
 * @return TRUE if the SO_KEEPALIVE flag is enabled, FALSE otherwise.
 * @since 0.0.1
 * @sa p_socket_set_keepalive()
 *
 * 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.
 */
P_LIB_API pboolean		p_socket_get_keepalive		(const PSocket		*socket);

/**
 * @brief Checks whether @a socket is used in a blocking mode.
 * @param socket #PSocket to check the blocking mode for.
 * @return TRUE if @a socket is in the blocking mode, FALSE otherwise.
 * @note A blocking socket will wait for an I/O operation to be completed before
 * returning to the caller function.
 * @since 0.0.1
 * @sa p_socket_set_blocking()
 *
 * 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 pboolean		p_socket_get_blocking		(PSocket 		*socket);

/**
 * @brief Gets a @a socket listen backlog parameter.
 * @param socket #PSocket to get the listen backlog parameter for.
 * @return Listen backlog parameter in case of success, -1 otherwise.
 * @since 0.0.1
 * @sa p_socket_set_listen_backlog(), p_socket_listen()
 *
 * 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 pint			p_socket_get_listen_backlog	(const PSocket 		*socket);

/**
 * @brief Gets a @a socket timeout for blocking I/O operations.
 * @param socket #PSocket to get the timeout for.
 * @return Timeout for blocking I/O operations in milliseconds, -1 in case of
 * fail.
 * @since 0.0.1
 * @sa p_socket_set_timeout(), p_socket_io_condition_wait()
 *
 * 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 pint			p_socket_get_timeout		(const PSocket		*socket);

/**
 * @brief Gets a @a socket local (bound) address.
 * @param socket #PSocket to get the local address for.
 * @param[out] error Error report object, NULL to ignore.
 * @return #PSocketAddress with the socket local address in case of success,
 * NULL otherwise.
 * @since 0.0.1
 * @sa p_socket_bind()
 *
 * If the @a socket was not bound explicitly with p_socket_bind() or implicitly
 * with p_socket_connect(), the call will fail.
 */
P_LIB_API PSocketAddress *	p_socket_get_local_address	(const PSocket 		*socket,
								 PError			**error);

/**
 * @brief Gets a @a socket remote endpoint address.
 * @param socket #PSocket to get the remote endpoint address for.
 * @param[out] error Error report object, NULL to ignore.
 * @return #PSocketAddress with the socket endpoint remote address in case of
 * success, NULL otherwise.
 * @since 0.0.1
 * @sa p_socket_connect()
 *
 * If the @a socket was not connected to the endpoint address with
 * p_socket_connect(), the call will fail.
 *
 * @warning On Syllable this call will always return NULL for connection-less
 * sockets (though connecting is possible).
 */
P_LIB_API PSocketAddress *	p_socket_get_remote_address	(const PSocket 		*socket,
								 PError			**error);

/**
 * @brief Checks whether a @a socket is connected.
 * @param socket #PSocket to check a connection for.
 * @return TRUE if the @a socket is connected, FALSE otherwise.
 * @since 0.0.1
 * @sa p_socket_connect(), p_socket_check_connect_result()
 *
 * 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
 * @a socket.
 */
P_LIB_API pboolean		p_socket_is_connected		(const PSocket		*socket);

/**
 * @brief Checks whether a @a socket is closed.
 * @param socket #PSocket to check a closed state.
 * @return TRUE if the @a socket is closed, FALSE otherwise.
 * @since 0.0.1
 * @sa p_socket_close(), p_socket_shutdown()
 *
 * 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.
 */
P_LIB_API pboolean		p_socket_is_closed		(const PSocket		*socket);

/**
 * @brief Checks a connection state after calling p_socket_connect().
 * @param socket #PSocket to check the connection state for.
 * @param[out] error Error report object, NULL to ignore.
 * @return TRUE if was no error, FALSE otherwise.
 * @since 0.0.1
 * @sa p_socket_io_condition_wait()
 * @warning Not supported on Syllable for connection-less sockets.
 *
 * 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 @a 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.
 */
P_LIB_API pboolean		p_socket_check_connect_result	(PSocket		*socket,
								 PError			**error);

/**
 * @brief Sets the @a socket SO_KEEPALIVE flag.
 * @param socket #PSocket to set the SO_KEEPALIVE flag for.
 * @param keepalive Value for the SO_KEEPALIVE flag.
 * @since 0.0.1
 * @sa p_socket_get_keepalive()
 *
 * See p_socket_get_keepalive() documentation for a description of this option.
 */
P_LIB_API void			p_socket_set_keepalive		(PSocket 		*socket,
								 pboolean		keepalive);

/**
 * @brief Sets a @a socket blocking mode.
 * @param socket #PSocket to set the blocking mode for.
 * @param blocking Whether to set the @a socket into the blocking mode.
 * @note A blocking socket will wait for an I/O operation to be completed
 * before returning to the caller function.
 * @note On some operating systems a blocking timeout may be less than threads
 * scheduling granularity, so the actual timeout can be greater than specified
 * one.
 * @since 0.0.1
 * @sa p_socket_get_blocking()
 */
P_LIB_API void			p_socket_set_blocking		(PSocket 		*socket,
								 pboolean		blocking);

/**
 * @brief Sets a @a socket listen backlog parameter.
 * @param socket #PSocket to set the listen backlog parameter for.
 * @param backlog Value for the listen backlog parameter.
 * @note This parameter can take effect only if it was set before calling
 * p_socket_listen(). Otherwise it will be ignored by underlying socket
 * system calls.
 * @since 0.0.1
 * @sa p_socket_get_listen_backlog()
 *
 * See p_socket_get_listen_backlog() documentation for a description of this
 * option.
 */
P_LIB_API void			p_socket_set_listen_backlog	(PSocket		*socket,
								 pint			backlog);

/**
 * @brief Sets a @a socket timeout value for blocking I/O operations.
 * @param socket #PSocket to set the @a timeout for.
 * @param timeout Timeout value in milliseconds.
 * @since 0.0.1
 * @sa p_socket_get_timeoout(), p_socket_io_condition_wait()
 *
 * See p_socket_get_timeout() documentation for a description of this option.
 */
P_LIB_API void			p_socket_set_timeout		(PSocket		*socket,
								 pint			timeout);

/**
 * @brief Binds a @a socket to a given local address.
 * @param socket #PSocket to bind.
 * @param address #PSocketAddress to bind the given @a socket to.
 * @param allow_reuse Whether to allow socket's address reusing.
 * @param[out] error Error report object, NULL to ignore.
 * @return TRUE in case of success, FALSE otherwise.
 * @since 0.0.1
 * @sa p_socket_get_local_address()
 *
 * The @a 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 @a 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 @a 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 @a 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 @a 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.
 */
P_LIB_API pboolean		p_socket_bind			(const PSocket 		*socket,
								 PSocketAddress		*address,
								 pboolean		allow_reuse,
								 PError			**error);

/**
 * @brief Connects a @a socket to a given remote address.
 * @param socket #PSocket to connect.
 * @param address #PSocketAddress to connect the @a socket to.
 * @param[out] error Error report object, NULL to ignore.
 * @return TRUE in case of success, FALSE otherwise.
 * @since 0.0.1
 * @sa p_socket_is_connected(), p_socket_check_connect_result(),
 * p_socket_get_remote_address(), p_socket_io_condition_wait()
 * @warning On Syllable this method changes a local port of the connection
 * oriented socket in case of success.
 *
 * 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 @a 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().
 */
P_LIB_API pboolean		p_socket_connect		(PSocket		*socket,
								 PSocketAddress		*address,
								 PError			**error);

/**
 * @brief Puts a @a socket into a listening state.
 * @param socket #PSocket to start listening.
 * @param[out] error Error report object, NULL to ignore.
 * @return TRUE in case of success, FALSE otherwise.
 * @since 0.0.1
 * @sa p_socket_get_listen_backlog(), p_socket_set_listen_backlog()
 *
 * 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 pboolean		p_socket_listen			(PSocket 		*socket,
								 PError			**error);

/**
 * @brief Accepts a @a socket incoming connection.
 * @param socket #PSocket to accept the incoming connection from.
 * @param[out] error Error report object, NULL to ignore.
 * @return New #PSocket with the accepted connection in case of success, NULL
 * otherwise.
 * @since 0.0.1
 *
 * 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 PSocket *		p_socket_accept			(const PSocket		*socket,
								 PError			**error);

/**
 * @brief Receives data from a given @a socket.
 * @param socket #PSocket to receive data from.
 * @param buffer Buffer to write received data in.
 * @param buflen Length of @a buffer.
 * @param[out] error Error report object, NULL to ignore.
 * @return Size in bytes of written data in case of success, -1 otherwise.
 * @note If the @a socket is in a blocking mode, then the caller will be blocked
 * until data arrives.
 * @since 0.0.1
 * @sa p_socket_receive_from(), p_socket_connect()
 *
 * If the @a buflen is less than the received data size, only @a buflen bytes of
 * data will be written to the @a 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		(const PSocket		*socket,
								 pchar			*buffer,
								 psize			buflen,
								 PError			**error);

/**
 * @brief Receives data from a given @a socket and saves a remote address.
 * @param socket #PSocket to receive data from.
 * @param[out] address Pointer to store the remote address in case of success,
 * may be NULL. The caller is responsible to free it after usage.
 * @param buffer Buffer to write received data in.
 * @param buflen Length of @a buffer.
 * @param[out] error Error report object, NULL to ignore.
 * @return Size in bytes of written data in case of success, -1 otherwise.
 * @note If the @a socket is in a blocking mode, then the caller will be blocked
 * until data arrives.
 * @since 0.0.1
 * @sa p_socket_receive()
 *
 * If the @a buflen is less than the received data size, only @a buflen bytes of
 * data will be written to the @a 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_receive_from		(const PSocket 		*socket,
								 PSocketAddress		**address,
								 pchar 			*buffer,
								 psize			buflen,
								 PError			**error);

/**
 * @brief Sends data through a given @a socket.
 * @param socket #PSocket to send data through.
 * @param buffer Buffer with data to send.
 * @param buflen Length of @a buffer.
 * @param[out] error Error report object, NULL to ignore.
 * @return Size in bytes of sent data in case of success, -1 otherwise.
 * @note If the @a socket is in a blocking mode, then the caller will be blocked
 * until data sent.
 * @since 0.0.1
 * @sa p_socket_send_to()
 *
 * 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			(const PSocket		*socket,
								 const pchar		*buffer,
								 psize			buflen,
								 PError			**error);

/**
 * @brief Sends data through a given @a socket to a given address.
 * @param socket #PSocket to send data through.
 * @param address #PSocketAddress to send data to.
 * @param buffer Buffer with data to send.
 * @param buflen Length of @a buffer.
 * @param[out] error Error report object, NULL to ignore.
 * @return Size in bytes of sent data in case of success, -1 otherwise.
 * @note If the @a socket is in a blocking mode, then the caller will be blocked
 * until data sent.
 * @since 0.0.1
 * @sa p_socket_send()
 *
 * 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.
 */
P_LIB_API pssize		p_socket_send_to		(const PSocket		*socket,
								 PSocketAddress		*address,
								 const pchar		*buffer,
								 psize			buflen,
								 PError			**error);

/**
 * @brief Closes a @a socket.
 * @param socket #PSocket to close.
 * @param[out] error Error report object, NULL to ignore.
 * @return TRUE in case of success, FALSE otherwise.
 * @since 0.0.1
 * @sa p_socket_free(), p_socket_is_closed()
 *
 * 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_close			(PSocket		*socket,
								 PError			**error);

/**
 * @brief Shutdowns a full-duplex @a socket data transfer link.
 * @param socket #PSocket to shutdown link.
 * @param shutdown_read Whether to shutdown the incoming data transfer link.
 * @param shutdown_write Whether to shutdown the outcoming data transfer link.
 * @param[out] error Error report object, NULL to ignore.
 * @return TRUE in case of success, FALSE otherwise.
 * @note Shutdown of any link is possible only on the socket in a connected
 * state, otherwise the call will fail.
 * @since 0.0.1
 *
 * 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.
 */
P_LIB_API pboolean		p_socket_shutdown		(PSocket		*socket,
								 pboolean		shutdown_read,
								 pboolean		shutdown_write,
								 PError			**error);

/**
 * @brief Closes a @a socket (if not closed yet) and frees its resources.
 * @param socket #PSocket to free resources from.
 * @since 0.0.1
 * @sa p_socket_close()
 */
P_LIB_API void			p_socket_free			(PSocket 		*socket);

/**
 * @brief Sets the @a socket buffer size for a given data transfer direction.
 * @param socket #PSocket to set the buffer size for.
 * @param dir Direction to set the buffer size on.
 * @param size Size of the buffer to set, in bytes.
 * @param[out] error Error report object, NULL to ignore.
 * @return TRUE in case of success, FALSE otherwise.
 * @since 0.0.1
 * @warning Not supported on Syllable.
 */
P_LIB_API pboolean		p_socket_set_buffer_size	(const PSocket		*socket,
								 PSocketDirection	dir,
								 psize			size,
								 PError			**error);

/**
 * @brief Waits for a specified I/O @a condition on @a socket.
 * @param socket #PSocket to wait for @a condition on.
 * @param condition An I/O condition to wait for on @a socket.
 * @param[out] error Error report object, NULL to ignore.
 * @return TRUE if @a condition has been met, FALSE otherwise.
 * @since 0.0.1
 * @sa p_socket_get_timeout(), p_socket_set_timeout()
 *
 * Waits until @a condition will be met on @a 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.
 */
P_LIB_API pboolean		p_socket_io_condition_wait	(const PSocket		*socket,
								 PSocketIOCondition	condition,
								 PError			**error);

P_END_DECLS

#endif /* PLIBSYS_HEADER_PSOCKET_H */