tcpconnection.cpp

来自「SMC takes a state machine stored in a .s」· C++ 代码 · 共 1,313 行 · 第 1/3 页

CPP
1,313
字号
//// The contents of this file are subject to the Mozilla Public// License Version 1.1 (the "License"); you may not use this file// except in compliance with the License. You may obtain a copy// of the License at http://www.mozilla.org/MPL/// // Software distributed under the License is distributed on an// "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or// implied. See the License for the specific language governing// rights and limitations under the License.// // The Original Code is State Machine Compiler (SMC).// // The Initial Developer of the Original Code is Charles W. Rapp.// Portions created by Charles W. Rapp are// Copyright (C) 2000 - 2007. Charles W. Rapp.// All Rights Reserved.// // Contributor(s): //// Name//  TcpConnection.cpp//// Description//  TCP connection class implementation.//// RCS ID// $Id: TcpConnection.cpp,v 1.7 2007/12/28 12:34:40 cwrapp Exp $//// CHANGE LOG// $Log: TcpConnection.cpp,v $// Revision 1.7  2007/12/28 12:34:40  cwrapp// Version 5.0.1 check-in.//// Revision 1.6  2005/06/08 11:09:12  cwrapp// + Updated Python code generator to place "pass" in methods with empty//   bodies.// + Corrected FSM errors in Python example 7.// + Removed unnecessary includes from C++ examples.// + Corrected errors in top-level makefile's distribution build.//// Revision 1.5  2005/05/28 13:31:18  cwrapp// Updated C++ examples.//// Revision 1.0  2003/12/14 19:40:23  charlesr// Initial revision//#ifdef WIN32#pragma warning(disable: 4355)#endif#include "TcpConnection.h"#include "TcpSegment.h"#include "TcpClient.h"#include "TcpServer.h"#include "Eventloop.h"#include <errno.h>#include <string.h>#include <memory.h>#include <fcntl.h>#if !defined(WIN32)#include <unistd.h>#include <netdb.h>#  if defined(__sun)#include <sys/systeminfo.h>#  endif#endif#if defined(WIN32)// Get rid of an annoying build warning.#pragma warning(disable: 4355)#endifusing namespace std;#if defined(WIN32)typedef int socklen_t;#endif// External variable declarations.extern Eventloop *Gevent_loop;// Const member declarations.const unsigned long TcpConnection::ISN = 1415531521;const int TcpConnection::MIN_TIMEOUT = 1;const int TcpConnection::ACK_TIMEOUT = 2000;const int TcpConnection::CLOSE_TIMEOUT = 5000;const int TcpConnection::BUFFER_BLOCK_SIZE = 4096;// Const declarations.const static int MSG_READ = 0;const static int NO_SEND_FLAGS = 0;const static long MAX_HOSTNAME_LEN = 257;const static unsigned long LOCAL_HOST_ADDRESS = 0x7f000001;#if defined(WIN32)const static unsigned short MIN_PORT = 1024;const static unsigned short MAX_PORT = 5000;#endif// External routine declarations.char* winsock_strerror(int);//---------------------------------------------------------------// getFarAddress() const (Public)// Return the far-end's 4-byte IP address.//unsigned long TcpConnection::getFarAddress() const{    return (_farAddress.sin_addr.s_addr);} // end of TcpConnection::getFarAddress() const//---------------------------------------------------------------// getFarPort() const (Public)// Return the far-end's TCP port.//unsigned short TcpConnection::getFarPort() const{    return (_farAddress.sin_port);} // end of TcpConnection::getFarPort() const//---------------------------------------------------------------// getSequenceNumber() const (Public)// Return the current sequence number.//unsigned long TcpConnection::getSequenceNumber() const{    return (_sequence_number);} // end of TcpConnection::getSequenceNumber() const//---------------------------------------------------------------// transmit(const unsigned char*, int, int) (Public)// Transmit data to the far side.//void TcpConnection::transmit(const char *data,                             int offset,                             int size){    _fsm.Transmit(data, offset, size);    return;} // end of TcpConnection::transmit(const unsigned char*, int, int)//---------------------------------------------------------------// doClose() (Public)// Start closing this connection.//void TcpConnection::doClose(){    _fsm.Close();    return;} // end of TcpConnection::doClose()//---------------------------------------------------------------// setListener(TcpConnectionListener&) (Public)// Set the connection's listener to a new object.//void TcpConnection::setListener(TcpConnectionListener& listener){    _listener = &listener;    return;} // end of TcpConnection::setListener(TcpConnectionListener&)//---------------------------------------------------------------// handleReceive(int) (Public)// Process incoming data.//void TcpConnection::handleReceive(int){    sockaddr sourceAddress;    TcpSegment *segment;    socklen_t addressSize;    int flags,        done,        errorFlag,        bytesRead,        totalBytesRead;    // Read in the segment. Since the data may exceed the buffer    // size, keep expanding the buffer until all the data is    // read.    for (done = 0, bytesRead = 0, totalBytesRead = 0, errorFlag = 0;         done == 0;         totalBytesRead += bytesRead)    {        // Be certain to offset properly into the input buffer.        addressSize = sizeof(sourceAddress);        bytesRead = recvfrom(_udp_socket,                             (_buffer + totalBytesRead),                             _bufferSize,                             MSG_READ,                             &sourceAddress,                             &addressSize);#if defined(WIN32)        if (bytesRead == SOCKET_ERROR)#else        if (bytesRead < 0)#endif        {            done = 1;            if (errno != EAGAIN)            {                cerr << "Receive failure - "                     << strerror(errno)                     << "."                     << endl;                errorFlag = 1;            }            else            {                bytesRead = 0;            }        }        else if (bytesRead >= 0 && bytesRead < _bufferSize)        {            done = 1;        }        else        {            // The entire buffer was filled with the data.            // Expand the buffer and read some more.            expandBuffer();        }    }    if (errorFlag == 0 && bytesRead > 0)    {        segment = new TcpSegment(reinterpret_cast<sockaddr_in&>(sourceAddress),                                 _nearAddress,                                 _buffer,                                 totalBytesRead);#if defined(SMC_DEBUG)        cout << "**** Received segment:"             << endl             << *segment             << endl;#endif        // Generate the appropriate transition based on the header        // flags.        flags = segment->getFlags();        switch(flags)        {            case TcpSegment::FIN:                _fsm.FIN(*segment);                break;            case TcpSegment::SYN:                _fsm.SYN(*segment);                break;            case TcpSegment::RST:                _fsm.RST(*segment);                break;            case TcpSegment::PSH:                _fsm.PSH(*segment);                break;            case TcpSegment::ACK:                _fsm.ACK(*segment);                break;            case TcpSegment::URG:                _fsm.URG(*segment);                break;            case TcpSegment::FIN_ACK:                _fsm.FIN_ACK(*segment);                break;            case TcpSegment::SYN_ACK:                _fsm.SYN_ACK(*segment);                break;            case TcpSegment::RST_ACK:                _fsm.RST_ACK(*segment);                break;            case TcpSegment::PSH_ACK:                _fsm.PSH_ACK(*segment);                break;            default:                _fsm.UNDEF(*segment);                break;        }    }    return;} // end of TcpConnection::handleReceive(int)//---------------------------------------------------------------// handleTimeout(const char*) (Public)// Generate the appropriate transition based on the timer's name.//void TcpConnection::handleTimeout(const char *name){#if defined(SMC_DEBUG)    cout << "**** Timer " << name << " has expired." << endl;#endif    if (strcmp(name, "ACK_TIMER") == 0)    {        _fsm.AckTimeout();    }    else if (strcmp(name, "CONN_ACK_TIMER") == 0)    {        _fsm.ConnAckTimeout();    }    else if (strcmp(name, "TRANS_ACK_TIMER") == 0)    {        _fsm.TransAckTimeout();    }    else if (strcmp(name, "CLOSE_ACK_TIMER") == 0)    {        _fsm.CloseAckTimeout();    }    else if (strcmp(name, "CLOSE_TIMER") == 0)    {        _fsm.CloseTimeout();    }    else if (strcmp(name, "SERVER_OPENED") == 0)    {        _fsm.ServerOpened();    }    else if (strcmp(name, "CLIENT_OPENED") == 0)    {        _fsm.ClientOpened(&_farAddress);    }    else if (strcmp(name, "OPEN_FAILED") == 0)    {        _fsm.OpenFailed(_errorMessage);        if (_errorMessage != NULL)        {            delete[] _errorMessage;            _errorMessage = NULL;        }    }    return;} // end of TcpConnection::handleTimeout(const char*)//---------------------------------------------------------------// openServerSocket(unsigned short) (Public)// Open a server socket on the specified port.//void TcpConnection::openServerSocket(unsigned short port){#if defined(WIN32)    unsigned long blockingFlag = 1;    HANDLE newHandle;#endif    // Set up this server's address.    (void) memset(&_nearAddress, 0, sizeof(_nearAddress));    _nearAddress.sin_family = AF_INET;    _nearAddress.sin_port = port;    _nearAddress.sin_addr.s_addr = INADDR_ANY;    // Tell the UDP socket to route data bound for port to this    // object.#if defined(WIN32)    if ((_udp_win_socket = socket(AF_INET, SOCK_DGRAM, 0))            == INVALID_SOCKET ||        DuplicateHandle(GetCurrentProcess(),                        (HANDLE) _udp_win_socket,                        GetCurrentProcess(),                        &newHandle,                        0,                        FALSE,                        DUPLICATE_SAME_ACCESS) == FALSE ||        bind((unsigned int) newHandle,             reinterpret_cast<sockaddr*>(&_nearAddress),             sizeof(_nearAddress))            == SOCKET_ERROR)#else    if ((_udp_socket = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ||        bind(_udp_socket,             reinterpret_cast<sockaddr*>(&_nearAddress),             sizeof(_nearAddress))            < 0)#endif    {        char *error;        // Use timer to report this event asynchronously.        // Store away error message.        if (_errorMessage != NULL)        {            delete[] _errorMessage;            _errorMessage = NULL;        }#if defined(WIN32)        error = winsock_strerror(WSAGetLastError());#else        error = strerror(errno);#endif        _errorMessage = new char[strlen(error) + 1];        (void) strcpy(_errorMessage, error);        Gevent_loop->startTimer("OPEN_FAILED",                                MIN_TIMEOUT,                                *this);    }    else    {        // Get the UDP socket's address.        _nearAddress.sin_family = AF_INET;        _nearAddress.sin_addr.s_addr = getLocalAddress();        // Set the socket to non-blocking and register it with        // the event loop.#if defined(WIN32)        _udp_socket = (unsigned int) newHandle;        (void) ioctlsocket(_udp_socket, FIONBIO, &blockingFlag);#else        (void) fcntl(_udp_socket, F_SETFL, O_NDELAY);#endif        Gevent_loop->addFD(_udp_socket, *this);        Gevent_loop->startTimer("SERVER_OPENED",                                MIN_TIMEOUT,                                *this);    }    return;} // end of TcpConnection::openServerSocket(int)//---------------------------------------------------------------// openClientSocket(const sockaddr_in*) (Public)// Connect to the specified address.//void TcpConnection::openClientSocket(const sockaddr_in *address){#if defined(WIN32)

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?