Переглянути джерело

Added SocketCore, make Socket a handle class for SocketCore.

Tatsuhiro Tsujikawa 19 роки тому
батько
коміт
8acb1181f9
7 змінених файлів з 280 додано та 113 видалено
  1. 6 6
      src/DownloadEngine.cc
  2. 1 0
      src/Makefile.am
  3. 17 0
      src/Makefile.in
  4. 23 105
      src/Socket.cc
  5. 5 2
      src/Socket.h
  6. 152 0
      src/SocketCore.cc
  7. 76 0
      src/SocketCore.h

+ 6 - 6
src/DownloadEngine.cc

@@ -104,15 +104,15 @@ void DownloadEngine::waitData() {
   FD_ZERO(&wfds);
   int max = 0;
   for(vector<Socket*>::iterator itr = rsockets.begin(); itr != rsockets.end(); itr++) {
-    FD_SET((*itr)->sockfd, &rfds);
-    if(max < (*itr)->sockfd) {
-      max = (*itr)->sockfd;
+    FD_SET((*itr)->getSockfd(), &rfds);
+    if(max < (*itr)->getSockfd()) {
+      max = (*itr)->getSockfd();
     }
   }
   for(vector<Socket*>::iterator itr = wsockets.begin(); itr != wsockets.end(); itr++) {
-    FD_SET((*itr)->sockfd, &wfds);
-    if(max < (*itr)->sockfd) {
-      max = (*itr)->sockfd;
+    FD_SET((*itr)->getSockfd(), &wfds);
+    if(max < (*itr)->getSockfd()) {
+      max = (*itr)->getSockfd();
     }
   }
   tv.tv_sec = 1;

+ 1 - 0
src/Makefile.am

@@ -1,6 +1,7 @@
 bin_PROGRAMS = aria2c
 aria2c_SOURCES = main.cc
 SRCS =  Socket.cc Socket.h\
+	SocketCore.cc SocketCore.h\
 	Command.h\
 	AbstractCommand.cc AbstractCommand.h\
 	InitiateConnectionCommandFactory.cc InitiateConnectionCommandFactory.h\

+ 17 - 0
src/Makefile.in

@@ -51,6 +51,7 @@ ARFLAGS = cru
 libaria2c_a_AR = $(AR) $(ARFLAGS)
 libaria2c_a_LIBADD =
 am__objects_1 = libaria2c_a-Socket.$(OBJEXT) \
+	libaria2c_a-SocketCore.$(OBJEXT) \
 	libaria2c_a-AbstractCommand.$(OBJEXT) \
 	libaria2c_a-InitiateConnectionCommandFactory.$(OBJEXT) \
 	libaria2c_a-DownloadCommand.$(OBJEXT) \
@@ -180,6 +181,7 @@ sysconfdir = @sysconfdir@
 target_alias = @target_alias@
 aria2c_SOURCES = main.cc
 SRCS = Socket.cc Socket.h\
+	SocketCore.cc SocketCore.h\
 	Command.h\
 	AbstractCommand.cc AbstractCommand.h\
 	InitiateConnectionCommandFactory.cc InitiateConnectionCommandFactory.h\
@@ -317,6 +319,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libaria2c_a-SimpleLogger.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libaria2c_a-SleepCommand.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libaria2c_a-Socket.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libaria2c_a-SocketCore.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libaria2c_a-Util.Po@am__quote@
 
 .cc.o:
@@ -347,6 +350,20 @@ libaria2c_a-Socket.obj: Socket.cc
 @AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -c -o libaria2c_a-Socket.obj `if test -f 'Socket.cc'; then $(CYGPATH_W) 'Socket.cc'; else $(CYGPATH_W) '$(srcdir)/Socket.cc'; fi`
 
+libaria2c_a-SocketCore.o: SocketCore.cc
+@am__fastdepCXX_TRUE@	if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -MT libaria2c_a-SocketCore.o -MD -MP -MF "$(DEPDIR)/libaria2c_a-SocketCore.Tpo" -c -o libaria2c_a-SocketCore.o `test -f 'SocketCore.cc' || echo '$(srcdir)/'`SocketCore.cc; \
+@am__fastdepCXX_TRUE@	then mv -f "$(DEPDIR)/libaria2c_a-SocketCore.Tpo" "$(DEPDIR)/libaria2c_a-SocketCore.Po"; else rm -f "$(DEPDIR)/libaria2c_a-SocketCore.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='SocketCore.cc' object='libaria2c_a-SocketCore.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -c -o libaria2c_a-SocketCore.o `test -f 'SocketCore.cc' || echo '$(srcdir)/'`SocketCore.cc
+
+libaria2c_a-SocketCore.obj: SocketCore.cc
+@am__fastdepCXX_TRUE@	if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -MT libaria2c_a-SocketCore.obj -MD -MP -MF "$(DEPDIR)/libaria2c_a-SocketCore.Tpo" -c -o libaria2c_a-SocketCore.obj `if test -f 'SocketCore.cc'; then $(CYGPATH_W) 'SocketCore.cc'; else $(CYGPATH_W) '$(srcdir)/SocketCore.cc'; fi`; \
+@am__fastdepCXX_TRUE@	then mv -f "$(DEPDIR)/libaria2c_a-SocketCore.Tpo" "$(DEPDIR)/libaria2c_a-SocketCore.Po"; else rm -f "$(DEPDIR)/libaria2c_a-SocketCore.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='SocketCore.cc' object='libaria2c_a-SocketCore.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -c -o libaria2c_a-SocketCore.obj `if test -f 'SocketCore.cc'; then $(CYGPATH_W) 'SocketCore.cc'; else $(CYGPATH_W) '$(srcdir)/SocketCore.cc'; fi`
+
 libaria2c_a-AbstractCommand.o: AbstractCommand.cc
 @am__fastdepCXX_TRUE@	if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -MT libaria2c_a-AbstractCommand.o -MD -MP -MF "$(DEPDIR)/libaria2c_a-AbstractCommand.Tpo" -c -o libaria2c_a-AbstractCommand.o `test -f 'AbstractCommand.cc' || echo '$(srcdir)/'`AbstractCommand.cc; \
 @am__fastdepCXX_TRUE@	then mv -f "$(DEPDIR)/libaria2c_a-AbstractCommand.Tpo" "$(DEPDIR)/libaria2c_a-AbstractCommand.Po"; else rm -f "$(DEPDIR)/libaria2c_a-AbstractCommand.Tpo"; exit 1; fi

+ 23 - 105
src/Socket.cc

@@ -20,145 +20,63 @@
  */
 /* copyright --> */
 #include "Socket.h"
-#include <unistd.h>
-#include <fcntl.h>
-#include <netdb.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <sys/time.h>
-#include <netdb.h>
-#include "DlRetryEx.h"
-#include "DlAbortEx.h"
-#include <errno.h>
 
-Socket::Socket():sockfd(-1) {}
+Socket::Socket() {
+  core = new SocketCore();
+}
 
 Socket::Socket(const Socket& s) {
-  sockfd = dup(s.sockfd);
+  core = s.core;
+  core->use++;
 }
 
 Socket::~Socket() {
-  closeConnection();
+  core->use--;
+  if(core->use == 0) {
+    delete core;
+  }
 }
 
 Socket& Socket::operator=(const Socket& s) {
   if(this != &s) {
-    closeConnection();
-    sockfd = dup(s.sockfd);
+    core->use--;
+    if(core->use == 0) {
+      delete core;
+    }
+    core = s.core;
+    core->use++;
   }
   return *this;
 }
 
 void Socket::establishConnection(string host, int port) {
-  sockfd = socket(AF_INET, SOCK_STREAM, 0);
-  if(sockfd >= 0) {
-    socklen_t sockopt = 1;
-    if(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof(int)) < 0) {
-      close(sockfd);
-      sockfd = -1;
-      throw new DlAbortEx(strerror(errno));
-    }
-  } else {
-      throw new DlAbortEx(strerror(errno));
-  }
-
-  struct sockaddr_in sockaddr;
-  memset((char*)&sockaddr, 0, sizeof(sockaddr));
-  sockaddr.sin_family = AF_INET;
-  sockaddr.sin_port = htons(port);
-  if(inet_aton(host.c_str(), &sockaddr.sin_addr)) {
-    // ok
-  } else {
-    struct addrinfo ai;
-    ai.ai_flags = 0;
-    ai.ai_family = PF_INET;
-    ai.ai_socktype = SOCK_STREAM;
-    ai.ai_protocol = 0; 
-    ai.ai_addr = (struct sockaddr*)&sockaddr;
-    struct addrinfo* res;
-    int ec;
-    if((ec = getaddrinfo(host.c_str(), NULL, &ai, &res)) != 0) {
-      throw new DlAbortEx(gai_strerror(ec));
-    }
-    sockaddr.sin_addr = ((struct sockaddr_in*)res->ai_addr)->sin_addr;
-    freeaddrinfo(res);
-  }
-  // make socket non-blocking mode
-  int flags = fcntl(sockfd, F_GETFL, 0);
-  fcntl(sockfd, F_SETFL, flags|O_NONBLOCK);
-  if(connect(sockfd, (struct sockaddr*)&sockaddr, (socklen_t)sizeof(sockaddr)) == -1 && errno != EINPROGRESS) {
-    throw new DlAbortEx(strerror(errno));
-  }
+  core->establishConnection(host, port);
 }
 
 void Socket::setNonBlockingMode() {
-  int flags = fcntl(sockfd, F_GETFL, 0);
-  fcntl(sockfd, F_SETFL, flags&~O_NONBLOCK);
+  core->setNonBlockingMode();
 }
 
 void Socket::closeConnection() {
-  if(sockfd != -1) {
-    close(sockfd);
-    sockfd = -1;
-  }
+  core->closeConnection();
 }
 
 bool Socket::isWritable(int timeout) {
-  fd_set fds;
-  FD_ZERO(&fds);
-  FD_SET(sockfd, &fds);
-
-  struct timeval tv;
-  tv.tv_sec = timeout;
-  tv.tv_usec = 0;
-
-  int r = select(sockfd+1, NULL, &fds, NULL, &tv);
-  if(r == 1) {
-    return true;
-  } else if(r == 0) {
-    // time out
-    return false;
-  } else {
-    throw new DlRetryEx(strerror(errno));
-  }
+  return core->isWritable(timeout);
 }
 
 bool Socket::isReadable(int timeout) {
-  fd_set fds;
-  FD_ZERO(&fds);
-  FD_SET(sockfd, &fds);
-
-  struct timeval tv;
-  tv.tv_sec = timeout;
-  tv.tv_usec = 0;
-
-  int r = select(sockfd+1, &fds, NULL, NULL, &tv);
-  if(r == 1) {
-    return true;
-  } else if(r == 0) {
-    // time out
-    return false;
-  } else {
-    throw new DlRetryEx(strerror(errno));
-  }
+  return core->isReadable(timeout);
 }
 
 void Socket::writeData(const char* data, int len, int timeout) {
-  if(!isWritable(timeout) || send(sockfd, data, (size_t)len, 0) != len) {
-    throw new DlRetryEx(strerror(errno));
-  }
+  core->writeData(data, len, timeout);
 }
 
 void Socket::readData(char* data, int& len, int timeout) {
-  if(!isReadable(timeout) || (len = recv(sockfd, data, (size_t)len, 0)) < 0) {
-    throw new DlRetryEx(strerror(errno));
-  }
+  core->readData(data, len, timeout);
 }
 
 void Socket::peekData(char* data, int& len, int timeout) {
-  if(!isReadable(timeout) || (len = recv(sockfd, data, (size_t)len, MSG_PEEK)) < 0) {
-    throw new DlRetryEx(strerror(errno));
-  }
+  core->peekData(data, len, timeout);
 }

+ 5 - 2
src/Socket.h

@@ -23,13 +23,14 @@
 #define _D_SOCKET_H_
 
 #include <string>
+#include "SocketCore.h"
 
 using namespace std;
 
 class Socket {
-public:
+private:
   // socket endpoint descriptor
-  int sockfd;
+  SocketCore* core;
 public:
   Socket();
   Socket(const Socket& s);
@@ -37,6 +38,8 @@ public:
 
   Socket& operator=(const Socket& s);
 
+  int getSockfd() const { return core->sockfd; }
+
   /**
    * Connects to the server named host and the destination port is port.
    * This method make socket non-blocking mode.

+ 152 - 0
src/SocketCore.cc

@@ -0,0 +1,152 @@
+/* <!-- copyright */
+/*
+ * aria2 - a simple utility for downloading files faster
+ *
+ * Copyright (C) 2006 Tatsuhiro Tsujikawa
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+/* copyright --> */
+#include "SocketCore.h"
+#include <unistd.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/time.h>
+#include <netdb.h>
+#include "DlRetryEx.h"
+#include "DlAbortEx.h"
+#include <errno.h>
+
+SocketCore::SocketCore():sockfd(-1), use(1) {}
+
+SocketCore::~SocketCore() {
+  closeConnection();
+}
+
+void SocketCore::establishConnection(string host, int port) {
+  sockfd = socket(AF_INET, SOCK_STREAM, 0);
+  if(sockfd >= 0) {
+    socklen_t sockopt = 1;
+    if(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof(int)) < 0) {
+      close(sockfd);
+      sockfd = -1;
+      throw new DlAbortEx(strerror(errno));
+    }
+  } else {
+      throw new DlAbortEx(strerror(errno));
+  }
+
+  struct sockaddr_in sockaddr;
+  memset((char*)&sockaddr, 0, sizeof(sockaddr));
+  sockaddr.sin_family = AF_INET;
+  sockaddr.sin_port = htons(port);
+  if(inet_aton(host.c_str(), &sockaddr.sin_addr)) {
+    // ok
+  } else {
+    struct addrinfo ai;
+    ai.ai_flags = 0;
+    ai.ai_family = PF_INET;
+    ai.ai_socktype = SOCK_STREAM;
+    ai.ai_protocol = 0; 
+    ai.ai_addr = (struct sockaddr*)&sockaddr;
+    struct addrinfo* res;
+    int ec;
+    if((ec = getaddrinfo(host.c_str(), NULL, &ai, &res)) != 0) {
+      throw new DlAbortEx(gai_strerror(ec));
+    }
+    sockaddr.sin_addr = ((struct sockaddr_in*)res->ai_addr)->sin_addr;
+    freeaddrinfo(res);
+  }
+  // make socket non-blocking mode
+  int flags = fcntl(sockfd, F_GETFL, 0);
+  fcntl(sockfd, F_SETFL, flags|O_NONBLOCK);
+  if(connect(sockfd, (struct sockaddr*)&sockaddr, (socklen_t)sizeof(sockaddr)) == -1 && errno != EINPROGRESS) {
+    throw new DlAbortEx(strerror(errno));
+  }
+}
+
+void SocketCore::setNonBlockingMode() {
+  int flags = fcntl(sockfd, F_GETFL, 0);
+  fcntl(sockfd, F_SETFL, flags&~O_NONBLOCK);
+}
+
+void SocketCore::closeConnection() {
+  if(sockfd != -1) {
+    close(sockfd);
+    sockfd = -1;
+  }
+}
+
+bool SocketCore::isWritable(int timeout) {
+  fd_set fds;
+  FD_ZERO(&fds);
+  FD_SET(sockfd, &fds);
+
+  struct timeval tv;
+  tv.tv_sec = timeout;
+  tv.tv_usec = 0;
+
+  int r = select(sockfd+1, NULL, &fds, NULL, &tv);
+  if(r == 1) {
+    return true;
+  } else if(r == 0) {
+    // time out
+    return false;
+  } else {
+    throw new DlRetryEx(strerror(errno));
+  }
+}
+
+bool SocketCore::isReadable(int timeout) {
+  fd_set fds;
+  FD_ZERO(&fds);
+  FD_SET(sockfd, &fds);
+
+  struct timeval tv;
+  tv.tv_sec = timeout;
+  tv.tv_usec = 0;
+
+  int r = select(sockfd+1, &fds, NULL, NULL, &tv);
+  if(r == 1) {
+    return true;
+  } else if(r == 0) {
+    // time out
+    return false;
+  } else {
+    throw new DlRetryEx(strerror(errno));
+  }
+}
+
+void SocketCore::writeData(const char* data, int len, int timeout) {
+  if(!isWritable(timeout) || send(sockfd, data, (size_t)len, 0) != len) {
+    throw new DlRetryEx(strerror(errno));
+  }
+}
+
+void SocketCore::readData(char* data, int& len, int timeout) {
+  if(!isReadable(timeout) || (len = recv(sockfd, data, (size_t)len, 0)) < 0) {
+    throw new DlRetryEx(strerror(errno));
+  }
+}
+
+void SocketCore::peekData(char* data, int& len, int timeout) {
+  if(!isReadable(timeout) || (len = recv(sockfd, data, (size_t)len, MSG_PEEK)) < 0) {
+    throw new DlRetryEx(strerror(errno));
+  }
+}

+ 76 - 0
src/SocketCore.h

@@ -0,0 +1,76 @@
+/* <!-- copyright */
+/*
+ * aria2 - a simple utility for downloading files faster
+ *
+ * Copyright (C) 2006 Tatsuhiro Tsujikawa
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+/* copyright --> */
+#ifndef _D_SOCKET_CORE_H_
+#define _D_SOCKET_CORE_H_
+
+#include <string>
+
+using namespace std;
+
+class SocketCore {
+  friend class Socket;
+private:
+  // socket endpoint descriptor
+  int sockfd;
+  // reference counter for this object.
+  int use;
+public:
+  SocketCore();
+  ~SocketCore();
+
+  /**
+   * Connects to the server named host and the destination port is port.
+   * This method make socket non-blocking mode.
+   * To make the socket blocking mode, call setNonBlockingMode() after
+   * the connection is established.
+   */
+  void establishConnection(string host, int port);
+
+  void setNonBlockingMode();
+
+  // Closes the connection which this socket object has
+  void closeConnection();
+
+  // examines whether the socket of this SocketCore object is available for writing.
+  // returns true if the socket is available for writing, otherwise returns false.
+  bool isWritable(int timeout);
+
+  // examines whether the socket of this SocketCore object is available for reading.
+  // returns true if the socket is available for reading, otherwise returns false.
+  bool isReadable(int timeout);
+
+  // writes characters into the socket. data is a pointer pointing the first
+  // byte of the data and len is the length of the data.
+  void writeData(const char* data, int len, int timeout = 5);
+
+  // Reads up to len bytes from this socket.
+  // data is a pointer pointing the first
+  // byte of the data, which must be allocated before this method is called.
+  // len is the size of the allocated memory. When this method returns
+  // successfully, len is replaced by the size of the read data.
+  void readData(char* data, int& len, int timeout = 5);
+  // Reads up to len bytes from this socket, but bytes are not removed from
+  // this socket.
+  void peekData(char* data, int& len, int timeout = 5);
+};
+
+#endif // _D_SOCKET_CORE_H_