Ejemplo n.º 1
0
void CTransferSocket::OnConnect(int nErrorCode)
{
    if (nErrorCode)
    {
        if (m_hFile!=INVALID_HANDLE_VALUE)
        {
            CloseHandle(m_hFile);
            m_hFile = INVALID_HANDLE_VALUE;
        }
        Close();
        if (!m_bSentClose)
        {
            m_bSentClose = TRUE;
            m_status = 2;
            m_pOwner->m_pOwner->PostThreadMessage(WM_FILEZILLA_THREADMSG, FTM_TRANSFERMSG, m_pOwner->m_userid);
        }
        return;
    }

#ifndef NOLAYERS
    if (m_pGssLayer)
        VERIFY(AddLayer(m_pGssLayer));
#endif

    if (!m_bStarted)
        InitTransfer(FALSE);

    CAsyncSocketEx::OnConnect(nErrorCode);
}
Ejemplo n.º 2
0
void CTransferSocket::OnAccept(int nErrorCode)
{
    CAsyncSocketEx tmp;
    Accept(tmp);
    SOCKET socket=tmp.Detach();
    Close();
    Attach(socket);
    bAccepted=TRUE;

#ifndef NOLAYERS
    if (m_pGssLayer)
        VERIFY(AddLayer(m_pGssLayer));
#endif

    if (m_bReady)
        if (!m_bStarted)
            InitTransfer(FALSE);

    CAsyncSocketEx::OnAccept(nErrorCode);
}
Ejemplo n.º 3
0
void CTransferSocket::OnReceive(int nErrorCode)
{
    CAsyncSocketEx::OnReceive(nErrorCode);

    if (nErrorCode)
    {
        Close();
        if (m_hFile != INVALID_HANDLE_VALUE)
        {
            CloseHandle(m_hFile);
            m_hFile = INVALID_HANDLE_VALUE;
        }
        if (!m_bSentClose)
        {
            m_bSentClose=TRUE;
            m_status=3;
            m_pOwner->m_pOwner->PostThreadMessage(WM_FILEZILLA_THREADMSG, FTM_TRANSFERMSG, m_pOwner->m_userid);
        }
        return;
    }

    GetSystemTime(&m_LastActiveTime);
    if (m_nMode==TRANSFERMODE_RECEIVE)
    {
        if (!m_bStarted)
            if (!InitTransfer(FALSE))
                return;

        if (m_hFile == INVALID_HANDLE_VALUE)
        {
            ASSERT(m_Filename!="");
#if defined(_XBOX)
            // this to handle fat-x limitations
            if (g_guiSettings.GetBool("servers.ftpautofatx"))
            {
                /*CUtil::ShortenFileName(m_Filename); // change! addme to new ports
                CStdString strFilename = CUtil::GetFileName(m_Filename);
                CStdString strPath;
                CUtil::GetDirectory(m_Filename,strPath);
                vector<CStdString> tokens;
                CUtil::Tokenize(strPath,tokens,"\\/");
                strPath = tokens.front();
                for (vector<CStdString>::iterator iter=tokens.begin()+1; iter != tokens.end(); ++iter)
                {
                  CUtil::ShortenFileName(*iter);
                  CUtil::RemoveIllegalChars(*iter);
                  strPath += "\\"+*iter;
                }
                CUtil::RemoveIllegalChars(strFilename);
                m_Filename = strPath+"\\"+strFilename;*/
                CUtil::GetFatXQualifiedPath(m_Filename);
            }
            m_hFile = CreateFile(m_Filename, GENERIC_WRITE, FILE_SHARE_READ, 0, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, 0);
#else
            m_hFile = CreateFile(m_Filename, GENERIC_WRITE, FILE_SHARE_READ, 0, OPEN_ALWAYS, 0, 0);
#endif

            if (m_hFile == INVALID_HANDLE_VALUE)
            {
                Close();
                if (!m_bSentClose)
                {
                    m_bSentClose=TRUE;
                    m_status=3;
                    m_pOwner->m_pOwner->PostThreadMessage(WM_FILEZILLA_THREADMSG, FTM_TRANSFERMSG, m_pOwner->m_userid);
                }
                return;
            }

#if defined(_XBOX)
            LARGE_INTEGER size;
            size.QuadPart = m_nRest;
            VERIFY(SetFilePointerEx(m_hFile, size, NULL, FILE_BEGIN));
            SetEndOfFile(m_hFile);
            m_nBufferPos = 0;
            m_nAlign = (4096 - (m_nRest & 4095)) & 4095;

            if (m_pBuffer)
                free(m_pBuffer);
            // Xbox writes ide data in 128k blocks, so always try to write 128k of data at a time.
            // Uses a 160k buffer so there's a bit of overrun as it's more efficient to always try and read 32k+ from the socket.
            // Also allows realignment to page alignment when restarting.
            m_nBufSize = 160*1024;
            m_pBuffer = (char*)malloc(m_nBufSize);
            if (!m_pBuffer)
            {
                CloseHandle(m_hFile);
                m_hFile = INVALID_HANDLE_VALUE;
                Close();
                if (!m_bSentClose)
                {
                    m_bSentClose=TRUE;
                    m_status=6;
                    m_pOwner->m_pOwner->PostThreadMessage(WM_FILEZILLA_THREADMSG, FTM_TRANSFERMSG, m_pOwner->m_userid);
                }
            }
            m_nPreAlloc = 0;
        }
        int len = m_nBufSize - m_nBufferPos;
#else
            DWORD low=(DWORD)(m_nRest&0xFFFFFFFF);
            LONG high=(LONG)(m_nRest>>32);
            VERIFY(SetFilePointer(m_hFile, low, &high, FILE_BEGIN)!=0xFFFFFFFF || GetLastError()==NO_ERROR);
            SetEndOfFile(m_hFile);
        }

        if (!m_pBuffer)
            m_pBuffer = new char[m_nBufSize];

        int len = m_nBufSize;
#endif
        int nLimit = -1;
        if (GetState() != closed)
        {
            nLimit = m_pOwner->GetSpeedLimit(1);
            if (nLimit != -1 && GetState() != aborted && len > nLimit)
                len = nLimit;
        }

        if (!len)
            return;

#if defined(_XBOX)
        int numread = Receive(m_pBuffer + m_nBufferPos, len);
#else
        int numread = Receive(m_pBuffer, len);
#endif

        if (numread==SOCKET_ERROR)
        {
            if (GetLastError()!=WSAEWOULDBLOCK)
            {
                if (m_hFile!=INVALID_HANDLE_VALUE)
                {
                    CloseHandle(m_hFile);
                    m_hFile = INVALID_HANDLE_VALUE;
                }
                Close();
                if (!m_bSentClose)
                {
                    m_bSentClose=TRUE;
                    m_status=1;
                    m_pOwner->m_pOwner->PostThreadMessage(WM_FILEZILLA_THREADMSG, FTM_TRANSFERMSG, m_pOwner->m_userid);
                }
            }
            Sleep(0);
            return;
        }
        if (!numread)
        {
            if (m_hFile != INVALID_HANDLE_VALUE)
            {
#if defined(_XBOX)
                if (m_nBufferPos)
                {
                    DWORD numwritten;
                    WriteFile(m_hFile, m_pBuffer, m_nBufferPos, &numwritten, 0);
                }
                FlushFileBuffers(m_hFile);
                SetEndOfFile(m_hFile);
#endif
                CloseHandle(m_hFile);
                m_hFile = INVALID_HANDLE_VALUE;
            }
            Close();
            if (!m_bSentClose)
            {
                m_bSentClose=TRUE;
                m_status=0;
                m_pOwner->m_pOwner->PostThreadMessage(WM_FILEZILLA_THREADMSG, FTM_TRANSFERMSG, m_pOwner->m_userid);
            }
            return;
        }
        ((CServerThread *)m_pOwner->m_pOwner)->IncRecvCount(numread);

        if (nLimit != -1 && GetState() != aborted)
            m_pOwner->m_SlQuota.nUploaded += numread;

#if defined(_XBOX)
        m_nBufferPos += numread;

        if (m_nBufferPos >= 128*1024 + m_nAlign)
        {
            if (!m_nPreAlloc)
            {
                // pre alloc the file on disk - makes writing much faster due to less FAT updates
                SetFilePointer(m_hFile, 32*1024*1024, 0, FILE_CURRENT);
                SetEndOfFile(m_hFile);
                SetFilePointer(m_hFile, -32*1024*1024, 0, FILE_CURRENT);
                m_nPreAlloc = 32*1024*1024 / (128*1024);
            }

            DWORD numwritten;
            if (!WriteFile(m_hFile, m_pBuffer, 128*1024 + m_nAlign, &numwritten, 0) || numwritten != 128*1024 + m_nAlign)
            {
                CloseHandle(m_hFile);
                m_hFile = INVALID_HANDLE_VALUE;
                Close();
                if (!m_bSentClose)
                {
                    m_bSentClose=TRUE;
                    m_status=3; //TODO: Better reason
                    m_pOwner->m_pOwner->PostThreadMessage(WM_FILEZILLA_THREADMSG, FTM_TRANSFERMSG, m_pOwner->m_userid);
                }
                return;
            }
            else
            {
                if (m_nBufferPos > numwritten)
                {
                    memmove(m_pBuffer, m_pBuffer + numwritten, m_nBufferPos - numwritten);
                }
                m_nBufferPos -= numwritten;
                --m_nPreAlloc;
                m_nAlign = 0;
            }
        }
#else
        DWORD numwritten;
        if (!WriteFile(m_hFile, m_pBuffer, numread, &numwritten, 0) || numwritten!=(unsigned int)numread)
        {
            CloseHandle(m_hFile);
            m_hFile = INVALID_HANDLE_VALUE;
            Close();
            if (!m_bSentClose)
            {
                m_bSentClose=TRUE;
                m_status=3; //TODO: Better reason
                m_pOwner->m_pOwner->PostThreadMessage(WM_FILEZILLA_THREADMSG, FTM_TRANSFERMSG, m_pOwner->m_userid);
            }
            return;
        }
#endif
    }
