Repository: qpid-proton Updated Branches: refs/heads/master c63b2bea6 -> 38a71ffe5
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/222574ed/proton-c/bindings/cpp/src/io/windows/socket.cpp ---------------------------------------------------------------------- diff --git a/proton-c/bindings/cpp/src/io/windows/socket.cpp b/proton-c/bindings/cpp/src/io/windows/socket.cpp new file mode 100644 index 0000000..afd3b56 --- /dev/null +++ b/proton-c/bindings/cpp/src/io/windows/socket.cpp @@ -0,0 +1,217 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "msg.hpp" + +#include <proton/io/socket.hpp> +#include <proton/url.hpp> + +#define FD_SETSIZE 2048 +#ifndef _WIN32_WINNT +#define _WIN32_WINNT 0x0501 +#endif +#if _WIN32_WINNT < 0x0501 +#error "Proton requires Windows API support for XP or later." +#endif +#include <winsock2.h> +#include <mswsock.h> +#include <Ws2tcpip.h> + +#include <ctype.h> +#include <errno.h> +#include <stdio.h> +#include <assert.h> + +namespace proton { +namespace io { +namespace socket { + +const descriptor INVALID_DESCRIPTOR = INVALID_SOCKET; + +std::string error_str() { + HRESULT code = WSAGetLastError(); + char err[1024] = {0}; + FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | + FORMAT_MESSAGE_MAX_WIDTH_MASK, NULL, code, 0, (LPSTR)&err, sizeof(err), NULL); + return err; +} + +io_error::io_error(const std::string& s) : error(s) {} + +namespace { + +template <class T> T check(T result, const std::string& msg=std::string()) { + if (result == SOCKET_ERROR) + throw io_error(msg + error_str()); + return result; +} + +void gai_check(int result, const std::string& msg="") { + if (result) + throw io_error(msg + gai_strerror(result)); +} + +} // namespace + +void initialize() { + WSADATA unused; + check(WSAStartup(0x0202, &unused), "can't load WinSock: "); // Version 2.2 +} + +void finalize() { + WSACleanup(); +} + +void engine::init() { + u_long nonblock = 1; + check(::ioctlsocket(socket_, FIONBIO, &nonblock), "ioctlsocket: "); +} + +engine::engine(descriptor fd, handler& h, const connection_options &opts) + : connection_engine(h, opts), socket_(fd) +{ + init(); +} + +engine::engine(const url& u, handler& h, const connection_options &opts) + : connection_engine(h, opts), socket_(connect(u)) +{ + init(); +} + +engine::~engine() {} + +void engine::read() { + mutable_buffer rbuf = read_buffer(); + if (rbuf.size > 0) { + int n = ::recv(socket_, rbuf.data, rbuf.size, 0); + if (n > 0) + read_done(n); + else if (n == 0) + read_close(); + else if (n == SOCKET_ERROR && WSAGetLastError() != WSAEWOULDBLOCK) + close("io_error", error_str()); + } +} + +void engine::write() { + const_buffer wbuf = write_buffer(); + if (wbuf.size > 0) { + int n = ::send(socket_, wbuf.data, wbuf.size, 0); + if (n > 0) + write_done(n); + else if (n == SOCKET_ERROR && WSAGetLastError() != WSAEWOULDBLOCK) + close("io_error", error_str()); + } +} + +void engine::run() { + while (dispatch()) { + fd_set rd, wr; + FD_ZERO(&rd); + if (read_buffer().size) + FD_SET(socket_, &rd); + FD_ZERO(&wr); + if (write_buffer().size) + FD_SET(socket_, &wr); + int n = ::select(FD_SETSIZE, &rd, &wr, NULL, NULL); + if (n < 0) { + close("io_error", error_str()); + break; + } + if (FD_ISSET(socket_, &rd)) { + read(); + } + if (FD_ISSET(socket_, &wr)) + write(); + } + ::closesocket(socket_); +} + +namespace { +struct auto_addrinfo { + struct addrinfo *ptr; + auto_addrinfo() : ptr(0) {} + ~auto_addrinfo() { ::freeaddrinfo(ptr); } + addrinfo* operator->() const { return ptr; } +}; + +static const char *amqp_service(const char *port) { + // Help older Windows to know about amqp[s] ports + if (port) { + if (!strcmp("amqp", port)) return "5672"; + if (!strcmp("amqps", port)) return "5671"; + } + return port; +} +} + + +descriptor connect(const proton::url& u) { + // convert "0.0.0.0" to "127.0.0.1" on Windows for outgoing sockets + std::string host = (u.host() == "0.0.0.0") ? "127.0.0.1" : u.host(); + descriptor fd = INVALID_SOCKET; + try{ + auto_addrinfo addr; + gai_check(::getaddrinfo(host.empty() ? 0 : host.c_str(), + amqp_service(u.port().empty() ? 0 : u.port().c_str()), + 0, &addr.ptr), + "connect address invalid: "); + fd = check(::socket(addr->ai_family, SOCK_STREAM, 0), "connect socket: "); + check(::connect(fd, addr->ai_addr, addr->ai_addrlen), "connect: "); + return fd; + } catch (...) { + if (fd != INVALID_SOCKET) ::closesocket(fd); + throw; + } +} + +listener::listener(const std::string& host, const std::string &port) : socket_(INVALID_SOCKET) { + try { + auto_addrinfo addr; + gai_check(::getaddrinfo(host.empty() ? 0 : host.c_str(), + port.empty() ? 0 : port.c_str(), 0, &addr.ptr), + "listener address invalid: "); + socket_ = check(::socket(addr->ai_family, SOCK_STREAM, 0), "listener socket: "); + bool yes = true; + check(setsockopt(socket_, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (const char*)&yes, sizeof(yes)), "setsockopt: "); + check(::bind(socket_, addr->ai_addr, addr->ai_addrlen), "listener bind: "); + check(::listen(socket_, 32), "listener listen: "); + } catch (...) { + if (socket_ != INVALID_SOCKET) ::closesocket(socket_); + throw; + } +} + +listener::~listener() { ::closesocket(socket_); } + +descriptor listener::accept(std::string& host_str, std::string& port_str) { + struct sockaddr_storage addr; + socklen_t size = sizeof(addr); + int fd = check(::accept(socket_, (struct sockaddr *)&addr, &size), "accept: "); + char host[NI_MAXHOST], port[NI_MAXSERV]; + gai_check(getnameinfo((struct sockaddr *) &addr, sizeof(addr), + host, sizeof(host), port, sizeof(port), 0), + "accept invalid remote address: "); + host_str = host; + port_str = port; + return fd; +} + +}}} http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/222574ed/proton-c/bindings/cpp/src/posix/io.cpp ---------------------------------------------------------------------- diff --git a/proton-c/bindings/cpp/src/posix/io.cpp b/proton-c/bindings/cpp/src/posix/io.cpp deleted file mode 100644 index be9db44..0000000 --- a/proton-c/bindings/cpp/src/posix/io.cpp +++ /dev/null @@ -1,175 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#include "msg.hpp" - -#include <proton/io.hpp> -#include <proton/url.hpp> - -#include <errno.h> -#include <string.h> -#include <fcntl.h> -#include <netdb.h> -#include <sys/socket.h> -#include <sys/types.h> -#include <unistd.h> - -namespace proton { -namespace io { - -const descriptor INVALID_DESCRIPTOR = -1; - -std::string error_str() { - char buf[512] = "Unknown error"; -#ifdef _GNU_SOURCE - // GNU strerror_r returns the message - return ::strerror_r(errno, buf, sizeof(buf)); -#else - // POSIX strerror_r doesn't return the buffer - ::strerror_r(errno, buf, sizeof(buf)); - return std::string(buf) -#endif -} - -namespace { - -template <class T> T check(T result, const std::string& msg=std::string()) { - if (result < 0) throw connection_engine::io_error(msg + error_str()); - return result; -} - -void gai_check(int result, const std::string& msg="") { - if (result) throw connection_engine::io_error(msg + gai_strerror(result)); -} - -} - -void socket_engine::init() { - check(fcntl(socket_, F_SETFL, fcntl(socket_, F_GETFL, 0) | O_NONBLOCK), "set nonblock: "); -} - -socket_engine::socket_engine(descriptor fd, handler& h, const connection_options &opts) - : connection_engine(h, opts), socket_(fd) -{ - init(); -} - -socket_engine::socket_engine(const url& u, handler& h, const connection_options& opts) - : connection_engine(h, opts), socket_(connect(u)) -{ - init(); -} - -socket_engine::~socket_engine() {} - -std::pair<size_t, bool> socket_engine::io_read(char *buf, size_t size) { - ssize_t n = ::read(socket_, buf, size); - if (n > 0) return std::make_pair(n, true); - if (n == 0) return std::make_pair(0, false); - if (errno == EAGAIN || errno == EWOULDBLOCK) - return std::make_pair(0, true); - throw io_error("read: " + error_str()); -} - -size_t socket_engine::io_write(const char *buf, size_t size) { - ssize_t n = ::write(socket_, buf, size); - if (n == EAGAIN || n == EWOULDBLOCK) return 0; - if (n < 0) check(n, "write: "); - return n; -} - -void socket_engine::io_close() { ::close(socket_); } - -void socket_engine::run() { - fd_set self; - FD_ZERO(&self); - FD_SET(socket_, &self); - while (!closed()) { - process(); - if (!closed()) { - int n = select(FD_SETSIZE, - can_read() ? &self : NULL, - can_write() ? &self : NULL, - NULL, NULL); - check(n, "select: "); - } - } -} - -namespace { -struct auto_addrinfo { - struct addrinfo *ptr; - auto_addrinfo() : ptr(0) {} - ~auto_addrinfo() { ::freeaddrinfo(ptr); } - addrinfo* operator->() const { return ptr; } -}; -} - -descriptor connect(const proton::url& u) { - descriptor fd = INVALID_DESCRIPTOR; - try{ - auto_addrinfo addr; - gai_check(::getaddrinfo(u.host().empty() ? 0 : u.host().c_str(), - u.port().empty() ? 0 : u.port().c_str(), - 0, &addr.ptr), u.str()+": "); - fd = check(::socket(addr->ai_family, SOCK_STREAM, 0), "connect: "); - check(::connect(fd, addr->ai_addr, addr->ai_addrlen), "connect: "); - return fd; - } catch (...) { - if (fd >= 0) close(fd); - throw; - } -} - -listener::listener(const std::string& host, const std::string &port) : socket_(INVALID_DESCRIPTOR) { - try { - auto_addrinfo addr; - gai_check(::getaddrinfo(host.empty() ? 0 : host.c_str(), - port.empty() ? 0 : port.c_str(), 0, &addr.ptr), - "listener address invalid: "); - socket_ = check(::socket(addr->ai_family, SOCK_STREAM, 0), "listen: "); - int yes = 1; - check(setsockopt(socket_, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)), "setsockopt: "); - check(::bind(socket_, addr->ai_addr, addr->ai_addrlen), "bind: "); - check(::listen(socket_, 32), "listen: "); - } catch (...) { - if (socket_ >= 0) close(socket_); - throw; - } -} - -listener::~listener() { ::close(socket_); } - -descriptor listener::accept(std::string& host_str, std::string& port_str) { - struct sockaddr_storage addr; - socklen_t size = sizeof(addr); - int fd = check(::accept(socket_, (struct sockaddr *)&addr, &size), "accept: "); - char host[NI_MAXHOST], port[NI_MAXSERV]; - gai_check(getnameinfo((struct sockaddr *) &addr, sizeof(addr), - host, sizeof(host), port, sizeof(port), 0), - "accept invalid remote address: "); - host_str = host; - port_str = port; - return fd; -} - -// Empty stubs, only needed on windows. -void initialize() {} -void finalize() {} -}} http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/222574ed/proton-c/bindings/cpp/src/scalar_test.cpp ---------------------------------------------------------------------- diff --git a/proton-c/bindings/cpp/src/scalar_test.cpp b/proton-c/bindings/cpp/src/scalar_test.cpp index b5955d5..cd00d31 100644 --- a/proton-c/bindings/cpp/src/scalar_test.cpp +++ b/proton-c/bindings/cpp/src/scalar_test.cpp @@ -62,7 +62,6 @@ template <class T> void type_test(T x, type_id tid, T y) { FAIL("expected conversion_error: " #EXPR); \ } catch (const conversion_error& e) {} -// FIXME aconway 2016-03-15: new coerce stuff. void coerce_test() { scalar a; ASSERT_EQUAL(NULL_TYPE, a.type()); http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/222574ed/proton-c/bindings/cpp/src/test_bits.hpp ---------------------------------------------------------------------- diff --git a/proton-c/bindings/cpp/src/test_bits.hpp b/proton-c/bindings/cpp/src/test_bits.hpp index 38cd7a8..18298cb 100644 --- a/proton-c/bindings/cpp/src/test_bits.hpp +++ b/proton-c/bindings/cpp/src/test_bits.hpp @@ -30,18 +30,29 @@ namespace test { -struct fail : public std::logic_error { fail(const std::string& what) : logic_error(what) {} }; +struct fail : public std::logic_error { + fail(const std::string& what) : logic_error(what) {} +}; + +template <class T, class U> +void assert_equal(const T& want, const U& got, const std::string& what) { + if (!(want == got)) + throw fail(MSG(what << " " << want << " != " << got)); +} -bool close(double want, double got, double delta) { - return fabs(want-got) <= delta; +void assert_equalish(double want, double got, double delta, const std::string& what) +{ + if (!(fabs(want-got) <= delta)) + throw fail(MSG(what << " " << want << " !=~ " << got)); } -#define FAIL(WHAT) throw fail(MSG(__FILE__ << ":" << __LINE__ << ": " << WHAT)) -#define ASSERT(TEST) do { if (!(TEST)) FAIL("assert failed: " << #TEST); } while(false) -#define ASSERT_EQUAL(WANT, GOT) if (!((WANT) == (GOT))) \ - FAIL(#WANT << " != " << #GOT << ": " << (WANT) << " != " << (GOT)) -#define ASSERT_CLOSE(WANT, GOT, DELTA) if (!close((WANT), (GOT), (DELTA))) \ - FAIL(#WANT << " != " << #GOT << ": " << (WANT) << " != " << (GOT)) +#define FAIL_MSG(WHAT) (MSG(__FILE__ << ":" << __LINE__ << ": " << WHAT).str()) +#define FAIL(WHAT) throw fail(FAIL_MSG(WHAT)) +#define ASSERT(TEST) do { if (!(TEST)) FAIL("failed ASSERT(" #TEST ")"); } while(false) +#define ASSERT_EQUAL(WANT, GOT) \ + assert_equal((WANT), (GOT), FAIL_MSG("failed ASSERT_EQUAL(" #WANT ", " #GOT ")")) +#define ASSERT_EQUALISH(WANT, GOT, DELTA) \ + assert_equalish((WANT), (GOT), (DELTA), FAIL_MSG("failed ASSERT_EQUALISH(" #WANT ", " #GOT ")")) #define RUN_TEST(BAD_COUNT, TEST) \ do { \ http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/222574ed/proton-c/bindings/cpp/src/value_test.cpp ---------------------------------------------------------------------- diff --git a/proton-c/bindings/cpp/src/value_test.cpp b/proton-c/bindings/cpp/src/value_test.cpp index d636ffa..7b4940a 100644 --- a/proton-c/bindings/cpp/src/value_test.cpp +++ b/proton-c/bindings/cpp/src/value_test.cpp @@ -132,8 +132,8 @@ void get_coerce_test() { ASSERT_EQUAL(4, coerce<uint64_t>(value(uint32_t(4)))); ASSERT_EQUAL(-4, coerce<int64_t>(value(int32_t(-4)))); - ASSERT_CLOSE(1.2, coerce<float>(value(double(1.2))), 0.001); - ASSERT_CLOSE(3.4, coerce<double>(value(float(3.4))), 0.001); + ASSERT_EQUALISH(1.2, coerce<float>(value(double(1.2))), 0.001); + ASSERT_EQUALISH(3.4, coerce<double>(value(float(3.4))), 0.001); ASSERT_EQUAL(std::string("foo"), coerce<std::string>(value(symbol("foo")))); http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/222574ed/proton-c/bindings/cpp/src/windows/io.cpp ---------------------------------------------------------------------- diff --git a/proton-c/bindings/cpp/src/windows/io.cpp b/proton-c/bindings/cpp/src/windows/io.cpp deleted file mode 100644 index 52f5fc0..0000000 --- a/proton-c/bindings/cpp/src/windows/io.cpp +++ /dev/null @@ -1,197 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#include "msg.hpp" -#include <proton/io.hpp> -#include <proton/url.hpp> - -#define FD_SETSIZE 2048 -#ifndef _WIN32_WINNT -#define _WIN32_WINNT 0x0501 -#endif -#if _WIN32_WINNT < 0x0501 -#error "Proton requires Windows API support for XP or later." -#endif -#include <winsock2.h> -#include <mswsock.h> -#include <Ws2tcpip.h> - -#include <ctype.h> -#include <errno.h> -#include <stdio.h> -#include <assert.h> - -namespace proton { -namespace io { - -const descriptor INVALID_DESCRIPTOR = INVALID_SOCKET; - -std::string error_str() { - HRESULT code = WSAGetLastError(); - char err[1024] = {0}; - FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | - FORMAT_MESSAGE_MAX_WIDTH_MASK, NULL, code, 0, (LPSTR)&err, sizeof(err), NULL); - return err; -} - -namespace { - -template <class T> T check(T result, const std::string& msg=std::string()) { - if (result == SOCKET_ERROR) - throw connection_engine::io_error(msg + error_str()); - return result; -} - -void gai_check(int result, const std::string& msg="") { - if (result) - throw connection_engine::io_error(msg + gai_strerror(result)); -} -} // namespace - -void initialize() { - WSADATA unused; - check(WSAStartup(0x0202, &unused), "can't load WinSock: "); // Version 2.2 -} - -void finalize() { - WSACleanup(); -} - -void socket_engine::init() { - u_long nonblock = 1; - check(::ioctlsocket(socket_, FIONBIO, &nonblock), "ioctlsocket: "); -} - -socket_engine::socket_engine(descriptor fd, handler& h, const connection_options &opts) - : connection_engine(h, opts), socket_(fd) -{ - init(); -} - -socket_engine::socket_engine(const url& u, handler& h, const connection_options &opts) - : connection_engine(h, opts), socket_(connect(u)) -{ - init(); -} - -socket_engine::~socket_engine() {} - -std::pair<size_t, bool> socket_engine::io_read(char *buf, size_t size) { - int n = ::recv(socket_, buf, size, 0); - if (n > 0) return std::make_pair(n, true); - if (n == 0) return std::make_pair(0, false); - if (n == SOCKET_ERROR && WSAGetLastError() == WSAEWOULDBLOCK) - return std::make_pair(0, true); - throw connection_engine::io_error("read: " + error_str()); -} - -size_t socket_engine::io_write(const char *buf, size_t size) { - int n = ::send(socket_, buf, size, 0); - if (n == SOCKET_ERROR && n == WSAEWOULDBLOCK) return 0; - return check(n, "write: "); -} - -void socket_engine::io_close() { ::closesocket(socket_); } - -void socket_engine::run() { - fd_set self; - FD_ZERO(&self); - FD_SET(socket_, &self); - while (!closed()) { - process(); - if (!closed()) { - int n = ::select(FD_SETSIZE, - can_read() ? &self : NULL, - can_write() ? &self : NULL, - NULL, NULL); - check(n, "select: "); - } - } -} - -namespace { -struct auto_addrinfo { - struct addrinfo *ptr; - auto_addrinfo() : ptr(0) {} - ~auto_addrinfo() { ::freeaddrinfo(ptr); } - addrinfo* operator->() const { return ptr; } -}; - -static const char *amqp_service(const char *port) { - // Help older Windows to know about amqp[s] ports - if (port) { - if (!strcmp("amqp", port)) return "5672"; - if (!strcmp("amqps", port)) return "5671"; - } - return port; -} -} - -descriptor connect(const proton::url& u) { - // convert "0.0.0.0" to "127.0.0.1" on Windows for outgoing sockets - std::string host = (u.host() == "0.0.0.0") ? "127.0.0.1" : u.host(); - descriptor fd = INVALID_SOCKET; - try{ - auto_addrinfo addr; - gai_check(::getaddrinfo(host.empty() ? 0 : host.c_str(), - amqp_service(u.port().empty() ? 0 : u.port().c_str()), - 0, &addr.ptr), - "connect address invalid: "); - fd = check(::socket(addr->ai_family, SOCK_STREAM, 0), "connect socket: "); - check(::connect(fd, addr->ai_addr, addr->ai_addrlen), "connect: "); - return fd; - } catch (...) { - if (fd != INVALID_SOCKET) ::closesocket(fd); - throw; - } -} - -listener::listener(const std::string& host, const std::string &port) : socket_(INVALID_SOCKET) { - try { - auto_addrinfo addr; - gai_check(::getaddrinfo(host.empty() ? 0 : host.c_str(), - port.empty() ? 0 : port.c_str(), 0, &addr.ptr), - "listener address invalid: "); - socket_ = check(::socket(addr->ai_family, SOCK_STREAM, 0), "listener socket: "); - bool yes = true; - check(setsockopt(socket_, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (const char*)&yes, sizeof(yes)), "setsockopt: "); - check(::bind(socket_, addr->ai_addr, addr->ai_addrlen), "listener bind: "); - check(::listen(socket_, 32), "listener listen: "); - } catch (...) { - if (socket_ != INVALID_SOCKET) ::closesocket(socket_); - throw; - } -} - -listener::~listener() { ::closesocket(socket_); } - -descriptor listener::accept(std::string& host_str, std::string& port_str) { - struct sockaddr_storage addr; - socklen_t size = sizeof(addr); - int fd = check(::accept(socket_, (struct sockaddr *)&addr, &size), "accept: "); - char host[NI_MAXHOST], port[NI_MAXSERV]; - gai_check(getnameinfo((struct sockaddr *) &addr, sizeof(addr), - host, sizeof(host), port, sizeof(port), 0), - "accept invalid remote address: "); - host_str = host; - port_str = port; - return fd; -} - -}} --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
