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

📄 cserversocket.c

📁 Gambas is a graphical development environment based on a Basic interpreter, like Visual Basic. It us
💻 C
字号:
/***************************************************************************  CServerSocket.c  Network component  (c) 2003-2004 Daniel Campos Fernández <danielcampos@netcourrier.com>  This is the implementation of the SocketServer 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 __CSERVERSOCKET_C#include <stdio.h>#include <stdlib.h>#include <string.h>#include <arpa/inet.h>#include <sys/types.h>#include <netinet/in.h>#include <sys/socket.h>#include <sys/ioctl.h>#include "main.h"#include "tools.h"#include "CServerSocket.h"#include "CSocket.h"#define UNIXPATHMAX 108DECLARE_EVENT (Connection);DECLARE_EVENT (CSERVERSOCKET_Error);void srvsock_post_error(CSERVERSOCKET* mythis){	GB.Raise((void*)mythis,CSERVERSOCKET_Error,0);	GB.Unref((void**)&mythis);}// BM: Fix bug in allocationsvoid CServerSocket_NewChild(CSERVERSOCKET *mythis,void *cli_obj){	if (mythis->nchildren++)		GB.Realloc ( (void**)&mythis->children,mythis->nchildren * sizeof(*mythis->children));	else		GB.Alloc   ( (void**)&mythis->children,mythis->nchildren * sizeof(*mythis->children));	mythis->children[mythis->nchildren-1]=cli_obj;}void CServerSocket_DeleteChild(CSERVERSOCKET *mythis,void *cli_obj){	int myloop;	int myloop2;	if (!mythis->nchildren) return;	for (myloop=0;myloop<mythis->nchildren;myloop++)	{		if (mythis->children[myloop]==cli_obj)		{			for (myloop2=myloop;myloop2<(mythis->nchildren-1);myloop2++)				mythis->children[myloop2]=mythis->children[myloop2+1];			if ( --mythis->nchildren)			{				GB.Realloc ( (void**)&mythis->children,mythis->nchildren * sizeof(*mythis->children));			}			else			{				GB.Free ((void**)&mythis->children);				mythis->children=NULL;			}			return;		}	}}void CServerSocket_OnClose(void *sck){	CSOCKET *chd=(CSOCKET*)sck;	CSERVERSOCKET *mythis;	if (!chd) return;	if (!chd->c_parent) return;	CServerSocket_DeleteChild(chd->c_parent,sck);	mythis=(CSERVERSOCKET*)chd->c_parent;	mythis->iCurConn--;}void CServerSocket_CallBack(int fd,int type,long lParam){	int okval=0;	char *rem_ip_buf;	int ClientLen;	CSERVERSOCKET *mythis;	mythis=(CSERVERSOCKET*)lParam;	if ( mythis->iStatus != 1) return;	mythis->iStatus=2;	ClientLen=sizeof(struct sockaddr_in);	mythis->Client=accept(mythis->ServerSocket,(struct sockaddr*)&mythis->so_client.in,&ClientLen);	if (mythis->Client == -1)	{		close(mythis->Client);		mythis->iStatus=1;		return;	}	rem_ip_buf=inet_ntoa(mythis->so_client.in.sin_addr);	if ( (!mythis->iMaxConn) || (mythis->iCurConn < mythis->iMaxConn) ) okval=1;	if ( (!mythis->iPause) && (okval) )		GB.Raise(mythis,Connection,1,GB_T_STRING,rem_ip_buf,0);	if  ( mythis->iStatus == 2) close(mythis->Client);	mythis->iStatus=1;}void CServerSocket_CallBackUnix(int fd,int type,long lParam){	//int position=0;	int okval=0;	int ClientLen;	CSERVERSOCKET *mythis;	mythis=(CSERVERSOCKET*)lParam;	if ( mythis->iStatus != 1) return;	mythis->iStatus=2;	ClientLen=sizeof(struct sockaddr_un);	mythis->Client=accept(mythis->ServerSocket,(struct sockaddr*)&mythis->so_client.un,&ClientLen);	if (mythis->Client == -1)	{		close(mythis->Client);		mythis->iStatus=1;		return;	}	if ( (!mythis->iMaxConn) || (mythis->iCurConn < mythis->iMaxConn) ) okval=1;	if ( (!mythis->iPause) && (okval) )		GB.Raise(mythis,Connection,1,GB_T_STRING,NULL,0);	if  ( mythis->iStatus == 2) close(mythis->Client);	mythis->iStatus=1;}/*************************************************** This property reflects current status of the socket (closed, listening...) ***************************************************/BEGIN_PROPERTY ( CSERVERSOCKET_MaxPathLength )	GB.ReturnInteger(UNIXPATHMAX);END_PROPERTY/*************************************************** This property reflects current status of the socket (closed, listening...) ***************************************************/BEGIN_PROPERTY ( CSERVERSOCKET_Status )	GB.ReturnInteger(THIS->iStatus);END_PROPERTY/****************************************************************** This property gets/sets the port to listen to (TCP or UDP sockets) ******************************************************************/BEGIN_PROPERTY ( CSERVERSOCKET_Port )	if (READ_PROPERTY)	{		GB.ReturnInteger(THIS->iPort);		return;	}	if (THIS->iStatus>0)	{		GB.Error("Port value can not be changed when socket is active");		return;	}	if ( (VPROP(GB_INTEGER)<1) || (VPROP(GB_INTEGER)>65535) )	{		GB.Error("Invalid Port Value");		return;	}	THIS->iPort=VPROP(GB_INTEGER);END_PROPERTY/*************************************************************** This property gets/sets the address to listen to (UNIX socket) ***************************************************************/BEGIN_PROPERTY ( CSERVERSOCKET_Path )	char *tmpstr=NULL;	if (READ_PROPERTY)	{		GB.ReturnString(THIS->sPath);		return;	}	if (THIS->iStatus>0)	{		GB.Error("Path value can not be changed when socket is active");		return;	}	tmpstr=GB.ToZeroString ( PROP(GB_STRING) );	if ( (strlen(tmpstr)<1) || (strlen(tmpstr)>UNIXPATHMAX) )	{		GB.Error ("Invalid path length");		return;	}	GB.StoreString(PROP(GB_STRING), &THIS->sPath);END_PROPERTY/*************************************************************** This property gets/sets the socket type (0 -> TCP, 1 -> UNIX) ***************************************************************/BEGIN_PROPERTY ( CSERVERSOCKET_Type )	if (READ_PROPERTY)	{		GB.ReturnInteger(THIS->iSockType);		return;	}	if (THIS->iStatus>0)	{		GB.Error("Socket Type can not be changed when socket is active");		return;	}	if ( (VPROP(GB_INTEGER)<0) || (VPROP(GB_INTEGER)>1) )	{		GB.Error("Invalid Socket Type Value");		return;	}	THIS->iSockType=VPROP(GB_INTEGER);END_PROPERTY/*********************************************** Gambas object "Constructor" ***********************************************/BEGIN_METHOD(CSERVERSOCKET_new,GB_STRING sPath;GB_INTEGER iMaxConn;)	int retval;	char *buf=NULL;	int nport=0;	int iMax=0;	THIS->iPort=0;	THIS->iStatus=0;	THIS->sPath=NULL;	THIS->iPause=0;	THIS->iMaxConn=0;	THIS->iCurConn=0;	THIS->iSockType=1;	THIS->children=NULL;	THIS->nchildren=0;	if (MISSING(sPath)) return;	if (!STRING(sPath)) return;	if (!MISSING(iMaxConn)) iMax=VARG(iMaxConn);	retval=IsHostPath(STRING(sPath),&buf,&nport);	if (!retval)	{		GB.Error("Invalid Host / Path string");		return;	}	if (retval==2)	{		THIS->iSockType=0;		buf=GB.ToZeroString ( (GB_STRING*)STRING(sPath) );		if ( (strlen(buf)<1) || (strlen(buf)>UNIXPATHMAX) )		{			GB.Error ("Invalid path length");			return;		}		GB.StoreString((GB_STRING*)STRING(sPath),&THIS->sPath);		return;	}	else	{		if (buf)		{			GB.Free((void**)&buf);			GB.Error("Invalid Host String");			return;		}		if (nport<1)		{			GB.Error("Invalid Port value");			return;		}		THIS->iSockType=1;		THIS->iPort=nport;	}	switch(srvsock_listen(THIS,iMax))	{		case 1:			GB.Error("Socket is already listening");			return;		case 7:			GB.Error ("You must define Path");			return;		case 8:			GB.Error ("Error. You must define port");			return;		case 13:			GB.Error ("Invalid maximun connections value");			return;	}END_METHODvoid close_server(CSERVERSOCKET *mythis){	CSOCKET *chd;	if (mythis->iStatus <= 0) return;	GB.Watch (mythis->ServerSocket , GB_WATCH_NONE , (void *)CServerSocket_CallBack,0);	close(mythis->ServerSocket);	mythis->iStatus=0;	if (!mythis->nchildren) return;	while(mythis->nchildren)	{		chd=(CSOCKET*)mythis->children[0];		if (chd->stream.desc) CSocket_stream_close(&chd->stream);		CServerSocket_DeleteChild(mythis,(void*)chd);	}}/************************************************* Gambas object "Destructor" *************************************************/BEGIN_METHOD_VOID(CSERVERSOCKET_free)	close_server(THIS);	GB.FreeString(&THIS->sPath);END_METHOD/******************************************************** Stops listening (TCP/UDP/UNIX), and closes all client sockets associated to this server *********************************************************/BEGIN_METHOD_VOID(CSERVERSOCKET_Close)	close_server(THIS);END_METHOD/******************************************************** Do not accept more connections until Resume is used *********************************************************/BEGIN_METHOD_VOID(CSERVERSOCKET_Pause)	THIS->iPause=1;END_METHOD/******************************************************** Accept connections again *********************************************************/BEGIN_METHOD_VOID(CSERVERSOCKET_Resume)	THIS->iPause=0;END_METHOD/********************************************************* Starts listening (TCP/UDP/UNIX) **********************************************************/int srvsock_listen(CSERVERSOCKET* mythis,int mymax){	int NoBlock=1;	int retval;	int auth = 1;	if ( (!mythis->iPort) && (mythis->iSockType) ) return 8;	if ( mythis->iStatus >0 ) return 1;	if (mymax<0) return 13;	if ( (!mythis->iSockType) && (!mythis->sPath) ) return 7;	if (mythis->iSockType)	{		mythis->so_server.in.sin_family=AF_INET;		mythis->so_server.in.sin_addr.s_addr=INADDR_ANY;		mythis->so_server.in.sin_port=htons(mythis->iPort);		mythis->ServerSocket=socket(PF_INET,SOCK_STREAM,0);	}	else	{		unlink(mythis->sPath);		mythis->so_server.un.sun_family=AF_UNIX;		strcpy(mythis->so_server.un.sun_path,mythis->sPath);		mythis->ServerSocket=socket(AF_UNIX,SOCK_STREAM,0);	}	if ( mythis->ServerSocket==-1 )	{		mythis->iStatus=-2;		GB.Ref(mythis);		GB.Post(srvsock_post_error,(long)mythis);		return 2;	}	// thanks to Benoit : this option allows non-root users to reuse the	// port after closing it and reopening it in a short interval of time.	// However, If you are porting this component to other O.S., be careful,	// as this is not a standard unix option	setsockopt(mythis->ServerSocket, SOL_SOCKET, SO_REUSEADDR, &auth, sizeof(int));	//	if (mythis->iSockType)		retval=bind(mythis->ServerSocket,(struct sockaddr*)&mythis->so_server.in, \			sizeof(struct sockaddr_in));	else		retval=bind(mythis->ServerSocket,(struct sockaddr*)&mythis->so_server.un, \			sizeof(struct sockaddr_un));	if (retval==-1)	{		close(mythis->ServerSocket);		mythis->iStatus=-10;		GB.Ref(mythis);		GB.Post(srvsock_post_error,(long)mythis);		return 10;	}	ioctl(mythis->ServerSocket,FIONBIO,&NoBlock);	if ( listen(mythis->ServerSocket,mymax) == -1 )	{		close(mythis->ServerSocket);		mythis->iStatus=-14;		GB.Ref(mythis);		GB.Post(srvsock_post_error,(long)mythis);		return 14;	}	mythis->iCurConn=0;	mythis->iMaxConn=mymax;	mythis->iStatus=1;	//CServerSocket_AssignCallBack((long)mythis,mythis->ServerSocket);	if (mythis->iSockType)		GB.Watch (mythis->ServerSocket , GB_WATCH_READ , (void *)CServerSocket_CallBack,(long)mythis);	else		GB.Watch (mythis->ServerSocket , GB_WATCH_READ , (void *)CServerSocket_CallBackUnix,(long)mythis);	return 0;}BEGIN_METHOD(CSERVERSOCKET_Listen,GB_INTEGER MaxConn;)	int retval;	int mymax=0; 	if (!MISSING(MaxConn)) mymax=VARG(MaxConn);	retval=srvsock_listen(THIS,mymax);	switch(retval)	{		case 1:			GB.Error("Socket is already listening");			return;		case 7:			GB.Error ("You must define Path");			return;		case 8:			GB.Error ("Error. You must define port");			return;		case 13:			GB.Error ("Invalid maximun connections value");			return;	}END_METHOD/****************************************************************** To accept a pending connection and delegate it to a Socket object*******************************************************************/BEGIN_METHOD_VOID(CSERVERSOCKET_Accept) CSOCKET *cli_obj; struct sockaddr_in myhost; int mylen; if ( THIS->iStatus != 2){ GB.Error("No connection to accept");return; } GB.New((void**)&cli_obj,GB.FindClass("Socket"),"Socket",NULL); cli_obj->Socket=THIS->Client; cli_obj->iStatus=7; cli_obj->c_parent=(void*)THIS; cli_obj->OnClose=CServerSocket_OnClose; THIS->iCurConn++; GB.FreeString ( &cli_obj->sRemoteHostIP); GB.FreeString ( &cli_obj->sLocalHostIP); GB.FreeString ( &cli_obj->sPath); cli_obj->iLocalPort=0; cli_obj->iPort=0; cli_obj->conn_type=0; if (THIS->iSockType) { 	GB.NewString ( &cli_obj->sRemoteHostIP , inet_ntoa(THIS->so_client.in.sin_addr) ,0); 	GB.NewString ( &cli_obj->Host, inet_ntoa(THIS->so_client.in.sin_addr) ,0);	mylen=sizeof(struct sockaddr); 	getsockname (cli_obj->Socket,(struct sockaddr*)&myhost,&mylen); 	GB.NewString ( &cli_obj->sLocalHostIP , inet_ntoa(myhost.sin_addr) ,0); 	cli_obj->iLocalPort=ntohs(myhost.sin_port); 	cli_obj->iPort=ntohs(THIS->so_client.in.sin_port);	cli_obj->iUsePort=ntohs(THIS->so_client.in.sin_port); } else { 	cli_obj->conn_type=1; 	GB.NewString ( &cli_obj->sPath,THIS->sPath,0);	GB.NewString ( &cli_obj->Path,THIS->sPath,0); } cli_obj->stream.desc=&SocketStream; cli_obj->stream._free[0]=(long)cli_obj; GB.Watch (cli_obj->Socket,GB_WATCH_WRITE,(void *)CSocket_CallBack,(long)cli_obj); CServerSocket_NewChild(THIS,cli_obj); GB.Ref(cli_obj); GB.Post(CSocket_post_connected,(long)cli_obj); THIS->iStatus=3; GB.ReturnObject((void*)cli_obj);END_METHOD/**************************************************************** Here we declare public structure of the ServerSocket class*****************************************************************/GB_DESC CServerSocketDesc[] ={  GB_DECLARE("ServerSocket", sizeof(CSERVERSOCKET)),  GB_EVENT("Connection", NULL, "(RemoteHostIP)s", &Connection),  GB_EVENT("Error", NULL,NULL, &CSERVERSOCKET_Error),  GB_METHOD("_new", NULL, CSERVERSOCKET_new,"[(Path)s(MaxConn)i]"),  GB_METHOD("_free", NULL, CSERVERSOCKET_free, NULL),  GB_METHOD("Listen",NULL, CSERVERSOCKET_Listen, "[(MaxConn)i]"),  GB_METHOD("Pause", NULL, CSERVERSOCKET_Pause, NULL),  GB_METHOD("Resume", NULL, CSERVERSOCKET_Resume, NULL),  GB_METHOD("Accept","Socket",CSERVERSOCKET_Accept,NULL),  GB_METHOD("Close",NULL,CSERVERSOCKET_Close,NULL),  GB_PROPERTY("Type","i<Net,Internet,Local>",CSERVERSOCKET_Type),  GB_PROPERTY("Path","s",CSERVERSOCKET_Path),  GB_PROPERTY("Port", "i", CSERVERSOCKET_Port),  GB_PROPERTY_READ("Status","i",CSERVERSOCKET_Status),  GB_STATIC_PROPERTY_READ("MaxPathLength","i",CSERVERSOCKET_MaxPathLength),  GB_CONSTANT("_Properties", "s", "Type=0,Path,Port"),  GB_CONSTANT("_DefaultEvent", "s", "Connection"),  GB_END_DECLARE};

⌨️ 快捷键说明

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