00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #ifndef QOLYESTER_SYS_UNIXSOCKET_HXX
00020 # define QOLYESTER_SYS_UNIXSOCKET_HXX 1
00021
00022 # include "unixsocket.hh"
00023
00024 # include <sys/socket.h>
00025 # include <sstream>
00026
00027 # include "cst/constants.hh"
00028 # include "utl/exception.hh"
00029
00030 namespace olsr {
00031
00032 namespace sys {
00033
00034 UnixSocket::UnixSocket(_dummy_values)
00035 : _fd(-1),
00036 _bound(false)
00037 {}
00038
00039 UnixSocket::UnixSocket() {
00040 init();
00041 }
00042
00043 UnixSocket::UnixSocket(int fd)
00044 : _fd(fd),
00045 _bound(false)
00046 {}
00047
00048 UnixSocket::UnixSocket(const path_t& fname) {
00049 init();
00050 bind(fname);
00051 }
00052
00053 UnixSocket::~UnixSocket() {
00054 }
00055
00056 void
00057 UnixSocket::bind(const path_t& fname) {
00058 assert(fname.length() < UNIX_PATH_MAX);
00059 sockaddr_t sun;
00060 sun.sun_family = AF_FILE;
00061 ::strncpy(sun.sun_path, fname.c_str(), UNIX_PATH_MAX);
00062 sun.sun_path[UNIX_PATH_MAX - 1] = 0;
00063
00064 if (::bind(_fd, (::sockaddr*) &sun, sizeof sun) < 0) {
00065 std::stringstream msg;
00066 msg << "bind(\""
00067 << fname << "\"): "
00068 << strerror(errno);
00069 throw errnoexcept_t(msg.str(), errno);
00070 }
00071 _bound = true;
00072 }
00073
00074 void
00075 UnixSocket::listen() {
00076 if (::listen(_fd, UNIX_BACKLOG) < 0)
00077 throw errnoexcept_t(std::string("listen(): ") + strerror(errno),
00078 errno);
00079 }
00080
00081 UnixSocket
00082 UnixSocket::accept(path_t& fname) {
00083 ::sockaddr_un sun;
00084 sun.sun_family = AF_UNIX;
00085 sun.sun_path[0] = 0;
00086 socklen_t len = sizeof sun;
00087 int fd = ::accept(_fd, (::sockaddr*) &sun, &len);
00088 if (fd < 0)
00089 throw errnoexcept_t(std::string("accept(): ") + strerror(errno),
00090 errno);
00091 fname = sun.sun_path;
00092 return This(fd);
00093 }
00094
00095 void
00096 UnixSocket::connect(const path_t& fname) {
00097 assert(fname.length() < UNIX_PATH_MAX);
00098 sockaddr_t sun;
00099
00100 sun.sun_family = AF_UNIX;
00101 ::strncpy(sun.sun_path, fname.c_str(), UNIX_PATH_MAX);
00102 sun.sun_path[UNIX_PATH_MAX - 1] = 0;
00103
00104 if (::connect(_fd, (::sockaddr*) &sun, sizeof sun) < 0) {
00105 std::stringstream msg;
00106 msg << "connect(\""
00107 << fname << "\"): "
00108 << strerror(errno);
00109 throw errnoexcept_t(msg.str(), errno);
00110 }
00111 }
00112
00113 void
00114 UnixSocket::close() {
00115 if (_fd >= 0 && !_locked) {
00116 sockaddr_t sun;
00117 socklen_t sun_len = sizeof sun;
00118 if (_bound)
00119 if (getsockname(_fd, (sockaddr*) &sun, &sun_len) < 0)
00120 throw std::runtime_error(std::string("getsockname() failed: ") +
00121 strerror(errno));
00122 if (::close(_fd) < 0)
00123 throw std::runtime_error(std::string("close() failed: ") +
00124 strerror(errno));
00125 if (_bound && sun_len > sizeof sun.sun_family) {
00126 assert(sun.sun_path[0] != 0);
00127 if (unlink(sun.sun_path) < 0)
00128 throw std::runtime_error(std::string("unlink(\"") +
00129 sun.sun_path + "\") failed: " +
00130 strerror(errno));
00131 }
00132 _bound = false;
00133 _fd = -1;
00134 }
00135 }
00136
00137 utl::Data
00138 UnixSocket::receive() const {
00139 utl::Data data(VIRTUAL_MTU);
00140 int len;
00141
00142 if ((len = ::recv(_fd, data.raw(), data.size(), 0)) < 0)
00143 throw errnoexcept_t(std::string("recv(): ") + strerror(errno),
00144 errno);
00145
00146 if (len == 0)
00147 throw UnixClosedConnection();
00148
00149 return data.shrink_to(len);
00150 }
00151
00152 bool
00153 UnixSocket::send(const utl::ConstData& d, int flags) const {
00154 if (::send(_fd, d.raw(), d.size(), flags) < 0) {
00155 if (errno == EPIPE)
00156 throw UnixClosedConnection();
00157 if (errno == EAGAIN && flags & MSG_DONTWAIT)
00158 return false;
00159 throw errnoexcept_t(std::string("send(): ") + strerror(errno), errno);
00160 }
00161 return true;
00162 }
00163
00164 bool
00165 UnixSocket::operator<(const This& rhs) const { return _fd < rhs._fd; }
00166
00167 sch::IOEvent::p_t
00168 UnixSocket::read_p() const {
00169 return sch::IOEvent::p_t(_fd, POLLIN);
00170 }
00171
00172 sch::IOEvent::p_t
00173 UnixSocket::write_p() const {
00174 return sch::IOEvent::p_t(_fd, POLLOUT);
00175 }
00176
00177 void
00178 UnixSocket::init() {
00179 if ((_fd = ::socket(PF_UNIX, SOCK_SEQPACKET, 0)) < 0)
00180 throw errnoexcept_t(std::string("socket(PF_UNIX, SOCK_SEQPACKET, 0): ") +
00181 strerror(errno), errno);
00182 _bound = false;
00183 }
00184
00185 }
00186
00187 }
00188
00189 #endif // ! QOLYESTER_SYS_UNIXSOCKET_HXX