source: PlatformSupport/pnet/pnet.c

Last change on this file was 1941, checked in by chunter, 11 years ago

modified so that 'version' argument only prints when nlhs is zero

File size: 47.2 KB
Line 
1/**********************************************************
2                             
3  MEX file for the tcpip toolbox.
4                                                          */
5#define VERSION "2.0.6d"
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 // ?? Is this OK ??
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/////////////////////////////////////////////////////////////////////////////////////////////////
171/* Some global variables */
172int        gret_args=0;         /* Global variable that holds number of matlab return argumens returned */
173int            gnlhs;           /* number of expected outputs */
174mxArray       **gplhs;          /* array of pointers to output arguments */
175int            gnrhs;           /* number of inputs */
176const mxArray  **gprhs;         /* array of pointers to input arguments */
177
178/* Global list with static length of connections structures holding info about current connection */
179con_info con[MAX_CON];
180int con_index=0;                   /* Current index possition for list of handlers */
181unsigned long mex_call_counter=0;  /* Counter that counts how many calls that have been done to pnet */
182
183/***********************************************************************/
184void Print_Start_Message(){
185    mexPrintf("Loaded pnet mex version " VERSION "\n");
186}
187
188void Print_Version_Message(){
189    mexPrintf("\n===============================================================================\n"
190          "pnet MEX-file for the tcp/udp/ip-toolbox Compiled @ "
191          __DATE__ " " __TIME__  "\n"
192          VERSION "\n"
193          "Original Source: Copyright (C) Peter Rydesäter, Sweden, et al. , 1998 - 2003\n"
194          "WARPLab Modifications: Copyright (C) Mango Communications, 2013\n"
195          "GNU General Public License, see license.txt for full license notice.\n"
196          "You are allowed to (dynamicaly) link this file with non-free code. \n"
197          "===============================================================================\n\n"
198          );
199}
200
201/***********************************************************************/
202int myoptstrcmp(const char *s1,const char *s2)
203{
204    int val;
205    while( (val= toupper(*s1) - toupper(*s2))==0 ){
206    if(*s1==0 || *s2==0) return 0;
207    s1++;
208    s2++;
209    while(*s1=='_') s1++;
210    while(*s2=='_') s2++;
211    }
212    return val;
213}
214
215/********************************************************************/
216/* A "wrapper" function for memory allocation. Most for debuging /tracing purpose */
217void *myrealloc(char *ptr,int newsize)
218{
219    ptr=realloc(ptr,newsize);
220    if(ptr==NULL && newsize>0)
221    mexErrMsgTxt("Internal out of memory!");
222    return ptr;
223}
224
225/********************************************************************/
226/* A "wrapper" function for memory allocation. Most for debuging /tracing purpose */
227void newbuffsize(io_buff *buff,int newsize)
228{
229    //    fprintf(stderr,"NEWSIZE:%d\n",newsize);
230    if(newsize==-1){
231    free(buff->ptr);
232    buff->ptr=NULL;
233    return;
234    }
235    if(newsize<buff->pos)
236    newsize=buff->pos;
237    if(newsize<256)
238    newsize=256;
239    if(newsize>buff->len){   // Grow....
240    //  fprintf(stderr,"NEWSIZE UP %d -> %d\n",buff->len,newsize*2);
241    buff->ptr=myrealloc(buff->ptr,newsize*2);
242    buff->len=newsize*2;
243    }else if(newsize*4 < buff->len){ // Decrease...
244    //  fprintf(stderr,"NEWSIZE DOWN %d -> %d\n",buff->len,newsize*2);
245    buff->ptr=myrealloc(buff->ptr,newsize*2);
246    buff->len=newsize*2;
247    }
248}
249
250/********************************************************************/
251mxClassID str2classid(const char *str)
252{
253    if(myoptstrcmp("CHAR",str)==0)      return mxCHAR_CLASS;
254    if(myoptstrcmp("DOUBLE",str)==0)    return mxDOUBLE_CLASS;
255    if(myoptstrcmp("SINGLE",str)==0)    return mxSINGLE_CLASS;
256    if(myoptstrcmp("INT8",str)==0)      return mxINT8_CLASS;
257    if(myoptstrcmp("UINT8",str)==0)     return mxUINT8_CLASS;
258    if(myoptstrcmp("INT16",str)==0)     return mxINT16_CLASS;
259    if(myoptstrcmp("UINT16",str)==0)    return mxUINT16_CLASS;
260    if(myoptstrcmp("INT32",str)==0)     return mxINT32_CLASS;
261    if(myoptstrcmp("UINT32",str)==0)    return mxUINT32_CLASS;
262    return mxCHAR_CLASS; // Default to char;
263}
264
265/********************************************************************/
266mxClassID classid2size(const mxClassID id)
267{
268    if(id==mxCHAR_CLASS)    return 1;
269    if(id==mxDOUBLE_CLASS)  return sizeof(double);
270    if(id==mxSINGLE_CLASS)  return sizeof(float);
271    if(id==mxINT8_CLASS)    return 1;
272    if(id==mxUINT8_CLASS)   return 1;
273    if(id==mxINT16_CLASS)   return 2;
274    if(id==mxUINT16_CLASS)  return 2;
275    if(id==mxINT32_CLASS)   return 4;
276    if(id==mxUINT32_CLASS)  return 4;
277    mexErrMsgTxt("Non supported datatype!");
278    return 0;
279}
280
281/* Windows implementation of perror() function */
282#ifdef WIN32
283/********************************************************************/
284void perror(const char *context )
285{
286    int wsa_err;
287    wsa_err = WSAGetLastError();
288    mexPrintf( "[%s]: WSA error: ", context );
289    switch ( wsa_err )
290    {
291    case WSANOTINITIALISED: mexPrintf( "WSANOTINITIALISED\n" ); break;
292    case WSAENETDOWN:       mexPrintf( "WSAENETDOWN      \n" ); break;
293    case WSAEADDRINUSE:     mexPrintf( "WSAEADDRINUSE    \n" ); break;
294    case WSAEACCES:         mexPrintf( "WSAEACCES        \n" ); break;
295    case WSAEINTR:          mexPrintf( "WSAEINTR         \n" ); break;
296    case WSAEINPROGRESS:    mexPrintf( "WSAEINPROGRESS   \n" ); break;
297    case WSAEALREADY:       mexPrintf( "WSAEALREADY      \n" ); break;
298    case WSAEADDRNOTAVAIL:  mexPrintf( "WSAEADDRNOTAVAIL \n" ); break;
299    case WSAEAFNOSUPPORT:   mexPrintf( "WSAEAFNOSUPPORT  \n" ); break;
300    case WSAEFAULT:         mexPrintf( "WSAEFAULT        \n" ); break;
301    case WSAENETRESET:      mexPrintf( "WSAENETRESET     \n" ); break;
302    case WSAENOBUFS:        mexPrintf( "WSAENOBUFS       \n" ); break;
303    case WSAENOTSOCK:       mexPrintf( "WSAENOTSOCK      \n" ); break;
304    case WSAEOPNOTSUPP:     mexPrintf( "WSAEOPNOTSUPP    \n" ); break;
305    case WSAESHUTDOWN:      mexPrintf( "WSAESHUTDOWN     \n" ); break;
306    case WSAEWOULDBLOCK:    mexPrintf( "WSAEWOULDBLOCK   \n" ); break;
307    case WSAEMSGSIZE:       mexPrintf( "WSAEMSGSIZE      \n" ); break;
308    case WSAEHOSTUNREACH:   mexPrintf( "WSAEHOSTUNREACH  \n" ); break;
309    case WSAEINVAL:         mexPrintf( "WSAEINVAL        \n" ); break;
310
311    case WSAECONNREFUSED:   mexPrintf( "WSAECONNREFUSED  \n" ); break;
312    case WSAECONNABORTED:   mexPrintf( "WSAECONNABORTED  \n" ); break;
313    case WSAECONNRESET:     mexPrintf( "WSAECONNRESET    \n" ); break;
314    case WSAEISCONN:        mexPrintf( "WSAEISCONN       \n" ); break;
315    case WSAENOTCONN:       mexPrintf( "WSAENOTCONN      \n" ); break;
316    case WSAETIMEDOUT:      mexPrintf( "WSAETIMEDOUT     \n" ); break;
317    default:                mexPrintf( "Unknown(%d) error!\n", wsa_err ); break;
318    }
319    return;
320}
321#endif
322
323/********************************************************************/
324/*Makes byte swapping, or not depending on the mode argument        */
325void byteswapdata(char *ptr,const int elements,const int elementsize,int mode)
326{
327    // MODE=0 Do nothing, MODE=1 Swap, MODE=2 network byte order, MODE=3 Intel byte order.
328#ifndef SWAPDATA
329#define SWAPDATA(a,b) { a^=b; b^=a; a^=b; }
330#endif
331    // A little smart ckeck of byte the machine byte order.
332    const int ordertest=1;
333    const char *is_intel_order=(const char *)(&ordertest);
334    //    fprintf(stderr,"SWAP FUNCTION...E:%d SI:%d\n",elements,elementsize);
335    if(elementsize<2) return;
336    if(is_intel_order[0]==1 && mode==2)   mode=1;
337    if(is_intel_order[0]==0 && mode==3)   mode=1;
338    if(mode==1){
339    int e;
340    //  fprintf(stderr,"SWAP DATA\n");
341    switch(elementsize){
342    case 2: for(e=0;e<elements*elementsize;e+=elementsize)
343        SWAPDATA(ptr[e],ptr[e+1]) break;
344    case 3: for(e=0;e<elements*elementsize;e+=elementsize)
345        SWAPDATA(ptr[e],ptr[e+2])  break;
346    case 4: for(e=0;e<elements*elementsize;e+=elementsize)
347        SWAPDATA(ptr[e],ptr[e+3]) SWAPDATA(ptr[e+1],ptr[e+2])  break;
348    case 5: for(e=0;e<elements*elementsize;e+=elementsize)
349        SWAPDATA(ptr[e],ptr[e+4]) SWAPDATA(ptr[e+1],ptr[e+3])  break;
350    case 6: for(e=0;e<elements*elementsize;e+=elementsize)
351        SWAPDATA(ptr[e],ptr[e+5]) SWAPDATA(ptr[e+1],ptr[e+4]) SWAPDATA(ptr[e+2],ptr[e+3])  break;
352    case 7: for(e=0;e<elements*elementsize;e+=elementsize)
353        SWAPDATA(ptr[e],ptr[e+6]) SWAPDATA(ptr[e+1],ptr[e+5]) SWAPDATA(ptr[e+2],ptr[e+4])  break;
354    case 8: for(e=0;e<elements*elementsize;e+=elementsize)
355        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;
356    }
357    }
358}
359
360/********************************************************************/
361/*Makes byte swapping, or not depending on the mode argument        */
362void byteswapcopy(char *dest,char *src,const int elements,const int elementsize,int mode)
363{
364    // MODE=0 Do nothing, MODE=1 Swap, MODE=2 network byte order, MODE=2 Intel byte order.
365    // A little smart ckeck of byte the machine byte order.
366    const int ordertest=1;
367    const char *is_intel_order=(const char *)(&ordertest);
368    if(is_intel_order[0]==1 && mode==2)   mode=1;   
369    if(is_intel_order[0]==0 && mode==3)   mode=1;
370    //    fprintf(stderr,"SWAP COPY E:%d SI:%d SWAP:%d\n",elements,elementsize,mode);
371    if(mode==1){
372    int e,n;
373    //  fprintf(stderr,"SWAP COPY\n");
374    for(e=0;e<elements;e++){
375        char *dp=&dest[e*elementsize];
376        char *sp=&src[e*elementsize];
377        for(n=0;n<elementsize;n++){
378        dp[n]=sp[elementsize-1-n];
379        //      fprintf(stderr,"E:%d/%d N:%d/%d\n",e,elements,n,elementsize);
380        }
381    }
382    //  fprintf(stderr,"SWAP COPY END\n");
383    }
384    else
385        memmove(dest,src,elements*elementsize);
386}
387
388/********************************************************************/
389/* DEBUGING FUNCTION */
390void __debug_view_con_status(char *str)
391{
392    int a;
393    mexPrintf("%s\n",str);
394    for(a=0;a<5;a++)
395    {
396    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);
397    if(con[a].read.ptr)
398        mexPrintf("RD: %02x %02x %02x %02x %02x %02x %02x %02x ",
399              (int)con[a].read.ptr[0],(int)con[a].read.ptr[1],(int)con[a].read.ptr[2],(int)con[a].read.ptr[3],
400              (int)con[a].read.ptr[4],(int)con[a].read.ptr[5],(int)con[a].read.ptr[6],(int)con[a].read.ptr[7]);
401    if(con[a].write.ptr)
402        mexPrintf("WR: %02x %02x %02x %02x %02x %02x %02x %02x ",
403              (int)con[a].write.ptr[0],(int)con[a].write.ptr[1],(int)con[a].write.ptr[2],(int)con[a].write.ptr[3],
404              (int)con[a].write.ptr[4],(int)con[a].write.ptr[5],(int)con[a].write.ptr[6],(int)con[a].write.ptr[7]);
405    if(a==con_index)
406        mexPrintf("<--\n");
407    else
408        mexPrintf("\n");
409    }
410    mexPrintf("--------------------\n");
411}
412
413/********************************************************************/
414/* Portable time function using matlabs NOW                         */
415double my_now(){
416    double sec;
417    double dotimenow;
418    static double lastdotime;
419    mxArray *plhs[1]={NULL};
420    mxArray *prhs[1]={NULL};
421    mexCallMATLAB(1,plhs,0,prhs,"now");
422    sec=mxGetScalar(plhs[0])*60*60*24; //Return time as sec from 1970
423    dotimenow=floor(sec*10)/10; // Do calls every 1/10 Sec
424    mxDestroyArray(plhs[0]);
425    if(lastdotime!=dotimenow){  //Call drawnow once evry X second
426        int ret=mexCallMATLAB(0,plhs,0,prhs,"drawnow");
427        //mexPrintf("wait... drawnow returns: %d\n",ret);
428        lastdotime= dotimenow;
429    }
430    return sec;
431}
432
433/*******************************************************************************/
434/* Checks that given index is valid index and set current index, "con_index"   */
435/* to that point. If index is CON_FREE (-1) then is search done for a free one */
436/* Returns 1 On success. 0 on error                                            */
437int move_con(int idx)
438{
439    if(idx>=MAX_CON)
440    mexErrMsgTxt("Unvalid value of handler!\n");
441    if(idx>=0)
442    {
443    con_index=idx;
444    if(con[con_index].status==STATUS_FREE)
445        mexErrMsgTxt("No valid handler! already closed?");
446    return 1;
447    }
448    debug_view_con_status("START MOVE");
449    if(idx==CON_FREE)    /* Move con_index until it find a free non used struct */
450    {
451    for(con_index=0;con_index<MAX_CON;con_index++)
452    {
453        debug_view_con_status("STEP MOVE");
454        if(con[con_index].status==STATUS_FREE)
455        return 1;
456    }
457    mexErrMsgTxt("To many open connection! Forgot to close old connections?");
458    }
459    if(idx<0)
460    mexErrMsgTxt("Unvalid value of handler!");
461    return 0;
462}
463
464/**********************************************************************************************/
465/* Returns true if specified argument exist                                                  */
466int my_mexIsInputArgOK(const int argno)
467{
468    //    fprintf(stderr,"IS_INPUT_ARG_OK NO:%d of %d\n",argno,gnrhs);        // DEBUG
469    if(gnrhs>argno)
470    return 1;
471    return 0;
472}
473
474/******************************************************************************************************/
475/* Returns specified input argument as scalar. Global and error tolerant replacement for mxGetScalar */
476const mxArray *my_mexInputArg(const int argno)
477{
478    //    fprintf(stderr,"GET_INPUT_ARG NO:%d\n",argno);                      // DEBUG
479    if(!my_mexIsInputArgOK(argno))
480    mexErrMsgTxt("Missing input argument.");
481    return gprhs[argno];
482}
483
484/****************************************************************************************************************/
485/* Returns pointer to static buffer (max 80 chars) holding a string in argument argno Global and error tolerant */
486const char *my_mexInputOptionString(const int argno)
487{
488    static char buff[80+1];
489    buff[0]=0;
490    if(my_mexIsInputArgOK(argno))
491    if(mxIsChar(my_mexInputArg(argno)))
492       mxGetString(my_mexInputArg(argno),buff,80);
493    return buff;
494}
495
496/****************************************************************************************************************/
497/* Returns pointer to static buffer (max 80 chars) holding the first string with non numeric,nonempty contents  */
498const char *my_mexFindInputString(int argno)
499{
500    const char *str;
501    static char buff[1];
502    buff[0]=0;
503    while(my_mexIsInputArgOK(argno)){
504    str=my_mexInputOptionString(argno);
505    if(!isdigit(str[0]) && str[0]!=0 )
506        return str;
507    argno++;
508    }
509    return buff;
510}
511
512/*********************************************************************/
513/* Returns true if if finds option opt at argument argno or later    */
514int my_mexFindInputOption(int argno,const char *opt)
515{
516    char buff[80+1];
517    while(my_mexIsInputArgOK(argno))
518    {
519    buff[0]=0;
520    mxGetString(my_mexInputArg(argno),buff,80);
521    if(myoptstrcmp(buff,opt)==0)
522        return 1;
523    argno++;
524    }
525    return 0;
526}
527
528/***********************************************************************************************************/
529/* Returns specified input arguments cell as scalar. Global and error tolerant replacement for mxGetScalar */
530double my_mexInputCell(const int argno,int cell_no)
531{
532    if(!mxIsDouble(my_mexInputArg(argno)))
533    mexErrMsgTxt("Argument has wrong datatype.");
534    if(cell_no>=mxGetNumberOfElements(my_mexInputArg(argno)))
535    mexErrMsgTxt("Argument has wrong number of cells");
536    return mxGetPr(my_mexInputArg(argno))[cell_no];
537}
538
539/******************************************************************************************************/
540/* Returns specified input argument as scalar or a scalar product of its elements.                    */
541/* Global and error tolerant replacement for mxGetScalar                                              */
542int my_mexInputSize(const int argno)
543{
544    if(!my_mexIsInputArgOK(argno))
545    return DEFAULT_INPUT_SIZE;
546    if(mxIsChar(my_mexInputArg(argno))){
547    const int ch=(my_mexInputOptionString(argno)[0]);
548    if(!isdigit(ch))
549        return DEFAULT_INPUT_SIZE;
550    else
551        return atoi(my_mexInputOptionString(argno));
552    }
553    if(mxGetNumberOfElements(my_mexInputArg(argno))>1){
554    int val=1,n=0,el=mxGetNumberOfElements(my_mexInputArg(argno));
555    for(n=0;n<el;n++)
556        val*=(int)my_mexInputCell(argno,n);
557    return val;
558    }else
559    return (int)mxGetScalar(my_mexInputArg(argno));
560}
561
562/******************************************************************************************************/
563/* Returns specified input argument as scalar. Global and error tolerant replacement for mxGetScalar */
564double my_mexInputScalar(const int argno)
565{
566    if(mxIsChar(my_mexInputArg(argno)))
567    return atof(my_mexInputOptionString(argno));
568    else
569    return mxGetScalar(my_mexInputArg(argno));
570}
571
572/********************************************************************/
573/* Copys a matlab Char array to a char * string buffer              */
574int my_mexInputArray2Buff(const int argno,io_buff *buff)
575{
576    mxClassID id=mxGetClassID(my_mexInputArg(argno));
577    int si=classid2size(id);
578    int len=mxGetNumberOfElements(my_mexInputArg(argno));
579    int swap=2;
580    if(my_mexFindInputOption(argno+1,"NATIVE"))  swap=0;
581    if(my_mexFindInputOption(argno+1,"SWAP"))    swap=1;
582    if(my_mexFindInputOption(argno+1,"NETWORK")) swap=2;
583    if(my_mexFindInputOption(argno+1,"INTEL"))   swap=3;
584   
585    newbuffsize(buff,buff->pos+len*si);
586
587    if(id==mxCHAR_CLASS){
588    mxChar *ptr = (mxChar *)mxGetPr(gprhs[argno]);
589    int a;
590    for(a=0;a<len;a++)
591        buff->ptr[buff->pos++]=(char)(unsigned char)ptr[a];
592    }else{
593    char *ptr = (char *)mxGetPr(gprhs[argno]);
594    byteswapcopy(&buff->ptr[buff->pos],ptr,len,si,swap);
595    buff->pos+=(len*si);
596    }
597    return len;
598}
599
600/*******************************************************************************/
601/* Puts double scalar in matlab variable in the array of return argument for mex*/
602void my_mexReturnValue(double val)
603{
604    if((gret_args>gnlhs) && (gret_args>1))
605    return;
606    gplhs[gret_args]=mxCreateDoubleMatrix(1,1,mxREAL);
607    if(gplhs[gret_args]==NULL)
608    mexErrMsgTxt("Matrix creation error! Lack of memory?");
609    else
610    {
611    *mxGetPr(gplhs[gret_args])=val;
612    gret_args++;
613    }
614//    mexPrintf("DEBUG MEX RETURN VALUE:%g\n",val);  // DEBUG
615}
616
617/*******************************************************************************/
618/* Puts double matrix in matlab variable in the array of return argument for mex*/
619void my_mexReturnMatrix(int rows, int cols, double *vals)
620{
621    double *pr;
622    if((gret_args>gnlhs) && (gret_args>1))
623    return;
624    gplhs[gret_args] = mxCreateDoubleMatrix( rows, cols, mxREAL);
625    if( gplhs[gret_args] == NULL)
626        mexErrMsgTxt("Matrix creation error");
627    pr = (double *)mxGetPr(gplhs[gret_args]);
628    memcpy(pr,vals,rows*cols*sizeof(double));
629    gret_args++;
630}
631
632/********************************************************************************/
633/* Puts string as matlab char char variable in array of return argument for mex */
634void my_mexReturnString(const char *str)
635{
636    if(gret_args>gnlhs && gret_args>1)
637    return;
638    gplhs[gret_args]=mxCreateString(str);
639    if(gplhs[gret_args]==NULL)
640    mexErrMsgTxt("String creation error! Lack of memory?");
641    gret_args++;
642}
643
644/******************************************************************************/
645/* Puts data from buffer into next MATLAB return Array                        */
646void my_mexReturnArrayFromBuff(const int argno,io_buff *buff,const int line)
647{
648    const int maxelements=my_mexInputSize(argno);
649    const mxClassID id=str2classid(my_mexInputOptionString(argno+1));
650    int dims[20]={0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0 };
651    const int si=classid2size(id);
652    int returnelements= ( (buff->pos/si)< maxelements )?(buff->pos/si):maxelements;
653    int deleteelements=returnelements;
654    int swap=2;
655    int return_no_dims= my_mexIsInputArgOK(argno) && !mxIsChar(my_mexInputArg(argno))?mxGetNumberOfElements(my_mexInputArg(argno)):1;
656
657    if(my_mexFindInputOption(argno+1,"NATIVE"))  swap=0;
658    if(my_mexFindInputOption(argno+1,"SWAP"))    swap=1;
659    if(my_mexFindInputOption(argno+1,"NETWORK")) swap=2;
660    if(my_mexFindInputOption(argno+1,"INTEL"))   swap=3;
661    if(return_no_dims>20)
662    mexErrMsgTxt("To many dimentions to return.");
663    debug_view_con_status("GET_ARRAY");
664    if(line){
665    int n=-7;
666    if(id!=mxCHAR_CLASS && return_no_dims)
667        mexErrMsgTxt("'READLINE' works only with datatype char and non fixed blocksize");
668    for(n=0;n<returnelements;n++)
669        if(buff->ptr[n]=='\n')
670        break;
671    if(n==maxelements)                             // If no new-line found inside limit...
672        deleteelements=returnelements=maxelements; // ...return first part of splited line.
673    else if(n==returnelements)                     // If new-line not recived inside limit...
674        deleteelements=returnelements=0;           // ...return empty string, and delete nothing.
675    else if(n>0 && buff->ptr[n-1]=='\r')           // If(*3) new-line, return line of char but not nl chars.
676       deleteelements=2+(returnelements=n-1);
677    else
678       deleteelements=1+(returnelements=n);
679    return_no_dims=1;
680    }
681    if(return_no_dims>1){                 // If shape of return argument is specified.....
682    if(returnelements==maxelements){        // ...then only accept correct shape.
683        int n;
684        for(n=0;n<return_no_dims;n++)
685        dims[n]=(int)my_mexInputCell(argno,n);
686    }
687    }else if(returnelements>0){           // else... Just return row of available elements
688    dims[0]=1;
689    dims[1]=returnelements;
690    return_no_dims=2;
691    }
692    if(! (gret_args>gnlhs && gret_args>1) ){
693    /* Create a 2-Dimensional character mxArray.*/
694    if( dims[0]==0)
695        gplhs[gret_args] = mxCreateNumericArray(0,dims,id,mxREAL);
696    else
697        gplhs[gret_args] = mxCreateNumericArray(return_no_dims,dims,id,mxREAL);
698    if(gplhs[gret_args] == NULL)
699        mexErrMsgTxt("Could not create return array.");
700    if(dims[0]!=0){
701        if(id==mxCHAR_CLASS){
702        int i;
703        mxChar *p=(mxChar *)mxGetPr(gplhs[gret_args]);
704        for(i=0;i<returnelements;i++)
705            p[i]=buff->ptr[i];
706        }else{
707        char *p=(char *)mxGetPr(gplhs[gret_args]);
708        byteswapcopy(p,buff->ptr,returnelements,si,swap);
709        }
710    }
711    gret_args++;
712    }
713       //    debug_view_con_status("GET_ARRAY NÄSTAN KLAR");
714    // Delete from read buffer if not "VIEW" option and dims filled
715    if(my_mexFindInputOption(argno+1,"VIEW")==0 && deleteelements>0 ){
716    buff->pos-=deleteelements*si;
717    memmove(buff->ptr,&buff->ptr[deleteelements*si],buff->pos);
718    newbuffsize(buff,buff->pos);
719    }
720    // mexPrintf("DEBUG MEX RETURN ARRAY OF:%d\n",returnelements);  // DEBUG
721
722    //    fprintf(stderr,"DIMS:[%d %d] DEL:%d RET:%d SI:%d POS:%d LEN:%d PTR:%08X\n",
723    //      dims[0],dims[1],deleteelements,returnelements,si,buff->pos,buff->len,buff->ptr);
724}
725
726
727/**********************************************************************/
728int ipv4_lookup(const char *hostname,int port)
729{
730    struct in_addr addr;    /* my address information */
731    /* Try IP address */
732    addr.s_addr=inet_addr(hostname);
733    if (addr.s_addr==INADDR_NONE){
734    /*Can't resolve host string as dot notation IP number...
735      try lookup IP from hostname */
736    struct hostent *he;
737    //  fprintf(stderr,"Trying nameserverlookup:%s\n",hostname);
738    he=gethostbyname(hostname);
739    if(he==NULL){
740        mexPrintf("\nUNKNOWN HOST:%s\n",hostname);
741        return -1;  /* Can not lookup hostname */
742    }
743    addr = *((struct in_addr *)he->h_addr);
744    }
745    con[con_index].remote_addr.sin_family=AF_INET;
746    con[con_index].remote_addr.sin_port=htons(port);
747    con[con_index].remote_addr.sin_addr=addr;
748    memset(&con[con_index].remote_addr.sin_zero, 0,8);
749    return 0;
750}
751
752
753/**********************************************************************/
754/* Writes from specified position (pointer) in buffer of spec. length */
755int writedata()
756{
757    const double timeoutat=my_now()+con[con_index].writetimeout;
758    int   len=con[con_index].write.pos;
759    const char *ptr=con[con_index].write.ptr;
760    const int  fid=con[con_index].fid;
761    int sentlen=0;
762    int retval=0;
763    int lastsize=1000000;
764    if(con[con_index].status<STATUS_IO_OK)
765    return 0;
766    //    if( !IS_STATUS_TCP_CONNECTED(con[con_index].status)  && len>65534 )   // TODO: Ta bort!
767    //  len=65534;
768    while(sentlen<len)
769    {
770    if(lastsize<1000)
771        usleep(DEFAULT_USLEEP);
772    if(IS_STATUS_UDP_NO_CON(con[con_index].status))
773        retval = sendto(fid,&ptr[sentlen],len-sentlen,MSG_NOSIGNAL,
774                (struct sockaddr *)&con[con_index].remote_addr,sizeof(struct sockaddr));
775    else
776        retval=send(fid,&ptr[sentlen],len-sentlen,MSG_NOSIGNAL);
777    lastsize=retval>0?retval:0;
778    sentlen+=lastsize;
779    /*  if( retval==0){
780        mexPrintf("\nREMOTE HOST DISCONNECTED\n");
781        con[con_index].status=STATUS_NOCONNECT;
782        break;
783        }*/
784    if(retval<0 && s_errno!=EWOULDBLOCK
785       //      IFWINDOWS( && s_errno!=WSAECONNRESET  )           // DEBUG: REMOVE THIS LINE?
786       ){
787        con[con_index].status=STATUS_NOCONNECT;
788        perror( "sendto() / send()" );
789        mexPrintf("\nREMOTE HOST DISCONNECTED\n");
790        break;
791    }
792    if( !IS_STATUS_TCP_CONNECTED(con[con_index].status) && sentlen>0 )
793        break;
794    if(timeoutat<=my_now())
795        break;
796    }
797    con[con_index].write.pos-=sentlen;
798    memmove(con[con_index].write.ptr, &con[con_index].write.ptr[sentlen], con[con_index].write.pos);
799    newbuffsize(&con[con_index].write,con[con_index].write.pos);
800    return sentlen;
801}
802
803/********************************************************************/
804/* Init current record with values                                  */
805void init_con(int fid,int status)
806{
807    memset(&con[con_index],0,sizeof(con_info));
808    con[con_index].fid=fid;
809    con[con_index].status=status;
810    con[con_index].writetimeout=DEFAULT_WRITETIMEOUT;
811    con[con_index].readtimeout=DEFAULT_READTIMEOUT;
812}
813
814/********************************************************************/
815/* Close con struct                                                 */
816void close_con()
817{
818    if(con[con_index].fid>=0)
819    close(con[con_index].fid);
820    else
821    mexWarnMsgTxt("Closing already closed connection!");
822    newbuffsize(&con[con_index].write,-1);
823    newbuffsize(&con[con_index].read,-1);
824    init_con(-1,STATUS_FREE);
825}
826
827/*******************************************************************      */
828/* Function to close all still open tcpip connections */
829int closeall(void)
830{
831    int flag=0;
832    for(con_index=0;con_index<MAX_CON;con_index++)
833    if(con[con_index].fid>=0) {  /* Already closed?? */
834        close_con();
835        flag=1;
836    }
837    return flag;
838}
839
840/****************************************************************************/
841/* This function is called on unloading of mex-file                         */
842void CleanUpMex(void)
843{
844    if(closeall()) /* close all still open connections...*/
845    mexWarnMsgTxt("Unloading mex file. Unclosed tcp/udp/ip connections will be closed!");
846    IFWINDOWS(   WSACleanup();  );
847}
848
849/********************************************************************/
850/* Read to fill input buffer with specified length from UDP or TCP network*/
851int read2buff(const int len,int newline,int noblock)
852{
853    //const double timeoutat=my_now()+con[con_index].readtimeout;
854    //double timeoutat=con[con_index].readtimeout;
855    double timeoutat;
856    int retval=-1;
857   
858    //mexPrintf("read2buff(%d,%d,%d)\n",len,newline,noblock);
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    if(noblock==0) timeoutat=my_now()+con[con_index].readtimeout;
873    while(1){
874   
875    int readlen=len-con[con_index].read.pos;
876//  mexPrintf("DEBUG: READLINE: readlen:%d\n",readlen);
877    if(readlen>0){
878        if(IS_STATUS_CONNECTED(con[con_index].status))
879        retval=recv(con[con_index].fid,&con[con_index].read.ptr[con[con_index].read.pos],readlen ,MSG_NOSIGNAL);
880        else{
881        struct sockaddr_in my_addr;
882        int fromlen=sizeof(my_addr); 
883
884        // Copy 0.0.0.0 adress and 0 port to remote_addr as init-value.
885        memset(&my_addr,0,sizeof(my_addr));
886        con[con_index].remote_addr.sin_addr = my_addr.sin_addr;
887        con[con_index].remote_addr.sin_port = my_addr.sin_port;
888        retval=recvfrom(con[con_index].fid,&con[con_index].read.ptr[con[con_index].read.pos],
889                readlen,MSG_NOSIGNAL,(struct sockaddr *)&my_addr, &fromlen);
890        if (retval>0){
891            con[con_index].remote_addr.sin_addr = my_addr.sin_addr;
892            con[con_index].remote_addr.sin_port = htons((unsigned short int)ntohs(my_addr.sin_port));
893        }
894        }
895        if( retval==0){
896        mexPrintf("\nREMOTE HOST DISCONNECTED\n");
897        con[con_index].status=STATUS_NOCONNECT;
898        break;
899        }
900        if(retval<0 && s_errno!=EWOULDBLOCK
901           //          IFWINDOWS( && s_errno!=WSAECONNRESET )// DEBUG: REMOVE THIS LINE?
902           ) {
903        con[con_index].status=STATUS_NOCONNECT;
904        perror( "recvfrom() or recv()" );
905        break;
906        }
907    }
908    //  fprintf(stderr,"RET:%d/%d ",retval,s_errno);
909    readlen=retval>0?retval:0;
910    con[con_index].read.pos+=readlen;
911   
912   
913    if( !IS_STATUS_TCP_CONNECTED(con[con_index].status) && con[con_index].read.pos>0 )
914        break;
915    if( con[con_index].read.pos>=len )
916        break;
917    if(noblock){
918        break;
919    } else {
920        if(timeoutat<=my_now()) break;
921    }
922   
923    if(newline){
924        int n;
925        for(n=0;n<con[con_index].read.pos;n++)
926        if(con[con_index].read.ptr[n]=='\n')
927            return con[con_index].read.pos;
928    }
929    //if(readlen<1000)
930    //    usleep(DEFAULT_USLEEP);
931    }
932    return con[con_index].read.pos;
933}
934
935/***************************************************************************/   // BORT???
936/* Read specified length & type from UDP or TCP network to input buffer    */
937int readtype2buff(int len,mxClassID datatype,int newline,int noblock)
938{
939    const int si=classid2size(datatype);
940    //mexPrintf("datatype = %d\n",si);
941    //mexPrintf("noblock = %d\n",noblock);
942    return read2buff(len*si,newline,noblock)/si;
943}
944
945/********************************************************************/
946/* Function Creating a tcpip connection and returns handler number  */
947int tcp_connect(const char *hostname,const int port)
948{
949    if(ipv4_lookup(hostname,port)==-1)
950    return -1;
951    con[con_index].fid=socket(AF_INET, SOCK_STREAM, 0);
952    if(con[con_index].fid== CON_FREE){
953    /*Can't open socket */
954    close_con();
955    return -1;
956    }
957    if(connect(con[con_index].fid,(struct sockaddr *)&con[con_index].remote_addr,sizeof(struct sockaddr)) == -1){
958    /*Can't connect to remote host. */
959    close_con();
960    return -1;
961    }
962    con[con_index].status=STATUS_TCP_CLIENT;
963    nonblockingsocket(con[con_index].fid); /* Non blocking read! */
964    return con_index;
965}
966
967/*******************************************************************     
968 Function Creating a TCP server socket                                 
969 or a connectionless UDP client socket.
970*/
971int tcp_udp_socket(int port,int dgram_f, int bufSize)
972{
973    int sockfd;
974    int a;
975   
976
977    struct sockaddr_in my_addr;    /* my address information */
978    const int on=1;
979    if(dgram_f)
980    sockfd = socket(AF_INET, SOCK_DGRAM, 0);
981    else
982    sockfd = socket(AF_INET, SOCK_STREAM, 0);
983    if(sockfd==-1)
984    return -1;
985   
986
987   
988   
989    my_addr.sin_family = AF_INET;         /* host byte order */
990    my_addr.sin_port = htons(port);       /* short, network byte order */
991    my_addr.sin_addr.s_addr = INADDR_ANY; /* auto-fill with my IP */
992    memset(&(my_addr.sin_zero),0, 8);        /* zero the rest of the struct */
993    setsockopt(sockfd,SOL_SOCKET,(SO_REUSEADDR|SO_BROADCAST),(const char *)&on,sizeof(on));
994   
995    if(bufSize){
996        a = bufSize;
997        setsockopt(sockfd,SOL_SOCKET,(SO_RCVBUF), &a, sizeof(int));
998    }
999   
1000    //mexPrintf("sockfd = %d\n",sockfd);
1001   
1002    if(bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr))== -1)
1003    {
1004    //mexPrintf("Socket Failed to Bind\n");
1005    close(sockfd);
1006    return -1;
1007    }
1008    listen(sockfd,BACKLOG);
1009    nonblockingsocket(sockfd);
1010    return sockfd;
1011}
1012
1013/*****************************************************************/
1014/* Listen to socket and returns connection if there is one...
1015   else it returns -1 */
1016int tcpiplisten(int noblock)
1017{
1018    const double timeoutat=my_now()+con[con_index].readtimeout;
1019    int new_fd;
1020    const int sock_fd= con[con_index].fid;
1021    int sin_size = sizeof(struct sockaddr_in);
1022    move_con(CON_FREE);        /* Find a new free con struct for the new connection.... */
1023    while(1){
1024        if ((new_fd = accept(sock_fd, (struct sockaddr *)&con[con_index].remote_addr,&sin_size)) > -1)
1025            break;
1026        if(timeoutat<=my_now()|| noblock)
1027            return -1;
1028        usleep(DEFAULT_USLEEP);
1029    }
1030    nonblockingsocket(new_fd); /* Non blocking read! */
1031    setsockopt(new_fd,SOL_SOCKET,SO_KEEPALIVE,(void *)1,0); /* realy needed? */
1032    con[con_index].fid=new_fd;
1033    con[con_index].status=STATUS_TCP_SERVER;
1034    return con_index;
1035}
1036
1037/*****************************************************************/
1038/* Make a UDP socket be a "connected" UDP socket                 */
1039int udp_connect(const char *hostname,int port)
1040{   
1041
1042    int i;
1043    //CRH
1044    //mexPrintf("Connecting on port: %d\n Host: ",port);
1045    //mexPrintf("hostname: %s\n",hostname);
1046
1047    //mexPrintf("con_index = %d, con[con_index].status = %d, STATUS_UDP_CLIENT = %d\n",con_index,con[con_index].status,STATUS_UDP_CLIENT);
1048   
1049    if(con[con_index].status < STATUS_UDP_CLIENT)
1050    mexErrMsgTxt("Must pass UDP client or server handler!");
1051    if(ipv4_lookup(hostname,port)==-1)
1052    return -1;
1053    if(connect(con[con_index].fid,(struct sockaddr *)&con[con_index].remote_addr,sizeof(struct sockaddr)) == -1)
1054    return -1; /*Can't connect to remote host. */
1055    if(con[con_index].status == STATUS_UDP_CLIENT)
1056    con[con_index].status = STATUS_UDP_CLIENT_CONNECT;
1057    else
1058    con[con_index].status = STATUS_UDP_SERVER_CONNECT;
1059    nonblockingsocket(con[con_index].fid); /* Non blocking read! */
1060    return con[con_index].status;
1061}
1062
1063/*****************************************************************/
1064/*                                                               */
1065/*    ----Main function that is called from matlab--------       */
1066/*                                                               */
1067void mexFunction(
1068    int           nlhs,           /* number of expected outputs */
1069    mxArray       *plhs[],        /* array of pointers to output arguments */
1070    int           nrhs,           /* number of inputs */
1071    const mxArray *prhs[]         /* array of pointers to input arguments */
1072    )
1073{
1074    char fun[80+1];
1075    /* Initialization on first call to the mex file */
1076    if(mex_call_counter==0)
1077    {
1078#ifdef WIN32
1079    WORD wVersionRequested;
1080    WSADATA wsaData;
1081    int wsa_err;   
1082    wVersionRequested = MAKEWORD( 2, 0 );
1083    wsa_err = WSAStartup( wVersionRequested, &wsaData );
1084    if (wsa_err)
1085        mexErrMsgTxt("Error starting WINSOCK32.");
1086#endif
1087    Print_Start_Message();
1088
1089    mexAtExit(CleanUpMex);
1090    /* Init all connecttions to to free */
1091    for(con_index=0;con_index<MAX_CON;con_index++)
1092        init_con(-1,STATUS_FREE);
1093        con_index=0;
1094    }
1095    mex_call_counter++;
1096    debug_view_con_status("ENTER_MEX");
1097
1098    /* GLOBAL IN-OUT ARGUMENTS */
1099    gnlhs=nlhs;       /* number of expected outputs */
1100    gplhs=plhs;       /* array of pointers to output arguments */
1101    gnrhs=nrhs;       /* number of inputs */
1102    gprhs=prhs;       /* array of pointers to input arguments */
1103    gret_args=0;      /* No return argumens returned */
1104
1105
1106    if(mxIsChar(my_mexInputArg(0))){
1107    /* GET FIRST ARGUMENT -- The "function" name */
1108    strncpy(fun,my_mexInputOptionString(0),80);
1109//  mexPrintf("DEBUG MEX(1):[%d] %s\n",con_index,fun);   // DEBUG
1110   
1111    /* Find of the function name corresponds to a non connection associated function */
1112    if(myoptstrcmp(fun,"CLOSEALL")==0){
1113        closeall();
1114        return;
1115    }
1116    if(myoptstrcmp(fun,"VERSION")==0){
1117        if(nlhs==0){
1118            Print_Version_Message();
1119        } else {
1120            my_mexReturnString(VERSION);
1121        }
1122        return;
1123    }
1124    if(myoptstrcmp(fun,"TCPCONNECT")==0){
1125        const int port=(int)my_mexInputScalar(2);
1126        const char *hostname=my_mexInputOptionString(1);
1127        move_con(STATUS_FREE);
1128        my_mexReturnValue(tcp_connect(hostname,port));
1129        return;
1130    }
1131    if(myoptstrcmp(fun,"TCPSOCKET")==0){
1132        const int fd=tcp_udp_socket((int)my_mexInputScalar(1), 0, 0);
1133        if(fd>=0){
1134        move_con(STATUS_FREE);
1135        init_con(fd,STATUS_TCP_SOCKET);
1136        my_mexReturnValue(con_index);
1137        }else
1138        my_mexReturnValue(-1);
1139        return;
1140    }
1141    if(myoptstrcmp(fun,"UDPSOCKET")==0){
1142        const int fd=tcp_udp_socket((int)my_mexInputScalar(1), 1, 0);
1143        if(fd>=0){
1144        move_con(STATUS_FREE);
1145        init_con(fd,STATUS_UDP_CLIENT);
1146        my_mexReturnValue(con_index);
1147        }else
1148        my_mexReturnValue(-1);
1149        return;
1150    }
1151   
1152    if(myoptstrcmp(fun,"UDPSOCKET_CUSTBUF")==0){
1153        const int fd=tcp_udp_socket((int)my_mexInputScalar(1), 1, (int)my_mexInputScalar(2));
1154        if(fd>=0){
1155        move_con(STATUS_FREE);
1156        init_con(fd,STATUS_UDP_CLIENT);
1157        my_mexReturnValue(con_index);
1158        }else
1159        my_mexReturnValue(-1);
1160        return;
1161    }
1162   
1163    if(myoptstrcmp(fun,"DOCALLBACKS")==0){
1164        return;
1165    }
1166    }
1167    /* Get connection handler and suppose that it is a connection assosiated function */
1168    /* Find given handel */
1169    //       if(strncasecmp(fun,"DEF",3)!=0)
1170    if(move_con((int)my_mexInputScalar(0))==0) 
1171    mexErrMsgTxt("Unknown connection handler");
1172    strncpy(fun,my_mexInputOptionString(1),80);
1173 //   mexPrintf("DEBUG MEX(2):[%d] %s\n",con_index,fun);   // DEBUG
1174    debug_view_con_status("CON_MOVED!!");
1175       
1176       if(myoptstrcmp(fun,"CLOSE")==0){
1177       close_con();
1178    return;
1179    }
1180    if(myoptstrcmp(fun,"TCPLISTEN")==0){
1181    if(con[con_index].status!=STATUS_TCP_SOCKET)
1182        mexErrMsgTxt("Invalid socket for LISTEN, Already open, or UDP?...");
1183    my_mexReturnValue(tcpiplisten(my_mexFindInputOption(2,"noblock")));
1184    return;
1185    }
1186    /* MATLAB called with status = UDP_CONNECT(fid, ip, port) */
1187    if(myoptstrcmp(fun,"UDPCONNECT")==0){
1188    const int port=(int)my_mexInputScalar(3);
1189    const char *hostname=my_mexInputOptionString(2);
1190    my_mexReturnValue(udp_connect(hostname,port));
1191    return;
1192    }
1193    if(myoptstrcmp(fun,"WRITE")==0){
1194    my_mexInputArray2Buff(2,&con[con_index].write);
1195    if(IS_STATUS_TCP_CONNECTED(con[con_index].status))
1196        writedata();
1197    return;
1198    }
1199    if(myoptstrcmp(fun,"PRINTF")==0){
1200    mxArray *plhs[1]={NULL};
1201    if(gnrhs<3) return;
1202    mexCallMATLAB(1,plhs, gnrhs-2, (mxArray **)&(gprhs[2]),"sprintf");
1203    gprhs=(const mxArray **)plhs; gnrhs=1; // HACK: Move return arg from sprintf to input arg of this mex.
1204    my_mexInputArray2Buff(0,&con[con_index].write);
1205    if(IS_STATUS_TCP_CONNECTED(con[con_index].status))
1206        writedata();
1207        return;
1208    }
1209    if(myoptstrcmp(fun,"READ")==0){
1210        if(IS_STATUS_TCP_CONNECTED(con[con_index].status)){
1211            //mexPrintf("loc1\n");
1212            //mexPrintf("%d,%s,%d,0,%d\n",(int)my_mexInputSize(2),my_mexFindInputString(2),my_mexFindInputOption(2,"noblock")); //CRH
1213            readtype2buff( (int)my_mexInputSize(2),str2classid(my_mexFindInputString(2)),0,my_mexFindInputOption(2,"noblock"));
1214        }
1215        my_mexReturnArrayFromBuff(2,&con[con_index].read,0);
1216        return;
1217    }
1218    if(myoptstrcmp(fun,"READLINE")==0){
1219    //  mexPrintf("DEBUG: READLINE....\n");
1220        if(IS_STATUS_TCP_CONNECTED(con[con_index].status))
1221            read2buff(my_mexInputSize(2),1,my_mexFindInputOption(2,"noblock"));
1222        my_mexReturnArrayFromBuff(2,&con[con_index].read,1);
1223    //  mexPrintf("DEBUG: READLINE END\n");
1224    return;
1225    }
1226    if(myoptstrcmp(fun,"READTOFILE")==0){
1227    FILE *f=NULL;
1228    const int blocklen=my_mexInputSize(2+1);
1229    int readlen=blocklen;
1230    int writelen=0;
1231    if(IS_STATUS_TCP_CONNECTED(con[con_index].status))
1232        readlen= read2buff(blocklen,0,(int)my_mexFindInputOption(2+1,"noblock"));
1233    if(readlen>0)
1234        f=fopen(my_mexInputOptionString(2),(int)my_mexFindInputOption(2+1,"append")?"ab":"wb");
1235    if(f){
1236        writelen=fwrite(con[con_index].read.ptr,1,readlen,f);
1237        fclose(f);
1238    }
1239    // Delete from read buffer if not "VIEW" option and dims filled
1240    if(my_mexFindInputOption(2+1,"VIEW")==0 ){
1241        con[con_index].read.pos-=writelen;
1242        memmove(con[con_index].read.ptr,&con[con_index].read.ptr[writelen],con[con_index].read.pos);
1243        newbuffsize(&con[con_index].read,con[con_index].read.pos);
1244    }
1245    my_mexReturnValue(writelen);
1246    return;
1247    }
1248    if(myoptstrcmp(fun,"WRITEFROMFILE")==0){
1249    int len=1024*1024*1024;int start=0;
1250    FILE *f=fopen(my_mexInputOptionString(2),"rb");
1251    if(f==NULL)
1252        my_mexReturnValue(-1);
1253    if(my_mexIsInputArgOK(2+1))
1254        start=(int)my_mexInputScalar(2+1);
1255    if(my_mexIsInputArgOK(2+2))
1256        len=(int)my_mexInputScalar(2+2);
1257    else{
1258        fseek(f,0,SEEK_END);
1259        len=ftell(f)-start;
1260    }
1261    fseek(f,start,SEEK_SET);
1262    newbuffsize(&con[con_index].write,con[con_index].write.pos+len);
1263    len=fread(&con[con_index].write.ptr[con[con_index].write.pos],1,len,f);
1264    con[con_index].write.pos+=len;
1265    fclose(f);
1266    if(IS_STATUS_TCP_CONNECTED(con[con_index].status))
1267        writedata();
1268    if(len<0)
1269        my_mexReturnValue(-1);
1270    else
1271        my_mexReturnValue(len);
1272    return;
1273    }
1274    if(myoptstrcmp(fun,"READPACKET")==0){
1275        con[con_index].read.pos=0;
1276        //mexPrintf("%d,%s,%d,0,%d\n",(int)my_mexInputSize(2),my_mexFindInputString(2),my_mexFindInputOption(2,"noblock")); //CRH
1277        //mexPrintf("%d,%s,%d,0,%d\n",(int)my_mexInputSize(2),my_mexInputOptionString(2+1),my_mexFindInputOption(2+1,"noblock")); //CRH
1278        my_mexReturnValue(readtype2buff(my_mexInputSize(2),str2classid(my_mexInputOptionString(2+1)),0,
1279            my_mexFindInputOption(2+1,"noblock")));
1280        return;
1281    }
1282    if(myoptstrcmp(fun,"WRITEPACKET")==0){
1283    if(IS_STATUS_UDP_NO_CON(con[con_index].status))
1284        ipv4_lookup(my_mexInputOptionString(2),my_mexInputScalar(3));
1285    my_mexReturnValue(writedata());
1286    con[con_index].write.pos=0;
1287    return;
1288    }
1289    if(myoptstrcmp(fun,"STATUS")==0){
1290    my_mexReturnValue(con[con_index].status);
1291    return;
1292    }
1293    if(myoptstrcmp(fun,"GETHOST")==0){
1294    int n;
1295    double ip_bytes[4] = {0, 0, 0, 0};
1296    const unsigned char *ipnr=(const unsigned char *)&con[con_index].remote_addr.sin_addr;
1297    for(n=0;n<4;n++)
1298        ip_bytes[n] = (double)ipnr[n];
1299    my_mexReturnMatrix(1,4,ip_bytes);
1300    my_mexReturnValue((int)ntohs(con[con_index].remote_addr.sin_port));
1301    return;
1302    }
1303    if(myoptstrcmp(fun,"SETCALLBACK")==0){
1304    strncpy(con[con_index].callback, my_mexInputOptionString(2), CBNAMELEN);
1305    return;
1306    }
1307    if(myoptstrcmp(fun,"GETCALLBACK")==0){
1308    my_mexReturnString(con[con_index].callback);
1309    return;
1310    }
1311    if(myoptstrcmp(fun,"SETWRITETIMEOUT")==0){
1312    con[con_index].writetimeout=my_mexInputScalar(2);
1313    return;
1314    }
1315    if(myoptstrcmp(fun,"SETREADTIMEOUT")==0){
1316    con[con_index].readtimeout=my_mexInputScalar(2);
1317    return;
1318    }
1319    if(myoptstrcmp(fun,"debug")==0){
1320    mexPrintf("     FID:%d\n",con[con_index].fid);
1321    mexPrintf("  STATUS:%d\n",con[con_index].status);
1322    mexPrintf("WRITE  TO:%g\n",con[con_index].writetimeout);
1323    mexPrintf("WRITE PTR:%x\n",(int)con[con_index].write.ptr);
1324    mexPrintf("WRITE POS:%d\n",con[con_index].write.pos);
1325    mexPrintf("WRITE LEN:%d\n",con[con_index].write.len);
1326    mexPrintf("READ  TO:%g\n",con[con_index].readtimeout);
1327    mexPrintf("READ PTR:%x\n",(int)con[con_index].read.ptr);
1328    mexPrintf("READ POS:%d\n",con[con_index].read.pos);
1329    mexPrintf("READ LEN:%d\n",con[con_index].read.len);
1330    return;
1331    }
1332    mexErrMsgTxt("Unknown 'function name' in argument.");
1333}
Note: See TracBrowser for help on using the repository browser.