LINUX.ORG.RU

Сообщения ocr

 

«Ассинхронность» QNetworkAccessManager

Создаю в потоке QThread несколько объектов QNetworkAccessManager и замечаю, что ОС создает отдельный поток для каждого объекта который создал сетевое соединение. Собираю на Qt-5.14.2, gcc 5.3.1 64x.

Я что-то делаю не так или это такая ассинхронность под капотом Qt?

 ,

ocr
()

PHP: stream_socket_enable_crypto не хочет переключать поток в режим шифрования

Пробую уже существующий сокет экспортировать в поток и перевести этот поток в режим TLS. В php.ini прописал:

openssl.cafile=/etc/ssl/certs/ca-certificates.crt
openssl.capath=/etc/ssl/certs

Пробую код:

<?php

    $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);

    $result = socket_connect($socket, 'google.com', 443);
    if ($result === false) {

            $str_err = "socket_connect() failed. Reason: ($result) ".socket_strerror(socket_last_error($socket));
            exit;
    }

    $opts = array(
    'ssl' => array(

        'verify_peer' => false,
        'verify_peer_name' => false,
        'allow_self_signed' => true,
    )
    );

    stream_context_set_default($opts);
    $fd = socket_export_stream($socket); //делаем из сокета поток

    if(stream_socket_enable_crypto($fd, true, STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT) === false) {

    die("Can't switch protocol");
    exit;
    }

echo "Success";
?>

Поток созданный из сокета в режим не переводится, гугл не помогает.

PHP 7.0.33-0+deb9u6 (cli) (built: Oct 24 2019 18:50:20) ( NTS )
Copyright (c) 1997-2017 The PHP Group
Zend Engine v3.0.0, Copyright (c) 1998-2017 Zend Technologies
    with Zend OPcache v7.0.33-0+deb9u6, Copyright (c) 1999-2017, by Zend Technologies

 , , ,

ocr
()

fork + popen. Залипание на wait при SIGCHLD

непоняная для меня картина случается когда выполняется код:

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

static void sig_chld_handler() {

	int status;
	wait(&status);
	//waitpid(-1, &status, WNOHANG);
}

void signals_init() {

	signal(SIGCHLD, sig_chld_handler);
}

void bash_cmd(char* cmd_str) {

	FILE* fp;
	const int buflen = 1024;
	char buf[buflen];

	if(!(fp = popen(cmd_str, "r"))) {

		fprintf(stderr, "\npopen error\n");
		return;
	}

	while( fgets(buf, buflen - 1, fp)  ) {

		fprintf(stderr, "\n%s", buf);
	}

	pclose(fp);
}

int main(void) {

	signals_init();
	pid_t pid = fork();

	if(!pid) {
		execl("/bin/sleep", "sleep", "1000", (char*)NULL);
		exit(EXIT_SUCCESS);
	}

	while(1) {

		bash_cmd("pwd");
		sleep(1);
	}

	return EXIT_SUCCESS;
}

Примерно на 3-10-й итерации цикла popen прилетает SICHLD и wait входит в ожидание. Если я не делаю execl(...) в форке, то wait ведет себя нормально.
Вместо wait стал использовать

waitpid(-1, &status, WNOHANG);
и в случае если прилетит sigchld, а никакой процесс не помер, то waitpid не впадет в ожидание.

Откуда SIGCHLD если никакой процесс не умер и почему это случается когда использую fork() до popen?

 , ,

ocr
()

Правильный(???) стиль работы со строковыми данными на С

Иногда (прямо сейчас) приходится обрабатыавть строки на C.
Меня коробит от громоздкости операций выделения памяти, конкатенации и самое главное это snprintf с проблемой размера буфера под конечную строку, гигантское поле для выращивания вских мемориликов по невнимательности.

К примеру, размеры mult1_str, mult2_str и equal_str известны, нужно выделить память под всю строку:

snprintf(
    buf,
    buflen,
    "%s miltilple %s equals %s",
    mult1_str,
    mult2_str,
    equal_str
    );
