在C#中使用OpenSSL在C#中无效的SniStream缓冲区数据重叠错误

问题描述

我实现了一个抽象抽象流的流类。 此类称为sniStream,我想将Sni工具添加到c#。

sniStream的来源是这样的,它使用了我已经实现的本地c ++库:

 public class SniStream : Stream
        {
            [DllImport(@"SniReceiver.dll",CallingConvention = CallingConvention.StdCall)]
            private static extern int write_ssl(string data);
    
            [DllImport(@"SniReceiver.dll",CharSet = CharSet.Ansi,CallingConvention = CallingConvention.StdCall)]
            private static extern int read_ssl_sni(byte[] data,int offset,int count);
    
            [DllImport(@"SniReceiver.dll",CallingConvention = CallingConvention.StdCall)]
            private static extern void cleanup_openssl();
    
            [DllImport(@"SniReceiver.dll",CallingConvention = CallingConvention.Cdecl)]
            private static extern IntPtr get_domainname(IntPtr sock);
    
            [DllImport(@"SniReceiver.dll",CallingConvention = CallingConvention.StdCall)]
            private static extern int get_ssl_pending();
    
            [DllImport(@"SniReceiver.dll",CallingConvention = CallingConvention.Cdecl)]
            private static extern IntPtr load_all_ssl_certificates(string path);
    public SniStream(Stream innerStream,bool leaveInnerStreamOpen)

    {
        innerStream = this;
        CanWrite = CanRead = true;
        Position = 0;
        CanSeek = false;          
    }
    }

 public override long Position { get; set; }


        public override long Length { get; }

        public override bool CanWrite { get; }

        public override bool CanSeek { get; }

        public override bool CanRead { get; }
        public override long Seek(long offset,SeekOrigin origin) => throw new NotImplementedException();

        public override void SetLength(long value) => throw new NotImplementedException();
public override void Write(byte[] buffer,int count)
        {            
            int writed = write_ssl(Encoding.UTF8.GetString(buffer));
            Position += writed;
            //Array.Clear(buffer,buffer.Length);
        }
public override int Read(byte[] buffer,int count)
        {
            int received = 0;
            string s = "";                    
            Array.Clear(buffer,buffer.Length);
            received = read_ssl_sni(buffer,offset,count);
            Position += received;
            return received;

        }
 public override ValueTask WriteAsync(ReadOnlyMemory<byte> buffer,CancellationToken cancellationToken = default)
        {
            return new ValueTask(new Task(() => {
                int read= write_ssl(Encoding.UTF8.GetString(buffer.ToArray()));
                Position += read;                
                })
                );
         
        }
 public override ValueTask<int> ReadAsync(Memory<byte> buffer,CancellationToken cancellationToken = default)
        {
            int revieved = 0;
            string s = "";

            Array.Clear(buffer.ToArray(),buffer.Length);
            revieved=read_ssl_sni(buffer.ToArray(),0);
            Position += revieved;
            return new ValueTask<int>(revieved);
           

        }
        public override Task<int> ReadAsync(byte[] buffer,int count,CancellationToken cancellationToken)
        {
            int revieved = 0;
            string s = "";
     

            Array.Clear(buffer,buffer.Length);
            revieved = read_ssl_sni(buffer,count);
            Position += revieved;
            return Task.Fromresult(revieved);
         
        }

        public string GetDomainName(Socket sClient)
        {
            return Marshal.PtrToStringAnsi(get_domainname(sClient.Handle));
        }

        public static string LoadAllCertificates(string path)
        {
            string res = Marshal.PtrToStringAnsi(load_all_ssl_certificates(path));
            return "";
        }

        public override void Flush()
        {
            //cleanup_openssl();
            Position = 0;
        }

C ++ SniReader是这样的:

#include "stdafx.h"
#include "SniReceiver.h"

#include <algorithm>
#include <cctype>
#include <string>   


SSL *ssl;
          

SSL_CTX *create_context(SSL_CTX *ctx)
{
    const SSL_METHOD *method;
    method = TLSv1_2_server_method();

    ctx = SSL_CTX_new(method);
    if (!ctx) {
        perror("Unable to create SSL context");
        ERR_print_errors_fp(stderr);
        exit(EXIT_FAILURE);
    }
    return ctx;
}

const char * load_all_ssl_certificates(char* certicatesPath)
{
    //load certificates from a folder
}

void init_openssl()
{
    SSL_load_error_strings();
    OpenSSL_add_ssl_algorithms();
}
void cleanup_openssl()
{
    EVP_cleanup();
    SSL_free(ssl);
}


static int ssl_servername_cb(SSL *s,int *ad,void *arg)
{
    const char *servername = SSL_get_servername(s,TLSEXT_NAMETYPE_host_name);
    domainname = servername;
    if (servername != NULL) {
        SSL_CTX * cc = certificates.at(servername);
        SSL_set_SSL_CTX(s,cc);
    }
    return SSL_TLSEXT_ERR_OK;
}

extern "C" __declspec(dllexport) const char * __cdecl get_domainname(DWORD socket)
{
    SSL_CTX *ctx = NULL;
    init_openssl();
    ctx = create_context(ctx);
    SSL_CTX_set_tlsext_servername_callback(ctx,ssl_servername_cb);

    ssl = SSL_new(ctx);
    int x = SSL_set_fd(ssl,socket);
    int hand = SSL_do_handshake(ssl);
    int acc = SSL_accept(ssl);

    return domainname;
}


extern "C" __declspec(dllexport) int __stdcall write_ssl(char data[])
{
    int writed=SSL_write(ssl,data,strlen(data));
    return writed;
}

extern "C" __declspec(dllexport) int __stdcall read_ssl_sni(char recvb[],int count)
{   
    const int recvbuflen = 4096;
    char recvbuf[recvbuflen];       
    return(SSL_read(ssl,recvb,count));            
}

文件是这个

#include <WinSock2.h>
#include "minwindef.h"
#include <iostream>
#include <openssl/crypto.h>
#include <openssl/x509.h>
#include <openssl/pem.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/bio.h>
#include <openssl/err.h>
#include <openssl/evp.h>
#include <map>

#include <tuple>
#include <filesystem> //New in C++ 17 //old one include <dirent.h> for windows
namespace fs = std::filesystem; // work with vs 2019


std::map<std::string,SSL_CTX *> certificates;

const char *domainname;
char *readResult;


extern "C" __declspec(dllexport) char * __cdecl receive_socket(DWORD socket);

extern "C" __declspec(dllexport) const char * __cdecl load_all_ssl_certificates(char* path);

extern "C" __declspec(dllexport) int __stdcall add_num(int a,int b);

extern "C" __declspec(dllexport) int __stdcall write_ssl(char* data);

extern "C" __declspec(dllexport) int __stdcall read_ssl_sni(char recvbuf[],int count);

extern "C" __declspec(dllexport) const char * __cdecl get_domainname(DWORD socket);

extern "C" __declspec(dllexport) int __stdcall get_ssl_pending();

extern "C" __declspec(dllexport) void __cdecl cleanup_openssl();

问题是c#程序在异步模式下使用sniStream。我有2页,一个叫做fulsh, 其他同花顺2。 (冲洗只是名称,而不是冲洗流)。

flush返回flush,而flush2返回flush2。

当我先调用每个,在加载第一个之前,在浏览器的新标签页中调用第二个时,第二页的内容先于前。我认为缓冲区中的某些部分重叠。 我在msdn上了解到,异步方法的流类的实现者应在其中调用Read和Write方法

有什么想法吗?我应该创建一个在sniStream中共享为缓冲区的字节数组吗?

enter image description here

enter image description here

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)