Added SocketCore, make Socket a handle class for SocketCore.

pull/1/head
Tatsuhiro Tsujikawa 2006-02-17 14:47:45 +00:00
parent 52634627bc
commit 8acb1181f9
7 changed files with 280 additions and 113 deletions

View File

@ -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;

View File

@ -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\

View File

@ -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

View File

@ -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);
}

View File

@ -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
src/SocketCore.cc Normal file
View File

@ -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
src/SocketCore.h Normal file
View File

@ -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_