kextsock.cpp
来自「konqueror3 embedded版本, KDE环境下的当家浏览器的嵌入式版」· C++ 代码 · 共 2,230 行 · 第 1/4 页
CPP
2,230 行
d->ipv6only = enable; if (sockfd == -1) return true; // can't set on a non-existing socket int on = enable; if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&on, sizeof(on)) == -1) { setError(IO_UnspecifiedError, errno); return false; } else return true;#else // we don't have the IPV6_V6ONLY constant in this system d->ipv6only = enable; setError(IO_UnspecifiedError, ENOSYS); return false; // can't set if we don't know about this flag#endif}/* * retrieve the IPV6_V6ONLY flag */bool KExtendedSocket::isIPv6Only(){#ifdef IPV6_V6ONLY cleanError(); if (d->status < created || sockfd == -1) return d->ipv6only; int on; socklen_t onsiz = sizeof(on); if (getsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&on, &onsiz) == -1) { setError(IO_UnspecifiedError, errno); return false; } return d->ipv6only = on;#else // we don't have the constant setError(IO_UnspecifiedError, ENOSYS); return false;#endif}/* * Sets the buffer sizes in this socket * Also, we create or delete the socket notifiers */bool KExtendedSocket::setBufferSize(int rsize, int wsize){ cleanError(); if (d->status < created) return false; if (sockfd == -1) return false; if (d->flags & passiveSocket) return false; // no I/O on passive sockets if (rsize < -2) return false; if (wsize < -2) return false; // LOCK BUFFER MUTEX // The input socket notifier is always enabled // That happens because we want to be notified of when the socket gets // closed if (d->qsnIn == NULL) { d->qsnIn = new QSocketNotifier(sockfd, QSocketNotifier::Read); QObject::connect(d->qsnIn, SIGNAL(activated(int)), this, SLOT(socketActivityRead())); d->qsnIn->setEnabled(true); } if (rsize == 0 && d->flags & inputBufferedSocket) { // user wants to disable input buffering d->flags &= ~inputBufferedSocket; consumeReadBuffer(readBufferSize(), NULL, true); d->inMaxSize = 0; } else if (rsize != -2) { // enabling input buffering if (rsize) d->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 (wsize == 0 && d->flags & outputBufferedSocket) { // disabling output buffering d->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) d->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) | ((d->flags & bufferedSocket) ? 0 : IO_Raw)); // check we didn't turn something off we shouldn't if (d->emitWrite && d->qsnOut == NULL) { d->qsnOut = new QSocketNotifier(sockfd, QSocketNotifier::Write); QObject::connect(d->qsnOut, SIGNAL(activated(int)), this, SLOT(socketActivityWrite())); } 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 (d->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 behavior on connectionless sockets is not defined here. */const ::KSocketAddress* KExtendedSocket::peerAddress(){ if (d->peer != NULL) return d->peer; if (d->flags & passiveSocket || d->status < connected) return NULL; return d->peer = peerAddress(sockfd);}/* * Perform the lookup on the addresses given */int KExtendedSocket::lookup(){ if (startAsyncLookup() != 0) return -1; if (!d->resRemote.wait() || !d->resLocal.wait()) { d->status = nothing; return -1; } d->status = lookupDone; if (d->resRemote.error() != KResolver::NoError) return d->resRemote.error(); if (d->resLocal.error() != KResolver::NoError) return d->resLocal.error(); return 0;}/* * Performs an asynchronous lookup on the given address(es) */int KExtendedSocket::startAsyncLookup(){ cleanError(); if (d->status > lookupInProgress) return -1; if (d->status == lookupInProgress) // already in progress return 0; /* check socket type flags */ int socktype, familyMask, flags; if (!process_flags(d->flags, socktype, familyMask, flags)) return -2; // perform the global lookup before if (!d->resRemote.isRunning()) { d->resRemote.setFlags(flags); d->resRemote.setFamily(familyMask); d->resRemote.setSocketType(socktype); QObject::connect(&d->resRemote, SIGNAL(finished(KResolverResults)), this, SLOT(dnsResultsReady())); if (!d->resRemote.start()) { setError(IO_LookupError, d->resRemote.error()); return d->resRemote.error(); } } if ((d->flags & passiveSocket) == 0 && !d->resLocal.isRunning()) { /* keep flags, but make this passive */ flags |= KResolver::Passive; d->resLocal.setFlags(flags); d->resLocal.setFamily(familyMask); d->resLocal.setSocketType(socktype); QObject::connect(&d->resLocal, SIGNAL(finished(KResolverResults)), this, SLOT(dnsResultsReady())); if (!d->resLocal.start()) { setError(IO_LookupError, d->resLocal.error()); return d->resLocal.error(); } } // if we are here, there were no errors if (d->resRemote.isRunning() || d->resLocal.isRunning()) d->status = lookupInProgress; // only if there actually is a running lookup else { d->status = lookupDone; emit lookupFinished(d->resRemote.results().count() + d->resLocal.results().count()); } return 0;}void KExtendedSocket::cancelAsyncLookup(){ cleanError(); if (d->status != lookupInProgress) return; // what's to cancel? d->status = nothing; d->resLocal.cancel(false); d->resRemote.cancel(false);}int KExtendedSocket::listen(int N){ cleanError(); if ((d->flags & passiveSocket) == 0 || d->status >= listening) return -2; if (d->status < lookupDone) if (lookup() != 0) return -2; // error! if (d->resRemote.error()) return -2; // doing the loop: KResolverResults::const_iterator it; KResolverResults res = d->resRemote.results(); for (it = res.begin(); it != res.end(); ++it) { //kdDebug(170) << "Trying to listen on " << (*it).address().toString() << endl; sockfd = ::socket((*it).family(), (*it).socketType(), (*it).protocol()); if (sockfd == -1) { // socket failed creating //kdDebug(170) << "Failed to create: " << perror << endl; continue; } fcntl(sockfd, F_SETFD, FD_CLOEXEC); if (d->addressReusable) setAddressReusable(sockfd, true); setIPv6Only(d->ipv6only); cleanError(); if (KSocks::self()->bind(sockfd, (*it).address().address(), (*it).length()) == -1) { //kdDebug(170) << "Failed to bind: " << perror << endl; ::close(sockfd); sockfd = -1; continue; } // ok, socket has bound // kdDebug(170) << "Socket bound: " << sockfd << endl; d->status = bound; break; } if (sockfd == -1) { setError(IO_ListenError, errno); //kdDebug(170) << "Listen error - sockfd is -1 " << endl; return -1; } d->status = bound; setFlags(IO_Sequential | IO_Raw | IO_ReadWrite); int retval = KSocks::self()->listen(sockfd, N); if (retval == -1) setError(IO_ListenError, errno); else { d->status = listening; d->qsnIn = new QSocketNotifier(sockfd, QSocketNotifier::Read); QObject::connect(d->qsnIn, SIGNAL(activated(int)), this, SLOT(socketActivityRead())); } return retval == -1 ? -1 : 0;}int KExtendedSocket::accept(KExtendedSocket *&sock){ cleanError(); sock = NULL; if ((d->flags & passiveSocket) == 0 || d->status >= accepting) return -2; if (d->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; } fcntl(newfd, F_SETFD, FD_CLOEXEC); //kdDebug(170).form("Socket %d accepted socket %d\n", sockfd, newfd); setBlockingMode(block); // restore blocking mode sock = new KExtendedSocket; sock->d->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 (d->flags & passiveSocket || d->status >= connected) return -2; if (d->status < lookupDone) if (lookup() != 0) return -2; 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",// d->timeout.tv_sec, d->timeout.tv_usec, end.tv_sec, end.tv_usec); } KResolverResults remote = d->resRemote.results(), local = d->resLocal.results(); KResolverResults::const_iterator it, it2; //kdDebug(170) << "Starting connect to " << host() << '|' << port() // << ": have " << local.count() << " local entries and " // << remote.count() << " remote" << endl; for (it = remote.begin(), it2 = local.begin(); it != remote.end(); ++it) { //kdDebug(170) << "Trying to connect to " << (*it).address().toString() << endl; if (it2 != local.end()) {// //kdDebug(170) << "Searching bind socket for family " << p->ai_family << endl; if ((*it).family() != (*it2).family()) // differing families, scan local for a matching family for (it2 = local.begin(); it2 != local.end(); ++it2) if ((*it).family() == (*it2).family()) break; if ((*it).family() != (*it2).family()) { // no matching families for this //kdDebug(170) << "No matching family for bind socket\n"; it2 = local.begin(); continue; } //kdDebug(170) << "Binding on " << (*it2).address().toString() << " before connect" << endl; errno = 0; sockfd = ::socket((*it).family(), (*it).socketType(), (*it).protocol()); setError(IO_ConnectError, errno); if (sockfd == -1) continue; // cannot create this socket fcntl(sockfd, F_SETFD, FD_CLOEXEC); if (d->addressReusable) setAddressReusable(sockfd, true); setIPv6Only(d->ipv6only); cleanError(); if (KSocks::self()->bind(sockfd, (*it2).address(), (*it2).length())) { //kdDebug(170) << "Bind failed: " << perror << endl; ::close(sockfd); sockfd = -1; continue; } } else { // no need to bind, just create sockfd = ::socket((*it).family(), (*it).socketType(), (*it).protocol()); if (sockfd == -1) { setError(IO_ConnectError, errno); continue; } fcntl(sockfd, F_SETFD, FD_CLOEXEC); if (d->addressReusable) setAddressReusable(sockfd, true); setIPv6Only(d->ipv6only); cleanError(); }// kdDebug(170) << "Socket " << sockfd << " created" << endl; d->status = created; // check if we have to do timeout if (doingtimeout && KSocks::self()->hasWorkingAsyncConnect()) { fd_set rd, wr; setBlockingMode(false); // now try and connect if (KSocks::self()->connect(sockfd, (*it).address(), (*it).length()) == -1) { // this could be EWOULDBLOCK if (errno != EWOULDBLOCK && errno != EINPROGRESS) { //kdDebug(170) << "Socket " << sockfd << " did not connect: " << perror << endl; setError(IO_ConnectError, errno); ::close(sockfd); sockfd = -1; continue; // nope, another error } FD_ZERO(&rd); FD_ZERO(&wr); FD_SET(sockfd, &rd); FD_SET(sockfd, &wr); int retval = KSocks::self()->select(sockfd + 1, &rd, &wr, NULL, &d->timeout); if (retval == -1) { setError(IO_FatalError, errno); continue; // system error } else if (retval == 0) { ::close(sockfd); sockfd = -1;// kdDebug(170) << "Time out while trying to connect to " <<// (*it).address().toString() << endl; d->status = lookupDone; setError(IO_TimeOutError, 0); return -3; // time out } // adjust remaining time gettimeofday(&now, NULL);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?