bio_apr_socket.c

最終更新:2009/11/9

bio_apr_socket.c

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: }
Copyright (C) KAKU PROJECT (2009)KAKU PROJECT (2009)