/* * Test the network write function with a timeout. We fork off a child * process that runs delay_reader, and then we write 64KB to the network in * two chunks, once with a timeout and once without, and then try a third time * when we should time out. */ static void test_network_write(void) { socket_type fd, c; pid_t child; struct sockaddr_in sin; socklen_t slen; char *buffer; /* Create the data that we're going to send. */ buffer = bmalloc(4096 * 1024); memset(buffer, 'a', 4096 * 1024); /* Create the listening socket. */ fd = network_bind_ipv4(SOCK_STREAM, "127.0.0.1", 11119); if (fd == INVALID_SOCKET) sysbail("cannot create or bind socket"); if (listen(fd, 1) < 0) sysbail("cannot listen to socket"); /* Create the child, which will connect and then read data with delay. */ child = fork(); if (child < 0) sysbail("cannot fork"); else if (child == 0) { socket_close(fd); client_delay_reader("127.0.0.1"); } /* Set an alarm just in case our timeouts don't work. */ alarm(10); /* Accept the client connection. */ slen = sizeof(struct sockaddr_in); c = accept(fd, &sin, &slen); if (c == INVALID_SOCKET) sysbail("cannot accept on socket"); /* Test some successful writes with and without a timeout. */ socket_set_errno(0); ok(network_write(c, buffer, 32 * 1024, 0), "network_write"); ok(network_write(c, buffer, 32 * 1024, 1), "network_write with timeout"); /* * A longer write cannot be completely absorbed before the client sleep, * so should fail with a timeout. */ ok(!network_write(c, buffer, 4096 * 1024, 1), "network_write aborted with timeout"); is_int(ETIMEDOUT, socket_errno, "...with correct error"); alarm(0); /* Clean up. */ socket_close(c); kill(child, SIGTERM); waitpid(child, NULL, 0); socket_close(fd); free(buffer); }
ssize_t recv(int sock, void * p_buf, size_t buf_size, int flags) { VERIFY_MODULE_IS_INITIALIZED(); VERIFY_SOCKET_ID(sock); NULL_PARAM_CHECK(p_buf); SOCKET_MUTEX_LOCK(); socket_entry_t * p_socket_entry = &m_socket_table[sock]; SOCKET_MUTEX_UNLOCK(); ssize_t ret = -1; if (p_socket_entry->state == STATE_CONNECTED) { uint32_t recv_size = 0; uint32_t err_code = socket_recv(&p_socket_entry->handle, p_buf, buf_size, &recv_size, flags); if (err_code == NRF_SUCCESS) { ret = (ssize_t) recv_size; } socket_set_errno(err_code); } else { set_errno(ENOTCONN); } return ret; }
int connect(int sock, const void * p_addr, socklen_t addrlen) { VERIFY_MODULE_IS_INITIALIZED(); VERIFY_SOCKET_ID(sock); NULL_PARAM_CHECK(p_addr); SOCKET_MUTEX_LOCK(); socket_entry_t * p_socket_entry = &m_socket_table[sock]; SOCKET_MUTEX_UNLOCK(); int ret = -1; if (p_socket_entry->state == STATE_OPEN) { uint32_t err_code = p_socket_entry->handler->connect_handler(&p_socket_entry->handle, p_addr, addrlen); if (err_code == NRF_SUCCESS) { p_socket_entry->state = STATE_CONNECTED; ret = 0; } socket_set_errno(err_code); } else if (p_socket_entry->state == STATE_CONNECTED) { set_errno(EISCONN); } else if (p_socket_entry->state == STATE_CLOSED) { set_errno(EBADF); } return ret; }
/* * Receive a token from a file descriptor. Takes the file descriptor, a * buffer into which to store the token, a pointer into which to store the * flags, and the maximum token length we're willing to accept. Returns * TOKEN_OK on success. On failure, returns one of: * * TOKEN_FAIL_SYSTEM System call failed, errno set * TOKEN_FAIL_SOCKET Socket call failed, socket_errno set * TOKEN_FAIL_INVALID Invalid token format * TOKEN_FAIL_LARGE Token data larger than provided limit * TOKEN_FAIL_EOF Unexpected end of file * TOKEN_FAIL_TIMEOUT Timeout receiving token * * TOKEN_FAIL_SYSTEM and TOKEN_FAIL_SOCKET are the same on UNIX but different * on Windows. * * recv_token reads the token flags (a single byte, even though they're stored * into an integer, then reads the token length (as a network long), allocates * memory to hold the data, and then reads the token data from the file * descriptor. On a successful return, the value member of the token should * be freed with free(). */ enum token_status token_recv(socket_type fd, int *flags, gss_buffer_t tok, size_t max, time_t timeout) { OM_uint32 len; unsigned char char_flags; int err; if (!network_read(fd, &char_flags, 1, timeout)) return map_socket_error(socket_errno); *flags = char_flags; if (!network_read(fd, &len, sizeof(OM_uint32), timeout)) return map_socket_error(socket_errno); tok->length = ntohl(len); if (tok->length > max) return TOKEN_FAIL_LARGE; if (tok->length == 0) { tok->value = NULL; return TOKEN_OK; } tok->value = malloc(tok->length); if (tok->value == NULL) return TOKEN_FAIL_SYSTEM; if (!network_read(fd, tok->value, tok->length, timeout)) { err = socket_errno; free(tok->value); socket_set_errno(err); return map_socket_error(err); } return TOKEN_OK; }
/* * Test the network read function with a timeout. We fork off a child process * that runs delay_writer, and then we read from the network twice, once with * a timeout and once without, and then try a third time when we should time * out. */ static void test_network_read(void) { socket_type fd, c; pid_t child; struct sockaddr_in sin; socklen_t slen; char buffer[4]; /* Create the listening socket. */ fd = network_bind_ipv4(SOCK_STREAM, "127.0.0.1", 11119); if (fd == INVALID_SOCKET) sysbail("cannot create or bind socket"); if (listen(fd, 1) < 0) sysbail("cannot listen to socket"); /* Fork off a child process that writes some data with delays. */ child = fork(); if (child < 0) sysbail("cannot fork"); else if (child == 0) { socket_close(fd); client_delay_writer("127.0.0.1"); } /* Set an alarm just in case our timeouts don't work. */ alarm(10); /* Accept the client connection. */ slen = sizeof(sin); c = accept(fd, &sin, &slen); if (c == INVALID_SOCKET) sysbail("cannot accept on socket"); /* Now test a couple of simple reads, with and without timeout. */ socket_set_errno(0); ok(network_read(c, buffer, sizeof(buffer), 0), "network_read"); ok(memcmp("one\n", buffer, sizeof(buffer)) == 0, "...with good data"); ok(network_read(c, buffer, sizeof(buffer), 1), "network_read with timeout"); ok(memcmp("two\n", buffer, sizeof(buffer)) == 0, "...with good data"); /* * The third read should abort with a timeout, since the writer is writing * with a ten second delay. */ ok(!network_read(c, buffer, sizeof(buffer), 1), "network_read aborted with timeout"); is_int(ETIMEDOUT, socket_errno, "...with correct error"); ok(memcmp("two\n", buffer, sizeof(buffer)) == 0, "...and data unchanged"); alarm(0); /* Clean up. */ socket_close(c); kill(child, SIGTERM); waitpid(child, NULL, 0); socket_close(fd); }
int socket(socket_family_t family, socket_type_t type, socket_protocol_t protocol) { if (m_initialization_state == false) { (void) socket_init(); } VERIFY_MODULE_IS_INITIALIZED(); int ret_sock = -1; int sock = socket_allocate(); SOCKET_TRACE("Got value %d from allocate\r\n", (int)sock); if (sock >= 0) { socket_entry_t *p_socket_entry = &m_socket_table[sock]; p_socket_entry->handle.params.family = family; p_socket_entry->handle.params.protocol = protocol; p_socket_entry->handle.params.type = type; p_socket_entry->handler = NULL; if (family == AF_INET6) { #if SOCKET_IPV6_ENABLE == 1 || SOCKET_LWIP_ENABLE == 1 p_socket_entry->handler = &transport_handler; #else set_errno(EAFNOSUPPORT); #endif // } else if (family == AF_BLE) { // TODO: Handle BLE } else { set_errno(EAFNOSUPPORT); } if (p_socket_entry->handler != NULL) { uint32_t err_code = p_socket_entry->handler->create_handler(&p_socket_entry->handle); socket_set_errno(err_code); ret_sock = (err_code == NRF_SUCCESS) ? sock : ret_sock; } if (ret_sock < 0) { socket_free(sock); } } SOCKET_TRACE("Returning socket value %d\r\n", (int)ret_sock); return ret_sock; }