lib/eggdrop/sockbuf.c File Reference

#include <eggdrop/eggdrop.h>
#include <unistd.h>
#include <sys/socket.h>
#include "lib/compat/poll.h"
#include <errno.h>

Go to the source code of this file.

Data Structures

struct  sockbuf_t

Functions

static void sockbuf_got_eof (int idx, int err)
static void stats_in (sockbuf_stats_t *stats, int len)
static void stats_out (sockbuf_stats_t *stats, int len)
static void skip_stats (sockbuf_stats_t *stats, int curtime)
static void update_stats (sockbuf_stats_t *stats)
int sockbuf_init (void)
int sockbuf_shutdown (void)
int sockbuf_list (int **idx, int *len, int flags)
static void sockbuf_block (int idx)
static void sockbuf_unblock (int idx)
static int sockbuf_real_write (int idx, const char *data, int len)
int sockbuf_on_eof (int idx, int level, int err, const char *errmsg)
int sockbuf_on_connect (int idx, int level, const char *peer_ip, int peer_port)
int sockbuf_on_newclient (int idx, int level, int newidx, const char *peer_ip, int peer_port)
int sockbuf_on_read (int idx, int level, char *data, int len)
int sockbuf_on_write (int idx, int level, const char *data, int len)
int sockbuf_on_written (int idx, int level, int len, int remaining)
static void sockbuf_got_writable_client (int idx)
static void sockbuf_got_readable_server (int idx)
static void sockbuf_got_writable (int idx)
static void sockbuf_got_readable (int idx)
int sockbuf_new ()
int sockbuf_get_sock (int idx)
int sockbuf_set_sock (int idx, int sock, int flags)
int sockbuf_get_peer (int idx, const char **peer_ip, int *peer_port)
int sockbuf_get_self (int idx, const char **my_ip, int *my_port)
int sockbuf_get_stats (int idx, sockbuf_stats_t **stats)
int sockbuf_noread (int idx)
int sockbuf_read (int idx)
int sockbuf_isvalid (int idx)
int sockbuf_close (int idx)
int sockbuf_delete (int idx)
int sockbuf_write (int idx, const char *data, int len)
int sockbuf_get_handler (int idx, sockbuf_handler_t **handler, void *client_data_ptr)
int sockbuf_set_handler (int idx, sockbuf_handler_t *handler, void *client_data, event_owner_t *owner)
int sockbuf_attach_listener (int fd)
int sockbuf_detach_listener (int fd)
int sockbuf_attach_filter (int idx, sockbuf_filter_t *filter, void *client_data)
int sockbuf_get_filter_data (int idx, sockbuf_filter_t *filter, void *client_data_ptr)
int sockbuf_detach_filter (int idx, sockbuf_filter_t *filter, void *client_data_ptr)
int sockbuf_update_all (int timeout)

Variables

static const char rcsid [] = "$Id: sockbuf.c,v 1.23 2007-09-13 22:20:55 sven Exp $"
static sockbuf_tsockbufs = NULL
static int nsockbufs = 0
static int ndeleted_sockbufs = 0
static int * idx_array = NULL
static struct pollfd * pollfds = NULL
static int npollfds = 0
static int nlisteners = 0
static sockbuf_handler_t sockbuf_idler


Function Documentation

static void skip_stats ( sockbuf_stats_t stats,
int  curtime 
) [static]

Definition at line 870 of file sockbuf.c.

References sockbuf_stats_t::last_snapshot, sockbuf_stats_t::snapshot_counter, sockbuf_stats_t::snapshot_in_bytes, and sockbuf_stats_t::snapshot_out_bytes.

Referenced by stats_in(), stats_out(), and update_stats().

00871 {
00872   int diff, i;
00873 
00874   diff = curtime - stats->last_snapshot;
00875   stats->last_snapshot = curtime;
00876   if (diff > 5) diff = 5;
00877 
00878   /* Reset counters for seconds that were skipped. */
00879   for (i = 0; i < diff; i++) {
00880     stats->snapshot_counter++;
00881     if (stats->snapshot_counter >= 5) stats->snapshot_counter = 0;
00882     stats->snapshot_out_bytes[stats->snapshot_counter] = 0;
00883     stats->snapshot_in_bytes[stats->snapshot_counter] = 0;
00884   }
00885 }

int sockbuf_attach_filter ( int  idx,
sockbuf_filter_t filter,
void *  client_data 
)

Definition at line 721 of file sockbuf.c.

References sockbuf_t::filter_client_data, sockbuf_t::filters, sockbuf_filter_t::level, sockbuf_t::nfilters, and sockbuf_isvalid().

Referenced by attach(), dcc_accept_send(), dcc_start_chat(), dcc_start_send(), http_reconnect(), linemode_on(), netstring_on(), socks5_reconnect(), socktimer_on(), telnet_on_newclient(), and throttle_on().

00722 {
00723   sockbuf_t *sbuf;
00724   int i;
00725 
00726   if (!sockbuf_isvalid(idx)) return(-1);
00727   sbuf = &sockbufs[idx];
00728 
00729   sbuf->filters = realloc(sbuf->filters, sizeof(filter) * (sbuf->nfilters+1));
00730 
00731   sbuf->filter_client_data = realloc(sbuf->filter_client_data, sizeof(void *) * (sbuf->nfilters+1));
00732 
00733   /* Filters are ordered according to levels. The lower the level, the
00734     earlier the filter comes. This allows filters to be stacked
00735     in different orders but still function intelligently (e.g.
00736     compression should always be above encryption).
00737   */
00738   for (i = 0; i < sbuf->nfilters; i++) {
00739     if (filter->level < sbuf->filters[i]->level) break;
00740   }
00741 
00742   /* Move up the higher-level filters. */
00743   memmove(sbuf->filters+i+1, sbuf->filters+i, sizeof(filter) * (sbuf->nfilters-i));
00744   memmove(sbuf->filter_client_data+i+1, sbuf->filter_client_data+i, sizeof(void *) * (sbuf->nfilters-i));
00745 
00746   /* Put this filter in the empty spot. */
00747   sbuf->filters[i] = filter;
00748   sbuf->filter_client_data[i] = client_data;
00749 
00750   sbuf->nfilters++;
00751   return(0);
00752 }

