Parcourir la source

fixbug: vector resize may cause invalid references

ithewei il y a 4 ans
Parent
commit
8e70be9fd9
3 fichiers modifiés avec 18 ajouts et 25 suppressions
  1. 3 3
      evpp/Channel.h
  2. 12 14
      evpp/TcpServer.h
  3. 3 8
      http/client/AsyncHttpClient.h

+ 3 - 3
evpp/Channel.h

@@ -34,9 +34,9 @@ public:
         close();
     }
 
-    hio_t* io() { return io_; }
-    int fd() { return fd_; }
-    int id() { return id_; }
+    hio_t*      io() { return io_; }
+    int         fd() { return fd_; }
+    uint32_t    id() { return id_; }
     int error() { return hio_error(io_); }
 
     // context

+ 12 - 14
evpp/TcpServer.h

@@ -17,7 +17,6 @@ public:
         listenfd = -1;
         tls = false;
         max_connections = 0xFFFFFFFF;
-        connection_num = 0;
     }
 
     virtual ~TcpServer() {
@@ -73,32 +72,31 @@ public:
     const SocketChannelPtr& addChannel(hio_t* io) {
         std::lock_guard<std::mutex> locker(mutex_);
         int fd = hio_fd(io);
-        if (fd >= channels.capacity()) {
-            channels.resize(2 * fd);
-        }
-        channels[fd].reset(new SocketChannel(io));
+        channels[fd] = SocketChannelPtr(new SocketChannel(io));
         return channels[fd];
     }
 
     void removeChannel(const SocketChannelPtr& channel) {
         std::lock_guard<std::mutex> locker(mutex_);
         int fd = channel->fd();
-        if (fd < channels.capacity()) {
-            channels[fd] = NULL;
-        }
+        channels.erase(fd);
+    }
+
+    size_t connectionNum() {
+        std::lock_guard<std::mutex> locker(mutex_);
+        return channels.size();
     }
 
 private:
     static void onAccept(hio_t* connio) {
         TcpServer* server = (TcpServer*)hevent_userdata(connio);
-        if (server->connection_num >= server->max_connections) {
+        if (server->connectionNum() >= server->max_connections) {
             hlogw("over max_connections");
             hio_close(connio);
             return;
         }
         const SocketChannelPtr& channel = server->addChannel(connio);
         channel->status = SocketChannel::CONNECTED;
-        ++server->connection_num;
 
         channel->onread = [server, &channel](Buffer* buf) {
             if (server->onMessage) {
@@ -116,7 +114,8 @@ private:
                 server->onConnection(channel);
             }
             server->removeChannel(channel);
-            --server->connection_num;
+            // NOTE: After removeChannel, channel may be destroyed,
+            // so in this lambda function, no code should be added below.
         };
 
         channel->startRead();
@@ -134,12 +133,11 @@ public:
     WriteCompleteCallback   onWriteComplete;
 
     uint32_t                max_connections;
-    std::atomic<uint32_t>   connection_num;
 
 private:
     EventLoopThreadPool     loop_threads;
-    // with fd as index
-    std::vector<SocketChannelPtr>   channels; // GUAREDE_BY(mutex_)
+    // fd => SocketChannelPtr
+    std::map<int, SocketChannelPtr> channels; // GUAREDE_BY(mutex_)
     std::mutex                      mutex_;
 };
 

+ 3 - 8
http/client/AsyncHttpClient.h

@@ -137,9 +137,6 @@ protected:
         SocketChannelPtr channel(new SocketChannel(io));
         channel->newContext<HttpClientContext>();
         int fd = channel->fd();
-        if (fd >= channels.capacity()) {
-            channels.resize(2 * fd);
-        }
         channels[fd] = channel;
         return channels[fd];
     }
@@ -147,16 +144,14 @@ protected:
     void removeChannel(const SocketChannelPtr& channel) {
         channel->deleteContext<HttpClientContext>();
         int fd = channel->fd();
-        if (fd < channels.capacity()) {
-            channels[fd] = NULL;
-        }
+        channels.erase(fd);
     }
 
 private:
     EventLoopThread                         loop_thread;
     // NOTE: just one loop thread, no need mutex.
-    // with fd as index
-    std::vector<SocketChannelPtr>           channels;
+    // fd => SocketChannelPtr
+    std::map<int, SocketChannelPtr>         channels;
     // peeraddr => ConnPool
     std::map<std::string, ConnPool<int>>    conn_pools;
 };