modules/server/dcc.c File Reference

#include <unistd.h>
#include <netinet/in.h>
#include <fcntl.h>
#include "server.h"

Go to the source code of this file.

Data Structures

struct  dcc_listen
struct  dcc_send

Defines

#define DCC_FILTER_LEVEL   (SOCKBUF_LEVEL_TEXT_BUFFER + 100)

Typedefs

typedef struct dcc_listen dcc_listen_t
typedef struct dcc_send dcc_send_t

Functions

static int dcc_listen_newclient (void *client_data, int idx, int newidx, const char *peer_ip, int peer_port)
static int dcc_listen_delete (event_owner_t *owner, void *client_data)
static int dcc_listen_timeout (void *client_data)
static int dcc_chat_connect (void *client_data, int idx, const char *peer_ip, int peer_port)
static int dcc_chat_eof (void *client_data, int idx, int err, const char *errmsg)
static int dcc_chat_delete (void *client_data, int idx)
static int dcc_send_connect (void *client_data, int idx, const char *peer_ip, int peer_port)
static int dcc_send_read (void *client_data, int idx, char *data, int len)
static int dcc_send_written (void *client_data, int idx, int len, int remaining)
static int dcc_send_eof (void *client_data, int idx, int err, const char *errmsg)
static int dcc_send_delete (void *client_data, int idx)
static int dcc_send_done (dcc_send_t *send)
static int dcc_recv_timeout (void *client_data)
static int dcc_recv_connect (void *client_data, int idx, const char *peer_ip, int peer_port)
static int dcc_recv_read (void *client_data, int idx, char *data, int len)
static int dcc_recv_eof (void *client_data, int idx, int err, const char *errmsg)
static int dcc_recv_delete (void *client_data, int idx)
static void update_snapshot (dcc_send_t *send, int len)
static int dcc_dns_callback (void *client_data, const char *host, char **ips)
int dcc_dns_set (const char *host)
static dcc_listen_tdcc_listen (int timeout)
int dcc_start_chat (const char *nick, int timeout)
int dcc_start_send (const char *nick, const char *fname, int timeout)
static int dcc_send_bytes (dcc_send_t *send)
int dcc_send_info (int idx, int field, void *valueptr)
int dcc_accept_send (char *nick, char *localfname, char *fname, int size, int resume, char *ip, int port, int timeout)
static void got_chat (char *nick, char *uhost, user_t *u, char *text)
static void got_resume (char *nick, char *uhost, user_t *u, char *text)
static void got_accept (char *nick, char *uhost, user_t *u, char *text)
static void got_send (char *nick, char *uhost, user_t *u, char *text)
static int got_dcc (char *nick, char *uhost, user_t *u, char *dest, char *cmd, char *text)

Variables

static const char rcsid [] = "$Id: dcc.c,v 1.27 2007-09-13 22:20:57 sven Exp $"
static dcc_send_tdcc_send_head = NULL
static dcc_send_tdcc_recv_head = NULL
event_owner_t server_dcclistener_owner
static sockbuf_handler_t dcc_listen_handler
static sockbuf_filter_t dcc_chat_filter
static sockbuf_filter_t dcc_send_filter
static sockbuf_filter_t dcc_recv_filter
bind_list_t ctcp_dcc_binds []


Define Documentation

#define DCC_FILTER_LEVEL   (SOCKBUF_LEVEL_TEXT_BUFFER + 100)


Typedef Documentation

typedef struct dcc_listen dcc_listen_t

typedef struct dcc_send dcc_send_t


Function Documentation

int dcc_accept_send ( char *  nick,
char *  localfname,
char *  fname,
int  size,
int  resume,
char *  ip,
int  port,
int  timeout 
)

Definition at line 506 of file dcc.c.

References dcc_send::bytes_left, dcc_send::bytes_sent, dcc_send::connect_time, dcc_recv_timeout(), egg_connect(), dcc_send::fd, dcc_send::fname, dcc_send::idx, dcc_send::ip, LOG_MISC, dcc_send::next, dcc_send::nick, dcc_send::port, printserv, putlog(), dcc_send::request_time, egg_timeval::sec, server_config, SERVER_NORMAL, server_owner, dcc_send::size, sockbuf_attach_filter(), sockbuf_new(), timer_create_complex(), timer_get_now_sec(), dcc_send::timer_id, and egg_timeval::usec.

