get error from getnameinfo if unable to improve hostname and use hostname
[profile/ivi/libwebsockets.git] / lib / extension-deflate-frame.c
1 #include "private-libwebsockets.h"
2 #include "extension-deflate-frame.h"
3 #include <stdio.h>
4 #include <string.h>
5 #include <assert.h>
6
7 #define LWS_ZLIB_WINDOW_BITS 15
8 #define LWS_ZLIB_MEMLEVEL 8
9
10 #define MIN_SIZE_TO_DEFLATE 4
11
12 int lws_extension_callback_deflate_frame(
13                 struct libwebsocket_context *context,
14                 struct libwebsocket_extension *ext,
15                 struct libwebsocket *wsi,
16                 enum libwebsocket_extension_callback_reasons reason,
17                 void *user, void *in, size_t len)
18 {
19         struct lws_ext_deflate_frame_conn *conn =
20                                      (struct lws_ext_deflate_frame_conn *)user;
21         struct lws_tokens *eff_buf = (struct lws_tokens *)in;
22         size_t current_payload, remaining_payload, total_payload;
23         int n;
24         size_t len_so_far;
25
26         switch (reason) {
27
28         /*
29          * for deflate-frame, both client and server sides act the same
30          */
31
32         case LWS_EXT_CALLBACK_CLIENT_CONSTRUCT:
33         case LWS_EXT_CALLBACK_CONSTRUCT:
34                 conn->zs_in.zalloc = conn->zs_out.zalloc = Z_NULL;
35                 conn->zs_in.zfree = conn->zs_out.zfree = Z_NULL;
36                 conn->zs_in.opaque = conn->zs_out.opaque = Z_NULL;
37                 n = inflateInit2(&conn->zs_in, -LWS_ZLIB_WINDOW_BITS);
38                 if (n != Z_OK) {
39                         lwsl_ext("deflateInit returned %d\n", n);
40                         return 1;
41                 }
42                 n = deflateInit2(&conn->zs_out,
43                                  (context->listen_port ?
44                                         DEFLATE_FRAME_COMPRESSION_LEVEL_SERVER :
45                                         DEFLATE_FRAME_COMPRESSION_LEVEL_CLIENT),
46                                  Z_DEFLATED,
47                                  -LWS_ZLIB_WINDOW_BITS, LWS_ZLIB_MEMLEVEL,
48                                  Z_DEFAULT_STRATEGY);
49                 if (n != Z_OK) {
50                         lwsl_ext("deflateInit2 returned %d\n", n);
51                         return 1;
52                 }
53                 conn->buf_pre_used = 0;
54                 conn->buf_pre_length = 0;
55                 conn->buf_in_length = MAX_USER_RX_BUFFER;
56                 conn->buf_out_length = MAX_USER_RX_BUFFER;
57                 conn->compressed_out = 0;
58                 conn->buf_pre = NULL;
59                 conn->buf_in = (unsigned char *)
60                                 malloc(LWS_SEND_BUFFER_PRE_PADDING +
61                                                conn->buf_in_length +
62                                                LWS_SEND_BUFFER_POST_PADDING);
63                 if (!conn->buf_in)
64                         goto bail;
65                 conn->buf_out = (unsigned char *)
66                                 malloc(LWS_SEND_BUFFER_PRE_PADDING +
67                                                 conn->buf_out_length +
68                                                 LWS_SEND_BUFFER_POST_PADDING);
69                 if (!conn->buf_out)
70                         goto bail;
71                 lwsl_ext("zlibs constructed\n");
72                 break;
73 bail:
74                 lwsl_err("Out of mem\n");
75                 (void)inflateEnd(&conn->zs_in);
76                 (void)deflateEnd(&conn->zs_out);
77                 return -1;
78
79         case LWS_EXT_CALLBACK_DESTROY:
80                 if (conn->buf_pre)
81                         free(conn->buf_pre);
82                 free(conn->buf_in);
83                 free(conn->buf_out);
84                 conn->buf_pre_used = 0;
85                 conn->buf_pre_length = 0;
86                 conn->buf_in_length = 0;
87                 conn->buf_out_length = 0;
88                 conn->compressed_out = 0;
89                 (void)inflateEnd(&conn->zs_in);
90                 (void)deflateEnd(&conn->zs_out);
91                 lwsl_ext("zlibs destructed\n");
92                 break;
93
94         case LWS_EXT_CALLBACK_PAYLOAD_RX:
95                 if (!(wsi->u.ws.rsv & 0x40))
96                         return 0;
97
98                 /*
99                  * inflate the incoming payload
100                  */
101                 current_payload = eff_buf->token_len;
102
103                 remaining_payload = wsi->u.ws.rx_packet_length;
104                 if (remaining_payload) {
105                         total_payload = conn->buf_pre_used +
106                                         current_payload +
107                                         remaining_payload;
108
109                         if (conn->buf_pre_length < total_payload) {
110                                 conn->buf_pre_length = total_payload;
111                                 if (conn->buf_pre)
112                                         free(conn->buf_pre);
113                                 conn->buf_pre =
114                                     (unsigned char *)malloc(total_payload + 4);
115                                 if (!conn->buf_pre) {
116                                         lwsl_err("Out of memory\n");
117                                         return -1;
118                                 }
119                         }
120
121                         memcpy(conn->buf_pre + conn->buf_pre_used,
122                                               eff_buf->token, current_payload);
123                         conn->buf_pre_used += current_payload;
124
125                         eff_buf->token = NULL;
126                         eff_buf->token_len = 0;
127
128                         return 0;
129                 }
130                 if (conn->buf_pre_used) {
131                         total_payload = conn->buf_pre_used +
132                                         current_payload;
133
134                         memcpy(conn->buf_pre + conn->buf_pre_used,
135                                               eff_buf->token, current_payload);
136                         conn->buf_pre_used = 0;
137
138                         conn->zs_in.next_in = conn->buf_pre;
139                 } else {
140                         total_payload = current_payload;
141
142                         conn->zs_in.next_in = (unsigned char *)eff_buf->token;
143                 }
144
145                 conn->zs_in.next_in[total_payload + 0] = 0;
146                 conn->zs_in.next_in[total_payload + 1] = 0;
147                 conn->zs_in.next_in[total_payload + 2] = 0xff;
148                 conn->zs_in.next_in[total_payload + 3] = 0xff;
149
150                 conn->zs_in.avail_in = total_payload + 4;
151
152                conn->zs_in.next_out = conn->buf_in + LWS_SEND_BUFFER_PRE_PADDING;
153                conn->zs_in.avail_out = conn->buf_in_length;
154
155                while (1) {
156                        n = inflate(&conn->zs_in, Z_SYNC_FLUSH);
157                        switch (n) {
158                        case Z_NEED_DICT:
159                        case Z_STREAM_ERROR:
160                        case Z_DATA_ERROR:
161                        case Z_MEM_ERROR:
162                                 /*
163                                  * screwed.. close the connection... we will get a
164                                  * destroy callback to take care of closing nicely
165                                  */
166                                 lwsl_err("zlib error inflate %d: %s\n",
167                                                            n, conn->zs_in.msg);
168                                 return -1;
169                         }
170
171                         if (conn->zs_in.avail_out)
172                                 break;
173
174                         len_so_far = conn->zs_in.next_out -
175                                 (conn->buf_in + LWS_SEND_BUFFER_PRE_PADDING);
176
177                         conn->buf_in_length *= 2;
178                         if (conn->buf_in_length > LWS_MAX_ZLIB_CONN_BUFFER) {
179                                 lwsl_ext("zlib in buffer tried to exceed "
180                                         "max allowed of %u\n",
181                                                 LWS_MAX_ZLIB_CONN_BUFFER);
182                                 return -1;
183                         }
184                         conn->buf_in = (unsigned char *)realloc(conn->buf_in,
185                                         LWS_SEND_BUFFER_PRE_PADDING +
186                                                 conn->buf_in_length +
187                                                  LWS_SEND_BUFFER_POST_PADDING);
188                         if (!conn->buf_in) {
189                                 lwsl_err("Out of memory\n");
190                                 return -1;
191                         }
192                         lwsl_debug(
193                                 "deflate-frame ext RX did realloc to %ld\n",
194                                         conn->buf_in_length);
195                         conn->zs_in.next_out = conn->buf_in +
196                                     LWS_SEND_BUFFER_PRE_PADDING + len_so_far;
197                         conn->zs_in.avail_out =
198                                              conn->buf_in_length - len_so_far;
199                }
200
201                 /* rewrite the buffer pointers and length */
202                 eff_buf->token = (char *)(conn->buf_in + LWS_SEND_BUFFER_PRE_PADDING);
203                 eff_buf->token_len = (int)(conn->zs_in.next_out -
204                                  (conn->buf_in + LWS_SEND_BUFFER_PRE_PADDING));
205
206                 return 0;
207
208         case LWS_EXT_CALLBACK_PAYLOAD_TX:
209                 /*
210                  * deflate the outgoing payload
211                  */
212                 current_payload = eff_buf->token_len;
213
214                 if (current_payload < MIN_SIZE_TO_DEFLATE)
215                         return 0;
216
217                 conn->zs_out.next_in = (unsigned char *)eff_buf->token;
218                 conn->zs_out.avail_in = current_payload;
219
220                 conn->zs_out.next_out = conn->buf_out + LWS_SEND_BUFFER_PRE_PADDING;
221                 conn->zs_out.avail_out = conn->buf_out_length;
222
223                 while (1) {
224                         n = deflate(&conn->zs_out, Z_SYNC_FLUSH);
225                         if (n == Z_STREAM_ERROR) {
226                                 /*
227                                  * screwed.. close the connection... we will get a
228                                  * destroy callback to take care of closing nicely
229                                  */
230                                 lwsl_ext("zlib error deflate\n");
231
232                                 return -1;
233                         }
234
235                         if (conn->zs_out.avail_out)
236                                 break;
237
238                         len_so_far = (conn->zs_out.next_out -
239                                         (conn->buf_out +
240                                                  LWS_SEND_BUFFER_PRE_PADDING));
241                         conn->buf_out_length *= 2;
242                         if (conn->buf_out_length > LWS_MAX_ZLIB_CONN_BUFFER) {
243                                 lwsl_ext("zlib out buffer tried to exceed "
244                                   "max allowed of %u\n",
245                                         LWS_MAX_ZLIB_CONN_BUFFER);
246                                 return -1;
247                         }
248                         conn->buf_out = (unsigned char *)realloc(
249                                         conn->buf_out,
250                                         LWS_SEND_BUFFER_PRE_PADDING +
251                                                   conn->buf_out_length +
252                                                   LWS_SEND_BUFFER_POST_PADDING);
253                         if (!conn->buf_out) {
254                                 lwsl_err("Out of memory\n");
255                                 return -1;
256                         }
257                         lwsl_debug(
258                                 "deflate-frame ext TX did realloc to %ld\n",
259                                         conn->buf_in_length);
260
261                         conn->zs_out.next_out = (conn->buf_out +
262                                      LWS_SEND_BUFFER_PRE_PADDING + len_so_far);
263                         conn->zs_out.avail_out =
264                                            (conn->buf_out_length - len_so_far);
265                 }
266
267                 conn->compressed_out = 1;
268
269                 /* rewrite the buffer pointers and length */
270                 eff_buf->token = (char *)(conn->buf_out +
271                                                 LWS_SEND_BUFFER_PRE_PADDING);
272                 eff_buf->token_len = (int)(conn->zs_out.next_out -
273                             (conn->buf_out + LWS_SEND_BUFFER_PRE_PADDING)) - 4;
274
275                 return 0;
276
277         case LWS_EXT_CALLBACK_PACKET_TX_PRESEND:
278                 if (conn->compressed_out) {
279                         conn->compressed_out = 0;
280                         *((unsigned char *)eff_buf->token) |= 0x40;
281                 }
282                 break;
283
284         case LWS_EXT_CALLBACK_CHECK_OK_TO_PROPOSE_EXTENSION:
285                 /* Avoid x-webkit-deflate-frame extension on client */
286                 if (!strcmp((char *)in, "x-webkit-deflate-frame"))
287                         return 1;
288                 break;
289
290         default:
291                 break;
292         }
293
294         return 0;
295 }
296