Skip to content

Commit e7e9b79

Browse files
committed
feat: add 4 platform client for lina server
1 parent 2617341 commit e7e9b79

File tree

20 files changed

+1150
-42
lines changed

20 files changed

+1150
-42
lines changed

.gitignore

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,15 @@ target/
1717
#.idea/
1818

1919
# Added by cargo
20-
2120
test/
2221
logs/
23-
linadata/
2422

23+
# Ide config
24+
.idea/
25+
.vscode/
26+
*.iml
27+
28+
# Custom
29+
linadata/
2530
*.sql
2631
*.db

client/c/src/crc32.c

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#include "crc32.h"
2+
3+
CRC32 CRC32_init(){
4+
CRC32 ctx;
5+
ctx.value = 0xFFFFFFFF;
6+
memset(ctx.table, 0, sizeof(ctx.table));
7+
8+
uint8_t index = 0, bit;
9+
do {
10+
ctx.table[index] = index;
11+
for(bit = 8; bit; bit--) ctx.table[index] = ctx.table[index] & 1 ? (ctx.table[index] >> 1) ^ 0xEDB88320 : ctx.table[index] >> 1;
12+
} while(++index);
13+
14+
return ctx;
15+
}
16+
17+
void CRC32_update(CRC32* crc32, uint8_t* data, size_t len) {
18+
uint8_t byte = 0;
19+
for (size_t i = 0; i < len; i++) {
20+
byte = data[i];
21+
crc32->value = (crc32->value >> 8) ^ crc32->table[(crc32->value & 0xFF) ^ byte];
22+
}
23+
}
24+
25+
uint64_t CRC32_finalize(CRC32* crc32) {
26+
uint32_t result = crc32->value;
27+
crc32->value = 0xffffffff;
28+
return result;
29+
}

client/c/src/crc32.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#ifndef CRC32_H
2+
#define CRC32_H
3+
4+
#include <stdint.h>
5+
#include <memory.h>
6+
7+
typedef struct CRC32
8+
{
9+
uint32_t value;
10+
uint32_t table[256];
11+
} CRC32;
12+
13+
CRC32 CRC32_init();
14+
void CRC32_update(CRC32* crc32, uint8_t data, size_t len);
15+
uint64_t CRC32_finalize(CRC32* crc32);
16+
#endif

client/c/src/linaclient.c

