1 /* dircproxy
2 * Copyright (C) 2000,2001,2002,2003 Scott James Remnant <scott@netsplit.com>.
3 *
4 * dcc_send.c
5 * - DCC send protocol
6 * --
7 * @(#) $Id: dcc_send.c,v 1.15 2002/12/29 21:30:11 scott Exp $
8 *
9 * This file is distributed according to the GNU General Public
10 * License. For full details, read the top of 'main.c' or the
11 * file called COPYING that was distributed with this code.
12 */
13
14 #include <stdio.h>
15 #include <sys/types.h>
16 #include <sys/socket.h>
17 #include <netinet/in.h>
18 #include <arpa/inet.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <stdarg.h>
22 #include <errno.h>
23
24 #include <dircproxy.h>
25 #include "sprintf.h"
26 #include "net.h"
27 #include "dns.h"
28 #include "timers.h"
29 #include "dcc_net.h"
30 #include "dcc_send.h"
31
32 /* forward declarations */
33 static void _dccsend_data(struct dccproxy *, int);
34 static void _dccsend_error(struct dccproxy *, int, int);
35 static int _dccsend_sendpacket(struct dccproxy *);
36
37 /* Called when we've connected to the sender */
dccsend_connected(struct dccproxy * p,int sock)38 void dccsend_connected(struct dccproxy *p, int sock) {
39 if (sock != p->sender_sock) {
40 error("Unexpected socket %d in dccsend_connected, expected %d", sock,
41 p->sender_sock);
42 net_close(&sock);
43 return;
44 }
45
46 debug("DCC Connection succeeded");
47 p->sender_status |= DCC_SENDER_CONNECTED;
48 net_hook(p->sender_sock, SOCK_NORMAL, (void *)p,
49 ACTIVITY_FUNCTION(_dccsend_data),
50 ERROR_FUNCTION(_dccsend_error));
51 }
52
53 /* Called when a connection fails */
dccsend_connectfailed(struct dccproxy * p,int sock,int bad)54 void dccsend_connectfailed(struct dccproxy *p, int sock, int bad) {
55 if (sock != p->sender_sock) {
56 error("Unexpected socket %d in dccsend_connectfailed, expected %d", sock,
57 p->sender_sock);
58 net_close(&sock);
59 return;
60 }
61
62 if (p->notify_func)
63 p->notify_func(p->notify_data, p->notify_msg,
64 "Connection to remote peer failed");
65
66 debug("DCC Connection failed");
67 p->sender_status &= ~(DCC_SENDER_CREATED);
68 net_close(&(p->sender_sock));
69 p->dead = 1;
70 }
71
72 /* Called when the sendee has been accepted */
dccsend_accepted(struct dccproxy * p)73 void dccsend_accepted(struct dccproxy *p) {
74 net_hook(p->sendee_sock, SOCK_NORMAL, (void *)p,
75 ACTIVITY_FUNCTION(_dccsend_data),
76 ERROR_FUNCTION(_dccsend_error));
77
78 /* If we've already got data, we better some */
79 if (p->bufsz)
80 _dccsend_sendpacket(p);
81 }
82
83 /* Called when we get data over a DCC link */
_dccsend_data(struct dccproxy * p,int sock)84 static void _dccsend_data(struct dccproxy *p, int sock) {
85 if (sock == p->sender_sock) {
86 int buflen, nr;
87
88 /* Read the data into the buffer */
89 buflen = net_read(p->sender_sock, 0, 0);
90 p->buf = (char *)realloc(p->buf, p->bufsz + buflen);
91 nr = net_read(p->sender_sock, (void *)(p->buf + p->bufsz), buflen);
92
93 /* Check we read some */
94 if (nr > 0) {
95 uint32_t na;
96 int ret;
97
98 p->bufsz += nr;
99 p->bytes_rcvd += nr;
100
101 /* Acknowledge them */
102 na = htonl(p->bytes_rcvd);
103 ret = net_queue(p->sender_sock, (void *)&na, sizeof(uint32_t));
104 if (ret) {
105 error("Couldn't queue data in dccsend_data");
106 net_close(&sock);
107 return;
108 }
109 } else {
110 p->buf = (char *)realloc(p->buf, p->bufsz);
111 }
112
113 } else if (sock == p->sendee_sock) {
114 uint32_t ack;
115 int len;
116
117 /* We should only ever get ack's back */
118 len = net_read(p->sendee_sock, (void *)&ack, sizeof(uint32_t));
119 if (len == sizeof(uint32_t))
120 p->bytes_ackd = ntohl(ack);
121
122 } else {
123 error("Unexpected socket %d in dccsend_data, expected %d or %d", sock,
124 p->sender_sock, p->sendee_sock);
125 net_close(&sock);
126 return;
127 }
128
129 /* Receiving data is as good as trigger as any to check whether we can send
130 more. */
131 if (p->bufsz && ((p->type & DCC_SEND_FAST) || (p->type & DCC_SEND_CAPTURE) ||
132 (p->bytes_ackd >= p->bytes_sent))) {
133 /* Capturing? Just eat the buffer right here, right now */
134 if (p->type & DCC_SEND_CAPTURE) {
135 /* Write it to the file */
136 fwrite((void *)p->buf, 1, p->bufsz, p->cap_file);
137
138 /* Sent the whole thing */
139 p->bytes_sent += p->bufsz;
140 p->bufsz = 0;
141 free(p->buf);
142 p->buf = 0;
143
144 /* Check we haven't exceeded the maximum size */
145 if (p->bytes_max && (p->bytes_sent >= p->bytes_max)) {
146 /* We have, kill it. It'll automatically get unlinked */
147 debug("Too big for my boots!");
148 p->dead = 1;
149 }
150
151 } else if (p->sendee_status == DCC_SENDEE_ACTIVE) {
152 /* Send packet to the client */
153 _dccsend_sendpacket(p);
154 }
155 }
156 }
157
158 /* Called on DCC disconnection or error */
_dccsend_error(struct dccproxy * p,int sock,int bad)159 static void _dccsend_error(struct dccproxy *p, int sock, int bad) {
160 char *who;
161
162 if (sock == p->sender_sock) {
163 who = "Sender";
164 p->sender_status &= ~(DCC_SENDER_CREATED);
165 net_close(&(p->sender_sock));
166
167 /* Not necessarily bad, just means the client has gone */
168 if (p->bufsz && !(p->type & DCC_SEND_CAPTURE)) {
169 p->sender_status = DCC_SENDER_GONE;
170 } else {
171 p->dead = 1;
172 }
173 } else if (sock == p->sendee_sock) {
174 who = "Sendee";
175 p->sendee_status &= ~(DCC_SENDEE_CREATED);
176 net_close(&(p->sendee_sock));
177 p->dead = 1;
178 } else {
179 error("Unexpected socket %d in dccsend_error, expected %d or %d", sock,
180 p->sender_sock, p->sendee_sock);
181 net_close(&sock);
182 return;
183 }
184
185 if (bad) {
186 debug("Socket error with %s", who);
187 } else {
188 debug("%s disconnected", who);
189
190 /* Close the file nicely if we're capturing, so it doesn't get unlinked */
191 if (p->type & DCC_SEND_CAPTURE) {
192 debug("%s closed", p->cap_filename);
193 free(p->cap_filename);
194 fclose(p->cap_file);
195 p->cap_filename = 0;
196 p->cap_file = 0;
197 }
198 }
199 }
200
201 /* Send a packet of buffered data to the client */
_dccsend_sendpacket(struct dccproxy * p)202 static int _dccsend_sendpacket(struct dccproxy *p) {
203 unsigned long nr;
204
205 /* If we're doing simple sends, we limit the amount we send, if doing fast
206 just shove the whole lot to them */
207 if (p->type & DCC_SEND_FAST) {
208 nr = p->bufsz;
209 } else {
210 nr = (p->bufsz > DCC_BLOCK_SIZE ? DCC_BLOCK_SIZE : p->bufsz);
211 }
212
213 /* Send it to the sendee */
214 if (nr) {
215 int ret;
216
217 ret = net_queue(p->sendee_sock, (void *)p->buf, nr);
218 if (ret) {
219 error("Couldn't queue data in dccsend_data");
220 net_close(&(p->sendee_sock));
221 return -1;
222 }
223
224 /* Adjust or free the buffer */
225 p->bytes_sent += nr;
226 p->bufsz -= nr;
227 if (p->bufsz) {
228 memmove(p->buf, p->buf + nr, p->bufsz);
229 p->buf = (char *)realloc(p->buf, p->bufsz);
230 } else {
231 free(p->buf);
232 p->buf = 0;
233 }
234 }
235
236 /* Out of buffer and the sender has gone */
237 if (!p->bufsz && (p->sender_status == DCC_SENDER_GONE))
238 p->dead = 1;
239
240 return nr;
241 }
242