예제 #1
0
void M8MPoolConnectingApp::Refresh(std::vector<Network::SocketInterface*> &toRead, std::vector<Network::SocketInterface*> &toWrite) {
    M8MConfiguredApp::Tick();
    // First of all, shut down pools whose connection has gone down.
    auto goodbye = [this](Network::SocketInterface *test) {
        if(!test) return; // this happens as Network::SleepOn clears dormient sockets.
        if(test->Works()) return;
        auto entry(std::find_if(pools.begin(), pools.end(), [test](Pool &entry) { return entry.route == test; }));
        if(entry == pools.end()) return; // this could be for example a mini-server web socket
        ConnectionState(*entry->source, ce_failed);
        entry->source->Disconnected();
        network.CloseConnection(*entry->route);
        entry->route = nullptr;

        auto zero = std::chrono::system_clock::time_point();
        if(entry->activated != zero) {
            auto now(std::chrono::system_clock::now());
            entry->totalTime += now - entry->activated;
            entry->activated = zero;
            entry->nextReconnect = now + reconnectDelay;
        }
    };
    for(auto entry : toRead) goodbye(entry);
    for(auto entry : toWrite) goodbye(entry);
    // Then do proper IO.
    auto activated = [](const std::vector<Network::SocketInterface*> &sockets, Network::SocketInterface *check) {
        return std::find(sockets.cbegin(), sockets.cend(), check) != sockets.cend();
    };
    for(auto &entry : pools) {
        if(entry.source->Ready() == false) continue;
        auto r(activated(toRead, entry.route));
        auto w(activated(toWrite, entry.route));
        if(!w && !r) continue;

        auto &pool(*entry.source);
        auto happens(pool.Refresh(r, w));
        if(happens.connFailed) goodbye(entry.route);
        else {
            if(happens.bytesReceived) PoolCommand(pool);
            if(happens.diffChanged) DiffChange(pool, pool.GetCurrentDiff());
            if(happens.newWork) WorkChange(pool, std::unique_ptr<stratum::AbstractWorkFactory>(pool.GenWork()));
        }
    }
    // Then initialize pools which have just connected.
    for(auto &entry : pools) {
        if(entry.source->Ready()) continue; // already fully enabled, not connecting
        if(entry.route == nullptr) continue; // disabled, different algo, not even trying
        if(!activated(toWrite, entry.route)) continue;
        entry.activated = std::chrono::system_clock::now();
        entry.numActivations++;
        entry.source->Use(entry.route); // what if connection failed? Nothing. We try anyway and then bail out.
        ConnectionState(*entry.source, ce_ready);
    }
    AttemptReconnections();
}
예제 #2
0
파일: connection.c 프로젝트: blakawk/Aio4c
Connection* ConnectionClose(Connection* connection, bool force) {
    Log(AIO4C_LOG_LEVEL_DEBUG, "closing connection %s (force: %s)", connection->string, (force?"true":"false"));

    if (force) {
        ConnectionState(connection, AIO4C_CONNECTION_STATE_CLOSED);
    } else {
        ConnectionState(connection, AIO4C_CONNECTION_STATE_PENDING_CLOSE);
    }

    return connection;
}
예제 #3
0
asizei M8MPoolConnectingApp::BeginPoolActivation(const char *algo) {
    asizei activated = 0;
    for(auto &entry : pools) {
        if(_stricmp(entry.config.algo.c_str(), algo)) { // different algos get disabled.
            if(entry.route) {
                entry.source->Shutdown();
                network.CloseConnection(*entry.route);
                entry.route = nullptr;
            }
            auto zero = std::chrono::system_clock::time_point();
            if(entry.activated != zero) {
                entry.totalTime += std::chrono::system_clock::now() - entry.activated;
                entry.activated = zero;
            }
        }
        else if(entry.route) {
            // A spurious call. Let's just ignore it, when connection will complete, it will be activated.
            // Or perhaps not, if connection fails but that's nothing I can fix there!
            activated++; // they still count however.
        }
        else {
            const char *port = entry.config.explicitPort.length()? entry.config.explicitPort.c_str() : entry.config.service.c_str();
            auto conn(network.BeginConnection(entry.config.host.c_str(), port));
            if(conn.first == nullptr) {
                ConnectionState(*entry.source, MapError(conn.second));
                // A failing connection is a very bad thing. It probably just makes sense to bail out but in case it's transient,
                // let's retry with a multiple of retry delay. It's really odd so give it quite some time to clear out.
                entry.nextReconnect = std::chrono::system_clock::now() + reconnectDelay * 4;
            }
            else {
                entry.route = conn.first;
                activated++;
                ConnectionState(*entry.source, ce_connecting);
            }
            // note pool is not activated yet; they are activated in Refresh() when their connection is ready.
        }
    }
    return activated;
}
예제 #4
0
void M8MPoolConnectingApp::AttemptReconnections() {
    asizei restarted = 0;
    auto now(std::chrono::system_clock::now());
    auto zero = std::chrono::system_clock::time_point(); // for some reason writing this with init syntax makes Intellisense think it's a function
    for(auto &entry : pools) {
        if(entry.nextReconnect == zero) continue;
        if(entry.nextReconnect > now) continue;

        const char *port = entry.config.explicitPort.length()? entry.config.explicitPort.c_str() : entry.config.service.c_str();
        auto conn(network.BeginConnection(entry.config.host.c_str(), port));
        if(conn.first == nullptr) {
            ConnectionState(*entry.source, MapError(conn.second));
            // A failing connection is a very bad thing. It probably just makes sense to bail out but in case it's transient,
            // let's retry with a multiple of retry delay. It's really odd so give it quite some time to clear out.
            entry.nextReconnect = std::chrono::system_clock::now() + reconnectDelay * 4;
        }
        else {
            entry.route = conn.first;
            restarted++;
            entry.nextReconnect = zero;
            ConnectionState(*entry.source, ce_connecting);
        }
    }
}
예제 #5
0
파일: connection.c 프로젝트: blakawk/Aio4c
void ConnectionManagedBy(Connection* connection, ConnectionOwner owner) {
    bool managedByAll = true;
    int i = 0;

    TakeLock(connection->managedByLock);

    connection->managedBy[owner] = true;

    Log(AIO4C_LOG_LEVEL_DEBUG, "connection %s managed by: [reader:%u,worker:%u,writer:%u]", connection->string,
        connection->managedBy[AIO4C_CONNECTION_OWNER_READER], connection->managedBy[AIO4C_CONNECTION_OWNER_WORKER],
        connection->managedBy[AIO4C_CONNECTION_OWNER_WRITER]);

    for (i = 0; i < AIO4C_CONNECTION_OWNER_MAX; i++) {
        managedByAll = (managedByAll && connection->managedBy[i]);
    }

    ReleaseLock(connection->managedByLock);

    if (managedByAll) {
        Log(AIO4C_LOG_LEVEL_DEBUG, "connection %s is managed by all threads", connection->string);
        ConnectionState(connection, AIO4C_CONNECTION_STATE_CONNECTED);
    }

}
예제 #6
0
파일: connection.c 프로젝트: blakawk/Aio4c
Connection* ConnectionInit(Connection* connection) {
    ErrorCode code = AIO4C_ERROR_CODE_INITIALIZER;

#ifndef AIO4C_WIN32
    if ((connection->socket = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
        code.error = errno;
#else /* AIO4C_WIN32 */
    if ((connection->socket = socket(PF_INET, SOCK_STREAM, 0)) == SOCKET_ERROR) {
        code.source = AIO4C_ERRNO_SOURCE_WSA;
#endif /* AIO4C_WIN32 */
        return _ConnectionHandleError(connection, AIO4C_LOG_LEVEL_ERROR, AIO4C_SOCKET_ERROR, &code);
    }

#ifndef AIO4C_WIN32
    if (fcntl(connection->socket, F_SETFL, O_NONBLOCK) == -1) {
        code.error = errno;
#else /* AIO4C_WIN32 */
    unsigned long ioctl = 1;
    if (ioctlsocket(connection->socket, FIONBIO, &ioctl) == SOCKET_ERROR) {
        code.source = AIO4C_ERRNO_SOURCE_WSA;
#endif /* AIO4C_WIN32 */
        return _ConnectionHandleError(connection, AIO4C_LOG_LEVEL_ERROR, AIO4C_FCNTL_ERROR, &code);
    }

    ConnectionState(connection, AIO4C_CONNECTION_STATE_INITIALIZED);

    return connection;
}

Connection* ConnectionConnect(Connection* connection) {
    ErrorCode code = AIO4C_ERROR_CODE_INITIALIZER;
    ConnectionState newState = AIO4C_CONNECTION_STATE_CONNECTING;

    if (connection->state != AIO4C_CONNECTION_STATE_INITIALIZED) {
        code.expected = AIO4C_CONNECTION_STATE_INITIALIZED;
        return _ConnectionHandleError(connection, AIO4C_LOG_LEVEL_DEBUG, AIO4C_CONNECTION_STATE_ERROR, &code);
    }

    if (connect(connection->socket, AddressGetAddr(connection->address), AddressGetAddrSize(connection->address)) == -1) {
#ifndef AIO4C_WIN32
        code.error = errno;
        if (errno == EINPROGRESS) {
#else /* AIO4C_WIN32 */
        int error = WSAGetLastError();
        code.source = AIO4C_ERRNO_SOURCE_WSA;
        if (error == WSAEINPROGRESS || error == WSAEALREADY || error == WSAEWOULDBLOCK) {
#endif /* AIO4C_WIN32 */
            newState = AIO4C_CONNECTION_STATE_CONNECTING;
        } else {
            return _ConnectionHandleError(connection, AIO4C_LOG_LEVEL_ERROR, AIO4C_CONNECT_ERROR, &code);
        }
    } else {
        newState = AIO4C_CONNECTION_STATE_CONNECTED;
    }

    ConnectionState(connection, newState);

    return connection;
}

Connection* ConnectionFinishConnect(Connection* connection) {
    ErrorCode code = AIO4C_ERROR_CODE_INITIALIZER;
    int soError = 0;
    socklen_t soSize = sizeof(int);

#ifdef AIO4C_HAVE_POLL
    aio4c_poll_t polls[1] = { { .fd = connection->socket, .events = POLLOUT, .revents = 0 } };

#ifndef AIO4C_WIN32
    if (poll(polls, 1, -1) == -1) {
        code.error = errno;
#else /* AIO4C_WIN32 */
    if (WSAPoll(polls, 1, -1) == SOCKET_ERROR) {
        code.source = AIO4C_ERRNO_SOURCE_WSA;
#endif /* AIO4C_WIN32 */
        return _ConnectionHandleError(connection, AIO4C_LOG_LEVEL_ERROR, AIO4C_POLL_ERROR, &code);
    }

    if (polls[0].revents > 0) {
#else /* AIO4C_HAVE_POLL */
    fd_set writeSet;
    fd_set errorSet;

    FD_ZERO(&writeSet);
    FD_ZERO(&errorSet);
    FD_SET(connection->socket, &writeSet);
    FD_SET(connection->socket, &errorSet);

#ifndef AIO4C_WIN32
    if (select(connection->socket + 1, NULL, &writeSet, &errorSet, NULL) == -1) {
        code.error = errno;
#else /* AIO4C_WIN32 */
    if (select(connection->socket + 1, NULL, &writeSet, &errorSet, NULL) == SOCKET_ERROR) {
        code.source = AIO4C_ERRNO_SOURCE_WSA;
#endif /* AIO4C_WIN32 */
        return _ConnectionHandleError(connection, AIO4C_LOG_LEVEL_ERROR, AIO4C_SELECT_ERROR, &code);
    }

    if (FD_ISSET(connection->socket, &writeSet) || FD_ISSET(connection->socket, &errorSet)) {
#endif /* AIO4C_HAVE_POLL */

#ifndef AIO4C_WIN32
        if (getsockopt(connection->socket, SOL_SOCKET, SO_ERROR, &soError, &soSize) != 0) {
            code.error = errno;
#else /* AI4OC_WIN32 */
        if (getsockopt(connection->socket, SOL_SOCKET, SO_ERROR, (char*)&soError, &soSize) == SOCKET_ERROR) {
            code.source = AIO4C_ERRNO_SOURCE_WSA;
#endif /* AIO4C_WIN32 */
            return _ConnectionHandleError(connection, AIO4C_LOG_LEVEL_ERROR, AIO4C_GETSOCKOPT_ERROR, &code);
        }

        if (soError != 0) {
#ifndef AIO4C_WIN32
            code.error = soError;
#else /* AIO4C_WIN32 */
            code.source = AIO4C_ERRNO_SOURCE_SOE;
            code.soError = soError;
#endif /* AIO4C_WIN32 */
            return _ConnectionHandleError(connection, AIO4C_LOG_LEVEL_ERROR, AIO4C_FINISH_CONNECT_ERROR, &code);
        }
    }

    return connection;
}

Connection* ConnectionRead(Connection* connection) {
    Buffer* buffer = NULL;
    ssize_t nbRead = 0;
    ErrorCode code = AIO4C_ERROR_CODE_INITIALIZER;
    aio4c_byte_t* data = NULL;

    buffer = connection->readBuffer;

    if (!BufferHasRemaining(buffer)) {
        code.buffer = buffer;
        return _ConnectionHandleError(connection, AIO4C_LOG_LEVEL_ERROR, AIO4C_BUFFER_OVERFLOW_ERROR, &code);
    }

    data = BufferGetBytes(buffer);
    if ((nbRead = recv(connection->socket, (void*)&data[BufferGetPosition(buffer)], BufferRemaining(buffer), 0)) < 0) {
#ifndef AIO4C_WIN32
        code.error = errno;
#else /* AIO4C_WIN32 */
        code.source = AIO4C_ERRNO_SOURCE_WSA;
#endif /* AIO4C_WIN32 */
        return _ConnectionHandleError(connection, AIO4C_LOG_LEVEL_ERROR, AIO4C_READ_ERROR, &code);
    }

    ProbeSize(AIO4C_PROBE_NETWORK_READ_SIZE, nbRead);

    if (nbRead == 0) {
        if (connection->state == AIO4C_CONNECTION_STATE_PENDING_CLOSE) {
            ConnectionState(connection, AIO4C_CONNECTION_STATE_CLOSED);
            return connection;
        } else {
            return _ConnectionHandleError(connection, AIO4C_LOG_LEVEL_INFO, AIO4C_CONNECTION_DISCONNECTED, &code);
        }
    }

    if (!connection->canRead) {
        Log(AIO4C_LOG_LEVEL_WARN, "received data on connection %s when reading is not allowed", connection->string);
        BufferReset(buffer);
        return connection;
    }

    BufferPosition(buffer, BufferGetPosition(buffer) + nbRead);

    _ConnectionEventHandle(connection, AIO4C_INBOUND_DATA_EVENT);

    return connection;
}