e193098543
This patch avoids unnecessary use of the <cfoo> headers in files that don't actually use the identifiers they declare in the std:: namespace. It also changes some files to better conform with the "Names and Order of Includes" rules in the Google C++ Style Guide. A=jimb R=mark git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@619 4c0a9323-5329-0410-9bdc-e9ce6186880e
187 lines
6 KiB
C++
187 lines
6 KiB
C++
// Copyright (c) 2010, Google Inc.
|
|
// All rights reserved.
|
|
//
|
|
// Redistribution and use in source and binary forms, with or without
|
|
// modification, are permitted provided that the following conditions are
|
|
// met:
|
|
//
|
|
// * Redistributions of source code must retain the above copyright
|
|
// notice, this list of conditions and the following disclaimer.
|
|
// * Redistributions in binary form must reproduce the above
|
|
// copyright notice, this list of conditions and the following disclaimer
|
|
// in the documentation and/or other materials provided with the
|
|
// distribution.
|
|
// * Neither the name of Google Inc. nor the names of its
|
|
// contributors may be used to endorse or promote products derived from
|
|
// this software without specific prior written permission.
|
|
//
|
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include "processor/udp_network.h"
|
|
|
|
#include <arpa/inet.h>
|
|
#include <errno.h>
|
|
#include <netdb.h>
|
|
#include <netinet/in.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <sys/socket.h>
|
|
|
|
#include <string>
|
|
|
|
#include "processor/logging.h"
|
|
|
|
namespace google_breakpad {
|
|
using std::string;
|
|
using std::dec;
|
|
|
|
UDPNetwork::~UDPNetwork() {
|
|
if (socket_ != -1) {
|
|
close(socket_);
|
|
socket_ = -1;
|
|
}
|
|
}
|
|
|
|
bool UDPNetwork::Init(bool listen) {
|
|
struct addrinfo hints;
|
|
struct addrinfo *results;
|
|
memset(&hints, 0, sizeof(hints));
|
|
if (ip4only_)
|
|
hints.ai_family = AF_INET;
|
|
else
|
|
// don't care if it's IPv4 or IPv6
|
|
hints.ai_family = AF_UNSPEC;
|
|
// want a UDP socket
|
|
hints.ai_socktype = SOCK_DGRAM;
|
|
if (listen)
|
|
hints.ai_flags = AI_PASSIVE;
|
|
|
|
const char *hostname = NULL;
|
|
if (!server_.empty())
|
|
hostname = server_.c_str();
|
|
char portname[6];
|
|
sprintf(portname, "%u", port_);
|
|
if (!listen) {
|
|
BPLOG(INFO) << "Initializing network connection to " << server_
|
|
<< ":" << dec << port_;
|
|
}
|
|
if (getaddrinfo(hostname, portname, &hints, &results) != 0) {
|
|
BPLOG(ERROR) << "failed to get address info for address " << server_
|
|
<< ": " << strerror(errno);
|
|
return false;
|
|
}
|
|
// save the address of the first result.
|
|
//TODO(ted): could support multiple DNS entries, round-robin them for
|
|
// fail-over etc
|
|
memcpy(&address_, results->ai_addr, GET_SA_LEN(results->ai_addr));
|
|
|
|
socket_ = socket(results->ai_family, results->ai_socktype,
|
|
results->ai_protocol);
|
|
freeaddrinfo(results);
|
|
|
|
if (socket_ == -1) {
|
|
BPLOG(ERROR) << "failed to create socket: " << strerror(errno);
|
|
return false;
|
|
}
|
|
|
|
if (listen) {
|
|
char address_string[INET_ADDRSTRLEN];
|
|
void *addr = NULL;
|
|
if (((struct sockaddr*)&address_)->sa_family == AF_INET)
|
|
addr = &((struct sockaddr_in*)&address_)->sin_addr;
|
|
else if (((struct sockaddr*)&address_)->sa_family == AF_INET6)
|
|
addr = &((struct sockaddr_in6*)&address_)->sin6_addr;
|
|
if (inet_ntop(((struct sockaddr*)&address_)->sa_family, addr,
|
|
address_string, sizeof(address_string)) != NULL)
|
|
BPLOG(INFO) << "Listening on address " << address_string;
|
|
|
|
if (bind(socket_,
|
|
(struct sockaddr *)&address_,
|
|
GET_SA_LEN(address_)) == -1) {
|
|
BPLOG(ERROR) << "Failed to bind socket";
|
|
close(socket_);
|
|
return false;
|
|
}
|
|
socklen_t bound_addr_len = GET_SA_LEN(address_);
|
|
if (getsockname(socket_, (struct sockaddr *)&address_, &bound_addr_len)
|
|
== 0) {
|
|
if (((struct sockaddr*)&address_)->sa_family == AF_INET)
|
|
port_ = ntohs(((struct sockaddr_in*)&address_)->sin_port);
|
|
else if (((struct sockaddr*)&address_)->sa_family == AF_INET6)
|
|
port_ = ntohs(((struct sockaddr_in6*)&address_)->sin6_port);
|
|
}
|
|
BPLOG(INFO) << "Listening on port " << port_;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool UDPNetwork::Send(const char *data, size_t length) {
|
|
int total_sent = 0;
|
|
while (total_sent < length) {
|
|
int bytes_sent = sendto(socket_,
|
|
data + total_sent,
|
|
length - total_sent,
|
|
0,
|
|
(struct sockaddr *)&address_,
|
|
GET_SA_LEN(address_));
|
|
if (bytes_sent < 0) {
|
|
BPLOG(ERROR) << "error sending message: "
|
|
<< strerror(errno) << " (" << errno << ")";
|
|
break;
|
|
}
|
|
total_sent += bytes_sent;
|
|
}
|
|
return total_sent == length;
|
|
}
|
|
|
|
bool UDPNetwork::WaitToReceive(int wait_time) {
|
|
fd_set readfds;
|
|
FD_ZERO(&readfds);
|
|
FD_SET(socket_, &readfds);
|
|
struct timeval timeout;
|
|
|
|
timeout.tv_sec = wait_time / 1000;
|
|
timeout.tv_usec = (wait_time % 1000) * 1000;
|
|
int ret = select(socket_+1, &readfds, NULL, NULL, &timeout);
|
|
if (ret == 0) {
|
|
return false;
|
|
} else if (ret == -1) {
|
|
if (errno != EINTR)
|
|
BPLOG(ERROR) << "error in select(): " << strerror(errno);
|
|
return false;
|
|
} else if (!FD_ISSET(socket_, &readfds)) {
|
|
BPLOG(ERROR) << "select returned, but our socket isn't ready?";
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool UDPNetwork::Receive(char *buffer, size_t buffer_size, ssize_t &received) {
|
|
socklen_t fromlen = GET_SA_LEN(address_);
|
|
received = recvfrom(socket_, buffer, buffer_size, 0,
|
|
(struct sockaddr *)&address_,
|
|
&fromlen);
|
|
|
|
if (received == -1) {
|
|
BPLOG(ERROR) << "Error in recvfrom reading response: "
|
|
<< strerror(errno);
|
|
}
|
|
return received != -1;
|
|
}
|
|
|
|
} // namespace google_breakpad
|