[Assorted-commits] SF.net SVN: assorted:[1177] cpp-commons/trunk/src/commons
Brought to you by:
yangzhang
From: <yan...@us...> - 2009-02-13 20:54:54
|
Revision: 1177 http://assorted.svn.sourceforge.net/assorted/?rev=1177&view=rev Author: yangzhang Date: 2009-02-13 20:54:46 +0000 (Fri, 13 Feb 2009) Log Message: ----------- - added release to closing - made closingfd publically inherit closing - refactored and cleaned up sockets code - added st_reader - fixed formatting bugs in check messages - added auto_array, array_view Modified Paths: -------------- cpp-commons/trunk/src/commons/array.h cpp-commons/trunk/src/commons/check.h cpp-commons/trunk/src/commons/closing.h cpp-commons/trunk/src/commons/sockets.h cpp-commons/trunk/src/commons/st/st.h Modified: cpp-commons/trunk/src/commons/array.h =================================================================== --- cpp-commons/trunk/src/commons/array.h 2009-02-11 19:59:53 UTC (rev 1176) +++ cpp-commons/trunk/src/commons/array.h 2009-02-13 20:54:46 UTC (rev 1177) @@ -2,6 +2,8 @@ #define COMMONS_ARRAY_H #include <boost/scoped_array.hpp> +#include <commons/check.h> +#include <commons/nullptr.h> namespace commons { @@ -14,20 +16,54 @@ template<typename T> class array : public scoped_array<T> { public: - explicit array(size_t n) : scoped_array<T>(new T[n]), n_(n) {} + explicit array(size_t n) : scoped_array<T>(checkpass(new T[n])), n_(n) {} size_t size() { return n_; } + char *end() { return this->get() + n_; } private: size_t n_; }; - //template<typename T> - // class array { - // public: - // explicit array(int n) : a(new T[n]) {} - // private: - // scoped_array<T> a; - // }; + /** + * A release-able array. + */ + template<typename T> + class auto_array { + public: + auto_array(T *p) : p_(p) {} + ~auto_array() { if (p_ != nullptr) delete [] p_; } + T *release() { T *p = p_; p_ = nullptr; return p; } + T *get() { return p_; } + const T *get() const { return p_; } + operator T*() { return p_; } + operator const T*() const { return p_; } + private: + T *p_; + }; + /** + * Move-able, conditionally-scoped array. + * + * TODO: rename to managed_array + */ + template<typename T> + class array_view { + public: + array_view(T *p, bool scoped) : p_(p), scoped_(scoped) {} +#ifdef __GXX_EXPERIMENTAL_CXX0X__ + array_view(array_view<T> &&a) : p_(a.p_), scoped_(a.scoped_) { a.release(); } +#endif + ~array_view() { if (scoped_) delete [] p_; } + T *release() { T *p = p_; p_ = nullptr; scoped_ = false; return p; } + T *get() { return p_; } + const T *get() const { return p_; } + operator T*() { return p_; } + operator const T*() const { return p_; } + bool scoped() const { return scoped_; } + private: + T *p_; + bool scoped_; + }; + } #endif Modified: cpp-commons/trunk/src/commons/check.h =================================================================== --- cpp-commons/trunk/src/commons/check.h 2009-02-11 19:59:53 UTC (rev 1176) +++ cpp-commons/trunk/src/commons/check.h 2009-02-13 20:54:46 UTC (rev 1177) @@ -23,6 +23,8 @@ // // - chkr(): same as chk but returns -1 instead of throwing +// TODO: incorporate __PRETTY_FUNCTION__ + namespace commons { @@ -60,7 +62,7 @@ } } - __attribute__((format(printf, 4, 5))) inline void + __attribute__((format(printf, 4, 5))) void _check(bool cond, const char *file, int line, const char *fmt, ...) { va_list ap; @@ -85,7 +87,11 @@ template<typename T> inline T _checknneg(T x, const char *file, int line) { - _check(x >= 0, file, line, "expecting non-negative, got %d", x); + if (x < 0) { + stringstream ss; + ss << "expecting non-negative, got " << x; + _check(false, file, line, "%s", ss.str().c_str()); + } return x; } @@ -95,7 +101,9 @@ if (x < 0) { int e = errno; errno = 0; - _check(x, file, line, "expecting >=0, got %d: %s", x, strerror(e)); + stringstream ss; + ss << "expecting >=0, got " << x << ": " << strerror(e); + _check(false, file, line, "%s", ss.str().c_str()); } return x; } @@ -106,8 +114,9 @@ if (!x) { int e = errno; errno = 0; - _check(x, file, line, "expecting !=0, got %s: %s", - lexical_cast<string>(x).c_str(), strerror(e)); + stringstream ss; + ss << "expecting !=0, got " << x << ": " << strerror(e); + _check(false, file, line, "%s", ss.str().c_str()); } return x; } Modified: cpp-commons/trunk/src/commons/closing.h =================================================================== --- cpp-commons/trunk/src/commons/closing.h 2009-02-11 19:59:53 UTC (rev 1176) +++ cpp-commons/trunk/src/commons/closing.h 2009-02-13 20:54:46 UTC (rev 1177) @@ -8,13 +8,16 @@ class closing { public: - closing(T x) : x(x) {} - ~closing() { close(x); } + closing(T x) : x(x), scoped(true) {} + ~closing() { if (scoped) close(x); } + T get() { return x; } + T release() { scoped = false; return x; } private: T x; + bool scoped; }; - class closingfd : closing<int> { + class closingfd : public closing<int> { public: closingfd(int x) : closing<int>(x) {} }; Modified: cpp-commons/trunk/src/commons/sockets.h =================================================================== --- cpp-commons/trunk/src/commons/sockets.h 2009-02-11 19:59:53 UTC (rev 1176) +++ cpp-commons/trunk/src/commons/sockets.h 2009-02-13 20:54:46 UTC (rev 1177) @@ -11,11 +11,78 @@ #include <unistd.h> #include <commons/check.h> +#include <commons/closing.h> +#include <commons/nullptr.h> namespace commons { /** + * Create a TCP socket. + */ + int + tcp_socket(bool nb) + { + int fd = checknnegerr(socket(PF_INET, SOCK_STREAM, 0)); + // Make our socket non-blocking if desired. + if (nb) + checknnegerr(fcntl(fd, F_SETFL, O_NONBLOCK | fcntl(fd, F_GETFL, 0))); + return fd; + } + + /** + * Initialize an inet address with just the port. + */ + void + sockaddr_init(sockaddr_in &a, uint16_t port) + { + bzero(&a, sizeof a); + a.sin_family = AF_INET; + a.sin_port = htons(port); + } + + /** + * Initialize an inet address. + */ + void + sockaddr_init(sockaddr_in &a, const char *host, uint16_t port) + { + sockaddr_init(a, port); + if (host == nullptr) { + a.sin_addr.s_addr = htonl(INADDR_ANY); + } else { + // First try to interpret host as a dot-notation string. + if (!inet_aton(host, (struct in_addr *) &a.sin_addr.s_addr)) { + // Now try to resolve the hostname. + struct hostent *res = checkpass(gethostbyname(host)); + memcpy(&a.sin_addr, res->h_addr_list[0], res->h_length); + } + } + } + + /** + * Initialize an inet address. + */ + void + sockaddr_init(sockaddr_in &a, in_addr host, uint16_t port) + { + sockaddr_init(a, port); + a.sin_addr = host; + } + + /** + * Construct an inet address. + */ + template <typename T> + sockaddr_in + make_sockaddr(T host, uint16_t port) + { + sockaddr_in a; + sockaddr_init(a, host, port); + return a; + } + + /** * Create a server socket bound to localhost, with SO_REUSEADDR enabled. * \param[in] port The port to listen on. * \param[in] nb Whether the socket should be non-blocking. @@ -25,34 +92,21 @@ server_socket(uint16_t port, bool nb = false) { // Create the socket. - int fd = checknneg(socket(PF_INET, SOCK_STREAM, 0)); + closingfd c(tcp_socket(nb)); + int fd = c.get(); - try { - // Configure the socket. - int n = 1; - check0x(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, - reinterpret_cast<char *>(&n), sizeof(n))); + // Configure the socket. + int n = 1; + check0x(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, + reinterpret_cast<char*>(&n), sizeof(n))); - // Make our socket non-blocking if desired. - if (nb) { - checknneg(fcntl(fd, F_SETFL, O_NONBLOCK | fcntl(fd, F_GETFL, 0))); - } + // Create the local socket address. + sockaddr_in sa = make_sockaddr(nullptr, port); - // Create the local socket address. - sockaddr_in sa; - bzero(&sa, sizeof(sa)); - sa.sin_family = AF_INET; - sa.sin_port = htons(port); - sa.sin_addr.s_addr = htonl(INADDR_ANY); + // Bind the socket to the local socket address. + check0x(::bind(fd, (sockaddr*) &sa, sizeof sa)); - // Bind the socket to the local socket address. - check0x(::bind(fd, (sockaddr*) &sa, sizeof sa)); - - return fd; - } catch (...) { - close(fd); - throw; - } + return c.release(); } /** @@ -75,6 +129,19 @@ throw; } } + + /** + * Connect to a TCP socket. + */ + int + tcp_connect(const char *host, uint16_t port) + { + closingfd c(tcp_socket(false)); + sockaddr_in a = make_sockaddr(host, port); + check0x(connect(c.get(), reinterpret_cast<sockaddr*>(&a), sizeof a)); + return c.release(); + } + } #endif Modified: cpp-commons/trunk/src/commons/st/st.h =================================================================== --- cpp-commons/trunk/src/commons/st/st.h 2009-02-11 19:59:53 UTC (rev 1176) +++ cpp-commons/trunk/src/commons/st/st.h 2009-02-13 20:54:46 UTC (rev 1177) @@ -1,6 +1,7 @@ #ifndef COMMONS_ST_ST_H #define COMMONS_ST_ST_H +#include <algorithm> #include <exception> #include <map> #include <queue> @@ -8,14 +9,17 @@ #include <sstream> #include <st.h> #include <stx.h> +#include <commons/array.h> #include <commons/nullptr.h> // delegates.h must be included after sockets.h due to bind() conflicts. #include <commons/sockets.h> #include <commons/boost/delegates.h> #include <boost/foreach.hpp> #include <boost/function.hpp> +#include <boost/shared_ptr.hpp> #define foreach BOOST_FOREACH +#define shared_ptr boost::shared_ptr namespace commons { @@ -31,7 +35,7 @@ { public: st_closing(st_netfd_t x) : attached(true), x(x) {} - ~st_closing() { if (attached) st_netfd_close(x); } + ~st_closing() { if (attached) check0x(st_netfd_close(x)); } void detach() { attached = false; } private: bool attached; @@ -47,6 +51,7 @@ stfd(st_netfd_t fd) : fd_(fd), sclose(fd) {} st_netfd_t fd() const { return fd_; } operator st_netfd_t() const { return fd_; } + st_netfd_t release() { sclose.detach(); return fd_; } private: const st_netfd_t fd_; st_closing sclose; @@ -94,24 +99,14 @@ st_tcp_connect(in_addr host, uint16_t port, st_utime_t timeout) { // Create remote socket address. - struct sockaddr_in sa; - bzero(&sa, sizeof sa); - sa.sin_family = AF_INET; - sa.sin_port = htons(port); - sa.sin_addr = host; + sockaddr_in sa = make_sockaddr(host, port); // Create the socket. - int sfd = checknnegerr(socket(PF_INET, SOCK_STREAM, 0)); - st_netfd_t nfd = st_netfd_open_socket(sfd); + stfd s(checkpass(st_netfd_open_socket(tcp_socket(true)))); // Connect. - try { - check0x(st_connect(nfd, (sockaddr*) &sa, sizeof sa, timeout)); - return nfd; - } catch (...) { - check0x(st_netfd_close(nfd)); - throw; - } + check0x(st_connect(s.fd(), reinterpret_cast<sockaddr*>(&sa), sizeof sa, timeout)); + return s.release(); } /** @@ -394,6 +389,100 @@ std::set<st_thread_t> ts; }; + class eof_exception : public std::exception { + const char *what() const throw() { return "EOF"; } + }; + + /** + * Convenience class for reading from sockets. + */ + class st_reader + { + public: + st_reader(st_netfd_t fd, size_t bufsize = 1e7) : + fd_(fd), + buf_(bufsize), + start_(buf_.get()), + end_(buf_.get()) + {} + + /** + * The size of the unconsumed range of bytes. + */ + size_t amt() { return end_ - start_; } + + /** + * The remaining number of bytes in the buffer + */ + size_t rem() { return buf_.end() - end_; } + + /** + * Returns a char array that contains the requested number of bytes. If + * we hit an error or EOF, then an exception is thrown. + */ + array_view<char> read(size_t req = 0, st_utime_t to = ST_UTIME_NO_TIMEOUT) { + // Do we already have the requested data? + if (amt() >= req) { + array_view<char> p(start_, false); + start_ += req; + return p; + } + + // Handle large arrays specially. + if (req > buf_.size()) { + array_view<char> p(checkpass(new char[req]), true); + copy(start_, end_, p.get()); + checkeqnneg(st_read_fully(fd_, p + amt(), req, to), static_cast<ssize_t>(req)); + start_ = end_ = buf_.get(); + return p; + } + + // Shift things down if necessary. + if (req > static_cast<size_t>(buf_.end() - end_)) { + copy(start_, end_, buf_.get()); + size_t diff = start_ - buf_.get(); + start_ -= diff; + end_ -= diff; + } + + // Keep reading until we have enough. + while (amt() < req) { + ssize_t res = st_read(fd_, end_, rem(), to); + checknneg(res); + if (res == 0) break; + else end_ += res; + } + + // If we got a premature EOF. + if (amt() < req) + throw eof_exception(); + + array_view<char> p(start_, false); + start_ += req; + return p; + } + + private: + st_reader(const st_reader &); + + st_netfd_t fd_; + + /** + * The temporary storage buffer. + */ + array<char> buf_; + + /** + * The start of the unconsumed range of bytes. + */ + char *start_; + + /** + * The end of the unconsumed range of bytes. + */ + char *end_; + }; + } #endif This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |