summaryrefslogtreecommitdiff
path: root/src/SocketCore.cc
diff options
context:
space:
mode:
authorTatsuhiro Tsujikawa <tatsuhiro.t@gmail.com>2007-07-31 16:45:16 +0000
committerTatsuhiro Tsujikawa <tatsuhiro.t@gmail.com>2007-07-31 16:45:16 +0000
commit46e8c332cd63e52ccbd9ac3c895de4b59b9ac2f3 (patch)
tree5eec8e6966c14ed576e75e9a7475e4a62abed55f /src/SocketCore.cc
parent8ca716529def7314cce645db24cd8927de6bff84 (diff)
2007-08-01 Tatsuhiro Tsujikawa <tujikawa at rednoah dot com>
Make a2netcompat.h include a2io.h to fix compilation error: * src/a2netcompat.h * src/SocketCore.cc: Removed include of a2io.h * src/Util.cc: Removed include of a2io.h Gather time related functions to a2time.h: * src/a2time.h: New file. * src/DefaultPeerStorage.cc * src/SimpleLogger.cc * src/Util.{h, cc} * src/SimpleRandomizer.h * src/TimeA2.{h,cc} * src/DownloadCommand.cc * src/main.cc Removed #ifdef __MINGW32__ since gai_strerror is included in a2netcompat.h: * src/NameResolver.cc Fixed compilation error without openssl: * src/SocketCore.{h,cc}: Moved include of openssl/err.h to SocketCore.h Added default block to suppress compiler warnings: * src/MetalinkRequestInfo.cc (AccumulateNonP2PUrl::operator()) 2007-07-26 Ross Smith II <aria2spam at smithii dot com> MinGW build enhancements. The following files are added: * src/gai_strerror.{c,h} * src/gettimeofday.{c,h} Changes to support the above new files: * configure.ac * src/Makefile.am * src/a2netcompat.h * src/TimeA2.cc * src/DefaultPeerStorage.cc * src/NameResolver.cc: removed mingw_strerror() function. * src/SocketCore.cc: removed mingw_strerror() function. Miscellaneous MinGW build fixes. * src/a2io.h: Use _lseeki64() instead of lseek() * src/common.h * src/DefaultFileAllocator.cc * src/GlowFileAllocator.cc * src/main.cc: Moved #include "prefs.h" to quiet compile error. * src/NameResolver.cc (callback): Changed int32_t to int. (resolve): Changed int32_t to int. * src/Platform.cc * src/Platform.h * test/MultiDiskWriterTest.cc * test/PeerMessageUtilTest.cc * src/localtime_r.c: Add DeleteCriticalSection() and at exit(). Other enhancements and fixes. * src/HttpRequestCommand.cc (executeInternal) Use non-blocking socket for HTTPS (MinGW only). * src/SocketCore.cc: (error): New function to abstract errno/WSAGetLastError(). (errorMsg): New function to abstract errno/WSAGetLastError(). (initiateSecureConnection): Added more detailed error reporting. * src/SocketCore.h: Added private variable blocking, to allow proper handling of OpenSSL psuedo-errors. * src/message.h (EX_SSL_INIT_FAILURE) (EX_SSL_IO_ERROR) (EX_SSL_PROTOCOL_ERROR) (EX_SSL_UNKNOWN_ERROR) (EX_SSL_CONNECT_ERROR) (EX_SOCKET_BLOCKING) (EX_SOCKET_NONBLOCKING) (EX_SOCKET_UNKNOWN_ERROR) * src/Util.cc (setGlobalSignalHandler): Renamed signal to sig as signal is a reserved name. (httpGMT): Fixed typo.
Diffstat (limited to 'src/SocketCore.cc')
-rw-r--r--src/SocketCore.cc230
1 files changed, 135 insertions, 95 deletions
diff --git a/src/SocketCore.cc b/src/SocketCore.cc
index 4cbfef21..b71e6111 100644
--- a/src/SocketCore.cc
+++ b/src/SocketCore.cc
@@ -36,36 +36,16 @@
#include "DlRetryEx.h"
#include "DlAbortEx.h"
#include "message.h"
-#include "a2io.h"
#include "a2netcompat.h"
+#include "a2time.h"
#include <unistd.h>
#include <fcntl.h>
-#include <sys/time.h>
#include <errno.h>
-#ifdef __MINGW32__
-
-static char *mingw_strerror(int err) {
- err = WSAGetLastError();
- static char buf[2048];
- if (FormatMessage(
- FORMAT_MESSAGE_FROM_SYSTEM |
- FORMAT_MESSAGE_IGNORE_INSERTS,
- NULL,
- err,
- MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
- (LPTSTR) &buf,
- sizeof(buf),
- NULL
- ) == 0) {
- snprintf(buf, sizeof(buf), _("Unknown socket error %d"), err);
- }
- return buf;
-}
-
-#define strerror mingw_strerror
-#define gai_strerror mingw_strerror
-
+#ifndef __MINGW32__
+# define SOCKET_ERRNO (errno)
+#else
+# define SOCKET_ERRNO (WSAGetLastError())
#endif // __MINGW32__
SocketCore::SocketCore():sockfd(-1) {
@@ -78,6 +58,7 @@ SocketCore::SocketCore(int32_t sockfd):sockfd(sockfd) {
void SocketCore::init() {
use = 1;
+ blocking = true;
secure = false;
#ifdef HAVE_LIBSSL
// for SSL
@@ -105,13 +86,17 @@ void SocketCore::beginListen(int32_t port) {
//sockfd = socket(AF_UNSPEC, SOCK_STREAM, PF_UNSPEC);
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd == -1) {
- throw new DlAbortEx(EX_SOCKET_OPEN, strerror(errno));
+ throw new DlAbortEx(EX_SOCKET_OPEN, errorMsg());
}
SOCKOPT_T sockopt = 1;
if(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof(socklen_t)) < 0) {
+#ifdef __MINGW32__
+ ::closesocket(sockfd);
+#else
close(sockfd);
+#endif // __MINGW32__
sockfd = -1;
- throw new DlAbortEx(EX_SOCKET_SET_OPT, strerror(errno));
+ throw new DlAbortEx(EX_SOCKET_SET_OPT, errorMsg());
}
struct sockaddr_in sockaddr;
@@ -121,11 +106,11 @@ void SocketCore::beginListen(int32_t port) {
sockaddr.sin_port = htons(port);
if(bind(sockfd, (struct sockaddr*)&sockaddr, sizeof(sockaddr)) == -1) {
- throw new DlAbortEx(EX_SOCKET_BIND, strerror(errno));
+ throw new DlAbortEx(EX_SOCKET_BIND, errorMsg());
}
if(listen(sockfd, 1) == -1) {
- throw new DlAbortEx(EX_SOCKET_LISTEN, strerror(errno));
+ throw new DlAbortEx(EX_SOCKET_LISTEN, errorMsg());
}
setNonBlockingMode();
@@ -137,7 +122,7 @@ SocketCore* SocketCore::acceptConnection() const {
memset((char*)&sockaddr, 0, sizeof(sockaddr));
int32_t fd;
if((fd = accept(sockfd, (struct sockaddr*)&sockaddr, &len)) == -1) {
- throw new DlAbortEx(EX_SOCKET_ACCEPT, strerror(errno));
+ throw new DlAbortEx(EX_SOCKET_ACCEPT, errorMsg());
}
SocketCore* s = new SocketCore(fd);
@@ -149,7 +134,7 @@ void SocketCore::getAddrInfo(pair<string, int32_t>& addrinfo) const {
memset((char*)&listenaddr, 0, sizeof(listenaddr));
socklen_t len = sizeof(listenaddr);
if(getsockname(sockfd, (struct sockaddr*)&listenaddr, &len) == -1) {
- throw new DlAbortEx(EX_SOCKET_GET_NAME, strerror(errno));
+ throw new DlAbortEx(EX_SOCKET_GET_NAME, errorMsg());
}
addrinfo.first = inet_ntoa(listenaddr.sin_addr);
addrinfo.second = ntohs(listenaddr.sin_port);
@@ -160,7 +145,7 @@ void SocketCore::getPeerInfo(pair<string, int32_t>& peerinfo) const {
memset(&peerin, 0, sizeof(peerin));
int32_t len = sizeof(peerin);
if(getpeername(sockfd, (struct sockaddr*)&peerin, (socklen_t*)&len) < 0) {
- throw new DlAbortEx(EX_SOCKET_GET_PEER, strerror(errno));
+ throw new DlAbortEx(EX_SOCKET_GET_PEER, errorMsg());
}
peerinfo.first = inet_ntoa(peerin.sin_addr);
peerinfo.second = ntohs(peerin.sin_port);
@@ -170,13 +155,13 @@ void SocketCore::establishConnection(const string& host, int32_t port) {
closeConnection();
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd == -1) {
- throw new DlAbortEx(EX_SOCKET_OPEN, strerror(errno));
+ throw new DlAbortEx(EX_SOCKET_OPEN, errorMsg());
}
SOCKOPT_T sockopt = 1;
if(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof(socklen_t)) < 0) {
close(sockfd);
sockfd = -1;
- throw new DlAbortEx(EX_SOCKET_SET_OPT, strerror(errno));
+ throw new DlAbortEx(EX_SOCKET_SET_OPT, errorMsg());
}
struct sockaddr_in sockaddr;
@@ -203,23 +188,27 @@ void SocketCore::establishConnection(const string& host, int32_t port) {
}
// make socket non-blocking mode
setNonBlockingMode();
- if(connect(sockfd, (struct sockaddr*)&sockaddr, (socklen_t)sizeof(sockaddr)) == -1 && errno != EINPROGRESS) {
- throw new DlAbortEx(EX_SOCKET_CONNECT, host.c_str(), strerror(errno));
+ if(connect(sockfd, (struct sockaddr*)&sockaddr, (socklen_t)sizeof(sockaddr)) == -1 && SOCKET_ERRNO != EINPROGRESS) {
+ throw new DlAbortEx(EX_SOCKET_CONNECT, host.c_str(), errorMsg());
}
}
-void SocketCore::setNonBlockingMode() const {
+void SocketCore::setNonBlockingMode() {
#ifdef __MINGW32__
u_long flag = 0;
::ioctlsocket(sockfd, FIONBIO, &flag);
+ if (WSAGetLastError()) {
+ throw new DlAbortEx(EX_SOCKET_NONBLOCKING, errorMsg());
+ }
#else
int32_t flags = fcntl(sockfd, F_GETFL, 0);
// TODO add error handling
fcntl(sockfd, F_SETFL, flags|O_NONBLOCK);
#endif // __MINGW32__
+ blocking = false;
}
-void SocketCore::setBlockingMode() const {
+void SocketCore::setBlockingMode() {
#ifdef __MINGW32__
u_long flag = 1;
::ioctlsocket(sockfd, FIONBIO, &flag);
@@ -228,6 +217,7 @@ void SocketCore::setBlockingMode() const {
// TODO add error handling
fcntl(sockfd, F_SETFL, flags&(~O_NONBLOCK));
#endif // __MINGW32__
+ blocking = true;
}
void SocketCore::closeConnection() {
@@ -243,7 +233,11 @@ void SocketCore::closeConnection() {
}
#endif // HAVE_LIBGNUTLS
if(sockfd != -1) {
+#ifdef __MINGW32__
+ ::closesocket(sockfd);
+#else
close(sockfd);
+#endif // __MINGW32__
sockfd = -1;
}
#ifdef HAVE_LIBSSL
@@ -277,10 +271,10 @@ bool SocketCore::isWritable(int32_t timeout) const {
// time out
return false;
} else {
- if(errno == EINPROGRESS || errno == EINTR) {
+ if(SOCKET_ERRNO == EINPROGRESS || SOCKET_ERRNO == EINTR) {
return false;
} else {
- throw new DlRetryEx(EX_SOCKET_CHECK_WRITABLE, strerror(errno));
+ throw new DlRetryEx(EX_SOCKET_CHECK_WRITABLE, errorMsg());
}
}
}
@@ -306,91 +300,84 @@ bool SocketCore::isReadable(int32_t timeout) const {
// time out
return false;
} else {
- if(errno == EINPROGRESS || errno == EINTR) {
+ if(SOCKET_ERRNO == EINPROGRESS || SOCKET_ERRNO == EINTR) {
return false;
} else {
- throw new DlRetryEx(EX_SOCKET_CHECK_READABLE, strerror(errno));
+ throw new DlRetryEx(EX_SOCKET_CHECK_READABLE, errorMsg());
}
}
}
void SocketCore::writeData(const char* data, int32_t len) {
int32_t ret = 0;
- if(!secure && (ret = send(sockfd, data, (size_t)len, 0)) != len
+
+ if(!secure) {
+ if((ret = send(sockfd, data, (size_t)len, 0)) != len) {
+ throw new DlRetryEx(EX_SOCKET_SEND, errorMsg());
+ }
+ } else {
#ifdef HAVE_LIBSSL
// for SSL
// TODO handling len == 0 case required
- || secure && (ret = SSL_write(ssl, data, len)) != len
+ if((ret = SSL_write(ssl, data, len)) != len) {
+ throw new DlRetryEx(EX_SOCKET_SEND, ERR_error_string(ERR_get_error(), NULL));
+ }
#endif // HAVE_LIBSSL
#ifdef HAVE_LIBGNUTLS
- || secure && (ret = gnutls_record_send(sslSession, data, len)) != len
-#endif // HAVE_LIBGNUTLS
- ) {
- const char* errorMsg;
-#ifdef HAVE_LIBGNUTLS
- if(secure) {
- errorMsg = gnutls_strerror(ret);
- } else {
- errorMsg = strerror(errno);
+ if((ret = gnutls_record_send(sslSession, data, len)) == len) {
+ throw new DlRetryEx(EX_SOCKET_SEND, gnutls_strerror(ret));
}
-#else // HAVE_LIBGNUTLS
- errorMsg = strerror(errno);
-#endif
- throw new DlRetryEx(EX_SOCKET_SEND, errorMsg);
+#endif // HAVE_LIBGNUTLS
}
}
void SocketCore::readData(char* data, int32_t& len) {
int32_t ret = 0;
- if(!secure && (ret = recv(sockfd, data, (size_t)len, 0)) < 0
+
+ if(!secure) {
+ if ((ret = recv(sockfd, data, (size_t)len, 0)) < 0) {
+ throw new DlRetryEx(EX_SOCKET_RECV, errorMsg());
+ }
+ } else {
#ifdef HAVE_LIBSSL
// for SSL
// TODO handling len == 0 case required
- || secure && (ret = SSL_read(ssl, data, len)) < 0
+ if ((ret = SSL_read(ssl, data, len)) < 0) {
+ throw new DlRetryEx(EX_SOCKET_RECV, ERR_error_string(ERR_get_error(), NULL));
+ }
#endif // HAVE_LIBSSL
#ifdef HAVE_LIBGNUTLS
- || secure && (ret = gnutlsRecv(data, len)) < 0
-#endif // HAVE_LIBGNUTLS
- ) {
- const char* errorMsg;
-#ifdef HAVE_LIBGNUTLS
- if(secure) {
- errorMsg = gnutls_strerror(ret);
- } else {
- errorMsg = strerror(errno);
+ if ((ret = gnutlsRecv(data, len)) < 0) {
+ throw new DlRetryEx(EX_SOCKET_RECV, gnutls_strerror(ret));
}
-#else // HAVE_LIBGNUTLS
- errorMsg = strerror(errno);
-#endif
- throw new DlRetryEx(EX_SOCKET_RECV, errorMsg);
+#endif // HAVE_LIBGNUTLS
}
+
len = ret;
}
void SocketCore::peekData(char* data, int32_t& len) {
int32_t ret = 0;
- if(!secure && (ret = recv(sockfd, data, (size_t)len, MSG_PEEK)) < 0
+
+ if(!secure) {
+ if ((ret = recv(sockfd, data, (size_t)len, MSG_PEEK)) < 0) {
+ throw new DlRetryEx(EX_SOCKET_PEEK, errorMsg());
+ }
+ } else {
#ifdef HAVE_LIBSSL
// for SSL
// TODO handling len == 0 case required
- || secure && (ret = SSL_peek(ssl, data, len)) < 0
+ if ((ret = SSL_peek(ssl, data, len)) < 0) {
+ throw new DlRetryEx(EX_SOCKET_PEEK, ERR_error_string(ERR_get_error(), NULL));
+ }
#endif // HAVE_LIBSSL
#ifdef HAVE_LIBGNUTLS
- || secure && (ret = gnutlsPeek(data, len)) < 0
-#endif // HAVE_LIBGNUTLS
- ) {
- const char* errorMsg;
-#ifdef HAVE_LIBGNUTLS
- if(secure) {
- errorMsg = gnutls_strerror(ret);
- } else {
- errorMsg = strerror(errno);
+ if ((ret = gnutlsPeek(data, len)) < 0) {
+ throw new DlRetryEx(EX_SOCKET_PEEK, gnutls_strerror(ret));
}
-#else // HAVE_LIBGNUTLS
- errorMsg = strerror(errno);
-#endif
- throw new DlRetryEx(EX_SOCKET_PEEK, errorMsg);
+#endif // HAVE_LIBGNUTLS
}
+
len = ret;
}
@@ -460,21 +447,44 @@ void SocketCore::initiateSecureConnection() {
if(!secure) {
sslCtx = SSL_CTX_new(SSLv23_client_method());
if(sslCtx == NULL) {
- throw new DlAbortEx(EX_SSL_INIT_FAILURE);
+ throw new DlAbortEx(EX_SSL_INIT_FAILURE, ERR_error_string(ERR_get_error(), NULL));
}
SSL_CTX_set_mode(sslCtx, SSL_MODE_AUTO_RETRY);
ssl = SSL_new(sslCtx);
if(ssl == NULL) {
- throw new DlAbortEx(EX_SSL_INIT_FAILURE);
+ throw new DlAbortEx(EX_SSL_INIT_FAILURE, ERR_error_string(ERR_get_error(), NULL));
}
if(SSL_set_fd(ssl, sockfd) == 0) {
- throw new DlAbortEx(EX_SSL_INIT_FAILURE);
+ throw new DlAbortEx(EX_SSL_INIT_FAILURE, ERR_error_string(ERR_get_error(), NULL));
}
// TODO handling return value == 0 case required
- if(SSL_connect(ssl) <= 0) {
- throw new DlAbortEx(EX_SSL_INIT_FAILURE);
+ int e = SSL_connect(ssl);
+
+ if (e <= 0) {
+ int ssl_error = SSL_get_error(ssl, e);
+ switch(ssl_error) {
+ case SSL_ERROR_NONE:
+ break;
+
+ case SSL_ERROR_WANT_READ:
+ case SSL_ERROR_WANT_WRITE:
+ case SSL_ERROR_WANT_X509_LOOKUP:
+ case SSL_ERROR_ZERO_RETURN:
+ if (blocking) {
+ throw new DlAbortEx(EX_SSL_CONNECT_ERROR, ssl_error);
+ }
+ break;
+
+ case SSL_ERROR_SYSCALL:
+ throw new DlAbortEx(EX_SSL_IO_ERROR);
+
+ case SSL_ERROR_SSL:
+ throw new DlAbortEx(EX_SSL_PROTOCOL_ERROR);
+
+ default:
+ throw new DlAbortEx(EX_SSL_UNKNOWN_ERROR, ssl_error);
+ }
}
- secure = true;
}
#endif // HAVE_LIBSSL
#ifdef HAVE_LIBGNUTLS
@@ -493,9 +503,39 @@ void SocketCore::initiateSecureConnection() {
gnutls_transport_set_ptr(sslSession, (gnutls_transport_ptr_t)sockfd);
int32_t ret = gnutls_handshake(sslSession);
if(ret < 0) {
- throw new DlAbortEx(gnutls_strerror(ret));
+ throw new DlAbortEx(EX_SSL_INIT_FAILURE, gnutls_strerror(ret));
}
- secure = true;
}
#endif // HAVE_LIBGNUTLS
+
+ secure = true;
+}
+
+/* static */ int SocketCore::error() {
+ return SOCKET_ERRNO;
+}
+
+/* static */ const char *SocketCore::errorMsg() {
+ return errorMsg(SOCKET_ERRNO);
+}
+
+/* static */ const char *SocketCore::errorMsg(const int err) {
+#ifndef __MINGW32__
+ return strerror(err);
+#else
+ static char buf[256];
+ if (FormatMessage(
+ FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL,
+ err,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
+ (LPTSTR) &buf,
+ sizeof(buf),
+ NULL
+ ) == 0) {
+ snprintf(buf, sizeof(buf), EX_SOCKET_UNKNOWN_ERROR, err, err);
+ }
+ return buf;
+#endif // __MINGW32__
}