варианты:
- махнуть шашкой и сделать килобайт на стеке ( ((( )
- ничем не размахивать и посчитать руками. (еще хуже)
- написать функцию которая будет вычислять длину «%s miltilple %s equals %s» без символов подстановки (уже лучше)
- отказаться от snprintf и собирать строку пачкой конкатенаций с аллокациями памяти и прочим...

А как делаешь ты?

 ,

ocr
()

Статическая линковка myapp+libcurl+libssl

Понадобилось статически прилинковать к своему приложению curl+libssl.

Собираю openssl-1.1.1b:

./Configure linux-generic64 no-hw no-engine no-threads no-shared --prefix=/home/user/prg/openssl-1.1.1b_custom --openssldir=/home/user/prg/openssl-1.1.1b_custom

Собираю curl-7.64.1

export PKG_CONFIG_PATH=/home/user/prg/openssl-1.1.1b_custom/lib/pkgconfig
./configure --with-ssl=/home/user/prg/openssl-1.1.1b_custom --disable-shared --without-zlib --disable-pthreads --disable-threaded-resolver --disable-unix-sockets --disable-cookie --without-libssl1.0.2 --without-libssl1.0-dev --without-libssl1.1 --disable-ftp --disable-file --disable-ldap --disable-ldaps --disable-rtsp --disable-proxy --disable-dict --disable-telnet --disable-tftp --disable-pop3 --disable-imap --disable-smtp --disable-gopher --disable-sspi --disable-crypto-auth --disable-ntlm-wb --disable-tls-srp --disable-soname-bump --without-libssh2 --disable-curldebug --disable-debug --disable-ipv6 --without-librtmp --disable-ntlm-wb --disable-manual --prefix=/home/user/prg/curl-7.64.1_custom

Пишем тестовое приложение, типа

#include <curl/curl.h>

void test() {

    const char* url = "https://ya.ru";
    CURL* curl;
    CURLcode res;

    curl = curl_easy_init();
    curl_easy_setopt(curl, CURLOPT_URL, url);
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);

    res = curl_easy_perform(curl);

    //Если что-то пошло не так...
    if(res != CURLE_OK) {

    curl_easy_strerror(res);
    } else {

    //Все OK
    }

    curl_easy_cleanup(curl);
}

int main(int argc, char** argv) {

    curl_global_init(CURL_GLOBAL_ALL);
    test();
}

и собираем строчкой

cc -Wall --static `pkg-config --static --libs --cflags /home/user/prg/curl-7.64.1_custom/lib/pkgconfig/libcurl.pc /home/user/prg/openssl-1.1.1b_custom/lib/pkgconfig/libcrypto.pc /home/user/prg/openssl-1.1.1b_custom/lib/pkgconfig/libssl.pc` curl-test-1.c -o curl-test-1

Результат:

In function `test':
curl-test-1.c:(.text+0x105): undefined reference to `curl_easy_init'
curl-test-1.c:(.text+0x12a): undefined reference to `curl_easy_setopt'
curl-test-1.c:(.text+0x14c): undefined reference to `curl_easy_setopt'
curl-test-1.c:(.text+0x16e): undefined reference to `curl_easy_setopt'
curl-test-1.c:(.text+0x192): undefined reference to `curl_easy_setopt'
curl-test-1.c:(.text+0x19e): undefined reference to `curl_easy_perform'
curl-test-1.c:(.text+0x1b1): undefined reference to `curl_easy_strerror'
curl-test-1.c:(.text+0x1bd): undefined reference to `curl_easy_cleanup'
/tmp/ccxVQLrA.o: In function `main':
curl-test-1.c:(.text+0x1db): undefined reference to `curl_global_init'
collect2: error: ld returned 1 exit status
Голову ломаю и не пойму, ведь все библиотеки нормально собрались. Почему не видит статическую библиотеку?

 , ,

ocr
()

Си, fork() и глобальные переменные

Хочу впилить в свой сишный код уже готовый фрагмент кода и запустить его в другом процессе.
Код определяет и использует свои глобальные переменные, нигде кроме как в этом коде они не используются.
Это безопасно?

 , ,

ocr
()

Правильная обработка обрывов и ошибок QSslSocket

Гоняю данные по сети с помощью QSslSocket.
Непонятно как правильно обрабатывать обрывы и ошибки «правильно».

Чтобы упростить набросал пример в котором шлем запрос на вэбсервер и читаем пстрочно ответ:

#include "cnetworking.h"

CNetworking::CNetworking(QString host, quint16 port):
    b_sock_disconnected(false),
    b_sock_error_occured(false)
{

    ssl_sock = new QSslSocket();

    connect(ssl_sock, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(SockErrorSlot()));
    connect(ssl_sock, SIGNAL(disconnected()), this, SLOT(SockDisconnectedSlot()));
    ssl_sock->connectToHostEncrypted(host, port);

    //Сразу ждем зашифрованного соединения
    if(!ssl_sock->waitForEncrypted() ) {

        SetErrors();
        return;
    }

    //Шлем какие-то данные
    ssl_sock->write("GET / HTTP/1.1\r\nHost: yandex.ru\r\n\r\n");

    //Читаем построчно до признака окончания
    QByteArray ba;
    bool flag = true;
    do {

        //Если что-то с соединеием не так...
        if(!isConnectionOk()) {

            SetErrors();
            return;
        }

        if(ssl_sock->waitForReadyRead()) {

            if(ssl_sock->canReadLine()) {
                ba = ssl_sock->readLine();//В реальности тут что-то делаем с данными
                if(ba == "\r\n")
                    flag = false;
            }
        }

    }while(flag);

}

//Все ли нормально с соединением
bool CNetworking::isConnectionOk() {

    if(b_sock_disconnected == true || b_sock_error_occured == true)
        return false;

    return true;
}

void CNetworking::SetErrors() {

    sock_error = ssl_sock->error();
    sock_error_str = ssl_sock->errorString();
}

QString CNetworking::GetErrorStr() {

    return sock_error_str;
}

int CNetworking::GetError() {

    return sock_error;
}

void CNetworking::SockDisconnectedSlot() {

    qDebug() << "SockDisconnectedSlot";
    b_sock_disconnected = true;
}

void CNetworking::SockErrorSlot(QAbstractSocket::SocketError) {

    b_sock_error_occured = true;
    qDebug() << "SockErrorSlot";
    SetErrors();
}

CNetworking::~CNetworking() {

}

-----------------------------------

#ifndef CNetworking_H
#define CNetworking_H

#include <QSslSocket>
#include <QString>

class CNetworking: public QObject
{
        Q_OBJECT
public:
    CNetworking(QString host, quint16 port/*, quint16 data_read_timeout_msec*/);
    int GetError();
    QString GetErrorStr();
    virtual ~CNetworking();

private:

    bool isConnectionOk();
    
    void SetErrors();

    QSslSocket* ssl_sock;

    bool b_sock_disconnected;
    bool b_sock_error_occured;
    
    QString sock_error_str;
    QAbstractSocket::SocketError sock_error;

private slots:
    void SockDisconnectedSlot();
    void SockErrorSlot(QAbstractSocket::SocketError);
};

#endif // CNetworking_H


У меня есть сомнения:
Кажется странным везде перед чтением/записью лепить проверку

        //Если что-то с соединеием не так...
        if(!isConnectionOk()) {

            SetErrors();
            return;
        }

интуиция говорит что должен быть какой-то способ на уровне сигналов/слотов (завершить выполнение метода???)

И другой момент касается использования waitForReadyRead(). В документации сказано
Reimplemented from QAbstractSocket::waitForReadyRead().
Смотрим описание QAbstractSocket::waitForReadyRead():
Note: This function may fail randomly on Windows. Consider using the event loop and the readyRead() signal if your software will run on Windows.
Мой код должен запускаться и под линукс и под виндой. Стоит ли обращать внимание на этот Note и для винды делать что-то типа:
QEventLoop myloop;

myloop.connect(ssl_sock, SIGNAL(connected()), SLOT(quit()));
myloop.connect(ssl_sock, SIGNAL(error(QAbstractSocket::SocketError)), SLOT(quit()));

myloop.exec();

Благодарю за любую помощь, критику или подсказки

 ,

ocr
()

В libcurl утечка памяти чтоли

Сделал пачку потоков в которых забирал файлы по https
Заметил что сильно отъедает память Для проверки сделал тестовый кусок кода, поднял апач и в цикле забирал один и тот же файл:

#include <curl/curl.h>
#include <thread>

size_t writefunc(void* ptr, size_t size, size_t nmemb, std::string* userdata) {

    return size*nmemb;
}

void thread_test() {

    const char* url = "https://КАКОЙ-ТО УРЛ";

    CURL* curl;
    CURLcode res;

    while(true) {

    curl = curl_easy_init();

    curl_easy_setopt(curl, CURLOPT_URL, url);
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); // Не будем проверять сертификаты
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); // Не будем проверять сертификаты

    //чтобы не валило в stdout
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writefunc);
//	curl_easy_setopt(curl, CURLOPT_WRITEDATA, &write_data);


//	curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);

    res = curl_easy_perform(curl);

    //Если что-то пошло не так...
    if(res != CURLE_OK) {

        curl_easy_strerror(res);
    } else {

    //Все OK

    }

    curl_easy_cleanup(curl);

    }


}

main() {

    curl_global_init(CURL_GLOBAL_ALL);

    int thread_num = 100;

    //Запускаем потоки
    std::thread threads[thread_num];
    for(int i = 0 ; i < thread_num ; i++) {

    threads[i] = std::thread(thread_test);
    }

    for(int i = 0 ; i < thread_num ; i++) {

    threads[i].join();
    }

}


собираем
g++ -std=c++11 curl-test-0.cpp -lcurl -lpthread -o curl-test-0
ldd:
	linux-vdso.so.1 (0x00007ffcf8d6c000)
	libcurl-nss.so.4 => /usr/lib/x86_64-linux-gnu/libcurl-nss.so.4 (0x00007f679df56000)
	libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f679dd39000)
	libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f679d9b7000)
	libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f679d6b3000)
	libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f679d49c000)
	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f679d0fd000)
	libnghttp2.so.14 => /usr/lib/x86_64-linux-gnu/libnghttp2.so.14 (0x00007f679ced7000)
	libidn2.so.0 => /usr/lib/x86_64-linux-gnu/libidn2.so.0 (0x00007f679ccb5000)
	librtmp.so.1 => /usr/lib/x86_64-linux-gnu/librtmp.so.1 (0x00007f679ca98000)
	libssh2.so.1 => /usr/lib/x86_64-linux-gnu/libssh2.so.1 (0x00007f679c86c000)
	libpsl.so.5 => /usr/lib/x86_64-linux-gnu/libpsl.so.5 (0x00007f679c65e000)
	libnss3.so => /usr/lib/x86_64-linux-gnu/libnss3.so (0x00007f679c314000)
	libnssutil3.so => /usr/lib/x86_64-linux-gnu/libnssutil3.so (0x00007f679c0e6000)
	libsmime3.so => /usr/lib/x86_64-linux-gnu/libsmime3.so (0x00007f679beb9000)
	libssl3.so => /usr/lib/x86_64-linux-gnu/libssl3.so (0x00007f679bc61000)
	libplds4.so => /usr/lib/x86_64-linux-gnu/libplds4.so (0x00007f679ba5d000)
	libplc4.so => /usr/lib/x86_64-linux-gnu/libplc4.so (0x00007f679b858000)
	libnspr4.so => /usr/lib/x86_64-linux-gnu/libnspr4.so (0x00007f679b618000)
	libgssapi_krb5.so.2 => /usr/lib/x86_64-linux-gnu/libgssapi_krb5.so.2 (0x00007f679b3cd000)
	libkrb5.so.3 => /usr/lib/x86_64-linux-gnu/libkrb5.so.3 (0x00007f679b0f3000)
	libk5crypto.so.3 => /usr/lib/x86_64-linux-gnu/libk5crypto.so.3 (0x00007f679aec0000)
	libcom_err.so.2 => /lib/x86_64-linux-gnu/libcom_err.so.2 (0x00007f679acbc000)
	liblber-2.4.so.2 => /usr/lib/x86_64-linux-gnu/liblber-2.4.so.2 (0x00007f679aaad000)
	libldap_r-2.4.so.2 => /usr/lib/x86_64-linux-gnu/libldap_r-2.4.so.2 (0x00007f679a85c000)
	libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007f679a642000)
	/lib64/ld-linux-x86-64.so.2 (0x00007f679e3dc000)
	libunistring.so.0 => /usr/lib/x86_64-linux-gnu/libunistring.so.0 (0x00007f679a32b000)
	libgnutls.so.30 => /usr/lib/x86_64-linux-gnu/libgnutls.so.30 (0x00007f6799f92000)
	libhogweed.so.4 => /usr/lib/x86_64-linux-gnu/libhogweed.so.4 (0x00007f6799d5d000)
	libnettle.so.6 => /usr/lib/x86_64-linux-gnu/libnettle.so.6 (0x00007f6799b26000)
	libgmp.so.10 => /usr/lib/x86_64-linux-gnu/libgmp.so.10 (0x00007f67998a3000)
	libgcrypt.so.20 => /lib/x86_64-linux-gnu/libgcrypt.so.20 (0x00007f6799593000)
	libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f679938f000)
	librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007f6799187000)
	libkrb5support.so.0 => /usr/lib/x86_64-linux-gnu/libkrb5support.so.0 (0x00007f6798f7b000)
	libkeyutils.so.1 => /lib/x86_64-linux-gnu/libkeyutils.so.1 (0x00007f6798d77000)
	libresolv.so.2 => /lib/x86_64-linux-gnu/libresolv.so.2 (0x00007f6798b60000)
	libsasl2.so.2 => /usr/lib/x86_64-linux-gnu/libsasl2.so.2 (0x00007f6798945000)
	libp11-kit.so.0 => /usr/lib/x86_64-linux-gnu/libp11-kit.so.0 (0x00007f67986e0000)
	libidn.so.11 => /lib/x86_64-linux-gnu/libidn.so.11 (0x00007f67984ac000)
	libtasn1.so.6 => /usr/lib/x86_64-linux-gnu/libtasn1.so.6 (0x00007f6798299000)
	libgpg-error.so.0 => /lib/x86_64-linux-gnu/libgpg-error.so.0 (0x00007f6798085000)
	libffi.so.6 => /usr/lib/x86_64-linux-gnu/libffi.so.6 (0x00007f6797e7c000)

Вскоре после запуска наблюдаем увеличение отъедаемой памяти. На гитхабе были какие-то разговоры про подобное, но решение не засветили. Специально использовал NSS потомучто на офсайте curl сказано что он потокобезопасный, а OpenSSL не всех версий. Проблема наблюдается только при работе по HTTPS.
Это на стретче 64х,

curl 7.52.1 (x86_64-pc-linux-gnu) libcurl/7.52.1 OpenSSL/1.0.2q zlib/1.2.8 libidn2/0.16 libpsl/0.17.0 (+libidn2/0.16) libssh2/1.7.0 nghttp2/1.18.1 librtmp/2.3
Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps pop3 pop3s rtmp rtsp scp sftp smb smbs smtp smtps telnet tftp 
Features: AsynchDNS IDN IPv6 Largefile GSS-API Kerberos SPNEGO NTLM NTLM_WB SSL libz TLS-SRP HTTP2 UnixSockets HTTPS-proxy PSL

Как быть?

 , ,

ocr
()

Выбор асинхронного днс-резолвера

Выбираю асихронный днс-резолвер для работы с libevent.
Тот что изкоробки не подходит потому что не работает с произвольными типами записей.

Рассматривал c-ares, но после просмотра документации и беглого осмотра кода посчитал что для работы с мультиплексирующими библиотеками он не подходит, автор немного увлекся select'ом и разнообразными FD_SET.

Остановился на udns: http://www.corpit.ru/mjt/udns.html, он же есть в стретче. Смущает то что код давно не обновлялся и скудная документация, но это компенсирует хороший говорящий код.

Какие подводные камни c udns?

 , ,

ocr
()

libevent thread-safe

Хочу мультиплексировать libevent'ом в нескольких потоках.
В документации сказано о потокобезопасности для случая когда несколько потоков работают с одним и тем же циклом обработки событий, а про потокобезопасность изолированных в разных потоках event_base и работу с OpenSSL не нашел.

В разных потоках и с OpenSSL безопасно?

 ,

ocr
()

Куда логиниться, кэп?

На работе создали типа корпоративной почты и выдали мыло с паролем. Когда настал момент забрать почту, я понял что не знаю как войти в ящик. Как выяснилось, у меня небыло адреса smtp-сервера.

Гугление и перебор субдоменов smtp и smtps ничего не дало. Тогда я открыл для себя RFC5321. В нем было все, даже то что MX-запись содержит домен на котором сервис принимает почту от других серверов, но не про то куда подключиться пользователю.

Стандаризированный способ узнать адрес smtp-сервера для подключения пользователей существует?

ЗЫ Поправлю что нужен и IMAP/POP3 и SMTP. Имею представление что для чего

 , ,

ocr
()

RSS подписка на новые темы