1/*
2 * Copyright (C) 1997-2000 Matt Newman <matt@novadigm.com>
3 *
4 * $Header: /cvsroot/tls/tls/tlsBIO.c,v 1.8 2004/03/24 05:22:53 razzell Exp $
5 *
6 * Provides BIO layer to interface openssl to Tcl.
7 */
8
9#include "tlsInt.h"
10
11/*
12 * Forward declarations
13 */
14
15static int BioWrite	_ANSI_ARGS_ ((BIO *h, CONST char *buf, int num));
16static int BioRead	_ANSI_ARGS_ ((BIO *h, char *buf, int num));
17static int BioPuts	_ANSI_ARGS_ ((BIO *h, CONST char *str));
18static long BioCtrl	_ANSI_ARGS_ ((BIO *h, int cmd, long arg1, void *ptr));
19static int BioNew	_ANSI_ARGS_ ((BIO *h));
20static int BioFree	_ANSI_ARGS_ ((BIO *h));
21
22
23static BIO_METHOD BioMethods = {
24    BIO_TYPE_TCL, "tcl",
25    BioWrite,
26    BioRead,
27    BioPuts,
28    NULL,	/* BioGets */
29    BioCtrl,
30    BioNew,
31    BioFree,
32};
33
34BIO *
35BIO_new_tcl(statePtr, flags)
36    State *statePtr;
37    int flags;
38{
39    BIO *bio;
40
41    bio			= BIO_new(&BioMethods);
42    bio->ptr		= (char*)statePtr;
43    bio->init		= 1;
44    bio->shutdown	= flags;
45
46    return bio;
47}
48
49BIO_METHOD *
50BIO_s_tcl()
51{
52    return &BioMethods;
53}
54
55static int
56BioWrite (bio, buf, bufLen)
57    BIO *bio;
58    CONST char *buf;
59    int bufLen;
60{
61    Tcl_Channel chan = Tls_GetParent((State*)(bio->ptr));
62    int ret;
63
64    dprintf(stderr,"\nBioWrite(0x%x, <buf>, %d) [0x%x]",
65	    (unsigned int) bio, bufLen, (unsigned int) chan);
66
67    if (channelTypeVersion == TLS_CHANNEL_VERSION_2) {
68	ret = Tcl_WriteRaw(chan, buf, bufLen);
69    } else {
70	ret = Tcl_Write(chan, buf, bufLen);
71    }
72
73    dprintf(stderr,"\n[0x%x] BioWrite(%d) -> %d [%d.%d]",
74	    (unsigned int) chan, bufLen, ret, Tcl_Eof(chan), Tcl_GetErrno());
75
76    BIO_clear_flags(bio, BIO_FLAGS_WRITE|BIO_FLAGS_SHOULD_RETRY);
77
78    if (ret == 0) {
79	if (!Tcl_Eof(chan)) {
80	    BIO_set_retry_write(bio);
81	    ret = -1;
82	}
83    }
84    if (BIO_should_read(bio)) {
85	BIO_set_retry_read(bio);
86    }
87    return ret;
88}
89
90static int
91BioRead (bio, buf, bufLen)
92    BIO *bio;
93    char *buf;
94    int bufLen;
95{
96    Tcl_Channel chan = Tls_GetParent((State*)bio->ptr);
97    int ret = 0;
98
99    dprintf(stderr,"\nBioRead(0x%x, <buf>, %d) [0x%x]",
100	    (unsigned int) bio, bufLen, (unsigned int) chan);
101
102    if (buf == NULL) return 0;
103
104    if (channelTypeVersion == TLS_CHANNEL_VERSION_2) {
105	ret = Tcl_ReadRaw(chan, buf, bufLen);
106    } else {
107	ret = Tcl_Read(chan, buf, bufLen);
108    }
109
110    dprintf(stderr,"\n[0x%x] BioRead(%d) -> %d [%d.%d]",
111	    (unsigned int) chan, bufLen, ret, Tcl_Eof(chan), Tcl_GetErrno());
112
113    BIO_clear_flags(bio, BIO_FLAGS_READ|BIO_FLAGS_SHOULD_RETRY);
114
115    if (ret == 0) {
116	if (!Tcl_Eof(chan)) {
117	    BIO_set_retry_read(bio);
118	    ret = -1;
119	}
120    }
121    if (BIO_should_write(bio)) {
122	BIO_set_retry_write(bio);
123    }
124    return ret;
125}
126
127static int
128BioPuts	(bio, str)
129    BIO *bio;
130    CONST char *str;
131{
132    return BioWrite(bio, str, (int) strlen(str));
133}
134
135static long
136BioCtrl	(bio, cmd, num, ptr)
137    BIO *bio;
138    int cmd;
139    long num;
140    void *ptr;
141{
142    Tcl_Channel chan = Tls_GetParent((State*)bio->ptr);
143    long ret = 1;
144    int *ip;
145
146    dprintf(stderr,"\nBioCtrl(0x%x, 0x%x, 0x%x, 0x%x)",
147	    (unsigned int) bio, (unsigned int) cmd, (unsigned int) num,
148	    (unsigned int) ptr);
149
150    switch (cmd) {
151    case BIO_CTRL_RESET:
152	num = 0;
153    case BIO_C_FILE_SEEK:
154    case BIO_C_FILE_TELL:
155	ret = 0;
156	break;
157    case BIO_CTRL_INFO:
158	ret = 1;
159	break;
160    case BIO_C_SET_FD:
161	BioFree(bio);
162	/* Sets State* */
163	bio->ptr	= *((char **)ptr);
164	bio->shutdown	= (int)num;
165	bio->init	= 1;
166	break;
167    case BIO_C_GET_FD:
168	if (bio->init) {
169	    ip = (int *)ptr;
170	    if (ip != NULL) {
171		*ip = bio->num;
172	    }
173	    ret = bio->num;
174	} else {
175	    ret = -1;
176	}
177	break;
178    case BIO_CTRL_GET_CLOSE:
179	ret = bio->shutdown;
180	break;
181    case BIO_CTRL_SET_CLOSE:
182	bio->shutdown = (int)num;
183	break;
184    case BIO_CTRL_EOF:
185	dprintf(stderr, "BIO_CTRL_EOF\n");
186	ret = Tcl_Eof(chan);
187	break;
188    case BIO_CTRL_PENDING:
189	ret = (Tcl_InputBuffered(chan) ? 1 : 0);
190	dprintf(stderr, "BIO_CTRL_PENDING(%d)\n", (int) ret);
191	break;
192    case BIO_CTRL_WPENDING:
193	ret = 0;
194	break;
195    case BIO_CTRL_DUP:
196	break;
197    case BIO_CTRL_FLUSH:
198	dprintf(stderr, "BIO_CTRL_FLUSH\n");
199	if (channelTypeVersion == TLS_CHANNEL_VERSION_2) {
200	    ret = ((Tcl_WriteRaw(chan, "", 0) >= 0) ? 1 : -1);
201	} else {
202	    ret = ((Tcl_Flush(chan) == TCL_OK) ? 1 : -1);
203	}
204	break;
205    default:
206	ret = 0;
207	break;
208    }
209    return(ret);
210}
211
212static int
213BioNew	(bio)
214    BIO *bio;
215{
216    bio->init	= 0;
217    bio->num	= 0;
218    bio->ptr	= NULL;
219    bio->flags	= 0;
220
221    return 1;
222}
223
224static int
225BioFree	(bio)
226    BIO *bio;
227{
228    if (bio == NULL) {
229	return 0;
230    }
231
232    if (bio->shutdown) {
233	if (bio->init) {
234	    /*shutdown(bio->num, 2) */
235	    /*closesocket(bio->num) */
236	}
237	bio->init	= 0;
238	bio->flags	= 0;
239	bio->num	= 0;
240    }
241    return 1;
242}
243