📄 sockutil.cpp
字号:
else { connDiagnostic("listening on port " << getLocalPort(s) << " on interface " << formatAddress(interface)); }}// create a listener socket on the specified port and interfaceSOCKET interface_listen_socket(IPAddress interface, int port){ // create the socket and bind it to the interface and port SOCKET s = create_socket(); bind_socket(s, interface, port); // establish that this socket is listening for incoming connections listen_socket(s, interface); return s;}SOCKET interface_listen_socket_range(IPAddress interface, PortRange const &range){ // same sequence of calls as interface_listen_socket SOCKET s = create_socket(); bind_socket_range(s, interface, range); listen_socket(s, interface); return s;}#ifndef SOCKLEN_TYPE // for linux, set it to socklen_t; for other systems, sometimes // it's unsigned long, sometimes it's int; we'll just guess // socklen_t if nothing is specified #define SOCKLEN_TYPE socklen_t#endif// accept a connectionSOCKET accept_socket(SOCKET s){ sockaddr saddr; SOCKLEN_TYPE saddrLen = sizeof(saddr); SOCKET ret = accept(s, &saddr, &saddrLen); if (ret == INVALID_SOCKET) { xsocket(s, "accept"); } incOpenSockets(); connDiagnostic("accepted connection: " << sockInfo(ret)); return ret;}// format an IP address into normal decimal-dot notationstring formatAddress(IPAddress addr){ return stringb( ((addr >> 24) & 0xff) << "." << ((addr >> 16) & 0xff) << "." << ((addr >> 8) & 0xff) << "." << (addr & 0xff) );}string formatAddress(IPAddress addr, int port){ return stringb( formatAddress(addr) << ", port " << port );}// format a socket address into a stringstring formatAddress(sockaddr_in const &saddr){ // extract fields IPAddress ip = ntohl(saddr.sin_addr.s_addr); int port = ntohs(saddr.sin_port); // write buffer return formatAddress(ip, port);}// initiate a connectionSOCKET connect_socket(IPAddress ipaddr, int port, PortRange const *range){ // create address structure sockaddr_in saddr; // address of receiver memset((char *)&saddr, 0, sizeof(saddr)); saddr.sin_family = AF_INET; saddr.sin_port = htons((short)port); // get correct byte ordering saddr.sin_addr.s_addr = htonl(ipaddr); // create the socket SOCKET s = create_socket(); // bind the socket locally if we've been asked to do so by 'range' if (range) { bind_socket_range(s, ipaddr, *range); } // connect the socket to the resolved address and port (sockaddr) if (connect(s, (sockaddr *)&saddr, sizeof(saddr)) == SOCKET_ERROR) { xsocket(s, "connect", true /*close*/); } connDiagnostic("connected: " << sockInfo(s)); return s;}void close_socket(SOCKET s){ #if DIAGNOSTIC && CONN_DIAGNOSTIC int port; try { port = getLocalPort(s); connDiagnostic("closing: " << sockInfo(s)); } catch (...) {} // I don't care--the next will probably throw anyway #endif if (closesocket(s) == SOCKET_ERROR) { xsocket(s, "closesocket"); } decOpenSockets();}bool pollReadable(SOCKET s){ // make a SocketSet of one, and use its fn SocketSet set; set.add(s); return set.pollReadable() > 0; // it returns # of readable sockets}bool isClosed(SOCKET s){ // first, test to see if recv will block if (!pollReadable(s)) { // isn't readable, therefore can't be closed // (or at least our OS can't have detected it) return false; } char c; int len = recv(s, &c, 1, MSG_PEEK); if (len == 0) { // socket closed connDiagnostic("detected closed: " << sockInfo(s)); return true; } else if (len == SOCKET_ERROR) { // some error xsocket(s, "recv(MSG_PEEK)"); } // not closed return false;}// throw a particular exception if it's closedvoid checkClosed(SOCKET s){ if (isClosed(s)) { xsocketClosed(s); }}void getSockName(SOCKET s, sockaddr_in &addr){ SOCKLEN_TYPE namelen = sizeof(sockaddr_in); if (getsockname(s, (sockaddr*)&addr, &namelen) == SOCKET_ERROR) { xsocket(s, "getsockname"); }}IPAddress getLocalAddress(SOCKET s){ sockaddr_in saddr; getSockName(s, saddr); return ntohl(saddr.sin_addr.s_addr);}int getLocalPort(SOCKET s){ sockaddr_in saddr; getSockName(s, saddr); return ntohs(saddr.sin_port);}void getSockPeer(SOCKET s, sockaddr_in &addr){ SOCKLEN_TYPE namelen = sizeof(sockaddr_in); if (getpeername(s, (sockaddr*)&addr, &namelen) == SOCKET_ERROR) { xsocket(s, "getpeername"); }}IPAddress getRemoteAddress(SOCKET s){ sockaddr_in saddr; getSockPeer(s, saddr); return ntohl(saddr.sin_addr.s_addr);}int getRemotePort(SOCKET s){ sockaddr_in saddr; getSockPeer(s, saddr); return ntohs(saddr.sin_port);}void printSocketInfo(SOCKET s){ sockaddr_in saddr; // get, display local name getSockName(s, saddr); printf(" local name: %s\n", (char const*)formatAddress(saddr)); // get, display remote name try { getSockPeer(s, saddr); printf(" remote name: %s\n", (char const*)formatAddress(saddr)); } catch (...) { printf(" (not connected)\n"); }}bool isListening(SOCKET s){ #ifdef SO_ACCEPTCONN long retval; SOCKLEN_TYPE retvalLen = sizeof(retval); int err = getsockopt(s, SOL_SOCKET, SO_ACCEPTCONN, (char*)&retval, &retvalLen); if (err == SOCKET_ERROR) { xsocket(s, "getsockopt"); } return retval != 0; #else // turns out some systems don't have an easy way to detect // if something is a listener (maybe winsock is only that does?) // for now, I can tolerate simply not having this information return false; #endif}// this is a separate fn so we can use 'return' to// end collection of information but finish sockInfo normallyvoid sockInfoHelper(SOCKET s, stringBuilder &sb){ // test for special value if (s == INVALID_SOCKET) { sb << "invalid socket"; return; } // local address sb << formatAddress(getLocalAddress(s)) << ":" << getLocalPort(s) << " - "; // listening? if (isListening(s)) { sb << "(listener)"; return; } // remote address sb << formatAddress(getRemoteAddress(s)) << ":" << getRemotePort(s);}// catch-all info retrievalstring sockInfo(SOCKET s){ // for accumulating results stringBuilder sb; sb << "["; // I don't want exceptions here dirtying up my output bool prev = xBase::logExceptions; xBase::logExceptions = false; try { sockInfoHelper(s, sb); } catch (xBase &x) { sb << "(" << x.why() << ")"; } xBase::logExceptions = prev; sb << "]"; return sb;}int getServByName(char const *serviceName){ struct servent *se = getservbyname(serviceName, "tcp"); if (!se) { return 0; // not found } int port = ntohs((short)se->s_port); return port;}IPAddress resolveHostName(char const *hostname){ xassert(hostname); // check for dotted decimal try { // if it is dotted decimal, this will simply parse it and return return parseDottedDecimal(hostname); } catch (...) {} // not a valid decimal addr; go on to try DNS // invoke the Domain Name Service (DNS) // NOTE: This is a blocking operation, and may timeout only after // a substantial period of time. hostent *he = gethostbyname(hostname); if (he == NULL) { xResolveFailure x(hostname); THROW(x); } else { // if multiple addresses are returned, we only return the first return ntohl( *((unsigned long const*)he->h_addr_list[0]) ); }}// --------------------- parsing ----------------------IPAddress parseDottedDecimal(char const *decimalAddr){ IPAddress ret = ntohl(inet_addr(decimalAddr)); if (ret == INADDR_NONE) { xfailure("inet_addr: invalid dotted-decimal address"); } return ret; #if 0 // this is supposedly the right way but some systems don't // yet have inet_aton struct in_addr addr; if (!inet_aton(decimalAddr, &addr)) { xfailure("inet_aton: invalid dotted-decimal address"); } return ntohl(addr.s_addr); #endif // 0}void parseAddrAndPort(IPAddress &ipaddr, int &port, char const *addrAndPort){ // separate on a colon, if present StrtokParse tok(addrAndPort, ":"); if (tok == 2) { // has both an IP address and a port ipaddr = parseDottedDecimal(tok[0]); port = atoi(tok[1]); } else if (tok == 1) { // only a port is supplied ipaddr = INADDR_ANY; port = atoi(tok[0]); } else { // wrong format xfailure("parseAddrAndPort: address must be AAA.BBB.CCC.DDD:PPPP or PPPP format"); }}// ------------------ SocketSet ------------------------------------// timeout of 0 means poll without blocking// (this is expected to be const, but I don't tag// it as such for same reason 'timeout' parameter// to select is not so tagged (see sockutil.h))timeval SocketSet::timeZero = {0, 0};SocketSet::SocketSet(){ reset();}SocketSet::~SocketSet(){}bool SocketSet::contains(SOCKET s) const{ // on unix, we segfault if we test INVALID_SOCKET if (s == INVALID_SOCKET) { return false; } // FD_ISSET declared incorrectly in OSF1 system header files (doesn't mention const for fd_set*) return !!FD_ISSET(s, ((fd_set*)&set));}void SocketSet::add(SOCKET s){ // this fn won't work after select is called xassert(!used); // silently filter out INVALID_SOCKETs if (s == INVALID_SOCKET) { return; } FD_SET(s, &set); maxSocket = mymax(maxSocket, (unsigned)s); numSockets++;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -