]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/redboot/v2_0/src/net/http_client.c
unified MX27, MX25, MX37 trees
[karo-tx-redboot.git] / packages / redboot / v2_0 / src / net / http_client.c
1 //==========================================================================
2 //
3 //      net/http_client.c
4 //
5 //      Stand-alone HTTP support for RedBoot
6 //
7 //==========================================================================
8 //####ECOSGPLCOPYRIGHTBEGIN####
9 // -------------------------------------------
10 // This file is part of eCos, the Embedded Configurable Operating System.
11 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
12 // Copyright (C) 2002, 2003 Gary Thomas
13 //
14 // eCos is free software; you can redistribute it and/or modify it under
15 // the terms of the GNU General Public License as published by the Free
16 // Software Foundation; either version 2 or (at your option) any later version.
17 //
18 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
19 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
20 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
21 // for more details.
22 //
23 // You should have received a copy of the GNU General Public License along
24 // with eCos; if not, write to the Free Software Foundation, Inc.,
25 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
26 //
27 // As a special exception, if other files instantiate templates or use macros
28 // or inline functions from this file, or you compile this file and link it
29 // with other works to produce a work based on this file, this file does not
30 // by itself cause the resulting work to be covered by the GNU General Public
31 // License. However the source code for this file must still be made available
32 // in accordance with section (3) of the GNU General Public License.
33 //
34 // This exception does not invalidate any other reasons why a work based on
35 // this file might be covered by the GNU General Public License.
36 //
37 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
38 // at http://sources.redhat.com/ecos/ecos-license/
39 // -------------------------------------------
40 //####ECOSGPLCOPYRIGHTEND####
41 //==========================================================================
42 //#####DESCRIPTIONBEGIN####
43 //
44 // Author(s):    gthomas
45 // Contributors: gthomas
46 // Date:         2002-05-22
47 // Purpose:      
48 // Description:  
49 //              
50 // This code is part of RedBoot (tm).
51 //
52 //####DESCRIPTIONEND####
53 //
54 //==========================================================================
55
56 // HTTP client support
57
58 #include <redboot.h>     // have_net
59 #include <net/net.h>
60 #include <net/http.h>
61
62 // So we remember which ports have been used
63 static int get_port = 7800;
64
65 static struct _stream{
66     bool open;
67     int  avail, actual_len, pos, filelen;
68     char data[4096];
69     char *bufp;
70     tcp_socket_t sock;
71 } http_stream;
72
73 static __inline__ int
74 min(int a, int b)
75 {
76     if (a < b) 
77         return a;
78     else
79         return b;
80 }
81
82 int
83 http_stream_open(connection_info_t *info, int *err)
84 {
85     int res;
86     struct _stream *s = &http_stream;
87
88     if (!info->server->sin_port)
89         info->server->sin_port = 80;  // HTTP port
90     if ((res = __tcp_open(&s->sock, info->server, get_port++, 5000, err)) < 0) {
91         *err = HTTP_OPEN;
92         return -1;
93     }
94     diag_sprintf(s->data, "GET %s HTTP/1.0\r\n\r\n", info->filename);
95     __tcp_write_block(&s->sock, s->data, strlen(s->data));    
96     s->avail = 0;
97     s->open = true;
98     s->pos = 0;
99     return 0;
100 }
101
102 void
103 http_stream_close(int *err)
104 {    
105     struct _stream *s = &http_stream;
106
107     if (s->open) {
108         __tcp_abort(&s->sock,1);
109         s->open = false;    
110     }
111 }
112
113 int
114 http_stream_read(void *buf,
115                  int len,
116                  int *err)
117 {    
118     struct _stream *s = &http_stream;
119     int total = 0;
120     int cnt, code;
121
122     if (!s->open) {
123         return -1;  // Shouldn't happen, but...
124     }
125     while (len) {
126         while (s->avail == 0) {
127             // Need to wait for some data to arrive
128             __tcp_poll();
129             if (s->sock.state != _ESTABLISHED) {
130                 if (s->sock.state == _CLOSE_WAIT) {
131                     // This connection is breaking
132                     if (s->sock.data_bytes == 0 && s->sock.rxcnt == 0) {
133                         __tcp_close(&s->sock);
134                         return total;
135                     }  
136                 } else if (s->sock.state == _CLOSED) {
137                         // The connection is gone
138                         s->open = false;
139                         return -1;
140                 } else {        
141                     *err = HTTP_IO;
142                     return -1;
143                 }
144             }
145             s->actual_len = __tcp_read(&s->sock, s->data, sizeof(s->data));
146             if (s->actual_len > 0) {
147                 s->bufp = s->data;
148                 s->avail = s->actual_len;
149                 if (s->pos == 0) {
150                     // First data - need to scan HTTP response header
151                     if (strncmp(s->bufp, "HTTP/", 5) == 0) {
152                         // Should look like "HTTP/1.1 200 OK"
153                         s->bufp += 5;
154                         s->avail -= 5;
155                         // Find first space
156                         while ((s->avail > 0) && (*s->bufp != ' ')) {
157                             s->bufp++;  
158                             s->avail--;
159                         }
160                         // Now the integer response
161                         code = 0;
162                         while ((s->avail > 0) && (*s->bufp == ' ')) {
163                             s->bufp++;  
164                             s->avail--;
165                         }
166                         while ((s->avail > 0) && isdigit(*s->bufp)) {
167                             code = (code * 10) + (*s->bufp - '0');
168                             s->bufp++;  
169                             s->avail--;
170                         }
171                         // Make sure it says OK
172                         while ((s->avail > 0) && (*s->bufp == ' ')) {
173                             s->bufp++;  
174                             s->avail--;
175                         }
176                         if (strncmp(s->bufp, "OK", 2)) {
177                             switch (code) {
178                             case 400:
179                                 *err = HTTP_BADREQ;
180                                 break;
181                             case 403:
182                                 *err = HTTP_FORBIDDEN;
183                                 break;
184                             case 404:
185                                 *err = HTTP_NOFILE;
186                                 break;
187                             default:
188                                 *err = HTTP_BADHDR;
189                                 break;
190                             }
191                             return -1;
192                         }
193                         // Find \r\n\r\n - end of HTTP preamble
194                         while (s->avail >= 4) {
195                             // This could be done faster, but not simpler
196                             if (strncmp(s->bufp, "\r\n\r\n", 4) == 0) {
197                                 s->bufp += 4;
198                                 s->avail -= 4;
199 #if 0 // DEBUG - show header
200                                 *(s->bufp-2) = '\0';
201                                 diag_printf(s->data);
202 #endif
203                                 break;
204                             }
205                             s->avail--;
206                             s->bufp++;
207                         }
208                         s->pos++;
209                     } else {
210                         // Unrecognized response
211                         *err = HTTP_BADHDR;
212                         return -1;
213                     }
214                 }
215             } else if (s->actual_len < 0) {
216                 *err = HTTP_IO;
217                 return -1;
218             }
219         }
220         cnt = min(len, s->avail);
221         memcpy(buf, s->bufp, cnt);
222         s->avail -= cnt;
223         s->bufp += cnt;
224         buf = (char *)buf + cnt;
225         total += cnt;
226         len -= cnt;
227     }
228     return total;
229 }
230
231 char *
232 http_error(int err)
233 {
234     char *errmsg = "Unknown error";
235
236     switch (err) {
237     case HTTP_NOERR:
238         return "";
239     case HTTP_BADHDR:
240         return "Unrecognized HTTP response";
241     case HTTP_BADREQ:
242         return "Bad HTTP request (check file name)";
243     case HTTP_NOFILE:
244         return "No such file";
245     case HTTP_OPEN:
246         return "Can't connect to host";
247     case HTTP_IO:
248         return "I/O error";
249     case HTTP_FORBIDDEN:
250         return "Forbidden (check permissions)";
251     }
252     return errmsg;
253 }
254
255 //
256 // RedBoot interface
257 //
258 GETC_IO_FUNCS(http_io, http_stream_open, http_stream_close,
259               0, http_stream_read, http_error);
260 RedBoot_load(http, http_io, true, true, 0);