www.pudn.com > tcp.zip > tcp.c, change:2001-02-14,size:9880b


/*
* tcp.c last update:1998.09.02
* by lgd/Paladin.InetSoft, www.programsalon.com
* 任何人可以使用本代码,但不可修改原作者名
*/
#include <stdio.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>    /* for HP Unix */
#include <signal.h>
#include <errno.h>
#include <time.h>
#include <netdb.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/xti.h>
/*#include <sys/select.h>    for IBM AIX */
#include <fcntl.h>

#include "tcp.h"

char g_lasterr[255];

int tcp_init()
{
  signal(SIGPIPE, SIG_IGN);
  return 0;
}

char *tcp_get_error()
{
  return g_lasterr;
}

#if defined(__STDC__) || defined(__cplusplus)
int tcp_status(int max_sd, int sd, char *type, int timeout)
#else
int tcp_status(max_sd, sd, type, timeout)
int max_sd;
int sd;
char *type;
int timeout;
#endif
{
  fd_set rset, wset, eset;
  fd_set *prset =NULL, *pwset =NULL, *peset =NULL;
  struct timeval tval;
  int i, len, status;
  time_t t1, t2;

  time(&t1);
  t2 =t1;

  /*while(t2-t1 <timeout)*/
  {
    FD_ZERO(&rset);
    FD_ZERO(&wset);
    FD_ZERO(&eset);

    for(i =0; i<strlen(type); i++)
    {
      if(type[i] =='r') { FD_SET(sd, &rset); prset =&rset; }
      if(type[i] =='w') { FD_SET(sd, &wset); pwset =&wset; }
      if(type[i] =='e') { FD_SET(sd, &eset); peset =&eset; }
    }
    memset(&tval, 0, sizeof(tval));
    tval.tv_sec =timeout; /* timeout=-1:blocking */
    tval.tv_usec =0;
    status =select(max_sd+1, prset, pwset, peset, &tval); 
    if(status ==0)
    {
      if(t2-t1 <timeout) return -1;/* continue */
      else
      {
        if(prset) FD_CLR(sd,prset);
        if(pwset) FD_CLR(sd,pwset);
        if(peset) FD_CLR(sd,peset);
        errno =ETIMEDOUT;
        return -10;
      }
    }
    if(peset && FD_ISSET(sd, peset))
    {
      if(prset) FD_CLR(sd,prset);
      if(pwset) FD_CLR(sd,pwset);
      if(peset) FD_CLR(sd,peset);
      len =sizeof(errno);
      getsockopt(sd, SOL_SOCKET, SO_ERROR, &errno, &len);
      return -1;
    }
    if((prset && FD_ISSET(sd, prset)) || (pwset && FD_ISSET(sd, pwset)))
    {
      len =sizeof(errno);
      getsockopt(sd, SOL_SOCKET, SO_ERROR, &errno, &len);
    }
    if(prset) FD_CLR(sd,prset);
    if(pwset) FD_CLR(sd,pwset);
    if(peset) FD_CLR(sd,peset);
    if(errno)
    {
      sprintf(g_lasterr, "tcp_status: errno=%d, errmsg =%s\n", errno, strerror(errno));
      return -1;
    }
    /*else break;*/
  }
  return 0;
}

#if defined(__STDC__) || defined(__cplusplus)
int tcp_connect(char *hostname, int port, int timeout)
#else
int tcp_connect(hostname, port, timeout)
char *hostname;
int port;
int timeout;
#endif
{
  long l;
  int sd =-1, flags, status, error =0;
  struct hostent *hp;
  struct sockaddr_in sa;
  unsigned long ul;

  memset(&sa, 0, sizeof(sa));
  sa.sin_family =AF_INET;
  sa.sin_port =htons(port);
  if((hp =gethostbyname(hostname)) ==NULL)
  {
    if((ul =inet_addr(hostname)) ==0xffffffff)
    {
      sprintf(g_lasterr, "tcp_connect:gethostbyname and inet_addr failed! hostname=%s\n%s", hostname, strerror(errno));
      return -1;
    }
    sa.sin_addr.s_addr =ul;
  }
  else memcpy(&sa.sin_addr, hp->h_addr, hp->h_length);

  if((sd =socket(AF_INET, SOCK_STREAM, 0)) <0)
  {
    sprintf(g_lasterr, "tcp_connect:socket failed! hostname=%s\n%s", hostname, strerror(errno));
    return -1;
  }

  /*flags =fcntl(sd, F_GETFL, 0);
  fcntl(sd, F_SETFL, flags|O_NONBLOCK);*/

  while(connect(sd, (struct sockaddr *)&sa, sizeof(sa)) <0)
  {
    if(errno ==EINTR) continue;
    if(errno ==EINPROGRESS) break;
    printf("connect failed:errno=%d\n", errno);
    close(sd);
    return -1;
  }

  if(tcp_status(sd, sd, "w", timeout) <0)
  {
    close(sd);
    return -1;
  }

  return sd;
}

