#include #include #include #include #include #include #include #include #include #include "oct_log.h" #include "oct_networking.h" struct { int needs_recv; char recv_buffer[BUFFER_SIZE]; char recv_addr[NI_MAXHOST]; char recv_port[NI_MAXSERV]; int needs_send; char send_buffer[BUFFER_SIZE]; char send_addr[NI_MAXHOST]; char send_port[NI_MAXSERV]; int sfd; } oct_network_node; int oct_network_node_init(char* port, lua_State* L) { oct_network_node.needs_recv = 1; oct_network_node.needs_send = 0; struct addrinfo hints; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; // ipv4 or ipv6 hints.ai_socktype = SOCK_DGRAM; // datagram hints.ai_flags = AI_PASSIVE; // any IP address hints.ai_protocol = 0; // any protocol hints.ai_canonname = NULL; hints.ai_addr = NULL; hints.ai_next = NULL; struct addrinfo* result; int s = getaddrinfo(NULL, port, &hints, &result); if (s != 0) { //fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(s)); return 0; } /* getaddrinfo() returns a list of address structures. Try each address until we successfully bind(2). If socket(2) (or bind(2)) fails, we (close the socket and) try the next address. */ struct addrinfo *rp; for (rp = result; rp != NULL; rp = rp->ai_next) { oct_network_node.sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); if (oct_network_node.sfd == -1) continue; if (bind(oct_network_node.sfd, rp->ai_addr, rp->ai_addrlen) == 0) break; /* Success */ close(oct_network_node.sfd); } freeaddrinfo(result); if (!rp) { return 0; } OCT_LOG_INFO("Listening on 127.0.0.1 port %s", port); lua_pushcfunction(L, oct_network_recv_msg_lua); lua_setglobal(L, "oct_recv"); lua_pushcfunction(L, oct_network_send_msg_lua); lua_setglobal(L, "oct_send"); return 1; } // This runs every loop, filling the receive buffer if needed int oct_network_recv_msg() { if (oct_network_node.needs_recv) { struct sockaddr_storage peer_addr; socklen_t peer_addrlen = sizeof(peer_addr); // recvfrom returns -1 if nothing was received // Need MSG_DONTWAIT flag for nonblocking if (recvfrom(oct_network_node.sfd, oct_network_node.recv_buffer, BUFFER_SIZE, MSG_DONTWAIT, (struct sockaddr *) &peer_addr, &peer_addrlen) > 0) { int s = getnameinfo((struct sockaddr *) &peer_addr, peer_addrlen, oct_network_node.recv_addr, NI_MAXHOST, oct_network_node.recv_port, NI_MAXSERV, NI_NUMERICSERV); if (s != 0) { OCT_LOG_WARNING("Received message from unknown host: %s", oct_network_node.recv_buffer); return -1; } oct_network_node.needs_recv = 0; } } return 0; } int oct_network_send_msg() { if (oct_network_node.needs_send) { int sfd; int s; struct addrinfo hints; struct addrinfo* result; struct addrinfo* rp; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */ hints.ai_socktype = SOCK_DGRAM; /* Datagram socket */ hints.ai_flags = 0; hints.ai_protocol = 0; /* Any protocol */ s = getaddrinfo(oct_network_node.send_addr, oct_network_node.send_port, &hints, &result); if (s != 0) { OCT_LOG_WARNING("getaddrinfo failed when sending message"); return -1; } /* getaddrinfo() returns a list of address structures. Try each address until we successfully connect(2). If socket(2) (or connect(2)) fails, we (close the socket and) try the next address. */ for (rp = result; rp != NULL; rp = rp->ai_next) { sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); if (sfd == -1) continue; if (connect(sfd, rp->ai_addr, rp->ai_addrlen) != -1) break; /* Success */ close(sfd); } freeaddrinfo(result); /* No longer needed */ if (rp == NULL) { /* No address succeeded */ fprintf(stderr, "Could not connect\n"); exit(EXIT_FAILURE); } ssize_t length = strlen(oct_network_node.send_buffer); if (write(sfd, oct_network_node.send_buffer, length) != length) { OCT_LOG_WARNING("Partial write when sending message"); return -1; } oct_network_node.needs_send = 0; close(sfd); } return 1; } int oct_network_recv_msg_lua(lua_State* L) { if (!oct_network_node.needs_recv) { lua_pushstring(L, oct_network_node.recv_buffer); lua_pushstring(L, oct_network_node.recv_addr); lua_pushstring(L, oct_network_node.recv_port); oct_network_node.needs_recv = 1; } else { lua_pushstring(L, ""); lua_pushstring(L, ""); lua_pushstring(L, ""); } return 3; } int oct_network_send_msg_lua(lua_State* L) { if (!oct_network_node.needs_send) { strncpy(oct_network_node.send_buffer, luaL_checkstring(L, -3), BUFFER_SIZE); strncpy(oct_network_node.send_addr, luaL_checkstring(L, -2), NI_MAXHOST); strncpy(oct_network_node.send_port, luaL_checkstring(L, -1), NI_MAXSERV); oct_network_node.needs_send = 1; } return 0; }