Communication between client and server is erratic - c++

I modified thegeekinthecorner examples to be able to continuously send data.
I am using g++4.9.2.
I tried uninstalling the oficial latest OFED from here http://downloads.openfabrics.org/OFED/
OFED Distribution Software Installation Menu
1) View OFED Installation Guide
2) Install OFED Software
3) Show Installed Software
4) Configure IPoIB
5) Uninstall OFED Software
Q) Exit
Select Option [1-5]:5
Uninstalling the previous version of OFED
Running rpm -e --allmatches libibverbs libibverbs-devel libibverbs-utils libmthca libmlx4 libcxgb3 libnes libipathverbs libibcm libibumad libibumad-devel libibmad ibacm librdmacm librdmacm-utils librdmacm-devel opensm opensm-libs dapl perftest mstflint ibutils infiniband-diags qperf infinipath-psm opensm opensm-libs libipathverbs dapl libibcm libibmad libibumad libibumad-devel libibverbs libibverbs-devel libibverbs-utils libipathverbs libmthca libmlx4 librdmacm librdmacm-devel librdmacm-utils ibacm ibutils ibutils-libs libnes infinipath-psm
Failed to uninstall the previous installation
See /tmp/OFED.22320.logs/ofed_uninstall.log
[idf#node1 OFED-1.5.4-20110726-0732]$
[idf#node1 OFED-1.5.4-20110726-0732]$
If instead I just try to install it, I get this:
OFED Distribution Software Installation Menu
1) Basic (OFED modules and basic user level libraries)
2) HPC (OFED modules and libraries, MPI and diagnostic tools)
3) All packages (all of Basic, HPC)
4) Customize
Q) Exit
Select Option [1-4]:3
Please choose an implementation of MVAPICH2:
1) OFA (IB and iWARP)
2) uDAPL
Implementation [1]: 1
Enable ROMIO support [Y/n]:
Enable shared library support [Y/n]:
Enable Checkpoint-Restart support [y/N]:
Kernel 3.10.0-229.7.2.el7.x86_64 is not supported.
For the list of Supported Platforms and Operating Systems see
/mnt/gluster/Downloads/OFED-1.5.4-20110726-0732/docs/OFED_release_notes.txt
[idf#node1 OFED-1.5.4-20110726-0732]$
[idf#node2 Release]$ lspci | grep -i mel
02:00.0 InfiniBand: Mellanox Technologies MT26428 [ConnectX VPI PCIe 2.0 5GT/s - IB QDR / 10GigE] (rev b0)
[idf#node2 Release]$
[idf#node1 Release]$ ibv_devinfo
hca_id: mlx4_0
transport: InfiniBand (0)
fw_ver: 2.7.200
node_guid: 0025:90ff:ff1a:081c
sys_image_guid: 0025:90ff:ff1a:081f
vendor_id: 0x02c9
vendor_part_id: 26428
hw_ver: 0xB0
board_id: SM_2092000001000
phys_port_cnt: 1
port: 1
state: PORT_ACTIVE (4)
max_mtu: 4096 (5)
active_mtu: 4096 (5)
sm_lid: 1
port_lid: 2
port_lmc: 0x00
link_layer: InfiniBand
[idf#node1 Release]$ ifconfig -a
ib0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 2044
inet 192.168.0.1 netmask 255.255.255.0 broadcast 192.168.0.255
inet6 fe80::225:90ff:ff1a:71 prefixlen 64 scopeid 0x20<link>
Infiniband hardware address can be incorrect! Please read BUGS section in ifconfig(8).
infiniband 80:00:00:48:FE:80:00:00:00:00:00:00:00:00:00:00:00:00:00:00 txqueuelen 256 (InfiniBand)
RX packets 5 bytes 280 (280.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 27 overruns 0 carrier 0 collisions 0
Below is the client and server. When I run this programs, the clients will send messages, but the number of messages it sends is erratic, error messages are often
Client:
#include <iostream>
#include <thread>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <rdma/rdma_cma.h>
#define TEST_NZ(x) do { if ( (x)) die("error: " #x " failed (returned non-zero)." ); } while (0)
#define TEST_Z(x) do { if (!(x)) die("error: " #x " failed (returned zero/null)."); } while (0)
const int BUFFER_SIZE = 2048;
const int TIMEOUT_IN_MS = 500; /* ms */
struct context
{
struct ibv_context *ctx;
struct ibv_pd *pd;
struct ibv_cq *cq;
struct ibv_comp_channel *comp_channel;
pthread_t cq_poller_thread;
};
struct connection
{
struct rdma_cm_id *id;
struct ibv_qp *qp;
struct ibv_mr *recv_mr;
struct ibv_mr *send_mr;
char *recv_region;
char *send_region;
int num_completions;
};
static pthread_t msgThread;
static void die(const char *reason);
static void build_context(struct ibv_context *verbs);
static void build_qp_attr(struct ibv_qp_init_attr *qp_attr);
static void * poll_cq(void *);
static void post_receives(struct connection *conn);
static void register_memory(struct connection *conn);
static int on_addr_resolved(struct rdma_cm_id *id);
static void on_completion(struct ibv_wc *wc);
static int on_connection(void *context);
static int on_disconnect(struct rdma_cm_id *id);
static int on_event(struct rdma_cm_event *event);
static int on_route_resolved(struct rdma_cm_id *id);
static struct context *s_ctx = NULL;
#include <mutex> // std::mutex, std::unique_lock
#include <condition_variable> // std::condition_variable
std::mutex mtx;
std::condition_variable cv;
bool ok_to_send_next_message = 1;
bool message_available()
{
return 0 != ok_to_send_next_message;
}
int main(int argc, char **argv)
{
struct addrinfo *addr;
struct rdma_cm_event *event = NULL;
struct rdma_cm_id *conn= NULL;
struct rdma_event_channel *ec = NULL;
if (argc != 3)
die("usage: client <server-address> <server-port>");
TEST_NZ(getaddrinfo(argv[1], argv[2], NULL, &addr));
TEST_Z(ec = rdma_create_event_channel());
TEST_NZ(rdma_create_id(ec, &conn, NULL, RDMA_PS_TCP));
TEST_NZ(rdma_resolve_addr(conn, NULL, addr->ai_addr, TIMEOUT_IN_MS));
freeaddrinfo(addr);
while (0 == rdma_get_cm_event(ec, &event))
//while (rdma_get_cm_event(ec, &event))
{
std::cout << "rdma_get_cm_event\n";
struct rdma_cm_event event_copy;
memcpy(&event_copy, event, sizeof(*event));
rdma_ack_cm_event(event);
if (on_event(&event_copy))
break;
}
rdma_destroy_event_channel(ec);
return 0;
}
void die(const char *reason)
{
fprintf(stderr, "%s\n", reason);
exit(EXIT_FAILURE);
}
void build_context(struct ibv_context *verbs)
{
if (s_ctx)
{
if (s_ctx->ctx != verbs)
die("cannot handle events in more than one context.");
return;
}
s_ctx = (struct context *)malloc(sizeof(struct context));
s_ctx->ctx = verbs;
TEST_Z(s_ctx->pd = ibv_alloc_pd(s_ctx->ctx));
TEST_Z(s_ctx->comp_channel = ibv_create_comp_channel(s_ctx->ctx));
TEST_Z(s_ctx->cq = ibv_create_cq(s_ctx->ctx, 100, NULL, s_ctx->comp_channel, 0)); /* cqe=10 is arbitrary */
TEST_NZ(ibv_req_notify_cq(s_ctx->cq, 0));
TEST_NZ(pthread_create(&s_ctx->cq_poller_thread, NULL, poll_cq, NULL));
}
void *SendMessages(void *context)
{
static int loopcount = 0;
while(1)
{
std::unique_lock<std::mutex> lck(mtx);
cv.wait(lck, message_available);
//std::this_thread::sleep_for(std::chrono::microseconds(50));
ok_to_send_next_message = 0;
struct connection *conn = (struct connection *)context;
struct ibv_send_wr wr, *bad_wr = NULL;
struct ibv_sge sge;
std::cout << "looping send..." << loopcount << '\n' << std::flush;
memset(&wr, 0, sizeof(wr));
wr.wr_id = (uintptr_t)conn;
wr.opcode = IBV_WR_SEND;
wr.sg_list = &sge;
wr.num_sge = 1;
wr.send_flags = IBV_SEND_SIGNALED;
sge.addr = (uintptr_t)conn->send_region;
sge.length = BUFFER_SIZE;
sge.lkey = conn->send_mr->lkey;
snprintf(conn->send_region, BUFFER_SIZE, "message from active/client side with count %d", loopcount++);
TEST_NZ(ibv_post_send(conn->qp, &wr, &bad_wr));
}
}
void build_qp_attr(struct ibv_qp_init_attr *qp_attr)
{
std::cout << "build_qp_attr\n";
memset(qp_attr, 0, sizeof(*qp_attr));
qp_attr->send_cq = s_ctx->cq;
qp_attr->recv_cq = s_ctx->cq;
qp_attr->qp_type = IBV_QPT_RC;
qp_attr->cap.max_send_wr = 100;
qp_attr->cap.max_recv_wr = 100;
qp_attr->cap.max_send_sge = 1;
qp_attr->cap.max_recv_sge = 1;
}
void * poll_cq(void *ctx)
{
struct ibv_cq *cq;
struct ibv_wc wc;
while (1)
{
TEST_NZ(ibv_get_cq_event(s_ctx->comp_channel, &cq, &ctx));
ibv_ack_cq_events(cq, 1);
TEST_NZ(ibv_req_notify_cq(cq, 0));
int ne;
struct ibv_wc wc;
do
{
std::cout << "polling\n";
ne = ibv_poll_cq(cq, 1, &wc);
}
while(ne == 0);
on_completion(&wc);
//if (wc.opcode == IBV_WC_SEND)
if (wc.status == IBV_WC_SUCCESS)
{
{
ok_to_send_next_message = 1;
//while (message_available()) std::this_thread::yield();
//std::cout << "past yield\n";
std::unique_lock<std::mutex> lck(mtx);
cv.notify_one();
}
}
}
return NULL;
}
void post_receives(struct connection *conn)
{
std::cout << "post_receives\n";
struct ibv_recv_wr wr, *bad_wr = NULL;
struct ibv_sge sge;
wr.wr_id = (uintptr_t)conn;
wr.next = NULL;
wr.sg_list = &sge;
wr.num_sge = 1;
sge.addr = (uintptr_t)conn->recv_region;
sge.length = BUFFER_SIZE;
sge.lkey = conn->recv_mr->lkey;
TEST_NZ(ibv_post_recv(conn->qp, &wr, &bad_wr));
}
void register_memory(struct connection *conn)
{
std::cout << "register_memory\n";
conn->send_region = (char *)malloc(BUFFER_SIZE);
conn->recv_region = (char *)malloc(BUFFER_SIZE);
TEST_Z(conn->send_mr = ibv_reg_mr(
s_ctx->pd,
conn->send_region,
BUFFER_SIZE,
IBV_ACCESS_LOCAL_WRITE | IBV_ACCESS_REMOTE_WRITE));
TEST_Z(conn->recv_mr = ibv_reg_mr(
s_ctx->pd,
conn->recv_region,
BUFFER_SIZE,
IBV_ACCESS_LOCAL_WRITE | IBV_ACCESS_REMOTE_WRITE));
}
int on_addr_resolved(struct rdma_cm_id *id)
{
std::cout << "on_addr_resolved\n";
struct ibv_qp_init_attr qp_attr;
struct connection *conn;
build_context(id->verbs);
build_qp_attr(&qp_attr);
TEST_NZ(rdma_create_qp(id, s_ctx->pd, &qp_attr));
id->context = conn = (struct connection *)malloc(sizeof(struct connection));
conn->id = id;
conn->qp = id->qp;
conn->num_completions = 0;
register_memory(conn);
post_receives(conn);
TEST_NZ(rdma_resolve_route(id, TIMEOUT_IN_MS));
return 0;
}
void on_completion(struct ibv_wc *wc)
{
std::cout << "on_completion\n";
struct connection *conn = (struct connection *)(uintptr_t)wc->wr_id;
if (wc->status != IBV_WC_SUCCESS)
{
//die("\ton_completion: status is not IBV_WC_SUCCESS.");
printf("\ton_completion: status is not IBV_WC_SUCCESS.");
printf("\t it is %d ", wc->status);
}
printf("\n");
if (wc->opcode & IBV_WC_RECV)
printf("\treceived message: %s\n", conn->recv_region);
else if (wc->opcode == IBV_WC_SEND)
printf("\tsend completed successfully.\n");
else
die("\ton_completion: completion isn't a send or a receive.");
if (5 == ++conn->num_completions)
rdma_disconnect(conn->id);
}
int on_connection(void *context)
{
std::cout << "on_connection\n";
TEST_NZ(pthread_create(&msgThread, NULL, SendMessages, context));
return 0;
}
int on_disconnect(struct rdma_cm_id *id)
{
struct connection *conn = (struct connection *)id->context;
printf("disconnected.\n");
rdma_destroy_qp(id);
ibv_dereg_mr(conn->send_mr);
ibv_dereg_mr(conn->recv_mr);
free(conn->send_region);
free(conn->recv_region);
free(conn);
rdma_destroy_id(id);
return 1; /* exit event loop */
}
int on_route_resolved(struct rdma_cm_id *id)
{
struct rdma_conn_param cm_params;
printf("route resolved.\n");
memset(&cm_params, 0, sizeof(cm_params));
TEST_NZ(rdma_connect(id, &cm_params));
return 0;
}
int on_event(struct rdma_cm_event *event)
{
int r = 0;
if (event->event == RDMA_CM_EVENT_ADDR_RESOLVED)
r = on_addr_resolved(event->id);
else if (event->event == RDMA_CM_EVENT_ROUTE_RESOLVED)
r = on_route_resolved(event->id);
else if (event->event == RDMA_CM_EVENT_ESTABLISHED)
r = on_connection(event->id->context);
else if (event->event == RDMA_CM_EVENT_DISCONNECTED)
r = on_disconnect(event->id);
else
die("on_event: unknown event.");
return r;
}
Server:
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <inttypes.h>
#include <rdma/rdma_cma.h>
#define TEST_NZ(x) do { if ( (x)) die("error: " #x " failed (returned non-zero)." ); } while (0)
#define TEST_Z(x) do { if (!(x)) die("error: " #x " failed (returned zero/null)."); } while (0)
const int BUFFER_SIZE = 2048;
struct context
{
struct ibv_context *ctx;
struct ibv_pd *pd;
struct ibv_cq *cq;
struct ibv_comp_channel *comp_channel;
pthread_t cq_poller_thread;
};
struct connection
{
struct ibv_qp *qp;
struct ibv_mr *recv_mr;
struct ibv_mr *send_mr;
char *recv_region;
char *send_region;
};
static void die(const char *reason);
static void build_context(struct ibv_context *verbs);
static void build_qp_attr(struct ibv_qp_init_attr *qp_attr);
static void * poll_cq(void *);
static void post_receives(struct connection *conn);
static void register_memory(struct connection *conn);
static void on_completion(struct ibv_wc *wc);
static int on_connect_request(struct rdma_cm_id *id);
static int on_connection(void *context);
static int on_disconnect(struct rdma_cm_id *id);
static int on_event(struct rdma_cm_event *event);
static struct context *s_ctx = NULL;
int main(int argc, char **argv)
{
struct sockaddr_in6 addr;
struct rdma_cm_event *event = NULL;
struct rdma_cm_id *listener = NULL;
struct rdma_event_channel *ec = NULL;
uint16_t port = 0;
memset(&addr, 0, sizeof(addr));
addr.sin6_family = AF_INET6;
TEST_Z(ec = rdma_create_event_channel());
TEST_NZ(rdma_create_id(ec, &listener, NULL, RDMA_PS_TCP));
TEST_NZ(rdma_bind_addr(listener, (struct sockaddr *)&addr));
TEST_NZ(rdma_listen(listener, 100)); /* backlog=10 is arbitrary */
//printf("[ %"PRIu32" ]\n", *addr.sin6_addr.s6_addr32);
port = ntohs(rdma_get_src_port(listener));
printf("listening on port %d.\n", port);
while (rdma_get_cm_event(ec, &event) == 0)
{
struct rdma_cm_event event_copy;
memcpy(&event_copy, event, sizeof(*event));
rdma_ack_cm_event(event);
if (on_event(&event_copy))
break;
}
rdma_destroy_id(listener);
rdma_destroy_event_channel(ec);
return 0;
}
void die(const char *reason)
{
fprintf(stderr, "%s\n", reason);
exit(EXIT_FAILURE);
}
void build_context(struct ibv_context *verbs)
{
if (s_ctx)
{
if (s_ctx->ctx != verbs)
die("cannot handle events in more than one context.");
return;
}
s_ctx = (struct context *)malloc(sizeof(struct context));
s_ctx->ctx = verbs;
TEST_Z(s_ctx->pd = ibv_alloc_pd(s_ctx->ctx));
TEST_Z(s_ctx->comp_channel = ibv_create_comp_channel(s_ctx->ctx));
TEST_Z(s_ctx->cq = ibv_create_cq(s_ctx->ctx, 100, NULL, s_ctx->comp_channel, 0)); /* cqe=10 is arbitrary */
TEST_NZ(ibv_req_notify_cq(s_ctx->cq, 0));
TEST_NZ(pthread_create(&s_ctx->cq_poller_thread, NULL, poll_cq, NULL));
}
void build_qp_attr(struct ibv_qp_init_attr *qp_attr)
{
memset(qp_attr, 0, sizeof(*qp_attr));
qp_attr->send_cq = s_ctx->cq;
qp_attr->recv_cq = s_ctx->cq;
qp_attr->qp_type = IBV_QPT_RC;
qp_attr->cap.max_send_wr = 100;
qp_attr->cap.max_recv_wr = 100;
qp_attr->cap.max_send_sge = 1;
qp_attr->cap.max_recv_sge = 1;
}
void * poll_cq(void *ctx)
{
struct ibv_cq *cq;
struct ibv_wc wc;
while (1)
{
TEST_NZ(ibv_get_cq_event(s_ctx->comp_channel, &cq, &ctx));
ibv_ack_cq_events(cq, 1);
TEST_NZ(ibv_req_notify_cq(cq, 0));
while (ibv_poll_cq(cq, 1, &wc))
{
std::cout << "polling\n";
on_completion(&wc);
}
}
return NULL;
}
void post_receives(struct connection *conn)
{
std::cout << "post_receives\n";
struct ibv_recv_wr wr, *bad_wr = NULL;
struct ibv_sge sge;
wr.wr_id = (uintptr_t)conn;
wr.next = NULL;
wr.sg_list = &sge;
wr.num_sge = 1;
sge.addr = (uintptr_t)conn->recv_region;
sge.length = BUFFER_SIZE;
sge.lkey = conn->recv_mr->lkey;
TEST_NZ(ibv_post_recv(conn->qp, &wr, &bad_wr));
}
void register_memory(struct connection *conn)
{
conn->send_region = (char *)malloc(BUFFER_SIZE);
conn->recv_region = (char *)malloc(BUFFER_SIZE);
TEST_Z(conn->send_mr = ibv_reg_mr(
s_ctx->pd,
conn->send_region,
BUFFER_SIZE,
IBV_ACCESS_LOCAL_WRITE | IBV_ACCESS_REMOTE_WRITE));
TEST_Z(conn->recv_mr = ibv_reg_mr(
s_ctx->pd,
conn->recv_region,
BUFFER_SIZE,
IBV_ACCESS_LOCAL_WRITE | IBV_ACCESS_REMOTE_WRITE));
}
void on_completion(struct ibv_wc *wc)
{
if (wc->status != IBV_WC_SUCCESS)
die("on_completion: status is not IBV_WC_SUCCESS.");
if (wc->opcode & IBV_WC_RECV)
{
struct connection *conn = (struct connection *)(uintptr_t)wc->wr_id;
post_receives(conn);
printf("received message: %s\n", conn->recv_region);
}
else if (wc->opcode == IBV_WC_SEND)
{
printf("send completed successfully.\n");
}
}
int on_connect_request(struct rdma_cm_id *id)
{
struct ibv_qp_init_attr qp_attr;
struct rdma_conn_param cm_params;
struct connection *conn;
printf("received connection request.\n");
build_context(id->verbs);
build_qp_attr(&qp_attr);
TEST_NZ(rdma_create_qp(id, s_ctx->pd, &qp_attr));
id->context = conn = (struct connection *)malloc(sizeof(struct connection));
conn->qp = id->qp;
register_memory(conn);
post_receives(conn);
memset(&cm_params, 0, sizeof(cm_params));
TEST_NZ(rdma_accept(id, &cm_params));
return 0;
}
int on_connection(void *context)
{
struct connection *conn = (struct connection *)context;
struct ibv_send_wr wr, *bad_wr = NULL;
struct ibv_sge sge;
snprintf(conn->send_region, BUFFER_SIZE, "message from passive/server side with pid %d", getpid());
printf("connected. posting send...\n");
memset(&wr, 0, sizeof(wr));
wr.opcode = IBV_WR_SEND;
wr.sg_list = &sge;
wr.num_sge = 1;
wr.send_flags = IBV_SEND_SIGNALED;
sge.addr = (uintptr_t)conn->send_region;
sge.length = BUFFER_SIZE;
sge.lkey = conn->send_mr->lkey;
TEST_NZ(ibv_post_send(conn->qp, &wr, &bad_wr));
return 0;
}
int on_disconnect(struct rdma_cm_id *id)
{
struct connection *conn = (struct connection *)id->context;
printf("peer disconnected.\n");
rdma_destroy_qp(id);
ibv_dereg_mr(conn->send_mr);
ibv_dereg_mr(conn->recv_mr);
free(conn->send_region);
free(conn->recv_region);
free(conn);
rdma_destroy_id(id);
return 0;
}
int on_event(struct rdma_cm_event *event)
{
std::cout << "on_event\n";
int r = 0;
if (event->event == RDMA_CM_EVENT_CONNECT_REQUEST)
r = on_connect_request(event->id);
else if (event->event == RDMA_CM_EVENT_ESTABLISHED)
r = on_connection(event->id->context);
else if (event->event == RDMA_CM_EVENT_DISCONNECTED)
r = on_disconnect(event->id);
else
die("on_event: unknown event.");
return r;
}
Here are a couple of runs. Totally random the number of message sent:
[idf#node1 Release]$ ./TGKITCClient 192.168.0.1 47819
rdma_get_cm_event
on_addr_resolved
build_qp_attr
register_memory
post_receives
rdma_get_cm_event
route resolved.
rdma_get_cm_event
on_connection
looping send...0
polling
on_completion
received message: message from passive/server side with pid 4188
polling
on_completion
send completed successfully.
looping send...1
polling
on_completion
send completed successfully.
^C
[idf#node1 Release]$
And then
[idf#node1 Release]$ ./TGKITCClient 192.168.0.1 55148
rdma_get_cm_event
on_addr_resolved
build_qp_attr
register_memory
post_receives
rdma_get_cm_event
route resolved.
rdma_get_cm_event
on_connection
looping send...0
polling
on_completion
received message: message from passive/server side with pid 4279
polling
on_completion
send completed successfully.
looping send...1
polling
on_completion
send completed successfully.
looping send...2
polling
on_completion
send completed successfully.
looping send...3
polling
on_completion
send completed successfully.
looping send...4
polling
on_completion
send completed successfully.
looping send...5
polling
on_completion
send completed successfully.
looping send...6
polling
on_completion
send completed successfully.
looping send...7
polling
on_completion
send completed successfully.
looping send...8
rdma_get_cm_event
disconnected.
polling
on_completion
send completed successfully.
on_completion: status is not IBV_WC_SUCCESS. it is 5 [idf#node1 Release]$
Here is the server side:
on_event
peer disconnected.
on_event
received connection request.
post_receives
on_event
connected. posting send...
polling
send completed successfully.
polling
post_receives
received message: message from active/client side with count 0
polling
post_receives
received message: message from active/client side with count 1
polling
post_receives
received message: message from active/client side with count 2
polling
post_receives
received message: message from active/client side with count 3
polling
post_receives
received message: message from active/client side with count 4
polling
post_receives
received message: message from active/client side with count 5
polling
post_receives
received message: message from active/client side with count 6
polling
post_receives
received message: message from active/client side with count 7
on_event
peer disconnected.

Make sure that the most recent drivers and firmware on the cards are installed. Beyond that, using the RDMA packages included with most OS distributions when trying to run IB is a dangerous game to play.
It is strongly recommended that for applications like these the Open Fabrics Enterprise Distribution should be used to provide openib, opensm and a variety of other useful infiniband related packages for analysis diagnostics and tuning of a network. The official OFED packages can be found on the OpenFabrics website.
Based on the question it looks like IPoIB is being used but the specific configuration is not mentioned. IPoIB is not necessarily the best way to take advantages of the hardware resources available in the IB cards.
In addition to those considerations making sure that the subnetmanager is setup and configured correctly. Some switches have built-in subnet managers that can be access and configured through a management interface, in other cases it might make more sense to run and configure the subnet manager on one of the nodes that you are using. OpenSM is a common subnet manager that is included with OFED distributions and there are many online guides available for setting up and configuring a subnet manager based on the type of network being setup.
OFED also includes a variety of IB testing and profiling tools. ibdiagnet is a useful tool for debugging IB network issues. And there are many guides available online that show different ways to make use of the tool as well as the other tools included in OFED.
Depending on the type of IB switch used there may additionally be some network management and diagnostic tools that would allow for further analysis of the network. The configuration of IB hardware and the low-level software that manages it is sometimes more critical to overall performance than the actual code being run. But with that being said recompiling and linking to relevant libraries from the correct version of OFED might be advisable if significant software of hardware configuration changes are made.

Related

Xcode app for macOS. This is how I setup to get audio from usb mic input. Worked a year ago, now doesn't. Why

Here is my audio init code. My app responds when queue buffers are ready, but all data in buffer is zero. Checking sound in system preferences shows that USB Audio CODEC in sound input dialog is active. AudioInit() is called right after app launches.
{
#pragma mark user data struct
typedef struct MyRecorder
{
AudioFileID recordFile;
SInt64 recordPacket;
Float32 *pSampledData;
MorseDecode *pMorseDecoder;
} MyRecorder;
#pragma mark utility functions
void CheckError(OSStatus error, const char *operation)
{
if(error == noErr) return;
char errorString[20];
// see if it appears to be a 4 char code
*(UInt32*)(errorString + 1) = CFSwapInt32HostToBig(error);
if (isprint(errorString[1]) && isprint(errorString[2]) &&
isprint(errorString[3]) && isprint(errorString[4]))
{
errorString[0] = errorString[5] = '\'';
errorString[6] = '\0';
}
else
{
sprintf(errorString, "%d", (int)error);
}
fprintf(stderr, "Error: %s (%s)\n", operation, errorString);
}
OSStatus MyGetDefaultInputDeviceSampleRate(Float64 *outSampleRate)
{
OSStatus error;
AudioDeviceID deviceID = 0;
AudioObjectPropertyAddress propertyAddress;
UInt32 propertySize;
propertyAddress.mSelector = kAudioHardwarePropertyDefaultInputDevice;
propertyAddress.mScope = kAudioObjectPropertyScopeGlobal;
propertyAddress.mElement = 0;
propertySize = sizeof(AudioDeviceID);
error = AudioObjectGetPropertyData(kAudioObjectSystemObject,
&propertyAddress,
0,
NULL,
&propertySize,
&deviceID);
if(error)
return error;
propertyAddress.mSelector = kAudioDevicePropertyNominalSampleRate;
propertyAddress.mScope = kAudioObjectPropertyScopeGlobal;
propertyAddress.mElement = 0;
propertySize = sizeof(Float64);
error = AudioObjectGetPropertyData(deviceID,
&propertyAddress,
0,
NULL,
&propertySize,
outSampleRate);
return error;
}
static int MyComputeRecordBufferSize(const AudioStreamBasicDescription *format,
AudioQueueRef queue,
float seconds)
{
int packets, frames, bytes;
frames = (int)ceil(seconds * format->mSampleRate);
if(format->mBytesPerFrame > 0)
{
bytes = frames * format->mBytesPerFrame;
}
else
{
UInt32 maxPacketSize;
if(format->mBytesPerPacket > 0)
{
// constant packet size
maxPacketSize = format->mBytesPerPacket;
}
else
{
// get the largest single packet size possible
UInt32 propertySize = sizeof(maxPacketSize);
CheckError(AudioQueueGetProperty(queue,
kAudioConverterPropertyMaximumOutputPacketSize,
&maxPacketSize,
&propertySize),
"Couldn't get queues max output packet size");
}
if(format->mFramesPerPacket > 0)
packets = frames / format->mFramesPerPacket;
else
// worst case scenario: 1 frame in a packet
packets = frames;
// sanity check
if(packets == 0)
packets = 1;
bytes = packets * maxPacketSize;
}
return bytes;
}
extern void bridgeToMainThread(MorseDecode *pDecode);
static int callBacks = 0;
// ---------------------------------------------
static void MyAQInputCallback(void *inUserData,
AudioQueueRef inQueue,
AudioQueueBufferRef inBuffer,
const AudioTimeStamp *inStartTime,
UInt32 inNumPackets,
const AudioStreamPacketDescription *inPacketDesc)
{
MyRecorder *recorder = (MyRecorder*)inUserData;
Float32 *pAudioData = (Float32*)(inBuffer->mAudioData);
recorder->pMorseDecoder->pBuffer = pAudioData;
recorder->pMorseDecoder->bufferSize = inNumPackets;
bridgeToMainThread(recorder->pMorseDecoder);
CheckError(AudioQueueEnqueueBuffer(inQueue,
inBuffer,
0,
NULL),
"AudioQueueEnqueueBuffer failed");
printf("packets = %ld, bytes = %ld\n",(long)inNumPackets,(long)inBuffer->mAudioDataByteSize);
callBacks++;
//printf("\ncallBacks = %d\n",callBacks);
//if(callBacks == 0)
//audioStop();
}
static AudioQueueRef queue = {0};
static MyRecorder recorder = {0};
static AudioStreamBasicDescription recordFormat;
void audioInit()
{
// set up format
memset(&recordFormat,0,sizeof(recordFormat));
recordFormat.mFormatID = kAudioFormatLinearPCM;
recordFormat.mChannelsPerFrame = 2;
recordFormat.mBitsPerChannel = 32;
recordFormat.mBytesPerPacket = recordFormat.mBytesPerFrame = recordFormat.mChannelsPerFrame * sizeof(Float32);
recordFormat.mFramesPerPacket = 1;
//recordFormat.mFormatFlags = kAudioFormatFlagsCanonical;
recordFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked;
MyGetDefaultInputDeviceSampleRate(&recordFormat.mSampleRate);
UInt32 propSize = sizeof(recordFormat);
CheckError(AudioFormatGetProperty(kAudioFormatProperty_FormatInfo,
0,
NULL,
&propSize,
&recordFormat),
"AudioFormatProperty failed");
recorder.pMorseDecoder = MorseDecode::pInstance();
recorder.pMorseDecoder->m_sampleRate = recordFormat.mSampleRate;
// recorder.pMorseDecoder->setCircularBuffer();
//set up queue
CheckError(AudioQueueNewInput(&recordFormat,
MyAQInputCallback,
&recorder,
NULL,
kCFRunLoopCommonModes,
0,
&queue),
"AudioQueueNewInput failed");
UInt32 size = sizeof(recordFormat);
CheckError(AudioQueueGetProperty(queue,
kAudioConverterCurrentOutputStreamDescription,
&recordFormat,
&size), "Couldn't get queue's format");
// set up buffers and enqueue
const int kNumberRecordBuffers = 3;
int bufferByteSize = MyComputeRecordBufferSize(&recordFormat, queue, AUDIO_BUFFER_DURATION);
for(int bufferIndex = 0; bufferIndex < kNumberRecordBuffers; bufferIndex++)
{
AudioQueueBufferRef buffer;
CheckError(AudioQueueAllocateBuffer(queue,
bufferByteSize,
&buffer),
"AudioQueueAllocateBuffer failed");
CheckError(AudioQueueEnqueueBuffer(queue,
buffer,
0,
NULL),
"AudioQueueEnqueueBuffer failed");
}
}
void audioRun()
{
CheckError(AudioQueueStart(queue, NULL), "AudioQueueStart failed");
}
void audioStop()
{
CheckError(AudioQueuePause(queue), "AudioQueuePause failed");
}
}
This sounds like the new macOS 'microphone privacy' setting, which, if set to 'no access' for your app, will cause precisely this behaviour. So:
Open the System Preferences pane.
Click on 'Security and Privacy'.
Select the Privacy tab.
Click on 'Microphone' in the left-hand pane.
Locate your app in the right-hand pane and tick the checkbox next to it.
Then restart your app and test it.
Tedious, no?
Edit: As stated in the comments, you can't directly request microphone access, but you can detect whether it has been granted to your app or not by calling [AVCaptureDevice authorizationStatusForMediaType: AVMediaTypeAudio].

get process inode using netlink

I want to try and correlate an IP packet (using libpcap) to a process. I have had some limited success using the relevant /proc/net/ files but found that on some of the machines i'm using, this file can be many thousands of lines and parsing it is not efficient (caching has alleviated some performance problems).
I read that using sock_diag netlink subsystem could help by directly querying the kernel about the socket I am interested in. I've had limited success with my attempts but have hit a mental block on what is wrong.
For the initial query I have:
if (query_fd_) {
struct {
nlmsghdr nlh;
inet_diag_req_v2 id_req;
} req = {
.nlh = {
.nlmsg_len = sizeof(req),
.nlmsg_type = SOCK_DIAG_BY_FAMILY,
.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP
},
.id_req = {
.sdiag_family = packet.l3_protocol,
.sdiag_protocol = packet.l4_protocol,
.idiag_ext = 0,
.pad = 0,
.idiag_states = -1,
.id = {
.idiag_sport = packet.src_port,
.idiag_dport = packet.dst_port
}
}
};
//packet ips are just binary data stored as strings!
memcpy(req.id_req.id.idiag_src, packet.src_ip.c_str(), 4);
memcpy(req.id_req.id.idiag_dst, packet.dst_ip.c_str(), 4);
struct sockaddr_nl nladdr = {
.nl_family = AF_NETLINK
};
struct iovec iov = {
.iov_base = &req,
.iov_len = sizeof(req)
};
struct msghdr msg = {
.msg_name = (void *) &nladdr,
.msg_namelen = sizeof(nladdr),
.msg_iov = &iov,
.msg_iovlen = 1
};
// Send message to kernel
for (;;) {
if (sendmsg(query_fd_, &msg, 0) < 0) {
if (errno == EINTR)
continue;
perror("sendmsg");
return false;
}
return true;
}
}
return false;
For the receive code I have:
long buffer[8192];
struct sockaddr_nl nladdr = {
.nl_family = AF_NETLINK
};
struct iovec iov = {
.iov_base = buffer,
.iov_len = sizeof(buffer)
};
struct msghdr msg = {
.msg_name = (void *) &nladdr,
.msg_namelen = sizeof(nladdr),
.msg_iov = &iov,
.msg_iovlen = 1
};
int flags = 0;
for (;;) {
ssize_t rv = recvmsg(query_fd_, &msg, flags);
// error handling
if (rv < 0) {
if (errno == EINTR)
continue;
if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
break;
perror("Failed to recv from netlink socket");
return 0;
}
if (rv == 0) {
printf("Unexpected shutdown of NETLINK socket");
return 0;
}
for (const struct nlmsghdr* header = reinterpret_cast<const struct nlmsghdr*>(buffer);
rv >= 0 && NLMSG_OK(header, static_cast<uint32_t>(rv));
header = NLMSG_NEXT(header, rv)) {
// The end of multipart message
if (header->nlmsg_type == NLMSG_DONE)
return 0;
if (header->nlmsg_type == NLMSG_ERROR) {
const struct nlmsgerr *err = reinterpret_cast<nlmsgerr*>(NLMSG_DATA(header));
if (err == NULL)
return 100;
errno = -err->error;
perror("NLMSG_ERROR");
return 0;
}
if (header->nlmsg_type != SOCK_DIAG_BY_FAMILY) {
printf("unexpected nlmsg_type %u\n", (unsigned)header->nlmsg_type);
continue;
}
// Get the details....
const struct inet_diag_msg* diag = reinterpret_cast<inet_diag_msg*>(NLMSG_DATA(header));
if (header->nlmsg_len < NLMSG_LENGTH(sizeof(*diag))) {
printf("Message too short %d vs %d\n", header->nlmsg_len, NLMSG_LENGTH(sizeof(*diag)));
return 0;
}
if (diag->idiag_family != PF_INET) {
printf("unexpected family %u\n", diag->idiag_family);
return 1;
}
return diag->idiag_inode;
The Problem:
The diag->udiag_inode value doesn't match the one I see in netstat output or in the /proc/net/ files. Is it supposed too? If not, is it possible to use this approach to retrieve the inode number for the process so that I can then query /proc for the corresponding PID?
Another thing I didn't quite understand is the NLMSG_DONE when checking the nlmsg_type in the header. What I am seeing:
1 - TCP 10.0.9.15:51002 -> 192.168.64.11:3128 [15047]
2 - TCP 192.168.64.11:3128 -> 10.0.9.15:51002 [0]
3 - TCP 10.0.9.15:51002 -> 192.168.64.11:3128 [0]
4 - TCP 192.168.64.11:3128 -> 10.0.9.15:51002 [15047]
5 - TCP 10.0.9.15:51002 -> 192.168.64.11:3128 [0]
6 - TCP 192.168.64.11:3128 -> 10.0.9.15:51002 [0]
7 - TCP 10.0.9.15:51002 -> 192.168.64.11:3128 [15047]
So I get an inode number on first query, then some NLMSG_DONE returns (stepping through code confirmed this was the path). Why don't I get the same result for say lines 1 and 3?
Appreciate any help or advice.
Found the answer and posting in case anyone stumbles across it:
I had a uint16_t as the return type from the recv code when in fact it should have been ino_t or uint32_t. I discovered this when I noticed that a few of the inodes matched correctly after a fresh reboot and then after a while stopped matching with no code changed (inode count obviously incrementing). Using the correct type in the function return sorted the problem (so the code I posted is actually correct!)
I was getting multi part messages. I should have looped whilst NLM_F_MULTI was set in the flags and then left the loop when receiving NLMSG_DONE.

AMQP-CPP: Broken pipe error in TCP Handler

Unfortunately, in my project I always end up in the onError function in the event handler with the error message "Broken pipe". Unfortunately, I never get into the onConnected state. The monitor Funktion in the Event Handler is called twice with the Flag AMQP::readable. After that, it is called with no flags set, that is the time when my pipe gets broken.
Here is what I do in my code.
First I open the connection:
int Communicator_RabbitMQ::Open(string device)
{
AMQP::Address address(AMQP::Address("amqp://test:test#localhost/"));
// make a connection
m_connection = std::make_shared< AMQP::TcpConnection> (&oCommunicator_RabbitMQ_Handler, address);
// we need a channel too
m_channel = std::make_shared <AMQP::TcpChannel> (m_connection.get());
m_channel->declareExchange("my-exchange", AMQP::fanout);
m_channel->declareQueue("my-queue");
m_channel->bindQueue("my-exchange", "my-queue", "my-routing-key");
m_channel->declareExchange("cyos_tx_exchange", AMQP::direct);
m_channel->declareQueue("cyos_queue");
m_channel->bindQueue("cyos_tx_exchange", "cyos_queue", "");
return true;
}
then I call the read function cyclically in my thread:
string Communicator_RabbitMQ::Read()
{
int result = 0;
int maxfd = 1;
struct timeval tv
{
1, 0
};
string returnValue; //Rückgabe der Methode
string message; // Nachricht aus RabbitMQ
try
{
FD_ZERO(&oCommunicator_RabbitMQ_Handler.m_set);
FD_SET(oCommunicator_RabbitMQ_Handler.m_fd, &oCommunicator_RabbitMQ_Handler.m_set);
if (oCommunicator_RabbitMQ_Handler.m_fd != -1)
{
maxfd = oCommunicator_RabbitMQ_Handler.m_fd + 1;
}
result = select(FD_SETSIZE, &oCommunicator_RabbitMQ_Handler.m_set, NULL, NULL, &tv);
if ((result == -1) && errno == EINTR)
{
TRACE(L"Error in socket");
}
else if (result > 0)
{
if (oCommunicator_RabbitMQ_Handler.m_flags & AMQP::readable)
TRACE(L"Got something");
if (FD_ISSET(oCommunicator_RabbitMQ_Handler.m_fd, &oCommunicator_RabbitMQ_Handler.m_set))
{
m_connection->process(oCommunicator_RabbitMQ_Handler.m_fd, oCommunicator_RabbitMQ_Handler.m_flags);
}
}
}
catch (exception e)
{
cout << e.what();
}
return "";
}
Here is the TCP Event Handler:
#pragma once
class Communicator_RabbitMQ_Handler : public AMQP::TcpHandler
{
private:
/**
* Method that is called when the connection succeeded
* #param socket Pointer to the socket
*/
virtual void onConnected(AMQP::TcpConnection* connection)
{
std::cout << "connected" << std::endl;
}
/**
* When the connection ends up in an error state this method is called.
* This happens when data comes in that does not match the AMQP protocol
*
* After this method is called, the connection no longer is in a valid
* state and can be used. In normal circumstances this method is not called.
*
* #param connection The connection that entered the error state
* #param message Error message
*/
virtual void onError(AMQP::TcpConnection* connection, const char* message)
{
// report error
std::cout << "AMQP TCPConnection error: " << message << std::endl;
}
/**
* Method that is called when the connection was closed.
* #param connection The connection that was closed and that is now unusable
*/
virtual void onClosed(AMQP::TcpConnection* connection)
{
std::cout << "closed" << std::endl;
}
/**
* Method that is called by AMQP-CPP to register a filedescriptor for readability or writability
* #param connection The TCP connection object that is reporting
* #param fd The filedescriptor to be monitored
* #param flags Should the object be monitored for readability or writability?
*/
virtual void monitor(AMQP::TcpConnection* connection, int fd, int flags)
{
//TRACE(L"Communicator_RabbitMQ_Handler, monitor called, %d, %d, %x", fd, flags, &m_set);
// we did not yet have this watcher - but that is ok if no filedescriptor was registered
if (flags == 0)
return;
if (flags & AMQP::readable)
{
FD_SET(fd, &m_set);
m_fd = fd;
m_flags = flags;
}
}
public:
Communicator_RabbitMQ_Handler() = default;
int m_fd = -1;
int m_flags = 0;
fd_set m_set;
};
RabbitMQ Log entry:
2018-07-02 07:04:50.272 [info] <0.9653.0> accepting AMQP connection <0.9653.0> ([::1]:39602 -> [::1]:5672)
2018-07-02 07:04:50.273 [warning] <0.9653.0> closing AMQP connection <0.9653.0> ([::1]:39602 -> [::1]:5672):
{handshake_timeout,handshake}
I finally fixed this problem by increasing the hanshake timeout to 20 seconds in the rabbitmq.config file. I just added the following in that file:
handshake_timeout = 20000
The value is given in milliseconds, an the default is 10 seconds, which seems not enough for my solution.

Where is the iteration running in this code?

I'm using NatNet SDK to receiving data from the cameras through tcp connection. In their example code below, it can print the stream data using DataHandler function while waiting for a while(c=_getchar()) loop. I have no idea why the code can both waiting for keyboard input and at the same time printing the camera's data in the DataHandler function in real time. I didn't see the code run in multi threads.
My second question is that how I can get the stream data in a for loop in the main function. If someone can tell me how to use that DataHandler to get data in the main function, that will be great.
//=============================================================================
// Copyright ?2014 NaturalPoint, Inc. All Rights Reserved.
//
// 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 NaturalPoint, Inc. 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.
//=============================================================================
/*
SampleClient.cpp
This program connects to a NatNet server, receives a data stream, and writes that data stream
to an ascii file. The purpose is to illustrate using the NatNetClient class.
Usage [optional]:
SampleClient [ServerIP] [LocalIP] [OutputFilename]
[ServerIP] IP address of the server (e.g. 192.168.0.107) ( defaults to local machine)
[OutputFilename] Name of points file (pts) to write out. defaults to Client-output.pts
*/
#include <stdio.h>
#include <tchar.h>
#include <conio.h>
#include <winsock2.h>
#include "NatNetTypes.h"
#include "NatNetClient.h"
#pragma warning( disable : 4996 )
void _WriteHeader(FILE* fp, sDataDescriptions* pBodyDefs);
void _WriteFrame(FILE* fp, sFrameOfMocapData* data);
void _WriteFooter(FILE* fp);
void __cdecl DataHandler(sFrameOfMocapData* data, void* pUserData); // receives data from the server
void __cdecl MessageHandler(int msgType, char* msg); // receives NatNet error mesages
void resetClient();
int CreateClient(int iConnectionType);
unsigned int MyServersDataPort = 3130;
unsigned int MyServersCommandPort = 3131;
int iConnectionType = ConnectionType_Multicast;
//int iConnectionType = ConnectionType_Unicast;
NatNetClient* theClient;
FILE* fp;
char szMyIPAddress[128] = "";
char szServerIPAddress[128] = "";
int analogSamplesPerMocapFrame = 0;
int _tmain(int argc, _TCHAR* argv[])
{
int iResult;
// parse command line args
if(argc>1)
{
strcpy(szServerIPAddress, argv[1]); // specified on command line
printf("Connecting to server at %s...\n", szServerIPAddress);
}
else
{
strcpy(szServerIPAddress, ""); // not specified - assume server is local machine
printf("Connecting to server at LocalMachine\n");
}
if(argc>2)
{
strcpy(szMyIPAddress, argv[2]); // specified on command line
printf("Connecting from %s...\n", szMyIPAddress);
}
else
{
strcpy(szMyIPAddress, ""); // not specified - assume server is local machine
printf("Connecting from LocalMachine...\n");
}
// Create NatNet Client
iResult = CreateClient(iConnectionType);
if(iResult != ErrorCode_OK)
{
printf("Error initializing client. See log for details. Exiting");
return 1;
}
else
{
printf("Client initialized and ready.\n");
}
// send/receive test request
printf("[SampleClient] Sending Test Request\n");
void* response;
int nBytes;
iResult = theClient->SendMessageAndWait("TestRequest", &response, &nBytes);
if (iResult == ErrorCode_OK)
{
printf("[SampleClient] Received: %s", (char*)response);
}
// Retrieve Data Descriptions from server
printf("\n\n[SampleClient] Requesting Data Descriptions...");
sDataDescriptions* pDataDefs = NULL;
int nBodies = theClient->GetDataDescriptions(&pDataDefs);
if(!pDataDefs)
{
printf("[SampleClient] Unable to retrieve Data Descriptions.");
}
else
{
printf("[SampleClient] Received %d Data Descriptions:\n", pDataDefs->nDataDescriptions );
for(int i=0; i < pDataDefs->nDataDescriptions; i++)
{
printf("Data Description # %d (type=%d)\n", i, pDataDefs->arrDataDescriptions[i].type);
if(pDataDefs->arrDataDescriptions[i].type == Descriptor_MarkerSet)
{
// MarkerSet
sMarkerSetDescription* pMS = pDataDefs->arrDataDescriptions[i].Data.MarkerSetDescription;
printf("MarkerSet Name : %s\n", pMS->szName);
for(int i=0; i < pMS->nMarkers; i++)
printf("%s\n", pMS->szMarkerNames[i]);
}
else if(pDataDefs->arrDataDescriptions[i].type == Descriptor_RigidBody)
{
// RigidBody
sRigidBodyDescription* pRB = pDataDefs->arrDataDescriptions[i].Data.RigidBodyDescription;
printf("RigidBody Name : %s\n", pRB->szName);
printf("RigidBody ID : %d\n", pRB->ID);
printf("RigidBody Parent ID : %d\n", pRB->parentID);
printf("Parent Offset : %3.2f,%3.2f,%3.2f\n", pRB->offsetx, pRB->offsety, pRB->offsetz);
}
else if(pDataDefs->arrDataDescriptions[i].type == Descriptor_Skeleton)
{
// Skeleton
sSkeletonDescription* pSK = pDataDefs->arrDataDescriptions[i].Data.SkeletonDescription;
printf("Skeleton Name : %s\n", pSK->szName);
printf("Skeleton ID : %d\n", pSK->skeletonID);
printf("RigidBody (Bone) Count : %d\n", pSK->nRigidBodies);
for(int j=0; j < pSK->nRigidBodies; j++)
{
sRigidBodyDescription* pRB = &pSK->RigidBodies[j];
printf(" RigidBody Name : %s\n", pRB->szName);
printf(" RigidBody ID : %d\n", pRB->ID);
printf(" RigidBody Parent ID : %d\n", pRB->parentID);
printf(" Parent Offset : %3.2f,%3.2f,%3.2f\n", pRB->offsetx, pRB->offsety, pRB->offsetz);
}
}
else if(pDataDefs->arrDataDescriptions[i].type == Descriptor_ForcePlate)
{
// Force Plate
sForcePlateDescription* pFP = pDataDefs->arrDataDescriptions[i].Data.ForcePlateDescription;
printf("Force Plate ID : %d\n", pFP->ID);
printf("Force Plate Serial : %s\n", pFP->strSerialNo);
printf("Force Plate Width : %3.2f\n", pFP->fWidth);
printf("Force Plate Length : %3.2f\n", pFP->fLength);
printf("Force Plate Electrical Center Offset (%3.3f, %3.3f, %3.3f)\n", pFP->fOriginX,pFP->fOriginY, pFP->fOriginZ);
for(int iCorner=0; iCorner<4; iCorner++)
printf("Force Plate Corner %d : (%3.4f, %3.4f, %3.4f)\n", iCorner, pFP->fCorners[iCorner][0],pFP->fCorners[iCorner][1],pFP->fCorners[iCorner][2]);
printf("Force Plate Type : %d\n", pFP->iPlateType);
printf("Force Plate Data Type : %d\n", pFP->iChannelDataType);
printf("Force Plate Channel Count : %d\n", pFP->nChannels);
for(int iChannel=0; iChannel<pFP->nChannels; iChannel++)
printf("\tChannel %d : %s\n", iChannel, pFP->szChannelNames[iChannel]);
}
else
{
printf("Unknown data type.");
// Unknown
}
}
}
// Create data file for writing received stream into
char szFile[MAX_PATH];
char szFolder[MAX_PATH];
GetCurrentDirectory(MAX_PATH, szFolder);
if(argc > 3)
sprintf(szFile, "%s\\%s", szFolder, argv[3]);
else
sprintf(szFile, "%s\\Client-output.pts",szFolder);
fp = fopen(szFile, "w");
if(!fp)
{
printf("error opening output file %s. Exiting.", szFile);
exit(1);
}
if(pDataDefs)
_WriteHeader(fp, pDataDefs);
// Ready to receive marker stream!
printf("\nClient is connected to server and listening for data...\n");
int c;
bool bExit = false;
while(c =_getch())
{
switch(c)
{
case 'q':
bExit = true;
break;
case 'r':
resetClient();
break;
case 'p':
sServerDescription ServerDescription;
memset(&ServerDescription, 0, sizeof(ServerDescription));
theClient->GetServerDescription(&ServerDescription);
if(!ServerDescription.HostPresent)
{
printf("Unable to connect to server. Host not present. Exiting.");
return 1;
}
break;
case 'f':
{
sFrameOfMocapData* pData = theClient->GetLastFrameOfData();
printf("Most Recent Frame: %d", pData->iFrame);
}
break;
case 'm': // change to multicast
iConnectionType = ConnectionType_Multicast;
iResult = CreateClient(iConnectionType);
if(iResult == ErrorCode_OK)
printf("Client connection type changed to Multicast.\n\n");
else
printf("Error changing client connection type to Multicast.\n\n");
break;
case 'u': // change to unicast
iConnectionType = ConnectionType_Unicast;
iResult = CreateClient(iConnectionType);
if(iResult == ErrorCode_OK)
printf("Client connection type changed to Unicast.\n\n");
else
printf("Error changing client connection type to Unicast.\n\n");
break;
case 'c' : // connect
iResult = CreateClient(iConnectionType);
break;
case 'd' : // disconnect
// note: applies to unicast connections only - indicates to Motive to stop sending packets to that client endpoint
iResult = theClient->SendMessageAndWait("Disconnect", &response, &nBytes);
if (iResult == ErrorCode_OK)
printf("[SampleClient] Disconnected");
break;
default:
break;
}
if(bExit)
break;
}
// Done - clean up.
theClient->Uninitialize();
_WriteFooter(fp);
fclose(fp);
return ErrorCode_OK;
}
// Establish a NatNet Client connection
int CreateClient(int iConnectionType)
{
// release previous server
if(theClient)
{
theClient->Uninitialize();
delete theClient;
}
// create NatNet client
theClient = new NatNetClient(iConnectionType);
// set the callback handlers
theClient->SetVerbosityLevel(Verbosity_Warning);
theClient->SetMessageCallback(MessageHandler);
theClient->SetDataCallback( DataHandler, theClient ); // this function will receive data from the server
// [optional] use old multicast group
//theClient->SetMulticastAddress("224.0.0.1");
// print version info
unsigned char ver[4];
theClient->NatNetVersion(ver);
printf("NatNet Sample Client (NatNet ver. %d.%d.%d.%d)\n", ver[0], ver[1], ver[2], ver[3]);
// Init Client and connect to NatNet server
// to use NatNet default port assignments
int retCode = theClient->Initialize(szMyIPAddress, szServerIPAddress);
// to use a different port for commands and/or data:
//int retCode = theClient->Initialize(szMyIPAddress, szServerIPAddress, MyServersCommandPort, MyServersDataPort);
if (retCode != ErrorCode_OK)
{
printf("Unable to connect to server. Error code: %d. Exiting", retCode);
return ErrorCode_Internal;
}
else
{
// get # of analog samples per mocap frame of data
void* pResult;
int ret = 0;
int nBytes = 0;
ret = theClient->SendMessageAndWait("AnalogSamplesPerMocapFrame", &pResult, &nBytes);
if (ret == ErrorCode_OK)
{
analogSamplesPerMocapFrame = *((int*)pResult);
printf("Analog Samples Per Mocap Frame : %d", analogSamplesPerMocapFrame);
}
// print server info
sServerDescription ServerDescription;
memset(&ServerDescription, 0, sizeof(ServerDescription));
theClient->GetServerDescription(&ServerDescription);
if(!ServerDescription.HostPresent)
{
printf("Unable to connect to server. Host not present. Exiting.");
return 1;
}
printf("[SampleClient] Server application info:\n");
printf("Application: %s (ver. %d.%d.%d.%d)\n", ServerDescription.szHostApp, ServerDescription.HostAppVersion[0],
ServerDescription.HostAppVersion[1],ServerDescription.HostAppVersion[2],ServerDescription.HostAppVersion[3]);
printf("NatNet Version: %d.%d.%d.%d\n", ServerDescription.NatNetVersion[0], ServerDescription.NatNetVersion[1],
ServerDescription.NatNetVersion[2], ServerDescription.NatNetVersion[3]);
printf("Client IP:%s\n", szMyIPAddress);
printf("Server IP:%s\n", szServerIPAddress);
printf("Server Name:%s\n\n", ServerDescription.szHostComputerName);
}
return ErrorCode_OK;
}
// DataHandler receives data from the server
void __cdecl DataHandler(sFrameOfMocapData* data, void* pUserData)
{
NatNetClient* pClient = (NatNetClient*) pUserData;
if(fp)
_WriteFrame(fp,data);
int i=0;
printf("FrameID : %d\n", data->iFrame);
printf("Timestamp : %3.2lf\n", data->fTimestamp);
printf("Latency : %3.2lf\n", data->fLatency);
// FrameOfMocapData params
bool bIsRecording = ((data->params & 0x01)!=0);
bool bTrackedModelsChanged = ((data->params & 0x02)!=0);
if(bIsRecording)
printf("RECORDING\n");
if(bTrackedModelsChanged)
printf("Models Changed.\n");
// timecode - for systems with an eSync and SMPTE timecode generator - decode to values
int hour, minute, second, frame, subframe;
bool bValid = pClient->DecodeTimecode(data->Timecode, data->TimecodeSubframe, &hour, &minute, &second, &frame, &subframe);
// decode to friendly string
char szTimecode[128] = "";
pClient->TimecodeStringify(data->Timecode, data->TimecodeSubframe, szTimecode, 128);
printf("Timecode : %s\n", szTimecode);
// Other Markers
printf("Other Markers [Count=%d]\n", data->nOtherMarkers);
for(i=0; i < data->nOtherMarkers; i++)
{
printf("Other Marker %d : %3.2f\t%3.2f\t%3.2f\n",
i,
data->OtherMarkers[i][0],
data->OtherMarkers[i][1],
data->OtherMarkers[i][2]);
}
// Rigid Bodies
printf("Rigid Bodies [Count=%d]\n", data->nRigidBodies);
for(i=0; i < data->nRigidBodies; i++)
{
// params
// 0x01 : bool, rigid body was successfully tracked in this frame
bool bTrackingValid = data->RigidBodies[i].params & 0x01;
printf("Rigid Body [ID=%d Error=%3.2f Valid=%d]\n", data->RigidBodies[i].ID, data->RigidBodies[i].MeanError, bTrackingValid);
printf("\tx\ty\tz\tqx\tqy\tqz\tqw\n");
printf("\t%3.2f\t%3.2f\t%3.2f\t%3.2f\t%3.2f\t%3.2f\t%3.2f\n",
data->RigidBodies[i].x,
data->RigidBodies[i].y,
data->RigidBodies[i].z,
data->RigidBodies[i].qx,
data->RigidBodies[i].qy,
data->RigidBodies[i].qz,
data->RigidBodies[i].qw);
printf("\tRigid body markers [Count=%d]\n", data->RigidBodies[i].nMarkers);
for(int iMarker=0; iMarker < data->RigidBodies[i].nMarkers; iMarker++)
{
printf("\t\t");
if(data->RigidBodies[i].MarkerIDs)
printf("MarkerID:%d", data->RigidBodies[i].MarkerIDs[iMarker]);
if(data->RigidBodies[i].MarkerSizes)
printf("\tMarkerSize:%3.2f", data->RigidBodies[i].MarkerSizes[iMarker]);
if(data->RigidBodies[i].Markers)
printf("\tMarkerPos:%3.2f,%3.2f,%3.2f\n" ,
data->RigidBodies[i].Markers[iMarker][0],
data->RigidBodies[i].Markers[iMarker][1],
data->RigidBodies[i].Markers[iMarker][2]);
}
}
// skeletons
printf("Skeletons [Count=%d]\n", data->nSkeletons);
for(i=0; i < data->nSkeletons; i++)
{
sSkeletonData skData = data->Skeletons[i];
printf("Skeleton [ID=%d Bone count=%d]\n", skData.skeletonID, skData.nRigidBodies);
for(int j=0; j< skData.nRigidBodies; j++)
{
sRigidBodyData rbData = skData.RigidBodyData[j];
printf("Bone %d\t%3.2f\t%3.2f\t%3.2f\t%3.2f\t%3.2f\t%3.2f\t%3.2f\n",
rbData.ID, rbData.x, rbData.y, rbData.z, rbData.qx, rbData.qy, rbData.qz, rbData.qw );
printf("\tRigid body markers [Count=%d]\n", rbData.nMarkers);
for(int iMarker=0; iMarker < rbData.nMarkers; iMarker++)
{
printf("\t\t");
if(rbData.MarkerIDs)
printf("MarkerID:%d", rbData.MarkerIDs[iMarker]);
if(rbData.MarkerSizes)
printf("\tMarkerSize:%3.2f", rbData.MarkerSizes[iMarker]);
if(rbData.Markers)
printf("\tMarkerPos:%3.2f,%3.2f,%3.2f\n" ,
data->RigidBodies[i].Markers[iMarker][0],
data->RigidBodies[i].Markers[iMarker][1],
data->RigidBodies[i].Markers[iMarker][2]);
}
}
}
// labeled markers
bool bOccluded; // marker was not visible (occluded) in this frame
bool bPCSolved; // reported position provided by point cloud solve
bool bModelSolved; // reported position provided by model solve
printf("Labeled Markers [Count=%d]\n", data->nLabeledMarkers);
for(i=0; i < data->nLabeledMarkers; i++)
{
bOccluded = ((data->LabeledMarkers[i].params & 0x01)!=0);
bPCSolved = ((data->LabeledMarkers[i].params & 0x02)!=0);
bModelSolved = ((data->LabeledMarkers[i].params & 0x04)!=0);
sMarker marker = data->LabeledMarkers[i];
int modelID, markerID;
theClient->DecodeID(marker.ID, &modelID, &markerID);
printf("Labeled Marker [ModelID=%d, MarkerID=%d, Occluded=%d, PCSolved=%d, ModelSolved=%d] [size=%3.2f] [pos=%3.2f,%3.2f,%3.2f]\n",
modelID, markerID, bOccluded, bPCSolved, bModelSolved, marker.size, marker.x, marker.y, marker.z);
}
// force plates
if(data->nForcePlates==0)
{
printf("No Plates\n");
}
printf("Force Plate [Count=%d]\n", data->nForcePlates);
for(int iPlate=0; iPlate < data->nForcePlates; iPlate++)
{
printf("Force Plate %d\n", data->ForcePlates[iPlate].ID);
for(int iChannel=0; iChannel < data->ForcePlates[iPlate].nChannels; iChannel++)
{
printf("\tChannel %d:\t", iChannel);
if(data->ForcePlates[iPlate].ChannelData[iChannel].nFrames == 0)
{
printf("\tEmpty Frame\n");
}
else if(data->ForcePlates[iPlate].ChannelData[iChannel].nFrames != analogSamplesPerMocapFrame)
{
printf("\tPartial Frame [Expected:%d Actual:%d]\n", analogSamplesPerMocapFrame, data->ForcePlates[iPlate].ChannelData[iChannel].nFrames);
}
for(int iSample=0; iSample < data->ForcePlates[iPlate].ChannelData[iChannel].nFrames; iSample++)
printf("%3.2f\t", data->ForcePlates[iPlate].ChannelData[iChannel].Values[iSample]);
printf("\n");
}
}
}
// MessageHandler receives NatNet error/debug messages
void __cdecl MessageHandler(int msgType, char* msg)
{
printf("\n%s\n", msg);
}
/* File writing routines */
void _WriteHeader(FILE* fp, sDataDescriptions* pBodyDefs)
{
int i=0;
if(!pBodyDefs->arrDataDescriptions[0].type == Descriptor_MarkerSet)
return;
sMarkerSetDescription* pMS = pBodyDefs->arrDataDescriptions[0].Data.MarkerSetDescription;
fprintf(fp, "<MarkerSet>\n\n");
fprintf(fp, "<Name>\n%s\n</Name>\n\n", pMS->szName);
fprintf(fp, "<Markers>\n");
for(i=0; i < pMS->nMarkers; i++)
{
fprintf(fp, "%s\n", pMS->szMarkerNames[i]);
}
fprintf(fp, "</Markers>\n\n");
fprintf(fp, "<Data>\n");
fprintf(fp, "Frame#\t");
for(i=0; i < pMS->nMarkers; i++)
{
fprintf(fp, "M%dX\tM%dY\tM%dZ\t", i, i, i);
}
fprintf(fp,"\n");
}
void _WriteFrame(FILE* fp, sFrameOfMocapData* data)
{
fprintf(fp, "%d", data->iFrame);
for(int i =0; i < data->MocapData->nMarkers; i++)
{
fprintf(fp, "\t%.5f\t%.5f\t%.5f", data->MocapData->Markers[i][0], data->MocapData->Markers[i][1], data->MocapData->Markers[i][2]);
}
fprintf(fp, "\n");
}
void _WriteFooter(FILE* fp)
{
fprintf(fp, "</Data>\n\n");
fprintf(fp, "</MarkerSet>\n");
}
void resetClient()
{
int iSuccess;
printf("\n\nre-setting Client\n\n.");
iSuccess = theClient->Uninitialize();
if(iSuccess != 0)
printf("error un-initting Client\n");
iSuccess = theClient->Initialize(szMyIPAddress, szServerIPAddress);
if(iSuccess != 0)
printf("error re-initting Client\n");
}
Very likely NatNetClient() or client->Initialize() is creating a new thread in the background. Since I do not have access to their code, I can't validate reliably.
You can either create a synchronous look in the main and always send and receive messages via NatNetClient::SendMessageAndWait
or
To receive data asyncronously, you need to figure out a way to poll on stdin (for getch) and also wait on a lock simultaneously. I am not sure how to do this on Microsoft console. If you figure that out, then when the handler gets control, de-queue the message into a link-list and wakup a mutex to notify the main.
The NatNet sample spins off a different thread for handling the data using the DataHandler function. The following line is where this happens:
theClient->SetDataCallback( DataHandler, theClient );
I would recommend doing the processing strictly in the DataHandler function. However, if talking between threads in necessary, then it's worth looking into the C++ 11 libraries
#include <threads>
#include <mutex>
Specifically mutex is used to lock and unlock threads in C++. You could create a global variable and write to it using the DataHandler function, then use that global variable in your main function. The problem is that you may read and write the data at the same time, because main and DataHandler are on different threads. So you can use the mutex library to lock a thread while reading or writing that global variable (meaning only that thread is allowed to run while doing that process).
Note: The NatNet sample actually uses a UDP transmission not TCP.

Socket class Error

ListenSocket.h
// class does not contain WSASTARTUP () and WSACLEANUP ()
#ifndef LISTENTHREAD_H
#define LISTENTHREAD_H
#include "includes.h"
#include "LOGMSGs.h"
// 1, CListenSocket: class is used to create the listener thread local variable.
// This class can be reused. When you call Close () is closed, re-calling Open () the new listening port. But the system did not use the feature.
class CListenSocket
{
public:
// main method:
// BIND each object only to a port.
CListenSocket(u_short nPort, int nSndSize = 0);
// to release SOCKET
~CListenSocket(){};
// Create server listening SOCKET, specific options see the code. Fails to return false.
bool Open(); // call can be repeated
// error return INVALID_SOCKET
SOCKET Accept(u_long & nClientIP);
// repeated calls. Usually not, can be used to take the initiative to close the SOCKET.
// close the re-call after Open () re-use the object.
void Close(); // call can be repeated
bool IsOpen() { return m_bState; }
bool Rebuild();
public:
SOCKET Socket() { return m_sockListen; }
protected:
// main member variables:
const u_short m_nPort;
const int m_nSndBuf;
SOCKET m_sockListen;
// network status is normal sign.
// When the value is false that the object is not available. May not have Open (), may also be a network error.
bool m_bState;
time_t m_tCloseTime; // SOCKET last closed the time delay for the automatic re-SOCKET
};
#endif // LISTENTHREAD_H
ListenSocket.cpp
#include "ListenSocket.h"
long s_nSocketCount = 0;
int REBUILDLISTENDELAYSEC;
CListenSocket::CListenSocket(u_short nPort, int nSndBuf /*= 0*/) // 0: Default
: m_nPort(nPort), m_nSndBuf(nSndBuf)
{
m_sockListen = INVALID_SOCKET;
m_bState = false;
// m_nPort = nPort;
m_tCloseTime = 0;
}
// Error returned INVALID_SOCKET
SOCKET CListenSocket::Accept(u_long & nClientIP)
{
/*
// Reconstruction SOCKET
if(!m_bState)
{
if(clock() < m_tCloseTime + REBUILDLISTENDELAYSEC*CLOCKS_PER_SEC)
return INVALID_SOCKET;
else
{
LOGMSG("Anti-crash system start listening SOCKET [%d] re under construction...", m_nPort);
if(Open())
{
LOGMSG("... listen SOCKET reconstruction success.");
PrintText("Listen SOCKET [%d] failed to rebuild SOCKET success. Server continues to run in the ...", m_nPort);
}
else
{
Error("... listen SOCKET reconstruction has failed. Server will not accept new connections");
PrintText("Listen SOCKET [%d] error, [%d] seconds after the re-SOCKET. Server continues to run in the ...", m_nPort, REBUILDLISTENDELAYSEC); // nDelaySec);
}
m_tCloseTime = clock();
}
}
//*/
if(!m_bState)
{
Error("ACCEPT inner exception a1");
return INVALID_SOCKET;
}
// ACCEPT
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
int len = sizeof(addr);
SOCKET newsock = accept(m_sockListen, (sockaddr*)&addr, (int*)&len); // receive to the other side of the map, you can use
#ifdef PROFILE_X
// Analysis Accept speed (cycle speed)
const int nTimes2 = ACCEPTPROFILESEC; // Statistics once every 30 seconds the speed ACCEPT
static clock_t tNextTime2 = clock() + nTimes2 * CLOCKS_PER_SEC; //? Only one monitor thread, no sharing violation
static long nCount2 = 0; //? Only one monitor thread, no sharing violation
if(clock() >= tNextTime2)
{
PrintText("Each [%d] seconds to execute a [%d] times Accept ()", nTimes2, InterlockedExchange(&nCount2, 0));
tNextTime2 = clock() + nTimes2 * CLOCKS_PER_SEC;
}
else
{
InterlockedIncrement(&nCount2);
}
#endif // PROFILE
if(newsock == INVALID_SOCKET)
{
// Network Error
int err = WSAGetLastError();
if(err != WSAEWOULDBLOCK)
{
PrintText("Listen SOCKET %d failed, %s seconds after the re-SOCKET.", m_nPort, REBUILDLISTENDELAYSEC);
Error("Listen SOCKET [%d] failed [%d], [%s] seconds after the re-SOCKET.", m_nPort, err, REBUILDLISTENDELAYSEC);
Close();
}
else
Error("ACCEPT inner exception a2");
return INVALID_SOCKET;
}
else
{
nClientIP = addr.sin_addr.S_un.S_addr;
InterlockedIncrement(&s_nSocketCount);
}
// Check whether the SOCKET closed
fd_set readmask;
FD_ZERO(&readmask);
FD_SET(newsock, &readmask);
struct timeval timeout = {0, 0};
/*
char nTemp;
if(select(FD_SETSIZE, &readmask, (fd_set *) 0, (fd_set *) 0, &timeout)
&& recv(newsock, &nTemp, 1, MSG_PEEK) == 0)
{
#ifdef ALPHA_X
LOGMSG("ACCEPT a new SOCKET is invalid .");
#endif
closesocket(newsock);
InterlockedDecrement(&s_nSocketCount);
return INVALID_SOCKET;
}
//else*/
//*
fd_set exceptmask;
FD_ZERO(&exceptmask);
FD_SET(newsock, &exceptmask);
int ret = select(FD_SETSIZE, &readmask, (fd_set *) 0, (fd_set *) &exceptmask, &timeout);
if(ret < 0)
{
Error("ACCEPT a new SOCKET is invalid . can't read"); // Not trigger
closesocket(newsock);
InterlockedDecrement(&s_nSocketCount);
return INVALID_SOCKET;
}
else if(ret > 0)
{
if(FD_ISSET(newsock, &exceptmask))
{
LOGMSG("ACCEPT a new SOCKET is invalid.except"); // Not trigger
closesocket(newsock);
InterlockedDecrement(&s_nSocketCount);
return INVALID_SOCKET;
}
else if(FD_ISSET(newsock, &readmask))
{
char nTemp;
if(recv(newsock, &nTemp, 1, MSG_PEEK) == 0)
{
#ifdef ALPHA_X
LOGMSG("ACCEPT a new SOCKET is invalid. recv==0"); // Not trigger
#endif
closesocket(newsock);
InterlockedDecrement(&s_nSocketCount);
return INVALID_SOCKET;
}
}
}
//*/
#ifdef PROFILE_X
// analysis Accept speed (received valid SOCKET)
const int nTimes = ACCEPTPROFILESEC; // Statistics once every 10 seconds the speed ACCEPT
static clock_t tNextTime = clock() + nTimes * CLOCKS_PER_SEC; //? Only one monitor thread, no sharing violation
static long nCount = 0; //? Only one monitor thread, no sharing violation
if(clock() >= tNextTime)
{
LOGPROFILE("Port [%d] for every [%d] seconds, the successful implementation of the [%d] times Accept()",
m_nPort, nTimes, InterlockedExchange(&nCount, 0));
tNextTime = clock() + nTimes * CLOCKS_PER_SEC;
}
else
{
InterlockedIncrement(&nCount);
}
#endif // PROFILE
return newsock;
}
Main.cpp
#include "includes.h"
#include "IniFile.h"
#include "LOGMSGs.h"
#include "ListenSocket.h"
CListenSocket Sock(9985);
int main()
{
Sock.Open();
if(!Sock.Open())
{
Sock.Rebuild();
}
if(Sock.IsOpen())
PrintText("okey");
Sock.Socket();
u_long ip;
Sock.Accept(ip);
}
but i always got this error : ACCEPT inner exception a2 while it should work anyclue why?
CListenSocket Sock(9985);
int main()
{
Sock.Open();
if(!Sock.Open())
/* I think you meant 'IsOpen()' */
{
Sock.Rebuild();
}
if(Sock.IsOpen())
PrintText("okey");
Sock.Socket();
u_long ip;
Sock.Accept(ip);
}
Incidentally, this code sure reads funny. It feels like a generic toolkit programmed without a specific goal in mind. Maybe I'm missing it, but I have to think you'd have better results if you just wrote the network code that actually needed, and then abstract out the common bits into some helper routines later. There's no point in trying too hard to make the be-all and end-all network helper library, but there is a huge point in making tools that collapse common cases.
Feel free to ignore that last paragraph if you know what you're doing :) but if you're just starting out, I'd like to suggest writing a few smaller clients and servers, and then try writing your abstraction layer.