⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tcpapi.c

📁 在ARM7和UC/OSII的平台上实现了GPS自动报站的功能,涉及GPS模块LEA_4S的驱动,位置速寻算法,语音芯片ISD4004的录放音驱动,LED页面管理等等.从启动代码到操作系统的移植以及到业
💻 C
📖 第 1 页 / 共 2 页
字号:
/*
 * FILENAME: tcpapi.c
 *
 * Copyright 2000 By InterNiche Technologies Inc. All rights reserved
 *
 * The mini-sockets API for the mini TCP layer.
 *
 * MODULE: MTCP
 *
 * ROUTINES: m_connect(), m_listen(), m_send(), m_recv(), m_close(). m_ioctl(),
 * ROUTINES: m_socket(), tcp_pktalloc(), tcp_pktfree(), tcp_send(), tcp_recv(),
 * ROUTINES: m_getpeername(), 
 *
 * PORTABLE: yes
 */

#include "ipport.h"
#include "mtcp.h"

#include "minip.h"      /* (yaxon add) */

void tcp_sleep(void *); /* (yaxon add) */



/* FUNCTION: m_socket()
 *
 * Allocates a socket structure for an active connect. 
 *
 * PARAM1: none
 *
 * RETURNS: returns the M_SOCK if OK, else NULL.
 */

M_SOCK
m_socket()
{
   M_SOCK so;

   so = (M_SOCK)SOC_ALLOC(sizeof(struct msocket));
   if (so)
   {
      LOCK_NET_RESOURCE(NET_RESID);    /* do net resource protection */
      putq(&msoq, so);                 /* put new socket in queue */
      UNLOCK_NET_RESOURCE(NET_RESID);
   }
   return(so);
}

/* FUNCTION: m_connect()
 *
 * Starts an active connect. If socket has been set to non-blocking and
 * no problems are detected it returns immediatly with EINPROGRESS.
 *
 * PARAM1: socket to start connect on
 * PARAM2: structure with port and address to conenct to.
 * PARAM3: pointer to callback routine for NB connects
 *
 * RETURNS: 0 if socket is connected, else BSD error code
 */


int
m_connect(M_SOCK so, struct sockaddr_in * sin, M_CALLBACK(name))
{
   struct tcpcb * tp;
   int e = 0;

   LOCK_NET_RESOURCE(NET_RESID);

   if(so->tp)  /* socket already has a tcpcb? */
   {
      e = EISCONN;
      goto rtn;
   }

   so->fhost = sin->sin_addr.s_addr;
   so->fport = sin->sin_port;
   if (so->lport == 0)
      m_setlport(so);
   tp = m_newtcpcb(so);
   if(!tp)
   {
      e = ENOMEM;
      goto rtn;
   }

   so->callback = name;             /* set callback routine */

   so->state |= SS_ISCONNECTING;    /* set state bitmask */
   tp->t_state = TCPS_SYN_SENT;     /* TCP state (after syn send) */
   tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT;
   tp->iss = tcp_iss;               /* setup initial SEQ number */
   tcp_iss += (tcp_seq)(TCP_ISSINCR/2);
   tcp_sendseqinit(tp);
   
   TCP_STAT_INC(tcps_connattempt);  /* Keep detailed (BSDish) stats */
   m_template(tp);                  /* set up header template for tcp sends */

   tcp_output(tp);                  /* send opening syn packet */

   if(so->state & SS_NBIO)    /* if non-blocking, return now */
   {
      /* Socket may have blocked to connect in tcp_output() and then been
       * set to non-blocking in connect callback - e.g., FTP server does this.
       */
      if(so->state & SS_ISCONNECTED)
         goto rtn;

      /* fall to here if it's really in progress */
      e = so->error = EINPROGRESS;
      goto rtn;
   }

   while(so->state & SS_ISCONNECTING)
   {
      tcp_sleep(so);
   }
   if(so->state & SS_ISCONNECTED)
      e = 0;
   else
      e = so->error;

rtn:
   UNLOCK_NET_RESOURCE(NET_RESID);
   return e;
}

/* FUNCTION: m_listen()
 *
 * Start a listen on the passed port (and optional IP address). The listen 
 * is implemented by creating a parially filled in M_SOCK and tcpcb. The socket
 * is returned to the caller for passing to later calls, like m_close(), but 
 * will never actually become a working connection. Any passive connects 
 * which succeed on this socket cause the callback routine to be called 
 * with a code of M_OPENED and passed a new, connected, socket.
 *
 *
 * PARAM1: struct sockaddr_in * - local port/foreign IP addr
 * PARAM2: callback routine
 * PARAM3: int * error - OUT - error return
 *
 * RETURNS: listening socket if success, else returns INVALID_SOCKET and
 * sets the passed error holder to one of the BSD error codes.
 */

M_SOCK
m_listen (struct sockaddr_in * sin, M_CALLBACK(name), int * error)
{
   M_SOCK   so;

   /* create a socket and tp to support the listen */
   so = m_socket();
   if(!so)
   {
      *error = ENOMEM;
      return INVALID_SOCKET;
   }

   LOCK_NET_RESOURCE(NET_RESID);
   so->fhost = sin->sin_addr.s_addr;
   so->lport = sin->sin_port;
   if (so->lport == 0)
      m_setlport(so);
   so->callback = name;
   
   so->tp = m_newtcpcb(so);
   if(!so->tp)
   {
      m_delsocket(so);
      *error = ENOMEM;
      so = INVALID_SOCKET;
      goto rtn;
   }
   so->tp->t_state = TCPS_LISTEN;

rtn:
   UNLOCK_NET_RESOURCE(NET_RESID);
   return so;
}


