sockbuf::sockbuf (int domain, sockbuf::type st, int proto) : rep (0) { #if defined(WIN32) && !defined(__CYGWIN__) WORD version = MAKEWORD(1,1); WSADATA wsaData; WSAStartup(version, &wsaData); #endif SOCKET soc = ::socket (domain, st, proto); if (soc == static_cast<SOCKET>(SOCKET_ERROR)) #if defined(__CYGWIN__) || !defined(WIN32) throw sockerr (errno, "sockbuf::sockbuf"); #else throw sockerr(WSAGetLastError(), "sockbuf::sockbuf"); #endif rep = new sockbuf::sockcnt (soc); char_type* gbuf = new char_type [BUFSIZ]; char_type* pbuf = new char_type [BUFSIZ]; setg (gbuf, gbuf + BUFSIZ, gbuf + BUFSIZ); setp (pbuf, pbuf + BUFSIZ); rep->gend = gbuf + BUFSIZ; rep->pend = pbuf + BUFSIZ; }
void sockstreambuf::bind(const char *port) { int ret; struct addrinfo hints, *res; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_PASSIVE; if ((ret = getaddrinfo(NULL, port, &hints, &res))) throw sockerr(std::string("getaddrinfo(): ") + gai_strerror(ret)); if ((sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) < 0) throw sockerr(std::string("socket(): ") + strerror(errno)); if ((ret = ::bind(sockfd, res->ai_addr, res->ai_addrlen)) < 0) { close(); throw sockerr(std::string("bind(): ") + strerror(errno)); } if ((ret = ::listen(sockfd, 32)) < 0) { close(); throw sockerr(std::string("listen(): ") + strerror(errno)); } }
int sockbuf::recvmsg (msghdr* msg, int msgf) { if (rep->rtmo != -1 && is_readready (rep->rtmo)==0) throw sockerr (ETIMEDOUT, "sockbuf::recvmsg", sockname.text.c_str()); if (rep->oob && atmark ()) throw sockoob (); int rval = ::recvmsg(rep->sock, msg, msgf); if (rval == -1) throw sockerr (errno, "sockbuf::recvmsg", sockname.text.c_str()); return rval; }
int sockbuf::recv (void* buf, int len, int msgf) { if (rep->rtmo != -1 && is_readready (rep->rtmo)==0) throw sockerr (ETIMEDOUT, "sockbuf::recv", sockname.text.c_str()); if (rep->oob && atmark ()) throw sockoob (); int rval = 0; if ((rval = ::recv (rep->sock, (char*) buf, len, msgf)) == -1) throw sockerr (errno, "sockbuf::recv", sockname.text.c_str()); return rval; }
void sockbuf::closeonexec (bool set) const // if set is true, set close on exec flag // else clear close on exec flag { #if !defined( __sgi) && !defined(__hpux) if (set) { if (::ioctl (rep->sock, FIOCLEX, 0) == -1) throw sockerr (errno, "sockbuf::closeonexec", sockname.text.c_str()); } else { if (::ioctl (rep->sock, FIONCLEX, 0) == -1) throw sockerr (errno, "sockbuf::closeonexec", sockname.text.c_str()); } #endif }
long sockbuf::nread () const // return how many chars are available for reading in the recvbuf of // the socket. { long arg; #if defined(__CYGWIN__) || !defined(WIN32) if (::ioctl (rep->sock, FIONREAD, &arg) == -1) throw sockerr (errno, "sockbuf::nread", sockname.text.c_str()); #else if (::ioctlsocket (rep->sock, FIONREAD, (unsigned long *) &arg) == SOCKET_ERROR) throw sockerr (WSAGetLastError(), "sockbuf::nread", sockname.text.c_str()); #endif // !WIN32 return arg; }
bool sockbuf::atmark () const // return true, if the read pointer for socket points to an // out of band data { #if !defined(WIN32) || defined(__CYGWIN__) int arg; if (::ioctl (rep->sock, SIOCATMARK, &arg) == -1) throw sockerr (errno, "sockbuf::atmark", sockname.text.c_str()); #else unsigned long arg = 0; if (::ioctlsocket(rep->sock, SIOCATMARK, &arg) == SOCKET_ERROR) throw sockerr (WSAGetLastError(), "sockbuf::atmark", sockname.text.c_str()); #endif // !WIN32 return arg!=0; }
int sockbuf::getopt (int op, void* buf, int len, int thelevel) const { socklen_t salen = len; if (::getsockopt (rep->sock, thelevel, op, (char*) buf, &salen) == -1) throw sockerr (errno, "sockbuf::getopt", sockname.text.c_str()); return len; }
sockstream sockstreambuf::accept(struct sockaddr *addr, socklen_t *addrlen) { int ret = ::accept(sockfd, addr, addrlen); if (ret < 0) throw sockerr(std::string("accept(): ") + strerror(errno)); return sockstream(ret); }
void sockbuf::nbio (bool set) const // if set is true, set socket to non-blocking io. Henceforth, any // write or read operation will not wait if write or read would block. // The read or write operation will result throwing a sockerr // exception with errno set to EWOULDBLOCK. { #if defined(__CYGWIN__) || !defined(WIN32) int arg = set; if (::ioctl (rep->sock, FIONBIO, &arg) == -1) throw sockerr (errno, "sockbuf::nbio", sockname.text.c_str()); #else unsigned long arg = (set)?1:0; if (::ioctlsocket (rep->sock, FIONBIO, &arg) == -1) throw sockerr (WSAGetLastError(), "sockbuf::nbio", sockname.text.c_str()); #endif // !WIN32 }
sockbuf::sockdesc sockbuf::accept () { int soc = -1; if ((int)(soc = ::accept (rep->sock, 0, 0)) == -1) throw sockerr (errno, "sockbuf::sockdesc", sockname.text.c_str()); return sockdesc (soc); }
int sockbuf::recvfrom (sockAddr& sa, void* buf, int len, int msgf) { if (rep->rtmo != -1 && is_readready (rep->rtmo)==0) throw sockerr (ETIMEDOUT, "sockbuf::recvfrom", sockname.text.c_str()); if (rep->oob && atmark ()) throw sockoob (); int rval = 0; socklen_t __sa_len = sa.size (); if ((rval = ::recvfrom (rep->sock, (char*) buf, len, msgf, sa.addr (), &__sa_len)) == -1) throw sockerr (errno, "sockbuf::recvfrom", sockname.text.c_str()); return rval; }
void sockbuf::async (bool set) const // if set is true, set socket for asynchronous io. If any io is // possible on the socket, the process will get SIGIO { int arg = set; if (::ioctl (rep->sock, FIOASYNC, &arg) == -1) throw sockerr (errno, "sockbuf::async", sockname.text.c_str()); }
int sockbuf::pgrp () const // return the process group id that would receive SIGIO and SIGURG // signals { int arg; if (::ioctl (rep->sock, SIOCGPGRP, &arg) == -1) throw sockerr (errno, "sockbuf::pgrp", sockname.text.c_str()); return arg; }
sockbuf::sockdesc sockbuf::accept (sockAddr& sa) { socklen_t len = sa.size (); int soc = -1; if ((int)(soc = ::accept (rep->sock, sa.addr (), &len)) == -1) throw sockerr (errno, "sockbuf::sockdesc", sockname.text.c_str()); return sockdesc (soc); }
int sockbuf::pgrp (int new_pgrp) const // set the process group id that would receive SIGIO and SIGURG signals. // return the old pgrp { int old = pgrp (); if (::ioctl (rep->sock, SIOCSPGRP, &new_pgrp) == -1) throw sockerr (errno, "sockbuf::pgrp", sockname.text.c_str()); return old; }
//------------------------------------------------------------- void CSimpleSocket::Send(const char* data, int len) { int sendDone = 0; while(sendDone < len) { int sent = send(m_Socket, &data[sendDone], len-sendDone, 0); if ( sent == SOCKET_ERROR ) { throw sockerr (WSAGetLastError()); } sendDone += sent; } }
sockbuf::~sockbuf () { overflow (eof); // flush write buffer if (--rep->cnt == 0) { delete [] pbase (); delete [] eback (); #if defined(__CYGWIN__) || !defined(WIN32) int c = close (rep->sock); #else int c = closesocket(rep->sock); #endif delete rep; if (c == SOCKET_ERROR) #if defined(__CYGWIN__) || !defined(WIN32) throw sockerr (errno, "sockbuf::~sockbuf", sockname.text.c_str()); #else throw sockerr(WSAGetLastError(), "sockbuf::~sockbuf", sockname.text.c_str()); #endif } }
void sockstreambuf::open(const char *hname, const char *port) { int ret; struct addrinfo hints, *res; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; if ((ret = getaddrinfo(hname, port, &hints, &res))) throw sockerr(std::string("getaddrinfo(): ") + gai_strerror(ret)); if((sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) < 0) throw sockerr(std::string("socket(): ") + strerror(errno)); if ((ret = connect(sockfd, res->ai_addr, res->ai_addrlen)) < 0) { close(); throw sockerr(std::string("connect(): ") + strerror(errno)); } }
int sockbuf::sendmsg (msghdr* msg, int msgf) // upon error, write throws the number of bytes writen so far instead // of sockerr. { if (rep->stmo != -1 && is_writeready (rep->stmo)==0) throw sockerr (ETIMEDOUT, "sockbuf::sendmsg", sockname.text.c_str()); int wlen = ::sendmsg (rep->sock, msg, msgf); if (wlen == -1) throw 0; return wlen; }
//------------------------------------------------------------- bool CSimpleSocket::Init() { WSADATA wsaData; WORD wVersionRequested = MAKEWORD( 2, 2 ); int err = WSAStartup(wVersionRequested, &wsaData); if(err!=0) { throw sockerr (WSAGetLastError()); return false; } m_Socket = socket( AF_INET, SOCK_STREAM, 0 ); if( m_Socket == INVALID_SOCKET ) { return false; } return true; }
int sockbuf::is_exceptionpending (int wp_sec, int wp_usec) const { fd_set fds; FD_ZERO (&fds); FD_SET (rep->sock, &fds); timeval tv; tv.tv_sec = wp_sec; tv.tv_usec = wp_usec; int ret = select ((int)(rep->sock)+1, 0, 0, &fds, (wp_sec == -1) ? 0: &tv); if (ret == -1) throw sockerr (errno, "sockbuf::is_exceptionpending", sockname.text.c_str()); return ret; }
int poll(sockstream socks[], int nsocks, int timeout) { struct pollfd *fds = new struct pollfd[nsocks]; for (int i = 0; i < nsocks; i++) { fds[i].fd = socks[i]->sockfd; fds[i].events = POLLIN; socks[i]->m_revents = 0; } int ret = poll(fds, nsocks, timeout); if (ret < 0) throw sockerr(std::string("poll(): ") + strerror(errno)); for (int i = 0; i < nsocks; i++) socks[i]->m_revents = fds[i].revents; delete fds; return ret; }
//------------------------------------------------------------- void CSimpleSocket::Read(std::string &buf) { static char buffer[RECV_BUFFER_SIZE]; buf.clear(); while(1) { int bytesRecv = recv( m_Socket, buffer, RECV_BUFFER_SIZE, 0 ); if(bytesRecv == 0) { Close(); break; } else if(bytesRecv == SOCKET_ERROR) { throw sockerr (WSAGetLastError()); } buf.append(buffer, bytesRecv); if(bytesRecv < RECV_BUFFER_SIZE) break; } }
int sockbuf::send (const void* buf, int len, int msgf) // upon error, write throws the number of bytes writen so far instead // of sockerr. { if (rep->stmo != -1 && is_writeready (rep->stmo)==0) throw sockerr (ETIMEDOUT, "sockbuf::send", sockname.text.c_str()); int wlen=0; while(len>0) { int wval = ::send (rep->sock, (char*) buf, len, msgf); if (wval == -1) throw wlen; len -= wval; wlen += wval; } return wlen; }
void sockbuf::shutdown (shuthow sh) { switch (sh) { case shut_read: delete [] eback (); setg (0, 0, 0); break; case shut_write: delete [] pbase (); setp (0, 0); break; case shut_readwrite: shutdown (shut_read); shutdown (shut_write); break; } if (::shutdown(rep->sock, sh) == -1) throw sockerr (errno, "sockbuf::shutdown", sockname.text.c_str()); }
int sockbuf::write(const void* buf, int len) // upon error, write throws the number of bytes writen so far instead // of sockerr. { if (rep->stmo != -1 && is_writeready (rep->stmo)==0) throw sockerr (ETIMEDOUT, "sockbuf::write", sockname.text.c_str()); int wlen=0; while(len>0) { //int wval = ::write (rep->sock, (char*) buf, len); int wval = ::send (rep->sock, (char*) buf, len, 0); //assert( wval > 0 ); if (wval == -1) throw wlen; len -= wval; wlen += wval; } return wlen; // == len if every thing is all right }
int sockbuf::sync () // we never return -1 because we throw sockerr // exception in the event of an error. { if (pptr () && pbase () < pptr () && pptr () <= epptr ()) { // we have some data to flush try { write (pbase (), pptr () - pbase ()); } catch (int wlen) { // write was not completely successful std::stringstream sb; std::string err ("sockbuf::sync"); err += "(" + sockname.text + ")"; if (wlen) { // reposition unwritten chars char* pto = pbase (); char* pfrom = pbase () + wlen; int len = pptr () - pbase () - wlen; while (pfrom < pptr ()) *pto++ = *pfrom++; setp (pbase (), (char_type*) rep->pend); pbump (len); sb << " wlen=(" << wlen << ")"; err += sb.rdbuf()->str(); } throw sockerr (errno, err.c_str ()); } setp (pbase (), (char_type*) rep->pend); } // we cannot restore input data back to the socket stream // thus we do not do anything on the input stream return 0; }
void sockbuf::listen (int num) { if (::listen (rep->sock, num) == -1) throw sockerr (errno, "sockbuf::listen", sockname.text.c_str()); }
void sockbuf::setopt (int op, void* buf, int len, int thelevel) const { if (::setsockopt (rep->sock, thelevel, op, (char*) buf, len) == -1) throw sockerr (errno, "sockbuf::setopt", sockname.text.c_str()); }