Просмотр исходного кода

2010-11-09 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net>

	Capture errno right after system/library call to avoid it to get
	overwritten. Use util::safeStrerror instead of strerror directly
	because strerror might return NULL. We don't check errno for
	std::fstream anymore.
	* src/AbstractDiskWriter.cc
	* src/CookieStorage.cc
	* src/DHTAutoSaveCommand.cc
	* src/DHTRoutingTableDeserializer.cc
	* src/DHTRoutingTableSerializer.cc
	* src/DefaultBtProgressInfoFile.cc
	* src/EpollEventPoll.cc
	* src/IteratableChunkChecksumValidator.cc
	* src/KqueueEventPoll.cc
	* src/Logger.cc
	* src/MessageDigestHelper.cc
	* src/PortEventPoll.cc
	* src/SelectEventPoll.cc
	* src/SocketCore.cc
	* src/message.h
	* src/util.cc
	* src/util.h
Tatsuhiro Tsujikawa 15 лет назад
Родитель
Сommit
228b4c50d7

+ 24 - 0
ChangeLog

@@ -1,3 +1,27 @@
+2010-11-09  Tatsuhiro Tsujikawa  <t-tujikawa@users.sourceforge.net>
+
+	Capture errno right after system/library call to avoid it to get
+	overwritten. Use util::safeStrerror instead of strerror directly
+	because strerror might return NULL. We don't check errno for
+	std::fstream anymore.
+	* src/AbstractDiskWriter.cc
+	* src/CookieStorage.cc
+	* src/DHTAutoSaveCommand.cc
+	* src/DHTRoutingTableDeserializer.cc
+	* src/DHTRoutingTableSerializer.cc
+	* src/DefaultBtProgressInfoFile.cc
+	* src/EpollEventPoll.cc
+	* src/IteratableChunkChecksumValidator.cc
+	* src/KqueueEventPoll.cc
+	* src/Logger.cc
+	* src/MessageDigestHelper.cc
+	* src/PortEventPoll.cc
+	* src/SelectEventPoll.cc
+	* src/SocketCore.cc
+	* src/message.h
+	* src/util.cc
+	* src/util.h
+
 2010-11-07  Tatsuhiro Tsujikawa  <t-tujikawa@users.sourceforge.net>
 
 	Use const reference

+ 34 - 15
src/AbstractDiskWriter.cc

@@ -99,10 +99,12 @@ void AbstractDiskWriter::openExistingFile(uint64_t totalLength)
   }
 
   if((fd_ = open(filename_.c_str(), flags, OPEN_MODE)) < 0) {
+    int errNum = errno;
     throw DL_ABORT_EX2
-      (errno,
-       StringFormat
-       (EX_FILE_OPEN, filename_.c_str(), strerror(errno)).str());
+      (errNum,
+       StringFormat(EX_FILE_OPEN,
+                    filename_.c_str(),
+                    util::safeStrerror(errNum).c_str()).str());
   }
 }
 
@@ -112,9 +114,12 @@ void AbstractDiskWriter::createFile(int addFlags)
   util::mkdirs(File(filename_).getDirname());
   if((fd_ = open(filename_.c_str(), O_CREAT|O_RDWR|O_TRUNC|O_BINARY|addFlags,
                 OPEN_MODE)) < 0) {
+    int errNum = errno;
     throw DL_ABORT_EX2
-      (errno,
-       StringFormat(EX_FILE_OPEN, filename_.c_str(), strerror(errno)).str());
+      (errNum,
+       StringFormat(EX_FILE_OPEN,
+                    filename_.c_str(),
+                    util::safeStrerror(errNum).c_str()).str());
   }  
 }
 
@@ -142,8 +147,11 @@ ssize_t AbstractDiskWriter::readDataInternal(unsigned char* data, size_t len)
 void AbstractDiskWriter::seek(off_t offset)
 {
   if(a2lseek(fd_, offset, SEEK_SET) == (off_t)-1) {
+    int errNum = errno;
     throw DL_ABORT_EX
-      (StringFormat(EX_FILE_SEEK, filename_.c_str(), strerror(errno)).str());
+      (StringFormat(EX_FILE_SEEK,
+                    filename_.c_str(),
+                    util::safeStrerror(errNum).c_str()).str());
   }
 }
 
@@ -151,14 +159,20 @@ void AbstractDiskWriter::writeData(const unsigned char* data, size_t len, off_t
 {
   seek(offset);
   if(writeDataInternal(data, len) < 0) {
+    int errNum = errno;
     // If errno is ENOSPC(not enough space in device), throw
     // DownloadFailureException and abort download instantly.
-    if(errno == ENOSPC) {
+    if(errNum == ENOSPC) {
       throw DOWNLOAD_FAILURE_EXCEPTION
-        (StringFormat(EX_FILE_WRITE, filename_.c_str(), strerror(errno)).str());
+        (StringFormat(EX_FILE_WRITE,
+                      filename_.c_str(),
+                      util::safeStrerror(errNum).c_str()).str());
+    } else {
+      throw DL_ABORT_EX
+        (StringFormat(EX_FILE_WRITE,
+                      filename_.c_str(),
+                      util::safeStrerror(errNum).c_str()).str());
     }
-    throw DL_ABORT_EX(StringFormat(EX_FILE_WRITE,
-                                   filename_.c_str(), strerror(errno)).str());
   }
 }
 
@@ -167,8 +181,11 @@ ssize_t AbstractDiskWriter::readData(unsigned char* data, size_t len, off_t offs
   ssize_t ret;
   seek(offset);
   if((ret = readDataInternal(data, len)) < 0) {
-    throw DL_ABORT_EX(StringFormat(EX_FILE_READ,
-                                   filename_.c_str(), strerror(errno)).str());
+    int errNum = errno;
+    throw DL_ABORT_EX
+      (StringFormat(EX_FILE_READ,
+                    filename_.c_str(),
+                    util::safeStrerror(errNum).c_str()).str());
   }
   return ret;
 }
@@ -189,8 +206,9 @@ void AbstractDiskWriter::truncate(uint64_t length)
   }
 #else
   if(ftruncate(fd_, length) == -1) {
+    int errNum = errno;
     throw DL_ABORT_EX(StringFormat("ftruncate failed. cause: %s",
-                                   strerror(errno)).str());
+                                   util::safeStrerror(errNum).c_str()).str());
   }
 #endif
 }
