notlstnr.cpp

来自「funambol window mobile客户端源代码」· C++ 代码 · 共 815 行 · 第 1/2 页

CPP
815
字号
///////////////////////////////////////////////////////////////////
// Notification Listener: connection handler
///////////////////////////////////////////////////////////////////
/**
* Open the socket connection and waits for the server messages.
*/
static DWORD acceptConnection(SOCKET sock)
{
    if (g_dwServiceState != SERVICE_STATE_ON) {
        // Do not accept connections unless the service is on

        // ALWAYS close the socket, even if you return
        // FALSE. Services.exe leaves it to the
        // service to close the socket in all cases.
        LOG.error("S4ND: ERROR: Service Conn fails. Service State != ON.  State = <%d>", g_dwServiceState);
        send(sock, RESP_BUSY, strlen(RESP_BUSY),0);
        closesocket(sock);
        return ERROR_SERVICE_NOT_ACTIVE;
    }
    int ret = ERROR_EXCEPTION_IN_SERVICE;

    __try {
        LOG.debug("Starting worker...");
        ret = startWorker(sock);
    }
    __except (EXCEPTION_EXECUTE_HANDLER) {
        LOG.info("Exception in Worker thread.");
    }

    if( ret != ERROR_SUCCESS ) {
        if (ret == ERROR_BUSY ){
            LOG.debug("Worker busy...");
            send(sock, RESP_BUSY, strlen(RESP_BUSY),0);
        }
        else {
            LOG.error("Worker error...");
            send(sock, RESP_GENERIC, strlen(RESP_BUSY),0);
        }
        closesocket(sock);
    }
    // Worker thread will close the socket.
    return ret;
}


///////////////////////////////////////////////////////////////////
// Address change handler
///////////////////////////////////////////////////////////////////

// FIXME: use the DM
/*
* Test a configuration property to understand if the client has already
* notified the server.
*/
static bool isServerNotified()
{
    wchar_t buf[10];

    memset(buf, 0, 10*sizeof(wchar_t));
    getClientConfigurationInternal (TEXT(""), PROPERTY_SPDM_SERVER_NOTIFIED,
                                     buf, FALSE);
    return ( wcscmp(buf, TEXT("1")) == 0);
}

// FIXME: use the DM
/*
* Set a configuration property to mark the client has
* notified the server.
*/
void setServerNotified(bool val)
{
    setClientConfiguration(
            TEXT(""),
            PROPERTY_SPDM_SERVER_NOTIFIED,
            ( (val) ? TEXT("1") : TEXT("0") ),
            NULL);
}



/**
 * Starts the STP or CTP process, based on the registry property 'push'.
 * STP: Start a particular sync saying to the server the new client IP address.
 * It sets the server notified parameter if succesfully finished.
 * CTP: starts the CTP main thread (ctpWorker) which will connect only
 * if the stpWorker ended unsuccessfully.
 */
