📄 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 + -