int sockbuf_attach_listener ( int  fd  ) 

Definition at line 689 of file sockbuf.c.

References nlisteners, npollfds, and pollfds.

Referenced by add_tcl_chan().

00690 {
00691   pollfds = realloc(pollfds, sizeof(*pollfds) * (npollfds + nlisteners + 1));
00692   pollfds[npollfds+nlisteners].fd = fd;
00693   pollfds[npollfds+nlisteners].events = POLLIN;
00694   pollfds[npollfds+nlisteners].revents = 0;
00695   nlisteners++;
00696   return(0);
00697 }

static void sockbuf_block ( int  idx  )  [static]

Definition at line 146 of file sockbuf.c.

References sockbuf_t::flags, idx_array, npollfds, pollfds, and SOCKBUF_BLOCK.

Referenced by sockbuf_real_write().

00147 {
00148   int i;
00149   sockbufs[idx].flags |= SOCKBUF_BLOCK;
00150   for (i = 0; i < npollfds; i++) {
00151     if (idx_array[i] == idx) {
00152       pollfds[i].events |= POLLOUT;
00153       break;
00154     }
00155   }
00156 }

int sockbuf_close ( int  idx  ) 

Definition at line 588 of file sockbuf.c.

References sockbuf_t::sock, sockbuf_isvalid(), sockbuf_set_sock(), and socket_close().

Referenced by sockbuf_got_eof().

00589 {
00590   sockbuf_t *sbuf;
00591 
00592   if (!sockbuf_isvalid(idx)) return(-1);
00593   sbuf = &sockbufs[idx];
00594   if (sbuf->sock >= 0) {
00595     socket_close(sbuf->sock);
00596     sockbuf_set_sock(idx, -1, 0);
00597   }
00598   return(0);
00599 }

int sockbuf_delete ( int  idx  ) 

Definition at line 601 of file sockbuf.c.

References sockbuf_t::client_data, sockbuf_t::data, sockbuf_t::filter_client_data, sockbuf_t::filters, sockbuf_t::flags, sockbuf_t::handler, idx_array, sockbuf_t::my_ip, ndeleted_sockbufs, sockbuf_t::nfilters, nlisteners, npollfds, event_owner_b::on_delete, sockbuf_filter_t::on_delete, sockbuf_t::owner, sockbuf_t::peer_ip, pollfds, sockbuf_t::sock, SOCKBUF_DELETED, sockbuf_isvalid(), socket_close(), and sockbuf_t::stats.

Referenced by bot_close(), bot_on_delete(), dcc_chat_delete(), dcc_listen_newclient(), dcc_listen_timeout(), dcc_on_eof(), dcc_on_read(), dcc_pm_delete(), dcc_recv_eof(), dcc_send_delete(), dcc_send_done(), dcc_send_eof(), disconnect_server(), dns_on_eof(), egg_ident_cancel(), egg_ident_cancel_by_owner(), got_passreq(), got_quit(), got_version(), http_err(), http_on_read(), http_on_their_delete(), ident_result(), idx_on_eof(), idx_on_read(), irc_on_eof(), irc_on_read(), irc_pm_delete(), ircparty_close(), oldbotnet_on_eof(), oldbotnet_on_read(), on_eof(), on_quit(), process_results(), recving_login(), script_event_cleanup(), script_net_close(), sending_login(), sockbuf_shutdown(), socks5_connect_reply(), socks5_err(), socks5_on_their_delete(), socks5_on_their_eof(), telnet_on_eof(), telnet_on_read(), telnet_pm_delete(), telnetparty_close(), terminal_shutdown(), and timer_callback().

00602 {
00603   sockbuf_t *sbuf;
00604   int i;
00605 
00606   if (!sockbuf_isvalid(idx)) return(-1);
00607   sbuf = &sockbufs[idx];
00608 
00609   sbuf->flags |= SOCKBUF_DELETED;
00610   /* Call the on_delete handler for all filters. */
00611   for (i = 0; i < sbuf->nfilters; i++) {
00612     if (sbuf->filters[i]->on_delete) {
00613       sbuf->filters[i]->on_delete(sbuf->filter_client_data[i], idx);
00614     }
00615   }
00616 
00617   if (sbuf->owner && sbuf->owner->on_delete) sbuf->owner->on_delete(sbuf->owner, sbuf->client_data);
00618 
00619   /* Close the file descriptor. */
00620   if (sbuf->sock >= 0) socket_close(sbuf->sock);
00621 
00622   /* Free ip data. */
00623   if (sbuf->peer_ip) free(sbuf->peer_ip);
00624   if (sbuf->my_ip) free(sbuf->my_ip);
00625 
00626   /* Free its output buffer. */
00627   if (sbuf->data) free(sbuf->data);
00628 
00629   /* Free the stats struct. */
00630   if (sbuf->stats) free(sbuf->stats);
00631 
00632   /* Free filters */
00633   if (sbuf->filters) free(sbuf->filters);
00634 
00635   /* Free filter client data */
00636   if (sbuf->filter_client_data) free(sbuf->filter_client_data);
00637 
00638   /* Mark it as deleted. */
00639   memset(sbuf, 0, sizeof(*sbuf));
00640   sbuf->sock = -1;
00641   sbuf->flags = SOCKBUF_DELETED;
00642   sbuf->handler = &sockbuf_idler;
00643   ndeleted_sockbufs++;
00644 
00645   /* Find it in the pollfds/idx_array and delete it. */
00646   for (i = 0; i < npollfds; i++) if (idx_array[i] == idx) break;
00647   if (i == npollfds) return(0);
00648 
00649   memmove(pollfds+i, pollfds+i+1, sizeof(*pollfds) * (npollfds+nlisteners-i-1));
00650   memmove(idx_array+i, idx_array+i+1, sizeof(int) * (npollfds-i-1));
00651   npollfds--;
00652 
00653   return(0);
00654 }

int sockbuf_detach_filter ( int  idx,
sockbuf_filter_t filter,
void *  client_data_ptr 
)

