// ---------------------------------------------------------------------- void SocketNs3:: connect() throw(SocketException) { in_addr addr; if (!atoaddr(host_.c_str(), addr)) BailOnSocketError("tcpip::SocketNs3::connect() @ Invalid network address"); sockaddr_in address; memset((char*)&address, 0, sizeof(address)); address.sin_family = AF_INET; address.sin_port = htons(port_); address.sin_addr.s_addr = addr.s_addr; socket_ = static_cast<int>(socket(PF_INET, SOCK_STREAM, 0)); if (socket_ < 0) BailOnSocketError("tcpip::SocketNs3::connect() @ socket"); if (::connect(socket_, (sockaddr const*)&address, sizeof(address)) < 0) BailOnSocketError("tcpip::SocketNs3::connect() @ connect"); if (socket_ >= 0) { int x = 1; setsockopt(socket_, IPPROTO_TCP, TCP_NODELAY, (const char*)&x, sizeof(x)); } }
void Connection::connect() { in_addr* addr = atoaddr( m_Host.c_str() ); if( !addr ) { std::cerr << m_Host.c_str() << std::endl; throw Wobbly( "Invalid network address" ); } sockaddr_in address; memset( (char*)&address, 0, sizeof(address) ); address.sin_family = AF_INET; address.sin_port = htons( m_Port ); address.sin_addr.s_addr = addr->s_addr; m_Sock = socket( AF_INET, SOCK_STREAM, 0 ); if( m_Sock < 0 ) BailOnSocketError( "socket()" ); // printf("Connecting to %s on port %d.\n",inet_ntoa(*addr), port); if( ::connect( m_Sock, (sockaddr const*)&address, sizeof(address) ) < 0 ) BailOnSocketError( "connect()" ); }
bool SocketNs3:: receiveExact(StorageNs3 &msg) throw(SocketException) { /* receive length of vector */ unsigned char* bufLength = new unsigned char[4]; int bytesRead = 0; int readThisTime = 0; while (bytesRead<4) { readThisTime = recv(socket_, (char*)(bufLength + bytesRead), 4-bytesRead, 0); if (readThisTime <= 0) BailOnSocketError("tcpip::SocketNs3::receive() @ recv"); bytesRead += readThisTime; } StorageNs3 length_storage(bufLength,4); int NN = length_storage.readInt() - 4; /* receive vector */ unsigned char* buf = new unsigned char[NN]; bytesRead = 0; readThisTime = 0; while (bytesRead<NN) { readThisTime = recv(socket_, (char*)(buf + bytesRead), NN-bytesRead, 0); if (readThisTime <= 0) BailOnSocketError("tcpip::SocketNs3::receive() @ recv"); bytesRead += readThisTime; } msg.reset(); msg.writePacket(buf, NN); if (verbose_) { cerr << "Rcvd Storage with " << 4 + NN << " bytes via tcpip::SocketNs3: ["; for (int i=0; i < 4; ++i) { cerr << " " << (int)bufLength[i] << " "; } for (int i=0; i < NN; ++i) { cerr << " " << (int)buf[i] << " "; } cerr << "]" << endl; } delete[] buf; delete[] bufLength; return true; }
// ---------------------------------------------------------------------- vector<unsigned char> SocketNs3:: receive(int bufSize) throw(SocketException) { vector<unsigned char> b; if (socket_ < 0) connect(); if (!datawaiting(socket_)) return b; unsigned char* buf = new unsigned char[bufSize]; int a = recv(socket_, (char*)buf, bufSize, 0); if (a <= 0) BailOnSocketError("SocketNs3::receive() @ recv"); b.resize(a); for (int i = 0; i < a; ++i) { b[i] = buf[i]; } if (verbose_) { cerr << "Rcvd " << a << " bytes via SocketNs3: ["; for (int i = 0; i < a; ++i) { cerr << " " << (int)b[i] << " "; } cerr << "]" << endl; } delete[] buf; return b; }
// ---------------------------------------------------------------------- void Socket:: set_blocking(bool blocking) throw(SocketException ) { blocking_ = blocking; if( server_socket_ > 0 ) { #ifdef WIN32 ULONG NonBlock = blocking_ ? 0 : 1; if (ioctlsocket(server_socket_, FIONBIO, &NonBlock) == SOCKET_ERROR) BailOnSocketError("tcpip::Socket::set_blocking() Unable to initialize non blocking I/O"); #else long arg = fcntl(server_socket_, F_GETFL, NULL); if (blocking_) { arg &= ~O_NONBLOCK; } else { arg |= O_NONBLOCK; } fcntl(server_socket_, F_SETFL, arg); #endif } }
void Connection::pump() { if( m_Outstanding.empty() ) return; // no requests outstanding if (m_Sock < 0) { throw Wobbly("Pumping unconnected socket."); } //assert( m_Sock >0 ); // outstanding requests but no connection! if( !datawaiting( m_Sock ) ) return; // recv will block unsigned char buf[ 2048 ]; int a = recv( m_Sock, (char*)buf, sizeof(buf), 0 ); if( a<0 ) BailOnSocketError( "recv()" ); if( a== 0 ) { // connection has closed Response* r = m_Outstanding.front(); r->notifyconnectionclosed(); assert( r->completed() ); delete r; m_Outstanding.pop_front(); // any outstanding requests will be discarded close(); } else { int used = 0; while( used < a && !m_Outstanding.empty() ) { Response* r = m_Outstanding.front(); int u = r->pump( &buf[used], a-used ); // delete response once completed if( r->completed() ) { delete r; m_Outstanding.pop_front(); } used += u; } // NOTE: will lose bytes if response queue goes empty // (but server shouldn't be sending anything if we don't have // anything outstanding anyway) assert( used == a ); // all bytes should be used up by here. } }
// ---------------------------------------------------------------------- void SocketNs3:: init() { #ifdef WIN32 instance_count_++; if (init_windows_sockets_ && !windows_sockets_initialized_) { WSAData wsaData; if (WSAStartup(MAKEWORD(1, 1), &wsaData) != 0) BailOnSocketError("Unable to init WSA Sockets"); windows_sockets_initialized_ = true; } #endif }
// ---------------------------------------------------------------------- void Socket:: send( std::vector<unsigned char> b) throw( SocketException ) { if( socket_ < 0 ) return; size_t numbytes = b.size(); unsigned char *const buf = new unsigned char[numbytes]; for(size_t i = 0; i < numbytes; ++i) { buf[i] = b[i]; } if (verbose_) { cerr << "Send " << numbytes << " bytes via tcpip::Socket: ["; for(size_t i = 0; i < numbytes; ++i) { buf[i] = b[i]; cerr << " " << (int)b[i] << " "; } cerr << "]" << endl; } unsigned char const *buf_ptr = buf; while( numbytes > 0 ) { #ifdef WIN32 int n = ::send( socket_, (const char*)buf_ptr, static_cast<int>(numbytes), 0 ); #else int n = ::send( socket_, buf_ptr, numbytes, 0 ); #endif if( n<0 ) { // BailOnSocketError definitely throws an exception so clear up heap delete[] buf; BailOnSocketError( "send failed" ); } numbytes -= n; buf_ptr += n; } delete[] buf; }
// return true if socket has data waiting to be read bool datawaiting( int sock ) { fd_set fds; FD_ZERO( &fds ); FD_SET( sock, &fds ); struct timeval tv; tv.tv_sec = 0; tv.tv_usec = 0; int r = select( sock+1, &fds, NULL, NULL, &tv); if (r < 0) BailOnSocketError( "select" ); if( FD_ISSET( sock, &fds ) ) return true; else return false; }
// ---------------------------------------------------------------------- vector<unsigned char> Socket:: receive(int bufSize) throw( SocketException ) { vector<unsigned char> b; if( socket_ < 0 ) connect(); if( !datawaiting( socket_) ) return b; unsigned char const * const buf = new unsigned char[bufSize]; int a = recv( socket_, (char*)buf, bufSize, 0 ); if( a <= 0 ) { // BailOnSocketError definitely throws an exception so clear up heap delete[] buf; BailOnSocketError( "tcpip::Socket::receive() @ recv" ); } b.resize(a); for(int i = 0; i < a; ++i) { b[i] = buf[i]; } if (verbose_) { cerr << "Rcvd " << a << " bytes via tcpip::Socket: ["; for(int i = 0; i < a; ++i) { cerr << " " << (int)b[i] << " "; } cerr << "]" << endl; } delete[] buf; return b; }
void Connection::send( const unsigned char* buf, int numbytes ) { // fwrite( buf, 1,numbytes, stdout ); if( m_Sock < 0 ) connect(); while( numbytes > 0 ) { #ifdef WIN32 int n = ::send( m_Sock, (const char*)buf, numbytes, 0 ); #else int n = ::send( m_Sock, buf, numbytes, 0 ); #endif if( n<0 ) BailOnSocketError( "send()" ); numbytes -= n; buf += n; } }
// ---------------------------------------------------------------------- void SocketNs3:: send(std::vector<unsigned char> b) throw(SocketException) { if (socket_ < 0) return; size_t numbytes = b.size(); unsigned char *buf = new unsigned char[numbytes]; unsigned char *buf_ = buf; for (size_t i = 0; i < numbytes; ++i) { buf[i] = b[i]; } if (verbose_) { cerr << "Send " << numbytes << " bytes via SocketNs3: ["; for (size_t i = 0; i < numbytes; ++i) { buf[i] = b[i]; cerr << " " << (int)b[i] << " "; } cerr << "]" << endl; } while (numbytes > 0) { #ifdef WIN32 int n = ::send(socket_, (const char*)buf, static_cast<int>(numbytes), 0); #else int n = ::send(socket_, buf, numbytes, 0); #endif if (n<0) BailOnSocketError("send failed"); numbytes -= n; buf += n; } delete[] buf_; }
// ---------------------------------------------------------------------- void SocketNs3:: accept() throw(SocketException) { if (socket_ >= 0) return; struct sockaddr_in client_addr; #ifdef WIN32 int addrlen = sizeof(client_addr); #else socklen_t addrlen = sizeof(client_addr); #endif if (server_socket_ < 0) { struct sockaddr_in self; //Create the server socket server_socket_ = static_cast<int>(socket(AF_INET, SOCK_STREAM, 0)); if (server_socket_ < 0) BailOnSocketError("SocketNs3::accept() @ socket"); //"Address already in use" error protection { int reuseaddr = 1; #ifdef WIN32 //setsockopt(server_socket_, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuseaddr, sizeof(reuseaddr)); // No address reuse in Windows!!! #else setsockopt(server_socket_, SOL_SOCKET, SO_REUSEADDR, &reuseaddr, sizeof(reuseaddr)); #endif } // Initialize address/port structure memset(&self, 0, sizeof(self)); self.sin_family = AF_INET; self.sin_port = htons(port_); self.sin_addr.s_addr = htonl(INADDR_ANY); // Assign a port number to the socket if (bind(server_socket_, (struct sockaddr*)&self, sizeof(self)) != 0) BailOnSocketError("tcpip::SocketNs3::accept() Unable to create listening socket"); // Make it a "listening socket" if (listen(server_socket_, 10) == -1) BailOnSocketError("tcpip::SocketNs3::accept() Unable to listen on server socket"); // Make the newly created socket blocking or not set_blocking(blocking_); } socket_ = static_cast<int>(::accept(server_socket_, (struct sockaddr*)&client_addr, &addrlen)); if (socket_ >= 0) { int x = 1; setsockopt(socket_, IPPROTO_TCP, TCP_NODELAY, (const char*)&x, sizeof(x)); } }