source: git/Singular/ssiLink.cc @ 317d77f

spielwiese
Last change on this file since 317d77f was 19bece, checked in by Hans Schoenemann <hannes@…>, 13 years ago
extend ssiStatusSsiL to MP git-svn-id: file:///usr/local/Singular/svn/trunk@13891 2c84dea3-7e68-4137-9b89-c4e89433aadc
  • Property mode set to 100644
File size: 34.3 KB
Line 
1/****************************************
2 * Computer Algebra System SINGULAR     *
3 ****************************************/
4/***************************************************************
5 * File:    ssiLink.h
6 *  Purpose: declaration of sl_link routines for ssi
7 *  Version: $Id$
8 ***************************************************************/
9#include <stdio.h>
10#include <fcntl.h>
11#include <errno.h>
12#include <unistd.h>
13#include <sys/types.h>
14#include <signal.h>
15#include <sys/types.h>          /* for portability */
16#include <sys/select.h>
17#include <sys/socket.h>
18#include <netinet/in.h>
19#include <ctype.h>   /*for isdigit*/
20#include <netdb.h>
21
22
23#include <kernel/mod2.h>
24// #include "mod2.h"
25
26#include <Singular/tok.h>
27#include <Singular/ipid.h>
28#include <omalloc/omalloc.h>
29#include <kernel/ring.h>
30#include <kernel/matpol.h>
31#include <kernel/ideals.h>
32#include <kernel/polys.h>
33#include <kernel/longrat.h>
34#include <kernel/ideals.h>
35#include <kernel/intvec.h>
36#include <kernel/options.h>
37#include <Singular/subexpr.h>
38#include <Singular/silink.h>
39#include <Singular/lists.h>
40#include <Singular/ssiLink.h>
41
42#ifdef HAVE_MPSR
43#include <Singular/mpsr.h>
44#endif
45
46
47#define SSI_VERSION 1
48
49typedef struct
50{
51  FILE *f_read;
52  FILE *f_write;
53  ring r;
54  pid_t pid; /* only valid for fork/tcp mode*/
55  int fd_read,fd_write; /* only valid for fork/tcp mode*/
56  char level;
57  char ungetc_buf; /* status sets to !=0, if ungetc was used, ssiRead* set to 0*/
58
59} ssiInfo;
60
61
62typedef struct
63{
64  leftv u;
65  si_link l;
66  void * next;
67} link_struct;
68
69typedef link_struct* link_list;
70
71link_list ssiToBeClosed=NULL;
72
73// the helper functions:
74void ssiSetCurrRing(const ring r)
75{
76  if (!rEqual(r,currRing,1))
77  {
78    char name[20];
79    int nr=0;
80    do
81    { sprintf(name,"ssiRing%d",nr); nr++; }
82    while(IDROOT->get(name, 0)!=NULL);
83    idhdl h=enterid(omStrDup(name),0,RING_CMD,&IDROOT,FALSE);
84    IDRING(h)=r;
85    r->ref++;
86    rSetHdl(h);
87  }
88}
89// the implementation of the functions:
90void ssiWriteInt(ssiInfo *d,const int i)
91{
92  fprintf(d->f_write,"%d ",i);
93  //if (d->f_debug!=NULL) fprintf(d->f_debug,"int: %d ",i);
94}
95
96void ssiWriteString(ssiInfo *d,const char *s)
97{
98  fprintf(d->f_write,"%d %s ",strlen(s),s);
99  //if (d->f_debug!=NULL) fprintf(d->f_debug,"stringi: %d \"%s\" ",strlen(s),s);
100}
101
102
103void ssiWriteBigInt(const ssiInfo *d, const number n)
104{
105  // syntax is as follows:
106  // case 2 Q:     3 4 <int>
107  //        or     3 3 <mpz_t nominator>
108  if(SR_HDL(n) & SR_INT)
109  {
110    fprintf(d->f_write,"4 %ld ",SR_TO_INT(n));
111    //if (d->f_debug!=NULL) fprintf(d->f_debug,"bigint: short \"%ld\" ",SR_TO_INT(n));
112  }
113  else if (n->s==3)
114  {
115    fprintf(d->f_write,"3 ");
116    mpz_out_str(d->f_write,10,n->z);
117    fprintf(d->f_write," ");
118    //gmp_fprintf(d->f_write,"3 %Zd ",n->z);
119    //if (d->f_debug!=NULL) gmp_fprintf(d->f_debug,"bigint: gmp \"%Zd\" ",n->z);
120  }
121  else Werror("illiegal bigint");
122}
123
124void ssiWriteNumber(const ssiInfo *d, const number n)
125{
126  // syntax is as follows:
127  // case 1 Z/p:   3 <int>
128  // case 2 Q:     3 4 <int>
129  //        or     3 0 <mpz_t nominator> <mpz_t denominator>
130  //        or     3 1  dto.
131  //        or     3 3 <mpz_t nominator>
132  //        or     3 5 <mpz_t raw nom.> <mpz_t raw denom.>
133  //        or     3 6 <mpz_t raw nom.> <mpz_t raw denom.>
134  //        or     3 7 <mpz_t raw nom.>
135  if(rField_is_Zp(d->r))
136  {
137    fprintf(d->f_write,"%d ",(int)(long)n);
138    //if (d->f_debug!=NULL) fprintf(d->f_debug,"number: \"%ld\" ",(int)(long)n);
139  }
140  else if (rField_is_Q(d->r))
141  {
142    if(SR_HDL(n) & SR_INT)
143    {
144      fprintf(d->f_write,"4 %ld ",SR_TO_INT(n));
145      //if (d->f_debug!=NULL) fprintf(d->f_debug,"number: short \"%ld\" ",SR_TO_INT(n));
146    }
147    else if (n->s<2)
148    {
149      //gmp_fprintf(d->f_write,"%d %Zd %Zd ",n->s,n->z,n->n);
150      fprintf(d->f_write,"%d ",n->s+5);
151      mpz_out_str (d->f_write,32, n->z);
152      fprintf(d->f_write," ");
153      mpz_out_str (d->f_write,32, n->n);
154      fprintf(d->f_write," ");
155
156      //if (d->f_debug!=NULL) gmp_fprintf(d->f_debug,"number: s=%d gmp/gmp \"%Zd %Zd\" ",n->s,n->z,n->n);
157    }
158    else /*n->s==3*/
159    {
160      //gmp_fprintf(d->f_write,"3 %Zd ",n->z);
161      fprintf(d->f_write,"8 ");
162      mpz_out_str (d->f_write,32, n->z);
163      fprintf(d->f_write," ");
164
165      //if (d->f_debug!=NULL) gmp_fprintf(d->f_debug,"number: gmp \"%Zd\" ",n->z);
166    }
167  }
168  else WerrorS("coeff field not implemented");
169}
170
171void ssiWriteRing(ssiInfo *d,const ring r)
172{
173  /* 5 <ch> <N> <l1> <s1>....<ln> <sN> */
174  if (d->r!=NULL) rKill(d->r);
175  d->r=r;
176  d->r->ref++;
177  fprintf(d->f_write,"%d %d ",r->ch,r->N);
178
179  int i;
180  for(i=0;i<r->N;i++)
181  {
182    fprintf(d->f_write,"%d %s ",strlen(r->names[i]),r->names[i]);
183  }
184  /* number of orderings:*/
185  i=0;
186  while (r->order[i]!=0) i++;
187  fprintf(d->f_write,"%d ",i);
188  /* each ordering block: */
189  i=0;
190  while(r->order[i]!=0)
191  {
192    fprintf(d->f_write,"%d %d %d ",r->order[i],r->block0[i], r->block1[i]);
193    i++;
194  }
195}
196
197void ssiWritePoly(ssiInfo *d, int typ, poly p)
198{
199  fprintf(d->f_write,"%d ",pLength(p));//number of terms
200  int i;
201
202  while(p!=NULL)
203  {
204    ssiWriteNumber(d,pGetCoeff(p));
205    //nWrite(fich,pGetCoeff(p));
206    fprintf(d->f_write,"%ld ",p_GetComp(p,d->r));//component
207
208    for(int j=1;j<=rVar(d->r);j++)
209    {
210      fprintf(d->f_write,"%ld ",p_GetExp(p,j,d->r ));//x^j
211    }
212    pIter(p);
213  }
214}
215
216void ssiWriteIdeal(ssiInfo *d, int typ,ideal I)
217{
218   // syntax: 7 # of elements <poly 1> <poly2>.....
219   // syntax: 8 <rows> <cols> <poly 1> <poly2>.....
220   matrix M=(matrix)I;
221   if (typ==MATRIX_CMD)
222        fprintf(d->f_write,"%d %d ", MATROWS(M),MATCOLS(M));
223   else
224     fprintf(d->f_write,"%d ",IDELEMS(I));
225
226   int i;
227   int tt;
228   if (typ==MODUL_CMD) tt=VECTOR_CMD;
229   else                tt=POLY_CMD;
230
231   for(i=0;i<IDELEMS(I);i++)
232   {
233     ssiWritePoly(d,tt,I->m[i]);
234   }
235}
236void ssiWriteCommand(si_link l, command D)
237{
238  ssiInfo *d=(ssiInfo*)l->data;
239  // syntax: <num ops> <operation> <op1> <op2> ....
240  fprintf(d->f_write,"%d %d ",D->argc,D->op);
241  if (D->argc >0) ssiWrite(l, &(D->arg1));
242  if (D->argc < 4)
243  {
244    if (D->argc >1) ssiWrite(l, &(D->arg2));
245    if (D->argc >2) ssiWrite(l, &(D->arg3));
246  }
247}
248
249void ssiWriteProc(ssiInfo *d,procinfov p)
250{
251  ssiWriteString(d,p->data.s.body);
252}
253
254void ssiWriteList(si_link l,lists dd)
255{
256  ssiInfo *d=(ssiInfo*)l->data;
257  fprintf(d->f_write,"%d ",dd->nr+1);
258  int i;
259  for(i=0;i<=dd->nr;i++)
260  {
261    ssiWrite(l,&(dd->m[i]));
262  }
263}
264void ssiWriteIntvec(ssiInfo *d,intvec * v)
265{
266  fprintf(d->f_write,"%d ",v->length());
267  int i;
268  for(i=0;i<v->length();i++)
269  {
270    fprintf(d->f_write,"%d ",(*v)[i]);
271  }
272}
273
274char *ssiReadString(ssiInfo *d)
275{
276  char *buf;
277  int l;
278  fscanf(d->f_read,"%d ",&l);
279  buf=(char*)omAlloc(l+1);
280  fread(buf,1,l,d->f_read);
281  buf[l]='\0';
282  return buf;
283}
284
285int ssiReadInt(FILE *fich)
286{
287  int d;
288  fscanf(fich,"%d",&d);
289  return d;
290}
291
292number ssiReadBigInt(ssiInfo *d)
293{
294   int sub_type=-1;
295   fscanf(d->f_read,"%d",&sub_type);
296   switch(sub_type)
297   {
298   case 3:
299     {// read int or mpz_t or mpz_t, mpz_t
300       number n=nlRInit(0);
301       mpz_inp_str(n->z,d->f_read,0);
302       n->s=sub_type;
303       return n;
304     }
305   case 4: { int dd; fscanf(d->f_read,"%d",&dd); return INT_TO_SR(dd); }
306   default: Werror("error in reading number: invalid subtype %d",sub_type);
307            return NULL;
308   }
309}
310
311number ssiReadNumber(ssiInfo *d)
312{
313  if (rField_is_Q(d->r))
314  {
315     int sub_type=-1;
316     fscanf(d->f_read,"%d",&sub_type);
317     switch(sub_type)
318     {
319     case 0:
320     case 1:
321       {// read mpz_t, mpz_t
322        number n=nlRInit(0);
323        mpz_init(n->n);
324        gmp_fscanf(d->f_read,"%Zd %Zd",n->z,n->n);
325        n->s=sub_type;
326        return n;
327       }
328
329     case 3:
330       {// read mpz_t
331         number n=nlRInit(0);
332         gmp_fscanf(d->f_read,"%Zd",n->z);
333         n->s=3; /*sub_type*/
334         return n;
335       }
336     case 4: { int dd; fscanf(d->f_read,"%d",&dd); return INT_TO_SR(dd); }
337     case 5:
338     case 6:
339       {// read raw mpz_t, mpz_t
340        number n=nlRInit(0);
341        mpz_init(n->n);
342        mpz_inp_str (n->z, d->f_read, 32);
343        mpz_inp_str (n->n, d->f_read, 32);
344        n->s=sub_type-5;
345        return n;
346       }
347     case 8:
348       {// read raw mpz_t
349        number n=nlRInit(0);
350        mpz_inp_str (n->z, d->f_read, 32);
351        n->s=sub_type=3; /*subtype-5*/
352        return n;
353       }
354
355     default: Werror("error in reading number: invalid subtype %d",sub_type);
356              return NULL;
357     }
358  }
359  else if (rField_is_Zp(d->r))
360  {
361    // read int
362    int dd;
363    fscanf(d->f_read,"%d",&dd);
364    return (number)dd;
365  }
366  else Werror("coeffs not implemented");
367  return NULL;
368}
369
370ring ssiReadRing(ssiInfo *d)
371{
372/* syntax is <ch> <N> <l1> <s1> ....<lN> <sN> */
373  int ch, N,i,l;
374  char **names;
375  fscanf(d->f_read,"%d %d ",&ch,&N);
376  names=(char**)omAlloc(N*sizeof(char*));
377  for(i=0;i<N;i++)
378  {
379    names[i]=ssiReadString(d);
380  }
381  // read the orderings:
382  int num_ord; // number of orderings
383  fscanf(d->f_read,"%d",&num_ord);
384  int *ord=(int *)omAlloc0((num_ord+1)*sizeof(int));
385  int *block0=(int *)omAlloc0((num_ord+1)*sizeof(int));
386  int *block1=(int *)omAlloc0((num_ord+1)*sizeof(int));
387  for(i=0;i<num_ord;i++)
388  {
389     fscanf(d->f_read,"%d %d %d",&ord[i],&block0[i],&block1[i]);
390  }
391  return rDefault(ch,N,names,num_ord,ord,block0,block1);
392}
393
394poly ssiReadPoly(ssiInfo *D)
395{
396// < # of terms> < term1> < .....
397  int n,i,l;
398  n=ssiReadInt(D->f_read);
399  //Print("poly: terms:%d\n",n);
400  poly p;
401  int j;
402  j=0;
403  poly ret=NULL;
404  poly prev=NULL;
405  for(l=0;l<n;l++) // read n terms
406  {
407// coef,comp.exp1,..exp N
408    p=p_Init(D->r);
409    pGetCoeff(p)=ssiReadNumber(D);
410    int d;
411    fscanf(D->f_read,"%d",&d);
412    p_SetComp(p,d,D->r);
413    for(i=1;i<=rVar(D->r);i++)
414    {
415      fscanf(D->f_read,"%d",&d);
416      p_SetExp(p,i,d,D->r);
417    }
418    p_Setm(p,D->r);
419    p_Test(p,D->r);
420    if (ret==NULL) ret=p;
421    else           pNext(prev)=p;
422    prev=p;
423 }
424 return ret;
425}
426
427ideal ssiReadIdeal(ssiInfo *d)
428{
429  int n,i;
430  ideal I;
431  fscanf(d->f_read,"%d",&n);
432  I=idInit(n,1);
433  for(i=0;i<IDELEMS(I);i++) // read n terms
434  {
435    I->m [i]=ssiReadPoly(d);
436  }
437  return I;
438}
439
440matrix ssiReadMatrix(ssiInfo *d)
441{
442  int n,m,i,j;
443  fscanf(d->f_read,"%d %d",&m,&n);
444  matrix M=mpNew(m,n);
445  poly p;
446  for(int i=1;i<=MATROWS(M);i++)
447    for(int j=1;j<=MATCOLS(M);j++)
448    {
449      p=ssiReadPoly(d);
450      MATELEM(M,i,j)=p;
451    }
452  return M;
453}
454
455command ssiReadCommand(si_link l)
456{
457  ssiInfo *d=(ssiInfo*)l->data;
458  // syntax: <num ops> <operation> <op1> <op2> ....
459  command D=(command)omAlloc0(sizeof(*D));
460  int argc,op;
461  fscanf(d->f_read,"%d %d",&argc,&op);
462  D->argc=argc; D->op=op;
463  leftv v;
464  if (argc >0)
465  {
466    v=ssiRead1(l);
467    memcpy(&(D->arg1),v,sizeof(*v));
468    omFreeBin(v,sleftv_bin);
469  }
470  if (argc <4)
471  {
472    if (D->argc >1)
473    {
474      v=ssiRead1(l);
475      memcpy(&(D->arg2),v,sizeof(*v));
476      omFreeBin(v,sleftv_bin);
477    }
478    if (D->argc >2)
479    {
480      v=ssiRead1(l);
481      memcpy(&(D->arg3),v,sizeof(*v));
482      omFreeBin(v,sleftv_bin);
483    }
484  }
485  else
486  {
487    leftv prev=&(D->arg1);
488    argc--;
489    while(argc >0)
490    {
491      v=ssiRead1(l);
492      prev->next=v;
493      prev=v;
494      argc--;
495    }
496  }
497  return D;
498}
499
500procinfov ssiReadProc(ssiInfo *d)
501{
502  char *s=ssiReadString(d);
503  procinfov p=(procinfov)omAlloc0Bin(procinfo_bin);
504  p->language=LANG_SINGULAR;
505  p->libname=omStrDup("");
506  p->procname=omStrDup("");
507  p->data.s.body=s;
508  return p;
509}
510lists ssiReadList(si_link l)
511{
512  ssiInfo *d=(ssiInfo*)l->data;
513  int nr;
514  fscanf(d->f_read,"%d",&nr);
515  lists L=(lists)omAlloc(sizeof(*L));
516  L->Init(nr);
517
518  int i;
519  leftv v;
520  for(i=0;i<nr;i++)
521  {
522    v=ssiRead1(l);
523    memcpy(&(L->m[i]),v,sizeof(*v));
524    omFreeBin(v,sleftv_bin);
525  }
526  return L;
527}
528intvec* ssiReadIntvec(ssiInfo *d)
529{
530  int nr;
531  fscanf(d->f_read,"%d",&nr);
532  intvec *v=new intvec(nr);
533  for(int i=0;i<nr;i++)
534  {
535    fscanf(d->f_read,"%d",&((*v)[i]));
536  }
537  return v;
538}
539
540//**************************************************************************/
541BOOLEAN ssiOpen(si_link l, short flag, leftv u)
542{
543  const char *mode;
544  ssiInfo *d=(ssiInfo*)omAlloc0(sizeof(ssiInfo));
545  if (flag & SI_LINK_OPEN)
546  {
547    if (l->mode[0] != '\0' && (strcmp(l->mode, "r") == 0))
548      flag = SI_LINK_READ;
549    else flag = SI_LINK_WRITE;
550  }
551
552  if (flag == SI_LINK_READ) mode = "r";
553  else if (strcmp(l->mode, "w") == 0) mode = "w";
554  else if (strcmp(l->mode, "fork") == 0) mode = "fork";
555  else if (strcmp(l->mode, "tcp") == 0) mode = "tcp";
556  else if (strcmp(l->mode, "connect") == 0) mode = "connect";
557  else mode = "a";
558
559
560  SI_LINK_SET_OPEN_P(l, flag);
561  l->data=d;
562  omFree(l->mode);
563  l->mode = omStrDup(mode);
564
565  if (l->name[0] == '\0')
566  {
567    if (strcmp(mode,"fork")==0)
568    {
569      link_list n=(link_list)omAlloc(sizeof(link_struct));
570      n->u=u;
571      n->l=l;
572      n->next=(void *)ssiToBeClosed;
573      ssiToBeClosed=n;
574
575      int pc[2];
576      int cp[2];
577      pipe(pc);
578      pipe(cp);
579      pid_t pid=fork();
580      if (pid==0) /*child*/
581      {
582        link_list hh=(link_list)ssiToBeClosed->next;
583        /* we know: l is the first entry in ssiToBeClosed-list */
584        while(hh!=NULL)
585        {
586          ssiInfo *dd=(ssiInfo*)hh->l->data;
587          fclose(dd->f_read);
588          fclose(dd->f_write);
589          if (dd->r!=NULL) rKill(dd->r);
590          omFreeSize((ADDRESS)dd,(sizeof *dd));
591          hh->l->data=NULL;
592          SI_LINK_SET_CLOSE_P(hh->l);
593          link_list nn=(link_list)hh->next;
594          omFree(hh);
595          hh=nn;
596        }
597        ssiToBeClosed->next=NULL;
598        close(pc[1]); close(cp[0]);
599        d->f_read=fdopen(pc[0],"r");
600        d->fd_read=pc[0];
601        d->f_write=fdopen(cp[1],"w");
602        d->fd_write=cp[1];
603        l->data=d;
604        omFree(l->mode);
605        l->mode = omStrDup(mode);
606        SI_LINK_SET_RW_OPEN_P(l);
607        //myynest=0;
608        fe_fgets_stdin=fe_fgets_dummy;
609        if ((u!=NULL)&&(u->rtyp==IDHDL))
610        {
611          idhdl h=(idhdl)u->data;
612          h->lev=0;
613        }
614        loop
615        {
616          leftv h=ssiRead1(l); /*contains an exit.... */
617          if (feErrors != NULL && *feErrors != '\0')
618          {
619            // handle errors:
620            PrintS(feErrors); /* currently quite simple */
621            *feErrors = '\0';
622          }
623          ssiWrite(l,h);
624          h->CleanUp();
625          omFreeBin(h, sleftv_bin);
626        }
627        /* never reached*/
628      }
629      else if (pid>0)
630      {
631        d->pid=pid;
632        close(pc[0]); close(cp[1]);
633        d->f_read=fdopen(cp[0],"r");
634        d->fd_read=cp[0];
635        d->f_write=fdopen(pc[1],"w");
636        d->fd_write=pc[1];
637        SI_LINK_SET_RW_OPEN_P(l);
638      }
639      else
640      {
641        Werror("fork failed (%d)",errno);
642        l->data=NULL;
643        omFree(d);
644        return TRUE;
645      }
646    }
647    // ---------------------------------------------------------------------
648    else if (strcmp(mode,"tcp")==0)
649    {
650      int sockfd, newsockfd, portno, clilen;
651      struct sockaddr_in serv_addr, cli_addr;
652      int n;
653      sockfd = socket(AF_INET, SOCK_STREAM, 0);
654      if(sockfd < 0)
655      {
656        WerrorS("ERROR opening socket");
657        l->data=NULL;
658        omFree(d);
659        return TRUE;
660      }
661      memset((char *) &serv_addr,0, sizeof(serv_addr));
662      portno = 1024;
663      serv_addr.sin_family = AF_INET;
664      serv_addr.sin_addr.s_addr = INADDR_ANY;
665      do
666      {
667        portno++;
668        serv_addr.sin_port = htons(portno);
669        if(portno > 50000)
670        {
671          WerrorS("ERROR on binding (no free port available?)");
672          l->data=NULL;
673          omFree(d);
674          return TRUE;
675        }
676      }
677      while(bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0);
678      Print("waiting on port %d\n", portno);mflush();
679      listen(sockfd,5);
680      newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, (socklen_t *)&clilen);
681      if(newsockfd < 0)
682      {
683        WerrorS("ERROR on accept");
684        l->data=NULL;
685        omFree(d);
686        return TRUE;
687      }
688      PrintS("client accepted\n");
689      d->fd_read = newsockfd;
690      d->fd_write = newsockfd;
691      d->f_read = fdopen(newsockfd, "r");
692      d->f_write = fdopen(newsockfd, "w");
693      SI_LINK_SET_RW_OPEN_P(l);
694      close(sockfd);
695    }
696    // no ssi-Link on stdin or stdout
697    else
698    {
699      Werror("invalid mode >>%s<< for ssi",mode);
700      l->data=NULL;
701      omFree(d);
702      return TRUE;
703    }
704  }
705  // =========================================================================
706  else /*l->name=NULL*/
707  {
708    // tcp mode
709    if(strcmp(mode,"tcp")==0)
710    {
711      int sockfd, newsockfd, portno, clilen;
712      struct sockaddr_in serv_addr, cli_addr;
713      int n;
714      sockfd = socket(AF_INET, SOCK_STREAM, 0);
715      if(sockfd < 0)
716      {
717        WerrorS("ERROR opening socket");
718        l->data=NULL;
719        omFree(d);
720        return TRUE;
721      }
722      memset((char *) &serv_addr,0, sizeof(serv_addr));
723      portno = 1024;
724      serv_addr.sin_family = AF_INET;
725      serv_addr.sin_addr.s_addr = INADDR_ANY;
726      do
727      {
728        portno++;
729        serv_addr.sin_port = htons(portno);
730        if(portno > 50000)
731        {
732          WerrorS("ERROR on binding (no free port available?)");
733          l->data=NULL;
734          return TRUE;
735        }
736      }
737      while(bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0);
738      //Print("waiting on port %d\n", portno);mflush();
739      listen(sockfd,5);
740      char* cli_host = (char*)omAlloc(256);
741      char* path = (char*)omAlloc(1024);
742      int r = sscanf(l->name,"%255[^:]:%s",cli_host,path);
743      if(r == 0)
744      {
745        WerrorS("ERROR: no host specified");
746        l->data=NULL;
747        omFree(d);
748        omFree(path);
749        omFree(cli_host);
750        return TRUE;
751      }
752      else if(r == 1)
753      {
754        WarnS("program not specified, using /usr/local/bin/Singular");
755        strcpy(path,"/usr/local/bin/Singular");
756      }
757      char* ssh_command = (char*)omAlloc(256);
758      char* ser_host = (char*)omAlloc(64);
759      gethostname(ser_host,64);
760      sprintf(ssh_command,"ssh %s %s -q --batch --link=ssi --MPhost=%s --MPport=%d &",cli_host,path,ser_host,portno);
761      //Print("client on %s started:%s\n",cli_host,path);
762      omFree(path);
763      omFree(cli_host);
764      if (TEST_OPT_PROT) { Print("running >>%s<<\n",ssh_command); }
765      system(ssh_command);
766      omFree(ssh_command);
767      omFree(ser_host);
768      clilen = sizeof(cli_addr);
769      newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, (socklen_t *)&clilen);
770      if(newsockfd < 0)
771      {
772        WerrorS("ERROR on accept");
773        l->data=NULL;
774        omFree(d);
775        return TRUE;
776      }
777      //PrintS("client accepted\n");
778      d->fd_read = newsockfd;
779      d->fd_write = newsockfd;
780      d->f_read = fdopen(newsockfd, "r");
781      d->f_write = fdopen(newsockfd, "w");
782      SI_LINK_SET_RW_OPEN_P(l);
783      close(sockfd);
784      fprintf(d->f_write,"98 %d %d %u %u\n",SSI_VERSION,MAX_TOK,test,verbose);
785    }
786    // ----------------------------------------------------------------------
787    else if(strcmp(mode,"connect")==0)
788    {
789      char* host = (char*)omAlloc(256);
790      int sockfd, portno, n;
791      struct sockaddr_in serv_addr;
792      struct hostent *server;
793
794      sscanf(l->name,"%255[^:]:%d",host,&portno);
795      //Print("connect to host %s, port %d\n",host,portno);mflush();
796      if (portno!=0)
797      {
798        sockfd = socket(AF_INET, SOCK_STREAM, 0);
799        if (sockfd < 0) { WerrorS("ERROR opening socket"); return TRUE; }
800        server = gethostbyname(host);
801        if (server == NULL) {  WerrorS("ERROR, no such host");  return TRUE; }
802        memset((char *) &serv_addr, 0, sizeof(serv_addr));
803        serv_addr.sin_family = AF_INET;
804        memcpy((char *)&serv_addr.sin_addr.s_addr,
805              (char *)server->h_addr,
806              server->h_length);
807        serv_addr.sin_port = htons(portno);
808        if (connect(sockfd,(sockaddr*)&serv_addr,sizeof(serv_addr)) < 0)
809        { WerrorS("ERROR connecting"); return TRUE; }
810        //PrintS("connected\n");mflush();
811        d->f_read=fdopen(sockfd,"r");
812        d->fd_read=sockfd;
813        d->f_write=fdopen(sockfd,"w");
814        d->fd_write=sockfd;
815        SI_LINK_SET_RW_OPEN_P(l);
816        omFree(host);
817      }
818      else
819      {
820        l->data=NULL;
821        omFree(d);
822        return TRUE;
823      }
824    }
825    // ======================================================================
826    else
827    {
828      // normal link to a file
829      FILE *outfile;
830      char *filename=l->name;
831
832      if(filename[0]=='>')
833      {
834        if (filename[1]=='>')
835        {
836          filename+=2;
837          mode = "a";
838        }
839        else
840        {
841          filename++;
842          mode="w";
843        }
844      }
845      outfile=myfopen(filename,mode);
846      if (outfile!=NULL)
847      {
848        if (strcmp(l->mode,"r")==0) d->f_read = outfile;
849        else
850        {
851          d->f_write = outfile;
852          fprintf(d->f_write,"98 %d %d %u %u\n",SSI_VERSION,MAX_TOK,test,verbose);
853        }
854      }
855      else
856      {
857        omFree(d);
858        l->data=NULL;
859        return TRUE;
860      }
861    }
862  }
863
864  return FALSE;
865}
866
867//**************************************************************************/
868LINKAGE BOOLEAN ssiClose(si_link l)
869{
870  ssiInfo *d = (ssiInfo *)l->data;
871  if (d!=NULL)
872  {
873    if ((strcmp(l->mode,"tcp")==0)
874    || (strcmp(l->mode,"fork")==0))
875    {
876      fprintf(d->f_write,"99\n");fflush(d->f_write);
877      link_list hh=ssiToBeClosed;
878      if (hh!=NULL)
879      {
880        if (hh->l==l)
881        {
882           ssiToBeClosed=(link_list)hh->next;
883           omFreeSize(hh,sizeof(link_struct));
884        }
885        else while(hh!=NULL)
886        {
887          link_list hhh=(link_list)hh->next;
888          if (hhh->l==l)
889          {
890            hh->next=hhh->next;
891            omFreeSize(hhh,sizeof(link_struct));
892            break;
893          }
894          hh=(link_list)hh->next;
895        }
896      }
897    }
898    if (d->f_read!=NULL) fclose(d->f_read);
899    if (d->f_write!=NULL) fclose(d->f_write);
900    if (d->r!=NULL) rKill(d->r);
901    if (d->pid!=0) { kill(d->pid,15); kill(d->pid,9); }
902    omFreeSize((ADDRESS)d,(sizeof *d));
903  }
904  l->data=NULL;
905  SI_LINK_SET_CLOSE_P(l);
906  return FALSE;
907}
908
909//**************************************************************************/
910LINKAGE leftv ssiRead1(si_link l)
911{
912  ssiInfo *d = (ssiInfo *)l->data;
913  d->ungetc_buf='\0';
914  leftv res=(leftv)omAlloc0(sizeof(sleftv));
915  int t=0;
916  fscanf(d->f_read,"%d",&t);
917  //Print("got type %d\n",t);
918  switch(t)
919  {
920    case 1:res->rtyp=INT_CMD;
921           res->data=(char *)ssiReadInt(d->f_read);
922           break;
923    case 2:res->rtyp=STRING_CMD;
924           res->data=(char *)ssiReadString(d);
925           break;
926    case 3:res->rtyp=NUMBER_CMD;
927           res->data=(char *)ssiReadNumber(d);
928           break;
929    case 4:res->rtyp=BIGINT_CMD;
930           res->data=(char *)ssiReadBigInt(d);
931           break;
932    case 15:
933    case 5:{
934             d->r=ssiReadRing(d);
935             d->r->ref++;
936             res->rtyp=RING_CMD;
937             res->data=(char*)d->r;
938             // we are in the top-level, so set the basering to d->r:
939             ssiSetCurrRing(d->r);
940             if (t==15) return ssiRead1(l);
941           }
942           break;
943    case 6:res->rtyp=POLY_CMD;
944           if (d->r==NULL) goto no_ring;
945           res->data=(char*)ssiReadPoly(d);
946           break;
947    case 7:res->rtyp=IDEAL_CMD;
948           if (d->r==NULL) goto no_ring;
949           res->data=(char*)ssiReadIdeal(d);
950           break;
951    case 8:res->rtyp=MATRIX_CMD;
952           if (d->r==NULL) goto no_ring;
953           res->data=(char*)ssiReadMatrix(d);
954           break;
955    case 9:res->rtyp=VECTOR_CMD;
956           if (d->r==NULL) goto no_ring;
957           res->data=(char*)ssiReadPoly(d);
958           break;
959    case 10:res->rtyp=MODUL_CMD;
960           if (d->r==NULL) goto no_ring;
961           res->data=(char*)ssiReadIdeal(d);
962           break;
963    case 11:
964           {
965             res->rtyp=COMMAND;
966             res->data=ssiReadCommand(l);
967             int nok=res->Eval();
968             if (nok) WerrorS("error in eval");
969             break;
970           }
971    case 12: /*DEF_CMD*/
972           {
973             res->rtyp=0;
974             res->name=(char *)ssiReadString(d);
975             int nok=res->Eval();
976             if (nok) WerrorS("error in name lookup");
977             break;
978           }
979    case 13: res->rtyp=PROC_CMD;
980             res->data=ssiReadProc(d);
981             break;
982    case 14: res->rtyp=LIST_CMD;
983             res->data=ssiReadList(l);
984             break;
985    case 16: res->rtyp=NONE; res->data=NULL;
986             break;
987    case 17: res->rtyp=INTVEC_CMD;
988             res->data=ssiReadIntvec(d);
989             break;
990    // ------------
991    case 98: // version
992             {
993                int n98_v,n98_m;
994                BITSET n98_o1,n98_o2;
995                fscanf(d->f_read,"%d %d %u %u\n",&n98_v,&n98_m,&n98_o1,&n98_o2);
996                if ((n98_v!=SSI_VERSION) ||(n98_m!=MAX_TOK))
997                {
998                  Print("incompatible versions of ssi: %d/%d vs %d/%d",
999                                  SSI_VERSION,MAX_TOK,n98_v,n98_m);
1000                }
1001                #ifndef NDEBUG
1002                if (TEST_OPT_DEBUG)
1003                  Print("// opening ssi-%d, MAX_TOK=%d\n",n98_v,n98_m);
1004                #endif
1005                test=n98_o1;
1006                verbose=n98_o2;
1007                return ssiRead1(l);
1008             }
1009    case 99: ssiClose(l); exit(0);
1010    case 0: if (feof(d->f_read))
1011            {
1012              ssiClose(l);
1013              res->rtyp=DEF_CMD;
1014              break;
1015            }
1016    default: Werror("not implemented (t:%d)",t);
1017             omFreeSize(res,sizeof(sleftv));
1018             res=NULL;
1019             break;
1020  }
1021  return res;
1022no_ring: WerrorS("no ring");
1023  return NULL;
1024}
1025//**************************************************************************/
1026LINKAGE BOOLEAN ssiWrite(si_link l, leftv data)
1027{
1028  if(SI_LINK_W_OPEN_P(l)==0) slOpen(l,SI_LINK_OPEN|SI_LINK_WRITE,NULL);
1029  ssiInfo *d = (ssiInfo *)l->data;
1030  d->level++;
1031  //FILE *fich=d->f;
1032  while (data!=NULL)
1033  {
1034    int tt=data->Typ();
1035    void *dd=data->Data();
1036
1037    switch(tt /*data->Typ()*/)
1038    {
1039          case NONE/* nothing*/:fprintf(d->f_write,"16 ");
1040                          break;
1041          case STRING_CMD: fprintf(d->f_write,"2 ");
1042                           ssiWriteString(d,(char *)dd);
1043                           break;
1044          case INT_CMD: fprintf(d->f_write,"1 ");
1045                        ssiWriteInt(d,(int)(long)dd);
1046                        break;
1047          case BIGINT_CMD:fprintf(d->f_write,"4 ");
1048                        ssiWriteBigInt(d,(number)dd);
1049                        break;
1050          case NUMBER_CMD:
1051                          if (d->r!=currRing)
1052                          {
1053                            fprintf(d->f_write,"15 ");
1054                            ssiWriteRing(d,currRing);
1055                            if (d->level<=1) fprintf(d->f_write,"\n");
1056                          }
1057                          fprintf(d->f_write,"3 ");
1058                          ssiWriteNumber(d,(number)dd);
1059                        break;
1060          case RING_CMD:fprintf(d->f_write,"5 ");
1061                        ssiWriteRing(d,(ring)dd);
1062                        break;
1063          case POLY_CMD:
1064          case VECTOR_CMD:
1065                        if (d->r!=currRing)
1066                        {
1067                          fprintf(d->f_write,"15 ");
1068                          ssiWriteRing(d,currRing);
1069                          if (d->level<=1) fprintf(d->f_write,"\n");
1070                        }
1071                        if(tt==POLY_CMD) fprintf(d->f_write,"6 ");
1072                        else             fprintf(d->f_write,"9 ");
1073                        ssiWritePoly(d,tt,(poly)dd);
1074                        break;
1075          case IDEAL_CMD:
1076          case MODUL_CMD:
1077          case MATRIX_CMD:
1078                        if (d->r!=currRing)
1079                        {
1080                          fprintf(d->f_write,"15 ");
1081                          ssiWriteRing(d,currRing);
1082                          if (d->level<=1) fprintf(d->f_write,"\n");
1083                        }
1084                        if(tt==IDEAL_CMD)       fprintf(d->f_write,"7 ");
1085                        else if(tt==MATRIX_CMD) fprintf(d->f_write,"8 ");
1086                        else                    fprintf(d->f_write,"10 ");
1087                        ssiWriteIdeal(d,tt,(ideal)dd);
1088                        break;
1089          case COMMAND:
1090                   fprintf(d->f_write,"11 ");
1091                   ssiWriteCommand(l,(command)dd);
1092                   break;
1093          case DEF_CMD: /* not evaluated stuff in quotes */
1094                   fprintf(d->f_write,"12 ");
1095                   ssiWriteString(d,data->Name());
1096                   break;
1097          case PROC_CMD:
1098                   fprintf(d->f_write,"13 ");
1099                   ssiWriteProc(d,(procinfov)dd);
1100                   break;
1101          case LIST_CMD:
1102                   fprintf(d->f_write,"14 ");
1103                   ssiWriteList(l,(lists)dd);
1104                   break;
1105          case INTVEC_CMD:
1106                   fprintf(d->f_write,"17 ");
1107                   ssiWriteIntvec(d,(intvec *)dd);
1108                   break;
1109          default: Werror("not implemented (t:%d, rtyp:%d)",tt, data->rtyp);
1110                   d->level=0;
1111                   return TRUE;
1112    }
1113    if (d->level<=1) { fprintf(d->f_write,"\n"); fflush(d->f_write); }
1114    data=data->next;
1115  }
1116  d->level--;
1117  return FALSE;
1118}
1119
1120si_link_extension slInitSsiExtension(si_link_extension s)
1121{
1122  s->Open=ssiOpen;
1123  s->Close=ssiClose;
1124  s->Kill=ssiClose;
1125  s->Read=ssiRead1;
1126  s->Read2=(slRead2Proc)NULL;
1127  s->Write=ssiWrite;
1128
1129  s->Status=slStatusSsi;
1130  s->type="ssi";
1131  return s;
1132}
1133
1134const char* slStatusSsi(si_link l, const char* request)
1135{
1136  ssiInfo *d=(ssiInfo*)l->data;
1137  if (d==NULL) return "not open";
1138  if (((strcmp(l->mode,"fork")==0)||(strcmp(l->mode,"tcp")==0))
1139  && (strcmp(request, "read") == 0))
1140  {
1141    fd_set  mask, fdmask;
1142    struct timeval wt;
1143    if (d->ungetc_buf) return "ready";
1144    loop
1145    {
1146      /* Don't block. Return socket status immediately. */
1147      wt.tv_sec  = 0;
1148      wt.tv_usec = 0;
1149
1150      FD_ZERO(&mask);
1151      FD_SET(d->fd_read, &mask);
1152      //Print("test fd %d\n",d->fd_read);
1153    /* check with select: chars waiting: no -> not ready */
1154      switch (select(d->fd_read+1, &mask, NULL, NULL, &wt))
1155      {
1156        case 0: /* not ready */ return "not ready";
1157        case -1: /*error*/      return "error";
1158        case 1: /*ready ? */    break;
1159      }
1160    /* yes: read 1 char*/
1161    /* if \n, check again with select else ungetc(c), ready*/
1162      int c=fgetc(d->f_read);
1163      //Print("try c=%d\n",c);
1164      if (c== -1) return "eof";
1165      else if (isdigit(c))
1166      { ungetc(c,d->f_read); d->ungetc_buf='\1'; return "ready"; }
1167      else if (c>' ')
1168      {
1169        Werror("unknown char in ssiLink(%d)",c);
1170        return "error";
1171      }
1172      /* else: next char */
1173    }
1174  }
1175  else if (strcmp(request, "read") == 0)
1176  {
1177    if (SI_LINK_R_OPEN_P(l) && (!feof(d->f_read))) return "ready";
1178    else return "not ready";
1179  }
1180  else if (strcmp(request, "write") == 0)
1181  {
1182    if (SI_LINK_W_OPEN_P(l)) return "ready";
1183    else return "not ready";
1184  }
1185  else return "unknown status request";
1186}
1187
1188int slStatusSsiL(lists L, int timeout)
1189{
1190  si_link l;
1191  ssiInfo *d;
1192  #ifdef HAVE_MPSR
1193  MP_Link_pt dd;
1194  #endif
1195  int d_fd;
1196  fd_set  mask, fdmask;
1197  FD_ZERO(&mask);
1198  int max_fd=0; /* max fd in fd_set */
1199  struct timeval wt;
1200  int i;
1201  for(i=L->nr; i>=0; i--)
1202  {
1203    if (L->m[i].Typ()!=LINK_CMD)
1204    { WerrorS("all elements must be of type link"); return -2;}
1205    l=(si_link)L->m[i].Data();
1206    if(SI_LINK_OPEN_P(l)==0)
1207    { WerrorS("all links must be open"); return -2;}
1208    if (((strcmp(l->m->type,"ssi")!=0) && (strcmp(l->m->type,"MPtcp")!=0))
1209    || ((strcmp(l->mode,"fork")!=0) && (strcmp(l->mode,"tcp")!=0)))
1210    { WerrorS("all links must be of type ssi:fork or ssi:tcp or MPtcp:fork"); return -2;}
1211    #ifdef HAVE_MPSR
1212    if (strcmp(l->m->type,"ssi")==0)
1213    {
1214      d=(ssiInfo*)l->data;
1215      d_fd=d->fd_read;
1216    }
1217    else
1218    {
1219      dd=(MP_Link_pt)l->data;
1220      d_fd=((MP_TCP_t *)dd->transp.private1)->sock;
1221    }
1222    #else
1223    d=(ssiInfo*)l->data;
1224    d_fd=d->fd_read;
1225    #endif
1226    FD_SET(d_fd, &mask);
1227    if (d_fd > max_fd) max_fd=d_fd;
1228  }
1229  max_fd++;
1230  struct timeval *wt_ptr=&wt;
1231  if (timeout== -1)
1232  {
1233    wt_ptr=NULL;
1234  }
1235  else
1236  {
1237    wt.tv_sec  = timeout / 1000000;
1238    wt.tv_usec = timeout % 1000000;
1239  }
1240  /* check with select: chars waiting: no -> not ready */
1241  int s= select(max_fd, &mask, NULL, NULL, wt_ptr);
1242  if (s==-1) return -2; /*error*/
1243  if (s==0)
1244  {
1245    return -1; /*poll: not ready */
1246  }
1247  else /* s>0, at least one ready */
1248  {
1249    int j=0;
1250    while (j<=max_fd) { if (FD_ISSET(j,&mask)) break; j++; }
1251    for(i=L->nr; i>=0; i--)
1252    {
1253      l=(si_link)L->m[i].Data();
1254      #ifdef HAVE_MPSR
1255      if (strcmp(l->m->type,"ssi")!=0)
1256      {
1257        // for MP links, return here:
1258        dd=(MP_Link_pt)l->data;
1259        d_fd=((MP_TCP_t *)dd->transp.private1)->sock;
1260        if(j==d_fd) return i+1;
1261      }
1262      else
1263      {
1264        d=(ssiInfo*)l->data;
1265        d_fd=d->fd_read;
1266        if(j==d_fd) break;
1267      }
1268      #else
1269      d=(ssiInfo*)l->data;
1270      d_fd=d->fd_read;
1271      if(j==d_fd) break;
1272      #endif
1273    }
1274    // only ssi links:
1275    if (d->ungetc_buf) return i+1;
1276    loop
1277    {
1278      /* yes: read 1 char*/
1279      /* if \n, check again with select else ungetc(c), ready*/
1280      /* setting: d: current ssiInfo, j current fd, i current entry in L*/
1281      int c=fgetc(d->f_read);
1282      //Print("try c=%d\n",c);
1283      if (c== -1) return 0;
1284      else if (isdigit(c))
1285      { ungetc(c,d->f_read); d->ungetc_buf='\1'; return i+1; }
1286      else if (c>' ')
1287      {
1288        Werror("unknown char in ssiLink(%d)",c);
1289        return -2;
1290      }
1291      /* else: next char */
1292    }
1293  }
1294}
1295
1296int ssiBatch(const char *host, const char * port)
1297/* return 0 on success, >0 else*/
1298{
1299  si_link l=(si_link) omAlloc0Bin(sip_link_bin);
1300  char *buf=(char*)omAlloc(256);
1301  sprintf(buf,"ssi:connect %s:%s",host,port);
1302  slInit(l, buf);
1303  slOpen(l,SI_LINK_OPEN,NULL);
1304  SI_LINK_SET_RW_OPEN_P(l);
1305
1306  idhdl id = enterid(omStrDup("link_ll"), 0, LINK_CMD, &IDROOT, FALSE);
1307  IDLINK(id) = l;
1308
1309  loop
1310  {
1311    leftv h=ssiRead1(l); /*contains an exit.... */
1312    if (feErrors != NULL && *feErrors != '\0')
1313    {
1314      // handle errors:
1315      PrintS(feErrors); /* currently quite simple */
1316      *feErrors = '\0';
1317    }
1318    ssiWrite(l,h);
1319    h->CleanUp();
1320    omFreeBin(h, sleftv_bin);
1321  }
1322  /* never reached*/
1323  exit(0);
1324}
1325
1326// ----------------------------------------------------------------
1327// format
1328// 1 int %d
1329// 2 string <len> %s
1330// 3 number
1331// 4 bigint 4 %d or 3 <mpz_t>
1332// 5 ring
1333// 6 poly
1334// 7 ideal
1335// 8 matrix
1336// 9 vector
1337// 10 module
1338// 11 command
1339// 12 def <len> %s
1340// 13 proc <len> %s
1341// 14 list %d <elem1> ....
1342// 15 setring .......
1343// 16 nothing
1344// 17 intvec <len> ...
1345//
1346// 98: verify version: <ssi-version> <MAX_TOK> <OPT1> <OPT2>
1347// 99: quit Singular
Note: See TracBrowser for help on using the repository browser.