Definition at line 772 of file sockbuf.c.

References sockbuf_t::filter_client_data, sockbuf_t::filters, sockbuf_t::nfilters, NULL, and sockbuf_isvalid().

Referenced by dcc_chat_connect(), dcc_chat_eof(), detach(), http_on_delete(), http_on_read(), linemode_off(), netstring_off(), socks5_connect_reply(), socks5_err(), socks5_on_delete(), socktimer_off(), and throttle_off().

00773 {
00774   int i;
00775   sockbuf_t *sbuf;
00776 
00777   if (!sockbuf_isvalid(idx)) return(-1);
00778   sbuf = &sockbufs[idx];
00779 
00780   for (i = 0; i < sbuf->nfilters; i++) if (sbuf->filters[i] == filter) break;
00781   if (i == sbuf->nfilters) {
00782     if (client_data_ptr) *(void **)client_data_ptr = NULL;
00783     return(-1);
00784   }
00785 
00786   if (client_data_ptr) *(void **)client_data_ptr = sbuf->filter_client_data[i];
00787   memmove(sbuf->filter_client_data+i, sbuf->filter_client_data+i+1, sizeof(void *) * (sbuf->nfilters-i-1));
00788   memmove(sbuf->filters+i, sbuf->filters+i+1, sizeof(void *) * (sbuf->nfilters-i-1));
00789   sbuf->nfilters--;
00790   return(0);
00791 }

int sockbuf_detach_listener ( int  fd  ) 

Definition at line 699 of file sockbuf.c.

References nlisteners, npollfds, and pollfds.

Referenced by rem_tcl_chan().

00700 {
00701   int i;
00702 
00703   /* Search for it so we can clear its event field. */
00704   for (i = 0; i < nlisteners; i++) {
00705     if (pollfds[npollfds+i].fd == fd) break;
00706   }
00707   if (i < nlisteners) {
00708     memmove(pollfds+npollfds+i, pollfds+npollfds+i+1, sizeof(*pollfds) * (nlisteners-i-1));
00709     nlisteners--;
00710   }
00711   return(0);
00712 }

int sockbuf_get_filter_data ( int  idx,
sockbuf_filter_t filter,
void *  client_data_ptr 
)

Definition at line 754 of file sockbuf.c.

References sockbuf_t::filter_client_data, sockbuf_t::filters, sockbuf_t::nfilters, and sockbuf_isvalid().

Referenced by dcc_send_info(), linemode_check(), netstring_check(), socktimer_check(), and socktimer_on().

00755 {
00756   int i;
00757   sockbuf_t *sbuf;
00758 
00759   if (!sockbuf_isvalid(idx)) return(-1);
00760   sbuf = &sockbufs[idx];
00761   for (i = 0; i < sbuf->nfilters; i++) {
00762     if (sbuf->filters[i] == filter) {
00763       if (client_data_ptr) *(void **)client_data_ptr = sbuf->filter_client_data[i];
00764       return(0);
00765     }
00766   }
00767   return(-1);
00768 }

int sockbuf_get_handler ( int  idx,
sockbuf_handler_t **  handler,
void *  client_data_ptr 
)

Definition at line 664 of file sockbuf.c.

References sockbuf_t::handler, and sockbuf_isvalid().

Referenced by print_net().

00665 {
00666   if (!sockbuf_isvalid(idx)) return(-1);
00667   if (handler) *handler = sockbufs[idx].handler;
00668   if (client_data_ptr) *(void **)client_data_ptr = sockbufs[idx].client_data;
00669 
00670   return(0);
00671 }

int sockbuf_get_peer ( int  idx,
const char **  peer_ip,
int *  peer_port 
)

Definition at line 522 of file sockbuf.c.

References sockbuf_t::peer_ip, sockbuf_t::peer_port, and sockbuf_isvalid().

Referenced by print_net().

00523 {
00524   if (!sockbuf_isvalid(idx)) return(-1);
00525   if (peer_ip) *peer_ip = sockbufs[idx].peer_ip;
00526   if (peer_port) *peer_port = sockbufs[idx].peer_port;
00527   return(0);
00528 }

int sockbuf_get_self ( int  idx,
const char **  my_ip,
int *  my_port 
)

Definition at line 530 of file sockbuf.c.

References sockbuf_t::my_ip, sockbuf_t::my_port, and sockbuf_isvalid().

Referenced by print_net().

00531 {
00532   if (!sockbuf_isvalid(idx)) return(-1);
00533   if (my_ip) *my_ip = sockbufs[idx].my_ip;
00534   if (my_port) *my_port = sockbufs[idx].my_port;
00535   return(0);
00536 }

int sockbuf_get_sock ( int  idx  ) 

Definition at line 463 of file sockbuf.c.

References sockbuf_isvalid().

Referenced by dcc_listen_newclient(), dcc_on_connect(), http_on_read(), server_on_connect(), and socks5_connect_reply().

00464 {
00465   if (!sockbuf_isvalid(idx)) return(-1);
00466   return(sockbufs[idx].sock);
00467 }

int sockbuf_get_stats ( int  idx,
sockbuf_stats_t **  stats 
)

Definition at line 538 of file sockbuf.c.

References sockbuf_isvalid(), sockbuf_t::stats, and update_stats().

Referenced by script_net_info(), and server_status().

00539 {
00540   if (!sockbuf_isvalid(idx)) return(-1);
00541   if (stats) {
00542     *stats = sockbufs[idx].stats;
00543     update_stats(*stats);
00544   }
00545   return(0);
00546 }

static void sockbuf_got_eof ( int  idx,
int  err 
) [static]

Definition at line 323 of file sockbuf.c.

References sockbuf_t::sock, sockbuf_close(), SOCKBUF_LEVEL_INTERNAL, sockbuf_on_eof(), and socket_get_error().

Referenced by sockbuf_got_readable(), sockbuf_got_writable(), sockbuf_got_writable_client(), sockbuf_real_write(), and sockbuf_update_all().

