PORT_Assert( ssl_HaveXmitBufLock(ss) );
PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss) );
ssl2_SendBlock(sslSocket *ss, const PRUint8 *in, PRInt32 len, PRInt32 flags){    PRUint8       *  out;  		    /* begining of output buffer.    */    PRUint8       *  op;		    /* next output byte goes here.   */    int              rv;		    /* value from funcs we called.   */    int              count	= 0;        /* this function's return value. */    unsigned int     hlen;		    /* output record hdr len, 2 or 3 */    unsigned int     macLen;		    /* MAC is this many bytes long.  */    int              amount;		    /* of plaintext to go in record. */    unsigned int     padding;		    /* add this many padding byte.   */    int              nout;		    /* ciphertext size after header. */    int              buflen;		    /* size of generated record.     */    PORT_Assert( ssl_HaveXmitBufLock(ss) );    SSL_TRC(10, ("%d: SSL[%d]: sending %d bytes using block cipher",		 SSL_GETPID(), ss->fd, len));    PRINT_BUF(50, (ss, "clear data:", in, len));    while (len) {	ssl_GetSpecReadLock(ss);  /*************************************/	macLen = ss->sec.hash->length;	/* Figure out how much to send, including mac and padding */	amount  = PR_MIN( len, MAX_BLOCK_CYPHER_LEN );	nout    = amount + macLen;	padding = nout & (ss->sec.blockSize - 1);	if (padding) {	    hlen    = 3;	    padding = ss->sec.blockSize - padding;	    nout   += padding;	} else {	    hlen = 2;	}	buflen = hlen + nout;	if (buflen > ss->sec.writeBuf.space) {	    rv = sslBuffer_Grow(&ss->sec.writeBuf, buflen);	    if (rv != SECSuccess) {		goto loser;	    }	}	out = ss->sec.writeBuf.buf;	/* Construct header */	op = out;	if (padding) {	    *op++ = MSB(nout);	    *op++ = LSB(nout);	    *op++ = padding;	} else {	    *op++ = 0x80 | MSB(nout);	    *op++ = LSB(nout);	}	/* Calculate MAC */	rv = ssl2_CalcMAC(op, 		/* MAC goes here. */	                  &ss->sec, 		          in, amount, 	/* intput addr, len */			  padding);	if (rv != SECSuccess) 	    goto loser;	op += macLen;	/* Copy in the input data */	/* XXX could eliminate the copy by folding it into the encryption */	PORT_Memcpy(op, in, amount);	op += amount;	if (padding) {	    PORT_Memset(op, padding, padding);	    op += padding;	}	/* Encrypt result */	rv = (*ss->sec.enc)(ss->sec.writecx, out+hlen, &nout, buflen-hlen,			 out+hlen, op - (out + hlen));	if (rv) 	    goto loser;	ssl_ReleaseSpecReadLock(ss);  /*************************************/	PRINT_BUF(50, (ss, "final xmit data:", out, op - out));	rv = ssl_DefSend(ss, out, op - out, flags & ~ssl_SEND_FLAG_MASK);	if (rv < 0) {	    if (PORT_GetError() == PR_WOULD_BLOCK_ERROR) {		rv = 0;	    } else {		SSL_TRC(10, ("%d: SSL[%d]: send block error %d",			     SSL_GETPID(), ss->fd, PORT_GetError()));		/* Return short write if some data already went out... */		if (count == 0)		    count = rv;		goto done;	    }	}	if (rv < (op - out)) {	    /* Short write.  Save the data and return. */	    if (ssl_SaveWriteData(ss, &ss->pendingBuf, out + rv,				  op - out - rv) == SECFailure) {		count = SECFailure;	    } else {		count += amount;		ss->sec.sendSequence++;	    }	    goto done;	}	ss->sec.sendSequence++;	in    += amount;	count += amount;	len   -= amount;    }done:    return count;loser:    ssl_ReleaseSpecReadLock(ss);    return SECFailure;}