1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | |
19 | |
20 | #include <unistd.h> |
21 | #include <errno(*__errno_location ()).h> |
22 | #include <string.h> |
23 | #include <netinet/in.h> |
24 | |
25 | #include <ftpconn.h> |
26 | #include "priv.h" |
27 |
|
28 | |
29 | static error_t |
30 | ftp_conn_start_open_actv_data (struct ftp_conn *conn, int *data) |
31 | { |
32 | error_t err = 0; |
33 | |
34 | int dcq; |
35 | struct sockaddr *addr = conn->actv_data_addr; |
36 | socklen_t addr_len = sizeof *addr; |
37 | |
38 | if (! addr) |
39 | |
40 | |
41 | { |
42 | addr = conn->actv_data_addr = malloc (sizeof (struct sockaddr_in)); |
| Result of 'malloc' is converted to a pointer of type 'struct sockaddr', which is incompatible with sizeof operand type 'struct sockaddr_in' |
43 | if (! addr) |
44 | return ENOMEM((0x10 << 26) | ((12) & 0x3fff)); |
45 | |
46 | |
47 | if (conn->control < 0) |
48 | err = EBADF((0x10 << 26) | ((9) & 0x3fff)); |
49 | else if (getsockname (conn->control, addr, &addr_len) < 0) |
50 | err = errno(*__errno_location ()); |
51 | |
52 | if (err == EBADF((0x10 << 26) | ((9) & 0x3fff)) || err == EPIPE((0x10 << 26) | ((32) & 0x3fff))) |
53 | |
54 | { |
55 | err = ftp_conn_open (conn); |
56 | if (!err && getsockname (conn->control, addr, &addr_len) < 0) |
57 | err = errno(*__errno_location ()); |
58 | } |
59 | |
60 | if (err) |
61 | { |
62 | free (addr); |
63 | conn->actv_data_addr = 0; |
64 | return err; |
65 | } |
66 | } |
67 | |
68 | dcq = socket (AF_INET2, SOCK_STREAMSOCK_STREAM, 0); |
69 | if (dcq < 0) |
70 | return errno(*__errno_location ()); |
71 | |
72 | |
73 | ((struct sockaddr_in *)addr)->sin_port = 0; |
74 | |
75 | |
76 | if (!err && bind (dcq, addr, addr_len) < 0) |
77 | err = errno(*__errno_location ()); |
78 | |
79 | |
80 | if (!err && getsockname (dcq, addr, &addr_len) < 0) |
81 | err = errno(*__errno_location ()); |
82 | |
83 | |
84 | if (!err && listen (dcq, 1) < 0) |
85 | err = errno(*__errno_location ()); |
86 | |
87 | if (err) |
88 | close (dcq); |
89 | else |
90 | err = ftp_conn_send_actv_addr (conn, conn->actv_data_addr); |
91 | |
92 | if (! err) |
93 | *data = dcq; |
94 | |
95 | return err; |
96 | } |
97 | |
98 | |
99 | |
100 | |
101 | |
102 | |
103 | static error_t |
104 | ftp_conn_finish_open_actv_data (struct ftp_conn *conn, int *data) |
105 | { |
106 | struct sockaddr_in rmt_addr; |
107 | socklen_t rmt_addr_len = sizeof rmt_addr; |
108 | int real = accept (*data, &rmt_addr, &rmt_addr_len); |
109 | |
110 | close (*data); |
111 | |
112 | if (real < 0) |
113 | return errno(*__errno_location ()); |
114 | |
115 | *data = real; |
116 | |
117 | return 0; |
118 | } |
119 | |
120 | |
121 | |
122 | |
123 | static void |
124 | ftp_conn_abort_open_actv_data (struct ftp_conn *conn, int data) |
125 | { |
126 | close (data); |
127 | } |
128 |
|
129 | |
130 | |
131 | |
132 | static error_t |
133 | ftp_conn_start_open_data (struct ftp_conn *conn, int *data) |
134 | { |
135 | error_t err; |
136 | |
137 | if (conn->use_passive) |
138 | |
139 | { |
140 | struct sockaddr *addr; |
141 | |
142 | |
143 | |
144 | err = ftp_conn_get_pasv_addr (conn, &addr); |
145 | |
146 | if (! err) |
147 | { |
148 | int dsock = socket (PF_INET2, SOCK_STREAMSOCK_STREAM, 0); |
149 | |
150 | if (dsock < 0) |
151 | err = errno(*__errno_location ()); |
152 | else if (connect (dsock, addr, addr->sa_len) < 0) |
153 | { |
154 | err = errno(*__errno_location ()); |
155 | close (dsock); |
156 | } |
157 | else |
158 | *data = dsock; |
159 | |
160 | free (addr); |
161 | } |
162 | } |
163 | else |
164 | err = EAGAIN((0x10 << 26) | ((35) & 0x3fff)); |
165 | |
166 | if (err) |
167 | |
168 | { |
169 | conn->use_passive = 0; |
170 | err = ftp_conn_start_open_actv_data (conn, data); |
171 | } |
172 | |
173 | return err; |
174 | } |
175 | |
176 | |
177 | |
178 | |
179 | |
180 | static error_t |
181 | ftp_conn_finish_open_data (struct ftp_conn *conn, int *data) |
182 | { |
183 | if (conn->use_passive) |
184 | |
185 | return 0; |
186 | else |
187 | return ftp_conn_finish_open_actv_data (conn, data); |
188 | } |
189 | |
190 | |
191 | |
192 | |
193 | static void |
194 | ftp_conn_abort_open_data (struct ftp_conn *conn, int data) |
195 | { |
196 | if (conn->use_passive) |
197 | close (data); |
198 | else |
199 | return ftp_conn_abort_open_actv_data (conn, data); |
200 | } |
201 |
|
202 | |
203 | |
204 | |
205 | error_t |
206 | ftp_conn_start_transfer (struct ftp_conn *conn, |
207 | const char *cmd, const char *arg, |
208 | const error_t *poss_errs, |
209 | int *data) |
210 | { |
211 | error_t err = ftp_conn_start_open_data (conn, data); |
212 | |
213 | if (! err) |
214 | { |
215 | int reply; |
216 | const char *txt; |
217 | |
218 | err = ftp_conn_cmd (conn, cmd, arg, &reply, &txt); |
219 | if (!err && !REPLY_IS_PRELIM (reply)((reply) >= 100 && (reply) < 200)) |
220 | err = unexpected_reply (conn, reply, txt, poss_errs); |
221 | |
222 | if (err) |
223 | ftp_conn_abort_open_data (conn, *data); |
224 | else |
225 | err = ftp_conn_finish_open_data (conn, data); |
226 | } |
227 | |
228 | return err; |
229 | } |
230 | |
231 | |
232 | error_t |
233 | ftp_conn_finish_transfer (struct ftp_conn *conn) |
234 | { |
235 | int reply; |
236 | error_t err = ftp_conn_get_reply (conn, &reply, 0); |
237 | if (!err && reply != REPLY_TRANS_OK226 && reply != REPLY_FCMD_OK250) |
238 | err = unexpected_reply (conn, reply, 0, 0); |
239 | return err; |
240 | } |
241 |
|
242 | |
243 | |
244 | error_t |
245 | ftp_conn_start_retrieve (struct ftp_conn *conn, const char *name, int *data) |
246 | { |
247 | if (! name) |
248 | return EINVAL((0x10 << 26) | ((22) & 0x3fff)); |
249 | return |
250 | ftp_conn_start_transfer (conn, "retr", name, ftp_conn_poss_file_errs, data); |
251 | } |
252 | |
253 | |
254 | |
255 | error_t |
256 | ftp_conn_start_list (struct ftp_conn *conn, const char *name, int *data) |
257 | { |
258 | return |
259 | ftp_conn_start_transfer (conn, "nlst", name, ftp_conn_poss_file_errs, data); |
260 | } |
261 | |
262 | |
263 | |
264 | error_t |
265 | ftp_conn_start_dir (struct ftp_conn *conn, const char *name, int *data) |
266 | { |
267 | return |
268 | ftp_conn_start_transfer (conn, "list", name, ftp_conn_poss_file_errs, data); |
269 | } |
270 | |
271 | |
272 | |
273 | error_t |
274 | ftp_conn_start_store (struct ftp_conn *conn, const char *name, int *data) |
275 | { |
276 | if (! name) |
277 | return EINVAL((0x10 << 26) | ((22) & 0x3fff)); |
278 | return |
279 | ftp_conn_start_transfer (conn, "stor", name, ftp_conn_poss_file_errs, data); |
280 | } |