📄 sim_serial_forwarder.c
字号:
/* * Copyright (c) 2007 Toilers Research Group - Colorado School of Mines * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the * distribution. * - Neither the name of Toilers Research Group - Colorado School of * Mines nor the names of its contributors may be used to endorse * or promote products derived from this software without specific * prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL STANFORD * UNIVERSITY OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. *//** * Author: Chad Metcalf * Date: July 9, 2007 * * The serial forwarder for TOSSIM * */#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <netdb.h>#include <errno.h>#include <fcntl.h>#include <unistd.h>#include <stdlib.h>#include <stdio.h>#include <string.h>#include <signal.h>#include "sim_serial_forwarder.h"#include "sim_serial_packet.h"#include "sim_tossim.h"struct sim_sf_client_list *sim_sf_clients;int sim_sf_server_socket;int sim_sf_packets_read, sim_sf_packets_written, sim_sf_num_clients;int sim_sf_unix_check(const char *msg, int result){ if (result < 0) { perror(msg); exit(2); } return result;}void *sim_sf_xmalloc(size_t s){ void *p = malloc(s); if (!p) { fprintf(stderr, "out of memory\n"); exit(2); } return p;}void sim_sf_fd_wait(fd_set *fds, int *maxfd, int fd){ if (fd > *maxfd) *maxfd = fd; FD_SET(fd, fds);}void sim_sf_pstatus(void){ printf("clients %d, read %d, wrote %d\n", sim_sf_num_clients, sim_sf_packets_read, sim_sf_packets_written);}void sim_sf_add_client(int fd){ struct sim_sf_client_list *c = (struct sim_sf_client_list*)sim_sf_xmalloc(sizeof *c); c->next = sim_sf_clients; sim_sf_clients = c; sim_sf_num_clients++; sim_sf_pstatus(); c->fd = fd;}void sim_sf_rem_client(struct sim_sf_client_list **c){ struct sim_sf_client_list *dead = *c; *c = dead->next; sim_sf_num_clients--; sim_sf_pstatus(); close(dead->fd); free(dead);}void sim_sf_new_client(int fd){ fcntl(fd, F_SETFL, 0); if (sim_sf_init_source(fd) < 0) close(fd); else sim_sf_add_client(fd);}void sim_sf_check_clients(fd_set *fds){ struct sim_sf_client_list **c; for (c = &sim_sf_clients; *c; ) { int isNext = 1; if (FD_ISSET((*c)->fd, fds)) { int len; const void *packet = sim_sf_read_packet((*c)->fd, &len); if (packet) { sim_sf_forward_packet(packet, len); free((void *)packet); } else { sim_sf_rem_client(c); isNext = 0; } } if (isNext) c = &(*c)->next; }}void sim_sf_wait_clients(fd_set *fds, int *maxfd){ struct sim_sf_client_list *c; for (c = sim_sf_clients; c; c = c->next) sim_sf_fd_wait(fds, maxfd, c->fd);}void sim_sf_dispatch_packet(const void *packet, int len){ struct sim_sf_client_list **c; char* dispatchPacket = (char*) sim_sf_xmalloc(len+1); memset(dispatchPacket, 0, len+1); memcpy(dispatchPacket+1, packet, len); for (c = &sim_sf_clients; *c; ) if (sim_sf_write_packet((*c)->fd, dispatchPacket, len+1) >= 0) { sim_sf_packets_written++; c = &(*c)->next; } else sim_sf_rem_client(c); free(dispatchPacket);}void sim_sf_open_server_socket(int port){ struct sockaddr_in me; int opt; sim_sf_server_socket = sim_sf_unix_check("socket", socket(AF_INET, SOCK_STREAM, 0)); sim_sf_unix_check("socket", fcntl(sim_sf_server_socket, F_SETFL, O_NONBLOCK)); memset(&me, 0, sizeof me); me.sin_family = AF_INET; me.sin_port = htons(port); opt = 1; sim_sf_unix_check("setsockopt", setsockopt(sim_sf_server_socket, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(opt))); sim_sf_unix_check("bind", bind(sim_sf_server_socket, (struct sockaddr *)&me, sizeof me)); sim_sf_unix_check("listen", listen(sim_sf_server_socket, 5));}void sim_sf_check_new_client(void){ int clientfd = accept(sim_sf_server_socket, NULL, NULL); if (clientfd >= 0) sim_sf_new_client(clientfd);}void sim_sf_forward_packet(const void *packet, int len){ char* forwardPacket = (char*)packet + 1; uint16_t addr = sim_serial_packet_destination((struct sim_serial_packet*)forwardPacket); sim_serial_packet_deliver(addr, (struct sim_serial_packet*)forwardPacket, sim_time()); sim_sf_packets_read++;}void sim_sf_process (){ fd_set rfds; int maxfd = -1; struct timeval zero; int ret; zero.tv_sec = zero.tv_usec = 0; FD_ZERO(&rfds); sim_sf_fd_wait(&rfds, &maxfd, sim_sf_server_socket); sim_sf_wait_clients(&rfds, &maxfd); ret = select(maxfd + 1, &rfds, NULL, NULL, &zero); if (ret >= 0) { if (FD_ISSET(sim_sf_server_socket, &rfds)) sim_sf_check_new_client(); sim_sf_check_clients(&rfds); }}int sim_sf_saferead(int fd, void *buffer, int count){ int actual = 0; while (count > 0) { int n = read(fd, buffer, count); if (n == -1 && errno == EINTR) continue; if (n == -1) return -1; if (n == 0) return actual; count -= n; actual += n; buffer = (char*)buffer + n; } return actual;}int sim_sf_safewrite(int fd, const void *buffer, int count){ int actual = 0; while (count > 0) { int n = write(fd, buffer, count); if (n == -1 && errno == EINTR) continue; if (n == -1) return -1; count -= n; actual += n; buffer = (char*)buffer + n; } return actual;}int sim_sf_open_source(const char *host, int port)/* Returns: file descriptor for serial forwarder at host:port */{ int fd = socket(AF_INET, SOCK_STREAM, 0); struct hostent *entry; struct sockaddr_in addr; if (fd < 0) return fd; entry = gethostbyname(host); if (!entry) { close(fd); return -1; } addr.sin_family = entry->h_addrtype; memcpy(&addr.sin_addr, entry->h_addr, entry->h_length); addr.sin_port = htons(port); if (connect(fd, (struct sockaddr *)&addr, sizeof addr) < 0) { close(fd); return -1; } if (sim_sf_init_source(fd) < 0) { close(fd); return -1; } return fd;}int sim_sf_init_source(int fd)/* Effects: Checks that fd is following the TinyOS 2.0 serial forwarder protocol. Use this if you obtain your file descriptor from some other source than open_sf_source (e.g., you're a server) Returns: 0 if it is, -1 otherwise */{ char check[2], us[2]; int version; /* Indicate version and check if a TinyOS 2.0 serial forwarder on the other end */ us[0] = 'U'; us[1] = ' '; if (sim_sf_safewrite(fd, us, 2) != 2 || sim_sf_saferead(fd, check, 2) != 2 || check[0] != 'U') return -1; version = check[1]; if (us[1] < version) version = us[1]; /* Add other cases here for later protocol versions */ switch (version) { case ' ': break; default: return -1; /* not a valid version */ } return 0;}void *sim_sf_read_packet(int fd, int *len)/* Effects: reads packet from serial forwarder on file descriptor fd Returns: the packet read (in newly allocated memory), and *len is set to the packet length, or NULL for failure*/{ unsigned char l; void *packet; if (sim_sf_saferead(fd, &l, 1) != 1) return NULL; packet = malloc(l); if (!packet) return NULL; if (sim_sf_saferead(fd, packet, l) != l) { free(packet); return NULL; } *len = l; return packet;}int sim_sf_write_packet(int fd, const void *packet, int len)/* Effects: writes len byte packet to serial forwarder on file descriptor fd Returns: 0 if packet successfully written, -1 otherwise*/{ unsigned char l = len; if (sim_sf_safewrite(fd, &l, 1) != 1 || sim_sf_safewrite(fd, packet, l) != l) return -1; return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -