1*d9f75844SAndroid Build Coastguard Worker /*
2*d9f75844SAndroid Build Coastguard Worker * Copyright 2011 The WebRTC Project Authors. All rights reserved.
3*d9f75844SAndroid Build Coastguard Worker *
4*d9f75844SAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license
5*d9f75844SAndroid Build Coastguard Worker * that can be found in the LICENSE file in the root of the source
6*d9f75844SAndroid Build Coastguard Worker * tree. An additional intellectual property rights grant can be found
7*d9f75844SAndroid Build Coastguard Worker * in the file PATENTS. All contributing project authors may
8*d9f75844SAndroid Build Coastguard Worker * be found in the AUTHORS file in the root of the source tree.
9*d9f75844SAndroid Build Coastguard Worker */
10*d9f75844SAndroid Build Coastguard Worker
11*d9f75844SAndroid Build Coastguard Worker #include "examples/peerconnection/server/data_socket.h"
12*d9f75844SAndroid Build Coastguard Worker
13*d9f75844SAndroid Build Coastguard Worker #include <stdio.h>
14*d9f75844SAndroid Build Coastguard Worker #include <stdlib.h>
15*d9f75844SAndroid Build Coastguard Worker #include <string.h>
16*d9f75844SAndroid Build Coastguard Worker #if defined(WEBRTC_POSIX)
17*d9f75844SAndroid Build Coastguard Worker #include <unistd.h>
18*d9f75844SAndroid Build Coastguard Worker #endif
19*d9f75844SAndroid Build Coastguard Worker
20*d9f75844SAndroid Build Coastguard Worker #include "examples/peerconnection/server/utils.h"
21*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/checks.h"
22*d9f75844SAndroid Build Coastguard Worker
23*d9f75844SAndroid Build Coastguard Worker static const char kHeaderTerminator[] = "\r\n\r\n";
24*d9f75844SAndroid Build Coastguard Worker static const int kHeaderTerminatorLength = sizeof(kHeaderTerminator) - 1;
25*d9f75844SAndroid Build Coastguard Worker
26*d9f75844SAndroid Build Coastguard Worker // static
27*d9f75844SAndroid Build Coastguard Worker const char DataSocket::kCrossOriginAllowHeaders[] =
28*d9f75844SAndroid Build Coastguard Worker "Access-Control-Allow-Origin: *\r\n"
29*d9f75844SAndroid Build Coastguard Worker "Access-Control-Allow-Credentials: true\r\n"
30*d9f75844SAndroid Build Coastguard Worker "Access-Control-Allow-Methods: POST, GET, OPTIONS\r\n"
31*d9f75844SAndroid Build Coastguard Worker "Access-Control-Allow-Headers: Content-Type, "
32*d9f75844SAndroid Build Coastguard Worker "Content-Length, Connection, Cache-Control\r\n"
33*d9f75844SAndroid Build Coastguard Worker "Access-Control-Expose-Headers: Content-Length\r\n";
34*d9f75844SAndroid Build Coastguard Worker
35*d9f75844SAndroid Build Coastguard Worker #if defined(WIN32)
36*d9f75844SAndroid Build Coastguard Worker class WinsockInitializer {
37*d9f75844SAndroid Build Coastguard Worker static WinsockInitializer singleton;
38*d9f75844SAndroid Build Coastguard Worker
WinsockInitializer()39*d9f75844SAndroid Build Coastguard Worker WinsockInitializer() {
40*d9f75844SAndroid Build Coastguard Worker WSADATA data;
41*d9f75844SAndroid Build Coastguard Worker WSAStartup(MAKEWORD(1, 0), &data);
42*d9f75844SAndroid Build Coastguard Worker }
43*d9f75844SAndroid Build Coastguard Worker
44*d9f75844SAndroid Build Coastguard Worker public:
~WinsockInitializer()45*d9f75844SAndroid Build Coastguard Worker ~WinsockInitializer() { WSACleanup(); }
46*d9f75844SAndroid Build Coastguard Worker };
47*d9f75844SAndroid Build Coastguard Worker WinsockInitializer WinsockInitializer::singleton;
48*d9f75844SAndroid Build Coastguard Worker #endif
49*d9f75844SAndroid Build Coastguard Worker
50*d9f75844SAndroid Build Coastguard Worker //
51*d9f75844SAndroid Build Coastguard Worker // SocketBase
52*d9f75844SAndroid Build Coastguard Worker //
53*d9f75844SAndroid Build Coastguard Worker
Create()54*d9f75844SAndroid Build Coastguard Worker bool SocketBase::Create() {
55*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(!valid());
56*d9f75844SAndroid Build Coastguard Worker socket_ = ::socket(AF_INET, SOCK_STREAM, 0);
57*d9f75844SAndroid Build Coastguard Worker return valid();
58*d9f75844SAndroid Build Coastguard Worker }
59*d9f75844SAndroid Build Coastguard Worker
Close()60*d9f75844SAndroid Build Coastguard Worker void SocketBase::Close() {
61*d9f75844SAndroid Build Coastguard Worker if (socket_ != INVALID_SOCKET) {
62*d9f75844SAndroid Build Coastguard Worker closesocket(socket_);
63*d9f75844SAndroid Build Coastguard Worker socket_ = INVALID_SOCKET;
64*d9f75844SAndroid Build Coastguard Worker }
65*d9f75844SAndroid Build Coastguard Worker }
66*d9f75844SAndroid Build Coastguard Worker
67*d9f75844SAndroid Build Coastguard Worker //
68*d9f75844SAndroid Build Coastguard Worker // DataSocket
69*d9f75844SAndroid Build Coastguard Worker //
70*d9f75844SAndroid Build Coastguard Worker
request_arguments() const71*d9f75844SAndroid Build Coastguard Worker std::string DataSocket::request_arguments() const {
72*d9f75844SAndroid Build Coastguard Worker size_t args = request_path_.find('?');
73*d9f75844SAndroid Build Coastguard Worker if (args != std::string::npos)
74*d9f75844SAndroid Build Coastguard Worker return request_path_.substr(args + 1);
75*d9f75844SAndroid Build Coastguard Worker return "";
76*d9f75844SAndroid Build Coastguard Worker }
77*d9f75844SAndroid Build Coastguard Worker
PathEquals(const char * path) const78*d9f75844SAndroid Build Coastguard Worker bool DataSocket::PathEquals(const char* path) const {
79*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(path);
80*d9f75844SAndroid Build Coastguard Worker size_t args = request_path_.find('?');
81*d9f75844SAndroid Build Coastguard Worker if (args != std::string::npos)
82*d9f75844SAndroid Build Coastguard Worker return request_path_.substr(0, args).compare(path) == 0;
83*d9f75844SAndroid Build Coastguard Worker return request_path_.compare(path) == 0;
84*d9f75844SAndroid Build Coastguard Worker }
85*d9f75844SAndroid Build Coastguard Worker
OnDataAvailable(bool * close_socket)86*d9f75844SAndroid Build Coastguard Worker bool DataSocket::OnDataAvailable(bool* close_socket) {
87*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(valid());
88*d9f75844SAndroid Build Coastguard Worker char buffer[0xfff] = {0};
89*d9f75844SAndroid Build Coastguard Worker int bytes = recv(socket_, buffer, sizeof(buffer), 0);
90*d9f75844SAndroid Build Coastguard Worker if (bytes == SOCKET_ERROR || bytes == 0) {
91*d9f75844SAndroid Build Coastguard Worker *close_socket = true;
92*d9f75844SAndroid Build Coastguard Worker return false;
93*d9f75844SAndroid Build Coastguard Worker }
94*d9f75844SAndroid Build Coastguard Worker
95*d9f75844SAndroid Build Coastguard Worker *close_socket = false;
96*d9f75844SAndroid Build Coastguard Worker
97*d9f75844SAndroid Build Coastguard Worker bool ret = true;
98*d9f75844SAndroid Build Coastguard Worker if (headers_received()) {
99*d9f75844SAndroid Build Coastguard Worker if (method_ != POST) {
100*d9f75844SAndroid Build Coastguard Worker // unexpectedly received data.
101*d9f75844SAndroid Build Coastguard Worker ret = false;
102*d9f75844SAndroid Build Coastguard Worker } else {
103*d9f75844SAndroid Build Coastguard Worker data_.append(buffer, bytes);
104*d9f75844SAndroid Build Coastguard Worker }
105*d9f75844SAndroid Build Coastguard Worker } else {
106*d9f75844SAndroid Build Coastguard Worker request_headers_.append(buffer, bytes);
107*d9f75844SAndroid Build Coastguard Worker size_t found = request_headers_.find(kHeaderTerminator);
108*d9f75844SAndroid Build Coastguard Worker if (found != std::string::npos) {
109*d9f75844SAndroid Build Coastguard Worker data_ = request_headers_.substr(found + kHeaderTerminatorLength);
110*d9f75844SAndroid Build Coastguard Worker request_headers_.resize(found + kHeaderTerminatorLength);
111*d9f75844SAndroid Build Coastguard Worker ret = ParseHeaders();
112*d9f75844SAndroid Build Coastguard Worker }
113*d9f75844SAndroid Build Coastguard Worker }
114*d9f75844SAndroid Build Coastguard Worker return ret;
115*d9f75844SAndroid Build Coastguard Worker }
116*d9f75844SAndroid Build Coastguard Worker
Send(const std::string & data) const117*d9f75844SAndroid Build Coastguard Worker bool DataSocket::Send(const std::string& data) const {
118*d9f75844SAndroid Build Coastguard Worker return send(socket_, data.data(), static_cast<int>(data.length()), 0) !=
119*d9f75844SAndroid Build Coastguard Worker SOCKET_ERROR;
120*d9f75844SAndroid Build Coastguard Worker }
121*d9f75844SAndroid Build Coastguard Worker
Send(const std::string & status,bool connection_close,const std::string & content_type,const std::string & extra_headers,const std::string & data) const122*d9f75844SAndroid Build Coastguard Worker bool DataSocket::Send(const std::string& status,
123*d9f75844SAndroid Build Coastguard Worker bool connection_close,
124*d9f75844SAndroid Build Coastguard Worker const std::string& content_type,
125*d9f75844SAndroid Build Coastguard Worker const std::string& extra_headers,
126*d9f75844SAndroid Build Coastguard Worker const std::string& data) const {
127*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(valid());
128*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(!status.empty());
129*d9f75844SAndroid Build Coastguard Worker std::string buffer("HTTP/1.1 " + status + "\r\n");
130*d9f75844SAndroid Build Coastguard Worker
131*d9f75844SAndroid Build Coastguard Worker buffer +=
132*d9f75844SAndroid Build Coastguard Worker "Server: PeerConnectionTestServer/0.1\r\n"
133*d9f75844SAndroid Build Coastguard Worker "Cache-Control: no-cache\r\n";
134*d9f75844SAndroid Build Coastguard Worker
135*d9f75844SAndroid Build Coastguard Worker if (connection_close)
136*d9f75844SAndroid Build Coastguard Worker buffer += "Connection: close\r\n";
137*d9f75844SAndroid Build Coastguard Worker
138*d9f75844SAndroid Build Coastguard Worker if (!content_type.empty())
139*d9f75844SAndroid Build Coastguard Worker buffer += "Content-Type: " + content_type + "\r\n";
140*d9f75844SAndroid Build Coastguard Worker
141*d9f75844SAndroid Build Coastguard Worker buffer +=
142*d9f75844SAndroid Build Coastguard Worker "Content-Length: " + int2str(static_cast<int>(data.size())) + "\r\n";
143*d9f75844SAndroid Build Coastguard Worker
144*d9f75844SAndroid Build Coastguard Worker if (!extra_headers.empty()) {
145*d9f75844SAndroid Build Coastguard Worker buffer += extra_headers;
146*d9f75844SAndroid Build Coastguard Worker // Extra headers are assumed to have a separator per header.
147*d9f75844SAndroid Build Coastguard Worker }
148*d9f75844SAndroid Build Coastguard Worker
149*d9f75844SAndroid Build Coastguard Worker buffer += kCrossOriginAllowHeaders;
150*d9f75844SAndroid Build Coastguard Worker
151*d9f75844SAndroid Build Coastguard Worker buffer += "\r\n";
152*d9f75844SAndroid Build Coastguard Worker buffer += data;
153*d9f75844SAndroid Build Coastguard Worker
154*d9f75844SAndroid Build Coastguard Worker return Send(buffer);
155*d9f75844SAndroid Build Coastguard Worker }
156*d9f75844SAndroid Build Coastguard Worker
Clear()157*d9f75844SAndroid Build Coastguard Worker void DataSocket::Clear() {
158*d9f75844SAndroid Build Coastguard Worker method_ = INVALID;
159*d9f75844SAndroid Build Coastguard Worker content_length_ = 0;
160*d9f75844SAndroid Build Coastguard Worker content_type_.clear();
161*d9f75844SAndroid Build Coastguard Worker request_path_.clear();
162*d9f75844SAndroid Build Coastguard Worker request_headers_.clear();
163*d9f75844SAndroid Build Coastguard Worker data_.clear();
164*d9f75844SAndroid Build Coastguard Worker }
165*d9f75844SAndroid Build Coastguard Worker
ParseHeaders()166*d9f75844SAndroid Build Coastguard Worker bool DataSocket::ParseHeaders() {
167*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(!request_headers_.empty());
168*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_EQ(method_, INVALID);
169*d9f75844SAndroid Build Coastguard Worker size_t i = request_headers_.find("\r\n");
170*d9f75844SAndroid Build Coastguard Worker if (i == std::string::npos)
171*d9f75844SAndroid Build Coastguard Worker return false;
172*d9f75844SAndroid Build Coastguard Worker
173*d9f75844SAndroid Build Coastguard Worker if (!ParseMethodAndPath(request_headers_.data(), i))
174*d9f75844SAndroid Build Coastguard Worker return false;
175*d9f75844SAndroid Build Coastguard Worker
176*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_NE(method_, INVALID);
177*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(!request_path_.empty());
178*d9f75844SAndroid Build Coastguard Worker
179*d9f75844SAndroid Build Coastguard Worker if (method_ == POST) {
180*d9f75844SAndroid Build Coastguard Worker const char* headers = request_headers_.data() + i + 2;
181*d9f75844SAndroid Build Coastguard Worker size_t len = request_headers_.length() - i - 2;
182*d9f75844SAndroid Build Coastguard Worker if (!ParseContentLengthAndType(headers, len))
183*d9f75844SAndroid Build Coastguard Worker return false;
184*d9f75844SAndroid Build Coastguard Worker }
185*d9f75844SAndroid Build Coastguard Worker
186*d9f75844SAndroid Build Coastguard Worker return true;
187*d9f75844SAndroid Build Coastguard Worker }
188*d9f75844SAndroid Build Coastguard Worker
ParseMethodAndPath(const char * begin,size_t len)189*d9f75844SAndroid Build Coastguard Worker bool DataSocket::ParseMethodAndPath(const char* begin, size_t len) {
190*d9f75844SAndroid Build Coastguard Worker struct {
191*d9f75844SAndroid Build Coastguard Worker const char* method_name;
192*d9f75844SAndroid Build Coastguard Worker size_t method_name_len;
193*d9f75844SAndroid Build Coastguard Worker RequestMethod id;
194*d9f75844SAndroid Build Coastguard Worker } supported_methods[] = {
195*d9f75844SAndroid Build Coastguard Worker {"GET", 3, GET},
196*d9f75844SAndroid Build Coastguard Worker {"POST", 4, POST},
197*d9f75844SAndroid Build Coastguard Worker {"OPTIONS", 7, OPTIONS},
198*d9f75844SAndroid Build Coastguard Worker };
199*d9f75844SAndroid Build Coastguard Worker
200*d9f75844SAndroid Build Coastguard Worker const char* path = NULL;
201*d9f75844SAndroid Build Coastguard Worker for (size_t i = 0; i < ARRAYSIZE(supported_methods); ++i) {
202*d9f75844SAndroid Build Coastguard Worker if (len > supported_methods[i].method_name_len &&
203*d9f75844SAndroid Build Coastguard Worker isspace(begin[supported_methods[i].method_name_len]) &&
204*d9f75844SAndroid Build Coastguard Worker strncmp(begin, supported_methods[i].method_name,
205*d9f75844SAndroid Build Coastguard Worker supported_methods[i].method_name_len) == 0) {
206*d9f75844SAndroid Build Coastguard Worker method_ = supported_methods[i].id;
207*d9f75844SAndroid Build Coastguard Worker path = begin + supported_methods[i].method_name_len;
208*d9f75844SAndroid Build Coastguard Worker break;
209*d9f75844SAndroid Build Coastguard Worker }
210*d9f75844SAndroid Build Coastguard Worker }
211*d9f75844SAndroid Build Coastguard Worker
212*d9f75844SAndroid Build Coastguard Worker const char* end = begin + len;
213*d9f75844SAndroid Build Coastguard Worker if (!path || path >= end)
214*d9f75844SAndroid Build Coastguard Worker return false;
215*d9f75844SAndroid Build Coastguard Worker
216*d9f75844SAndroid Build Coastguard Worker ++path;
217*d9f75844SAndroid Build Coastguard Worker begin = path;
218*d9f75844SAndroid Build Coastguard Worker while (!isspace(*path) && path < end)
219*d9f75844SAndroid Build Coastguard Worker ++path;
220*d9f75844SAndroid Build Coastguard Worker
221*d9f75844SAndroid Build Coastguard Worker request_path_.assign(begin, path - begin);
222*d9f75844SAndroid Build Coastguard Worker
223*d9f75844SAndroid Build Coastguard Worker return true;
224*d9f75844SAndroid Build Coastguard Worker }
225*d9f75844SAndroid Build Coastguard Worker
ParseContentLengthAndType(const char * headers,size_t length)226*d9f75844SAndroid Build Coastguard Worker bool DataSocket::ParseContentLengthAndType(const char* headers, size_t length) {
227*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_EQ(content_length_, 0);
228*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(content_type_.empty());
229*d9f75844SAndroid Build Coastguard Worker
230*d9f75844SAndroid Build Coastguard Worker const char* end = headers + length;
231*d9f75844SAndroid Build Coastguard Worker while (headers && headers < end) {
232*d9f75844SAndroid Build Coastguard Worker if (!isspace(headers[0])) {
233*d9f75844SAndroid Build Coastguard Worker static const char kContentLength[] = "Content-Length:";
234*d9f75844SAndroid Build Coastguard Worker static const char kContentType[] = "Content-Type:";
235*d9f75844SAndroid Build Coastguard Worker if ((headers + ARRAYSIZE(kContentLength)) < end &&
236*d9f75844SAndroid Build Coastguard Worker strncmp(headers, kContentLength, ARRAYSIZE(kContentLength) - 1) ==
237*d9f75844SAndroid Build Coastguard Worker 0) {
238*d9f75844SAndroid Build Coastguard Worker headers += ARRAYSIZE(kContentLength) - 1;
239*d9f75844SAndroid Build Coastguard Worker while (headers[0] == ' ')
240*d9f75844SAndroid Build Coastguard Worker ++headers;
241*d9f75844SAndroid Build Coastguard Worker content_length_ = atoi(headers);
242*d9f75844SAndroid Build Coastguard Worker } else if ((headers + ARRAYSIZE(kContentType)) < end &&
243*d9f75844SAndroid Build Coastguard Worker strncmp(headers, kContentType, ARRAYSIZE(kContentType) - 1) ==
244*d9f75844SAndroid Build Coastguard Worker 0) {
245*d9f75844SAndroid Build Coastguard Worker headers += ARRAYSIZE(kContentType) - 1;
246*d9f75844SAndroid Build Coastguard Worker while (headers[0] == ' ')
247*d9f75844SAndroid Build Coastguard Worker ++headers;
248*d9f75844SAndroid Build Coastguard Worker const char* type_end = strstr(headers, "\r\n");
249*d9f75844SAndroid Build Coastguard Worker if (type_end == NULL)
250*d9f75844SAndroid Build Coastguard Worker type_end = end;
251*d9f75844SAndroid Build Coastguard Worker content_type_.assign(headers, type_end);
252*d9f75844SAndroid Build Coastguard Worker }
253*d9f75844SAndroid Build Coastguard Worker } else {
254*d9f75844SAndroid Build Coastguard Worker ++headers;
255*d9f75844SAndroid Build Coastguard Worker }
256*d9f75844SAndroid Build Coastguard Worker headers = strstr(headers, "\r\n");
257*d9f75844SAndroid Build Coastguard Worker if (headers)
258*d9f75844SAndroid Build Coastguard Worker headers += 2;
259*d9f75844SAndroid Build Coastguard Worker }
260*d9f75844SAndroid Build Coastguard Worker
261*d9f75844SAndroid Build Coastguard Worker return !content_type_.empty() && content_length_ != 0;
262*d9f75844SAndroid Build Coastguard Worker }
263*d9f75844SAndroid Build Coastguard Worker
264*d9f75844SAndroid Build Coastguard Worker //
265*d9f75844SAndroid Build Coastguard Worker // ListeningSocket
266*d9f75844SAndroid Build Coastguard Worker //
267*d9f75844SAndroid Build Coastguard Worker
Listen(unsigned short port)268*d9f75844SAndroid Build Coastguard Worker bool ListeningSocket::Listen(unsigned short port) {
269*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(valid());
270*d9f75844SAndroid Build Coastguard Worker int enabled = 1;
271*d9f75844SAndroid Build Coastguard Worker if (setsockopt(socket_, SOL_SOCKET, SO_REUSEADDR,
272*d9f75844SAndroid Build Coastguard Worker reinterpret_cast<const char*>(&enabled),
273*d9f75844SAndroid Build Coastguard Worker sizeof(enabled)) != 0) {
274*d9f75844SAndroid Build Coastguard Worker printf("setsockopt failed\n");
275*d9f75844SAndroid Build Coastguard Worker return false;
276*d9f75844SAndroid Build Coastguard Worker }
277*d9f75844SAndroid Build Coastguard Worker struct sockaddr_in addr = {0};
278*d9f75844SAndroid Build Coastguard Worker addr.sin_family = AF_INET;
279*d9f75844SAndroid Build Coastguard Worker addr.sin_addr.s_addr = htonl(INADDR_ANY);
280*d9f75844SAndroid Build Coastguard Worker addr.sin_port = htons(port);
281*d9f75844SAndroid Build Coastguard Worker if (bind(socket_, reinterpret_cast<const sockaddr*>(&addr), sizeof(addr)) ==
282*d9f75844SAndroid Build Coastguard Worker SOCKET_ERROR) {
283*d9f75844SAndroid Build Coastguard Worker printf("bind failed\n");
284*d9f75844SAndroid Build Coastguard Worker return false;
285*d9f75844SAndroid Build Coastguard Worker }
286*d9f75844SAndroid Build Coastguard Worker return listen(socket_, 5) != SOCKET_ERROR;
287*d9f75844SAndroid Build Coastguard Worker }
288*d9f75844SAndroid Build Coastguard Worker
Accept() const289*d9f75844SAndroid Build Coastguard Worker DataSocket* ListeningSocket::Accept() const {
290*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(valid());
291*d9f75844SAndroid Build Coastguard Worker struct sockaddr_in addr = {0};
292*d9f75844SAndroid Build Coastguard Worker socklen_t size = sizeof(addr);
293*d9f75844SAndroid Build Coastguard Worker NativeSocket client =
294*d9f75844SAndroid Build Coastguard Worker accept(socket_, reinterpret_cast<sockaddr*>(&addr), &size);
295*d9f75844SAndroid Build Coastguard Worker if (client == INVALID_SOCKET)
296*d9f75844SAndroid Build Coastguard Worker return NULL;
297*d9f75844SAndroid Build Coastguard Worker
298*d9f75844SAndroid Build Coastguard Worker return new DataSocket(client);
299*d9f75844SAndroid Build Coastguard Worker }
300