/* FUNCTION: tcp_send()
 *
 * Send a packet allocated via tcp_pktalloc(). User should have filled
 * data to be sent at pkt->m_data and set length in pkt->m_len.
 *
 * An OK return means the data is queued for sending and is now the 
 * responsability of the stack. An error return means the pkt has
 * NOT been queued or freed and is still owned by the caller.
 *
 * PARAM1: so - socket to send on. Must be open
 * PAMAR2: pkt - filled in data packet to send.
 *
 * RETURNS: 0 if OK or BSD error code.
 */

int
tcp_send(M_SOCK so, PACKET pkt)
{
   int err;

   LOCK_NET_RESOURCE(NET_RESID);

   /* make sure we are not overfilling the socket send buffer */
   while((pkt->m_len + so->sendq.sb_cc) > mt_deftxwin)
   {
      if((so->state & SS_ISCONNECTED) == 0)  /* not connected? */
         err = ENOTCONN;
      else if(so->state & SS_NBIO)    /* If non-blocking return now */
         err = EWOULDBLOCK;
      else
      {
         tcp_sleep(&so->sendq);  /* else wait for data ack */
         continue;
      }
      goto rtn;
   }

   /* setup packet protocol data pointers to TCP data */
   pkt->nb_prot = pkt->m_data;
   pkt->nb_plen = pkt->m_len;

   if(so->tp == NULL)      /* guard against TCP close by fhost */
   {
      err = EPIPE;         /* host killed connection */
   }
   else     /* connection seems OK, send it */
   {
      put_soq(&so->sendq, pkt);        /* place pkt in send que */
      err = tcp_output(so->tp);        /* call TCP send routine */
   }

rtn:
   UNLOCK_NET_RESOURCE(NET_RESID);
   return err;
}


/* FUNCTION: tcp_recv()
 *
 * Return next received packet on passed socket. Caller is responsible
 * for returning pkt to freeq via pk_free(). pkt->m_data points to data,
 * pkt->m_len is length of data.
 *
 * PARAM1: socket to receive on
 *
 * RETURNS: pkt if one is ready, NULL if no packet is ready and socket
 * is non-blocking.
 */

PACKET
tcp_recv(M_SOCK so)
{
   PACKET pkt;

   LOCK_NET_RESOURCE(NET_RESID);    /* do net resource protection */

   pkt = NULL;

   if(so->rcvdq.p_head)
      goto returnit;

   /* non-blocking sockets return a null now */
   if(so->state & SS_NBIO)
      goto returnpkt;

   /* wait till blocking socket gets data or disconnects */
   while(so->rcvdq.p_head == NULL)
   {
      if((so->state & SS_ISCONNECTED) == 0)
         goto returnpkt;
      UNLOCK_NET_RESOURCE(NET_RESID);
      tk_yield();
      LOCK_NET_RESOURCE(NET_RESID);
   }

returnit:
   pkt = get_soq(&so->rcvdq);
returnpkt:
   UNLOCK_NET_RESOURCE(NET_RESID);
   return pkt;
}



/* FUNCTION: m_ioctl()
 *
 *    Implement selected SO_ options from socket.h. This one routine
 * maintains both the so->so_options (socket options) and tp->t_state
 * (TCP ioclt) masks.
 *
 * PARAM1: 
 *
 * RETURNS: 
 */

int
m_ioctl(M_SOCK so, int option, void * data)
{
   int e = 0;

   LOCK_NET_RESOURCE(NET_RESID);

   /* map iniche type NBIO to BSD type option */
   if(option == SO_NBIO)
   {
      if((data == NULL) ||    /* treat null as a pointer to zero */
         (*(int*)data != 0))  /* set the masks for non-blocking */
      {
         so->so_options |= SO_NBIO;
         option = SO_NONBLOCK;
      }
      else     /* set socket and tp masks for blocking */
      {
         so->so_options &= ~SO_NBIO;
         option = SO_NBIO;
      }
   }

   switch (option)
   {
      case SO_NONBLOCK:
         so->state |= SS_NBIO;
         break;
      case SO_BIO:
         so->state &= ~SS_NBIO;
         break;
      case SO_DEBUG:    /* toggle debug option based on data as ptr to boolean */
         if(*(int*)data == 0)    /* (*data) is FALSE, clear debug bit */
            so->so_options &= ~SO_DEBUG;
         else
            so->so_options |= SO_DEBUG;
         break;      
      case SO_LINGER:
         /* This mini ioctl only sets the linger option bit and has no
          * mechanism to clear it.
          */
         so->so_options |= SO_LINGER;
         so->linger = *(int*)data;  /* number of seconds */
         break;
      default:
         e = EOPNOTSUPP;
         /* FALLTHROUGH */
   }

   UNLOCK_NET_RESOURCE(NET_RESID);
   return e;
}


/* FUNCTION: m_close()
 *
 * close the socket
 *
 * PARAM1: 
 *
 * RETURNS: 
 */

int
m_close(M_SOCK so)
{
   struct tcpcb * tp;
   M_SOCK tmp;
   int e = 0;

   LOCK_NET_RESOURCE(NET_RESID);    /* do net resource protection */

   /* search msoq to make sure sock exists */
   for(tmp = (M_SOCK)msoq.q_head; tmp; tmp = tmp->next)
      if(tmp == so)
         break;
   if(tmp == NULL)      /* bogus or stale socket */
   {
      e = EINVAL;
      goto rtn;
   }
   if (so->tp == NULL)     /* tp already cleaned up */
   {
      m_delsocket(so);
      goto rtn;
   }
   tp = so->tp;      /* make a local copy of the tcpcb */

   /* mark socket as closed so it can be deleted by tcp_slowtimo()

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -