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) |