Warning, file /sdk/dferry/transport/localserver.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /*
0002    Copyright (C) 2014 Andreas Hartmetz <ahartmetz@gmail.com>
0003 
0004    This library is free software; you can redistribute it and/or
0005    modify it under the terms of the GNU Library General Public
0006    License as published by the Free Software Foundation; either
0007    version 2 of the License, or (at your option) any later version.
0008 
0009    This library is distributed in the hope that it will be useful,
0010    but WITHOUT ANY WARRANTY; without even the implied warranty of
0011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0012    Library General Public License for more details.
0013 
0014    You should have received a copy of the GNU Library General Public License
0015    along with this library; see the file COPYING.LGPL.  If not, write to
0016    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0017    Boston, MA 02110-1301, USA.
0018 
0019    Alternatively, this file is available under the Mozilla Public License
0020    Version 1.1.  You may obtain a copy of the License at
0021    http://www.mozilla.org/MPL/
0022 */
0023 
0024 #include "localserver.h"
0025 
0026 #include "icompletionlistener.h"
0027 #include "localsocket.h"
0028 
0029 #include <fcntl.h>
0030 #include <sys/socket.h>
0031 #include <sys/un.h>
0032 #include <unistd.h>
0033 
0034 #include <cassert>
0035 #include <cstring>
0036 
0037 LocalServer::LocalServer(const std::string &socketFilePath)
0038    : m_listenFd(-1)
0039 {
0040     const int fd = socket(PF_UNIX, SOCK_STREAM, 0);
0041     if (fd < 0) {
0042         return;
0043     }
0044     // don't let forks inherit the file descriptor - just in case
0045     fcntl(fd, F_SETFD, FD_CLOEXEC);
0046 
0047     struct sockaddr_un addr;
0048     addr.sun_family = PF_UNIX;
0049     bool ok = socketFilePath.length() + 1 <= sizeof(addr.sun_path);
0050     if (ok) {
0051         memcpy(addr.sun_path, socketFilePath.c_str(), socketFilePath.length() + 1);
0052     }
0053 
0054     if (!socketFilePath.empty() && socketFilePath[0] != '\0') {
0055         // not a so-called abstract socket (weird but useful Linux specialty)
0056         unlink(socketFilePath.c_str());
0057     }
0058     ok = ok && (bind(fd, (struct sockaddr *)&addr, sizeof(sa_family_t) + socketFilePath.length()) == 0);
0059     ok = ok && (::listen(fd, /* max queued incoming connections */ 64) == 0);
0060 
0061     if (ok) {
0062         m_listenFd = fd;
0063     } else {
0064         ::close(fd);
0065     }
0066 }
0067 
0068 LocalServer::~LocalServer()
0069 {
0070     close();
0071 }
0072 
0073 IO::Status LocalServer::handleIoReady(IO::RW rw)
0074 {
0075     if (rw != IO::RW::Read) {
0076         assert(false);
0077         return IO::Status::InternalError;
0078     }
0079     if (m_listenFd < 0) {
0080         return IO::Status::LocalClosed;
0081     }
0082     int connFd = -1;
0083     while (true) {
0084         connFd = accept(m_listenFd, nullptr, nullptr);
0085         if (connFd >= 0) {
0086             break;
0087         }
0088         if (errno == EINTR) {
0089             continue;
0090         }
0091         // After listen() succeeded, the only possible errors are invalid parameters (we don't do that,
0092         // right?), EINTR, out of resource errors (which can be temporary), or aborted connection
0093         // attempt. Just give up on this connection attempt and stay in listening state.
0094         return IO::Status::OK;
0095     }
0096     fcntl(connFd, F_SETFD, FD_CLOEXEC);
0097 
0098     m_incomingConnections.push_back(new LocalSocket(connFd));
0099     if (m_newConnectionListener) {
0100         m_newConnectionListener->handleCompletion(this);
0101     }
0102     return IO::Status::OK;
0103 }
0104 
0105 bool LocalServer::isListening() const
0106 {
0107     return m_listenFd >= 0;
0108 }
0109 
0110 void LocalServer::platformClose()
0111 {
0112     if (m_listenFd >= 0) {
0113         ::close(m_listenFd);
0114         m_listenFd = -1;
0115     }
0116 }
0117 
0118 FileDescriptor LocalServer::fileDescriptor() const
0119 {
0120     return m_listenFd;
0121 }