// Functionality: // Request UDT to receive data into a file described as "fd", starting from "offset", with expected size of "size". // Parameters: // 0) [out] ofs: The output file stream. // 1) [in] offset: From where to write data; // 2) [in] size: How many data to be received. // 3) [in] block: size of block per write to disk // Returned value: // Actual size of data received. public Int64 recvfile(Stream ofs, Int64 offset, Int64 size, int block) { if (UDT_DGRAM == m_iSockType) throw new CUDTException(5, 10, 0); if (!m_bConnected) throw new CUDTException(2, 2, 0); else if ((m_bBroken || m_bClosing) && (0 == m_pRcvBuffer.getRcvDataSize())) throw new CUDTException(2, 1, 0); if (size <= 0) return 0; CGuard recvguard = new CGuard(m_RecvLock); long torecv = size; int unitsize = block; int recvsize; // positioning... try { ofs.seekp((streamoff)offset); } catch (Exception e) { throw new CUDTException(4, 3); } // receiving... "recvfile" is always blocking while (torecv > 0) { if (ofs.bad() || ofs.fail()) break; while (!m_bBroken && m_bConnected && !m_bClosing && (0 == m_pRcvBuffer.getRcvDataSize())) m_RecvDataCond.WaitOne(-1); if (!m_bConnected) throw new CUDTException(2, 2, 0); else if ((m_bBroken || m_bClosing) && (0 == m_pRcvBuffer.getRcvDataSize())) throw new CUDTException(2, 1, 0); unitsize = (int)((torecv >= block) ? block : torecv); recvsize = m_pRcvBuffer.readBufferToFile(ofs, unitsize); torecv -= recvsize; } return size - torecv; }
// Functionality: // Read a block of data from file and insert it into the sending list. // Parameters: // 0) [in] ifs: input file stream. // 1) [in] len: size of the block. // Returned value: // actual size of data added from the file. public int addBufferFromFile(Stream ifs, int len) { int size = len / m_iMSS; if ((len % m_iMSS) != 0) size++; // dynamically increase sender buffer while (size + m_iCount >= m_iSize) increase(); Block s = m_pLastBlock; int total = 0; for (int i = 0; i < size; ++i) { if (ifs.bad() || ifs.fail() || ifs.eof()) break; int pktlen = len - i * m_iMSS; if (pktlen > m_iMSS) pktlen = m_iMSS; ifs.Read(s.m_pcData, 0, pktlen); if ((pktlen = ifs.gcount()) <= 0) break; s.m_iLength = pktlen; s.m_iTTL = -1; s = s.m_pNext; total += pktlen; } m_pLastBlock = s; lock (m_BufLock) { m_iCount += size; } return total; }
// Functionality: // Request UDT to send out a file described as "fd", starting from "offset", with size of "size". // Parameters: // 0) [in] ifs: The input file stream. // 1) [in] offset: From where to read and send data; // 2) [in] size: How many data to be sent. // 3) [in] block: size of block per read from disk // Returned value: // Actual size of data sent. public Int64 sendfile(Stream ifs, Int64 offset, Int64 size, int block) { if (UDT_DGRAM == m_iSockType) throw new CUDTException(5, 10, 0); if (m_bBroken || m_bClosing) throw new CUDTException(2, 1, 0); else if (!m_bConnected) throw new CUDTException(2, 2, 0); if (size <= 0) return 0; CGuard sendguard = new CGuard(m_SendLock); long tosend = size; int unitsize; // positioning... try { ifs.seekg((streamoff)offset); } catch (Exception e) { throw new CUDTException(4, 1); } // sending block by block while (tosend > 0) { if (ifs.bad() || ifs.fail() || ifs.eof()) break; unitsize = (int)((tosend >= block) ? block : tosend); while (!m_bBroken && m_bConnected && !m_bClosing && (m_iSndBufSize <= m_pSndBuffer.getCurrBufSize())) WaitForSingleObject(m_SendBlockCond, INFINITE); if (m_bBroken || m_bClosing) throw new CUDTException(2, 1, 0); else if (!m_bConnected) throw new CUDTException(2, 2, 0); // record total time used for sending if (0 == m_pSndBuffer.getCurrBufSize()) m_llSndDurationCounter = CClock.getTime(); tosend -= m_pSndBuffer.addBufferFromFile(ifs, unitsize); // insert this socket to snd list if it is not on the list yet m_pSndQueue.m_pSndUList.update(this, false); } return size - tosend; }