35 #ifdef FASTCGIPP_LINUX 36 #include <sys/epoll.h> 37 #elif defined FASTCGIPP_UNIX 41 #include <sys/socket.h> 43 #include <sys/types.h> 45 #include <sys/socket.h> 57 m_data(new
Data(socket, valid, group)),
62 ERROR_LOG(
"Unable to add socket " << socket <<
" to poll list: " \
63 << std::strerror(errno))
73 const ssize_t count = ::read(m_data->m_socket, buffer, size);
77 << m_data->m_socket <<
": " << std::strerror(errno))
83 if(count == 0 && m_data->m_closing)
85 #if FASTCGIPP_LOG_LEVEL > 3 86 ++m_data->m_group.m_connectionRDHupCount;
92 #if FASTCGIPP_LOG_LEVEL > 3 93 m_data->m_group.m_bytesReceived += count;
101 if(!valid() || m_data->m_closing)
104 const ssize_t count = ::send(m_data->m_socket, buffer, size, MSG_NOSIGNAL);
108 << m_data->m_socket <<
": " << strerror(errno))
115 #if FASTCGIPP_LOG_LEVEL > 3 116 m_data->m_group.m_bytesSent += count;
126 ::shutdown(m_data->m_socket, SHUT_RDWR);
127 ::close(m_data->m_socket);
128 m_data->m_valid =
false;
129 m_data->m_group.pollDel(m_data->m_socket);
130 m_data->m_group.m_sockets.erase(m_data->m_socket);
131 #if FASTCGIPP_LOG_LEVEL > 3 132 if(!m_data->m_closing)
133 ++m_data->m_group.m_connectionKillCount;
140 if(m_original && valid())
142 ::shutdown(m_data->m_socket, SHUT_RDWR);
143 ::close(m_data->m_socket);
144 m_data->m_valid =
false;
145 m_data->m_group.pollDel(m_data->m_socket);
151 m_poll(epoll_create1(0)),
155 m_refreshListeners(false)
157 ,m_incomingConnectionCount(0),
158 m_outgoingConnectionCount(0),
159 m_connectionKillCount(0),
160 m_connectionRDHupCount(0),
168 DIAG_LOG(
"SocketGroup::SocketGroup(): Initialized ")
173 #ifdef FASTCGIPP_LINUX 176 close(m_wakeSockets[0]);
177 close(m_wakeSockets[1]);
178 for(
const auto& listener: m_listeners)
180 ::shutdown(listener, SHUT_RDWR);
183 for(
const auto& filename: m_filenames)
184 std::remove(filename.c_str());
186 DIAG_LOG(
"SocketGroup::~SocketGroup(): Incoming sockets ======== " \
187 << m_incomingConnectionCount)
188 DIAG_LOG(
"SocketGroup::~SocketGroup(): Outgoing sockets ======== " \
189 << m_outgoingConnectionCount)
190 DIAG_LOG(
"SocketGroup::~SocketGroup(): Locally closed sockets == " \
191 << m_connectionKillCount)
192 DIAG_LOG(
"SocketGroup::~SocketGroup(): Remotely closed sockets = " \
193 << m_connectionRDHupCount)
194 DIAG_LOG(
"SocketGroup::~SocketGroup(): Remaining sockets ======= " \
196 DIAG_LOG(
"SocketGroup::~SocketGroup(): Bytes sent ===== " << m_bytesSent)
197 DIAG_LOG(
"SocketGroup::~SocketGroup(): Bytes received = " \
205 fcntl(listen, F_SETFL, fcntl(listen, F_GETFL)|O_NONBLOCK);
207 if(m_listeners.find(listen) == m_listeners.end())
209 if(::listen(listen, 100) < 0)
211 ERROR_LOG(
"Unable to listen on default FastCGI socket: "\
212 << std::strerror(errno));
215 m_listeners.insert(listen);
216 m_refreshListeners =
true;
221 ERROR_LOG(
"Socket " << listen <<
" already being listened to")
228 uint32_t permissions,
232 if(std::remove(name) != 0 && errno != ENOENT)
234 ERROR_LOG(
"Unable to delete file \"" << name <<
"\": " \
235 << std::strerror(errno))
239 const auto fd = socket(AF_UNIX, SOCK_STREAM, 0);
242 ERROR_LOG(
"Unable to create unix socket: " << std::strerror(errno))
247 struct sockaddr_un address;
248 std::memset(&address, 0,
sizeof(address));
249 address.sun_family = AF_UNIX;
250 std::strncpy(address.sun_path, name,
sizeof(address.sun_path) - 1);
254 reinterpret_cast<struct sockaddr*>(&address),
255 sizeof(address)) < 0)
257 ERROR_LOG(
"Unable to bind to unix socket \"" << name <<
"\": " \
258 << std::strerror(errno));
265 if(owner!=
nullptr && group!=
nullptr)
267 struct passwd* passwd = getpwnam(owner);
268 struct group* grp = getgrnam(group);
269 if(fchown(fd, passwd->pw_uid, grp->gr_gid)==-1)
271 ERROR_LOG(
"Unable to chown " << owner <<
":" << group \
272 <<
" on the unix socket \"" << name <<
"\": " \
273 << std::strerror(errno));
280 if(permissions != 0xffffffffUL)
282 if(fchmod(fd, permissions)<0)
284 ERROR_LOG(
"Unable to set permissions 0" << std::oct << permissions \
285 << std::dec <<
" on \"" << name <<
"\": " \
286 << std::strerror(errno));
292 if(::listen(fd, 100) < 0)
294 ERROR_LOG(
"Unable to listen on unix socket :\"" << name <<
"\": "\
295 << std::strerror(errno));
300 m_filenames.emplace_back(name);
301 m_listeners.insert(fd);
302 m_refreshListeners =
true;
307 const char* interface,
310 if(service ==
nullptr)
312 ERROR_LOG(
"Cannot call listen(interface, service) with service=nullptr.")
317 std::memset(&hints, 0,
sizeof(addrinfo));
318 hints.ai_family = AF_UNSPEC;
319 hints.ai_socktype = SOCK_STREAM;
320 hints.ai_flags = AI_PASSIVE;
321 hints.ai_protocol = IPPROTO_TCP;
322 hints.ai_canonname =
nullptr;
323 hints.ai_addr =
nullptr;
324 hints.ai_next =
nullptr;
328 if(getaddrinfo(interface, service, &hints, &result))
330 ERROR_LOG(
"Unable to use getaddrinfo() on " \
331 << (interface==
nullptr?
"0.0.0.0":interface) <<
":" << service <<
". " \
332 << std::strerror(errno))
337 for(
auto i=result; i!=
nullptr; i=result->ai_next)
339 fd = socket(i->ai_family, i->ai_socktype, i->ai_protocol);
343 bind(fd, i->ai_addr, i->ai_addrlen) == 0
344 && ::listen(fd, 100) == 0)
349 freeaddrinfo(result);
354 << (interface==
nullptr?
"0.0.0.0":interface) <<
":" << service)
358 m_listeners.insert(fd);
359 m_refreshListeners =
true;
365 const auto fd = socket(AF_UNIX, SOCK_STREAM, 0);
368 ERROR_LOG(
"Unable to create unix socket: " << std::strerror(errno))
373 std::memset(&address, 0,
sizeof(address));
374 address.sun_family = AF_UNIX;
375 std::strncpy(address.sun_path, name,
sizeof(address.sun_path) - 1);
379 reinterpret_cast<struct sockaddr*>(&address),
380 sizeof(address))==-1)
382 ERROR_LOG(
"Unable to connect to unix socket \"" << name <<
"\": " \
383 << std::strerror(errno));
388 #if FASTCGIPP_LOG_LEVEL > 3 389 ++m_outgoingConnectionCount;
392 return m_sockets.emplace(
394 Socket(fd, *
this)).first->second;
401 if(service ==
nullptr)
403 ERROR_LOG(
"Cannot call connect(host, service) with service=nullptr.")
409 ERROR_LOG(
"Cannot call host(host, service) with host=nullptr.")
414 std::memset(&hints, 0,
sizeof(addrinfo));
415 hints.ai_family = AF_UNSPEC;
416 hints.ai_socktype = SOCK_STREAM;
418 hints.ai_protocol = IPPROTO_TCP;
419 hints.ai_canonname =
nullptr;
420 hints.ai_addr =
nullptr;
421 hints.ai_next =
nullptr;
425 if(getaddrinfo(host, service, &hints, &result))
427 ERROR_LOG(
"Unable to use getaddrinfo() on " << host <<
":" << service \
428 <<
". " << std::strerror(errno))
433 for(
auto i=result; i!=
nullptr; i=result->ai_next)
435 fd = socket(i->ai_family, i->ai_socktype, i->ai_protocol);
438 if(::connect(fd, i->ai_addr, i->ai_addrlen) != -1)
443 freeaddrinfo(result);
447 ERROR_LOG(
"Unable to connect to " << host <<
":" << service)
451 #if FASTCGIPP_LOG_LEVEL > 3 452 ++m_outgoingConnectionCount;
455 return m_sockets.emplace(
457 Socket(fd, *
this)).first->second;
464 #ifdef FASTCGIPP_LINUX 465 epoll_event epollEvent;
466 const auto& pollIn = EPOLLIN;
467 const auto& pollErr = EPOLLERR;
468 const auto& pollHup = EPOLLHUP;
469 const auto& pollRdHup = EPOLLRDHUP;
470 #elif defined FASTCGIPP_UNIX 471 const auto& pollIn = POLLIN;
472 const auto& pollErr = POLLERR;
473 const auto& pollHup = POLLHUP;
474 const auto& pollRdHup = POLLRDHUP;
477 while(m_listeners.size()+m_sockets.size() > 0)
479 if(m_refreshListeners)
481 for(
auto& listener: m_listeners)
484 if(m_accept && !pollAdd(listener))
485 FAIL_LOG(
"Unable to add listen socket " << listener \
486 <<
" to the poll list: " << std::strerror(errno))
488 m_refreshListeners=
false;
490 #ifdef FASTCGIPP_LINUX 491 pollResult = epoll_wait(
496 #elif defined FASTCGIPP_UNIX 507 FAIL_LOG(
"Error on poll: " << std::strerror(errno))
509 else if(pollResult>0)
511 #ifdef FASTCGIPP_LINUX 512 const auto& socketId = epollEvent.data.fd;
513 const auto& events = epollEvent.events;
514 #elif defined FASTCGIPP_UNIX 515 const auto fd = std::find_if(
520 return x.revents != 0;
522 if(fd == m_poll.end())
523 FAIL_LOG(
"poll() gave a result >0 but no revents are non-zero")
524 const auto& socketId = fd->fd;
525 const auto& events = fd->revents;
528 if(m_listeners.find(socketId) != m_listeners.end())
532 createSocket(socketId);
535 else if(events & pollErr)
537 else if(events & (pollHup | pollRdHup))
538 FAIL_LOG(
"The listen socket hung up.")
540 FAIL_LOG(
"Got a weird event 0x" << std::hex << events\
541 <<
" on listen poll." )
543 else if(socketId == m_wakeSockets[1])
547 std::lock_guard<std::mutex> lock(m_wakingMutex);
549 if(read(m_wakeSockets[1], x, 256)<1)
550 FAIL_LOG(
"Unable to read out of wakeup socket: " << \
551 std::strerror(errno))
556 else if(events & (pollHup | pollRdHup))
557 FAIL_LOG(
"The wakeup socket hung up.")
558 else if(events & pollErr)
559 FAIL_LOG(
"Error in the wakeup socket.")
563 const auto socket = m_sockets.find(socketId);
564 if(socket == m_sockets.end())
567 <<
" which isn't in m_sockets.")
573 if(events & pollRdHup)
574 socket->second.m_data->m_closing=
true;
575 else if(events & pollHup)
578 socket->second.m_data->m_closing=
true;
580 else if(events & pollErr)
582 ERROR_LOG(
"Error in socket " << socketId)
583 socket->second.m_data->m_closing=
true;
585 else if((events & pollIn) == 0)
586 FAIL_LOG(
"Got a weird event 0x" << std::hex << events\
587 <<
" on socket poll." )
588 return socket->second;
598 std::lock_guard<std::mutex> lock(m_wakingMutex);
603 if(write(m_wakeSockets[0], &x, 1) != 1)
604 FAIL_LOG(
"Unable to write to wakeup socket: " \
605 << std::strerror(errno))
612 socklen_t addrlen=
sizeof(sockaddr_un);
615 reinterpret_cast<sockaddr*>(&addr),
618 FAIL_LOG(
"Unable to accept() with fd " \
619 << listener <<
": " \
620 << std::strerror(errno))
624 fcntl(socket, F_GETFL)|O_NONBLOCK)
627 ERROR_LOG(
"Unable to set NONBLOCK on fd " << socket \
628 <<
" with fcntl(): " << std::strerror(errno))
638 #if FASTCGIPP_LOG_LEVEL > 3 639 ++m_incomingConnectionCount;
653 #ifdef FASTCGIPP_LINUX 655 event.data.fd = socket;
656 event.events = EPOLLIN | EPOLLERR | EPOLLHUP | EPOLLRDHUP;
657 return epoll_ctl(m_poll, EPOLL_CTL_ADD, socket, &event) != -1;
658 #elif defined FASTCGIPP_UNIX 659 const auto fd = std::find_if(
662 [&socket] (
const pollfd& x)
664 return x.fd == socket;
666 if(fd != m_poll.end())
669 m_poll.emplace_back();
670 m_poll.back().fd = socket;
671 m_poll.back().events = POLLIN | POLLRDHUP | POLLERR | POLLHUP;
678 #ifdef FASTCGIPP_LINUX 679 return epoll_ctl(m_poll, EPOLL_CTL_DEL, socket,
nullptr) != -1;
680 #elif defined FASTCGIPP_UNIX 681 const auto fd = std::find_if(
684 [&socket] (
const pollfd& x)
686 return x.fd == socket;
688 if(fd == m_poll.end())
698 if(status != m_accept)
700 m_refreshListeners =
true;
socket_t m_wakeSockets[2]
A pair of sockets for wakeup purposes.
void close() const
Call this to close the socket.
~Socket()
Calls close() on the socket if we are destructing the original.
bool listen()
Listen to the default Fastcgi socket.
void accept(bool status)
Should we accept new connections?
#define FASTCGIPP_LOG_LEVEL
void createSocket(const socket_t listener)
Accept a new connection and create it's socket.
int socket_t
Our socket identifier type in GNU/Linux is simply an int.
bool pollDel(const socket_t socket)
Remove a socket identifier to the poll list.
void wake()
Wake up from a nap inside poll()
ssize_t read(char *buffer, size_t size) const
Try and read a chunk of data out of the socket.
Class for representing an OS level I/O socket.
Socket poll(bool block)
Poll socket set for new incoming connections and data.
ssize_t write(const char *buffer, size_t size) const
Try and write a chunk of data into the socket.
bool pollAdd(const socket_t socket)
Add a socket identifier to the poll list.
Class for representing an OS level socket that listens for connections.
Data structure to hold the shared socket data.
#define FAIL_LOG(data)
Log any "errors" that cannot be recovered from and then exit.
#define ERROR_LOG(data)
Log any "errors" that can be recovered from.
Declares the Fastcgipp debugging/logging facilities.
Declares everything for interfaces with OS level sockets.
Socket connect(const char *name)
Connect to a named socket.
Socket()
Creates an invalid socket with no original.
#define WARNING_LOG(data)
Log any externally caused "errors".