⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 datagram.cxx

📁 这是国外的resip协议栈
💻 CXX
字号:
/* * Copyright (C) 2001-2003 Peter J Jones (pjones@pmade.org) * All Rights Reserved *  * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: *  * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * 2. 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. * 3. Neither the name of the Author 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 AUTHOR 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 AUTHOR * 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. *//** @file * This file contains the implementation of the Netxx::Datagram class.**/// common header#include "common.h"// Netxx includes#include "Netxx/Datagram.h"#include "Netxx/Address.h"#include "Netxx/Peer.h"#include "Socket.h"#include "SockAddr.h"#include "RecvFrom.h"#include "OSError.h"// system includes#if defined (WIN32)# include <winsock2.h>#else# include <sys/types.h># include <sys/socket.h># include <sys/un.h># include <errno.h># include <stdio.h># include <unistd.h># include <sys/stat.h>#endif// standard includes#include <string>#include <memory>#include <cstring>#include <vector>namespace {    void call_connect(Netxx::Socket &socket, const Netxx::Peer &peer, std::vector<std::string> &files);    void call_bind(Netxx::Socket &socket, std::vector<std::string> &files);    void get_tmp_filename (std::string &tmp_name);}//####################################################################struct Netxx::Datagram::pimpl {    pimpl (const Timeout &timeout) : timeout_(timeout) {}    pimpl (const Timeout &timeout, socket_type socketfd) : timeout_(timeout), socket_(socketfd) {}    ~pimpl (void) {#   ifndef WIN32	if (!files_.empty()) {	    socket_.close();	    std::vector<std::string>::const_iterator i(files_.begin()), end(files_.end());	    for (; i!=end; ++i) unlink(i->c_str());	}#   endif    }    Timeout timeout_;    Socket socket_;    ProbeInfo pi_;    std::vector<std::string> files_;};//####################################################################Netxx::Datagram::Datagram (const Address &connect_to, const Timeout &timeout) {    if (!connect_to.size()) throw Exception("no addresses to call connect for");    std::auto_ptr<pimpl> ap(pimpl_ = new pimpl(timeout));    call_connect(pimpl_->socket_, *connect_to.begin(), pimpl_->files_);    pimpl_->pi_.add_socket(pimpl_->socket_.get_socketfd());    ap.release();}//####################################################################Netxx::Datagram::Datagram (const char *peer_name, port_type default_port, const Timeout &timeout) {    Address connect_to(peer_name, default_port);    std::auto_ptr<pimpl> ap(pimpl_ = new pimpl(timeout));    call_connect(pimpl_->socket_, *connect_to.begin(), pimpl_->files_);    pimpl_->pi_.add_socket(pimpl_->socket_.get_socketfd());    ap.release();}//####################################################################Netxx::Datagram::Datagram (socket_type socketfd, const Timeout &timeout) {    std::auto_ptr<pimpl> ap (pimpl_ = new pimpl(timeout, socketfd));    pimpl_->pi_.add_socket(pimpl_->socket_.get_socketfd());    ap.release();}//####################################################################Netxx::Datagram::Datagram (const Timeout &timeout) {    std::auto_ptr<pimpl> ap (pimpl_ = new pimpl(timeout));    pimpl_->pi_.add_socket(pimpl_->socket_.get_socketfd());    ap.release();}//####################################################################Netxx::Datagram::~Datagram (void) {    delete pimpl_;}//####################################################################Netxx::signed_size_type Netxx::Datagram::send (const Peer &peer, const void *buffer, size_type length) {#   if defined(WIN32)	const char *buffer_ptr = static_cast<const char*>(buffer);#   else	const void *buffer_ptr = buffer;#   endif    const sockaddr *sa = reinterpret_cast<const sockaddr*>(peer.get_sa());    size_type sa_size = peer.get_sa_size();    bool correct_type = false;    /*     * make sure our socket is setup to handle this type of peer     */    if (peer.get_socketfd() != -1 && peer.get_socketfd() == pimpl_->socket_.get_socketfd()) {	// we have to be ready!	correct_type = true;    } else if (pimpl_->socket_.get_socketfd() >= 0) {	Socket::Type stype = pimpl_->socket_.get_type();	switch (stype) {#   ifndef WIN32	    case Socket::LOCALDGRAM:		correct_type = sa->sa_family == AF_LOCAL;		break;#   endif	    case Socket::UDP:		correct_type = sa->sa_family == AF_INET;		break;#   ifndef NETXX_NO_INET6	    case Socket::UDP6:		correct_type = sa->sa_family == AF_INET6;		break;#   endif	    default:		break;	}    }    if (!correct_type) {	Socket::Type stype;	switch (sa->sa_family) {	    case AF_INET:		stype = Socket::UDP;		break;#   ifndef NETXX_NO_INET6	    case AF_INET6:		stype = Socket::UDP6;		break;#   endif#   ifndef WIN32	    case AF_LOCAL:		stype = Socket::LOCALDGRAM;		break;#   endif	    default:		stype = Socket::UDP;	}	Socket tmp_socket(stype);	pimpl_->socket_.swap(tmp_socket);	call_bind(pimpl_->socket_, pimpl_->files_);    }    if (pimpl_->timeout_ && !pimpl_->socket_.writable(pimpl_->timeout_))	return -1;    signed_size_type rc;    if ( (rc = sendto(pimpl_->socket_.get_socketfd(), buffer_ptr, length, 0, sa, sa_size)) < 0) {	std::string error("sendto(2) failure: ");	error += strerror(get_last_error());	throw Exception(error);    }    return rc;}//####################################################################Netxx::Datagram::receive_type Netxx::Datagram::receive (void *buffer, size_type length) {    /*     * if this is not a connected datagram, the socket might not be ready     * yet. We can't receive a datagram because we don't know if it should     * be a AF_INET, AF_INET6 or even a AF_LOCAL datagram.     */    if (pimpl_->socket_.get_socketfd() < 0)	throw Exception("can't receive datagram unless one is sent first");    if (pimpl_->timeout_ && !pimpl_->socket_.readable(pimpl_->timeout_))	return std::make_pair(-1, Peer());    return call_recvfrom(pimpl_->socket_, buffer, length);}//####################################################################Netxx::signed_size_type Netxx::Datagram::write (const void *buffer, size_type length) {    return pimpl_->socket_.write(buffer, length, pimpl_->timeout_);}//####################################################################Netxx::signed_size_type Netxx::Datagram::read (void *buffer, size_type length) {    return pimpl_->socket_.read(buffer, length, pimpl_->timeout_);}//####################################################################void Netxx::Datagram::close (void) {    pimpl_->socket_.close();    pimpl_->pi_.clear();}//####################################################################void Netxx::Datagram::release (void) {    pimpl_->socket_.release();}//####################################################################const Netxx::ProbeInfo* Netxx::Datagram::get_probe_info (void) const {    return &(pimpl_->pi_);}//####################################################################namespace {    //####################################################################    void call_connect (Netxx::Socket &socket, const Netxx::Peer &peer, std::vector<std::string> &files) {	const sockaddr *sa = reinterpret_cast<const sockaddr*>(peer.get_sa());	Netxx::size_type sa_size = peer.get_sa_size();	Netxx::Socket::Type stype;	switch (sa->sa_family) {	    case AF_INET:		stype = Netxx::Socket::UDP;		break;# ifndef NETXX_NO_INET6	    case AF_INET6:		stype = Netxx::Socket::UDP6;		break;# endif# ifndef WIN32	    case AF_LOCAL:		stype = Netxx::Socket::LOCALDGRAM;		break;# endif	    default:		stype = Netxx::Socket::UDP;	}	Netxx::Socket tmp_socket(stype);	socket.swap(tmp_socket);	call_bind(socket, files);	if (connect(socket.get_socketfd(), sa, sa_size) != 0) {	    std::string error("connect(2) failed: ");	    error += strerror(Netxx::get_last_error());	    throw Netxx::Exception(error);	}    }    //####################################################################    void call_bind (Netxx::Socket &socket, std::vector<std::string> &files) {#	ifndef WIN32	    if (socket.get_type() == Netxx::Socket::LOCALDGRAM) {		Netxx::SockAddr socket_addr(socket.get_type());		sockaddr_un *saun = reinterpret_cast<sockaddr_un*>(socket_addr.get_sa());		Netxx::size_type saun_size = socket_addr.get_sa_size();		std::string tmp_name;		get_tmp_filename(tmp_name);		files.push_back(tmp_name);		if (tmp_name.size() >= sizeof(saun->sun_path))		    throw Netxx::Exception("temp name is too large for sockaddr_un");		std::strcpy(saun->sun_path, tmp_name.c_str());				if (bind(socket.get_socketfd(), reinterpret_cast<sockaddr*>(saun), saun_size) != 0) {		    std::string error("bind(2) error: ");		    error += strerror(Netxx::get_last_error());		    throw Netxx::Exception(error);		}		/*		 * This will make a local domain socket more like a real		 * socket since anyone with local file system access can		 * connect to it. This may be a bad thing in this case		 * though. More to come.		 */		chmod(saun->sun_path, 0666);	    }#	endif    }    //####################################################################    void get_tmp_filename (std::string &tmp_name) {#	ifndef WIN32	    char buffer[] = "/tmp/Netxx_Domain_Socket.XXXXXXXXXXXXXXXXX";	    int fd;	    if ( (fd = mkstemp(buffer)) < 0) {		std::string error("can't create temporary file: ");		error += strerror(Netxx::get_last_error());		throw Netxx::Exception(error);	    }	    /*	     * WARNING WARNING WARNING WARNING	     *	     * The following action could create a race condition.  It may	     * not be that big of a deal in this case since when we call	     * bind(2) and it will fail if the file in sun_path already	     * exists. 	     *	     * So, if we close and unlink the file, and then before we call	     * bind(2) someone creates a file with the same name, bind	     * should fail.	     *	     * It might just be better to use tmpnam(3) but then you have to	     * see the linker warning about tmpnam might be used in an	     * unsafe manner. I think what we have here should be good	     * enough.	     *	     * WARNING WARNING WARNING WARNING	     */	    close(fd);	    unlink(buffer);	    tmp_name = buffer;#	endif    }    //####################################################################} // end anonymous namespace

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -