📄 csocket.c
字号:
/*************************************************************************** CSocket.c Network component (c) 2003-2004 Daniel Campos Fernández <danielcampos@netcourrier.com> This is the implementation of Socket Gambas Class This program 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 1, 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, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.***************************************************************************/#define __CSOCKET_C#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <errno.h>#include <sys/types.h>#include <sys/socket.h>#include <sys/ioctl.h>#include <sys/poll.h>#include <sys/un.h>#include <netinet/in.h>#include <arpa/inet.h>#include <unistd.h>#include <netdb.h>#include <time.h>#include "main.h"#include "tools.h"#include "CSocket.h"#include "CServerSocket.h"#include "CDnsClient.h"#define MAX_CLIENT_BUFFER_SIZE 65536#define UNIXPATHMAX 108DECLARE_EVENT (SocketError);DECLARE_EVENT (Closed);DECLARE_EVENT (HostFound);DECLARE_EVENT (Socket_Read);DECLARE_EVENT (Connected);GB_STREAM_DESC SocketStream = { CSocket_stream_open, CSocket_stream_close, CSocket_stream_read, CSocket_stream_write, CSocket_stream_seek, CSocket_stream_tell, CSocket_stream_flush, CSocket_stream_eof, CSocket_stream_lof};/********************************** Routines to call events **********************************/void CSocket_post_error(CSOCKET *mythis){ GB.Raise(mythis,SocketError,0); GB.Unref((void**)&mythis);}void CSocket_post_closed(CSOCKET *mythis){ GB.Raise(mythis,Closed,0); GB.Unref((void**)&mythis);}void CSocket_post_hostfound(CSOCKET *mythis){ GB.Raise(mythis,HostFound,0); GB.Unref((void**)&mythis);}void CSocket_post_connected(CSOCKET *mythis){ GB.Raise(mythis,Connected,0); GB.Unref((void**)&mythis);}void CSocket_post_data_available(CSOCKET *mythis){ if (mythis->iStatus==7) GB.Raise(mythis,Socket_Read,0); GB.Unref((void**)&mythis);}/************************************************** This function is called by DnsClient to inform that it has finished its work *************************************************/void CSocket_CallBackFromDns(void *myobj){ int NoBlock=1; int myval=0; CSOCKET *mythis; mythis=(CSOCKET*)myobj; if ( mythis->iStatus != 5) return; if ( !mythis->DnsTool->sHostIP) { mythis->iStatus=-6; /* error host not found */ dns_close_all(mythis->DnsTool); GB.Unref((void**)&mythis->DnsTool); mythis->DnsTool=NULL; GB.Ref (mythis); GB.Post (CSocket_post_error,(long)mythis); if (mythis->OnClose) mythis->OnClose((void*)mythis); return; } GB.FreeString (&mythis->sRemoteHostIP); GB.NewString ( &mythis->sRemoteHostIP ,mythis->DnsTool->sHostIP,0); /* Let's turn socket to async mode */ ioctl(mythis->Socket,FIONBIO,&NoBlock); /* Third, we connect the socket */ mythis->Server.sin_family=AF_INET; mythis->Server.sin_port=htons(mythis->iPort); mythis->Server.sin_addr.s_addr =inet_addr(mythis->DnsTool->sHostIP); bzero(&(mythis->Server.sin_zero),8); myval=connect(mythis->Socket,(struct sockaddr*)&(mythis->Server), sizeof(struct sockaddr)); if (errno==EINPROGRESS) /* this is the good answer : connect in progress */ { mythis->iStatus=6; GB.Watch (mythis->Socket,GB_WATCH_WRITE,(void *)CSocket_CallBackConnecting,(long)mythis); } else { GB.Watch (mythis->Socket , GB_WATCH_NONE , (void *)CSocket_CallBack,0); mythis->stream.desc=NULL; close(mythis->Socket); mythis->iStatus=0; } if (mythis->DnsTool) { dns_close_all(mythis->DnsTool); GB.Unref((void**)&mythis->DnsTool); mythis->DnsTool=NULL; } if ( mythis->iStatus<=0 ) { mythis->iStatus=-3; GB.Ref (mythis); GB.Post (CSocket_post_error,(long)mythis); if (mythis->OnClose) mythis->OnClose((void*)mythis); return; } GB.Ref(mythis); GB.Post(CSocket_post_hostfound,(long)mythis);}/******************************************************************* This CallBack is used while waiting to finish a connection process ******************************************************************/void CSocket_CallBackConnecting(int t_sock,int type,long lParam){ struct sockaddr_in myhost; int mylen; struct timespec mywait; CSOCKET *mythis; /* Just sleeping a little to reduce CPU waste */ mywait.tv_sec=0; mywait.tv_nsec=1000000; nanosleep(&mywait,NULL); mythis=(CSOCKET*)lParam; if (mythis->iStatus!=6) return; /**************************************************** Checks if Connection was Stablished or there was an error trying to connect ****************************************************/ mythis->iStatus=CheckConnection(mythis->Socket); if (mythis->iStatus == 0) { GB.Watch (mythis->Socket , GB_WATCH_NONE , (void *)CSocket_CallBack,0); mythis->stream.desc=NULL; close(mythis->Socket); mythis->iStatus=-3; GB.Ref (mythis); GB.Post (CSocket_post_error,(long)mythis); if (mythis->OnClose) mythis->OnClose((void*)mythis); return; } if (mythis->iStatus != 7) return; // we obtain local IP and host mylen=sizeof(struct sockaddr); getsockname (mythis->Socket,(struct sockaddr*)&myhost,&mylen); mythis->iLocalPort=ntohs(myhost.sin_port); GB.FreeString( &mythis->sLocalHostIP); GB.NewString ( &mythis->sLocalHostIP ,inet_ntoa(myhost.sin_addr),0); GB.Watch (mythis->Socket,GB_WATCH_NONE,(void *)CSocket_CallBack,(long)mythis); GB.Watch (mythis->Socket,GB_WATCH_WRITE,(void *)CSocket_CallBack,(long)mythis); mythis->stream.desc=&SocketStream; mythis->stream._free[0]=(long)mythis; GB.Ref(mythis); GB.Post(CSocket_post_connected,(long)mythis);}/******************************************************************* This CallBack is used while socket is connected to remote host ******************************************************************/void CSocket_CallBack(int t_sock,int type,long lParam){ char buf[1]; struct pollfd mypoll; int numpoll; struct timespec mywait; CSOCKET *mythis; /* Just sleeping a little to reduce CPU waste */ mywait.tv_sec=0; mywait.tv_nsec=100000; nanosleep(&mywait,NULL); /* is there data avilable or an error? */ mythis=(CSOCKET*)lParam; if (mythis->iStatus!=7) return; mypoll.fd=t_sock; mypoll.events=POLLIN | POLLNVAL; mypoll.revents=0; numpoll=poll(&mypoll,1,0); if (numpoll<=0) return; /* there's data available */ USE_MSG_NOSIGNAL(numpoll=recv(t_sock,(void*)buf,sizeof(char),MSG_PEEK | MSG_NOSIGNAL)); if (!numpoll) { /* socket error, no valid data received */ GB.Watch (mythis->Socket , GB_WATCH_NONE , (void *)CSocket_CallBack,0); mythis->stream.desc=NULL; close(t_sock); mythis->iStatus=0; GB.Ref(mythis); GB.Post(CSocket_post_closed,(long)mythis); if (mythis->OnClose) mythis->OnClose((void*)mythis); return; } /****************************************************** There's data available to read, so we'll raise event Socket_Read *******************************************************/ GB.Ref(mythis); GB.Post(CSocket_post_data_available,(long)mythis); }void CSocket_stream_internal_error(CSOCKET *mythis,int ncode){ /* fatal socket error handling */ GB.Watch (mythis->Socket,GB_WATCH_NONE,(void *)CSocket_CallBack,0); mythis->stream.desc=NULL; close(mythis->Socket); mythis->iStatus = ncode;}////////////////////////////////////////////////////////////////////////////////////################################################################################/********************************************************************************* "PUBLIC" C/C++ INTERFACE**********************************************************************************///################################################################################///////////////////////////////////////////////////////////////////////////////////* not allowed methods */int CSocket_stream_open(GB_STREAM *stream, const char *path, int mode, void *data){return -1;}int CSocket_stream_seek(GB_STREAM *stream, long pos, int whence){return -1;}int CSocket_stream_tell(GB_STREAM *stream, long *pos){return -1;}int CSocket_stream_flush(GB_STREAM *stream){ return 0; /* OK */}int CSocket_stream_close(GB_STREAM *stream){ CSOCKET *mythis; if (!(mythis=(CSOCKET*)stream->_free[0]) ) return -1; if (mythis->DnsTool) { dns_close_all(mythis->DnsTool); GB.Unref((void**)&mythis->DnsTool); mythis->DnsTool=NULL; } if (mythis->iStatus > 0) /* if it's not connected, does nothing */ { GB.Watch (mythis->Socket , GB_WATCH_NONE , (void *)CSocket_CallBack,0); stream->desc=NULL; close(mythis->Socket); mythis->iStatus=0; } if (mythis->OnClose) mythis->OnClose((void*)mythis); return 0;}int CSocket_stream_lof(GB_STREAM *stream, long *len){ CSOCKET *mythis; int bytes; *len=0; if (!(mythis=(CSOCKET*)stream->_free[0]) ) return -1; if (ioctl(mythis->Socket,FIONREAD,&bytes)) { CSocket_stream_internal_error(mythis,-4); if (mythis->OnClose) mythis->OnClose((void*)mythis); return -1; } *len=bytes; return 0;}int CSocket_stream_eof(GB_STREAM *stream){ CSOCKET *mythis; int bytes; if (!(mythis=(CSOCKET*)stream->_free[0]) ) return -1; if (ioctl(mythis->Socket,FIONREAD,&bytes)) { CSocket_stream_internal_error(mythis,-4); if (mythis->OnClose) mythis->OnClose((void*)mythis); return -1; } if (!bytes) return -1; return 0;}int CSocket_stream_read(GB_STREAM *stream, char *buffer, long len){ CSOCKET *mythis; int npos=-1; int NoBlock=0; int bytes; if (!(mythis=(CSOCKET*)stream->_free[0]) ) return -1; if (ioctl(mythis->Socket,FIONREAD,&bytes)) { CSocket_stream_internal_error(mythis,-4); if (mythis->OnClose) mythis->OnClose((void*)mythis); return -1; } if (bytes < len) return -1; ioctl(mythis->Socket,FIONBIO,&NoBlock); USE_MSG_NOSIGNAL(npos=recv(mythis->Socket,(void*)buffer,len*sizeof(char),MSG_NOSIGNAL)); NoBlock++; ioctl(mythis->Socket,FIONBIO,&NoBlock); if (npos==len) return 0; if (npos<0) { CSocket_stream_internal_error(mythis,-4); if (mythis->OnClose) mythis->OnClose((void*)mythis); return -1; } if (mythis->OnClose) mythis->OnClose((void*)mythis); return -1;}int CSocket_stream_write(GB_STREAM *stream, char *buffer, long len){ CSOCKET *mythis; int npos=-1; int NoBlock=0; if (!(mythis=(CSOCKET*)stream->_free[0]) ) return -1; ioctl(mythis->Socket,FIONBIO,&NoBlock); USE_MSG_NOSIGNAL(npos=send(mythis->Socket,(void*)buffer,len*sizeof(char),MSG_NOSIGNAL)); NoBlock++; ioctl(mythis->Socket,FIONBIO,&NoBlock); if (npos>=0) return 0; CSocket_stream_internal_error(mythis,-5); if (mythis->OnClose) mythis->OnClose((void*)mythis); return -1;}/************************************************************************** To start a UNIX connection **************************************************************************/int CSocket_connect_unix(CSOCKET *mythis,char *sPath,int lenpath){ int NoBlock=1; if ( mythis->iStatus > 0 ) return 1; if (!sPath) return 7; if ( (lenpath<1) || (lenpath>UNIXPATHMAX) ) return 7; GB.FreeString(&mythis->sRemoteHostIP); GB.FreeString(&mythis->sLocalHostIP); mythis->UServer.sun_family=AF_UNIX; strcpy(mythis->UServer.sun_path,sPath); if ( (mythis->Socket=socket(AF_UNIX,SOCK_STREAM,0))==-1 ) { mythis->iStatus=-2; GB.Ref (mythis); CSocket_post_error(mythis); /* Unable to create socket */ return 2; } GB.FreeString(&mythis->sPath); GB.NewString ( &mythis->sPath , mythis->UServer.sun_path ,0); mythis->conn_type=1; if (connect(mythis->Socket,(struct sockaddr*)&mythis->UServer,sizeof(struct sockaddr_un))==0) { mythis->iStatus=7; ioctl(mythis->Socket,FIONBIO,&NoBlock); GB.Watch (mythis->Socket,GB_WATCH_WRITE,(void *)CSocket_CallBack,(long)mythis); mythis->stream.desc=&SocketStream; mythis->stream._free[0]=(long)mythis; // $BM if (mythis->Host) GB.FreeString(&mythis->Host); if (mythis->Path) GB.FreeString(&mythis->Path); GB.NewString(&mythis->Path,sPath,0); GB.Ref (mythis); CSocket_post_connected(mythis); return 0; } /* Error */ mythis->stream.desc=NULL; close(mythis->Socket); GB.FreeString(&mythis->sPath); mythis->iStatus=-3; GB.Ref (mythis); CSocket_post_error(mythis); /* Unable to connect to remote host */ return 3;}/************************************************************************** To start a TCP connection **************************************************************************/int CSocket_connect_socket(CSOCKET *mythis,char *sHost,int lenhost,int myport){ if ( mythis->iStatus > 0 ) return 1; if (!lenhost) return 9; if (!sHost) return 9; if ( (myport<1) || (myport>65535) ) return 8; GB.FreeString(&mythis->sRemoteHostIP); GB.FreeString(&mythis->sLocalHostIP); if ( (mythis->Socket=socket(AF_INET,SOCK_STREAM,0))==-1 )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -