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 + -
显示快捷键?