00324 {
00325   char *errmsg;
00326   sockbuf_t *sbuf = &sockbufs[idx];
00327 
00328   /* If there's no error given, check for a socket-level error. */
00329   if (!err) err = socket_get_error(sbuf->sock);
00330 
00331   /* Get the associated error message. */
00332   errmsg = strerror(err);
00333 
00334   sockbuf_close(idx);
00335   sockbuf_on_eof(idx, SOCKBUF_LEVEL_INTERNAL, err, errmsg);
00336 }

static void sockbuf_got_readable ( int  idx  )  [static]

Definition at line 414 of file sockbuf.c.

References sockbuf_t::sock, sockbuf_got_eof(), SOCKBUF_LEVEL_INTERNAL, sockbuf_on_read(), sockbuf_t::stats, and stats_in().

Referenced by sockbuf_update_all().

00415 {
00416   sockbuf_t *sbuf = &sockbufs[idx];
00417   char buf[4097];
00418   int nbytes;
00419 
00420   if (sbuf->sock < 0) return;
00421   errno = 0;
00422   nbytes = read(sbuf->sock, buf, sizeof(buf)-1);
00423   if (nbytes > 0) {
00424     stats_in(sbuf->stats, nbytes);
00425     buf[nbytes] = 0;
00426     sockbuf_on_read(idx, SOCKBUF_LEVEL_INTERNAL, buf, nbytes);
00427   }
00428   else {
00429     sockbuf_got_eof(idx, errno);
00430   }
00431 }

static void sockbuf_got_readable_server ( int  idx  )  [static]

Definition at line 364 of file sockbuf.c.

References NULL, sockbuf_t::sock, SOCKBUF_INBOUND, SOCKBUF_LEVEL_INTERNAL, sockbuf_new(), sockbuf_on_newclient(), sockbuf_set_sock(), socket_accept(), socket_set_nonblock(), and timer_get_now().

Referenced by sockbuf_update_all().

00365 {
00366   int newsock, newidx, peer_port;
00367   char *peer_ip = NULL;
00368   sockbuf_t *sbuf = &sockbufs[idx];
00369 
00370   newsock = socket_accept(sbuf->sock, &peer_ip, &peer_port);
00371   if (newsock < 0) {
00372     if (peer_ip) free(peer_ip);
00373     return;
00374   }
00375   socket_set_nonblock(newsock, 1);
00376 
00377   newidx = sockbuf_new();
00378   timer_get_now(&sockbufs[newidx].stats->connected_at);
00379   sockbuf_set_sock(newidx, newsock, SOCKBUF_INBOUND);
00380   sockbuf_on_newclient(idx, SOCKBUF_LEVEL_INTERNAL, newidx, peer_ip, peer_port);
00381   free(peer_ip);
00382 }

static void sockbuf_got_writable ( int  idx  )  [static]

Definition at line 387 of file sockbuf.c.

References sockbuf_t::data, sockbuf_t::len, sockbuf_stats_t::raw_bytes_left, sockbuf_t::sock, sockbuf_got_eof(), SOCKBUF_LEVEL_INTERNAL, sockbuf_on_written(), sockbuf_unblock(), sockbuf_t::stats, and stats_out().

Referenced by sockbuf_update_all().

00388 {
00389   int nbytes;
00390   sockbuf_t *sbuf = &sockbufs[idx];
00391 
00392   if (sbuf->sock < 0) return;
00393   /* Try to write any buffered data. */
00394   errno = 0;
00395   nbytes = write(sbuf->sock, sbuf->data, sbuf->len);
00396   if (nbytes > 0) {
00397     stats_out(sbuf->stats, nbytes);
00398     sbuf->len -= nbytes;
00399     sbuf->stats->raw_bytes_left = sbuf->len;
00400     if (!sbuf->len) sockbuf_unblock(idx);
00401     else memmove(sbuf->data, sbuf->data+nbytes, sbuf->len);
00402     sockbuf_on_written(idx, SOCKBUF_LEVEL_INTERNAL, nbytes, sbuf->len);
00403   }
00404   else if (nbytes < 0) {
00405     /* If there's an error writing to a socket that's marked as
00406       writable, then there's probably a socket-level error. */
00407     sockbuf_got_eof(idx, errno);
00408   }
00409 }

static void sockbuf_got_writable_client ( int  idx  )  [static]

Definition at line 341 of file sockbuf.c.

References sockbuf_t::flags, sockbuf_t::len, sockbuf_t::sock, SOCKBUF_CONNECTING, sockbuf_got_eof(), SOCKBUF_LEVEL_INTERNAL, sockbuf_on_connect(), sockbuf_unblock(), socket_get_error(), and socket_get_peer_name().

Referenced by sockbuf_update_all().

00342 {
00343   int err, peer_port;
00344   char *peer_ip;
00345   sockbuf_t *sbuf = &sockbufs[idx];
00346 
00347   err = socket_get_error(sbuf->sock);
00348   if (err) {
00349     sockbuf_got_eof(idx, err);
00350     return;
00351   }
00352 
00353   sbuf->flags &= ~SOCKBUF_CONNECTING;
00354   if (!sbuf->len) sockbuf_unblock(idx);
00355   socket_get_peer_name(sbuf->sock, &peer_ip, &peer_port);
00356 
00357   sockbuf_on_connect(idx, SOCKBUF_LEVEL_INTERNAL, peer_ip, peer_port);
00358   if (peer_ip) free(peer_ip);
00359 }

int sockbuf_init ( void   ) 

Definition at line 92 of file sockbuf.c.

Referenced by egg_net_init().

00093 {
00094   return (0); 
00095 }

int sockbuf_isvalid ( int  idx  ) 

int sockbuf_list ( int **  idx,
int *  len,
int  flags 
)

Definition at line 131 of file sockbuf.c.

References nsockbufs, SOCKBUF_AVAIL, and SOCKBUF_DELETED.

Referenced by print_net().

00132 {
00133   int i, j;
00134 
00135   *idx = malloc(sizeof(int) * (nsockbufs+1));
00136   j = 0;
00137   for (i = 0; i < nsockbufs; i++) {
00138     if (sockbufs[i].flags & (SOCKBUF_DELETED | SOCKBUF_AVAIL)) continue;
00139     if (sockbufs[i].flags & flags) (*idx)[j++] = i;
00140   }
00141   *len = j;
00142   return(0);
00143 }

