Home | History | Annotate | Download | only in libstagefright
      1 /*
      2  * Copyright (C) 2009 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 //#define LOG_NDEBUG 0
     18 #define LOG_TAG "HTTPStream"
     19 #include <utils/Log.h>
     20 
     21 #include "include/HTTPStream.h"
     22 
     23 #include <sys/socket.h>
     24 
     25 #include <arpa/inet.h>
     26 #include <ctype.h>
     27 #include <errno.h>
     28 #include <netdb.h>
     29 #include <stdio.h>
     30 #include <stdlib.h>
     31 #include <string.h>
     32 #include <unistd.h>
     33 
     34 #include <media/stagefright/MediaDebug.h>
     35 
     36 namespace android {
     37 
     38 // static
     39 const char *HTTPStream::kStatusKey = ":status:";
     40 
     41 HTTPStream::HTTPStream()
     42     : mState(READY),
     43       mSocket(-1) {
     44 }
     45 
     46 HTTPStream::~HTTPStream() {
     47     disconnect();
     48 }
     49 
     50 status_t HTTPStream::connect(const char *server, int port) {
     51     Mutex::Autolock autoLock(mLock);
     52 
     53     status_t err = OK;
     54 
     55     if (mState == CONNECTED) {
     56         return ERROR_ALREADY_CONNECTED;
     57     }
     58 
     59     struct hostent *ent = gethostbyname(server);
     60     if (ent == NULL) {
     61         return ERROR_UNKNOWN_HOST;
     62     }
     63 
     64     CHECK_EQ(mSocket, -1);
     65     mSocket = socket(AF_INET, SOCK_STREAM, 0);
     66 
     67     if (mSocket < 0) {
     68         return UNKNOWN_ERROR;
     69     }
     70 
     71     setReceiveTimeout(30);  // Time out reads after 30 secs by default
     72 
     73     mState = CONNECTING;
     74 
     75     int s = mSocket;
     76 
     77     mLock.unlock();
     78 
     79     struct sockaddr_in addr;
     80     addr.sin_family = AF_INET;
     81     addr.sin_port = htons(port);
     82     addr.sin_addr.s_addr = *(in_addr_t *)ent->h_addr;
     83     memset(addr.sin_zero, 0, sizeof(addr.sin_zero));
     84 
     85     int res = ::connect(s, (const struct sockaddr *)&addr, sizeof(addr));
     86 
     87     mLock.lock();
     88 
     89     if (mState != CONNECTING) {
     90         return UNKNOWN_ERROR;
     91     }
     92 
     93     if (res < 0) {
     94         close(mSocket);
     95         mSocket = -1;
     96 
     97         mState = READY;
     98         return UNKNOWN_ERROR;
     99     }
    100 
    101     mState = CONNECTED;
    102 
    103     return OK;
    104 }
    105 
    106 status_t HTTPStream::disconnect() {
    107     Mutex::Autolock autoLock(mLock);
    108 
    109     if (mState != CONNECTED && mState != CONNECTING) {
    110         return ERROR_NOT_CONNECTED;
    111     }
    112 
    113     CHECK(mSocket >= 0);
    114     close(mSocket);
    115     mSocket = -1;
    116 
    117     mState = READY;
    118 
    119     return OK;
    120 }
    121 
    122 status_t HTTPStream::send(const char *data, size_t size) {
    123     if (mState != CONNECTED) {
    124         return ERROR_NOT_CONNECTED;
    125     }
    126 
    127     while (size > 0) {
    128         ssize_t n = ::send(mSocket, data, size, 0);
    129 
    130         if (n < 0) {
    131             if (errno == EINTR) {
    132                 continue;
    133             }
    134 
    135             disconnect();
    136 
    137             return ERROR_IO;
    138         } else if (n == 0) {
    139             disconnect();
    140 
    141             return ERROR_CONNECTION_LOST;
    142         }
    143 
    144         size -= (size_t)n;
    145         data += (size_t)n;
    146     }
    147 
    148     return OK;
    149 }
    150 
    151 status_t HTTPStream::send(const char *data) {
    152     return send(data, strlen(data));
    153 }
    154 
    155 // A certain application spawns a local webserver that sends invalid responses,
    156 // specifically it terminates header line with only a newline instead of the
    157 // CRLF (carriage-return followed by newline) required by the HTTP specs.
    158 // The workaround accepts both behaviours but could potentially break
    159 // legitimate responses that use a single newline to "fold" headers, which is
    160 // why it's not yet on by default.
    161 #define WORKAROUND_FOR_MISSING_CR       1
    162 
    163 status_t HTTPStream::receive_line(char *line, size_t size) {
    164     if (mState != CONNECTED) {
    165         return ERROR_NOT_CONNECTED;
    166     }
    167 
    168     bool saw_CR = false;
    169     size_t length = 0;
    170 
    171     for (;;) {
    172         char c;
    173         ssize_t n = recv(mSocket, &c, 1, 0);
    174         if (n < 0) {
    175             if (errno == EINTR) {
    176                 continue;
    177             }
    178 
    179             disconnect();
    180 
    181             return ERROR_IO;
    182         } else if (n == 0) {
    183             disconnect();
    184 
    185             return ERROR_CONNECTION_LOST;
    186         }
    187 
    188 #if WORKAROUND_FOR_MISSING_CR
    189         if (c == '\n') {
    190             // We have a complete line.
    191 
    192             line[saw_CR ? length - 1 : length] = '\0';
    193             return OK;
    194         }
    195 #else
    196         if (saw_CR &&  c == '\n') {
    197             // We have a complete line.
    198 
    199             line[length - 1] = '\0';
    200             return OK;
    201         }
    202 #endif
    203 
    204         saw_CR = (c == '\r');
    205 
    206         if (length + 1 >= size) {
    207             return ERROR_MALFORMED;
    208         }
    209         line[length++] = c;
    210     }
    211 }
    212 
    213 status_t HTTPStream::receive_header(int *http_status) {
    214     *http_status = -1;
    215     mHeaders.clear();
    216 
    217     char line[2048];
    218     status_t err = receive_line(line, sizeof(line));
    219     if (err != OK) {
    220         return err;
    221     }
    222 
    223     mHeaders.add(string(kStatusKey), string(line));
    224 
    225     char *spacePos = strchr(line, ' ');
    226     if (spacePos == NULL) {
    227         // Malformed response?
    228         return UNKNOWN_ERROR;
    229     }
    230 
    231     char *status_start = spacePos + 1;
    232     char *status_end = status_start;
    233     while (isdigit(*status_end)) {
    234         ++status_end;
    235     }
    236 
    237     if (status_end == status_start) {
    238         // Malformed response, status missing?
    239         return UNKNOWN_ERROR;
    240     }
    241 
    242     memmove(line, status_start, status_end - status_start);
    243     line[status_end - status_start] = '\0';
    244 
    245     long tmp = strtol(line, NULL, 10);
    246     if (tmp < 0 || tmp > 999) {
    247         return UNKNOWN_ERROR;
    248     }
    249 
    250     *http_status = (int)tmp;
    251 
    252     for (;;) {
    253         err = receive_line(line, sizeof(line));
    254         if (err != OK) {
    255             return err;
    256         }
    257 
    258         if (*line == '\0') {
    259             // Empty line signals the end of the header.
    260             break;
    261         }
    262 
    263         // puts(line);
    264 
    265         char *colonPos = strchr(line, ':');
    266         if (colonPos == NULL) {
    267             mHeaders.add(string(line), string());
    268         } else {
    269             char *end_of_key = colonPos;
    270             while (end_of_key > line && isspace(end_of_key[-1])) {
    271                 --end_of_key;
    272             }
    273 
    274             char *start_of_value = colonPos + 1;
    275             while (isspace(*start_of_value)) {
    276                 ++start_of_value;
    277             }
    278 
    279             *end_of_key = '\0';
    280 
    281             mHeaders.add(string(line), string(start_of_value));
    282         }
    283     }
    284 
    285     return OK;
    286 }
    287 
    288 ssize_t HTTPStream::receive(void *data, size_t size) {
    289     size_t total = 0;
    290     while (total < size) {
    291         ssize_t n = recv(mSocket, (char *)data + total, size - total, 0);
    292 
    293         if (n < 0) {
    294             if (errno == EINTR) {
    295                 continue;
    296             }
    297 
    298             LOGE("recv failed, errno = %d (%s)", errno, strerror(errno));
    299 
    300             disconnect();
    301             return (ssize_t)ERROR_IO;
    302         } else if (n == 0) {
    303             disconnect();
    304 
    305             LOGE("recv failed, server is gone, total received: %d bytes",
    306                  total);
    307 
    308             return total == 0 ? (ssize_t)ERROR_CONNECTION_LOST : total;
    309         }
    310 
    311         total += (size_t)n;
    312     }
    313 
    314     return (ssize_t)total;
    315 }
    316 
    317 bool HTTPStream::find_header_value(const string &key, string *value) const {
    318     ssize_t index = mHeaders.indexOfKey(key);
    319     if (index < 0) {
    320         value->clear();
    321         return false;
    322     }
    323 
    324     *value = mHeaders.valueAt(index);
    325 
    326     return true;
    327 }
    328 
    329 void HTTPStream::setReceiveTimeout(int seconds) {
    330     if (seconds < 0) {
    331         // Disable the timeout.
    332         seconds = 0;
    333     }
    334 
    335     struct timeval tv;
    336     tv.tv_usec = 0;
    337     tv.tv_sec = seconds;
    338     CHECK_EQ(0, setsockopt(mSocket, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)));
    339 }
    340 
    341 }  // namespace android
    342 
    343