diff --git a/CHANGES b/CHANGES index 4c3d9a3..83d59e4 100644 --- a/CHANGES +++ b/CHANGES @@ -17,6 +17,7 @@ introduce io_eagain_read and io_eagain_write (discontinue using io_eagain plz) fix buffer_get add fmt_html_tagarg, fmt_xml, scan_html_tagarg + add socket_fastopen, socket_fastopen_connect4, socket_fastopen_connect6 and socket_quickack 0.29: save 8 bytes in taia.h for 64-bit systems diff --git a/socket.h b/socket.h index 279545a..2ece1fd 100644 --- a/socket.h +++ b/socket.h @@ -39,7 +39,9 @@ int socket_accept6(int s,char* ip,uint16* port,uint32* scope_id); ssize_t socket_recv4(int s,char* buf,size_t len,char* ip,uint16* port); ssize_t socket_recv6(int s,char* buf,size_t len,char* ip,uint16* port,uint32* scope_id); ssize_t socket_send4(int s,const char* buf,size_t len,const char* ip,uint16 port); +ssize_t socket_send4_flag(int s,const char* buf,size_t len,const char* ip,uint16 port,int flags); ssize_t socket_send6(int s,const char* buf,size_t len,const char* ip,uint16 port,uint32 scope_id); +ssize_t socket_send6_flag(int s,const char* buf,size_t len,const char* ip,uint16 port,uint32 scope_id,int flags); int socket_local4(int s,char* ip,uint16* port); int socket_local6(int s,char* ip,uint16* port,uint32* scope_id); int socket_remote4(int s,char* ip,uint16* port); @@ -60,7 +62,7 @@ int socket_mchopcount6(int s,char hops); int socket_mcloop4(int s,char loop); int socket_mcloop6(int s,char loop); -/* please note that these are platform specific. Do not expect them to +/* Please note that these are platform specific. Do not expect them to * work. You might still get an accept() signalled even though there is * no data available. So far, DATAIN is supported on FreeBSD and Linux, * and HTTPIN is supported on FreeBSD. */ @@ -78,6 +80,24 @@ uint32 socket_getifidx(const char* ifname); extern int noipv6; + +/* if HAVE_SOCKET_FASTOPEN is #defined, your version of libowfat + * has socket_fastopen, socket_fastopen_connect4, + * socket_fastopen_connect6 and socket_quickack */ +#define HAVE_SOCKET_FASTOPEN + +/* Turn on server-side TCP fast open support (0 success, -1 error) */ +int socket_fastopen(int s); + +/* Turn quick ack mode on or off for the socket s. */ +int socket_quickack(int s,int value); + +/* For client-side TCP fast open, connect and sending the first data is + * just one step, so we need an API to do it in one step */ +ssize_t socket_fastopen_connect4(int s,const char* ip,uint16 port,const char* buf,size_t len); +ssize_t socket_fastopen_connect6(int s,const char* ip,uint16 port,uint32 scope_id,const char* buf,size_t len); + + #ifdef __MINGW32__ #include #include diff --git a/socket/socket_connect4.3 b/socket/socket_connect4.3 index 2d6a60b..64fb2f1 100644 --- a/socket/socket_connect4.3 +++ b/socket/socket_connect4.3 @@ -45,4 +45,4 @@ effect as first calling socket_bind4 with IP address 0.0.0.0 and port 0. socket_connect4(s,ip,p); .SH "SEE ALSO" -socket_connect6(3) +socket_connect6(3), socket_fastopen_connect4(3) diff --git a/socket/socket_connect6.3 b/socket/socket_connect6.3 index 76a2f20..b534d56 100644 --- a/socket/socket_connect6.3 +++ b/socket/socket_connect6.3 @@ -51,4 +51,4 @@ effect as first calling socket_bind6 with IP address :: and port 0. socket_connect6(s,ip,p,0); .SH "SEE ALSO" -socket_connect4(3), socket_getifname(3) +socket_connect4(3), socket_fastopen_connect6(3), socket_getifname(3) diff --git a/socket/socket_fastopen.3 b/socket/socket_fastopen.3 new file mode 100644 index 0000000..1dea660 --- /dev/null +++ b/socket/socket_fastopen.3 @@ -0,0 +1,30 @@ +.TH socket_fastopen 3 +.SH NAME +socket_fastopen \- enable TCP Fast Open on a server-side TCP socket +.SH SYNTAX +.B #include + +int \fBsocket_fastopen\fP(int \fIs\fR); +.SH DESCRIPTION +socket_fastopen enables TCP Fast Open support on a server-side TCP +socket. Call this before socket_listen(). If the platform does not +support this functionality, returns -1 and sets errno to ENOPROTOOPT (or +ENOSYS if the platform does not define ENOPROTOOPT). + +Normally socket_fastopen returns 0. If anything goes wrong, socket_fastopen +returns -1, setting errno appropriately. + +.SH EXAMPLE + #include + + int \fIs\fR; + char \fIip\fR[4]; + uint16 \fIp\fR; + + \fIs\fR = socket_tcp4b(); + socket_fastopen(s); + socket_bind4_reuse(s,ip,p); + socket_listen(16); + +.SH "SEE ALSO" +socket_fastopen_connect4(3), socket_fastopen_connect6(3) diff --git a/socket/socket_fastopen_connect4.3 b/socket/socket_fastopen_connect4.3 new file mode 100644 index 0000000..f5b8ecb --- /dev/null +++ b/socket/socket_fastopen_connect4.3 @@ -0,0 +1,58 @@ +.TH socket_fastopen_connect4 3 +.SH NAME +socket_fastopen_connect4 \- make a TCP connection and send some data +.SH SYNTAX +.B #include + +ssize_t \fBsocket_fastopen_connect4\fP(int \fIs\fR,const char \fIip\fR[4],uint16 \fIport\fR, + const char* \fIbuf\fR,size_t \fIlen\fR); +.SH DESCRIPTION +socket_fastopen_connect4 attempts to make a connection from TCP socket \fIs\fR to +TCP port \fIport\fR on IP address \fIip\fR. If that succeeds, it +attempts to send \fIlen\fR bytes from \fIbuf\fR. + +The difference to calling socket_connect4 followed by write is that, on +platforms supporting TCP Fast Open, socket_fastopen_connect4 will send +the first data packet in the third packet of the TCP handshake, saving +one useless ACK packet in network traffic. + +This is only useful for protocols where the client sends the first +bytes. + +socket_connect4 may return +.sp 1 +.IP \(bu +>=0, to indicate that the connection succeeded and this many bytes were +sent. +.IP \(bu +-1, setting errno to error_inprogress or error_wouldblock, to indicate +that the socket is non-blocking +.IP \(bu +-1, setting errno to something else, to indicate that the connection +failed (and failed immediately, if the socket is non-blocking). +.PP + +When a background connection succeeds or fails, \fIs\fR becomes +writable; you can use socket_connected to see whether the connection +succeeded. If the connection failed, socket_connected returns 0, +setting errno appropriately. + +Once a TCP socket is connected, you can use the read and write +system calls to transmit data. + +You can call socket_connect4 without calling socket_bind4. This has the +effect as first calling socket_bind4 with IP address 0.0.0.0 and port 0. + +.SH EXAMPLE + #include + + int \fIs\fR; + char \fIip\fR[4]; + uint16 \fIp\fR; + + \fIs\fR = socket_tcp4(); + socket_bind4(s,ip,p); + socket_fastopen_connect4(s,ip,p,"hello",5); + +.SH "SEE ALSO" +socket_connect4(3), socket_fastopen_connect6(3), socket_fastopen(3) diff --git a/socket/socket_fastopen_connect6.3 b/socket/socket_fastopen_connect6.3 new file mode 100644 index 0000000..e4b6b9d --- /dev/null +++ b/socket/socket_fastopen_connect6.3 @@ -0,0 +1,60 @@ +.TH socket_fastopen_connect6 3 +.SH NAME +socket_fastopen_connect6 \- make a TCP connection and send some data +.SH SYNTAX +.B #include + +ssize_t \fBsocket_fastopen_connect6\fP(int \fIs\fR, + const char \fIip\fR[16],uint16 \fIport\fR,uint32 \fIscope_id\fR, + const char* \fIbuf\fR,size_t \fIlen\fR); +.SH DESCRIPTION +socket_fastopen_connect6 attempts to make a connection from TCP socket \fIs\fR to +TCP port \fIport\fR on IP address \fIip\fR. If that succeeds, it +attempts to send \fIlen\fR bytes from \fIbuf\fR. + +The difference to calling socket_connect6 followed by write is that, on +platforms supporting TCP Fast Open, socket_fastopen_connect6 will send +the first data packet in the third packet of the TCP handshake, saving +one useless ACK packet in network traffic. + +This is only useful for protocols where the client sends the first +bytes. + +socket_connect6 may return +.sp 1 +.IP \(bu +>=0, to indicate that the connection succeeded and this many bytes were +sent. +.IP \(bu +-1, setting errno to error_inprogress or error_wouldblock, to indicate +that the socket is non-blocking +.IP \(bu +-1, setting errno to something else, to indicate that the connection +failed (and failed immediately, if the socket is non-blocking). +.PP + +When a background connection succeeds or fails, \fIs\fR becomes +writable; you can use socket_connected to see whether the connection +succeeded. If the connection failed, socket_connected returns 0, +setting errno appropriately. + +Once a TCP socket is connected, you can use the read and write +system calls to transmit data. + +You can call socket_connect6 without calling socket_bind6. This has the +effect as first calling socket_bind6 with IP address :: and port 0. + +.SH EXAMPLE + #include + + int \fIs\fR; + char \fIip\fR[16]; + uint16 \fIp\fR; + uint32 \fIscope_id\fR; + + \fIs\fR = socket_tcp6b(); + socket_bind6(s,ip,p); + socket_fastopen_connect6(s,ip,p,scope_id,"hello",5); + +.SH "SEE ALSO" +socket_connect6(3), socket_fastopen_connect4(3), socket_fastopen(3) diff --git a/socket/socket_quickack.3 b/socket/socket_quickack.3 new file mode 100644 index 0000000..620f954 --- /dev/null +++ b/socket/socket_quickack.3 @@ -0,0 +1,38 @@ +.TH socket_quickack 3 +.SH NAME +socket_quickack \- turn TCP Quick ACK mode on or off +.SH SYNTAX +.B #include + +int \fBsocket_quickack\fP(int \fIs\fR,int \fIvalue\fR); +.SH DESCRIPTION +socket_quickack switches TCP Quick ACK mode on (value=1) or off +(value=0). If the platform does not support this functionality, returns +-1 and sets errno to ENOPROTOOPT (or ENOSYS if the platform does not +define ENOPROTOOPT). + +TCP Quick ACK mode is on by default because the operating system has to +assume it's an interactive connection. In that case, an ACK will be +sent quickly after data came in. If your code handles non-interactive +server connections, it may make sense to switch Quick ACK mode off, +telling the kernel to delay sending ACKs because the server is going to +respond to incoming requests anyway, so the ACK can be piggy-backed onto +that response, saving useless network traffic. + +Normally socket_quickack returns 0. If anything goes wrong, socket_quickack +returns -1, setting errno appropriately. + +.SH EXAMPLE + #include + + int \fIs\fR; + char \fIip\fR[4]; + uint16 \fIp\fR; + + \fIs\fR = socket_tcp4b(); + socket_quickack(s); + socket_bind4_reuse(s,ip,p); + socket_listen(16); + +.SH "SEE ALSO" +socket_fastopen(3) diff --git a/socket/socket_quickack.c b/socket/socket_quickack.c new file mode 100644 index 0000000..cd027f8 --- /dev/null +++ b/socket/socket_quickack.c @@ -0,0 +1,18 @@ +#include "socket.h" +#include +#include +#include +#include + +int socket_quickack(int s,int value) { +#ifdef TCP_QUICKACK + return setsockopt(s, SOL_TCP, TCP_QUICKACK, &value, sizeof(int)); +#else +#ifdef ENOPROTOOPT + errno=ENOPROTOOPT; +#else + errno=ENOSYS; +#endif + return -1; +#endif +} diff --git a/socket/socket_send4.3 b/socket/socket_send4.3 index 13cc779..685be73 100644 --- a/socket/socket_send4.3 +++ b/socket/socket_send4.3 @@ -5,7 +5,7 @@ socket_send4 \- send a UDP datagram .B #include ssize_t \fBsocket_send4\fP(int \fIs\fR, const char* \fIbuf\fR, size_t \fIlen\fR, - const char \fIip\fR[4],uint16 \fIport\fR); + const char \fIip\fR[4],uint16 \fIport\fR); .SH DESCRIPTION socket_send4 sends \fIlen\fR bytes starting at \fIbuf\fR in a UDP datagram over the socket \fIs\fR to UDP port \fIport\fR on IP address diff --git a/socket/socket_send4.c b/socket/socket_send4.c index c2ace8b..3255f3d 100644 --- a/socket/socket_send4.c +++ b/socket/socket_send4.c @@ -8,12 +8,16 @@ #include "byte.h" #include "socket.h" -ssize_t socket_send4(int s,const char *buf,size_t len,const char ip[4],uint16 port) { +ssize_t socket_send4_flag(int s,const char *buf,size_t len,const char ip[4],uint16 port,int flag) { struct sockaddr_in si; byte_zero(&si,sizeof si); si.sin_family = AF_INET; uint16_pack_big((char*) &si.sin_port,port); *((uint32*)&si.sin_addr) = *((uint32*)ip); - return winsock2errno(sendto(s,buf,len,0,(void*) &si,sizeof si)); + return winsock2errno(sendto(s,buf,len,flag,(void*) &si,sizeof si)); +} + +ssize_t socket_send4(int s,const char *buf,size_t len,const char ip[4],uint16 port) { + return socket_send4_flag(s,buf,len,ip,port,0); } diff --git a/socket/socket_send6.3 b/socket/socket_send6.3 index 9fddb57..1fa6a24 100644 --- a/socket/socket_send6.3 +++ b/socket/socket_send6.3 @@ -5,7 +5,7 @@ socket_send6 \- send a UDP datagram .B #include ssize_t \fBsocket_send6\fP(int \fIs\fR, const char* \fIbuf\fR, size_t \fIlen\fR, - const char \fIip\fR[16], uint16 \fIport\fR, uint32 \fIscope_id\fR); + const char \fIip\fR[16], uint16 \fIport\fR, uint32 \fIscope_id\fR); .SH DESCRIPTION socket_send6 sends \fIlen\fR bytes starting at \fIbuf\fR in a UDP datagram over the socket \fIs\fR to UDP port \fIport\fR on IP address diff --git a/socket/socket_send6.c b/socket/socket_send6.c index f30bbc5..21ee14e 100644 --- a/socket/socket_send6.c +++ b/socket/socket_send6.c @@ -13,7 +13,7 @@ #include "ip4.h" #include "havescope.h" -ssize_t socket_send6(int s,const char *buf,size_t len,const char ip[16],uint16 port,uint32 scope_id) +ssize_t socket_send6_flag(int s,const char *buf,size_t len,const char ip[16],uint16 port,uint32 scope_id,int flag) { #ifdef LIBC_HAS_IP6 struct sockaddr_in6 si; @@ -41,9 +41,13 @@ ssize_t socket_send6(int s,const char *buf,size_t len,const char ip[16],uint16 p #else si.sin6_scope_id=0; #endif - return winsock2errno(sendto(s,buf,len,0,(void*) &si,sizeof si)); + return winsock2errno(sendto(s,buf,len,flag,(void*) &si,sizeof si)); #else errno=EPROTONOSUPPORT; return -1; #endif } + +ssize_t socket_send6(int s,const char *buf,size_t len,const char ip[16],uint16 port,uint32 scope_id) { + return socket_send6_flag(s,buf,len,ip,port,scope_id,0); +}