00507 {
00508   dcc_send_t *send;
00509   char *quote;
00510   egg_timeval_t howlong;
00511 
00512   send = calloc(1, sizeof(*send));
00513   send->next = dcc_recv_head;
00514   dcc_recv_head = send;
00515 
00516   /* See if they want the default timeout. */
00517   if (!timeout) timeout = server_config.dcc_timeout;
00518   if (timeout > 0) {
00519     char buf[128];
00520 
00521     snprintf(buf, sizeof(buf), "dcc recv %s/%d", ip, port);
00522     howlong.sec = timeout;
00523     howlong.usec = 0;
00524     send->timer_id = timer_create_complex(&howlong, buf, dcc_recv_timeout, send, 0, &server_owner);
00525   }
00526   else send->connect_time = -1;
00527 
00528   send->port = port;
00529   send->fname = strdup(localfname);
00530   send->nick = strdup(nick);
00531   send->ip = strdup(ip);
00532   send->size = size;
00533   send->bytes_sent = 0;
00534   send->bytes_left = size;
00535   timer_get_now_sec(&send->request_time);
00536 
00537   if (resume < 0) {
00538     send->fd = open(localfname, O_RDWR | O_CREAT, 0640);
00539     resume = lseek(send->fd, 0, SEEK_END);
00540     close(send->fd);
00541     if (resume < 0) resume = 0;
00542   }
00543 
00544   if (resume >= size) resume = 0;
00545 
00546   if (resume) {
00547     putlog(LOG_MISC, "*", "sending resume request");
00548     send->idx = sockbuf_new();
00549     send->fd = open(localfname, O_RDWR | O_CREAT, 0640);
00550     if (resume < 0) resume = lseek(send->fd, 0, SEEK_END);
00551     else resume = lseek(send->fd, resume, SEEK_SET);
00552     if (strchr(fname, ' ')) quote = "\"";
00553     else quote = "";
00554     printserv(SERVER_NORMAL, "PRIVMSG %s :%cDCC RESUME %s%s%s %d %d%c", nick, 1, quote, fname, quote, port, resume, 1);
00555   }
00556   else {
00557     send->idx = egg_connect(ip, port, -1);
00558     send->fd = open(localfname, O_RDWR | O_CREAT | O_TRUNC, 0640);
00559   }
00560 
00561   sockbuf_attach_filter(send->idx, &dcc_recv_filter, send);
00562 
00563   return(send->idx);
00564 }

static int dcc_chat_connect ( void *  client_data,
int  idx,
const char *  peer_ip,
int  peer_port 
) [static]

Definition at line 237 of file dcc.c.

References DCC_FILTER_LEVEL, NULL, sockbuf_detach_filter(), and sockbuf_on_connect().

00238 {
00239   sockbuf_detach_filter(idx, &dcc_chat_filter, NULL);
00240   return sockbuf_on_connect(idx, DCC_FILTER_LEVEL, peer_ip, peer_port);
00241 }

static int dcc_chat_delete ( void *  client_data,
int  idx 
) [static]

Definition at line 249 of file dcc.c.

References dcc_send::serv, and sockbuf_delete().

00250 {
00251   int serv = (int) client_data;
00252   sockbuf_delete(serv);
00253   return(0);
00254 }

static int dcc_chat_eof ( void *  client_data,
int  idx,
int  err,
const char *  errmsg 
) [static]

Definition at line 243 of file dcc.c.

References DCC_FILTER_LEVEL, NULL, sockbuf_detach_filter(), and sockbuf_on_eof().

00244 {
00245   sockbuf_detach_filter(idx, &dcc_chat_filter, NULL);
00246   return sockbuf_on_eof(idx, DCC_FILTER_LEVEL, err, errmsg);
00247 }

static int dcc_dns_callback ( void *  client_data,
const char *  host,
char **  ips 
) [static]

Definition at line 116 of file dcc.c.

References current_server, socket_ip_to_uint(), and str_redup().

Referenced by dcc_dns_set().

00117 {
00118   if (ips && ips[0]) str_redup(&current_server.myip, ips[0]);
00119   else str_redup(&current_server.myip, "127.0.0.1");
00120   socket_ip_to_uint(current_server.myip, &current_server.mylongip);
00121   return(0);
00122 }

int dcc_dns_set ( const char *  host  ) 

Definition at line 124 of file dcc.c.

References dcc_dns_callback(), egg_dns_lookup(), NULL, and server_owner.

00125 {
00126   egg_dns_lookup(host, 0, dcc_dns_callback, NULL, &server_owner);
00127   return(0);
00128 }

static dcc_listen_t* dcc_listen ( int  timeout  )  [static]

Definition at line 130 of file dcc.c.

References dcc_listen_timeout(), egg_listen(), dcc_send::idx, NULL, dcc_listen::port, dcc_send::port, egg_timeval::sec, dcc_listen::serv, server_config, server_owner, sockbuf_set_handler(), timer_create_complex(), dcc_listen::timer_id, and egg_timeval::usec.

Referenced by dcc_start_chat(), and dcc_start_send().