@@ -205,15 +223,16 @@ void AbstractDiskWriter::allocate(off_t offset, uint64_t length)
   // For linux, we use fallocate to detect file system supports
   // fallocate or not.
   int r = fallocate(fd_, 0, offset, length);
+  int errNum = errno;
   if(r == -1) {
     throw DL_ABORT_EX(StringFormat("fallocate failed. cause: %s",
-                                   strerror(errno)).str());
+                                   util::safeStrerror(errNum).c_str()).str());
   }
 # elif HAVE_POSIX_FALLOCATE
   int r = posix_fallocate(fd_, offset, length);
   if(r != 0) {
     throw DL_ABORT_EX(StringFormat("posix_fallocate failed. cause: %s",
-                                   strerror(r)).str());
+                                   util::safeStrerror(r).c_str()).str());
   }
 # else
 #  error "no *_fallocate function available."

+ 2 - 4
src/CookieStorage.cc

@@ -343,8 +343,7 @@ bool CookieStorage::saveNsFormat(const std::string& filename)
   {
     std::ofstream o(tempfilename.c_str(), std::ios::binary);
     if(!o) {
-      logger_->error("Cannot create cookie file %s, cause %s",
-                     filename.c_str(), strerror(errno));
+      logger_->error("Cannot create cookie file %s", filename.c_str());
       return false;
     }
     for(std::deque<DomainEntry>::const_iterator i = domains_.begin(),
@@ -353,8 +352,7 @@ bool CookieStorage::saveNsFormat(const std::string& filename)
     }
     o.flush();
     if(!o) {
-      logger_->error("Failed to save cookies to %s, cause %s",
-                     filename.c_str(), strerror(errno));
+      logger_->error("Failed to save cookies to %s", filename.c_str());
       return false;
     }  
   }

+ 2 - 3
src/DHTAutoSaveCommand.cc

@@ -34,7 +34,6 @@
 /* copyright --> */
 #include "DHTAutoSaveCommand.h"
 
-#include <cerrno>
 #include <cstring>
 #include <fstream>
 
@@ -117,8 +116,8 @@ void DHTAutoSaveCommand::save()
                       std::ios::out|std::ios::binary);
       if(!o) {
         throw DL_ABORT_EX
-          (StringFormat("Failed to save DHT routing table to %s. cause:%s",
-                        dhtFile.c_str(), strerror(errno)).str());
+          (StringFormat("Failed to save DHT routing table to %s.",
+                        dhtFile.c_str()).str());
       }
       serializer.serialize(o);
     }

+ 1 - 4
src/DHTRoutingTableDeserializer.cc

@@ -34,7 +34,6 @@
 /* copyright --> */
 #include "DHTRoutingTableDeserializer.h"
 
-#include <cerrno>
 #include <cstring>
 #include <cassert>
 #include <istream>
@@ -73,9 +72,7 @@ void readBytes(unsigned char* buf, size_t buflen,
                     "Unexpected EOF").str());                           \
   }                                                                     \
   if(!in) {                                                             \
-    throw DL_ABORT_EX                                                   \
-      (StringFormat("Failed to load DHT routing table. cause:%s",       \
-                    strerror(errno)).str());                            \
+    throw DL_ABORT_EX("Failed to load DHT routing table.");             \
   }
 
 void DHTRoutingTableDeserializer::deserialize(std::istream& in)

+ 1 - 4
src/DHTRoutingTableSerializer.cc

@@ -34,7 +34,6 @@
 /* copyright --> */
 #include "DHTRoutingTableSerializer.h"
 
-#include <cerrno>
 #include <cstring>
 #include <ostream>
 
@@ -130,9 +129,7 @@ void DHTRoutingTableSerializer::serialize(std::ostream& o)
 
   o.flush();
   if(!o) {
-    throw DL_ABORT_EX
-      (StringFormat("Failed to save DHT routing table. cause:%s",
-                    strerror(errno)).str());
+    throw DL_ABORT_EX("Failed to save DHT routing table.");
   }
 }
 

+ 14 - 14
src/DefaultBtProgressInfoFile.cc

@@ -34,7 +34,6 @@
 /* copyright --> */
 #include "DefaultBtProgressInfoFile.h"
 
-#include <cerrno>
 #include <cstring>
 #include <fstream>
 
@@ -111,8 +110,8 @@ void DefaultBtProgressInfoFile::save()
   {
     std::ofstream o(filenameTemp.c_str(), std::ios::out|std::ios::binary);
     if(!o) {
-      throw DL_ABORT_EX(StringFormat(EX_SEGMENT_FILE_WRITE,
-                                     filename_.c_str(), strerror(errno)).str());
+      throw DL_ABORT_EX
+        (StringFormat(EX_SEGMENT_FILE_WRITE, filename_.c_str()).str());
     }
 #ifdef ENABLE_BITTORRENT
     bool torrentDownload = isTorrentDownload();
@@ -199,25 +198,26 @@ void DefaultBtProgressInfoFile::save()
     }
     o.flush();
     if(!o) {
-      throw DL_ABORT_EX(StringFormat(EX_SEGMENT_FILE_WRITE,
-                                     filename_.c_str(), strerror(errno)).str());
+      throw DL_ABORT_EX
+        (StringFormat(EX_SEGMENT_FILE_WRITE, filename_.c_str()).str());
     }
     logger_->info(MSG_SAVED_SEGMENT_FILE);
   }
   if(!File(filenameTemp).renameTo(filename_)) {
-    throw DL_ABORT_EX(StringFormat(EX_SEGMENT_FILE_WRITE,
-                                   filename_.c_str(), strerror(errno)).str());
+    throw DL_ABORT_EX
+      (StringFormat(EX_SEGMENT_FILE_WRITE, filename_.c_str()).str());
   }
 }
 
 #define CHECK_STREAM(in, length)                                        \
   if(in.gcount() != length) {                                           \
-    throw DL_ABORT_EX(StringFormat(EX_SEGMENT_FILE_READ,                \
-                                   filename_.c_str(),"Unexpected EOF").str()); \
+  throw DL_ABORT_EX(StringFormat("Failed to read segment file %s."      \
+                                 " Unexpected EOF.",                    \
+                                 filename_.c_str()).str());             \
   }                                                                     \
   if(!in) {                                                             \
-    throw DL_ABORT_EX(StringFormat(EX_SEGMENT_FILE_READ,                \
-                                   filename_.c_str(), strerror(errno)).str()); \
+    throw DL_ABORT_EX                                                   \
+      (StringFormat(EX_SEGMENT_FILE_READ, filename_.c_str()).str());    \
   }
 
 // It is assumed that integers are saved as:
