Gen_TCP how to limit the size of the package

When we do TCP servers, we usually cause damage to both security attacks or to avoid extreme requests from safety, and prevent extreme requests for business.

Our TCP servers are usually doing Erlang, then Gen_TCP is involved in how Gen_TCP restricts the size of the package.

Gen_TCP has two ways to get the package:

1. {Active, False} Packet is received through Gen_TCP: Recv (Socket, LENGTH) -> {OK, Packet} | {Error, Reason}.

2. {Active, True} Pack is delivered in a message.

For the first way: Gen_tcp: Recv (socket, length) We will open the down code implementation:

/ * Inet_drv.c * / # define TCP_MAX_PACKET_SIZE 0x4000000 / * 64 M * // * TCP requests from Erlang * / static ErlDrvSSizeT tcp_inet_ctl (ErlDrvData e, unsigned int cmd, char * buf, ErlDrvSizeT len, char ** rbuf, ErlDrvSizeT rsize ) {… case tcp_req_recv: {Unsigned Timeout; char TBUF [2]; int N; debugf ((“TCP_INET_CTL (% ld): Recv

“(long) desc-> inet.port)); / * Input: Timeout (4), Length (4) * / if (! is_connected)) {if (desc-> tcp_add_flags & tcp_addf_delayed_close_recv) {desc-> tcp_add_flags & ~ (TCP_ADDF_DELAYED_CLOSE_RECV | TCP_ADDF_DELAYED_CLOSE_SEND); return ctl_reply (INET_REP_ERROR, “closed”, 6, rbuf, rsize);} return ctl_error (ENOTCONN, rbuf, rsize);} if (desc-> | | (LEN! 8)) RETURN CTL_ERROR (EINVAL, RBUF, RSIZE); TIMEOUT GET_INT32 (BUF); BUF + 4; N get_int32 (buf); debugf (“” TCP_INET_CTL (% LD) TIMEOUT% D, N% D

“, (long) desc-> inet.port, timeout, n)); (long) desc-> inet.port, timeout, n)); if ((Desc-> INET.HTYPE! TCP_PB_RAW) && (N! 0)) return ctl_error (EINVAL, rbuf, rsize); if (n> TCP_MAX_PACKET_SIZE) return ctl_error (ENOMEM, rbuf, rsize); if (enq_async (INETP (desc), tbuf, TCP_REQ_RECV) is_IGNORED || TCP_RECV (DESC, N) 0) {…}

Logically is simple, if the type of packet is TCP_PB_RAW, it is necessary to explicitly specify the length, otherwise the length of the package is determined by the peer, and the length can only be set to 0. Then call TCP_RECV to receive data asynchronously. In the previous blog post, when TCP_RECV data, it is necessary to allocate the buffer, the size of the buffer is N, so it has been limited here, which cannot exceed TCP_MAX_PACKET_SIZE, that is, the maximum 64m, more than the Meeting ENOMEM error !

For the case of active delivery of the second message:

From document inet: setopts you can see: {packet_size, integer} (TCP / IP Sockets)


For Line Oriented Protocols (Line, http *), Option Packet_size Also Guarantees That Lines Up To The Indicated INVALID DUE TO INTERNAL BUFFER LIMITATIONS.

Then how this limit does it work, and look at the code:

/*ET_DRV.C * / TYPEDEF STRUCT {… unsigned int psize; / * max packet size (tcp only?) * / …} inet_descriptor; static int inet_set_opts (inet_descriptor * desc, char * ptr, int LEN) {… case inet_lopt_packet_size: debugf (“inet_set_opts (% ld): S% D, packet_size% d

“, (long) desc-> port, desc-> s, ival); desc-> psize (unsigned int) ival; continue; …} / * allocate descriptor * / static erdrvdata inet_start (Erldrvport Port, int size , int protocol) {… desc-> psize 0; / * no size check * …} / * Copy a descriptor, by Creating a new port with same settings * as the descriptor desc. * Return Null On Error SYSTEM_LIMIT no ports avail) * / static tcp_descriptor * tcp_inet_copy (tcp_descriptor * desc, SOCKET s, ErlDrvTermData owner, int * err) {… copy_desc-> inet.psize desc-> inet.psize; …} static int tcp_remain (TCP_DESCRIPTOR * DESC, INT * LEN) {… Debugf (“TCP_REMAIN (% LD): S% D, N% D, NFILL% D NSZ% D

“(long) desc-> inet.port, desc-> inet.s, n, nfill, nsz)); tlen packet_get_length (desc-> inet.htype, ptr, n, desc-> inet.psize, desc- > i_bufsz, & desc-> http_state); if (tlen> 0) {if (tlen nothing remain packet% d

“, tlen); RETURN 0;} else {/ * ned kNown more * / if (TCP_EXPAND_BUFFER (DESC, TLEN) remain% d

“, * len); return * len;}} else if (tlen 0) {/ * nesed unknown more * / * len 0; if (nsz 0) {if (nfill n) {if (desc-> inet. Psize! 0 && Desc-> inet.psize> nfill) {IF (tcp_expand_buffer (desc, desc-> inet.psize) inet.psize;} elsegoto error;} debugf “RESTART MORE% D

“, nfill – n)); Return nfill – n;} else {debugf ((“> more% d)

“, nsz)); return nsz;}} error: debugf ((“>

Packet error

“)); return -1; …} static int TCP_RECV (TCP_DESCRIPTOR * DESC, INT Request_len) {… else if (desc-> i_remain 0) {/ * Poll Remain from buffer data * / if ((NREAD) TCP_REMAIN (DESC, & LEN)) 0) Desc-> i_remain len; / * set remain * / }… }/* packet_parser.c * // * Return> 0 Total packet bytes * 0 Length unknown, need more data. *

] * / const char * ptr2; IF ((Ptr2 Memchr (PTR, ‘