00131 {
00132   dcc_listen_t *listen;
00133   int idx, port;
00134   egg_timeval_t howlong;
00135 
00136   idx = egg_listen(0, &port);
00137   if (idx < 0) return(NULL);
00138 
00139   listen = calloc(1, sizeof(*listen));
00140   listen->serv = idx;
00141   listen->port = port;
00142 
00143   sockbuf_set_handler(idx, &dcc_listen_handler, listen, &server_dcclistener_owner);
00144 
00145   /* See if they want the default timeout. */
00146   if (!timeout) timeout = server_config.dcc_timeout;
00147 
00148   if (timeout > 0) {
00149     char buf[128];
00150 
00151     snprintf(buf, sizeof(buf), "dcc listen port %d", port);
00152     howlong.sec = timeout;
00153     howlong.usec = 0;
00154     listen->timer_id = timer_create_complex(&howlong, buf, dcc_listen_timeout, listen, 0, &server_owner);
00155   }
00156 
00157   return(listen);
00158 }

static int dcc_listen_delete ( event_owner_t owner,
void *  client_data 
) [static]

Definition at line 203 of file dcc.c.

References dcc_listen::client, sockbuf_isvalid(), SOCKBUF_LEVEL_INTERNAL, sockbuf_on_eof(), dcc_listen::timeout, timer_destroy(), and dcc_listen::timer_id.

00204 {
00205   dcc_listen_t *listen = client_data;
00206 
00207   /* If the timer is still going, kill it. */
00208   if (listen->timer_id != -1) {
00209     timer_destroy(listen->timer_id);
00210     listen->timer_id = -1;
00211   }
00212 
00213   /* If we're still waiting for the connection to come in, then send
00214    * an error to the associated client sock. */
00215   if (sockbuf_isvalid(listen->client)) {
00216     if (listen->timeout) {
00217       sockbuf_on_eof(listen->client, SOCKBUF_LEVEL_INTERNAL, -1, "DCC timed out");
00218     }
00219     else {
00220       sockbuf_on_eof(listen->client, SOCKBUF_LEVEL_INTERNAL, -2, "DCC listening socket unexpectedly closed");
00221     }
00222   }
00223   free(listen);
00224   return(0);
00225 }

static int dcc_listen_newclient ( void *  client_data,
int  idx,
int  newidx,
const char *  peer_ip,
int  peer_port 
) [static]

Definition at line 184 of file dcc.c.

References dcc_listen::client, SOCKBUF_CLIENT, SOCKBUF_CONNECTING, sockbuf_delete(), sockbuf_get_sock(), and sockbuf_set_sock().

00185 {
00186   int sock;
00187   dcc_listen_t *chat = client_data;
00188 
00189   sock = sockbuf_get_sock(newidx);
00190   sockbuf_set_sock(newidx, -1, 0);
00191   sockbuf_delete(newidx);
00192 
00193   /* Give the waiting sockbuf the new socket and mark it as a client
00194    * so that it fires the on_connect event. */
00195   sockbuf_set_sock(chat->client, sock, SOCKBUF_CONNECTING|SOCKBUF_CLIENT);
00196 
00197   /* Delete the listening idx since it's not needed. */
00198   chat->client = -1;
00199   sockbuf_delete(idx);
00200   return(0);
00201 }

static int dcc_listen_timeout ( void *  client_data  )  [static]

Definition at line 227 of file dcc.c.

References dcc_listen::serv, sockbuf_delete(), dcc_listen::timeout, and dcc_listen::timer_id.

Referenced by dcc_listen().

00228 {
00229   dcc_listen_t *listen = client_data;
00230 
00231   listen->timeout = 1;
00232   listen->timer_id = -1;
00233   sockbuf_delete(listen->serv);
00234   return(0);
00235 }

static int dcc_recv_connect ( void *  client_data,
int  idx,
const char *  peer_ip,
int  peer_port 
) [static]

Definition at line 575 of file dcc.c.

References dcc_send::connect_time, DCC_FILTER_LEVEL, sockbuf_on_connect(), timer_destroy(), timer_get_now_sec(), and dcc_send::timer_id.

00576 {
00577   dcc_send_t *send = client_data;
00578 
00579   /* send->connect_time holds our connect timer if there was one */
00580   if (send->timer_id >= 0) timer_destroy(send->timer_id);
00581   timer_get_now_sec(&send->connect_time);
00582   sockbuf_on_connect(idx, DCC_FILTER_LEVEL, peer_ip, peer_port);
00583   return(0);
00584 }

static int dcc_recv_delete ( void *  client_data,
int  idx 
) [static]

Definition at line 607 of file dcc.c.

References dcc_send::fd, dcc_send::fname, dcc_send::ip, dcc_send::next, dcc_send::nick, NULL, timer_destroy(), and dcc_send::timer_id.

