/* Non-blocking write data. Return the number of bytes written or -1 on errors. Returns zero if part of the data was written. Encode caller's data buffer into an SSL record and write to socket. The encoded data will always be bigger than the incoming data because of the record header (5 bytes) and MAC (16 bytes MD5 / 20 bytes SHA1) This would be fine if we were using blocking sockets, but non-blocking presents an interesting problem. Example: A 100 byte input record is encoded to a 125 byte SSL record We can send 124 bytes without blocking, leaving one buffered byte We can't return 124 to the caller because it's more than they requested We can't return 100 to the caller because they would assume all data has been written, and we wouldn't get re-called to send the last byte We handle the above case by returning 0 to the caller if the entire encoded record could not be sent. Returning 0 will prompt us to select this socket for write events, and we'll be called again when the socket is writable. We'll use this mechanism to flush the remaining encoded data, ignoring the bytes sent in, as they have already been encoded. When it is completely flushed, we return the originally requested length, and resume normal processing. */ PUBLIC ssize sslWrite(Webs *wp, void *buf, ssize len) { Ms *ms; uchar *obuf; ssize encoded, nbytes, written; ms = (Ms*) wp->ssl; while (len > 0 || ms->outlen > 0) { if ((encoded = matrixSslGetOutdata(ms->handle, &obuf)) <= 0) { if (ms->outlen <= 0) { ms->outbuf = (char*) buf; ms->outlen = len; ms->written = 0; len = 0; } nbytes = min(ms->outlen, SSL_MAX_PLAINTEXT_LEN); if ((encoded = matrixSslEncodeToOutdata(ms->handle, (uchar*) buf, (int) nbytes)) < 0) { return encoded; } ms->outbuf += nbytes; ms->outlen -= nbytes; ms->written += nbytes; } if ((written = socketWrite(wp->sid, obuf, encoded)) < 0) { return written; } else if (written == 0) { break; } matrixSslSentData(ms->handle, (int) written); } /* Only signify all the data has been written if MatrixSSL has absorbed all the data */ return ms->outlen == 0 ? ms->written : 0; }
CAMLprim value stub_encode_data(value ssl, value str) { CAMLparam2(ssl,str); unsigned char *buf=NULL; int len=0; int rc; memcpy(buf,String_val(str),len); len = caml_string_length(str); rc=matrixSslEncodeToOutdata(ssl_t_val(ssl), (unsigned char *)String_val(str), len); if(rc<0) { caml_failwith("Failed to encode writebuf"); } CAMLreturn(Val_int(rc)); }