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