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 + -
显示快捷键?