diff --git a/src/ioslaves/file/CMakeLists.txt b/src/ioslaves/file/CMakeLists.txt --- a/src/ioslaves/file/CMakeLists.txt +++ b/src/ioslaves/file/CMakeLists.txt @@ -8,7 +8,7 @@ if(WIN32) set(kio_file_PART_SRCS file.cpp file_win.cpp ) else() - set(kio_file_PART_SRCS file.cpp file_unix.cpp ) + set(kio_file_PART_SRCS file.cpp file_unix.cpp fdreceiver.cpp ) endif() find_package(ACL) @@ -23,6 +23,10 @@ add_library(kio_file MODULE ${kio_file_PART_SRCS}) target_link_libraries(kio_file KF5::KIOCore KF5::I18n) +if(UNIX) + target_link_libraries(kio_file Qt5::Network) +endif() + if (HAVE_VOLMGT AND CMAKE_SYSTEM_NAME MATCHES SunOS) target_link_libraries(kio_file -lvolmgt) endif () diff --git a/src/ioslaves/file/fdreceiver.h b/src/ioslaves/file/fdreceiver.h new file mode 100644 --- /dev/null +++ b/src/ioslaves/file/fdreceiver.h @@ -0,0 +1,47 @@ +/*** + Copyright (C) 2017 by Chinmoy Ranjan Pradhan + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) version 3, or any + later version accepted by the membership of KDE e.V. (or its + successor approved by the membership of KDE e.V.), which shall + act as a proxy defined in Section 6 of version 3 of the license. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. If not, see . +***/ + +#ifndef FDRECEIVER_H +#define FDRECEIVER_H + +#include +#include + +class QSocketNotifier; +class FdReceiver : public QObject +{ + Q_OBJECT + +public: + FdReceiver(const QString &path, QObject *parent = nullptr); + ~FdReceiver(); + + bool isListening() const; + int fileDescriptor() const; + +private: + Q_SLOT void receiveFileDescriptor(); + + QSocketNotifier *m_readNotifier; + int m_socketDes; + int m_fileDes; +}; + +#endif diff --git a/src/ioslaves/file/fdreceiver.cpp b/src/ioslaves/file/fdreceiver.cpp new file mode 100644 --- /dev/null +++ b/src/ioslaves/file/fdreceiver.cpp @@ -0,0 +1,80 @@ +/*** + Copyright (C) 2017 by Chinmoy Ranjan Pradhan + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) version 3, or any + later version accepted by the membership of KDE e.V. (or its + successor approved by the membership of KDE e.V.), which shall + act as a proxy defined in Section 6 of version 3 of the license. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. If not, see . +***/ + +#include +#include + +#include + +#include "sharefd_p.h" +#include "fdreceiver.h" + +FdReceiver::FdReceiver(const QString &path, QObject *parent) + : QObject(parent) + , m_readNotifier(nullptr) + , m_socketDes(-1) + , m_fileDes(-1) +{ + m_socketDes = ::socket(AF_LOCAL, SOCK_STREAM|SOCK_NONBLOCK, 0); + if (m_socketDes == -1) { + std::cerr << "socket error:" << strerror(errno) << std::endl; + return; + } + + const SocketAddress addr(path.toStdString()); + if (bind(m_socketDes, addr.address(), addr.length()) != 0 || listen(m_socketDes, 5) != 0) { + std::cerr << "bind/listen error:" << strerror(errno) << std::endl; + ::close(m_socketDes); + m_socketDes = -1; + return; + } + + m_readNotifier = new QSocketNotifier(m_socketDes, QSocketNotifier::Read, this); + connect(m_readNotifier, &QSocketNotifier::activated, this, &FdReceiver::receiveFileDescriptor); +} + +FdReceiver::~FdReceiver() +{ + if (m_socketDes >= 0) { + ::close(m_socketDes); + } +} + +bool FdReceiver::isListening() const +{ + return m_socketDes >= 0 && m_readNotifier; +} + +void FdReceiver::receiveFileDescriptor() +{ + int client = ::accept(m_socketDes, NULL, NULL); + if (client > 0) { + FDMessageHeader msg; + if (::recvmsg(client, msg.message(), 0) == 2) { + ::memcpy(&m_fileDes, CMSG_DATA(msg.cmsgHeader()), sizeof m_fileDes); + } + ::close(client); + } +} + +int FdReceiver::fileDescriptor() const +{ + return m_fileDes; +} diff --git a/src/ioslaves/file/kauth/fdsender.h b/src/ioslaves/file/kauth/fdsender.h new file mode 100644 --- /dev/null +++ b/src/ioslaves/file/kauth/fdsender.h @@ -0,0 +1,37 @@ +/*** + Copyright (C) 2017 by Chinmoy Ranjan Pradhan + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) version 3, or any + later version accepted by the membership of KDE e.V. (or its + successor approved by the membership of KDE e.V.), which shall + act as a proxy defined in Section 6 of version 3 of the license. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. If not, see . +***/ + +#ifndef FDSENDER_H +#define FDSENDER_H + +class FdSender +{ +public: + FdSender(const std::string &path); + ~FdSender(); + + bool sendFileDescriptor(int fd); + bool isConnected() const; + +private: + int m_socketDes; +}; + +#endif diff --git a/src/ioslaves/file/kauth/fdsender.cpp b/src/ioslaves/file/kauth/fdsender.cpp new file mode 100644 --- /dev/null +++ b/src/ioslaves/file/kauth/fdsender.cpp @@ -0,0 +1,68 @@ +/*** + Copyright (C) 2017 by Chinmoy Ranjan Pradhan + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) version 3, or any + later version accepted by the membership of KDE e.V. (or its + successor approved by the membership of KDE e.V.), which shall + act as a proxy defined in Section 6 of version 3 of the license. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. If not, see . +***/ + +#include +#include + +#include "../sharefd_p.h" +#include "fdsender.h" + +FdSender::FdSender(const std::string &path) + : m_socketDes(-1) +{ + m_socketDes = ::socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0); + if (m_socketDes == -1) { + std::cerr << "socket error:" << strerror(errno) << std::endl; + return; + } + + SocketAddress addr(path); + if (::connect(m_socketDes, addr.address(), addr.length()) != 0) { + std::cerr << "connection error:" << strerror(errno) << std::endl; + ::close(m_socketDes); + m_socketDes = -1; + return; + } +} + +FdSender::~FdSender() +{ + if (m_socketDes >= 0) { + ::close(m_socketDes); + } +} + +bool FdSender::sendFileDescriptor(int fd) +{ + FDMessageHeader msg; + cmsghdr *cmsg = msg.cmsgHeader(); + cmsg->cmsg_len = CMSG_LEN(sizeof(int)); + cmsg->cmsg_type = SCM_RIGHTS; + cmsg->cmsg_level = SOL_SOCKET; + memcpy(CMSG_DATA(cmsg), &fd, sizeof fd); + bool success = sendmsg(m_socketDes, msg.message(), 0) == 2; + ::close(m_socketDes); + return success; +} + +bool FdSender::isConnected() const +{ + return m_socketDes >= 0; +} diff --git a/src/ioslaves/file/sharefd_p.h b/src/ioslaves/file/sharefd_p.h new file mode 100644 --- /dev/null +++ b/src/ioslaves/file/sharefd_p.h @@ -0,0 +1,83 @@ +/*** + Copyright (C) 2017 by Chinmoy Ranjan Pradhan + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) version 3, or any + later version accepted by the membership of KDE e.V. (or its + successor approved by the membership of KDE e.V.), which shall + act as a proxy defined in Section 6 of version 3 of the license. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. If not, see . +***/ + +#include +#include + +class SocketAddress +{ + const sockaddr_un addr; + +public: + SocketAddress(const std::string &path) + : addr(make_address(path)) + { + } + + int length() const + { + return sizeof addr; + } + const sockaddr *address() const + { + return reinterpret_cast(&addr); + } + +private: + static sockaddr_un make_address(const std::string& path) + { + sockaddr_un a{ AF_UNIX, {0}}; + std::string finalPath = "/tmp/" + path; +#ifdef __linux__ + ::strcpy(&a.sun_path[1], finalPath.c_str()); +#else + ::strcpy(a.sun_path, finalPath.c_str()); + ::unlink(finalPath.c_str()); +#endif + return a; + } +}; + +class FDMessageHeader +{ + char io_buf[2]; + char cmsg_buf[CMSG_SPACE(sizeof(int))]; + iovec io; + msghdr msg; + +public: + FDMessageHeader() + : io_buf{0} + , cmsg_buf{0} + , io{io_buf, sizeof io_buf} + , msg{nullptr, 0, &io, 1, &cmsg_buf, sizeof cmsg_buf, 0} + { + } + + msghdr *message() + { + return &msg; + } + + cmsghdr *cmsgHeader() + { + return CMSG_FIRSTHDR(&msg); + } +};