diff --git a/lib/comms.cpp b/lib/comms.cpp index 1b4cfe2e..dabea8f0 100644 --- a/lib/comms.cpp +++ b/lib/comms.cpp @@ -357,7 +357,7 @@ namespace Comms{ dataPage.init(userPageName, 0, false, false); if (!dataPage){ std::string host; - Socket::hostBytesToStr(ip.data(), 16, host); + Socket::hostBytesToStr(ip.data(), ip.size(), host); pid_t thisPid; std::deque args; args.push_back(Util::getMyPath() + "MistSession"); diff --git a/lib/socket.cpp b/lib/socket.cpp index abf99a1b..a0972f8a 100644 --- a/lib/socket.cpp +++ b/lib/socket.cpp @@ -1221,7 +1221,7 @@ std::string Socket::Connection::getBoundAddress() const{ /// Gets binary IPv6 address for connection, if available. /// Guaranteed to be either empty or 16 bytes long. -std::string Socket::Connection::getBinHost(){ +std::string Socket::Connection::getBinHost() const{ return getIPv6BinAddr(remoteaddr); } @@ -1726,6 +1726,22 @@ void Socket::UDPConnection::setSocketFamily(int AF_TYPE){\ family = AF_TYPE; } +/// Allocates enough space for the largest type of address we support, so that receive calls can write to it. +void Socket::UDPConnection::allocateDestination(){ + if (destAddr && destAddr_size < sizeof(sockaddr_in6)){ + free(destAddr); + destAddr = 0; + } + if (!destAddr){ + destAddr = malloc(sizeof(sockaddr_in6)); + if (destAddr){ + destAddr_size = sizeof(sockaddr_in6); + memset(destAddr, 0, sizeof(sockaddr_in6)); + ((struct sockaddr_in *)destAddr)->sin_family = AF_UNSPEC; + } + } +} + /// Stores the properties of the receiving end of this UDP socket. /// This will be the receiving end for all SendNow calls. void Socket::UDPConnection::SetDestination(std::string destIp, uint32_t port){ @@ -1824,8 +1840,9 @@ void Socket::UDPConnection::GetDestination(std::string &destIp, uint32_t &port){ /// Gets the properties of the receiving end of this UDP socket. /// This will be the receiving end for all SendNow calls. std::string Socket::UDPConnection::getBinDestination(){ - std::string binList = getIPv6BinAddr(*(sockaddr_in6*)destAddr); - if (binList.size() < 16){ return std::string("\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000", 16); } + std::string binList; + if (destAddr && destAddr_size){binList = getIPv6BinAddr(*(sockaddr_in6*)destAddr);} + if (binList.size() < 16){return std::string("\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000", 16);} return binList.substr(0, 16); }// Socket::UDPConnection GetDestination @@ -2081,12 +2098,14 @@ uint16_t Socket::UDPConnection::bind(int port, std::string iface, const std::str bool Socket::UDPConnection::Receive(){ if (sock == -1){return false;} data.truncate(0); - socklen_t destsize = destAddr_size; - int r = recvfrom(sock, data, data.rsize(), MSG_TRUNC | MSG_DONTWAIT, (sockaddr *)destAddr, &destsize); + sockaddr_in6 addr; + socklen_t destsize = sizeof(addr); + int r = recvfrom(sock, data, data.rsize(), MSG_TRUNC | MSG_DONTWAIT, (sockaddr *)&addr, &destsize); if (r == -1){ if (errno != EAGAIN){INFO_MSG("UDP receive: %d (%s)", errno, strerror(errno));} return false; } + if (destAddr && destsize && destAddr_size >= destsize){memcpy(destAddr, &addr, destsize);} data.append(0, r); down += r; //Handle UDP packets that are too large diff --git a/lib/socket.h b/lib/socket.h index e6366fcd..ddba48ac 100644 --- a/lib/socket.h +++ b/lib/socket.h @@ -134,7 +134,7 @@ namespace Socket{ void setBlocking(bool blocking); ///< Set this socket to be blocking (true) or nonblocking (false). bool isBlocking(); ///< Check if this socket is blocking (true) or nonblocking (false). std::string getHost() const; ///< Gets hostname for connection, if available. - std::string getBinHost(); + std::string getBinHost() const; void setHost(std::string host); ///< Sets hostname for connection manually. std::string getBoundAddress() const; int getSocket(); ///< Returns internal socket number. @@ -216,6 +216,7 @@ namespace Socket{ int getSock(); uint16_t bind(int port, std::string iface = "", const std::string &multicastAddress = ""); void setBlocking(bool blocking); + void allocateDestination(); void SetDestination(std::string hostname, uint32_t port); void GetDestination(std::string &hostname, uint32_t &port); std::string getBinDestination(); diff --git a/lib/urireader.cpp b/lib/urireader.cpp index d096777a..78658c46 100644 --- a/lib/urireader.cpp +++ b/lib/urireader.cpp @@ -277,6 +277,16 @@ namespace HTTP{ return false; } + std::string URIReader::getHost() const{ + if (stateType == HTTP::File){return "";} + return downer.getSocket().getHost(); + } + + std::string URIReader::getBinHost() const{ + if (stateType == HTTP::File){return std::string("\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000", 16);} + return downer.getSocket().getBinHost(); + } + void URIReader::readAll(size_t (*dataCallback)(const char *data, size_t len)){ while (!isEOF()){readSome(dataCallback, 419430);} } @@ -306,42 +316,37 @@ namespace HTTP{ // readsome with callback void URIReader::readSome(size_t wantedLen, Util::DataCallback &cb){ if (isEOF()){return;} + // Files read from the memory-mapped file if (stateType == HTTP::File){ - // dataPtr = mapped + curPos; - uint64_t dataLen = 0; - - if (wantedLen < totalSize){ - if ((wantedLen + curPos) > totalSize){ - dataLen = totalSize - curPos; // restant - // INFO_MSG("file curpos: %llu, dataLen: %llu, totalSize: %llu ", curPos, dataLen, totalSize); - }else{ - dataLen = wantedLen; - } - }else{ - dataLen = totalSize; - } - - std::string t = std::string(mapped + curPos, dataLen); - cb.dataCallback(t.c_str(), dataLen); - + // Simple bounds check, don't read beyond the end of the file + uint64_t dataLen = ((wantedLen + curPos) > totalSize) ? totalSize - curPos : wantedLen; + cb.dataCallback(mapped + curPos, dataLen); curPos += dataLen; - - }else if (stateType == HTTP::HTTP){ - downer.continueNonBlocking(cb); - }else{// streaming mode - int s = downer.getSocket().Received().bytes(wantedLen); - if (!s){ - if (downer.getSocket() && downer.getSocket().spool()){ - s = downer.getSocket().Received().bytes(wantedLen); - }else{ - Util::sleep(50); - return; - } - } - Util::ResizeablePointer buf; - downer.getSocket().Received().remove(buf, s); - cb.dataCallback(buf, s); + return; } + // HTTP-based read from the Downloader + if (stateType == HTTP::HTTP){ + // Note: this function returns true if the full read was completed only. + // It's the reason this function returns void rather than bool. + downer.continueNonBlocking(cb); + return; + } + // Everything else uses the socket directly + int s = downer.getSocket().Received().bytes(wantedLen); + if (!s){ + // Only attempt to read more if nothing was in the buffer + if (downer.getSocket() && downer.getSocket().spool()){ + s = downer.getSocket().Received().bytes(wantedLen); + }else{ + Util::sleep(50); + return; + } + } + // Future optimization: augment the Socket::Buffer to handle a Util::DataCallback as argument. + // Would remove the need for this extra copy here. + Util::ResizeablePointer buf; + downer.getSocket().Received().remove(buf, s); + cb.dataCallback(buf, s); } /// Readsome blocking function. diff --git a/lib/urireader.h b/lib/urireader.h index dc904218..1cca08b2 100644 --- a/lib/urireader.h +++ b/lib/urireader.h @@ -67,6 +67,9 @@ namespace HTTP{ std::string userAgentOverride; + std::string getHost() const; ///< Gets hostname for connection, or [::] if local. + std::string getBinHost() const; ///< Gets binary form hostname for connection, or [::] if local. + private: // Internal state variables bool (*cbProgress)(uint8_t); ///< The progress callback, if any. Not called if set to a null pointer. diff --git a/src/output/output_webrtc.cpp b/src/output/output_webrtc.cpp index b8f0169a..1cef2884 100644 --- a/src/output/output_webrtc.cpp +++ b/src/output/output_webrtc.cpp @@ -836,7 +836,7 @@ namespace Mist{ } // this is necessary so that we can get the remote IP when creating STUN replies. - udp.SetDestination("0.0.0.0", 4444); + udp.allocateDestination(); // we set parseData to `true` to start the data flow. Is also // used to break out of our loop in `onHTTP()`. @@ -1153,7 +1153,7 @@ namespace Mist{ // function. The `webRTCInputOutputThreadFunc()` is basically empty // and all work for the thread is done here. void OutWebRTC::handleWebRTCInputOutputFromThread(){ - udp.SetDestination("0.0.0.0", 4444); + udp.allocateDestination(); while (keepGoing()){ if (!handleWebRTCInputOutput()){Util::sleep(20);} }