/* sock_udp.c * * copyright (c) 2000-2003 SeaD * see GPL for copying info * */ #include #include #include #include #include #include #include "echat.h" #ifdef DEBUG # include #endif /* DEBUG */ #define POLL_TIMEOUT 1 struct sockaddr_in *sacl, *sacu, *sacb[ADDRS_MAX]; int sfdcl, sfdcu, sfdcb; int packet_buffer(void) { register int n; for (n = 0; n < PBUF_SIZE; n++) if (!strncmp(packet, status->packet_buf[n], HEADER_LEN)) { #ifdef DEBUG fprintf(debug_file, "buffer: dupe(%15s): %s\n", status->address, packet); fflush(debug_file); #endif /* DEBUG */ return -1; } for (n = PBUF_SIZE-2; n > 0; n--) { strncpy(status->packet_buf[n], status->packet_buf[n-1], HEADER_LEN); } strncpy(status->packet_buf[n], packet, HEADER_LEN); return 0; } void packet_xor(void) { register int n; for (n = HEADER_LEN; n < status->packet_len; packet[n++] ^= config->packet_xor); } void packet_b64dec(void) { /* b64_pton(char *src, char *target, size_t targsize); */ } void packet_b64enc(void) { /* b64_ntop(u_char const *src, size_t srclength, char *target, size_t targsize); */ } void sock_init(void) { int s = 1; register int n; if ((sacl = (struct sockaddr_in *) malloc(sizeof(struct sockaddr_in))) == NULL) { #ifdef DEBUG fprintf(debug_file, "malloc(): %s\n", strerror(errno)); #endif /* DEBUG */ exit(EXIT_FAILURE); } if ((sacu = (struct sockaddr_in *) malloc(sizeof(struct sockaddr_in))) == NULL) { #ifdef DEBUG fprintf(debug_file, "malloc(): %s\n", strerror(errno)); #endif /* DEBUG */ exit(EXIT_FAILURE); } for (n = 0; n < status->addrs; n++) if ((sacb[n] = (struct sockaddr_in *) malloc(sizeof(struct sockaddr_in))) == NULL) { #ifdef DEBUG fprintf(debug_file, "malloc(): %s\n", strerror(errno)); #endif /* DEBUG */ exit(EXIT_FAILURE); } memset(sacl, 0, sizeof(struct sockaddr_in)); sacl->sin_family = AF_INET; sacl->sin_port = htons(config->port); sacl->sin_addr.s_addr = INADDR_ANY; memset(sacu, 0, sizeof(struct sockaddr_in)); sacu->sin_family = AF_INET; sacu->sin_port = htons(config->port); for (n = 0; n < status->addrs; n++) { memset(sacb[n], 0, sizeof(struct sockaddr_in)); sacb[n]->sin_family = AF_INET; sacb[n]->sin_port = htons(config->port); if (!inet_aton(status->addr[n], &sacb[n]->sin_addr)) { #ifdef DEBUG fprintf(debug_file, "eChat: Invalid address %s\n", status->address); fflush(debug_file); #endif /* DEBUG */ fprintf(stderr, "eChat: Invalid address.\n"); exit(EXIT_FAILURE); } } if ((sfdcl = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { #ifdef DEBUG fprintf(debug_file, "socket(): %s\n", strerror(errno)); fflush(debug_file); #endif /* DEBUG */ fprintf(stderr, "eChat: Socket allocation failed.\n"); exit(EXIT_FAILURE); } #ifdef PORTREUSE if (setsockopt(sfdcl, SOL_SOCKET, SO_REUSEPORT, &s, sizeof(s)) < 0) { #ifdef DEBUG fprintf(debug_file, "setsockopt(): %s\n", strerror(errno)); fflush(debug_file); #endif /* DEBUG */ fprintf(stderr, "eChat: Set socket option failed.\n"); exit(EXIT_FAILURE); } #endif /* PORTREUSE */ if (bind(sfdcl, (struct sockaddr *) sacl, sizeof(struct sockaddr)) < 0) { #ifdef DEBUG fprintf(debug_file, "bind(): %s\n", strerror(errno)); fflush(debug_file); #endif /* DEBUG */ fprintf(stderr, "eChat: Bind socket failed.\n"); exit(EXIT_FAILURE); } if ((sfdcu = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { #ifdef DEBUG fprintf(debug_file, "socket(): %s\n", strerror(errno)); fflush(debug_file); #endif /* DEBUG */ snprintf(message, STR_SIZE, SOCK_ALLOC, time_get()); write_str(status->room->name, COL_ERROR); return; } if ((sfdcb = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { #ifdef DEBUG fprintf(debug_file, "socket(): %s\n", strerror(errno)); fflush(debug_file); #endif /* DEBUG */ fprintf(stderr, "eChat: Socket allocation failed.\n"); exit(EXIT_FAILURE); } if (setsockopt(sfdcb, SOL_SOCKET, SO_BROADCAST, &s, sizeof(s)) < 0) { #ifdef DEBUG fprintf(debug_file, "setsockopt(): %s\n", strerror(errno)); fflush(debug_file); #endif /* DEBUG */ fprintf(stderr, "eChat: Set socket option failed.\n"); exit(EXIT_FAILURE); } #ifdef TCP sock_tcpinit(); #endif /* TCP */ #ifdef DEBUG fprintf(debug_file, "socket: Initialization complete.\n"); fflush(debug_file); #endif /* DEBUG */ } void sock_kill(void) { register int n; #ifdef TCP sock_tcpkill(); #endif /* TCP */ close(sfdcl); close(sfdcu); close(sfdcb); free(sacl); free(sacu); for (n = 0; n < status->addrs; n++) free(sacb[n]); status->addrs = 0; #ifdef DEBUG fprintf(debug_file, "socket: Shutdown complete.\n"); fflush(debug_file); #endif /* DEBUG */ } void sock_route(void) { register int n; for (n = 0; n < status->addrs; n++) { if (!addr_netcmp(status->addr[n], status->address)) continue; /* if (!strncmp(status->address, LOCALHOST, ADDR_SIZE)) continue; */ #ifdef DEBUG fprintf(debug_file, "sendto(%15s): _%s_ (%u bytes)\n", inet_ntoa(sacb[n]->sin_addr), packet, status->packet_len); fflush(debug_file); #endif /* DEBUG */ if (sendto(sfdcb, packet, status->packet_len, 0, (struct sockaddr *) sacb[n], sizeof(struct sockaddr)) < 0) { #ifdef DEBUG fprintf(debug_file, "sendto(): %s\n", strerror(errno)); fflush(debug_file); #endif /* DEBUG */ if (config->status_str) status_error(SOCK_SROUTE); else { snprintf(message, STR_SIZE, SOCK_ROUTE, time_get(), inet_ntoa(sacb[n]->sin_addr)); write_str(status->room->name, COL_ERROR); } } } } void sock_recv(void) { struct pollfd usfd; int s; #ifdef DEBUG_PACKET register int n; #endif /* DEBUG_PACKET */ usfd.fd = sfdcl; usfd.events = POLLIN | POLLPRI; while (poll(&usfd, 1, POLL_TIMEOUT) > 0) { s = sizeof(struct sockaddr); if ((status->packet_len = recvfrom(sfdcl, packet, MSG_SIZE, 0, (struct sockaddr *) sacl, &s)) < 0) { #ifdef DEBUG fprintf(debug_file, "recvfr(): %s\n", strerror(errno)); fflush(debug_file); #endif /* DEBUG */ if (config->status_str) status_error(SOCK_SRECEIVE); else { snprintf(message, STR_SIZE, SOCK_RECV, time_get(), inet_ntoa(sacl->sin_addr)); write_str(status->room->name, COL_ERROR); } return; } strncpy(status->address, inet_ntoa(sacl->sin_addr), ADDR_SIZE); #ifdef DEBUG #ifdef DEBUG_PACKET for (n = 0; n < status->packet_len; n++) if ((message[n] = packet[n]) == '\0') message[n] = '|'; message[n] = '\0'; #else /* DEBUG_PACKET */ strncpy(message, packet, status->packet_len); #endif /* DEBUG_PACKET */ fprintf(debug_file, "recvfr(%-15s): _%s_ (%u bytes)\n", status->address, message, status->packet_len); fflush(debug_file); #endif /* DEBUG */ if (!config->packet_qchat && !config->packet_pchat) if (packet_buffer()) return; if (config->packet_route) sock_route(); if (config->packet_pchat) packet_b64dec(); if (config->packet_vchat && config->packet_xor) packet_xor(); #ifdef CHARSET if (config->charset) cset_outin(); #endif /* CHARSET */ recv_message(); } } void sock_usend(void) { #ifdef DEBUG_PACKET register int n; #endif /* DEBUG_PACKET */ #ifdef CHARSET if (config->charset) cset_inout(); #endif /* CHARSET */ if (config->packet_vchat && config->packet_xor) packet_xor(); if (config->packet_pchat) packet_b64enc(); if (!inet_aton(status->address, &sacu->sin_addr)) { #ifdef DEBUG fprintf(debug_file, "inet_aton(%15s): invalid address for %s\n", status->address, status->nick); fflush(debug_file); #endif /* DEBUG */ snprintf(message, STR_SIZE, SOCK_ADDRESS, time_get(), status->nick, status->address); write_str(status->room->name, COL_ERROR); return; } #ifdef DEBUG #ifdef DEBUG_PACKET for (n = 0; n < status->packet_len; n++) if ((message[n] = packet[n]) == '\0') message[n] = '|'; message[n] = '\0'; #else /* DEBUG_PACKET */ strncpy(message, packet, status->packet_len); #endif /* DEBUG_PACKET */ fprintf(debug_file, "sendto(%-15s): _%s_ (%u bytes)\n", status->address, message, status->packet_len); fflush(debug_file); #endif /* DEBUG */ if (sendto(sfdcu, packet, status->packet_len, 0, (struct sockaddr *) sacu, sizeof(struct sockaddr)) < 0) { #ifdef DEBUG fprintf(debug_file, "sendto(): %s\n", strerror(errno)); fflush(debug_file); #endif /* DEBUG */ if (config->status_str) status_error(SOCK_SUSEND); else { snprintf(message, STR_SIZE, SOCK_USEND, time_get(), status->address); write_str(status->room->name, COL_ERROR); } } } void sock_bsend(void) { register int n; #ifdef CHARSET if (config->charset) cset_inout(); #endif /* CHARSET */ if (config->packet_vchat && config->packet_xor) packet_xor(); if (config->packet_pchat) packet_b64enc(); #ifdef DEBUG #ifdef DEBUG_PACKET for (n = 0; n < status->packet_len; n++) if ((message[n] = packet[n]) == '\0') message[n] = '|'; message[n] = '\0'; #else /* DEBUG_PACKET */ strncpy(message, packet, status->packet_len); #endif /* DEBUG_PACKET */ #endif /* DEBUG */ for (n = 0; n < status->addrs; n++) { #ifdef DEBUG fprintf(debug_file, "sendto(%-15s): _%s_ (%u bytes)\n", inet_ntoa(sacb[n]->sin_addr), message, status->packet_len); fflush(debug_file); #endif /* DEBUG */ if (sendto(sfdcb, packet, status->packet_len, 0, (struct sockaddr *) sacb[n], sizeof(struct sockaddr)) < 0) { #ifdef DEBUG fprintf(debug_file, "sendto(): %s\n", strerror(errno)); fflush(debug_file); #endif /* DEBUG */ if (config->status_str) status_error(SOCK_SBSEND); else { snprintf(message, STR_SIZE, SOCK_BSEND, time_get(), inet_ntoa(sacb[n]->sin_addr)); write_str(status->room->name, COL_ERROR); } } } }