#define MAX_PACKET_LEN 4096
/*
- * Open a socket on the given IP and port.
- */
-int fr_tcp_socket(fr_ipaddr_t *ipaddr, int port)
-{
- int sockfd;
- int on = 1;
- struct sockaddr_storage salocal;
- socklen_t salen;
-
- if ((port < 0) || (port > 65535)) {
- fr_strerror_printf("Port %d is out of allowed bounds", port);
- return -1;
- }
-
- sockfd = socket(ipaddr->af, SOCK_STREAM, 0);
- if (sockfd < 0) {
- return sockfd;
- }
-
- if (fr_nonblock(sockfd) < 0) {
- close(sockfd);
- return -1;
- }
-
- if (!fr_ipaddr2sockaddr(ipaddr, port, &salocal, &salen)) {
- close(sockfd);
- return -1;
- }
-
-#ifdef HAVE_STRUCT_SOCKADDR_IN6
- if (ipaddr->af == AF_INET6) {
- /*
- * Listening on '::' does NOT get you IPv4 to
- * IPv6 mapping. You've got to listen on an IPv4
- * address, too. This makes the rest of the server
- * design a little simpler.
- */
-#ifdef IPV6_V6ONLY
-
- if (IN6_IS_ADDR_UNSPECIFIED(&ipaddr->ipaddr.ip6addr)) {
- if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY,
- (char *)&on, sizeof(on)) < 0) {
- fr_strerror_printf("Failed in setsockopt(): %s",
- fr_syserror(errno));
- close(sockfd);
- return -1;
- }
- }
-#endif /* IPV6_V6ONLY */
- }
-#endif /* HAVE_STRUCT_SOCKADDR_IN6 */
-
- if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
- fr_strerror_printf("Failed in setsockopt(): %s", fr_syserror(errno));
- close(sockfd);
- return -1;
- }
-
- if (bind(sockfd, (struct sockaddr *) &salocal, salen) < 0) {
- fr_strerror_printf("Failed in bind(): %s", fr_syserror(errno));
- close(sockfd);
- return -1;
- }
-
- if (listen(sockfd, 8) < 0) {
- fr_strerror_printf("Failed in listen(): %s", fr_syserror(errno));
- close(sockfd);
- return -1;
- }
-
- return sockfd;
-}
-
-
-/*
* Open a socket TO the given IP and port.
*/
int fr_tcp_client_socket(fr_ipaddr_t *src_ipaddr,
return 1; /* done reading the packet */
}
-RADIUS_PACKET *fr_tcp_accept(int sockfd)
-{
- int newfd;
- socklen_t salen;
- RADIUS_PACKET *packet;
- struct sockaddr_storage src;
-
- salen = sizeof(src);
-
- newfd = accept(sockfd, (struct sockaddr *) &src, &salen);
- if (newfd < 0) {
- /*
- * Non-blocking sockets must handle this.
- */
-#ifdef EWOULDBLOCK
- if (errno == EWOULDBLOCK) {
- packet = rad_alloc(NULL, 0);
- if (!packet) return NULL;
-
- packet->sockfd = sockfd;
- packet->src_ipaddr.af = AF_UNSPEC;
- return packet;
- }
-#endif
-
- return NULL;
- }
-
- packet = rad_alloc(NULL, 0);
- if (!packet) {
- close(newfd);
- return NULL;
- }
-
- if (src.ss_family == AF_INET) {
- struct sockaddr_in s4;
-
- memcpy(&s4, &src, sizeof(s4));
- packet->src_ipaddr.af = AF_INET;
- packet->src_ipaddr.ipaddr.ip4addr = s4.sin_addr;
- packet->src_port = ntohs(s4.sin_port);
-
-#ifdef HAVE_STRUCT_SOCKADDR_IN6
- } else if (src.ss_family == AF_INET6) {
- struct sockaddr_in6 s6;
-
- memcpy(&s6, &src, sizeof(s6));
- packet->src_ipaddr.af = AF_INET6;
- packet->src_ipaddr.ipaddr.ip6addr = s6.sin6_addr;
- packet->src_port = ntohs(s6.sin6_port);
-
-#endif
- } else {
- rad_free(&packet);
- close(newfd);
- return NULL;
- }
-
- packet->sockfd = newfd;
-
- /*
- * Note: Caller has to set dst_ipaddr && dst_port.
- */
- return packet;
-}
-
-
-/*
- * Writes a packet, assuming it's already been encoded.
- *
- * It returns the number of bytes written, which MAY be less than
- * the packet size (data_len). It is the caller's responsibility
- * to check the return code, and to schedule writes again.
- */
-ssize_t fr_tcp_write_packet(RADIUS_PACKET *packet)
-{
- ssize_t rcode;
-
- if (!packet || !packet->data) return 0;
-
- if (packet->partial >= packet->data_len) return packet->data_len;
-
- rcode = write(packet->sockfd, packet->data + packet->partial,
- packet->data_len - packet->partial);
- if (rcode < 0) return packet->partial; /* ignore most errors */
-
- packet->partial += rcode;
-
- return packet->partial;
-}
#endif /* WITH_TCP */