Repository navigation
Expand file tree
/
Copy pathclientLibrary.c
More file actions
179 lines (143 loc) · 4.74 KB
/
Copy pathclientLibrary.c
File metadata and controls
179 lines (143 loc) · 4.74 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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
/**
* @file clientLibrary.c
* @brief Object Store Client Library Implementation
*
* Implements the client-side API for communicating with the object store server.
* Handles socket connection, protocol message formatting, and response parsing.
*
* @author Gennaro Baratta
* @date 2018/19
*/
#define _POSIX_C_SOURCE 200809L
#include <assert.h>
#include <clientLibrary.h>
#include <string.h>
#include <sys/time.h>
/* Global connection state */
int sockfd; /**< Socket file descriptor for server connection */
int notused, n; /**< Temporary variables for syscall returns */
/**
* Implementation of os_connect
* Creates Unix socket, connects to server, sends REGISTER command
*/
int os_connect(char* name) {
struct sockaddr_un serv_addr;
/* Create Unix domain socket */
SYSCALL(sockfd, socket(AF_UNIX, SOCK_STREAM, 0), "socket");
memset(&serv_addr, '0', sizeof(serv_addr));
/* Set up server address */
serv_addr.sun_family = AF_UNIX;
strncpy(serv_addr.sun_path, SOCKNAME, strlen(SOCKNAME) + 1);
/* Connect to server */
SYSCALL(notused,
connect(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)),
"connect");
/* Send REGISTER command */
char buf[BUFSIZE] = "";
sprintf(buf, "REGISTER %s \n", name);
SYSCALL(notused, writen(sockfd, buf, strlen(buf)), "writen client");
/* Read response */
memset(buf, 0, BUFSIZE);
SYSCALL(n, read(sockfd, buf, BUFSIZE), "read client");
/* Return 0 if "OK", -1 otherwise */
return strncmp(buf, "OK", 2);
}
/**
* Implementation of os_disconnect
* Sends LEAVE command and closes socket
*/
int os_disconnect() {
char buf[BUFSIZE];
memset(buf, 0, BUFSIZE);
/* Send LEAVE command */
SYSCALL(notused, writen(sockfd, "LEAVE \n", 8), "writen");
/* Read response */
SYSCALL(n, read(sockfd, buf, BUFSIZE), "read client");
/* Close socket */
close(sockfd);
/* Return 0 if "OK", -1 otherwise */
return strncmp(buf, "OK", 2);
}
/**
* Implementation of os_store
* Sends STORE command with object name, length, and binary data
*/
int os_store(char* name, void* block, size_t len) {
assert(block);
char buf[BUFSIZE] = "";
/* Send STORE command header: "STORE <name> <len>\n" */
sprintf(buf, "STORE %s %zu \n", name, len);
SYSCALL(notused, writen(sockfd, buf, strlen(buf)), "writen client");
/* Send binary data */
SYSCALL(notused, writen(sockfd, block, len), "writen client");
/* Read response */
memset(buf, 0, BUFSIZE);
SYSCALL(n, read(sockfd, buf, BUFSIZE), "read client");
/* Return 0 if "OK", -1 otherwise */
return strncmp(buf, "OK", 2);
}
/**
* Implementation of os_retrieve
* Sends RETRIEVE command and parses "DATA <len>\n<data>" response
* Handles data larger than buffer size by reading in chunks
*/
void* os_retrieve(char* name) {
assert(name);
char buf[BUFSIZE];
char* data;
char *token1, *token2, *token3, *tokptr;
int ret;
/* Send RETRIEVE command */
sprintf(buf, "RETRIVE %s \n", name);
SYSCALL(notused, writen(sockfd, buf, strlen(buf)), "writen client");
/* Read response header */
memset(buf, 0, BUFSIZE);
SYSCALL(n, read(sockfd, buf, BUFSIZE - 1), "read client");
/* Parse response: should be "DATA <len>\n<data>" or "KO <message>\n" */
CHECKNULL(token1, strtok_r(buf, " ", &tokptr), "strtok_r retrive");
/* Check for error response */
if (strncmp(token1, "KO", 2) == 0) {
return NULL;
}
/* Parse data length */
token2 = strtok_r(NULL, "\n", &tokptr);
if (!token2) {
return NULL;
}
size_t lenNum = strlen(token2) - 1;
size_t len = strtol(token2, NULL, 10);
/* Get pointer to data in buffer */
CHECKNULL(token3, strtok_r(NULL, " ", &tokptr), "strtok_r3 retrive");
/* Calculate how much data is already in buffer */
size_t maxLenBlock = BUFSIZE - strlen("DATA \n ") - lenNum - 1;
/* Allocate buffer for full data */
CHECKNULL(data, calloc((len + 1), sizeof(char)), "malloc");
/* Copy data from initial read */
memcpy(data, token3, len < maxLenBlock ? len : maxLenBlock);
/* If data is larger than buffer, read remaining bytes */
if (len > maxLenBlock) {
void* bufferino = calloc(len - maxLenBlock + 1, sizeof(char));
SYSCALL(ret, readn(sockfd, bufferino, len - maxLenBlock), "read file");
if (ret > 0) {
memcpy(data + maxLenBlock, bufferino, ret);
}
free(bufferino);
}
return data;
}
/**
* Implementation of os_delete
* Sends DELETE command with object name
*/
int os_delete(char* name) {
assert(name);
char buf[BUFSIZE] = "";
/* Send DELETE command */
sprintf(buf, "DELETE %s \n", name);
SYSCALL(notused, writen(sockfd, buf, strlen(buf)), "writen client");
/* Read response */
memset(buf, 0, BUFSIZE);
SYSCALL(n, read(sockfd, buf, BUFSIZE), "read client");
/* Return 0 if "OK", -1 otherwise */
return strncmp(buf, "OK", 2);
}