00608 {
00609   dcc_send_t *send = client_data;
00610   dcc_send_t *prev, *ptr;
00611 
00612   if (send->timer_id != -1) timer_destroy(send->timer_id);
00613 
00614   if (send->fd != -1) close(send->fd);
00615   if (send->fname) free(send->fname);
00616   if (send->nick) free(send->nick);
00617   if (send->ip) free(send->ip);
00618   prev = NULL;
00619   for (ptr = dcc_recv_head; ptr; ptr = ptr->next) {
00620     if (ptr == send) break;
00621     prev = ptr;
00622   }
00623   if (prev) prev->next = send->next;
00624   else dcc_recv_head = send->next;
00625   free(send);
00626   return(0);
00627 }

static int dcc_recv_eof ( void *  client_data,
int  idx,
int  err,
const char *  errmsg 
) [static]

Definition at line 600 of file dcc.c.

References DCC_FILTER_LEVEL, sockbuf_delete(), and sockbuf_on_eof().

00601 {
00602   sockbuf_on_eof(idx, DCC_FILTER_LEVEL, err, errmsg);
00603   sockbuf_delete(idx);
00604   return(0);
00605 }

static int dcc_recv_read ( void *  client_data,
int  idx,
char *  data,
int  len 
) [static]

Definition at line 586 of file dcc.c.

References dcc_send::bytes_left, dcc_send::bytes_sent, DCC_FILTER_LEVEL, dcc_send::fd, sockbuf_on_read(), sockbuf_on_write(), and update_snapshot().

00587 {
00588   dcc_send_t *send = client_data;
00589   int nlen; /* len in network byte order */
00590 
00591   send->bytes_sent += len;
00592   send->bytes_left -= len;
00593   update_snapshot(send, len);
00594   write(send->fd, data, len);
00595   nlen = htonl(send->bytes_sent);
00596   sockbuf_on_write(idx, DCC_FILTER_LEVEL, (char *)&nlen, 4);
00597   return sockbuf_on_read(idx, DCC_FILTER_LEVEL, data, len);
00598 }

static int dcc_recv_timeout ( void *  client_data  )  [static]

Definition at line 566 of file dcc.c.

References dcc_send::idx, SOCKBUF_LEVEL_INTERNAL, sockbuf_on_eof(), and dcc_send::timer_id.

Referenced by dcc_accept_send().

00567 {
00568   dcc_send_t *send = client_data;
00569 
00570   send->timer_id = -1;
00571   sockbuf_on_eof(send->idx, SOCKBUF_LEVEL_INTERNAL, -1, "DCC timed out");
00572   return(0);
00573 }

static int dcc_send_bytes ( dcc_send_t send  )  [static]

Definition at line 311 of file dcc.c.

References dcc_send::bytes_left, dcc_send::bytes_sent, DCC_FILTER_LEVEL, dcc_send::fd, dcc_send::idx, sockbuf_isvalid(), sockbuf_on_written(), sockbuf_write(), and update_snapshot().

Referenced by dcc_send_connect(), and dcc_send_written().

00312 {
00313   int n, out, total;
00314   char buf[4096];
00315 
00316   total = 0;
00317   for (;;) {
00318     /* Read in a chunk from the file. If we get eof or error,
00319      * return -1. */
00320     n = read(send->fd, buf, sizeof(buf));
00321     if (n <= 0) return(-1);
00322 
00323     /* Now write the chunk to the sockbuf. If we get an error
00324      * return -2, and if it starts blocking return 0. Otherwise
00325      * we loop to send another chunk. */
00326     out = sockbuf_write(send->idx, buf, n);
00327     if (out < 0) return(-2);
00328     send->bytes_sent += out;
00329     send->bytes_left -= out;
00330     update_snapshot(send, out);
00331     total += out;
00332     if (out < n) {
00333       sockbuf_on_written(send->idx, DCC_FILTER_LEVEL, total, n - out);
00334       if (sockbuf_isvalid(send->idx)) return(0);
00335       else return(-2);
00336     }
00337   }
00338 }

static int dcc_send_connect ( void *  client_data,
int  idx,
const char *  peer_ip,
int  peer_port 
) [static]

Definition at line 340 of file dcc.c.

References dcc_send::connect_time, DCC_FILTER_LEVEL, dcc_send_bytes(), dcc_send_done(), dcc_send::ip, dcc_send::serv, sockbuf_isvalid(), sockbuf_on_connect(), and timer_get_now_sec().

00341 {
00342   dcc_send_t *send = client_data;
00343   int n;
00344 
00345   timer_get_now_sec(&send->connect_time);
00346   send->serv = -1;
00347   send->ip = strdup(peer_ip);
00348   sockbuf_on_connect(idx, DCC_FILTER_LEVEL, peer_ip, peer_port);
00349   if (sockbuf_isvalid(idx)) {
00350     n = dcc_send_bytes(send);
00351     if (n == -1) dcc_send_done(send);
00352   }
00353   return(0);
00354 }

static int dcc_send_delete ( void *  client_data,
int  idx 
) [static]

Definition at line 403 of file dcc.c.

References dcc_send::fd, dcc_send::fname, dcc_send::ip, dcc_send::next, dcc_send::nick, NULL, dcc_send::serv, sockbuf_delete(), and sockbuf_isvalid().

