/* hca.c Henriks communication API www.eit.se/hcpips Copyright 2008 Henrik Björkman www.eit.se May be redistributed as under Gnu General Public License version 3. http://www.gnu.org/licenses/licenses.html#GPL You may modify this code as long as you document the modifications you have made in the History section below and do not remove this copyright notice and the file history section. It should work with both Windows and UNIX (such as Solaris & Linux). But the latest version is only tested under Win32. It should work with both Windows and UNIX (such as Solaris & Linux). History 941111 Created by Henrik Bjorkman 000418 Ported to win32s by Henrik and Bengt Englund 010718 Renamed to hca. Henrik (www.eit.se) 010719 ported to unix again. Henrik 010721 Both the client and server API merged into one file. Henrik 030508 Support for standard input and serial port. Henrik 050709 Improved comments and renamed some function to make things more clear. Henrik 080921 Improved serial port handling in windows version. Henrik */ #include #include #include "serial_port.h" #include "hca.h" //#define DEBUG /* Macro for debug printouts */ #ifdef DEBUG #define D(x) x #else #define D(x) #endif /* To write a buffer in hex */ static void HexPrint(char *ptr, int len) { D(printf("HexPrint %2d: ",len);) if (len>30) len=30; while(len-->0) { printf("%02x",(unsigned char)*ptr++); } printf("\n"); } /* To write all graphic characters in a buffer */ /* static void GraphPrint(char *ptr, int len) { D(printf("GraphPrint %2d: ",len);) if (len>64) len=64; while(len-->0) { if (isgraph(*ptr)) {putc(*ptr,stdout);} else {putc('.',stdout);} ptr++; } printf("\n"); } */ /****************************************************************************/ #ifdef WIN32 /****************************************************************************/ #include /* When linking for windows perhaps wsock32.lib needs to be added to project. */ #include #include #include #include #include #include /*****************************************************************************/ /* The following variables and functions are only to be used internaly. */ /* Global data for the communication */ static fd_set hca_active_fds; static fd_set hca_readfds; static unsigned int hca_server_socket=HCA_NO_FD; static unsigned int hca_width=FD_SETSIZE; static int hca_initiated=0; static int std_input_fd=HCA_NO_FD; //static HANDLE hSerialPort=NULL; //static int serial_port_fd=HCA_NO_FD; int hca_needed_delay=50; static void hca_start_up() { WORD wVersionRequested; WSADATA wsaData; int err; wVersionRequested = MAKEWORD( 2, 0 ); err = WSAStartup( wVersionRequested, &wsaData ); if ( err != 0 ) { /* Tell the user that we couldn't find a usable */ /* WinSock DLL. */ printf("WSAStartup error code %d %d \n",err, WSAGetLastError()); return; } /* Confirm that the WinSock DLL supports 2.0.*/ /* Note that if the DLL supports versions greater */ /* than 2.0 in addition to 2.0, it will still return */ /* 2.0 in wVersion since that is the version we */ /* requested. */ if ( LOBYTE( wsaData.wVersion ) != 2 || HIBYTE( wsaData.wVersion ) != 0 ) { /* Tell the user that we couldn't find a usable */ /* WinSock DLL. */ printf("WinSock DLL error (perhaps to old)\n"); WSACleanup( ); return; } } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Our own signal handler. It does nothing but count the signals */ /* and print an error message */ static int hca_signal_count=0; static void hca_signal_hander(int i) { hca_signal_count++; fprintf(stderr,"hca: signal %d %d\n",hca_signal_count, i); } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* The following functions are to be used by other functions. */ /* Wait for something to happen Return codes are: <0 Something went wrong 0 Timeout >0 something received from one of the sockets or a new client wants to connect. After this function use "hca_accept" to check if a new client connected (only if this is a server). Use "hca_get_next_socket_to_read" to check from which socket something was received. */ int hca_wait(int timeout_us) { struct timeval timeout; /* seconds and microseconds */ int nready; D(unsigned int i); timeout.tv_sec=0; timeout.tv_usec=timeout_us; // if no data was sent or received we need a short delay here to avoid using 100% CPU time */ Sleep(hca_needed_delay); memcpy(&hca_readfds, &hca_active_fds, sizeof(hca_readfds)); nready=select(hca_width, &hca_readfds, NULL, NULL, &timeout); if (nready==SOCKET_ERROR) { printf("select error code %d %d \n",nready, WSAGetLastError()); } D(for(i=0;i0) { hca_needed_delay=0; } else*/ { hca_needed_delay=50; } // scan input from console, this is not very efficient since it will // be checked only when something else has happend or at timeout. But // keyboard input is not very fast anyway. if ((nready>=0) && (std_input_fd!=HCA_NO_FD) && (kbhit())) { nready++; } return(nready); } /* Initiates global data and sets up the communication. This function must be called before uning any of the others. */ int hca_init() { if (!hca_initiated) { D(printf("hca_init\n");) /* Check the name of the computer */ /* initiate global data */ hca_start_up(); memset(&hca_active_fds,0,sizeof(hca_active_fds)); /* Registrating our own handler for the some signals. */ /* Otherwise the program might terminate if they happen. */ /*signal( SIGPOLL, hca_signal_hander );*/ /*signal( SIGPIPE, hca_signal_hander );*/ /*signal( SIGURG, hca_signal_hander );*/ hca_initiated=1; } return(0); } /* The CreateFile function can create a handle to a communications resource, such as the serial port COM1. For communications resources, the dwCreationDisposition parameter must be OPEN_EXISTING, and the hTemplate parameter must be NULL. Read, write, or read/write access can be specified, and the handle can be opened for overlapped I/O. For more information about communications, see Communications. */ /* Open a serial port dev_name chall be: COM1 COM2 etc Returns: a handle if ok, INVALID_HANDLE_VALUE if not ok. */ HANDLE hca_open_serial_port(const char *dev_name, int baudrate) { return HANDLE serial_port_open(const char *dev_name, int baudrate); } // An alternative to the current implementation below would be // to use CreateFile to create a handle to console input (CONIN$). /* Open standard input */ int hca_open_standard_input() { // stdin is actually on fd 0, while stdout is 1. // but here we try to use same for both input and output. std_input_fd=1; //FD_SET(std_input_fd, &hca_active_fds); return std_input_fd; } /* Initiates global data and sets up the communication as a server. */ int hca_server(unsigned short port) { struct sockaddr_in ServerAddress; SOCKET s; /* Check the name of the computer */ /* initiate global data */ hca_init(); /* Create a socket and bind it to the server port number */ D(printf("hca_server: %d \n",port);) /* Store address data in an address struct to be used by bind */ ServerAddress.sin_family=AF_INET; ServerAddress.sin_port=htons(port); ServerAddress.sin_addr.s_addr=INADDR_ANY; /* Create a new socket SOCK_STREAM*/ s=socket(AF_INET ,SOCK_STREAM , 0 /*PF_INET*/); if ((s==INVALID_SOCKET) || (s<0)) { printf("socket error code %d %d \n",s, WSAGetLastError()); exit(1); } D(printf("hca_create_server_socket: New socket %d created\n",s);) /* Connect bind to server port */ if (bind(s,(struct sockaddr*)&ServerAddress, sizeof ServerAddress)!=0) { printf("bind error code %d %d \n",s, WSAGetLastError()); exit(1); } if (listen(s,8)!=0) { printf("listen error code %d %d \n",s, WSAGetLastError()); exit(1); } FD_SET(s, &hca_active_fds); /* Create server socket */ hca_server_socket=s; return(s); } /* Create a socket and bind it to the server port number */ /* returns <0 if not ok */ int hca_client(const char *hostname, unsigned short port) { char ownhostname[32+1]={0}; struct hostent *hp=NULL; struct sockaddr_in server_address; SOCKET s; long cmd=FIONBIO; long arg=0; hca_init(); /* Get name of the own host if no hostname was given. */ if (hostname==NULL) { gethostname(ownhostname,32);ownhostname[32]=0;hostname=ownhostname; } printf("port %d host %s\n",port,hostname); /* Get host address for host with name as in hostname */ hp=gethostbyname(hostname); if (hp==NULL) { fprintf(stderr,"Unknown host %s\n",hostname); return -1; } /* Store address data in an address struct to be used by connect */ server_address.sin_family=AF_INET; server_address.sin_port=htons(port); // dont forget byte order (htons). memcpy((char*)&server_address.sin_addr, (char*)hp->h_addr, hp->h_length); D(printf("Address family %d port %d \n",server_address.sin_family,server_address.sin_port);) /* Create a new socket SOCK_STREAM*/ s=socket(AF_INET ,SOCK_STREAM , 0 /*PF_INET*/); if ((s==INVALID_SOCKET) || (s<0)) { printf("socket error code %d %d \n",s, WSAGetLastError()); return -1; } D(printf("hca: New socket %d created\n",s);) /* Connect socket to server */ { const int err=connect(s,(struct sockaddr*)&server_address, sizeof(server_address)); if (err!=0) { printf("connect error code %d %d \n",err, WSAGetLastError()); close(s); return -1; } } FD_SET(s, &hca_active_fds); /* Set socket to non blocking mode. http://msdn.microsoft.com/en-us/library/ms738573(VS.85).aspx */ { const long cmd=FIONBIO; unsigned long arg=1; const int err=ioctlsocket(s, cmd, &arg); if (err!=0) { fprintf(stderr, "ioctlsocket %d %ld %ld %d %d\n", s, cmd, arg, err, WSAGetLastError()); } } return(s); } /* To deactivate the communication, This is not nessesary. */ /* But on win32s it is nessesary! */ int hca_close(int fd) { D(printf("hca_close socket %d\n",fd);) closesocket(fd); FD_CLR((unsigned)fd, &hca_active_fds); return(0); } int hca_close_handle(HANDLE h) { CloseHandle(h); return(0); } /* This is supposed to be called before program terminates to clean things up. */ int hca_cleanup() { unsigned int i; for(i=0;i0) { hca_needed_delay=0; } else if (bytesWritten<0) { const int e = WSAGetLastError(); if (e == WSAEWOULDBLOCK) { return 0; } else { fprintf(stderr,"send error %d %d %d\n", len ,bytesWritten, e); return -1; } } /*if (bytesWritten!=len) { fprintf(stderr,"send error %d %d\n", len ,bytesWritten); }*/ return(bytesWritten); } int hca_write_handle(HANDLE h, const char *buf, const int len) { DWORD bytesWritten; if (!WriteFile(h, buf, len, &bytesWritten, NULL)) { int e=GetLastError(); fprintf(stderr,"WriteFile error %p %d\n", h, e); return 0; } if (bytesWritten>0) { hca_needed_delay=0; } return bytesWritten; } /* To read data that has arrived on a socket. Ungefdr som vanlig read plus en felutskrift om det blev fel. Return codes: >0 The number of characters read. 0 no data from this client. -1 The client has probably disconnected. -2 Other error. */ int hca_read(int fd,char *buf, int len) { /*D(printf("hca_read: socket %d\n",fd);)*/ if (fd==std_input_fd) { if (kbhit() && (len>0)) { *buf=getch(); return (1); } else { return (0); } } /* Set socket to non blocking mode. http://msdn.microsoft.com/en-us/library/ms738573(VS.85).aspx */ { const long cmd=FIONBIO; unsigned long arg=1; const int err=ioctlsocket(fd, cmd, &arg); if (err!=0) { fprintf(stderr, "ioctlsocket %d %ld %ld %d %d\n", fd, cmd, arg, err, WSAGetLastError()); } } len=recv(fd,buf,len,0); if (len>0) /* inkommande data */ { D(printf("Data recieved on socket %2d: \n",fd);) D(GraphPrint(buf,len);) D(HexPrint(buf,len);) hca_needed_delay=0; } else if (len==0) // Client has disconnected (I think) { D(printf("Client has disconnected, fd=%d\n",fd);) #if 0 close(fd); #endif return(-1); } else if (len<0) /* Fel? */ { const int err=WSAGetLastError(); if (err==WSAEWOULDBLOCK) { return(0); } D(fprintf(stderr,"hca: socket %d error %d %d\n", fd, err, len);) D(if (errno==EBADF) {printf("EBADF\n");}) return(-2); } return(len); } /* To read data that has arrived on a socket. Ungefdr som vanlig read plus en felutskrift om det blev fel. Return codes: >0 The number of characters read. 0 no data from this client. -1 The client has probably disconnected. -2 Other error. */ int hca_read_handle(HANDLE h, char *buf, const int len) { { //COMMTIMEOUTS commTimeouts={MAXDWORD,0,hca_needed_delay,0,0}; COMMTIMEOUTS commTimeouts={MAXDWORD,0,0,0,0}; if (!SetCommTimeouts(h, &commTimeouts)) { fprintf(stderr,"SetCommTimeouts failed %d\n",GetLastError()); } } { DWORD nNumberOfBytesRead; if (!ReadFile(h, buf, len, &nNumberOfBytesRead, NULL)) { fprintf(stderr,"ReadFile error %d\n", GetLastError()); return 0; } if (nNumberOfBytesRead>0) { hca_needed_delay=0; } return nNumberOfBytesRead; } } /* Accept a new socket for communication with a new client. */ int hca_accept(int serversock, int only_localhost) { /*D(printf("hca_accept %d \n",serversock);)*/ if (FD_ISSET(serversock, &hca_readfds)) { SOCKET newsock; struct sockaddr addr; int addrlen=sizeof(addr); FD_CLR((unsigned)serversock, &hca_readfds); newsock=accept(serversock,&addr, &addrlen); if (newsock==INVALID_SOCKET) { printf("accept error code %d %d\n",newsock, WSAGetLastError()); } else { D(printf("hca: accepted new socket %d\n",newsock);) if (addr.sa_family==AF_INET) { //struct hostent *hp=NULL; struct sockaddr_in *server_address; server_address=(struct sockaddr_in*)&addr; D(printf("connection from port %d ", ntohs(server_address->sin_port));) if (memcmp("\x7f\x00\x00\x01", (char*)&server_address->sin_addr, sizeof(server_address->sin_addr))!=0) { if (only_localhost) { fprintf(stderr, "rejected connection %d\n", addr.sa_family); HexPrint((char*)&server_address->sin_addr, sizeof(server_address->sin_addr)); close(newsock); return(HCA_NO_FD); } } } else { if (only_localhost) { fprintf(stderr, "rejected unknown address family %d\n", addr.sa_family); HexPrint((char*)&addr.sa_data, sizeof(addr.sa_data)); close(newsock); return(HCA_NO_FD); } } FD_SET(newsock, &hca_active_fds); return(newsock); } } return(HCA_NO_FD); } /* Returns next socket found that might have something to be read */ /* returns a negative value if no more to be read */ int hca_get_next_socket_to_read() { /* Ger igenom klienterna fvr att hitta nasta som kanske skickat negot. */ if (hca_readfds.fd_count>0) { int s=hca_readfds.fd_array[0]; FD_CLR(hca_readfds.fd_array[0], &hca_readfds); return(s); } if (std_input_fd!=HCA_NO_FD) { if (kbhit()) { return(std_input_fd); } } return(HCA_NO_FD); } /****************************************************************************/ #else /****************************************************************************/ /* This code for a unix target using Berkeley style sockets. */ /* IP server socket interface by Henrik Bjorkman 1994-11-23 For more information see an exampel server on page 4-6 in: Programmer's Guide: Networking Interfaces ISBN 0-13-020645-8 And: Internetworking with TCP/IP Volume 1; Principles, protocolls and architecture. Douglas E. Comer ISBN 0-13-474321-0 And ofcourse the man pages in unix. Serial port programming is from: http://www.linux.org/docs/ldp/howto/Serial-Programming-HOWTO/x115.html */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include /*****************************************************************************/ /* The following variables and functions are only to be used internaly. */ /* Global data for the communication */ static int hca_initiated=0; static fd_set hca_active_fds; static fd_set hca_readfds; static int hca_server_socket=HCA_NO_FD; static int hca_width=10; //static int hca_fd=0; static int hca_latest_ready=HCA_NO_FD; /* For standard input */ static struct termios hca_stdin_old_tio; static int hca_stdin_fd = HCA_NO_FD; /* Accept a new socket for communication with a new client. */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Our own signal handler. It does nothing but count the signals */ /* and print an error message */ int hca_signal_count=0; void hca_signal_handler(int i) { hca_signal_count++; fprintf(stderr,"hca: ignored signal %d\n",i); } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* The following functions are to be used by other functions. */ /* This function should be called before any of the other. Initiates global data and sets up the communication. This function must be called before uning any of the others. Returns zero. After calling this call "hca_server" or "hca_client". */ int hca_init() { if (!hca_initiated) { D(printf("hca_init:\n");) /* initiate global data */ FD_ZERO(&hca_active_fds); FD_ZERO(&hca_readfds); /* Registrating our own handler for the some signals. */ /* Otherwise the program might terminate if they happen. */ /*signal( SIGPOLL, hca_signal_handler );*/ signal( SIGPIPE, hca_signal_handler ); signal( SIGURG, hca_signal_handler ); hca_initiated=1; } return(0); } /* Initiates global data and sets up the communication as a server. This function should be called only once (only one server socket may be opened). */ int hca_server(unsigned short port) { struct sockaddr_in ServerAddress; int s; hca_init(); D(printf("hca_server: port %d\n",port);) /* Create a new socket */ if ((s=socket(AF_INET,SOCK_STREAM,0))<0) {perror("socket");exit(1);} D(printf("hca_create_server_socket: New socket %d created\n",s);) /* Store address data in an address struct to be used by bind */ ServerAddress.sin_family=AF_INET; ServerAddress.sin_port=htons(port); ServerAddress.sin_addr.s_addr=INADDR_ANY; /* bind socket to server port number */ if (bind(s,(struct sockaddr*)&ServerAddress, sizeof ServerAddress)<0) { perror("bind"); exit(1); } listen(s,8); FD_SET(s, &hca_active_fds); hca_server_socket=s; return(s); } /* Initiates global data and sets up the communication as a client. Returns <0 if not ok. */ int hca_client(const char *hostname, unsigned short port) { int s; char ownhostname[32+1]={0}; struct hostent *hp=NULL; struct sockaddr_in server_address; int err; hca_init(); D(printf("hca_client: port %d\n",port);) /* Get name of the own host if no hostname was given. */ if (hostname==NULL) { gethostname(ownhostname,32);ownhostname[32]=0;hostname=ownhostname; } D(printf("port %d host %s\n",port,hostname);) /* Get host address for host with name as in hostname */ hp=gethostbyname(hostname); if (hp==NULL) { fprintf(stderr,"Unknown host %s\n",hostname); return -1; } /* Store address data in an address struct to be used by connect */ server_address.sin_family=AF_INET; server_address.sin_port=htons(port); memcpy((char*)&server_address.sin_addr, (char*)hp->h_addr, hp->h_length); D(printf("Address family %d port %d \n",server_address.sin_family,server_address.sin_port);) /* Create a new socket SOCK_STREAM*/ s=socket(AF_INET ,SOCK_STREAM , 0 /*PF_INET*/); if (s<0) { perror("socket"); exit(1); } D(printf("hca: New socket %d created\n",s);) /* Connect socket to server */ err=connect(s,(struct sockaddr*)&server_address, sizeof(server_address)); if (err!=0) { perror("connect"); return -1; } /* Set its bit in the hca_active_fds bit mask. */ FD_SET(s, &hca_active_fds); /* Set socket to non blocking mode */ err=fcntl(s, F_SETFL,O_NDELAY); if (err) { fprintf(stderr, "hsa: socket %d fcntl returned error code %d\n", s, err); } return(s); } /* This is supposed to be called before program terminates to clean things up. */ int hca_cleanup() { int i; for(i=0;i=0) { /* restore the old port settings */ tcsetattr(hca_tty_fd,TCSANOW,&hca_oldtio); } #endif if (hca_stdin_fd>=0) { /* restore the old port settings */ tcsetattr(hca_stdin_fd,TCSANOW,&hca_stdin_old_tio); hca_stdin_fd = HCA_NO_FD; } return(0); } /* To close a socket. */ int hca_close(int s) { //int i; D(printf("hca_close: Closing %d\n",s);) close(s); FD_CLR(s, &hca_active_fds); FD_CLR(s, &hca_readfds); return(0); } /* This funktion sends data on a socket. Same as standard write but a message is printed in case of some error. */ int hca_write(int fd, const char *buf, int len) { //char *b; D(printf("hca_write: %d %d\n",fd, len);) /* Set socket to non blocking mode */ /* this should not be needed here, remove later */ { int err=fcntl(fd, F_SETFL,O_NDELAY); if (err) { fprintf(stderr, "hsa: socket %d fcntl returned error code %d\n", fd, err); } } if ((fd<0) || ((FD_ISSET(fd, &hca_active_fds))==0)) { fprintf(stderr,"not active fd %d\n",fd); return(-1); } const int n=write(fd,buf,len); if (n<0) { if (errno==EWOULDBLOCK) { return(0); } perror("write"); fprintf(stderr,"write error %d\n", n); } return(n); } /* returns the number of bytes available in the input buffer. */ /*int hca_data_available(int fd) { int bytes; ioctl(fd, FIONREAD, &bytes); return bytes; }*/ /* To read data that has arrived on a socket. Ungefdr som vanlig read plus en felutskrift om det blev fel. Return codes: >0 The number of characters read. 0 no data. -1 The client has probably disconnected. -2 Other error. */ int hca_read(int fd,char *buf, int len) { /*D(printf("hca_read: socket %d\n",fd);)*/ /* Set socket to non blocking mode */ /* this should not be needed here, remove later */ { int err=fcntl(fd, F_SETFL,O_NDELAY); if (err) { fprintf(stderr, "hca: socket %d fcntl returned error code %d\n", fd, err); } } { const int n=read(fd,buf,len); if (n>0) /* inkommande data */ { D(printf("Data recieved on socket %2d: \n",fd);) D(GraphPrint(buf,n);) D(HexPrint(buf,n);) } else if (n==0) // Client has disconnected (I think) { printf("Client has disconnected, fd=%d\n",fd); #if 0 FD_CLR(fd, &hca_active_fds); /* Deactivate client */ close(fd); #endif return(-1); } else if (n<0) /* Fel? */ { if (errno==EWOULDBLOCK) { return(0); } perror("read"); fprintf(stderr,"hca_read: socket %d error %d\n",fd,errno); return(-2); } return(n); } } /* Wait for something to happen Return codes are: <0 Something went wrong 0 Timeout >0 something received from one of the sockets or a new client wants to connect. After this function use "hca_accept" to check if a new client connected. Use "hca_get_next_socket_to_read" to check from which socket something was received. */ int hca_wait(int timeout_us) { struct timeval timeout; /* seconds and microseconds */ int nready; int i; hca_latest_ready=HCA_NO_FD; timeout.tv_sec=0; timeout.tv_usec=timeout_us; hca_width=getdtablesize(); //D(for(i=0;i=0) { int err; /* Set its bit in the hca_active_fds bit mask. */ FD_SET(newsock, &hca_active_fds); /* Set socket to non blocking mode */ err=fcntl(newsock, F_SETFL,O_NDELAY); if (err) { fprintf(stderr, "hca: socket %d fcntl returned error code %d\n", newsock, err); } return(newsock); } } return(new_socket); } #else /* Accept a new socket for communication with a new client. */ int hca_accept(int serversock, int only_localhost) { /*D(printf("hca_accept %d \n",serversock);)*/ if (FD_ISSET(serversock, &hca_readfds)) { int newsock; struct sockaddr addr; socklen_t addrlen=sizeof(addr); FD_CLR((unsigned)serversock, &hca_readfds); newsock=accept(serversock,&addr, &addrlen); if (newsock<0) { printf("accept error code, socket=%d, errno=%d\n",newsock, errno); perror("accept"); } else { D(printf("hca: accepted new socket %d\n",newsock);) if (addr.sa_family==AF_INET) { //struct hostent *hp=NULL; struct sockaddr_in *server_address; server_address=(struct sockaddr_in*)&addr; D(printf("connection from port %d ", ntohs(server_address->sin_port));) if (memcmp("\x7f\x00\x00\x01", (char*)&server_address->sin_addr, sizeof(server_address->sin_addr))!=0) { if (only_localhost) { fprintf(stderr, "rejected connection %d\n", addr.sa_family); HexPrint((char*)&server_address->sin_addr, sizeof(server_address->sin_addr)); close(newsock); return(HCA_NO_FD); } } } else { if (only_localhost) { fprintf(stderr, "rejected unknown address family %d\n", addr.sa_family); HexPrint((char*)&addr.sa_data, sizeof(addr.sa_data)); close(newsock); return(HCA_NO_FD); } } FD_SET(newsock, &hca_active_fds); return(newsock); } } return(HCA_NO_FD); } #endif #if 0 /* Returns next socket found that might have something to be read. Need to be called in a loop until there are no more sockets to read from. returns a negative value if no more to be read */ int hca_get_next_socket_to_read() { /* Ger igenom klienterna fvr att hitta nasta som kanske skickat negot. */ while (++hca_latest_ready