/* The port of TinySec to the MICAz motes is (c) 2007-2008 University of Cambridge The original source code was adapted for the use of TinySec library on MICAz motes by Matt Lewis and Dan Cvrcek as part of WINES II - Smart Infrastructure EPSRC Project EP/D076870/1 http://www.winesinfrastructure.org/ The security-related part of this project was led by Frank Stajano. None of the above parties will provide support for this port. This port 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, either version 3 of the License, or (at your option) any later version. This program 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 this program. If not, see http://www.gnu.org/licenses/. Parts of the code are subject of Moteworks 2.0 license. See license.txt file in the MoteWorks distribution for details. */ /* tab:4 * IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. By * downloading, copying, installing or using the software you agree to * this license. If you do not agree to this license, do not download, * */ /* tab:4 * "Copyright (c) 2000-2003 The Regents of the University of California. * All rights reserved. * * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose, without fee, and without written agreement is * hereby granted, provided that the above copyright notice, the following * two paragraphs and the author appear in all copies of this software. * * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS." * */ /* tab:4 * Copyright (c) 2003 Intel Corporation * All rights reserved Contributions to the above software program by Intel * Corporation is program is licensed subject to the BSD License, available at * http://www.opensource.org/licenses/bsd-license.html * */ /* * Authors: Mark Yarvis * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef VERSION #define VERSION "unknown" #endif #define DEFAULT_COM "COM1" #define DEFAULT_SERVER_PORT 9001 #define PERSISTENCE_CHECK_PERIOD 5000 #define MAX_IO_STREAMS 100 // The max number of characters that could be in either a raw or ASCII message #define MAX_MESSAGE_LEN 5000 #define BUFFER_SIZE (MAX_MESSAGE_LEN*3) char* comPorts[][2] = { { "COM1", "/dev/ttyS0"}, { "COM2", "/dev/ttyS1"}, { "COM3", "/dev/ttyS2"}, /* { "COM4", "/dev/tts/3"}, { "COM5", "/dev/tts/4"}, { "COM6", "/dev/tts/5"}, { "COM7", "/dev/tts/6"}, */ { 0, 0} }; #define MICA 1 #define MICA2 2 #define IMOTE 3 #define MAX_MOTE_TYPE 3 #define BAUD_RATE 0 #define USE_PREAMBLE 1 int mote_configs[][2] = { { 0, 0 }, // NOT USED { B19200, 0 }, // MICA { B57600, 1 }, // MICA2 { B115200, 0 } // Imote }; #define SF_VERSION_STRING "T " char uart_frame_vals[3] = {0x97, 0x53, 0x71}; char uart_preamble_vals[5] = {0xFF, 0x00, 0xFF, 0x00, 0xFF}; /*WINES wines - new variables for wines needs*/ int wines=0; //switch enabling creation of special files int sniffer=0; //switch enabling extra functions for network monitoring int client=0; unsigned char wines_buf[MAX_MESSAGE_LEN]; int wines_ptr=0; int wines_ptr_sync=0; int msgTypeFilter=0; unsigned char wines_data[256][10]; int exclude_heartbeat = 0; unsigned char wines_network[256][257]; int wines_motes=10; unsigned int file_number=0; unsigned int msg_record=0; unsigned int experiment=0; #define DC_DEBUG 0 // types #define CLIENT_SOCKET 1 #define SERVER_SOCKET 2 #define SERIAL_PORT 3 #define FW_SOCKET_OPEN 4 #define FW_SOCKET_CLOSE 5 // formats #define ASCII_FORMAT 1 #define RAW_FORMAT 2 #define FRAMED_FORMAT 3 // for communication with serial forwarder #define SF_FORMAT 4 #define DEMO_FORMAT 5 //for Wines demo application typedef struct { int fd; char name[100]; char buf[BUFFER_SIZE]; // input buffer int bufLen; // number of bytes in buffer char type; // char useRawIO; // char useFramedIO; // only valid for Raw IO char format; // only valid for Raw IO char writePreamble; char bePersistent; struct termios origtio; // original serial port settings to restore } ioStream; ioStream streams[MAX_IO_STREAMS]; ioStream *fw_socketStream; int numStreams = 0; char usePersistentSockets = 1; int packetLen = 0; // use for raw unframed communication only! void handleClientSocket(ioStream *s); void printUsage(char *progName) { printf("Usage: %s [-1 | -2 | -3] [ ... ] [ -r ] [ -sf :]\n", progName); printf(" Where is one of\n"); printf(" port - to create a server socket\n"); printf(" host:port - to connect to a server\n"); printf(" COMn - to connect to a comm port\n"); printf(" -SNIFFER - options for attack monitoring\n"); printf(" And additional options are\n"); printf(" -r - opens any subsequent comm ports for unframed\n"); printf(" and non-ascii communication with packets of\n"); printf(" the specified length\n"); printf(" -sf - opens any subsequent sockets for communication \n"); printf(" using the serial forwarder protocol\n"); printf(" -1 - opens any subsequent comm ports with a baud\n"); printf(" rate for RENE or MICA motes\n"); printf(" -2 - opens any subsequent comm ports with a baud\n"); printf(" rate for MICA2 motes\n"); printf(" -3 - opens any subsequent comm ports with a baud\n"); printf(" rate for XMesh motes\n"); printf(" -NoHB Exclude heartbeat packats from log file\n"); } uint64_t currentTimeMillis() { struct timeval tv; gettimeofday(&tv, 0); return ( ((uint64_t) tv.tv_sec) *1000) + (tv.tv_usec / 1000); } void restoreSerialSettings(ioStream *s) { if (s->type == SERIAL_PORT) { printf("Restoring serial settings on %s\n", s->name); tcsetattr(s->fd,TCSANOW,&(s->origtio)); } else { fprintf(stderr, "WARNING: Attempt to restore serial settings on "); fprintf(stderr, "non-serial file descriptor\n"); } } void cleanExit(int code) { int i; for (i=0; ibePersistent) { s->fd = -1; return; } if (s != &(streams[numStreams-1])) { // if not last entry // copy the last entry into the hole memcpy(s, &(streams[numStreams-1]), sizeof(ioStream)); } numStreams--; } int isNum(char *s) { if ((s == 0 ) || (*s == 0)) { // if NULL or a null string is passed, fail return 0; } while (*s != 0) { if ((*s > '9') || (*s < '0')) { return 0; } s++; } return 1; } void shiftBufferLeft(ioStream *s, int n) { int i; s->bufLen -= n; for (i=0; i < s->bufLen; i++) { s->buf[i] = s->buf[i+n]; } } int hexToDecimal(char c) { if ((c>='0') && (c<='9')) { return c - '0'; } else if ((c>='a') && (c<='f')) { return c - 'a' + 10; } else if ((c>='A') && (c<='F')) { return c - 'A' + 10; } else { fprintf(stderr, "ERROR: Bad character in hex value: %c\n", c); return 0; } } int switchToRawUnframedIO(char * arg) { if ((arg[0] == '-') && (arg[1] == 'r') && (isNum(arg+2))) { if (packetLen > 0) { // only allowed once! printUsage("uartserver"); cleanExit(0); } packetLen = atoi(arg+2); printf("Setting packet length for raw connections to %d\n", packetLen); return 1; } else { return 0; } } int writeMessage(int fd, char* buf, int buflen) { struct timeval zero_timeout; fd_set wfds, efds; int written=-1; FD_ZERO(&wfds); FD_SET(fd, &wfds); FD_ZERO(&efds); FD_SET(fd, &efds); zero_timeout.tv_sec = 0; zero_timeout.tv_usec = 0; if (select(fd+1, NULL, &wfds, &efds, &zero_timeout) > 0) { // printf("writee %d %d %s\n",fd, buflen,buf); written=write(fd, buf, buflen); } return written; } void write_bytes(int fd, const void *buf, size_t count) { #ifdef WRITE_PACE int i; for (i=0; i packetLen)) { printf("WARNING: attempt to write a long packet on a raw unframed port\n"); return; } out = (hexToDecimal(*(buf++))<<4); out |= hexToDecimal(*(buf++)); write_bytes(fd, &out, 1); } while (*(buf++) != '\n'); if ((format == RAW_FORMAT) && (i < packetLen)) { printf("WARNING: padding a short packet written to a raw unframed port\n"); out = 0; for (; i < packetLen; i++) { write_bytes(fd, &out, 1); } } } int isHexDigit(char c) { return (((c>='0') && (c<='9')) || ((c>='a') && (c<='f')) || ((c>='A') && (c<='F'))); } int isWhitespace(char c) { return ((c == ' ') || (c == '\t') || (c == '\r')); } // normalizes buf to the format "hh hh ... \n", where h is a hex digit // len may be shortened // the return value is 1 iff the conversion was successful int normalizeMessage(char *buf, int *len) { char out[BUFFER_SIZE]; int out_i=0; int i=0; while (1) { while ((i < *len) && isWhitespace(buf[i])) { // skip whitespace i++; } if (i >= *len) { return 0; // string can't end here } if (! isHexDigit(buf[i])) { // check first hex digit return 0; } out[out_i++] = buf[i++]; // copy byte if (i >= *len) { return 0; // string can't end here } if (! isHexDigit(buf[i])) { // check second hex digit return 0; } out[out_i++] = buf[i++]; // copy byte while ((i < *len) && isWhitespace(buf[i])) { // skip whitespace i++; } if (i >= *len) { return 0; // string can't end here } if (buf[i] == '\n') { // this is end of message out[out_i++] = '\n'; // add a newline to the end // update the length and copy the string back *len = out_i; bcopy(out, buf, *len); return 1; // success! } out[out_i++] = ' '; } } // should call normalizeMessage before calling this function void forwardMessage(char *buf, int n, ioStream *sourceStream) { int i; for (i=0; ifd<0)||(s->type==FW_SOCKET_CLOSE)){ s->type = FW_SOCKET_CLOSE; s->fd=-1; return; } if (s->type!=FW_SOCKET_OPEN){ return; } //len=read(s->fd, buff, 0); len=recv(s->fd, buff, sizeof(buff), MSG_PEEK | MSG_DONTWAIT); if (len==0){ s->type = FW_SOCKET_CLOSE; s->fd=-1; //printf ("Hurrayyyy\n"); } else if (len>0){ recv(s->fd, buff, sizeof(buff), MSG_DONTWAIT); if (strtod(buff,NULL)!=0) { msgTypeFilter=(int)strtod(buff,NULL) % 256; if (msgTypeFilter>0) printf("Message filter set to %d (%02X)\n",msgTypeFilter,msgTypeFilter); else printf("Message filter set to %d (-%02X)\n",msgTypeFilter,-msgTypeFilter); } else { msgTypeFilter=0; printf("Message filter reset!\n"); } buff[0]=0; } } void handleServerSocket(ioStream *s) { struct sockaddr_in sa; unsigned int addrlen; struct hostent *he; char *hostname=NULL; ioStream *newStream; int fd; addrlen = sizeof(sa); fd = accept(s->fd, (struct sockaddr *) &sa, &addrlen); if (fd < 0) { if (errno!=EAGAIN) { // it's nonblocking, so this is ok perror("accept()"); } return; } he = gethostbyaddr((char *) &(sa.sin_addr), 4, AF_INET); if (he == NULL) { char *bytes = (char *) &(sa.sin_addr); sa.sin_addr.s_addr = ntohl(sa.sin_addr.s_addr); hostname = (char *) malloc(16); sprintf(hostname, "%d.%d.%d.%d", bytes[0], bytes[1], bytes[2], bytes[3]); } else { hostname = (char *) malloc(strlen(he->h_name)+1); strcpy(hostname, he->h_name); } printf("Got connection from %s:%d to %s\n", hostname, ntohs(sa.sin_port), s->name); newStream = createStreamStruct(); newStream->fd = fd; newStream->type = CLIENT_SOCKET; newStream->format = s->format; sprintf(newStream->name, "%s:%d", hostname, ntohs(sa.sin_port)); if ((newStream->format == SF_FORMAT)&&(sniffer==0)) { char buf[2]; write(newStream->fd, SF_VERSION_STRING, 2); read(newStream->fd, buf, 2); } } char intToHexChar(int n) { if (n < 10) { return n + '0'; } else { return n - 10 + 'A'; } } char *byteToHexString(char b, char *s) { s[0] = intToHexChar((b>>4)&0xf); s[1] = intToHexChar(b&0xf); s[2] = '\0'; return s; } int fillBuffer(ioStream *s) { int n; n = read(s->fd, &(s->buf[s->bufLen]), BUFFER_SIZE - s->bufLen); if (n <= 0) { // close or EOF if (n < 0) { printf("Input %s failed: %s\n", s->name, strerror(errno)); } else { printf("Input %s closed\n", s->name); } if (s->type == SERIAL_PORT) { restoreSerialSettings(s); } close(s->fd); deleteStream(s); return 1; } s->bufLen += n; return 0; } int handleWinesOutput(ioStream *s, int bytes, int useBytes, int repeated, char *hexbuf){ int i=0,j; FILE *wine_fd; int msg_offset,offset; int min,value; unsigned char cycle[32]; char filename[32]; int sync_old; struct stat check_file; char forwardBuf[BUFFER_SIZE]; int inside; if ((!wines)&&(!sniffer)){ return 0; } else { if (DC_DEBUG) printf("Wines or sniffer is here\n"); } if ((repeated==0)&&(hexbuf==NULL)){ if (useBytes){ if (DC_DEBUG) printf("We have got some bytes %d\n",bytes); memcpy(wines_buf+wines_ptr, s->buf, bytes); wines_ptr= wines_ptr+bytes; } else { for (i=0; (i < s->bufLen); i++) { wines_buf[wines_ptr++]=s->buf[i]; } } } // we copy the new bytes into our internal buffer first if ((repeated==0)&&(hexbuf!=NULL)){ // printf("ok, we have got the message %d",wines_ptr); memcpy(wines_buf+wines_ptr, hexbuf, bytes); wines_ptr+=bytes; // printf(" %d\n",wines_ptr); } //zeroise the rest of buffer memset(wines_buf+wines_ptr,0,sizeof(wines_buf)-wines_ptr); if (DC_DEBUG){ printf("1 still alive, wines_ptr = %d %d\n",wines_ptr,wines_ptr_sync); printf("DBG: "); for(i=0;i0) if (wines_ptr_sync==0) inside=0; else inside=1; if ((client==0)||(sniffer==0)){ for (i=wines_ptr_sync; i0)&&(value path towards gateway\n"); printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"); printf("Table of path costs.\n"); fprintf(wine_fd,"Table of path costs\n"); for (i=1;i<10;i++){ if (wines_network[i][256]==0){ printf("%d| %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d 'parent': -\n",i,wines_network[i][0],wines_network[i][1],wines_network[i][2],wines_network[i][3],wines_network[i][4],wines_network[i][5],wines_network[i][6],wines_network[i][7],wines_network[i][8],wines_network[i][9]); fprintf(wine_fd,"%d| %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d 'parent': -\n",i,wines_network[i][0],wines_network[i][1],wines_network[i][2],wines_network[i][3],wines_network[i][4],wines_network[i][5],wines_network[i][6],wines_network[i][7],wines_network[i][8],wines_network[i][9]); } else { printf("%d| %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d 'parent': %d\n",i,wines_network[i][0],wines_network[i][1],wines_network[i][2],wines_network[i][3],wines_network[i][4],wines_network[i][5],wines_network[i][6],wines_network[i][7],wines_network[i][8],wines_network[i][9],wines_network[i][256]-1); fprintf(wine_fd,"%d| %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d 'parent':%d\n",i,wines_network[i][0],wines_network[i][1],wines_network[i][2],wines_network[i][3],wines_network[i][4],wines_network[i][5],wines_network[i][6],wines_network[i][7],wines_network[i][8],wines_network[i][9],wines_network[i][256]-1); } } printf("#ID|-> path towards gateway\n"); for (i=0;i<256;i++){ memset(cycle, 0, sizeof(cycle)); if (wines_network[i][256]>0){ fprintf(wine_fd,"%d| ",i); printf("%d| ",i); j=i; do { // printf("Cycle: %d\n",cycle[0]); cycle[j>>3]|=(1<<(j&0x7)); value=wines_network[j][256]; if (value<1){ fprintf(wine_fd,"-> ?"); printf("-> ?"); } else { fprintf(wine_fd,"-> %d (%5.2f) ",value-1,(float)wines_network[j][value-1]/256); printf("-> %d (%5.2f) ",value-1,(float)wines_network[j][value-1]/256); } j=value-1; } while ((value>1)&&((cycle[j>>3]&(1<<(j&0x7)))==0) ); fprintf(wine_fd,"\n"); printf("\n"); } } fclose(wine_fd); } else { //it is not debug/health message if (client==0) printf("."); // and we are not in the tapping mode } // we have processed a message and we can get rid of it //maybe???? //wines_buf[0]=0; memmove(wines_buf,wines_buf+wines_ptr_sync+1,(wines_ptr-wines_ptr_sync-1)); wines_ptr-=(wines_ptr_sync+1); wines_ptr_sync=0; // is there another message? if (DC_DEBUG) printf("DDDDD %d %d %d",7+wines_buf[6]+2,wines_buf[wines_buf[6]+7+2+7],wines_ptr); // if (7+wines_buf[6]+2+wines_buf[wines_buf[6]+7+2+7]+5>wines_ptr) if (wines_ptr_sync>=wines_ptr-1) return 0; else{ return 1; } } return 0; } void handleRawUnframedInput(ioStream *s, int bytesToRead) { int i; char scratch[3]; char output[BUFFER_SIZE]; int j; i=0; while (handleWinesOutput(s, bytesToRead, 1,i,NULL)){i=1;}; if (s->bufLen < bytesToRead) { return; // not enough bytes in the buffer yet } if (!(wines || sniffer)){ // create a message in ASCII format j=0; for (i=0; i < bytesToRead; i++) { if ((s->buf[i]==0x7d)&&(i+1buf[i+1]=s->buf[i+1]^0x20; i=i+1; } byteToHexString(s->buf[i], scratch); output[j++]=scratch[0]; output[j++]=scratch[1]; if (i < bytesToRead-1) { output[j++]=' '; } else { output[j++]='\n'; } } output[j]='\0'; // print out the message printf("%s", output); fflush(stdout); // forward the message forwardMessage(output, j, s); } // remove the packet bytes from the buffer and keep going shiftBufferLeft(s, bytesToRead); } void handleSFInput(ioStream *s) { int len; if (s->bufLen < 2) { return; // not enough bytes in the buffer yet } len = (s->buf[0] & 0xFF); shiftBufferLeft(s, 1); handleRawUnframedInput(s, len); } void handleRawFramedInput(ioStream *s) { int i; if (fillBuffer(s)) { return; } i=0; while (handleWinesOutput(s,0,0,i,NULL)){i=1;}; while (1) { char scratch[3]; // throw away bytes until we see first byte of uart frame if (sniffer==0){ for (i=0; (i < s->bufLen) && (s->buf[i] != uart_frame_vals[0]); i++) { if ((s->buf[i]==0x7d)&&(i+1 < s->bufLen)){ s->buf[i+1] ^= 0x20; i++; } if ((sniffer==0)||(DC_DEBUG==1)) printf("(%s) ", byteToHexString(s->buf[i], scratch)); } } else { for (i=0; (i < s->bufLen); i++) { if ((s->buf[i]==0x7d)&&(i+1 < s->bufLen)){ s->buf[i+1] ^= 0x20; i++; } if ((sniffer==0)||(DC_DEBUG==1)) printf("(%s) ", byteToHexString(s->buf[i], scratch)); } } fflush(stdout); shiftBufferLeft(s, i); // if there aren't enough bytes for a whole frame, wait for more if (s->bufLen < 4) { //4 is an arbitrary? (is it?) value return; } // is this a frame? if (sniffer==0){ //only for non sniffer modes if ((s->buf[1] != uart_frame_vals[1]) || (s->buf[2] != uart_frame_vals[2])) { // not a frame, discard the "frame start" byte and keep going if ((unsigned char)(s->buf[0])==0x7d){ s->buf[1]=s->buf[1]^0x20; } else if ((sniffer==0)||(DC_DEBUG==1)) printf("(%s) ", byteToHexString(s->buf[0], scratch)); fflush(stdout); shiftBufferLeft(s, 1); } else { // this is the frame char output[BUFFER_SIZE]; int len = s->buf[3]; int j; // is the entire packet in the buffer? if (s->bufLen < len + 4) { return; // no, wait for more data } // print out the frame for (i=0; i<4; i++) { printf("[%s] ", byteToHexString(s->buf[i], scratch)); } // create a message in ASCII format j=0; for (i=4; i < len + 4; i++) { byteToHexString(s->buf[i], scratch); output[j++]=scratch[0]; output[j++]=scratch[1]; if (i < len+3) { output[j++]=' '; } else { output[j++]='\n'; } } output[j]='\0'; // print out the message printf("%s", output); fflush(stdout); // forward the message forwardMessage(output, j, s); // remove the packet bytes from the buffer and keep going shiftBufferLeft(s, len + 4); } } } } void handleAsciiInput(ioStream *s) { int bytesRead, i, offset; char hexBuf[MAX_MESSAGE_LEN]; bytesRead = read(s->fd, &(s->buf[s->bufLen]), BUFFER_SIZE - s->bufLen); if ((sniffer==1)&&(bytesRead>0)){ // change to hex array i=s->bufLen; offset=1; hexBuf[0]=0x7e; // hexBuf[1]=0x42; // printf("Do not know - we got %d bytes\n",bytesRead);; while (i < bytesRead+s->bufLen){ if (s->buf[i]<0x30){ break; //it is \n that we do not need } hexBuf[offset]=16 * ((s->buf[i]&0xf)+((s->buf[i]&0x40)>>6)*9); hexBuf[offset]+=((s->buf[i+1]&0xf)+((s->buf[i+1]&0x40)>>6)*9); // printf("%c%c %02X \n",s->buf[i],s->buf[i+1],(unsigned char)hexBuf[offset]); i=i+3; offset++; } hexBuf[offset++]=0x7e; // printf("called our handle\n"); i=0; while (handleWinesOutput(NULL, offset,0,i,hexBuf)){i=1;}; } if (bytesRead <= 0) { // close or EOF if (bytesRead < 0) { printf("Input %s failed: %s\n", s->name, strerror(errno)); } else { printf("Input %s closed\n", s->name); } close(s->fd); deleteStream(s); } else { int i; s->bufLen += bytesRead; i = 0; while (i < s->bufLen) { if (s->buf[i] == '\n') { char buf[BUFFER_SIZE]; int msgLen=i+1; bcopy(s->buf, buf, msgLen); if (normalizeMessage(buf, &msgLen)) { buf[msgLen]=0; if (sniffer==0) printf("Forwarding message from %s: %s\n", s->name, buf); else printf("%s",buf); forwardMessage(buf, msgLen, s); } else { bcopy(s->buf, buf, i+1); buf[i+1]=0; fprintf(stderr, "Bad message format: %s\n", buf); } shiftBufferLeft(s, i+1); i=0; } else { i++; } } } } void handleInput(ioStream *s) { if (s->type == SERVER_SOCKET) { handleServerSocket(s); } else if (s->type == FW_SOCKET_OPEN) { handleClientSocket(s); } else if (s->format == ASCII_FORMAT) { handleAsciiInput(s); } else if (s->format == FRAMED_FORMAT) { handleRawFramedInput(s); } else if ((s->format == RAW_FORMAT) || (s->format == SF_FORMAT)) { if (fillBuffer(s)) { return; } if (s->format == RAW_FORMAT) { handleRawUnframedInput(s, packetLen); } else if (s->format == SF_FORMAT) { handleSFInput(s); } } else { fprintf(stderr, "FATAL ERROR: Invalid stream format."); exit(1); } } // timeout is in msec void waitForInputs(long timeout) { fd_set rfds; fd_set efds; int highest=0; int i; struct timeval tv; tv.tv_sec = timeout / 1000; tv.tv_usec = (timeout % 1000) * 1000; FD_ZERO(&rfds); FD_ZERO(&efds); for (i=0; i -1) { // ignore persistent streams that are closed if (streams[i].fd > highest) { highest = streams[i].fd; } FD_SET(streams[i].fd, &rfds); FD_SET(streams[i].fd, &efds); } } if (select(highest+1, &rfds, NULL, &efds, &tv) > 0) { for (i=0; i -1) && (FD_ISSET(streams[i].fd, &rfds) || FD_ISSET(streams[i].fd, &efds)) ) { // Note: It's possible, as a result of handleInput(), for the // array of streams to be changed. Most notably, an entry // can be deleted, shifting others up. The worst this // can cause is for us to miss reading from a descriptor // this time around and have to catch it on the next // call to select(). handleInput(&(streams[i])); } } } } void createComm(char *portName, ioStream *s, char format, int moteType) { char * filename = filenameForCommPort(portName); struct termios newtio; strcpy(s->name, portName); s->type = SERIAL_PORT; s->format=format; if (s->format == FRAMED_FORMAT) { s->writePreamble = mote_configs[moteType][USE_PREAMBLE]; } /* open serial port for read/write */ printf("Opening port: %s (%s)\n", portName, filename); s->fd = open(filename, O_RDONLY|O_NONBLOCK);//WR);//|O_NOCTTY); if (s->fd < 0) { perror("open()"); cleanExit(1); } tcgetattr(s->fd, &(s->origtio)); /* Serial port setting */ memset(&newtio, 0, sizeof(newtio)); newtio.c_cflag = mote_configs[moteType][BAUD_RATE] | CS8 | CLOCAL | CREAD; newtio.c_iflag = IGNPAR; cfsetospeed(&newtio, (speed_t)mote_configs[moteType][BAUD_RATE]); cfsetispeed(&newtio, (speed_t)mote_configs[moteType][BAUD_RATE]); /* Raw output_file */ newtio.c_oflag = 0; tcflush(s->fd, TCIFLUSH); tcsetattr(s->fd, TCSANOW, &newtio); } void createServerSocket(int port, ioStream *s, char format) { struct sockaddr_in sa; printf("Listening to port %d\n", port); sa.sin_family=AF_INET; sa.sin_port=htons(port); sa.sin_addr.s_addr=INADDR_ANY; s->fd=socket(PF_INET, SOCK_STREAM, 0); if (s->fd < 0) { perror("socket()"); cleanExit(1); } { // Allow immediate socket reuse. int reuse_opt = 1; if (setsockopt(s->fd, SOL_SOCKET, SO_REUSEADDR, &reuse_opt, sizeof(reuse_opt)) < 0) { perror("setsockopt(SO_REUSEADDR)"); cleanExit(1); } } if (bind(s->fd, (struct sockaddr *) &sa, sizeof(sa)) < 0) { printf("Failure binding to port %d: %s\n", port, strerror(errno)); cleanExit(1); } if (listen(s->fd, 5)<0) { perror("listen()"); cleanExit(1); } // Make it nonblocking. Otherwise, accept can block even if select // indicated that a new connection was present (if the connection died // before the call to accept()) if (fcntl(s->fd, F_SETFL, O_NONBLOCK)<0) { perror("fcntl()"); cleanExit(1); } sprintf(s->name, "%d", port); s->type = SERVER_SOCKET; s->format = format; } void createClientSocket(char *hostSpec, ioStream *s, char format) { char hostname[strlen(hostSpec)]; int port = DEFAULT_SERVER_PORT; char *colon; struct hostent *he; struct sockaddr_in sa; printf("Connecting to %s\n", hostSpec); strcpy(hostname, hostSpec); colon = index(hostname, ':'); if (colon != NULL) { *colon=0; if (!isNum(colon+1)) { printf("Invalid port number in argument: %s\n", hostSpec); cleanExit(1); } port=atoi(colon+1); } s->type = CLIENT_SOCKET; s->bePersistent = usePersistentSockets; s->format = format; strcpy(s->name, hostSpec); he = gethostbyname(hostname); if (he == NULL) { printf("Unknown host name: %s\n", hostname); cleanExit(1); } sa.sin_family=AF_INET; sa.sin_port=htons(port); memcpy(&(sa.sin_addr), he->h_addr, he->h_length); s->fd=socket(PF_INET, SOCK_STREAM, 0); if (s->fd < 0) { perror("socket()"); cleanExit(1); } if (connect(s->fd, (struct sockaddr *) &sa, sizeof(sa)) < 0) { printf("Failure connecting to %s: %s\n", hostSpec, strerror(errno)); deleteStream(s); } if ((format == SF_FORMAT)&&(sniffer==0)) { char buf[2]; write(s->fd, SF_VERSION_STRING, 2); read(s->fd, buf, 2); } } int isDigit(char c) { return ((c >= '0') && (c <= '9')); } void createStreams(int argc, char* argv[]) { int i,j; char serial_format = FRAMED_FORMAT; char socket_format = ASCII_FORMAT; int moteType=MICA; // no arguments, assume DEFAULT_COM and DEFAULT_SERVER_PORT if (argc == 1) { createComm(DEFAULT_COM, createStreamStruct(), FRAMED_FORMAT, MICA); createServerSocket(DEFAULT_SERVER_PORT, createStreamStruct(), ASCII_FORMAT); return; } // create a streams record for each item on the command line, which can be // COMn, hostname, hostname:port, port for (i=1; i MAX_MOTE_TYPE)) { printf("Bad mote type\n"); printUsage(argv[0]); cleanExit(0); } } else if (strcmp(argv[i], "-SF")==0) { socket_format = SF_FORMAT; } else if (switchToRawUnframedIO(argv[i])) { serial_format = RAW_FORMAT; socket_format = RAW_FORMAT; } else if (strcmp(argv[i], "-SNIFFER")==0){ sniffer=1; wines_ptr=0; } else if (strcmp(argv[i], "-NOHB")==0){ exclude_heartbeat=1; } else if (filenameForCommPort(argv[i]) != NULL) { // is it COMn? createComm(argv[i], newStream, serial_format, moteType); } else if (isNum(argv[i])) { // is it a server port number? createServerSocket(atoi(argv[i]), newStream, socket_format); } else { // assume it's a host or host:port client=1; createClientSocket(argv[i], newStream, socket_format); } } } void signalHandler(int signum) { switch (signum) { case SIGHUP: printf("Exiting on SIGHUP\n"); break; case SIGINT: printf("Exiting on SIGINT\n"); break; case SIGTERM: printf("Exiting on SIGTERM\n"); break; default: printf("Exiting on signal %d\n", signum); } cleanExit(1); } void setupSignalHandler() { signal(SIGHUP, &signalHandler); signal(SIGINT, &signalHandler); signal(SIGTERM, &signalHandler); } void doPersistenceCheck() { int i; for (i=0; itype!=FW_SOCKET_CLOSE){sleep(1); }; //wait for the descriptor to be freed if ( (new_connection = accept(socket_in, (struct sockaddr *) &sockin, &sinlen) ) < 0 ) { printf("error on accept %d\n",new_connection); /* accept error */ return NULL; } printf("new connection was accepted and a thread spawned.\n"); printf( "Spawning a new connection from %s: %d.\n",inet_ntoa(sockin.sin_addr), ntohs(sockin.sin_port) ); fw_socketStream->fd=new_connection; fw_socketStream->type=FW_SOCKET_OPEN; while (fw_socketStream->type!=FW_SOCKET_CLOSE){ sleep(1); }; /* close connection, clean up sockets */ if (close(new_connection) < 0) { printf("error on close"); return NULL; } else { printf("Connection closed\n"); } } // not reach below if (close(listening_port) < 0) { printf("close"); } } int main(int argc, char* argv[]) { uint64_t lastPersistenceCheck = currentTimeMillis(); pthread_t mythread; fw_socketStream=createStreamStruct(); printf("Stream created %d\n",numStreams); fw_socketStream->type=FW_SOCKET_CLOSE; fw_socketStream->bePersistent=1; if ( pthread_create( &mythread, NULL, start_TCP_server, NULL) ) { printf("error creating thread."); abort(); } memset(wines_network,0, sizeof(wines_network)); memset(wines_buf,0,sizeof(wines_buf)); setupSignalHandler(); createStreams(argc, argv); while (1) { uint64_t time = currentTimeMillis(); if ((time - lastPersistenceCheck) > PERSISTENCE_CHECK_PERIOD) { doPersistenceCheck(); time = lastPersistenceCheck = currentTimeMillis(); } waitForInputs(PERSISTENCE_CHECK_PERIOD - (time - lastPersistenceCheck)); } if ( pthread_join ( mythread, NULL ) ) { printf("error joining thread."); abort(); } return 0; }