ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/hopm/trunk/src/irc.c
(Generate patch)

Comparing hopm/trunk/src/irc.c (file contents):
Revision 5274 by michael, Thu Jan 1 20:00:33 2015 UTC vs.
Revision 5726 by michael, Tue Mar 24 18:04:06 2015 UTC

# Line 1 | Line 1
1   /*
2 < * Copyright (C) 2002-2003  Erik Fears
3 < *
4 < * This program is free software; you can redistribute it and/or
5 < * modify it under the terms of the GNU General Public License
6 < * as published by the Free Software Foundation; either version 2
7 < * of the License, or (at your option) any later version.
8 < *
9 < * This program is distributed in the hope that it will be useful,
10 < * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 < * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 < * GNU General Public License for more details.
13 < *
14 < * You should have received a copy of the GNU General Public License
15 < * along with this program; if not, write to
16 < *
17 < *       The Free Software Foundation, Inc.
18 < *       59 Temple Place - Suite 330
19 < *       Boston, MA  02111-1307, USA.
20 < *
2 > *  Copyright (c) 2002-2003 Erik Fears
3 > *  Copyright (c) 2014-2015 ircd-hybrid development team
4   *
5 + *  This program is free software; you can redistribute it and/or modify
6 + *  it under the terms of the GNU General Public License as published by
7 + *  the Free Software Foundation; either version 2 of the License, or
8 + *  (at your option) any later version.
9 + *
10 + *  This program is distributed in the hope that it will be useful,
11 + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12 + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 + *  GNU General Public License for more details.
14 + *
15 + *  You should have received a copy of the GNU General Public License
16 + *  along with this program; if not, write to the Free Software
17 + *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
18 + *  USA
19   */
20  
21   #include "setup.h"
# Line 29 | Line 26
26   #include <string.h>
27   #include <sys/types.h>
28   #include <sys/socket.h>
29 + #include <netdb.h>
30   #include <netinet/in.h>
31   #include <arpa/inet.h>
32   #include <poll.h>
# Line 50 | Line 48
48   #include "match.h"
49   #include "compat.h"
50   #include "negcache.h"
51 < #include "malloc.h"
51 > #include "memory.h"
52   #include "main.h"
53  
54  
# Line 60 | Line 58 | static void irc_reconnect(void);
58   static void irc_read(void);
59   static void irc_parse(void);
60  
61 < static struct ChannelConf *get_channel(const char *);
61 > static const struct ChannelConf *get_channel(const char *);
62  
63 < static struct UserInfo *userinfo_create(char *);
63 > static struct UserInfo *userinfo_create(const char *);
64   static void userinfo_free(struct UserInfo *source);
65  
66 < static void m_ping(char **, unsigned int, char *, struct UserInfo *);
67 < static void m_invite(char **, unsigned int, char *, struct UserInfo *);
68 < static void m_privmsg(char **, unsigned int, char *, struct UserInfo *);
69 < static void m_ctcp(char **, unsigned int, char *, struct UserInfo *);
70 < static void m_notice(char **, unsigned int, char *, struct UserInfo *);
71 < static void m_perform(char **, unsigned int, char *, struct UserInfo *);
72 < static void m_userhost(char **, unsigned int, char *, struct UserInfo *);
73 < static void m_cannot_join(char **, unsigned int, char *, struct UserInfo *);
74 < static void m_kill(char **, unsigned int, char *, struct UserInfo *);
66 > static void m_ping(char *[], unsigned int, const char *, const struct UserInfo *);
67 > static void m_invite(char *[], unsigned int, const char *, const struct UserInfo *);
68 > static void m_privmsg(char *[], unsigned int, const char *, const struct UserInfo *);
69 > static void m_ctcp(char *[], unsigned int, const char *, const struct UserInfo *);
70 > static void m_notice(char *[], unsigned int, const char *, const struct UserInfo *);
71 > static void m_perform(char *[], unsigned int, const char *, const struct UserInfo *);
72 > static void m_userhost(char *[], unsigned int, const char *, const struct UserInfo *);
73 > static void m_cannot_join(char *[], unsigned int, const char *, const struct UserInfo *);
74 > static void m_kill(char *[], unsigned int, const char *, const struct UserInfo *);
75  
78 extern struct cnode *nc_head;
76  
77   /*
78   * Certain variables we don't want to allocate memory for over and over
79   * again so global scope is given.
80   */
81 <
82 < static char          IRC_RAW[MSGLENMAX];         /* Buffer to read data into              */
83 < static unsigned int  IRC_RAW_LEN    = 0;         /* Position of IRC_RAW                   */
84 < static int           IRC_FD         = 0;         /* File descriptor for IRC client        */
85 <
86 < static struct bopm_sockaddr IRC_SVR;             /* Sock Address Struct for IRC server    */
87 < static struct bopm_ircaddr  IRC_LOCAL;           /* Sock Address Struct for Bind          */
91 <
92 < static time_t IRC_LAST = 0;                      /* Last full line of data from irc server*/
93 < static time_t IRC_LASTRECONNECT = 0;             /* Time of last reconnection */
81 > static char         IRC_RAW[MSGLENMAX];  /* Buffer to read data into               */
82 > static unsigned int IRC_RAW_LEN;         /* Position of IRC_RAW                    */
83 > static int          IRC_FD;              /* File descriptor for IRC client         */
84 >
85 > static struct sockaddr_storage IRC_SVR;  /* Sock Address Struct for IRC server     */
86 > static time_t IRC_LAST;                  /* Last full line of data from irc server */
87 > static time_t IRC_LASTRECONNECT;         /* Time of last reconnection              */
88  
89   /*
90   * Table should be ordered with most occuring (or priority)
91   * commands at the top of the list.
92   */
93 < static struct CommandHash COMMAND_TABLE[] =
93 > static const struct CommandHash COMMAND_TABLE[] =
94   {
95    { "NOTICE",   m_notice      },
96    { "PRIVMSG",  m_privmsg     },
# Line 130 | Line 124 | irc_cycle(void)
124    if (IRC_FD <= 0)
125    {
126      /* Initialise negative cache. */
127 <    if (OptionsItem->negcache > 0)
127 >    if (OptionsItem->negcache)
128        nc_init(&nc_head);
129  
130      /* Resolve remote host. */
# Line 144 | Line 138 | irc_cycle(void)
138    pfd.fd = IRC_FD;
139    pfd.events = POLLIN;
140  
141 <  /* Block .025 seconds to avoid excessive CPU use on poll(). */
142 <  switch (poll(&pfd, 1, 25))
141 >  /* Block .050 seconds to avoid excessive CPU use on poll(). */
142 >  switch (poll(&pfd, 1, 50))
143    {
144      case  0:
145      case -1:
# Line 154 | Line 148 | irc_cycle(void)
148        /* Check if IRC data is available. */
149        if (pfd.revents & POLLIN)
150          irc_read();
151 +      else if (pfd.revents & (POLLERR | POLLHUP))
152 +        irc_reconnect();
153  
154        break;
155    }
# Line 172 | Line 168 | irc_cycle(void)
168   static void
169   irc_init(void)
170   {
171 <  struct bopm_sockaddr bsaddr;
176 <  struct in_addr *irc_host;
171 >  const void *address = NULL;
172  
173    if (IRC_FD)
174      close(IRC_FD);
175  
176    memset(&IRC_SVR, 0, sizeof(IRC_SVR));
182  memset(&IRC_LOCAL, 0, sizeof(IRC_LOCAL));
183  memset(&bsaddr, 0, sizeof(struct bopm_sockaddr));
177  
178    /* Resolve IRC host. */
179 <  if ((irc_host = firedns_resolveip4(IRCItem->server)) == NULL)
179 >  if ((address = firedns_resolveip6(IRCItem->server)))
180    {
181 <    log_printf("IRC -> firedns_resolveip4(\"%s\"): %s", IRCItem->server,
189 <               firedns_strerror(fdns_errno));
190 <    exit(EXIT_FAILURE);
191 <  }
181 >    struct sockaddr_in6 *in = (struct sockaddr_in6 *)&IRC_SVR;
182  
183 <  IRC_SVR.sa4.sin_family = AF_INET;
184 <  IRC_SVR.sa4.sin_port = htons(IRCItem->port);
185 <  IRC_SVR.sa4.sin_addr = *irc_host;
183 >    IRC_SVR.ss_family = AF_INET6;
184 >    in->sin6_port = htons(IRCItem->port);
185 >    memcpy(&in->sin6_addr, address, sizeof(in->sin6_addr));
186 >  }
187 >  else if ((address = firedns_resolveip4(IRCItem->server)))
188 >  {
189 >    struct sockaddr_in *in = (struct sockaddr_in *)&IRC_SVR;
190  
191 <  if (IRC_SVR.sa4.sin_addr.s_addr == INADDR_NONE)
191 >    IRC_SVR.ss_family = AF_INET;
192 >    in->sin_port = htons(IRCItem->port);
193 >    memcpy(&in->sin_addr, address, sizeof(in->sin_addr));
194 >  }
195 >  else
196    {
197 <    log_printf("IRC -> Unknown error resolving remote host (%s)",
198 <               IRCItem->server);
197 >    log_printf("IRC -> firedns_resolveip(\"%s\"): %s", IRCItem->server,
198 >               firedns_strerror(firedns_errno));
199      exit(EXIT_FAILURE);
200    }
201  
202    /* Request file desc for IRC client socket */
203 <  IRC_FD = socket(AF_INET, SOCK_STREAM, 0);
203 >  IRC_FD = socket(IRC_SVR.ss_family, SOCK_STREAM, 0);
204  
205    if (IRC_FD == -1)
206    {
# Line 213 | Line 211 | irc_init(void)
211    /* Bind */
212    if (!EmptyString(IRCItem->vhost))
213    {
214 <    int bindret = 0;
214 >    struct addrinfo hints, *res;
215 >
216 >    memset(&hints, 0, sizeof(hints));
217  
218 <    if (inet_pton(AF_INET, IRCItem->vhost, &(IRC_LOCAL.in4.s_addr)) <= 0)
218 >    hints.ai_family = AF_UNSPEC;
219 >    hints.ai_socktype = SOCK_STREAM;
220 >    hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
221 >
222 >    if (getaddrinfo(IRCItem->vhost, NULL, &hints, &res))
223      {
224        log_printf("IRC -> bind(): %s is an invalid address", IRCItem->vhost);
225        exit(EXIT_FAILURE);
226      }
227 <
224 <    bsaddr.sa4.sin_addr.s_addr = IRC_LOCAL.in4.s_addr;
225 <    bsaddr.sa4.sin_family = AF_INET;
226 <    bsaddr.sa4.sin_port = htons(0);
227 <
228 <    bindret = bind(IRC_FD, (struct sockaddr *) &(bsaddr.sa4), sizeof(bsaddr.sa4));
229 <
230 <    if (bindret)
227 >    else if (bind(IRC_FD, res->ai_addr, res->ai_addrlen))
228      {
229        log_printf("IRC -> bind(): error binding to %s: %s", IRCItem->vhost, strerror(errno));
230        exit(EXIT_FAILURE);
231      }
232 +
233 +    freeaddrinfo(res);
234    }
235   }
236  
# Line 250 | Line 249 | irc_send(const char *data, ...)
249   {
250    va_list arglist;
251    char buf[MSGLENMAX];
252 <  int len = 0;
252 >  size_t len = 0;
253  
254    va_start(arglist, data);
255    len = vsnprintf(buf, sizeof(buf), data, arglist);
# Line 294 | Line 293 | irc_send_channels(const char *data, ...)
293    vsnprintf(buf, sizeof(buf), data, arglist);
294    va_end(arglist);
295  
297
296    LIST_FOREACH(node, IRCItem->channels->head)
297    {
298      const struct ChannelConf *chan = node->data;
# Line 317 | Line 315 | irc_connect(void)
315    /* Connect to IRC server as client. */
316    if (connect(IRC_FD, (struct sockaddr *)&IRC_SVR, sizeof(IRC_SVR)) == -1)
317    {
318 <    switch (errno)
319 <    {
322 <      case EISCONN:
323 <        /* Already connected */
324 <        return;
325 <      case ECONNREFUSED:
326 <        log_printf("IRC -> connect(): Connection refused by (%s)",
327 <                   IRCItem->server);
328 <        break;
329 <      case ETIMEDOUT:
330 <        log_printf("IRC -> connect(): Timed out connecting to (%s)",
331 <                   IRCItem->server);
332 <        break;
333 <      case ENETUNREACH:
334 <        log_printf("IRC -> connect(): Network unreachable");
335 <        break;
336 <      case EALREADY:
337 <        /* Previous attempt not complete */
338 <        return;
339 <      default:
340 <        log_printf("IRC -> connect(): Unknown error connecting to (%s)",
341 <                   IRCItem->server);
318 >    log_printf("IRC -> connect(): error connecting to %s: %s",
319 >               IRCItem->server, strerror(errno));
320  
321 <        if (OPT_DEBUG >= 1)
322 <          log_printf("%s", strerror(errno));
345 <    }
321 >    if (errno == EISCONN /* Already connected */ || errno == EALREADY /* Previous attempt not complete */)
322 >      return;
323  
324      /* Try to connect again */
325      irc_reconnect();
# Line 398 | Line 375 | irc_reconnect(void)
375  
376   /* irc_read
377   *
378 < *    irc_read is called my irc_cycle when new data is ready to be
378 > *    irc_read is called by irc_cycle when new data is ready to be
379   *    read from the irc server.
380   *
381   * Parameters: NONE
# Line 493 | Line 470 | irc_parse(void)
470    while ((pos = strchr(pos, ' ')) && parc <= 17)
471    {
472      /* Avoid excessive spaces and end of IRC_RAW */
473 <    if (*(pos + 1) == ' ' && *(pos + 1) == '\0')
473 >    if (*(pos + 1) == ' ' || *(pos + 1) == '\0')
474      {
475        pos++;
476        continue;
# Line 557 | Line 534 | irc_timer(void)
534      log_printf("IRC -> Timeout awaiting data from server.");
535      irc_reconnect();
536  
537 <    /* Make sure we dont do this again for a while */
537 >    /* Make sure we don't do this again for a while */
538      time(&IRC_LAST);
539    }
540    else if (delta >= IRCItem->readtimeout / 2)
541    {
542      /*
543 <     * Generate some data so high ping times or bugs in certain
567 <     * ircds (*cough* unreal *cough*) don't cause uneeded
543 >     * Generate some data so high ping times don't cause uneeded
544       * reconnections
545       */
546      irc_send("PING :HOPM");
# Line 581 | Line 557 | irc_timer(void)
557   *
558   * Return: Pointer to ChannelConf containing the channel
559   */
560 < static struct ChannelConf *
560 > static const struct ChannelConf *
561   get_channel(const char *channel)
562   {
563    node_t *node;
# Line 609 | Line 585 | get_channel(const char *channel)
585   *    pointer to new UserInfo struct, or NULL if parsing failed
586   */
587   static struct UserInfo *
588 < userinfo_create(char *source)
588 > userinfo_create(const char *source)
589   {
590    struct UserInfo *ret;
591 <  char *nick;
592 <  char *username;
593 <  char *hostname;
594 <  char *tmp;
595 <  int i, len;
596 <
597 <  nick = username = hostname = NULL;
622 <  tmp = xstrdup(source);
623 <  len = strlen(tmp);
591 >  char *nick = NULL;
592 >  char *username = NULL;
593 >  char *hostname = NULL;
594 >  char tmp[MSGLENMAX];
595 >  size_t len;
596 >
597 >  len = strlcpy(tmp, source, sizeof(tmp));
598    nick = tmp;
599  
600 <  for (i = 0; i < len; ++i)
600 >  for (size_t i = 0; i < len; ++i)
601    {
602      if (tmp[i] == '!')
603      {
# Line 638 | Line 612 | userinfo_create(char *source)
612      }
613    }
614  
615 <  if (nick == NULL || username == NULL || hostname == NULL)
642 <  {
643 <    MyFree(tmp);
615 >  if (username == NULL || hostname == NULL)
616      return NULL;
645  }
617  
618    ret = xcalloc(sizeof *ret);
619    ret->irc_nick     = xstrdup(nick);
620    ret->irc_username = xstrdup(username);
621    ret->irc_hostname = xstrdup(hostname);
622  
652  MyFree(tmp);
653
623    return ret;
624   };
625  
# Line 669 | Line 638 | userinfo_free(struct UserInfo *source_p)
638    if (source_p == NULL)
639      return;
640  
641 <  MyFree(source_p->irc_nick);
642 <  MyFree(source_p->irc_username);
643 <  MyFree(source_p->irc_hostname);
644 <  MyFree(source_p);
641 >  xfree(source_p->irc_nick);
642 >  xfree(source_p->irc_username);
643 >  xfree(source_p->irc_hostname);
644 >  xfree(source_p);
645   }
646  
647   /* m_perform
# Line 688 | Line 657 | userinfo_free(struct UserInfo *source_p)
657   * the source (parv[0]) is a server.
658   */
659   static void
660 < m_perform(char **parv, unsigned int parc, char *msg, struct UserInfo *notused)
660 > m_perform(char *parv[], unsigned int parc, const char *msg, const struct UserInfo *notused)
661   {
662    node_t *node;
663  
664 <  log_printf("IRC -> Connected to %s:%d", IRCItem->server, IRCItem->port);
664 >  log_printf("IRC -> Connected to %s/%d", IRCItem->server, IRCItem->port);
665  
666    /* Identify to nickserv if needed */
667    if (!EmptyString(IRCItem->nickserv))
# Line 715 | Line 684 | m_perform(char **parv, unsigned int parc
684    /* Join all listed channels. */
685    LIST_FOREACH(node, IRCItem->channels->head)
686    {
687 <    struct ChannelConf *channel = node->data;
687 >    const struct ChannelConf *channel = node->data;
688  
689      if (EmptyString(channel->name))
690        continue;
# Line 737 | Line 706 | m_perform(char **parv, unsigned int parc
706   * the source (parv[0]) is a server.
707   */
708   static void
709 < m_ping(char **parv, unsigned int parc, char *msg, struct UserInfo *source_p)
709 > m_ping(char *parv[], unsigned int parc, const char *msg, const struct UserInfo *source_p)
710   {
711    if (parc < 3)
712      return;
# Line 759 | Line 728 | m_ping(char **parv, unsigned int parc, c
728   * the source (parv[0]) is a server.
729   */
730   static void
731 < m_invite(char **parv, unsigned int parc, char *msg, struct UserInfo *source_p)
731 > m_invite(char *parv[], unsigned int parc, const char *msg, const struct UserInfo *source_p)
732   {
733 <  struct ChannelConf *channel;
733 >  const struct ChannelConf *channel = NULL;
734  
735    if (parc < 4)
736      return;
# Line 785 | Line 754 | m_invite(char **parv, unsigned int parc,
754   * the source (parv[0]) is a server.
755   */
756   static void
757 < m_privmsg(char **parv, unsigned int parc, char *msg, struct UserInfo *source_p)
757 > m_privmsg(char *parv[], unsigned int parc, const char *msg, const struct UserInfo *source_p)
758   {
759 <  struct ChannelConf *channel;
759 >  const struct ChannelConf *channel = NULL;
760    size_t nick_len;
761  
762    if (source_p == NULL)
# Line 819 | Line 788 | m_privmsg(char **parv, unsigned int parc
788        strncasecmp(parv[3], "!all", 4) == 0)
789    {
790      /* XXX command_parse will alter parv[3]. */
791 <    command_parse(parv[3], msg, channel, source_p);
791 >    command_parse(parv[3], channel, source_p);
792    }
793   }
794  
# Line 834 | Line 803 | m_privmsg(char **parv, unsigned int parc
803   *
804   */
805   static void
806 < m_ctcp(char **parv, unsigned int parc, char *msg, struct UserInfo *source_p)
806 > m_ctcp(char *parv[], unsigned int parc, const char *msg, const struct UserInfo *source_p)
807   {
808    if (strncasecmp(parv[3], "\001VERSION\001", 9) == 0)
809      irc_send("NOTICE %s :\001VERSION Hybrid Open Proxy Monitor %s\001",
# Line 854 | Line 823 | m_ctcp(char **parv, unsigned int parc, c
823   *
824   */
825   static void
826 < m_notice(char **parv, unsigned int parc, char *msg, struct UserInfo *source_p)
826 > m_notice(char *parv[], unsigned int parc, const char *msg, const struct UserInfo *source_p)
827   {
828    static regex_t *preg = NULL;
829    regmatch_t pmatch[5];
830 <
831 <  static char errmsg[256];
832 <  int errnum, i;
864 <  char *user[4];
865 <
866 <  if (parc < 4)
867 <    return;
830 >  int errnum;
831 >  const char *user[4];
832 >  const node_t *node;
833  
834    /* Not interested in notices from users */
835    if (source_p)
836      return;
837  
838 +  if (parc < 4)
839 +    return;
840 +
841    /* Compile the regular expression if it has not been already */
842    if (preg == NULL)
843    {
# Line 877 | Line 845 | m_notice(char **parv, unsigned int parc,
845  
846      if ((errnum = regcomp(preg, IRCItem->connregex, REG_ICASE | REG_EXTENDED)))
847      {
848 <      regerror(errnum, preg, errmsg, 256);
848 >      char errmsg[256];
849 >
850 >      regerror(errnum, preg, errmsg, sizeof(errmsg));
851        log_printf("IRC REGEX -> Error when compiling regular expression");
852        log_printf("IRC REGEX -> %s", errmsg);
853  
854 <      MyFree(preg);
854 >      xfree(preg);
855        preg = NULL;
856        return;
857      }
# Line 908 | Line 878 | m_notice(char **parv, unsigned int parc,
878     *   HOSTNAME: pmatch[3].rm_so  TO  pmatch[3].rm_eo
879     *   IP      : pmatch[4].rm_so  TO  pmatch[4].rm_eo
880     */
881 <  for (i = 0; i < 4; ++i)
881 >  for (unsigned int i = 0; i < 4; ++i)
882    {
883      user[i] = (parv[3] + pmatch[i + 1].rm_so);
884      *(parv[3] + pmatch[i + 1].rm_eo) = '\0';
# Line 918 | Line 888 | m_notice(char **parv, unsigned int parc,
888      log_printf("IRC REGEX -> Parsed %s!%s@%s [%s] from connection notice.",
889                 user[0], user[1], user[2], user[3]);
890  
891 <  /*FIXME (reminder) In the case of any rehash to the regex, preg MUST be freed first.
892 <      regfree(preg);
923 <   */
891 >  LIST_FOREACH(node, IRCItem->notices->head)
892 >    irc_send("NOTICE %s :%s", user[0], node->data);
893  
894    /* Pass this information off to scan.c */
895    scan_connect(user, msg);
# Line 942 | Line 911 | m_notice(char **parv, unsigned int parc,
911   *
912   */
913   static void
914 < m_userhost(char **parv, unsigned int parc, char *msg, struct UserInfo *source_p)
914 > m_userhost(char *parv[], unsigned int parc, const char *msg, const struct UserInfo *source_p)
915   {
916    if (parc < 4)
917      return;
# Line 960 | Line 929 | m_userhost(char **parv, unsigned int par
929   *
930   */
931   static void
932 < m_cannot_join(char **parv, unsigned int parc, char *msg, struct UserInfo *source_p)
932 > m_cannot_join(char *parv[], unsigned int parc, const char *msg, const struct UserInfo *source_p)
933   {
934 <  struct ChannelConf *channel;
934 >  const struct ChannelConf *channel = NULL;
935  
936    if (parc < 5)
937      return;
# Line 987 | Line 956 | m_cannot_join(char **parv, unsigned int
956   *
957   */
958   static void
959 < m_kill(char **parv, unsigned int parc, char *msg, struct UserInfo *source_p)
959 > m_kill(char *parv[], unsigned int parc, const char *msg, const struct UserInfo *source_p)
960   {
961    /* Restart hopm to rehash */
962    main_restart();

Diff Legend

Removed lines
+ Added lines
< Changed lines (old)
> Changed lines (new)