/* * Copyright (c) 2001 Tommy Bohlin * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* sendobex.c */ #include #include #include #include #include #include #include #include #include #include #include #include #include static void connection(void* handle); typedef struct SockCon { int socket; int fd; int offset; int bufsize; u_char *buf; #define SC_IDLE 1 #define SC_INPUT_READ 2 #define SC_CONNECTED 4 int scstate; #define LC_IDLE 1 #define LC_CONNECTED 2 int lcstate; void (*oldLapConnected)(LAP* lap); void (*oldLapDisconnected)(LAP* lap); void *oldHandle; OBEXClient* obex; } SockCon; static const char id_sc[]="SockCon"; static int verbosity = 1; /********************************************************************** * OBEX control **********************************************************************/ static void obexStatus(OBEXClient* oc, int event) { switch(event) { case OBEX_SUCCESS: if (verbosity > 0) birda_log("put succeeded\n"); break; case OBEX_FAILURE: birda_log("put failed\n"); break; } obexCltClose(oc); lapDisconnect(optLap); } /********************************************************************** * LAP control **********************************************************************/ static void lapConnected(LAP* lap) { SockCon* sc = lap->handle; if (verbosity > 0) birda_log("LAP connected\n"); #if 0 lapDisconnect(optLap); #endif sc->obex = createOBEXClient(lap); if(!sc->obex) { birda_log("OBEX connect failed\n"); lapDisconnect(lap); } if(verbosity > 0) sc->obex->debug |= OBEX_DEBUG_INFO; sc->obex->status = obexStatus; obexCltPut(sc->obex,sc->buf,sc->offset); } static void showLap(LAP *lap) { fprintf(stderr, "LAP: flags=%x debug=%x handle=%lx status=%lx\n", lap->flags, lap->debug, (u_long)lap->handle, (u_long)lap->status); } static void lapDisconnected(LAP* lap) { SockCon* sc = lap->handle; if (verbosity > 0) birda_log("LAP disconnected\n"); optLapConnected = sc->oldLapConnected; optLapDisconnected = sc->oldLapDisconnected; optLap->handle = sc->oldHandle; sc->scstate = SC_IDLE; freeMem(sc->buf); sc->buf = NULL; sc->offset = 0; showLap(optLap); evtAddSource(sc->socket, connection, sc); /* Listen for connections again */ } static SockCon* createSocketConnection(void) { SockCon* sc = allocMem(id_sc, sizeof(SockCon)); sc->buf = NULL; sc->offset = 0; sc->scstate = SC_IDLE; sc->lcstate = LC_IDLE; sc->obex = NULL; return sc; } static void input(void* handle) { SockCon* sc = (SockCon *)handle; ssize_t len; if (sc->offset == sc->bufsize) { sc->bufsize *= 2; sc->buf = growMem(sc->buf, sc->bufsize); } len = read(sc->fd, &sc->buf[sc->offset], sc->bufsize-sc->offset); if(len>0) { sc->offset += len; } else if(len==0) { evtRemoveSource(sc->fd); close(sc->fd); /* Done reading from socket */ fprintf(stderr, "Read OBEX object from socket, length=%d\n", sc->offset); if (sc->offset > 0) { sc->scstate = SC_INPUT_READ; sc->oldLapConnected = optLapConnected; sc->oldLapDisconnected = optLapDisconnected; sc->oldHandle = optLap->handle; optLapConnected = lapConnected; optLapDisconnected = lapDisconnected; optLap->handle = sc; fprintf(stderr, "We are initialized\n"); showLap(optLap); doConnect(); } } else if(len<0 && errno!=EAGAIN && errno!=EINTR) { evtRemoveSource(sc->fd); close(sc->fd); perror("Error reading from socket"); } } static void connection(void* handle) { SockCon* sc = (SockCon *)handle; struct sockaddr addr; socklen_t len; fprintf(stderr, "Someone connected!\n"); showLap(optLap); evtRemoveSource(sc->socket); /* Can only handle one connection at a time */ if (sc->scstate == SC_IDLE) { len = sizeof(addr); sc->fd = accept(sc->socket, &addr, &len); if (sc->fd > 0) { fprintf(stderr, "Conn: fd = %d\n", sc->fd); fprintf(stderr, "error = %d\n", errno); if (sc->buf == NULL) { #define INITIAL_BUFSIZE 4096 sc->buf = allocMem(id_sc, INITIAL_BUFSIZE); sc->bufsize = INITIAL_BUFSIZE; } sc->offset = 0; evtAddSource(sc->fd, input, sc); } } } #define MAXTRIES 3 #define SYSCALL_ERROR -1 #define RESOLVER_ERROR -2 #define OPTION_ERROR -3 #define CLOSE( sd, t )\ t = errno;\ (void)close(sd);\ errno = t static int in_bind(short port, int type) { int sd; struct sockaddr_in sin; int errno_save; if ((sd = socket( AF_INET, type, 0)) == -1) return SYSCALL_ERROR; sin.sin_family = AF_INET; sin.sin_addr.s_addr = INADDR_ANY; sin.sin_port = htons(port); if (bind(sd, (struct sockaddr *)&sin, sizeof(sin)) == -1) { CLOSE(sd, errno_save); return SYSCALL_ERROR; } return sd; } #define TYPE_NAME_LEN 10 static char *socket_type_name(int type) { static char type_name[TYPE_NAME_LEN]; if (type == SOCK_STREAM) return "SOCK_STREAM"; else if (type == SOCK_DGRAM) return "SOCK_DGRAM"; else { (void) sprintf(type_name, "%d", type); return type_name; } } static void resolver_error(char *call, char *host) { fprintf(stderr, "%s: resolver error. ", call); #ifdef HAS_H_ERRNO switch (errno) { case HOST_NOT_FOUND: fprintf(stderr, "Host not found. "); break; case TRY_AGAIN: fprintf(stderr, "Got a TRY_AGAIN after %d times. ", MAX_TRIES); break; case NO_RECOVERY: fprintf(stderr, "Non-recoverable error. "); break; case NO_DATA: fprintf(stderr, "Valid name, but no data record of requested type. "); break; #if NO_ADDRESS != NO_DATA case NO_ADDRESS: fprintf(stderr, "No address. "); break; #endif default: fprintf(stderr, "UNKNOWN h_errno VALUE (h_errno=%d). ", errno); break; } #endif /* HAS_H_ERRNO */ fprintf(stderr, "Host = %s\n", ( host ) ? host : "LOCAL"); /* exit 1; */ } static int in_bind_ne(short port, int type) { int tries = 0, sd; while ((tries++ < MAXTRIES) && ((sd = in_bind(port, type)) < 0)) sleep(1); if (sd < 0) switch (sd) { case SYSCALL_ERROR: fprintf(stderr, "in_bind_ne: bind", "port = %d, type = %s\n", port, socket_type_name(type)); /* NOTREACHED */ case RESOLVER_ERROR: resolver_error("in_bind_ne", NULL); /* NOTREACHED */ default: fprintf(stderr, "in_bind_ne: in_bind RETURNED BAD VALUE: %d\n", sd); exit(1); } return sd; } void createOBEXSender(int port) { //int fdesc; int error; SockCon* sc = createSocketConnection(); fprintf(stderr, "Trying to listen on port %d\n", port); if (listen(sc->socket = in_bind_ne(port, SOCK_STREAM), 5) >= 0) { //struct sockaddr addr; //socklen_t len; fprintf(stderr, "Socket fd=%d\n", sc->socket); error = fcntl(sc->socket, F_SETFL, O_NONBLOCK | O_ASYNC); if (error == -1) { perror("Couldn't fcntl socket\n"); } #if 0 len=sizeof(addr); fdesc = accept(sc->socket, &addr, &len); if (fdesc != -1 || errno != EWOULDBLOCK) { fprintf(stderr, "odd accept: %d, %d\n", fdesc, errno); } #endif showLap(optLap); evtAddSource(sc->socket, connection, sc); } else { fprintf(stderr, "Couldn't listen on port %d: errno=%d\n", port, errno); } }