http_client.c

00001 
00017 #include "includes.h"
00018 #include <fcntl.h>
00019 
00020 #include "common.h"
00021 #include "eloop.h"
00022 #include "httpread.h"
00023 #include "http_client.h"
00024 
00025 
00026 #define HTTP_CLIENT_TIMEOUT 30
00027 
00028 
00029 struct http_client {
00030         struct sockaddr_in dst;
00031         int sd;
00032         struct wpabuf *req;
00033         size_t req_pos;
00034         size_t max_response;
00035 
00036         void (*cb)(void *ctx, struct http_client *c,
00037                    enum http_client_event event);
00038         void *cb_ctx;
00039         struct httpread *hread;
00040         struct wpabuf body;
00041 };
00042 
00043 
00044 static void http_client_timeout(void *eloop_data, void *user_ctx)
00045 {
00046         struct http_client *c = eloop_data;
00047         wpa_printf(MSG_DEBUG, "HTTP: Timeout");
00048         c->cb(c->cb_ctx, c, HTTP_CLIENT_TIMEOUT);
00049 }
00050 
00051 
00052 static void http_client_got_response(struct httpread *handle, void *cookie,
00053                                      enum httpread_event e)
00054 {
00055         struct http_client *c = cookie;
00056 
00057         eloop_cancel_timeout(http_client_timeout, c, NULL);
00058         switch (e) {
00059         case HTTPREAD_EVENT_FILE_READY:
00060                 if (httpread_hdr_type_get(c->hread) == HTTPREAD_HDR_TYPE_REPLY)
00061                 {
00062                         int reply_code = httpread_reply_code_get(c->hread);
00063                         if (reply_code == 200 /* OK */) {
00064                                 wpa_printf(MSG_DEBUG, "HTTP: Response OK from "
00065                                            "%s:%d",
00066                                            inet_ntoa(c->dst.sin_addr),
00067                                            ntohs(c->dst.sin_port));
00068                                 c->cb(c->cb_ctx, c, HTTP_CLIENT_OK);
00069                         } else {
00070                                 wpa_printf(MSG_DEBUG, "HTTP: Error %d from "
00071                                            "%s:%d", reply_code,
00072                                            inet_ntoa(c->dst.sin_addr),
00073                                            ntohs(c->dst.sin_port));
00074                                 c->cb(c->cb_ctx, c, HTTP_CLIENT_INVALID_REPLY);
00075                         }
00076                 } else
00077                         c->cb(c->cb_ctx, c, HTTP_CLIENT_INVALID_REPLY);
00078                 break;
00079         case HTTPREAD_EVENT_TIMEOUT:
00080                 c->cb(c->cb_ctx, c, HTTP_CLIENT_TIMEOUT);
00081                 break;
00082         case HTTPREAD_EVENT_ERROR:
00083                 c->cb(c->cb_ctx, c, HTTP_CLIENT_FAILED);
00084                 break;
00085         }
00086 }
00087 
00088 
00089 static void http_client_tx_ready(int sock, void *eloop_ctx, void *sock_ctx)
00090 {
00091         struct http_client *c = eloop_ctx;
00092         int res;
00093 
00094         wpa_printf(MSG_DEBUG, "HTTP: Send client request to %s:%d (%lu of %lu "
00095                    "bytes remaining)",
00096                    inet_ntoa(c->dst.sin_addr), ntohs(c->dst.sin_port),
00097                    (unsigned long) wpabuf_len(c->req),
00098                    (unsigned long) wpabuf_len(c->req) - c->req_pos);
00099 
00100         res = send(c->sd, wpabuf_head(c->req) + c->req_pos,
00101                    wpabuf_len(c->req) - c->req_pos, 0);
00102         if (res < 0) {
00103                 wpa_printf(MSG_DEBUG, "HTTP: Failed to send buffer: %s",
00104                            strerror(errno));
00105                 eloop_unregister_sock(c->sd, EVENT_TYPE_WRITE);
00106                 c->cb(c->cb_ctx, c, HTTP_CLIENT_FAILED);
00107                 return;
00108         }
00109 
00110         if ((size_t) res < wpabuf_len(c->req) - c->req_pos) {
00111                 wpa_printf(MSG_DEBUG, "HTTP: Sent %d of %lu bytes; %lu bytes "
00112                            "remaining",
00113                            res, (unsigned long) wpabuf_len(c->req),
00114                            (unsigned long) wpabuf_len(c->req) - c->req_pos -
00115                            res);
00116                 c->req_pos += res;
00117                 return;
00118         }
00119 
00120         wpa_printf(MSG_DEBUG, "HTTP: Full client request sent to %s:%d",
00121                    inet_ntoa(c->dst.sin_addr), ntohs(c->dst.sin_port));
00122         eloop_unregister_sock(c->sd, EVENT_TYPE_WRITE);
00123         wpabuf_free(c->req);
00124         c->req = NULL;
00125 
00126         c->hread = httpread_create(c->sd, http_client_got_response, c,
00127                                    c->max_response, HTTP_CLIENT_TIMEOUT);
00128         if (c->hread == NULL) {
00129                 c->cb(c->cb_ctx, c, HTTP_CLIENT_FAILED);
00130                 return;
00131         }
00132 }
00133 
00134 
00135 struct http_client * http_client_addr(struct sockaddr_in *dst,
00136                                       struct wpabuf *req, size_t max_response,
00137                                       void (*cb)(void *ctx,
00138                                                  struct http_client *c,
00139                                                  enum http_client_event event),
00140                                       void *cb_ctx)
00141 {
00142         struct http_client *c;
00143 
00144         c = os_zalloc(sizeof(*c));
00145         if (c == NULL)
00146                 return NULL;
00147         c->sd = -1;
00148         c->dst = *dst;
00149         c->max_response = max_response;
00150         c->cb = cb;
00151         c->cb_ctx = cb_ctx;
00152 
00153         c->sd = socket(AF_INET, SOCK_STREAM, 0);
00154         if (c->sd < 0) {
00155                 http_client_free(c);
00156                 return NULL;
00157         }
00158 
00159         if (fcntl(c->sd, F_SETFL, O_NONBLOCK) != 0) {
00160                 wpa_printf(MSG_DEBUG, "HTTP: fnctl(O_NONBLOCK) failed: %s",
00161                            strerror(errno));
00162                 http_client_free(c);
00163                 return NULL;
00164         }
00165 
00166         if (connect(c->sd, (struct sockaddr *) dst, sizeof(*dst))) {
00167                 if (errno != EINPROGRESS) {
00168                         wpa_printf(MSG_DEBUG, "HTTP: Failed to connect: %s",
00169                                    strerror(errno));
00170                         http_client_free(c);
00171                         return NULL;
00172                 }
00173 
00174                 /*
00175                  * Continue connecting in the background; eloop will call us
00176                  * once the connection is ready (or failed).
00177                  */
00178         }
00179 
00180         if (eloop_register_sock(c->sd, EVENT_TYPE_WRITE, http_client_tx_ready,
00181                                 c, NULL)) {
00182                 http_client_free(c);
00183                 return NULL;
00184         }
00185 
00186         if (eloop_register_timeout(HTTP_CLIENT_TIMEOUT, 0, http_client_timeout,
00187                                    c, NULL)) {
00188                 http_client_free(c);
00189                 return NULL;
00190         }
00191 
00192         c->req = req;
00193 
00194         return c;
00195 }
00196 
00197 
00198 char * http_client_url_parse(const char *url, struct sockaddr_in *dst,
00199                              char **ret_path)
00200 {
00201         char *u, *addr, *port, *path;
00202 
00203         u = os_strdup(url);
00204         if (u == NULL)
00205                 return NULL;
00206 
00207         os_memset(dst, 0, sizeof(*dst));
00208         dst->sin_family = AF_INET;
00209         addr = u + 7;
00210         path = os_strchr(addr, '/');
00211         port = os_strchr(addr, ':');
00212         if (path == NULL) {
00213                 path = "/";
00214         } else {
00215                 *path = '\0'; /* temporary nul termination for address */
00216                 if (port > path)
00217                         port = NULL;
00218         }
00219         if (port)
00220                 *port++ = '\0';
00221 
00222         if (inet_aton(addr, &dst->sin_addr) == 0) {
00223                 /* TODO: name lookup */
00224                 wpa_printf(MSG_DEBUG, "HTTP: Unsupported address in URL '%s' "
00225                            "(addr='%s' port='%s')",
00226                            url, addr, port);
00227                 os_free(u);
00228                 return NULL;
00229         }
00230 
00231         if (port)
00232                 dst->sin_port = htons(atoi(port));
00233         else
00234                 dst->sin_port = htons(80);
00235 
00236         if (*path == '\0') {
00237                 /* remove temporary nul termination for address */
00238                 *path = '/';
00239         }
00240 
00241         *ret_path = path;
00242 
00243         return u;
00244 }
00245 
00246 
00247 struct http_client * http_client_url(const char *url,
00248                                      struct wpabuf *req, size_t max_response,
00249                                      void (*cb)(void *ctx,
00250                                                 struct http_client *c,
00251                                                 enum http_client_event event),
00252                                      void *cb_ctx)
00253 {
00254         struct sockaddr_in dst;
00255         struct http_client *c;
00256         char *u, *path;
00257         struct wpabuf *req_buf = NULL;
00258 
00259         if (os_strncmp(url, "http://", 7) != 0)
00260                 return NULL;
00261         u = http_client_url_parse(url, &dst, &path);
00262         if (u == NULL)
00263                 return NULL;
00264 
00265         if (req == NULL) {
00266                 req_buf = wpabuf_alloc(os_strlen(url) + 1000);
00267                 if (req_buf == NULL) {
00268                         os_free(u);
00269                         return NULL;
00270                 }
00271                 req = req_buf;
00272                 wpabuf_printf(req,
00273                               "GET %s HTTP/1.1\r\n"
00274                               "Cache-Control: no-cache\r\n"
00275                               "Pragma: no-cache\r\n"
00276                               "Accept: text/xml, application/xml\r\n"
00277                               "User-Agent: wpa_supplicant\r\n"
00278                               "Host: %s:%d\r\n"
00279                               "\r\n",
00280                               path, inet_ntoa(dst.sin_addr),
00281                               ntohs(dst.sin_port));
00282         }
00283         os_free(u);
00284 
00285         c = http_client_addr(&dst, req, max_response, cb, cb_ctx);
00286         if (c == NULL) {
00287                 wpabuf_free(req_buf);
00288                 return NULL;
00289         }
00290 
00291         return c;
00292 }
00293 
00294 
00295 void http_client_free(struct http_client *c)
00296 {
00297         if (c == NULL)
00298                 return;
00299         httpread_destroy(c->hread);
00300         wpabuf_free(c->req);
00301         if (c->sd >= 0) {
00302                 eloop_unregister_sock(c->sd, EVENT_TYPE_WRITE);
00303                 close(c->sd);
00304         }
00305         eloop_cancel_timeout(http_client_timeout, c, NULL);
00306         os_free(c);
00307 }
00308 
00309 
00310 struct wpabuf * http_client_get_body(struct http_client *c)
00311 {
00312         if (c->hread == NULL)
00313                 return NULL;
00314         wpabuf_set(&c->body, httpread_data_get(c->hread),
00315                    httpread_length_get(c->hread));
00316         return &c->body;
00317 }
00318 
00319 
00320 char * http_link_update(char *url, const char *base)
00321 {
00322         char *n;
00323         size_t len;
00324         const char *pos;
00325 
00326         /* RFC 2396, Chapter 5.2 */
00327         /* TODO: consider adding all cases described in RFC 2396 */
00328 
00329         if (url == NULL)
00330                 return NULL;
00331 
00332         if (os_strncmp(url, "http://", 7) == 0)
00333                 return url; /* absolute link */
00334 
00335         if (os_strncmp(base, "http://", 7) != 0)
00336                 return url; /* unable to handle base URL */
00337 
00338         len = os_strlen(url) + 1 + os_strlen(base) + 1;
00339         n = os_malloc(len);
00340         if (n == NULL)
00341                 return url; /* failed */
00342 
00343         if (url[0] == '/') {
00344                 pos = os_strchr(base + 7, '/');
00345                 if (pos == NULL) {
00346                         os_snprintf(n, len, "%s%s", base, url);
00347                 } else {
00348                         os_memcpy(n, base, pos - base);
00349                         os_memcpy(n + (pos - base), url, os_strlen(url) + 1);
00350                 }
00351         } else {
00352                 pos = os_strrchr(base + 7, '/');
00353                 if (pos == NULL) {
00354                         os_snprintf(n, len, "%s/%s", base, url);
00355                 } else {
00356                         os_memcpy(n, base, pos - base + 1);
00357                         os_memcpy(n + (pos - base) + 1, url, os_strlen(url) +
00358                                   1);
00359                 }
00360         }
00361 
00362         os_free(url);
00363 
00364         return n;
00365 }
00366 
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines

Generated on Sat Nov 21 23:16:54 2009 for hostapd by  doxygen 1.6.1