00404 {
00405   dcc_send_t *send = client_data;
00406   dcc_send_t *prev, *ptr;
00407 
00408   if (sockbuf_isvalid(send->serv)) {
00409     sockbuf_delete(send->serv);
00410   }
00411   if (send->fd != -1) close(send->fd);
00412   if (send->fname) free(send->fname);
00413   if (send->nick) free(send->nick);
00414   if (send->ip) free(send->ip);
00415   prev = NULL;
00416   for (ptr = dcc_send_head; ptr; ptr = ptr->next) {
00417     if (ptr == send) break;
00418     prev = ptr;
00419   }
00420   if (prev) prev->next = send->next;
00421   else dcc_send_head = send->next;
00422   free(send);
00423   return(0);
00424 }

static int dcc_send_done ( dcc_send_t send  )  [static]

Definition at line 426 of file dcc.c.

References DCC_FILTER_LEVEL, dcc_send::fd, dcc_send::idx, sockbuf_delete(), sockbuf_isvalid(), and sockbuf_on_eof().

Referenced by dcc_send_connect(), and dcc_send_written().

00427 {
00428   int idx;
00429 
00430   idx = send->idx;
00431   close(send->fd);
00432   send->fd = -1;
00433   sockbuf_on_eof(idx, DCC_FILTER_LEVEL, 0, "Success");
00434 
00435   /* If their handler didn't close the idx, do it here. */
00436   if (sockbuf_isvalid(idx)) sockbuf_delete(idx);
00437   return(0);
00438 }

static int dcc_send_eof ( void *  client_data,
int  idx,
int  err,
const char *  errmsg 
) [static]

Definition at line 396 of file dcc.c.

References DCC_FILTER_LEVEL, sockbuf_delete(), and sockbuf_on_eof().

00397 {
00398   sockbuf_on_eof(idx, DCC_FILTER_LEVEL, err, errmsg);
00399   sockbuf_delete(idx);
00400   return(0);
00401 }

int dcc_send_info ( int  idx,
int  field,
void *  valueptr 
)

Definition at line 440 of file dcc.c.

References dcc_send::acks, dcc_send::bytes_acked, dcc_send::bytes_left, dcc_send::bytes_sent, dcc_send::connect_time, DCC_SEND_ACKS, DCC_SEND_BYTES_ACKED, DCC_SEND_CONNECT_TIME, DCC_SEND_CPS_SNAPSHOT, DCC_SEND_CPS_TOTAL, DCC_SEND_LEFT, DCC_SEND_REQUEST_TIME, DCC_SEND_SENT, now, dcc_send::request_time, dcc_send::snapshot_bytes, dcc_send::snapshot_counter, sockbuf_get_filter_data(), timer_get_now_sec(), and update_snapshot().

00441 {
00442   dcc_send_t *send;
00443   int i, n;
00444   long now;
00445 
00446   if (!valueptr)
00447     return(-1);
00448 
00449   if (sockbuf_get_filter_data(idx, &dcc_send_filter, &send) < 0)
00450     if (sockbuf_get_filter_data(idx, &dcc_recv_filter, &send) < 0)
00451       return(-1);
00452 
00453   timer_get_now_sec(&now);
00454   switch (field) {
00455     case DCC_SEND_SENT:
00456       *(int *)valueptr = send->bytes_sent;
00457       break;
00458     case DCC_SEND_LEFT:
00459       *(int *)valueptr = send->bytes_left;
00460       break;
00461     case DCC_SEND_CPS_TOTAL:
00462       if (!send->connect_time)
00463         n = 0;
00464       else if (send->connect_time >= now)
00465         n = send->bytes_sent;
00466       else
00467         n = (int) ((float) send->bytes_sent / ((float) now - (float) send->connect_time));
00468       *(int *)valueptr = n;
00469       break;
00470     case DCC_SEND_CPS_SNAPSHOT:
00471       update_snapshot(send, 0);
00472       /* When we calculate the total, we do not include
00473        * the current second (snapshot_counter) because more
00474        * data might be sent this second and our report won't
00475        * be accurate. */
00476       n = 0;
00477       for (i = 0; i < 5; i++) {
00478         if (i != send->snapshot_counter)
00479           n += send->snapshot_bytes[i];
00480       }
00481       if (now - send->connect_time >= 5)
00482         n = (int) ((float) n / 4.0);
00483       else if (now - send->connect_time > 1)
00484         n = (int) ((float) n / (float) (now - send->connect_time - 1));
00485       else n = 0;
00486       *(int *)valueptr = n;
00487       break;
00488     case DCC_SEND_ACKS:
00489       *(int *)valueptr = send->acks;
00490       break;
00491     case DCC_SEND_BYTES_ACKED:
00492       *(int *)valueptr = send->bytes_acked;
00493       break;
00494     case DCC_SEND_REQUEST_TIME:
00495       *(int *)valueptr = send->request_time;
00496       break;
00497     case DCC_SEND_CONNECT_TIME:
00498       *(int *)valueptr = send->connect_time;
00499       break;
00500     default:
00501       return(-1);
00502   }
00503   return(0);
00504 }