@@ -227,9 +227,9 @@ void DefaultBtProgressInfoFile::load()
 {
   logger_->info(MSG_LOADING_SEGMENT_FILE, filename_.c_str());
   std::ifstream in(filename_.c_str(), std::ios::in|std::ios::binary);
-  if(!in) {                                                             \
-    throw DL_ABORT_EX(StringFormat(EX_SEGMENT_FILE_READ,                \
-                                   filename_.c_str(), strerror(errno)).str());
+  if(!in) {
+    throw DL_ABORT_EX
+      (StringFormat(EX_SEGMENT_FILE_READ, filename_.c_str()).str());
   }
   unsigned char versionBuf[2];
   in.read(reinterpret_cast<char*>(versionBuf), sizeof(versionBuf));

+ 14 - 4
src/EpollEventPoll.cc

@@ -34,6 +34,7 @@
 /* copyright --> */
 #include "EpollEventPoll.h"
 
+#include <cerrno>
 #include <cstring>
 #include <algorithm>
 #include <numeric>
@@ -41,6 +42,7 @@
 #include "Command.h"
 #include "LogFactory.h"
 #include "Logger.h"
+#include "util.h"
 
 namespace aria2 {
 
@@ -90,10 +92,11 @@ EpollEventPoll::~EpollEventPoll()
   if(epfd_ != -1) {
     int r;
     while((r = close(epfd_)) == -1 && errno == EINTR);
+    int errNum = errno;
     if(r == -1) {
       logger_->error("Error occurred while closing epoll file descriptor"
                      " %d: %s",
-                     epfd_, strerror(errno));
+                     epfd_, util::safeStrerror(errNum).c_str());
     }
   }
   delete [] epEvents_;
@@ -165,6 +168,7 @@ bool EpollEventPoll::addEvents(sock_t socket,
   std::deque<SharedHandle<KSocketEntry> >::iterator i =
     std::lower_bound(socketEntries_.begin(), socketEntries_.end(), socketEntry);
   int r = 0;
+  int errNum = 0;
   if(i != socketEntries_.end() && (*i) == socketEntry) {
 
     event.addSelf(*i);
@@ -178,6 +182,7 @@ bool EpollEventPoll::addEvents(sock_t socket,
 
       r = epoll_ctl(epfd_, EPOLL_CTL_ADD, (*i)->getSocket(),
                     &epEvent);
+      errNum = errno;
     }
   } else {
     socketEntries_.insert(i, socketEntry);
@@ -191,11 +196,12 @@ bool EpollEventPoll::addEvents(sock_t socket,
 
     struct epoll_event epEvent = socketEntry->getEvents();
     r = epoll_ctl(epfd_, EPOLL_CTL_ADD, socketEntry->getSocket(), &epEvent);
+    errNum = errno;
   }
   if(r == -1) {
     if(logger_->debug()) {
       logger_->debug("Failed to add socket event %d:%s",
-                     socket, strerror(errno));
+                     socket, util::safeStrerror(errNum).c_str());
     }
     return false;
   } else {
@@ -229,27 +235,31 @@ bool EpollEventPoll::deleteEvents(sock_t socket,
     event.removeSelf(*i);
 
     int r = 0;
+    int errNum = 0;
     if((*i)->eventEmpty()) {
       // In kernel before 2.6.9, epoll_ctl with EPOLL_CTL_DEL requires non-null
       // pointer of epoll_event.
       struct epoll_event ev = {0,{0}};
       r = epoll_ctl(epfd_, EPOLL_CTL_DEL, (*i)->getSocket(), &ev);
+      errNum = r;
       socketEntries_.erase(i);
     } else {
       // If socket is closed, then it seems it is automatically removed from
       // epoll, so following EPOLL_CTL_MOD may fail.
       struct epoll_event epEvent = (*i)->getEvents();
       r = epoll_ctl(epfd_, EPOLL_CTL_MOD, (*i)->getSocket(), &epEvent);
+      errNum = r;
       if(r == -1) {
         if(logger_->debug()) {
           logger_->debug("Failed to delete socket event, but may be ignored:%s",
-                         strerror(errno));
+                         util::safeStrerror(errNum).c_str());
         }
       }
     }
     if(r == -1) {
       if(logger_->debug()) {
-        logger_->debug("Failed to delete socket event:%s", strerror(errno));
+        logger_->debug("Failed to delete socket event:%s",
+                       util::safeStrerror(errNum).c_str());
       }
       return false;
     } else {

+ 1 - 2
src/IteratableChunkChecksumValidator.cc

@@ -34,7 +34,6 @@
 /* copyright --> */
 #include "IteratableChunkChecksumValidator.h"
 
-#include <cerrno>
 #include <cstring>
 #include <cstdlib>
 
@@ -161,7 +160,7 @@ std::string IteratableChunkChecksumValidator::digest(off_t offset, size_t length
     if(r == 0 || r < static_cast<size_t>(woffset)) {
       throw DL_ABORT_EX
         (StringFormat(EX_FILE_READ, dctx_->getBasePath().c_str(),
-                      strerror(errno)).str());
+                      "data is too short").str());
     }
     size_t wlength;
     if(max < static_cast<off_t>(curoffset+r)) {

+ 9 - 3
src/KqueueEventPoll.cc

@@ -34,6 +34,7 @@
 /* copyright --> */
 #include "KqueueEventPoll.h"
 
+#include <cerrno>
 #include <cstring>
 #include <algorithm>
 #include <numeric>
@@ -41,6 +42,7 @@
 #include "Command.h"
 #include "LogFactory.h"
 #include "Logger.h"
+#include "util.h"
 
 #ifdef KEVENT_UDATA_INTPTR_T
 # define PTR_TO_UDATA(X) (reinterpret_cast<intptr_t>(X))
@@ -96,10 +98,11 @@ KqueueEventPoll::~KqueueEventPoll()
   if(kqfd_ != -1) {
     int r;
     while((r = close(kqfd_)) == -1 && errno == EINTR);
+    int errNum = errno;
     if(r == -1) {
       logger_->error("Error occurred while closing kqueue file descriptor"
                      " %d: %s",
-                     kqfd_, strerror(errno));
+                     kqfd_, util::safeStrerror(errNum).c_str());
     }
   }
   delete [] kqEvents_;
@@ -186,10 +189,11 @@ bool KqueueEventPoll::addEvents
     n = socketEntry->getEvents(changelist);
   }
   r = kevent(kqfd_, changelist, n, changelist, 0, &zeroTimeout);
+  int errNum = errno;
   if(r == -1) {
     if(logger_->debug()) {
       logger_->debug("Failed to add socket event %d:%s",
-                     socket, strerror(errno));
+                     socket, util::safeStrerror(errNum).c_str());
     }
     return false;
   } else {
@@ -225,12 +229,14 @@ bool KqueueEventPoll::deleteEvents(sock_t socket,
     struct kevent changelist[2];
     size_t n = (*i)->getEvents(changelist);
     r = kevent(kqfd_, changelist, n, changelist, 0, &zeroTimeout);
+    int errNum = errno;
     if((*i)->eventEmpty()) {
       socketEntries_.erase(i);
     }
     if(r == -1) {
       if(logger_->debug()) {
-        logger_->debug("Failed to delete socket event:%s", strerror(errno));
+        logger_->debug("Failed to delete socket event:%s",
+                       util::safeStrerror(errNum).c_str());
       }
       return false;
     } else {

+ 1 - 2
src/Logger.cc

@@ -34,7 +34,6 @@
 /* copyright --> */
 #include "Logger.h"
 
-#include <cerrno>
 #include <cstring>
 
 #include "DlAbortEx.h"
@@ -68,7 +67,7 @@ void Logger::openFile(const std::string& filename)
   file_.open(filename.c_str(), std::ios::app|std::ios::binary);
   if(!file_) {
     throw DL_ABORT_EX
-      (StringFormat(EX_FILE_OPEN, filename.c_str(), strerror(errno)).str());
+      (StringFormat(EX_FILE_OPEN, filename.c_str(), "n/a").str());
   }
 }
 

+ 6 - 5
src/MessageDigestHelper.cc

@@ -33,15 +33,16 @@
  */
 /* copyright --> */
 #include "MessageDigestHelper.h"
+
+#include <cstring>
+#include <cstdlib>
+
 #include "messageDigest.h"
 #include "DlAbortEx.h"
 #include "message.h"
 #include "DefaultDiskWriter.h"
 #include "util.h"
 #include "StringFormat.h"
-#include <cerrno>
-#include <cstring>
-#include <cstdlib>
 
 namespace aria2 {
 
@@ -92,7 +93,7 @@ std::string MessageDigestHelper::digest(MessageDigestContext* ctx,
     ssize_t readLength = bs->readData(BUF, BUFSIZE, offset);
     if((size_t)readLength != BUFSIZE) {
       throw DL_ABORT_EX
-        (StringFormat(EX_FILE_READ, "n/a", strerror(errno)).str());
+        (StringFormat(EX_FILE_READ, "n/a", "data is too short").str());
     }
     ctx->digestUpdate(BUF, readLength);
     offset += readLength;
@@ -101,7 +102,7 @@ std::string MessageDigestHelper::digest(MessageDigestContext* ctx,
     ssize_t readLength = bs->readData(BUF, tail, offset);
     if((size_t)readLength != tail) {
       throw DL_ABORT_EX
-        (StringFormat(EX_FILE_READ, "n/a", strerror(errno)).str());
+        (StringFormat(EX_FILE_READ, "n/a", "data is too short").str());
     }
     ctx->digestUpdate(BUF, readLength);
   }

+ 15 - 4
src/PortEventPoll.cc

@@ -34,6 +34,7 @@
 /* copyright --> */
 #include "PortEventPoll.h"
 
+#include <cerrno>
 #include <cstring>
 #include <algorithm>
 #include <numeric>
@@ -41,6 +42,7 @@
 #include "Command.h"
 #include "LogFactory.h"
 #include "Logger.h"
+#include "util.h"
 
 namespace aria2 {
 
@@ -85,9 +87,10 @@ PortEventPoll::~PortEventPoll()
   if(port_ != -1) {
     int r;
     while((r = close(port_)) == -1 && errno == EINTR);
+    int errNum = errno;
     if(r == -1) {
       logger_->error("Error occurred while closing port %d: %s",
-                     port_, strerror(errno));
+                     port_, util::safeStrerror(errNum).c_str());
     }
   }
   delete [] portEvents_;
@@ -120,9 +123,10 @@ void PortEventPoll::poll(const struct timeval& tv)
       p->processEvents(pev.portev_events);
       int r = port_associate(port_, PORT_SOURCE_FD, pev.portev_object,
                              p->getEvents().events, p);
+      int errNum = errno;
       if(r == -1) {
         logger_->error("port_associate failed for file descriptor %d: cause %s",
-                       pev.portev_object, strerror(errno));
+                       pev.portev_object, util::safeStrerror(errNum).c_str());
       }
     }
   }
@@ -171,11 +175,13 @@ bool PortEventPoll::addEvents(sock_t socket,
   std::deque<SharedHandle<KSocketEntry> >::iterator i =
     std::lower_bound(socketEntries_.begin(), socketEntries_.end(), socketEntry);
   int r = 0;
+  int errNum = 0;
   if(i != socketEntries_.end() && (*i) == socketEntry) {
     event.addSelf(*i);
     A2PortEvent pv = (*i)->getEvents();
     r = port_associate(port_, PORT_SOURCE_FD, (*i)->getSocket(),
                        pv.events, pv.socketEntry);
+    errNum = r;
   } else {
     socketEntries_.insert(i, socketEntry);
     if(socketEntries_.size() > portEventsSize_) {
@@ -187,11 +193,12 @@ bool PortEventPoll::addEvents(sock_t socket,
     A2PortEvent pv = socketEntry->getEvents();
     r = port_associate(port_, PORT_SOURCE_FD, socketEntry->getSocket(),
                        pv.events, pv.socketEntry);
+    errNum = r;
   }
   if(r == -1) {
     if(logger_->debug()) {
       logger_->debug("Failed to add socket event %d:%s",
-                     socket, strerror(errno));
+                     socket, util::safeStrerror(errNum).c_str());
     }
     return false;
   } else {
@@ -223,17 +230,21 @@ bool PortEventPoll::deleteEvents(sock_t socket,
   if(i != socketEntries_.end() && (*i) == socketEntry) {
     event.removeSelf(*i);
     int r = 0;
+    int errNum = 0;
     if((*i)->eventEmpty()) {
       r = port_dissociate(port_, PORT_SOURCE_FD, (*i)->getSocket());
+      errNum = errno;
       socketEntries_.erase(i);
     } else {
       A2PortEvent pv = (*i)->getEvents();
       r = port_associate(port_, PORT_SOURCE_FD, (*i)->getSocket(),
                          pv.events, pv.socketEntry);
+      errNum = errno;
     }
     if(r == -1) {
       if(logger_->debug()) {
-        logger_->debug("Failed to delete socket event:%s", strerror(errno));
+        logger_->debug("Failed to delete socket event:%s",
+                       util::safeStrerror(errNum).c_str());
       }
       return false;
     } else {

+ 2 - 20
src/SelectEventPoll.cc

@@ -40,7 +40,6 @@
 #include <cstring>
 #include <algorithm>
 #include <numeric>
-#include <iostream>
 
 #include "Command.h"
 #include "LogFactory.h"
@@ -280,7 +279,6 @@ bool SelectEventPoll::addEvents(sock_t socket, Command* command,
   SharedHandle<SocketEntry> socketEntry(new SocketEntry(socket));
   std::deque<SharedHandle<SocketEntry> >::iterator i =
     std::lower_bound(socketEntries_.begin(), socketEntries_.end(), socketEntry);
-  int r = 0;
   if(i != socketEntries_.end() && (*i) == socketEntry) {
     (*i)->addCommandEvent(command, events);
   } else {
@@ -288,15 +286,7 @@ bool SelectEventPoll::addEvents(sock_t socket, Command* command,
     socketEntry->addCommandEvent(command, events);
   }
   updateFdSet();
-  if(r == -1) {
-    if(logger_->debug()) {
-      logger_->debug("Failed to add socket event %d:%s",
-                     socket, strerror(errno));
-    }
-    return false;
-  } else {
-    return true;
-  }
+  return true;
 }
 
 bool SelectEventPoll::deleteEvents(sock_t socket, Command* command,
@@ -307,19 +297,11 @@ bool SelectEventPoll::deleteEvents(sock_t socket, Command* command,
     std::lower_bound(socketEntries_.begin(), socketEntries_.end(), socketEntry);
   if(i != socketEntries_.end() && (*i) == socketEntry) {
     (*i)->removeCommandEvent(command, events);
-    int r = 0;
     if((*i)->eventEmpty()) {
       socketEntries_.erase(i);
     }
     updateFdSet();
-    if(r == -1) {
-      if(logger_->debug()) {
-        logger_->debug("Failed to delete socket event:%s", strerror(errno));
-      }
-      return false;
-    } else {
-      return true;
-    }
+    return true;
   } else {
     if(logger_->debug()) {
       logger_->debug("Socket %d is not found in SocketEntries.", socket);

+ 97 - 44
src/SocketCore.cc

@@ -92,32 +92,29 @@ namespace aria2 {
 # define CLOSE(X) while(close(X) == -1 && errno == EINTR)
 #endif // __MINGW32__
 
-static const char *errorMsg(const int err)
+namespace {
+std::string errorMsg(int errNum)
 {
 #ifndef __MINGW32__
-  return strerror(err);
+  return util::safeStrerror(errNum);
 #else
   static char buf[256];
   if (FormatMessage(
                     FORMAT_MESSAGE_FROM_SYSTEM |
                     FORMAT_MESSAGE_IGNORE_INSERTS,
                     NULL,
-                    err,
+                    errNum,
                     MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
                     (LPTSTR) &buf,
                     sizeof(buf),
                     NULL
                     ) == 0) {
-    snprintf(buf, sizeof(buf), EX_SOCKET_UNKNOWN_ERROR, err, err);
+    snprintf(buf, sizeof(buf), EX_SOCKET_UNKNOWN_ERROR, errNum, errNum);
   }
   return buf;
 #endif // __MINGW32__
 }
-
-static const char *errorMsg()
-{
-  return errorMsg(SOCKET_ERRNO);
-}
+} // namespace
 
 int SocketCore::protocolFamily_ = AF_UNSPEC;
 
@@ -170,18 +167,23 @@ SocketCore::~SocketCore() {
 
 void SocketCore::create(int family, int protocol)
 {
+  int errNum;
   closeConnection();
   sock_t fd = socket(family, sockType_, protocol);
+  errNum = SOCKET_ERRNO;
   if(fd == (sock_t) -1) {
     throw DL_ABORT_EX
-      (StringFormat("Failed to create socket. Cause:%s", errorMsg()).str());
+      (StringFormat
+       ("Failed to create socket. Cause:%s", errorMsg(errNum).c_str()).str());
   }
   int sockopt = 1;
   if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
                 (a2_sockopt_t) &sockopt, sizeof(sockopt)) < 0) {
+    errNum = SOCKET_ERRNO;
     CLOSE(fd);
     throw DL_ABORT_EX
-      (StringFormat("Failed to create socket. Cause:%s", errorMsg()).str());
+      (StringFormat
+       ("Failed to create socket. Cause:%s", errorMsg(errNum).c_str()).str());
   }
   sockfd_ = fd;
 }
@@ -190,13 +192,18 @@ static sock_t bindInternal(int family, int socktype, int protocol,
                            const struct sockaddr* addr, socklen_t addrlen,
                            std::string& error)
 {
+  int errNum;
   sock_t fd = socket(family, socktype, protocol);
+  errNum = SOCKET_ERRNO;
   if(fd == (sock_t) -1) {
+    error = errorMsg(errNum);
     return -1;
   }
   int sockopt = 1;
   if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (a2_sockopt_t) &sockopt,
                 sizeof(sockopt)) < 0) {
+    errNum = SOCKET_ERRNO;
+    error = errorMsg(errNum);
     CLOSE(fd);
     return -1;
   }
@@ -205,13 +212,16 @@ static sock_t bindInternal(int family, int socktype, int protocol,
     int sockopt = 1;
     if(setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (a2_sockopt_t) &sockopt,
                   sizeof(sockopt)) < 0) {
+      errNum = SOCKET_ERRNO;
+      error = errorMsg(errNum);
       CLOSE(fd);
       return -1;
     }
   }
 #endif // IPV6_V6ONLY
   if(::bind(fd, addr, addrlen) == -1) {
-    error = errorMsg();
+    errNum = SOCKET_ERRNO;
+    error = errorMsg(errNum);
     CLOSE(fd);
     return -1;
   }
@@ -319,7 +329,9 @@ void SocketCore::bind(const struct sockaddr* addr, socklen_t addrlen)
 void SocketCore::beginListen()
 {
   if(listen(sockfd_, 1) == -1) {
-    throw DL_ABORT_EX(StringFormat(EX_SOCKET_LISTEN, errorMsg()).str());
+    int errNum = SOCKET_ERRNO;
+    throw DL_ABORT_EX(StringFormat
+                      (EX_SOCKET_LISTEN, errorMsg(errNum).c_str()).str());
   }
 }
 
@@ -328,9 +340,13 @@ SocketCore* SocketCore::acceptConnection() const
   struct sockaddr_storage sockaddr;
   socklen_t len = sizeof(sockaddr);
   sock_t fd;
-  while((fd = accept(sockfd_, reinterpret_cast<struct sockaddr*>(&sockaddr), &len)) == (sock_t) -1 && SOCKET_ERRNO == A2_EINTR);
+  while((fd = accept(sockfd_, reinterpret_cast<struct sockaddr*>(&sockaddr),
+                     &len)) == (sock_t) -1 &&
+        SOCKET_ERRNO == A2_EINTR);
+  int errNum = SOCKET_ERRNO;
   if(fd == (sock_t) -1) {
-    throw DL_ABORT_EX(StringFormat(EX_SOCKET_ACCEPT, errorMsg()).str());
+    throw DL_ABORT_EX(StringFormat
+                      (EX_SOCKET_ACCEPT, errorMsg(errNum).c_str()).str());
   }
   return new SocketCore(fd, sockType_);
 }
@@ -349,7 +365,9 @@ void SocketCore::getAddrInfo
 {
   struct sockaddr* addrp = reinterpret_cast<struct sockaddr*>(&sockaddr);
   if(getsockname(sockfd_, addrp, &len) == -1) {
-    throw DL_ABORT_EX(StringFormat(EX_SOCKET_GET_NAME, errorMsg()).str());
+    int errNum = SOCKET_ERRNO;
+    throw DL_ABORT_EX(StringFormat
+                      (EX_SOCKET_GET_NAME, errorMsg(errNum).c_str()).str());
   }
 }
 
@@ -367,7 +385,9 @@ void SocketCore::getPeerInfo(std::pair<std::string, uint16_t>& peerinfo) const
   socklen_t len = sizeof(sockaddr);
   struct sockaddr* addrp = reinterpret_cast<struct sockaddr*>(&sockaddr);
   if(getpeername(sockfd_, addrp, &len) == -1) {
-    throw DL_ABORT_EX(StringFormat(EX_SOCKET_GET_NAME, errorMsg()).str());
+    int errNum = SOCKET_ERRNO;
+    throw DL_ABORT_EX(StringFormat
+                      (EX_SOCKET_GET_NAME, errorMsg(errNum).c_str()).str());
   }
   peerinfo = util::getNumericNameInfo(addrp, len);
 }
@@ -386,15 +406,19 @@ void SocketCore::establishConnection(const std::string& host, uint16_t port)
   }
   WSAAPI_AUTO_DELETE<struct addrinfo*> resDeleter(res, freeaddrinfo);
   struct addrinfo* rp;
+  int errNum;
   for(rp = res; rp; rp = rp->ai_next) {
     sock_t fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
+    errNum = SOCKET_ERRNO;
     if(fd == (sock_t) -1) {
-      error = errorMsg();
+      error = errorMsg(errNum);
       continue;
     }
     int sockopt = 1;
-    if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (a2_sockopt_t) &sockopt, sizeof(sockopt)) < 0) {
-      error = errorMsg();
+    if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (a2_sockopt_t) &sockopt,
+                  sizeof(sockopt)) < 0) {
+      errNum = SOCKET_ERRNO;
+      error = errorMsg(errNum);
       CLOSE(fd);
       continue;
     }
@@ -405,7 +429,8 @@ void SocketCore::establishConnection(const std::string& host, uint16_t port)
           i != eoi; ++i) {
         if(::bind(fd,reinterpret_cast<const struct sockaddr*>(&(*i).first),
                   (*i).second) == -1) {
-          error = errorMsg();
+          errNum = SOCKET_ERRNO;
+          error = errorMsg(errNum);
           if(LogFactory::getInstance()->debug()) {
             LogFactory::getInstance()->debug(EX_SOCKET_BIND, error.c_str());
           }
@@ -425,7 +450,8 @@ void SocketCore::establishConnection(const std::string& host, uint16_t port)
     setNonBlockingMode();
     if(connect(fd, rp->ai_addr, rp->ai_addrlen) == -1 &&
        SOCKET_ERRNO != A2_EINPROGRESS) {
-      error = errorMsg();
+      errNum = SOCKET_ERRNO;
+      error = errorMsg(errNum);
       CLOSE(sockfd_);
       sockfd_ = (sock_t) -1;
       continue;
@@ -444,7 +470,9 @@ void SocketCore::setSockOpt
 (int level, int optname, void* optval, socklen_t optlen)
 {
   if(setsockopt(sockfd_, level, optname, (a2_sockopt_t)optval, optlen) < 0) {
-    throw DL_ABORT_EX(StringFormat(EX_SOCKET_SET_OPT, errorMsg()).str());
+    int errNum = SOCKET_ERRNO;
+    throw DL_ABORT_EX(StringFormat
+                      (EX_SOCKET_SET_OPT, errorMsg(errNum).c_str()).str());
   }
 }   
 
@@ -502,7 +530,9 @@ void SocketCore::setNonBlockingMode()
 #ifdef __MINGW32__
   static u_long flag = 1;
   if (::ioctlsocket(sockfd_, FIONBIO, &flag) == -1) {
-    throw DL_ABORT_EX(StringFormat(EX_SOCKET_NONBLOCKING, errorMsg()).str());
+    int errNum = SOCKET_ERRNO;
+    throw DL_ABORT_EX(StringFormat
+                      (EX_SOCKET_NONBLOCKING, errorMsg(errNum).c_str()).str());
   }
 #else
   int flags;
@@ -518,7 +548,9 @@ void SocketCore::setBlockingMode()
 #ifdef __MINGW32__
   static u_long flag = 0;
   if (::ioctlsocket(sockfd_, FIONBIO, &flag) == -1) {
-    throw DL_ABORT_EX(StringFormat(EX_SOCKET_BLOCKING, errorMsg()).str());
+    int errNum = SOCKET_ERRNO;
+    throw DL_ABORT_EX(StringFormat
+                      (EX_SOCKET_BLOCKING, errorMsg(errNum).c_str()).str());
   }
 #else
   int flags;
@@ -576,13 +608,14 @@ bool SocketCore::isWritable(time_t timeout)
   p.events = POLLOUT;
   int r;
   while((r = poll(&p, 1, timeout*1000)) == -1 && errno == EINTR);
+  int errNum = SOCKET_ERRNO;
   if(r > 0) {
     return p.revents&(POLLOUT|POLLHUP|POLLERR);
   } else if(r == 0) {
     return false;
   } else {
     throw DL_RETRY_EX
-      (StringFormat(EX_SOCKET_CHECK_WRITABLE, errorMsg()).str());
+      (StringFormat(EX_SOCKET_CHECK_WRITABLE, errorMsg(errNum).c_str()).str());
   }
 #else // !HAVE_POLL
 # ifndef __MINGW32__
@@ -597,17 +630,19 @@ bool SocketCore::isWritable(time_t timeout)
   tv.tv_usec = 0;
 
   int r = select(sockfd_+1, NULL, &fds, NULL, &tv);
+  int errNum = SOCKET_ERRNO;
   if(r == 1) {
     return true;
   } else if(r == 0) {
     // time out
     return false;
   } else {
-    if(SOCKET_ERRNO == A2_EINPROGRESS || SOCKET_ERRNO == A2_EINTR) {
+    if(errNum == A2_EINPROGRESS || errNum == A2_EINTR) {
       return false;
     } else {
       throw DL_RETRY_EX
-        (StringFormat(EX_SOCKET_CHECK_WRITABLE, errorMsg()).str());
+        (StringFormat(EX_SOCKET_CHECK_WRITABLE,
+                      errorMsg(errNum).c_str()).str());
     }
   }
 #endif // !HAVE_POLL
@@ -626,13 +661,14 @@ bool SocketCore::isReadable(time_t timeout)
   p.events = POLLIN;
   int r;
   while((r = poll(&p, 1, timeout*1000)) == -1 && errno == EINTR);
+  int errNum = SOCKET_ERRNO;
   if(r > 0) {
     return p.revents&(POLLIN|POLLHUP|POLLERR);
   } else if(r == 0) {
     return false;
   } else {
     throw DL_RETRY_EX
-      (StringFormat(EX_SOCKET_CHECK_READABLE, errorMsg()).str());
+      (StringFormat(EX_SOCKET_CHECK_READABLE, errorMsg(errNum).c_str()).str());
   }
 #else // !HAVE_POLL
 # ifndef __MINGW32__
@@ -647,17 +683,19 @@ bool SocketCore::isReadable(time_t timeout)
   tv.tv_usec = 0;
 
   int r = select(sockfd_+1, &fds, NULL, NULL, &tv);
+  int errNum = SOCKET_ERRNO;
   if(r == 1) {
     return true;
   } else if(r == 0) {
     // time out
     return false;
   } else {
-    if(SOCKET_ERRNO == A2_EINPROGRESS || SOCKET_ERRNO == A2_EINTR) {
+    if(errNum == A2_EINPROGRESS || errNum == A2_EINTR) {
       return false;
     } else {
       throw DL_RETRY_EX
-        (StringFormat(EX_SOCKET_CHECK_READABLE, errorMsg()).str());
+        (StringFormat(EX_SOCKET_CHECK_READABLE,
+                      errorMsg(errNum).c_str()).str());
     }
   }
 #endif // !HAVE_POLL
@@ -699,12 +737,14 @@ ssize_t SocketCore::writeData(const char* data, size_t len)
 
   if(!secure_) {
     while((ret = send(sockfd_, data, len, 0)) == -1 && SOCKET_ERRNO == A2_EINTR);
+    int errNum = SOCKET_ERRNO;
     if(ret == -1) {
-      if(A2_WOULDBLOCK(SOCKET_ERRNO)) {
+      if(A2_WOULDBLOCK(errNum)) {
         wantWrite_ = true;
         ret = 0;
       } else {
-        throw DL_RETRY_EX(StringFormat(EX_SOCKET_SEND, errorMsg()).str());
+        throw DL_RETRY_EX(StringFormat(EX_SOCKET_SEND,
+                                       errorMsg(errNum).c_str()).str());
       }
     }
   } else {
@@ -743,12 +783,14 @@ void SocketCore::readData(char* data, size_t& len)
   if(!secure_) {    
     while((ret = recv(sockfd_, data, len, 0)) == -1 && SOCKET_ERRNO == A2_EINTR);
     
+    int errNum = SOCKET_ERRNO;
     if(ret == -1) {
-      if(A2_WOULDBLOCK(SOCKET_ERRNO)) {
+      if(A2_WOULDBLOCK(errNum)) {
         wantRead_ = true;
         ret = 0;
       } else {
-        throw DL_RETRY_EX(StringFormat(EX_SOCKET_RECV, errorMsg()).str());
+        throw DL_RETRY_EX(StringFormat(EX_SOCKET_RECV,
+                                       errorMsg(errNum).c_str()).str());
       }
     }
   } else {
@@ -789,12 +831,14 @@ void SocketCore::peekData(char* data, size_t& len)
   if(!secure_) {
     while((ret = recv(sockfd_, data, len, MSG_PEEK)) == -1 &&
           SOCKET_ERRNO == A2_EINTR);
+    int errNum = SOCKET_ERRNO;
     if(ret == -1) {
-      if(A2_WOULDBLOCK(SOCKET_ERRNO)) {
+      if(A2_WOULDBLOCK(errNum)) {
         wantRead_ = true;
         ret = 0;
       } else {
-        throw DL_RETRY_EX(StringFormat(EX_SOCKET_PEEK, errorMsg()).str());
+        throw DL_RETRY_EX(StringFormat(EX_SOCKET_PEEK,
+                                       errorMsg(errNum).c_str()).str());
       }
     }
   } else {
@@ -1133,20 +1177,23 @@ ssize_t SocketCore::writeData(const char* data, size_t len,
   WSAAPI_AUTO_DELETE<struct addrinfo*> resDeleter(res, freeaddrinfo);
   struct addrinfo* rp;
   ssize_t r = -1;
+  int errNum = 0;
   for(rp = res; rp; rp = rp->ai_next) {
     while((r = sendto(sockfd_, data, len, 0, rp->ai_addr, rp->ai_addrlen)) == -1
           && A2_EINTR == SOCKET_ERRNO);
+    errNum = SOCKET_ERRNO;
     if(r == static_cast<ssize_t>(len)) {
       break;
     }
-    if(r == -1 && A2_WOULDBLOCK(SOCKET_ERRNO)) {
+    if(r == -1 && A2_WOULDBLOCK(errNum)) {
       wantWrite_ = true;
       r = 0;
       break;
     }
   }
   if(r == -1) {
-    throw DL_ABORT_EX(StringFormat(EX_SOCKET_SEND, errorMsg()).str());
+    throw DL_ABORT_EX(StringFormat(EX_SOCKET_SEND,
+                                   errorMsg(errNum).c_str()).str());
   }
   return r;
 }
@@ -1163,12 +1210,14 @@ ssize_t SocketCore::readDataFrom(char* data, size_t len,
   ssize_t r;
   while((r = recvfrom(sockfd_, data, len, 0, addrp, &sockaddrlen)) == -1 &&
         A2_EINTR == SOCKET_ERRNO);
+  int errNum = SOCKET_ERRNO;
   if(r == -1) {
-    if(A2_WOULDBLOCK(SOCKET_ERRNO)) {
+    if(A2_WOULDBLOCK(errNum)) {
       wantRead_ = true;
       r = 0;
     } else {
-      throw DL_RETRY_EX(StringFormat(EX_SOCKET_RECV, errorMsg()).str());
+      throw DL_RETRY_EX(StringFormat(EX_SOCKET_RECV,
+                                     errorMsg(errNum).c_str()).str());
     }
   } else {
     sender = util::getNumericNameInfo(addrp, sockaddrlen);
@@ -1182,9 +1231,11 @@ std::string SocketCore::getSocketError() const
   int error;
   socklen_t optlen = sizeof(error);
 
-  if(getsockopt(sockfd_, SOL_SOCKET, SO_ERROR, (a2_sockopt_t) &error, &optlen) == -1) {
+  if(getsockopt(sockfd_, SOL_SOCKET, SO_ERROR,
+                (a2_sockopt_t) &error, &optlen) == -1) {
+    int errNum = SOCKET_ERRNO;
     throw DL_ABORT_EX(StringFormat("Failed to get socket error: %s",
-                                   errorMsg()).str());
+                                   errorMsg(errNum).c_str()).str());
   }
   if(error != 0) {
     return errorMsg(error);
@@ -1243,7 +1294,9 @@ void getInterfaceAddress
   // First find interface in interface addresses
   struct ifaddrs* ifaddr = 0;
   if(getifaddrs(&ifaddr) == -1) {
-    logger->info(MSG_INTERFACE_NOT_FOUND, iface.c_str(), errorMsg());
+    int errNum = SOCKET_ERRNO;
+    logger->info(MSG_INTERFACE_NOT_FOUND,
+                 iface.c_str(), errorMsg(errNum).c_str());
   } else {
     auto_delete<struct ifaddrs*> ifaddrDeleter(ifaddr, freeifaddrs);
     for(struct ifaddrs* ifa = ifaddr; ifa; ifa = ifa->ifa_next) {

+ 2 - 3
src/message.h

@@ -229,9 +229,8 @@
 #define EX_FILE_OFFSET_OUT_OF_RANGE _("The offset is out of range, offset=%s")
 #define EX_NOT_DIRECTORY _("%s is not a directory.")
 #define EX_MAKE_DIR _("Failed to make the directory %s, cause: %s")
-#define EX_SEGMENT_FILE_OPEN _("Failed to open the segment file %s, cause: %s")
-#define EX_SEGMENT_FILE_WRITE _("Failed to write into the segment file %s, cause: %s")
-#define EX_SEGMENT_FILE_READ _("Failed to read from the segment file %s, cause: %s")
+#define EX_SEGMENT_FILE_WRITE "Failed to write into the segment file %s"
+#define EX_SEGMENT_FILE_READ "Failed to read from the segment file %s"
 
 #define EX_SOCKET_OPEN _("Failed to open a socket, cause: %s")
 #define EX_SOCKET_SET_OPT _("Failed to set a socket option, cause: %s")

+ 23 - 5
src/util.cc

@@ -1128,10 +1128,13 @@ unsigned int alphaToNum(const std::string& alphabets)
 void mkdirs(const std::string& dirpath)
 {
   File dir(dirpath);
-  if(!dir.mkdirs() &&!dir.isDir()) {
-    throw DL_ABORT_EX
-      (StringFormat(EX_MAKE_DIR, dir.getPath().c_str(),
-                    strerror(errno)).str());
+  if(!dir.mkdirs()) {
+    int errNum = errno;
+    if(!dir.isDir()) {
+      throw DL_ABORT_EX
+        (StringFormat(EX_MAKE_DIR, dir.getPath().c_str(),
+                      safeStrerror(errNum).c_str()).str());
+    }
   }
 }
 
@@ -1171,7 +1174,8 @@ void* allocateAlignedMemory(size_t alignment, size_t size)
   int res;
   if((res = posix_memalign(&buffer, alignment, size)) != 0) {
     throw FATAL_EXCEPTION
-      (StringFormat("Error in posix_memalign: %s", strerror(res)).str());
+      (StringFormat("Error in posix_memalign: %s",
+                    util::safeStrerror(res).c_str()).str());
   }
   return buffer;
 }
@@ -1498,6 +1502,20 @@ std::string encodeNonUtf8(const std::string& s)
   return util::isUtf8(s)?s:util::percentEncode(s);
 }
 
+std::string makeString(const char* str)
+{
+  if(str) {
+    return str;
+  } else {
+    return A2STR::NIL;
+  }
+}
+
+std::string safeStrerror(int errNum)
+{
+  return makeString(strerror(errNum));
+}
+
 } // namespace util
 
 } // namespace aria2

+ 8 - 0
src/util.h

@@ -427,6 +427,14 @@ std::string createSafePath(const std::string& dir, const std::string& filename);
 
 std::string encodeNonUtf8(const std::string& s);
 
+// Create string safely. If str is NULL, returns empty string.
+// Otherwise, returns std::string(str).
+std::string makeString(const char* str);
+
+// This function is basically the same with strerror(errNum) but when
+// strerror returns NULL, this function returns empty string.
+std::string safeStrerror(int errNum);
+
 } // namespace util
 
 } // namespace aria2