int sockbuf_new ( void   ) 

Definition at line 433 of file sockbuf.c.

References sockbuf_t::flags, sockbuf_t::handler, nsockbufs, sockbuf_t::sock, SOCKBUF_AVAIL, SOCKBUF_BLOCK, and sockbuf_t::stats.

Referenced by dcc_accept_send(), dcc_start_chat(), dcc_start_send(), egg_client(), egg_connect(), egg_server(), get_dns_idx(), http_reconnect(), sockbuf_got_readable_server(), socks5_reconnect(), and terminal_init().

00434 {
00435   sockbuf_t *sbuf;
00436   int idx;
00437 
00438   for (idx = 0; idx < nsockbufs; idx++) {
00439     if (sockbufs[idx].flags & SOCKBUF_AVAIL) break;
00440   }
00441   if (idx == nsockbufs) {
00442     int i;
00443 
00444     sockbufs = realloc(sockbufs, (nsockbufs+5) * sizeof(*sockbufs));
00445     memset(sockbufs+nsockbufs, 0, 5 * sizeof(*sockbufs));
00446     for (i = 0; i < 5; i++) {
00447       sockbufs[nsockbufs+i].sock = -1;
00448       sockbufs[nsockbufs+i].flags = SOCKBUF_AVAIL;
00449     }
00450     nsockbufs += 5;
00451   }
00452 
00453   sbuf = &sockbufs[idx];
00454   memset(sbuf, 0, sizeof(*sbuf));
00455   sbuf->flags = SOCKBUF_BLOCK;
00456   sbuf->sock = -1;
00457   sbuf->handler = &sockbuf_idler;
00458   sbuf->stats = calloc(1, sizeof(*sbuf->stats));
00459 
00460   return(idx);
00461 }

int sockbuf_noread ( int  idx  ) 

Definition at line 548 of file sockbuf.c.

References idx_array, npollfds, pollfds, and sockbuf_isvalid().

Referenced by throttle_on_read().

00549 {
00550   int i;
00551 
00552   if (!sockbuf_isvalid(idx)) return(-1);
00553 
00554   /* Find the entry in the pollfds array. */
00555   for (i = 0; i < npollfds; i++) {
00556     if (idx_array[i] == idx) break;
00557   }
00558 
00559   if (i == npollfds) return(-1);
00560 
00561   pollfds[i].events &= (~POLLIN);
00562   return(0);
00563 }

int sockbuf_on_connect ( int  idx,
int  level,
const char *  peer_ip,
int  peer_port 
)

Definition at line 224 of file sockbuf.c.

References sockbuf_t::client_data, sockbuf_stats_t::connected_at, sockbuf_t::filter_client_data, sockbuf_t::filters, sockbuf_t::handler, sockbuf_filter_t::level, sockbuf_t::my_ip, sockbuf_t::my_port, sockbuf_t::nfilters, sockbuf_handler_t::on_connect, sockbuf_filter_t::on_connect, sockbuf_t::peer_ip, sockbuf_t::peer_port, sockbuf_t::sock, socket_get_name(), sockbuf_t::stats, str_redup(), and timer_get_now().

Referenced by dcc_chat_connect(), dcc_recv_connect(), dcc_send_connect(), egg_on_connect(), http_on_read(), sockbuf_got_writable_client(), and socks5_connect_reply().

00225 {
00226   int i;
00227   sockbuf_t *sbuf = &sockbufs[idx];
00228 
00229   for (i = 0; i < sbuf->nfilters; i++) {
00230     if (sbuf->filters[i]->on_connect && sbuf->filters[i]->level > level) {
00231       return sbuf->filters[i]->on_connect(sbuf->filter_client_data[i], idx, peer_ip, peer_port);
00232     }
00233   }
00234 
00235   timer_get_now(&sbuf->stats->connected_at);
00236   if (peer_ip) str_redup(&sbuf->peer_ip, peer_ip);
00237   sbuf->peer_port = peer_port;
00238   socket_get_name(sbuf->sock, &sbuf->my_ip, &sbuf->my_port);
00239 
00240   if (sbuf->handler->on_connect) {
00241     sbuf->handler->on_connect(sbuf->client_data, idx, peer_ip, peer_port);
00242   }
00243   return(0);
00244 }

int sockbuf_on_eof ( int  idx,
int  level,
int  err,
const char *  errmsg 
)

Definition at line 205 of file sockbuf.c.

References sockbuf_t::client_data, sockbuf_t::filter_client_data, sockbuf_t::filters, sockbuf_t::handler, sockbuf_filter_t::level, sockbuf_t::nfilters, sockbuf_handler_t::on_eof, and sockbuf_filter_t::on_eof.

Referenced by connect_host_resolved(), dcc_chat_eof(), dcc_listen_delete(), dcc_recv_eof(), dcc_recv_timeout(), dcc_send_done(), dcc_send_eof(), egg_connect_timeout(), egg_on_eof(), http_err(), linemode_on_eof(), netstring_on_read(), sockbuf_got_eof(), socks5_err(), and socks5_on_delete().

00206 {
00207   int i;
00208   sockbuf_t *sbuf = &sockbufs[idx];
00209 
00210   for (i = 0; i < sbuf->nfilters; i++) {
00211     if (sbuf->filters[i]->on_eof && sbuf->filters[i]->level > level) {
00212       return sbuf->filters[i]->on_eof(sbuf->filter_client_data[i], idx, err, errmsg);
00213     }
00214   }
00215 
00216   /* If we didn't branch to a filter, try the user handler. */
00217   if (sbuf->handler->on_eof) {
00218     sbuf->handler->on_eof(sbuf->client_data, idx, err, errmsg);
00219   }
00220   return(0);
00221 }

int sockbuf_on_newclient ( int  idx,
int  level,
int  newidx,
const char *  peer_ip,
int  peer_port 
)

Definition at line 247 of file sockbuf.c.

