source: PlatformSupport/matperf/client/pnet.c

Last change on this file was 951, checked in by chunter, 16 years ago

adding matperf

  • Property svn:executable set to *
File size: 45.4 KB
Line 
1/**********************************************************
2                             
3  MEX file for the tcpip toolbox.
4                                                          */
5#define VERSION "Version  2.0.5  2003-09-16"
6
7/*
8%   This file(s) is part of the tcp_udp_ip toolbox (C) Peter Rydes�ter et al.
9%   et al.  1998-2003 for running in MATLAB(R) as scripts and/or plug-ins.
10%
11%   This program is free software; you can redistribute it and/or modify
12%   it under the terms of the GNU General Public License as published by
13%   the Free Software Foundation; either version 2 of the License, or
14%   (at your option) any later version.
15%
16%   This program is distributed in the hope that it will be useful,
17%   but WITHOUT ANY WARRANTY; without even the implied warranty of
18%   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19%   GNU General Public License for more details.
20%
21%   You should have received a copy of the GNU General Public License
22%   along with this program; if not, write to the Free Software
23%   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24%
25%   In addition, as a SPECIAL EXCEPTION, Peter Rydes�ter, SWEDEN,
26%   gives permission to link the code of this program with any library,
27%   and distribute linked combinations of it. You must obey the GNU
28%   General Public License in all respects for all of the code in the
29%   tcp_udp_ip toolbox and any . If you modify any source file included,
30%   you may extend this exception to your version of the file, but you are
31%   not obligated to do so.  If you do not wish to do so, delete this exception
32%   statement from your version. This exception makes it possible to use
33%   pnet.c (.dll) as a plug-in as it is intended and let it be (dynamical)
34%   linked to MATLAB(R) or any compiled stand alone application.
35
36   
37  Notes for Unix implementation
38  Compile this with:
39 
40  mex -O pnet.c
41 
42  Notes for Windows implementation
43 
44  When using LCC, compile this with:
45  mex -O pnet.c {MATLAB_INSTALL_DIR}\sys\lcc\lib\wsock32.lib -DWIN32
46
47  When using Visual C++, compile this with:
48  mex -O pnet.c ws2_32.lib -DWIN32
49 
50 
51  == Main Authour ==           == Windows support ==      == Earlie/Basic UDP support ==
52  Peter Rydes�ter              Mario Bergeron             Mike Medeiros at 23-Jan-2001.
53                               LYRtech
54  �stersund, Sweden            Qu�bec, Canada
55  +46 70 560 68 16             
56  Peter.Rydesater@mh.se        Mario.Bergeron@lyrtech.com
57
58
59  SE MORE:  http://www.rydesater.com
60 
61  **********************************************************/
62   
63/******* GENERAL DEFINES *********/
64#include <stdio.h>
65#include <stdlib.h>
66#include <string.h>
67#include <math.h>
68#include <ctype.h>
69
70/******* WINDOWS ONLY DEFINES *********/
71#ifdef WIN32
72#define IFWINDOWS(dothis) dothis
73#define IFUNIX(dothis)
74/*#include <windows.h>*/
75#include <winsock2.h>
76#define close(s) closesocket(s)
77#define nonblockingsocket(s) {unsigned long ctl = 1;ioctlsocket( s, FIONBIO, &ctl );}
78#define s_errno WSAGetLastError()
79#define EWOULDBLOCK WSAEWOULDBLOCK
80#define usleep(a) Sleep((a)/1000)
81#define MSG_NOSIGNAL 0
82
83/******* NON WINDOWS DEFINES *********/
84#else
85#define IFWINDOWS(dothis)
86#define IFUNIX(dothis) dothis
87
88#include <errno.h>
89#define s_errno errno
90#include <netdb.h>
91#include <sys/types.h>
92#include <sys/socket.h>
93#include <netinet/in.h>
94#include <arpa/inet.h> 
95#include <unistd.h>
96#include <fcntl.h>
97#define nonblockingsocket(s)  fcntl(s,F_SETFL,O_NONBLOCK)
98#endif
99
100#ifndef INADDR_NONE
101#define INADDR_NONE (-1)
102#endif
103
104/* Do this hack cause SIGPIPE that kills matlab on any platform??? */
105#ifndef MSG_NOSIGNAL
106#define MSG_NOSIGNAL 0
107#endif
108
109/* Include header file for matlab mex file functionality */
110#include "mex.h"
111
112/********** DEFINES related to pnet own functionality *****************/
113/*   Set debuging on/off   */
114#define debug_view_con_status(X)   /* __debug_view_con_status(X)*/
115
116#define MAX_CON         100       /* Maximum number of simultanius tcpip connections.*/
117#define NAMEBUFF_LEN    100
118#define MINBUFFSIZE     1000      /* readbuffer will shrink to this size if datalength is smaller. */
119#define CBNAMELEN       30
120
121#define CON_FREE         -1       /* Find a new free struct in struct array */
122
123#define BACKLOG           50       /* How many pending connections queue will hold */
124
125#define double_inf            HUGE_VAL
126#define DEFAULT_WRITETIMEOUT  double_inf
127#define DEFAULT_READTIMEOUT   double_inf
128#define DEFAULT_INPUT_SIZE    50000
129#define DEFAULT_USLEEP        10000
130
131/* Different status of a con_info struct handles a file descriptor    */
132#define STATUS_FREE       -1
133#define STATUS_NOCONNECT   0    /* Disconnected pipe that is note closed */ 
134#define STATUS_TCP_SOCKET  1
135#define STATUS_IO_OK       5    /* Used for IS_... test */
136#define STATUS_UDP_CLIENT  6
137#define STATUS_UDP_SERVER  8
138#define STATUS_CONNECT     10   /* Used for IS_... test */
139#define STATUS_TCP_CLIENT  11
140#define STATUS_TCP_SERVER  12
141#define STATUS_UDP_CLIENT_CONNECT 18
142#define STATUS_UDP_SERVER_CONNECT 19
143
144#define IS_STATUS_IO_OK(x) ((x)>=STATUS_IO_OK)
145#define IS_STATUS_CONNECTED(x) ((x)>=STATUS_CONNECT)
146#define IS_STATUS_UDP_NO_CON(x) ((x)==STATUS_UDP_CLIENT || (x)==STATUS_UDP_SERVER)
147#define IS_STATUS_TCP_CONNECTED(x) ((x)==STATUS_TCP_CLIENT || (x)==STATUS_TCP_SERVER)
148
149typedef struct
150{
151    char *ptr;       /* Pointer to buffert. */
152    int len;         /* Length of allocated buffert. */
153    int pos;         /* Length used of buffer for data storage.*/
154} io_buff;
155
156/* Structure that hold all information about a tcpip connection. */
157typedef struct
158{
159    int fid;
160    double writetimeout;
161    double readtimeout;
162    struct sockaddr_in remote_addr;
163    io_buff write;
164    io_buff read;
165    int status;       /* STATUS_... FREE, NOCONNECT, SERVER, CLIENT ... */
166    char callback[CBNAMELEN+1];
167} con_info;
168
169
170/* Some global variables */
171int        gret_args=0;         /* Global variable that holds number of matlab return argumens returned */
172int            gnlhs;           /* number of expected outputs */
173mxArray       **gplhs;          /* array of pointers to output arguments */
174int            gnrhs;           /* number of inputs */
175const mxArray  **gprhs;         /* array of pointers to input arguments */
176
177/* Global list with static length of connections structures holding info about current connection */
178con_info con[MAX_CON];
179int con_index=0;                   /* Current index possition for list of handlers */
180unsigned long mex_call_counter=0;  /* Counter that counts how many calls that have been done to pnet */
181
182/***********************************************************************/
183void Print_Start_Message(){
184    mexPrintf("\n===============================================================================\n"
185          "Loaded pnet MEX-file for the tcp/udp/ip-toolbox Compiled @ "
186          __DATE__ " " __TIME__  "\n"
187          VERSION "\n"
188          "Copyright (C) Peter Rydes�ter, Sweden, et al. , 1998 - 2003\n"
189          "GNU General Public License, se license.txt for full license notis.\n"
190          "You are allowed to (dynamicaly) link this file with non-free code. \n\n"
191          "   http://www.rydesater.com \n\n"
192          "===============================================================================\n\n"
193          );
194}
195
196/***********************************************************************/
197int myoptstrcmp(const char *s1,const char *s2)
198{
199    int val;
200    while( (val= toupper(*s1) - toupper(*s2))==0 ){
201    if(*s1==0 || *s2==0) return 0;
202    s1++;
203    s2++;
204    while(*s1=='_') s1++;
205    while(*s2=='_') s2++;
206    }
207    return val;
208}
209
210/********************************************************************/
211/* A "wrapper" function for memory allocation. Most for debuging /tracing purpose */
212void *myrealloc(char *ptr,int newsize)
213{
214    ptr=realloc(ptr,newsize);
215    if(ptr==NULL && newsize>0)
216    mexErrMsgTxt("Internal out of memory!");
217    return ptr;
218}
219
220/********************************************************************/
221/* A "wrapper" function for memory allocation. Most for debuging /tracing purpose */
222void newbuffsize(io_buff *buff,int newsize)
223{
224    /*    fprintf(stderr,"NEWSIZE:%d\n",newsize); */
225    if(newsize==-1){
226    free(buff->ptr);
227    buff->ptr=NULL;
228    return;
229    }
230    if(newsize<buff->pos)
231    newsize=buff->pos;
232    if(newsize<256)
233    newsize=256;
234    if(newsize>buff->len){   /* Grow.... */
235    /*  fprintf(stderr,"NEWSIZE UP %d -> %d\n",buff->len,newsize*2);*/
236    buff->ptr=myrealloc(buff->ptr,newsize*2);
237    buff->len=newsize*2;
238    }else if(newsize*4 < buff->len){ /* Decrease... */
239    /*  fprintf(stderr,"NEWSIZE DOWN %d -> %d\n",buff->len,newsize*2); */
240    buff->ptr=myrealloc(buff->ptr,newsize*2);
241    buff->len=newsize*2;
242    }
243}
244
245/********************************************************************/
246mxClassID str2classid(const char *str)
247{
248    if(myoptstrcmp("CHAR",str)==0)      return mxCHAR_CLASS;
249    if(myoptstrcmp("DOUBLE",str)==0)    return mxDOUBLE_CLASS;
250    if(myoptstrcmp("SINGLE",str)==0)    return mxSINGLE_CLASS;
251    if(myoptstrcmp("INT8",str)==0)      return mxINT8_CLASS;
252    if(myoptstrcmp("UINT8",str)==0)     return mxUINT8_CLASS;
253    if(myoptstrcmp("INT16",str)==0)     return mxINT16_CLASS;
254    if(myoptstrcmp("UINT16",str)==0)    return mxUINT16_CLASS;
255    if(myoptstrcmp("INT32",str)==0)     return mxINT32_CLASS;
256    if(myoptstrcmp("UINT32",str)==0)    return mxUINT32_CLASS;
257    return mxCHAR_CLASS;  /* Default to char; */
258}
259
260/********************************************************************/
261mxClassID classid2size(const mxClassID id)
262{
263    if(id==mxCHAR_CLASS)    return 1;
264    if(id==mxDOUBLE_CLASS)  return sizeof(double);
265    if(id==mxSINGLE_CLASS)  return sizeof(float);
266    if(id==mxINT8_CLASS)    return 1;
267    if(id==mxUINT8_CLASS)   return 1;
268    if(id==mxINT16_CLASS)   return 2;
269    if(id==mxUINT16_CLASS)  return 2;
270    if(id==mxINT32_CLASS)   return 4;
271    if(id==mxUINT32_CLASS)  return 4;
272    mexErrMsgTxt("Non supported datatype!");
273    return 0;
274}
275
276/* Windows implementation of perror() function */
277#ifdef WIN32
278/********************************************************************/
279void perror(const char *context )
280{
281    int wsa_err;
282    wsa_err = WSAGetLastError();
283    mexPrintf( "[%s]: WSA error: ", context );
284    switch ( wsa_err )
285    {
286    case WSANOTINITIALISED: mexPrintf( "WSANOTINITIALISED\n" ); break;
287    case WSAENETDOWN:       mexPrintf( "WSAENETDOWN      \n" ); break;
288    case WSAEADDRINUSE:     mexPrintf( "WSAEADDRINUSE    \n" ); break;
289    case WSAEACCES:         mexPrintf( "WSAEACCES        \n" ); break;
290    case WSAEINTR:          mexPrintf( "WSAEINTR         \n" ); break;
291    case WSAEINPROGRESS:    mexPrintf( "WSAEINPROGRESS   \n" ); break;
292    case WSAEALREADY:       mexPrintf( "WSAEALREADY      \n" ); break;
293    case WSAEADDRNOTAVAIL:  mexPrintf( "WSAEADDRNOTAVAIL \n" ); break;
294    case WSAEAFNOSUPPORT:   mexPrintf( "WSAEAFNOSUPPORT  \n" ); break;
295    case WSAEFAULT:         mexPrintf( "WSAEFAULT        \n" ); break;
296    case WSAENETRESET:      mexPrintf( "WSAENETRESET     \n" ); break;
297    case WSAENOBUFS:        mexPrintf( "WSAENOBUFS       \n" ); break;
298    case WSAENOTSOCK:       mexPrintf( "WSAENOTSOCK      \n" ); break;
299    case WSAEOPNOTSUPP:     mexPrintf( "WSAEOPNOTSUPP    \n" ); break;
300    case WSAESHUTDOWN:      mexPrintf( "WSAESHUTDOWN     \n" ); break;
301    case WSAEWOULDBLOCK:    mexPrintf( "WSAEWOULDBLOCK   \n" ); break;
302    case WSAEMSGSIZE:       mexPrintf( "WSAEMSGSIZE      \n" ); break;
303    case WSAEHOSTUNREACH:   mexPrintf( "WSAEHOSTUNREACH  \n" ); break;
304    case WSAEINVAL:         mexPrintf( "WSAEINVAL        \n" ); break;
305
306    case WSAECONNREFUSED:   mexPrintf( "WSAECONNREFUSED  \n" ); break;
307    case WSAECONNABORTED:   mexPrintf( "WSAECONNABORTED  \n" ); break;
308    case WSAECONNRESET:     mexPrintf( "WSAECONNRESET    \n" ); break;
309    case WSAEISCONN:        mexPrintf( "WSAEISCONN       \n" ); break;
310    case WSAENOTCONN:       mexPrintf( "WSAENOTCONN      \n" ); break;
311    case WSAETIMEDOUT:      mexPrintf( "WSAETIMEDOUT     \n" ); break;
312    default:                mexPrintf( "Unknown(%d) error!\n", wsa_err ); break;
313    }
314    return;
315}
316#endif
317
318/********************************************************************/
319/*Makes byte swapping, or not depending on the mode argument        */
320void byteswapdata(char *ptr,const int elements,const int elementsize,int mode)
321{
322    /* MODE=0 Do nothing, MODE=1 Swap, MODE=2 network byte order, MODE=3 Intel byte order. */
323#ifndef SWAPDATA
324#define SWAPDATA(a,b) { a^=b; b^=a; a^=b; }
325#endif
326    /* A little smart ckeck of byte the machine byte order. */
327    const int ordertest=1;
328    const char *is_intel_order=(const char *)(&ordertest);
329    /*    fprintf(stderr,"SWAP FUNCTION...E:%d SI:%d\n",elements,elementsize); */
330    if(elementsize<2) return;
331    if(is_intel_order[0]==1 && mode==2)   mode=1;
332    if(is_intel_order[0]==0 && mode==3)   mode=1;
333    if(mode==1){
334    int e;
335    /*  fprintf(stderr,"SWAP DATA\n"); */
336    switch(elementsize){
337    case 2: for(e=0;e<elements*elementsize;e+=elementsize)
338        SWAPDATA(ptr[e],ptr[e+1]) break;
339    case 3: for(e=0;e<elements*elementsize;e+=elementsize)
340        SWAPDATA(ptr[e],ptr[e+2])  break;
341    case 4: for(e=0;e<elements*elementsize;e+=elementsize)
342        SWAPDATA(ptr[e],ptr[e+3]) SWAPDATA(ptr[e+1],ptr[e+2])  break;
343    case 5: for(e=0;e<elements*elementsize;e+=elementsize)
344        SWAPDATA(ptr[e],ptr[e+4]) SWAPDATA(ptr[e+1],ptr[e+3])  break;
345    case 6: for(e=0;e<elements*elementsize;e+=elementsize)
346        SWAPDATA(ptr[e],ptr[e+5]) SWAPDATA(ptr[e+1],ptr[e+4]) SWAPDATA(ptr[e+2],ptr[e+3])  break;
347    case 7: for(e=0;e<elements*elementsize;e+=elementsize)
348        SWAPDATA(ptr[e],ptr[e+6]) SWAPDATA(ptr[e+1],ptr[e+5]) SWAPDATA(ptr[e+2],ptr[e+4])  break;
349    case 8: for(e=0;e<elements*elementsize;e+=elementsize)
350        SWAPDATA(ptr[e],ptr[e+7]) SWAPDATA(ptr[e+1],ptr[e+6]) SWAPDATA(ptr[e+2],ptr[e+5]) SWAPDATA(ptr[e+3],ptr[e+4])  break;
351    }
352    }
353}
354
355/********************************************************************/
356/*Makes byte swapping, or not depending on the mode argument        */
357void byteswapcopy(char *dest,char *src,const int elements,const int elementsize,int mode)
358{
359    /* MODE=0 Do nothing, MODE=1 Swap, MODE=2 network byte order, MODE=2 Intel byte order.
360       A little smart ckeck of byte the machine byte order.*/
361    const int ordertest=1;
362    const char *is_intel_order=(const char *)(&ordertest);
363    if(is_intel_order[0]==1 && mode==2)   mode=1;   
364    if(is_intel_order[0]==0 && mode==3)   mode=1;
365    /*    fprintf(stderr,"SWAP COPY E:%d SI:%d SWAP:%d\n",elements,elementsize,mode); */
366    if(mode==1){
367    int e,n;
368    /*  fprintf(stderr,"SWAP COPY\n"); */
369    for(e=0;e<elements;e++){
370        char *dp=&dest[e*elementsize];
371        char *sp=&src[e*elementsize];
372        for(n=0;n<elementsize;n++){
373        dp[n]=sp[elementsize-1-n];
374        /*      fprintf(stderr,"E:%d/%d N:%d/%d\n",e,elements,n,elementsize); */
375        }
376    }
377    /*  fprintf(stderr,"SWAP COPY END\n"); */
378    }
379    else
380        memmove(dest,src,elements*elementsize);
381}
382
383/********************************************************************/
384/* DEBUGING FUNCTION */
385void __debug_view_con_status(char *str)
386{
387    int a;
388    mexPrintf("%s\n",str);
389    for(a=0;a<5;a++)
390    {
391    mexPrintf("[%02d] FID:%02d STATUS:%02d WRT.POS:%d RD.POS:%d ",a,con[a].fid,con[a].status,con[a].write.pos,con[a].read.pos);
392    if(con[a].read.ptr)
393        mexPrintf("RD: %02x %02x %02x %02x %02x %02x %02x %02x ",
394              (int)con[a].read.ptr[0],(int)con[a].read.ptr[1],(int)con[a].read.ptr[2],(int)con[a].read.ptr[3],
395              (int)con[a].read.ptr[4],(int)con[a].read.ptr[5],(int)con[a].read.ptr[6],(int)con[a].read.ptr[7]);
396    if(con[a].write.ptr)
397        mexPrintf("WR: %02x %02x %02x %02x %02x %02x %02x %02x ",
398              (int)con[a].write.ptr[0],(int)con[a].write.ptr[1],(int)con[a].write.ptr[2],(int)con[a].write.ptr[3],
399              (int)con[a].write.ptr[4],(int)con[a].write.ptr[5],(int)con[a].write.ptr[6],(int)con[a].write.ptr[7]);
400    if(a==con_index)
401        mexPrintf("<--\n");
402    else
403        mexPrintf("\n");
404    }
405    mexPrintf("--------------------\n");
406}
407
408/********************************************************************/
409/* Portable time function using matlabs NOW                         */
410double my_now(){
411    double sec;
412    double dotimenow;
413    static double lastdotime;
414    mxArray *plhs[1]={NULL};
415    mxArray *prhs[1]={NULL};
416    mexCallMATLAB(1,plhs,0,prhs,"now");
417    sec=mxGetScalar(plhs[0])*60*60*24; /*Return time as sec from 1970*/
418    dotimenow=floor(sec*10)/10; /* Do calls every 1/10 Sec */
419    mxDestroyArray(plhs[0]);
420    if(lastdotime!=dotimenow){  /* Call drawnow once evry X second */
421        int ret=mexCallMATLAB(0,plhs,0,prhs,"drawnow");
422        /*  mexPrintf("wait... drawnow returns: %d\n",ret); */
423        lastdotime= dotimenow;
424    }
425    return sec;
426}
427
428/*******************************************************************************/
429/* Checks that given index is valid index and set current index, "con_index"   */
430/* to that point. If index is CON_FREE (-1) then is search done for a free one */
431/* Returns 1 On success. 0 on error                                            */
432int move_con(int idx)
433{
434    if(idx>=MAX_CON)
435    mexErrMsgTxt("Unvalid value of handler!\n");
436    if(idx>=0)
437    {
438    con_index=idx;
439    if(con[con_index].status==STATUS_FREE)
440        mexErrMsgTxt("No valid handler! already closed?");
441    return 1;
442    }
443    debug_view_con_status("START MOVE");
444    if(idx==CON_FREE)    /* Move con_index until it find a free non used struct */
445    {
446    for(con_index=0;con_index<MAX_CON;con_index++)
447    {
448        debug_view_con_status("STEP MOVE");
449        if(con[con_index].status==STATUS_FREE)
450        return 1;
451    }
452    mexErrMsgTxt("To many open connection! Forgot to close old connections?");
453    }
454    if(idx<0)
455    mexErrMsgTxt("Unvalid value of handler!");
456    return 0;
457}
458
459/**********************************************************************************************/
460/* Returns true if specified argument exist                                                  */
461int my_mexIsInputArgOK(const int argno)
462{
463    /*    fprintf(stderr,"IS_INPUT_ARG_OK NO:%d of %d\n",argno,gnrhs);        // DEBUG */
464    if(gnrhs>argno)
465    return 1;
466    return 0;
467}
468
469/******************************************************************************************************/
470/* Returns specified input argument as scalar. Global and error tolerant replacement for mxGetScalar */
471const mxArray *my_mexInputArg(const int argno)
472{
473    /*    fprintf(stderr,"GET_INPUT_ARG NO:%d\n",argno);                      // DEBUG */
474    if(!my_mexIsInputArgOK(argno))
475    mexErrMsgTxt("Missing input argument.");
476    return gprhs[argno];
477}
478
479/****************************************************************************************************************/
480/* Returns pointer to static buffer (max 80 chars) holding a string in argument argno Global and error tolerant */
481const char *my_mexInputOptionString(const int argno)
482{
483    static char buff[80+1];
484    buff[0]=0;
485    if(my_mexIsInputArgOK(argno))
486    if(mxIsChar(my_mexInputArg(argno)))
487       mxGetString(my_mexInputArg(argno),buff,80);
488    return buff;
489}
490
491/****************************************************************************************************************/
492/* Returns pointer to static buffer (max 80 chars) holding the first string with non numeric,nonempty contents  */
493const char *my_mexFindInputString(int argno)
494{
495    const char *str;
496    static char buff[1];
497    buff[0]=0;
498    while(my_mexIsInputArgOK(argno)){
499    str=my_mexInputOptionString(argno);
500    if(!isdigit(str[0]) && str[0]!=0 )
501        return str;
502    argno++;
503    }
504    return buff;
505}
506
507/*********************************************************************/
508/* Returns true if if finds option opt at argument argno or later    */
509int my_mexFindInputOption(int argno,const char *opt)
510{
511    char buff[80+1];
512    while(my_mexIsInputArgOK(argno))
513    {
514    buff[0]=0;
515    mxGetString(my_mexInputArg(argno),buff,80);
516    if(myoptstrcmp(buff,opt)==0)
517        return 1;
518    argno++;
519    }
520    return 0;
521}
522
523/***********************************************************************************************************/
524/* Returns specified input arguments cell as scalar. Global and error tolerant replacement for mxGetScalar */
525double my_mexInputCell(const int argno,int cell_no)
526{
527    if(!mxIsDouble(my_mexInputArg(argno)))
528    mexErrMsgTxt("Argument has wrong datatype.");
529    if(cell_no>=mxGetNumberOfElements(my_mexInputArg(argno)))
530    mexErrMsgTxt("Argument has wrong number of cells");
531    return mxGetPr(my_mexInputArg(argno))[cell_no];
532}
533
534/******************************************************************************************************/
535/* Returns specified input argument as scalar or a scalar product of its elements.                    */
536/* Global and error tolerant replacement for mxGetScalar                                              */
537int my_mexInputSize(const int argno)
538{
539    if(!my_mexIsInputArgOK(argno))
540    return DEFAULT_INPUT_SIZE;
541    if(mxIsChar(my_mexInputArg(argno))){
542    const int ch=(my_mexInputOptionString(argno)[0]);
543    if(!isdigit(ch))
544        return DEFAULT_INPUT_SIZE;
545    else
546        return atoi(my_mexInputOptionString(argno));
547    }
548    if(mxGetNumberOfElements(my_mexInputArg(argno))>1){
549    int val=1,n=0,el=mxGetNumberOfElements(my_mexInputArg(argno));
550    for(n=0;n<el;n++)
551        val*=(int)my_mexInputCell(argno,n);
552    return val;
553    }else
554    return (int)mxGetScalar(my_mexInputArg(argno));
555}
556
557/******************************************************************************************************/
558/* Returns specified input argument as scalar. Global and error tolerant replacement for mxGetScalar */
559double my_mexInputScalar(const int argno)
560{
561    if(mxIsChar(my_mexInputArg(argno)))
562    return atof(my_mexInputOptionString(argno));
563    else
564    return mxGetScalar(my_mexInputArg(argno));
565}
566
567/********************************************************************/
568/* Copys a matlab Char array to a char * string buffer              */
569int my_mexInputArray2Buff(const int argno,io_buff *buff)
570{
571    mxClassID id=mxGetClassID(my_mexInputArg(argno));
572    int si=classid2size(id);
573    int len=mxGetNumberOfElements(my_mexInputArg(argno));
574    int swap=2;
575    if(my_mexFindInputOption(argno+1,"NATIVE"))  swap=0;
576    if(my_mexFindInputOption(argno+1,"SWAP"))    swap=1;
577    if(my_mexFindInputOption(argno+1,"NETWORK")) swap=2;
578    if(my_mexFindInputOption(argno+1,"INTEL"))   swap=3;
579   
580    newbuffsize(buff,buff->pos+len*si);
581
582    if(id==mxCHAR_CLASS){
583    mxChar *ptr = (mxChar *)mxGetPr(gprhs[argno]);
584    int a;
585    for(a=0;a<len;a++)
586        buff->ptr[buff->pos++]=(char)(unsigned char)ptr[a];
587    }else{
588    char *ptr = (char *)mxGetPr(gprhs[argno]);
589    byteswapcopy(&buff->ptr[buff->pos],ptr,len,si,swap);
590    buff->pos+=(len*si);
591    }
592    return len;
593}
594
595/*******************************************************************************/
596/* Puts double scalar in matlab variable in the array of return argument for mex*/
597void my_mexReturnValue(double val)
598{
599    if((gret_args>gnlhs) && (gret_args>1))
600    return;
601    gplhs[gret_args]=mxCreateDoubleMatrix(1,1,mxREAL);
602    if(gplhs[gret_args]==NULL)
603    mexErrMsgTxt("Matrix creation error! Lack of memory?");
604    else
605    {
606    *mxGetPr(gplhs[gret_args])=val;
607    gret_args++;
608    }
609/*    mexPrintf("DEBUG MEX RETURN VALUE:%g\n",val);  // DEBUG */
610}
611
612/*******************************************************************************/
613/* Puts double matrix in matlab variable in the array of return argument for mex*/
614void my_mexReturnMatrix(int rows, int cols, double *vals)
615{
616    double *pr;
617    if((gret_args>gnlhs) && (gret_args>1))
618    return;
619    gplhs[gret_args] = mxCreateDoubleMatrix( rows, cols, mxREAL);
620    if( gplhs[gret_args] == NULL)
621        mexErrMsgTxt("Matrix creation error");
622    pr = (double *)mxGetPr(gplhs[gret_args]);
623    memcpy(pr,vals,rows*cols*sizeof(double));
624    gret_args++;
625}
626
627/********************************************************************************/
628/* Puts string as matlab char char variable in array of return argument for mex */
629void my_mexReturnString(const char *str)
630{
631    if(gret_args>gnlhs && gret_args>1)
632    return;
633    gplhs[gret_args]=mxCreateString(str);
634    if(gplhs[gret_args]==NULL)
635    mexErrMsgTxt("String creation error! Lack of memory?");
636    gret_args++;
637}
638
639/******************************************************************************/
640/* Puts data from buffer into next MATLAB return Array                        */
641void my_mexReturnArrayFromBuff(const int argno,io_buff *buff,const int line)
642{
643    const int maxelements=my_mexInputSize(argno);
644    const mxClassID id=str2classid(my_mexInputOptionString(argno+1));
645    int dims[20]={0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0 };
646    const int si=classid2size(id);
647    int returnelements= ( (buff->pos/si)< maxelements )?(buff->pos/si):maxelements;
648    int deleteelements=returnelements;
649    int swap=2;
650    int return_no_dims= my_mexIsInputArgOK(argno) && !mxIsChar(my_mexInputArg(argno))?mxGetNumberOfElements(my_mexInputArg(argno)):1;
651
652    if(my_mexFindInputOption(argno+1,"NATIVE"))  swap=0;
653    if(my_mexFindInputOption(argno+1,"SWAP"))    swap=1;
654    if(my_mexFindInputOption(argno+1,"NETWORK")) swap=2;
655    if(my_mexFindInputOption(argno+1,"INTEL"))   swap=3;
656    if(return_no_dims>20)
657    mexErrMsgTxt("To many dimentions to return.");
658    debug_view_con_status("GET_ARRAY");
659    if(line){
660    int n=-7;
661    if(id!=mxCHAR_CLASS && return_no_dims)
662        mexErrMsgTxt("'READLINE' works only with datatype char and non fixed blocksize");
663    for(n=0;n<returnelements;n++)
664        if(buff->ptr[n]=='\n')
665        break;
666    if(n==maxelements)                             /* If no new-line found inside limit...*/
667        deleteelements=returnelements=maxelements; /* ...return first part of splited line.*/
668    else if(n==returnelements)                     /* If new-line not recived inside limit...*/
669        deleteelements=returnelements=0;           /* ...return empty string, and delete nothing.*/
670    else if(n>0 && buff->ptr[n-1]=='\r')           /* If(*3) new-line, return line of char but not nl chars.*/
671       deleteelements=2+(returnelements=n-1);
672    else
673       deleteelements=1+(returnelements=n);
674    return_no_dims=1;
675    }
676    if(return_no_dims>1){                 /* If shape of return argument is specified.....*/
677    if(returnelements==maxelements){        /* ...then only accept correct shape. */
678        int n;
679        for(n=0;n<return_no_dims;n++)
680        dims[n]=(int)my_mexInputCell(argno,n);
681    }
682    }else if(returnelements>0){           /* else... Just return row of available elements */
683    dims[0]=1;
684    dims[1]=returnelements;
685    return_no_dims=2;
686    }
687    if(! (gret_args>gnlhs && gret_args>1) ){
688    /* Create a 2-Dimensional character mxArray.*/
689    if( dims[0]==0)
690        gplhs[gret_args] = mxCreateNumericArray(0,dims,id,mxREAL);
691    else
692        gplhs[gret_args] = mxCreateNumericArray(return_no_dims,dims,id,mxREAL);
693    if(gplhs[gret_args] == NULL)
694        mexErrMsgTxt("Could not create return array.");
695    if(dims[0]!=0){
696        if(id==mxCHAR_CLASS){
697        int i;
698        mxChar *p=(mxChar *)mxGetPr(gplhs[gret_args]);
699        for(i=0;i<returnelements;i++)
700            p[i]=buff->ptr[i];
701        }else{
702        char *p=(char *)mxGetPr(gplhs[gret_args]);
703        byteswapcopy(p,buff->ptr,returnelements,si,swap);
704        }
705    }
706    gret_args++;
707    }
708       /*    debug_view_con_status("GET_ARRAY N�STAN KLAR");*/
709    /* Delete from read buffer if not "VIEW" option and dims filled */
710    if(my_mexFindInputOption(argno+1,"VIEW")==0 && deleteelements>0 ){
711    buff->pos-=deleteelements*si;
712    memmove(buff->ptr,&buff->ptr[deleteelements*si],buff->pos);
713    newbuffsize(buff,buff->pos);
714    }
715    /* mexPrintf("DEBUG MEX RETURN ARRAY OF:%d\n",returnelements);  // DEBUG */
716
717    /*    fprintf(stderr,"DIMS:[%d %d] DEL:%d RET:%d SI:%d POS:%d LEN:%d PTR:%08X\n",
718            dims[0],dims[1],deleteelements,returnelements,si,buff->pos,buff->len,buff->ptr); */
719}
720
721
722/**********************************************************************/
723int ipv4_lookup(const char *hostname,int port)
724{
725    struct in_addr addr;    /* my address information */
726    /* Try IP address */
727    addr.s_addr=inet_addr(hostname);
728    if (addr.s_addr==INADDR_NONE){
729    /*Can't resolve host string as dot notation IP number...
730      try lookup IP from hostname */
731    struct hostent *he;
732    /*  fprintf(stderr,"Trying nameserverlookup:%s\n",hostname); */
733    he=gethostbyname(hostname);
734    if(he==NULL){
735        mexPrintf("\nUNKNOWN HOST:%s\n",hostname);
736        return -1;  /* Can not lookup hostname */
737    }
738    addr = *((struct in_addr *)he->h_addr);
739    }
740    con[con_index].remote_addr.sin_family=AF_INET;
741    con[con_index].remote_addr.sin_port=htons(port);
742    con[con_index].remote_addr.sin_addr=addr;
743    memset(&con[con_index].remote_addr.sin_zero, 0,8);
744    return 0;
745}
746
747
748
749
750
751
752
753
754
755
756
757/**********************************************************************/
758/* Writes from specified position (pointer) in buffer of spec. length */
759int writedata()
760{
761    const double timeoutat=my_now()+con[con_index].writetimeout;
762    int   len=con[con_index].write.pos;
763    const char *ptr=con[con_index].write.ptr;
764    const int  fid=con[con_index].fid;
765    int sentlen=0;
766    int retval=0;
767    int lastsize=1000000;
768    if(con[con_index].status<STATUS_IO_OK)
769    return 0;
770    /*    if( !IS_STATUS_TCP_CONNECTED(con[con_index].status)  && len>65534 )   // TODO: Ta bort! */
771    /*  len=65534; */
772    while(sentlen<len)
773    {
774    if(lastsize<1000)
775        usleep(DEFAULT_USLEEP);
776    if(IS_STATUS_UDP_NO_CON(con[con_index].status))
777        retval = sendto(fid,&ptr[sentlen],len-sentlen,MSG_NOSIGNAL,
778                (struct sockaddr *)&con[con_index].remote_addr,sizeof(struct sockaddr));
779    else
780        retval=send(fid,&ptr[sentlen],len-sentlen,MSG_NOSIGNAL);
781    lastsize=retval>0?retval:0;
782    sentlen+=lastsize;
783    /*  if( retval==0){
784        mexPrintf("\nREMOTE HOST DISCONNECTED\n");
785        con[con_index].status=STATUS_NOCONNECT;
786        break;
787        }*/
788    if(retval<0 && s_errno != EWOULDBLOCK)
789
790       {
791        con[con_index].status=STATUS_NOCONNECT;
792        perror( "sendto() / send()" );
793        mexPrintf("\nREMOTE HOST DISCONNECTED\n");
794        break;
795    }
796    if( !IS_STATUS_TCP_CONNECTED(con[con_index].status) && sentlen>0 )
797        break;
798    if(timeoutat<=my_now())
799        break;
800    }
801    con[con_index].write.pos-=sentlen;
802    memmove(con[con_index].write.ptr, &con[con_index].write.ptr[sentlen], con[con_index].write.pos);
803    newbuffsize(&con[con_index].write,con[con_index].write.pos);
804    return sentlen;
805}
806
807/********************************************************************/
808/* Init current record with values                                  */
809void init_con(int fid,int status)
810{
811    memset(&con[con_index],0,sizeof(con_info));
812    con[con_index].fid=fid;
813    con[con_index].status=status;
814    con[con_index].writetimeout=DEFAULT_WRITETIMEOUT;
815    con[con_index].readtimeout=DEFAULT_READTIMEOUT;
816}
817
818/********************************************************************/
819/* Close con struct                                                 */
820void close_con()
821{
822    if(con[con_index].fid>=0)
823    close(con[con_index].fid);
824    else
825    mexWarnMsgTxt("Closing already closed connection!");
826    newbuffsize(&con[con_index].write,-1);
827    newbuffsize(&con[con_index].read,-1);
828    init_con(-1,STATUS_FREE);
829}
830
831/*******************************************************************      */
832/* Function to close all still open tcpip connections */
833int closeall(void)
834{
835    int flag=0;
836    for(con_index=0;con_index<MAX_CON;con_index++)
837    if(con[con_index].fid>=0) {  /* Already closed?? */
838        close_con();
839        flag=1;
840    }
841    return flag;
842}
843
844/****************************************************************************/
845/* This function is called on unloading of mex-file                         */
846void CleanUpMex(void)
847{
848    if(closeall()) /* close all still open connections...*/
849    mexWarnMsgTxt("Unloading mex file. Unclosed tcp/udp/ip connections will be closed!");
850    IFWINDOWS(   WSACleanup();  );
851}
852
853/********************************************************************/
854/* Read to fill input buffer with specified length from UDP or TCP network*/
855int read2buff(const int len,int newline,int noblock)
856{
857    const double timeoutat=my_now()+con[con_index].readtimeout;
858    int retval=-1;
859
860    if(len<con[con_index].read.pos)              /* If enouth in buffer then return */
861    return len;
862    if(0==IS_STATUS_IO_OK(con[con_index].status))/* If not read/write fid (broken pipe) then exit.*/
863    if(len<con[con_index].read.pos)
864        return len;
865    else
866        return con[con_index].read.pos;
867
868    /* Resize readbuffer to needed size */
869    if(con[con_index].read.len<len)
870    newbuffsize(&con[con_index].read,len);
871
872    while(1){
873    int readlen=len-con[con_index].read.pos;
874/*  mexPrintf("DEBUG: READLINE: readlen:%d\n",readlen); */
875    if(readlen>0){
876        if(IS_STATUS_CONNECTED(con[con_index].status))
877        retval=recv(con[con_index].fid,&con[con_index].read.ptr[con[con_index].read.pos],readlen ,MSG_NOSIGNAL);
878        else{
879        struct sockaddr_in my_addr;
880        int fromlen=sizeof(my_addr); 
881
882        /* Copy 0.0.0.0 adress and 0 port to remote_addr as init-value. */
883        memset(&my_addr,0,sizeof(my_addr));
884        con[con_index].remote_addr.sin_addr = my_addr.sin_addr;
885        con[con_index].remote_addr.sin_port = my_addr.sin_port;
886        retval=recvfrom(con[con_index].fid,&con[con_index].read.ptr[con[con_index].read.pos],
887                readlen,MSG_NOSIGNAL,(struct sockaddr *)&my_addr, &fromlen);
888        if (retval>0){
889            con[con_index].remote_addr.sin_addr = my_addr.sin_addr;
890            con[con_index].remote_addr.sin_port = htons((unsigned short int)ntohs(my_addr.sin_port));
891        }
892        }
893        if( retval==0){
894        mexPrintf("\nREMOTE HOST DISCONNECTED\n");
895        con[con_index].status=STATUS_NOCONNECT;
896        break;
897        }
898       
899        if(retval<0 && s_errno!=EWOULDBLOCK)
900        /*IFWINDOWS( && s_errno!=WSAECONNRESET )// DEBUG: REMOVE THIS LINE? */{
901        con[con_index].status=STATUS_NOCONNECT;
902        perror( "recvfrom() or recv()" );
903        break;
904        }
905    }
906    /*  fprintf(stderr,"RET:%d/%d ",retval,s_errno); */
907    readlen=retval>0?retval:0;
908    con[con_index].read.pos+=readlen;
909    if( !IS_STATUS_TCP_CONNECTED(con[con_index].status) && con[con_index].read.pos>0 )
910        break;
911    if( con[con_index].read.pos>=len )
912        break;
913    if(timeoutat<=my_now() || noblock)
914        break;
915    if(newline){
916        int n;
917        for(n=0;n<con[con_index].read.pos;n++)
918        if(con[con_index].read.ptr[n]=='\n')
919            return con[con_index].read.pos;
920    }
921    if(readlen<1000)
922        usleep(DEFAULT_USLEEP);
923    }
924    return con[con_index].read.pos;
925}
926
927/***************************************************************************/   
928/* Read specified length & type from UDP or TCP network to input buffer    */
929int readtype2buff(int len,mxClassID datatype,int newline,int noblock)
930{
931    const int si=classid2size(datatype);
932    return read2buff(len*si,newline,noblock)/si;
933}
934
935/********************************************************************/
936/* Function Creating a tcpip connection and returns handler number  */
937int tcp_connect(const char *hostname,const int port)
938{
939    if(ipv4_lookup(hostname,port)==-1)
940    return -1;
941    con[con_index].fid=socket(AF_INET, SOCK_STREAM, 0);
942    if(con[con_index].fid== CON_FREE){
943    /*Can't open socket */
944    close_con();
945    return -1;
946    }
947    if(connect(con[con_index].fid,(struct sockaddr *)&con[con_index].remote_addr,sizeof(struct sockaddr)) == -1){
948    /*Can't connect to remote host. */
949    close_con();
950    return -1;
951    }
952    con[con_index].status=STATUS_TCP_CLIENT;
953    nonblockingsocket(con[con_index].fid); /* Non blocking read! */
954    return con_index;
955}
956
957/*******************************************************************     
958 Function Creating a TCP server socket                                 
959 or a connectionless UDP client socket.
960*/
961int tcp_udp_socket(int port,int dgram_f)
962{
963    int sockfd;
964    struct sockaddr_in my_addr;    /* my address information */
965    const int on=1;
966    if(dgram_f)
967    sockfd = socket(AF_INET, SOCK_DGRAM, 0);
968    else
969    sockfd = socket(AF_INET, SOCK_STREAM, 0);
970    if(sockfd==-1)
971    return -1;
972    my_addr.sin_family = AF_INET;         /* host byte order */
973    my_addr.sin_port = htons(port);       /* short, network byte order */
974    my_addr.sin_addr.s_addr = INADDR_ANY; /* auto-fill with my IP */
975    memset(&(my_addr.sin_zero),0, 8);        /* zero the rest of the struct */
976    setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,(const char *)&on,sizeof(on));
977    if(bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr))== -1)
978    {
979    close(sockfd);
980    return -1;
981    }
982    listen(sockfd,BACKLOG);
983    nonblockingsocket(sockfd);
984    return sockfd;
985}
986
987/*****************************************************************/
988/* Listen to socket and returns connection if there is one...
989   else it returns -1 */
990int tcpiplisten(int noblock)
991{
992    const double timeoutat=my_now()+con[con_index].readtimeout;
993    int new_fd;
994    const int sock_fd= con[con_index].fid;
995    int sin_size = sizeof(struct sockaddr_in);
996    move_con(CON_FREE);        /* Find a new free con struct for the new connection.... */
997    while(1){
998        if ((new_fd = accept(sock_fd, (struct sockaddr *)&con[con_index].remote_addr,&sin_size)) > -1)
999            break;
1000        if(timeoutat<=my_now()|| noblock)
1001            return -1;
1002        usleep(DEFAULT_USLEEP);
1003    }
1004    nonblockingsocket(new_fd); /* Non blocking read! */
1005    setsockopt(new_fd,SOL_SOCKET,SO_KEEPALIVE,(void *)1,0); /* realy needed? */
1006    con[con_index].fid=new_fd;
1007    con[con_index].status=STATUS_TCP_SERVER;
1008    return con_index;
1009}
1010
1011/*****************************************************************/
1012/* Make a UDP socket be a "connected" UDP socket                 */
1013int udp_connect(const char *hostname,int port)
1014{   
1015    if(con[con_index].status < STATUS_UDP_CLIENT)
1016    mexErrMsgTxt("Must pass UDP client or server handler!");
1017    if(ipv4_lookup(hostname,port)==-1)
1018    return -1;
1019    if(connect(con[con_index].fid,(struct sockaddr *)&con[con_index].remote_addr,sizeof(struct sockaddr)) == -1)
1020    return -1; /*Can't connect to remote host. */
1021    if(con[con_index].status == STATUS_UDP_CLIENT)
1022    con[con_index].status = STATUS_UDP_CLIENT_CONNECT;
1023    else
1024    con[con_index].status = STATUS_UDP_SERVER_CONNECT;
1025    nonblockingsocket(con[con_index].fid); /* Non blocking read! */
1026    return con[con_index].status;
1027}
1028
1029/*****************************************************************/
1030/*                                                               */
1031/*    ----Main function that is called from matlab--------       */
1032/*                                                               */
1033void mexFunction(
1034    int           nlhs,           /* number of expected outputs */
1035    mxArray       *plhs[],        /* array of pointers to output arguments */
1036    int           nrhs,           /* number of inputs */
1037    const mxArray *prhs[]         /* array of pointers to input arguments */
1038    )
1039{
1040    char fun[80+1];
1041    /* Initialization on first call to the mex file */
1042    if(mex_call_counter==0)
1043    {
1044#ifdef WIN32
1045    WORD wVersionRequested;
1046    WSADATA wsaData;
1047    int wsa_err;   
1048    wVersionRequested = MAKEWORD( 2, 0 );
1049    wsa_err = WSAStartup( wVersionRequested, &wsaData );
1050    if (wsa_err)
1051        mexErrMsgTxt("Error starting WINSOCK32.");
1052#endif
1053    Print_Start_Message();
1054
1055    mexAtExit(CleanUpMex);
1056    /* Init all connecttions to to free */
1057    for(con_index=0;con_index<MAX_CON;con_index++)
1058        init_con(-1,STATUS_FREE);
1059        con_index=0;
1060    }
1061    mex_call_counter++;
1062    debug_view_con_status("ENTER_MEX");
1063
1064    /* GLOBAL IN-OUT ARGUMENTS */
1065    gnlhs=nlhs;       /* number of expected outputs */
1066    gplhs=plhs;       /* array of pointers to output arguments */
1067    gnrhs=nrhs;       /* number of inputs */
1068    gprhs=prhs;       /* array of pointers to input arguments */
1069    gret_args=0;      /* No return argumens returned */
1070
1071
1072    if(mxIsChar(my_mexInputArg(0))){
1073    /* GET FIRST ARGUMENT -- The "function" name */
1074    strncpy(fun,my_mexInputOptionString(0),80);
1075/*  mexPrintf("DEBUG MEX(1):[%d] %s\n",con_index,fun);   // DEBUG */
1076   
1077    /* Find of the function name corresponds to a non connection associated function */
1078    if(myoptstrcmp(fun,"CLOSEALL")==0){
1079        closeall();
1080        return;
1081    }
1082    if(myoptstrcmp(fun,"TCPCONNECT")==0){
1083        const int port=(int)my_mexInputScalar(2);
1084        const char *hostname=my_mexInputOptionString(1);
1085        move_con(STATUS_FREE);
1086        my_mexReturnValue(tcp_connect(hostname,port));
1087        return;
1088    }
1089    if(myoptstrcmp(fun,"TCPSOCKET")==0){
1090        const int fd=tcp_udp_socket((int)my_mexInputScalar(1), 0);
1091        if(fd>=0){
1092        move_con(STATUS_FREE);
1093        init_con(fd,STATUS_TCP_SOCKET);
1094        my_mexReturnValue(con_index);
1095        }else
1096        my_mexReturnValue(-1);
1097        return;
1098    }
1099    if(myoptstrcmp(fun,"UDPSOCKET")==0){
1100        const int fd=tcp_udp_socket((int)my_mexInputScalar(1), 1);
1101        if(fd>=0){
1102        move_con(STATUS_FREE);
1103        init_con(fd,STATUS_UDP_CLIENT);
1104        my_mexReturnValue(con_index);
1105        }else
1106        my_mexReturnValue(-1);
1107        return;
1108    }
1109    if(myoptstrcmp(fun,"DOCALLBACKS")==0){
1110        return;
1111    }
1112    }
1113    /* Get connection handler and suppose that it is a connection assosiated function */
1114    /* Find given handel */
1115    /*       if(strncasecmp(fun,"DEF",3)!=0) */
1116    if(move_con((int)my_mexInputScalar(0))==0) 
1117    mexErrMsgTxt("Unknown connection handler");
1118    strncpy(fun,my_mexInputOptionString(1),80);
1119 /*   mexPrintf("DEBUG MEX(2):[%d] %s\n",con_index,fun);   // DEBUG */
1120    debug_view_con_status("CON_MOVED!!");
1121       
1122       if(myoptstrcmp(fun,"CLOSE")==0){
1123       close_con();
1124    return;
1125    }
1126    if(myoptstrcmp(fun,"TCPLISTEN")==0){
1127    if(con[con_index].status!=STATUS_TCP_SOCKET)
1128        mexErrMsgTxt("Invalid socket for LISTEN, Already open, or UDP?...");
1129    my_mexReturnValue(tcpiplisten(my_mexFindInputOption(2,"noblock")));
1130    return;
1131    }
1132    /* MATLAB called with status = UDP_CONNECT(fid, ip, port) */
1133    if(myoptstrcmp(fun,"UDPCONNECT")==0){
1134    const int port=(int)my_mexInputScalar(3);
1135    const char *hostname=my_mexInputOptionString(2);
1136    my_mexReturnValue(udp_connect(hostname,port));
1137    return;
1138    }
1139    if(myoptstrcmp(fun,"WRITE")==0){
1140    my_mexInputArray2Buff(2,&con[con_index].write);
1141    if(IS_STATUS_TCP_CONNECTED(con[con_index].status))
1142        writedata();
1143    return;
1144    }
1145    if(myoptstrcmp(fun,"PRINTF")==0){
1146    mxArray *plhs[1]={NULL};
1147    if(gnrhs<3) return;
1148    mexCallMATLAB(1,plhs, gnrhs-2, (mxArray **)&(gprhs[2]),"sprintf");
1149    gprhs=(const mxArray **)plhs; gnrhs=1; /* HACK: Move return arg from sprintf to input arg of this mex. */
1150    my_mexInputArray2Buff(0,&con[con_index].write);
1151    if(IS_STATUS_TCP_CONNECTED(con[con_index].status))
1152        writedata();
1153        return;
1154    }
1155    if(myoptstrcmp(fun,"READ")==0){
1156        if(IS_STATUS_TCP_CONNECTED(con[con_index].status))
1157            readtype2buff( (int)my_mexInputSize(2),str2classid(my_mexFindInputString(2)),0,my_mexFindInputOption(2,"noblock"));
1158        my_mexReturnArrayFromBuff(2,&con[con_index].read,0);
1159        return;
1160    }
1161    if(myoptstrcmp(fun,"READLINE")==0){
1162    /*  mexPrintf("DEBUG: READLINE....\n"); */
1163        if(IS_STATUS_TCP_CONNECTED(con[con_index].status))
1164            read2buff(my_mexInputSize(2),1,my_mexFindInputOption(2,"noblock"));
1165        my_mexReturnArrayFromBuff(2,&con[con_index].read,1);
1166    /*  mexPrintf("DEBUG: READLINE END\n"); */
1167    return;
1168    }
1169    if(myoptstrcmp(fun,"READTOFILE")==0){
1170    FILE *f=NULL;
1171    const int blocklen=my_mexInputSize(2+1);
1172    int readlen=blocklen;
1173    int writelen=0;
1174    if(IS_STATUS_TCP_CONNECTED(con[con_index].status))
1175        readlen= read2buff(blocklen,0,(int)my_mexFindInputOption(2+1,"noblock"));
1176    if(readlen>0)
1177        f=fopen(my_mexInputOptionString(2),(int)my_mexFindInputOption(2+1,"append")?"ab":"wb");
1178    if(f){
1179        writelen=fwrite(con[con_index].read.ptr,1,readlen,f);
1180        fclose(f);
1181    }
1182    /* Delete from read buffer if not "VIEW" option and dims filled */
1183    if(my_mexFindInputOption(2+1,"VIEW")==0 ){
1184        con[con_index].read.pos-=writelen;
1185        memmove(con[con_index].read.ptr,&con[con_index].read.ptr[writelen],con[con_index].read.pos);
1186        newbuffsize(&con[con_index].read,con[con_index].read.pos);
1187    }
1188    my_mexReturnValue(writelen);
1189    return;
1190    }
1191    if(myoptstrcmp(fun,"WRITEFROMFILE")==0){
1192    int len=1024*1024*1024;int start=0;
1193    FILE *f=fopen(my_mexInputOptionString(2),"rb");
1194    if(f==NULL)
1195        my_mexReturnValue(-1);
1196    if(my_mexIsInputArgOK(2+1))
1197        start=(int)my_mexInputScalar(2+1);
1198    if(my_mexIsInputArgOK(2+2))
1199        len=(int)my_mexInputScalar(2+2);
1200    else{
1201        fseek(f,0,SEEK_END);
1202        len=ftell(f)-start;
1203    }
1204    fseek(f,start,SEEK_SET);
1205    newbuffsize(&con[con_index].write,con[con_index].write.pos+len);
1206    len=fread(&con[con_index].write.ptr[con[con_index].write.pos],1,len,f);
1207    con[con_index].write.pos+=len;
1208    fclose(f);
1209    if(IS_STATUS_TCP_CONNECTED(con[con_index].status))
1210        writedata();
1211    if(len<0)
1212        my_mexReturnValue(-1);
1213    else
1214        my_mexReturnValue(len);
1215    return;
1216    }
1217    if(myoptstrcmp(fun,"READPACKET")==0){
1218        con[con_index].read.pos=0;
1219        my_mexReturnValue(readtype2buff(my_mexInputSize(2),str2classid(my_mexInputOptionString(2+1)),0,
1220            my_mexFindInputOption(2+1,"noblock")));
1221        return;
1222    }
1223    if(myoptstrcmp(fun,"WRITEPACKET")==0){
1224    if(IS_STATUS_UDP_NO_CON(con[con_index].status))
1225        ipv4_lookup(my_mexInputOptionString(2),my_mexInputScalar(3));
1226    my_mexReturnValue(writedata());
1227    con[con_index].write.pos=0;
1228    return;
1229    }
1230    if(myoptstrcmp(fun,"STATUS")==0){
1231    my_mexReturnValue(con[con_index].status);
1232    return;
1233    }
1234    if(myoptstrcmp(fun,"GETHOST")==0){
1235    int n;
1236    double ip_bytes[4] = {0, 0, 0, 0};
1237    const unsigned char *ipnr=(const unsigned char *)&con[con_index].remote_addr.sin_addr;
1238    for(n=0;n<4;n++)
1239        ip_bytes[n] = (double)ipnr[n];
1240    my_mexReturnMatrix(1,4,ip_bytes);
1241    my_mexReturnValue((int)ntohs(con[con_index].remote_addr.sin_port));
1242    return;
1243    }
1244    if(myoptstrcmp(fun,"SETCALLBACK")==0){
1245    strncpy(con[con_index].callback, my_mexInputOptionString(2), CBNAMELEN);
1246    return;
1247    }
1248    if(myoptstrcmp(fun,"GETCALLBACK")==0){
1249    my_mexReturnString(con[con_index].callback);
1250    return;
1251    }
1252    if(myoptstrcmp(fun,"SETWRITETIMEOUT")==0){
1253    con[con_index].writetimeout=my_mexInputScalar(2);
1254    return;
1255    }
1256    if(myoptstrcmp(fun,"SETREADTIMEOUT")==0){
1257    con[con_index].readtimeout=my_mexInputScalar(2);
1258    return;
1259    }
1260    if(myoptstrcmp(fun,"debug")==0){
1261    mexPrintf("     FID:%d\n",con[con_index].fid);
1262    mexPrintf("  STATUS:%d\n",con[con_index].status);
1263    mexPrintf("WRITE  TO:%g\n",con[con_index].writetimeout);
1264    mexPrintf("WRITE PTR:%x\n",(int)con[con_index].write.ptr);
1265    mexPrintf("WRITE POS:%d\n",con[con_index].write.pos);
1266    mexPrintf("WRITE LEN:%d\n",con[con_index].write.len);
1267    mexPrintf("READ  TO:%g\n",con[con_index].readtimeout);
1268    mexPrintf("READ PTR:%x\n",(int)con[con_index].read.ptr);
1269    mexPrintf("READ POS:%d\n",con[con_index].read.pos);
1270    mexPrintf("READ LEN:%d\n",con[con_index].read.len);
1271    return;
1272    }
1273    mexErrMsgTxt("Unknown 'function name' in argument.");
1274}
Note: See TracBrowser for help on using the repository browser.