#include <haproxy/listener-t.h>
#include <haproxy/sock-t.h>
-int sock_create_server_socket(struct connection *conn);
+int sock_create_server_socket(struct connection *conn, struct proxy *be);
void sock_enable(struct receiver *rx);
void sock_disable(struct receiver *rx);
void sock_unbind(struct receiver *rx);
return SF_ERR_INTERNAL;
}
- fd = conn->handle.fd = sock_create_server_socket(conn);
-
- if (fd == -1) {
- qfprintf(stderr, "Cannot get a server socket.\n");
-
- if (errno == ENFILE) {
- conn->err_code = CO_ER_SYS_FDLIM;
- send_log(be, LOG_EMERG,
- "Proxy %s reached system FD limit (maxsock=%d). Please check system tunables.\n",
- be->id, global.maxsock);
- }
- else if (errno == EMFILE) {
- conn->err_code = CO_ER_PROC_FDLIM;
- send_log(be, LOG_EMERG,
- "Proxy %s reached process FD limit (maxsock=%d). Please check 'ulimit-n' and restart.\n",
- be->id, global.maxsock);
- }
- else if (errno == ENOBUFS || errno == ENOMEM) {
- conn->err_code = CO_ER_SYS_MEMLIM;
- send_log(be, LOG_EMERG,
- "Proxy %s reached system memory limit (maxsock=%d). Please check system tunables.\n",
- be->id, global.maxsock);
- }
- else if (errno == EAFNOSUPPORT || errno == EPROTONOSUPPORT) {
- conn->err_code = CO_ER_NOPROTO;
- }
- else
- conn->err_code = CO_ER_SOCK_ERR;
-
- /* this is a resource error */
- conn->flags |= CO_FL_ERROR;
- return SF_ERR_RESOURCE;
- }
-
- if (fd >= global.maxsock) {
- /* do not log anything there, it's a normal condition when this option
- * is used to serialize connections to a server !
- */
- ha_alert("socket(): not enough free sockets. Raise -n argument. Giving up.\n");
- close(fd);
- conn->err_code = CO_ER_CONF_FDLIM;
- conn->flags |= CO_FL_ERROR;
- return SF_ERR_PRXCOND; /* it is a configuration limit */
- }
-
- if (fd_set_nonblock(fd) == -1) {
- qfprintf(stderr,"Cannot set client socket to non blocking mode.\n");
- close(fd);
- conn->err_code = CO_ER_SOCK_ERR;
- conn->flags |= CO_FL_ERROR;
- return SF_ERR_INTERNAL;
- }
-
- if (master == 1 && fd_set_cloexec(fd) == -1) {
- ha_alert("Cannot set CLOEXEC on client socket.\n");
- close(fd);
- conn->err_code = CO_ER_SOCK_ERR;
- conn->flags |= CO_FL_ERROR;
- return SF_ERR_INTERNAL;
- }
+ /* perform common checks on obtained socket FD, return appropriate Stream Error Flag in case of failure */
+ fd = conn->handle.fd = sock_create_server_socket(conn, be);
+ if (fd & SF_ERR_MASK)
+ return fd;
+ /* FD is ok, perform protocol specific settings */
/* allow specific binding :
* - server-specific at first
* - proxy-specific next
return SF_ERR_INTERNAL;
}
- fd = conn->handle.fd = sock_create_server_socket(conn);
- if (fd == -1) {
- qfprintf(stderr, "Cannot get a server socket.\n");
- if (errno == ENFILE) {
- conn->err_code = CO_ER_SYS_FDLIM;
- send_log(be, LOG_EMERG,
- "Proxy %s reached system FD limit (maxsock=%d). Please check system tunables.\n",
- be->id, global.maxsock);
- }
- else if (errno == EMFILE) {
- conn->err_code = CO_ER_PROC_FDLIM;
- send_log(be, LOG_EMERG,
- "Proxy %s reached process FD limit (maxsock=%d). Please check 'ulimit-n' and restart.\n",
- be->id, global.maxsock);
- }
- else if (errno == ENOBUFS || errno == ENOMEM) {
- conn->err_code = CO_ER_SYS_MEMLIM;
- send_log(be, LOG_EMERG,
- "Proxy %s reached system memory limit (maxsock=%d). Please check system tunables.\n",
- be->id, global.maxsock);
- }
- else if (errno == EAFNOSUPPORT || errno == EPROTONOSUPPORT) {
- conn->err_code = CO_ER_NOPROTO;
- }
- else
- conn->err_code = CO_ER_SOCK_ERR;
-
- /* this is a resource error */
- conn->flags |= CO_FL_ERROR;
- return SF_ERR_RESOURCE;
- }
-
- if (fd >= global.maxsock) {
- /* do not log anything there, it's a normal condition when this option
- * is used to serialize connections to a server !
- */
- ha_alert("socket(): not enough free sockets. Raise -n argument. Giving up.\n");
- close(fd);
- conn->err_code = CO_ER_CONF_FDLIM;
- conn->flags |= CO_FL_ERROR;
- return SF_ERR_PRXCOND; /* it is a configuration limit */
- }
-
- if (fd_set_nonblock(fd) == -1 ||
- (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(one)) == -1)) {
- qfprintf(stderr,"Cannot set client socket to non blocking mode.\n");
- close(fd);
- conn->err_code = CO_ER_SOCK_ERR;
- conn->flags |= CO_FL_ERROR;
- return SF_ERR_INTERNAL;
- }
-
- if (master == 1 && fd_set_cloexec(fd) == -1) {
- ha_alert("Cannot set CLOEXEC on client socket.\n");
- close(fd);
- conn->err_code = CO_ER_SOCK_ERR;
- conn->flags |= CO_FL_ERROR;
- return SF_ERR_INTERNAL;
- }
+ /* perform common checks on obtained socket FD, return appropriate Stream Error Flag in case of failure */
+ fd = conn->handle.fd = sock_create_server_socket(conn, be);
+ if ((fd & SF_ERR_MASK) == fd)
+ return fd;
+ /* FD is OK, continue with protocol specific settings */
if (be->options & PR_O_TCP_SRV_KA) {
setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &one, sizeof(one));
return SF_ERR_INTERNAL;
}
- fd = conn->handle.fd = sock_create_server_socket(conn);
- if (fd == -1) {
- qfprintf(stderr, "Cannot get a server socket.\n");
-
- if (errno == ENFILE) {
- conn->err_code = CO_ER_SYS_FDLIM;
- send_log(be, LOG_EMERG,
- "Proxy %s reached system FD limit (maxsock=%d). Please check system tunables.\n",
- be->id, global.maxsock);
- }
- else if (errno == EMFILE) {
- conn->err_code = CO_ER_PROC_FDLIM;
- send_log(be, LOG_EMERG,
- "Proxy %s reached process FD limit (maxsock=%d). Please check 'ulimit-n' and restart.\n",
- be->id, global.maxsock);
- }
- else if (errno == ENOBUFS || errno == ENOMEM) {
- conn->err_code = CO_ER_SYS_MEMLIM;
- send_log(be, LOG_EMERG,
- "Proxy %s reached system memory limit (maxsock=%d). Please check system tunables.\n",
- be->id, global.maxsock);
- }
- else if (errno == EAFNOSUPPORT || errno == EPROTONOSUPPORT) {
- conn->err_code = CO_ER_NOPROTO;
- }
- else
- conn->err_code = CO_ER_SOCK_ERR;
-
- /* this is a resource error */
- conn->flags |= CO_FL_ERROR;
- return SF_ERR_RESOURCE;
- }
-
- if (fd >= global.maxsock) {
- /* do not log anything there, it's a normal condition when this option
- * is used to serialize connections to a server !
- */
- ha_alert("socket(): not enough free sockets. Raise -n argument. Giving up.\n");
- close(fd);
- conn->err_code = CO_ER_CONF_FDLIM;
- conn->flags |= CO_FL_ERROR;
- return SF_ERR_PRXCOND; /* it is a configuration limit */
- }
-
- if (fd_set_nonblock(fd) == -1) {
- qfprintf(stderr,"Cannot set client socket to non blocking mode.\n");
- close(fd);
- conn->err_code = CO_ER_SOCK_ERR;
- conn->flags |= CO_FL_ERROR;
- return SF_ERR_INTERNAL;
- }
-
- if (master == 1 && fd_set_cloexec(fd) == -1) {
- ha_alert("Cannot set CLOEXEC on client socket.\n");
- close(fd);
- conn->err_code = CO_ER_SOCK_ERR;
- conn->flags |= CO_FL_ERROR;
- return SF_ERR_INTERNAL;
- }
+ /* perform common checks on obtained socket FD, return appropriate Stream Error Flag in case of failure */
+ fd = conn->handle.fd = sock_create_server_socket(conn, be);
+ if (fd & SF_ERR_MASK)
+ return fd;
+ /* FD is ok, continue with protocol specific settings */
if (global.tune.server_sndbuf)
setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &global.tune.server_sndbuf, sizeof(global.tune.server_sndbuf));
goto done;
}
+/* Common code to handle in one place different ERRNOs, that socket() et setns()
+ * may return
+ */
+static int sock_handle_system_err(struct connection *conn, struct proxy *be)
+{
+ qfprintf(stderr, "Cannot get a server socket.\n");
+
+ conn->flags |= CO_FL_ERROR;
+ conn->err_code = CO_ER_SOCK_ERR;
+
+ switch(errno) {
+ case ENFILE:
+ conn->err_code = CO_ER_SYS_FDLIM;
+ send_log(be, LOG_EMERG,
+ "Proxy %s reached system FD limit (maxsock=%d). "
+ "Please check system tunables.\n", be->id, global.maxsock);
+
+ return SF_ERR_RESOURCE;
+
+ case EMFILE:
+ conn->err_code = CO_ER_PROC_FDLIM;
+ send_log(be, LOG_EMERG,
+ "Proxy %s reached process FD limit (maxsock=%d). "
+ "Please check 'ulimit-n' and restart.\n", be->id, global.maxsock);
+
+ return SF_ERR_RESOURCE;
+
+ case ENOBUFS:
+ case ENOMEM:
+ conn->err_code = CO_ER_SYS_MEMLIM;
+ send_log(be, LOG_EMERG,
+ "Proxy %s reached system memory limit (maxsock=%d). "
+ "Please check system tunables.\n", be->id, global.maxsock);
+
+ return SF_ERR_RESOURCE;
+
+ case EAFNOSUPPORT:
+ case EPROTONOSUPPORT:
+ conn->err_code = CO_ER_NOPROTO;
+ break;
+
+ default:
+ send_log(be, LOG_EMERG,
+ "Proxy %s cannot create a server socket: %s\n",
+ be->id, strerror(errno));
+ }
+
+ return SF_ERR_INTERNAL;
+}
+
/* Create a socket to connect to the server in conn->dst (which MUST be valid),
* using the configured namespace if needed, or the one passed by the proxy
* protocol if required to do so. It then calls socket() or socketat(). On
* success, checks if mark or tos sockopts need to be set on the file handle.
* Returns the FD or error code.
*/
-int sock_create_server_socket(struct connection *conn)
+int sock_create_server_socket(struct connection *conn, struct proxy *be)
{
const struct netns_entry *ns = NULL;
int sock_fd;
}
#endif
sock_fd = my_socketat(ns, conn->dst->ss_family, SOCK_STREAM, 0);
- if (sock_fd == -1)
- goto end;
+
+ /* at first, handle common to all proto families system limits and permission related errors */
+ if (sock_fd == -1) {
+ return sock_handle_system_err(conn, be);
+ }
+
+ /* now perform some runtime condition checks */
+ if (sock_fd >= global.maxsock) {
+ /* do not log anything there, it's a normal condition when this option
+ * is used to serialize connections to a server !
+ */
+ ha_alert("socket(): not enough free sockets. Raise -n argument. Giving up.\n");
+ send_log(be, LOG_EMERG, "socket(): not enough free sockets. Raise -n argument. Giving up.\n");
+ close(sock_fd);
+ conn->err_code = CO_ER_CONF_FDLIM;
+ conn->flags |= CO_FL_ERROR;
+
+ return SF_ERR_PRXCOND; /* it is a configuration limit */
+ }
+
+ if (fd_set_nonblock(sock_fd) == -1 ||
+ ((conn->ctrl->sock_prot == IPPROTO_TCP) && (setsockopt(sock_fd, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(one)) == -1))) {
+ qfprintf(stderr,"Cannot set client socket to non blocking mode.\n");
+ send_log(be, LOG_EMERG, "Cannot set client socket to non blocking mode.\n");
+ close(sock_fd);
+ conn->err_code = CO_ER_SOCK_ERR;
+ conn->flags |= CO_FL_ERROR;
+
+ return SF_ERR_INTERNAL;
+ }
+
+ if (master == 1 && fd_set_cloexec(sock_fd) == -1) {
+ ha_alert("Cannot set CLOEXEC on client socket.\n");
+ send_log(be, LOG_EMERG, "Cannot set CLOEXEC on client socket.\n");
+ close(sock_fd);
+ conn->err_code = CO_ER_SOCK_ERR;
+ conn->flags |= CO_FL_ERROR;
+
+ return SF_ERR_INTERNAL;
+ }
+
if (conn->flags & CO_FL_OPT_MARK)
sock_set_mark(sock_fd, conn->ctrl->fam->sock_family, conn->mark);
if (conn->flags & CO_FL_OPT_TOS)
sock_set_tos(sock_fd, conn->dst, conn->tos);
- end:
return sock_fd;
}