Запрашивать у пользователя логин пароль в браузере при использовании winsock - PullRequest
2 голосов
/ 28 апреля 2020

Я написал код на C ++ с Winsock. Он преобразует видео в поток mjpeg и отправляет его по TCP с помощью Winsock в windows. Теперь я могу посмотреть видео в любом браузере по ссылке. Но проблема в том, что любой, у кого есть ссылка, может это увидеть. Я хочу предложить пользователю ввести имя пользователя и пароль для доступа к каналу всякий раз, когда он вводит IP-адрес.

Вот мой код:

    #include <winsock.h>
    #include <windows.h>
    #include <time.h>
    #define PORT        unsigned long
    #define ADDRPOINTER   int*
    struct _INIT_W32DATA
    {
       WSADATA w;
       _INIT_W32DATA() { WSAStartup( MAKEWORD( 2, 1 ), &w ); }
    } _init_once;


#include <iostream>
using std::cerr;
using std::endl;

#include <iostream>
#pragma comment(lib, "wsock32.lib")
using namespace std;


class MJPGWriter
{
    SOCKET sock;
    fd_set master;
    int timeout; // master sock timeout, shutdown after timeout millis.
    int quality; // jpeg compression [1..100]

    int _write( int sock, char *s, int len ) 
    { 
        if ( len < 1 ) { len = strlen(s); }
        return ::send( sock, s, len, 0 );
    }

public:

    MJPGWriter(int port = 0) 
        : sock(INVALID_SOCKET) 
        , timeout(20000)
        , quality(30)
    {
        FD_ZERO( &master );
            if (port)
                open(port);
    }

    ~MJPGWriter() 
    {
        release();
    }

    bool release()
    {
        if ( sock != INVALID_SOCKET )
            ::shutdown( sock, 2 );
        sock = (INVALID_SOCKET);
        return false;
    }

    bool open( int port )
    {
        sock = ::socket (AF_INET, SOCK_STREAM, IPPROTO_TCP) ;

        SOCKADDR_IN address;       
        address.sin_addr.s_addr = INADDR_ANY;
        address.sin_family      = AF_INET;
        address.sin_port        = ::htons(port);
        if ( ::bind( sock, (SOCKADDR*) &address, sizeof(SOCKADDR_IN) ) == SOCKET_ERROR )
        {
            cerr << "error : couldn't bind sock "<<sock<<" to port "<<port<<"!" << endl;
            return release();
        }
        if ( ::listen( sock, 10 ) == SOCKET_ERROR )
        {
            cerr << "error : couldn't listen on sock "<<sock<<" on port "<<port<<" !" << endl;
            return release();
        }
        FD_SET( sock, &master );    
        return true;
    }

    bool isOpened() 
    {
        return sock != INVALID_SOCKET; 
    }

    bool write(const cv::Mat & frame)
    {
        fd_set rread = master;
        struct timeval to = {0,timeout};
        SOCKET maxfd = sock+1;

        if ( ::select( maxfd, &rread, NULL, NULL, &to ) <= 0 )
            return true; // nothing broken, there's just noone listening

        std::vector<uchar>outbuf;
        std::vector<int> params;
        params.push_back(cv::IMWRITE_JPEG_QUALITY);
        params.push_back(quality);
        cv::imencode(".jpg", frame, outbuf, params);
        int outlen = outbuf.size();

        #ifdef _WIN32 
        for ( unsigned i=0; i<rread.fd_count; i++ )
        {
            SOCKET s = rread.fd_array[i];    // fd_set on win is an array, while ...
        #else         
        for ( int s=0; s<maxfd; s++ )
        {
            if ( ! FD_ISSET(s,&rread) )      // ... on linux it's a bitmask ;)
                continue;
        #endif                   
            if ( s == sock ) // request on master socket, accept and send main header.
            {
                int         addrlen = sizeof(SOCKADDR);
                SOCKADDR_IN address = {0};     
                SOCKET      client  = ::accept( sock,  (SOCKADDR*)&address, &addrlen );
                if ( client == SOCKET_ERROR )
                {
                    cerr << "error : couldn't accept connection on sock " << sock<< " !" << endl;
                    return false;
                }
                maxfd=(maxfd>client?maxfd:client);
                FD_SET( client, &master );
                _write( client,"HTTP/1.0 200 OK\r\n",0);
                _write( client,
                    "Server: Mozarella/2.2\r\n"
                    "Accept-Range: bytes\r\n"
                    "Connection: close\r\n"
                    "Max-Age: 0\r\n"
                    "Expires: 0\r\n"
                    "Cache-Control: no-cache, private\r\n"
                    "Pragma: no-cache\r\n"
                    "Content-Type: multipart/x-mixed-replace; boundary=mjpegstream\r\n"
                    "\r\n",0);
                cerr << "new client " << client << endl;
            } 
            else // existing client, just stream pix
            {
                char head[400];
                sprintf(head,"--mjpegstream\r\nContent-Type: image/jpeg\r\nContent-Length: %lu\r\n\r\n",outlen);
                _write(s,head,0);
                int n = _write(s,(char*)(&outbuf[0]),outlen);
                //cerr << "known client " << s << " " << n << endl;
                if ( n < outlen )
                {
                    cerr << "kill client " << s << endl;
                    ::shutdown(s,2);
                    FD_CLR(s,&master);
                }
            }
        }
        return true;
    }
};

Я использую его, отправив изображение кадр и номер порта для устройства записи.

...