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