1 /*
2 * Copyright (C) 2017-2019 Alibaba Group Holding Limited
3 */
4
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #include <unistd.h>
9 #include <lwip/def.h>
10 #include <lwip/netdb.h>
11 #include <lwip/sockets.h>
12 #include <lwip/apps/sendfile.h>
13
14 #define DATALEN 1024
15 #define MAXSIZE 32
16 #define PATHMAX 64
17 static int sendfile_server_task_started = 0;
18
19 void sendfile_server_task_create(char *port);
20
sendfile(int out_fd,int in_fd,off_t * offset,size_t count)21 ssize_t sendfile(int out_fd, int in_fd, off_t* offset, size_t count)
22 {
23 char data[DATALEN];
24 int writelen;
25 int readlen;
26 int curlen = 0;
27
28 while(1) {
29 memset(data, 0, sizeof(data));
30 readlen = read(in_fd, data, sizeof(data));
31
32 if(0 == readlen) {
33 LWIP_DEBUGF( SENDFILE_DEBUG, ("%s:%d read finished", __func__, __LINE__));
34 break;
35 }
36
37 if(readlen < 0) {
38 if((EAGAIN != errno) && (EINTR != errno) && (EINPROGRESS != errno)) {
39 LWIP_DEBUGF( SENDFILE_DEBUG, ("%s:%d readlen %d errno: %d out_fd %d in_fd %d", __func__, __LINE__, readlen, errno, out_fd, in_fd));
40 return -1;
41 } else {
42 aos_msleep(100);
43 continue;
44 }
45 }
46
47 if(readlen > sizeof(data)) {
48 LWIP_DEBUGF( SENDFILE_DEBUG, ("%s:%d read len %d is large than data len %d",
49 __func__, __LINE__, readlen ,sizeof(data)));
50 return -1;
51 }
52
53 if((NULL != offset) && (curlen < *offset) && (curlen + readlen > *offset)) {
54 curlen += readlen;
55
56 writelen = write(out_fd, data + *offset - curlen, curlen - *offset);
57 if (((writelen < 0)&&(EAGAIN != errno) && (EINTR != errno) && (EINPROGRESS != errno))
58 || (writelen != readlen)) {
59 LWIP_DEBUGF( SENDFILE_DEBUG, ("sendfile failed out_fd %d in_fd %d", out_fd, in_fd));
60 return -1;
61 }
62 }
63 else if((NULL == offset) || (curlen + readlen > *offset)) {
64 curlen += readlen;
65 writelen = write(out_fd, data, readlen);
66 if (((writelen < 0)&&(EAGAIN != errno) && (EINTR != errno) && (EINPROGRESS != errno))
67 || (writelen != readlen)) {
68 LWIP_DEBUGF( SENDFILE_DEBUG, ("sendfile write failed out_fd %d errno %d", out_fd, errno));
69 return -1;
70 }
71 }
72 aos_msleep(100);
73 }
74 return curlen;
75 }
76
sendfile_client(int argc,char * argv[])77 int sendfile_client(int argc,char *argv[])
78 {
79 int fd, sockfd;
80 char buf[MAXSIZE];
81 int mode, size;
82 struct sockaddr_in srvaddr;
83 char * dst_addr = NULL;
84 char * dst_port = NULL;
85 char * src_file = NULL;
86 char * file_name = NULL;
87 int i;
88 int ret = -1;
89
90 for(i = 1; i< argc; i++) {
91 if(0 == strcmp(argv[i], "-d")) {
92 i++;
93 if(i >= argc) {
94 LWIP_DEBUGF( SENDFILE_DEBUG, ("%s:%d Invalid command", __func__, __LINE__));
95 goto exit;
96 }
97 dst_addr = argv[i];
98 }
99 else if(0 == strcmp(argv[i], "-p")) {
100 i++;
101 if(i >= argc) {
102 LWIP_DEBUGF( SENDFILE_DEBUG, ("%s:%d Invalid command", __func__, __LINE__));
103 goto exit;
104 }
105 dst_port = argv[i];
106 }
107 else if(0 == strcmp(argv[i], "-f")) {
108 i++;
109 if(i >= argc) {
110 LWIP_DEBUGF( SENDFILE_DEBUG, ("%s:%d Invalid command", __func__, __LINE__));
111 goto exit;
112 }
113 src_file = argv[i];
114 }
115 else if(0 == strcmp(argv[i], "-n")) {
116 i++;
117 if(i >= argc) {
118 LWIP_DEBUGF( SENDFILE_DEBUG, ("%s:%d Invalid command", __func__, __LINE__));
119 goto exit;
120 }
121 file_name = argv[i];
122 }
123 }
124
125 if((NULL == dst_addr) || (NULL == dst_port) || (NULL == src_file) || (NULL == file_name)) {
126 LWIP_DEBUGF( SENDFILE_DEBUG, ("%s:%d Invalid command", __func__, __LINE__));
127 goto exit;
128 }
129
130 sockfd = lwip_socket(AF_INET,SOCK_STREAM,0);
131 if(sockfd < 0) {
132 LWIP_DEBUGF( SENDFILE_DEBUG, ("%s:%d Invalid command", __func__, __LINE__));
133 goto exit;
134 }
135 bzero(&srvaddr,sizeof(srvaddr));
136 srvaddr.sin_family = AF_INET;
137 inet_pton(AF_INET, dst_addr, (struct sockaddr *)&(srvaddr.sin_addr));
138 srvaddr.sin_port = htons(atoi(dst_port));
139 ret = lwip_connect(sockfd, (struct sockaddr *)&srvaddr,sizeof(srvaddr));
140 if (ret == -1) {
141 lwip_close(sockfd);
142 LWIP_DEBUGF( SENDFILE_DEBUG, ("connect failed: %s", strerror(errno)));
143 goto exit;
144 }
145
146 /* write file name to server */
147 ret = lwip_write(sockfd, src_file, strlen(src_file));
148 if (ret == -1) {
149 lwip_close(sockfd);
150 LWIP_DEBUGF( SENDFILE_DEBUG, ("write failed: %s", strerror(errno)));
151 goto exit;
152 }
153
154 /* get the file mode/size from server */
155 memset(buf, 0, sizeof(buf));
156 ret = lwip_recv(sockfd, buf, sizeof(buf), 0);
157 if (ret == -1) {
158 lwip_close(sockfd);
159 LWIP_DEBUGF( SENDFILE_DEBUG, ("recv failed: %s", strerror(errno)));
160 goto exit;
161 }
162
163 if(2 != sscanf(buf, "mode=%d size=%d\n", &mode, &size)) {
164 lwip_close(sockfd);
165 LWIP_DEBUGF( SENDFILE_DEBUG, ("wrong mode and size input: %s", strerror(errno)));
166 goto exit;
167 }
168
169 fd = open(file_name, O_WRONLY|O_CREAT, mode);
170 if(fd < 0) {
171 LWIP_DEBUGF( SENDFILE_DEBUG, ("open file %s failed: %s", file_name, strerror(errno)));
172 lwip_close(sockfd);
173 goto exit;
174 }
175
176 while(1) {
177 ret = sendfile(fd, sockfd, 0, size);
178 if((ret < 0) && ((EAGAIN != errno) && (EINTR != errno) && (EINPROGRESS != errno))) {
179 LWIP_DEBUGF( SENDFILE_DEBUG, ("sendfile ret %d, %s", ret, strerror(errno)));
180 break;
181 }
182 if(ret == 0) {
183 LWIP_DEBUGF( SENDFILE_DEBUG, ("sendfile finished"));
184 break;
185 }
186 }
187
188 lwip_close(fd);
189 lwip_close(sockfd);
190 exit:
191 return ret;
192 }
193
sendfile_server(int argc,char ** argv)194 int sendfile_server(int argc, char **argv)
195 {
196 int i;
197 char* port = NULL; /* port number to use */
198
199 for(i = 1; i< argc; i++) {
200 if(0 == strcmp(argv[i], "-p")) {
201 i++;
202 if(i >= argc) {
203 LWIP_DEBUGF( SENDFILE_DEBUG, ("%s:%d Invalid command", __func__, __LINE__));
204 return -1;
205 }
206 port = argv[i];
207 if (atoi(port) <= 0) {
208 LWIP_DEBUGF( SENDFILE_DEBUG, ("invalid port: %s", port));
209 return -1;
210 }
211 }
212 }
213
214 if (port == NULL) {
215 LWIP_DEBUGF( SENDFILE_DEBUG, ("No port input"));
216 return -1;
217 }
218 sendfile_server_task_create(port);
219 return 0;
220 }
221
sendfile_server_thread(void * args)222 void sendfile_server_thread(void *args)
223 {
224 int sockfd; /* socket desciptor */
225 int connfd; /* file descriptor for socket */
226 socklen_t addrlen; /* argument to accept */
227 int ret; /* holds return code of system calls */
228 int fd; /* file descriptor for file to send */
229 int port = 0; /* port number to use */
230
231 char filename[PATHMAX]={0}; /* filename to send */
232 char buf[MAXSIZE];
233 off_t offset = 0; /* file offset */
234 struct stat stat_buf; /* argument to fstat */
235
236 struct sockaddr_in addrserver; /* socket parameters for bind ipv4*/
237 struct sockaddr_in addrclient; /* socket parameters for accept ipv4*/
238
239 port = atoi((char *)args);
240
241 /* create Internet domain socket */
242 sockfd = lwip_socket(AF_INET, SOCK_STREAM, 0);
243 if (sockfd == -1) {
244 LWIP_DEBUGF( SENDFILE_DEBUG, ("unable to create socket: %s", strerror(errno)));
245 goto exit;
246 }
247
248 /* fill in socket structure */
249 bzero(&addrserver, sizeof(addrserver));
250 addrserver.sin_family = AF_INET;
251 addrserver.sin_addr.s_addr = INADDR_ANY;
252 addrserver.sin_port = htons(port);
253
254 /* bind socket to the port */
255 ret = lwip_bind(sockfd, (struct sockaddr *)&addrserver, sizeof(addrserver));
256 if (ret == -1) {
257 LWIP_DEBUGF( SENDFILE_DEBUG, ("unable to bind to socket: %s", strerror(errno)));
258 goto exit;
259 }
260
261 /* listen for clients on the socket */
262 ret = lwip_listen(sockfd, 1);
263 if (ret == -1) {
264 LWIP_DEBUGF( SENDFILE_DEBUG, ("listen failed: %s", strerror(errno)));
265 goto exit;
266 }
267
268 for ( ;; ) {
269 addrlen = sizeof(addrclient);
270 /* wait for a client to connect */
271 connfd = lwip_accept(sockfd, (struct sockaddr *)&addrclient, &addrlen);
272 if (connfd == -1) {
273 LWIP_DEBUGF( SENDFILE_DEBUG, ("accept failed: %s", strerror(errno)));
274 goto exit;
275 }
276
277 /* get the file name from the client */
278 ret = lwip_recv(connfd, filename, sizeof(filename), 0);
279 if (ret == -1) {
280 LWIP_DEBUGF( SENDFILE_DEBUG, ("recv failed: %s", strerror(errno)));
281 lwip_close(connfd);
282 goto exit;
283 }
284
285 /* null terminate and strip any \r and \n from filename */
286 filename[ret] = '\0';
287 if ( (filename[strlen(filename)-1] == '\n') || \
288 (filename[strlen(filename)-1] == '\r'))
289 filename[strlen(filename)-1] = '\0';
290
291 /* exit server if filename is "quit" */
292 if (strcmp(filename, "quit") == 0) {
293 LWIP_DEBUGF( SENDFILE_DEBUG, ("quit command received, shutting down server"));
294 lwip_close(connfd);
295 break;
296 }
297
298 LWIP_DEBUGF( SENDFILE_DEBUG, ("received request to send file %s", filename));
299
300 /* open the file to be sent */
301 fd = open(filename, O_RDONLY);
302 if (fd < 0) {
303 lwip_close(connfd);
304 LWIP_DEBUGF( SENDFILE_DEBUG, ("unable to open '%s': %s", filename, strerror(errno)));
305 goto exit;
306 }
307
308 /* get the size of the file to be sent */
309 ret = fstat(fd, &stat_buf);
310 if (ret == -1) {
311 lwip_close(connfd);
312 lwip_close(fd);
313 LWIP_DEBUGF( SENDFILE_DEBUG, ("unable to open '%s': %s", filename, strerror(errno)));
314 goto exit;
315 }
316 memset(buf, 0, sizeof(buf));
317 snprintf(buf, sizeof(buf), "mode=%d size=%ld\n", stat_buf.st_mode, stat_buf.st_size);
318 ret = lwip_write(connfd, buf, strlen(buf));
319 if (ret < 0) {
320 LWIP_DEBUGF( SENDFILE_DEBUG, ("error from sendfile: %s", strerror(errno)));
321 lwip_close(connfd);
322 lwip_close(fd);
323 goto exit;
324 }
325
326 /* copy file using sendfile */
327 offset = 0;
328 ret = sendfile(connfd, fd, &offset, stat_buf.st_size);
329 if (ret < 0) {
330 LWIP_DEBUGF( SENDFILE_DEBUG, ("error from sendfile: %s", strerror(errno)));
331 lwip_close(connfd);
332 lwip_close(fd);
333 goto exit;
334 }
335
336 if(ret == 0) {
337 lwip_close(connfd);
338 lwip_close(fd);
339 goto exit;
340 }
341
342 if (ret != stat_buf.st_size) {
343 LWIP_DEBUGF( SENDFILE_DEBUG, ("incomplete transfer from sendfile: %d of %d bytes",
344 ret, (int)stat_buf.st_size));
345 lwip_close(connfd);
346 lwip_close(fd);
347 goto exit;
348 }
349 lwip_close(connfd);
350 lwip_close(fd);
351 }//for(;;)
352
353 exit:
354 /* close socket */
355 if(sockfd != -1) {
356 lwip_close(sockfd);
357 }
358 sendfile_server_task_started = 0;
359 }
360
sendfile_server_task_create(char * port)361 void sendfile_server_task_create(char *port)
362 {
363 if(1 != sendfile_server_task_started) {
364 aos_task_new("sendfile_server_task", sendfile_server_thread, port, 20 * 1024);
365 sendfile_server_task_started = 1;
366 }
367 else {
368 LWIP_DEBUGF( SENDFILE_DEBUG, ("http upload task is already running, create a new task should do previous exit first"));
369 }
370 }
371
372