#if defined(__STDC__) || defined(__cplusplus)
int tcp_bind(int port)
#else
int tcp_bind(port)
int port;
#endif
{
  long l;
  int sd =-1;
  struct sockaddr_in sa;
  char temp[200];
  memset(&sa, 0, sizeof(sa));
  sa.sin_family =AF_INET;
  sa.sin_port =htons(port);

  if((sd =socket(AF_INET, SOCK_STREAM, 0)) <0)
  {
    sprintf(temp, "tcp_bind:socket failed! port=%d\n%s", port, strerror(errno));
    return -1;
  }

  l =1;
  if(setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, (char *)&l, sizeof(l)) <0)
    printf("setsockopt SO_REUSEADDR failed!\n");
  if(setsockopt(sd, SOL_SOCKET, SO_REUSEPORT, (char *)&l, sizeof(l)) <0)
    printf("setsockopt SO_REUSEPORT failed!\n");
  
  if(bind(sd, (struct sockaddr *)&sa, sizeof(sa)) <0)
  {
    sprintf(temp, "tcp_bind:bind failed! port=%d\n%s", port, strerror(errno));
    return -1;
  }

  l =1;
  if(ioctl(sd, FIONBIO, &l) <0)
  {
    sprintf(temp, "tcp_bind:ioctl failed! port=%d\n%s", port, strerror(errno));
    close(sd);
    return -1;
  }

  if(listen(sd, 5) <0)
  {
    sprintf(temp, "tcp_bind:listen failed! port=%d\n%s", port, strerror(errno));
    close(sd);
    return -1;
  }

  return sd;
}

#if defined(__STDC__) || defined(__cplusplus)
int tcp_accept(int sd, int timeout)
#else
int tcp_accept(sd, timeout)
int sd;
int timeout;
#endif
{
 
  int sd_acc =-1, flags;
  struct sockaddr_in sa;
  int len;
  /*flags =fcntl(sd, F_GETFL, 0);
  fcntl(sd, F_SETFL, flags|O_NONBLOCK);*/

  if(tcp_status(sd, sd, "rw", timeout) <0)
    return -1;
  len =sizeof(sa);
  if((sd_acc =accept(sd, (struct sockaddr *)&sa, &len)) <0)
    return -1;
  return sd_acc;
}

int tcp_recv(int sd, void *buf, int len, int timeout)
{
  int len1, len_recv;
  char temp[200];
  time_t t2, t1;
  
  len_recv =0;
  time(&t1);

  while(len_recv <len)
  {
    time(&t2);
    if(t2 -t1 >timeout)
    {
      sprintf(temp, "tcp_recv timeout! len_recv=%d, len=%d\n%s",
              len_recv, len, strerror(errno));
      return len_recv;
    }
    if(tcp_status(sd, sd, "r", timeout-(t2-t1)) <0)
    {
      return len_recv;
    }

    if((len1 =recv(sd, (char *)buf +len_recv, len-len_recv, 0)) <=0)
    {
      if(errno)
      {
        sprintf(temp, "tcp_recv failed! len_recv=%d, len=%d\n%s",
              len_recv, len, strerror(errno));
        printf(temp);
      }
      return len_recv;
    }
    len_recv +=len1;
  }
  return len_recv; 
}

int tcp_send(int sd, const void *buf, int len, int timeout)
{
  int len1, len_send =0;
  char temp[200];
  time_t t1, t2;
  char buff[300]; 
  len_send =0;
  time(&t1);
  while(len_send <len)
  {
    time(&t2);
    if(t2-t1 >timeout)
    {
      sprintf(temp, "tcp_send timeout! len_send=%d, len=%d\n%s",
              len_send, len, strerror(errno));
      return len_send;
    }
    if(tcp_status(sd, sd, "w", timeout-(t2-t1)) <0)
      return len_send;
    if((len1 =send(sd, (char *)buf+len_send, len-len_send, 0)) <=0)
    {
      sprintf(temp, "tcp_send failed! len_send=%d, len=%d\n%s",
              len_send, len, strerror(errno));
      return len_send;
    }
    len_send +=len1;
  }
  return len_send;
}