Ejemplo n.º 4
0
void CTransferSocket::OnSend(int nErrorCode)
{
    CAsyncSocketEx::OnSend(nErrorCode);
    if (nErrorCode)
    {
        if (m_hFile != INVALID_HANDLE_VALUE)
            CloseHandle(m_hFile);
        m_hFile = INVALID_HANDLE_VALUE;
        m_status=1;
        m_pOwner->m_pOwner->PostThreadMessage(WM_FILEZILLA_THREADMSG, FTM_TRANSFERMSG, m_pOwner->m_userid);
        Close();
        return;
    }

    if (m_nMode==TRANSFERMODE_LIST || m_nMode==TRANSFERMODE_NLST)
    {   //Send directory listing
        if (!m_bStarted)
            if (!InitTransfer(TRUE))
                return;
        while (m_pDirListing && m_pDirListing->len)
        {
            int numsend = m_nBufSize;
            if ((m_pDirListing->len - m_nBufferPos) < m_nBufSize)
                numsend = m_pDirListing->len - m_nBufferPos;

            int nLimit = m_pOwner->GetSpeedLimit(0);
            if (nLimit != -1 && GetState() != aborted && numsend > nLimit)
                numsend = nLimit;

            if (!numsend)
                return;

            int numsent = Send(m_pDirListing->buffer + m_nBufferPos, numsend);
            if (numsent==SOCKET_ERROR)
            {
                if (GetLastError()!=WSAEWOULDBLOCK)
                {
                    Close();
                    m_status=1;
                    m_pOwner->m_pOwner->PostThreadMessage(WM_FILEZILLA_THREADMSG, FTM_TRANSFERMSG, m_pOwner->m_userid);
                }
                return;
            }

            if (nLimit != -1 && GetState() != aborted)
                m_pOwner->m_SlQuota.nDownloaded += numsent;

            ((CServerThread *)m_pOwner->m_pOwner)->IncSendCount(numsent);
            GetSystemTime(&m_LastActiveTime);
            if (numsent < numsend)
                m_nBufferPos += numsent;
            else
                m_nBufferPos += numsend;

            ASSERT(m_nBufferPos <= m_pDirListing->len);

            if (m_nBufferPos == m_pDirListing->len)
            {
                t_dirlisting *pPrev = m_pDirListing;
                m_pDirListing = m_pDirListing->pNext;
                delete pPrev;
                m_nBufferPos = 0;

                if (!m_pDirListing)
                    break;
            }

            //Check if there are other commands in the command queue.
            MSG msg;
            if (PeekMessage(&msg,0, 0, 0, PM_NOREMOVE))
            {
                TriggerEvent(FD_WRITE);
                return;
            }
        }
#ifndef NOLAYERS
        if (m_pGssLayer)
            if (!ShutDown() && GetLastError() == WSAEWOULDBLOCK)
                return;
#endif
        Close();
        m_status = 0;
        m_pOwner->m_pOwner->PostThreadMessage(WM_FILEZILLA_THREADMSG, FTM_TRANSFERMSG, m_pOwner->m_userid);
    }
    else if (m_nMode==TRANSFERMODE_SEND)
    {   //Send file
        if (!m_bStarted)
            if (!InitTransfer(TRUE))
                return;
        int count=0;
        while (m_hFile!=INVALID_HANDLE_VALUE || m_nBufferPos)
        {
            count++;
            DWORD numread;
            if (m_nBufSize-m_nBufferPos && m_hFile!=INVALID_HANDLE_VALUE)
            {
                if (!ReadFile(m_hFile, m_pBuffer+m_nBufferPos, m_nBufSize-m_nBufferPos, &numread, 0))
                {
                    CloseHandle(m_hFile);
                    m_hFile = INVALID_HANDLE_VALUE;
                    Close();
                    m_status=3; //TODO: Better reason
                    m_pOwner->m_pOwner->PostThreadMessage(WM_FILEZILLA_THREADMSG, FTM_TRANSFERMSG, m_pOwner->m_userid);
                    return;
                }

                if (!numread)
                {
                    CloseHandle(m_hFile);
                    m_hFile = INVALID_HANDLE_VALUE;
                    if (!m_nBufferPos)
                    {   // only close if we've actually finished!
                        m_status=0;
                        m_pOwner->m_pOwner->PostThreadMessage(WM_FILEZILLA_THREADMSG, FTM_TRANSFERMSG, m_pOwner->m_userid);
                        Close();
                        return;
                    }
                }
                numread+=m_nBufferPos;
                m_nBufferPos=0;
            }
            else
                numread=m_nBufferPos;
            m_nBufferPos=0;

            if (numread<m_nBufSize)
            {
                CloseHandle(m_hFile);
                m_hFile = INVALID_HANDLE_VALUE;
            }

            int numsend = numread;
            int nLimit = m_pOwner->GetSpeedLimit(0);
            if (nLimit != -1 && GetState() != aborted && numsend > nLimit)
                numsend = nLimit;

            if (!numsend)
            {
                m_nBufferPos = numread;
                return;
            }

            int numsent=Send(m_pBuffer, numsend);
            if (numsent==SOCKET_ERROR)
            {
                if (GetLastError()!=WSAEWOULDBLOCK)
                {
                    CloseHandle(m_hFile);
                    m_hFile = INVALID_HANDLE_VALUE;
                    m_status=1;
                    m_pOwner->m_pOwner->PostThreadMessage(WM_FILEZILLA_THREADMSG, FTM_TRANSFERMSG, m_pOwner->m_userid);
                    Close();
                    return;
                }
                m_nBufferPos=numread;
                return;
            }
            else if ((unsigned int)numsent<numread)
            {
                memmove(m_pBuffer, m_pBuffer+numsent, numread-numsent);
                m_nBufferPos=numread-numsent;
            }

            if (nLimit != -1 && GetState() != aborted)
                m_pOwner->m_SlQuota.nDownloaded += numsent;

            ((CServerThread *)m_pOwner->m_pOwner)->IncSendCount(numsent);
            GetSystemTime(&m_LastActiveTime);

            //Check if there are other commands in the command queue.
            MSG msg;
            if (PeekMessage(&msg,0, 0, 0, PM_NOREMOVE))
            {
                TriggerEvent(FD_WRITE);
                return;
            }
        }
#ifndef NOLAYERS
        if (m_pGssLayer)
            if (!ShutDown() && GetLastError() == WSAEWOULDBLOCK)
                return;
#endif
        m_status=0;
        Sleep(0); //Give the system the possibility to relay the data
        //If not using Sleep(0), GetRight for example can't receive the last chunk.
        m_pOwner->m_pOwner->PostThreadMessage(WM_FILEZILLA_THREADMSG, FTM_TRANSFERMSG, m_pOwner->m_userid);
        Close();
    }
}
Ejemplo n.º 5
0
void PerfSocket::Client_Recv_TCP(void) {
    // terminate loop nicely on user interupts

    sInterupted = false;
    //my_signal( SIGINT,  Sig_Interupt );
    //my_signal( SIGPIPE, Sig_Interupt );
#ifndef WIN32
    signal (SIGPIPE, SIG_IGN);
#endif

    int currLen;
    InitTransfer();
    double fract = 0.0;
    mStartTime.setnow();
    long  endSize = get_tcp_windowsize(mSock), startSize=endSize, loopLen =0, prevLen =0;
    Timestamp prevTime;
    prevTime.setnow();



    /* Periodic reporting is done here in the loop itself, if Suggest Window Size option is set*/
    mPReporting = false;

    /* Send the first packet indicating that the server has to send data */
    mBuf[0] = 'a';
    currLen = write( mSock, mBuf, mSettings->mBufLen );
    if ( currLen < 0 ) {
        WARN_errno( currLen < 0, "write" );
        return;
    }

    do {
        // perform read
        currLen = read( mSock, mBuf, mSettings->mBufLen );
        mPacketTime.setnow();
        if ( currLen < 0 ) {
            WARN_errno( currLen < 0, "read" );
            break;
        }

        mTotalLen += currLen;
        loopLen +=currLen;

        // periodically report bandwidths
        ReportPeriodicBW();

        double nFract = mStartTime.fraction(mPacketTime,mEndTime);
        if ( nFract > (fract + 0.1) ) {
            printf(seperator_line);
            ReportWindowSize();
            sReporting.Lock();
            ReportBW( loopLen, prevTime.subSec(mStartTime),  mPacketTime.subSec( mStartTime));
            sReporting.Unlock();
            fract +=0.1;
            if ( startSize != endSize ) {
                /* Change the window size only if the data transfer has changed at least by 5% */
                if ( loopLen < prevLen ) {

                    if ( ( ((double)(prevLen - loopLen)) /  
                           ((double)prevLen))  > 0.05         
                       ) {
                        endSize = startSize + (endSize - startSize)/2;
                    }

                } else {
                    if ( ( ((double)(loopLen - prevLen)) /       
                           ((double)prevLen) ) > 0.05          
                       ) {
                        startSize = endSize;
                        endSize = endSize*2;
                        prevLen = loopLen;

                    }
                }
            } else {
                endSize = endSize*2;
                prevLen = loopLen;
            }

            /** Reset the variables after setting new window size */
            prevTime.setnow();
            loopLen = 0 ;
            //shutdown(mSock,SHUT_RDWR);
            close(mSock);
            mSock = -1;
            Connect( mSettings->mHost, mSettings->mLocalhost );
            mBuf[0] = 'a';
            if ( set_tcp_windowsize(mSock,endSize) == -1 ) {
                printf(unable_to_change_win);
            }
            if ( get_tcp_windowsize(mSock) != endSize ) {
                printf(unable_to_change_win);
            }
            write( mSock, mBuf, mSettings->mBufLen );
        }
    } while ( ! (sInterupted  ||
                 (mMode_time   &&  mPacketTime.after( mEndTime ))  ||
                 (!mMode_time  &&  mTotalLen >= mAmount))
            );


    printf( seperator_line );
    ReportWindowSize();
    sReporting.Lock();
    ReportBW( loopLen, prevTime.subSec(mStartTime),  mPacketTime.subSec( mStartTime));
    sReporting.Unlock();

    printf( seperator_line);
    printf( opt_estimate);
    if ( loopLen > prevLen )
        set_tcp_windowsize(mSock,endSize);
    else
        set_tcp_windowsize(mSock,startSize);

    ReportWindowSize();
    printf( seperator_line );

    // stop timing
    mEndTime.setnow();

    sReporting.Lock();
    ReportBW( mTotalLen, 0.0, mEndTime.subSec( mStartTime ));
    sReporting.Unlock();

    if ( mSettings->mPrintMSS ) {
        // read the socket option for MSS (maximum segment size)
        ReportMSS( getsock_tcp_mss( mSock ));
    }
    //close(mSock);
    //mSock = -1;
}
Ejemplo n.º 6
0
void PerfSocket::Recv_TCP( void ) {
    extern Mutex clients_mutex;
    extern Iperf_ListEntry *clients;

    // get the remote address and remove it later from the set of clients 
    SocketAddr remote = getRemoteAddress(); 
    iperf_sockaddr peer = *(iperf_sockaddr *) (remote.get_sockaddr()); 

    // keep track of read sizes -> gives some indication of MTU size
    // on SGI this must be dynamically allocated to avoid seg faults
    int currLen;
    int *readLenCnt = new int[ mSettings->mBufLen+1 ];
    for ( int i = 0; i <= mSettings->mBufLen; i++ ) {
        readLenCnt[ i ] = 0;
    }

    InitTransfer();
#ifndef WIN32
    signal (SIGPIPE, SIG_IGN);
#endif

    do {
        // perform read
        currLen = read( mSock, mBuf, mSettings->mBufLen );

        if ( false ) {
            DELETE_ARRAY( readLenCnt );
            Server_Send_TCP();
            return;
        }
        mPacketTime.setnow();

        // periodically report bandwidths
        ReportPeriodicBW();

        mTotalLen += currLen;

        // count number of reads of each size
        if ( currLen <= mSettings->mBufLen ) {
            readLenCnt[ currLen ]++;
        }

    } while ( currLen > 0  &&  sInterupted == false );

    // stop timing
    mEndTime.setnow();
    sReporting.Lock();
    ReportBW( mTotalLen, 0.0, mEndTime.subSec( mStartTime ));
    sReporting.Unlock();

    if ( mSettings->mPrintMSS ) {
        // read the socket option for MSS (maximum segment size)
        ReportMSS( getsock_tcp_mss( mSock ));

        // on WANs the most common read length is often the MSS
        // on fast LANs it is much harder to detect
        int totalReads  = 0;
        for ( currLen = 0; currLen < mSettings->mBufLen+1; currLen++ ) {
            totalReads += readLenCnt[ currLen ];
        }

        // print each read length that occured > 5% of reads
        int thresh = (int) (0.05 * totalReads);
        printf( report_read_lengths, mSock );
        for ( currLen = 0; currLen < mSettings->mBufLen+1; currLen++ ) {
            if ( readLenCnt[ currLen ] > thresh ) {
                printf( report_read_length_times, mSock,
                        (int) currLen, readLenCnt[ currLen ],
                        (100.0 * readLenCnt[ currLen ]) / totalReads );
            }
        }
    }
    DELETE_ARRAY( readLenCnt );

    clients_mutex.Lock();     
    Iperf_delete ( &peer, &clients ); 
    clients_mutex.Unlock(); 
}
Ejemplo n.º 7
0
void PerfSocket::Send_TCP( void ) {
    if ( false ) {
        Client_Recv_TCP();
        return;
    }

    // terminate loop nicely on user interupts
    sInterupted = false;
    SigfuncPtr oldINT = my_signal( SIGINT,  Sig_Interupt );
    SigfuncPtr oldPIPE = my_signal( SIGPIPE, Sig_Interupt );

    int currLen;
    bool canRead;
    InitTransfer();

    do {

        // If the input is from a 
        // file, fill the buffer with
        // data from the file 
        if ( mSettings->mFileInput ) {
            extractor->getNextDataBlock(mBuf);

            // If the first character is 'a'
            // change if to '0' so that the
            // server does not mistake it for
            // a Window Suggest option
            if ( mBuf[0] == 'a' )
                mBuf[0] = '0';
            canRead = extractor->canRead();
        } else
            canRead = true;

        // perform write
        currLen = write( mSock, mBuf, mSettings->mBufLen );
        mPacketTime.setnow();
        if ( currLen < 0 ) {
            WARN_errno( currLen < 0, "write" );
            break;
        }

        // periodically report bandwidths
        ReportPeriodicBW();

        mTotalLen += currLen;

    } while ( ! (sInterupted  ||
                 (mMode_time   &&  mPacketTime.after( mEndTime ))  ||
                 (!mMode_time  &&  mTotalLen >= mAmount)) && canRead );

    if ( oldINT != Sig_Interupt ) {
        // Return signal handlers to previous handlers
        my_signal( SIGINT, oldINT );
        my_signal( SIGPIPE, oldPIPE );
    }

    // shutdown sending connection and wait (read)
    // for the other side to shutdown
    shutdown( mSock, SHUT_WR );
    currLen = read( mSock, mBuf, mSettings->mBufLen );
    WARN_errno( currLen == SOCKET_ERROR, "read on server close" );
    WARN( currLen > 0, "server sent unexpected data" );

    // stop timing
    mEndTime.setnow();
    sReporting.Lock();
    ReportBW( mTotalLen, 0.0, mEndTime.subSec( mStartTime ));
    sReporting.Unlock();

    if ( mSettings->mPrintMSS ) {
        // read the socket option for MSS (maximum segment size)
        ReportMSS( getsock_tcp_mss( mSock ));
    }

}