serial_transport_tcp_posix.c
Go to the documentation of this file.
00001 
00009 /*
00010  * Copyright (c) 2009 ThingMagic, Inc.
00011  *
00012  * Permission is hereby granted, free of charge, to any person obtaining a copy
00013  * of this software and associated documentation files (the "Software"), to deal
00014  * in the Software without restriction, including without limitation the rights
00015  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
00016  * copies of the Software, and to permit persons to whom the Software is
00017  * furnished to do so, subject to the following conditions:
00018  *
00019  * The above copyright notice and this permission notice shall be included in
00020  * all copies or substantial portions of the Software.
00021  * 
00022  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00023  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00024  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
00025  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00026  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00027  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
00028  * THE SOFTWARE.
00029  */
00030 
00031 #include <sys/socket.h>
00032 #include <netinet/in.h>
00033 #include <netinet/tcp.h>
00034 #include <arpa/inet.h>
00035 #include <netdb.h>
00036 #include <unistd.h>
00037 #include <string.h>
00038 #include <errno.h>
00039 #include <sys/ioctl.h>
00040 #include <stdlib.h>
00041 
00042 #include "tm_reader.h"
00043 
00044 #ifdef TMR_ENABLE_SERIAL_TRANSPORT_NATIVE
00045 static TMR_Status
00046 tcp_open(TMR_SR_SerialTransport *this)
00047 {
00048   int sock;
00049   const char *port;
00050   char hostCopy[256];
00051   TMR_Status ret;
00052   int portNum = 0;
00053   TMR_SR_SerialPortNativeContext *c; 
00054 
00055   c = this->cookie;
00056   port = strchr(c->devicename, ':');
00057   strcpy(hostCopy, c->devicename + 1);
00058   portNum = atoi(port + 1);
00059   hostCopy[port - c->devicename -1 ] = '\0';
00060 
00061   static const struct addrinfo addrInfoMask =
00062   {    
00063     0,   
00064     AF_INET,
00065     SOCK_STREAM,
00066     0,                                                                                                                                                             
00067     0,   
00068     NULL,
00069     NULL,
00070     NULL 
00071   };   
00072   struct addrinfo *           hostAddress;
00073   int                         flag;
00074   struct sockaddr_in          sin; 
00075   int                         rc;
00076 
00077   /*
00078    * Look up host using getaddrinfo().
00079    * Gethostbyname() could be configured a lot of
00080    * different ways. There is /etc/hosts, DNS, NIS, etc, etc.
00081    * Suffice to say it is big, bulky, and susceptible to stall.
00082    */
00083   if(0 != getaddrinfo(hostCopy, NULL, &addrInfoMask, &hostAddress))
00084   {
00085     return TMR_ERROR_INVALID;
00086   }
00087 
00088   /*
00089    * Convert the address to sockaddr_in format
00090    */
00091   memset(&sin, 0, sizeof sin);
00092   sin.sin_family = AF_INET;
00093   sin.sin_addr = ((struct sockaddr_in *)(hostAddress->ai_addr))->sin_addr;
00094   sin.sin_port = htons(portNum);
00095 
00096   /*
00097    * Done withe the host addrinfo
00098    */
00099   freeaddrinfo(hostAddress);
00100 
00101   /*
00102    * Create the socket.
00103    */
00104   sock = socket(AF_INET, SOCK_STREAM, 0);
00105   if(0 > sock)
00106   {
00107     return TMR_ERROR_INVALID;
00108   }
00109 
00110   /*
00111    * Connect the socket to reader. This can stall.
00112    */
00113   rc = connect(sock, (struct sockaddr *)&sin, sizeof sin);
00114   if(0 > rc)
00115   {
00116     /* Connect failed */
00117     close(sock);
00118     return TMR_ERROR_INVALID;
00119   }
00120 
00121   /*
00122    * Best effort to set no delay. If this doesn't work
00123    * (no reason it shouldn't) we do not declare defeat.
00124    */
00125   flag = 1;
00126   setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void*)&flag, sizeof flag);
00127 
00128   /*
00129    * Record the socket in the connection instance
00130    */
00131   c->handle = sock;
00132 
00133   ret = TMR_SUCCESS;
00134  
00135   return ret;
00136 }
00137 
00138 
00139 static TMR_Status
00140 tcp_sendBytes(TMR_SR_SerialTransport *this, uint32_t length, 
00141                 uint8_t* message, const uint32_t timeoutMs)
00142 {
00143   TMR_SR_SerialPortNativeContext *c;
00144   int ret;
00145 
00146   c = this->cookie;
00147   do 
00148   {
00149     ret = write(c->handle, message, length);
00150     if (ret == -1)
00151     {
00152       return TMR_ERROR_COMM_ERRNO(errno);
00153     }
00154     length -= ret;
00155     message += ret;
00156   }
00157   while (length > 0);
00158 
00159   return TMR_SUCCESS;
00160 }
00161 
00162 
00163 static TMR_Status
00164 tcp_receiveBytes(TMR_SR_SerialTransport *this, uint32_t length, 
00165                    uint32_t* messageLength, uint8_t* message, const uint32_t timeoutMs)
00166 {
00167   TMR_SR_SerialPortNativeContext *c;
00168   int ret;
00169   struct timeval tv;
00170   fd_set set;
00171   int status = 0;
00172 
00173   *messageLength = 0;
00174   c = this->cookie;
00175 
00176   do
00177   {
00178     FD_ZERO(&set);
00179     FD_SET(c->handle, &set);
00180     tv.tv_sec = timeoutMs/1000;
00181     tv.tv_usec = (timeoutMs % 1000) * 1000;
00182     /* Ideally should reset this timeout value every time through */
00183     ret = select(c->handle + 1, &set, NULL, NULL, &tv);
00184     if (ret < 1)
00185     {
00186       return TMR_ERROR_TIMEOUT;
00187     }
00188     ret = read(c->handle, message, length);
00189     if (ret == -1)
00190     {
00191       return TMR_ERROR_COMM_ERRNO(errno);
00192     }
00193 
00194     if (0 == ret)
00195     {
00201       ret = ioctl(c->handle, TIOCMGET, &status);
00202       if (-1 == ret)
00203       {
00204         /* not success. check for errno */
00205         if (EIO == errno)
00206         {
00211           return TMR_ERROR_TIMEOUT;
00212         }
00213       }
00214     }
00215 
00216     length -= ret;
00217     *messageLength += ret;
00218     message += ret;
00219   }
00220   while (length > 0);
00221 
00222   return TMR_SUCCESS;
00223 }
00224 
00225 #if 0
00226 static TMR_Status
00227 tcp_setBaudRate(TMR_SR_SerialTransport *this, uint32_t rate)
00228 {
00229 
00230   /* This routine should change the baud rate of the serial connection
00231    * to the specified rate, or return TMR_ERROR_INVALID if the rate is
00232    * not supported.
00233    */
00234 
00235   return TMR_ERROR_UNIMPLEMENTED;
00236 }
00237 #endif
00238 
00239 static TMR_Status
00240 tcp_shutdown(TMR_SR_SerialTransport *this)
00241 {
00242         TMR_Status ret = TMR_SUCCESS;
00243         TMR_SR_SerialPortNativeContext *c;
00244 
00245         c = this->cookie;
00246 
00247         if (0 > c->handle)
00248         {
00249                 ret = TMR_ERROR_INVALID;
00250         }
00251 
00252         close(c->handle);
00253 
00254         c->handle = -1;
00255 
00256         return ret;
00257 
00258 }
00259 
00260 static TMR_Status
00261 tcp_flush(TMR_SR_SerialTransport *this)
00262 {
00263 
00264   /* This routine should empty any input or output buffers in the
00265    * communication channel. If there are no such buffers, it may do
00266    * nothing.
00267    */
00268 
00269   return TMR_SUCCESS;
00270 }
00271 
00279 TMR_Status
00280 TMR_SR_SerialTransportTcpNativeInit(TMR_SR_SerialTransport *transport,
00281                                  TMR_SR_SerialPortNativeContext *context,
00282                                  const char *device)
00283 {
00284 
00285   if (strlen(device) + 1 > TMR_MAX_READER_NAME_LENGTH)
00286   {
00287     return TMR_ERROR_INVALID;
00288   }
00289   strcpy(context->devicename, device);
00290 
00291   transport->cookie = context;
00292   transport->open = tcp_open;
00293   transport->sendBytes = tcp_sendBytes;
00294   transport->receiveBytes = tcp_receiveBytes;
00295   transport->setBaudRate = NULL;
00296   transport->shutdown = tcp_shutdown;
00297   transport->flush = tcp_flush;
00298 
00299   return TMR_SUCCESS;
00300 }
00301 #endif


thingmagic_rfid
Author(s): Brian Bingham
autogenerated on Thu May 16 2019 03:01:24