-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathclient.cpp
More file actions
118 lines (104 loc) · 4.33 KB
/
Copy pathclient.cpp
File metadata and controls
118 lines (104 loc) · 4.33 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
/*
// client.cpp – Kayles game client.
//
// Parses the -m flag, builds a UDP datagram (client_message.h), sends it to
// the server, and waits up to -t seconds for the reply. Prints a human-readable
// rendering of the response (MSG_GAME_STATE or MSG_WRONG_MSG) (client_print.h).
//
// Build: see Makefile
// Usage: kayles_client -a address -p port -m message -t client_timeout
//
// The -m field contains the message fields separated by '/':
// MSG_JOIN: 0/<player_id>
// MSG_MOVE_ONE: 1/<player_id>/<game_id>/<pawn>
// MSG_MOVE_TWO: 2/<player_id>/<game_id>/<pawn>
// MSG_KEEP_ALIVE: 3/<player_id>/<game_id>
// MSG_GIVE_UP: 4/<player_id>/<game_id>
*/
#include "protocol.h"
#include "helpers.h"
#include "client_config.h"
#include "client_message.h"
#include "client_print.h"
#include <arpa/inet.h>
#include <cerrno>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <netdb.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <string>
#include <vector>
int main(int argc, char *argv[]) {
const ClientConfig cfg = parse_args(argc, argv);
// ── Build datagram from -m ────────────────────────────────────────────
uint8_t send_buf[MAX_CLIENT_MSG];
const size_t send_len = build_message(cfg.message, send_buf);
// ── Create UDP socket ─────────────────────────────────────────────────
const int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0) {
std::perror("socket");
return 1;
}
// ── Set receive timeout ───────────────────────────────────────────────
timeval tv{};
tv.tv_sec = cfg.client_timeout;
tv.tv_usec = 0;
if (setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO,
&tv, sizeof(tv)) < 0) {
std::perror("setsockopt(SO_RCVTIMEO)");
close(sockfd);
return 1;
}
// ── Resolve server address ────────────────────────────────────────────
sockaddr_in server_addr{};
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(cfg.port);
if (inet_pton(AF_INET, cfg.address.c_str(),
&server_addr.sin_addr) != 1) {
addrinfo hints{};
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_DGRAM;
addrinfo *res = nullptr;
const int rc = getaddrinfo(cfg.address.c_str(), nullptr, &hints, &res);
if (rc != 0) {
std::fprintf(stderr, "cannot resolve address '%s': %s\n",
cfg.address.c_str(), gai_strerror(rc));
close(sockfd);
return 1;
}
server_addr.sin_addr =
reinterpret_cast<sockaddr_in *>(res->ai_addr)->sin_addr;
freeaddrinfo(res);
}
// ── Send ──────────────────────────────────────────────────────────────
if (sendto(sockfd, send_buf, send_len, 0,
reinterpret_cast<sockaddr *>(&server_addr),
sizeof(server_addr)) < 0) {
std::perror("sendto");
close(sockfd);
return 1;
}
// ── Receive ───────────────────────────────────────────────────────────
uint8_t recv_buf[MAX_SERVER_MSG];
sockaddr_in from_addr{};
socklen_t from_len = sizeof(from_addr);
const ssize_t n = recvfrom(sockfd, recv_buf, sizeof(recv_buf), 0,
reinterpret_cast<sockaddr *>(&from_addr),
&from_len);
if (n < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK) {
std::printf("No response from server within %d second(s).\n",
cfg.client_timeout);
} else {
std::perror("recvfrom");
}
close(sockfd);
return 0;
}
print_response(recv_buf, static_cast<size_t>(n));
close(sockfd);
return 0;
}