static int dcc_send_read ( void *  client_data,
int  idx,
char *  data,
int  len 
) [static]

Definition at line 356 of file dcc.c.

References dcc_send::acks, and dcc_send::bytes_acked.

00357 {
00358   dcc_send_t *send = client_data;
00359   int ack;
00360 
00361   memcpy(&ack, data, sizeof(int));
00362   ack = ntohl(ack);
00363   send->acks++;
00364   send->bytes_acked = ack;
00365 
00366   return(0);
00367 }

static int dcc_send_written ( void *  client_data,
int  idx,
int  len,
int  remaining 
) [static]

Definition at line 369 of file dcc.c.

References dcc_send::bytes_acked, dcc_send::bytes_left, dcc_send::bytes_sent, DCC_FILTER_LEVEL, dcc_send_bytes(), dcc_send_done(), sockbuf_isvalid(), sockbuf_on_written(), and update_snapshot().

00370 {
00371   dcc_send_t *send = client_data;
00372   int n;
00373 
00374   /* Update stats on the send. */
00375   send->bytes_sent += len;
00376   send->bytes_left -= len;
00377   update_snapshot(send, len);
00378 
00379   /* Pass the event up to whoever's listening. */
00380 
00381   sockbuf_on_written(idx, DCC_FILTER_LEVEL, len, remaining);
00382 
00383   if (!sockbuf_isvalid(idx))
00384     return(0);
00385 
00386   /* Send as much data as we can until we block. dcc_send_bytes()
00387    * returns -1 when the file has eof(). */
00388   n = dcc_send_bytes(send);
00389   if (n == -1 && send->bytes_left <= 0 && send->bytes_acked >= send->bytes_sent) {
00390     dcc_send_done(send);
00391   }
00392 
00393   return(0);
00394 }

int dcc_start_chat ( const char *  nick,
int  timeout 
)

Definition at line 165 of file dcc.c.

References dcc_listen::client, current_server, dcc_listen(), dcc_send::idx, dcc_listen::port, printserv, dcc_listen::serv, SERVER_NORMAL, sockbuf_attach_filter(), and sockbuf_new().

00166 {
00167   dcc_listen_t *listen;
00168   int idx;
00169 
00170   /* Create a listening idx to accept the chat connection. */
00171   listen = dcc_listen(timeout);
00172   if (!listen) return(-1);
00173 
00174   /* Create an empty sockbuf that will eventually be used for the
00175    * dcc chat (when they connect to us). */
00176   idx = sockbuf_new();
00177   sockbuf_attach_filter(idx, &dcc_chat_filter, (void *)listen->serv);
00178   listen->client = idx;
00179 
00180   printserv(SERVER_NORMAL, "PRIVMSG %s :%cDCC CHAT chat %u %d%c", nick, 1, current_server.mylongip, listen->port, 1);
00181   return(idx);
00182 }

int dcc_start_send ( const char *  nick,
const char *  fname,
int  timeout 
)

Definition at line 256 of file dcc.c.

References dcc_send::bytes_left, dcc_send::bytes_sent, dcc_listen::client, current_server, dcc_listen(), dcc_send::fd, dcc_send::fname, dcc_send::idx, dcc_send::next, dcc_send::nick, dcc_listen::port, dcc_send::port, printserv, dcc_send::request_time, dcc_listen::serv, dcc_send::serv, SERVER_NORMAL, dcc_send::size, sockbuf_attach_filter(), sockbuf_new(), and timer_get_now_sec().

00257 {
00258   dcc_listen_t *listen;
00259   dcc_send_t *send;
00260   int idx, size, fd;
00261   char *quote, *slash;
00262 
00263   fd = open(fname, O_RDONLY);
00264   if (!fd)
00265     return(-2); /* File could not be opened. */
00266 
00267   size = lseek(fd, 0, SEEK_END);
00268   lseek(fd, 0, SEEK_SET);
00269 
00270   listen = dcc_listen(timeout);
00271   if (!listen) {
00272     close(fd);
00273     return(-1);
00274   }
00275 
00276   /* Create an empty sockbuf that will eventually be used for the
00277    * dcc chat (when they connect to us). */
00278   idx = sockbuf_new();
00279   send = calloc(1, sizeof(*send));
00280   sockbuf_attach_filter(idx, &dcc_send_filter, send);
00281 
00282   listen->client = idx;
00283   send->next = dcc_send_head;
00284   dcc_send_head = send;
00285   send->serv = listen->serv;
00286   send->port = listen->port;
00287   send->fd = fd;
00288   send->idx = idx;
00289   send->size = size;
00290   send->bytes_sent = 0;
00291   send->bytes_left = size;
00292   timer_get_now_sec(&send->request_time);
00293   send->fname = strdup(fname);
00294   send->nick = strdup(nick);
00295 
00296   slash = strrchr(fname, '/');
00297   if (slash)
00298     fname = slash+1;
00299 
00300   if (strchr(fname, ' '))
00301     quote = "\"";
00302   else
00303     quote = "";
00304 
00305   printserv(SERVER_NORMAL, "PRIVMSG %s :%cDCC SEND %s%s%s %u %d %d%c", nick, 1, quote, fname, quote,
00306       current_server.mylongip, listen->port, size, 1);
00307 
00308   return(idx);
00309 }

