1 // Copyright 2016 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "aemu/base/Log.h"
16 #include "aemu/base/sockets/ScopedSocket.h"
17 #include "aemu/base/sockets/SocketUtils.h"
18 
19 #include "aemu/base/threads/Thread.h"
20 
21 #include <string>
22 #include <string_view>
23 
24 #include <stddef.h>
25 
26 #ifdef _WIN32
27 #undef ERROR
28 #endif
29 
30 namespace android {
31 namespace base {
32 
33 // Simple server thread that receives data and stores it in a buffer.
34 // Usage is the following:
35 //
36 // 1) Create instance, passing a port to listen to the constructor.
37 //    The default constructor will bind to a random port, which you
38 //    can retrieve with the port() method. Check that the port could be
39 //    be bound with the valid() method.
40 //
41 // 2) Start the thread, it will store all the data it receives into
42 //    an internal buffer. The thread only stops when the connection
43 //    is closed from the remote end.
44 //
45 // 3) Join the thread, the result is the size of the buffer in bytes, or
46 //    -1 if a connection could not be accepted.
47 //
48 // 4) Use view() to retrieve a view of the content.
49 //
50 class TestInputBufferSocketServerThread : public android::base::Thread {
51 public:
52     // Create new thread instance, try to bound to specific TCP |port|,
53     // a value of 0 let the system choose a free IPv4 port, which can
54     // later be retrieved with port().
55     TestInputBufferSocketServerThread(int port = 0)
Thread()56         : Thread(), mSocket(android::base::socketTcp4LoopbackServer(port)) {}
57 
58     // Returns true if port could be bound.
valid()59     bool valid() const { return mSocket.valid(); }
60 
61     // Return bound server port.
port()62     int port() const { return android::base::socketGetPort(mSocket.get()); }
63 
64     // Return buffer content as a std::string_view.
view()65     std::string_view view() const { return mString; }
66 
67     // Main function simply receives everything and stores it in a string.
main()68     virtual intptr_t main() override {
69         // Wait for a single connection.
70         int fd = android::base::socketAcceptAny(mSocket.get());
71         if (fd < 0) {
72             LOG(ERROR) << "Could not accept one connection!";
73             return -1;
74         }
75 
76         // Now read data from the connection until it closes.
77         size_t size = 0;
78         for (;;) {
79             size_t capacity = mString.size();
80             if (size >= capacity) {
81                 mString.resize(1024 + capacity * 2);
82                 capacity = mString.size();
83             }
84             size_t avail = capacity - size;
85             ssize_t len = android::base::socketRecv(fd, &mString[size], avail);
86             if (len <= 0) {
87                 break;
88             }
89             size += len;
90         }
91         android::base::socketClose(fd);
92 
93         mString.resize(size);
94         return static_cast<intptr_t>(size);
95     }
96 
97 private:
98     ScopedSocket mSocket;
99     std::string mString;
100 };
101 
102 }  // namespace base
103 }  // namespace android
104