/*----- PROTECTED REGION ID(Socket2.cpp) ENABLED START -----*/ //============================================================================= // // file : Socket2.cpp // // description : C++ source for the Socket2 class and its commands. // The class is derived from Device. It represents the // CORBA servant object which will be accessed from the // network. All commands which can be executed on the // Socket2 are implemented in this file. // // project : // // This file is part of Tango device class. // // Tango 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 3 of the License, or // (at your option) any later version. // // Tango 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 Tango. If not, see <http://www.gnu.org/licenses/>. // // $Author: alessio $ // // $Revision: 1.26 $ // $Date: 2019-01-10 15:58:04 $ // // $HeadURL: $ // //============================================================================= // This file is generated by POGO // (Program Obviously used to Generate tango Object) //============================================================================= #include <Socket2.h> #include <Socket2Class.h> #include <sys/types.h> #include <sys/socket.h> #include <unistd.h> #include <fcntl.h> #include <sys/ioctl.h> #include <arpa/inet.h> #include <netinet/tcp.h> #include <errno.h> #include <algorithm> #include <ctime> #include <csignal> /*----- PROTECTED REGION END -----*/ // Socket2.cpp /** * Socket2 class description: * */ //================================================================ // The following table gives the correspondence // between command and method names. // // Command name | Method name //================================================================ // Write | write // Read | read // ReadUntil | read_until //================================================================ //================================================================ // Attributes managed are: //================================================================ // InputLength | Tango::DevLong Scalar // OutputLength | Tango::DevLong Scalar // Reconnections | Tango::DevLong Scalar //================================================================ namespace Socket2_ns { /*----- PROTECTED REGION ID(Socket2::namespace_starting) ENABLED START -----*/ // static initializations /*----- PROTECTED REGION END -----*/ // Socket2::namespace_starting //-------------------------------------------------------- /** * Method : Socket2::Socket2() * Description: Constructors for a Tango device * implementing the classSocket2 */ //-------------------------------------------------------- Socket2::Socket2(Tango::DeviceClass *cl, std::string &s) : TANGO_BASE_CLASS(cl, s.c_str()) { /*----- PROTECTED REGION ID(Socket2::constructor_1) ENABLED START -----*/ init_device(); /*----- PROTECTED REGION END -----*/ // Socket2::constructor_1 } //-------------------------------------------------------- Socket2::Socket2(Tango::DeviceClass *cl, const char *s) : TANGO_BASE_CLASS(cl, s) { /*----- PROTECTED REGION ID(Socket2::constructor_2) ENABLED START -----*/ init_device(); /*----- PROTECTED REGION END -----*/ // Socket2::constructor_2 } //-------------------------------------------------------- Socket2::Socket2(Tango::DeviceClass *cl, const char *s, const char *d) : TANGO_BASE_CLASS(cl, s, d) { /*----- PROTECTED REGION ID(Socket2::constructor_3) ENABLED START -----*/ init_device(); /*----- PROTECTED REGION END -----*/ // Socket2::constructor_3 } //-------------------------------------------------------- Socket2::~Socket2() { delete_device(); } //-------------------------------------------------------- /** * Method : Socket2::delete_device() * Description: will be called at device destruction or at init command */ //-------------------------------------------------------- void Socket2::delete_device() { DEBUG_STREAM << "Socket2::delete_device() " << device_name << std::endl; /*----- PROTECTED REGION ID(Socket2::delete_device) ENABLED START -----*/ // Delete device allocated objects close(); /*----- PROTECTED REGION END -----*/ // Socket2::delete_device delete[] attr_InputLength_read; delete[] attr_OutputLength_read; delete[] attr_Reconnections_read; } //-------------------------------------------------------- /** * Method : Socket2::init_device() * Description: will be called at device initialization. */ //-------------------------------------------------------- void Socket2::init_device() { DEBUG_STREAM << "Socket2::init_device() create device " << device_name << std::endl; /*----- PROTECTED REGION ID(Socket2::init_device_before) ENABLED START -----*/ // Initialization before get_device_property() call reconnections = 0; init_error.clear(); /*----- PROTECTED REGION END -----*/ // Socket2::init_device_before // Get the device properties from database get_device_property(); attr_InputLength_read = new Tango::DevLong[1]; attr_OutputLength_read = new Tango::DevLong[1]; attr_Reconnections_read = new Tango::DevLong[1]; // No longer if mandatory property not set. if (mandatoryNotDefined) return; /*----- PROTECTED REGION ID(Socket2::init_device) ENABLED START -----*/ // Disabling SIGPIPE signal if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) init_error = "Fail to ignore SIGPIPE signal"; // Initialize device if (init_error.empty()) { resolve(); open(); check_state(true); } /*----- PROTECTED REGION END -----*/ // Socket2::init_device } //-------------------------------------------------------- /** * Method : Socket2::get_device_property() * Description: Read database to initialize property data members. */ //-------------------------------------------------------- void Socket2::get_device_property() { /*----- PROTECTED REGION ID(Socket2::get_device_property_before) ENABLED START -----*/ // Initialize property data members /*----- PROTECTED REGION END -----*/ // Socket2::get_device_property_before mandatoryNotDefined = false; // Read device properties from database. Tango::DbData dev_prop; dev_prop.push_back(Tango::DbDatum("Hostname")); dev_prop.push_back(Tango::DbDatum("Port")); dev_prop.push_back(Tango::DbDatum("Protocol")); dev_prop.push_back(Tango::DbDatum("Timeout")); dev_prop.push_back(Tango::DbDatum("IOMultiplexing")); // is there at least one property to be read ? if (dev_prop.size()>0) { // Call database and extract values if (Tango::Util::instance()->_UseDb==true) get_db_device()->get_property(dev_prop); // get instance on Socket2Class to get class property Tango::DbDatum def_prop, cl_prop; Socket2Class *ds_class = (static_cast<Socket2Class *>(get_device_class())); int i = -1; // Try to initialize Hostname from class property cl_prop = ds_class->get_class_property(dev_prop[++i].name); if (cl_prop.is_empty()==false) cl_prop >> hostname; else { // Try to initialize Hostname from default device value def_prop = ds_class->get_default_device_property(dev_prop[i].name); if (def_prop.is_empty()==false) def_prop >> hostname; } // And try to extract Hostname value from database if (dev_prop[i].is_empty()==false) dev_prop[i] >> hostname; // Property StartDsPath is mandatory, check if has been defined in database. check_mandatory_property(cl_prop, dev_prop[i]); // Try to initialize Port from class property cl_prop = ds_class->get_class_property(dev_prop[++i].name); if (cl_prop.is_empty()==false) cl_prop >> port; else { // Try to initialize Port from default device value def_prop = ds_class->get_default_device_property(dev_prop[i].name); if (def_prop.is_empty()==false) def_prop >> port; } // And try to extract Port value from database if (dev_prop[i].is_empty()==false) dev_prop[i] >> port; // Property StartDsPath is mandatory, check if has been defined in database. check_mandatory_property(cl_prop, dev_prop[i]); // Try to initialize Protocol from class property cl_prop = ds_class->get_class_property(dev_prop[++i].name); if (cl_prop.is_empty()==false) cl_prop >> protocol; else { // Try to initialize Protocol from default device value def_prop = ds_class->get_default_device_property(dev_prop[i].name); if (def_prop.is_empty()==false) def_prop >> protocol; } // And try to extract Protocol value from database if (dev_prop[i].is_empty()==false) dev_prop[i] >> protocol; // Try to initialize Timeout from class property cl_prop = ds_class->get_class_property(dev_prop[++i].name); if (cl_prop.is_empty()==false) cl_prop >> timeout; else { // Try to initialize Timeout from default device value def_prop = ds_class->get_default_device_property(dev_prop[i].name); if (def_prop.is_empty()==false) def_prop >> timeout; } // And try to extract Timeout value from database if (dev_prop[i].is_empty()==false) dev_prop[i] >> timeout; // Property StartDsPath is mandatory, check if has been defined in database. check_mandatory_property(cl_prop, dev_prop[i]); // Try to initialize IOMultiplexing from class property cl_prop = ds_class->get_class_property(dev_prop[++i].name); if (cl_prop.is_empty()==false) cl_prop >> iOMultiplexing; else { // Try to initialize IOMultiplexing from default device value def_prop = ds_class->get_default_device_property(dev_prop[i].name); if (def_prop.is_empty()==false) def_prop >> iOMultiplexing; } // And try to extract IOMultiplexing value from database if (dev_prop[i].is_empty()==false) dev_prop[i] >> iOMultiplexing; } /*----- PROTECTED REGION ID(Socket2::get_device_property_after) ENABLED START -----*/ // Check device property data members init transform(iOMultiplexing.begin(), iOMultiplexing.end(), iOMultiplexing.begin(), ::tolower); if (iOMultiplexing == "sleep") { multiplexing = SLEEP; } else { multiplexing = SELECT; } transform(protocol.begin(), protocol.end(), protocol.begin(), ::tolower); if (protocol == "udp") { proto = UDP; } else { proto = TCP; } if (port <= 0 || port > 65535) init_error = "Invalid port"; if (timeout <= 0) timeout = 1000; DEBUG_STREAM << "Connecting to " << hostname << " on port " << port << " using " << protocol << " protocol" << " and " << iOMultiplexing << " IO multiplexing type" << " with a timeout of " << timeout << " ms "<< endl; timeout_timeval.tv_sec = timeout / 1000; timeout_timeval.tv_usec = timeout % 1000 * 1000; /*----- PROTECTED REGION END -----*/ // Socket2::get_device_property_after } //-------------------------------------------------------- /** * Method : Socket2::check_mandatory_property() * Description: For mandatory properties check if defined in database. */ //-------------------------------------------------------- void Socket2::check_mandatory_property(Tango::DbDatum &class_prop, Tango::DbDatum &dev_prop) { // Check if all properties are empty if (class_prop.is_empty() && dev_prop.is_empty()) { TangoSys_OMemStream tms; tms << std::endl <<"Property \'" << dev_prop.name; if (Tango::Util::instance()->_UseDb==true) tms << "\' is mandatory but not defined in database"; else tms << "\' is mandatory but cannot be defined without database"; append_status(tms.str()); mandatoryNotDefined = true; /*----- PROTECTED REGION ID(Socket2::check_mandatory_property) ENABLED START -----*/ cerr << tms.str() << " for " << device_name << endl; /*----- PROTECTED REGION END -----*/ // Socket2::check_mandatory_property } } //-------------------------------------------------------- /** * Method : Socket2::always_executed_hook() * Description: method always executed before any command is executed */ //-------------------------------------------------------- void Socket2::always_executed_hook() { DEBUG_STREAM << "Socket2::always_executed_hook() " << device_name << std::endl; if (mandatoryNotDefined) { Tango::Except::throw_exception( (const char *)"PROPERTY_NOT_SET", get_status().c_str(), (const char *)"Socket2::always_executed_hook()"); } /*----- PROTECTED REGION ID(Socket2::always_executed_hook) ENABLED START -----*/ // code always executed before all requests tout = timeout_timeval; if (! init_error.empty()) { set_state(Tango::FAULT); set_status(init_error); DEBUG_STREAM << init_error << endl; } else { check_state(true); } /*----- PROTECTED REGION END -----*/ // Socket2::always_executed_hook } //-------------------------------------------------------- /** * Method : Socket2::read_attr_hardware() * Description: Hardware acquisition for attributes */ //-------------------------------------------------------- void Socket2::read_attr_hardware(TANGO_UNUSED(std::vector<long> &attr_list)) { DEBUG_STREAM << "Socket2::read_attr_hardware(std::vector<long> &attr_list) entering... " << std::endl; /*----- PROTECTED REGION ID(Socket2::read_attr_hardware) ENABLED START -----*/ // Add your own code /*----- PROTECTED REGION END -----*/ // Socket2::read_attr_hardware } //-------------------------------------------------------- /** * Read attribute InputLength related method * * * Data type: Tango::DevLong * Attr type: Scalar */ //-------------------------------------------------------- void Socket2::read_InputLength(Tango::Attribute &attr) { DEBUG_STREAM << "Socket2::read_InputLength(Tango::Attribute &attr) entering... " << std::endl; /*----- PROTECTED REGION ID(Socket2::read_InputLength) ENABLED START -----*/ // Set the attribute value Tango::AttrQuality qual; long len = input_queue_length(); if (len >= 0) { qual = Tango::ATTR_VALID; attr_InputLength_read[0] = len + data.size(); } else { qual = Tango::ATTR_INVALID; attr_InputLength_read[0] = data.size(); } attr.set_value_date_quality(attr_InputLength_read, time(NULL), qual); /*----- PROTECTED REGION END -----*/ // Socket2::read_InputLength } //-------------------------------------------------------- /** * Read attribute OutputLength related method * * * Data type: Tango::DevLong * Attr type: Scalar */ //-------------------------------------------------------- void Socket2::read_OutputLength(Tango::Attribute &attr) { DEBUG_STREAM << "Socket2::read_OutputLength(Tango::Attribute &attr) entering... " << std::endl; /*----- PROTECTED REGION ID(Socket2::read_OutputLength) ENABLED START -----*/ // Set the attribute value Tango::AttrQuality qual; long len = output_queue_length(); if (len >= 0) { qual = Tango::ATTR_VALID; attr_OutputLength_read[0] = len; } else { qual = Tango::ATTR_INVALID; attr_OutputLength_read[0] = 0; } attr.set_value_date_quality(attr_OutputLength_read, time(NULL), qual); /*----- PROTECTED REGION END -----*/ // Socket2::read_OutputLength } //-------------------------------------------------------- /** * Read attribute Reconnections related method * * * Data type: Tango::DevLong * Attr type: Scalar */ //-------------------------------------------------------- void Socket2::read_Reconnections(Tango::Attribute &attr) { DEBUG_STREAM << "Socket2::read_Reconnections(Tango::Attribute &attr) entering... " << std::endl; /*----- PROTECTED REGION ID(Socket2::read_Reconnections) ENABLED START -----*/ // Set the attribute value attr_Reconnections_read[0] = reconnections; attr.set_value(attr_Reconnections_read); /*----- PROTECTED REGION END -----*/ // Socket2::read_Reconnections } //-------------------------------------------------------- /** * Method : Socket2::add_dynamic_attributes() * Description: Create the dynamic attributes if any * for specified device. */ //-------------------------------------------------------- void Socket2::add_dynamic_attributes() { /*----- PROTECTED REGION ID(Socket2::add_dynamic_attributes) ENABLED START -----*/ // Add your own code to create and add dynamic attributes if any /*----- PROTECTED REGION END -----*/ // Socket2::add_dynamic_attributes } //-------------------------------------------------------- /** * Command Write related method * * * @param argin */ //-------------------------------------------------------- void Socket2::write(const Tango::DevVarCharArray *argin) { DEBUG_STREAM << "Socket2::Write() - " << device_name << std::endl; /*----- PROTECTED REGION ID(Socket2::write) ENABLED START -----*/ vector<unsigned char> argin_data; argin_data << *argin; size_t bytes_total = 0, bytes_to_write = argin_data.size(); if (! init_error.empty()) { sleep(tout); Tango::Except::throw_exception( "", init_error.c_str(), __PRETTY_FUNCTION__); } if (max(output_queue_length(), 0) != 0) { close(); resolve(); open(); reconnections += 1; goto error; } while (bytes_total < bytes_to_write) { int s = select(WRITE); if (s == 0) goto timeout; else if (s < 0) goto error; else { /* s > 0 */ } ssize_t bytes_written = _write( fd, argin_data.data() + bytes_total, bytes_to_write - bytes_total); if ( bytes_written > 0) { bytes_total += bytes_written; } else if (bytes_written == 0) { if (multiplexing == SELECT) goto error; /* Continue if multiplexing == SLEEP */ } else { /* bytes_written < 0 */ goto error; } } timeval twait; timerclear(&twait); twait.tv_usec = 1000; while (max(output_queue_length(), 0) != 0) { if (! sleep(twait)) goto timeout; timeradd(&twait, &twait, &twait); } return; error: check_state(false); sleep(tout); timeout: Tango::Except::throw_exception( "", "Timeout expired", __PRETTY_FUNCTION__); /*----- PROTECTED REGION END -----*/ // Socket2::write } //-------------------------------------------------------- /** * Command Read related method * * * @param argin * @returns */ //-------------------------------------------------------- Tango::DevVarCharArray *Socket2::read(Tango::DevLong argin) { Tango::DevVarCharArray *argout; DEBUG_STREAM << "Socket2::Read() - " << device_name << std::endl; /*----- PROTECTED REGION ID(Socket2::read) ENABLED START -----*/ if (! init_error.empty()) { sleep(tout); Tango::Except::throw_exception( "", init_error.c_str(), __PRETTY_FUNCTION__); } if (argin < 0) { sleep(tout); Tango::Except::throw_exception( "", "Out of limit", __PRETTY_FUNCTION__); } _read(argin); argout = new Tango::DevVarCharArray(); vector<unsigned char> transfer(data.begin(), data.begin() + argin); data.erase(data.begin(), data.begin() + argin); *argout << transfer; /*----- PROTECTED REGION END -----*/ // Socket2::read return argout; } //-------------------------------------------------------- /** * Command ReadUntil related method * * * @param argin * @returns */ //-------------------------------------------------------- Tango::DevVarCharArray *Socket2::read_until(const Tango::DevVarCharArray *argin) { Tango::DevVarCharArray *argout; DEBUG_STREAM << "Socket2::ReadUntil() - " << device_name << std::endl; /*----- PROTECTED REGION ID(Socket2::read_until) ENABLED START -----*/ if (! init_error.empty()) { sleep(tout); Tango::Except::throw_exception( "", init_error.c_str(), __PRETTY_FUNCTION__); } if (argin->length() != 1) { sleep(tout); Tango::Except::throw_exception( "", "Delimiter has to be exactly one byte", __PRETTY_FUNCTION__); } char delim = (*argin)[0]; size_t pos = 0, dsize; bool found = false; do { dsize = data.size(); for (; pos < dsize; ++pos) { if (memcmp(&data[pos], &delim, 1) == 0) { found = true; break; } } if (found) break; _read(dsize + 1); } while (true); argout = new Tango::DevVarCharArray(); vector<unsigned char> transfer(data.begin(), data.begin() + pos +1); data.erase(data.begin(), data.begin() + pos + 1); *argout << transfer; /*----- PROTECTED REGION END -----*/ // Socket2::read_until return argout; } //-------------------------------------------------------- /** * Method : Socket2::add_dynamic_commands() * Description: Create the dynamic commands if any * for specified device. */ //-------------------------------------------------------- void Socket2::add_dynamic_commands() { /*----- PROTECTED REGION ID(Socket2::add_dynamic_commands) ENABLED START -----*/ // Add your own code to create and add dynamic commands if any /*----- PROTECTED REGION END -----*/ // Socket2::add_dynamic_commands } /*----- PROTECTED REGION ID(Socket2::namespace_ending) ENABLED START -----*/ // Additional Methods bool Socket2::sleep(timeval tv) { if (! timerisset(&tout)) return false; if (timercmp(&tout, &tv, <)) { ::sleep(tout.tv_sec); usleep(tout.tv_usec); timerclear(&tout); } else { // tout >= tv ::sleep(tv.tv_sec); usleep(tv.tv_usec); timersub(&tout, &tv, &tout); assert(tout.tv_sec >= 0 && tout.tv_usec >= 0); } return true; } void Socket2::open() { DEBUG_STREAM << "Opening the file descriptor..." << endl; if ((fd = socket(PF_INET, proto == UDP? SOCK_DGRAM:SOCK_STREAM, 0)) == -1) { ERROR_STREAM << "Socket creation failed: " << string(strerror(errno)) << endl; return; } if (proto == TCP) { int flag = 1; if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(flag)) == -1) { ::close(fd); ERROR_STREAM << "Disabling Nagle failed: " << string(strerror(errno)) << endl; return; } flag = 1; if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag)) == -1) { ::close(fd); ERROR_STREAM << "Enabling reuseaddr flag failed: " << string(strerror(errno)) << endl; return; } } int flags = fcntl(fd, F_GETFL, 0); if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) { ::close(fd); ERROR_STREAM << "Enabling O_NONBLOCK failed: " << string(strerror(errno)) << endl; return; } connect(fd, (sockaddr*)&sa, sizeof(sockaddr)); } int Socket2::input_queue_length() { int len; if (ioctl(fd, TIOCINQ, &len) == -1) return -1; return len; } int Socket2::output_queue_length() { int len; if (ioctl(fd, TIOCOUTQ, &len) == -1) return -1; return len; } void Socket2::close() { DEBUG_STREAM << "Closing the file descriptor..." << endl; int output_len = max(output_queue_length(), 0); int input_len = max(input_queue_length(), 0) + data.size(); if(input_len + output_len) { WARN_STREAM << " Bytes dropped: " << input_len << " (" << data.size() << ") input, " << output_len << " output" << endl; } if (::close(fd) == -1) { ERROR_STREAM << "Error closing file descriptor: " << strerror(errno) << endl; } data.clear(); } ssize_t Socket2::_write(int fd, const void *buf, size_t count) { errno = 0; int ret = proto == UDP? ::sendto(fd, buf, count, 0, (sockaddr*) &sa, sa_len) : ::write(fd, buf, count); conn_state = errno; return ret; } void Socket2::_read(size_t bytes_to_read) { unsigned char buffer[10000]; size_t bytes_total = data.size(); ssize_t bytes_readed; while (bytes_total < bytes_to_read) { int s = select(READ); if (s == 0) goto timeout; else if (s < 0) goto error; else { /* s > 0 */ } size_t count = min((size_t)max(input_queue_length(), 0), sizeof(buffer)); bytes_readed = proto == UDP? ::recvfrom(fd, buffer, count, 0, (sockaddr*) &sa, &sa_len): ::read(fd, buffer, count); if (bytes_readed > 0) { data.insert(data.end(), &buffer[0], &buffer[bytes_readed]); bytes_total += bytes_readed; } else if (bytes_readed == 0) { if (multiplexing == SELECT) goto error; /* Continue if multiplexing == SLEEP */ } else { /* bytes_readed < 0 */ goto error; } } return; error: check_state(true); sleep(tout); timeout: Tango::Except::throw_exception( "", "Timeout expired", __PRETTY_FUNCTION__); } void Socket2::check_state(bool forcing) { string mesg; if (forcing) (void)_write(fd, NULL, 0); switch(conn_state) { case 0: /* Success */ set_state(Tango::ON); set_status("Connected"); case EINTR: case EAGAIN: return; case EHOSTUNREACH: mesg = "No route to host"; break; case ECONNREFUSED: mesg = "Connection refused"; break; case EPIPE: mesg = "Broken pipe"; break; case ETIMEDOUT: mesg = "Connection timed out"; break; case ECONNRESET: mesg = "Connection reset by peer"; break; case EISCONN: case EALREADY: case EINPROGRESS: case EADDRNOTAVAIL: case EAFNOSUPPORT: case EBADF: case ENOTSOCK: case EPROTOTYPE: case EIO: case ELOOP: case ENAMETOOLONG: case ENOENT: case ENOTDIR: default: ERROR_STREAM << "Socket error " << conn_state << " not handled!" << endl; assert(false); break; } set_state(Tango::INIT); set_status("Reconnecting due: " + mesg); DEBUG_STREAM << "Reconnecting due: " << mesg << endl; close(); resolve(); open(); reconnections += 1; } int Socket2::select(event_type et) { if (multiplexing == SLEEP) { timeval twait; timerclear(&twait); twait.tv_usec = 10000; return sleep(twait); } // multiplexing == SELECT fd_set readfds; fd_set writefds; fd_set errorfds; FD_ZERO(&errorfds); FD_ZERO(&readfds); FD_ZERO(&writefds); FD_SET(fd, &errorfds); switch (et) { case WRITE: FD_SET(fd, &writefds); break; case READ: FD_SET(fd, &readfds); break; } int select_ret = ::select(fd + 1, &readfds, &writefds, &errorfds, &tout); if (FD_ISSET(fd, &errorfds)) { assert(false); return -1; } if (select_ret > 0) { if (et == READ && FD_ISSET(fd, &readfds)) return select_ret; if (et == WRITE && FD_ISSET(fd, &writefds)) return select_ret; assert(false); return -1; } else if (select_ret == 0) { return select_ret; } else { // select_ret < 0 return select_ret; } assert(false); return -1; } void Socket2::resolve() { DEBUG_STREAM << "Resolving " << hostname << "... " << endl; char ipstr[INET6_ADDRSTRLEN]; sa_len = sizeof(sa); memset(&sa, 0, sa_len); addrinfo hints; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; addrinfo *res, *p; if (inet_pton(AF_INET, hostname.c_str(), &(sa.sin_addr)) > 0) { sa.sin_family = AF_INET; sa.sin_port = htons(port); } else if (getaddrinfo(hostname.c_str(), NULL, &hints, &res) == 0) { for (p=res; p!=NULL; p=p->ai_next) { if (p->ai_family == AF_INET) { inet_ntop(p->ai_family, &(((sockaddr_in *)p->ai_addr)->sin_addr), ipstr, sizeof ipstr); sa.sin_addr = ((sockaddr_in *)p->ai_addr)->sin_addr; sa.sin_family = ((sockaddr_in *)p->ai_addr)->sin_family; sa.sin_port = htons(port); } } freeaddrinfo(res); } else { ERROR_STREAM << "Name resolution failed" << endl; } } /*----- PROTECTED REGION END -----*/ // Socket2::namespace_ending } // namespace