/* ------------------------------------------------------------------------------ ------------------------------------------------------------------------------ -- This file is part of 'UDP', a datagram sockets library. -- -- -- -- (C) 2018 Stanislav Datskovskiy ( www.loper-os.org ) -- -- http://wot.deedbot.org/17215D118B7239507FAFED98B98228A001ABFFC7.html -- -- -- -- You do not have, nor can you ever acquire the right to use, copy or -- -- distribute this software ; Should you use this software for any purpose, -- -- or copy and distribute it to anyone or in any manner, you are breaking -- -- the laws of whatever soi-disant jurisdiction, and you promise to -- -- continue doing so for the indefinite future. In any case, please -- -- always : read and understand any software ; verify any PGP signatures -- -- that you use - for any purpose. -- -- -- -- See also http://trilema.com/2015/a-new-software-licensing-paradigm . -- ------------------------------------------------------------------------------ ------------------------------------------------------------------------------ */ #include #include #include #include #include #include /* Socket state representation: */ typedef struct _UDP_Socket { struct sockaddr_in sa_local; int sock; } UDP_Socket; /* local-endian ip to string conversion */ void unix_udp_ip_to_string(uint32_t ip, char *buf, uint32_t buf_size) { struct in_addr addr; addr.s_addr = htonl(ip); char *txt = inet_ntoa(addr); strncpy(buf, txt, buf_size); } /* Should be replaced with native routine */ /* string to local-endian ip conversion */ int unix_udp_string_to_ip(char *buf, uint32_t *ip) { struct in_addr addr; if (inet_aton(buf, &addr) <= 0) return -1; *ip = ntohl(addr.s_addr); return 0; } /* Should be replaced with native routine */ int unix_udp_socket_open(UDP_Socket *S, uint32_t local_ip, uint16_t local_port) { /* Open the socket FD: */ if ((S->sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { return -1; } memset(&S->sa_local, 0, sizeof(struct sockaddr_in)); /* Set up emitter endpoint, converting from local endianness: */ S->sa_local.sin_family = AF_INET; S->sa_local.sin_addr.s_addr = htonl(local_ip); S->sa_local.sin_port = htons(local_port); /* Cure the asinine linuxism where dead sockets interfere with living: */ int one = 1; if (setsockopt(S->sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) < 0) { close(S->sock); return -2; } /* Bind the socket */ if (bind(S->sock, (struct sockaddr *)&(S->sa_local), sizeof(S->sa_local)) < 0) { close(S->sock); return -3; } /* ok */ return 0; } void unix_udp_socket_close(UDP_Socket *S) { close(S->sock); } int unix_udp_socket_transmit(UDP_Socket *S, uint32_t remote_ip, uint16_t remote_port, uint8_t *payload, uint32_t payload_len) { int bytes_sent = 0; struct sockaddr_in remote_addr; memset((char *)&remote_addr, 0, sizeof(remote_addr)); /* Set up dest endpoint, converting from local endianness: */ remote_addr.sin_family = AF_INET; remote_addr.sin_port = htons(remote_port); remote_addr.sin_addr.s_addr = htonl(remote_ip); /* Transmit Datagram */ bytes_sent = sendto(S->sock, payload, payload_len, 0, /* no flags */ (struct sockaddr*)&remote_addr, sizeof(remote_addr)); if (bytes_sent <= 0) return -1; return bytes_sent; } int unix_udp_socket_receive(UDP_Socket *S, uint32_t *origin_ip, uint16_t *origin_port, uint8_t *payload, uint32_t payload_len) { int bytes_received = 0; struct sockaddr_in orig_addr; socklen_t orig_addr_len = sizeof(orig_addr); memset((char *)&orig_addr, 0, sizeof(orig_addr)); /* Receive Datagram (blocking!) */ bytes_received = recvfrom(S->sock, payload, payload_len, 0, /* no flags */ (struct sockaddr *)&orig_addr, &orig_addr_len); if (bytes_received < 0) return -1; /* Save the originator's endpoint in ~local~ endianness */ *origin_ip = ntohl(orig_addr.sin_addr.s_addr); *origin_port = ntohs(orig_addr.sin_port); return bytes_received; }