diff --git a/src/DirectPlay8Peer.cpp b/src/DirectPlay8Peer.cpp index dd256ef..eadfaf9 100644 --- a/src/DirectPlay8Peer.cpp +++ b/src/DirectPlay8Peer.cpp @@ -415,6 +415,12 @@ HRESULT DirectPlay8Peer::Connect(CONST DPN_APPLICATION_DESC* CONST pdnAppDesc, I return DPNERR_GENERIC; } + if(WSAEventSelect(udp_socket, udp_socket_event, FD_READ | FD_WRITE) != 0 + || WSAEventSelect(listener_socket, other_socket_event, FD_ACCEPT) != 0) + { + return DPNERR_GENERIC; + } + if(dwFlags & DPNCONNECT_SYNC) { connect_cv.wait(l, [this]() { return (state != STATE_CONNECTING && state != STATE_CONNECT_FAILED); }); @@ -1937,7 +1943,22 @@ void DirectPlay8Peer::io_peer_connected(std::unique_lock &l, unsigne } else if(peer->state == Peer::PS_CONNECTING_PEER) { - /* TODO: Send DPLITE_MSGID_CONNECT_PEER message. */ + PacketSerialiser connect_peer(DPLITE_MSGID_CONNECT_PEER); + + connect_peer.append_guid(instance_guid); + connect_peer.append_guid(application_guid); + connect_peer.append_wstring(password); + + connect_peer.append_dword(local_player_id); + connect_peer.append_wstring(local_player_name); + connect_peer.append_data(local_player_data.data(), local_player_data.size()); + + peer->sq.send(SendQueue::SEND_PRI_HIGH, + connect_peer, + NULL, + [](std::unique_lock &l, HRESULT result){}); + + peer->state = Peer::PS_REQUESTING_PEER; } } else{ @@ -2122,6 +2143,24 @@ void DirectPlay8Peer::io_peer_recv(std::unique_lock &l, unsigned int break; } + case DPLITE_MSGID_CONNECT_PEER: + { + handle_connect_peer(l, peer_id, *pd); + break; + } + + case DPLITE_MSGID_CONNECT_PEER_OK: + { + handle_connect_peer_ok(l, peer_id, *pd); + break; + } + + case DPLITE_MSGID_CONNECT_PEER_FAIL: + { + handle_connect_peer_fail(l, peer_id, *pd); + break; + } + default: log_printf( "Unexpected message type %u received from peer %u", @@ -2204,7 +2243,7 @@ void DirectPlay8Peer::peer_accept(std::unique_lock &l) worker_pool.add_handle(peer->event, [this, peer_id]() { io_peer_triggered(peer_id); }); } -bool DirectPlay8Peer::peer_connect(Peer::PeerState initial_state, uint32_t remote_ip, uint16_t remote_port) +bool DirectPlay8Peer::peer_connect(Peer::PeerState initial_state, uint32_t remote_ip, uint16_t remote_port, DPNID player_id) { int p_sock = create_client_socket(local_ip, local_port); if(p_sock == -1) @@ -2215,6 +2254,8 @@ bool DirectPlay8Peer::peer_connect(Peer::PeerState initial_state, uint32_t remot unsigned int peer_id = next_peer_id++; Peer *peer = new Peer(initial_state, p_sock, remote_ip, remote_port); + peer->player_id = player_id; + if(WSAEventSelect(peer->sock, peer->event, FD_CONNECT | FD_READ | FD_WRITE | FD_CLOSE) != 0) { closesocket(peer->sock); @@ -2589,7 +2630,19 @@ void DirectPlay8Peer::handle_host_connect_request(std::unique_lock & connect_host_ok.append_dword(host_player_id); connect_host_ok.append_dword(peer->player_id); - connect_host_ok.append_dword(0); /* TODO: Other peers */ + connect_host_ok.append_dword(player_to_peer_id.size() - 1); + + for(auto pi = peers.begin(); pi != peers.end(); ++pi) + { + Peer *pip = pi->second; + + if(pip != peer && pip->state == Peer::PS_CONNECTED) + { + connect_host_ok.append_dword(pip->player_id); + connect_host_ok.append_dword(pip->ip); + connect_host_ok.append_dword(pip->port); + } + } if(ic.dwReplyDataSize > 0) { @@ -2674,12 +2727,10 @@ void DirectPlay8Peer::handle_host_connect_ok(std::unique_lock &l, un for(DWORD n = 0; n < n_other_peers; ++n) { - DPNID player_id = pd.get_dword(4 + (n * 3)); - uint32_t player_ipaddr = pd.get_dword(5 + (n * 3)); - uint16_t player_port = pd.get_dword(6 + (n * 3)); - - /* TODO: Setup connections to other peers. */ - abort(); + /* Spinning through the loop so we blow up early if malformed. */ + pd.get_dword(4 + (n * 3)); + pd.get_dword(5 + (n * 3)); + pd.get_dword(6 + (n * 3)); } int after_peers_base = 4 + (n_other_peers * 3); @@ -2755,6 +2806,19 @@ void DirectPlay8Peer::handle_host_connect_ok(std::unique_lock &l, un peer->player_ctx = cp.pvPlayerContext; } + for(DWORD n = 0; n < n_other_peers; ++n) + { + DPNID player_id = pd.get_dword(4 + (n * 3)); + uint32_t player_ipaddr = pd.get_dword(5 + (n * 3)); + uint16_t player_port = pd.get_dword(6 + (n * 3)); + + if(!peer_connect(Peer::PS_CONNECTING_PEER, player_ipaddr, player_port, player_id)) + { + connect_fail(l, DPNERR_PLAYERNOTREACHABLE, NULL, 0); + return; + } + } + connect_check(l); } @@ -2799,6 +2863,179 @@ void DirectPlay8Peer::handle_host_connect_fail(std::unique_lock &l, connect_fail(l, hResultCode, pvApplicationReplyData, dwApplicationReplyDataSize); } +void DirectPlay8Peer::handle_connect_peer(std::unique_lock &l, unsigned int peer_id, const PacketDeserialiser &pd) +{ + Peer *peer = get_peer_by_peer_id(peer_id); + assert(peer != NULL); + + if(peer->state != Peer::PS_ACCEPTED) + { + log_printf("Received unexpected DPLITE_MSGID_CONNECT_PEER from peer %u, in state %u", + peer_id, (unsigned)(peer->state)); + return; + } + + auto send_fail = [&peer](DWORD error) + { + PacketSerialiser connect_peer_fail(DPLITE_MSGID_CONNECT_PEER_FAIL); + connect_peer_fail.append_dword(error); + + peer->sq.send(SendQueue::SEND_PRI_HIGH, + connect_peer_fail, + NULL, + [](std::unique_lock &l, HRESULT result) {}); + }; + + if(state != STATE_CONNECTED) + { + send_fail(DPNERR_GENERIC); + return; + } + + if(pd.get_guid(0) != instance_guid) + { + send_fail(DPNERR_INVALIDINSTANCE); + return; + } + + if(pd.get_guid(1) != application_guid) + { + send_fail(DPNERR_INVALIDAPPLICATION); + return; + } + + if(pd.get_wstring(2) != password) + { + send_fail(DPNERR_INVALIDPASSWORD); + return; + } + + peer->player_id = pd.get_dword(3); + peer->player_name = pd.get_wstring(4); + + peer->player_data.clear(); + + std::pair player_data = pd.get_data(5); + + peer->player_data.reserve(player_data.second); + peer->player_data.insert(peer->player_data.end(), + (const unsigned char*)(player_data.first), + (const unsigned char*)(player_data.first) + player_data.second); + + if(player_to_peer_id.find(peer->player_id) != player_to_peer_id.end()) + { + log_printf("Rejected DPLITE_MSGID_CONNECT_PEER with already-known Player ID %u", (unsigned)(peer->player_id)); + + send_fail(DPNERR_ALREADYCONNECTED); + return; + } + + player_to_peer_id[peer->player_id] = peer_id; + + peer->state = Peer::PS_CONNECTED; + + PacketSerialiser connect_peer_ok(DPLITE_MSGID_CONNECT_PEER_OK); + connect_peer_ok.append_wstring(local_player_name); + connect_peer_ok.append_data(local_player_data.data(), local_player_data.size()); + + peer->sq.send(SendQueue::SEND_PRI_HIGH, + connect_peer_ok, + NULL, + [](std::unique_lock &l, HRESULT result) {}); + + DPNMSG_CREATE_PLAYER cp; + memset(&cp, 0, sizeof(cp)); + + cp.dwSize = sizeof(cp); + cp.dpnidPlayer = peer->player_id; + cp.pvPlayerContext = NULL; + + l.unlock(); + message_handler(message_handler_ctx, DPN_MSGID_CREATE_PLAYER, &cp); + l.lock(); + + RENEW_PEER_OR_RETURN(); + + peer->player_ctx = cp.pvPlayerContext; +} + +void DirectPlay8Peer::handle_connect_peer_ok(std::unique_lock &l, unsigned int peer_id, const PacketDeserialiser &pd) +{ + Peer *peer = get_peer_by_peer_id(peer_id); + assert(peer != NULL); + + if(peer->state != Peer::PS_REQUESTING_PEER) + { + /* TODO: LOG ME */ + return; + } + + assert(state == STATE_CONNECTING); + + peer->player_name = pd.get_wstring(0); + + peer->player_data.clear(); + + std::pair player_data = pd.get_data(1); + + peer->player_data.reserve(player_data.second); + peer->player_data.insert(peer->player_data.end(), + (const unsigned char*)(player_data.first), + (const unsigned char*)(player_data.first) + player_data.second); + + peer->state = Peer::PS_CONNECTED; + + /* player_id initialised in handling of DPLITE_MSGID_CONNECT_HOST_OK. */ + player_to_peer_id[peer->player_id] = peer_id; + + { + DPNMSG_CREATE_PLAYER cp; + memset(&cp, 0, sizeof(cp)); + + cp.dwSize = sizeof(cp); + cp.dpnidPlayer = peer->player_id; + cp.pvPlayerContext = NULL; + + l.unlock(); + message_handler(message_handler_ctx, DPN_MSGID_CREATE_PLAYER, &cp); + l.lock(); + + RENEW_PEER_OR_RETURN(); + + peer->player_ctx = cp.pvPlayerContext; + } + + connect_check(l); +} + +void DirectPlay8Peer::handle_connect_peer_fail(std::unique_lock &l, unsigned int peer_id, const PacketDeserialiser &pd) +{ + Peer *peer = get_peer_by_peer_id(peer_id); + assert(peer != NULL); + + if(peer->state != Peer::PS_REQUESTING_PEER) + { + log_printf("Received unexpected DPLITE_MSGID_CONNECT_PEER_FAIL from peer %u, in state %u", + peer_id, (unsigned)(peer->state)); + return; + } + + assert(state == STATE_CONNECTING); + + DWORD hResultCode = DPNERR_GENERIC; + + try { + hResultCode = pd.get_dword(0); + } + catch(const PacketDeserialiser::Error &e) + { + log_printf("Received invalid DPLITE_MSGID_CONNECT_PEER_FAIL from peer %u: %s", + peer_id, e.what()); + } + + connect_fail(l, DPNERR_PLAYERNOTREACHABLE, NULL, 0); +} + void DirectPlay8Peer::handle_message(std::unique_lock &l, const PacketDeserialiser &pd) { try { diff --git a/src/DirectPlay8Peer.hpp b/src/DirectPlay8Peer.hpp index 01db70a..4eb0754 100644 --- a/src/DirectPlay8Peer.hpp +++ b/src/DirectPlay8Peer.hpp @@ -182,7 +182,7 @@ class DirectPlay8Peer: public IDirectPlay8Peer void io_peer_recv(std::unique_lock &l, unsigned int peer_id); void peer_accept(std::unique_lock &l); - bool peer_connect(Peer::PeerState initial_state, uint32_t remote_ip, uint16_t remote_port); + bool peer_connect(Peer::PeerState initial_state, uint32_t remote_ip, uint16_t remote_port, DPNID player_id = 0); void peer_destroy(std::unique_lock &l, unsigned int peer_id, HRESULT outstanding_op_result); void close_everything_now(std::unique_lock &l); @@ -191,6 +191,9 @@ class DirectPlay8Peer: public IDirectPlay8Peer void handle_host_connect_request(std::unique_lock &l, unsigned int peer_id, const PacketDeserialiser &pd); void handle_host_connect_ok(std::unique_lock &l, unsigned int peer_id, const PacketDeserialiser &pd); void handle_host_connect_fail(std::unique_lock &l, unsigned int peer_id, const PacketDeserialiser &pd); + void handle_connect_peer(std::unique_lock &l, unsigned int peer_id, const PacketDeserialiser &pd); + void handle_connect_peer_ok(std::unique_lock &l, unsigned int peer_id, const PacketDeserialiser &pd); + void handle_connect_peer_fail(std::unique_lock &l, unsigned int peer_id, const PacketDeserialiser &pd); void handle_message(std::unique_lock &l, const PacketDeserialiser &pd); void handle_playerinfo(std::unique_lock &l, unsigned int peer_id, const PacketDeserialiser &pd); void handle_ack(std::unique_lock &l, unsigned int peer_id, const PacketDeserialiser &pd); diff --git a/src/Messages.hpp b/src/Messages.hpp index fcaea6d..608e8cf 100644 --- a/src/Messages.hpp +++ b/src/Messages.hpp @@ -107,4 +107,32 @@ * DATA - DPN_APPLICATION_DESC.pvApplicationReservedData */ +#define DPLITE_MSGID_CONNECT_PEER 10 + +/* Initial connect request to a follow non-host peer. + * + * GUID - Instance GUID + * GUID - Application GUID + * WSTRING - Password + * DWORD - Player ID + * WSTRING - Player name (empty = none) + * DATA - Player data (empty = none) +*/ + +#define DPLITE_MSGID_CONNECT_PEER_OK 11 + +/* Successful response to DPLITE_MSGID_CONNECT_PEER. + * + * WSTRING - Player name (empty = none) + * DATA - Player data (empty = none) +*/ + +#define DPLITE_MSGID_CONNECT_PEER_FAIL 12 + +/* Negative response to DPLITE_MSGID_CONNECT_PEER. + * Peer will close the connection after sending this. + * + * DWORD - Error code (DPNERR_HOSTREJECTEDCONNECTION, DPNERR_INVALIDAPPLICATION, etc) +*/ + #endif /* !DPLITE_MESSAGES_HPP */ diff --git a/src/network.cpp b/src/network.cpp index eb2e776..e592d68 100644 --- a/src/network.cpp +++ b/src/network.cpp @@ -1,6 +1,8 @@ #include #include +#include #include +#include #include "network.hpp" diff --git a/tests/DirectPlay8Peer.cpp b/tests/DirectPlay8Peer.cpp index 5c5dd75..6b815e2 100644 --- a/tests/DirectPlay8Peer.cpp +++ b/tests/DirectPlay8Peer.cpp @@ -1929,6 +1929,377 @@ TEST(DirectPlay8Peer, ConnectToIPX) EXPECT_EQ(p1_cc_dpnidLocal, p1_player_id); } +TEST(DirectPlay8Peer, ConnectTwoPeersToHost) +{ + std::atomic testing(true); + + std::atomic host_seq(0), p1_seq(0), p2_seq(0); + DPNID host_player_id = -1, p1_player_id = -1, p2_player_id = -1; + + SessionHost host(APP_GUID_1, L"Session 1", PORT, + [&testing, &host_seq, &host_player_id, &p1_player_id, &p2_player_id] + (DWORD dwMessageType, PVOID pMessage) + { + if(!testing) + { + return DPN_OK; + } + + int seq = ++host_seq; + + switch(seq) + { + case 1: + EXPECT_EQ(dwMessageType, DPN_MSGID_CREATE_PLAYER); + + if(dwMessageType == DPN_MSGID_CREATE_PLAYER) + { + DPNMSG_CREATE_PLAYER *cp = (DPNMSG_CREATE_PLAYER*)(pMessage); + host_player_id = cp->dpnidPlayer; + + EXPECT_EQ(cp->dwSize, sizeof(DPNMSG_CREATE_PLAYER)); + EXPECT_EQ(cp->pvPlayerContext, (void*)(0xB00)); + + cp->pvPlayerContext = (void*)(0xB00B00); + } + + break; + + case 2: + EXPECT_EQ(dwMessageType, DPN_MSGID_INDICATE_CONNECT); + + if(dwMessageType == DPN_MSGID_INDICATE_CONNECT) + { + DPNMSG_INDICATE_CONNECT *ic = (DPNMSG_INDICATE_CONNECT*)(pMessage); + + EXPECT_EQ(ic->dwSize, sizeof(DPNMSG_INDICATE_CONNECT)); + + EXPECT_EQ(ic->pvUserConnectData, (void*)(NULL)); + EXPECT_EQ(ic->dwUserConnectDataSize, 0); + + EXPECT_EQ(ic->pvReplyData, (void*)(NULL)); + EXPECT_EQ(ic->dwReplyDataSize, 0); + + EXPECT_EQ(ic->pvReplyContext, (void*)(NULL)); + EXPECT_EQ(ic->pvPlayerContext, (void*)(NULL)); + + /* TODO: Check pAddressPlayer, pAddressDevice */ + + ic->pvPlayerContext = (void*)(0xB441); + } + + break; + + case 3: + EXPECT_EQ(dwMessageType, DPN_MSGID_CREATE_PLAYER); + + if(dwMessageType == DPN_MSGID_CREATE_PLAYER) + { + DPNMSG_CREATE_PLAYER *cp = (DPNMSG_CREATE_PLAYER*)(pMessage); + p1_player_id = cp->dpnidPlayer; + + EXPECT_EQ(cp->dwSize, sizeof(DPNMSG_CREATE_PLAYER)); + EXPECT_EQ(cp->pvPlayerContext, (void*)(0xB441)); + + cp->pvPlayerContext = (void*)(0xFEED); + } + + break; + + case 4: + EXPECT_EQ(dwMessageType, DPN_MSGID_INDICATE_CONNECT); + + if(dwMessageType == DPN_MSGID_INDICATE_CONNECT) + { + DPNMSG_INDICATE_CONNECT *ic = (DPNMSG_INDICATE_CONNECT*)(pMessage); + + EXPECT_EQ(ic->dwSize, sizeof(DPNMSG_INDICATE_CONNECT)); + + EXPECT_EQ(ic->pvUserConnectData, (void*)(NULL)); + EXPECT_EQ(ic->dwUserConnectDataSize, 0); + + EXPECT_EQ(ic->pvReplyData, (void*)(NULL)); + EXPECT_EQ(ic->dwReplyDataSize, 0); + + EXPECT_EQ(ic->pvReplyContext, (void*)(NULL)); + EXPECT_EQ(ic->pvPlayerContext, (void*)(NULL)); + + /* TODO: Check pAddressPlayer, pAddressDevice */ + + ic->pvPlayerContext = (void*)(0xB442); + } + + break; + + case 5: + EXPECT_EQ(dwMessageType, DPN_MSGID_CREATE_PLAYER); + + if(dwMessageType == DPN_MSGID_CREATE_PLAYER) + { + DPNMSG_CREATE_PLAYER *cp = (DPNMSG_CREATE_PLAYER*)(pMessage); + p2_player_id = cp->dpnidPlayer; + + EXPECT_EQ(cp->dwSize, sizeof(DPNMSG_CREATE_PLAYER)); + EXPECT_EQ(cp->pvPlayerContext, (void*)(0xB442)); + + cp->pvPlayerContext = (void*)(0xFEEE); + } + + break; + + default: + ADD_FAILURE() << "Unexpected message of type " << dwMessageType <<", sequence " << seq; + break; + } + + return DPN_OK; + }); + + Sleep(1000); + + DPNID p1_cp1_dpnidPlayer = -1, p1_cc_dpnidLocal = -1, p1_cp2_dpnidPlayer = -1; + + std::function p1_cb = + [&testing, &p1_seq, &host_player_id, &p1_player_id, &p1_cp1_dpnidPlayer, &p1_cc_dpnidLocal, &p1_cp2_dpnidPlayer] + (DWORD dwMessageType, PVOID pMessage) + { + if(!testing) + { + return DPN_OK; + } + + int seq = ++p1_seq; + + switch(seq) + { + case 1: + EXPECT_EQ(dwMessageType, DPN_MSGID_CREATE_PLAYER); + + if(dwMessageType == DPN_MSGID_CREATE_PLAYER) + { + DPNMSG_CREATE_PLAYER *cp = (DPNMSG_CREATE_PLAYER*)(pMessage); + p1_cp1_dpnidPlayer = cp->dpnidPlayer; + + EXPECT_EQ(cp->dwSize, sizeof(DPNMSG_CREATE_PLAYER)); + EXPECT_EQ(cp->pvPlayerContext, (void*)(0xBCDE)); + + cp->pvPlayerContext = (void*)(0xCDEF); + } + + break; + + case 2: + EXPECT_EQ(dwMessageType, DPN_MSGID_CREATE_PLAYER); + + if(dwMessageType == DPN_MSGID_CREATE_PLAYER) + { + DPNMSG_CREATE_PLAYER *cp = (DPNMSG_CREATE_PLAYER*)(pMessage); + + EXPECT_EQ(cp->dwSize, sizeof(DPNMSG_CREATE_PLAYER)); + EXPECT_EQ(cp->dpnidPlayer, host_player_id); + EXPECT_EQ(cp->pvPlayerContext, (void*)(0)); + + cp->pvPlayerContext = (void*)(0xBAA); + } + + break; + + case 3: + EXPECT_EQ(dwMessageType, DPN_MSGID_CONNECT_COMPLETE); + + if(dwMessageType == DPN_MSGID_CONNECT_COMPLETE) + { + DPNMSG_CONNECT_COMPLETE *cc = (DPNMSG_CONNECT_COMPLETE*)(pMessage); + + EXPECT_EQ(cc->dwSize, sizeof(DPNMSG_CONNECT_COMPLETE)); + EXPECT_EQ(cc->hAsyncOp, 0); + EXPECT_EQ(cc->hResultCode, S_OK); + + EXPECT_EQ(cc->pvApplicationReplyData, (PVOID)(NULL)); + EXPECT_EQ(cc->dwApplicationReplyDataSize, 0); + + p1_cc_dpnidLocal = cc->dpnidLocal; + } + + break; + + case 4: + EXPECT_EQ(dwMessageType, DPN_MSGID_CREATE_PLAYER); + + if(dwMessageType == DPN_MSGID_CREATE_PLAYER) + { + DPNMSG_CREATE_PLAYER *cp = (DPNMSG_CREATE_PLAYER*)(pMessage); + p1_cp2_dpnidPlayer = cp->dpnidPlayer; + + EXPECT_EQ(cp->dwSize, sizeof(DPNMSG_CREATE_PLAYER)); + EXPECT_EQ(cp->pvPlayerContext, (void*)(0)); + + cp->pvPlayerContext = (void*)(0xBAB); + } + + break; + + default: + ADD_FAILURE() << "Unexpected message of type " << dwMessageType <<", sequence " << seq; + break; + } + + return DPN_OK; + }; + + IDP8PeerInstance p1; + + ASSERT_EQ(p1->Initialize(&p1_cb, &callback_shim, 0), S_OK); + + DPN_APPLICATION_DESC connect_to_app; + memset(&connect_to_app, 0, sizeof(connect_to_app)); + + connect_to_app.dwSize = sizeof(connect_to_app); + connect_to_app.guidApplication = APP_GUID_1; + + IDP8AddressInstance connect_to_addr(L"127.0.0.1", PORT); + + EXPECT_EQ(p1->Connect( + &connect_to_app, /* pdnAppDesc */ + connect_to_addr, /* pHostAddr */ + NULL, /* pDeviceInfo */ + NULL, /* pdnSecurity */ + NULL, /* pdnCredentials */ + NULL, /* pvUserConnectData */ + 0, /* dwUserConnectDataSize */ + (void*)(0xBCDE), /* pvPlayerContext */ + NULL, /* pvAsyncContext */ + NULL, /* phAsyncHandle */ + DPNCONNECT_SYNC /* dwFlags */ + ), S_OK); + + Sleep(1000); + + DPNID p2_cp1_dpnidPlayer = -1, p2_cc_dpnidLocal = -1, p2_cp2_dpnidPlayer = -1; + + std::function p2_cb = + [&testing, &p2_seq, &host_player_id, &p2_cp1_dpnidPlayer, &p2_cc_dpnidLocal, &p2_cp2_dpnidPlayer] + (DWORD dwMessageType, PVOID pMessage) + { + if(!testing) + { + return DPN_OK; + } + + int seq = ++p2_seq; + + switch(seq) + { + case 1: + EXPECT_EQ(dwMessageType, DPN_MSGID_CREATE_PLAYER); + + if(dwMessageType == DPN_MSGID_CREATE_PLAYER) + { + DPNMSG_CREATE_PLAYER *cp = (DPNMSG_CREATE_PLAYER*)(pMessage); + p2_cp1_dpnidPlayer = cp->dpnidPlayer; + + EXPECT_EQ(cp->dwSize, sizeof(DPNMSG_CREATE_PLAYER)); + EXPECT_EQ(cp->pvPlayerContext, (void*)(0xCDEF)); + + cp->pvPlayerContext = (void*)(0xCDEF); + } + + break; + + case 2: + EXPECT_EQ(dwMessageType, DPN_MSGID_CREATE_PLAYER); + + if(dwMessageType == DPN_MSGID_CREATE_PLAYER) + { + DPNMSG_CREATE_PLAYER *cp = (DPNMSG_CREATE_PLAYER*)(pMessage); + + EXPECT_EQ(cp->dwSize, sizeof(DPNMSG_CREATE_PLAYER)); + EXPECT_EQ(cp->dpnidPlayer, host_player_id); + EXPECT_EQ(cp->pvPlayerContext, (void*)(0)); + + cp->pvPlayerContext = (void*)(0xBAA); + } + + break; + + case 3: + EXPECT_EQ(dwMessageType, DPN_MSGID_CREATE_PLAYER); + + if(dwMessageType == DPN_MSGID_CREATE_PLAYER) + { + DPNMSG_CREATE_PLAYER *cp = (DPNMSG_CREATE_PLAYER*)(pMessage); + p2_cp2_dpnidPlayer = cp->dpnidPlayer; + + EXPECT_EQ(cp->dwSize, sizeof(DPNMSG_CREATE_PLAYER)); + EXPECT_EQ(cp->pvPlayerContext, (void*)(0)); + + cp->pvPlayerContext = (void*)(0xBAB); + } + + break; + + case 4: + EXPECT_EQ(dwMessageType, DPN_MSGID_CONNECT_COMPLETE); + + if(dwMessageType == DPN_MSGID_CONNECT_COMPLETE) + { + DPNMSG_CONNECT_COMPLETE *cc = (DPNMSG_CONNECT_COMPLETE*)(pMessage); + + EXPECT_EQ(cc->dwSize, sizeof(DPNMSG_CONNECT_COMPLETE)); + EXPECT_EQ(cc->hAsyncOp, 0); + EXPECT_EQ(cc->hResultCode, S_OK); + + EXPECT_EQ(cc->pvApplicationReplyData, (PVOID)(NULL)); + EXPECT_EQ(cc->dwApplicationReplyDataSize, 0); + + p2_cc_dpnidLocal = cc->dpnidLocal; + } + + break; + + default: + ADD_FAILURE() << "Unexpected message of type " << dwMessageType <<", sequence " << seq; + break; + } + + return DPN_OK; + }; + + IDP8PeerInstance p2; + + ASSERT_EQ(p2->Initialize(&p2_cb, &callback_shim, 0), S_OK); + + EXPECT_EQ(p2->Connect( + &connect_to_app, /* pdnAppDesc */ + connect_to_addr, /* pHostAddr */ + NULL, /* pDeviceInfo */ + NULL, /* pdnSecurity */ + NULL, /* pdnCredentials */ + NULL, /* pvUserConnectData */ + 0, /* dwUserConnectDataSize */ + (void*)(0xCDEF), /* pvPlayerContext */ + NULL, /* pvAsyncContext */ + NULL, /* phAsyncHandle */ + DPNCONNECT_SYNC /* dwFlags */ + ), S_OK); + + Sleep(1000); + + testing = false; + + EXPECT_EQ(host_seq, 5); + EXPECT_EQ(p1_seq, 4); + EXPECT_EQ(p2_seq, 4); + + EXPECT_EQ(p1_cp1_dpnidPlayer, p1_player_id); + EXPECT_EQ(p1_cc_dpnidLocal, p1_player_id); + EXPECT_EQ(p1_cp2_dpnidPlayer, p2_player_id); + + EXPECT_EQ(p2_cp1_dpnidPlayer, p2_player_id); + EXPECT_EQ(p2_cc_dpnidLocal, p2_player_id); + EXPECT_EQ(p2_cp2_dpnidPlayer, p1_player_id); +} + TEST(DirectPlay8Peer, GetApplicationDesc) { const unsigned char APP_DATA[] = { 0x00, 0x01, 0x02, 0x03, 0x04 };