c2701d24cd2c9d5a59dbfb17509f1b31d28c19ba
[ircu2.10.12-pk.git] / ircd / os_linux.c
1 /*
2  * IRC - Internet Relay Chat, ircd/os_linux.c
3  * Copyright (C) 1999 Thomas Helvey
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 1, or (at your option)
8  * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
18  *
19  * $Id$
20  *
21  */
22 #include "ircd_osdep.h"
23
24 #include <assert.h>
25 #include <errno.h>
26 #include <fcntl.h>
27 #include <stdio.h>
28 #include <netinet/in.h>
29 #include <string.h>
30 #include <sys/ioctl.h>
31 #include <sys/resource.h>
32 #include <sys/socket.h>
33 #include <sys/types.h>
34 #include <sys/times.h>
35 #include <sys/param.h>
36 #if 0
37 #include <unistd.h>
38 #endif
39
40 /*
41  * This is part of the STATS replies. There is no offical numeric for this
42  * since this isnt an official command, in much the same way as HASH isnt.
43  * It is also possible that some systems wont support this call or have
44  * different field names for "struct rusage".
45  * -avalon
46  */
47 int os_get_rusage(struct Client *cptr, int uptime, EnumFn enumerator)
48 {
49   char buf[256];
50   struct rusage rus;
51   struct tms tmsbuf;
52   time_t secs;
53   time_t mins;
54   int umin;
55   int smin;
56   int usec;
57   int ssec;
58   int ticpermin = HZ * 60;
59   unsigned int tick_count = uptime * HZ;
60
61   if (0 == tick_count)
62     ++tick_count;
63
64   assert(0 != enumerator);
65   if (getrusage(RUSAGE_SELF, &rus) == -1)
66     return 0;
67
68   secs = rus.ru_utime.tv_sec + rus.ru_stime.tv_sec;
69   if (secs == 0)
70     secs = 1;
71
72   sprintf(buf, "CPU Secs %ld:%ld User %ld:%ld System %ld:%ld",
73           secs / 60, secs % 60,
74           rus.ru_utime.tv_sec / 60, rus.ru_utime.tv_sec % 60,
75           rus.ru_stime.tv_sec / 60, rus.ru_stime.tv_sec % 60);
76   (*enumerator)(cptr, buf);
77
78   sprintf(buf, "RSS %ld ShMem %ld Data %ld Stack %ld",
79           rus.ru_maxrss,
80           rus.ru_ixrss / tick_count, rus.ru_idrss / tick_count,
81           rus.ru_isrss / tick_count);
82   (*enumerator)(cptr, buf);
83
84   sprintf(buf, "Swaps %ld Reclaims %ld Faults %ld",
85           rus.ru_nswap, rus.ru_minflt, rus.ru_majflt);
86   (*enumerator)(cptr, buf);
87
88   sprintf(buf, "Block in %ld out %ld", rus.ru_inblock, rus.ru_oublock);
89   (*enumerator)(cptr, buf);
90   
91   sprintf(buf, "Msg Rcv %ld Send %ld", rus.ru_msgrcv, rus.ru_msgsnd);
92   (*enumerator)(cptr, buf);
93
94   sprintf(buf, "Signals %ld Context Vol. %ld Invol %ld",
95           rus.ru_nsignals, rus.ru_nvcsw, rus.ru_nivcsw);
96   (*enumerator)(cptr, buf);
97
98   if (times(&tmsbuf) == -1)
99     return 0;
100
101   umin = tmsbuf.tms_utime / ticpermin;
102   usec = (tmsbuf.tms_utime % ticpermin) / (float)HZ;
103   smin = tmsbuf.tms_stime / ticpermin;
104   ssec = (tmsbuf.tms_stime % ticpermin) / (float)HZ;
105   secs = usec + ssec;
106   mins = (secs / 60) + umin + smin;
107   secs %= HZ;
108
109   sprintf(buf, "CPU Secs %ld:%ld User %d:%d System %d:%d", 
110           mins, secs, umin, usec, smin, ssec);
111   (*enumerator)(cptr, buf);
112   return 1;
113 }
114
115 int os_get_sockerr(int fd)
116 {
117   int    err = 0;
118   size_t len = sizeof(err);
119   getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &len);
120   return err;
121 }
122
123 /*
124  * set_non_blocking
125  *
126  * Set the client connection into non-blocking mode. If your
127  * system doesn't support this, you can make this a dummy
128  * function (and get all the old problems that plagued the
129  * blocking version of IRC--not a problem if you are a
130  * lightly loaded node...)
131  */
132 int os_set_nonblocking(int fd)
133 {
134   int res = 1;
135   return (0 == ioctl(fd, FIONBIO, &res));
136 }
137
138
139 /*
140  *  set_sock_opts
141  */
142 int os_set_reuseaddr(int fd)
143 {
144   size_t opt = 1;
145   return (0 == setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)));
146 }
147
148 int os_set_sockbufs(int fd, unsigned int size)
149 {
150   size_t opt = size;
151   return (0 == setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt)) &&
152           0 == setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &opt, sizeof(opt)));
153 }
154
155 int os_disable_options(int fd)
156 {
157   return (0 == setsockopt(fd, IPPROTO_IP, IP_OPTIONS, NULL, 0));
158 }
159
160 int os_set_fdlimit(unsigned int max_descriptors)
161 {
162   struct rlimit limit;
163
164   if (!getrlimit(RLIMIT_NOFILE, &limit)) {
165     if (limit.rlim_max < max_descriptors)
166       return limit.rlim_max;
167     limit.rlim_cur = limit.rlim_max;    /* make soft limit the max */
168     return setrlimit(RLIMIT_NOFILE, &limit);
169   }
170   return 0;
171 }
172
173 /*
174  * os_recv_nonb - non blocking read of a connection
175  * returns:
176  *  1  if data was read or socket is blocked (recoverable error)
177  *    count_out > 0 if data was read
178  *   
179  *  0  if socket closed from other end
180  *  -1 if an unrecoverable error occurred
181  */
182 IOResult os_recv_nonb(int fd, char* buf, unsigned int length, 
183                  unsigned int* count_out)
184 {
185   int res;
186   assert(0 != buf);
187   assert(0 != count_out);
188   *count_out = 0;
189   errno = 0;
190
191   if (0 < (res = recv(fd, buf, length, 0))) {
192     *count_out = (unsigned) res;
193     return IO_SUCCESS;
194   }
195   else if (res < 0) {
196     if (EWOULDBLOCK == errno || EAGAIN == errno)
197       return IO_BLOCKED;
198     else
199       return IO_FAILURE;
200   } 
201   /*
202    * 0   == client closed the connection
203    * < 1 == error
204    */
205   return IO_FAILURE;
206 }
207
208 IOResult os_recvfrom_nonb(int fd, char* buf, unsigned int length, 
209                           unsigned int* length_out, struct sockaddr_in* sin_out)
210 {
211   int    res;
212   size_t len = sizeof(struct sockaddr_in);
213   assert(0 != buf);
214   assert(0 != length_out);
215   assert(0 != sin_out);
216   errno = 0;
217
218   res = recvfrom(fd, buf, length, 0, (struct sockaddr*) sin_out, &len);
219   if (-1 == res) {
220     if (EWOULDBLOCK == errno || ENOMEM == errno)
221       return IO_BLOCKED;
222     return IO_FAILURE;
223   }
224   *length_out = res;
225   return IO_SUCCESS;
226 }
227
228 /*
229  * os_send_nonb - non blocking read of a connection
230  * returns:
231  *  1  if data was written
232  *    count_out contains amount written
233  *   
234  *  0  if write call blocked, recoverable error
235  *  -1 if an unrecoverable error occurred
236  */
237 IOResult os_send_nonb(int fd, const char* buf, unsigned int length, 
238                  unsigned int* count_out)
239 {
240   int res;
241   assert(0 != buf);
242   assert(0 != count_out);
243   *count_out = 0;
244   errno = 0;
245
246   if (-1 < (res = send(fd, buf, length, 0))) {
247     *count_out = (unsigned) res;
248     return IO_SUCCESS;
249   }
250   else if (EAGAIN == errno || ENOMEM == errno || ENOBUFS == errno)
251     return IO_BLOCKED;
252
253   return IO_FAILURE;
254 }
255
256
257 int os_connect_nonb(int fd, const struct sockaddr_in* sin)
258 {
259   if (connect(fd, (const struct sockaddr*) sin, sizeof(struct sockaddr_in))) {
260     if (errno != EINPROGRESS)
261       return 0;
262   }
263   return 1;
264 }
265       
266 int os_get_sockname(int fd, struct sockaddr_in* sin_out)
267 {
268   size_t len = sizeof(struct sockaddr_in);
269   assert(0 != sin_out);
270   return (0 == getsockname(fd, (struct sockaddr*) sin_out, &len));
271 }
272
273 int os_get_peername(int fd, struct sockaddr_in* sin_out)
274 {
275   size_t len = sizeof(struct sockaddr_in);
276   assert(0 != sin_out);
277   return (0 == getpeername(fd, (struct sockaddr*) sin_out, &len));
278 }
279
280 int os_set_listen(int fd, int backlog)
281 {
282   /*
283    * for linux 2.2 backlog is the number of connections ready to be accepted
284    * not the max syn requests, there is a kernel tweak there to set the max
285    * syn request queue length
286    */
287   return (0 == listen(fd, backlog));
288 }
289