static void got_accept ( char *  nick,
char *  uhost,
user_t u,
char *  text 
) [static]

Definition at line 700 of file dcc.c.

References dcc_send::bytes_left, egg_reconnect(), dcc_send::fd, dcc_send::fname, dcc_send::idx, dcc_send::ip, dcc_send::next, dcc_send::nick, dcc_send::port, and dcc_send::resumed_at.

Referenced by got_dcc().

00701 {
00702   int port, pos, n;
00703   dcc_send_t *send;
00704   char *fname, *space;
00705 
00706   fname = text;
00707   space = strrchr(text, ' ');
00708   if (space && space != text) pos = atoi(space+1);
00709   else return;
00710   *space = 0;
00711   space--;
00712   space = strrchr(text, ' ');
00713   if (space && space != text) port = atoi(space+1);
00714   else return;
00715   *space = 0;
00716 
00717   for (send = dcc_recv_head; send; send = send->next) {
00718     if (send->port == port && !strcasecmp(send->nick, nick)) {
00719       n = lseek(send->fd, pos, SEEK_SET);
00720       send->bytes_left -= n;
00721       send->resumed_at = n;
00722       egg_reconnect(send->idx, send->ip, port, -1);
00723       break;
00724     }
00725   }
00726 }

static void got_chat ( char *  nick,
char *  uhost,
user_t u,
char *  text 
) [static]

Definition at line 650 of file dcc.c.

References bind_check(), BT_dcc_chat, user_setting_t::flags, dcc_send::ip, NULL, dcc_send::port, and user::settings.

00651 {
00652   char type[256], ip[256], port[32];
00653   int nport;
00654 
00655   type[0] = ip[0] = port[0] = 0;
00656   sscanf(text, "%255[^ ] %255[^ ] %31[^ ]", type, ip, port);
00657   type[255] = ip[255] = port[31] = 0;
00658 
00659   /* Check if the ip is 'new-style' (dotted decimal or ipv6). If not,
00660    * it's the old-style long ip. */
00661   if (!strchr(ip, '.') && !strchr(ip, ':')) {
00662     unsigned long longip;
00663     longip = strtoul(ip, NULL, 10);
00664     snprintf(ip, sizeof(ip), "%lu.%lu.%lu.%lu", (longip >> 24) & 255, (longip >> 16) & 255, (longip >> 8) & 255, (longip) & 255);
00665   }
00666 
00667   nport = atoi(port);
00668 
00669   bind_check(BT_dcc_chat, u ? &u->settings[0].flags : NULL, nick, nick, uhost, u, type, ip, nport);
00670 }

static int got_dcc ( char *  nick,
char *  uhost,
user_t u,
char *  dest,
char *  cmd,
char *  text 
) [static]

Definition at line 765 of file dcc.c.

References got_accept(), got_chat(), got_resume(), and got_send().

00766 {
00767   if (!strncasecmp(text, "chat ", 5)) {
00768     got_chat(nick, uhost, u, text+5);
00769   }
00770   else if (!strncasecmp(text, "send ", 5)) {
00771     got_send(nick, uhost, u, text+5);
00772   }
00773   else if (!strncasecmp(text, "resume ", 7)) {
00774     got_resume(nick, uhost, u, text+7);
00775   }
00776   else if (!strncasecmp(text, "accept ", 7)) {
00777     got_accept(nick, uhost, u, text+7);
00778   }
00779   return(0);
00780 }

static void got_resume ( char *  nick,
char *  uhost,
user_t u,
char *  text 
) [static]

Definition at line 672 of file dcc.c.

References dcc_send::bytes_left, dcc_send::fd, dcc_send::fname, dcc_send::next, dcc_send::nick, dcc_send::port, printserv, dcc_send::resumed_at, and SERVER_NORMAL.

Referenced by got_dcc().