Lines changed: 321 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,321 @@
1+
#include "linaclient.h"
2+
3+
uint8_t* to_array(uint64_t value, uint8_t length, bool little_endian)
4+
{
5+
uint8_t* result = (uint8_t*)malloc(length);
6+
for (uint8_t i = 0; i < length; i++)
7+
{
8+
if (little_endian)
9+
{
10+
result[i] = (value >> (i * 8)) & 0xFF;
11+
}
12+
else
13+
{
14+
result[length - i - 1] = (value >> (i * 8)) & 0xFF;
15+
}
16+
}
17+
return result;
18+
}
19+
20+
uint64_t to_long(char* data, uint8_t length, bool little_endian)
21+
{
22+
uint64_t result = 0;
23+
for (uint8_t i = 0; i < length; i++)
24+
{
25+
if (little_endian)
26+
{
27+
result |= (uint64_t)((uint8_t)data[i]) << (i * 8);
28+
}
29+
}
30+
return result;
31+
}
32+
33+
int8_t check_sendv(LiNaClient* client, const void* buffers, size_t buffer_count, const char* context)
34+
{
35+
#ifdef _WIN32
36+
// Windows implementation using WSASend
37+
DWORD bytesSent;
38+
int result = WSASend(client->sock, (WSABUF*)buffers, 4, &bytesSent, 0, NULL, NULL);
39+
if (result == SOCKET_ERROR)
40+
return SOCKET_ERROR;
41+
return bytesSent == (1 + LINA_NAME_LENGTH + 4 + ((WSABUF*)buffers)[buffer_count - 1].len);
42+
#else
43+
// POSIX implementation using writev
44+
ssize_t result = writev(client->sock, (struct iovec*)buffers, 4);
45+
if (result == SOCKET_ERROR)
46+
return SOCKET_ERROR;
47+
return result == (1 + LINA_NAME_LENGTH + 4 + ((struct iovec*)buffers)[buffer_count - 1].iov_len);
48+
#endif
49+
return true;
50+
}
51+
52+
53+
54+
bool _connect(LiNaClient *client)
55+
{
56+
return connect(&client->sock, (struct sockaddr *)&client->sock, sizeof(client->sock));
57+
}
58+
59+
bool _disconnect(LiNaClient *client)
60+
{
61+
#ifdef _WIN32
62+
return closesocket(client->sock) == 0;
63+
#else
64+
return close(client->sock) == 0;
65+
#endif
66+
}
67+
68+
LiNaResult uploadFile(LiNaClient *client, char *name, char *data, size_t data_len, uint8_t flags)
69+
{
70+
LiNaResult res = { .status = false };
71+
char *msg = (char *)malloc(MAX_MSG_LEN);
72+
73+
if (strlen(name) > LINA_NAME_LENGTH)
74+
{
75+
strcpy(msg, "File name is too long");
76+
res.payload.message = &msg;
77+
return res;
78+
}
79+
80+
char* name_buf = (char*)malloc(LINA_NAME_LENGTH);
81+
// \0 is added by strncpy
82+
if (strlen(name) > LINA_NAME_LENGTH)
83+
{
84+
strcpy(msg, "File name is too long");
85+
res.payload.message = &msg;
86+
return res;
87+
}
88+
memcpy(name_buf, name, strlen(name));
89+
90+
uint8_t* length = to_array(data_len, 4, true);
91+
92+
CRC32 crc32 = CRC32_init();
93+
CRC32_update(&crc32, (uint8_t*)name_buf, LINA_NAME_LENGTH);
94+
CRC32_update(&crc32, length, 4);
95+
CRC32_update(&crc32, (uint8_t*)data, data_len);
96+
97+
uint8_t* checksum = to_array(CRC32_finalize(&crc32), 4, true);
98+
99+
int8_t sock_status = 0;
100+
// Connect to LiNa server
101+
__connect(client);
102+
103+
#ifdef _WIN32
104+
WSABUF buffers[4] = {
105+
{ .len = 1, .buf = (char*)&flags },
106+
{ .len = LINA_NAME_LENGTH, .buf = name_buf },
107+
{ .len = 4, .buf = (char*)checksum },
108+
{ .len = data_len, .buf = data }
109+
};
110+
#else
111+
struct iovec buffers[4] = {
112+
{ .iov_len = 1, .iov_base = &flags },
113+
{ .iov_len = LINA_NAME_LENGTH, .iov_base = name_buf },
114+
{ .iov_len = 4, .iov_base = checksum },
115+
{ .iov_len = data_len, .iov_base = data }
116+
};
117+
#endif
118+
119+
if((sock_status = check_sendv(client, buffers, 4, "Upload file")) <= 0)
120+
goto error;
121+
122+
char* header_buf = (char* )malloc(LINA_HEADER_LENGTH);
123+
if((sock_status = recv(client->sock, header_buf, LINA_HEADER_LENGTH, 0)) <= 0)
124+
goto error;
125+
__disconnect(client);
126+
127+
free(name_buf);
128+
free(length);
129+
130+
res.status = true;
131+
res.payload.data = NULL;
132+
133+
return res;
134+
135+
error:
136+
__disconnect(client);
137+
if(sock_status == 0)
138+
#ifdef _WIN32
139+
snprintf(msg, MAX_MSG_LEN, "Winsock error: %d", WSAGetLastError());
140+
#else
141+
snprintf(msg, MAX_MSG_LEN, "errno: %d", errno);
142+
#endif
143+
else if(sock_status == -1)
144+
snprintf(msg, MAX_MSG_LEN, "Socket closed unexpectedly");
145+
res.payload.message = &msg;
146+
return res;
147+
}
148+
149+
LiNaResult downloadFile(LiNaClient* client, char* name) {
150+
LiNaResult res = { .status = false };
151+
char *msg = (char *)malloc(MAX_MSG_LEN);
152+
153+
uint8_t flags = LINA_READ;
154+
if (strlen(name) > LINA_NAME_LENGTH)
155+
{
156+
strcpy(msg, "File name is too long");
157+
res.payload.message = &msg;
158+
return res;
159+
}
160+
161+
char* name_buf = (char*)malloc(LINA_NAME_LENGTH);
162+
// \0 is added by strncpy
163+
if (strlen(name) > LINA_NAME_LENGTH)
164+
{
165+
strcpy(msg, "File name is too long");
166+
res.payload.message = &msg;
167+
return res;
168+
}
169+
memcpy(name_buf, name, strlen(name));
170+
171+
uint8_t* length = to_array(0, 4, true);
172+
173+
CRC32 crc32 = CRC32_init();
174+
CRC32_update(&crc32, (uint8_t*)name_buf, LINA_NAME_LENGTH);
175+
CRC32_update(&crc32, length, 4);
176+
177+
uint8_t* checksum = to_array(CRC32_finalize(&crc32), 4, true);
178+
179+
int8_t sock_status = 0;
180+
// Connect to LiNa server
181+
__connect(client);
182+
#ifdef _WIN32
183+
WSABUF buffers[3] = {
184+
{ .len = 1, .buf = (char*)&flags },
185+
{ .len = LINA_NAME_LENGTH, .buf = name_buf },
186+
{ .len = 4, .buf = (char*)checksum }
187+
};
188+
#else
189+
// POSIX implementation using writev
190+
struct iovec buffers[3] = {
191+
{ .iov_base = &flags, .iov_len = 1 },
192+
{ .iov_base = name_buf, .iov_len = LINA_NAME_LENGTH },
193+
{ .iov_base = checksum, .iov_len = 4 },
194+
};
195+
#endif
196+
if((sock_status = check_sendv(client, buffers, 4, "Upload file")) <= 0)
197+
goto error;
198+
199+
char* header_buf = (char* )malloc(LINA_HEADER_LENGTH);
200+
if(recv(client->sock, header_buf, LINA_HEADER_LENGTH, 0) <= 0)
201+
goto error;
202+
203+
int p = 1;
204+
char* name_recv = header_buf + p;
205+
p += LINA_NAME_LENGTH;
206+
uint32_t length_recv = to_long(header_buf + p, 4, true);
207+
p += 4;
208+
uint32_t checksum_recv = to_long(header_buf + p, 4, true);
209+
210+
char* data_recv = (char* )malloc(length_recv);
211+
if((sock_status = recv(client->sock, data_recv, length_recv, 0)) <= 0)
212+
goto error;
213+
214+
CRC32_update(&crc32, name_recv, LINA_NAME_LENGTH);
215+
CRC32_update(&crc32, length_recv, 4);
216+
CRC32_update(&crc32, data_recv, length_recv);
217+
218+
if(CRC32_finalize(&crc32) != checksum_recv)
219+
goto error;
220+
221+
__disconnect(client);
222+
223+
free(name_buf);
224+
free(length);
225+
226+
res.status = true;
227+
res.payload.data = data_recv;
228+
229+
return res;
230+
231+
error:
232+
__disconnect(client);
233+
if(sock_status == 0)
234+
#ifdef _WIN32
235+
snprintf(msg, MAX_MSG_LEN, "Winsock error: %d", WSAGetLastError());
236+
#else
237+
snprintf(msg, MAX_MSG_LEN, "errno: %d", errno);
238+
#endif
239+
else if(sock_status == -1)
240+
snprintf(msg, MAX_MSG_LEN, "Socket closed unexpectedly");
241+
res.payload.message = &msg;
242+
return res;
243+
}
244+
245+
LiNaResult deleteFile(LiNaClient* client, char* name)
246+
{
247+
LiNaResult res = { .status = false };
248+
char *msg = (char *)malloc(MAX_MSG_LEN);
249+
250+
uint8_t flags = LINA_DELETE;
251+
char* name_buf = (char*)malloc(LINA_NAME_LENGTH);
252+
// \0 is added by strncpy
253+
if (strlen(name) > LINA_NAME_LENGTH)
254+
{
255+
strcpy(msg, "File name is too long");
256+
res.payload.message = &msg;
257+
return res;
258+
}
259+
memcpy(name_buf, name, strlen(name));
260+
261+
uint8_t* length = to_array(strlen(name), 4, true);
262+
263+
CRC32 crc32 = CRC32_init();
264+
CRC32_update(&crc32, (uint8_t*)name_buf, LINA_NAME_LENGTH);
265+
CRC32_update(&crc32, length, 4);
266+
267+
uint8_t* checksum = to_array(CRC32_finalize(&crc32), 4, true);
268+
269+
int8_t sock_status = 0;
270+
// Connect to LiNa server
271+
__connect(client);
272+
#ifdef _WIN32
273+
WSABUF buffers[3] = {
274+
{ .len = 1, .buf = (char*)&flags },
275+
{ .len = LINA_NAME_LENGTH, .buf = name_buf },
276+
{ .len = 4, .buf = (char*)checksum }
277+
};
278+
#else
279+
// POSIX implementation using writev
280+
struct iovec buffers[3] = {
281+
{ .iov_base = &flags, .iov_len = 1 },
282+
{ .iov_base = name_buf, .iov_len = LINA_NAME_LENGTH },
283+
{ .iov_base = checksum, .iov_len = 4 },
284+
};
285+
#endif
286+
287+
if((sock_status = check_sendv(client, buffers, 4, "Upload file")) <= 0)
288+
goto error;
289+
290+
char* header_buf = (char* )malloc(LINA_HEADER_LENGTH);
291+
if((sock_status = recv(client->sock, header_buf, LINA_HEADER_LENGTH, 0)) <= 0)
292+
goto error;
293+
__disconnect(client);
294+
295+
free(name_buf);
296+
free(length);
297+
298+
res.status = true;
299+
res.payload.data = NULL;
300+
301+
return res;
302+
303+
error:
304+
__disconnect(client);
305+
if(sock_status == 0)
306+
#ifdef _WIN32
307+
snprintf(msg, MAX_MSG_LEN, "Winsock error: %d", WSAGetLastError());
308+
#else
309+
snprintf(msg, MAX_MSG_LEN, "errno: %d", errno);
310+
#endif
311+
else if(sock_status == -1)
312+
snprintf(msg, MAX_MSG_LEN, "Socket closed unexpectedly");
313+
res.payload.message = &msg;
314+
return res;
315+
}
316+
317+
void freeResult(LiNaResult* result) {
318+
if (!result->status) {
319+
free(result->payload.message);
320+
}
321+
}

0 commit comments

Comments
 (0)