]> jfr.im git - irc/quakenet/newserv.git/blob - nickrate/nickrate.c
A4STATS: remove E style escapes and switch to createtable for indices
[irc/quakenet/newserv.git] / nickrate / nickrate.c
1 #include "../server/server.h"
2 #include "../core/hooks.h"
3 #include "../core/events.h"
4 #include "../nick/nick.h"
5 #include <sys/poll.h>
6 #include <sys/types.h>
7 #include <sys/socket.h>
8 #include <netdb.h>
9 #include "../core/error.h"
10 #include <stdlib.h>
11 #include <stdio.h>
12 #include <errno.h>
13 #include <sys/ioctl.h>
14 #include <unistd.h>
15 #include <netinet/in.h>
16 #include <string.h>
17 #include "../lib/version.h"
18
19 MODULE_VERSION("")
20
21 unsigned int nicks;
22 unsigned int quits;
23 int nickrate_listenfd;
24
25 void nr_nick(int hooknum, void *arg);
26 void nr_handlelistensocket(int fd, short events);
27 int nr_openlistensocket(int portnum);
28
29 void _init() {
30 nicks=0;
31 quits=0;
32 registerhook(HOOK_NICK_NEWNICK, &nr_nick);
33 registerhook(HOOK_NICK_LOSTNICK, &nr_nick);
34
35 nickrate_listenfd=nr_openlistensocket(6002);
36 if (nickrate_listenfd>0) {
37 registerhandler(nickrate_listenfd,POLLIN,&nr_handlelistensocket);
38 }
39
40 }
41
42 void _fini() {
43 deregisterhook(HOOK_NICK_NEWNICK, &nr_nick);
44 deregisterhook(HOOK_NICK_LOSTNICK, &nr_nick);
45 deregisterhandler(nickrate_listenfd,1);
46 }
47
48 void nr_nick(int hooknum, void *arg) {
49 nick *np=(nick *)arg;
50
51 if (serverlist[homeserver(np->numeric)].linkstate == LS_LINKED) {
52 if (hooknum==HOOK_NICK_NEWNICK) {
53 nicks++;
54 } else {
55 quits++;
56 }
57 }
58 }
59
60 int nr_openlistensocket(int portnum) {
61 struct sockaddr_in sin;
62 int fd;
63 unsigned int opt=1;
64
65 if ((fd=socket(AF_INET,SOCK_STREAM,0))==-1) {
66 Error("nickrate",ERR_ERROR,"Unable to open listening socket (%d).",errno);
67 return -1;
68 }
69
70 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char *) &opt, sizeof(opt))!=0) {
71 close(fd);
72 Error("nickrate",ERR_ERROR,"Unable to set SO_REUSEADDR on listen socket.");
73 return -1;
74 }
75
76 /* Initialiase the addresses */
77 memset(&sin,0,sizeof(sin));
78 sin.sin_family=AF_INET;
79 sin.sin_port=htons(portnum);
80
81 if (bind(fd, (struct sockaddr *) &sin, sizeof(sin))) {
82 close(fd);
83 Error("nickrate",ERR_ERROR,"Unable to bind listen socket (%d).",errno);
84 return -1;
85 }
86
87 listen(fd,5);
88
89 if (ioctl(fd, FIONBIO, &opt)!=0) {
90 close(fd);
91 Error("nickrate",ERR_ERROR,"Unable to set listen socket non-blocking.");
92 return -1;
93 }
94
95 return fd;
96 }
97
98 /* Here's what we do when poll throws the listen socket at us:
99 * accept() the connection, spam a short message and immediately
100 * close it again */
101
102 void nr_handlelistensocket(int fd, short events) {
103 struct sockaddr_in sin;
104 socklen_t addrsize=sizeof(sin);
105 char buf[20];
106 int newfd;
107 if ((newfd=accept(fd, (struct sockaddr *)&sin, &addrsize))>-1) {
108 /* Got new connection */
109 sprintf(buf,"%u\n",nicks);
110 write(newfd,buf,strlen(buf));
111 sprintf(buf,"%u\n",quits);
112 write(newfd,buf,strlen(buf));
113 close(newfd);
114 }
115 }