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