OSDN Git Service

git-svn-id: http://svn.osdn.jp/svnroot/mimic/trunk@18 47198e57-cb75-475f-84c4-a814cd6...
[mimic/MiMicSDK.git] / lib / src / http / NyLPC_cHttpStream.c
1 /*********************************************************************************\r
2  * PROJECT: MiMic\r
3  * --------------------------------------------------------------------------------\r
4  *\r
5  * This file is part of MiMic\r
6  * Copyright (C)2011 Ryo Iizuka\r
7  *\r
8  * MiMic is free software: you can redistribute it and/or modify\r
9  * it under the terms of the GNU Lesser General Public License as published\r
10  * by the Free Software Foundation, either version 3 of the License, or\r
11  * (at your option) any later version.\r
12  *\r
13  * This program is distributed in the hope that it will be useful,\r
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
16  * GNU General Public License for more details.\r
17  *\r
18  * You should have received a copy of the GNU Lesser General Public License\r
19  * along with this program.  If not, see <http://www.gnu.org/licenses/>.\r
20  *\r
21  * For further information please contact.\r
22  *      http://nyatla.jp/\r
23  *      <airmail(at)ebony.plala.or.jp> or <nyatla(at)nyatla.jp>\r
24  *\r
25  *********************************************************************************/\r
26 #include "NyLPC_cHttpStream.h"\r
27 \r
28 \r
29 \r
30 #if NyLPC_CONFIG_cHttpStream_DEBUG == 1\r
31 #include <stdio.h>\r
32 char _wbuf[1024];\r
33 const char* _rbuf;\r
34 int _rbuf_len;\r
35 void NyLPC_cTcpSocket_initialized(void* inst,const char* rb,int l)\r
36 {\r
37         _rbuf=rb;\r
38         _rbuf_len=l;\r
39 \r
40 }\r
41 void* NyLPC_cTcpSocket_allocSendBuf(void* inst,NyLPC_TUInt16 i_hint,NyLPC_TUInt16* o_len,NyLPC_TUInt32 i_to)\r
42 {\r
43         *o_len=30;\r
44         return _wbuf;\r
45 }\r
46 NyLPC_TBool NyLPC_cTcpSocket_psend(void* inst,void* i_buf,NyLPC_TUInt16 i_len,NyLPC_TUInt32 i_to)\r
47 {\r
48         printf("%.*s",i_len,i_buf);\r
49         return NyLPC_TBool_TRUE;\r
50 }\r
51 NyLPC_TInt32 NyLPC_cTcpSocket_precv(void* i_inst,const void** o_buf_ptr,NyLPC_TUInt32 i_wait_msec)\r
52 {\r
53         int l=_rbuf_len>100?100:_rbuf_len;\r
54         *o_buf_ptr=_rbuf;\r
55         return l;\r
56 }\r
57 void NyLPC_cTcpSocket_pseek(void* i_inst,NyLPC_TUInt16 i_seek)\r
58 {\r
59         _rbuf+=i_seek;\r
60         _rbuf_len-=i_seek;\r
61 }\r
62 \r
63 void* NyLPC_cTcpSocket_releaseSendBuf(NyLPC_TcTcpSocket_t* i_inst,void* i_buf_ptr)\r
64 {\r
65         return NULL;\r
66 }\r
67 #endif\r
68 \r
69 \r
70 static NyLPC_TInt32 pread_func(void* i_inst,const void** o_buf_ptr);\r
71 static NyLPC_TBool write_func(void* i_inst,const void* i_data,NyLPC_TInt32 i_length);\r
72 static void pseek_func(void* i_inst,NyLPC_TUInt16 i_seek);\r
73 static NyLPC_TBool flush_func(void* i_inst);\r
74 static void setReadEncoding_func(void* i_inst,NyLPC_TiHttpPtrStream_ET i_et);\r
75 static void setWriteEncoding_func(void* i_inst,NyLPC_TiHttpPtrStream_ET i_et);\r
76 \r
77 /**\r
78  * HTTP送受信のタイムアウト値\r
79  */\r
80 #define HTTP_TIMEOUT 10*1000\r
81 /**\r
82  * HTTP送信バッファのヒント値\r
83  */\r
84 #define HTTP_TX_BUF_HINT 1024\r
85 \r
86 //関数テーブル\r
87 const static struct NyLPC_TiHttpPtrStream_TInterface _interface=\r
88 {\r
89                 pread_func,\r
90                 write_func,\r
91                 pseek_func,\r
92                 flush_func,\r
93                 setReadEncoding_func,\r
94                 setWriteEncoding_func\r
95 };\r
96 \r
97 /**\r
98  * i_bufに5バイトのchunkedヘッダを書きます。\r
99  */\r
100 static void put_chunked_header(NyLPC_TUInt16 i_val,NyLPC_TUInt8* o_buf)\r
101 {\r
102         const static char* D="0123456789ABCDEF";\r
103         *(o_buf+0)=D[((i_val&0x0f00)>>8)];\r
104         *(o_buf+1)=D[((i_val&0x00f0)>>4)];\r
105         *(o_buf+2)=D[ (i_val&0x000f)];\r
106         *(o_buf+3)='\r';\r
107         *(o_buf+4)='\n';\r
108 }\r
109 /**\r
110  * 接続済のソケットをストリームに抽象化します。\r
111  */\r
112 NyLPC_TBool NyLPC_cHttpStream_initialize(NyLPC_TcHttpStream_t* i_inst,NyLPC_TcTcpSocket_t* i_ref_sock)\r
113 {\r
114         i_inst->_interface_httpptrstream=&_interface;\r
115         i_inst->_ref_sock=i_ref_sock;\r
116         i_inst->we_type=NyLPC_TiHttpPtrStream_ET_NONE;\r
117         i_inst->re_type=NyLPC_TiHttpPtrStream_ET_NONE;\r
118         i_inst->txb=NULL;\r
119         return NyLPC_TBool_TRUE;\r
120 }\r
121 \r
122 void NyLPC_cHttpStream_finalize(NyLPC_TcHttpStream_t* i_inst)\r
123 {\r
124         if(i_inst->txb!=NULL){\r
125                 NyLPC_cTcpSocket_releaseSendBuf(i_inst->_ref_sock,i_inst->txb);\r
126         }\r
127 }\r
128 \r
129 //\r
130 //      インタフェイス\r
131 //\r
132 \r
133 static NyLPC_TInt32 pread_func(void* i_inst,const void** o_buf_ptr)\r
134 {\r
135         NyLPC_TcHttpStream_t* inst=(NyLPC_TcHttpStream_t*)i_inst;\r
136         return NyLPC_cTcpSocket_precv(inst->_ref_sock,o_buf_ptr,HTTP_TIMEOUT);\r
137 }\r
138 \r
139 static NyLPC_TBool write_func(void* i_inst,const void* i_data,NyLPC_TInt32 i_length)\r
140 {\r
141         NyLPC_TcHttpStream_t* inst=(NyLPC_TcHttpStream_t*)i_inst;\r
142         NyLPC_TUInt16 s,free_size;\r
143         NyLPC_TUInt32 l;\r
144         const char* src=i_data;\r
145         l=(NyLPC_TUInt16)(i_length<0?strlen(src):i_length);\r
146         if(l>=NyLPC_TUInt16_MAX){\r
147                 return NyLPC_TBool_FALSE;\r
148         }\r
149         while(l>0){\r
150                 //送信バッファがNULLなら、割り当て。\r
151                 if(inst->txb==NULL){\r
152                         inst->txb=NyLPC_cTcpSocket_allocSendBuf(inst->_ref_sock,HTTP_TX_BUF_HINT,&s,HTTP_TIMEOUT);\r
153                         if(inst->txb==NULL){\r
154                                 return NyLPC_TBool_FALSE;\r
155                         }\r
156                         //chunked encodingなら、先頭5バイト+末尾2バイトを予約する. 000\r
157                         if(inst->we_type==NyLPC_TiHttpPtrStream_ET_CHUNKED){\r
158                                 inst->tx_len=5;\r
159                                 inst->txb_size=s-7;\r
160                         }else{\r
161                                 inst->tx_len=0;\r
162                                 inst->txb_size=s;\r
163                         }\r
164                 }\r
165                 //書き込み可能サイズの計算\r
166                 free_size=inst->txb_size-inst->tx_len;\r
167                 if(free_size>l){\r
168                         //書き込み可能サイズがi_length未満なら、バッファに貯めるだけ。\r
169                         memcpy(inst->txb+inst->tx_len,src,l);\r
170                         inst->tx_len+=(NyLPC_TUInt16)l;\r
171                         break;\r
172                 }\r
173                 //バッファフルになるなら、送信する。\r
174                 memcpy(inst->txb+inst->tx_len,src,free_size);\r
175                 inst->tx_len+=free_size;\r
176                 //書き込み\r
177                 flush_func(i_inst);\r
178                 //読み出し位置の調整\r
179                 l-=free_size;\r
180                 src+=free_size;\r
181         };\r
182         return NyLPC_TBool_TRUE;\r
183 }\r
184 \r
185 \r
186 static void pseek_func(void* i_inst,NyLPC_TUInt16 i_seek)\r
187 {\r
188         NyLPC_TcHttpStream_t* inst=(NyLPC_TcHttpStream_t*)i_inst;\r
189 \r
190         NyLPC_cTcpSocket_pseek(inst->_ref_sock,i_seek);\r
191 }\r
192 \r
193 /**\r
194  * キャッシュに保持してるデータを出力する。\r
195  */\r
196 static NyLPC_TBool flush_func(void* i_inst)\r
197 {\r
198         NyLPC_TcHttpStream_t* inst=(NyLPC_TcHttpStream_t*)i_inst;\r
199         if(inst->txb==NULL){\r
200                 return NyLPC_TBool_TRUE;\r
201         }\r
202         //chunkedの場合は、header/footerをセットする。\r
203         if(inst->we_type==NyLPC_TiHttpPtrStream_ET_CHUNKED){\r
204                 //5バイト分のヘッダを記述。\r
205                 put_chunked_header(inst->tx_len-5,inst->txb);\r
206                 *(inst->txb+inst->tx_len)=0x0d;\r
207                 *(inst->txb+inst->tx_len+1)=0x0a;\r
208                 inst->tx_len+=2;\r
209         }\r
210         //送信する。\r
211         if(!NyLPC_cTcpSocket_psend(inst->_ref_sock,inst->txb,inst->tx_len,HTTP_TIMEOUT)){\r
212                 //失敗。\r
213                 NyLPC_cTcpSocket_releaseSendBuf(inst->_ref_sock,inst->txb);\r
214                 inst->txb=NULL;\r
215                 return NyLPC_TBool_FALSE;\r
216         }\r
217         //キャッシュを開放\r
218         inst->txb=NULL;\r
219         return NyLPC_TBool_TRUE;\r
220 }\r
221 static void setReadEncoding_func(void* i_inst,NyLPC_TiHttpPtrStream_ET i_et)\r
222 {\r
223         //未実装。\r
224         NyLPC_Abort();\r
225         return;\r
226 }\r
227 static void setWriteEncoding_func(void* i_inst,NyLPC_TiHttpPtrStream_ET i_et)\r
228 {\r
229         NyLPC_TcHttpStream_t* inst=(NyLPC_TcHttpStream_t*)i_inst;\r
230         if(inst->we_type==i_et)\r
231         {\r
232                 return;\r
233         }\r
234         //バッファがあるならフラッシュしてしまう。\r
235         if(inst->txb!=NULL){\r
236                 if(!flush_func(i_inst)){\r
237                         return;\r
238                 }\r
239         }\r
240         //モードの切り替え。\r
241         inst->we_type=i_et;\r
242 }\r