]> git.stg.codes - stg.git/blob - projects/sgauthstress/proto.cpp
Add proto implementation and user state holder
[stg.git] / projects / sgauthstress / proto.cpp
1 #include <netdb.h>
2 #include <arpa/inet.h>
3
4 #include <cerrno>
5 #include <cstring>
6 #include <stdexcept>
7
8 #include "stg/common.h"
9
10 #include "proto.h"
11
12 int WaitPacket(int sd, int timeout)
13 {
14 fd_set rfds;
15 FD_ZERO(&rfds);
16 FD_SET(sd, &rfds);
17
18 struct timeval tv;
19 tv.tv_sec = timeout;
20 tv.tv_usec = 0;
21
22 int res = select(sd + 1, &rfds, NULL, NULL, &tv);
23 if (res == -1) // Error
24     {
25     if (errno != EINTR)
26         {
27         printfd(__FILE__, "Error on select: '%s'\n", strerror(errno));
28         }
29     return -1;
30     }
31
32 if (res == 0) // Timeout
33     {
34     return 0;
35     }
36
37 return 1;
38 }
39
40 PROTO::PROTO(const std::string & server,
41              uint16_t port,
42              uint16_t localPort,
43              int to)
44     : running(false),
45       stopped(true),
46       timeout(to)
47 {
48 uint32_t ip = inet_addr(server.c_str());
49 if (ip == INADDR_NONE)
50     {
51     struct hostent * hePtr = gethostbyname(server.c_str());
52     if (hePtr)
53         {
54         ip = *((uint32_t *)hePtr->h_addr_list[0]);
55         }
56     else
57         {
58         errorStr = "Unknown host: '";
59         errorStr += server;
60         errorStr += "'";
61         printfd(__FILE__, "PROTO::PROTO() - %s\n", errorStr.c_str());
62         throw std::runtime_error(errorStr);
63         }
64     }
65
66 sock = socket(AF_INET, SOCK_DGRAM, 0);
67
68 localAddr.sin_family = AF_INET;
69 localAddr.sin_port = htons(localPort);
70 localAddr.sin_addr.s_addr = inet_addr("0.0.0.0");
71
72 serverAddr.sin_family = AF_INET;
73 serverAddr.sin_port = htons(port);
74 serverAddr.sin_addr.s_addr = ip;
75
76 unsigned char key[IA_PASSWD_LEN];
77 memset(key, 0, IA_PASSWD_LEN);
78 strncpy(reinterpret_cast<char *>(key), "pr7Hhen", 8);
79 Blowfish_Init(&ctx, key, IA_PASSWD_LEN);
80
81 processors["CONN_SYN_ACK"] = &PROTO::CONN_SYN_ACK_Proc;
82 processors["ALIVE_SYN"] = &PROTO::ALIVE_SYN_Proc;
83 processors["DISCONN_SYN_ACK"] = &PROTO::DISCONN_SYN_ACK_Proc;
84 processors["FIN"] = &PROTO::FIN_Proc;
85 processors["INFO"] = &PROTO::INFO_Proc;
86 // ERR_Proc will be handled explicitly
87 }
88
89 PROTO::~PROTO()
90 {
91 close(sock);
92 }
93
94 void * PROTO::Runner(void * data)
95 {
96 PROTO * protoPtr = static_cast<PROTO *>(data);
97 protoPtr->Run();
98 }
99
100 bool PROTO::Start()
101 {
102 stopped = false;
103 running = true;
104 if (pthread_create(&tid, NULL, &Runner, NULL))
105     {
106     errorStr = "Failed to create listening thread: '";
107     errorStr += strerror(errno);
108     errorStr += "'";
109     printfd(__FILE__, "PROTO::Start() - %s\n", errorStr.c_str());
110     return false;
111     }
112 return true;
113 }
114
115 bool PROTO::Stop()
116 {
117 running = false;
118 int time = 0;
119 while (!stopped && time < timeout)
120     {
121     struct timespec ts = {1, 0};
122     nanosleep(&ts, NULL);
123     ++time;
124     }
125 if (!stopped)
126     {
127     errorStr = "Failed to stop listening thread - timed out";
128     printfd(__FILE__, "PROTO::Stop() - %s\n", errorStr.c_str());
129     return false;
130     }
131 if (pthread_join(tid, NULL))
132     {
133     errorStr = "Failed to join listening thread after stop: '";
134     errorStr += strerror(errno);
135     errorStr += "'";
136     printfd(__FILE__, "PROTO::Stop() - %s\n", errorStr.c_str());
137     return false;
138     }
139 return true;
140 }
141
142 bool PROTO::Connect(const std::string & login)
143 {
144 std::map<std::string, USER>::const_iterator it;
145 it = users.find(login);
146 if (it == users.end())
147     return false;
148
149 // Do something
150
151 return true;
152 }
153
154 bool PROTO::Disconnect(const std::string & login)
155 {
156 std::map<std::string, USER>::const_iterator it;
157 it = users.find(login);
158 if (it == users.end())
159     return false;
160
161 // Do something
162
163 return true;
164 }
165
166 void PROTO::Run()
167 {
168 while (running)
169     {
170     int res = WaitPacket(sock, timeout);
171     if (res < 0)
172         break;
173     if (!running)
174         break;
175     if (res)
176         RecvPacket();
177     }
178
179 stopped = true;
180 }
181
182 bool PROTO::RecvPacket()
183 {
184 struct sockaddr_in addr;
185 socklen_t fromLen = sizeof(addr);
186 char buffer[2048];
187 int res = recvfrom(sock, buffer, sizeof(buffer), 0, (struct sockaddr*)&addr, &fromLen);
188
189 if (res == -1)
190     return res;
191
192 return HandlePacket(buffer);
193 }
194
195 bool PROTO::HandlePacket(char * buffer)
196 {
197 if (strcmp(buffer + 4 + sizeof(HDR_8), "ERR"))
198     {
199     return ERR_Proc(buffer);
200     }
201
202 std::string packetName(buffer + 12);
203 std::map<std::string, PacketProcessor>::const_iterator it;
204 it = processors.find(packetName);
205 if (it != processors.end())
206     return (this->*it->second)(buffer);
207
208 return false;
209 }