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;
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);
131 #if FASTCGIPP_LOG_LEVEL > 3 133 ++
m_data->m_group.m_connectionKillCount;
142 ::shutdown(
m_data->m_socket, SHUT_RDWR);
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 180 ::shutdown(listener, SHUT_RDWR);
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);
209 if(::
listen(listen, 100) < 0)
211 ERROR_LOG(
"Unable to listen on default FastCGI socket: "\
212 << std::strerror(errno));
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));
294 ERROR_LOG(
"Unable to listen on unix socket :\"" << name <<
"\": "\
295 << std::strerror(errno));
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)
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;
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;
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;
485 FAIL_LOG(
"Unable to add listen socket " << listener \
486 <<
" to the poll list: " << std::strerror(errno))
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;
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;
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." )
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);
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;
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;
std::map< socket_t, Socket > m_sockets
All the sockets.
socket_t m_wakeSockets[2]
A pair of sockets for wakeup purposes.
bool m_waking
Set to true while there is a pending wake.
void close() const
Call this to close the socket.
~Socket()
Calls close() on the socket if we are destructing the original.
ssize_t read(char *buffer, size_t size) const
Try and read a chunk of data out of the socket.
bool m_original
This is only true for a non-copy constructed object.
bool valid() const
Returns true if this socket is still open and capable of read/write.
bool listen()
Listen to the default Fastcgi socket.
std::shared_ptr< Data > m_data
Shared pointer to hold the socket data.
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.
std::mutex m_wakingMutex
We need this mutex to thread safe the wake() function.
bool pollDel(const socket_t socket)
Remove a socket identifier to the poll list.
friend class Socket
Our sockets need access to our private data.
std::set< socket_t > m_listeners
These are the sockets we listen for connections on.
void wake()
Wake up from a nap inside poll()
Class for representing an OS level I/O socket.
Socket poll(bool block)
Poll socket set for new incoming connections and data.
bool pollAdd(const socket_t socket)
Add a socket identifier to the poll list.
ssize_t write(const char *buffer, size_t size) const
Try and write a chunk of data into the socket.
Class for representing an OS level socket that listens for connections.
Data structure to hold the shared socket data.
poll_t m_poll
Our poll object.
#define FAIL_LOG(data)
Log any "errors" that cannot be recovered from and then exit.
std::atomic_bool m_accept
Set to true if we should be accepting new connections.
#define ERROR_LOG(data)
Log any "errors" that can be recovered from.
Declares the Fastcgipp debugging/logging facilities.
std::deque< std::string > m_filenames
Filenames to cleanup when we're done.
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.
std::atomic_bool m_refreshListeners
Set to true if we should refresh the listeners in the poll.
#define WARNING_LOG(data)
Log any externally caused "errors".