References sockbuf_t::client_data, sockbuf_stats_t::connected_at, sockbuf_t::filter_client_data, sockbuf_t::filters, sockbuf_t::handler, sockbuf_filter_t::level, sockbuf_t::my_ip, sockbuf_t::my_port, sockbuf_t::nfilters, sockbuf_filter_t::on_connect, sockbuf_handler_t::on_newclient, sockbuf_filter_t::on_newclient, sockbuf_t::peer_ip, sockbuf_t::peer_port, sockbuf_t::sock, socket_get_name(), sockbuf_t::stats, str_redup(), and timer_get_now().

Referenced by sockbuf_got_readable_server().

00248 {
00249   int i;
00250   sockbuf_t *sbuf = &sockbufs[idx];
00251   sockbuf_t *newsbuf = &sockbufs[newidx];
00252 
00253   for (i = 0; i < sbuf->nfilters; i++) {
00254     if (sbuf->filters[i]->on_connect && sbuf->filters[i]->level > level) {
00255       return sbuf->filters[i]->on_newclient(sbuf->filter_client_data[i], idx, newidx, peer_ip, peer_port);
00256     }
00257   }
00258 
00259   timer_get_now(&newsbuf->stats->connected_at);
00260   if (peer_ip) str_redup(&newsbuf->peer_ip, peer_ip);
00261   newsbuf->peer_port = peer_port;
00262   socket_get_name(newsbuf->sock, &newsbuf->my_ip, &newsbuf->my_port);
00263 
00264   if (sbuf->handler->on_newclient) {
00265     sbuf->handler->on_newclient(sbuf->client_data, idx, newidx, peer_ip, peer_port);
00266   }
00267   return(0);
00268 }

int sockbuf_on_read ( int  idx,
int  level,
char *  data,
int  len 
)

Definition at line 271 of file sockbuf.c.

References sockbuf_stats_t::bytes_in, sockbuf_t::client_data, sockbuf_t::filter_client_data, sockbuf_t::filters, sockbuf_t::handler, sockbuf_filter_t::level, sockbuf_t::nfilters, sockbuf_handler_t::on_read, sockbuf_filter_t::on_read, and sockbuf_t::stats.

Referenced by dcc_recv_read(), linemode_off(), linemode_on_eof(), linemode_on_read(), netstring_off(), netstring_on_read(), sockbuf_got_readable(), telnet_filter_read(), and throttle_on_read().

00272 {
00273   int i;
00274   sockbuf_t *sbuf = &sockbufs[idx];
00275 
00276   for (i = 0; i < sbuf->nfilters; i++) {
00277     if (sbuf->filters[i]->on_read && sbuf->filters[i]->level > level) {
00278       return sbuf->filters[i]->on_read(sbuf->filter_client_data[i], idx, data, len);
00279     }
00280   }
00281 
00282   sbuf->stats->bytes_in += len;
00283   if (sbuf->handler->on_read) {
00284     sbuf->handler->on_read(sbuf->client_data, idx, data, len);
00285   }
00286   return(0);
00287 }

int sockbuf_on_write ( int  idx,
int  level,
const char *  data,
int  len 
)

Definition at line 290 of file sockbuf.c.

References sockbuf_t::filter_client_data, sockbuf_t::filters, sockbuf_filter_t::level, sockbuf_t::nfilters, sockbuf_filter_t::on_write, and sockbuf_real_write().

Referenced by dcc_recv_read(), netstring_on_write(), sockbuf_write(), telnet_code(), telnet_filter_read(), telnet_filter_write(), throttle_off(), throttle_on_write(), throttle_secondly(), and throttle_set().

00291 {
00292   int i;
00293   sockbuf_t *sbuf = &sockbufs[idx];
00294 
00295   for (i = sbuf->nfilters-1; i >= 0; i--) {
00296     if (sbuf->filters[i]->on_write && sbuf->filters[i]->level < level) {
00297       return sbuf->filters[i]->on_write(sbuf->filter_client_data[i], idx, data, len);
00298     }
00299   }
00300   /* There's no user handler for on_write (they wrote it). */
00301   return sockbuf_real_write(idx, data, len);
00302 }

int sockbuf_on_written ( int  idx,
int  level,
int  len,
int  remaining 
)

Definition at line 305 of file sockbuf.c.

References sockbuf_t::client_data, sockbuf_t::filter_client_data, sockbuf_t::filters, sockbuf_t::handler, sockbuf_filter_t::level, sockbuf_t::nfilters, sockbuf_handler_t::on_written, and sockbuf_filter_t::on_written.

Referenced by dcc_send_bytes(), dcc_send_written(), sockbuf_got_writable(), throttle_on_written(), throttle_secondly(), and throttle_set().

00306 {
00307   int i;
00308   sockbuf_t *sbuf = &sockbufs[idx];
00309 
00310   for (i = 0; i < sbuf->nfilters; i++) {
00311     if (sbuf->filters[i]->on_written && sbuf->filters[i]->level > level) {
00312       return sbuf->filters[i]->on_written(sbuf->filter_client_data[i], idx, len, remaining);
00313     }
00314   }
00315 
00316   if (sbuf->handler->on_written) {
00317     sbuf->handler->on_written(sbuf->client_data, idx, len, remaining);
00318   }
00319   return(0);
00320 }

int sockbuf_read ( int  idx  ) 

Definition at line 565 of file sockbuf.c.

References idx_array, npollfds, pollfds, and sockbuf_isvalid().

Referenced by throttle_secondly().

00566 {
00567   int i;
00568 
00569   if (!sockbuf_isvalid(idx)) return(-1);
00570 
00571   /* Find the entry in the pollfds array. */
00572   for (i = 0; i < npollfds; i++) {
00573     if (idx_array[i] == idx) break;
00574   }
00575 
00576   if (i == npollfds) return(-1);
00577 
00578   pollfds[i].events |= POLLIN;
00579   return(0);
00580 }

static int sockbuf_real_write ( int  idx,
const char *  data,
int  len 
) [static]

Definition at line 173 of file sockbuf.c.

References sockbuf_t::data, sockbuf_t::flags, sockbuf_t::len, sockbuf_t::sock, sockbuf_block(), SOCKBUF_BLOCK, sockbuf_got_eof(), sockbuf_t::stats, and stats_out().

Referenced by sockbuf_on_write().

