Changeset View
Changeset View
Standalone View
Standalone View
head/sys/kern/uipc_socket.c
Show First 20 Lines • Show All 569 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
#ifdef REGRESSION | #ifdef REGRESSION | ||||
static int regression_sonewconn_earlytest = 1; | static int regression_sonewconn_earlytest = 1; | ||||
SYSCTL_INT(_regression, OID_AUTO, sonewconn_earlytest, CTLFLAG_RW, | SYSCTL_INT(_regression, OID_AUTO, sonewconn_earlytest, CTLFLAG_RW, | ||||
®ression_sonewconn_earlytest, 0, "Perform early sonewconn limit test"); | ®ression_sonewconn_earlytest, 0, "Perform early sonewconn limit test"); | ||||
#endif | #endif | ||||
static struct timeval overinterval = { 60, 0 }; | |||||
SYSCTL_TIMEVAL_SEC(_kern_ipc, OID_AUTO, sooverinterval, CTLFLAG_RW, | |||||
&overinterval, | |||||
"Delay in seconds between warnings for listen socket overflows"); | |||||
/* | /* | ||||
* When an attempt at a new connection is noted on a socket which accepts | * When an attempt at a new connection is noted on a socket which accepts | ||||
* connections, sonewconn is called. If the connection is possible (subject | * connections, sonewconn is called. If the connection is possible (subject | ||||
* to space constraints, etc.) then we allocate a new structure, properly | * to space constraints, etc.) then we allocate a new structure, properly | ||||
* linked into the data structure of the original socket, and return this. | * linked into the data structure of the original socket, and return this. | ||||
* Connstatus may be 0, or SS_ISCONFIRMING, or SS_ISCONNECTED. | * Connstatus may be 0, or SS_ISCONFIRMING, or SS_ISCONNECTED. | ||||
* | * | ||||
* Note: the ref count on the socket is 0 on return. | * Note: the ref count on the socket is 0 on return. | ||||
*/ | */ | ||||
struct socket * | struct socket * | ||||
sonewconn(struct socket *head, int connstatus) | sonewconn(struct socket *head, int connstatus) | ||||
{ | { | ||||
static struct timeval lastover; | |||||
static struct timeval overinterval = { 60, 0 }; | |||||
static int overcount; | |||||
struct sbuf descrsb; | struct sbuf descrsb; | ||||
struct socket *so; | struct socket *so; | ||||
u_int over; | int len, overcount; | ||||
int len; | u_int qlen; | ||||
const char localprefix[] = "local:"; | const char localprefix[] = "local:"; | ||||
char descrbuf[SUNPATHLEN + sizeof(localprefix)]; | char descrbuf[SUNPATHLEN + sizeof(localprefix)]; | ||||
#if defined(INET6) | #if defined(INET6) | ||||
char addrbuf[INET6_ADDRSTRLEN]; | char addrbuf[INET6_ADDRSTRLEN]; | ||||
#elif defined(INET) | #elif defined(INET) | ||||
char addrbuf[INET_ADDRSTRLEN]; | char addrbuf[INET_ADDRSTRLEN]; | ||||
#endif | #endif | ||||
bool dolog, over; | |||||
SOLISTEN_LOCK(head); | SOLISTEN_LOCK(head); | ||||
over = (head->sol_qlen > 3 * head->sol_qlimit / 2); | over = (head->sol_qlen > 3 * head->sol_qlimit / 2); | ||||
SOLISTEN_UNLOCK(head); | |||||
#ifdef REGRESSION | #ifdef REGRESSION | ||||
if (regression_sonewconn_earlytest && over) { | if (regression_sonewconn_earlytest && over) { | ||||
#else | #else | ||||
if (over) { | if (over) { | ||||
#endif | #endif | ||||
overcount++; | head->sol_overcount++; | ||||
dolog = !!ratecheck(&head->sol_lastover, &overinterval); | |||||
if (ratecheck(&lastover, &overinterval)) { | |||||
/* | /* | ||||
* If we're going to log, copy the overflow count and queue | |||||
* length from the listen socket before dropping the lock. | |||||
* Also, reset the overflow count. | |||||
*/ | |||||
if (dolog) { | |||||
overcount = head->sol_overcount; | |||||
head->sol_overcount = 0; | |||||
qlen = head->sol_qlen; | |||||
} | |||||
SOLISTEN_UNLOCK(head); | |||||
if (dolog) { | |||||
/* | |||||
* Try to print something descriptive about the | * Try to print something descriptive about the | ||||
* socket for the error message. | * socket for the error message. | ||||
*/ | */ | ||||
sbuf_new(&descrsb, descrbuf, sizeof(descrbuf), | sbuf_new(&descrsb, descrbuf, sizeof(descrbuf), | ||||
SBUF_FIXEDLEN); | SBUF_FIXEDLEN); | ||||
switch (head->so_proto->pr_domain->dom_family) { | switch (head->so_proto->pr_domain->dom_family) { | ||||
#if defined(INET) || defined(INET6) | #if defined(INET) || defined(INET6) | ||||
#ifdef INET | #ifdef INET | ||||
▲ Show 20 Lines • Show All 55 Lines • ▼ Show 20 Lines | #endif /* INET || INET6 */ | ||||
} | } | ||||
KASSERT(sbuf_len(&descrsb) > 0, | KASSERT(sbuf_len(&descrsb) > 0, | ||||
("%s: sbuf creation failed", __func__)); | ("%s: sbuf creation failed", __func__)); | ||||
log(LOG_DEBUG, | log(LOG_DEBUG, | ||||
"%s: pcb %p (%s): Listen queue overflow: " | "%s: pcb %p (%s): Listen queue overflow: " | ||||
"%i already in queue awaiting acceptance " | "%i already in queue awaiting acceptance " | ||||
"(%d occurrences)\n", | "(%d occurrences)\n", | ||||
__func__, head->so_pcb, sbuf_data(&descrsb), | __func__, head->so_pcb, sbuf_data(&descrsb), | ||||
head->sol_qlen, overcount); | qlen, overcount); | ||||
sbuf_delete(&descrsb); | sbuf_delete(&descrsb); | ||||
overcount = 0; | overcount = 0; | ||||
} | } | ||||
return (NULL); | return (NULL); | ||||
} | } | ||||
SOLISTEN_UNLOCK(head); | |||||
VNET_ASSERT(head->so_vnet != NULL, ("%s: so %p vnet is NULL", | VNET_ASSERT(head->so_vnet != NULL, ("%s: so %p vnet is NULL", | ||||
__func__, head)); | __func__, head)); | ||||
so = soalloc(head->so_vnet); | so = soalloc(head->so_vnet); | ||||
if (so == NULL) { | if (so == NULL) { | ||||
log(LOG_DEBUG, "%s: pcb %p: New socket allocation failure: " | log(LOG_DEBUG, "%s: pcb %p: New socket allocation failure: " | ||||
"limit reached or out of memory\n", | "limit reached or out of memory\n", | ||||
__func__, head->so_pcb); | __func__, head->so_pcb); | ||||
return (NULL); | return (NULL); | ||||
▲ Show 20 Lines • Show All 3,630 Lines • Show Last 20 Lines |