| Commit | Line | Data |
|---|---|---|
| 984263bc MD |
1 | /* |
| 2 | * Copyright (c) 1998,1999 Martin Husemann. All rights reserved. | |
| 3 | * | |
| 4 | * Redistribution and use in source and binary forms, with or without | |
| 5 | * modification, are permitted provided that the following conditions | |
| 6 | * are met: | |
| 7 | * | |
| 8 | * 1. Redistributions of source code must retain the above copyright | |
| 9 | * notice, this list of conditions and the following disclaimer. | |
| 10 | * 2. Redistributions in binary form must reproduce the above copyright | |
| 11 | * notice, this list of conditions and the following disclaimer in the | |
| 12 | * documentation and/or other materials provided with the distribution. | |
| 13 | * 3. Neither the name of the author nor the names of any co-contributors | |
| 14 | * may be used to endorse or promote products derived from this software | |
| 15 | * without specific prior written permission. | |
| 16 | * 4. Altered versions must be plainly marked as such, and must not be | |
| 17 | * misrepresented as being the original software and/or documentation. | |
| 18 | * | |
| 19 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | |
| 20 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
| 21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
| 22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | |
| 23 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
| 24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
| 25 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
| 26 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
| 27 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
| 28 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
| 29 | * SUCH DAMAGE. | |
| 30 | * | |
| 31 | *--------------------------------------------------------------------------- | |
| 32 | * | |
| 33 | * i4b daemon - network monitor server module | |
| 34 | * ------------------------------------------ | |
| 35 | * | |
| 36 | * $Id: monitor.c,v 1.30 2000/10/09 12:53:29 hm Exp $ | |
| 37 | * | |
| 38 | * $FreeBSD: src/usr.sbin/i4b/isdnd/monitor.c,v 1.6.2.2 2001/08/01 17:45:03 obrien Exp $ | |
| fe361e7d | 39 | * $DragonFly: src/usr.sbin/i4b/isdnd/monitor.c,v 1.4 2005/11/25 00:58:52 swildner Exp $ |
| 984263bc MD |
40 | * |
| 41 | * last edit-date: [Mon Dec 13 21:47:44 1999] | |
| 42 | * | |
| 43 | *---------------------------------------------------------------------------*/ | |
| 44 | ||
| 45 | #include "isdnd.h" | |
| 46 | ||
| 47 | #ifndef I4B_EXTERNAL_MONITOR | |
| 48 | ||
| 49 | /* | |
| 50 | * dummy version of routines needed by config file parser | |
| 51 | * (config files should be valid with and without external montioring | |
| 52 | * support compiled into the daemon) | |
| 53 | */ | |
| 54 | ||
| fe361e7d SW |
55 | void |
| 56 | monitor_clear_rights(void) | |
| 68da13b1 EN |
57 | { |
| 58 | } | |
| 984263bc | 59 | |
| fe361e7d SW |
60 | int |
| 61 | monitor_start_rights(const char *clientspec) | |
| 68da13b1 EN |
62 | { |
| 63 | return I4BMAR_OK; | |
| 64 | } | |
| 984263bc | 65 | |
| fe361e7d SW |
66 | void |
| 67 | monitor_add_rights(int rights_mask) | |
| 68da13b1 EN |
68 | { |
| 69 | } | |
| 984263bc | 70 | |
| fe361e7d SW |
71 | void |
| 72 | monitor_fixup_rights(void) | |
| 68da13b1 EN |
73 | { |
| 74 | } | |
| 984263bc MD |
75 | |
| 76 | #else | |
| 77 | ||
| 78 | #include "monitor.h" | |
| 79 | #include <sys/socket.h> | |
| 80 | #include <sys/un.h> | |
| 81 | #ifndef I4B_NOTCPIP_MONITOR | |
| 82 | #include <netinet/in.h> | |
| 83 | #include <arpa/inet.h> | |
| 84 | #include <netdb.h> | |
| 85 | #endif | |
| 86 | ||
| 87 | ||
| 88 | static TAILQ_HEAD(rights_q, monitor_rights) rights = TAILQ_HEAD_INITIALIZER(rights); | |
| 89 | ||
| 90 | static struct monitor_rights * local_rights = NULL; /* entry for local socket */ | |
| 91 | ||
| 92 | /* for each active monitor connection we have one of this: */ | |
| 93 | ||
| 94 | struct monitor_connection { | |
| 95 | TAILQ_ENTRY(monitor_connection) connections; | |
| 96 | int sock; /* socket for this connection */ | |
| 97 | int rights; /* active rights for this connection */ | |
| 98 | int events; /* bitmask of events client is interested in */ | |
| 99 | char source[FILENAME_MAX]; | |
| 100 | }; | |
| 101 | ||
| 102 | static TAILQ_HEAD(connections_tq, monitor_connection) connections = TAILQ_HEAD_INITIALIZER(connections); | |
| 103 | ||
| 104 | /* local prototypes */ | |
| 105 | static int cmp_rights(const struct monitor_rights *pa, const struct monitor_rights *pb); | |
| 106 | static int monitor_command(struct monitor_connection *con, int fd, int rights); | |
| 107 | static void cmd_dump_rights(int fd, int rights, u_int8_t *cmd, const char * source); | |
| 108 | static void cmd_dump_mcons(int fd, int rights, u_int8_t *cmd, const char * source); | |
| 109 | static void cmd_reread_cfg(int fd, int rights, u_int8_t *cmd, const char * source); | |
| 110 | static void cmd_hangup(int fd, int rights, u_int8_t *cmd, const char * source); | |
| 111 | static void monitor_broadcast(int mask, u_int8_t *pkt, size_t bytes); | |
| 112 | static int anybody(int mask); | |
| 113 | static void hangup_channel(int controller, int channel, const char *source); | |
| 114 | static ssize_t sock_read(int fd, void *buf, size_t nbytes); | |
| 115 | static ssize_t sock_write(int fd, void *buf, size_t nbytes); | |
| 116 | ||
| 117 | /* | |
| 118 | * Due to the way we structure config files, the rights for an external | |
| 119 | * monitor might be stated in multiple steps. First a call to | |
| 120 | * monitor_start_rights opens an entry. Further (optional) calls to | |
| 121 | * montior_add_rights assemble additional rights for this "current" | |
| 122 | * entry. When closing the sys-file section of the config file, the | |
| 123 | * "current" entry becomes invalid. | |
| 124 | */ | |
| 125 | static struct monitor_rights * cur_add_entry = NULL; | |
| 126 | ||
| 127 | /*--------------------------------------------------------------------------- | |
| 128 | * Initialize the monitor server module. This affects only active | |
| 129 | * connections, the access rights are not modified here! | |
| 130 | *---------------------------------------------------------------------------*/ | |
| 131 | void | |
| 132 | monitor_init(void) | |
| 133 | { | |
| 134 | struct monitor_connection * con; | |
| 135 | accepted = 0; | |
| 136 | while ((con = TAILQ_FIRST(&connections)) != NULL) | |
| 137 | { | |
| 138 | TAILQ_REMOVE(&connections, con, connections); | |
| 139 | free(con); | |
| 140 | } | |
| 141 | } | |
| 142 | ||
| 143 | /*--------------------------------------------------------------------------- | |
| 144 | * Prepare for exit | |
| 145 | *---------------------------------------------------------------------------*/ | |
| 146 | void | |
| 147 | monitor_exit(void) | |
| 148 | { | |
| 149 | struct monitor_connection *c; | |
| 150 | ||
| 151 | /* Close all open connections. */ | |
| 152 | while((c = TAILQ_FIRST(&connections)) != NULL) { | |
| 153 | close(c->sock); | |
| 154 | TAILQ_REMOVE(&connections, c, connections); | |
| 155 | free(c); | |
| 156 | } | |
| 157 | } | |
| 158 | ||
| 159 | /*--------------------------------------------------------------------------- | |
| 160 | * Initialize access rights. No active connections are affected! | |
| 161 | *---------------------------------------------------------------------------*/ | |
| 162 | void | |
| 163 | monitor_clear_rights(void) | |
| 164 | { | |
| 165 | struct monitor_rights *r; | |
| 166 | while ((r = TAILQ_FIRST(&rights)) != NULL) { | |
| 167 | TAILQ_REMOVE(&rights, r, list); | |
| 168 | free(r); | |
| 169 | } | |
| 170 | cur_add_entry = NULL; | |
| 171 | local_rights = NULL; | |
| 172 | } | |
| 173 | ||
| 174 | /*--------------------------------------------------------------------------- | |
| 175 | * Add an entry to the access lists. The clientspec either is | |
| 176 | * the name of the local socket or a host- or networkname or | |
| 177 | * numeric ip/host-bit-len spec. | |
| 178 | *---------------------------------------------------------------------------*/ | |
| 179 | int | |
| 180 | monitor_start_rights(const char *clientspec) | |
| 181 | { | |
| 182 | struct monitor_rights r; | |
| 183 | ||
| 184 | /* initialize the new rights entry */ | |
| 185 | ||
| 186 | memset(&r, 0, sizeof r); | |
| 187 | ||
| 188 | /* check clientspec */ | |
| 189 | ||
| 190 | if (*clientspec == '/') | |
| 191 | { | |
| 192 | struct sockaddr_un sa; | |
| 193 | ||
| 194 | /* this is a local socket spec, check if we already have one */ | |
| 195 | ||
| 196 | if (local_rights != NULL) | |
| 197 | return I4BMAR_DUP; | |
| 198 | ||
| 199 | /* does it fit in a local socket address? */ | |
| 200 | ||
| 201 | if (strlen(clientspec) > sizeof sa.sun_path) | |
| 202 | return I4BMAR_LENGTH; | |
| 203 | ||
| 204 | r.local = 1; | |
| 205 | strcpy(r.name, clientspec); | |
| 206 | ||
| 207 | #ifndef I4B_NOTCPIP_MONITOR | |
| 208 | ||
| 209 | } | |
| 210 | else | |
| 211 | { | |
| 212 | /* remote entry, parse host/net and cidr */ | |
| 213 | ||
| 214 | struct monitor_rights * rp; | |
| 215 | char hostname[FILENAME_MAX]; | |
| 216 | char *p; | |
| 217 | ||
| 218 | p = strchr(clientspec, '/'); | |
| 219 | ||
| 220 | if (!p) | |
| 221 | { | |
| 222 | struct hostent *host; | |
| 223 | u_int32_t hn; | |
| 224 | ||
| 225 | /* must be a host spec */ | |
| 226 | ||
| 227 | r.mask = ~0; | |
| 228 | host = gethostbyname(clientspec); | |
| 229 | ||
| 230 | if (!host) | |
| 231 | return I4BMAR_NOIP; | |
| 232 | ||
| 233 | memcpy(&hn, host->h_addr_list[0], sizeof hn); | |
| 234 | r.net = (u_int32_t)ntohl(hn); | |
| 235 | } | |
| 236 | else if(p[1]) | |
| 237 | { | |
| 238 | /* must be net/cidr spec */ | |
| 239 | ||
| 240 | int l; | |
| 241 | struct netent *net; | |
| 242 | u_int32_t s = ~0U; | |
| 243 | int num = strtol(p+1, NULL, 10); | |
| 244 | ||
| 245 | if (num < 0 || num > 32) | |
| 246 | return I4BMAR_CIDR; | |
| 247 | ||
| 248 | s >>= num; | |
| 249 | s ^= ~0U; | |
| 250 | l = p - clientspec; | |
| 251 | ||
| 252 | if (l >= sizeof hostname) | |
| 253 | return I4BMAR_LENGTH; | |
| 254 | ||
| 255 | strncpy(hostname, clientspec, l); | |
| 256 | ||
| 257 | hostname[l] = '\0'; | |
| 258 | ||
| 259 | net = getnetbyname(hostname); | |
| 260 | ||
| 261 | if (net == NULL) | |
| 262 | r.net = (u_int32_t)inet_network(hostname); | |
| 263 | else | |
| 264 | r.net = (u_int32_t)net->n_net; | |
| 265 | ||
| 266 | r.mask = s; | |
| 267 | r.net &= s; | |
| 268 | } | |
| 269 | else | |
| 270 | { | |
| 271 | return I4BMAR_CIDR; | |
| 272 | } | |
| 273 | ||
| 274 | /* check for duplicate entry */ | |
| 275 | ||
| 276 | for (rp = TAILQ_FIRST(&rights); rp != NULL; rp = TAILQ_NEXT(rp, list)) | |
| 277 | { | |
| 278 | if (rp->mask == r.mask && | |
| 279 | rp->net == r.net && | |
| 280 | rp->local == r.local) | |
| 281 | { | |
| 282 | return I4BMAR_DUP; | |
| 283 | } | |
| 284 | } | |
| 285 | #endif | |
| 286 | } | |
| 287 | ||
| 288 | r.rights = 0; | |
| 289 | ||
| 290 | /* entry ok, add it to the collection */ | |
| 291 | ||
| 292 | cur_add_entry = malloc(sizeof(r)); | |
| 293 | memcpy(cur_add_entry, &r, sizeof(r)); | |
| 294 | TAILQ_INSERT_TAIL(&rights, cur_add_entry, list); | |
| 295 | ||
| 296 | if(r.local) | |
| 297 | local_rights = cur_add_entry; | |
| 298 | ||
| 299 | DBGL(DL_RCCF, (log(LL_DBG, "system: monitor = %s", clientspec))); | |
| 300 | ||
| 301 | return I4BMAR_OK; | |
| 302 | } | |
| 303 | ||
| 304 | /*--------------------------------------------------------------------------- | |
| 305 | * Add rights to the currently constructed entry - if any. | |
| 306 | *---------------------------------------------------------------------------*/ | |
| 307 | void | |
| 308 | monitor_add_rights(int rights_mask) | |
| 309 | { | |
| 310 | if(cur_add_entry == NULL) | |
| 311 | return; /* noone under construction */ | |
| 312 | ||
| 313 | cur_add_entry->rights |= rights_mask; | |
| 314 | ||
| 315 | DBGL(DL_RCCF, (log(LL_DBG, "system: monitor-access = 0x%x", rights_mask))); | |
| 316 | } | |
| 317 | ||
| 318 | /*--------------------------------------------------------------------------- | |
| 319 | * All rights have been added now. Sort the to get most specific | |
| 320 | * host/net masks first, so we can travel the list and use the first | |
| 321 | * match for actual rights. | |
| 322 | *---------------------------------------------------------------------------*/ | |
| 323 | void | |
| 324 | monitor_fixup_rights(void) | |
| 325 | { | |
| 326 | struct monitor_rights * cur, * test, * next; | |
| 327 | ||
| 328 | /* no more rights may be added to the current entry */ | |
| 329 | ||
| 330 | cur_add_entry = NULL; | |
| 331 | ||
| 332 | /* sort the rights */ | |
| 333 | for (next = NULL, cur = TAILQ_FIRST(&rights); cur != NULL; cur = next) | |
| 334 | { | |
| 335 | next = TAILQ_NEXT(cur, list); | |
| 336 | for (test = TAILQ_FIRST(&rights); test != NULL && test != cur; test = TAILQ_NEXT(test, list)) | |
| 337 | { | |
| 338 | if (cmp_rights(cur, test) > 0) { | |
| 339 | /* move cur up the list and insert before test */ | |
| 340 | TAILQ_REMOVE(&rights, cur, list); | |
| 341 | if (test == TAILQ_FIRST(&rights)) | |
| 342 | TAILQ_INSERT_HEAD(&rights, cur, list); | |
| 343 | else | |
| 344 | TAILQ_INSERT_BEFORE(test, cur, list); | |
| 345 | break; | |
| 346 | } | |
| 347 | } | |
| 348 | } | |
| 349 | } | |
| 350 | ||
| 351 | /*--------------------------------------------------------------------------- | |
| 352 | * comparator for rights | |
| 353 | *---------------------------------------------------------------------------*/ | |
| 354 | static int | |
| 355 | cmp_rights(const struct monitor_rights *pa, const struct monitor_rights *pb) | |
| 356 | { | |
| 357 | u_int32_t mask; | |
| 358 | ||
| 359 | /* local sorts first */ | |
| 360 | ||
| 361 | if (pa->local) | |
| 362 | return -1; | |
| 363 | ||
| 364 | /* which is the less specific netmask? */ | |
| 365 | ||
| 366 | mask = pa->mask; | |
| 367 | ||
| 368 | if ((pb->mask & mask) == 0) | |
| 369 | mask = pb->mask; | |
| 370 | ||
| 371 | /* are the entries disjunct? */ | |
| 372 | ||
| 373 | if ((pa->net & mask) != (pb->net & mask)) | |
| 374 | { | |
| 375 | /* simply compare net part of address */ | |
| 376 | return ((pa->net & mask) < (pb->net & mask)) ? -1 : 1; | |
| 377 | } | |
| 378 | ||
| 379 | /* One entry is part of the others net. We already now "mask" is | |
| 380 | * the netmask of the less specific (i.e. greater) one */ | |
| 381 | ||
| 382 | return (pa->mask == mask) ? 1 : -1; | |
| 383 | } | |
| 384 | ||
| 385 | #ifndef I4B_NOTCPIP_MONITOR | |
| 386 | /*--------------------------------------------------------------------------- | |
| 387 | * Check if access rights for a remote socket are specified and | |
| 388 | * create this socket. Return -1 otherwise. | |
| 389 | *---------------------------------------------------------------------------*/ | |
| 390 | int | |
| 391 | monitor_create_remote_socket(int portno) | |
| 392 | { | |
| 393 | struct sockaddr_in sa; | |
| 394 | int val; | |
| 395 | int remotesockfd; | |
| 396 | ||
| 397 | remotesockfd = socket(AF_INET, SOCK_STREAM, 0); | |
| 398 | ||
| 399 | if(remotesockfd == -1) | |
| 400 | { | |
| 401 | log(LL_MER, "could not create remote monitor socket: %s", strerror(errno)); | |
| 402 | return(-1); | |
| 403 | } | |
| 404 | ||
| 405 | val = 1; | |
| 406 | ||
| 407 | if(setsockopt(remotesockfd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof val)) | |
| 408 | { | |
| 409 | log(LL_MER, "could not setsockopt: %s", strerror(errno)); | |
| 410 | return(-1); | |
| 411 | } | |
| 412 | ||
| 413 | memset(&sa, 0, sizeof sa); | |
| 414 | sa.sin_len = sizeof sa; | |
| 415 | sa.sin_family = AF_INET; | |
| 416 | sa.sin_port = htons(portno); | |
| 417 | sa.sin_addr.s_addr = htonl(INADDR_ANY); | |
| 418 | ||
| 419 | if(bind(remotesockfd, (struct sockaddr *)&sa, sizeof sa) == -1) | |
| 420 | { | |
| 421 | log(LL_MER, "could not bind remote monitor socket to port %d: %s", portno, strerror(errno)); | |
| 422 | return(-1); | |
| 423 | } | |
| 424 | ||
| 425 | if(listen(remotesockfd, 0)) | |
| 426 | { | |
| 427 | log(LL_MER, "could not listen on monitor socket: %s", strerror(errno)); | |
| 428 | return(-1); | |
| 429 | } | |
| 430 | ||
| 431 | return(remotesockfd); | |
| 432 | } | |
| 433 | #endif | |
| 434 | ||
| 435 | /*--------------------------------------------------------------------------- | |
| 436 | * Check if access rights for a local socket are specified and | |
| 437 | * create this socket. Return -1 otherwise. | |
| 438 | *---------------------------------------------------------------------------*/ | |
| 439 | int | |
| 440 | monitor_create_local_socket(void) | |
| 441 | { | |
| 442 | int s; | |
| 443 | struct sockaddr_un sa; | |
| 444 | ||
| 445 | /* check for a local entry */ | |
| 446 | ||
| 447 | if (local_rights == NULL) | |
| 448 | return(-1); | |
| 449 | ||
| 450 | /* create and setup socket */ | |
| 451 | ||
| 452 | s = socket(AF_LOCAL, SOCK_STREAM, 0); | |
| 453 | ||
| 454 | if (s == -1) | |
| 455 | { | |
| 456 | log(LL_MER, "could not create local monitor socket, errno = %d", errno); | |
| 457 | return(-1); | |
| 458 | } | |
| 459 | ||
| 460 | unlink(local_rights->name); | |
| 461 | ||
| 462 | memset(&sa, 0, sizeof sa); | |
| 463 | sa.sun_len = sizeof sa; | |
| 464 | sa.sun_family = AF_LOCAL; | |
| 465 | strcpy(sa.sun_path, local_rights->name); | |
| 466 | ||
| 467 | if (bind(s, (struct sockaddr *)&sa, SUN_LEN(&sa))) | |
| 468 | { | |
| 469 | log(LL_MER, "could not bind local monitor socket [%s], errno = %d", local_rights->name, errno); | |
| 470 | return(-1); | |
| 471 | } | |
| 472 | ||
| 473 | chmod(local_rights->name, 0500); | |
| 474 | ||
| 475 | if (listen(s, 0)) | |
| 476 | { | |
| 477 | log(LL_MER, "could not listen on local monitor socket, errno = %d", errno); | |
| 478 | return(-1); | |
| 479 | } | |
| 480 | ||
| 481 | return(s); | |
| 482 | } | |
| 483 | ||
| 484 | /*--------------------------------------------------------------------------- | |
| 485 | * Prepare a fd_set for a select call. Add all our local | |
| 486 | * filedescriptors to the set, increment max_fd if appropriate. | |
| 487 | *---------------------------------------------------------------------------*/ | |
| 488 | void | |
| 489 | monitor_prepselect(fd_set *selset, int *max_fd) | |
| 490 | { | |
| 491 | struct monitor_connection * con; | |
| 492 | ||
| 493 | for (con = TAILQ_FIRST(&connections); con != NULL; con = TAILQ_NEXT(con, connections)) | |
| 494 | { | |
| 495 | int fd = con->sock; | |
| 496 | ||
| 497 | if (fd > *max_fd) | |
| 498 | *max_fd = fd; | |
| 499 | ||
| 500 | FD_SET(fd, selset); | |
| 501 | } | |
| 502 | } | |
| 503 | ||
| 504 | /*--------------------------------------------------------------------------- | |
| 505 | * Check if the result from a select call indicates something | |
| 506 | * to do for us. | |
| 507 | *---------------------------------------------------------------------------*/ | |
| 508 | void | |
| 509 | monitor_handle_input(fd_set *selset) | |
| 510 | { | |
| 511 | struct monitor_connection * con, * next; | |
| 512 | ||
| 513 | for (next = NULL, con = TAILQ_FIRST(&connections); con != NULL; con = next) | |
| 514 | { | |
| 515 | int fd = con->sock; | |
| 516 | next = TAILQ_NEXT(con, connections); | |
| 517 | ||
| 518 | if (FD_ISSET(fd, selset)) | |
| 519 | { | |
| 520 | /* handle command from this client */ | |
| 521 | ||
| 522 | if (monitor_command(con, fd, con->rights) != 0) | |
| 523 | { | |
| 524 | /* broken or closed connection */ | |
| 525 | ||
| 526 | char source[FILENAME_MAX]; | |
| 527 | ||
| 528 | strcpy(source, con->source); | |
| 529 | TAILQ_REMOVE(&connections, con, connections); | |
| 530 | free(con); | |
| 531 | log(LL_DMN, "monitor closed from %s", source ); | |
| 532 | } | |
| 533 | } | |
| 534 | } | |
| 535 | ||
| 536 | /* all connections gone? */ | |
| 537 | ||
| 538 | if (TAILQ_FIRST(&connections) == NULL) | |
| 539 | accepted = 0; | |
| 540 | } | |
| 541 | ||
| 542 | /*--------------------------------------------------------------------------- | |
| 543 | * Try new incoming connection on the given socket. | |
| 544 | * Setup client descriptor and send initial data. | |
| 545 | *---------------------------------------------------------------------------*/ | |
| 546 | void | |
| 547 | monitor_handle_connect(int sockfd, int is_local) | |
| 548 | { | |
| 549 | struct monitor_connection *con; | |
| 550 | struct monitor_rights *rp; | |
| 551 | ||
| 552 | #ifndef I4B_NOTCPIP_MONITOR | |
| 553 | struct sockaddr_in ia; | |
| 554 | u_int32_t ha = 0; | |
| 555 | #endif | |
| 556 | ||
| 557 | struct sockaddr_un ua; | |
| 558 | u_int8_t idata[I4B_MON_IDATA_SIZE]; | |
| 559 | int fd = -1, s, i, r_mask, t_events; | |
| 560 | char source[FILENAME_MAX]; | |
| 561 | ||
| 562 | /* accept the connection */ | |
| 563 | ||
| 564 | if(is_local) | |
| 565 | { | |
| 566 | s = sizeof ua; | |
| 567 | fd = accept(sockfd, (struct sockaddr *)&ua, &s); | |
| 568 | strcpy(source, "local"); | |
| 569 | ||
| 570 | #ifndef I4B_NOTCPIP_MONITOR | |
| 571 | } | |
| 572 | else | |
| 573 | { | |
| 574 | struct hostent *hp; | |
| 575 | ||
| 576 | s = sizeof ia; | |
| 577 | fd = accept(sockfd, (struct sockaddr *)&ia, &s); | |
| 578 | ||
| 15b85273 | 579 | hp = gethostbyaddr(&ia.sin_addr, 4, AF_INET); |
| 984263bc MD |
580 | |
| 581 | if(hp == NULL) | |
| 582 | snprintf(source, sizeof source, "%s (%s)", inet_ntoa(ia.sin_addr), inet_ntoa(ia.sin_addr)); | |
| 583 | else | |
| 584 | snprintf(source, sizeof source, "%s (%s)", hp->h_name, inet_ntoa(ia.sin_addr)); | |
| 585 | ||
| 586 | memcpy(&ha, &ia.sin_addr.s_addr, sizeof ha); | |
| 587 | ||
| 588 | ha = ntohl(ha); | |
| 589 | #endif | |
| 590 | } | |
| 591 | ||
| 592 | /* check the access rights of this connection */ | |
| 593 | ||
| 594 | r_mask = 0; | |
| 595 | ||
| 596 | for (rp = TAILQ_FIRST(&rights); rp != NULL; rp = TAILQ_NEXT(rp, list)) | |
| 597 | { | |
| 598 | if(rp->local) | |
| 599 | { | |
| 600 | if(is_local) | |
| 601 | { | |
| 602 | r_mask = rp->rights; | |
| 603 | break; | |
| 604 | } | |
| 605 | ||
| 606 | #ifndef I4B_NOTCPIP_MONITOR | |
| 607 | } | |
| 608 | else | |
| 609 | { | |
| 610 | if((ha & rp->mask) == rp->net) | |
| 611 | { | |
| 612 | r_mask = rp->rights; | |
| 613 | break; | |
| 614 | } | |
| 615 | #endif | |
| 616 | } | |
| 617 | } | |
| 618 | ||
| 619 | if(r_mask == 0) | |
| 620 | { | |
| 621 | /* no rights - go away */ | |
| 622 | log(LL_MER, "monitor access denied from %s", source); | |
| 623 | close(fd); | |
| 624 | return; | |
| 625 | } | |
| 626 | ||
| 627 | accepted = 1; | |
| 628 | ||
| 629 | con = malloc(sizeof(struct monitor_connection)); | |
| 630 | memset(con, 0, sizeof *con); | |
| 631 | TAILQ_INSERT_TAIL(&connections, con, connections); | |
| 632 | con->sock = fd; | |
| 633 | con->rights = r_mask; | |
| 634 | strcpy(con->source, source); | |
| 635 | ||
| 636 | log(LL_DMN, "monitor opened from %s rights 0x%x", source, r_mask); | |
| 637 | ||
| 638 | /* send initial data */ | |
| 639 | I4B_PREP_CMD(idata, I4B_MON_IDATA_CODE); | |
| 640 | I4B_PUT_2B(idata, I4B_MON_IDATA_VERSMAJOR, MPROT_VERSION); | |
| 641 | I4B_PUT_2B(idata, I4B_MON_IDATA_VERSMINOR, MPROT_REL); | |
| 642 | I4B_PUT_2B(idata, I4B_MON_IDATA_NUMCTRL, ncontroller); | |
| 643 | I4B_PUT_2B(idata, I4B_MON_IDATA_NUMENTR, nentries); | |
| 644 | I4B_PUT_4B(idata, I4B_MON_IDATA_CLACCESS, r_mask); | |
| 645 | ||
| 646 | if((sock_write(fd, idata, sizeof idata)) == -1) | |
| 647 | { | |
| 648 | log(LL_MER, "monitor_handle_connect: sock_write 1 error - %s", strerror(errno)); | |
| 649 | } | |
| 650 | ||
| 651 | for (i = 0; i < ncontroller; i++) | |
| 652 | { | |
| 653 | u_int8_t ictrl[I4B_MON_ICTRL_SIZE]; | |
| 654 | ||
| 655 | I4B_PREP_CMD(ictrl, I4B_MON_ICTRL_CODE); | |
| 656 | I4B_PUT_STR(ictrl, I4B_MON_ICTRL_NAME, name_of_controller(isdn_ctrl_tab[i].ctrl_type, isdn_ctrl_tab[i].card_type)); | |
| 657 | I4B_PUT_2B(ictrl, I4B_MON_ICTRL_BUSID, 0); | |
| 658 | I4B_PUT_4B(ictrl, I4B_MON_ICTRL_FLAGS, 0); | |
| 659 | I4B_PUT_4B(ictrl, I4B_MON_ICTRL_NCHAN, 2); | |
| 660 | ||
| 661 | if((sock_write(fd, ictrl, sizeof ictrl)) == -1) | |
| 662 | { | |
| 663 | log(LL_MER, "monitor_handle_connect: sock_write 2 error - %s", strerror(errno)); | |
| 664 | } | |
| 665 | ||
| 666 | } | |
| 667 | ||
| 668 | /* send device names from entries */ | |
| 669 | ||
| 670 | for(i=0; i < nentries; i++) /* walk thru all entries */ | |
| 671 | { | |
| 672 | u_int8_t ictrl[I4B_MON_IDEV_SIZE]; | |
| 673 | cfg_entry_t *p; | |
| 674 | char nbuf[64]; | |
| 675 | p = &cfg_entry_tab[i]; /* get ptr to enry */ | |
| 676 | ||
| 677 | snprintf(nbuf, sizeof(nbuf), "%s%d ", bdrivername(p->usrdevicename), p->usrdeviceunit); | |
| 678 | ||
| 679 | I4B_PREP_CMD(ictrl, I4B_MON_IDEV_CODE); | |
| 680 | /*XXX*/ I4B_PUT_2B(ictrl, I4B_MON_IDEV_STATE, 1); | |
| 681 | I4B_PUT_STR(ictrl, I4B_MON_IDEV_NAME, nbuf); | |
| 682 | ||
| 683 | if((sock_write(fd, ictrl, sizeof ictrl)) == -1) | |
| 684 | { | |
| 685 | log(LL_MER, "monitor_handle_connect: sock_write 3 error - %s", strerror(errno)); | |
| 686 | } | |
| 687 | } | |
| 688 | ||
| 689 | /*XXX*/ t_events = con->events; | |
| 690 | /*XXX*/ con->events = -1; | |
| 691 | ||
| 692 | /* current state of controller(s) */ | |
| 693 | ||
| 694 | for(i=0; i < ncontroller; i++) | |
| 695 | { | |
| 696 | monitor_evnt_tei(i, isdn_ctrl_tab[i].tei); | |
| 697 | monitor_evnt_l12stat(i, LAYER_ONE, isdn_ctrl_tab[i].l1stat); | |
| 698 | monitor_evnt_l12stat(i, LAYER_TWO, isdn_ctrl_tab[i].l2stat); | |
| 699 | } | |
| 700 | ||
| 701 | /* current state of entries */ | |
| 702 | ||
| 703 | for(i=0; i < nentries; i++) | |
| 704 | { | |
| 705 | cfg_entry_t *cep = &cfg_entry_tab[i]; | |
| 706 | ||
| 707 | if(cep->state == ST_CONNECTED) | |
| 708 | { | |
| 709 | monitor_evnt_connect(cep); | |
| 710 | monitor_evnt_acct(cep); | |
| 711 | monitor_evnt_charge(cep, cep->charge, 1); | |
| 712 | } | |
| 713 | } | |
| 714 | ||
| 715 | /*XXX*/ con->events = t_events; | |
| 716 | ||
| 717 | } | |
| 718 | ||
| 719 | /*--------------------------------------------------------------------------- | |
| 720 | * dump all monitor rights | |
| 721 | *---------------------------------------------------------------------------*/ | |
| 722 | static void | |
| 723 | cmd_dump_rights(int fd, int r_mask, u_int8_t *cmd, const char *source) | |
| 724 | { | |
| 725 | struct monitor_rights * r; | |
| 726 | int num_rights; | |
| 727 | u_int8_t drini[I4B_MON_DRINI_SIZE]; | |
| 728 | u_int8_t dr[I4B_MON_DR_SIZE]; | |
| 729 | ||
| 730 | for (num_rights = 0, r = TAILQ_FIRST(&rights); r != NULL; r = TAILQ_NEXT(r, list)) | |
| 731 | num_rights++; | |
| 732 | ||
| 733 | I4B_PREP_EVNT(drini, I4B_MON_DRINI_CODE); | |
| 734 | I4B_PUT_2B(drini, I4B_MON_DRINI_COUNT, num_rights); | |
| 735 | ||
| 736 | if((sock_write(fd, drini, sizeof drini)) == -1) | |
| 737 | { | |
| 738 | log(LL_MER, "cmd_dump_rights: sock_write 1 error - %s", strerror(errno)); | |
| 739 | } | |
| 740 | ||
| 741 | for (r = TAILQ_FIRST(&rights); r != NULL; r = TAILQ_NEXT(r, list)) | |
| 742 | { | |
| 743 | I4B_PREP_EVNT(dr, I4B_MON_DR_CODE); | |
| 744 | I4B_PUT_4B(dr, I4B_MON_DR_RIGHTS, r->rights); | |
| 745 | I4B_PUT_4B(dr, I4B_MON_DR_NET, r->net); | |
| 746 | I4B_PUT_4B(dr, I4B_MON_DR_MASK, r->mask); | |
| 747 | I4B_PUT_1B(dr, I4B_MON_DR_LOCAL, r->local); | |
| 748 | if((sock_write(fd, dr, sizeof dr)) == -1) | |
| 749 | { | |
| 750 | log(LL_MER, "cmd_dump_rights: sock_write 2 error - %s", strerror(errno)); | |
| 751 | } | |
| 752 | } | |
| 753 | } | |
| 754 | ||
| 755 | /*--------------------------------------------------------------------------- | |
| 756 | * rescan config file | |
| 757 | *---------------------------------------------------------------------------*/ | |
| 758 | static void | |
| 759 | cmd_reread_cfg(int fd, int rights, u_int8_t *cmd, const char * source) | |
| 760 | { | |
| 761 | rereadconfig(42); | |
| 762 | } | |
| 763 | ||
| 764 | /*--------------------------------------------------------------------------- | |
| 765 | * drop one connection | |
| 766 | *---------------------------------------------------------------------------*/ | |
| 767 | static void | |
| 768 | cmd_hangup(int fd, int rights, u_int8_t *cmd, const char * source) | |
| 769 | { | |
| 770 | int channel = I4B_GET_4B(cmd, I4B_MON_HANGUP_CHANNEL); | |
| 771 | int ctrl = I4B_GET_4B(cmd, I4B_MON_HANGUP_CTRL); | |
| 772 | ||
| 773 | hangup_channel(ctrl, channel, source); | |
| 774 | } | |
| 775 | ||
| 776 | /*--------------------------------------------------------------------------- | |
| 777 | * dump all active monitor connections | |
| 778 | *---------------------------------------------------------------------------*/ | |
| 779 | static void | |
| 780 | cmd_dump_mcons(int fd, int rights, u_int8_t *cmd, const char * source) | |
| 781 | { | |
| 782 | int num_connections; | |
| 783 | struct monitor_connection *con; | |
| 784 | u_int8_t dcini[I4B_MON_DCINI_SIZE]; | |
| 785 | ||
| 786 | for (num_connections = 0, con = TAILQ_FIRST(&connections); con != NULL; con = TAILQ_NEXT(con, connections)) | |
| 787 | num_connections++; | |
| 788 | ||
| 789 | I4B_PREP_EVNT(dcini, I4B_MON_DCINI_CODE); | |
| 790 | I4B_PUT_2B(dcini, I4B_MON_DCINI_COUNT, num_connections); | |
| 791 | ||
| 792 | if((sock_write(fd, dcini, sizeof dcini)) == -1) | |
| 793 | { | |
| 794 | log(LL_MER, "cmd_dump_mcons: sock_write 1 error - %s", strerror(errno)); | |
| 795 | } | |
| 796 | ||
| 797 | for (con = TAILQ_FIRST(&connections); con != NULL; con = TAILQ_NEXT(con, connections)) | |
| 798 | { | |
| 799 | #ifndef I4B_NOTCPIP_MONITOR | |
| 800 | int namelen; | |
| 801 | struct sockaddr_in name; | |
| 802 | #endif | |
| 803 | u_int8_t dc[I4B_MON_DC_SIZE]; | |
| 804 | ||
| 805 | I4B_PREP_EVNT(dc, I4B_MON_DC_CODE); | |
| 806 | I4B_PUT_4B(dc, I4B_MON_DC_RIGHTS, con->rights); | |
| 807 | ||
| 808 | #ifndef I4B_NOTCPIP_MONITOR | |
| 809 | namelen = sizeof name; | |
| 810 | ||
| 811 | if (getpeername(con->sock, (struct sockaddr*)&name, &namelen) == 0) | |
| 812 | memcpy(dc+I4B_MON_DC_WHO, &name.sin_addr, sizeof name.sin_addr); | |
| 813 | #endif | |
| 814 | if((sock_write(fd, dc, sizeof dc)) == -1) | |
| 815 | { | |
| 816 | log(LL_MER, "cmd_dump_mcons: sock_write 2 error - %s", strerror(errno)); | |
| 817 | } | |
| 818 | } | |
| 819 | } | |
| 820 | ||
| 821 | /*--------------------------------------------------------------------------- | |
| 822 | * Handle a command from the given socket. The client | |
| 823 | * has rights as specified in the rights parameter. | |
| 824 | * Return non-zero if connection is closed. | |
| 825 | *---------------------------------------------------------------------------*/ | |
| 826 | static int | |
| 827 | monitor_command(struct monitor_connection * con, int fd, int rights) | |
| 828 | { | |
| 829 | char cmd[I4B_MAX_MON_CLIENT_CMD]; | |
| 830 | u_int code; | |
| 831 | ||
| 832 | /* command dispatch table */ | |
| 833 | typedef void (*cmd_func_t)(int fd, int rights, u_int8_t *cmd, const char *source); | |
| 834 | ||
| 835 | static struct { | |
| 836 | cmd_func_t call; /* function to execute */ | |
| 837 | u_int rights; /* necessary rights */ | |
| 838 | } cmd_tab[] = | |
| 839 | { | |
| 840 | /* 0 */ { NULL, 0 }, | |
| 841 | /* 1 */ { cmd_dump_rights, I4B_CA_COMMAND_FULL }, | |
| 842 | /* 2 */ { cmd_dump_mcons, I4B_CA_COMMAND_FULL }, | |
| 843 | /* 3 */ { cmd_reread_cfg, I4B_CA_COMMAND_FULL }, | |
| 844 | /* 4 */ { cmd_hangup, I4B_CA_COMMAND_FULL }, | |
| 845 | }; | |
| 846 | #define NUMCMD (sizeof cmd_tab / sizeof cmd_tab[0]) | |
| 847 | ||
| 848 | u_long u; | |
| 849 | int bytes; | |
| 850 | ||
| 851 | /* Network transfer may deliver two or more packets concatenated. | |
| 852 | * Peek at the header and read only one event at a time... */ | |
| 853 | ||
| 854 | ioctl(fd, FIONREAD, &u); | |
| 855 | ||
| 856 | if (u < I4B_MON_CMD_HDR) | |
| 857 | { | |
| 858 | if (u == 0) | |
| 859 | { | |
| 860 | /* log(LL_MER, "monitor read 0 bytes"); */ | |
| 861 | /* socket closed by peer */ | |
| 862 | close(fd); | |
| 863 | return 1; | |
| 864 | } | |
| 865 | return 0; /* not enough data there yet */ | |
| 866 | } | |
| 867 | ||
| 868 | bytes = recv(fd, cmd, I4B_MON_CMD_HDR, MSG_PEEK); | |
| 869 | ||
| 870 | if (bytes < I4B_MON_CMD_HDR) | |
| 871 | { | |
| 872 | log(LL_MER, "monitor read only %d bytes", bytes); | |
| 873 | return 0; /* errh? something must be wrong... */ | |
| 874 | } | |
| 875 | ||
| 876 | bytes = I4B_GET_2B(cmd, I4B_MON_CMD_LEN); | |
| 877 | ||
| 878 | if (bytes >= sizeof cmd) | |
| 879 | { | |
| 880 | close(fd); | |
| 881 | log(LL_MER, "monitor: garbage on connection"); | |
| 882 | return 1; | |
| 883 | } | |
| 884 | ||
| 885 | /* now we know the size, it fits, so lets read it! */ | |
| 886 | ||
| 887 | if(sock_read(fd, cmd, bytes) <= 0) | |
| 888 | { | |
| 889 | log(LL_MER, "monitor: sock_read <= 0"); | |
| 890 | close(fd); | |
| 891 | return 1; | |
| 892 | } | |
| 893 | ||
| 894 | /* decode command */ | |
| 895 | code = I4B_GET_2B(cmd, I4B_MON_CMD); | |
| 896 | ||
| 897 | /* special case: may modify our connection descriptor, is | |
| 898 | * beyound all rights checks */ | |
| 899 | ||
| 900 | if (code == I4B_MON_CCMD_SETMASK) | |
| 901 | { | |
| 902 | /*XXX*/ | |
| 903 | /* | |
| 904 | u_int major = I4B_GET_2B(cmd, I4B_MON_ICLIENT_VERMAJOR); | |
| 905 | u_int minor = I4B_GET_2B(cmd, I4B_MON_ICLIENT_VERMINOR); | |
| 906 | */ | |
| 907 | ||
| 908 | int events = I4B_GET_4B(cmd, I4B_MON_ICLIENT_EVENTS); | |
| 909 | con->events = events & rights; | |
| 910 | return 0; | |
| 911 | } | |
| 912 | ||
| 913 | if (code < 0 || code >= NUMCMD) | |
| 914 | { | |
| 915 | log(LL_MER, "illegal command from client, code = %d\n", | |
| 916 | code); | |
| 917 | return 0; | |
| 918 | } | |
| 919 | ||
| 920 | if (cmd_tab[code].call == NULL) | |
| 921 | return 0; | |
| 922 | ||
| 923 | if ((cmd_tab[code].rights & rights) == cmd_tab[code].rights) | |
| 924 | cmd_tab[code].call(fd, rights, cmd, con->source); | |
| 925 | ||
| 926 | return 0; | |
| 927 | } | |
| 928 | ||
| 929 | /*--------------------------------------------------------------------------- | |
| 930 | * Check if somebody would receive an event with this mask. | |
| 931 | * We are lazy and try to avoid assembling unneccesary packets. | |
| 932 | * Return 0 if no one interested, nonzero otherwise. | |
| 933 | *---------------------------------------------------------------------------*/ | |
| 934 | static int | |
| 935 | anybody(int mask) | |
| 936 | { | |
| 937 | struct monitor_connection * con; | |
| 938 | ||
| 939 | for (con = TAILQ_FIRST(&connections); con != NULL; con = TAILQ_NEXT(con, connections)) | |
| 940 | { | |
| 941 | if ((con->events & mask) == mask) | |
| 942 | return 1; | |
| 943 | } | |
| 944 | return 0; | |
| 945 | } | |
| 946 | ||
| 947 | /*--------------------------------------------------------------------------- | |
| 948 | * exec hangup command | |
| 949 | *---------------------------------------------------------------------------*/ | |
| 950 | static void | |
| 951 | hangup_channel(int controller, int channel, const char *source) | |
| 952 | { | |
| 953 | cfg_entry_t * cep = NULL; | |
| 954 | int i; | |
| 955 | ||
| 956 | if(controller < ncontroller) | |
| 957 | { | |
| 958 | if(isdn_ctrl_tab[controller].state != CTRL_UP) | |
| 959 | return; | |
| 960 | for (i = 0; i < isdn_ctrl_tab[controller].nbch; i++) | |
| 961 | { | |
| 962 | if(isdn_ctrl_tab[controller].stateb[i] != CHAN_IDLE) | |
| 963 | { | |
| 964 | cep = get_cep_by_cc(controller, i); | |
| 965 | if (cep != NULL && cep->isdnchannelused == channel && | |
| 966 | cep->isdncontrollerused == controller) | |
| 967 | goto found; | |
| 968 | } | |
| 969 | } | |
| 970 | } | |
| 971 | /* not found */ | |
| 972 | return; | |
| 973 | ||
| 974 | found: | |
| 975 | log(LL_CHD, "%05d %s manual disconnect (remote from %s)", cep->cdid, cep->name, source); | |
| 976 | cep->hangup = 1; | |
| 977 | return; | |
| 978 | } | |
| 979 | ||
| 980 | /*--------------------------------------------------------------------------- | |
| 981 | * Send an event to every connection interested in this kind of | |
| 982 | * event | |
| 983 | *---------------------------------------------------------------------------*/ | |
| 984 | static void | |
| 985 | monitor_broadcast(int mask, u_int8_t *pkt, size_t bytes) | |
| 986 | { | |
| 987 | struct monitor_connection *con; | |
| 988 | ||
| 989 | for (con = TAILQ_FIRST(&connections); con != NULL; con = TAILQ_NEXT(con, connections)) | |
| 990 | { | |
| 991 | if ((con->events & mask) == mask) | |
| 992 | { | |
| 993 | int fd = con->sock; | |
| 994 | ||
| 995 | if((sock_write(fd, pkt, bytes)) == -1) | |
| 996 | { | |
| 997 | log(LL_MER, "monitor_broadcast: sock_write error - %s", strerror(errno)); | |
| 998 | } | |
| 999 | } | |
| 1000 | } | |
| 1001 | } | |
| 1002 | ||
| 1003 | /*--------------------------------------------------------------------------- | |
| 1004 | * Post a logfile event | |
| 1005 | *---------------------------------------------------------------------------*/ | |
| 1006 | void | |
| 1007 | monitor_evnt_log(int prio, const char * what, const char * msg) | |
| 1008 | { | |
| 1009 | u_int8_t evnt[I4B_MON_LOGEVNT_SIZE]; | |
| 1010 | time_t now; | |
| 1011 | ||
| 1012 | if (!anybody(I4B_CA_EVNT_I4B)) | |
| 1013 | return; | |
| 1014 | ||
| 1015 | time(&now); | |
| 1016 | ||
| 1017 | I4B_PREP_EVNT(evnt, I4B_MON_LOGEVNT_CODE); | |
| 1018 | I4B_PUT_4B(evnt, I4B_MON_LOGEVNT_TSTAMP, (long)now); | |
| 1019 | I4B_PUT_4B(evnt, I4B_MON_LOGEVNT_PRIO, prio); | |
| 1020 | I4B_PUT_STR(evnt, I4B_MON_LOGEVNT_WHAT, what); | |
| 1021 | I4B_PUT_STR(evnt, I4B_MON_LOGEVNT_MSG, msg); | |
| 1022 | ||
| 1023 | monitor_broadcast(I4B_CA_EVNT_I4B, evnt, sizeof evnt); | |
| 1024 | } | |
| 1025 | ||
| 1026 | /*--------------------------------------------------------------------------- | |
| 1027 | * Post a charging event on the connection described | |
| 1028 | * by the given config entry. | |
| 1029 | *---------------------------------------------------------------------------*/ | |
| 1030 | void | |
| 1031 | monitor_evnt_charge(cfg_entry_t *cep, int units, int estimate) | |
| 1032 | { | |
| 1033 | int mask; | |
| 1034 | time_t now; | |
| 1035 | u_int8_t evnt[I4B_MON_CHRG_SIZE]; | |
| 1036 | ||
| 1037 | mask = (cep->direction == DIR_IN) ? I4B_CA_EVNT_CALLIN : I4B_CA_EVNT_CALLOUT; | |
| 1038 | ||
| 1039 | if(!anybody(mask)) | |
| 1040 | return; | |
| 1041 | ||
| 1042 | time(&now); | |
| 1043 | ||
| 1044 | I4B_PREP_EVNT(evnt, I4B_MON_CHRG_CODE); | |
| 1045 | I4B_PUT_4B(evnt, I4B_MON_CHRG_TSTAMP, (long)now); | |
| 1046 | I4B_PUT_4B(evnt, I4B_MON_CHRG_CTRL, cep->isdncontrollerused); | |
| 1047 | I4B_PUT_4B(evnt, I4B_MON_CHRG_CHANNEL, cep->isdnchannelused); | |
| 1048 | I4B_PUT_4B(evnt, I4B_MON_CHRG_UNITS, units); | |
| 1049 | I4B_PUT_4B(evnt, I4B_MON_CHRG_ESTIMATED, estimate ? 1 : 0); | |
| 1050 | ||
| 1051 | monitor_broadcast(mask, evnt, sizeof evnt); | |
| 1052 | } | |
| 1053 | ||
| 1054 | /*--------------------------------------------------------------------------- | |
| 1055 | * Post a connection event | |
| 1056 | *---------------------------------------------------------------------------*/ | |
| 1057 | void | |
| 1058 | monitor_evnt_connect(cfg_entry_t *cep) | |
| 1059 | { | |
| 1060 | u_int8_t evnt[I4B_MON_CONNECT_SIZE]; | |
| 1061 | char devname[I4B_MAX_MON_STRING]; | |
| 1062 | int mask; | |
| 1063 | time_t now; | |
| 1064 | ||
| 1065 | mask = (cep->direction == DIR_IN) ? I4B_CA_EVNT_CALLIN : I4B_CA_EVNT_CALLOUT; | |
| 1066 | ||
| 1067 | if (!anybody(mask)) | |
| 1068 | return; | |
| 1069 | ||
| 1070 | time(&now); | |
| 1071 | ||
| 1072 | snprintf(devname, sizeof devname, "%s%d", bdrivername(cep->usrdevicename), cep->usrdeviceunit); | |
| 1073 | ||
| 1074 | I4B_PREP_EVNT(evnt, I4B_MON_CONNECT_CODE); | |
| 1075 | I4B_PUT_4B(evnt, I4B_MON_CONNECT_TSTAMP, (long)now); | |
| 1076 | I4B_PUT_4B(evnt, I4B_MON_CONNECT_DIR, cep->direction == DIR_OUT ? 1 : 0); | |
| 1077 | I4B_PUT_4B(evnt, I4B_MON_CONNECT_CTRL, cep->isdncontrollerused); | |
| 1078 | I4B_PUT_4B(evnt, I4B_MON_CONNECT_CHANNEL, cep->isdnchannelused); | |
| 1079 | I4B_PUT_STR(evnt, I4B_MON_CONNECT_CFGNAME, cep->name); | |
| 1080 | I4B_PUT_STR(evnt, I4B_MON_CONNECT_DEVNAME, devname); | |
| 1081 | ||
| 1082 | if(cep->direction == DIR_OUT) | |
| 1083 | { | |
| 1084 | I4B_PUT_STR(evnt, I4B_MON_CONNECT_REMPHONE, cep->remote_phone_dialout); | |
| 1085 | I4B_PUT_STR(evnt, I4B_MON_CONNECT_LOCPHONE, cep->local_phone_dialout); | |
| 1086 | } | |
| 1087 | else | |
| 1088 | { | |
| 1089 | I4B_PUT_STR(evnt, I4B_MON_CONNECT_REMPHONE, cep->real_phone_incoming); | |
| 1090 | I4B_PUT_STR(evnt, I4B_MON_CONNECT_LOCPHONE, cep->local_phone_incoming); | |
| 1091 | } | |
| 1092 | monitor_broadcast(mask, evnt, sizeof evnt); | |
| 1093 | } | |
| 1094 | ||
| 1095 | /*--------------------------------------------------------------------------- | |
| 1096 | * Post a disconnect event | |
| 1097 | *---------------------------------------------------------------------------*/ | |
| 1098 | void | |
| 1099 | monitor_evnt_disconnect(cfg_entry_t *cep) | |
| 1100 | { | |
| 1101 | u_int8_t evnt[I4B_MON_DISCONNECT_SIZE]; | |
| 1102 | int mask; | |
| 1103 | time_t now; | |
| 1104 | ||
| 1105 | mask = (cep->direction == DIR_IN) ? I4B_CA_EVNT_CALLIN : I4B_CA_EVNT_CALLOUT; | |
| 1106 | ||
| 1107 | if (!anybody(mask)) | |
| 1108 | return; | |
| 1109 | ||
| 1110 | time(&now); | |
| 1111 | ||
| 1112 | I4B_PREP_EVNT(evnt, I4B_MON_DISCONNECT_CODE); | |
| 1113 | I4B_PUT_4B(evnt, I4B_MON_DISCONNECT_TSTAMP, (long)now); | |
| 1114 | I4B_PUT_4B(evnt, I4B_MON_DISCONNECT_CTRL, cep->isdncontrollerused); | |
| 1115 | I4B_PUT_4B(evnt, I4B_MON_DISCONNECT_CHANNEL, cep->isdnchannelused); | |
| 1116 | ||
| 1117 | monitor_broadcast(mask, evnt, sizeof evnt); | |
| 1118 | } | |
| 1119 | ||
| 1120 | /*--------------------------------------------------------------------------- | |
| 1121 | * Post an up/down event | |
| 1122 | *---------------------------------------------------------------------------*/ | |
| 1123 | void | |
| 1124 | monitor_evnt_updown(cfg_entry_t *cep, int up) | |
| 1125 | { | |
| 1126 | u_int8_t evnt[I4B_MON_UPDOWN_SIZE]; | |
| 1127 | int mask; | |
| 1128 | time_t now; | |
| 1129 | ||
| 1130 | mask = (cep->direction == DIR_IN) ? I4B_CA_EVNT_CALLIN : I4B_CA_EVNT_CALLOUT; | |
| 1131 | ||
| 1132 | if (!anybody(mask)) | |
| 1133 | return; | |
| 1134 | ||
| 1135 | time(&now); | |
| 1136 | ||
| 1137 | I4B_PREP_EVNT(evnt, I4B_MON_UPDOWN_CODE); | |
| 1138 | I4B_PUT_4B(evnt, I4B_MON_UPDOWN_TSTAMP, (long)now); | |
| 1139 | I4B_PUT_4B(evnt, I4B_MON_UPDOWN_CTRL, cep->isdncontrollerused); | |
| 1140 | I4B_PUT_4B(evnt, I4B_MON_UPDOWN_CHANNEL, cep->isdnchannelused); | |
| 1141 | I4B_PUT_4B(evnt, I4B_MON_UPDOWN_ISUP, up); | |
| 1142 | ||
| 1143 | monitor_broadcast(mask, evnt, sizeof evnt); | |
| 1144 | } | |
| 1145 | ||
| 1146 | /*--------------------------------------------------------------------------- | |
| 1147 | * Post a Layer1/2 status change event | |
| 1148 | *---------------------------------------------------------------------------*/ | |
| 1149 | void | |
| 1150 | monitor_evnt_l12stat(int controller, int layer, int state) | |
| 1151 | { | |
| 1152 | u_int8_t evnt[I4B_MON_L12STAT_SIZE]; | |
| 1153 | time_t now; | |
| 1154 | ||
| 1155 | if(!anybody(I4B_CA_EVNT_I4B)) | |
| 1156 | return; | |
| 1157 | ||
| 1158 | time(&now); | |
| 1159 | ||
| 1160 | I4B_PREP_EVNT(evnt, I4B_MON_L12STAT_CODE); | |
| 1161 | I4B_PUT_4B(evnt, I4B_MON_L12STAT_TSTAMP, (long)now); | |
| 1162 | I4B_PUT_4B(evnt, I4B_MON_L12STAT_CTRL, controller); | |
| 1163 | I4B_PUT_4B(evnt, I4B_MON_L12STAT_LAYER, layer); | |
| 1164 | I4B_PUT_4B(evnt, I4B_MON_L12STAT_STATE, state); | |
| 1165 | ||
| 1166 | monitor_broadcast(I4B_CA_EVNT_I4B, evnt, sizeof evnt); | |
| 1167 | } | |
| 1168 | ||
| 1169 | /*--------------------------------------------------------------------------- | |
| 1170 | * Post a TEI change event | |
| 1171 | *---------------------------------------------------------------------------*/ | |
| 1172 | void | |
| 1173 | monitor_evnt_tei(int controller, int tei) | |
| 1174 | { | |
| 1175 | u_int8_t evnt[I4B_MON_TEI_SIZE]; | |
| 1176 | time_t now; | |
| 1177 | ||
| 1178 | if(!anybody(I4B_CA_EVNT_I4B)) | |
| 1179 | return; | |
| 1180 | ||
| 1181 | time(&now); | |
| 1182 | ||
| 1183 | I4B_PREP_EVNT(evnt, I4B_MON_TEI_CODE); | |
| 1184 | I4B_PUT_4B(evnt, I4B_MON_TEI_TSTAMP, (long)now); | |
| 1185 | I4B_PUT_4B(evnt, I4B_MON_TEI_CTRL, controller); | |
| 1186 | I4B_PUT_4B(evnt, I4B_MON_TEI_TEI, tei); | |
| 1187 | ||
| 1188 | monitor_broadcast(I4B_CA_EVNT_I4B, evnt, sizeof evnt); | |
| 1189 | } | |
| 1190 | ||
| 1191 | /*--------------------------------------------------------------------------- | |
| 1192 | * Post an accounting event | |
| 1193 | *---------------------------------------------------------------------------*/ | |
| 1194 | void | |
| 1195 | monitor_evnt_acct(cfg_entry_t *cep) | |
| 1196 | { | |
| 1197 | u_int8_t evnt[I4B_MON_ACCT_SIZE]; | |
| 1198 | time_t now; | |
| 1199 | ||
| 1200 | if(!anybody(I4B_CA_EVNT_I4B)) | |
| 1201 | return; | |
| 1202 | ||
| 1203 | time(&now); | |
| 1204 | ||
| 1205 | I4B_PREP_EVNT(evnt, I4B_MON_ACCT_CODE); | |
| 1206 | I4B_PUT_4B(evnt, I4B_MON_ACCT_TSTAMP, (long)now); | |
| 1207 | ||
| 1208 | I4B_PUT_4B(evnt, I4B_MON_ACCT_CTRL, cep->isdncontrollerused); | |
| 1209 | I4B_PUT_4B(evnt, I4B_MON_ACCT_CHAN, cep->isdnchannelused); | |
| 1210 | I4B_PUT_4B(evnt, I4B_MON_ACCT_OBYTES, cep->outbytes); | |
| 1211 | I4B_PUT_4B(evnt, I4B_MON_ACCT_OBPS, cep->outbps); | |
| 1212 | I4B_PUT_4B(evnt, I4B_MON_ACCT_IBYTES, cep->inbytes); | |
| 1213 | I4B_PUT_4B(evnt, I4B_MON_ACCT_IBPS, cep->inbps); | |
| 1214 | ||
| 1215 | monitor_broadcast(I4B_CA_EVNT_I4B, evnt, sizeof evnt); | |
| 1216 | } | |
| 1217 | ||
| 1218 | /*--------------------------------------------------------------------------- | |
| 1219 | * read from a socket | |
| 1220 | *---------------------------------------------------------------------------*/ | |
| 1221 | static ssize_t | |
| 1222 | sock_read(int fd, void *buf, size_t nbytes) | |
| 1223 | { | |
| 1224 | size_t nleft; | |
| 1225 | ssize_t nread; | |
| 1226 | unsigned char *ptr; | |
| 1227 | ||
| 1228 | ptr = buf; | |
| 1229 | nleft = nbytes; | |
| 1230 | ||
| 1231 | while(nleft > 0) | |
| 1232 | { | |
| 1233 | if((nread = read(fd, ptr, nleft)) < 0) | |
| 1234 | { | |
| 1235 | if(errno == EINTR) | |
| 1236 | { | |
| 1237 | nread = 0; | |
| 1238 | } | |
| 1239 | else | |
| 1240 | { | |
| 1241 | return(-1); | |
| 1242 | } | |
| 1243 | } | |
| 1244 | else if(nread == 0) | |
| 1245 | { | |
| 1246 | break; /* EOF */ | |
| 1247 | } | |
| 1248 | ||
| 1249 | nleft -= nread; | |
| 1250 | ptr += nread; | |
| 1251 | } | |
| 1252 | return(nbytes - nleft); | |
| 1253 | } | |
| 1254 | ||
| 1255 | /*--------------------------------------------------------------------------- | |
| 1256 | * write to a socket | |
| 1257 | *---------------------------------------------------------------------------*/ | |
| 1258 | static ssize_t | |
| 1259 | sock_write(int fd, void *buf, size_t nbytes) | |
| 1260 | { | |
| 1261 | size_t nleft; | |
| 1262 | ssize_t nwritten; | |
| 1263 | unsigned char *ptr; | |
| 1264 | ||
| 1265 | ptr = buf; | |
| 1266 | nleft = nbytes; | |
| 1267 | ||
| 1268 | while(nleft > 0) | |
| 1269 | { | |
| 1270 | if((nwritten = write(fd, ptr, nleft)) <= 0) | |
| 1271 | { | |
| 1272 | if(errno == EINTR) | |
| 1273 | { | |
| 1274 | nwritten = 0; | |
| 1275 | } | |
| 1276 | else | |
| 1277 | { | |
| 1278 | return(-1); | |
| 1279 | } | |
| 1280 | } | |
| 1281 | ||
| 1282 | nleft -= nwritten; | |
| 1283 | ptr += nwritten; | |
| 1284 | } | |
| 1285 | return(nbytes); | |
| 1286 | } | |
| 1287 | ||
| fe361e7d SW |
1288 | struct monitor_rights * |
| 1289 | monitor_next_rights(const struct monitor_rights *r) | |
| 984263bc MD |
1290 | { |
| 1291 | if (r == NULL) | |
| 1292 | return TAILQ_FIRST(&rights); | |
| 1293 | else | |
| 1294 | return TAILQ_NEXT(r, list); | |
| 1295 | } | |
| 1296 | ||
| 1297 | #endif /* I4B_EXTERNAL_MONITOR */ |