Skip to content

Commit

Permalink
add loopback by multi-socketset
Browse files Browse the repository at this point in the history
  • Loading branch information
lhw2002426 committed Jul 22, 2024
1 parent a66b4bb commit a532ca4
Show file tree
Hide file tree
Showing 15 changed files with 4,107 additions and 191 deletions.
3,458 changes: 3,458 additions & 0 deletions api/arceos_posix_api/src/ctypes_gen.rs

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions apps/c/httpserver_loopback/axbuild.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
app-objs := httpserver.o
4 changes: 4 additions & 0 deletions apps/c/httpserver_loopback/features.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
alloc
paging
net
multitask
139 changes: 139 additions & 0 deletions apps/c/httpserver_loopback/httpserver.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
/* Copyright (c) [2023] [Syswonder Community]
* [Ruxos] is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <arpa/inet.h>
#include <sys/socket.h>

#define PORT 5555
#define BUFFER_SIZE 1024

void *handle_client(void *arg) {
int new_socket = *(int*)arg;
char buffer[BUFFER_SIZE] = {0};

read(new_socket, buffer, BUFFER_SIZE);
printf("Server received: %s\n", buffer);
send(new_socket, "Hello from server", strlen("Hello from server"), 0);
printf("Server sent: %s\n", "Hello from server");

close(new_socket);
free(arg); // Free the allocated memory for the socket

return NULL;
}

void *server_thread(void *arg) {
int server_fd, *new_socket;
struct sockaddr_in address;
int addrlen = sizeof(address);

if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
perror("Socket failed");
exit(EXIT_FAILURE);
}

address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(PORT);

if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {
perror("Bind failed");
close(server_fd);
exit(EXIT_FAILURE);
}

if (listen(server_fd, 3) < 0) {
perror("Listen failed");
close(server_fd);
exit(EXIT_FAILURE);
}

printf("Server listening on 127.0.0.1:%d\n", PORT);

while (1) {
new_socket = malloc(sizeof(int));
if ((*new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen)) < 0) {
perror("Accept failed");
free(new_socket);
continue;
}

pthread_t client_thread;
if (pthread_create(&client_thread, NULL, handle_client, new_socket) != 0) {
perror("Failed to create client thread");
free(new_socket);
}
}

close(server_fd);

return NULL;
}

void *client_thread(void *arg) {
sleep(1); // Ensure the server is listening before the client tries to connect

struct sockaddr_in serv_addr;
char *message = "Hello from client";
char buffer[BUFFER_SIZE] = {0};
int sock = 0;

if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
perror("Socket creation error");
return NULL;
}

serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(PORT);

if (inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr) <= 0) {
perror("Invalid address / Address not supported");
close(sock);
return NULL;
}

if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
perror("Connection failed");
close(sock);
return NULL;
}

send(sock, message, strlen(message), 0);
printf("Client sent: %s\n", message);
read(sock, buffer, BUFFER_SIZE);
printf("Client received: %s\n", buffer);

close(sock);

return NULL;
}

int main() {
pthread_t server_tid, client_tid;

if (pthread_create(&server_tid, NULL, server_thread, NULL) != 0) {
perror("Failed to create server thread");
exit(EXIT_FAILURE);
}

if (pthread_create(&client_tid, NULL, client_thread, NULL) != 0) {
perror("Failed to create client thread");
exit(EXIT_FAILURE);
}

pthread_join(server_tid, NULL);
pthread_join(client_tid, NULL);

return 0;
}
2 changes: 2 additions & 0 deletions crates/driver_net/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ use alloc::sync::Arc;
#[cfg(feature = "ixgbe")]
/// ixgbe NIC device driver.
pub mod ixgbe;
/// loopback device driver
pub mod loopback;
mod net_buf;

use core::ptr::NonNull;
Expand Down
126 changes: 126 additions & 0 deletions crates/driver_net/src/loopback.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
/* Copyright (c) [2023] [Syswonder Community]
* [Ruxos] is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
use crate::{EthernetAddress, NetBuf, NetBufBox, NetBufPool, NetBufPtr, NetDriverOps};
use alloc::collections::VecDeque;
use alloc::sync::Arc;
use driver_common::{BaseDriverOps, DevError, DevResult, DeviceType};

extern crate alloc;

const NET_BUF_LEN: usize = 1526;

/// The VirtIO network device driver.
///
/// `QS` is the VirtIO queue size.
pub struct LoopbackDevice {
mac_address: EthernetAddress,
pub(crate) queue: VecDeque<NetBufBox>,
buf_pool: Arc<NetBufPool>,
}

unsafe impl Send for LoopbackDevice {}
unsafe impl Sync for LoopbackDevice {}

impl LoopbackDevice {
/// Creates a new driver instance and initializes the device
pub fn new(mac_address: [u8; 6]) -> Self {
let buf_pool = match NetBufPool::new(1024, NET_BUF_LEN) {
Ok(pool) => pool,
Err(_) => {
panic!("fail to create netbufpool");
}
};
Self {
mac_address: EthernetAddress(mac_address),
queue: VecDeque::new(),
buf_pool: buf_pool,
}
}
}

impl BaseDriverOps for LoopbackDevice {
fn device_name(&self) -> &str {
"loopback"
}

fn device_type(&self) -> DeviceType {
DeviceType::Net
}
}

impl NetDriverOps for LoopbackDevice {
#[inline]
fn mac_address(&self) -> EthernetAddress {
EthernetAddress(self.mac_address.0)
}

#[inline]
fn can_transmit(&self) -> bool {
true
}

#[inline]
fn can_receive(&self) -> bool {
!self.queue.is_empty()
}

#[inline]
fn rx_queue_size(&self) -> usize {
self.queue.len()
}

#[inline]
fn tx_queue_size(&self) -> usize {
self.queue.len()
}

fn fill_rx_buffers(&mut self, buf_pool: &Arc<NetBufPool>) -> DevResult {
Ok(())
}

fn recycle_rx_buffer(&mut self, rx_buf: NetBufPtr) -> DevResult {
Ok(())
}

fn recycle_tx_buffers(&mut self) -> DevResult {
Ok(())
}

fn prepare_tx_buffer(&self, tx_buf: &mut NetBuf, pkt_len: usize) -> DevResult {
Ok(())
}

fn transmit(&mut self, tx_buf: NetBufPtr) -> DevResult {
unsafe { self.queue.push_back(NetBuf::from_buf_ptr(tx_buf)) }
Ok(())
}

fn receive(&mut self) -> DevResult<NetBufPtr> {
if let Some(token) = self.queue.pop_front() {
Ok(token.into_buf_ptr())
} else {
Err(DevError::Again)
}
}

fn alloc_tx_buffer(&mut self, size: usize) -> DevResult<NetBufPtr> {
let mut net_buf = self.buf_pool.alloc_boxed().ok_or(DevError::NoMemory)?;
let pkt_len = size;

// 1. Check if the buffer is large enough.
let hdr_len = net_buf.header_len();
if hdr_len + pkt_len > net_buf.capacity() {
return Err(DevError::InvalidParam);
}
net_buf.set_packet_len(pkt_len);

// 2. Return the buffer.
Ok(net_buf.into_buf_ptr())
}
}
2 changes: 1 addition & 1 deletion modules/ruxfs/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ features = [ # no std
]

[dev-dependencies]
ruxdriver = { path = "../ruxdriver", features = ["block", "ramdisk"] }
ruxdriver = { path = "../ruxdriver", features = ["block", "ramdisk", "dyn"] }
driver_block = { path = "../../crates/driver_block", features = ["ramdisk"] }
axsync = { path = "../axsync", features = ["multitask"] }
ruxtask = { path = "../ruxtask", features = ["test"] }
4 changes: 3 additions & 1 deletion modules/ruxfs/tests/test_fatfs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@ fn test_fatfs() {
// By default, mount_points[0] will be rootfs
let mut mount_points: Vec<ruxfs::MountPoint> = Vec::new();
// setup and initialize blkfs as one mountpoint for rootfs
mount_points.push(ruxfs::init_blkfs(AxDeviceContainer::from_one(disk)));
mount_points.push(ruxfs::init_blkfs(AxDeviceContainer::from_one(Box::new(
disk,
))));
ruxfs::prepare_commonfs(&mut mount_points);

// setup and initialize rootfs
Expand Down
4 changes: 2 additions & 2 deletions modules/ruxfs/tests/test_ramfs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,9 @@ fn test_ramfs() {
// By default, mount_points[0] will be rootfs
let mut mount_points: Vec<ruxfs::MountPoint> = Vec::new();
// setup and initialize blkfs as one mountpoint for rootfs
mount_points.push(ruxfs::init_blkfs(AxDeviceContainer::from_one(
mount_points.push(ruxfs::init_blkfs(AxDeviceContainer::from_one(Box::new(
RamDisk::default(),
)));
))));
ruxfs::prepare_commonfs(&mut mount_points);

// setup and initialize rootfs
Expand Down
2 changes: 1 addition & 1 deletion modules/ruxnet/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ ruxhal = { path = "../ruxhal" }
axsync = { path = "../axsync" }
axlog = { path = "../axlog" }
ruxtask = { path = "../ruxtask" }
ruxdriver = { path = "../ruxdriver", features = ["net"] }
ruxdriver = { path = "../ruxdriver", features = ["net", "dyn"] }
cty = { version = "0.2.2", optional = true }
axio = { path = "../../crates/axio" }

Expand Down
Loading

0 comments on commit a532ca4

Please sign in to comment.