Difference between revisions of "Server.c"

From Organic Design wiki
m
(use nodeState)
Line 131: Line 131:
 
n = nodeLoopInsert(n,nodeNULL);
 
n = nodeLoopInsert(n,nodeNULL);
 
nodeSetValue(nodeCLIENTS,nodeLOOP,n);
 
nodeSetValue(nodeCLIENTS,nodeLOOP,n);
nodeSetState(n,nodeNULL,&client);
 
 
nodeSetValue(n,nodeCODE,nodeTRUE);
 
nodeSetValue(n,nodeCODE,nodeTRUE);
nodeSetState(n,nodeSTREAMINFO,newsi);
+
*nodeState(n,nodeNULL) = &client;
 +
*nodeState(n,nodeSTREAMINFO) = newsi;
 
}
 
}
 
else logErr("accept(): failed!");
 
else logErr("accept(): failed!");
Line 144: Line 144:
 
void client() {
 
void client() {
 
// Get the info for this stream ready for reading/writing a packet if necessary
 
// Get the info for this stream ready for reading/writing a packet if necessary
streamInfo *info = nodeGetState(this, nodeSTREAMINFO);
+
streamInfo *info = *nodeState(this, nodeSTREAMINFO);
 
int i,fd = info->fd, inptr = info->inptr, outptr = info->outptr;
 
int i,fd = info->fd, inptr = info->inptr, outptr = info->outptr;
 
char *inbuf = info->inbuf, *outbuf = info->outbuf;
 
char *inbuf = info->inbuf, *outbuf = info->outbuf;

Revision as of 12:58, 31 July 2006

// This article and all its includes are licenced under LGPL // GPL: http://www.gnu.org/copyleft/lesser.html // SRC: http://www.organicdesign.co.nz/server.c


  1. define svrDELAY 0 // normal operation is 0 for no delay
  2. define svrPAKSIZE 128 // keep packet-size small for non-multithreaded design
  3. define svrBUFSIZE 10000 // dictates max message size
  4. define svrMAXCLIENTS 1000 // used by listen()
  5. ifndef __WIN32__
  6. define WSAGetLastError() errno
  7. endif

// Socket structures and variables struct sockaddr_in addr; struct timeval to; fd_set fdset; unsigned long int sockopt_on; int sock;

// struct for a stream-node's state to point to typedef struct siStruct { int fd, inptr, outptr; char *inbuf, *outbuf; } streamInfo;

// Function prototypes //void server(); // declared earlier in nodalHusk since called in root loop //void client(); int server_init(); int server_exit(); int nonblocking(int socket);

int server_init() {

#if __WIN32__ WSADATA wsaData; if (WSAStartup(MAKEWORD(2,0),&wsaData)!=0) logErr("WSAStartup() failed!"); #endif

// Set up structures for socket & select sockopt_on = 1; int szAddr = sizeof(struct sockaddr_in); memset((char*)&addr, 0, szAddr); // zero the struct addr.sin_family = AF_INET; addr.sin_port = htons(port); addr.sin_addr.s_addr = htonl(INADDR_ANY); errno = 0;

// struct for a stream-node's state to point to typedef struct siStruct { int fd, inptr, outptr; char *inbuf, *outbuf; } streamInfo;

// Do the usual socket polava: create,options,bind,listen if ((sock = socket(PF_INET,SOCK_STREAM,IPPROTO_TCP))<0) logErrNum("socket() failed returning %d",WSAGetLastError()); if (setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,(char*)&sockopt_on,sizeof(int))<0) logErr("setsockopt() failed!"); if (bind(nonblocking(sock),(struct sockaddr*)&addr,szAddr)<0) logErr("bind() failed!"); if (listen(sock,svrMAXCLIENTS)<0) logErr("listen() failed!"); if (errno) logAdd("Server failed to start!");

if (errno == 0) { char *msg = malloc(100); sprintf(msg,"Daemon \"%s\" started successfully and serving on port %d.",peer,port); logAdd(msg); free(msg); } return errno; }

// Perform any cleanup for socket int server_exit() { // todo: close streams and free buffers etc #if __WIN32__ WSACleanup(); #endif return WSAGetLastError(); }

// make the passed socket non-blocking so accept() returns straight away for multiplexed model // - if no incoming requests, returns EAGAIN or EWOULDBLOCK state int nonblocking(int socket) { #if __WIN32__ ioctlsocket(socket,FIONBIO,&sockopt_on); #else fcntl(socket,F_SETFL,fcntl(socket,F_GETFL)|O_NONBLOCK); #endif return socket; }

// Parses a message content and responds to client void processMessage(int fd,char *msg) {

//char **items = split(' ',msg); //char **path = split('/',items[1]); //if (strncmp(path[1],"stop",4)==0) { logAdd("stop recieved."); exit(EXIT_SUCCESS); } if (msg) printf(msg); //printf("\nRequest: %s\n",path[1]);

// Create a new context node

// validate and extract event, params and mime-type // /GET\s+\/+(.*?)(\/(.+))?\s+(HTTP\/[0-9.]+)/

// add appropriate response to nodal context // - restart, click?x&y, else content/mime/type

send(fd,"HTTP/1.1 200 OK\r\nDate: Mon, 31 Jul 2006 22:27:14 NZST\r\nContent-Type: text/html\r\nConnection: close\r\nContent-Length: 9\r\n\r\nStink Ow!",129,0); }

// Function called by each stream-node in network's reduction loop // - there is also a streams-container node containing zero or more stream nodes void server() { FD_ZERO(&fdset); FD_SET(sock,&fdset); to.tv_sec = to.tv_usec = svrDELAY; if (select(sock+1,&fdset,NULL,NULL,&to)>0) { // New connection request, accpet and create new stream-node int fd = nonblocking(accept(sock,NULL,NULL)); if (fd>0) { printf("New connection: Stream%d.\n",fd); streamInfo *newsi = malloc(sizeof(streamInfo)); newsi->fd = fd; newsi->inbuf = malloc(svrBUFSIZE); newsi->outbuf = malloc(svrBUFSIZE); newsi->inptr = 0; newsi->outptr = 0; node n = nodeGetValue(nodeCLIENTS,nodeLOOP); n = nodeLoopInsert(n,nodeNULL); nodeSetValue(nodeCLIENTS,nodeLOOP,n); nodeSetValue(n,nodeCODE,nodeTRUE); *nodeState(n,nodeNULL) = &client; *nodeState(n,nodeSTREAMINFO) = newsi; } else logErr("accept(): failed!"); } printf("server()\n"); }


// Each of the stream nodes points to this function in its State void client() { // Get the info for this stream ready for reading/writing a packet if necessary streamInfo *info = *nodeState(this, nodeSTREAMINFO); int i,fd = info->fd, inptr = info->inptr, outptr = info->outptr; char *inbuf = info->inbuf, *outbuf = info->outbuf;

// Data to receive? FD_ZERO(&fdset); FD_SET(fd,&fdset); to.tv_sec = to.tv_usec = svrDELAY; if (select(fd+1,&fdset,NULL,NULL,&to)>0) { // read a packet into inbuf if (i = recv(fd,inbuf+inptr,svrPAKSIZE,0)>0) {

// test if complete message in buffer char *message = NULL; //while (i--) { // /\r?\n\r?\n\x00?/ // }

//if (message) { //inptr = info->inptr -= msg_size; // hook a process into the loop processMessage(fd,message); // } } else if (i == 0) { // zero bytes to read, do orderly termination printf("Stream%d closed.\n",fd); //nodeLoopRemove(this); // NOTE: reduction not handling PREV free(inbuf); free(outbuf); free(info); } else logErr("recv(): failed!"); }

printf("client(%d)\n",fd); return; // Data to send? FD_ZERO(&fdset); FD_SET(fd,&fdset); to.tv_sec = to.tv_usec = svrDELAY; if (select(fd+1,NULL,&fdset,NULL,&to)>0) { // write a packet from outbuf //int len = svrPAKSIZE; // or less //if (send(fd,outbuf+outptr,len,0)<0) logErr("send() failed!"); }

}