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