00174 {
00175   int nbytes = 0;
00176   sockbuf_t *sbuf = &sockbufs[idx];
00177 
00178   if (sbuf->sock < 0) return 0;
00179   /* If it's not blocked already, write as much as we can. */
00180   if (!(sbuf->flags & SOCKBUF_BLOCK)) {   
00181     nbytes = write (sbuf->sock, data, len);
00182     if (nbytes < 0) {
00183       if (errno != EAGAIN) {
00184         sockbuf_got_eof(idx, errno);
00185         return(nbytes);
00186       }
00187       nbytes = 0;
00188     }
00189 
00190     if (nbytes > 0) stats_out(sbuf->stats, nbytes);
00191     if (nbytes == len) return(nbytes);
00192     sockbuf_block(idx);
00193     data += nbytes;
00194     len -= nbytes;
00195   }
00196 
00197   /* Add the remaining data to the buffer. */
00198   sbuf->data = realloc(sbuf->data, sbuf->len + len);
00199   memcpy(sbuf->data + sbuf->len, data, len);
00200   sbuf->len += len;
00201   return(nbytes);
00202 }

int sockbuf_set_handler ( int  idx,
sockbuf_handler_t handler,
void *  client_data,
event_owner_t owner 
)

int sockbuf_set_sock ( int  idx,
int  sock,
int  flags 
)

Definition at line 469 of file sockbuf.c.

References sockbuf_t::flags, idx_array, nlisteners, npollfds, pollfds, sockbuf_t::sock, SOCKBUF_BLOCK, SOCKBUF_CLIENT, SOCKBUF_CONNECTING, sockbuf_isvalid(), SOCKBUF_NOREAD, SOCKBUF_SERVER, and socket_get_name().

Referenced by connect_host_resolved(), dcc_listen_newclient(), egg_server(), get_dns_idx(), http_on_read(), sockbuf_close(), sockbuf_got_readable_server(), socks5_connect_reply(), terminal_init(), and terminal_shutdown().

00470 {
00471   int i;
00472 
00473   if (!sockbuf_isvalid(idx)) return(-1);
00474 
00475   sockbufs[idx].sock = sock;
00476   sockbufs[idx].flags &= ~(SOCKBUF_CONNECTING|SOCKBUF_CLIENT|SOCKBUF_SERVER|SOCKBUF_BLOCK|SOCKBUF_NOREAD);
00477   sockbufs[idx].flags |= flags;
00478   if (sockbufs[idx].flags & SOCKBUF_SERVER) {
00479     socket_get_name(sockbufs[idx].sock, &sockbufs[idx].my_ip, &sockbufs[idx].my_port);
00480   }
00481 
00482   /* pollfds   = [socks][socks][socks][listeners][listeners][end] */
00483   /* idx_array = [ idx ][ idx ][ idx ][end]*/
00484   /* So when we grow pollfds, we shift the listeners at the end. */
00485 
00486   /* Find the entry in the pollfds array. */
00487   for (i = 0; i < npollfds; i++) {
00488     if (idx_array[i] == idx) break;
00489   }
00490 
00491   if (sock == -1) {
00492     if (i == npollfds) return(1);
00493 
00494     /* If they set the sock to -1, then we remove the entry. */
00495     memmove(idx_array+i, idx_array+i+1, sizeof(int) * (npollfds-i-1));
00496     memmove(pollfds+i, pollfds+i+1, sizeof(*pollfds) * (nlisteners + npollfds-i-1));
00497     npollfds--;
00498     return(0);
00499   }
00500 
00501   /* Add it to the end if it's not found. */
00502   if (i == npollfds) {
00503     /* Add the new idx to the idx_array. */
00504     idx_array = realloc(idx_array, sizeof(int) * (i+1));
00505     idx_array[i] = idx;
00506 
00507     /* Add corresponding pollfd to pollfds. */
00508     pollfds = realloc(pollfds, sizeof(*pollfds) * (i+nlisteners+1));
00509     memmove(pollfds+i+1, pollfds+i, sizeof(*pollfds) * nlisteners);
00510 
00511     npollfds++;
00512   }
00513 
00514   pollfds[i].fd = sock;
00515   pollfds[i].events = 0;
00516   if (flags & (SOCKBUF_BLOCK|SOCKBUF_CONNECTING)) pollfds[i].events |= POLLOUT;
00517   if (!(flags & SOCKBUF_NOREAD)) pollfds[i].events |= POLLIN;
00518 
00519   return(idx);
00520 }

int sockbuf_shutdown ( void   ) 

Definition at line 97 of file sockbuf.c.

References idx_array, LOG_DEBUG, sockbuf_t::my_ip, sockbuf_t::my_port, npollfds, nsockbufs, NULL, sockbuf_t::peer_ip, sockbuf_t::peer_port, pollfds, putlog(), and sockbuf_delete().

Referenced by egg_net_shutdown().

00098 {
00099   int i;
00100 
00101   for (i = npollfds - 1; i >= 0; i--) {
00102           sockbuf_t *sbuf = &sockbufs[idx_array[i]];
00103 
00104     putlog(LOG_DEBUG, "*", "Socket %i %s:%i shouldn't be opened at this stage, closing.", idx_array[i],
00105       (sbuf->peer_ip) ? sbuf->peer_ip : sbuf->my_ip,
00106       (sbuf->peer_ip) ? sbuf->peer_port : sbuf->my_port);
00107       
00108     sockbuf_delete(idx_array[i]);
00109   }
00110 
00111   if (idx_array) {
00112     free(idx_array);
00113     idx_array = NULL;
00114   }
00115 
00116   if (pollfds) {
00117     free(pollfds);
00118     pollfds = NULL;
00119   }
00120   npollfds = 0;
00121 
00122   if (sockbufs) {
00123     free(sockbufs);
00124     sockbufs = NULL;
00125   }
00126   nsockbufs = 0;
00127 
00128   return (0);
00129 }

static void sockbuf_unblock ( int  idx  )  [static]

Definition at line 159 of file sockbuf.c.

References sockbuf_t::flags, idx_array, npollfds, pollfds, and SOCKBUF_BLOCK.