00673 {
00674   int port, pos, n;
00675   dcc_send_t *send;
00676   char *fname, *space;
00677 
00678   fname = text;
00679   space = strrchr(text, ' ');
00680   if (space && space != text) pos = atoi(space+1);
00681   else return;
00682   *space = 0;
00683   space--;
00684   space = strrchr(text, ' ');
00685   if (space && space != text) port = atoi(space+1);
00686   else return;
00687   *space = 0;
00688 
00689   for (send = dcc_send_head; send; send = send->next) {
00690     if (send->port == port && !strcasecmp(send->nick, nick)) {
00691       n = lseek(send->fd, pos, SEEK_SET);
00692       send->bytes_left -= n;
00693       send->resumed_at = n;
00694       printserv(SERVER_NORMAL, "PRIVMSG %s :%cDCC ACCEPT %s %d %d%c", nick, 1, fname, port, n, 1);
00695       break;
00696     }
00697   }
00698 }

static void got_send ( char *  nick,
char *  uhost,
user_t u,
char *  text 
) [static]

Definition at line 728 of file dcc.c.

References bind_check(), BT_dcc_recv, user_setting_t::flags, dcc_send::fname, dcc_send::ip, NULL, dcc_send::port, user::settings, and dcc_send::size.

Referenced by got_dcc().

00729 {
00730   char *space, *fname, ip[256];
00731   int port, size, n;
00732 
00733   fname = text;
00734   space = strrchr(text, ' ');
00735   if (!space || space == text) return;
00736   size = atoi(space+1);
00737   *space-- = 0;
00738   space = strrchr(text, ' ');
00739   if (!space || space == text) return;
00740   port = atoi(space+1);
00741   *space-- = 0;
00742   space = strchr(text, ' ');
00743   if (!space || space == text) return;
00744   strlcpy(ip, space + 1, sizeof ip);
00745   *space = 0;
00746 
00747   if (*fname == '"') {
00748     fname++;
00749     n = strlen(fname);
00750     if (n && fname[n-1] == '"') fname[n-1] = 0;
00751     else return;
00752   }
00753   /* Check if the ip is new-style (dotted decimal or ipv6). If not,
00754    * it's the old-style long ip. */
00755   if (!strchr(ip, '.') && !strchr(ip, ':')) {
00756     unsigned int longip;
00757     longip = (unsigned int) atol(ip);
00758     sprintf(ip, "%d.%d.%d.%d", (longip >> 24) & 255, (longip >> 16) & 255, (longip >> 8) & 255, (longip) & 255);
00759   }
00760 
00761   bind_check(BT_dcc_recv, u ? &u->settings[0].flags : NULL, nick, nick, uhost, u, fname, ip, port, size);
00762 }

static void update_snapshot ( dcc_send_t send,
int  len 
) [static]

Definition at line 629 of file dcc.c.

References dcc_send::last_snapshot, NULL, dcc_send::snapshot_bytes, dcc_send::snapshot_counter, and timer_get_now_sec().

Referenced by dcc_recv_read(), dcc_send_bytes(), dcc_send_info(), and dcc_send_written().

00630 {
00631   int diff;
00632   int i;
00633 
00634   /* Get time diff. */
00635   diff = timer_get_now_sec(NULL) - send->last_snapshot;
00636   timer_get_now_sec(&send->last_snapshot);
00637   if (diff > 5) diff = 5;
00638 
00639   /* Reset counter for seconds that were skipped. */
00640   for (i = 0; i < diff; i++) {
00641     send->snapshot_counter++;
00642     if (send->snapshot_counter >= 5) send->snapshot_counter = 0;
00643     send->snapshot_bytes[send->snapshot_counter] = 0;
00644   }
00645 
00646   /* Add the bytes to the current second. */
00647   send->snapshot_bytes[send->snapshot_counter] += len;
00648 }


Variable Documentation

Initial value:

 {
  {NULL, "DCC", (Function) got_dcc},
  {0}
}

Definition at line 782 of file dcc.c.

Initial value:

 {
  "DCC chat", DCC_FILTER_LEVEL,
  dcc_chat_connect, dcc_chat_eof, NULL,
  NULL, NULL, NULL,
  NULL, dcc_chat_delete
}

Definition at line 95 of file dcc.c.

Initial value:

 {
  "DCC listen",
  NULL, NULL, dcc_listen_newclient,
  NULL, NULL
}

Definition at line 87 of file dcc.c.

Initial value:

Definition at line 109 of file dcc.c.

dcc_send_t* dcc_recv_head = NULL [static]

Definition at line 60 of file dcc.c.

Initial value:

Definition at line 102 of file dcc.c.

dcc_send_t* dcc_send_head = NULL [static]

Definition at line 59 of file dcc.c.

const char rcsid[] = "$Id: dcc.c,v 1.27 2007-09-13 22:20:57 sven Exp $" [static]

Definition at line 21 of file dcc.c.

Initial value:

 {
  "server", 0,
  0, 0,
  dcc_listen_delete
}

Definition at line 81 of file dcc.c.


Generated on Sun Nov 30 18:43:36 2008 for eggdrop1.9 by  doxygen 1.5.6