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 5226 by michael, Wed Dec 31 14:08:39 2014 UTC vs.
Revision 5367 by michael, Mon Jan 12 20:13:22 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>
33 <
34 < #ifdef TIME_WITH_SYS_TIME
37 < # include <sys/time.h>
38 < # include <time.h>
39 < #else
40 < # ifdef HAVE_SYS_TIME_H
41 < #  include <sys/time.h>
42 < # else
43 < #  include <time.h>
44 < # endif
45 < #endif
33 > #include <sys/time.h>
34 > #include <time.h>
35  
36   #include <errno.h>
37   #include <stdarg.h>
# Line 59 | 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 74 | Line 63 | static struct ChannelConf *get_channel(c
63   static struct UserInfo *userinfo_create(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, char *, const struct UserInfo *);
67 > static void m_invite(char *[], unsigned int, char *, const struct UserInfo *);
68 > static void m_privmsg(char *[], unsigned int, char *, const struct UserInfo *);
69 > static void m_ctcp(char *[], unsigned int, char *, const struct UserInfo *);
70 > static void m_notice(char *[], unsigned int, char *, const struct UserInfo *);
71 > static void m_perform(char *[], unsigned int, char *, const struct UserInfo *);
72 > static void m_userhost(char *[], unsigned int, char *, const struct UserInfo *);
73 > static void m_cannot_join(char *[], unsigned int, char *, const struct UserInfo *);
74 > static void m_kill(char *[], unsigned int, char *, const struct UserInfo *);
75  
87 extern struct cnode *nc_head;
76  
77   /*
78   * Certain variables we don't want to allocate memory for over and over
# Line 95 | Line 83 | static char          IRC_RAW[MSGLENMAX];
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    */
99 < static struct bopm_ircaddr  IRC_LOCAL;           /* Sock Address Struct for Bind          */
86 > static struct sockaddr_storage IRC_SVR;          /* Sock Address Struct for IRC server    */
87  
88   static time_t IRC_LAST = 0;                      /* Last full line of data from irc server*/
89   static time_t IRC_LASTRECONNECT = 0;             /* Time of last reconnection */
# Line 181 | Line 168 | irc_cycle(void)
168   static void
169   irc_init(void)
170   {
171 <  struct bopm_sockaddr bsaddr;
185 <  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));
191  memset(&IRC_LOCAL, 0, sizeof(IRC_LOCAL));
192  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,
198 <               firedns_strerror(fdns_errno));
199 <    exit(EXIT_FAILURE);
200 <  }
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(fdns_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    {
207 <    switch (errno)
219 <    {
220 <      case EINVAL:
221 <      case EPROTONOSUPPORT:
222 <        log_printf("IRC -> socket(): SOCK_STREAM is not supported on this domain");
223 <        break;
224 <      case ENFILE:
225 <        log_printf("IRC -> socket(): Not enough free file descriptors to allocate IRC socket");
226 <        break;
227 <      case EMFILE:
228 <        log_printf("IRC -> socket(): Process table overflow when requesting file descriptor");
229 <        break;
230 <      case EACCES:
231 <        log_printf("IRC -> socket(): Permission denied to create socket of type SOCK_STREAM");
232 <        break;
233 <      case ENOMEM:
234 <        log_printf("IRC -> socket(): Insufficient memory to allocate socket");
235 <        break;
236 <      default:
237 <        log_printf("IRC -> socket(): Unknown error allocating socket");
238 <        break;
239 <    }
240 <
207 >    log_printf("IRC -> socket(): error creating socket: %s", strerror(errno));
208      exit(EXIT_FAILURE);
209    }
210  
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 <
255 <    bsaddr.sa4.sin_addr.s_addr = IRC_LOCAL.in4.s_addr;
256 <    bsaddr.sa4.sin_family = AF_INET;
257 <    bsaddr.sa4.sin_port = htons(0);
258 <
259 <    bindret = bind(IRC_FD, (struct sockaddr *) &(bsaddr.sa4), sizeof(bsaddr.sa4));
260 <
261 <    if (bindret)
227 >    else if (bind(IRC_FD, res->ai_addr, res->ai_addrlen))
228      {
229 <      switch (errno)
264 <      {
265 <        case EACCES:
266 <          log_printf("IRC -> bind(): No access to bind to %s", IRCItem->vhost);
267 <          break;
268 <        default:
269 <          log_printf("IRC -> bind(): Error binding to %s (%d)", IRCItem->vhost, errno);
270 <          break;
271 <      }
272 <
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 290 | 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 308 | Line 267 | irc_send(const char *data, ...)
267    if (send(IRC_FD, buf, len, 0) == -1)
268    {
269      /* Return of -1 indicates error sending data; we reconnect. */
270 <    log_printf("IRC -> Error sending data to server\n");
270 >    log_printf("IRC -> Error sending data to server: %s", strerror(errno));
271      irc_reconnect();
272    }
273   }
# Line 334 | Line 293 | irc_send_channels(const char *data, ...)
293    vsnprintf(buf, sizeof(buf), data, arglist);
294    va_end(arglist);
295  
337
296    LIST_FOREACH(node, IRCItem->channels->head)
297    {
298      const struct ChannelConf *chan = node->data;
# Line 357 | 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 <    {
362 <      case EISCONN:
363 <        /* Already connected */
364 <        return;
365 <      case ECONNREFUSED:
366 <        log_printf("IRC -> connect(): Connection refused by (%s)",
367 <                   IRCItem->server);
368 <        break;
369 <      case ETIMEDOUT:
370 <        log_printf("IRC -> connect(): Timed out connecting to (%s)",
371 <                   IRCItem->server);
372 <        break;
373 <      case ENETUNREACH:
374 <        log_printf("IRC -> connect(): Network unreachable");
375 <        break;
376 <      case EALREADY:
377 <        /* Previous attempt not complete */
378 <        return;
379 <      default:
380 <        log_printf("IRC -> connect(): Unknown error connecting to (%s)",
381 <                   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));
385 <    }
321 >    if (errno == EISCONN /* Already connected */ || errno == EALREADY /* Previous attempt not complete */)
322 >      return;
323  
324      /* Try to connect again */
325      irc_reconnect();
# Line 533 | 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 597 | 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
607 <     * 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 684 | Line 620 | userinfo_create(char *source)
620      return NULL;
621    }
622  
623 <  ret = MyMalloc(sizeof *ret);
623 >  ret = xcalloc(sizeof *ret);
624    ret->irc_nick     = xstrdup(nick);
625    ret->irc_username = xstrdup(username);
626    ret->irc_hostname = xstrdup(hostname);
# Line 728 | Line 664 | userinfo_free(struct UserInfo *source_p)
664   * the source (parv[0]) is a server.
665   */
666   static void
667 < m_perform(char **parv, unsigned int parc, char *msg, struct UserInfo *notused)
667 > m_perform(char *parv[], unsigned int parc, char *msg, const struct UserInfo *notused)
668   {
669    node_t *node;
670  
671 <  log_printf("IRC -> Connected to %s:%d", IRCItem->server, IRCItem->port);
671 >  log_printf("IRC -> Connected to %s/%d", IRCItem->server, IRCItem->port);
672  
673    /* Identify to nickserv if needed */
674    if (!EmptyString(IRCItem->nickserv))
# Line 755 | Line 691 | m_perform(char **parv, unsigned int parc
691    /* Join all listed channels. */
692    LIST_FOREACH(node, IRCItem->channels->head)
693    {
694 <    struct ChannelConf *channel = node->data;
694 >    const struct ChannelConf *channel = node->data;
695  
696      if (EmptyString(channel->name))
697        continue;
# Line 777 | Line 713 | m_perform(char **parv, unsigned int parc
713   * the source (parv[0]) is a server.
714   */
715   static void
716 < m_ping(char **parv, unsigned int parc, char *msg, struct UserInfo *source_p)
716 > m_ping(char *parv[], unsigned int parc, char *msg, const struct UserInfo *source_p)
717   {
718    if (parc < 3)
719      return;
# Line 799 | Line 735 | m_ping(char **parv, unsigned int parc, c
735   * the source (parv[0]) is a server.
736   */
737   static void
738 < m_invite(char **parv, unsigned int parc, char *msg, struct UserInfo *source_p)
738 > m_invite(char *parv[], unsigned int parc, char *msg, const struct UserInfo *source_p)
739   {
740 <  struct ChannelConf *channel;
740 >  struct ChannelConf *channel = NULL;
741  
742    if (parc < 4)
743      return;
# Line 825 | Line 761 | m_invite(char **parv, unsigned int parc,
761   * the source (parv[0]) is a server.
762   */
763   static void
764 < m_privmsg(char **parv, unsigned int parc, char *msg, struct UserInfo *source_p)
764 > m_privmsg(char *parv[], unsigned int parc, char *msg, const struct UserInfo *source_p)
765   {
766 <  struct ChannelConf *channel;
766 >  struct ChannelConf *channel = NULL;
767    size_t nick_len;
768  
769    if (source_p == NULL)
# Line 859 | Line 795 | m_privmsg(char **parv, unsigned int parc
795        strncasecmp(parv[3], "!all", 4) == 0)
796    {
797      /* XXX command_parse will alter parv[3]. */
798 <    command_parse(parv[3], msg, channel, source_p);
798 >    command_parse(parv[3], channel, source_p);
799    }
800   }
801  
# Line 874 | Line 810 | m_privmsg(char **parv, unsigned int parc
810   *
811   */
812   static void
813 < m_ctcp(char **parv, unsigned int parc, char *msg, struct UserInfo *source_p)
813 > m_ctcp(char *parv[], unsigned int parc, char *msg, const struct UserInfo *source_p)
814   {
815    if (strncasecmp(parv[3], "\001VERSION\001", 9) == 0)
816      irc_send("NOTICE %s :\001VERSION Hybrid Open Proxy Monitor %s\001",
# Line 894 | Line 830 | m_ctcp(char **parv, unsigned int parc, c
830   *
831   */
832   static void
833 < m_notice(char **parv, unsigned int parc, char *msg, struct UserInfo *source_p)
833 > m_notice(char *parv[], unsigned int parc, char *msg, const struct UserInfo *source_p)
834   {
835    static regex_t *preg = NULL;
836    regmatch_t pmatch[5];
837 <
838 <  static char errmsg[256];
903 <  int errnum, i;
904 <  char *user[4];
905 <
906 <  if (parc < 4)
907 <    return;
837 >  int errnum;
838 >  const char *user[4];
839  
840    /* Not interested in notices from users */
841    if (source_p)
842      return;
843  
844 +  if (parc < 4)
845 +    return;
846 +
847    /* Compile the regular expression if it has not been already */
848    if (preg == NULL)
849    {
850 <    preg = MyMalloc(sizeof *preg);
850 >    preg = xcalloc(sizeof *preg);
851  
852      if ((errnum = regcomp(preg, IRCItem->connregex, REG_ICASE | REG_EXTENDED)))
853      {
854 <      regerror(errnum, preg, errmsg, 256);
854 >      char errmsg[256];
855 >
856 >      regerror(errnum, preg, errmsg, sizeof(errmsg));
857        log_printf("IRC REGEX -> Error when compiling regular expression");
858        log_printf("IRC REGEX -> %s", errmsg);
859  
# Line 948 | Line 884 | m_notice(char **parv, unsigned int parc,
884     *   HOSTNAME: pmatch[3].rm_so  TO  pmatch[3].rm_eo
885     *   IP      : pmatch[4].rm_so  TO  pmatch[4].rm_eo
886     */
887 <  for (i = 0; i < 4; ++i)
887 >  for (unsigned int i = 0; i < 4; ++i)
888    {
889      user[i] = (parv[3] + pmatch[i + 1].rm_so);
890      *(parv[3] + pmatch[i + 1].rm_eo) = '\0';
# Line 982 | Line 918 | m_notice(char **parv, unsigned int parc,
918   *
919   */
920   static void
921 < m_userhost(char **parv, unsigned int parc, char *msg, struct UserInfo *source_p)
921 > m_userhost(char *parv[], unsigned int parc, char *msg, const struct UserInfo *source_p)
922   {
923    if (parc < 4)
924      return;
# Line 1000 | Line 936 | m_userhost(char **parv, unsigned int par
936   *
937   */
938   static void
939 < m_cannot_join(char **parv, unsigned int parc, char *msg, struct UserInfo *source_p)
939 > m_cannot_join(char *parv[], unsigned int parc, char *msg, const struct UserInfo *source_p)
940   {
941 <  struct ChannelConf *channel;
941 >  const struct ChannelConf *channel = NULL;
942  
943    if (parc < 5)
944      return;
# Line 1027 | Line 963 | m_cannot_join(char **parv, unsigned int
963   *
964   */
965   static void
966 < m_kill(char **parv, unsigned int parc, char *msg, struct UserInfo *source_p)
966 > m_kill(char *parv[], unsigned int parc, char *msg, const struct UserInfo *source_p)
967   {
968    /* Restart hopm to rehash */
969    main_restart();

Diff Legend

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