DWORD addressChangeHandler(void)
{
    LOG.debug("addressChangeHandler begin");
    static wchar_t oldIP[40] = TEXT("127.0.0.1");
    wchar_t newIP[40];
    DWORD ret = ERROR_SUCCESS;
    bool useSTP = false;
    bool useCTP = false;

    //MessageBox (NULL, TEXT("addressChangeHandler"), TEXT("Test"), MB_SETFOREGROUND | MB_OK);

    // Reset LOG if > 100k
    if (LOG.getLogSize() > NOTLSTNR_MAX_SIZE) {
        LOG.reset(NOTLSTNR_LOG_TITLE);
    }

    // Read getPush -> switch if using STP / CTP
    int pushType = getPushTypeFromRegistry();
    if (pushType & 1) {
        useSTP = true;
    }
    if (pushType & 2) {
        useCTP = true;
    }

    if (!useSTP && !useCTP) {
        // Nothing to do
        setServerNotified(false);
        return 0;
    }
    LOG.debug("useSTP = %d, useCTP = %d", useSTP, useCTP);

    try {
        if (checkNetwork()) {
            LOG.debug("Connected to network, getting IP address...");
            getIPAddress(newIP);
            LOG.info("Current IP: %ls", newIP);

            if (wcscmp(newIP, TEXT("192.168.55.101"))==0 ||
                 wcsstr(newIP, TEXT("169.254.2.")) ) {
                LOG.info("Device is using ActiveSync -> use only CTP");
                wcscpy(oldIP, newIP);
                setServerNotified(false);
                useSTP = false;     // Because it would fail.
            }

            // The server is already notified and the IP is
            // the same of the current, do not send a new notification.
            if ( isServerNotified() && (wcscmp(oldIP, newIP)==0) ) {
                LOG.info("Server already notified.");
                return ret;
            }

            // Save the IP
            wcscpy(oldIP, newIP);

            HANDLE stpThread = NULL;
            CTPManager* ctpManager = CTPManager::getInstance();

            // ----------- STP -----------
            if (useSTP) {
                // create STP thread, get handle of stpThread
                stpThread = CreateThread(NULL, 0, stpWorker, NULL, 0, NULL);
                if (!stpThread) {
                    LOG.error("Error creating STP thread: code 0x%08x", GetLastError());
                }
            }

            // ----------- CTP -----------
            if (useCTP) {
                // create CTP thread, passing handle stpThread (NULL if not created)
                ctpManager->startCTP(stpThread);
            }
        }
        else {
            LOG.debug("Not connected to network: close CTP if active and try to restart connection.");
            CTPManager* ctpManager = CTPManager::getInstance();
            ctpManager->setLeaving(true);
            ctpManager->closeConnection();
            setServerNotified(false);
            CreateThread(NULL, 0, establishConnectionWorker, NULL, 0, NULL);
        }
    }
    catch (...) {
        DWORD errorCode = GetLastError();
        LOG.error("Unexpected exception in addressChangeHandler: code %d", errorCode);
    }

    LOG.debug("Exiting addressChangeHandler");
    return ret;
}




/**
 * Reads the 'push' registry value from CTPConfig, possible values:
 * 0  -> None
 * 1  -> STP
 * 2  -> CTP
 * 3  -> STP with fallback to CTP
 */
int getPushTypeFromRegistry() {

    CTPConfig config(APPLICATION_URI);
    config.readCTPConfig();
    return config.getPush();
}



/**
 * Starts the program "startsync.exe" with params:
 * "manual <sourcename1, sourcename2,...>" where sourcenames are
 * retrieved from the SyncNotification passed.
 * @note      the process is started and then the control is returned
 *            immediately to the caller (no wait on the process started)
 * @param sn  pointer to the SyncNotification object to read
 * @return    the PID of process started, a value < 0 in case of errors
 */
int startSyncFromSAN(SyncNotification* sn) {

    if (!sn) {
        LOG.error("CTP notification error: SyncNotification is NULL");
        return -1;
    }

    // Get number of sources to sync
    int n = sn->getNumSyncs();
    if (!n) {
        LOG.error("CTP notification error: no sources to sync from server");
        return -2;
    }

    //
    // Call "startsync.exe" with command-line parameters (sequence of source names)
    //
    wstring app     = L"startsync.exe";
    wstring cmdLine = L"tcpip";
    int count = 0;
    for (int i=0; i<n; i++) {
        SyncAlert* sync = sn->getSyncAlert(i);
        if(!sync) {
            LOG.error("CTP notification error: no SyncAlert in SyncNotification");
            return -3;
        }

        WCHAR* srcname = getSSourceName(APPLICATION_URI, sync->getServerURI());
        if (srcname) {
            if (count == 0) { cmdLine += L" "; }
            else            { cmdLine += L","; }
            cmdLine += srcname;
            delete [] srcname;
            count++;
        } 
        else {
            LOG.error("CTP notification error: no source found from server notification request: %s", sync->getServerURI());
            continue;
        }
    }

    if (count == 0) {
        // 0 sources to sync -> out
        LOG.info("No sources to sync");
        return NULL;
    }
    
    //
    // Start the sync process: "startsync.exe tcpip <sourcename1, sourcename2,...>"
    //
    int pid = 0;
    if (askConfirm()) {
        LOG.info("Starting sync: '%ls %ls'", app.c_str(), cmdLine.c_str());
        pid = startProgram(app.c_str(), cmdLine.c_str());

    }
    return pid;
}



