10#include <sys/socket.h>
11#include <netinet/in.h>
43static int routemax = -1;
46static inline void fpm_sockets_get_env_name(
char *envname,
size_t envname_length,
unsigned idx)
49 strcpy(envname,
"FPM_SOCKETS");
51 snprintf(envname, envname_length,
"FPM_SOCKETS_%d", idx);
56static void fpm_sockets_cleanup(
int which,
void *
arg)
59 unsigned socket_set_count = 0;
61 unsigned socket_set_buf = 0;
67 for (i = 0; i < sockets_list.used; i++, ls++) {
76 tmpenv_value = realloc(env_value,
p + (
p ? 1 : 0) +
strlen(ls->
key) + 1 +
strlen(
fd) + socket_set_buf + 1);
78 zlog(
ZLOG_SYSERROR,
"failure to inherit data on parent exec for socket `%s` due to memory allocation failure", ls->
key);
83 env_value = tmpenv_value;
86 socket_set[socket_set_count] =
p + socket_set_buf;
89 *(env_value +
p + 1) = 0;
93 p +=
sprintf(env_value +
p + socket_set_buf,
"%s%s=%s", (
p && !socket_set_buf) ?
"," :
"", ls->
key,
fd);
106 for (i = 0; i < socket_set_count; i++) {
107 fpm_sockets_get_env_name(envname,
sizeof(envname), i);
108 setenv(envname, env_value + socket_set[i], 1);
110 fpm_sockets_get_env_name(envname,
sizeof(envname), socket_set_count);
115 fpm_array_free(&sockets_list);
119static void *fpm_get_in_addr(
struct sockaddr *sa)
121 if (sa->sa_family ==
AF_INET) {
122 return &(((
struct sockaddr_in*)sa)->sin_addr);
125 return &(((
struct sockaddr_in6*)sa)->sin6_addr);
129static int fpm_get_in_port(
struct sockaddr *sa)
131 if (sa->sa_family ==
AF_INET) {
132 return ntohs(((
struct sockaddr_in*)sa)->sin_port);
135 return ntohs(((
struct sockaddr_in6*)sa)->sin6_port);
139static int fpm_sockets_hash_op(
int sock,
struct sockaddr *sa,
char *
key,
int type,
int op)
145 inet_ntop(sa->sa_family, fpm_get_in_addr(sa),
key, INET6_ADDRSTRLEN);
147 snprintf(
key + key_length, INET6_ADDRSTRLEN + 10 - key_length,
":%d", fpm_get_in_port(sa));
152 struct sockaddr_un *sa_un = (
struct sockaddr_un *) sa;
154 strcpy(
key, sa_un->sun_path);
170 for (i = 0; i < sockets_list.used; i++, ls++) {
184 ls = fpm_array_push(&sockets_list);
205static int fpm_sockets_new_listening_socket(
struct fpm_worker_pool_s *wp,
struct sockaddr *sa,
int socklen)
224 zlog(
ZLOG_ERROR,
"Another FPM instance seems to already listen on %s", ((
struct sockaddr_un *) sa)->sun_path);
228 unlink( ((
struct sockaddr_un *) sa)->sun_path);
232 if (0 > bind(
sock, sa, socklen)) {
242 char *path = ((
struct sockaddr_un *) sa)->sun_path;
259 if (-1 < wp->
config->listen_setfib) {
260 if (routemax < wp->config->listen_setfib) {
261 zlog(
ZLOG_ERROR,
"Invalid routing table id %d, max is %d", wp->
config->listen_setfib, routemax);
276static int fpm_sockets_get_listening_socket(
struct fpm_worker_pool_s *wp,
struct sockaddr *sa,
int socklen)
285 sock = fpm_sockets_new_listening_socket(wp, sa, socklen);
294 if (
strchr(address,
':')) {
305static int fpm_socket_af_inet_socket_by_addr(
struct fpm_worker_pool_s *wp,
const char *
addr,
const char *port)
307 struct addrinfo hints, *servinfo, *
p;
308 char tmpbuf[INET6_ADDRSTRLEN];
312 memset(&hints, 0,
sizeof hints);
313 hints.ai_family = AF_UNSPEC;
316 if ((
status = getaddrinfo(
addr, port, &hints, &servinfo)) != 0) {
321 for (
p = servinfo;
p !=
NULL;
p =
p->ai_next) {
322 inet_ntop(
p->ai_family, fpm_get_in_addr(
p->ai_addr), tmpbuf, INET6_ADDRSTRLEN);
324 if ((sock = fpm_sockets_get_listening_socket(wp,
p->ai_addr,
p->ai_addrlen)) != -1) {
332 freeaddrinfo(servinfo);
341 char *port_str =
strrchr(dup_address,
':');
349 port = atoi(port_str);
354 if (
addr[0] ==
'[' &&
addr[addr_len - 1] ==
']') {
355 addr[addr_len - 1] =
'\0';
359 }
else if (
strlen(dup_address) ==
strspn(dup_address,
"0123456789")) {
360 port = atoi(dup_address);
361 port_str = dup_address;
364 if (port < 1 || port > 65535) {
372 sock = fpm_socket_af_inet_socket_by_addr(wp,
addr, port_str);
382 sock = fpm_socket_af_inet_socket_by_addr(wp,
"::", port_str);
386 zlog(
ZLOG_NOTICE,
"Failed implicitly binding to ::, retrying with 0.0.0.0");
387 sock = fpm_socket_af_inet_socket_by_addr(wp,
"0.0.0.0", port_str);
399 struct sockaddr_un sa_un;
400 size_t socket_length =
sizeof(sa_un.sun_path);
403 memset(&sa_un, 0,
sizeof(sa_un));
406 if (address_length >= socket_length) {
409 "[pool %s] cannot bind to UNIX socket '%s' as path is too long (found length: %zu, "
410 "maximal length: %zu), trying cut socket path instead '%s'",
420 return fpm_sockets_get_listening_socket(wp, (
struct sockaddr *) &sa_un,
sizeof(
struct sockaddr_un));
428 size_t len =
sizeof(routemax);
429 if (sysctlbyname(
"net.fibs", &routemax, &
len,
NULL, 0) < 0) {
452 if (fpm_socket_setfib_init() ==
FAILURE) {
459 fpm_sockets_get_env_name(envname,
sizeof(envname), i);
460 inherited =
getenv(envname);
465 while (inherited && *inherited) {
466 char *comma =
strchr(inherited,
',');
474 eq =
strchr(inherited,
'=');
476 int sockpath_len = eq - inherited;
477 if (sockpath_len > 255) {
481 memcpy(sockpath, inherited, sockpath_len);
482 sockpath[sockpath_len] =
'\0';
483 fd_no = atoi(eq + 1);
485 zlog(
ZLOG_NOTICE,
"using inherited socket fd=%d, \"%s\"", fd_no, sockpath);
490 inherited = comma + 1;
522 ls = sockets_list.data;
524 for (i = 0; i < sockets_list.used; ) {
531 fpm_array_item_remove(&sockets_list, i);
546#ifdef HAVE_LQ_TCP_INFO
548#include <netinet/tcp.h>
552 struct tcp_info info;
555 if (0 > getsockopt(sock, IPPROTO_TCP, TCP_INFO, &info, &
len)) {
559#if defined(__FreeBSD__) || defined(__NetBSD__)
560 if (info.__tcpi_sacked == 0) {
565 *cur_lq = info.__tcpi_unacked;
569 *max_lq = info.__tcpi_sacked;
573 if (info.tcpi_sacked == 0) {
578 *cur_lq = info.tcpi_unacked;
582 *max_lq = info.tcpi_sacked;
589#elif defined(HAVE_LQ_TCP_CONNECTION_INFO)
591#include <netinet/tcp.h>
595 struct tcp_connection_info info;
598 if (0 > getsockopt(sock, IPPROTO_TCP, TCP_CONNECTION_INFO, &info, &
len)) {
604 *cur_lq = info.tcpi_tfo_syn_data_acked;
614#elif defined(HAVE_LQ_SO_LISTENQ)
655 if (!sock || sock->sun_family !=
AF_UNIX) {
663 if (connect(
fd, (
struct sockaddr *)sock, socklen) == -1) {
unlink(string $filename, $context=null)
getenv(?string $name=null, bool $local_only=false)
strrchr(string $haystack, string $needle, bool $before_needle=false)
strspn(string $string, string $characters, int $offset=0, ?int $length=null)
strchr(string $haystack, string $needle, bool $before_needle=false)
memset(ptr, 0, type->size)
int fpm_cleanup_add(int type, void(*cleanup)(int, void *), void *arg)
@ FPM_CLEANUP_PARENT_EXEC
@ FPM_CLEANUP_PARENT_EXIT_MAIN
void unsetenv(const char *name)
int setenv(char *name, char *value, int overwrite)
void fpm_scoreboard_update(int idle, int active, int lq, int lq_len, int requests, int max_children_reached, int slow_rq, size_t memory_peak, int action, struct fpm_scoreboard_s *scoreboard)
#define FPM_SCOREBOARD_ACTION_SET
int fpm_sockets_init_main(void)
int fpm_socket_get_listening_queue(int sock, unsigned *cur_lq, unsigned *max_lq)
enum fpm_address_domain fpm_sockets_domain_from_address(char *address)
int fpm_socket_unix_test_connect(struct sockaddr_un *sock, size_t socklen)
#define FPM_ENV_SOCKET_SET_SIZE
#define FPM_ENV_SOCKET_SET_MAX
int fpm_unix_set_socket_permissions(struct fpm_worker_pool_s *wp, const char *path)
int fpm_unix_resolve_socket_permissions(struct fpm_worker_pool_s *wp)
struct fpm_worker_pool_s * fpm_worker_all_pools
sprintf("0x%X", $numelems)
inet_ntop(AF_INET, addr, addr_str, sizeof(addr_str))
unsigned char key[REFLECTION_KEY_LEN]
struct fpm_worker_pool_config_s * config
enum fpm_address_domain listen_address_domain
struct fpm_scoreboard_s * scoreboard
struct fpm_worker_pool_s * next
strcmp(string $string1, string $string2)
ZEND_RESULT_CODE zend_result
int zlog_set_level(int new_value)