@@ -325,6 +325,12 @@ static ERL_NIF_TERM essio_sendfile_ok(ErlNifEnv* env,
325
325
size_t count );
326
326
#endif
327
327
328
+ static BOOLEAN_T recv_alloc_buf (size_t size ,
329
+ ErlNifBinary * bufP );
330
+ static BOOLEAN_T recv_create_bin (ErlNifBinary * bufP ,
331
+ size_t size ,
332
+ ErlNifBinary * binP );
333
+
328
334
static BOOLEAN_T recv_check_entry (ErlNifEnv * env ,
329
335
ESockDescriptor * descP ,
330
336
ERL_NIF_TERM recvRef ,
@@ -2725,7 +2731,7 @@ ERL_NIF_TERM essio_recv(ErlNifEnv* env,
2725
2731
int flags )
2726
2732
{
2727
2733
int saveErrno ;
2728
- ErlNifBinary buf ;
2734
+ ErlNifBinary bin , * bufP ;
2729
2735
ssize_t readResult ;
2730
2736
size_t bufSz = (len != 0 ? len : descP -> rBufSz ); // 0 means default
2731
2737
ERL_NIF_TERM ret ;
@@ -2746,16 +2752,8 @@ ERL_NIF_TERM essio_recv(ErlNifEnv* env,
2746
2752
return ret ;
2747
2753
}
2748
2754
2749
- /* Allocate the receive buffer */
2750
- if (descP -> buf .data == NULL ) {
2751
- ESOCK_ASSERT ( ALLOC_BIN (bufSz , & buf ) );
2752
- }
2753
- else {
2754
- buf = descP -> buf ;
2755
- if (buf .size != bufSz ) {
2756
- REALLOC_BIN (& buf , bufSz );
2757
- }
2758
- }
2755
+ bufP = & descP -> buf ;
2756
+ ESOCK_ASSERT ( recv_alloc_buf (bufSz , bufP ) );
2759
2757
2760
2758
SSDBG ( descP , ("UNIX-ESSIO" , "essio_recv {%d} -> try read (%lu)\r\n" ,
2761
2759
descP -> sock , (unsigned long ) len ) );
@@ -2764,7 +2762,7 @@ ERL_NIF_TERM essio_recv(ErlNifEnv* env,
2764
2762
esock_atom_read_tries , & descP -> readTries , 1 );
2765
2763
2766
2764
/* recv() */
2767
- readResult = sock_recv (descP -> sock , buf . data , buf . size , flags );
2765
+ readResult = sock_recv (descP -> sock , bufP -> data , bufP -> size , flags );
2768
2766
saveErrno = ESOCK_IS_ERROR (readResult ) ? sock_errno () : 0 ;
2769
2767
2770
2768
SSDBG ( descP , ("UNIX-ESSIO" ,
@@ -2775,40 +2773,25 @@ ERL_NIF_TERM essio_recv(ErlNifEnv* env,
2775
2773
if (! recv_check_result (env , descP , sockRef , recvRef ,
2776
2774
readResult , saveErrno , & ret ) ) {
2777
2775
/* Keep the buffer */
2778
- descP -> buf = buf ;
2779
2776
return ret ;
2780
2777
}
2781
2778
/* readResult >= 0 */
2782
- ESOCK_ASSERT ( readResult <= buf .size );
2783
2779
2784
- if (readResult < buf .size ) {
2780
+ ESOCK_ASSERT ( recv_create_bin (bufP , readResult , & bin ) );
2781
+
2782
+ if (bin .size < bufP -> size ) {
2785
2783
2786
2784
/* +++ We did not fill the buffer +++ */
2787
2785
2788
2786
SSDBG ( descP ,
2789
2787
("UNIX-ESSIO" ,
2790
2788
"essio_recv {%d} -> [%lu] "
2791
2789
"did not fill the buffer (%ld)\r\n" ,
2792
- descP -> sock , (unsigned long ) buf .size ,
2793
- (long ) readResult ) );
2794
-
2795
- if (// Less than 4K (1 page) wasted
2796
- readResult >= (buf .size & ~4095 ) ||
2797
- // Less than 25% wasted
2798
- readResult >= (buf .size >> 1 ) + (buf .size >> 2 )) {
2799
- //
2800
- /* Reallocate and drop buffer */
2801
- descP -> buf .data = NULL ;
2802
- ESOCK_ASSERT ( REALLOC_BIN (& buf , readResult ) );
2803
- }
2804
- else {
2805
- /* Keep buffer, copy content to new binary*/
2806
- descP -> buf = buf ;
2807
- ESOCK_ASSERT ( ALLOC_BIN (readResult , & buf ) );
2808
- sys_memcpy (buf .data , descP -> buf .data , buf .size );
2809
- }
2790
+ descP -> sock , (unsigned long ) bufP -> size ,
2791
+ (unsigned long ) bin .size ) );
2792
+
2810
2793
/* Return {ok|timeout|select|select_read, Bin} */
2811
- return recv_check_partial (env , descP , sockRef , recvRef , len , & buf );
2794
+ return recv_check_partial (env , descP , sockRef , recvRef , len , & bin );
2812
2795
2813
2796
} else {
2814
2797
@@ -2817,11 +2800,10 @@ ERL_NIF_TERM essio_recv(ErlNifEnv* env,
2817
2800
SSDBG ( descP ,
2818
2801
("UNIX-ESSIO" ,
2819
2802
"essio_recv {%d} -> [%lu] filled the buffer\r\n" ,
2820
- descP -> sock , (unsigned long ) buf .size ) );
2803
+ descP -> sock , (unsigned long ) bin .size ) );
2821
2804
2822
- descP -> buf .data = NULL ; // Drop buffer
2823
2805
/* Return {more|ok|select_read, Bin} */
2824
- return recv_check_full (env , descP , sockRef , recvRef , len , & buf );
2806
+ return recv_check_full (env , descP , sockRef , recvRef , len , & bin );
2825
2807
}
2826
2808
}
2827
2809
@@ -2844,7 +2826,7 @@ ERL_NIF_TERM essio_recvfrom(ErlNifEnv* env,
2844
2826
SOCKLEN_T fromAddrLen ;
2845
2827
ssize_t readResult ;
2846
2828
int saveErrno ;
2847
- ErlNifBinary buf ;
2829
+ ErlNifBinary bin , * bufP ;
2848
2830
size_t bufSz = (len != 0 ? len : descP -> rBufSz ); // 0 means default
2849
2831
ERL_NIF_TERM ret ;
2850
2832
@@ -2861,8 +2843,8 @@ ERL_NIF_TERM essio_recvfrom(ErlNifEnv* env,
2861
2843
return ret ;
2862
2844
}
2863
2845
2864
- /* Allocate the receive buffer */
2865
- ESOCK_ASSERT ( ALLOC_BIN (bufSz , & buf ) );
2846
+ bufP = & descP -> buf ;
2847
+ ESOCK_ASSERT ( recv_alloc_buf (bufSz , bufP ) );
2866
2848
2867
2849
ESOCK_CNT_INC (env , descP , sockRef ,
2868
2850
esock_atom_read_tries , & descP -> readTries , 1 );
@@ -2871,18 +2853,19 @@ ERL_NIF_TERM essio_recvfrom(ErlNifEnv* env,
2871
2853
sys_memzero ((char * ) & fromAddr , fromAddrLen );
2872
2854
2873
2855
/* recvfrom() */
2874
- readResult = sock_recvfrom (descP -> sock , buf . data , buf . size , flags ,
2856
+ readResult = sock_recvfrom (descP -> sock , bufP -> data , bufP -> size , flags ,
2875
2857
& fromAddr .sa , & fromAddrLen );
2876
2858
saveErrno = ESOCK_IS_ERROR (readResult ) ? sock_errno () : 0 ;
2877
2859
2878
2860
/* Check for errors and end of stream */
2879
2861
if (! recv_check_result (env , descP , sockRef , recvRef ,
2880
2862
readResult , saveErrno , & ret ) ) {
2881
- FREE_BIN ( & buf );
2863
+ /* Keep the buffer */
2882
2864
return ret ;
2883
2865
}
2884
2866
/* readResult >= 0 */
2885
- ESOCK_ASSERT ( readResult <= buf .size );
2867
+
2868
+ ESOCK_ASSERT ( recv_create_bin (bufP , readResult , & bin ) );
2886
2869
2887
2870
/* The recvfrom function delivers one (1) message. If our buffer
2888
2871
* is too small, the message will be truncated. So, regardless
@@ -2892,18 +2875,14 @@ ERL_NIF_TERM essio_recvfrom(ErlNifEnv* env,
2892
2875
* Encode the message and source address
2893
2876
*/
2894
2877
2895
- if (readResult < buf .size ) {
2896
- ESOCK_ASSERT ( REALLOC_BIN (& buf , readResult ) );
2897
- }
2898
-
2899
2878
descP -> rNumCnt = 0 ;
2900
2879
2901
2880
ESOCK_CNT_INC (env , descP , sockRef , esock_atom_read_pkg ,
2902
2881
& descP -> readPkgCnt , 1 );
2903
2882
ESOCK_CNT_INC (env , descP , sockRef , esock_atom_read_byte ,
2904
- & descP -> readByteCnt , buf .size );
2905
- if (buf .size > descP -> readPkgMax )
2906
- descP -> readPkgMax = buf .size ;
2883
+ & descP -> readByteCnt , bin .size );
2884
+ if (bin .size > descP -> readPkgMax )
2885
+ descP -> readPkgMax = bin .size ;
2907
2886
2908
2887
esock_encode_sockaddr (env ,
2909
2888
& fromAddr , fromAddrLen ,
@@ -2913,7 +2892,7 @@ ERL_NIF_TERM essio_recvfrom(ErlNifEnv* env,
2913
2892
* erlang term in env (no need to free; it will be GC:ed).
2914
2893
*/
2915
2894
/* {FromAddr, Bin} */
2916
- ret = MKT2 (env , ret , MKBIN (env , & buf ));
2895
+ ret = MKT2 (env , ret , MKBIN (env , & bin ));
2917
2896
2918
2897
if (descP -> selectRead && (COMPARE (recvRef , esock_atom_zero ) != 0 )) {
2919
2898
/* Return {select_read, {FromAddr, Bin}} */
@@ -2950,8 +2929,7 @@ ERL_NIF_TERM essio_recvmsg(ErlNifEnv* env,
2950
2929
size_t ctrlSz = (ctrlLen != 0 ? ctrlLen : descP -> rCtrlSz );
2951
2930
struct msghdr msgHdr ;
2952
2931
SysIOVec iov [1 ]; // Shall we always use 1?
2953
- ErlNifBinary data [1 ]; // Shall we always use 1?
2954
- ErlNifBinary ctrl ;
2932
+ ErlNifBinary ctrl , bin , * bufP ;
2955
2933
ERL_NIF_TERM ret ;
2956
2934
ESockAddress addr ;
2957
2935
@@ -2970,9 +2948,10 @@ ERL_NIF_TERM essio_recvmsg(ErlNifEnv* env,
2970
2948
return ret ;
2971
2949
}
2972
2950
2973
- /* Allocate the (msg) data buffer:
2951
+ /* Allocate the data buffer
2974
2952
*/
2975
- ESOCK_ASSERT ( ALLOC_BIN (bufSz , & data [0 ]) );
2953
+ bufP = & descP -> buf ;
2954
+ ESOCK_ASSERT ( recv_alloc_buf (bufSz , bufP ) );
2976
2955
2977
2956
/* Allocate the ctrl (buffer):
2978
2957
*/
@@ -2985,8 +2964,8 @@ ERL_NIF_TERM essio_recvmsg(ErlNifEnv* env,
2985
2964
sys_memzero ((char * ) & addr , addrLen );
2986
2965
sys_memzero ((char * ) & msgHdr , sizeof (msgHdr ));
2987
2966
2988
- iov [0 ].iov_base = data [ 0 ]. data ;
2989
- iov [0 ].iov_len = data [ 0 ]. size ;
2967
+ iov [0 ].iov_base = bufP -> data ;
2968
+ iov [0 ].iov_len = bufP -> size ;
2990
2969
2991
2970
msgHdr .msg_name = & addr ;
2992
2971
msgHdr .msg_namelen = addrLen ;
@@ -3002,12 +2981,14 @@ ERL_NIF_TERM essio_recvmsg(ErlNifEnv* env,
3002
2981
/* Check for errors and end of stream */
3003
2982
if (! recv_check_result (env , descP , sockRef , recvRef ,
3004
2983
readResult , saveErrno , & ret ) ) {
3005
- FREE_BIN ( & data [ 0 ]);
2984
+ /* Keep the data buffer */
3006
2985
FREE_BIN (& ctrl );
3007
2986
return ret ;
3008
2987
}
3009
2988
/* readResult >= 0 */
3010
2989
2990
+ ESOCK_ASSERT ( recv_create_bin (bufP , readResult , & bin ) );
2991
+
3011
2992
/* The recvmsg function delivers one (1) message. If our buffer
3012
2993
* is to small, the message will be truncated. So, regardless
3013
2994
* if we filled the buffer or not, we have got what we are going
@@ -3038,7 +3019,7 @@ ERL_NIF_TERM essio_recvmsg(ErlNifEnv* env,
3038
3019
descP -> readPkgMax = readResult ;
3039
3020
3040
3021
encode_msg (env , descP ,
3041
- readResult , & msgHdr , & data [ 0 ] , & ctrl ,
3022
+ readResult , & msgHdr , & bin , & ctrl ,
3042
3023
& ret );
3043
3024
3044
3025
if (descP -> selectRead && (COMPARE (recvRef , esock_atom_zero ) != 0 )) {
@@ -6861,6 +6842,55 @@ void essio_down(ErlNifEnv* env,
6861
6842
6862
6843
/* *** Recv/recvfrom/recvmsg utility functions *** */
6863
6844
6845
+ static
6846
+ BOOLEAN_T recv_alloc_buf (size_t size ,
6847
+ ErlNifBinary * bufP )
6848
+ {
6849
+ if (bufP -> data == NULL ) {
6850
+ return ALLOC_BIN (size , bufP );
6851
+ }
6852
+ else {
6853
+ if (size != bufP -> size )
6854
+ return REALLOC_BIN (bufP , size );
6855
+ else
6856
+ return TRUE;
6857
+ }
6858
+ }
6859
+
6860
+ static
6861
+ BOOLEAN_T recv_create_bin (ErlNifBinary * bufP , size_t size , ErlNifBinary * binP )
6862
+ {
6863
+ /* Don't touch bufP->size
6864
+ */
6865
+ if (size >= bufP -> size ) {
6866
+ /* Buffer full
6867
+ * - use it as return binary and drop buffer
6868
+ */
6869
+ ESOCK_ASSERT ( bufP -> size >= size );
6870
+ * binP = * bufP ;
6871
+ bufP -> data = NULL ;
6872
+ return TRUE;
6873
+ }
6874
+ else if (size >= (bufP -> size & ~4095 ) ||
6875
+ size >= (bufP -> size >> 1 ) + (bufP -> size >> 2 )) {
6876
+ /* Less than a 4 K page shrink or less than 25% shrink
6877
+ * - reallocate and drop buffer
6878
+ */
6879
+ * binP = * bufP ;
6880
+ bufP -> data = NULL ;
6881
+ return REALLOC_BIN (binP , size );
6882
+ }
6883
+ else {
6884
+ BOOLEAN_T ret ;
6885
+ /* Keep buffer, copy content to new allocated binary
6886
+ */
6887
+ ret = ALLOC_BIN (size , binP );
6888
+ if (ret )
6889
+ sys_memcpy (binP -> data , bufP -> data , size );
6890
+ return ret ;
6891
+ }
6892
+ }
6893
+
6864
6894
static
6865
6895
BOOLEAN_T recv_check_entry (ErlNifEnv * env ,
6866
6896
ESockDescriptor * descP ,
0 commit comments