|
|
1.1 root 1: /* execnet.cpp */
2:
3: /* Synchronet command shell/module TCP/IP Network functions */
4:
1.1.1.2 ! root 5: /* $Id: execnet.cpp,v 1.30 2008/06/04 04:38:47 deuce Exp $ */
1.1 root 6:
7: /****************************************************************************
8: * @format.tab-size 4 (Plain Text/Source Code File Header) *
9: * @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) *
10: * *
1.1.1.2 ! root 11: * Copyright 2007 Rob Swindell - http://www.synchro.net/copyright.html *
1.1 root 12: * *
13: * This program is free software; you can redistribute it and/or *
14: * modify it under the terms of the GNU General Public License *
15: * as published by the Free Software Foundation; either version 2 *
16: * of the License, or (at your option) any later version. *
17: * See the GNU General Public License for more details: gpl.txt or *
18: * http://www.fsf.org/copyleft/gpl.html *
19: * *
20: * Anonymous FTP access to the most recent released source is available at *
21: * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net *
22: * *
23: * Anonymous CVS access to the development source and modification history *
24: * is available at cvs.synchro.net:/cvsroot/sbbs, example: *
25: * cvs -d :pserver:[email protected]:/cvsroot/sbbs login *
26: * (just hit return, no password is necessary) *
27: * cvs -d :pserver:[email protected]:/cvsroot/sbbs checkout src *
28: * *
29: * For Synchronet coding style and modification guidelines, see *
30: * http://www.synchro.net/source.html *
31: * *
32: * You are encouraged to submit any modifications (preferably in Unix diff *
33: * format) via e-mail to [email protected] *
34: * *
35: * Note: If this box doesn't appear square, then you need to fix your tabs. *
36: ****************************************************************************/
37:
38: #include "sbbs.h"
39: #include "cmdshell.h"
40:
41: #define TIMEOUT_SOCK_READLINE 30 /* seconds */
42: #define TIMEOUT_SOCK_LISTEN 30 /* seconds */
43: #define TIMEOUT_FTP_RESPONSE 300 /* seconds */
44:
45: int sbbs_t::exec_net(csi_t* csi)
46: {
47: char str[512],rsp[512],buf[1025],ch,*p,**pp,**pp1,**pp2;
48: ushort w;
49: uint i;
50: BOOL rd;
1.1.1.2 ! root 51: int32_t *lp,*lp1,*lp2;
1.1 root 52: time_t start;
53:
54: switch(*(csi->ip++)) { /* sub-op-code stored as next byte */
55: case CS_SOCKET_OPEN:
1.1.1.2 ! root 56: lp=getintvar(csi,*(int32_t *)csi->ip);
1.1 root 57: csi->ip+=4;
58: csi->logic=LOGIC_FALSE;
59: csi->socket_error=0;
60: if(csi->sockets>=MAX_SOCKETS)
61: return(0);
62: if(lp!=NULL) {
63:
64: SOCKET sock=open_socket(SOCK_STREAM, NULL);
65: if(sock!=INVALID_SOCKET) {
66:
67: SOCKADDR_IN addr;
68:
69: memset(&addr,0,sizeof(addr));
70: addr.sin_addr.s_addr = htonl(startup->telnet_interface);
71: addr.sin_family = AF_INET;
72:
73: if((i=bind(sock, (struct sockaddr *) &addr, sizeof (addr)))!=0) {
74: csi->socket_error=ERROR_VALUE;
75: close_socket(sock);
76: return(0);
77: }
78:
79: *lp=sock;
80:
81: for(i=0;i<csi->sockets;i++)
82: if(!csi->socket[i])
83: break;
84: csi->socket[i]=*lp;
85: if(i==csi->sockets)
86: csi->sockets++;
87: csi->logic=LOGIC_TRUE;
88: }
89: }
90: return(0);
91: case CS_SOCKET_CLOSE:
1.1.1.2 ! root 92: lp=getintvar(csi,*(int32_t *)csi->ip);
1.1 root 93: csi->ip+=4;
94: csi->logic=LOGIC_FALSE;
95: csi->socket_error=0;
96: if(lp && *lp) {
97: csi->logic=close_socket((SOCKET)*lp);
98: csi->socket_error=ERROR_VALUE;
99: for(i=0;i<csi->sockets;i++)
1.1.1.2 ! root 100: if(csi->socket[i]==(SOCKET)*lp)
1.1 root 101: csi->socket[i]=0;
102: *lp=0;
103: }
104: return(0);
105: case CS_SOCKET_CHECK:
1.1.1.2 ! root 106: lp=getintvar(csi,*(int32_t *)csi->ip);
1.1 root 107: csi->ip+=4;
108: csi->logic=LOGIC_FALSE;
109: csi->socket_error=0;
110:
111: if(lp==NULL || *lp==INVALID_SOCKET)
112: return(0);
113:
114: if(socket_check(*lp,NULL,NULL,0)==TRUE)
115: csi->logic=LOGIC_TRUE;
116: else
117: csi->socket_error=ERROR_VALUE;
118:
119: return(0);
120: case CS_SOCKET_CONNECT:
1.1.1.2 ! root 121: lp=getintvar(csi,*(int32_t *)csi->ip); /* socket */
1.1 root 122: csi->ip+=4;
123:
1.1.1.2 ! root 124: pp=getstrvar(csi,*(int32_t *)csi->ip); /* address */
1.1 root 125: csi->ip+=4;
126:
127: w=*(ushort *)csi->ip; /* port */
128: csi->ip+=2;
129:
130: csi->logic=LOGIC_FALSE;
131: csi->socket_error=0;
132:
133: if(!lp || !*lp || !pp || !*pp || !w)
134: return(0);
135:
136: ulong ip_addr;
137:
138: if((ip_addr=resolve_ip(*pp))==INADDR_NONE)
139: return(0);
140:
141: SOCKADDR_IN addr;
142:
143: memset(&addr,0,sizeof(addr));
144: addr.sin_addr.s_addr = ip_addr;
145: addr.sin_family = AF_INET;
146: addr.sin_port = htons(w);
147:
148: if((i=connect(*lp, (struct sockaddr *)&addr, sizeof(addr)))!=0) {
149: csi->socket_error=ERROR_VALUE;
150: return(0);
151: }
152: csi->logic=LOGIC_TRUE;
153: return(0);
154: case CS_SOCKET_ACCEPT:
1.1.1.2 ! root 155: lp1=getintvar(csi,*(int32_t *)csi->ip); /* socket */
1.1 root 156: csi->ip+=4;
157: csi->socket_error=0;
158: /* TODO */
159: return(0);
160: case CS_SOCKET_NREAD:
1.1.1.2 ! root 161: lp1=getintvar(csi,*(int32_t *)csi->ip); /* socket */
1.1 root 162: csi->ip+=4;
1.1.1.2 ! root 163: lp2=getintvar(csi,*(int32_t *)csi->ip); /* var */
1.1 root 164: csi->ip+=4;
165:
166: csi->logic=LOGIC_FALSE;
167: csi->socket_error=0;
168:
169: if(!lp1 || !lp2)
170: return(0);
171:
172: if(ioctlsocket(*lp1, FIONREAD, (ulong*)lp2)==0)
173: csi->logic=LOGIC_TRUE;
174: else
175: csi->socket_error=ERROR_VALUE;
176: return(0);
177: case CS_SOCKET_PEEK:
178: case CS_SOCKET_READ:
1.1.1.2 ! root 179: lp=getintvar(csi,*(int32_t *)csi->ip); /* socket */
1.1 root 180: csi->ip+=4;
1.1.1.2 ! root 181: pp=getstrvar(csi,*(int32_t *)csi->ip); /* buffer */
1.1 root 182: csi->ip+=4;
183: w=*(ushort *)csi->ip; /* length */
184: csi->ip+=2;
185:
186: csi->logic=LOGIC_FALSE;
187: csi->socket_error=0;
188:
189: if(!lp || !pp)
190: return(0);
191:
192: if(w<1 || w>sizeof(buf)-1)
193: w=sizeof(buf)-1;
194:
195: if((i=recv(*lp,buf,w
196: ,*(csi->ip-13)==CS_SOCKET_PEEK ? MSG_PEEK : 0))>0) {
197: csi->logic=LOGIC_TRUE;
198: buf[i]=0;
199: if(csi->etx) {
200: p=strchr(buf,csi->etx);
201: if(p) *p=0;
202: }
203: *pp=copystrvar(csi,*pp,buf);
204: } else
205: csi->socket_error=ERROR_VALUE;
206: return(0);
207: case CS_SOCKET_READLINE:
1.1.1.2 ! root 208: lp=getintvar(csi,*(int32_t *)csi->ip); /* socket */
1.1 root 209: csi->ip+=4;
1.1.1.2 ! root 210: pp=getstrvar(csi,*(int32_t *)csi->ip); /* buffer */
1.1 root 211: csi->ip+=4;
212: w=*(ushort *)csi->ip; /* length */
213: csi->ip+=2;
214:
215: csi->logic=LOGIC_FALSE;
216: csi->socket_error=0;
217:
218: if(!lp || !pp)
219: return(0);
220:
221: if(w<1 || w>sizeof(buf)-1)
222: w=sizeof(buf)-1;
223:
224: start=time(NULL);
225: for(i=0;i<w;) {
226:
227: if(!online)
228: return(1);
229:
230: if(!socket_check(*lp,&rd,NULL,1000))
231: return(0);
232:
233: if(!rd) {
234: if(time(NULL)-start>TIMEOUT_SOCK_READLINE) {
235: lprintf(LOG_WARNING,"!socket_readline: timeout (%d) exceeded"
236: ,TIMEOUT_SOCK_READLINE);
237: return(0);
238: }
239: continue;
240: }
241:
242: if(recv(*lp, &ch, 1, 0)!=1) {
243: csi->socket_error=ERROR_VALUE;
244: return(0);
245: }
246:
247: if(ch=='\n' && i>=1)
248: break;
249:
250: buf[i++]=ch;
251: }
252: if(i>0 && buf[i-1]=='\r')
253: buf[i-1]=0;
254: else
255: buf[i]=0;
256:
257: if(csi->etx) {
258: p=strchr(buf,csi->etx);
259: if(p) *p=0;
260: }
261: *pp=copystrvar(csi,*pp,buf);
262: csi->logic=LOGIC_TRUE;
263: return(0);
264: case CS_SOCKET_WRITE:
1.1.1.2 ! root 265: lp=getintvar(csi,*(int32_t *)csi->ip); /* socket */
1.1 root 266: csi->ip+=4;
1.1.1.2 ! root 267: pp=getstrvar(csi,*(int32_t *)csi->ip); /* buffer */
1.1 root 268: csi->ip+=4;
269:
270: csi->logic=LOGIC_FALSE;
271: csi->socket_error=0;
272:
273: if(!lp || !pp || !(*pp))
274: return(0);
275:
276: if(sendsocket(*lp,*pp,strlen(*pp))>0)
277: csi->logic=LOGIC_TRUE;
278: else
279: csi->socket_error=ERROR_VALUE;
280: return(0);
281:
282: /* FTP Functions */
283: case CS_FTP_LOGIN:
1.1.1.2 ! root 284: lp=getintvar(csi,*(int32_t *)csi->ip); /* socket */
1.1 root 285: csi->ip+=4;
1.1.1.2 ! root 286: pp1=getstrvar(csi,*(int32_t *)csi->ip); /* username */
1.1 root 287: csi->ip+=4;
1.1.1.2 ! root 288: pp2=getstrvar(csi,*(int32_t *)csi->ip); /* password */
1.1 root 289: csi->ip+=4;
290:
291: csi->logic=LOGIC_FALSE;
292: csi->socket_error=0;
293:
294: if(!lp || !pp1 || !pp2)
295: return(0);
296:
297: if(!ftp_cmd(csi,*lp,NULL,rsp))
298: return(0);
299:
300: if(atoi(rsp)!=220)
301: return(0);
302:
303: sprintf(str,"USER %s",*pp1);
304:
305: if(!ftp_cmd(csi,*lp,str,rsp))
306: return(0);
307:
308: if(atoi(rsp)==331) { /* Password needed */
309: sprintf(str,"PASS %s",*pp2);
310: if(!ftp_cmd(csi,*lp,str,rsp))
311: return(0);
312: }
313:
314: if(atoi(rsp)==230) /* Login successful */
315: csi->logic=LOGIC_TRUE;
316: return(0);
317:
318: case CS_FTP_LOGOUT:
1.1.1.2 ! root 319: lp=getintvar(csi,*(int32_t *)csi->ip); /* socket */
1.1 root 320: csi->ip+=4;
321: csi->logic=LOGIC_FALSE;
322: csi->socket_error=0;
323:
324: if(!lp)
325: return(0);
326:
327: if(!ftp_cmd(csi,*lp,"QUIT",rsp))
328: return(0);
329:
330: if(atoi(rsp)==221) /* Logout successful */
331: csi->logic=LOGIC_TRUE;
332: return(0);
333:
334: case CS_FTP_PWD:
1.1.1.2 ! root 335: lp=getintvar(csi,*(int32_t *)csi->ip); /* socket */
1.1 root 336: csi->ip+=4;
337: csi->logic=LOGIC_FALSE;
338: csi->socket_error=0;
339: if(!lp)
340: return(0);
341:
342: if(!ftp_cmd(csi,*lp,"PWD",rsp))
343: return(0);
344:
345: if(atoi(rsp)==257) /* pathname */
346: csi->logic=LOGIC_TRUE;
347: return(0);
348:
349: case CS_FTP_CWD:
1.1.1.2 ! root 350: lp=getintvar(csi,*(int32_t *)csi->ip); /* socket */
1.1 root 351: csi->ip+=4;
1.1.1.2 ! root 352: pp=getstrvar(csi,*(int32_t *)csi->ip); /* path */
1.1 root 353: csi->ip+=4;
354:
355: csi->logic=LOGIC_FALSE;
356: csi->socket_error=0;
357: if(!lp || !pp)
358: return(0);
359:
360: sprintf(str,"CWD %s",*pp);
361: if(!ftp_cmd(csi,*lp,str,rsp))
362: return(0);
363:
364: if(atoi(rsp)==250)
365: csi->logic=LOGIC_TRUE;
366:
367: return(0);
368:
369: case CS_FTP_DIR:
1.1.1.2 ! root 370: lp=getintvar(csi,*(int32_t *)csi->ip); /* socket */
1.1 root 371: csi->ip+=4;
1.1.1.2 ! root 372: pp=getstrvar(csi,*(int32_t *)csi->ip); /* path */
1.1 root 373: csi->ip+=4;
374:
375: csi->logic=LOGIC_FALSE;
376: csi->socket_error=0;
377:
378: if(!lp || !pp)
379: return(0);
380:
381: if(ftp_get(csi,*lp,*pp,NULL /* unused */, true /* DIR */)==true)
382: csi->logic=LOGIC_TRUE;
383:
384: return(0);
385:
386: case CS_FTP_DELETE:
1.1.1.2 ! root 387: lp=getintvar(csi,*(int32_t *)csi->ip); /* socket */
1.1 root 388: csi->ip+=4;
1.1.1.2 ! root 389: pp=getstrvar(csi,*(int32_t *)csi->ip); /* path */
1.1 root 390: csi->ip+=4;
391:
392: csi->logic=LOGIC_FALSE;
393: csi->socket_error=0;
394: if(!lp || !pp)
395: return(0);
396:
397: sprintf(str,"DELE %s",*pp);
398: if(!ftp_cmd(csi,*lp,str,rsp))
399: return(0);
400:
401: if(atoi(rsp)==250)
402: csi->logic=LOGIC_TRUE;
403:
404: return(0);
405:
406:
407: case CS_FTP_GET:
1.1.1.2 ! root 408: lp=getintvar(csi,*(int32_t *)csi->ip); /* socket */
1.1 root 409: csi->ip+=4;
1.1.1.2 ! root 410: pp1=getstrvar(csi,*(int32_t *)csi->ip); /* src path */
1.1 root 411: csi->ip+=4;
1.1.1.2 ! root 412: pp2=getstrvar(csi,*(int32_t *)csi->ip); /* dest path */
1.1 root 413: csi->ip+=4;
414:
415: csi->logic=LOGIC_FALSE;
416: csi->socket_error=0;
417:
418: if(!lp || !pp1 || !pp2)
419: return(0);
420:
421: if(ftp_get(csi,*lp,*pp1,*pp2)==true)
422: csi->logic=LOGIC_TRUE;
423:
424: return(0);
425:
426: case CS_FTP_PUT:
1.1.1.2 ! root 427: lp=getintvar(csi,*(int32_t *)csi->ip); /* socket */
1.1 root 428: csi->ip+=4;
1.1.1.2 ! root 429: pp1=getstrvar(csi,*(int32_t *)csi->ip); /* src path */
1.1 root 430: csi->ip+=4;
1.1.1.2 ! root 431: pp2=getstrvar(csi,*(int32_t *)csi->ip); /* dest path */
1.1 root 432: csi->ip+=4;
433:
434: csi->logic=LOGIC_FALSE;
435: csi->socket_error=0;
436:
437: if(!lp || !pp1 || !pp2)
438: return(0);
439:
440: if(ftp_put(csi,*lp,*pp1,*pp2)==true)
441: csi->logic=LOGIC_TRUE;
442:
443: return(0);
444:
445:
446: default:
447: errormsg(WHERE,ERR_CHK,"net sub-instruction",*(csi->ip-1));
448: return(0);
449: }
450: }
451:
452: /* FTP Command/Response function */
1.1.1.2 ! root 453: bool sbbs_t::ftp_cmd(csi_t* csi, SOCKET sock, const char* cmdsrc, char* rsp)
1.1 root 454: {
455: char cmd[512];
456: int len;
457: BOOL data_avail;
458: time_t start;
459:
460: if(cmdsrc!=NULL) {
461: sprintf(cmd,"%s\r\n",cmdsrc);
462:
463: if(csi->ftp_mode&CS_FTP_ECHO_CMD)
464: bputs(cmd);
465:
466: len=strlen(cmd);
467: if(sendsocket(sock,cmd,len)!=len) {
468: csi->socket_error=ERROR_VALUE;
469: return(FALSE);
470: }
471: }
472:
473: if(rsp!=NULL) {
474:
475: int rd;
476: char ch;
477:
478: while(1) {
479: rd=0;
480:
481: start=time(NULL);
482: while(rd<500) {
483:
484: if(!online)
485: return(FALSE);
486:
487: if(!socket_check(sock,&data_avail,NULL,1000))
488: return(FALSE);
489:
490: if(!data_avail) {
491: if(time(NULL)-start>TIMEOUT_FTP_RESPONSE) {
492: lprintf(LOG_WARNING,"!ftp_cmd: TIMEOUT_FTP_RESPONSE (%d) exceeded"
493: ,TIMEOUT_FTP_RESPONSE);
494: return(FALSE);
495: }
496: continue;
497: }
498:
499: if(recv(sock, &ch, 1, 0)!=1) {
500: csi->socket_error=ERROR_VALUE;
501: return(FALSE);
502: }
503:
504: if(ch=='\n' && rd>=1)
505: break;
506:
507: rsp[rd++]=ch;
508: }
509: rsp[rd-1]=0;
510: if(csi->ftp_mode&CS_FTP_ECHO_RSP)
511: bprintf("%s\r\n",rsp);
512: if(rsp[0]!=' ' && rsp[3]!='-')
513: break;
514: }
515: }
516:
517: return(TRUE);
518: }
519:
520: SOCKET sbbs_t::ftp_data_sock(csi_t* csi, SOCKET ctrl_sock, SOCKADDR_IN* addr)
521: {
522: char cmd[512];
523: char rsp[512];
524: char* p;
525: socklen_t addr_len;
526: SOCKET data_sock;
527: int ip_b[4];
528: int port_b[2];
529: union {
530: DWORD dw;
531: BYTE b[sizeof(DWORD)];
532: } ip_addr;
533: union {
534: WORD w;
535: BYTE b[sizeof(WORD)];
536: } port;
537:
538: if(csi->ftp_mode&CS_FTP_ASCII)
539: strcpy(cmd,"TYPE A");
540: else /* BINARY */
541: strcpy(cmd,"TYPE I");
542: if(!ftp_cmd(csi,ctrl_sock,cmd,rsp)
543: || atoi(rsp)!=200) {
544: return(INVALID_SOCKET);
545: }
546:
547: if((data_sock=open_socket(SOCK_STREAM, "ftp"))==INVALID_SOCKET) {
548: csi->socket_error=ERROR_VALUE;
549: return(INVALID_SOCKET);
550: }
551:
552: memset(addr,0,sizeof(SOCKADDR_IN));
553: addr->sin_addr.s_addr = htonl(startup->telnet_interface);
554: addr->sin_family = AF_INET;
555:
556: if(bind(data_sock, (struct sockaddr *)addr,sizeof(SOCKADDR_IN))!= 0) {
557: csi->socket_error=ERROR_VALUE;
558: close_socket(data_sock);
559: return(INVALID_SOCKET);
560: }
561:
562: if(csi->ftp_mode&CS_FTP_PASV) {
563:
564: if(!ftp_cmd(csi,ctrl_sock,"PASV",rsp)
565: || atoi(rsp)!=227 /* PASV response */) {
566: bprintf("ftp: failure, line %d",__LINE__);
567: close_socket(data_sock);
568: return(INVALID_SOCKET);
569: }
570:
571: p=strchr(rsp,'(');
572: if(p==NULL) {
573: bprintf("ftp: failure, line %d",__LINE__);
574: close_socket(data_sock);
575: return(INVALID_SOCKET);
576: }
577: p++;
578: if(sscanf(p,"%u,%u,%u,%u,%u,%u"
579: ,&ip_b[0],&ip_b[1],&ip_b[2],&ip_b[3]
580: ,&port_b[0],&port_b[1])!=6) {
581: bprintf("ftp: failure, line %d",__LINE__);
582: close_socket(data_sock);
583: return(INVALID_SOCKET);
584: }
585:
586: ip_addr.b[0]=ip_b[0]; ip_addr.b[1]=ip_b[1];
587: ip_addr.b[2]=ip_b[2]; ip_addr.b[3]=ip_b[3];
588: port.b[0]=port_b[0]; port.b[1]=port_b[1];
589:
590: addr->sin_addr.s_addr=ip_addr.dw;
591: addr->sin_port=port.w;
592:
593: } else { /* Normal (Active) FTP */
594:
595: addr_len=sizeof(SOCKADDR_IN);
596: if(getsockname(data_sock, (struct sockaddr *)addr,&addr_len)!=0) {
597: csi->socket_error=ERROR_VALUE;
598: close_socket(data_sock);
599: return(INVALID_SOCKET);
600: }
601:
602: SOCKADDR_IN ctrl_addr;
603: addr_len=sizeof(ctrl_addr);
604: if(getsockname(ctrl_sock, (struct sockaddr *)&ctrl_addr,&addr_len)!=0) {
605: csi->socket_error=ERROR_VALUE;
606: close_socket(data_sock);
607: return(INVALID_SOCKET);
608: }
609:
610: if(listen(data_sock, 1)!= 0) {
611: csi->socket_error=ERROR_VALUE;
612: close_socket(data_sock);
613: return(INVALID_SOCKET);
614: }
615:
616: ip_addr.dw=ntohl(ctrl_addr.sin_addr.s_addr);
617: port.w=ntohs(addr->sin_port);
618: sprintf(cmd,"PORT %u,%u,%u,%u,%u,%u"
619: ,ip_addr.b[3]
620: ,ip_addr.b[2]
621: ,ip_addr.b[1]
622: ,ip_addr.b[0]
623: ,port.b[1]
624: ,port.b[0]
625: );
626:
627: if(!ftp_cmd(csi,ctrl_sock,cmd,rsp)
628: || atoi(rsp)!=200 /* PORT response */) {
629: close_socket(data_sock);
630: return(INVALID_SOCKET);
631: }
632:
633: }
634:
635: return(data_sock);
636: }
637:
638: bool sbbs_t::ftp_get(csi_t* csi, SOCKET ctrl_sock, char* src, char* dest, bool dir)
639: {
640: char cmd[512];
641: char rsp[512];
642: char buf[4097];
643: int rd;
644: int result;
645: BOOL data_avail;
646: ulong total=0;
647: SOCKET data_sock;
648: SOCKADDR_IN addr;
649: socklen_t addr_len;
650: FILE* fp=NULL;
651: struct timeval tv;
652: fd_set socket_set;
653:
654: if((data_sock=ftp_data_sock(csi, ctrl_sock, &addr))==INVALID_SOCKET)
655: return(false);
656:
657: if(csi->ftp_mode&CS_FTP_PASV) {
658:
659: #if 0 // Debug
660: bprintf("Connecting to %s:%hd\r\n"
661: ,inet_ntoa(addr.sin_addr)
662: ,ntohs(addr.sin_port));
663: #endif
664:
665: if(connect(data_sock,(struct sockaddr *)&addr,sizeof(addr))!=0) {
666: csi->socket_error=ERROR_VALUE;
667: close_socket(data_sock);
668: return(false);
669: }
670: }
671:
672: if(dir)
673: sprintf(cmd,"LIST %s",src);
674: else
675: sprintf(cmd,"RETR %s",src);
676:
677: if(!ftp_cmd(csi,ctrl_sock,cmd,rsp)
678: || atoi(rsp)!=150 /* Open data connection */) {
679: close_socket(data_sock);
680: return(false);
681: }
682:
683: if(!(csi->ftp_mode&CS_FTP_PASV)) { /* Normal (Active) FTP */
684:
685: /* Setup for select() */
686: tv.tv_sec=TIMEOUT_SOCK_LISTEN;
687: tv.tv_usec=0;
688:
689: FD_ZERO(&socket_set);
690: FD_SET(data_sock,&socket_set);
691:
692: result=select(data_sock+1,&socket_set,NULL,NULL,&tv);
693: if(result<1) {
694: csi->socket_error=ERROR_VALUE;
695: closesocket(data_sock);
696: return(false);
697: }
698:
699: SOCKET accept_sock;
700:
701: addr_len=sizeof(addr);
702: if((accept_sock=accept_socket(data_sock,(struct sockaddr*)&addr,&addr_len))
703: ==INVALID_SOCKET) {
704: csi->socket_error=ERROR_VALUE;
705: closesocket(data_sock);
706: return(false);
707: }
708:
709: close_socket(data_sock);
710: data_sock=accept_sock;
711: }
712:
713: if(!dir)
714: if((fp=fopen(dest,"wb"))==NULL) {
715: close_socket(data_sock);
716: return(false);
717: }
718:
719: while(online) {
720:
721: if(!socket_check(ctrl_sock,NULL,NULL,0))
722: break; /* Control connection lost */
723:
724: if(!socket_check(data_sock,&data_avail,NULL,100))
725: break; /* Data connection lost */
726:
727: if(!data_avail)
728: continue;
729:
730: if((rd=recv(data_sock, buf, sizeof(buf)-1, 0))<1)
731: break;
732:
733: if(dir) {
734: buf[rd]=0;
735: bputs(buf);
736: } else
737: fwrite(buf,1,rd,fp);
738:
739: total+=rd;
740:
741: if(!dir && csi->ftp_mode&CS_FTP_HASH)
742: outchar('#');
743: }
744:
745: if(!dir && csi->ftp_mode&CS_FTP_HASH) {
746: CRLF;
747: }
748:
749: if(fp!=NULL)
750: fclose(fp);
751:
752: close_socket(data_sock);
753:
754: if(!ftp_cmd(csi,ctrl_sock,NULL,rsp)
755: || atoi(rsp)!=226 /* Download complete */)
756: return(false);
757:
758: bprintf("ftp: %lu bytes received.\r\n", total);
759:
760: return(true);
761: }
762:
763: bool sbbs_t::ftp_put(csi_t* csi, SOCKET ctrl_sock, char* src, char* dest)
764: {
765: char cmd[512];
766: char rsp[512];
767: char path[MAX_PATH+1];
768: char buf[4097];
769: int rd;
770: int result;
771: ulong total=0;
772: SOCKET data_sock;
773: SOCKADDR_IN addr;
774: socklen_t addr_len;
775: FILE* fp=NULL;
776: bool error=false;
777: struct timeval tv;
778: fd_set socket_set;
779:
780: SAFECOPY(path,src);
781:
782: if(!fexistcase(path))
783: return(false);
784:
785: if((data_sock=ftp_data_sock(csi, ctrl_sock, &addr))==INVALID_SOCKET) {
786: bprintf("ftp: failure, line %d",__LINE__);
787: return(false);
788: }
789:
790: if(csi->ftp_mode&CS_FTP_PASV) {
791:
792: #if 0 // Debug
793: bprintf("Connecting to %s:%hd\r\n"
794: ,inet_ntoa(addr.sin_addr)
795: ,ntohs(addr.sin_port));
796: #endif
797:
798: if(connect(data_sock,(struct sockaddr *)&addr,sizeof(addr))!=0) {
799: bprintf("ftp: failure, line %d",__LINE__);
800: csi->socket_error=ERROR_VALUE;
801: close_socket(data_sock);
802: return(false);
803: }
804: }
805:
806: if((fp=fopen(path,"rb"))==NULL) {
807: bprintf("ftp: failure, line %d",__LINE__);
808: close_socket(data_sock);
809: return(false);
810: }
811:
812: sprintf(cmd,"STOR %s",dest);
813:
814: if(!ftp_cmd(csi,ctrl_sock,cmd,rsp)
815: || atoi(rsp)!=150 /* Open data connection */) {
816: bprintf("ftp: failure, line %d",__LINE__);
817: close_socket(data_sock);
818: return(false);
819: }
820:
821: if(!(csi->ftp_mode&CS_FTP_PASV)) { /* Normal (Active) FTP */
822:
823: /* Setup for select() */
824: tv.tv_sec=TIMEOUT_SOCK_LISTEN;
825: tv.tv_usec=0;
826:
827: FD_ZERO(&socket_set);
828: FD_SET(data_sock,&socket_set);
829:
830: result=select(data_sock+1,&socket_set,NULL,NULL,&tv);
831: if(result<1) {
832: csi->socket_error=ERROR_VALUE;
833: closesocket(data_sock);
834: return(false);
835: }
836:
837: SOCKET accept_sock;
838:
839: addr_len=sizeof(addr);
840: if((accept_sock=accept_socket(data_sock,(struct sockaddr*)&addr,&addr_len))
841: ==INVALID_SOCKET) {
842: csi->socket_error=ERROR_VALUE;
843: closesocket(data_sock);
844: return(false);
845: }
846:
847: close_socket(data_sock);
848: data_sock=accept_sock;
849: }
850:
851: while(online && !feof(fp)) {
852:
853: rd=fread(buf,sizeof(char),sizeof(buf),fp);
854: if(rd<1) /* EOF or READ error */
855: break;
856:
857: if(!socket_check(ctrl_sock,NULL,NULL,0))
858: break; /* Control connection lost */
859:
860: if(sendsocket(data_sock,buf,rd)<1) {
861: error=true;
862: break;
863: }
864:
865: total+=rd;
866:
867: if(csi->ftp_mode&CS_FTP_HASH)
868: outchar('#');
869: }
870:
871: if(csi->ftp_mode&CS_FTP_HASH) {
872: CRLF;
873: }
874:
875: fclose(fp);
876:
877: close_socket(data_sock);
878:
879: if(!ftp_cmd(csi,ctrl_sock,NULL,rsp)
880: || atoi(rsp)!=226 /* Upload complete */)
881: return(false);
882:
883: if(!error)
884: bprintf("ftp: %lu bytes sent.\r\n", total);
885:
886: return(!error);
887: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.