Referenced by sockbuf_got_writable(), and sockbuf_got_writable_client().

00160 {
00161   int i;
00162   sockbufs[idx].flags &= (~SOCKBUF_BLOCK);
00163   for (i = 0; i < npollfds; i++) {
00164     if (idx_array[i] == idx) {
00165       pollfds[i].events &= (~POLLOUT);
00166       break;
00167     }
00168   }
00169 }

int sockbuf_update_all ( int  timeout  ) 

Definition at line 798 of file sockbuf.c.

References sockbuf_t::flags, idx_array, ndeleted_sockbufs, npollfds, nsockbufs, pollfds, SOCKBUF_AVAIL, SOCKBUF_CONNECTING, SOCKBUF_DELETED, sockbuf_got_eof(), sockbuf_got_readable(), sockbuf_got_readable_server(), sockbuf_got_writable(), sockbuf_got_writable_client(), and SOCKBUF_SERVER.

Referenced by main().

00799 {
00800   int i, n, flags, revents, idx;
00801   static int depth = 0;
00802 
00803   /* Increment the depth counter when we enter the proc. */
00804   depth++;
00805 
00806   n = poll(pollfds, npollfds, timeout);
00807   if (n < 0) n = npollfds;
00808 
00809   /* If a sockbuf gets deleted during its event handler, the pollfds array
00810     gets shifted down and we will miss the events of the next
00811     socket. That's ok, because we'll pick up those events next
00812     time.
00813   */
00814   for (i = 0; n && i < npollfds; i++) {
00815     /* Common case: no activity. */
00816     revents = pollfds[i].revents;
00817     if (!revents) continue;
00818 
00819     idx = idx_array[i];
00820     flags = sockbufs[idx].flags;
00821     if (revents & POLLOUT) {
00822       if (flags & SOCKBUF_CONNECTING) sockbuf_got_writable_client(idx);
00823       else sockbuf_got_writable(idx);
00824     }
00825     if (revents & POLLIN) {
00826       if (flags & SOCKBUF_SERVER) sockbuf_got_readable_server(idx);
00827       else sockbuf_got_readable(idx);
00828     }
00829     if (revents & (POLLHUP|POLLNVAL|POLLERR)) sockbuf_got_eof(idx, 0);
00830     n--;
00831   }
00832 
00833   /* Now that we're done manipulating stuff, back out of the depth. */
00834   depth--;
00835 
00836   /* If this is the topmost level, check for deleted sockbufs. */
00837   if (ndeleted_sockbufs && !depth) {
00838     for (i = 0; ndeleted_sockbufs && i < nsockbufs; i++) {
00839       if (sockbufs[i].flags & SOCKBUF_DELETED) {
00840         sockbufs[i].flags = SOCKBUF_AVAIL;
00841         ndeleted_sockbufs--;
00842       }
00843     }
00844     /* If ndeleted_sockbufs isn't 0, then we somehow lost track of
00845       an idx. That can't happen, but we might as well be
00846       safe. */
00847     ndeleted_sockbufs = 0;
00848   }
00849 
00850   return(0);
00851 }

int sockbuf_write ( int  idx,
const char *  data,
int  len 
)

static void stats_in ( sockbuf_stats_t stats,
int  len 
) [static]

static void stats_out ( sockbuf_stats_t stats,
int  len 
) [static]

static void update_stats ( sockbuf_stats_t stats  )  [static]

Definition at line 888 of file sockbuf.c.

References sockbuf_stats_t::connected_at, NULL, sockbuf_stats_t::raw_bytes_in, sockbuf_stats_t::raw_bytes_out, egg_timeval::sec, skip_stats(), sockbuf_stats_t::snapshot_counter, sockbuf_stats_t::snapshot_in_bytes, sockbuf_stats_t::snapshot_in_cps, sockbuf_stats_t::snapshot_out_bytes, sockbuf_stats_t::snapshot_out_cps, timer_get_now_sec(), sockbuf_stats_t::total_in_cps, and sockbuf_stats_t::total_out_cps.

Referenced by sockbuf_get_stats().

00889 {
00890   int curtime = timer_get_now_sec(NULL);
00891   int nsecs;
00892   int snap_in = 0, snap_out = 0;
00893   int i;
00894 
00895   /* Compute total input cps. */
00896   nsecs = curtime - stats->connected_at.sec + 1;
00897 
00898   stats->total_in_cps = stats->raw_bytes_in / nsecs;
00899   stats->total_out_cps = stats->raw_bytes_out / nsecs;
00900 
00901   /* Compute cps. */
00902 
00903   /* Zero out any skipped seconds. */
00904   skip_stats(stats, curtime);
00905 
00906   /* When we calculate the totals, we do not include the current second
00907    * because more data might be sent during this second and our report
00908    * will be pretty inaccurate. */
00909   for (i = 0; i < 5; i++) {
00910     if (i != stats->snapshot_counter) {
00911       snap_in += stats->snapshot_in_bytes[i];
00912       snap_out += stats->snapshot_out_bytes[i];
00913     }
00914   }
00915   if (nsecs > 4) nsecs = 4;
00916   else if (nsecs > 1) nsecs--;
00917   else nsecs = 1;
00918   stats->snapshot_in_cps = snap_in / nsecs;
00919   stats->snapshot_out_cps = snap_out / nsecs;
00920 }


Variable Documentation

int* idx_array = NULL [static]

int ndeleted_sockbufs = 0 [static]

Definition at line 66 of file sockbuf.c.

Referenced by sockbuf_delete(), and sockbuf_update_all().

int nlisteners = 0 [static]

int npollfds = 0 [static]

int nsockbufs = 0 [static]

struct pollfd* pollfds = NULL [static]

const char rcsid[] = "$Id: sockbuf.c,v 1.23 2007-09-13 22:20:55 sven Exp $" [static]

Definition at line 21 of file sockbuf.c.

Initial value:

 {
  "idle",
  NULL, NULL, NULL,
  NULL, NULL
}

Definition at line 78 of file sockbuf.c.

sockbuf_t* sockbufs = NULL [static]

Definition at line 64 of file sockbuf.c.


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