void test_allocmsg_reqrep () { int rc; int req; void *p; struct nn_iovec iov; struct nn_msghdr hdr; /* Try to create an oversized message. */ p = nn_allocmsg (-1, 0); nn_assert (!p && nn_errno () == ENOMEM); p = nn_allocmsg (-1000, 0); nn_assert (!p && nn_errno () == ENOMEM); /* Try to create a message of unknown type. */ p = nn_allocmsg (100, 333); nn_assert (!p && nn_errno () == EINVAL); /* Create a socket. */ req = test_socket (AF_SP_RAW, NN_REQ); /* Make send fail and check whether the zero-copy buffer is left alone rather than deallocated. */ p = nn_allocmsg (100, 0); nn_assert (p); rc = nn_send (req, &p, NN_MSG, NN_DONTWAIT); nn_assert (rc < 0); errno_assert (nn_errno () == EAGAIN); memset (p, 0, 100); rc = nn_freemsg (p); errno_assert (rc == 0); /* Same thing with nn_sendmsg(). */ p = nn_allocmsg (100, 0); nn_assert (p); iov.iov_base = &p; iov.iov_len = NN_MSG; memset (&hdr, 0, sizeof (hdr)); hdr.msg_iov = &iov; hdr.msg_iovlen = 1; nn_sendmsg (req, &hdr, NN_DONTWAIT); errno_assert (nn_errno () == EAGAIN); memset (p, 0, 100); rc = nn_freemsg (p); errno_assert (rc == 0); /* Clean up. */ test_close (req); }
inline void *allocmsg (size_t size, int type) { void *msg = nn_allocmsg (size, type); if (nn_slow (!msg)) throw nn::exception (); return msg; }
int nn_ws_send (int s, const void *msg, size_t len, uint8_t msg_type, int flags) { int rc; struct nn_iovec iov; struct nn_msghdr hdr; struct nn_cmsghdr *cmsg; size_t cmsgsz; iov.iov_base = (void*) msg; iov.iov_len = len; cmsgsz = NN_CMSG_SPACE (sizeof (msg_type)); cmsg = nn_allocmsg (cmsgsz, 0); if (cmsg == NULL) return -1; cmsg->cmsg_level = NN_WS; cmsg->cmsg_type = NN_WS_HDR_OPCODE; cmsg->cmsg_len = NN_CMSG_LEN (sizeof (msg_type)); memcpy (NN_CMSG_DATA (cmsg), &msg_type, sizeof (msg_type)); hdr.msg_iov = &iov; hdr.msg_iovlen = 1; hdr.msg_control = &cmsg; hdr.msg_controllen = NN_MSG; rc = nn_sendmsg (s, &hdr, flags); return rc; }
void send_ctxts(int socket, const std::vector<Ctxt> &ctxts) { std::vector<void *> data; std::vector<size_t> lens; std::stringstream sstream; MDL::Timer timer; for (auto &ctxt : ctxts) { sstream.str(""); sstream << ctxt; auto str = sstream.str(); auto len = str.size(); auto tmp = nn_allocmsg(len, 0); std::memcpy(tmp, str.c_str(), len); data.push_back(tmp); lens.push_back(len); } MDL::net::msg_header *hdr; MDL::net::make_header(&hdr, lens); nn_send(socket, hdr, MDL::net::header_size(hdr), 0); // send lens nn_recv(socket, NULL, 0, 0); // recv ok struct nn_msghdr nn_hdr; MDL::net::make_nn_header(&nn_hdr, data, lens); timer.start(); nn_sendmsg(socket, &nn_hdr, 0); // send data timer.end(); printf("sent %zd ctxt %f s\n", ctxts.size(), timer.second()); nn_recv(socket, NULL, 0, 0); MDL::net::free_header(&nn_hdr, true); }
static void* serialize_control_message(CONTROL_MESSAGE * msg, int32_t * theMessageSize) { void * result; int32_t msg_size = ControlMessage_ToByteArray(msg, NULL, 0); if (msg_size < 0) { LogError("unable to serialize a control message"); result = NULL; } else { result = nn_allocmsg(msg_size, 0); if (result == NULL) { LogError("unable to allocate a control message"); } else { unsigned char *nn_msg_bytes = (unsigned char *)result; ControlMessage_ToByteArray(msg, nn_msg_bytes, msg_size); *theMessageSize = msg_size; } } return result; }
int zmq_msg_init_size (zmq_msg_t *msg, size_t size) { struct nn_zmqmsg *zmqmsg; zmqmsg = (struct nn_zmqmsg*) msg; zmqmsg->size = size; zmqmsg->data = nn_allocmsg (size, 0); return zmqmsg->data ? 0 : -1; }
void test_reallocmsg_reqrep () { int rc; int req; int rep; void *p; void *p2; /* Create sockets. */ req = nn_socket (AF_SP, NN_REQ); rep = nn_socket (AF_SP, NN_REP); rc = nn_bind (rep, "inproc://test"); errno_assert (rc >= 0); rc = nn_connect (req, "inproc://test"); errno_assert (rc >= 0); /* Create message, make sure we handle overflow. */ p = nn_allocmsg (100, 0); nn_assert (p); p2 = nn_reallocmsg (p, -1000); errno_assert (nn_errno () == ENOMEM); nn_assert (p2 == NULL); /* Realloc to fit data size. */ memcpy (p, "Hello World!", 12); p = nn_reallocmsg (p, 12); nn_assert (p); rc = nn_send (req, &p, NN_MSG, 0); errno_assert (rc == 12); /* Receive request and send response. */ rc = nn_recv (rep, &p, NN_MSG, 0); errno_assert (rc == 12); rc = nn_send (rep, &p, NN_MSG, 0); errno_assert (rc == 12); /* Receive response and free message. */ rc = nn_recv (req, &p, NN_MSG, 0); errno_assert (rc == 12); rc = memcmp (p, "Hello World!", 12); nn_assert (rc == 0); rc = nn_freemsg (p); errno_assert (rc == 0); /* Clean up. */ nn_close (req); nn_close (rep); }
int zmq_msg_copy (zmq_msg_t *dest, zmq_msg_t *src) { struct nn_zmqmsg *zmqdest; struct nn_zmqmsg *zmqsrc; /* In nanomsg this functionality is not exposed to the user. Let's do an actual copy of the message instead. */ zmqdest = (struct nn_zmqmsg*) dest; zmqsrc = (struct nn_zmqmsg*) src; zmqdest->size = zmqsrc->size; zmqdest->data = nn_allocmsg (zmqdest->size, 0); if (!zmqdest->data) return -1; memcpy (zmqdest->data, zmqsrc->data, zmqdest->size); return 0; }
void test_reallocmsg_pubsub () { int rc; int pub; int sub1; int sub2; void *p; void *p1; void *p2; /* Create sockets. */ pub = nn_socket (AF_SP, NN_PUB); sub1 = nn_socket (AF_SP, NN_SUB); sub2 = nn_socket (AF_SP, NN_SUB); rc = nn_bind (pub, "inproc://test"); errno_assert (rc >= 0); rc = nn_connect (sub1, "inproc://test"); errno_assert (rc >= 0); rc = nn_connect (sub2, "inproc://test"); errno_assert (rc >= 0); rc = nn_setsockopt (sub1, NN_SUB, NN_SUB_SUBSCRIBE, "", 0); errno_assert (rc == 0); rc = nn_setsockopt (sub2, NN_SUB, NN_SUB_SUBSCRIBE, "", 0); errno_assert (rc == 0); /* Publish message. */ p = nn_allocmsg (12, 0); nn_assert (p); memcpy (p, "Hello World!", 12); rc = nn_send (pub, &p, NN_MSG, 0); errno_assert (rc == 12); /* Receive messages, both messages are the same object with inproc. */ rc = nn_recv (sub1, &p1, NN_MSG, 0); errno_assert (rc == 12); rc = nn_recv (sub2, &p2, NN_MSG, 0); errno_assert (rc == 12); nn_assert (p1 == p2); rc = memcmp (p1, "Hello World!", 12); nn_assert (rc == 0); rc = memcmp (p2, "Hello World!", 12); nn_assert (rc == 0); /* Reallocate one message, both messages shouldn't be the same object anymore. */ p1 = nn_reallocmsg (p1, 15); errno_assert (p1); nn_assert (p1 != p2); memcpy ((char*)p1 + 12, " 42", 3); rc = memcmp (p1, "Hello World! 42", 15); nn_assert (rc == 0); /* Release messages. */ rc = nn_freemsg (p1); errno_assert (rc == 0); rc = nn_freemsg (p2); errno_assert (rc == 0); /* Clean up. */ nn_close (sub2); nn_close (sub1); nn_close (pub); }
BROKER_RESULT Broker_Publish(BROKER_HANDLE broker, MODULE_HANDLE source, MESSAGE_HANDLE message) { BROKER_RESULT result; /*Codes_SRS_BROKER_13_030: [If broker or message is NULL the function shall return BROKER_INVALIDARG.]*/ if (broker == NULL || source == NULL || message == NULL) { result = BROKER_INVALIDARG; LogError("Broker handle, source, and/or message handle is NULL"); } else { BROKER_HANDLE_DATA* broker_data = (BROKER_HANDLE_DATA*)broker; /*Codes_SRS_BROKER_17_022: [ Broker_Publish shall Lock the modules lock. ]*/ if (Lock(broker_data->modules_lock) != LOCK_OK) { /*Codes_SRS_BROKER_13_053: [This function shall return BROKER_ERROR if an underlying API call to the platform causes an error or BROKER_OK otherwise.]*/ LogError("Lock on broker_data->modules_lock failed"); result = BROKER_ERROR; } else { int32_t msg_size; int32_t buf_size; /*Codes_SRS_BROKER_17_007: [ Broker_Publish shall clone the message. ]*/ MESSAGE_HANDLE msg = Message_Clone(message); /*Codes_SRS_BROKER_17_008: [ Broker_Publish shall serialize the message. ]*/ msg_size = Message_ToByteArray(message, NULL, 0); if (msg_size < 0) { /*Codes_SRS_BROKER_13_053: [This function shall return BROKER_ERROR if an underlying API call to the platform causes an error or BROKER_OK otherwise.]*/ LogError("unable to serialize a message [%p]", msg); Message_Destroy(msg); result = BROKER_ERROR; } else { /*Codes_SRS_BROKER_17_025: [ Broker_Publish shall allocate a nanomsg buffer the size of the serialized message + sizeof(MODULE_HANDLE). ]*/ buf_size = msg_size + sizeof(MODULE_HANDLE); void* nn_msg = nn_allocmsg(buf_size, 0); if (nn_msg == NULL) { /*Codes_SRS_BROKER_13_053: [This function shall return BROKER_ERROR if an underlying API call to the platform causes an error or BROKER_OK otherwise.]*/ LogError("unable to serialize a message [%p]", msg); result = BROKER_ERROR; } else { /*Codes_SRS_BROKER_17_026: [ Broker_Publish shall copy source into the beginning of the nanomsg buffer. ]*/ unsigned char *nn_msg_bytes = (unsigned char *)nn_msg; memcpy(nn_msg_bytes, &source, sizeof(MODULE_HANDLE)); /*Codes_SRS_BROKER_17_027: [ Broker_Publish shall serialize the message into the remainder of the nanomsg buffer. ]*/ nn_msg_bytes += sizeof(MODULE_HANDLE); Message_ToByteArray(message, nn_msg_bytes, msg_size); /*Codes_SRS_BROKER_17_010: [ Broker_Publish shall send a message on the publish_socket. ]*/ int nbytes = nn_send(broker_data->publish_socket, &nn_msg, NN_MSG, 0); if (nbytes != buf_size) { /*Codes_SRS_BROKER_13_053: [This function shall return BROKER_ERROR if an underlying API call to the platform causes an error or BROKER_OK otherwise.]*/ LogError("unable to send a message [%p]", msg); /*Codes_SRS_BROKER_17_012: [ Broker_Publish shall free the message. ]*/ nn_freemsg(nn_msg); result = BROKER_ERROR; } else { result = BROKER_OK; } } /*Codes_SRS_BROKER_17_012: [ Broker_Publish shall free the message. ]*/ Message_Destroy(msg); /*Codes_SRS_BROKER_17_011: [ Broker_Publish shall free the serialized message data. ]*/ } /*Codes_SRS_BROKER_17_023: [ Broker_Publish shall Unlock the modules lock. ]*/ Unlock(broker_data->modules_lock); } } /*Codes_SRS_BROKER_13_037: [ This function shall return BROKER_ERROR if an underlying API call to the platform causes an error or BROKER_OK otherwise. ]*/ return result; }
/* Codes_SRS_BROKER_17_026: [ N/A - Broker_Publish shall copy source into the beginning of the nanomsg buffer. ] */ BROKER_RESULT Broker_Publish ( BROKER_HANDLE broker, MODULE_HANDLE source, MESSAGE_HANDLE message ) { (void)source; REMOTE_MODULE_HANDLE remote_module = (REMOTE_MODULE_HANDLE)broker; BROKER_RESULT result; /* Codes_SRS_BROKER_13_030: [If broker or message is NULL the function shall return BROKER_INVALIDARG.] */ if (broker == NULL || message == NULL) { result = BROKER_INVALIDARG; LogError("Broker handle and/or message handle is NULL"); } else { // Send message_ to nanomsg int32_t msg_size; int32_t buf_size; /* Codes_SRS_BROKER_17_007: [ Broker_Publish shall clone the message. ] */ MESSAGE_HANDLE msg = Message_Clone(message); /* Codes_SRS_BROKER_17_008: [ Broker_Publish shall serialize the message. ] */ msg_size = Message_ToByteArray(message, NULL, 0); if (msg_size < 0) { /* Codes_SRS_BROKER_13_037: [ This function shall return BROKER_ERROR if an underlying API call to the platform causes an error or BROKER_OK otherwise. ] */ LogError("unable to serialize a message [%p]", msg); Message_Destroy(msg); result = BROKER_ERROR; } else { /* Codes_SRS_BROKER_17_025: [ Broker_Publish shall allocate a nanomsg buffer the size of the serialized message + sizeof(MODULE_HANDLE). ] */ buf_size = msg_size; void* nn_msg = nn_allocmsg(buf_size, 0); if (nn_msg == NULL) { /* Codes_SRS_BROKER_13_037: [ This function shall return BROKER_ERROR if an underlying API call to the platform causes an error or BROKER_OK otherwise. ] */ LogError("unable to serialize a message [%p]", msg); result = BROKER_ERROR; } else { unsigned char *nn_msg_bytes = (unsigned char *)nn_msg; /* Codes_SRS_BROKER_17_027: [ Broker_Publish shall serialize the message into the remainder of the nanomsg buffer. ] */ Message_ToByteArray(message, nn_msg_bytes, msg_size); /* Codes_SRS_BROKER_17_010: [ Broker_Publish shall send a message on the publish_socket. ] */ int nbytes = nn_really_send(remote_module->message_socket, &nn_msg, NN_MSG, 0); if (nbytes != buf_size) { /* Codes_SRS_BROKER_13_037: [ This function shall return BROKER_ERROR if an underlying API call to the platform causes an error or BROKER_OK otherwise. ] */ LogError("unable to send a message [%p]", msg); /* Codes_SRS_BROKER_17_012: [ Broker_Publish shall free the message. ] */ nn_freemsg(nn_msg); result = BROKER_ERROR; } else { result = BROKER_OK; } } /* Codes_SRS_BROKER_17_012: [ Broker_Publish shall free the message. ] */ Message_Destroy(msg); /* Codes_SRS_BROKER_17_011: [ Broker_Publish shall free the serialized message data. ] */ } } /* Codes_SRS_BROKER_13_037: [ This function shall return BROKER_ERROR if an underlying API call to the platform causes an error or BROKER_OK otherwise. ] */ return result; }
int testmsg() { int rc; int sb; int sc; unsigned char *buf1, *buf2; int i; struct nn_iovec iov; struct nn_msghdr hdr; printf("test msg\n"); if ( 1 ) { sb = test_socket (AF_SP, NN_PAIR); test_bind (sb, SOCKET_ADDRESS); sc = test_socket (AF_SP, NN_PAIR); test_connect (sc, SOCKET_ADDRESS); buf1 = nn_allocmsg (256, 0); alloc_assert (buf1); for (i = 0; i != 256; ++i) buf1 [i] = (unsigned char) i; printf("send 256\n"); rc = nn_send (sc, &buf1, NN_MSG, 0); printf("rc.%d\n",rc); errno_assert (rc >= 0); nn_assert (rc == 256); buf2 = NULL; rc = nn_recv (sb, &buf2, NN_MSG, 0); errno_assert (rc >= 0); nn_assert (rc == 256); nn_assert (buf2); for (i = 0; i != 256; ++i) nn_assert (buf2 [i] == (unsigned char) i); rc = nn_freemsg (buf2); errno_assert (rc == 0); buf1 = nn_allocmsg (256, 0); alloc_assert (buf1); for (i = 0; i != 256; ++i) buf1 [i] = (unsigned char) i; iov.iov_base = &buf1; iov.iov_len = NN_MSG; memset (&hdr, 0, sizeof (hdr)); hdr.msg_iov = &iov; hdr.msg_iovlen = 1; rc = nn_sendmsg (sc, &hdr, 0); errno_assert (rc >= 0); nn_assert (rc == 256); buf2 = NULL; iov.iov_base = &buf2; iov.iov_len = NN_MSG; memset (&hdr, 0, sizeof (hdr)); hdr.msg_iov = &iov; hdr.msg_iovlen = 1; rc = nn_recvmsg (sb, &hdr, 0); errno_assert (rc >= 0); nn_assert (rc == 256); nn_assert (buf2); for (i = 0; i != 256; ++i) nn_assert (buf2 [i] == (unsigned char) i); rc = nn_freemsg (buf2); errno_assert (rc == 0); test_close (sc); test_close (sb); } /* Test receiving of large message */ sb = test_socket(AF_SP, NN_PAIR); //printf("test_bind.(%s)\n",SOCKET_ADDRESS_TCP); test_bind(sb,SOCKET_ADDRESS_TCP); sc = test_socket(AF_SP,NN_PAIR); //printf("test_connect.(%s)\n",SOCKET_ADDRESS_TCP); test_connect(sc,SOCKET_ADDRESS_TCP); for (i = 0; i < (int) sizeof (longdata); ++i) longdata[i] = '0' + (i % 10); longdata [sizeof(longdata) - 1] = 0; printf("send longdata.%d\n",(int32_t)sizeof(longdata)); test_send(sb,longdata); printf("recv longdata.%d\n",(int32_t)sizeof(longdata)); rc = nn_recv (sc, &buf2, NN_MSG, 0); errno_assert (rc >= 0); nn_assert (rc == sizeof (longdata) - 1); nn_assert (buf2); for (i = 0; i < (int) sizeof (longdata) - 1; ++i) nn_assert (buf2 [i] == longdata [i]); rc = nn_freemsg (buf2); errno_assert (rc == 0); test_close (sc); test_close (sb); //printf("testmsg completed\n"); return 0; }
int main (int argc, const char *argv[]) { int rc; int sb; int sc; unsigned char *buf1, *buf2; int i; struct nn_iovec iov; struct nn_msghdr hdr; char socket_address_tcp[128]; test_addr_from(socket_address_tcp, "tcp", "127.0.0.1", get_test_port(argc, argv)); sb = test_socket (AF_SP, NN_PAIR); test_bind (sb, SOCKET_ADDRESS); sc = test_socket (AF_SP, NN_PAIR); test_connect (sc, SOCKET_ADDRESS); buf1 = nn_allocmsg (256, 0); alloc_assert (buf1); for (i = 0; i != 256; ++i) buf1 [i] = (unsigned char) i; rc = nn_send (sc, &buf1, NN_MSG, 0); errno_assert (rc >= 0); nn_assert (rc == 256); buf2 = NULL; rc = nn_recv (sb, &buf2, NN_MSG, 0); errno_assert (rc >= 0); nn_assert (rc == 256); nn_assert (buf2); for (i = 0; i != 256; ++i) nn_assert (buf2 [i] == (unsigned char) i); rc = nn_freemsg (buf2); errno_assert (rc == 0); buf1 = nn_allocmsg (256, 0); alloc_assert (buf1); for (i = 0; i != 256; ++i) buf1 [i] = (unsigned char) i; iov.iov_base = &buf1; iov.iov_len = NN_MSG; memset (&hdr, 0, sizeof (hdr)); hdr.msg_iov = &iov; hdr.msg_iovlen = 1; rc = nn_sendmsg (sc, &hdr, 0); errno_assert (rc >= 0); nn_assert (rc == 256); buf2 = NULL; iov.iov_base = &buf2; iov.iov_len = NN_MSG; memset (&hdr, 0, sizeof (hdr)); hdr.msg_iov = &iov; hdr.msg_iovlen = 1; rc = nn_recvmsg (sb, &hdr, 0); errno_assert (rc >= 0); nn_assert (rc == 256); nn_assert (buf2); for (i = 0; i != 256; ++i) nn_assert (buf2 [i] == (unsigned char) i); rc = nn_freemsg (buf2); errno_assert (rc == 0); test_close (sc); test_close (sb); /* Test receiving of large message */ sb = test_socket (AF_SP, NN_PAIR); test_bind (sb, socket_address_tcp); sc = test_socket (AF_SP, NN_PAIR); test_connect (sc, socket_address_tcp); for (i = 0; i < (int) sizeof (longdata); ++i) longdata[i] = '0' + (i % 10); longdata [sizeof (longdata) - 1] = 0; test_send (sb, longdata); rc = nn_recv (sc, &buf2, NN_MSG, 0); errno_assert (rc >= 0); nn_assert (rc == sizeof (longdata) - 1); nn_assert (buf2); for (i = 0; i < (int) sizeof (longdata) - 1; ++i) nn_assert (buf2 [i] == longdata [i]); rc = nn_freemsg (buf2); errno_assert (rc == 0); test_close (sc); test_close (sb); return 0; }
static int outprocessOutgoingMessagesThread(void * param) { OUTPROCESS_HANDLE_DATA * handleData = (OUTPROCESS_HANDLE_DATA*)param; if (handleData == NULL) { LogError("outprocess send message thread: parameter is NULL"); } else { int should_continue = 1; while (should_continue) { /*Codes_SRS_OUTPROCESS_MODULE_17_053: [ This thread shall ensure thread safety on the module data. ]*/ if (Lock(handleData->message_send_thread.thread_lock) != LOCK_OK) { LogError("unable to Lock"); should_continue = 0; break; } if (handleData->message_send_thread.thread_flag == THREAD_FLAG_STOP) { should_continue = 0; (void)Unlock(handleData->message_send_thread.thread_lock); break; } if (Unlock(handleData->message_send_thread.thread_lock) != LOCK_OK) { should_continue = 0; break; } MESSAGE_HANDLE messageHandle; /*Codes_SRS_OUTPROCESS_MODULE_17_053: [ This thread shall ensure thread safety on the module data. ]*/ if (Lock(handleData->handle_lock) != LOCK_OK) { LogError("unable to Lock"); should_continue = 0; break; } if (MESSAGE_QUEUE_is_empty(handleData->outgoing_messages)) { messageHandle = NULL; } else { /*Codes_SRS_OUTPROCESS_MODULE_17_054: [ This function shall remove the oldest message from the outgoing gateway message queue. ]*/ messageHandle = MESSAGE_QUEUE_pop(handleData->outgoing_messages); if (messageHandle == NULL) { LogError("bad condition: message handle in queue is NULL"); (void)Unlock(handleData->handle_lock); should_continue = 0; break; } } if (Unlock(handleData->handle_lock) != LOCK_OK) { should_continue = 0; break; } /* forward message to remote */ if (messageHandle != NULL) { /*Codes_SRS_OUTPROCESS_MODULE_17_023: [ This function shall serialize the message for transmission on the message channel. ]*/ int32_t msg_size = Message_ToByteArray(messageHandle, NULL, 0); if (msg_size < 0) { LogError("unable to serialize outgoing message [%p]", messageHandle); } else { void* result = nn_allocmsg(msg_size, 0); if (result == NULL) { LogError("unable to allocate buffer for outgoing message [%p]", messageHandle); } else { unsigned char *nn_msg_bytes = (unsigned char *)result; Message_ToByteArray(messageHandle, nn_msg_bytes, msg_size); /*Codes_SRS_OUTPROCESS_MODULE_17_024: [ This function shall send the message on the message channel. ]*/ int nbytes = nn_really_send(handleData->message_socket, &result, NN_MSG, 0); if (nbytes != msg_size) { LogError("unable to send buffer to remote for message [%p]", messageHandle); /*Codes_SRS_OUTPROCESS_MODULE_17_025: [ This function shall free any resources created. ]*/ nn_freemsg(result); } } } // We are finally finished with this message /*Codes_SRS_OUTPROCESS_MODULE_17_055: [ This function shall Destroy the message once successfully transmitted. ]*/ Message_Destroy(messageHandle); } ThreadAPI_Sleep(1); } } return 0; }