/**
 * Utility to extract the nonce parameter from CTPMessage passed and
 * save it to 'CTPConfig::ctpNonce'.
 * The configuration (CTPConfig) is also saved to registry.
 * The nonce is expected to be the first parameter of the message.
 * @param authStatusMsg  the CTPMessage to analyze
 * @return               true if the nonce has been saved, 
 *                       false if nonce not found
 */
bool saveNonceParam(CTPMessage* authStatusMsg) {

    if (authStatusMsg->params.size() == 0) {
        return false;
    }

    // Get nonce param
    int nonceLen = 0;
    void* nonce  = NULL;
    list<CTPParam>::iterator param = authStatusMsg->params.begin();
    if ((*param).getParamCode() == P_NONCE) {
        nonceLen = (*param).getValueLength();
        nonce    = (*param).getValue();
    }
    else {
        return false;
    }
    if (!nonce || nonceLen==0) {
        return false;
    }


    // Nonce is encoded in b64.
    char* b64Nonce = new char[((nonceLen/3+1)<<2) + 32];
    int len = b64_encode(b64Nonce, nonce, nonceLen);
    b64Nonce[len] = 0;

    //LOG.debug("New nonce received:");
    //hexDump((char*)nonce, nonceLen);
    LOG.debug("New nonce received: '%s'", b64Nonce);

    // Save new nonce to config, and save config to registry!
    CTPManager* ctpManager = CTPManager::getInstance();
    ctpManager->getConfig()->setCtpNonce(b64Nonce);
    ctpManager->getConfig()->saveCTPConfig();

    delete [] b64Nonce;
    return true;
}


/**
 * Utility to print the error message which is the first (and only)
 * param of the passed statusMsg.
 * @param statusMsg  the CTPMessage to analyze
 * @return           0 if the error param has been found 
 *                   1 if the error param not found
 */
int printErrorStatus(CTPMessage* statusMsg) {

    if (statusMsg->params.size() == 0) {
        return 1;
    }

    // Get error param
    int errorLen = 0;
    void* error  = NULL;
    list<CTPParam>::iterator param = statusMsg->params.begin();
    errorLen = (*param).getValueLength();
    error    = (*param).getValue();

    if (!error || errorLen<=0) {
        return 1;
    }

    char* buf = NULL;
    strncpy(buf, (char*)error, errorLen);
    LOG.info("Error message received: '%s'", buf);
    
    return 0;
}



/**
 * Utility to extract the message length from a CTP package.
 * The message length is stored in the first 2 bytes of the CTP package.
 * @param  package    the input package
 * @param  packageLen the length of the passed package
 * @return            the message length
 */
int extractMsgLength(const char* package, int packageLen) {

    if (packageLen < 2) {
        LOG.error("Unable to read the package length: not enough bytes received (%d)", packageLen);
        return 0;
    }

    int messageLen  = (int)((unsigned char)package[0]);
    int messageLen1 = (int)((unsigned char)package[1]);

    messageLen <<= 8;
    messageLen = messageLen | messageLen1;
    //LOG.debug("messageLen = %d", messageLen);
    return messageLen;
}


/**
 * Print the message written in exadecimal code.
 */
void hexDump(char *buf, int len){

    if (LOG.getLevel() < LOG_LEVEL_DEBUG) {
        return;
    }

    //int i=0, byte;
    //for(i=0;i<len;i++){
    //    if(i%8==0){
    //        LOG.debug("%08x: ", i);
    //    }
    //    byte = buf[i];
    //    LOG.debug("%02x%s", byte  & 0xFF, (i%2)? " ":"");
    //}

    char* tmp = new char[len*8 + 3];
    tmp[0] = '[';
    int pos = 1;
    for (int i=0; i<len; i++) {
        sprintf(&tmp[pos], "%02x ", buf[i]);
        pos += 3;
    }
    tmp[pos-1] = ']';
    tmp[pos] = 0;
    LOG.debug("%s", tmp);
    delete [] tmp;
}

⌨️ 快捷键说明

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