/* * socket.c - socket API implementation. * * Authors Alain Greiner (2016,2017,2018,2019,2020) * * Copyright (c) UPMC Sorbonne Universites * * This file is part of ALMOS-MKH. * * ALMOS-MKH.is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2.0 of the License. * * ALMOS-MKH.is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with ALMOS-MKH.; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include #include #include #include #include #include ////////////////////////////////////////////////////////////////////////////////////// // Extern global variables ////////////////////////////////////////////////////////////////////////////////////// extern chdev_directory_t chdev_dir; // allocated in kernel_init.c ////////////////////////////////////// char * socket_cmd_str( uint32_t type ) { switch( type ) { case SOCKET_TX_CONNECT : return "CONNECT"; case SOCKET_TX_SEND : return "SEND"; case SOCKET_TX_CLOSE : return "CLOSE"; default: return "undefined"; } } ///////////////////////////////////////// char * socket_state_str( uint32_t state ) { switch( state ) { case UDP_STATE_UNBOUND : return "UDP_UNBOUND"; case UDP_STATE_BOUND : return "UDP_BOUND"; case UDP_STATE_CONNECT : return "UDP_CONNECT"; case TCP_STATE_UNBOUND : return "TCP_UNBOUND"; case TCP_STATE_BOUND : return "TCP_BOUND"; case TCP_STATE_LISTEN : return "TCP_LISTEN"; case TCP_STATE_SYN_SENT : return "TCP_SYN_SENT"; case TCP_STATE_SYN_RCVD : return "TCP_SYN_RCVD"; case TCP_STATE_ESTAB : return "TCP_ESTAB"; case TCP_STATE_FIN_WAIT1 : return "TCP_FIN_WAIT1"; case TCP_STATE_FIN_WAIT2 : return "TCP_FIN_WAIT2"; case TCP_STATE_CLOSING : return "TCP_CLOSING"; case TCP_STATE_TIME_WAIT : return "TCP_TIME_WAIT"; case TCP_STATE_CLOSE_WAIT : return "TCP_CLOSE_WAIT"; case TCP_STATE_LAST_ACK : return "TCP_LAST_ACK"; default: return "undefined"; } } /////////////////////////////////////// error_t socket_create( cxy_t cxy, uint32_t domain, uint32_t type, socket_t ** socket_ptr, uint32_t * fdid_ptr ) { uint32_t fdid; thread_t * this = CURRENT_THREAD; process_t * process = this->process; kmem_req_t req; socket_t * socket; vfs_file_t * file; uint32_t state; error_t error; // allocate memory for socket descriptor req.type = KMEM_KCM; req.order = bits_log2( sizeof(socket_t) ); req.flags = AF_ZERO; socket = kmem_remote_alloc( cxy , &req ); if( socket == NULL ) { printk("\n[ERROR] in %s : cannot allocate socket descriptor / thread[%x,%x]\n", __FUNCTION__, process->pid, this->trdid ); return -1; } // allocate memory for rx_buf buffer error = remote_buf_create( XPTR( cxy , &socket->rx_buf ), NIC_RX_BUF_SIZE ); if( error ) { printk("\n[ERROR] in %s : cannot allocate rx_buf / thread[%x,%x]\n", __FUNCTION__, process->pid, this->trdid ); req.type = KMEM_KCM; req.ptr = socket; kmem_remote_free( cxy , &req ); return -1; } // allocate memory for r2tq queue error = remote_buf_create( XPTR( cxy , &socket->r2tq ), NIC_R2T_QUEUE_SIZE ); if( error ) { printk("\n[ERROR] in %s : cannot allocate R2T queue / thread[%x,%x]\n", __FUNCTION__, process->pid, this->trdid ); remote_buf_destroy( XPTR( cxy , &socket->rx_buf ) ); req.type = KMEM_KCM; req.ptr = socket; kmem_remote_free( cxy , &req ); return -1; } // allocate memory for crqq queue error = remote_buf_create( XPTR( cxy , &socket->crqq ), NIC_CRQ_QUEUE_SIZE * sizeof(sockaddr_t) ); if( error ) { printk("\n[ERROR] in %s : cannot allocate CRQ queue / thread[%x,%x]\n", __FUNCTION__, process->pid, this->trdid ); remote_buf_destroy( XPTR( cxy , &socket->r2tq ) ); remote_buf_destroy( XPTR( cxy , &socket->rx_buf ) ); req.type = KMEM_KCM; req.ptr = socket; kmem_remote_free( cxy , &req ); return -1; } // allocate memory for file descriptor req.type = KMEM_KCM; req.order = bits_log2( sizeof(vfs_file_t) ); req.flags = AF_ZERO; file = kmem_remote_alloc( cxy , &req ); if( file == NULL ) { printk("\n[ERROR] in %s : cannot allocate file descriptor / thread[%x,%x]\n", __FUNCTION__, process->pid, this->trdid ); remote_buf_destroy( XPTR( cxy , &socket->crqq ) ); remote_buf_destroy( XPTR( cxy , &socket->r2tq ) ); remote_buf_destroy( XPTR( cxy , &socket->rx_buf ) ); req.type = KMEM_KCM; req.ptr = socket; kmem_remote_free( cxy , &req ); return -1; } // get an fdid value, and register file descriptor in fd_array[] error = process_fd_register( process->ref_xp, XPTR( cxy , file ), &fdid ); if ( error ) { printk("\n[ERROR] in %s : cannot register file descriptor / thread[%x,%x]\n", __FUNCTION__, process->pid, this->trdid ); req.type = KMEM_KCM; req.ptr = file; kmem_free( &req ); remote_buf_destroy( XPTR( cxy , &socket->crqq ) ); remote_buf_destroy( XPTR( cxy , &socket->r2tq ) ); remote_buf_destroy( XPTR( cxy , &socket->rx_buf ) ); req.ptr = socket; kmem_free( &req ); return -1; } state = (type == SOCK_STREAM) ? TCP_STATE_UNBOUND : UDP_STATE_UNBOUND; // initialise socket descriptor hal_remote_s32( XPTR( cxy , &socket->domain ) , domain ); hal_remote_s32( XPTR( cxy , &socket->type ) , type ); hal_remote_s32( XPTR( cxy , &socket->pid ) , process->pid ); hal_remote_s32( XPTR( cxy , &socket->state ) , state ); hal_remote_s64( XPTR( cxy , &socket->tx_client ) , XPTR_NULL ); hal_remote_s64( XPTR( cxy , &socket->rx_client ) , XPTR_NULL ); // initialize file descriptor hal_remote_s32( XPTR( cxy , &file->type ) , INODE_TYPE_SOCK ); hal_remote_spt( XPTR( cxy , &file->socket ) , socket ); hal_remote_s32( XPTR( cxy , &file->refcount ) , 1 ); remote_rwlock_init( XPTR( cxy , &file->lock ) , LOCK_VFS_FILE ); // return success *socket_ptr = socket; *fdid_ptr = fdid; return 0; } // end socket_create //////////////////////////////////// void socket_destroy( uint32_t fdid ) { uint32_t type; socket_t * socket; kmem_req_t req; thread_t * this = CURRENT_THREAD; process_t * process = this->process; // get pointers on file descriptor xptr_t file_xp = process_fd_get_xptr( process , fdid ); vfs_file_t * file = GET_PTR( file_xp ); cxy_t cxy = GET_CXY( file_xp ); type = hal_remote_l32( XPTR( cxy , &file->type ) ); socket = hal_remote_lpt( XPTR( cxy , &file->socket ) ); // check file descriptor pointer assert( (file_xp != XPTR_NULL), "illegal fdid\n" ); // check file descriptor type assert( (type == INODE_TYPE_SOCK), "illegal file type\n" ); // remove the file descriptor from the process process_fd_remove( process->owner_xp , fdid ); // release memory allocated for file descriptor req.type = KMEM_KCM; req.ptr = file; kmem_remote_free( cxy , &req ); // release memory allocated for buffers attached to socket descriptor remote_buf_destroy( XPTR( cxy , &socket->crqq ) ); remote_buf_destroy( XPTR( cxy , &socket->r2tq ) ); remote_buf_destroy( XPTR( cxy , &socket->rx_buf ) ); // release memory allocated for socket descriptor req.type = KMEM_KCM; req.ptr = socket; kmem_remote_free( cxy , &req ); } // end socket_destroy() ///////////////////////////////////////////////// void socket_link_to_servers( xptr_t socket_xp, uint32_t nic_channel ) { cxy_t socket_cxy = GET_CXY( socket_xp ); socket_t * socket_ptr = GET_PTR( socket_xp ); // get pointers on NIC_TX[index] chdev xptr_t tx_chdev_xp = chdev_dir.nic_tx[nic_channel]; chdev_t * tx_chdev_ptr = GET_PTR( tx_chdev_xp ); cxy_t tx_chdev_cxy = GET_CXY( tx_chdev_xp ); // build extended pointers on root of sockets attached to NIC_TX[channel] chdev xptr_t tx_root_xp = XPTR( tx_chdev_cxy , &tx_chdev_ptr->wait_root ); xptr_t tx_lock_xp = XPTR( tx_chdev_cxy , &tx_chdev_ptr->wait_lock ); // register socket in the NIC_TX[channel] chdev clients queue remote_rwlock_wr_acquire( tx_lock_xp ); xlist_add_last( tx_root_xp , XPTR( socket_cxy , &socket_ptr->tx_list ) ); remote_rwlock_wr_release( tx_lock_xp ); // get pointers on NIC_RX[index] chdev xptr_t rx_chdev_xp = chdev_dir.nic_rx[nic_channel]; chdev_t * rx_chdev_ptr = GET_PTR( rx_chdev_xp ); cxy_t rx_chdev_cxy = GET_CXY( rx_chdev_xp ); // build extended pointer on root of sockets attached to NIC_TX[channel] chdev xptr_t rx_root_xp = XPTR( rx_chdev_cxy , &rx_chdev_ptr->wait_root ); xptr_t rx_lock_xp = XPTR( rx_chdev_cxy , &rx_chdev_ptr->wait_lock ); // register socket in the NIC_RX[channel] chdev clients queue remote_rwlock_wr_acquire( rx_lock_xp ); xlist_add_last( rx_root_xp , XPTR( socket_cxy , &socket_ptr->rx_list ) ); remote_rwlock_wr_release( rx_lock_xp ); } // end socket_link_to_server()