• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include <sys/socket.h>
18 
19 #include <arpa/inet.h>
20 #include <ctype.h>
21 #include <errno.h>
22 #include <netdb.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <unistd.h>
27 
28 #include <media/stagefright/HTTPStream.h>
29 #include <media/stagefright/MediaDebug.h>
30 
31 namespace android {
32 
33 // static
34 const char *HTTPStream::kStatusKey = ":status:";
35 
HTTPStream()36 HTTPStream::HTTPStream()
37     : mState(READY),
38       mSocket(-1) {
39 }
40 
~HTTPStream()41 HTTPStream::~HTTPStream() {
42     disconnect();
43 }
44 
connect(const char * server,int port)45 status_t HTTPStream::connect(const char *server, int port) {
46     status_t err = OK;
47 
48     if (mState == CONNECTED) {
49         return ERROR_ALREADY_CONNECTED;
50     }
51 
52     CHECK_EQ(mSocket, -1);
53     mSocket = socket(AF_INET, SOCK_STREAM, 0);
54 
55     if (mSocket < 0) {
56         return UNKNOWN_ERROR;
57     }
58 
59     struct hostent *ent = gethostbyname(server);
60     if (ent == NULL) {
61         err = ERROR_UNKNOWN_HOST;
62         goto exit1;
63     }
64 
65     struct sockaddr_in addr;
66     addr.sin_family = AF_INET;
67     addr.sin_port = htons(port);
68     addr.sin_addr.s_addr = *(in_addr_t *)ent->h_addr;
69     memset(addr.sin_zero, 0, sizeof(addr.sin_zero));
70 
71     if (::connect(mSocket, (const struct sockaddr *)&addr, sizeof(addr)) < 0) {
72         err = ERROR_CANNOT_CONNECT;
73         goto exit1;
74     }
75 
76     mState = CONNECTED;
77 
78     return OK;
79 
80 exit1:
81     close(mSocket);
82     mSocket = -1;
83 
84     return err;
85 }
86 
disconnect()87 status_t HTTPStream::disconnect() {
88     if (mState != CONNECTED) {
89         return ERROR_NOT_CONNECTED;
90     }
91 
92     CHECK(mSocket >= 0);
93     close(mSocket);
94     mSocket = -1;
95 
96     mState = READY;
97 
98     return OK;
99 }
100 
send(const char * data,size_t size)101 status_t HTTPStream::send(const char *data, size_t size) {
102     if (mState != CONNECTED) {
103         return ERROR_NOT_CONNECTED;
104     }
105 
106     while (size > 0) {
107         ssize_t n = ::send(mSocket, data, size, 0);
108 
109         if (n < 0) {
110             if (errno == EINTR) {
111                 continue;
112             }
113 
114             disconnect();
115 
116             return ERROR_IO;
117         } else if (n == 0) {
118             disconnect();
119 
120             return ERROR_CONNECTION_LOST;
121         }
122 
123         size -= (size_t)n;
124         data += (size_t)n;
125     }
126 
127     return OK;
128 }
129 
send(const char * data)130 status_t HTTPStream::send(const char *data) {
131     return send(data, strlen(data));
132 }
133 
receive_line(char * line,size_t size)134 status_t HTTPStream::receive_line(char *line, size_t size) {
135     if (mState != CONNECTED) {
136         return ERROR_NOT_CONNECTED;
137     }
138 
139     bool saw_CR = false;
140     size_t length = 0;
141 
142     for (;;) {
143         char c;
144         ssize_t n = recv(mSocket, &c, 1, 0);
145         if (n < 0) {
146             if (errno == EINTR) {
147                 continue;
148             }
149 
150             disconnect();
151 
152             return ERROR_IO;
153         } else if (n == 0) {
154             disconnect();
155 
156             return ERROR_CONNECTION_LOST;
157         }
158 
159         if (saw_CR && c == '\n') {
160             // We have a complete line.
161 
162             line[length - 1] = '\0';
163             return OK;
164         }
165 
166         saw_CR = (c == '\r');
167 
168         CHECK(length + 1 < size);
169         line[length++] = c;
170     }
171 }
172 
receive_header(int * http_status)173 status_t HTTPStream::receive_header(int *http_status) {
174     *http_status = -1;
175     mHeaders.clear();
176 
177     char line[1024];
178     status_t err = receive_line(line, sizeof(line));
179     if (err != OK) {
180         return err;
181     }
182 
183     mHeaders.add(string(kStatusKey), string(line));
184 
185     char *spacePos = strchr(line, ' ');
186     if (spacePos == NULL) {
187         // Malformed response?
188         return UNKNOWN_ERROR;
189     }
190 
191     char *status_start = spacePos + 1;
192     char *status_end = status_start;
193     while (isdigit(*status_end)) {
194         ++status_end;
195     }
196 
197     if (status_end == status_start) {
198         // Malformed response, status missing?
199         return UNKNOWN_ERROR;
200     }
201 
202     memmove(line, status_start, status_end - status_start);
203     line[status_end - status_start] = '\0';
204 
205     long tmp = strtol(line, NULL, 10);
206     if (tmp < 0 || tmp > 999) {
207         return UNKNOWN_ERROR;
208     }
209 
210     *http_status = (int)tmp;
211 
212     for (;;) {
213         err = receive_line(line, sizeof(line));
214         if (err != OK) {
215             return err;
216         }
217 
218         if (*line == '\0') {
219             // Empty line signals the end of the header.
220             break;
221         }
222 
223         // puts(line);
224 
225         char *colonPos = strchr(line, ':');
226         if (colonPos == NULL) {
227             mHeaders.add(string(line), string());
228         } else {
229             char *end_of_key = colonPos;
230             while (end_of_key > line && isspace(end_of_key[-1])) {
231                 --end_of_key;
232             }
233 
234             char *start_of_value = colonPos + 1;
235             while (isspace(*start_of_value)) {
236                 ++start_of_value;
237             }
238 
239             *end_of_key = '\0';
240 
241             mHeaders.add(string(line), string(start_of_value));
242         }
243     }
244 
245     return OK;
246 }
247 
receive(void * data,size_t size)248 ssize_t HTTPStream::receive(void *data, size_t size) {
249     size_t total = 0;
250     while (total < size) {
251         ssize_t n = recv(mSocket, (char *)data + total, size - total, 0);
252 
253         if (n < 0) {
254             if (errno == EINTR) {
255                 continue;
256             }
257 
258             disconnect();
259             return ERROR_IO;
260         } else if (n == 0) {
261             disconnect();
262 
263             return ERROR_CONNECTION_LOST;
264         }
265 
266         total += (size_t)n;
267     }
268 
269     return (ssize_t)total;
270 }
271 
find_header_value(const string & key,string * value) const272 bool HTTPStream::find_header_value(const string &key, string *value) const {
273     ssize_t index = mHeaders.indexOfKey(key);
274     if (index < 0) {
275         value->clear();
276         return false;
277     }
278 
279     *value = mHeaders.valueAt(index);
280 
281     return true;
282 }
283 
284 }  // namespace android
285 
286