#include "scgi.h"
namespace cppcms {
using namespace std;
namespace scgi {
streamsize scgi_outbuffer:: xsputn ( const char * s, streamsize n )
{
int v;
size=n;
n=0;
while((v=::write(fd,s,size))!=size){
if(v<0) {
if(errno==EINTR)
continue;
return EOF;
}
else if(v==0) {
return n;
}
else {
n+=v;
s+=v;
size-=v;
}
}
return n+size;
}
}; // namespace scgi
bool scgi_connection::prepare()
{
char tmpbuf[16];
if(read(tmpbuf,15)!=15) {
return false;
}
tmpbuf[16]=0;
char *ptr;
if((ptr=strstr(tmpbuf,":"))==NULL) {
return false;
}
*ptr=0;
int len;
if(sscanf(tmpbuf,"%d".&len)!=1)
return false;
char *data_buffer=new char[len+2];
scoped_array<cachar> dealloc(data_buffer);
memset(data_buffer,0,len+1);
if(read(data_buffer,len+1)!=len+1 || data_buffer[len]!=',')
return false;
data_buffer[len]=0;
int n=0;
while(n<len) {
char *p1=data_buffer+n;
char *p2=data_buffer+strlen(p1)+1;
if(p2-data_buffer>=len || *p2=0) return false;
env[p1]=p2;
p2=p2+strlen(p2)+1;
n=p2-data_buffer;
}
return true;
}
size_t scgi_connection::read(char *s, size_t n)
{
int v;
size=n;
n=0;
while((v=::read(fd,s,size))!=size){
if(v<0) {
if(errno==EINTR)
continue;
return EOF;
}
else if(v==0) {
return n;
}
else {
n+=v;
s+=v;
size-=v;
}
}
return n+size;
}
scgi_connection::~scgi_connection()
{
shutdown(socket,SHUT_RDWR);
close(socket);
}
scgi::scgi(string socket,int backlog)
{
fd=-1;
size_t p;
if((p=socket.find(':'))!=string::npos) {
struct sockaddr_in a;
memset (&a, 0, sizeof (a));
a.sin_family = AF_INET;
a.sin_port = htons (atoi(socket.c_str()+p+1));
if(p!=0){
socket=socket.substr(0,p-1);
if(inet_aton(socket.c_str(),&a.sin_addr)<0) {
throw cppcms_error("Invalid IP" + socket);
}
}
fd=socket(AF_INET,SOCK_STREAM,0);
if(fd<0) {
throwerror("socket");
}
int yes=1;
if(setsockopt(fd,SOL_SOCKET, SO_REUSEADDR,(char *)&yes,sizeof(yes))<0) {
throwerror("reuse addr");
}
if(bind(fd,(struct sockaddr *) &a, sizeof (a)) < 0) {
throwerror("bind");
}
}
else {
struct sockaddr_un addr;
fd=socket(AF_UNIX, SOCK_STREAM, 0);
if(fd<0) throwerror("socket");
memset(&addr, 0, sizeof(struct sockaddr_un));
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, socket.c_str() ,sizeof(addr.sun_path) - 1);
if(bind(fd,(struct sockaddr *) &addr,sizeof(addr))<0) {
throwerror("bind");
}
}
listen(fd,backlog)
}
void scgi::throwerror(char const *s)
{
char buf[256];
strerror_r(errno,buf,sizeof(buf));
throw cppcms_error(string(s)+":"+buf);
}
scgi::~scgi()
{
if(fd!=-1)
close(fd);
}
int scgi::accept()
{
int socket=::accept(fd,NULL,NULL);
if(socket<0) {
return -1;
}
int yes=1;
if(setsockopt(socket,SOL_SOCKET,SO_LINGER,(char*)&yes,sizeof(yes))<0){
throwerror("setsockopt");
}
return socket;
}
}; // cppcms