OSDN Git Service

update libMiMic
[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_iTcpSocket_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_iIpTcpSocket_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_iTcpSocket_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_iTcpSocket_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_iTcpSocket_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_iTcpSocket_releaseSendBuf(NyLPC_TiTcpSocket_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,NyLPC_TUInt32 i_timeout);\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 /**\r
79  * HTTP送信バッファのヒント値\r
80  */\r
81 #define HTTP_TX_BUF_HINT 1024\r
82 \r
83 //関数テーブル\r
84 const static struct NyLPC_TiHttpPtrStream_TInterface _interface=\r
85 {\r
86         pread_func,\r
87         write_func,\r
88         pseek_func,\r
89         flush_func,\r
90         setReadEncoding_func,\r
91         setWriteEncoding_func\r
92 };\r
93 \r
94 /**\r
95  * i_bufに5バイトのchunkedヘッダを書きます。\r
96  */\r
97 static void put_chunked_header(NyLPC_TUInt16 i_val,NyLPC_TUInt8* o_buf)\r
98 {\r
99     const static char* D="0123456789ABCDEF";\r
100     *(o_buf+0)=D[((i_val&0x0f00)>>8)];\r
101     *(o_buf+1)=D[((i_val&0x00f0)>>4)];\r
102     *(o_buf+2)=D[ (i_val&0x000f)];\r
103     *(o_buf+3)='\r';\r
104     *(o_buf+4)='\n';\r
105 }\r
106 /**\r
107  * 接続済のソケットをストリームに抽象化します。\r
108  */\r
109 NyLPC_TBool NyLPC_cHttpStream_initialize(NyLPC_TcHttpStream_t* i_inst,NyLPC_TiTcpSocket_t* i_ref_sock)\r
110 {\r
111     i_inst->super.absfunc=&_interface;\r
112     i_inst->_ref_sock=i_ref_sock;\r
113     i_inst->we_type=NyLPC_TiHttpPtrStream_ET_NONE;\r
114     i_inst->re_type=NyLPC_TiHttpPtrStream_ET_NONE;\r
115     i_inst->txb=NULL;\r
116     return NyLPC_TBool_TRUE;\r
117 }\r
118 \r
119 void NyLPC_cHttpStream_finalize(NyLPC_TcHttpStream_t* i_inst)\r
120 {\r
121     if(i_inst->txb!=NULL){\r
122         NyLPC_iTcpSocket_releaseSendBuf(i_inst->_ref_sock,i_inst->txb);\r
123     }\r
124 }\r
125 \r
126 //\r
127 //  インタフェイス\r
128 //\r
129 \r
130 static NyLPC_TInt32 pread_func(void* i_inst,const void** o_buf_ptr,NyLPC_TUInt32 i_timeout)\r
131 {\r
132     NyLPC_TcHttpStream_t* inst=(NyLPC_TcHttpStream_t*)i_inst;\r
133     return NyLPC_iTcpSocket_precv(inst->_ref_sock,o_buf_ptr,i_timeout);\r
134 }\r
135 \r
136 static NyLPC_TBool write_func(void* i_inst,const void* i_data,NyLPC_TInt32 i_length)\r
137 {\r
138     NyLPC_TcHttpStream_t* inst=(NyLPC_TcHttpStream_t*)i_inst;\r
139     NyLPC_TUInt16 s,free_size;\r
140     NyLPC_TUInt32 l;\r
141     const char* src=(const char*)i_data;\r
142     l=((i_length<0)?strlen(src):i_length);\r
143     while(l>0){\r
144         //送信バッファがNULLなら、割り当て。\r
145         if(inst->txb==NULL){\r
146             inst->txb=(NyLPC_TUInt8*)NyLPC_iTcpSocket_allocSendBuf(inst->_ref_sock,HTTP_TX_BUF_HINT,&s,NyLPC_TiHttpPtrStream_DEFAULT_HTTP_TIMEOUT);\r
147             if(inst->txb==NULL){\r
148                 return NyLPC_TBool_FALSE;\r
149             }\r
150             //chunked encodingなら、先頭5バイト+末尾2バイトを予約する. 000\r
151             if(inst->we_type==NyLPC_TiHttpPtrStream_ET_CHUNKED){\r
152                 inst->tx_len=5;\r
153                 inst->txb_size=s-7;\r
154             }else{\r
155                 inst->tx_len=0;\r
156                 inst->txb_size=s;\r
157             }\r
158         }\r
159         //書き込み可能サイズの計算\r
160         free_size=inst->txb_size-inst->tx_len;\r
161         if((NyLPC_TInt32)free_size>l){\r
162             //書き込み可能サイズがi_length未満なら、バッファに貯めるだけ。\r
163             memcpy(inst->txb+inst->tx_len,src,l);\r
164             inst->tx_len+=(NyLPC_TUInt16)l;\r
165             break;\r
166         }\r
167         //バッファフルになるなら、送信する。\r
168         memcpy(inst->txb+inst->tx_len,src,free_size);\r
169         inst->tx_len+=free_size;\r
170         //書き込み\r
171         if(!flush_func(i_inst)){\r
172             //書込みエラー・・・\r
173             return NyLPC_TBool_FALSE;\r
174         }\r
175         //読み出し位置の調整\r
176         l-=free_size;\r
177         src+=free_size;\r
178     };\r
179     return NyLPC_TBool_TRUE;\r
180 }\r
181 \r
182 \r
183 static void pseek_func(void* i_inst,NyLPC_TUInt16 i_seek)\r
184 {\r
185     NyLPC_TcHttpStream_t* inst=(NyLPC_TcHttpStream_t*)i_inst;\r
186 \r
187     NyLPC_iTcpSocket_pseek(inst->_ref_sock,i_seek);\r
188 }\r
189 \r
190 /**\r
191  * キャッシュに保持してるデータを出力する。\r
192  */\r
193 static NyLPC_TBool flush_func(void* i_inst)\r
194 {\r
195     NyLPC_TcHttpStream_t* inst=(NyLPC_TcHttpStream_t*)i_inst;\r
196     if(inst->txb==NULL){\r
197         return NyLPC_TBool_TRUE;\r
198     }\r
199     //chunkedの場合は、header/footerをセットする。\r
200     if(inst->we_type==NyLPC_TiHttpPtrStream_ET_CHUNKED){\r
201         //5バイト分のヘッダを記述。\r
202         put_chunked_header(inst->tx_len-5,inst->txb);\r
203         *(inst->txb+inst->tx_len)=0x0d;\r
204         *(inst->txb+inst->tx_len+1)=0x0a;\r
205         inst->tx_len+=2;\r
206     }\r
207     //送信する。\r
208     if(!NyLPC_iTcpSocket_psend(inst->_ref_sock,inst->txb,inst->tx_len,NyLPC_TiHttpPtrStream_DEFAULT_HTTP_TIMEOUT)){\r
209         //失敗。\r
210         NyLPC_iTcpSocket_releaseSendBuf(inst->_ref_sock,inst->txb);\r
211         inst->txb=NULL;\r
212         return NyLPC_TBool_FALSE;\r
213     }\r
214     //キャッシュを開放\r
215     inst->txb=NULL;\r
216     return NyLPC_TBool_TRUE;\r
217 }\r
218 static void setReadEncoding_func(void* i_inst,NyLPC_TiHttpPtrStream_ET i_et)\r
219 {\r
220     //未実装。(この関数は不要?)\r
221     NyLPC_Abort();\r
222     return;\r
223 }\r
224 static void setWriteEncoding_func(void* i_inst,NyLPC_TiHttpPtrStream_ET i_et)\r
225 {\r
226     NyLPC_TcHttpStream_t* inst=(NyLPC_TcHttpStream_t*)i_inst;\r
227     if(inst->we_type==i_et)\r
228     {\r
229         return;\r
230     }\r
231     //バッファがあるならフラッシュしてしまう。\r
232     if(inst->txb!=NULL){\r
233         if(!flush_func(i_inst)){\r
234             return;\r
235         }\r
236     }\r
237     //モードの切り替え。\r
238     inst->we_type=i_et;\r
239 }\r