kextsock.cpp
来自「将konqueror浏览器移植到ARM9 2410中」· C++ 代码 · 共 2,280 行 · 第 1/4 页
CPP
2,280 行
* returns the binding port */QString KExtendedSocket::bindPort() const{ return d->localservice;}/* * sets the binding address */bool KExtendedSocket::setBindAddress(const QString& host, int port){ return setBindHost(host) && setBindPort(port);}/* * same */bool KExtendedSocket::setBindAddress(const QString& host, const QString& service){ return setBindHost(host) && setBindPort(service);}/* * unsets binding address */bool KExtendedSocket::unsetBindAddress(){ return unsetBindHost() && unsetBindPort();}/* * sets the timeout for the connection */bool KExtendedSocket::setTimeout(int secs, int usecs){ if (m_status >= connected) // closed? return false; d->timeout.tv_sec = secs; d->timeout.tv_usec = usecs; return true;}/* * returns the timeout */timeval KExtendedSocket::timeout() const{ return d->timeout; }/* * Sets the blocking mode on this socket */bool KExtendedSocket::setBlockingMode(bool enable){ cleanError(); if (m_status < created) return false; if (sockfd == -1) return false; // error! int fdflags = fcntl(sockfd, F_GETFL, 0); if (fdflags == -1) return false; // error! if (!enable) fdflags |= O_NONBLOCK; else fdflags &= ~O_NONBLOCK; if (fcntl(sockfd, F_SETFL, fdflags) == -1) { setError(IO_UnspecifiedError, errno); return false; } return true;}/* * Returns the blocking mode on the socket */bool KExtendedSocket::blockingMode(){ cleanError(); if (m_status < created) return false; // sockets not created are in blocking mode if (sockfd == -1) return false; // error int fdflags = fcntl(sockfd, F_GETFL, 0); if (fdflags == -1) { setError(IO_UnspecifiedError, errno); return false; } return (fdflags & O_NONBLOCK) == 0; // non-blocking == false}/* * Sets the reusability flag for this socket in the OS */bool KExtendedSocket::setAddressReusable(bool enable){ cleanError(); if (m_status < created) return false; if (sockfd == -1) return false; // error! int on = (int)enable; // just to be on the safe side if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char*)&on, sizeof(on)) == -1) { setError(IO_UnspecifiedError, errno); return false; } return true;}/* * Retrieves the reusability flag for this socket */bool KExtendedSocket::addressReusable(){ cleanError(); if (m_status < created) return false; if (sockfd == -1) return false; int on; socklen_t onsiz = sizeof(on); if (getsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char*)&on, &onsiz) == -1) { setError(IO_UnspecifiedError, errno); return false; } return on != 0;}/* * Sets the buffer sizes in this socket * Also, we create or delete the socket notifiers */bool KExtendedSocket::setBufferSize(int rsize, int wsize){ cleanError(); if (m_status < created) return false; if (sockfd == -1) return false; if (m_flags & passiveSocket) return false; // no I/O on passive sockets if (rsize < -2) return false; if (wsize < -2) return false; // LOCK BUFFER MUTEX if (rsize == 0 && m_flags & inputBufferedSocket) { // user wants to disable input buffering m_flags &= ~inputBufferedSocket; if (d->qsnIn && !d->emitRead) d->qsnIn->setEnabled(false); consumeReadBuffer(readBufferSize(), NULL, true); d->inMaxSize = 0; } else if (rsize != -2) { // enabling input buffering if (rsize) m_flags |= inputBufferedSocket; d->inMaxSize = rsize; if (rsize > 0 && (unsigned)rsize < readBufferSize()) // input buffer has more data than the new size; discard consumeReadBuffer(readBufferSize() - rsize, NULL, true); if (d->qsnIn == NULL) { d->qsnIn = new QSocketNotifier(sockfd, QSocketNotifier::Read); QObject::connect(d->qsnIn, SIGNAL(activated(int)), this, SLOT(socketActivityRead())); } } if (wsize == 0 & m_flags & outputBufferedSocket) { // disabling output buffering m_flags &= ~outputBufferedSocket; if (d->qsnOut && !d->emitWrite) d->qsnOut->setEnabled(false); consumeWriteBuffer(writeBufferSize()); d->outMaxSize = 0; } else if (wsize != -2) { // enabling input buffering if (wsize) m_flags |= outputBufferedSocket; d->outMaxSize = wsize; if (wsize > 0 && (unsigned)wsize < writeBufferSize()) // output buffer is bigger than it is to become; shrink consumeWriteBuffer(writeBufferSize() - wsize); if (d->qsnOut == NULL) { d->qsnOut = new QSocketNotifier(sockfd, QSocketNotifier::Write); QObject::connect(d->qsnOut, SIGNAL(activated(int)), this, SLOT(socketActivityWrite())); // if the class is being created now, there's nothing to write yet // so socketActivityWrite() will get called once and disable // the notifier } } // UNLOCK BUFFER MUTEX setFlags((mode() & ~IO_Raw) | ((m_flags & bufferedSocket) ? 0 : IO_Raw)); return true;}/* * Finds the local address for this socket * if we have done this already, we return it. Otherwise, we'll have * to find the socket name */const KSocketAddress *KExtendedSocket::localAddress(){ if (d->local != NULL) return d->local; if (m_status < bound) return NULL; return d->local = localAddress(sockfd);}/* * Same thing, but for peer address. Which means this does not work on * passiveSocket and that we require to be connected already. Also note that * the behaviour on connectionless sockets is not defined here. */const KSocketAddress* KExtendedSocket::peerAddress(){ if (d->peer != NULL) return d->peer; if (m_flags & passiveSocket || m_status < connected) return NULL; return d->peer = peerAddress(sockfd);}/* * Perform the lookup on the addresses given */int KExtendedSocket::lookup(){ cleanError(); if (m_status >= lookupInProgress) return EAI_BADFLAGS; // we needed an error... addrinfo hint; memset(&hint, 0, sizeof(hint)); hint.ai_family = AF_UNSPEC; // perform the global lookup before if (d->resolution == NULL) { /* check socket type flags */ if (!process_flags(m_flags, hint)) return EAI_BADFLAGS; int err = doLookup(d->host, d->service, hint, &d->resolution); if (err != 0) { setError(IO_LookupError, err); return err; } } if (d->bindres == NULL && (d->localhost.length() > 0 || d->localservice.length() > 0)) { /* leave hint.ai_socktype the same */ hint.ai_flags |= AI_PASSIVE; // this is passive, for bind() int err = doLookup(d->localhost, d->localservice, hint, &d->bindres); if (err != 0) { setError(IO_LookupError, err); return err; } } m_status = lookupDone; return 0;}/* * Performs an asynchronous lookup on the given address(es) */int KExtendedSocket::startAsyncLookup(){ cleanError(); if (m_status > lookupInProgress) return -1; if (m_status == lookupInProgress) // already in progress return 0; addrinfo hint; memset(&hint, 0, sizeof(hint)); hint.ai_family = AF_UNSPEC; if (!process_flags(m_flags, hint)) return -1; int n = 0; // number of asynchronous lookups if (d->host.length() > 0) { if ((m_flags & noResolve) == 0) { d->dns = new KExtendedSocketLookup(d->host, d->service, hint); QObject::connect(d->dns, SIGNAL(resultsReady()), this, SLOT(dnsResultsReady())); n++; } else { int err = doLookup(d->host, d->service, hint, &d->resolution); if (err != 0) { setError(IO_LookupError, err); return -1; } } } if (d->localhost.length() > 0) { if ((m_flags & noResolve) == 0) { hint.ai_flags |= AI_PASSIVE; d->dnsLocal = new KExtendedSocketLookup(d->localhost, d->localservice, hint); QObject::connect(d->dnsLocal, SIGNAL(resultsReady()), this, SLOT(dnsResultsReady())); n++; } else { int err = doLookup(d->localhost, d->localservice, hint, &d->bindres); if (err != 0) { // damn! Early error in the lookup setError(IO_LookupError, err); if (d->dns != NULL) { delete d->dns; d->dns = NULL; } return -1; } } } // if we are here, there were no errors if (n) m_status = lookupInProgress; // only if there actually is a running lookup else { m_status = lookupDone; dnsResultsReady(); } return 0;}void KExtendedSocket::cancelAsyncLookup(){ cleanError(); if (m_status != lookupInProgress) return; // what's to cancel? m_status = nothing; if (d->dns) { delete d->dns; d->dns = 0; } if (d->dnsLocal) { delete d->dnsLocal; d->dnsLocal = 0; } local_freeaddrinfo(d->resolution); local_freeaddrinfo(d->bindres);}int KExtendedSocket::listen(int N){ cleanError(); if ((m_flags & passiveSocket) == 0 || m_status >= listening) return -2; if (m_status < lookupDone) if (lookup() < 0) return -2; // error! addrinfo *p; // doing the loop: for (p = d->resolution->data; p; p = p->ai_next) { // check for family restriction if (!valid_family(p, m_flags)) continue; //kdDebug(170) << "Trying to listen on " << pretty_sock(p) << endl; sockfd = ::socket(p->ai_family, p->ai_socktype, p->ai_protocol); if (sockfd == -1) { // socket failed creating kdDebug(170) << "Failed to create: " << perror << endl; continue; } if (KSocks::self()->bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) { kdDebug(170) << "Failed to bind: " << perror << endl; ::close(sockfd); sockfd = -1; continue; } // ok, socket has bound // kdDebug(170) << "Socket bound: " << sockfd << endl; m_status = bound; break; } if (sockfd == -1) { setError(IO_ListenError, errno); kdDebug(170) << "Listen error - sockfd is -1 " << endl; return -1; } m_status = listening; setFlags(IO_Sequential | IO_Raw | IO_ReadWrite); int retval = KSocks::self()->listen(sockfd, N); if (retval == -1) setError(IO_ListenError, errno); return retval == -1 ? -1 : 0;}int KExtendedSocket::accept(KExtendedSocket *&sock){ cleanError(); sock = NULL; if ((m_flags & passiveSocket) == 0 || m_status >= accepting) return -2; if (m_status < listening) if (listen() < 0) return -2; // error! // let's see // if we have a timeout in place, we have to place this socket in non-blocking // mode bool block = blockingMode(); struct sockaddr sa; ksocklen_t len = sizeof(sa); sock = NULL; if (d->timeout.tv_sec > 0 || d->timeout.tv_usec > 0) { fd_set set; setBlockingMode(false); // turn on non-blocking FD_ZERO(&set); FD_SET(sockfd, &set); //kdDebug(170).form("Accepting on %d with %d.%06d second timeout\n", // sockfd, d->timeout.tv_sec, d->timeout.tv_usec); // check if there is anything to accept now int retval = KSocks::self()->select(sockfd + 1, &set, NULL, NULL, &d->timeout); if (retval == -1) { setError(IO_UnspecifiedError, errno); return -1; // system error } else if (retval == 0 || !FD_ISSET(sockfd, &set)) { setError(IO_TimeOutError, 0); return -3; // timeout } } // it's common stuff here int newfd = KSocks::self()->accept(sockfd, &sa, &len); if (newfd == -1) { setError(IO_AcceptError, errno); kdWarning(170) << "Error accepting on socket " << sockfd << ":" << perror << endl; return -1; } //kdDebug(170).form("Socket %d accepted socket %d\n", sockfd, newfd); setBlockingMode(block); // restore blocking mode sock = new KExtendedSocket; sock->m_status = connected; sock->sockfd = newfd; sock->setFlags(IO_Sequential | IO_Raw | IO_ReadWrite | IO_Open | IO_Async); sock->setBufferSize(0, 0); // always unbuffered here. User can change that later return 0;}/* * tries to connect * * FIXME! * This function is critical path. It has to be cleaned up and made faster */int KExtendedSocket::connect(){ cleanError(); if (m_flags & passiveSocket) return -2; if (m_status < lookupDone) if (lookup() < 0) return -2; addrinfo *p, *q; timeval end, now; // Ok, things are a little tricky here // Let me explain // getaddrinfo() will return several different families of sockets // When we have to bind before we connect, we have to make sure we're binding // and connecting to the same family, or things won't work bool doingtimeout = d->timeout.tv_sec > 0 || d->timeout.tv_usec > 0; if (doingtimeout) { gettimeofday(&end, NULL); end.tv_usec += d->timeout.tv_usec; end.tv_sec += d->timeout.tv_sec; if (end.tv_usec > 1000*1000) { end.tv_usec -= 1000*1000; end.tv_sec++; }// kdDebug(170).form("Connection with timeout of %d.%06d seconds (ends in %d.%06d)\n",
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?