SSL传输数据时,是根据记录进行传输的socket(tcp)是面向流的协议。原因估计是要加密与解密。
比如:一端SSL_write(ssl,buf, size)之后再SSL_write(ssl, buf, size)
另一端SSL_read(ssl,buf, size-n)之后再SSL_read(ssl, buf, 2*size),此时buf中只有n个数据。
这是与socket不同的一点。
SSL的错误处理与socket错误处理方式不同,SSL 调用返回值描述中没有关于设置errno。
SSL协议是在socket之上的的协议,有SSL自己的握手与关闭过程
客户端,在connect成功返回后,若要加密传输,可先通知服务端要进行加密传输,需要先发送给服务端一段选择数据,之后则处理scoket描述符调用SSL_connect进行握手。
服务端,在accept成功返回后,先接收一段选择数据,如要加密传输,则要处理socket描述符之后调用SSL_accept进行握手
SSL io目前发现两个,SSL_read和SSL_write
SSL_read:基于SSL/TLS记录,记录有个最大值(man中是16KB)。仅当一个记录完全接收完后,SSL_read才能处理。SSL_read读数据是按记录(最大16kb)进行读取,如果底层io是blocking,SSL_read会在完成读或发生错误是返回。除非发生重新协商。调用SSL_get_error()查看错误原因
SSL_write:按记录进行写,如果写的数据size比最大记录(16kb)大,就会将数据分成多个记录写入,直到写完size个数据后返回。如果底层io是blocking的,SSL_write会在完成写或出错时返回,除非发生重新协商。调用SSL_get_error()查看错误。
Libev支持:
Libev库中的事件是监视socket描述符进行的,当socket描述符对应的连接缓冲区有数据时,事件被触发,而SSL是在socket(tcp)之上的的一层协议,在使用的时候与socket是有区别的,SSL就像是在socket(tcp) 之上作的一层应用,这层应用有自己的IO函数(SSL_read,SSL_write),同样的是,SSL层还有自己的缓冲区。SSL使用libev的问题就出在SSL缓冲区这一块,比如出现这种情况:socket(tcp)缓冲区中有4KB字节,此时触发libev事件,调用回调函数,回调函数中的IO使用的是SSL_read,通过SSL_read读,size参数是2KB,所以只读取了2KB字节就返回,此时socket缓冲区中可能已经没有了数据,即4KB字节的数据全被SSL读到自己的缓冲区中了,这样,没有通过SSL_read读出的剩下2KB字节就无法触发libev事件,这样回调函数就无法被调用,剩下的2KB字节就无法读出。
SSL_read读取数据过程(通过libev事件验证得到的)
如果SSL缓冲区中有数据,就从SSL缓冲区中读取,如果SSL缓冲区没有数据,就从socket缓冲区中读取(以个记录为单位进行读)。另外,SSL缓冲区中的数据都是同一个记录的数据,每一次SSL层从socket缓冲区读数据时,无论socket缓冲区有多少数据,SSL层每次只读一个记录的数据(最大是16KB),这样,当有大量数据是,SSL层会频繁的进行系统调用进入内核读数据,会影响性能,但还没有找到方法改变SSL层缓冲区限制。
对于libev的支持方面,如果每次SSL_read都按leosync协议的记录(先读一个头,在从头中获取之后数据的大小)进行读取,SSL_read是可以使用的,但是还是会有性能的影响,因为一个事件的发生,可能会频繁的进入内核读取数据。
SSL_write的写过程与都过程类似,如果写的数据大小 < 16KB这按一个记录进行写,如果 > 16KB,则分成多个记录进行写。
SSL错误处理
SSL_get_error(SSL*, int)函数是专门处理SSL I/O操作错误的函数,SSL_get_error监视当前线程的OpenSSL错误队列,SSL_get_error必须使用在当同一线程的SSLI/O操作上,并且I/O操作与SSL_get_error之间没有其他的OpenSSL函数调用。其中SSL I/O的返回值是SSL_get_error函数的第二个参数。如果出现的是linux文件系统的IO错误,则SSL_get_error会返回SSL_ERROR_SYSCALL,通过errno查看错误原因。
在支持加密传输的程序中,
SSL_CTX_set_mode
SSL_connect
SSL_set_connect_state
SSL_accept
SSL_set_accept_state
SSL_shutdown
SSL_set_shutdown
SSL_get_error
SSL_library_init
SSL_CTX_new
SSL_new
SSL_set_fd
SSL错误处理
Leosync 加密传输
Client部分
Connect过程
Client在需要传输数据时才进行必要tcp连接,
LsTarget::comm->lsNetServer::getCommand->lsNetServer::getCommandPoint
->lsNetServer::getCommandPointLocked->lsNetPoint::connect
->lsCommandPoint::connectLocked
这些方法的参数中要增加iscryto 参数选项。
客户端与服务器完成tcp连接时,客户端要通过tcp通知服务器是否需要加密传输。客户端和服务端都要处理加密选项的处理。
Client在传输数据的过程