#include #include #include #include #include #include "util.h" #include "net.h" #include "gss.h" #include "strbuf.h" struct strbuf fqdn = STRBUF_INIT; const size_t MAX_MSGLEN = 65536; const size_t MSG_BUFINC = 4096; void setup_fqdn(void) { struct utsname uts; struct hostent *lo; if (uname(&uts)) fatalpe("uname"); lo = gethostbyname(uts.nodename); if (!lo) fatalpe("gethostbyname"); strbuf_addstr(&fqdn, lo->h_name); } void free_fqdn(void) { strbuf_release(&fqdn); } static size_t recv_one_message(int sock, struct sctp_meta *msg_meta, struct strbuf *msg, int *notification) { size_t len = 0; int flags = 0; int bytes; strbuf_reset(msg); do { msg_meta->fromlen = sizeof(msg_meta->from); bytes = sctp_recvmsg(sock, msg->buf + len, strbuf_avail(msg) - len, (sa *)&msg_meta->from, &msg_meta->fromlen, &msg_meta->sinfo, &flags); if (bytes < 0) { if (errno == EAGAIN) continue; fatalpe("sctp_recvmsg"); } if (!bytes) break; len += bytes; if (msg->len > MAX_MSGLEN) fatal("oversized message received"); if (strbuf_avail(msg) < MSG_BUFINC) strbuf_grow(msg, MSG_BUFINC); } while (~flags & MSG_EOR); if (!bytes && len) fatalpe("EOF in the middle of a message"); *notification = flags & MSG_NOTIFICATION; if (*notification) { notification_dbg(msg->buf); union sctp_notification *sn = (union sctp_notification *) msg->buf; switch (sn->sn_header.sn_type) { case SCTP_SHUTDOWN_EVENT: fatal("connection shut down"); break; } } strbuf_setlen(msg, len); return len; } int receive_one_message(int sock, struct sctp_meta *msg_meta, struct strbuf *msg) { int notification = 0; do { recv_one_message(sock, msg_meta, msg, ¬ification); } while (notification); return msg->len > 0; } void notification_dbg(char *notification) { union sctp_notification *sn = (union sctp_notification *) notification; char *extra; switch (sn->sn_header.sn_type) { case SCTP_ASSOC_CHANGE: extra = "unknown state"; switch (sn->sn_assoc_change.sac_state) { case SCTP_COMM_UP: extra = "established"; break; case SCTP_COMM_LOST: extra = "lost"; break; case SCTP_RESTART: extra = "restarted"; break; case SCTP_SHUTDOWN_COMP: extra = "completed shutdown"; break; case SCTP_CANT_STR_ASSOC: extra = "cannot start"; break; } debug("association changed: association 0x%x %s", sn->sn_assoc_change.sac_assoc_id, extra); break; case SCTP_PEER_ADDR_CHANGE: extra = "unknown state"; switch (sn->sn_paddr_change.spc_state) { case SCTP_ADDR_AVAILABLE: extra = "unavailable"; break; case SCTP_ADDR_UNREACHABLE: extra = "unreachable"; break; case SCTP_ADDR_REMOVED: extra = "removed"; break; case SCTP_ADDR_ADDED: extra = "added"; break; case SCTP_ADDR_MADE_PRIM: extra = "made primary"; break; #ifdef SCTP_ADDR_CONFIRMED case SCTP_ADDR_CONFIRMED: extra = "confirmed"; break; #endif } struct sockaddr_in *sa = (struct sockaddr_in *) &sn->sn_paddr_change.spc_aaddr; char addr[INET_ADDRSTRLEN]; inet_ntop(AF_INET, &sa->sin_addr, addr, sizeof(addr)); debug("peer address change: remote address %s %s", addr, extra); break; case SCTP_REMOTE_ERROR: debug("remote error: association=0x%x error=0x%x", sn->sn_remote_error.sre_assoc_id, sn->sn_remote_error.sre_error); break; case SCTP_SEND_FAILED: debug("send failed: association=0x%x error=0x%x", sn->sn_send_failed.ssf_assoc_id, sn->sn_send_failed.ssf_error); break; case SCTP_ADAPTATION_INDICATION: debug("adaptation indication: 0x%x", sn->sn_adaptation_event.sai_adaptation_ind); break; case SCTP_PARTIAL_DELIVERY_EVENT: extra = "unknown indication"; switch (sn->sn_pdapi_event.pdapi_indication) { case SCTP_PARTIAL_DELIVERY_ABORTED: extra = "partial delivery aborted"; break; } debug("partial delivery event: %s", extra); break; case SCTP_SHUTDOWN_EVENT: debug("association 0x%x was shut down", sn->sn_shutdown_event.sse_assoc_id); break; default: debug("unknown sctp notification type 0x%x\n", sn->sn_header.sn_type); } }