📄 ctpmanager.cpp
字号:
/*
* Copyright (C) 2003-2007 Funambol, Inc
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY, TITLE, NONINFRINGEMENT or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
#include <winsock2.h>
#include "Ws2tcpip.h"
#include "base/Log.h"
#include "base/util/utils.h"
#include "CTPManager.h"
#include "CTPParam.h"
// Init static pointer.
CTPManager* CTPManager::pinstance = NULL;
/**
* Method to create the sole instance of CTPManager
*/
CTPManager* CTPManager::getInstance() {
if (pinstance == NULL) {
pinstance = new CTPManager;
}
return pinstance;
}
/**
* Constructor: reads the CTPConfig from registry and init members.
*/
CTPManager::CTPManager() : config(APPLICATION_URI) {
// Read config from registry
config.readCTPConfig();
LOG.debug("CTP config read");
ctpSocket = NULL;
ctpThread = NULL;
receiveThread = NULL;
heartbeatThread = NULL;
receivedMsg = NULL;
}
CTPManager::~CTPManager() {
stopThread(ctpThread);
stopThread(receiveThread);
stopThread(heartbeatThread);
closeConnection();
if (receivedMsg) {
delete receivedMsg;
}
}
/**
* Creates the mai CTP thread, passing handle stpThread (NULL if not created)
*/
HANDLE CTPManager::startCTP(HANDLE stpThread) {
if (ctpThread) {
stopThread(ctpThread);
}
config.setLeavingState(false);
ctpThread = CreateThread(NULL, 0, ctpWorker, (LPVOID*)stpThread, 0, NULL);
if (!ctpThread) {
LOG.error("Error creating CTP thread: code 0x%08x", GetLastError());
}
return ctpThread;
}
int CTPManager::stopCTP() {
if (!ctpThread) {
LOG.debug("No CTP thread available -> exiting.");
return 1;
}
if (!ctpSocket) {
LOG.debug("No socket connection -> exiting.");
return 2;
}
int ret = 0;
LOG.debug("Closing CTP connection...");
// Terminate immediately the heartbeat thread to avoid sending
// any READY msg now. Keep receiveThread alive, to receive the last OK msg.
if (stopThread(heartbeatThread)) {
LOG.debug("heartbeatThread killed");
}
// Start thread to receive messages from Server if not running
// If client authenticated, receiveThread is already running
if (!receiveThread) {
receiveThread = CreateThread(NULL, 0, receiveWorker, (LPVOID*)ctpSocket, 0, NULL);
if (!receiveThread) {
LOG.error("Error creating receive thread: code 0x%08x", GetLastError());
return -1;
}
// Just to be sure the receiveWorker has reached the 'recv' state
Sleep(1000);
}
// Set flag of leaving state, so receive thread will exit after the OK msg.
config.setLeavingState(true);
//
// Send the BYE message
//
LOG.info("Sending [BYE] message...");
if (sendByeMsg()) {
LOG.error("Error sending the BYE message");
goto finally;
}
//
// Wait for OK msg: receive thread should exit after the last OK
// message sent by Server.
//
DWORD waitResult = WaitForSingleObject(receiveThread, LEAVING_STATE_TIMEOUT * 1000);
switch (waitResult) {
// Thread exited normally or abandoned -> ok
case WAIT_ABANDONED:
LOG.debug("receiveThread abandoned");
case WAIT_OBJECT_0: {
DWORD exitcode = 0;
GetExitCodeThread(receiveThread, &exitcode);
LOG.debug("receiveThread ended with code %d", exitcode);
ret = exitcode;
break;
}
// Timeout: kill thread -> out.
case WAIT_TIMEOUT: {
LOG.debug("Timeout - receiveThread will now be terminated");
TerminateThread(receiveThread, 1);
ret = 1;
break;
}
// Some error occurred (case WAIT_FAILED)
default: {
LOG.debug("Wait error on receiveThread");
TerminateThread(receiveThread, 1);
ret = 2;
break;
}
}
CloseHandle(receiveThread);
receiveThread = NULL;
finally:
// Close them if still running...
if (stopThread(receiveThread)) {
LOG.debug("receiveThread killed");
}
if (stopThread(ctpThread)) {
LOG.debug("ctpThread killed");
}
//
// Close socket connection
//
closeConnection();
return ret;
}
int CTPManager::openConnection(){
DWORD errorCode = 0;
int ret = 0;
if (ctpSocket) {
closeConnection();
}
LOG.debug("--- Starting a new SOCKET connection ---");
//
// Initialize Winsock
//
WORD versionRequested = MAKEWORD(1, 1);
WSADATA wsaData;
ret = WSAStartup(versionRequested, &wsaData);
if (ret != NO_ERROR) {
errorCode = WSAGetLastError();
LOG.error("SOCKET WSAStartup() error %d: %s", errorCode, createErrorMsg(errorCode));
return -1;
}
// Check if version is correct
if (wsaData.wVersion != versionRequested) {
LOG.error("WinSock version not supported: %d (%d expected)", wsaData.wVersion, versionRequested);
return -1;
}
//
// Find the server
//
LOG.debug("Find the server address...");
struct addrinfo aiHints;
struct addrinfo *aiList = NULL;
// Setup the hints address info structure
// which is passed to the getaddrinfo() function
memset(&aiHints, 0, sizeof(aiHints));
aiHints.ai_family = AF_INET; // Address family
aiHints.ai_socktype = SOCK_STREAM; // Socket type
aiHints.ai_protocol = IPPROTO_TCP; // Protocol
aiHints.ai_flags = AI_CANONNAME; // To get the canonical name
const char* hostName = config.getUrlTo().c_str();
char port[10];
sprintf(port, "%d", config.getCtpPort());
LOG.info("HOSTNAME = '%s' PORT = '%s'", hostName, port);
// Resolve the host name.
ret = getaddrinfo(hostName, port, &aiHints, &aiList);
if (ret) {
lastErrorCode = ERR_HOST_NOT_FOUND;
LOG.error("getaddrinfo() failed: %s", gai_strerror(ret));
ret = -2;
goto finally;
}
struct addrinfo *addr = aiList;
// Loop on possible addresses
while (addr != NULL) {
//
// Create a TCP/IP stream socket
//
LOG.debug("Create SOCKET connection...");
ctpSocket = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
if (ctpSocket == INVALID_SOCKET) {
if (addr->ai_next != NULL) {
addr=addr->ai_next; // take next address
continue;
}
else {
errorCode = WSAGetLastError();
LOG.error("SOCKET socket() error %d: %s", errorCode, createErrorMsg(errorCode));
ret = -3;
goto finally;
}
}
//
// Connect to the server
//
LOG.debug("Connecting to '%s'...", hostName);
ret = connect(ctpSocket, addr->ai_addr, addr->ai_addrlen);
if (ret == SOCKET_ERROR) {
if (addr->ai_next != NULL) {
addr=addr->ai_next; // take next address
closesocket(ctpSocket);
continue;
}
else {
errorCode = WSAGetLastError();
if (errorCode == WSAECONNREFUSED) {
LOG.error("SOCKET connect() error: Server not responding at %s:%s", hostName, port);
}
else {
LOG.error("SOCKET connect() error %d: %s", errorCode, createErrorMsg(errorCode));
}
ret = -4;
goto finally;
}
}
LOG.info("Succesfully connected to %s!", addr->ai_canonname);
break;
}
finally:
if (aiList) {
freeaddrinfo(aiList);
}
return ret;
}
int CTPManager::closeConnection(){
int ret = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -