diff --git a/src/DownloadEngine.cc b/src/DownloadEngine.cc index 2748e153..0621e66b 100644 --- a/src/DownloadEngine.cc +++ b/src/DownloadEngine.cc @@ -104,15 +104,15 @@ void DownloadEngine::waitData() { FD_ZERO(&wfds); int max = 0; for(vector::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::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; diff --git a/src/Makefile.am b/src/Makefile.am index ff8cb4ef..6b5994ea 100644 --- a/src/Makefile.am +++ b/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\ diff --git a/src/Makefile.in b/src/Makefile.in index 76809092..006717df 100644 --- a/src/Makefile.in +++ b/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 diff --git a/src/Socket.cc b/src/Socket.cc index 292efc51..f14fc296 100644 --- a/src/Socket.cc +++ b/src/Socket.cc @@ -20,145 +20,63 @@ */ /* copyright --> */ #include "Socket.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "DlRetryEx.h" -#include "DlAbortEx.h" -#include -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); } diff --git a/src/Socket.h b/src/Socket.h index 3f38a343..e6254f17 100644 --- a/src/Socket.h +++ b/src/Socket.h @@ -23,13 +23,14 @@ #define _D_SOCKET_H_ #include +#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. diff --git a/src/SocketCore.cc b/src/SocketCore.cc new file mode 100644 index 00000000..e89e1d53 --- /dev/null +++ b/src/SocketCore.cc @@ -0,0 +1,152 @@ +/* */ +#include "SocketCore.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "DlRetryEx.h" +#include "DlAbortEx.h" +#include + +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)); + } +} diff --git a/src/SocketCore.h b/src/SocketCore.h new file mode 100644 index 00000000..2c4cd185 --- /dev/null +++ b/src/SocketCore.h @@ -0,0 +1,76 @@ +/* */ +#ifndef _D_SOCKET_CORE_H_ +#define _D_SOCKET_CORE_H_ + +#include + +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_