[Libreoffice-commits] online.git: 3 commits - Mobile/TestFakeSocket net/FakeSocket.cpp net/FakeSocket.hpp

Libreoffice Gerrit user logerrit at kemper.freedesktop.org
Sat Sep 15 09:37:04 UTC 2018


 Mobile/TestFakeSocket/TestFakeSocket.xcodeproj/project.pbxproj |  285 +++++
 Mobile/TestFakeSocket/TestFakeSocket/main.cpp                  |  128 ++
 net/FakeSocket.cpp                                             |  506 ++++++++++
 net/FakeSocket.hpp                                             |   49 
 4 files changed, 968 insertions(+)

New commits:
commit 0a2868b8d4d3702041ad6f8018f3d4e10a876b44
Author:     Tor Lillqvist <tml at iki.fi>
AuthorDate: Sat Sep 15 12:04:05 2018 +0300
Commit:     Tor Lillqvist <tml at collabora.com>
CommitDate: Sat Sep 15 12:35:23 2018 +0300

    More FakeSocket hacking
    
    As we use #ifdefs at all call sites anyway (because we don't dare use
    the generic overrides of close() etc), we can leave out the parameters
    related to actual BSD sockets that we ignore anyway.
    
    "Real" Online always uses non-blocking sockets. We don't need to take
    flags for that or check it. We can hardcode such behaviour always.
    (Assuing that is what we want; let's see once something works.)
    
    Change-Id: I6863907d71c5599b00ce1f8305a44d41bbaf7bee

diff --git a/Mobile/TestFakeSocket/TestFakeSocket/main.cpp b/Mobile/TestFakeSocket/TestFakeSocket/main.cpp
index ea7a8ccd1..22e46d85c 100644
--- a/Mobile/TestFakeSocket/TestFakeSocket/main.cpp
+++ b/Mobile/TestFakeSocket/TestFakeSocket/main.cpp
@@ -16,18 +16,18 @@
 
 int main(int argc, char **argv)
 {
-    int s0 = fakeSocketSocket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0);
-    int s1 = fakeSocketSocket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0);
-    int s2 = fakeSocketSocket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0);
+    int s0 = fakeSocketSocket();
+    int s1 = fakeSocketSocket();
+    int s2 = fakeSocketSocket();
 
     std::cout << "sockets: " << s0 << ", " << s1 << ", " << s2 << "\n";
 
     fakeSocketClose(s1);
 
-    s1 = fakeSocketSocket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0);
+    s1 = fakeSocketSocket();
     std::cout << "closed and created s1 again: " << s1 << "\n";
 
