bio_apr_socket.c
最終更新:2009/11/9
001: /* 002: * bio_apr_socket.c 003: * BIO API 用 apr_socket_t 版ソケット 004: * OpenSSL の入出力フレームワークの BIO で apr_socket_t を対応させる試み。 005: * ・read / write のみ使用可能 006: * ・バッファリングなし。従って、gets は効率が悪い。 007: * 008: * 入出力ストリームのフレームワークとして、OpenSSL の BIO と APR の 009: * Buckets Brigade と複数の方式があって悩ましい。 010: * 現時点では、OpenSSL の SSL API を使いたいので、BIO ということになるのだが、 011: * 慣れてきたので APR Buckets Brigade で統一したいところだ。 012: * 013: * それにしても、C 言語を使ったストリームの抽象化ってわかりにくい。 014: * こういうのはオブジェクト指向言語の方が向いてる。 015: * Java の java.io.*Stream は実に使いやすかった。 016: * 017: */ 018: 019: #ifndef APR_NETWORK_IO_H 020: #include "apr_network_io.h" 021: #endif 022: #ifndef HEADER_BIO_H 023: #include "openssl/bio.h" 024: #endif 025: #include "bio_apr_socket.h" 026: 027: typedef struct bio_apr_socket_ctx_st { 028: apr_socket_t *sock; 029: int seen_eof; 030: } bio_apr_socket_ctx; 031: 032: int bio_apr_socket_create( 033: BIO *bio 034: ) { 035: bio->shutdown = 1; 036: bio->init = 1; 037: bio->num = -1; 038: bio->ptr = NULL; 039: 040: return 1; 041: } 042: 043: int bio_apr_socket_destroy( 044: BIO *bio 045: ) { 046: if (!bio) { 047: return 0; 048: } 049: return 1; 050: } 051: 052: int bio_apr_socket_write( 053: BIO *bio 054: , const char *out_buf 055: , int out_len 056: ) { 057: apr_status_t rv=APR_SUCCESS; 058: bio_apr_socket_ctx *ctx= (bio_apr_socket_ctx*)(bio->ptr); 059: apr_socket_t *sock = ctx->sock; 060: apr_size_t len = out_len; 061: 062: if (!sock || !out_buf || out_len <= 0) { 063: return -1; 064: } 065: 066: rv = apr_socket_send(sock, out_buf, &len); 067: if (rv != APR_SUCCESS) { 068: ctx->seen_eof = 1; 069: return -1; 070: } 071: 072: return len; 073: } 074: 075: int bio_apr_socket_read ( 076: BIO *bio 077: , char *in_buf 078: , int in_len 079: ) { 080: apr_status_t rv=APR_SUCCESS; 081: bio_apr_socket_ctx *ctx= (bio_apr_socket_ctx*)(bio->ptr); 082: apr_socket_t *sock = ctx->sock; 083: apr_size_t len = in_len; 084: 085: if (!sock || !in_buf || in_len <= 0) { 086: return -1; 087: } 088: 089: rv = apr_socket_recv(sock, in_buf, &len); 090: if (rv != APR_SUCCESS) { 091: ctx->seen_eof = 1; 092: return -1; 093: } 094: 095: return len; 096: } 097: 098: /* LF で終わる文字列を取得する。 099: * ・CRLF もしくは LF で終わる場合はヌル文字で終わる文字列を buf に保存。 100: * ・size-2 の長さ以内で CRLF もしくは LF を見つけられなかった場合は 101: * バッファの size-1 はヌル文字にする。エラーにすべきかもしれない。 102: * 103: * ・内部のバッファを実装するのが面倒なので、何度も1バイト単位で BIO_read を 104: * 呼ぶ。…従って効率が悪い。 105: */ 106: 107: int bio_apr_socket_gets( 108: BIO *bio 109: , char *buf 110: , int size 111: ) { 112: int len = 0; 113: 114: if (!buf || size<3) { 115: return -1; 116: } 117: 118: while (len < size-2) { 119: char b[1]; 120: int nbytes = BIO_read(bio, b, 1); 121: if (nbytes < 1 ) { 122: return -1; 123: } 124: if (b[0] == '\n') { 125: buf[len] = '\0'; 126: if (len>0 && buf[len-1] == '\r') { /* CRLF の時 */ 127: buf[len-1] = '\0'; 128: len--; 129: } 130: break; 131: } else { 132: buf[len] = b[0]; 133: } 134: len++; 135: } 136: 137: /* 与えられたバッファサイズを過ぎても CRLF または LF を見つけられなかった時 138: * とりあえずこの実装では最後にヌル文字を入れている。 139: * エラーとすべきかもしれない。 140: */ 141: if (len == size-2) { 142: buf[size-1] = '\0'; 143: } 144: 145: /* 146: if (len == 0) { 147: return -1; 148: } 149: */ 150: 151: return len; 152: } 153: 154: int bio_apr_socket_puts( 155: BIO *bio 156: , const char *str 157: ) { 158: apr_status_t rv=APR_SUCCESS; 159: bio_apr_socket_ctx *ctx= (bio_apr_socket_ctx*)(bio->ptr); 160: apr_socket_t *sock = ctx->sock; 161: apr_size_t len = 0; 162: 163: if (!sock || !str) { 164: return -1; 165: } 166: 167: len = strlen(str); 168: rv = apr_socket_send(sock, str, &len); 169: if (rv != APR_SUCCESS) { 170: ctx->seen_eof = 1; 171: return -1; 172: } 173: 174: return len; 175: } 176: 177: /* この関数は自信がない…。 178: * 179: */ 180: long bio_apr_socket_ctrl( 181: BIO *bio 182: , int cmd 183: , long num 184: , void *ptr 185: ) { 186: long ret = 1; 187: 188: bio_apr_socket_ctx *ctx= (bio_apr_socket_ctx*)(bio->ptr); 189: 190: switch (cmd) { 191: case BIO_CTRL_RESET:/* opt - rewind/zero etc */ 192: ; 193: break; 194: case BIO_CTRL_EOF:/* opt - are we at the eof */ 195: if(ctx->seen_eof) { 196: ret = 1L; 197: } else { 198: ret = 0L; 199: } 200: break; 201: case BIO_C_SET_BUF_MEM_EOF_RETURN:/*return end of input value*/ 202: ret = 1L; 203: break; 204: case BIO_CTRL_INFO:/* opt - extra tit-bits */ 205: ret = 0L; 206: break; 207: case BIO_CTRL_GET_CLOSE:/* man - set the 'close' on free */ 208: ret = (long)bio->shutdown; 209: break; 210: case BIO_CTRL_SET_CLOSE:/* man - set the 'close' on free */ 211: bio->shutdown = (int)num; 212: break; 213: case BIO_CTRL_WPENDING: /* opt - number of bytes still to write */ 214: ret = 0L; 215: break; 216: case BIO_CTRL_PENDING:/* opt - is their more data buffered */ 217: ret = 0L; 218: break; 219: case BIO_CTRL_FLUSH:/* opt - 'flush' buffered output */ 220: ret = 1L; 221: break; 222: case BIO_CTRL_DUP:/* man - extra stuff for 'duped' BIO */ 223: ret = 1L; 224: break; 225: /* N/A */ 226: case BIO_C_SET_BUF_MEM: 227: case BIO_C_GET_BUF_MEM_PTR: 228: /* we don't care */ 229: case BIO_CTRL_PUSH: 230: case BIO_CTRL_POP: 231: default: 232: ret = 0; 233: break; 234: } 235: 236: return ret; 237: } 238: 239: BIO_METHOD bio_apr_socket_method = { 240: BIO_TYPE_MEM, 241: "APR Socket", 242: bio_apr_socket_write, 243: bio_apr_socket_read, 244: bio_apr_socket_puts, /* puts will be not called */ 245: bio_apr_socket_gets, /* gets will be not called */ 246: bio_apr_socket_ctrl, 247: bio_apr_socket_create, 248: bio_apr_socket_destroy, 249: #ifdef OPENSSL_VERSION_NUMBER 250: NULL /* sslc does not have the callback_ctrl field */ 251: #endif 252: }; 253: 254: /* 255: * ソケット接続関数 256: */ 257: static apr_socket_t *my_connect ( 258: char *hostname 259: , int port 260: , apr_pool_t * pool 261: ) { 262: 263: apr_socket_t *s = NULL; 264: 265: if (! pool || ! hostname || port<=0) { 266: 267: return NULL; 268: 269: } else { 270: 271: apr_status_t rv = APR_SUCCESS; 272: apr_sockaddr_t *sa=NULL; 273: 274: rv = apr_sockaddr_info_get(&sa, hostname, APR_UNSPEC, port, 0, pool); 275: if (APR_SUCCESS != rv) { 276: return NULL; 277: } 278: 279: for (; sa!=NULL; sa=sa->next) 280: { 281: rv = apr_socket_create(&s, sa->family, 282: SOCK_STREAM, APR_PROTO_TCP, pool); 283: if (APR_SUCCESS != rv) { 284: continue; 285: } 286: 287: rv = apr_socket_connect(s, sa); 288: if (APR_SUCCESS == rv) { 289: break; 290: } 291: } 292: 293: if (!sa) { 294: return NULL; 295: } 296: } 297: 298: return s; 299: } 300: 301: /* 302: * オープン済みのソケットを使って BIO オブジェクトを生成する関数 303: * 返り値: 304: * 成功時:ソケットを保持した BIO オブジェクト 305: * 失敗時:ヌル 306: */ 307: 308: BIO *bio_apr_socket_new ( 309: apr_socket_t *sock /* BIO オブジェクトに保持させるソケット */ 310: , apr_pool_t *pool 311: ) { 312: BIO *bio = NULL; 313: if (!sock) { 314: return NULL; 315: } 316: 317: if(sock) { 318: bio_apr_socket_ctx *ctx = 319: (bio_apr_socket_ctx*)apr_palloc(pool, 320: sizeof(bio_apr_socket_ctx)); 321: memset(ctx, 0, sizeof(bio_apr_socket_ctx)); 322: ctx->sock = sock; 323: ctx->seen_eof = 0; 324: bio = BIO_new(&bio_apr_socket_method); 325: bio->ptr = ctx; 326: } 327: return bio; 328: } 329: 330: /* 331: * ソケット接続し、BIO オブジェクトを生成する関数 332: * 返り値: 333: * 成功時:ソケットを保持した BIO オブジェクト 334: * 失敗時:ヌル 335: * メモ: 336: * ソケットオプションはデフォルト設定。 337: */ 338: 339: BIO *bio_apr_socket_connect( 340: char *hostname /* 接続先ホスト名 */ 341: , int port /* 接続先ポート番号 */ 342: , apr_pool_t * pool 343: ) { 344: apr_socket_t *sock = my_connect (hostname, port, pool); 345: if (!sock) { 346: return NULL; 347: } 348: 349: return bio_apr_socket_new(sock, pool); 350: }
KAKU PROJECT (2009) |