#if defined(__STDC__) || defined(_cplusplus)
int tcp_close(int sd)
#else
int tcp_close(sd)
int sd;
#endif
{
  struct linger lin;

  memset(&lin, 0, sizeof(lin));
  /*shutdown(sd, 2);*/
  lin.l_onoff =1;
  lin.l_linger =0;
  /*setsockopt(sd, SOL_SOCKET, SO_LINGER, (char *)&lin, sizeof(lin));*/
  close(sd);
  return 0;
}

int tcp_shut(int sd)
{
  struct linger lin;

  memset(&lin, 0, sizeof(lin));
  /*shutdown(sd, 2);*/
  lin.l_onoff =1;
  lin.l_linger =0;
  setsockopt(sd, SOL_SOCKET, SO_LINGER, (char *)&lin, sizeof(lin));
  close(sd);
  return 0;
}

#if defined(__STDC__) || defined(_cplusplus)
unsigned short tcp_htons(unsigned short s)
#else
unsigned short tcp_htons(s)
unsigned short s;
#endif
{
  return htons(s);
}

#if defined(__STDC__) || defined(_cplusplus)
unsigned short tcp_ntohs(unsigned short s)
#else
unsigned short tcp_ntohs(s)
unsigned short s;
#endif
{
  return ntohs(s);
}

#if defined(__STDC__) || defined(_cplusplus)
unsigned long int tcp_htonl(unsigned long int l)
#else
unsigned long int tcp_htonl(l)
unsigned long int l;
#endif
{
  return htonl(l);
}

#if defined(__STDC__) || defined(_cplusplus)
unsigned long int tcp_ntohl(unsigned long int l)
#else
unsigned long int tcp_ntohl(l)
unsigned long int l;
#endif
{
  return ntohl(l);
}

#if defined(__STDC__) || defined(_cplusplus)
float tcp_htonf(float f)
#else
float tcp_htonf(f)
float f;
#endif
{
  unsigned char *p, p0, p1;

  if(htons(1) ==1) return f;
  p =(unsigned char *)&f;
  p0 =p[0];
  p1 =p[1];
  p[0] =p[3];
  p[3] =p0;
  p[1] =p[2];
  p[2] =p1;

  return f;
}

#if defined(__STDC__) || defined(_cplusplus)
float tcp_ntohf(float f)
#else
float tcp_ntohf(f)
float f;
#endif
{
  unsigned char *p, p0, p1;

  if(ntohs(1) ==1) return f;

  p =(unsigned char *)&f;
  p0 =p[0];
  p1 =p[1];
  p[0] =p[3];
  p[3] =p0;
  p[1] =p[2];
  p[2] =p1;
  return f;
}

#if defined(__STDC__) || defined(_cplusplus)
double tcp_htond(double d)
#else
double tcp_htond(d)
double d;
#endif
{
  unsigned char *p, p0, p1, p2, p3;

  if(htons(1) ==1) return d;

  p =(unsigned char *)&d;
  p0 =p[0];
  p1 =p[1];
  p2 =p[2];
  p3 =p[3];
  p[0] =p[7];
  p[7] =p0;
  p[1] =p[6];
  p[6] =p1;
  p[2] =p[5];
  p[5] =p2;
  p[3] =p[4];
  p[4] =p3;

  return d;
}

#if defined(__STDC__) || defined(_cplusplus)
double tcp_ntohd(double d)
#else
double tcp_ntohd(d)
double d;
#endif
{
  unsigned char *p, p0, p1, p2, p3;

  if(ntohs(1) ==1) return d;

  p =(unsigned char *)&d;
  p0 =p[0];
  p1 =p[1];
  p2 =p[2];
  p3 =p[3];
  p[0] =p[7];
  p[7] =p0;
  p[1] =p[6];
  p[6] =p1;
  p[2] =p[5];
  p[5] =p2;
  p[3] =p[4];
  p[4] =p3;

  return d;
}

#if defined(__STDC__) || defined(_cplusplus)
char *get_ip(int sd)
#else
char *get_ip(sd)
int sd;
#endif
{
  struct sockaddr_in addr_in;
  int len =sizeof(addr_in);
  static char sz_ip[20];
  char *p1;

  if(sd <0) return  NULL;
  if(getpeername(sd, (struct sockaddr *)&addr_in, &len) <0)
    return NULL;
  p1 =(char *)&addr_in.sin_addr;
  sprintf(sz_ip, "%d.%d.%d.%d", ((int)p1[0]) &0xff, ((int)p1[1]) &0xff, (int)p1[2] &0xff, (int)p1[3]&0xff);
  return sz_ip;
}