1 /*******************************************************************************************
2 *
3 *   raylib [network] example - Client/Server ping-pong
4 *
5 *   This example has been created using raylib 3.0 (www.raylib.com)
6 *   raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
7 *
8 *   Copyright (c) 2019-2020 Jak Barnes (@syphonx) and Ramon Santamaria (@raysan5)
9 *
10 ********************************************************************************************/
11 
12 #include "raylib.h"
13 
14 #define RNET_IMPLEMENTATION
15 #include "rnet.h"
16 
17 float elapsed = 0.0f;
18 float delay = 1.0f;
19 bool ping = false;
20 bool pong = false;
21 bool connected = false;
22 bool clientConnected = false;
23 const char *pingmsg = "Ping!";
24 const char *pongmsg = "Pong!";
25 int msglen = 0;
26 SocketConfig serverConfig = { .host = "127.0.0.1", .port = "4950", .type = SOCKET_TCP, .server = true, .nonblocking = true };
27 SocketConfig clientConfig = { .host = "127.0.0.1", .port = "4950", .type = SOCKET_TCP, .nonblocking = true };
28 SocketConfig connectionConfig = { .nonblocking = true };
29 SocketResult *serverResult = NULL;
30 SocketResult *clientResult = NULL;
31 SocketSet *socketSet = NULL;
32 Socket *connection = NULL;
33 char receiveBuffer[512] = { 0 };
34 
35 // Attempt to connect to the network (Either TCP, or UDP)
NetworkConnect(void)36 static void NetworkConnect(void)
37 {
38     // If the server is configured as UDP, ignore connection requests
39     if ((serverConfig.type == SOCKET_UDP) && (clientConfig.type == SOCKET_UDP))
40     {
41         ping = true;
42         connected = true;
43     }
44     else
45     {
46         // If the client is connected, run the server code to check for a connection
47         if (clientConnected)
48         {
49             int active = CheckSockets(socketSet, 0);
50             if (active != 0) TraceLog(LOG_INFO, "There are currently %d socket(s) with data to be processed.", active);
51 
52             if (active > 0)
53             {
54                 if ((connection = SocketAccept(serverResult->socket, &connectionConfig)) != NULL)
55                 {
56                     AddSocket(socketSet, connection);
57                     connected = true;
58                     ping = true;
59                 }
60             }
61         }
62         else
63         {
64             // Check if we're connected every _delay_ seconds
65             elapsed += GetFrameTime();
66             if (elapsed > delay)
67             {
68                 if (IsSocketConnected(clientResult->socket)) clientConnected = true;
69 
70                 elapsed = 0.0f;
71             }
72         }
73     }
74 }
75 
76 // Once connected to the network, check the sockets for pending information
77 // and when information is ready, send either a Ping or a Pong.
UpdateNetwork(void)78 static void UpdateNetwork(void)
79 {
80     // CheckSockets, if any of the sockets in the socketSet are pending (received data, or requests)
81     // then mark the socket as being ready. You can check this with IsSocketReady(clientResult->socket)
82     int active = CheckSockets(socketSet, 0);
83     if (active != 0) TraceLog(LOG_DEBUG, "There are currently %d socket(s) with data to be processed.", active);
84 
85     // IsSocketReady, if the socket is ready, attempt to receive data from the socket
86     int bytesRecv = 0;
87     if ((serverConfig.type == SOCKET_UDP) && (clientConfig.type == SOCKET_UDP))
88     {
89         if (IsSocketReady(clientResult->socket)) bytesRecv = SocketReceive(clientResult->socket, receiveBuffer, msglen);
90         if (IsSocketReady(serverResult->socket)) bytesRecv = SocketReceive(serverResult->socket, receiveBuffer, msglen);
91     }
92     else if (IsSocketReady(connection)) bytesRecv = SocketReceive(connection, receiveBuffer, msglen);
93 
94     // If we received data, was that data a "Ping!" or a "Pong!"
95     if (bytesRecv > 0)
96     {
97         if (strcmp(receiveBuffer, pingmsg) == 0) { pong = true; }
98         if (strcmp(receiveBuffer, pongmsg) == 0) { ping = true; }
99     }
100 
101     // After each delay has expired, send a response "Ping!" for a "Pong!" and vice versa
102     elapsed += GetFrameTime();
103     if (elapsed > delay)
104     {
105         if (ping)
106         {
107             ping = false;
108             if (serverConfig.type == SOCKET_UDP && clientConfig.type == SOCKET_UDP) SocketSend(clientResult->socket, pingmsg, msglen);
109             else SocketSend(clientResult->socket, pingmsg, msglen);
110         }
111         else if (pong)
112         {
113             pong = false;
114             if (serverConfig.type == SOCKET_UDP && clientConfig.type == SOCKET_UDP) SocketSend(clientResult->socket, pongmsg, msglen);
115             else SocketSend(clientResult->socket, pongmsg, msglen);
116         }
117 
118         elapsed = 0.0f;
119     }
120 }
121 
main(void)122 int main(void)
123 {
124     // Initialization
125     //--------------------------------------------------------------------------------------
126     const int screenWidth = 800;
127     const int screenHeight = 450;
128 
129     InitWindow(screenWidth, screenHeight, "raylib [network] example - ping pong");
130 
131     InitNetworkDevice();    // Init network communications
132 
133     //  Create the server: getaddrinfo + socket + setsockopt + bind + listen
134     serverResult = LoadSocketResult();
135     if (!SocketCreate(&serverConfig, serverResult))
136     {
137         TraceLog(LOG_WARNING, "Failed to open server: status %d, errno %d", serverResult->status, serverResult->socket->status);
138     }
139     else
140     {
141         if (!SocketBind(&serverConfig, serverResult))
142         {
143             TraceLog(LOG_WARNING, "Failed to bind server: status %d, errno %d", serverResult->status, serverResult->socket->status);
144         }
145         else
146         {
147             if (!(serverConfig.type == SOCKET_UDP))
148             {
149                 if (!SocketListen(&serverConfig, serverResult))
150                 {
151                     TraceLog(LOG_WARNING, "Failed to start listen server: status %d, errno %d", serverResult->status, serverResult->socket->status);
152                 }
153             }
154         }
155     }
156 
157     // Create the client: getaddrinfo + socket + setsockopt + connect (TCP only)
158     clientResult = LoadSocketResult();
159     if (!SocketCreate(&clientConfig, clientResult))
160     {
161         TraceLog(LOG_WARNING, "Failed to open client: status %d, errno %d", clientResult->status, clientResult->socket->status);
162     }
163     else
164     {
165         if (!(clientConfig.type == SOCKET_UDP))
166         {
167             if (!SocketConnect(&clientConfig, clientResult))
168             {
169                 TraceLog(LOG_WARNING, "Failed to connect to server: status %d, errno %d", clientResult->status, clientResult->socket->status);
170             }
171         }
172     }
173 
174     // Create and add sockets to the socket set
175     socketSet = LoadSocketSet(3);
176 
177     AddSocket(socketSet, serverResult->socket);
178     AddSocket(socketSet, clientResult->socket);
179 
180     SetTargetFPS(60);               // Set our game to run at 60 frames-per-second
181     //--------------------------------------------------------------------------------------
182 
183     // Main game loop
184     while (!WindowShouldClose())    // Detect window close button or ESC key
185     {
186         // Update
187         //----------------------------------------------------------------------------------
188         if (connected) UpdateNetwork();
189         //else NetworkConnect();
190         //----------------------------------------------------------------------------------
191 
192         // Draw
193         //----------------------------------------------------------------------------------
194         BeginDrawing();
195 
196             ClearBackground(RAYWHITE);
197 
198             // TODO: Draw relevant connection info
199 
200         EndDrawing();
201         //----------------------------------------------------------------------------------
202     }
203 
204     // De-Initialization
205     //--------------------------------------------------------------------------------------
206     CloseNetworkDevice();   // Close network communication
207 
208     CloseWindow();          // Close window and OpenGL context
209     //--------------------------------------------------------------------------------------
210 
211     return 0;
212 }