-    int rc = fakeSocketListen(s0, 10);
+    int rc = fakeSocketListen(s0);
     if (rc == -1)
     {
         perror("listen");
@@ -36,7 +36,7 @@ int main(int argc, char **argv)
 
     int s3;
     std::thread t0([&] {
-            s3 = fakeSocketAccept4(s0, nullptr, nullptr, 0);
+            s3 = fakeSocketAccept4(s0, 0);
             if (s3 == -1)
                 perror("accept");
         });
@@ -95,7 +95,7 @@ int main(int argc, char **argv)
     std::cout << "read " << buf << "\n";
 
     int pipe[2];
-    rc = fakeSocketPipe2(pipe, 0);
+    rc = fakeSocketPipe2(pipe);
     if (rc == -1)
     {
         perror("pipe2");
diff --git a/net/FakeSocket.cpp b/net/FakeSocket.cpp
index 7477c9755..e9681b392 100644
--- a/net/FakeSocket.cpp
+++ b/net/FakeSocket.cpp
@@ -10,15 +10,13 @@
 #include <errno.h>
 #include <fcntl.h>
 
+#include <chrono>
 #include <condition_variable>
+#include <iostream>
 #include <mutex>
+#include <thread>
 #include <vector>
 
-#ifdef TEST
-#include <iostream>
-#define MOBILEAPP
-#endif
-
 #include "FakeSocket.hpp"
 
 struct FakeSocketPair
@@ -26,59 +24,66 @@ struct FakeSocketPair
     int fd[2];
     bool listening;
     int connectingFd;
-    bool nonblocking[2];
     std::vector<char> buffer[2];
     std::mutex *mutex;
-    std::condition_variable *cv;
+    // std::condition_variable *cv;
 
     FakeSocketPair()
     {
         fd[0] = -1;
         fd[1] = -1;
         listening = false;
+        connectingFd = -1;
         mutex = new std::mutex();
-        cv = new std::condition_variable();
+        // cv = new std::condition_variable();
     }
 };
 
 static std::mutex fdsMutex;
+static std::condition_variable cv;
 
-static std::vector<FakeSocketPair> fds;
-
-int fakeSocketSocket(int domain, int type, int protocol)
+// Avoid problems with order of initialisation of static globals.
+static std::vector<FakeSocketPair>& getFds()
 {
-    if (domain == AF_INET && (type & ~SOCK_NONBLOCK) == SOCK_STREAM && protocol == 0)
-    {
-        std::lock_guard<std::mutex> fdsLock(fdsMutex);
-        size_t i;
-        for (i = 0; i < fds.size(); i++)
-        {
-            if (fds[i].fd[0] == -1 && fds[i].fd[1] == -1)
-                break;
-        }
-        if (i == fds.size())
-            fds.resize(fds.size() + 1);
+    static std::vector<FakeSocketPair> fds;
 
-        FakeSocketPair& result = fds[i];
+    return fds;
+}
 
-        result.fd[0] = i*2;
-        result.fd[1] = -1;
-        result.listening = false;
-        result.nonblocking[0] = !!(type & SOCK_NONBLOCK);
-        result.buffer[0].resize(0);
-        result.buffer[1].resize(0);
+int fakeSocketSocket()
+{
+    std::vector<FakeSocketPair>& fds = getFds();
+    std::cerr << "----- &fds=" << &fds << " size=" << fds.size() << std::endl;
 
-        return i*2;
+    std::lock_guard<std::mutex> fdsLock(fdsMutex);
+    size_t i;
+    for (i = 0; i < fds.size(); i++)
+    {
+        if (fds[i].fd[0] == -1 && fds[i].fd[1] == -1)
+            break;
     }
+    if (i == fds.size())
+        fds.resize(fds.size() + 1);
+    FakeSocketPair& result = fds[i];
+
+    result.fd[0] = i*2;
+    result.fd[1] = -1;
+    result.listening = false;
+    result.connectingFd = -1;
+    result.buffer[0].resize(0);
+    result.buffer[1].resize(0);
+
+    std::cerr << "+++++ Created a FakeSocket " << i*2 << "\n";
 
-    errno = EACCES;
-    return -1;
+    return i*2;
 }
 
-int fakeSocketPipe2(int pipefd[2], int flags)
+int fakeSocketPipe2(int pipefd[2])
 {
-    pipefd[0] = fakeSocketSocket(AF_INET, SOCK_STREAM, ((flags & O_NONBLOCK) ? SOCK_NONBLOCK : 0));
+    pipefd[0] = fakeSocketSocket();
+    assert(pipefd[0] >= 0);
 
+    std::vector<FakeSocketPair>& fds = getFds();
     FakeSocketPair& pair = fds[pipefd[0]/2];
 
     std::unique_lock<std::mutex> fdLock(pair.mutex[0]);
@@ -86,22 +91,69 @@ int fakeSocketPipe2(int pipefd[2], int flags)
     assert(pair.fd[0] == pipefd[0]);
 
     pair.fd[1] = pair.fd[0] + 1;
-    pair.nonblocking[1] = pair.nonblocking[0];
     pipefd[1] = pair.fd[1];
 
+    std::cerr << "+++++ Created a FakeSocket pipe (" << pipefd[0] << "," << pipefd[1] << ")\n";
+
     return 0;
 }
 
-int fakeSocketPoll(struct pollfd *fds, int nfds, int timeout)
+static bool someFdReadable(struct pollfd *pollfds, int nfds)
+{
+    std::vector<FakeSocketPair>& fds = getFds();
+    bool retval = false;
+    for (int i = 0; i < nfds; i++)
+    {
+        pollfds[i].revents = 0;
+        const int K = ((pollfds[i].fd)&1);
+        if (pollfds[i].events & POLLIN)
+            if (fds[pollfds[i].fd/2].fd[K] != -1 && fds[pollfds[i].fd/2].buffer[K].size() > 0)
+            {
+                pollfds[i].revents = POLLIN;
+                retval = true;
+            }
+    }
+    return retval;
+}
+
+int fakeSocketPoll(struct pollfd *pollfds, int nfds, int timeout)
 {
-    return -1;
+    std::cerr << "+++++ Polling " << nfds << " fds: ";
+    for (int i = 0; i < nfds; i++)
+    {
+        if (i > 0)
+            std::cerr << ",";
+        std::cerr << pollfds[i].fd;
+    }
+    std::cerr << "\n";
+
+    std::vector<FakeSocketPair>& fds = getFds();
+    std::unique_lock<std::mutex> fdsLock(fdsMutex);
+    for (int i = 0; i < nfds; i++)
+    {
+        if (pollfds[i].fd < 1 || pollfds[i].fd/2 >= fds.size())
+        {
+            errno = EBADF;
+            return -1;
+        }
+    }
+    // Here we lock just the first FakeSocketPair struct, hmm
+    std::unique_lock<std::mutex> fdLock(fds[pollfds[0].fd/2].mutex[0]);
+    fdsLock.unlock();
+
+    while (!someFdReadable(pollfds, nfds))
+        cv.wait(fdLock);
+
+    return 0;
 }
 
-int fakeSocketListen(int fd, int backlog)
+int fakeSocketListen(int fd)
 {
+    std::vector<FakeSocketPair>& fds = getFds();
     std::unique_lock<std::mutex> fdsLock(fdsMutex);
     if (fd < 0 || fd/2 >= fds.size())
     {
+        std::cerr << "+++++ EBADF: Listening on fd " << fd << "\n";
         errno = EBADF;
         return -1;
     }
@@ -112,12 +164,14 @@ int fakeSocketListen(int fd, int backlog)
 
     if (fd&1 || pair.fd[1] != -1)
     {
+        std::cerr << "+++++ EISCONN: Listening on fd " << fd << "\n";
         errno = EISCONN;
         return -1;
     }
     
     if (pair.listening)
     {
+        std::cerr << "+++++ EIO: Listening on fd " << fd << "\n";
         errno = EIO;
         return -1;
     }
@@ -125,19 +179,24 @@ int fakeSocketListen(int fd, int backlog)
     pair.listening = true;
     pair.connectingFd = -1;
 
+    std::cerr << "+++++ Listening on fd " << fd << "\n";
+
     return 0;
 }
 
 int fakeSocketConnect(int fd1, int fd2)
 {
+    std::vector<FakeSocketPair>& fds = getFds();
     std::unique_lock<std::mutex> fdsLock(fdsMutex);
     if (fd1 < 0 || fd2 < 0 || fd1/2 >= fds.size() || fd2/2 >= fds.size())
     {
+        std::cerr << "+++++ EBADF: Connect fd " << fd1 << " to " << fd2 << "\n";
         errno = EBADF;
         return -1;
     }
     if (fd1/2 == fd2/2)
     {
+        std::cerr << "+++++ EBADF: Connect fd " << fd1 << " to " << fd2 << "\n";
         errno = EBADF;
         return -1;
     }
@@ -151,39 +210,48 @@ int fakeSocketConnect(int fd1, int fd2)
 
     if ((fd1&1) || (fd2&1))
     {
+        std::cerr << "+++++ EISCONN: Connect fd " << fd1 << " to " << fd2 << "\n";
         errno = EISCONN;
         return -1;
     }
 
     if (!pair2.listening || pair2.connectingFd != -1)
     {
+        std::cerr << "+++++ ECONNREFUSED: Connect fd " << fd1 << " to " << fd2 << "\n";
         errno = ECONNREFUSED;
         return -1;
     }
 
     pair2.connectingFd = fd1;
-    pair2.cv->notify_all();
+    // pair2.cv->notify_all();
+    cv.notify_all();
 
     fdLock2.unlock();
     while (pair1.fd[1] == -1)
-        pair1.cv->wait(fdLock1);
+        // pair1.cv->wait(fdLock1);
+        cv.wait(fdLock1);
 
     assert(pair1.fd[1] == pair1.fd[0] + 1);
 
+    std::cerr << "+++++ Connect fd " << fd1 << " to " << fd2 << "\n";
+
     return 0;
 }
 
-int fakeSocketAccept4(int fd, struct sockaddr *addr, socklen_t *addrlen, int flags)
+int fakeSocketAccept4(int fd, int flags)
 {
+    std::vector<FakeSocketPair>& fds = getFds();
     std::unique_lock<std::mutex> fdsLock(fdsMutex);
     if (fd < 0 || fd/2 >= fds.size())
     {
+        std::cerr << "+++++ EBADF: Accept fd " << fd << "\n";
         errno = EBADF;
         return -1;
     }
 
     if (fd & 1)
     {
+        std::cerr << "+++++ EISCONN: Accept fd " << fd << "\n";
         errno = EISCONN;
         return -1;
     }
@@ -192,6 +260,7 @@ int fakeSocketAccept4(int fd, struct sockaddr *addr, socklen_t *addrlen, int fla
 
     if (!pair.listening)
     {
+        std::cerr << "+++++ EIO: Accept fd " << fd << "\n";
         errno = EIO;
         return -1;
     }
@@ -200,7 +269,8 @@ int fakeSocketAccept4(int fd, struct sockaddr *addr, socklen_t *addrlen, int fla
     fdsLock.unlock();
 
     while (pair.connectingFd == -1)
-        pair.cv->wait(fdLock);
+        // pair.cv->wait(fdLock);
+        cv.wait(fdLock);
     
     assert(pair.connectingFd >= 0 && pair.connectingFd/2 < fds.size());
 
@@ -216,13 +286,38 @@ int fakeSocketAccept4(int fd, struct sockaddr *addr, socklen_t *addrlen, int fla
 
     pair1.fd[1] = pair1.fd[0] + 1;
 
-    pair1.cv->notify_one();
+    // pair1.cv->notify_one();
+    cv.notify_one();
+
+    std::cerr << "+++++ Accept fd " << fd << ": " << pair1.fd[1] << "\n";
 
     return pair1.fd[1];
 }
 
+int fakeSocketPeer(int fd)
+{
+    std::vector<FakeSocketPair>& fds = getFds();
+    std::unique_lock<std::mutex> fdsLock(fdsMutex);
+    if (fd < 0 || fd/2 >= fds.size())
+    {
+        errno = EBADF;
+        return -1;
+    }
+
+    FakeSocketPair& pair = fds[fd/2];
+
+    std::unique_lock<std::mutex> fdLock(pair.mutex[0]);
+    fdsLock.unlock();
+
+    const int K = (fd&1);
+    const int N = 1 - K;
+
+    return pair.fd[N];
+}
+
 ssize_t fakeSocketAvailableDataLength(int fd)
 {
+    std::vector<FakeSocketPair>& fds = getFds();
     std::unique_lock<std::mutex> fdsLock(fdsMutex);
     if (fd < 0 || fd/2 >= fds.size())
     {
@@ -243,9 +338,11 @@ ssize_t fakeSocketAvailableDataLength(int fd)
 
 ssize_t fakeSocketRead(int fd, void *buf, size_t nbytes)
 {
+    std::vector<FakeSocketPair>& fds = getFds();
     std::unique_lock<std::mutex> fdsLock(fdsMutex);
     if (fd < 0 || fd/2 >= fds.size())
     {
+        std::cerr << "+++++ EBADF: Read from fd " << fd << ", " << nbytes << (nbytes == 1 ? " byte" : " bytes") << "\n";
         errno = EBADF;
         return -1;
     }
@@ -258,53 +355,91 @@ ssize_t fakeSocketRead(int fd, void *buf, size_t nbytes)
     // K: for this fd
     const int K = (fd&1);
 
-    if (pair.nonblocking[K])
+    if (pair.fd[K] == -1)
     {
-        if (pair.fd[K] == -1)
-        {
-            errno = EBADF;
-            return -1;
-        }
-
-        if (pair.buffer[K].size() == 0)
-        {
-            errno = EAGAIN;
-            return -1;
-        }
+        std::cerr << "+++++ EBADF: Read from fd " << fd << ", " << nbytes << (nbytes == 1 ? " byte" : " bytes") << "\n";
+        errno = EBADF;
+        return -1;
     }
-    else
-    {
-        while (pair.fd[K] != -1 && pair.buffer[K].size() == 0)
-            pair.cv->wait(fdLock);
 
-        if (pair.fd[K] == -1)
-        {
-            errno = EBADF;
-            return -1;
-        }
+    if (pair.buffer[K].size() == 0)
+    {
+        std::cerr << "+++++ EAGAIN: Read from fd " << fd << ", " << nbytes << (nbytes == 1 ? " byte" : " bytes") << "\n";
+        errno = EAGAIN;
+        return -1;
     }
 
     // These sockets are record-oriented!
     ssize_t result = pair.buffer[K].size();
     if (nbytes < result)
     {
-        errno = EAGAIN; // Not the right errno, but what would be?
+        std::cerr << "+++++ EAGAIN: Read from fd " << fd << ", " << nbytes << (nbytes == 1 ? " byte" : " bytes") << "\n";
+        errno = EAGAIN; // Not the right errno, but what would be?q
         return -1;
     }
 
     memmove(buf, pair.buffer[K].data(), result);
     pair.buffer[K].resize(0);
 
-    pair.cv->notify_one();
+    // pair.cv->notify_one();
+    cv.notify_one();
+
+    std::cerr << "+++++ Read from fd " << fd << ": " << result << (result == 1 ? " byte" : " bytes") << "\n";
 
     return result;
 }
 
+ssize_t fakeSocketFeed(int fd, const void *buf, size_t nbytes)
+{
+    std::vector<FakeSocketPair>& fds = getFds();
+    std::unique_lock<std::mutex> fdsLock(fdsMutex);
+    if (fd < 0 || fd/2 >= fds.size())
+    {
+        std::cerr << "+++++ EBADF: Feed to fd " << fd << ", " << nbytes << (nbytes == 1 ? " byte" : " bytes") << "\n";
+        errno = EBADF;
+        return -1;
+    }
+
+    FakeSocketPair& pair = fds[fd/2];
+
+    std::unique_lock<std::mutex> fdLock(pair.mutex[0]);
+    fdsLock.unlock();
+
+    // K: for this fd, whose read buffer we want to write into
+    const int K = (fd&1);
+
+    if (pair.fd[K] == -1)
+    {
+        std::cerr << "+++++ EBADF: Feed to fd " << fd << ", " << nbytes << (nbytes == 1 ? " byte" : " bytes") << "\n";
+        errno = EBADF;
+        return -1;
+    }
+
+    if (pair.buffer[K].size() != 0)
+    {
+        std::cerr << "+++++ EAGAIN: Feed to fd " << fd << ", " << nbytes << (nbytes == 1 ? " byte" : " bytes") << "\n";
+        errno = EAGAIN;
+        return -1;
+    }
+
+    pair.buffer[K].resize(nbytes);
+    memmove(pair.buffer[K].data(), buf, nbytes);
+
+    // pair.cv->notify_one();
+    cv.notify_one();
+
+    std::cerr << "+++++ Feed to fd " << fd << ": " << nbytes << (nbytes == 1 ? " byte" : " bytes") << "\n";
+
+    return nbytes;
+}
+
 ssize_t fakeSocketWrite(int fd, const void *buf, size_t nbytes)
 {
+    std::vector<FakeSocketPair>& fds = getFds();
     std::unique_lock<std::mutex> fdsLock(fdsMutex);
     if (fd < 0 || fd/2 >= fds.size())
     {
+        std::cerr << "+++++ EBADF: Write to fd " << fd << ", " << nbytes << (nbytes == 1 ? " byte" : " bytes") << "\n";
         errno = EBADF;
         return -1;
     }
@@ -319,45 +454,37 @@ ssize_t fakeSocketWrite(int fd, const void *buf, size_t nbytes)
     const int K = (fd&1);
     const int N = 1 - K;
 
-    if (pair.nonblocking[K])
+    if (pair.fd[K] == -1)
     {
-        if (pair.fd[K] == -1)
-        {
-            errno = EBADF;
-            return -1;
-        }
-
-        if (pair.buffer[N].size() != 0)
-        {
-            errno = EAGAIN;
-            return -1;
-        }
+        std::cerr << "+++++ EBADF: Write to fd " << fd << ", " << nbytes << (nbytes == 1 ? " byte" : " bytes") << "\n";
+        errno = EBADF;
+        return -1;
     }
-    else
-    {
-        while (pair.fd[K] != -1 && pair.buffer[N].size() != 0)
-            pair.cv->wait(fdLock);
 
-        if (pair.fd[K] == -1)
-        {
-            errno = EBADF;
-            return -1;
-        }
+    if (pair.buffer[N].size() != 0)
+    {
+        std::cerr << "+++++ EAGAIN: Write to fd " << fd << ", " << nbytes << (nbytes == 1 ? " byte" : " bytes") << "\n";
+        errno = EAGAIN;
+        return -1;
     }
 
     pair.buffer[N].resize(nbytes);
     memmove(pair.buffer[N].data(), buf, nbytes);
 
-    pair.cv->notify_one();
+    // pair.cv->notify_one();
+    cv.notify_one();
 
+    std::cerr << "+++++ Write to fd " << fd << ": " << nbytes << (nbytes == 1 ? " byte" : " bytes") << "\n";
     return nbytes;
 }
 
 int fakeSocketClose(int fd)
 {
+    std::vector<FakeSocketPair>& fds = getFds();
     std::unique_lock<std::mutex> fdsLock(fdsMutex);
     if (fd < 0 || fd/2 >= fds.size())
     {
+        std::cerr << "+++++ EBADF: Close fd " << fd << "\n";
         errno = EBADF;
         return -1;
     }
@@ -371,6 +498,8 @@ int fakeSocketClose(int fd)
 
     pair.fd[fd&1] = -1;
 
+    std::cerr << "+++++ Close fd " << fd << "\n";
+
     return 0;
 }
 
diff --git a/net/FakeSocket.hpp b/net/FakeSocket.hpp
index db672b5fc..e1f89d53c 100644
--- a/net/FakeSocket.hpp
+++ b/net/FakeSocket.hpp
@@ -13,74 +13,35 @@
 #ifdef MOBILEAPP
 
 #include <poll.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <unistd.h>
 
 #ifndef SOCK_NONBLOCK
 #define SOCK_NONBLOCK 0x100
 #endif
 
-int fakeSocketSocket(int domain, int type, int protocol);
+int fakeSocketSocket();
 
-int fakeSocketPipe2(int pipefd[2], int flags);
+int fakeSocketPipe2(int pipefd[2]);
 
 int fakeSocketPoll(struct pollfd *fds, int nfds, int timeout);
 
-int fakeSocketListen(int fd, int backlog);
+int fakeSocketListen(int fd);
 
 int fakeSocketConnect(int fd1, int fd2);
 
-int fakeSocketAccept4(int fd, struct sockaddr *addr, socklen_t *addrlen, int flags);
+int fakeSocketAccept4(int fd, int flags);
+
+int fakeSocketPeer(int fd);
 
 ssize_t fakeSocketAvailableDataLength(int fd);
 
 ssize_t fakeSocketRead(int fd, void *buf, size_t nbytes);
 
+ssize_t fakeSocketFeed(int fd, const void *buf, size_t nbytes);
+
 ssize_t fakeSocketWrite(int fd, const void *buf, size_t nbytes);
 
 int fakeSocketClose(int fd);
 
-inline int socket(int domain, int type, int protocol)
-{
-    return fakeSocketSocket(domain, type, protocol);
-}
-
-inline int pipe2(int pipefd[2], int flags)
-{
-    return fakeSocketPipe2(pipefd, flags);
-}
-
-inline int poll(struct pollfd *fds, int nfds, int timeout)
-{
-    return fakeSocketPoll(fds, nfds, timeout);
-}
-
-inline int listen(int fd, int backlog)
-{
-    return fakeSocketListen(fd, backlog);
-}
-
-inline int accept4(int fd, struct sockaddr *addr, socklen_t *addrlen, int flags)
-{
-    return fakeSocketAccept4(fd, addr, addrlen, flags);
-}
-
-inline ssize_t read(int fd, void *buf, size_t nbytes)
-{
-    return fakeSocketRead(fd, buf, nbytes);
-}
-
-inline ssize_t write(int fd, const void *buf, size_t nbytes)
-{
-    return fakeSocketWrite(fd, buf, nbytes);
-}
-
-inline int close(int fd)
-{
-    return fakeSocketClose(fd);
-}
-
 #endif // MOBILEAPP
 
 #endif // INCLUDED_FAKESOCKET_H
commit 55a2f804a67f08c6abae31b4193a257e2491387d
Author:     Tor Lillqvist <tml at iki.fi>
AuthorDate: Fri Sep 14 10:49:58 2018 +0300
Commit:     Tor Lillqvist <tml at collabora.com>
CommitDate: Sat Sep 15 12:34:29 2018 +0300

    Change the FakeSocket to be record-oriented
    
    That is how Online uses the sockets for communication between the
    processes anyway: It send and receives complete WebSocket frames.
    Sure, in the mobile case there is just one process, but (I think) we
    want to keep the same basic structure anyway, even if "wsd" and "kit"
    are just threads. (We probably also want to drop the WebSocket framing
    of the messages.)
    
    Change-Id: I2397f321029c1cbbbc448a9b2403ad185a51cf14

diff --git a/Mobile/TestFakeSocket/TestFakeSocket/main.cpp b/Mobile/TestFakeSocket/TestFakeSocket/main.cpp
index 98463ab04..ea7a8ccd1 100644
--- a/Mobile/TestFakeSocket/TestFakeSocket/main.cpp
+++ b/Mobile/TestFakeSocket/TestFakeSocket/main.cpp
@@ -61,7 +61,7 @@ int main(int argc, char **argv)
     std::cout << "wrote 'hello'\n";
 
     char buf[100];
-    rc = fakeSocketRead(s3, buf, 3);
+    rc = fakeSocketRead(s3, buf, 100);
     if (rc == -1)
     {
         perror("read");
@@ -70,24 +70,22 @@ int main(int argc, char **argv)
     buf[rc] = 0;
     std::cout << "read " << buf << "\n";
 
-    rc = fakeSocketRead(s3, buf, 50);
+    rc = fakeSocketWrite(s1, "goodbye", 7);
     if (rc == -1)
     {
-        perror("read");
+        perror("write");
         return 1;
     }
-    buf[rc] = 0;
-    std::cout << "read " << buf << "\n";
+    std::cout << "wrote 'goodbye'\n";
 
-    rc = fakeSocketWrite(s1, "goodbye", 7);
-    if (rc == -1)
+    rc = fakeSocketRead(s3, buf, 4);
+    if (rc != -1)
     {
-        perror("write");
+        std::cerr << "Tried partial read, and succeeded!?\n";
         return 1;
     }
-    std::cout << "wrote 'goodbye'\n";
 
-    rc = fakeSocketRead(s3, buf, 50);
+    rc = fakeSocketRead(s3, buf, 100);
     if (rc == -1)
     {
         perror("read");
diff --git a/net/FakeSocket.cpp b/net/FakeSocket.cpp
index 03dac197e..7477c9755 100644
--- a/net/FakeSocket.cpp
+++ b/net/FakeSocket.cpp
@@ -28,7 +28,6 @@ struct FakeSocketPair
     int connectingFd;
     bool nonblocking[2];
     std::vector<char> buffer[2];
-    int readp[2];
     std::mutex *mutex;
     std::condition_variable *cv;
 
@@ -37,7 +36,6 @@ struct FakeSocketPair
         fd[0] = -1;
         fd[1] = -1;
         listening = false;
-        readp[0] = readp[1] = 0;
         mutex = new std::mutex();
         cv = new std::condition_variable();
     }
@@ -223,6 +221,26 @@ int fakeSocketAccept4(int fd, struct sockaddr *addr, socklen_t *addrlen, int fla
     return pair1.fd[1];
 }
 
+ssize_t fakeSocketAvailableDataLength(int fd)
+{
+    std::unique_lock<std::mutex> fdsLock(fdsMutex);
+    if (fd < 0 || fd/2 >= fds.size())
+    {
+        errno = EBADF;
+        return -1;
+    }
+
+    FakeSocketPair& pair = fds[fd/2];
+
+    std::unique_lock<std::mutex> fdLock(pair.mutex[0]);
+    fdsLock.unlock();
+
+    // K: for this fd
+    const int K = (fd&1);
+
+    return pair.buffer[K].size();
+}
+
 ssize_t fakeSocketRead(int fd, void *buf, size_t nbytes)
 {
     std::unique_lock<std::mutex> fdsLock(fdsMutex);
@@ -266,17 +284,20 @@ ssize_t fakeSocketRead(int fd, void *buf, size_t nbytes)
         }
     }
 
-    ssize_t result = std::min(nbytes, pair.buffer[K].size() - pair.readp[K]);
+    // These sockets are record-oriented!
+    ssize_t result = pair.buffer[K].size();
+    if (nbytes < result)
+    {
+        errno = EAGAIN; // Not the right errno, but what would be?
+        return -1;
+    }
 
-    memmove(buf, pair.buffer[K].data() + pair.readp[K], result);
-    if (pair.readp[K] + result < pair.buffer[K].size())
-        pair.readp[K] += result;
-    else
-        pair.buffer[K].resize(0);
+    memmove(buf, pair.buffer[K].data(), result);
+    pair.buffer[K].resize(0);
 
     pair.cv->notify_one();
 
-    return nbytes;
+    return result;
 }
 
 ssize_t fakeSocketWrite(int fd, const void *buf, size_t nbytes)
@@ -326,7 +347,6 @@ ssize_t fakeSocketWrite(int fd, const void *buf, size_t nbytes)
 
     pair.buffer[N].resize(nbytes);
     memmove(pair.buffer[N].data(), buf, nbytes);
-    pair.readp[N] = 0;
 
     pair.cv->notify_one();
 
diff --git a/net/FakeSocket.hpp b/net/FakeSocket.hpp
index 7e799698e..db672b5fc 100644
--- a/net/FakeSocket.hpp
+++ b/net/FakeSocket.hpp
@@ -33,6 +33,8 @@ int fakeSocketConnect(int fd1, int fd2);
 
 int fakeSocketAccept4(int fd, struct sockaddr *addr, socklen_t *addrlen, int flags);
 
+ssize_t fakeSocketAvailableDataLength(int fd);
+
 ssize_t fakeSocketRead(int fd, void *buf, size_t nbytes);
 
 ssize_t fakeSocketWrite(int fd, const void *buf, size_t nbytes);
commit 6d81ebcfeb507b185c26440ff0fe09e32fc58896
Author:     Tor Lillqvist <tml at iki.fi>
AuthorDate: Thu Sep 13 23:22:36 2018 +0300
Commit:     Tor Lillqvist <tml at collabora.com>
CommitDate: Sat Sep 15 12:30:50 2018 +0300

    Add FakeSocket
    
    Intended as a replacement for the real sockets used for WebSocket IPC
    in Online on Linux. The idea is that in a mobile app we don't want to
    bother with any actual sockets or WebSocket protocol (because we are
    running as a single process after all), but keep much of the code that
    thinks it is using such mostly unmodified. Just an idea so far, let's
    see how this turns out.
    
    Change-Id: I7878b0db99d9cbf70650227186c1fec9677fa74b

diff --git a/Mobile/TestFakeSocket/TestFakeSocket.xcodeproj/project.pbxproj b/Mobile/TestFakeSocket/TestFakeSocket.xcodeproj/project.pbxproj
new file mode 100644
index 000000000..33f62d2b6
--- /dev/null
+++ b/Mobile/TestFakeSocket/TestFakeSocket.xcodeproj/project.pbxproj
@@ -0,0 +1,285 @@
+// !$*UTF8*$!
+{
+	archiveVersion = 1;
+	classes = {
+	};
+	objectVersion = 50;
+	objects = {
+
+/* Begin PBXBuildFile section */
+		BEA28375214AFFCA00848631 /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEA28374214AFFCA00848631 /* main.cpp */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXCopyFilesBuildPhase section */
+		BEA28368214AFF9A00848631 /* CopyFiles */ = {
+			isa = PBXCopyFilesBuildPhase;
+			buildActionMask = 2147483647;
+			dstPath = /usr/share/man/man1/;
+			dstSubfolderSpec = 0;
+			files = (
+			);
+			runOnlyForDeploymentPostprocessing = 1;
+		};
+/* End PBXCopyFilesBuildPhase section */
+
+/* Begin PBXFileReference section */
+		BEA2836A214AFF9A00848631 /* TestFakeSocket */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = TestFakeSocket; sourceTree = BUILT_PRODUCTS_DIR; };
+		BEA28374214AFFCA00848631 /* main.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = main.cpp; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+		BEA28367214AFF9A00848631 /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+		BEA28361214AFF9A00848631 = {
+			isa = PBXGroup;
+			children = (
+				BEA2836C214AFF9A00848631 /* TestFakeSocket */,
+				BEA2836B214AFF9A00848631 /* Products */,
+			);
+			sourceTree = "<group>";
+		};
+		BEA2836B214AFF9A00848631 /* Products */ = {
+			isa = PBXGroup;
+			children = (
+				BEA2836A214AFF9A00848631 /* TestFakeSocket */,
+			);
+			name = Products;
+			sourceTree = "<group>";
+		};
+		BEA2836C214AFF9A00848631 /* TestFakeSocket */ = {
+			isa = PBXGroup;
+			children = (
+				BEA28374214AFFCA00848631 /* main.cpp */,
+			);
+			path = TestFakeSocket;
+			sourceTree = "<group>";
+		};
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+		BEA28369214AFF9A00848631 /* TestFakeSocket */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = BEA28371214AFF9A00848631 /* Build configuration list for PBXNativeTarget "TestFakeSocket" */;
+			buildPhases = (
+				BEA28366214AFF9A00848631 /* Sources */,
+				BEA28367214AFF9A00848631 /* Frameworks */,
+				BEA28368214AFF9A00848631 /* CopyFiles */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+			);
+			name = TestFakeSocket;
+			productName = TestFakeSocket;
+			productReference = BEA2836A214AFF9A00848631 /* TestFakeSocket */;
+			productType = "com.apple.product-type.tool";
+		};
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+		BEA28362214AFF9A00848631 /* Project object */ = {
+			isa = PBXProject;
+			attributes = {
+				LastUpgradeCheck = 0940;
+				ORGANIZATIONNAME = Collabora;
+				TargetAttributes = {
+					BEA28369214AFF9A00848631 = {
+						CreatedOnToolsVersion = 9.4.1;
+					};
+				};
+			};
+			buildConfigurationList = BEA28365214AFF9A00848631 /* Build configuration list for PBXProject "TestFakeSocket" */;
+			compatibilityVersion = "Xcode 9.3";
+			developmentRegion = en;
+			hasScannedForEncodings = 0;
+			knownRegions = (
+				en,
+			);
+			mainGroup = BEA28361214AFF9A00848631;
+			productRefGroup = BEA2836B214AFF9A00848631 /* Products */;
+			projectDirPath = "";
+			projectRoot = "";
+			targets = (
+				BEA28369214AFF9A00848631 /* TestFakeSocket */,
+			);
+		};
+/* End PBXProject section */
+
+/* Begin PBXSourcesBuildPhase section */
+		BEA28366214AFF9A00848631 /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				BEA28375214AFFCA00848631 /* main.cpp in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXSourcesBuildPhase section */
+
+/* Begin XCBuildConfiguration section */
+		BEA2836F214AFF9A00848631 /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				CLANG_ANALYZER_NONNULL = YES;
+				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+				CLANG_CXX_LIBRARY = "libc++";
+				CLANG_ENABLE_MODULES = YES;
+				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_ENABLE_OBJC_WEAK = YES;
+				CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_COMMA = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INFINITE_RECURSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+				CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+				CLANG_WARN_STRICT_PROTOTYPES = YES;
+				CLANG_WARN_SUSPICIOUS_MOVE = YES;
+				CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+				CLANG_WARN_UNREACHABLE_CODE = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				CODE_SIGN_IDENTITY = "Mac Developer";
+				COPY_PHASE_STRIP = NO;
+				DEBUG_INFORMATION_FORMAT = dwarf;
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				ENABLE_TESTABILITY = YES;
+				GCC_C_LANGUAGE_STANDARD = gnu11;
+				GCC_DYNAMIC_NO_PIC = NO;
+				GCC_NO_COMMON_BLOCKS = YES;
+				GCC_OPTIMIZATION_LEVEL = 0;
+				GCC_PREPROCESSOR_DEFINITIONS = (
+					"DEBUG=1",
+					"$(inherited)",
+				);
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+				GCC_WARN_UNUSED_FUNCTION = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				MACOSX_DEPLOYMENT_TARGET = 10.13;
+				MTL_ENABLE_DEBUG_INFO = YES;
+				ONLY_ACTIVE_ARCH = YES;
+				SDKROOT = macosx;
+			};
+			name = Debug;
+		};
+		BEA28370214AFF9A00848631 /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				CLANG_ANALYZER_NONNULL = YES;
+				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+				CLANG_CXX_LIBRARY = "libc++";
+				CLANG_ENABLE_MODULES = YES;
+				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_ENABLE_OBJC_WEAK = YES;
+				CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_COMMA = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INFINITE_RECURSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+				CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+				CLANG_WARN_STRICT_PROTOTYPES = YES;
+				CLANG_WARN_SUSPICIOUS_MOVE = YES;
+				CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+				CLANG_WARN_UNREACHABLE_CODE = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				CODE_SIGN_IDENTITY = "Mac Developer";
+				COPY_PHASE_STRIP = NO;
+				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+				ENABLE_NS_ASSERTIONS = NO;
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				GCC_C_LANGUAGE_STANDARD = gnu11;
+				GCC_NO_COMMON_BLOCKS = YES;
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+				GCC_WARN_UNUSED_FUNCTION = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				MACOSX_DEPLOYMENT_TARGET = 10.13;
+				MTL_ENABLE_DEBUG_INFO = NO;
+				SDKROOT = macosx;
+			};
+			name = Release;
+		};
+		BEA28372214AFF9A00848631 /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				CODE_SIGN_IDENTITY = "Mac Developer";
+				CODE_SIGN_STYLE = Automatic;
+				DEVELOPMENT_TEAM = J4FQ687VJK;
+				HEADER_SEARCH_PATHS = ../../net;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				PROVISIONING_PROFILE_SPECIFIER = "";
+			};
+			name = Debug;
+		};
+		BEA28373214AFF9A00848631 /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				CODE_SIGN_IDENTITY = "Mac Developer";
+				CODE_SIGN_STYLE = Automatic;
+				DEVELOPMENT_TEAM = J4FQ687VJK;
+				HEADER_SEARCH_PATHS = ../../net;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				PROVISIONING_PROFILE_SPECIFIER = "";
+			};
+			name = Release;
+		};
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+		BEA28365214AFF9A00848631 /* Build configuration list for PBXProject "TestFakeSocket" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				BEA2836F214AFF9A00848631 /* Debug */,
+				BEA28370214AFF9A00848631 /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+		BEA28371214AFF9A00848631 /* Build configuration list for PBXNativeTarget "TestFakeSocket" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				BEA28372214AFF9A00848631 /* Debug */,
+				BEA28373214AFF9A00848631 /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+/* End XCConfigurationList section */
+	};
+	rootObject = BEA28362214AFF9A00848631 /* Project object */;
+}
diff --git a/Mobile/TestFakeSocket/TestFakeSocket/main.cpp b/Mobile/TestFakeSocket/TestFakeSocket/main.cpp
new file mode 100644
index 000000000..98463ab04
--- /dev/null
+++ b/Mobile/TestFakeSocket/TestFakeSocket/main.cpp
@@ -0,0 +1,130 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <iostream>
+#include <thread>
+
+#define MOBILEAPP
+
+#include "FakeSocket.cpp"
+
+int main(int argc, char **argv)
+{
+    int s0 = fakeSocketSocket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0);
+    int s1 = fakeSocketSocket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0);
+    int s2 = fakeSocketSocket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0);
+
+    std::cout << "sockets: " << s0 << ", " << s1 << ", " << s2 << "\n";
+
+    fakeSocketClose(s1);
+
+    s1 = fakeSocketSocket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0);
+    std::cout << "closed and created s1 again: " << s1 << "\n";
+
+    int rc = fakeSocketListen(s0, 10);
+    if (rc == -1)
+    {
+        perror("listen");
+        return 1;
+    }
+
+    int s3;
+    std::thread t0([&] {
+            s3 = fakeSocketAccept4(s0, nullptr, nullptr, 0);
+            if (s3 == -1)
+                perror("accept");
+        });
+
+    rc = fakeSocketConnect(s1, s0);
+    if (rc == -1)
+    {
+        perror("connect");
+        return 1;
+    }
+    
+    t0.join();
+    if (s3 == -1)
+        return 1;
+
+    rc = fakeSocketWrite(s1, "hello", 6);
+    if (rc == -1)
+    {
+        perror("write");
+        return 1;
+    }
+    std::cout << "wrote 'hello'\n";
+
+    char buf[100];
+    rc = fakeSocketRead(s3, buf, 3);
+    if (rc == -1)
+    {
+        perror("read");
+        return 1;
+    }
+    buf[rc] = 0;
+    std::cout << "read " << buf << "\n";
+
+    rc = fakeSocketRead(s3, buf, 50);
+    if (rc == -1)
+    {
+        perror("read");
+        return 1;
+    }
+    buf[rc] = 0;
+    std::cout << "read " << buf << "\n";
+
+    rc = fakeSocketWrite(s1, "goodbye", 7);
+    if (rc == -1)
+    {
+        perror("write");
+        return 1;
+    }
+    std::cout << "wrote 'goodbye'\n";
+
+    rc = fakeSocketRead(s3, buf, 50);
+    if (rc == -1)
+    {
+        perror("read");
+        return 1;
+    }
+    buf[rc] = 0;
+    std::cout << "read " << buf << "\n";
+
+    int pipe[2];
+    rc = fakeSocketPipe2(pipe, 0);
+    if (rc == -1)
+    {
+        perror("pipe2");
+        return 1;
+    }
+
+    rc = fakeSocketWrite(pipe[0], "x", 1);
+    if (rc == -1)
+    {
+        perror("write");
+        return 1;
+    }
+    rc = fakeSocketRead(pipe[1], buf, 1);
+    if (rc == -1)
+    {
+        perror("read");
+        return 1;
+    }
+    if (buf[0] != 'x')
+    {
+        std::cerr << "Wrote 'x' but read '" << buf[0] << "'\n";
+        return 1;
+    }
+        
+    return 0;
+}
+
+
+    
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/net/FakeSocket.cpp b/net/FakeSocket.cpp
new file mode 100644
index 000000000..03dac197e
--- /dev/null
+++ b/net/FakeSocket.cpp
@@ -0,0 +1,357 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+
+#include <condition_variable>
+#include <mutex>
+#include <vector>
+
+#ifdef TEST
+#include <iostream>
+#define MOBILEAPP
+#endif
+
+#include "FakeSocket.hpp"
+
+struct FakeSocketPair
+{
+    int fd[2];
+    bool listening;
+    int connectingFd;
+    bool nonblocking[2];
+    std::vector<char> buffer[2];
+    int readp[2];
+    std::mutex *mutex;
+    std::condition_variable *cv;
+
+    FakeSocketPair()
+    {
+        fd[0] = -1;
+        fd[1] = -1;
+        listening = false;
+        readp[0] = readp[1] = 0;
+        mutex = new std::mutex();
+        cv = new std::condition_variable();
+    }
+};
+
+static std::mutex fdsMutex;
+
+static std::vector<FakeSocketPair> fds;
+
+int fakeSocketSocket(int domain, int type, int protocol)
+{
+    if (domain == AF_INET && (type & ~SOCK_NONBLOCK) == SOCK_STREAM && protocol == 0)
+    {
+        std::lock_guard<std::mutex> fdsLock(fdsMutex);
+        size_t i;
+        for (i = 0; i < fds.size(); i++)
+        {
+            if (fds[i].fd[0] == -1 && fds[i].fd[1] == -1)
+                break;
+        }
+        if (i == fds.size())
+            fds.resize(fds.size() + 1);
+
+        FakeSocketPair& result = fds[i];
+
+        result.fd[0] = i*2;
+        result.fd[1] = -1;
+        result.listening = false;
+        result.nonblocking[0] = !!(type & SOCK_NONBLOCK);
+        result.buffer[0].resize(0);
+        result.buffer[1].resize(0);
+
+        return i*2;
+    }
+
+    errno = EACCES;
+    return -1;
+}
+
+int fakeSocketPipe2(int pipefd[2], int flags)
+{
+    pipefd[0] = fakeSocketSocket(AF_INET, SOCK_STREAM, ((flags & O_NONBLOCK) ? SOCK_NONBLOCK : 0));
+
+    FakeSocketPair& pair = fds[pipefd[0]/2];
+
+    std::unique_lock<std::mutex> fdLock(pair.mutex[0]);
+
+    assert(pair.fd[0] == pipefd[0]);
+
+    pair.fd[1] = pair.fd[0] + 1;
+    pair.nonblocking[1] = pair.nonblocking[0];
+    pipefd[1] = pair.fd[1];
+
+    return 0;
+}
+
+int fakeSocketPoll(struct pollfd *fds, int nfds, int timeout)
+{
+    return -1;
+}
+
+int fakeSocketListen(int fd, int backlog)
+{
+    std::unique_lock<std::mutex> fdsLock(fdsMutex);
+    if (fd < 0 || fd/2 >= fds.size())
+    {
+        errno = EBADF;
+        return -1;
+    }
+    
+    FakeSocketPair& pair = fds[fd/2];
+    std::unique_lock<std::mutex> fdLock(pair.mutex[0]);
+    fdsLock.unlock();
+
+    if (fd&1 || pair.fd[1] != -1)
+    {
+        errno = EISCONN;
+        return -1;
+    }
+    
+    if (pair.listening)
+    {
+        errno = EIO;
+        return -1;
+    }
+
+    pair.listening = true;
+    pair.connectingFd = -1;
+
+    return 0;
+}
+
+int fakeSocketConnect(int fd1, int fd2)
+{
+    std::unique_lock<std::mutex> fdsLock(fdsMutex);
+    if (fd1 < 0 || fd2 < 0 || fd1/2 >= fds.size() || fd2/2 >= fds.size())
+    {
+        errno = EBADF;
+        return -1;
+    }
+    if (fd1/2 == fd2/2)
+    {
+        errno = EBADF;
+        return -1;
+    }
+
+    FakeSocketPair& pair1 = fds[fd1/2];
+    FakeSocketPair& pair2 = fds[fd2/2];
+
+    std::unique_lock<std::mutex> fdLock1(pair1.mutex[0]);
+    std::unique_lock<std::mutex> fdLock2(pair2.mutex[0]);
+    fdsLock.unlock();
+
+    if ((fd1&1) || (fd2&1))
+    {
+        errno = EISCONN;
+        return -1;
+    }
+
+    if (!pair2.listening || pair2.connectingFd != -1)
+    {
+        errno = ECONNREFUSED;
+        return -1;
+    }
+
+    pair2.connectingFd = fd1;
+    pair2.cv->notify_all();
+
+    fdLock2.unlock();
+    while (pair1.fd[1] == -1)
+        pair1.cv->wait(fdLock1);
+
+    assert(pair1.fd[1] == pair1.fd[0] + 1);
+
+    return 0;
+}
+
+int fakeSocketAccept4(int fd, struct sockaddr *addr, socklen_t *addrlen, int flags)
+{
+    std::unique_lock<std::mutex> fdsLock(fdsMutex);
+    if (fd < 0 || fd/2 >= fds.size())
+    {
+        errno = EBADF;
+        return -1;
+    }
+
+    if (fd & 1)
+    {
+        errno = EISCONN;
+        return -1;
+    }
+
+    FakeSocketPair& pair = fds[fd/2];
+
+    if (!pair.listening)
+    {
+        errno = EIO;
+        return -1;
+    }
+
+    std::unique_lock<std::mutex> fdLock(pair.mutex[0]);
+    fdsLock.unlock();
+
+    while (pair.connectingFd == -1)
+        pair.cv->wait(fdLock);
+    
+    assert(pair.connectingFd >= 0 && pair.connectingFd/2 < fds.size());
+
+    FakeSocketPair& pair1 = fds[pair.connectingFd/2];
+    
+    std::unique_lock<std::mutex> fdLock1(pair1.mutex[0]);
+
+    assert(pair1.fd[1] == -1);
+    assert(pair1.fd[0] == pair.connectingFd);
+
+    pair.connectingFd = -1;
+    fdLock.unlock();
+
+    pair1.fd[1] = pair1.fd[0] + 1;
+
+    pair1.cv->notify_one();
+
+    return pair1.fd[1];
+}
+
+ssize_t fakeSocketRead(int fd, void *buf, size_t nbytes)
+{
+    std::unique_lock<std::mutex> fdsLock(fdsMutex);
+    if (fd < 0 || fd/2 >= fds.size())
+    {
+        errno = EBADF;
+        return -1;
+    }
+
+    FakeSocketPair& pair = fds[fd/2];
+
+    std::unique_lock<std::mutex> fdLock(pair.mutex[0]);
+    fdsLock.unlock();
+
+    // K: for this fd
+    const int K = (fd&1);
+
+    if (pair.nonblocking[K])
+    {
+        if (pair.fd[K] == -1)
+        {
+            errno = EBADF;
+            return -1;
+        }
+
+        if (pair.buffer[K].size() == 0)
+        {
+            errno = EAGAIN;
+            return -1;
+        }
+    }
+    else
+    {
+        while (pair.fd[K] != -1 && pair.buffer[K].size() == 0)
+            pair.cv->wait(fdLock);
+
+        if (pair.fd[K] == -1)
+        {
+            errno = EBADF;
+            return -1;
+        }
+    }
+
+    ssize_t result = std::min(nbytes, pair.buffer[K].size() - pair.readp[K]);
+
+    memmove(buf, pair.buffer[K].data() + pair.readp[K], result);
+    if (pair.readp[K] + result < pair.buffer[K].size())
+        pair.readp[K] += result;
+    else
+        pair.buffer[K].resize(0);
+
+    pair.cv->notify_one();
+
+    return nbytes;
+}
+
+ssize_t fakeSocketWrite(int fd, const void *buf, size_t nbytes)
+{
+    std::unique_lock<std::mutex> fdsLock(fdsMutex);
+    if (fd < 0 || fd/2 >= fds.size())
+    {
+        errno = EBADF;
+        return -1;
+    }
+
+    FakeSocketPair& pair = fds[fd/2];
+
+    std::unique_lock<std::mutex> fdLock(pair.mutex[0]);
+    fdsLock.unlock();
+
+    // K: for this fd
+    // N: for its peer, whose read buffer we want to write into
+    const int K = (fd&1);
+    const int N = 1 - K;
+
+    if (pair.nonblocking[K])
+    {
+        if (pair.fd[K] == -1)
+        {
+            errno = EBADF;
+            return -1;
+        }
+
+        if (pair.buffer[N].size() != 0)
+        {
+            errno = EAGAIN;
+            return -1;
+        }
+    }
+    else
+    {
+        while (pair.fd[K] != -1 && pair.buffer[N].size() != 0)
+            pair.cv->wait(fdLock);
+
+        if (pair.fd[K] == -1)
+        {
+            errno = EBADF;
+            return -1;
+        }
+    }
+
+    pair.buffer[N].resize(nbytes);
+    memmove(pair.buffer[N].data(), buf, nbytes);
+    pair.readp[N] = 0;
+
+    pair.cv->notify_one();
+
+    return nbytes;
+}
+
+int fakeSocketClose(int fd)
+{
+    std::unique_lock<std::mutex> fdsLock(fdsMutex);
+    if (fd < 0 || fd/2 >= fds.size())
+    {
+        errno = EBADF;
+        return -1;
+    }
+
+    FakeSocketPair& pair = fds[fd/2];
+
+    std::unique_lock<std::mutex> fdLock(pair.mutex[0]);
+    fdsLock.unlock();
+
+    assert(pair.fd[fd&1] == fd);
+
+    pair.fd[fd&1] = -1;
+
+    return 0;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/net/FakeSocket.hpp b/net/FakeSocket.hpp
new file mode 100644
index 000000000..7e799698e
--- /dev/null
+++ b/net/FakeSocket.hpp
@@ -0,0 +1,86 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_FAKESOCKET_H
+#define INCLUDED_FAKESOCKET_H
+
+#ifdef MOBILEAPP
+
+#include <poll.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#ifndef SOCK_NONBLOCK
+#define SOCK_NONBLOCK 0x100
+#endif
+
+int fakeSocketSocket(int domain, int type, int protocol);
+
+int fakeSocketPipe2(int pipefd[2], int flags);
+
+int fakeSocketPoll(struct pollfd *fds, int nfds, int timeout);
+
+int fakeSocketListen(int fd, int backlog);
+
+int fakeSocketConnect(int fd1, int fd2);
+
+int fakeSocketAccept4(int fd, struct sockaddr *addr, socklen_t *addrlen, int flags);
+
+ssize_t fakeSocketRead(int fd, void *buf, size_t nbytes);
+
+ssize_t fakeSocketWrite(int fd, const void *buf, size_t nbytes);
+
+int fakeSocketClose(int fd);
+
+inline int socket(int domain, int type, int protocol)
+{
+    return fakeSocketSocket(domain, type, protocol);
+}
+
+inline int pipe2(int pipefd[2], int flags)
+{
+    return fakeSocketPipe2(pipefd, flags);
+}
+
+inline int poll(struct pollfd *fds, int nfds, int timeout)
+{
+    return fakeSocketPoll(fds, nfds, timeout);
+}
+
+inline int listen(int fd, int backlog)
+{
+    return fakeSocketListen(fd, backlog);
+}
+
+inline int accept4(int fd, struct sockaddr *addr, socklen_t *addrlen, int flags)
+{
+    return fakeSocketAccept4(fd, addr, addrlen, flags);
+}
+
+inline ssize_t read(int fd, void *buf, size_t nbytes)
+{
+    return fakeSocketRead(fd, buf, nbytes);
+}
+
+inline ssize_t write(int fd, const void *buf, size_t nbytes)
+{
+    return fakeSocketWrite(fd, buf, nbytes);
+}
+
+inline int close(int fd)
+{
+    return fakeSocketClose(fd);
+}
+
+#endif // MOBILEAPP
+
+#endif // INCLUDED_FAKESOCKET_H
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */


More information about the Libreoffice-commits mailing list