[JDEV] Jabber DevZone News - flea

Jabber DevZone webmaster at jabber.org
Mon Mar 5 05:17:33 CST 2001


flea

Below you'll find the source for a mostly functional jabber server, in
less than 4k of C.
You should be able to cut and paste it into a file, then compile and
run it, and connect to it with any client and be able to see any other
clients connected.
It supports authentication, rosters, presence, and messaging between
clients, but that's it.  
I wrote it mostly to prove to myself that it could be done, but also
as a toy that was fun to create and play with.
It's also in CVS as 'flea', but I'm not planning any major updates to
it (next time I get ambitious I might be able to add server-server and
keep it less than 5k).
Enjoy!

#include <resolv.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <errno.h>
#include <string.h>
#define U 100
#define B 8192
#define N "flea"

typedef struct itch_s{char buf[B],p[256],u[24],r[128]; int fd;} *itch;
itch i,I[U];

#define WR(x,y) write(x->fd,y->r,strlen(y->r));
write(x->fd,y->p,strlen(y->p))
itch scratch(char *s, int l){ int f;
 for(f=0; f<U; f++){
  if(I[f] == NULL || I[f]->u[0] == '\0') continue;
  if(s == NULL){ if(I[f]->p[0] != '\0'){ WR(I[f],i); if(I[i->fd]
!= NULL){ WR(i,I[f]); }} continue; }
  if(*s == '<') write(f,s,l); else if(strncmp(s,I[f]->u,l) == 0)
return I[f];}
 return NULL;}

#define NEXT(s) memmove(i->buf,s,strlen(s)+1); continue
#define CHR(s,c) (s = strchr(i->buf,c)) != NULL && s++
#define IQ(t) if((ad = strstr(sp,"id=")) != NULL && (sp =
strstr(ad,"xmlns=")) != NULL){ ad+=3; sp+=6; sprintf(n,"<iq
type='%s' id=%.*s><query
xmlns=%.*s/></iq>",t,strchr(ad+1,*ad)-ad+1,ad,strchr(sp+1,*sp)-sp+1,sp);
}else sprintf(n,"<iq type='%s'/>",t);
write(i->fd,n,strlen(n)); NEXT(end)
parse(){ char *lt, *gt, *sp, *ad, *end, n[64]; itch i2;
 while(CHR(lt,'<') && CHR(gt,'>')){ if((sp = strchr(lt,'
')) == NULL || sp > gt) sp = gt - 1;
  if(gt[-2] == '?'){ NEXT(gt); } /* <?xml ?> PI */
  if(*lt == 's'){ write(i->fd,"<stream:stream
xmlns='jabber:client' from='" N "'>",49); NEXT(gt); } /*
<stream:stream> header */
  if(gt[-2] == '/'){ if(sp == (gt - 1)) sp -= 1; end = gt; } /* empty
tag detector */
  else{ sprintf(n,"</%.*s>",sp - lt, lt); if((end =
strstr(gt,n)) == NULL) return; end += strlen(n);} /* end tag detector
*/
  if(i->u[0] == '\0'){ if(*lt != 'i'){ NEXT(end); } /* no user yet,
get <username> from iq */
   if((lt = strstr(gt,"<username>")) == NULL || (ad =
strstr(sp,"set")) == NULL || ad > gt){ IQ("error"); }
   gt = lt + 10; lt = strchr(gt,'<'); if(scratch(gt,lt-gt) != NULL)
{ IQ("error"); } /* existing user */
   memcpy(i->u,gt,lt-gt); IQ("result"); }
  if((ad = strstr(sp,"from=")) == NULL || ad > gt){ /* insert a
from='' if none and reset */
   sprintf(n," from='%s@" N "'",i->u); memmove(sp + strlen(n), sp,
strlen(sp)+1); memcpy(sp,n,strlen(n)); continue; }
  if((ad = strstr(sp,"to=")) != NULL && ad < gt &&
strchr(ad,'@') != NULL){ /* send direct if a to='user at foo' */
   ad+=4; if((i2 = scratch(ad,strchr(ad,'@')-ad)) != NULL)
write(i2->fd,--lt, end - lt + 1); NEXT(end); }
  if(*lt == 'i'){ IQ("result"); }
  if(*lt != 'p'){ NEXT(end); } /* handle presence */
  if(i->p[0] == '\0'){ sprintf(i->r,"<iq
type='set'><query xmlns='jabber:iq:roster'><item jid='%s@"
N "' subscription='both'/></query></iq>",i->u);
scratch(NULL,0);}
  --lt;sprintf(i->p,"%.*s",end-lt,lt);
scratch(i->p,strlen(i->p)); NEXT(end);
 }}

main(int argc, char **argv){ fd_set fdr,fda; struct sockaddr_in sa;
int max=0,l,x,f,sz=1,sai=sizeof(sa); char *buf;
 memset(&sa,0,sai); sa.sin_family = AF_INET; sa.sin_port =
htons(5222);
 if((l = socket(AF_INET,SOCK_STREAM,0)) < 0 ||
setsockopt(l,SOL_SOCKET,SO_REUSEADDR,&sz,sizeof(sz)) < 0 ||
bind(l,&sa,sai) < 0 || listen(l,10) < 0){
  printf("unable to listen: %s\n",strerror(errno)); exit(1);}
 FD_ZERO(&fdr); FD_ZERO(&fda); max = l; FD_SET(l,&fda);
memset(I,0,sizeof(I));
 while((fdr = fda),select(max+1, &fdr, NULL, NULL, NULL) > 0){
for(x = 0; x <= max; x++){ if(!FD_ISSET(x,&fdr)) continue;
  if(x == l){ f = accept(l,&sa,&sai); if(f > max) max = f;
FD_SET(f,&fda); I[f] = (itch)malloc(sizeof(struct itch_s));
memset(I[f],0,sizeof(struct itch_s)); I[f]->fd = f; continue; }
  i = I[x]; sz = strlen(i->buf); buf = i->buf + sz;
  if((sz = read(x,buf,B - sz - 100)) <= 0){ FD_CLR(x,&fda);
I[x] = NULL; 
   if(i->p[0] != '\0'){ sprintf(i->p + 9," from='%s@" N "'
type='unavailable'/>",i->u); sprintf(i->r +
(strlen(i->r)-20),"remove'/></query></iq>");
scratch(NULL,0); }
   free(i); close(x); continue; }
  buf[sz] = '\0'; parse();
 }}}





More information about the JDev mailing list