// Copyright (C) 1999-2005 Open Source Telecom Corporation. // // 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. // // As a special exception, you may use this file as part of a free software // library without restriction. Specifically, if other files instantiate // templates or use macros or inline functions from this file, or you compile // this file and link it with other files to produce an executable, this // file does not by itself cause the resulting executable to be covered by // the GNU General Public License. This exception does not however // invalidate any other reasons why the executable file might be covered by // the GNU General Public License. // // This exception applies only to the code released under the name GNU // Common C++. If you copy code from other releases into a copy of GNU // Common C++, as the General Public License permits, the exception does // not apply to the code that you add in this way. To avoid misleading // anyone as to the status of such modified files, you must delete // this exception notice from them. // // If you write modifications of your own for GNU Common C++, it is your choice // whether to permit this exception to apply to your modifications. // If you do not wish that, delete this exception notice. // #include #include #include #include #include #include #include #include #include #include #include #include #ifndef WIN32 #include #include #endif #ifdef WIN32 #include #endif #ifdef CCXX_NAMESPACES namespace ost { using namespace std; #endif #ifndef WIN32 UnixSocket::UnixSocket(const char* pathname, int backlog) : Socket(AF_UNIX, SOCK_STREAM, 0) { struct sockaddr_un addr; socklen_t len; unsigned slen = strlen(pathname); if(slen > sizeof(addr.sun_path)) slen = sizeof(addr.sun_path); path = NULL; memset(&addr, 0, sizeof(addr)); addr.sun_family = AF_UNIX; memcpy( addr.sun_path, pathname, slen ); #ifdef __SUN_LEN len = sizeof(addr.sun_len) + strlen(addr.sun_path) + sizeof(addr.sun_family) + 1; addr.sun_len = len; #else len = strlen(addr.sun_path) + sizeof(addr.sun_family) + 1; #endif remove(pathname); if(bind(so, (struct sockaddr *)&addr, len)) { endSocket(); error(errBindingFailed); return; } path = new char[slen + 1]; strcpy(path, pathname); if(listen(so, backlog)) { endSocket(); error(errBindingFailed); return; } state = BOUND; } UnixSocket::~UnixSocket() { close(); } void UnixSocket::close(void) { endSocket(); if(path) { remove(path); delete[] path; path = NULL; } } UnixStream::UnixStream(UnixSocket &server, int size, bool throwflag, timeout_t to) : Socket(accept(server.so, NULL, NULL)) ,streambuf() #ifdef HAVE_OLD_IOSTREAM ,iostream() #else ,iostream((streambuf *)this) #endif ,bufsize(0) ,gbuf(NULL) ,pbuf(NULL) { #ifdef HAVE_OLD_IOSTREAM init((streambuf *)this); #endif timeout = to; setError(throwflag); allocate(size); Socket::state = CONNECTED; } UnixStream::UnixStream(const char* pathname, int size, bool throwflag, timeout_t to) : Socket(AF_UNIX, SOCK_STREAM, 0), streambuf(), #ifdef HAVE_OLD_IOSTREAM iostream(), #else iostream((streambuf *)this), #endif bufsize(0),gbuf(NULL),pbuf(NULL) { #ifdef HAVE_OLD_IOSTREAM init((streambuf *)this); #endif timeout = to; setError(throwflag); connect(pathname, size); } UnixStream::~UnixStream() { endStream(); } void UnixStream::connect(const char* pathname, int size) { struct sockaddr_un addr; socklen_t len; unsigned slen = strlen(pathname); if(slen > sizeof(addr.sun_path)) slen = sizeof(addr.sun_path); memset(&addr, 0, sizeof(addr)); addr.sun_family = AF_UNIX; memcpy( addr.sun_path, pathname, slen ); #ifdef __SUN_LEN len = sizeof(addr.sun_len) + strlen(addr.sun_path) + sizeof(addr.sun_family) + 1; addr.sun_len = len; #else len = strlen(addr.sun_path) + sizeof(addr.sun_family); #endif if(::connect(so, (struct sockaddr *)&addr, len) != 0) { connectError(); endSocket(); return; } allocate(size); Socket::state = CONNECTED; } UnixStream::UnixStream(bool throwflag) : Socket(PF_UNIX, SOCK_STREAM, 0), streambuf(), #ifdef HAVE_OLD_IOSTREAM iostream(), #else iostream((streambuf *)this), #endif timeout(0), bufsize(0),gbuf(NULL),pbuf(NULL) { #ifdef HAVE_OLD_IOSTREAM init((streambuf *)this); #endif setError(throwflag); } UnixStream::UnixStream(const UnixStream &source) : Socket(dup(source.so)), streambuf(), #ifdef HAVE_OLD_IOSTREAM iostream() #else iostream((streambuf *)this) #endif { #ifdef HAVE_OLD_IOSTREAM init((streambuf *)this); #endif bufsize = source.bufsize; allocate(bufsize); } void UnixStream::endStream(void) { if(bufsize) sync(); if(gbuf) delete[] gbuf; if(pbuf) delete[] pbuf; gbuf = pbuf = NULL; bufsize = 0; endSocket(); } void UnixStream::allocate(int size) { if(size < 2) { bufsize = 1; return; } gbuf = new char[size]; pbuf = new char[size]; if(!pbuf || !gbuf) { error(errResourceFailure); return; } bufsize = size; clear(); #if (defined(__GNUC__) && (__GNUC__ < 3)) && !defined(WIN32) && !defined(STLPORT) setb(gbuf, gbuf + size, 0); #endif setg(gbuf, gbuf + size, gbuf + size); setp(pbuf, pbuf + size); } int UnixStream::doallocate() { if(bufsize) return 0; allocate(1); return 1; } int UnixStream::uflow(void) { int ret = underflow(); if (ret == EOF) return EOF; if (bufsize != 1) gbump(1); return ret; } int UnixStream::underflow(void) { int rlen = 1; unsigned char ch; if(bufsize == 1) { if(Socket::state == STREAM) rlen = ::read(so, (char *)&ch, 1); else if(timeout && !Socket::isPending(pendingInput, timeout)) { clear(ios::failbit | rdstate()); error(errTimeout); return EOF; } else rlen = ::recv(so, (char *)&ch, 1, 0); if(rlen < 1) { if(rlen < 0) { clear(ios::failbit | rdstate()); error(errInput); } return EOF; } return ch; } if(!gptr()) return EOF; if(gptr() < egptr()) return (unsigned char)*gptr(); rlen = (gbuf + bufsize) - eback(); if(Socket::state == STREAM) rlen = ::read(so, (char *)eback(), rlen); else if(timeout && !Socket::isPending(pendingInput, timeout)) { clear(ios::failbit | rdstate()); error(errTimeout); return EOF; } else rlen = ::recv(so, (char *)eback(), rlen, 0); if(rlen < 1) { if(rlen < 0) { clear(ios::failbit | rdstate()); error(errInput); } return EOF; } setg(eback(), eback(), eback() + rlen); return (unsigned char) *gptr(); } bool UnixStream::isPending(Pending pending, timeout_t timeout) { if(pending == pendingInput && in_avail()) return true; else if(pending == pendingOutput) flush(); return Socket::isPending(pending, timeout); } int UnixStream::sync(void) { overflow(EOF); setg(gbuf, gbuf + bufsize, gbuf + bufsize); return 0; } int UnixStream::overflow(int c) { unsigned char ch; int rlen, req; if(bufsize == 1) { if(c == EOF) return 0; ch = (unsigned char)(c); if(Socket::state == STREAM) rlen = ::write(so, (const char *)&ch, 1); else rlen = ::send(so, (const char *)&ch, 1, 0); if(rlen < 1) { if(rlen < 0) { clear(ios::failbit | rdstate()); error(errOutput); } return EOF; } else return c; } if(!pbase()) return EOF; req = pptr() - pbase(); if(req) { if(Socket::state == STREAM) rlen = ::write(so, (const char *)pbase(), req); else rlen = ::send(so, (const char *)pbase(), req, 0); if(rlen < 1) { if(rlen < 0) { clear(ios::failbit | rdstate()); error(errOutput); } return EOF; } req -= rlen; } // if write "partial", rebuffer remainder if(req) memcpy(pptr(), pptr() + rlen, req); setp(pbuf + req, pbuf + bufsize); if(c != EOF) { *pptr() = (unsigned char)c; pbump(1); } return c; } unixstream::unixstream() : UnixStream() { setError(false); /* no exceptions */ } unixstream::unixstream(const char *pathname, int buf) : UnixStream() { setError(false); open(pathname, buf); } unixstream::unixstream(UnixSocket &server, int buf) : UnixStream() { setError(false); open(server, buf); } bool unixstream::operator!() const { return (Socket::state != CONNECTED) ? true : false; } void unixstream::open(UnixSocket &unixsock, int buf) { endStream(); so = accept(unixsock.so, NULL, NULL); if(so == INVALID_SOCKET) return; allocate(buf); Socket::state = CONNECTED; } void unixstream::close(void) { if(Socket::state == AVAILABLE) return; endStream(); so = socket(AF_UNIX, SOCK_STREAM, 0); if(so != INVALID_SOCKET) Socket::state = AVAILABLE; } UnixSession::UnixSession(const char* pathname, int size, int pri, int stack) : Thread(pri, stack), UnixStream() { struct sockaddr_un addr; unsigned slen = strlen(pathname); if(slen > sizeof(addr.sun_path)) slen = sizeof(addr.sun_path); socklen_t len; setCompletion(false); setError(false); allocate(size); memset(&addr, 0, sizeof(addr)); addr.sun_family = AF_UNIX; memcpy( addr.sun_path, pathname, slen ); #ifdef __SUN_LEN len = sizeof(addr.sun_len) + strlen(addr.sun_path) + sizeof(addr.sun_family) + 1; addr.sun_len = len; #else len = strlen(addr.sun_path) + sizeof(addr.sun_family); #endif if(::connect(so, (struct sockaddr *)&addr, len ) != 0) { #ifdef WIN32 if( WSAGetLastError() == WAEISCONN ) #else if( EINPROGRESS == errno ) #endif { Socket::state = CONNECTING; } else { endSocket(); Socket::state = INITIAL; } return; } setCompletion(true); Socket::state = CONNECTED; } UnixSession::UnixSession(UnixSocket &s,int size, int pri, int stack) : Thread(pri, stack), UnixStream(s, size) { setCompletion(true); setError(false); } UnixSession::~UnixSession() { terminate(); endStream(); } int UnixSession::waitConnection(timeout_t timeout) { long sockopt = 0; socklen_t len = sizeof(sockopt); switch(Socket::state) { case INITIAL: return -1; case CONNECTED: break; case CONNECTING: if(!Socket::isPending(pendingOutput, timeout)) { endSocket(); Socket::state = INITIAL; return -1; } getsockopt(so, SOL_SOCKET, SO_ERROR, (char *)&sockopt, &len); if(sockopt) { endSocket(); Socket::state = INITIAL; return -1; } case AVAILABLE: case BOUND: case STREAM: break; } Socket::state = CONNECTED; return 0; } void UnixSession::initial(void) { if(waitConnection(60000)) exit(); } #endif // ndef WIN32 #ifdef CCXX_NAMESPACES } #endif