tcpconnection.cpp

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

CPP
1,313
字号
    unsigned long blockingFlag = 1;    HANDLE newHandle;    int new_port;#endif    // Set up this client's address.    (void) memset(&_nearAddress, 0, sizeof(_nearAddress));    _nearAddress.sin_family = AF_INET;    _nearAddress.sin_port = 0;    _nearAddress.sin_addr.s_addr = INADDR_ANY;#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 ||        (new_port = doBind((int) newHandle)) < 0)#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;#if defined(WIN32)        _nearAddress.sin_port = (unsigned short) new_port;#else        _nearAddress.sin_port = getLocalPort(_udp_socket);#endif        _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);        // Save the far-end address for later use.        (void) memcpy(&_farAddress, address, sizeof(_farAddress));        _sequence_number = ISN;        Gevent_loop->startTimer("CLIENT_OPENED",                                MIN_TIMEOUT,                                *this);    }    return;} // end of TcpConnection::openClientSocket(const sockaddr_in*)//---------------------------------------------------------------// openSuccess() (Public)// The socket has been successfully opened.//void TcpConnection::openSuccess(){    _listener->opened(*this);    return;} // end of TcpConnection::openSuccess()//---------------------------------------------------------------// openFailed(const char*) (Public)// The socket could not be opened.//void TcpConnection::openFailed(const char *reason){    _listener->openFailed(reason, *this);    return;} // end of TcpConnection::openFailed(const char*)//---------------------------------------------------------------// closeSocket() (Public)// Finish closing the socket.//void TcpConnection::closeSocket(){    if (_udp_socket >= 0)    {        // Remove this UDP socket from the event loop.        Gevent_loop->removeFD(_udp_socket);        // Now close the UDP socket.#if defined(WIN32)        CloseHandle((HANDLE) _udp_socket);        closesocket(_udp_win_socket);        _udp_win_socket = NULL;#else        close(_udp_socket);#endif        _udp_socket = -1;    }        return;} // end of TcpConnection::closeSocket()//---------------------------------------------------------------// halfClosed() (Public)// The far end client socket has closed its half of the// connection.//void TcpConnection::halfClosed(){    _listener->halfClosed(*this);    return;} // end of TcpConnection::halfClosed()//---------------------------------------------------------------// closed(const char*) (Public)// The connection is completely closed.//void TcpConnection::closed(const char *reason){    TcpConnectionListener *listener;    if (_listener != NULL)    {        listener = _listener;        _listener = NULL;        listener->closed(reason, *this);    }    return;} // end of TcpConnection::closed(const char*)//---------------------------------------------------------------// clearListener() (Public)// Clear this connection's current listener.//void TcpConnection::clearListener(){    _listener = NULL;    return;} // end of TcpConnection::clearListener()//---------------------------------------------------------------// transmitted() (Public)// Data transmission successfully completed.//void TcpConnection::transmitted(){    _listener->transmitted(*this);    return;} // end of TcpConnection::transmitted()//---------------------------------------------------------------// transmitFailed(const char*) (Public)// Data transmission failed.//void TcpConnection::transmitFailed(const char *reason){    _listener->transmitFailed(reason, *this);    return;} // end of TcpConnection::transmitFailed(const char*)//---------------------------------------------------------------// receive(const TcpSegment&) (Public)// Send received data to the listener.//void TcpConnection::receive(const TcpSegment& segment){    if (_listener != NULL)    {        _listener->receive(segment.getData(),                           segment.getDataSize(),                           *this);    }    return;} // end of TcpConnection::receive(const TcpSegment&)//---------------------------------------------------------------// sendOpenSyn(const sockaddr_in*) (Public)// Send the opening SYN message which requests connection to a// service.//void TcpConnection::sendOpenSyn(const sockaddr_in *address){    TcpSegment segment(*address,                       _nearAddress,                       0,                       0,                       TcpSegment::SYN,                       NULL,                       0,                       0);    doSend(TcpSegment::SYN, NULL, 0, 0, &segment);    return;} // end of TcpConnection::sendOpenSyn(const sockaddr_in*)//---------------------------------------------------------------// accept(const TcpSegment&) (Public)// Create a client socket to handle the new connection.//void TcpConnection::accept(const TcpSegment& segment){    TcpClient *accept_client;    int new_socket;#if defined(WIN32)    unsigned long blockingFlag = 1;    HANDLE newHandle;    int new_port;#else    sockaddr_in clientAddress;#endif    // Create a new UDP socket to handle this connection.    // Let it be assigned a random UDP port.#if defined(WIN32)    newHandle = NULL;    if ((new_socket = socket(AF_INET, SOCK_DGRAM, 0))            == INVALID_SOCKET ||        DuplicateHandle(GetCurrentProcess(),                        (HANDLE) new_socket,                        GetCurrentProcess(),                        &newHandle,                        0,                        FALSE,                        DUPLICATE_SAME_ACCESS) == FALSE ||        (new_port = doBind((int) newHandle)) < 0)    {        // If an error occurs now, ignore it.        if (new_socket != INVALID_SOCKET)        {            closesocket(new_socket);        }        if (newHandle != NULL)        {            CloseHandle((HANDLE) newHandle);        }    }    else    {        // Set the socket to non-blocking.        (void) ioctlsocket(            (unsigned int) newHandle, FIONBIO, &blockingFlag);        // Have the new client socket use this server        // socket's near address for now.        accept_client = new TcpClient(segment.getSource(),                                      _nearAddress,                                      (unsigned short) new_port,                                      new_socket,                                      newHandle,                                      _sequence_number,                                      (TcpServer&) *this,                                      *_listener);#else    // Set up this client's address.    (void) memset(&clientAddress, 0, sizeof(clientAddress));    clientAddress.sin_family = AF_INET;    clientAddress.sin_port = 0;    clientAddress.sin_addr.s_addr = INADDR_ANY;    if ((new_socket = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ||        bind(new_socket,             reinterpret_cast<sockaddr*>(&clientAddress),             sizeof(clientAddress))            < 0)    {        // If an error occurs now, ignore it.        if (new_socket >= 0)        {            close(new_socket);        }    }    else    {        // Set the socket to non-blocking.        (void) fcntl(new_socket, F_SETFL, O_NDELAY);        // Have the new client socket use this server        // socket's near address for now.        accept_client = new TcpClient(segment.getSource(),                                      _nearAddress,                                      new_socket,                                      _sequence_number,                                      (TcpServer&) *this,                                      *_listener);#endif        accept_client->acceptOpen(segment);    }    return;} // end of TcpConnection::accept(const TcpSegment&)//---------------------------------------------------------------// accepted() (Public)// Connection completely accepted.//void TcpConnection::accepted(){    TcpServer *server = _server;    TcpConnectionListener *listener = _listener;    // Tell the server listener that a new connection has    // been accepted. Then clear the server listener because    // this socket is now truly a client socket. Clear the    // listener member data now because the callback method    // will be resetting it and the reset will fail if we    // don't do it.    _server = NULL;    _listener = NULL;    listener->accepted((TcpClient&) *this, *server);    return;} // end of TcpConnection::accepted()//---------------------------------------------------------------// sendSynAck(const TcpSegment&) (Public)// Acknowledge a SYN message.//void TcpConnection::sendSynAck(const TcpSegment& segment){    unsigned short port;    char port_bytes[2];    // Tell the far end client socket with what port it should    // now communicate.#if defined(WIN32)    port = _actualPort;#else    port = getLocalPort(_udp_socket);#endif    port_bytes[0] = (char) (port & 0x00ff);    port_bytes[1] = (char) ((port & 0xff00) >> 8);    doSend(TcpSegment::SYN_ACK, port_bytes, 0, 2, &segment);    return;} // end of TcpConnection::sendSynAck(const TcpSegment&)//---------------------------------------------------------------// sendSynAckAck(const TcpSegment&) (Public)// Acknowledge the service's acknowledge. Need to do this so// doSend() will use the correct address.//void TcpConnection::sendSynAckAck(const TcpSegment& segment){    TcpSegment faux_segment(_farAddress,                            _nearAddress,                            segment.getSequenceNumber(),                            segment.getAcknowledgeNumber(),                            segment.getFlags(),                            NULL,                            0,                            0);    doSend(TcpSegment::ACK, NULL, 0, 0, &faux_segment);    return;} // end of TcpConnection::sendSynAckAck(const TcpSegment&)//---------------------------------------------------------------// doSend(...) (Public)// Send data to the specified address.//void TcpConnection::doSend(unsigned short flags,                           const char *data,                           int offset,                           int size,                           const TcpSegment *recv_segment){    sockaddr_in to_address;    unsigned long ack_number;    TcpSegment *send_segment;    char *packet;    int packet_size;    (void) memset(&to_address, 0, sizeof(to_address));    // First, use the received segment.    // Else, use the connection's far end.    if (recv_segment != NULL)    {        (void) memcpy(&to_address,                      &(recv_segment->getSource()),                      sizeof(to_address));    }    // If the address was not specified, then send this segment    // to whatever client socket we are currently speaking.    else    {        (void) memcpy(&to_address, &_farAddress, sizeof(to_address));    }    // Send the ack number only if the ack flag is set.    if ((flags & TcpSegment::ACK) == 0 || recv_segment == NULL)    {        ack_number = 0;    }    else    {        // Figure out the ack number based on the received        // segment's sequence number and data size.        ack_number = getAck(*recv_segment);    }    send_segment =        new TcpSegment(_nearAddress,                       to_address,                       _sequence_number,

⌨️ 快捷键说明

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