/* Sockline 0.1 by Luigi Auriemma e-mail: aluigi@autistici.org web: aluigi.org Introduction ============ easy to use function for reading delimited data (like text lines) from multiple sockets. Usage ===== - initialization: len = sizeof(buff) - 1; // -1 since sockline adds a 0 at the end of the buffer sockline(NULL, &len, '\n', sd[0], sd[1], sd[2], ..., sd[n], 0); | | | | | | | | | sockets delimiter | | | lists of sockets to read | | delimiter char, '\n' for lines | size of the buffer means initialization - usage: for(;;) { s = sockline(buff, &len); | | | | | will contain the lenght of the read data | the buffer receives the socket from which has been read the data if(len <= 0) break; printf("%d) %d %s\n", s, len, buff); } - finish: sockline(buff, 0); | | | means finish unused, use a positive number License ======= Copyright 2005,2006 Luigi Auriemma This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA http://www.gnu.org/licenses/gpl.txt */ #include #include int sockline(u_char *out, int *outlen, ...) { va_list ap; fd_set rset; int i, t, len; u_char *p, *l; static int num, sel, maxlen, last, *sd, *blen; static u_char **b, chr; if(!out) { // INIT num = 0; sd = NULL; sel = 0; maxlen = *outlen; last = -1; va_start(ap, outlen); chr = va_arg(ap, int); while((t = va_arg(ap, int))) { sd = realloc(sd, (num + 1) * sizeof(int)); if(!sd) return(-1); sd[num] = t; num++; if(t > sel) sel = t; } va_end(ap); sel++; b = malloc(num * sizeof(u_char *)); if(!b) return(-1); blen = malloc(num * sizeof(int)); if(!blen) return(-1); for(i = 0; i < num; i++) { b[i] = malloc(maxlen); if(!b[i]) return(-1); blen[i] = 0; } return(0); } if(!outlen) { // FINISH for(i = 0; i < num; i++) { free(b[i]); shutdown(sd[i], 2); close(sd[i]); } free(b); free(blen); free(sd); return(0); } #define SOCKLINESCAN \ l = b[i] + blen[i]; \ for(p = b[i]; (p < l) && (*p != chr); p++); \ if(p < l) { \ p++; \ goto linefull; \ } if(last >= 0) { // handles the remaining buffer i = last; // if there is remaining data in SOCKLINESCAN; // the latest handled socket } for(;;) { FD_ZERO(&rset); for(i = 0; i < num; i++) { FD_SET(sd[i], &rset); } if(select(sel, &rset, NULL, NULL, NULL) < 0) { *outlen = -1; return(-1); } for(i = 0; i < num; i++) { if(FD_ISSET(sd[i], &rset)) { t = recv(sd[i], b[i] + blen[i], maxlen - blen[i], 0); if(t <= 0) { *outlen = t; return(sd[i]); } blen[i] += t; if(blen[i] == maxlen) { p = b[i] + maxlen; goto linefull; } SOCKLINESCAN; break; } } } #undef SOCKLINESCAN linefull: len = p - b[i]; memcpy(out, b[i], len); out[len] = 0; blen[i] -= len; memmove(b[i], p, blen[i]); if(blen[i]) { last = i; } else { last = -1; } *outlen = len; return(sd[i]); }